打印
[DSP编程]

异步串口UART程序没看明白,希望大家点拨下

[复制链接]
1407|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ttxs_2013|  楼主 | 2014-3-19 20:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在做异步串口UART实验,对厂家提供的例程没看明白,例程中没有任何注释,想了几天都没想明白,代码和原理是如何对应的?例程
/*********************************************************************
**        Module Name:                UART                                                                            **
**        Author:                                CTH                                                                              **
**        Version:                        1.0                                                                                    **
**        CreateDate:                        2008-8-10                                                                    **
**        Description:                                                                                        **
**        Remark:                                                                                                                  **
**        Revision History:  2008-8-10                                                                    **
**  Web:                                http://www.study-kit.com                                        **
**********************************************************************/

/*********************************************************************
** start:2014-3-15 pm 2:00                          ******************
** end  :2014-3-                                    ******************
*********************************************************************/

#include <csl.h>
#include <csl_pll.h>
#include <csl_emif.h>
#include <csl_chip.h>
#include <stdio.h>
  
#define UART_BASE_ADDR                        0x200008    // UART寄存器地址   
/*异步通信接口芯片INS 8520 内部寄存器*/
#define RHR                                *((int *)(UART_BASE_ADDR+0))
#define THR                                *((int *)(UART_BASE_ADDR+0))       
#define IER                                *((int *)(UART_BASE_ADDR+1))
#define ISR                                *((int *)(UART_BASE_ADDR+2))       
#define FCR                                *((int *)(UART_BASE_ADDR+2))       
#define LCR                                *((int *)(UART_BASE_ADDR+3))
#define MCR                                *((int *)(UART_BASE_ADDR+4))
#define LSR                                *((int *)(UART_BASE_ADDR+5))
#define MSR                                *((int *)(UART_BASE_ADDR+6))
#define SCR                                *((int *)(UART_BASE_ADDR+7))
#define DLL                                *((int *)(UART_BASE_ADDR+0))
#define DLM                                *((int *)(UART_BASE_ADDR+1))

#define DLL_DATA 0x48//定义UART分频系数,在11.05926M时,波特率为9600BPS
#define DLM_DATA 0x00


CSLBool b;
Uint16 eventId0;
int old_intm;
interrupt void int0(void);  //外部中断0
unsigned char str1[]={"study-kit.com   "};
unsigned char str2[]={"TEL:010-82623343"};
extern void VECSTART(void);

void Delay(unsigned int nDelay);
/*锁相环的设置*/
PLL_Config  myConfig      = {
  0,    //IAI: the PLL locks using the same process that was underway
                //before the idle mode was entered
  1,    //IOB: If the PLL indicates a break in the phase lock,
                //it switches to its bypass mode and restarts the PLL phase-locking
                //sequence
  12,    //PLL multiply value; multiply 12 times
  0             //Divide by 2 PLL divide value; it can be either PLL divide value
                //(when PLL is enabled), or Bypass-mode divide value
                //(PLL in bypass mode, if PLL multiply value is set to 1)
};
/*SDRAM的EMIF设置*/
EMIF_Config emiffig = {
  0x221,         //EGCR  : the MEMFREQ = 00,the clock for the memory is equal to cpu frequence
                          //                  the WPE = 0 ,forbiden the writing posting when we debug the EMIF
                          //        the MEMCEN = 1,the memory clock is reflected on the CLKMEM pin
                          //        the NOHOLD = 1,HOLD requests are not recognized by the EMIF
  0xFFFF,        //EMI_RST: any write to this register resets the EMIF state machine

  0x1fff,        //CE3_1:  CE0 space control register 1
  0x00ff,        //CE3_2:  CE0 space control register 2
  0x00ff,        //CE3_3:  CE0 space control register 3  

  0x1fff,        //CE1_1:  CE0 space control register 1
            //        Asynchronous, 16Bit
  0x00ff,        //CE1_2:  CE0 space control register 2
  0x00ff,        //CE1_3:  CE0 space control register 3

  0x1FFF,        //CE2_1:  CE0 space control register 1
            //        Asynchronous, 16Bit
  0xFFFF,        //CE2_2:  CE0 space control register 2
  0x00FF,        //CE2_3:  CE0 space control register 3
  
  0x1fff,        //CE3_1:  CE0 space control register 1
  0x00ff,        //CE3_2:  CE0 space control register 2
  0x00ff,        //CE3_3:  CE0 space control register 3
  
  0x2911,   //SDC1:   SDRAM control register 1
                          //                  TRC = 8
                          //        SDSIZE = 0;SDWID = 0
                          //        RFEN = 1
                          //        TRCD = 2
                          //        TRP  = 2
  0x0410,        //SDPER : SDRAM period register
                          //                  7ns *4096
  0x07FF,    //SDINIT: SDRAM initialization register
                          //        any write to this register to init the all CE spaces,
                          //        do it after hardware reset or power up the C55x device
  0x0131        //SDC2:          SDRAM control register 2
                          //        SDACC = 0;
                          //        TMRD = 01;
                          //        TRAS = 0101;
                          //        TACTV2ACTV = 0001;                                                               
  };

