mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
cpu/samd5x: implement driver for samd5x CAN controller
cpu/samd5x: load RX mailbox
This commit is contained in:
parent
3eeac9895d
commit
e4e5558694
@ -2,4 +2,8 @@ ifneq (,$(filter periph_gpio_tamper_wake,$(USEMODULE)))
|
||||
USEMODULE += periph_rtc_rtt
|
||||
endif
|
||||
|
||||
ifneq (,$(filter periph_can,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += can_rx_mailbox
|
||||
endif
|
||||
|
||||
include $(RIOTCPU)/sam0_common/Makefile.dep
|
||||
|
@ -7,5 +7,6 @@ FEATURES_PROVIDED += periph_gpio_tamper_wake
|
||||
FEATURES_PROVIDED += periph_rtc_mem
|
||||
FEATURES_PROVIDED += periph_spi_on_qspi
|
||||
FEATURES_PROVIDED += periph_uart_collision
|
||||
FEATURES_PROVIDED += can_rx_mailbox
|
||||
|
||||
include $(RIOTCPU)/sam0_common/Makefile.features
|
||||
|
44
cpu/samd5x/include/can_params.h
Normal file
44
cpu/samd5x/include/can_params.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2024 ML!PA Consulting GmbH
|
||||
*
|
||||
* 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_samd5x
|
||||
* @brief CPU specific definitions for CAN controllers
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief SAMD5x CAN controller (M_CAN Bosch) default device parameters
|
||||
*
|
||||
* @author Firas Hamdi <firas.hamdi@ml-pa.com>
|
||||
*/
|
||||
|
||||
#ifndef CAN_PARAMS_H
|
||||
#define CAN_PARAMS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "can/device.h"
|
||||
|
||||
/** Default SAMD5x CAN devices parameters */
|
||||
static const candev_params_t candev_params[] = {
|
||||
{
|
||||
.name = "can_samd5x_0",
|
||||
},
|
||||
{
|
||||
.name = "can_samd5x_1",
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CAN_PARAMS_H */
|
||||
/** @} */
|
156
cpu/samd5x/include/candev_samd5x.h
Normal file
156
cpu/samd5x/include/candev_samd5x.h
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 2024 ML!PA Consulting GmbH
|
||||
*
|
||||
* 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_samd5x
|
||||
* @brief CPU specific definitions for CAN controllers
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief SAMD5x CAN controller (M_CAN Bosch) driver
|
||||
*
|
||||
* @author Firas Hamdi <firas.hamdi@ml-pa.com>
|
||||
*/
|
||||
|
||||
#ifndef CANDEV_SAMD5X_H
|
||||
#define CANDEV_SAMD5X_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(CAN_INST_NUM)
|
||||
#include "can/candev.h"
|
||||
|
||||
#ifndef CANDEV_SAMD5X_DEFAULT_BITRATE
|
||||
/** Default bitrate */
|
||||
#define CANDEV_SAMD5X_DEFAULT_BITRATE 500000U
|
||||
#endif
|
||||
|
||||
#ifndef CANDEV_SAMD5X_DEFAULT_SPT
|
||||
/** Default sampling-point */
|
||||
#define CANDEV_SAMD5X_DEFAULT_SPT 875
|
||||
#endif
|
||||
|
||||
#ifndef CANDEV_SAMD5X_DEFAULT_STD_FILTER_NUM
|
||||
#define CANDEV_SAMD5X_DEFAULT_STD_FILTER_NUM 3
|
||||
#endif
|
||||
|
||||
#ifndef CANDEV_SAMD5X_DEFAULT_EXT_FILTER_NUM
|
||||
#define CANDEV_SAMD5X_DEFAULT_EXT_FILTER_NUM 3
|
||||
#endif
|
||||
|
||||
#ifndef CANDEV_SAMD5X_DEFAULT_RX_FIFO_0_ELTS_NUM
|
||||
#define CANDEV_SAMD5X_DEFAULT_RX_FIFO_0_ELTS_NUM 32
|
||||
#endif
|
||||
|
||||
#ifndef CANDEV_SAMD5X_DEFAULT_RX_FIFO_1_ELTS_NUM
|
||||
#define CANDEV_SAMD5X_DEFAULT_RX_FIFO_1_ELTS_NUM 32
|
||||
#endif
|
||||
|
||||
#ifndef CANDEV_SAMD5X_DEFAULT_TX_EVT_FIFO_ELTS_NUM
|
||||
#define CANDEV_SAMD5X_DEFAULT_TX_EVT_FIFO_ELTS_NUM 16
|
||||
#endif
|
||||
|
||||
#ifndef CANDEV_SAMD5X_DEFAULT_TX_BUFFER_NUM
|
||||
#define CANDEV_SAMD5X_DEFAULT_TX_BUFFER_NUM 16
|
||||
#endif
|
||||
|
||||
#ifndef CANDEV_SAMD5X_DEFAULT_TX_BUFFER_FIFO_QUEUE_NUM
|
||||
#define CANDEV_SAMD5X_DEFAULT_TX_BUFFER_FIFO_QUEUE_NUM 16
|
||||
#endif
|
||||
|
||||
/* unit: elements */
|
||||
#define CANDEV_SAMD5X_MAX_STD_FILTER 128
|
||||
#define CANDEV_SAMD5X_MAX_EXT_FILTER 64
|
||||
#define CANDEV_SAMD5X_MAX_RX_FIFO_0_ELTS 64
|
||||
#define CANDEV_SAMD5X_MAX_RX_FIFO_1_ELTS 64
|
||||
#define CANDEV_SAMD5X_MAX_RX_BUFFER 64
|
||||
#define CANDEV_SAMD5X_MAX_TX_EVT_FIFO_ELTS 32
|
||||
#define CANDEV_SAMD5X_MAX_TX_BUFFER 32
|
||||
#define CANDEV_SAMD5X_MSG_RAM_MAX_SIZE 448
|
||||
|
||||
/**
|
||||
* @brief CAN device configuration descriptor
|
||||
*/
|
||||
typedef struct {
|
||||
/** CAN device handler */
|
||||
Can *can;
|
||||
/** CAN Rx pin */
|
||||
gpio_t rx_pin;
|
||||
/** CAN Tx pin */
|
||||
gpio_t tx_pin;
|
||||
/** GCLK source supplying the CAN controller */
|
||||
uint8_t gclk_src;
|
||||
} can_conf_t;
|
||||
#define HAVE_CAN_CONF_T
|
||||
|
||||
/**
|
||||
* @brief CAN message RAM accessible to the CAN controller
|
||||
*/
|
||||
typedef struct {
|
||||
/** Standard filters space in the CAN message RAM */
|
||||
CanMramSidfe std_filter[CANDEV_SAMD5X_DEFAULT_STD_FILTER_NUM];
|
||||
/** Extended filters space in the CAN message RAM */
|
||||
CanMramXifde ext_filter[CANDEV_SAMD5X_DEFAULT_EXT_FILTER_NUM];
|
||||
/** Reception FIFO_0 space in the CAN message RAM */
|
||||
CanMramRxf0e rx_fifo_0[CANDEV_SAMD5X_DEFAULT_RX_FIFO_0_ELTS_NUM];
|
||||
/** Reception FIFO_1 space in the CAN message RAM */
|
||||
CanMramRxf1e rx_fifo_1[CANDEV_SAMD5X_DEFAULT_RX_FIFO_1_ELTS_NUM];
|
||||
/** Reception buffers space in the CAN message RAM */
|
||||
CanMramRxbe rx_buffer[CANDEV_SAMD5X_MAX_RX_BUFFER];
|
||||
/** Transmission events FIFO space in the CAN message RAM */
|
||||
CanMramTxefe tx_event_fifo[CANDEV_SAMD5X_DEFAULT_TX_EVT_FIFO_ELTS_NUM];
|
||||
/** Transmission FIFO space in the CAN message RAM */
|
||||
CanMramTxbe tx_fifo_queue[CANDEV_SAMD5X_DEFAULT_TX_BUFFER_FIFO_QUEUE_NUM];
|
||||
} msg_ram_conf_t;
|
||||
|
||||
/**
|
||||
* @brief CAN device descriptor
|
||||
*/
|
||||
typedef struct {
|
||||
/** Structure to hold driver state */
|
||||
candev_t candev;
|
||||
/** CAN device configuration descriptor */
|
||||
const can_conf_t *conf;
|
||||
/** CAN message RAM accessible to the CAN controller */
|
||||
msg_ram_conf_t msg_ram_conf;
|
||||
/** Enable/Disable Transceiver Delay Compensation */
|
||||
bool tdc_ctrl;
|
||||
/** False to use Tx FIFO operation, True to use Tx Queue operation */
|
||||
bool tx_fifo_queue_ctrl;
|
||||
} can_t;
|
||||
#define HAVE_CAN_T
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable the transmitter delay compensation
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
*
|
||||
*/
|
||||
void candev_samd5x_tdc_control(can_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Enter the device into sleep mode
|
||||
*
|
||||
* @param[in] candev candev driver
|
||||
*
|
||||
*/
|
||||
void candev_samd5x_enter_sleep_mode(candev_t *candev);
|
||||
|
||||
/**
|
||||
* @brief Wake up the device from sleep mode
|
||||
*
|
||||
* @param[in] candev candev driver
|
||||
*
|
||||
*/
|
||||
void candev_samd5x_exit_sleep_mode(candev_t *candev);
|
||||
|
||||
#endif /* CAN_INST_NUM */
|
||||
#endif /* CANDEV_SAMD5X_H */
|
||||
/** @} */
|
@ -25,6 +25,7 @@
|
||||
#include "macros/units.h"
|
||||
#include "periph_cpu_common.h"
|
||||
|
||||
#include "candev_samd5x.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
802
cpu/samd5x/periph/can.c
Normal file
802
cpu/samd5x/periph/can.c
Normal file
@ -0,0 +1,802 @@
|
||||
/*
|
||||
* Copyright (C) 2023 ML!PA Consulting GmbH
|
||||
*
|
||||
* 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_samd5x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Implementation of the CAN controller driver
|
||||
*
|
||||
* @author Firas Hamdi <firas.hamdi@ml-pa.com>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "periph/can.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "can/device.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief Value from SAMD5x/E5x Family datasheet, Tables 39-13 and 39-17
|
||||
*/
|
||||
#define CANDEV_SAMD5X_CLASSIC_FILTER 0x02
|
||||
/**
|
||||
* @brief Set to 1 to access the internal loopback mode.
|
||||
* Check SAMD5x/E5x Family datasheet, Figure 39-4
|
||||
*/
|
||||
#define CANDEV_SAMD5X_INTERNAL_LOOPBACK 0
|
||||
|
||||
/**
|
||||
* @brief Specific configuration of the CAN filter
|
||||
*/
|
||||
enum {
|
||||
CANDEV_SAMD5X_FILTER_DISABLE = 0x00,
|
||||
CANDEV_SAMD5X_FILTER_RX_FIFO_0,
|
||||
CANDEV_SAMD5X_FILTER_RX_FIFO_1
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Configuration of how to handle frames not matching the CAN filters
|
||||
*/
|
||||
enum {
|
||||
/* Direct frames not matching any CAN filters applied to Rx FIFO 0 */
|
||||
CAN_ACCEPT_RX_FIFO_0 = 0x00,
|
||||
/* Direct frames not matching any CAN filters applied to Rx FIFO 1 */
|
||||
CAN_ACCEPT_RX_FIFO_1,
|
||||
/* Reject all frames not matching any CAN filters applied */
|
||||
CAN_REJECT
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
MODE_INIT,
|
||||
MODE_TEST,
|
||||
} can_mode_t;
|
||||
|
||||
typedef struct {
|
||||
/* Message Marker Put index */
|
||||
uint8_t put:4;
|
||||
/* Message Marker Get index */
|
||||
uint8_t get:4;
|
||||
} can_mm_t;
|
||||
|
||||
/* Used to handle interrupts generated by the CAN controller 0 */
|
||||
static can_t *_can_0;
|
||||
/* Used to handle interrupts generated by the CAN controller 1 */
|
||||
static can_t *_can_1;
|
||||
|
||||
static int _init(candev_t *candev);
|
||||
static int _send(candev_t *candev, const struct can_frame *frame);
|
||||
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 int _set(candev_t *candev, canopt_t opt, void *value, size_t value_len);
|
||||
static void _isr(candev_t *candev);
|
||||
|
||||
static int _set_mode(Can *can, can_mode_t mode);
|
||||
|
||||
static const candev_driver_t candev_samd5x_driver = {
|
||||
.init = _init,
|
||||
.send = _send,
|
||||
.set_filter = _set_filter,
|
||||
.remove_filter = _remove_filter,
|
||||
.set = _set,
|
||||
.isr = _isr,
|
||||
};
|
||||
|
||||
/* Values taken from SAMD5x/E5x datasheet section 39.8.8 */
|
||||
static const struct can_bittiming_const bittiming_const = {
|
||||
.tseg1_min = 1,
|
||||
.tseg1_max = 256,
|
||||
.tseg2_min = 1,
|
||||
.tseg2_max = 128,
|
||||
.sjw_max = 128,
|
||||
.brp_min = 1,
|
||||
.brp_max = 512,
|
||||
.brp_inc = 1,
|
||||
};
|
||||
|
||||
static int _power_on(can_t *dev)
|
||||
{
|
||||
if (dev->conf->can == CAN0) {
|
||||
DEBUG_PUTS("CAN0 controller is used");
|
||||
MCLK->AHBMASK.reg |= MCLK_AHBMASK_CAN0;
|
||||
}
|
||||
else if (dev->conf->can == CAN1) {
|
||||
DEBUG_PUTS("CAN1 controller is used");
|
||||
MCLK->AHBMASK.reg |= MCLK_AHBMASK_CAN1;
|
||||
}
|
||||
else {
|
||||
DEBUG_PUTS("Unsupported CAN channel");
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _power_off(can_t *dev)
|
||||
{
|
||||
if (dev->conf->can == CAN0) {
|
||||
DEBUG_PUTS("CAN0 controller is used");
|
||||
MCLK->AHBMASK.reg &= ~MCLK_AHBMASK_CAN0;
|
||||
}
|
||||
else if (dev->conf->can == CAN1) {
|
||||
DEBUG_PUTS("CAN1 controller is used");
|
||||
MCLK->AHBMASK.reg &= ~MCLK_AHBMASK_CAN1;
|
||||
}
|
||||
else {
|
||||
DEBUG_PUTS("Unsupported CAN channel");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _enter_init_mode(Can *can)
|
||||
{
|
||||
can->CCCR.reg |= CAN_CCCR_INIT;
|
||||
while (!(can->CCCR.reg & CAN_CCCR_INIT)) {}
|
||||
DEBUG_PUTS("Device in init mode");
|
||||
}
|
||||
|
||||
static void _exit_init_mode(Can *can)
|
||||
{
|
||||
if (can->CCCR.reg & CAN_CCCR_INIT) {
|
||||
can->CCCR.reg &= ~CAN_CCCR_INIT;
|
||||
}
|
||||
|
||||
while (can->CCCR.reg & CAN_CCCR_INIT) {}
|
||||
DEBUG_PUTS("Device out of init mode");
|
||||
}
|
||||
|
||||
static int _set_mode(Can *can, can_mode_t can_mode)
|
||||
{
|
||||
switch (can_mode) {
|
||||
case MODE_INIT:
|
||||
_enter_init_mode(can);
|
||||
can->CCCR.reg |= CAN_CCCR_CCE;
|
||||
break;
|
||||
case MODE_TEST:
|
||||
DEBUG_PUTS("test mode");
|
||||
_enter_init_mode(can);
|
||||
/* CCCR.TEST and CCCR.MON can be set only when CCCR.INIT and CCCR.CCE are set */
|
||||
can->CCCR.reg |= CAN_CCCR_CCE;
|
||||
can->CCCR.reg |= CAN_CCCR_TEST;
|
||||
can->TEST.reg |= CAN_TEST_LBCK;
|
||||
#if IS_ACTIVE(CANDEV_SAMD5X_INTERNAL_LOOPBACK)
|
||||
can->CCCR.reg |= CAN_CCCR_MON;
|
||||
#endif
|
||||
_exit_init_mode(can);
|
||||
break;
|
||||
default:
|
||||
DEBUG_PUTS("Unsupported mode");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _setup_clock(can_t *dev)
|
||||
{
|
||||
if (dev->conf->can == CAN0) {
|
||||
GCLK->PCHCTRL[CAN0_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(dev->conf->gclk_src);
|
||||
}
|
||||
else if (dev->conf->can == CAN1) {
|
||||
GCLK->PCHCTRL[CAN1_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(dev->conf->gclk_src);
|
||||
}
|
||||
else {
|
||||
DEBUG_PUTS("CAN channel not supported");
|
||||
}
|
||||
}
|
||||
|
||||
static void _set_bit_timing(can_t *dev)
|
||||
{
|
||||
assert(dev->candev.bittiming.sjw >= 1);
|
||||
assert(dev->candev.bittiming.phase_seg2 >= 1);
|
||||
assert(dev->candev.bittiming.phase_seg1 + dev->candev.bittiming.prop_seg >= 1);
|
||||
assert(dev->candev.bittiming.brp >= 1);
|
||||
|
||||
DEBUG("bitrate=%" PRIu32 ", sample_point=%" PRIu32 ", brp=%" PRIu32 ", prop_seg=%" PRIu32
|
||||
", phase_seg1=%" PRIu32 ", phase_seg2=%" PRIu32 ", sjw=%" PRIu32 "\n",
|
||||
dev->candev.bittiming.bitrate, dev->candev.bittiming.sample_point,
|
||||
dev->candev.bittiming.brp, dev->candev.bittiming.prop_seg,
|
||||
dev->candev.bittiming.phase_seg1, dev->candev.bittiming.phase_seg2,
|
||||
dev->candev.bittiming.sjw);
|
||||
|
||||
/* Set bit timing */
|
||||
dev->conf->can->NBTP.reg = (uint32_t)((CAN_NBTP_NTSEG2(dev->candev.bittiming.phase_seg2 - 1))
|
||||
| (CAN_NBTP_NTSEG1(dev->candev.bittiming.phase_seg1 + dev->candev.bittiming.prop_seg - 1))
|
||||
| (CAN_NBTP_NBRP(dev->candev.bittiming.brp - 1))
|
||||
| (CAN_NBTP_NSJW(dev->candev.bittiming.sjw - 1)));
|
||||
}
|
||||
|
||||
static void _set_tx_fifo_data_size(can_t *dev, uint8_t size) {
|
||||
assert(size < 0x8);
|
||||
dev->conf->can->TXESC.reg |= CAN_TXESC_TBDS(size);
|
||||
}
|
||||
|
||||
static void _set_rx_buffer_data_size(can_t *dev, uint8_t size) {
|
||||
assert(size < 0x8);
|
||||
dev->conf->can->RXESC.reg |= CAN_RXESC_RBDS(size);
|
||||
}
|
||||
|
||||
static void _set_rx_fifo_0_data_size(can_t *dev, uint8_t size) {
|
||||
assert(size < 0x8);
|
||||
dev->conf->can->RXESC.reg |= CAN_RXESC_F0DS(size);
|
||||
}
|
||||
|
||||
static void _set_rx_fifo_1_data_size(can_t *dev, uint8_t size) {
|
||||
assert(size < 0x8);
|
||||
dev->conf->can->RXESC.reg |= CAN_RXESC_F1DS(size);
|
||||
}
|
||||
|
||||
static void _set_can_pins(can_t *dev)
|
||||
{
|
||||
assert(dev->conf->tx_pin != GPIO_UNDEF);
|
||||
assert(dev->conf->rx_pin != GPIO_UNDEF);
|
||||
|
||||
gpio_init(dev->conf->tx_pin, GPIO_OUT);
|
||||
gpio_init(dev->conf->rx_pin, GPIO_IN);
|
||||
|
||||
if (dev->conf->can == CAN0) {
|
||||
gpio_init_mux(dev->conf->tx_pin, GPIO_MUX_I);
|
||||
gpio_init_mux(dev->conf->rx_pin, GPIO_MUX_I);
|
||||
}
|
||||
else if (dev->conf->can == CAN1) {
|
||||
gpio_init_mux(dev->conf->tx_pin, GPIO_MUX_H);
|
||||
gpio_init_mux(dev->conf->rx_pin, GPIO_MUX_H);
|
||||
}
|
||||
else {
|
||||
DEBUG_PUTS("Unsupported can channel");
|
||||
}
|
||||
}
|
||||
|
||||
void candev_samd5x_enter_sleep_mode(candev_t *candev)
|
||||
{
|
||||
can_t *dev = container_of(candev, can_t, candev);
|
||||
|
||||
dev->conf->can->CCCR.reg |= CAN_CCCR_CSR;
|
||||
while (!(dev->conf->can->CCCR.reg & CAN_CCCR_CSA)) {}
|
||||
DEBUG_PUTS("Device in sleep mode");
|
||||
}
|
||||
|
||||
void candev_samd5x_exit_sleep_mode(candev_t *candev)
|
||||
{
|
||||
can_t *dev = container_of(candev, can_t, candev);
|
||||
|
||||
dev->conf->can->CCCR.reg &= ~CAN_CCCR_CSR;
|
||||
while (dev->conf->can->CCCR.reg & CAN_CCCR_CSA) {}
|
||||
DEBUG_PUTS("Device out of sleep mode");
|
||||
}
|
||||
|
||||
void candev_samd5x_tdc_control(can_t *dev)
|
||||
{
|
||||
if (dev->tdc_ctrl) {
|
||||
DEBUG_PUTS("Enable Transceiver Delay Compensation");
|
||||
dev->conf->can->DBTP.reg |= CAN_DBTP_TDC;
|
||||
}
|
||||
else {
|
||||
DEBUG_PUTS("Disable Transceiver Delay Compensation");
|
||||
dev->conf->can->DBTP.reg &= ~(CAN_DBTP_TDC);
|
||||
}
|
||||
}
|
||||
|
||||
void can_init(can_t *dev, const can_conf_t *conf)
|
||||
{
|
||||
dev->candev.driver = &candev_samd5x_driver;
|
||||
|
||||
struct can_bittiming timing = { .bitrate = CANDEV_SAMD5X_DEFAULT_BITRATE,
|
||||
.sample_point = CANDEV_SAMD5X_DEFAULT_SPT };
|
||||
|
||||
uint32_t clk_freq = sam0_gclk_freq(conf->gclk_src);
|
||||
can_device_calc_bittiming(clk_freq, &bittiming_const, &timing);
|
||||
|
||||
memcpy(&dev->candev.bittiming, &timing, sizeof(timing));
|
||||
dev->conf = conf;
|
||||
}
|
||||
|
||||
static void _dump_msg_ram_section(can_t *dev)
|
||||
{
|
||||
puts("start address|\tsize of section");
|
||||
printf("Standard filters|\t0x%02lx|\t%lu\n", (uint32_t)(dev->msg_ram_conf.std_filter),
|
||||
(uint32_t)(ARRAY_SIZE(dev->msg_ram_conf.std_filter)));
|
||||
printf("Extended filters|\t0x%02lx|\t%lu\n", (uint32_t)(dev->msg_ram_conf.ext_filter),
|
||||
(uint32_t)(ARRAY_SIZE(dev->msg_ram_conf.ext_filter)));
|
||||
printf("Rx FIFO 0|\t0x%02lx|\t%lu\n", (uint32_t)(dev->msg_ram_conf.rx_fifo_0),
|
||||
(uint32_t)(ARRAY_SIZE(dev->msg_ram_conf.rx_fifo_0)));
|
||||
printf("Rx FIFO 1|\t0x%02lx|\t%lu\n", (uint32_t)(dev->msg_ram_conf.rx_fifo_1),
|
||||
(uint32_t)(ARRAY_SIZE(dev->msg_ram_conf.rx_fifo_1)));
|
||||
printf("Rx buffer|\t0x%02lx|\t%lu\n", (uint32_t)(dev->msg_ram_conf.rx_buffer),
|
||||
(uint32_t)(ARRAY_SIZE(dev->msg_ram_conf.rx_buffer)));
|
||||
printf("Tx event FIFO|\t0x%02lx|\t%lu\n", (uint32_t)(dev->msg_ram_conf.tx_event_fifo),
|
||||
(uint32_t)(ARRAY_SIZE(dev->msg_ram_conf.tx_event_fifo)));
|
||||
printf("Tx buffer|\t0x%02lx|\t%lu\n", (uint32_t)(dev->msg_ram_conf.tx_fifo_queue),
|
||||
(uint32_t)(ARRAY_SIZE(dev->msg_ram_conf.tx_fifo_queue)));
|
||||
}
|
||||
|
||||
static int _init(candev_t *candev)
|
||||
{
|
||||
can_t *dev = container_of(candev, can_t, candev);
|
||||
int res = 0;
|
||||
|
||||
sam0_gclk_enable(dev->conf->gclk_src);
|
||||
|
||||
_setup_clock(dev);
|
||||
_power_on(dev);
|
||||
|
||||
_set_can_pins(dev);
|
||||
|
||||
res = _set_mode(dev->conf->can, MODE_INIT);
|
||||
if (res != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_set_bit_timing(dev);
|
||||
|
||||
candev_samd5x_tdc_control(dev);
|
||||
|
||||
/*Configure the start addresses of the RAM message sections */
|
||||
dev->conf->can->SIDFC.reg = CAN_SIDFC_FLSSA((uint32_t)(dev->msg_ram_conf.std_filter))
|
||||
| CAN_SIDFC_LSS((uint32_t)(ARRAY_SIZE(dev->msg_ram_conf.std_filter)));
|
||||
dev->conf->can->XIDFC.reg = CAN_XIDFC_FLESA((uint32_t)(dev->msg_ram_conf.ext_filter))
|
||||
| CAN_XIDFC_LSE((uint32_t)(ARRAY_SIZE(dev->msg_ram_conf.ext_filter)));
|
||||
dev->conf->can->RXF0C.reg = CAN_RXF0C_F0SA((uint32_t)(dev->msg_ram_conf.rx_fifo_0))
|
||||
| CAN_RXF0C_F0S((uint32_t)(ARRAY_SIZE(dev->msg_ram_conf.rx_fifo_0)));
|
||||
dev->conf->can->RXF1C.reg = CAN_RXF1C_F1SA((uint32_t)(dev->msg_ram_conf.rx_fifo_1))
|
||||
| CAN_RXF1C_F1S((uint32_t)(ARRAY_SIZE(dev->msg_ram_conf.rx_fifo_1)));
|
||||
dev->conf->can->RXBC.reg = CAN_RXBC_RBSA((uint32_t)(dev->msg_ram_conf.rx_buffer));
|
||||
dev->conf->can->TXEFC.reg = CAN_TXEFC_EFSA((uint32_t)(dev->msg_ram_conf.tx_event_fifo))
|
||||
| CAN_TXEFC_EFS((uint32_t)(ARRAY_SIZE(dev->msg_ram_conf.tx_event_fifo)));
|
||||
dev->conf->can->TXBC.reg = CAN_TXBC_TBSA((uint32_t)(dev->msg_ram_conf.tx_fifo_queue))
|
||||
| CAN_TXBC_TFQS((uint32_t)(ARRAY_SIZE(dev->msg_ram_conf.tx_fifo_queue)));
|
||||
|
||||
/* In the vendor file, the data field size in CanMramTxbe is set to 64 bytes
|
||||
although it can be configurable. That's why 64 bytes is used here by default */
|
||||
_set_tx_fifo_data_size(dev, CAN_RXESC_F1DS_DATA64_Val);
|
||||
/* In the vendor file, the data field size in CanMramRxbe is set to 64 bytes
|
||||
although it can be configurable. That's why 64 bytes is used here by default */
|
||||
_set_rx_buffer_data_size(dev, CAN_RXESC_RBDS_DATA64_Val);
|
||||
/* In the vendor file, the data field size in CanMramRxf0e is set to 64 bytes
|
||||
although it can be configurable. That's why 64 bytes is used here by default */
|
||||
_set_rx_fifo_0_data_size(dev, CAN_RXESC_F0DS_DATA64_Val);
|
||||
/* In the vendor file, the data field size in CanMramRxf1e is set to 64 bytes
|
||||
although it can be configurable. That's why 64 bytes is used here by default */
|
||||
_set_rx_fifo_1_data_size(dev, CAN_RXESC_F1DS_DATA64_Val);
|
||||
|
||||
if (IS_ACTIVE(ENABLE_DEBUG)) {
|
||||
_dump_msg_ram_section(dev);
|
||||
}
|
||||
/* Disable automatic retransmission by default */
|
||||
/* This can be added as a configuration parameter for the CAN controller */
|
||||
dev->conf->can->CCCR.reg |= CAN_CCCR_DAR;
|
||||
|
||||
/* Reject all remote frames */
|
||||
dev->conf->can->GFC.reg |= CAN_GFC_RRFE | CAN_GFC_RRFS;
|
||||
|
||||
/* Enable reception interrupts: reception on FIFO0 and FIFO1 */
|
||||
dev->conf->can->IE.reg |= CAN_IE_RF0NE | CAN_IE_RF1NE;
|
||||
/* Enable transmission events interrupts */
|
||||
dev->conf->can->IE.reg |= CAN_IE_TEFNE;
|
||||
/* Enable the interrupt lines */
|
||||
dev->conf->can->ILE.reg = CAN_ILE_EINT0 | CAN_ILE_EINT1;
|
||||
|
||||
/* Enable the peripheral's interrupt */
|
||||
if (dev->conf->can == CAN0) {
|
||||
NVIC_EnableIRQ(CAN0_IRQn);
|
||||
_can_0 = dev;
|
||||
}
|
||||
else {
|
||||
NVIC_EnableIRQ(CAN1_IRQn);
|
||||
_can_1 = dev;
|
||||
}
|
||||
|
||||
/* Exit initialization mode */
|
||||
_exit_init_mode(dev->conf->can);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static uint8_t _form_message_marker(can_mm_t *can_mm)
|
||||
{
|
||||
return can_mm->put | (can_mm->get << 4);
|
||||
}
|
||||
|
||||
static int _send(candev_t *candev, const struct can_frame *frame)
|
||||
{
|
||||
can_t *dev = container_of(candev, can_t, candev);
|
||||
|
||||
if (frame->can_dlc > CAN_MAX_DLEN) {
|
||||
DEBUG_PUTS("CAN frame payload not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if the Tx FIFO is full */
|
||||
if (dev->conf->can->TXFQS.reg & CAN_TXFQS_TFQF) {
|
||||
DEBUG_PUTS("Tx FIFO is full");
|
||||
return -1;
|
||||
}
|
||||
|
||||
can_mm_t can_mm = {0};
|
||||
uint8_t fifo_queue_put_idx = (dev->conf->can->TXFQS.reg >> CAN_TXFQS_TFQPI_Pos) & 0x1F;
|
||||
DEBUG("Tx FIFO put index = %u\n", fifo_queue_put_idx);
|
||||
uint8_t fifo_queue_get_idx = (dev->conf->can->TXFQS.reg >> CAN_TXFQS_TFGI_Pos) & 0x1F;
|
||||
DEBUG("Tx FIFO get index = %u\n", fifo_queue_get_idx);
|
||||
can_mm.put = fifo_queue_put_idx;
|
||||
can_mm.get = fifo_queue_get_idx;
|
||||
|
||||
if (frame->can_id & CAN_EFF_FLAG) {
|
||||
DEBUG_PUTS("Extended ID");
|
||||
dev->msg_ram_conf.tx_fifo_queue[can_mm.put].TXBE_0.bit.ID = frame->can_id & CAN_EFF_MASK;
|
||||
dev->msg_ram_conf.tx_fifo_queue[can_mm.put].TXBE_0.bit.XTD = 1;
|
||||
}
|
||||
else {
|
||||
DEBUG_PUTS("Standard identifier");
|
||||
dev->msg_ram_conf.tx_fifo_queue[can_mm.put].TXBE_0.bit.ID = (frame->can_id & CAN_SFF_MASK) << 18;
|
||||
dev->msg_ram_conf.tx_fifo_queue[can_mm.put].TXBE_0.bit.XTD = 0;
|
||||
}
|
||||
dev->msg_ram_conf.tx_fifo_queue[can_mm.put].TXBE_0.bit.RTR = (frame->can_id & CAN_RTR_FLAG) >> 30;
|
||||
dev->msg_ram_conf.tx_fifo_queue[can_mm.put].TXBE_0.bit.ESI = 1;
|
||||
dev->msg_ram_conf.tx_fifo_queue[can_mm.put].TXBE_1.bit.DLC = frame->can_dlc;
|
||||
dev->msg_ram_conf.tx_fifo_queue[can_mm.put].TXBE_1.bit.EFC = 1;
|
||||
dev->msg_ram_conf.tx_fifo_queue[can_mm.put].TXBE_1.bit.MM = _form_message_marker(&can_mm);
|
||||
memcpy((void *)dev->msg_ram_conf.tx_fifo_queue[can_mm.put].TXBE_DATA, frame->data, frame->can_dlc);
|
||||
|
||||
/* Request transmission */
|
||||
dev->conf->can->TXBAR.reg |= (1 << can_mm.put);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int16_t _find_filter(can_t *can, const struct can_filter *filter, bool is_std_filter)
|
||||
{
|
||||
int16_t idx = -1;
|
||||
|
||||
/* Standard filter */
|
||||
if (is_std_filter) {
|
||||
/* Search for the standard filter in the CAN controller message RAM */
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(can->msg_ram_conf.std_filter); i++) {
|
||||
if (((filter->can_id & CAN_SFF_MASK) == can->msg_ram_conf.std_filter[i].SIDFE_0.bit.SFID1)) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Extended filter */
|
||||
else {
|
||||
/* Search for the extended filter in the CAN controller message RAM */
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(can->msg_ram_conf.ext_filter); i++) {
|
||||
if (((filter->can_id & CAN_EFF_MASK) == can->msg_ram_conf.ext_filter[i].XIDFE_0.bit.EFID1)) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static int _set_filter(candev_t *candev, const struct can_filter *filter)
|
||||
{
|
||||
can_t *dev = container_of(candev, can_t, candev);
|
||||
|
||||
int16_t idx = 0;
|
||||
uint8_t filter_conf = 0;
|
||||
switch (filter->target_mailbox) {
|
||||
case 0:
|
||||
filter_conf = CANDEV_SAMD5X_FILTER_RX_FIFO_0;
|
||||
break;
|
||||
case 1 :
|
||||
filter_conf = CANDEV_SAMD5X_FILTER_RX_FIFO_1;
|
||||
break;
|
||||
default:
|
||||
puts("Invalid target mailbox --> Do not apply filter");
|
||||
return -1;
|
||||
}
|
||||
if (filter->can_id & CAN_EFF_FLAG) {
|
||||
DEBUG_PUTS("Extended filter to add in the extended filter section of the message RAM");
|
||||
/* Check if the filter already exists */
|
||||
idx = _find_filter(dev, filter, false);
|
||||
if (idx != -1) {
|
||||
DEBUG_PUTS("Extended filter already exists --> Update it");
|
||||
}
|
||||
else {
|
||||
/* Find a free slot where to save the filter */
|
||||
for (idx = 0; (uint16_t)idx < ARRAY_SIZE(dev->msg_ram_conf.ext_filter); idx++) {
|
||||
if (dev->msg_ram_conf.ext_filter[idx].XIDFE_0.bit.EFEC == CANDEV_SAMD5X_FILTER_DISABLE) {
|
||||
DEBUG_PUTS("empty slot");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (idx == ARRAY_SIZE(dev->msg_ram_conf.ext_filter)) {
|
||||
DEBUG_PUTS("Reached maximum capacity of extended filters --> Could not add filter");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG("Extended Filter to add at idx = %d\n", idx);
|
||||
dev->msg_ram_conf.ext_filter[idx].XIDFE_0.bit.EFEC = filter_conf;
|
||||
/* For now, only CLASSIC filters are supported */
|
||||
dev->msg_ram_conf.ext_filter[idx].XIDFE_1.bit.EFT = CANDEV_SAMD5X_CLASSIC_FILTER;
|
||||
dev->msg_ram_conf.ext_filter[idx].XIDFE_0.bit.EFID1 = filter->can_id;
|
||||
dev->msg_ram_conf.ext_filter[idx].XIDFE_1.bit.EFID2 = filter->can_mask & CAN_EFF_MASK;
|
||||
DEBUG("Extended message ID filter element N°%d = 0x%02lx\n", idx,
|
||||
(uint32_t)(dev->msg_ram_conf.std_filter[idx].SIDFE_0.reg));
|
||||
_set_mode(dev->conf->can, MODE_INIT);
|
||||
/* Reject all extended frames that are not matching the filters applied */
|
||||
dev->conf->can->GFC.reg |= CAN_GFC_ANFE((uint32_t)CAN_REJECT);
|
||||
_exit_init_mode(dev->conf->can);
|
||||
}
|
||||
else {
|
||||
DEBUG_PUTS("Standard filter to add in the standard filter section of the message RAM");
|
||||
/* Check if the filter already exists */
|
||||
idx = _find_filter(dev, filter, true);
|
||||
if (idx != -1) {
|
||||
DEBUG_PUTS("Standard filter already exists --> Update it");
|
||||
}
|
||||
else {
|
||||
/* Find a free slot where to save the filter */
|
||||
for (idx = 0; (uint16_t)idx < ARRAY_SIZE(dev->msg_ram_conf.std_filter); idx++) {
|
||||
if (dev->msg_ram_conf.std_filter[idx].SIDFE_0.bit.SFEC == CANDEV_SAMD5X_FILTER_DISABLE) {
|
||||
DEBUG_PUTS("empty slot");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (idx == ARRAY_SIZE(dev->msg_ram_conf.std_filter)) {
|
||||
DEBUG_PUTS("Reached maximum capacity of standard filters --> Could not add filter");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG("Standard Filter to add at idx = %d\n", idx);
|
||||
dev->msg_ram_conf.std_filter[idx].SIDFE_0.bit.SFEC = filter_conf;
|
||||
/* For now, only CLASSIC filters are supported */
|
||||
dev->msg_ram_conf.std_filter[idx].SIDFE_0.bit.SFT = CANDEV_SAMD5X_CLASSIC_FILTER;
|
||||
dev->msg_ram_conf.std_filter[idx].SIDFE_0.bit.SFID1 = filter->can_id & CAN_SFF_MASK;
|
||||
dev->msg_ram_conf.std_filter[idx].SIDFE_0.bit.SFID2 = filter->can_mask & CAN_SFF_MASK;
|
||||
DEBUG("Standard message ID filter element N°%d = 0x%02lx\n", idx,
|
||||
(uint32_t)(dev->msg_ram_conf.std_filter[idx].SIDFE_0.reg));
|
||||
_set_mode(dev->conf->can, MODE_INIT);
|
||||
/* Reject all standard frames that are not matching the filters applied */
|
||||
dev->conf->can->GFC.reg |= CAN_GFC_ANFS((uint32_t)CAN_REJECT);
|
||||
_exit_init_mode(dev->conf->can);
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static int _remove_filter(candev_t *candev, const struct can_filter *filter)
|
||||
{
|
||||
can_t *dev = container_of(candev, can_t, candev);
|
||||
|
||||
int16_t idx = 0;
|
||||
if (filter->can_id & CAN_EFF_FLAG) {
|
||||
idx = _find_filter(dev, filter, false);
|
||||
if (idx != -1) {
|
||||
DEBUG("Extended filter to disable at idx = %d\n", idx);
|
||||
dev->msg_ram_conf.ext_filter[idx].XIDFE_0.bit.EFEC = CANDEV_SAMD5X_FILTER_DISABLE;
|
||||
}
|
||||
else {
|
||||
DEBUG_PUTS("Filter not found");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
idx = _find_filter(dev, filter, true);
|
||||
if (idx != -1) {
|
||||
DEBUG("Standard filter to disable at idx = %d\n", idx);
|
||||
dev->msg_ram_conf.std_filter[idx].SIDFE_0.bit.SFEC = CANDEV_SAMD5X_FILTER_DISABLE;
|
||||
}
|
||||
else {
|
||||
DEBUG_PUTS("Filter not found");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static int _set(candev_t *candev, canopt_t opt, void *value, size_t value_len)
|
||||
{
|
||||
can_t *dev = container_of(candev, can_t, candev);
|
||||
int res = 0;
|
||||
|
||||
switch (opt) {
|
||||
case CANOPT_BITTIMING:
|
||||
if (value_len < sizeof(struct can_bittiming)) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
memcpy(&candev->bittiming, value, sizeof(struct can_bittiming));
|
||||
uint32_t clk_freq = sam0_gclk_freq(dev->conf->gclk_src);
|
||||
can_device_calc_bittiming(clk_freq, &bittiming_const, &candev->bittiming);
|
||||
res = _init(candev);
|
||||
if (res == 0) {
|
||||
res = sizeof(candev->bittiming);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CANOPT_RX_FILTERS:
|
||||
if (value_len < sizeof(struct can_filter)) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
res = _set_filter(candev, value);
|
||||
if (res >= 0) {
|
||||
res = sizeof(struct can_filter);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CANOPT_STATE:
|
||||
if (value_len < sizeof(canopt_state_t)) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
switch (*((canopt_state_t *)value)) {
|
||||
case CANOPT_STATE_OFF:
|
||||
res = _power_off(dev);
|
||||
if (res == 0) {
|
||||
res = sizeof(canopt_state_t);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CANOPT_STATE_ON:
|
||||
res = _power_on(dev);
|
||||
if (res == 0) {
|
||||
res = sizeof(canopt_state_t);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CANOPT_STATE_LOOPBACK:
|
||||
res = _set_mode(dev->conf->can, MODE_TEST);
|
||||
if (res == 0) {
|
||||
res = sizeof(canopt_state_t);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _isr(candev_t *candev)
|
||||
{
|
||||
can_t *dev = container_of(candev, can_t, candev);
|
||||
|
||||
uint32_t irq_reg = dev->conf->can->IR.reg;
|
||||
DEBUG("isr: IR reg = 0x%02lx\n", irq_reg);
|
||||
|
||||
/* Interrupt triggered due to reception of CAN frame on Rx_FIFO_0 */
|
||||
if (irq_reg & CAN_IR_RF0N) {
|
||||
DEBUG_PUTS("New message in Rx FIFO 0");
|
||||
/* Clear the interrupt source flag */
|
||||
dev->conf->can->IR.reg |= CAN_IR_RF0N;
|
||||
|
||||
uint16_t rx_get_idx = 0;
|
||||
uint16_t rx_put_idx = 0;
|
||||
rx_get_idx = (dev->conf->can->RXF0S.reg >> CAN_RXF0S_F0GI_Pos) & 0x3F;
|
||||
DEBUG("rx get index = %u\n", rx_get_idx);
|
||||
rx_put_idx = (dev->conf->can->RXF0S.reg >> CAN_RXF0S_F0PI_Pos) & 0x3F;
|
||||
DEBUG("rx put index = %u\n", rx_put_idx);
|
||||
|
||||
struct can_frame frame_received = {0};
|
||||
if (!dev->msg_ram_conf.rx_fifo_0[rx_get_idx].RXF0E_0.bit.XTD) {
|
||||
DEBUG_PUTS("Received standard CAN frame");
|
||||
frame_received.can_id = dev->msg_ram_conf.rx_fifo_0[rx_get_idx].RXF0E_0.bit.ID >> 18;
|
||||
}
|
||||
else {
|
||||
DEBUG_PUTS("Received extended CAN frame");
|
||||
frame_received.can_id = dev->msg_ram_conf.rx_fifo_0[rx_get_idx].RXF0E_0.bit.ID;
|
||||
}
|
||||
frame_received.can_dlc = dev->msg_ram_conf.rx_fifo_0[rx_get_idx].RXF0E_1.bit.DLC;
|
||||
memcpy(frame_received.data, (uint32_t *)dev->msg_ram_conf.rx_fifo_0[rx_get_idx].RXF0E_DATA, frame_received.can_dlc);
|
||||
|
||||
dev->conf->can->RXF0A.reg = CAN_RXF0A_F0AI(rx_get_idx);
|
||||
if (dev->candev.event_callback) {
|
||||
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_RX_INDICATION, &frame_received);
|
||||
}
|
||||
}
|
||||
|
||||
/* Interrupt triggered due to reception of CAN frame on Rx_FIFO_1 */
|
||||
if (irq_reg & CAN_IR_RF1N) {
|
||||
DEBUG_PUTS("New message in Rx FIFO 1");
|
||||
/* Clear the interrupt source flag */
|
||||
dev->conf->can->IR.reg |= CAN_IR_RF1N;
|
||||
|
||||
uint16_t rx_get_idx = 0;
|
||||
uint16_t rx_put_idx = 0;
|
||||
rx_get_idx = (dev->conf->can->RXF1S.reg >> CAN_RXF1S_F1GI_Pos) & 0x3F;
|
||||
DEBUG("rx get index = %u\n", rx_get_idx);
|
||||
rx_put_idx = (dev->conf->can->RXF1S.reg >> CAN_RXF1S_F1PI_Pos) & 0x3F;
|
||||
DEBUG("rx put index = %u\n", rx_put_idx);
|
||||
|
||||
struct can_frame frame_received = {0};
|
||||
if (!dev->msg_ram_conf.rx_fifo_1[rx_get_idx].RXF1E_0.bit.XTD) {
|
||||
DEBUG_PUTS("Received standard CAN frame");
|
||||
frame_received.can_id = dev->msg_ram_conf.rx_fifo_1[rx_get_idx].RXF1E_0.bit.ID >> 18;
|
||||
}
|
||||
else {
|
||||
DEBUG_PUTS("Received extended CAN frame");
|
||||
frame_received.can_id = dev->msg_ram_conf.rx_fifo_1[rx_get_idx].RXF1E_0.bit.ID;
|
||||
}
|
||||
frame_received.can_dlc = dev->msg_ram_conf.rx_fifo_1[rx_get_idx].RXF1E_1.bit.DLC;
|
||||
memcpy(frame_received.data, (uint32_t *)dev->msg_ram_conf.rx_fifo_1[rx_get_idx].RXF1E_DATA, frame_received.can_dlc);
|
||||
|
||||
dev->conf->can->RXF1A.reg = CAN_RXF1A_F1AI(rx_get_idx);
|
||||
if (dev->candev.event_callback) {
|
||||
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_RX_INDICATION, &frame_received);
|
||||
}
|
||||
}
|
||||
|
||||
/* Interrupt triggered due to new transmission event */
|
||||
if (irq_reg & CAN_IR_TEFN) {
|
||||
DEBUG_PUTS("New Tx event FIFO entry");
|
||||
dev->conf->can->IR.reg |= CAN_IR_TEFN;
|
||||
if (dev->candev.event_callback) {
|
||||
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_TX_CONFIRMATION, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable the peripheral's interrupt */
|
||||
if (dev->conf->can == CAN0) {
|
||||
NVIC_EnableIRQ(CAN0_IRQn);
|
||||
}
|
||||
else {
|
||||
NVIC_EnableIRQ(CAN1_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ISR_CAN0
|
||||
void ISR_CAN0(void)
|
||||
{
|
||||
DEBUG_PUTS("ISR CAN0");
|
||||
|
||||
/* Disable the peripheral's interrupt to avoid potential 'interrupt bouncing' */
|
||||
NVIC_DisableIRQ(CAN0_IRQn);
|
||||
if (_can_0->candev.event_callback) {
|
||||
_can_0->candev.event_callback(&(_can_0->candev), CANDEV_EVENT_ISR, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ISR_CAN1
|
||||
void ISR_CAN1(void)
|
||||
{
|
||||
DEBUG_PUTS("ISR CAN1");
|
||||
|
||||
/* Disable the peripheral's interrupt to avoid potential 'interrupt bouncing' */
|
||||
NVIC_DisableIRQ(CAN1_IRQn);
|
||||
if (_can_1->candev.event_callback) {
|
||||
_can_1->candev.event_callback(&(_can_1->candev), CANDEV_EVENT_ISR, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user