硬汉嵌入式论坛

 找回密码
 立即注册
查看: 202|回复: 1
收起左侧

[Flash] STM32H743写FLASH时间测试

[复制链接]

1

主题

7

回帖

10

积分

新手上路

积分
10
发表于 2025-11-13 11:49:07 | 显示全部楼层 |阅读模式
本帖最后由 凯瑞 于 2025-11-13 11:58 编辑

FLASH读写驱动程序:


#include "flash_drive.h"
#include <string.h>

/*
*********************************************************************************************************
*        函 数 名: bsp_GetSector
*        功能说明: 根据地址计算扇区首地址
*        形    参: 无
*        返 回 值: 扇区号(0-7)
*********************************************************************************************************
*/
uint32_t bsp_GetSector(uint32_t Address)
{
    uint32_t sector = 0;

    if (((Address < ADDR_FLASH_SECTOR_1_BANK1) && (Address >= ADDR_FLASH_SECTOR_0_BANK1)) ||
        ((Address < ADDR_FLASH_SECTOR_1_BANK2) && (Address >= ADDR_FLASH_SECTOR_0_BANK2)))
    {
        sector = FLASH_SECTOR_0;
    }
    else if (((Address < ADDR_FLASH_SECTOR_2_BANK1) && (Address >= ADDR_FLASH_SECTOR_1_BANK1)) ||
             ((Address < ADDR_FLASH_SECTOR_2_BANK2) && (Address >= ADDR_FLASH_SECTOR_1_BANK2)))
    {
        sector = FLASH_SECTOR_1;
    }
    else if (((Address < ADDR_FLASH_SECTOR_3_BANK1) && (Address >= ADDR_FLASH_SECTOR_2_BANK1)) ||
             ((Address < ADDR_FLASH_SECTOR_3_BANK2) && (Address >= ADDR_FLASH_SECTOR_2_BANK2)))
    {
        sector = FLASH_SECTOR_2;
    }
    else if (((Address < ADDR_FLASH_SECTOR_4_BANK1) && (Address >= ADDR_FLASH_SECTOR_3_BANK1)) ||
             ((Address < ADDR_FLASH_SECTOR_4_BANK2) && (Address >= ADDR_FLASH_SECTOR_3_BANK2)))
    {
        sector = FLASH_SECTOR_3;
    }
    else if (((Address < ADDR_FLASH_SECTOR_5_BANK1) && (Address >= ADDR_FLASH_SECTOR_4_BANK1)) ||
             ((Address < ADDR_FLASH_SECTOR_5_BANK2) && (Address >= ADDR_FLASH_SECTOR_4_BANK2)))
    {
        sector = FLASH_SECTOR_4;
    }
    else if (((Address < ADDR_FLASH_SECTOR_6_BANK1) && (Address >= ADDR_FLASH_SECTOR_5_BANK1)) ||
             ((Address < ADDR_FLASH_SECTOR_6_BANK2) && (Address >= ADDR_FLASH_SECTOR_5_BANK2)))
    {
        sector = FLASH_SECTOR_5;
    }
    else if (((Address < ADDR_FLASH_SECTOR_7_BANK1) && (Address >= ADDR_FLASH_SECTOR_6_BANK1)) ||
             ((Address < ADDR_FLASH_SECTOR_7_BANK2) && (Address >= ADDR_FLASH_SECTOR_6_BANK2)))
    {
        sector = FLASH_SECTOR_6;
    }
    else if (((Address < ADDR_FLASH_SECTOR_0_BANK2) && (Address >= ADDR_FLASH_SECTOR_7_BANK1)) ||
             ((Address < CPU_FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_7_BANK2)))
    {
        sector = FLASH_SECTOR_7;
    }
    else
    {
        sector = FLASH_SECTOR_7;
    }

    return sector;
}

/*
*********************************************************************************************************
*        函 数 名: bsp_ReadCpuFlash
*        功能说明: 读取CPU Flash的内容
*        形    参:  _ucpDst : 目标缓冲区
*                         _ulFlashAddr : 起始地址
*                         _ulSize : 数据大小(单位是字节)
*        返 回 值: 0=成功,1=失败
*********************************************************************************************************
*/
uint8_t bsp_ReadCpuFlash(uint32_t _ulFlashAddr, uint8_t *_ucpDst, uint32_t _ulSize)
{
    uint32_t i;

    if (_ulFlashAddr + _ulSize > CPU_FLASH_BASE_ADDR + CPU_FLASH_SIZE)
    {
        return 1;
    }

    /* 长度为0时不继续操作,否则起始地址为奇地址会出错 */
    if (_ulSize == 0)
    {
        return 1;
    }

    for (i = 0; i < _ulSize; i++)
    {
        *_ucpDst++ = *(uint8_t *)_ulFlashAddr++;
    }

    return 0;
}

