cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F746 Discovery QSPI Memory mapped mode issue

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 */
 
}

3 REPLIES 3

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.

  1. QSPI_CommandTypeDef sCommand = {0};
  2. QSPI_MemoryMappedTypeDef sMemMappedCfg = {0}; // make sure all fields clear when not initializing

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

@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, &reg, 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, &reg, 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 */
 
}

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, &reg, 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, &reg, 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);
	}
 
}