/*中断配置*/
void INTconfig()
{
    /* Temporarily disable all maskable interrupts */
    IRQ_setVecs((Uint32)(&VECSTART));

        /* Temporarily disable all maskable interrupts */
    old_intm = IRQ_globalDisable();

        /* Get Event Id associated with External INT1(8019), for use with */
        eventId0 = IRQ_EVT_INT0;

        /* Clear any pending INT0 interrupts */
        IRQ_clear(eventId0);

        /* Place interrupt service routine address at */
    /* associated vector location */
    IRQ_plug(eventId0,&int0);

        /* Enable INT0(8019) interrupt */
    IRQ_enable(eventId0);

        /* Enable all maskable interrupts */
    IRQ_globalEnable();   
}
void  delay(unsigned int d_time)
{
        while(d_time--);
}

main()
{
    unsigned int temp,data,i,k;
        /*初始化CSL库*/       
    CSL_init();
   
    /*EMIF为全EMIF接口*/
    CHIP_RSET(XBSR,0x0a01);
   
    /*设置系统的运行速度为144MHz*/
    PLL_config(&myConfig);
   
    /*初始化DSP的EMIF*/
    EMIF_config(&emiffig);
   
        INTconfig();

    /*UART初始化*/
           LCR = 0x80;      //设置波提率 通信线路控制寄存器
        temp=LCR;        //通信线路控制寄存器
        DLL = DLL_DATA;  //写除数低8位   
        DLM = DLM_DATA;  //写除数高8位
        temp=DLL_DATA;
        LCR = 0x00;     //设置通信的数据格式,D7=0
        LCR = 0x03;    //8位数据,一个停止位       
        FCR = 0x00;    //FIFO控制寄存器,在非FIFO模式
        MCR = 0x08;    //调制解调控制寄存器,OUT2=1,中断信号可通过系统总线送给8520中断控制寄存器
        IER = 0x00;    //中断使能寄存器禁止,4种中断都禁止
   

    while(1)
    {
        /*发送字符串*/
                /*for(k=0;k<16;k++)
                  {
                      THR=str1[k];
                      delay(200);
                   }

                for(k=0;k<16;k++)
                  {
                      THR=str2[k];
                      delay(200);
                   }  
      delay(5000); */
      
     
          temp=LSR;   //通信线路状态寄存器
          data=ISR;   //中断识别寄存器,判别中断的类型 ,但是从下面的代码中,不明白它的作用体现在哪条语句?
         THR =0x55;  //发送保持寄存器,要发送的数据是U,对应16进制ASCII
          if(temp&0x01)
          {  
                    data=RHR; //发送的字符已到达接收缓冲寄存器
                THR=data;
                    temp=0;
          }                                    
         delay(5000);

    }


         
}
void Delay(unsigned int nDelay)
{
        int ii,jj,kk=0;
        for ( ii=0;ii<nDelay;ii++ )
        {
                for ( jj=0;jj<1024;jj++ )
                {
                        kk++;
                }
        }
}



//External INT0(EXINT)中断处理函数
interrupt void int0()
{
   unsigned int temp,data,i;
          temp=LSR;
          data=ISR;

           if(temp&0x01)//LSR的最低位不为0,表示数据已经准备好接收
            {  
            data=RHR;  //接收保持寄存器的值送到发送保持寄存器
                THR=data;
            temp=0;
            }  
}
/******************************************************************************\
* End of UART.c
\******************************************************************************/
不明白的地方有:
1)IER = 0x00;   中断都禁止了,又怎么产生中断?
2)while中的temp应该是只能检测到LSR的第0位DR的状态,为1表示接受数据准备好,当中断使能时,这时候是不是应该进入中断的?这里if语句的功能是什么?
3)中断程序中,ISR的作用体现在哪里,似乎没用到?while程序和中断程序为什么是一样的代码,中断中应该是字符的写入或者从接受缓冲寄存器中读数据,那while中语句又是什么意思?

