本帖最后由 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[index].uVal = nortst.dat++;
- }
- // 写入一页数据
- bsp_snor_write(nortst.addr, SPI_NOR_PAGE_SIZE, nortst.buff[0].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[0].v);
- for (int index = 0; index < SPI_NOR_SECTOR_SIZE / 4; index++)
- {
- if (nortst.buff[index].uVal != nortst.dat)
- {
- nortst.err++;
- }
- nortst.dat++;
- }
- if (nortst.err)
- {
- flash_dbg_print("fix spi mode check err: %d [url=home.php?mod=space&uid=72445]@[/url] %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
|