2020-09-01 09:31 AM
Hello, I want to use external QSPI flash memory micron n25q128 in Memory mapped mode STM32F746 Discovery. I used below code to make external flash in memory mapped mode but I can see incorrect data at external flash. I am not sure whats wrong in my code. any suggestions ? Thanks
#define DUMMY_CLOCK_CYCLES_READ_QUAD 10
#define QUAD_OUT_FAST_READ_CMD 0x6B
static void MX_QUADSPI_Init(void)
{
/* USER CODE BEGIN QUADSPI_Init 0 */
/* USER CODE END QUADSPI_Init 0 */
/* USER CODE BEGIN QUADSPI_Init 1 */
/* USER CODE END QUADSPI_Init 1 */
/* QUADSPI parameter configuration*/
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 255;
hqspi.Init.FifoThreshold = 1;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
hqspi.Init.FlashSize = 1;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.FlashID = QSPI_FLASH_ID_1;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN QUADSPI_Init 2 */
// uint8_t CSP_QSPI_EnableMemoryMappedMode(void) {
QSPI_CommandTypeDef sCommand;
QSPI_MemoryMappedTypeDef sMemMappedCfg;
/* Enable Memory-Mapped mode-------------------------------------------------- */
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;
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
sCommand.DataMode = QSPI_DATA_4_LINES;
sCommand.NbData = 0;
sCommand.Address = 0;
sCommand.Instruction = QUAD_OUT_FAST_READ_CMD;
sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD;
sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
if (HAL_QSPI_MemoryMapped(&hqspi, &sCommand, &sMemMappedCfg) != HAL_OK) {
Error_Handler();
}
/* USER CODE END QUADSPI_Init 2 */
}
2020-09-01 10:01 AM
Size parameter is entirely wrong.
ClockPrescaler will be very slow.
SampleShifting and ChipSelectHighTime not consistent with BSP.
Not programming dummy cycles into IC.
BSP uses 0xEB command, where addresses broken into 4-bit groups.
2020-09-01 09:13 PM
@Community member I updated size ,Clock Prescaler. Also added dummy cycle into IC. Have some doubt ,
SampleShifting and ChipSelectHighTime not consistent with BSP.
- Do you mean it sample shifting should be half cycle and chip high time should be more than 1? I didn't find correct value of chip high time in datasheet, can u suggest?
BSP uses 0xEB command, where addresses broken into 4-bit groups.
-you mean before memory maped mode, we should send command QUAD INPUT/OUTPUT FAST READ 0xEB.
Thanks
#define READ_VOL_CFG_REG_CMD 0x85
#define WRITE_VOL_CFG_REG_CMD 0x81
/* Write Operations */
#define WRITE_ENABLE_CMD 0x06
#define READ_STATUS_REG_CMD 0x05
uint8_t StatusMatch = 0;
void HAL_QSPI_StatusMatchCallback(QSPI_HandleTypeDef *hqspi)
{
StatusMatch = 1;
}
/**
* @brief This function sends a Write Enable and waits until it is effective.
* @param hqspi: QSPI handle
* @retval None
*/
static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspiH)
{
QSPI_CommandTypeDef s_command;
QSPI_AutoPollingTypeDef sConfig;
/* Enable write operations ------------------------------------------ */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
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(hqspiH, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
/* Configure automatic polling mode to wait for write enabling ---- */
sConfig.Match = 0x02; // 2nd bit high means "Write enable latch SET"
sConfig.Mask = 0x02;
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.Interval = 0x10;
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
s_command.Instruction = READ_STATUS_REG_CMD;
s_command.DataMode = QSPI_DATA_1_LINE;
StatusMatch = 0;
if (HAL_QSPI_AutoPolling(hqspiH, &s_command, &sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
while(!StatusMatch){
}
}
/**
* @brief This function configures the dummy cycles on memory side.
* @param hqspi: QSPI handle
* @retval None
*/
static void QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspiH)
{
QSPI_CommandTypeDef sCommand;
uint8_t reg;
/* Read Volatile Configuration register --------------------------- */
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = READ_VOL_CFG_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;
sCommand.NbData = 1;
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
if (HAL_QSPI_Receive(&hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
/* Enable write operations ---------------------------------------- */
QSPI_WriteEnable(&hqspi);
/* Write Volatile Configuration register (with new dummy cycles) -- */
sCommand.Instruction = WRITE_VOL_CFG_REG_CMD;
MODIFY_REG(reg, 0xF0, (DUMMY_CLOCK_CYCLES_READ_QUAD << POSITION_VAL(0xF0)));
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
if (HAL_QSPI_Transmit(&hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief QUADSPI Initialization Function
* @param None
* @retval None
*/
static void MX_QUADSPI_Init(void)
{
/* USER CODE BEGIN QUADSPI_Init 0 */
/* USER CODE END QUADSPI_Init 0 */
/* USER CODE BEGIN QUADSPI_Init 1 */
/* USER CODE END QUADSPI_Init 1 */
/* QUADSPI parameter configuration*/
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 2;
hqspi.Init.FifoThreshold = 1;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
hqspi.Init.FlashSize = 23;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.FlashID = QSPI_FLASH_ID_1;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN QUADSPI_Init 2 */
// uint8_t CSP_QSPI_EnableMemoryMappedMode(void) {
QSPI_CommandTypeDef sCommand = {0};
QSPI_MemoryMappedTypeDef sMemMappedCfg = {0};
/* Configure Volatile Configuration register (with new dummy cycles) */
QSPI_DummyCyclesCfg(&hqspi);
/* Enable Memory-Mapped mode-------------------------------------------------- */
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;
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
sCommand.DataMode = QSPI_DATA_4_LINES;
sCommand.NbData = 0;
sCommand.Address = 0;
sCommand.Instruction = QUAD_OUT_FAST_READ_CMD;
sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD;
sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
if (HAL_QSPI_MemoryMapped(&hqspi, &sCommand, &sMemMappedCfg) != HAL_OK) {
Error_Handler();
}
// }
/* USER CODE END QUADSPI_Init 2 */
}
2020-09-02 01:34 AM
I updated the code and now am able to load data from external flash memory but during beginner display is flickering. Please check video using below link.
https://drive.google.com/file/d/1Y_qbsM-2iQcHDFH6mA2lt7MuAzxujCqu/view?usp=sharing
I m displaying logo and text "REVOS" for 1 second before main screen and during same time display is flickering. When I was storing data in internal flash, there was no such issue.
void memoryMaped(void){
QSPI_CommandTypeDef sCommand = { 0 };
QSPI_MemoryMappedTypeDef sMemMappedCfg = {0};
/* Enable write operations ------------------------------------------- */
/* Configure Volatile Configuration register (with new dummy cycles) */
QSPI_DummyCyclesCfg(&hqspi);
/* Enable Memory-Mapped mode-------------------------------------------------- */
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;
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
sCommand.DataMode = QSPI_DATA_4_LINES;
sCommand.NbData = 0;
sCommand.Address = 0;
sCommand.Instruction = QUAD_OUT_FAST_READ_CMD;
sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD;
sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
if (HAL_QSPI_MemoryMapped(&hqspi, &sCommand, &sMemMappedCfg) != HAL_OK) {
Error_Handler();
}
/* USER CODE END QUADSPI_Init 2 */
}
void HAL_QSPI_StatusMatchCallback(QSPI_HandleTypeDef *hqspi)
{
StatusMatch = 1;
}
/**
* @brief This function sends a Write Enable and waits until it is effective.
* @param hqspi: QSPI handle
* @retval None
*/
static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspiH)
{
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(hqspiH, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
/* Configure automatic polling mode to wait for write enabling ---- */
sConfig.Match = 0x02; // 2nd bit high means "Write enable latch SET"
sConfig.Mask = 0x02;
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;
StatusMatch = 0;
if (HAL_QSPI_AutoPolling_IT(hqspiH, &sCommand, &sConfig) != HAL_OK)
{
Error_Handler();
}
while(!StatusMatch){
}
}
/**
* @brief This function configures the dummy cycles on memory side.
* @param hqspi: QSPI handle
* @retval None
*/
static void QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspiH)
{
QSPI_CommandTypeDef sCommand;
uint8_t reg;
/* Read Volatile Configuration register --------------------------- */
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = READ_VOL_CFG_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;
sCommand.NbData = 1;
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
if (HAL_QSPI_Receive(&hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
/* Enable write operations ---------------------------------------- */
QSPI_WriteEnable(&hqspi);
/* Write Volatile Configuration register (with new dummy cycles) -- */
sCommand.Instruction = WRITE_VOL_CFG_REG_CMD;
MODIFY_REG(reg, 0xF0, (DUMMY_CLOCK_CYCLES_READ_QUAD << POSITION_VAL(0xF0)));
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
if (HAL_QSPI_Transmit(&hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
}
uint8_t QSPI_RxData[31] = {0};
uint8_t QSPI_working = false;
/**
* @brief QUADSPI Initialization Function
* @param None
* @retval None
*/
static void MX_QUADSPI_Init(void) {
/* USER CODE BEGIN QUADSPI_Init 0 */
/* USER CODE END QUADSPI_Init 0 */
/* USER CODE BEGIN QUADSPI_Init 1 */
/* USER CODE END QUADSPI_Init 1 */
/* QUADSPI parameter configuration*/
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 2;
hqspi.Init.FifoThreshold = 1;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
hqspi.Init.FlashSize = 23;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.FlashID = QSPI_FLASH_ID_1;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK) {
Error_Handler();
}
/* USER CODE BEGIN QUADSPI_Init 2 */
QSPI_CommandTypeDef sCommand = { 0 };
QSPI_MemoryMappedTypeDef sMemMappedCfg = {0};
sCommand.Instruction = 0x00; //0x9E;
sCommand.Address = 0x9E;
sCommand.AlternateBytes = 0x00;
sCommand.AddressSize = QSPI_ADDRESS_8_BITS; //QSPI_ADDRESS_16_BITS;
sCommand.AlternateBytesSize = 0;
sCommand.DummyCycles = 0;
sCommand.InstructionMode = QSPI_INSTRUCTION_NONE;//QSPI_INSTRUCTION_1_LINE;
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_1_LINE;
sCommand.NbData = 4;
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
//HAL_QSPI_Transmit(&hqspi, QSPI_TxData, 0xffff);
HAL_QSPI_Receive(&hqspi, QSPI_RxData, 0x00ff);
if (QSPI_RxData[0] == 0x20 && QSPI_RxData[1] == 0xBA
&& QSPI_RxData[2] == 0x18 && QSPI_RxData[3] == 0x10) {
QSPI_working = true;
//HAL_GPIO_WritePin(GPIOC, LOWBATT_LED_Pin, GPIO_PIN_RESET);
}
}