/** * @file CANFD.cpp * @brief CANFD 通信模块实现。 */ #include "main.h" #include "device/canfd.h" #include "sys/config.h" namespace { constexpr uint32_t kSlpGpio = GPIOA; constexpr uint32_t kSlpPin = GPIO_PIN_8; struct CanFdTxBuffer { can_trasnmit_message_struct tx_message; uint8_t payload[64]; uint8_t valid; }; CanFdTxBuffer s_txBuffer; } // namespace CanFd::Diag CanFd::s_diag; CanFd::RxFrame CanFd::s_rxFrame; void CanFd::initGpio() { rcu_periph_clock_enable(CONFIG_CAN_RCU); rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_AF); gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_11); gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12); gpio_init(kSlpGpio, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, kSlpPin); } void CanFd::filterAcceptAll() { can_filter_parameter_struct can_filter{}; can_filter.filter_number = 0U; can_filter.filter_mode = CAN_FILTERMODE_MASK; can_filter.filter_bits = CAN_FILTERBITS_32BIT; can_filter.filter_list_high = 0x0000U; can_filter.filter_list_low = 0x0000U; can_filter.filter_mask_high = 0x0000U; can_filter.filter_mask_low = 0x0000U; can_filter.filter_fifo_number = CAN_FIFO0; can_filter.filter_enable = ENABLE; can_filter_init(CONFIG_CAN_INSTANCE, &can_filter); } void CanFd::initNominalTiming() { can_parameter_struct can_parameter{}; can_struct_para_init(CAN_INIT_STRUCT, &can_parameter); can_parameter.time_triggered = DISABLE; can_parameter.auto_bus_off_recovery = ENABLE; can_parameter.auto_wake_up = DISABLE; can_parameter.auto_retrans = ENABLE; can_parameter.rec_fifo_overwrite = ENABLE; can_parameter.trans_fifo_order = ENABLE; can_parameter.working_mode = CAN_NORMAL_MODE; can_parameter.resync_jump_width = CAN_BT_SJW_1TQ; can_parameter.time_segment_1 = CAN_BT_BS1_7TQ; can_parameter.time_segment_2 = CAN_BT_BS2_2TQ; can_parameter.prescaler = 6U; can_init(CONFIG_CAN_INSTANCE, &can_parameter); } void CanFd::initFdMode() { #ifdef GD32E508 can_fdframe_struct can_fd_parameter{}; can_fd_tdc_struct can_fd_tdc_parameter{}; can_struct_para_init(CAN_FD_FRAME_STRUCT, &can_fd_parameter); can_fd_parameter.fd_frame = ENABLE; can_fd_parameter.excp_event_detect = ENABLE; can_fd_parameter.delay_compensation = ENABLE; can_fd_tdc_parameter.tdc_filter = 0x04U; can_fd_tdc_parameter.tdc_mode = CAN_TDCMOD_CALC_AND_OFFSET; can_fd_tdc_parameter.tdc_offset = 0x04U; can_fd_parameter.p_delay_compensation = &can_fd_tdc_parameter; can_fd_parameter.iso_bosch = CAN_FDMOD_ISO; can_fd_parameter.esi_mode = CAN_ESIMOD_HARDWARE; can_fd_parameter.data_prescaler = 6U; can_fd_parameter.data_resync_jump_width = CAN_BT_SJW_1TQ; can_fd_parameter.data_time_segment_1 = CAN_BT_BS1_3TQ; can_fd_parameter.data_time_segment_2 = CAN_BT_BS2_1TQ; can_fd_init(CONFIG_CAN_INSTANCE, &can_fd_parameter); #else can_fd_function_enable(CONFIG_CAN_INSTANCE); #endif } void CanFd::buildStatusFrame(const StatusPayload *status) { const int16_t temp_x100 = static_cast(status->temperature * 100.0f); const uint16_t vdda_x1000 = static_cast(status->vdda * 1000.0f); can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &s_txBuffer.tx_message); s_txBuffer.tx_message.tx_sfid = CONFIG_CAN_STATUS_ID; s_txBuffer.tx_message.tx_efid = 0U; s_txBuffer.tx_message.tx_ff = CAN_FF_STANDARD; s_txBuffer.tx_message.tx_ft = CAN_FT_DATA; s_txBuffer.tx_message.tx_dlen = CANFD_STATUS_DLEN; #ifdef GD32E508 s_txBuffer.tx_message.fd_flag = ENABLE; s_txBuffer.tx_message.fd_brs = ENABLE; s_txBuffer.tx_message.fd_esi = CAN_ESI_DOMINANT; #endif auto &p = s_txBuffer.payload; p[0] = static_cast(status->temp_raw & 0xFFU); p[1] = static_cast((status->temp_raw >> 8) & 0xFFU); p[2] = static_cast(status->vref_raw & 0xFFU); p[3] = static_cast((status->vref_raw >> 8) & 0xFFU); p[4] = static_cast(temp_x100 & 0xFF); p[5] = static_cast((temp_x100 >> 8) & 0xFF); p[6] = static_cast(vdda_x1000 & 0xFFU); p[7] = static_cast((vdda_x1000 >> 8) & 0xFFU); p[8] = CONFIG_CAN_STATUS_TAG0; p[9] = CONFIG_CAN_STATUS_TAG1; p[10] = CONFIG_CAN_STATUS_TAG2; p[11] = CONFIG_CAN_STATUS_TAG3; for(uint8_t i = 0; i < CANFD_STATUS_DLEN; ++i) { s_txBuffer.tx_message.tx_data[i] = p[i]; } s_txBuffer.valid = 1U; } void CanFd::init() { initGpio(); setNormalMode(); can_deinit(CONFIG_CAN_INSTANCE); initNominalTiming(); initFdMode(); filterAcceptAll(); can_interrupt_enable(CONFIG_CAN_INSTANCE, CAN_INT_RFNE0); nvic_irq_enable(CAN0_RX0_IRQn, 1U, 1U); s_rxFrame.valid = 0U; s_txBuffer.valid = 0U; } void CanFd::poll() { /* 已由 CAN0_RX0_IRQHandler 中断驱动 */ } void CanFd::prepareStatus(const StatusPayload *status) { if(status == nullptr) { s_txBuffer.valid = 0U; return; } buildStatusFrame(status); } void CanFd::sendPrepared() { if(s_txBuffer.valid == 0U) return; const uint8_t mailbox = can_message_transmit(CONFIG_CAN_INSTANCE, &s_txBuffer.tx_message); if(mailbox != CAN_NOMAILBOX) { s_diag.tx_count++; s_diag.last_payload_length = s_txBuffer.tx_message.tx_dlen; s_diag.last_tx_id = s_txBuffer.tx_message.tx_sfid; } else { s_diag.error_count++; } } bool CanFd::hasRxFrame() { return s_rxFrame.valid != 0U; } bool CanFd::consumeRxFrame(uint32_t *id, uint8_t *data, uint8_t *length) { if(s_rxFrame.valid == 0U) return false; if(id) *id = s_rxFrame.id; if(length) *length = s_rxFrame.length; if(data) { for(uint8_t i = 0; i < s_rxFrame.length; ++i) data[i] = s_rxFrame.data[i]; } s_rxFrame.valid = 0U; return true; } const CanFd::Diag *CanFd::diag() { return &s_diag; } void CanFd::setNormalMode() { gpio_bit_reset(kSlpGpio, kSlpPin); } void CanFd::setSilentMode() { gpio_bit_set(kSlpGpio, kSlpPin); } void CanFd::onRx0Interrupt() { if(can_interrupt_flag_get(CONFIG_CAN_INSTANCE, CAN_INT_FLAG_RFL0) == RESET) return; can_receive_message_struct rx_message{}; can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &rx_message); can_message_receive(CONFIG_CAN_INSTANCE, CAN_FIFO0, &rx_message); s_diag.rx_count++; s_diag.last_payload_length = rx_message.rx_dlen; s_diag.last_rx_fd_flag = rx_message.fd_flag; s_diag.last_rx_brs = rx_message.fd_brs; s_diag.last_rx_esi = rx_message.fd_esi; s_diag.last_rx_id = (rx_message.rx_ff == CAN_FF_STANDARD) ? rx_message.rx_sfid : rx_message.rx_efid; s_rxFrame.id = s_diag.last_rx_id; s_rxFrame.length = rx_message.rx_dlen; for(uint8_t i = 0; i < rx_message.rx_dlen; ++i) s_rxFrame.data[i] = rx_message.rx_data[i]; s_rxFrame.valid = 1U; can_interrupt_flag_clear(CONFIG_CAN_INSTANCE, CAN_INT_FLAG_RFL0); } /* ----- 中断入口 C 包装 ------------------------------------------------- */ extern "C" void CAN0_RX0_IRQHandler(void) { CanFd::onRx0Interrupt(); }