[Biblioteca HAL] STM32F407 ---- leitura e gravação de Flash interno

[Biblioteca HAL] Desenvolvimento STM32CubeMX ---- STM32F407 ---- Conteúdo


1. Introdução à memória STM32

A memória STM32 é dividida nos dois tipos a seguir:

1. Memória de acesso aleatório – RAM

  • RAM é uma memória interna que troca dados diretamente com a CPU, também chamada de memória principal (memória).
  • Ele pode ser lido e gravado a qualquer momento , e a velocidade é muito rápida, e geralmente é usado como meio de armazenamento temporário de dados para sistemas operacionais ou outros programas em execução.
  • A RAM não pode reter dados quando a energia é desligada ( os dados de desligamento desaparecem ).Se precisar salvar dados, você deve gravá-los em um dispositivo de armazenamento de longo prazo (como um disco rígido).

2. Memória somente leitura – ROM

  • Os dados armazenados na ROM são geralmente gravados antecipadamente antes de serem carregados em toda a máquina e só podem ser lidos durante o processo de trabalho de toda a máquina, ao contrário da memória de acesso aleatório, que pode ser reescrita de forma rápida e conveniente.
  • Os dados armazenados na ROM são estáveis ​​e os dados armazenados não serão alterados após o desligamento.

2. Introdução da memória da série STM32F407

Segundo a memória, a classificação específica é a seguinte:

modelo Capacidade ROM (bytes) Capacidade de RAM (bytes)
stm32f407xE 512 mil 192 mil
stm32f407xG 1024K 192 mil

Este artigo usa o chip STM32F407VET6, e a configuração de memória padrão no ambiente keil5 é mostrada na figura abaixo:

insira a descrição da imagem aqui

  • A área ROM começa em 0x8000000 e o tamanho é de 512K bytes.
  • A área RAM começa em 0x20000000 e tem tamanho de 192K bytes.

Noções básicas de flash interno

O Flash interno é a área ROM da memória STM32, e os dados não serão perdidos quando a energia estiver desligada . Porém, o Flash é mais importante no STM32, e o programa também é armazenado neste local, por isso é fácil de evitar que os usuários leiam e escrevam à vontade para evitar problemas desnecessários.

O módulo Flash interno é composto da seguinte forma:
insira a descrição da imagem aqui

A função de apagamento do Flash interno é apagada setor por setor.

3. Leitura de Flash interno

A operação de leitura do Flash interno é relativamente simples e os dados podem ser lidos diretamente através do endereçamento do ponteiro.
O código específico é o seguinte:

/**
 *@功能:从内部Flash读取指定字节数据
 *@参数1:ReadAddress:数据起始地址
 *@参数2:*data:      读取到的数据缓存首地址
 *@参数3:length:     读取字节个数
 */
void ReadFlashData(uint32_t ReadAddress, uint8_t *data, uint32_t length)
{
    
    
    for(uint32_t i=0;i<length;i++)
    {
    
    
        data[i]=*(uint8_t*)(ReadAddress+i); //读取数据
    }
}

4. Escreva o Flash interno

Antes de gravar dados no Flash interno, é necessário avaliar se os dados anteriores são 0xFF. Se não for 0xFF, eles precisam ser apagados para gravar novos dados corretamente.

Por exemplo:
os últimos dados armazenados são 0x52 e na próxima vez os dados armazenados são 0x01 diretamente.
Se não for apagado, os dados são gravados e o resultado é lido como 0x51.

Devido à operação de apagamento do STM32F407, pelo menos apagamento de setor . Portanto, quando escrevemos dados, precisamos escrever um setor inteiro . Não podemos gravar dados em um setor várias vezes, porque a próxima gravação e exclusão apagará os dados anteriores.

1. Etapas específicas da operação

  1. Desbloqueie a proteção contra gravação do Flash.
  2. Apague dados Flash.
  3. Grave dados Flash.
  4. Relock a proteção contra gravação do Flash.

2. Função de biblioteca HAL

(1) Funções de desbloqueio e bloqueio do flash

HAL_FLASH_Unlock();    //解锁
HAL_FLASH_Lock();      //上锁

(2) Função de apagamento do flash

função apagar

/*
功能:Flash擦除
参数1:擦除操作的配置信息
参数2:错误扇区的配置信息
*/
HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError);

Informações de configuração para operações de limpeza

