mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
edc43201db
This should not change any generated binary
1285 lines
36 KiB
C
1285 lines
36 KiB
C
/*
|
|
* 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 cpu_stm32
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Implementation of the CAN controller driver
|
|
*
|
|
* @author Vincent Dupont <vincent@otakeys.com>
|
|
* @}
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <cpu_conf.h>
|
|
|
|
#include "periph/can.h"
|
|
#include "periph/gpio.h"
|
|
#include "can/device.h"
|
|
#include "can/common.h"
|
|
#include "periph_conf.h"
|
|
#include "pm_layered.h"
|
|
#include "thread.h"
|
|
#include "sched.h"
|
|
#include "mutex.h"
|
|
|
|
#define ENABLE_DEBUG 0
|
|
#include "debug.h"
|
|
|
|
#define CAN_MAX_WAIT_CHANGE (10000U)
|
|
#define CAN_TIxR_SFF_SHIFT (21U)
|
|
#define CAN_TIxR_EFF_SHIFT (3U)
|
|
|
|
#define CAN_MCR_BIT_DONT_TOUCH (0xFFFFFF03)
|
|
|
|
typedef enum {
|
|
MODE_NORMAL,
|
|
MODE_SLEEP,
|
|
MODE_INIT,
|
|
} can_mode_t;
|
|
|
|
static int _init(candev_t *candev);
|
|
static void _isr(candev_t *candev);
|
|
static int _send(candev_t *candev, const struct can_frame *frame);
|
|
static int _abort(candev_t *candev, const struct can_frame *frame);
|
|
static int _set(candev_t *candev, canopt_t opt, void *value, size_t value_len);
|
|
static int _get(candev_t *candev, canopt_t opt, void *value, size_t max_len);
|
|
static int _set_filter(candev_t *candev, const struct can_filter *filter);
|
|
static int _remove_filter(candev_t *candev, const struct can_filter *filter);
|
|
|
|
static void tx_irq_handler(can_t *dev);
|
|
static void tx_isr(can_t *dev);
|
|
static void tx_conf(can_t *dev, int mailbox);
|
|
static void rx_irq_handler(can_t *dev, int mailbox);
|
|
static void rx_isr(can_t *dev);
|
|
static void sce_irq_handler(can_t *dev);
|
|
|
|
static inline void set_bit_timing(can_t *dev);
|
|
|
|
static inline can_mode_t get_mode(CAN_TypeDef *can);
|
|
static int set_mode(CAN_TypeDef *can, can_mode_t mode);
|
|
|
|
static const candev_driver_t candev_stm32_driver = {
|
|
.send = _send,
|
|
.init = _init,
|
|
.isr = _isr,
|
|
.get = _get,
|
|
.set = _set,
|
|
.abort = _abort,
|
|
.set_filter = _set_filter,
|
|
.remove_filter = _remove_filter,
|
|
};
|
|
|
|
static const struct can_bittiming_const bittiming_const = {
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 1,
|
|
.brp_min = 1,
|
|
.brp_max = 1024,
|
|
.brp_inc = 1,
|
|
};
|
|
|
|
enum {
|
|
STATUS_NOT_USED,
|
|
STATUS_ON,
|
|
STATUS_READY_FOR_SLEEP,
|
|
STATUS_SLEEP,
|
|
};
|
|
|
|
static uint8_t _status[CANDEV_STM32_CHAN_NUMOF];
|
|
|
|
static can_t *_can[CANDEV_STM32_CHAN_NUMOF];
|
|
|
|
static inline int get_channel(CAN_TypeDef *can)
|
|
{
|
|
#if CANDEV_STM32_CHAN_NUMOF == 1
|
|
(void)can;
|
|
return 0;
|
|
#else
|
|
return (int) (((uint32_t)can - (uint32_t)CAN1) >> 10);
|
|
#endif
|
|
}
|
|
|
|
static inline can_mode_t get_mode(CAN_TypeDef *can)
|
|
{
|
|
if ((can->MCR & CAN_MCR_SLEEP) == CAN_MCR_SLEEP) {
|
|
return MODE_SLEEP;
|
|
}
|
|
else if ((can->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) {
|
|
return MODE_INIT;
|
|
}
|
|
else {
|
|
return MODE_NORMAL;
|
|
}
|
|
}
|
|
|
|
static int set_mode(CAN_TypeDef *can, can_mode_t mode)
|
|
{
|
|
int max_loop = CAN_MAX_WAIT_CHANGE;
|
|
int res = 0;
|
|
|
|
switch (mode) {
|
|
case MODE_NORMAL:
|
|
can->MCR &= ~(CAN_MCR_SLEEP | CAN_MCR_INRQ);
|
|
/* wait for hardware confirmation */
|
|
while (((can->MSR & CAN_MSR_INAK) || (can->MSR & CAN_MSR_SLAK)) && max_loop != 0) {
|
|
max_loop--;
|
|
}
|
|
break;
|
|
case MODE_SLEEP:
|
|
/* set sleep mode */
|
|
can->MCR &= ~CAN_MCR_INRQ;
|
|
can->MCR |= CAN_MCR_SLEEP;
|
|
while (((can->MSR & CAN_MSR_INAK) || !(can->MSR & CAN_MSR_SLAK)) && max_loop != 0) {
|
|
max_loop--;
|
|
}
|
|
break;
|
|
case MODE_INIT:
|
|
can->MCR &= ~CAN_MCR_SLEEP;
|
|
can->MCR |= CAN_MCR_INRQ;
|
|
/* wait for hardware confirmation */
|
|
while ((!(can->MSR & CAN_MSR_INAK) || (can->MSR & CAN_MSR_SLAK)) && max_loop != 0) {
|
|
max_loop--;
|
|
}
|
|
break;
|
|
default:
|
|
DEBUG("unsupported mode\n");
|
|
res = -1;
|
|
break;
|
|
}
|
|
|
|
if (max_loop == 0) {
|
|
DEBUG("candev_stm32: didn't switch mode %d\n", mode);
|
|
res = -1;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static inline int filter_is_set(CAN_TypeDef *master, uint8_t filter)
|
|
{
|
|
return (master->FA1R & (1 << filter)) >> filter;
|
|
}
|
|
|
|
void can_init(can_t *dev, const can_conf_t *conf)
|
|
{
|
|
dev->candev.driver = &candev_stm32_driver;
|
|
|
|
struct can_bittiming timing = { .bitrate = CANDEV_STM32_DEFAULT_BITRATE,
|
|
.sample_point = CANDEV_STM32_DEFAULT_SPT };
|
|
can_device_calc_bittiming(CLOCK_APB1, &bittiming_const, &timing);
|
|
|
|
memcpy(&dev->candev.bittiming, &timing, sizeof(timing));
|
|
dev->conf = conf;
|
|
|
|
dev->rx_pin = GPIO_UNDEF;
|
|
dev->tx_pin = GPIO_UNDEF;
|
|
}
|
|
|
|
static void set_filter(CAN_TypeDef *can, uint32_t fr1, uint32_t fr2, uint8_t filter, uint8_t fifo)
|
|
{
|
|
/* Set filter/mask */
|
|
if ((fr1 & CAN_EFF_FLAG) == CAN_EFF_FLAG) {
|
|
can->sFilterRegister[filter].FR1 = ((fr1 & CAN_EFF_MASK) << CAN_TIxR_EFF_SHIFT)
|
|
| CAN_TI0R_IDE;
|
|
can->sFilterRegister[filter].FR2 = ((fr2 & CAN_EFF_MASK) << CAN_TIxR_EFF_SHIFT)
|
|
| CAN_TI0R_IDE;
|
|
}
|
|
else {
|
|
can->sFilterRegister[filter].FR1 = (fr1 & CAN_SFF_MASK) << CAN_TIxR_SFF_SHIFT;
|
|
can->sFilterRegister[filter].FR2 = (fr2 & CAN_SFF_MASK) << CAN_TIxR_SFF_SHIFT;
|
|
}
|
|
if (fifo == 0) {
|
|
can->FFA1R &= ~(1 << filter); /* To FIFO 0 */
|
|
}
|
|
else {
|
|
can->FFA1R |= (1 << filter); /* To FIFO 1 */
|
|
}
|
|
can->FM1R &= ~(1 << filter); /* Identifier Mask mode */
|
|
can->FS1R |= (1 << filter); /* Single 32-bit scale config */
|
|
can->FA1R |= (1 << filter); /* Activate filer */
|
|
}
|
|
|
|
static void get_can_filter(CAN_TypeDef *can, uint8_t filter_id, uint32_t *filter, uint32_t *mask)
|
|
{
|
|
uint32_t fr1 = can->sFilterRegister[filter_id].FR1;
|
|
uint32_t fr2 = can->sFilterRegister[filter_id].FR2;
|
|
|
|
if ((fr1 & CAN_TI0R_IDE) == CAN_TI0R_IDE) {
|
|
*filter = ((fr1 >> CAN_TIxR_EFF_SHIFT) & CAN_EFF_MASK) | CAN_EFF_FLAG;
|
|
*mask = ((fr2 >> CAN_TIxR_EFF_SHIFT) & CAN_EFF_MASK) | CAN_EFF_FLAG;
|
|
}
|
|
else {
|
|
*filter = (fr1 >> CAN_TIxR_SFF_SHIFT) & CAN_SFF_MASK;
|
|
*mask = (fr2 >> CAN_TIxR_SFF_SHIFT) & CAN_SFF_MASK;
|
|
}
|
|
if (fr1 & CAN_TI0R_RTR) {
|
|
*filter |= CAN_RTR_FLAG;
|
|
}
|
|
if (fr2 & CAN_TI0R_RTR) {
|
|
*mask |= CAN_RTR_FLAG;
|
|
}
|
|
}
|
|
|
|
static inline void unset_filter(CAN_TypeDef *can, uint8_t filter)
|
|
{
|
|
can->FA1R &= ~(1 << filter);
|
|
}
|
|
|
|
#ifndef CPU_FAM_STM32F1
|
|
void candev_stm32_set_pins(can_t *dev, gpio_t tx_pin, gpio_t rx_pin,
|
|
gpio_af_t af)
|
|
#else
|
|
void candev_stm32_set_pins(can_t *dev, gpio_t tx_pin, gpio_t rx_pin)
|
|
#endif
|
|
{
|
|
if (dev->tx_pin != GPIO_UNDEF) {
|
|
gpio_init(dev->tx_pin, GPIO_IN);
|
|
gpio_init_analog(dev->tx_pin);
|
|
}
|
|
if (dev->rx_pin != GPIO_UNDEF) {
|
|
gpio_init(dev->rx_pin, GPIO_IN);
|
|
gpio_init_analog(dev->rx_pin);
|
|
}
|
|
dev->tx_pin = tx_pin;
|
|
dev->rx_pin = rx_pin;
|
|
/* configure pins */
|
|
gpio_init(rx_pin, GPIO_IN);
|
|
gpio_init(tx_pin, GPIO_OUT);
|
|
#ifndef CPU_FAM_STM32F1
|
|
dev->af = af;
|
|
gpio_init_af(rx_pin, af);
|
|
gpio_init_af(tx_pin, af);
|
|
#else
|
|
gpio_init_af(tx_pin, GPIO_AF_OUT_PP);
|
|
#endif
|
|
}
|
|
|
|
static int _init(candev_t *candev)
|
|
{
|
|
can_t *dev = container_of(candev, can_t, candev);
|
|
int res = 0;
|
|
|
|
_can[get_channel(dev->conf->can)] = dev;
|
|
|
|
memset(dev->tx_mailbox, 0, sizeof(dev->tx_mailbox));
|
|
memset(&dev->rx_fifo, 0, sizeof(dev->rx_fifo));
|
|
|
|
dev->isr_flags.isr_tx = 0;
|
|
dev->isr_flags.isr_rx = 0;
|
|
|
|
#if CANDEV_STM32_CHAN_NUMOF > 1
|
|
/* Enable master clock */
|
|
periph_clk_en(APB1, dev->conf->master_rcc_mask);
|
|
#endif
|
|
/* Enable device clock */
|
|
periph_clk_en(APB1, dev->conf->rcc_mask);
|
|
|
|
_status[get_channel(dev->conf->can)] = STATUS_ON;
|
|
|
|
/* configure pins */
|
|
#ifndef CPU_FAM_STM32F1
|
|
candev_stm32_set_pins(dev, dev->conf->tx_pin, dev->conf->rx_pin, dev->conf->af);
|
|
#else
|
|
candev_stm32_set_pins(dev, dev->conf->tx_pin, dev->conf->rx_pin);
|
|
#endif
|
|
|
|
set_mode(dev->conf->can, MODE_INIT);
|
|
|
|
/* Set configuration */
|
|
uint32_t mask_config = (CAN_MCR_TTCM * dev->conf->ttcm) | (CAN_MCR_ABOM * dev->conf->abom) |
|
|
(CAN_MCR_AWUM * dev->conf->awum) | (CAN_MCR_NART * dev->conf->nart) |
|
|
(CAN_MCR_RFLM * dev->conf->rflm) | (CAN_MCR_TXFP * dev->conf->txfp);
|
|
dev->conf->can->MCR |= mask_config;
|
|
dev->conf->can->MCR &= (mask_config | CAN_MCR_BIT_DONT_TOUCH);
|
|
|
|
set_bit_timing(dev);
|
|
|
|
/* Loopback and/or silent mode */
|
|
dev->conf->can->BTR |= (CAN_BTR_LBKM * dev->conf->lbkm) | (CAN_BTR_SILM * dev->conf->silm);
|
|
|
|
/* Default filter config: No rx frame */
|
|
#if CANDEV_STM32_CHAN_NUMOF > 1
|
|
if (dev->conf->can == dev->conf->can_master) {
|
|
|
|
assert(dev->conf->first_filter == 0);
|
|
assert(dev->conf->nb_filters <= CAN_STM32_NB_FILTER);
|
|
#endif
|
|
|
|
dev->conf->can->FMR = CAN_FMR_FINIT;
|
|
#if CANDEV_STM32_CHAN_NUMOF > 1
|
|
/* Clear start bank */
|
|
dev->conf->can->FMR &= ~CAN_FMR_CAN2SB;
|
|
/* Set start filter */
|
|
dev->conf->can->FMR |= dev->conf->nb_filters << 8;
|
|
|
|
for (int i = 0; i < dev->conf->nb_filters; i++) {
|
|
#else
|
|
for (int i = 0; i < CAN_STM32_NB_FILTER; i++) {
|
|
#endif
|
|
dev->conf->can->FA1R &= ~(1 << i);
|
|
}
|
|
dev->conf->can->FMR &= ~CAN_FMR_FINIT;
|
|
#if CANDEV_STM32_CHAN_NUMOF > 1
|
|
}
|
|
else {
|
|
can_mode_t mode = get_mode(dev->conf->can_master);
|
|
set_mode(dev->conf->can_master, MODE_INIT);
|
|
dev->conf->can_master->FMR = CAN_FMR_FINIT;
|
|
dev->conf->can_master->FMR &= ~CAN_FMR_CAN2SB;
|
|
dev->conf->can_master->FMR |= dev->conf->first_filter << 8;
|
|
for (int i = 0; i < dev->conf->nb_filters; i++) {
|
|
dev->conf->can_master->FA1R &= ~(1 << (i + dev->conf->first_filter));
|
|
}
|
|
dev->conf->can_master->FMR &= ~CAN_FMR_FINIT;
|
|
set_mode(dev->conf->can_master, mode);
|
|
}
|
|
#endif
|
|
|
|
/* Clear interrupt flags */
|
|
dev->conf->can->TSR |= CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2;
|
|
dev->conf->can->RF0R |= CAN_RF0R_FMP0 | CAN_RF0R_FULL0 | CAN_RF0R_FOVR0;
|
|
dev->conf->can->RF1R |= CAN_RF1R_FMP1 | CAN_RF1R_FULL1 | CAN_RF1R_FOVR1;
|
|
dev->conf->can->ESR |= CAN_ESR_EWGF | CAN_ESR_EPVF | CAN_ESR_BOFF;
|
|
dev->conf->can->MSR |= CAN_MSR_WKUI;
|
|
|
|
dev->conf->can->IER = CAN_IER_WKUIE |
|
|
CAN_IER_EPVIE | CAN_IER_EWGIE | CAN_IER_ERRIE | CAN_IER_BOFIE |
|
|
CAN_IER_FOVIE1 | CAN_IER_FMPIE1 | CAN_IER_FOVIE0 | CAN_IER_FMPIE0 |
|
|
CAN_IER_TMEIE;
|
|
/* Enable interrupts */
|
|
#if defined(CPU_FAM_STM32F0)
|
|
NVIC_EnableIRQ(dev->conf->irqn);
|
|
#else
|
|
NVIC_EnableIRQ(dev->conf->tx_irqn);
|
|
NVIC_EnableIRQ(dev->conf->rx0_irqn);
|
|
NVIC_EnableIRQ(dev->conf->rx1_irqn);
|
|
NVIC_EnableIRQ(dev->conf->sce_irqn);
|
|
#endif
|
|
|
|
res = set_mode(dev->conf->can, MODE_NORMAL);
|
|
#ifdef STM32_PM_STOP
|
|
pm_block(STM32_PM_STOP);
|
|
#endif
|
|
|
|
return res;
|
|
}
|
|
|
|
static inline void set_bit_timing(can_t *dev)
|
|
{
|
|
/* Set bit timing */
|
|
dev->conf->can->BTR = (((uint32_t)(dev->candev.bittiming.sjw - 1) << 24) & CAN_BTR_SJW) |
|
|
(((uint32_t)(dev->candev.bittiming.phase_seg2 - 1) << 20) & CAN_BTR_TS2) |
|
|
(((uint32_t)((dev->candev.bittiming.phase_seg1 +
|
|
dev->candev.bittiming.prop_seg)
|
|
- 1) << 16) & CAN_BTR_TS1) |
|
|
((uint32_t)(dev->candev.bittiming.brp - 1) & CAN_BTR_BRP);
|
|
}
|
|
|
|
static int _send(candev_t *candev, const struct can_frame *frame)
|
|
{
|
|
can_t *dev = container_of(candev, can_t, candev);
|
|
CAN_TypeDef *can = dev->conf->can;
|
|
int mailbox = 0;
|
|
|
|
DEBUG("_send: candev=%p, frame=%p\n", (void *) candev, (void *) frame);
|
|
|
|
for (mailbox = 0; mailbox < CAN_STM32_TX_MAILBOXES; mailbox++) {
|
|
if (dev->tx_mailbox[mailbox] == NULL) {
|
|
break;
|
|
}
|
|
}
|
|
if (mailbox == CAN_STM32_TX_MAILBOXES) {
|
|
return -EBUSY;
|
|
}
|
|
dev->tx_mailbox[mailbox] = frame;
|
|
|
|
if ((frame->can_id & CAN_EFF_FLAG) == CAN_EFF_FLAG) {
|
|
can->sTxMailBox[mailbox].TIR = (frame->can_id & CAN_EFF_MASK) << CAN_TIxR_EFF_SHIFT
|
|
| CAN_TI0R_IDE;
|
|
}
|
|
else {
|
|
can->sTxMailBox[mailbox].TIR = (frame->can_id & CAN_SFF_MASK) << CAN_TIxR_SFF_SHIFT;
|
|
}
|
|
can->sTxMailBox[mailbox].TDTR = frame->can_dlc & CAN_TDT0R_DLC;
|
|
|
|
can->sTxMailBox[mailbox].TDLR = 0;
|
|
can->sTxMailBox[mailbox].TDHR = 0;
|
|
for (int j = 0; j < 4 && frame->can_dlc > j; j++) {
|
|
can->sTxMailBox[mailbox].TDLR |= (uint32_t)(frame->data[j] << (8 * j));
|
|
}
|
|
for (int j = 4; j < 8 && frame->can_dlc > j; j++) {
|
|
can->sTxMailBox[mailbox].TDHR |= (uint32_t)(frame->data[j] << (8 * (j - 4)));
|
|
}
|
|
|
|
can->sTxMailBox[mailbox].TIR |= CAN_TI0R_TXRQ;
|
|
|
|
return mailbox;
|
|
}
|
|
|
|
static int _abort(candev_t *candev, const struct can_frame *frame)
|
|
{
|
|
can_t *dev = container_of(candev, can_t, candev);
|
|
CAN_TypeDef *can = dev->conf->can;
|
|
int mailbox = 0;
|
|
|
|
for (mailbox = 0; mailbox < CAN_STM32_TX_MAILBOXES; mailbox++) {
|
|
if (dev->tx_mailbox[mailbox] == frame) {
|
|
break;
|
|
}
|
|
}
|
|
if (mailbox == CAN_STM32_TX_MAILBOXES) {
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
can->TSR |= CAN_TSR_ABRQ0 << (8 * mailbox);
|
|
dev->tx_mailbox[mailbox] = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define CAN_RIxR_SFF_SHIFT 21
|
|
#define CAN_RIxR_EFF_SHIFT 3
|
|
#define CAN_RDTxR_FMI_SHIFT 8
|
|
|
|
static int read_frame(can_t *dev, struct can_frame *frame, int mailbox)
|
|
{
|
|
CAN_TypeDef *can = dev->conf->can;
|
|
|
|
/* Get frame ID */
|
|
if ((can->sFIFOMailBox[mailbox].RIR & CAN_RI0R_IDE) == CAN_RI0R_IDE) {
|
|
frame->can_id = can->sFIFOMailBox[mailbox].RIR >> CAN_RIxR_EFF_SHIFT;
|
|
frame->can_id |= CAN_EFF_FLAG;
|
|
}
|
|
else {
|
|
frame->can_id = can->sFIFOMailBox[mailbox].RIR >> CAN_RIxR_SFF_SHIFT;
|
|
}
|
|
if ((can->sFIFOMailBox[mailbox].RIR & CAN_RI0R_RTR) == CAN_RI0R_RTR) {
|
|
frame->can_id |= CAN_RTR_FLAG;
|
|
}
|
|
|
|
/* Get DLC */
|
|
frame->can_dlc = can->sFIFOMailBox[mailbox].RDTR & CAN_RDT0R_DLC;
|
|
|
|
/* Get Data */
|
|
for (int j = 0; j < 4; j++) {
|
|
frame->data[j] = (can->sFIFOMailBox[mailbox].RDLR >> (j * 8)) & 0xFF;
|
|
}
|
|
for (int j = 4; j < 8; j++) {
|
|
frame->data[j] = (can->sFIFOMailBox[mailbox].RDHR >> ((j - 4) * 8)) & 0xFF;
|
|
}
|
|
|
|
/* filter number matching the received frame */
|
|
/* filter = (can->sFIFOMailBox[mailbox].RDTR & CAN_RDT0R_FMI) >> CAN_RDTxR_FMI_SHIFT; */
|
|
|
|
/* Release input mailbox */
|
|
if (mailbox == 0) {
|
|
can->RF0R |= CAN_RF0R_RFOM0;
|
|
}
|
|
else {
|
|
can->RF1R |= CAN_RF1R_RFOM1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void _isr(candev_t *candev)
|
|
{
|
|
can_t *dev = container_of(candev, can_t, candev);
|
|
|
|
if (dev->isr_flags.isr_tx) {
|
|
tx_isr(dev);
|
|
}
|
|
|
|
if (dev->isr_flags.isr_wkup) {
|
|
if (dev->candev.event_callback) {
|
|
dev->candev.event_callback(&dev->candev, CANDEV_EVENT_WAKE_UP, NULL);
|
|
}
|
|
}
|
|
|
|
unsigned int irq;
|
|
|
|
irq = irq_disable();
|
|
if (dev->isr_flags.isr_rx & 1) {
|
|
dev->isr_flags.isr_rx &= ~1;
|
|
irq_restore(irq);
|
|
rx_isr(dev);
|
|
}
|
|
else {
|
|
irq_restore(irq);
|
|
}
|
|
|
|
irq = irq_disable();
|
|
if (dev->isr_flags.isr_rx & 2) {
|
|
dev->isr_flags.isr_rx &= ~2;
|
|
irq_restore(irq);
|
|
rx_isr(dev);
|
|
}
|
|
else {
|
|
irq_restore(irq);
|
|
}
|
|
}
|
|
|
|
static inline int get_first_filter(can_t *dev)
|
|
{
|
|
#if CANDEV_STM32_CHAN_NUMOF == 1
|
|
(void)dev;
|
|
return 0;
|
|
#else
|
|
return dev->conf->first_filter;
|
|
#endif
|
|
}
|
|
|
|
static inline int get_nb_filter(can_t *dev)
|
|
{
|
|
#if CANDEV_STM32_CHAN_NUMOF == 1
|
|
(void)dev;
|
|
return CAN_STM32_NB_FILTER;
|
|
#else
|
|
return dev->conf->nb_filters;
|
|
#endif
|
|
}
|
|
|
|
static inline CAN_TypeDef *get_master(can_t *dev)
|
|
{
|
|
#if CANDEV_STM32_CHAN_NUMOF == 1
|
|
return dev->conf->can;
|
|
#else
|
|
return dev->conf->can_master;
|
|
#endif
|
|
}
|
|
|
|
static inline int is_master(can_t *dev)
|
|
{
|
|
#if CANDEV_STM32_CHAN_NUMOF == 1
|
|
(void)dev;
|
|
return 1;
|
|
#else
|
|
return dev->conf->can_master == dev->conf->can;
|
|
#endif
|
|
}
|
|
|
|
static void _wkup_cb(void *arg)
|
|
{
|
|
can_t *dev = arg;
|
|
gpio_irq_disable(dev->rx_pin);
|
|
|
|
DEBUG("int wkup: %p\n", arg);
|
|
|
|
dev->isr_flags.isr_wkup = 1;
|
|
|
|
if (dev->candev.event_callback) {
|
|
dev->candev.event_callback(&dev->candev, CANDEV_EVENT_ISR, NULL);
|
|
}
|
|
}
|
|
|
|
#if CANDEV_STM32_CHAN_NUMOF > 1
|
|
static void enable_int(can_t *dev, int master_from_slave)
|
|
{
|
|
DEBUG("EN int (%d) (%p)\n", master_from_slave, (void *)dev);
|
|
|
|
if (master_from_slave) {
|
|
can_t *master = _can[get_channel(get_master(dev))];
|
|
gpio_init_int(master->rx_pin, GPIO_IN, GPIO_FALLING, _wkup_cb, master);
|
|
}
|
|
else {
|
|
gpio_init_int(dev->rx_pin, GPIO_IN, GPIO_FALLING, _wkup_cb, dev);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void disable_int(can_t *dev, int master_from_slave)
|
|
{
|
|
DEBUG("DIS int (%d) (%p)\n", master_from_slave, (void *)dev);
|
|
|
|
if (master_from_slave) {
|
|
#if CANDEV_STM32_CHAN_NUMOF > 1
|
|
can_t *master = _can[get_channel(get_master(dev))];
|
|
gpio_irq_disable(master->rx_pin);
|
|
#ifndef CPU_FAM_STM32F1
|
|
candev_stm32_set_pins(master, master->tx_pin, master->rx_pin, master->af);
|
|
#else
|
|
candev_stm32_set_pins(master, master->tx_pin, master->rx_pin);
|
|
#endif
|
|
#endif
|
|
}
|
|
else {
|
|
gpio_irq_disable(dev->rx_pin);
|
|
#ifndef CPU_FAM_STM32F1
|
|
candev_stm32_set_pins(dev, dev->tx_pin, dev->rx_pin, dev->af);
|
|
#else
|
|
candev_stm32_set_pins(dev, dev->tx_pin, dev->rx_pin);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void turn_off(can_t *dev)
|
|
{
|
|
DEBUG("turn off (%p)\n", (void *)dev);
|
|
|
|
unsigned irq = irq_disable();
|
|
#if CANDEV_STM32_CHAN_NUMOF > 1
|
|
if (is_master(dev)) {
|
|
int chan = get_channel(dev->conf->can);
|
|
if (chan < CANDEV_STM32_CHAN_NUMOF - 1 && _status[chan + 1] != STATUS_SLEEP) {
|
|
/* a slave exists and is not sleeping */
|
|
_status[chan] = STATUS_READY_FOR_SLEEP;
|
|
}
|
|
else {
|
|
/* no slave or slave already sleeping */
|
|
if (_status[get_channel(dev->conf->can)] != STATUS_SLEEP) {
|
|
#ifdef STM32_PM_STOP
|
|
pm_unblock(STM32_PM_STOP);
|
|
#endif
|
|
}
|
|
_status[chan] = STATUS_SLEEP;
|
|
if (dev->conf->en_deep_sleep_wake_up) {
|
|
periph_clk_dis(APB1, dev->conf->rcc_mask);
|
|
enable_int(dev, 0);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
int master_chan = get_channel(get_master(dev));
|
|
switch (_status[master_chan]) {
|
|
case STATUS_READY_FOR_SLEEP:
|
|
_status[master_chan] = STATUS_SLEEP;
|
|
#ifdef STM32_PM_STOP
|
|
pm_unblock(STM32_PM_STOP);
|
|
#endif
|
|
/* Fall through */
|
|
case STATUS_NOT_USED:
|
|
if (dev->conf->en_deep_sleep_wake_up) {
|
|
periph_clk_dis(APB1, dev->conf->master_rcc_mask);
|
|
}
|
|
break;
|
|
}
|
|
if (dev->conf->en_deep_sleep_wake_up) {
|
|
periph_clk_dis(APB1, dev->conf->rcc_mask);
|
|
}
|
|
if (_status[get_channel(dev->conf->can)] != STATUS_SLEEP) {
|
|
#ifdef STM32_PM_STOP
|
|
pm_unblock(STM32_PM_STOP);
|
|
#endif
|
|
}
|
|
_status[get_channel(dev->conf->can)] = STATUS_SLEEP;
|
|
if (dev->conf->en_deep_sleep_wake_up) {
|
|
if (_status[master_chan] == STATUS_SLEEP) {
|
|
enable_int(dev, 1);
|
|
}
|
|
enable_int(dev, 0);
|
|
}
|
|
}
|
|
#else
|
|
if (_status[get_channel(dev->conf->can)] != STATUS_SLEEP) {
|
|
#ifdef STM32_PM_STOP
|
|
pm_unblock(STM32_PM_STOP);
|
|
#endif
|
|
}
|
|
_status[get_channel(dev->conf->can)] = STATUS_SLEEP;
|
|
if (dev->conf->en_deep_sleep_wake_up) {
|
|
periph_clk_dis(APB1, dev->conf->rcc_mask);
|
|
gpio_init_int(dev->rx_pin, GPIO_IN, GPIO_FALLING, _wkup_cb, dev);
|
|
}
|
|
#endif
|
|
irq_restore(irq);
|
|
}
|
|
|
|
static void turn_on(can_t *dev)
|
|
{
|
|
DEBUG("turn on (%p)\n", (void *)dev);
|
|
|
|
unsigned irq = irq_disable();
|
|
#if CANDEV_STM32_CHAN_NUMOF > 1
|
|
if (!is_master(dev)) {
|
|
int master_chan = get_channel(get_master(dev));
|
|
switch (_status[master_chan]) {
|
|
case STATUS_SLEEP:
|
|
_status[master_chan] = STATUS_READY_FOR_SLEEP;
|
|
if (dev->conf->en_deep_sleep_wake_up) {
|
|
disable_int(dev, 1);
|
|
}
|
|
#ifdef STM32_PM_STOP
|
|
pm_block(STM32_PM_STOP);
|
|
#endif
|
|
/* Fall through */
|
|
case STATUS_NOT_USED:
|
|
periph_clk_en(APB1, dev->conf->master_rcc_mask);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
if (_status[get_channel(dev->conf->can)] == STATUS_SLEEP) {
|
|
#ifdef STM32_PM_STOP
|
|
pm_block(STM32_PM_STOP);
|
|
#endif
|
|
if (dev->conf->en_deep_sleep_wake_up) {
|
|
disable_int(dev, 0);
|
|
}
|
|
periph_clk_en(APB1, dev->conf->rcc_mask);
|
|
}
|
|
_status[get_channel(dev->conf->can)] = STATUS_ON;
|
|
|
|
irq_restore(irq);
|
|
}
|
|
|
|
static int _wake_up(can_t *dev)
|
|
{
|
|
turn_on(dev);
|
|
return set_mode(dev->conf->can, MODE_NORMAL);
|
|
}
|
|
|
|
static int _sleep(can_t *dev)
|
|
{
|
|
int res = set_mode(dev->conf->can, MODE_SLEEP);
|
|
turn_off(dev);
|
|
return res;
|
|
}
|
|
|
|
static int _set(candev_t *candev, canopt_t opt, void *value, size_t value_len)
|
|
{
|
|
can_t *dev = container_of(candev, can_t, candev);
|
|
CAN_TypeDef *can = dev->conf->can;
|
|
int res = 0;
|
|
can_mode_t mode;
|
|
|
|
switch (opt) {
|
|
case CANOPT_BITTIMING:
|
|
if (value_len < sizeof(dev->candev.bittiming)) {
|
|
res = -EOVERFLOW;
|
|
}
|
|
else {
|
|
memcpy(&dev->candev.bittiming, value, sizeof(dev->candev.bittiming));
|
|
mode = get_mode(can);
|
|
if (mode == MODE_SLEEP) {
|
|
res = _wake_up(dev);
|
|
if (res != 0) {
|
|
res = -EBUSY;
|
|
break;
|
|
}
|
|
}
|
|
res = set_mode(can, MODE_INIT);
|
|
if (res == 0) {
|
|
set_bit_timing(dev);
|
|
res = sizeof(dev->candev.bittiming);
|
|
}
|
|
if (mode == MODE_SLEEP) {
|
|
if (_sleep(dev) < 0) {
|
|
res = -EBUSY;
|
|
}
|
|
}
|
|
else if (set_mode(can, mode) < 0) {
|
|
res = -EBUSY;
|
|
}
|
|
}
|
|
break;
|
|
case CANOPT_STATE:
|
|
if (value_len < sizeof(canopt_state_t)) {
|
|
res = -EOVERFLOW;
|
|
}
|
|
else {
|
|
switch (*((canopt_state_t *)value)) {
|
|
case CANOPT_STATE_OFF:
|
|
case CANOPT_STATE_SLEEP:
|
|
DEBUG("candev_stm32 %p: power down\n", (void *)dev);
|
|
res = _sleep(dev);
|
|
break;
|
|
case CANOPT_STATE_ON:
|
|
DEBUG("candev_stm32 %p: power up\n", (void *)dev);
|
|
res = _wake_up(dev);
|
|
break;
|
|
case CANOPT_STATE_LISTEN_ONLY:
|
|
mode = get_mode(can);
|
|
res = set_mode(can, MODE_INIT);
|
|
can->BTR |= CAN_BTR_SILM;
|
|
res += set_mode(can, mode);
|
|
break;
|
|
case CANOPT_STATE_LOOPBACK:
|
|
DEBUG("candev_stm32 %p: Loopback\n", (void *)dev);
|
|
res = set_mode(can, MODE_INIT);
|
|
can->BTR |= CAN_BTR_LBKM;
|
|
res += set_mode(can, MODE_NORMAL);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
res = -ENOTSUP;
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
#define CAN_ESR_REC_SHIFT 24
|
|
#define CAN_ESR_TEC_SHIFT 16
|
|
|
|
static int _get(candev_t *candev, canopt_t opt, void *value, size_t max_len)
|
|
{
|
|
can_t *dev = container_of(candev, can_t, candev);
|
|
CAN_TypeDef *can = dev->conf->can;
|
|
int res = 0;
|
|
|
|
switch (opt) {
|
|
case CANOPT_BITTIMING:
|
|
if (max_len < sizeof(dev->candev.bittiming)) {
|
|
res = -EOVERFLOW;
|
|
}
|
|
else {
|
|
memcpy(value, &dev->candev.bittiming, sizeof(dev->candev.bittiming));
|
|
res = sizeof(dev->candev.bittiming);
|
|
}
|
|
break;
|
|
case CANOPT_BITTIMING_CONST:
|
|
if (max_len < sizeof(bittiming_const)) {
|
|
res = -EOVERFLOW;
|
|
}
|
|
else {
|
|
memcpy(value, &bittiming_const, sizeof(bittiming_const));
|
|
res = sizeof(bittiming_const);
|
|
}
|
|
break;
|
|
case CANOPT_CLOCK:
|
|
if (max_len < sizeof(uint32_t)) {
|
|
res = -EOVERFLOW;
|
|
}
|
|
else {
|
|
*((uint32_t *)value) = CLOCK_APB1;
|
|
res = sizeof(uint32_t);
|
|
}
|
|
break;
|
|
case CANOPT_RX_FILTERS:
|
|
if (max_len % sizeof(struct can_filter) != 0) {
|
|
res = -EOVERFLOW;
|
|
}
|
|
else {
|
|
unsigned en_filt = 0;
|
|
unsigned base_filter = get_first_filter(dev);
|
|
unsigned last_filter = base_filter + get_nb_filter(dev);
|
|
for (unsigned i = base_filter; i < last_filter; i++) {
|
|
if ((get_master(dev)->FA1R & (1u << i)) == (1u << i)) {
|
|
en_filt++;
|
|
}
|
|
}
|
|
if (max_len / sizeof(struct can_filter) < en_filt) {
|
|
res = -EOVERFLOW;
|
|
}
|
|
else {
|
|
for (unsigned i = 0; i < en_filt; i++) {
|
|
struct can_filter *filter = (struct can_filter *)value + i;
|
|
get_can_filter(get_master(
|
|
dev), i + base_filter, &filter->can_id,
|
|
&filter->can_mask);
|
|
}
|
|
res = en_filt * sizeof(struct can_filter);
|
|
}
|
|
}
|
|
break;
|
|
case CANOPT_TEC:
|
|
if (max_len != sizeof(uint16_t)) {
|
|
res = -EOVERFLOW;
|
|
}
|
|
else {
|
|
uint16_t *tec = (uint16_t *)value;
|
|
*tec = (can->ESR & CAN_ESR_TEC) >> CAN_ESR_TEC_SHIFT;
|
|
res = sizeof(uint16_t);
|
|
}
|
|
break;
|
|
case CANOPT_REC:
|
|
if (max_len != sizeof(uint16_t)) {
|
|
res = -EOVERFLOW;
|
|
}
|
|
else {
|
|
uint16_t *rec = (uint16_t *)value;
|
|
*rec = (can->ESR & CAN_ESR_REC) >> CAN_ESR_REC_SHIFT;
|
|
res = sizeof(uint16_t);
|
|
}
|
|
break;
|
|
default:
|
|
res = -ENOTSUP;
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static int _set_filter(candev_t *candev, const struct can_filter *filter)
|
|
{
|
|
can_t *dev = container_of(candev, can_t, candev);
|
|
|
|
DEBUG("_set_filter: dev=%p, filter=0x%" PRIx32 "\n", (void *)candev, filter->can_id);
|
|
|
|
int first_filter = get_first_filter(dev);
|
|
int last_filter = first_filter + get_nb_filter(dev);
|
|
|
|
uint8_t i;
|
|
for (i = first_filter; i < last_filter; i++) {
|
|
if (!filter_is_set(get_master(dev), i)) {
|
|
get_master(dev)->FMR = CAN_FMR_FINIT;
|
|
set_filter(get_master(
|
|
dev), filter->can_id, filter->can_mask, i, i % CAN_STM32_RX_MAILBOXES);
|
|
get_master(dev)->FMR &= ~CAN_FMR_FINIT;
|
|
break;
|
|
}
|
|
}
|
|
if (i == last_filter) {
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
return i - first_filter;
|
|
}
|
|
|
|
static int _remove_filter(candev_t *candev, const struct can_filter *filter)
|
|
{
|
|
can_t *dev = container_of(candev, can_t, candev);
|
|
|
|
int first_filter = get_first_filter(dev);
|
|
int last_filter = first_filter + get_nb_filter(dev);
|
|
|
|
uint8_t i;
|
|
|
|
for (i = first_filter; i < last_filter; i++) {
|
|
if (filter_is_set(get_master(dev), i)) {
|
|
uint32_t filt, mask;
|
|
/* Clear RTR and ERR flags as they are ignored by the set/get filter */
|
|
get_can_filter(get_master(dev), i, &filt, &mask);
|
|
DEBUG("_remove_filter: filter=0x%" PRIx32 ",0x%" PRIx32 ", nb=%d, "
|
|
"dev_filter=0x%" PRIx32 ",0x%" PRIx32 "\n",
|
|
filter->can_id, filter->can_mask, (int)i, filt, mask);
|
|
if ((filt == filter->can_id) && /* ID match */
|
|
/* Filter match (extended case */
|
|
(((filt & CAN_EFF_FLAG) &&
|
|
((mask & CAN_EFF_MASK) == (filter->can_mask & CAN_EFF_MASK)))
|
|
/* Filter match (standard case */
|
|
|| (!(filt & CAN_EFF_FLAG) &&
|
|
((mask & CAN_SFF_MASK) == (filter->can_mask & CAN_SFF_MASK))))) {
|
|
get_master(dev)->FMR = CAN_FMR_FINIT;
|
|
unset_filter(get_master(dev), i);
|
|
get_master(dev)->FMR &= ~CAN_FMR_FINIT;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (i == last_filter) {
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void tx_conf(can_t *dev, int mailbox)
|
|
{
|
|
candev_t *candev = (candev_t *) dev;
|
|
const struct can_frame *frame = dev->tx_mailbox[mailbox];
|
|
|
|
dev->tx_mailbox[mailbox] = NULL;
|
|
|
|
DEBUG("_tx_conf: device=%p, mb=%d\n", (void *)dev, mailbox);
|
|
|
|
if (frame && dev->candev.event_callback) {
|
|
dev->candev.event_callback(candev, CANDEV_EVENT_TX_CONFIRMATION,
|
|
(void *) frame);
|
|
}
|
|
}
|
|
|
|
static void tx_irq_handler(can_t *dev)
|
|
{
|
|
CAN_TypeDef *can = dev->conf->can;
|
|
int flags = dev->isr_flags.isr_tx;
|
|
|
|
DEBUG("tx irq\n");
|
|
|
|
if (can->TSR & CAN_TSR_RQCP0) {
|
|
if (can->TSR & CAN_TSR_TXOK0) {
|
|
dev->isr_flags.isr_tx |= 1;
|
|
}
|
|
can->TSR |= CAN_TSR_RQCP0;
|
|
}
|
|
if (can->TSR & CAN_TSR_RQCP1) {
|
|
if (can->TSR & CAN_TSR_TXOK1) {
|
|
dev->isr_flags.isr_tx |= 2;
|
|
}
|
|
can->TSR |= CAN_TSR_RQCP1;
|
|
}
|
|
if (can->TSR & CAN_TSR_RQCP2) {
|
|
if (can->TSR & CAN_TSR_TXOK2) {
|
|
dev->isr_flags.isr_tx |= 4;
|
|
}
|
|
can->TSR |= CAN_TSR_RQCP2;
|
|
}
|
|
|
|
if (dev->candev.event_callback && flags != dev->isr_flags.isr_tx) {
|
|
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_ISR, NULL);
|
|
}
|
|
}
|
|
|
|
static void tx_isr(can_t *dev)
|
|
{
|
|
unsigned int irq;
|
|
|
|
irq = irq_disable();
|
|
if (dev->isr_flags.isr_tx & 1) {
|
|
dev->isr_flags.isr_tx &= ~1;
|
|
irq_restore(irq);
|
|
tx_conf(dev, 0);
|
|
}
|
|
else {
|
|
irq_restore(irq);
|
|
}
|
|
|
|
irq = irq_disable();
|
|
if (dev->isr_flags.isr_tx & 2) {
|
|
dev->isr_flags.isr_tx &= ~2;
|
|
irq_restore(irq);
|
|
tx_conf(dev, 1);
|
|
}
|
|
else {
|
|
irq_restore(irq);
|
|
}
|
|
|
|
irq = irq_disable();
|
|
if (dev->isr_flags.isr_tx & 4) {
|
|
dev->isr_flags.isr_tx &= ~4;
|
|
irq_restore(irq);
|
|
tx_conf(dev, 2);
|
|
}
|
|
else {
|
|
irq_restore(irq);
|
|
}
|
|
}
|
|
|
|
static void rx_irq_handler(can_t *dev, int mailbox)
|
|
{
|
|
CAN_TypeDef *can = dev->conf->can;
|
|
candev_t *candev = (candev_t *) dev;
|
|
|
|
DEBUG("rx irq\n");
|
|
if ((can->RF0R & CAN_RF0R_FOVR0) == CAN_RF0R_FOVR0) {
|
|
can->RF0R |= CAN_RF0R_FOVR0;
|
|
if (dev->candev.event_callback) {
|
|
dev->candev.event_callback(candev, CANDEV_EVENT_RX_ERROR, NULL);
|
|
}
|
|
return;
|
|
}
|
|
if ((can->RF1R & CAN_RF1R_FOVR1) == CAN_RF1R_FOVR1) {
|
|
can->RF1R |= CAN_RF1R_FOVR1;
|
|
if (dev->candev.event_callback) {
|
|
dev->candev.event_callback(candev, CANDEV_EVENT_RX_ERROR, NULL);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!dev->rx_fifo.is_full) {
|
|
int i = dev->rx_fifo.write_idx;
|
|
read_frame(dev, &(dev->rx_fifo.frame[i]), mailbox);
|
|
|
|
if (!dev->isr_flags.isr_rx) {
|
|
dev->isr_flags.isr_rx |= mailbox + 1;
|
|
if (dev->candev.event_callback) {
|
|
dev->candev.event_callback(candev, CANDEV_EVENT_ISR, NULL);
|
|
}
|
|
}
|
|
|
|
dev->rx_fifo.write_idx++;
|
|
if (dev->rx_fifo.write_idx == CAN_STM32_RX_MAIL_FIFO) {
|
|
dev->rx_fifo.write_idx = 0;
|
|
}
|
|
if (dev->rx_fifo.write_idx == dev->rx_fifo.read_idx) {
|
|
dev->rx_fifo.is_full = 1;
|
|
}
|
|
}
|
|
else {
|
|
if (dev->candev.event_callback) {
|
|
dev->candev.event_callback(candev, CANDEV_EVENT_RX_ERROR, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void rx_isr(can_t *dev)
|
|
{
|
|
DEBUG("_rx_isr: device=%p\n", (void *)dev);
|
|
|
|
while (dev->rx_fifo.is_full || dev->rx_fifo.read_idx != dev->rx_fifo.write_idx) {
|
|
int i = dev->rx_fifo.read_idx;
|
|
|
|
if (dev->candev.event_callback) {
|
|
dev->candev.event_callback(&dev->candev,
|
|
CANDEV_EVENT_RX_INDICATION,
|
|
&dev->rx_fifo.frame[i]);
|
|
}
|
|
|
|
dev->rx_fifo.read_idx++;
|
|
if (dev->rx_fifo.read_idx == CAN_STM32_RX_MAIL_FIFO) {
|
|
dev->rx_fifo.read_idx = 0;
|
|
}
|
|
|
|
dev->rx_fifo.is_full = 0;
|
|
}
|
|
}
|
|
|
|
static void sce_irq_handler(can_t *dev)
|
|
{
|
|
CAN_TypeDef *can = dev->conf->can;
|
|
candev_t *candev = (candev_t *) dev;
|
|
|
|
DEBUG("sce irq: ");
|
|
|
|
if ((can->MSR & CAN_MSR_ERRI) == CAN_MSR_ERRI) {
|
|
can->MSR = CAN_MSR_ERRI;
|
|
if ((can->ESR & CAN_ESR_BOFF) == CAN_ESR_BOFF) {
|
|
DEBUG("bus-off\n");
|
|
if (!dev->conf->abom) {
|
|
set_mode(can, MODE_INIT);
|
|
}
|
|
if (dev->candev.event_callback) {
|
|
dev->candev.event_callback(candev, CANDEV_EVENT_BUS_OFF, NULL);
|
|
}
|
|
}
|
|
else if ((can->ESR & CAN_ESR_EPVF) == CAN_ESR_EPVF) {
|
|
DEBUG("error passive\n");
|
|
if (dev->candev.event_callback) {
|
|
dev->candev.event_callback(candev, CANDEV_EVENT_ERROR_PASSIVE, NULL);
|
|
}
|
|
}
|
|
else if ((can->ESR & CAN_ESR_EWGF) == CAN_ESR_EWGF) {
|
|
DEBUG("error warning\n");
|
|
if (dev->candev.event_callback) {
|
|
dev->candev.event_callback(candev, CANDEV_EVENT_ERROR_WARNING, NULL);
|
|
}
|
|
}
|
|
}
|
|
else if ((can->MSR & CAN_MSR_WKUI) == CAN_MSR_WKUI) {
|
|
can->MSR = CAN_MSR_WKUI;
|
|
DEBUG("wakeup\n");
|
|
if (dev->candev.event_callback) {
|
|
dev->candev.event_callback(candev, CANDEV_EVENT_WAKE_UP, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(CPU_FAM_STM32F0)
|
|
#define CAN_MSR_INT_MASK 0x0000001C
|
|
#define CAN_TSR_INT_MASK 0x000F0F0F
|
|
#define CAN_RFxR_INT_MASK 0x0000001B
|
|
#define CAN_ESR_INT_MASK 0x00000077
|
|
|
|
void isr_cec_can(void)
|
|
{
|
|
DEBUG("bxCAN irq\n");
|
|
|
|
if ((CAN->ESR & CAN_ESR_INT_MASK) || (CAN->MSR & CAN_MSR_INT_MASK)) {
|
|
sce_irq_handler(_can[0]);
|
|
}
|
|
if (CAN->TSR & CAN_TSR_INT_MASK) {
|
|
tx_irq_handler(_can[0]);
|
|
}
|
|
if (CAN->RF0R & CAN_RFxR_INT_MASK) {
|
|
rx_irq_handler(_can[0], 0);
|
|
}
|
|
if (CAN->RF1R & CAN_RFxR_INT_MASK) {
|
|
rx_irq_handler(_can[0], 1);
|
|
}
|
|
|
|
cortexm_isr_end();
|
|
}
|
|
#else
|
|
void ISR_CAN1_TX(void)
|
|
{
|
|
tx_irq_handler(_can[0]);
|
|
|
|
cortexm_isr_end();
|
|
}
|
|
|
|
void ISR_CAN1_RX0(void)
|
|
{
|
|
rx_irq_handler(_can[0], 0);
|
|
|
|
cortexm_isr_end();
|
|
}
|
|
|
|
void ISR_CAN1_RX1(void)
|
|
{
|
|
rx_irq_handler(_can[0], 1);
|
|
|
|
cortexm_isr_end();
|
|
}
|
|
|
|
void ISR_CAN1_SCE(void)
|
|
{
|
|
sce_irq_handler(_can[0]);
|
|
|
|
cortexm_isr_end();
|
|
}
|
|
|
|
#if CANDEV_STM32_CHAN_NUMOF > 1
|
|
void ISR_CAN2_TX(void)
|
|
{
|
|
tx_irq_handler(_can[1]);
|
|
|
|
cortexm_isr_end();
|
|
}
|
|
|
|
void ISR_CAN2_RX0(void)
|
|
{
|
|
rx_irq_handler(_can[1], 0);
|
|
|
|
cortexm_isr_end();
|
|
}
|
|
|
|
void ISR_CAN2_RX1(void)
|
|
{
|
|
rx_irq_handler(_can[1], 1);
|
|
|
|
cortexm_isr_end();
|
|
}
|
|
|
|
void ISR_CAN2_SCE(void)
|
|
{
|
|
sce_irq_handler(_can[1]);
|
|
|
|
cortexm_isr_end();
|
|
}
|
|
#endif
|
|
|
|
#if CANDEV_STM32_CHAN_NUMOF > 2
|
|
void ISR_CAN3_TX(void)
|
|
{
|
|
tx_irq_handler(_can[2]);
|
|
|
|
cortexm_isr_end();
|
|
}
|
|
|
|
void ISR_CAN3_RX0(void)
|
|
{
|
|
rx_irq_handler(_can[2], 0);
|
|
|
|
cortexm_isr_end();
|
|
}
|
|
|
|
void ISR_CAN3_RX1(void)
|
|
{
|
|
rx_irq_handler(_can[2], 1);
|
|
|
|
cortexm_isr_end();
|
|
}
|
|
|
|
void ISR_CAN3_SCE(void)
|
|
{
|
|
sce_irq_handler(_can[2]);
|
|
|
|
cortexm_isr_end();
|
|
}
|
|
#endif
|
|
#endif
|