[经验] TMS320F28335项目开发记录10_28335之SCI模块

风雨也无晴   2015-3-30 17:19 楼主
28335之SCI模块1.介绍

    TMS320F28335内部有三个SCI模块,SCIA、SCIB、SCIC。

    每一个SCI模块都有一个接收器和发送器,SCI的接收器和发送器各有一个16级的FIFO(First In First Out先入先出)队列,它们都还有自己独立的使能位和中断位;可以工作在半双工或全双工模式;

    串行通信的三种方式:

   

2.SCI深入

    A. GPIO的管脚对应如下:

  SCIA对应GPIO28/29和GPIO35/36两组可选

  SCIB有四组管脚可以选择,分别是 O9/11,GPIO14/15,GPIO18/19,GPIO22/23;

  SCIC对应的是GPIO62/63。


    在编程初始化时,需要先将对应的GPIO管脚配置为SCI模式,才能使得这些管脚具有SCI功能;

   

   

    B. SCI通信中带有格式信息的数据字符叫帧,下面是典型的数据帧格式

   

    C. 下面单独介绍一下SCI波特率设置寄存器SCIHBAUD和SCILBAUD,0-15是高字节与低字节连在一起,构成16位波特率设置寄存器BRR。


    BRR = SCIHBAUD + SCILBAUD

    如果1<= BRR <=65535,那么SCI波特率=LSPCLK / ( (BRR+1) * 8 ),由此,可以带入你需要的波特率,既可以得到BRR的值;

    如果BRR = 0,那么SCI波特率=LSPCLK/ 16


   D. SCI模块发送和接受数据的原理:



3.SCI串口编程

   A.先初始化IO管脚 (以SCI-A为例,SCI-B、SCI-C的初始化方法一样,就是照着改对应的管脚就行)

  1. void InitSciaGpio()    //初始化SCIA的GPIO管脚为例子  
  2. {  
  3.    EALLOW;  
  4. //根据硬件设计决定采用GPIO28/29和GPIO35/36中的哪一组。这里以35/36为例  
  5. //定义管脚为上拉  
  6.     GpioCtrlRegs.GPBPUD.bit.GPIO36 = 0;      
  7.     GpioCtrlRegs.GPBPUD.bit.GPIO35 = 0;      
  8.   
  9. //定义管脚为异步输入  
  10.     GpioCtrlRegs.GPBQSEL1.bit.GPIO36 = 3;   
  11.   
  12. //配置管脚为SCI功能管脚  
  13.     GpioCtrlRegs.GPBMUX1.bit.GPIO36 = 1;   
  14.     GpioCtrlRegs.GPBMUX1.bit.GPIO35 = 1;     
  15.   
  16.     EDIS;  
  17. }  

B.SCI初始化配置

  1. void scia_init()  
  2. {  
  3.     SciaRegs.SCICCR.all =0x0007;   // 1 stop bit, No loopback  
  4.                                    // No parity,8 char bits,  
  5.                                    // async mode, idle-line protocol  
  6.   
  7.     SciaRegs.SCICTL1.all =0x0003; // enable TX, RX, internal SCICLK,  
  8.                                    // Disable RX ERR, SLEEP, TXWAKE  
  9.   
  10.     SciaRegs.SCICTL2.bit.TXINTENA =1; //发送中断使能  
  11.     SciaRegs.SCICTL2.bit.RXBKINTENA =1;//接收中断使能  
  12.   
  13.     SciaRegs.SCIHBAUD    =0x0001; // 9600 baud @LSPCLK = 37.5MHz.  
  14.     SciaRegs.SCILBAUD    =0x00E7;  
  15.   
  16.     SciaRegs.SCICTL1.all =0x0023; // Relinquish SCI from Reset  
  17. }  

C.接着进行中断的配置

  1. EALLOW;    // This is needed to write to EALLOW protected registers  
  2.    PieVectTable.SCIRXINTA = &sciaRxIsr;  
  3.    PieVectTable.SCITXINTA = &sciaTxIsr;  
  4.    PieVectTable.SCIRXINTB = &scibRxIsr;  
  5.    PieVectTable.SCITXINTB = &scibTxIsr;  
  6. EDIS;   // This is needed to disable write to EALLOW protected registers  

D.上面是将SCIA和SCIB的中断服务程序连到PIE的中断表中,发生中断就会跑到你的ISR去了,下面是开中断:

  1. PieCtrlRegs.PIECTRL.bit.ENPIE = 1;   // Enable the PIE block  
  2.   PieCtrlRegs.PIEIER9.bit.INTx1=1;     // PIE Group 9, int1  
  3.   PieCtrlRegs.PIEIER9.bit.INTx2=1;     // PIE Group 9, INT2  
  4.   PieCtrlRegs.PIEIER9.bit.INTx3=1;     // PIE Group 9, INT3  
  5.   PieCtrlRegs.PIEIER9.bit.INTx4=1;     // PIE Group 9, INT4  
  6.   IER = 0x100;    // Enable CPU INT  
  7.   EINT;  

这样串口基本就OK了。


上面的配置是配置典型的串口中断程序;

