AT32F403A STM32F103内部flash模拟eeprom读写和擦除


闪存控制器(FLASH)

一、FLASH介绍

闪存由主存储器、外部存储器、信息块、闪存寄存器这四个部分组成。
 主存储器容量高达 1024K 字节,分为第 1 片闪存(bank1)和第 2 片闪存(bank2)  外部存储器容量最高可达 16M 字节
 信息块由 16K 字节的系统启动程序代码区和用户系统数据区组成。系统启动程序使用
USART1、USART2 或者 USB(DFU)接口实现 ISP 编程
1024K 字节容量的主存储器分为片 1 和片 2 闪存,每片闪存容量为 512K 字节,每片闪存包含 256 扇区,
每扇区大小为 2K 字节。
外部存储器容量可高达 16M 字节,包含 4096 扇区,每扇区大小为 4K 字节。
表 1 闪存存储结构(1024K)
在这里插入图片描述
512K 字节容量的主存储器只有片 1 闪存,包含 256 扇区,每扇区大小为 2K 字节。
外部存储器容量可高达 16M 字节,包含 4096 扇区,每扇区大小为 4K 字节。
表 2 闪存存储组织(512K)
在这里插入图片描述
256K 字节容量的主存储器只有片 1 闪存,包含 128 扇区,每扇区大小为 2K 字节。
外部存储器容量可高达 16M 字节,包含 4096 扇区,每扇区大小为 4K 字节。
表 3 闪存存储组织(256K)
在这里插入图片描述
下面以雅特力官方库版本 AT32F403A_407_Firmware_Library-v2.0.8 flash驱动为例,介绍AT32F403A内部flash读写的具体流程和读写测试方法

二、AT32F403A 内部flash读写

1. 内部flash写入

当想要改写主存储器的内容时,可以通过主存储器编程流程完成一次写入 32 位、16 位或 8 位的数据。
主存储器编程流程:  检查闪存状态寄存器 x(FLASH_STSx)的 OBF 位,确认没有正在进行的闪存操作;  对闪存控制寄存器 x(FLASH_CTRLx)的 FPRGM 位置 1,此时可以接受对主闪存的
编程指令;
 对指定的地址写入要编程的数据(任意字/半字/字节);
 等待闪存状态寄存器 x(FLASH_STSx)的 OBF 位变为‘0’,并查询闪存状态寄存器 x (FLASH_STSx)的 EPPERR 位、PRGMERR 位和 ODF 位,确认编程结果。
注意:1.当要写入的地址未被提前擦除时,除非要写入的数据值是全 0,否则编程不被执
行,并置位闪存状态寄存器 x(FLASH_STSx)的 PRGMERR 位来告知编程发生错
误。
2.编程期间进行读闪存的操作,将导致 CPU 会被暂停直到编程完成才处理读闪存操
作。
图 4 主存储器编程流程
在这里插入图片描述

1、不带校验直接写入

/**
  * @brief  write data using halfword mode without checking
  * @param  write_addr: the address of writing
  * @param  p_buffer: the buffer of writing data
  * @param  num_write: the number of writing data
  * @retval none
  */
void flash_write_nocheck(uint32_t write_addr, uint16_t *p_buffer, uint16_t num_write)
{
  uint16_t i;
  for(i = 0; i < num_write; i++)
  {
    flash_halfword_program(write_addr, p_buffer[i]);
    write_addr += 2;
  }
}

2、带校验写入

/**
  * @brief  write data using halfword mode with checking
  * @param  write_addr: the address of writing
  * @param  p_buffer: the buffer of writing data
  * @param  num_write: the number of writing data
  * @retval none
  */
void flash_write(uint32_t write_addr, uint16_t *p_buffer, uint16_t num_write)
{
  uint32_t offset_addr;
  uint32_t sector_position;
  uint16_t sector_offset;
  uint16_t sector_remain;
  uint16_t i;

  flash_unlock();
  offset_addr = write_addr - FLASH_BASE;
  sector_position = offset_addr / SECTOR_SIZE;
  sector_offset = (offset_addr % SECTOR_SIZE) / 2;
  sector_remain = SECTOR_SIZE / 2 - sector_offset;
  if(num_write <= sector_remain)
    sector_remain = num_write;
  while(1)
  {
    flash_read(sector_position * SECTOR_SIZE + FLASH_BASE, flash_buf, SECTOR_SIZE / 2);
    for(i = 0; i < sector_remain; i++)
    {
      if(flash_buf[sector_offset + i] != 0xFFFF)
        break;
    }
     if(i < sector_remain)
    {
      flash_sector_erase(sector_position * SECTOR_SIZE + FLASH_BASE);
      for(i = 0; i < sector_remain; i++)
      {
        flash_buf[i + sector_offset] = p_buffer[i];
      }
      flash_write_nocheck(sector_position * SECTOR_SIZE + FLASH_BASE, flash_buf, SECTOR_SIZE / 2);
    }
    else
    {
      flash_write_nocheck(write_addr, p_buffer, sector_remain);
    }
    if(num_write == sector_remain)
      break;
    else
    {
      sector_position++;
      sector_offset = 0;
      p_buffer += sector_remain;
      write_addr += (sector_remain * 2);
      num_write -= sector_remain;
      if(num_write > (SECTOR_SIZE / 2))
        sector_remain = SECTOR_SIZE / 2;
      else
        sector_remain = num_write;
    }
  }
  flash_lock();
}