/*
*********************************************************************************************************
*        函 数 名: bsp_CmpCpuFlash
*        功能说明: 比较Flash指定地址的数据.
*        形    参: _ulFlashAddr : Flash地址
*                         _ucpBuf : 数据缓冲区
*                         _ulSize : 数据大小(单位是字节)
*        返 回 值:
*                        FLASH_IS_EQU                0   Flash内容和待写入的数据相等,不需要擦除和写操作
*                        FLASH_REQ_WRITE                1        Flash不需要擦除,直接写
*                        FLASH_REQ_ERASE                2        Flash需要先擦除,再写
*                        FLASH_PARAM_ERR                3        函数参数错误
*********************************************************************************************************
*/
uint8_t bsp_CmpCpuFlash(uint32_t _ulFlashAddr, uint8_t *_ucpBuf, uint32_t _ulSize)
{
    uint32_t i;
    uint8_t  ucIsEqu; /* 相等标志 */
    uint8_t  ucByte;

    /* 如果偏移地址超过芯片容量,则不改写输出缓冲区 */
    if (_ulFlashAddr + _ulSize > CPU_FLASH_BASE_ADDR + CPU_FLASH_SIZE)
    {
        return FLASH_PARAM_ERR; /* 函数参数错误 */
    }

    /* 长度为0时返回正确 */
    if (_ulSize == 0)
    {
        return FLASH_IS_EQU; /* Flash内容和待写入的数据相等 */
    }

    ucIsEqu = 1; /* 先假设所有字节和待写入的数据相等,如果遇到任何一个不相等,则设置为 0 */
    for (i = 0; i < _ulSize; i++)
    {
        ucByte = *(uint8_t *)_ulFlashAddr;

        if (ucByte != *_ucpBuf)
        {
            if (ucByte != 0xFF)
            {
                return FLASH_REQ_ERASE; /* 需要擦除后再写 */
            }
            else
            {
                ucIsEqu = 0; /* 不相等,需要写 */
            }
        }

        _ulFlashAddr++;
        _ucpBuf++;
    }

    if (ucIsEqu == 1)
    {
        return FLASH_IS_EQU; /* Flash内容和待写入的数据相等,不需要擦除和写操作 */
    }
    else
    {
        return FLASH_REQ_WRITE; /* Flash不需要擦除,直接写 */
    }
}

/*
*********************************************************************************************************
*        函 数 名: bsp_EraseCpuFlash
*        功能说明: 擦除CPU FLASH一个扇区 (128KB)
*        形    参: _ulFlashAddr : Flash地址      _ulSize : Flash大小
*        返 回 值: 0 成功, 1 失败
*                          HAL_OK       = 0x00,
*                          HAL_ERROR    = 0x01,
*                          HAL_BUSY     = 0x02,
*                          HAL_TIMEOUT  = 0x03
*
*********************************************************************************************************
*/
uint8_t bsp_EraseCpuFlash(uint32_t _ulFlashAddr, uint32_t _ulSize)
{
    uint32_t               FirstSector = 0, NbOfSectors = 0, EndSector = 0;
    FLASH_EraseInitTypeDef EraseInitStruct;
    uint32_t               SECTORError = 0;
    uint8_t                re;

    /* 长度为0时不继续操作  */
    if (_ulSize == 0)
    {
        return 0;
    }
    /* 解锁 */
    HAL_FLASH_Unlock();

    /* 获取此地址所在的扇区 */
    FirstSector                  = bsp_GetSector(_ulFlashAddr);

    // 获取此地址结束所在的扇区
    EndSector                    = bsp_GetSector(_ulFlashAddr + _ulSize - 1);

    /* 擦除扇区数量 */
    NbOfSectors                  = EndSector - FirstSector + 1;

    /* 擦除扇区配置 */
    EraseInitStruct.TypeErase    = FLASH_TYPEERASE_SECTORS;
    EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;

    if (_ulFlashAddr >= ADDR_FLASH_SECTOR_0_BANK2)
    {
        EraseInitStruct.Banks = FLASH_BANK_2;
    }
    else
    {
        EraseInitStruct.Banks = FLASH_BANK_1;
    }

    EraseInitStruct.Sector    = FirstSector;
    EraseInitStruct.NbSectors = NbOfSectors;

    /* 扇区擦除 */
    re                        = HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError);

    /* 擦除完毕后,上锁 */
    HAL_FLASH_Lock();

    return re;
}

