5.IAP - FLASH

本文详细介绍了STM32的时钟系统与Flash操作,包括HSI、HSE等时钟源的选择及其对Flash操作的影响。此外,还深入探讨了IAP编程原理,包括程序跳转、中断向量表偏移等问题,并提供了调试指导。

一.Flash与时钟系统的关系
        
    STM32系统时钟:
                 HSE 高速外部时钟,电路上焊接的外部时钟,一般是4Mhz-16Mhz,板子上的是8Mhz -->是外接的晶振,耗能高于内部,但准确度也高
                 LSE 低速外部时钟,电路板上焊接的外部时钟,32.768Khz,用于RTC
                 HSI 高速内部时钟,STM32内部的时钟,默认为8Mhz  -->是单片机内部的RC振荡电路     
                 LSI 低速内部时钟  40KHz,用于内部看门狗。
                 STM32的时钟选择在启动文件中进行选择。复位后使用HSI,并且SW,HPRE,PPRE1,PPRE2,ADCPRE,MCO bit被设置。时钟频率高会增加功耗,
             而且抗干扰能力会降低。
   STM32FLASH操作说明:
      STM32的存储器由三个部分组成。主存储器/信息块/闪存存储器寄存器接口。
                主存储器:地址由0x080 00000~0x80 40000的大小(256KB,每页2K,共128页)。当BOOT0/BOOT1接地时,由此启动程序。
                信息块  : 用于存放ST自带的 启动程序,用于串口下载程序,当BOOT0接3.3V BOOT1接GND时将由此启动程序。
                
   ****************************************************************************************************************************          
   *程序异常/调试状况及原因分析:*             
   ***************************
            **当开启外部时钟,关闭内部时钟时,操作Flash时会导致程序在FLASH_WaitForLastBank1Operation()等待操作同步时进入HardFault。
            **当时系统时钟频率设置为 72Mhz时,需要相应设置 FLASH_SetLatency()的等待周期为2。 Flash的操作频率不超过24Mhz。
            **系统关闭HSI内部时钟,导致操作Flash出现错误?

    在官方提供的闪存编程手册中,有如下规定:进行闪存编程操作时(写或擦除),必须打开内部的RC振荡器(HSI)。因为flash的读写需要HSI提供内部时钟。
 
 二、IAP编程说明
        一般程序的下载方式有三种:ICP ISP IAP。
        
        IAP编程的核心是单片机内部含有可重复编程闪存控制器,拥有丰富的外设接口。
        
        关键操作 : 1.设置应用程序在闪存的位置,通过IDE进行修改。
                   2. 设置应用程序的中断向量表的偏移位置,通过库函数或者寄存器进行修改。
                   3.设置跳转程序。
 
三、IAP调试 说明
              -->调试错误:
                   gpio的rcc时钟未开启,导致程序不能正常运行--->键盘不能正常工作。
              IAP跳转程序的原理:
                   BootLoader:用于接收更新的APP程序,且跳转到APP程序。
                   通过修改APP程序的中断向量表,确定APP程序的Reset Handler地址。在BootLoader程序里,将APP程序写到STM32内部的Flash固定地址,
               读取APP程序中断向量表的复位地址,即通过操作指针的方式 *(vu32*)Flash_ResetHandler_Addr,读取Flash地址上的值,且初始化APP程序
               的堆栈指针,代码区的第一个地址用于存放栈顶地址。
              
              --> 调试出现错误:
                      读取Flash上复位地址的值出现错误,查找错误原因:既然是读取Flash上的值不正确,可能由以下几个方面问题
                      (1).通过串口接收数据出现异常。通过比对接收的数据buff【】和相应Bin文件内容,证明串口收发正常。则考虑下面因素。
                      (2).串口接收数据正常,读写Flash数据出现错误。
                           1.读数据出现错误:读取一个flash上确定的值,发现正常,证明读操作正常。
                           2.写数据出现错误:因为Flash写操作能正常运行,则证明是Iap整体写flash操作出现错误。
           经最终排查,因为写flash时地址操作出现错误,导致程序不能写入正确地址,所以读到的数据便是错误的。
           要根据现象一步步排查原因,确定的原因没必要反复验证!!!

    

 注意事项:

    由IAP程序跳转到APP程序不能正常执行中断程序的原因:

    ①程序间的相互跳转只是改变程序计数器PC指针的位置,再修改中断向量表的位置使CPU在发生硬件中断时重映射到相应的位置执行另一套中断服务程序。不会改变

  已经设置的寄存器的值,所以已经开启的中断会导致APP程序中的程序无法正常进行中断。

    解决办法:①使能所有已开中断 ②复位时钟 ③复位IO口及关闭总中断

     ②在IAP程序的中断中,如在串口中断中执行跳转命令,无论如何修改,在APP程序中均不会触发中断了。所以,一定不能在中断中进行跳转。

 


             
             
    
          
                 

