ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MCU外挂PSRAM:APS6404L 8MB内存扩展实战

MCU外挂PSRAM:APS6404L 8MB内存扩展实战 最近做的一个项目里MCU 要跑图形界面、音频处理和一堆状态机逻辑内置 RAM 直接顶爆。翻遍了手头的库存最后盯上了 APS6404L-SQH-SN 这个型号。这是一颗 64Mbit也就是 8MB的 PSRAM给 MCU 当外部大内存用空间一瓶直接顶到 8MB算是把“小单片机跑大程序”这个局给解开了。这个过程里有不少硬件连接和驱动时序的坑今天把这些经验整理出来给打算外挂内存的同行们一个参考。1. 为什么 MCU 会需要外挂一颗 64Mbit 的内存很多人对 MCU 的印象还停留在“跑跑裸机流水灯、控制个电机”的阶段觉得内存给个几十 KB 绰绰有余。但真把项目做深了就会发现内存瓶颈对 MCU 的制约非常明显已经到了不改不行、不扩展不行的地步。1.1 内置 RAM 的天生瓶颈以典型的 Cortex-M 系列为例很多中高端 MCU 内置 RAM 通常只有 128KB 到 512KB看着数字不小可实际分配时却处处捉襟见肘。先算账一颗 320×240 的 RGB565 屏幕一个完整帧缓冲需要 320×240×2 字节算下来是 153600 字节也就是 150KB。光一个 framebuffer 就把 128KB 的 RAM 干穿了再算上系统栈、RTOS 任务栈、协议栈缓冲区内置 RAM 根本装不下。底层原因在于MCU 芯片内部 RAM 通常用 SRAM 单元实现。SRAM 每个 bit 需要 6 个晶体管才能存住数据密度低、成本高、功耗也不低。芯片厂商不可能在 MCU 内部塞大容量的 SRAM因为 die size 会被撑得巨大晶圆成本直接起飞。所以常见 MCU 内置 RAM 长期停留在几十 KB 到几百 KB 的水平不是厂商不想给是 SRAM 这种结构本身就贵。还有一层原因很多 MCU 的带 Flash 型号Flash 和 RAM 共用一块地址空间RAM 空间本身被限制在固定的地址映射区域内。比如某些系列 RAM 地址上限就是 0x2000 0000 开始的若干 KB想扩都扩不了因为地址没有预留空间。1.2 什么场景在逼着 MCU 往上走这几年 MCU 端应用的复杂度明显在涨动不动就要跑 LVGL 图形库、TCP/IP 协议栈、音频采集回放、神经网络推理、数据加密解密。这些任务对内存的需求是突发性的大块分配平时空闲时可能几十 KB 就够一旦跑 GUI 动画、存储一段长录音缓存几百 KB 打不住1MB 甚至更多才稳。我具体遇到的场景是项目里要同时跑 mongoose Web 服务器做参数配置页面这个库本身不算重但加上 HTTP 解析、WebSocket 缓冲区、JSON 序列化临时变量内存消耗唰唰往上走。还有一个状态机驱动的过程控制逻辑需要把整段时间内的传感器原始数据保存在环形缓冲区里方便事后故障诊断回放。这两个需求加一起内置 RAM 根本扛不住我就意识到外挂内存是绕不开的路。另外现在 MCU 上用的很多软件中间件比如 FreeRTOS 的任务栈、事件分组、消息队列加上各种驱动库的DMA缓冲区每一样看起来只吃几 KB林林总总加起来就成了压死骆驼的最后一根稻草。与其不断优化内存分配策略、抠每一块静态内存不如直接外挂一颗大内存把内存天花板抬起来软件开发成本反而更低。1.3 为什么偏偏是 PSRAM 而不是 SRAM、DRAM、Flash外扩内存的方案理论上不止一种有外部 SRAM、SDRAM、NOR Flash 转 RAM、甚至直接换一个大 RAM 的 MCU但实际权衡下来PSRAM伪静态随机存储器是最适合 MCU 的方案。SPI SRAM 虽然接口简单容量做到 8MB 的也不常见而且价格贵。SDRAM 容量大、价格便宜但需要 MCU 带 SDRAM 控制器引脚多、刷新逻辑复杂一般只有 ARM9 以上的应用处理器才有。给普通 MCU 上 SDRAM成本和复杂度都不值当。PSRAM 很有意思它在接口上表现得像 SRAM存储单元其实是 DRAM。芯片内部集成了刷新电路外部接口不需要像 SDRAM 那样定期发刷新命令看起来跟普通 SRAM 一样随机读写即可。这样 MCU 侧完全不需要复杂的 SDRAM 控制器普通的 QSPI 接口就能驱动甚至 DMA 都能参与传输。APS6404L 就是这种 PSRAM 的典型代表用 SPI/QPI 接口和 MCU 通讯引脚只占四根数据线加一根时钟、一根片选硬件改动极小软件上把它当成一块大容量外设来管理就行。这个思路说白了是用一个管脚开销小、易驱动、容量又够大的中间方案绕开了 SRAM 贵、SDRAM 难的怪圈。用在跑 GUI 和网络协议栈的 MCU 上刚好处在甜点区。2. APS6404L 这颗芯片到底怎么读APS6404L-SQH-SN 这个型号看起来长串拗口拆开看其实信息量很大每一段都代表了这颗芯片的关键规格。拿货之前得先会看型号不然拿错电压版本、搞错封装整个设计就废了。2.1 型号逐段拆解先看前缀“APS6404L”。APS 是厂商的 PSRAM 产品系列代号6404 是容量标识表示 64Mbit 大小也就是 8MB。后面的 L 通常关联工作电压范围或者功耗等级具体得对厂商手册。中间“SQH”是封装形式标识指的是 SOP-8 封装业界经常叫 208mil 或 150mil 的宽体/窄体 SOP具体宽度对引脚间距手册。最后“SN”一般表示无铅、环保等级或者代表温度范围是工业级 -40°C 到 85°C。如果你的项目工作在 -40°C 以下的极端环境或者对功耗有严格限制下单前务必去官网核对当前批次的具体规格确认电压范围、温度等级别光看丝印长得一样就往上焊。我自己就吃过这种亏供应商发来一颗同样丝印的料引脚定义一致但电压等级不同直接导致高电平闩锁问题整块板子工作异常。2.2 内部结构和协议模式APS6404L 内部存储阵列是 DRAM 结构容量 64Mbit分成若干行和列通过内部刷新电路定时给电容补充电荷保证数据不丢失。这也是“伪静态”名字的由来——外部访问方式和静态 RAM 一模一样写地址给数据就行完全不需要 MCU 操心刷新时序。对外通讯接口支持多种模式包括标准 SPI 模式、双 SPIDual SPI、四 SPIQuad SPI也叫 QPI模式以及带 DDR 功能的 QPI 模式。标准 SPI 用一根数据线传数据频率低、速度慢但任何 MCU 的 SPI 外设都能驱动。QPI 模式下四根数据线同时传输配合 DDR双沿采样时钟上下沿都传数据吞吐率大幅提升。想要榨干这颗芯片的性能就得用上 QPI DDR 模式。芯片内部通过 mode register 设置工作模式上电后默认可能是标准 SPI 模式需要 MCU 发命令切换成 QPI 模式然后才能跑高速读写。如果只追求简单稳定不追求极限速度标准 SPI 模式也能用数据吞吐确实低不少。我实际项目中用的是 QPI 模式MCU 侧 SPI 外设刚好支持四线模式直接连就行。2.3 关键电参数和引脚定义硬件设计前必须关注的参数包括供电电压、待机电流、读写时序、输入输出逻辑电平。APS6404L 通常有 1.8V 和 3.3V 两种供电型号后缀不完全相同务必确认你手里那颗到底工作在哪个电压。供电电压错了轻则读写异常重则芯片直接烧掉。SOP-8 封装的引脚定义大致包括CS#片选输入低电平有效。PSRAM 芯片选通的关键引脚拉高时芯片忽略所有输入信号。CK/SCLK时钟输入所有命令和数据都在这个时钟节拍上采样。SI/SIO0数据输入/输出引脚标准 SPI 模式下是串行输入QPI 模式下变成双向数据线 D0。SO/SIO1数据输出/输出引脚标准 SPI 模式下是串行输出QPI 模式下变成双向数据线 D1。HOLD#/SIO2、WP#/SIO3这两个引脚在标准 SPI 模式下是保持和写保护功能切到 QPI 模式下后变成数据线 D2、D3负责双向数据传输。针对引脚配置特别注意一点如果只用标准 SPI 模式建议把 WP# 和 HOLD# 引脚固定拉到电平正确的状态防止悬浮导致意外进入保持或写保护。如果要用 QPI 模式两个引脚作为数据线直接接 MCU 对应的数据引脚即可。还有一点芯片访问是 8 位寻址的但很多 PSRAM 也支持 XIP直接在外部执行方式也就是代码可以直接从 PSRAM 里跑。这对某些 RAM 不够想扩程序加载空间的场景很实用但需要 MCU 端的 QSPI 控制器支持内存映射模式。不是所有 MCU 都有这个能力选型时要看数据手册里有没有 QSPI memory-mapped 功能。3. 硬件设计把 PSRAM 接到 MCU 上要注意什么硬件连接看起来就是几根线的事但实际画板子、调板子时有不少容易踩歪的地方。高速信号布线、电源去耦、启动状态的引脚逻辑每一个都可能在外挂内存这个环节上翻车。3.1 引脚连接方案和模式选择给 MCU 外挂 PSRAM优先选四线 QPI 模式因为吞吐率最好。MCU 侧要用具备四线 SPI/QSPI 功能的外设通常叫 QuadSPI。连接关系很直白MCU 的四条 IO 线对应芯片的 SIO0 到 SIO3时钟输出接 CK片选接 CS#。这里有个容易忽略的点很多 MCU 的 QSPI 外设和普通 SPI 外设在引脚复用上是冲突的需要检查 PF0 或者 PB2 之类的引脚是否被烧录器、调试器、用户按键占用。我遇到过一次MCU 的 QSPI 引脚和板上一个拨码开关共用结果拨码开关瞬间的接触抖动被当成时钟信号灌进 PSRAM导致偶发读写错乱。后来改成用跳线隔离才解决。另外如果 MCU 的 QSPI 外设不支持 4 线模式只能用标准 SPI 模式驱动 PSRAM此时 SIO2 和 SIO3也就是 HOLD# 和 WP#要处理干净不要悬空。特别是 HOLD# 引脚如果悬空被噪声拉低PSRAM 会进入暂停状态时钟和数据都被忽略看起来就像芯片死掉一样。通常做法是通过上拉电阻拉高让它保持非保持状态。模式的选择还影响软件复杂度。标准 SPI 模式只需要 MCU 软件模拟时序或者用普通 SPI 发送字节调试简单QPI 模式需要额外配置 MCU 外设的引脚方向、三态控制还要发切换命令软件流程要多几步。前期验证建议先用标准 SPI 跑通基本读写确认硬件无误后再切换到 QPI 模式提升速度。3.2 电源和去耦的细节电源是 PSRAM 稳定工作的前提这颗芯片对电源噪声挺敏感因为内部是 DRAM 结构靠电容电荷保存数据电源波动直接影响刷新可靠性。给 PSRAM 供电的电源轨上至少要放一个 100nF 陶瓷电容靠近芯片电源引脚放置再并联一个 1uF 到 10uF 的容量电容稳住低频波动。去耦电容不要离芯片太远PCB 布线时从电源引脚出来先过电容再到电源平面路径越短越好。如果 MCU 和 PSRAM 共用同一路电源要留意电源波动可能互相干扰。我在调试中发现电机启动瞬间电源跌落几百毫伏PSRAM 的读写偶尔会出故障。后来把 MCU 和 PSRAM 的电源做了简单隔离在电源路径上串了磁珠问题就稳定了。还要确认芯片 VCC 电压和 MCU IO 的电压匹配。如果 MCU 是 3.3V IO而 PSRAM 是 1.8V 供电电平不匹配会导致读数据误判需要对 IO 线做电平转换反过来 PSRAM 供电高于 MCU IO 能力也可能损坏 MCU。最舒服的方案是二者电压一致比如 MCU 和 PSRAM 都工作在 3.3V直接互连即可。3.3 PCB 布局和信号完整性PSRAM 如果工作在几十 MHz 的时钟频率下PCB 布线就不能太随意了。虽然 QSPI 接口不像 DDR3 那样要求等长严格但注意几条原则能省很多事时钟线尽量短避免走线过孔过多四根数据线走线长度尽量一致减少偏斜CS# 和时钟线不要靠得太近防止片选信号在时钟边沿附近抖动造成误采样。地平面尽量保持完整不要在下层走线把 PSRAM 周围的地平面切碎。如果实在做不到完整地平面至少在芯片下方留一块完整的地铜作为信号回流的参考面。一个我踩过的坑样品阶段用飞线连 PSRAM线长在 15cm 左右标准 SPI 低速模式还能跑切到 QPI 高频模式后完全废掉读回来的全是乱码。后来把 PSRAM 直接贴在 MCU 附近走线压到 2cm 以内问题立刻消失。高频信号对寄生电感非常敏感低电平采样窗口本来就很短飞线电感一拉时序全乱了。4. 软件驱动初始化、读写时序和性能评估硬件焊好之后的重头戏在软件。PSRAM 虽然是“伪静态”访问方式像 SRAM但毕竟不是真正静态 RAM命令序列、模式寄存器配置、时序操作都得按芯片手册来读错命令序可不会给你提示数据就是错的。4.1 初始化序列详解APS6404L 上电后是默认 SPI 模式需要用命令把它切到 QPI 模式并设置好等待周期latency参数。标准流程大致为上电后保持 CS# 置高芯片处于待机状态。拉低 CS#发送 Reset 命令通常是 66h再发送 Reset 确认命令99h完成芯片复位。发送进入 QPI 模式的命令通常是 35h芯片进入 QPI 模式。这里有讲究进入 QPI 模式的命令本身是在标准 SPI 模式下发的一旦发送成功后续所有命令都以 QPI 模式传输。所以 MCU 侧外设必须在发送命令后立刻把 IO 方向配置成四线双向模式否则后续时序会乱套。我见过不少新手在这里卡住命令发完MCU 外设还停在标准 SPI 输出模式四根线的三态没切好PSRAM 根本收不到后续数据。进入 QPI 模式后还需要通过写模式寄存器配置读操作的等待周期。等待周期可以理解为读命令发出后数据要等多少个时钟周期才有效。不同频率下的推荐等待周期不同频率越高需要的等待周期越多。配置模式寄存器的命令格式和字段位置必须看芯片手册不同地址对应不同寄存器别想当然。初始化完成后推荐做一次全地址写读校验往所有地址写入递增模式数据再读回来验证。校验通过说明模式配置成功硬件时序正常再进入实际应用层。我习惯把这段校验代码放在上电启动阶段应用跑起来后会大大减小排查难度。4.2 读写的具体时序和命令在 QPI 模式下读操作发送命令字节加 24 位地址之后等待若干 latency 周期然后接收数据。写操作则是发送命令和地址后直接跟要写入的数据。命令字节和地址都是四根线并行传的所以一字节命令只需要两个时钟周期就传完。有几个细节要特别注意页长度PSRAM 通常按页组织页大小常是 1024 字节或 2048 字节。跨页连续写或连续读时地址会自动回卷到页起始位置如果不做处理数据会写到错误的位置。驱动程序里一定要做跨页边界处理把一次大块读写拆成多段不超过页边界的传输。等待周期不同读命令有不同的等待周期设置写操作也有相应的等待。设置模式寄存器之后驱动里的实际读时序必须和配置一致否则高速模式下一开始还能出数据跑着跑着数据就错位了。字节序MCU 的内存访问有大小端之分PSRAM 数据线没有字节序概念纯粹是按 bit 传输但 MCU 端 DMA 或 CPU 读写外设寄存器时如果外设数据寄存器和内存字节序不匹配数据组合会乱。建议在驱动初始化时先做一个小端/大端测试写一个已知模式再读回来看。DDR 模式下数据线上每个时钟边沿都采样一次这对 MCU 外设的要求更高。如果 MCU 的 QSPI 外设不支持 DDR就不要硬开 DDR 模式否则读回来的数据全是乱的。选型时这一点必须提前确认。4.3 性能估算到底能跑多快很多人想知道外挂 PSRAM 到底比内置 SRAM 慢多少这直接影响能不能用它跑实时性要求高的任务。拿一颗跑在 80MHz 的 MCU、QSPI 外设在 80MHz 时钟下举例标准 SPI 模式每时钟传 1 bit读一字节 8 bit 需要 8 个时钟周期加上命令、地址、等待时间实际读吞吐大约在 80Mbit/108MB/s 左右。切到 QPI 模式后每时钟传 4 bit读一字节平均只需要 2 个时钟周期再算上命令和等待开销实际吞吐大概可以到 20MB/s。DDR QPI 模式理论上还能翻倍但实际受制于 MCU 端外设和芯片时序能到 30MB/s 已经很不错了。这个速度和内部 SRAM 动辄几百 MB/s 比不了但应付 GUI 刷屏、音频缓存、网络数据缓冲区绰绰有余。关键应用里把高频访问的数据放在内部 SRAM把低频大块数据放到 PSRAM是常见的性能优化策略。我在项目里就是把 framebuffer 放 PSRAM但把图像裁剪、alpha 混合的临时缓冲放在内部 RAM画面流畅度基本没受影响。5. 实际应用外挂 64Mbit 内存能在项目里干什么8MB 空间对 MCU 来说是个质变不是量变。很多以前想都不敢想的方案有了这颗内存后可以轻松落地。分享一下我在实际项目里的几个典型用法大家可以按自己的场景举一反三。5.1 图形界面 framebuffer 不再是奢侈品跑 LVGL 或其他 GUI 库时最头疼的就是帧缓冲和脏矩形缓冲。320×240 的 RGB565 屏幕一个完整 framebuffer 占 150KB再上到 800×480光一帧就是 768KB。把 framebuffer 放到 PSRAM 后不仅能跑高分辨率还能做双缓冲GUI 动画切换时先渲染到后台缓冲再整体复制到显示缓冲画面撕裂问题直接消除。Framebuffer 从内部 RAM 移到 PSRAM刷屏速度会下降但屏幕刷新本身就是一个周期性 DMA 传输过程DMA 从 PSRAM 读数据送到 LCD 控制器CPU 完全不用介入。实测下来LCD 刷新率从 60fps 降到 50fps 左右视觉上几乎没有差别换来的是内存空间暴涨可以同时开好几个页面缓存和字体缓冲开发体验好很多。5.2 音频缓冲录音、回放和播放列表一起扛音频应用是内存大户尤其做语音识别或长时间录音的项目。48kHz 采样、16bit 单声道每秒数据量是 96KB如果只是 24KB 内置 RAM录音 0.25 秒就满了啥都干不了。外挂 8MB 后可以这样分配分配一个 4MB 的环形缓冲做长时间录音缓存录音数据先写到 PSRAM后台慢慢搬运到 Flash 或者直接上传再分配一个 512KB 的播放缓冲存放多首提示音或者常用语音片段。音频流的实时性要求不苛刻数据传输通过 DMA 在 PSRAM 和音频外设之间搬运再加上环形缓冲区的够大jitter 完全被吸收。实际效果是录音长度从秒级直接跳到了分钟级再配合压缩编码做个小录音笔、语音助手都够用。5.3 状态机日志和故障诊断缓冲区这是很多人容易忽略的场景。MCU 跑复杂状态机时出故障后想排查到底哪个状态跳转出了问题最需要的是一份完整的运行轨迹。传统做法是往串口打日志但日志格式和频率一高串口就成了瓶颈。把运行日志写到 PSRAM 里的环形缓冲区每条日志记时间戳、状态编号、输入事件、跳转结果循环覆盖写掉电前再把整个缓冲区的数据转储到外部存储故障现场就完整保留了。我的项目里就是这么实现的用 1MB 空间做状态机事件日志记录 10 万条以上的活动记录故障诊断时可以像看录像回放一样找出问题所在。这个方案在空间充裕的前提下极大提升了产品问题定位效率。还有一个用途是保存大表格数据、传感器校准参数、字库或算法系数。以前这些数据要么硬编码到 Flash要么每次现算现在可以直接放 PSRAM运行时动态生成和更新灵活性上一个档次。6. 常见问题排查与避坑实录外挂内存这种事理论通畅实操全是坑。我把自己和同行交流中遇到的高频问题整理出来做成一个速查清单大家调试时可以对号入座。6.1 读回来的数据错乱时好时坏这类问题优先查电源和时序其次查模式配置。常见原因有三个供电电压偏低或电源纹波大导致芯片内部 DRAM 单元刷新不稳定。用示波器测量 PSRAM 电源引脚的纹波确保低于 50mV。纹波超标就在电源入口加磁珠和加大容量电容。时钟线过长或走线细导致时钟边沿退化。降低 SPI 时钟频率试一下如果降频后稳定多半是信号完整性问题重新布线或加驱动能力。模式寄存器配置的等待周期和实际执行频率不匹配。尝试增大等待周期给数据输出留更充足的时间。6.2 芯片完全不响应读写没反应先检查 CS# 是否被正确拉低HOLD# 是否被意外拉低。HOLD# 被拉低时芯片暂停工作所有输入都忽略。如果 HOLD# 引脚悬空再加上 PCB 上有些噪声芯片可能随机进入保持状态。解决办法是 HOLD# 引脚接上拉电阻或直接接高电平。再检查时钟是否正常。用逻辑分析仪看 CK 引脚有没有时钟输出时钟幅度太小也会让芯片无法采样。如果 MCU 侧的 SPI 外设时钟使能没开这问题也会出现。6.3 上电初始化就卡住连复位命令都没反应这种问题基本是上电时序问题。PSRAM 要求电源稳定后再拉高片选如果芯片在电压未稳定时就被操作内部状态机可能锁死。解决办法是在上电后延时 1ms 到 10ms再执行复位命令。我习惯在初始化代码里加一个 5ms 的延迟专门等电压稳定。还可能是因为复位后立刻进入 QPI 模式而 MCU 自己还没把外设切到 QPI 模式两边不同步。复位后严格按手册推荐的等待时间操作给芯片一点反映时间。6.4 大块数据写崩了越界写坏相邻数据这类问题大概率是跨页处理没做。PSRAM 的页回卷特性意味着写地址到页尾后继续写会自动回到页头开始覆盖。驱动层必须对每次访问做地址检查和分段保证单次连续访问不跨越页边界。同时也检查 DMA 突发长度如果 DMA 配置的突发长度跨越了页边界同样会出现数据错乱。6.5 启动阶段不能让 PSRAM 影响 MCU 启动很多 MCU 上电后会检测特殊引脚的电平状态来决定启动模式比如 BOOT0 或者 QSPI 片选相关的引脚。如果这些引脚被 PSRAM 电路占用或者电平不对MCU 可能启动不了甚至启动到错误模式。设计硬件时要检查 PSRAM 连接引脚是否和启动配置引脚冲突或者加一个启动延时电路确保 PSRAM 在 MCU 完成启动后再被操作。7. 给后续项目选型和外扩内存的三点建议外挂内存这条路走通之后回头看有几个经验是通用且值得沉淀的分享给后续准备这么搞的同行。第一先评估你的 MCU 到底能不能驱动这颗 PSRAM。不是所有 MCU 都有 QSPI 外设这个外设能否支持 QPI 四线模式、能否 DDR 采样、有没有内存映射功能选型和设计前必须确认清楚。如果硬件不支持却硬上只能软件模拟 SPI速度会差好几个数量级很多场景直接不实用。第二能不用 DMA 就别用 CPU 搬运。PSRAM 作为外部内存CPU 逐字节读写会卡在等待状态里效率极低。所有大块数据搬运都用 DMA启动 DMA 后 CPU 可以继续做其他事情。注意 DMA 的突发长度和页边界限制提前在驱动层做好拆分。第三给驱动留一个调试接口。初始化时做全地址回读校验运行时提供读写计数、错误计数、时钟频率打印等诊断信息。这些接口平时不占用资源一旦现场出问题能快速区分是软件读写错误还是硬件时序问题省掉大量排查时间。从我个人实际体验来看外挂 PSRAM 这件事难度不在于读懂芯片手册而在于硬件细节和软件配置的协同。只要电源干净、时序正确、页边界处理到位这颗 64Mbit 的大内存用起来相当顺手MCU 项目能做的事情一下子就打开了。
返回列表