感觉原理明白了,但是结合到代码,又有好多疑问,没想通。

相关帖子

沙发
zhangmangui| | 2014-3-19 21:27 | 只看该作者
用到了 8520   不懂  帮忙顶

使用特权

评论回复
板凳
ttxs_2013|  楼主 | 2014-3-19 22:44 | 只看该作者
zhangmangui 发表于 2014-3-19 21:27
用到了 8520   不懂  帮忙顶

这个只是自己在网上查的计算机串口通讯的资料,实际上DSP 中用的不是这个芯片,是sp3232,原理是一样的,我没有改过来。我的问题是代码部分,版主不要被8520欺骗了,希望指点。

使用特权

评论回复
地板
zhangmangui| | 2014-3-19 22:49 | 只看该作者
ttxs_2013 发表于 2014-3-19 22:44
这个只是自己在网上查的计算机串口通讯的资料,实际上DSP 中用的不是这个芯片,是sp3232,原理是一样的, ...

明天帮你找找相关代码  

使用特权

评论回复
5
pinda_| | 2014-3-20 11:19 | 只看该作者
:L先看看再说。

使用特权

评论回复
6
pinda_| | 2014-3-20 11:36 | 只看该作者
1)IER = 0x00;   中断都禁止了,又怎么产生中断?
答:我不明白,为什么不放在系统时钟配置完之后,放在这里确实禁止中断。只是,我们一般可以通过中断初始化来开始,所以,感觉这里应该有个逻辑错误。
2)while中的temp应该是只能检测到LSR的第0位DR的状态,为1表示接受数据准备好,当中断使能时,这时候是不是应该进入中断的?这里if语句的功能是什么?
答:如果按照上一步正确的思想,这里有一种轮循的意思(好像是这样),不停的判断当前接收数据的状态,如果数据成功接收,表明接收FIFO中已经存在数据,LSR被置位,软件将数据从FIFO中读取出来。
3)中断程序中,ISR的作用体现在哪里,似乎没用到?while程序和中断程序为什么是一样的代码,中断中应该是字符的写入或者从接受缓冲寄存器中读数据,那while中语句又是什么意思?
答:一个是中断接收, 一个是轮循接收。这个要看情况的,中断比较浪费资源,轮循数据接收一旦快了,感觉会丢帧,但是接收能力,个人感觉比中断厉害。

最后,看这个代码,怎么有一种处于回环模式的感觉。  8520不懂,忘指教。

使用特权

评论回复
7
ttxs_2013|  楼主 | 2014-3-20 22:58 | 只看该作者
pinda_ 发表于 2014-3-20 11:36
1)IER = 0x00;   中断都禁止了,又怎么产生中断?
答:我不明白,为什么不放在系统时钟配置完之后,放在这 ...

按照你说的思路,我研究了下,觉得还是和代码不符:
第一个,这段代码中并没有轮循模式,因为 FCR = 0x00 是在非FIFO模式
第二个,如果说有轮循的话,参考资料对轮循的解释是:FIFO轮循模式—FIFO使能而相关的中断被禁止,CPU通过轮循状态位来检测事件。而我也把代码按照此模式改动了下,即FCR=0x01,IER=0x00,但是调试时,没有结果。
第三个,关于while和interrupt代码一样,你的解释是一个是中断接受,一个是轮循接收,但我觉得既然有中断的,那轮循不是多余 的,用一个不就就够了,并且也和第二点的FIFO轮循模式的解释相矛盾。

沿着楼主说的FIFO,轮循,参考了下资料,试着把代码改成 FIFO的中断模式(FIFO被使能而相关的中断也被使能,在事件发生时向CPU发送中断),基于此,代码改为:FCR=0x01,IER=0x07(四种中断都打开),结果也能够接受到数据。原代码中断禁止并且在非FIFO模式,同样接受成功,感觉很奇怪。

