Files
DCU_APP/GD32E508_DCU_APP/device/CANFD.cpp.bak_hideimpl
T

225 lines
6.9 KiB
Plaintext
Raw Normal View History

/**
* @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;
} // namespace
CanFd::Diag CanFd::s_diag;
CanFd::RxFrame CanFd::s_rxFrame;
CanFd::TxBuffer CanFd::s_txBuffer;
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<int16_t>(status->temperature * 100.0f);
const uint16_t vdda_x1000 = static_cast<uint16_t>(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<uint8_t>(status->temp_raw & 0xFFU);
p[1] = static_cast<uint8_t>((status->temp_raw >> 8) & 0xFFU);
p[2] = static_cast<uint8_t>(status->vref_raw & 0xFFU);
p[3] = static_cast<uint8_t>((status->vref_raw >> 8) & 0xFFU);
p[4] = static_cast<uint8_t>(temp_x100 & 0xFF);
p[5] = static_cast<uint8_t>((temp_x100 >> 8) & 0xFF);
p[6] = static_cast<uint8_t>(vdda_x1000 & 0xFFU);
p[7] = static_cast<uint8_t>((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(); }