Trying to get fdcan working on the UNO Q

I enabled fdcan1 support in both the overlay and config file for the Arduino Uno Q:

arduino_uno_q_stm32u585xx.conf

CONFIG_POLL=y
CONFIG_CAN=y
#CONFIG_CAN_FD_MODE=y

arduino_uno_q_stm32u585xx.overlay

&fdcan1 {
        status = "okay";
        pinctrl-0 = <&fdcan1_rx_pa11 &fdcan1_tx_pa12>;
        pinctrl-names = "default";
};

/ {
        chosen {
                zephyr,canbus = &fdcan1;
        };
};

Not sure if I need to config clocks in &fdcan1 since they are already configured in stm32u5 common.

Then rebuilt core - no issues but the counter test sketch has issues.

Using a slightly modified version of the example: Controller Area Network (CAN) counter — Zephyr Project Documentation I get two distinct errors:

  1. Seems like work queues dont work. So ran a simple test sketch:

#define STACK_SIZE 1024
#define PRIORITY 5

K_THREAD_STACK_DEFINE(my_stack, STACK_SIZE);
static struct k_work_q my_work_q;

static void my_custom_handler(struct k_work *work)
{
    printk("Custom work executed!\n");
}

K_WORK_DEFINE(my_custom_work, my_custom_handler);

void setup(void)
{
    k_work_queue_init(&my_work_q);
    k_work_queue_start(&my_work_q, my_stack,
                       K_THREAD_STACK_SIZEOF(my_stack),
                       PRIORITY, NULL);

    printk("Submitting to custom work queue...\n");
    k_work_submit_to_queue(&my_work_q, &my_custom_work);
}

void loop() {}

and got the following error messages:

/home/arduino/.arduino15/packages/zephyr/tools/arm-zephyr-eabi/0.16.8/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld: /home/arduino/ArduinoApps/ccc/.cache/sketch/sketch/sketch.ino.cpp.o: in function `setup':
/home/arduino/ArduinoApps/ccc/sketch/sketch.ino:23: undefined reference to `k_work_queue_init'
/home/arduino/.arduino15/packages/zephyr/tools/arm-zephyr-eabi/0.16.8/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld: /home/arduino/ArduinoApps/ccc/sketch/sketch.ino:23: undefined reference to `k_work_queue_start'
/home/arduino/.arduino15/packages/zephyr/tools/arm-zephyr-eabi/0.16.8/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld: /home/arduino/ArduinoApps/ccc/sketch/sketch.ino:23: undefined reference to `k_work_submit_to_queue'
collect2: error: ld returned 1 exit status
  1. The function can_send
		can_send(can_dev, &change_led_frame, K_FOREVER,
			 tx_irq_callback,
			 "LED change");

gives

/home/arduino/ArduinoApps/fdcan1_experiment/sketch/sketch.ino:289:26: error: invalid conversion from 'const void*' to 'void*' [-fpermissive]
289 |                          "LED change");
|                          ^~~~~~~~~~~~
|                          |
|                          const void*
In file included from /home/arduino/Arduino/hardware/arduino/zephyr/variants/arduino_uno_q_stm32u585xx/llext-edk/include/zephyr/include/zephyr/drivers/can.h:1748,
from /home/arduino/ArduinoApps/fdcan1_experiment/sketch/sketch.ino:12:
/home/arduino/Arduino/hardware/arduino/zephyr/variants/arduino_uno_q_stm32u585xx/llext-edk/include/zephyr/include/generated/zephyr/syscalls/can.h:476:143: note:   initializing argument 5 of 'int can_send(const device*, const can_frame*, k_timeout_t, can_tx_callback_t, void*)'
476 | static inline int can_send(const struct device * dev, const struct can_frame * frame, k_timeout_t timeout, can_tx_callback_t callback, void * user_data)

ref: zephyr/doc/hardware/peripherals/can/controller.rst at main · zephyrproject-rtos/zephyr

At this point think its up to the Arduino Team to officially enable it and sort the problem with work queue;s

UPDATE: Fixed issue 2 by just adding a void* to literal. But still issue with #1

a bit of an update with the help of AI refreshing my memory on how to use can and fixing it so dont need threads I was able to get a version running but FD seems to be an issue.

In FD mode I keep getting the error message:

<err> can_mcan: CAN FD format not supported in non-FD mode

So I was able to get it running in classic mode without errors but now need to hook up to Teensy 4 to test since loopback mode does not work - gives me build errors

Ok all tried but cant seem to get can working. I attached a Teensy 4.1 to the Q and couldn't get the 2 of them talking.

If anyone wants to take a look and try here are the conf and overlay mods
arduino_uno_q_stm32u585xx.zip (3.3 KB)

