STM8的储存器

在《深入浅出STM8单片机入门、进阶与应用实例》一书中本章节排列在前,但因为此部分内容较为底层且与其他章节关系不大,我将其移至末尾介绍,作为进入汇编的预备

STM8中的储存器

STM8储存器资源概述

  • 不同系列的STM8储存器资源配置

    对于不同的项目要求,需要不同的储存器资源配置,比如要在单片机上运行RTOS,那么就需要单片机有比较大的RAM,如果需要在断电后储存较多参数,那就需要单片机有比较大的EEPROM

    按储存器的结构和配置可以将STM8分为三种产品系列:高密度/中密度/低密度

  • 不同储存器资源配置的特点

    不同系列的储存器配置划分,其储存器资源有以下三个主要的区别

    • 储存器的组成:STM8的储存器资源配置随型号不同而变化,比如低密度的产品就没有boot ROM这个结构

    • 储存器的容量:不同系列储存器容量差别很大,最直观地体现在RAM容量和Flash容量

    • 储存器的组织结构:主要表现为页大小、块大小、容量大小等方面,后文介绍

  • STM8储存器资源的结构概述

    以高密度产品为例,介绍储存器的结构,如图所示

    image

    其中左侧编号即对应储存器区域的起始地址,可见STM8S中不同类型的各种资源都是连在一起的

    这是因为STM8S在设计时为了读写指令和寻址的方便,将RAM、EEPROM、boot ROM、Flash ROM以及相关的寄存器全部统一编址在内存空间中

随机读写RAM

  • RAM简介

    RAM单元具有随机存取、读写速度快、断电后数据不能保留的特点

    因此RAM是一个运算处理和CPU数据交互的临时场合,处理结束CPU就会回收相应的内存

  • RAM地址

    RAM的起始地址在内存空间的最低位(0x00 0000),而因为各型号RAM容量有差别,因此结束地址各不相同,具体可查阅数据手册

堆栈区

  • 堆栈简介

    堆栈是一个特殊的储存区,其作用是暂存数据和地址,通常用于保护断点和现场,例如说:一个函数调用了另一个函数,那么调用前的变量或数据就要放入堆栈中,被调用的函数执行完毕后又把那些数据取出来继续运算或传递

  • 堆栈的FILO特点

    堆栈遵循FILO(first in last out),即先进入堆栈的数据在最后才出栈

程序FlashROM

  • Flash简介

    Flash ROM是储存器中用于存放要运行程序的一个部分(运行时加载到RAM中),其中还包含了32级中断向量和UBC(User Boot Code)这两个特殊的区域,它们占据Flash的一部分空间

  • Flash地址

    Flash的起始地址是008000H,32级中断向量占据的空间是固定的,为008000H-00807FH,再之后从008080H开始为UBC区,而UBC区由选项字节配置是否开启及其大小;剩下的区域都是主程序区域

    image

  • 页page与块block

    为了调节UBC和剩下的FlashROM主程序大小,STM8引入了页与块的概念,将整个FlashROM分成多页或块,每一页或每一块包含了一定的字节,不同系列的STM8其页或块的大小是不同的

    image

    由表可见:小容量的STM8S单片机系列有8K的Flash,分128页,每页和每块都是64B;而中容量和大容量每页为512B,每块是128B

  • UBC用户启动区域

    其有无和大小都由用户配置选项字节OPT1决定

    具体通过配置UBC[7:0]实现,当UBC[7:0]=0x01时UBC为1kB(对高密度产品来说是第0页和第1页),最多可配置至128kB(也是对高密度产品,具体要查阅对应型号数据手册),如果这个值为0则表示不定义UBC

    UBC包含有复位和中断向量表,可以储存IAP和通信程序

    因为其重要的功能,所以这个区域总是写保护的

  • 32级中断向量

    也即中断一章中介绍的中断向量表,地址自0x8000至0x807F,不再赘述

数据EEPROM

  • EEPROM简介

    EEPROM全称电可擦除可编程只读存储器,其最大的特点是能断电后长时间保存数据,因此用于储存具体项目所需的数据,一般情况下这个区域是写保护的,避免数据被无意破坏

  • EEPROM地址

    image

    EEPROM的起始地址是004000H,结束地址根据容量不同各不相同

    EEPROM中的页和块的大小和FlashROM中的一致,例如小容量STM8S有640B的EEPROM,每页也是64B,共10页

