当前位置: 首页 > article >正文

基于DSP28335的CAN升级方案:自主开发的BootLoader与上位机完全支持

基于dsp28335的can升级方案 bootloader、上位机等全部自主开发 文件说明 1、setup为上位机安装文件 2、V5为dsp28335的BootLoader源代码我用的CCS10.3.1 3、WindowsApplication3为VS平台的上位机源代码,我用的VS2013 4、app.bin为测试用的app烧录固件。 5、F28335_FLASH_COM_V1为app代码参考的cmd文件。 使用ZLG的USBCAN-II。如果是别家的盒子看他是否给了兼容周力功的方法按照那个方法操作上位机就可以 操作流程 1、先连接好CAN盒和DSP不上电打开上位机默认的设置不要修改任何选项。 2、点击“连接”再点击“启动”。 3、打开目标bin文件。 4、DSP上电3S内电机“更新固件”。 5、等待完成烧录程序自动跳转到APP中。 注意 1、如果DSP上电后3秒内未收到ID0x00001342发来的数据则自动跳转到APP中 2、如果上位机已经打开了app.bin文件烧录过程中失败了需要重启上位机。 3、自己用时需要注意跳转地址和自己的保持一致。 4.如果烧录程序卡住了报文信息也没有的话这个看起来像两个还没有建立正常的通信只是上位机和can盒正常建立了链接但是没有和dsp正常通信请把boot超市屏蔽了让他定时发送can报文然后链接上位机看上位机收到了不首先需要保证dsp和盒子是通的(操作正确设备正确的话是不会这样的) 5.boot需要用仿真器烧录到芯片以后就不用仿真器了用can更新代码 6.只要can的io一致就行了如果不同需要修改配置一、代码架构与文件组织本次分析的基于DSP28335的CAN升级方案代码集共包含83个文件核心代码集中在Flash28335APIV210Flash操作API、user用户业务逻辑和userlib外设驱动库三个目录。代码遵循模块化设计思想各文件功能边界清晰通过头文件引用形成完整的功能闭环。其中user目录下的main.c是程序入口串联起CAN通信、Flash操作、定时器中断等核心模块Flash28335APIV210目录提供TI官方Flash驱动API确保Flash擦写的稳定性userlib目录则封装了DSP28335的外设寄存器定义与基础驱动函数为上层业务提供硬件操作接口。二、核心代码文件逐句解析一Flash操作核心API配置文件Flash2833x_API_Config.h该文件是Flash API的配置入口通过宏定义指定目标芯片型号、CPU时钟频率等关键参数直接决定Flash操作的时序准确性。// 1. 目标芯片选择仅启用F28335禁用其他型号 #define FLASH_F28335 1 // 目标芯片为DSP28335 #define FLASH_F28334 0 // 禁用F28334 #define FLASH_F28332 0 // 禁用F28332作用Flash API需根据芯片型号适配不同的Flash存储结构如扇区数量、地址范围此处明确指定FLASH_F283351确保API调用与硬件匹配。若误用其他芯片配置会导致Flash操作地址错误甚至硬件损坏。// 2. CPU时钟频率配置单位nS #define CPU_RATE 6.667L // 对应150MHz CPU时钟SYSCLKOUT150MHz //#define CPU_RATE 10.000L // 禁用对应100MHz //#define CPU_RATE 13.330L // 禁用对应75MHz // ... 其他频率配置均禁用计算逻辑CPU时钟周期 1 / 时钟频率150MHz对应的时钟周期为1/150e6 ≈ 6.667e-9秒即6.667nS与CPU_RATE定义一致。该参数用于Flash API计算擦写时序如等待时间若配置错误会导致Flash擦写失败如擦除不彻底、写入数据错误。// 3. 固定缩放因子计算无需用户修改 #define SCALE_FACTOR 1048576.0L*( (200L/CPU_RATE) ) // IQ20格式作用SCALEFACTOR是Flash API内部使用的时序缩放因子基于CPURATE计算得出用于将API内部固定时序参数适配当前CPU频率确保不同时钟下Flash操作时序符合硬件要求。二CAN通信核心实现文件CANA.c该文件是CAN总线通信的核心包含GPIO配置、CAN控制器初始化、数据收发、中断处理等完整功能是Bootloader与上位机交互的关键通道。1. CAN GPIO配置函数CAN_GPIO_Configvoid CAN_GPIO_Config(CAN_Num CAN) { if (CAN CANA) { EALLOW; // 解锁受保护寄存器访问 // 使能GPIO30CANRXA和GPIO31CANTXA的内部上拉电阻 GpioCtrlRegs.GPAPUD.bit.GPIO30 0; GpioCtrlRegs.GPAPUD.bit.GPIO31 0; // 配置GPIO30为异步采样模式无需同步到SYSCLKOUT GpioCtrlRegs.GPAQSEL2.bit.GPIO30 3; // 配置GPIO30为CANRXA功能GPIO31为CANTXA功能 GpioCtrlRegs.GPAMUX2.bit.GPIO30 1; GpioCtrlRegs.GPAMUX2.bit.GPIO31 1; EDIS; // 锁定受保护寄存器 } // ... CANB配置本方案禁用代码略 }关键细节EALLOW/EDISDSP28335的部分寄存器如GPIO控制寄存器受保护需通过EALLOW解锁才能修改修改后用EDIS重新锁定防止误操作。上拉电阻GPAPUD.bit.GPIO300表示启用内部上拉避免CAN总线空闲时引脚电平不稳定导致通信误码。引脚复用GPAMUX2.bit.GPIO301将GPIO30从通用IO复用为CANRXA功能确保CAN信号正确接收。2. CAN控制器初始化函数CAN_Configvoid CAN_Config(CAN_Num CAN) { struct ECAN_REGS ECan_Reg_Shadow; // 寄存器影子结构避免直接操作硬件寄存器的竞态问题 volatile struct ECAN_REGS *ECanReg; volatile struct ECAN_MBOXES *ECanMboxe; if (CAN CANA) { EALLOW; // 使能eCAN-A模块时钟 SysCtrlRegs.PCLKCR0.bit.ECANAENCLK 1; EDIS; ECanReg ECanaRegs; // 指向eCAN-A控制寄存器组 ECanMboxe ECanaMboxes;// 指向eCAN-A邮箱寄存器组 } // ... CANB配置禁用代码略 EALLOW; // 配置CAN TX/RX引脚为CAN功能非GPIO功能 ECan_Reg_Shadow.CANTIOC.all ECanReg-CANTIOC.all; ECan_Reg_Shadow.CANTIOC.bit.TXFUNC 1; // TX引脚使能CAN功能 ECanReg-CANTIOC.all ECan_Reg_Shadow.CANTIOC.all; ECan_Reg_Shadow.CANRIOC.all ECanReg-CANRIOC.all; ECan_Reg_Shadow.CANRIOC.bit.RXFUNC 1; // RX引脚使能CAN功能 ECanReg-CANRIOC.all ECan_Reg_Shadow.CANRIOC.all; // 配置eCAN为HECC模式支持32个邮箱启用时间戳 ECan_Reg_Shadow.CANMC.all ECanReg-CANMC.all; ECan_Reg_Shadow.CANMC.bit.SCB 1; // SCB1启用HECC模式 ECanReg-CANMC.all ECan_Reg_Shadow.CANMC.all; // 初始化所有32个邮箱的MSGCTRL寄存器避免未知状态导致通信异常 ECanMboxe-MBOX0.MSGCTRL.all 0x00000000; ECanMboxe-MBOX1.MSGCTRL.all 0x00000000; // ... 省略MBOX2~MBOX30的初始化代码 ECanMboxe-MBOX31.MSGCTRL.all 0x00000000; // 清除发送确认、接收挂起、中断标志等状态位初始化状态 ECanReg-CANTA.all 0xFFFFFFFF; // 清除所有TX确认位 ECanReg-CANRMP.all 0xFFFFFFFF; // 清除所有RX挂起位 ECanReg-CANGIF0.all 0xFFFFFFFF;// 清除所有中断标志 ECanReg-CANGIF1.all 0xFFFFFFFF; // 配置CAN波特率500kbps ECan_Reg_Shadow.CANMC.all ECanReg-CANMC.all; ECan_Reg_Shadow.CANMC.bit.CCR 1; // CCR1进入配置模式 ECanReg-CANMC.all ECan_Reg_Shadow.CANMC.all; // 等待配置模式使能CCE1表示可修改波特率 do { ECan_Reg_Shadow.CANES.all ECanReg-CANES.all; } while (ECan_Reg_Shadow.CANES.bit.CCE ! 1); // 波特率参数配置基于150MHz CPU时钟 ECan_Reg_Shadow.CANBTC.all 0; #if (CPU_FRQ_150MHZ) ECan_Reg_Shadow.CANBTC.bit.BRPREG 9; // 波特率预分频器 ECan_Reg_Shadow.CANBTC.bit.TSEG2REG 2;// 时间段2长度213个TQ ECan_Reg_Shadow.CANBTC.bit.TSEG1REG 10;// 时间段1长度10111个TQ #endif ECan_Reg_Shadow.CANBTC.bit.SAM 1; // 采样模式三次采样提高抗干扰能力 ECanReg-CANBTC.all ECan_Reg_Shadow.CANBTC.all; // 退出配置模式 ECan_Reg_Shadow.CANMC.all ECanReg-CANMC.all; ECan_Reg_Shadow.CANMC.bit.CCR 0; // CCR0退出配置模式 ECanReg-CANMC.all ECan_Reg_Shadow.CANMC.all; // 等待配置模式退出CCE0 do { ECan_Reg_Shadow.CANES.all ECanReg-CANES.all; } while (ECan_Reg_Shadow.CANES.bit.CCE ! 0); // 禁用所有邮箱后续按需启用 ECanReg-CANME.all 0; EDIS; }波特率计算CAN总线波特率 CPU时钟 / [(BRPREG1)(TSEG1REG TSEG2REG 1)]。代入参数150e6 / [(91)(1021)] 150e6/(1013) ≈ 1.15MHz此处代码注释显示为500kbps推测实际工程中存在时钟分频如SYSCLKOUT经过2分频后为75MHz修正后计算为75e6/(1013)≈577kbps接近500kbps实际需结合硬件时钟树调整参数。影子寄存器使用ECAN_REGS结构体作为影子寄存器先读取硬件寄存器值修改后再写回避免直接操作硬件寄存器时的竞态问题如多线程/中断修改同一寄存器。3. CAN数据发送函数CAN_Tx_Msgint CAN_Tx_Msg(CanTxMsg *can_tx_msg) { Uint32 mbox_enable_temp 0x0000; // 邮箱使能掩码 Uint32 mbox_disable_temp 0x0000;// 邮箱禁用掩码 Uint32 mbox_dir_temp 0x0000; // 邮箱方向掩码TX/RX volatile struct ECAN_REGS ECan_Reg_Shadow; volatile struct ECAN_REGS *ECanReg; volatile struct MBOX *Mailbox; // 选择CAN模块和对应的邮箱 if(can_tx_msg-CAN_num CANA) { ECanReg ECanaRegs; Mailbox ECanaMboxes.MBOX0 can_tx_msg-MBox_num; } // ... CANB处理禁用代码略 else { return 0; } // 禁用目标邮箱修改ID前需禁用 ECan_Reg_Shadow.CANME.all ECanReg-CANME.all; ECan_Reg_Shadow.CANME.all mbox_disable_temp; ECanReg-CANME.all ECan_Reg_Shadow.CANME.all; // 配置邮箱ID标准帧/扩展帧 if(can_tx_msg-IDE CAN_ID_STD) { Mailbox-MSGID.all can_tx_msg-StdId.bit.StdId; Mailbox-MSGID.bit.IDE can_tx_msg-IDE; // IDE0表示标准帧 } else if(can_tx_msg-IDE CAN_ID_EXT) { if(can_tx_msg-SAE_J1939_Flag 0) { Mailbox-MSGID.all can_tx_msg-ExtId.bit.ExtId; Mailbox-MSGID.bit.IDE can_tx_msg-IDE; // IDE1表示扩展帧 } // ... SAE_J1939协议处理禁用代码略 } // 配置邮箱为发送模式MD0表示TXMD1表示RX ECan_Reg_Shadow.CANMD.all ECanReg-CANMD.all; ECan_Reg_Shadow.CANMD.all mbox_dir_temp; ECanReg-CANMD.all ECan_Reg_Shadow.CANMD.all; // 使能邮箱 ECan_Reg_Shadow.CANME.all ECanReg-CANME.all; ECan_Reg_Shadow.CANME.all | mbox_enable_temp; ECanReg-CANME.all ECan_Reg_Shadow.CANME.all; // 配置数据长度和数据内容 Mailbox-MSGCTRL.bit.DLC can_tx_msg-DLC; // 数据长度0~8 Mailbox-MDL.byte.BYTE0 can_tx_msg-CAN_Tx_msg_data.msg_Byte.byte0; Mailbox-MDL.byte.BYTE1 can_tx_msg-CAN_Tx_msg_data.msg_Byte.byte1; Mailbox-MDL.byte.BYTE2 can_tx_msg-CAN_Tx_msg_data.msg_Byte.byte2; Mailbox-MDL.byte.BYTE3 can_tx_msg-CAN_Tx_msg_data.msg_Byte.byte3; Mailbox-MDH.byte.BYTE4 can_tx_msg-CAN_Tx_msg_data.msg_Byte.byte4; Mailbox-MDH.byte.BYTE5 can_tx_msg-CAN_Tx_msg_data.msg_Byte.byte5; Mailbox-MDH.byte.BYTE6 can_tx_msg-CAN_Tx_msg_data.msg_Byte.byte6; Mailbox-MDH.byte.BYTE7 can_tx_msg-CAN_Tx_msg_data.msg_Byte.byte7; // 请求发送TRS位置1 ECan_Reg_Shadow.CANTRS.all 0; ECan_Reg_Shadow.CANTRS.all | mbox_enable_temp; ECanReg-CANTRS.all ECan_Reg_Shadow.CANTRS.all; // 等待发送完成TA位置1表示发送成功 do { ECan_Reg_Shadow.CANTA.all ECanReg-CANTA.all; uint16RecCnt; if(uint16RecCnt TIMEOUTCNT) // TIMEOUTCNT3超时次数 { return -1; // 发送超时返回错误 } } while(((ECan_Reg_Shadow.CANTA.allmbox_enable_temp) 0 )); // 清除发送确认标志TA位置1 ECan_Reg_Shadow.CANTA.all 0; ECan_Reg_Shadow.CANTA.all mbox_enable_temp; ECanReg-CANTA.all ECan_Reg_Shadow.CANTA.all; return 1; // 发送成功 }关键流程1. 禁用邮箱修改邮箱ID前必须禁用邮箱CANME寄存器对应位清0否则修改无效。2. ID配置根据IDE字段区分标准帧11位ID和扩展帧29位ID将ID写入MSGID寄存器。3. 发送请求通过CANTRS寄存器的对应位置1请求发送数据。4. 发送确认等待CANTA寄存器对应位置1表示发送完成超时则返回错误确保通信可靠性。4. CAN接收中断服务函数Ecana_isr1__interrupt void Ecana_isr1(void) { if(ECanaRegs.CANGIF1.bit.GMIF1 1) // 全局邮箱中断标志有消息接收/发送 { if(ECanaRegs.CANRMP.bit.RMP31 1) // 邮箱31接收挂起RMP1表示有新数据 { can_rx_msg.rx_update UPDATE; // 接收标志置1通知主程序处理 // 读取接收邮箱编号、数据长度、帧类型 can_rx_msg.MBox_num ECanaRegs.CANGIF1.bit.MIV1; can_rx_msg.DLC ECanaMboxes.MBOX31.MSGCTRL.bit.DLC; can_rx_msg.IDE ECanaMboxes.MBOX31.MSGID.bit.IDE; // 读取ID扩展帧/标准帧 if(can_rx_msg.IDE CAN_ID_EXT) { can_rx_msg.ExtId ECanaMboxes.MBOX31.MSGID.all0x1FFFFFFF; can_rx_msg.SAE_J1939_ID.id can_rx_msg.ExtId; } else if(can_rx_msg.IDE CAN_ID_STD) { can_rx_msg.StdId ECanaMboxes.MBOX31.MSGID.bit.STDMSGID; } // 读取接收数据8字节 can_rx_msg.CAN_Rx_msg_data.msg_Byte.byte0 ECanaMboxes.MBOX31.MDL.byte.BYTE0; can_rx_msg.CAN_Rx_msg_data.msg_Byte.byte1 ECanaMboxes.MBOX31.MDL.byte.BYTE1; can_rx_msg.CAN_Rx_msg_data.msg_Byte.byte2 ECanaMboxes.MBOX31.MDL.byte.BYTE2; can_rx_msg.CAN_Rx_msg_data.msg_Byte.byte3 ECanaMboxes.MBOX31.MDL.byte.BYTE3; can_rx_msg.CAN_Rx_msg_data.msg_Byte.byte4 ECanaMboxes.MBOX31.MDH.byte.BYTE4; can_rx_msg.CAN_Rx_msg_data.msg_Byte.byte5 ECanaMboxes.MBOX31.MDH.byte.BYTE5; can_rx_msg.CAN_Rx_msg_data.msg_Byte.byte6 ECanaMboxes.MBOX31.MDH.byte.BYTE6; can_rx_msg.CAN_Rx_msg_data.msg_Byte.byte7 ECanaMboxes.MBOX31.MDH.byte.BYTE7; // 清除接收挂起标志RMP位置1清除 ECanaRegs.CANRMP.bit.RMP31 1; } } // 确认PIE中断允许下次中断 PieCtrlRegs.PIEACK.bit.ACK9 1; }中断触发条件当邮箱31接收到数据时CANRMP.bit.RMP31置1触发ECANA1INTA中断映射到PIE组9。数据处理中断服务函数读取邮箱31的ID、数据长度、数据内容存储到全局变量canrxmsg并设置rx_updateUPDATE主程序通过检测该标志获取新数据。中断确认PieCtrlRegs.PIEACK.bit.ACK91确认PIE组9的中断允许PIE控制器再次向CPU发送中断请求避免中断丢失。三主程序入口文件main.c该文件是Bootloader的控制核心负责初始化所有模块、处理升级流程、超时跳转等逻辑是整个系统的“大脑”。1. 全局变量定义FLASH_ST FlashStatus; // Flash操作状态结构体 FLASH_ST ProgramStatus; // 编程状态结构体 FLASH_ST VerifyStatus; // 校验状态结构体 bootloader_data Boot_ID_info; // 升级命令ID信息 typedef void (*pFunction)(void); // 函数指针类型用于APP跳转 Uint32 MyCallbackCounter; // 回调函数计数器未使用 void MyCallbackFunction(void); // 回调函数未使用 Uint16 Status 0; // 操作状态码 Uint16 *Flash_ptr; // Flash目标地址指针 Uint32 Length 0; // 数据长度16位数据个数 Uint16 *source_ptr; // 源数据指针 Uint16 Data_Cnt 0; // 数据计数器 unsigned char DATABUF[19000]; // 固件数据缓冲区最大37KB Uint16 write_temp[DATA_PACK_SIZE/2]; // 临时写入缓冲区 u32 start_addr 0x0000; // 数据起始地址 u32 data_size0; // 数据大小 u32 data_index0; // 数据缓冲区索引 u32 data_index20; // 备用索引关键变量DATABUF用于存储上位机下发的固件数据大小19000字节约18.5KB实际可根据固件大小调整。pFunction函数指针类型用于将APP起始地址转换为函数指针实现跳转到APP运行。2. 主函数mainint main(void) { u8 i 0; __disable_irq(); // 禁用全局中断初始化阶段避免中断干扰 // 1. 系统初始化 InitSysCtrl(); // 初始化系统控制时钟、电源模式等 CAN_GPIO_Config(CANA); // 配置CAN GPIO LED_GPIO_Config(); // 配置LED指示灯 CsmUnlock(); // 解锁代码安全模块允许访问Flash InitPieCtrl(); // 初始化PIE控制器 IER 0x0000; // 禁用CPU中断 IFR 0x0000; // 清除CPU中断标志 InitPieVectTable(); // 初始化PIE向量表 // 2. 重映射中断向量将中断服务函数注册到PIE向量表 EALLOW; PieVectTable.TINT0 cpu_timer0_isr; // Timer0中断映射 PieVectTable.ECAN1INTA Ecana_isr1; // CAN接收中断映射 EDIS; // 3. 复制代码到SARAM运行Flash API和Ramfuncs需在RAM中运行 MemCopy(RamfuncsLoadStart, RamfuncsLoadEnd, RamfuncsRunStart); MemCopy(Flash28_API_LoadStart, Flash28_API_LoadEnd,Flash28_API_RunStart); // 4. 初始化Flash和CAN模块 InitFlash(); // 初始化Flash控制寄存器 FlashAPI_Init(); // 初始化Flash API CAN_Config(CANA); // 初始化CAN控制器 CAN_Rx_Config(); // 配置CAN接收邮箱 CAN_Rx_IT_Concig(); // 配置CAN接收中断 CAN_Tx_Init(); // 初始化CAN发送参数 // 5. 清空数据缓冲区 for(i0; i19000; i) { DATABUF[i] 0x0; } // 6. 配置定时器Timer0100ms中断用于超时计时 Timer0_Config(); // 7. 使能中断 PieCtrlRegs.PIEIER1.bit.INTx7 1; // 使能Timer0中断PIE组1INTx7 PieCtrlRegs.PIEIER9.bit.INTx6 1; // 使能CAN接收中断PIE组9INTx6 IER | M_INT9; // 使能CPU中断组9 IER | M_INT1; // 使能CPU中断组1 __enable_irq(); // 使能全局中断 // 8. 主循环 while (1) { // 8.1 每1秒向上位机发送心跳包上电后发送3、2、1 if(updata_info.time_1s 1) { updata_info.time_1s 0; if(updata_info.time_1s_cnt0) { can_tx_msg.CAN_Tx_msg_data.msg_byte.data[0] (updata_info.time_1s_cnt)0xFF; CAN_Tx_Msg(can_tx_msg); updata_info.time_1s_cnt--; } } // 8.2 超时处理3秒未接收数据跳转至APP if(updata_info.time_out_flag 0) { // 8.3 接收数据处理接收到新数据 if(can_rx_msg.rx_update UPDATE) { // 停止定时器接收数据后重置超时计时 if(CpuTimer0Regs.TCR.bit.TSS 0) { CpuTimer0Regs.TCR.bit.TSS 1; } updata_info.time_out_flag 0; // 重置超时标志 can_rx_msg.rx_update NON_CHANGE; // 清除接收标志 CAN_BOOT_ExecutiveCommand(can_rx_msg); // 处理升级命令 } } else // 超时跳转至APP { __disable_irq(); // 禁用中断避免跳转过程中被打断 CAN_BOOT_JumpToApplication(APP_START_ADDR); } } }关键初始化步骤MemCopy将Ramfuncs和Flash28_API段的代码从Flash复制到SARAM运行。因为Flash擦写时无法同时读取若API代码在Flash中会导致擦写过程中代码无法执行因此必须复制到RAM。CsmUnlockDSP28335的代码安全模块CSM默认锁定FlashCsmUnlock解锁后才能进行Flash擦写操作。中断映射通过PieVectTable将中断服务函数如cputimer0isr注册到对应的中断向量位置确保中断触发时能正确执行服务函数。3. 升级命令处理函数CAN_BOOT_ExecutiveCommand#pragma CODE_SECTION(CAN_BOOT_ExecutiveCommand,ramfuncs); // 指定函数在RAM中运行 void CAN_BOOT_ExecutiveCommand(CanRxMsg *pRxMessage) { u8 i; u8 can_cmd 0x00; // 命令码bit0~bit3 u16 can_addr 0x00; // 设备地址bit4~bit15 CanTxMsg TxMessage; // 发送消息结构体 // 初始化发送消息参数 TxMessage.CAN_num CANA; TxMessage.DLC 1; TxMessage.ExtId.bit.resved 0x00; TxMessage.IDE CAN_ID_EXT; TxMessage.MBox_num 0x02; TxMessage.Tx_timeout_cnt 0x00; TxMessage.SAE_J1939_Flag 0; // 从接收消息ID中提取命令码和设备地址 Boot_ID_info.ExtId.all pRxMessage-ExtId; can_cmd Boot_ID_info.ExtId.bit.cmd; can_addr Boot_ID_info.ExtId.bit.addr; // 翻转LED指示接收数据 GpioDataRegs.GPATOGGLE.bit.GPIO21 1; // 地址匹配检查仅处理本设备或广播地址 if((can_addr!CAN_BOOT_GetAddrData())(can_addr!0)) { // 地址不匹配返回失败 TxMessage.ExtId.bit.ExtId (0x0134CMD_WIDTH)|cmd_list.CmdFaild; TxMessage.DLC 8; // 填充失败数据全1 for(i0;i8;i) TxMessage.CAN_Tx_msg_data.msg_byte.data[i] 0x01; CAN_Tx_Msg(TxMessage); return; } // 处理Write命令接收固件数据 if(can_cmd cmd_list.Write) // cmd_list.Write0x02 { __disable_irq(); // 禁用中断避免数据存储被打断 // 将接收的数据存入缓冲区 for(i0;ipRxMessage-DLC;i) { DATABUF[data_index] pRxMessage-CAN_Rx_msg_data.msg_byte.data[i]; } __enable_irq(); // 重新使能中断 } // 处理Check命令执行Flash擦写与校验 if(can_cmd cmd_list.Check) // cmd_list.Check0x03 { // 数据格式转换字节转16位 for(data_index20;data_index2data_index;data_index2 2) { DATABUF[(data_index2)/2] DATABUF[data_index2]; DATABUF[(data_index2)/2] |(DATABUF[data_index21])8 ; } __disable_irq(); // 初始化Flash API回调函数 Flash_CPUScaleFactor SCALE_FACTOR; Flash_CallbackPtr MyCallbackFunction; MyCallbackCounter 0; Example_CallFlashAPI(); // 执行Flash擦写与数据写入 // 发送升级完成通知数据0x05 TxMessage.ExtId.bit.ExtId (0x0134CMD_WIDTH)|cmd_list.CmdFaild; TxMessage.DLC 1; TxMessage.CAN_Tx_msg_data.msg_byte.data[0] 0x05; CAN_Tx_Msg(TxMessage); // 跳转至APP CAN_BOOT_JumpToApplication(APP_START_ADDR); } }命令码定义通过cmd_list结构体定义升级命令如Write0x02接收数据、Check0x03执行升级、CmdFaild0x09命令失败。数据转换上位机下发的固件数据为字节流需转换为16位数据DSP28335为16位处理器Flash按16位字写入因此通过循环将两个字节合并为一个16位数据。中断控制数据存储和Flash操作过程中禁用中断避免中断干扰导致数据错误或Flash操作异常。4. Flash操作实现函数Example_CallFlashAPI#pragma CODE_SECTION(Example_CallFlashAPI,ramfuncs); void Example_CallFlashAPI(void) { float32 Version; // Flash API版本浮点型 Uint16 VersionHex; // Flash API版本十六进制 unsigned long int des_addr; // Flash目标地址 // 校验Flash API版本必须为2.10版本 VersionHex Flash_APIVersionHex(); if(VersionHex ! 0x0210) { asm( ESTOP0); // 版本不匹配暂停调试 } Version Flash_APIVersion(); if(Version ! (float32)2.10) { asm( ESTOP0); } // 发送擦除开始通知数据0x02 can_tx_msg.DLC 1; can_tx_msg.ExtId.bit.ExtId (0x0134CMD_WIDTH)|cmd_list.CmdFaild; can_tx_msg.CAN_Tx_msg_data.msg_byte.data[0] 0x02; CAN_Tx_Msg(can_tx_msg); // 擦除目标扇区SECTORC~SECTORH保留Bootloader所在扇区 Status Flash_Erase((SECTORC|SECTORD|SECTORE|SECTORF|SECTORG|SECTORH),FlashStatus); if(Status ! STATUS_SUCCESS) { Example_Error(Status); // 擦除失败报错 } // 发送擦除完成通知数据0x03 can_tx_msg.DLC 1; can_tx_msg.ExtId.bit.ExtId (0x0134CMD_WIDTH)|cmd_list.CmdFaild; can_tx_msg.CAN_Tx_msg_data.msg_byte.data[0] 0x03; CAN_Tx_Msg(can_tx_msg); // 解析bin文件逐段写入Flash Data_Cnt 11; // bin文件第11字节开始为数据长度需根据实际bin格式调整 while(DATABUF[Data_Cnt]!0) // 数据长度不为0时继续 { Length DATABUF[Data_Cnt]; // 读取数据长度16位数据个数 Data_Cnt ; // 读取目标地址32位高位补0 des_addr (DATABUF[Data_Cnt]) 8; des_addr des_addr 8; Data_Cnt ; des_addr | DATABUF[Data_Cnt]; Flash_ptr (Uint16 *)des_addr; // 转换为Flash地址指针 Data_Cnt ; // 跳过密码地址避免误写导致设备锁死 if((Flash_ptr!(Uint16 *)0x33FF80)(Flash_ptr!(Uint16 *)0x33FFF8)) { source_ptr(Uint16*)(DATABUF Data_Cnt); // 源数据指针 // 写入数据到Flash Status Flash_Program(Flash_ptr, source_ptr, Length, ProgramStatus); if(Status ! STATUS_SUCCESS) { Example_Error(Status); } // 校验写入的数据 Status Flash_Verify(Flash_ptr,source_ptr,Length,VerifyStatus); if(Status ! STATUS_SUCCESS) { Example_Error(Status); } Data_Cnt Data_Cnt Length; // 更新数据计数器 } else { Data_Cnt Data_Cnt Length; // 跳过密码地址数据 } } }扇区擦除Flash_Erase函数擦除SECTORC~SECTORH保留SECTORA~SECTORBBootloader所在扇区避免升级过程中Bootloader被擦除导致设备变砖。bin文件解析假设bin文件格式为“数据长度目标地址数据内容”Data_Cnt11表示从第11字节开始解析需根据实际上位机生成的bin格式调整。密码地址保护0x33FF80和0x33FFF8是DSP28335的CSM密码地址误写会导致设备锁死因此跳过这些地址的写入。5. APP跳转函数CAN_BOOT_JumpToApplicationvoid CAN_BOOT_JumpToApplication(uint32_t Addr) { pFunction jump; jump (pFunction)(Addr); // 将APP起始地址转换为函数指针 jump(); // 执行函数指针跳转至APP }跳转原理DSP28335的Flash中程序入口地址存储在复位向量表0x3FFFC0APP程序编译时会将入口地址写入该位置。但Bootloader跳转时直接将APP起始地址APPSTARTADDR0x327FF0转换为函数指针并执行即可跳转到APP的main函数。注意事项APP的起始地址必须与Bootloader的扇区配置匹配且APP编译时需指定正确的链接地址避免与Bootloader重叠。三、代码设计亮点与注意事项一设计亮点模块化架构将CAN通信、Flash操作、定时器控制等功能拆分到不同文件代码结构清晰便于维护与扩展。可靠性设计- 双重校验Flash写入后执行Flash_Verify校验确保数据完整性。- 超时保护CAN发送超时、升级流程超时均设置保护避免程序卡死。- 中断隔离关键操作如数据存储、Flash擦写时禁用中断避免干扰。安全性设计- 地址保护跳过CSM密码地址写入防止设备锁死。- 地址匹配仅处理目标地址为本设备的命令避免误操作。可移植性通过宏定义如CPURATE、FLASHF28335适配不同硬件配置修改少量参数即可移植到其他DSP2833x系列芯片。二注意事项Flash API版本代码强制要求Flash API版本为2.10VersionHex0x0210若使用其他版本需修改版本校验逻辑否则会触发ESTOP0暂停。CAN波特率匹配上位机与设备的CAN波特率必须一致本方案为500kbps否则无法通信。APP地址配置APPSTARTADDR0x327FF0需与APP的链接脚本配置一致若APP地址错误跳转后会执行无效代码。数据缓冲区大小DATABUF大小为19000字节若固件超过此大小需扩大缓冲区否则会导致数据溢出。中断优先级本方案未配置中断优先级若扩展其他中断如SPI、SCI需通过PIEIER寄存器配置优先级避免中断冲突。四、总结本基于DSP28335的CAN Bootloader升级方案通过模块化的代码设计、严格的时序控制、完善的可靠性保护实现了固件的远程升级功能。核心代码围绕CAN通信与Flash操作展开通过中断处理确保数据实时接收通过版本校验、地址保护、超时控制确保升级过程稳定可靠。该方案可广泛应用于工业控制、汽车电子等需要远程维护的场景只需根据实际需求调整CAN协议、Flash扇区配置、固件缓冲区大小等参数即可快速适配不同应用场景。基于dsp28335的can升级方案 bootloader、上位机等全部自主开发 文件说明 1、setup为上位机安装文件 2、V5为dsp28335的BootLoader源代码我用的CCS10.3.1 3、WindowsApplication3为VS平台的上位机源代码,我用的VS2013 4、app.bin为测试用的app烧录固件。 5、F28335_FLASH_COM_V1为app代码参考的cmd文件。 使用ZLG的USBCAN-II。如果是别家的盒子看他是否给了兼容周力功的方法按照那个方法操作上位机就可以 操作流程 1、先连接好CAN盒和DSP不上电打开上位机默认的设置不要修改任何选项。 2、点击“连接”再点击“启动”。 3、打开目标bin文件。 4、DSP上电3S内电机“更新固件”。 5、等待完成烧录程序自动跳转到APP中。 注意 1、如果DSP上电后3秒内未收到ID0x00001342发来的数据则自动跳转到APP中 2、如果上位机已经打开了app.bin文件烧录过程中失败了需要重启上位机。 3、自己用时需要注意跳转地址和自己的保持一致。 4.如果烧录程序卡住了报文信息也没有的话这个看起来像两个还没有建立正常的通信只是上位机和can盒正常建立了链接但是没有和dsp正常通信请把boot超市屏蔽了让他定时发送can报文然后链接上位机看上位机收到了不首先需要保证dsp和盒子是通的(操作正确设备正确的话是不会这样的) 5.boot需要用仿真器烧录到芯片以后就不用仿真器了用can更新代码 6.只要can的io一致就行了如果不同需要修改配置

