本帖最后由 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
|