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);
}