aple0807 发表于 2022-12-28 15:38

【AT-START-F437测评】QPI-FLASH测试

本帖最后由 aple0807 于 2022-12-28 17:42 编辑

QPI是很多高性能MCU的标配,AT32F437也不例外,今天来测试一下板载QPI-FLASH的读写性能如何。

QPI初始化代码如下:
void bsp_qpi_init(void)
{
      intx_alloc();

      intx_disable();

      /* enable the qspi clock */
      crm_periph_clock_enable(CRM_QSPI1_PERIPH_CLOCK, TRUE);
      crm_periph_reset(CRM_QSPI1_PERIPH_RESET, TRUE);
      crm_periph_reset(CRM_QSPI1_PERIPH_RESET, FALSE);

      intx_enable();

      /* switch to cmd port */
      qspi_xip_enable(QPIX, FALSE);

      /* set sclk , AHB / 4*/
      qspi_clk_division_set(QPIX, QSPI_CLK_DIV_4);

      /* set sck idle mode 0 */
      qspi_sck_mode_set(QPIX, QSPI_SCK_MODE_0);

      /* set wip in bit 0 */
      qspi_busy_config(QPIX, QSPI_BUSY_OFFSET_0);

      cmd_cfg.pe_mode_enable = FALSE;
      cmd_cfg.pe_mode_operate_code = 0;
      cmd_cfg.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
      cmd_cfg.read_status_config = QSPI_RSTSC_HW_AUTO;
      cmd_cfg.read_status_enable = FALSE;
}该接口为AHB外设,时钟设定4分频,即72MHz。
AT32的QPI接口是基于命令处理的,用户配置好命令、时序等内容启动后,硬件自动按照指定的位宽发送/接收数据。
本测试读写均采用DMA方式,这样可以最大限度的发挥QPI的执行速度,特别是读操作。
void qspi_dma_set(dma_dir_type dir, uint8_t *buf, uint32_t length)
{
      dma_init_type dma_init_struct;
      dma_reset(DMA2_CHANNEL1);
      dma_default_para_init(&dma_init_struct);
      dma_init_struct.buffer_size = (length + 3) >> 2; /* using word unit */
      dma_init_struct.loop_mode_enable = FALSE;
      dma_init_struct.direction = dir;
      dma_init_struct.memory_base_addr = (uint32_t)buf;
      dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_WORD;
      dma_init_struct.memory_inc_enable = TRUE;
      dma_init_struct.peripheral_base_addr = (uint32_t)(&(QPIX->dt));
      dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_WORD;
      dma_init_struct.peripheral_inc_enable = FALSE;
      dma_init_struct.priority = DMA_PRIORITY_HIGH;

      dma_init(DMA2_CHANNEL1, &dma_init_struct);

      dmamux_init(DMA2MUX_CHANNEL1, DMAMUX_DMAREQ_ID_QSPI1);
      dmamux_enable(DMA2, TRUE);

      dma_channel_enable(DMA2_CHANNEL1, TRUE);
}
应用层测试代码如下:
if (1 == nortst.check_req || nortst.chk_keep)

      {

                uint32_t amount = nortst.amount;

                uint32_t ticks;



                // 写入数据

                uint32_t dats = nortst.dat = nortst.dat_first;



                flash_dbg_print("fix spi mode check : start : R/W : %dMB\n", amount / (1024 * 1024));

                ticks = app_tick_get();

                for (nortst.addr = nortst.addr_start; nortst.addr < amount + nortst.addr_start; nortst.addr += SPI_NOR_PAGE_SIZE)

                {

                        if (nortst.addr % SPI_NOR_SECTOR_SIZE == 0)

                        {

                              bsp_snor_sector_erase(nortst.addr);

                        }



                        for (int index = 0; index < SPI_NOR_PAGE_SIZE / 4; index++)

                        {

                              nortst.buff.uVal = nortst.dat++;

                        }



                        // 写入一页数据

                        bsp_snor_write(nortst.addr, SPI_NOR_PAGE_SIZE, nortst.buff.v);



                        if (0 == (nortst.addr & 0x03FFFF))

                        {

                              flash_dbg_print("fix spi mode check write data: %d %% \n", (nortst.addr - nortst.addr_start) * 100 / amount);

                        }

                }

                flash_dbg_print("fix spi write end: time : %d ms \n", app_tick_get() - ticks);



                // 读回校验

                ticks = app_tick_get();

                nortst.dat = dats;

                for (nortst.addr = nortst.addr_start; nortst.addr < amount + nortst.addr_start; nortst.addr += SPI_NOR_PAGE_SIZE)

                {

                        if (nortst.addr % SPI_NOR_SECTOR_SIZE == 0)

                        {

                              // 读取一扇区数据

                              bsp_snor_read(nortst.addr, SPI_NOR_SECTOR_SIZE, nortst.buff.v);



                              for (int index = 0; index < SPI_NOR_SECTOR_SIZE / 4; index++)

                              {

                                        if (nortst.buff.uVal != nortst.dat)

                                        {

                                                nortst.err++;

                                        }

                                        nortst.dat++;

                              }



                              if (nortst.err)

                              {

                                        flash_dbg_print("fix spi mode check err: %d @ %x \n", nortst.err, nortst.addr);

                                        nortst.err = 0;

                              }

                        }

                }



                nortst.check_req = 0;

                flash_dbg_print("fix qpi mode read and check end : time : %d ms\n", app_tick_get() - ticks);



                set_u32(nortst.buff, 0, 4096 / 4);



                nortst.chk_cnt++;

                if (nortst.err)

                        nortst.chk_err_cnt++;

      }





先写入FLASH一定量的数据,然后读回验证。
在串口终端 输入 : nor check 4 启动测试,测试FLASH容量4MB,测试结果如下图所示:

4MB,写46s,读156ms。可以算得Flash写入速度大约87KB/s,读取并验证速度大约25.6MB/s。 写速度受FLASH擦写特性影响等待操作比较耗时。而读操作是无延时的,速度十分感人,这样读取16MB数据也只需要0.7s,比访问内置FLASH也差不了多少了。
QPI暂时测到这里,后面就可以给它加文件系统存储数据了。

代码托管在GITEE,后面评测会一直用这个仓库更新。
https://gitee.com/aple_sun/atf437-start


页: [1]
查看完整版本: 【AT-START-F437测评】QPI-FLASH测试