Sophie Dexter
/
Just4Trionic
Just4Trionic - CAN and BDM FLASH programmer for Saab cars
canutils.cpp
- Committer:
- Just4pLeisure
- Date:
- 2016-04-23
- Revision:
- 6:2fbcbebed28c
- Parent:
- 5:1775b4b13232
File content as of revision 6:2fbcbebed28c:
/******************************************************************************* canutils.cpp (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 must (should anyway) be done by one of these functions. ******************************************************************************** WARNING: Use at your own risk, sadly this software comes with no guarantees. This software is provided 'free' and in good faith, but the author does not accept liability for any damage arising from its use. *******************************************************************************/ #include "canutils.h" //CAN can2(p30, p29); // Use a timer to see if things take too long 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(); can_rs_pin = 0; } void can_close() { // disable external can transceiver can_rs_pin = 1; 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); // 615kbit/s direct write of 615 kbit/s speed setting // LPC_CAN2->BTR = 0x370002; return (can.frequency(speed)) ? TERM_OK : TERM_ERR; } // // show_can_message // // Displays a 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_can_message() { CANMessage can_MsgRx; if (can.read(can_MsgRx)) { CANRXLEDON; 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"); } 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 // but doesn't displays anything. // // inputs: none // return: bool TRUE if there was a message, FALSE if no message. // extern void silent_can_message() { CANMessage can_MsgRx; if (can.read(can_MsgRx)) { CANRXLEDON; } return; } // // Sends a CAN Message, returns FALSE if the message wasn't sent in time // // inputs: integer CAN message 'id', pointer to 'frame', integer message length and integer timeout // return: TRUE if the CAN message was sent before the 'timeout' expires // FALSE if 'timeout' expires or the message length is wrong // extern bool can_send_timeout (uint32_t id, char *frame, uint8_t len, uint16_t timeout) { CANTimer.reset(); CANTimer.start(); #ifdef DEBUG printf("ID:%03x Len:%03x", id, len); for (char i=0; i<len; i++) { printf(" %02x", frame[i]); } printf("\n\r"); #endif while (CANTimer.read_ms() < timeout) { if (can.write(CANMessage(id, frame, len))) { CANTimer.stop(); CANTXLEDON; // led1 = 1; return TRUE; } } can.reset(); CANTimer.stop(); return FALSE; } // // Waits for a CAN Message with the specified 'id' for a time specified by the 'timeout' // All other messages are ignored // The CAN message frame is returned using the pointer to 'frame' // // inputs: integer CAN message 'id', pointer to 'frame' for returning the data // integer expected length of message, len and integer for the waiting time 'timeout' // // return: TRUE if a qualifying message was received // FALSE if 'timeout' expires or the message length is wrong // extern bool can_wait_timeout (uint32_t id, char *frame, uint8_t len, uint16_t timeout) { CANMessage CANMsgRx; CANTimer.reset(); CANTimer.start(); while (CANTimer.read_ms() < timeout) { if (can.read(CANMsgRx)) { #ifdef DEBUG printf("ID:%03x Len:%03x", CANMsgRx.id, CANMsgRx.len); for (char i=0; i<len; i++) { printf(" %02x", CANMsgRx.data[i]); } printf("\n\r"); #endif CANRXLEDON; // led2 = 1; if (CANMsgRx.id == id || id ==0) { CANTimer.stop(); // if (CANMsgRx.len != len) // return FALSE; for (int i=0; i<len; i++) frame[i] = CANMsgRx.data[i]; return TRUE; } } } can.reset(); CANTimer.stop(); return FALSE; }