【STM32学习2】存储器相关概念与操作

目录

前言

一、存储器类型介绍

1、易失性存储器

1)RAM(Random Access Memory)

2、非易失性存储器

1)ROM(Read Only Memory)

2)FLASH存储器

3)其它常见非易失性存储器

二、存储器映射与寄存器映射

二、volatile、const等关键字

三、内部FLASH操作

总结


前言

        描述STM32单片机的存储器构成以及相关的一些操作,比如向FLASH写入数据。


一、存储器类型介绍

        存储器是计算机系统的重要组成部分,用于存储程序代码以及数据。主要可以分为“易失性存储器”以及“非易失性存储器”两大类,前者在存储器断电后会丢失数据内容,而后者在断电后依旧可以保存数据。相比较下,易失性存储器的存取速度会更快。在大家熟悉的个人电脑(PC)中,易失性存储器的代表是内存,而非易失性存储器的代表是硬盘。而在嵌入式的领域乃至广大的计算机领域,二者的种类都非常多,以下分别加以介绍。

1、易失性存储器

1)RAM(Random Access Memory)

随机存储器,随机是指数据在读写时,所需时间与这段信息在存储器上的位置无关。早期RAM是为了与磁鼓这样的顺序读写存储器做区分,现在的RAM一词也被专用于指代计算机内存。根据RAM的存储机制,又分为DRAM(Dynamic RAM,动态随机存储器)以及SRAM(Static RAM,静态随机存储器)。

  • DRAM:采用电容电荷表示数据,有电荷表示1、无电荷表示0,由于时间一长电容会放电,所以DRAM需要定期刷新数据,为代表1的电容充满电,并为代表0的电容放电。这种需要“刷新”的特性也就是“动态”的名称由来。DRAM还可以细分为SDRAM(Synchronous DRAM,同步DRAM)、DDR SDARAM(Double Data Rate SDRAM,两倍速SDRAM)以及更高频率的DDRⅡ SDRAM、DDRⅢ SDRAM等。目前应用到个人电脑上的内存条大多是DRAM。

  • SRAM:采用锁存器存储数据,不需要定期刷新操作。与DRAM相比存取速度更快,但结构更加复杂、集成度较低、生产成本较高。STM32一般型号自带内部SRAM,也只支持扩展SRAM。

2、非易失性存储器

1)ROM(Read Only Memory)

本意只读存储器,现在随着技术的发展,ROM也能进行写入操作,所以ROM可以指代大多数的非易失性存储器。ROM与RAM的英文缩写十分类似,但其实是个巧合,英文本意并没有太大的关系。

  • MASK ROM:掩膜ROM也就是ROM的鼻祖,存储的数据是在出厂时固化的,不可再修改,所以为只读存储器,优点是成本低。
  • OTPROM(One Time Programmable ROM):一次可编程ROM,顾名思义就是只能进行一次写操作的ROM,一般用来存储密钥之类的信息。
  • EPROM(Erasable Programmable ROM):可重复擦写ROM,这种存储器采用紫外线照射芯片内部的方式擦除数据,只能整片擦除,擦除和写入需要专用设备。现在基本被EEPROM取代。
  • EEPROM(Electrically Erasable Programmable ROM):电可重复擦除存储器。通过电路控制进行数据写入与擦除,不再需要外部设备,并且可以以字节为单位修改数据,不再需要整片擦除。

2)FLASH存储器

FLASH又称为闪存,是舛冈富士雄博士1980年申请了一个叫做simultaneously erasable EEPROM的专利,可以看作一种特殊的EEPROM,但它的容量比一般的EEPROM大很多,擦除时以多个字节(扇区)为单位。主要分为NOR FLASH与NAND FLASH,前者地址线与数据线分开,一般存储代码指令,比如单片机中的程序存储空间;而后者共用地址线与数据线,必须以“块”为单位读写,成本较低,一般用于大数据量的存储场合,比如SD卡、U盘、固态硬盘。

