中颖51芯片学习5. 类EEPROM操作
- 一、SH79F9476 Flash存储空间
- 1. 特性
- 2. 分区
- 3. OP_EEPROMSIZE选项设置
- 3. 编程接口
- 4. 代码保护控制模式简介
- (1)**代码保护模式0:**
- (2)**代码保护模式1:**
- (3)**代码保护模式2:**
- (4)**代码保护模式3:**
- 二、扇区自编程(SSP)功能
- 1. SSP 编程流程
- (1)代码/数据编程
- (2)扇区擦除
- 2. 寄存器介绍
- (1)编程用地址选择寄存器
- (2)擦除/编程用扇区选择寄存器
- (3)编程用地址偏移寄存器
- (4)编程用数据寄存器
- (5)SSP型选择寄存器
- (6)SSP流程控制寄存器1
- (7) SSP流程控制寄存器2
- (8)SSP流程控制寄存器3
- (9)SSP流程控制寄存器4
- (10)FLASHCON
- 三、补充知识 C51的存储空间
- 1. C51的RAM空间
- 四、代码实现
- 1. C语言访问存储区的方法
- 2. 读取可读识别码
- eeprom_random_id.c
- main.c
- 运行示例:
- 3. 扇区删除
- 2. 字节读
- 3. 字节编程
一、SH79F9476 Flash存储空间
1. 特性
SH79F9476 集成了64KB(128x512Byte) Flash 存储器,有以下特性:
- 支持在线编程(ICP)操作,包括写入、读取、擦除;
- 支持整体和扇区擦除、编程操作;
- 支持代码保护控制模式编程,
- 程序区域的编程/擦除次数至少为10,000 次;
- 类 EEPROM 区域的编程/擦除次数至少为100,000 次
- 数据保存年限至少为10 年。
2. 分区
SH79F9476 Flash分成两个区:
- 64K可编程Flash,支持ICP、SSP
- 4096字节类EEPROM区,每个扇区512字节 , 最多8个扇区。
EEPROM与程序存储区共享空间共享 , 即EEPROM与程序存储区总和为64K,如下图所示:
可以通过 OP_EEPROMSIZE配置EEPROM 大小。
3. OP_EEPROMSIZE选项设置
- 0000:8 X 512Bytes(默认,即4K=1000H)
- 0001:7 X 512Bytes
- 0010:6 X 512Bytes
- 0011:5 X 512Bytes
- 0100:4 X 512Bytes
- 0101:3 X 512Bytes
- 0110:2 X 512Bytes
- 0111:1 X 512Bytes
- 1000:0 Bytes
- 其余:0 Bytes
3. 编程接口
提供了ICP模式和SSP模式两种编程接口。
- ICP模式,通过Flash编程器对存储器擦、读、写。
- SSP模式适用于用户程序代码运行在Program Memory中,对Flash存储器进行编程操作。
ICP模式同时可用于对MCU进行仿真调试,SH79F9476 支持单线模式(3线接口编程器)和四线模式(使用4个JTAG引脚)。接线如下图所示:
3线接口
四线模式
本文重点是扇区自编程(SSP)功能 ,包括下一节的代码保护并非本文重点。
4. 代码保护控制模式简介
代码保护模式是一种微控制器提供的安全功能,旨在保护程序代码不受未经授权的访问和修改。中颖 SH79F9476 提供了四种代码保护模式,分别是代码保护模式0、代码保护模式1、代码保护模式2和代码保护模式3。
Flash编程器在ICP模式设置相应的保护位,以进入所需的保护模式。SSP模式不支持代码保护控制模式编程。
(1)代码保护模式0:
- 允许/禁止任何编程器的写入/读取操作,但不包括整体擦除。
- 在该模式下,可以选择允许或禁止对芯片的编程操作,以防止未经授权的程序代码修改。
(2)代码保护模式1:
- 允许/禁止在其它扇区中通过 MOVC 指令进行读取操作。
- 在该模式下,可以限制在其他扇区中读取程序代码的操作,以加强对程序代码的保护。
(3)代码保护模式2:
- SSP 功能允许/禁止控制,选中后,芯片对 code 区域的 SSP 操作(擦除或写入,不包括读取)是禁止的,但不会禁止芯片对类 EEPROM 的操作。
- 这种模式下,可以限制对代码区域的 SSP(扇区自编程)操作,从而进一步加强代码的安全性。
(4)代码保护模式3:
- 客户密码保护,可由客户自设密码,密码由6字节组成。如果将此功能开启,表示在烧写器或仿真器工具对芯片做任何操作(读出,写入,擦除或仿真)之前先输入这个密码,如果这个密码正确,则芯片允许烧写器或仿真器工具进行相应的操作,反之则报错,无法执行相应操作。
- 在该模式下,可以设置一个客户自定义的密码,只有输入正确的密码才能执行对芯片的编程、读取、擦除或仿真等操作。
二、扇区自编程(SSP)功能
SH79F9476支持SSP功能。如果所选扇区未被保护,用户代码可以对任何扇区执行编程操作。
一旦该扇区被编程,必须在擦除后才能再次编程。
1. SSP 编程流程
(1)代码/数据编程
- 关闭中断;
- 根据地址设置XPAGE,IB_OFFSET;
- 如果需要写数据,设置IB_DATA;
- 按照顺序设置IB_CON1 - 5;
- 添加4个NOP指令;
- 开始编程,CPU将进入IDLE模式;烧写完成后自动退出IDLE模式;
- 如需继续写入数据,跳转至第2步;
- XPAGE寄存器清0,恢复中断设置。
(2)扇区擦除
- 关闭中断;
- 按相应的扇区设置XPAGE;
- 按照顺序设置IB_CON1 - 5;
- 添加4个NOP指令;
- 开始擦除,CPU将进入IDLE模式;擦除完成后自动退出IDLE模式;
- 如需要继续擦除数据,跳转至第2步;
- XPAGE寄存器清0,恢复中断设置。
需要注意的几点:
- 在对类EEPROM进行擦除、写或读之前,应首先将FLASHCON寄存器的最低位FAC位置1。
- 类EEPROM的扇区为512字节,而不是1024字节。
- 系统时钟不得低于 200kHz 以确保 FLASH 的正常编程。
- 当不需对类 EEPROM 操作时,必须将 FAC 位清 0 。
2. 寄存器介绍
(1)编程用地址选择寄存器
地址: F7H Bank0
符号:XPAGE
对于程序存储区,一个扇区为 512 字节 。 寄存器定义如下
(2)擦除/编程用扇区选择寄存器
地址: F7H Bank0
符号:XPAGE
对于类 EEPROM 存储区,一个扇区为 512 字节,最大 8 个扇区 。 寄存器定义如下:
需要将 FLASHCON 寄存器中的 FAC 位置 1 。
(3)编程用地址偏移寄存器
地址:FBH, Bank0
符号:IB_OFFSET
(4)编程用数据寄存器
地址:FCH, Bank0
符号:IB_DATA
(5)SSP型选择寄存器
地址:F2H, Bank0
符号:IB_CON1
(6)SSP流程控制寄存器1
地址:F3H, Bank0
符号:IB_CON2
(7) SSP流程控制寄存器2
地址:F4H, Bank0
符号:IB_CON3
(8)SSP流程控制寄存器3
地址:F5H, Bank0
符号:IB_CON4
(9)SSP流程控制寄存器4
地址:F6H, Bank0
符号:IB_CON5
(10)FLASHCON
A7H,Bank0 | 第7位 | 第6位 | 第5位 | 第4位 | 第3位 | 第2位 | 第1位 | 第0位 |
---|---|---|---|---|---|---|---|---|
FLASHCON | - | - | - | - | - | - | CRC_FAC | FAC |
读/写 | - | - | - | - | - | - | 读/写 | 读/写 |
复位值 (POR/WDT/LVR/PIN) |
- | - | - | - | - | - | 0 | 0 |
位编号定义:
位编号 | 位符号 | 说明 |
---|---|---|
7-2 | - | 保留位 |
1 | CRC_FAC | 访问控制 0:对MAIN区做CRC的验证 1:对INFO区做CRC的验证 |
0 | FAC | 访问控制 0:MOVC指令或者SSP功能访问Main Block区域 1:MOVC指令或者SSP功能访问类EEPROM区域或信息存储区 |
三、补充知识 C51的存储空间
1. C51的RAM空间
C51编译器可以访问8051的所有存储区域,声明变量时可以指定分配的存储区,下面是关键字:
关键字 | 存储空间 | 地址范围 | 访问方式 |
---|---|---|---|
data | 内部RAM(低位128 bytes) | 0x00~0x7F | 直接寻址 |
idata | 内部RAM(全部256 bytes) | 0x00~0xFF | 间接寻址 |
bdata | 内部RAM(指定 16 bytes) | 0x20~0x2F | 位寻址/直接寻址 |
pdata | 扩展RAM(低位256 bytes) | 0x00~0xFF | 间接寻址 |
xdata | 扩展RAM(最大64K bytes) | 0x0000~0xFFFF | 间接寻址 |
code | Flash(最大64K bytes) | 0x0000~0xFFFF | 间接寻址 |
下面是变量声明的示例:
unsigned char data my_data;
unsigned char code text[] = "Hello World!";
unsigned char xdata array[100];
unsigned char idata x,y,z;
unsigned char pdata dimension;
unsigned char xdata vector[10][4][4];
unsigned char bdata flags;
存储结构图示如下:
SH79F9476RAM空间分配略有不同,主要在外部RAM区、增加的TK RAM、LED RAM。
关键字code用于声明常量或函数在Flash区,声明函数时编译器默认隐匿添加 code 关键字,不用处理。
四、代码实现
1. C语言访问存储区的方法
在ABSACC.H里定义了宏:
#define CBYTE ((unsigned char volatile code *) 0)
通过这个宏来读取FLASH存储区域数据,详解如下:
-
((unsigned char volatile code *))
: 定义了一个类型转换和指针。 -
unsigned char
: 将指针指向的数据类型定义为 unsigned char,即一个字节的无符号字符。 -
volatile
: 告诉编译器不要对指针指向的内存进行优化,即使似乎没有被程序直接访问到,也要保持读写的一致性。 -
code
: 这是一个特殊的关键字,用于指示数据存储在程序存储器中(如 Flash 存储器),而不是RAM。 -
0
: 这是一个常量,表示一个内存地址,这个宏定义了一个指向地址为0的位置的指针。
这个宏定义CBYTE
用来访问程序存储器中地址为0的位置的数据,如果要访问 0x127b处的数据,可以使用:
CBYTE[0x127b]
在下面的读取可读识别码部分,展示了该宏的使用方法。
2. 读取可读识别码
SH79F9476出厂时会固化一个40位可读识别码,是0-0xffffffffff 的随机值,无法被擦除,地址在:
0x127b ~ 0x127F,可使用下面代码读取:
eeprom_random_id.c
#include "eeprom_random_id.h"
#include "ABSACC.H"
/**
* @brief 读取随机识别码
*/
void readRandomID(unsigned char *r){
// 访问类EEPROM
FLASHCON = 0x01;
r[0] = CBYTE[0x127b];
r[1] = CBYTE[0x127c];
r[2] = CBYTE[0x127d];
r[3] = CBYTE[0x127e];
r[4] = CBYTE[0x127f];
// 访问 FLASH
FLASHCON = 0x00;
}
main.c
#include "SH79F9476.h"
#include "cpu.h"
#include "intrins.h"
#include "api_ext.h"
#include "clk_util.h"
#include "eeprom_op.h"
void main()
{
UCHAR val;
// 选择高速时钟
highFrequenceClk();
// 擦除扇区
EEPromSectorErase(0);
// EEPROM 0x0100地址写值
ssp_flag = 0x5A;
EEPromByteProgram(0x01,0x00,0x69);
//读取EEPROM 0x0100地址的值
val=EEPromByteRead(0x01,0x00);
while (1);
}
运行示例:
3. 扇区删除
/**
* @brief 扇区擦除
**/
void EEPromSectorErase(UCHAR nAddrH)
{
// 保护中断
_push_(IEN0);
//关总中断
IEN0 &=0x7F;
// 访问EEPROM区
FLASHCON = 0x01;
XPAGE = nAddrH<<1 ;
// E6 扇区擦除
IB_CON1 = 0xE6;
// 编程时IB_CON2必须为05H
IB_CON2 = 0x05;
// 编程时IB_CON3必须为0AH
IB_CON3 = 0x0A;
// 编程时IB_CON4必须为09H
IB_CON4 = 0x09;
// 增加flag判断,加强抗干扰能力
if(ssp_flag!=0xA5)
goto Error;
// 编程时IB_CON5必须为06H
IB_CON5 = 0x06;
_nop_();
_nop_();
_nop_();
_nop_();
Error:
ssp_flag = 0;
IB_CON1 = 0x00;
IB_CON2 = 0x00;
IB_CON3 = 0x00;
IB_CON4 = 0x00;
IB_CON5 = 0x00;
// 切回Flash区
FLASHCON = 0x00;
// 操作结束,恢复总中断
_pop_(IEN0);
}
2. 字节读
/**
* @brief 字节读
**/
UCHAR EEPromByteRead(UCHAR nAddrH,UCHAR nAddrL){
UCHAR nTemp;
// 保护现场
_push_(IEN0);
// 关总中断
IEN0 &=0x7F;
// 访问 EEPROM 区
FLASHCON = 0x01;
// 读取相应地址数据
nTemp= CBYTE[nAddrH*256+nAddrL];
// 切回 Flash 区
FLASHCON = 0x00;
// 操作结束,恢复现场
_pop_(IEN0);
return (nTemp);
}
3. 字节编程
/**
* @brief 字节编程
**/
void EEPromByteProgram(UCHAR nAddrH,UCHAR nAddrL, UCHAR nData){
// 保护现场
_push_(IEN0);
// 关总中断
IEN0 &=0x7F;
// 访问 EEPROM 区
FLASHCON = 0x01;
// 从0x00开始
XPAGE = nAddrH;
IB_OFFSET = nAddrL;
// 烧写内容
IB_DATA = nData;
IB_CON1 = 0x6E;
// 编程时IB_CON2必须为05H
IB_CON2 = 0x05;
// 编程时IB_CON3必须为0AH
IB_CON3 = 0x0A;
// 编程时IB_CON4必须为09H
IB_CON4 = 0x09;
// 增加flag判断,加强抗干扰能力
if(ssp_flag!=0x5A)
goto Error;
// 编程时IB_CON5必须为06H
IB_CON5 = 0x06;
_nop_() ;
_nop_() ;
_nop_() ;
_nop_() ;
Error:
ssp_flag = 0;
IB_CON1 = 0x00;
IB_CON2 = 0x00;
IB_CON3 = 0x00;
IB_CON4 = 0x00;
IB_CON5 = 0x00;
// 切回Flash区
FLASHCON = 0x00;
// 操作结束,恢复现场
_pop_(IEN0);
}
运行本文对应代码,观察读出的数据与写入相同。
本文学习资料来源中颖官方文档
本文代码开源地址:
https://gitee.com/xundh/learn-sinowealth-51