[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:
- 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:
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
- Desbloqueie a proteção contra gravação do Flash.
- Apague dados Flash.
- Grave dados Flash.
- 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(); //上锁
}