USART硬件及接收驱动的详细说明

来源:互联网 发布:上网记录查询软件 编辑:程序博客网 时间:2024/05/29 13:21
 USART硬件及接收驱动的详细说明

杨晔   2003-2-16   ver0.1
                               2003-2-19   ver0.2
notice:以下的说明都是针对skyeye中的UART模拟部份,并不是真实的硬件,两者还是有区别的,所以如果要把skyeye的程序移植到真实的硬件上,请参考硬件手册作修改!


一、skyeye对USART所作的模拟为:
目前仅模拟了UART0(当然加上UART1也是很容易的,只要去掉一个注释),UART0的基址为0xfffd0000,下面是偏移量。

US_RPR:0x30 存放指向接收缓冲区地址的指针(注意本寄存器是只写的!!)
       注意本寄存器的工作原理!:每接收一个字符,rpr会加1,即指向缓冲区的下一个位置。所以为清晰安全起见,一般在UART ISR的最后会把rpr重新设置为指向缓冲区头部。


US_RCR:0x34 存放接收缓冲区大小(1-65535),如果设为0就是停止USART的接收。
       注意本寄存器的工作原理!:每接收一个字符,rcr会减1。所以在ISR中要看实际rpr指向的缓冲区中收了多少字符,就应该用rcr的预设值(如256)减去rcr的当前值得到字符个数。然后从接收缓冲读取字符。一般在UART ISR的最后会把rcr重新设为预设值如256。

US_TPR:0x38 存放指向发送缓冲区地址的指针
US_TCR:0x3c 存放发送缓冲区大小(1-65535),如果设为0就是停止USART的发送。此寄存器被写入后立即开始发送US_TPR指向的buf中的tcr个字符。(skyeye里发送就是打印)

只读寄存器:
US_CSR:0x14
USART状态寄存器。目前读该寄存器的返回值为 0B100000x01x。其中的前两个1(9位和2位上)表示USART可以发送(TXRDY),这两位在skyeye中始终为1。最后一位是接收状态,根据是否接收到数据决定。如果没有输入,最低位为0,CSR=0B1000000010;如果rcr不为0 ,则3位和0位(RXRDY)上都为1,表明接收到输入字符,也就是CSR=0B1000001011。总结起来CSR只有以上两种状态值。
     但是这里引入了问题:
如果用户设置了rcr寄存器等待接收字符,但还没有输入,此时的rcr>0,那么如果读csr寄存器会发现RxRdy位也为1,即还没有输入csr的状态就成了有输入;
或者用户设置rcr寄存器为10,skyeye又接收了10个字符,此时rcr寄存器为0,读出的csr寄存器的RxRdy为0,明明有输入了但csr的状态确是无输入。   
以上两个问题,说明目前不能用csr寄存器来判断UART的输入状态。

只写寄存器:
US_THR:0x1c
        USART发送寄存器,写入此寄存器的字符被立即发送(在skyeye中就是打印)。


二、skyeye内部机制:
   在io_do_cycle中,如果rcr>0,就会检查键盘当前有没有输入,没有立即返回。如果有输入,则根据输入字符的个数从键盘读取n个字符存放到rpr指向的内存中,rcr=rcr-n,然后raise usart 的输入中断。

三、本接收驱动的说明:
   目前本驱动仅处理USART的接收部份,发送部份依然用liming原来的at91_usart.c和skyeye_printf。
   驱动分为下层硬件部份serial.c和上层serialucos.c两部份。

1、下层硬件部份有三个模块:
void UART0ISR(void);   
//uart0 的接收isr,负责从硬件接收缓冲区receive_buf(设定为256个字节的深度)读出接收到的字符,并放入上层的ucos环形缓冲区中。

void CommRxIntDis(INT8U ch);  
//关闭usart0的接收中断

void CommRxIntEn(INT8U ch);   
//初始化usart0,并打开接收中断。这里的初始化就是写rcr=256,rpr=&receive_buf[0]。
打开和关闭中断是处理的AIC中断控制器的imr寄存器,见aic部份。参数ch是指明控制usart0还是usart1,目前只处理usart0,但为了将来的扩展还是保留了一个参数。

2、上层ucos部份主要是建立了环形接收缓冲区,并使用信号量来控制接收,如下:
void CommPutRxChar (INT8U ch, INT8U c);
//由ISR调用,负责把从硬件接收到的字符放入环形缓冲区,并发出信号量唤醒等待uart输入的任务。

BOOLEAN CommIsEmpty (INT8U ch)
//检查环形缓冲区是否为空,使用这个函数可以实现轮询式uart输入。ch依然是指明控制usart0还是usart1。

void CommInit (void)
//初始化环形缓冲队列,主要是对COMM_RING_BUF结构定义的UART0BUF进行初始化。

INT8U CommGetChar (INT8U ch, INT16U time_out, INT8U *err)
//这是整个接收驱动对外界的接口。任务调用此函数,如果环形缓冲队列中有字符,立即返回该字符,如果没有,任务休眠(有timeout时间,time_out为0则永远等待),直到有字符输入发出信号量唤醒任务,或者timeout到期返回NULL。

环形缓冲区结构:
typedef struct {
    INT16U     RingBufRxCtr;          /* Number of characters in the Rx ring buffer              */
    OS_EVENT *RingBufRxSem;          /* Pointer to Rx semaphore    */
    INT8U     *RingBufRxInPtr;        /* Pointer to where next character will be inserted        */
    INT8U     *RingBufRxOutPtr;      /* Pointer from where next character will be extracted */
    INT8U      RingBufRx[COMM_RX_BUF_SIZE]; /* Ring buffer character storage (Rx)                 */
} COMM_RING_BUF;
原创粉丝点击