代码拉取完成,页面将自动刷新
#include <stdio.h>
#include <string.h>
#include "BSP/InternalFlash/bsp_internal_flash.h"
/**
* @brief 读取指定地址的半字(16位) 数据
* @note 32位单片机的话,一个字是32位,半字是16位
* @param faddr 要读取的地址,32位地址(此地址必须为2的倍数!!)
* @retval 返回一个16位数据
*/
uint16_t InternalFLASH_ReadHalfWord(uint32_t faddr) {
return *(__IO uint16_t *)faddr;
}
#if InternalFLASH_WREN // 如果使能了写
/**
* @brief 不检查是否擦除,直接写入半字数据
* @note 注意:数据个数按半字(16位)计算
* @param WriteAddr 起始地址
* @param pBuffer 数据指针
* @param NumToWrite 要写入的数据的半字(16位)数,字节数x2
* @retval
*/
void InternalFLASH_Write_NoCheck(uint32_t WriteAddr, uint16_t *pBuffer, uint16_t NumToWrite) {
uint16_t i;
for (i = 0; i < NumToWrite; i++)
{
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, WriteAddr, pBuffer[i]);
WriteAddr += 2; // 地址增加2,每次写入16位数据
}
}
uint16_t InternalFLASH_BUF[InternalFLASH_SECTOR_SIZE / 2]; // 最多是2K字节,每个数据是16位,所以大小定义为扇区的一半
/**
* @brief 从指定地址开始写入指定长度的数据
* @note 注意:数据个数按半字(16位)计算
* @param WriteAddr 起始地址(此地址必须为2的倍数!!)
* @param pBuffer 数据指针
* @param NumToWrite 要写入的半字(16位)数(就是要写入的16位数据的个数)
* @retval
*/
void InternalFLASH_Write(uint32_t WriteAddr, uint16_t *pBuffer, uint16_t NumToWrite) {
uint32_t secpos; // 扇区地址
uint16_t secoff; // 扇区内偏移地址(16位字计算)
uint16_t secremain; // 扇区内剩余地址(16位字计算)
uint16_t i;
uint32_t offaddr; // 去掉 0X08000000 后的地址,也就是相对于 0X08000000 的偏移地址
if (WriteAddr < InternalFLASH_BASE || (WriteAddr >= (InternalFLASH_BASE + 1024 * InternalFLASH_SIZE)))
return; // 非法地址
HAL_FLASH_Unlock(); // 解锁
offaddr = WriteAddr - InternalFLASH_BASE; // 计算实际偏移地址,要写入的地址 - 0x0800 0000
secpos = offaddr / InternalFLASH_SECTOR_SIZE; // 计算要写的地址是哪个扇区,也就是页,偏移地址/2048即可。扇区地址 0~255
// for STM32F103ZET6
secoff = (offaddr % InternalFLASH_SECTOR_SIZE) / 2; // 在扇区内的偏移(2个字节为基本单位.)
secremain = InternalFLASH_SECTOR_SIZE / 2 - secoff; // 计算扇区剩余空间大小
if (NumToWrite <= secremain) // 判断整个页中剩下的空间是否足够写入我们要写入的数据
secremain = NumToWrite; // 要写的数据长度不大于该扇区范围的话,我们将剩余长度设置为要写入的长度
while (1)
{
InternalFLASH_Read(secpos * InternalFLASH_SECTOR_SIZE + InternalFLASH_BASE, InternalFLASH_BUF,
InternalFLASH_SECTOR_SIZE / 2); // 读出整个扇区的内容
for (i = 0; i < secremain; i++) // 校验数据,判断我们要写的区域中的数据是否都是0xFFFF // 校验数据
{
if (InternalFLASH_BUF[secoff + i] != 0XFFFF)
break; // 需要擦除
}
if (i < secremain) // 需要擦除
{
// 这里的擦除操作也可以使用 HAL_FLASHEx_Erase() 函数,它包含了下边的三个步骤
FLASH_PageErase(secpos * InternalFLASH_SECTOR_SIZE + InternalFLASH_BASE); // 擦除这个扇区
FLASH_WaitForLastOperation(FLASH_WAITETIME); // 等待上次操作完成
CLEAR_BIT(FLASH->CR, FLASH_CR_PER); // 清除CR寄存器的PER位,此操作应该在FLASH_PageErase()中完成!
// 但是HAL库里面并没有做,因为HAL库一般使用HAL_FLASHEx_Erase()来擦除
for (i = 0; i < secremain; i++) /// 复制要写入的数据到缓冲区
{
InternalFLASH_BUF[i + secoff] = pBuffer[i]; // 直接从偏移的位置复制数据,保护了其他不需要被覆盖的数据
}
InternalFLASH_Write_NoCheck(secpos * InternalFLASH_SECTOR_SIZE + InternalFLASH_BASE, InternalFLASH_BUF,
InternalFLASH_SECTOR_SIZE / 2); // 写入整个扇区
}
else
{
FLASH_WaitForLastOperation(FLASH_WAITETIME); // 等待上次操作完成
InternalFLASH_Write_NoCheck(WriteAddr, pBuffer, secremain); // 写已经擦除了的,直接写入扇区剩余区间.
}
if (NumToWrite == secremain)
break; // 写入结束了
else // 写入未结束
{
secpos++; // 扇区地址增1
secoff = 0; // 偏移位置为0
pBuffer += secremain; // 指针偏移
WriteAddr += secremain * 2; // 写地址偏移(16位数据地址,需要*2)
NumToWrite -= secremain; // 字节(16位)数递减
if (NumToWrite > (InternalFLASH_SECTOR_SIZE / 2))
secremain = InternalFLASH_SECTOR_SIZE / 2; // 下一个扇区还是写不完
else
secremain = NumToWrite; // 下一个扇区可以写完了
}
}
HAL_FLASH_Lock(); // 上锁
}
#endif
/**
* @brief 从指定地址开始读出指定长度的数据
* @note 注意:数据个数按半字(16位)计算
* @param ReadAddr 起始地址
* @param pBuffer 数据指针
* @param NumTRead 要读取的半字(16位)数,即2个字节的整数倍
* @retval
*/
void InternalFLASH_Read(uint32_t ReadAddr, uint16_t *pBuffer, uint16_t NumToRead) {
uint16_t i;
for (i = 0; i < NumToRead; i++)
{
pBuffer[i] = InternalFLASH_ReadHalfWord(ReadAddr); // 读取2个字节.
ReadAddr += 2; // 偏移2个字节.
}
}
void InternalFlash_Test(void) {
static int cnt = 0;
uint8_t TEXT_Buffer[128] = {0};
uint16_t datatemp[64] = {0};
uint32_t FLASH_SAVE_ADDR = 0X08070000;
// 生成要写入的数据
cnt++;
snprintf((char *)TEXT_Buffer, sizeof(TEXT_Buffer), "%s %d", "STM32F103 FLASH TEST!", cnt);
printf("TEXT_Buffer:%s, Size=%d HalfWordSize=%d\r\n", TEXT_Buffer, sizeof(TEXT_Buffer),
sizeof(TEXT_Buffer) / 2 + ((sizeof(TEXT_Buffer) % 2) ? 1 : 0));
// 写入前读取一次
InternalFLASH_Read(FLASH_SAVE_ADDR, (uint16_t *)datatemp,
sizeof(TEXT_Buffer) / 2 + ((sizeof(TEXT_Buffer) % 2) ? 1 : 0));
printf("before write:%s\r\n", (char *)datatemp);
// 写入数据
InternalFLASH_Write(FLASH_SAVE_ADDR, (uint16_t *)TEXT_Buffer,
sizeof(TEXT_Buffer) / 2 + ((sizeof(TEXT_Buffer) % 2) ? 1 : 0));
memset(datatemp, 0, sizeof(datatemp));
InternalFLASH_Read(FLASH_SAVE_ADDR, (uint16_t *)datatemp,
sizeof(TEXT_Buffer) / 2 + ((sizeof(TEXT_Buffer) % 2) ? 1 : 0));
printf("after write:%s\r\n", (char *)datatemp);
return;
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。