cancel
Showing results for 
Search instead for 
Did you mean: 

How do I initilize two QSPI flash chips but only place one in Memory Mapped Mode?

JohnS
Associate II

I'm working on a system that requires the ability to do an Over The Air (OTA) upgrade. It's on a TouchGFX project, and the MCU is a 64K internal flash so the project exists on the QSPI flash in Memory Mapped Mode (MMM). I learned MMM is read only, so I can't store the OTA data on the QSPI chip that is in MMM. I'm setting up hardware to have a Dual Flash arrangment, where each flash has a unique Chip Select line.

My understanding of how MX configures a "Dual Flash" is so that the data is "stripped" with odd addresses on one chip and even addreses on the other. This is fantastic for accelerating data access, but not what I need.

I need to be able to MMM one chip and leave the other unmapped so that code from Bank1 can store large amounts of data into Bank2. Once the OTA data is all received I then need to either:

A) Copy data from Bank2 and overwrite the project in Bank1

B) Get the bootloader to change which bank it initilizes in memory mapped mode.

Looking at the initilization code it's not clear to me how I could go about initilizing the two QSPIs seperately so that I could talk to them each individually.

Any suggestions/ideas that can point me in the right direction would be most appreciated.

7 REPLIES 7

You should be able to configure in a single chip mode, and which select to use, 1 or 2, they'd need independent selects

 /* QSPI initialization */

 /* ClockPrescaler set to 1, so QSPI clock = 200MHz / (1+3) = 50MHz */

 QSPIHandle.Init.ClockPrescaler   = 3;

 QSPIHandle.Init.FifoThreshold   = 1;

 QSPIHandle.Init.SampleShifting   = QSPI_SAMPLE_SHIFTING_HALFCYCLE;

 QSPIHandle.Init.FlashSize     = POSITION_VAL(MT25TL01G_FLASH_SIZE) - 1;

 QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_3_CYCLE;

 QSPIHandle.Init.ClockMode     = QSPI_CLOCK_MODE_0;

 QSPIHandle.Init.FlashID      = QSPI_FLASH_ID_2; // ONE or TWO

 QSPIHandle.Init.DualFlash     = QSPI_DUALFLASH_ENABLE; // << DISABLE

Will want to use two instances. Addresses likely to be end-to-end, based on size, not something I've tried.

Size could be set to 128MB for each (doesn't really care, just impacts decode/shadows), then would be at 0x90000000, and 0x98000000

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Might look to see if I can test/evaluate this later, not sure there are multiple instances of the QSPI peripheral/registers, might not do one in memory-map, the other in command mode.

What model of STM32?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Thank you for your responses and being willing to look into it further. My MCU is F7 family, specifically STM32F750N8H6.

JohnS
Associate II

I just got hardware in hand, so hopefully this goes smoothly... for once. If you have a chance to test or have any additional tips, please let me know. I hope to share details of what works with the community soon.

JohnS
Associate II

So I've got some odd behavior I can't explain, would like to get the community's thoughts:

I am able to incorporate the chip into my project, and when I connect to it I am able to program and read data from it. I can shut off the board and read data off of it, which matches the data I programmed before the power cycle. That all seems fine.

However, I can also connect to it with an external loader and read data, but it doesn't match the data read and read in the program. I can erase the data and program in different data. I can close the external loader and reconnect and it repeat ably gives me the same answer. But it it is a different answer of the data stored of when I access it through the project.

Both the project and the external loader consistently give me a response, but they don't match each other. The project always returns dataset AAAAAAAA while the external loader always returns dataset 12345678 (for example).

Also, when I try to talk to the second chip, it looks like it is getting answers from the first chip. Is that a fundamental issue with the F7 family or am I doing something incorrect?

Thank you for the help.

The design and pining on the F7 QUADSPI peripheral is unhelpful.

They share a clock, and a lot of common hardware, so even if you could use both chips, concurrent operation would be a problem, and you'd need to mutex usage. And definitely avoid spurious memory-mapped interaction.

The H7Bx OCTOSPI does look to accommodate multiple instances.

ST's External Loaders constantly reinitialize and remap the memories, so there could be an initialization or configuration step there. Repetitive data patterns tend to mean the mode of operation is wrong, or the command hasn't been accepted. The lack of a async reset tends to mean memories hold their configuration/mode expectation across peripheral resets, but not power cycles.

You should be able to read the individual chip JEDEC ID and serial numbers from Micron QSPI parts.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

With some help from a very smart friend I was able to get to the bottom of what was happening and the very strange behavior I was seeing. I commented repeatedly that it was behaving as though I was talking to one QSPI in my program, and the other one when I connected via the External Loader, but I couldn't figure out how that was possible.

static void MX_QUADSPI_Init(void)

{

 /* USER CODE BEGIN QUADSPI_Init 0 */

 hqspi2.Instance = QUADSPI;

 hqspi2.Init.ClockPrescaler = 1;

 hqspi2.Init.FifoThreshold = 4;

 hqspi2.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;

 hqspi2.Init.FlashSize = 24;

 hqspi2.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_8_CYCLE;

 hqspi2.Init.ClockMode = QSPI_CLOCK_MODE_0;

 hqspi2.Init.DualFlash = QSPI_DUALFLASH_DISABLE;

 hqspi2.Init.FlashID   = QSPI_FLASH_ID_2; // ONE or TWO

 /* USER CODE END QUADSPI_Init 0 */

 /* USER CODE BEGIN QUADSPI_Init 1 */

 hqspi.Init.FlashID   = QSPI_FLASH_ID_1; // ONE or TWO

 /* 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 = 24;

 hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE;

 hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;

 hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;

 if (HAL_QSPI_Init(&hqspi) != HAL_OK)

 {

  Error_Handler();

 }

 /* USER CODE BEGIN QUADSPI_Init 2 */

 if (HAL_QSPI_Init(&hqspi2) != HAL_OK)

 {

  printf("Configure hqspi2 FAILED\n");

  Error_Handler();

 }

 /* USER CODE END QUADSPI_Init 2 */

}

Because there is only one instance supported in an F7 chip when I created the second instance the first was overwritten so both &hqspi and &hqspi2 were essentially the same thing. But they were talking to Bank2. The External Loader was configured to talk to Bank1. So they were showing me different data repeat ably, and they were actually both telling the truth.

When I flipped the order of which initialize was called, it suddenly made sense. When &hqspi was initialized second suddenly the data shown in the Programmer matched what my program was doing because it overwrote the other one.

So, moving forward, I can't talk to both chips in QSPI mode separately so I'm looking at options. Seems like possibly the best solution is to move the Bank2 chip to an SPI channel and use it as a SPI device. Because the QSPI configuration uses a common clock, I assume communicating with it on the Bank2 QSPI would be pretty complicated to implement on an F7 chip. Am I missing something?