static rt_uint32_t qspixfer(struct rt_spi_device *device, struct rt_spi_message *message) { rt_size_t len = 0; RT_ASSERT(device != RT_NULL); RT_ASSERT(device->bus != RT_NULL); struct rt_qspi_message *qspi_message = (struct rt_qspi_message *)message; struct stm32_qspi_bus *qspi_bus = device->bus->parent.user_data; #ifdef BSP_QSPI_USING_SOFTCS struct stm32_hw_spi_cs *cs = device->parent.user_data; #endif const rt_uint8_t *sndb = message->send_buf; rt_uint8_t *rcvb = message->recv_buf; rt_int32_t length = message->length; #ifdef BSP_QSPI_USING_SOFTCS if (message->cs_take) { rt_pin_write(cs->pin, 0); } #endif /* send data */ if (sndb) { qspi_send_cmd(qspi_bus, qspi_message); if (qspi_message->parent.length != 0) { if (HAL_QSPI_Transmit(&qspi_bus->QSPI_Handler, (rt_uint8_t *)sndb, 5000) == HAL_OK) { len = length; } else { LOG_E("QSPI send data failed(%d)!", qspi_bus->QSPI_Handler.ErrorCode); qspi_bus->QSPI_Handler.State = HAL_QSPI_STATE_READY; goto __exit; } } else { len = 1; } } else if (rcvb)/* recv data */ { qspi_send_cmd(qspi_bus, qspi_message); #ifdef BSP_QSPI_USING_DMA if (HAL_QSPI_Receive_DMA(&qspi_bus->QSPI_Handler, rcvb) == HAL_OK) #else if (HAL_QSPI_Receive(&qspi_bus->QSPI_Handler, rcvb, 5000) == HAL_OK) #endif { len = length; #ifdef BSP_QSPI_USING_DMA while (qspi_bus->QSPI_Handler.RxXferCount != 0); #endif } else { LOG_E("QSPI recv data failed(%d)!", qspi_bus->QSPI_Handler.ErrorCode); qspi_bus->QSPI_Handler.State = HAL_QSPI_STATE_READY; goto __exit; } } __exit: #ifdef BSP_QSPI_USING_SOFTCS if (message->cs_release) { rt_pin_write(cs->pin, 1); } #endif return len; }
/** * @brief Main program * @param None * @retval None */ int main(void) { QSPI_CommandTypeDef sCommand; uint32_t address = 0; uint16_t index; __IO uint8_t step = 0; /* STM32F4xx HAL library initialization: - Configure the Flash prefetch, instruction and Data caches - Systick timer is configured by default as source of time base, but user can eventually implement his proper time base source (a general purpose timer for example or other time source), keeping in mind that Time base duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and handled in milliseconds basis. - Set NVIC Group Priority to 4 - Low Level Initialization: global MSP (MCU Support Package) initialization */ HAL_Init(); /* Configure the system clock to 180 MHz */ SystemClock_Config(); BSP_LED_Init(LED1); BSP_LED_Init(LED3); /* Initialize QuadSPI ------------------------------------------------------ */ QSPIHandle.Instance = QUADSPI; HAL_QSPI_DeInit(&QSPIHandle); QSPIHandle.Init.ClockPrescaler = 1; QSPIHandle.Init.FifoThreshold = 4; QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; QSPIHandle.Init.FlashSize = QSPI_FLASH_SIZE; QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE; QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) { Error_Handler(); } sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; sCommand.AddressSize = QSPI_ADDRESS_24_BITS; sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; while(1) { switch(step) { case 0: CmdCplt = 0; /* Initialize Reception buffer --------------------------------------- */ for (index = 0; index < BUFFERSIZE; index++) { aRxBuffer[index] = 0; } /* Enable write operations ------------------------------------------- */ QSPI_WriteEnable(&QSPIHandle); /* Erasing Sequence -------------------------------------------------- */ sCommand.Instruction = SECTOR_ERASE_CMD; sCommand.AddressMode = QSPI_ADDRESS_1_LINE; sCommand.Address = address; sCommand.DataMode = QSPI_DATA_NONE; sCommand.DummyCycles = 0; if (HAL_QSPI_Command_IT(&QSPIHandle, &sCommand) != HAL_OK) { Error_Handler(); } step++; break; case 1: if(CmdCplt != 0) { CmdCplt = 0; StatusMatch = 0; /* Configure automatic polling mode to wait for end of erase ------- */ QSPI_AutoPollingMemReady(&QSPIHandle); step++; } break; case 2: if(StatusMatch != 0) { StatusMatch = 0; TxCplt = 0; /* Enable write operations ----------------------------------------- */ QSPI_WriteEnable(&QSPIHandle); /* Writing Sequence ------------------------------------------------ */ sCommand.Instruction = EXT_QUAD_IN_FAST_PROG_CMD; sCommand.AddressMode = QSPI_ADDRESS_4_LINES; sCommand.DataMode = QSPI_DATA_4_LINES; sCommand.NbData = BUFFERSIZE; if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_QSPI_Transmit_DMA(&QSPIHandle, aTxBuffer) != HAL_OK) { Error_Handler(); } step++; } break; case 3: if(TxCplt != 0) { TxCplt = 0; StatusMatch = 0; /* Configure automatic polling mode to wait for end of program ----- */ QSPI_AutoPollingMemReady(&QSPIHandle); step++; } break; case 4: if(StatusMatch != 0) { StatusMatch = 0; RxCplt = 0; /* Configure Volatile Configuration register (with new dummy cycles) */ QSPI_DummyCyclesCfg(&QSPIHandle); /* Reading Sequence ------------------------------------------------ */ sCommand.Instruction = QUAD_INOUT_FAST_READ_CMD; sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD; if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_QSPI_Receive_DMA(&QSPIHandle, aRxBuffer) != HAL_OK) { Error_Handler(); } step++; } break; case 5: if (RxCplt != 0) { RxCplt = 0; /* Result comparison ----------------------------------------------- */ for (index = 0; index < BUFFERSIZE; index++) { if (aRxBuffer[index] != aTxBuffer[index]) { BSP_LED_On(LED3); } } BSP_LED_Toggle(LED1); address += QSPI_PAGE_SIZE; if(address >= QSPI_END_ADDR) { address = 0; } step = 0; } break; default : Error_Handler(); } } }