QSPI DMA SPI
QSPI DMA SPI示例实现了采用QSPI接口的外部Flash,读取Flash中的数据并通过SPI Master DMA方式传输数据。
QSPI DMA SPI示例的源代码和工程文件位于SDK_Folder\projects\peripheral\qspi\qspi_flash_dma_spim,其中工程文件在文件夹Keil_5下。
代码理解
示例工程流程图如图 37所示:
- 配置QSPI DMA SPI。
g_qspi_handle.init.clock_prescaler = SystemCoreClock / 1000000; g_qspi_handle.init.clock_mode = QSPI_CLOCK_MODE_3; g_qspi_handle.init.rx_sample_delay = 0; hal_qspi_deinit(&g_qspi_handle); if (HAL_OK != hal_qspi_init(&g_qspi_handle)) { printf("\r\nFlash initial failed.\r\n"); return 0; } p_spi_handle->init.data_size = SPI_DATASIZE_32BIT; p_spi_handle->init.clock_polarity = SPI_POLARITY_LOW; p_spi_handle->init.clock_phase = SPI_PHASE_1EDGE; p_spi_handle->init.baudrate_prescaler = SystemCoreClock / 1000000; p_spi_handle->init.ti_mode = SPI_TIMODE_DISABLE; p_spi_handle->init.slave_select = SPI_SLAVE_SELECT_0; hal_spi_deinit(p_spi_handle); hal_spi_init(p_spi_handle);- 配置QSPI模块。
配置QSPI的时钟为1 MHz,配置空闲状态时时钟信号为高电平。
- 配置SPI模块。
- init.data_size:SPI数据发送宽度,可选择:SPI_DATASIZE_4BIT ~ SPI_DATASIZE_32BIT。
- init.clock_polarity:SPI空闲状态时的时钟信号,可选择:SPI_POLARITY_LOW、SPI_POLARITY_HIGH。
- init.clock_phase:SPI时钟切换的时间,可选择SPI_PHASE_1EDGE、SPI_PHASE_2EDGE。
- baudrate_prescaler:SPI的时钟选择,此处为SystemCoreClock / 1000000即1 MHz;
- init.ti_mode:SPI TI模式使能,可选择:SPI_TIMODE_DISABLE、SPI_TIMODE_ENABLE。
- init.slave_select:SPI从设备的选择,可选择:SPI_SLAVE_SELECT_0、SPI_SLAVE_SELECT_1、SPI_SLAVE_SELECT_ALL。
- 配置QSPI模块。
- 调用hal_qspi_init()初始化QSPI模块。代码如下:
hal_qspi_init(&g_qspi_handle); - 调用SPI_FLASH_Read_Device_ID()获取Flash的设备ID。代码如下:
device_id = SPI_FLASH_Read_Device_ID(); printf("Read_Device_ID = 0x%06X\r\n", device_id); - 调用SPI_FLASH_Page_Program()向Flash写数据。代码如下:
printf("Page_Program...\r\n"); SPI_FLASH_Page_Program(FLASH_PROGRAM_START_ADDR, flash_buffer); printf("Page Program Success.\r\n"); - 配置QSPI模式为SPI模式,配置数据位宽为32位,传输目的为EEPROM,输出大小为(FLASH_PAGE_SIZE >> 2) - 1。代码如下:
/* Config QSPI in SPI mode, data size is 32bits */ __HAL_QSPI_DISABLE(p_qspi_handle); ll_spi_set_frame_format(p_qspi_handle->p_instance, LL_SSI_FRF_SPI); ll_spi_set_data_size(p_qspi_handle->p_instance, LL_SSI_DATASIZE_32BIT); ll_spi_set_transfer_direction(p_qspi_handle->p_instance, LL_SSI_READ_EEPROM); ll_spi_set_receive_size(p_qspi_handle->p_instance, (FLASH_PAGE_SIZE >> 2) - 1); __HAL_QSPI_ENABLE(p_qspi_handle); - 配置SPI为写模式。代码如下:
/* Config SPI in write mode */ __HAL_SPI_DISABLE(p_spi_handle); ll_spi_set_transfer_direction(p_spi_handle->p_instance, LL_SSI_SIMPLEX_TX); __HAL_SPI_ENABLE(p_spi_handle); - 配置DMA burst length。代码如下:
/* Config burst length of DMA */ ll_dma_set_source_burst_length(DMA, p_qspi_handle->p_dma->channel, LL_DMA_SRC_BURST_LENGTH_1); ll_dma_set_destination_burst_length(DMA, p_qspi_handle->p_dma->channel, LL_DMA_DST_BURST_LENGTH_4); - 开始DMA传输并等待传输完成。代码如下:
/* Start read SPI flash */ uint32_t cmd_addr = ((uint32_t)SPI_FLASH_CMD_READ << 24) | FLASH_PROGRAM_START_ADDR; hal_dma_start(p_qspi_handle->p_dma, (uint32_t)& p_qspi_handle->p_instance->DATA, (uint32_t)& p_spi_handle->p_instance->DATA, FLASH_PAGE_SIZE >> 2); p_qspi_handle->p_instance->DATA = cmd_addr; __HAL_QSPI_ENABLE_DMARX(p_qspi_handle); __HAL_SPI_ENABLE_DMATX(p_spi_handle); hal_status_t status = hal_dma_poll_for_transfer(p_qspi_handle->p_dma, 1000); if (status == HAL_OK) { printf("Transfer finished.\r\n"); } else { printf("Transfer failed, hal_status = %d\r\n", status); }
测试验证
- 用GProgrammer下载qspi_flash_dma_spim.bin至开发板。
- 将开发板串口连接至PC端,打开并配置GRUart。
- 在GRUart的Receive Data窗口中将会显示QSPI FLASH SPI数据的交互数据信息。