Using CAN bus with (not just NUCLEO) mbed boards

Dependencies:   mbed CANMsg

Using CAN bus with mbed boards

Two low cost STM32F103C8T6 boards are connected to the same CAN bus via transceivers (MCP2551 or TJA1040, or etc.). CAN transceivers are not part of NUCLEO boards, therefore must be added by us. Remember also that CAN bus (even a short one) must be terminated with 120 Ohm resitors at both ends. Although there seems to be an alternative solution.

Schematic

Zoom in

/media/uploads/hudakz/stm32f103c8t6_can_hello.png

Hookup

/media/uploads/hudakz/20150724_080148.jpg

The mbed boards in this example are transmitting CAN messages carrying two data items:

uint8_t   counter;  // one byte
float     voltage;  // four bytes

So in this case the total length of payload data is five bytes (must not exceed eight bytes).
For our convenience, the "<<" (append) operator (defined in CANMsg library) is used to add data to the CAN message.
The usage of "<<" and ">>" operators is similar to the C++ io-streams operators. We can append data one at a time

txMsg << counter;
txMsg << voltage;

or combine all into one expression.

txMsg << counter << voltage;

The actual data length of a CAN message is automatically updated when using "<<" or ">>" operators.
After successful transmission the CAN message is printed to the serial terminal of the connected PC. So we can check the details (ID, type, format, length and raw data). If something goes wrong during transmission a "Transmission error" message is printed to the serial terminal.

On arrival of a CAN message it's also printed to the serial terminal of the connected PC. So we can see the details (ID, type, format, length and raw data). Then its ID is checked. If there is a match with the ID of awaited message then data is extracted from the CAN message (in the same sequence as it was appended before transmitting) using the ">>" (extract) operator one at a time

rxMsg >> counter;
rxMsg >> voltage;

or all in one shot

rxMsg >> counter >> voltage;


The same source code is used for both boards, but:

  • For board #1 compile the example without any change to main.cpp
  • For board #2 comment out the line #define BOARD1 1 before compiling

Once binaries have been downloaded to the boards reset both board at the same time.

NOTE:

The code published here was written for the official NUCLEO boards. When using STM32F103C8T6 boards, shown in the picture above (on-board LED is active on 0),

  • Include (uncomment) the line #define TARGET_STM32F103C8T6 1
  • Select NUCLEO-F103RB as target platform for the online compiler.

CAN bus related information

