AnsweredAssumed Answered

STM32L4 QSPI init sequence and operation

Question asked by Lukasz Przenioslo on Mar 13, 2018

Hello there,

I am using STM32L452 series MCU and I am trying to interface with a quad spi memory from Micron (MT25Q series).

I am following the example found in this location:

 

STM32Cube_FW_L4_V1.8.0\Projects\STM32L476G_EVAL\Examples\QSPI\QSPI_MemoryMapped\Src\

 

So far, I have been able to enable writing by executing 06h command and pool for bit setting by using command 05h. This seems to work. Although, if I understood the datasheet correctly, every memory chip is by default set to 1 line SPI mode, not Quad line. This would indicate that the whole example presented in the quoted location is using QSPI in single data line mode? Could someone confirm this please?

 

Anyways, I tried to switch to quad mode by executing "enter quad mode" command code 35h. The command passes through and at this point I cannot check either I have succeed. In the above example, there is a pooling mechanism described where one uses a function that pools a command until. It will stop pooling either at timeout, or if it read data that matches the set mask. This mechanism is used for status register pooling bit 1 (Write enable latch).

 

I wanted to use this similar mechanism in order to pool the Non volatile configuration register (B5h), bit 3 (Quad I/O protocol). If its 0, then quad spi is enabled. But I am getting timeouts. Here are my wrappers:

 

/**
 * @brief    Puts the memory chip into quad SPI mode.
 * @return
 */
HAL_StatusTypeDef qspi_enterQuadMode()
{
    if (!qspi.init)
        return HAL_ERROR;

    HAL_StatusTypeDef retVal = HAL_ERROR;
    do
    {
        osMutexWait(qspi.mut, osWaitForever);

        /* Enable write operations ------------------------------------------ */
        if (HAL_OK != qspi_sendCommand(0x35))
            break;

        qspi.quadOn = true;

        /* Configure automatic polling mode to wait for Quad I/O protocol ---- */
        if (HAL_OK != qspi_autoPool(0xB5, 2, 1 << 3,  0))  // timeout in here
            break;

        retVal = HAL_OK;
    }
    while (0);

    osMutexRelease(qspi.mut);
    return retVal;
}

 

/**
 * @brief    Pools a command and receives data. Finishes after the \ref mask and \ref match are OK.
 * @param     cmd: command to auto pool with.
 * @param     mask: masking bits.
 * @param     match: match bits.
 * @return    HAL_OK on success.
 */
HAL_StatusTypeDef qspi_autoPool(const qspiCmd_t cmd, const uint32_t bytes,
        const uint32_t mask, const uint32_t match)
{
    // check how many status bytes to read
    if ((bytes < QSPI_MIN_STATUS_BYTES) || (bytes > QSPI_MAX_STATUS_BYTES))
        return HAL_ERROR;

    qspi.sAutoPool.Match = match;
    qspi.sAutoPool.Mask = mask;
    qspi.sAutoPool.MatchMode = QSPI_MATCH_MODE_AND;
    qspi.sAutoPool.StatusBytesSize = bytes;
    qspi.sAutoPool.Interval = QSPI_DEFAULT_DUMMY_CYCLES;
    qspi.sAutoPool.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;

    qspi.sCmd.Instruction = cmd;
    qspi.sCmd.InstructionMode = (qspi.quadOn) ? QSPI_INSTRUCTION_4_LINES: QSPI_INSTRUCTION_1_LINE;
    qspi.sCmd.DataMode = (qspi.quadOn) ? QSPI_DATA_4_LINES : QSPI_DATA_1_LINE;
    qspi.sCmd.AddressMode = QSPI_ADDRESS_NONE;
    qspi.sCmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    qspi.sCmd.DummyCycles = 0;
    qspi.sCmd.DdrMode = QSPI_DDR_MODE_DISABLE;
    qspi.sCmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
    qspi.sCmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

    return HAL_QSPI_AutoPolling(qspi.hqspi, &qspi.sCmd, &qspi.sAutoPool, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
}

 

/**
 * @brief    Sends a single command to the memory
 * @param     cmd: command to send.
 * @return    HAL_OK on success.
 */
HAL_StatusTypeDef qspi_sendCommand(const qspiCmd_t cmd)
{
    qspi.sCmd.InstructionMode   = (qspi.quadOn) ? QSPI_INSTRUCTION_4_LINES: QSPI_INSTRUCTION_1_LINE;
    qspi.sCmd.Instruction       = cmd;
    qspi.sCmd.AddressMode       = QSPI_ADDRESS_NONE;
    qspi.sCmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    qspi.sCmd.DataMode          = QSPI_DATA_NONE;
    qspi.sCmd.DummyCycles       = 0;
    qspi.sCmd.DdrMode           = QSPI_DDR_MODE_DISABLE;
    qspi.sCmd.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
    qspi.sCmd.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;

    return HAL_QSPI_Command(qspi.hqspi, &qspi.sCmd, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
}

 

The second thing is: After I configure the qspi for memory mapped mode (using HAL_QSPI_MemoryMapped), do I need to do it each time I want to read something, or does it have to be done in code only once?

I would appreciate all help.

Outcomes