GD32F450替换ST32F429 部分flash速度慢问题解决

  1. 由于st的芯片涨价,原来一片stm32f429ZGT6只要40多块钱,现在一片400多块钱,就这还没货,而GD32F450ZIT6现在100多块钱一片(之前20多一片),所以公司决定替换降本,选用pin to pin的GD32F450ZIT6替换ST芯片,任务就分配给我,直接烧录使用hal库的st应用代码调试,发现GD的片子串口中断方式接收数据,在波特率大于57600的情况下就会丢字节,大概50-100个字节就会丢失一个字节,但同样的代码在ST上完全正常。而使用GD提供的库函数,则串口完全正常,遂开始着手解决问题。
  2. 于是第一个考虑的是库函数的问题,开始对比Hal库与GD的标准库串口初始化的区别,经过两天的对比之后发现在底层操作上完全没有任何区别 = = ,同时感叹hal库看起来真让人头疼,从头到尾的函数指针,指到人逐渐崩溃。排除是库函数的问题。
  3. 排除掉库函数的问题,我就真的不知道是什么问题了,只好百度GD单片机问题汇总,最终发现GD的片子flash有高低速之分,而ST的全部为高速flash(贵有贵的道理哈),我用的这款GD芯片,flash一共是2M字节—高速区是flash的前256K字节(0x08000000-0x08040000),低速区是flash的后1792K字节(0x80400000-0x82000000),于是猜想是串口中断处理函数编译在了低速区flash,导致每次中断内代码执行时间过长,波特率越高,中断频率越高,也就自然会丢失字节。
  4. 有了猜想就开始验证----查看keil生成的.map文件发现,串口中断内的所有函数都编译在了低速区,也就是在地址0x80400000之后,那么到底低速区flash执行速度相较高速区慢了多少呢?于是使用一个定时器来测试同样的代码在高速区的执行速度与低速区的执行速度对比,代码如下:
//定时器时钟频率设定在1MHZ,计数方式为向上计数,上溢值设置为60000,因此CNT寄存器值每加1,就等于计时1us,所以这个计数最多可以计时60ms。
//清零CNT寄存器(当前计数值寄存器)
__HAL_TIM_SET_COUNTER(&htim6,0);
//开启定时器
HAL_TIM_Base_Start(&htim6);
//获取CNT寄存器值
time_began=__HAL_TIM_GET_COUNTER(&htim6);
//运行测试代码
TimeTest();
//再次获取CNT寄存器值
time_end=__HAL_TIM_GET_COUNTER(&htim6);
printf("TimeTest()函数耗时=%dus",time_end-time_began);
//关闭定时器
HAL_TIM_Base_Stop(&htim6);

使用以上代码测试发现,在ST上运行,TimeTest()函数耗时4到5us,在GD上运行,TimeTest()函数在高速区耗时3到4us;在低速区耗时57us之久!速度居然相差15倍之大…于是得出结论,GD-HighSpeedFlash>=ST-flash>>GD-LowSpeedFlash,好了,接下来要做的就是,如何把对耗时有严格要求的代码编译到高速区flash内,对耗时有严格要求的代码,例如 中断,实时系统(ucos、freertos)。步骤如下:

1


2,点击Linker,取消勾选[Use Memory Layout from Target Dialog],点击[Edit…]
在这里插入图片描述
3编辑.sct文件,比如说你要把main.c和stm32f4xx_it.c,stm32f4xx_hal_gpio.c编译在高速区,把user_a.c与user_b.c编译到低速区,那么你可以这样写:

;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)
   ;*是通配符,写过脚本的应该都理解,不理解的自行百度,这样就把stm32f4xx_it.c,stm32f4xx_hal_gpio.c都编译进了高速区
   ;(+RO)代表将stm32f4xx*.c文件中的代码段,全局变量,静态变量编译进去。
   stm32f4xx*.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_IROM1 0x08040000 0x08200000  {  ; load address = execution address
   .ANY (+RO)
   ;同理,这样就把user_a.c,user_b.c都编译进了低速区
   user_*.o (+RO)
  }
}

这个文件就是一个脚本文件,规定了.c文件编译在flash中的地址,语法规则自行百度, ;号后是注释,这样就可以完美的把不同的.c文件编译进自己指定的flash区域了。
修改之后,GD的片子串口就不再丢数据了,根本原因就是将中断代码编译进了低速区。问题解决。
如果你觉得这篇文章还行,点个赞吧