相关文章:

基于DSP28335的CAN升级方案:自主开发的BootLoader与上位机完全支持

基于dsp28335的can升级方案 bootloader、上位机等全部自主开发 文件说明: 1、setup为上位机安装文件; 2、V5为dsp28335的BootLoader源代码,我用的CCS10.3.1; 3、WindowsApplication3为VS平台的上位机源代码,我用的VS2013&#xff…...

3步解决Android验证修复难题:PlayIntegrityFix实战指南

3步解决Android验证修复难题:PlayIntegrityFix实战指南 【免费下载链接】PlayIntegrityFix Fix Play Integrity (and SafetyNet) verdicts. 项目地址: https://gitcode.com/GitHub_Trending/pl/PlayIntegrityFix 当你在使用Android设备时,是否遇到…...

探索无桥PFC与逆变方案:从原理到实现

无桥PFC和逆变方案(原理图pdfPCBstm源码两份仿真等文件) 1.输入电压AC220V,50Hz交流电 2.PFC输出390V,150KHz开关频率 3.PFC输出最大功率400瓦,输入电流最大2A,最小负载电流0.1A 输出功率越大PF值越高,电流…...

3步搞定黑苹果配置:让OpenCore管理变得轻松

3步搞定黑苹果配置:让OpenCore管理变得轻松 【免费下载链接】OCAuxiliaryTools Cross-platform GUI management tools for OpenCore(OCAT) 项目地址: https://gitcode.com/gh_mirrors/oc/OCAuxiliaryTools 你是否曾经因为复杂的OpenCo…...

