最近调试TMS570,有个关于SPI的问题纠结了很久。下面对问题进行描述:
首先,是SPI的硬件连接:570作为主设备,和某从设备连接,使用了SPI2。因为只有一个从设备,所以SPI2的片选和ENA都没有用。两个设备间SPI2SIMO和SPI2SOMI对应直接连接,SPI2CLK相连,并串联一个22欧姆的电阻。
其次,是测试程序的配置:使能 SPI2 driver,不使用中断,波特率1000,片选、ENA管脚用作普通的IO口。程序工作过程:570主设备发送一个字符到从设备,从设备立即把这个字符返回发给主设备570。
出现的问题:在使用JTAG单步调试的时候,570主设备收到的数据总会错位。例如发送的是0xAA,收到的是0x55,只能收到高7位,最低位丢了!, 从示波器抓到的波形看,从设备是从第二个时钟周期才开始有数据。但是,当不用JTAG调试的时候,单纯使用示波器看波形,或者数据判断正确后点亮LED来 指示,这些情况下,数据竟然是正确的!
请问造成这样问题的原因可能是什么?
MCU:TMS570LS3137
开发环境:CCSv5 + HalCoGen3.01
JTAG Emulator:XDS100v2 (BlackHawk: BH-USB-100v2)
aaaa LOOK:
回复 Renton:
Hi Renton,
在程序合适的位置设置了断点,问题依然存在。
把570的代码贴在下面了,程序运行流程:
主设备MCU:t1->Send Data(非Dummy Data), t2->Recv Dummy Data, t3->Send Dummy Data(为了保持CLK), t4->Recv Data.
从设备: t1->Send Dummy Data, t2->Recv Data(非Dummy Data), t3->Send Data, t4->Recv Dummy Data(清空RX register).
注:t1, t2, t3, t4代表时间顺序。
代码:
#define DUMMY_DATA 0xFF unsigned char sendData = 0xA5; while(1) { while ((spiREG2->FLG & 0x0200) == 0); spiREG2->DAT1 = sendData | 0x100D0000; // Send Data while ((spiREG2->FLG & 0x0100) == 0); retVal = (unsigned char)spiREG2->BUF; // receive Dummy data if(sendData != DUMMY_DATA) { while ((spiREG2->FLG & 0x0200) == 0); spiREG2->DAT1 = DUMMY_DATA | 0x100D0000; // Send Dummy Data while ((spiREG2->FLG & 0x0100) == 0); retVal = (unsigned char)spiREG2->BUF; // receive data } int index = 0x4FFFFF; for(;index>0;index–); // delay /*此处设置断点*/ }
在For循环处设置了断点,情况和以前一样,MCU 发送0xA5, 收到0x52,MCU 发送0xEE, 收到0x77,而在不用JTAG仿真的情况下,接收正确了!不过有一点可以确信,从设备接收MCU的数据是正确的,JTAG调试模式下的问题出在从设备发送给MCU的过程中。
在全速运行的情况下接收正常,是不是就说明信号回路没有问题了。大胆猜测:难道是JTAG模式下,MCU的负担重了,影响了SPI外设的正常工作(时钟产生,信号采样等)?仅仅是一种猜测,还请Renton指点。
另外,这里的程序设计思路参考了读写SD卡的程序中SPI_send函数:
/*—————————————————————————— Write and Read a byte on SPI interface *——————————————————————————*/unsigned char SPI_send (unsigned char outb) { while ((spiRegMCUsCom->FLG & 0x0200) == 0); // Wait until TXINTFLG is set for previous transmission spiRegMCUsCom->DAT1 = outb | 0x100D0000; // transmit register address while ((spiRegMCUsCom->FLG & 0x0100) == 0); // Wait until RXINTFLG is set when new value is received return((unsigned char)spiRegMCUsCom->BUF); // Return received value}
后来,因为前面的从设备是判断收到非Dummy Data时才回复,就怀疑这里的判断造成了一定的延时,所以又改变了从设备的程序过程为及时回复(主设备的不变),如下:
主设备MCU:t1->Send Data(非Dummy Data), t2->Recv Dummy Data, t3->Send Dummy Data(为了保持CLK), t4->Recv Data.
从设备: ta->Recv Data(任何数据), tb->Send Data(立即回复收到的数据).
问题依然如前面所述,难道真的是JTAG调试的介入影响了SPI的外设正常工作?请Renton指点。
Thanks,
Regards,
Look
Renton:
回复 aaaa LOOK:
Hi Look,
除了有可能在breakpoint处停止外设工作外, JTAG对外设应该没有严重的影响。
具体是什么原因造成数据移位,还不太能肯定。
我建议还是用Loopback模式测试一下。
aaaa LOOK:
回复 Renton:
Hi Renton,
根据你的建议,测试loopback模式。结果如下:
看了下TMS570LS3137的datasheet,发现SPI有几种LoopBack Mode . 都测试了一下。internal Loopback Test Mode 没有问题,但是Input/Output Loopback Test Mode下, 不管是Digital Loopback 还是Analog Loopback都不能正确接收数据。
测试internal Loopback Test Mode使用的程序:
unsigned char sendData = 0xA5; spiREG2 ->LB = 1; while(1) { int index = 0; for(index=0x3FFFFF;index>0;index–); // delay while ((spiREG2->FLG & 0x0200) == 0); spiREG2->DAT1 = sendData | 0x100D0000; // Send Data while ((spiREG2->FLG & 0x0100) == 0); retVal = (unsigned char)spiREG2->BUF; // receive data for(index=0x3FFFFF;index>0;index–); // delay }
测试Input/Output Loopback ,先是使用了上面的程序(只是把spiREG2->LB = 1; 这一行换成spiEnableLoopback(spiRegMCUsCom, Digital); ),不能正确接收数据,retVal变量读到的总是0xFF。后来又使用下面的程序测试,还是不能正确接收,retVal变量同样读到的总是0xFF:
#define DUMMY_DATA 0xFF unsigned char sendData = 0xA5;#if 1 // enables the Loopback mode for self test – Digital spiEnableLoopback(spiRegMCUsCom, Digital);#else // enables the Loopback mode for self test – Analog spiEnableLoopback(spiRegMCUsCom, Analog);#endif while(1) { int index = 0; for(index=0x3FFFFF;index>0;index–); // delay while ((spiREG2->FLG & 0x0200) == 0); spiREG2->DAT1 = sendData | 0x100D0000; // Send Data while ((spiREG2->FLG & 0x0100) == 0); retVal = (unsigned char)spiREG2->BUF; // receive Dummy data if(sendData != DUMMY_DATA) { while ((spiREG2->FLG & 0x0200) == 0); spiREG2->DAT1 = DUMMY_DATA | 0x100D0000; // Send Dummy Data while ((spiREG2->FLG & 0x0100) == 0); retVal = (unsigned char)spiREG2->BUF; // receive data } for(index=0x3FFFFF;index>0;index–); // delay }
请问是什么原因造成了Digital Loopback 和 Analog Loopback的失败,程序这样写是否可以?
另外,我使用的是Three-Pin Mode,SPI2CS,SPI2ENA引脚都设置成了GIO,问题会不会因为这个造成的?
最后,需要说明的是,昨天还测试了不同波特率的程序,随之而来的问题更让我困惑。还是使用如下代码:
#define DUMMY_DATA 0xFF unsigned char sendData = 0xA5; while(1) { while ((spiREG2->FLG & 0x0200) == 0); spiREG2->DAT1 = sendData | 0x100D0000; // Send Data while ((spiREG2->FLG & 0x0100) == 0); retVal = (unsigned char)spiREG2->BUF; // receive Dummy data if(sendData != DUMMY_DATA) { while ((spiREG2->FLG & 0x0200) == 0); spiREG2->DAT1 = DUMMY_DATA | 0x100D0000; // Send Dummy Data while ((spiREG2->FLG & 0x0100) == 0); retVal = (unsigned char)spiREG2->BUF; // receive data } int index = 0x4FFFFF; for(;index>0;index–); // delay /*此处设置断点*/ }
变换波特率的测试结果如下:
1000kHz时,在主设备JTAG断点调试下数据错位,JTAG调试全速运行也数据错位,只有非JTAG模式下,正常接收数据。
400kHz或者500KHz时,非JTAG模式下,反而不能正常接收数据,只在从设备的JTAG断点调试下或者JTAG调试全速运行才能正确接收。
10000kHz时,在主设备JTAG断点调试下第一个字节数据错位,以后的数据接收正确,JTAG调试全速运行也是这样,只有非JTAG模式下,所有数据都能正常接收。
其中存在的问题有和波特率有什么内在的联系呢?实在搞不懂了。请Renton给分析一下,谢谢!
Regards,
Look
Axel Gao:
回复 aaaa LOOK:
是否可以使用while()循环的delay来代替for()循环的delay?我采用上述类似的代码(只是delay的方式不同),在loopback模式下并没有复现楼主的问题。此外,也可以尝试使用SDK中的函数来进行收发,这样通过查询FLG寄存器的值可以知道在收发过程中是哪一步出现了问题。