下面是一个SCI例程:

  1. /*
  2. * Serial.c
  3. *
  4. *  Created on: 2014-12-8
  5. *      Author: SCOTT
  6. */  
  7.   
  8.   
  9. #include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File  
  10. #include "DSP2833x_Examples.h"   // CPU_FRQ_100MHZ is in it!  
  11.   
  12. void scib_fifo_init()  
  13. {  
  14.     ScibRegs.SCIFFTX.all = 0xe040;  
  15.     ScibRegs.SCIFFRX.all = 0x204f;  
  16.     ScibRegs.SCIFFCT.all = 0x0;  
  17. }  
  18.   
  19. /*
  20. void scib_echoback_init()
  21. {
  22.     ScibRegs.SCICCR.all = 0x0007;           // one stop bit,8 data bit,No parity, No Lookback
  23.     ScibRegs.SCICTL1.all = 0x0003;          // enable TX, RX, internal SCICLK,
  24.                                             // Disable RX ERR, SLEEP, TXWAKE
  25.     ScibRegs.SCICTL2.all =0x0003;
  26.     ScibRegs.SCICTL2.bit.TXINTENA = 1;      // TX interrupt enable
  27.     ScibRegs.SCICTL2.bit.RXBKINTENA =1;
  28. #if (CPU_FRQ_150MHZ)
  29.     ScibRegs.SCIHBAUD    =0x0001;           // 9600 baud @LSPCLK = 37.5MHz. 150/4 = 37.5MHZ
  30.     ScibRegs.SCILBAUD    =0x00E7;
  31. #endif
  32. #if (CPU_FRQ_100MHZ)
  33.     ScibRegs.SCIHBAUD    =0x0001;           // 9600 baud @LSPCLK = 20MHz.
  34.     ScibRegs.SCILBAUD    =0x0044;
  35. #endif
  36.     ScibRegs.SCICTL1.all =0x0023;           // Relinquish SCI from Reset
  37. }

  38. */  
  39.   
  40.   
  41. void scib_echoback_init()  
  42. {  
  43.     ScibRegs.SCICCR.all = 0x0007;           // one stop bit,8 data bit,No parity, No Lookback  
  44.     ScibRegs.SCICTL1.all = 0x0003;          // enable TX, RX, internal SCICLK,  
  45.                                             // Disable RX ERR, SLEEP, TXWAKE  
  46.     ScibRegs.SCICTL2.all =0x0003;           // RX TX Interrupt enable  
  47.     ScibRegs.SCICTL2.bit.TXINTENA = 1;      // TX interrupt enable  
  48.     ScibRegs.SCICTL2.bit.RXBKINTENA =1;     // RX interrupt enable  
  49. #if (CPU_FRQ_150MHZ)  
  50.     ScibRegs.SCIHBAUD    =0x0001;           // 9600 baud @LSPCLK = 37.5MHz. 150/4 = 37.5MHZ  
  51.     ScibRegs.SCILBAUD    =0x00E7;  
  52. #endif  
  53. #if (CPU_FRQ_100MHZ)  
  54.     ScibRegs.SCIHBAUD    =0x0001;           // 9600 baud @LSPCLK = 20MHz.  
  55.     ScibRegs.SCILBAUD    =0x0044;  
  56. #endif  
  57.     ScibRegs.SCIFFTX.all = 0xC020;  
  58.     ScibRegs.SCIFFRX.all = 0x0021;                  // Receive FIFO generates interrupt when the FIFO status bits (RXFFST4–0) and FIFO level bits  
  59.                                                     //(RXFFIL4–0) match (i.e., are greater than or equal to). Default value of these bits after reset                                                        //–11111. This will avoid frequent interrupts, after reset, as the receive FIFO will be empty mos                                                        // t of the time.  
  60.     ScibRegs.SCIFFCT.all = 0x00;  
  61.     ScibRegs.SCIFFTX.bit.TXFIFOXRESET=1;  
  62.     ScibRegs.SCIFFRX.bit.RXFIFORESET=1;  
  63.     ScibRegs.SCICTL1.all =0x0023;           // Relinquish SCI from Reset  
  64. }  
  65.   
  66. void scib_xmit(int c)  
  67. {  
  68.     //while (ScicRegs.SCIFFTX.bit.TXFFST != 0) {} //==0 -> transmit BUF is empty,can receive new data  
  69.     while(ScibRegs.SCICTL2.bit.TXRDY != 1){}      //also right,but the way of tool's display is different  
  70.     ScibRegs.SCITXBUF = c;  
  71. }  
  72.   
  73. void scib_msg(char *msg)  
  74. {  
  75.     int i;  
  76.     i = 0;  
  77.     while('\0' != msg[i])  
  78.     {  
  79.         scib_xmit(msg[i]);  
  80.         i++;  
  81.     }  
  82. }  
  83.   
  84. Uint16 scib_rvc()  
  85. {  
  86.     Uint16 data = 0x0000;  
  87.     while(ScibRegs.SCIFFRX.bit.RXFFST == 0){}  
  88.     data = ScibRegs.SCIRXBUF.all;  
  89.   
  90.     while(ScibRegs.SCICTL2.bit.TXRDY != 1){}  
  91.     ScibRegs.SCITXBUF = (data & 0xff);  
  92.     return data;  
  93. }  
  94.   
  95. /*No More*/  


