STM32读写flash

一、工程创建

打开STM32CubeMX,配置RCC,将PC13设置为GPIO_Output

在这里插入图片描述

配置系统时钟树

在这里插入图片描述

调整堆栈大小

在这里插入图片描述

二、代码配置

将flash.c和flash.h加入到工程中

flash.h

#ifndef _flash_H_
#define _flash_H_

#include "stm32f1xx_hal.h"

/*********************************************************************/
//                        变量定义
/*********************************************************************/
//-- 用途划分
// 0x0800FC00-0x0800FFFF -- 使用最后4k 个字节用来存放电机信息
#define FMC_FLASH_BASE      0x08000000 	// FLASH的起始地址
#define APP_MAX_SIZE        0x00010000  // 


#define FMC_FLASH_END        0x08010000  // FLASH的结束地址 256
#define DEVICE_INFO_ADDRESS  0x0800C000  //(STM32_FLASH_END - DEVICE_INFO_SIZE)   // 设备信息起始地址
#define DEVICE_LOG_ADDRESS   0x0800E000  //(STM32_FLASH_END - 2*DEVICE_INFO_SIZE) // 设备日志起始地址



#define FMC_FLASH_SIZE 64			          // 定义Flash大小,单位KB


#if FMC_FLASH_SIZE < 256
#define FMC_SECTOR_SIZE 1024            // 字节
#define MOD_SECTOR_SIZE 0X3FF
#define PAGE_COUNT_BY16 512
#else
#define FMC_SECTOR_SIZE	2048
#define MOD_SECTOR_SIZE 0X7FF
#define PAGE_COUNT_BY16 1024
#endif





/*********************************************************************/
//                        函数声明
/*********************************************************************/
void FlashWriteBuff( const uint32_t destination_address, uint8_t *const buffer,uint32_t length );
void FlashReadBuff(const uint32_t source_address,uint8_t *const buffer,uint16_t length);




#endif

flash.c

#include "flash.h"
// 不检查的写入
// WriteAddr:起始地址
// pBuffer:  数据指针
// NumToWrite:字节数数
void FlashWriteNoCheck( uint32_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite )
{
    uint16_t i;

    for( i=0; i<NumToWrite; i+=4 )
    {
        while( HAL_OK != HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, WriteAddr+i,*(uint32_t *)(pBuffer+i) ) );
    }

}

extern void FLASH_PageErase(uint32_t PageAddress);
void FlashWriteBuff( const uint32_t destination_address, uint8_t *const buffer,uint32_t length )
{
    uint16_t i;
    uint8_t FlashBuff[FMC_SECTOR_SIZE];
    uint32_t StartAddress = destination_address - destination_address%FMC_SECTOR_SIZE;
    uint16_t Offset = destination_address - StartAddress;
    uint8_t *pBuf = buffer;
    uint32_t remaindNum = length;

    HAL_StatusTypeDef status = HAL_ERROR;

    // 地址检查
    if( (destination_address < FMC_FLASH_BASE) || ( destination_address + length >= FMC_FLASH_END) || (length <= 0) )
        return;

    HAL_FLASH_Unlock();	// 解锁
    do
    {
        // 读出一页数据
        for(i=0; i < FMC_SECTOR_SIZE; i += 4 )
            *(uint32_t *)(FlashBuff+i) = *(uint32_t *)(StartAddress+i);

        // 修改要改入的数据
        for ( i=0; (i+Offset)<FMC_SECTOR_SIZE && i< remaindNum; i++ )
            *(FlashBuff+Offset+i) = *(pBuf+i);


        // 擦除一ROW数据
        FLASH_PageErase( StartAddress );

        // HAL库 FLASH_PageErase有BUFF,要加上下面三行代码
        while( status != HAL_OK )
            status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
        CLEAR_BIT(FLASH->CR, FLASH_CR_PER);

        // 写入数据
        FlashWriteNoCheck( StartAddress,FlashBuff,FMC_SECTOR_SIZE );

        // 为下一页做准备
        StartAddress +=  FMC_SECTOR_SIZE;
        remaindNum -= i;
        pBuf += i;
        Offset = 0;

    } while( remaindNum > 0 );

    HAL_FLASH_Lock();  // 上锁
		
}



// 从FLASH中读指定长度数据
void FlashReadBuff(const uint32_t source_address,uint8_t *const buffer,uint16_t length)
{
    uint16_t i;
    uint8_t Offset = 0;
    uint32_t StartAddress = source_address;
    uint16_t data;

    // 地址检测
    if( source_address + length > FMC_FLASH_END ) return;

    // 如果没有对16齐
    if( source_address & 1 )
    {
        Offset = 1;
        StartAddress = source_address-1;
    }

    // flash的操作要求16对齐 最小读写操作16个比特
    if ( Offset )
    {
        data = *(uint16_t *)(StartAddress);
        buffer[0] = data >> 8;
        StartAddress += 2;
    }

    for ( i = 0; i < (length-Offset); i += 2)
    {
        data = *(uint16_t *)(StartAddress+i);
        buffer[i+Offset] = (data & 0xFF);
        if ( (i+Offset) < (length - 1) )
            buffer[i + Offset + 1] = (data >> 8);
    }

}

将文件加入到工程后,在main.c中加入

#include "flash.h"

