STM32_HAL_使用FPEC实现闪存的读写

STM32的FLASH结构

  1. 主存储器(Main Memory):这是STM32中最大的存储区域,用于存储用户的程序代码、常量数据以及程序运行时不变的数据。STM32的主存储器通常被组织为多个扇区(sector),每个扇区的大小不同,可以是几个KB到几十KB不等。这些扇区可以被独立擦除,但不能独立编程。

  2. 信息块(Information Block):这个区域通常包含了STM32微控制器的唯一标识码(UID)、产品型号、生产批次等信息。这些信息对于产品的追踪和生产管理是非常有用的,但是在正常编程时不会修改这部分数据。

    1. 系统存储器(System Memory):这部分存储区域通常用于存储ST公司提供的bootloader。系统存储器的内容是在生产时被固化在芯片中的,用户一般不能修改。

    2. 选项字节(Option Bytes):这些字节用于配置微控制器的某些选项,例如读保护、写保护、BOR级别(Brown-out Reset Level)、软件或硬件看门狗等。选项字节的内容可以通过软件编程来修改,但需要遵循特定的编程流程。

  3. OTP区域(One-Time Programmable Area):这是一些只能编程一次的区域,用于存储一些关键的安全信息或者配置参数。一旦编程之后,这些信息就无法更改。

型号范例

STM32 F 103 Z E T 6

家族

“STM32 “表示32bit的MCU

产品类型

“F”表示基础型

具体特性

“103”基础型

引脚数目

“Z”表示144个引脚, 其他常用的为: C表示48引脚, R表示64引脚, V表示100引脚, “Z”表示144个引脚, B表示208引脚, N表示216引脚

FLASH大小

E表示512KB, 其他常用的为: 4表示16KB(小容量ld), 6表示32KB(小容量ld), 8表示64KB(中容量md), B表示128KB(中容量md), C表示256 KB(大容量hd), E表示512 KB(大容量hd), F表示768KB(超大容量xl), G表示1024KB(超大容量xl),

封装

“T”表示QFP封装,这个是最常用的封装

温度

“6”表示温度等级为A :-40~85°

STM32 Flash编程的注意事项:

  1. 扇区和页的结构:STM32的Flash扇区和页的大小根据不同的型号会有所不同。例如,一些STM32型号的页大小可能是128字节或256字节,而扇区大小可能是2KB、4KB、8KB等。

  2. 编程(写)操作:编程操作只能在已经擦除的页上进行,且一次只能编程一页。你不能在未擦除的页上直接编程,因为这可能会导致数据损坏。

  3. 擦除操作:在编程之前,目标页所在的扇区必须先被擦除。擦除操作会清除扇区内的所有数据,将所有位设置为1。

  4. 写保护:STM32的Flash通常具有写保护功能,以防止意外写入或擦除。在编程之前,可能需要确保相应的写保护功能被禁用。

  5. 地址对齐:在编程时,写入的数据必须与页的起始地址对齐。如果写入的数据跨越了页的边界,就需要分成多次编程操作。

  6. 固件升级:在进行固件升级时,通常会选择一个特定的扇区来存储新的固件映像,这个扇区通常被称为“引导扇区”或“更新扇区”。

  7. 特殊扇区:有些扇区可能被保留用于存储Bootloader或其他重要的系统代码,因此在编程时应该避免对这些扇区进行操作。

stm32的FPEC与FSMC的区别

在STM32中,FPEC和FSMC是两个不同的功能模块,它们服务于不同的目的。

  1. FPEC (Flash Program and Erase Controller):

    • FPEC是STM32的一个模块,负责控制内置的Flash存储器的编程(烧写)和擦除操作。
    • 它允许微控制器在运行时重新编程自己的Flash,这意味着可以不通过外部编程器而直接在微控制器上更新固件。
    • FPEC还支持扇区擦除和整个Flash的擦除操作,确保了固件更新的灵活性。
  2. FSMC (Flexible Static Memory Controller):

    • FSMC是STM32的一个接口,它允许微控制器与外部静态存储器(如SRAM、ROM、NOR闪存和NAND闪存)进行通信。
    • FSMC支持多种访问模式,包括8位、16位和32位,以及不同的时序控制,以适应各种外部存储设备的操作需求。
    • FSMC的灵活性使其可以用于多种应用,如扩展微控制器的存储空间,或者连接图形液晶显示器(LCD)等设备。