and the apps
fdcan_nothreads.zip (3.3 KB)
Copy of fdcan_nothreads.zip (3.8 KB)

@Merlin513 looks like fun.

One of my first guesses would be maybe one or more of the Can pins are not configured properly for CAN...

Arduino Pin usage Port AF0 AF1 AF2 AF3 AF4 AF5 AF6 AF7 AF8 AF9 AF10 AF11 AF12 AF13 AF14 AF15
0 D0 PB7 - LPTIM1_IN2 TIM4_CH2 TIM8_BKIN I2C1_SDA I2C4_SDA MDF1_CKI5 USART1_RX UART4_CTS TSC_G2_IO4 DCMI_VSYNC/
PSSI_RDY
- FMC_NL - TIM17_CH1N EVENTOUT
1 D1 PB6 - LPTIM1_ETR TIM4_CH1 TIM8_BKIN2 I2C1_SCL I2C4_SCL MDF1_SDI5 USART1_TX - TSC_G2_IO3 DCMI_D5/PSSI_D5 - - SAI1_FS_B TIM16_CH1N EVENTOUT
2 D2 PB3 JTDO/
TRACESWO
TIM2_CH2 LPTIM1_CH1 ADF1_CCK0 I2C1_SDA SPI1_SCK SPI3_SCK USART1_
RTS/USART1_
DE
- - CRS_SYNC LPGPIO1_P11 SDMMC2_D2 SAI1_SCK_B - EVENTOUT
3 D3 PB0 - TIM1_CH2N TIM3_CH3 TIM8_CH2N LPTIM3_CH1 SPI1_NSS - USART3_CK - - OCTOSPIM_P1_IO1 LPGPIO1_P9 COMP1_OUT AUDIOCLK - EVENTOUT
4 D4 PA12 - TIM1_ETR - - - SPI1_MOSI OCTOSPIM_
P2_NCS
USART1_
RTS/USART1_
DE
- FDCAN1_TX - - - - - EVENTOUT
5 D5 PA11 - TIM1_CH4 TIM1_BKIN2 - - SPI1_MISO - USART1_CTS - FDCAN1_RX - - - - - EVENTOUT

I know you are using D4/D5 PA12/PA11.

My guess is one or more other functions are also configured for those pins in the Device Tree. Like PWM, or Analog or...

At least one of my sketches, has some quick and dirty dump functions to see
how the different GPIO registers are configured. Which is up at:
Arduino_UNO_Q/Test Sketches/fillrect_test/fillrect_test.ino at main · KurtE/Arduino_UNO_Q

void set_gpio_pin_mode(GPIO_TypeDef *port, uint8_t pin, uint8_t af) {
  // Set the MODER = could be done in fewer steps
  uint32_t moder = port->MODER;
  uint32_t mask = ~(0x3 << (pin * 2));
  moder = (moder & mask) | (0x2 << (pin * 2));
  port->MODER = moder;

  if (pin < 8) {
    port->AFR[0] = port->AFR[0] & ~(0xf << (pin * 4)) | (af << (pin * 4));
  } else {
    pin -= 8;
    port->AFR[1] = port->AFR[1] & ~(0xf << (pin * 4)) | (af << (pin * 4));
  }
}

void print_gpio_regs(const char *name, GPIO_TypeDef *port) {
  //printk("GPIO%s(%p) %08X %08X %08x\n", name, port, port->MODER, port->AFR[0], port->AFR[1]);
  Serial.print("GPIO");
  Serial.print(name);
  Serial.print(" ");
  uint32_t moder = port->MODER;
  Serial.print(moder, HEX);
  Serial.print(" : "); 
  for (uint8_t i = 0; i < 16; i++) {
    switch (moder & 0xC0000000) {
      case 0x00000000ul: Serial.print("I"); break;
      case 0x40000000ul: Serial.print("O"); break;
      case 0x80000000ul: Serial.print("F"); break;
      default: Serial.print("A"); break;
    }
    moder <<= 2;
  }
  Serial.print(" ");
  Serial.print(port->AFR[0], HEX);
  Serial.print(" ");
  Serial.print(port->AFR[1], HEX);
  Serial.print(" ");
  Serial.print(port->IDR, HEX);
  Serial.print(" ");
  Serial.print(port->ODR, HEX);
  Serial.print(" ");
  uint32_t pupdr = port->PUPDR;
  Serial.print(pupdr, HEX);
  Serial.print(" : ");
  for (uint8_t i = 0; i < 16; i++) {
    switch (pupdr & 0xC0000000) {
      case 0x00000000ul: Serial.print("-"); break;
      case 0x40000000ul: Serial.print("U"); break;
      case 0x80000000ul: Serial.print("D"); break;
      default: Serial.print("?"); break;
    }
    pupdr <<= 2;
  }
  Serial.println();
}