在这里插入图片描述

	uint8_t i;
	uint8_t FlashTest[] = "Hello This is ZhangShiSan Flash Test DEMO";

/****************************************/

	FlashWriteBuff( DEVICE_INFO_ADDRESS, 			FlashTest,sizeof(FlashTest) );        // 写入数据到Flash
	for(i=0;i<255;i++)
	FlashWBuff[i] = i;
	
  	FlashWriteBuff(DEVICE_INFO_ADDRESS+ sizeof(FlashTest),FlashWBuff,255);  // 写入数据到Flash
	FlashReadBuff(DEVICE_INFO_ADDRESS+ sizeof(FlashTest),FlashRBuff,255);  // 从Flash中读取数

在这里插入图片描述

uint8_t FlashWBuff [255];
uint8_t FlashRBuff [255];

在这里插入图片描述

三、实验结果

编译成功后将程序通过ST-link下载到板子中

进入调试界面,打开Memory1窗口

在这里插入图片描述

打开watch1窗口并勾选自动变量更新

在这里插入图片描述

通过Enter expression将FlashWBuff和FlashRBuff加入到观察窗口

在这里插入图片描述

在memory中输入0x0800c000,回车

在这里插入图片描述

F5运行,我们可以看到FlashRBuff里的内容变得和FlashWBuff里的一样了,表示我们写入flash成功

在这里插入图片描述

接着查看memory,FlashTest的内容写入成功

在这里插入图片描述

四、总结

本次实验进行了简单的FLASH读写

五、参考文献

https://blog.csdn.net/zhanglifu3601881/article/details/96632971

  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: STM32L4系列微控制器的Flash入对齐是指在进行数据入操作时,需按照特定的对齐规则进行操作。这是由于Flash入操作必须按照特定的字节顺序进行,否则可能会导致数据入错误。 STM32L4系列微控制器的Flash入对齐要求以字为单位进行,即每次入的数据长度必须是4字节(32位)的整数倍。如果入的数据长度不满足该要求,就需要进行数据对齐处理,通常是通过在数据前面添加填充字节来使其长度满足要求。 例如,如果要入长度为5字节的数据到Flash中,就需要进行对齐处理。在此情况下,可以添加3个填充字节,使总长度变为8字节,然后再进行入操作。这样就满足了Flash入对齐的要求。 对Flash进行入对齐操作的目的是确保数据入的可靠性和正确性。如果不按照要求进行对齐,可能会导致数据入错位或错误,进而影响系统的稳定性和功能。 总之,STM32L4系列微控制器的Flash入对齐要求数据长度必须是4字节的整数倍,如果不满足要求,则需要进行数据对齐处理。这样可以保证数据的正确入,提高系统的可靠性。 ### 回答2: 在进行STM32 L4系列芯片的Flash入操作时,对齐是非常重要的一个因素。对齐是指在数据Flash存储器时,需要按照特定的规则将数据的存储地址与Flash内存的块边界对齐。对齐的目的是提高数据访问效率和保证入数据的正确性。 在STM32 L4系列芯片中,Flash内存是以块的形式进行管理的,每个块的大小为一个固定的字节数。当进行Flash入操作时,需要保证待入数据的存储地址是块大小的倍数,即对齐于块边界。 对齐的好处主要有两点。首先,对齐可以提高数据访问的速度,因为Flash存储器是按块进行操作的,如果数据不对齐,可能会导致读取或入操作跨越多个块,增加了访问时间。而对齐可以保证数据操作的范围在一个块内,减少了对其他块的访问,提高了效率。 其次,对齐可以确保入数据的正确性。Flash存储器在进行入操作时,只能对整个块进行擦除和入,而不能对部分数据进行操作。如果数据不对齐,可能会导致需要修改的数据与其他数据混杂在同一个块中,从而导致擦除整个块,进而丢失其他数据。而对齐可以保证每个块只包含待入的数据,避免了数据的损失。 总之,STM32 L4系列芯片的Flash入对齐非常重要。正确的对齐可以提高数据访问效率和确保数据的正确性。在进行Flash入操作时,需要根据Flash内存块的大小,保证待入数据的存储地址是块大小的倍数,以充分利用Flash存储器的性能和功能。 ### 回答3: 在进行STM32 L4系列微控制器的Flash入时,对齐是一个很重要的概念。 对齐意味着将数据按照特定的边界地址进行整理和存储。在STM32 L4系列中,Flash入的最小单位是字(Word),每个字大小为4字节(32位)。因此,对齐的概念是基于字节的,要求每次入的数据长度是4的倍数。 对齐是必要的,因为Flash入操作必须按照特定的规则进行。如果数据的长度不是4的倍数,并且没有对齐到起始地址,则会导致无效的入操作,从而导致数据错误或者系统不稳定。 在进行Flash入操作时,需要确保待入数据的长度是4的倍数,并且起始地址是对齐的。一个简单的方法是使用字节对齐的数据类型或者使用填充字节(padding bytes)将数据补齐到4的倍数,并确保起始地址是对齐的。 另外,ST提供了一些库函数来帮助进行Flash入操作的对齐。例如,通过调用HAL_FLASH_Program函数,可以以字节为单位进行连续入,该函数会自动进行对齐。 总之,对齐是STM32 L4系列Flash入的一个重要概念,确保数据长度是4的倍数,并且起始地址是对齐的是必要的,以避免入操作错误和系统不稳定。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值