Problems accessing QSI Flash with consecutive reads
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-09-14 3:19 AM
I have a Cypress S25FL064 flash memory connected through QSPI interface to a STM32H753.
The memory is booting in "single IO" mode (ie. classical SPI protocol with MISO/MOSI signals).
In this mode I am able to erase, program and read the memory through its command set.
Then I switch to "quad io" and "memory mapped" mode.
In this configuration:
- when the CPU sends "short" read commands (ex: I read a byte in my software -> the CPU sends a 4 bytes read command to the memory) everything works fine
- when the CPU sends "long" read commands (ex. i do a memcpy from flash to internal RAM -> the CPU sends a single N bytes read command) the read data is corrupted after 10 bytes or so. However the signals on a scope seem correct.
The SPI clock is pretty slow (6.25MHz) compared to QPSI peripheral clock (200MHz) and CPU clock (400MHz).
About GPIOs I've let all IOs in high impedance mode (ie. bits 00 in GPIOx_PUPDR register) as adviced in the flash user manual. Pins frequency is medium.
The flash user manual mentions explicitely that it is possible to read the whole memory in a single command.
Any idea why "long" read commands would fail ? It looks like a synchronisation issue but I don't see what setting could cause that.
- Labels:
-
GPIO-EXTI
-
QSPI
-
STM32H7 Series
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-09-14 5:23 AM
Hello @Gpeti​,
Can you please share your QSPI configuration and the main function.
Thank you.
Chahinez.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-09-14 5:39 AM
Here is the code (sorry, I removed the comments that were in french):
#define K_QSPI_CR1V 0x02
#define K_QSPI_DCR (22 << QUADSPI_DCR_FSIZE_Pos)
#define K_QSPI_INSTRUCTION_MODE_CONFIG QUADSPI_CCR_IMODE_0
#define K_QSPI_DATA_MODE_CONFIG QUADSPI_CCR_DMODE_0
#define K_QSPI_ADRESSE_MODE_CONFIG QUADSPI_CCR_ADMODE_0
#define K_QSPI_CMD_WRR 0x01
#define K_QSPI_CCR_MEMORY_MAPPED (QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | (8<<QUADSPI_CCR_DCYC_Pos) | QUADSPI_CCR_ABMODE | QUADSPI_CCR_ADSIZE_1 | QUADSPI_CCR_ADMODE | QUADSPI_CCR_IMODE_0 | 0xEB)
STATIC_ void envoi_commande_sans_data(octet O_INSTRUCTION)
{
ECRIRE_REG(QUADSPI.DLR, 0);
ECRIRE_REG(QUADSPI.CCR, (K_QSPI_INSTRUCTION_MODE_CONFIG | O_INSTRUCTION) );
while( (QUADSPI.SR & QUADSPI_SR_TCF) == 0 );
ECRIRE_REG(QUADSPI.FCR, QUADSPI_FCR_CTCF);
while ((QUADSPI.SR & QUADSPI_SR_BUSY) != 0);
}
_STATIC_ void config_quadio(void)
{
envoi_commande_sans_data((octet)K_QSPI_CMD_WRENV);
ECRIRE_REG(QUADSPI.DLR, 1);
ECRIRE_REG(QUADSPI.CCR, (K_QSPI_DATA_MODE_CONFIG | K_QSPI_INSTRUCTION_MODE_CONFIG | K_QSPI_CMD_WRR) );
*((__IO octet *)&(QUADSPI.DR)) = 0;
*((__IO octet *)&(QUADSPI.DR)) = K_QSPI_CR1V;
while( (QUADSPI.SR & QUADSPI_SR_TCF) == 0 );
ECRIRE_REG(QUADSPI.FCR, QUADSPI_FCR_CTCF);
while ((QUADSPI.SR & QUADSPI_SR_BUSY) != 0);
}
void main(void)
{
#ifdef _TEST_MEM_CHAR_
octet *PO_LECTURE;
naturel4 U4_INDEX;
octet O_ID1;
octet O_ID2;
octet O_ID3;
#endif
/* init STM32 */
(...)
__IO naturel4 U4_REG_TEMP;
SET_BIT(RCC.AHB3ENR, RCC_AHB3ENR_QSPIEN);
U4_REG_TEMP = LIRE_BIT(RCC.AHB3ENR, RCC_AHB3ENR_QSPIEN);
(void)U4_REG_TEMP;
/* Reset */
SET_BIT(RCC.AHB3RSTR, RCC_AHB3RSTR_QSPIRST);
CLEAR_BIT(RCC.AHB3RSTR, RCC_AHB3RSTR_QSPIRST);
ECRIRE_REG(QUADSPI.CR, (31U << QUADSPI_CR_PRESCALER_Pos) | (8 << QUADSPI_CR_PRESCALER_Pos));
ECRIRE_REG(QUADSPI.DCR, (22 << QUADSPI_DCR_FSIZE_Pos));
SET_BIT(QUADSPI.CR, QUADSPI_CR_EN);
config_quadio();
while( (QUADSPI.SR & QUADSPI_SR_BUSY) != 0 );
ECRIRE_REG(QUADSPI.CCR, K_QSPI_CCR_MEMORY_MAPPED);
#ifdef _TEST_MEM_CHAR_
// PO_LECTURE = (octet *)0x90000000;
// if (*PO_LECTURE != 0) while(1);
// PO_LECTURE = (octet *)0x90000010;
// if (*PO_LECTURE != (octet)0x10) while(1);
// PO_LECTURE = (octet *)0x90000100;
// if (*PO_LECTURE != (octet)0x100) while(1);
// PO_LECTURE = (octet *)0x90000233;
// if (*PO_LECTURE != (octet)0x233) while(1);
PO_LECTURE = (octet *)0x90000000;
U4_INDEX = 0;
while (U4_INDEX < K_MEM_CHAR_TEST_SIZE)
{
TO_TEST_BUFFER[U4_INDEX] = 0;
U4_INDEX += KU4_UN;
}
U4_INDEX = 0;
while (U4_INDEX < K_MEM_CHAR_TEST_SIZE)
{
TO_TEST_BUFFER[U4_INDEX] = *PO_LECTURE;
U4_INDEX += KU4_UN;
PO_LECTURE += KU4_UN;
}
U4_INDEX = 0;
while (U4_INDEX < K_MEM_CHAR_TEST_SIZE)
{
if ( TO_TEST_BUFFER[U4_INDEX] != (octet)U4_INDEX )
{
while(1);
}
U4_INDEX += KU4_UN;
}
#endif
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-09-14 6:37 AM
Yeah, I don't know you're going to get a lot of support for register level code, or odd libraries.
Depending on the read command, and the memory, you can exhaust the buffering of the chips, but you say it is clocking is super-slow. On faster interfaces you use read commands with dummy cycles behind them to allow the memory to prefetch into a buffer.
How does it work with HAL code examples?
Up vote any posts that you find helpful, it shows what's working..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-09-14 6:41 AM
Yes, the memory requires 8 dummy cycles before returning its data. But it is the same whether you are reading 1 byte or many.
Didn't try with the HAL, but I looked at it for QSPI configuration.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-09-14 6:52 AM
I'd have thought the memory could sustain 25-50 mbps without being out-run.
You're using 0xEB Quad IO Fast
Prior thread so I can find it later
Up vote any posts that you find helpful, it shows what's working..
