【GD32】GD32F103RCT6运行RT-Thread实现IAP升级

前言

最近在使用gd32单片机,bootloader是产品不能少的一部分,所以准备基于RT-Thread实现一个Bootloader以及Iap升级。
众所周知GD32F103RCT6是可以平替STM32F103TCT6,但是作为强迫症的我不想用st的固件库或者HAL库,但是RT-Thread对GD32没有做板级支持包的设计,只能自己写,所以这里准备使用 RT-Thread4.1内核+env进行制作bsp,bsp就不说了教程有很多直接讲开发过程。

内核剪裁

由于GD32F103RCT6的Flash为256k,资源有限所以Bootloader尽量短小精悍。
只保留信号量、互斥量
在这里插入图片描述
关闭内核调试功能及软件定时器
在这里插入图片描述
其他的功能自己调整,我剪裁完后50
k左右,实际上最小能达到30k以下。
在这里插入图片描述
熟悉基于rtt构建bootloader的都知道第一步先配置fal组件,但是fal调用的是flash驱动,在gd系列里是需要自己实现对接接口的,这里就不多赘述一下是代码。

#include "rtthread.h"
#ifdef BSP_USING_FMC

#include "gd32f10x_fmc.h"

#if defined(RT_USING_FAL)
#include "fal.h"
#endif


/* FLASH����256K */
#define GD32FLASH_SIZE  0x40000UL

/* FLASH��ʼ��ַ */
#define GD32FLASH_BASE  FLASH_BASE

/* FLASH������ַ */
#define GD32FLASH_END   (GD32FLASH_BASE | GD32FLASH_SIZE)

/* FLASHҳ��С��2K */
#define GD32FLASH_PAGE_SIZE (2048U)

/* FLASH��ҳ�� */
#define GD32FLASH_PAGE_NUM  (GD32FLASH_SIZE / GD32FLASH_PAGE_SIZE)


int flash_write( rt_uint32_t addr, const rt_uint8_t *buf, size_t size)
{
  size_t i;
    rt_uint16_t buf16;

    if ((addr + size) > GD32FLASH_END)
    {
        log_e("ERROR: erase outrange flash size! addr is (0x%p)\n", (void*)(addr + size));
        return -1;
    }
    /* unlock the flash program/erase controller */
    fmc_unlock();

    fmc_flag_clear(FMC_FLAG_BANK0_END);
    fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
    fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
    i = (size_t)addr;
    if(i % 2 == 1)  //��ôд�˵��ֽڻ��ǻ�治��ȥ��ֻ�ܱ�֤û���
    {
        buf16 = *((rt_uint16_t*)buf)<<8 | 0xff;

        fmc_halfword_program(addr-1, buf16);
        buf++;
        addr++;
        size--;
    }
    for(i=0;i<size;i+=2)
    {
        buf16 = *((rt_uint16_t*)buf);
        if(size-1 == i)
        {
            buf16 |= 0xff00;
        }
        rt_kprintf("buf16 %x",buf16);

        fmc_halfword_program(addr + i, buf16);
        buf += 2;
    }

    /* lock the main FMC after the erase operation */
    fmc_lock();
    return size;
}
static int flash_erase(rt_uint32_t addr, size_t size)
{
  size_t i;


    if ((addr + size) > GD32FLASH_END)
    {
        //LOG_E("ERROR: erase outrange flash size! addr is (0x%p)\n", (void*)(addr + size));
        return -1;
    }
    /* unlock the flash program/erase controller */
    fmc_unlock();
//    fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR | FMC_FLAG_BANK1_WPERR | FMC_FLAG_BANK1_PGERR );
    fmc_flag_clear(FMC_FLAG_BANK0_END);
    fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
    fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
    for(i = 0;i < size;i += GD32FLASH_PAGE_SIZE)
    {
        fmc_page_erase(addr);
        addr += GD32FLASH_PAGE_SIZE;
//            fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR | FMC_FLAG_BANK1_WPERR | FMC_FLAG_BANK1_PGERR );
        fmc_flag_clear(FMC_FLAG_BANK0_END);
        fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
        fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
    }

    /* lock the main FMC after the erase operation */
    fmc_lock();
    return size;
}
static int flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size)
{
    size_t i;

    if ((addr + size) > GD32FLASH_END)
    {
            //LOG_E("read outrange flash size! addr is (0x%p)", (void*)(addr + size));
            return -1;
    }
    for (i = 0; i < size; i++, buf++, addr++)
    {
        *buf = (*(__IO uint8_t*) addr);
    }
    return size;
}

