目录
本文旨在向读者详细说明,指定FLASH的地址范围,并按字节、半字、字、双字读写FLASH的方法。在方法里具体地向读者提供了如何编写目的所需要的程序,如何对齐地址,如何通过串口助手显示效果。
阅读本文之前,可以参考本文作者发布的相似内容的文章,参考文章:细说STM32F407读写片内Flash和创建USBD_MSC_FlashInChip虚拟U盘接口的方法_stm32f407 flash 读写-CSDN博客 https://wenchm.blog.csdn.net/article/details/157392668?spm=1011.2415.3001.5331
继续使用旺宝红龙开发板STM32F407ZGT6 KIT1.0,使用STM32CUBEIDE 1.19.0开发环境。
一、硬件配置
与参考文章基本相同,不再重复描述;
二、软件设计
1、软件目的
(1)Test1_FlashInChip()
定义一个函数void Test1_FlashInChip(void),用于测试在指定的FLASH空间范围内,向每一个地址写入常量DATA_32 ((uint32_t)0x12345678),然后再逐地址读FLASH的值Data32。最后检查每次读FLASH的值Data32是否=写入值DATA_32,记录失败的次数。通过串口助手显示写入和读出的数据。
(2)Test2_FlashInChip()
定义一个函数void Test2_FlashInChip(void),用于测试在指定的FLASH空间范围内,向每一个地址写入变量uint8_t DATA8[bytes_tobe_rw],并用代码实现按字节bytes、半字half word、字word、双字double word实现对数据的写入、读出。
通过串口助手显示准备好的数据、写入的数据和读出的数据。
2、main.h
main.h是本项目软件的公共代码。
cpp
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
/* USER CODE BEGIN EFP */
void Test1_FlashInChip(void);
void Test2_FlashInChip(void);
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
/* USER CODE BEGIN Private defines */
#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes */
#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */
#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */
#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes */
#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes */
#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) /* Base @ of Sector 5, 128 Kbytes */
#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000) /* Base @ of Sector 6, 128 Kbytes */
#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000) /* Base @ of Sector 7, 128 Kbytes */
#define ADDR_FLASH_SECTOR_8 ((uint32_t)0x08080000) /* Base @ of Sector 8, 128 Kbytes */
#define ADDR_FLASH_SECTOR_9 ((uint32_t)0x080A0000) /* Base @ of Sector 9, 128 Kbytes */
#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000) /* Base @ of Sector 10, 128 Kbytes */
#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000) /* Base @ of Sector 11, 128 Kbytes */
#define ADDR_FLASH_SECTOR_12 ((uint32_t)0x08100000) /* a virtual sector 12, 128 Kbytes, */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
3、main.c
cpp
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "usb_device.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define FLASH_USER_START_ADDR ADDR_FLASH_SECTOR_10
#define FLASH_USER_END_ADDR ADDR_FLASH_SECTOR_11
#define DATA_32 ((uint32_t)0x12345678)
/* USER CODE END PM */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
static uint32_t GetSector(uint32_t Address);
/* USER CODE END PFP */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART3_UART_Init();
MX_USB_DEVICE_Init();
/* USER CODE BEGIN 2 */
printf("test Demo15_7 read and write Flash_In_Chip, and used for USBD MSC.\r\n");
Test1_FlashInChip();
// Test2_FlashInChip();
/* USER CODE END 2 */
Test1和Test2可以切换测试。
(1)Test1_FlashInChip()
Test1_FlashInChip()用于测试在指定的FLASH空间内,按word向指定的地址Address写入、读出常量数据DATA_32 ((uint32_t)0x12345678)。然后校验数据,最后在串口助手上显示写入的数据、读出的数据。
cpp
/* USER CODE BEGIN 4 */
/*
* @brief:get sector
*/
/* start test 6 */
uint32_t Addr_Index[12+1] = {ADDR_FLASH_SECTOR_0,ADDR_FLASH_SECTOR_1,ADDR_FLASH_SECTOR_2,\
ADDR_FLASH_SECTOR_3,ADDR_FLASH_SECTOR_4,ADDR_FLASH_SECTOR_5,\
ADDR_FLASH_SECTOR_6,ADDR_FLASH_SECTOR_7,ADDR_FLASH_SECTOR_8,\
ADDR_FLASH_SECTOR_9,ADDR_FLASH_SECTOR_10,ADDR_FLASH_SECTOR_11,ADDR_FLASH_SECTOR_12};
uint8_t FlashSector_Index[12] = {FLASH_SECTOR_0,FLASH_SECTOR_1,FLASH_SECTOR_2,
FLASH_SECTOR_3,FLASH_SECTOR_4,FLASH_SECTOR_5,
FLASH_SECTOR_6,FLASH_SECTOR_7,FLASH_SECTOR_8,
FLASH_SECTOR_9,FLASH_SECTOR_10,FLASH_SECTOR_11,};
/**
* @brief give the sector according to the address
* such as:
BeginSector =GetSector(start_addr);
EndSector =GetSector(start_addr +bytes_tobe_written -1);
* @param Address:address
* @retval the sector where the address is located
*/
static uint32_t GetSector(uint32_t Address)
{
uint32_t sector = 0;
for(uint8_t i=0; i<12; i++)
if((Address >=Addr_Index[i]) && (Address <Addr_Index[i+1]))
sector =(uint32_t)(FlashSector_Index[i]);
return sector;
}
上面的代码是公用的代码。
cpp
/**
* @brief Test1 read and write flash,
* @brief directly call HAL library functions.
* @param None
* @retval 0:OK,-1,ERROR
*/
void Test1_FlashInChip(void)
{
uint32_t StartSector = 0;
uint32_t EndSector = 0;
uint32_t Address = 0;
__IO uint32_t Data32 = 0;
__IO uint32_t MemoryProgramStatus = 0;
HAL_FLASH_Unlock();
/* erase user area.
* The user area refers to the space not utilized by the program itself,
* which can be customized.
*/
/* clear FLASH flags*/
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
StartSector = GetSector(FLASH_USER_START_ADDR);
EndSector = GetSector(FLASH_USER_END_ADDR);
/* erase sectors or mass********************************/
// FLASH_EraseInitTypeDef *eraseinit ={};
// eraseinit->NbSectors =EndSector -StartSector +1;
// eraseinit->Sector =StartSector; //this 2 code have same effect
// eraseinit->TypeErase =FLASH_TYPEERASE_SECTORS;
// eraseinit->VoltageRange =FLASH_VOLTAGE_RANGE_3;
// uint32_t *SectorError =0;
// HAL_FLASHEx_Erase(eraseinit, SectorError);
FLASH_EraseInitTypeDef eraseinit ={};
eraseinit.NbSectors =EndSector -StartSector +1;
eraseinit.Sector =StartSector; //this 2 code have same effect
eraseinit.TypeErase =FLASH_TYPEERASE_SECTORS;
eraseinit.VoltageRange =FLASH_VOLTAGE_RANGE_3;
uint32_t SectorError =0;
if(HAL_FLASHEx_Erase(&eraseinit, &SectorError) !=HAL_OK){
printf("erase failure.\r\n");
//此处写入异常处理
}
else
printf("erase success.\r\n");
/* Write into FLASH in words *******************************
* Write a constant to each address in the specified address space
*/
Address =FLASH_USER_START_ADDR;
while (Address <FLASH_USER_END_ADDR)
{
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, DATA_32) ==HAL_OK)
{
printf("write Address %08lx =%08lx,\r\n",Address,DATA_32); //test
Address =Address +4;
}
}
HAL_FLASH_Lock();
/* read from FLASH and check***************************************/
/* MemoryProgramStatus =0: write in correct
* MemoryProgramStatus !=0:write in error
*/
Address =FLASH_USER_START_ADDR;
MemoryProgramStatus = 0;
//Check if the data read out is equal to the data written in.
while (Address <FLASH_USER_END_ADDR)
{
Data32 = *(__IO uint32_t*)Address;
printf("read Address %08lx =%08lx,\r\n",Address,Data32); //test
//record data checked failed
if(Data32 != DATA_32)
MemoryProgramStatus++;
Address +=4; //Address alignment
}
printf("check error times =%08lx,\r\n",MemoryProgramStatus); //test
}
这里有一段被注释掉的用于格式化的代码,通过定义了一个结构体实例的指针进行初始化,理论化应该和通过定义结构体实例的变量进行初始化获得一样的结果,但是程序运行以后,结果是不一样的,通过指针初始化后,再调用HAL_FLASHEx_Erase(eraseinit, SectorError),其进行的擦除操作,是不完全的,开始的16个数据(16*4=64字节)的空间没有被成功擦除,因而写入这16个地址也不会成功,读出的数据也是错的,检查后记录的错误数据=16(0x10)。
按字word,32bit写入、读出FLASH的地址对齐方法:Address +=4;
程序运行后,在串口助手上显示的测试结果:
cpp
test Demo15_7 read and write Flash_In_Chip, and used for USBD MSC.
write Address 080c0000 =12345678,
write Address 080c0004 =12345678,
write Address 080c0008 =12345678,
write Address 080c000c =12345678,
write Address 080c0010 =12345678,
write Address 080c0014 =12345678,
write Address 080c0018 =12345678,
write Address 080c001c =12345678,
write Address 080c0020 =12345678,
write Address 080c0024 =12345678,
write Address 080c0028 =12345678,
write Address 080c002c =12345678,
write Address 080c0030 =12345678,
write Address 080c0034 =12345678,
//此处省略显示结果
write Address 080dffd0 =12345678,
write Address 080dffd4 =12345678,
write Address 080dffd8 =12345678,
write Address 080dffdc =12345678,
write Address 080dffe0 =12345678,
write Address 080dffe4 =12345678,
write Address 080dffe8 =12345678,
write Address 080dffec =12345678,
write Address 080dfff0 =12345678,
write Address 080dfff4 =12345678,
write Address 080dfff8 =12345678,
write Address 080dfffc =12345678,
read Address 080c0000 =12345678,
read Address 080c0004 =12345678,
read Address 080c0008 =12345678,
read Address 080c000c =12345678,
read Address 080c0010 =12345678,
read Address 080c0014 =12345678,
read Address 080c0018 =12345678,
read Address 080c001c =12345678,
read Address 080c0020 =12345678,
read Address 080c0024 =12345678,
read Address 080c0028 =12345678,
read Address 080c002c =12345678,
read Address 080c0030 =12345678,
read Address 080c0034 =12345678,
//此处省略显示结果
read Address 080dffcc =12345678,
read Address 080dffd0 =12345678,
read Address 080dffd4 =12345678,
read Address 080dffd8 =12345678,
read Address 080dffdc =12345678,
read Address 080dffe0 =12345678,
read Address 080dffe4 =12345678,
read Address 080dffe8 =12345678,
read Address 080dffec =12345678,
read Address 080dfff0 =12345678,
read Address 080dfff4 =12345678,
read Address 080dfff8 =12345678,
read Address 080dfffc =12345678,
check error times =00000000,
(2)Test2_FlashInChip()
Test2_FlashInChip()用于测试在指定的FLASH空间内,按字节bytes、半字half word、按字words、按双字double words,向指定的地址Address写入、读出数据变量uint8_t DATA8[bytes_tobe_rw] 。然后校验数据,最后在串口助手上显示写入的数据、读出的数据。
写、读的字节数量=64字节。起始扇区号=10。
公共代码部分
cpp
void Test2_FlashInChip(void)
{
uint32_t StartSector = 0;
uint32_t EndSector = 0;
uint32_t Address = 0;
uint16_t bytes_tobe_rw =64; //bytes
/* erase user area.
* The user area refers to the space not utilized by the program itself,
* which can be customized.
*/
/* clear FLASH flags*/
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
HAL_FLASH_Unlock();
StartSector = GetSector(FLASH_USER_START_ADDR);
EndSector = GetSector(FLASH_USER_START_ADDR +bytes_tobe_rw -1);
/* erase sectors or mass********************************/
FLASH_EraseInitTypeDef erase = {
.TypeErase =FLASH_TYPEERASE_SECTORS,
.Sector =StartSector,
.NbSectors =(EndSector -StartSector +1),
.VoltageRange =FLASH_VOLTAGE_RANGE_3
};
uint32_t sector_error;
if(HAL_FLASHEx_Erase(&erase, §or_error) !=HAL_OK){
printf("erase failure.\r\n");
//Here is exception handling.
}
else
printf("erase success.\r\n");
按字节写、读
一个地址=1个字节的数据,16进制表示为2个字符,地址对齐的方法Address ++。
写:
cpp
/* Write into FLASH in bytes,8bits ********************************/
uint8_t DATA8[bytes_tobe_rw] ={};
for(uint32_t i=0; i <bytes_tobe_rw;i++)
DATA8[i] =i;
Address =FLASH_USER_START_ADDR;
uint8_t j =0;
while (Address <(uint32_t)(FLASH_USER_START_ADDR +bytes_tobe_rw))
{
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, Address, DATA8[j]) == HAL_OK)
{
printf("写入Address %08lx =%02x,\r\n",Address,DATA8[j]); //test
Address ++;
j ++;
}
}
while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY));
读:
cpp
/* read from FLASH in bytes, 8bits***************************************/
Address =FLASH_USER_START_ADDR;
volatile uint8_t Data8[bytes_tobe_rw] ={};
j=0;
while (Address <(FLASH_USER_START_ADDR +bytes_tobe_rw))
{
__DSB();
Data8[j] = *(__IO uint8_t*)Address;
printf("read Address %08lx =%02x,\r\n", Address, Data8[j]); //test
Address++;
j++;
}
通过串口助手显示按字节写、读FLASH的测试结果:
cpp
test Demo15_7 read and write Flash_In_Chip, and used for USBD MSC.
erase success.
写入Address 080c0000 =00,
写入Address 080c0001 =01,
写入Address 080c0002 =02,
写入Address 080c0003 =03,
写入Address 080c0004 =04,
写入Address 080c0005 =05,
写入Address 080c0006 =06,
写入Address 080c0007 =07,
写入Address 080c0008 =08,
写入Address 080c0009 =09,
写入Address 080c000a =0a,
写入Address 080c000b =0b,
写入Address 080c000c =0c,
写入Address 080c000d =0d,
写入Address 080c000e =0e,
写入Address 080c000f =0f,
写入Address 080c0010 =10,
写入Address 080c0011 =11,
写入Address 080c0012 =12,
写入Address 080c0013 =13,
写入Address 080c0014 =14,
写入Address 080c0015 =15,
写入Address 080c0016 =16,
写入Address 080c0017 =17,
写入Address 080c0018 =18,
写入Address 080c0019 =19,
写入Address 080c001a =1a,
写入Address 080c001b =1b,
写入Address 080c001c =1c,
写入Address 080c001d =1d,
写入Address 080c001e =1e,
写入Address 080c001f =1f,
写入Address 080c0020 =20,
写入Address 080c0021 =21,
写入Address 080c0022 =22,
写入Address 080c0023 =23,
写入Address 080c0024 =24,
写入Address 080c0025 =25,
写入Address 080c0026 =26,
写入Address 080c0027 =27,
写入Address 080c0028 =28,
写入Address 080c0029 =29,
写入Address 080c002a =2a,
写入Address 080c002b =2b,
写入Address 080c002c =2c,
写入Address 080c002d =2d,
写入Address 080c002e =2e,
写入Address 080c002f =2f,
写入Address 080c0030 =30,
写入Address 080c0031 =31,
写入Address 080c0032 =32,
写入Address 080c0033 =33,
写入Address 080c0034 =34,
写入Address 080c0035 =35,
写入Address 080c0036 =36,
写入Address 080c0037 =37,
写入Address 080c0038 =38,
写入Address 080c0039 =39,
写入Address 080c003a =3a,
写入Address 080c003b =3b,
写入Address 080c003c =3c,
写入Address 080c003d =3d,
写入Address 080c003e =3e,
写入Address 080c003f =3f,
read Address 080c0000 =00,
read Address 080c0001 =01,
read Address 080c0002 =02,
read Address 080c0003 =03,
read Address 080c0004 =04,
read Address 080c0005 =05,
read Address 080c0006 =06,
read Address 080c0007 =07,
read Address 080c0008 =08,
read Address 080c0009 =09,
read Address 080c000a =0a,
read Address 080c000b =0b,
read Address 080c000c =0c,
read Address 080c000d =0d,
read Address 080c000e =0e,
read Address 080c000f =0f,
read Address 080c0010 =10,
read Address 080c0011 =11,
read Address 080c0012 =12,
read Address 080c0013 =13,
read Address 080c0014 =14,
read Address 080c0015 =15,
read Address 080c0016 =16,
read Address 080c0017 =17,
read Address 080c0018 =18,
read Address 080c0019 =19,
read Address 080c001a =1a,
read Address 080c001b =1b,
read Address 080c001c =1c,
read Address 080c001d =1d,
read Address 080c001e =1e,
read Address 080c001f =1f,
read Address 080c0020 =20,
read Address 080c0021 =21,
read Address 080c0022 =22,
read Address 080c0023 =23,
read Address 080c0024 =24,
read Address 080c0025 =25,
read Address 080c0026 =26,
read Address 080c0027 =27,
read Address 080c0028 =28,
read Address 080c0029 =29,
read Address 080c002a =2a,
read Address 080c002b =2b,
read Address 080c002c =2c,
read Address 080c002d =2d,
read Address 080c002e =2e,
read Address 080c002f =2f,
read Address 080c0030 =30,
read Address 080c0031 =31,
read Address 080c0032 =32,
read Address 080c0033 =33,
read Address 080c0034 =34,
read Address 080c0035 =35,
read Address 080c0036 =36,
read Address 080c0037 =37,
read Address 080c0038 =38,
read Address 080c0039 =39,
read Address 080c003a =3a,
read Address 080c003b =3b,
read Address 080c003c =3c,
read Address 080c003d =3d,
read Address 080c003e =3e,
read Address 080c003f =3f,
按半字写、读
一个起始地址表示2个字节的数据,16进制表示为4个字符,地址对齐的方法Address +=2。
写:
cpp
/* Write into FLASH in half word,16bits********************************/
uint16_t DATA16[bytes_tobe_rw/2] ={};
for(uint32_t j=0; j <bytes_tobe_rw/2; j++)
{
DATA16[j] =DATA8[j*2+0]|(DATA8[j*2+1]<<8);
printf("data ready, DATA16[0x%08lx] =0x%04x,\r\n",j,DATA16[j]);//test
}
Address =FLASH_USER_START_ADDR;
uint32_t j =0;
while (Address <(uint32_t)(FLASH_USER_START_ADDR +bytes_tobe_rw))
{
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Address, DATA16[j]) == HAL_OK)
{
printf("写入Address %08lx =%04x,\r\n",Address,DATA16[j]); //test
Address +=2;
j ++;
}
}
while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY));
读:
cpp
/* read from FLASH in half words, 16bits***************************************/
Address =FLASH_USER_START_ADDR;
volatile uint16_t Data16[bytes_tobe_rw/2] ={};
j=0;
while (Address <(FLASH_USER_START_ADDR +bytes_tobe_rw))
{
__DSB();
Data16[j] = *(__IO uint16_t*)Address;
printf("read Address %08lx =0x%04x,\r\n", Address, Data16[j]); //test
Address +=2;
j++;
}
通过串口助手显示按半字写、读FLASH的测试结果:
cpp
test Demo15_7 read and write Flash_In_Chip, and used for USBD MSC.
erase success.
data ready, DATA16[0x00000000] =0x0100,
data ready, DATA16[0x00000001] =0x0302,
data ready, DATA16[0x00000002] =0x0504,
data ready, DATA16[0x00000003] =0x0706,
data ready, DATA16[0x00000004] =0x0908,
data ready, DATA16[0x00000005] =0x0b0a,
data ready, DATA16[0x00000006] =0x0d0c,
data ready, DATA16[0x00000007] =0x0f0e,
data ready, DATA16[0x00000008] =0x1110,
data ready, DATA16[0x00000009] =0x1312,
data ready, DATA16[0x0000000a] =0x1514,
data ready, DATA16[0x0000000b] =0x1716,
data ready, DATA16[0x0000000c] =0x1918,
data ready, DATA16[0x0000000d] =0x1b1a,
data ready, DATA16[0x0000000e] =0x1d1c,
data ready, DATA16[0x0000000f] =0x1f1e,
data ready, DATA16[0x00000010] =0x2120,
data ready, DATA16[0x00000011] =0x2322,
data ready, DATA16[0x00000012] =0x2524,
data ready, DATA16[0x00000013] =0x2726,
data ready, DATA16[0x00000014] =0x2928,
data ready, DATA16[0x00000015] =0x2b2a,
data ready, DATA16[0x00000016] =0x2d2c,
data ready, DATA16[0x00000017] =0x2f2e,
data ready, DATA16[0x00000018] =0x3130,
data ready, DATA16[0x00000019] =0x3332,
data ready, DATA16[0x0000001a] =0x3534,
data ready, DATA16[0x0000001b] =0x3736,
data ready, DATA16[0x0000001c] =0x3938,
data ready, DATA16[0x0000001d] =0x3b3a,
data ready, DATA16[0x0000001e] =0x3d3c,
data ready, DATA16[0x0000001f] =0x3f3e,
写入Address 080c0000 =0100,
写入Address 080c0002 =0302,
写入Address 080c0004 =0504,
写入Address 080c0006 =0706,
写入Address 080c0008 =0908,
写入Address 080c000a =0b0a,
写入Address 080c000c =0d0c,
写入Address 080c000e =0f0e,
写入Address 080c0010 =1110,
写入Address 080c0012 =1312,
写入Address 080c0014 =1514,
写入Address 080c0016 =1716,
写入Address 080c0018 =1918,
写入Address 080c001a =1b1a,
写入Address 080c001c =1d1c,
写入Address 080c001e =1f1e,
写入Address 080c0020 =2120,
写入Address 080c0022 =2322,
写入Address 080c0024 =2524,
写入Address 080c0026 =2726,
写入Address 080c0028 =2928,
写入Address 080c002a =2b2a,
写入Address 080c002c =2d2c,
写入Address 080c002e =2f2e,
写入Address 080c0030 =3130,
写入Address 080c0032 =3332,
写入Address 080c0034 =3534,
写入Address 080c0036 =3736,
写入Address 080c0038 =3938,
写入Address 080c003a =3b3a,
写入Address 080c003c =3d3c,
写入Address 080c003e =3f3e,
read Address 080c0000 =0x0100,
read Address 080c0002 =0x0302,
read Address 080c0004 =0x0504,
read Address 080c0006 =0x0706,
read Address 080c0008 =0x0908,
read Address 080c000a =0x0b0a,
read Address 080c000c =0x0d0c,
read Address 080c000e =0x0f0e,
read Address 080c0010 =0x1110,
read Address 080c0012 =0x1312,
read Address 080c0014 =0x1514,
read Address 080c0016 =0x1716,
read Address 080c0018 =0x1918,
read Address 080c001a =0x1b1a,
read Address 080c001c =0x1d1c,
read Address 080c001e =0x1f1e,
read Address 080c0020 =0x2120,
read Address 080c0022 =0x2322,
read Address 080c0024 =0x2524,
read Address 080c0026 =0x2726,
read Address 080c0028 =0x2928,
read Address 080c002a =0x2b2a,
read Address 080c002c =0x2d2c,
read Address 080c002e =0x2f2e,
read Address 080c0030 =0x3130,
read Address 080c0032 =0x3332,
read Address 080c0034 =0x3534,
read Address 080c0036 =0x3736,
read Address 080c0038 =0x3938,
read Address 080c003a =0x3b3a,
read Address 080c003c =0x3d3c,
read Address 080c003e =0x3f3e,
按字写、读
一个起始地址表示4个字节的数据,16进制表示为8个字符,地址对齐的方法Address +=4。
写:
cpp
uint32_t DATA32[bytes_tobe_rw/4] ={};
for(uint32_t j=0; j <bytes_tobe_rw/4; j++)
{
DATA32[j] =DATA8[j*4+0] |(DATA8[j*4+1]<<8) |(DATA8[j*4+2]<<16) |(DATA8[j*4+3]<<24);
printf("data ready, DATA32[0x%08lx] =0x%08lx,\r\n",j,DATA32[j]);//test
}
Address =FLASH_USER_START_ADDR;
uint32_t j =0;
while (Address <(uint32_t)(FLASH_USER_START_ADDR +bytes_tobe_rw))
{
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, DATA32[j]) == HAL_OK)
{
printf("写入Address %08lx =%08lx,\r\n",Address,DATA32[j]); //test
Address +=4;
j ++;
}
}
while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY));
读:
cpp
Address =FLASH_USER_START_ADDR;
volatile uint32_t Data32[bytes_tobe_rw/4] ={};
volatile uint32_t *pFlash;
j=0;
while (Address <(FLASH_USER_START_ADDR +bytes_tobe_rw))
{
__DSB();
pFlash = (volatile uint32_t*)Address;
Data32[j] = *pFlash; //Forced read from physical address
printf("read Address %08lx =%08lx,\r\n", Address, Data32[j]); //test
Address +=4;
j++;
}
通过串口助手显示按字写、读FLASH的测试结果:
cpp
test Demo15_7 read and write Flash_In_Chip, and used for USBD MSC.
erase success.
data ready, DATA32[0x00000000] =0x03020100,
data ready, DATA32[0x00000001] =0x07060504,
data ready, DATA32[0x00000002] =0x0b0a0908,
data ready, DATA32[0x00000003] =0x0f0e0d0c,
data ready, DATA32[0x00000004] =0x13121110,
data ready, DATA32[0x00000005] =0x17161514,
data ready, DATA32[0x00000006] =0x1b1a1918,
data ready, DATA32[0x00000007] =0x1f1e1d1c,
data ready, DATA32[0x00000008] =0x23222120,
data ready, DATA32[0x00000009] =0x27262524,
data ready, DATA32[0x0000000a] =0x2b2a2928,
data ready, DATA32[0x0000000b] =0x2f2e2d2c,
data ready, DATA32[0x0000000c] =0x33323130,
data ready, DATA32[0x0000000d] =0x37363534,
data ready, DATA32[0x0000000e] =0x3b3a3938,
data ready, DATA32[0x0000000f] =0x3f3e3d3c,
写入Address 080c0000 =03020100,
写入Address 080c0004 =07060504,
写入Address 080c0008 =0b0a0908,
写入Address 080c000c =0f0e0d0c,
写入Address 080c0010 =13121110,
写入Address 080c0014 =17161514,
写入Address 080c0018 =1b1a1918,
写入Address 080c001c =1f1e1d1c,
写入Address 080c0020 =23222120,
写入Address 080c0024 =27262524,
写入Address 080c0028 =2b2a2928,
写入Address 080c002c =2f2e2d2c,
写入Address 080c0030 =33323130,
写入Address 080c0034 =37363534,
写入Address 080c0038 =3b3a3938,
写入Address 080c003c =3f3e3d3c,
read Address 080c0000 =03020100,
read Address 080c0004 =07060504,
read Address 080c0008 =0b0a0908,
read Address 080c000c =0f0e0d0c,
read Address 080c0010 =13121110,
read Address 080c0014 =17161514,
read Address 080c0018 =1b1a1918,
read Address 080c001c =1f1e1d1c,
read Address 080c0020 =23222120,
read Address 080c0024 =27262524,
read Address 080c0028 =2b2a2928,
read Address 080c002c =2f2e2d2c,
read Address 080c0030 =33323130,
read Address 080c0034 =37363534,
read Address 080c0038 =3b3a3938,
read Address 080c003c =3f3e3d3c,
按双字写、读
一个起始地址表示8个字节的数据,16进制表示为16个字符,地址对齐的方法Address +=8。
写:
cpp
/* Write into FLASH in double words, 64bits********************************/
uint64_t DATA64[bytes_tobe_rw/8] ={};
uint32_t Hi_DATA64[bytes_tobe_rw/8] ={};
uint32_t Li_DATA64[bytes_tobe_rw/8] ={};
for(uint32_t j=0; j <bytes_tobe_rw/8; j++)
{
/* When shifting left more than 31 bits,
* ensure the operand is 64-bit (such as using uint64_t typecasting)
* avoid 32-bit integer shift truncation.
*/
DATA64[j] =DATA8[j*8+0] |(DATA8[j*8+1]<<8) |(DATA8[j*8+2]<<16) |(DATA8[j*8+3]<<24) |
((uint64_t)DATA8[j*8+4]<<32) |
((uint64_t)DATA8[j*8+5]<<40) |
((uint64_t)DATA8[j*8+6]<<48) |
((uint64_t)DATA8[j*8+7]<<56);
Hi_DATA64[j] =DATA64[j] >>32;
Li_DATA64[j] =DATA64[j] &(0xFFFFFFFF);
printf("data ready, DATA64[%lx] =0x%08lx%08lx,\r\n",j, Hi_DATA64[j], Li_DATA64[j]); //test
}
Address =FLASH_USER_START_ADDR;
uint32_t j =0;
HAL_StatusTypeDef ret1,ret2;
if(*(volatile uint32_t*)Address != 0xFFFFFFFF) {
HAL_FLASHEx_Erase(eraseinit, SectorError); //Re-erase
}
/* When TypeProgram is double word,
* HAL_FLASH_Program write fails,
* and it can only be written successfully after being split into word
*/
while (Address <(uint32_t)(FLASH_USER_START_ADDR +bytes_tobe_rw))
{
// HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, DATA64[j]); //Unavailable
ret2 =HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, Li_DATA64[j]);
ret1 =HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address+4, Hi_DATA64[j]);
if((ret1 ==HAL_OK) &&(ret2 ==HAL_OK))
{
printf("写入Address %08lx =0x%08lx%08lx,\r\n",Address, Hi_DATA64[j], Li_DATA64[j]); //test
}
Address +=8;
j ++;
}
while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY));
HAL_FLASH_Lock();
读,使用了3种方法,切换使用
cpp
/* read from FLASH in double words, 64bits split into two 32bits*******
* method 1
*/
Address =FLASH_USER_START_ADDR;
volatile uint32_t Hi_Data64[bytes_tobe_rw/8] ={};
volatile uint32_t Li_Data64[bytes_tobe_rw/8] ={};
j=0;
while (Address <(FLASH_USER_START_ADDR +bytes_tobe_rw))
{
__DSB();
__HAL_FLASH_SET_LATENCY(FLASH_LATENCY_5); //Adjust according to the clock frequency
//Read out 64 bits data at two times
Li_Data64[j] =*(volatile uint32_t*)Address;
Address +=4;
Hi_Data64[j] =*(volatile uint32_t*)(Address);
printf("read Address, %08lx =0x%08lx%08lx,\r\n",Address-4, Hi_Data64[j], Li_Data64[j]); //test
Address +=4;
j++;
}
cpp
/* read from FLASH in double words, 64bits split into two 32bits*******
* method 2 is more convenient to read.
*/
Address =FLASH_USER_START_ADDR;
volatile uint32_t Hi_Data64[bytes_tobe_rw/8] ={};
volatile uint32_t Li_Data64[bytes_tobe_rw/8] ={};
j=0;
while (Address <(FLASH_USER_START_ADDR +bytes_tobe_rw))
{
__DSB();
__HAL_FLASH_SET_LATENCY(FLASH_LATENCY_5); //Adjust according to the clock frequency
//Read out 64 bits data at two times
Li_Data64[j] =*(volatile uint32_t*)Address;
Hi_Data64[j] =*(volatile uint32_t*)(Address +4);
printf("read Address, %08lx =0x%08lx%08lx,\r\n",Address, Hi_Data64[j], Li_Data64[j]); //test
Address +=8;
j++;
}
cpp
Address =FLASH_USER_START_ADDR;
volatile uint64_t Data64[bytes_tobe_rw/8] ={};
uint32_t Hi_Data64[bytes_tobe_rw/8] ={};
uint32_t Li_Data64[bytes_tobe_rw/8] ={};
j=0;
volatile uint32_t Li_data64 = *(__IO uint32_t*)Address;
printf("read first Address, %08lx =%08lx,\r\n",Address, Li_data64); //test
while (Address <(FLASH_USER_START_ADDR +bytes_tobe_rw))
{
__DSB();
__HAL_FLASH_SET_LATENCY(FLASH_LATENCY_5); //Adjust according to the clock frequency
//Read out 64 bits data at a time
Data64[j] = *(__IO uint64_t*)Address;
Hi_Data64[j] =(Data64[j] >>32) &(0xFFFFFFFF);
Li_Data64[j] =Data64[j] &(0xFFFFFFFF);
printf("read Address, %08lx =0x%08lx%08lx,\r\n",Address, Hi_Data64[j], Li_Data64[j]); //test
Address +=8;
j++;
}
cpp
}//void Test2_FlashInChip(void)
int __io_putchar(int ch)
{
HAL_UART_Transmit(&huart3,(uint8_t*)&ch,1,0xFFFF);
return ch;
}
/* USER CODE END 4 */
通过串口助手显示按双字写、读FLASH的测试结果:
cpp
test Demo15_7 read and write Flash_In_Chip, and used for USBD MSC.
erase success.
data ready, DATA64[0] =0x0706050403020100,
data ready, DATA64[1] =0x0f0e0d0c0b0a0908,
data ready, DATA64[2] =0x1716151413121110,
data ready, DATA64[3] =0x1f1e1d1c1b1a1918,
data ready, DATA64[4] =0x2726252423222120,
data ready, DATA64[5] =0x2f2e2d2c2b2a2928,
data ready, DATA64[6] =0x3736353433323130,
data ready, DATA64[7] =0x3f3e3d3c3b3a3938,
写入Address 080c0000 =0x0706050403020100,
写入Address 080c0008 =0x0f0e0d0c0b0a0908,
写入Address 080c0010 =0x1716151413121110,
写入Address 080c0018 =0x1f1e1d1c1b1a1918,
写入Address 080c0020 =0x2726252423222120,
写入Address 080c0028 =0x2f2e2d2c2b2a2928,
写入Address 080c0030 =0x3736353433323130,
写入Address 080c0038 =0x3f3e3d3c3b3a3938,
read Address, 080c0000 =0x0706050403020100,
read Address, 080c0008 =0x0f0e0d0c0b0a0908,
read Address, 080c0010 =0x1716151413121110,
read Address, 080c0018 =0x1f1e1d1c1b1a1918,
read Address, 080c0020 =0x2726252423222120,
read Address, 080c0028 =0x2f2e2d2c2b2a2928,
read Address, 080c0030 =0x3736353433323130,
read Address, 080c0038 =0x3f3e3d3c3b3a3938,
好了,全部写好了。享受吧。
完整代码:
wenchm/Demo15_7USBD_RW_FlashInChip: 指定片内FLASH的地址范围,按字节、半字、字、双字进行写与读,并地址对齐的方法 https://github.com/wenchm/Demo15_7USBD_RW_FlashInChip