基于某些安全考虑或者降成本,我们不希望使用外部存储器件,但有时我们由需要记录一下参数,确保断电不丢失,这时,富余的内部代码存储Flash就派上用场了。

不同于外部存储器,几乎所有的内部Flash读写都十分麻烦,甚至需要使用到汇编。

下面我们将讲述dsPIC33E如何读写内部Flash,此处以dsPIC33EP256GP506为例。

示例代码下载:https://download.csdn.net/download/u010875635/10821230

在操作Flash之前,我们有必要下了解一下Flash的结构,注意以下几点:

1、dsPIC33E/PIC24E闪存程序存储器被分段为页和行,每页1024个指令字,每行128个指令字,部分器件不支持行

2、dsPIC33E/PIC24E闪存程序存储器支持128/2个保持寄存器以一次对存储器的一行/双指令字进行编程

3、dsPIC33E/PIC24E每个指令字为24位,占2个16为,最高8位为虚字节

4、 dsPIC33E/PIC24E每个指令字占2个地址,例如0x000000和0x000001都是表示第一个指令字

5、对于大多数应用,24位中的高8位不用于存储数据,建议便成为NOP指令或者非法操作码值

6、地址总是偶数呈现,读取奇数地址获取到的与前一个偶数时一致的,所以读取奇数地址没有意义

dsPIC33E/PIC24E操作Flash相关的几个寄存器。

1、TBLPAG:表地址页位,8位表地址页位与W寄存器组组合形成23位有效程序存储器地址加上一个字节选择位

2、 每个地址数据由2个字合并而成,由以下四个寄存器操作

TBLRDL:表读低位字

TBLWTL:表写低位字

TBLRDH:表读高位字

TBLWTH:表写高位字

程序存储器分为很多个表页,表页地址为TBLPAG,占据地址高8位(共24位),表页不同于Flash的擦除页。表页内部地址为16位的有效地址,占据低16位,所以一个表页大小为0x010000

表操作地址生成,有TBLPAG和来自Wn的16位组合成24位的有效地址,7-->0  15------>0

读相关操作较为简单,只需要写入TBLPAB和TBLRDL或TBLRDH然后读取即可

写相关操作较为复杂,允许一次擦除1页(8行),运行一次编程1行,或者编程2个指令字字。

注意擦除和编程都是边沿对齐的,从存储器起始开始,分别以1024指令字和128或2指令字作为边界,即,擦除的地址单位长度为0x400,例如擦除0-0x0003ff,0x000400-0x0007ff;编程的地址单位长度为0x80或者0x04,例如,编程0-0x00007f,0x000080-0x0000ff或者0x000080-0x000083

在程序存储器的最后一页上执行页擦除操作会清零闪存配置字,从而使能代码保护。因此,用户应避免在程序存储器的最后一页上执行页擦除操作。

要执行编程操作,必须先将其对应的整页(1024个指令字)全部擦除,然后重新编程,所以一般操作流程如下:
                     1、读取闪存程序存储器的一页,并将其作为数据镜像存储到RAM中,RAM镜像必须从1024字程序存储器的偶地址边界读取
                      2、用新的数据更新RAM中的数据镜像
                      3、擦除闪存存储器页
                                 a)设置NVMCON寄存器以擦除一页
                                 b)禁止中断
                                 c)将要擦除页的地址写入NVMADRU和NVMADR寄存器(可以是该页任意地址)
                                 d)将秘钥序列吸入NVMKEY寄存器,以使能擦除
                                 e)将NVMCON<15>的WR位置1,启动擦除周期
                                 f)擦除周期结束时WR位清零
                                 g)允许中断
                       4、用表写操作将128或者2个指令字的一行或双指令字从RAM装入写锁存器
                       5、对一行或者2个指令字进行编程
                                 a)设置NVMCON以编程一行
                                 b)禁止中断
                                 c)将要编程行或第一个字的地址写入NVMADRU和NVMADR寄存器
                                 d)将秘钥序列吸入NVMKEY寄存器,以使能编程周期
                                 e)将NVMCON<15>的WR位置1,启动编程周期
                                  f)编程周期结束时WR位清零
                                  g)允许中断
                      6、重复4-6步骤,对多个数据进行编程,直到一页编程完成
                      7、根据需要,重复1-6,对多页进行编程

