打印
[方案相关]

华大HC32F系列MCU的IAP流程及示例

[复制链接]
4463|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
观海|  楼主 | 2021-8-1 16:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
准备两个工程,1个BOOT,1个APP

1、FLASH刷写,boot将片内FLASH后面一半保存的新程序刷到前面一半,APP则是将通过通讯接口获取升级包,将升级包刷写到后一半的FLASH

//IAP写入
uint8_t IAP_Write(void)
{
        uint16_t j;
        uint32_t left_len,addr=0;
        static uint16_t check_sum = 0;
        static uint16_t flash_read_checknum;
       
        uint8_t retry_time = 0;

        left_len = System_Para.Filesize-4;
        while(left_len)
        {
                if(left_len > 256)
                {
                        Flash_Read_Data(addr,256,Prog_data);
                        addr += 256;
                        left_len = System_Para.Filesize-4-addr;
                        for(j=0;j<256;j++)
                        {
                                check_sum += Prog_data[j];
                        }
                }
                else
                {
                        Flash_Read_Data(addr,left_len,Prog_data);
                        for(j=0;j<left_len;j++)
                        {
                                check_sum += Prog_data[j];
                        }
                        left_len = 0;
                }
        }
       
        flash_read_checknum = Flash_Read_Byte(System_Para.Filesize-2);
        flash_read_checknum = (flash_read_checknum<<8) + Flash_Read_Byte(System_Para.Filesize-1);
       
        if(flash_read_checknum == check_sum)
        {
                //校验和正确
                Flash_Read_Data(0,256,Prog_data);
                if(((*(__IO uint32_t*)Prog_data) & 0x2FFE0000 ) != 0x20000000)
                {
                        //程序错误,直接返回主程序
                        return 10;
                }
        }
        else
        {
                //校验和错误,直接返回主程序
                return 10;
        }
       
        total_data = System_Para.Filesize;
       
        //擦除程序区,失败就返回0
        if(FlashErase((uint32_t)PGM_START_ADDR))   //清除程序空间
        {
                //FLASH烧写擦除过程中失败,不能直接返回主程序,因为主程序已经没有代码了
                return 0;
        }

        addr = 0;
        left_len = total_data;
       
        //开始写入程序
        while(left_len)
        {
                if(left_len > 256)
                {
                        Flash_Read_Data(addr,256,Prog_data);
                        for(j=0;j<256;j++)
                        {
                                Flash_WriteByte(addr+PGM_START_ADDR+j,Prog_data[j]);
                                while(*((volatile uint8_t*)addr+PGM_START_ADDR+j) != Prog_data[j])
                                {
                                        retry_time ++;
                                        delay1ms(10);
                                        if(retry_time>10)
                                                return 0;
                                }
                                delay100us(2);
                        }
                        addr += 256;
                        left_len = total_data-addr;
                }
                else        //剩余不足256字节
                {
                        Flash_Read_Data(addr,left_len,Prog_data);
                        for(j=0;j<left_len;j++)
                        {
                                Flash_WriteByte(addr+PGM_START_ADDR+j,Prog_data[j]);
                                while(*((volatile uint8_t*)addr+PGM_START_ADDR+j) != Prog_data[j])
                                {
                                        retry_time ++;
                                        delay1ms(10);
                                        if(retry_time>10)
                                                return 0;
                                }
                                delay100us(2);
                        }
                        left_len = 0;                       
                }
        }
        return 10;
}


使用特权

评论回复
沙发
观海|  楼主 | 2021-8-1 16:01 | 只看该作者
2、上面的流程就是一般情况下的刷写流程,都是通用的,重点是刷写完后跳转到新的APP的地址:

typedef  void (*iapfun)(void);                                //定义一个函数类型的参数.
uint32_t JumpAddress;
iapfun jump2app;

void MSR_MSP(unsigned  int addr);        //设置堆栈地址

//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(unsigned  int addr)
{
    MSR MSP, r0                         //set Main Stack value
    BX r14
}

//程序跳转
void Check_And_Jump(void)
{
   if(((*(__IO uint32_t*)PGM_START_ADDR)&0x2FFE0000)==0x20000000)        //检查栈顶地址是否合法
        {
                jump2app=(iapfun)*(__IO uint32_t*)(PGM_START_ADDR+4);//APP程序复位地址
                MSR_MSP(*(__IO uint32_t*)PGM_START_ADDR);        //初始化APP堆栈指针
                jump2app();                                                                        //跳转到APP程序
        }
}


使用特权

评论回复
板凳
观海|  楼主 | 2021-8-1 16:01 | 只看该作者
主程序处,需要更改启动的.S文件(startup_hc32f072.s),配置中断向量表偏移

1、开头定义一个新的终端向量偏移地址new_vect_table,指向APP程序地址,如下文指向了8K地址(0x00002000 )

Stack_Size      EQU     0x00000200
       
new_vect_table  EQU     0x00002000         ;中断向量偏移长度8K

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp
2、将该地址装载到0xE000ED08即中断向量表保存的地址下

              ; reset Vector table address.
                LDR     R0, =0xE000ED08
                                LDR     R2, =new_vect_table
                STR     R2, [R0]                        ;向量表重定义
                LDR     R0, =SystemInit
                BLX     R0
                LDR     R0, =__main
                BX      R0
                ENDP