/*
*********************************************************************************************************
*        函 数 名: bsp_WriteCpuFlash
*        功能说明: 写数据到CPU 内部Flash。 必须按32字节整数倍写。不支持跨扇区。扇区大小128KB. \
*                          写之前需要擦除扇区. 长度不是32字节整数倍时,最后几个字节末尾补0写入.
*        形    参: _ulFlashAddr : Flash地址
*                         _ucpSrc : 数据缓冲区
*                         _ulSize : 数据大小(单位是字节, 必须是32字节整数倍)
*        返 回 值: 0-成功,1-数据长度或地址溢出,2-写Flash出错(估计Flash寿命到)
*********************************************************************************************************
*/
uint8_t bsp_WriteCpuFlash(uint32_t _ulFlashAddr, uint8_t *_ucpSrc, uint32_t _ulSize)
{
    uint32_t i;
    uint8_t  ucRet;

    /* 如果偏移地址超过芯片容量,则不改写输出缓冲区 */
    if (_ulFlashAddr + _ulSize > CPU_FLASH_BASE_ADDR + CPU_FLASH_SIZE)
    {
        return 1;
    }

    /* 长度为0时不继续操作  */
    if (_ulSize == 0)
    {
        return 0;
    }

    ucRet = bsp_CmpCpuFlash(_ulFlashAddr, _ucpSrc, _ulSize);

    if (ucRet == FLASH_IS_EQU)
    {
        return 0;
    }

    __set_PRIMASK(1); /* 关中断 */

    //擦除扇区
    bsp_EraseCpuFlash(_ulFlashAddr, _ulSize);

    /* FLASH 解锁 */
    HAL_FLASH_Unlock();

    for (i = 0; i < _ulSize / 32; i++)
    {
        uint64_t FlashWord[4];

        memcpy((char *)FlashWord, _ucpSrc, 32);
        _ucpSrc += 32;

        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, _ulFlashAddr, (uint64_t)((uint32_t)FlashWord)) == HAL_OK)
        {
            _ulFlashAddr = _ulFlashAddr + 32; /* 递增,操作下一个256bit */
        }
        else
        {
            goto err;
        }
    }

    /* 长度不是32字节整数倍 */
    if (_ulSize % 32)
    {
        uint64_t FlashWord[4];

        FlashWord[0] = 0;
        FlashWord[1] = 0;
        FlashWord[2] = 0;
        FlashWord[3] = 0;
        memcpy((char *)FlashWord, _ucpSrc, _ulSize % 32);
        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, _ulFlashAddr, (uint64_t)((uint32_t)FlashWord)) == HAL_OK)
        {
            ; // _ulFlashAddr = _ulFlashAddr + 32;
        }
        else
        {
            goto err;
        }
    }

    /* Flash 加锁,禁止写Flash控制寄存器 */
    HAL_FLASH_Lock();

    __set_PRIMASK(0); /* 开中断 */

    return 0;

err:
    /* Flash 加锁,禁止写Flash控制寄存器 */
    HAL_FLASH_Lock();

    __set_PRIMASK(0); /* 开中断 */

    return 1;
}


写FLASH程序,只使用到一个扇区:
EEPROM_Write(ADDR_FLASH_SECTOR_4_BANK1, (uint8_t *)&holding_reg.sys_param, sizeof(sys_param_t));
使用IO测试FLASH擦除读写一个扇区时间居然差不多要1秒

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET);
EEPROM_Write(0, (uint8_t *)&holding_reg.sys_param, sizeof(sys_param_t));
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET);



同时也使用到DWT测试程序运行时间的方法测试时间

uint32_t start_ticks, end_ticks, cycle_count;
float    time_us;



HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET);
start_ticks                 = DWT->CYCCNT;
EEPROM_Write(0, (uint8_t *)&holding_reg.sys_param, sizeof(sys_param_t));
end_ticks = DWT->CYCCNT;
cycle_count = end_ticks - start_ticks;
time_us = ((float)cycle_count * 1000000.0f) / (float)SystemCoreClock;
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET);

测量的时间差不多


逻辑分析仪测量时间

逻辑分析仪测量时间

DWT测量时间

DWT测量时间
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
119430
QQ
发表于 2025-11-13 15:02:32 | 显示全部楼层
差不多,基本1-4秒

3.png
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-11-22 01:00 , Processed in 0.054366 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表