本文摘要:本文章介绍如何使用NXP官方软件S32KDS实现CAN总线上的bootloader

开发平台:S32 Design Studio for ARM Version 2.2

SDK版本:S32_SDK_S32K1xx_RTM_3.0.0

使用芯片:S32K148

使用设备:图莫斯usb2can

源码下载方式在文末!!!

1. 先介绍一下用于升级的CAN协议(假定ID:0x555为设备的独有ID)

(1)开始升级时,上位机会持续发送表1-1的报文。在APP程序里会有一个相应的处理,即接收到表1-1的报文后会重启MCU,使得MCU能够进入BOOT程序;在BOOT程序里也会有一个相应的处理,即接收到表1-1的报文后会将BOOT延时跳转APP的标志置位,即不再进行APP的跳转,同时发送一则表1-2的报文用以通知上位机已进入BOOT程序。

ID Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7
0x555 0x7F N/A N/A N/A N/A N/A N/A N/A

表1-1

ID Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7
0x555 0x63 N/A N/A N/A N/A 0x1 N/A N/A

表1-2

(2)上位机收到表1-2的报文后,则发送表1-3的报文,其中后四个字节表示APP程序bin文件的大小,即总字节数(APPByteSize = Byte4<<24+Byte5<<16+Byte6<<8+Byte7)。BOOT程序收到表1-3的报文则会计算APP程序的大小,用在后续对照接收APP数据和判断APP数据接收是否完成,随后发送一则表1-4的报文用以通知上位机可以开始发送APP数据。

ID Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7
0x555 0x60 N/A N/A N/A APPsize APPsize APPsize APPsize

表1-3

ID Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7
0x555 0x63 N/A N/A N/A N/A N/A 0x1 N/A

表1-4

(3)上位机收到表1-4的报文后,则持续发送表1-5格式的APP数据报文,直到发送完。其中Byte1-Byte3表示当前报文携带的APP数据的索引号(逐帧累加),用于和BOOT程序自身的索引号对照,保证APP数据的正确性;其Byte4-Byte7表示APP的四字节数据,Byte4-Byte7——APPByte1-APPByte4,即CAN报文的低字节存放APP的低字节数据。

ID Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7
0x555 0x61 index index index APPByte1 APPByte2 APPByte3 APPByte4

表1-5

(4)BOOT程序持续接收表1-5的报文期间,每接收一帧都会对照自身索引号和报文携带索引号是否一致,以保证接收正确。如果出现不一致的情况则会返回给上位机一则表1-6的报文,其中Byte5-Byte7存放出错的索引号,上位机可以据此重新发送此索引号的APP数据。

ID Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7
0x555 0x62 N/A N/A N/A N/A index index index

表1-6

(5)BOOT程序持续接收表1-5的报文期间,会依据此前计算出的APP数据总大小来判断APP数据是否接收完成。接收完成后,BOOT程序会发送一则表1-7的报文,用以通知上位机接收完成,自身则会跳转至APP执行APP程序。

ID Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7
0x555 0x63 N/A N/A N/A N/A N/A N/A 0x1

表1-7

2. bootloader的实现逻辑和基本原理就不再赘述,主程序奉上

实现bootloader主要用到了以下组件,在往期文章中均有介绍:

flexcan组件:

(104条消息) S32K的flexcan组件使用(RxFIFO+中断)_阿衰0110的博客-CSDN博客

lptmr组件:

(104条消息) S32K的lptmr组件使用(系统定时器)_阿衰0110的博客-CSDN博客

flash组件:

(104条消息) S32K的flash组件使用(操作FLASH)_阿衰0110的博客-CSDN博客

wdog组件:

(104条消息) S32K的wdog组件使用(看门狗)_阿衰0110的博客-CSDN博客

