IAPプロセスとHuadaHC32FシリーズMCUの例

この記事では、HC32F072を例として取り上げます。
BGIのMCUのIAPメソッドとプロセスは基本的にSTM32と同じです。次の記事を参照できます:
https

//blog.csdn.net/zhangfls/article/details/111685866 2つのプロジェクト(1つのBOOTと1つのAPP

1)を準備します。 FLASHが点滅し、ブートがオンチップ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;
}

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

メインプログラムでは、スタートアップ.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.このようにして、ブートは通常どおりAPPにジャンプできます(BOOTおよびAPPプロジェクトの開始アドレス構成に注意してください)。
 

特記
事項(1)BGI 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)フラッシュ消去プロセス中は割り込みをオフにする必要があります。オフにしないと失敗する可能性があります

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

 

おすすめ

転載: blog.csdn.net/zhangfls/article/details/115177827