选项字节

  • 选项字节简介

    EEPROM中有一页(64B或512B)用于储存选项字节,选项字节用于配置硬件特性和储存器保护状态,具体见下表

    image

  • 选项字节配置

    选项字节可以在SWIM/ICP模式或IAP模式中修改,在修改时要保证FLASH_CR2的OPT位为1以及FLASH_NCR2的NOPT位为0

    具体软件操作方法见基础知识一章

端口及外设寄存器

  • 寄存器简介

    端口即单片机与外界交互的通道,外设是单片机实现各种功能的单元,端口和外设的控制是通过各种功能寄存器实现的,在之前的章节中,我们就在通过操作寄存器来配置单片机功能

  • 寄存器地址

    端口及外设的寄存器存放在内存空间的0x005000H-0x0057FFH之间,在我们所写程序开头调用的头文件iostm8s105c6.h(具体头文件根据型号不同而不同)中,已经定义了各个寄存器地址,比如:

    __IO_REG8_BIT(PA_ODR,0x5000,__READ_WRITE,__BITS_PA_ODR);
    //以此类推,各个寄存器都和对应的物理地址联系起来,就好比一个城市名和其经纬度
    //当我们配置寄存器时,实际上是在直接写对应的内存
    

CPU/SWIM/Debug/ITC寄存器

  • 寄存器介绍

    与上面控制端口和外设的寄存器相比,这些寄存器处理的是单片机的核心事务:CPU控制和运算状态、单线调试接口SWIM配置、DM调试模块、ITC中断等等不及时处理就会影响系统工作的事务

  • 寄存器地址

    这些核心事务的寄存器放在0x007F00-0x007FFF中,同样在单片机头文件里有定义

引导启动BootROM

  • 引导启动ROM简介

    这是一个特殊区域:我们一般使用ST-LINK连接SWIM接口来烧录程序,但如果借助这个区域,就能在不使用专用硬件的情况下,通过UART、SPI、CAN这些接口把程序代码、数据、选项字节和中断向量表下载到内部的Flash和EEPROM储存器中

    但是并非所有的STM8都具备这个区域,而该区域的大小在不同型号的STM8中也不尽相同

  • Boot loader

    boot loader 简称BL,是单片机上电后,在进入Flash ROM之前,运行在Boot ROM中的一段小程序,这段程序的作用是初始化硬件设备,建立内存的空间映射表,建立适当的系统软硬件环境,为最终调用片内相关资源作准备


储存器功能寄存器

控制寄存器

  • Flash控制寄存器1 FLASH_CR1

    配置各种电源模式下Flash是否掉电,启动中断使能,编程时间

image

  • Flash控制寄存器2 FLASH_CR2

    控制寄存器2与其互补寄存器主要用于控制和确定Flash储存器的编程方式

    image

  • Flash控制寄存器2互补寄存器 FLASH_NCR2

    image

保护寄存器

  • Flash保护寄存器 FLASH_FPR

    保护寄存器及其互补保护寄存器主要用于保护用户启动代码UBC区域内容

    其位5:0为用户启动代码保护位WPB[5:0],用以指示用户启动代码UBC的大小,其值在启动时由UBC选项字节装载

  • Flash保护寄存器互补寄存器 FLASH_NFPR

    同FLASH_FPR,其位5:0为用户启动代码保护位NWPB[5:0],同样用以指示用户启动代码大小,其值为NUBC选项字节的对应字节

  • Flash程序储存器解保护寄存器 FLASH_PUKR

    其位7:0为主程序储存器解密密钥PUK[7:0]

    在单片机上电复位后,Flash程序储存器默认是被保护的,在需要进行改写时,要向此储存器写入0x56,再写入0xAE才能解除保护状态

  • DATA EEPROM解保护寄存器 FLASH_DUKR

    同上,EEPROM储存器默认也是被保护的,需要改写时,则要向此储存器先写入0xAE,再写入0x56

状态寄存器

  • Flash状态寄存器 FLAHS_IAPSR

    image

储存器的编程方法

更新存储器数据的方式概述

  • 要更新储存器中的数据,有多种方法,首先分为IAP和ICP,然后又可分字节编程/字编程/块编程,从中还能引出标准/快速编程方式,有些型号支持读同时写功能RWW,接下来依次介绍

