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 Mar 17 16:38:46 2017 +0000
Revision:
0:1b9561cd1c36
Child:
1:6f8ffb2c2dd7
Initial release.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:1b9561cd1c36 1 /*
hudakz 0:1b9561cd1c36 2 * A demo showing how to use CAN bus and the CANMsg library's << (append) and the >> (extract) operators
hudakz 0:1b9561cd1c36 3 *
hudakz 0:1b9561cd1c36 4 * Two affordable (less than $3 on ebay) STM32F103C8T6 boards (20kB SRAM, 64kB Flash),
hudakz 0:1b9561cd1c36 5 * are connected to the same CAN bus via transceivers (MCP2551 or TJA1040, or etc.).
hudakz 0:1b9561cd1c36 6 * CAN transceivers are not part of NUCLEO boards, therefore must be added by you.
hudakz 0:1b9561cd1c36 7 * Remember also that CAN bus (even a short one) must be terminated with 120 Ohm resitors at both ends.
hudakz 0:1b9561cd1c36 8 * In this demo, the mbed board is transmitting two data items to the CAN bus.
hudakz 0:1b9561cd1c36 9 * counter: uint_8 value (one byte).
hudakz 0:1b9561cd1c36 10 * voltage: floating point value (four bytes).
hudakz 0:1b9561cd1c36 11 * So the total length of payload data is five bytes.
hudakz 0:1b9561cd1c36 12 * The "<<" (append) operator is used to add data to the CAN message.
hudakz 0:1b9561cd1c36 13 * If a CAN message is received its ID is checked. If there is match with the awaited ID
hudakz 0:1b9561cd1c36 14 * then data is extracted from the CAN message using the ">>" (extract) operator.
hudakz 0:1b9561cd1c36 15 *
hudakz 0:1b9561cd1c36 16 * The usage of "<<" and ">>" operators is similar to the C++ io-stream ones.
hudakz 0:1b9561cd1c36 17 * Data length of CAN message is automatically updated when using "<<" or ">>" operators.
hudakz 0:1b9561cd1c36 18 *
hudakz 0:1b9561cd1c36 19 * For schematic see the wiki page <https://developer.mbed.org/users/hudakz/code/CAN_Hello/>
hudakz 0:1b9561cd1c36 20 *
hudakz 0:1b9561cd1c36 21 * NOTE: If you'd like to use an STM32F103C8T6 board uncomment line 28
hudakz 0:1b9561cd1c36 22 *
hudakz 0:1b9561cd1c36 23 * The same code is used for both NUCLEO boards, but:
hudakz 0:1b9561cd1c36 24 * For board #1 compile the example without any change.
hudakz 0:1b9561cd1c36 25 * For board #2 comment out line 27 before compilation
hudakz 0:1b9561cd1c36 26 *
hudakz 0:1b9561cd1c36 27 * Once the binaries have been downloaded to the boards reset board #1.
hudakz 0:1b9561cd1c36 28 *
hudakz 0:1b9561cd1c36 29 */
hudakz 0:1b9561cd1c36 30 #define BOARD1 1 // comment out this line when compiling for board #2
hudakz 0:1b9561cd1c36 31 //#define TARGET_STM32F103C8T6 1 // uncomment this line when using STM32F103C8T6 boards!
hudakz 0:1b9561cd1c36 32
hudakz 0:1b9561cd1c36 33 #if defined(TARGET_STM32F103C8T6)
hudakz 0:1b9561cd1c36 34 #include "stm32f103c8t6.h"
hudakz 0:1b9561cd1c36 35 #define LED_PIN PC_13
hudakz 0:1b9561cd1c36 36 const int OFF = 1;
hudakz 0:1b9561cd1c36 37 const int ON = 0;
hudakz 0:1b9561cd1c36 38 #else
hudakz 0:1b9561cd1c36 39 #define LED_PIN LED1
hudakz 0:1b9561cd1c36 40 const int OFF = 0;
hudakz 0:1b9561cd1c36 41 const int ON = 1;
hudakz 0:1b9561cd1c36 42 #endif
hudakz 0:1b9561cd1c36 43 #if defined(BOARD1)
hudakz 0:1b9561cd1c36 44 const unsigned int RX_ID = 0x100;
hudakz 0:1b9561cd1c36 45 const unsigned int TX_ID = 0x101;
hudakz 0:1b9561cd1c36 46 #else
hudakz 0:1b9561cd1c36 47 const unsigned int RX_ID = 0x101;
hudakz 0:1b9561cd1c36 48 const unsigned int TX_ID = 0x100;
hudakz 0:1b9561cd1c36 49 #endif
hudakz 0:1b9561cd1c36 50
hudakz 0:1b9561cd1c36 51 #include "mbed.h"
hudakz 0:1b9561cd1c36 52 #include "CANMsg.h"
hudakz 0:1b9561cd1c36 53
hudakz 0:1b9561cd1c36 54 Serial pc(USBTX, USBRX);
hudakz 0:1b9561cd1c36 55 CAN can(PA_11, PA_12); // CAN Rx pin name, CAN Tx pin name
hudakz 0:1b9561cd1c36 56 CANMsg rxMsg;
hudakz 0:1b9561cd1c36 57 CANMsg txMsg;
hudakz 0:1b9561cd1c36 58 DigitalOut led(LED_PIN);
hudakz 0:1b9561cd1c36 59 Timer timer;
hudakz 0:1b9561cd1c36 60 uint8_t counter = 0;
hudakz 0:1b9561cd1c36 61 AnalogIn analogIn(A0);
hudakz 0:1b9561cd1c36 62 float voltage;
hudakz 0:1b9561cd1c36 63
hudakz 0:1b9561cd1c36 64 /**
hudakz 0:1b9561cd1c36 65 * @brief Prints CAN msg to PC's serial terminal
hudakz 0:1b9561cd1c36 66 * @note}
hudakz 0:1b9561cd1c36 67 * @param CANMess to print
hudakz 0:1b9561cd1c36 68 * @retval none
hudakz 0:1b9561cd1c36 69 */
hudakz 0:1b9561cd1c36 70 void printMsg(CANMsg& msg) {
hudakz 0:1b9561cd1c36 71 pc.printf(" ID = 0x%.3x\r\n", msg.id);
hudakz 0:1b9561cd1c36 72 pc.printf(" Type = %d\r\n", msg.type);
hudakz 0:1b9561cd1c36 73 pc.printf(" Format = %d\r\n", msg.format);
hudakz 0:1b9561cd1c36 74 pc.printf(" Length = %d\r\n", msg.len);
hudakz 0:1b9561cd1c36 75 pc.printf(" Data =");
hudakz 0:1b9561cd1c36 76 for(int i = 0; i < msg.len; i++)
hudakz 0:1b9561cd1c36 77 pc.printf(" 0x%.2X", msg.data[i]);
hudakz 0:1b9561cd1c36 78 pc.printf("\r\n");
hudakz 0:1b9561cd1c36 79 }
hudakz 0:1b9561cd1c36 80
hudakz 0:1b9561cd1c36 81 /**
hudakz 0:1b9561cd1c36 82 * @brief Main
hudakz 0:1b9561cd1c36 83 * @note
hudakz 0:1b9561cd1c36 84 * @param
hudakz 0:1b9561cd1c36 85 * @retval
hudakz 0:1b9561cd1c36 86 */
hudakz 0:1b9561cd1c36 87 int main(void)
hudakz 0:1b9561cd1c36 88 {
hudakz 0:1b9561cd1c36 89 #if defined(TARGET_STM32F103C8T6)
hudakz 0:1b9561cd1c36 90 confSysClock(); //Configure system clock (72MHz HSE clock, 48MHz USB clock)
hudakz 0:1b9561cd1c36 91 #endif
hudakz 0:1b9561cd1c36 92
hudakz 0:1b9561cd1c36 93 pc.baud(9600); // set Serial speed
hudakz 0:1b9561cd1c36 94 can.frequency(1000000); // set bit rate to 1Mbps
hudakz 0:1b9561cd1c36 95
hudakz 0:1b9561cd1c36 96 #if defined(BOARD1)
hudakz 0:1b9561cd1c36 97 led = ON; // turn LED on
hudakz 0:1b9561cd1c36 98 timer.start(); // start timer
hudakz 0:1b9561cd1c36 99 pc.printf("CANnucleo_Hello board #1\r\n");
hudakz 0:1b9561cd1c36 100 #else
hudakz 0:1b9561cd1c36 101 led = OFF; // turn LED off
hudakz 0:1b9561cd1c36 102 pc.printf("CANnucleo_Hello board #2\r\n");
hudakz 0:1b9561cd1c36 103 #endif
hudakz 0:1b9561cd1c36 104
hudakz 0:1b9561cd1c36 105 while(1) {
hudakz 0:1b9561cd1c36 106 if(timer.read_ms() >= 1000) {
hudakz 0:1b9561cd1c36 107
hudakz 0:1b9561cd1c36 108 // check for timeout
hudakz 0:1b9561cd1c36 109 timer.stop(); // stop timer
hudakz 0:1b9561cd1c36 110 timer.reset(); // reset timer
hudakz 0:1b9561cd1c36 111 counter++; // increment counter
hudakz 0:1b9561cd1c36 112 voltage = (analogIn * 3.3f) / 4096.0f; // read the small drifting voltage from analog input
hudakz 0:1b9561cd1c36 113 txMsg.clear(); // clear Tx message storage
hudakz 0:1b9561cd1c36 114 txMsg.id = TX_ID; // set ID
hudakz 0:1b9561cd1c36 115 txMsg << counter << voltage; // append data (total data length must be <= 8 bytes!)
hudakz 0:1b9561cd1c36 116 if(can.write(txMsg)) {
hudakz 0:1b9561cd1c36 117
hudakz 0:1b9561cd1c36 118 // transmit message
hudakz 0:1b9561cd1c36 119 led = OFF; // turn LED off
hudakz 0:1b9561cd1c36 120 pc.printf("-------------------------------------\r\n");
hudakz 0:1b9561cd1c36 121 pc.printf("CAN message sent\r\n");
hudakz 0:1b9561cd1c36 122 printMsg(txMsg);
hudakz 0:1b9561cd1c36 123 pc.printf(" counter = %d\r\n", counter);
hudakz 0:1b9561cd1c36 124 pc.printf(" voltage = %e V\r\n", voltage);
hudakz 0:1b9561cd1c36 125 }
hudakz 0:1b9561cd1c36 126 else
hudakz 0:1b9561cd1c36 127 pc.printf("Transmission error\r\n");
hudakz 0:1b9561cd1c36 128 }
hudakz 0:1b9561cd1c36 129
hudakz 0:1b9561cd1c36 130 if(can.read(rxMsg)) {
hudakz 0:1b9561cd1c36 131 led = ON; // turn LED on
hudakz 0:1b9561cd1c36 132 pc.printf("-------------------------------------\r\n");
hudakz 0:1b9561cd1c36 133 pc.printf("CAN message received\r\n");
hudakz 0:1b9561cd1c36 134 printMsg(rxMsg);
hudakz 0:1b9561cd1c36 135
hudakz 0:1b9561cd1c36 136 // Filtering performed by software:
hudakz 0:1b9561cd1c36 137 if(rxMsg.id == RX_ID) {
hudakz 0:1b9561cd1c36 138 rxMsg >> counter >> voltage; // extract data from the received CAN message
hudakz 0:1b9561cd1c36 139 pc.printf(" counter = %d\r\n", counter);
hudakz 0:1b9561cd1c36 140 pc.printf(" voltage = %e V\r\n", voltage);
hudakz 0:1b9561cd1c36 141 timer.start(); // transmission lag
hudakz 0:1b9561cd1c36 142 }
hudakz 0:1b9561cd1c36 143 }
hudakz 0:1b9561cd1c36 144 }
hudakz 0:1b9561cd1c36 145 }