'Driver QUADSPI W25q128jv on STM32 Project not working, can't seem to write on it

I am trying to initialize my W25Q128jv External Flash in a my project, but I am not able to write on the external flash and I think it could be because of the Memory Mapping Mode but I really don't know.

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 = 1;
  hqspi.Init.FifoThreshold = 4;
  hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
  hqspi.Init.FlashSize = 23;
  hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_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 */
  BSP_QSPI_Init();


  /* USER CODE END QUADSPI_Init 2 */

}

Here the driver:

uint8_t BSP_QSPI_Init(void) { QSPI_CommandTypeDef s_command; uint8_t value = W25Q128JV_FSR_QE;

/* QSPI memory reset */ if (QSPI_ResetMemory() != QSPI_OK) { return QSPI_NOT_SUPPORTED; }/* Enable write operations */
if (QSPI_WriteEnable() != QSPI_OK)
{
    return QSPI_ERROR;
}

/* Set status register for Quad Enable,the Quad IO2 and IO3 pins are enable */
s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction       = WRITE_STATUS_REG2_CMD; s_command.AddressMode       = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode          = QSPI_DATA_1_LINE; 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(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } / Transmit the data */ if (HAL_QSPI_Transmit(&hqspi, &value, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; }

/* automatic polling mode to wait for memory ready */ if (QSPI_AutoPollingMemReady(W25Q128JV_WRITE_STATUS_REG_TIME_MS) != QSPI_OK) { return QSPI_ERROR; } BSP_QSPI_MemoryMappedMode(); //BSP_QSPI_Erase(0x90000000, 1000); return QSPI_OK; } /BSP_QSPI_Init/

static uint8_t QSPI_ResetMemory(void) { 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; }

/* Configure automatic polling mode to wait the memory is ready */ if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) { return QSPI_ERROR; }

return QSPI_OK; }



static uint8_t QSPI_WriteEnable(void) {
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(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {

    return (QSPI_ERROR);
}

/* Configure automatic polling mode to wait for write enabling ---- */
sConfig.Match = W25Q128JV_FSR_WREN;
sConfig.Mask = W25Q128JV_FSR_WREN;
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.Interval = 0x10;
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;

sCommand.Instruction = READ_STATUS_REG1_CMD;
sCommand.DataMode = QSPI_DATA_1_LINE;
sCommand.NbData = 1;

if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {

    return (QSPI_ERROR);
}

return (QSPI_OK);
} /* QSPI_WriteEnable */

static uint8_t QSPI_AutoPollingMemReady(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_1_LINE;
s_command.Instruction = READ_STATUS_REG1_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_1_LINE;
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;

s_config.Match = 0x00;
s_config.Mask = W25Q128JV_FSR_BUSY;
s_config.MatchMode = QSPI_MATCH_MODE_AND;
s_config.StatusBytesSize = 1;
s_config.Interval = 0x10;
s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;

if (HAL_QSPI_AutoPolling(&hqspi, &s_command, &s_config, Timeout) != HAL_OK) {

    return (QSPI_ERROR);
}

return (QSPI_OK);
} /* QSPI_AutoPollingMemReady */

static uint8_t BSP_QSPI_Write(const 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_addr = 0U;

while (current_addr <= WriteAddr) {

    current_addr += W25Q128JV_PAGE_SIZE;
}

current_size = current_addr - WriteAddr;

/* 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_1_LINE;
s_command.Instruction = QUAD_INPUT_PAGE_PROG_CMD;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_24_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 */
    QSPI_WriteEnable();

    /* Configure the 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 *)((uint32_t)pData), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {

        return (QSPI_ERROR);
    }

    /* Configure automatic polling mode to wait for end of program */
    if (QSPI_AutoPollingMemReady(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 + W25Q128JV_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25Q128JV_PAGE_SIZE;

} while (current_addr < end_addr);

return (QSPI_OK);
} /* BSP_QSPI_Write */

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_1_LINE;
s_command.Instruction = READ_CMD;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.Address = ReadAddr;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = Size;
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, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {

    return (QSPI_ERROR);
}

return (QSPI_OK);
} /* BSP_QSPI_Read */

static void BSP_QSPI_MemoryMappedMode(void) {
QSPI_CommandTypeDef s_command;
QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;

/* Configure the command for the read instruction */
s_command.Instruction = QUAD_INOUT_FAST_READ_CMD;
s_command.Address = 0U;
s_command.AlternateBytes = 0xF0;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS;
s_command.DummyCycles = W25Q128JV_DUMMY_CYCLES_READ_QUAD;
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.AddressMode = QSPI_ADDRESS_4_LINES;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.NbData = 0U;
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 memory mapped mode */
s_mem_mapped_cfg.TimeOutPeriod = 0;
s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;

if (HAL_QSPI_MemoryMapped(&hqspi, &s_command, &s_mem_mapped_cfg) != HAL_OK) {

    Error_Handler();
}
} /* BSP_QSPI_MemoryMappedMode */

static uint8_t BSP_QSPI_Erase(uint32_t Address, uint32_t Size) {
#define TIMEOUTSAFE_MS    1000U

QSPI_CommandTypeDef s_command;

uint16_t Timeout;

/* Initialize the erase command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;

if (Size > W25Q128JV_SECTOR_SIZE) {

    s_command.Instruction = BLOCK_64_ERASE_CMD;

} else {

    s_command.Instruction = SECTOR_ERASE_CMD;
}

s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.Address = Address;
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() != QSPI_OK) {

    return (QSPI_ERROR);
}

/* Send the command */
QSPI_Cplt = 0U;
Timeout = TIMEOUTSAFE_MS;

if (HAL_QSPI_Command_IT(&hqspi, &s_command) != HAL_OK) {

    return (QSPI_ERROR);
}

while ((QSPI_Cplt == 0U) && (Timeout > 0U)) {

    HAL_Delay(1000);
    Timeout--;
}

if (Timeout == 0U) {

    return (QSPI_ERROR);
}

if (s_command.Instruction == BLOCK_64_ERASE_CMD) {

    Timeout = W25Q128JV_BLOCK_64_ERASE_MAX_TIME;

} else if (s_command.Instruction == BLOCK_32_ERASE_CMD) {

    Timeout = W25Q128JV_BLOCK_32_ERASE_MAX_TIME;

} else {

    Timeout = W25Q128JV_SECTOR_ERASE_MAX_TIME;
}

/* Configure automatic polling mode to wait for end of erase */
if (QSPI_AutoPollingMemReady(Timeout) != QSPI_OK) {

    return (QSPI_ERROR);
}

return (QSPI_OK);
} /* BSP_QSPI_Erase*/

For this project I will need my QUADSPI when I will add TouchGFX to save some items, but for now I am only trying to do a for cycle to verify that it works and its performance

uint32_t *flashbuffer = (uint32_t*)0x90000000;
const uint32_t size = 1000;

int begin = HAL_GetTick();
  for(i = 0; i < size; i++)
    {
      flashbuffer[i]=i;
    }
int end = HAL_GetTick();


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source