这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » 【IAR】 基于GD32F427的flashloader下载算法实现

共5条 1/1 1 跳转至

【IAR】 基于GD32F427的flashloader下载算法实现

工程师
2025-02-18 22:42:33     打赏

简介

在上一篇帖子([IAR] Flash Loader 下载过程解析)中已经介绍了IAR flash 程序下载的过程,其中flah 上内容的跟新是通过C-SPY,将flash 下载算法加载到RAM 中调用flashloader 的下载算法完成,flash 的编程。

image.png

          image.png

上述流程为flashloader 下载算法的主要工作流程,flashloader  下载算法中主要依赖如下flash 写入和擦除的函数。

image.png

以下是flashloader 中其他接口功能说明

image.png

IAR 针对 flashloader 的制作,也提供了标准的实现模板,我们使用标准模板的基础上实现对应的flash 下载算法就可以实现一个基本功能的flash 下载算法了。IAR 的\arm\src\flashloader安装路径下包含部分flash loader 的示例工程,我们可以基于此模板进行修改,默认的flash loader 程序是不能进行串口打印输出的,我们再次gd32 的flash loader 工程上进行修改,添加串口打印功能方便我们理解flashloader 的工作过程,从以上的函数接口功能描述可知,FlashInit函数是第一个被调用的函数,我们可以在这个函数里添加串口的初始话配置处理。

FlashInit 接口功能描述如下

image.png

image.png

#if USE_ARGC_ARGV
uint32_t FlashInit(void *base_of_flash, uint32_t image_size,
                   uint32_t link_address, uint32_t flags,
                   int argc, char const *argv[])
#else
uint32_t FlashInit(void *base_of_flash, uint32_t image_size,
                   uint32_t link_address, uint32_t flags)
#endif
{
    uint32_t temp = 0;
    parallelism = 1;
    
    /* enable GPIO clock */
    RCU_AHB1EN |= 0x01u << 1;
    /* enable USART clock */
    RCU_APB2EN |= 0x01u <<4;

    GPIO_CTL(GPIOB) &= ~(0x03u << (2*6));
    GPIO_CTL(GPIOB) |= (2 << (2*6));

    GPIO_PUD(GPIOB) &= ~(0x03u << (2*6));
    GPIO_PUD(GPIOB) |= (1u << (2*6));
    GPIO_OMODE(GPIOB) &= ~(0x01u << 6);

    GPIO_OSPD(GPIOB) &= ~(0x03u << (2*6));
    GPIO_OSPD(GPIOB) |= (0x01u << (2*6));

    GPIO_AFSEL0(GPIOB) &= ~(0xf << (4*6));
    GPIO_AFSEL0(GPIOB) |= (0x7 << (4*6));

    /* config uart0 */
    uint32_t uclk = 0U, intdiv = 0U, fradiv = 0U, udiv = 0U;
    uclk = rcu_clock_freq_get(CK_APB2);

    if(USART_CTL0(USART0) & USART_CTL0_OVSMOD) {
        /* when oversampling by 8, configure the value of USART_BAUD */
        udiv = ((2U * uclk) + 115200 / 2U) / 115200;
        intdiv = udiv & 0xfff0U;
        fradiv = (udiv >> 1U) & 0x7U;
        USART_BAUD(USART0) = ((USART_BAUD_FRADIV | USART_BAUD_INTDIV) & (intdiv | fradiv));
    } else {
        /* when oversampling by 16, configure the value of USART_BAUD */
        udiv = (uclk + 115200 / 2U) / 115200;
        intdiv = udiv & 0xfff0U;
        fradiv = udiv & 0xfU;
        USART_BAUD(USART0) = ((USART_BAUD_FRADIV | USART_BAUD_INTDIV) & (intdiv | fradiv));
    }

    USART_CTL0(USART0) &= ~(0x01u << 10);
    USART_CTL0(USART0) &= ~(0x01u << 12);

    USART_CTL1(USART0) &= ~(0x03u << 12);

    USART_CTL0(USART0) |= (0x01u << 3);
    USART_CTL0(USART0) |= (0x01u << 13);

    FMC_WS = 0x00000000;
    temp = FMC_CTL;
    temp &= ~(0x3u << 8);
    temp |= (parallelism << 8);
    FMC_CTL = temp;

    return 0;
}

参考GD32F4 的flash 编程接口实现flashwrite/flasherase 接口。对应实现如下

FlashWrite 接口功能描述如下

image.png

uint32_t FlashWrite(void *block_start,
                    uint32_t offset_into_block,
                    uint32_t count,
                    char const *buffer)
{
    uint8_t * dst = (uint8_t *)((unsigned char *)block_start + offset_into_block);
    uint8_t * src = (uint8_t *)buffer;

    mini_printf("flash write dst %p %d %d.\r\n",dst,offset_into_block,count);

    FMC_CTL |= 0x01u;
    FMC_STAT = 0x1d2;

    for ( ; count; count -= 8)
    {
      
        while (FMC_STAT & (0x01u<<16));
        *((uint64_t *)dst) = *((uint64_t *)src);
        src += 8;
        dst += 8;
    }
  }

    while (FMC_STAT & (0x01u<<16));
    FMC_CTL &= ~0x01;

    if(FMC_STAT & 0x1d2)
        return 1;

    return 0;
}

FlashErase  接口功能描述如下

image.png

