Flash memory
C8051F396片上的Flash存储着程序代码和非易失性数据
Flash可以通过物理接口C2在系统内一次一个字节进行编程,或者使用MOVX指令进行软件编程,这里主要是说明软件编程进行操作;
通过软件操作Flash时,如果单片机没有在工作电压范围内运行,会存在一定风险导致系统故障,为确保Flash内容的完整性,建议启用VDD监视器;
VDD监视器:
如果系统不能满足 1 ms 的最小 VDD 上升时间,或者VDD电压在2.7V以下时,开启复位,需要将VDD监视器配置为复位源。并且在启用VDD监视器和配置为复位源之间不能有任何延时。
void VDDMon_Init(void)
{
VDM0CN |= 0x80; // Ensure the VDD Monitor is enabled
RSTSRC = 0x02; // Select the VDD Monitor as a reset source
//PS:对RSTSRC(复位源)寄存器的写入都使用直接赋值运算符,不能使用按位运算符
}
在Flash操作过程中,VDD监视器使能要放在 PSWE 程序存储写使能位置一之后,然后在进行Flash写入擦除操作。
PSCTL |= 0x03; // PSWE = 1; PSEE = 1
VDM0CN = 0x80; // enable VDD monitor
RSTSRC = 0x02; // enable VDD monitor as a reset source
//擦除操作,PSWE = 1; PSEE = 1
PS:
1.确保Flash写入和擦除指针变量不在XRAM中,
2.在写入或擦除闪存的程序中添加地址边界检查,以确保使用非法地址调用不会导致修改闪存
#define FLASH_TEMP 0x03B00L // For 16K Flash Devices
// #define FLASH_TEMP 0x01B00L // For 8K Flash Devices
#define FLASH_LAST 0x03D00L // For 16K Flash Devices
// #define FLASH_LAST 0x01D00L // For 8K Flash Devices
系统时钟
在外部时钟下,在闪存写入或擦除操作时切换到内部时钟。CPU在闪存操作完成后切换回外部时钟继续运行
闪存操作锁(FLKEY: Flash Lock and Key)
在擦除和写入时,需要配置FLKEY寄存器来解锁:
FLKEY = 0xA5; // Key Sequence 1
FLKEY = 0xF1; // Key Sequence 2
在写入或擦除操作后,自动上锁,禁止操作Flash
PS:
1.如果对FLKEY写入错误的值,Flash将被锁死不能进行操作,直到下一次设备复位后才可以操作,
2.可以向FLKEY写入非0xA5的值来人为锁定Flash
3.可以读取FLKEY寄存器bit[1:0]两位来判断锁的状态
00:锁状态
01:已经向写入0xA5
10:解锁状态
11:锁死状态
操作位
PSWE 写使能位:置1,写使能
将一个字节的数据写入Flash程序内存;在写入数据之前,要先擦除Flash地址
PS:
1.在“PSWE=1;…PSWE=0;”区域之外 处理指针地址更新和循环变量。
2. 在PSWE 置一时减少变量的访问,禁用所有中断。
3.在将PSWE设置为“1”之前禁用中断,并在PSWE重置为0之前保持禁用状态。闪存写入或擦除操作期间任何触发的中断将在闪存操作完成并通过软件重新启用中断后按优先顺序进行执行。
PSEE 擦除使能位:置1,擦除使能,外加条件:PSWE置1
函数
写入
void FLASH_ByteWrite (unsigned int addr, char byte)
{
bit EA_SAVE = EA; // 保存中断
char xdata * data pwrite; // 定义地址指针
EA = 0; // 关闭中断
// change clock speed to slow, then restore later
VDM0CN = 0x80; // 开启VDD监视器
RSTSRC = 0x02; // VDD监视器作为复位源
pwrite = (char xdata *) addr; //传入地址
//解锁
FLKEY = 0xA5; // Key Sequence 1
FLKEY = 0xF1; // Key Sequence 2
PSCTL |= 0x01; // PSWE = 1,写使能
VDM0CN = 0x80; // enable VDD monitor
RSTSRC = 0x02; // enable VDD monitor as a reset source
*pwrite = byte; // write the byte
PSCTL &= ~0x01; // PSWE = 0,写失能
EA = EA_SAVE; // 恢复中断
}
读取
unsigned char FLASH_ByteRead (FLADDR addr)
{
bit EA_SAVE = EA; // 保存中断
char code * data pread; // 定义地址指针
unsigned char byte;
EA = 0; // 关闭中断
pread = (char code *) addr;
byte = *pread; // 返回值
EA = EA_SAVE; // 恢复中断
return byte;
}
擦除
void FLASH_PageErase (unsigned int addr)
{
bit EA_SAVE = EA; // 保存中断
char xdata * data pwrite; // 定义地址指针
EA = 0; // 关闭中断
// change clock speed to slow, then restore later
VDM0CN = 0x80; // 开启VDD监视器
RSTSRC = 0x02; // VDD监视器作为复位源
pwrite = (char xdata *) addr;
//解锁
FLKEY = 0xA5; // Key Sequence 1
FLKEY = 0xF1; // Key Sequence 2
PSCTL |= 0x03; // PSWE = 1; PSEE = 1 擦除失能
VDM0CN = 0x80; // enable VDD monitor
RSTSRC = 0x02; // enable VDD monitor as a reset source
*pwrite = 0; // initiate page erase
PSCTL &= ~0x03; // PSWE = 0; PSEE = 0
EA = EA_SAVE; // restore interrupts
}