STM32 使用HAL库操作FLASH

这篇具有很好参考价值的文章主要介绍了STM32 使用HAL库操作FLASH。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文参考:STM32CubeMX学习笔记(51)——读写内部Flash - 简书

STM32F103C8T6

stmhalflash.h

#ifndef __STMHALFLASH_H__
#define __STMHALFLASH_H__

/* FLASH大小:STM32F103C8T6:64K */
#define STM32FLASH_SIZE             0x00010000UL
/* FLASH起始地址 */
#define STM32FLASH_BASE             0x08000000UL
/* FLASH结束地址 */
#define STM32FLASH_END              (STM32FLASH_BASE|STM32FLASH_SIZE)
/* FLASH页大小:1K */
#define STM32FLASH_PAGE_SIZE        0x400
/* FLASH总页数 */
#define STM32FLASH_PAGE_NUM         (STM32FLASH_SIZE/STM32FLASH_PAGE_SIZE)


#define WRITE_START_ADDR            ((unsigned int)0x08008000)
#define WRITE_END_ADDR              ((unsigned int)0x0800C000)


int Internal_ReadFlash(unsigned int addrStart,void *pData,unsigned int dataLen);

int Internal_WriteFlash(unsigned int addrStart,const unsigned short *pData,unsigned int dataLen);


#endif

stmhalflash.c

#include "stmhalflash.h"
#include "main.h"


// FLASH一个扇区数据的缓存
unsigned short FlashBuffer[STM32FLASH_PAGE_SIZE/2] = {0};

/**
 * @brief 内部FLASH读取
 * 
 * @param addrStart [IN]读取的地址
 * @param pData     [OUT]指向需要操作的数据
 * @param dataLen   [IN]数据字节长度
 * @return int 读出成功的字节数
 */
int Internal_ReadFlash(unsigned int addrStart,void *pData,unsigned int dataLen)
{
    unsigned int nread = dataLen;
    unsigned char *pBuffer = (unsigned char *)pData;
    const unsigned char *pAddr = (const unsigned char *)addrStart;

    /* 检测地址和数据合法性 */
    if( (!pData) || (addrStart < STM32FLASH_BASE) || (addrStart > STM32FLASH_END) )
    {
        return 0;
    }

    /* 读取数据不少于4字节时,每次读4字节 */
    while((nread >= sizeof(unsigned int)) && ( ((unsigned int)pAddr) <= (STM32FLASH_END - 4) ) )
    {
        *(unsigned int *)pBuffer = *(unsigned int *)pAddr;
        pBuffer += sizeof(unsigned int);
        pAddr += sizeof(unsigned int);
        nread -= sizeof(unsigned int);
    }

    /* 读取剩余不足4字节的数据 */
    while(nread && ( ((unsigned int)pAddr)<STM32FLASH_END ))
    {
        *pBuffer++ = *pAddr++;
        nread--;
    }

    return dataLen - nread;
}




/**
 * @brief 内部Flash页擦除
 * 
 * @param pageAddress   [IN]擦除起始地址
 * @param nbPages       [IN]擦除页数
 * @return int 0-OK !0-Err
 */
static int Internal_ErasePage(unsigned int pageAddress,unsigned int nbPages)
{
    unsigned int pageError = 0;
    
    FLASH_EraseInitTypeDef eraseInit;
    eraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
    eraseInit.PageAddress = pageAddress;
    eraseInit.Banks = FLASH_BANK_1;
    eraseInit.NbPages = nbPages;
    
    if(HAL_FLASHEx_Erase(&eraseInit,&pageError) != HAL_OK)
    {
        return -1;
    }
    return 0;
}


/**
 * @brief 内部Flash无检查写入(半字写入)
 * 
 * @param addrStart [IN]写入的地址
 * @param pData     [IN]执行需要操作的数据
 * @param dataLen   [IN]写入数据的半字数
 * @return unsigned int 实际写入的字节数 
 */
static unsigned int Internal_WriteFlashNoCHeck(unsigned int addrStart,const unsigned short *pData,unsigned int dataLen)
{
    unsigned int nwrite = dataLen;              //记录剩余要写入的数据量
    unsigned int addrmax = STM32FLASH_END - 2;  //记录写入的最大FLASH地址
    
    while(nwrite)
    {
        /* 地址非法检查 */
        if(addrStart > addrmax)
        {
            break;
        }
        
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,addrStart,*pData);
        if( (*(volatile unsigned short*)addrStart) != *pData )
        {
            break;
        }
        
        nwrite--;
        pData++;
        addrStart += 2;
        
    }
    
    return (dataLen - nwrite);
}


/**
 * @brief 内部Flash写入
 * 
 * @param addrStart     [IN]写入的地址
 * @param pData         [IN]指向需要操作的数据
 * @param dataLen       [IN]写入数据半字数
 * @return unsigned int 实际写入的字节数
 */