此外,还想请教楼主的是:
data=ISR ,当有中断使能,中断事件发生,ISR被置位,于是请求CPU执行中断程序,但是在If语句中为什么也是把RHR幅值给data,if中的data可以改成其他的变量吗?
还有,如果if语句是表示从接受缓冲寄存器中读数据,那么数据最终会读到哪里去?代码中是从接受缓冲到发送保持,为什么?
还有当发送移位寄存器为空,应该发送写中断,重新写入下一个字符,那么写入字符又是从哪里写入的?中断中肯定是既有写也有读,但是代码是一样的,难道也是从接受缓冲到发送保持?

以上只是我自己的理解,不知道对不对,还望楼主指教!

使用特权

评论回复
8
pinda_| | 2014-3-21 09:09 | 只看该作者
ttxs_2013 发表于 2014-3-20 22:58
按照你说的思路,我研究了下,觉得还是和代码不符:
第一个,这段代码中并没有轮循模式,因为 FCR = 0x00 ...

首先,我确实对8520不是很懂,那些寄存器相关的说明,不是很明白。只是根据你这个代码(原来是来自网上例程,刚刚看到)来分析罢了。。。

第一,当每次只发一个数据的时候,为什么要把FIFO打开,浪费了。。。我的理解是FIFO有点类似DMA的功能,看发送数据的多少才去决定,要不要使用它。

第二,根据你之前说的 “ LSR的第0位DR的状态,为1表示接受数据准备好,”,那么,temp时时会对数据接收状态进行判断,这不是轮循模式?如果不是,关于LSR的状态说明本身就是错的。

第三,这个代码是网上的,一般网上的例程都包含多个功能,如果是官方提供的,它会注释。如果不是官方的,那么我也无法解释。(最好的方法,把中断去掉,做轮循测试;再把WHILE中IF相关的去掉,测中断,分开来尝试下,理论的分析,永远也没用,要动手试试,独立开来)

最后,我上面说了,这是回环模式,也就是自己发送自己接收,这是全双工下,很好用的调试方法,好像也就UART用用吧。发送写中断,我没有看到,不明白你说的意思。

再再最后,澄清下,我不是楼主,你才是楼主,哈哈。还望指教。



使用特权

评论回复
9
pinda_| | 2014-3-21 09:19 | 只看该作者
ttxs_2013 发表于 2014-3-20 22:58
按照你说的思路,我研究了下,觉得还是和代码不符:
第一个,这段代码中并没有轮循模式,因为 FCR = 0x00 ...

补充,中断接收与轮循接收同时存在时,程序进入中断接收,接收完后,该状态寄存器被复位,那么,也就进不了轮循了。

使用特权

评论回复
10
ttxs_2013|  楼主 | 2014-3-22 22:52 | 只看该作者
pinda_ 发表于 2014-3-21 09:19
补充,中断接收与轮循接收同时存在时,程序进入中断接收,接收完后,该状态寄存器被复位,那么,也就进不 ...

首先得说明下,你的思路的确是正确的,只是例程本身就有些误人子弟。按照你说的调试方法,我分别测试了

       UART工作模式                            代码改动                                                                 测试结果
  1    FIFO轮循模式                       FCR=0x01,IER=0x00 不变)                                      数据接收正常
  2    非FIFO模式                           FCR=0x00,IER=0x07(四中中断打开)
                                                       while中的if语句注释掉                                                数据接收正常
  3   FIFO中断模式                         FCR=0x01,IER=0x00,,while中if注释掉                       数据接收正常

实际上这三种测试,是建立在FCR和IER理论上【理论上IER=0x00,中断就是禁止的,FCR=0x00,就是在非FIFO模式】设置的,但是我把IER注释掉,上述测试同样可以。所以感觉是 :提供的例程中FCR和IER的设置是有问题的,至于为什么测试结果还很理论上的实验验证一样,不知道是没有找到合理的解释还是什么原因,这也是我之前说和代码不符的原因!

同时我也明白了while中if语句的作用,其实就是数据到达接受缓冲寄存器后,你想要进行什么控制,比如还可以 用外设显示接受到的字符,就是你说的全双工通信,发的同时,也可以接收来自串口的数据