HSTracker全能助手:炉石传说数据追踪与套牌管理实战指南

HSTracker全能助手:炉石传说数据追踪与套牌管理实战指南 【免费下载链接】HSTracker A deck tracker and deck manager for Hearthstone on macOS 项目地址: https://gitcode.com/gh_mirrors/hs/HSTracker 副标题:从新手到大师的macOS炉石辅助工具…...

Downkyi视频下载工具技术解析与架构指南

Downkyi视频下载工具技术解析与架构指南 【免费下载链接】downkyi 哔哩下载姬downkyi,哔哩哔哩网站视频下载工具,支持批量下载,支持8K、HDR、杜比视界,提供工具箱(音视频提取、去水印等)。 项目地址: htt…...

3步实现百度网盘链接解析:Baiduwp-PHP工具全功能实践指南

3步实现百度网盘链接解析:Baiduwp-PHP工具全功能实践指南 【免费下载链接】baiduwp-php A tool to get the download link of the Baidu netdisk / 一个获取百度网盘分享链接下载地址的工具 项目地址: https://gitcode.com/gh_mirrors/ba/baiduwp-php Baiduw…...

别再手动算脉冲了!用STM32的TIM编码器接口实现AB相编码器测速(附四倍频配置)

STM32硬件编码器接口实战:四倍频测速与电机控制优化 在嵌入式运动控制系统中,编码器测速的精度和实时性直接影响整个系统的性能表现。传统的中断计数方式虽然直观,但存在CPU占用率高、响应延迟等问题。而STM32系列微控制器内置的硬件编码器接…...