int Internal_WriteFlash(unsigned int addrStart,const unsigned short *pData,unsigned int dataLen)
{
    unsigned int i = 0;
    unsigned int pagepos = 0;       //页位置
    unsigned int pageoff = 0;       //页内偏移地址
    unsigned int pagefre = 0;       //页内空余空间
    unsigned int offset  = 0;       //Address在Flash中的偏移
    unsigned int nwrite = dataLen;  //记录剩余要写入的数据量
    const unsigned short *pBuffer = (const unsigned short *)pData;
    
    /* 检测非法地址 */
    if( (addrStart < STM32FLASH_BASE) || (addrStart > (STM32FLASH_END - 2)) || (dataLen == 0) || (pData == NULL) )
    {
        return 0;
    }
    
    /* 解锁FLASH */
    HAL_FLASH_Unlock();
    
    
    //计算写入地址在FLASH中的偏移地址
    offset = addrStart - STM32FLASH_BASE;
    //计算当前页位置
    pagepos = offset/STM32FLASH_PAGE_SIZE;
    //计算要写入数据的起始地址在当前页内的偏移地址(半字写入)
    pageoff = ((offset%STM32FLASH_PAGE_SIZE)>>1);
    //计算当前页内空余空间(半字写入)
    pagefre = ((STM32FLASH_PAGE_SIZE>>1) - pageoff);
    //要写入的数量低于当前页空余量
    if(nwrite <= pagefre)
    {
        pagefre = nwrite;
    }
    
    while(nwrite !=0)
    {
        /* 检查是否超页 */
        if(pagepos >= STM32FLASH_PAGE_NUM)
        {
            //写入地址超出FLASH最大位置
            break;
        }
        
        /* 读取一页 */
        Internal_ReadFlash(STM32FLASH_BASE + pagepos*STM32FLASH_PAGE_SIZE,FlashBuffer,STM32FLASH_PAGE_SIZE);
        
        /* 检查是否需要擦除 */
        for(i=0;i<pagefre;i++)
        {
            if( *(FlashBuffer + pageoff + i) != 0xFFFF ) // FLASH擦除后默认内容全为0xFF
            {
                break;
            }
        }
        
        if(i < pagefre)
        {
            /* 需要擦除 */
            unsigned int count = 0;
            unsigned int index = 0;
            unsigned int PageError = 0;
            
            FLASH_EraseInitTypeDef pEraseInit;
            
            /* 擦除一页 */
            pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
            pEraseInit.PageAddress = STM32FLASH_BASE+pagepos*STM32FLASH_PAGE_SIZE;
            pEraseInit.Banks = FLASH_BANK_1;
            pEraseInit.NbPages = 1;
            if(HAL_FLASHEx_Erase(&pEraseInit,&PageError) != HAL_OK)
            {
                break;
            }
            
            /* 复制缓存 */
            for(index = 0;index<pagefre;index++)
            {
                *(FlashBuffer+pageoff+index) = *(pBuffer+index);
            }
            
            /* 写回FLASH */
            count = Internal_WriteFlashNoCHeck(STM32FLASH_BASE+pagepos*STM32FLASH_PAGE_SIZE,FlashBuffer,(STM32FLASH_PAGE_SIZE>>1));
            if(count != (STM32FLASH_PAGE_SIZE>>1))
            {
                nwrite -= count;
                break;
            }
            
        }else{
            /* 无需擦除,直接写 */
            unsigned int count = Internal_WriteFlashNoCHeck(addrStart,pBuffer,pagefre);
            if(count != pagefre)
            {
                nwrite -= count;
                break;
            }
        }
        
        
        pBuffer += pagefre;             //读取地址递增
        addrStart += (pagefre<<1);      //写入地址递增
        nwrite -= pagefre;              //更新剩余未写入数据量
        
        pagepos++;                      //下一页
        pageoff = 0;                    //页内偏移地址置零
        
        /* 根据剩余量计算下次写入数据量 */
        pagefre = nwrite >= (STM32FLASH_PAGE_SIZE>>1) ? (STM32FLASH_PAGE_SIZE>>1) : nwrite;
    }
    
    /* 解锁FLASH */
    HAL_FLASH_Lock();
    
    return ((dataLen - nwrite)<<1);
}

使用示例文章来源地址https://www.toymoban.com/news/detail-658527.html

unsigned char t_arr[40]={0};
//写数据
unsigned int writedata_addr = WRITE_START_ADDR;
i=0;
if(i<100)
{
    //写入数据
    Internal_WriteFlash(writedata_addr,(unsigned short*)&t_arr[0],sizeof(t_arr)/2);
    writedata_addr+= 40;
    i++;
}

//读数据
calidata_addr = WRITE_START_ADDR;
i=0;
if(i<100)
{
    //读取数据
    Internal_ReadFlash(calidata_addr,t_arr,sizeof(t_arr));
	calidata_addr+=40;
    i++;
}

