您的位置:首页 > 其它

tiny4412 UART 收发数据

2018-03-02 13:36 183 查看
Exynos4412 UART 的特性Exynos4412 中UART,有4 个独立的通道,每个通道都可以工作于中断模式或DMA 模式,即 UART 可以发出中断或 DMA 请求以便在UART 、CPU 间传输数据。UART 由波特率发生器、发送器、接收器和控制逻辑组成。使用系统时钟时,Exynos4412 的 UART 波特率可以达到 4Mbps 。波特率可以通过编程进行 。Exynos4412 UART 的通道 0有 256 字节的发送 FIFO 和 256 字节的接收FIFO ;通道 1、4有 64 字节的发送 FIFO 和 64 字节的接收FIFO;通道 2、3有 16 字节的发送FIFO 和 16 字节 的接收 FIFO 。发送数据时, CPU 先将数据写入发送FIFO 中,然后 UART 会自动将FIFO 中的数据复制到“发送移位器” (Transmit Shifter )中,发送移位器将数据一位一位地发送到 TxDn 数据线上 (根据设定的格式,插入开始位 、较验和停止)。接收数据时,“移位器” (Receive Shifter )将 RxDn 数据线上的数据一位一位的接收进来,然后复制到FIFO 中, CPU即可从中读取数据。Exynos4412 UART的每个通道支持停止位有 1位、 2位,数据位有 5、6、7或 8位,支持校验功能,另外还有红外发送 /接收功能。Exynos4412 UART结构图


声明以后没有特殊说明,程序结构都和《Tiny4412裸机程序之代码在DDR SDRAM中运行》时的一样。整个程序的运行过程大致如下:系统上电后,首先将sd卡扇区1处的bl1拷贝到IRAM的0x02020000地址处,然后运行该部分代码,该部分代码首先又会加载BL2.bin,BL2.bin会进行时钟和DRAM初始化,然后把位于sd卡中扇区49处的main.bin拷贝到DRAM的0x43E00000地址处,最后跳转到该地址处继续运行。uart初始化步骤:1.将所涉及的UART通道管脚设为UART功能比如 UART 通道 0中, GPA0_0 、GPA0_1 分别用作 RXD0 、TXD0,要使用 UART 通道 0时,先设置 GPA0CON 寄存器将 GPA0_0 、GPA0_1 引脚的功能设为 RXD0 、TXD0 。2. 选择UART的时钟源



Exynos4412 UART的时钟源有八种选择: XXTI 、XusbXTI 、SCLK_HDMI24M 、SCLK_USBPHY0 、 SCLK_HDMIPHY 、SCLKMPLL_USER_T 、SCLKEPLL 、SCLKVPLL ,由 CLK_SRC_PERIL0 寄存器控制。
选择好时钟源后,还可以通过 DIVUART0 ~4设置分频系数 设置分频系数 ,由 CLK_DIV_PERIL0 寄存器控制。 从分频器得到的时钟被称为SCLK UART 。SCLK UART 经过上图中的“ UCLK Generator”后,得到UCLK ,它的频率就是UART 的波特率。“ Generator UCLK Generator ”通过这 2个寄存器来设置: UBRDEVn 、UFRACVALn (在下面描述 在下面描述 )。3. 设置波特率:UBRDIVn寄存器(UART BAUD RATE DIVISOR)、UFRACVALn寄存器根据给定的波特率、所选择时钟源频率,可以通过以下公式计算 UBRDIVn 寄存器 (n 为 0~4,对应 5个 UART 通道 )的值。UBRDIVn = (int)( UART clock / ( buad rate x 16) ) – 1上式计算出来的 UBRDIVn 寄存器值不一定是整数, UBRDIVn 寄存器取其整数部分,小部分由 UFRACVALn 寄存器设置, UFRACVALn 寄存器的引入,使产生波特率更加精确。例如,当UART clock为100MHz时,要求波特率为115200 bps,则:100000000/(115200 x 16) – 1 = 54.25 – 1 = 53.25UBRDIVn = 整数部分 = 53UFRACVALn/16 = 小数部分 = 0.25UFRACVALn = 44. 设置传输格式:ULCONn寄存器(UART LINE CONTROL)ULCONn 寄存器 (n 为 0~4) 格式如下图所示:


