STM32芯片近年来涨价太厉害,翻了几乎10倍,如此情况下只能更换国产芯片,考虑之前有换过GD的,这次还是采用GD的芯片。
2022.4.20
首先:按照网上都能下载的替换说明改了启动时间以及内部FLASH擦除等位置后,程序烧录成功。 然鹅并没有那么简单,程序卡住无法启动。
排除问题,发现是GPIO模拟I2C总线读取时钟的代码卡住,暂时屏蔽,启动终于成功。
能正常启动,LED运行灯亮起来了,也算是初步有些进展,但是面临的问题还是很多;
2022.4.21
第一个问题就是串口问题,由于采用GD32芯片替换STM32,所以库函数并没有更换,沿用的STM的,低速波特率9600通讯无问题,但是在115200会出现丢包的情况。
1)在网上找到这样一个可能的原因:
GD32IDLEF中断需要先读STAT再读DATA才会清除。
而STM32可以直接清除对应的标志位 。因此代码加入如下几行:
/*--------------------USART1中断函数--------------------*/
void USART1_IRQHandler(void)
{
if (USART1_func) (*USART1_func)(USART1_para);
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
if(RESET != USART_GetITStatus(USART1, USART_IT_IDLE))
{
USART_ReceiveData(USART1);
}
else if(RESET != USART_GetITStatus(USART1, USART_IT_ORE))
{
USART_ReceiveData(USART1);
}
}
重新下载后发现并没有解决,看了还是没有找到真正的原因。
2)又找到这样一个可能的原因:原文:GD32F450的USART接收数据错误bug - 知乎
UART判断起始位的时候,16倍过采样,需要16个点全部为0才能确认。
实测115200波特率,正常低电平为1e6/115200=8.68us,实测经过422接口芯片以后,低电平比正常短7%(高电平长6%),刚好在临界点上。
7%超过了6.25%的误差容限,会导致16个采样点至少有一个不为0,采样不到起始位,导致出错。
将过采样降低到8倍,那么误差容限为1/8=12.5%,这样,115200波特率就不会有问题了,230400还是不行。
但是采样降低到8倍后还是不行。
进一步测试发现,当代码减少一部分,只是单独测试串口等有限的代码时在115200波特率是可以正常接收的。因此初步怀疑有可能是代码过多执行串口中断时候执行速度不够快,所以接收有确实。
3)GD的片子flash有高低速之分,而ST的全部为高速flash(贵有贵的道理哈),我用的这款GD芯片,flash一共是2M字节—高速区是flash的前256K字节(0x08000000-0x08040000),低速区是flash的后1792K字节(0x80400000-0x82000000),于是猜想是串口中断处理函数编译在了低速区flash,导致每次中断内代码执行时间过长,波特率越高,中断频率越高,也就自然会丢失字节。
————————————————
因此考虑采用分散加载来测试,把串口中断及服务子程序全部放入高速区。
;LR_IROM1 是flash 0x08000000-0x08040000 (高速区)区域
LR_IROM1 0x08000000 0x08040000 { ; load region size_region
ER_IROM1 0x08000000 0x00100000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
main.o (+RO)
intr.o (+RO)
scom.o (+RO)
;*是通配符,写过脚本的应该都理解,不理解的自行百度,这样就把stm32f4xx_it.c,stm32f4xx_hal_gpio.c都编译进了高速区
;(+RO)代表将stm32f4xx*.c文件中的代码段,全局变量,静态变量编译进去。
stm32f10x*.o (+RO)
}
RW_IRAM1 0x20000000 0x00030000 { ; RW data
.ANY (+RW +ZI)
}
RW_IRAM2 0x10000000 0x00010000 {
.ANY (+RW +ZI)
}
}
;LR_IROM1 是flash 0x08040000 0x08200000(低速区)区域
LR_IROM2 0x08040000 0x08200000 { ; load region size_region
ER_IROM2 0x08040000 0x08200000 { ; load address = execution address
.ANY (+RO)
;同理,这样就把user_a.c,user_b.c都编译进了低速区
}
}
经过测试,发现正常了。终于解决GD32串口高波特率丢包问题。
2022.4.25
第二个问题是模拟I2C的问题,主板有一个时钟芯片PCF8563,采用GPIO模拟I2C来读写。改成GD后无法正常读取。
https://blog.csdn.net/lmgandxka/article/details/119932876?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0.pc_relevant_default&spm=1001.2101.3001.4242.1&utm_relevant_index=3
在CSDN查到这样一个类似的问题:模拟IIC的时序好像不同(没做具体测试,也可能与我使用的通信芯片有关),STM32是delay_us(2),GD改为STM32是delay_us(4)后正常。
按照此方法修改后果然可以正常通讯,初步推测是由于I2C代码在GD的高速区,所以采用空炒作来延时需要增加时间。
第三个问题是内部FLASH的IAP读写问题。主板的配置参数是存储在内部FLASH里的,改成GD芯片后,参数无法正常存入。
查看芯片手册发现有这样一句: GD32F10x_XD,使用了两片闪存;前512KB容量在第一片闪存(bank0)中,后续的容量在第 二片闪存(bank1)中。其中bank0的闪存页大小为2KB,bank1的闪存页大小为4KB。
而之前用ST的芯片都是按每页2KB来处理的,存储参数用的又刚好是512KB之后的FLASH,所以改成GD芯片后,读操作应该可以按原来的操作都没问题,就是在擦除时按页擦除就有问题了,而写的时候通常要先擦除,所以这里需要修改擦除的代码。
修改对应代码后,功能正常。