3、这样boot就可以正常跳转到APP了(注意BOOT和APP工程的起始地址配置)


使用特权

评论回复
地板
观海|  楼主 | 2021-8-1 16:02 | 只看该作者
特别注意:
(1)华大的MCU片内FALSH擦除和写入的函数要定义在32K之前,可以这样配置FLASH擦除和写入的函数的声明,将其定义到32K之前

en_result_t Flash_SectorErase(uint32_t u32SectorAddr) __attribute__((section(".ARM.__at_0x2200")));

en_result_t Flash_WriteByte(uint32_t u32Addr, uint8_t u8Data) __attribute__((section(".ARM.__at_0x2400")));
(2)FLASH擦写过程中必须要关中断,不然有可能失败

/**
*****************************************************************************
** \brief FLASH 字节写
**
** 用于向FLASH写入1字节数据.
**
** \param [in]  u32Addr          Flash地址
** \param [in]  u8Data           1字节数据
**
** \retval Ok                    写入成功.
** \retval ErrorInvalidParameter FLASH地址无效
** \retval ErrorTimeout          操作超时
*****************************************************************************/
en_result_t Flash_WriteByte(uint32_t u32Addr, uint8_t u8Data)
{
    en_result_t             enResult = Ok;   
    volatile uint32_t       u32TimeOut = FLASH_TIMEOUT_PGM;

    if (FLASH_END_ADDR < u32Addr)
    {
        enResult = ErrorInvalidParameter;
        return (enResult);
    }
               
                __disable_irq();

    //busy?
    u32TimeOut = FLASH_TIMEOUT_PGM;
    while (TRUE == M0P_FLASH->CR_f.BUSY)
    {
                        if(0 == u32TimeOut--)
                        {
                                __enable_irq();
                                return ErrorTimeout;
                        }
    }

    //set OP
    u32TimeOut = FLASH_TIMEOUT_PGM;
    while(Program != M0P_FLASH->CR_f.OP)
    {
        if(u32TimeOut--)
        {
            FLASH_BYPASS();
            M0P_FLASH->CR_f.OP = Program;
        }
        else
        {
                                        __enable_irq();
            return ErrorTimeout;
        }
    }

    //Flash 解锁
    Flash_UnlockAll();

    //write data
    *((volatile uint8_t*)u32Addr) = u8Data;

    //busy?
    u32TimeOut = FLASH_TIMEOUT_PGM;
    while (TRUE == M0P_FLASH->CR_f.BUSY)
    {
        if(0 == u32TimeOut--)
        {
                                        __enable_irq();
            return ErrorTimeout;
        }
    }

    //Flash 加锁
    Flash_LockAll();
               
                __enable_irq();

    return (enResult);
}
/**
*****************************************************************************
** \brief FLASH 扇区擦除
**
** FLASH 扇区擦除.
**
** \param [in]  u32SectorAddr    所擦除扇区内的地址
**
** \retval Ok                    擦除成功.
** \retval ErrorInvalidParameter FLASH地址无效
** \retval ErrorTimeout          操作超时
*****************************************************************************/
en_result_t Flash_SectorErase(uint32_t u32SectorAddr)
{
    en_result_t             enResult = Ok;   
    volatile uint32_t       u32TimeOut = FLASH_TIMEOUT_ERASE;

    if (FLASH_END_ADDR < u32SectorAddr)
    {
        enResult = ErrorInvalidParameter;
        return (enResult);
    }
               
                __disable_irq();

    //busy?
    u32TimeOut = FLASH_TIMEOUT_ERASE;
    while (TRUE == M0P_FLASH->CR_f.BUSY)
    {
        if(0 == u32TimeOut--)
        {
                                        __enable_irq();
            return ErrorTimeout;
        }
    }

    //Flash 解锁
    Flash_UnlockAll();

    //set OP
    u32TimeOut = FLASH_TIMEOUT_ERASE;
    while(SectorErase != M0P_FLASH->CR_f.OP)
    {
        if(u32TimeOut--)
        {
            FLASH_BYPASS();
            M0P_FLASH->CR_f.OP = SectorErase;
        }
        else
        {
                                        __enable_irq();
            return ErrorTimeout;
        }
    }

    //write data
    *((volatile uint8_t*)u32SectorAddr) = 0;

    //busy?
    u32TimeOut = FLASH_TIMEOUT_ERASE;
    while (TRUE == M0P_FLASH->CR_f.BUSY)
    {
        if(0 == u32TimeOut--)
        {
                                        __enable_irq();
            return ErrorTimeout;
        }
    }
               
    //Flash 加锁
    Flash_LockAll();
               
                __enable_irq();

    return (enResult);
}


使用特权

评论回复
5
caigang13| | 2021-8-2 21:16 | 只看该作者
谢谢,有源代码文件吗?

使用特权

评论回复
6
两只袜子| | 2021-8-11 20:49 | 只看该作者
参考参考

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

99

主题

3882

帖子

1

粉丝