0%

基于FPGA的MPU6050姿态解算(3)

本篇为沉浸式DEBUG记录(

废话比较多,纯流水账和我自己的内心戏,大家看个乐,最后的总结就是两点:

  1. 好好写tb,测试数据尽量多
  2. 用杜邦线的时候要保证连接的稳定性,因为杜邦线很容易松动,导致传输出错

BUG1:

数码管上显示的ROLL角度值目测是正确的,但是经过data_packing之后就传输错误,具体错误是上位机解码错误,通过串口调试器查看接收到的数据之后,发现经过一段时间的传输后,每一帧的数据量并不是13字节,如下:

image-20220315111552606

从220行开始就错位了。

  1. 尝试不同UART速率,问题仍存在
  2. UART改为每次间隔一个空闲位传输,问题仍存在

同时可以发现,前面正确的每一帧,最后两个checksum计算存在问题,例如可以带入208行的数据验算一下,发现checksum就是错的,这个问题的原因很简单,就是我代码截位因为马虎写错了。

经过ILA的波形抓取分析,发现FIFO在一段时间后一直处于满的状态,这将导致后面的数据写不进去,进而导致丢数据。

根本原因是I2C的读取速率与UART发送的速率不匹配。

下面来分析一下,I2C配置的分频后的时钟是400K,但是根据I2C ip中的verilog,实际的SCL频率要除以2,也就是200K,1s能传输200K bit,一组数据大约是7x16+=128bit,1s能读取3125组数据,一组数据经过处理会变成13字节的一帧,也就是1s产生3125帧。

UART的发送速率假设为115200,那么就是1s发送115200个bit,发送一个字节要1+1+8+1=11bit,1s就只能发送大约10472个字节,再除以一帧13个字节,1s最多只能发送805帧。

产生数据的速度大约是发送数据的4倍,这很不行。所以,我们要限制数据产生的速率(或者方案2就是当FIFO不能保存一帧的时候就丢弃整个帧,不过这要判断FIFO还差多少个数据就满,能不能保存一帧)。

具体方案是,写一个定时器,定时频率是800Hz,每次读取一组。

增加了timer之后,发现FIFO仍然会存满,同时发现,在CALCULATE状态下,再按一下key,理论上应该是WAIT模式,但是角度数据还在更新,于是怀疑是不是I2C的WAIT并不是真的WAIT。

原来是Kalman_Filter的calib_done没有输出连到Kalman_Ctrl上,wtm裂开

连好后,问题仍存在o(≧口≦)o

继续找bug,发现将I2C切换为Wait模式时,前一个连续读取的停止信号没有发送完就进入了等待状态,可能导致I2C从机一直以为没有停止,从而导致后续数据读取错误。

修复这个bug后(如下图),上位机接收的误码率从100%降到了30%左右!!!说明之前的主要问题就是这个!

BUG2:

接下来观察传过来的数据:

image-20220316225947129

发现其中还是有个别数据传输错误,例如把帧开头的AA、FF传成53、F7,不过这次有个好消息,就是没有掉数据或莫名多数据的情况发生(因为FIFO一直没有满)。

同时,debug发现计算出的最优角度值也有问题,例如下图:

image-20220316211540410

此时MPU是平放状态,但是放大一百倍后的数值仍然有-2295,那么原值就是-22.95°,这很离谱。暂时先不管,我们先看UART传输错误的问题。

通过计算一行数据的校验和1(例如截图中的第一行,即29957行),把53、F7当作原来的AA和FF来计算checksum1,发现开头两个字节确实是由于误码造成的:

image-20220316230343166

但是!发现checksum2还是有问题的,发现是少加了一次,但是修改后,上位机接收的checksum2还是有问题!应该也属于误码

分析一下可能的原因:

  1. 波特率产生不稳从而导致误码,因为是通过任意分频器产生的,有误差

  2. 波特率过大导致误码率增大

第一次尝试,增加任意分频器的精度(以及增加bps_en对baud_gen进行重置),稍微降低了一点误码率,但还是在25%左右,失败

第二次尝试,降低波特率,首先降低一半,到57600

image-20220317104153894

这次可喜的是,checksum1和checksum2传输都完全正确,且最开始的几十组数据都没有出现误码!!!

但是到了后面仍然出现错位(下图),查看一下FIFO的full信号,原来是FIFO又满了呀。

image-20220317104210898

重新计算一下需要的mpu timer频率,57600/11≈5236 Bytes,5236/13≈402帧,所以要降低timer的频率到400Hz

误码率很不稳定,有时15%,有时99%。

直接降到9600,9600/11/13=67………wtf????为什么误码率又飙升到100%,麻了

修复粗心bug:

  1. 读取acc和gyro的数据量是14字节,不是7字节

  2. acc_rdy和gyro_rdy产生的时间早了一个周期

现在重新分析原因:

  1. UART模块传输数据不稳定的原因
  2. UART中FIFO的写入和读出不一致的原因(时序导致的)

3.23更新!!!

死活也没想到,还是因为我的代码写的有问题(つ﹏⊂),但是我之前是有单独验证这个模块的,只不过没有模拟实际的情况来写testbench,今天想着单独测试一下UART模块,为此甚至买了一个逻辑分析仪!然后想着还是模拟实际传输情况写一个testbench吧,结果就!发现了问题!

主要问题出在波特率发生器的使能信号上:

1
2
assign	bps_clk_en	=	((!fifo_empty_in) & bps_en);	//这是有bug的版本
assign bps_clk_en = fifo_empty_in ? (state_current!=STATE_IDLE) : bps_en; //这是修改后的版本

image-20220323214334455

原来的写法导致了在读取FIFO中最后一个数据之后,由于FIFO_EMPTY立马变成了1,导致bps_clk_en变为0,进而产生不了波特率,一直卡在START状态,从而导致后续的数据传输出错。

修改后的时序如下(主要区别在bps_clkbps_clk_en两个信号):

image-20220323214935876

经测试,可以正常发送,误码率为0%!!!太不容易了/(ㄒoㄒ)/~~

通过这个bug,得到一个教训,就是写testbench,不要觉得麻烦而随便写一个,尽量按照实际的数据产生流程来写,以便发现BUG。

BUG3:

解决掉数据传输的BUG后,还剩一个数据计算的BUG,这还算是一个正常的BUG。

BUG3的现象是,ROLL和PITCH极不稳定,反复横跳,不过经过一段时间后,ROLL会稳定下来,PITCH则仍然反复横跳。

测试计划:

  1. 查看I2C读出的原始数据观察是否正常

调试过程中还出现了一个小故障,FPGA开发板和插着MPU6050的面包板是通过杜邦线连接的,有时一动面包板就会导致I2C读不出数据,数码管显示卡住,估计是因为杜邦线的接触不良,毕竟很松动,于是改为直接插在开发板上,故障解决。

PS:这个经验很重要!!!一定要要保证数据传输的正确性!!!

image-20220324120155237

然后惊奇地发现,ROLL数据变得正常了?!!不再反复横跳,能正确计算ROLL角度的实时变化。然后就只剩PITCH角度需要调试了。

等等!!!麻了,遇到一个更诡异的现象,就是,经过一段时间之后,ROLL和PITCH的情况交换了,也就是,ROLL变得反复横跳,PITCH则是能正常测量。然后。。。再过一段时间,又会交换,绝了。算了,一步一步DEBUG吧。

经过观察,MPU6050读出的原始数据没有问题。

接下来进一步DEBUG。

  1. 观察原始的,未经滤波的ROLL和PITCH

在经过Kalman_Iter_Unit之前,roll、pitch、gyro_x_fp、gyro_y_fp都是正常的。所以问题出在迭代部分,这次我准备先写一个tb来对Iter模块进行仿真。

果然,tb的结果出错了,这次的情况是,开始的一段时间并没有异常,随着计算的轮数增加,PITCH越来越偏,开始反复横跳。

image-20220325122314295

按照数据流向观察计算过程,发现UPDATE模块计算的divident1和K1的值很奇怪,仔细一看,发现由于K_0和K_1晚K_done一个周期,而后续的angle_temp和bias_temp的计算都会用到新的K_0、和K_1的结果,但是这里采集的仍然是老的K_0和K_1(step的上升沿),所以导致了后续结果的错误。

image-20220325154052927

要解决这个问题就是把K_done延迟一个周期,修改后的结果如图:

image-20220325172044296

同时发现一个事实:每经过一轮更新,ROLL和PITCH的P矩阵的值都是一样的。因为P的初始值都相同,P的更新过程都是一样的。

从这次的经验来看,好好写tb是多么重要!!!

完结撒花!!!