DSP

Ti的C28x系列的DSP(28069)使用经验,SCI与RS485(ADM2587EBRWZ)

2019-07-13 10:53发布

本人使用SCI的通讯经历也不多,仅仅是用于DSP与威纶通公司的触摸屏进行过简单的通讯,通讯方式为RS485,通讯协议为ModbusRTU。 说到SCI,一开始我弄这个的时候,也不懂,网上看了很多资料,但也没有特别合适的,我现在公司的DSP的代码架构,都是一个主中断,一个主循环,一个1ms定时器中断,所以通讯函数,要么放主循环或1ms中断中运行,不会为SCI单独弄个中断,但我这边也不想用《手把手教你学DSP--基于TMS320X281x》上描述的简单SCI查询方式通讯,因为这种方法FIFO没有用,会造成对CPU资源的浪费。 所以我现在提的SCI通讯方式是基于FIFO的轮询方式,以这种方式来配置寄存器,从而形成的读写函数。但28069的SCI的FIFO只有4级,28377D的FIFO有16级。RS485是读写是不能够同时进行的,具体特点,可以百度,这跟RS232不相同。RS485的读写函数是基于ADM2587EBRWZ芯片而写,除了SCI的RX与TX引脚,还多了一个DIR引脚,DIR引脚为高,SCI能够发送数据,反之,读取数据。 代码:
  • SCI的初始化;
void InitScia(void) // LSPCLK = SYSCLKOUT/4 = 20Mhz { SciaRegs.SCICCR.all = 0x07; //1 stopbit,no parity, //idle line mode,loopback test disable SciaRegs.SCIHBAUD = 0x10; //20M baud 9600 BBR = 0x103 // BBR = LSPCLK/(波特率*8) - 1 SciaRegs.SCILBAUD = 0x3; SciaRegs.SCICTL1.all = 0x0003; // enable TX, RX, internal SCICLK, // Disable RX ERR, SLEEP, TXWAKE SciaRegs.SCICTL2.all = 0; SciaRegs.SCIFFTX.all = 0xE040; SciaRegs.SCIFFRX.all = 0x2040; SciaRegs.SCIPRI.bit.SOFT = 1; //Complete current receive/transmit //sequence before stopping SciaRegs.SCIPRI.bit.FREE = 0; SciaRegs.SCICTL1.bit.SWRESET = 1; } void InitScib(void) { ScibRegs.SCICCR.all = 0x07; //1 stopbit,no parity, //idle line mode,loopback test disable ScibRegs.SCIHBAUD = 0x10; //20M baud 9600 BBR = 0x103 //BBR = LSPCLK/(波特率*8) - 1 ScibRegs.SCILBAUD = 0x3; ScibRegs.SCICTL1.all = 0x0003; // enable TX, RX, internal SCICLK, // Disable RX ERR, SLEEP, TXWAKE ScibRegs.SCICTL2.all = 0; ScibRegs.SCIFFTX.all = 0xE040; ScibRegs.SCIFFRX.all = 0x2040; ScibRegs.SCIPRI.bit.SOFT = 1; //Complete current receive/transmit // sequence before stopping ScibRegs.SCIPRI.bit.FREE = 0; ScibRegs.SCICTL1.bit.SWRESET = 1; } void InitScibGpio(void) { EALLOW; GpioCtrlRegs.GPAPUD.bit.GPIO22 = 0; // Enable pull-up for GPIO22 (SCITXDB) GpioCtrlRegs.GPAPUD.bit.GPIO23 = 0; // Enable pull-up for GPIO23 (SCIRXDB) GpioCtrlRegs.GPAQSEL2.bit.GPIO23 = 3; // Asynch qual for GPIO23 (SCIRXDB) GpioCtrlRegs.GPAMUX2.bit.GPIO22 = 3; // Configure GPIO22 for SCITXDB operation GpioCtrlRegs.GPAMUX2.bit.GPIO23 = 3; // Configure GPIO23 for SCIRXDB operation EDIS; }
  • SCI的读写及复位函数;
