Just4Trionic - CAN and BDM FLASH programmer for Saab cars

Dependencies:   mbed

Revision:
4:682d96ff6d79
Parent:
3:92dae9083c83
Child:
5:1775b4b13232
--- a/canutils.cpp	Tue Jun 07 12:23:28 2011 +0000
+++ b/canutils.cpp	Wed Sep 11 11:55:51 2013 +0000
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
 canutils.cpp
-(c) 2010 by Sophie Dexter
+(c) 2010, 2012 by Sophie Dexter
 
 General purpose CAN bus functions for Just4Trionic by Just4pLeisure
 Functions that work with the CAN bus directly. Anything to do with the CAN bus
@@ -22,6 +22,181 @@
 Timer CANTimer;
 
 
+//LPC_CANx->MOD |= 1;          // Disble CAN controller 2
+//LPC_CANx->MOD |= (1 << 1);   // Put into listen only mode
+//LPC_CANx->MOD &= ~(1);       // Re-enable CAN controller
+
+void can_disable(uint8_t chan) {
+    // Put a CAN controller into disabled condition
+    chan == 1 ? LPC_CAN1->MOD |= 1 : LPC_CAN2->MOD |= 1;
+}
+
+void can_enable(uint8_t chan) {
+    // Put a CAN controller in operating mode
+    chan == 1 ? LPC_CAN1->MOD &= ~(1) : LPC_CAN2->MOD &= ~(1);
+}
+
+void can_configure(uint8_t chan, uint32_t baud, bool listen) {
+
+    LPC_CAN_TypeDef *pCANx = (chan == 1) ? LPC_CAN1 : LPC_CAN2;
+
+    uint32_t result;
+    uint8_t TQU, TSEG1=0, TSEG2=0;
+    uint16_t BRP=0;
+
+    switch (chan) {
+        case 1:
+            LPC_SC->PCONP       |=  (1 << 13);          // Enable CAN controller 1
+            LPC_PINCON->PINSEL0 |=  (1 <<  0);          // Pin 9 (port0 bit0) used as Receive
+            LPC_PINCON->PINSEL0 |=  (1 <<  2);          // Pin 10 (port0 bit1) used as Transmit
+            break;
+        case 2:
+        default:
+            LPC_SC->PCONP       |=  (1 << 14);          // Enable CAN controller 2
+            LPC_PINCON->PINSEL0 |=  (1 <<  9);          // Pin 30 (port0 bit4) used as Receive
+            LPC_PINCON->PINSEL0 |=  (1 << 11);          // Pin 29 (port0 bit5) used as Transmit
+            break;
+    }
+    pCANx->MOD = 0x01;                                  // Put into reset mode
+
+    pCANx->IER   = 0;                                   // Disable all interrupts
+    pCANx->GSR   = 0;                                   // Clear status register
+    pCANx->CMR = (1<<1)|(1<<2)|(1<<3);                  // Clear Receive path, abort anything waiting to send and clear errors
+    // CANx->CMR = CAN_CMR_AT | CAN_CMR_RRB | CAN_CMR_CDO;
+    result = pCANx->ICR;                                // Read interrupt register to clear it
+
+    // Calculate a suitable BTR register setting
+    // The Bit Rate Pre-scaler (BRP) can be in the range of 1-1024
+    // Bit Time can be be between 25 and 8 Time Quanta (TQU) according to CANopen
+    // Bit Time = SyncSeg(1) + TSEG1(1-16) + TSEG2(1-8)
+    // SyncSeg is always 1TQU, TSEG2 must be at least 2TQU to be longer than the processing time
+    // Opinions vary on when to take a sample but a point roughly 2/3 of Bit Time seems OK, TSEG1 is roughly 2*TSEG2
+    // Synchronisation Jump width can be 1-4 TQU, a value of 1 seems to be normal
+    // 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
+    result =  CANsuppliedCLK / baud;
+    for (TQU=25; TQU>7; TQU--) {
+        if ((result%TQU)==0) {
+            BRP = (result/TQU) - 1;
+            TSEG2 = (TQU/3) - 1;                        // Subtract 1
+            TSEG1 = TQU - (TQU/3) - 2;                  // Subtract 2 to allow for SyncSeg
+            break;
+        }
+    }
+    pCANx->BTR  = (TSEG2<<20)|(TSEG1<<16)|(0<<14)|BRP;  // Set bit timing, SAM = 0, TSEG2, TSEG1, SJW = 1 (0+1), BRP
+
+    can_reset_filters();                                // Initialise the Acceptance Filters
+    can_use_filters(FALSE);                             // Accept all messages (Acceptance Filters disabled)
+    // Go :-)
+    can_rs_pin = listen;                                // enable/disable CAN driver chip
+    pCANx->MOD = (listen <<1);                          // Enable CAN controller in active/listen mode
+}
+
+
+void can_reset_filters() {
+    // Initialise the Acceptance Filters
+    LPC_CANAF->AFMR = 0x01;                             // Put Acceptance Filter into reset/configuration mode
+    for (uint16_t i = 0; i < 512; i++)
+        LPC_CANAF_RAM->mask[i] = 0x00;                  // Clear the Acceptance Filter memory
+    LPC_CANAF->SFF_sa = 0x00;                           // Clear the Acceptance Filter registers
+    LPC_CANAF->SFF_GRP_sa = 0x00;
+    LPC_CANAF->EFF_sa = 0x00;
+    LPC_CANAF->EFF_GRP_sa = 0x00;
+    LPC_CANAF->ENDofTable = 0x00;
+    LPC_CANAF->AFMR = 0x00;                             // Enable Acceptance Filter all messages should be rejected
+}
+
+void can_use_filters(bool active) {
+    active ? LPC_CANAF->AFMR = 0 : LPC_CANAF->AFMR = 2;
+}
+
+/*--------------------------------------------
+  setup acceptance filter for CAN controller 2
+  original http://www.dragonwake.com/download/LPC1768/Example/CAN/CAN.c
+  simplified for CAN2 interface and std id (11 bit) only
+ *--------------------------------------------*/
+void can_add_filter(uint8_t chan, uint32_t id)  {
+
+    static int CAN_std_cnt = 0;
+    uint32_t buf0, buf1;
+    int cnt1, cnt2, bound1;
+
+    /* Acceptance Filter Memory full */
+    if (((CAN_std_cnt + 1) >> 1) >= 512)
+        return;                                         // error: objects full
+
+    /* Setup Acceptance Filter Configuration
+      Acceptance Filter Mode Register = Off  */
+    LPC_CANAF->AFMR = 0x00000001;
+
+    id &= 0x000007FF;                                   // Mask out 16-bits of ID
+    id |= (chan-1) << 13;                               // Add CAN controller number (1 or 2)
+
+    if (CAN_std_cnt == 0)  {                     /* For entering first  ID */
+        LPC_CANAF_RAM->mask[0] = 0x0000FFFF | (id << 16);
+    }  else if (CAN_std_cnt == 1)  {             /* For entering second ID */
+        if ((LPC_CANAF_RAM->mask[0] >> 16) > id)
+            LPC_CANAF_RAM->mask[0] = (LPC_CANAF_RAM->mask[0] >> 16) | (id << 16);
+        else
+            LPC_CANAF_RAM->mask[0] = (LPC_CANAF_RAM->mask[0] & 0xFFFF0000) | id;
+    }  else  {
+        /* Find where to insert new ID */
+        cnt1 = 0;
+        cnt2 = CAN_std_cnt;
+        bound1 = (CAN_std_cnt - 1) >> 1;
+        while (cnt1 <= bound1)  {                  /* Loop through standard existing IDs */
+            if ((LPC_CANAF_RAM->mask[cnt1] >> 16) > id)  {
+                cnt2 = cnt1 * 2;
+                break;
+            }
+            if ((LPC_CANAF_RAM->mask[cnt1] & 0x0000FFFF) > id)  {
+                cnt2 = cnt1 * 2 + 1;
+                break;
+            }
+            cnt1++;                                  /* cnt1 = U32 where to insert new ID */
+        }                                          /* cnt2 = U16 where to insert new ID */
+
+        if (cnt1 > bound1)  {                      /* Adding ID as last entry */
+            if ((CAN_std_cnt & 0x0001) == 0)         /* Even number of IDs exists */
+                LPC_CANAF_RAM->mask[cnt1]  = 0x0000FFFF | (id << 16);
+            else                                     /* Odd  number of IDs exists */
+                LPC_CANAF_RAM->mask[cnt1]  = (LPC_CANAF_RAM->mask[cnt1] & 0xFFFF0000) | id;
+        }  else  {
+            buf0 = LPC_CANAF_RAM->mask[cnt1];        /* Remember current entry */
+            if ((cnt2 & 0x0001) == 0)                /* Insert new mask to even address */
+                buf1 = (id << 16) | (buf0 >> 16);
+            else                                     /* Insert new mask to odd  address */
+                buf1 = (buf0 & 0xFFFF0000) | id;
+
+            LPC_CANAF_RAM->mask[cnt1] = buf1;        /* Insert mask */
+
+            bound1 = CAN_std_cnt >> 1;
+            /* Move all remaining standard mask entries one place up */
+            while (cnt1 < bound1)  {
+                cnt1++;
+                buf1  = LPC_CANAF_RAM->mask[cnt1];
+                LPC_CANAF_RAM->mask[cnt1] = (buf1 >> 16) | (buf0 << 16);
+                buf0  = buf1;
+            }
+
+            if ((CAN_std_cnt & 0x0001) == 0)         /* Even number of IDs exists */
+                LPC_CANAF_RAM->mask[cnt1] = (LPC_CANAF_RAM->mask[cnt1] & 0xFFFF0000) | (0x0000FFFF);
+        }
+    }
+    CAN_std_cnt++;
+
+    /* Calculate std ID start address (buf0) and ext ID start address <- none (buf1) */
+    buf0 = ((CAN_std_cnt + 1) >> 1) << 2;
+    /* Setup acceptance filter pointers */
+    LPC_CANAF->SFF_sa     = 0;
+    LPC_CANAF->SFF_GRP_sa = buf0;
+    LPC_CANAF->EFF_sa     = buf0;
+    LPC_CANAF->EFF_GRP_sa = buf0;
+    LPC_CANAF->ENDofTable = buf0;
+
+    LPC_CANAF->AFMR = 0x00000000;                  /* Use acceptance filter */
+} // CAN2_wrFilter
+
+
 void can_open() {
     // activate external can transceiver
     can.reset();
@@ -34,6 +209,16 @@
     can.reset();
 }
 
