当前位置:   article > 正文

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

stm32 flash 驱动

前言

  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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

源文件(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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/481370
推荐阅读
相关标签
  

闽ICP备14008679号