diff --git a/bsp/renesas/libraries/HAL_Drivers/drivers/drv_can.c b/bsp/renesas/libraries/HAL_Drivers/drivers/drv_can.c index fdf0ae24240..15d541dac92 100644 --- a/bsp/renesas/libraries/HAL_Drivers/drivers/drv_can.c +++ b/bsp/renesas/libraries/HAL_Drivers/drivers/drv_can.c @@ -11,6 +11,11 @@ #include "drv_can.h" +#if defined(BSP_USING_CANFD) && defined(BSP_FEATURE_CANFD_HAS_CLOCK) && \ + BSP_FEATURE_CANFD_HAS_CLOCK +#define RA_CAN_USING_DYNAMIC_CANFD_TIMING +#endif + static struct ra_can_config can_config[] = { #ifdef BSP_USING_CAN0 @@ -35,6 +40,7 @@ enum static struct ra_can can_obj[sizeof(can_config) / sizeof(can_config[0])] = {0}; +#ifndef RA_CAN_USING_DYNAMIC_CANFD_TIMING static const struct ra_baud_rate_tab can_baud_rate_tab[] = { {CAN1MBaud, 3, 6, 3, 1 + 4}, @@ -47,6 +53,7 @@ static const struct ra_baud_rate_tab can_baud_rate_tab[] = {CAN20kBaud, 4, 14, 5, 1 + 124}, {CAN10kBaud, 4, 14, 5, 1 + 249} }; +#endif #if defined(BSP_USING_CANFD) @@ -57,10 +64,12 @@ static const struct ra_baud_rate_tab can_baud_rate_tab[] = #define R_CAN_ModeTransition R_CANFD_ModeTransition #define R_CAN_InfoGet R_CANFD_InfoGet #define R_CAN_Write R_CANFD_Write +#define R_CAN_Close R_CANFD_Close #define can0_callback canfd0_callback #define can1_callback canfd1_callback +#ifdef BSP_USING_CAN0 const canfd_afl_entry_t p_canfd0_afl[CANFD_CFG_AFL_CH0_RULE_NUM] = { { @@ -78,7 +87,9 @@ const canfd_afl_entry_t p_canfd0_afl[CANFD_CFG_AFL_CH0_RULE_NUM] = } }, }; +#endif +#ifdef BSP_USING_CAN1 const canfd_afl_entry_t p_canfd1_afl[CANFD_CFG_AFL_CH1_RULE_NUM] = { { @@ -92,13 +103,19 @@ const canfd_afl_entry_t p_canfd1_afl[CANFD_CFG_AFL_CH1_RULE_NUM] = { .minimum_dlc = CANFD_MINIMUM_DLC_1, .rx_buffer = CANFD_RX_MB_NONE, +#if defined(BSP_FEATURE_CANFD_NUM_INSTANCES) && BSP_FEATURE_CANFD_NUM_INSTANCES > 1 + .fifo_select_flags = CANFD_RX_FIFO_0 +#else .fifo_select_flags = CANFD_RX_FIFO_1 +#endif } }, }; +#endif #endif +#ifndef RA_CAN_USING_DYNAMIC_CANFD_TIMING static rt_uint32_t get_can_baud_index(rt_uint32_t baud) { rt_uint32_t len, index; @@ -112,6 +129,167 @@ static rt_uint32_t get_can_baud_index(rt_uint32_t baud) return 0; /* default baud is CAN1MBaud */ } +#endif + +#ifdef RA_CAN_USING_DYNAMIC_CANFD_TIMING +static rt_uint32_t ra_canfd_clock_divisor_get(void) +{ +#if BSP_CFG_CANFDCLK_DIV == BSP_CLOCKS_CANFD_CLOCK_DIV_1 + return 1; +#elif BSP_CFG_CANFDCLK_DIV == BSP_CLOCKS_CANFD_CLOCK_DIV_2 + return 2; +#elif defined(BSP_CLOCKS_CANFD_CLOCK_DIV_3) && \ + BSP_CFG_CANFDCLK_DIV == BSP_CLOCKS_CANFD_CLOCK_DIV_3 + return 3; +#elif BSP_CFG_CANFDCLK_DIV == BSP_CLOCKS_CANFD_CLOCK_DIV_4 + return 4; +#elif defined(BSP_CLOCKS_CANFD_CLOCK_DIV_5) && \ + BSP_CFG_CANFDCLK_DIV == BSP_CLOCKS_CANFD_CLOCK_DIV_5 + return 5; +#elif BSP_CFG_CANFDCLK_DIV == BSP_CLOCKS_CANFD_CLOCK_DIV_6 + return 6; +#elif BSP_CFG_CANFDCLK_DIV == BSP_CLOCKS_CANFD_CLOCK_DIV_8 + return 8; +#elif defined(BSP_CLOCKS_CANFD_CLOCK_DIV_10) && \ + BSP_CFG_CANFDCLK_DIV == BSP_CLOCKS_CANFD_CLOCK_DIV_10 + return 10; +#elif defined(BSP_CLOCKS_CANFD_CLOCK_DIV_16) && \ + BSP_CFG_CANFDCLK_DIV == BSP_CLOCKS_CANFD_CLOCK_DIV_16 + return 16; +#elif defined(BSP_CLOCKS_CANFD_CLOCK_DIV_32) && \ + BSP_CFG_CANFDCLK_DIV == BSP_CLOCKS_CANFD_CLOCK_DIV_32 + return 32; +#else + return 0; +#endif +} + +static rt_uint32_t ra_canfd_clock_hz_get(void) +{ + rt_uint32_t source_clock; + + source_clock = R_BSP_SourceClockHzGet((fsp_priv_source_clock_t)BSP_CFG_CANFDCLK_SOURCE); +#if BSP_CFG_CANFDCLK_SOURCE == BSP_CLOCKS_SOURCE_CLOCK_MAIN_OSC + return source_clock; +#else + rt_uint32_t divisor = ra_canfd_clock_divisor_get(); + + return divisor == 0 ? 0 : source_clock / divisor; +#endif +} + +static rt_err_t ra_canfd_timing_calculate(can_bit_timing_cfg_t *timing, + rt_uint32_t clock_hz, + rt_uint32_t baud, + rt_bool_t data_phase) +{ + rt_uint32_t max_prescaler = data_phase ? 256 : 1024; + rt_uint32_t max_time_segment_1 = data_phase ? 32 : 256; + rt_uint32_t max_time_segment_2 = data_phase ? 16 : 128; + rt_uint32_t prescaler; + + if (timing == RT_NULL || clock_hz == 0 || baud == 0) + { + return -RT_EINVAL; + } + + for (prescaler = 1; prescaler <= max_prescaler; prescaler++) + { + rt_uint32_t denominator = baud * prescaler; + rt_uint32_t total_tq; + rt_uint32_t sample_tq; + rt_uint32_t time_segment_1; + rt_uint32_t time_segment_2; + + if (denominator == 0 || clock_hz % denominator != 0) + { + continue; + } + + total_tq = clock_hz / denominator; + if (total_tq < 8 || + total_tq > max_time_segment_1 + max_time_segment_2 + 1) + { + continue; + } + + sample_tq = (total_tq * 3) / 4; + time_segment_1 = sample_tq - 1; + time_segment_2 = total_tq - sample_tq; + if (time_segment_1 > max_time_segment_1 || + time_segment_2 > max_time_segment_2 || + time_segment_1 <= time_segment_2 || time_segment_2 == 0) + { + continue; + } + + timing->baud_rate_prescaler = prescaler; + timing->time_segment_1 = time_segment_1; + timing->time_segment_2 = time_segment_2; + timing->synchronization_jump_width = time_segment_2 < 4 ? time_segment_2 : 4; + return RT_EOK; + } + + return -RT_EINVAL; +} +#endif + +static rt_err_t ra_can_apply_baud(struct ra_can *can, rt_uint32_t baud) +{ + can_bit_timing_cfg_t *timing = can->config->p_cfg->p_bit_timing; + +#ifdef RA_CAN_USING_DYNAMIC_CANFD_TIMING + rt_uint32_t clock_hz = ra_canfd_clock_hz_get(); + + return ra_canfd_timing_calculate(timing, clock_hz, baud, RT_FALSE); +#else + rt_uint32_t index = get_can_baud_index(baud); + + timing->baud_rate_prescaler = can_baud_rate_tab[index].prescaler; + timing->synchronization_jump_width = can_baud_rate_tab[index].sjw; + timing->time_segment_1 = can_baud_rate_tab[index].ts1; + timing->time_segment_2 = can_baud_rate_tab[index].ts2; + return RT_EOK; +#endif +} + +static void ra_can_irq_control(IRQn_Type irq, rt_bool_t enable) +{ + if (irq < 0) + { + return; + } + + if (enable) + { + R_BSP_IrqEnable(irq); + } + else + { + R_BSP_IrqDisable(irq); + R_BSP_IrqStatusClear(irq); + } +} + +#if defined(BSP_USING_CANFD) && defined(VECTOR_NUMBER_CAN_RXF) +static rt_bool_t ra_can_other_rx_irq_enabled(struct ra_can *can) +{ + rt_size_t index; + + for (index = 0; index < sizeof(can_obj) / sizeof(can_obj[0]); index++) + { + struct rt_can_device *can_dev = &can_obj[index].can_dev; + + if (&can_obj[index] != can && can_dev->can_rx != RT_NULL && + (can_dev->parent.open_flag & RT_DEVICE_FLAG_INT_RX)) + { + return RT_TRUE; + } + } + + return RT_FALSE; +} +#endif static void ra_can_get_config(void) { @@ -132,6 +310,7 @@ static void ra_can_get_config(void) rt_err_t ra_can_configure(struct rt_can_device *can_dev, struct can_configure *cfg) { struct ra_can *can; + rt_err_t result; RT_ASSERT(can_dev != RT_NULL); RT_ASSERT(cfg != RT_NULL); @@ -140,11 +319,48 @@ rt_err_t ra_can_configure(struct rt_can_device *can_dev, struct can_configure *c can = rt_container_of(can_dev, struct ra_can, can_dev); RT_ASSERT(can != RT_NULL); + result = ra_can_apply_baud(can, cfg->baud_rate); + if (result != RT_EOK) + { + return result; + } + +#if defined(RA_CAN_USING_DYNAMIC_CANFD_TIMING) && defined(BSP_USING_CANFD) + if (cfg->enable_canfd) + { + canfd_extended_cfg_t *extend = (canfd_extended_cfg_t *)can->config->p_cfg->p_extend; + + if (extend == RT_NULL || extend->p_data_timing == RT_NULL) + { + return -RT_EINVAL; + } + + result = ra_canfd_timing_calculate(extend->p_data_timing, + ra_canfd_clock_hz_get(), + cfg->baud_rate_fd, + RT_TRUE); + if (result != RT_EOK) + { + return result; + } + } +#endif + + if (((can_instance_ctrl_t *)can->config->p_api_ctrl)->open != 0) + { + err = R_CAN_Close(can->config->p_api_ctrl); + if (FSP_SUCCESS != err) + { + return -RT_ERROR; + } + } + err = R_CAN_Open(can->config->p_api_ctrl, can->config->p_cfg); if (FSP_SUCCESS != err) { return -RT_ERROR; } + can_dev->config = *cfg; return RT_EOK; } rt_err_t ra_can_control(struct rt_can_device *can_dev, int cmd, void *arg) @@ -156,8 +372,31 @@ rt_err_t ra_can_control(struct rt_can_device *can_dev, int cmd, void *arg) can = rt_container_of(can_dev, struct ra_can, can_dev); switch (cmd) { + case RT_DEVICE_CTRL_SET_INT: case RT_DEVICE_CTRL_CLR_INT: - R_BSP_IrqStatusClear((IRQn_Type)arg); + argval = (rt_uint32_t)(rt_ubase_t)arg; + if (argval == RT_DEVICE_FLAG_INT_RX) + { + ra_can_irq_control(can->config->p_cfg->rx_irq, cmd == RT_DEVICE_CTRL_SET_INT); +#if defined(BSP_USING_CANFD) && defined(VECTOR_NUMBER_CAN_RXF) + if (cmd == RT_DEVICE_CTRL_SET_INT || !ra_can_other_rx_irq_enabled(can)) + { + ra_can_irq_control(VECTOR_NUMBER_CAN_RXF, cmd == RT_DEVICE_CTRL_SET_INT); + } +#endif + } + else if (argval == RT_DEVICE_FLAG_INT_TX) + { + ra_can_irq_control(can->config->p_cfg->tx_irq, cmd == RT_DEVICE_CTRL_SET_INT); + } + else if (argval == RT_DEVICE_CAN_INT_ERR) + { + ra_can_irq_control(can->config->p_cfg->error_irq, cmd == RT_DEVICE_CTRL_SET_INT); + } + else + { + return -RT_EINVAL; + } break; case RT_CAN_CMD_SET_BAUD: argval = (rt_uint32_t) arg; @@ -175,13 +414,10 @@ rt_err_t ra_can_control(struct rt_can_device *can_dev, int cmd, void *arg) } if (argval != can->can_dev.config.baud_rate) { - can->can_dev.config.baud_rate = argval; - uint32_t index = get_can_baud_index(argval); - can->config->p_cfg->p_bit_timing->baud_rate_prescaler = can_baud_rate_tab[index].prescaler; - can->config->p_cfg->p_bit_timing->synchronization_jump_width = can_baud_rate_tab[index].sjw; - can->config->p_cfg->p_bit_timing->time_segment_1 = can_baud_rate_tab[index].ts1; - can->config->p_cfg->p_bit_timing->time_segment_2 = can_baud_rate_tab[index].ts2; - return ra_can_configure(&can->can_dev, &can->can_dev.config); + struct can_configure config = can->can_dev.config; + + config.baud_rate = argval; + return ra_can_configure(&can->can_dev, &config); } break; case RT_CAN_CMD_SET_MODE: @@ -195,21 +431,35 @@ rt_err_t ra_can_control(struct rt_can_device *can_dev, int cmd, void *arg) if (argval != can->can_dev.config.mode) { can_test_mode_t mode_to_set; - can->can_dev.config.mode = argval; + switch (argval) { case RT_CAN_MODE_NORMAL: mode_to_set = CAN_TEST_MODE_DISABLED; + break; case RT_CAN_MODE_LISTEN: mode_to_set = CAN_TEST_MODE_LISTEN; + break; case RT_CAN_MODE_LOOPBACK: mode_to_set = CAN_TEST_MODE_LOOPBACK_INTERNAL; + break; + default: + return -RT_EINVAL; + } + if (R_CAN_ModeTransition(can->config->p_api_ctrl, + ((can_instance_ctrl_t *)can->config->p_api_ctrl)->operation_mode, + mode_to_set) != FSP_SUCCESS) + { + return -RT_ERROR; } - R_CAN_ModeTransition(can->config->p_api_ctrl, ((can_instance_ctrl_t *)(can->config->p_api_ctrl))->operation_mode, mode_to_set); + can->can_dev.config.mode = argval; } break; case RT_CAN_CMD_GET_STATUS: - R_CAN_InfoGet(can->config->p_api_ctrl, &can_info); + if (R_CAN_InfoGet(can->config->p_api_ctrl, &can_info) != FSP_SUCCESS) + { + return -RT_ERROR; + } can->can_dev.status.rcverrcnt = can_info.error_count_receive; can->can_dev.status.snderrcnt = can_info.error_count_transmit; can->can_dev.status.errcode = can_info.error_code; @@ -220,32 +470,105 @@ rt_err_t ra_can_control(struct rt_can_device *can_dev, int cmd, void *arg) } return RT_EOK; } + +#if defined(BSP_USING_CANFD) +static rt_err_t ra_can_dlc_to_length(rt_uint8_t dlc, rt_uint8_t *length) +{ + static const rt_uint8_t dlc_to_length[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64 + }; + + if (dlc >= sizeof(dlc_to_length)) + { + return -RT_EINVAL; + } + + *length = dlc_to_length[dlc]; + return RT_EOK; +} + +static rt_err_t ra_can_length_to_dlc(rt_uint8_t length, rt_uint8_t *dlc) +{ + static const rt_uint8_t dlc_to_length[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64 + }; + rt_uint8_t index; + + for (index = 0; index < sizeof(dlc_to_length); index++) + { + if (dlc_to_length[index] == length) + { + *dlc = index; + return RT_EOK; + } + } + + return -RT_EINVAL; +} +#endif + rt_ssize_t ra_can_sendmsg(struct rt_can_device *can_dev, const void *buf, rt_uint32_t boxno) { struct ra_can *can; can_frame_t g_can_tx_frame; struct rt_can_msg *msg_rt = (struct rt_can_msg *)buf; + rt_uint8_t payload_length; RT_ASSERT(can_dev != RT_NULL); RT_ASSERT(buf != RT_NULL); + rt_memset(&g_can_tx_frame, 0, sizeof(g_can_tx_frame)); g_can_tx_frame.id = msg_rt->id; g_can_tx_frame.id_mode = msg_rt->ide; g_can_tx_frame.type = msg_rt->rtr; +#if defined(BSP_USING_CANFD) +#ifdef BSP_USING_CANFD + if ((!msg_rt->fd_frame && (msg_rt->len > 8 || msg_rt->brs)) || + (msg_rt->fd_frame && msg_rt->rtr)) + { + return -RT_EINVAL; + } +#else + if (msg_rt->len > 8) + { + return -RT_EINVAL; + } +#endif + if (ra_can_dlc_to_length(msg_rt->len, &payload_length) != RT_EOK) + { + return -RT_EINVAL; + } + g_can_tx_frame.data_length_code = payload_length; +#else + if (msg_rt->len > 8) + { + return -RT_EINVAL; + } + payload_length = msg_rt->len; g_can_tx_frame.data_length_code = msg_rt->len; -#if defined(BSP_USING_CANFD) && (defined(BSP_USING_CAN_RZ) || defined(BSP_USING_CAN_RA)) +#endif +#if defined(BSP_USING_CANFD) g_can_tx_frame.options = 0; -#elif defined(BSP_USING_CANFD) - g_can_tx_frame.options = CANFD_FRAME_OPTION_FD | CANFD_FRAME_OPTION_BRS; +#ifdef BSP_USING_CANFD + if (msg_rt->fd_frame) + { + g_can_tx_frame.options |= CANFD_FRAME_OPTION_FD; + if (msg_rt->brs) + { + g_can_tx_frame.options |= CANFD_FRAME_OPTION_BRS; + } + } +#endif #else g_can_tx_frame.options = 0; #endif - memcpy(g_can_tx_frame.data, msg_rt->data, 8); + memcpy(g_can_tx_frame.data, msg_rt->data, payload_length); can = rt_container_of(can_dev, struct ra_can, can_dev); RT_ASSERT(boxno < can->config->num_of_mailboxs); if (R_CAN_Write(can->config->p_api_ctrl, boxno, &g_can_tx_frame) != FSP_SUCCESS) { - rt_exit_critical(); return -RT_ERROR; } return RT_EOK; @@ -256,6 +579,8 @@ rt_ssize_t ra_can_recvmsg(struct rt_can_device *can_dev, void *buf, rt_uint32_t struct rt_can_msg *msg_rt = (struct rt_can_msg *)buf; can_frame_t *msg_ra; struct ra_can *can; + rt_uint8_t dlc; + rt_uint8_t payload_length; RT_ASSERT(can_dev != RT_NULL); RT_ASSERT(buf != RT_NULL); @@ -265,15 +590,37 @@ rt_ssize_t ra_can_recvmsg(struct rt_can_device *can_dev, void *buf, rt_uint32_t return 0; msg_ra = &can->callback_args->frame; + payload_length = msg_ra->data_length_code; + if (payload_length > sizeof(msg_rt->data)) + { + return -RT_EINVAL; + } + rt_memset(msg_rt, 0, sizeof(*msg_rt)); msg_rt->id = msg_ra->id; msg_rt->ide = msg_ra->id_mode; msg_rt->rtr = msg_ra->type; msg_rt->rsv = RT_NULL; - msg_rt->len = msg_ra->data_length_code; +#if defined(BSP_USING_CANFD) + if (ra_can_length_to_dlc(payload_length, &dlc) != RT_EOK) + { + return -RT_ERROR; + } + msg_rt->len = dlc; +#else + msg_rt->len = payload_length; +#endif msg_rt->priv = boxno; - msg_rt->hdr_index = RT_NULL; - memcpy(msg_rt->data, msg_ra->data, msg_ra->data_length_code); + msg_rt->hdr_index = -1; +#if defined(BSP_USING_CANFD) + msg_rt->fd_frame = (msg_ra->options & CANFD_FRAME_OPTION_FD) != 0; + msg_rt->brs = (msg_ra->options & CANFD_FRAME_OPTION_BRS) != 0; + if (boxno >= 32) + { + msg_rt->rxfifo = boxno - 32; + } +#endif + memcpy(msg_rt->data, msg_ra->data, payload_length); return sizeof(struct rt_can_msg); } const struct rt_can_ops ra_can_ops = @@ -294,9 +641,12 @@ void can0_callback(can_callback_args_t *p_args) rt_hw_can_isr(&can_obj[CAN0_INDEX].can_dev, RT_CAN_EVENT_TX_DONE | p_args->mailbox << 8); break; case CAN_EVENT_RX_COMPLETE: - can_obj[CAN0_INDEX].callback_args = p_args; - if (p_args->event == CAN_EVENT_RX_COMPLETE) + if (can_obj[CAN0_INDEX].can_dev.can_rx != RT_NULL && + (can_obj[CAN0_INDEX].can_dev.parent.open_flag & RT_DEVICE_FLAG_INT_RX)) + { + can_obj[CAN0_INDEX].callback_args = p_args; rt_hw_can_isr(&can_obj[CAN0_INDEX].can_dev, RT_CAN_EVENT_RX_IND | p_args->mailbox << 8); + } break; case CAN_EVENT_TX_ABORTED: rt_hw_can_isr(&can_obj[CAN0_INDEX].can_dev, RT_CAN_EVENT_TX_FAIL | p_args->mailbox << 8); @@ -313,6 +663,8 @@ void can0_callback(can_callback_args_t *p_args) { break; } + default: + break; } rt_interrupt_leave(); } @@ -328,9 +680,12 @@ void can1_callback(can_callback_args_t *p_args) rt_hw_can_isr(&can_obj[CAN1_INDEX].can_dev, RT_CAN_EVENT_TX_DONE | p_args->mailbox << 8); break; case CAN_EVENT_RX_COMPLETE: - can_obj[CAN1_INDEX].callback_args = p_args; - if (p_args->event == CAN_EVENT_RX_COMPLETE) + if (can_obj[CAN1_INDEX].can_dev.can_rx != RT_NULL && + (can_obj[CAN1_INDEX].can_dev.parent.open_flag & RT_DEVICE_FLAG_INT_RX)) + { + can_obj[CAN1_INDEX].callback_args = p_args; rt_hw_can_isr(&can_obj[CAN1_INDEX].can_dev, RT_CAN_EVENT_RX_IND | p_args->mailbox << 8); + } break; case CAN_EVENT_TX_ABORTED: rt_hw_can_isr(&can_obj[CAN1_INDEX].can_dev, RT_CAN_EVENT_TX_FAIL | p_args->mailbox << 8); @@ -346,6 +701,8 @@ void can1_callback(can_callback_args_t *p_args) { break; } + default: + break; } rt_interrupt_leave(); }