转载于:https://www.cnblogs.com/nyqm/p/7955639.html

<think>我们有一个任务:将两个HEX文件(ztr_bms_boot.hex和ztr_bms_app.hex)合并,并用0xFF填充地址范围0x0000到0x20000(注意:这个地址范围可能是指从0x0000到0x20000,即128KB的空间),最终输出一个合并后的HEX文件ztrbms_boot_with_app.hex。 用户提供的命令是: bin\srec_cat.exe .\ztr_bms_boot.hex -intel .\output\ztr_bms_app.hex -intel -fill 0xFF 0x0000 0x20000 -range 0x0000 0x20000 -o output\combinehex\ztrbms_boot_with_app.hex -Intel 我们需要详细解释这个命令,并说明可能的问题及解决方法。 注意:在HEX文件中,地址通常是32位的(如0x08000000),但这里给出的地址范围是0x0000到0x20000,这可能是基于某个基地址的偏移,或者是绝对地址。需要明确的是,srec_cat命令中的地址参数是绝对地址。 然而,在微控制器中,Flash的起始地址通常不是0x0000(0x0000可能是内存映射的起始地址,但Flash往往在另一个位置,如0x08000000)。因此,我们必须注意这个地址范围是否与芯片的实际Flash地址对应。 但是,用户命令中直接使用了0x0000到0x20000,这可能是因为: 1. HEX文件中的地址已经是绝对地址(例如,bootloader从0x0000开始,但实际芯片可能是0x08000000,而HEX文件已经定位到0x08000000,但用户在这里用0x0000表示偏移?) 2. 或者用户希望将整个地址空间视为从0x0000开始,然后通过偏移来调整? 实际上,在srec_cat命令中,我们处理的是文件中的地址。如果HEX文件中的地址是从0x08000000开始的,那么我们不能直接使用0x0000作为起始地址,而应该使用0x08000000。 因此,我们需要明确:用户命令中的地址范围0x0000到0x20000,应该是指从绝对地址0x0000到0x20000?还是说用户实际上想表达的是从基地址(如0x08000000)开始,到0x08020000?如果是后者,那么命令中的地址就需要修改。 但是,用户命令中使用了`-range 0x0000 0x20000`,这个选项的作用是限制输出文件只包含这个地址范围(即只输出这个范围内的数据)。而`-fill 0xFF 0x0000 0x20000`则是在这个地址范围内填充0xFF。 然而,注意:在合并两个HEX文件时,我们通常需要指定每个文件在最终地址空间中的位置。用户命令中,第一个文件(ztr_bms_boot.hex)没有指定偏移,所以它使用文件中的地址。第二个文件(ztr_bms_app.hex)也没有指定偏移?不对,用户命令中在第二个文件后没有使用`-offset`选项。所以两个文件都将使用它们自己的地址。 但是,命令中有一个`-fill`选项,它会在指定的地址范围内填充0xFF,然后两个文件的数据会覆盖这个填充区域。也就是说,最终在这个地址范围内,有数据的地方用数据覆盖,没有数据的地方保持0xFF。 另外,`-range`选项会裁剪输出文件,只保留指定地址范围内的数据。 现在,我们详细分解命令: 命令结构: bin\srec_cat.exe .\ztr_bms_boot.hex -intel # 输入文件1,格式为Intel HEX .\output\ztr_bms_app.hex -intel # 输入文件2,格式为Intel HEX -fill 0xFF 0x0000 0x20000 # 在地址范围[0x0000, 0x20000]内填充0xFF(注意:这个填充操作会生成一个“填充块”) -range 0x0000 0x20000 # 只输出地址范围在[0x0000, 0x20000]内的数据 -o output\combinehex\ztrbms_boot_with_app.hex -Intel # 输出文件,格式为Intel HEX 但是,这个命令有一个问题:两个输入文件的数据和填充操作是依次添加的,而填充操作会覆盖整个地址范围,然后两个文件的数据会覆盖填充区域。但是,如果两个文件的数据有重叠,那么后出现的文件会覆盖前面的文件(包括填充和先前的文件数据)。因为srec_cat命令按照命令行中出现的顺序处理输入文件。 因此,在这个命令中,处理顺序是: 1. 读取ztr_bms_boot.hex 2. 读取ztr_bms_app.hex(如果两个文件有地址重叠,那么app的数据会覆盖boot的数据) 3. 然后执行填充操作(-fill):在0x0000到0x20000范围内填充0xFF。注意:填充操作实际上是在当前数据的基础上,将指定地址范围内没有数据的地方填上0xFF。但是,如果之前已经有数据,则保持不变。然而,这里有一个关键点:填充操作只对当前还没有数据的地址进行填充,不会覆盖已有的数据。 4. 然后,使用-range选项,只保留0x0000到0x20000范围内的数据。 但是,注意:srec_cat命令中,多个输入文件会按照顺序叠加(后面的文件会覆盖前面文件的相同地址),而填充操作(-fill)是在它出现的位置对当前已经合并的数据进行填充(填充那些没有数据的区域)。因此,在这个命令中,填充操作出现在两个文件之后,所以填充操作会对两个文件合并后的结果进行填充。 但是,我们通常希望先填充整个区域,然后依次将文件放入(这样文件数据会覆盖填充值)。所以,正确的顺序应该是: 1. 填充整个区域(生成一个填充块) 2. 将第一个文件(boot)合并到填充块上(覆盖填充块中相应地址) 3. 将第二个文件(app)合并到当前结果上(覆盖相应地址) 然而,用户命令中,两个文件出现在填充操作之前,那么填充操作是在两个文件之后执行的。这样,填充操作只会填充两个文件都没有覆盖到的区域。这通常也是我们想要的,因为两个文件已经提供了数据,填充操作补全空白部分。 所以,这个顺序是合理的。 但是,注意:命令中两个文件的位置,如果boot和app的地址有重叠,那么后出现的app文件会覆盖boot文件。所以,我们需要确保boot和app的地址不重叠,或者我们希望app覆盖boot的某些部分(比如boot后面的一部分被app覆盖,这是不合理的,因为boot和app应该是连续的或者不重叠的)。 因此,我们需要检查两个HEX文件的地址范围,确保它们不重叠(除非有特殊需求,比如boot文件包含跳转到app的引导代码,而app文件从某个地址开始,两者在地址上是连续的,没有重叠)。 另外,用户命令中使用了绝对地址0x0000到0x20000(128KB),这个地址范围是否与两个HEX文件中的地址匹配?如果不匹配,那么可能得不到正确的结果。 例如,如果boot.hex的地址范围是0x08000000到0x0800B000,而app.hex的地址范围是0x0800C000到0x08020000(假设0x0800B000到0x0800C000是空白),那么我们需要将填充范围设置为0x08000000到0x08020000(即0x0000对应0x08000000,0x20000对应0x08020000?不对,因为0x20000是128KB,所以绝对地址应该是0x08000000到0x08200000?)。这里显然存在地址不一致。 所以,用户命令中的0x0000到0x20000很可能是相对地址,或者是用户希望将整个地址空间映射到0x0000开始?但HEX文件通常包含绝对地址。 因此,我们需要明确:这个命令中使用的地址是绝对地址,而且必须与HEX文件中的地址一致。 如果HEX文件中的地址是从0x08000000开始的,那么我们应该使用: -fill 0xFF 0x08000000 0x08020000 -range 0x08000000 0x08020000 但用户命令中的是0x0000到0x20000,这会导致填充和范围限制在0x0000到0x20000,而HEX文件中的数据地址(比如0x08000000)不在这个范围内,所以这些数据会被-range选项过滤掉,导致输出的HEX文件为空(除了地址0x0000到0x20000内的数据,但HEX文件的数据地址通常不会在这个范围)。 因此,这个命令很可能是有问题的。 解决方案:使用正确的地址范围,即芯片Flash的绝对地址范围。例如,如果Flash起始地址是0x08000000,大小为128KB,则结束地址为0x08000000+0x20000=0x08200000?不对,0x20000就是128KB,所以结束地址应该是0x08000000+0x20000-1=0x081FFFFF。但通常我们使用起始地址和结束地址(包含)时,结束地址是0x081FFFFF。不过,srec_cat命令中的结束地址是不包含的?实际上,srec_cat的地址范围是[起始, 结束),即半开区间。所以,如果结束地址是0x08200000,那么实际覆盖的地址范围是0x08000000到0x081FFFFF。 因此,正确的命令应该是(假设Flash地址从0x08000000开始): -fill 0xFF 0x08000000 0x08200000 # 填充范围:0x08000000(包含)到0x08200000(不包含) -range 0x08000000 0x08200000 # 输出这个范围内的数据 但是,用户命令中的是0x0000到0x20000,这显然不对。所以,我们需要根据实际情况调整。 如果用户确实希望将地址映射到0x0000开始(即去掉基地址0x08000000),那么我们需要在输入文件时使用偏移量调整地址。例如,将boot.hex的地址减去0x08000000,这样它就从0x0000开始。但这样操作需要两个文件都做偏移,而且还要注意地址对齐。 不过,通常我们不这样做,因为烧录到Flash时,需要的是绝对地址。 因此,我们假设用户命令中的0x0000到0x20000是笔误,实际应该是0x08000000到0x08200000(假设芯片Flash起始地址为0x08000000,大小为128KB)。 所以,修改后的命令为: bin\srec_cat.exe .\ztr_bms_boot.hex -Intel .\output\ztr_bms_app.hex -Intel -fill 0xFF 0x08000000 0x08200000 -range 0x08000000 0x08200000 -o output\combinehex\ztrbms_boot_with_app.hex -Intel 但是,如果用户确实想用0x0000到0x20000(例如,在仿真时使用从0x0000开始的地址),那么我们需要对两个输入文件进行地址偏移,将它们的地址减去0x08000000(如果它们原本是从0x08000000开始的话)。这时,命令应该改为: bin\srec_cat.exe .\ztr_bms_boot.hex -Intel -offset -0x08000000 .\output\ztr_bms_app.hex -Intel -offset -0x08000000 -fill 0xFF 0x0000 0x20000 -range 0x0000 0x20000 -o output\combinehex\ztrbms_boot_with_app.hex -Intel 但是,这样处理后的HEX文件地址是从0x0000开始的,烧录时需要知道这个地址偏移,或者烧录工具支持重新定位。 因此,我们需要根据实际需求来选择。 总结:用户原始命令可能因为地址范围不正确而导致生成的HEX文件不正确(没有数据,或者数据不在输出范围内)。 另外,注意:srec_cat命令中,输入文件的顺序很重要。如果两个文件有重叠的地址,后出现的文件会覆盖先出现的文件。因此,如果boot和app有重叠,那么应该先放boot,再放app(这样app可以覆盖boot中不需要的部分?)但通常boot和app应该是连续的,没有重叠。如果有重叠,说明有冲突。 所以,我们假设boot和app没有地址重叠。 现在,我们来详细解释用户命令中的每个部分: bin\srec_cat.exe # 调用srec_cat工具 .\ztr_bms_boot.hex -intel # 第一个输入文件,Intel HEX格式 .\output\ztr_bms_app.hex -intel # 第二个输入文件,Intel HEX格式 -fill 0xFF 0x0000 0x20000 # 在地址范围[0x0000, 0x20000)内,对当前合并的数据中没有数据的区域填充0xFF -range 0x0000 0x20000 # 只输出地址在[0x0000, 0x20000)范围内的数据 -o output\combinehex\ztrbms_boot_with_app.hex -Intel # 输出文件,Intel HEX格式 可能出现的问题及解决办法: 1. **地址范围不正确**:如果两个HEX文件中的地址不在0x0000到0x20000范围内,则输出文件将为空(或只有填充数据)。解决办法:使用正确的地址范围(通常是芯片Flash的绝对地址范围)。 2. **两个文件地址重叠**:如果两个文件有重叠的地址,后出现的文件会覆盖前面的文件。解决办法:确保两个文件的地址不重叠,或者按正确顺序放置(将需要保留的文件放在后面)。 3. **填充值不正确**:如果填充值不是0xFF,而是其他值,可能会影响芯片运行(如Flash编程要求空白为0xFF)。所以填充0xFF通常是安全的。 4. **文件路径问题**:如果输入文件不存在或输出路径不存在,命令会失败。解决办法:检查文件路径,确保输出目录存在。 5. **地址对齐问题**:srec_cat要求地址范围对齐,但一般不会出错。 建议:使用绝对地址(芯片Flash地址)来指定填充和范围。 因此,如果芯片Flash起始地址为0x08000000,大小为128KB,则结束地址为0x08200000(注意:半开区间,实际覆盖到0x081FFFFF)。那么命令应修改为: bin\srec_cat.exe .\ztr_bms_boot.hex -Intel .\output\ztr_bms_app.hex -Intel -fill 0xFF 0x08000000 0x08200000 -range 0x08000000 0x08200000 -o output\combinehex\ztrbms_boot_with_app.hex -Intel 如果用户希望保留原始命令中的地址范围(0x0000到0x20000),那么需要先调整两个输入文件的地址(减去基地址0x08000000),使用-offset选项。 但是,我们不知道基地址是多少,所以需要用户提供。 因此,我们给出两种情况的命令: 情况一:使用绝对地址(推荐) bin\srec_cat.exe .\ztr_bms_boot.hex -Intel .\output\ztr_bms_app.hex -Intel -fill 0xFF [起始地址] [结束地址] -range [起始地址] [结束地址] -o output\combinehex\ztrbms_boot_with_app.hex -Intel 情况二:使用相对地址(需要偏移) bin\srec_cat.exe .\ztr_bms_boot.hex -Intel -offset -[基地址] .\output\ztr_bms_app.hex -Intel -offset -[基地址] -fill 0xFF 0x0000 0x20000 -range 0x0000 0x20000 -o output\combinehex\ztrbms_boot_with_app.hex -Intel 其中[基地址]是HEX文件中使用的基地址(如0x08000000),[起始地址]和[结束地址]是绝对地址(如0x08000000和0x08200000)。 注意:-offset选项的用法:负偏移表示减去一个值。 最后,我们还可以使用srec_cat的其他功能,比如生成二进制文件(BIN)而不是HEX文件,但用户要求输出HEX文件。 因此,我们根据用户的原始命令,解释其含义,并指出可能的问题和解决方案。 </think> 以下是针对 `srec_cat.exe` 命令的详细解析,包括参数含义、使用方法和注意事项: ### 一、命令解析 ``` bin\srec_cat.exe .\ztr_bms_boot.hex -intel .\output\ztr_bms_app.hex -intel -fill 0xFF 0x0000 0x20000 -range 0x0000 0x20000 -o output\combinehex\ztrbms_boot_with_app.hex -Intel ``` 1. **输入文件设置** - `.\ztr_bms_boot.hex -intel` 指定第一个输入文件为 `ztr_bms_boot.hex`,格式为 Intel HEX。 - `.\output\ztr_bms_app.hex -intel` 指定第二个输入文件为 `ztr_bms_app.hex`,格式为 Intel HEX。 2. **填充与范围控制** - `-fill 0xFF 0x0000 0x20000` 在地址范围 `0x0000` 到 `0x20000`(128KB)内,所有空白区域填充 `0xFF`。 *公式:* $$ \forall a \in [0x0000, 0x20000], \text{ if } a \notin D_{\text{boot}} \cup D_{\text{app}} \text{ then } B[a] = 0\text{xFF} $$ 其中 $D_{\text{boot}}$ 和 $D_{\text{app}}$ 分别为两个 HEX 文件的数据点集。 - `-range 0x0000 0x20000` 限制输出文件仅包含此地址范围的数据(超出范围的数据将被丢弃)。 3. **输出设置** - `-o output\combinehex\ztrbms_boot_with_app.hex -Intel` 输出合并后的文件到指定路径,格式为 Intel HEX。 --- ### 二、关键技术点 1. **合并逻辑** - 文件按命令行顺序处理:`boot.hex` 先加载,`app.hex` 后加载(后者覆盖前者重叠地址的数据)。 - 填充操作在文件加载*后*执行,确保空白区域被正确填充[^1]。 - 地址范围限制确保最终文件严格限定在 128KB 内。 2. **地址范围选择** - `0x0000-0x20000` 对应 128KB 空间(计算:$0x20000 = 131072 \text{ bytes}$)。 - 实际应用中需根据芯片 Flash 物理地址调整(如 STM32 通常为 `0x08000000-0x08020000`)[^3]。 --- ### 三、常见问题与解决方案 1. **地址范围错误** **现象**:输出文件为空或数据不完整。 **解决**: - 检查芯片实际 Flash 地址(如 STM32F4 应为 `0x08000000-0x08020000`) - 修改命令:`-fill 0xFF 0x08000000 0x08200000 -range 0x08000000 0x08200000` 2. **文件覆盖冲突** **现象**:后加载文件意外覆盖先加载文件的关键数据。 **解决**: - 使用 `srec_info` 检查文件地址范围: ```bash srec_info.exe ztr_bms_boot.hex srec_info.exe ztr_bms_app.hex ``` - 调整加载顺序或确保地址无重叠。 3. **路径错误** **现象**:`Cannot open file` 报错。 **解决**: - 使用相对路径 `..\output\ztr_bms_app.hex` 或绝对路径。 - 确保输出目录 `output\combinehex` 存在。 4. **填充值无效** **现象**:空白区域未填充 `0xFF`。 **解决**: - 确保 `-fill` 参数在输入文件*之后*指定(否则被覆盖)[^1]。 - 验证命令顺序:`输入文件 → 填充 → 范围限制 → 输出`。 --- ### 四、操作流程建议 ```mermaid graph LR A[检查文件地址范围] --> B[确认物理地址映射] B --> C[修改填充/范围参数] C --> D[执行合并命令] D --> E[验证输出文件] ``` 1. **地址验证命令**: ```bash srec_info.exe ztr_bms_boot.hex | findstr "Start End" srec_info.exe .\output\ztr_bms_app.hex | findstr "Start End" ``` 2. **推荐修正命令**(假设 Flash 基址 `0x08000000`): ```bash bin\srec_cat.exe ^ .\ztr_bms_boot.hex -Intel ^ .\output\ztr_bms_app.hex -Intel ^ -fill 0xFF 0x08000000 0x08200000 ^ -range 0x08000000 0x08200000 ^ -o output\combinehex\ztrbms_boot_with_app.hex -Intel ``` > **提示**:对于 IAP 升级,后续可转换为 BIN 格式: > ```bash > srec_cat.exe ztrbms_boot_with_app.hex -Intel -o firmware.bin -Binary > ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值