El proceso IAP y el ejemplo de MCU de la serie Huada HC32F

Este artículo toma HC32F072 como ejemplo.
El método y el proceso IAP del MCU de BGI son básicamente los mismos que los de STM32. Puede consultar este artículo:
https://blog.csdn.net/zhangfls/article/details/111685866

Prepare dos proyectos, 1 BOOT y 1 APP

1. FLASH parpadeando, el arranque parpadea el nuevo programa guardado en la mitad posterior del FLASH en el chip a la mitad frontal, la APLICACIÓN obtendrá el paquete de actualización a través de la interfaz de comunicación y actualizará el paquete de actualización a la segunda mitad del 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. El proceso anterior es el proceso de flasheo general, que es universal. El punto clave es saltar a la dirección de la nueva APLICACIÓN después de flashear:

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

En el programa principal, debe cambiar el archivo .S de inicio (startup_hc32f072.s), configurar el desplazamiento de la tabla de vectores de interrupción

1, definir una nueva dirección de desplazamiento del vector de terminal new_vect_table al principio, apuntar a la dirección del programa de la aplicación y apuntar a la dirección 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. Cargue la dirección en 0xE000ED08, que es la dirección guardada en la tabla de vectores de interrupción.

              ; 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. De esta manera, el arranque puede saltar a la APLICACIÓN normalmente (preste atención a la configuración de la dirección de inicio del proyecto de ARRANQUE y APLICACIÓN)
 

Atención especial:
(1) Las funciones de borrado y escritura FALSH del chip BGI MCU deben definirse antes de 32 K. Puede configurar la declaración de las funciones de borrado y escritura de FLASH para definirlas antes de 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) La interrupción debe apagarse durante el proceso de borrado de FLASH, de lo contrario puede fallar.

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

 

Supongo que te gusta

Origin blog.csdn.net/zhangfls/article/details/115177827
Recomendado
Clasificación