1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

can stm32: add a driver for STM32 bxCAN peripheral

This driver is compliant with the candev interface. It has been tested
with STM32F0 and STM32F2 and STM32F413 ONLY at this time but should be
compliant with other STM32Fx devices
This commit is contained in:
Vincent Dupont 2016-11-24 16:29:33 +01:00
parent 14f47bf220
commit ae95137f95
7 changed files with 1722 additions and 0 deletions

View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2016 OTA keys S.A.
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup candev_stm32
* @{
*
* @file
* @brief STM32 CAN controller driver (bxCAN) default parameters
*
* @author Vincent Dupont <vincent@otakeys.com>
* @}
*/
#ifndef CANDEV_STM32_PARAMS_H
#define CANDEV_STM32_PARAMS_H
#include "can/device.h"
#include "periph/can.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Default STM32 CAN devices config */
static const can_conf_t candev_conf[] = {
{
#if defined(CPU_FAM_STM32F0)
.can = CAN,
.rcc_mask = RCC_APB1ENR_CANEN,
.rx_pin = GPIO_PIN(PORT_A, 11),
.tx_pin = GPIO_PIN(PORT_A, 12),
.af = GPIO_AF4,
.irqn = CEC_CAN_IRQn,
#else
.can = CAN1,
.rcc_mask = RCC_APB1ENR_CAN1EN,
.can_master = CAN1,
.master_rcc_mask = RCC_APB1ENR_CAN1EN,
.first_filter = 0,
.nb_filters = 14,
#ifndef CPU_FAM_STM32F1
.rx_pin = GPIO_PIN(PORT_D, 0),
.tx_pin = GPIO_PIN(PORT_D, 1),
.af = GPIO_AF9,
#else
.rx_pin = GPIO_PIN(PORT_A, 11),
.tx_pin = GPIO_PIN(PORT_A, 12),
#endif
.tx_irqn = CAN1_TX_IRQn,
.rx0_irqn = CAN1_RX0_IRQn,
.rx1_irqn = CAN1_RX1_IRQn,
.sce_irqn = CAN1_SCE_IRQn,
#endif
.ttcm = 0,
.abom = 1,
.awum = 1,
.nart = 0,
.rflm = 0,
.txfp = 0,
},
#if (CANDEV_STM32_CHAN_NUMOF >= 2) && (CAN_DLL_NUMOF >= 2)
{
.can = CAN2,
.rcc_mask = RCC_APB1ENR_CAN2EN,
.can_master = CAN1,
.master_rcc_mask = RCC_APB1ENR_CAN1EN,
.first_filter = 14,
.nb_filters = 14,
.rx_pin = GPIO_PIN(PORT_B, 5),
.tx_pin = GPIO_PIN(PORT_B, 6),
#ifndef CPU_FAM_STM32F1
.af = GPIO_AF9,
#endif
.tx_irqn = CAN2_TX_IRQn,
.rx0_irqn = CAN2_RX0_IRQn,
.rx1_irqn = CAN2_RX1_IRQn,
.sce_irqn = CAN2_SCE_IRQn,
.ttcm = 0,
.abom = 1,
.awum = 1,
.nart = 0,
.rflm = 0,
.txfp = 0,
},
#endif
#if (CANDEV_STM32_CHAN_NUMOF >= 3) && (CAN_DLL_NUMOF >= 3)
{
.can = CAN3,
.rcc_mask = RCC_APB1ENR_CAN3EN,
.can_master = CAN3,
.master_rcc_mask = RCC_APB1ENR_CAN3EN,
.first_filter = 0,
.nb_filters = 14,
.rx_pin = GPIO_PIN(PORT_B, 3),
.tx_pin = GPIO_PIN(PORT_B, 4),
.af = GPIO_AF11,
.tx_irqn = CAN3_TX_IRQn,
.rx0_irqn = CAN3_RX0_IRQn,
.rx1_irqn = CAN3_RX1_IRQn,
.sce_irqn = CAN3_SCE_IRQn,
.ttcm = 0,
.abom = 1,
.awum = 1,
.nart = 0,
.rflm = 0,
.txfp = 0,
},
#endif
};
/** Default STM32 CAN devices parameters */
static const candev_params_t candev_params[] = {
{
.name = "can_stm32_0",
},
#if (CANDEV_STM32_CHAN_NUMOF >= 2) && (CAN_DLL_NUMOF >= 2)
{
.name = "can_stm32_1",
},
#endif
#if (CANDEV_STM32_CHAN_NUMOF >= 3) && (CAN_DLL_NUMOF >= 3)
{
.name = "can_stm32_2",
},
#endif
};
#ifdef __cplusplus
}
#endif
#endif /* CANDEV_STM32_PARAMS_H */

