clion开发stm32之flash驱动(f4系列)

news2024/12/26 9:30:26

前言

  1. 使用的开发工具(clion+msys2+openocd)
  2. 使用的开发版芯片stm32f407vet6
  3. 参考手册为stm32f4中文参考文档

查看中文手册

详细信息自行查阅资料详细信息自行查阅资料## 驱动代码

头文件(bsp_flash.h)

#ifndef STM32F103VET6_PROJECT_BSP_FLASH_H
#define STM32F103VET6_PROJECT_BSP_FLASH_H
#include "sys.h"

//FLASH起始地址
#define STM32_FLASH_BASE 0x08000000    //STM32 FLASH的起始地址
#define STM32_FLASH_BASE 0x08000000    //STM32 FLASH的起始地址
#define STM32_FLASH_END 0x0807FFFFUL
#define FLASH_WAITETIME  50000          //FLASH等待超时时间

//FLASH 扇区的起始地址
#define ADDR_FLASH_SECTOR_0     ((u32)0x08000000)    //扇区0起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_1     ((u32)0x08004000)    //扇区1起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_2     ((u32)0x08008000)    //扇区2起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_3     ((u32)0x0800C000)    //扇区3起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_4     ((u32)0x08010000)    //扇区4起始地址, 64 Kbytes
#define ADDR_FLASH_SECTOR_5     ((u32)0x08020000)    //扇区5起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_6     ((u32)0x08040000)    //扇区6起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_7     ((u32)0x08060000)    //扇区7起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_8     ((u32)0x08080000)    //扇区8起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_9     ((u32)0x080A0000)    //扇区9起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_10    ((u32)0x080C0000)    //扇区10起始地址,128 Kbytes
#define ADDR_FLASH_SECTOR_11    ((u32)0x080E0000)    //扇区11起始地址,128 Kbytes
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef volatile uint32_t vu32;
typedef volatile uint16_t vu16;
typedef volatile uint8_t vu8;


u32 STMFLASH_ReadBase(u32 Address, void *Buffer, u32 Size);

bool STMFLASH_WriteBase(u32 TypeProgram, u32 WriteAddr, void *pBuffer, u16 byteNum);

bool STMFLASH_Write_u8(u32 WriteAddr, u8 *pBuffer, u16 Size);

bool STMFLASH_Write_u16(u32 WriteAddr, u16 *pBuffer, u16 Size);

bool STMFLASH_Write_u32(u32 WriteAddr, u32 *pBuffer, u16 Size);

bool STMFLASH_Write_u64(u32 WriteAddr, u64 *pBuffer, u16 Size);

#endif //STM32F103VET6_PROJECT_BSP_FLASH_H

源文件(bsp_flash.c)

#include "bsp_flash.h"

static HAL_StatusTypeDef p_Status;

//读取指定地址的字(32位数据)
//faddr:读地址
//返回值:对应数据.
u32 STM32_FLASH_ReadWord(u32 faddr) {
    return *(vu32 *) faddr;
}

//获取某个地址所在的flash扇区
//addr:flash地址
//返回值:0~11,即addr所在的扇区
u8 STM32_FLASH_GetFlashSector(u32 addr) {
    if (addr < ADDR_FLASH_SECTOR_1)return FLASH_SECTOR_0;
    else if (addr < ADDR_FLASH_SECTOR_2)return FLASH_SECTOR_1;
    else if (addr < ADDR_FLASH_SECTOR_3)return FLASH_SECTOR_2;
    else if (addr < ADDR_FLASH_SECTOR_4)return FLASH_SECTOR_3;
    else if (addr < ADDR_FLASH_SECTOR_5)return FLASH_SECTOR_4;
    else if (addr < ADDR_FLASH_SECTOR_6)return FLASH_SECTOR_5;
    else if (addr < ADDR_FLASH_SECTOR_7)return FLASH_SECTOR_6;
    else if (addr < ADDR_FLASH_SECTOR_8)return FLASH_SECTOR_7;
    else if (addr < ADDR_FLASH_SECTOR_9)return FLASH_SECTOR_8;
    else if (addr < ADDR_FLASH_SECTOR_10)return FLASH_SECTOR_9;
    else if (addr < ADDR_FLASH_SECTOR_11)return FLASH_SECTOR_10;
    return FLASH_SECTOR_11;
}



/**
 * 获取地址递增数
 * @param TypeProgram
 * @return
 */
static inline u8 GetIncreasingCnt(uint32_t TypeProgram) {
    switch (TypeProgram) {
        case FLASH_TYPEPROGRAM_BYTE:
            return 1;
        case FLASH_TYPEPROGRAM_HALFWORD:
            return 3;
        case FLASH_TYPEPROGRAM_WORD:
            return 4;
        default:
            return 8;
    }
}

