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:
Wed Apr 25 12:00:10 2018 +0000
Revision:
4:09d564da0e24
Parent:
3:87a128bca8f5
Child:
5:37ab4112d547
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 1:6f8ffb2c2dd7 10 * For more details see the wiki page <https://developer.mbed.org/users/hudakz/code/CAN_Hello/>
hudakz 0:1b9561cd1c36 11 *
hudakz 4:09d564da0e24 12 * NOTE: When using an STM32F103C8T6 board uncomment line 22 and import the mbed-STM32F103C8T6 library
hudakz 0:1b9561cd1c36 13 *
hudakz 1:6f8ffb2c2dd7 14 * The same code is used for both mbed boards, but:
hudakz 0:1b9561cd1c36 15 * For board #1 compile the example without any change.
hudakz 3:87a128bca8f5 16 * For board #2 comment out line 21 before compiling
hudakz 0:1b9561cd1c36 17 *
hudakz 3:87a128bca8f5 18 * Once the binaries have been downloaded to the boards reset both boards at the same time.
hudakz 0:1b9561cd1c36 19 *
hudakz 0:1b9561cd1c36 20 */
hudakz 1:6f8ffb2c2dd7 21
hudakz 4:09d564da0e24 22 //#define TARGET_STM32F103C8T6 1 // uncomment this line and import the mbed-STM32F103C8T6 library when using STM32F103C8T6 boards!
hudakz 4:09d564da0e24 23
hudakz 4:09d564da0e24 24 #define BOARD1 1 // comment out this line when compiling for board #2
hudakz 0:1b9561cd1c36 25
hudakz 0:1b9561cd1c36 26 #if defined(TARGET_STM32F103C8T6)
hudakz 0:1b9561cd1c36 27 #include "stm32f103c8t6.h"
hudakz 0:1b9561cd1c36 28 #define LED_PIN PC_13
hudakz 0:1b9561cd1c36 29 const int OFF = 1;
hudakz 0:1b9561cd1c36 30 const int ON = 0;
hudakz 0:1b9561cd1c36 31 #else
hudakz 0:1b9561cd1c36 32 #define LED_PIN LED1
hudakz 0:1b9561cd1c36 33 const int OFF = 0;
hudakz 0:1b9561cd1c36 34 const int ON = 1;
hudakz 0:1b9561cd1c36 35 #endif
hudakz 0:1b9561cd1c36 36 #if defined(BOARD1)
hudakz 0:1b9561cd1c36 37 const unsigned int RX_ID = 0x100;
hudakz 0:1b9561cd1c36 38 const unsigned int TX_ID = 0x101;
hudakz 0:1b9561cd1c36 39 #else
hudakz 0:1b9561cd1c36 40 const unsigned int RX_ID = 0x101;
hudakz 0:1b9561cd1c36 41 const unsigned int TX_ID = 0x100;
hudakz 0:1b9561cd1c36 42 #endif
hudakz 0:1b9561cd1c36 43 #include "mbed.h"
hudakz 0:1b9561cd1c36 44 #include "CANMsg.h"
hudakz 0:1b9561cd1c36 45
hudakz 3:87a128bca8f5 46 Serial pc(USBTX, USBRX);
hudakz 4:09d564da0e24 47 CAN can(PB_8, PB_9); // CAN Rx pin name, CAN Tx pin name
hudakz 0:1b9561cd1c36 48 CANMsg rxMsg;
hudakz 0:1b9561cd1c36 49 CANMsg txMsg;
hudakz 0:1b9561cd1c36 50 DigitalOut led(LED_PIN);
hudakz 0:1b9561cd1c36 51 Timer timer;
hudakz 0:1b9561cd1c36 52 uint8_t counter = 0;
hudakz 0:1b9561cd1c36 53 AnalogIn analogIn(A0);
hudakz 0:1b9561cd1c36 54 float voltage;
hudakz 0:1b9561cd1c36 55
hudakz 0:1b9561cd1c36 56 /**
hudakz 0:1b9561cd1c36 57 * @brief Prints CAN msg to PC's serial terminal
hudakz 2:6546e4a2d593 58 * @note
hudakz 1:6f8ffb2c2dd7 59 * @param CANMessage to print
hudakz 3:87a128bca8f5 60 * @retval
hudakz 0:1b9561cd1c36 61 */
hudakz 1:6f8ffb2c2dd7 62 void printMsg(CANMessage& msg) {
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 0:1b9561cd1c36 74 * @brief Main
hudakz 0:1b9561cd1c36 75 * @note
hudakz 0:1b9561cd1c36 76 * @param
hudakz 0:1b9561cd1c36 77 * @retval
hudakz 0:1b9561cd1c36 78 */
hudakz 0:1b9561cd1c36 79 int main(void)
hudakz 0:1b9561cd1c36 80 {
hudakz 0:1b9561cd1c36 81 #if defined(TARGET_STM32F103C8T6)
hudakz 1:6f8ffb2c2dd7 82 confSysClock(); //Configure system clock (72MHz HSE clock, 48MHz USB clock)
hudakz 0:1b9561cd1c36 83 #endif
hudakz 1:6f8ffb2c2dd7 84 pc.baud(9600); // set Serial speed
hudakz 1:6f8ffb2c2dd7 85 can.frequency(1000000); // set bit rate to 1Mbps
hudakz 0:1b9561cd1c36 86 #if defined(BOARD1)
hudakz 1:6f8ffb2c2dd7 87 led = ON; // turn the LED on
hudakz 1:6f8ffb2c2dd7 88 timer.start(); // start timer
hudakz 1:6f8ffb2c2dd7 89 pc.printf("CAN_Hello board #1\r\n");
hudakz 0:1b9561cd1c36 90 #else
hudakz 0:1b9561cd1c36 91 led = OFF; // turn LED off
hudakz 1:6f8ffb2c2dd7 92 pc.printf("CAN_Hello board #2\r\n");
hudakz 0:1b9561cd1c36 93 #endif
hudakz 0:1b9561cd1c36 94 while(1) {
hudakz 3:87a128bca8f5 95 if(timer.read_ms() >= 1000) { // check for timeout
hudakz 3:87a128bca8f5 96 timer.stop(); // stop timer
hudakz 3:87a128bca8f5 97 timer.reset(); // reset timer
hudakz 3:87a128bca8f5 98 counter++; // increment counter
hudakz 3:87a128bca8f5 99 voltage = analogIn * 3.3f; // read the small drifting voltage from analog input
hudakz 3:87a128bca8f5 100 txMsg.clear(); // clear Tx message storage
hudakz 3:87a128bca8f5 101 txMsg.id = TX_ID; // set ID
hudakz 3:87a128bca8f5 102 txMsg << counter << voltage; // append data (total data length must not exceed 8 bytes!)
hudakz 3:87a128bca8f5 103 if(can.write(txMsg)) { // transmit message
hudakz 3:87a128bca8f5 104 led = OFF; // turn the LED off
hudakz 0:1b9561cd1c36 105 pc.printf("-------------------------------------\r\n");
hudakz 0:1b9561cd1c36 106 pc.printf("CAN message sent\r\n");
hudakz 0:1b9561cd1c36 107 printMsg(txMsg);
hudakz 0:1b9561cd1c36 108 pc.printf(" counter = %d\r\n", counter);
hudakz 0:1b9561cd1c36 109 pc.printf(" voltage = %e V\r\n", voltage);
hudakz 0:1b9561cd1c36 110 }
hudakz 0:1b9561cd1c36 111 else
hudakz 0:1b9561cd1c36 112 pc.printf("Transmission error\r\n");
hudakz 0:1b9561cd1c36 113 }
hudakz 0:1b9561cd1c36 114
hudakz 0:1b9561cd1c36 115 if(can.read(rxMsg)) {
hudakz 1:6f8ffb2c2dd7 116 led = ON; // turn the LED on
hudakz 0:1b9561cd1c36 117 pc.printf("-------------------------------------\r\n");
hudakz 0:1b9561cd1c36 118 pc.printf("CAN message received\r\n");
hudakz 0:1b9561cd1c36 119 printMsg(rxMsg);
hudakz 0:1b9561cd1c36 120
hudakz 0:1b9561cd1c36 121 // Filtering performed by software:
hudakz 0:1b9561cd1c36 122 if(rxMsg.id == RX_ID) {
hudakz 0:1b9561cd1c36 123 rxMsg >> counter >> voltage; // extract data from the received CAN message
hudakz 0:1b9561cd1c36 124 pc.printf(" counter = %d\r\n", counter);
hudakz 0:1b9561cd1c36 125 pc.printf(" voltage = %e V\r\n", voltage);
hudakz 1:6f8ffb2c2dd7 126 timer.start(); // transmission lag
hudakz 0:1b9561cd1c36 127 }
hudakz 0:1b9561cd1c36 128 }
hudakz 0:1b9561cd1c36 129 }
hudakz 0:1b9561cd1c36 130 }