ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

GD32H759工控HMI实战:SDRAM、SDIO与触摸屏驱动全解析

GD32H759工控HMI实战:SDRAM、SDIO与触摸屏驱动全解析 GD32H759 这颗片子属于兆易创新高性能系列Cortex-M7 内核跑到 600MHz带 TCM、Cache、外部总线接口定位就是冲着工业 HMI、边缘网关、运动控制这类场景去的。我手上这个工控项目从第 1 篇的裸机点灯、第 2 篇的 RT-Thread 移植、第 3 篇的以太网与文件系统一路走到第 4 篇终于要碰外扩存储和人机交互这两块硬骨头了。SDRAM 决定你的 GUI 能不能跑得动、跑得稳SDIO 决定你的数据能不能落盘、配方和日志能不能存得住触摸屏决定现场操作工愿不愿意用你的设备。这三样东西凑在一起基本就是一台工控 HMI 的完整骨架。这篇不打算写成手册翻译而是把我从选型、画板、写驱动、调时序、踩坑到最终跑通的全过程摊开讲。如果你也在用 GD32H759 或者类似的 M7 平台配 RT-Thread 做工控设备尤其是第一次碰 SDRAM 时序和 SDIO 卡初始化这篇应该能帮你省下不少通宵的时间。文中涉及的具体参数我会给出计算过程涉及的操作我会说明为什么这么做涉及踩过的坑我会把排查链路完整还原方便你复现思路而不是照抄结论。1. 为什么工控 HMI 一定要外扩 SDRAM以及选型时先想清楚的三件事1.1 片内 SRAM 到底够不够用先算一笔账GD32H759 片内 SRAM 看着不小但真正能拿来当显存和 GUI 缓冲的其实很紧张。RT-Thread 本身要占一部分线程栈、堆、驱动缓冲、网络协议栈都要吃内存。假设你跑一个 800x480 的 RGB565 界面单帧缓冲就是 800×480×2 768KB。如果做双缓冲防撕裂直接 1.5MB 起步。再叠加 LVGL 的对象树、字体缓存、图片解码缓冲片内那点 SRAM 根本不够分。我实际项目里用的是 1024x600 的屏RGB565 单帧 1.2MB双缓冲 2.4MB加上 LVGL 动态内存池 512KB光显示这块就要接近 3MB。所以外扩 SDRAM 不是锦上添花而是没它做不了。这也是为什么工控 HMI 方案里SDRAM 几乎是标配。1.2 容量、位宽、速度三者的取舍逻辑选 SDRAM 芯片时我一般按这个顺序定先定位宽再定容量最后卡速度。位宽优先选 16bit。原因很直接GD32H759 的 EXMC 外部存储控制器支持 8/16/32 位但 32 位要占更多引脚PCB 布线难度陡增而 16 位在 600MHz 主频下配合突发传输带宽已经足够喂饱 1024x600 的屏。32 位一般留给需要极高刷新率或者视频级数据吞吐的场景工控 HMI 用不上。容量上128Mbit16MB是甜点。64Mbit 做双缓冲加 GUI 内存池会紧张256Mbit 价格上去了但用不满。16MB 刚好能划出 4MB 给显示、4MB 给 LVGL 堆、剩下给文件系统缓存和临时缓冲。速度这块要注意SDRAM 的时钟不是随便设的。GD32H759 的 EXMC 时钟源来自系统时钟分频具体能跑多高要看你的 PCB 走线质量和芯片等级。我一般先用保守频率跑通再逐步往上压而不是一上来就冲最高频。1.3 硬件设计阶段最容易埋雷的地方SDRAM 的坑八成在硬件阶段就埋下了。我见过太多板子软件怎么调都不稳最后发现是走线问题。第一等长。数据线 D0-D15、地址线、控制线要分组等长组内误差控制在 ±50mil 以内时钟线要单独处理。SDRAM 对时序敏感等长没做好高频下必然出错。第二电源去耦。每颗 SDRAM 的 VDD 引脚旁边必须有 0.1uF 电容而且要尽量靠近引脚。我习惯在 SDRAM 电源入口再放一个 10uF 钽电容做储能。去耦没做好读写时电源纹波会导致随机位翻转这种问题最难查。第三参考层完整。SDRAM 走线下方要有完整的地平面不要跨分割。跨分割会导致回流路径断裂信号完整性直接崩。提示画完 SDRAM 部分后一定要让硬件同事做一次信号完整性仿真尤其是时钟线和数据线的过冲、振铃。软件调时序只能补偿延迟补偿不了反射。2. GD32H759 的 EXMC 配置从时钟计算到 SDRAM 初始化代码2.1 EXMC 时钟树与 SDRAM 时钟频率的推导GD32H759 的 EXMC 挂在 AHB 总线上SDRAM 时钟由 EXMC 时钟分频得到。假设系统时钟 600MHzAHB 分频后 EXMC 时钟为 300MHz再经过 SDRAM 时钟分频器可以配置为 2 分频得到 150MHz或者 3 分频得到 100MHz。这里有个关键点SDRAM 芯片本身有速度等级比如常见的 -7 表示 143MHz-6 表示 166MHz。你配置的 SDRAM 时钟不能超过芯片标称值同时还要留余量。我一般先按 100MHz 跑稳定后再尝试 133MHz 或 150MHz。计算示例系统时钟 600MHzAHB 不分频 600MHzEXMC 时钟分频设为 2 得到 300MHzSDRAM 时钟再 2 分频得到 150MHz。如果 SDRAM 芯片是 -7 等级150MHz 已经超了必须降到 100MHz 或换 -6 的芯片。2.2 时序参数的计算以常见 16bit SDRAM 为例SDRAM 初始化需要配置一堆时序参数这些参数不是拍脑袋填的要根据芯片手册和时钟周期算。以一颗常见的 16bit SDRAM 为例假设 SDRAM 时钟 100MHz周期 10ns。手册给出tRCD行到列延迟最小 18ns需要 2 个时钟周期tRP预充电时间最小 18ns需要 2 个时钟周期tWR写恢复时间最小 14ns需要 2 个时钟周期tRFC自动刷新周期最小 66ns需要 7 个时钟周期tMRD模式寄存器设置时间最小 2 个时钟周期这些值填进 EXMC 的 SDRAM 时序寄存器。注意 tRFC 要向上取整宁大勿小刷新不够会导致数据丢失。2.3 初始化代码的完整流程与每一步的意图SDRAM 上电后不能直接读写必须走一遍初始化序列。这个序列在 JEDEC 标准里有明确规定顺序错了芯片不工作。// 伪代码展示初始化流程 void sdram_init(void) { // 1. 配置 EXMC 时钟和 GPIO exmc_clock_enable(); sdram_gpio_config(); // 2. 配置 SDRAM 时序参数 exmc_sdram_timing_config(); // 3. 配置 SDRAM 控制寄存器行列数、位宽、bank数 exmc_sdram_ctrl_config(); // 4. 发送时钟配置使能命令 exmc_sdram_cmd(EXMC_SDRAM_CMD_CLK_ENABLE); delay_us(100); // 等待时钟稳定 // 5. 发送预充电全部 bank 命令 exmc_sdram_cmd(EXMC_SDRAM_CMD_PALL); // 6. 发送自动刷新命令至少 8 次 for (int i 0; i 8; i) { exmc_sdram_cmd(EXMC_SDRAM_CMD_AUTOREFRESH); } // 7. 加载模式寄存器 exmc_sdram_cmd(EXMC_SDRAM_CMD_LOAD_MODE); // 8. 设置刷新计数器 exmc_sdram_refresh_count_config(); // 9. 等待 SDRAM 就绪 delay_us(100); }每一步的意图时钟使能是让 SDRAM 收到稳定时钟预充电是把所有 bank 关掉自动刷新是给电容充电SDRAM 靠电容存储数据上电后必须先刷新加载模式寄存器是设置突发长度、CAS 延迟等最后设置刷新计数器让硬件定期自动刷新。2.4 读写测试怎么确认 SDRAM 真的稳了初始化完不能直接上 GUI要先做内存测试。我一般分三步第一步全地址写固定值再读回比如写 0x55 读 0x55写 0xAA 读 0xAA检查有没有位翻转。第二步地址线测试。写地址值到对应地址比如往 0x0000 写 0x0000往 0x0004 写 0x0004读回检查地址线有没有短路或断路。第三步数据线测试。往同一地址写 0x0001、0x0002、0x0004、0x0008 这种单比特值读回检查数据线。这三步过了SDRAM 基本就稳了。如果某一步出错根据出错模式能反推是地址线还是数据线问题。注意内存测试要跑多轮最好跑个几万次循环因为有些问题只在特定温度或特定时序下出现。我遇到过常温测试全过、高温下偶发错误的板子最后发现是去耦电容不够。3. SDIO 接口驱动 SD 卡从卡识别到文件系统挂载3.1 SDIO 与 SPI 模式的选择以及为什么工控场景优先 SDIOSD 卡有两种访问模式SPI 和 SDIO。SPI 简单四根线但速度慢一般也就几 Mbps。SDIO 用 4 位数据线速度能到几十 Mbps适合需要频繁读写日志、配方、升级包的工控场景。工控设备经常要记录运行日志、保存配方参数、支持 U 盘或 SD 卡升级固件这些操作对写入速度有要求。SPI 模式下写一个大文件能等到你怀疑人生所以只要引脚够优先上 SDIO。GD32H759 的 SDIO 控制器支持 1 位和 4 位模式支持 DMA配合 RT-Thread 的 SDIO 驱动框架能比较顺地接上文件系统。3.2 卡识别流程CMD0 到 CMD3 的完整链路SD 卡上电后处于 idle 状态需要一系列命令让它进入传输状态。这个流程在 SD 规范里有但实际调试时容易卡在某一步。// SD 卡识别流程伪代码 rt_uint8_t sd_card_init(void) { // CMD0: 复位卡到 idle 状态 sd_send_cmd(CMD0, 0); // CMD8: 检查电压范围判断是否 SDHC/SDXC sd_send_cmd(CMD8, 0x1AA); // ACMD41: 发送主机容量支持信息循环直到卡就绪 do { sd_send_cmd(CMD55, 0); // 先发 CMD55 表示下一个是 ACMD sd_send_cmd(ACMD41, 0x40FF8000); } while (!(response 0x80000000)); // CMD2: 获取卡 CID sd_send_cmd(CMD2, 0); // CMD3: 获取卡 RCA sd_send_cmd(CMD3, 0); // CMD7: 选中卡 sd_send_cmd(CMD7, rca); // ACMD6: 设置总线宽度为 4 位 sd_send_cmd(CMD55, rca); sd_send_cmd(ACMD6, 2); // CMD16: 设置块大小 512 字节 sd_send_cmd(CMD16, 512); return RT_EOK; }实际调试时最容易卡在 ACMD41 循环。如果卡一直不就绪可能是电压参数不对或者 CMD8 没响应说明卡不支持高容量。这时候要检查硬件供电和上拉电阻。3.3 4 位总线宽度切换与 DMA 传输配置总线宽度从 1 位切到 4 位是 ACMD6参数 2 表示 4 位。切换后要确认卡真的接受了可以读一下卡状态。DMA 配置这块GD32H759 的 SDIO 支持内部 DMA配置好源地址、目的地址、传输长度就行。注意 DMA 缓冲要对齐一般要求 4 字节对齐否则可能传输异常。// DMA 传输配置示例 void sdio_dma_config(rt_uint32_t *buf, rt_uint32_t len) { // 配置 DMA 源地址为 SDIO FIFO DMA_SRC SDIO_FIFO_ADDR; // 配置目的地址为内存缓冲 DMA_DST (rt_uint32_t)buf; // 传输长度单位是字节 DMA_LEN len; // 使能 DMA DMA_ENABLE(); }3.4 挂载 FatFS 与掉电保护的实际处理RT-Thread 上用 FatFS 挂载 SD 卡比较直接初始化 SDIO 设备后调用 dfs_mount 就行。但工控场景有个特殊需求掉电保护。SD 卡在写入过程中掉电可能导致文件系统损坏。我的做法是关键数据先写临时文件写完调用 fsync 强制刷盘再重命名为正式文件。这样即使掉电最多丢临时文件正式文件不会坏。另外SD 卡本身有寿命限制频繁写同一区块会加速磨损。日志类数据建议做环形缓冲或者定期切换文件避免一直写同一个文件。提示工控现场电压波动大SD 卡供电最好加 TVS 和储能电容防止瞬间掉电导致卡进入异常状态。我遇到过现场设备频繁重启后 SD 卡无法识别的情况最后发现是供电跌落导致卡内部状态机卡死重新上电才能恢复。4. 触摸屏接入从硬件接口到 RT-Thread 输入设备框架4.1 电阻屏与电容屏的接口差异以及工控场景的选择工控触摸屏主流是电阻屏和电容屏。电阻屏需要 ADC 采样成本低戴手套能操作但透光率和寿命一般。电容屏需要 I2C 或 SPI 接口的触摸控制器手感好支持多点但戴厚手套可能不灵。工控现场很多操作工戴手套所以电阻屏反而更常见。我这次项目用的是四线电阻屏通过 GD32H759 的 ADC 采样 X、Y 坐标再配合触摸中断引脚判断按下。电容屏的话常见控制器比如 GT911、FT6236走 I2C驱动相对标准化RT-Thread 也有现成软件包。选哪个看你的操作场景和成本预算。4.2 电阻屏 ADC 采样与坐标换算的数学过程四线电阻屏的原理X 方向加电压测 Y 方向电压得到 X 坐标Y 方向加电压测 X 方向电压得到 Y 坐标。需要两次 ADC 采样。// 电阻屏坐标采样伪代码 void touch_sample(rt_uint16_t *x, rt_uint16_t *y) { // 第一次X 接高X- 接低测 Y 得到 X 坐标 set_xp_high(); set_xm_low(); set_yp_adc(); *x adc_read(); // 第二次Y 接高Y- 接低测 X 得到 Y 坐标 set_yp_high(); set_ym_low(); set_xp_adc(); *y adc_read(); }采样值需要换算成屏幕坐标。假设 ADC 是 12 位满量程 4095屏幕宽 1024高 600那么screen_x raw_x * 1024 / 4095 screen_y raw_y * 600 / 4095但实际会有偏移和缩放误差需要校准。校准就是取屏幕四个角或两个对角记录 ADC 原始值算出线性变换系数。4.3 触摸校准两点校准与四点校准的取舍两点校准取左上和右下两个点算缩放和偏移简单快速但屏幕边缘可能有误差。四点校准取四个角能补偿旋转和梯形畸变精度更高。工控场景我一般用四点校准因为现场安装后屏幕可能有轻微形变四点校准能兜住。校准参数存在 Flash 或 EEPROM 里开机读取。校准算法本质是解一个线性方程组screen_x a * raw_x b * raw_y c screen_y d * raw_x e * raw_y f四个点可以解出 a 到 f 六个系数。如果只做两点校准就假设 b 和 d 为 0简化成缩放加偏移。4.4 接入 RT-Thread 输入设备框架与 LVGL 联动RT-Thread 有 input 设备框架触摸屏注册成 input 设备后LVGL 可以通过 indev 接口读取坐标。这样上层 GUI 不用关心底层是电阻屏还是电容屏。// 注册触摸设备到 RT-Thread input 框架 static rt_err_t touch_read(rt_device_t dev, rt_off_t pos, void *buf, rt_size_t size) { struct rt_touch_data *data (struct rt_touch_data *)buf; rt_uint16_t x, y; touch_sample(x, y); >
返回列表