在使用STM32进行嵌入式系统设计时,开发者可以根据需要选择是否使用FPEC和FSMC。例如,当需要频繁更新固件或者使用外部存储器扩展存储空间时,这两个模块就特别有用。

FPEC

STM32微控制器中的FPEC(Flash Program and Erase Controller)是负责管理闪存编程和擦除的硬件模块。FPEC允许微控制器对自己的内置闪存进行读写操作,这是固件更新、数据存储和其他类似应用的基础。

FPEC的主要功能包括:

  1. 编程(Programming):将数据写入闪存。STM32的闪存通常以半字(16位)或字(32位)为单位进行编程。

  2. 擦除(Erasing):清除闪存中的数据,通常是以扇区(sector)为单位的。STM32的闪存扇区大小不一,从几个KB到几十KB不等。

  3. 读取(Reading):从闪存中读取数据,这是最简单的操作,不需要特殊的硬件支持。

  4. 选项字节编程(Option Byte Programming):配置微控制器的某些选项,如读保护、写保护、BOR级别等。

步骤

用STM32的标准库或HAL库:

  1. 配置闪存接口

    • 确保时钟已经使能到闪存接口。
    • 如果需要,配置闪存访问时间(LATENCY),这通常在高速时钟下是必需的。
  2. 解锁闪存编程控制寄存器

    • 使用HAL_FLASH_Unlock()FLASH_Unlock()函数来解锁闪存编程和擦除控制。
  3. 擦除扇区

    • 使用HAL_FLASHEx_Erase()FLASH_ErasePage()函数来选择并擦除要写入的扇区。STM32的闪存被分为多个扇区,每个扇区可以独立擦除。
    • 等待擦除完成,可以通过检查闪存状态寄存器来判断。
  4. 编程闪存

    • 使用HAL_FLASH_Program()FLASH_ProgramWord()函数将数据编程到闪存中。这个操作通常是以半字或字为单位的。
    • 确保在编程之前扇区已经被擦除。
    • 等待编程完成,并检查闪存状态寄存器是否有错误发生。
  5. 读取闪存

    • 直接通过指针访问闪存地址来读取数据。闪存的读取操作是最简单的,不需要特殊的硬件支持。
  6. 配置选项字节(如果需要):

    • 使用HAL_FLASH_OB_Program()FLASH_OB_Program()函数来配置选项字节。
    • 选项字节的编程可能需要特定的序列和条件,比如在执行选项字节编程之前可能需要禁用全局中断。
  7. 锁定闪存编程控制寄存器

    • 使用HAL_FLASH_Lock()FLASH_Lock()函数来锁定闪存编程和擦存控制,防止意外的写入。
  8. 错误处理

    • 在编程和擦除过程中,如果发生错误,通常需要通过读取闪存状态寄存器来确定错误类型,并采取相应的措施。

框图

HAL配置

STM32CubeMX可以帮助用户初始化FPEC(Flash Programming and Erase Controller),但这是在生成的代码中自动完成的,而不是通过STM32CubeMX的用户界面直接配置

1打开GPIO中断

2配置时钟

3打开UART以显示数据

 

即可生成代码

代码编写

由于内部FLASH本身存储有程序数据,若不是有意删除某段程序代码,一般不应修改程序空间的内容,所以在使用 内部FLASH存储其它数据前需要了解哪一些空间已经写入了程序代码,存储了程序代码的扇区都不应作任何修改。 通过查询应用程序编译时产生的“*.map”后缀文件,可以了解程序存储到了哪些区域,

找.map文件(可以确定变量的地址)