2. 内部flash读取

通过 CPU 的 AHB 总线可以直接寻址访问主闪存存储区。

/**
  * @brief  read data using halfword mode
  * @param  read_addr: the address of reading
  * @param  p_buffer: the buffer of reading data
  * @param  num_read: the number of reading data
  * @retval none
  */
void flash_read(uint32_t read_addr, uint16_t *p_buffer, uint16_t num_read)
{
  uint16_t i;
  for(i = 0; i < num_read; i++)
  {
    p_buffer[i] = *(uint16_t*)(read_addr);
    read_addr += 2;
  }
}

3. 内部flash读写测试

1、头文件 flash.h

#ifndef __FLASH_H__
#define __FLASH_H__

#ifdef __cplusplus
extern "C" {
#endif

#include "at32f403a_407_board.h"



/** @defgroup FLASH_write_read_functions
  * @{
  */
u16 flash_ReadHalfWord(u32 faddr);
void flash_read(uint32_t read_addr, uint16_t *p_buffer, uint16_t num_read);
void flash_write_nocheck(uint32_t write_addr, uint16_t *p_buffer, uint16_t num_write);
void flash_write(uint32_t write_addr,uint16_t *p_Buffer, uint16_t num_write);

/**
  * @}
  */

2、源文件 flash.c

/**
  **************************************************************************
  * @file     flash.c
  * @version  v2.0.8
  * @date     2022-04-02
  * @brief    flash program
  **************************************************************************
  *                       Copyright notice & Disclaimer
  *
  * The software Board Support Package (BSP) that is made available to
  * download from Artery official website is the copyrighted work of Artery.
  * Artery authorizes customers to use, copy, and distribute the BSP
  * software and its related documentation for the purpose of design and
  * development in conjunction with Artery microcontrollers. Use of the
  * software is governed by this copyright notice and the following disclaimer.
  *
  *
  * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
  * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
  * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
  * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
  * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
  *
  **************************************************************************
  */
#include "at32f403a_407_board.h"
#include "flash.h"
/** @addtogroup AT32F403A_periph_examples
  * @{
  */

/** @addtogroup 403A_FLASH_write_read
  * @{
  */

#define SECTOR_SIZE                      2048   /* this parameter depends on the specific model of the chip */

uint16_t flash_buf[SECTOR_SIZE / 2];
uint16_t flash_buf[SECTOR_SIZE / 2];


//读取指定地址的半字(16位数据)
//faddr:读地址(此地址必须为2的倍数!!)
//返回值:对应数据.
u16 flash_ReadHalfWord(u32 faddr){
	return *(vu16*)faddr; 
}
/**
  * @brief  read data using halfword mode
  * @param  read_addr: the address of reading
  * @param  p_buffer: the buffer of reading data
  * @param  num_read: the number of reading data
  * @retval none
  */
void flash_read(uint32_t read_addr, uint16_t *p_buffer, uint16_t num_read)
{
  uint16_t i;
  for(i = 0; i < num_read; i++)
  {
    p_buffer[i] = *(uint16_t*)(read_addr);
    read_addr += 2;
  }
}


/**
  * @brief  write data using halfword mode without checking
  * @param  write_addr: the address of writing
  * @param  p_buffer: the buffer of writing data
  * @param  num_write: the number of writing data
  * @retval none
  */
void flash_write_nocheck(uint32_t write_addr, uint16_t *p_buffer, uint16_t num_write)
{
  uint16_t i;
  for(i = 0; i < num_write; i++)
  {
    flash_halfword_program(write_addr, p_buffer[i]);
    write_addr += 2;
  }
}

/**
  * @brief  write data using halfword mode with checking
  * @param  write_addr: the address of writing
  * @param  p_buffer: the buffer of writing data
  * @param  num_write: the number of writing data
  * @retval none
  */
void flash_write(uint32_t write_addr, uint16_t *p_buffer, uint16_t num_write)
{
  uint32_t offset_addr;
  uint32_t sector_position;
  uint16_t sector_offset;
  uint16_t sector_remain;
  uint16_t i;

  flash_unlock();
  offset_addr = write_addr - FLASH_BASE;
  sector_position = offset_addr / SECTOR_SIZE;
  sector_offset = (offset_addr % SECTOR_SIZE) / 2;
  sector_remain = SECTOR_SIZE / 2 - sector_offset;
  if(num_write <= sector_remain)
    sector_remain = num_write;
  while(1)
  {
    flash_read(sector_position * SECTOR_SIZE + FLASH_BASE, flash_buf, SECTOR_SIZE / 2);
    for(i = 0; i < sector_remain; i++)
    {
      if(flash_buf[sector_offset + i] != 0xFFFF)
        break;
    }
    if(i < sector_remain)
    {
      flash_sector_erase(sector_position * SECTOR_SIZE + FLASH_BASE);
      for(i = 0; i < sector_remain; i++)
      {
        flash_buf[i + sector_offset] = p_buffer[i];
      }
      flash_write_nocheck(sector_position * SECTOR_SIZE + FLASH_BASE, flash_buf, SECTOR_SIZE / 2);
    }
    else
    {
      flash_write_nocheck(write_addr, p_buffer, sector_remain);
    }
    if(num_write == sector_remain)
      break;
    else
    {
      sector_position++;
      sector_offset = 0;
      p_buffer += sector_remain;
      write_addr += (sector_remain * 2);
      num_write -= sector_remain;
      if(num_write > (SECTOR_SIZE / 2))
        sector_remain = SECTOR_SIZE / 2;
      else
        sector_remain = num_write;
    }
  }
  flash_lock();
}



/**
  * @}
  */

3、主程序main.c

将闪存存储结构片1连续写入3000字节数据并读取出来放到buffer_read[TEST_BUFEER_SIZE]缓存

#define TEST_BUFEER_SIZE                 3000
#define TEST_FLASH_ADDRESS_START         (0x08000000 + 1024 * 512)

uint16_t buffer_write[TEST_BUFEER_SIZE];
uint16_t buffer_read[TEST_BUFEER_SIZE];

error_status buffer_compare(uint16_t* p_buffer1, uint16_t* p_buffer2, uint16_t buffer_length);

/**
  * @brief  compares two buffers.
  * @param  p_buffer1, p_buffer2: buffers to be compared.
  * @param  buffer_length: buffer's length
  * @retval SUCCESS: p_buffer1 identical to p_buffer2
  *         failed: p_buffer1 differs from p_buffer2
  */
error_status buffer_compare(uint16_t* p_buffer1, uint16_t* p_buffer2, uint16_t buffer_length)
{
  while(buffer_length--)
  {
    if(*p_buffer1 != *p_buffer2)
    {
      return ERROR;
    }
    p_buffer1++;
    p_buffer2++;
  }
  return SUCCESS;
}


/**
  * @brief  main function.
  * @param  none
  * @retval none
  */

int main(void)
{
    uint32_t index=0;
    system_clock_config();
    at32_board_init();
 /* fill buffer_write data to test */
    for(index = 0; index < TEST_BUFEER_SIZE; index++)
    {
        buffer_write[index] = index;
    }
    while(1)
    {
        /* write data to flash */
		flash_write(FLASH_ADDRESS_START, buffer_write, TEST_BUFEER_SIZE);
		/* read data from flash */
		flash_read(FLASH_ADDRESS_START, buffer_read, TEST_BUFEER_SIZE);
		 /* compare the buffer */
		if(buffer_compare(buffer_write, buffer_read, TEST_BUFEER_SIZE) == SUCCESS)
		{
			at32_led_on(LED2);
			at32_led_on(LED3);
			at32_led_on(LED4);
		}
		delay_sec(1);
 
      }



}

4. 存储器擦除

和stm32一样,AT32内部flash编程之前必须先进行擦除操作,主存储器有扇区擦除和整片擦除两种擦除方式。

1、扇区擦除步骤:

1检查FLASH_CR的LOCK是否解锁,如果没有则先解锁

2检查FLASH_SR寄存器中的BSY 位,确保当前未执行任何FLASH操作

3在FLASH_CR寄存器中,将SER位置1,并从主存储块的12个扇区中选择要擦除的扇区 (SNB)

4将FLASH_CR寄存器中的STRT位置1,触发擦除操作

5等待BSY位清零

经过以上五步,就可以擦除某个扇区。

2、批量擦除步骤

1检查FLASH_SR寄存器中的BSY 位,确保当前未执行任何FLASH操作

2在FLASH_CR寄存器中,将MER位置1 (STM32F407xx)其他板子不同

3将FLASH_CR寄存器中的STRT位置1,触发擦除操作

4等待BSY位清零

经过以上四步,就可以批量擦除扇区。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

章鱼哥嵌入式开发

坚持不易,你们的鼓励是我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>