You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1134 lines
34 KiB
1134 lines
34 KiB
2 years ago
|
/**
|
||
|
******************************************************************************
|
||
|
* @file stm32l496g_discovery_qspi.c
|
||
|
* @author MCD Application Team
|
||
|
* @brief This file includes a standard driver for the MX25R6435F QSPI
|
||
|
* memory mounted on STM32L496G-Discovery board.
|
||
|
@verbatim
|
||
|
==============================================================================
|
||
|
##### How to use this driver #####
|
||
|
==============================================================================
|
||
|
[..]
|
||
|
(#) This driver is used to drive the MX25R6435F QSPI external
|
||
|
memory mounted on STM32L496G-DISCO evaluation board.
|
||
|
|
||
|
(#) This driver need a specific component driver (MX25R6435F) 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. The BSP_QSPI_DeInit() can be used
|
||
|
to deactivate the QSPI interface.
|
||
|
|
||
|
(#) 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 to the QSPI memory in memory-mapped mode is possible after
|
||
|
the call of the function BSP_QSPI_EnableMemoryMappedMode().
|
||
|
(++) 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)
|
||
|
(++) Perform erase sector operation using the function BSP_QSPI_Erase_Sector()
|
||
|
which is not blocking. So the function BSP_QSPI_GetStatus() should be used
|
||
|
to check if the memory is busy, and the functions BSP_QSPI_SuspendErase()/
|
||
|
BSP_QSPI_ResumeErase() can be used to perform other operations during the
|
||
|
sector erase.
|
||
|
(++) Deep power down of the QSPI memory is managed with the call of the functions
|
||
|
BSP_QSPI_EnterDeepPowerDown()/BSP_QSPI_LeaveDeepPowerDown()
|
||
|
@endverbatim
|
||
|
******************************************************************************
|
||
|
* @attention
|
||
|
*
|
||
|
* <h2><center>© Copyright (c) 2017 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 "stm32l496g_discovery_qspi.h"
|
||
|
|
||
|
/** @addtogroup BSP
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/** @addtogroup STM32L496G_DISCOVERY
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/** @defgroup STM32L496G_DISCOVERY_QSPI STM32L496G-DISCOVERY QSPI
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/* Private constants --------------------------------------------------------*/
|
||
|
/** @defgroup STM32L496G_DISCOVERY_QSPI_Private_Constants Private Constants
|
||
|
* @{
|
||
|
*/
|
||
|
#define QSPI_QUAD_DISABLE 0x0
|
||
|
#define QSPI_QUAD_ENABLE 0x1
|
||
|
|
||
|
#define QSPI_HIGH_PERF_DISABLE 0x0
|
||
|
#define QSPI_HIGH_PERF_ENABLE 0x1
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
/* Private variables ---------------------------------------------------------*/
|
||
|
|
||
|
/** @defgroup STM32L496G_DISCOVERY_QSPI_Private_Variables Private Variables
|
||
|
* @{
|
||
|
*/
|
||
|
QSPI_HandleTypeDef QSPIHandle;
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
|
||
|
/* Private functions ---------------------------------------------------------*/
|
||
|
|
||
|
/** @defgroup STM32L496G_DISCOVERY_QSPI_Private_Functions Private Functions
|
||
|
* @{
|
||
|
*/
|
||
|
static void QSPI_MspInit(void);
|
||
|
static void QSPI_MspDeInit(void);
|
||
|
static uint8_t QSPI_ResetMemory(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_QuadMode(QSPI_HandleTypeDef *hqspi, uint8_t Operation);
|
||
|
static uint8_t QSPI_HighPerfMode(QSPI_HandleTypeDef *hqspi, uint8_t Operation);
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/* Exported functions ---------------------------------------------------------*/
|
||
|
|
||
|
/** @addtogroup STM32L496G_DISCOVERY_QSPI_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 */
|
||
|
QSPI_MspInit();
|
||
|
|
||
|
/* QSPI initialization */
|
||
|
QSPIHandle.Init.ClockPrescaler = 2; /* QSPI clock = 80MHz / (ClockPrescaler+1) = 26.67MHz */
|
||
|
QSPIHandle.Init.FifoThreshold = 4;
|
||
|
QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
|
||
|
QSPIHandle.Init.FlashSize = POSITION_VAL(MX25R6435F_FLASH_SIZE) - 1;
|
||
|
QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
|
||
|
QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
|
||
|
|
||
|
if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* QSPI memory reset */
|
||
|
if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK)
|
||
|
{
|
||
|
return QSPI_NOT_SUPPORTED;
|
||
|
}
|
||
|
|
||
|
/* QSPI quad enable */
|
||
|
if (QSPI_QuadMode(&QSPIHandle, QSPI_QUAD_ENABLE) != QSPI_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* High performance mode enable */
|
||
|
if (QSPI_HighPerfMode(&QSPIHandle, QSPI_HIGH_PERF_ENABLE) != QSPI_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Re-configure the clock for the high performance mode */
|
||
|
QSPIHandle.Init.ClockPrescaler = 1; /* QSPI clock = 80MHz / (ClockPrescaler+1) = 40MHz */
|
||
|
|
||
|
if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
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 */
|
||
|
QSPI_MspDeInit();
|
||
|
|
||
|
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 sCommand;
|
||
|
|
||
|
/* Initialize the read command */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = QUAD_INOUT_READ_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
|
||
|
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
|
||
|
sCommand.Address = ReadAddr;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES;
|
||
|
sCommand.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS;
|
||
|
sCommand.AlternateBytes = MX25R6435F_ALT_BYTES_NO_PE_MODE;
|
||
|
sCommand.DataMode = QSPI_DATA_4_LINES;
|
||
|
sCommand.DummyCycles = MX25R6435F_DUMMY_CYCLES_READ_QUAD;
|
||
|
sCommand.NbData = Size;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
||
|
|
||
|
/* Configure the command */
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 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 sCommand;
|
||
|
uint32_t end_addr, current_size, current_addr;
|
||
|
|
||
|
/* Calculation of the size between the write address and the end of the page */
|
||
|
current_size = MX25R6435F_PAGE_SIZE - (WriteAddr % MX25R6435F_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 */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = QUAD_PAGE_PROG_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
|
||
|
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||
|
sCommand.DataMode = QSPI_DATA_4_LINES;
|
||
|
sCommand.DummyCycles = 0;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
||
|
|
||
|
/* Perform the write page by page */
|
||
|
do
|
||
|
{
|
||
|
sCommand.Address = current_addr;
|
||
|
sCommand.NbData = current_size;
|
||
|
|
||
|
/* Enable write operations */
|
||
|
if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Configure the command */
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 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 + MX25R6435F_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : MX25R6435F_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 sCommand;
|
||
|
|
||
|
/* Initialize the erase command */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = BLOCK_ERASE_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
|
||
|
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
|
||
|
sCommand.Address = BlockAddress;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||
|
sCommand.DataMode = QSPI_DATA_NONE;
|
||
|
sCommand.DummyCycles = 0;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.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, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Configure automatic polling mode to wait for end of erase */
|
||
|
if (QSPI_AutoPollingMemReady(&QSPIHandle, MX25R6435F_BLOCK_ERASE_MAX_TIME) != QSPI_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
return QSPI_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Erases the specified sector of the QSPI memory.
|
||
|
* @param Sector : Sector address to erase (0 to 255)
|
||
|
* @retval QSPI memory status
|
||
|
* @note This function is non blocking meaning that sector erase
|
||
|
* operation is started but not completed when the function
|
||
|
* returns. Application has to call BSP_QSPI_GetStatus()
|
||
|
* to know when the device is available again (i.e. erase operation
|
||
|
* completed).
|
||
|
*/
|
||
|
uint8_t BSP_QSPI_Erase_Sector(uint32_t Sector)
|
||
|
{
|
||
|
QSPI_CommandTypeDef sCommand;
|
||
|
|
||
|
if (Sector >= (uint32_t)(MX25R6435F_FLASH_SIZE / MX25R6435F_SECTOR_SIZE))
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Initialize the erase command */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = SECTOR_ERASE_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
|
||
|
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
|
||
|
sCommand.Address = (Sector * MX25R6435F_SECTOR_SIZE);
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||
|
sCommand.DataMode = QSPI_DATA_NONE;
|
||
|
sCommand.DummyCycles = 0;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.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, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_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 sCommand;
|
||
|
|
||
|
/* Initialize the erase command */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = CHIP_ERASE_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||
|
sCommand.DataMode = QSPI_DATA_NONE;
|
||
|
sCommand.DummyCycles = 0;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.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, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Configure automatic polling mode to wait for end of erase */
|
||
|
if (QSPI_AutoPollingMemReady(&QSPIHandle, MX25R6435F_CHIP_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 sCommand;
|
||
|
uint8_t reg;
|
||
|
|
||
|
/* Initialize the read security register command */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = READ_SEC_REG_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||
|
sCommand.DataMode = QSPI_DATA_1_LINE;
|
||
|
sCommand.DummyCycles = 0;
|
||
|
sCommand.NbData = 1;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
||
|
|
||
|
/* Configure the command */
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Reception of the data */
|
||
|
if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Check the value of the register */
|
||
|
if ((reg & (MX25R6435F_SECR_P_FAIL | MX25R6435F_SECR_E_FAIL)) != 0)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
else if ((reg & (MX25R6435F_SECR_PSB | MX25R6435F_SECR_ESB)) != 0)
|
||
|
{
|
||
|
return QSPI_SUSPENDED;
|
||
|
}
|
||
|
|
||
|
/* Initialize the read status register command */
|
||
|
sCommand.Instruction = READ_STATUS_REG_CMD;
|
||
|
|
||
|
/* Configure the command */
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Reception of the data */
|
||
|
if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Check the value of the register */
|
||
|
if ((reg & MX25R6435F_SR_WIP) != 0)
|
||
|
{
|
||
|
return QSPI_BUSY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return QSPI_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @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 = MX25R6435F_FLASH_SIZE;
|
||
|
pInfo->EraseSectorSize = MX25R6435F_SECTOR_SIZE;
|
||
|
pInfo->EraseSectorsNumber = (MX25R6435F_FLASH_SIZE / MX25R6435F_SECTOR_SIZE);
|
||
|
pInfo->ProgPageSize = MX25R6435F_PAGE_SIZE;
|
||
|
pInfo->ProgPagesNumber = (MX25R6435F_FLASH_SIZE / MX25R6435F_PAGE_SIZE);
|
||
|
|
||
|
return QSPI_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Configure the QSPI in memory-mapped mode
|
||
|
* @retval QSPI memory status
|
||
|
*/
|
||
|
uint8_t BSP_QSPI_EnableMemoryMappedMode(void)
|
||
|
{
|
||
|
QSPI_CommandTypeDef sCommand;
|
||
|
QSPI_MemoryMappedTypeDef sMemMappedCfg;
|
||
|
|
||
|
/* Configure the command for the read instruction */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = QUAD_INOUT_READ_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
|
||
|
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES;
|
||
|
sCommand.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS;
|
||
|
sCommand.AlternateBytes = MX25R6435F_ALT_BYTES_NO_PE_MODE;
|
||
|
sCommand.DataMode = QSPI_DATA_4_LINES;
|
||
|
sCommand.DummyCycles = MX25R6435F_DUMMY_CYCLES_READ_QUAD;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
||
|
|
||
|
/* Configure the memory mapped mode */
|
||
|
sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
|
||
|
|
||
|
if (HAL_QSPI_MemoryMapped(&QSPIHandle, &sCommand, &sMemMappedCfg) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
return QSPI_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This function suspends an ongoing erase command.
|
||
|
* @retval QSPI memory status
|
||
|
*/
|
||
|
uint8_t BSP_QSPI_SuspendErase(void)
|
||
|
{
|
||
|
QSPI_CommandTypeDef sCommand;
|
||
|
|
||
|
/* Check whether the device is busy (erase operation is
|
||
|
in progress).
|
||
|
*/
|
||
|
if (BSP_QSPI_GetStatus() == QSPI_BUSY)
|
||
|
{
|
||
|
/* Initialize the erase command */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = PROG_ERASE_SUSPEND_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||
|
sCommand.DataMode = QSPI_DATA_NONE;
|
||
|
sCommand.DummyCycles = 0;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
||
|
|
||
|
/* Send the command */
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
if (BSP_QSPI_GetStatus() == QSPI_SUSPENDED)
|
||
|
{
|
||
|
return QSPI_OK;
|
||
|
}
|
||
|
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
return QSPI_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This function resumes a paused erase command.
|
||
|
* @retval QSPI memory status
|
||
|
*/
|
||
|
uint8_t BSP_QSPI_ResumeErase(void)
|
||
|
{
|
||
|
QSPI_CommandTypeDef sCommand;
|
||
|
|
||
|
/* Check whether the device is in suspended state */
|
||
|
if (BSP_QSPI_GetStatus() == QSPI_SUSPENDED)
|
||
|
{
|
||
|
/* Initialize the erase command */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = PROG_ERASE_RESUME_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||
|
sCommand.DataMode = QSPI_DATA_NONE;
|
||
|
sCommand.DummyCycles = 0;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
||
|
|
||
|
/* Send the command */
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
When this command is executed, the status register write in progress bit is set to 1, and
|
||
|
the flag status register program erase controller bit is set to 0. This command is ignored
|
||
|
if the device is not in a suspended state.
|
||
|
*/
|
||
|
|
||
|
if (BSP_QSPI_GetStatus() == QSPI_BUSY)
|
||
|
{
|
||
|
return QSPI_OK;
|
||
|
}
|
||
|
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
return QSPI_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This function enter the QSPI memory in deep power down mode.
|
||
|
* @retval QSPI memory status
|
||
|
*/
|
||
|
uint8_t BSP_QSPI_EnterDeepPowerDown(void)
|
||
|
{
|
||
|
QSPI_CommandTypeDef sCommand;
|
||
|
|
||
|
/* Initialize the deep power down command */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = DEEP_POWER_DOWN_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||
|
sCommand.DataMode = QSPI_DATA_NONE;
|
||
|
sCommand.DummyCycles = 0;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
||
|
|
||
|
/* Send the command */
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* --- Memory takes 10us max to enter deep power down --- */
|
||
|
/* --- At least 30us should be respected before leaving deep power down --- */
|
||
|
|
||
|
return QSPI_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This function leave the QSPI memory from deep power down mode.
|
||
|
* @retval QSPI memory status
|
||
|
*/
|
||
|
uint8_t BSP_QSPI_LeaveDeepPowerDown(void)
|
||
|
{
|
||
|
QSPI_CommandTypeDef sCommand;
|
||
|
|
||
|
/* Initialize the erase command */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = NO_OPERATION_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||
|
sCommand.DataMode = QSPI_DATA_NONE;
|
||
|
sCommand.DummyCycles = 0;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
||
|
|
||
|
/* Send the command */
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* --- A NOP command is sent to the memory, as the nCS should be low for at least 20 ns --- */
|
||
|
/* --- Memory takes 35us min to leave deep power down --- */
|
||
|
|
||
|
return QSPI_OK;
|
||
|
}
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/** @addtogroup STM32L496G_DISCOVERY_QSPI_Private_Functions
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @brief Initializes the QSPI MSP.
|
||
|
* @retval None
|
||
|
*/
|
||
|
static void QSPI_MspInit(void)
|
||
|
{
|
||
|
GPIO_InitTypeDef GPIO_InitStruct;
|
||
|
|
||
|
/* Enable the QuadSPI memory interface clock */
|
||
|
__HAL_RCC_QSPI_CLK_ENABLE();
|
||
|
|
||
|
/* Reset the QuadSPI memory interface */
|
||
|
__HAL_RCC_QSPI_FORCE_RESET();
|
||
|
__HAL_RCC_QSPI_RELEASE_RESET();
|
||
|
|
||
|
/* Enable GPIO clocks */
|
||
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||
|
|
||
|
/* QSPI CS GPIO pin configuration */
|
||
|
GPIO_InitStruct.Pin = GPIO_PIN_11;
|
||
|
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||
|
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||
|
GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
|
||
|
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||
|
|
||
|
/* QSPI CLK, D0, D1, D2 and D3 GPIO pins configuration */
|
||
|
GPIO_InitStruct.Pin = (GPIO_PIN_3 | GPIO_PIN_6 | GPIO_PIN_7);
|
||
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||
|
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||
|
|
||
|
GPIO_InitStruct.Pin = (GPIO_PIN_0 | GPIO_PIN_1);
|
||
|
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief De-Initializes the QSPI MSP.
|
||
|
* @retval None
|
||
|
*/
|
||
|
static void QSPI_MspDeInit(void)
|
||
|
{
|
||
|
GPIO_InitTypeDef GPIO_InitStruct;
|
||
|
|
||
|
/* QSPI CLK, CS, D0-D3 GPIO pins de-configuration */
|
||
|
|
||
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||
|
|
||
|
HAL_GPIO_DeInit(GPIOA, (GPIO_PIN_6 | GPIO_PIN_7));
|
||
|
HAL_GPIO_DeInit(GPIOB, (GPIO_PIN_0 | GPIO_PIN_1));
|
||
|
|
||
|
/* Set GPIOB pin 11 in pull up mode (optimum default setting) */
|
||
|
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||
|
GPIO_InitStruct.Pin = GPIO_PIN_11;
|
||
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||
|
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||
|
|
||
|
/* Set GPIOA pin 3 in no pull, low state (optimum default setting) */
|
||
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP ;
|
||
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||
|
GPIO_InitStruct.Pin = GPIO_PIN_3;
|
||
|
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||
|
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
|
||
|
|
||
|
/* Reset the QuadSPI memory interface */
|
||
|
__HAL_RCC_QSPI_FORCE_RESET();
|
||
|
__HAL_RCC_QSPI_RELEASE_RESET();
|
||
|
|
||
|
/* Disable the QuadSPI memory interface clock */
|
||
|
__HAL_RCC_QSPI_CLK_DISABLE();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This function reset the QSPI memory.
|
||
|
* @param hqspi : QSPI handle
|
||
|
* @retval None
|
||
|
*/
|
||
|
static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi)
|
||
|
{
|
||
|
QSPI_CommandTypeDef sCommand;
|
||
|
|
||
|
/* Initialize the reset enable command */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = RESET_ENABLE_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||
|
sCommand.DataMode = QSPI_DATA_NONE;
|
||
|
sCommand.DummyCycles = 0;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
||
|
|
||
|
/* Send the command */
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Send the reset memory command */
|
||
|
sCommand.Instruction = RESET_MEMORY_CMD;
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Configure automatic polling mode to wait the memory is ready */
|
||
|
if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_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 sCommand;
|
||
|
QSPI_AutoPollingTypeDef sConfig;
|
||
|
|
||
|
/* Enable write operations */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = WRITE_ENABLE_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||
|
sCommand.DataMode = QSPI_DATA_NONE;
|
||
|
sCommand.DummyCycles = 0;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
||
|
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Configure automatic polling mode to wait for write enabling */
|
||
|
sConfig.Match = MX25R6435F_SR_WEL;
|
||
|
sConfig.Mask = MX25R6435F_SR_WEL;
|
||
|
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
|
||
|
sConfig.StatusBytesSize = 1;
|
||
|
sConfig.Interval = 0x10;
|
||
|
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
|
||
|
|
||
|
sCommand.Instruction = READ_STATUS_REG_CMD;
|
||
|
sCommand.DataMode = QSPI_DATA_1_LINE;
|
||
|
|
||
|
if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, 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 : Timeout for auto-polling
|
||
|
* @retval None
|
||
|
*/
|
||
|
static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout)
|
||
|
{
|
||
|
QSPI_CommandTypeDef sCommand;
|
||
|
QSPI_AutoPollingTypeDef sConfig;
|
||
|
|
||
|
/* Configure automatic polling mode to wait for memory ready */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = READ_STATUS_REG_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||
|
sCommand.DataMode = QSPI_DATA_1_LINE;
|
||
|
sCommand.DummyCycles = 0;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
||
|
|
||
|
sConfig.Match = 0;
|
||
|
sConfig.Mask = MX25R6435F_SR_WIP;
|
||
|
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
|
||
|
sConfig.StatusBytesSize = 1;
|
||
|
sConfig.Interval = 0x10;
|
||
|
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
|
||
|
|
||
|
if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, Timeout) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
return QSPI_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This function enables/disables the Quad mode of the memory.
|
||
|
* @param hqspi : QSPI handle
|
||
|
* @param Operation : QSPI_QUAD_ENABLE or QSPI_QUAD_DISABLE mode
|
||
|
* @retval None
|
||
|
*/
|
||
|
static uint8_t QSPI_QuadMode(QSPI_HandleTypeDef *hqspi, uint8_t Operation)
|
||
|
{
|
||
|
QSPI_CommandTypeDef sCommand;
|
||
|
uint8_t reg;
|
||
|
|
||
|
/* Read status register */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = READ_STATUS_REG_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||
|
sCommand.DataMode = QSPI_DATA_1_LINE;
|
||
|
sCommand.DummyCycles = 0;
|
||
|
sCommand.NbData = 1;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
||
|
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Enable write operations */
|
||
|
if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Activate/deactivate the Quad mode */
|
||
|
if (Operation == QSPI_QUAD_ENABLE)
|
||
|
{
|
||
|
SET_BIT(reg, MX25R6435F_SR_QE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CLEAR_BIT(reg, MX25R6435F_SR_QE);
|
||
|
}
|
||
|
|
||
|
sCommand.Instruction = WRITE_STATUS_CFG_REG_CMD;
|
||
|
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
if (HAL_QSPI_Transmit(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Wait that memory is ready */
|
||
|
if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Check the configuration has been correctly done */
|
||
|
sCommand.Instruction = READ_STATUS_REG_CMD;
|
||
|
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
if ((((reg & MX25R6435F_SR_QE) == 0) && (Operation == QSPI_QUAD_ENABLE)) ||
|
||
|
(((reg & MX25R6435F_SR_QE) != 0) && (Operation == QSPI_QUAD_DISABLE)))
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
return QSPI_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This function enables/disables the high performance mode of the memory.
|
||
|
* @param hqspi : QSPI handle
|
||
|
* @param Operation : QSPI_HIGH_PERF_ENABLE or QSPI_HIGH_PERF_DISABLE high performance mode
|
||
|
* @retval None
|
||
|
*/
|
||
|
static uint8_t QSPI_HighPerfMode(QSPI_HandleTypeDef *hqspi, uint8_t Operation)
|
||
|
{
|
||
|
QSPI_CommandTypeDef sCommand;
|
||
|
uint8_t reg[3];
|
||
|
|
||
|
/* Read status register */
|
||
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||
|
sCommand.Instruction = READ_STATUS_REG_CMD;
|
||
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
||
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||
|
sCommand.DataMode = QSPI_DATA_1_LINE;
|
||
|
sCommand.DummyCycles = 0;
|
||
|
sCommand.NbData = 1;
|
||
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||
|
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
||
|
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
if (HAL_QSPI_Receive(&QSPIHandle, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Read configuration registers */
|
||
|
sCommand.Instruction = READ_CFG_REG_CMD;
|
||
|
sCommand.NbData = 2;
|
||
|
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
if (HAL_QSPI_Receive(&QSPIHandle, &(reg[1]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Enable write operations */
|
||
|
if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Activate/deactivate the Quad mode */
|
||
|
if (Operation == QSPI_HIGH_PERF_ENABLE)
|
||
|
{
|
||
|
SET_BIT(reg[2], MX25R6435F_CR2_LH_SWITCH);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CLEAR_BIT(reg[2], MX25R6435F_CR2_LH_SWITCH);
|
||
|
}
|
||
|
|
||
|
sCommand.Instruction = WRITE_STATUS_CFG_REG_CMD;
|
||
|
sCommand.NbData = 3;
|
||
|
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
if (HAL_QSPI_Transmit(&QSPIHandle, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Wait that memory is ready */
|
||
|
if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Check the configuration has been correctly done */
|
||
|
sCommand.Instruction = READ_CFG_REG_CMD;
|
||
|
sCommand.NbData = 2;
|
||
|
|
||
|
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
if (HAL_QSPI_Receive(&QSPIHandle, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
if ((((reg[1] & MX25R6435F_CR2_LH_SWITCH) == 0) && (Operation == QSPI_HIGH_PERF_ENABLE)) ||
|
||
|
(((reg[1] & MX25R6435F_CR2_LH_SWITCH) != 0) && (Operation == QSPI_HIGH_PERF_DISABLE)))
|
||
|
{
|
||
|
return QSPI_ERROR;
|
||
|
}
|
||
|
|
||
|
return QSPI_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||
|
|