3)其它常见非易失性存储器

  • 光盘(Optical disc):1965年由美国发明家詹姆斯·拉塞尔发明,当时所存储的格式仍以模拟信号(Analog)为主。它是用激光扫描的记录和读出方式保存信息的一种介质。光盘经过许多代的发展产生了VCD、DVD、BD等类型,当前主要在音频与视频领域有所应用。
  • 机械硬盘(Hard Disk Drive,HDD):在平整的磁性表面存储和检索数字数据,数据通过离磁性表面很近的磁头由电磁流来改变极性的方式被写入到磁盘上,数据可以通过盘片被读取,原理是磁头经过盘片的上方时盘片本身的磁场导致读取线圈中电气信号改变。前面还提到一种固态硬盘(Solid-state drive,SSD),是目前主流的硬盘,大多采用NAND FLASH,少数采用SDRAM。

  • 软盘(Floppy Disk):是一种碟盘存储器,主要部分是一张薄软的磁存储介质盘片,盘片封装在矩形塑料壳中,内衬有用于清理灰尘的纤维织物。读写软盘需要借助软盘驱动器。在20世纪为主要的存储器之一,但在进入21世纪后逐渐过时并被淘汰。

bd2cb4637912727f02af66052e1091cb.jpeg

二、存储器映射与寄存器映射

        STM32内部的存储器包括SRAM与FLASH,前者为数据存储器,后者为程序存储器。这两个存储器负责存储信息,本身不具有地址信息。所以STM32给存储器都分配了地址,这个过程就叫存储器映射。以STM32F1系列为例,芯片里有4GB的地址空间分配给了SRAM、FLASH以及众多的外设与其他寄存器。4GB不代表能够存储这么多的数据,其中有的地址并没有指向存储器或者某个外设寄存器。下表示意了4GB的空间(被分为了8块,每块512MB)是如何分配的。

         有了存储器映射后,我们便可通过C语言指针操作来访问各个地址,比如令GPIOB端口全部输出高电平的代码:

// GPIOB端口全部输出高电平
*(uint32_t*)(0x40010C0C) = 0xFF

 可是在实际开发过程中,每次都通过这种直接访问地址的方式繁琐并且容易记错,所以STM32官方根据每个单元的功能,给各个地址都取了一个别名,这个别名就是我们常说的寄存器,而这个取名的过程就叫寄存器映射。

        比如上面的GPIO端口控制代码,如果事先做如下定义:

#define  GPIOB_ODR  *(uint32_t*)(0x40010C0C)

实际编程时,我们就只需要编写以下代码即可:

GPIOB_ODR = 0xFF

 有了寄存器映射,我们不再需要知道具体的寄存器地址,只用知道其名称即可。

二、volatile、const等关键字

  • volatile:本意不稳定的、挥发性的,引申为易变的。在定义变量时加上volatile关键字表示每次使用该变量时,都要从内存(SRAM或FLASH)里取出该值。若不加该关键字,编译器可能对变量进行优化,不一定每次都从内存中得到变量值。

volatile关键字有如下应用场景:

1、中断服务程序中修改的供其它程序检测的变量需要加volatile

2、多任务环境下各任务间共享的标志应该加volatile

3、存储器映射的硬件寄存器也要加volatile说明,因为每次对它的读写都可能有不同意义

  • const:意为只读变量,编译时,如果尝试修改只读变量,则编译器提示出错,能后防止误修改。若定义全局变量时加上const关键字,会将此变量保存在程序存储器(FLASH)中。

 cortex内核还提供了一些宏定义重新定义了volatile与const关键字

#ifdef __cplusplus
  #define   __I     volatile             /*!< Defines 'read only' permissions */
#else
  #define   __I     volatile const       /*!< Defines 'read only' permissions */
#endif
#define     __O     volatile             /*!< Defines 'write only' permissions */
#define     __IO    volatile             /*!< Defines 'read / write' permissions */

