Skip to content

Support CAN FD for STM32 targets #478

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

Conversation

wdx04
Copy link

@wdx04 wdx04 commented Jul 22, 2025

Summary of changes

Added CAN FD support with a data rate up to 8Mbit/s on STM32 L5, G0, G4, H5, H7 and U5 families.
Unified the system_clock.c on STM32U5, as all STM32U5 devices normally work at 160MHz.
Fixed an issue where STM32U5 took too long to restore from deep sleep.

I measured the latency to transmit 64 bytes of data between two CAN FD instances on the same board, with external MCP2562FD PHY modules. The latency of various arbitration+data frequencies are measured on each board.

Board Frequency Latency
Custom STM32H750VB 1M+1M 596μs
Custom STM32H750VB 1M+2M 311μs
Custom STM32H750VB 1M+4M 179μs
Custom STM32H750VB 1M+5M 151μs
Custom STM32H750VB 1M+8M 109μs
Custom STM32H563VI 1M+1M 616μs
Custom STM32H563VI 1M+2M 340μs
Custom STM32H563VI 1M+4M 197μs
Custom STM32H563VI 1M+5M 170μs
NUCLEO-G474RE 1M+1M 674μs
NUCLEO-G474RE 1M+2M 389μs
NUCLEO-G474RE 1M+4M 272μs
NUCLEO-G474RE 1M+5M 234μs
NUCLEO-G474RE 1M+8M 192μs
NUCLEO-G0B1RE 1M+1M 832μs
NUCLEO-G0B1RE 1M+2M 556μs
NUCLEO-G0B1RE 1M+4M 424μs

Impact of changes

Migration actions required

No source-level changes are required to existing CAN applications.

Documentation

The CAN FD interface reuses the existing CAN class with a few changes:

  • Constructors and frequency function accepts a new 'data_hz' parameter to specify the frequency of the data phrase. This parameter is ignored if the device does not support CAN FD. If data_hz is zero, CAN FD support is disabled for this CAN instance, it's ony allowed to read/write classical CAN frames. If data_hz equals to hz, CAN FD support is enabled but bit rate switching turned off, then it is possible to read/write CAN FD frames with payloads up to 64 bytes, but with no speedup.
    /** Initialize CAN interface and set the frequency
      *
      * @param rd the read pin
      * @param td the transmit pin
      * @param hz the bus frequency in hertz
      * @param data_hz the data frequency in hertz(CAN FD only)
      */
    CAN(PinName rd, PinName td, int hz, int data_hz = 0);

    /** Initialize CAN interface and set the frequency
      *
      * @param pinmap reference to structure which holds static pinmap
      * @param hz the bus frequency in hertz
      * @param data_hz the data frequency in hertz(CAN FD only)
      */
    CAN(const can_pinmap_t &pinmap, int hz, int data_hz = 0);

    /** Set the frequency of the CAN interface
     *
     *  @param hz The bus frequency in hertz
      * @param data_hz the data frequency in hertz(CAN FD only)
     *
     *  @returns
     *    1 if successful,
     *    0 otherwise
     */
    int frequency(int hz, int data_hz = 0);
  • New overloads of read/write functions to operate on CAN FD messages. Note even if CAN FD support is enabled, the old read/write function can still be used to communicate with other CAN 2.0 devices in a mixed network. The new read function can also read classical CAN messages.
#if DEVICE_CAN_FD

    /** Write a CANFDMessage to the bus.
     *
     *  @param msg The CANFDMessage to write.
     *
     *  @returns
     *    0 if write failed,
     *    1 if write was successful
     */
    int write(CANFDMessage msg);

    /** Read a CANFDMessage from the bus.
     *
     *  @param msg A CANFDMessage to read to.
     *  @param handle message filter handle (0 for any message)
     *
     *  @returns
     *    0 if no message arrived,
     *    1 if message arrived
     */
    int read(CANFDMessage &msg, int handle = 0);

#endif

A new struct, CANFD_Message is used to holder CAN FD messages with payload size up to 64 bytes:

struct CANFD_Message {
    unsigned int   id;                 // 29 bit identifier
    unsigned char  data[64];            // Data field
    unsigned char  len;                // Length of data field in bytes
    CANFormat      format;             // Format ::CANFormat
    CANType        type;               // Type ::CANType
};
typedef struct CANFD_Message CANFD_Message;

To support CAN FD on new targets, it is required to implemented these functions:

#if DEVICE_CAN_FD
void          canfd_init_freq(can_t *obj, PinName rd, PinName td, int hz, int data_hz);
void          canfd_init_freq_direct(can_t *obj, const can_pinmap_t *pinmap, int hz, int data_hz);
int           canfd_frequency(can_t *obj, int hz, int data_hz);
int           canfd_write(can_t *obj, CANFD_Message, int cc);
int           canfd_read(can_t *obj, CANFD_Message *msg, int handle);
#endif

Pull request type

[] Patch update (Bug fix / Target update / Docs update / Test update / Refactor)
[X] Feature update (New feature / Functionality change / New API)
[] Major update (Breaking change E.g. Return code change / API behaviour change)

Test results

[] No Tests required for this change (E.g docs only update)
[] Covered by existing mbed-os tests (Greentea or Unittest)
[X] Tests / results supplied as part of this PR

Currently there are no existing CAN-related greentea tests, so I tested with a minimal CAN FD test application.
For devices with two or more CAN FD instanes, CAN1 is used to send 64 bytes of data to CAN2(CAN3 on STM32G474) on the same device, then the received data is verified for correctness. For devices with only one CAN FD instance(L5 and U5), two boards are used for the test, where one board acts as sender and another board acts as receiver.

To test if the unified system_clock.c is working properly, I also run greentea tests on NUCLEO-U545RE-Q. There is one failed test: mbed-hal-common-tickers. More precisely, ticker_disable_test and ticker_overflow_test are failed. I found ticker_disable_test is added recently and ticker_overflow_test has been modified recently. If I revert the test code to a previous version, the mbed-hal-common-tickers is passable. Maybe the new/modified tests are too strict for some targets.


greentea-nucleo-u545re-q.txt
can-fd-test.zip

wdx04 added 5 commits July 14, 2025 14:34
enable MSIPLL auto calibration for L5,U5 serieses
adjusted PLL1Q clock for H5, H7 series to enable CAN FD a data rate of 5 MBit/s
…TM32U5 improve the speed of recovery from stop mode
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants