打印
[KungFu8位 MCU]

KF8F4156 Flash的读写操作

[复制链接]
1001|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
l科科1987|  楼主 | 2017-7-31 15:55 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/*************************************************************************************
     标         题: 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);
}


发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

19

主题

214

帖子

1

粉丝