跳转至

Flash demo和Falsh相关说明*

1.Flash demo 介绍*

1.1 简介*

  • 用于测试 flash 读、写、擦
  • 提供 flash 接口使用例程
  • flash 分区说明

1.2 源码位置*

  • lvp_tws/app/flash_demo/lvp_app_flash_demo.c

1.3 参考编译配置*

  • configs/release/grus_gx8002b_dev_1v_flash_demo.config
  • 可选择不同的测试项目,不同的测试地址、测试长度,是否循环测试等

1.4 flash接口注意事项*

  • 初始化接口 gx_spinor_flash_init 仅需要调用一次
  • 擦除地址和长度必须按block对齐,通过这个接口获取 block size:gx_spinor_flash_getinfo(GX_FLASH_ERASE_SIZE)
  • 必须在所有模块都没有正在访问XIP时才可以使用 flash 接口
  • 必须在所有模块都没有正在访问XIP时才可以使用 flash 接口
  • 必须在所有模块都没有正在访问XIP时才可以使用 flash 接口
  • 避免与XIP冲突可直接关中断、暂停其他模块(I2C UART 等可使用 dma 的模块),NPU需要关中断后其最后任务完成

1.5 Demo 使用方法*

  • 运行上述编译配置的固件,将出现如下log,"<>"中出现非0值时,表示对应测试项失败
    ...
    [FLASH_DEMO] ---- SampleAppInit ----  
    [FLASH_DEMO]Init 
    [FLASH_DEMO]Type:        [p25q80l]    
    [FLASH_DEMO]ID:          [0x856014]     
    [FLASH_DEMO]Size:        [1044480 Bytes]     
    [FLASH_DEMO]Erase block: [4096 Bytes] 
    [FLASH_DEMO]Test addr:   [1042147]
    [FLASH_DEMO]Erase size:  [4096]   
    [FLASH_DEMO]Prepare Test Data ...     
    [FLASH_DEMO]Prepare Test Data Done!  
    
    
    [FLASH_DEMO]Test count: 1     
    
    [FLASH_DEMO]Test size : 233   
    [FLASH_DEMO]Wait Npu Idle..   
    [FLASH_DEMO]Npu Idle
    [FLASH_DEMO]Read 1 Start ...  
    [FLASH_DEMO]Read 1 Done <0>   
    [FLASH_DEMO]Erase Start ...   
    [FLASH_DEMO]Erase Done! <0>   
    [FLASH_DEMO]Write Start ...   
    [FLASH_DEMO]Write Done! <0>   
    [FLASH_DEMO]Read 2 Start ...  
    [FLASH_DEMO]Read 2 Done <0>   
    ...     
    

1.6 关键代码*

lvp_tws/app/flash_demo/lvp_app_flash_demo.c
 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
        gx_spinor_flash_init();
        ... flash 相关信息打印  ...

        int erase_block_size = gx_spinor_flash_getinfo(GX_FLASH_ERASE_SIZE);

        // 获取 Flash 擦除块大小,擦除的地址必须是擦除块对齐的,擦除大小必须是擦除块的整数倍
        int test_size = CONFIG_LVP_APP_FLASH_TEST_SIZE;
        int flash_addr = (CONFIG_LVP_APP_FLASH_TEST_OFFSET + flash_size) % flash_size;
        int erase_addr = flash_addr - (flash_addr % erase_block_size);
        int erase_end  = ((flash_addr + test_size - 1) / erase_block_size + 1) * erase_block_size;
        int erase_size = erase_end - erase_addr;


        printf(LOG_TAG"Prepare Test Data ...\n");
        for (int i = 0; i < sizeof(s_test_buf); ++i) {
            s_test_buf[i] = i;
        }
        printf(LOG_TAG"Prepare Test Data Done!\n");

        int ret = 0;
        static unsigned int test_count = 0;
        while (_LOOP) {
            printf("\n"LOG_TAG"Test count: %d\n", ++test_count);
            printf("\n"LOG_TAG"Test size : %d\n", test_size);

    #ifdef CONFIG_LVP_APP_FLASH_TEST_LOCK_IRQ
            // 关闭中断
            unsigned int irq_state = gx_lock_irq_save();
    #endif

    #ifdef CONFIG_NPU_RUN_IN_FLASH
            printf(LOG_TAG"Wait Npu Idle..\n");
            while (gx_snpu_get_state() == GX_SNPU_BUSY); // 等待NPU停止使用flash
            printf(LOG_TAG"Npu Idle\n");
    #endif
            // 指定地址和长度读取 Flash
            printf(LOG_TAG"Read 1 Start ...\n");
            ret = gx_spinor_flash_readdata(flash_addr, s_test_buf, test_size);
            printf(LOG_TAG"Read 1 Done <%d>\n", ret);

    #ifdef CONFIG_LVP_APP_FLASH_TEST_ERASE
            // 指定地址和长度擦除 Flash
            printf(LOG_TAG"Erase Start ...\n");
            ret = gx_spinor_flash_erasedata(flash_addr, erase_size);
            printf(LOG_TAG"Erase Done! <%d>\n", ret);
    #endif

    #ifdef CONFIG_LVP_APP_FLASH_TEST_WRITE
            // 指定地址和长度写 Flash
            printf(LOG_TAG"Write Start ...\n");
            ret = gx_spinor_flash_pageprogram(flash_addr, s_test_buf, test_size);
            printf(LOG_TAG"Write Done! <%d>\n", ret);
    #endif

    #ifdef CONFIG_LVP_APP_FLASH_TEST_READ
            // 指定地址和长度读取 Flash
            printf(LOG_TAG"Read 2 Start ...\n");
            ret = gx_spinor_flash_readdata(flash_addr, s_test_buf, test_size);
            printf(LOG_TAG"Read 2 Done <%d>\n", ret);
    #endif

    #ifdef CONFIG_LVP_APP_FLASH_TEST_LOCK_IRQ
            // 恢复中断
            gx_unlock_irq_restore(irq_state);
    #endif

2.Flash分区说明*

注意事项

  • 用户空间不能覆盖固件地址空间,可以紧接着mcu_nor.bin后面的空间,但是需要4k字节对齐。
  • 驱动和下载器对 Flash 最后 4KB 做了保护,用户无法使用。
  • Flash Sector 大小为4KB,用户在分区的时候需要4k字节对齐。
  • GX8002A Flash Szie:256k , GX8002B Flash Size:512k , GX8002D Flash Size:1M

3.Falsh地址转换*

  • flash地址加xip基地址CONFIG_FLASH_XIP_BASE

    • 源码:#define CONFIG_FLASH_XIP_BASE 0x10200000
    • 头文件:#include <base_addr.h>
    • 示例:(CONFIG_FLASH_XIP_BASE + flash_addr))
  • 变量加XIP_RODATA_ATTR属性

    • 源码:#define XIP_RODATA_ATTR __attribute__((section(".xip.rodata*")))
    • 头文件:#include <lvp_attr.h>
    • 示例:const unsigned char test_buf[i] XIP_RODATA_ATTR;