STM32CbueMX之NAND FLASH

前言:

关于NAND FLASH,外面好多例程都是关于时序的计算都是一笔带过。

只会告诉你a=2,但是不会告诉你为什么=2,而不是3.

所以找了挺多资料看,希望文章对你有帮助吧。

ECC我没研究。

本文代码链接:FSMCNAND.rar-其它代码类资源-CSDN下载

Nand flash

Nand-flash存储器是flash存储器的一种,其内部采用非线性宏单元模式,为固态大容量内存的实现提供了廉价有效的解决方案。Nand-flash存储器具有容量较大,改写速度快等优点,适用于大量数据的存储,因而在业界得到了越来越广泛的应用,如嵌入式产品中包括数码相机、MP3随身听记忆卡、体积小巧的U盘等。

硬件 :MT29F4G08+ F429

发送命令周期时序图:

STM32 FMC NAND寄存器

(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章节(手册可以在意法半导体STM32/STM8技术社区 - 提供最新的ST资讯和技术交流搜索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

STM32MXCUBEMX配置:

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 */
}

现象:

20200715:更新main函数的测试代码

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循环,正确。

  全篇完。

本人是一个嵌入式未入门小白,博客仅仅代表我个人主观见解,记录成长笔记。
笔记是以最简单的方式,只展示最核心的原理。
若有与 大神大大 见解有歧义,我绝对坚信 大神大大 见解是对的,我的是错的。
若无积分等无法下载源码,可加入QQ群657407920下载交流经验。感谢~!

 

 

  • 15
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 22
    评论
STM32F4是意法半导体公司推出的一款32位ARM Cortex-M4处理器核心的微控制器系列,具有丰富的外设和强大的性能。NAND Flash是一种常见的非易失性存储器,具有较大的存储容量和高速读写特性。本文将介绍如何使用STM32F4驱动NAND Flash。 首先,STM32F4的GPIO外设可以用来配置引脚的输入输出状态。我们可以通过设置GPIO引脚为输出模式,控制NAND Flash的片选、写使能、读使能等信号。另外,STM32F4还提供了寄存器控制的SPI和FSMC接口,可以用来和NAND Flash进行通信。 其次,STM32Cube软件平台可以为STM32F4系列提供丰富的驱动库。在使用NAND Flash时,我们可以借助STM32Cube的外设库函数,方便地对NAND Flash进行初始化、读写操作。可以通过调用库函数来配置FSMC接口的时序参数,以及设置NAND Flash的特性和模式等。此外,还可以使用DMA控制器来提高数据读写效率。 最后,针对具体的NAND Flash型号,我们需要查阅其数据手册来了解其特性和命令集。通过合理配置STM32F4的寄存器参数,将数据传输到NAND Flash的相应寄存器,然后读取返回的数据,完成对NAND Flash的读写操作。 综上所述,通过合理配置STM32F4的GPIO和FSMC接口,并结合STM32Cube库函数和DMA控制器,我们可以实现对NAND Flash的驱动。这样可以充分发挥STM32F4的性能优势,实现高速、可靠的数据存储和读取,满足各种应用的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值