路漫漫其修远兮,吾将上下而求索!(今天,你努力了吗?还记得你的目标吗?)

回复评论 (5)

楼主您好,非常感谢您的整理,很清晰,很棒!在这里有几个问题想问:
我最近在学28027,恰好看到Sci,和28335是非常类似的,但是看controlsuite里面的例程,有一点疑惑想问:在sci_loopback_int例程中,是怎样进入发送中断和接收中断的?
我本来觉得接收中断应该是我们在串口输入一个字符,点击发送就触发了(这里的话因为是Loopback,所以进入发送中断后,发送数据,就进入接收中断),但发送中断是怎么进入的就非常不理解了。
看到有说法是说把Sci初始化后就有定时器进行计时,到一定数后即触发中断,如果是这样,那定时器的配置在初始化中似乎并没有体现。
也有说法是根据中断标志位来进入中断,但似乎初始化函数里并没有把中断标志置1.
不知楼主能否帮我解答,谢谢~

此外,还有一个问题,用Sci每次接收的是一个字符,那如果我希望接收输入的一个两位数,来改变程序中的某个变量值,应该怎么编程比较合理呢?
点赞  2015-4-3 08:35
引用: 丫小米 发表于 2015-4-3 08:35
楼主您好,非常感谢您的整理,很清晰,很棒!在这里有几个问题想问:
我最近在学28027,恰好看到Sci,和28335是非常类似的,但是看controlsuite里面的例程,有一点疑惑想问:在sci_loopback_int例程中,是怎样进入发送中断和接收中断的?
我本来觉得接收中断应该是我们在串口输入一个字符,点击发送就触发了(这里的话因为是Loopback,所以进入发送中断后,发送数据,就进入接收中断),但发送中断是怎么进入的就非常不理解了。
看到有说法是说把Sci初始化后就有定时器进行计时,到一定数后即触发中断,如果是这样,那定时器的配置在初始化中似乎并没有体现。
也有说法是根据中断标志位来进入中断,但似乎初始化函数里并没有把中断标志置1.
不知楼主能否帮我解答,谢谢~

此外,还有一个问题,用Sci每次接收的是一个字符,那如果我希望接收输入的一个两位数,来改变程序中的某个变量值,应该怎么编程比较合理呢?

1、SCI发送时间间隔不需要你去考虑,SCI硬件已经完成这部分功能。SCI串口设置好后,你只要把数据写入发送寄存器,串口能够自动按照设置的波特率发送数据。SCI硬件组成里面里面有计数器/定时器,但这个是已经固化好的,只为SCI服务。。你没有修改的权利,而且与平时说的定时器完全是两个东西。学习DSP,你想忘了51

2、你接收的字符的ASCII码吧,ASCII难道不是数据。
点赞  2015-4-3 10:53
引用: ltbytyn 发表于 2015-4-3 10:53
1、SCI发送时间间隔不需要你去考虑,SCI硬件已经完成这部分功能。SCI串口设置好后,你只要把数据写入发送寄存器,串口能够自动按照设置的波特率发送数据。SCI硬件组成里面里面有计数器/定时器,但这个是已经固化好的,只为SCI服务。。你没有修改的权利,而且与平时说的定时器完全是两个东西。学习DSP,你想忘了51

2、你接收的是字符的ASCII码吧,ASCII难道不是数据。

您没有理解他的意思,他是指在其他单片机中,一般是在主函数里写一个UART_PutChar('0x55'),然后才会触发发送中断从而进入发送中断函数。但28027好像在主函数里不写发送函数也会进入发送中断,而且是周期性的进入,根本停不下来啊,TI的例程如此,我自己写的程序也是如此,找不到原因,就好像是发送中断标志位没有被清零一样,而且初始化完成后就自动进入中断函数,先进接收中断,然后是发送中断,然后一直是发送中断

点赞  2015-4-29 09:18
引用: mark86739851 发表于 2015-4-29 09:18
您没有理解他的意思,他是指在其他单片机中,一般是在主函数里写一个UART_PutChar('0x55'),然后才会触发发送中断从而进入发送中断函数。但28027好像在主函数里不写发送函数也会进入发送中断,而且是周期性的进入,根本停不下来啊,TI的例程如此,我自己写的程序也是如此,找不到原因,就好像是发送中断标志位没有被清零一样,而且初始化完成后就自动进入中断函数,先进接收中断,然后是发送中断,然后一直是发送中断

我基本都是直接设置寄存器,很少用库。谢谢提醒,有时间了学习学习
点赞  2015-4-29 10:07
引用: mark86739851 发表于 2015-4-29 09:18
您没有理解他的意思,他是指在其他单片机中,一般是在主函数里写一个UART_PutChar('0x55'),然后才会触发 ...

进发送中断有三种可能:TXRDY为1;SCITXBUF送TXSHF;TXFFST寄存器的值小于等于TXFFIL
点赞  2016-8-3 11:57
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复