步骤操作:

  1. 编译项目:首先确保你已经编译了你的STM32项目。在Keil 5中,这通常是通过点击“Build”菜单下的“Rebuild all”来完成的。

  2. 查看项目设置:在Keil 5中,默认情况下.map文件是在编译过程中自动生成的。你可以在项目的选项设置中确认这一点。点击“Project”菜单下的“Options for Target”打开目标选项窗口。

  3. 输出目录:在目标选项窗口中,选择“Output”标签页。在这里,你可以看到“Select folder for object files”和“Select folder for listing files”。这些选项指定了对象文件和列表文件(包括.map文件)的输出目录。

  4. 查找.map文件:在指定的输出目录中,查找与你项目同名的.map文件。例如,如果你的项目名为MyProject.uvprojx,那么.map文件可能被命名为MyProject.map

  5. 打开.map文件:找到.map文件后,你可以使用文本编辑器(如Notepad++或Visual Studio Code)打开它,以便查看和解析其中的内容。

截取重要的一段解释

Execution Region ER_IROM1确实指的是用户编写程序所要的空间大小,即用户编写的程序代码在Flash存储器中实际占用的空间。这个区域的大小取决于用户编写的代码、链接器分配的其他段(如数据段、未初始化数据段等)的大小,以及链接器在编译和链接过程中所做的优化和调整。

==============================================================================

Memory Map of the image
/*程序的入口点,即程序开始执行的地址。在这个特定的例子中,Image Entry point的值为0x08000131。

这意味着在STM32微控制器启动时,它将从这个地址开始执行程序。这个地址是在Flash存储器中的,对于STM32系列微控制器,通常起始地址是0x08000000,但由于Flash存储器是分段的,不同的段可能会有不同的起始地址。*/
  Image Entry point : 0x08000131
 /*程序ROM加载空间*/

  Load Region LR_IROM1 (Base: 0x08000000, Size: 0x0000137c, Max: 0x00080000, ABSOLUTE)

//Load Region LR_IROM1:
Base: 基地址,即Flash存储器中这个区域的起始地址,这里是0x08000000。
Size: 区域的大小,这里是0x0000137c字节。
Max: 区域的最大值,即Flash存储器中这个区域可以使用的最大地址,这里是0x00080000。
ABSOLUTE: 表示这个区域的地址是绝对的,即在整个Flash存储器中是固定不变的。

/*程序ROM执行空间*/
    Execution Region ER_IROM1 (Exec base: 0x08000000, Load base: 0x08000000, Size: 0x0000136c, Max: 0x00080000, ABSOLUTE)

//Execution Region ER_IROM1:
Exec base: 执行基地址,与加载基地址相同,这里是0x08000000。
Load base: 加载基地址,与加载基地址相同,这里是0x08000000。
Size: 执行区域的大小,这里是0x0000136c字节。
Max: 执行区域的最大值,与加载区域的最大值相同,这里是0x00080000。
ABSOLUTE: 表示这个区域的地址是绝对的。