#if defined(RT_USING_FAL)

static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size);
static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size);
static int fal_flash_erase(long offset, size_t size);

const struct fal_flash_dev gd32_onchip_flash =
{
    .name       = "onchip_flash",
    .addr       = GD32FLASH_BASE,
    .len        = GD32FLASH_SIZE,
    .blk_size   = GD32FLASH_PAGE_SIZE,
    .ops        = {NULL, fal_flash_read, fal_flash_write, fal_flash_erase},

};

static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size)
{
      return flash_read(gd32_onchip_flash.addr + offset, (int8_t*)buf, size);
}

static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size)
{
      return flash_write(gd32_onchip_flash.addr + offset, (int8_t*)buf, size);
}

static int fal_flash_erase(long offset, size_t size)
{
    return flash_erase(gd32_onchip_flash.addr + offset, size);
}
#endif /* RT_USING_FAL */

#endif /* BSP_USING_FMC */

/************************ (C) COPYRIGHT  *****END OF FILE****/

RT_USING_FAL和BSP_USING_FMC是检测编译代码区域的,如果你使用了fal组件会自动添加RT_USING_FAL定义但是有可能定义名称不一样,这里要确认,BSP_USING_FMC这个是要自己添加的以下是添加步骤。

  1. 每个型号的bsp都有一个固件库以及驱动库,把flash.c的文件代码添加到gd32_drivers中后打开SConscript在这里插入图片描述

  2. 添加if GetDepend('BSP_USING_FMC'): src += ['drv_flash.c']这个是如果定义了BSP_USING_FMC关键字添加drv_flash.c驱动文件。

  3. 同级目下打开GD32F10x_Firmware_Library中的SConscript,添加if GetDepend('BSP_USING_FMC'): src += ['GD32F10x_standard_peripheral/Source/gd32f10x_fmc.c']这个是添加固件库文件的。

  4. 到board文件夹下打开Kconfig文件添加BSP_USING_FMC定义在这里插入图片描述
    这样整个就跟emv关联起来了。

Fal配置

打开ENV工具,添加fal组件已经使能FMC功能
在这里插入图片描述
在这里插入图片描述

保存退出后,输入scons 会报错fal_cfg.h的文件。所以新建fal_cfg.h文件内容如下。

/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-05-17     armink       the first version
 */

#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_


#include <board.h>

#define RT_APP_PART_ADDR 0x8014000

/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev gd32_onchip_flash;