到了这里,关于STM32 使用HAL库操作FLASH的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • stm32基于HAL库驱动外部SPI flash制作虚拟U盘

    📌参考文章: https://xiaozhuanlan.com/topic/6058234791 🎞实现效果演示: 🔖上图中的读到的 FLASH_ID 所指的是针对不同容量,所对应的ID。 🔖在电脑端,支持对虚拟出来的存储器进行读写操作。 ✨如果设计成一块PCB,可以制作成一个微小容量的移动U盘。 🌿基于STM32F103,HAL库生成

    2024年02月11日
    浏览(46)
  • STM32L051使用HAL库操作实例(14)- ADC采集电压

    目录 一、前言 二、ADC外设简要说明 三、STM32CubeMX配置(本文使用的STM32CubeMX版本为6.1.2) 1.MCU选型 2.时钟使能 3.外部时钟配置 4.串口配置 5.ADC引脚配置 6.配置STM32CubeMX生成工程文件 7.点击GENERATE CODE生成工程文件 四、工程源码 五、运行状态 一、前言 本文主要介绍通过HAL库搭建

    2024年01月16日
    浏览(57)
  • cubmx基础操作,hal库基本配置流程之使用 stm32cubmx生成HAL库进行gpio点亮led(stm32h7xx)(超详细,小白教程)

    HAL库(硬件抽象层库)是一个提供对底层硬件操作的抽象的库,它使得开发者可以使用统一的接口进行硬件操作,而不必关心底层硬件的具体实现细节。HAL库通常由硬件厂商提供,用于支持其硬件设备,并为其提供标准化的接口。 HAL库的主要目的是简化底层硬件的操作,使得

    2024年02月20日
    浏览(54)
  • STM32 HAL库形式制作SPI Flash(W25Q16)的 Keil下载算法

    常见的SPI Flash:W25Qxx系列,本文以W25Q16为实例制作Keil下载算法。 如下图,红框内的东西就是下载算法。 只要导入下载算法后,就可以在烧录MCU的同时对W25Q16页进行烧录。此操作可方便LCD运用场景,字库、图片存放在外部Flash的烧录。 实际操作: 1、硬件:STM32G030C8T6、W25Q16(

    2024年02月21日
    浏览(41)
  • STM32源码阅读之HAL位操作相关

    HAL库结构基础是基于位操作+对地址读写 头文件: stm32f1xx.h 编程约定 SET_BIT中的BIT是要保证BIT的值只有一位为‘1’,其余均为‘0’ 头文件: stm32f1xx_hal_def.h

    2024年02月13日
    浏览(24)
  • STM32的GPIO操作(寄存器&HAL)

    (注:此为乐某学习记录,若有出错的地方欢迎各位指出!) 本人使用的开发板的芯片是STM32H743XIH6,所以外设也是根据此芯片来介绍。 在使用HAL库配置的时候,需要安装STM32CubeMX。此软件可在ST官网下载,剩下的安装步骤比较简单,不会单独出篇进行讲解。 STM32CubeMX下载网址

    2024年02月04日
    浏览(50)
  • STM32基于HAL库和STM32CubeMX的实时操作系统FreeRtOS开发

    1、FreeRTOS RTOS是一类操作系统,µC/OS,FreeRTOS,RTX,RT-Thread 等这些都是RTOS 类的操作系统 FreeRTOS 是众多RTOS 类操作系统中的一种,FreeRTOS 十分的小巧,可以在资源有限的微控制器中运行,FreeRTOS 也不仅仅局限于在微控制器中使用。就单从文件数量上来看FreeRTOS 要比µC/OS 少得多

    2024年02月21日
    浏览(60)
  • 【08】STM32·HAL库开发-HAL库介绍 | STM32Cube固件库介绍 | HAL库框架结构 | 如何使用HAL库及使用注意事项

      CMSIS (微控制器 软件接口标准 ):Cortex Microcontroller Software Interface Standard,是由ARM和与其合作的芯片厂商( 比如ST、NXP公司等 )、软件工具厂商( Keil、IAR公司等 ),共同制定的标准。 如果没有此标准,ARM公司的产品兼容性非常差。   下图中分为三层,第一层是用户层

    2024年02月11日
    浏览(58)
  • STM32操作系统FreeRTOS学习——基于hal库

    目录 一、基础概念 1、FreeRTOS 2、单片机编程的系统概念 a、裸机系统,包括轮询系统(不包括中断)和前后台系统(中断为前台,轮询为后台) b、多任务系统 3、FreeRTOS编程风格 a、数据类型 b、变量名的定义 c、函数名 d、宏定义 二、Cubemx创建工程 1、创建任务 2、创建队列

    2024年02月10日
    浏览(38)
  • 【HAL库】HAL库STM32cubemx快速使用

    软件:keil5、STM32Cubemx 硬件:淘宝的STM32F103C8T6最小系统 1 新建工程 2 配置RCC 选择外部时钟源。 设置外部晶振输入值,我这块板子是8M。 然后手动输入最大时钟频率,然后回车让他自动配置时钟树。我这块板子是72M。 3 配置SYS 我的下载器是SWD两根线的,所以我选这个。(一定

    2023年04月20日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包