Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: canutils.cpp
- Revision:
- 4:682d96ff6d79
- Parent:
- 3:92dae9083c83
- Child:
- 5:1775b4b13232
diff -r 92dae9083c83 -r 682d96ff6d79 canutils.cpp
--- 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;