Configuring libuavcan_stm32 for STM32F0XX

Hi. I’m trying to set up a uavcan-node on a STM32F098CC6 MCU which will publish sensor-data. I’m currently stuck at setting up the driver and library for my project. I’ve come as far as reducing errors down to three, which appear to be due to configuration issues.

I configured for BAREMETAL, one Interface and timer number 2 in build_config.hpp.

In my chip.h I have:

#include "stm32f0xx.h"
#include "stm32f0xx_hal.h"

#define STM32F0XX
#define STM32_PCLK1 (42000000ul)
#define STM32_TIMCLK1 (42000000ul) (Actually using TIMCLK2, but compilation demanded for definition of TIMCLK1)
#define RCC_APB1ENR_CAN1EN RCC_APB1ENR_CANEN
#define RCC_APB1RSTR_CAN1RST RCC_APB1RSTR_CANRST
(erroneous:)#define CAN1_RX1_IRQn CAN_RX1_IRQn
#define CAN1_TX_IRQHandler CAN1_TX_IRQHandler
#define CAN1_RX0_IRQHandler CAN1_RX0_IRQHandler
#define CAN1_RX1_IRQHandler CAN1_RX1_IRQHandler

of which yields a ‘CAN_RX1_IRQn’ was not declared in this scope error.

I tracked the error to nvicEnableVector(CAN1_RX0_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK); in uc_stm32_can.cpp which demands the parameter to be of uint_t32 type. Hence, I speculate that what actually should be defined here is some kind of register-adress.

I have the same problem with ‘USB_HP_CAN1_TX_IRQn’ and ‘USB_LP_CAN1_RX0_IRQn’ from uc_stm32_can.cpp.

Can you affirm my speculations and help me find the corresponding registers, for example as per spelling out their respective names? Or am I wrong entirely?

Also; are some of my configurations nonsensical or superfluous?

Thanks a lot!

Nope, it’s an IRQ number, not a register address. You should look up the CAN IRQ numbers in the datasheet for your MCU, or just look at the header file and see how it’s named there.

Not sure about STM32_TIMCLK1. The driver assumes that all supported timers use the same clock domain, perhaps this is not the case for your MCU?

Hey there,

So, I’ve dug up the IRQ-numbers. It showed me, why I have an issue understanding this:

There is only one IRQn for CAN: CEC_CAN_IRQn = 30 /!< CEC and CAN global Interrupts & EXTI Line27 Interrupt/

I’ve seen that the IRQns which are supposed to be specified are present in STM32F107 and other MCUs on the list.

Does this mean, the driver is not compatible with my MCU?

No, it just means that the driver has never been tested with your MCU. If your CAN controller is implemented on the bxCAN macrocell (which is almost certainly the case, excepting only the newer STM32H7), it will work, you just need to add a macro alias to your CEC_CAN_IRQn. Please send a pull request.

Thanks!

Can you elaborate a little further on what I have to do? I’m pretty new to all of this. I can think up various ways of how this instruction could be interpreted in terms of what I have to do exactly. Sure I can try to analyze the driver and figure out what it means, but I guess it would be very equivocal.

Do I just have to define aliases that will direct all faulty references to IRQns to the CEC_CAN_IRQn?
The same obviously goes for the IRQ-handler.

Concerning the pull request: I didn’t make any changes to the stm32_uavcan files. I can send a pull request when and if I’m done. You can look at the MCU specific files at https://github.com/6ramr/MCU_CODE/tree/uavcan if you care. There isn’t much there either, because setting up the UAVCAN is primal.

Thank you again.

Yes, except there will be just one alias for the IRQ number and one for the IRQ handler (unless I’m misremembering stuff). E.g., #define CAN1_RX0_IRQn CEC_CAN_IRQn

Sadly, this configuration gives me “Misconfigured build”-error at line 1181 of uc_stm32_can.cpp:

#if !defined(CAN1_TX_IRQHandler) ||\
    !defined(CAN1_RX0_IRQHandler) ||\
    !defined(CAN1_RX1_IRQHandler)
# error "Misconfigured build"
#endif

