/** * @brief Initializes the QSPI interface. * @retval QSPI memory status */ uint8_t BSP_QSPI_Init(void) { QSPIHandle.Instance = QUADSPI; /* Call the DeInit function to reset the driver */ if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) { return QSPI_ERROR; } /* System level initialization */ BSP_QSPI_MspInit(&QSPIHandle, NULL); /* QSPI initialization */ /* Init typedef is the same for both S25FL512S and N25Q512A memories, as they have the same FLASH size */ QSPIHandle.Init.ClockPrescaler = 1; /* QSPI Freq= 180 MHz / (1+1) = 90 MHz */ QSPIHandle.Init.FifoThreshold = 1; QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; QSPIHandle.Init.FlashSize = POSITION_VAL(S25FL512S_FLASH_SIZE) - 1; /* same size on both memory types */ QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE; QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1; QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE; if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) { return QSPI_ERROR; } /* Detect the memory ID */ if (QSPI_ReadID(&QspiInfo) != QSPI_OK) { return QSPI_NOT_SUPPORTED; } /* QSPI memory reset */ if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK) { return QSPI_NOT_SUPPORTED; } /* Set the QSPI memory in 4-bytes address mode */ if (QSPI_EnterFourBytesAddress(&QSPIHandle) != QSPI_OK) { return QSPI_NOT_SUPPORTED; } /* Configuration of the dummy cucles on QSPI memory side */ if (QSPI_DummyCyclesCfg(&QSPIHandle) != QSPI_OK) { return QSPI_NOT_SUPPORTED; } return QSPI_OK; }
/** * @brief Initializes the QSPI interface. * @retval QSPI memory status */ uint8_t BSP_QSPI_Init(void) { QSPIHandle.Instance = QUADSPI; /* Call the DeInit function to reset the driver */ if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) { return QSPI_ERROR; } /* System level initialization */ BSP_QSPI_MspInit(&QSPIHandle, NULL); /* QSPI initialization */ /* QSPI freq = SYSCLK /(1 + ClockPrescaler) = 216 MHz/(1+1) = 108 Mhz */ QSPIHandle.Init.ClockPrescaler = 1; QSPIHandle.Init.FifoThreshold = 4; QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; QSPIHandle.Init.FlashSize = POSITION_VAL(N25Q512A_FLASH_SIZE) - 1; QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE; QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1; QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE; if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) { return QSPI_ERROR; } /* QSPI memory reset */ if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK) { return QSPI_NOT_SUPPORTED; } /* Set the QSPI memory in 4-bytes address mode */ if (QSPI_EnterFourBytesAddress(&QSPIHandle) != QSPI_OK) { return QSPI_NOT_SUPPORTED; } /* Configuration of the dummy cycles on QSPI memory side */ if (QSPI_DummyCyclesCfg(&QSPIHandle) != QSPI_OK) { return QSPI_NOT_SUPPORTED; } return QSPI_OK; }
/** * @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_2_CYCLE; QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1; QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE; if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) { Error_Handler(); } /* QSPI memory reset */ if (QSPI_ResetMemory(&QSPIHandle) != HAL_OK) { Error_Handler(); } /* Set the QSPI memory in 4-bytes address mode */ if (QSPI_EnterFourBytesAddress(&QSPIHandle) != HAL_OK) { Error_Handler(); } sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; sCommand.AddressSize = QSPI_ADDRESS_32_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 = QUAD_IN_FAST_PROG_CMD; sCommand.AddressMode = QSPI_ADDRESS_1_LINE; 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_IT(&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_OUT_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_IT(&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(); } } }