ICP/IAP

  • ICP基于电路编程

    in circuit programing,该方法会从头到尾更新整个储存器的内容

    使用SWIM接口(SWIM的含义即单线接口模块)把用户的程序装载到微控制器中,这也就是我们一直所使用的ST-LINK把程序从电脑烧录进单片机的原理

  • IAP基于程序编程

    in applicating programing,该方法允许在应用程序中对Flash程序储存器的内容重新编程

    该编程方法不需要SWIM接口,而是使用STM8支持的任意通信接口来下载需要烧录进储存器的数据

    如果要使用IAP,必须通过ICP方式对Flash程序储存器预先编程,利用单片机中的程序自己对自己进行编程更新

标准/快速编程/RWW

  • 标准编程

    如果欲写入的单元并不是空白的,则应该先擦除单元的内容再写入,这样操作的时间数就是擦除时间+写入时间

  • 快速编程

    如果要写入的单元本身就是空白的,就没有必要再进行擦除而可以直接写入,这样所用时间就更短

  • RWW

    部分STM8单片机支持RWW特性,即read while write,拥有此功能的单片机允许用户在执行程序和读程序储存器的同时对DATA EEPROM区域进行写操作,这样执行的时间进一步被缩短(但是不能反过来在写程序储存器时对DATA EEPTOM进行读操作)

    查询是否有RWW功能:一般在对应型号的单片机数据手册的Flash program and data EEPROM memory一节,或者直接在数据手册搜索Read while write,搜到了就证明支持

字节编程

  • 字节编程

    应用程序直接向目标地址写入单字节数据,以单个字节为单位逐个地址编程

    主程序储存器、数据EEPROM、选项字节都支持该方式,注意不同区域使用字节编程的步骤和流程是不同的

  • 字节编程的结束检测方式

    有两种方式来检测字节编程结束:查询法和中断法

    • 查询法:不断地判断标志位FLASH_IAPSR_EOP位,其为1表示编程结束
    • 中断法:启用中断功能,将FLASH_CR1_IE位置1
  • 主程序储存器区域下的字节编程配置流程

    在主程序储存器中执行字节编程操作时,CPU会停止应用程序的运行,所用采样查询方式比较合理,步骤如下:

    1. 禁止中断功能,即配置FLASH_CR1_IE=0,采用查询方式
    2. 解锁主程序区:向Flash程序储存器解保护寄存器FLASH_PUKR先写0x56再写0xAE(此处输入的数值为解锁用的硬件密钥,后文介绍),操作之后判断FLASH_IAPSR_PUL位是否为1,当其为1时才说明解锁成功
    3. 向目标地址写入单字节数据,若需要擦除地址数据,写入0x00即可
    4. 查询FLASH_IAPSR_EOP位,判断编程是否结束
    5. 查询FLASH_IAPSR的WP_PG_DIS位是否为0,若不为0说明发生了错误
    6. 按照实际需要对数据进行校验,再软件清除FLASH_IAPSR的PUL位,重新对主程序区域写保护
  • 数据EEPROM区域下的字节编程配置流程

    在数据EEPROM区域中执行字节编程操作时,要先判断单片机是否支持RWW读同时写功能,如果具备,那么在IAP模式下应用程序不停止运行,字节编程利用RWW功能进行操作,不具备的话就要停止运行,依次是否具备RWW决定了选择中断还是查询法

    1. 按需配置使用中断或查询法

    2. 解锁EEPROM区,向DATA EEPROM解保护寄存器FLASH_DUKR先写入0xAE再写入0x56(不仅寄存器不同,写入顺序与解锁FLASH相反),操作完成后检测FLASH_IAPSR的DUL位,为1时解锁成功

    3. 向目标地址写入单字节数据,若需要擦除地址数据,写入0x00即可

    4. 查询FLASH_IAPSR_EOP位,判断编程是否结束

    5. 查询FLASH_IAPSR的WP_PG_DIS位是否为0,若不为0说明发生了错误

    6. 按照实际需要对数据进行校验,再软件清除FLASH_IAPSR的DUL位,重新对主程序区域写保护

  • 选项字节的字节编程配置流程

    与上文流程相似,细节有所不同:需要配置FLASH_CR2的OPT位为1以及FLASH_NCR2的OPT位为0,以运行对选项字节进行写操作

  • 字节编程的用时

    根据目标地址初始化内容的不同(可能空也可能非空),编程时间不同(标准/快速编程),如果需要获得固定的编程时间,可以强制使用标准编程,无论空不空统统先擦除再写入,配置方法是FLASH_CR1的FIX位置1

