板间通信2:调试SPI记录心得
前段时间调查了一些异常重启的问题,以及升级功能,都用到了ipc和spi。
记录下一些需要注意的点
1:spi除协议上规定的clk cs mosi miso四根线之外,通常还用了一跟协议外的握手引脚。ioc端通过这个引脚告诉soc数据是否准备好(在这个设定中,soc是master ioc是slave,clock cs由soc发出)
例如,引脚拉高,表示数据已经准备好,soc检测到高电平,可以发起一次spi传输,一次发一包数据,数据大小为512k或者1024等等。(做的准备:例如dma初始化,将接受和发送buffer地址送入等等)
在ioc的系统中, 对于ipc这个task,引脚拉高后就会将任务挂起,任务恢复的条件就是超时或者传输完成产生的回调。
将引脚拉低的动作放在任务恢复之后。
注意这个没有检测上升沿,这样会有一个风险:
ioc拉低引脚的动作在rtos任务恢复之后才能拉低,可能会有一个延迟,这个延迟可能在ms级别,但是两包通信数据之间的最短间隔可能会达到5-8ms,这就导致了soc检测到的高电平可能是上次传输完成后尚未拉低的高电平。 但是此时ioc并没有将buffer准备好,也就是说soc发过来的这一包数据会丢掉。
在ipc通信中,消息层面上设置的心跳消息的failcounter就可能有一点累计,如果下一包数据恢复了正常,failcounter会清除掉。在极端情况下,很多包连续的都是高电平拉的不正确的情况下发送,导致连续丢包,心跳机制认为soc已经挂掉,触发重启动作。
解决办法:将握手引脚拉低的动作放在回调中断(由dma传输完成产生的中断,共两个,一个发一收,使用其中一个即可)中,保证及时拉低
2:新项目中soc的base与ioc的base不适配,需要ioc重新修改spi的配置,要注意(时钟极性,时钟相位,MSB/LSB, 高低有效性等问题),初始化一个是主一个是从,如果使用了电平转换器记得拉使能脚(都是坑...)
另:8位电平转换器左右两端外围电路有分压电路,soc端可能1.几v就认为是高电平了。逻辑分析仪可能在测电平转换器上的电平时,可能会将毛刺识别为高低电平变化(坑的一比,最开始还以为soc没有初始化好,在很高频的拉高拉低电平,再加上万用表量出来是1.几v,还真以为是在拉高低电平。这种关键时刻还是要靠示波器...)
spi驱动层面有个坑,两边一次传输的数据buffer一定要保持一致,否则就会同时发起一次spi传输,但是一端认为一次传输没有结束,另一端已经结束了,导致每次只能收到部分数据
3:ipc层面copy数据时,注意结构体的定义,需考虑对齐问题,因为C结构体内存空间分布的原因,不合理的定义结构体会导致数据错位。可能升级消息中的cnt拿到的只是数据包头的部分信息
例:
uint8 swdl;//A5
uint8 cnt;
uint16 length;
char [512];
cnt 改成了u16
真实数据 A5 01 0C 02 //02 0C = 524 高地址存高位数据
变为 A5 01 00 0C 02
因为uint 16 是最小内存单元, //结构体变量中成员的偏移量必须是成员大小的整数倍
uint8 后面再加 uin16 会一个unit16放不下,所以 第一个uint8 会占两个字节
导致 真实数据填入结构体时,第一帧的cnt会识别为 0C 00 = 3072 ,01被吃掉了
最终修改:
uint16 swdl;
uint16 cnt;
uint16 length;
char[512];
真实数据:A5 00 01 00 0C 02
如果全是char就没有空白,正常填。
附sizeof求结构体大小规则:
偏移量。偏移量指的是结构体变量中成员的地址和结构体变量地址的差。结构体大小等于最后一个成员的偏移量加上最后一个成员的大小。
存储变量时地址要求对齐,编译器在编译程序时会遵循两条原则:
(1)结构体变量中成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍)
(2)结构体大小必须是所有成员大小的整数倍,也即所有成员大小的公倍数。
结构体大小等于最后一个成员的偏移量加上其大小
结构体类型需要考虑到字节对齐的情况,不同的顺序会影响结构体的大小
sizeof计算嵌套的结构体大小
对于嵌套的结构体,需要将其展开。对结构体求sizeof时,上述两种原则变为:
(1)展开后的结构体的第一个成员的偏移量应当是被展开的结构体中最大的成员的整数倍。
(2)结构体大小必须是所有成员大小的整数倍,这里所有成员计算的是展开后的成员,而不是将嵌套的结构体当做一个整体。
4:
调升级可以直接在工具中输入对应地址去看memory中内容是否写入
获取到数据后写flash失败
原因有很多列举遇到的几个:
a:flash以block为单位擦除和写入,如果每次写之前先擦除要写的这一块内容,而且每次写的长度小于block的长度,
就会导致每次写之前的block擦除擦掉上一次写的内容(最好是将要写的地址范围全擦之后再写,或者注意对齐使得新内容不要被擦除)
b:要注意每一包传输过来的地址是低地址还是高地址,第一次的时候没约定好,soc传过来的是每一包偏移后的地址,但是写入的时候是需要起始地址。这样数据整体会写歪掉,升级失败
c:最后一包数据一般都不是整数,一般写flash需要对齐的长度,需要手动填充避免没有对齐问题。、
d :hex包有相关定义,soc需要解析这个包,ioc需要写对应的包头,这个一搜就有。

浙公网安备 33010602011771号