blob: c8eb66868e0e3959280040a32f2fd679e9d92e9b [file] [log] [blame]
/**
******************************************************************************
* @file stm32h745i_discovery_qspi.c
* @author MCD Application Team
* @brief This file includes a standard driver for the MT25TL01G QSPI
* memory mounted on STM32H745I-DISCOVERY board.
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
(#) This driver is used to drive the MT25TL01G QSPI external
memory mounted on STM32H745I_DISCOVERY board.
(#) This driver need a specific component driver (MT25TL01G) to be included with.
(#) Initialization steps:
(++) Initialize the QPSI external memory using the BSP_QSPI_Init() function. This
function includes the MSP layer hardware resources initialization and the
QSPI interface with the external memory.
(#) QSPI memory operations
(++) QSPI memory can be accessed with read/write operations once it is
initialized.
Read/write operation can be performed with AHB access using the functions
BSP_QSPI_Read()/BSP_QSPI_Write().
(++) The function BSP_QSPI_GetInfo() returns the configuration of the QSPI memory.
(see the QSPI memory data sheet)
(++) Perform erase block operation using the function BSP_QSPI_Erase_Block() and by
specifying the block address. You can perform an erase operation of the whole
chip by calling the function BSP_QSPI_Erase_Chip().
(++) The function BSP_QSPI_GetStatus() returns the current status of the QSPI memory.
(see the QSPI memory data sheet)
@endverbatim
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32h745i_discovery_qspi.h"
/** @addtogroup BSP
* @{
*/
/** @addtogroup STM32H745I_DISCOVERY
* @{
*/
/** @defgroup STM32H745I_DISCOVERY_QSPI STM32H745I_DISCOVERY_QSPI
* @{
*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup STM32H745I_DISCOVERY_QSPI_Private_Variables Private Variables
* @{
*/
QSPI_HandleTypeDef QSPIHandle;
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup STM32H745I_DISCOVERY_QSPI_Private_Functions Private Functions
* @{
*/
static uint8_t QSPI_ResetMemory (QSPI_HandleTypeDef *hqspi);
static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi);
static uint8_t QSPI_DummyCyclesCfg (QSPI_HandleTypeDef *hqspi);
static uint8_t QSPI_WriteEnable (QSPI_HandleTypeDef *hqspi);
static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout);
static uint8_t QSPI_EnterQPI(QSPI_HandleTypeDef *hqspi);
/**
* @}
*/
/** @defgroup STM32H745I_DISCOVERY_QSPI_Exported_Functions Exported Functions
* @{
*/
/**
* @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 */
/* ClockPrescaler set to 1, so QSPI clock = 200MHz / (1+3) = 50MHz */
QSPIHandle.Init.ClockPrescaler = 3;
QSPIHandle.Init.FifoThreshold = 1;
QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
QSPIHandle.Init.FlashSize = POSITION_VAL(MT25TL01G_FLASH_SIZE) - 1;
QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_3_CYCLE;
QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
QSPIHandle.Init.FlashID = QSPI_FLASH_ID_2;
QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_ENABLE;
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 De-Initializes the QSPI interface.
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_DeInit(void)
{
QSPIHandle.Instance = QUADSPI;
/* Call the DeInit function to reset the driver */
if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK)
{
return QSPI_ERROR;
}
/* System level De-initialization */
BSP_QSPI_MspDeInit(&QSPIHandle, NULL);
return QSPI_OK;
}
/**
* @brief Reads an amount of data from the QSPI memory.
* @param pData: Pointer to data to be read
* @param ReadAddr: Read start address
* @param Size: Size of data to read
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size)
{
QSPI_CommandTypeDef s_command;
/* Initialize the read command */
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
s_command.Instruction = QUAD_INOUT_FAST_READ_DTR_CMD; /* DTR QUAD INPUT/OUTPUT FAST READ and 4-BYTE DTR FAST READ commands */
s_command.AddressMode = QSPI_ADDRESS_4_LINES;
s_command.AddressSize = QSPI_ADDRESS_32_BITS;
s_command.Address = ReadAddr;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.DummyCycles = MT25TL01G_DUMMY_CYCLES_READ_QUAD_DTR - 1;
s_command.NbData = Size;
s_command.DdrMode = QSPI_DDR_MODE_ENABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_HALF_CLK_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Configure the command */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Reception of the data */
if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief Writes an amount of data to the QSPI memory.
* @param pData: Pointer to data to be written
* @param WriteAddr: Write start address
* @param Size: Size of data to write
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size)
{
QSPI_CommandTypeDef s_command;
uint32_t end_addr, current_size, current_addr;
/* Calculation of the size between the write address and the end of the page */
current_size = MT25TL01G_PAGE_SIZE - (WriteAddr % MT25TL01G_PAGE_SIZE);
/* Check if the size of the data is less than the remaining place in the page */
if (current_size > Size)
{
current_size = Size;
}
/* Initialize the address variables */
current_addr = WriteAddr;
end_addr = WriteAddr + Size;
/* Initialize the program command */
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
s_command.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD;
s_command.AddressMode = QSPI_ADDRESS_4_LINES;
s_command.AddressSize = QSPI_ADDRESS_32_BITS;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.DummyCycles = 0;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Perform the write page by page */
do
{
s_command.Address = current_addr;
s_command.NbData = current_size;
/* Enable write operations */
if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK)
{
return QSPI_ERROR;
}
/* Configure the command */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Transmission of the data */
if (HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Configure automatic polling mode to wait for end of program */
if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK)
{
return QSPI_ERROR;
}
/* Update the address and size variables for next page programming */
current_addr += current_size;
pData += current_size;
current_size = ((current_addr + MT25TL01G_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : MT25TL01G_PAGE_SIZE;
} while (current_addr < end_addr);
return QSPI_OK;
}
/**
* @brief Erases the specified block of the QSPI memory.
* @param BlockAddress: Block address to erase
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress)
{
QSPI_CommandTypeDef s_command;
/* Initialize the erase command */
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
s_command.Instruction = SUBSECTOR_ERASE_4_BYTE_ADDR_CMD;
s_command.AddressMode = QSPI_ADDRESS_4_LINES;
s_command.AddressSize = QSPI_ADDRESS_32_BITS;
s_command.Address = BlockAddress;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_NONE;
s_command.DummyCycles = 0;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Enable write operations */
if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK)
{
return QSPI_ERROR;
}
/* Send the command */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Configure automatic polling mode to wait for end of erase */
if (QSPI_AutoPollingMemReady(&QSPIHandle, MT25TL01G_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief Erases the entire QSPI memory.
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_Erase_Chip(void)
{
QSPI_CommandTypeDef s_command;
/* Initialize the erase command */
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
s_command.Instruction = DIE_ERASE_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_NONE;
s_command.DummyCycles = 0;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Enable write operations */
if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK)
{
return QSPI_ERROR;
}
/* Send the command */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Configure automatic polling mode to wait for end of erase */
if (QSPI_AutoPollingMemReady(&QSPIHandle, MT25TL01G_DIE_ERASE_MAX_TIME) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief Reads current status of the QSPI memory.
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_GetStatus(void)
{
QSPI_CommandTypeDef s_command;
uint16_t reg;
/* Initialize the read flag status register command */
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
s_command.Instruction = READ_FLAG_STATUS_REG_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.DummyCycles = 0;
s_command.NbData = 1;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Configure the command */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Reception of the data */
if (HAL_QSPI_Receive(&QSPIHandle, (uint8_t*)(&reg), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Check the value of the register */
if ((reg & (MT25TL01G_FSR_PRERR | MT25TL01G_FSR_PGERR | MT25TL01G_FSR_ERERR)) != 0)
{
return QSPI_ERROR;
}
else if ((reg & (MT25TL01G_FSR_PGSUS | MT25TL01G_FSR_ERSUS)) != 0)
{
return QSPI_SUSPENDED;
}
else if ((reg & MT25TL01G_FSR_READY) != 0)
{
return QSPI_OK;
}
else
{
return QSPI_BUSY;
}
}
/**
* @brief Return the configuration of the QSPI memory.
* @param pInfo: pointer on the configuration structure
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_GetInfo(QSPI_Info* pInfo)
{
/* Configure the structure with the memory configuration */
pInfo->FlashSize = MT25TL01G_FLASH_SIZE;
pInfo->EraseSectorSize = (2 * MT25TL01G_SUBSECTOR_SIZE);
pInfo->ProgPageSize = MT25TL01G_PAGE_SIZE;
pInfo->EraseSectorsNumber = (MT25TL01G_FLASH_SIZE/pInfo->EraseSectorSize);
pInfo->ProgPagesNumber = (MT25TL01G_FLASH_SIZE/pInfo->ProgPageSize);
return QSPI_OK;
}
/**
* @brief Configure the QSPI in memory-mapped mode
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_EnableMemoryMappedMode(void)
{
QSPI_CommandTypeDef s_command;
QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
/* Configure the command for the read instruction */
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
s_command.Instruction = QUAD_INOUT_FAST_READ_DTR_CMD; /* DTR QUAD INPUT/OUTPUT FAST READ and 4-BYTE DTR FAST READ commands */
s_command.AddressMode = QSPI_ADDRESS_4_LINES;
s_command.AddressSize = QSPI_ADDRESS_32_BITS;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.DummyCycles = MT25TL01G_DUMMY_CYCLES_READ_QUAD_DTR - 1;
s_command.DdrMode = QSPI_DDR_MODE_ENABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_HALF_CLK_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Configure the memory mapped mode */
s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
s_mem_mapped_cfg.TimeOutPeriod = 0;
if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief QSPI MSP Initialization
* This function configures the hardware resources used in this example:
* - Peripheral's clock enable
* - Peripheral's GPIO Configuration
* - NVIC configuration for QSPI interrupt
* @retval None
*/
__weak void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params)
{
GPIO_InitTypeDef gpio_init_structure;
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* Enable the QuadSPI memory interface clock */
QSPI_CLK_ENABLE();
/* Reset the QuadSPI memory interface */
QSPI_FORCE_RESET();
QSPI_RELEASE_RESET();
/* Enable GPIO clocks */
QSPI_CLK_GPIO_CLK_ENABLE();
QSPI_BK1_CS_GPIO_CLK_ENABLE();
QSPI_BK1_D0_GPIO_CLK_ENABLE();
QSPI_BK1_D1_GPIO_CLK_ENABLE();
QSPI_BK1_D2_GPIO_CLK_ENABLE();
QSPI_BK1_D3_GPIO_CLK_ENABLE();
QSPI_BK2_CS_GPIO_CLK_ENABLE();
QSPI_BK2_D0_GPIO_CLK_ENABLE();
QSPI_BK2_D1_GPIO_CLK_ENABLE();
QSPI_BK2_D2_GPIO_CLK_ENABLE();
QSPI_BK2_D3_GPIO_CLK_ENABLE();
/*##-2- Configure peripheral GPIO ##########################################*/
/* QSPI CLK GPIO pin configuration */
gpio_init_structure.Pin = QSPI_CLK_PIN;
gpio_init_structure.Mode = GPIO_MODE_AF_PP;
gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
gpio_init_structure.Pull = GPIO_NOPULL;
gpio_init_structure.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &gpio_init_structure);
/* QSPI CS GPIO pin configuration */
gpio_init_structure.Pin = QSPI_BK1_CS_PIN;
gpio_init_structure.Pull = GPIO_PULLUP;
gpio_init_structure.Alternate = GPIO_AF10_QUADSPI;
HAL_GPIO_Init(QSPI_BK1_CS_GPIO_PORT, &gpio_init_structure);
/* QSPI D0 GPIO pin configuration */
gpio_init_structure.Pin = QSPI_BK1_D0_PIN;
gpio_init_structure.Pull = GPIO_NOPULL;
gpio_init_structure.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(QSPI_BK1_D0_GPIO_PORT, &gpio_init_structure);
gpio_init_structure.Pin = QSPI_BK2_D0_PIN;
gpio_init_structure.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(QSPI_BK2_D0_GPIO_PORT, &gpio_init_structure);
/* QSPI D1 GPIO pin configuration */
gpio_init_structure.Pin = QSPI_BK1_D1_PIN;
gpio_init_structure.Alternate = GPIO_AF10_QUADSPI;
HAL_GPIO_Init(QSPI_BK1_D1_GPIO_PORT, &gpio_init_structure);
gpio_init_structure.Pin = QSPI_BK2_D1_PIN;
gpio_init_structure.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(QSPI_BK2_D1_GPIO_PORT, &gpio_init_structure);
/* QSPI D2 GPIO pin configuration */
gpio_init_structure.Pin = QSPI_BK1_D2_PIN;
gpio_init_structure.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(QSPI_BK1_D2_GPIO_PORT, &gpio_init_structure);
gpio_init_structure.Pin = QSPI_BK2_D2_PIN;
HAL_GPIO_Init(QSPI_BK2_D2_GPIO_PORT, &gpio_init_structure);
/* QSPI D3 GPIO pin configuration */
gpio_init_structure.Pin = QSPI_BK1_D3_PIN;
HAL_GPIO_Init(QSPI_BK1_D3_GPIO_PORT, &gpio_init_structure);
gpio_init_structure.Pin = QSPI_BK2_D3_PIN;
HAL_GPIO_Init(QSPI_BK2_D3_GPIO_PORT, &gpio_init_structure);
/*##-3- Configure the NVIC for QSPI #########################################*/
/* NVIC configuration for QSPI interrupt */
HAL_NVIC_SetPriority(QUADSPI_IRQn, 0x0F, 0);
HAL_NVIC_EnableIRQ(QUADSPI_IRQn);
}
/**
* @brief QSPI MSP De-Initialization
* This function frees the hardware resources used in this example:
* - Disable the Peripheral's clock
* - Revert GPIO and NVIC configuration to their default state
* @retval None
*/
__weak void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params)
{
/*##-1- Disable the NVIC for QSPI ###########################################*/
HAL_NVIC_DisableIRQ(QUADSPI_IRQn);
/*##-2- Disable peripherals and GPIO Clocks ################################*/
/* De-Configure QSPI pins */
HAL_GPIO_DeInit(QSPI_CLK_GPIO_PORT, QSPI_CLK_PIN);
HAL_GPIO_DeInit(QSPI_BK1_CS_GPIO_PORT, QSPI_BK1_CS_PIN);
HAL_GPIO_DeInit(QSPI_BK1_D0_GPIO_PORT, QSPI_BK1_D0_PIN);
HAL_GPIO_DeInit(QSPI_BK1_D1_GPIO_PORT, QSPI_BK1_D1_PIN);
HAL_GPIO_DeInit(QSPI_BK1_D2_GPIO_PORT, QSPI_BK1_D2_PIN);
HAL_GPIO_DeInit(QSPI_BK1_D3_GPIO_PORT, QSPI_BK1_D3_PIN);
HAL_GPIO_DeInit(QSPI_BK2_CS_GPIO_PORT, QSPI_BK2_CS_PIN);
HAL_GPIO_DeInit(QSPI_BK2_D0_GPIO_PORT, QSPI_BK2_D0_PIN);
HAL_GPIO_DeInit(QSPI_BK2_D1_GPIO_PORT, QSPI_BK2_D1_PIN);
HAL_GPIO_DeInit(QSPI_BK2_D2_GPIO_PORT, QSPI_BK2_D2_PIN);
HAL_GPIO_DeInit(QSPI_BK2_D3_GPIO_PORT, QSPI_BK2_D3_PIN);
/*##-3- Reset peripherals ##################################################*/
/* Reset the QuadSPI memory interface */
QSPI_FORCE_RESET();
QSPI_RELEASE_RESET();
/* Disable the QuadSPI memory interface clock */
QSPI_CLK_DISABLE();
}
/**
* @}
*/
/** @addtogroup STM32H745I_DISCOVERY_QSPI_Private_Functions
* @{
*/
/**
* @brief This function reset the QSPI memory.
* @param hqspi: QSPI handle
* @retval None
*/
static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef s_command;
/* Initialize the reset enable command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = RESET_ENABLE_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_NONE;
s_command.DummyCycles = 0;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Send the command */
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Send the reset memory command */
s_command.Instruction = RESET_MEMORY_CMD;
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
s_command.Instruction = RESET_ENABLE_CMD;
/* Send the command */
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Send the reset memory command */
s_command.Instruction = RESET_MEMORY_CMD;
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Enter QSPI memory in QPI mode */
if(QSPI_EnterQPI(&QSPIHandle) != QSPI_OK)
{
return QSPI_ERROR;
}
/* Configure automatic polling mode to wait the memory is ready */
if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief This function set the QSPI memory in 4-byte address mode
* @param hqspi: QSPI handle
* @retval None
*/
static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef s_command;
/* Initialize the command */
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
s_command.Instruction = ENTER_4_BYTE_ADDR_MODE_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_NONE;
s_command.DummyCycles = 0;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Enable write operations */
if (QSPI_WriteEnable(hqspi) != QSPI_OK)
{
return QSPI_ERROR;
}
/* Send the command */
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Configure automatic polling mode to wait the memory is ready */
if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief This function configure the dummy cycles on memory side.
* @param hqspi: QSPI handle
* @retval None
*/
static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef s_command;
uint16_t reg = 0;
/* Initialize the read volatile configuration register command */
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
s_command.Instruction = READ_VOL_CFG_REG_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.DummyCycles = 0;
s_command.NbData = 2;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Configure the command */
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Reception of the data */
if (HAL_QSPI_Receive(hqspi, (uint8_t *)(&reg), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Enable write operations */
if (QSPI_WriteEnable(hqspi) != QSPI_OK)
{
return QSPI_ERROR;
}
/* Update volatile configuration register (with new dummy cycles) */
s_command.Instruction = WRITE_VOL_CFG_REG_CMD;
MODIFY_REG(reg, 0xF0F0, ((MT25TL01G_DUMMY_CYCLES_READ_QUAD << 4) |
(MT25TL01G_DUMMY_CYCLES_READ_QUAD << 12)));
/* Configure the write volatile configuration register command */
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Transmission of the data */
if (HAL_QSPI_Transmit(hqspi, (uint8_t *)(&reg), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief This function send a Write Enable and wait it is effective.
* @param hqspi: QSPI handle
* @retval None
*/
static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef s_command;
QSPI_AutoPollingTypeDef s_config;
/* Enable write operations */
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
s_command.Instruction = WRITE_ENABLE_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_NONE;
s_command.DummyCycles = 0;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Configure automatic polling mode to wait for write enabling */
s_config.Match = MT25TL01G_SR_WREN | (MT25TL01G_SR_WREN << 8);
s_config.Mask = MT25TL01G_SR_WREN | (MT25TL01G_SR_WREN << 8);
s_config.MatchMode = QSPI_MATCH_MODE_AND;
s_config.StatusBytesSize = 2;
s_config.Interval = 0x10;
s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
s_command.Instruction = READ_STATUS_REG_CMD;
s_command.DataMode = QSPI_DATA_4_LINES;
if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief This function read the SR of the memory and wait the EOP.
* @param hqspi QSPI handle
* @param Timeout Autopolling timeout
* @retval None
*/
static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout)
{
QSPI_CommandTypeDef s_command;
QSPI_AutoPollingTypeDef s_config;
/* Configure automatic polling mode to wait for memory ready */
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
s_command.Instruction = READ_STATUS_REG_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.DummyCycles = 2;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
s_config.Match = 0;
s_config.MatchMode = QSPI_MATCH_MODE_AND;
s_config.Interval = 0x10;
s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
s_config.Mask = MT25TL01G_SR_WIP | (MT25TL01G_SR_WIP <<8);
s_config.StatusBytesSize = 2;
if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, Timeout) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief This function enter the QPSI memory in QPI mode
* @param hqspi QSPI handle
* @retval QSPI status
*/
static uint8_t QSPI_EnterQPI(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef s_command;
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = ENTER_QUAD_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_NONE;
s_command.DummyCycles = 0;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/