The IAP process and example of Huada HC32F series MCU

This article takes HC32F072 as an example.
The IAP method and process of BGI's MCU are basically the same as STM32. You can refer to this article:
https://blog.csdn.net/zhangfls/article/details/111685866

Prepare two projects, 1 BOOT and 1 APP

1. FLASH flashing, boot flashes the new program saved in the back half of the on-chip FLASH to the front half, APP will obtain the upgrade package through the communication interface, and flash the upgrade package to the second half of the 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;
}

2. The above process is the general flashing process, which is universal. The key point is to jump to the address of the new APP after flashing:

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程序
	}
}

In the main program, you need to change the startup .S file (startup_hc32f072.s), configure the interrupt vector table offset

1, define a new terminal vector offset address new_vect_table at the beginning, point to the APP program address, and point to the 8K address (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. Load the address to 0xE000ED08, which is the address saved in the interrupt vector table

              ; 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. In this way, boot can jump to APP normally (pay attention to the start address configuration of BOOT and APP project)
 

Special attention:
(1) The FALSH erasing and writing functions of BGI MCU chip should be defined before 32K. You can configure the declaration of the FLASH erasing and writing functions to define them before 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) The interrupt must be turned off during the FLASH erasing process, otherwise it may fail

/**
 *****************************************************************************
 ** \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);
}

 

Guess you like

Origin blog.csdn.net/zhangfls/article/details/115177827