void show_all_gpio_regs() {
  print_gpio_regs("A", (GPIO_TypeDef *)GPIOA_BASE);
  print_gpio_regs("B", (GPIO_TypeDef *)GPIOB_BASE);
  print_gpio_regs("C", (GPIO_TypeDef *)GPIOC_BASE);
  print_gpio_regs("D", (GPIO_TypeDef *)GPIOD_BASE);
  print_gpio_regs("E", (GPIO_TypeDef *)GPIOE_BASE);
  print_gpio_regs("F", (GPIO_TypeDef *)GPIOF_BASE);
  print_gpio_regs("G", (GPIO_TypeDef *)GPIOG_BASE);
  print_gpio_regs("H", (GPIO_TypeDef *)GPIOH_BASE);
  print_gpio_regs("I", (GPIO_TypeDef *)GPIOI_BASE);
}

I recently enhanced it slightly to make it easier to decode the MODER register, where there are two bits per possible IO pin on that port. Sample output from the
fillrect test:

*** Booting Zephyr OS build v4.2.0-38-g994b835f5936 ***
Setup
GPIOA A9BEFFDF : FFFOFAAFAAAAAOAA 0 1000 D100 1000 64000000 : UDU-------------
GPIOB 3AAAA79 : IIIAFFFFFFFFOAFO 77600022 55504422 CD9 9 505900 : ----UU--UUDU----
GPIOC FFFFFFAF : AAAAAAAAAAAAFFAA 5500 0 8 0 0 : ----------------
GPIOD FAFFFFFB : AAFFAAAAAAAAAAFA 50 440000 3000 0 5000000 : --UU------------
GPIOE FFFFFFFF : AAAAAAAAAAAAAAAA 0 0 0 0 0 : ----------------
GPIOF FFFFFFFF : AAAAAAAAAAAAAAAA 0 0 0 0 0 : ----------------
GPIOG F2EAABFF : AAIFAFFFFFFAAAAA 88800000 60668 3580 0 9294400 : --DU-DDUU-U-----
GPIOH FEAFFFFF : AAAFFFAAAAAAAAAA 0 22200 400 0 0 : ----------------
GPIOI FFFF : IIIIIIIIAAAAAAAA 0 0 0 0 0 : ----------------

I know this output is somewhat cryptic, but at least for example on this
sketch and released Q firmware:

PA11 - F (Alternate function) (0 1000) - first 0 pins 0-7, 1000 is for 8-15 so AF=1
Whis is TIM1_CH4 - so PWM and the UDU---- is for PU/PD neither of this pins has this set.

PA12 - O (Output)

Currently there is no clean way to setup zephyr for pins to have multiple capabilities active. It is assumed that your zephyr app will configure the pins the way you want it...

I believe there are some proposals on how to resolve this at the Zephyr level, been awhile since I looked at the status of that. Hopefully one of the Arduino Developers can shed some light. I know that @facchinm has a Pull Request at the local
level to partially fix it:
core: pinmux: implement rough solution by facchinm · Pull Request #269 · arduino/ArduinoCore-zephyr
But I have not seen anything change on this PR for several months now.

In the mean time, In my above functions I have a hack function, that allows me
to set the MODER to AF and a specific AF for different pins. I used that to work
around being able to use the alternate SPI pins...

In this case you might be able to get it to work, by, doing something like:

set_gpio_pin_mode(GPIOA, 11, 9);
set_gpio_pin_mode(GPIOA, 12, 9);

Not sure if you also need to set either of these pins in PU or PD mode, if so we can hack up equivalent function.

Also at some point if necessary, may also either extend that earlier function or add another one to only set the MODER for a pin...

Hope that helps.

Thanks for checking and jumping in on this. I tried what you recommended but no luck

FDCAN1 up, CANb FD singleb bitrate, filter=0
GPIOA AABEFFDF : FFFFFAAFAAAAAOAA 0 99000 D800 0 64000000 : UDU-------------
GPIOB ABAAAABA : FFFAFFFFFFFFFAFF 77600022 55504422 CD0 0 A8505900 : DDD-UU--UUDU----
GPIOC FFFFFFFF : AAAAAAAAAAAAAAAA 0 0 0 0 0 : ----------------
GPIOD FAFFFFFF : AAFFAAAAAAAAAAAA 0 440000 3000 0 5000000 : --UU------------
GPIOE FFFFFFFF : AAAAAAAAAAAAAAAA 0 0 0 0 0 : ----------------
GPIOF FFFFFFFF : AAAAAAAAAAAAAAAA 0 0 0 0 0 : ----------------
GPIOG F2EAABFF : AAIFAFFFFFFAAAAA 88800000 60668 3580 0 9294400 : --DU-DDUU-U-----
GPIOH FEAFFFFF : AAAFFFAAAAAAAAAA 0 22200 400 0 0 : ----------------
GPIOI FFFF : IIIIIIIIAAAAAAAA 0 0 0 0 0 : ----------------

