Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
5 years, 1 month ago.
Facing issues in establishing CAN communication between two nodes
I am trying to establish CAN communication between two nodes using NUCLEO-F103RB board and two CAN transceivers SN65HVD230DR. I used 120ohm termination resistance and remaining connections also seem right(i.e I connected transceivers RX pin to NUCLEO TD pin & transceivers TX pin to NUCLEO RD pin). I used the below attached code.
Output: I was getting 0 rderrors and 248 tderrors irrespective of whether I connect CAN transceivers to NUCLEO board or not. can1 is able to send data for the first three loop iterations and after that can1 is also failing to send the message. can2 is not able to receive data from the first loop iteration itself.
Anyone, please help me in establishing communication.
#include "mbed.h" #if defined (DEVICE_CAN) || defined(DOXYGEN_ONLY) Ticker ticker; DigitalOut led1(LED1); DigitalOut led2(LED2); CAN can1(PB_8,PB_9); CAN can2(PA_11,PA_12); char counter = 0; void send() { CANMessage msg1(887, &counter, 1); // create and initialize msg to being the message to send. if(can1.write(msg1)) { // sends the message counter++; printf("MESSAGE SENT: %d, %d\n", counter, msg1.data[0]); led1 = !led1; } else{ printf("Failed to send the message\n"); } printf("CAN1 rderror: %d, tderror: %d\r\n\n", can1.rderror(), can1.tderror() ); } int main() { printf("main()\n"); can2.frequency(250000); can1.frequency(250000); ticker.attach(&send, 2); CANMessage msg; while(1) { if(can2.read(msg)) { printf("Message received: %d\n", msg.data[0]); led2 = !led2; } else{ printf("message not received\n"); } printf("CAN2 rderror: %d, tderror: %d\r\n\n", can2.rderror(), can2.tderror() ); wait(1); } } #else #error CAN NOT SUPPORTED #endif
2 Answers
5 years, 1 month ago.
Hello Dheeraj,
When using Mbed OS 2
try this example.
Because Mbed OS 5
doesn't allow to call CAN's read
method in ISR, replace main.cpp
with the one below when building with Mbed OS 5
:
main.cpp
/* * An example showing how to use the mbed CAN API: * * Two affordable (about $2 on ebay) STM32F103C8T6 boards (20kB SRAM, 64kB Flash), * (see [https://developer.mbed.org/users/hudakz/code/STM32F103C8T6_Hello/] for more details) * 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 you. * Remember also that CAN bus (even a short one) must be terminated with 120 Ohm resitors at both ends. * * * The same code is used for both mbed boards, but: * For board #1 compile the example without any change. * For board #2 comment out line 21 before compiling * * Once the binaries have been downloaded to the boards reset both boards at the same time. * */ //#define TARGET_STM32F103C8T6 1 // uncomment this line to use STM32F103C8T6 boards //#define BOARD1 1 // comment out this line when compiling for board #2 // #if defined(TARGET_STM32F103C8T6) #define LED_PIN PC_13 const int OFF = 1; const int ON = 0; #else #define LED_PIN LED1 const int OFF = 0; const int ON = 1; #endif #if defined(BOARD1) const unsigned int RX_ID = 0x100; const unsigned int TX_ID = 0x101; #else const unsigned int RX_ID = 0x101; const unsigned int TX_ID = 0x100; #endif #include "mbed.h" #include "CANMsg.h" Serial pc(USBTX, USBRX); CAN can(PB_8, PB_9); // CAN Rx pin name, CAN Tx pin name //CAN can(p30, p29); // CAN Rx pin name, CAN Tx pin name CANMsg rxMsg; CANMsg txMsg; DigitalOut led(LED_PIN); Timer timer; uint8_t counter = 0; AnalogIn analogIn(A0); float voltage; /** * @brief Prints CAN message to PC's serial terminal * @note * @param CANMessage to print * @retval */ void printMsg(CANMessage& msg) { pc.printf(" ID = 0x%.3x\r\n", msg.id); pc.printf(" Type = %d\r\n", msg.type); pc.printf(" Format = %d\r\n", msg.format); pc.printf(" Length = %d\r\n", msg.len); pc.printf(" Data ="); for (int i = 0; i < msg.len; i++) pc.printf(" 0x%.2X", msg.data[i]); pc.printf("\r\n"); } /** * @brief Main * @note * @param * @retval */ int main(void) { pc.baud(9600); // set serial speed #if defined(BOARD1) led = ON; // turn the LED on timer.start(); // start timer pc.printf("CAN_Hello board #1\r\n"); #else led = OFF; // turn LED off pc.printf("CAN_Hello board #2\r\n"); #endif can.frequency(1000000); // set CAN bit rate to 1Mbps can.filter(RX_ID, 0xFFF, CANStandard, 0); // set filter #0 to accept only standard messages with ID == RX_ID while (1) { if (timer.read_ms() >= 2000) { // check for timeout timer.stop(); // stop timer timer.reset(); // reset timer counter++; // increment counter voltage = analogIn * 3.3f; // read the small drift voltage from analog input txMsg.clear(); // clear Tx message storage txMsg.id = TX_ID; // set ID // append data (total data length must not exceed 8 bytes!) txMsg << counter; // one byte txMsg << voltage; // four bytes if (can.write(txMsg)) { // transmit message led = OFF; // turn the LED off pc.printf("-------------------------------------\r\n"); pc.printf("-------------------------------------\r\n"); pc.printf("CAN message sent\r\n"); printMsg(txMsg); pc.printf(" counter = %d\r\n", counter); pc.printf(" voltage = %e V\r\n", voltage); } else pc.printf("Transmission error\r\n"); } if (can.read(rxMsg)) { pc.printf("-------------------------------------\r\n"); pc.printf("CAN message received\r\n"); printMsg(rxMsg); led = ON; // turn the LED on if (rxMsg.id == RX_ID) { // extract data from the received CAN message // in the same order as it was added on the transmitter side rxMsg >> counter; rxMsg >> voltage; pc.printf(" counter = %d\r\n", counter); pc.printf(" voltage = %e V\r\n", voltage); } timer.start(); // to transmit next message } } }
Edit:
- When you create two CAN objects by using different pin names also make sure they are associated with different CAN controllers! Your code:
CAN can1(PB_8, PB_9); CAN can2(PA_11, PA_12);
creates two CAN objects, however, they are associated with the same CAN controller (they both represent the CAN1 controller). The NUCLEO-F103RB board is equipped with only one CAN peripheral but fortunately there are available many other Mbed borads equipped with two or more CAN controllers to chose from.
- As Jan says, also check your wiring - compare with the schematics available here.
Hello Zoltan, Thanks for the reply. But, it's not working. My board1 was able to send the first data after 2000ms then after that board2 was not able to receive data as a result of which no further connection is established between the boards. I measured the voltages of CAN_H and CAN_L lines, both were at 2.4V. I connected transceivers RX pin to NUCLEO RD pin & transceivers TX pin to NUCLEO TD pin. And remaining wiring also seems fine. What could be the reason for board2 not receiving data?
posted by 11 Oct 2019- To avoid problems resulting from incompatible mbed library version, please do not update the mbed library when importing the example program into the online compiler.
- For board #1 compile without any modification to
main.cpp
- For board #2 exclude (comment out) the line as below before compilation:
//#define BOARD1 1
- To start testing the communication try to reset both boards at the same time.
5 years, 1 month ago.
Hi there,
The MbedOS5 with bare metal profile is also usable for CAN's read method in the interrupt context.
However if I correctly understand what you wrote, you had crossed wires. The CAN is not like an UART, the TX pin from the Nucleo must be connected to the TX pin on the transceiver and same for the RX.
Best regards, Jan
You beat me to it. Check the datasheet for the CAN transceiver used but almost certainly the issue is a wiring problem. Tx on the CAN transceiver normally means data to transmit on to the CAN bus which means it's an input and should be connected to the Tx output from the processor.
posted by 11 Oct 2019
Hello Dheeraj,
Try to click on the
Edit
button located in the top-right corner and then enclose your source code with<<code>>
and<</code>>
tags, each on separate line, like:Then after clicking on the
posted by Zoltan Hudak 10 Oct 2019Save Question
button it will be displayed as formatted code which can be copy & pasted into the online editor for testing. A picture (png
,bmp
,jpg
) doesn't allow that.