feat(cproject): 重构项目文件结构并添加EtherCAT通信支持
- 将设备相关文件重新组织为device/spi和comm分组 - 添加EtherCAT从站通信模块(esc_exmc_bus、esc_lan9252、ethercat_slave等) - 添加EXMC外设组件支持 - 统一文件命名规范为小写 refactor(canfd): 优化CANFD模块中断安全性和配置方式 - 替换自定义临界区函数为RT_CRITICAL_SAVE/RESTORE宏 - 使用配置常量CONFIG_IRQ_PREEMPT_CAN替代硬编码值 - 简化邮箱满时的处理逻辑,移除不必要的SysTick等待 - 移除废弃的中断保存头文件引用 refactor(timer): 更新定时器配置以使用配置常量 - 修复头文件包含路径大小写问题 - 使用CONFIG_NVIC_PRIORITY_GROUP配置项替代硬编码值
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file ADC.cpp
|
||||
* @file adc.cpp
|
||||
* @brief ADC 采样模块实现。
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/**
|
||||
* @file CANFD.cpp
|
||||
* @file canfd.cpp
|
||||
* @brief CANFD 通信模块实现。
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "device/canfd.h"
|
||||
#include "sys/config.h"
|
||||
#include "sys/critical.h"
|
||||
#include "sys/task_manager.h"
|
||||
#include "sys/systick.h"
|
||||
|
||||
namespace {
|
||||
struct TxFrame {
|
||||
@@ -44,30 +44,6 @@ constexpr CanChannelConfig kChannels[] = {
|
||||
constexpr size_t kChannelCount = sizeof(kChannels) / sizeof(kChannels[0]);
|
||||
constexpr uint8_t kTxQueueDepth = 4U;
|
||||
constexpr uint32_t kCanRxParseTaskMask = (1UL << TASK_CAN_RX_PARSE);
|
||||
|
||||
/**
|
||||
* @brief Enter a critical section and preserve the previous interrupt mask.
|
||||
* @param[in] 无。
|
||||
* @param[out] 无。
|
||||
* @retval uint32_t Previous PRIMASK value.
|
||||
*/
|
||||
static uint32_t enterCriticalSection()
|
||||
{
|
||||
const uint32_t primask = __get_PRIMASK();
|
||||
__disable_irq();
|
||||
return primask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exit a critical section by restoring the saved interrupt mask.
|
||||
* @param[in] primask Previous PRIMASK value returned by `enterCriticalSection()`.
|
||||
* @param[out] 无。
|
||||
* @retval 无返回值。
|
||||
*/
|
||||
static void exitCriticalSection(uint32_t primask)
|
||||
{
|
||||
__set_PRIMASK(primask);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
CanFd::Diag CanFd::s_diag{};
|
||||
@@ -281,7 +257,7 @@ void CanFd::init()
|
||||
initFdMode(ch.canPeriph);
|
||||
configureRxFilter(ch.canPeriph, ch.filterNumber);
|
||||
can_interrupt_enable(ch.canPeriph, CAN_INT_RFNE0 | CAN_INT_RFF0 | CAN_INT_RFO0);
|
||||
nvic_irq_enable(ch.rx0Irq, 1U, static_cast<uint8_t>(i));
|
||||
nvic_irq_enable(ch.rx0Irq, CONFIG_IRQ_PREEMPT_CAN, static_cast<uint8_t>(i));
|
||||
|
||||
s_rxQueues[i].head = 0U;
|
||||
s_rxQueues[i].tail = 0U;
|
||||
@@ -375,14 +351,14 @@ void CanFd::sendPrepared()
|
||||
bool CanFd::hasRxFrame()
|
||||
{
|
||||
bool found = false;
|
||||
const uint32_t primask = enterCriticalSection();
|
||||
uint32_t save = RT_CRITICAL_SAVE();
|
||||
for(size_t i = 0; i < kChannelCount; ++i) {
|
||||
if(s_rxQueues[i].count != 0U) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
exitCriticalSection(primask);
|
||||
RT_CRITICAL_RESTORE(save);
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -401,7 +377,7 @@ bool CanFd::consumeRxFrame(uint32_t *id, uint8_t *data, uint8_t *length, uint8_t
|
||||
RxFrame localFrame{};
|
||||
bool found = false;
|
||||
|
||||
const uint32_t primask = enterCriticalSection();
|
||||
uint32_t save = RT_CRITICAL_SAVE();
|
||||
for(size_t n = 0; n < kChannelCount; ++n) {
|
||||
const uint8_t idx = static_cast<uint8_t>((s_nextConsumeChannel + n) % kChannelCount);
|
||||
auto &queue = s_rxQueues[idx];
|
||||
@@ -416,7 +392,7 @@ bool CanFd::consumeRxFrame(uint32_t *id, uint8_t *data, uint8_t *length, uint8_t
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
exitCriticalSection(primask);
|
||||
RT_CRITICAL_RESTORE(save);
|
||||
|
||||
if(!found) {
|
||||
return false;
|
||||
@@ -467,29 +443,10 @@ bool CanFd::transmitFrame(uint8_t channelIndex, uint32_t ext_id,
|
||||
const uint32_t canPeriph = kChannels[channelIndex].canPeriph;
|
||||
uint8_t mailbox = can_message_transmit(canPeriph, &tx_msg);
|
||||
|
||||
/* 邮箱全占时的恢复处理:
|
||||
* 当目标控制器初始化时 auto_retrans = ENABLE,且总线上没有其它节点回 ACK,
|
||||
* 已入邮箱的帧会无限自动重传,TME 位永不置回,导致后续帧一律 CAN_NOMAILBOX。
|
||||
*
|
||||
* 改良策略(两段式,尽量不丢帧):
|
||||
* 1) 先短自旋 ~2 ms 轮询邮箱状态。健康总线上 1 Mbps + 8 字节帧的实际发送
|
||||
* 仅约 130 µs,正常重传几百 µs 内即可 drain,绝大多数“偶发 NOMAILBOX”
|
||||
* 场景到这一步就已经恢复,不会触发 abort,也就不会丢帧。
|
||||
* 2) 若 2 ms 后仍全部 PENDING(典型:物理层不通、TCAN1057A 没焊或 CAN_L/H
|
||||
* 断线导致 ACK Error 死循环),只 abort 第一个 PENDING 邮箱腾一个位置,
|
||||
* 最坏丢 1 帧而不是 3 帧,并通过 s_diag.tx_abort_count 暴露给串口 diag,
|
||||
* 上层(含 SPI 桥)仍能把后续帧正常下发。 */
|
||||
/* 邮箱全占时保持非阻塞:本函数可能处于 SPI CS 中断链路,不能等待
|
||||
* SysTick。若 auto_retrans 因总线无 ACK 卡住全部邮箱,只立即 abort
|
||||
* 一个 PENDING 邮箱并重投一次,把中断占用时间控制在寄存器访问级别。 */
|
||||
if (mailbox == CAN_NOMAILBOX) {
|
||||
constexpr uint8_t kDrainPolls = 2U;
|
||||
for (uint8_t poll = 0U; poll < kDrainPolls && mailbox == CAN_NOMAILBOX; ++poll) {
|
||||
SysTickTimer::delayMs(1U);
|
||||
mailbox = can_message_transmit(canPeriph, &tx_msg);
|
||||
}
|
||||
}
|
||||
if (mailbox == CAN_NOMAILBOX) {
|
||||
/* 只 abort 一个 PENDING 邮箱:找到首个 stop 成功的就停手,
|
||||
* 不再扫描后续邮箱,把丢帧上限收敛到 1。stop 失败的邮箱
|
||||
* (硬件正在物理发送)继续尝试下一个,避免一次 abort 都没成功。 */
|
||||
for (uint8_t mb = CAN_MAILBOX0; mb <= CAN_MAILBOX2; ++mb) {
|
||||
if (can_transmit_states(canPeriph, mb) != CAN_TRANSMIT_PENDING) {
|
||||
continue;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/**
|
||||
* @file Timer.cpp
|
||||
* @file timer.cpp
|
||||
* @brief 用户调度定时器模块实现。
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "device/Timer.h"
|
||||
#include "device/timer.h"
|
||||
#include "sys/task_manager.h"
|
||||
#include "sys/config.h"
|
||||
|
||||
@@ -44,7 +44,7 @@ void SchedulerTimer::configureTimer()
|
||||
*/
|
||||
void SchedulerTimer::configureNvic()
|
||||
{
|
||||
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
|
||||
nvic_priority_group_set(CONFIG_NVIC_PRIORITY_GROUP);
|
||||
nvic_irq_enable(CONFIG_SCHED_TIMER_IRQn, CONFIG_SCHED_TIMER_IRQ_PREEMPT_PRIO, CONFIG_SCHED_TIMER_IRQ_SUB_PRIO);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
#include "device/spi_command_handler.h"
|
||||
#include "device/app_spi_command.h"
|
||||
#include "device/app_spi_command_defs.h"
|
||||
#include "device/spi/spi_command_handler.h"
|
||||
#include "device/spi/app_spi_command.h"
|
||||
#include "device/spi/app_spi_command_defs.h"
|
||||
#include "sys/ota_boot_request.h"
|
||||
#include "sys/config.h"
|
||||
#include "sys/task_manager.h"
|
||||
+17
-3
@@ -1,17 +1,21 @@
|
||||
#include "device/spi_command_handler.h"
|
||||
#include "device/app_spi_command.h"
|
||||
#include "device/app_spi_command_defs.h"
|
||||
#include "device/spi/spi_command_handler.h"
|
||||
#include "device/spi/app_spi_command.h"
|
||||
#include "device/spi/app_spi_command_defs.h"
|
||||
#include "device/canfd.h"
|
||||
#include "sys/config.h"
|
||||
#include <cstdio>
|
||||
|
||||
namespace {
|
||||
|
||||
#if (CONFIG_SPI_CAN_SEND_VERBOSE_LOG != 0)
|
||||
constexpr uint8_t kCanLogMaxDlc = 64U;
|
||||
#endif
|
||||
|
||||
void postCanSendLog(AppSpiCommand &bus, const char *result,
|
||||
uint8_t can_ch, uint32_t can_id,
|
||||
const uint8_t *can_data, uint8_t can_dlc)
|
||||
{
|
||||
#if (CONFIG_SPI_CAN_SEND_VERBOSE_LOG != 0)
|
||||
const uint8_t logged_dlc = (can_dlc <= kCanLogMaxDlc) ? can_dlc : kCanLogMaxDlc;
|
||||
char data_hex[(kCanLogMaxDlc * 2U) + 1U] = {};
|
||||
for (uint8_t i = 0U; i < logged_dlc; ++i) {
|
||||
@@ -27,6 +31,14 @@ void postCanSendLog(AppSpiCommand &bus, const char *result,
|
||||
(logged_dlc > 0U) ? data_hex : "-",
|
||||
result ? result : "UNKNOWN");
|
||||
bus.postLog(log_msg);
|
||||
#else
|
||||
(void)bus;
|
||||
(void)result;
|
||||
(void)can_ch;
|
||||
(void)can_id;
|
||||
(void)can_data;
|
||||
(void)can_dlc;
|
||||
#endif
|
||||
}
|
||||
|
||||
class SpiCanBridgeHandler final : public ISpiCommandHandler {
|
||||
@@ -39,11 +51,13 @@ public:
|
||||
void handle(AppSpiCommand &bus, const SpiCommandContext &ctx) override
|
||||
{
|
||||
if (ctx.payload_len < 6U) {
|
||||
#if (CONFIG_SPI_APP_LOG_ENABLE != 0)
|
||||
char log_msg[AppSpiCommand::kLogBufSize] = {};
|
||||
(void)snprintf(log_msg, sizeof(log_msg),
|
||||
"CAN_SEND payload too short: len=%u -> ERROR",
|
||||
static_cast<unsigned>(ctx.payload_len));
|
||||
bus.postLog(log_msg);
|
||||
#endif
|
||||
uint8_t err = 0xE0U;
|
||||
bus.buildResponse(ctx.tx_buf, ctx.tx_buf_size, ctx.tx_len,
|
||||
SpiDefs::kRspError, &err, 1U);
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
#include "device/spi_command_handler.h"
|
||||
#include "device/app_spi_command.h"
|
||||
#include "device/app_spi_command_defs.h"
|
||||
#include "device/spi/spi_command_handler.h"
|
||||
#include "device/spi/app_spi_command.h"
|
||||
#include "device/spi/app_spi_command_defs.h"
|
||||
|
||||
namespace {
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
#include "device/spi_command_handler.h"
|
||||
#include "device/app_spi_command.h"
|
||||
#include "device/app_spi_command_defs.h"
|
||||
#include "device/spi/spi_command_handler.h"
|
||||
#include "device/spi/app_spi_command.h"
|
||||
#include "device/spi/app_spi_command_defs.h"
|
||||
#include "sys/config.h"
|
||||
#include "main.h"
|
||||
#include <cstring>
|
||||
+34
-12
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
* @file app_spi_command.cpp
|
||||
* @brief APP 运行期 SPI 链路与命令路由实现。
|
||||
*
|
||||
@@ -13,9 +13,9 @@
|
||||
* 只需要新增命令处理器,不再继续膨胀本文件。
|
||||
*/
|
||||
|
||||
#include "device/app_spi_command.h"
|
||||
#include "device/spi_command_handler.h"
|
||||
#include "device/app_spi_command_defs.h"
|
||||
#include "device/spi/app_spi_command.h"
|
||||
#include "device/spi/spi_command_handler.h"
|
||||
#include "device/spi/app_spi_command_defs.h"
|
||||
|
||||
extern "C" {
|
||||
#include "gd32e50x_exti.h"
|
||||
@@ -26,6 +26,7 @@ extern "C" {
|
||||
#include "gd32e50x_dma.h"
|
||||
#include "gd32e50x_spi.h"
|
||||
#include "sys/config.h"
|
||||
#include "sys/critical.h"
|
||||
#include "sys/task_manager.h"
|
||||
#include "sys/ota_boot_request.h"
|
||||
#include "sys/systick.h"
|
||||
@@ -180,16 +181,25 @@ static bool spi_try_parse_frame(const uint8_t *frame, uint16_t frame_len,
|
||||
|
||||
void AppSpiCommand::postLog(const char *msg)
|
||||
{
|
||||
#if (CONFIG_SPI_APP_LOG_ENABLE != 0)
|
||||
if (!msg) return;
|
||||
snprintf(m_logBuf, kLogBufSize, "[SPI-APP] %s", msg);
|
||||
m_logPending = true;
|
||||
#else
|
||||
(void)msg;
|
||||
#endif
|
||||
}
|
||||
|
||||
void AppSpiCommand::postLogFmt(const char *fmt, uint8_t val)
|
||||
{
|
||||
#if (CONFIG_SPI_APP_LOG_ENABLE != 0)
|
||||
if (!fmt) return;
|
||||
snprintf(m_logBuf, kLogBufSize, fmt, val);
|
||||
m_logPending = true;
|
||||
#else
|
||||
(void)fmt;
|
||||
(void)val;
|
||||
#endif
|
||||
}
|
||||
|
||||
void AppSpiCommand::buildResponse(uint8_t *tx_buf, uint16_t tx_buf_size,
|
||||
@@ -251,7 +261,7 @@ void AppSpiCommand::configureSpi0()
|
||||
spi_i2s_interrupt_enable(SPI0, SPI_I2S_INT_RBNE);
|
||||
spi_i2s_interrupt_enable(SPI0, SPI_I2S_INT_ERR);
|
||||
spi_i2s_interrupt_disable(SPI0, SPI_I2S_INT_TBE);
|
||||
nvic_irq_enable(SPI0_IRQn, 2U, 0U);
|
||||
nvic_irq_enable(SPI0_IRQn, CONFIG_IRQ_PREEMPT_SPI_USART, 0U);
|
||||
spi_enable(SPI0);
|
||||
}
|
||||
|
||||
@@ -282,7 +292,7 @@ void AppSpiCommand::configureExti()
|
||||
exti_init(EXTI_15, EXTI_INTERRUPT, EXTI_TRIG_BOTH);
|
||||
exti_interrupt_enable(EXTI_15);
|
||||
exti_interrupt_flag_clear(EXTI_15);
|
||||
nvic_irq_enable(EXTI10_15_IRQn, 1U, 1U);
|
||||
nvic_irq_enable(EXTI10_15_IRQn, CONFIG_IRQ_PREEMPT_SPI_USART, 1U);
|
||||
}
|
||||
|
||||
|
||||
@@ -341,7 +351,7 @@ void AppSpiCommand::processCommand()
|
||||
uint16_t payload_len = 0U;
|
||||
|
||||
if (spi_try_parse_frame(m_rxBuf, m_rxLen, &frame_type, &payload, &payload_len)) {
|
||||
if (!isFlashRelatedFrame(frame_type)) {
|
||||
if (CONFIG_SPI_APP_LOG_ENABLE != 0 && !isFlashRelatedFrame(frame_type)) {
|
||||
postLogFmt("[SPI-APP] 收到非刷写 SPI type=0x%02X", frame_type);
|
||||
}
|
||||
|
||||
@@ -432,8 +442,10 @@ void AppSpiCommand::processCommand()
|
||||
}
|
||||
}
|
||||
|
||||
/* 置位 TASK_SPI_LOG,唤醒主循环立刻打印日志 */
|
||||
TaskManager::set(1UL << TASK_SPI_LOG);
|
||||
if (m_logPending) {
|
||||
/* 置位 TASK_SPI_LOG,唤醒主循环立刻打印日志 */
|
||||
TaskManager::set(1UL << TASK_SPI_LOG);
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
@@ -445,19 +457,28 @@ void AppSpiCommand::poll()
|
||||
char log_copy[kLogBufSize] = {};
|
||||
bool has_log = false;
|
||||
|
||||
__disable_irq();
|
||||
uint32_t save = RT_CRITICAL_SAVE();
|
||||
if (m_logPending) {
|
||||
memcpy(log_copy, m_logBuf, sizeof(log_copy));
|
||||
m_logPending = false;
|
||||
has_log = true;
|
||||
}
|
||||
__enable_irq();
|
||||
RT_CRITICAL_RESTORE(save);
|
||||
|
||||
if (has_log) {
|
||||
printf("%s\r\n", log_copy);
|
||||
}
|
||||
}
|
||||
|
||||
void AppSpiCommand::processPendingCommand()
|
||||
{
|
||||
if (!m_cmdPending) {
|
||||
return;
|
||||
}
|
||||
m_cmdPending = false;
|
||||
processCommand();
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* CS 边沿处理
|
||||
* ============================================================ */
|
||||
@@ -522,7 +543,8 @@ void AppSpiCommand::onCsRelease()
|
||||
m_rxLen = 0U;
|
||||
return;
|
||||
}
|
||||
processCommand();
|
||||
m_cmdPending = true;
|
||||
TaskManager::set(1UL << TASK_SPI_CMD_PROCESS);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
+6
-2
@@ -1,4 +1,4 @@
|
||||
#ifndef DEVICE_APP_SPI_COMMAND_H
|
||||
#ifndef DEVICE_APP_SPI_COMMAND_H
|
||||
#define DEVICE_APP_SPI_COMMAND_H
|
||||
|
||||
#include <cstdint>
|
||||
@@ -12,7 +12,7 @@ class ISpiCommandHandler;
|
||||
* - 维护 SPI0 从机的硬件链路(GPIO/SPI/DMA/EXTI)
|
||||
* - 将接收到的合法帧按 TYPE 注册式分发给 ISpiCommandHandler
|
||||
*
|
||||
* 具体命令处理逻辑不再放在这里,而是拆到 `device/app_spi_cmd_*.cpp`,
|
||||
* 具体命令处理逻辑不再放在这里,而是拆到 `device/spi/app_spi_cmd_*.cpp`,
|
||||
* 通过 `registerHandler()` 注册进来,保持本模块可扩展。
|
||||
*/
|
||||
class AppSpiCommand {
|
||||
@@ -23,6 +23,9 @@ public:
|
||||
/** @brief 主循环轮询:打印延迟日志。 */
|
||||
void poll();
|
||||
|
||||
/** @brief 主循环调用:执行 ISR 中推迟的 SPI 命令解析(从 onCsRelease 移出)。 */
|
||||
void processPendingCommand();
|
||||
|
||||
/** @brief SPI0 中断处理入口。 */
|
||||
void onInterrupt();
|
||||
|
||||
@@ -66,6 +69,7 @@ private:
|
||||
uint8_t m_txLen = 0U;
|
||||
volatile uint8_t m_txPos = 0U;
|
||||
volatile bool m_logPending = false;
|
||||
volatile bool m_cmdPending = false; /**< ISR 置位,标记有待主循环解析的 SPI 命令。 */
|
||||
uint8_t m_rxBuf[kRxBufSize] = {};
|
||||
uint8_t m_txBuf[kTxBufSize] = {};
|
||||
char m_logBuf[kLogBufSize] = {};
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "main.h"
|
||||
#include "device/usart0.h"
|
||||
#include "sys/config.h"
|
||||
#include "sys/critical.h"
|
||||
|
||||
uint8_t Usart0::s_txBuf[Usart0::kTxBufSize];
|
||||
volatile uint16_t Usart0::s_txHead = 0U;
|
||||
@@ -54,10 +55,10 @@ bool Usart0::isBufferEmpty()
|
||||
*/
|
||||
bool Usart0::putCharNonBlocking(int ch)
|
||||
{
|
||||
__disable_irq();
|
||||
uint32_t save = RT_CRITICAL_SAVE();
|
||||
const uint16_t next = nextIndex(s_txHead);
|
||||
if(next == s_txTail) {
|
||||
__enable_irq();
|
||||
RT_CRITICAL_RESTORE(save);
|
||||
s_dropCount++;
|
||||
return false;
|
||||
}
|
||||
@@ -65,7 +66,7 @@ bool Usart0::putCharNonBlocking(int ch)
|
||||
s_txBuf[s_txHead] = static_cast<uint8_t>(ch);
|
||||
s_txHead = next;
|
||||
usart_interrupt_enable(USART0, USART_INT_TBE);
|
||||
__enable_irq();
|
||||
RT_CRITICAL_RESTORE(save);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -136,7 +137,7 @@ void Usart0::init()
|
||||
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
|
||||
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
|
||||
usart_enable(USART0);
|
||||
nvic_irq_enable(USART0_IRQn, 2U, 0U);
|
||||
nvic_irq_enable(USART0_IRQn, CONFIG_IRQ_PREEMPT_SPI_USART, 0U);
|
||||
}
|
||||
|
||||
/* ----- 中断入口 / printf 重定向的 C 包装 --------------------------- */
|
||||
|
||||
Reference in New Issue
Block a user