/** system.c**  Created on: 2022年3月8日*      Author: MNIAS*/
#include "main.h"// App起始地址
#define AppAddr         0x8000u
// App大小
#define AppSize         0x20000u
// IAP缓存区大小   S32K148的FLASH_DRV_Program最小可写大小是8B
#define IAPBuffSize     1024u
// 私有ID
uint16_t CANID_Private;
// IAP升级标志
static uint8_t IAP_Flag = 0;
// IAP数据索引
static uint32_t IAP_DATA_Index = 0;
// IAP数据大小
static uint32_t IAP_DATA_Size = 0;
// IAP缓存区
static uint8_t IAP_DATA_Buff[IAPBuffSize];
// flash操作结果
uint8_t result = 0;
static uint32_t failAddr = 0;typedef  void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t JumpAddress;static void return_beginSignal(void);
static void receive_IAP_begin(void);
static void receive_IAP_handle(void);
static void JumpToApp(void);/*** @brief  硬件错误处理* @param  None* @retval None*/
void HardFault_Handler(void)
{
#ifdef DEBUG_printfSEGGER_RTT_printf(0,"Hard fault error\n");
#endif
}
/*** @brief  系统初始化* @param  None* @retval None*/
void SYSTEM_Init(void)
{CLOCK_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT, g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT);CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_AGREEMENT);PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);CAN0_Init();CAN1_Init();CAN2_Init();lptmr_Init();get_CANID_Private(&CANID_Private);Flash_Init();WDOG_Init(500); // 1s
#ifdef DEBUG_printfSEGGER_RTT_printf(0,"entery boot, private CAN ID is 0x%03x\n", CANID_Private);
#endif
}
/*** @brief  任务处理* @param  None* @retval None*/
void TASK_Schedule(void)
{// 数据第一字节为模式switch(CANrecMsg.CAN_DATA[0]){case 0x60:receive_IAP_begin();break;case 0x61:receive_IAP_handle();break;case 0x7e:set_CANID_Private(CANrecMsg.CAN_DATA);break;case 0x7F:return_beginSignal();break;}// 无升级操作if(IAP_Flag == 0){// 超时则跳转APPif(TIM_DelayTimeCounter >= 50){JumpToApp();}}WDOG_Feed();
}
/*** @brief  返回IAP开始信号* @param  None* @retval None*/
static void return_beginSignal(void)
{// 返回IAP预备信号  上位机接收后将发送IAP数据大小set_CANTransmitData(useCANx, MAILBOX_9, CANID_Private,0x63,0,0,0,0,0x1,0,0);// 清除模式位CANrecMsg.CAN_DATA[0] = 0;
}
/*** @brief  准备接收IAP数据  计算IAP数据大小* @param  None* @retval None*/
static void receive_IAP_begin(void)
{// 清零索引  索引从0开始IAP_DATA_Index = 0;// 置位IAP升级标志IAP_Flag = 1;// 计算IAP数据大小IAP_DATA_Size = (CANrecMsg.CAN_DATA[4] << 24) | (CANrecMsg.CAN_DATA[5] << 16) | (CANrecMsg.CAN_DATA[6] << 8) | (CANrecMsg.CAN_DATA[7]);
#ifdef DEBUG_printfSEGGER_RTT_printf(0,"IAP data size : %d\n", IAP_DATA_Size);
#endifINT_SYS_DisableIRQGlobal();// S32K148的FLASH_DRV_EraseSector最小擦除扇区大小是 4KBresult = FLASH_DRV_EraseSector(&flashSSDConfig, AppAddr, ((IAP_DATA_Size >> 12) + 1) << 12);
#ifdef DEBUG_printfSEGGER_RTT_printf(0,"erase flash T(0)/F(!0) : %d\n", result);
#endif// 验证擦除result = FLASH_DRV_VerifySection(&flashSSDConfig, AppAddr, ((IAP_DATA_Size >> 12) + 1) << 12 >> 4, 1u);
#ifdef DEBUG_printfSEGGER_RTT_printf(0,"verify erase T(0)/F(!0) : %d\n", result);
#endifINT_SYS_EnableIRQGlobal();// 返回IAP开始信号  上位机接收后会持续发送IAP数据set_CANTransmitData(useCANx, MAILBOX_9, CANID_Private,0x63,0,0,0,0,0,0x1,0);// 清除模式位CANrecMsg.CAN_DATA[0] = 0;
}
/*** @brief  正在接收IAP数据* @param  None* @retval None*/
static void receive_IAP_handle(void)
{// 计算当前帧的IAP数据索引uint32_t IndexTemp = (CANrecMsg.CAN_DATA[1] << 16) | (CANrecMsg.CAN_DATA[2] << 8) | CANrecMsg.CAN_DATA[3];
#ifdef DEBUG_printfSEGGER_RTT_printf(0,"message current IAP data index : %d\nboot current IAP data index : %d\n", IndexTemp, IAP_DATA_Index);
#endif// IAP升级标志被置位if(IAP_Flag == 1){// 判断当前帧的IAP数据索引和存储的IAP数据索引是否一致,且数据大小小于APP的大小  IndexTemp<<2 = IndexTemp*4  因为一帧报文携带了4Byteif(IndexTemp == IAP_DATA_Index && (IndexTemp << 2) < AppSize){// 计算当前缓存字节数uint16_t currentBuffSize = ((IAP_DATA_Index << 2) % IAPBuffSize) + 4;// 计算当前接收总字节数uint32_t currentRecSize = (IAP_DATA_Index << 2) + 4;uint8_t count;// 一帧4Bytefor(count = 0; count < 4; count++){// IAP数据放入缓存区IAP_DATA_Buff[currentBuffSize - 4 + count] = CANrecMsg.CAN_DATA[4 + count];
#ifdef DEBUG_printfSEGGER_RTT_printf(0,"IAP data buff %d : %02x\n", currentBuffSize - 4 + count, IAP_DATA_Buff[currentBuffSize - 4 + count]);
#endif}// 缓存区数据存满 或 接收到的IAP数据大小达到此次IAP升级数据的大小时  进行一次写入if(currentBuffSize == IAPBuffSize || currentRecSize >= IAP_DATA_Size){INT_SYS_DisableIRQGlobal();// S32K148的FLASH_DRV_Program最小可写大小是8Bresult = FLASH_DRV_Program(&flashSSDConfig, AppAddr + ((IAP_DATA_Index << 2) >> 10 << 10), IAPBuffSize, IAP_DATA_Buff);
#ifdef DEBUG_printfSEGGER_RTT_printf(0,"write flash T(0)/F(!0) : %d\n", result);
#endif// 检验写flashresult = FLASH_DRV_ProgramCheck(&flashSSDConfig, AppAddr + ((IAP_DATA_Index << 2) >> 10 << 10), IAPBuffSize, IAP_DATA_Buff, &failAddr, 1u);
#ifdef DEBUG_printfSEGGER_RTT_printf(0,"check write T(0)/F(!0) : %d, fail address %x\n", result, failAddr);
#endifINT_SYS_EnableIRQGlobal();// 接收到的IAP数据大小达到此次IAP升级数据的总大小  即为接收完全部数据  IAP完成if(currentRecSize >= IAP_DATA_Size){// 返回IAP完成信号set_CANTransmitData(useCANx, MAILBOX_9, CANID_Private,0x63,0,0,0,0,0,0,0x1);// 延时5msTIM_DelayTimeCounter = 0;while(TIM_DelayTimeCounter < 5);// 返回IAP完成信号set_CANTransmitData(useCANx, MAILBOX_9, CANID_Private,0x63,0,0,0,0,0,0,0x1);// 延时5msTIM_DelayTimeCounter = 0;while(TIM_DelayTimeCounter < 5);// 跳转APPJumpToApp();}}IAP_DATA_Index++;}else{// 返回IAP错误信号set_CANTransmitData(useCANx, MAILBOX_9, CANID_Private,0x62,0,0,0,0,IAP_DATA_Index >> 16, IAP_DATA_Index >> 8, IAP_DATA_Index);}}// 清除模式位CANrecMsg.CAN_DATA[0] = 0;
}
/*** @brief  跳转APP程序* @param  None* @retval None*/
static void JumpToApp(void)
{LPTMR_DRV_Deinit(INST_LPTMR1);FLEXCAN_DRV_Deinit(INST_CANCOM1);FLEXCAN_DRV_Deinit(INST_CANCOM2);FLEXCAN_DRV_Deinit(INST_CANCOM3);WDOG_DRV_Deinit(INST_WATCHDOG1);/* Disable FIRC divider  *///SCG->FIRCDIV |= SCG_FIRCDIV_FIRCDIV2(0x000);// 关闭全局中断INT_SYS_DisableIRQGlobal();JumpAddress = *(volatile uint32_t*) (AppAddr + 4);Jump_To_Application =  (pFunction) JumpAddress;Jump_To_Application();
}