/**********************************************************************************
 * 函数功能:不检查的写入
 * 输入参数: WriteAddr:起始地址、pBuffer:数据指针、NumToWrite:半字(16位)数
 * 返 回 值: 无
 * 说    明:
 */
HAL_StatusTypeDef write_no_check(uint32_t TypeProgram, uint32_t WriteAddr, void *pBuffer, uint16_t NumToWrite) {
    uint8_t cnt = GetIncreasingCnt(TypeProgram);
    for (uint16_t i = 0; i < NumToWrite; i++) {
        switch (TypeProgram) {
            case FLASH_TYPEPROGRAM_BYTE:
                p_Status = HAL_FLASH_Program(TypeProgram, WriteAddr, ((u8 *) pBuffer)[i]);
                break;
            case FLASH_TYPEPROGRAM_HALFWORD:
                p_Status = HAL_FLASH_Program(TypeProgram, WriteAddr, ((u16 *) pBuffer)[i]);
                break;
            case FLASH_TYPEPROGRAM_WORD:
                p_Status = HAL_FLASH_Program(TypeProgram, WriteAddr, ((u32 *) pBuffer)[i]);
                break;
            default:
                p_Status = HAL_FLASH_Program(TypeProgram, WriteAddr, ((u64 *) pBuffer)[i]);
                break;
        }

        if (p_Status != HAL_OK) {
            return p_Status;
        }
        WriteAddr += cnt; //地址增加cnt.
    }
    return HAL_OK;
}



/**
 * 读FLASH
 * @param  Address 地址
 * @param  Buffer  存放读取的数据
 * @param  Size    要读取的数据大小,单位字节
 * @return         读出成功的字节数
 */
