- /*************************************************************************************
- 标 题: Flash的读写操作
- * 项 目 名: W-R_FLASH_TEST
- * 开发环境:ChipON IDE
- * 使用芯片:KF8F4156
- * 作 者:上海芯旺微电子技术有限公司
- * 功能简述: 如程序所示,对相应的地址进行操作,操作结果通过断电 使用PRO读取。
- *
- * 跳线接法:只需给单片机供电即可,为了观看数据操作是否完成,可以连接P12和J21 ,当D4灯闪烁时表示操作完成。可断电读取数据。
- *
- * 特殊说明: 程序会占用不确定的FLASH地址,因此你需要确定用于自写的块或确保当前使用地址为非程序区
- * 当前芯片的可自写范围:800H~1FDFH,
- * 实现方法在该项目目录中建立occupancy.txt的文件,添加地址占用描述使编译器跳过该段区域的实现
- * 格式:
- * 一行一条记录,一条记录由3部分组成标识、起始地址、结束地址。
- * 文件可以包含任意多条记录
- * 标识用于标记占用数据段还是代码段,可以是code或者是data。
- * 起始地址结束地址使用十六进制表示。
- * 占用包含起始和结束地址。
- *
- * 例如
- * data 0x180 0x190
- * code 0x800 0x810
- *************************************************************************************/
- #include <KF8F4156.h>
- //====================////////////////////FLASH相关声明/////////////////==============//////////
- /*参数传递说明见函数实现位置*/
- #define FLASH_BUFFER_MAX 32 // 数据的大小与单次操作量相关,这里int型,16,32,除非不用写操作或不关心一些数据。
- #define LED P1LR2
- unsigned int FLASH_BUFFER[FLASH_BUFFER_MAX];
- unsigned int FLASH_READ_BUF; //当单字读函数使用非全嵌汇编模式时,使用该值获取读取结果值
- unsigned int FLASH_READ_ONE (unsigned int address); //读一个字
- void FLASH_READ_FUN (unsigned int address,unsigned char length);//读多个数据到数据缓存区,建议最多量为1个页即32个数据,同时建议不跨页操作,与写函数对应
- void FLASH_WRITE_ONE (unsigned int address,unsigned int value); // 过程封装
- void FLASH_WRITE_FUN (unsigned int address,unsigned char length); //将缓存区数据写到对应位置,从第一个开始
- ///=========================================================================================///
- void init_mcu()
- {
- OSCCTL = 0x60; //设置为8M
- /*********端口初始化***********/
- TR0 = 0x04; //设置P0端口 1100 1111
- TR1 = 0x00; //设置P1端口 0000 0000
- TR2 = 0x00; //设置P2端口 0011 1111
- P0 = 0x00;
- P1 = 0x80; //P1.6 P1.7 指示运行结束灯
- P2 = 0xF0;
- }
- void main()
- {
- unsigned char i;
- unsigned int temp=0;
- init_mcu();
- //--- 准备待写入的数据0x0000 0x1111 0x2222...0xFFFF 0x1110 0x2221 0x3332 ...0xFFFE 0x110F
- for (i = 0; i < FLASH_BUFFER_MAX; i++)
- {
- FLASH_BUFFER[i] = temp;
- temp += 0x1111;
- }
- //---setp 1 写入到0x1E60 和0x1E80的FLASH空间 (页的首地址)
- FLASH_WRITE_FUN(0x1E60,FLASH_BUFFER_MAX);
- FLASH_WRITE_FUN(0x1E80,FLASH_BUFFER_MAX);
- //--- setp 2 读取 0x1E71,并写入到0x1EB5
- // 读取所需到缓存
- temp=FLASH_READ_ONE(0x1E71);
- // 非需要段的任意数据填充
- for (i = 0; i < 16; i++)
- {
- FLASH_BUFFER[i] = 0x0000;
- }
- //应该擦除0x1EA0页的数据 以便后续以0x1EB0开始的块写,如果确定该页为0xFFFF,可以跳过
- FLASH_WRITE_FUN(0x1EA0,16);
- // 修改要写入的值
- FLASH_BUFFER[5]=temp;
- FLASH_BUFFER[6]=0xFF33; //验证 用 0x1FB6
- // 执行0x0F98块的写入
- FLASH_WRITE_FUN(0x1EB0,16);
- //--- setp 3 将OX0F69中的数据修改为0X55AA
- #if 1 // 0 或 1
- FLASH_WRITE_ONE(0x1E69,0x55AA);
- #else
- FLASH_READ_FUN(0x1E60,FLASH_BUFFER_MAX); //缓存必须满足操作对应大小,不满足整页时,后续数据被删空
- FLASH_BUFFER[9]=0x55AA;
- FLASH_WRITE_FUN(0x1E60,FLASH_BUFFER_MAX);
- #endif
- //----------------------------------------- setp 4 end display
- while(1)
- {
- temp++;
- if(temp>30000)
- {
- temp=0;
- LED = !LED;
- }
- }
- }
- /***********************************************************************************
- * 函数名 :FLASH_READ_ONE
- * 函数功能:以设定地址开始,读取一个数的FLASH数据并返回结果
- * 入口参数:起始地址
- * 返回 :无
- **********************************************************************************/
- unsigned int FLASH_READ_ONE(unsigned int address)
- {
- #if 1 // 1 选用C语言表达 0 选用嵌汇编表达,嵌汇编效率更高,但提示传递参数未使用和函数无返回,可以忽略
- // FLASH_READ_BUF; 需要定义全局的该变量,获取值用于返回,或直接使用
- //; 参数的使用
- NVMADDRH=(unsigned char)(address>>8);
- NVMADDRL=(unsigned char)address;
- __asm
- ;//备份中断使能寄存器
- BANKSEL _INTCTL
- MOV R1,_INTCTL
- ;//关闭中断,操作不可打断
- CLR _INTCTL,_AIE
- JNB _INTCTL,_AIE
- JMP $-2
- ;//时钟频率备份及降频操作,建议降频到1M,此时中断已被关
- MOV R0,#0x30
- MOV R2,_OSCCTL
- MOV _OSCCTL,R0
- ;//硬件使能读操作
- BANKSEL _NVMCTL0
- MOV R5,#0x81
- MOV _NVMCTL0,R5
- NOPZ
- NOPZ
- NOPZ
- NOPZ
- ;//时钟与中断使能的还原
- MOV _OSCCTL,R2
- AND R1,#0xC0 ;//中断使能仅关系高2位
- ORL INTCTL,R1
- ;//操作结果赋值到变量,用于返回
- BANKSEL _NVMDATAL
- MOV R6,_NVMDATAL
- MOV R7,_NVMDATAH
- BANKSEL _FLASH_READ_BUF
- MOV (_FLASH_READ_BUF),R6
- MOV (_FLASH_READ_BUF+1),R7
- __endasm;
- return FLASH_READ_BUF;
- #else
- // 参数的传递使用 编译器自动变量 STK00 和 R0 ,其中R0为高位,返回使用STK00 和 R0 ,其中R0为高位
- __asm
- ;//传递操作地址
- BANKSEL _NVMADDRH
- MOV _NVMADDRH,R0
- BANKSEL STK00
- MOV R0,STK00
- BANKSEL _NVMADDRL
- MOV _NVMADDRL,R0
- ;//备份中断使能寄存器
- BANKSEL _INTCTL
- MOV R1,_INTCTL
- ;//关闭中断,操作不可打断
- CLR _INTCTL,_AIE
- JNB _INTCTL,_AIE
- JMP $-2
- ;//时钟频率备份及降频操作,建议降频到1M,此时中断已被关
- MOV R0,#0x30
- MOV R2,_OSCCTL
- MOV _OSCCTL,R0
- ;//硬件使能读操作
- BANKSEL _NVMCTL0
- MOV R5,#0x81
- MOV _NVMCTL0,R5
- NOPZ
- NOPZ
- NOPZ
- NOPZ
- ;//时钟与中断使能的还原
- MOV _OSCCTL,R2
- AND R1,#0xC0 ;//中断使能仅关系高2位
- ORL _INTCTL,R1
- ;//操作结果提供形式 整型数据返回结果使用 编译器自动变量 STK00 和 R0 ,其中R0为高位
- BANKSEL _NVMDATAL
- MOV R0,NVMDATAL
- BANKSEL STK00
- MOV STK00,R0
- BANKSEL _NVMDATAH
- MOV R0,NVMDATAH
- __endasm;
- #endif
- }
- /***********************************************************************************
- * 函数名 :FLASH_READ_FUN
- * 函数功能:以设定地址开始,读取一定个数的FLASH数据放置到数值FLASH_BUFFER[x]中
- * 入口参数:起始地址,操作个数
- * 返回 :无
- **********************************************************************************/
- void FLASH_READ_FUN(unsigned int address,unsigned char length)
- {
- #if 1 // 1时效率比0小 1 使用传递参数 0 按编译器全嵌汇编实现,但编译提示参数未使用,可以忽略
- //; 参数的使用
- NVMADDRH=(unsigned char) (address>>8);
- NVMADDRL=address;
- __asm
- ;//备份中断使能寄存器
- BANKSEL _INTCTL
- MOV R1,_INTCTL
- ;//关闭中断,操作不可打断
- CLR _INTCTL,_AIE
- JNB _INTCTL,_AIE
- JMP $-2
- ;//时钟频率备份及降频操作,建议降频到1M,此时中断已被关
- MOV R0,#0x30
- MOV R2,_OSCCTL
- MOV _OSCCTL,R0
- ;//读取结果的存放起始RAM地址,即数组缓存区 FLASH_BUFFER[x]
- MOV R3,#_FLASH_BUFFER
- __endasm;
- while(length--) // 仅使用R0,不改变R1
- {
- __asm
- ;//硬件读
- BANKSEL _NVMCTL0
- MOV R5,#0x81
- MOV _NVMCTL0,R5
- NOPZ
- NOPZ
- NOPZ ;//至少2条
- NOPZ
- ;//读结果处理
- BANKSEL _NVMDATAL
- MOV R6,_NVMDATAL
- MOV R7,_NVMDATAH
- BANKSEL _FLASH_BUFFER
- ST [R3],R6
- INC R3
- ST [R3],R7
- INC R3
- ;//指向下一操作地址,建议每次操作内容在一个块中,此时不需要处理_BADDRL进位的_BADDRH+1操作
- BANKSEL _NVMADDRL
- INC _NVMADDRL
- JNB _PSW,_Z
- INC _NVMADDRH
- __endasm;
- }
- __asm
- ;//时钟与中断使能的还原
- BANKSEL _OSCCTL
- MOV _OSCCTL,R2
- AND R1,#0xC0 ;//中断使能仅关系高2位
- ORL _INTCTL,R1
- __endasm;
- #else
- // 参数1的传递使用 编译器自动变量 STK00 和 R0 ,其中R0为高位
- // 参数2的传递使用 编译器自动变量 STK01
- // 整体实现的嵌汇编会提示参数未被使用,可以忽略
- __asm
- ;//传递操作地址
- BANKSEL _NVMADDRH
- MOV _NVMADDRH,R0
- BANKSEL STK00
- MOV R0,STK00
- BANKSEL _NVMADDRL
- MOV _NVMADDRL,R0
- ;//备份中断使能寄存器
- BANKSEL _INTCTL
- MOV R1,_INTCTL
- ;//关闭中断,操作不可打断
- CLR _INTCTL,_AIE
- JNB _INTCTL,_AIE
- JMP $-2
- ;//时钟频率备份及降频操作,建议降频到1M,此时中断已被关
- MOV R0,#0x30
- MOV R2,_OSCCTL
- MOV _OSCCTL,R0
- ;//读取结果的存放起始RAM地址,即数组缓存区 FLASH_BUFFER[x]
- MOV R0,#_FLASH_BUFFER
- FLASH_READ_FUN_LOOP:
- ;//硬件读
- BANKSEL _NVMCTL0
- MOV R5,#0x81
- MOV _NVMCTL0,R5
- NOPZ
- NOPZ
- NOPZ ;//至少2条
- NOPZ
- ;//读结果处理
- BANKSEL _NVMDATAL
- MOV R6,_NVMDATAL
- MOV R7,_NVMDATAH
- BANKSEL _FLASH_BUFFER
- ST [R0],R6
- INC R0
- ST [R0],R7
- INC R0
- ;//指向下一操作地址,建议每次操作内容在一个块中,此时不需要处理_BADDRL进位的_BADDRH+1操作
- BANKSEL _NVMADDRL
- INC _NVMADDRL
- JNB _PSW,_Z
- INC _NVMADDRH
- ;//读数量的判断
- BANKSEL STK01
- DECJZ STK01
- JMP FLASH_READ_FUN_LOOP
- ;//时钟与中断使能的还原
- BANKSEL _OSCCTL
- MOV _OSCCTL,R2
- AND R1,#0xC0 ;//中断使能仅关系高2位
- ORL _INTCTL,R1
- __endasm;
- #endif
- }
- /***********************************************************************************
- * 函数名 :FLASH_WRITE_FUN
- * 函数功能:按块或按页写入数据到FLASH,个数参数只能为16,32 ,地址必须为块的首地址 如十六进制下结尾00 20 40 60 80 A0 C0 E0
- * 如果地址不是页的首地址,必须确定后续块结果为0xFFFF,或前面操作过块首写,使后续块值被0xFFFF,否则写结果异常。
- * 入口参数:待写地址,待写地址的数据
- * 返回 :无
- * 写时间说明:除去代码,以整页FLASH为例,操作完第一块需要6ms,另外3块需要3ms。即第一块执行整页的擦除后写自身块,其他块直接写。
- **********************************************************************************/
- void FLASH_WRITE_FUN(unsigned int address,unsigned char length)
- {
- #if 1 // 1时效率比0小 1 使用传递参数 0 按编译器全嵌汇编实现,但编译提示参数未使用,可以忽略
- //; 参数的使用
- NVMADDRH=(unsigned char) (address>>8);
- NVMADDRL=address;
- __asm
- ;//备份中断使能寄存器
- BANKSEL _INTCTL
- MOV R1,_INTCTL
- ;//关闭中断,操作不可打断
- CLR _INTCTL,_PUIE
- CLR _INTCTL,_AIE
- JNB _INTCTL,_AIE
- JMP $-2
- ;//时钟频率备份及降频操作,建议降频到1M,此时中断已被关
- MOV R0,#0x30
- MOV R2,_OSCCTL
- MOV _OSCCTL,R0
- ;//读取结果的存放起始RAM地址,即数组缓存区 FLASH_BUFFER[x]
- MOV R3,#_FLASH_BUFFER
- __endasm;
- while(length--) // 仅使用R0,不改变R1
- {
- __asm
- ;//加载待写数据
- BANKSEL _FLASH_BUFFER
- LD R6,[R3]
- INC R3
- LD R7,[R3]
- INC R3
- BANKSEL _NVMDATAH
- MOV _NVMDATAH,R7
- MOV _NVMDATAL,R6
- ;//硬件写
- MOV R5 ,#0x84
- MOV _NVMCTL0,R5
- MOV R5,#0x69
- MOV _NVMCTL1,R5
- MOV R5,#0x96
- MOV _NVMCTL1,R5
- SET _NVMCTL0 , 1 ;// 写存在高压,高压还原添加空指令确保后续运行正常
- NOPZ
- NOPZ
- NOPZ
- NOPZ
- NOPZ
- NOPZ ;// 建议10条,至少2条
- NOPZ
- NOPZ
- NOPZ
- NOPZ
- MOV R5,#0X80
- MOV _NVMCTL0,R5
- ;//指向下一操作地址,这里不考虑高位,特性要求只能操作一页内的数据,不能跨页
- BANKSEL _NVMADDRL
- INC _NVMADDRL
- __endasm;
- }
- __asm
- ;//时钟与中断使能的还原
- BANKSEL _OSCCTL
- MOV _OSCCTL,R2
- AND R1,#0xC0 ;//中断使能仅关系高2位
- ORL _INTCTL,R1
- __endasm;
- #else
- // 参数1的传递使用 编译器自动变量 STK00 和 R0 ,其中R0为高位
- // 参数2的传递使用 编译器自动变量 STK01
- // 整体实现的嵌汇编会提示参数未被使用,可以忽略
- __asm
- ;//传递操作的地址(块首)
- BANKSEL _NVMADDRH
- MOV _NVMADDRH,R0
- BANKSEL STK00
- MOV R0,STK00
- BANKSEL _NVMADDRL
- MOV _NVMADDRL,R0
- ;//备份中断使能寄存器
- BANKSEL _INTCTL
- MOV R1,_INTCTL
- ;//关闭中断,操作不可打断
- CLR _INTCTL,_PUIE
- CLR _INTCTL,_AIE
- JNB _INTCTL,_AIE
- JMP $-2
- ;//时钟频率备份及降频操作,建议降频到1M,此时中断已被关
- MOV R0,#0x30
- MOV R2,_OSCCTL
- MOV _OSCCTL,R0
- ;//待写数据的存放起始RAM地址,即数组缓存区 FLASH_BUFFER[x]
- MOV R0,#_FLASH_BUFFER
- FALSH_WRITE_PAGE_LOOP:
- ;//加载待写数据
- BANKSEL _FLASH_BUFFER
- LD R6,[R0]
- INC R0
- LD R7,[R0]
- INC R0
- BANKSEL _NVMDATAH
- MOV _NVMDATAH,R7
- MOV _NVMDATAL,R6
- ;//硬件写
- MOV R5 ,#0x84
- MOV _NVMCTL0,R5
- MOV R5,#0x69
- MOV _NVMCTL1,R5
- MOV R5,#0x96
- MOV _NVMCTL1,R5
- SET _NVMCTL0 , 1 ;// 写存在高压,高压还原添加空指令确保后续运行正常
- NOPZ
- NOPZ
- NOPZ
- NOPZ
- NOPZ
- NOPZ ;// 建议10条,至少2条
- NOPZ
- NOPZ
- NOPZ
- NOPZ
- MOV R5,#0X80
- MOV _NVMCTL0,R5
- ;//指向下一操作地址,这里不考虑高位,特性要求只能操作一页内的数据,不能跨页
- BANKSEL _NVMADDRL
- INC _NVMADDRL
- BANKSEL STK01
- DECJZ STK01
- JMP FALSH_WRITE_PAGE_LOOP
- ;//时钟与中断使能的还原
- BANKSEL _OSCCTL
- MOV _OSCCTL,R2
- AND R1,#0xC0 ;//中断使能仅关系高2位
- ORL _INTCTL,R1
- __endasm;
- #endif
- }
- /***********************************************************************************
- * 函数名 :FLASH_WRITE_ONE
- * 函数功能:向某一地址写入一个字,不建议使用,实际执行从页首读出,经对应地址的缓存修改,在页起始回写,因此地址与页首偏移量需要数组大小满足需求。
- * 建议: 可采用FLASH_WRITE_FUN的传递个数为16,32 对应连续操作地址开始的第一块 第二块
- * 但地址必须是某块的开始
- * 入口参数:待写地址,待写地址的数据
- * 返回 :无
- **********************************************************************************/
- void FLASH_WRITE_ONE(unsigned int address,unsigned int value)
- {
- // 读出当前页到数据缓存,要求缓存大小必须满足写地址的偏移量要求
- FLASH_READ_FUN(address&0xFFE0,FLASH_BUFFER_MAX);
- // 修改待写数据在按照页排序中位置数据结果
- FLASH_BUFFER[address&0x1F] = value;
- // 整页数据回写
- FLASH_WRITE_FUN(address&0xFFE0,FLASH_BUFFER_MAX);
- }