uint32_t FlashErase(void *block_start,
                    uint32_t block_size)
{
    uint32_t offset = (uint32_t)block_start;
    uint32_t sector_num = 0;

    mini_printf("flash erase %x.\r\n",offset);

    if(offset >= 0x08000000 && offset <= 0x08003fff)
    {
        //sector_num = 0;
        sector_num = 0x00u << 3;
     }
    else if(offset >= 0x08004000 && offset <= 0x08007fff)
    {
        //sector_num = 1;
        sector_num = 0x01u << 3;
    }
    else if(offset >= 0x08008000 && offset <= 0x0800bfff)
    {
        //sector_num = 2;
        sector_num = 0x02u << 3;
    }
    else if(offset >= 0x0800c000 && offset <= 0x0800ffff)
    {
        //sector_num = 3;
        sector_num = 0x03u << 3;
    }
    else if(offset >= 0x08010000 && offset <= 0x0801ffff)
    {
        //sector_num = 4;
        sector_num = 0x04u << 3;
    }
    else if(offset >= 0x08020000 && offset <= 0x0803ffff)
    {
        //sector_num = 5;
        sector_num = 0x05u << 3;
    }
    else if(offset >= 0x08040000 && offset <= 0x0805ffff)
    {
        //sector_num = 6;
        sector_num = 0x06u << 3;
    }
    else if(offset >= 0x08060000 && offset <= 0x0807ffff)
    {
        //sector_num = 7;
        sector_num = 0x07u << 3;
    }
    else if(offset >= 0x08080000 && offset <= 0x0809ffff)
    {
        //sector_num = 8;
        sector_num = 0x08u << 3;
    }
    else if(offset >= 0x080a0000 && offset <= 0x080bffff)
    {
        //sector_num = 9;
        sector_num = 0x09u << 3;
    }
    else if(offset >= 0x080c0000 && offset <= 0x080dffff)
    {
        //sector_num = 10;
        sector_num = 10u << 3;
    }
    else if(offset >= 0x080e0000 && offset <= 0x080fffff)
    {
        //sector_num = 11;
        sector_num = 11u << 3;
    }
    else if(offset >= 0x08100000 && offset <= 0x08103fff)
    {
        //sector_num = 12;
        sector_num = 0x10u << 3;
    }
    else if(offset >= 0x08104000 && offset <= 0x08107fff)
    {
        //sector_num = 13;
        sector_num = 0x11u << 3;
    }
    else if(offset >= 0x08108000 && offset <= 0x0810Bfff)
    {
        //sector_num = 14;
        sector_num = 0x12u << 3;
    }
    else if(offset >= 0x0810C000 && offset <= 0x0810Ffff)
    {
        //sector_num = 15;
        sector_num = 0x13u << 3;
    }
    else if(offset >= 0x08110000 && offset <= 0x0811Ffff)
    {
        //sector_num = 16;
        sector_num = 0x14u << 3;
    }
    else if(offset >= 0x08120000 && offset <= 0x0813Ffff)
    {
        //sector_num = 17;
        sector_num = 0x15u << 3;
    }
    else if(offset >= 0x08140000 && offset <= 0x0815Ffff)
    {
        //sector_num = 18;
        sector_num = 0x16u << 3;
    }
    else if(offset >= 0x08160000 && offset <= 0x0817Ffff)
    {
        //sector_num = 19;
        sector_num = 0x17u << 3;
    }
    else if(offset >= 0x08180000 && offset <= 0x0819Ffff)
    {
        //sector_num = 20;
        sector_num = 0x18u << 3;
    }
    else if(offset >= 0x081A0000 && offset <= 0x081BFfff)
    {
        //sector_num = 21;
        sector_num = 0x19u << 3;
    }
    else if(offset >= 0x081C0000 && offset <= 0x081DFfff)
    {
        //sector_num = 22;
        sector_num = 0x1au << 3;
    }
    else if(offset >= 0x081E0000 && offset <= 0x081FFfff)
    {
        //sector_num = 23;
        sector_num = 0x1bu << 3;
    }
    else if(offset >= 0x08200000 && offset <= 0x0823Ffff)
    {
        //sector_num = 24;
        sector_num = 0xcu << 3;
    }
    else if(offset >= 0x08240000 && offset <= 0x0827Ffff)
    {
        //sector_num = 25;
        sector_num = 0xdu << 3;
    }
    else if(offset >= 0x08280000 && offset <= 0x082BFfff)
    {
        //sector_num = 26;
        sector_num = 0xeu << 3;
    }
    else if(offset >= 0x082C0000 && offset <= 0x082FFfff)
    {
        //sector_num = 27;
        sector_num = 0xfu << 3;
    }
    else
    {
        return 1;
    }

    while (FMC_STAT & (0x01u<<16));
    FMC_CTL |= ((sector_num) | (0x01<<1));
    FMC_CTL |= (0x01u<<16);
    while (FMC_STAT & (0x01u<<16));
    FMC_CTL &= ~(0x1f<<3 | 0x01<<1);

    if(FMC_STAT & 0x1d2)
        return 1;

    return 0;
}

  因为在FlashInit 函数中已经完成了flash 的初始化处理,在flash 的write 和 erase 函数里添加了打印处理,我们使用本地编译的flashloader 程序,下载过程中对应的log 也按照预期的打印输出了。

image.png

只要添加以上三个函数即可完成基本的flashloader 功能,至此已经完成flashloader 下载算法的编写并可以在IAR环境下使用。


院士
2025-02-18 23:24:35     打赏
2楼

在国内还有人在坚持使用IAR呀!

真厉害


工程师
2025-02-19 08:50:10     打赏
3楼

刚毕业那会用IAR搞msp430,因为TI的ccs下不到,TI的技术支持也没搞定这。那时的IAR有没license 只能编译大小16K的固件的限制,现在的版本还有嘛?


工程师
2025-02-19 09:33:09     打赏
4楼

没有过IAR啊,和KEIL区别大吗?


院士
2025-02-20 19:00:05     打赏
5楼

IAR有两个版本可以试用,一个是16KB的kickoff版本;还有一个是30天试用版本。

不过,这都快十年了吧


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]