低速 Flash 与 1MB SRAM 下的通用缓存架构设计
嵌入式面试真题第 01 题:低速 Flash 与 1MB SRAM 下的通用缓存架构设计 问题在一款资源受限的嵌入式设备中,系统只有 1MB SRAM 和一块读延迟不稳定的低速 SPI Flash。业务需要从 Flash 中持续或按需读取资源包、配置表、字库、语音片段、模型分块、日志回放数据或其他离线资源,并供应用线程实时或准实时消费。 如果应用线程直接等待 Flash 读取,系统可能因为低速 I/O、随机访问、文件碎片、擦写干扰或后台任务抢占而出现卡顿、超时或数据供应不连续。你会如何设计一套通用 Buffer/Cache 机制,使应用线程尽量读取 SRAM 中已经准备好的数据,而不是直接阻塞等待 Flash? 回答结论:不要让应用线程直接等待低速 Flash。更合理的设计是在应用和 Flash 之间增加一层 SRAM Cache/Buffer Manager:应用优先读 SRAM 中已经准备好的数据;后台 I/O Worker 根据访问模式、缓存水位和请求压力提前把 Flash 数据搬入 SRAM;缓存层再用 Ring Buffer、...
CANopen CiA 协议全景:核心内容、重点与组合关系
CANopen CiA 协议全景:重点规范、核心内容与组合关系 @[toc] 本文面向 CANopen 工程学习、设备选型、对象字典设计和协议组合判断。本版按你的要求移除了原文末尾的项目建议和评审清单类章节。图片均为 PNG,不包含 SVG;交付格式为 Markdown + images 目录。 1. 结论CANopen 的协议体系可以按三层理解: 通信基础层:以 CiA 301 / CiA 1301 为核心,定义对象字典、通信服务和网络管理。 横向功能层:例如 CiA 320 处理 sleep/wake-up,CiA 710 处理 bootloader,CiA 305 处理 LSS,CiA 306 处理 EDS/DCF。 设备与应用 Profile 层:例如 CiA 401、402、406、445、461、434 等,为某类设备定义应用对象、过程数据、配置参数、诊断信息和默认 PDO 思路。 本版重点单独展开 8 个规范:CiA 320、CiA 710、CiA 401、CiA 402、CiA 445、CiA 406、CiA 461、Ci...
CANopenEditor 从新建工程到导出 EDS OD
CANopenEditor 从新建工程到导出 EDS / OD.c / OD.h 从新建工程开始先新建空工程执行: 1File -> New 此时左侧显示 New Product,Object Dictionary 里还没有完整的 CiA 301 通信对象。不要直接在空工程里逐个手写 0x1000、0x1018、0x1200、0x1800、0x1A00 等标准对象,容易漏子索引、数据类型、访问权限和 CANopenNode 导出属性。 插入 DS301 profile执行: 1Insert Profile -> DS301_profile.xpd 这里的含义是: 项目 含义 DS301_profile.xpd CiA 301 通信对象 profile,提供标准通信对象候选项 DS301_profile_old.xpd 旧版本 profile,除非兼容旧工程,否则不优先使用 DS401_profile.xpd I/O 类设备 profile,只有做对应设备类型时再插入 DSP302-NMTMaster.xp...
由于 Cortex-M 栈未满足 8 字节对齐导致的问题与原因分析
# 由于 Cortex-M 栈未满足 8 字节对齐导致的问题与原因分析 @[toc] 嵌入式工程中,栈对齐通常不会被单独拿出来讨论。很多 Cortex-M 工程长期使用 4 字节对齐的内存访问,也能正常启动、跑任务、处理中断,因此“栈必须 8 字节对齐”看起来不像一个硬性问题。真正容易暴露问题的场景,往往出现在变参函数、64 位数据、浮点参数、启动阶段 C 代码、异常入口,以及手写汇编与编译器生成代码混用的边界上。 这篇文章从规定开始,解释为什么 Cortex-M 工程需要关心栈的 8 字节对齐;再说明不满足时可能出现什么现象;最后给出不同工具链脚本的查看方法和修改方法。 一、规定:公开接口处 SP 必须 8 字节对齐AAPCS32 是 Arm 32 位架构的过程调用标准。它规定函数之间如何传参、如何返回、哪些寄存器由调用者保存、哪些寄存器由被调用者保存,以及栈指针需要满足什么约束。 在 AAPCS32 中,栈有两层约束: 位置 要求 含义 任意时刻 SP mod 4 = 0 栈指针至少按字对齐 函数公开调用边界 SP mod 8 = 0 栈指针必须按双字对...
CANopen PDO 运行流程
CANopen PDO 运行流程 @[toc] PDO 不是“带 index/sub-index 的小 SDO”,也不是“谁发给谁的一问一答报文”。它更像一条预先约定好格式的实时数据通道:发送方把对象字典里的几个变量按固定顺序塞进一个 CAN 数据帧,接收方再按自己的 PDO 映射表把这些字节拆回本地对象字典变量。 理解 PDO 时要先把两个问题分开: 协议规定 PDO 应该是什么样。 包括它为什么只有过程数据、为什么要靠对象字典配置、为什么要区分 RPDO/TPDO、为什么 transmission type 会影响触发时机。 CANopenNode 源码怎样实现这些规定。 包括 CO_CANopenInitPDO() 如何初始化每个 PDO,CO_PDO_receive() 为什么只缓存,CO_RPDO_process() 为什么等到主循环才写 OD,CO_TPDO_process() 又为什么要同时看 SYNC、event timer、inhibit timer 和 sendRequest。 本文按这个顺序讲。前半部分先把协议模型讲清楚,后半部分...
CANopen TIME/SYNC 运行流程
CANopen TIME/SYNC 运行流程 @[toc] 1. 先把 TIME 和 SYNC 分开TIME 和 SYNC 都属于 CANopen 的特殊功能通信对象,但它们解决的问题不同: 对象 核心问题 默认 CAN-ID 数据长度 典型用途 SYNC “什么时候进入一个同步周期?” 0x080 0 或 1 同步 TPDO/RPDO、周期采样、周期控制 TIME “网络当前时间是多少?” 0x100 6 网络时间校准、时间戳、日志时间基准 一句话区分: 1SYNC 是节拍;TIME 是时钟。 SYNC 不携带实际过程数据,它只广播一个同步事件。同步 PDO 在这个事件前后按配置动作。TIME 也不携带过程数据,它只携带“当天毫秒数 + 自 1984-01-01 起的天数”。 2. 协议侧:SYNC 规定了什么2.1 SYNC 的角色SYNC 使用 producer/consumer 模型: 1234567flowchart LR P["SYNC producer<br/>周期发送同步对...
CANopen 搞懂 SDO client/server 运行流程
CANopen 搞懂 SDO client/server 运行流程 @[toc] 先给结论SDO(Service Data Object)是 CANopen 里用于读写对象字典的标准服务。它不是实时过程数据通道,也不是 Heartbeat 那类状态上报通道。它更像“标准化的配置/诊断访问入口”: SDO 永远由 client 发起。client 访问另一个节点的对象字典;拥有对象字典的一方是 server。 download / upload 是站在 server 角度命名。 SDO download:client 把数据写入 server 的对象字典。 SDO upload:client 从 server 的对象字典读取数据。 普通 CANopen 从机必须有 SDO server;SDO client 通常是可选的。一个普通 STM32 从机被主站配置,只需要 CO_SDOserver;只有当前节点要主动读写别的节点时,才需要 CO_SDOclient。 CANopenNode 的 SDO 实现是非阻塞状态机。CAN 接...
CANopene Heartbeat运行流程
CANopene Heartbeat运行流程 @[toc] 123456789101112131415flowchart LR subgraph PNode["远端 Heartbeat Producer<br/>Node-ID = n"] P_OD["OD 0x1017<br/>Producer heartbeat time<br/>配置发送周期"] P["Heartbeat producer<br/>周期 = producer time"] P_OD --> P end P -->|周期广播| Frame["CAN 数据帧<br/>COB-ID = 0x700 + n<br/>DLC = 1<br/>Byte0 = NMT state"] Frame -->|CAN 接收过滤| Cons["Heartbeat consu...
CANopen NMT:搞懂 NMT 运行流程
CANopen NMT:搞懂 NMT 运行流程 @[toc] 先给结论NMT 是 CANopen 的网络管理状态机控制协议,Heartbeat 是配套的节点在线与状态上报机制。在 CANopenNode 里,CO_NMT_Heartbeat.c/h 不是单纯“收一帧命令就切状态”的代码,而是把以下功能合在一个对象 CO_NMT_t 里: NMT slave / NMT consumer:接收 CAN-ID 0x000 的 NMT 命令,目标 Node-ID 为 0 或本节点时才处理。 Heartbeat producer:用 CAN-ID 0x700 + nodeId 周期发送本节点 NMT 状态;初始化阶段还会发 boot-up message。 NMT 状态机执行点:真正状态切换不在 CAN 接收回调里完成,而是在 CO_NMT_process() 周期调用中完成。 错误条件联动:可根据 CAN bus off、Heartbeat consumer 错误、Error register mask,把 Operational 自动降到 Pre-operation...
CANopen Emergency: 搞懂 EM 运行流程
CANopen Emergency: 搞懂 EM 运行流程 @[toc] 先给结论Emergency(下文简称 EMCY 或 EM)不是普通日志,也不是 PDO。它是 CANopen 用于故障事件上报的标准机制。CAN in Automation 对 EMCY 的公开说明包括:由设备内部错误触发、映射到单个 CAN Classic 帧、内容包含 0x1001 error register、16 位 emergency error code 和最多 5 字节制造商信息,默认 CAN-ID 为 0x80 + node-ID,且同一 error event 只发送一次。[^cia-emcy] 在 CANopenNode 的 301/CO_Emergency.c/h 中,运行链路可以压缩成: 1234567应用/协议栈检测到错误变化 -> CO_errorReport() / CO_errorReset() -> CO_error() 修改 errorStatusBits[] 并写入 FIFO -> CO_EM_process() 周期运行 ...