字编程

  • 字的概念

    字编程和字节编程几乎一样,只是写入的单位容量变大了

    一个字word等于4个字节Byte(一个字有几个字节具体取决于系统总线宽度,32位系统中1个字为4字节,64位系统则1个字有8个字节),这样可以缩短编程时间

  • 字编程配置流程

    与字节编程的流程类似类似,细节有所不同:

    1. 需要配置FLASH_CR2的WPRG位为1使能字编程操作
    2. 同时配置FLASH_NCR2的NWPRG位为0
    3. 然后将欲编程的字内容从目标地址的首地址开始装载,再写入4个字节的内容即可

块编程

  • 块的概念

    在块编程中写入的单位容量进一步变大,(具体每个块有多少字节取决于单片机的密度类型),整个块的编程在一个编程周期内就可完成,写入效率最高;

    主程序储存器区域和数据EEPROM区域可以执行块操作;

    注意:在主程序储存器编程时要求用于块编程的程序代码必须全部在RAM中执行;

    在数据EEPROM区域中使用块编程方式时还要考虑器件是否RWW,如果有则数据EEPROM块操作可以在主程序储存器中执行,然而数据装载阶段依旧必须在RAM中执行,对于没有RWW功能的器件则代码必须全部在RAM中执行

  • 标准块编程

    同标准编程和快速编程的区别,标准块编程中整个块在编程之前会被自动擦除

    1. 需要首先配置FLASH_CR2_PRG位为1,使能标准块编程
    2. 同时配置FLASH_NCR2_NFPRG位为0
    3. 然后向主程序储存器或数据EEPROM区域的目标地址依次写入要编程的数据
    4. 最后利用查询法或者中断法检测编程是否结束
  • 快速块编程

    快速块编程不擦除储存器内容,直接对块编程,因此编程速度是标准块编程的两倍,步骤与标准块编程一致

    但是需要注意在执行快速块编程之前如果目标地址中的内容非空,则不能保证写入的数据无误

  • 块擦除

    允许擦除整个块

    1. FLASH_CR2的ERASE位为1,使能块擦除

    2. 同时配置FLASH_NCR2的NERASE位为0

    3. 然后同时对块所有的字(4个字节)写入0来擦除整个块

      字的起始地址必须以0、4、8、C作为结尾

    4. 最后再利用查询法或中断法来检测编程是否结束

读/写保护与控制

ROP储存器读出保护

  • ROP简介

    STM8系列单片机具备储存器的读出保护功能Read-out protection,即ROP

    该功能可以阻止在ICP模式和调试模式下用户对Flash程序储存器和数据EEPROM储存器数据的读出操作,而且一旦使能ROP后,任何尝试改变其状态的操作都会将Flash、UBC、EEPROM以及选项字节中的内容全部擦除,从而最大限度实现了数据保密性

  • 使能ROP

    选项字节的ROP字节被编程为0xAA,就会开启读出保护

MASS储存器存取安全保障系统

  • MASS简介

    ROP是读出保护,而对应有写入的保护以防止软件故障对储存器意外擦写,即write protection,WP功能,这个功能由MASS,即memory access security system执行

  • MASS保护机制

    在进行IAP编程前,要解除MASS的写保护状态,需要通过使用硬件密钥,也就是前文字节编程流程中提到的,向Flash程序储存器解保护寄存器FLASH_PUKR先写0x56,再写0xAE,这就是两个硬件密钥(解锁EEPROM区则要配置FLASH_DUKR寄存器,且写入硬件密钥的顺序相反)

    解锁EEPROM区,向DATA EEPROM解保护寄存器FLASH_DUKR先写入0xAE再写入0x56,操作完成后检测FLASH_IAPSR的DUL位,为1时解锁成功

    操作之后判断FLASH_IAPSR_PUL位是否为1,当其为1时才说明解锁成功;DUL位,为1时解锁成功

  • 对主程序储存器的写操作

    使用硬件密钥解锁的流程

    1. 向程序储存器解保护寄存器FLASH_PUKR写入第一个八位密钥0x56,当该密钥首次写入时,数据总线上的值没有直接锁存到寄存器中,而是和第一个硬件密钥0x56比较
    2. 如果第一个密钥输入错误,FLASH_PUKR寄存器会被一直锁住,除非触发一次复位操作,因此写入只有一次机会
    3. 如果第一个密钥输入正确,会重复同样的流程来判断第二个密钥0xAE,如果第二个密钥输入也会锁定FLASH_PUKR寄存器
    4. 当两个密钥配置正确,主程序写保护会被成功解除,同时状态寄存器FLASH_IAPSR的PUL位会被置1,表示主程序储存器已被解锁
    5. 解锁完毕就可以写入内容,编程结束后要重新为其配置写保护,将FLASH_IAPSR的PUL位重新置零
  • 对数据EEPROM区域的写保护

    解锁步骤与上文主程序储存器类似,有三点不同

    • 要写入的是DATA EEPROM解保护寄存器FLASH_DUKR
    • 写入顺序相反,第一个密钥是0xAE,第二个密钥才是0x56
    • 状态寄存器FLASH_IAPSR中判断保护状态的标志位为DUL

