Skip to content

Add CAN support for STM32L4KC #16516

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 2 commits into
base: master
Choose a base branch
from

Conversation

LightDestory
Copy link
Contributor

@LightDestory LightDestory commented Jun 11, 2025

Summary

Nucleo-L432KC provides a CAN1 interface, but the current NuttX configuration misses both the PINs declaration and the setup definition.

Impact

This PR aims to add CAN support to the nucleo-l432kc board and a dedicated configuration where CAN is enabled, so it is available out of the box for testing.

Testing

Trying to compile with the following configuration: CAN1 enabled, CAN Driver enabled, CAN example enabled.
Before PR:
image
After PR:
image

@github-actions github-actions bot added Board: arm Size: M The size of the change in this PR is medium labels Jun 11, 2025
Copy link
Contributor

@cederom cederom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @LightDestory and thank you for your first PR welcome to The NuttX Club :-)

We have automated CI verification for each PR, including build and code formatting, all checks must pass to unblock merge.

I can see formatting needs some update. Please take a look at:

Please update git commit message:

  • topic boards/nucleo-l432kc: add can support and configuration.
  • please add some short description to the commit so people reading the git log will know what/why happened here :-)

All three sections of the PR are mandatory (Summary, Impact, Testing). Please update :-)

  • Impact - adds CAN support to nucleo-l432kc board and dedicated configuration where CAN is enabled so it is available out of the box for testing.
  • Testing - this is very important to show the patch that you provide works and was tested, you can provide build log essentials + testing logs (text preferred).

Added support of CAN so the CAN example can be compiles out-of-the-box without any modification.

Added "nucleo-l432kc:can" config.
@LightDestory
Copy link
Contributor Author

Hello @LightDestory and thank you for your first PR welcome to The NuttX Club :-)

We have automated CI verification for each PR, including build and code formatting, all checks must pass to unblock merge.

I can see formatting needs some update. Please take a look at:

Please update git commit message:

  • topic boards/nucleo-l432kc: add can support and configuration.
  • please add some short description to the commit so people reading the git log will know what/why happened here :-)

All three sections of the PR are mandatory (Summary, Impact, Testing). Please update :-)

  • Impact - adds CAN support to nucleo-l432kc board and dedicated configuration where CAN is enabled so it is available out of the box for testing.
  • Testing - this is very important to show the patch that you provide works and was tested, you can provide build log essentials + testing logs (text preferred).

Thanks for your review. I tried to meet all the requirements.

@LightDestory LightDestory requested a review from cederom June 11, 2025 22:07
Copy link
Contributor

@cederom cederom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @LightDestory :-)

Still some minor formatting issue (see Check CI logs it complains about blank line). You can test on local machine two ways:

./tools/checkpatch.sh -g HEAD~...HEAD
./tools/checkpatch.sh -f path/to/your/file.c

It would be nice if you also provided runtime logs showing that CAN works :-) For me it fails to poen /dev/can0 but I only have one board with no CAN network attached - is this the problem?

nsh> uname -a
NuttX 10.4.0 f4ad320a86 Jun 12 2025 00:45:58 arm nucleo-l432kc
nsh> help
help usage:  help [-v] [<cmd>]

    .           cd          exit        mkrd        sleep       unset
    [           cp          expr        mount       source      uptime
    ?           cmp         false       mv          test        usleep
    alias       dirname     help        printf      time        watch
    unalias     date        hexdump     pwd         true        xd
    basename    dmesg       kill        rm          truncate
    break       echo        ls          rmdir       uname
    cat         exec        mkdir       set         umount

Builtin Apps:
    alarm     can       dd        nsh       ostest    rand      sh
nsh> can
nmsgs: 0
min ID: 1 max ID: 2047
ERROR: open /dev/can0 failed: 110
Terminating!
nsh> ls /dev
/dev:
 can0
 console
 null
 random
 rtc0
 ttyS0
 zero

I also noticed some build warnings in chip/stm32l4_can.c we may want to fix one day (can be separate PR) :-)

% gmake -j24
Create version.h
LN: platform/board to /XXX/nuttx/pr/nuttx-apps.git/platform/dummy
Register: rand
Register: alarm
Register: dd
Register: nsh
Register: ostest
Register: sh
Register: can
CC:  obstack/lib_obstack_grow.c chip/stm32l4_gpio.c:46:11: note: '#pragma message: CONFIG_STM32L4_USE_LEGACY_PINMAP will be deprecated migrate board.h see tools/stm32_pinmap_tool.py'
   46 | #  pragma message "CONFIG_STM32L4_USE_LEGACY_PINMAP will be deprecated migrate board.h see tools/stm32_pinmap_tool.py"
      |           ^~~~~~~
