主要参考文档:rt-thread-master\rt-thread-master\bsp\gd32\docs\GD32系列BSP制作教程.md
GD32F4xx_Firmware_Library_User_Guide_V1.0.pdf
GD32F4xx_yonghushouce_Rev2.6.pdf
GD32F427xx_Datasheet_Rev1.0.pdf
GD32407R_START_Demo_Suites
过程中的关键点:
RT-Thread完整版和nano的区别移植的具体哪个型号,要据此修改配置文件注意标准库和rt-thread间的匹配,可能版本不一样,前者在兆易创新官网找,后者在rt-thread开源仓库找标准库和rt-thread间的过度库移植自gdf103,所以版本一样也可能库不兼容,在下面的坑描述会提到主要修改的文件:SConscript、SConstruct、Kconfig,这些分布在各个子文件夹中
注意事项:
如果把rt-thread-master中的例程移植到别的地方,注意修改bsp/gd32/gd32407v-start/Kconfig中的路径相关内容,比如default “…/…/…” source “…/libraries/Kconfig” source “board/Kconfig”,修改为自己的相对位置
bsp/gd32/gd32407v-start/SConstruct中的路径相关内容要修改比如,RTT_ROOT = os.path.normpath(os.getcwd() + ‘/…/…/…’)
bsp/gd32/gd32407v-start/board/linker_scripts/link.sct中的flash和ram地址要根据手册提供的具体大小进行修改,并且和keil的 Read/Only Memory Areas设置一致
移植完成后记得复制rtconfig.py文件过来,否则在控制台使用scons的时候会报错
注意单片机flash分几块,ram分几块区域:仿真调试一直卡在rt_hw_hard_fault_exception,在rt_system_heap_init的时候报错,
修改board.h里面的GD32_SRAM_SIZE从256改为192 因为两个ram不连续,另外64kb从0x10000000开始
官方没有提供GD32f425或者427的库的话,可以选择f405或者407,基本可以替代
每次用rtt的工具设置后都要求添加某个路径,即便之前已经在keil中添加过了;路径要在使用env前在文件对应文件夹下的SConscript中进行添加,比如path = [cwd] path += [cwd + ‘/CubeMX_Config/Core/Inc’]
Error: L6200E: Symbol __rt_init_cpu_usage_init multiply defined (by cpu_usage-v1.0.0_cpu_usage.o and cpu_usage.o). 去掉packages文件夹里面的cpu_usage-latest文件夹,或者其它类似的packages文件夹里有两个不同版本的第三方包问题
如果把rt_components_board_init和rt_components_init和屏蔽了,INIT_BOARD_EXPORT和其它类似函数是不起作用的
一、在rt-thread环境下移植外设到GD32
如果在RT-Thread env工具的menuconfig中找不到对应内容,要按照固定格式编辑board中的Kconfig文件
外设号在stm32的基础上统一减一,从0开始,比如stm32的串口1对应gd32的串口0,stm32的串口2对应gd32的串口1,以此类推;stm32的iic1对应gd32的iic0;stm32的spi1对应gd32的spi0;stm32的pwm1对应gd32的pwm0;stm32的timer1对应gd32的timer0;stm32的adc1对应gd32的adc0;stm32的dac1对应gd32的dac0;其它外设以此类推
下述一些问题的共同点是rt-thread的过渡函数和gd32的新标准库匹配不上
一、移植看门狗/RTC到GD32
drv_wdt.c 中 “RCU_IRC40K” is undefined,经查阅手册,没有40k内部时钟,改为RCU_IRC32K
添加WWDG_IRQn定义,HAL_NVIC_DisableIRQ改为NVIC_DisableIRQ,HAL_NVIC_ClearPendingIRQ改为NVIC_ClearPendingIRQ
#define WWDG_IRQn 0// Window WatchDog Interrupt
在watchdog_init中添加rt_device_init(wdg_dev);
rcu_periph_clock_enable(RCU_BKPI);中的RCU_BKPI找不到定义,经查阅用户手册应为RCU_BKPSRAM
board\board.c(31): error: #20: identifier “RTC_HandleTypeDef” is undefined 去掉其定义,用标准库替代
修改获取时间戳get_rtc_timestamp的内部实现为rtc_timestamp_subsecond_get();
添加设置时间戳函数rtc_timestamp_subsecond_set(rtc_counter); 重新实现set_rtc_timestamp
二、移植ADC/DAC到GD32
adc配置时报错libraries\gd32_drivers\drv_adc.c(61): error: #20: identifier “GPIO_MODE_AIN” is undefined:error所在行的函数和参数都不对,改为 gpio_mode_set(PIN_GDPORT(pin), GPIO_MODE_ANALOG, GPIO_OSPEED_50MHZ, PIN_GDPIN(pin));//bug gpio_init - gpio_mode_set GPIO_MODE_AIN - GPIO_MODE_ANALOGadc_deinit(adc_periph);显示error: #140: too many arguments in function call 去掉adc_periph可解决adc_external_trigger_source_config(adc_periph, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);中的ADC0_1_2_EXTTRIG_REGULAR_NONE找不到定义,将其暂时改为ADC_EXTTRIG_REGULAR_T0_CH0,并将上面的规则组外部触发使能改为不使能adc_regular_channel_config(adc_periph, 0, channel, ADC_SAMPLETIME_239POINT5);中的ADC_SAMPLETIME_239POINT5未定义 将ADC_SAMPLETIME_239POINT5 改为 ADC_SAMPLETIME_480rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV6);找不到定义,改为rcu_apb2_clock_config(RCU_APB2_CKAHB_DIV8);adc_mode_config(ADC_MODE_FREE);找不到定义,改为adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT);gd32未提供drv_dac文件,需手动实现(具体实现文件在工程中搜drv_dac.c),drv_dac比drv_pwm实现简单,实现过程的一些记录 Kconfig及dac相关文件的DAC1\2改为0\1,并开启DAC0添加drv_dac.c、drv_dac.h和dac_config.h文件添加HAL_DAC_StateTypeDef、DAC_HandleTypeDef及其它dac相关的结构体和宏定义,暂时去掉DMA相关内容添加gd32_dac_enabled和gd32_dac_disabled函数添加gd32_set_dac_value和gd32_dac_init函数,注意dac的两个引脚对应通道是固定的在Kconfig中添加DAC的设备名字和通道选择
三、移植内部flash操作到GD32
fal_flash_stm32l4_port.c文件需要适配gd32rt_sfud_flash_probe(SPI_FLASH_CHIP, SPI_FLASH_DEVICE_NAME)中的SPI_FLASH_CHIP找不到定义,将SPI_FLASH_CHIP改为自己外部flash芯片的名字或者规定名字drv_flash需手动实现(具体实现文件在工程中搜drv_flash.c和fmc_operation.c),用于对片内和片外flash的访问读写等操作,实现过程的一些记录 添加drv_flash源文件和头文件在gd32驱动库脚本中添加drv_flash.c路径,修改SOC_SERIES_STM32L4为SOC_SERIES_GD32F4xx在gd32标准库脚本中添加gd32f4xx_fmc.c路径添加fmc_operation头文件和源文件及脚本路径stm32_onchip_flash中的FLASH_PAGE_SIZE改为SIZE_4KB,gd32只有少数芯片支持页擦除即4k擦除,如果是不支持页擦除的芯片不可以用SIZE_4KB,要根据块来定,不同位置的块大小不一样添加flash起始和结束地址重写fal_flash_read、fal_flash_write函数添加fal_flash_erase函数将fal_flash_stm32l4_port.c改为fal_flash_gd32f4_port.c,并在脚本中添加路径添加get_page和fmc_page_erase函数添加FMC_PECFG和FMC_PEKEY寄存器添加UNLOCK_PAGE_KEY定义在flash读写操作中添加操作状态返回
四、移植外部flash操作及spi到GD32
spi底层未初始化正确,会卡在rt_assert_handler,assertion failed at function:rt_hw_spi_device_attach, line number:419 ,即注册失败,可能原因是序号错误、引脚定义或复用错误报错:“no source”: Error: #219: error while deleting file “.\build\keil\obj\gd32_drivers_drv_spi.d”: Permission denied;原因是每次通过env生成过程的时候会自动加入gd32_drivers_drv_spi.c文件,找了各个构建文件都没有这个文件,但是显示到了keil的project上,没法打开,也不存在这个文件; 解决方法:将gd32_drivers_drv_spi.c去掉或者禁止编译libraries\gd32_drivers\drv_spi_flash.c(89): error: At end of source: #65: expected a “;” 在INIT_COMPONENT_EXPORT(rt_hw_spi_flash_with_sfud_init)后面加一个;缺少stm32_onchip_flash的定义,gd32_drivers没有drv_flash文件夹,暂时将stm32_onchip_flash也改为nor_flash0没有板载flash或者flash损坏情况会卡在sfud_device_init(sfud_dev)这里,错误原因是SFUD_ERR_NOT_FOUND,为了后续测试可以先屏蔽此错误(屏蔽rt_sfud_flash_probe(“xxxxx”, xxxxx_SPI_DEVICE_NAME))
五、移植定时器和时钟配置
GD32标准库没有drv_pwm文件,暂不支持DMA和捕获,手动实现(具体实现文件在工程中搜drv_pwm.c),实现过程的一些记录 修改gd32_drivers的SConscript文件,添加手动实现的pwm源文件及drv_log头文件修改Kconfig以适配不同库对同一外设的不同命名,比如BSP_USING_TIM改为BSP_USING_HWTIMER修改标准库的脚本文件添加gd32f4xx_timer.c按着标准库提供的文件添加TIM_HandleTypeDef定义,暂时去掉DMA相关的内容添加pwm_config头文件,修改其中.tim_handle.Instance为gd32标准库格式并添加定时器0修改HAL_TIM_ActiveChannel定义使用移位实现__HAL_TIM_GET_CLOCKDIVISION等简单hal函数使用gd32库函数重新实现_HAL_TIM_SET_PRESCALER、_HAL_TIM_SET_AUTORELOAD、__HAL_TIM_SET_COUNTER、__HAL_TIM_GET_COMPARE等复杂一些函数根据GD32时钟树及hal库逻辑重写drv_pwm_get和drv_pwm_set函数(只适配了f4)未找到HAL_TIM_GenerateEvent对应的替代函数,暂时使用timer_disable和timer_enable代替替代TIM_OC_InitTypeDef和__HAL_TIM_URS_ENABLE,未找到TIM_MasterConfigTypeDef和TIM_ClockConfigTypeDef的替代HAL_TIM_Base_Init替换为timer_init,timer_init没有初始化失败返回,未找到HAL_TIM_PWM_Init替代,注意gd32库中基本没有pwm的定义,取而代之的是TIMER channel output的定义替代pwm初始化关于时钟源相关的配置将timer0添加到CK_APB2判断中(需要查看数据手册的时钟树)HAL_TIMEx_MasterConfigSynchronization未找到替代,应该是输入捕获相关的,暂不需要实现参考hal_msp文件实现pwm输出引脚映射函数GD32_TIM_MspPostInit(TIM_HandleTypeDef* htim),没有cubemx了,这个函数每次更换引脚后要手动更新修改pwm_get_channel函数中数据填充内容按照hal库的stm32_hw_pwm_init逻辑重新实现gd32_hw_pwm_initpwm的时间不对,1khz出来4khz,修改分频clockdivision不起作用,将分频prescaler扩大4倍起作用gd32库未提供pwm单通道开关函数(用的另一种方式实现,但这种方式和rt-thread的调用顺序相违背),只有某定时器开关函数,暂不实现对pwm单通道的开关,默认设置pwm后自动输出
六、其它
修改I2C0驱动不兼容的问题,I2C4_BUS_CONFIG修改为I2C0_BUS_CONFIGGPIO相关的一些重映射#define GPIO_PIN_RESET RESET#define GPIO_PIN_SET SET#define HAL_GPIO_WritePin(GPIOx, GPIO_Pin, PinState) gpio_bit_write(GPIOx, GPIO_Pin, PinState)#define HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) gpio_input_bit_get(GPIOx, GPIO_Pin)#define __HAL_RCC_GPIOA_CLK_ENABLE() rcu_periph_clock_enable(RCU_GPIOA) #define __HAL_RCC_GPIOB_CLK_ENABLE() rcu_periph_clock_enable(RCU_GPIOB)#define HAL_GPIO_DeInit(GPIOx, GPIO_Pin) __NOP //gpio_deinit(GPIOx) gd32没有初始化单个引脚,只有port#define HAL_Delay(Delay) rt_thread_mdelay(Delay)
一些外设测试函数
//testOTAextern void rt_fota_init(void);rt_fota_init();//testadcextern int16_t get_adc_temperature_value(void);uint16_t vol = get_adc_temperature_value();LOG_I("the controller temperature is :%dmV", vol);//testdacrt_dac_device_t dac_dev = (rt_dac_device_t)rt_device_find(BSP_USING_RF_PA_VBIAS_DAC_DEVICE_NAME);if (dac_dev == RT_NULL){LOG_E(find_device_Err, BSP_USING_RF_PA_VBIAS_DAC_DEVICE_NAME);}rt_dac_enable(dac_dev, BSP_USING_RF_PA_VBIAS_DAC_DEVICE_CHANNEL);for(uint16_t i=0; i<4095; i++){rt_thread_mdelay(10);rt_dac_write(dac_dev, BSP_USING_RF_PA_VBIAS_DAC_DEVICE_CHANNEL, i);}//testpwmrt_pwm_set(pwm_device, TIMER_CH_0, LED_STATE_PERIOD, LED_STATE_PERIOD/2);//设置pwm设备的TIMER_CH_0通道//testwkuprt_thread_mdelay(2000);LOG_I("enter standbymode");rt_thread_mdelay(2000);Sys_Enter_Standby();LOG_I("out standbymode");//testgpiort_pin_write(LEDR_PIN, PIN_LOW);rt_thread_mdelay(1000);rt_pin_write(LEDR_PIN, PIN_HIGH);extern rt_uint8_t key_up_read_pin();uint8_t IO = key_up_read_pin();LOG_I("the io state is :%d", IO);
二、在rt-thread环境下移植HAL库到GD32
GD32也可以使用hal库,但是异常比较多,可以使用标准库,把之前的hal库的函数用类似的标准库函数替代
CubeMX_Config文件夹的内容需要做适配,不用hal也要适配,否则找不到main.h文件(board\CubeMX_Config\Core\Inc\main.h)
stm32l4xx_hal.h文件和gd32f30x.h不一样,gd32f30x.h和stm32l476xx.h一样是地址映射相关的内容
libraries\GD32F30x_Firmware_Library\CMSIS\GD\GD32F30x\Include\gd32f30x.h(115): error: #101: “NonMaskableInt_IRQn” has already been declared in the current scope:出现上述错误是因为重定义了,需要把CubeMX_Config文件中的l4相关的内容去掉
报错 #error “Please select the target GD32F4xx device in gd32f4xx.h file”,是因为标准库没有定义GD32F42x,需要在keil的宏定义里面点击魔术棒->C/C++/Define,添加GD32F405,或者修改board文件夹下面的SConscript文件中的GD32F425为GD32F405(这是长久生效的方法),F405和407是最接近的
修改引用头文件stm32l4xx.h为gd32f4xx.h
直接复制移植HAL_StatusTypeDef定义
libraries\GD32F4xx_Firmware_Library\CMSIS\GD\GD32F4xx\Include\gd32f4xx.h(292): error: #40: expected an identifier
typedef enum {FALSE = 0, TRUE = !FALSE} bool; 参考解决方法,省流:重复定义了
GPIO_MODE_AF_PP显示未定义 原因:SOC_SERIES_GD32F4xx未定义导致"gd32f4xx_gpio.h"未被添加进来,解决方法:board\Kconfig文件config SOC_SERIES_GD32F425RG改为SOC_SERIES_GD32F4xx
重新实现SystemClock_Config
void SystemClock_Config(void){SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);systick_clksource_set(SYSTICK_CLKSOURCE_HCLK);NVIC_SetPriority(SysTick_IRQn, 0xFF);}
重新实现进入低功耗函数Sys_Enter_Standby
int Sys_Enter_Standby(void){rcu_periph_clock_enable(RCU_PMU);pmu_wakeup_pin_enable();pmu_to_standbymode(WFI_CMD); //notice:WFI need EXTI interrupt wakeupreturn 0;}
注意stm32l476有5个wkup唤醒源引脚,gd32只有一个PA0引脚做待机唤醒用
gd32没有实现类似HAL_PWREx_DisablePullUpPullDownConfig的函数,即gd32没有进入待机模式后锁定某个引脚状态的功能
移植获取uid的相关定义
uint32_t UUID = FMC_PID;
```
将__HAL_PWR_GET_FLAG(PWR_FLAG_SB)替换为pmu_flag_get(PMU_CS_STBF)
将__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);替换为pmu_flag_reset(PMU_FLAG_RESET_STANDBY);
将HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN5);改为pmu_wakeup_pin_disable();
HAL_RCC_DeInit改为rcu_deinit
三、在rt-thread环境下移植bootloader/OTA到GD32
rt-thread的bootloader不开源,可参考及移植的开源项目/Aladdin-Wang/RT-FOTA-STM32L431和/spunky_973/rt-fota?_from=gitee_search
添加或者去掉bootloader时需要修改\board\linker_scripts\link.sct,或者点击keil->options->linker->scatter file->edit,修改LR_IROM1和ER_IROM1的起始地址,比如bootloader占256k,就改为0x08040000
程序中关于中断偏移的要修改,正常的话就nvic_vector_table_set(NVIC_VECTTAB_FLASH, 0);偏移256k的话就 nvic_vector_table_set(NVIC_VECTTAB_RAM, 0x40000);或者沿用自己的方式
SCB->VTOR在单片机的数据手册找不到,可以取M4内核编程手册上查找
RF-FOTA开源移植过程的一些记录
打开ymodem配置,为了方便开关ota功能,在kconfig中添加PKG_USING_YMODEM_OTA相关定义,用于开启rf_fota.h中关于ota的宏定义,并修改fm_area为下载分区,df_area为工程文件分区
#ifdef PKG_USING_YMODEM_OTA#define RT_USING_SPI#define RT_USING_SFUD#define RT_SFUD_USING_SFDP#define RT_SFUD_USING_FLASH_INFO_TABLE#define RT_USING_WDT/* FOTA application partition name */#ifndef RT_FOTA_APP_PART_NAME#define RT_FOTA_APP_PART_NAME "app"#endif/* FOTA download partition name */#ifndef DEFAULT_DOWNLOAD_PART_NAME#define DEFAULT_DOWNLOAD_PART_NAME "download"#endif/* FOTA default partition name */#ifndef DEFAULT_FACTORY_PART_NAME#define DEFAULT_FACTORY_PART_NAME "factory"#endif/* AES256 encryption algorithm option */#define RT_FOTA_ALGO_AES_IV "0123456789ABCDEF"#define RT_FOTA_ALGO_AES_KEY "0123456789ABCDEF0123456789ABCDEF"/* RT-FOTA module define */#define RT_FOTA_SW_VERSION"1.0.0"#endif#define FAL_PART_TABLE \{ \{FAL_PART_MAGIC_WORD, "bl","onchip_flash",0*128*1024, 128*1024, 0}, \{FAL_PART_MAGIC_WORD, "app", "onchip_flash",2*128*1024, 256*1024, 0}, \{FAL_PART_MAGIC_WORD, "download", "onchip_flash",4*128*1024, 256*1024, 0}, \{FAL_PART_MAGIC_WORD, "factory","onchip_flash",6*128*1024, 256*1024, 0}, \}
添加FastLZ库、QuickLZ库、 SignalLed库,这些库在fota上用
因为用的是片内flash升级,开源是片外的,为了省一些bin的大小,去掉片外相关的内容,比如sfud和nor_flash0
屏蔽掉fal库中fal_flash_sfud_port.c的内容
添加WWDG_IRQn定义,定义为0
HAL_RCC_DeInit();改为rcu_deinit();
重新实现HAL_DeInit(); – 添加复位所有外设的实现,复位之后清除复位标志,未找到复位时钟,例
rcu_periph_reset_enable(RCU_GPIOARST);rcu_periph_reset_disable(RCU_GPIOARST);·····
原工程未定义按键恢复出厂及按键时间,可以加上
因为是从原gd32工程复制过来修改成bootloader的,注意修改中断偏移和link.sct、各个线程的顺序和一些重要参数(比如rt_system_scheduler_init、rt_hw_board_init)的一致性,尽量把之前没用的外设关掉,没用的文件输出,保证bootloader的精简
打开“Options for target…”->“target”勾选“Use MiclroLIB”,否则一仿真就在BEAB BKPT 0xAB
添加是否进入shell mode的提示,打开FAL_DEBUG
GD32的FMC读取一次最多256字节,OTA搬移的时候一次需要4k,fmc_read_8bit_data的读取长度改为32位
将fmc_write_8bit_data中的擦除函数去掉,因为在fal_flash_erase中重定义fal_flash_erase了,否则会crc校验错误
通过Xshell进入控制台后,发送ymdown -p factory可以直接将rbl文件升级到工厂固件区
FOTA未实现hash校验功能,/spunky_973/rt-fota/issues/I41CTW这里面有实现
其它一些issues见/Aladdin-Wang/RT-FOTA-STM32L431/issues/I1S58N和/spunky_973/rt-fota/issues
移植的rbl文件如果打不开,可以添加.bin的后缀,使用STM32 ST-LINK Utility或者BCompare.exe打开
四、移植GD32遇到的和程序无关keil报错
browse information of one or more file is not available:.\xx\xxxx.c,解决方法:注释再取消注释文件 ①全选文件中的代码,按下注释键,编译 ②再全选,按下取消注释,问题就解决了插上jlink报错没识别到f427,会自动跳出一个页面选择,这时候选择f407rg可以互相兼容keil显示encountered an improper argument,后台中止重新启动打开“Options for target…”->“target”勾选“Use MiclroLIB”,否则一仿真就在BEAB BKPT 0xAB在rtt的配置工具中使用scons --target=mdk5 -s生成工程后会出现一个文件夹中没有的文件,命名格式是它的路径+文件名,比如src文件下的timer.c会变成src_timer.c,这样编译的时候会显示找不到这个文件或者报错误1,原因是还有一个别的路径下也有一个timer.c,重复,系统自动改名字了,解决方法是修改重复文件的名字,重新scons --target=mdk5 -s五、移植过程中添加的pwm驱动、dac驱动、flash驱动、RTC驱动、OTA例程
本来想给上传到rt-thread的github库,但之前没上传过别人的库,也没有做其它型号芯片的兼容,所以发到博客上吧
GD32 RT-Thread PWM驱动函数
GD32 RT-Thread DAC驱动函数
GD32 RT-Thread flash驱动函数
GD32 RT-Thread RTC驱动函数
GD32 RT-Thread OTA/Bootloader驱动函数
如果觉得《移植完整版RT-Thread到GD32F4XX(详细)》对你有帮助,请点赞、收藏,并留下你的观点哦!