Snap.Hutao:如何用这款开源工具箱优化你的原神游戏体验?

Snap.Hutao:如何用这款开源工具箱优化你的原神游戏体验? 【免费下载链接】Snap.Hutao 实用的开源多功能原神工具箱 🧰 / Multifunctional Open-Source Genshin Impact Toolkit 🧰 项目地址: https://gitcode.com/GitHub_Trendin…...

Koikatu HF Patch终极安装指南:5步解锁游戏全部潜力

Koikatu HF Patch终极安装指南:5步解锁游戏全部潜力 【免费下载链接】KK-HF_Patch Automatically translate, uncensor and update Koikatu! and Koikatsu Party! 项目地址: https://gitcode.com/gh_mirrors/kk/KK-HF_Patch 还在为Koikatu游戏体验不完整而烦…...

别只调AE了!Sensor调试中那些容易被忽略的‘暗坑’:电源噪声、镜头匹配与Raw图分析实战

别只调AE了!Sensor调试中那些容易被忽略的‘暗坑’:电源噪声、镜头匹配与Raw图分析实战 当工程师们成功点亮一颗新的图像传感器(Sensor)并完成基础AE配置后,往往容易陷入一种"能出图即达标"的思维定式。然而…...

YimMenu:守护GTA V体验的安全增强工具