复位函数: void SciReset(Uchar dev) { volatile struct SCI_REGS *p; switch(dev) { case Sci_a: p = &SciaRegs; break; case Sci_b: p = &ScibRegs; break; default: p = &SciaRegs; break; } if( p->SCIRXST.bit.RXERROR || p->SCIRXST.bit.FE || p->SCIRXST.bit.PE || p->SCIRXST.bit.OE ) { p->SCICTL1.bit.SWRESET = 0; DELAY_US(100); p->SCICTL1.bit.SWRESET = 1; } } 写函数: Uint16 WriteSci(Uchar dev,char *buf,Uint16 cnt) { static Uint16 i,Num; volatile struct SCI_REGS *p; switch(dev) { case Sci_a: p = &SciaRegs; break; case Sci_b: p = &ScibRegs; break; default: p = &SciaRegs; break; } i=0; Num = cnt; SciReset_C1062(dev); while(p->SCIFFTX.bit.TXFFST != 0); p->SCICTL1.bit.TXWAKE = 1; p->SCITXBUF = 0xAA; while(i < Num) { while(p->SCIFFTX.bit.TXFFST >= 4); p->SCITXBUF = buf[i++]; } return(i); }   读函数: 读函数这里有个DELAY_US(3800),这个非常重要,没有这个延时RS485没法正常的读取数据,至于原理,暂时我也没完全搞清楚,应该是为了度过发送数据的而产生的低电平吧,因为DIR引脚为高时,ADM2587EBRWZ芯片的引脚会把SCI的Rx引脚拉低,如果这段时间SCIRX引脚读数据会读到错误的数据,因为SCI的Rx引脚读取数据时,认为8个时钟周期的低电平就是一个有效的数据起始位,这个读函数完全时为了RS485而准备的,我也试过RS232,当使用RS232时,SCI的收发是互不干扰,就没有这个问题。 Uint16 ReadSci(Uchar dev,char *buf) { static Uint16 i; volatile struct SCI_REGS *p; switch(dev) { case Sci_a: p = &SciaRegs; break; case Sci_b: p = &ScibRegs; break; default: p = &SciaRegs; break; } SciReset_C1062(dev); if(p->SCIFFRX.bit.RXFFST == 0) { return(0); } i = 0; do { while(p->SCIFFRX.bit.RXFFST != 0) { buf[i] = p->SCIRXBUF.bit.RXDT; i ++; } DELAY_US(3800); }while(p->SCIFFRX.bit.RXFFST != 0); return(i); } 忙函数: void BusyWaitingSci(Uchar dev) { volatile struct SCI_REGS *p; switch(dev) { case Sci_a: p = &SciaRegs; break; case Sci_b: p = &ScibRegs; break; default: p = &SciaRegs; break; } while(p->SCIFFTX.bit.TXFFST > 0); } 波特率设置函数: void SetBaudrateSci(Uchar dev,Uint32 baud) { Uint32 rate; volatile struct SCI_REGS *p; switch(dev) { case Sci_a: p = &SciaRegs; break; case Sci_b: p = &ScibRegs; break; default: p = &SciaRegs; break; } rate = 20000000 / (baud*8) - 1; p->SCIHBAUD = rate >> 8; //20M baud 9600 2603 p->SCILBAUD = rate & 0x0FF; }
  • RS485函数;
写函数: void Rs485Write(char *buf,Uint32 Baudrate,Uint16 cnt) { float ByteDelay; ByteDelay = (1000000 / Baudrate ) * 11; RcvDisable(); DELAY_US(10); ADM2587_Write(buf,cnt); ADM2587_BusyWaiting(); DELAY_US(ByteDelay); RcvEnable(); } 读函数: Uint16 Rs485Read(char *buf) { RcvEnable(); DELAY_US(10); return(ADM2587_Read(buf)); } 头文件: #define ADM2587_Write(buf,cnt) WriteSci(Sci_b,buf,cnt) #define ADM2587_Read(buf) ReadSci(Sci_b,buf) #define ADM2587_BusyWaiting() BusyWaitingSci(Sci_b) #define ADM2587_BaudrateSet(baud) SetBaudrateSci(Sci_b,baud) #define RcvDisable() GpioDataRegs.GPBSET.bit.GPIO50 = 1 #define RcvEnable() GpioDataRegs.GPBCLEAR.bit.GPIO50 = 1