本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:STM32F103是一款基于ARM Cortex-M3内核的微控制器,广泛应用于嵌入式系统中。本项目旨在利用其内置CAN控制器,实现通过CAN总线进行固件在线升级(bootloader)的功能。该bootloader包含接收和验证CAN消息、写入闪存、跳转到新代码执行等关键步骤,并考虑了引导加载流程、CAN配置、数据接收校验、存储管理、安全机制、更新过程和故障恢复等关键点。本项目提供了源代码或相关资源,可帮助开发者理解STM32微控制器的底层操作,提高嵌入式系统设计能力。

1. STM32F103 CAN总线简介

CAN(控制器局域网络)总线是一种广泛应用于汽车、工业自动化和医疗设备等领域的串行通信协议。它以其高可靠性、高实时性和抗干扰性而著称。STM32F103系列微控制器集成了一个CAN控制器,支持CAN 2.0B协议。

CAN总线采用多主从结构,每个节点都可以发送和接收消息。消息通过称为“帧”的数据包进行传输,帧中包含标识符、数据和校验信息。CAN总线使用非破坏性仲裁机制,优先级高的消息可以打断优先级低的正在发送的消息。

2.1 CAN控制器寄存器

2.1.1 CAN_MCR寄存器

CAN_MCR寄存器用于配置CAN控制器的基本功能和模式。其寄存器结构如下:

typedef struct
{
    uint32_t DBF:1;      //禁用时间段长度
    uint32_t TTCM:1;     //时间触发通信模式
    uint32_t ABOM:1;     //自动离线管理
    uint32_t AWUM:1;     //自动唤醒模式
    uint32_t NART:1;     //不应答时间
    uint32_t RFLM:1;     //接收FIFO锁定模式
    uint32_t TXFP:4;     //发送FIFO优先级
    uint32_t SLEEP:1;    //睡眠模式
    uint32_t INRQ:1;     //初始化请求
    uint32_t RESET:1;    //复位请求
    uint32_t TTCME:1;    //时间触发通信模式使能
    uint32_t Reserved:14;
}CAN_MCR_TypeDef;

参数说明:

  • DBF:禁用时间段长度,用于设置禁用时间段的长度。
  • TTCM:时间触发通信模式,用于使能或禁用时间触发通信模式。
  • ABOM:自动离线管理,用于使能或禁用自动离线管理功能。
  • AWUM:自动唤醒模式,用于使能或禁用自动唤醒模式。
  • NART:不应答时间,用于设置不应答时间的长度。
  • RFLM:接收FIFO锁定模式,用于使能或禁用接收FIFO锁定模式。
  • TXFP:发送FIFO优先级,用于设置发送FIFO的优先级。
  • SLEEP:睡眠模式,用于使能或禁用睡眠模式。
  • INRQ:初始化请求,用于触发CAN控制器的初始化过程。
  • RESET:复位请求,用于复位CAN控制器。
  • TTCME:时间触发通信模式使能,用于使能或禁用时间触发通信模式。

2.1.2 CAN_MSR寄存器

CAN_MSR寄存器用于反映CAN控制器的当前状态。其寄存器结构如下:

typedef struct
{
    uint32_t RX:1;       //接收缓冲区未读信息标志
    uint32_t TX:1;       //发送缓冲区未发送信息标志
    uint32_t SERR:1;     //错误警告标志
    uint32_t EWGF:1;     //错误警告标志生成标志
    uint32_t EPVF:1;     //错误被动标志
    uint32_t BOFF:1;     //总线离线标志
    uint32_t STF:1;      //时间戳标志
    uint32_t MLOK:1;     //消息锁定标志
    uint32_t SLAK:1;     //同步丢失标志
    uint32_t INAK:1;     //初始化未完成标志
    uint32_t Reserved:19;
}CAN_MSR_TypeDef;

参数说明:

  • RX:接收缓冲区未读信息标志,用于指示接收缓冲区是否有未读信息。
  • TX:发送缓冲区未发送信息标志,用于指示发送缓冲区是否有未发送信息。
  • SERR:错误警告标志,用于指示是否发生错误。
  • EWGF:错误警告标志生成标志,用于指示错误警告标志是否被生成。
  • EPVF:错误被动标志,用于指示是否发生错误被动。
  • BOFF:总线离线标志,用于指示是否发生总线离线。
  • STF:时间戳标志,用于指示是否发生时间戳。
  • MLOK:消息锁定标志,用于指示是否发生消息锁定。
  • SLAK:同步丢失标志,用于指示是否发生同步丢失。
  • INAK:初始化未完成标志,用于指示是否发生初始化未完成。

3. CAN消息接收与校验

3.1 CAN消息格式

CAN总线上的消息采用特定格式进行传输,分为标准帧和扩展帧两种类型。

3.1.1 标准帧