View File

@ -0,0 +1,193 @@
/*
* Copyright (C) 2016 OTA keys S.A.
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup cpu_stm32_common
* @ingroup drivers_can
* @defgroup candev_stm32 STM32 CAN controller
* @brief STM32 CAN controller driver (bxCAN)
*
* The STM32Fx microcontroller can have an integrated CAN controller (bxCAN)
*
* This driver has been tested with a STM32F0,STM32F2 and STM32F4 MCU
* but should work on others
* @{
*
* @file
* @brief bxCAN specific definitions
*
* @author Vincent Dupont <vincent@otakeys.com>
* @}
*/
#ifndef CANDEV_STM32_H
#define CANDEV_STM32_H
#ifdef __cplusplus
extern "C" {
#endif
#include "can/candev.h"
#if defined(CPU_LINE_STM32F413xx) || defined(CPU_LINE_STM32F423xx)
#define CANDEV_STM32_CHAN_NUMOF 3
#elif defined(CPU_FAM_STM32F1) || defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4)
#define CANDEV_STM32_CHAN_NUMOF 2
#elif defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3) || DOXYGEN
/** Number of channels in the device (up to 3) */
#define CANDEV_STM32_CHAN_NUMOF 1
#else
#error "CAN STM32: CPU not supported"
#endif
#if defined(CPU_FAM_STM32F1)
#define ISR_CAN1_TX isr_usb_hp_can1_tx
#define ISR_CAN1_RX0 isr_usb_lp_can1_rx0
#define ISR_CAN1_RX1 isr_can1_rx1
#define ISR_CAN1_SCE isr_can1_sce
#else
#define ISR_CAN1_TX isr_can1_tx
#define ISR_CAN1_RX0 isr_can1_rx0
#define ISR_CAN1_RX1 isr_can1_rx1
#define ISR_CAN1_SCE isr_can1_sce
#define ISR_CAN2_TX isr_can2_tx
#define ISR_CAN2_RX0 isr_can2_rx0
#define ISR_CAN2_RX1 isr_can2_rx1
#define ISR_CAN2_SCE isr_can2_sce
#define ISR_CAN3_TX isr_can3_tx
#define ISR_CAN3_RX0 isr_can3_rx0
#define ISR_CAN3_RX1 isr_can3_rx1
#define ISR_CAN3_SCE isr_can3_sce
#endif
#if CANDEV_STM32_CHAN_NUMOF > 1 || DOXYGEN
/** The maximum number of filters: 28 for dual channel, 14 for single channel */
#define CAN_STM32_NB_FILTER 28
#else
#define CAN_STM32_NB_FILTER 14
#endif
#ifndef CANDEV_STM32_DEFAULT_BITRATE
/** Default bitrate */
#define CANDEV_STM32_DEFAULT_BITRATE 500000U
#endif
#ifndef CANDEV_STM32_DEFAULT_SPT
/** Default sampling-point */
#define CANDEV_STM32_DEFAULT_SPT 875
#endif
/** bxCAN device configuration */
typedef struct {
CAN_TypeDef *can; /**< CAN device */
uint32_t rcc_mask; /**< RCC mask to enable clock */
gpio_t rx_pin; /**< RX pin */
gpio_t tx_pin; /**< TX pin */
#ifndef CPU_FAM_STM32F1
gpio_af_t af; /**< Alternate pin function to use */
#endif
#if CANDEV_STM32_CHAN_NUMOF > 1 || defined(DOXYGEN)
CAN_TypeDef *can_master; /**< Master CAN device */
uint32_t master_rcc_mask; /**< Master device RCC mask */
/** First filter in the bank. For a master channel it must be 0.
* For a slave channel, it is used without checking with the master channel,
* beware bot to overwrite the master config. */
uint8_t first_filter;
/** Number of filters to use. Must be less or equal
* to CAN_STM32_NB_FILTER - first_filter */
uint8_t nb_filters;
#endif
#if defined(CPU_FAM_STM32F0)
uint8_t irqn; /**< CAN common IRQ channel */
#else
uint8_t tx_irqn; /**< TX IRQ channel */
uint8_t rx0_irqn; /**< RX0 IRQ channel */
uint8_t rx1_irqn; /**< RX1 IRQ channel */
uint8_t sce_irqn; /**< SCE IRQ channel */
#endif
uint8_t ttcm : 1; /**< Time triggered communication mode */
uint8_t abom : 1; /**< Automatic bus-off management */
uint8_t awum : 1; /**< Automatic wakeup mode */
uint8_t nart : 1; /**< No automatic retransmission */
uint8_t rflm : 1; /**< Receive FIFO locked mode */
uint8_t txfp : 1; /**< Transmit FIFO priority */
uint8_t lbkm : 1; /**< Loopback mode */
uint8_t silm : 1; /**< Silent mode */
} can_conf_t;
#define HAVE_CAN_CONF_T
/** The number of transmit mailboxes */
#define CAN_STM32_TX_MAILBOXES 3
/** The number of receive FIFO */
#define CAN_STM32_RX_MAILBOXES 2
#ifndef CAN_STM32_RX_MAIL_FIFO
/** This is the maximum number of frame the driver can receive simultaneously */
#define CAN_STM32_RX_MAIL_FIFO 12
#endif
/** bxCAN candev descriptor */
typedef struct can can_t;
#define HAVE_CAN_T
/** This structure holds anything related to the receive part */
typedef struct candev_stm32_rx_fifo {
struct can_frame frame[CAN_STM32_RX_MAIL_FIFO]; /**< Receive FIFO */
int write_idx; /**< Write index in the receive FIFO */
int read_idx; /**< Read index in the receive FIFO*/
int is_full; /**< Flag set when the FIFO is full */
} candev_stm32_rx_fifo_t;
/** Internal interrupt flags */
typedef struct candev_stm32_isr {
int isr_tx : 3; /**< Tx mailboxes interrupt */
int isr_rx : 2; /**< Rx FIFO interrupt */
int isr_wkup : 1; /**< Wake up interrupt */
} candev_stm32_isr_t;
/** STM32 CAN device descriptor */
struct can {
candev_t candev; /**< Common candev struct */
const can_conf_t *conf; /**< Configuration */
gpio_t rx_pin; /**< RX pin */
gpio_t tx_pin; /**< TX pin */
gpio_af_t af; /**< Alternate pin function to use */
/** Tx mailboxes */
const struct can_frame *tx_mailbox[CAN_STM32_TX_MAILBOXES];
candev_stm32_rx_fifo_t rx_fifo; /**< Rx FIFOs */
candev_stm32_isr_t isr_flags; /**< ISR flags */
};
#ifndef CPU_FAM_STM32F1
/**
* @brief Set the pins of an stm32 CAN device
*
* @param[in,out] dev the device to set pins
* @param[in] tx_pin tx pin
* @param[in] rx_pin rx pin
* @param[in] af alternate function
*/
void candev_stm32_set_pins(can_t *dev, gpio_t tx_pin, gpio_t rx_pin,
gpio_af_t af);
#else
/**
* @brief Set the pins of an stm32 CAN device
*
* @param[in,out] dev the device to set pins
* @param[in] tx_pin tx pin
* @param[in] rx_pin rx pin
*/
void candev_stm32_set_pins(can_t *dev, gpio_t tx_pin, gpio_t rx_pin);
#endif
#ifdef __cplusplus
}
#endif
#endif /* CANDEV_STM32_H */

