I had also trouble to get QSPI with Arduino/mbed LIB to work (it does not look working).
Based on STM HAL drivers (as native STM32 project) - I got it to work.
Some remarks based on my experience:
- not all commands are 4-4-4, most of the commands needed, e.g. RESET, configure chip etc. are 1-1-1
- 4-4-4 is mainly just the FAST_READ command (see the chip datasheet), just one single, specific READ command
- I had to tweak the timing, mainly via:
hqspi.Init.SampleShifting = QSPI_SHIFTING_SAMPLES;
- also very important to know how many dummy cycles for a FAST_READ command:
#define MT25TL01G_DUMMY_CYCLES_READ 6U //not 8U !
I have used a QSPI driver from a NUCLEO board and modified the parameters, the driver code (names are still for another chip). It was necessary to go along with the QSPI chip datasheet.
Remark: the best is, when you read - to use the MemoryMappedMode. It should be a real 4-4-4 FAST_READ command. The beauty: you can access directly, via a simple data pointer and if caches are enabled for QSPI address region (MPU setting) - it is pretty fast and efficient.
Just to bear in mind: in MemoryMappedMode you cannot erase, program etc. You had to disable MemoryMappedMode and use the functions for "indirect" access.
It works for me.
Find my HAL based QSPI driver attached here:
QSPI.zip (18.9 KB)
There is clock enable for QSPI needed, which is in my system_clock.c:
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC | RCC_PERIPHCLK_USB | RCC_PERIPHCLK_SPI2 | RCC_PERIPHCLK_QSPI | RCC_PERIPHCLK_ADC;
PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_PLL2;
My general experience:
- you have to know exactly which QSPI chip is used: go with its datasheet: chips differ a lot in terms of which commands possible and their parameters (the chip on Portenta H7 is not really "the best one")
- try to "tweak" the timing, e.g. play with:
hqspi.Init.SampleShifting = QSPI_SHIFTING_SAMPLES; //QSPI_SAMPLE_SHIFTING_HALFCYCLE; //QSPI_SAMPLE_SHIFTING_NONE;
My function void QSPI_demo(int par, uint32_t addr) is the main function: via par I can select "Init", "Erase", "Program", "Read" and "MemoryMappedMode".
I use it in order to flash pages in QSPI with man pages (text), reading is done in "MemoryMappedMode" - see void QSPI_ManPage(EResultOut out, int num)
Works fine for me, as 4-4-4 for FAST_READ. But just in STR mode, not DDR: this one I could not bring to work. DDR is more tricky in terms of timing. And there is this DLY (Delay block) which can be trimmed.