标准帧由11位标识符、1个RTR位、1个IDE位、1个DLC位和8个数据字节组成,总长为11位+1位+1位+1位+8字节=12字节。

  • 标识符(11位) :用于唯一标识消息。
  • RTR(远程传输请求)位(1位) :为0表示数据帧,为1表示远程帧。
  • IDE(标识符扩展)位(1位) :为0表示标准帧,为1表示扩展帧。
  • DLC(数据长度代码)位(1位) :表示数据字节的个数,范围为0-8。
  • 数据字节(8个) :用于传输数据。

3.1.2 扩展帧

扩展帧由29位标识符、1个RTR位、1个IDE位、1个DLC位和0-64个数据字节组成,总长为29位+1位+1位+1位+0-64字节=32-96字节。

  • 标识符(29位) :用于唯一标识消息。
  • RTR(远程传输请求)位(1位) :为0表示数据帧,为1表示远程帧。
  • IDE(标识符扩展)位(1位) :为0表示标准帧,为1表示扩展帧。
  • DLC(数据长度代码)位(1位) :表示数据字节的个数,范围为0-64。
  • 数据字节(0-64个) :用于传输数据。

3.2 CAN消息接收

3.2.1 消息缓冲区配置

STM32F103 CAN控制器有3个接收缓冲区,每个缓冲区可以存储一个CAN消息。消息缓冲区通过寄存器CAN_FMR配置。

CAN_FMR |= CAN_FMR_CAN2SB;  // 启用双缓冲区模式

3.2.2 消息接收中断处理

当CAN控制器收到消息时,会产生接收中断。中断处理函数需要读取CAN_SR寄存器中的RBS1和RBS2位,确定接收到的消息存储在哪个缓冲区中。

void CAN1_RX0_IRQHandler(void)
{
    uint32_t rbs = CAN1->SR & (CAN_SR_RBS1 | CAN_SR_RBS2);
    uint8_t buf_idx = (rbs >> CAN_SR_RBS1_Pos) & 0x03;

    // 读取接收到的消息
    CAN_RxMessage rx_msg;
    CAN_Receive(CAN1, buf_idx, &rx_msg);

    // 处理消息
    ...
}

3.3 CAN消息校验

3.3.1 奇偶校验

CAN总线采用奇偶校验来检测数据传输中的错误。奇偶校验位位于数据帧的最后一位,为0表示偶校验,为1表示奇校验。

// 计算奇偶校验位
uint8_t parity = 0;
for (int i = 0; i < 8; i++) {
    parity ^= rx_msg.Data[i];
}
parity = (parity % 2) == 0 ? 0 : 1;

// 检查奇偶校验位
if (parity != rx_msg.Data[8]) {
    // 奇偶校验错误
}

3.3.2 CRC校验

CAN总线还采用CRC校验来检测数据传输中的错误。CRC校验码位于数据帧的最后16位。

// 计算CRC校验码
uint16_t crc = CAN_CalculateCRC(rx_msg.Data, 8);

// 检查CRC校验码
if (crc != rx_msg.CRC) {
    // CRC校验错误
}

4. 闪存编程与管理

4.1 闪存结构与编程

4.1.1 闪存结构

STM32F103 的闪存分为两个部分:

  • 主闪存 (Main Flash) :存储用户程序代码和数据。容量为 128KB。
  • 系统存储器 (System Memory) :存储引导加载程序和系统参数。容量为 20KB。

闪存由页组成,每个页的大小为 256 字节。页进一步划分为 16 个字(32 位)。

4.1.2 闪存编程过程

闪存编程过程涉及以下步骤:

  1. 解锁闪存: 使用 FLASH_Unlock() 函数解锁闪存。
  2. 擦除页: 使用 FLASH_ErasePage() 函数擦除要写入的页。
  3. 编程字: 使用 FLASH_ProgramWord() 函数逐个编程 32 位字。
  4. 锁定闪存: 使用 FLASH_Lock() 函数锁定闪存。
// 解锁闪存
FLASH_Unlock();

// 擦除页
FLASH_ErasePage(FLASH_PAGE_ADDRESS);

// 编程字
FLASH_ProgramWord(FLASH_WORD_ADDRESS, 0x12345678);

// 锁定闪存
FLASH_Lock();

4.2 闪存擦除

4.2.1 页擦除

页擦除将页中所有字重置为 0xFF。使用 FLASH_ErasePage() 函数进行页擦除。

// 擦除页
FLASH_ErasePage(FLASH_PAGE_ADDRESS);

4.2.2 扇区擦除

扇区由多个页组成。扇区擦除将扇区中所有页擦除。使用 FLASH_EraseSector() 函数进行扇区擦除。

// 擦除扇区
FLASH_EraseSector(FLASH_SECTOR_ADDRESS, FLASH_SECTOR_SIZE);

4.3 闪存读写保护

4.3.1 读保护

读保护防止对闪存内容的读取。使用 FLASH_OB_RDP() 选项字节启用读保护。

// 启用读保护
FLASH_OB_RDP(ENABLE);

4.3.2 写保护

写保护防止对闪存内容的写入。使用 FLASH_OB_WRP() 选项字节启用写保护。

// 启用写保护
FLASH_OB_WRP(ENABLE);

5. 安全机制设计