View File

@ -704,6 +704,10 @@ int dma_configure(dma_t dma, int chan, const volatile void *src, volatile void *
#endif /* MODULE_PERIPH_DMA */
#ifdef MODULE_PERIPH_CAN
#include "candev_stm32.h"
#endif
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2018 OTA keys S.A.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup drivers_periph_can CAN
* @ingroup drivers_periph
* @brief Low-level CAN peripheral driver interface
*
* This is a basic abstract peripheral to be used with candev.
*
* The @p can_t type should be compatible with @p candev_t to be used by the
* candev interface.
*
* See auto init for more details how the can_t is used.
*
* @{
*
* @file
* @brief Low-level CAN peripheral driver interface definitions
*
* @author Vincent Dupont <vincent@otakeys.com>
*/
#ifndef PERIPH_CAN_H
#define PERIPH_CAN_H
#include "periph_cpu.h"
#include "can/candev.h"
#ifndef HAVE_CAN_T
/**
* @brief CAN device descriptor identifier
*/
typedef candev_t can_t;
#endif
#ifndef HAVE_CAN_CONF_T
/**
* @brief CAN configuration identifier
*/
typedef void can_conf_t;
#endif
/**
* @brief Initialize a periph CAN device with the given configuration
*
* @param[in,out] dev device descriptor
* @param[in] conf device vonfiguration
*/
void can_init(can_t *dev, const can_conf_t *conf);
#endif /* PERIPH_CAN_H */

View File

@ -54,8 +54,18 @@ void auto_init_candev(void)
auto_init_can_native();
#endif
#ifdef MODULE_PERIPH_CAN
extern void auto_init_periph_can(void);
auto_init_periph_can();
#endif
#ifdef MODULE_ESP_CAN
extern void auto_init_esp_can(void);
auto_init_esp_can();
#endif
#ifdef MODULE_CAN_STM32
extern void auto_init_can_stm32(void);
auto_init_can_stm32();
#endif
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2016-2018 OTA keys S.A.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup auto_init
* @{
* @file
* @brief initializes periph_can devices
*
* @author Vincent Dupont <vincent@otakeys.com>
* @}
*/
#ifdef MODULE_PERIPH_CAN
#include "can/device.h"
#include "can_params.h"
#define CANDEV_NUMOF ((sizeof(candev_params) / sizeof(candev_params[0])))
#ifndef CANDEV_STACKSIZE
#define CANDEV_STACKSIZE (THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF)
#endif
#ifndef CANDEV_BASE_PRIORITY
#define CANDEV_BASE_PRIORITY (THREAD_PRIORITY_MAIN - CANDEV_NUMOF - 2)
#endif
static candev_dev_t candev_dev[CANDEV_NUMOF];
static char _can_stacks[CANDEV_NUMOF][CANDEV_STACKSIZE];
static can_t candev[CANDEV_NUMOF];
void auto_init_periph_can(void) {
for (size_t i = 0; i < CANDEV_NUMOF; i++) {
can_init(&candev[i], &candev_conf[i]);
candev_dev[i].dev = (candev_t *)&candev[i];
candev_dev[i].name = candev_params[i].name;
#ifdef MODULE_CAN_TRX
candev_dev[i].trx = candev_params[i].trx;
#endif
#ifdef MODULE_CAN_PM
candev_dev[i].rx_inactivity_timeout = candev_params[i].rx_inactivity_timeout;
candev_dev[i].tx_wakeup_timeout = candev_params[i].tx_wakeup_timeout;
#endif
can_device_init(_can_stacks[i], CANDEV_STACKSIZE, CANDEV_BASE_PRIORITY + i,
candev_params[i].name, &candev_dev[i]);
}
}
#else
typedef int dont_be_pedantic;
#endif