关联寄存器如下:
              NVMCON:主控制寄存器,选择执行擦出还是编程操作
              NVMKEY:只写寄存器,防止闪存被误写或者误擦除,编程或擦除前必须执行解锁序列,解锁期间禁止中断,①将0x55写入NVMKEY;②将0xAA写入NVMKEY;③执行2条NOP指令④一个周期中写入NVMCON寄存器

写锁存器长度与器件有关,要参考对应器件的Datasheet。

dsPIC33E通用flash存储结构如下:

dsPIC33EP256GP506存储结构如下:

所有可用的flash操作。

dsPIC33EP256GP506可用操作。

汇编级读写Flash底层代码,dsPICflash.s

.include "xc.inc";C Called Function
.global _MemRead
.global _MemReadHigh
.global _MemReadLow
.global _MemEraseOnePage
.global _MemWriteDoubleInstructionWords.section .text;************************
; Function _MemRead:
; W0 = TBLPAG value
; W1 = Table Offset
; Return: Data in W1:W0
;************************
_MemRead:MOV W0, TBLPAGNOPTBLRDL [W1], W0TBLRDH [W1], W1RETURN;************************
; Function _MemRead:
; W0 = TBLPAG value
; W1 = Table Offset
; Return: Data in W0
;************************
_MemReadHigh:MOV W0, TBLPAGNOPTBLRDH [W1], W0RETURN;************************
; Function _MemRead:
; W0 = TBLPAG value
; W1 = Table Offset
; Return: Data in W0
;************************
_MemReadLow:MOV W0, TBLPAGNOPTBLRDL [W1], W0RETURN;************************
; Function _MemErasePage:
; W0 = TBLPAG value
; W1 = Table Offset
;************************
_MemEraseOnePage:MOV W0,NVMADRUMOV W1,NVMADR;TBLWTL w2,[w1]; Setup NVMCON to erase one page of Program MemoryMOV #0x4003,W0MOV W0,NVMCON; Disable interrupts while the KEY sequence is writtenPUSH SR;MOV #0x00E0,W0;IOR SR; Write the KEY SequenceMOV #0x55,W0MOV W0,NVMKEYMOV #0xAA,W0MOV W0,NVMKEY; Start the erase operationBSET NVMCON,#15; Insert two NOPs after the erase cycle (required)NOPNOP;Re-enable interrupts, if neededPOP SRRETURN; ************************
; Error , no use
; Function _MemWriteDoubleInstructionWords:
; All PIC device support Double Instructions program
; Write four 16-bit data to Double Instructions to Flash
; W0 = TBLPAG value
; W1 = Table Offset
; W2 = data
;************************
_MemWriteDoubleInstructionWords_Error:; Load the destination address to be writtenMOV W0,NVMADRUMOV W1,NVMADR; Load the two words into the latches; W2 points to the address of the data to write to the latches ; Set up a pointer to the first latch location to be written MOV #0xFA,W0MOV W0,TBLPAGMOV #0,W1; Perform the TBLWT instructions to write the latchesTBLWTL [W2++],[W1]TBLWTH [W2++],[W1++]TBLWTL [W2++],[W1]TBLWTH [W2++],[W1++]; Setup NVMCON for word programmingMOV #0x4001,W0MOV W0,NVMCON; Disable interrupts < priority 7 for next 5 instructions; Assumes no level 7 peripheral interrupts;DISI #06PUSH SR; Write the key sequenceMOV #0x55,W0MOV W0,NVMKEYMOV #0xAA,W0MOV W0,NVMKEY; Start the write cycleBSET NVMCON,#15NOPNOPPOP SRNOPNOPRETURN;************************
; Function _MemWriteDoubleInstructionWords:
; All PIC device support Double Instructions program
; Write four 16-bit data to Double Instructions to Flash
; W0 = TBLPAG value
; W1 = Table Offset
; W2 = data
;************************
_MemWriteDoubleInstructionWords:; Define the address from where the programming has to start;.equ PROG_ADDR, 0x01800;; Load the destination address to be written;MOV #tblpage(PROG_ADDR),W9;MOV #tbloffset(PROG_ADDR),W8MOV W0,NVMADRUMOV W1,NVMADR;MOV W9,NVMADRU;MOV W8,NVMADR;; Load the two words into the latches; W2 points to the address of the data to write to the latches; Set up a pointer to the first latch location to be writtenMOV #0xFA,W0MOV W0,TBLPAGMOV #0,W1; Perform the TBLWT instructions to write the latchesTBLWTL [W2++],[W1]TBLWTH [W2++],[W1++]TBLWTL [W2++],[W1]TBLWTH [W2++],[W1++]; Setup NVMCON for word programmingMOV #0x4001,W0MOV W0,NVMCON; Disable interrupts < priority 7 for next 5 instructions; Assumes no level 7 peripheral interruptsDISI #06; Write the key sequenceMOV #0x55,W0MOV W0,NVMKEYMOV #0xAA,W0MOV W0,NVMKEY; Start the write cycleBSET NVMCON,#15NOPNOPreturn