/* flash device table */
#define FAL_FLASH_DEV_TABLE                                          \
{                                                                    \
    &gd32_onchip_flash,                                           \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE                                                               \
{                                                                                    \
    {FAL_PART_MAGIC_WORD,        "bl",     "onchip_flash",         0,   80*1024, 0}, \
    {FAL_PART_MAGIC_WORD,       "app",     "onchip_flash",   80*1024,  160*1024, 0}, \
    {FAL_PART_MAGIC_WORD,  "download", "onchip_flash", 160*1024, 240*1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */

#endif /* _FAL_CFG_H_ */

这里说明几点注意事项:

  • RT_APP_PART_ADDR 一定要定义已经修改成自己的app起始地址,如果不定义就按默认地址0x08020000
  • extern const struct fal_flash_dev gd32_onchip_flash引入的是drv_flash的定义在这里插入图片描述
    所以名称要统一。
  • FAL_PART_TABLE 定义分区表中它的flash名称要与定义的名称对应上onchip_flash

Qboot移植

fal组件添加完成之后添加qboot组件,只保留压缩算法以及ota功能。
在这里插入图片描述
在这里插入图片描述
保存退出 输入pkgs --update 下载并更新组件,然后scons -- target=mdk5更新到keil中。

修补报错内容

qboot.c中的void qbt_jump_to_app(void)函数注释掉,在qboot_gd32.c中添加宏定义#define SOC_FAMILY_GD32修改void hal_DeInit(void)以及void qbt_jump_to_app(void)内容如下。

void hal_DeInit(void)
{
    //AHB1 peripherals 
    rcu_periph_reset_enable(RCU_GPIOARST);    
    rcu_periph_reset_enable(RCU_GPIOBRST);   
    rcu_periph_reset_enable(RCU_GPIOCRST);   
    rcu_periph_reset_enable(RCU_GPIODRST);  
    rcu_periph_reset_enable(RCU_GPIOERST);   
    rcu_periph_reset_enable(RCU_GPIOFRST);   
    rcu_periph_reset_enable(RCU_GPIOGRST);  
//    rcu_periph_reset_enable(RCU_GPIOHRST);
//    rcu_periph_reset_enable(RCU_GPIOIRST);
//    rcu_periph_reset_enable(RCU_CRCRST);
//    rcu_periph_reset_enable(RCU_DMA0RST);
//    rcu_periph_reset_enable(RCU_DMA1RST);
//    rcu_periph_reset_enable(RCU_IPARST);
//    rcu_periph_reset_enable(RCU_ENETRST);
//    rcu_periph_reset_enable(RCU_USBHSRST);
    //AHB2 peripheral
//    rcu_periph_reset_enable(RCU_DCIRST);
//    rcu_periph_reset_enable(RCU_TRNGRST);
//    rcu_periph_reset_enable(RCU_USBFSRST);
//    //AHB3 peripheral
//    rcu_periph_reset_enable(RCU_EXMCRST);
//    // APB1 peripheral
    rcu_periph_reset_enable(RCU_TIMER1RST);  
    rcu_periph_reset_enable(RCU_TIMER2RST);  
    rcu_periph_reset_enable(RCU_TIMER3RST);  
    rcu_periph_reset_enable(RCU_TIMER4RST);  
    rcu_periph_reset_enable(RCU_TIMER5RST);  
    rcu_periph_reset_enable(RCU_TIMER6RST);  
//    rcu_periph_reset_enable(RCU_TIMER11RST);
//    rcu_periph_reset_enable(RCU_TIMER12RST);
//    rcu_periph_reset_enable(RCU_TIMER13RST);
    rcu_periph_reset_enable(RCU_WWDGTRST); 
    rcu_periph_reset_enable(RCU_SPI1RST);     
    rcu_periph_reset_enable(RCU_SPI2RST);     
    rcu_periph_reset_enable(RCU_USART1RST); 
    rcu_periph_reset_enable(RCU_USART2RST); 
    rcu_periph_reset_enable(RCU_UART3RST);  
    rcu_periph_reset_enable(RCU_UART4RST);  
    rcu_periph_reset_enable(RCU_I2C0RST);    
    rcu_periph_reset_enable(RCU_I2C1RST);    
//    rcu_periph_reset_enable(RCU_I2C2RST);
    rcu_periph_reset_enable(RCU_CAN0RST);   
//    rcu_periph_reset_enable(RCU_CAN1RST);
    rcu_periph_reset_enable(RCU_PMURST);    
    rcu_periph_reset_enable(RCU_DACRST);    
//    rcu_periph_reset_enable(RCU_UART6RST);
//    rcu_periph_reset_enable(RCU_UART7RST);
    //APB2 peripheral
    rcu_periph_reset_enable(RCU_TIMER0RST);  
    rcu_periph_reset_enable(RCU_TIMER7RST);  
    rcu_periph_reset_enable(RCU_USART0RST); 
//    rcu_periph_reset_enable(RCU_USART5RST);
//    rcu_periph_reset_enable(RCU_ADCRST);
//    rcu_periph_reset_enable(RCU_SDIORST);
    rcu_periph_reset_enable(RCU_SPI0RST);     
//    rcu_periph_reset_enable(RCU_SPI3RST);
//    rcu_periph_reset_enable(RCU_SYSCFGRST);
//    rcu_periph_reset_enable(RCU_TIMER8RST);
//    rcu_periph_reset_enable(RCU_TIMER9RST);
//    rcu_periph_reset_enable(RCU_TIMER10RST);
//    rcu_periph_reset_enable(RCU_SPI4RST);
//    rcu_periph_reset_enable(RCU_SPI5RST);
//    rcu_periph_reset_enable(RCU_TLIRST);
//    //APB1 additional
//    rcu_periph_reset_enable(RCU_CTCRST);
//    rcu_periph_reset_enable(RCU_IREFRST);

//AHB1 peripherals 
    rcu_periph_reset_disable(RCU_GPIOARST);    
    rcu_periph_reset_disable(RCU_GPIOBRST);   
    rcu_periph_reset_disable(RCU_GPIOCRST);   
    rcu_periph_reset_disable(RCU_GPIODRST);  
    rcu_periph_reset_disable(RCU_GPIOERST);   
    rcu_periph_reset_disable(RCU_GPIOFRST);   
    rcu_periph_reset_disable(RCU_GPIOGRST);  
//    rcu_periph_reset_disable(RCU_GPIOHRST);
//    rcu_periph_reset_disable(RCU_GPIOIRST);
//    rcu_periph_reset_disable(RCU_CRCRST);
//    rcu_periph_reset_disable(RCU_DMA0RST);
//    rcu_periph_reset_disable(RCU_DMA1RST);
//    rcu_periph_reset_disable(RCU_IPARST);
//    rcu_periph_reset_disable(RCU_ENETRST);
//    rcu_periph_reset_disable(RCU_USBHSRST);
    //AHB2 peripheral
//    rcu_periph_reset_disable(RCU_DCIRST);
//    rcu_periph_reset_disable(RCU_TRNGRST);
//    rcu_periph_reset_disable(RCU_USBFSRST);
//    //AHB3 peripheral
//    rcu_periph_reset_disable(RCU_EXMCRST);
    // APB1 peripheral
    rcu_periph_reset_disable(RCU_TIMER1RST);  
    rcu_periph_reset_disable(RCU_TIMER2RST);  
    rcu_periph_reset_disable(RCU_TIMER3RST);  
    rcu_periph_reset_disable(RCU_TIMER4RST);  
    rcu_periph_reset_disable(RCU_TIMER5RST);  
    rcu_periph_reset_disable(RCU_TIMER6RST);  
//    rcu_periph_reset_disable(RCU_TIMER11RST);
//    rcu_periph_reset_disable(RCU_TIMER12RST);
//    rcu_periph_reset_disable(RCU_TIMER13RST);
    rcu_periph_reset_disable(RCU_WWDGTRST); 
    rcu_periph_reset_disable(RCU_SPI1RST);     
    rcu_periph_reset_disable(RCU_SPI2RST);     
    rcu_periph_reset_disable(RCU_USART1RST); 
    rcu_periph_reset_disable(RCU_USART2RST); 
    rcu_periph_reset_disable(RCU_UART3RST);  
    rcu_periph_reset_disable(RCU_UART4RST);  
    rcu_periph_reset_disable(RCU_I2C0RST);    
    rcu_periph_reset_disable(RCU_I2C1RST);    
//    rcu_periph_reset_disable(RCU_I2C2RST);
    rcu_periph_reset_disable(RCU_CAN0RST);   
//    rcu_periph_reset_disable(RCU_CAN1RST);
    rcu_periph_reset_disable(RCU_PMURST);    
    rcu_periph_reset_disable(RCU_DACRST);    
//    rcu_periph_reset_disable(RCU_UART6RST);
//    rcu_periph_reset_disable(RCU_UART7RST);
    //APB2 peripheral
    rcu_periph_reset_disable(RCU_TIMER0RST);  
    rcu_periph_reset_disable(RCU_TIMER7RST);  
    rcu_periph_reset_disable(RCU_USART0RST); 
//    rcu_periph_reset_disable(RCU_USART5RST);
//    rcu_periph_reset_disable(RCU_ADCRST);
//    rcu_periph_reset_disable(RCU_SDIORST);
    rcu_periph_reset_disable(RCU_SPI0RST);     
//    rcu_periph_reset_disable(RCU_SPI3RST);
//    rcu_periph_reset_disable(RCU_SYSCFGRST);
//    rcu_periph_reset_disable(RCU_TIMER8RST);
//    rcu_periph_reset_disable(RCU_TIMER9RST);
//    rcu_periph_reset_disable(RCU_TIMER10RST);
//    rcu_periph_reset_disable(RCU_SPI4RST);
//    rcu_periph_reset_disable(RCU_SPI5RST);
//    rcu_periph_reset_disable(RCU_TLIRST);
//    //APB1 additional
//    rcu_periph_reset_disable(RCU_CTCRST);
//    rcu_periph_reset_disable(RCU_IREFRST);
}

void qbt_jump_to_app(void)
{
   typedef void (*app_func_t)(void);

    unsigned long app_addr = QBOOT_APP_ADDR;
    unsigned long stk_addr = *((__IO uint32_t *)app_addr);
    app_func_t app_func = (app_func_t)(*((__IO uint32_t *)(app_addr + 4)));

    if ((((unsigned long)app_func & 0xff000000) != 0x08000000) || ((stk_addr & 0x2ff00000) != 0x20000000))
    {
        rt_kprintf("No legitimate application.");
        return;
    }

    rt_kprintf("Jump to application running ... \n");
    rt_thread_mdelay(200);

		__set_PRIMASK(1);
		
		SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;
		
		for(int i = 0; i< 8; i++)
    {
			NVIC->ICER[i] = 0xFFFFFFFF;
			NVIC->ICPR[i] = 0xFFFFFFFF;

			__DSB();
			__ISB();
    }
		
    __disable_irq();
    hal_DeInit();

		SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;

    //Resets the RCC clock configuration to the default reset state.
    rcu_deinit();   



    __set_CONTROL(0);
    __set_MSP(stk_addr);

    app_func();//Jump to application running

    rt_kprintf("Qboot jump to application fail.");
}

修改main.c

int main(void)
{
	fal_init();
    return RT_EOK;
}

keil设置

下载起始地址为flash首地址,下载方式为全片擦除。
在这里插入图片描述

在这里插入图片描述

ok到这里bootloader就结束了。
在这里插入图片描述

APP制作

复制bootloader文件,进入env,组件只保留fal以及ota,其他删除。
这里就不截图了,删除路径就是添加路径。

App main.c

/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-12-18     BruceOu      first implementation
 */

#include <stdio.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include "fal.h"

int main(void)
{
	fal_init();

	
	while(1)
	{
	
		//rt_kprintf("app v2.0\n");
		rt_thread_mdelay(1000);
		
	}
    return RT_EOK;
}
void run(void)
{
	nvic_vector_table_set(0x08000000, 0x00014000);
}

INIT_BOARD_EXPORT(run);

中断向量表一定要在main函数执行的前面,所以要使用INIT_BOARD_EXPORT

keil设置

在魔法棒中修改下载地址以及,下载方式按扇区擦除,生成bin文件位置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

烧入程序后已经可以正常跳转了
在这里插入图片描述

IAP OTA验证

修改main函数

int main(void)
{
	fal_init();

	
	while(1)
	{
	
		rt_kprintf("app v2.0\n");
		rt_thread_mdelay(1000);
		
	}
    return RT_EOK;
}

编译后把bin文件通过rtthread ota固件打包器生成.rbl格式文件
在这里插入图片描述
在xshell中输入ymodem_ota,然后右键传输使用ymodem发送生成的.rbl文件
在这里插入图片描述
在这里插入图片描述
已经ota成功了。

  • 14
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
您好!对于使用STM32F103RCT6和RFID-RC522的示例程序,您可以参考以下步骤: 1. 首先,确保您已经配置好STM32F103RCT6的开发环境,包括安装好Keil MDK软件和相应的STM32Cube库。 2. 下载并安装RFID-RC522的库文件。您可以在GitHub或其他资源网站上找到适用于STM32的RFID-RC522库。确保选择与您的开发环境兼容的版本。 3. 创建一个新的Keil项目,并配置正确的芯片型号(STM32F103RCT6)和时钟设置。 4. 将RFID-RC522库文件添加到您的项目中。将库文件中提供的源代码和头文件复制到您的项目目录中,并在Keil中添加这些文件到您的项目中。 5. 根据您的硬件连接,配置GPIO引脚和SPI接口。确保正确连接RFID-RC522模块与STM32开发板,并通过SPI接口进行通信。 6. 在主程序中,初始化SPI接口并使用RFID-RC522库提供的函数来初始化RFID模块。这些函数通常包括初始化SPI、设置IO口方向和模式、复位模块等。 7. 通过调用RFID-RC522库中的函数,实现读取和写入RFID卡的功能。例如,您可以使用函数来检测卡片是否存在、读取卡片UID、读取或写入卡片数据等。 8. 编译和烧录程序到STM32F103RCT6开发板上。 请注意,以上步骤仅提供了一个大致的指导。具体的实现过程可能因您所选择的库和硬件连接方式而有所不同。确保阅读并遵循RFID-RC522库的文档和示例程序以获取更详细的指导。 祝您成功使用STM32F103RCT6和RFID-RC522!如果您有更多问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值