本帖最后由 yirongfu 于 2012-7-5 09:41 编辑
此前一直使用模拟的SPI
接口或者主机模式的SPI
接口,未尝试过从机SPI
编程,近期学习了视频教程,想试试来个跨界握手:通过LaunchPad
上的MSP430G2553
的硬件SPI
与EK-LM3S811
上的SSI
(SPI
模式)进行互联,简化起见,MSP430G2553
作为从机,LM3S811
作为主机。利用LM3S811
的虚拟串口来间接检验双向通讯效果,通讯的思路是LM3S811
发出若干字节数据,MSP430G2553
接收到后原文回传,LM3S811
接收到回传直接通过UART
显示到PC
端的串口调试助手上。当然也可以逆过来设计,我这么选择只是为了实验的方便,因为需要尝试的重点是SPI
通讯,其他的如虚拟串口可以利用LM3S
的库来快速实现。关键的难点还是接口时序的选择,比如时钟的极性、相位等。
*****************************************
硬件连接(从评估板的引出端子处飞线互连):
PC1+MSP430G2553 PC2+ LM3S811
GND
(Pin20
)------------------------------GND
(外侧引出焊盘列,下同)
UCA0SOMI
(P1.1
)------------------------SSIRx
UCA0SIMO
(P1.2
)------------------------SSITx
UCA0CLK
(P1.4
)-------------------------SSICLK
UCA0STE
(P1.5
)-------------------------SSIFss
(可省)
*****************************************
注:目前的MSP430G2553
器件手册SLAS735F
第3
页第一个器件引脚图上,第4
脚描述有误,多了个字母P
,变成PUCA0SIMO
了。
接下来的重点就是编程了,首先需要查阅官方的例程,当然没有现成的上述连接方式的例程,不过MSP430G2553
倒是有两个分别作为从机和主机的例程,主从双方均为MSP430
单片机,LM3S811
也有SPI
主机模式的例程,但没找着对应的从机例程。参考例程作如下设计:
1. MSP430G2553
采用三线SPI
从机模式,上电复位进行必要的初始化后进入低功耗LPM4
状态,接收数据和发送数据均在中断服务程序内执行。这也是近期的视频教程第八讲“串行通信模块”里,丁经理反复强调的430适合低功耗设计的要求,为低功耗设计而设计,它可从任意低功耗模式(LPM)实现自动时钟起动,具体来说就是即使在CPU和所有时钟禁能的LPM4模式下都可以正常通信,不过请注意,这针对的是SPI的时钟取自SMCLK且作为从机的操作,在需要的时候SMCLK被自动激活,比如接收和发送操作就可以激活,并保持到操作执行完毕,然后回到激活前的低功耗状态(详见用户手册说明)。而如果作为主机,它需要向外输送时钟的,所以就跟低功耗模式相矛盾了。为了便于调试观察,设置了一个数组用于存放从SPI
收到的数据,接收到一个字节立即回传该字节,芯片大部分时间处于LPM4
,另外,联调时先运行该从机。调试环境CCSv4.2.4
。
2. LM3S811
采用Freescale
的SPI
主机模式,SPH=1
,SPO=0
,速率取500kHz
,8-bit
数据宽度。注意,LM3S811数据手册里提到,当工作模式为主机模式时,系统时钟至少是SSIClk的两倍;当工作模式为从机模式时,系统时钟至少是SSIClk的12倍。程序采用查询方式发送和接收数据,发送5
个字符Hello
,全部发送完毕再进行接收查询,接收的数据直接送UART
口,UART
口采用例程中的配置115200 bps
、8-N-1
。调试环境IAREmbedded Workbench for ARM 5.30 Kickstart
。
3.
两个MCU
的用户手册所述及的SPI
接口模式不太一样,MSP430G2553
并不像LM3S811
那样区分出三种定义的SPI
接口,从具体的配置来看,MSP430G2553
和LM3S811
的Freescale
接口模式更为接近,就是不知道LM3S811
支持的TI
的模式是不是430
上的SPI
模式?最终基本可行的接口时序形式如下:
MSP430G2553
,CKPL=0
,CKPH=0
LM3S811
,Freescale
,SPO= 0
,SPH=1
其实我一开始分析时,觉得SPO=0
、SPH=0
更配对,可惜不对。
实验内容及结果总结:
1. MSP430G2553
作为从机,SPI
的总线时钟CLK
取决于主机,当然,也不能让MCU
的系统时钟低于SPI
时钟线频率。实验过上电默认的约1MHz DCO
,修改为8MHz
,修改为4.3
~7.3MHz
(RSELx = 12, DCOx = 3, MODx = 0
),均可。稳妥起见,个人觉得系统时钟和总线频率的选择参考上述LM3S811
数据手册的建议为宜。
2.
试了MSP430G2553
配置为3
线制,LM3S811
配置为TI SPI
模式,MSP430G2553
接收到的数据错误。
3. LM3S811
的Freescale SPI
是4线制,试验了如下情况:
· 分别试了用与不用SSISTE
引脚(软件配置LM3S811
的I/O
口部分的PA3
屏蔽),MSP430G2553
也分别配置了3
线制和4
线制,效果一样,这个STE
脚应该就是多主机的时候才有用(此时注意如果使用4线JTAG进行调试,MSP430G2xx3的UCA0STE与TMS引脚是复用的,开发环境可以使用Release JTAG on Go或者Free Run来避免冲突)。
· 试了LM3S811
的SPO=0
、SPH=0
模式,MSP430G2553
接收的数据正确,但LM3S811
收到的其回传数据与原发出数据不一样,不过基本都是固定的几个值。
· 试了LM3S811
的SPO=0
、SPH=1
模式,MSP430G2553
接收数据正确,但回送给LM3S811
的数据不完全一致,这个不一致是说收到的字符是对的,但先后顺序不吻合,比如实验中LM3S811
发送的是“Hello
”,MSP430G2553
接收到的也是“Hello
”,并且收一个字符回传一个,LM3S811
也是读出一个就往串口送一个,结果PC
端的串口调试器上得到的是“oHell
”,就是说顺序错了,还试过只送三个字节“mhz
”,同样存在这种现象,变成“hzm
”,DCO
改为8MHz
后,又变成“zmh
”。目前只调试到这种程度,虽然不完全吻合,排序有错,但至少收到正确的数据了,下面是串口终端的截图。
· 至于为何数据错位,LM3S811
的FIFO
接收机制既然先进先出,照理不应该错,而且从机MSP430G2553
也是按正确的先后顺序回传的,我想只可能在主机端接收和读取时才会产生错误,感觉也不应该是查询方式存取FIFO
的问题,否则先不说错位,就连数值的正确性都无法保证。至于问题到底出在哪里,还没找出来,有待继续研究调试,如果有朋友知道,望指点!
· 现在总算深刻体会到了SPI总线的弱点:没有指定的流控制,没有完善的应答机制确认是否接收到数据。曾经将MSP430G2553
的回传屏蔽,结果LM3S811
的接收还是照常执行,收到的数据当然都是空白的,也就是说,SPI
并没有像I2C
那样有停止位、起始位、确认位之类的,它仅是依靠时钟线来作为存取数据的基准,如果主从机的时序没有严格对应上,就很可能出错。也曾怀疑我上述失败实验中有些就是数据回传与LM3S811
开始程序读取FIFO
之间的时间间隔问题,可惜没有示波器,暂时无法去验证分析。对于这种双MCU
的由程序控制的SPI
主从通讯,特别是两种不同架构的MCU
之间的通讯,关键之关键,应该还是时序的同步。
这回调试费了好几天的业余时间,因为没有好的实验条件,比调试I2C
和其它仅作Slave
用途的SPI
器件要费劲的多,而且熟悉CCS
调试环境也花了点时间,好在多少有些成果,亲自验证了MSP430
和LM3S
之间的SPI
互联,虽然还有数据错位的问题,但至少数值对了,如果大家有碰到类似的实际应用,可以再进一步做调试。
后面附上两MCU
的主代码供大家参考。
另外,因为本文既涉及MSP430又涉及Stellaris,所以放到《讨论》这个版块。
发帖系统真的有些问题,烦人,上帖最后一张图重复,部分字体颜 {MOD}也编辑不成功,期待新版!
下面是MSP430G2553的源代码,环境CCSv4.2.4:
参考例程:slac485a ——MSP430G2xx3Code Examples.zip(例程有些描述也不一定都正确)
- #include "msp430g2553.h"
-
- unsigned char temp[5];
- static unsigned char num;
-
- void main(void)
- {
- WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
-
- /*if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
-
- {
-
- while(1);
- // If calibration constants erased
- // do not load, trap CPU!!
- }
-
- //8Mhz
-
- BCSCTL1 = CALBC1_8MHZ;//0x0C; // Set range
-
- DCOCTL = CALDCO_8MHZ;//0x60; // Set DCO step +
- modulation */
-
- P1SEL = BIT1 + BIT2 + BIT4;
- P1SEL2 = BIT1 + BIT2 + BIT4;
- UCA0CTL1 = UCSWRST; // **Put state machine in reset**
- UCA0CTL0 |= UCMSB + UCSYNC + UCMODE_2; // 3-pin, 8-bit SPI slave
- //官方例程此处注释有误,变成了master
- UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
- IE2 |= UCA0RXIE; // Enable USCI0 RX interrupt
- temp[0] = '-';
- temp[1] = '-';
- temp[2] = '-';
- temp[3] = '-';
- temp[4] = '-';
- num = 0;
-
- __bis_SR_register(LPM4_bits + GIE); // Enter LPM4, enable interrupts
- }
-
- // Echo character
- #pragma vector=USCIAB0RX_VECTOR
- __interrupt void USCI0RX_ISR (void)
- {
- temp[num] = UCA0RXBUF;
- while (!(IFG2 & UCA0TXIFG));
- UCA0TXBUF = temp[num];
- num++;
-
- if(num == 5)
- num = 0;
- }
复制代码没人解答我的问题吗?:L
一周热门 更多>