C语言封装一层为InnerFlash:

InnerFlash.h

#ifndef _MCU_DRIVERS_INNERFLASH_H_
#define _MCU_DRIVERS_INNERFLASH_H_//一个指令占2个16位,其中高16位的高8位为虚字节
typedef union OneInstruction {uint32_t UINT32;struct {uint16_t LowWord;  //低16位uint16_t HighWord; //高16位} HighLowUINT16s;
} OneInstruction_t;//一个地址占2个16位,其中高16位为Flash大页面
typedef union FlashAddr {uint32_t Uint32Addr;struct {uint16_t LowAddr;  //低16位uint16_t HighAddr; //高16位} Uint16Addr;
} FlashAddr_t;//读取一个指令字
OneInstruction_t InnerFlash_ReadOneInstruction(FlashAddr_t flashAddr);//读取低16位
unsigned int InnerFlash_ReadInstructionLow(FlashAddr_t flashAddr);//读取高16位,仅低8位有效,高8位始终为0
unsigned int InnerFlash_ReadInstructionHigh(FlashAddr_t flashAddr);//擦除0x000800倍数起始的1024个字(2048个地址,一页)
unsigned int InnerFlash_EraseFlashPage(FlashAddr_t flashAddr);//需要先擦除,再写入
//写入Flash,2个指令字为一组,若为奇数,最后一个填充为0xFFFFFF
//每个指令字的低16位存储一个数据,即2个地址存储1个16位数据
//例如 data[2]={0xaa05,0xaa06};,存入0x004000,即0x004000存入0x00aa05,0x004002存入0x00aa06
void InnerFlash_WriteInstructionsToFlash(volatile FlashAddr_t source_addr,volatile OneInstruction_t *data,volatile uint16_t dataLength);#endif

InnerFlash.c


#include <xc.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>#include "InnerFlash.h"extern unsigned int MemReadHigh (unsigned int TablePage, unsigned int TableOffset);
extern unsigned int MemReadLow (unsigned int TablePage, unsigned int TableOffset);
extern unsigned int MemEraseOnePage (unsigned int TablePage, unsigned int TableOffset);//写入2个指令字,即4个16bits,注意奇数位为高,仅8bits
//data[0]为第一个指令字的低16位,data[1]的低8位为第一个指令字的高8位,一个指令字宽度为32,最高8位为虚拟字节,所以实际宽度为24
extern void MemWriteDoubleInstructionWords(volatile unsigned int TablePage,volatile unsigned int TableOffset, volatile OneInstruction_t *temp);//每个指令字占2个地址,例如0x000000和0x000001都是表示第一个指令字
//flash分为多个表页,每一表页有0x10000/2个指令字,例如地址0x004000,为第0x00页,页内地址为:0x4000
//每个偶数地址包含2个16位数据,但实际上只有24位,高8位数据是虚拟的,此函数读取低八位
//可通过Mplab的PIC存储器视图->程序,查看hex文件对应地址的数据,然后使用下面方法读取测试比对
//读取一个指令字
OneInstruction_t InnerFlash_ReadOneInstruction(FlashAddr_t flashAddr)
{unsigned int Data1;OneInstruction_t Data;//方法一//TBLPAG = TablePage;//Data1 = __builtin_tblrdl(TableOffset);//方法二Data1 = MemReadLow (flashAddr.Uint16Addr.HighAddr, flashAddr.Uint16Addr.LowAddr);Data.HighLowUINT16s.LowWord = Data1;Data1 = MemReadHigh (flashAddr.Uint16Addr.HighAddr, flashAddr.Uint16Addr.LowAddr);Data.HighLowUINT16s.HighWord = Data1;return Data;
}//每个指令字占2个地址,例如0x000000和0x000001都是表示第一个指令字
//flash分为多个表页,每一表页有0x10000/2个指令字,例如地址0x004000,为第0x00页,页内地址为:0x4000
//每个偶数地址包含2个16位数据,但实际上只有24位,高8位数据是虚拟的,此函数读取低八位
//可通过Mplab的PIC存储器视图->程序,查看hex文件对应地址的数据,然后使用下面方法读取测试比对
unsigned int InnerFlash_ReadInstructionLow(FlashAddr_t flashAddr)
{unsigned int Data1;//方法一//TBLPAG = TablePage;//Data1 = __builtin_tblrdl(TableOffset);//方法二Data1 = MemReadLow (flashAddr.Uint16Addr.HighAddr, flashAddr.Uint16Addr.LowAddr);return Data1;
}//每个指令字占2个地址,例如0x000000和0x000001都是表示第一个指令字
//flash分为多个表页,每一表页有0x10000/2个指令字,例如地址0x004000,为第0x00页,页内地址为:0x4000
//每个偶数地址包含2个16位数据,但实际上只有24位,高8位数据是虚拟的,此函数读取高八位
//可通过Mplab的PIC存储器视图->程序,查看hex文件对应地址的数据,然后使用下面方法读取测试比对
unsigned int InnerFlash_ReadInstructionHigh(FlashAddr_t flashAddr)
{unsigned int Data1;//方法一//TBLPAG = TablePage;//Data1 = __builtin_tblrdh(TableOffset);//方法二Data1 = MemReadHigh (flashAddr.Uint16Addr.HighAddr, flashAddr.Uint16Addr.LowAddr);return Data1;
}//每个指令字占2个地址,例如0x000000和0x000001都是表示第一个指令字
//flash分为多个表页,每一表页有0x10000/2个指令字,例如地址0x004000,为第0x00页,页内地址为:0x4000
//每个偶数地址包含2个16位数据,但实际上只有24位,高8位数据是虚拟的,此函数读取高八位
//可通过Mplab的PIC存储器视图->程序,查看hex文件对应地址的数据,然后使用下面方法读取测试比对
//擦除必须一次性擦除1024(实际地址偏移会*2,0x400*2,因为一组奇数和偶数表示一个指令字)个指令字,从0开始,边沿对齐,输入任意地址,会擦除包含这个地址在内的一页
//配置字在最后一页,不允许擦除最后一页,否则会导致代码保护,全部置0
//并非所有器件都支持配置字编程,若是支持,一般配置字不需要擦除,可直接编程,但是要求时钟为FRC,不能带PLL,具体是否可编程配置字,查看NVMOP<3:0>
unsigned int InnerFlash_EraseFlashPage(FlashAddr_t flashAddr)
{MemEraseOnePage (flashAddr.Uint16Addr.HighAddr, flashAddr.Uint16Addr.LowAddr);return 1;
}//需要先擦除,再写入
//写入Flash,2个指令字为一组,若为奇数,最后一个填充为0xFFFFFF
//每个指令字的低16位存储一个数据,即2个地址存储1个16位数据
//例如 data[2]={0xaa05,0xaa06};,存入0x004000,即0x004000存入0x00aa05,0x004002存入0x00aa06
void InnerFlash_WriteInstructionsToFlash(volatile FlashAddr_t flashAddr,volatile OneInstruction_t *data,volatile uint16_t dataLength)
{volatile OneInstruction_t dataTmp[2];volatile uint16_t i;for(i=0;i<dataLength/2*2;i+=2){//数组偶数位为指令字高16位(高8位为虚拟字节,仅低8位有效),奇数位为指令字低16位//每个指令字存入一个实际16位数据,高8位为0dataTmp[0]= data[i];dataTmp[1] = data[i+1];//每次写入2个指令字,偏移4个地址,每2个地址表示一个指令字MemWriteDoubleInstructionWords(flashAddr.Uint16Addr.HighAddr, flashAddr.Uint16Addr.LowAddr+i*2, dataTmp);}if(dataLength%2==1){dataTmp[0]= data[i];dataTmp[1].UINT32 = 0xFFFFFF;//每次写入2个指令字,偏移4个地址,每2个地址表示一个指令字MemWriteDoubleInstructionWords(flashAddr.Uint16Addr.HighAddr, flashAddr.Uint16Addr.LowAddr+i*2, dataTmp);}}

再封装一层,设置特殊地址为参数存储地址,存储起始地址为0x02A000。

DataRecord.h

#ifndef _MCU_DRIVERS_DATARECORD_H_
#define _MCU_DRIVERS_DATARECORD_H_#include "InnerFlash.h"//index要小于4074,目前开辟的最大的用于存储数量的空间索引为4073
//读取flash内容
uint16_t DataRecord_ReadData(uint16_t index);void DataRecord_ErasePage();//index要小于4074,目前开辟的最大的用于存储数量的空间索引为4073
//往flash写入内容
uint16_t DataRecord_WriteData(uint16_t index, volatile OneInstruction_t data);uint16_t DataRecord_WriteDataArray(uint16_t index, volatile OneInstruction_t *data, uint16_t length);//擦除一大页flash
void EraseLargePage(uint16_t pageIndex);//填充一大页flash
void FillLagrePage(uint16_t pageIndex);#endif

DataRecord.c

/****************************************************** 本文件函数用于记录标定参数,断电不丢失*****************************************************/#include <xc.h>
#include "DataRecord.h"
//dsPIC33EP256GP50X, dsPIC33EP256MC20X/50X, PIC24EP256GP/MC20X这类256K的器件
//用户编程flash存储有88K个指令字空间,地址范围为:0x000200-0x02AFEA
//写锁存器占2个指令字,地址为:0xFA0000和0xFA0002
//USERID起始为0x800FF8,结束0x800FFE
//DEVID起始0xFF0000,结束0xFF0002//定义存储数据所在空间的起始地址,0x02A000,结束地址为0x2AFE8,可存储数据量为:(0x2AFE8-0x2A000+2)/2=4074
#define DATA_RECORD_START_PAGE 0x0002
#define DATA_RECORD_START_ADDR 0xA000//index要小于4074,目前开辟的最大的用于存储数量的空间索引为4073
//读取flash内容
uint16_t DataRecord_ReadData(uint16_t index)
{FlashAddr_t flashAddr;flashAddr.Uint16Addr.HighAddr = DATA_RECORD_START_PAGE;flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR+index*2;return InnerFlash_ReadInstructionLow(flashAddr);
}void DataRecord_ErasePage()
{FlashAddr_t flashAddr;flashAddr.Uint16Addr.HighAddr = DATA_RECORD_START_PAGE;flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR;InnerFlash_EraseFlashPage(flashAddr);
}//可写范围为0x2A000-0x2AF7E,总共一页,长度为0x800,每2个地址一个指令字,总共1024个指令字
//往flash写入内容
uint16_t DataRecord_WriteData(uint16_t index, volatile OneInstruction_t data)
{if(index>1023)  //超过一页return 0xa5a5;FlashAddr_t flashAddr;flashAddr.Uint16Addr.HighAddr = DATA_RECORD_START_PAGE;flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR+index*2;//读取对应地址数据,若数据与要写入的一致,则不再写入OneInstruction_t dataTmp = InnerFlash_ReadOneInstruction(flashAddr);if(dataTmp.UINT32==data.UINT32) //写入与实际的一样,不用写入return 0xffff;//先读取一页,再擦除,修改读取数据,写入一页OneInstruction_t pageData[1024];uint16_t i;//先将对应页的数据全部读出来,0x800个地址,0x400个字for(i=0;i<1024;i++){flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR+i*2;pageData[i] = InnerFlash_ReadOneInstruction(flashAddr);}//擦除整页flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR;InnerFlash_EraseFlashPage(flashAddr);//修改数据,每1024个数据pageData索引要从0重新开始pageData[index] = data;//将修改后的数据写回该页InnerFlash_WriteInstructionsToFlash(flashAddr,pageData,1024);return 0;
}//不允许数组超过一页
uint16_t DataRecord_WriteDataArray(uint16_t index, volatile OneInstruction_t *data, uint16_t length)
{//超过一页if((index+length)>1023)return 0xa5a5;FlashAddr_t flashAddr;uint16_t i,cmpNZ=0;OneInstruction_t pageData[1024];//取对应页的首地址flashAddr.Uint16Addr.HighAddr = DATA_RECORD_START_PAGE;flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR+index*2;//比对数组for(i=index;i<length;i++){//读取对应地址数据,若数据与要写入的一致,则不再写入flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR+i*2;pageData[i] = InnerFlash_ReadOneInstruction(flashAddr);if(pageData[i].UINT32!=data[i-index].UINT32) //只要有一个数据不同,则需要重新写入{cmpNZ = 1;break;}}if(cmpNZ==0) //数据完全一致,不写入return 0xffff;//先读取一页,再擦除,修改读取数据,写入一页for(i=0;i<1024;i++){//读取对应地址数据,若数据与要写入的一致,则不再写入flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR+i*2;pageData[i] = InnerFlash_ReadOneInstruction(flashAddr);}flashAddr.Uint16Addr.LowAddr = DATA_RECORD_START_ADDR;//擦除整页InnerFlash_EraseFlashPage(flashAddr);for(i=index;i<length;i++){//修改数据,每1024个数据pageData索引要从0重新开始pageData[index-(index/1024)*1024+i].UINT32 = data[i].UINT32;}//将修改后的数据写回该页InnerFlash_WriteInstructionsToFlash(flashAddr,pageData,1024);return 0;
}//擦除一大页flash
void EraseLargePage(uint16_t pageIndex)
{uint16_t offset;FlashAddr_t flashAddr;flashAddr.Uint16Addr.HighAddr = pageIndex;switch(pageIndex){case 0://第零大页for(offset=0x8000;offset<=0xF800;offset+=0x800){flashAddr.Uint16Addr.LowAddr = offset;InnerFlash_EraseFlashPage(flashAddr);if(offset>=0xF800)break;}break;case 1://第一大页for(offset=0;offset<=0xF800;offset+=0x800){flashAddr.Uint16Addr.LowAddr = offset;InnerFlash_EraseFlashPage(flashAddr);if(offset>=0xF800)break;}break;case 2://第二大页for(offset=0;offset<0xA800;offset+=0x800){flashAddr.Uint16Addr.LowAddr = offset;InnerFlash_EraseFlashPage(flashAddr);}break;default:break;}
}//填充一大页flash
void FillLagrePage(uint16_t pageIndex)
{volatile uint16_t offset=0;volatile FlashAddr_t source_addr;volatile OneInstruction_t data[2];switch(pageIndex){case 0:for(offset=0x8000;offset<=0xFFFC;offset+=4){source_addr.Uint16Addr.HighAddr = 0;source_addr.Uint16Addr.LowAddr = offset;data[0].HighLowUINT16s.HighWord = 0xF0;data[0].HighLowUINT16s.LowWord = offset;data[1].HighLowUINT16s.HighWord = 0xF0;data[1].HighLowUINT16s.LowWord = offset+2;InnerFlash_WriteInstructionsToFlash(source_addr,data,2);//由于最大值为0xFFFF,超过会从0开始,0xFFFC+4=0x0000;if(offset>=0xFFFC)break; //跳出循环}break;case 1:for(offset=0;offset<=0xFFFC;offset+=4){source_addr.Uint16Addr.HighAddr = 1;source_addr.Uint16Addr.LowAddr = offset;data[0].HighLowUINT16s.HighWord = 0xF1;data[0].HighLowUINT16s.LowWord = offset;data[1].HighLowUINT16s.HighWord = 0xF1;data[1].HighLowUINT16s.LowWord = offset+2;InnerFlash_WriteInstructionsToFlash(source_addr,data,2);//由于最大值为0xFFFF,超过会从0开始,0xFFFC+4=0x0000;if(offset>=0xFFFC)break; //跳出循环}break;case 2://InnerFlash_EraseFlashPage(2,0xA800);for(offset=0;offset<0xA800;offset+=4){source_addr.Uint16Addr.HighAddr = 2;source_addr.Uint16Addr.LowAddr = offset;data[0].HighLowUINT16s.HighWord = 0xF2;data[0].HighLowUINT16s.LowWord = offset;data[1].HighLowUINT16s.HighWord = 0xF2;data[1].HighLowUINT16s.LowWord = offset+2;InnerFlash_WriteInstructionsToFlash(source_addr,data,2);}break;default:break;}
}

使用范例,main.c

#include "McuDrivers/uart/uart.h"
#include "McuDrivers/system/system.h"
#include "McuDrivers/flash/DataRecord.h"
#include "McuDrivers/gpio/gpio.h"
#include "McuDrivers/timer/timer.h"uint16_t count = 0x0;int main(void)
{    /******** Initial ********/System_Initialize_g();Timer1_Initial_g();GPIO_Initial_g();Timer1_Start_g(10);//DataEEInit();Uart_Initial_g(115200);//InnerEEPromDataInit();System_Delay_MS_g(100);Uart_Printf_g("start!\n");//DataRecord_ErasePage(2,0xA000);//连续跨TBLPAG编程会出现后面的TBLPAG全部清零EraseLargePage(0);EraseLargePage(1);EraseLargePage(2);//    FillLagrePage(0);
//    FillLagrePage(1);
//    FillLagrePage(2);OneInstruction_t data[29];uint16_t i;for(i=0;i<29;i++)data[i].UINT32 = 0xF20000+i;DataRecord_WriteDataArray(0,data,29);GPIO_LED_D3_Toggle_g();while(1){System_Delay_MS_g(1000);//Uart_Printf_g("addr:%06X,read:%04X%04X\r\n",count,InnerFlash_ReadFlashHigh(0x00,count),ReadFlashLow(0x00,count));//Uart_Printf_g("realaddr:%X, data:%X\r\n",0xa000+count*2,DataRecord_ReadData(count));}return 0;
}uint16_t timerCount = 0;
void  Timer1CallBack()
{timerCount++;if(timerCount>50){timerCount=0;GPIO_LED_D4_Toggle_g();}
}uint16_t interruptCount=0;
void Int1Function(void)
{EraseLargePage(interruptCount);count = 0;interruptCount++;GPIO_LED_D3_Toggle_g();
}

【dsPIC33E】内部Flash读写相关推荐

  1. 单片机编程php,STC单片机内部FLASH读写程序(最新整理)

    <STC单片机内部FLASH读写程序(最新整理)>由会员分享,可在线阅读,更多相关<STC单片机内部FLASH读写程序(最新整理)(6页珍藏版)>请在人人文库网上搜索. 1.S ...

  2. 读写STM32内部flash读写代码

    读写STM32内部flash读写代码 由于老师的要求,所以写了一份读写STM32内部FLASH的代码,这样的话就可以把STM32里面没有用来保存代码段的部分用来存储数据了. 由于<stm32fl ...

  3. STM32CUBEIDE(16)----内部Flash读写

    STM32CUBEIDE(16)----内部Flash读写 概述 视频教学 csdn课程 硬件准备 配置时钟树 串口重定向 FLASH定义 低密度 中密度 高密度 变量定义 演示效果 最后 概述 本例 ...

  4. STM32 内部Flash读写 程序源码 [已验证]

    目录 STM32 内部Flash带缓存读写 程序源码 0 Macro 1.Flash_Erase 2. Flash_Read_Byte 3.Flash_Write_NoBuffer 4.Flash_W ...

  5. GD32F303固件库开发(17)----内部Flash读写

    概述 本例程主要讲解如何对芯片自带Flash进行读写,用芯片内部Flash可以对一些需要断电保存的数据进行保存,无需加外部得存储芯片,本例程采用的是GD32F303ZET6主控,512K大小的Flas ...

  6. stm32内部Flash读写

    文章目录 1.stm32内部flash介绍 2.读写驱动编写 3.源码 上篇文章讲到了STM32来驱动外部flah的操作,flash真是好东西啊,内存大,能存的东西多,这样我们就可以用它来做一些大点的 ...

  7. c语言 将结构体放在flash,stm32的内部flash读写操作(含结构体的保存)

    不同的stm32单片机的flash大小不同,这个需要查阅芯片手册或者查看STM32CubeMX软件. stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实 ...

  8. STM32F103ZE 内部flash 读写

    首先要了解自己的开发板内部flash容量以及地址 这里103ZE系列的内部flash是512K 属于大容量内存产品 这里贴一张内存对应地址映射的图  可以看到这里有几个比较重要的寄存器,我们稍后会讲到 ...

  9. STM32的内部Flash读写

    内部Flash官方手册介绍 STM官方关于stm32F103系列的芯片有一个专门介绍flash读写的手册.STM32F100xx超值型产品闪存编程手册 通过J-Link查看自己的芯片内部的flash大 ...

最新文章

  1. OpenGL绘制带有索引的矩形的实例
  2. python基本数据类型包括哪些_python入门3——基本数据类型
  3. 前端学习(528):等分布局存在间距得问题
  4. cursor.execute(sql) 执行结果集是有记录的 但是num=cursor.rownumber 返回值为0
  5. PHP笔记-学生成绩例子
  6. asp.net mvc3 利用Ajax实现局部刷新
  7. 《大型数据库技术》MySQL数据库安装配置及基础使用
  8. python 函数积累
  9. 百度区块链 xuperchain 如何剪枝 裁剪区块
  10. 再议 封装、继承、多态
  11. npm 下载第三方包
  12. P3853 路标设置
  13. 机器学习实战:支持向量机回归预测财政收入
  14. Excel公式:index + match多条件匹配,以当前行多个单元值去另一文档匹配,返回指定单元值
  15. 飞秋2013官方下载
  16. 数据学习(十)-假设检验
  17. 02 who——open、read、close
  18. Recurrent Filter Learning for Visual Tracking(RFL)论文笔记
  19. 嵌入式应用-详解移植并使用freetype显示文字
  20. AC6969A 双声道蓝牙芯片 经典蓝牙5.3 纯蓝牙

热门文章

  1. 【图像超分辨率重建】——EnhanceNet论文精读笔记
  2. 【数据结构】二叉树的非递归遍历
  3. pcb图3d模型丢失的情况解决
  4. 【线性代数】结合 Ax=b 的通解结构,直观理解秩、线性变换、相关无关、基础解系
  5. 6本超实用平面设计书籍
  6. 关于公司奖惩制度的想法
  7. 单链表 插入操作 和 删除操作 的易错点
  8. 新书介绍 -- 《Redis核心原理与实践》
  9. C语言实现SMTP发邮件
  10. Javascript算法实现PDF批量加盖不同宽度骑缝章,vue加持。