Another random thought.

I know with some sub-systems we have had to enable HAL level drivers to make things work... Example in the Arduino GIGA config we have entries like:
CONFIG_VIDEO_STM32_DCMI=y

Wondering if for example in the file zephyr\modules\Kconfig.stm32 There is
the define:
config USE_STM32_HAL_CAN

Wonder if we need to add some item to our conf file.

Sorry, I know completely semi-random, but maybe if we through enough darts
maybe something will work.

That was my thought as well based on past experience.

I did try your suggestion but that gives a build error on config. However I did find this for the H7

and updated config but still no luck, think this will have to wait.

Question I now have is: Has Arduino configured CAN for any of their current Zephyr based setups? It might be easier to debug/fix on most all of the other ST32 boards, as you don't have the added complications, of Serial is not Serial and you can potentially build directly on Zephyr one of their two samples and actually be able to do
west flash on those boards.

Probably should look through all of their Device Trees...
I think I tried some of this yesterday and did not find anything, but, I might have missed it.

Yeah did that as well but not much there and a bit confusing. Not much help.

Ok posting everything I have at this point:
CAN_APPS.zip (14.0 KB)

arduino_uno_q_stm32u585xx.zip (3.3 KB)

@KurtE

Ok since I am too stubborn to leave well enough alone I managed to get it working in classic CAN mode:
Receiving on Teensy 4.1

MB 99  OVERRUN: 0  LEN: 8 EXT: 0 TS: 12059 ID: 123 Buffer: DE AD BE EF 11 22 33 44 
MB 99  OVERRUN: 0  LEN: 8 EXT: 0 TS: 22265 ID: 123 Buffer: DE AD BE EF 11 22 33 44 
MB 99  OVERRUN: 0  LEN: 8 EXT: 0 TS: 32472 ID: 123 Buffer: DE AD BE EF 11 22 33 44 
MB 99  OVERRUN: 0  LEN: 8 EXT: 0 TS: 42679 ID: 123 Buffer: DE AD BE EF 11 22 33 44 

continuously which is what I the Q sending to the T4.1.

And the Q is receiving from the T4.1

RX: ID=0x123 DLC=8 Flags=0x0 Data: 01 02 03 04 05 06 07 08
RX: ID=0x123 DLC=8 Flags=0x0 Data: 01 02 03 04 05 06 07 08
RX: ID=0x123 DLC=8 Flags=0x0 Data: 01 02 03 04 05 06 07 08
RX: ID=0x123 DLC=8 Flags=0x0 Data: 01 02 03 04 05 06 07 08
RX: ID=0x123 DLC=8 Flags=0x0 Data: 01 02 03 04 05 06 07 08
RX: ID=0x123 DLC=8 Flags=0x0 Data: 01 02 03 04 05 06 07 08
RX: ID=0x123 DLC=8 Flags=0x0 Data: 01 02 03 04 05 06 07 08

Success. Still have some cleaning up to do and will post the updates

Actually Both GIGA and H7 have FDCAN in their Device tree.
However I am not sure they have it configured to work.

That is I don't see anything in the generated autoconf.h file for CAN in the
portenta H7 build, and on the GIGA I only see:

#define CONFIG_DT_HAS_ST_STM32H7_FDCAN_ENABLED 1

At some point we might try it on the H7 as the Mid Carrier looks like it is setup with
can screw in connections...

Here are the updated files

arduino_uno_q_stm32u585xx.zip (3.3 KB)

fdcan_nothreads.zip (4.4 KB)

Begining to snow now - not going to be fun in NYC - 12inches of snow + blizzard conditions tonight

Since I have not any takers I asked on discord:

Just tried this on the Portenta H7 on the Mid carrier board with the same results - only classic can working. So odds are missing something in the config file.

Wrote up 2 new issues:
Workque threads are undefined on compile · Issue #358 · arduino/ArduinoCore-zephyr

and

Trying to FDCAN Working on the Arduino Uno Q and Arduino Portenta H7 · Issue #357 · arduino/ArduinoCore-zephyr

Hopefully the Arduino Team will get around to addressing them at some point.

with the release of 0.55 workque issue has been resolved