FLASH read and write function based on STM32


foreword

What we are going to learn today is flash reading and writing. Flash memory (Flash Memory) is a long-life non-volatile memory (it can still maintain the stored data information in the case of power failure). Use SD card, solid state drive, chip memory storage unit to store code.

1. FLASH

1 Introduction

The Flash interface manages CPU access to Flash through AHB I-Code and D-Code. This interface can perform erase and program operations on Flash, and implement read and write protection mechanisms.

The Flash interface accelerates code execution through instruction prefetching and caching mechanisms.

2. Main features

● 对于 STM32F40x 和 STM32F41x,容量高达 1 MB;对于 STM32F42x 和 STM32F43x, 
容量高达 2 MB
● 128 位宽数据读取
● 字节、半字、字和双字数据写入
● 扇区擦除与全部擦除
● 存储器组织结构
Flash 结构如下:
	— 主存储器块,分为 4 个 16 KB 扇区、1 个 64 KB 扇区和 7 个 128 KB 扇区
	— 系统存储器,器件在系统存储器自举模式下从该存储器启动
	— 512 字节 OTP(一次性可编程),用于存储用户数据
		OTP 区域还有 16 个额外字节,用于锁定对应的 OTP 数据块。
	— 选项字节,用于配置读写保护、BOR 级别、软件/硬件看门狗以及器件处于待机或 
		停止模式下的复位。
● 低功耗模式(有关详细信息,请参见参考手册的“电源控制 (PWR)”部分)

3. Flash module composition

insert image description here

It is about 512kb here, which is enough for most functions.

2. Use steps

1. Write operation

	//解除写保护
	FLASH_Unlock();
	//将一切的标志归零
	FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | 
                  FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); 
				  
	//擦除扇区4,擦除最小单元速度为4字节
	 if (FLASH_EraseSector(FLASH_Sector_4, VoltageRange_3) != FLASH_COMPLETE)
	{
    
     
		printf("FLASH_EraseSector sector 4 fail!\r\n");
		while(1);
	}
	for(i=0;i<64;i++)
	{
    
    
		//向扇区4首地址写入一个32位地址
		if(FLASH_ProgramWord(0x8010000+i*4,i+1) != FLASH_COMPLETE)
		{
    
    
			printf("FLASH_ProgramWord fail!\r\n");
			while(1);
		}
	}
	
	
	//添加写保护
	FLASH_Lock();

First remove the write protection, then clear all the flag bits, then erase the sectors, then write data one by one, and finally add write protection.

2. Read operation

for(i=0;i<64;i++)
	{
    
    
		d = *(__IO uint32_t*)(0x8010000+i*4);

		printf("read addr at 0x%08x data is 0x%x!\r\n",(0x8010000+i*4),d);
		
	}

Directly read an address of sector 4.

3. Complete code

#include "stm32f4xx.h"                  // Device header
#include "sys.h"
#include "stdio.h"


static GPIO_InitTypeDef  GPIO_InitStructure;
static USART_InitTypeDef USART_InitStructure;
static NVIC_InitTypeDef NVIC_InitStructure;
static uint16_t d;
uint32_t i;


struct __FILE {
    
     int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;
int fputc(int ch, FILE *f) 
{
    
    
	
	USART_SendData(USART1,ch);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	
	return ch;
}


void delay_ms(uint32_t n)
{
    
    
	while(n--)
	{
    
    
		SysTick->CTRL = 0; // Disable SysTick
		SysTick->LOAD = (168000)-1; // Count from 255 to 0 (256 cycles)
		SysTick->VAL = 0; // Clear current value as well as count flag
		SysTick->CTRL = 5; // Enable SysTick timer with processor clock
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
	}
	
	SysTick->CTRL = 0; // Disable SysTick
}
void delay_us(uint32_t n)
{
    
    
	while(n--)
	{
    
    
		SysTick->CTRL = 0; // Disable SysTick
		SysTick->LOAD = (168)-1; // Count from 255 to 0 (256 cycles)
		SysTick->VAL = 0; // Clear current value as well as count flag
		SysTick->CTRL = 5; // Enable SysTick timer with processor clock
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
	}
	
	SysTick->CTRL = 0; // Disable SysTick
}

void usart1_init(uint32_t band)
{
    
    
	
	//打开硬件时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	
	//打开串口1硬件时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//配置PA9和PA10为服用功能
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
	
	
	//将PA9和PA10引脚连接到串口1的硬件
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
	
	//配置串口1相关参数:波特率、无校验位、8位数位、1位停止位
	USART_InitStructure.USART_BaudRate = band;					//波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位数据位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;		//1个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;			//无奇偶检验
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//允许收发数据
  
    USART_Init(USART1, &USART_InitStructure);
	
	//配置串口1的中断触发方法 接收一个字节触发中断
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	//配置串口1的中断优先级

	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	//使能串口1工作
	USART_Cmd(USART1,ENABLE);
}




int main(void)
{
    
    
	int32_t d;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能GPIOF时钟

	//GPIOF9,F10初始化设置
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//复用功能模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化
	
	
	
	GPIO_SetBits(GPIOF,GPIO_Pin_9);
	
	
	usart1_init(115200);
	
	printf("this is Flash test!\r\n");
	
	
	//解除写保护
	FLASH_Unlock();
	//将一切的标志归零
	FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | 
                  FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); 
				  
	//擦除扇区4,擦除最小单元速度为4字节
	 if (FLASH_EraseSector(FLASH_Sector_4, VoltageRange_3) != FLASH_COMPLETE)
	{
    
     
		printf("FLASH_EraseSector sector 4 fail!\r\n");
		while(1);
	}
	for(i=0;i<64;i++)
	{
    
    
		//向扇区4首地址写入一个32位地址
		if(FLASH_ProgramWord(0x8010000+i*4,i+1) != FLASH_COMPLETE)
		{
    
    
			printf("FLASH_ProgramWord fail!\r\n");
			while(1);
		}
	}
	
	
	//添加写保护
	FLASH_Lock();
	
	for(i=0;i<64;i++)
	{
    
    
		d = *(__IO uint32_t*)(0x8010000+i*4);

		printf("read addr at 0x%08x data is 0x%x!\r\n",(0x8010000+i*4),d);
		
	}
	
	while(1)
	{
    
    

		
	}
	
}


void USART1_IRQHandler(void)
{
    
    
	
	//检查标志位
	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
	{
    
    
		d=USART_ReceiveData(USART1);
		
		printf(d+"");
		//清空标志位
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);
	}
	
	
}



3. Effect demonstration

insert image description here
Completely read out the written data.

Guess you like

Origin blog.csdn.net/weixin_46155589/article/details/128099949