LPC213x ARM7开发实战:ADC/DAC配置与Flash ISP/IAP编程避坑指南
1. 项目概述与核心价值如果你正在使用NXP的LPC213x系列ARM7微控制器那么模数转换器ADC、数模转换器DAC和Flash的在线编程ISP/IAP这三块内容绝对是绕不开的核心技能点。我接触这个系列芯片十几年了从早期的工控项目到后来的消费电子发现很多开发者对数据手册里这些寄存器的描述和引导程序的流程感到头疼要么是配置不对导致采样不准要么是IAP操作把整个系统搞挂了。其实只要把底层机制和操作流程理顺了这些功能用起来非常顺手。简单来说ADC负责把外界的模拟信号比如温度传感器的电压、麦克风的声音信号转换成微控制器能理解的数字值DAC则相反把数字代码变成模拟电压输出去驱动其他设备比如音频输出、电机控制。而Flash的ISP和IAP则是你给芯片“灌输”程序和后期“打补丁”的关键手段。ISP让你能通过一根串口线就给焊在板子上的芯片下载程序IAP则允许你的程序在运行时自己修改自己的Flash实现固件升级或者保存掉电不丢失的参数。LPC213x的这套机制设计得相当经典理解了它你对其他ARM Cortex-M系列芯片的类似功能也能触类旁通。这篇文章我就结合官方手册和这些年的踩坑经验把LPC213x的ADC、DAC以及Flash编程的里里外外给你讲透。我会重点拆解那些容易让人迷糊的寄存器配置细节、ISP/IAP的实际操作流程以及如何避开那些手册里没明说但实际开发中一定会遇到的“坑”。无论你是刚开始接触嵌入式的新手还是想深入优化现有项目的老鸟相信都能从中找到实用的干货。2. LPC213x ADC模块深度解析与实战配置LPC213x的ADC模块是一个逐次逼近型SARADC精度为10位。它支持最多8个通道的模拟输入具体通道数因型号而异并提供了灵活的工作模式包括软件启动、硬件触发和连续Burst转换模式。2.1 ADC核心寄存器精讲驱动ADC本质上就是配置几个关键的寄存器。手册里的描述比较分散我把它梳理成更易操作的几个部分。1. A/D控制寄存器ADCR这是ADC的“总指挥部”。你需要通过它来启动转换、选择通道、设置时钟分频和工作模式。它的地址对于ADC0是0xE0034000对于ADC1是0xE0060000。几个关键位段需要特别注意SEL位3:0: 通道选择。这是一个位图你可以同时选择多个通道。在Burst模式下被选中的通道会按顺序自动转换。在单次模式下只有最低位的那个被选中的通道有效。例如SEL 0x01选择通道0SEL 0x05则选择通道0和通道2。CLKDIV位15:8: 时钟分频器。ADC的转换时钟ADCCLK由VPB时钟PCLK分频得到计算公式是ADCCLK PCLK / (CLKDIV 1)。这里有个大坑ADCCLK必须不大于4.5 MHz在3.3V供电下。如果你的PCLK是60MHz那么CLKDIV至少需要设置为(60/4.5) - 1 12.33向上取整为13。设置太小会导致转换结果错误甚至ADC模块损坏。BURST位16: 突发模式使能。置1后ADC会按照SEL字段选中的通道顺序连续自动进行转换无需软件反复触发。这在需要高速、多通道采样的场合非常有用。START位26:24: 启动控制。当BURST0时向这个字段写入001可以立即启动一次转换。更强大的是你可以设置010到111的值让ADC由特定的硬件事件如定时器匹配或捕获/比较引脚边沿来触发转换实现与外部事件的精确同步。PDN位21: 掉电控制。1为正常工作0为掉电模式。上电后必须将PDN置1并等待一段稳定时间手册建议至少3ms后才能进行转换否则第一次转换结果很可能是不准确的。2. A/D数据寄存器ADDR0-ADDR7每个通道都有一个对应的数据寄存器ADDRx。转换完成后结果就放在这里。以ADDR0地址0xE0034010为例关键位是DONE位31: 转换完成标志。硬件在转换完成后自动置1读取本寄存器后自动清零。这是判断转换是否完成最直接的方式。OVERRUN位30: 数据溢出标志。在Burst模式下如果转换结果产生得太快而软件来不及读取导致新的结果覆盖了旧的结果此位会被置1。读取本寄存器可清除。RESULT位15:6: 10位转换结果。这是一个二进制小数代表V_{AIN} / V_{REF}的比值。当AIN引脚电压等于VSSA时结果接近0等于VREF时结果接近0x3FF1023。3. A/D全局数据寄存器ADGDR这是所有通道共享的一个数据寄存器。在Burst模式下每次转换完成的结果都会更新到这个寄存器同时会更新其中的通道编号CHN字段位26:24告诉你当前结果是哪个通道的。注意在非Burst模式下如果你通过ADGDR读取数据需要自行记录是哪个通道的转换。4. A/D中断使能寄存器ADINTEN用于控制哪个通道的转换完成可以产生中断。你可以使能单个通道ADINTENx也可以使用全局中断模式ADGINTEN。在全局中断模式下只要任何一个通道转换完成ADGDR的DONE位置1就会产生中断你需要在中断服务程序中读取ADGDR的CHN字段来判断是哪个通道。2.2 ADC实战配置步骤与代码示例理解了寄存器写驱动代码就是按部就班。下面是一个配置ADC0通道0进行单次转换并读取结果的典型流程// 假设PCLK 60MHz 目标ADCCLK 4.5MHz #define PCLK 60000000 #define ADCCLK_MAX 4500000 #define CLKDIV_VAL ((PCLK / ADCCLK_MAX) - 1) // 计算结果为13 void ADC0_Init(void) { // 1. 连接引脚功能将P0.28设置为AD0.1假设使用通道1 // PINSEL1的位25:24控制P0.28 设置为01选择AD0.1功能 PINSEL1 (PINSEL1 ~(324)) | (124); // 2. 给ADC上电并设置时钟分频 AD0CR (1 21) | (CLKDIV_VAL 8); // 位21 (PDN)1: 上电 // 位15:8 (CLKDIV)13: 分频 // 3. 等待ADC模拟部分稳定至少3ms delay_ms(5); // 使用一个简单的延时函数 } uint16_t ADC0_ReadChannel(uint8_t channel) { uint32_t adc_data; uint16_t result; // 1. 配置单次转换选择通道关闭Burst模式软件启动 AD0CR (AD0CR ~0xFF) | (1 channel) | (1 21) | (CLKDIV_VAL 8) | (1 24); // 清除SEL字段后选择指定通道保持PDN1和CLKDIVSTART字段001立即启动 // 2. 等待转换完成轮询DONE位 do { adc_data AD0DR[channel]; // 读取对应通道的数据寄存器 } while ((adc_data (1 31)) 0); // 检查DONE位位31 // 3. 提取10位结果 result (adc_data 6) 0x3FF; // RESULT在位15:6 return result; } // 主函数中调用 int main(void) { uint16_t adc_value; ADC0_Init(); while(1) { adc_value ADC0_ReadChannel(1); // 读取AD0.1通道 // ... 处理adc_value ... delay_ms(100); } }2.3 ADC应用注意事项与避坑指南参考电压VREF是关键ADC的转换结果是相对于VREF的比值。VREF必须稳定、干净。强烈建议使用独立的基准电压源芯片如REF3033为VREF引脚供电而不是直接连接到VDD。VDD的纹波和噪声会直接反映到你的采样精度上。模拟地与数字地芯片有独立的VSSA模拟地和VSSD数字地。在PCB布局时必须将它们在芯片附近通过一个磁珠或0欧电阻单点连接并且确保模拟部分ADC输入走线、VREF滤波电容的地回路先汇聚到VSSA再连接到这个单点。这是抑制数字噪声干扰模拟信号最有效的办法。输入信号阻抗手册建议信号源阻抗Rs低于40kΩ。如果信号源阻抗过高例如来自一个很大的分压电阻网络需要在ADC输入引脚前加一个电压跟随器运算放大器进行缓冲否则采样电容的充放电会导致读数严重偏差。Burst模式下的中断处理在Burst模式下使用中断时如果你使能了多个通道中断服务程序ISR中应该读取ADGDR并根据其CHN字段判断是哪个通道完成了转换。务必在ISR中读取ADGDR来清除DONE标志否则会一直产生中断。首次转换丢弃ADC模块上电或长时间休眠后第一次转换的结果往往不准。一个可靠的做法是在初始化完成后或每次从掉电模式唤醒后先进行一次“哑”转换读取并丢弃结果从第二次转换开始使用。3. LPC213x DAC模块配置与应用详解LPC213x的DAC是一个10位、电阻串架构、带输出缓冲器的数模转换器。它的使用比ADC简单得多但细节决定成败。3.1 DAC寄存器与引脚配置DAC只有一个核心寄存器DAC寄存器DACR地址是0xE006C000。VALUE位15:610位数据值。你写入的数字将转换为模拟电压输出V_{AOUT} (VALUE / 1024) * V_{REF}。BIAS位16速度/功耗权衡位。BIAS 0高速模式。建立时间最大1μs最大电流700μA。适用于需要快速响应的场合如波形生成。BIAS 1低功耗模式。建立时间最大2.5μs最大电流350μA。适用于对速度要求不高但对功耗敏感的应用如电池供电设备。使能DAC输出DAC的输出引脚AOUT与GPIO P0.25/AD0.4复用。你需要通过PINSEL1寄存器地址0xE002C004的位19:18来配置00: GPIO功能。01: AD0.4功能ADC输入。10:AOUT功能DAC输出。11: 保留。因此要使用DAC必须执行PINSEL1 (PINSEL1 ~(318)) | (218);。3.2 DAC驱动实现与波形生成示例DAC的驱动非常简单基本就是写寄存器。但如何产生一个稳定的电压或者波形则有讲究。void DAC_Init(void) { // 1. 配置P0.25为AOUT功能 PINSEL1 (PINSEL1 ~(3 18)) | (2 18); // 2. 初始化DACR选择高速模式BIAS0输出0V DACR (0 6); // VALUE0, BIAS0 } void DAC_SetVoltage(uint16_t value) { // 确保输入值在0-1023范围内 if(value 1023) value 1023; // 更新DAC输出 BIAS位保持为0高速模式 DACR (value 6); } // 示例生成一个三角波 void DAC_GenerateTriangleWave(uint32_t frequency_hz) { uint16_t dac_value 0; uint8_t direction 0; // 0:上升1:下降 // 计算每个台阶的延时以控制频率 // 三角波一个周期有2046个台阶0-1023-0 uint32_t delay_us 1000000 / (frequency_hz * 2046); while(1) { DAC_SetVoltage(dac_value); if(direction 0) { dac_value; if(dac_value 1023) direction 1; } else { dac_value--; if(dac_value 0) direction 0; } delay_us(delay_us); // 需要一个微秒级延时函数 } }3.3 DAC设计要点与常见问题负载能力DAC内部输出缓冲器的驱动能力有限。手册明确指出当负载电容超过100pF时建立时间会超过标称值。如果你要驱动低阻抗负载如直接驱动一个扬声器线圈必须在输出端加一个运算放大器作为缓冲器。一个典型的同相电压跟随器电路就非常合适。参考电压VREF和ADC一样DAC的输出精度直接依赖于VREF的质量。必须为VREF引脚提供干净、稳定的电压。通常可以和ADC共用同一个基准电压源。建立时间与更新率在BIAS0模式下建立时间是1μs这意味着你理论上每秒可以更新100万次输出。但实际上受限于你写DACR寄存器的软件速度很难达到这个理论值。在需要高更新率的应用如音频合成中可以考虑使用DMA来搬运数据到DACR或者使用定时器触发来精确控制更新时刻。功耗考虑在电池供电设备中如果DAC输出一个固定电压比如作为参考源可以将BIAS设为1以降低功耗。如果需要动态变化则需权衡速度和功耗。输出滤波DAC输出的是阶梯波在VALUE变化时会有毛刺。对于高精度或需要纯净模拟输出的应用在AOUT引脚后添加一个简单的RC低通滤波器例如1kΩ电阻串联0.1μF电容对地可以有效地平滑输出滤除高频噪声。4. Flash ISP/IAP编程机制全解析这是LPC213x开发中最强大也最容易出错的部分。ISP和IAP让你能灵活地管理芯片内部的Flash存储器。4.1 核心概念辨析ISP vs IAPISPIn-System Programming在系统编程。指芯片已经焊接到目标板上通过串口0UART0利用芯片内部固化的Bootloader程序对Flash进行编程。这通常用于产品的初次烧录或后期返修升级。关键硬件条件P0.14引脚在复位时被拉低。IAPIn-Application Programming在应用编程。指芯片内正在运行的用户应用程序调用芯片ROM中固化的IAP例程对自身的Flash存储器进行擦除和写入操作。这用于实现设备的固件在线升级FOTA、存储系统参数或记录日志等。简单比喻ISP就像用电脑通过数据线给手机刷机IAP就像手机自己从网络下载更新包并给自己安装。4.2 启动流程与ISP进入条件芯片复位后的启动流程是理解ISP/IAP的基础。其决策逻辑如下图所示根据手册流程图整理复位初始化。检查CRP判断是否启用了代码读保护CRP3级别会限制ISP。检查看门狗标志如果看门狗溢出标志被置位则忽略硬件ISP请求。采样P0.14这是进入ISP模式的关键。如果P0.14为低电平且上述条件允许则尝试进入ISP模式。检查用户代码有效性如果P0.14为高或ISP进入被阻止则检查Flash Sector 0起始处的中断向量表校验和。如果有效则跳转到用户程序地址0x00000000执行。执行自动波特率如果用户代码无效或P0.14为低且允许ISP则启动UART0的自动波特率程序等待主机发送同步字符?从而建立通信进入ISP命令处理器。重要提示由于复位后P0.14处于高阻态必须在外部通过一个上拉电阻如10kΩ将其拉高否则引脚电平不确定可能导致意外进入ISP模式使你的应用程序无法启动。这是新手最容易忽略的硬件设计问题。4.3 IAP编程接口与实战IAP功能是通过调用位于芯片ROM中的一段固定地址的代码来实现的。对于LPC213xIAP入口地址是**0x7FFFFFF0**。你需要通过汇编或C语言设置好参数然后跳转到这个地址。IAP命令通过寄存器传递参数和结果。通常使用R0寄存器传递命令代码R1寄存器传递参数块的起始地址。参数块和结果块都是存放在RAM中的32位字数组。一个典型的IAP擦除并编程扇区的C语言封装示例// 定义IAP命令代码和入口 #define IAP_ENTRY_ADDR 0x7FFFFFF0 #define IAP_CMD_PREPARE_SECTOR 50 #define IAP_CMD_ERASE_SECTOR 52 #define IAP_CMD_COPY_RAM_TO_FLASH 51 #define IAP_CMD_BLANK_CHECK_SECTOR 53 typedef void (*IAP_Entry)(uint32_t[], uint32_t[]); IAP_Entry iap_entry (IAP_Entry)IAP_ENTRY_ADDR; int IAP_ProgramFlash(uint32_t dst_addr, uint32_t *src_data, uint32_t len) { uint32_t command[5]; uint32_t result[3]; uint32_t start_sector, end_sector; // 0. 计算目标地址所在的扇区号需要根据具体芯片的Flash布局表 start_sector GetSectorNumber(dst_addr); end_sector GetSectorNumber(dst_addr len - 1); // 1. 准备扇区必须步骤 command[0] IAP_CMD_PREPARE_SECTOR; command[1] start_sector; command[2] end_sector; iap_entry(command, result); if(result[0] ! 0) return result[0]; // 返回错误码 // 2. 擦除扇区 command[0] IAP_CMD_ERASE_SECTOR; command[1] start_sector; command[2] end_sector; command[3] SystemCoreClock / 1000; // 以kHz为单位的CPU时钟频率 iap_entry(command, result); if(result[0] ! 0) return result[0]; // 3. 再次准备扇区擦除后需要重新准备 command[0] IAP_CMD_PREPARE_SECTOR; command[1] start_sector; command[2] end_sector; iap_entry(command, result); if(result[0] ! 0) return result[0]; // 4. 将RAM数据复制到Flash command[0] IAP_CMD_COPY_RAM_TO_FLASH; command[1] dst_addr; // 目标Flash地址必须256字节对齐 command[2] (uint32_t)src_data; // 源RAM地址必须字对齐 command[3] len; // 字节数必须是256 | 512 | 1024 | 4096 command[4] SystemCoreClock / 1000; iap_entry(command, result); return result[0]; // 0表示成功 } // 使用示例在Flash的0x00010000地址存储一段数据 uint32_t my_data[128] __attribute__((aligned(4))); // 确保数据在RAM中字对齐 int main(void) { // ... 初始化 ... // 填充my_data... // 编程Flash int status IAP_ProgramFlash(0x00010000, my_data, sizeof(my_data)); if(status 0) { // 编程成功 } else { // 处理错误status即为IAP返回的错误码 } }4.4 IAP操作黄金法则与避坑指南中断与向量表重映射这是IAP操作中最危险的一步。Flash在擦写期间是不可读的。如果你的中断向量表在Flash中而在此期间发生了中断CPU去Flash取向量就会失败导致硬件错误系统崩溃。标准做法是在调用IAP例程前将中断向量表复制到RAM中并重映射向量表到RAM地址通过设置ARM的VTOR寄存器但LPC213x是ARM7没有VTOR。通常需要手动禁用所有中断或者确保中断服务程序本身就在RAM中运行。地址与长度对齐COPY_RAM_TO_FLASH命令对目标Flash地址、源RAM地址和数据长度有严格的对齐要求。Flash地址必须256字节对齐RAM地址必须字对齐4字节数据长度必须是256、512、1024或4096字节。不满足这些条件会导致命令失败。扇区操作Flash擦除以扇区为单位。LPC2138的扇区有4KB和32KB两种见手册表223。在擦除或写入前必须对目标扇区执行PREPARE命令。擦除后该扇区需要再次PREPARE才能写入。时钟参数擦除和写入命令需要传入以kHz为单位的系统时钟频率CCO时钟。例如如果SystemCoreClock 60MHz则传入60000。堆栈位置IAP例程会使用用户提供的堆栈。必须确保在调用IAP时堆栈指针SP指向的RAM区域有至少128字节的可用空间并且这段内存不会被其他操作破坏。数据验证编程完成后务必使用COMPARE命令或自行计算CRC校验和来验证写入Flash的数据是否正确。Flash写入过程中可能因电源波动等原因出错。5. ISP命令集详解与上位机通信实战ISP模式通过UART0与主机通信有一套完整的ASCII命令协议。理解这套协议你可以自己编写上位机烧录工具。5.1 ISP通信协议与数据格式命令格式命令 参数1 参数2 ... 参数NCRLF。例如解锁命令U 23130\r\n。响应格式返回码CRLF响应行1CRLF...。返回码0表示CMD_SUCCESS。数据格式UU编码为了通过纯文本串口传输二进制数据ISP使用了UU编码。它将3字节二进制数据编码为4字节可打印ASCII字符比Hex编码1字节变2字节效率更高。主机和Bootloader在传输数据块后都会附加一个校验和供对方验证。5.2 关键ISP命令流程拆解一个完整的ISP编程会话通常遵循以下流程建立连接与解锁硬件拉低P0.14后复位或让芯片运行无效用户代码使其进入自动波特率状态。上位机发送?等待回复Synchronized\r\n然后回复同样的字符串。上位机发送晶振频率如12000\r\n表示12MHz。芯片回复OK\r\n进入ISP命令模式。发送解锁命令U 23130\r\n。这是执行擦写类命令前的必要步骤。擦除FlashP 0 10\r\n准备扇区0到10。E 0 10\r\n擦除扇区0到10。擦除后这些扇区所有位变为10xFF。编程FlashP 0 0\r\n再次准备要写入的扇区例如扇区0。W 1073742336 1024\r\n命令写入1024字节数据到RAM地址0x40000200。发送此命令后芯片会回复CMD_SUCCESS然后上位机开始发送UU编码的数据流每20行附加一个校验和。C 0x00000000 1073742336 1024\r\n将RAM中0x40000200开始的1024字节数据复制到Flash的0x00000000地址。验证与运行M 0x00000000 1073742336 1024\r\n比较Flash和RAM中的数据是否一致。G 0x00000000 0\r\n跳转到地址0x00000000执行用户程序。5.3 代码读保护CRP机制与安全考量CRP是保护你知识产权和固件安全的重要机制。通过在Flash的0x000001FC地址写入特定模式可以启用不同级别的保护。CRP1 (0x12345678)作用禁用JTAG调试接口。ISP限制允许部分更新。但不能读写RAM低端区域0x40000200以下不能单独擦写扇区0除非全片擦除禁用Compare命令。适用于需要现场增量升级但又想保护核心代码扇区0的场景。CRP2 (0x87654321)作用禁用JTAG。ISP限制更加严格。禁止Read Memory、Write to RAM、Go、Copy RAM to Flash、Compare命令。擦除命令只能全片擦除。适用于产品发布后完全禁止通过ISP读取和修改代码只允许全片擦除后重新烧录的场景。CRP3 (0x43218765)作用禁用JTAG并且当扇区0存在有效用户代码时完全禁用通过P0.14进入ISP模式。影响这是最高级别的保护。一旦启用且程序有效常规的ISP入口将被封锁。你必须在自己的应用程序中实现通过其他途径如网络、USB触发IAP来更新固件。如果应用程序没有留后门芯片将无法再被更新。启用前务必三思致命警告如果你启用了CRP3然后又不小心烧录了一个有bug的、无法触发IAP升级的程序那么这颗芯片就“变砖”了无法再通过常规手段恢复。因此在开发阶段绝对不要启用CRP3。产品发布前也必须经过极其严格的测试确保IAP升级通道万无一失。6. 常见问题排查与实战经验汇总十几年下来我在LPC213x的ADC、DAC和Flash操作上踩遍了几乎所有能踩的坑。下面这个表格是我整理的“避坑速查表”希望能帮你节省大量调试时间。问题现象可能原因排查步骤与解决方案ADC采样值跳动大不准1. 参考电压VREF不稳或噪声大。2. 模拟输入信号源阻抗过高。3. PCB布局不佳数字噪声串扰。4. ADC时钟ADCCLK超速。1. 用示波器测量VREF引脚纹波确保使用独立基准源并加足够大的滤波电容如10uF钽电容0.1uF陶瓷电容。2. 检查信号源电路必要时加电压跟随器缓冲。3. 检查VSSA和VSSD的单点连接模拟信号走线远离数字信号特别是时钟线。4. 核对CLKDIV设置确保PCLK/(CLKDIV1) 4.5MHz。ADC转换完成标志DONE一直为01. ADC未上电PDN位为0。2. 在Burst模式下读取了ADDRx而非ADGDR。3. 启动模式START配置错误。1. 确认ADCR的PDN位位21已置1并等待了足够的稳定时间3ms。2. Burst模式下应轮询或中断响应ADGDR的DONE位。3. 单次转换时确保向START字段位26:24写入了001。DAC输出有噪声或驱动能力弱1. 负载过重阻抗过低或容性负载过大。2. VREF噪声大。3. 输出变化时有数字毛刺。1.绝对不要用DAC直接驱动负载必须使用运放缓冲电压跟随器。2. 同ADC优化VREF电路。3. 在DAC输出端添加一个RC低通滤波器如1kΩ 0.1uF截止频率约1.6kHz可有效平滑。程序无法启动总是进入ISP模式1. P0.14引脚外部无上拉电阻处于浮空状态。2. Flash扇区0的用户代码校验和错误。3. 误启用了CRP3且用户代码有效。1.硬件上在P0.14和3.3V之间添加一个4.7kΩ-10kΩ的上拉电阻。2.软件上检查链接脚本确保中断向量表正确且0x14地址的校验和计算正确。3. 如果启用了CRP3只能通过全片擦除在无有效代码时或用户程序中的IAP来恢复。IAP操作导致系统死机或重启1. 擦写Flash时未处理中断。2. 参数地址、长度未对齐。3. 堆栈空间不足或溢出。4. 时钟频率参数传错。1.在调用IAP前必须关闭总中断__disable_irq()操作完成后再开启。2. 仔细检查目标地址256字节对齐、源地址字对齐和长度合法值。3. 增大堆栈大小确保IAP调用时SP指向安全区域。4. 确认传入的时钟频率单位是kHz。ISP烧录时校验失败1. 串口波特率不匹配或有误差。2. 目标板供电不足导致Flash编程时电压跌落。3. UU编码/解码或校验和计算错误。1. 使用更精确的晶振或尝试略低的波特率如57600。2. 确保编程时电源有足够余量可在VDD附近加大电容。3. 使用成熟的烧录工具如Flash Magic、LPC21ISP进行对比排查自定义上位机程序的编码错误。启用CRP后无法再连接调试器这是CRP的设计目的禁用JTAG。如果只是CRP1/CRP2可以通过拉低P0.14进入ISP模式然后执行全片擦除命令E 0 最后一个扇区号CRP即可被清除。CRP3在用户代码有效时无法通过ISP清除必须通过用户代码的IAP功能来解除或者让代码失效如擦除扇区0后再进入ISP。最后分享一个我个人的深刻体会在开始任何Flash写操作无论是ISP还是IAP之前一定要先完整地读一遍目标扇区并做好备份。尤其是在开发IAP固件升级功能时我强烈建议在应用程序中开辟一个独立的、小的“引导加载程序Bootloader”它只负责更新主应用程序区。主程序区和Bootloader区互相校验、互相备份。这样即使升级中途断电Bootloader依然完好可以重新尝试升级极大提升了系统的鲁棒性。LPC213x的Flash分为多个扇区为这种安全引导设计提供了天然的便利。

相关新闻