大家在开发过程中遇到BUG?
真正的目的是给自己一个纠错记录,最近老是忘事,遇到的bug,过几天再次遇到,就会忘了之前如何处理,遂留笔记一篇,也给后面可能遇到该问题的小伙伴一个借鉴。
问题汇总:最近没得更新,主要是我们搞到了一批芯片,之前的项目可以重新提上日程,于是保留了之前的开发思路,在其他MCU平台上进行重新开发,遇到的问题是一件接着一件。首先产品端最初是STM32F030,现在的情况大家都了解,这颗料肯定是无法再用了,虽然手里还有几千片存货,可能一周都坚持不住,于是主控换成了GD32E230F4,主频更高,但是flash太小,我的代码编译之后会超出内存空间,此为所遇问题之一。我们有一个用于给产品配合的小玩意,一般一个客户有几个就行,小客户一个便可。之前为了开发快捷迅速,选择了STM32F103作为主控,所有功能开发完毕。
但是因为这个小玩意是免费赠送,而且现在STM32F103也买不到,这个问题只有换芯片才能解决,于是换了GD32E230F4,同样面临代码空间不够的问题,而且还附带其他问题,此为其二。还有一个是用STM32F030遇到发送数据也会进入USART的空闲中断,无论代码如何处理。此为其三。
问题详情及解决之道:
问题一:flash空间不足的问题我算是解决了一半,只能算解决了问题,而解决问题后所带来的其他问题,本人暂时无法追踪原因。因为之前STM32F030的flash足够大,所以没遇到这个问题,在资源紧张的GD32E230中遇到了。但是在缺货的情况下,能找到一颗供应满足的MCU实属不易,想方设法也得用起来。在代码编写完之后遇到如下问题:
我第一次遇到这种问题,去搜索发现是代码太大,无法烧录进MCU的FLASH。检查发现code的确超出容量了。
于是借鉴网络上的方法提高优化等级。
可以发现明显变小,烧录也没问题,但是代码不正常运行,没有卡死在任何地方,但是确实功能异常,在debug后发现问题出在SPI通信,我使用DMA+SPI0,发送一个数组给传感器例如tx[3] = {0x01,0x02,0x03};然后接受数组可以正常接收到传感器数据rx[3] = {0x01,0x02,0x03},将优化等级提高到1,此时SPI收到的数据rx[3] = {0x03,0x01,0x02}。这就导致了我后面处理SPI数据的时候数据出错。于是我将发送的数据改为4个,也就是多发一个字节,此时接收到的数据是rx[4] = {0x00,0x01,0x02,0x03}。我在取数据的时候取后三个便可,这是一个治标不治本的办法,至今我没找到解决之道。其实这个问题的根源就是硬件IIC的驱动太大了,我没能简化掉。但是发现提高优化等级可以将代码空间压缩,那FLASH不就有闲置空间了吗?为何还要用外置EEPROM呢?于是舍弃外置EEPROM,更换片内FLAH。因为一页flash足够我用了,这里只写一页,下面的代码是参考官方例程自己简化的一个写FLASH的驱动,灰常好用。
void fmc_program(uint8_t* p_buffer,uint32_t Start_Address,uint16_t number_of_byte)
{
uint32_t u32data;//fmc解锁
fmc_unlock();
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGERR);
fmc_page_erase(ERASE_PAGE_START_ADDR);
address = PROGRAM_ADDRESS;
for(uint16_t i = 0;i<number_of_byte;i++)
{
u32data = (uint32_t)p_buffer[i];
fmc_word_program(address, u32data);
address+= 4U;
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGERR);
}
fmc_lock(); //fmc上锁
}
GD的FLASH例程叫FMC,一开始都没找到,以为例程没有。
过程很简单:
1.使用库函数fmc_unlock();函数将FLAH解锁,
2.使用库函数清标志位fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGERR);
3.使用库函数fmc_page_erase(ERASE_PAGE_START_ADDR);擦除一页,写之前必须先擦除,而且一擦就是整页,这里我有个内容没写,是需要先将原来的数据读出来的,否则会造成不需要改的数据擦掉。读数据直接取地址就行,将数据全读到一个数组中,然后在数组中将需要改的数据修改,调用这个驱动进行写便可。ERASE_PAGE_START_ADDR为该页的首地址。4.调用函数fmc_word_program(address, u32data);循环写入,我是从页首开始写,这个参数address就是上面的ERASE_PAGE_START_ADDR。5.写完重新置位标志位并上锁。
uint32_t data;
address = PROGRAM_ADDRESS;
for(uint16_t j=0;j<256;j++)//取出所有FLASH里面的数据
{
data = *(uint32_t*)address;
i2c_rxbuff[j] = (uint8_t)data;
address += 4U;
}
上面是将整页数据读出放在数组i2c_rxbuff中。
这里忽然想到还有一个问题,这里得说一下:我的工程用到了IIC,目的是像24C04里面写数据,但是我的项目要求没有足够的时间给我写,每个上位机的指令过来我必须及时回复,间隔时间只有几十微秒,而写24c04需要的是ms级别的时间,而且GD32E230没有足够的DMA通道给我使用,会和URAT以及SPI的DMA冲突。于是挤压了一点时间出来,在主循环执行IIC写操作,其他应用用DMA处理,这样每个指令之间都可以空出一点点时间来写,慢慢写呗,不影响正常通信就行。但是在调试的时候发现了一个问题,这个问题很严重,但是不会影响我之前的应用,前提是我不在主循环进行IIC的读写。问题很简单,我退出不了串口接收中断,这个问题在一般应用中很常见,但是因为项目需求的原因,我所有的应用都在中断内完成,没有中断外的应用,都是一个中断打断另一个中断。最后还是在论坛里找到了答案。这一点在GD的例程中是没有体现的,
问题二:代码空间不足的问题上文已经处理,这里不赘述。这里说一下其他问题。我们的产品为例节省成本,基本都是使用MCU内部时钟,之前ST是,现在GD也是,所用外设为:USRAT,SPI,IIC。均无任何问题。但是在芯片荒之前用STM32F103做这个小玩意时加上了外部晶振,而这次改用GD32E230再次取消外部晶振,于是遇到了大问题。我通过定时器触发SPI采集若干个数据,在MCU内部进行算法处理,得到的值有问题,我怀疑是MCU计算出错,毕竟里面包括了浮点运算,三角函数等等。于是我将数据导入到EXCLE中,发现计算并无问题。最后问题定位在定时器不准,在使用内部时钟时,其他通信外设没有问题,我就觉得内部时钟是可靠的,但是遇到定时器他就歇菜了。于是重新打板,问题得以解决。还有个问题就是很容易出现的SPI通信问题,在产品上,MCU和传感器是在同一个PCB上,距离很近,用100Khz的通信速率可以读写传感器内部EEPROM,但是用这个小玩意和产品通信时通过排线连接,100K的通信速率会导致通信失败,降低通信速率,将速率降低到50K便可。
问题三:发送数据进入串口接收中断直到写这篇帖子之前才找到原因,在网上没找到这个问题的解决之道,也怀疑过时清标志位的问题,但是无论我如何操作,都无法解决这个问题。然后用示波器点了一下rx
明明在发送数据,但是却有一个下降沿,然后再看空闲中断的定义:空闲中断是接收数据后出现一个byte的高电平(空闲)状态,就会触发空闲中断.并不是空闲就会一直中断,准确的说应该是上升沿(停止位)后一个byte,如果一直是低电平是不会触发空闲中断的。因为这一个电平的下拉,导致电平回拉的时候产生了一个上升沿,导致误判为空闲状态。查看电路图,发现了一颗碍事的下拉电阻。
于是将该电阻拆掉便可,这个问题之所以一直未发现,其实是之前所有的应用都用不到空闲中断,电路一直这么设计并无问题,但是在空闲中断应用中就会导致出错。ps:硬件不是我设计,所以这个问题发现的比较晚,而且我之前发现这个问题后在软件上做处理给抵消了。不影响使用。