typedef struct
{
    
    
  uint32_t TypeErase;   /*擦除类型:FLASH_TYPEERASE_SECTORS 扇区擦除和 FLASH_TYPEERASE_MASSERASE 批量擦除*/

  uint32_t Banks;       /*当启用批量擦除时,选择要擦除的存储体。*/

  uint32_t Sector;      /*当启用扇区擦除时,要擦除的初始FLASH扇区 */

  uint32_t NbSectors;   /*要擦除的扇区数。此参数的值必须介于1和(最大扇区数-初始扇区的值)之间*/

  uint32_t VoltageRange;/*定义擦除并行性的设备电压范围。*/

} FLASH_EraseInitTypeDef;

(3) Função de operação de gravação flash

/*
功能:在指定地址写入数据
参数1:写入数据类型:	FLASH_TYPEPROGRAM_BYTE - 8bit,
					FLASH_TYPEPROGRAM_HALFWORD - 16bit
					FLASH_TYPEPROGRAM_WORD - 32bit
					FLASH_TYPEPROGRAM_DOUBLEWORD - 64bit
参数2:指定要写入的地址
参数3:指定要写入的数据
*/
HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data);

(4) Função de espera de flash

//等待FLASH操作完成
HAL_StatusTypeDef FLASH_WaitForLastOperation(uint32_t Timeout);

3. Procedimentos específicos

#define FMC_FLASH_BASE      0x08000000   // FLASH的起始地址
#define FMC_FLASH_END       0x08080000   // FLASH的结束地址

#define FLASH_WAITETIME     50000        //FLASH等待超时时间

//FLASH 扇区的起始地址
#define ADDR_FLASH_SECTOR_0     ((uint32_t)0x08000000) 	//扇区0起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_1     ((uint32_t)0x08004000) 	//扇区1起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_2     ((uint32_t)0x08008000) 	//扇区2起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_3     ((uint32_t)0x0800C000) 	//扇区3起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_4     ((uint32_t)0x08010000) 	//扇区4起始地址, 64 Kbytes  
#define ADDR_FLASH_SECTOR_5     ((uint32_t)0x08020000) 	//扇区5起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_6     ((uint32_t)0x08040000) 	//扇区6起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_7     ((uint32_t)0x08060000) 	//扇区7起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_8     ((uint32_t)0x08080000) 	//扇区8起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_9     ((uint32_t)0x080A0000) 	//扇区9起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_10    ((uint32_t)0x080C0000) 	//扇区10起始地址,128 Kbytes  
#define ADDR_FLASH_SECTOR_11    ((uint32_t)0x080E0000) 	//扇区11起始地址,128 Kbytes 

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

//获取某个地址所在的flash扇区
//addr:flash地址
//返回值:0~11,即addr所在的扇区
uint8_t STMFLASH_GetFlashSector(uint32_t 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;	
}

/**
 *@功能:向内部Flash写入数据
 *@参数1:WriteAddress:数据要写入的目标地址(偏移地址)
 *@参数2:*data: 写入的数据首地址
 *@参数3:length:写入数据的个数
 */
void WriteFlashData(uint32_t WriteAddress, uint8_t *data, uint32_t length)
{
    
    
    FLASH_EraseInitTypeDef FlashEraseInit;
    HAL_StatusTypeDef FlashStatus=HAL_OK;
    uint32_t SectorError=0;
    uint32_t addrx=0;
    uint32_t endaddr=0;
    
    if( (WriteAddress < FMC_FLASH_BASE) || ( WriteAddress + length >= FMC_FLASH_END) || (length <= 0) )
    return;

    HAL_FLASH_Unlock();              //解锁
    addrx = WriteAddress;            //写入的起始地址
    endaddr = WriteAddress+length;   //写入的结束地址


        while(addrx<endaddr)  //扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
        {
    
    
             if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区
            {
    
       
                FlashEraseInit.TypeErase=FLASH_TYPEERASE_SECTORS;       //擦除类型,扇区擦除 
                FlashEraseInit.Sector=STMFLASH_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+=1;
                FLASH_WaitForLastOperation(FLASH_WAITETIME);                //等待上次操作完成
        }
    
    FlashStatus=FLASH_WaitForLastOperation(FLASH_WAITETIME);            //等待上次操作完成
    if(FlashStatus==HAL_OK)
    {
    
    
         while(WriteAddress<endaddr)//写数据
         {
    
    
            if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE,WriteAddress,*data)!=HAL_OK)//写入数据
            {
    
     
                break;	//写入异常
            }
            WriteAddress+=1;
            data++;
        }  
    }
    HAL_FLASH_Lock();           //上锁
}

Acho que você gosta

Origin blog.csdn.net/MQ0522/article/details/132623409
Recomendado
Clasificación