但是还存在两个问题:
(1) 我让串口发送一个字符串,DSP 接受后在液晶上显示,起初显示的是乱码,后来换成其他字符串时,头两个字符是错的,其他的正常,在换成数字字符串时,中间的有两个是错的,其他的也是对的。想请教下,这是什么原因?是波特率问题?还是代码有问题?
(2)我把轮循模式禁止,while中if语句注释掉,只在中断模式下,同样的想让接受到的字符在液晶上显示,但是发送后,液晶上  没有任何显示。代码是和轮循模式一样的,只不过是放在中断中,似乎中断中的语句并没有执行!因为printf语句就没有输出。
interrupt void int0()
{
         unsigned int detect,flag,temp;
          detect=LSR;            
           if(detect&0x01)  //从LSR检测相应的状态位,进入到中断里,进一步判断中断的类型
              {  
                 lcd_display( );
                 printf(" lcd display");
          }
         if(detect&0x20)//发送移位寄存器为空
        {
                    THR=0x55;
                      printf("write data:%x",THR);
         }
         detect=0;
}
是自己对中断模式下的UART理解错误?

使用特权

评论回复
11
pinda_| | 2014-3-24 10:38 | 只看该作者
(1)关于发送后接收出错,你不可能一次大批量的发送数据,所以不存在波特率的问题。感觉像是电平逻辑芯片那边有问题,你先试着在代码里写一些错误寄存器的出错状态检测,看看,有没有错误发生,再去判断硬件上的问题。
(2)DEBUG下慢慢调吧,单步什么的都可以,中断进不了,那就只能看看总线上有没有执行过相应的状态。

UART中断,我的理解是:
           它有一个发送FIFO寄存器与发送状态寄存器,另一个接收FIFO寄存器与接收状态寄存器,先把UART的中断打开 ,然后,硬件会通过状态寄存器中的值来判断是否有数据进来,是根据中断还是查询的方式,然后再去读写数据操作。(写的简单了点。。。。。突然发现写不好。。。。。)

使用特权

评论回复
12
ttxs_2013|  楼主 | 2014-3-26 21:35 | 只看该作者
pinda_ 发表于 2014-3-24 10:38
(1)关于发送后接收出错,你不可能一次大批量的发送数据,所以不存在波特率的问题。感觉像是电平逻辑芯片 ...

按照你说的思路,调试中的确是出现了    溢出错误,代码改动的思路是每一个错误类型进行逐一检测,最后发现是溢出错误,代码如下:
if(detect&0x01)              {
                        lcd_display( );
                       if(detect&0x03)
                       printf(" error happen!\n");
                         detect=0;
                       
             }
但是,关于溢出错误,有两个问题不明白:
溢出错误是怎样产生的?按照参考资料上写的,FIFO中存储的数据超过了容量,并已经被移位寄存器接受,新的数据会覆盖移位寄存器的值,数据不会送到FIFO      这里的容量就是指的触发值?新的数据不会送达FIFO,这又是什么意思?

如果指的是触发值,那么就是说发送的字符串中字符的个数超过了14个字节(程序设置是14个字节),于是,我就把字符个数改为1个或者4个,同样是显示 溢出错误,把字符换成数字字符串,个数少于14个字节,也显示溢出错误,所以就不知道溢出错误到底是什么原因造成的?

还有,明明发送的字符串中字符个数小于14个,但是在液晶上仍然显示14个字符,如果是发一个,那么第一个是对的,后面的就是乱码,而且每次后面的都不一样;发送四个,如abcd,则abcd显示出来了,后面的又是乱码。

另外,我想既然发送字符串,无论是PC 接受还是DSP接受,都是乱码,我就测了下,DSP发送字符串给串口,是否也是溢出错误,但结果没有报错。

基于以上的原因,就弄不明白,溢出错误到底是如何产生的?接受到乱码是否是溢出错误造成的?又该如何避免,使之接受正常?
(PS:原本以为串口线有问题,但换了根线,还是一样,网上也查了URAT溢出错误,但是很杂,也没有解释溢出错误的原因的帖子,所以还是来问问你)

关于串口中断,我觉得中断和轮循模式都是要检测LSR响应的位,两者哪个发生,就看中断是否使能及中断标志是否置位,如果是,那么中断和轮询都应该发生,只不过两者,具体实现怎样的操做,看代码怎么写,所以我觉得就这个程序而言不应该不会不进入中断的,现在也没有调。

使用特权

评论回复
13
ttxs_2013|  楼主 | 2014-3-27 14:07 | 只看该作者
zhangmangui 发表于 2014-3-19 22:49
明天帮你找找相关代码

版主有没有找到其他的代码?这个例程调了一个多星期了,还是没有解决!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

31

主题

125

帖子

4

粉丝