深入解析PXD10 Flash保护机制:锁存、选择与用户测试寄存器实战

📅 2026/6/15 20:25:34
深入解析PXD10 Flash保护机制:锁存、选择与用户测试寄存器实战
1. 项目概述与核心价值在嵌入式开发尤其是汽车电子和工业控制这类对可靠性要求极高的领域微控制器MCU的Flash存储器远不止是一个简单的代码和数据仓库。它更像是一个需要严密守护的“保险库”既要保证固件在复杂电磁环境或异常掉电情况下的绝对安全又要支持在线升级、故障诊断等高级功能。飞思卡尔现为NXP的PXD10系列微控制器其Flash模块的设计就深刻体现了这种高可靠性的设计哲学。很多开发者初次接触这类MCU的参考手册时面对动辄几十页的Flash控制器章节尤其是其中密密麻麻的寄存器描述往往会感到无从下手。手册提供了所有位域的定义但寄存器之间如何协同工作、操作时序的“潜规则”、以及那些手册里不会明说的“坑”才是真正决定开发成败的关键。比如你以为简单地写一个值到锁定寄存器就能保护代码区结果发现操作无效或者在进行Flash自检时读回来的签名总是不对却找不到原因。本文将聚焦于PXD10 Flash模块中一组至关重要的寄存器锁存寄存器Locking Registers、选择寄存器Select Registers和用户测试寄存器User Test Registers。我不会仅仅复述手册中的位定义而是会结合我多年在汽车ECU开发中的实际经验深入剖析这些寄存器背后的设计逻辑、它们之间的联动关系以及一套经过验证的、可落地的配置与操作流程。无论你是在开发Bootloader、实现安全启动、还是设计在线诊断功能理解这些内容都将帮助你绕过许多暗礁写出更健壮、更可靠的底层驱动。2. Flash保护机制深度解析锁存与选择寄存器的协同PXD10的Flash保护机制是一个多层次、精细化的系统。简单来说它通过两把“锁”和一个“开关”来管理对Flash存储器的修改权限。理解这三者的关系是掌握其Flash操作的基础。2.1 核心保护逻辑LML SLL与操作使能首先我们需要建立核心概念。Flash的每个物理块Block是否被锁定由两个锁存寄存器的“或OR”运算结果决定主锁存寄存器LML, Low/Mid address space block Locking register这是主要的、易失性的锁。通过软件在运行时配置复位后丢失除非从非易失性区域加载。次级锁存寄存器SLL, Secondary Low/Mid address space block Locking register这是一个备用的、同样易失性的锁。它还有一个对应的非易失性镜像NVSLL其值在芯片复位时会被自动加载到SLL中提供了上电即有的默认保护状态。最终锁定状态 LML.LLK[x] OR SLL.SLK[x]对于低地址空间块为例 这意味着只要LML或SLL中任意一个寄存器将某个块标记为锁定值为1该块就被保护起来无法被编程或擦除。这种“或”逻辑提供了冗余的保护路径。然而仅有锁存状态还不够。要对这些锁存寄存器LML或SLL进行写入即上锁或解锁还必须先打开对应的“写使能开关”LML.LLE必须为1才能写入LML中的锁定位LLK。SLL.SLE必须为1才能写入SLL中的锁定位SLK, SMK, STSLK。开启这些使能位的方法正是手册中提到的密码验证机制。这是一种硬件级别的安全互锁Interlock防止软件意外或恶意修改锁定状态。实操心得密码写入的“一次性”与时机手册上只说了写入特定密码如对SLE写入0xC3C33333可以使能SLE位。但实际操作中有一个关键细节这个密码写入操作本身也必须在没有其他Flash高电压操作编程/擦除挂起、且MCR.DONE标志为1表示前一个操作已完成时进行。通常我们在系统初始化阶段、进行任何Flash修改操作之前就先完成所有必要的锁存寄存器使能和配置。一旦使能位被置起它将保持有效直到下一次系统复位。不要尝试在Flash操作间隙反复使能这可能导致不可预知的行为。2.2 地址空间划分与寄存器映射PXD10将Flash地址空间划分为几个区域不同的锁存和选择寄存器管理不同的区域低地址空间Low Address Space通常映射用户应用程序代码。由LML.LLK[15:0]和SLL.SLK[15:0]管理锁定由LMS.LSL[15:0]管理擦除选择。中地址空间Mid Address Space在某些内存配置中存在。由LML.MLK[1:0]和SLL.SMK[1:0]管理锁定由LMS.MSL[1:0]管理擦除选择。高地址空间High Address Space由单独的HBL.HLK[5:0]管理锁定由HBS.HSL[5:0]管理擦除选择。注意HBL的使能位是HBE密码是0xB2B22222。测试/影子空间Test/Shadow Space用于存储出厂配置、校准数据或Bootloader。由LML.TSLK和SLL.STSLK共同管理锁定。一个重要提示在您提供的80 KB Flash配置中手册多次提到“All the HLK5-0 are not used for this memory cut that is all mapped in low address space”。这意味着对于这个具体的芯片型号所有Flash物理上都映射在低地址空间。因此高地址空间和中地址空间的锁定/选择寄存器HLK, HSL, SMK, MSL可能是只读且固定值的。在编程时我们必须主要关注低地址空间相关的寄存器LLK, SLK, LSL以及测试空间锁TSLK, STSLK。在编写通用驱动时最好通过读取芯片的配置寄存器如SIM_FCFG1来动态判断可用的地址空间而不是写死。2.3 非易失性锁存NVSLL的妙用与风险NVSLL是一个位于测试Flash区块中的非易失性寄存器。它的值在每次芯片复位时都会自动加载到易失性的SLL寄存器中。这带来了一个强大的功能定义上电默认保护状态。典型应用场景 假设你的产品中Bootloader和出厂校准数据存放在固定的Flash块中这些内容在产品的整个生命周期内都不应被修改。你可以在生产烧录阶段通过特殊工具在SLE使能的情况下配置好SLL寄存器中对应块的锁定位SLK[x] 1然后将这个SLL的值编程到NVSLL所在的测试Flash区域。这样每次芯片上电这些关键区块就会自动被SLL锁定。而用户应用程序在运行时只能操作LML寄存器来动态锁定/解锁其他区域如用于存储动态数据的EEPROM模拟区。重大风险与注意事项警告对NVSLL的编程属于对测试Flash区块的操作通常需要特定的工厂编程模式或更高的访问权限。错误的操作可能导致测试区块损坏进而影响NVSLL的加载使芯片失去上电默认保护甚至引发更严重的故障。非标准操作用户模式下的标准Flash驱动库可能不包含对NVSLL编程的接口。这通常是在芯片出厂前由产线编程器完成的。不可逆性测试Flash区块的擦写次数可能远低于主Flash阵列。反复对NVSLL编程会消耗其寿命。依赖复位NVSLL的值只在复位阶段加载。如果你在运行时修改了SLL然后发生了局部复位如看门狗复位而非上电复位SLL可能会被重新加载为NVSLL的值导致运行时配置的锁定状态丢失。在设计安全关键系统时必须考虑这种场景。3. 锁存与选择寄存器的实战配置流程理解了原理我们来看如何在实际代码中操作这些寄存器。以下是一个典型的配置流程旨在保护Bootloader区域假设位于低地址空间的Block 0和1并允许应用程序擦写其他区域。3.1 初始化使能锁存寄存器写入权限在系统启动早期例如在启动代码或Flash驱动初始化函数中我们需要使能LML和SLL的写入权限。/** * brief 使能Flash锁存寄存器的写权限 * note 必须在任何尝试修改LML或SLL之前调用。假设寄存器基地址为FLASH_BASE。 */ void Flash_EnableLockWrite(void) { volatile uint32_t *flash_base (volatile uint32_t *)FLASH_BASE; // 1. 确保Flash模块处于就绪状态MCR.DONE 1 // 通常上电后默认就是1但良好实践是先检查。 while(!(flash_base[MCR_OFFSET] MCR_DONE_MASK)) { // 等待就绪可加入超时机制 } // 2. 使能LML寄存器写入 (解锁主锁) // 向LML寄存器地址写入特定密码 flash_base[LML_OFFSET] 0xA5A55555; // LLE的密码假设值需查确切手册 // 检查LLE是否被置位 if(!(flash_base[LML_OFFSET] LML_LLE_MASK)) { // 使能失败处理错误 Error_Handler(); } // 3. 使能SLL寄存器写入 (解锁次级锁) // 向SLL寄存器地址写入特定密码 flash_base[SLL_OFFSET] 0xC3C33333; // SLE的密码 // 检查SLE是否被置位 if(!(flash_base[SLL_OFFSET] SLL_SLE_MASK)) { // 使能失败处理错误 Error_Handler(); } // 4. 可选如果需操作高地址空间使能HBL // flash_base[HBL_OFFSET] 0xB2B22222; // HBE的密码 }3.2 配置锁定状态保护关键区块假设我们要永久锁定Block 0和1通过NVSLL实现上电默认锁并在运行时动态管理Block 2用于参数存储。场景一生产端配置NVSLL模拟流程实际通常在编程器脚本中完成此操作风险极高仅示意流程。// 此代码仅为原理示意切勿在用户模式下直接使用 void Production_ConfigureNVSLL(void) { // 0. 进入特殊的工厂测试模式方法依芯片和工具链而定 EnterFactoryMode(); // 1. 使能测试Flash块的编程/擦除能力可能需要操作LML.TSLK等 // 2. 解锁并擦除包含NVSLL的测试Flash扇区 // 3. 构建要写入NVSLL的值我们希望Block0和1永远锁定即SLK01, SLK11 uint32_t nvsll_value 0x00000000; nvsll_value | (1 0); // SLK0 1 nvsll_value | (1 1); // SLK1 1 // SLE位在NVSLL中也是可编程的默认值但通常我们不想默认开启写权限所以设为0。 // 其他位根据需求设置。 // 4. 编程NVSLL寄存器所在的物理地址如0x403DF8 ProgramFlashWord(0x403DF8, nvsll_value); // 5. 重新锁定测试Flash块退出工厂模式 ExitFactoryMode(); }场景二应用程序运行时动态管理锁定更常用/** * brief 配置运行时Flash块锁定状态 * param block_mask 位掩码bit0对应Block0bit1对应Block1以此类推。1表示锁定0表示解锁。 */ void Flash_ConfigureRuntimeLock(uint32_t block_mask) { volatile uint32_t *flash_base (volatile uint32_t *)FLASH_BASE; uint32_t current_lml; // 1. 确保LLE已使能见上一节初始化 if(!(flash_base[LML_OFFSET] LML_LLE_MASK)) { Flash_EnableLockWrite(); // 或返回错误 } // 2. 读取当前的LML值 current_lml flash_base[LML_OFFSET]; // 3. 清除低16位锁定位LLK[15:0]然后应用我们的掩码。 // 注意我们只操作低地址空间锁并保留其他位如TSLK, MLK等。 current_lml ~(0x0000FFFF); // 清除LLK[15:0] current_lml | (block_mask 0x0000FFFF); // 设置新的锁定位 // 4. 写入新的LML值 flash_base[LML_OFFSET] current_lml; // 5. 验证写入可选但推荐 if((flash_base[LML_OFFSET] 0x0000FFFF) ! (block_mask 0x0000FFFF)) { // 锁定状态配置失败 Error_Handler(); } } // 应用示例在应用程序初始化时解锁用于参数存储的Block 2 int main(void) { // ... 其他初始化 Flash_EnableLockWrite(); // 解锁Block2 (bit2 0)其他块保持原状或锁定。假设我们只想让Block2可写。 // 即掩码中除了bit2为0其他需要锁定的位为1。 // 例如我们希望锁定Block0,1,3,4,5...只解锁Block2 uint32_t lock_mask 0x0000FFFF (~(1 2)); // 所有位为1然后清除bit2 Flash_ConfigureRuntimeLock(lock_mask); // ... 后续操作 }3.3 擦除操作选择寄存器的正确使用擦除操作不是直接向地址写数据而是一个需要预先选择目标块的序列化过程。LMS低/中地址空间选择寄存器和HBS高地址空间选择寄存器就是用于此目的。擦除单个块例如Block 2的标准流程Flash_StatusTypeDef Flash_EraseBlock(uint8_t block_num) { volatile uint32_t *flash_base (volatile uint32_t *)FLASH_BASE; uint32_t temp; // 1. 检查目标块是否被锁定LML OR SLL uint32_t lock_status (flash_base[LML_OFFSET] (1 block_num)) | (flash_base[SLL_OFFSET] (1 block_num)); if(lock_status) { return FLASH_ERROR_LOCKED; } // 2. 确保Flash就绪且无挂起操作 if(!(flash_base[MCR_OFFSET] MCR_DONE_MASK)) { return FLASH_ERROR_BUSY; } // 3. 配置块选择寄存器LMS // 先读取当前值然后只设置目标块的选择位清除其他位确保只擦除一个块。 temp flash_base[LMS_OFFSET]; temp ~(0x0000FFFF); // 清除所有低地址空间选择位 temp | (1 block_num); // 设置目标块选择位 flash_base[LMS_OFFSET] temp; // 4. 设置擦除操作选择位MCR.ERS flash_base[MCR_OFFSET] | MCR_ERS_MASK; // 5. 启动擦除操作设置MCR.EHV flash_base[MCR_OFFSET] | MCR_EHV_MASK; // 6. 等待操作完成MCR.DONE 1 while(!(flash_base[MCR_OFFSET] MCR_DONE_MASK)) { // 此处应加入超时检测防止死等 } // 7. 清除选择位和操作位可选但为下次操作做好准备 flash_base[MCR_OFFSET] ~(MCR_EHV_MASK | MCR_ERS_MASK); flash_base[LMS_OFFSET] ~(1 block_num); // 8. 检查错误标志如MCR.PEG, MCR.RWE等 if(flash_base[MCR_OFFSET] (MCR_PEG_MASK | MCR_RWE_MASK | MCR_EER_MASK)) { // 处理错误读取ADR寄存器获取失败地址 uint32_t fail_address flash_base[ADR_OFFSET]; return FLASH_ERROR_OPERATION; } return FLASH_OK; }关键细节选择寄存器的“一次性”手册明确指出“The blocks must be selected (or unselected) before doing an erase interlock write as part of the Erase sequence. The select register is not writable once an interlock write is completed or if a high voltage operation is suspended.” 这意味着顺序至关重要必须在设置MCR.EHV启动高电压操作之前配置好LMS/HBS。一旦MCR.EHV置位选择寄存器就被锁死直到操作完成MCR.DONE1或操作被取消。擦除多个块如果需要一次性擦除多个块可以在步骤3中一次性设置多个选择位例如temp | (12) | (15) | (17);。但务必谨慎确保这些块都是确定需要擦除且未被锁定的。4. 高级诊断功能用户测试寄存器实战指南用户测试存器UT0-UT2和多重输入签名寄存器UMISR0-4是PXD10 Flash模块提供给开发者的强大诊断工具。它们主要用于生产测试、固件完整性验证和ECC功能校验在研发和故障分析阶段极其有用。4.1 阵列完整性检查与Margin Read阵列完整性检查Array Integrity Check是一种非破坏性的自检用于验证Flash存储单元的可靠性。Margin Read则是更严格的读取使用比正常读电压更高或更低的阈值来检测处于“临界”状态的存储单元提前发现潜在故障。操作流程如下/** * brief 执行Flash阵列完整性检查 * param use_sequential 0使用专有序列更全面1使用顺序序列更快 * param start_block 起始块号 * param end_block 结束块号 * return 成功返回0失败返回错误码。成功后可通过ReadMISR()获取签名。 */ int Flash_ArrayIntegrityCheck(uint8_t use_sequential, uint8_t start_block, uint8_t end_block) { volatile uint32_t *flash_base (volatile uint32_t *)FLASH_BASE; // 0. 准备工作确保目标块未被锁定且被选择用于检查 // 这里的选择逻辑与擦除不同是通过UT0.AIE启动的检查会自动扫描所有未锁定的块 // 手册描述是“on all selected and unlocked blocks”。但“selected”机制在此处未明确。 // 一种常见实现是阵列检查会检查所有地址空间。安全做法是确保待检查区域未锁定。 for(int istart_block; iend_block; i) { if((flash_base[LML_OFFSET] (1i)) || (flash_base[SLL_OFFSET] (1i))) { return -1; // 区块被锁定无法检查 } } // 1. 确保Flash就绪MCR.DONE1且无其他高电压操作 if(!(flash_base[MCR_OFFSET] MCR_DONE_MASK)) { return -2; } if(flash_base[MCR_OFFSET] (MCR_ERS_MASK | MCR_PGM_MASK | MCR_EHV_MASK)) { return -3; } // 2. 使能用户测试功能UTE flash_base[UT0_OFFSET] 0xF9F99999; // 写入UTE密码 if(!(flash_base[UT0_OFFSET] UT0_UTE_MASK)) { return -4; // UTE使能失败 } // 3. 配置检查模式 uint32_t ut0_val flash_base[UT0_OFFSET]; ut0_val ~(UT0_AIS_MASK); // 清除AIS位 if(use_sequential) { ut0_val | UT0_AIS_MASK; // 设置为顺序序列 } // 如果要做Margin Read在此处设置UT0.MRE和UT0.MRV // ut0_val | UT0_MRE_MASK; // 使能Margin Read // ut0_val ~(UT0_MRV_MASK); // 设置为检查编程电平0或置1检查擦除电平 flash_base[UT0_OFFSET] ut0_val; // 4. 可选为MISR设置种子值。如果不设置默认为0。 flash_base[UMISR0_OFFSET] 0x12345678; // 示例种子 flash_base[UMISR1_OFFSET] 0x9ABCDEF0; // ... 设置UMISR2-4 // 5. 启动阵列完整性检查设置UT0.AIE flash_base[UT0_OFFSET] | UT0_AIE_MASK; // 6. 等待检查完成轮询UT0.AID while(!(flash_base[UT0_OFFSET] UT0_AID_MASK)) { // 加入超时机制这个检查可能耗时较长。 } // 7. 检查完成后UT0.AID会自动置1。此时可以读取MISR值进行分析。 // 8. 清除AIE位结束操作 flash_base[UT0_OFFSET] ~UT0_AIE_MASK; // 9. 可选关闭用户测试功能 // flash_base[UT0_OFFSET] ~UT0_UTE_MASK; // UTE位只能写0清除 return 0; // 成功 } /** * brief 读取MISR签名 */ void Flash_ReadMISR(uint32_t misr[5]) { volatile uint32_t *flash_base (volatile uint32_t *)FLASH_BASE; misr[0] flash_base[UMISR0_OFFSET]; misr[1] flash_base[UMISR1_OFFSET]; misr[2] flash_base[UMISR2_OFFSET]; misr[3] flash_base[UMISR3_OFFSET]; misr[4] flash_base[UMISR4_OFFSET]; }如何解读MISR结果MISR是一个基于线性反馈移位寄存器LFSR的签名。在相同的输入序列即Flash内容和相同的种子下每次计算都会产生一个唯一的、确定性的签名。预期一致如果Flash内容完好无损且检查参数序列模式、起始结束地址完全一致每次得到的MISR签名应该相同。你可以在生产测试阶段对已知完好的芯片运行一次检查记录下这个“黄金签名”Golden Signature。签名不符如果后续检查中签名与“黄金签名”不匹配则表明Flash内容或存储单元本身发生了改变或损坏可能是位翻转、物理损坏或程序异常写入导致。4.2 ECC逻辑校验ECC Logic CheckECC逻辑校验是一种验证片上ECC编解码电路是否正常工作的方法而不是检查Flash存储的数据。它通过UT1和UT2寄存器向ECC逻辑注入模拟的“数据”通过UT0注入模拟的“校验位Syndrome”然后观察ECC逻辑是否能正确检测或纠正错误。基本操作思路使能用户测试UTE。在UT1DAI31-0和UT2DAI63-32中设置模拟的64位数据。在UT0DSI7-0中设置模拟的8位ECC校验位或错误模式。使能ECC逻辑检查UT0.EIE 1。启动操作UT0.AIE 1。注意此时AIS应选择顺序模式且不应设置MREMargin Read。操作完成后检查MCR中的ECC错误标志EDC EER和ADR寄存器中的地址。由于我们注入的是模拟数据这个地址可能无实际意义但标志位的变化可以验证ECC逻辑的响应是否正确。这个功能非常底层主要用于芯片生产测试或极度深度的故障诊断普通应用开发中极少使用。5. 常见问题排查与实战避坑指南在实际开发中仅仅按照手册配置寄存器往往不够很多问题源于对交互逻辑和时序的忽视。下面是我总结的几个典型问题及解决方案。5.1 问题锁存寄存器LML/SLL写入成功但锁定不起作用现象代码中已经成功写入了LML或SLL寄存器读取回写值确认但对应的Flash块仍然可以被编程或擦除。排查步骤检查“或”逻辑确认你检查的是最终锁定状态。锁定状态由LML.LLK[x] OR SLL.SLK[x]决定。你可能只修改了LML但SLL中对应的位在上电时从NVSLL加载了0解锁状态。始终读取两个寄存器并计算“或”值来判断是否锁定。检查使能位状态LML.LLE和SLL.SLE是易失性的。你的写入操作可能发生在使能位有效期间但随后如果发生了某些操作如Flash擦写导致MCU局部复位使能位会清零但锁存位的值可能被保留不手册指出复位会从非易失性区域重新加载SLL而LML是易失的复位后可能清零。确保在每次需要判断锁定状态前你的使能逻辑是清晰的并且考虑了复位场景。确认物理地址映射你尝试锁定的块号bit index是否确实映射到了你想要保护的物理地址区间参考芯片的内存映射图确认应用程序或Bootloader的链接脚本定义的段确实落在你锁定的块内。检查操作序列对Flash进行编程/擦除的操作序列是否完全遵守了手册的步骤特别是在启动高电压操作EHV前是否正确地通过选择寄存器LMS/HBS选择了目标块即使一个块被锁定如果你错误地没有在LMS中选择它擦除操作可能会跳过它而不会报错因为根本没选它造成“锁定失效”的错觉。5.2 问题擦除或编程操作总是失败MCR.PEG标志被清除现象启动擦除/编程后等待DONE标志超时或完成后发现MCR.PEG位为0表示Flash编程/擦除错误。排查步骤首要检查锁定状态这是最常见的原因。使用上述方法计算目标块的最终锁定状态。如果被锁定操作会静默失败或报告错误。检查供电和时钟Flash操作对电源电压和时钟稳定性非常敏感。确保在操作期间内核电压和Flash供电电压在规格范围内且系统时钟没有发生异常变化。检查操作间隔连续的Flash操作之间需要满足最小时间间隔。在启动一次操作EHV置位后即使DONE标志很快置起也应等待手册规定的最小间隔时间tERSH, tPROG等后再进行下一次操作。在DONE置位后插入一个几十微秒的软件延时是简单有效的避坑方法。检查地址对齐编程操作必须是双字64位对齐的擦除操作必须是块对齐的。传入的地址不符合要求会导致失败。查看ADR寄存器当PEG标志为0时ADR寄存器会保存第一个失败操作的地址。读取这个地址可以帮助你定位是哪个存储单元出了问题。检查代码执行位置手册强调“The Modify Operation commands must be executed from another Memory (internal Ram or external Memory).”执行Flash擦写操作的代码本身绝对不能位于正在被擦写的Flash区域中。通常的做法是将Flash驱动函数链接到RAM中或者在执行操作前将关键的指令序列复制到RAM中运行。5.3 问题用户测试功能如阵列检查无法启动或结果异常现象配置UT0等寄存器后AIE置位但AID标志永远不置起或MISR签名每次都不一样。排查步骤确认UTE已使能这是前提。写入密码后务必检查UT0.UTE位是否为1。检查DONE和AID状态UT0.AID和MCR.DONE是互斥的不手册说UT0-2和UMISR在MCR.DONE或UT0.AID为低时不可访问。在启动测试AIE置位前必须确保MCR.DONE1且UT0.AID1表示上次测试已完成。在测试进行中UT0.AID0你无法读写这些测试寄存器。检查操作冲突在设置AIE时必须确保MCR.ERS、MCR.PGM和MCR.EHV全部为0。任何正在进行或挂起的Flash修改操作都会与测试冲突。理解MISR的随机性如果你没有为UMISR0-4设置初始种子值那么每次上电后第一次运行阵列检查由于MISR初始值为0得到的签名是确定的。但如果你在单次上电中多次运行检查且没有重置MISR种子第二次的签名将是基于第一次结果累积计算的自然会不同。在每次启动新的、独立的完整性检查前最好重新初始化写入种子值UMISR寄存器。检查测试范围阵列完整性检查是针对“所有被选择且未锁定的块”。你需要确认你希望检查的块确实处于未锁定状态。如果整个Flash都被锁了检查操作可能立即完成因为无块可检得到的MISR签名可能就是初始种子值容易被误认为异常。5.4 寄存器访问时机总结表下表总结了关键寄存器在何种状态下可写这是避免硬件互锁违规的关键。寄存器/位域可写入条件不可写入条件说明LML.LLK[x], SLELLE1LLE0必须先通过密码使能LLESLL.SLK[x], STSLK, SMK[x]SLE1SLE0必须先通过密码使能SLEHBL.HLK[x]HBE1HBE0必须先通过密码使能HBELMS.LSL[x], MSL[x]MCR.DONE1且MCR.EHV0且无挂起操作MCR.EHV1或 有挂起操作必须在启动擦除EHV前配置MCR.PGM, ERSMCR.DONE1且MCR.EHV0MCR.EHV1设置操作类型MCR.EHVMCR.DONE1且 操作位(PGM/ERS)已设MCR.DONE0启动操作的最后一步UT0-UT2, UMISR0-4MCR.DONE1且UT0.AID1且UT0.UTE1MCR.DONE0或UT0.AID0用户测试寄存器有独立的状态机UT0.AIEMCR.ERS0,MCR.PGM0,MCR.EHV0任何Flash修改操作进行中启动测试的条件更严格掌握这张表你在编写Flash驱动时就能清晰地规划操作序列避免状态冲突。归根结底与PXD10的Flash模块打交道需要像与一个严谨的协议状态机对话每一步都必须满足前置条件任何“抢跑”或“遗忘”都会导致操作失败。