Just4Trionic - CAN and BDM FLASH programmer for Saab cars

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers canutils.cpp Source File

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 }