//总结来说,Load Region LR_IROM1和Execution Region ER_IROM1描述的是同一个Flash区域,这个区域用于存储程序代码。Load Region是指程序被加载到Flash中的地址,而Execution Region是指程序实际执行时的地址。由于STM32微控制器在启动时会从Flash中加载程序代码并执行,所以这两个地址是相同的。

    Exec Addr    Load Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x08000000   0x08000000   0x00000130   Data   RO            3    RESET               startup_stm32f103xe.o
    0x08000130   0x08000130   0x00000008   Code   RO         2341  * !!!main             c_w.l(__main.o)
    0x08000138   0x08000138   0x00000034   Code   RO         2500    !!!scatter          c_w.l(__scatter.o)
    0x0800016c   0x0800016c   0x0000001a   Code   RO         2502    !!handler_copy      c_w.l(__scatter_copy.o)
    0x08000186   0x08000186   0x00000002   PAD
    0x08000188   0x08000188   0x0000001c   Code   RO         2504    !!handler_zi        c_w.l(__scatter_zi.o)
    0x080001a4   0x080001a4   0x00000002   Code   RO         2368    .ARM.Collect$$libinit$$00000000  c_w.l(libinit.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2375    .ARM.Collect$$libinit$$00000002  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2377    .ARM.Collect$$libinit$$00000004  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2380    .ARM.Collect$$libinit$$0000000A  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2382    .ARM.Collect$$libinit$$0000000C  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2384    .ARM.Collect$$libinit$$0000000E  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2387    .ARM.Collect$$libinit$$00000011  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2389    .ARM.Collect$$libinit$$00000013  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2391    .ARM.Collect$$libinit$$00000015  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2393    .ARM.Collect$$libinit$$00000017  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2395    .ARM.Collect$$libinit$$00000019  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2397    .ARM.Collect$$libinit$$0000001B  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2399    .ARM.Collect$$libinit$$0000001D  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2401    .ARM.Collect$$libinit$$0000001F  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2403    .ARM.Collect$$libinit$$00000021  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2405    .ARM.Collect$$libinit$$00000023  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2407    .ARM.Collect$$libinit$$00000025  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2411    .ARM.Collect$$libinit$$0000002C  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2413    .ARM.Collect$$libinit$$0000002E  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2415    .ARM.Collect$$libinit$$00000030  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000000   Code   RO         2417    .ARM.Collect$$libinit$$00000032  c_w.l(libinit2.o)
    0x080001a6   0x080001a6   0x00000002   Code   RO         2418    .ARM.Collect$$libinit$$00000033  c_w.l(libinit2.o)
    0x080001a8   0x080001a8   0x00000002   Code   RO         2438    .ARM.Collect$$libshutdown$$00000000  c_w.l(libshutdown.o)
    0x080001aa   0x080001aa   0x00000000   Code   RO         2451    .ARM.Collect$$libshutdown$$00000002  c_w.l(libshutdown2.o)
    0x080001aa   0x080001aa   0x00000000   Code   RO         2453    .ARM.Collect$$libshutdown$$00000004  c_w.l(libshutdown2.o)
    0x080001aa   0x080001aa   0x00000000   Code   RO         2455    .ARM.Collect$$libshutdown$$00000006  c_w.l(libshutdown2.o)
    0x080001aa   0x080001aa   0x00000000   Code   RO         2458    .ARM.Collect$$libshutdown$$00000009  c_w.l(libshutdown2.o)
    0x080001aa   0x080001aa   0x00000000   Code   RO         2461    .ARM.Collect$$libshutdown$$0000000C  c_w.l(libshutdown2.o)
    0x080001aa   0x080001aa   0x00000000   Code   RO         2463    .ARM.Collect$$libshutdown$$0000000E  c_w.l(libshutdown2.o)
    0x080001aa   0x080001aa   0x00000000   Code   RO         2466    .ARM.Collect$$libshutdown$$00000011  c_w.l(libshutdown2.o)
    0x080001aa   0x080001aa   0x00000002   Code   RO         2467    .ARM.Collect$$libshutdown$$00000012  c_w.l(libshutdown2.o)
    0x080001ac   0x080001ac   0x00000000   Code   RO         2343    .ARM.Collect$$rtentry$$00000000  c_w.l(__rtentry.o)
    0x080001ac   0x080001ac   0x00000000   Code   RO         2345    .ARM.Collect$$rtentry$$00000002  c_w.l(__rtentry2.o)
    0x080001ac   0x080001ac   0x00000006   Code   RO         2357    .ARM.Collect$$rtentry$$00000004  c_w.l(__rtentry4.o)
    0x080001b2   0x080001b2   0x00000000   Code   RO         2347    .ARM.Collect$$rtentry$$00000009  c_w.l(__rtentry2.o)
    0x080001b2   0x080001b2   0x00000004   Code   RO         2348    .ARM.Collect$$rtentry$$0000000A  c_w.l(__rtentry2.o)
    0x080001b6   0x080001b6   0x00000000   Code   RO         2350    .ARM.Collect$$rtentry$$0000000C  c_w.l(__rtentry2.o)
    0x080001b6   0x080001b6   0x00000008   Code   RO         2351    .ARM.Collect$$rtentry$$0000000D  c_w.l(__rtentry2.o)
    0x080001be   0x080001be   0x00000002   Code   RO         2372    .ARM.Collect$$rtexit$$00000000  c_w.l(rtexit.o)
    0x080001c0   0x080001c0   0x00000000   Code   RO         2420    .ARM.Collect$$rtexit$$00000002  c_w.l(rtexit2.o)
    0x080001c0   0x080001c0   0x00000004   Code   RO         2421    .ARM.Collect$$rtexit$$00000003  c_w.l(rtexit2.o)
    0x080001c4   0x080001c4   0x00000006   Code   RO         2422    .ARM.Collect$$rtexit$$00000004  c_w.l(rtexit2.o)
    0x080001ca   0x080001ca   0x00000002   PAD
    0x080001cc   0x080001cc   0x00000040   Code   RO            4    .text               startup_stm32f103xe.o
    0x0800020c   0x0800020c   0x0000004e   Code   RO         2337    .text               c_w.l(rt_memclr_w.o)
    0x0800025a   0x0800025a   0x00000006   Code   RO         2339    .text               c_w.l(heapauxi.o)
    0x08000260   0x08000260   0x0000004a   Code   RO         2359    .text               c_w.l(sys_stackheap_outer.o)
    0x080002aa   0x080002aa   0x00000012   Code   RO         2361    .text               c_w.l(exit.o)
    0x080002bc   0x080002bc   0x00000008   Code   RO         2369    .text               c_w.l(libspace.o)
    0x080002c4   0x080002c4   0x0000000c   Code   RO         2430    .text               c_w.l(sys_exit.o)
    0x080002d0   0x080002d0   0x00000002   Code   RO         2441    .text               c_w.l(use_no_semi.o)
    0x080002d2   0x080002d2   0x00000000   Code   RO         2443    .text               c_w.l(indicate_semi.o)
    0x080002d2   0x080002d2   0x00000002   Code   RO          213    i.BusFault_Handler  stm32f1xx_it.o
    0x080002d4   0x080002d4   0x00000002   Code   RO          214    i.DebugMon_Handler  stm32f1xx_it.o
    0x080002d6   0x080002d6   0x00000004   Code   RO           13    i.Error_Handler     main.o
    0x080002da   0x080002da   0x00000002   PAD
    0x080002dc   0x080002dc   0x00000024   Code   RO         1328    i.HAL_Delay         stm32f1xx_hal.o
    0x08000300   0x08000300   0x000001f8   Code   RO         1638    i.HAL_GPIO_Init     stm32f1xx_hal_gpio.o
    0x080004f8   0x080004f8   0x0000000c   Code   RO         1332    i.HAL_GetTick       stm32f1xx_hal.o
    0x08000504   0x08000504   0x00000010   Code   RO         1338    i.HAL_IncTick       stm32f1xx_hal.o
    0x08000514   0x08000514   0x00000024   Code   RO         1339    i.HAL_Init          stm32f1xx_hal.o
    0x08000538   0x08000538   0x00000040   Code   RO         1340    i.HAL_InitTick      stm32f1xx_hal.o
    0x08000578   0x08000578   0x0000003c   Code   RO          288    i.HAL_MspInit       stm32f1xx_hal_msp.o
    0x080005b4   0x080005b4   0x00000040   Code   RO         1804    i.HAL_NVIC_SetPriority  stm32f1xx_hal_cortex.o
    0x080005f4   0x080005f4   0x00000024   Code   RO         1805    i.HAL_NVIC_SetPriorityGrouping  stm32f1xx_hal_cortex.o
    0x08000618   0x08000618   0x0000012c   Code   RO         1496    i.HAL_RCC_ClockConfig  stm32f1xx_hal_rcc.o
    0x08000744   0x08000744   0x0000004c   Code   RO         1505    i.HAL_RCC_GetSysClockFreq  stm32f1xx_hal_rcc.o
    0x08000790   0x08000790   0x00000320   Code   RO         1508    i.HAL_RCC_OscConfig  stm32f1xx_hal_rcc.o
    0x08000ab0   0x08000ab0   0x00000028   Code   RO         1809    i.HAL_SYSTICK_Config  stm32f1xx_hal_cortex.o
    0x08000ad8   0x08000ad8   0x0000007c   Code   RO         1073    i.HAL_TIMEx_MasterConfigSynchronization  stm32f1xx_hal_tim_ex.o
    0x08000b54   0x08000b54   0x0000005a   Code   RO          350    i.HAL_TIM_Base_Init  stm32f1xx_hal_tim.o
    0x08000bae   0x08000bae   0x00000002   PAD
    0x08000bb0   0x08000bb0   0x00000024   Code   RO          166    i.HAL_TIM_Base_MspInit  tim.o
    0x08000bd4   0x08000bd4   0x000000dc   Code   RO          359    i.HAL_TIM_ConfigClockSource  stm32f1xx_hal_tim.o
    0x08000cb0   0x08000cb0   0x00000048   Code   RO          167    i.HAL_TIM_MspPostInit  tim.o
    0x08000cf8   0x08000cf8   0x000000cc   Code   RO          422    i.HAL_TIM_PWM_ConfigChannel  stm32f1xx_hal_tim.o
    0x08000dc4   0x08000dc4   0x0000005a   Code   RO          425    i.HAL_TIM_PWM_Init  stm32f1xx_hal_tim.o
    0x08000e1e   0x08000e1e   0x00000002   Code   RO          427    i.HAL_TIM_PWM_MspInit  stm32f1xx_hal_tim.o
    0x08000e20   0x08000e20   0x000000b4   Code   RO          430    i.HAL_TIM_PWM_Start  stm32f1xx_hal_tim.o
    0x08000ed4   0x08000ed4   0x00000002   Code   RO          215    i.HardFault_Handler  stm32f1xx_it.o
    0x08000ed6   0x08000ed6   0x00000002   PAD
    0x08000ed8   0x08000ed8   0x00000058   Code   RO          141    i.MX_GPIO_Init      gpio.o
    0x08000f30   0x08000f30   0x0000009c   Code   RO          168    i.MX_TIM2_Init      tim.o
    0x08000fcc   0x08000fcc   0x00000002   Code   RO          216    i.MemManage_Handler  stm32f1xx_it.o
    0x08000fce   0x08000fce   0x00000002   Code   RO          217    i.NMI_Handler       stm32f1xx_it.o
    0x08000fd0   0x08000fd0   0x00000002   Code   RO          218    i.PendSV_Handler    stm32f1xx_it.o
    0x08000fd2   0x08000fd2   0x00000002   Code   RO          219    i.SVC_Handler       stm32f1xx_it.o
    0x08000fd4   0x08000fd4   0x00000004   Code   RO          220    i.SysTick_Handler   stm32f1xx_it.o
    0x08000fd8   0x08000fd8   0x0000005e   Code   RO           14    i.SystemClock_Config  main.o
    0x08001036   0x08001036   0x00000002   Code   RO         2299    i.SystemInit        system_stm32f1xx.o
    0x08001038   0x08001038   0x0000008c   Code   RO          443    i.TIM_Base_SetConfig  stm32f1xx_hal_tim.o
    0x080010c4   0x080010c4   0x0000001a   Code   RO          444    i.TIM_CCxChannelCmd  stm32f1xx_hal_tim.o
    0x080010de   0x080010de   0x00000014   Code   RO          454    i.TIM_ETR_SetConfig  stm32f1xx_hal_tim.o
    0x080010f2   0x080010f2   0x00000010   Code   RO          455    i.TIM_ITRx_SetConfig  stm32f1xx_hal_tim.o
    0x08001102   0x08001102   0x00000002   PAD
    0x08001104   0x08001104   0x00000060   Code   RO          456    i.TIM_OC1_SetConfig  stm32f1xx_hal_tim.o
    0x08001164   0x08001164   0x0000006c   Code   RO          457    i.TIM_OC2_SetConfig  stm32f1xx_hal_tim.o
    0x080011d0   0x080011d0   0x00000068   Code   RO          458    i.TIM_OC3_SetConfig  stm32f1xx_hal_tim.o
    0x08001238   0x08001238   0x00000050   Code   RO          459    i.TIM_OC4_SetConfig  stm32f1xx_hal_tim.o
    0x08001288   0x08001288   0x00000022   Code   RO          461    i.TIM_TI1_ConfigInputStage  stm32f1xx_hal_tim.o
    0x080012aa   0x080012aa   0x00000024   Code   RO          463    i.TIM_TI2_ConfigInputStage  stm32f1xx_hal_tim.o
    0x080012ce   0x080012ce   0x00000002   Code   RO          221    i.UsageFault_Handler  stm32f1xx_it.o
    0x080012d0   0x080012d0   0x00000020   Code   RO         1811    i.__NVIC_SetPriority  stm32f1xx_hal_cortex.o
    0x080012f0   0x080012f0   0x00000038   Code   RO           15    i.main              main.o
    0x08001328   0x08001328   0x00000012   Data   RO         1509    .constdata          stm32f1xx_hal_rcc.o
    0x0800133a   0x0800133a   0x00000010   Data   RO         2300    .constdata          system_stm32f1xx.o
    0x0800134a   0x0800134a   0x00000002   PAD
    0x0800134c   0x0800134c   0x00000020   Data   RO         2498    Region$$Table       anon$$obj.o


    Execution Region RW_IRAM1 (Exec base: 0x20000000, Load base: 0x0800136c, Size: 0x000006b8, Max: 0x00010000, ABSOLUTE)

    Exec Addr    Load Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x20000000   0x0800136c   0x0000000c   Data   RW         1346    .data               stm32f1xx_hal.o
    0x2000000c   0x08001378   0x00000004   Data   RW         2302    .data               system_stm32f1xx.o
    0x20000010        -       0x00000048   Zero   RW          169    .bss                tim.o
    0x20000058        -       0x00000060   Zero   RW         2370    .bss                c_w.l(libspace.o)
    0x200000b8        -       0x00000200   Zero   RW            2    HEAP                startup_stm32f103xe.o
    0x200002b8        -       0x00000400   Zero   RW            1    STACK               startup_stm32f103xe.o


==============================================================================

有哪些函数

1解锁与上锁

解锁
HAL_StatusTypeDef HAL_FLASH_Unlock(void);
HAL_OK: 操作成功。
HAL_ERROR: 操作失败。
HAL_BUSY: FLASH控制器忙,操作不能执行。
HAL_TIMEOUT: 操作超时。


上锁
HAL_StatusTypeDef HAL_FLASH_Unlock(void);
HAL_OK: 操作成功。
HAL_ERROR: 操作失败。
HAL_BUSY: FLASH控制器忙,操作不能执行。
HAL_TIMEOUT: 操作超时。

2写操作

HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data);