3. boot程序需要配置自身所占地址的大小,防止自身地址与APP程序地址重合导致的一些问题

4. APP程序里需要配置flash基地址偏移(同上述 3. 的路径)

bootloader源码下载地址:

https://download.csdn.net/download/m0_50669075/85034836

END

S32K的bootloader CAN总线实现相关推荐

  1. S32Kxxx bootloader之CAN bootloader

    Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/cou ...

  2. 贺世界智能网联汽车大会-速锐得V8翻开智能驾驶汽车新篇章

    2018年10月18日,世界智能网联汽车大会在北京国家会议中心盛大开幕. 智能网联汽车是信息通信.互联网.大数据.人工智能.道路交通等行业加速跨界融合变革的新兴产物,是全球产业创新热点与未来发展的制高 ...

  3. 汽车电气化共享移动性及自动驾驶对未来出行方式的全面展望

    汽车电气化共享移动性及自动驾驶对未来出行方式的全面展望 执行总结 从上空鸟瞰一座城市就是在看一个处于运动之中的世界.火车载着人们去工作或从工作中返回,出租车忙碌地穿梭在大街小巷,卡车在运送货物或运走垃 ...

  4. S32K Bootloader

    S32K Bootloader 开发流程– 1. 功能 bootlloader一般分为三个部分,上位机客户端,boot程序和App程序. 上位机客户端软件:用来将mcu的app程序文件发送给mcu,发 ...

  5. 基于S32K的油门踏板检测项目(基于CAN的Bootloader覆盖升级、回滚升级)

    文章目录 项目概述 要求 Bootloader介绍 原理设计 功能设计 硬件设计 软件设计 主机 主机流程 Xmodem协议 代码 从机 从机流程 升级方案 区域划分 Boot链接文件修改 APP A ...

  6. 汽车电子ECU bootloader开发要点详解

    引言 1. bootloader的功能 2. 如何建立可靠的总线通信? 3. 解析编程文件(S19/HEX/BIN) 4. NVM驱动程序开发 5. bootloader开发的其他要点 a. boot ...

  7. bootloader详解(转载)

    一.bootloader介绍 bootloader是硬件在加电开机后,除BIOS固化程序外最先运行的软件,负责载入真正的操作系统,可以理解为一个超小型的os.目前在Linux平台中主要有lilo.gr ...

  8. 操作系统实现(一):从Bootloader到ELF内核

    Bootloader 我们知道计算机启动是从BIOS开始,再由BIOS决定从哪个设备启动以及启动顺序,比如先从DVD启动再从硬盘启动等.计算机启动后,BIOS根据配置找到启动设备,并读取这个设备的第0 ...

  9. 服务总线yali测试_满足吉利要求的车载总线测试服务

    自2012年以来,经纬恒润连续参与吉利10多款车型的电子电器开发与测试工作,包括吉利1.0及2.0两代平台的首发车型.吉利高度认可经纬恒润团队专业的技术能力.丰富的经验以及多年来持之以恒的认真负责的工 ...

