From 2976ac351db2bcb88a23984f47b3022e79836cab Mon Sep 17 00:00:00 2001 From: Alexander Wachter Date: Thu, 3 May 2018 10:59:12 +0200 Subject: [PATCH] drivers: can: Add CAN driver support for STM32 This commit adds low level driver support for STM32 micro controllers. It is tested on stm32f072b in loopback and normal mode. Signed-off-by: Alexander Wachter --- drivers/can/CMakeLists.txt | 1 + drivers/can/Kconfig | 1 + drivers/can/Kconfig.stm32 | 23 ++ drivers/can/stm32_can.c | 805 +++++++++++++++++++++++++++++++++++++ drivers/can/stm32_can.h | 75 ++++ 5 files changed, 905 insertions(+) create mode 100644 drivers/can/Kconfig.stm32 create mode 100644 drivers/can/stm32_can.c create mode 100644 drivers/can/stm32_can.h diff --git a/drivers/can/CMakeLists.txt b/drivers/can/CMakeLists.txt index 0e4e7604124..7b683babc3d 100644 --- a/drivers/can/CMakeLists.txt +++ b/drivers/can/CMakeLists.txt @@ -1 +1,2 @@ +zephyr_sources_ifdef(CONFIG_CAN_STM32 stm32_can.c) zephyr_sources_ifdef(CONFIG_USERSPACE can_handlers.c) diff --git a/drivers/can/Kconfig b/drivers/can/Kconfig index ef6c9ae3c19..d987016f6e1 100644 --- a/drivers/can/Kconfig +++ b/drivers/can/Kconfig @@ -67,5 +67,6 @@ config CAN_1 help Enable CAN controller 1 +source "drivers/can/Kconfig.stm32" endif # CAN diff --git a/drivers/can/Kconfig.stm32 b/drivers/can/Kconfig.stm32 new file mode 100644 index 00000000000..cceadee0df5 --- /dev/null +++ b/drivers/can/Kconfig.stm32 @@ -0,0 +1,23 @@ +# Kconfig.stm32 - STM32 CAN configuration options + +# +# Copyright (c) 2018 Alexander Wachter +# +# SPDX-License-Identifier: Apache-2.0 +# + +config CAN_STM32 + bool "STM32 CAN Driver" + default n + select USE_STM32_HAL_CAN + help + Enable STM32 CAN Driver (tested on stm32F0 series) + +config CAN_MAX_FILTER + int "Maximum number of concurrent active filters" + depends on CAN_STM32 + default 5 + range 1 56 + help + Defines the array size of the callback/msgq pointers. + Must be at least the size of concurrent reads. diff --git a/drivers/can/stm32_can.c b/drivers/can/stm32_can.c new file mode 100644 index 00000000000..6c51f183fd4 --- /dev/null +++ b/drivers/can/stm32_can.c @@ -0,0 +1,805 @@ +/* + * Copyright (c) 2018 Alexander Wachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "stm32_can.h" + +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_CAN_LEVEL +#include + +static void can_stm32_signal_tx_complete(struct can_mailbox *mb) +{ + if (mb->tx_callback) { + mb->tx_callback(mb->error_flags); + } else { + k_sem_give(&mb->tx_int_sem); + } +} + +static inline void can_stm32_get_msg_fifo(CAN_FIFOMailBox_TypeDef *mbox, + struct can_msg *msg) +{ + if (mbox->RIR & CAN_RI0R_IDE) { + msg->ext_id = mbox->RIR >> CAN_RI0R_EXID_Pos; + msg->id_type = CAN_EXTENDED_IDENTIFIER; + } else { + msg->std_id = mbox->RIR >> CAN_RI0R_STID_Pos; + msg->id_type = CAN_STANDARD_IDENTIFIER; + } + + msg->rtr = mbox->RIR & CAN_RI0R_RTR ? CAN_REMOTEREQUEST : CAN_DATAFRAME; + msg->dlc = mbox->RDTR & (CAN_RDT0R_DLC >> CAN_RDT0R_DLC_Pos); + msg->data_32[0] = mbox->RDLR; + msg->data_32[1] = mbox->RDHR; +} + +static void can_stm32_isr(void *arg) +{ + struct device *dev; + struct can_stm32_data *data; + const struct can_stm32_config *cfg; + CAN_TypeDef *can; + u32_t bus_off; + + dev = (struct device *)arg; + data = DEV_DATA(dev); + cfg = DEV_CFG(dev); + can = cfg->can; + + bus_off = can->ESR & CAN_ESR_BOFF; + + if ((can->TSR & CAN_TSR_RQCP0) | bus_off) { + data->mb0.error_flags = + can->TSR & CAN_TSR_TXOK0 ? CAN_TX_OK : + can->TSR & CAN_TSR_TERR0 ? CAN_TX_ERR : + can->TSR & CAN_TSR_ALST0 ? CAN_TX_ARB_LOST : + bus_off ? CAN_TX_BUS_OFF : + CAN_TX_UNKNOWN; + /* clear the request. */ + can->TSR |= CAN_TSR_RQCP0; + can_stm32_signal_tx_complete(&data->mb0); + } + + if ((can->TSR & CAN_TSR_RQCP1) | bus_off) { + data->mb0.error_flags = + can->TSR & CAN_TSR_TXOK1 ? CAN_TX_OK : + can->TSR & CAN_TSR_TERR1 ? CAN_TX_ERR : + can->TSR & CAN_TSR_ALST1 ? CAN_TX_ARB_LOST : + bus_off ? CAN_TX_BUS_OFF : + CAN_TX_UNKNOWN; + /* clear the request. */ + can->TSR |= CAN_TSR_RQCP1; + can_stm32_signal_tx_complete(&data->mb1); + } + + if ((can->TSR & CAN_TSR_RQCP2) | bus_off) { + data->mb2.error_flags = + can->TSR & CAN_TSR_TXOK2 ? CAN_TX_OK : + can->TSR & CAN_TSR_TERR2 ? CAN_TX_ERR : + can->TSR & CAN_TSR_ALST2 ? CAN_TX_ARB_LOST : + bus_off ? CAN_TX_BUS_OFF : + CAN_TX_UNKNOWN; + /* clear the request. */ + can->TSR |= CAN_TSR_RQCP2; + can_stm32_signal_tx_complete(&data->mb2); + } + + if (can->TSR & CAN_TSR_TME_Msk) { + k_sem_give(&data->tx_int_sem); + } + + while (can->RF0R & CAN_RF0R_FMP0_Msk) { + CAN_FIFOMailBox_TypeDef *mbox; + int filter_match_index; + struct can_msg msg; + + mbox = &can->sFIFOMailBox[0]; + filter_match_index = ((mbox->RDTR & CAN_RDT0R_FMI_Msk) + >> CAN_RDT0R_FMI_Pos); + + if (filter_match_index >= CONFIG_CAN_MAX_FILTER) { + break; + } + + SYS_LOG_DBG("Message on filter index %d", filter_match_index); + can_stm32_get_msg_fifo(mbox, &msg); + + if (data->rx_response[filter_match_index]) { + if (data->response_type & (1ULL << filter_match_index)) { + struct k_msgq *msg_q = + data->rx_response[filter_match_index]; + + k_msgq_put(msg_q, &msg, K_NO_WAIT); + } else { + can_rx_callback_t callback = + data->rx_response[filter_match_index]; + callback(&msg); + } + } + + /* Release message */ + can->RF0R |= CAN_RF0R_RFOM0; + } +} + +void HAL_CAN_MspInit(CAN_HandleTypeDef *hcan) +{ + ARG_UNUSED(hcan); +} + +int can_stm32_runtime_configure(struct device *dev, enum can_mode mode, + u32_t bitrate) +{ + CAN_HandleTypeDef hcan; + const struct can_stm32_config *cfg = DEV_CFG(dev); + CAN_TypeDef *can = cfg->can; + struct device *clock; + u32_t clock_rate; + u32_t prescaler; + u32_t hal_mode; + int hal_ret; + u32_t bs1; + u32_t bs2; + u32_t swj; + + clock = device_get_binding(STM32_CLOCK_CONTROL_NAME); + __ASSERT_NO_MSG(clock); + hcan.Instance = can; + + clock_control_get_rate(clock, (clock_control_subsys_t *) &cfg->pclken, + &clock_rate); + if (!bitrate) { + bitrate = cfg->bus_speed; + } + + prescaler = clock_rate / (BIT_SEG_LENGTH * cfg->bus_speed); + if (prescaler == 0 || prescaler > 1024) { + SYS_LOG_ERR("HAL_CAN_Init failed: prescaler > max (%d > 1024)", + prescaler); + return -EINVAL; + } + + bs1 = (CONFIG_CAN_PHASE_SEG1_PROP_SEG - 1) << CAN_BTR_TS1_Pos; + bs2 = (CONFIG_CAN_PHASE_SEG2 - 1) << CAN_BTR_TS2_Pos; + swj = (CONFIG_CAN_SJW - 1) << CAN_BTR_SJW_Pos; + + hal_mode = mode == CAN_NORMAL_MODE ? CAN_MODE_NORMAL : + mode == CAN_LOOPBACK_MODE ? CAN_MODE_LOOPBACK : + mode == CAN_SILENT_MODE ? CAN_MODE_SILENT : + CAN_MODE_SILENT_LOOPBACK; + + hcan.Init.TTCM = DISABLE; + hcan.Init.ABOM = DISABLE; + hcan.Init.AWUM = DISABLE; + hcan.Init.NART = DISABLE; + hcan.Init.RFLM = DISABLE; + hcan.Init.TXFP = DISABLE; + hcan.Init.Mode = hal_mode; + hcan.Init.SJW = swj; + hcan.Init.BS1 = bs1; + hcan.Init.BS2 = bs2; + hcan.Init.Prescaler = prescaler; + + hal_ret = HAL_CAN_Init(&hcan); + if (hal_ret != HAL_OK) { + SYS_LOG_ERR("HAL_CAN_Init failed: %d", hal_ret); + return -EIO; + } + + SYS_LOG_DBG("Runtime configure of %s done", dev->config->name); + return 0; +} + +static int can_stm32_init(struct device *dev) +{ + const struct can_stm32_config *cfg = DEV_CFG(dev); + struct can_stm32_data *data = DEV_DATA(dev); + CAN_TypeDef *can = cfg->can; + struct device *clock; + int ret; + + k_mutex_init(&data->tx_mutex); + k_mutex_init(&data->set_filter_mutex); + k_sem_init(&data->tx_int_sem, 0, 1); + k_sem_init(&data->mb0.tx_int_sem, 0, 1); + k_sem_init(&data->mb1.tx_int_sem, 0, 1); + k_sem_init(&data->mb2.tx_int_sem, 0, 1); + data->mb0.tx_callback = NULL; + data->mb1.tx_callback = NULL; + data->mb2.tx_callback = NULL; + + data->filter_usage = (1ULL << CAN_MAX_NUMBER_OF_FILTES) - 1ULL; + memset(data->rx_response, 0, sizeof(void *) * CONFIG_CAN_MAX_FILTER); + data->response_type = 0; + + clock = device_get_binding(STM32_CLOCK_CONTROL_NAME); + __ASSERT_NO_MSG(clock); + + ret = clock_control_on(clock, (clock_control_subsys_t *) &cfg->pclken); + if (ret != 0) { + SYS_LOG_ERR("HAL_CAN_Init clock control on failed: %d", ret); + return -EIO; + } + + ret = can_stm32_runtime_configure(dev, CAN_NORMAL_MODE, 0); + if (ret) { + return ret; + } + + cfg->config_irq(can); + can->IER |= CAN_IT_TME; + SYS_LOG_INF("Init of %s done", dev->config->name); + return 0; +} + +int can_stm32_send(struct device *dev, struct can_msg *msg, s32_t timeout, + can_tx_callback_t callback) +{ + const struct can_stm32_config *cfg = DEV_CFG(dev); + struct can_stm32_data *data = DEV_DATA(dev); + CAN_TypeDef *can = cfg->can; + u32_t transmit_status_register = can->TSR; + CAN_TxMailBox_TypeDef *mailbox = NULL; + struct k_mutex *tx_mutex = &data->tx_mutex; + struct can_mailbox *mb = NULL; + + SYS_LOG_DBG("Sending %d bytes on %s. " + "Id: 0x%x, " + "ID type: %s, " + "Remote Frame: %s" + , msg->dlc, dev->config->name + , msg->id_type == CAN_STANDARD_IDENTIFIER ? + msg->std_id : msg->ext_id + , msg->id_type == CAN_STANDARD_IDENTIFIER ? + "standard" : "extended" + , msg->rtr == CAN_DATAFRAME ? "no" : "yes"); + + __ASSERT(msg->dlc == 0 || msg->data != NULL, "Dataptr is null"); + __ASSERT(msg->dlc <= CAN_MAX_DLC, "DLC > 8"); + + if (can->ESR & CAN_ESR_BOFF) { + return CAN_TX_BUS_OFF; + } + + k_mutex_lock(tx_mutex, K_FOREVER); + while (!(transmit_status_register & CAN_TSR_TME_Msk)) { + k_mutex_unlock(tx_mutex); + SYS_LOG_DBG("Transmit buffer full. Wait with timeout (%dms)", + timeout); + if (k_sem_take(&data->tx_int_sem, timeout) == -EAGAIN) { + return CAN_TIMEOUT; + } + + k_mutex_lock(tx_mutex, K_FOREVER); + transmit_status_register = can->TSR; + } + + if (transmit_status_register & CAN_TSR_TME0) { + SYS_LOG_DBG("Using mailbox 0"); + mailbox = &can->sTxMailBox[CAN_TXMAILBOX_0]; + mb = &(data->mb0); + } else if (transmit_status_register & CAN_TSR_TME1) { + SYS_LOG_DBG("Using mailbox 1"); + mailbox = &can->sTxMailBox[CAN_TXMAILBOX_1]; + mb = &data->mb1; + } else if (transmit_status_register & CAN_TSR_TME2) { + SYS_LOG_DBG("Using mailbox 2"); + mailbox = &can->sTxMailBox[CAN_TXMAILBOX_2]; + mb = &data->mb2; + } + + mb->tx_callback = callback; + + /* mailbix identifier register setup */ + mailbox->TIR &= CAN_TI0R_TXRQ; + + if (msg->id_type == CAN_STANDARD_IDENTIFIER) { + mailbox->TIR |= (msg->std_id << CAN_TI0R_STID_Pos); + } else { + mailbox->TIR |= (msg->ext_id << CAN_TI0R_EXID_Pos) + | CAN_TI0R_IDE; + } + + if (msg->rtr == CAN_REMOTEREQUEST) { + mailbox->TIR |= CAN_TI1R_RTR; + } + + mailbox->TDTR = (mailbox->TDTR & ~CAN_TDT1R_DLC_Msk) | + ((msg->dlc & 0xF) << CAN_TDT1R_DLC_Pos); + + mailbox->TDLR = msg->data_32[0]; + mailbox->TDHR = msg->data_32[1]; + + mailbox->TIR |= CAN_TI0R_TXRQ; + k_mutex_unlock(tx_mutex); + + if (callback == NULL) { + k_sem_reset(&mb->tx_int_sem); + k_sem_take(&mb->tx_int_sem, K_FOREVER); + return mb->error_flags; + } + + return 0; +} + +static int can_stm32_shift_arr(void **arr, int start, int count) +{ + void **start_ptr = arr + start; + size_t cnt; + + if (start > CONFIG_CAN_MAX_FILTER) { + return CAN_NO_FREE_FILTER; + } + + if (count > 0) { + void *move_dest; + + if ((start + count) >= CONFIG_CAN_MAX_FILTER || + arr[CONFIG_CAN_MAX_FILTER - 1 - count] != NULL) { + return CAN_NO_FREE_FILTER; + } + + cnt = (CONFIG_CAN_MAX_FILTER - start - count) * sizeof(void *); + move_dest = start_ptr + count; + memmove(move_dest, start_ptr, cnt); + memset(start_ptr, 0, count * sizeof(void *)); + } else if (count < 0) { + count = -count; + + if (start - count < 0) { + return CAN_NO_FREE_FILTER; + } + + cnt = (CONFIG_CAN_MAX_FILTER - start) * sizeof(void *); + memmove(start_ptr - count, start_ptr, cnt); + memset(arr + CONFIG_CAN_MAX_FILTER - count, 0, + count * sizeof(void *)); + } + + return 0; +} + +static inline void can_stm32_shift_bits(u64_t *bits, int start, int count) +{ + u64_t mask_right = (UINT64_MAX >> start); + + if (count > 0) { + *bits = (*bits & ~mask_right) | ((*bits & mask_right) << count); + } else if (count < 0) { + u64_t mask_left; + + count = -count; + mask_left = ~(UINT64_MAX >> (start - count)); + *bits = (*bits & mask_left) | ((*bits & mask_right) >> count); + } +} + +static int can_calc_filter_index(int filter_nr, u32_t mode_reg, u32_t scale_reg) +{ + int filter_bank = filter_nr / 4; + int cnt = 0; + u32_t mode_masked; + u32_t scale_masked; + + /*count filters in the banks before */ + for (int i = 0; i < filter_bank; i++) { + mode_masked = mode_reg & (1U << i); + scale_masked = scale_reg & (1U << i); + cnt += !scale_masked && mode_masked ? 4 : + scale_masked && !mode_masked ? 1 : + 2; + } + + /* plus the filters in the same bank */ + mode_masked = mode_reg & (1U << filter_bank); + scale_masked = scale_reg & (1U << filter_bank); + cnt += (!scale_masked && mode_masked) ? filter_nr & 0x03 : + (filter_nr & 0x03) >> 1; + return cnt; +} + +enum can_filter_type can_stm32_get_filter_type(u32_t bank_bit, u32_t mode_reg, + u32_t scale_reg) +{ + u32_t mode_masked = mode_reg & bank_bit; + u32_t scale_masked = scale_reg & bank_bit; + enum can_filter_type type = + !scale_masked && mode_masked ? CAN_FILTER_STANDARD : + !scale_masked && !mode_masked ? CAN_FILTER_STANDARD_MASKED : + scale_masked && mode_masked ? CAN_FILTER_EXTENDED : + CAN_FILTER_EXTENDED_MASKED; + + return type; +} + +static void can_stm32_set_filter_bank(int filter_nr, + CAN_FilterRegister_TypeDef *filter_reg, + enum can_filter_type filter_type, + u32_t id, u32_t mask) +{ + switch (filter_type) { + case CAN_FILTER_STANDARD: + switch (filter_nr & 0x03) { + case 0: + filter_reg->FR1 = (filter_reg->FR1 & 0xFFFF0000) | id; + break; + case 1: + filter_reg->FR1 = (filter_reg->FR1 & 0x0000FFFF) + | (id << 16); + break; + case 2: + filter_reg->FR2 = (filter_reg->FR2 & 0xFFFF0000) | id; + break; + case 3: + filter_reg->FR2 = (filter_reg->FR2 & 0x0000FFFF) + | (id << 16); + break; + } + + break; + case CAN_FILTER_STANDARD_MASKED: + switch (filter_nr & 0x02) { + case 0: + filter_reg->FR1 = id | (mask << 16); + break; + case 2: + filter_reg->FR2 = id | (mask << 16); + break; + } + + break; + case CAN_FILTER_EXTENDED: + switch (filter_nr & 0x02) { + case 0: + filter_reg->FR1 = id; + break; + case 2: + filter_reg->FR2 = id; + break; + } + + break; + case CAN_FILTER_EXTENDED_MASKED: + filter_reg->FR1 = id; + filter_reg->FR2 = mask; + break; + } +} + +static inline +int can_stm32_calc_shift_width(enum can_filter_type new_filter_type, + enum can_filter_type old_filter_type) +{ + switch (new_filter_type) { + case CAN_FILTER_STANDARD: + return old_filter_type == CAN_FILTER_EXTENDED_MASKED ? 3 : 1; + case CAN_FILTER_STANDARD_MASKED: + return old_filter_type == CAN_FILTER_STANDARD ? -2 : + old_filter_type == CAN_FILTER_EXTENDED_MASKED ? 1 : + 0; + case CAN_FILTER_EXTENDED: + return old_filter_type == CAN_FILTER_STANDARD ? -2 : + old_filter_type == CAN_FILTER_EXTENDED_MASKED ? 1 : + 0; + case CAN_FILTER_EXTENDED_MASKED: + return old_filter_type == CAN_FILTER_STANDARD ? -3 : -1; + } + + return 0; +} + +static inline void can_stm32_set_mode_scale(enum can_filter_type filter_type, + u32_t *mode_reg, u32_t *scale_reg, + u32_t bank_bit) +{ + switch (filter_type) { + case CAN_FILTER_STANDARD: + *mode_reg |= bank_bit; + *scale_reg &= ~bank_bit; + break; + case CAN_FILTER_STANDARD_MASKED: + *mode_reg &= ~bank_bit; + *scale_reg &= ~bank_bit; + break; + case CAN_FILTER_EXTENDED: + *mode_reg |= bank_bit; + *scale_reg |= bank_bit; + break; + case CAN_FILTER_EXTENDED_MASKED: + *mode_reg &= ~bank_bit; + *scale_reg |= bank_bit; + break; + } +} + +static inline int can_stm32_set_filter(const struct can_filter *filter, + struct can_stm32_data *device_data, + CAN_TypeDef *can, + int *filter_index) +{ + u32_t mask = 0; + u32_t id = 0; + int filter_nr = 0; + int filter_index_tmp = CAN_NO_FREE_FILTER; + int bank_nr; + u32_t bank_bit; + int register_demand; + enum can_filter_type filter_type; + enum can_filter_type bank_mode; + + if (filter->id_type == CAN_STANDARD_IDENTIFIER) { + id = (filter->std_id << CAN_FIRX_STD_ID_POS) + | (filter->rtr << CAN_FIRX_STD_RTR_POS); + + if (filter->std_id_mask == CAN_STD_ID_MASK && filter->rtr_mask) { + filter_type = CAN_FILTER_STANDARD; + register_demand = 1; + } else { + filter_type = CAN_FILTER_STANDARD_MASKED; + register_demand = 2; + mask = (filter->std_id_mask << CAN_FIRX_STD_ID_POS) + | (filter->rtr_mask << CAN_FIRX_STD_RTR_POS) + | (1U << CAN_FIRX_STD_IDE_POS); + } + + } else { + id = (filter->ext_id << CAN_FIRX_EXT_EXT_ID_POS) + | (filter->rtr << CAN_FIRX_EXT_RTR_POS) + | (1U << CAN_FIRX_EXT_IDE_POS); + + if (filter->ext_id_mask == CAN_EXT_ID_MASK && filter->rtr_mask) { + filter_type = CAN_FILTER_EXTENDED; + register_demand = 2; + } else { + filter_type = CAN_FILTER_EXTENDED_MASKED; + register_demand = 4; + mask = (filter->ext_id_mask << CAN_FIRX_EXT_EXT_ID_POS) + | (filter->rtr_mask << CAN_FIRX_EXT_RTR_POS) + | (1U << CAN_FIRX_EXT_IDE_POS); + } + } + + SYS_LOG_DBG("Setting filter ID: 0x%x, mask: 0x%x", filter->ext_id, + filter->ext_id_mask); + SYS_LOG_DBG("Filter type: %s ID %s mask (%d)", + (filter_type == CAN_FILTER_STANDARD || + filter_type == CAN_FILTER_STANDARD_MASKED) ? + "standard" : "extended", + (filter_type == CAN_FILTER_STANDARD_MASKED || + filter_type == CAN_FILTER_EXTENDED_MASKED) ? + "with" : "without", + filter_type); + + do { + u64_t usage_shifted = (device_data->filter_usage >> filter_nr); + u8_t usage_demand_mask = (1U << register_demand) - 1; + bool bank_is_empty; + + bank_nr = filter_nr / 4; + bank_bit = (1U << bank_nr); + bank_mode = can_stm32_get_filter_type(bank_bit, can->FM1R, + can->FS1R); + bank_is_empty = CAN_BANK_IS_EMPTY(device_data->filter_usage, + bank_nr); + + if ((usage_shifted & usage_demand_mask) == usage_demand_mask) { + if (bank_mode == filter_type || bank_is_empty) { + device_data->filter_usage &= + ~((u64_t)usage_demand_mask << filter_nr); + break; + } else { + /* Filter Bank has unsuitable configuration */ + filter_nr = (bank_nr + 1) * 4; + } + } else { + filter_nr += register_demand; + } + + if (!usage_shifted) { + SYS_LOG_INF("No free filter bank found"); + return CAN_NO_FREE_FILTER; + } + } while (filter_nr < CAN_MAX_NUMBER_OF_FILTES); + + /* set the filter init mode */ + can->FMR |= CAN_FMR_FINIT; + can->FA1R &= ~bank_bit; + + /* TODO fifo balancing */ + if (filter_type != bank_mode) { + int shift_width; + int res; + u32_t mode_reg = can->FM1R; + u32_t scale_reg = can->FS1R; + + can_stm32_set_mode_scale(filter_type, &mode_reg, &scale_reg, + bank_bit); + + shift_width = can_stm32_calc_shift_width(filter_type, + bank_mode); + + filter_index_tmp = can_calc_filter_index(filter_nr, mode_reg, + scale_reg); + + res = can_stm32_shift_arr(device_data->rx_response, + filter_index_tmp + 1, shift_width); + + if (filter_index_tmp >= CAN_MAX_NUMBER_OF_FILTES || res) { + SYS_LOG_INF("No space for a new filter!"); + filter_nr = CAN_NO_FREE_FILTER; + goto done; + } + + can_stm32_shift_bits(&device_data->response_type, + filter_index_tmp + 1, shift_width); + can->FM1R = mode_reg; + can->FS1R = scale_reg; + } else { + filter_index_tmp = can_calc_filter_index(filter_nr, can->FM1R, + can->FS1R); + if (filter_index_tmp >= CAN_MAX_NUMBER_OF_FILTES) { + filter_nr = CAN_NO_FREE_FILTER; + goto done; + } + } + + can_stm32_set_filter_bank(filter_nr, &can->sFilterRegister[bank_nr], + filter_type, id, mask); +done: + can->FA1R |= bank_bit; + can->FMR &= ~(CAN_FMR_FINIT); + SYS_LOG_DBG("Filter set! Filter number: %d (index %d)", + filter_nr, filter_index_tmp); + *filter_index = filter_index_tmp; + return filter_nr; +} + + +static inline int can_stm32_attach(struct device *dev, void *response_ptr, + const struct can_filter *filter, + int *filter_index) +{ + const struct can_stm32_config *cfg = DEV_CFG(dev); + struct can_stm32_data *data = DEV_DATA(dev); + CAN_TypeDef *can = cfg->can; + int filter_index_tmp = 0; + int filter_nr; + + k_mutex_lock(&data->set_filter_mutex, K_FOREVER); + + filter_nr = can_stm32_set_filter(filter, data, can, &filter_index_tmp); + if (filter_nr != CAN_NO_FREE_FILTER) { + data->rx_response[filter_index_tmp] = response_ptr; + } + + k_mutex_unlock(&data->set_filter_mutex); + *filter_index = filter_index_tmp; + return filter_nr; +} + +int can_stm32_attach_msgq(struct device *dev, struct k_msgq *msgq, + const struct can_filter *filter) +{ + int filter_nr; + int filter_index; + struct can_stm32_data *data = DEV_DATA(dev); + + filter_nr = can_stm32_attach(dev, msgq, filter, &filter_index); + data->response_type |= (1ULL << filter_index); + return filter_nr; +} + +int can_stm32_attach_isr(struct device *dev, can_rx_callback_t isr, + const struct can_filter *filter) +{ + struct can_stm32_data *data = DEV_DATA(dev); + int filter_nr; + int filter_index; + + filter_nr = can_stm32_attach(dev, isr, filter, &filter_index); + data->response_type &= ~(1ULL << filter_index); + return filter_nr; +} + +void can_stm32_detach(struct device *dev, int filter_nr) +{ + const struct can_stm32_config *cfg = DEV_CFG(dev); + struct can_stm32_data *data = DEV_DATA(dev); + CAN_TypeDef *can = cfg->can; + int bank_nr; + int filter_index; + u32_t bank_bit; + u32_t mode_reg; + u32_t scale_reg; + enum can_filter_type type; + u32_t reset_mask; + + __ASSERT_NO_MSG(filter_nr >= 0 && filter_nr < CAN_MAX_NUMBER_OF_FILTES); + + k_mutex_lock(&data->set_filter_mutex, K_FOREVER); + + bank_nr = filter_nr / 4; + bank_bit = (1U << bank_nr); + mode_reg = can->FM1R; + scale_reg = can->FS1R; + + filter_index = can_calc_filter_index(filter_nr, mode_reg, scale_reg); + type = can_stm32_get_filter_type(bank_bit, mode_reg, scale_reg); + + SYS_LOG_DBG("Detatch filter number %d (index %d), type %d", filter_nr, + filter_index, + type); + + reset_mask = (type == CAN_FILTER_STANDARD) ? 0x01 : + (type == CAN_FILTER_EXTENDED_MASKED) ? 0x0F : + 0x03; + reset_mask = reset_mask << filter_nr; + + data->filter_usage |= reset_mask; + can->FMR |= CAN_FMR_FINIT; + can->FA1R &= ~bank_bit; + + can_stm32_set_filter_bank(filter_nr, &can->sFilterRegister[bank_nr], + type, 0, 0xFFFFFFFF); + + if (!CAN_BANK_IS_EMPTY(data->filter_usage, bank_nr)) { + can->FA1R |= bank_bit; + } else { + SYS_LOG_DBG("Bank number %d is empty -> deakivate", bank_nr); + } + + can->FMR &= ~(CAN_FMR_FINIT); + data->rx_response[filter_index] = NULL; + + k_mutex_unlock(&data->set_filter_mutex); +} + +static const struct can_driver_api can_api_funcs = { + .configure = can_stm32_runtime_configure, + .send = can_stm32_send, + .attach_msgq = can_stm32_attach_msgq, + .attach_isr = can_stm32_attach_isr, + .detach = can_stm32_detach +}; + +#ifdef CONFIG_CAN_1 + +static void config_can_1_irq(CAN_TypeDef *can); + +static const struct can_stm32_config can_stm32_cfg_1 = { + .can = (CAN_TypeDef *)CONFIG_CAN_1_BASE_ADDRESS, + .bus_speed = CONFIG_CAN_1_BUS_SPEED, + .pclken = { + .enr = RCC_APB1ENR_CANEN, + .bus = STM32_CLOCK_BUS_APB1, + }, + .config_irq = config_can_1_irq +}; + +static struct can_stm32_data can_stm32_dev_data_1; + +DEVICE_AND_API_INIT(can_stm32_1, CONFIG_CAN_1_NAME, &can_stm32_init, + &can_stm32_dev_data_1, &can_stm32_cfg_1, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &can_api_funcs); + +static void config_can_1_irq(CAN_TypeDef *can) +{ + SYS_LOG_DBG("Enable CAN1 IRQ"); + IRQ_CONNECT(CONFIG_CAN_1_IRQ, CONFIG_CAN_1_IRQ_PRIORITY, can_stm32_isr, + DEVICE_GET(can_stm32_1), 0); + irq_enable(CONFIG_CAN_1_IRQ); + can->IER |= CAN_IT_TME | CAN_IT_ERR | CAN_IT_FMP0 | CAN_IT_FMP1; +} + +#endif /*CONFIG_CAN_1*/ diff --git a/drivers/can/stm32_can.h b/drivers/can/stm32_can.h new file mode 100644 index 00000000000..74df83d381f --- /dev/null +++ b/drivers/can/stm32_can.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2018 Alexander Wachter + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef _STM32_CAN_H_ +#define _STM32_CAN_H_ + +#include + +#define DEV_DATA(dev) ((struct can_stm32_data *const)(dev)->driver_data) +#define DEV_CFG(dev) \ + ((const struct can_stm32_config *const)(dev)->config->config_info) + +#define BIT_SEG_LENGTH ((CONFIG_CAN_PHASE_SEG1_PROP_SEG) \ + + (CONFIG_CAN_PHASE_SEG2) + 1) + +#define CAN_NUMBER_OF_FILTER_BANKS (14) +#define CAN_MAX_NUMBER_OF_FILTES (CAN_NUMBER_OF_FILTER_BANKS * 4) + +#define CAN_FIRX_STD_IDE_POS (3U) +#define CAN_FIRX_STD_RTR_POS (4U) +#define CAN_FIRX_STD_ID_POS (5U) + +#define CAN_FIRX_EXT_IDE_POS (2U) +#define CAN_FIRX_EXT_RTR_POS (1U) +#define CAN_FIRX_EXT_STD_ID_POS (21U) +#define CAN_FIRX_EXT_EXT_ID_POS (3U) + +#define CAN_BANK_IS_EMPTY(usage, bank_nr) (((usage >> ((bank_nr) * 4)) & 0x0F) == 0x0F) +#define CAN_BANK_IN_LIST_MODE(can, bank) ((can)->FM1R & (1U << (bank))) +#define CAN_BANK_IN_32BIT_MODE(can, bank) ((can)->FS1R & (1U << (bank))) +#define CAN_IN_16BIT_LIST_MODE(can, bank) (CAN_BANK_IN_LIST_MODE(can, bank) && \ + !CAN_BANK_IN_32BIT_MODE(can, bank)) +#define CAN_IN_16BIT_MASK_MODE(can, bank) (!CAN_BANK_IN_LIST_MODE(can, bank) && \ + !CAN_BANK_IN_32BIT_MODE(can, bank)) +#define CAN_IN_32BIT_LIST_MODE(can, bank) (CAN_BANK_IN_LIST_MODE(can, bank) && \ + CAN_BANK_IN_32BIT_MODE(can, bank)) +#define CAN_IN_32BIT_MASK_MODE(can, bank) (!CAN_BANK_IN_LIST_MODE(can, bank) && \ + CAN_BANK_IN_32BIT_MODE(can, bank)) +struct can_mailbox { + can_tx_callback_t tx_callback; + struct k_sem tx_int_sem; + u32_t error_flags; +}; + +enum can_filter_type { + CAN_FILTER_STANDARD, + CAN_FILTER_STANDARD_MASKED, + CAN_FILTER_EXTENDED, + CAN_FILTER_EXTENDED_MASKED +}; + +struct can_stm32_data { + struct k_mutex tx_mutex; + struct k_mutex set_filter_mutex; + struct k_sem tx_int_sem; + struct can_mailbox mb0; + struct can_mailbox mb1; + struct can_mailbox mb2; + u64_t filter_usage; + u64_t response_type; + void *rx_response[CONFIG_CAN_MAX_FILTER]; +}; + +struct can_stm32_config { + CAN_TypeDef *can; /*!< CAN Registers*/ + u32_t bus_speed; + struct stm32_pclken pclken; + void (*config_irq)(CAN_TypeDef *can); +}; + +#endif /*_STM32_CAN_H_*/