版权声明:本文为CSDN博主「雪狐JXH」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39525606/article/details/117925772

  1. 由于st的芯片涨价,原来一片stm32f429ZGT6只要40多块钱,现在一片400多块钱,就这还没货,而GD32F450ZIT6现在100多块钱一片(之前20多一片),所以公司决定替换降本,选用pin to pin的GD32F450ZIT6替换ST芯片,任务就分配给我,直接烧录使用hal库的st应用代码调试,发现GD的片子串口中断方式接收数据,在波特率大于57600的情况下就会丢字节,大概50-100个字节就会丢失一个字节,但同样的代码在ST上完全正常。而使用GD提供的库函数,则串口完全正常,遂开始着手解决问题。
  2. 于是第一个考虑的是库函数的问题,开始对比Hal库与GD的标准库串口初始化的区别,经过两天的对比之后发现在底层操作上完全没有任何区别 = = ,同时感叹hal库看起来真让人头疼,从头到尾的函数指针,指到人逐渐崩溃。排除是库函数的问题。
  3. 排除掉库函数的问题,我就真的不知道是什么问题了,只好百度GD单片机问题汇总,最终发现GD的片子flash有高低速之分,而ST的全部为高速flash(贵有贵的道理哈),我用的这款GD芯片,flash一共是2M字节—高速区是flash的前256K字节(0x08000000-0x08040000),低速区是flash的后1792K字节(0x80400000-0x82000000),于是猜想是串口中断处理函数编译在了低速区flash,导致每次中断内代码执行时间过长,波特率越高,中断频率越高,也就自然会丢失字节。
  4. 有了猜想就开始验证----查看keil生成的.map文件发现,串口中断内的所有函数都编译在了低速区,也就是在地址0x80400000之后,那么到底低速区flash执行速度相较高速区慢了多少呢?于是使用一个定时器来测试同样的代码在高速区的执行速度与低速区的执行速度对比,代码如下:
//定时器时钟频率设定在1MHZ,计数方式为向上计数,上溢值设置为60000,因此CNT寄存器值每加1,就等于计时1us,所以这个计数最多可以计时60ms。
//清零CNT寄存器(当前计数值寄存器)
__HAL_TIM_SET_COUNTER(&htim6,0);
//开启定时器
HAL_TIM_Base_Start(&htim6);
//获取CNT寄存器值
time_began=__HAL_TIM_GET_COUNTER(&htim6);
//运行测试代码
TimeTest();
//再次获取CNT寄存器值
time_end=__HAL_TIM_GET_COUNTER(&htim6);
printf("TimeTest()函数耗时=%dus",time_end-time_began);
//关闭定时器
HAL_TIM_Base_Stop(&htim6);

使用以上代码测试发现,在ST上运行,TimeTest()函数耗时4到5us,在GD上运行,TimeTest()函数在高速区耗时3到4us;在低速区耗时57us之久!速度居然相差15倍之大…于是得出结论,GD-HighSpeedFlash>=ST-flash>>GD-LowSpeedFlash,好了,接下来要做的就是,如何把对耗时有严格要求的代码编译到高速区flash内,对耗时有严格要求的代码,例如 中断,实时系统(ucos、freertos)。步骤如下:

1


2,点击Linker,取消勾选[Use Memory Layout from Target Dialog],点击[Edit…]
在这里插入图片描述
3编辑.sct文件,比如说你要把main.c和stm32f4xx_it.c,stm32f4xx_hal_gpio.c编译在高速区,把user_a.c与user_b.c编译到低速区,那么你可以这样写:

;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)
   ;*是通配符,写过脚本的应该都理解,不理解的自行百度,这样就把stm32f4xx_it.c,stm32f4xx_hal_gpio.c都编译进了高速区
   ;(+RO)代表将stm32f4xx*.c文件中的代码段,全局变量,静态变量编译进去。
   stm32f4xx*.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_IROM1 0x08040000 0x08200000  {  ; load address = execution address
   .ANY (+RO)
   ;同理,这样就把user_a.c,user_b.c都编译进了低速区
   user_*.o (+RO)
  }
}

这个文件就是一个脚本文件,规定了.c文件编译在flash中的地址,语法规则自行百度, ;号后是注释,这样就可以完美的把不同的.c文件编译进自己指定的flash区域了。
修改之后,GD的片子串口就不再丢数据了,根本原因就是将中断代码编译进了低速区。问题解决。
如果你觉得这篇文章还行,点个赞吧

版权声明:本文为CSDN博主「雪狐JXH」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39525606/article/details/117925772

生成海报
点赞 0

雪狐JXH

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

GD32 ADC DMA

ADC_F450.cpp #include "Adc_F450.hpp" #include "main.h" #include /* STM32 所用管脚和ADC通道PA4 --- ADC1_IN4 --- ADC24