feat(can): 新增CAN通道收发器Silent模式功能
- 新增SPI 0xC8命令用于切换CAN通道收发器Silent模式(只听不发) - 在canFdSetTxSilent函数中实现静默模式控制逻辑 - 在HTTP API中添加POST /can/silent端点 - 更新CAN协议文档,记录新命令和错误码E6 - 修改bus_state位图,添加bit5表示静默状态 fix(can): 优化CAN反馈任务内存使用和链路离线处理 - 将任务栈上的临时缓冲区改为静态分配,防止栈溢出 - 添加链路在线检测,在离线状态下进入休眠退避 - 修复queryMotorStatePages和queryAdcFeedback函数返回值类型 - 优化UDP日志发送的冷却退避机制 chore(config): 更新调试日志配置和版本信息 - 在VSCode设置中添加ESP-IDF串口配置 - 添加SPI调试日志级别编译期开关CONFIG_SPI_DEBUG_LOG_LEVEL - 更新固件版本至0.5.2,记录相关变更内容 - 调整SPI和CAN反馈任务的栈大小配置
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
* 0xC0 发 CAN 帧(canFdSend)
|
||||
* 0xC1 反馈页解析(canFdParseFeedbackPage;由 GD32 主动推送,本文件不轮询)
|
||||
* 0xC2 设 RX 模式(canFdSetRxMode)
|
||||
* 0xC8 设通道收发器 Silent(canFdSetTxSilent,只听不发)
|
||||
*
|
||||
* 0xC1 线格式与 GD32 app_spi_cmd_can_feedback.cpp 对齐:
|
||||
* 固定头 28B + 条目 id(4LE)+dlc(1)+flags(1)+rsvd(2)+data(dlc)
|
||||
@@ -22,6 +23,7 @@ namespace {
|
||||
constexpr uint8_t kSpiCanFrameType = 0xC0U;
|
||||
constexpr uint8_t kSpiCanBurstType = 0xC7U;
|
||||
constexpr uint8_t kSpiCanSetModeType = 0xC2U;
|
||||
constexpr uint8_t kSpiCanSetSilentType = 0xC8U;
|
||||
constexpr uint8_t kFeedbackFixedHeader = 28U;
|
||||
constexpr uint8_t kFeedbackMaxPage = 1U; /* GD32 仅 page 0/1 */
|
||||
|
||||
@@ -403,8 +405,13 @@ int canFdQueryFeedback(uint8_t channel, uint8_t page,
|
||||
&resp_type, resp_buf, sizeof(resp_buf), &resp_len, 200U);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
DEBUG_WARN("CAN", "queryFeedback ch=%u p=%u SPI失败: %s",
|
||||
(unsigned)channel, (unsigned)page, esp_err_to_name(ret));
|
||||
static TickType_t s_lastFailWarnTick = 0;
|
||||
const TickType_t now_tick = xTaskGetTickCount();
|
||||
if (s_lastFailWarnTick == 0 || (now_tick - s_lastFailWarnTick) >= pdMS_TO_TICKS(5000)) {
|
||||
s_lastFailWarnTick = now_tick;
|
||||
DEBUG_WARN("CAN", "queryFeedback ch=%u p=%u SPI失败: %s (限频5s)",
|
||||
(unsigned)channel, (unsigned)page, esp_err_to_name(ret));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (resp_type == SPI_OTA_RSP_ERROR) {
|
||||
@@ -489,3 +496,52 @@ int canFdSetRxMode(can_rx_mode_t mode,
|
||||
(unsigned)resp_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 切换指定 CAN 通道收发器 Silent(SPI 0xC8):只听不发。
|
||||
* @return 0 成功;-1 参数非法或 SPI/应答失败;-2 GD32 返回 ERROR。
|
||||
* @note 与 canFdSetRxMode 同款单步事务:GD32 在 CS EXTI ISR 内直接回 ACK/ERROR,
|
||||
* 不会回 WAIT(区别于 0xC0 那条要排空 OTA 残留 WAIT 的路径)。
|
||||
* ACK payload = [0]channel [1]实际 silent [2]通道使能位。
|
||||
*/
|
||||
int canFdSetTxSilent(uint8_t channel,
|
||||
bool silent,
|
||||
uint8_t *actual,
|
||||
uint32_t timeout_ms)
|
||||
{
|
||||
if (channel > 2U) {
|
||||
DEBUG_WARN("CAN", "SET_SILENT 非法 ch=%u", (unsigned)channel);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t req[2] = { channel, static_cast<uint8_t>(silent ? 1U : 0U) };
|
||||
uint8_t resp_buf[3] = {0};
|
||||
uint8_t resp_type = 0U;
|
||||
size_t resp_len = 0U;
|
||||
|
||||
esp_err_t ret = SpiMaster::instance().transact(
|
||||
kSpiCanSetSilentType,
|
||||
req, sizeof(req),
|
||||
&resp_type, resp_buf, sizeof(resp_buf), &resp_len, timeout_ms);
|
||||
|
||||
if (ret == ESP_OK && resp_type == SPI_OTA_RSP_ACK && resp_len >= 2U) {
|
||||
if (actual != nullptr) {
|
||||
*actual = resp_buf[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret == ESP_OK && resp_type == SPI_OTA_RSP_ERROR) {
|
||||
DEBUG_WARN("CAN", "SET_SILENT ch=%u want=%u GD32 err=0x%02X",
|
||||
(unsigned)channel, (unsigned)(silent ? 1U : 0U),
|
||||
(resp_len >= 1U) ? (unsigned)resp_buf[0] : 0U);
|
||||
return -2;
|
||||
}
|
||||
|
||||
DEBUG_WARN("CAN", "SET_SILENT ch=%u want=%u %s r=0x%02X n=%u",
|
||||
(unsigned)channel, (unsigned)(silent ? 1U : 0U),
|
||||
esp_err_to_name(ret),
|
||||
(unsigned)resp_type,
|
||||
(unsigned)resp_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user