主机平台:Linux CentOS 6.5
arm平台:粤嵌GEC210开发板(S5PV210)
这次写一下串口的驱动,功能是在linux终端中键入并向arm发送一个字符,arm返回这个字符将其在终端上显示。
其中,串口采用串口0,非FIFO模式,波特率115200,8位数据为,无较检位,接收用中断方式,发送用查询方式。
既然用到中断,那还是按就之前写中断的步骤进行:
(1--7步是中断通用部分,依然省略,不懂的话看我的另一篇文章:GEC210(S5PV210)裸机驱动之中断系统)
8.编写外设对应的中断服务程序
8.1.根据标志为判断发生了什么中断。(当多个中断共享一个中断号时通常需要做此判断)
8.2.根据发生的中断执行相应的任务
8.3.清除所发生中断的中断标志位
8.4.清除全部VICxADDR(置0)
8.5.重新使能全局IRQ中断(进入中断后,全局IRQ中断会被关闭)
9.设置外设寄存器初始化外设(包括清除中断标志位,使能中断等操作)
9.1.关闭外设寄存器的中断使能
9.2.清除外设中断标志位
9.3.初始化设置与外设相关的其它寄存器。例如I/O的功能选择(这个容易忘记),设置输入时钟频率等等。
9.4开启外设对应中断
10.根据外设查找中断源表获得其中断号
11.根据中断号设置对应的中断服务程序入口地址寄存器(VICxVECTADDRx)
12.根据中断号使能对应中断
下面就是针对串口将每个步骤具体化:
8.编写外设对应的中断服务程序
8.1.判断该次中断是否串口的发送中断、接收中断、还是错误中断
8.2.执行对应任务,此处是只当为接收中断时,通过查询方式将获得的数据发送出去
8.3.清除对应中断标志位(UINTSP0和UINTP0)
8.4.清除全部VICxADDR(置0)
8.5.重新使能全局IRQ中断(进入中断后,全局IRQ中断会被关闭)
9.设置外设寄存器初始化外设(包括清除中断标志位,使能中断等操作)
9.1.关闭串口0中断使能(UINTM0[3:0])
9.2.清除串口0中断所有标志位 (UINTSP0[3:0]和UINTP0[3:0])
9.3
(1)将串口0对应的IO引脚功能设置为UART_0_RXDGPA0CON[3:0] 和 UART_0_TXD(GPA0CON[7:4])
(2)设置波特率。波特率由PCLK时钟、UCON[10]、UBRDIV、UDIVSLOT寄存器确定
公式:
DIV_VAL = UBRDIVn + (num of 1's in UDIVSLOTn)/16
DIV_VAL = (PCLK / (bps x 16)) −1
or
DIV_VAL = (SCLK_UART / (bps x 16)) −1
此处,时钟源选择PCLK(UCON[10]=0),为66M,且UDIVSLOTn=0,因此由第1、2条公式得:
UBRDIV0 = (66M/(115200*16))-1 = 35
(3)设置帧格式,包括数据位位数、停止位位数、较检方式(ULCON0)
(4)配置UCON寄存器,里面有很多设置,我讲一些个人认为比较重要的,其它没看懂的话就保持默认值吧
[10]:波特率时钟源选择位
[9:8]:Tx/Rx Interrupt Type:手册上写这两位必须置1
[5]:Loop-back Mode ,即回环测试模式,可以自发自收
[3:2]:Transmit Mode:什么情况下允许写串口发送寄存器 00:不可写;01:可通过中断或查询方式写入;10:在DMA模式下可写
[1:0]:Receive Mode:什么情况下允许读串口接收寄存器 00:不可写;01:可通过中断或查询方式写入;10:在DMA模式下可写
9.4.使能串口中断,这里只使能接收中断(UINTM0[0])
10.根据外设查找中断源表获得其中断号,可知中断号为42
11.根据中断号设置对应的中断服务程序入口地址寄存器(VIC3VECTADDR10)
12.根据中断号使能对应中断(VIC3INTENABLE[10])
跟着再讲下如何发送和接收,这里比较简单
发送:先判断串口是否空闲,然后向发送缓冲寄存器写入数据
接收:在中断中直接读接收缓冲寄存器就可以了
具体实现看下面代码:
void uart0_int_func()
{
unsigned long temp;
if(UTRSTAT0&0x1) //判断是否为接收中断
{
temp=URXH0; //读取接收寄存器
while(!(UTRSTAT0&0x2)); //等待串口空闲
UTXH0=temp; //发送接收到的内容
UINTSP0|=0xf; //清除中断标志位
UINTP0|=0xf; //清除中断标志位
clear_vicaddress(); //清除全部VICADDR寄存器
}
enable_global_IRQ(); //使能全局IRQ中断
}
void uart0_init()
{
ULCON0|=0x3; //设置帧格式
UCON0=0x305; //时钟源、读写发送接收寄存器模式
UBRDIV0=35; //设置波特率
UINTM0=0xf; //屏蔽所有串口中断
GPA0CON=0x22; //设置引脚功能为串口收发
UINTSP0|=0xf; //清除中断标志
UINTP0|=0xf; //清除中断标志
set_int_vectaddr(42,uart0_int_func); //设置42号中断服务程序入口地址
interrupt_enable(42); //使能中断系统42号中断
UINTM0=0xe; //使能串口接收中断
}
好了,这就是一个简单的串口程序,串口还有很多种模式的,例如FIFO、Infrared、DMA等模式,这些就要以后慢慢去深入学习了。