S32K144 CANbootloaer实现

1.基本概念

s32k144 canbootloader工程包含三部分.

  • canbootloader程序:与CAN上位机进行通信,接收到更新指令后,将app程序烧录到app flash区域.
  • app程序:实现用户功能,并监听app更新指令.若接收到app更新指令,则跳转到CANbootloadre进行程序更新.
  • can上位机:根据用户操作,向app发送更新指令,向canbootloader传输待烧录程序的二进制文件.

2.程序运行流程

===================2.1canbootloader程序进行模式判断

程序首先在CANbootlloaer中运行,进行更新标志的读取.更新标志保存在eeprom(掉电不丢失)中预先设定的地址,每次开机到固定地址读取该标志位.若为APP_UPDATE_MODE则表示需要进行程序更新.否则直接跳转到app程序运行.

/*read the UpdateFlag*/
	UpdateMode = (uint8_t)EEPROM_Read(UPDATA_FLAG_EEPROM_ADDR);

	/*update app*/
	if((UpdateMode == APP_UPDATE_MODE) || (UpdateMode == 0xFF)) //若为0xFF,则为首次写入,此时还没有下载任何app,进入update_mode
	{														    //若为0xab,则进入到update_mode
		EEPROM_Write(UPDATA_FLAG_EEPROM_ADDR, 0x00); //防止下次CPU重启进入到下载状态
		IAP_UpdateApp(); //更新程序
	}
	/*directive jump to app*/
	else
	{
#ifdef DE_BUG
		UART_TransmitString("jump!\n");
#endif
		IAP_JumpApp(FLASH_APP_ADDR);//跳转到app
	}

=================2.2 若为APP_UPDATE_MODE,则进行程序更新

通过CAN中断接收CAN上位机发送的app.bin文件,当可执行文件发送完成后,跳转到app程序中运行.

while(1)
	{
		/*接收数据*/
		if(CanRevCount)
		{
			if(OldCount == CanRevCount)//是否还有新的数据被接收
			{
				DelayMs(200); //延迟等待,判断是否结束传输.
				if(OldCount == CanRevCount)
				{
					AppLenth = CanRevCount*4; //32bit/8bit = 4,文件传输完成,保存文件size.
					OldCount = 0;
					CanRevCount = 0;
				}
				else
				{
					OldCount = CanRevCount; //更新接收数据计数
				}
			}
			else
			{
				OldCount = CanRevCount; //更新接收数据计数
			}
		}

		/*接收结束*/
		if(AppLenth > 0)
		{
#ifdef DE_BUG
			UART_TransmitChar(GET_BIT_0_7(AppLenth));//打印size
			UART_TransmitChar(GET_BIT_8_15(AppLenth));
#endif
			IAP_WriteFLash(FLASH_APP_ADDR, (uint8_t *)CanBuf, AppLenth);//将app写入到flash中.
			UART_TransmitString("download!\n");
			IAP_JumpApp(FLASH_APP_ADDR);//跳转到app.
		}

	}

================ 2.3 从CANbootloaer跳转到app程序.

1.在IAP_JumpApp(uint32_t AppAddr)调用时,传入FLASH_APP_ADDR .FLASH_APP_ADDR 处存放SP指针,FLASH_APP_ADDR +4即为app程序的中断向量表在flash中的起始地址.

2.赋值函数指针JumpToApp 

  • 将FLASH_APP_ADDR +4强制转化为地址常量(告诉编译器为地址常量)
  • 指针间接访问方式,访问LASH_APP_ADDR +4中保存的数值,即reset中断服务程序的入口地址.
  • 将入口地址强制转化为 void (* )(void)类型,与JumpToApp 函数指针类型匹配.
  • 将该地址赋值给JumpToApp函数指针.即JumpToApp函数指针变量中存放函数的入口地址.

3.通过函数指针方式调用函数.

#define FLASH_APP_ADDR 0x00004000为预先设定的app程序的起始FLASH地址.
typedef  void (*IapFun)(void);
IapFun   JumpToApp;  //函数指针
void IAP_JumpApp(uint32_t AppAddr)
{
	/*获取app.bin的reset handle中断向量.*/
	JumpToApp = (IapFun)(*(uint32_t *)(AppAddr + 4));/*强制转化为函数指针.*/
	JumpToApp();  /*通过函数指针间接访问函数,运行函数reset_handle*/
}

=================2.4 app程序运行

app程序在bootloader阶段,即start.S中对中断向量表进行偏移设置(在本工程中,映射到RAM中).