TypeProgram:指定要执行的编程操作类型。这可以是FLASH_TYPEPROGRAM_WORD(写入一个字),FLASH_TYPEPROGRAM_HALFWORD(写入一个半字),或者FLASH_TYPEPROGRAM_DOUBLEWORD(写入一个双字)。
Address:要写入数据的FLASH地址。
Data:要写入的数据。即使你只写入一个字,这个参数也是一个64位的,因为HAL库支持写入双字操作。



HAL_OK: 操作成功。
HAL_ERROR: 操作失败。
HAL_BUSY: FLASH控制器忙,操作不能执行。
HAL_TIMEOUT: 操作超时。

3闪存擦除函数

HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *PageError);

pEraseInit:指向一个FLASH_EraseInitTypeDef结构的指针,该结构包含了擦除操作的参数,如擦除类型、起始页、页数等。
PageError:指向一个uint32_t变量的指针,该变量用于存储擦除过程中出现错误的页码(如果有的话)。


  1. TypeErase:这个成员定义了擦除操作的类型。它可以是以下值之一,这些值通常在@ref FLASH_TYPE_ERASE中定义:

    • FLASH_TYPEERASE_MASSERASE:执行整个Flash存储器的擦除。
    • FLASH_TYPEERASE_PAGEERASE:仅擦除指定的一个或多个页面。
  2. Banks:这个成员用于在大规模擦除时选择要擦除的银行。STM32微控制器可能有多个Flash存储器银行。这个参数的值通常在@ref FLASH_BANK_ERASE中定义。对于页面擦除,这个参数不被使用。

  3. Page:这个成员指定了页面擦除操作的起始页面。页面是从0开始编号的,并且这个值必须位于0和MAX_PAGE_NUMBER - 1之间。MAX_PAGE_NUMBER是微控制器Flash的最大页面数。对于大规模擦除,这个参数不被使用。

  4. NbPages:这个成员指定了要擦除的页面数量。这个值必须在1和(MAX_PAGE_NUMBER - 起始页的值)之间。对于大规模擦除,这个参数不被使用。

