Air32 | 合宙Air001单片机内部FLASH读写示例
代码已经通过测试,开发环境KEIL-MDK 5.36。
测试代码
c
void FLASH_RdWrTest(void)
{
uint32_t Address;
uint32_t PageReadBuffer[FLASH_PAGE_SIZE >> 2];
uint32_t PageWriteBuffer[FLASH_PAGE_SIZE >> 2];
memset(PageWriteBuffer, 0XAA, sizeof(PageWriteBuffer));
for(Address = 0x08003000; Address < 0x08008000; Address += FLASH_PAGE_SIZE) // 16K~32K
{
FLASH_Write(Address, PageWriteBuffer, sizeof(PageReadBuffer) >> 2);
memset(PageReadBuffer, 0, sizeof(PageReadBuffer));
FLASH_Read(Address, PageReadBuffer, sizeof(PageReadBuffer) >> 2);
if(memcmp(PageReadBuffer, PageWriteBuffer, sizeof(PageReadBuffer)) == 0)
{
printf("page[%04d] 0x%08X read & write %s \r\n", (Address - FLASH_BASE) / FLASH_PAGE_SIZE, Address, "ok");
}
else
{
printf("page[%04d] 0x%08X read & write %s \r\n", (Address - FLASH_BASE) / FLASH_PAGE_SIZE, Address, "failed");
}
}
}
头文件
c
/**
* @brief Create by AnKun on 2019/10/10
*/
#ifndef FLASH_H__
#define FLASH_H__
#include "air001xx_hal.h"
/// 导出函数声明
void FLASH_Init(void);
void FLASH_Read(uint32_t Address, uint32_t *Buffer, uint32_t NumToRead);
void FLASH_Write(uint32_t Address, const uint32_t *Buffer, uint32_t NumToWrite);
void FLASH_WritePage_NoCheck(uint32_t Address, const uint32_t* Buffer);
void FLASH_ErasePage(uint32_t Address);
void FLASH_SetReadProtectionState(int state);
#endif // !__FLASH_H
源文件
c
/**
* @file flash.c
*
* @brief Create by AnKun on 2023/7/20
*
*/
#include "flash.h"
#include <string.h>
static uint32_t FlashBuffer[FLASH_PAGE_SIZE >> 2];
void FLASH_Init(void)
{
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); /* Clear SR register */
HAL_FLASH_Lock();
}
void FLASH_Read(uint32_t Address, uint32_t *Buffer, uint32_t NumToRead)
{
while(NumToRead--)
{
*Buffer++ = (*((volatile unsigned int *)Address));
Address += 4;
}
}
void FLASH_WritePage_NoCheck(uint32_t Address, const uint32_t* Buffer)
{
HAL_FLASH_Lock(); //解锁
HAL_FLASH_Program(FLASH_TYPEPROGRAM_PAGE, Address, (uint32_t *)Buffer);
HAL_FLASH_Unlock(); //上锁
}
void FLASH_ErasePage(uint32_t Address)
{
uint32_t PageError = 0;
FLASH_EraseInitTypeDef EraseInitStruct = {0};
HAL_FLASH_Unlock();
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGEERASE;
EraseInitStruct.PageAddress = Address;
EraseInitStruct.NbPages = 1; /* erase nums pages. */
if(HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)
{
printf("%s\r\n", __FUNCTION__);
}
HAL_FLASH_Lock();
}
void FLASH_Write(uint32_t Address, const uint32_t *Buffer, uint32_t NumToWrite)
{
uint32_t secpos; //页地址
uint32_t secoff; //页内偏移地址(16位字计算)
uint32_t secremain; //页内剩余地址(16位字计算)
uint32_t i;
uint32_t offaddr; //去掉0X08000000后的地址
HAL_FLASH_Unlock(); //解锁
offaddr = Address - FLASH_BASE; //实际偏移地址.
secpos = offaddr / FLASH_PAGE_SIZE; //页地址
secoff = (offaddr % FLASH_PAGE_SIZE) >> 2; //在页内的偏移(2个字节为基本单位.)
secremain = (FLASH_PAGE_SIZE >> 2) - secoff; //页剩余空间大小
if(NumToWrite <= secremain)secremain = NumToWrite; //不大于该页范围
while(1)
{
FLASH_Read(secpos * FLASH_PAGE_SIZE + FLASH_BASE, FlashBuffer, FLASH_PAGE_SIZE >> 2); //读出整个页的内容
for(i = 0; i < (FLASH_PAGE_SIZE >> 2); i++) //校验数据
{
if(FlashBuffer[i] != 0XFFFFFFFF)
{
uint32_t PageError = 0;
FLASH_EraseInitTypeDef EraseInitStruct = {0};
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGEERASE;
EraseInitStruct.PageAddress = Address;
EraseInitStruct.NbPages = 1; /* erase nums pages. */
HAL_FLASHEx_Erase(&EraseInitStruct, &PageError);
break;
}
}
for(i = 0; i < secremain; i++) //复制
{
FlashBuffer[i + secoff] = Buffer[i];
}
HAL_FLASH_Program(FLASH_TYPEPROGRAM_PAGE, secpos * FLASH_PAGE_SIZE + FLASH_BASE, (uint32_t *)FlashBuffer); //写入整个页
if(NumToWrite == secremain)break; //写入结束了
else//写入未结束
{
secpos++; //页地址增1
secoff = 0; //偏移位置为0
Buffer += secremain; //指针偏移
Address += secremain; //写地址偏移
NumToWrite -= secremain; //字节(16位)数递减
if(NumToWrite > (FLASH_PAGE_SIZE >> 2)) secremain = (FLASH_PAGE_SIZE >> 2); //下一个页还是写不完
else secremain = NumToWrite; //下一个页可以写完了
}
}
HAL_FLASH_Lock(); //解锁
}
void FLASH_SetReadProtectionState(int onoff)
{
FLASH_OBProgramInitTypeDef OptionsBytesStruct;
HAL_FLASH_Unlock();
HAL_FLASH_OB_Unlock();
HAL_FLASH_OBGetConfig(&OptionsBytesStruct);
if(onoff)
{
if(OptionsBytesStruct.RDPLevel == OB_RDP_LEVEL_0)
{
OptionsBytesStruct.OptionType = OPTIONBYTE_RDP;
OptionsBytesStruct.RDPLevel = OB_RDP_LEVEL_1;
HAL_FLASH_OBProgram(&OptionsBytesStruct);
HAL_FLASH_OB_Launch();
}
}
else
{
if(OptionsBytesStruct.RDPLevel == OB_RDP_LEVEL_1)
{
OptionsBytesStruct.OptionType = OPTIONBYTE_RDP;
OptionsBytesStruct.RDPLevel = OB_RDP_LEVEL_0;
HAL_FLASH_OBProgram(&OptionsBytesStruct);
HAL_FLASH_OB_Launch();
}
}
HAL_FLASH_OB_Lock();
HAL_FLASH_Lock();
}
void FLASH_RdWrTest(void)
{
uint32_t Address;
uint32_t PageReadBuffer[FLASH_PAGE_SIZE >> 2];
uint32_t PageWriteBuffer[FLASH_PAGE_SIZE >> 2];
memset(PageWriteBuffer, 0XAA, sizeof(PageWriteBuffer));
for(Address = 0x08003000; Address < 0x08008000; Address += FLASH_PAGE_SIZE) // 16K~32K
{
FLASH_Write(Address, PageWriteBuffer, sizeof(PageReadBuffer) >> 2);
memset(PageReadBuffer, 0, sizeof(PageReadBuffer));
FLASH_Read(Address, PageReadBuffer, sizeof(PageReadBuffer) >> 2);
if(memcmp(PageReadBuffer, PageWriteBuffer, sizeof(PageReadBuffer)) == 0)
{
printf("page[%04d] 0x%08X read & write %s \r\n", (int)((Address - FLASH_BASE) / FLASH_PAGE_SIZE), Address, "ok");
}
else
{
printf("page[%04d] 0x%08X read & write %s \r\n", (int)((Address - FLASH_BASE) / FLASH_PAGE_SIZE), Address, "failed");
}
}
}