Skip to main content
JNguyen
Senior
November 7, 2019
Question

How to create CubeProg stldr loader file for QSPI external memory?

  • November 7, 2019
  • 9 replies
  • 4625 views

..

This topic has been closed for replies.

9 replies

Tesla DeLorean
Guru
November 7, 2019

Not super well documented. Review doc for Keil FLASH algorithms to understand the background.

Several examples under the ExternalLoader directory that could be adapted.

Basically wrapping the BSP QSPI code, providing entry points to Initialize and map the memory, and then additional routines to erase device/sectors, and write memory.

If you have specific requirements I'll quote the work.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Tesla DeLorean
Guru
November 7, 2019

STM32H750

MT25QL256, 32MB

PB6 NCS

PB2 CLK

PD11 D0

PD12 D1

PE2 D2

PA1 D3

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
JNguyen
JNguyenAuthor
Senior
November 7, 2019

My board has the exact same QSPI connections, configured for single flash/BK1/Quad. My board FW runs QSPI memory verification successfully, writes LCD image data to QSPI memory, and copy it to LCD w/o error.

JNguyen
JNguyenAuthor
Senior
November 7, 2019

Thanks.

My board has H750V and MT25QL256 QSPI memory. I got stldr file for CubeProg created. CubeProg can read QSPI correctly. Here are my issues:

1) At the first time target is power on, CubeProg cannot read QSPI. I have to load the loader hex file (that is used to create stldr file) to CubeProg, download it to target. Then CubeProg can read memory OK from here on, until target is power cycled. This means that CubeProg does not set the entry point in H750V RAM. I don't know how to fix this.

2) After CubeProg read memory successfully, CubeProg does sector erase and reports successfully. However, memory is not erased when CubeProg reads it again.

3) If I try to modify a location (a byte, or a word, or 4 bytes) of the memory after CubeProg read it, I'll get and error msg "Memory edition verification failed"

Tesla DeLorean
Guru
November 7, 2019

The Cube Programmer is a bit fragile on the H7 currently. Prefer the GUI and ST-LINK Utilities in some contexts.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
JNguyen
JNguyenAuthor
Senior
November 7, 2019

I'm seeing the same issues in ST-Link Util

JNguyen
JNguyenAuthor
Senior
November 8, 2019

For those of you seeing the similar issue with stldr file, I found out one of the reason for my issue was that the below is not met:

  • VECT_TAB_SRAM has to be defined
  • VECT_TAB_OFFSET has to be 0x200

These are in system_stm32h7xx.c in my case. This is not documented any where. I found it out the hard way. I hope this saves you time.

Tesla DeLorean
Guru
November 8, 2019

Generally speaking, Interrupts and VTOR shouldn't be in use at all.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
JNguyen
JNguyenAuthor
Senior
November 8, 2019

Attached are major files of my CubeProg project with STM32H750, MT25QL256 (32MB). CubeProg can read QSPI OK, not write/sector-erase correctly. I'd appreciate if someone review and provide feedback.

Tesla DeLorean
Guru
November 8, 2019

I perhaps would avoid putting it into QUAD mode all the time, as this then expects commands to be sent differently (ie not 1_LINE mode)

Use the commands implementing 1-4-4 mode for instruction/address/data.

Don't make assumptions about mapped/un-mapped mode, the application calls Init() repeatedly switching modes.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
JNguyen
JNguyenAuthor
Senior
November 8, 2019

I went back to check. I don't have any 4_LINES instructionmode. Only 4_LINES mode I have is in code for the commands (0x38 and 0x6B) which require 1-4-4 or 1-1-4. For mapped/un-mapped mode, that is what I was concerned about, since I don't know how CubeProg behavors. So I added QSPI_AutoPollingMemReady() in Read, Write, SectorErase, Verify functions (in Loader_Src.c). That actually got rid lot of errors, and got me to this point.

JNguyen
JNguyenAuthor
Senior
December 30, 2019

I finally got this to work. In addition items I mentioned above, below items are also needed. They are not documented any where, so it took me long time to get it resolved. They are not guarantied to be correct solution for you if you use a different CPU. I hope this help you to save time. At least you know which areas to experiment.

1)  memory location 0x24000004 must be used in stm32_flash.ld. STM32H750 has other 3 RAM areas, 0x20000000, 0x30000000, 0x38000000. None of these 3 works.

/* Specify the memory areas */

MEMORY

{ RAM (xrw)     : ORIGIN = 0x24000004, LENGTH = 512K }

2) Adding *(uint32_t*)0xE000EDF0=0xA05F0000; in LoaderSrc.c to enables IRQs in debug state.

int Init(uint8_t memMappedMode) {

       uint8_t status=0xFF;

        *(uint32_t*)0xE000EDF0=0xA05F0000;   // enables IRQs in debug state.

        status=MCU_Init(memMappedMode);

       if (status == 0)

              return 1;

        return 0;

}

Tesla DeLorean
Guru
December 31, 2019

The alternative is to be able to mark time accurately *without* using interrupts.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
egoltzman
Senior
December 31, 2019

Hello,

I'm in the middle of building an external loader for a target board based on L496 & QSPI, the same as used in the L496G-Disco board but the QSPI on my target sits under different lines then the disco.

I started by building an running successfully a loader based on the example from the CubeProgrammer install dir for the disco board, after I had this I thought moving it to the target will be as simple as change the lines but this did not worked and I have problem to activate the write.

