Sophie Dexter
/
Just4Trionic
Just4Trionic - CAN and BDM FLASH programmer for Saab cars
Embed:
(wiki syntax)
Show/hide line numbers
canutils.cpp
00001 /******************************************************************************* 00002 00003 canutils.cpp 00004 (c) 2010, 2012 by Sophie Dexter 00005 00006 General purpose CAN bus functions for Just4Trionic by Just4pLeisure 00007 Functions that work with the CAN bus directly. Anything to do with the CAN bus 00008 must (should anyway) be done by one of these functions. 00009 00010 ******************************************************************************** 00011 00012 WARNING: Use at your own risk, sadly this software comes with no guarantees. 00013 This software is provided 'free' and in good faith, but the author does not 00014 accept liability for any damage arising from its use. 00015 00016 *******************************************************************************/ 00017 00018 #include "canutils.h" 00019 00020 //CAN can2(p30, p29); 00021 // Use a timer to see if things take too long 00022 Timer CANTimer; 00023 00024 00025 //LPC_CANx->MOD |= 1; // Disble CAN controller 2 00026 //LPC_CANx->MOD |= (1 << 1); // Put into listen only mode 00027 //LPC_CANx->MOD &= ~(1); // Re-enable CAN controller 00028 00029 void can_disable(uint8_t chan) 00030 { 00031 // Put a CAN controller into disabled condition 00032 chan == 1 ? LPC_CAN1->MOD |= 1 : LPC_CAN2->MOD |= 1; 00033 } 00034 00035 void can_enable(uint8_t chan) 00036 { 00037 // Put a CAN controller in operating mode 00038 chan == 1 ? LPC_CAN1->MOD &= ~(1) : LPC_CAN2->MOD &= ~(1); 00039 } 00040 00041 void can_configure(uint8_t chan, uint32_t baud, bool listen) 00042 { 00043 00044 LPC_CAN_TypeDef *pCANx = (chan == 1) ? LPC_CAN1 : LPC_CAN2; 00045 00046 uint32_t result; 00047 uint8_t TQU, TSEG1=0, TSEG2=0; 00048 uint16_t BRP=0; 00049 00050 switch (chan) { 00051 case 1: 00052 LPC_SC->PCONP |= (1 << 13); // Enable CAN controller 1 00053 LPC_PINCON->PINSEL0 |= (1 << 0); // Pin 9 (port0 bit0) used as Receive 00054 LPC_PINCON->PINSEL0 |= (1 << 2); // Pin 10 (port0 bit1) used as Transmit 00055 break; 00056 case 2: 00057 default: 00058 LPC_SC->PCONP |= (1 << 14); // Enable CAN controller 2 00059 LPC_PINCON->PINSEL0 |= (1 << 9); // Pin 30 (port0 bit4) used as Receive 00060 LPC_PINCON->PINSEL0 |= (1 << 11); // Pin 29 (port0 bit5) used as Transmit 00061 break; 00062 } 00063 pCANx->MOD = 0x01; // Put into reset mode 00064 00065 pCANx->IER = 0; // Disable all interrupts 00066 pCANx->GSR = 0; // Clear status register 00067 pCANx->CMR = (1<<1)|(1<<2)|(1<<3); // Clear Receive path, abort anything waiting to send and clear errors 00068 // CANx->CMR = CAN_CMR_AT | CAN_CMR_RRB | CAN_CMR_CDO; 00069 result = pCANx->ICR; // Read interrupt register to clear it 00070 00071 // Calculate a suitable BTR register setting 00072 // The Bit Rate Pre-scaler (BRP) can be in the range of 1-1024 00073 // Bit Time can be be between 25 and 8 Time Quanta (TQU) according to CANopen 00074 // Bit Time = SyncSeg(1) + TSEG1(1-16) + TSEG2(1-8) 00075 // SyncSeg is always 1TQU, TSEG2 must be at least 2TQU to be longer than the processing time 00076 // Opinions vary on when to take a sample but a point roughly 2/3 of Bit Time seems OK, TSEG1 is roughly 2*TSEG2 00077 // Synchronisation Jump width can be 1-4 TQU, a value of 1 seems to be normal 00078 // All register values are -1, e.g. TSEG1 can range from 1-16 TQU, so register values are 0-15 to fit into 4 bits 00079 result = CANsuppliedCLK / baud; 00080 for (TQU=25; TQU>7; TQU--) { 00081 if ((result%TQU)==0) { 00082 BRP = (result/TQU) - 1; 00083 TSEG2 = (TQU/3) - 1; // Subtract 1 00084 TSEG1 = TQU - (TQU/3) - 2; // Subtract 2 to allow for SyncSeg 00085 break; 00086 } 00087 } 00088 pCANx->BTR = (TSEG2<<20)|(TSEG1<<16)|(0<<14)|BRP; // Set bit timing, SAM = 0, TSEG2, TSEG1, SJW = 1 (0+1), BRP 00089 00090 can_reset_filters(); // Initialise the Acceptance Filters 00091 can_use_filters(FALSE); // Accept all messages (Acceptance Filters disabled) 00092 // Go :-) 00093 can_rs_pin = listen; // enable/disable CAN driver chip 00094 pCANx->MOD = (listen <<1); // Enable CAN controller in active/listen mode 00095 } 00096 00097 00098 void can_reset_filters() 00099 { 00100 // Initialise the Acceptance Filters 00101 LPC_CANAF->AFMR = 0x01; // Put Acceptance Filter into reset/configuration mode 00102 for (uint16_t i = 0; i < 512; i++) 00103 LPC_CANAF_RAM->mask[i] = 0x00; // Clear the Acceptance Filter memory 00104 LPC_CANAF->SFF_sa = 0x00; // Clear the Acceptance Filter registers 00105 LPC_CANAF->SFF_GRP_sa = 0x00; 00106 LPC_CANAF->EFF_sa = 0x00; 00107 LPC_CANAF->EFF_GRP_sa = 0x00; 00108 LPC_CANAF->ENDofTable = 0x00; 00109 LPC_CANAF->AFMR = 0x00; // Enable Acceptance Filter all messages should be rejected 00110 } 00111 00112 void can_use_filters(bool active) 00113 { 00114 active ? LPC_CANAF->AFMR = 0 : LPC_CANAF->AFMR = 2; 00115 } 00116 00117 /*-------------------------------------------- 00118 setup acceptance filter for CAN controller 2 00119 original http://www.dragonwake.com/download/LPC1768/Example/CAN/CAN.c 00120 simplified for CAN2 interface and std id (11 bit) only 00121 *--------------------------------------------*/ 00122 void can_add_filter(uint8_t chan, uint32_t id) 00123 { 00124 00125 static int CAN_std_cnt = 0; 00126 uint32_t buf0, buf1; 00127 int cnt1, cnt2, bound1; 00128 00129 /* Acceptance Filter Memory full */ 00130 if (((CAN_std_cnt + 1) >> 1) >= 512) 00131 return; // error: objects full 00132 00133 /* Setup Acceptance Filter Configuration 00134 Acceptance Filter Mode Register = Off */ 00135 LPC_CANAF->AFMR = 0x00000001; 00136 00137 id &= 0x000007FF; // Mask out 16-bits of ID 00138 id |= (chan-1) << 13; // Add CAN controller number (1 or 2) 00139 00140 if (CAN_std_cnt == 0) { /* For entering first ID */ 00141 LPC_CANAF_RAM->mask[0] = 0x0000FFFF | (id << 16); 00142 } else if (CAN_std_cnt == 1) { /* For entering second ID */ 00143 if ((LPC_CANAF_RAM->mask[0] >> 16) > id) 00144 LPC_CANAF_RAM->mask[0] = (LPC_CANAF_RAM->mask[0] >> 16) | (id << 16); 00145 else 00146 LPC_CANAF_RAM->mask[0] = (LPC_CANAF_RAM->mask[0] & 0xFFFF0000) | id; 00147 } else { 00148 /* Find where to insert new ID */ 00149 cnt1 = 0; 00150 cnt2 = CAN_std_cnt; 00151 bound1 = (CAN_std_cnt - 1) >> 1; 00152 while (cnt1 <= bound1) { /* Loop through standard existing IDs */ 00153 if ((LPC_CANAF_RAM->mask[cnt1] >> 16) > id) { 00154 cnt2 = cnt1 * 2; 00155 break; 00156 } 00157 if ((LPC_CANAF_RAM->mask[cnt1] & 0x0000FFFF) > id) { 00158 cnt2 = cnt1 * 2 + 1; 00159 break; 00160 } 00161 cnt1++; /* cnt1 = U32 where to insert new ID */ 00162 } /* cnt2 = U16 where to insert new ID */ 00163 00164 if (cnt1 > bound1) { /* Adding ID as last entry */ 00165 if ((CAN_std_cnt & 0x0001) == 0) /* Even number of IDs exists */ 00166 LPC_CANAF_RAM->mask[cnt1] = 0x0000FFFF | (id << 16); 00167 else /* Odd number of IDs exists */ 00168 LPC_CANAF_RAM->mask[cnt1] = (LPC_CANAF_RAM->mask[cnt1] & 0xFFFF0000) | id; 00169 } else { 00170 buf0 = LPC_CANAF_RAM->mask[cnt1]; /* Remember current entry */ 00171 if ((cnt2 & 0x0001) == 0) /* Insert new mask to even address */ 00172 buf1 = (id << 16) | (buf0 >> 16); 00173 else /* Insert new mask to odd address */ 00174 buf1 = (buf0 & 0xFFFF0000) | id; 00175 00176 LPC_CANAF_RAM->mask[cnt1] = buf1; /* Insert mask */ 00177 00178 bound1 = CAN_std_cnt >> 1; 00179 /* Move all remaining standard mask entries one place up */ 00180 while (cnt1 < bound1) { 00181 cnt1++; 00182 buf1 = LPC_CANAF_RAM->mask[cnt1]; 00183 LPC_CANAF_RAM->mask[cnt1] = (buf1 >> 16) | (buf0 << 16); 00184 buf0 = buf1; 00185 } 00186 00187 if ((CAN_std_cnt & 0x0001) == 0) /* Even number of IDs exists */ 00188 LPC_CANAF_RAM->mask[cnt1] = (LPC_CANAF_RAM->mask[cnt1] & 0xFFFF0000) | (0x0000FFFF); 00189 } 00190 } 00191 CAN_std_cnt++; 00192 00193 /* Calculate std ID start address (buf0) and ext ID start address <- none (buf1) */ 00194 buf0 = ((CAN_std_cnt + 1) >> 1) << 2; 00195 /* Setup acceptance filter pointers */ 00196 LPC_CANAF->SFF_sa = 0; 00197 LPC_CANAF->SFF_GRP_sa = buf0; 00198 LPC_CANAF->EFF_sa = buf0; 00199 LPC_CANAF->EFF_GRP_sa = buf0; 00200 LPC_CANAF->ENDofTable = buf0; 00201 00202 LPC_CANAF->AFMR = 0x00000000; /* Use acceptance filter */ 00203 } // CAN2_wrFilter 00204 00205 00206 void can_open() 00207 { 00208 // activate external can transceiver 00209 can.reset(); 00210 can_rs_pin = 0; 00211 } 00212 00213 void can_close() 00214 { 00215 // disable external can transceiver 00216 can_rs_pin = 1; 00217 can.reset(); 00218 } 00219 00220 void can_monitor() 00221 { 00222 // Put CAN into silent monitoring mode 00223 can.monitor(1); 00224 } 00225 00226 void can_active() 00227 { 00228 // Take CAN out of silent monitoring mode 00229 can.monitor(0); 00230 } 00231 00232 uint8_t can_set_speed(uint32_t speed) 00233 { 00234 // 600kbit/s first - basically sets up CAN interface, but to wrong speed - not sure what else it does 00235 // can.frequency(600000); 00236 // 615kbit/s direct write of 615 kbit/s speed setting 00237 // LPC_CAN2->BTR = 0x370002; 00238 return (can.frequency(speed)) ? TERM_OK : TERM_ERR; 00239 } 00240 00241 // 00242 // show_can_message 00243 // 00244 // Displays a CAN message in the RX buffer if there is one. 00245 // 00246 // inputs: none 00247 // return: bool TRUE if there was a message, FALSE if no message. 00248 // 00249 extern void show_can_message() 00250 { 00251 CANMessage can_MsgRx; 00252 if (can.read(can_MsgRx)) { 00253 CANRXLEDON; 00254 printf("w%03x%d", can_MsgRx.id, can_MsgRx.len); 00255 for (char i=0; i<can_MsgRx.len; i++) 00256 printf("%02x", can_MsgRx.data[i]); 00257 //printf(" %c ", can_MsgRx.data[2]); 00258 printf("\r\n"); 00259 } 00260 return; 00261 } 00262 00263 // 00264 // show_T5can_message 00265 // 00266 // Displays a Trionic 5 CAN message in the RX buffer if there is one. 00267 // 00268 // inputs: none 00269 // return: bool TRUE if there was a message, FALSE if no message. 00270 // 00271 extern void show_T5can_message() 00272 { 00273 CANMessage can_MsgRx; 00274 if (can.read(can_MsgRx)) { 00275 CANRXLEDON; 00276 switch (can_MsgRx.id) { 00277 case 0x005: 00278 case 0x006: 00279 case 0x00C: 00280 case 0x008: 00281 printf("w%03x%d", can_MsgRx.id, can_MsgRx.len); 00282 for (char i=0; i<can_MsgRx.len; i++) 00283 printf("%02x", can_MsgRx.data[i]); 00284 printf("\r\n"); 00285 break; 00286 } 00287 } 00288 return; 00289 } 00290 // 00291 // show_T7can_message 00292 // 00293 // Displays a Trionic 7 CAN message in the RX buffer if there is one. 00294 // 00295 // inputs: none 00296 // return: bool TRUE if there was a message, FALSE if no message. 00297 // 00298 extern void show_T7can_message() 00299 { 00300 CANMessage can_MsgRx; 00301 if (can.read(can_MsgRx)) { 00302 CANRXLEDON; 00303 switch (can_MsgRx.id) { 00304 case 0x1A0: //1A0h - Engine information 00305 case 0x280: //280h - Pedals, reverse gear 00306 case 0x290: //290h - Steering wheel and SID buttons 00307 case 0x2F0: //2F0h - Vehicle speed 00308 case 0x320: //320h - Doors, central locking and seat belts 00309 case 0x370: //370h - Mileage 00310 case 0x3A0: //3A0h - Vehicle speed 00311 case 0x3B0: //3B0h - Head lights 00312 case 0x3E0: //3E0h - Automatic Gearbox 00313 case 0x410: //410h - Light dimmer and light sensor 00314 case 0x430: //430h - SID beep request (interesting for Knock indicator?) 00315 case 0x460: //460h - Engine rpm and speed 00316 case 0x4A0: //4A0h - Steering wheel, Vehicle Identification Number 00317 case 0x520: //520h - ACC, inside temperature 00318 case 0x530: //530h - ACC 00319 case 0x5C0: //5C0h - Coolant temperature, air pressure 00320 case 0x630: //630h - Fuel usage 00321 case 0x640: //640h - Mileage 00322 case 0x7A0: //7A0h - Outside temperature 00323 printf("w%03x%d", can_MsgRx.id, can_MsgRx.len); 00324 for (char i=0; i<can_MsgRx.len; i++) 00325 printf("%02x", can_MsgRx.data[i]); 00326 //printf(" %c ", can_MsgRx.data[2]); 00327 printf("\r\n"); 00328 break; 00329 } 00330 } 00331 return; 00332 } 00333 // 00334 // show_T8can_message 00335 // 00336 // Displays a Trionic 8 CAN message in the RX buffer if there is one. 00337 // 00338 // inputs: none 00339 // return: bool TRUE if there was a message, FALSE if no message. 00340 // 00341 extern void show_T8can_message() 00342 { 00343 CANMessage can_MsgRx; 00344 if (can.read(can_MsgRx)) { 00345 CANRXLEDON; 00346 switch (can_MsgRx.id) { 00347 case 0x645: // CIM 00348 case 0x7E0: 00349 case 0x7E8: 00350 case 0x311: 00351 case 0x5E8: 00352 //case 0x101: 00353 printf("w%03x%d", can_MsgRx.id, can_MsgRx.len); 00354 for (char i=0; i<can_MsgRx.len; i++) 00355 printf("%02x", can_MsgRx.data[i]); 00356 printf("\r\n"); 00357 break; 00358 } 00359 } 00360 return; 00361 } 00362 00363 // 00364 // silent_can_message 00365 // 00366 // Turns on the CAN receive LED if there is a CAN message 00367 // but doesn't displays anything. 00368 // 00369 // inputs: none 00370 // return: bool TRUE if there was a message, FALSE if no message. 00371 // 00372 extern void silent_can_message() 00373 { 00374 CANMessage can_MsgRx; 00375 if (can.read(can_MsgRx)) { 00376 CANRXLEDON; 00377 } 00378 return; 00379 } 00380 00381 // 00382 // Sends a CAN Message, returns FALSE if the message wasn't sent in time 00383 // 00384 // inputs: integer CAN message 'id', pointer to 'frame', integer message length and integer timeout 00385 // return: TRUE if the CAN message was sent before the 'timeout' expires 00386 // FALSE if 'timeout' expires or the message length is wrong 00387 // 00388 extern bool can_send_timeout (uint32_t id, char *frame, uint8_t len, uint16_t timeout) 00389 { 00390 CANTimer.reset(); 00391 CANTimer.start(); 00392 #ifdef DEBUG 00393 printf("ID:%03x Len:%03x", id, len); 00394 for (char i=0; i<len; i++) { 00395 printf(" %02x", frame[i]); 00396 } 00397 printf("\n\r"); 00398 #endif 00399 while (CANTimer.read_ms() < timeout) { 00400 if (can.write(CANMessage(id, frame, len))) { 00401 CANTimer.stop(); 00402 CANTXLEDON; 00403 // led1 = 1; 00404 return TRUE; 00405 } 00406 } 00407 can.reset(); 00408 CANTimer.stop(); 00409 return FALSE; 00410 } 00411 00412 // 00413 // Waits for a CAN Message with the specified 'id' for a time specified by the 'timeout' 00414 // All other messages are ignored 00415 // The CAN message frame is returned using the pointer to 'frame' 00416 // 00417 // inputs: integer CAN message 'id', pointer to 'frame' for returning the data 00418 // integer expected length of message, len and integer for the waiting time 'timeout' 00419 // 00420 // return: TRUE if a qualifying message was received 00421 // FALSE if 'timeout' expires or the message length is wrong 00422 // 00423 extern bool can_wait_timeout (uint32_t id, char *frame, uint8_t len, uint16_t timeout) 00424 { 00425 CANMessage CANMsgRx; 00426 CANTimer.reset(); 00427 CANTimer.start(); 00428 while (CANTimer.read_ms() < timeout) { 00429 if (can.read(CANMsgRx)) { 00430 #ifdef DEBUG 00431 printf("ID:%03x Len:%03x", CANMsgRx.id, CANMsgRx.len); 00432 for (char i=0; i<len; i++) { 00433 printf(" %02x", CANMsgRx.data[i]); 00434 } 00435 printf("\n\r"); 00436 #endif 00437 CANRXLEDON; 00438 // led2 = 1; 00439 if (CANMsgRx.id == id || id ==0) { 00440 CANTimer.stop(); 00441 // if (CANMsgRx.len != len) 00442 // return FALSE; 00443 for (int i=0; i<len; i++) 00444 frame[i] = CANMsgRx.data[i]; 00445 return TRUE; 00446 } 00447 } 00448 } 00449 can.reset(); 00450 CANTimer.stop(); 00451 return FALSE; 00452 }
Generated on Fri Jul 15 2022 00:43:05 by 1.7.2