5. 设置UART工作模式:UCONn寄存器(UART CONTROL)





6. UFCONn寄存器(UART FIFO CONTROL)、UFSTATn寄存器(UART FIFO STATUS)UFCON n寄存器用于设置是否使用FIFO,设置各 FIFO的触发阀值,即发送 FIFO中有多少个数据时产生中断、接收 FIFO 中有多少个数据时产生中断。并可以通过设置UFCON n寄存器来复位各个 FIFO 。读取 UFSTAT n寄存器可以知道各个 FIFO 是否已经满、其中有多少个数据。不使用 FIFO 时,可以认为 FIFO 的深度为1,使用 FIFO 时 Exynos4412 的 FIFO 深度最高可达到256 。7. UMCONn寄存器(UART MODEM CONTROL)、UMSTATn寄存器(UART MODEM STATUS)这两类寄存器用于流量控制,里不介绍。8. UTRSTATn寄存器(UART TX/RX STATUS)UTRSTAT n寄存器用来表明数据是否已经发送完毕、是否已经接收到数据,格式如下表所示,下面说的“缓冲区”,其实就是下图中的 FIFO ,不使用 FIFO 功能时可以认为其深度为 1。

9. UERSTATn寄存器(UART ERROR STATUS)用来表示各种错误是否发生,位 [0] 至位 [3] 为 1时分别表示溢出错误、校验错误、帧错误、检测到“ break ”信号。读取这个寄存器时,它会自动清 0。需要注意的是,接收数据时如果使用 FIFO ,则 UART 内部会使用一个“错误 FIFO ”来表明接收 FIFO 中哪个数据在接收过程发生了错误。 CPU 只有在读出这个错误的数据时,才会觉察到发生了错误 。要想清除“FIFO ”,则必须读出错误的数据,并读出UERSTATn 寄存器。10. UTXHn寄存器(UART TRANSMIT BUFFER REGISTER)CPU 将数据写入这个寄存器, UART即会将它保存到缓冲区中,并自动发送出去。11. URXHn寄存器(UART RECEIVE BUFFER REGISTER)当 UART 接收到数据时,读取这个寄存器,即可获得数据。 程序说明1. UART时钟源如在《Tiny4412裸机程序,时钟操作》试验里对 MPLL 进行了设置 ,本程序使用相同的 PLL 设置代码 (文件 system_clock.c 中的 system_clock_init函数 ):[cpp] view plain copyMPLL_CON0 = (1<<31 | 0x64<<16 | 0x3<<8 | 0x0);  
...............  
CLK_SRC_DMC = 0x00011000;  
..............  
CLK_SRC_TOP1 = 0x01111000;  
第 1 行设置MPLL 输出 800MHz,计算公式如下:FOUT = MDIV x FIN / (PDIV x 2 ^ SDIV) = 0x64 x 24MHz / (3 x 2^ 0) = 800MHz第5行设置CLK_SRC_DMC 寄存器的  bit[12] 即 MUXMPLL设置为 1,使得 SCLKMPLL 使用 MPLL的输出,即  800MHz 。第9行设置CLK_SRC_TOP1 寄存器的bit[12] 即 MUX_MPLL_USER_SEL_T为 1,使得 SCLKMPLL_USER_T 使用 SCLKMPLL ,即 800MHz 。下图摘自芯片手册时钟管理单元的章节, 图中 MUXMPLL 和 MUXMPLL_CTRL_USER_T 都被设置为 1,所以 SCLKMPLL_USER_T 就等于 MPLL 的输出,也就是 800MHz 。


