太亏了,调试这玩意儿不写点啥记录下来简直亏成翔啊,原本DWM1000的官方例程就是基于STM32的,网上更是清一色的用32来控制DWM1000,本菜鸡要用的微控制器是KEA128,不是STM32,光是移植问题就足够原地爆炸了,何况之后还有双向收发测距…不说了,进入正题。
首先,经过一段时间的浸淫,总算对官方的例程有所了解,还被自愿地学了一波32(宝宝心里苦啊)硬件方面队友是根据datasheet的接线图画的原理图,这里把两张图都贴出来,连接上应该是没问题的:
接下来就是代码了,这里先贴出main函数的前一部分:
以上是STM32例程的初始化部分。第一句,peripherals_init(); STM32系统初始化,不用移植;第二句,lcd_display_str(APP_NAME); LCD显示字符串,不用移植;第三句,reset_DW1000(); DW1000复位函数,进去一看,是STM32的GPIO引脚配置:
简单来说就是先把DW1000的复位引脚设置为推挽输出然后拉低,再把它设置成模拟输入,延时2ms,那么,对应的KEA128程序如下:
回到main函数的第四句,spi_set_rate_low(); SPI配置为低速模式,为啥呢?有注释:
为了让DW1000初始化,必须将它的时钟暂时设置为晶振频率,初始化之后就可以将SPI配置成高速模式以获得更好的性能。是了,spi_set_rate_low(); 到 spi_set_rate_high(); 干的就是这个。接下来的问题是,对32来说SPI速度是多少才算是低速?
而例程中STM32使用SPI2来控制LCD,用来和DW1000通信的是SPI1:
以72MHz来算,那么SPI1接口时钟32分频就是 72M / 32 = 2.25M,本菜鸡直接配置成3MHz,然后DW1000初始化部分去掉LCD的部分,剩下的直接Copy:
还差最后一步,底层函数重写。STM32和KEA128的SPI底层函数是不同的,要想顺利完成移植,底层移植才是真正的核心。重要,而且极易猝死…接下来又是愉快的挖STM32底层环节,个人解读SPI写函数如下:
SPI读也是类似的,唯一不同的就是两个for循环体:
因为KEA128只有一个SPI0通道,这个UWB测距本身也因为要做成模块的原因而只有DW1000一个从设备,所以KEA128为默认主机,SPI的片选CS硬件拉低,再去掉保留中断状态这一环节,移植到KEA128这边的时候就变成了下面这样:
好,移植暂时告一段落,现在测试KEA128和PC能否正常通信:
首先将之前的spi_init()函数与后面的DW1000初始化注释,然后UART0初始化,接收中断使能:
编写接收中断函数,收到信号后回复字符‘K’表示应答:
测试情况如下:
KEA128正常工作,且与PC间通信正常。接下来测试KEA128与DW1000间能否正常通信:
哦嚯,果然还是猝死了orz…
正常正常,一次就成功那就不是菜鸡了,接下来开始找原因。直接将dwt_readdevid()放到while(1)中,利用逻辑分析仪读取SPI四个引脚的状态:
附上官方给出的dwt_readdevid()函数说明:
再对比一下数据手册里的相关说明:
从收发格式上看MOSI线是没啥问题的,但是手册里还有一个简单的模型:
所以这个CSn是怎么回事啊喂!!??
之前使用的是KEA128自带的SPI模块,此次移植也是直接用KEA的库,底层函数这边没太注意,现在这节奏,不得不再去挖一波KEA的底层QAQ
先看看spi的初始化函数,然后在下面这一块发现了CSn之外的问题:
SPIN[spin]->C1 = (0
| (pcs << SPI_C1_SSOE_SHIFT) //配合C2_MODFEN位选择片选引脚的功能
| SPI_C1_SPE_MASK //SPI 系统使能
| SPI_C1_MSTR_MASK //SPI 模块配置为SPI 主机
//| SPI_C1_SPIE_MASK //SPRF 或MODF 为1 时请求硬件中断
//| SPI_C1_SPTIE_MASK //SPTEF 为1 时,请求硬件中断。
//| SPI_C1_CPOL_MASK //0:高电平有效SPI 时钟(空闲时为低电平) 1:低电平有效SPI 时钟(空闲时为高电平)
| SPI_C1_CPHA_MASK //0:SPSCK 上的第一个边沿出现在数据传输的第一个周期的中间 1:SPSCK 上的第一个边沿出现在数据传输的第一个周期的开始
//| SPI_C1_LSBFE_MASK //1:SPI 串行数据传输从最低有效位开始
);
SPIN[spin]->C2 = pcs << SPI_C2_MODFEN_SHIFT; //配合C1_SSOE位选择片选引脚的功能
SPIN[spin]->BR = SPI_BR_SPR(spr) | SPI_BR_SPPR(sppr); //设置波特率参数
CPHA位被置1了…底层啊orz…默默地把它注释掉,再看逻辑分析仪:
不是全部为FF了,DWM1000和KEA能进行通信了,但是后四次的数据传输读到的值全是7F,还是不对,得先让CSn的变化和官方给出的示意图相同才知道到底是啥情况。
目前的片选很烦,每传完一个字节就自己拉高,设备ID有32位四个字节啊,这样根本没办法正常传输嘛,行,不要这个片选了,直接用gpio控制,简单粗暴。修改SPI初始化函数如下:
spi_init(spi0,NOT_PCS,MASTER,2.25*1000*1000);
gpio_init(B0,GPO,1);
直接把片选脚单独拉出来控制,这样的话之前的两个底层函数的首尾就都需要分别加上gpio_set(B0,0);和gpio_set(B0,1);来表示片选信号。
修改完毕后,也不看波形了,直接利用uart把读到ID的发回来:
和库里的设备ID对上了,ojbk,至此DWM1000初始化成功,后续开始Double-sidedTwo-way Ranging的移植。