So, you specifically do request these aliases to exist.

Also the other IRQns are required at 1038 of uc_stm32_can.cpp:

#elif UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS
    {
        CriticalSectionLocker lock;
        nvicEnableVector(CAN1_TX_IRQn,  UAVCAN_STM32_IRQ_PRIORITY_MASK);
        nvicEnableVector(CAN1_RX0_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
        nvicEnableVector(CAN1_RX1_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
# if UAVCAN_STM32_NUM_IFACES > 1
        nvicEnableVector(CAN2_TX_IRQn,  UAVCAN_STM32_IRQ_PRIORITY_MASK);
        nvicEnableVector(CAN2_RX0_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
        nvicEnableVector(CAN2_RX1_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
# endif
    }
#endif
}

I will edit out these lines and see what happens, although, from what I see in the code, it shouldn’t work:

UAVCAN_STM32_IRQ_HANDLER(CAN2_TX_IRQHandler);
UAVCAN_STM32_IRQ_HANDLER(CAN2_TX_IRQHandler)
{
    UAVCAN_STM32_IRQ_PROLOGUE();
    uavcan_stm32::handleTxInterrupt(1);
    UAVCAN_STM32_IRQ_EPILOGUE();
}

UAVCAN_STM32_IRQ_HANDLER(CAN2_RX0_IRQHandler);
UAVCAN_STM32_IRQ_HANDLER(CAN2_RX0_IRQHandler)
{
    UAVCAN_STM32_IRQ_PROLOGUE();
    uavcan_stm32::handleRxInterrupt(1, 0);
    UAVCAN_STM32_IRQ_EPILOGUE();
}

UAVCAN_STM32_IRQ_HANDLER(CAN2_RX1_IRQHandler);
UAVCAN_STM32_IRQ_HANDLER(CAN2_RX1_IRQHandler)
{
    UAVCAN_STM32_IRQ_PROLOGUE();
    uavcan_stm32::handleRxInterrupt(1, 1);
    UAVCAN_STM32_IRQ_EPILOGUE();
}

So, I had a nother look in the files. From what I got, the respective IRQ_Handlers check the registers for IRQ-sources. Because of this, I decided to move all three interrupt service routines to the same handler and remove theire calls to the nvic.

I will report, when I know if it works.

I get a region flash overflow now by roughly 40KB. I have 256KB flash on my MCU. I use hal and CMSIS, which I think both are necessary for uavcan?

Do you have any idea what’s the typical flash footprint of a node without any other functionality?

Normally you should be looking at ~70 KB for regular builds and ~25KB for tiny builds, IIRC. Yes, libuavcan is huge and complex. Consider checking whether your build is configured correctly: enable size optimizations, enable LTO, use small standard libraries, ensure that exception handling and RTTI are disabled. Have a look here (YMMV): https://groups.google.com/forum/#!searchin/uavcan/footprint|sort:date/uavcan/18_GhJchWX4/ke6EZ6ih0D0J

Libuavcan does not require those, because it’s platform-agnostic. The STM32 driver requires that the MCU-specific header file is available though.

So, I managed to get past this flaws, and sadly, it was my own fault: I overlooked an include I copied from the Zubax implementation to my main file. Apparently it was huge.

Having some compiler trouble now: __atomic_exchange_n() is defined at compiler level, from what I get. I’m using Atollic True Studio(which is essentially eclipse IDE) with their standard arm-atollic-eabi-gcc compiler. But something seems to be off. My $PATH only has a arm-atollic-NONE-eabi-gcc compiler. So the problem might originate from this call or from using the wrong compiler. Some more research… :exploding_head:

You have been a great help so far already! Thank you for that!

It’s really strange:

All other __atomic_XXX_n are working. Only __atomic_exchange_n at line 148 of thread.hpp is not working. The compiler points to this call but writes “__atomic_exchange_1” is undefined reference…

I tried different compilers and different c+±versions (standard and gnu), but to no avail. Tricky problem… I can’t make sense of this.

Turns out: it was just a very annoying eclipse-bug. After restarting it vanished…