CC:  obstack/lib_obstack_room.c In file included from chip/stm32l4_rcc.c:47:
chip/stm32l4x3xx_rcc.c: In function 'stm32l4_stdclockconfig':
chip/stm32l4x3xx_rcc.c:699:2: warning: #warning todo: regulator voltage according to clock freq [-Wcpp]
  699 | #warning todo: regulator voltage according to clock freq
      |  ^~~~~~~
In file included from chip/stm32l4_can.c:35:
chip/stm32l4_can.c: In function 'stm32l4can_ioctl':
chip/stm32l4_can.c:880:19: warning: format '%d' expects argument of type 'int', but argument 5 has type 'uint32_t' {aka 'long unsigned int'} [-Wformat=]
  880 |           caninfo("TS1: %d TS2: %d BRP: %d\n",
      |                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
  881 |                   bt->bt_tseg1, bt->bt_tseg2, brp);
      |                                               ~~~
      |                                               |
      |                                               uint32_t {aka long unsigned int}
chip/stm32l4_can.c:880:42: note: format string is defined here
  880 |           caninfo("TS1: %d TS2: %d BRP: %d\n",
      |                                         ~^
      |                                          |
      |                                          int
      |                                         %ld
chip/stm32l4_can.c: In function 'stm32l4can_remoterequest':
chip/stm32l4_can.c:1139:2: warning: #warning "Remote request not implemented" [-Wcpp]
 1139 | #warning "Remote request not implemented"
      |  ^~~~~~~
chip/stm32l4_can.c: In function 'stm32l4can_txready':
chip/stm32l4_can.c:1335:11: warning: format '%x' expects argument of type 'unsigned int', but argument 4 has type 'uint32_t' {aka 'long unsigned int'} [-Wformat=]
 1335 |   caninfo("CAN%d TSR: %08x\n", priv->port, regval);
      |           ^~~~~~~~~~~~~~~~~~~              ~~~~~~
      |                                            |
      |                                            uint32_t {aka long unsigned int}
chip/stm32l4_can.c:1335:26: note: format string is defined here
 1335 |   caninfo("CAN%d TSR: %08x\n", priv->port, regval);
      |                       ~~~^
      |                          |
      |                          unsigned int
      |                       %08lx
chip/stm32l4_can.c: In function 'stm32l4can_txempty':
chip/stm32l4_can.c:1366:11: warning: format '%x' expects argument of type 'unsigned int', but argument 4 has type 'uint32_t' {aka 'long unsigned int'} [-Wformat=]
 1366 |   caninfo("CAN%d TSR: %08x\n", priv->port, regval);
      |           ^~~~~~~~~~~~~~~~~~~              ~~~~~~
      |                                            |
      |                                            uint32_t {aka long unsigned int}
CC:  pthread/pthread_attr_getscope.c chip/stm32l4_can.c:1366:26: note: format string is defined here
 1366 |   caninfo("CAN%d TSR: %08x\n", priv->port, regval);
      |                       ~~~^
      |                          |
      |                          unsigned int
      |                       %08lx
chip/stm32l4_can.c: In function 'stm32l4can_bittiming':
chip/stm32l4_can.c:1685:11: warning: format '%d' expects argument of type 'int', but argument 4 has type 'long unsigned int' [-Wformat=]
 1685 |   caninfo("CAN%d PCLK1: %d baud: %d\n",
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
chip/stm32l4_can.c:1685:26: note: format string is defined here
 1685 |   caninfo("CAN%d PCLK1: %d baud: %d\n",
      |                         ~^
      |                          |
      |                          int
      |                         %ld
chip/stm32l4_can.c:1685:11: warning: format '%d' expects argument of type 'int', but argument 5 has type 'uint32_t' {aka 'long unsigned int'} [-Wformat=]
 1685 |   caninfo("CAN%d PCLK1: %d baud: %d\n",
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1686 |           priv->port, STM32L4_PCLK1_FREQUENCY, priv->baud);
      |                                                ~~~~~~~~~~
      |                                                    |
      |                                                    uint32_t {aka long unsigned int}
CC:  common/arm_modifyreg.c chip/stm32l4_can.c:1685:35: note: format string is defined here
 1685 |   caninfo("CAN%d PCLK1: %d baud: %d\n",
      |                                  ~^
      |                                   |
      |                                   int
      |                                  %ld
chip/stm32l4_can.c:1738:11: warning: format '%d' expects argument of type 'int', but argument 3 has type 'uint32_t' {aka 'long unsigned int'} [-Wformat=]
 1738 |   caninfo("TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~  ~~~
      |                                        |
      |                                        uint32_t {aka long unsigned int}
chip/stm32l4_can.c:1738:18: note: format string is defined here
 1738 |   caninfo("TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
      |                 ~^
      |                  |
      |                  int
      |                 %ld
chip/stm32l4_can.c:1738:11: warning: format '%d' expects argument of type 'int', but argument 4 has type 'uint32_t' {aka 'long unsigned int'} [-Wformat=]
 1738 |   caninfo("TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~       ~~~
      |                                             |
      |                                             uint32_t {aka long unsigned int}
chip/stm32l4_can.c:1738:26: note: format string is defined here
 1738 |   caninfo("TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
      |                         ~^
      |                          |
      |                          int
      |                         %ld
chip/stm32l4_can.c:1738:11: warning: format '%d' expects argument of type 'int', but argument 5 has type 'uint32_t' {aka 'long unsigned int'} [-Wformat=]
 1738 |   caninfo("TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~            ~~~
      |                                                  |
      |                                                  uint32_t {aka long unsigned int}
chip/stm32l4_can.c:1738:34: note: format string is defined here
 1738 |   caninfo("TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
      |                                 ~^
      |                                  |
      |                                  int
      |                                 %ld
chip/stm32l4_can.c: In function 'stm32l4can_exitinitmode':
chip/stm32l4_can.c:1857:14: warning: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'uint32_t' {aka 'long unsigned int'} [-Wformat=]
 1857 |       canerr("ERROR: Timed out waiting to exit initialization mode: %08x\n",
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1858 |              regval);
      |              ~~~~~~
      |              |
      |              uint32_t {aka long unsigned int}
chip/stm32l4_can.c:1857:72: note: format string is defined here
 1857 |       canerr("ERROR: Timed out waiting to exit initialization mode: %08x\n",
      |                                                                     ~~~^
      |                                                                        |
      |                                                                        unsigned int
      |                                                                     %08lx
LD: nuttx
Memory region         Used Size  Region Size  %age Used
           flash:      229212 B       256 KB     87.44%
            sram:        9912 B        64 KB     15.12%
CP: nuttx.hex
CP: nuttx.bin

@LightDestory LightDestory marked this pull request as draft June 11, 2025 23:01
@LightDestory
Copy link
Contributor Author

LightDestory commented Jun 11, 2025

I have converted the PR to draft, I will provide text logs of the CAN as soon as I get my hands on the board itself.

Regarding the warnings, I just took as reference the can implementation for the l476rg.

@cederom
Copy link
Contributor

cederom commented Jun 12, 2025

@LightDestory: I have converted the PR to draft, I will provide text logs of the CAN as soon as I get my hands on the board itself.

Thank you :-) In a perfect situation we want to include code that is already verified on a real world hardware. I know this is copy-paste from similar MCU but there may be slight differences that will not allow exact same code to work on different MCU (happened to me recently with stm32) :-)

Regarding the warnings, I just took as reference the can implementation for the l476rg.

It would be nice to update the existing code as well when you know it already and there are known issues :-) This fix updates may come already in this PR as part of L432 but then you will have copy-paste for L476 :-)

Thanks again @LightDestory :-)

@@ -226,7 +226,7 @@ int stm32_bringup(void)

#ifdef CONFIG_CAN
/* Initialize CAN and register the CAN device. */

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's squash into one patch

@LightDestory
Copy link
Contributor Author

image
I can confirm that CAN works on my L4 board :)

@LightDestory LightDestory marked this pull request as ready for review June 25, 2025 12:48
@acassis
Copy link
Contributor

acassis commented Jun 25, 2025

@LightDestory same issue that @cederom pointed early. The issue was not caused by you, but the CI detected that stm32l4_can.c in arch/ has some printing error. Replace %d from those variables that are unsigned int with %u or %" PRIu32 ".

chip/stm32l4_can.c: In function 'stm32l4can_ioctl':
Error: chip/stm32l4_can.c:880:19: error: format '%d' expects argument of type 'int', but argument 5 has type 'uint32_t' {aka 'long unsigned int'} [-Werror=format=]
  880 |           caninfo("TS1: %d TS2: %d BRP: %d\n",
      |                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
  881 |                   bt->bt_tseg1, bt->bt_tseg2, brp);
      |                                               ~~~
      |                                               |
      |                                               uint32_t {aka long unsigned int}
chip/stm32l4_can.c:880:42: note: format string is defined here
  880 |           caninfo("TS1: %d TS2: %d BRP: %d\n",
      |                                         ~^
      |                                          |
      |                                          int
      |                                         %ld
chip/stm32l4_can.c: In function 'stm32l4can_txready':
Error: chip/stm32l4_can.c:1335:11: error: format '%x' expects argument of type 'unsigned int', but argument 4 has type 'uint32_t' {aka 'long unsigned int'} [-Werror=format=]
 1335 |   caninfo("CAN%d TSR: %08x\n", priv->port, regval);
      |           ^~~~~~~~~~~~~~~~~~~              ~~~~~~
      |                                            |
      |                                            uint32_t {aka long unsigned int}
chip/stm32l4_can.c:1335:26: note: format string is defined here
 1335 |   caninfo("CAN%d TSR: %08x\n", priv->port, regval);
      |                       ~~~^
      |                          |
      |                          unsigned int
      |                       %08lx
chip/stm32l4_can.c: In function 'stm32l4can_txempty':
Error: chip/stm32l4_can.c:1366:11: error: format '%x' expects argument of type 'unsigned int', but argument 4 has type 'uint32_t' {aka 'long unsigned int'} [-Werror=format=]
 1366 |   caninfo("CAN%d TSR: %08x\n", priv->port, regval);
      |           ^~~~~~~~~~~~~~~~~~~              ~~~~~~
      |                                            |
      |                                            uint32_t {aka long unsigned int}
chip/stm32l4_can.c:1366:26: note: format string is defined here
 1366 |   caninfo("CAN%d TSR: %08x\n", priv->port, regval);
      |                       ~~~^
      |                          |
      |                          unsigned int
      |                       %08lx
chip/stm32l4_can.c: In function 'stm32l4can_bittiming':
Error: chip/stm32l4_can.c:1685:11: error: format '%d' expects argument of type 'int', but argument 4 has type 'long unsigned int' [-Werror=format=]
 1685 |   caninfo("CAN%d PCLK1: %d baud: %d\n",
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
chip/stm32l4_can.c:1685:26: note: format string is defined here
 1685 |   caninfo("CAN%d PCLK1: %d baud: %d\n",
      |                         ~^
      |                          |
      |                          int
      |                         %ld
Error: chip/stm32l4_can.c:1685:11: error: format '%d' expects argument of type 'int', but argument 5 has type 'uint32_t' {aka 'long unsigned int'} [-Werror=format=]
 1685 |   caninfo("CAN%d PCLK1: %d baud: %d\n",
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1686 |           priv->port, STM32L4_PCLK1_FREQUENCY, priv->baud);
      |                                                ~~~~~~~~~~
      |                                                    |
      |                                                    uint32_t {aka long unsigned int}
chip/stm32l4_can.c:1685:35: note: format string is defined here
 1685 |   caninfo("CAN%d PCLK1: %d baud: %d\n",
      |                                  ~^
      |                                   |
      |                                   int
      |                                  %ld
Error: chip/stm32l4_can.c:1738:11: error: format '%d' expects argument of type 'int', but argument 3 has type 'uint32_t' {aka 'long unsigned int'} [-Werror=format=]
 1738 |   caninfo("TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~  ~~~
      |                                        |
      |                                        uint32_t {aka long unsigned int}
chip/stm32l4_can.c:1738:18: note: format string is defined here
 1738 |   caninfo("TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
      |                 ~^
      |                  |
      |                  int
      |                 %ld
Error: chip/stm32l4_can.c:1738:11: error: format '%d' expects argument of type 'int', but argument 4 has type 'uint32_t' {aka 'long unsigned int'} [-Werror=format=]
 1738 |   caninfo("TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~       ~~~
      |                                             |
      |                                             uint32_t {aka long unsigned int}
chip/stm32l4_can.c:1738:26: note: format string is defined here
 1738 |   caninfo("TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
      |                         ~^
      |                          |
      |                          int
      |                         %ld
Error: chip/stm32l4_can.c:1738:11: error: format '%d' expects argument of type 'int', but argument 5 has type 'uint32_t' {aka 'long unsigned int'} [-Werror=format=]
 1738 |   caninfo("TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~            ~~~
      |                                                  |
      |                                                  uint32_t {aka long unsigned int}
chip/stm32l4_can.c:1738:34: note: format string is defined here
 1738 |   caninfo("TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
      |                                 ~^
      |                                  |
      |                                  int
      |                                 %ld
chip/stm32l4_can.c: In function 'stm32l4can_exitinitmode':
Error: chip/stm32l4_can.c:1857:14: error: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'uint32_t' {aka 'long unsigned int'} [-Werror=format=]
 1857 |       canerr("ERROR: Timed out waiting to exit initialization mode: %08x\n",
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1858 |              regval);
      |              ~~~~~~
      |              |
      |              uint32_t {aka long unsigned int}
chip/stm32l4_can.c:1857:72: note: format string is defined here
 1857 |       canerr("ERROR: Timed out waiting to exit initialization mode: %08x\n",
      |                                                                     ~~~^
      |                                                                        |
      |                                                                        unsigned int
      |                                                                     %08lx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Board: arm Size: M The size of the change in this PR is medium
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants