Files
DCU_APP/GD32E508_DCU_APP/comm/esc_exmc_bus.cpp
T
cbb 46ef19d882 feat(build): 优化构建配置并引入日志分级系统
- 将优化级别从balanced调整为size,减少Flash占用
- 添加hardfault.cpp文件以增强故障诊断能力
- 关闭RTTI和异常处理以移除libcppabi运行时(节省约2.5KB Flash)
- 添加链接器参数输出未引用段与总量报告用于Flash尺寸分析

refactor(logging): 统一日志输出并实现编译时日志分级

- 将printf调用替换为模块化的日志宏(ECAT_LOGI、CAN_LOGI等)
- 实现CONFIG_*_LOG_ENABLE编译开关控制各模块INFO级日志
- 错误和关键事件使用LOG_ERR恒定保留,其他日志可编译时裁剪
- 保持原有日志内容不变,但支持链接器自动回收未使用的格式字符串
2026-07-27 01:49:18 +08:00

141 lines
6.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file esc_exmc_bus.cpp
* @brief LAN9252 ESC 的 EXMC 16-bit 并行总线驱动实现。
*
* 使用 GigaDevice gd32e50x_exmc 标准库。
* 注意:DFP 只把 FMC 注册为 CMSIS 组件,EXMC 未进组件列表;
* 源文件放在 RTE/Device/... 并由 cproject group device_exmc 本地编译。
*/
#include "comm/esc_exmc_bus.h"
#include "sys/config.h"
#include <stdio.h>
extern "C" {
#include "gd32e50x_rcu.h"
#include "gd32e50x_gpio.h"
#include "gd32e50x_exmc.h" /* RTE/Device/GD32E508VE 或 -I 同目录 */
}
/* 内存映射访问宏:基址 + 偏移(按 16-bit 半字对齐,LAN9252 HBI 地址左移 1 位)。 */
#define ESC_EXMC_REG16(offset) (*(volatile uint16_t*)(CONFIG_ESC_EXMC_BASE_ADDR + (offset)))
bool EscExmcBus::s_ok = false;
bool EscExmcBus::init()
{
s_ok = false;
ECAT_LOGI("[ECAT][EXMC] init: enable RCU clocks\r\n");
rcu_periph_clock_enable(RCU_GPIOD);
rcu_periph_clock_enable(RCU_GPIOE);
rcu_periph_clock_enable(RCU_AF);
rcu_periph_clock_enable(RCU_EXMC);
/* 配置 16-bit 数据线 D0-D15 为 AF 推挽 */
gpio_init(CONFIG_EXMC_D0_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D0_PIN);
gpio_init(CONFIG_EXMC_D1_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D1_PIN);
gpio_init(CONFIG_EXMC_D2_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D2_PIN);
gpio_init(CONFIG_EXMC_D3_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D3_PIN);
gpio_init(CONFIG_EXMC_D4_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D4_PIN);
gpio_init(CONFIG_EXMC_D5_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D5_PIN);
gpio_init(CONFIG_EXMC_D6_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D6_PIN);
gpio_init(CONFIG_EXMC_D7_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D7_PIN);
gpio_init(CONFIG_EXMC_D8_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D8_PIN);
gpio_init(CONFIG_EXMC_D9_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D9_PIN);
gpio_init(CONFIG_EXMC_D10_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D10_PIN);
gpio_init(CONFIG_EXMC_D11_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D11_PIN);
gpio_init(CONFIG_EXMC_D12_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D12_PIN);
gpio_init(CONFIG_EXMC_D13_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D13_PIN);
gpio_init(CONFIG_EXMC_D14_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D14_PIN);
gpio_init(CONFIG_EXMC_D15_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_D15_PIN);
/* 控制线:A16 / A17 / NOE / NWE / NE1
* A17(PD12) 用于 HBI Indexed Mode 访问 HBI_DATA_0,已将 LAN9252 A2 (Pin 29) 接到 PD12。 */
gpio_init(CONFIG_EXMC_A16_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_A16_PIN);
gpio_init(CONFIG_EXMC_A17_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_A17_PIN);
gpio_init(CONFIG_EXMC_NOE_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_NOE_PIN);
gpio_init(CONFIG_EXMC_NWE_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_NWE_PIN);
gpio_init(CONFIG_EXMC_NE1_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_NE1_PIN);
ECAT_LOGI("[ECAT][EXMC] init: GPIO configured (D0-D15/A16/A17/NOE/NWE/NE1)\r\n");
/*
* EXMC NOR/SRAM Region1:16-bit、非复用、异步写。
* 时序(AHB=180MHz,1 HCLK ≈ 5.56ns):
* LAN9252 HBI 最小读/写周期约 100ns → data_setup ≥ 18 HCLK。
* asyn_* 字段单位为 HCLK 计数(库文档范围 address_setup 1..16,data_setup 2..256)。
*/
exmc_norsram_parameter_struct norsram_init;
exmc_norsram_timing_parameter_struct rw_timing;
exmc_norsram_timing_parameter_struct wr_timing;
norsram_init.read_write_timing = &rw_timing;
norsram_init.write_timing = &wr_timing;
exmc_norsram_struct_para_init(&norsram_init);
norsram_init.norsram_region = CONFIG_ESC_EXMC_BANK_NOR_SRAM_REGION1;
norsram_init.write_mode = EXMC_ASYN_WRITE;
norsram_init.extended_mode = DISABLE;
norsram_init.asyn_wait = DISABLE;
norsram_init.nwait_signal = DISABLE;
norsram_init.memory_write = ENABLE;
norsram_init.nwait_config = EXMC_NWAIT_CONFIG_BEFORE;
norsram_init.wrap_burst_mode = DISABLE;
norsram_init.nwait_polarity = EXMC_NWAIT_POLARITY_LOW;
norsram_init.burst_mode = DISABLE;
norsram_init.databus_width = EXMC_NOR_DATABUS_WIDTH_16B;
norsram_init.memory_type = EXMC_MEMORY_TYPE_SRAM;
norsram_init.address_data_mux = DISABLE;
/* 读/写共用时序(非 extended mode) */
rw_timing.asyn_access_mode = EXMC_ACCESS_MODE_A;
rw_timing.syn_data_latency = EXMC_DATALAT_2_CLK;
rw_timing.syn_clk_division = EXMC_SYN_CLOCK_RATIO_DISABLE;
rw_timing.bus_latency = 1U;
rw_timing.asyn_address_setuptime = 2U; /* ~11ns */
rw_timing.asyn_address_holdtime = 2U; /* min 2 */
rw_timing.asyn_data_setuptime = 20U; /* ~111ns ≥ 100ns HBI */
wr_timing = rw_timing;
ECAT_LOGI("[ECAT][EXMC] init: applying NOR/SRAM Region1 params (16b, async, t_data=%u HCLK)\r\n",
(unsigned)rw_timing.asyn_data_setuptime);
exmc_norsram_init(&norsram_init);
exmc_norsram_enable(CONFIG_ESC_EXMC_BANK_NOR_SRAM_REGION1);
/* 总线探活:Region1 使能后立即读取 LAN9252 芯片 ID 低半字(期望 0x4321)。
* 0x0000/0xFFFF 通常意味着 EXMC 时序不满足、地址线接错或 ESC 未上电;
* 此处仅做总线可见性探活,芯片 ID 完整性校验留给 EscLan9252::init()。 */
const uint16_t probe_low = read16((uint32_t)0x0000U << 1U);
const uint16_t probe_high = read16((uint32_t)0x0002U << 1U);
const uint32_t probe_id = ((uint32_t)probe_high << 16) | probe_low;
ECAT_LOGI("[ECAT][EXMC] init: Region1 enabled, probe id_lo=0x%04X id_hi=0x%04X (id=0x%08lX)\r\n",
(unsigned)probe_low, (unsigned)probe_high, (unsigned long)probe_id);
/* 总线挂死(全 0/全 1)视为 EXMC 未就绪;chip ID 完整校验在 EscLan9252::init()。 */
if (probe_low == 0x0000U && probe_high == 0x0000U) {
LOG_ERR("[ECAT][EXMC] init: FAIL, bus reads all-zero (check wiring/NE1/A16/timing)\r\n");
return false;
}
if (probe_low == 0xFFFFU && probe_high == 0xFFFFU) {
LOG_ERR("[ECAT][EXMC] init: FAIL, bus reads all-ones (check ESC power/NOE/NWE)\r\n");
return false;
}
s_ok = true;
ECAT_LOGI("[ECAT][EXMC] init: OK, bus visible\r\n");
return true;
}
__attribute__((section(".ramfunc"), noinline))
uint16_t EscExmcBus::read16(uint32_t offset)
{
return ESC_EXMC_REG16(offset);
}
__attribute__((section(".ramfunc"), noinline))
void EscExmcBus::write16(uint32_t offset, uint16_t data)
{
ESC_EXMC_REG16(offset) = data;
}