uds bootloader stm32f103 iso 15765 14229 在线升级 uds can 15765 14229 所有源码开源!!!测试板(底层,应用层),上位机软件

搞过车载开发的朋友肯定知道UDS协议有多磨人,特别是要在资源有限的STM32F103上搞在线升级。今天咱们直接上硬货,手把手拆解基于ISO 15765和14229标准的Bootloader实现,所有代码都开源给你看个通透。

先看Bootloader启动流程的关键代码:

void jump_to_app(void) {
  typedef void (*pFunction)(void);
  pFunction Jump_To_Application;
  
  if (((*(__IO uint32_t*)APP_ADDRESS) & 0x2FFE0000) == 0x20000000) {
    Jump_To_Application = (pFunction)(*(__IO uint32_t*)(APP_ADDRESS + 4));
    __set_MSP(*(__IO uint32_t*)APP_ADDRESS);
    Jump_To_Application();
  }
}

这段代码的精髓在于检查应用程序栈顶地址是否合法(0x20000000是STM32F103的RAM起始地址),然后通过函数指针跳转。注意这里必须用set_MSP手动设置主栈指针,否则直接跳转必死机。

CAN通信部分采用动态ID配置:

CAN_FilterInitTypeDef filter;
filter.CAN_FilterIdHigh = 0x123 << 5; //标准帧ID高位
filter.CAN_FilterIdLow = 0 | CAN_ID_STD; 
filter.CAN_FilterMaskIdHigh = 0xFFE0; //精确匹配前11位
filter.CAN_FilterMaskIdLow = 0x0000;
filter.CAN_FilterFIFOAssignment = 0;
filter.CAN_FilterNumber = 0;
filter.CAN_FilterMode = CAN_FilterMode_IdMask;
filter.CAN_FilterScale = CAN_FilterScale_32bit;
filter.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&filter);

这里有个坑点:STM32的过滤器配置寄存器是把ID左移5位对齐的,所以实际写入时要将ID值左移5位。掩码设置成0xFFE0意味着只匹配ID部分,不关注扩展帧标志。

uds bootloader stm32f103 iso 15765 14229 在线升级 uds can 15765 14229 所有源码开源!!!测试板(底层,应用层),上位机软件

处理UDS请求时要注意时序控制:

def send_uds_request():
    can_id = 0x701  # 物理寻址
    data = [0x34, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66] # 34服务请求下载
    can_bus.send(can_id, data)
    
    # 等待流控帧
    flow_control = can_bus.recv(timeout=1)
    if flow_control.data[0] & 0xF0 == 0x30:  # 流控帧类型判断
        block_size = flow_control.data[1]
        st_min = flow_control.data[2]
        # 开始分段传输...

这里有个实战技巧:当发送大数据包时,建议将STmin设置为5ms以上,避免低端MCU处理不过来导致超时。我们在STM32F103上实测发现,把块大小控制在8帧以内最稳定。

源码仓库里有个特别实用的调试功能——内存实时校验:

void check_flash(uint32_t addr, uint8_t *data, uint32_t len) {
    uint8_t *flash_ptr = (uint8_t*)addr;
    for(uint32_t i=0; i<len; i++) {
        if(flash_ptr[i] != data[i]) {
            send_negative_response(SERVICE_34, NRC_GENERAL_PROGRAMMING_FAILURE);
            return;
        }
    }
    send_positive_response(SERVICE_34);
}

这个校验逻辑看似简单,但能避免90%以上的烧写失败问题。特别是在劣质CAN转换器环境下,数据丢帧时有发生,实时校验比CRC更直接。

上位机用PyQT实现了这样的传输效果:当检测到连续5帧传输失败时,自动切换波特率到125K重试。这个功能在实车测试中救过好几次场,毕竟车载CAN总线质量参差不齐。

完整项目已经扔在Github(地址在文末),包含STM32F103的IAP工程、应用层demo、Python上位机。测试板上特意留了个彩蛋:长按按键3秒会进入低速回环模式,专门用来抓总线异常。下次遇到刷写失败,不妨试试这个调试模式,保准能快速定位是MCU问题还是总线问题。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