历史上的今天
返回首页

历史上的今天

今天是:2024年12月09日(星期一)

正在发生

2021年12月09日 | tiny4412 UART 收发数据

2021-12-09 来源:eefocus

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.25

UBRDIVn = 整数部分 = 53

UFRACVALn/16 = 小数部分 = 0.25

UFRACVALn = 4

4. 设置传输格式: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函数 ):


  1. MPLL_CON0 = (1<<31 | 0x64<<16 | 0x3<<8 | 0x0);  

  2. ...............  

  3. CLK_SRC_DMC = 0x00011000;  

  4. ..............  

  5. 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 函数来实现:


  1. // GPIO    

  2. #define GPA0CON (*(volatile unsigned int *)0x11400000)    

  3. // system clock    

  4. #define CLK_SRC_PERIL0 (*(volatile unsigned int *)0x1003C250)    

  5. #define CLK_DIV_PERIL0 (*(volatile unsigned int *)0x1003C550)    

  6. // UART    

  7. #define UFCON0      (*(volatile unsigned int *)0x13800008)    

  8. #define ULCON0      (*(volatile unsigned int *)0x13800000)    

  9. #define UCON0       (*(volatile unsigned int *)0x13800004)    

  10. #define UBRDIV0     (*(volatile unsigned int *)0x13800028)    

  11. #define UFRACVAL0   (*(volatile unsigned int *)0x1380002c)    

  12. #define UTXH0       (*(volatile unsigned int *)0x13800020)    

  13. #define URXH0       (*(volatile unsigned int *)0x13800024)      

  14. #define UTRSTAT0    (*(volatile unsigned int *)0x13800010)    

  15.     

  16. #define CLK_SRC_DMC     (*(volatile unsigned int *)0x10040200)    

  17. #define MPLL_LOCK       (*(volatile unsigned int *)0x10040000)    

  18. #define MPLL_CON0       (*(volatile unsigned int *)0x10040108)  

  19. #define MPLL_CON1       (*(volatile unsigned int *)0x1004010C)  

  20.   

  21. static void uartInit()    

  22. {    

  23.     /* 1.设置相应的GPIO用于串口功能 */    

  24.     unsigned long tmp = 0;    

  25.          

  26.     tmp = GPA0CON;    

  27.     tmp &= ~(0xff); //设置UART0对应的GPIO为UART功能    

  28.     tmp |= 0x22;    

  29.     GPA0CON = tmp;    

  30.          

  31.     /* 2.设置 UART 时钟源 SCLK_UART */    

  32.     CLK_SRC_PERIL0 = ((0 << 24) | (0 << 20) | (6 << 16) | (6 << 12) | (6<< 8) | (6 << 4) | (6));    

  33.          

  34.     /* 分频系数 = 7+1 = 8 CLK_DIV_PERIL0 : bit[3:0]即UART0_RATIO=7,所以SCLK_UART0=MOUTUART0/(7+1)=100MHz */    

  35.     CLK_DIV_PERIL0 = ((7 << 20) | (7 << 16) | (7 << 12) | (7 << 8) | (7 << 4) | (7));    

  36.       

  37.     /* 设置MPLL 为 800 MHz */  

  38.     CLK_SRC_DMC = 0x0;  

  39.     MPLL_LOCK   = 270 * 3;    

  40.     MPLL_CON0   = 0x80640300;  

  41.     MPLL_CON1   = 0x00803800;  

  42.     CLK_SRC_DMC = 0x00011000;  

  43.       

  44.     /* 3.设置串口0相关 设置FIFO中断触发阈值 32使能FIFO */    

  45.     UFCON0 = 0x111;    

  46.          

  47.     /* 设置数据格式: 8n1, 即8个数据位,没有较验位,1个停止位 */    

  48.     ULCON0 = 0x3;    

  49.          

  50.     /* 工作于中断/查询模式,另一种是DMA模式,本章不使用 */    

  51.     UCON0 = 0x5;    

  52.          

  53.     /* 

  54.      * SCLK_UART0=100MHz, 波特率设置为115200  

  55.      * 寄存器的值如下计算:  

  56.      * DIV_VAL = 100,000,000 / (115200 * 16) - 1 = 53.25  

  57.      * UBRDIVn0 = 整数部分 = 53  

  58.      * UFRACVAL0 = 小数部分 x 16 = 0.25 * 16 = 4  

  59.      */    

  60.     UBRDIV0 = 53;    

  61.     UFRACVAL0 = 4;       

  62. }    

  63.      

  64. static char getchar(void)    

  65. {    

  66.     char c;    

  67.     /* 查询状态寄存器,直到有有效数据 */    

  68.     while (!(UTRSTAT0 & (1<<0)));    

  69.          

  70.     c = URXH0; /* 读取接收寄存器的值 */    

  71.          

  72.     return c;    

  73. }    

推荐阅读

史海拾趣

Accetek公司的发展小趣事

