关于NAND FLASH,外面好多例程都是关于时序的计算都是一笔带过。
只会告诉你a=2,但是不会告诉你为什么=2,而不是3.
所以找了挺多资料看,希望文章对你有帮助吧。
ECC我没研究。
Nand-flash存储器是flash存储器的一种,其内部采用非线性宏单元模式,为固态大容量内存的实现提供了廉价有效的解决方案。Nand-flash存储器具有容量较大,改写速度快等优点,适用于大量数据的存储,因而在业界得到了越来越广泛的应用,如嵌入式产品中包括数码相机、MP3随身听记忆卡、体积小巧的U盘等。
发送命令周期时序图:
(MEMxSET + 1) + MEMxHOLD 控制NWE/NOE的高电平时间,
(MEMxWAIT + 1) 控制NWE/NOE的低电平时间,
MEMxHIZ 控制写入时数据线高阻态时间。
配置STM32CubeMX之前需要先把MEMxSET、MEMxWAIT、MEMxHOLD 和 MEMxHIZ算出来。
先看一下《AN4761 Application note Using STM32L476/486 FSMC peripheral to drive external memories》手册的4 Interfacing an 8-bit NAND Flash memory章节(手册可以在https://www.stmcu.org.cn/搜索AN4761找到)
得到下面时序计算不等式:
结合我们上面硬件芯片时序表格,代入不等式,未知数大等于0且向上取整:
tHCLK = 1s / 180MHz = 5.5ns
(SET + 1) x tHCLK ≥ max (tCS, tCLS, tALS, tCLR, tAR) - tWP
(SET + 1) x 5.5 >= max (15, 10, 10, 10, 10) - 10
(SET + 1) x 5.5 >= 15 - 10
SET >= 0 即可让不等式成立;
不等式(SET + 1) x 5.5 >= 5 ,SET >= 0 虽然不等式成立;
但是5.5ns仅仅比5ns大了0.5ns,考虑到走线等等因素,建议SET >= 1;(向上加 1)
(HIZ) x tHCLK ≥ max (tCS, tALS, tCLS) + (tWP - tDS)
(HIZ) x 5.5 ≥ max (15, 10, 10) + (10 - 7)
(HIZ) x 5.5 >= 15 + 3
HIZ >= 4 即可让不等式成立;
(HOLD) x tHCLK ≥ max (tCH, tCLH, tALH)
(HOLD) x tHCLK ≥ max (5, 5, 5)
(HOLD) x tHCLK ≥ 5
HOLD >= 1 即可让不等式成立;
不等式HOLD x 5.5 >= 5 ,HOLD >= 1 虽然不等式成立;
但是5.5ns仅仅比5ns大了0.5ns,考虑到走线等等因素,建议HOLD >= 2;(向上加 1)
WAIT 计算比较麻烦:必须满足下面几条不等式:
(WAIT + 1) x tHCLK ≥ max (tWP, tRP)
(WAIT + 1)× tHCLK ≥ (tREA + tsu(D-NOE))
WAIT ≥ (tREA + tsu(D-NOE)) /tHCLK - 1
tsu(D-NOE) = 9 ns(来自如《DS9405 STM32F427xx STM32F429xx datasheets》)
最后的计算结果:WAIT >= 4 即可让不等式成立;
最后一步验证一下:
((WAIT + 1) + (HOLD) + (SET + 1)) x tHCLK ≥ max (tWC/RC)
((4+ 1) + (2) + (1+ 1)) x 5.5 ≥ 20
成立!
得到下面结果:
MEMxSET = 1
MEMxWAIT = 4
MEMxHOLD = 2
MEMxHIZ = 4
NAND FLASH使用的是AHB时钟,180MHz,1 HCLK = 5.5ns
ECC computation 使能ECC纠正
ECC page size 选PAGE大小,芯片的page大小是2048
CLE low to RE low delay in HCLK cycles = 1
ALE low to RE low delay in HCLK cycles = 1
由下图手册得知:t_clr = (TCLR + SET + 2) × THCLK ;其中 TCLR 是我们软件CLE low to RE low delay in HCLK cycles的设置值,而SET手册也有写 “注意: 根据寻址空间,SET 为 MEMSET 或 ATTSET”。芯片手册tCLR = 10ns
THCLK = 1 / 180MHz = 5.5ns。由于MEMSET = 1;故TAR >= 0即可。
那为什么软件配置是CLE low to RE low delay in HCLK cycles = 1 呢,
看下面手册 TAR = 0,实际上是1个tHCKL。而软件配置问的是几个tHCKL,
那么配置写1个tHCKL,生成代码的时候会变成0。
ALE low to RE low delay in HCLK cycles计算过程如上。
Common space setup time = MEMxSET = 2 tHCLK;
STM32CubeMX 的Common space setup time的单位是tHCLK;从下面手册图可以看到
MEMxSET = 0的时候就是1个tHCLK;由于上面我们已经算出来MEMxSET 取 1,即2tHCLK。
图片来源于《STM32F4xx中文参考手册-扩展章节.pdf》
Common space wait time = MEMxWAIT = 4 tHCLK
Common space hold time = MEMxHOLD = 2 tHCLK(这个参数 不 需要MEMxHOLD 往上加1)
Common space Hi-Z time = MEMxHIZ = 4 tHCLK
下面4个参数和上面4个参数设置过程类似。
Attribute space setup time = MEMxSET = 1 tHCLK
Attribute space wait time = MEMxWAIT = 4 tHCLK
Attribute space hold time = MEMxHOLD = 2 tHCLK
Attribute space Hi-Z time = MEMxHIZ = 4 tHCLK
看图配置
Page size = 2048 bytes
Spare area size = 64 bytes
Block size = 64 pages
Block number = 2048 blocks
Plane number = 2 planes
Plane size = 4096 blocks
Extra command enable = Disabled
生成代码。
main.c
int main(void)
{
/* USER CODE BEGIN 1 */
uint32_t i = 0;
NAND_IDTypeDef id;
NAND_AddressTypeDef temp;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_FMC_Init();
/* USER CODE BEGIN 2 */
HAL_Delay(100);
printf("sudaroot\r\n");
HAL_NAND_Reset(&hnand1);
HAL_NAND_Read_ID(&hnand1, &id);
printf("HAL_id = 0x%X\r\n", *((unsigned int *)&id));
for(i = 0; i < NAND_PAGE_SIZE; i++)
{
buf[i] = 0xFA;
}
temp.Plane = 0;
temp.Block = 0;
temp.Page = 0;
printf("HAL_NAND_Erase_Block = %d\r\n", HAL_NAND_Erase_Block(&hnand1, &temp));
printf("HAL_NAND_Write_Page_8b = %d\r\n", HAL_NAND_Write_Page_8b(&hnand1, &temp, buf, 1));
memset(buf, 0, NAND_PAGE_SIZE);
printf("HAL_NAND_Read_Page_8b = %d\r\n", HAL_NAND_Read_Page_8b(&hnand1, &temp, buf, 1));
for(i = 0; i < NAND_PAGE_SIZE; i++)
{
if((i % 5) == 0) printf("\r\n");
printf("buf[%04d] = 0x%02X ", i, buf[i]);
}
printf("\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
HAL_Delay(100);
}
/* USER CODE END 3 */
}
现象:
int main(void)
{
uint32_t i = 0;
NAND_IDTypeDef id;
NAND_AddressTypeDef temp;
temp.Plane = 0;
temp.Block = 0;
temp.Page = 0;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_FMC_Init();
HAL_Delay(100);
printf("sudaroot\r\n");
// 1、复位NAND芯片,读取芯片ID
HAL_NAND_Reset(&hnand1);
HAL_NAND_Read_ID(&hnand1, &id);
printf("1.HAL_id = 0x%X\r\n", *((unsigned int *)&id));
// 2、擦除第0页所在的第0块的数据,并打印HAL_NAND_Erase_Block函数执行结果
printf("3.HAL_NAND_Erase_Block = %d\r\n", HAL_NAND_Erase_Block(&hnand1, &temp));
// 3、读取在芯片第0页的数据,并打印HAL_NAND_Read_Page_8b函数执行结果
memset(buf, 0, NAND_PAGE_SIZE);
printf("2.HAL_NAND_Read_Page_8b = %d\r\n", HAL_NAND_Read_Page_8b(&hnand1, &temp, buf, 1));
for(i = 0; i < NAND_PAGE_SIZE; i++)
{
if((i % 5) == 0) printf("\r\n");
printf("buf[%04d] = 0x%02X ", i, buf[i]);
}
printf("\r\n");
// 4、初始化数据,把新的数据写入芯片第0页,并打印HAL_NAND_Write_Page_8b函数执行结果
for(i = 0; i < NAND_PAGE_SIZE; i++)
{
buf[i] = i & 0x00FF;
}
printf("4.HAL_NAND_Write_Page_8b = %d\r\n", HAL_NAND_Write_Page_8b(&hnand1, &temp, buf, 1));
// 5、重新读取芯片第0页数据,并打印HAL_NAND_Read_Page_8b函数执行结果
memset(buf, 0, NAND_PAGE_SIZE);
printf("5.HAL_NAND_Read_Page_8b = %d\r\n", HAL_NAND_Read_Page_8b(&hnand1, &temp, buf, 1));
for(i = 0; i < NAND_PAGE_SIZE; i++)
{
if((i % 5) == 0) printf("\r\n");
printf("buf[%04d] = 0x%02X ", i, buf[i]);
}
printf("\r\n");
while (1)
{
HAL_Delay(100);
}
}
现象:
1、读取芯片ID.证明时序配置正常。
2、擦除第0页所在的第0块的数据,并打印HAL_NAND_Erase_Block函数执行结果(0表示成功)
3、读取在芯片第0页的数据,并打印HAL_NAND_Read_Page_8b函数执行结果(此时数据全是0xFF)
4、初始化数据0x00~0xFF循环,把新的数据写入芯片第0页,并打印HAL_NAND_Write_Page_8b函数执行结果
5、重新读取芯片第0页数据,并打印HAL_NAND_Read_Page_8b函数执行结果,数据0x00~0xFF循环,正确。
全篇完。
本人是一个嵌入式未入门小白,博客仅仅代表我个人主观见解方便记录成长笔记。 若有与大神大大见解有冲突,我坚信大神大大见解是对的,我的是错的。 若无法下载源码,可私聊私发。 感谢~!