+void can_monitor() {
+    // Put CAN into silent monitoring mode
+    can.monitor(1);
+}
+
+void can_active() {
+    // Take CAN out of silent monitoring mode
+    can.monitor(0);
+}
+
 uint8_t can_set_speed(uint32_t speed) {
     // 600kbit/s first - basically sets up CAN interface, but to wrong speed - not sure what else it does
 //    can.frequency(600000);
@@ -57,13 +242,110 @@
         printf("w%03x%d", can_MsgRx.id, can_MsgRx.len);
         for (char i=0; i<can_MsgRx.len; i++)
             printf("%02x", can_MsgRx.data[i]);
-        printf(" %c ", can_MsgRx.data[2]);
+        //printf(" %c ", can_MsgRx.data[2]);
         printf("\r\n");
     }
     return;
 }
 
 //
+// show_T5can_message
+//
+// Displays a Trionic 5 CAN message in the RX buffer if there is one.
+//
+// inputs:    none
+// return:    bool TRUE if there was a message, FALSE if no message.
+//
+extern void show_T5can_message() {
+    CANMessage can_MsgRx;
+    if (can.read(can_MsgRx)) {
+        CANRXLEDON;
+        switch (can_MsgRx.id) {
+            case 0x005:
+            case 0x006:
+            case 0x00C:
+            case 0x008:
+                printf("w%03x%d", can_MsgRx.id, can_MsgRx.len);
+                for (char i=0; i<can_MsgRx.len; i++)
+                    printf("%02x", can_MsgRx.data[i]);
+                printf("\r\n");
+                break;
+        }
+    }
+    return;
+}
+//
+// show_T7can_message
+//
+// Displays a Trionic 7 CAN message in the RX buffer if there is one.
+//
+// inputs:    none
+// return:    bool TRUE if there was a message, FALSE if no message.
+//
+extern void show_T7can_message() {
+    CANMessage can_MsgRx;
+    if (can.read(can_MsgRx)) {
+        CANRXLEDON;
+        switch (can_MsgRx.id) {
+            case 0x1A0:         //1A0h - Engine information
+            case 0x280:         //280h - Pedals, reverse gear
+            case 0x290:         //290h - Steering wheel and SID buttons
+            case 0x2F0:         //2F0h - Vehicle speed
+            case 0x320:         //320h - Doors, central locking and seat belts
+            case 0x370:         //370h - Mileage
+            case 0x3A0:         //3A0h - Vehicle speed
+            case 0x3B0:         //3B0h - Head lights
+            case 0x3E0:         //3E0h - Automatic Gearbox
+            case 0x410:         //410h - Light dimmer and light sensor
+            case 0x430:         //430h - SID beep request (interesting for Knock indicator?)
+            case 0x460:         //460h - Engine rpm and speed
+            case 0x4A0:         //4A0h - Steering wheel, Vehicle Identification Number
+            case 0x520:         //520h - ACC, inside temperature
+            case 0x530:         //530h - ACC
+            case 0x5C0:         //5C0h - Coolant temperature, air pressure
+            case 0x630:         //630h - Fuel usage
+            case 0x640:         //640h - Mileage
+            case 0x7A0:         //7A0h - Outside temperature
+                printf("w%03x%d", can_MsgRx.id, can_MsgRx.len);
+                for (char i=0; i<can_MsgRx.len; i++)
+                    printf("%02x", can_MsgRx.data[i]);
+                //printf(" %c ", can_MsgRx.data[2]);
+                printf("\r\n");
+                break;
+        }
+    }
+    return;
+}
+//
+// show_T8can_message
+//
+// Displays a Trionic 8 CAN message in the RX buffer if there is one.
+//
+// inputs:    none
+// return:    bool TRUE if there was a message, FALSE if no message.
+//
+extern void show_T8can_message() {
+    CANMessage can_MsgRx;
+    if (can.read(can_MsgRx)) {
+        CANRXLEDON;
+        switch (can_MsgRx.id) {
+            case 0x645: // CIM
+            case 0x7E0:
+            case 0x7E8:
+            case 0x311:
+            case 0x5E8:
+                //case 0x101:
+                printf("w%03x%d", can_MsgRx.id, can_MsgRx.len);
+                for (char i=0; i<can_MsgRx.len; i++)
+                    printf("%02x", can_MsgRx.data[i]);
+                printf("\r\n");
+                break;
+        }
+    }
+    return;
+}
+
+//
 // silent_can_message
 //
 // Turns on the CAN receive LED if there is a CAN message
@@ -120,16 +402,16 @@
     CANTimer.start();
     while (CANTimer.read_ms() < timeout) {
         if (can.read(CANMsgRx)) {
-/*
-            printf("w%03x8", CANMsgRx.id);
-            for (char i=0; i<len; i++) {
-                printf("%02x", CANMsgRx.data[i]);
-            }
-            printf("\n\r");
-//            */
+            /*
+                        printf("w%03x8", CANMsgRx.id);
+                        for (char i=0; i<len; i++) {
+                            printf("%02x", CANMsgRx.data[i]);
+                        }
+                        printf("\n\r");
+            //            */
             CANRXLEDON;
 //            led2 = 1;
-            if (CANMsgRx.id == id) {
+            if (CANMsgRx.id == id || id ==0) {
                 CANTimer.stop();
 //                if (T5MsgRx.len != len)
 //                    return FALSE;