1. 项目概述与核心挑战最近在做一个对PCB尺寸有严格限制的嵌入式项目主控芯片选用了先楫半导体的高性能MCU HPM6750。为了压缩板子面积我放弃了引脚更丰富的BGA289封装HPM6750IVM2转而选择了更紧凑的BGA196封装HPM6750IAN2。这个选择带来了一个意料之外但又在情理之中的技术挑战BGA196封装的芯片没有引出XPI0控制器的CA端口引脚。XPIeXternal Program Interface是先楫HPM6000系列芯片用于连接外部串行NOR Flash的核心接口是实现代码在Flash中原地执行XIP的关键。官方评估板HPM6750EVKMINI默认使用XPI0的CA端口具体是CA_CS0连接启动Flash。这意味着当我为了节省空间而使用CB端口时芯片上电后根本无法从默认的CA端口找到Flash自然也就无法启动。这个问题的本质是需要引导芯片内部的BootROM在启动初期就去访问一个“非默认”的物理引脚组CB端口并在后续阶段确保Flash控制器能被正确配置以驱动这些引脚。整个过程涉及到底层OTP配置的修改、启动镜像中配置数据结构的调整以及烧录工具链的适配是一套完整的、从硬件到软件的启动链路定制。2. 硬件设计与启动流程深度解析2.1 引脚资源差异与选型决策先楫HPM6750芯片的XPI控制器功能强大支持多组片选CS和端口Port。简单来说你可以把它想象成一个有多组“接线端子”的Flash读写器。CA端口和CB端口就是其中两组独立的“端子排”它们都能连接Flash芯片但物理上连接到芯片不同的引脚上。查阅HPM6750IAN2BGA196的数据手册引脚复用表会发现一个关键信息XPI0_CA相关的信号线如CA_SCLK、CA_CS0、CA_DQ[3:0]等在BGA196封装上根本没有对应的物理引脚。而XPI0_CB端口的信号线则是完整引出的。这就好比你的设备默认插头是A型但墙上只有B型插座幸运的是设备内部其实也预留了B型插头的线路只是需要你手动切换一下内部的接线开关。这个“内部的接线开关”一部分是固化在芯片OTP中的配置另一部分则是存储在Flash开头、供BootROM读取的配置信息。选择CB端口纯粹是硬件封装限制下的唯一可行解。这要求我们必须深入理解芯片从上电到运行用户代码的完整链条并精准地修改其中的两个关键节点。2.2 BootROM启动流程与配置节点剖析HPM6750的启动过程是一个精密的自动化流程理解它对于解决问题至关重要上电复位芯片上电CPU从复位向量开始执行首先运行的是芯片内部固化的BootROM代码。这段代码是“只读”的用户无法修改。读取OTP配置BootROM会读取芯片内部一块称为OTPOne-Time Programmable的存储区域。OTP可以理解为芯片的“身份证”或“硬编码开关”一旦写入无法擦除。这里存放着影响启动行为的根本性配置其中就包括XPI_PORT_SEL这个字段。它告诉BootROM“我应该去哪个端口CA还是CB寻找Flash芯片”初始化XPI控制器根据OTP中XPI_PORT_SEL的值BootROM会初始化对应的XPI端口例如CB端口的控制器到一种最基础的、兼容性最强的模式通常是1位SPI模式。探测Flash并读取配置表BootROM通过刚初始化的端口尝试访问连接Flash的0x400地址偏移处。这里存放着一个非常重要的数据结构——XPI NOR配置选项表。这个表详细定义了如何与这块特定的Flash芯片通信是几线制1/2/4线时钟频率多高用什么命令序列来开启高性能模式重新配置并加载BootROM读取这个配置表后会按照表中的参数重新初始化XPI控制器。这次初始化会将端口配置成与Flash芯片匹配的最佳工作模式。之后BootROM才会从Flash的固定位置通常是0x1000以后加载用户应用程序代码到芯片内部的RAM中或者为XIP执行做好准备。跳转执行最后BootROM将CPU的执行权交给用户程序启动完成。从这个流程可以看出我们要修改两个地方节点AOTP告诉BootROM第一步去哪找CB端口。节点BFlash中的配置表告诉BootROM找到之后该怎么用用CB端口的配置参数。如果只改OTP不改配置表BootROM能在CB端口找到Flash但用CA端口的配置参数去驱动CB端口的物理引脚通信肯定会失败。反之如果只改配置表不改OTPBootROM第一步就去CA端口找根本找不到Flash流程直接中断。3. OTP配置修改实操与风险规避OTP操作是本次修改中最需要谨慎对待的环节因为其写入具有不可逆性。务必在操作前确认硬件连接稳定供电可靠。3.1 关键OTP字段解读根据HPM6750参考手册控制启动端口选择的OTP字段位于Word 24一个字为32位。我们需要关注的是其中的第6位即XPI_PORT_SEL位。XPI_PORT_SEL 0BootROM从XPI0 CA_CS0端口启动。默认值XPI_PORT_SEL 1BootROM从XPI0 CB_CS0端口启动。我们的目标非常明确将Word 24的值从默认的0x0000_0000修改为0x0000_0040即第6位为1。这里有一个非常重要的细节OTP中每个Bit通常只有从0写成1的能力反之则不行取决于具体OTP单元设计。先楫的这款OTP支持回写0但为了安全起见我们在修改时仍应遵循最小改动原则只改动目标位。3.2 使用HPMicro量产工具烧写OTP进入ISP模式将板卡上的BOOT模式拨码开关设置为BOOT_MODE[1:0] 0b10即1脚高位0脚低位。此模式会使芯片上电后进入系统编程状态等待主机连接。硬件连接通过USB线将板卡的USB0接口通常是Type-C连接到电脑。打开工具并连接运行HPMicro提供的量产工具HPMicro Programmer或类似工具。在工具中选择对应的USB设备点击“连接”。连接成功后工具界面会显示芯片型号、UID等信息。导航至OTP操作页面在工具中找到“OTP操作”或“Fuse”相关的标签页。读取当前OTP值点击“刷新”或“读取”按钮工具会读取芯片中所有OTP Word的当前值。找到Word 24确认其值为0x00000000。准备写入数据切换到“写视图”或“编程视图”。点击“添加Word”或类似按钮。在弹出的对话框中设置地址Address为24数据Data为0x00000040。务必仔细核对这两个数值。这里的0x40就是十进制64即二进制0100_0000第6位为1。执行写入再次确认地址和数据无误后点击“写入”或“编程”按钮。工具会执行OTP写入操作这个过程很快。验证写入结果写入完成后再次点击“刷新”读取OTP。检查Word 24的值是否已经变为0x00000040。注意OTP操作具有永久性在执行写入操作前请务必确认板卡供电稳定USB连接可靠避免在写入过程中断电。双重甚至三重核对目标Word地址和要写入的数据。错误的OTP配置可能导致芯片无法正常启动且无法恢复。建议在正式产品板上操作前先在有冗余的工程样板上进行全过程验证。3.3 验证OTP生效的简易方法修改OTP后将BOOT拨码开关切回XPI NOR启动模式例如0b00给板卡重新上电。此时最直接的验证方法不是看程序是否运行因为配置表还没改而是观察物理信号。使用逻辑分析仪或示波器探头连接到XPI0_CB_SCLKCB端口的时钟信号引脚。触发方式设置为上电触发或边沿触发。给板卡重新上电你应该能观察到BootROM在启动初期发出的一串SCLK时钟脉冲。这串脉冲是BootROM在尝试初始化CB端口并与Flash进行首次通信。如果能捕获到这个信号就铁证如山地说明OTP的XPI_PORT_SEL配置已经生效BootROM确实在访问CB端口了。如果测不到信号则需检查OTP是否写入成功、引脚连接是否正确。4. 修改XPI NOR配置选项与工程适配OTP指引BootROM找到了“门”CB端口接下来我们需要在“门口”Flash的0x400地址放一把正确的“钥匙”针对CB端口的配置表BootROM才能打开门并正确使用里面的东西。4.1 理解NOR配置选项数据结构这个配置选项表是一个由4个32位字Word组成的数组存放在Flash的绝对地址0x400处。对于我们修改端口而言最关键的是第一个Wordoption[0]其结构如下bit[31:28]: Header[3:0] - 固定为0xF标识这是一个有效的配置头。 bit[27:24]: Option[11:8] - Flash端口选择。 0: CA_CS0 (默认) 1: CB_CS0 (我们的目标) 2: CA_CS1 3: CB_CS1 ... 其他片选 bit[23:0]: 其他配置信息如时钟频率分频、指令模式等。因此为了选择CB_CS0端口我们需要将Option[11:8]字段设置为1。在默认的SDK配置中option[0]的值通常是0xFCF90000CA_CS0。我们需要将其修改为0xFCF90001吗不对注意看Option[11:8]对应的是bit[27:24]。0x1左移24位是0x01000000。所以正确的计算是0xFCF90000 | 0x01000000 0xFCF90000这里有个误区0xFCF90000的bit[27:24]已经是0x9了我们需要的是把这个半字节从0x9改成0x1。实际上SDK中常用的一个代表CB_CS0端口的魔数是0xFCF90002。我们来拆解一下0xFCF900020xFHeader有效。0xCbit[27:24]是0xC吗等等0xFCF90002是十六进制写成二进制更容易看1111 1100 1111 1001 0000 0000 0000 0010。取bit[31:28]是11110xF。取bit[27:24]是11000xC。参考手册0xC对应的正是端口选择值2二进制1100的十进制是12但这里字段映射可能不是直接等于而是某种编码。根据SDK源码和实际验证0xFCF90002这个值就是用于CB_CS0的标准配置。因此我们无需手动计算直接采用这个经验值即可将option[0]改为0xFCF90002。4.2 在自定义板级支持包中修改配置为了不污染SDK原文件最佳实践是创建自己的板级支持包BSP。创建自定义板级目录在你的项目目录下例如src/board/复制一份最接近你硬件设计的官方板级目录比如hpm6750evkmini。将其重命名为你自己的板子名称例如myboard。修改关键文件进入myboard目录找到board.c文件。使用编辑器或IDE的全局搜索功能查找名为.nor_cfg_option的section。你会找到类似如下的数组定义__attribute__ ((section(.nor_cfg_option))) const uint32_t option[4] { 0xfcf90000, /* 默认是CA_CS0: 0xfcf90000 需要改为CB_CS0: 0xfcf90002 */ 0x00000007, 0x00000100, 0x0 };应用修改将数组的第一个元素从0xfcf90000修改为0xfcf90002。修改后的结果如下__attribute__ ((section(.nor_cfg_option))) const uint32_t option[4] { 0xfcf90002, /* 修改为CB_CS0端口配置 */ 0x00000007, 0x00000100, 0x0 };其余三个值通常与Flash的读指令、 dummy cycle、强度设置有关如果使用的Flash型号与评估板一致则无需改动。4.3 配置CMake工程以使用自定义板级包你需要告诉构建系统使用你自定义的myboard而不是SDK中预定义的板子。在项目根目录的CMakeLists.txt中或者通过CMake命令行参数指定。使用SDK 1.2.0及以上版本时可以通过BOARD_SEARCH_PATH指定额外的板级包搜索路径。在项目根目录下执行类似如下的CMake命令假设使用Ninja作为生成器cmake -Bbuild -DBOARDmyboard -DBOARD_SEARCH_PATH./src/board -GNinja -DCMAKE_BUILD_TYPEflash_xip-DBOARDmyboard指定使用的板级包名称为myboard。-DBOARD_SEARCH_PATH./src/board告诉CMake除了SDK默认路径还要去./src/board目录下寻找板级包。-DCMAKE_BUILD_TYPEflash_xip构建在Flash中XIP执行的镜像。配置成功后使用Segger Embedded Studio (SES) 打开build目录下的工程在项目树中你应该能看到src/board/myboard/board.c已经被包含进来并且其修改已生效。编译项目生成最终的.bin或.hex文件。5. 镜像烧录与Flash特殊位配置生成正确的镜像后我们需要将其烧录到已连接在CB端口的Flash中。这里有一个关键点如何确保Flash芯片本身被正确配置以支持XPI控制器后续可能使用的四线Quad高速模式。5.1 使用HPMicro Programmer进行烧录连接与配置确保板卡处于ISP模式或正常运行模式如果BootROM能识别CB端口且Flash为空也可能进入编程状态。在HPMicro Programmer工具中连接你的设备。关键设置Connection Selection在工具的Flash编程相关设置区域找到Connection Selection或类似的选项。必须将其从默认的CA_CS0更改为CB_CS0。这个设置告诉编程器“请通过CB端口与Flash芯片通信。” 如果这里选错编程器将无法找到Flash。加载镜像文件选择你刚刚编译生成的.bin文件。工具通常会根据链接脚本自动识别出烧录的起始地址对于XIP程序通常是0x80000000之类的XPI映射地址但编程器会处理到物理Flash地址0x0的转换。配置Quad Enable Sequence关键步骤很多高性能的NOR Flash芯片其四线Quad SPI模式需要通过一个“使能序列”来开启即设置Flash内部状态寄存器Status Register中的一个非易失性位——QEQuad Enable位。这个位一旦设置掉电不会丢失。在HPMicro Programmer的Flash配置部分找到Quad Enable Sequence或QE Bit Setting。你需要根据你所使用的具体Flash芯片型号的数据手册来配置。以我使用的GD25Q40C为例查阅其数据手册可知QE位位于Status Register 2的Bit 1。使能Quad模式通常需要发送特定的写状态寄存器命令例如0x31并写入相应的数据。在工具中选择对应的配置。对于GD25Q40C通常可以选择类似“At bit1 in Status Register2”的选项。工具会自动生成正确的命令序列在擦除和编程操作前先对Flash执行这个“使能序列”将QE位置位。重要提示这个“Quad Enable Sequence”操作是通过编程器借助BootROM在烧录过程中一次性完成的。我们的应用程序镜像.bin文件和XPI NOR配置选项表option[0]里不需要也不应该包含设置QE位的指令。配置选项表中的Option[7:4]字段Instruction Mode如果设置为四线模式其前提是Flash的QE位已经被正确设置。因此正确的流程是先用编程器烧录并设置QE位之后芯片每次上电BootROM和应用代码都会基于已使能的Quad模式与Flash通信。执行烧录确认所有设置无误后点击“烧录”或“编程”按钮。工具会依次执行擦除、写入QE位如果配置了、写入你的程序镜像、校验等步骤。5.2 最终验证烧录完成后将BOOT拨码开关设置回正常的XPI NOR启动模式例如0b00给板卡重新上电复位。如果一切顺利你应该能看到程序开始运行通过LED闪烁、串口打印信息等用户程序定义的行为来验证。或者至少可以通过调试器连接到芯片看到PC指针在Flash地址空间内运行。如果失败请进入下一章节的排查流程。6. 问题排查与调试经验实录即使按照上述步骤操作也可能会遇到问题。以下是我在实际操作中遇到的一些典型情况及排查思路。6.1 常见问题速查表现象可能原因排查步骤上电后无任何反应调试器无法连接1. OTP配置错误BootROM跑飞。2. Flash配置表错误BootROM在二次配置后通信失败。3. 硬件连接问题虚焊、线接错。1.测量CB_SCLK用示波器看是否有启动时钟脉冲无则OTP或硬件问题。2.检查供电和复位确保芯片供电稳定复位引脚上电过程正常。3.回退验证尝试用编程器读取Flash 0x400地址内容看配置表是否正确写入。调试器可连接但PC指针不在Flash区或停在BootROMBootROM启动流程在某一步失败。1.查看BootROM日志有些芯片的BootROM会通过某个UART输出调试信息查看数据手册确认。2.单步调试BootROM如果支持在非常早期设置断点观察执行流。程序似乎烧录成功但运行行为异常如卡死、数据错乱1. Flash配置表中的时钟频率等参数与硬件不匹配。2. QE位未正确使能但配置表要求四线模式。3. 链接脚本中地址映射错误。1.降低配置表频率将option[0]中的时钟分频系数调大降低SCLK频率测试。2.确认QE位用编程器读取Flash的状态寄存器确认QE位是否为1。3.检查向量表确认中断向量表是否正确链接到了Flash的XIP地址区域。使用编程器无法连接或识别Flash1.Connection Selection端口选择错误。2. 板卡未进入ISP模式。3. Flash芯片型号选择错误或损坏。1.核对端口设置确保编程器选择的是CB_CS0。2.检查BOOT拨码确认是否为ISP模式0b10。3.尝试低速模式在编程器设置中尝试更低的通信速率。4.单独测试Flash有条件可将Flash拆下用通用编程器测试其好坏。6.2 深度调试技巧与心得逻辑分析仪是你的好朋友在SCLK、CS#、DQ0这些信号线上挂上逻辑分析仪解码SPI协议。你可以清晰地看到BootROM阶段发出的读取0x400地址的命令通常是0x03或0x0B以及Flash返回的数据。对比返回的数据和你编译生成的二进制文件中0x400位置的数据可以立刻判断配置表是否被正确写入和读取。这是最直接的证据链。利用BootROM的失败码部分高级MCU的BootROM在启动失败时会将一个特定的错误码写入某个通用寄存器如GPIO或SRAM中。查阅HPM6750的参考手册附录或BootROM章节看是否有此类设计。通过调试器在复位后第一时间读取该寄存器能快速定位是“Flash未找到”、“配置表校验错误”还是“镜像加载错误”。分阶段修改与测试不要一次性修改OTP和配置表。可以分两步走先只修改OTPXPI_PORT_SEL保持Flash中的配置表仍是CA端口的。用逻辑分析仪看CB_SCLK是否有活动。如果有证明OTP生效BootROM在尝试访问CB端口虽然会因为配置不匹配而失败。这一步验证了硬件链路和OTP修改的正确性。再修改配置表为CB端口进行完整烧录和测试。这样能将问题域隔离。关于Flash型号的兼容性board.c中的option数组后三个参数读指令、dummy cycle、等待周期与Flash型号强相关。如果你使用的不是评估板默认的Flash如W25QxxJV而是GD、MXIC、PUYA等其他品牌务必查阅其数据手册调整这些参数。一个常见的错误是dummy cycle数不对导致在较高时钟频率下读取数据错位。电源完整性检查当SCLK频率配置较高时如100MHz以上电源噪声可能严重影响Flash通信的稳定性。确保Flash芯片的VCC电源引脚附近有足够且响应快的去耦电容例如100nF 10uF组合并且电源走线尽可能短而粗。