使用EEPROM

实验设计

  • 实验概述

    做一个关于EEPROM区域的读写实验,利用EEPROM断电数据保留的特性来储存信息,这个信息借助数码管表达

  • 实验原理

    设定一个数值自动+1(到9时变回0),而这个数值在显示到数码管的同时保存到EEPROM中,然后通过断电操作验证系统是否保存了断电前的计数状态值

    单片机上电后读取EEPROM单元目标地址中的数据,判断读出的数据是否为0x00,如果是就表示这是第一次断电(或上一次刚好循环到0),读出的不为0x00就表示这个数值是上一次保存下来的数值,将该值显示并送给自增变量让其加1

代码实现

  • 指定目标地址

    实验的重点是:怎样指定数据EEPROM单元的目标地址并写入数据

    指定地址的代码:u8 disnum_EEPROM @0x4000;

    • u8是数据类型unsigned char,详见GPIO端口“配置使用的数据类型”一节
    • 0x4000是EEPROM的起始地址,这一行代码的作用是让disnum_EEPROM指向地址0x4000,实际上和前文寄存器的定义原理相同,相当于给某个经纬度上的区域命名为一个城市
  • 解锁函数

    在写入数据之前,要编写解锁EEPROM的函数用于向MASS输入两个硬件密钥并检查解锁状态,还要处理解锁失败的情况

    u8 unlock_EEPROM(void)
    {
    	FLASH_DUKR = 0xAE;
    	FLASH_DUKR = 0x56;
    	//之后还要判断DUL位看解锁是否成功
    	if(FLASH_IAPSR & 0x08)
    		return 0;
    	else
    		return 1;//解锁失败
    }
    
  • 主程序
    //延时函数和数码管显示在本合集流水灯和数码管章节中已介绍,不再赘述
    u8 disnum_EEPROM @0x4000;//指定EEPROM地址
    u8 unlock_EEPROM(void);//解锁函数原型
    unsigned char num[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xa0,0x83,0xc6,0xa1,0x86,0x8e};
    //段选码,由于只显示一位数字,因此不需要使用动态刷新数码管函数
    #define LED PB_OCR//取决与数码管的段选型号连接到哪组GPIO上
    
    void main(void)
    {
    	u8 i =0;//自增控制变量
    	Digit_GPIO_Init();//配置连接数码管的引脚
    	while(unlock_EEPROM());//等待解锁成功
    	if(disnum_EEPROM!=0)//如果EEPROM首地址装载数值不为0
    	{
    		LED=num[disnum_EEPROM];//显示EEPROM中储存的数值
    		i=disnum_EEPROM;
    		delay(200);
    	}
    	else
    		LED=num[i];
    	while(1)
    	{
    		i=(i+1)%1;//i自增,限定i取值为0~9
    		LED=num[i];//把0~9放到数码管上显示
    		disnum_EEPROM=i;//把0~9数值写入EEPROM首地址
    		while((FLASH_IAPSR&0x40)==0);//写入成功
    		delay(200);//延时停留
    	}
    }
    
  • 实验现象

    若出现这样的现象,说明实验成功:

    首次上电运行且不产生任何干预的情况下,数码管显示数字从0到9循环

    如果在其间突然断电,再次上电时不会重新开始从0计数,而是显示断电前的数字

posted on   无术师  阅读(12)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?

统计

点击右上角即可分享
微信分享提示