u32 STMFLASH_ReadBase(u32 Address, void *Buffer, u32 Size) {
    u32 nread = Size;
    vu8 *d = (vu8 *) Buffer;
    const vu8 *s = (const vu8 *) Address;
    if (!Buffer || Address < STM32_FLASH_BASE || Address >= STM32_FLASH_END)
        return 0;

    while (nread >= sizeof(uint32_t) && (((uint32_t) s) <= (STM32_FLASH_END - 4))) {
        *(vu32 *) d = *(vu32 *) s;
        d += sizeof(uint32_t);
        s += sizeof(uint32_t);
        nread -= sizeof(uint32_t);
    }

    while (nread && (((vu32) s) < STM32_FLASH_END)) {
        *d++ = *s++;
        nread--;
    }

    return Size - nread;
}
//从指定地址开始写入指定长度的数据
//特别注意:因为STM32F4的扇区实在太大,没办法本地保存扇区数据,所以本函数
//         写地址如果非0XFF,那么会先擦除整个扇区且不保存扇区数据.所以
//         写非0XFF的地址,将导致整个扇区数据丢失.建议写之前确保扇区里
//         没有重要数据,最好是整个扇区先擦除了,然后慢慢往后写.
//该函数对OTP区域也有效!可以用来写OTP区!
//OTP区域地址范围:0X1FFF7800~0X1FFF7A0F(注意:最后16字节,用于OTP数据块锁定,别乱写!!)
bool STMFLASH_WriteBase(u32 TypeProgram, u32 WriteAddr, void *pBuffer, u16 byteNum) {
    FLASH_EraseInitTypeDef FlashEraseInit;
    HAL_StatusTypeDef FlashStatus;
    u32 SectorError = 0;
    u32 addrx = 0;
    u32 endAddr = 0;
    if (WriteAddr < STM32_FLASH_BASE || WriteAddr % 4)return false;    //非法地址

    HAL_FLASH_Unlock();             //解锁
    addrx = WriteAddr;                //写入的起始地址
    endAddr = WriteAddr + byteNum;    //写入的结束地址

    if (addrx < 0X1FFF0000) {
        uint8_t cnt = GetIncreasingCnt(TypeProgram);
        while (addrx < endAddr)        //扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
        {
            if (STM32_FLASH_ReadWord(addrx) != 0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区
            {
                FlashEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;       //擦除类型,扇区擦除
                FlashEraseInit.Sector = STM32_FLASH_GetFlashSector(addrx);   //要擦除的扇区
                FlashEraseInit.NbSectors = 1;                             //一次只擦除一个扇区
                FlashEraseInit.VoltageRange = FLASH_VOLTAGE_RANGE_3;      //电压范围,VCC=2.7~3.6V之间!!
                if (HAL_FLASHEx_Erase(&FlashEraseInit, &SectorError) != HAL_OK) {
                    break;//发生错误了
                }
            } else addrx += cnt;
            FLASH_WaitForLastOperation(FLASH_WAITETIME);                //等待上次操作完成
        }
    }
    FlashStatus = FLASH_WaitForLastOperation(FLASH_WAITETIME);            //等待上次操作完成
    if (FlashStatus == HAL_OK) {
        FlashStatus = write_no_check(TypeProgram, WriteAddr, pBuffer, byteNum);
    }
    HAL_FLASH_Lock();           //上锁

    return FlashStatus == HAL_OK;
}

bool STMFLASH_Write_u8(u32 WriteAddr, u8 *pBuffer, u16 Size) {
    return STMFLASH_WriteBase(FLASH_TYPEPROGRAM_BYTE, WriteAddr, pBuffer, Size);
}

bool STMFLASH_Write_u16(u32 WriteAddr, u16 *pBuffer, u16 Size) {
    return STMFLASH_WriteBase(FLASH_TYPEPROGRAM_HALFWORD, WriteAddr, pBuffer, Size);
}

bool STMFLASH_Write_u32(u32 WriteAddr, u32 *pBuffer, u16 Size) {
    return STMFLASH_WriteBase(FLASH_TYPEPROGRAM_WORD, WriteAddr, pBuffer, Size);
}

bool STMFLASH_Write_u64(u32 WriteAddr, u64 *pBuffer, u16 Size) {
    return STMFLASH_WriteBase(FLASH_TYPEPROGRAM_DOUBLEWORD, WriteAddr, pBuffer, Size);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/546847.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华硕幻X 2023 Windows11原厂预装系统 工厂恢复安装带ASUSRecevory一键还原

华硕幻X 2023 Windows11原厂预装系统 工厂模式恢复安装带ASUSRecevory一键还原 文件地址&#xff1a;https://pan.baidu.com/s/1snKOsH3OMl3GZLqeAf-GLA?pwd8888 华硕工厂恢复系统 &#xff0c;安装结束后带隐藏分区以及机器所有驱动软件 需准备一个16G左右空u盘进行恢复 …

chatgpt赋能Python-python3怎么用

Python3入门指南&#xff1a;从基础到进阶 Python是一款简单而强大的编程语言&#xff0c;具有易读性、易学性和高生产性的特点。它广泛应用于数据分析、机器学习、Web开发、自动化测试等领域。Python的第三个版本&#xff08;Python3&#xff09;相对于第二个版本&#xff08…

网络互连与互联网 - 路由信息协议(RIP)

文章目录 1 概述2 RIP 要点2.1 根据 距离矢量&#xff08;或 跳数&#xff09;寻找最佳路由2.2 RIP 三大要点2.3 基本工作过程2.4 路由条目的更新规则2.5 RIPv1 和 RIPv2 区别2.6 "坏消息传播慢" 的问题 3 网工软考真题 1 概述 #mermaid-svg-DFp89TU9n8BiJLTr {font-…

K8s scheduler 调度:NodeName、NodeSelector与Taint

1 前言 上篇介绍了k8s调度的预选和优选策略&#xff0c;K8s scheduler 调度&#xff1a;预选和优选策略。 本篇介绍三个影响pod调度的配置&#xff1a;NodeName、NodeSelector与Taint。 2 NodeName NodeName是根据node的名称调度pod。可用于强制约束Pod跳过默认的Kubernetes调度…

Hive on Spark调优(大数据技术6)

第6章 Join优化 6.1 Hive Join算法概述 Hive拥有多种join算法&#xff0c;包括common join&#xff0c;map join&#xff0c;sort Merge Bucket Map Join等。下面对每种join算法做简要说明&#xff1a; 1&#xff09;common join Map端负责读取参与join的表的数据&#xff…

Hive on Spark调优(大数据技术8)

第8章 任务并行度优化 8.1 优化说明 对于一个分布式的计算任务而言&#xff0c;设置一个合适的并行度十分重要。在Hive中&#xff0c;无论其计算引擎是什么&#xff0c;所有的计算任务都可分为Map阶段和Reduce阶段。所以并行度的调整&#xff0c;也可从上述两个方面进行调整。 …

Maven基础学习---3、Maven的使用(命令行)

1、根据坐标创建Maven工程 1、Maven核心概念&#xff1a;坐标 &#xff08;1&#xff09;数学中的坐标 使用x、y、z三个[向量]作为空间的坐标系&#xff0c;可以在[空间]中唯一定位到一个[点]。 &#xff08;2&#xff09;Maven中的坐标 1、向量说明 使用三个[向量]在[Maven…

MapReduce排序

MapTask和ReduceTask均会对数据按照key进行排序。该操作属于Hadoop的默认行为。任何应用程序中的数据均会被排序&#xff0c;而不管逻辑上是否需要。 默认排序是按照字典顺序排序&#xff0c;且实现该排序的方法是快速排序。 对于MapTask&#xff0c;它会将处理的结果暂时放到…

25 SQL ——标量子查询

create table dept(id int primary key auto_increment,name varchar(15))comment 部门;insert into dept(id, name) values (1,研发部),(2,市场部),(3,财务部),(4,销售部),(5,总经办),(6,人事部);create table staff (id int primary key auto_increment commentID,name …

Java课设部署教程

这里我只演示使用IDEA软件或Eclipse两种常用的Java编译器的导入项目的教程&#xff01; IDEA部署教程 把下载的压缩包解压&#xff0c;解压后就是源码&#xff0c;打开IDEA&#xff0c;导入项目【源码】 选择源码所在的位置&#xff0c;点击ok即可导入 下面就是把源码导入到I…

(三)人工智能应用--深度学习原理与实战--神经网络的工作原理

机器学习是将输入(比如图像)映射到目标(比如标签“猫”)&#xff0c;并建立映射规则(即模型)。在深度学习中&#xff0c;神经网络通过一系列数据变换层来实现这种输入到目标的映射&#xff0c;本章节我们具体来看这种学习过程是如何实现的。 学习内容 1、理解层(Layer)及权重(…

【王道·计算机网络】第四章 网络层

一、 概述和功能 1.1 网络层功能 主要任务&#xff1a;把分组从源端传到目的端&#xff0c;为分组交换网上的不同主机提供通信服务传输单位&#xff1a;数据报功能&#xff1a; 路由选择与分组转发&#xff0c;即选择最佳路径异构网络互联(依靠路由器)拥塞控制(所有结点都来不…

基于PyQt5的图形化界面开发——自制ssh工具

基于PyQt5的图形化界面开发——自制ssh工具 0. 前言1. 第三方库的安装2. ssh原理3. 完整代码4. 演示效果5. 其他PyQt文章 0. 前言 本节我们使用PyQt5来制作一个简单的ssh小工具。 操作系统&#xff1a;Windows10 专业版 开发环境&#xff1a;Pycahrm Comunity 2022.3 Pytho…

设计模式中的UML基础

目录 1、UML概述 2、UML的用途 3、UML的构成 4、UML图 5、UML类图 5.1、类的构成 5.2、类与类之间的关系 6、绘制UML图的软件工具 VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#xff09;https://blog.csdn.net/chenlycl…

java线程组

文章目录 1. 简介2. 线程对象关联线程组&#xff1a;一级关联3. 线程对象关联线程组&#xff1a;多级关联4. 自动归属属性5. 获取根线程组 1. 简介 为了方便某些具有相同功能的线程进行管理&#xff0c;我们可以把线程归属到某一个线程组。线程组中可以有线程对象、线程&#…

【三维激光扫描】实验03:点云着色渲染模式详解

在SiScan软件中,点云的着色模式有:高程彩色、倾斜度、反射强度、自有颜色、点云测站、分隔片、分类7中,本文进行详细讲解。 文章目录 一、高程彩色二、倾斜度三、反射强度四、自有颜色五、分隔片一、高程彩色 高程彩色模式是按点云数据的Z值起算,颜色渐变显示。 二、倾斜度…

【AIGC】10、Chinese CLIP | 专为中文图文匹配设计

文章目录 一、背景二、方法2.1 基础内容2.2 数据集2.3 预训练方法2.4 模型尺寸 三、效果 论文&#xff1a;Chinese CLIP: Contrastive Vision-Language Pretraining in Chinese 代码&#xff1a;https://github.com/OFA-Sys/Chinese-CLIP 出处&#xff1a;阿里达摩院 时间&a…

061:cesium设置棋盘图材质(material-5)

第061个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中设置棋盘材质,请参考源代码,了解CheckerboardMaterialProperty的应用。 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共89行)相关API参考:专栏目标…

第09章_子查询

第09章_子查询 子查询指一个查询语句嵌套在另一个查询语句内部的查询&#xff0c;这个特性从MySQL 4.1开始引入。 SQL 中子查询的使用大大增强了 SELECT 查询的能力&#xff0c;因为很多时候查询需要从结果集中获取数据&#xff0c;或者需要从同一个表中先计算得出一个数据结果…

SeaweedFs使用-环境准备

SeaweedFs使用-环境准备 1.下载go语言包实现go语言环境2.下载SeaweedFs文件3.安装SeaweedFs SeaweedFs是一款开源的分布式存储软件&#xff0c;在存储大量小文件方面有更好的优化&#xff0c;比较适合存储web项目的图片等文件。 1.下载go语言包实现go语言环境 因为SeaweedFs是…