Hi,
I’m pretty new to RIOT and am in the process of doing a bringup for a custom stm32f103cb based board with support for CAN. When I compile the tests/sys/conn_can
test for my board I get a hard fault when trying to send can packets. I’m not sure if this is an issue with my board definition or the tests/sys/conn_can
example. I’m not sure how best to proceed.
The issue
I’m using the tests/sys/conn_can
as an example. Which I have correctly compiled and flashed to my custom board.
I connect to my board over uart and enter the following in the riot shell:
test_can send 0 12 abcd
My oscilloscope decodes a can frame id=0x012, DLC=1, data=cd
.
Not DLC=2 data=abcd
as I would expect, however this isn’t the main issue.
I’ve set DEBUG=1 in most of the can related header files which gives me the following output on the console:
_send: candev=0x20001b58, frame=0x200032c8
tx irq
_can_event: dev=0Stack pointer corrupted, reset to top of stack
active thread: 1
FSR/FAR:
CFSR: 0x00009200
HFSR: 0x40000000
DFSR: 0x00000008
AFSR: 0x00000000
BFAR: 0x1ffffff8
Misc
EXC_RET: 0xfffffff1
*** RIOT kernel panic:
HARD FAULT HANDLER
Other verification steps I’ve taken:
- I don’t believe there are any hardware or electrical issues. I’ve compiled and run different firmware generated with CubeMX on this exact same setup and had no issues. I’ve been able to correctly send and receive can packets.
- I’ve verified that all the bit-timing parameters are the same as the CubeMx known working example:
bitrate=500000, sample_point=875, brp=9, prop_seg=3, phase_seg1=3, phase_seg2=1
. - The same behaviour occurs when only transmitting one byte.
- I have another device on the bus which can ACK transmitted packets.
My setup:
RIOT: (Version: 2025.01-devel-13-g88e6a)
I’m using a STM32F103CB MCU. I’m using the non default can pins PB8 and PB9.
My board folder:
custom_board:
├── board.c
├── dist
│ └── openocd.cfg
├── doc.txt
├── include
│ ├── board.h
│ ├── can_params.h
│ ├── gpio_params.h
│ └── periph_conf.h
├── Kconfig
├── Makefile
├── Makefile.features
└── Makefile.include
My periph_conf.h:
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
/* This board provides an HSE */
#include "stm32f103xb.h"
#ifndef CONFIG_BOARD_HAS_HSE
#define CONFIG_BOARD_HAS_HSE 1
#endif
#include "periph_cpu.h"
#include "clk_conf.h"
// #include "candev_stm32.h"
// #include "periph/can.h"
// #include "can/device.h"
#ifdef __cplusplusq
extern "C" {
#endif
/**
* @name UART configuration
* @{
*/
static const uart_conf_t uart_config[] = {
{
.dev = USART1,
.rcc_mask = RCC_APB2ENR_USART1EN, // provide USE non default pins for UART1
.rx_pin = GPIO_PIN(PORT_B, 7),
.tx_pin = GPIO_PIN(PORT_B, 6),
.bus = APB2,
.irqn = USART1_IRQn
},
};
#define UART_0_ISR isr_usart1
#define UART_NUMOF ARRAY_SIZE(uart_config)
/** @} */
/**
* @name Timer configuration
* @{
*/
static const timer_conf_t timer_config[] = {
{
.dev = TIM4, // provide TIM4 for ztimer usec
.max = 0x0000ffff,
.rcc_mask = RCC_APB1ENR_TIM4EN,
.bus = APB1,
.irqn = TIM4_IRQn
},
};
#define TIMER_0_ISR isr_tim4
#define TIMER_NUMOF ARRAY_SIZE(timer_config)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* PERIPH_CONF_H */
/** @} */
My can_params.h: I’m just hiding the default can params defined under:
cpu/stm32/include/can_params.h
#ifndef CAN_PARAMS_H
#define CAN_PARAMS_H
#include "can/device.h"
#include "periph/can.h"
#ifdef __cplusplus
extern "C" {
#endif
static const can_conf_t candev_conf[] = {
{
.can = CAN1,
.rcc_mask = RCC_APB1ENR_CAN1EN,
.rx_pin = GPIO_PIN(PORT_B, 8),
.tx_pin = GPIO_PIN(PORT_B, 9),
.tx_irqn = CAN1_TX_IRQn,
.rx0_irqn = CAN1_RX0_IRQn,
.rx1_irqn = CAN1_RX1_IRQn,
.sce_irqn = CAN1_SCE_IRQn,
.en_deep_sleep_wake_up = true,
.ttcm = 0,
.abom = 1,
.awum = 1,
.nart = 1,
.rflm = 0,
.txfp = 0,
},
};
static const candev_params_t candev_params[] = {
{
.name = "can_stm32_0",
},
};
#ifdef __cplusplus
}
#endif
#endif /* CAN_PARAMS_H */
In my board.c I’m taking care of non default pin remapping using the AFIO-MAPR register to remap can and uart to non default pins
#include "board.h"
#include "periph/cpu_gpio.h"
#include "periph/gpio.h"
#include "log.h"
// #include "periph_conf.h"
void board_init(void)
{
/* remap USART1 to PB7 and PB6 */
AFIO->MAPR |= AFIO_MAPR_USART1_REMAP;
RCC->APB1ENR |= RCC_APB1ENR_CAN1EN; // enable CAN clock on APB1
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // enable port B GPIO for can
/* remap CAN1 to PB8 and PB9 */
uint32_t tmpreg = AFIO->MAPR;
tmpreg &= ~AFIO_MAPR_CAN_REMAP;
tmpreg |= AFIO_MAPR_SWJ_CFG;
tmpreg |= AFIO_MAPR_CAN_REMAP_REMAP2;
AFIO->MAPR = tmpreg;
printf("Initialising board, AFIO->MAPR: 0x%04lx!\r\n", AFIO->MAPR);
}
In my Makefile.features I provide:
CPU = stm32
CPU_MODEL = stm32f103cb
# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_can
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart
I’m not sure how best to proceed.