收藏1 举报
/* 项目组织 1.将eeprom.c添加到项目中 2.在设置菜单所在c文件中定义数组u16 FEE_data[],并赋予初始值 3.修改eeprom.h中FEE_data数组大小及变量id枚举名 运用 4.上电初始化 FEE_init(); 5.FEE_rd(en_feedata_t); // 读,数组标号用枚举名 FEE_wr(u16,en_feedata_t); // 写 */ #include "eeprom.h" #define FEEP0_ADDR 0x00003C00 /* 首页地址 */ #define FEEP_PCS 10 /* 页个数 */ #define FEEP_BYTES 512 /* 页字节数 */ #define FEE_LOCKS 2048 /* 锁定区字节数 */ static u32 FEEcounts; // 累计擦除次数(用作启用页页首标记) static u32 FEEaddr; // 当前页首地址,指向当前启用页 static u16 FEEoffset; // 页指针,指向当前页内可写地址 static void FEEeof(void); // 存满处理 static void FEEput(u32 addr); // 转存处理 static void FEEextr(u32 addr); // 提取数据 static void FEEerase(u32 addr); // 擦除 /***/ u32 FEE_rd(en_feedata_t id) // eeprom读 { return FEE_data[id]; // 直接读取数组成员 } /***/ void FEE_wr(u32 data, en_feedata_t id) // eeprom写 { if(data!=FEE_data[id]) { u32 addr; FEE_data[id]=data; // 更新数组成员 addr=FEEaddr+FEEoffset; // 写FLASH地址 FLASH->PAGELOCK = 0x5A5A0000|(1<<(addr/FEE_LOCKS)); // 解锁地址所属锁定区 while (FLASH->CR1 & 0x20); // 等待空闲 FLASH->CR1 = 0x5A5A0001; // 编程模式 *((u32 *)addr) = ((u32)id)<<24|(data&0xFFFFFF); //id在高8位,值在低24位 while (FLASH->CR1 & 0x20); // 等待完成 FLASH->CR1 = 0x5A5A0000; // 改为只读 FLASH->PAGELOCK = 0x5A5A0000; // 锁定页面 FEEoffset+=4; // 指向下一个 if(FEEoffset>=FEEP_BYTES) FEEeof(); // 存满处理 } } /***/ static void FEEput(u32 addr) // 转存 { u8 nxh; FEEaddr=addr; // 作为当前页 FLASH->PAGELOCK = 0x5A5A0000|(1<<(addr/FEE_LOCKS)); // 解锁地址所属锁定区 while (FLASH->CR1 & 0x20); // 等待空闲 FLASH->CR1 = 0x5A5A0001; // 编程模式 FEEoffset=4; // 偏移4是数据开始 for(nxh=0; nxh<(sizeof(FEE_data)/sizeof(FEE_data[0])); nxh++) // 数组各成员 { *((u32 *)(addr+FEEoffset)) = (u32)(nxh<<24)|(FEE_data[nxh]&0xFFFFFF); // id在高8位,值在低24位 while (FLASH->CR1 & 0x20); // 等待完成 FEEoffset+=4; } *((u32 *)addr) = ++FEEcounts; // 页首写累计擦除次数作为启用标记 while (FLASH->CR1 & 0x20); // 等待完成 FLASH->CR1 = 0x5A5A0000; // 改为只读 FLASH->PAGELOCK = 0x5A5A0000; // 重新锁定 } /***/ static void FEEerase(u32 addr) // 擦除指定页面 { FLASH->PAGELOCK = 0x5A5A0000|(1<<(addr/FEE_LOCKS)); // 解锁地址所属锁定区 while (FLASH->CR1 & 0x20); // 等待空闲 FLASH->CR1 = 0x5A5A0002; // 页擦除模式 *((u32 *)addr) = 0; // 页面上写启动擦除 while (FLASH->CR1 & 0x20); // 等待完成 FLASH->CR1 = 0x5A5A0000; // 改为只读 FLASH->PAGELOCK = 0x5A5A0000; // 重新锁定 } /***/ static void FEEextr(u32 addr) // 提取数据 { u32 data; FEEaddr=addr; //作为当前页 FEEcounts=*(u32 *)(addr); // 偏移0是累计擦除次数 for(FEEoffset=4; FEEoffset<FEEP_BYTES; FEEoffset+=4) // 数据从偏移4开始 { data=*(u32 *)(addr+FEEoffset); if(~data) // 非空,有数据 { FEE_data[data>>24] = data & 0xFFFFFF;// 替换数组成员值 } else // 空,数据区结束 { break; } } } /***/ static void FEEeof(void) // 存满处理 { u32 temp0, temp1; temp0= FEEaddr; // 当前页 temp1=temp0+FEEP_BYTES; // 下一页 if(temp1<(FEEP0_ADDR + FEEP_BYTES * FEEP_PCS)) { FEEput(temp1); // 在指定范围内,切换到下一页 } else { FEEput(FEEP0_ADDR); // 超出,用首页 } FEEerase(temp0); //擦除旧页 } /***/ void FEE_init(void) // 上电初始化 { u8 temp; u32 tempaddr,tempmax; SYSCTRL->AHBEN |= 0x02; //开FLASH时钟 tempmax=0; for(temp=0;temp<FEEP_PCS;temp++) // 轮询各页 { tempaddr=FEEP0_ADDR + FEEP_BYTES * temp; // 页首地址 if(~(*(u32 *)(tempaddr+4))) // 数据区非空 { if(~(*(u32 *)tempaddr)) // 首地址非空,有擦除次数 { if((*(u32 *)tempaddr)>tempmax) tempmax=*(u32 *)tempaddr; // 记下最大的 } else { FEEerase(tempaddr); // 空表示转存失败,直接擦除 } } } if(tempmax) // 至少启用了一页 { for(temp=0;temp<FEEP_PCS;temp++) // 轮询各页 { tempaddr=FEEP0_ADDR + FEEP_BYTES * temp; // 页首地址 if(~(*(u32 *)tempaddr)) // 首地址非空,有擦除次数 { if((*(u32 *)tempaddr)==tempmax) // 擦除次数=最大次数的 { FEEextr(tempaddr); // 作为当前页,提取数据 } else { FEEerase(tempaddr); // 非当前页则擦除 } } } if(FEEoffset>=FEEP_BYTES) FEEeof(); // 满页处理 } else // 全空未用,初始化原始数据 { FEEcounts=0; FEEput(FEEP0_ADDR); // 转存 } } /***/ /*******************/
本版积分规则 发表回复 回帖并转播 回帖后跳转到最后一页
人才类勋章
本站内容禁止未经授权用于AI模型训练。如需商业数据合作,请联系我们。
扫码关注 21ic 官方微信
扫码关注嵌入式微处理器
扫码关注电源系统设计
扫码关注21ic项目外包
扫码浏览21ic手机版
本站介绍 | 申请友情链接 | 欢迎投稿 | 隐私声明 | 广告业务 | 网站地图 | 联系我们 | 诚聘英才
京公网安备 11010802024343号