Basic Extended CAN(BxCan) communication example for Arduino Core STM32.
- STM32F072 Development Board.
- STM32F103 Development Board.
- STM32F303 Development Board.
- STM32F405 Development Board.
- STM32F407 Development Board.
- STM32F413 Development Board.
- STM32F446 Development Board.
- STM32F722 Development Board.
- STM32F767 Development Board.
- STM32L452 Development Board.
- STM32L496 Development Board.
- STM32G431 Development Board.
- CAN Transceiver.
MCP2551/2561/2562(5V)
TJA1040/1050/1051/1055(5V)
SN65HVD230/231/232(3.3V)
NOTE
3V CAN Transceivers are fully interoperable with 5V CAN Transceivers.
Check here.
-
Arduino core support for STM32 based boards.
https://github.com/stm32duino/Arduino_Core_STM32
Note for Core version
Core version 2.8 or later requires Arduino IDE 2.x.
I used version 2.7.1.
This is the final version available for Arduino IDE 1.x.
There is some core library for STM32.
It doesn't work with Arduino STM32.
-
USB power supply (board with 5V pin)
STM32 CAN RX GPIO has 5V tolerant.
-
Board without 5V pin, such as BlackPill, or ST-Link power supply
The Nano on the left is a receiver with a terminating resistor.
The Nano on the right is a transmitter without a terminating resistor.
The STM32 transceiver has a terminating resistor.
The bxCAN Controller provides 14 or 28 configurable and scalable filter banks to the application.
The number of filter banks varies by model and is specified in the Reference manual.
On models with only one CAN port, all filters are available on master port (CAN1).
On models with two CAN ports, all filters are shared between master ports (CAN1) and slave port (CAN2).
In this example, filter banks 0 to 13 are used on CAN1, and filter banks 14 to 27 are used on CAN2.
The bxCAN controller provides four types of receive filters:
Before you can configure a filter, you must set it to filter initialization mode.
uint32_t bank1, bank2;
CAN1->FMR |= 0x1UL; // Set to filter initialization mode
bank1 = your settings
bank2 = your settings
CANSetFilter(0, 0, 1, 0, bank1, bank2);
CAN1->FMR &= ~(0x1UL); // Deactivate initialization mode
This is the simplest usage.
Here is an example for STM32F103.
-
One 32-Bit Filter - Identifier Mask
This can be used for both standard and extended IDs.// One 32-Bit Filter - Identifier Mask int fsc = 1; int fbm = 0; bank1 = 0x101 << 21; bank2 = 0xFFE00006; // Must be IDE=0 RTR=0 CANSetFilter(0, fsc, fbm, 0, bank1, bank2); // One 32-Bit Filter - Identifier Mask bank1 = 0x101 << 3; bank1 = bank1 + 0x04; // Ext bank2 = 0xFFFFFFFE; // Must be IDE=1 RTR=0 CANSetFilter(1, fsc, fbm, 0, bank1, bank2);
-
Two 32-Bit Filters - Identifier List
This can be used for both standard and extended IDs.// Two 32-Bit Filters - Identifier List int fsc = 1; int fbm = 1; bank1 = 0x102 << 21; bank2 = 0x103 << 21; CANSetFilter(0, fsc, fbm, 0, bank1, bank2); bank1 = 0x102 << 3; bank1 = bank1 + 0x04; // Ext bank2 = 0x103 << 3; bank2 = bank2 + 0x04; // Ext CANSetFilter(1, fsc, fbm, 0, bank1, bank2);
-
Two 16-Bit Filters - Identifier Mask
This can only be used with standard IDs.// Two 16-Bit Filters - Identifier Mask int fsc = 0; int fbm = 0; bank1 = 0xFFFF << 16; bank1 = bank1 | 0x104 << 5; bank2 = 0xFFFF << 16; bank2 = bank1 | 0x105 << 5; CANSetFilter(0, fsc, fbm, 0, bank1, bank2);
-
Four 16-Bit Filters - Identifier List
This can only be used with standard IDs.// Four 16-Bit Filters - Identifier List int fsc = 0; int fbm = 1; bank1 = 0x104 << 21; bank1 = bank1 | 0x105 << 5; bank2 = 0x106 << 21; bank2 = bank2 | 0x107 << 5; CANSetFilter(0, fsc, fbm, 0, bank1, bank2);
STM32 has two receive(RX) FIFOs.
Each RX FIFO has three mailboxes and provides access only to the oldest received message in the mailbox.
This sample code uses only the FIFO 0.
The RX FIFO is closely related to the receive filter settings.
By properly setting the receive filter, you can sort the received messages into two RX FIFOs.
For example, high priority messages can be stored in the FIFO0 and low priority messages can be stored in the FIFO1.
As a result, up to six incoming messages can be stored in the mailbox.
Please refer to the reference manual for each model for more information.
Here is an example for STM32F103.
You can use this library.
Arduino-UNO R4 has a built-in CAN controller.
You can use this library.
You can use this library.
You can use this library.
ESP-IDE has a CAN Network example.
https://github.com/espressif/esp-idf/tree/master/examples/peripherals/twai/twai_network
You can use it.
Notes on ESP32 bitrate
In ESP-IDF V4, CONFIG_ESP32_REV_MIN >= 2 means "halve communication speed".
This is to support slower bitrates below 25Kbps.
This fuature can be controlled by CONFIG_ESP32_REV_MIN.
This fuature is enabled when CONFIG_ESP32_REV_MIN >= 2.
See here for detail.
This specification is not available in ESP-IDF V5.
Edit /boot/config.txt and reboot.
dtparam=spi=on
dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25
dtoverlay=spi-bcm2835-overlay
Make sure the device is ready after reboot.
$ dmesg | grep mcp251x
[ 19.992025] mcp251x spi0.0 can0: MCP2515 successfully initialized.
$ ls /sys/bus/spi/devices/spi0.0
driver modalias net of_node power statistics subsystem uevent
$ ls /sys/bus/spi/devices/spi0.0/net
can0
$ sudo /sbin/ip link set can0 up type can bitrate 1000000
$ dmesg | grep can0
[ 19.992025] mcp251x spi0.0 can0: MCP2515 successfully initialized.
[ 1309.525795] IPv6: ADDRCONF(NETDEV_CHANGE): can0: link becomes ready
$ sudo ifconfig can0
can0: flags=193<UP,RUNNING,NOARP> mtu 16
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 10 (UNSPEC)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
$ sudo ifconfig can0 txqueuelen 1000
Install can-utils.
$ sudo apt-get install can-utils
# Receiver
$ candump can0
# Transmitter
$ cansend can0 123#11223344AABBCCDD
There is a module of SN65HVD230 like this.
There is a 120 ohms terminating resistor on the left side.
A transmission fail will occur.
I have removed the terminating resistor.
And I used a external resistance of 150 ohms.
A transmission fail is fixed.
If the transmission fails, these are the possible causes.
- There is no receiving app on CanBus.
- The speed does not match the receiver.
- There is no terminating resistor on the CanBus.
- There are three terminating resistors on the CanBus.
- The resistance value of the terminating resistor is incorrect.
- 3.3V transceiver and 5V transceiver are mixed.
Use +1V Ground Shift using Split Termination.
Check out Figure 7 here. - Stub length in CAN bus is too long.
ISO11898 Standard specifies a maximum bus length of 40m and maximum stub length of 0.3m at 1Mbps. See here. - Noise effects.
It occurs when the wire cable is thin or wire cable is crossing.
It is preferable to use wires that are noise-proof.
I changed the single wire to twisted wire. It's fixed.
Arduino-IDE only supports ST-LINK V2.1 adapters, but OpenOCD used by PlatformIO supports both V2.0 and V2.1.
With ST-LINK, there is no need to change boot mode when writing firmware.
PlatformIO allows you to use cheap Chinese ST-LINK adapters like this one.
You can get it at a low price (about $2).
Connect the ST-LINK adapter and the STM32 development board as follows.
ST-LINK | STM32 |
---|---|
3.3V | 3.3V |
GND | GND |
SWDIO | SWIO(=PA13) |
SWCLK | SWCLK(=PA14) |
Skip if you don't need advanced usage.
Advanced usage has different purposes depending on the requirements of the application.
So I can't give you a concrete code example.
STM32 has three transmit(TX) mailboxes.
Three TX mailboxes are provided to the software for setting up messages.
This sample code uses only the first TX mailbox and blocks the application until the send is successfully completed.
There are two ways to know if the send was successful without blocking.
Read the reference manual carefully and modify the source code as needed.
-
Uses a transmission completion interrupt
You need to set the CAN interrupt enable register (CAN_IER) appropriately. -
Check TX mailbox space before sending
An application can store transmission requests in three TX mailboxes simultaneously.
When there are requests for multiple TX mailboxes, the transmission scheduler decides which mailbox has to be transmitted first.
You can specify which mailbox has priority using the CAN Master Control Register (CAN_MCR).
You can tell if a mailbox is free using the CAN Transmit Status Register (CAN_TSR).
When all three TX mailboxes are pending, no new messages can be sent until the transmit is canceled or completed.
When all three TX mailboxes are pending, you can choose to cancel the pending transmission, wait until the transmission is complete, or give up on the new transmission.
This choice depends on your application requirements.
When all three TX mailboxes are pending for a long time, it could be a transmission error.
CAN Error Status Register (CAN_ESR) should be checked.