随着产品质量的不断提升和市场口碑的积累,Accetek公司开始积极拓展国内外市场。公司参加了多个国际电子展览和交流活动,与全球多家知名企业建立了合作关系。同时,公司还加强了品牌建设和市场推广工作,通过广告宣传、媒体合作等方式提高品牌知名度和美誉度。这些举措有效地提升了公司的市场竞争力,为公司的快速发展提供了有力支持。

Eagle Plastic Devices公司的发展小趣事

进入21世纪后,随着信息化和智能化技术的快速发展,Eagle Plastic Devices公司开始积极推动数字化转型和智能制造。公司引入了先进的信息化管理系统和智能生产设备,实现了生产过程的自动化和智能化。这不仅提高了生产效率和产品质量,还降低了生产成本和人力资源投入。同时,公司还利用大数据和人工智能技术优化供应链管理、市场营销等方面的工作,进一步提升了公司的综合竞争力。

EOZ S.A.S公司的发展小趣事

为了进一步扩大市场份额,EOZ S.A.S公司积极实施国际化战略。公司通过参加国际电子展、建立海外研发中心和生产基地等方式,加强与国际市场的联系和合作。同时,EOZ S.A.S还针对不同国家和地区的消费者需求进行产品定制和本地化营销,成功将产品打入多个国际市场并取得良好业绩。

HellermannTyton公司的发展小趣事

面对全球经济波动和行业竞争加剧的挑战,Heimann Optoelectronics Gmbh果断实施转型升级战略。公司加大在物联网、人工智能等新兴技术领域的研发投入,成功开发出了一系列智能光电传感器和解决方案。这些产品能够实时监测环境变化、智能控制设备运行,为智慧城市、智能家居等领域提供了强有力的支持。通过转型升级,公司不仅巩固了传统市场的领先地位,还成功开拓了新的增长点。

CTC [Compact Technology Corp.]公司的发展小趣事

CTC公司深知人才是企业发展的核心。因此,公司一直注重人才培养和引进。通过与高校和研究机构的合作,CTC公司吸引了大批优秀的科研人才加入。同时,公司还建立了完善的培训体系,为员工提供持续的技能提升和职业发展机会。这些人才成为了CTC公司发展的中坚力量,为公司构筑了核心竞争力。

Altmustech公司的发展小趣事

为了进一步扩大市场份额,Altmustech积极寻求与行业内外的战略合作。公司与多家知名企业签订了长期合作协议,共同研发新产品,开拓新市场。通过这些合作,Altmustech不仅获得了更多的资源支持,还提高了品牌知名度,进一步巩固了其在电子行业的地位。

问答坊 | AI 解惑

刚学visual studio 2005 下VC++编串口通信老是弄不通

private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {                         if(COM1->Checked == true)   &nbs ...…

查看全部问答>

我想用testcap写了个虚拟摄像头驱动程序,但是我怎么把视频数据传递给驱动呢,谢谢你们指教!

我想用testcap写了个虚拟摄像头驱动程序,但是我怎么把视频数据传递给驱动呢,谢谢你们指教!…

查看全部问答>

wince下的ftp客户端问题

在wince(或wm5)下实现ftp客户端后,用gprs发数据失败 听说gprs在某一时间只会分配不固定的IP和一个可用端口,而ftp需要2个,一个传信息,一个传数据 请问如果用类似NAT穿透的技术能否达到目的? 我主要是想从wince上传文件到服务器,很多人都 ...…

查看全部问答>

labview怎么跟汇编语言联啊

想用labveiw做一些接口实验,但是需要用到汇编语言,怎么联啊…

查看全部问答>

纳米测量中学习曲线 和灵敏度/分辨率的挑战

仪器操作中繁琐的编程[1]工作以及神秘的种种细节会分散工作繁重的研究者的精力。许多电特性测量工具[2]都极为复杂,而且它们的数据传输机制极为冗琐,需要大容量的存储介质。图形分析所花费的时间也过长。学习和编程设定的工作会占用本来应该用于 ...…

查看全部问答>

用线程解决网络断开重连的问题

网络断开重连-------线程   网络断开后重连的问题,可以使用线程去重连,即创建一个线程专门负责去建立连接,如果连接断开,则由这个线程去重新连接,连接完成后,这个线程则会阻塞(休眠)。        ...…

查看全部问答>

FIR滤波问题

void fir_filter(void) {         int i,j;         float sum;         float x1[932];         float h[31]={ 0.01492972,0.01096342,0.01458647,0.0186, ...…

查看全部问答>

【TI首届低功耗设计大赛】第二个外设程序 MSP430FR5969读取ADXL362数据通过CC1101发送

本帖最后由 littleshrimp 于 2014-12-27 13:24 编辑 世界上最低功耗的MCUMSP430FR5969+世界最低功耗的加速度传感器ADXL362堪称完美组合。组合完能嘎蛤?谁知道,先跑起来再说。MSP430FR5969就不介绍了,那不是一搬的强大。ADXL362是一款超低功耗 ...…

查看全部问答>

TMDSEVM6678L

2015年2月份才能入关发货,还没到手,够新了吧,想换个达芬奇系列开发板,XDS560仿真器也行…

查看全部问答>