5.1 身份认证

身份认证是确保系统中只有授权用户才能访问敏感信息和资源的关键安全机制。STM32F103 微控制器提供了多种身份认证机制,包括:

5.1.1 挑战-应答机制

挑战-应答机制是一种身份认证协议,其中认证服务器向客户端发送一个随机数(称为挑战),客户端使用其私钥对挑战进行加密并将其发送回服务器。服务器验证响应是否正确,从而验证客户端的身份。

// 服务器端代码
uint32_t challenge = rand();
send_challenge(challenge, client_id);

// 客户端端代码
uint32_t response = encrypt_challenge(challenge, private_key);
send_response(response, client_id);

5.1.2 密码认证

密码认证是一种身份认证机制,其中用户输入密码,系统将密码与存储在系统中的哈希值进行比较。如果密码匹配,则用户被认证。

// 服务器端代码
uint32_t hash = get_password_hash(username);

// 客户端端代码
uint32_t input_hash = hash(password);
send_hash(input_hash, username);

5.2 数据加密

数据加密是保护敏感数据免遭未经授权访问的一种重要安全机制。STM32F103 微控制器支持多种加密算法,包括:

5.2.1 对称加密算法

对称加密算法使用相同的密钥对数据进行加密和解密。常见的对称加密算法包括 AES、DES 和 RC4。

// 加密函数
uint8_t *encrypt(uint8_t *data, size_t data_len, uint8_t *key, size_t key_len) {
  AES_KEY aes_key;
  AES_set_encrypt_key(key, key_len * 8, &aes_key);
  AES_encrypt(data, data, &aes_key);
  return data;
}

// 解密函数
uint8_t *decrypt(uint8_t *data, size_t data_len, uint8_t *key, size_t key_len) {
  AES_KEY aes_key;
  AES_set_decrypt_key(key, key_len * 8, &aes_key);
  AES_decrypt(data, data, &aes_key);
  return data;
}

5.2.2 非对称加密算法

非对称加密算法使用一对密钥:公钥和私钥。公钥用于加密数据,而私钥用于解密数据。常见的非对称加密算法包括 RSA、ECC 和 DSA。

// 生成密钥对
RSA *rsa = RSA_new();
RSA_generate_key_ex(rsa, 2048, RSA_F4, NULL);

// 公钥加密
uint8_t *encrypt(uint8_t *data, size_t data_len, RSA *rsa) {
  int rsa_len = RSA_size(rsa);
  uint8_t *encrypted_data = malloc(rsa_len);
  RSA_public_encrypt(data_len, data, encrypted_data, rsa, RSA_PKCS1_OAEP_PADDING);
  return encrypted_data;
}

// 私钥解密
uint8_t *decrypt(uint8_t *data, size_t data_len, RSA *rsa) {
  int rsa_len = RSA_size(rsa);
  uint8_t *decrypted_data = malloc(rsa_len);
  RSA_private_decrypt(data_len, data, decrypted_data, rsa, RSA_PKCS1_OAEP_PADDING);
  return decrypted_data;
}

6. 更新过程与故障恢复

6.1 更新过程

6.1.1 固件下载

固件下载可以通过串口、USB或网络等方式进行。具体步骤如下:

  1. 建立与设备的通信连接。
  2. 发送固件文件到设备。
  3. 接收设备返回的确认信息。
6.1.2 固件验证

固件验证用于确保下载的固件文件完整无误。常用的验证方法有:

  • CRC校验: 计算固件文件的CRC值,并与固件文件中的CRC值进行比较。
  • MD5校验: 计算固件文件的MD5值,并与固件文件中的MD5值进行比较。
6.1.3 固件更新

固件更新是指将验证通过的固件文件写入设备的闪存中。具体步骤如下:

  1. 擦除目标闪存区域。
  2. 将固件文件写入闪存。
  3. 验证固件更新是否成功。

6.2 故障恢复

6.2.1 看门狗定时器

看门狗定时器是一种硬件机制,用于检测系统是否正常运行。如果系统在指定时间内没有向看门狗定时器发送复位信号,则看门狗定时器将触发系统复位。

6.2.2 故障处理机制

故障处理机制用于处理系统中发生的各种故障,包括:

  • 内存错误: 使用内存保护单元(MPU)或错误校验码(ECC)来检测和处理内存错误。
  • 外设故障: 使用外设状态寄存器来检测和处理外设故障。
  • 软件异常: 使用异常处理机制来捕获和处理软件异常。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:STM32F103是一款基于ARM Cortex-M3内核的微控制器,广泛应用于嵌入式系统中。本项目旨在利用其内置CAN控制器,实现通过CAN总线进行固件在线升级(bootloader)的功能。该bootloader包含接收和验证CAN消息、写入闪存、跳转到新代码执行等关键步骤,并考虑了引导加载流程、CAN配置、数据接收校验、存储管理、安全机制、更新过程和故障恢复等关键点。本项目提供了源代码或相关资源,可帮助开发者理解STM32微控制器的底层操作,提高嵌入式系统设计能力。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