4获取闪存状态函数

HAL_FLASH_StateTypeDef HAL_FLASH_GetState(void);

这个函数可以用来检查FLASH是否处于忙碌状态

返回值
HAL_FLASH_STATE_BUSY: FLASH忙,一个编程或擦除操作正在进行中。
HAL_FLASH_STATE_ERROR: FLASH发生错误,可能是因为编程或擦除操作失败。
HAL_FLASH_STATE_READY: FLASH准备就绪,没有进行中的操作,并且没有错误。

5等待操作完成函数

HAL_StatusTypeDef HAL_FLASH_WaitForLastOperation(uint32_t Timeout);

当你需要对FLASH进行操作时,通常需要等待上一个操作完成。这可以通过检查FLASH的状态或者使用特定的等待函数来实现


Timeout:等待操作完成的超时时间(以毫秒为单位)。
这个函数返回一个HAL_StatusTypeDef类型的值,用于指示操作是否成功。可能的返回值包括:

HAL_OK: 操作成功完成。
HAL_ERROR: 操作失败。
HAL_TIMEOUT: 等待操作完成时发生超时。

6读取闪存特定地址的函数      //库中没有

main.h源码

使用了UART   GPIO   

不用初始换写入的闪存   库已经初始化了

思路

uart输出地址内的数据1秒一次

