跳转至

Spi Nand Flash 使用说明*

注意事项说明:

  • flash 操作地址从 0 开始,应不超过最大 flash 大小。
  • 写数据前应先进行擦除。
  • 写、读:操作地址 应该按照 page(2K) 大小对齐, 长度也应该为 page 的整数倍。
  • 擦:操作地址 应该按照 block(128K) 大小对齐, 擦除大小也应该为 block 的整数倍。
  • 对于坏块,在调用 读,写,擦 等接口时是不需要关心的,驱动内部会进行相应处理。

1.工程相关示例*

示例位置:

  • 示例 App Demo 位置: app/spi_nand_flash_sample/spi_nand_flash_sample.c
  • 默认配置位置: configs/release/nationalchip/grus_gx8002b_dev_1v4_spi_nand_flash_sample.config

使用方法:

$ cp configs/release/nationalchip/grus_gx8002b_dev_1v4_spi_nand_flash_sample.config .config
$ make defconfig
$ make clean;make
编译完成后即可烧录开发板运行。

2.管脚复用说明*

应确保 Spi Master 管脚复用正确

  • 执行 make menuconfig
  • 进入 Board Options
  • 勾选 BOARD_HAS_SPI_MASTER

文件boards/nationalchip/grus_gx8002b_dev_1v/misc_board.c 会进行相关配置

#if defined(CONFIG_BOARD_HAS_SPI_MASTER)
    ret += _BoardPadmuxSet(7, 4);
    ret += _BoardPadmuxSet(8, 4);
    ret += _BoardPadmuxSet(9, 4);
    ret += _BoardPadmuxSet(10, 4);
#endif

3.相关API调用说明*

3.1.头文件包含:*

#include <board_config.h>
#include <driver/gx_flash.h>

3.2.初始化说明:*

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
GX_FLASH_DEV *flash = NULL;
int spi_nand_flash_init(void)
{
    extern GX_FLASH_DEV spi_nand_flash_dev;
    flash = spi_nand_flash_dev.init(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS, CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE);

    if (flash == NULL) {
        printf("spi_nand_flash_dev init fail !!!\n", __LINE__);

        return -1;
    }
}

3.3.读、写、擦相关说明:*

 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
uint8_t test_data[4096] = {0};
int spi_nand_flash_test(void)
{
    printf(LOG_TAG"Test start\n");

    // 准备测试数据
    for (int i = 0; i < sizeof(test_data); i++) {
        test_data[i] = i % 256;
    }

    // 读、写的操作地址应该确保 page(2K) 对齐
    unsigned int test_flash_addr = 0x400000 - 0x1000;

    // 1. 打印当前 flash 的坏块信息,若有坏块信息,会打印出来
    gx_spi_flash_badinfo(flash);

    // 2. 判断某地址处是否是坏块, 返回 1: 是坏块,0: 不是坏块
    ret = gx_spi_flash_block_isbad(flash, test_flash_addr);
    printf(LOG_TAG"addr: %#x isbad? %s\n", test_flash_addr, ret == 1 ? "yes" : "no");

    // 3. 擦除, 地址必须 block(128K) 对齐,擦除大小应为 block(128K) 的倍数,遇到坏块会跳过当前坏块,继续擦除下一块,直到满足擦除长度
    // [注意:擦除长度不满足block倍数大小并不会报错,其会按照block倍数向上取整大小擦除]
    int block_size = gx_spi_flash_getinfo(flash, GX_FLASH_BLOCK_SIZE);
    int block_num = gx_spi_flash_getinfo(flash, GX_FLASH_BLOCK_NUM);
    ret = gx_spi_flash_erasedata(flash, 0x0, block_size * block_num);   // 全部擦除
    if (ret < 0)
        printf(LOG_TAG"erasedata error %d\n",  ret);
    else
        printf(LOG_TAG"erasedata success\n");

    // 4. 写入, 地址必须 page(2K) 对齐,长度为 page(2K) 倍数,遇到坏块会跳过当前坏块,向下一块写数据,直到满足写入长度
    // [注意:写入长度不满足 page 倍数大小并不会报错,写入仅写入指定长度大小, 但这个 page 后面未写入的位置将无法写入了,只能按 block 擦除后再进行写入]
    ret = gx_spi_flash_pageprogram(flash, test_flash_addr, test_data, sizeof(test_data));
    if (ret < 0)
        printf(LOG_TAG"write data error %d\n",  ret);
    else if (ret >= sizeof(test_data))
        printf(LOG_TAG"write data success, len: %d\n",  ret);

    // 将读取要写入的位置清空
    memset(test_data, 0, sizeof(test_data));
    for (int i = 0; i < sizeof(test_data); i++) {
        if (test_data[i] != 0)
            printf(LOG_TAG"error index [%d] is not 0: %d", i, test_data[i]);
    }

    // 5. 读取, 地址必须 page(2K) 对齐, 长度 为 page(2K) 倍数,遇到坏块会跳过当前坏块,向下一块读数据,直到满足读取长度
    // [注意:读取长度不满足 page 倍数大小并不会报错,读取仅读取指定长度大小]
    ret = gx_spi_flash_readdata(flash, test_flash_addr, test_data, sizeof(test_data));
    if (ret < 0)
        printf(LOG_TAG"readdata error %d\n",  ret);
    else if (ret >= sizeof(test_data))
        printf(LOG_TAG"readdata success, len: %d\n",  ret);

    // 对比读取的数据与写入的数据是否一致
    for (int i = 0; i < sizeof(test_data); i++) {
        if (test_data[i] != (i % 256))
            printf(LOG_TAG"error index[%d] read(%d) != write(%d)\n", i, test_data[i], i % 256);
    }
    printf(LOG_TAG"Test Successful\n");

    return 0;
}