细说STM32F407指定地址范围按字节、半字、字、双字读、写片内Flash的方法

目录

一、硬件配置

二、软件设计

1、软件目的

(1)Test1_FlashInChip()

(2)Test2_FlashInChip()

2、main.h

3、main.c

(1)Test1_FlashInChip()

(2)Test2_FlashInChip()

公共代码部分

按字节写、读

按半字写、读

按字写、读

按双字写、读


本文旨在向读者详细说明,指定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, &sector_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

相关推荐
不做无法实现的梦~14 小时前
ros2实现路径规划---nav2部分
linux·stm32·嵌入式硬件·机器人·自动驾驶
熊猫_豆豆19 小时前
同步整流 Buck 降压变换器
单片机·嵌入式硬件·matlab
chenchen000000001 天前
49元能否买到四核性能?HZ-RK3506G2_MiniEVM开发板评测:MCU+三核CPU带来的超高性价比
单片机·嵌入式硬件
孤芳剑影1 天前
反馈环路设计总结
嵌入式硬件·学习
dump linux1 天前
设备树子系统与驱动开发入门
linux·驱动开发·嵌入式硬件
专注VB编程开发20年1 天前
简易虚拟 PLC 服务器-流水线自动化,上位机程序维护升级,西门子PLC仿真
服务器·单片机·自动化·上位机·plc·流水线·工控
LeoZY_1 天前
CH347/339W开源项目:集SPI、I2C、JTAG、SWD、UART、GPIO多功能为一体(3)
stm32·单片机·嵌入式硬件·mcu·开源
chenchen000000001 天前
国产显示芯势力新篇章:内置DDR+四核A35!MY-SSD2351-MINI开发板深度评测
驱动开发·嵌入式硬件
BackCatK Chen1 天前
第13篇:TMC2240 StallGuard4失速检测|寄存器配置+状态读取(保姆级)
单片机·嵌入式硬件·tmc2240·stm32实战·stallguard4·失速检测·电机故障识别
Hello_Embed1 天前
libmodbus STM32 板载串口实验(双串口主从通信)
笔记·stm32·单片机·学习·modbus