Introductory CAN bus messaging application using a microcontroller built in UART connection and requiring a second CAN bus peer (to transmit or receive.)
main.cpp@0:fd2dbe74d7f6, 2017-07-24 (annotated)
- Committer:
- michaesc
- Date:
- Mon Jul 24 10:21:43 2017 +0000
- Revision:
- 0:fd2dbe74d7f6
Initialized introductory CAN bus receiver application pending import.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
michaesc | 0:fd2dbe74d7f6 | 1 | /* |
michaesc | 0:fd2dbe74d7f6 | 2 | * WARNING! With some CAN shields (those breaking SPI out exclusively to ICSP) |
michaesc | 0:fd2dbe74d7f6 | 3 | * there must be rewiring done. This is simple and involves connecting |
michaesc | 0:fd2dbe74d7f6 | 4 | * ICSP contacts for MOSI, MISO, and SCLK to D11, D12, and D13 on FRDM. |
michaesc | 0:fd2dbe74d7f6 | 5 | * |
michaesc | 0:fd2dbe74d7f6 | 6 | * SPI clock rate is 1MHz by default, set a Bus Pirate to this speed. |
michaesc | 0:fd2dbe74d7f6 | 7 | */ |
michaesc | 0:fd2dbe74d7f6 | 8 | |
michaesc | 0:fd2dbe74d7f6 | 9 | #include "mbed.h" |
michaesc | 0:fd2dbe74d7f6 | 10 | #include "seeed_can.h" |
michaesc | 0:fd2dbe74d7f6 | 11 | |
michaesc | 0:fd2dbe74d7f6 | 12 | //SEEED_CAN can(SEEED_CAN_CS, SEEED_CAN_IRQ, SEEED_CAN_MOSI, SEEED_CAN_MISO, SEEED_CAN_CLK, 30000); |
michaesc | 0:fd2dbe74d7f6 | 13 | SEEED_CAN can; // No parameters needed when Seeed Studios' CAN-BUS Shield is plugged into a FRDM-KL25Z mbed |
michaesc | 0:fd2dbe74d7f6 | 14 | // or an LPC1768b and using pins p9, p10, p11, p12 and p13. |
michaesc | 0:fd2dbe74d7f6 | 15 | Serial pc(USBTX, USBRX); // USB serial port TTYACM0 (or COMn in a Windows environment - use device manager to find 'n') |
michaesc | 0:fd2dbe74d7f6 | 16 | |
michaesc | 0:fd2dbe74d7f6 | 17 | Ticker minute; |
michaesc | 0:fd2dbe74d7f6 | 18 | Timer timestamp; |
michaesc | 0:fd2dbe74d7f6 | 19 | |
michaesc | 0:fd2dbe74d7f6 | 20 | bool msgRxFlag = 0; |
michaesc | 0:fd2dbe74d7f6 | 21 | |
michaesc | 0:fd2dbe74d7f6 | 22 | void canInterrupt() |
michaesc | 0:fd2dbe74d7f6 | 23 | { |
michaesc | 0:fd2dbe74d7f6 | 24 | can.attach(NULL); // Disable the interrupt - the application must re-anable the interrupt after it has acted upon it |
michaesc | 0:fd2dbe74d7f6 | 25 | msgRxFlag = 1; // Set a 'Flag' to say that there is an interrupt that needs to be processed |
michaesc | 0:fd2dbe74d7f6 | 26 | } |
michaesc | 0:fd2dbe74d7f6 | 27 | |
michaesc | 0:fd2dbe74d7f6 | 28 | void resetTimestamp() // Resets the 'timestamp' Timer (attached to the 'minute' Ticker) |
michaesc | 0:fd2dbe74d7f6 | 29 | { |
michaesc | 0:fd2dbe74d7f6 | 30 | timestamp.reset(); |
michaesc | 0:fd2dbe74d7f6 | 31 | } |
michaesc | 0:fd2dbe74d7f6 | 32 | |
michaesc | 0:fd2dbe74d7f6 | 33 | void displayMessage() // Display a CAN message if there is one in a receive buffer |
michaesc | 0:fd2dbe74d7f6 | 34 | { |
michaesc | 0:fd2dbe74d7f6 | 35 | SEEED_CANMessage canMsg; |
michaesc | 0:fd2dbe74d7f6 | 36 | |
michaesc | 0:fd2dbe74d7f6 | 37 | /* Note: If incoming message bytes are higher than '30' |
michaesc | 0:fd2dbe74d7f6 | 38 | it could mean that they are encoded, ANSI, ASCII |
michaesc | 0:fd2dbe74d7f6 | 39 | or similar, for example D:3031323334353637 == 01234567 */ |
michaesc | 0:fd2dbe74d7f6 | 40 | if (can.read(canMsg)) { // Timestamp in ms, message Id and message Length |
michaesc | 0:fd2dbe74d7f6 | 41 | printf("**** T:%05d I:%03x L:%d D:", timestamp.read_ms(), canMsg.id, canMsg.len); |
michaesc | 0:fd2dbe74d7f6 | 42 | for (uint32_t i = 0; i < canMsg.len; i++) { |
michaesc | 0:fd2dbe74d7f6 | 43 | printf("%02x", canMsg.data[i]); // Show the message's data bytes in Hex representation |
michaesc | 0:fd2dbe74d7f6 | 44 | } |
michaesc | 0:fd2dbe74d7f6 | 45 | printf(" ****\r\n"); |
michaesc | 0:fd2dbe74d7f6 | 46 | } |
michaesc | 0:fd2dbe74d7f6 | 47 | } |
michaesc | 0:fd2dbe74d7f6 | 48 | |
michaesc | 0:fd2dbe74d7f6 | 49 | int main() |
michaesc | 0:fd2dbe74d7f6 | 50 | { |
michaesc | 0:fd2dbe74d7f6 | 51 | SEEED_CANMessage canMsg; |
michaesc | 0:fd2dbe74d7f6 | 52 | char VIN[18] = {NULL}; // VIN code is 17 characters long + 1 for string terminator character (NULL or \0) |
michaesc | 0:fd2dbe74d7f6 | 53 | char reqvin[] = {0x02,0x1A,0x90,0x00,0x00,0x00,0x00,0x00}; // CAN message to request VIN code |
michaesc | 0:fd2dbe74d7f6 | 54 | char floctl[] = {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; // CAN message to request all remaining frames in a multi-frame message |
michaesc | 0:fd2dbe74d7f6 | 55 | |
michaesc | 0:fd2dbe74d7f6 | 56 | pc.baud(115200); // Increase bitrate appropriately for receiving and printing CAN messages |
michaesc | 0:fd2dbe74d7f6 | 57 | |
michaesc | 0:fd2dbe74d7f6 | 58 | printf("Analyzing an IoT Empire CAN Bus Test\r\n"); |
michaesc | 0:fd2dbe74d7f6 | 59 | timestamp.start(); |
michaesc | 0:fd2dbe74d7f6 | 60 | minute.attach(&resetTimestamp, 60.0); // Reset the 'Timestamp' timer every minute |
michaesc | 0:fd2dbe74d7f6 | 61 | can.open(500000, SEEED_CAN::Config); // Initialise CAN Bus hardware with a baudrate of 500 kbps (P-bus) |
michaesc | 0:fd2dbe74d7f6 | 62 | can.mask(0, 0x7FF); // Configure Mask 0 to check all bits of a Standard CAN message Id |
michaesc | 0:fd2dbe74d7f6 | 63 | can.mask(1, 0x7FF, CANStandard); // Configure Mask 1 to check all bits of a Standard CAN message Id |
michaesc | 0:fd2dbe74d7f6 | 64 | can.filter(0, 0x222); // Configure Filter 0 - 0x7E8 is the id used by ECUs on GMLAN |
michaesc | 0:fd2dbe74d7f6 | 65 | |
michaesc | 0:fd2dbe74d7f6 | 66 | // Read and Display the VIN code stored in a ECU |
michaesc | 0:fd2dbe74d7f6 | 67 | can.write(SEEED_CANMessage(0x7E0, reqvin)); // Request VIN using ReadDataByIdentifier method (GMLAN_DID) |
michaesc | 0:fd2dbe74d7f6 | 68 | while (!(can.read(canMsg) && (canMsg.id == 0x222))); // Wait for the response |
michaesc | 0:fd2dbe74d7f6 | 69 | memcpy(VIN+0, canMsg.data+4, 4); // 1st 4 Bytes are part of message protocol, last 4 bytes are 1st 4 characters of VIN |
michaesc | 0:fd2dbe74d7f6 | 70 | can.write(SEEED_CANMessage(0x7E0, floctl)); // Send Trionic8 a "Flow Control Message to get the rest of the VIN |
michaesc | 0:fd2dbe74d7f6 | 71 | while (!(can.read(canMsg) && (canMsg.id == 0x222))); // Wait for the 1st continuation message |
michaesc | 0:fd2dbe74d7f6 | 72 | memcpy(VIN+4, canMsg.data+1, 7); // 1st Byte is message continuation sequence number, last 7 bytes are next 7 characters of VIN |
michaesc | 0:fd2dbe74d7f6 | 73 | while (!(can.read(canMsg) && (canMsg.id == 0x222))); // Wait for the last message |
michaesc | 0:fd2dbe74d7f6 | 74 | memcpy(VIN+11, canMsg.data+1, 6); // 1st Byte is message continuation sequence number, last 6 bytes are remaining characters of VIN |
michaesc | 0:fd2dbe74d7f6 | 75 | printf("VIN code: %s\r\n", VIN); |
michaesc | 0:fd2dbe74d7f6 | 76 | |
michaesc | 0:fd2dbe74d7f6 | 77 | // Analysis loop, display all messages on the CAN bus regardless of addressing |
michaesc | 0:fd2dbe74d7f6 | 78 | can.monitor(1); // Select moniter mode to listen only (no ACKs to CAN) |
michaesc | 0:fd2dbe74d7f6 | 79 | can.mask(0, NULL); // Clear acceptance mask 0 (i.e. accept all meassages) |
michaesc | 0:fd2dbe74d7f6 | 80 | can.attach(&canInterrupt, SEEED_CAN::RxAny); |
michaesc | 0:fd2dbe74d7f6 | 81 | while (1) { |
michaesc | 0:fd2dbe74d7f6 | 82 | if (msgRxFlag) { |
michaesc | 0:fd2dbe74d7f6 | 83 | displayMessage(); |
michaesc | 0:fd2dbe74d7f6 | 84 | if (can.interrupts(SEEED_CAN::RxAny)) { |
michaesc | 0:fd2dbe74d7f6 | 85 | msgRxFlag = 0; |
michaesc | 0:fd2dbe74d7f6 | 86 | can.attach(&canInterrupt, SEEED_CAN::RxAny); |
michaesc | 0:fd2dbe74d7f6 | 87 | } |
michaesc | 0:fd2dbe74d7f6 | 88 | } |
michaesc | 0:fd2dbe74d7f6 | 89 | } |
michaesc | 0:fd2dbe74d7f6 | 90 | } |