按键点击一下触发中断中断内部是写了,先将地址的值先擦除,在写入数据数据会将原来的值加一

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint32_t address =0x0807F800;//地址data_32的地址(在MOP文件中看一下哪些位置没有写入数据)

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
	
		uint32_t data_values=*(uint32_t*)address;//要写入的数据
	
	
		//解锁  FLASH(闪存)
		HAL_FLASH_Unlock();
		
		//擦除页          										//必须擦除要写入的页在写入不然数据不能保存或写入失败
		FLASH_EraseInitTypeDef eraseInit;
											
		//eraseInit.Banks=FLASH_BANK_1;//只有一块闪存时可以不写  //指的是那一块
		eraseInit.NbPages=1;//擦除几页
		eraseInit.PageAddress=address;//开始地址
		eraseInit.TypeErase=FLASH_TYPEERASE_PAGES;//按页擦除
	
		//变量存放错误  值为0xffffff  为成功
		uint32_t pag=0xFFFFFFFF;
		//开始擦写
		HAL_FLASHEx_Erase(&eraseInit,&pag);
	
		//写入数据
		//1代表地址是多大16 32 64 2:地址3:数据
		if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,address,(data_values+1))==HAL_OK){
			
				uint8_t a[]={"写入成功"};
				HAL_UART_Transmit(&huart1,a,8,20);
		}else{
			
				uint8_t a[]={"写入失败"};
				HAL_UART_Transmit(&huart1,a,8,20);
		}
	
		//上锁
		HAL_FLASH_Lock();
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		char data_char[19];
		//闪存地址的值
		long data_=*(uint32_t*)address;
		//将值转换为字符
		sprintf(data_char,"数据是:%ld",data_);
		HAL_UART_Transmit(&huart1,(uint8_t*)data_char,18,20);
		HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

重点总结

在STM32微控制器中,Flash存储器的未编程区域通常会被初始化为0xFF(因为Flash擦除后的状态是所有位都是1)。然而,SRAM(静态随机存取存储器)的未初始化区域则可能包含随机数据,这些数据是上电后或者上次执行程序后遗留下来的。

使用前必须先解锁,之后在上所

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值