eeprom.c
4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "eeprom.h"
#include "stm32f10x.h"
// #include "stmflash.h"
// #include "delay.h"
// #include "usart.h"
//////////////////////////////////////////////////////////////////////////////////
// 本程序只供学习使用,未经作者许可,不得用于其它任何用途
// ALIENTEK miniSTM32开发板
// STM32 FLASH 驱动代码
// 正点原子@ALIENTEK
// 技术论坛:www.openedv.com
// 修改日期:2012/9/13
// 版本:V1.0
// 版权所有,盗版必究。
// Copyright(C) 广州市星翼电子科技有限公司 2009-2019
// All rights reserved
//////////////////////////////////////////////////////////////////////////////////
// 读取指定地址的半字(16位数据)
// faddr:读地址(此地址必须为2的倍数!!)
// 返回值:对应数据.
u16 STMFLASH_ReadHalfWord(u32 faddr)
{
return *(vu16 *)faddr;
}
#if STM32_FLASH_WREN // 如果使能了写
// 不检查的写入
// WriteAddr:起始地址
// pBuffer:数据指针
// NumToWrite:半字(16位)数
void STMFLASH_Write_NoCheck(u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)
{
u16 i;
for (i = 0; i < NumToWrite; i++)
{
FLASH_ProgramHalfWord(WriteAddr, pBuffer[i]);
WriteAddr += 2; // 地址增加2.
}
}
// 从指定地址开始写入指定长度的数据
// WriteAddr:起始地址(此地址必须为2的倍数!!)
// pBuffer:数据指针
// NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
#if STM32_FLASH_BASE < 256
#define STM_SECTOR_SIZE 1024 // 字节
#else
#define STM_SECTOR_SIZE 2048
#endif
u16 STMFLASH_BUF[STM_SECTOR_SIZE / 2]; // 最多是2K字节
void STMFLASH_Write(u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)
{
u32 secpos; // 扇区地址
u16 secoff; // 扇区内偏移地址(16位字计算)
u16 secremain; // 扇区内剩余地址(16位字计算)
u16 i;
u32 offaddr; // 去掉0X08000000后的地址
if (WriteAddr < STM32_FLASH_BASE || (WriteAddr >= (STM32_FLASH_BASE + 1024 * STM32_FLASH_SIZE)))
return; // 非法地址
FLASH_Unlock(); // 解锁
offaddr = WriteAddr - STM32_FLASH_BASE; // 实际偏移地址.
secpos = offaddr / STM_SECTOR_SIZE; // 扇区地址 0~127 for STM32F103RBT6
secoff = (offaddr % STM_SECTOR_SIZE) / 2; // 在扇区内的偏移(2个字节为基本单位.)
secremain = STM_SECTOR_SIZE / 2 - secoff; // 扇区剩余空间大小
if (NumToWrite <= secremain)
secremain = NumToWrite; // 不大于该扇区范围
while (1)
{
STMFLASH_Read(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE / 2); // 读出整个扇区的内容
for (i = 0; i < secremain; i++) // 校验数据
{
if (STMFLASH_BUF[secoff + i] != 0XFFFF)
break; // 需要擦除
}
if (i < secremain) // 需要擦除
{
FLASH_ErasePage(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE); // 擦除这个扇区
for (i = 0; i < secremain; i++) // 复制
{
STMFLASH_BUF[i + secoff] = pBuffer[i];
}
STMFLASH_Write_NoCheck(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE / 2); // 写入整个扇区
}
else
STMFLASH_Write_NoCheck(WriteAddr, pBuffer, secremain); // 写已经擦除了的,直接写入扇区剩余区间.
if (NumToWrite == secremain)
break; // 写入结束了
else // 写入未结束
{
secpos++; // 扇区地址增1
secoff = 0; // 偏移位置为0
pBuffer += secremain; // 指针偏移
WriteAddr += secremain; // 写地址偏移
NumToWrite -= secremain; // 字节(16位)数递减
if (NumToWrite > (STM_SECTOR_SIZE / 2))
secremain = STM_SECTOR_SIZE / 2; // 下一个扇区还是写不完
else
secremain = NumToWrite; // 下一个扇区可以写完了
}
};
FLASH_Lock(); // 上锁
}
#endif
// 从指定地址开始读出指定长度的数据
// ReadAddr:起始地址
// pBuffer:数据指针
// NumToWrite:半字(16位)数
void STMFLASH_Read(u32 ReadAddr, u16 *pBuffer, u16 NumToRead)
{
u16 i;
for (i = 0; i < NumToRead; i++)
{
pBuffer[i] = STMFLASH_ReadHalfWord(ReadAddr); // 读取2个字节.
ReadAddr += 2; // 偏移2个字节.
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
// WriteAddr:起始地址
// WriteData:要写入的数据
void Test_Write(u32 WriteAddr, u16 WriteData)
{
STMFLASH_Write(WriteAddr, &WriteData, 1); // 写入一个字
}