SCLKMPLL_USER_T 将作为整个UART 模块的时钟源。2. UART的初始化如上init.c文件所示,注释非常详细,不做说明。3. UART的使用对 UART 的使用,不外乎读取数据、输出。这由 getc 、putc 函数来实现:[cpp] view plain copy// GPIO    
#define GPA0CON (*(volatile unsigned int *)0x11400000)    
// system clock    
#define CLK_SRC_PERIL0 (*(volatile unsigned int *)0x1003C250)    
#define CLK_DIV_PERIL0 (*(volatile unsigned int *)0x1003C550)    
// UART    
#define UFCON0      (*(volatile unsigned int *)0x13800008)    
#define ULCON0      (*(volatile unsigned int *)0x13800000)    
#define UCON0       (*(volatile unsigned int *)0x13800004)    
#define UBRDIV0     (*(volatile unsigned int *)0x13800028)    
#define UFRACVAL0   (*(volatile unsigned int *)0x1380002c)    
#define UTXH0       (*(volatile unsigned int *)0x13800020)    
#define URXH0       (*(volatile unsigned int *)0x13800024)      
#define UTRSTAT0    (*(volatile unsigned int *)0x13800010)    
    
#define CLK_SRC_DMC     (*(volatile unsigned int *)0x10040200)    
#define MPLL_LOCK       (*(volatile unsigned int *)0x10040000)    
#define MPLL_CON0       (*(volatile unsigned int *)0x10040108)  
#define MPLL_CON1       (*(volatile unsigned int *)0x1004010C)  
  
static void uartInit()    
{    
    /* 1.设置相应的GPIO用于串口功能 */    
    unsigned long tmp = 0;    
         
    tmp = GPA0CON;    
    tmp &= ~(0xff); //设置UART0对应的GPIO为UART功能    
    tmp |= 0x22;    
    GPA0CON = tmp;    
         
    /* 2.设置 UART 时钟源 SCLK_UART */    
    CLK_SRC_PERIL0 = ((0 << 24) | (0 << 20) | (6 << 16) | (6 << 12) | (6<< 8) | (6 << 4) | (6));    
         
    /* 分频系数 = 7+1 = 8 CLK_DIV_PERIL0 : bit[3:0]即UART0_RATIO=7,所以SCLK_UART0=MOUTUART0/(7+1)=100MHz */    
    CLK_DIV_PERIL0 = ((7 << 20) | (7 << 16) | (7 << 12) | (7 << 8) | (7 << 4) | (7));    
      
    /* 设置MPLL 为 800 MHz */  
    CLK_SRC_DMC = 0x0;  
    MPLL_LOCK   = 270 * 3;    
    MPLL_CON0   = 0x80640300;  
    MPLL_CON1   = 0x00803800;  
    CLK_SRC_DMC = 0x00011000;  
      
    /* 3.设置串口0相关 设置FIFO中断触发阈值 32使能FIFO */    
    UFCON0 = 0x111;    
         
    /* 设置数据格式: 8n1, 即8个数据位,没有较验位,1个停止位 */    
    ULCON0 = 0x3;    
         
    /* 工作于中断/查询模式,另一种是DMA模式,本章不使用 */    
    UCON0 = 0x5;    
         
    /* 
     * SCLK_UART0=100MHz, 波特率设置为115200  
     * 寄存器的值如下计算:  
     * DIV_VAL = 100,000,000 / (115200 * 16) - 1 = 53.25  
     * UBRDIVn0 = 整数部分 = 53  
     * UFRACVAL0 = 小数部分 x 16 = 0.25 * 16 = 4  
     */    
    UBRDIV0 = 53;    
    UFRACVAL0 = 4;       
}    
     
static char getchar(void)    
{    
    char c;    
    /* 查询状态寄存器,直到有有效数据 */    
    while (!(UTRSTAT0 & (1<<0)));    
         
    c = URXH0; /* 读取接收寄存器的值 */    
         
    return c;    
}    
     
static void m_putchar(char c)    
{    
    /* 查询状态寄存器,直到发送缓存为空 */    
    while (!(UTRSTAT0 & (1<<2)));    
         
    UTXH0 = c; /* 写入发送寄存器 */    
         
    return;    
}    
     
static void putstr(char *s)    
{    
    while (*s)    
    {    
        m_putchar(*s);    
        s++;    
    }    
}   
int main(void)    
{    
    char rec;    
    uartInit();    
    putstr("uart init ok!!!");       
    while(1)    
    {    
        rec = getchar();  
        rec++;    
        m_putchar('\r');    
        m_putchar('\n');    
        m_putchar(rec);    
    }        
    return 0;    
}    

在 main 函数里,就是调用getc 、putc 来实现我们的目:获取字符,加 1后输出:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: