2018-03-14 05:28 AM
Hello there,
I am using STM32L4 series MCU and I am trying to interface with a M25Q Micron memory using QSPI. Following the examples given from ST I have noticed that there are no HAL functions allowing registers reading, that is:
and etc.
In the examples the &sharpdefines for those commands are defined, but never used. Looking into the stm32l4xx_hal_qspi.h/c files, there is no read register command. All I could find is AutoPolling, which I am not sure either it works.
Does those functionalities need to be implemented by myself? I would appreciate all help.
#quad-spi #qspi-flash2018-03-14 10:38 AM
not sure why you need a HAL function
uint32_t tmpreg = 0;
tmpreg = hqspi.Instance->SR; //read the status register2018-03-14 01:45 PM
Thanks for answer,
I didnt mean the status register of the QSPI peripheral of the MCU, but the status register of the external QSPI memory.
2018-03-14 02:06 PM
Look at the BSP code for Disco/Eval boards that have QSPI memory on them. That should at least show you how to send a command and get a response from the external memory.
2018-03-14 02:15 PM
I have looked into:
STM32Cube_FW_L4_V1.8.0\Projects\STM32L476G_EVAL\Examples\QSPIThere are no registers reading examples. Even though I have managed to read the status register using HAL functions ( i think), the same function doesnt work for reading non volatile memory register... Here is the code:
/** * @brief Reads the status register and saves it under \ref status pointer. * @param status: pointer under which the status register will be saved. * @return HAL_OK on succesfull status read. */HAL_StatusTypeDef qspi_readStatusReg(uint8_t* const status){ assert_param(status); QSPI_CommandTypeDef command; qspi_setCommonCmdAndCfg(&command, 0); command.Instruction = e_qspiCmd_ReadStatusReg; command.NbData = 1; // send the command if(HAL_OK != HAL_QSPI_Command(qspi.hqspi, &command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)) return HAL_ERROR; return HAL_QSPI_Receive(qspi.hqspi, status, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);}/** * @brief Sets the common command and configuration parameters. * @param cmd: pointer to the command structure. * @param cfg: pointer to the configuration structure. */static void qspi_setCommonCmdAndCfg(QSPI_CommandTypeDef* const cmd, QSPI_AutoPollingTypeDef* const cfg){ if (cmd) { if (qspi.quadOn) { cmd->InstructionMode = QSPI_INSTRUCTION_4_LINES; cmd->DataMode = QSPI_DATA_4_LINES; cmd->AddressMode = QSPI_ADDRESS_4_LINES; } else { cmd->InstructionMode = QSPI_INSTRUCTION_1_LINE; cmd->DataMode = QSPI_DATA_1_LINE; cmd->AddressMode = QSPI_ADDRESS_1_LINE; } cmd->AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; cmd->DummyCycles = 0; cmd->DdrMode = QSPI_DDR_MODE_DISABLE; cmd->DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; cmd->SIOOMode = QSPI_SIOO_INST_EVERY_CMD; cmd->AddressSize = QSPI_ADDRESS_24_BITS; cmd->Address = 0; } if (cfg) { cfg->MatchMode = QSPI_MATCH_MODE_AND; cfg->Interval = QSPI_DEFAULT_DUMMY_CYCLES; cfg->AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; }}/** * @brief Available QSPI commands */typedef enum{ e_qspiCmd_ReadStatusReg = 0x05, e_qspiCmd_WriteEnable = 0x06, e_qspiCmd_ReadNonvolatileConfigReg = 0xB5, e_qspiCmd_EnterQuadIoMode = 0x35, e_qspiCmd_ResetEnable = 0x66, e_qspiCmd_ResetMemory = 0x99, e_qspiCmd_ReadId = 0x9F, e_qspiCmd_ReadIdMultiIo = 0xAF,} qspiCmd_t;Now when I replace the command 0x05 with 0xB5 and read 2 bytes instead of 1, it should give me the non volatile register, but it doesnt. Is there any misunderstood logic in here?
Also, what does BSP stand for?
2018-03-14 02:47 PM
>
Does those functionalities need to be implemented by myself?
Generally yes unless you find a suitable example project. HAL for STM32 provides API for the SPI controller, not for any specific device behind it. Micron has
https://www.micron.com/products/nor-flash/parallel-nor-flash/m29ew/m29ew-software
, you can try to port them; at least - get the correct sequence of commands.-- pa
2018-03-14 03:07 PM
BSP - Board Support Package
I'd imagine there is response via the DR
void ResetMemory(QSPI_HandleTypeDef *hqspi)
{/* Reset memory config, Cmd in 1 line */ /* Send RESET ENABLE command (0x66) to be able to reset the memory registers */ while(QSPIHandle.Instance->SR & QSPI_FLAG_BUSY); /* Wait for busy flag to be cleared */ QSPIHandle.Instance->CCR = 0x2166; QSPIHandle.Instance->AR = 0; QSPIHandle.Instance->ABR = 0; QSPIHandle.Instance->DLR = 0; __DSB();/* Send RESET command (0x99) to reset the memory registers */
while(QSPIHandle.Instance->SR & QSPI_FLAG_BUSY); /* Wait for busy flag to be cleared */ QSPIHandle.Instance->CCR = 0x2199; QSPIHandle.Instance->AR = 0; QSPIHandle.Instance->ABR = 0; QSPIHandle.Instance->DLR = 0; __DSB();..
Reading/Writing 1-byte CMD, Data
/**
* @brief This function configure the dummy cycles on memory side. * @param hqspi: QSPI handle * @retval None */static void QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi){ 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(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{ Error_Handler(); }if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{ Error_Handler(); }/* Enable write operations ---------------------------------------- */
QSPI_WriteEnable(&QSPIHandle);/* 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(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{ Error_Handler(); }if (HAL_QSPI_Transmit(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{ Error_Handler(); }}2018-03-14 06:26 PM
So was able to us READ ID (0x9F) on the N25Q128A13EF840E used on the STM32F746G-DISCO
20 BA 18 10 00 00 23 42-34 09 23 00 25 00 35 18 07 14 EF 27
extern QSPI_HandleTypeDef QSPIHandle;
static void QSPI_TestReadId(QSPI_HandleTypeDef *hqspi)
{ QSPI_CommandTypeDef sCommand; uint8_t reg[20]; // N25Q128A13EF840E 0x20, 0xBA, 0x18/* Read Id register --------------------------- */
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; sCommand.Instruction = 0x9F; // READ ID 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 = sizeof(reg);if (HAL_QSPI_Command(hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{ puts('ERROR:HAL_QSPI_Command'); Error_Handler(); }memset(reg, 0, sizeof(reg));
if (HAL_QSPI_Receive(hqspi, ®[0], HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { puts('ERROR:HAL_QSPI_Receive'); Error_Handler(); }DumpData(sizeof(reg), (void *)reg);
putchar('\n');}void QSPITest(void)
{ BSP_QSPI_Init();QSPI_TestReadId(&QSPIHandle);
}2018-03-15 12:19 AM
Turvey.Clive
You have played a large role in my electronics and programming saga. This time you have helped as well. I did miss this configuration:
sCommand.AddressMode = QSPI_ADDRESS_NONE;Instead I had QSPI_DATA_1_LINE.
Now the read device ID is correct. Thank you for taking the time and testing this setup on your hardware.
2018-10-02 06:10 AM
Hi,
I am using stm32l486 and interface MT25QL128xx Micron memory using QSPI, but getting an issue in API BSP_QSPI_Init => QSPI_DummyCyclesCfg => QSPI_WriteEnable => HAL_QSPI_AutoPolling=> QSPI_WaitFlagStateUntilTimeout.
It doesn't get flag is in expected state in API "QSPI_WaitFlagStateUntilTimeout".
Could you please help to me figure out. Appreciate, if you could share your working source code.
Thanks,
John