关于FLASH操作

本文详细探讨了在STM32单片机中操作FLASH的过程,包括单字节读取、写入及多字节读写。作者分析了原始代码并提出改进措施,减少了内存占用,同时讨论了编译器优化和地址对齐问题。还介绍了多字节操作时的复杂情况,以及实验中的数据存储和赋值差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么要写这篇

  有些断电保存的功能需要操作FLASH,固件更新的功能也需要操作FLASH,当意识到它的重要性后,投入一些关注是自然而然的事情。

  熟悉一个项目所用到的芯片,了解到FLASH相关能用的只有5个底层函数:

void FMC_Open(void);		/* Enable FMC function */
int32_t FMC_Erase(uint32_t u32PageAddr);		/* Erase a page, page size if 512 bytes */
uint32_t FMC_Read(uint32_t u32Addr);	/* Read a word from specified flash address */
void FMC_Write(uint32_t u32Addr, uint32_t u32Data);		/* Writes a word data to specified flash address */
void FMC_Close(void);		/* Disable FMC function */

  公司有人写了一个FLASH的封装,我敲了一下代码,基本理解其要干什么,然后考虑我能给它添加什么改动。

单字节读取

源代码

uint8_t fmc_read_byte(uint32_t addr)
{
   
    uint32_t offset_addr = addr - (addr & 3); //addr-(addr%4)
    union_t  f_data;
    uint8_t  ret;

    if (addr < boot_flag_addr || addr > APROM_END_ADDR ) return 0xFF;

    FMC_Open();
    f_data.four[0] = FMC_Read(offset_addr);
    FMC_Close();
    ret = f_data.one[addr & 3];
    return ret;
}

源代码分析

  了解到32位单片机的FLASH地址是4字节跳跃式递增的,每个地址能存储4字节的数值。要读取FLASH中某一个地址的字节,需要先4字节对齐得到地址,读取该地址的4字节数据中对应字节,返回。

image-20210820102626801

uint8_t fmc_read_byte(uint32_t addr)
{
   
    /* 将地址4字节对齐后获得新的地址 */
    /* 地址合法性检测 */
    /* 使能FLASH */
    /* 读取4字节 */
    /* 失能FLASH */
    /* 返回对应地址的数据(一个字节) */
}

他用到的这种方式感觉很任性,随时占用512字节的连续空间作为变量。

#define FLASH_PAGE_SIZE		512

typedef union
{
   
    uint32_t four[FLASH_PAGE_SIZE >> 2];
    uint16_t two[FLASH_PAGE_SIZE >> 1];
    uint8_t  one[FLASH_PAGE_SIZE];
} union_t;

理解要实现目的后我的写法

typedef union 
{
   
    uint32_t four_bytes;
    uint8_t byte[4];
} BYTE;

uint8_t fmc_read_byte(uint32_t addr)
{
   
    if (addr < boot_flag_addr || addr > APROM_END_ADDR) return ;
    
    uint32_t start_addr = (addr >> 2) << 2;		/* Four byte alignment */
    BYTE temp_val;

    FMC_Open();
    temp_val.four_bytes = FMC_Read(start_addr);
    FMC_Close();

    return temp_val.byte[addr - start_addr];
}

一些说明

  关于联合体的使用方式可能需要说明一下,涉及到大小端模式。

对于小端模式(我用的电脑和单片机都是小端模式)
BYTE temp_val;
temp_val.four_bytes = 0x08070605;
小端模式为 :低地址存储低字节
temp_val.byte[0] 和 temp_val.byte[1] 地址对比,下标小的0 为低地址
temp_val.four_bytes 的0x05 和 0x06 字节对比, 表示数值小的0x05(0x05 * (160) ) 为低字节

我的改进措施

  • 通过右移2位(除4)去掉余数得商,再左移2位(乘4)得到 4字节对齐后地址
  • 读取的起始地址的4字节,返回的是地址偏移量的字节,可读性较好
  • 使用占用4字节的联合体,极大减少空间占用

我的担心

  使用右移左移的方式我担心会被编译器优化掉,验证方式有三种:

  • 看编译后汇编代码。假设说addr
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值