基于CAN总线的车载应用Bootloader设计
- 格式:pdf
- 大小:4.10 MB
- 文档页数:5
一种用于汽车电控单元CAN Bootloader的设计与实现陈彤;黄立梅【摘要】传统汽车电控单元对程序的烧写一般采用BDM调试接口实现,该方法不仅影响电控单元应用程序的开发效率,而且会给汽车电控单元后期的升级维护带来不便.使用嵌入式启动引导程序(即Bootloader),能够较好的解决上述问题.本文设计并实现了一种应用于汽车电控单元的基于CAN通信的Bootloader.通过实际应用和测试,结果表明该Bootloader能够正确引导程序运行,准确、方便地为控制器下载应用程序.【期刊名称】《汽车实用技术》【年(卷),期】2016(000)009【总页数】5页(P156-160)【关键词】汽车电控单元;Bootloader;CAN总线;Labview【作者】陈彤;黄立梅【作者单位】陕西法士特汽车传动工程研究院,陕西西安 710119;陕西法士特汽车传动工程研究院,陕西西安 710119【正文语种】中文【中图分类】U463.6110.16638/ki.1671-7988.2016.09.055CLC NO.: U463.61 Document Code: A Article ID: 1671-7988 (2016)09-156-05在汽车电控单元的开发过程中需要频繁地进行程序烧写工作,传统的烧写方式一般是利用芯片专用下载器通过BDM调试接口下载程序,该方式的下载速度较慢,而且在汽车电控单元的后期维护中,如果需要升级应用程序,就需要从整车上将电控单元拆卸下来,为电控单元的维护和调试带来极大的不便。
对于已经投入使用的汽车电控单元来说,急需一种方便快捷的程序升级方法,从而提高维护人员的工作效率。
Bootloader作为应用程序运行之前的一段程序,主要完成应用程序的启动引导和更新,而CAN总线通信在汽车电子领域的广泛应用,使得Bootloader可以直接通过CAN总线进行程序升级。
本文设计并实现了一种基于CAN总线的Bootloader,通过自定义的数据传输协议与上位机进行通信并完成程序下载。
基于CANoe的ECUBootloader刷写软件⽬标:车辆ECU需要更新软件,通过OBD⼝实现,通过CAN总线实现,编程语⾔是CAPL。
刷写流程基于ISO15765-3;应⽤层基于UDS(ISO14229)诊断协议;TP层基于ISO15765-2;数据链路层和物理层基于ISO11898实现:1.图形⽤户界⾯使⽤CANoe⾃带的panel来实现,⽤户可以选取刷写⽂件,ECU的地址等信息,这些信息通过环境变量被程序访问,环境变量在CANDB++中编辑⽣成。
2.软件架构:刷写⼯具解析s19 app,如果没有s19 app,那么可以使⽤HexView将HEX,BIN等app转成s19⽂件依据ISO15765-3编写刷写流程代码,将app数据扔给应⽤层应⽤层是基于UDS编写的,应⽤层在将数据扔给TP层TP层将数据扔给数据链路层数据链路层将数据扔给物理层,数据通过CAN总线被ECU接收代码:⼯作保密原因,只贴出UDS层的代码,秘钥也删了[cpp] view plain copy print?1. includes{2.3. }4.5. variables{6. char gECU[7]="Tester";7.8. int useExtendedId=0; //use standard Id9. long useFC=1; //use flow control10. long bs=8; //block size of FC11. long stmin=20; //set STmin to 10 ms12.13. dword tester_address=0x7c1; //tester address14. dword target_ecu_address=0x7c9; //BCM address15. char wait_rsp_text_event[18]="response received"; //used to wait for response16.17. const int BUFFER_SIZE_2048=0x2048;17. const int BUFFER_SIZE_2048=0x2048;18. const int BUFFER_SIZE_1024=0x1024;19. const int LENGTH_4=4;20. byte rxBuffer[BUFFER_SIZE_2048]; //receive buffer21. long rxBufferLen=0; //receive buffer length22. dword timeout=5000;23. dword min_request_distance=50; //minum distance between two request24. dword dist_request = 10;25. char gDebugBuffer[255];26. }27.28. /*29. read fault memory30. */31. int read_fault_memory(byte _sub_func,byte _status_mask){32. byte request[3]={0x19,0x02,0x09};33.34. rxBufferLen=0;35. request[1]=_sub_func;request[2]=_status_mask;36. OSEKTL_DataReq(request,elcount(request));37. return wait_server_response(request,timeout);38. }39.40. /*41. sessionControl42. */43. int session_control(byte _session_type){44. byte request[2]={0x10,0x01};45.46. request[1]=_session_type;47. OSEKTL_DataReq(request,elcount(request));48. return wait_server_response(request,timeout);49. }50.51. /*52. reset53. */54. int reset(byte reset_type){55. byte request[2]={0x11,0x01};56.57. request[1]=reset_type;58. OSEKTL_DataReq(request,elcount(request));59. return wait_server_response(request,timeout);60. }61.62. /*63. securityAccess64. */65. int security_access(byte security_level,byte seed_szie,char ecu_name[]){66. //actual size of Seed & Key Arrays depends on ECU67. byte gSeedArray[2];68. dword gSeedArraySize = 4;69. char gVariant[9] = "Variant1";70. char gOption[7] = "option";71. dword gMaxKeyArraySize = 4;72. dword gActualSize = 0;73.74. byte request_seed[2]={0x27,0x01};75. byte send_key[6]={0x27,0x02,0xAA,0xAA,0xAA,0xAA};76.77. byte const_secu_flash[4]={}; //security const number for level flash for BCM78. byte const_secu_level1[4]={}; //security const number for level 1 for BCM79. byte const_secu_flash_rfcm[4]={}; //security const number for level flash for BCM80.81. byte seed[4]={0xAA,0xAA,0xAA,0xAA}; //store the seed received from server82. byte _key[4]={0xAA,0xAA,0xAA,0xAA}; //store the key generated by tester83. int i=0;84.85. request_seed[ 1 ] = security_level;send_key[ 1 ] = security_level + 0x01;86. OSEKTL_DataReq(request_seed,elcount(request_seed));87. if(wait_server_response(request_seed,timeout)!=0){88. write("fail to retrive seed while unlocking ECU");89. return -1;90. }91.92. for(i=0;i<seed_szie;++i){92. for(i=0;i<seed_szie;++i){93. seed[i]=rxBuffer[i+2];94. }95.96. gSeedArraySize = seed_szie;gMaxKeyArraySize = seed_szie;97. //generate_key(const_secu_flash_rfcm,seed,_key);98. diagSetTarget(ecu_name);99. DiagGenerateKeyFromSeed(seed, gSeedArraySize, security_level, gVariant, gOption, _key, gMaxKeyArraySize, gActualSize); 100.101. for(i=0;i<gActualSize;++i){102. send_key[i+2]=_key[i];103. }104.105. OSEKTL_DataReq(send_key,2+gActualSize);106. return wait_server_response(send_key,timeout);107. }108.109. _Diag_GetError (char buffer[])110. {111. //called if error in DiagGenerateKeyFromSeed occurs112. snprintf(gDebugBuffer,elcount(gDebugBuffer),"%s", buffer);113. write("CALLBACK %s", gDebugBuffer);114. }115.116.117. /*118. routineControl119. */120. int routine_control(byte _routine_control_type,byte _routine_id[],byte data_record[],int data_record_length){121. byte request[BUFFER_SIZE_1024];122. int index=0;123.124. request[0]=0x31;125. request[1]=_routine_control_type;126. request[2]=_routine_id[0];127. request[3]=_routine_id[1];128.129. for(index=0;index<data_record_length;++index){130. request[index+4]=data_record[index];131. }132.133. OSEKTL_DataReq(request,data_record_length+4);134.135. return wait_server_response(request,timeout);136. }137.138. /*139. generate key according to the received seed140. */141. void generate_key(byte const_secu[],byte seed_secu_flash[],byte securityKey[]){142. byte key1_secu_flash[4]={0x00,0x00,0x00,0x00};143. byte key2_secu_flash[4]={0x00,0x00,0x00,0x00};144. int i=0;145. byte tmp=0x00;146.147. for(i=0;i<4;++i){148. key1_secu_flash[i]=seed_secu_flash[i]^const_secu[i];149. }150.151. for(i=0;i<2;++i){152. tmp=seed_secu_flash[i];153. seed_secu_flash[i]=seed_secu_flash[3-i];154. seed_secu_flash[3-i]=tmp;155. }156.157. for(i=0;i<4;++i){158. key2_secu_flash[i]=seed_secu_flash[i]^const_secu[i];159. }160.161. for(i=0;i<4;++i){162. securityKey[i]=key1_secu_flash[i]+key2_secu_flash[i];163. }164. }165.166. /*167. communicationControl167. communicationControl168. */169. int communication_control(byte _control_type,byte _communication_type){170. byte request[3]={0x28,0x00,0x00};171.172. request[1]=_control_type;request[2]=_communication_type;173.174. OSEKTL_DataReq(request,elcount(request));175. return wait_server_response(request,timeout);176. }177.178.179. /*180. controlDTCSetting181. */182. int control_dtc_setting(byte _DTC_setting_type){183. byte request[2]={0x85,0x00};184.185. request[1]=_DTC_setting_type;186.187. OSEKTL_DataReq(request,elcount(request));188. return wait_server_response(request,timeout);189. }190.191. /*192. tester Present193. */194. int tester_present(byte sub_function){195. byte request[2]={0x3e,0x00};196.197. request[1]=sub_function;198.199. OSEKTL_DataReq(request,elcount(request));200. return wait_server_response(request,timeout);201. }202.203. /*204. writeDataByID205. */206. int write_data_by_id(byte did[],byte _data_record[],int _data_record_length){207. byte request[256];208. int i=0,_did_length=2;209.210. request[0]=0x2E;211.212. for(i=0;i<_did_length;++i){213. request[1+i]=did[i];214. }215.216. for(i=0;i<_data_record_length;++i){217. request[1+_did_length+i]=_data_record[i];218. }219.220. OSEKTL_DataReq(request,1+_did_length+_data_record_length);221. return wait_server_response(request,timeout);222. }223.224. /*225. requestDownload226. */227. int request_download(byte _memory_address[],int _memory_address_length,byte _memory_size[],int __memory_size_length){ 228. byte request[256];229. int i=0;230.231. request[0]=0x34;request[1]=0x00;request[2]=0x44;232.233. for(i=0;i<_memory_address_length;++i){234. request[3+i]=_memory_address[i];235. }236.237. for(i=0;i<__memory_size_length;++i){238. request[3+_memory_address_length+i]=_memory_size[i];239. }240.240.241. OSEKTL_DataReq(request,3+_memory_address_length+__memory_size_length);242. return wait_server_response(request,timeout);243. }244.245. /*246. tansferData247. */248. int transfer_data(byte _block_sequence,byte _upload_data[],int _upload_data_length){249. byte request[BUFFER_SIZE_2048];250. int i=0 , status = 0;251.252. request[0]=0x36;request[1]=_block_sequence;253.254. for(i=0;i<_upload_data_length;++i){255. request[2+i]=_upload_data[i];256. }257.258. OSEKTL_DataReq(request,_upload_data_length+2);259. status = wait_server_response(request,timeout);260.261. return status;262. }263.264. /*265. requstTransferExit266. */267. int request_transfer_exit(){268. byte request[1]={0x37};269.270. OSEKTL_DataReq(request,elcount(request));271. return wait_server_response(request,timeout);272. }273.274. int read_data_by_id(byte did[]){275. byte request[3]={0x22,0x00,0x00};276.277. request[1]=did[0];278. request[2]=did[1];279.280. OSEKTL_DataReq(request,elcount(request));281. return wait_server_response(request,timeout);282. }283.284. OSEKTL_FirstFrameIndication( long sourceadr, long destadr, long rxCount )285. {286. /* Print message to write window */287. //write("CAPL: %s: FF indication called, SA= 0x%02lx, TA= 0x%02lx, RxCount = %ld (AE=%d)", gECU, sourceadr, destadr, rxCount, OSEKTL_GetRecentAE()); 288. }289.290. //error handle291. OSEKTL_ErrorInd(int error)292. {293. switch (error)294. {295. case 1: write("----CAPL: Error (%d): Timeout while waiting for CF", error); break;296. case 2: write("----CAPL: Error (%d): Timeout while waiting for FC", error); break;297. case 3: write("----CAPL: Error (%d): Wrong Sequence Number", error); break;298. case 4: write("----CAPL: Error (%d): TP_DLL busy", error); break;299. case 5: write("----CAPL: Error (%d): Unexpected PDU", error);stop(); break;300. case 6: write("----CAPL: Error (%d): Timeout while waiting for Tx-Ack", error); break;301. case 7: write("----CAPL: Error (%d): WFT Overrun", error); break;302. case 8: write("----CAPL: Error (%d): Buffer overflow", error); break;303. case 9: write("----CAPL: Error (%d): Wrong parameter", error); break;304. default: write("----CAPL: Error (%d): unknown error", error); break;305. }306. }307.308. //request confirm309. OSEKTL_DataCon(long status)310. {311. if (status != 0)312. {313. //write("CAPL: %s: data sent using normal addressing", gECU);314. }315. else315. else316. {317. write("----CAPL: %s: tx error, status is %d", gECU, status);318. }319. }320.321. OSEKTL_DataInd( long rxCount )322. {323. dword glhandle=0;324.325. /* Get received data */326. OSEKTL_GetRxData( rxBuffer, 4095 );327. rxBufferLen=rxCount;328.329. //signal response received330. TestSupplyTextEvent(wait_rsp_text_event);331. }332.333. //process will suspend for tTime ms to wait for response334. int wait_server_response(byte request[],dword _tTime){335. long status=0;336. int result=0;337. long flag=5;338.339. flag=2;result=0;status=0;340.341. //loop while response pending342. while(flag>=0)343. {344. status=testWaitForTextEvent(wait_rsp_text_event,_tTime);345. if(status<0){346. write("service %x:fail to wait server response",request[0]);347. return -1;348. }else if(status==0){349. write("service %x:timeout while waiting for server\'s response",request[0]); 350. return -1;351. }352.353. result=checkResponse(request);354.355. if(result==-3){356. write("response pending");357. flag=5;358. }359.360. if(result==-2){361. write("Warning:unexpected positive response");362. flag--;363. }364.365. if(result==-1){366. write("service %x:negative response received",request[0]);367. break;368. }369.370. if(result==0){371. //write("positive response received\n");372. break;373. }374. }375.376. if(result<0){377. msgBeep(5);378. return -1;379. }380.381. return 0;382. }383.384. /*385. check response386. return 0 if positive response received387. otherwise return -1,-2,-3,0388. */389. int checkResponse(byte request[]){389. int checkResponse(byte request[]){390. if(rxBufferLen<=0){391. write("Error:empty response reveived\n");392. return -1;393. }394. else{395. if(rxBuffer[0]==request[0]+0x40){396. //write("positive response received\n");397. return 0;398. }else if(rxBuffer[0]!=0x7F&&rxBuffer[0]!=(rxBuffer[0]+0x40)){ 399. //unexpected positive response400. return -2;401. }402. else if(rxBuffer[0]==0x7F&&rxBuffer[1]==request[0]){ 403. if(rxBuffer[2]!=0x78)404. {405. //write("Error:negative response received\n");406. return -1;407. }else{408. //response pending409. return -3;410. }411. }412. }413. return 0;414. }。
基于CAN总线的车载检测模块固件升级系统设计打开文本图片集摘要:智能车载检测模块是典型的嵌入式设备之一。
嵌入式设备的主要特点是同一个硬件采用不同的固件便可以实现不同的功能。
为了降低车载检测模块的维护成本,该文设计了一种基于CAN总线的车载检测模块固件升级系统。
固件升级系统包括上位机和车载设备固件两部分。
车载设备固件将微控制器内部flash区域划分成Bootloader引導区和APP用户程序区。
升级采用被动模式,车载设备收到上位机发送的升级命令后,跳转到Bootloader区域并执行对应的操作完成固件烧写。
实验证明,此方法在很大程度上提高了车载设备的可维护性,方便稳定可靠。
关键词:嵌入式设备;CAN总线;Bootloader;固件升级随着科学技术的进步,车联网技术的发展,汽车保有量的持续增加,各种各样的车载设备需求量增加,新能源车辆的出现对智能车载设备需求量进一步增加。
智能车载检测模块是典型的车载设备之一,主要用途是借用车辆的OBD诊断接口通过CAN总线实时获取车辆的各种信息,如新能源汽车的电瓶电压,电池温度、电机转速、剩余电池电量、行驶里程等。
智能车载检测模块是典型的嵌入式设备之一,模块可以实现的具体功能和模块内部使用的微控制器烧写的固件有关,不同车型可以使用同一个车载检测模块硬件。
车载检测模块一旦批量出厂到达客户手中,客户如果想更改模块的功能或是更换使用车型,供应商需要派出大量的技术支持人员前往支持,成本高,效率低。
为了解决这一问题,充分利用车载检测模块的外部接口,本文设计了一款基于CAN总线的车载检测模块固件升级系统,车载检测模块通过CAN总线实现固件的升级方法,方便可靠,操作简单,客户只需要简单几步便能够完成对固件的升级,对于模块供应商,在很大程度上节约了工程师差旅成本。
对于客户,提高了工作效率。
1微控制器固件升级方法介绍2基于CAN总线固件升级系统设计实现2.1智能车载检测模块智能车载检测模块使用的微控制器是ST公司的STM32F105RC,此芯片有两路CAN接口,两路ADC,256KB的Flash。
基于CAN总线的Bootloader设计与实现王琦;黄悦鹏;邢正阳;苏骏凯;倪孟雄【期刊名称】《微型机与应用》【年(卷),期】2015(000)018【摘要】使用 BDM 工具下载或升级应用程序,不仅麻烦而且稳定性也不高。
采用在线更新的方法,设计并实现了一种基于 CAN 总线的 Bootloader。
介绍车载网络通信与诊断服务的实现、Bootloader的设计以及其在车载控制单元的实现,并在此基础上,提出最小 Bootloader 的概念,可以有效提高程序的灵活性。
实验结果证明, Bootloader 能正确引导加载程序的运行,准确方便地实现应用程序的下载和更新,在软件开发和测试过程中能够极大地提高工作效率,而且Bootloader 的稳定性也很高。
还能将网络层和 UDS 诊断服务部分方便地移植到其他芯片上,为后序的软件开发与测试提供了方便。
%Using BDM tools to download or upgrade the application brings not only inconvenience but also low reliability. This paper designs and implements a Bootloader based on CAN bus to download or update application online. It introduces implements of network communication and diagnostic services, design of Bootloader and its implements in vehicle control unit. And on this basis, it puts forward minimum Bootloader, which can improve flexibility efficiently. Test proves that Bootloader can boot and load correctly, download and update applications accurately and conveniently, which can improve efficiency in software development and test greatly. Also, stability of this Bootloader is very high. Moreover, network layer and UDS diagnosticservices of this Bootloader can be transplanted to other chips, providing convenience for following software development and test.【总页数】3页(P14-16)【作者】王琦;黄悦鹏;邢正阳;苏骏凯;倪孟雄【作者单位】南京邮电大学通信与信息工程学院,江苏南京 210000;南京邮电大学通信与信息工程学院,江苏南京 210000;南京邮电大学通信与信息工程学院,江苏南京 210000;南京邮电大学通信与信息工程学院,江苏南京 210000;上海奉天电子有限公司,上海 201800【正文语种】中文【中图分类】TP391【相关文献】1.基于CAN总线的车载应用Bootloader设计 [J], 张成雨;杨朝阳;单志文2.基于CAN总线的整车电控单元Bootloader的开发 [J], 于海燕;侯素礼3.基于CAN总线的电机控制器Bootloader开发 [J], 么居标;宋建桐;吕江毅;王谷娜4.基于CAN总线电气综合控制盒Bootloader软件的设计与实现 [J], 李鑫;李艳明;王志远;倪永亮5.基于CAN总线UDS服务BootLoader应用开发 [J], 汪春华;白稳峰;刘胤博;张玉稳因版权原因,仅展示原文概要,查看原文内容请购买。