From c81eebcd5d8a36e69afbe94319abaa8a04fca3f8 Mon Sep 17 00:00:00 2001 From: tyustli <1225613647@qq.com> Date: Fri, 16 Aug 2019 11:56:26 +0800 Subject: [PATCH] [bsp] [stm32] fix drv_can.c --- bsp/stm32/libraries/HAL_Drivers/drv_can.c | 1092 +++++++++--------- bsp/stm32/libraries/HAL_Drivers/drv_can.h | 43 +- bsp/stm32/libraries/STM32H7xx_HAL/SConscript | 8 +- components/drivers/can/can.c | 152 +-- components/drivers/include/drivers/can.h | 6 +- components/finsh/cmd.c | 2 +- 6 files changed, 678 insertions(+), 625 deletions(-) diff --git a/bsp/stm32/libraries/HAL_Drivers/drv_can.c b/bsp/stm32/libraries/HAL_Drivers/drv_can.c index fd700e6c69..d0221b9623 100644 --- a/bsp/stm32/libraries/HAL_Drivers/drv_can.c +++ b/bsp/stm32/libraries/HAL_Drivers/drv_can.c @@ -14,13 +14,14 @@ */ #include "drv_can.h" +#ifdef BSP_USING_CAN -#ifdef RT_USING_CAN +#define LOG_TAG "drv_can" +#include -static void drv_rx_isr(struct rt_can_device *can, rt_uint32_t fifo); - -#if defined (SOC_SERIES_STM32F1) -static const struct stm_baud_rate_tab can_baud_rate_tab[] = +/* attention !!! baud calculation example: Tclk / ((ss + bs1 + bs2) * brp) 36 / ((1 + 8 + 3) * 3) = 1MHz*/ +#if defined (SOC_SERIES_STM32F1)/* APB1 36MHz(max) */ +static const struct stm32_baud_rate_tab can_baud_rate_tab[] = { {CAN1MBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_3TQ | 3)}, {CAN800kBaud, (CAN_SJW_2TQ | CAN_BS1_5TQ | CAN_BS2_3TQ | 5)}, @@ -32,8 +33,8 @@ static const struct stm_baud_rate_tab can_baud_rate_tab[] = {CAN20kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_3TQ | 150)}, {CAN10kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_3TQ | 300)} }; -#elif defined (SOC_STM32F429IG) -static const struct stm_baud_rate_tab can_baud_rate_tab[] = +#elif defined (SOC_SERIES_STM32F4)/* APB1 45MHz(max) */ +static const struct stm32_baud_rate_tab can_baud_rate_tab[] = { {CAN1MBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_5TQ | 3)}, {CAN800kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_5TQ | 4)}, @@ -45,368 +46,112 @@ static const struct stm_baud_rate_tab can_baud_rate_tab[] = {CAN20kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_5TQ | 150)}, {CAN10kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_5TQ | 300)} }; -#elif defined (SOC_SERIES_STM32F4) -static const struct stm_baud_rate_tab can_baud_rate_tab[] = +#elif defined (SOC_SERIES_STM32F7)/* APB1 54MHz(max) */ +static const struct stm32_baud_rate_tab can_baud_rate_tab[] = { - {CAN1MBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 3)}, - {CAN800kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_4TQ | 4)}, - {CAN500kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 6)}, - {CAN250kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 12)}, - {CAN125kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 24)}, - {CAN100kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 30)}, - {CAN50kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 60)}, - {CAN20kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 150)}, - {CAN10kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_4TQ | 300)} + {CAN1MBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 3)}, + {CAN800kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_7TQ | 4)}, + {CAN500kBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 6)}, + {CAN250kBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 12)}, + {CAN125kBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 24)}, + {CAN100kBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 30)}, + {CAN50kBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 60)}, + {CAN20kBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 150)}, + {CAN10kBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 300)} }; #endif -#define BAUD_DATA(TYPE,NO) \ - ((can_baud_rate_tab[NO].confdata & TYPE##MASK)) +#ifdef BSP_USING_CAN1 +static struct stm32_can drv_can1 = +{ + .name = "can1", + .CanHandle.Instance = CAN1, +}; +#endif + +#ifdef BSP_USING_CAN2 +static struct stm32_can drv_can2 = +{ + "can2", + .CanHandle.Instance = CAN2, +}; +#endif static rt_uint32_t get_can_baud_index(rt_uint32_t baud) { - rt_uint32_t len, index, default_index; + rt_uint32_t len, index; len = sizeof(can_baud_rate_tab) / sizeof(can_baud_rate_tab[0]); - default_index = len; - for (index = 0; index < len; index++) { if (can_baud_rate_tab[index].baud_rate == baud) return index; - - if (can_baud_rate_tab[index].baud_rate == 1000UL * 250) - default_index = index; } - if (default_index != len) - return default_index; - - return 0; + return 0; /* default baud is CAN1MBaud */ } -#ifdef BSP_USING_CAN1 -static struct stm32_drv_can drv_can1; -struct rt_can_device dev_can1; -/** - * @brief This function handles CAN1 TX interrupts. - */ -void CAN1_TX_IRQHandler(void) +static rt_err_t _can_config(struct rt_can_device *can, struct can_configure *cfg) { - rt_interrupt_enter(); - CAN_HandleTypeDef *hcan; - hcan = &drv_can1.CanHandle; - if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP0)) - { - if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK0)) - { - rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_TX_DONE | 0 << 8); - } - else - { - rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_TX_FAIL | 0 << 8); - } - /* Write 0 to Clear transmission status flag RQCPx */ - SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP0); - } - else if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP1)) - { - if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK1)) - { - rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_TX_DONE | 1 << 8); - } - else - { - rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_TX_FAIL | 1 << 8); - } - /* Write 0 to Clear transmission status flag RQCPx */ - SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP1); - } - else if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP2)) - { - if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK2)) - { - rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_TX_DONE | 2 << 8); - } - else - { - rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_TX_FAIL | 2 << 8); - } - /* Write 0 to Clear transmission status flag RQCPx */ - SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP2); - } - rt_interrupt_leave(); -} - -/** - * @brief This function handles CAN1 RX0 interrupts. - */ -void CAN1_RX0_IRQHandler(void) -{ - rt_interrupt_enter(); - drv_rx_isr(&dev_can1, CAN_RX_FIFO0); - rt_interrupt_leave(); -} - -/** - * @brief This function handles CAN1 RX1 interrupts. - */ -void CAN1_RX1_IRQHandler(void) -{ - rt_interrupt_enter(); - drv_rx_isr(&dev_can1, CAN_RX_FIFO1); - rt_interrupt_leave(); -} - -/** - * @brief This function handles CAN1 SCE interrupts. - */ -void CAN1_SCE_IRQHandler(void) -{ - rt_uint32_t errtype; - CAN_HandleTypeDef *hcan; - - hcan = &drv_can1.CanHandle; - errtype = hcan->Instance->ESR; - - rt_interrupt_enter(); - HAL_CAN_IRQHandler(hcan); - - if (errtype & 0x70 && dev_can1.status.lasterrtype == (errtype & 0x70)) - { - switch ((errtype & 0x70) >> 4) - { - case RT_CAN_BUS_BIT_PAD_ERR: - dev_can1.status.bitpaderrcnt++; - break; - case RT_CAN_BUS_FORMAT_ERR: - dev_can1.status.formaterrcnt++; - break; - case RT_CAN_BUS_ACK_ERR: - dev_can1.status.ackerrcnt++; - break; - case RT_CAN_BUS_IMPLICIT_BIT_ERR: - case RT_CAN_BUS_EXPLICIT_BIT_ERR: - dev_can1.status.biterrcnt++; - break; - case RT_CAN_BUS_CRC_ERR: - dev_can1.status.crcerrcnt++; - break; - } - dev_can1.status.lasterrtype = errtype & 0x70; - hcan->Instance->ESR &= ~0x70; - } - dev_can1.status.rcverrcnt = errtype >> 24; - dev_can1.status.snderrcnt = (errtype >> 16 & 0xFF); - dev_can1.status.errcode = errtype & 0x07; - hcan->Instance->MSR |= CAN_MSR_ERRI; - rt_interrupt_leave(); -} -#endif /* BSP_USING_CAN1 */ - -#ifdef BSP_USING_CAN2 -static struct stm32_drv_can drv_can2; -struct rt_can_device dev_can2; -/** - * @brief This function handles CAN2 TX interrupts. - */ -void CAN2_TX_IRQHandler(void) -{ - rt_interrupt_enter(); - CAN_HandleTypeDef *hcan; - hcan = &drv_can2.CanHandle; - if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP0)) - { - if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK0)) - { - rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_TX_DONE | 0 << 8); - } - else - { - rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_TX_FAIL | 0 << 8); - } - /* Write 0 to Clear transmission status flag RQCPx */ - SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP0); - } - else if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP1)) - { - if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK1)) - { - rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_TX_DONE | 1 << 8); - } - else - { - rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_TX_FAIL | 1 << 8); - } - /* Write 0 to Clear transmission status flag RQCPx */ - SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP1); - } - else if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP2)) - { - if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK2)) - { - rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_TX_DONE | 2 << 8); - } - else - { - rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_TX_FAIL | 2 << 8); - } - /* Write 0 to Clear transmission status flag RQCPx */ - SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP2); - } - rt_interrupt_leave(); -} - -/** - * @brief This function handles CAN2 RX0 interrupts. - */ -void CAN2_RX0_IRQHandler(void) -{ - rt_interrupt_enter(); - drv_rx_isr(&dev_can2, CAN_RX_FIFO0); - rt_interrupt_leave(); -} - -/** - * @brief This function handles CAN2 RX1 interrupts. - */ -void CAN2_RX1_IRQHandler(void) -{ - rt_interrupt_enter(); - drv_rx_isr(&dev_can2, CAN_RX_FIFO1); - rt_interrupt_leave(); -} - -/** - * @brief This function handles CAN2 SCE interrupts. - */ -void CAN2_SCE_IRQHandler(void) -{ - rt_uint32_t errtype; - CAN_HandleTypeDef *hcan; - - hcan = &drv_can2.CanHandle; - errtype = hcan->Instance->ESR; - - rt_interrupt_enter(); - HAL_CAN_IRQHandler(hcan); - - if (errtype & 0x70 && dev_can2.status.lasterrtype == (errtype & 0x70)) - { - switch ((errtype & 0x70) >> 4) - { - case RT_CAN_BUS_BIT_PAD_ERR: - dev_can2.status.bitpaderrcnt++; - break; - case RT_CAN_BUS_FORMAT_ERR: - dev_can2.status.formaterrcnt++; - break; - case RT_CAN_BUS_ACK_ERR: - dev_can2.status.ackerrcnt++; - break; - case RT_CAN_BUS_IMPLICIT_BIT_ERR: - case RT_CAN_BUS_EXPLICIT_BIT_ERR: - dev_can2.status.biterrcnt++; - break; - case RT_CAN_BUS_CRC_ERR: - dev_can2.status.crcerrcnt++; - break; - } - dev_can2.status.lasterrtype = errtype & 0x70; - hcan->Instance->ESR &= ~0x70; - } - dev_can2.status.rcverrcnt = errtype >> 24; - dev_can2.status.snderrcnt = (errtype >> 16 & 0xFF); - dev_can2.status.errcode = errtype & 0x07; - hcan->Instance->MSR |= CAN_MSR_ERRI; - rt_interrupt_leave(); -} -#endif /* BSP_USING_CAN2 */ - -/** - * @brief Error CAN callback. - * @param hcan pointer to a CAN_HandleTypeDef structure that contains - * the configuration information for the specified CAN. - * @retval None - */ -void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan) -{ - __HAL_CAN_ENABLE_IT(hcan, CAN_IT_ERROR_WARNING | - CAN_IT_ERROR_PASSIVE | - CAN_IT_BUSOFF | - CAN_IT_LAST_ERROR_CODE | - CAN_IT_ERROR | - CAN_IT_RX_FIFO0_MSG_PENDING| - CAN_IT_RX_FIFO0_OVERRUN| - CAN_IT_RX_FIFO1_MSG_PENDING| - CAN_IT_RX_FIFO1_OVERRUN| - CAN_IT_TX_MAILBOX_EMPTY); -} - - - - -static rt_err_t drv_configure(struct rt_can_device *dev_can, - struct can_configure *cfg) -{ - struct stm32_drv_can *drv_can; + struct stm32_can *drv_can; rt_uint32_t baud_index; - CAN_InitTypeDef *drv_init; - RT_ASSERT(dev_can); + RT_ASSERT(can); RT_ASSERT(cfg); + drv_can = (struct stm32_can *)can->parent.user_data; + RT_ASSERT(drv_can); - drv_can = (struct stm32_drv_can *)dev_can->parent.user_data; - drv_init = &drv_can->CanHandle.Init; - - drv_init->TimeTriggeredMode = DISABLE; - drv_init->AutoBusOff = ENABLE; - drv_init->AutoWakeUp = DISABLE; - drv_init->AutoRetransmission = DISABLE; - drv_init->ReceiveFifoLocked = DISABLE; - drv_init->TransmitFifoPriority = ENABLE; + drv_can->CanHandle.Init.TimeTriggeredMode = DISABLE; + drv_can->CanHandle.Init.AutoBusOff = ENABLE; + drv_can->CanHandle.Init.AutoWakeUp = DISABLE; + drv_can->CanHandle.Init.AutoRetransmission = DISABLE; + drv_can->CanHandle.Init.ReceiveFifoLocked = DISABLE; + drv_can->CanHandle.Init.TransmitFifoPriority = ENABLE; switch (cfg->mode) { case RT_CAN_MODE_NORMAL: - drv_init->Mode = CAN_MODE_NORMAL; + drv_can->CanHandle.Init.Mode = CAN_MODE_NORMAL; break; case RT_CAN_MODE_LISEN: - drv_init->Mode = CAN_MODE_SILENT; + drv_can->CanHandle.Init.Mode = CAN_MODE_SILENT; break; case RT_CAN_MODE_LOOPBACK: - drv_init->Mode = CAN_MODE_LOOPBACK; + drv_can->CanHandle.Init.Mode = CAN_MODE_LOOPBACK; break; case RT_CAN_MODE_LOOPBACKANLISEN: - drv_init->Mode = CAN_MODE_SILENT_LOOPBACK; + drv_can->CanHandle.Init.Mode = CAN_MODE_SILENT_LOOPBACK; break; } baud_index = get_can_baud_index(cfg->baud_rate); - drv_init->SyncJumpWidth = BAUD_DATA(SJW, baud_index); - drv_init->TimeSeg1 = BAUD_DATA(BS1, baud_index); - drv_init->TimeSeg2 = BAUD_DATA(BS2, baud_index); - drv_init->Prescaler = BAUD_DATA(RRESCL, baud_index); + drv_can->CanHandle.Init.SyncJumpWidth = BAUD_DATA(SJW, baud_index); + drv_can->CanHandle.Init.TimeSeg1 = BAUD_DATA(BS1, baud_index); + drv_can->CanHandle.Init.TimeSeg2 = BAUD_DATA(BS2, baud_index); + drv_can->CanHandle.Init.Prescaler = BAUD_DATA(RRESCL, baud_index); + /* init can */ if (HAL_CAN_Init(&drv_can->CanHandle) != HAL_OK) { - return RT_ERROR; + return -RT_ERROR; } - - /* Filter conf */ + + /* default filter config */ HAL_CAN_ConfigFilter(&drv_can->CanHandle, &drv_can->FilterConfig); /* can start */ HAL_CAN_Start(&drv_can->CanHandle); + return RT_EOK; } -static rt_err_t drv_control(struct rt_can_device *can, int cmd, void *arg) +static rt_err_t _can_control(struct rt_can_device *can, int cmd, void *arg) { - struct stm32_drv_can *drv_can = RT_NULL; rt_uint32_t argval; - struct rt_can_filter_config *filter_cfg = RT_NULL; - CAN_FilterTypeDef can_filter; - drv_can = (struct stm32_drv_can *) can->parent.user_data; - assert_param(drv_can != RT_NULL); + struct stm32_can *drv_can; + struct rt_can_filter_config *filter_cfg; + + RT_ASSERT(can != RT_NULL); + drv_can = (struct stm32_can *)can->parent.user_data; + RT_ASSERT(drv_can != RT_NULL); switch (cmd) { @@ -419,13 +164,13 @@ static rt_err_t drv_control(struct rt_can_device *can, int cmd, void *arg) HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn); HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn); } - #ifdef CAN2 - else +#ifdef CAN2 + if (CAN2 == drv_can->CanHandle.Instance) { HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn); HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn); } - #endif +#endif __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_RX_FIFO0_MSG_PENDING); __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_RX_FIFO0_FULL); __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_RX_FIFO0_OVERRUN); @@ -439,12 +184,12 @@ static rt_err_t drv_control(struct rt_can_device *can, int cmd, void *arg) { HAL_NVIC_DisableIRQ(CAN1_TX_IRQn); } - #ifdef CAN2 - else +#ifdef CAN2 + if (CAN2 == drv_can->CanHandle.Instance) { HAL_NVIC_DisableIRQ(CAN2_TX_IRQn); } - #endif +#endif __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_TX_MAILBOX_EMPTY); } else if (argval == RT_DEVICE_CAN_INT_ERR) @@ -453,12 +198,14 @@ static rt_err_t drv_control(struct rt_can_device *can, int cmd, void *arg) { NVIC_DisableIRQ(CAN1_SCE_IRQn); } - #ifdef CAN2 - else +#ifdef CAN2 + if (CAN2 == drv_can->CanHandle.Instance) { NVIC_DisableIRQ(CAN2_SCE_IRQn); } - #endif +#endif + __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_ERROR_WARNING); + __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_ERROR_PASSIVE); __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_BUSOFF); __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_LAST_ERROR_CODE); __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_ERROR); @@ -482,15 +229,15 @@ static rt_err_t drv_control(struct rt_can_device *can, int cmd, void *arg) HAL_NVIC_SetPriority(CAN1_RX1_IRQn, 1, 0); HAL_NVIC_EnableIRQ(CAN1_RX1_IRQn); } - #ifdef CAN2 - else +#ifdef CAN2 + if (CAN2 == drv_can->CanHandle.Instance) { HAL_NVIC_SetPriority(CAN2_RX0_IRQn, 1, 0); HAL_NVIC_EnableIRQ(CAN2_RX0_IRQn); HAL_NVIC_SetPriority(CAN2_RX1_IRQn, 1, 0); HAL_NVIC_EnableIRQ(CAN2_RX1_IRQn); } - #endif +#endif } else if (argval == RT_DEVICE_FLAG_INT_TX) { @@ -501,16 +248,18 @@ static rt_err_t drv_control(struct rt_can_device *can, int cmd, void *arg) HAL_NVIC_SetPriority(CAN1_TX_IRQn, 1, 0); HAL_NVIC_EnableIRQ(CAN1_TX_IRQn); } - #ifdef CAN2 - else +#ifdef CAN2 + if (CAN2 == drv_can->CanHandle.Instance) { HAL_NVIC_SetPriority(CAN2_TX_IRQn, 1, 0); HAL_NVIC_EnableIRQ(CAN2_TX_IRQn); } - #endif +#endif } else if (argval == RT_DEVICE_CAN_INT_ERR) { + __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_ERROR_WARNING); + __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_ERROR_PASSIVE); __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_BUSOFF); __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_LAST_ERROR_CODE); __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_ERROR); @@ -520,100 +269,98 @@ static rt_err_t drv_control(struct rt_can_device *can, int cmd, void *arg) HAL_NVIC_SetPriority(CAN1_SCE_IRQn, 1, 0); HAL_NVIC_EnableIRQ(CAN1_SCE_IRQn); } - #ifdef CAN2 - else +#ifdef CAN2 + if (CAN2 == drv_can->CanHandle.Instance) { HAL_NVIC_SetPriority(CAN2_SCE_IRQn, 1, 0); HAL_NVIC_EnableIRQ(CAN2_SCE_IRQn); } - #endif +#endif } break; case RT_CAN_CMD_SET_FILTER: if (RT_NULL == arg) { - /* default Filter conf */ + /* default filter config */ HAL_CAN_ConfigFilter(&drv_can->CanHandle, &drv_can->FilterConfig); } else { filter_cfg = (struct rt_can_filter_config *)arg; /* get default filter */ - can_filter = drv_can->FilterConfig; - for (int i = 0; i < filter_cfg->count; ++i) + for (int i = 0; i < filter_cfg->count; i++) { - can_filter.FilterBank = filter_cfg->items[i].hdr; - can_filter.FilterIdHigh = (filter_cfg->items[i].id >> 13) & 0xFFFF; - can_filter.FilterIdLow = ((filter_cfg->items[i].id << 3) | - (filter_cfg->items[i].ide << 2) | - (filter_cfg->items[i].rtr << 1)) & 0xFFFF; - can_filter.FilterMaskIdHigh = (filter_cfg->items[i].mask >> 16) & 0xFFFF; - can_filter.FilterMaskIdLow = filter_cfg->items[i].mask & 0xFFFF; - can_filter.FilterMode = filter_cfg->items[i].mode; + drv_can->FilterConfig.FilterBank = filter_cfg->items[i].hdr; + drv_can->FilterConfig.FilterIdHigh = (filter_cfg->items[i].id >> 13) & 0xFFFF; + drv_can->FilterConfig.FilterIdLow = ((filter_cfg->items[i].id << 3) | + (filter_cfg->items[i].ide << 2) | + (filter_cfg->items[i].rtr << 1)) & 0xFFFF; + drv_can->FilterConfig.FilterMaskIdHigh = (filter_cfg->items[i].mask >> 16) & 0xFFFF; + drv_can->FilterConfig.FilterMaskIdLow = filter_cfg->items[i].mask & 0xFFFF; + drv_can->FilterConfig.FilterMode = filter_cfg->items[i].mode; /* Filter conf */ - HAL_CAN_ConfigFilter(&drv_can->CanHandle, &can_filter); + HAL_CAN_ConfigFilter(&drv_can->CanHandle, &drv_can->FilterConfig); } } break; case RT_CAN_CMD_SET_MODE: argval = (rt_uint32_t) arg; if (argval != RT_CAN_MODE_NORMAL && - argval != RT_CAN_MODE_LISEN && - argval != RT_CAN_MODE_LOOPBACK && - argval != RT_CAN_MODE_LOOPBACKANLISEN) + argval != RT_CAN_MODE_LISEN && + argval != RT_CAN_MODE_LOOPBACK && + argval != RT_CAN_MODE_LOOPBACKANLISEN) { - return RT_ERROR; + return -RT_ERROR; } - if (argval != can->config.mode) + if (argval != drv_can->device.config.mode) { - can->config.mode = argval; - return drv_configure(can, &can->config); + drv_can->device.config.mode = argval; + return _can_config(&drv_can->device, &drv_can->device.config); } break; case RT_CAN_CMD_SET_BAUD: argval = (rt_uint32_t) arg; if (argval != CAN1MBaud && - argval != CAN800kBaud && - argval != CAN500kBaud && - argval != CAN250kBaud && - argval != CAN125kBaud && - argval != CAN100kBaud && - argval != CAN50kBaud && - argval != CAN20kBaud && - argval != CAN10kBaud) + argval != CAN800kBaud && + argval != CAN500kBaud && + argval != CAN250kBaud && + argval != CAN125kBaud && + argval != CAN100kBaud && + argval != CAN50kBaud && + argval != CAN20kBaud && + argval != CAN10kBaud) { - return RT_ERROR; + return -RT_ERROR; } - if (argval != can->config.baud_rate) + if (argval != drv_can->device.config.baud_rate) { - can->config.baud_rate = argval; - return drv_configure(can, &can->config); + drv_can->device.config.baud_rate = argval; + return _can_config(&drv_can->device, &drv_can->device.config); } break; case RT_CAN_CMD_SET_PRIV: argval = (rt_uint32_t) arg; if (argval != RT_CAN_MODE_PRIV && - argval != RT_CAN_MODE_NOPRIV) + argval != RT_CAN_MODE_NOPRIV) { - return RT_ERROR; + return -RT_ERROR; } - if (argval != can->config.privmode) + if (argval != drv_can->device.config.privmode) { - can->config.privmode = argval; - return drv_configure(can, &can->config); + drv_can->device.config.privmode = argval; + return _can_config(&drv_can->device, &drv_can->device.config); } break; case RT_CAN_CMD_GET_STATUS: { rt_uint32_t errtype; errtype = drv_can->CanHandle.Instance->ESR; - can->status.rcverrcnt = errtype >> 24; - can->status.snderrcnt = (errtype >> 16 & 0xFF); - can->status.errcode = errtype & 0x07; - if (arg != &can->status) - { - rt_memcpy(arg, &can->status, sizeof(can->status)); - } + drv_can->device.status.rcverrcnt = errtype >> 24; + drv_can->device.status.snderrcnt = (errtype >> 16 & 0xFF); + drv_can->device.status.lasterrtype = errtype & 0x70; + drv_can->device.status.errcode = errtype & 0x07; + + rt_memcpy(arg, &drv_can->device.status, sizeof(drv_can->device.status)); } break; } @@ -621,19 +368,28 @@ static rt_err_t drv_control(struct rt_can_device *can, int cmd, void *arg) return RT_EOK; } -static int drv_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t boxno) +static int _can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t box_num) { - CAN_HandleTypeDef *hcan = RT_NULL; - hcan = &((struct stm32_drv_can *) can->parent.user_data)->CanHandle; + CAN_HandleTypeDef *hcan; + hcan = &((struct stm32_can *) can->parent.user_data)->CanHandle; struct rt_can_msg *pmsg = (struct rt_can_msg *) buf; CAN_TxHeaderTypeDef txheader = {0}; - - /*check Select mailbox is empty */ - switch (1 << boxno) + HAL_CAN_StateTypeDef state = hcan->State; + + /* Check the parameters */ + RT_ASSERT(IS_CAN_IDTYPE(pmsg->ide)); + RT_ASSERT(IS_CAN_RTR(pmsg->rtr)); + RT_ASSERT(IS_CAN_DLC(pmsg->len)); + + if ((state == HAL_CAN_STATE_READY) || + (state == HAL_CAN_STATE_LISTENING)) { - case CAN_TX_MAILBOX0: - if (HAL_IS_BIT_SET(hcan->Instance->TSR, CAN_TSR_TME0) != SET) - { + /*check select mailbox is empty */ + switch (1 << box_num) + { + case CAN_TX_MAILBOX0: + if (HAL_IS_BIT_SET(hcan->Instance->TSR, CAN_TSR_TME0) != SET) + { /* Change CAN state */ hcan->State = HAL_CAN_STATE_ERROR; /* Return function status */ @@ -641,8 +397,8 @@ static int drv_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t b } break; case CAN_TX_MAILBOX1: - if (HAL_IS_BIT_SET(hcan->Instance->TSR, CAN_TSR_TME1) != SET) - { + if (HAL_IS_BIT_SET(hcan->Instance->TSR, CAN_TSR_TME1) != SET) + { /* Change CAN state */ hcan->State = HAL_CAN_STATE_ERROR; /* Return function status */ @@ -650,8 +406,8 @@ static int drv_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t b } break; case CAN_TX_MAILBOX2: - if (HAL_IS_BIT_SET(hcan->Instance->TSR, CAN_TSR_TME2) != SET) - { + if (HAL_IS_BIT_SET(hcan->Instance->TSR, CAN_TSR_TME2) != SET) + { /* Change CAN state */ hcan->State = HAL_CAN_STATE_ERROR; /* Return function status */ @@ -661,119 +417,81 @@ static int drv_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t b default: RT_ASSERT(0); break; - } - - if (RT_CAN_STDID == pmsg->ide) - { - txheader.IDE = CAN_ID_STD; - txheader.StdId = pmsg->id; - } - else - { - txheader.IDE = CAN_ID_EXT; - txheader.ExtId = pmsg->id; - } - - if (RT_CAN_DTR == pmsg->rtr) - { - txheader.RTR = CAN_RTR_DATA; - } - else - { - txheader.RTR = CAN_RTR_REMOTE; - } - - /* clear TIR */ - hcan->Instance->sTxMailBox[boxno].TIR &= CAN_TI0R_TXRQ; - /* Set up the Id */ - if (RT_CAN_STDID == pmsg->ide) - { - hcan->Instance->sTxMailBox[boxno].TIR |= (txheader.StdId << CAN_TI0R_STID_Pos) | txheader.IDE | txheader.RTR; - } - else - { - hcan->Instance->sTxMailBox[boxno].TIR |= (txheader.ExtId << CAN_TI0R_EXID_Pos) | txheader.IDE | txheader.RTR; - } - /* Set up the DLC */ - hcan->Instance->sTxMailBox[boxno].TDTR = pmsg->len & 0x0FU; - /* Set up the data field */ - WRITE_REG(hcan->Instance->sTxMailBox[boxno].TDHR, - ((uint32_t)pmsg->data[7] << CAN_TDH0R_DATA7_Pos) | - ((uint32_t)pmsg->data[6] << CAN_TDH0R_DATA6_Pos) | - ((uint32_t)pmsg->data[5] << CAN_TDH0R_DATA5_Pos) | - ((uint32_t)pmsg->data[4] << CAN_TDH0R_DATA4_Pos)); - WRITE_REG(hcan->Instance->sTxMailBox[boxno].TDLR, - ((uint32_t)pmsg->data[3] << CAN_TDL0R_DATA3_Pos) | - ((uint32_t)pmsg->data[2] << CAN_TDL0R_DATA2_Pos) | - ((uint32_t)pmsg->data[1] << CAN_TDL0R_DATA1_Pos) | - ((uint32_t)pmsg->data[0] << CAN_TDL0R_DATA0_Pos)); - /* Request transmission */ - SET_BIT(hcan->Instance->sTxMailBox[boxno].TIR, CAN_TI0R_TXRQ); - return RT_EOK; -} + } -static void drv_rx_isr(struct rt_can_device *can, rt_uint32_t fifo) -{ - CAN_HandleTypeDef *hcan; - hcan = &((struct stm32_drv_can *) can->parent.user_data)->CanHandle; - - switch (fifo) + if (RT_CAN_STDID == pmsg->ide) + { + txheader.IDE = CAN_ID_STD; + RT_ASSERT(IS_CAN_STDID(pmsg->id)); + txheader.StdId = pmsg->id; + } + else + { + txheader.IDE = CAN_ID_EXT; + RT_ASSERT(IS_CAN_EXTID(pmsg->id)); + txheader.ExtId = pmsg->id; + } + + if (RT_CAN_DTR == pmsg->rtr) + { + txheader.RTR = CAN_RTR_DATA; + } + else + { + txheader.RTR = CAN_RTR_REMOTE; + } + /* Set up the Id */ + if (RT_CAN_STDID == pmsg->ide) + { + hcan->Instance->sTxMailBox[box_num].TIR |= (txheader.StdId << CAN_TI0R_STID_Pos) | txheader.RTR; + } + else + { + hcan->Instance->sTxMailBox[box_num].TIR |= (txheader.ExtId << CAN_TI0R_EXID_Pos) | txheader.IDE | txheader.RTR; + } + /* Set up the DLC */ + hcan->Instance->sTxMailBox[box_num].TDTR = pmsg->len & 0x0FU; + /* Set up the data field */ + WRITE_REG(hcan->Instance->sTxMailBox[box_num].TDHR, + ((uint32_t)pmsg->data[7] << CAN_TDH0R_DATA7_Pos) | + ((uint32_t)pmsg->data[6] << CAN_TDH0R_DATA6_Pos) | + ((uint32_t)pmsg->data[5] << CAN_TDH0R_DATA5_Pos) | + ((uint32_t)pmsg->data[4] << CAN_TDH0R_DATA4_Pos)); + WRITE_REG(hcan->Instance->sTxMailBox[box_num].TDLR, + ((uint32_t)pmsg->data[3] << CAN_TDL0R_DATA3_Pos) | + ((uint32_t)pmsg->data[2] << CAN_TDL0R_DATA2_Pos) | + ((uint32_t)pmsg->data[1] << CAN_TDL0R_DATA1_Pos) | + ((uint32_t)pmsg->data[0] << CAN_TDL0R_DATA0_Pos)); + /* Request transmission */ + SET_BIT(hcan->Instance->sTxMailBox[box_num].TIR, CAN_TI0R_TXRQ); + + return RT_EOK; + } + else { - case CAN_RX_FIFO0: - /* save to user list */ - if (HAL_CAN_GetRxFifoFillLevel(hcan, CAN_RX_FIFO0) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO0_MSG_PENDING)) - { - rt_hw_can_isr(can, RT_CAN_EVENT_RX_IND | fifo << 8); - } - /* Check FULL flag for FIFO0 */ - if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FF0) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO0_FULL)) - { - /* Clear FIFO0 FULL Flag */ - __HAL_CAN_CLEAR_FLAG(hcan, CAN_FLAG_FF0); - } - - /* Check Overrun flag for FIFO0 */ - if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FOV0) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO0_OVERRUN)) - { - /* Clear FIFO0 Overrun Flag */ - __HAL_CAN_CLEAR_FLAG(hcan, CAN_FLAG_FOV0); - rt_hw_can_isr(can, RT_CAN_EVENT_RXOF_IND | fifo << 8); - } - break; - case CAN_RX_FIFO1: - /* save to user list */ - if (HAL_CAN_GetRxFifoFillLevel(hcan, CAN_RX_FIFO1) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO1_MSG_PENDING)) - { - rt_hw_can_isr(can, RT_CAN_EVENT_RX_IND | fifo << 8); - } - /* Check FULL flag for FIFO1 */ - if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FF1) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO1_FULL)) - { - /* Clear FIFO1 FULL Flag */ - __HAL_CAN_CLEAR_FLAG(hcan, CAN_FLAG_FF1); - } - - /* Check Overrun flag for FIFO1 */ - if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FOV1) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO1_OVERRUN)) - { - /* Clear FIFO1 Overrun Flag */ - __HAL_CAN_CLEAR_FLAG(hcan, CAN_FLAG_FOV1); - rt_hw_can_isr(can, RT_CAN_EVENT_RXOF_IND | fifo << 8); - } - break; + /* Update error code */ + hcan->ErrorCode |= HAL_CAN_ERROR_NOT_INITIALIZED; + + return -RT_ERROR; } } -static int drv_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo) +static int _can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo) { HAL_StatusTypeDef status; - CAN_HandleTypeDef *hcan = RT_NULL; - struct rt_can_msg *pmsg = (struct rt_can_msg *) buf; - hcan = &((struct stm32_drv_can *) can->parent.user_data)->CanHandle; + CAN_HandleTypeDef *hcan; + struct rt_can_msg *pmsg; CAN_RxHeaderTypeDef rxheader = {0}; + + RT_ASSERT(can); + + hcan = &((struct stm32_can *)can->parent.user_data)->CanHandle; + pmsg = (struct rt_can_msg *) buf; + /* get data */ status = HAL_CAN_GetRxMessage(hcan, fifo, &rxheader, pmsg->data); - if (HAL_OK != status) return -RT_ERROR; + if (HAL_OK != status) + return -RT_ERROR; /* get id */ if (CAN_ID_STD == rxheader.IDE) { @@ -798,71 +516,387 @@ static int drv_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo) pmsg->len = rxheader.DLC; /* get hdr */ pmsg->hdr = rxheader.FilterMatchIndex; + return RT_EOK; } -static const struct rt_can_ops drv_can_ops = + +static const struct rt_can_ops _can_ops = { - drv_configure, - drv_control, - drv_sendmsg, - drv_recvmsg, + _can_config, + _can_control, + _can_sendmsg, + _can_recvmsg, }; +static void _can_rx_isr(struct rt_can_device *can, rt_uint32_t fifo) +{ + CAN_HandleTypeDef *hcan; + RT_ASSERT(can); + hcan = &((struct stm32_can *) can->parent.user_data)->CanHandle; + + switch (fifo) + { + case CAN_RX_FIFO0: + /* save to user list */ + if (HAL_CAN_GetRxFifoFillLevel(hcan, CAN_RX_FIFO0) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO0_MSG_PENDING)) + { + rt_hw_can_isr(can, RT_CAN_EVENT_RX_IND | fifo << 8); + } + /* Check FULL flag for FIFO0 */ + if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FF0) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO0_FULL)) + { + /* Clear FIFO0 FULL Flag */ + __HAL_CAN_CLEAR_FLAG(hcan, CAN_FLAG_FF0); + } + + /* Check Overrun flag for FIFO0 */ + if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FOV0) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO0_OVERRUN)) + { + /* Clear FIFO0 Overrun Flag */ + __HAL_CAN_CLEAR_FLAG(hcan, CAN_FLAG_FOV0); + rt_hw_can_isr(can, RT_CAN_EVENT_RXOF_IND | fifo << 8); + } + break; + case CAN_RX_FIFO1: + /* save to user list */ + if (HAL_CAN_GetRxFifoFillLevel(hcan, CAN_RX_FIFO1) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO1_MSG_PENDING)) + { + rt_hw_can_isr(can, RT_CAN_EVENT_RX_IND | fifo << 8); + } + /* Check FULL flag for FIFO1 */ + if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FF1) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO1_FULL)) + { + /* Clear FIFO1 FULL Flag */ + __HAL_CAN_CLEAR_FLAG(hcan, CAN_FLAG_FF1); + } + + /* Check Overrun flag for FIFO1 */ + if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FOV1) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO1_OVERRUN)) + { + /* Clear FIFO1 Overrun Flag */ + __HAL_CAN_CLEAR_FLAG(hcan, CAN_FLAG_FOV1); + rt_hw_can_isr(can, RT_CAN_EVENT_RXOF_IND | fifo << 8); + } + break; + } +} + +#ifdef BSP_USING_CAN1 +/** + * @brief This function handles CAN1 TX interrupts. transmit fifo0/1/2 is empty can trigger this interrupt + */ +void CAN1_TX_IRQHandler(void) +{ + rt_interrupt_enter(); + CAN_HandleTypeDef *hcan; + hcan = &drv_can1.CanHandle; + if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP0)) + { + if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK0)) + { + rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_DONE | 0 << 8); + } + else + { + rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_FAIL | 0 << 8); + } + /* Write 0 to Clear transmission status flag RQCPx */ + SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP0); + } + else if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP1)) + { + if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK1)) + { + rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_DONE | 1 << 8); + } + else + { + rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_FAIL | 1 << 8); + } + /* Write 0 to Clear transmission status flag RQCPx */ + SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP1); + } + else if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP2)) + { + if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK2)) + { + rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_DONE | 2 << 8); + } + else + { + rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_FAIL | 2 << 8); + } + /* Write 0 to Clear transmission status flag RQCPx */ + SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP2); + } + rt_interrupt_leave(); +} + +/** + * @brief This function handles CAN1 RX0 interrupts. + */ +void CAN1_RX0_IRQHandler(void) +{ + rt_interrupt_enter(); + _can_rx_isr(&drv_can1.device, CAN_RX_FIFO0); + rt_interrupt_leave(); +} + +/** + * @brief This function handles CAN1 RX1 interrupts. + */ +void CAN1_RX1_IRQHandler(void) +{ + rt_interrupt_enter(); + _can_rx_isr(&drv_can1.device, CAN_RX_FIFO1); + rt_interrupt_leave(); +} + +/** + * @brief This function handles CAN1 SCE interrupts. + */ +void CAN1_SCE_IRQHandler(void) +{ + rt_uint32_t errtype; + CAN_HandleTypeDef *hcan; + + hcan = &drv_can1.CanHandle; + errtype = hcan->Instance->ESR; + + rt_interrupt_enter(); + HAL_CAN_IRQHandler(hcan); + + switch ((errtype & 0x70) >> 4) + { + case RT_CAN_BUS_BIT_PAD_ERR: + drv_can1.device.status.bitpaderrcnt++; + break; + case RT_CAN_BUS_FORMAT_ERR: + drv_can1.device.status.formaterrcnt++; + break; + case RT_CAN_BUS_ACK_ERR:/* attention !!! test ack err's unit is transmit unit */ + drv_can1.device.status.ackerrcnt++; + if (!READ_BIT(drv_can1.CanHandle.Instance->TSR, CAN_FLAG_TXOK0)) + rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_FAIL | 0 << 8); + else if (!READ_BIT(drv_can1.CanHandle.Instance->TSR, CAN_FLAG_TXOK0)) + rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_FAIL | 1 << 8); + else if (!READ_BIT(drv_can1.CanHandle.Instance->TSR, CAN_FLAG_TXOK0)) + rt_hw_can_isr(&drv_can1.device, RT_CAN_EVENT_TX_FAIL | 2 << 8); + break; + case RT_CAN_BUS_IMPLICIT_BIT_ERR: + case RT_CAN_BUS_EXPLICIT_BIT_ERR: + drv_can1.device.status.biterrcnt++; + break; + case RT_CAN_BUS_CRC_ERR: + drv_can1.device.status.crcerrcnt++; + break; + } + + drv_can1.device.status.lasterrtype = errtype & 0x70; + drv_can1.device.status.rcverrcnt = errtype >> 24; + drv_can1.device.status.snderrcnt = (errtype >> 16 & 0xFF); + drv_can1.device.status.errcode = errtype & 0x07; + hcan->Instance->MSR |= CAN_MSR_ERRI; + rt_interrupt_leave(); +} +#endif /* BSP_USING_CAN1 */ + +#ifdef BSP_USING_CAN2 +/** + * @brief This function handles CAN2 TX interrupts. + */ +void CAN2_TX_IRQHandler(void) +{ + rt_interrupt_enter(); + CAN_HandleTypeDef *hcan; + hcan = &drv_can2.CanHandle; + if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP0)) + { + if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK0)) + { + rt_hw_can_isr(&drv_can2.device, RT_CAN_EVENT_TX_DONE | 0 << 8); + } + else + { + rt_hw_can_isr(&drv_can2.device, RT_CAN_EVENT_TX_FAIL | 0 << 8); + } + /* Write 0 to Clear transmission status flag RQCPx */ + SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP0); + } + else if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP1)) + { + if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK1)) + { + rt_hw_can_isr(&drv_can2.device, RT_CAN_EVENT_TX_DONE | 1 << 8); + } + else + { + rt_hw_can_isr(&drv_can2.device, RT_CAN_EVENT_TX_FAIL | 1 << 8); + } + /* Write 0 to Clear transmission status flag RQCPx */ + SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP1); + } + else if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP2)) + { + if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK2)) + { + rt_hw_can_isr(&drv_can2.device, RT_CAN_EVENT_TX_DONE | 2 << 8); + } + else + { + rt_hw_can_isr(&drv_can2.device, RT_CAN_EVENT_TX_FAIL | 2 << 8); + } + /* Write 0 to Clear transmission status flag RQCPx */ + SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP2); + } + rt_interrupt_leave(); +} + +/** + * @brief This function handles CAN2 RX0 interrupts. + */ +void CAN2_RX0_IRQHandler(void) +{ + rt_interrupt_enter(); + _can_rx_isr(&drv_can2.device, CAN_RX_FIFO0); + rt_interrupt_leave(); +} + +/** + * @brief This function handles CAN2 RX1 interrupts. + */ +void CAN2_RX1_IRQHandler(void) +{ + rt_interrupt_enter(); + _can_rx_isr(&drv_can2.device, CAN_RX_FIFO1); + rt_interrupt_leave(); +} + +/** + * @brief This function handles CAN2 SCE interrupts. + */ +void CAN2_SCE_IRQHandler(void) +{ + rt_uint32_t errtype; + CAN_HandleTypeDef *hcan; + + hcan = &drv_can2.CanHandle; + errtype = hcan->Instance->ESR; + + rt_interrupt_enter(); + HAL_CAN_IRQHandler(hcan); + + switch ((errtype & 0x70) >> 4) + { + case RT_CAN_BUS_BIT_PAD_ERR: + drv_can2.device.status.bitpaderrcnt++; + break; + case RT_CAN_BUS_FORMAT_ERR: + drv_can2.device.status.formaterrcnt++; + break; + case RT_CAN_BUS_ACK_ERR: + drv_can2.device.status.ackerrcnt++; + if (!READ_BIT(drv_can1.CanHandle.Instance->TSR, CAN_FLAG_TXOK0)) + rt_hw_can_isr(&drv_can2.device, RT_CAN_EVENT_TX_FAIL | 0 << 8); + else if (!READ_BIT(drv_can2.CanHandle.Instance->TSR, CAN_FLAG_TXOK0)) + rt_hw_can_isr(&drv_can2.device, RT_CAN_EVENT_TX_FAIL | 1 << 8); + else if (!READ_BIT(drv_can2.CanHandle.Instance->TSR, CAN_FLAG_TXOK0)) + rt_hw_can_isr(&drv_can2.device, RT_CAN_EVENT_TX_FAIL | 2 << 8); + break; + case RT_CAN_BUS_IMPLICIT_BIT_ERR: + case RT_CAN_BUS_EXPLICIT_BIT_ERR: + drv_can2.device.status.biterrcnt++; + break; + case RT_CAN_BUS_CRC_ERR: + drv_can2.device.status.crcerrcnt++; + break; + } + + drv_can2.device.status.lasterrtype = errtype & 0x70; + drv_can2.device.status.rcverrcnt = errtype >> 24; + drv_can2.device.status.snderrcnt = (errtype >> 16 & 0xFF); + drv_can2.device.status.errcode = errtype & 0x07; + hcan->Instance->MSR |= CAN_MSR_ERRI; + rt_interrupt_leave(); +} +#endif /* BSP_USING_CAN2 */ + +/** + * @brief Error CAN callback. + * @param hcan pointer to a CAN_HandleTypeDef structure that contains + * the configuration information for the specified CAN. + * @retval None + */ +void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan) +{ + __HAL_CAN_ENABLE_IT(hcan, CAN_IT_ERROR_WARNING | + CAN_IT_ERROR_PASSIVE | + CAN_IT_BUSOFF | + CAN_IT_LAST_ERROR_CODE | + CAN_IT_ERROR | + CAN_IT_RX_FIFO0_MSG_PENDING | + CAN_IT_RX_FIFO0_OVERRUN | + CAN_IT_RX_FIFO0_FULL | + CAN_IT_RX_FIFO1_MSG_PENDING | + CAN_IT_RX_FIFO1_OVERRUN | + CAN_IT_RX_FIFO1_FULL | + CAN_IT_TX_MAILBOX_EMPTY); +} + int rt_hw_can_init(void) { - struct stm32_drv_can *drv_can; struct can_configure config = CANDEFAULTCONFIG; - config.privmode = 0; + config.privmode = RT_CAN_MODE_NOPRIV; config.ticks = 50; - config.sndboxnumber = 3; - config.msgboxsz = 32; #ifdef RT_CAN_USING_HDR config.maxhdr = 14; - #ifdef CAN2 +#ifdef CAN2 config.maxhdr = 28; - #endif +#endif #endif /* config default filter */ CAN_FilterTypeDef filterConf = {0}; - filterConf.FilterBank = 0; - filterConf.FilterMode = CAN_FILTERMODE_IDMASK; - filterConf.FilterScale = CAN_FILTERSCALE_32BIT; filterConf.FilterIdHigh = 0x0000; filterConf.FilterIdLow = 0x0000; filterConf.FilterMaskIdHigh = 0x0000; filterConf.FilterMaskIdLow = 0x0000; filterConf.FilterFIFOAssignment = CAN_FILTER_FIFO0; + filterConf.FilterBank = 0; + filterConf.FilterMode = CAN_FILTERMODE_IDMASK; + filterConf.FilterScale = CAN_FILTERSCALE_32BIT; filterConf.FilterActivation = ENABLE; filterConf.SlaveStartFilterBank = 14; - + #ifdef BSP_USING_CAN1 filterConf.FilterBank = 0; + drv_can1.FilterConfig = filterConf; - drv_can = &drv_can1; - drv_can->CanHandle.Instance = CAN1; - dev_can1.ops = &drv_can_ops; - dev_can1.config = config; + drv_can1.device.config = config; /* register CAN1 device */ - rt_hw_can_register(&dev_can1, "can1", - &drv_can_ops, - drv_can); + rt_hw_can_register(&drv_can1.device, + drv_can1.name, + &_can_ops, + &drv_can1); #endif /* BSP_USING_CAN1 */ #ifdef BSP_USING_CAN2 filterConf.FilterBank = filterConf.SlaveStartFilterBank; + drv_can2.FilterConfig = filterConf; - drv_can = &drv_can2; - drv_can->CanHandle.Instance = CAN2; - dev_can2.ops = &drv_can_ops; - dev_can2.config = config; + drv_can2.device.config = config; /* register CAN2 device */ - rt_hw_can_register(&dev_can2, "can2", - &drv_can_ops, - drv_can); + rt_hw_can_register(&drv_can2.device, + drv_can2.name, + &_can_ops, + &drv_can2); #endif /* BSP_USING_CAN2 */ return 0; } + INIT_BOARD_EXPORT(rt_hw_can_init); -#endif /* RT_USING_CAN */ + +#endif /* BSP_USING_CAN */ + +/************************** end of file ******************/ diff --git a/bsp/stm32/libraries/HAL_Drivers/drv_can.h b/bsp/stm32/libraries/HAL_Drivers/drv_can.h index 736df7dec5..b0ae3072e6 100644 --- a/bsp/stm32/libraries/HAL_Drivers/drv_can.h +++ b/bsp/stm32/libraries/HAL_Drivers/drv_can.h @@ -11,40 +11,49 @@ * 2019-02-19 YLZ port to BSP [stm32] * 2019-06-17 YLZ modify struct stm32_drv_can. */ + #ifndef __DRV_CAN_H__ #define __DRV_CAN_H__ + +#ifdef __cplusplus +extern "C" { +#endif + #include #include -#include #include -#define BS1SHIFT 16 -#define BS2SHIFT 20 -#define RRESCLSHIFT 0 -#define SJWSHIFT 24 -#define BS1MASK ( (0x0F) << BS1SHIFT ) -#define BS2MASK ( (0x07) << BS2SHIFT ) -#define RRESCLMASK ( 0x3FF << RRESCLSHIFT ) -#define SJWMASK ( 0x3 << SJWSHIFT ) +#define BS1SHIFT 16 +#define BS2SHIFT 20 +#define RRESCLSHIFT 0 +#define SJWSHIFT 24 +#define BS1MASK ((0x0F) << BS1SHIFT ) +#define BS2MASK ((0x07) << BS2SHIFT ) +#define RRESCLMASK (0x3FF << RRESCLSHIFT ) +#define SJWMASK (0x3 << SJWSHIFT ) -struct stm_baud_rate_tab +struct stm32_baud_rate_tab { rt_uint32_t baud_rate; - rt_uint32_t confdata; + rt_uint32_t config_data; }; +#define BAUD_DATA(TYPE,NO) ((can_baud_rate_tab[NO].config_data & TYPE##MASK)) -/* STM32 can driver */ -struct stm32_drv_can +/* stm32 can device */ +struct stm32_can { + char *name; CAN_HandleTypeDef CanHandle; CAN_FilterTypeDef FilterConfig; + struct rt_can_device device; /* inherit from can device */ }; -#ifdef __cplusplus - extern "C" { -#endif int rt_hw_can_init(void); + #ifdef __cplusplus - } +} #endif + #endif /*__DRV_CAN_H__ */ + +/************************** end of file ******************/ diff --git a/bsp/stm32/libraries/STM32H7xx_HAL/SConscript b/bsp/stm32/libraries/STM32H7xx_HAL/SConscript index aacf24b3fe..f1548a3525 100644 --- a/bsp/stm32/libraries/STM32H7xx_HAL/SConscript +++ b/bsp/stm32/libraries/STM32H7xx_HAL/SConscript @@ -29,9 +29,9 @@ STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_gpio.c ''') if GetDepend(['RT_USING_SERIAL']): - src += ['STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart.c'] - src += ['STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_usart.c'] - src += ['STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart_ex.c'] + src += ['STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart.c'] + src += ['STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_usart.c'] + src += ['STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart_ex.c'] if GetDepend(['RT_USING_I2C']): src += ['STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_i2c.c'] @@ -49,7 +49,7 @@ if GetDepend(['RT_USING_USB_HOST']) or GetDepend(['RT_USING_USB_DEVICE']): src += ['STM32H7xx_HAL_Driver/Src/stm32h7xx_ll_usb.c'] if GetDepend(['RT_USING_CAN']): - src += ['STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_can.c'] + src += ['STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_fdcan.c'] if GetDepend(['RT_USING_HWTIMER']) or GetDepend(['RT_USING_PWM']): src += ['STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim.c'] diff --git a/components/drivers/can/can.c b/components/drivers/can/can.c index 0769c79fd7..48604993b9 100644 --- a/components/drivers/can/can.c +++ b/components/drivers/can/can.c @@ -27,10 +27,15 @@ static rt_err_t rt_can_init(struct rt_device *dev) /* initialize rx/tx */ can->can_rx = RT_NULL; can->can_tx = RT_NULL; +#ifdef RT_CAN_USING_HDR + can->hdr = RT_NULL; +#endif /* apply configuration */ if (can->ops->configure) result = can->ops->configure(can, &can->config); + else + result = -RT_ENOSYS; return result; } @@ -293,7 +298,7 @@ static rt_err_t rt_can_open(struct rt_device *dev, rt_uint16_t oflag) can->can_rx = rx_fifo; dev->open_flag |= RT_DEVICE_FLAG_INT_RX; - /* configure low level device */ + /* open can rx interrupt */ can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX); } } @@ -311,7 +316,7 @@ static rt_err_t rt_can_open(struct rt_device *dev, rt_uint16_t oflag) tx_fifo->buffer = (struct rt_can_sndbxinx_list *)(tx_fifo + 1); rt_memset(tx_fifo->buffer, 0, - can->config.sndboxnumber * sizeof(struct rt_can_sndbxinx_list)); + can->config.sndboxnumber * sizeof(struct rt_can_sndbxinx_list)); rt_list_init(&tx_fifo->freelist); for (i = 0; i < can->config.sndboxnumber; i++) { @@ -325,7 +330,7 @@ static rt_err_t rt_can_open(struct rt_device *dev, rt_uint16_t oflag) can->can_tx = tx_fifo; dev->open_flag |= RT_DEVICE_FLAG_INT_TX; - /* configure low level device */ + /* open can tx interrupt */ can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX); } } @@ -406,7 +411,7 @@ static rt_err_t rt_can_close(struct rt_device *dev) rt_free(rx_fifo); dev->open_flag &= ~RT_DEVICE_FLAG_INT_RX; can->can_rx = RT_NULL; - /* configure low level device */ + /* clear can rx interrupt */ can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX); } @@ -420,7 +425,7 @@ static rt_err_t rt_can_close(struct rt_device *dev) rt_free(tx_fifo); dev->open_flag &= ~RT_DEVICE_FLAG_INT_TX; can->can_tx = RT_NULL; - /* configure low level device */ + /* clear can tx interrupt */ can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_TX); } @@ -484,6 +489,7 @@ static rt_err_t rt_can_control(struct rt_device *dev, struct rt_can_device *can; rt_err_t res; + res = RT_EOK; RT_ASSERT(dev != RT_NULL); can = (struct rt_can_device *)dev; @@ -501,8 +507,9 @@ static rt_err_t rt_can_control(struct rt_device *dev, case RT_DEVICE_CTRL_CONFIG: /* configure device */ - can->ops->configure(can, (struct can_configure *)args); + res = can->ops->configure(can, (struct can_configure *)args); break; + case RT_CAN_CMD_SET_PRIV: /* configure device */ if ((rt_uint32_t)args != can->config.privmode) @@ -513,7 +520,6 @@ static rt_err_t rt_can_control(struct rt_device *dev, res = can->ops->control(can, cmd, args); if (res != RT_EOK) return res; - tx_fifo = (struct rt_can_tx_fifo *) can->can_tx; if (can->config.privmode) { @@ -522,11 +528,11 @@ static rt_err_t rt_can_control(struct rt_device *dev, level = rt_hw_interrupt_disable(); if(rt_list_isempty(&tx_fifo->buffer[i].list)) { - rt_sem_release(&(tx_fifo->sem)); + rt_sem_release(&(tx_fifo->sem)); } else { - rt_list_remove(&tx_fifo->buffer[i].list); + rt_list_remove(&tx_fifo->buffer[i].list); } rt_hw_interrupt_enable(level); } @@ -544,7 +550,6 @@ static rt_err_t rt_can_control(struct rt_device *dev, rt_hw_interrupt_enable(level); } } - return RT_EOK; } break; @@ -561,74 +566,73 @@ static rt_err_t rt_can_control(struct rt_device *dev, return res; } + struct rt_can_filter_config *pfilter; + struct rt_can_filter_item *pitem; + rt_uint32_t count; + rt_base_t level; + + pfilter = (struct rt_can_filter_config *)args; + RT_ASSERT(pfilter); + count = pfilter->count; + pitem = pfilter->items; + if (pfilter->actived) { - struct rt_can_filter_config *pfilter; - struct rt_can_filter_item *pitem; - rt_uint32_t count; - rt_base_t level; - - pfilter = (struct rt_can_filter_config *)args; - count = pfilter->count; - pitem = pfilter->items; - if (pfilter->actived) + while (count) { - while (count) + if (pitem->hdr >= can->config.maxhdr || pitem->hdr < 0) { - if (pitem->hdr >= can->config.maxhdr || pitem->hdr < 0) - { - count--; - pitem++; - continue; - } + count--; + pitem++; + continue; + } + level = rt_hw_interrupt_disable(); + if (!can->hdr[pitem->hdr].connected) + { + rt_hw_interrupt_enable(level); + rt_memcpy(&can->hdr[pitem->hdr].filter, pitem, + sizeof(struct rt_can_filter_item)); level = rt_hw_interrupt_disable(); - if (!can->hdr[pitem->hdr].connected) + can->hdr[pitem->hdr].connected = 1; + can->hdr[pitem->hdr].msgs = 0; + rt_list_init(&can->hdr[pitem->hdr].list); + } + rt_hw_interrupt_enable(level); + + count--; + pitem++; + } + } + else + { + while (count) + { + if (pitem->hdr >= can->config.maxhdr || pitem->hdr < 0) + { + count--; + pitem++; + continue; + } + level = rt_hw_interrupt_disable(); + + if (can->hdr[pitem->hdr].connected) + { + can->hdr[pitem->hdr].connected = 0; + can->hdr[pitem->hdr].msgs = 0; + if (!rt_list_isempty(&can->hdr[pitem->hdr].list)) { - rt_hw_interrupt_enable(level); - rt_memcpy(&can->hdr[pitem->hdr].filter, pitem, - sizeof(struct rt_can_filter_item)); - level = rt_hw_interrupt_disable(); - can->hdr[pitem->hdr].connected = 1; - can->hdr[pitem->hdr].msgs = 0; - rt_list_init(&can->hdr[pitem->hdr].list); + rt_list_remove(can->hdr[pitem->hdr].list.next); } rt_hw_interrupt_enable(level); - - count--; - pitem++; + rt_memset(&can->hdr[pitem->hdr].filter, 0, + sizeof(struct rt_can_filter_item)); } - } - else - { - while (count) + else { - if (pitem->hdr >= can->config.maxhdr || pitem->hdr < 0) - { - count--; - pitem++; - continue; - } - level = rt_hw_interrupt_disable(); - - if (can->hdr[pitem->hdr].connected) - { - can->hdr[pitem->hdr].connected = 0; - can->hdr[pitem->hdr].msgs = 0; - if (!rt_list_isempty(&can->hdr[pitem->hdr].list)) - { - rt_list_remove(can->hdr[pitem->hdr].list.next); - } - rt_hw_interrupt_enable(level); - rt_memset(&can->hdr[pitem->hdr].filter, 0, - sizeof(struct rt_can_filter_item)); - } - else - { - rt_hw_interrupt_enable(level); - } - count--; - pitem++; + rt_hw_interrupt_enable(level); } + count--; + pitem++; } } break; @@ -642,12 +646,16 @@ static rt_err_t rt_can_control(struct rt_device *dev, /* control device */ if (can->ops->control != RT_NULL) { - can->ops->control(can, cmd, args); + res = can->ops->control(can, cmd, args); + } + else + { + res = -RT_ENOSYS; } break; } - return RT_EOK; + return res; } /* @@ -655,8 +663,10 @@ static rt_err_t rt_can_control(struct rt_device *dev, */ static void cantimeout(void *arg) { - rt_can_t can = (rt_can_t)arg; + rt_can_t can; + can = (rt_can_t)arg; + RT_ASSERT(can); rt_device_control((rt_device_t)can, RT_CAN_CMD_GET_STATUS, (void *)&can->status); if (can->status_indicate.ind != RT_NULL) @@ -690,7 +700,7 @@ const static struct rt_device_ops can_device_ops = /* * can register */ -rt_err_t rt_hw_can_register(struct rt_can_device *can, +rt_err_t rt_hw_can_register(struct rt_can_device *can, const char *name, const struct rt_can_ops *ops, void *data) diff --git a/components/drivers/include/drivers/can.h b/components/drivers/include/drivers/can.h index c61fb19eaa..d4fcc845b4 100644 --- a/components/drivers/include/drivers/can.h +++ b/components/drivers/include/drivers/can.h @@ -221,7 +221,7 @@ struct rt_can_msg rt_uint32_t rsv : 1; rt_uint32_t len : 8; rt_uint32_t priv : 8; - rt_uint32_t hdr : 8; + rt_int32_t hdr : 8; rt_uint32_t reserved : 8; rt_uint8_t data[8]; }; @@ -252,7 +252,7 @@ struct rt_can_rx_fifo #define RT_CAN_EVENT_RX_IND 0x01 /* Rx indication */ #define RT_CAN_EVENT_TX_DONE 0x02 /* Tx complete */ -#define RT_CAN_EVENT_TX_FAIL 0x03 /* Tx complete */ +#define RT_CAN_EVENT_TX_FAIL 0x03 /* Tx fail */ #define RT_CAN_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */ #define RT_CAN_EVENT_RXOF_IND 0x06 /* Rx overflow */ @@ -278,7 +278,7 @@ struct rt_can_ops int (*recvmsg)(struct rt_can_device *can, void *buf, rt_uint32_t boxno); }; -rt_err_t rt_hw_can_register(struct rt_can_device *can, +rt_err_t rt_hw_can_register(struct rt_can_device *can, const char *name, const struct rt_can_ops *ops, void *data); diff --git a/components/finsh/cmd.c b/components/finsh/cmd.c index 608e962f6c..570f525bca 100644 --- a/components/finsh/cmd.c +++ b/components/finsh/cmd.c @@ -847,7 +847,7 @@ long list_device(void) device->parent.name, (device->type <= RT_Device_Class_Unknown) ? device_type_str[device->type] : - device_type_str[RT_Device_Class_Unknown], + device_type_str[RT_Device_Class_Unknown - 1], device->ref_count); }