最新文章

  1. 训练Epoch, Batch, Iteration
  2. [转] createObjectURL方法 实现本地图片预览
  3. void func(int n)C语言,C语言高手帮忙分析一下复杂的函数声明
  4. Python用泰勒公式模拟函数
  5. Caffe: Caffe的Python接口
  6. 大数据平台容量评估_大数据平台
  7. 转-SpringBoot——使用外置的Tomcat服务器
  8. 大数据要学javaweb吗_大数据是私有财产吗?
  9. Git 小问题:fatal: not a git repository (or any of the parent directories): .git
  10. 微信支付jsapi并写入数据库--回调函数(notify.php)的使用
  11. CSS 自定义滚动条样式
  12. win10摄像头可以用计算机里不显示,win10打开计算机如何显示摄像头
  13. 如何查询一个网站的域名备案信息?
  14. 入围T00ls 2018风云人物
  15. 第四天(打造离线下载服务器)
  16. 计算机视觉领域常见期刊和会议
  17. 图片灯箱插件——lightBox
  18. echarts 圆环图中间插图或文字
  19. [精简]托福核心词汇100
  20. python字典怎么处理_Python字典的处理

热门文章

  1. 5G NR 基本概念——BWP
  2. fpga hdmi接收和发送部分调试
  3. 木块砌墙算法(C#源码)
  4. 像素、分辨率与图片大小之关系
  5. 打开office word excel弹出visual studio
  6. linux终端stty恢复默认,linux stty命令
  7. 为什么要初始化CSS样式
  8. 散养土鸡野外天敌的防护
  9. gitlab中如何删除项目
  10. “存储为Web所用格式”命令是灰色不可用的原因和解决方法