在CAN中断中监听程序更新指令,0x111111110x11111111,若接收到8字节0x11,则进入到app程序更新模式.设置APP_UPDATE_MODE标志位,并延迟10ms(等待eeprom写入完成)后,软件重启s32k144.则跳转到2.1节进行app程序更新.

if(RxDATA[0] == 0x11111111 && RxDATA[1] == 0x11111111)
		{
			/*set and save flag*/
			UpdateFlag1 = 0xab;
			EEPROM_Write(UPDATA_FLAG_EEPROM_ADDR, UpdateFlag1);
			DelayMs(10); //wait 10ms for eeprom to save UpdateFlag

			/*software reset CPU*/
			S32_SCB->AIRCR = S32_SCB_AIRCR_VECTKEY(0x05FA) | S32_SCB_AIRCR_SYSRESETREQ_MASK;
			for(;;); /* wait until reset */
		}

3.需要注意的点

=========================3.1 app程序进行中断向量表的偏移设置.

本工程中使用S32DS IDE,并将中断向量表的偏移地址设置RAM的起始地址处.在链接器脚本中指定中断向量表偏移设置标志位,并在startup.c中将flash中的中断向量表复制到RAM中.实际上中断向量表的偏移即设置中断向量表偏移量寄存器 SCB_VICTOR的VTOR位段(在S32DS IDE中,如果__VECTOR_RAM__标识符被设置,则IDE应该会自行设置该寄存器).

__VECTOR_RAM = DEFINED(__flash_vector_table__) ? ORIGIN(m_interrupts) : __VECTOR_RAM__ ;

/*复制中断向量表 flash-->RAM*/
/* Check if VECTOR_TABLE copy is needed */
    if (__VECTOR_RAM != __VECTOR_TABLE)
    {
        /* Copy the vector table from ROM to RAM */
        for (n = 0; n < (((uint32_t)__RAM_VECTOR_TABLE_SIZE)/sizeof(uint32_t)); n++)
        {
            __VECTOR_RAM[n] = __VECTOR_TABLE[n];
        }
        /* Point the VTOR to the position of vector table */
        INT_VECTOR_Reg = (uint32_t)__VECTOR_RAM;
    }

===========================3.2 修改链接器脚本,划分CANbootloaer和APP工程的falsh存储.

需要为bootloader和app工程明确划分flash.一般将bootloader存放在低地址,app存放在高地址flash.在两个链接工程的链接器脚本中指定划分规则.

  •  CANbootloader(0x0000 - 0x4000)(16kb)
  •  app(0X4000  -  (512K-0X4000))
/*CANbootloader*/
/* Specify the memory areas */
MEMORY
{
  /* Flash */
  m_interrupts          (RX)  : ORIGIN = 0x00000000, LENGTH = 0x00000400
  m_flash_config        (RX)  : ORIGIN = 0x00000400, LENGTH = 0x00000010
  m_text                (RX)  : ORIGIN = 0x00000410, LENGTH = 0x0007FBF0

  /* SRAM_L */
  m_data                (RW)  : ORIGIN = 0x1FFF8000, LENGTH = 0x00008000

  /* SRAM_U */
  m_data_2              (RW)  : ORIGIN = 0x20000000, LENGTH = 0x00007000
}


/*app */
/* Specify the memory areas */
MEMORY
{
  /* Flash */
  m_interrupts          (RX)  : ORIGIN = 0x00004000, LENGTH = 0x00000400
  m_flash_config        (RX)  : ORIGIN = 0x00004400, LENGTH = 0x00000010
  m_text                (RX)  : ORIGIN = 0x00004410, LENGTH = 0x0007BBF0

  /*
  m_interrupts        (RX)  : ORIGIN = 0x00000000, LENGTH = 0x00000400
  m_flash_config        (RX)  : ORIGIN = 0x0000400, LENGTH = 0x00000010
  m_text                (RX)  : ORIGIN = 0x0000410, LENGTH = 0x0007BBF0
  */

  /* SRAM_L */
  m_data                (RW)  : ORIGIN = 0x1FFF8000, LENGTH = 0x00008000

  /* SRAM_U */
  m_data_2              (RW)  : ORIGIN = 0x20000000, LENGTH = 0x00007000
}

4.上位机

使用VB编写,对原有上位机进行了功能扩展,支持二进制文件烧录.在此放上界面.

源码​​​​​​​

GitHub - wytzzz/S32K144_CANbootloader

  • 7
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值