After digging in this issue I saw this discussion and my main concern now is who makes the HAL ticks tick?

I saw that Clive mention more then once that interrupt should not be used, if so then how HAL_IncTick is pushed if not from SysTick_Handler?

Using the QSPI HAL API needs this as I see in the code:

HAL_StatusTypeDef HAL_QSPI_Command(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, uint32_t Timeout)
{
 HAL_StatusTypeDef status;
 uint32_t tickstart = HAL_GetTick();

I see from reading and review JNguy code and comments that he use interrupts, but the HAL_Delay is commented out, why?

I believe my problem with the QSPI write on the target is a timing issue and thus this interrupt issue is relevant.

I'll be happy and thankful for any kind of input or suggestion on that.

Thanks and happy new year!

Tesla DeLorean
Guru
December 31, 2019

>>I saw that Clive mention more then once that interrupt should not be used, if so then how HAL_IncTick is pushed if not from SysTick_Handler?

There is obviously more than one way to skin the cat... Your mind is trapped in a box of it's own creation.

The CPU has a cycle counter, and TIM2 can be used as a free running maximal 32-bit counter, both methods can determine the elapsed time between calls to HAL_GetTick()

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
egoltzman
Senior
January 1, 2020

OK, I did this with TIM2 but it did not change the state and the loader on the target is still not working properly.

I have a situation where I have a working loader project that is built for the L496Disco board that have on it the same MX25R6435F 8M QSPI as I have on my target, but after I only change the QSPI lines to the ones that fits the target board the loader is not working properly when I try to write.

I have this phenomena:

  • I'm starting from an erased flash
  • I'm trying to write "12345" at address 0 from the CubeProgrammer GUI
  • I get this "CCCDEFCD" on this address after I try to write and a popup error message say "Memory edition verification failed"

When I erase a sector it is look like the job is being done properly.

Two things are different in my target in compare to the disco board, I'm working with 1.8V and the I have an external crystal of 16M, but I'm not setting the clock to use it in the loader project.

Any idea what could be the problem?

Thanks

JNguyen
JNguyenAuthor
Senior
January 2, 2020

Hi Ego,

I have HAL_Delay in my final working code. below is MCU_Init() in main.c. You don't need Enter4ByteAddressMode() if you are not using 4-byte Addr mode.

/* USER CODE BEGIN 4 */

uint8_t MCU_Init(uint8_t memMappedMode) {

   SystemInit();

   memset(&hqspi, 0, sizeof(hqspi));

   hqspi.Instance = QUADSPI;

   HAL_Init();

   MX_GPIO_Init();

   SystemClock_Config();

   //prepare QSPI peripheral for ST-Link Utility operations

   if (HAL_QSPI_DeInit(&hqspi) != HAL_OK) {

      return HAL_ERROR;

   }

   MX_QUADSPI_Init();

   if (QSPI_ResetChip() != HAL_OK)

      return HAL_ERROR;

   HAL_Delay(1);

   if (QSPI_AutoPollingMemReady() != HAL_OK)

      return HAL_ERROR;

   if (QSPI_WriteEnable() != HAL_OK)

      return HAL_ERROR;

   if (QSPI_Configuration() != HAL_OK)

      return HAL_ERROR;

   Enter4ByteAddressMode();

   if (memMappedMode != 1) {

      if (QSPI_WriteEnable() != HAL_OK)

         return HAL_ERROR;

      if (QSPI_AutoPollingMemReady() != HAL_OK)

         return HAL_ERROR;

      if (QSPI_EnableMemoryMappedMode() != HAL_OK)

         return HAL_ERROR;

   }

   return HAL_OK;

}

Check HAL_QSPI_MspInit() (created by CubeMX) to make sure the IO lines are assigned to QSPI correctly for your target.

JNguyen
JNguyenAuthor
Senior
January 2, 2020

Hi Ego,

is your QSPI chip is exactly the same as the one on Disco board? if not, check the commands for read and write, and change it accordingly in the QSPI read, write functions.

egoltzman
Senior
January 2, 2020

Thank you JNguy for getting back to me.

I actually just found the problem now and it was that I used in my original loader project calls to BSP_QSPI_*** from within stm32l496g_discovery_qspi.c, and the problem was that the BSP_QSPI_Init has its own QSPI_MspInit that used the wrong lines setup and override my HAL_QSPI_MspInit that was created by CubeMX and fits my QSPI lines.

In my original project I used one of the samples under STM32CubeProgrammer\bin\ExternalLoader, after I saw your conversation here I was able to trace the source code of the project you used (the F769_discovery_QSPI) but when I built it and try to use the stsldr file it generated I was not able to access the F769 QSPI, I'm not sure I fully understand the structure of it since it uses main and the CubeProgrammer\STLinkUtility does not.

Thanks

JNguyen
JNguyenAuthor
Senior
January 2, 2020

At the end, you will have two projects in your IDE, one for your normal application, one for the loader for CubeProgrammer\STLinkUtility for the QSPI chip on your target board. The loader project will likely have to change if QSPI chip changes and/or CPU changes and/or QPSI lines change. The loader project uses different entry point, Init(), other than main(). Main.c is still needed in loader project, since definitions of QSPI lines and QSPI functions are in main.c

If your application doesn't need pre-stored data on QSPI chip, such as image for LCD..., then you don't need loader project. Your application can still read/write to QSPI chip.