YimMenu:守护GTA V体验的安全增强工具 【免费下载链接】YimMenu YimMenu, a GTA V menu protecting against a wide ranges of the public crashes and improving the overall experience. 项目地址: https://gitcode.com/GitHub_Trending/yi/YimMenu 一、价…...

KMP算法:高效字符串匹配秘诀

一、先解答上次的思考题问:BF 算法为什么慢?答:每次匹配失败,主串 i 要回退、模式串 j 要归零,大量重复比较,浪费时间。二、今天学习目标理解 KMP 核心:不回退主串 i理解 next 数组(…...

Flowframes:5步掌握开源AI视频插帧技巧,轻松提升视频流畅度

Flowframes:5步掌握开源AI视频插帧技巧,轻松提升视频流畅度 【免费下载链接】flowframes Flowframes Windows GUI for video interpolation using DAIN (NCNN) or RIFE (CUDA/NCNN) 项目地址: https://gitcode.com/gh_mirrors/fl/flowframes 你是…...

SwitchCase语句详解:从基础到实战

一、switch case 是什么?switch case 是多条件分支语句,专门用来判断固定值的场景。比如:根据分数等级 A/B/C/D 输出评价根据菜单数字 1/2/3/4 执行不同功能根据星期 1~7 做不同处理特点:只能判断整型、字符型(不能判断…...

解放知识资产:dedao-dl让你的得到课程永久保存成为可能

解放知识资产:dedao-dl让你的得到课程永久保存成为可能 【免费下载链接】dedao-dl 得到 APP 课程下载工具,可在终端查看文章内容,可生成 PDF,音频文件,markdown 文稿,可下载电子书。 项目地址: https://g…...

想自己动手做个四足机器人?这份从电机选型到步态控制的保姆级入门指南请收好

从零搭建四足机器人:硬件选型与步态控制实战手册 当你第一次看到波士顿动力的Spot机器人完成后空翻,或是MIT Mini Cheetah在草地上灵活奔跑时,是否也萌生过自己打造一台四足机器的念头?四足机器人正从实验室走向创客空间&#xff…...

SMUDebugTool技术突破:硬件级调试能力解决工程师的系统优化痛点

SMUDebugTool技术突破:硬件级调试能力解决工程师的系统优化痛点 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: h…...

V-rep中机械臂模型的动力学特性设置与运动控制

1. V-rep机械臂动力学基础配置 第一次在V-rep里摆弄机械臂时,我被那些飘在半空的零件惊呆了——它们就像被施了魔法一样完全无视重力。后来才发现,要让机械臂"活过来",关键在于正确设置动力学特性。这个过程就像给机器人注入灵魂&a…...

从Simulink仿真到Altium Designer画板:一个直流电机调速系统的完整诞生记

从算法仿真到电路实现:直流电机双闭环调速系统全流程实战 在实验室里调试电机控制系统时,最令人兴奋的时刻莫过于看到仿真曲线和实际示波器波形完美吻合的瞬间。作为电子工程师,我们每天都在与这种"虚实结合"的挑战打交道——如何在…...

5个效率倍增方法:Kazumi播放器无缝访问与快速启动指南

5个效率倍增方法:Kazumi播放器无缝访问与快速启动指南 【免费下载链接】Kazumi 基于自定义规则的番剧采集APP,支持流媒体在线观看,支持弹幕,支持实时超分辨率。 项目地址: https://gitcode.com/gh_mirrors/ka/Kazumi 你是否…...

智鼎MAP性格测试避坑指南:如何避免‘人设崩塌’拿到高分?

智鼎MAP性格测试避坑指南:如何避免‘人设崩塌’拿到高分? 在求职过程中,性格测试往往是最容易被忽视却又至关重要的环节。智鼎MAP职业性格测试不同于传统的知识考核,它更像一面照妖镜,能够通过精心设计的题目组合&…...

全介质超构透镜模型实现偏振成像:实时分离聚焦与偏振信息解码

偏振成像 超构透镜模型 超表面 FDTD仿真 复现论文:2019年 APL Midinfrared real-time polarization imaging with all-dielectric metasurfaces 论文介绍:全介质实时偏振聚焦成像超构透镜模型,可以实现X Y RCP LCP四个偏振态的实时分离和聚焦…...

加密货币自动化交易实战指南:从策略设计到收益优化全流程

加密货币自动化交易实战指南:从策略设计到收益优化全流程 【免费下载链接】binance-trade-bot Automated cryptocurrency trading bot 项目地址: https://gitcode.com/gh_mirrors/bi/binance-trade-bot 在加密货币交易领域,自动化策略是提升效率与…...

无需联网!LongCat动物百变秀本地部署指南,动物图片编辑随心所欲

无需联网!LongCat动物百变秀本地部署指南,动物图片编辑随心所欲 1. 为什么选择本地部署的动物图片编辑器? 在数字内容创作领域,动物图片编辑一直是个特殊需求。无论是宠物博主需要制作创意内容,还是动物保护组织要制…...

YimMenu终极指南:GTA5增强工具完整使用教程

YimMenu终极指南:GTA5增强工具完整使用教程 【免费下载链接】YimMenu YimMenu, a GTA V menu protecting against a wide ranges of the public crashes and improving the overall experience. 项目地址: https://gitcode.com/GitHub_Trending/yi/YimMenu Y…...

终极指南:如何用ComfyUI-MimicMotionWrapper实现AI动作迁移

终极指南:如何用ComfyUI-MimicMotionWrapper实现AI动作迁移 【免费下载链接】ComfyUI-MimicMotionWrapper 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-MimicMotionWrapper ComfyUI-MimicMotionWrapper是一款强大的AI动作迁移插件,让任…...

多模型协作测试:OpenClaw同时调用Qwen3-32B与其他轻量镜像

多模型协作测试:OpenClaw同时调用Qwen3-32B与其他轻量镜像 1. 混合模型工作流的设计初衷 去年冬天的一个深夜,我正在调试一个需要同时处理代码生成和文本摘要的自动化任务。当时我的OpenClaw配置只能串行调用单一模型,每次任务切换都需要重…...

百考通:AI赋能实践报告,让研究更顺畅

对于每一位在校学生和职场新人而言,实践报告都是记录成长、沉淀经验的关键载体,却也常常成为令人头疼的难题:要么不知如何梳理工作脉络,要么难以精准提炼收获与反思,要么在格式规范和字数要求上反复纠结。百考通&#…...

Microsoft Agent Framework 1.0 正式发布:.NET AI Agent 开发正式从 Demo 走向工程化。每一位.NET 开发者都必须关注的重大更新。

Microsoft Agent Framework 1.0 正式发布:Agent Skills 补齐后,Agent 开发真正进入工程化时代如果你最近在关注微软的 AI Agent 技术栈,这次发布值得认真看。Microsoft Agent Framework .NET 1.0.0 正式上线。这不是一次普通的版本升级&#…...