nor-flash:MX29LV640EBXEI-70G

image.png
● MX29LV640EB 的前 8 个扇区是 8KB,之后的扇区是 64KB。
● 启动扇区8个,每个大小8KB
● 主扇区127个,每个大小64KB
存储大小概念
● 8位数据 = 1个字节
● 比如8K扇区,那么它的大小就是 1024 * 8 = 8192字节
● 在16位的模式下,1次就是2个字节。所以8K的扇区只能存取8192/2 = 4096个数据
● 扇区0的大小是0x000000 - 0x001000
驱动方式:根据电路图,flash是16位模式

image.png

image.png
代码:封装成函数
/**
* @description: 扇区擦除
* @param {uint32_t} SectorBaseAddr 某扇区
* @return {*}
*/
void flash_erase_sector(uint8_t sector_index) {
uint32_t TimeOut = 0;
uint16_t status;
// 1. 获取半字偏移
uint32_t halfword_offset = SectorOffset[sector_index];
// 2. 发送解锁和擦除设置命令
*(FLASH_ADDR + 0x555) = 0x00AA;
*(FLASH_ADDR + 0x2AA) = 0x0055;
*(FLASH_ADDR + 0x555) = 0x0080; // 擦除命令
*(FLASH_ADDR + 0x555) = 0x00AA;
*(FLASH_ADDR + 0x2AA) = 0x0055;
// 3. 写入要擦除的扇区地址(注意:偏移量是相对于Flash基址的)
*(FLASH_ADDR + halfword_offset ) = 0x0030; // 扇区擦除确认
// 4. 等待擦除完成(擦除耗时较长,通常需几十到几百毫秒)
while (1) {
status = *(FLASH_ADDR + halfword_offset);
if ((status & 0x80) == 0x80)
{
break; // DQ7=1 表示擦除完成
}
TimeOut++;
if (TimeOut > 0x2000000) { // 擦除超时设大一些(约几千万次循环)
shell_uart_write_string("Erase timeout\r\n");
return;
}
}
shell_uart_write_uint(sector_index);
shell_uart_write_string(" :sector Erase finish\r\n");
}
/**
* @description: 向flash读取一个数据
* @param {unsigned int} sector_index 具体那个扇区
* @param {unsigned int} index 第几个数据
* @return {*}
*/
uint16_t flash_read(unsigned int sector_index, unsigned int index) {
// 1. 计算扇区起始地址(指针类型必须与硬件位宽匹配)
volatile uint16_t *SectorStart = FLASH_ADDR + SectorOffset[sector_index];
// 2. 读取目标地址的数据(注意:参数名是 index,不是 num)
uint16_t data = *(SectorStart + index);
return data;
}
/**
* @description: 向flash写入一个16位数据(带超时等待)
* @param {unsigned int} sector_index 具体那个扇区
* @param {unsigned int} index 第几个数据
* @param {unsigned int} udData 要写入的16位数据(取低16位)
* @return {*} 0:成功, 1:超时失败
*/
unsigned int flash_write(unsigned int sector_index,unsigned int index, unsigned int udData) {
uint32_t TimeOut = 0;
uint16_t Data1, Data2;
// 1. 计算目标地址(基于半字偏移)
volatile uint16_t *target = FLASH_ADDR + SectorOffset[sector_index] + index;
// 2. 发送解锁和编程命令序列
*(FLASH_ADDR + 0x555) = 0x00AA;
*(FLASH_ADDR + 0x2AA) = 0x0055;
*(FLASH_ADDR + 0x555) = 0x00A0; // 编程命令
// 2. 写入目标地址和数据
*target = (uint16_t)(udData & 0xFFFF);
// 3. 等待写入完成(使用您已验证过的双重读比较方法)
while (1) {
Data1 = *target;
Data2 = *target;
if (Data1 == Data2)
break; // 数据稳定,写入完成
TimeOut++;
if (TimeOut > 0x1000000) { // 超时保护
shell_uart_write_string("Write timeout\r\n");
return 1; // 返回错误码
}
}
return 0; // 写入成功
}