Committer:
hudakz
Date:
Fri Feb 08 13:16:55 2019 +0000
Revision:
9:3211e88e30a5
Parent:
8:c65afde7f7f5
Updated.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:1b9561cd1c36 1 /*
hudakz 1:6f8ffb2c2dd7 2 * An example showing how to use the mbed CAN API:
hudakz 0:1b9561cd1c36 3 *
hudakz 3:87a128bca8f5 4 * Two affordable (about $2 on ebay) STM32F103C8T6 boards (20kB SRAM, 64kB Flash),
hudakz 1:6f8ffb2c2dd7 5 * (see [https://developer.mbed.org/users/hudakz/code/STM32F103C8T6_Hello/] for more details)
hudakz 0:1b9561cd1c36 6 * are connected to the same CAN bus via transceivers (MCP2551 or TJA1040, or etc.).
hudakz 0:1b9561cd1c36 7 * CAN transceivers are not part of NUCLEO boards, therefore must be added by you.
hudakz 0:1b9561cd1c36 8 * Remember also that CAN bus (even a short one) must be terminated with 120 Ohm resitors at both ends.
hudakz 1:6f8ffb2c2dd7 9 *
hudakz 0:1b9561cd1c36 10 *
hudakz 1:6f8ffb2c2dd7 11 * The same code is used for both mbed boards, but:
hudakz 0:1b9561cd1c36 12 * For board #1 compile the example without any change.
hudakz 3:87a128bca8f5 13 * For board #2 comment out line 21 before compiling
hudakz 0:1b9561cd1c36 14 *
hudakz 3:87a128bca8f5 15 * Once the binaries have been downloaded to the boards reset both boards at the same time.
hudakz 0:1b9561cd1c36 16 *
hudakz 0:1b9561cd1c36 17 */
hudakz 1:6f8ffb2c2dd7 18
hudakz 8:c65afde7f7f5 19 //#define TARGET_STM32F103C8T6 1 // uncomment this line to use STM32F103C8T6 boards
hudakz 4:09d564da0e24 20
hudakz 4:09d564da0e24 21 #define BOARD1 1 // comment out this line when compiling for board #2
hudakz 0:1b9561cd1c36 22
hudakz 0:1b9561cd1c36 23 #if defined(TARGET_STM32F103C8T6)
hudakz 7:883da97339ab 24 #define LED_PIN PC_13
hudakz 7:883da97339ab 25 const int OFF = 1;
hudakz 7:883da97339ab 26 const int ON = 0;
hudakz 0:1b9561cd1c36 27 #else
hudakz 7:883da97339ab 28 #define LED_PIN LED1
hudakz 7:883da97339ab 29 const int OFF = 0;
hudakz 7:883da97339ab 30 const int ON = 1;
hudakz 0:1b9561cd1c36 31 #endif
hudakz 7:883da97339ab 32
hudakz 0:1b9561cd1c36 33 #if defined(BOARD1)
hudakz 7:883da97339ab 34 const unsigned int RX_ID = 0x100;
hudakz 7:883da97339ab 35 const unsigned int TX_ID = 0x101;
hudakz 0:1b9561cd1c36 36 #else
hudakz 7:883da97339ab 37 const unsigned int RX_ID = 0x101;
hudakz 7:883da97339ab 38 const unsigned int TX_ID = 0x100;
hudakz 0:1b9561cd1c36 39 #endif
hudakz 7:883da97339ab 40
hudakz 0:1b9561cd1c36 41 #include "mbed.h"
hudakz 0:1b9561cd1c36 42 #include "CANMsg.h"
hudakz 0:1b9561cd1c36 43
hudakz 3:87a128bca8f5 44 Serial pc(USBTX, USBRX);
hudakz 4:09d564da0e24 45 CAN can(PB_8, PB_9); // CAN Rx pin name, CAN Tx pin name
hudakz 9:3211e88e30a5 46 //CAN can(p30, p29); // CAN Rx pin name, CAN Tx pin name
hudakz 0:1b9561cd1c36 47 CANMsg rxMsg;
hudakz 0:1b9561cd1c36 48 CANMsg txMsg;
hudakz 0:1b9561cd1c36 49 DigitalOut led(LED_PIN);
hudakz 0:1b9561cd1c36 50 Timer timer;
hudakz 0:1b9561cd1c36 51 uint8_t counter = 0;
hudakz 0:1b9561cd1c36 52 AnalogIn analogIn(A0);
hudakz 0:1b9561cd1c36 53 float voltage;
hudakz 0:1b9561cd1c36 54
hudakz 0:1b9561cd1c36 55 /**
hudakz 8:c65afde7f7f5 56 * @brief Prints CAN message to PC's serial terminal
hudakz 2:6546e4a2d593 57 * @note
hudakz 1:6f8ffb2c2dd7 58 * @param CANMessage to print
hudakz 3:87a128bca8f5 59 * @retval
hudakz 0:1b9561cd1c36 60 */
hudakz 5:37ab4112d547 61 void printMsg(CANMessage& msg)
hudakz 5:37ab4112d547 62 {
hudakz 0:1b9561cd1c36 63 pc.printf(" ID = 0x%.3x\r\n", msg.id);
hudakz 0:1b9561cd1c36 64 pc.printf(" Type = %d\r\n", msg.type);
hudakz 0:1b9561cd1c36 65 pc.printf(" Format = %d\r\n", msg.format);
hudakz 0:1b9561cd1c36 66 pc.printf(" Length = %d\r\n", msg.len);
hudakz 0:1b9561cd1c36 67 pc.printf(" Data =");
hudakz 0:1b9561cd1c36 68 for(int i = 0; i < msg.len; i++)
hudakz 0:1b9561cd1c36 69 pc.printf(" 0x%.2X", msg.data[i]);
hudakz 0:1b9561cd1c36 70 pc.printf("\r\n");
hudakz 0:1b9561cd1c36 71 }
hudakz 0:1b9561cd1c36 72
hudakz 0:1b9561cd1c36 73 /**
hudakz 5:37ab4112d547 74 * @brief Handles received CAN messages
hudakz 8:c65afde7f7f5 75 * @note Called on 'CAN message received' interrupt.
hudakz 5:37ab4112d547 76 * @param
hudakz 5:37ab4112d547 77 * @retval
hudakz 5:37ab4112d547 78 */
hudakz 5:37ab4112d547 79 void onCanReceived(void)
hudakz 5:37ab4112d547 80 {
hudakz 5:37ab4112d547 81 can.read(rxMsg);
hudakz 9:3211e88e30a5 82 pc.printf("-------------------------------------\r\n");
hudakz 9:3211e88e30a5 83 pc.printf("CAN message received\r\n");
hudakz 5:37ab4112d547 84 printMsg(rxMsg);
hudakz 5:37ab4112d547 85
hudakz 5:37ab4112d547 86 if (rxMsg.id == RX_ID) {
hudakz 5:37ab4112d547 87 // extract data from the received CAN message
hudakz 8:c65afde7f7f5 88 // in the same order as it was added on the transmitter side
hudakz 5:37ab4112d547 89 rxMsg >> counter;
hudakz 5:37ab4112d547 90 rxMsg >> voltage;
hudakz 5:37ab4112d547 91 pc.printf(" counter = %d\r\n", counter);
hudakz 5:37ab4112d547 92 pc.printf(" voltage = %e V\r\n", voltage);
hudakz 5:37ab4112d547 93 }
hudakz 8:c65afde7f7f5 94 timer.start(); // to transmit next message in main
hudakz 5:37ab4112d547 95 }
hudakz 5:37ab4112d547 96
hudakz 5:37ab4112d547 97
hudakz 5:37ab4112d547 98 /**
hudakz 0:1b9561cd1c36 99 * @brief Main
hudakz 0:1b9561cd1c36 100 * @note
hudakz 0:1b9561cd1c36 101 * @param
hudakz 0:1b9561cd1c36 102 * @retval
hudakz 0:1b9561cd1c36 103 */
hudakz 0:1b9561cd1c36 104 int main(void)
hudakz 0:1b9561cd1c36 105 {
hudakz 8:c65afde7f7f5 106 pc.baud(9600); // set serial speed
hudakz 8:c65afde7f7f5 107 can.frequency(1000000); // set CAN bit rate to 1Mbps
hudakz 5:37ab4112d547 108 can.filter(RX_ID, 0xFFF, CANStandard, 0); // set filter #0 to accept only standard messages with ID == RX_ID
hudakz 8:c65afde7f7f5 109 can.attach(onCanReceived); // attach ISR to handle received messages
hudakz 5:37ab4112d547 110
hudakz 0:1b9561cd1c36 111 #if defined(BOARD1)
hudakz 1:6f8ffb2c2dd7 112 led = ON; // turn the LED on
hudakz 1:6f8ffb2c2dd7 113 timer.start(); // start timer
hudakz 1:6f8ffb2c2dd7 114 pc.printf("CAN_Hello board #1\r\n");
hudakz 0:1b9561cd1c36 115 #else
hudakz 0:1b9561cd1c36 116 led = OFF; // turn LED off
hudakz 1:6f8ffb2c2dd7 117 pc.printf("CAN_Hello board #2\r\n");
hudakz 0:1b9561cd1c36 118 #endif
hudakz 0:1b9561cd1c36 119 while(1) {
hudakz 9:3211e88e30a5 120 if(timer.read_ms() >= 2000) { // check for timeout
hudakz 3:87a128bca8f5 121 timer.stop(); // stop timer
hudakz 3:87a128bca8f5 122 timer.reset(); // reset timer
hudakz 3:87a128bca8f5 123 counter++; // increment counter
hudakz 5:37ab4112d547 124 voltage = analogIn * 3.3f; // read the small drift voltage from analog input
hudakz 3:87a128bca8f5 125 txMsg.clear(); // clear Tx message storage
hudakz 3:87a128bca8f5 126 txMsg.id = TX_ID; // set ID
hudakz 5:37ab4112d547 127 // append data (total data length must not exceed 8 bytes!)
hudakz 5:37ab4112d547 128 txMsg << counter; // one byte
hudakz 5:37ab4112d547 129 txMsg << voltage; // four bytes
hudakz 5:37ab4112d547 130
hudakz 3:87a128bca8f5 131 if(can.write(txMsg)) { // transmit message
hudakz 3:87a128bca8f5 132 led = OFF; // turn the LED off
hudakz 0:1b9561cd1c36 133 pc.printf("-------------------------------------\r\n");
hudakz 9:3211e88e30a5 134 pc.printf("-------------------------------------\r\n");
hudakz 0:1b9561cd1c36 135 pc.printf("CAN message sent\r\n");
hudakz 0:1b9561cd1c36 136 printMsg(txMsg);
hudakz 0:1b9561cd1c36 137 pc.printf(" counter = %d\r\n", counter);
hudakz 0:1b9561cd1c36 138 pc.printf(" voltage = %e V\r\n", voltage);
hudakz 0:1b9561cd1c36 139 }
hudakz 0:1b9561cd1c36 140 else
hudakz 0:1b9561cd1c36 141 pc.printf("Transmission error\r\n");
hudakz 0:1b9561cd1c36 142 }
hudakz 0:1b9561cd1c36 143 }
hudakz 0:1b9561cd1c36 144 }