/* following defines should be used for structure members */
#define     __IM     volatile const      /*! Defines 'read only' structure member permissions */
#define     __OM     volatile            /*! Defines 'write only' structure member permissions */
#define     __IOM    volatile            /*! Defines 'read / write' structure member permissions */
  • __I:输入口,在C环境下指volatile const。既然是输入,那么寄存器的值就随时会外部修改,那就不能进行优化(volatile),每次都要重新从寄存器中读取。也不能自行进行修改,即只读(const),不然就是输出了。
  • __O:输出口。可以进行修改(不加const),但不能进行优化(volatile),不然如果连续两次输出相同值,编译器认为没改变,优化后就认为后面一次输出等于上一次输出。假如外部在两次输出之间修改了值,优化后就会导致输出不对。
  • __IO:输入输出口。同时具有输入与输出功能,所以要可以修改(不加const)但又不能被编译器优化(volatile)。

后面__IM、__OM、__IOM用在结构体成员上,应用较少。这些宏定义前面加两条下划线是为了避免命名冲突,因为这些名字都很短。

三、内部FLASH操作

        STM32的内部FLASH一般用于存储代码,但由于其掉电数据不丢失的特性,如果在存储了程序后还有剩余空间,我们也可以用其存储一些需要掉电保存的数据。

        为了防止误操作修改应用程序,在对内部FLASH写入之前需要先进行解锁操作。在写入完成后要重新上锁。另外在写入数据之前,要先按页(扇区)擦除原本数据,一页也是FLASH最小能擦除的单位,在STM32F1系列为2kb。HAL库给我们提供了丰富的操作FLASH的函数,大大简化了代码。

        以STM32F03VET6为例,FLASH内存大小为512kb,每页2kb,地址为0x0800 0000 - 0x0808 0000。我们尝试在地址0x0800 8000 - 0x0800 C000之间连续写入数据,首先定义写入的起始地址、结束地址以及每页的大小(2kb,0x800):

#define WRITE_START_ADDR ((uint32_t)0x08008000)
#define WRITE_END_ADDR ((uint32_t)0x0800C000)
#define FLASH_PAGE_SIZE 0x800;

 对FLASH执行操作的函数体如下:

int InternalFlash_Test(void)
{
	uint32_t SECTORerror = 0;
	uint32_t NbrOfPage = 0x00;
	uint32_t Address = 0x00;
	// 定义待写入数据DATA_32
	uint32_t DATA_32 = 0x3210ABCD;
	uint32_t STATE = 1;

	// 定义擦除结构体
	static FLASH_EraseInitTypeDef EraseInitStruct;

	// FLASH解锁
	HAL_FLASH_Unlock();
	// 待操作页数
	NbrOfPage = (WRITE_END_ADDR - WRITE_START_ADDR) / FLASH_PAGE_SIZE;
	// 设置擦除类型(按页擦除)、擦除页数、起始地址
	EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
	EraseInitStruct.NbPages = NbrOfPage;
	EraseInitStruct.PageAddress = WRITE_START_ADDR;
	// 擦除,并判断完成状态
	if(HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORerror) != HAL_OK){
	  return -1;
	}

	// Address为当前操作地址
	Address = WRITE_START_ADDR;
	while(Address < WRITE_END_ADDR){
		// 依次写入数据,每次写入32位(4b),地址位移4b
		if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, DATA_32) == HAL_OK){
			Address += 4;
		}
		else{
			return -1;
		}
	}
	
	// FLASH上锁
	HAL_FLASH_Lock();

	// 检查数据是否正确
	Address = WRITE_START_ADDR;
	while((Address < WRITE_END_ADDR) && (STATE != 0)){
		if((*(__IO uint32_t*)Address) != DATA_32){
			STATE = 0;
		}
		Address += 4;
	}
	return STATE;
}

操作的步骤大致为:

  1. FLASH解锁,使用到的函数为HAL_FLASH_Unlock。
  2. 按页擦除,首先通过FLASH_EraseInitTypeDef定义擦除结构体,设置擦除的方式、页数以及起始地址,然后通过HAL_FLASHx_Erase实现擦除。
  3.  使用函数HAL_FLASH_Program写入数据。
  4. FLASH上锁,使用到的函数为HAL_FLASH_Lock。

总结

        介绍了存储器的类型,STM32中的存储器映射以及寄存器映射,另外介绍了关键字volatile、const以及如何向内部FLASH中写入数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值