2022-03-17 11:03 PM
Dear ST Community,
Thank you for taking the time to go through this :)
I had created the External Loader by following the Tutorial uploaded by STM on Youtube.
Link to the Tutorial: https://youtu.be/XqCq0xtQmbI
I created the External Loader after seeing successful implementation of Sector Erase, Write and Memory mapped Mode in my Cube IDE Project
Cube Programmer (v.2.10.0) returns this when trying to program the Flash with a Binary File:
An Interesting thing is that The file does get written till Address 0x900037FF but it fails afterwards as shown here:
I have tried using older versions of Cube Programmer ( 2.8.0 and 2.7.0) but still the same result.
Any help or direction from your side will go a long way.
Thank you so much in advance!
Attaching the Cube Programmer Log ( Verbose Level 3 ) in case it helps
2022-03-18 01:25 AM
Will check log when at a PC later.
Best to test and debug the BSP code thoroughly outside of the loader before integrating it.
2022-03-18 01:55 AM
If you erase and program repeatedly, does the "good" part (i.e. till 0x900037F0) always extend *precisely* to 0x900037F0? And, do you program in full page size (most commonly 256 bytes) chunks?
2022-03-18 04:49 AM
Hi Tesla, Thank you so much for taking the time to go through my issue. I hope that you'll be able to uncover something in the Error Log. With Regards to testing, I just followed the STM tutorial. Here is the code snipet. It performs Erase Sector, Write Memory and Memory Mapped mode. Then it reads the Memory and checks if the Read Data from Memory is same as that in the Buffer. If it fails any of these, it will end up in an "Error While Loop". And Finally If all operations are success, it will reach the Main WHILE LOOP.
CSP_QUADSPI_Init();
for (var = 0; var < MEMORY_SECTOR_SIZE; var++)
{
buffer_test[var] = (var & 0xff);
}
for (var = 0; var < SECTORS_COUNT; var++)
{
if (CSP_QSPI_EraseSector(var * MEMORY_SECTOR_SIZE, (var + 1) * MEMORY_SECTOR_SIZE - 1) != HAL_OK)
{
while (1); //breakpoint - error detected
}
if (CSP_QSPI_WriteMemory(buffer_test, var * MEMORY_SECTOR_SIZE,
sizeof(buffer_test)) != HAL_OK)
{
while (1); //breakpoint - error detected
}
}
if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK)
{
while (1); //breakpoint - error detected
}
for (var = 0; var < SECTORS_COUNT; var++)
{
if (memcmp(buffer_test, (uint8_t*) (0x90000000 + var * MEMORY_SECTOR_SIZE),
MEMORY_SECTOR_SIZE) != HAL_OK)
{
while (1); //breakpoint - error detected - otherwise QSPI works properly
}
}
while (1)
{
}
I checked the data in the Memory Monitor to double check and it was correct as shown.
I even tried writing a Buffer that was bigger so that it crosses the address 0x90003800 and it still worked.
Is there any other test that you recommend that I should try out?
Thanks Once Again Tesla ! :)
2022-03-18 05:06 AM
Hi Andreas, Thank you so much for your time. I have edited my original post. The final Address that is written is 0x900037FF(Not 0x900037F0) And Yes it always extends precisely to this Address.
The Write Memory Function that I have implemented uses the QUAD IN PAGE PROGRAM operation that programs 256 bytes per operation
Also please note that I wrote a program to write data from a Buffer big enough to Exceed 0x900037FF and it was successful. Its the External Loader when used with Cube Programmer (and Cube IDE) that is causing the issue.
Thank you once Again
2022-03-18 10:21 AM
The log doesn't provide much additional information.
It does look like an initialization / memory-mapped issue.
The loader/programming initializes the OSPI for each operation, and this could lead to an issue with the state that the memory device ends up in. Not clear it has an independent async reset.
From a loader perspective you can use GPIO, LEDs or UART to reflect the internal states and progress on your board, you can add instrumentation as you can't directly debug the code via the ST-LINK/SWD interfaces. All board level resources are under your control.
What pins are you using for the OCTOSPI1/QSPI interfacing?
https://www.issi.com/WW/pdf/25LP-WP064D.pdf
2022-03-20 11:12 PM
Hi Tesla, Thank you for looking into the Error Log.
Here are the pin configurations for the OSPI Peripheral interface with the Quad SPI Flash.
Also attaching the OSPI Parameters that I have used.
I am also attaching the Loader_Src.c file that was used to create the .stldr file. I got this from the STM Tutorial on Youtube. I replaced the QUAD SPI headers and HAL functions with the equivalent OCTO SPI Headers and Hal Function. Hope this helps.
Loader_Src.c
#include "octospi.h"
#include "main.h"
#include "gpio.h"
#define LOADER_OK 0x1
#define LOADER_FAIL 0x0
/**
* @brief System initialization.
* @param None
* @retval LOADER_OK = 1 : Operation succeeded
* @retval LOADER_FAIL = 0 : Operation failed
*/
int Init(void) {
*(uint32_t*)0xE000EDF0=0xA05F0000; //enable interrupts in debug
SystemInit();
/* ADAPTATION TO THE DEVICE
*
* change VTOR setting for H7 device
* SCB->VTOR = 0x24000000 | 0x200;
*
* change VTOR setting for other devices
* SCB->VTOR = 0x20000000 | 0x200;
*
* */
SCB->VTOR = 0x24000000 | 0x200;
__set_PRIMASK(0); //enable interrupts
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
__HAL_RCC_OSPI1_FORCE_RESET();//__HAL_RCC_OSPI_FORCE_RESET(); //completely reset peripheral
__HAL_RCC_OSPI1_RELEASE_RESET();//__HAL_RCC_QSPI_RELEASE_RESET();
if (CSP_QUADSPI_Init() != HAL_OK)
{
__set_PRIMASK(1); //disable interrupts
return LOADER_FAIL;
}
if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK)
{
__set_PRIMASK(1); //disable interrupts
return LOADER_FAIL;
}
/*Trigger read access before HAL_OSPI_Abort() otherwise abort functionality gets stuck*/
uint32_t a = *(uint32_t*) 0x90000000;
a++;
__set_PRIMASK(1); //disable interrupts
return LOADER_OK;
}
/**
* @brief Program memory.
* @param Address: page address
* @param Size : size of data
* @param buffer : pointer to data buffer
* @retval LOADER_OK = 1 : Operation succeeded
* @retval LOADER_FAIL = 0 : Operation failed
*/
int Write(uint32_t Address, uint32_t Size, uint8_t* buffer) {
__set_PRIMASK(0); //enable interrupts
if(HAL_OSPI_Abort(&hospi1) != HAL_OK)
{
__set_PRIMASK(1); //disable interrupts
return LOADER_FAIL;
}
//CSP_QUADSPI_Init();
if (CSP_QSPI_WriteMemory((uint8_t*) buffer, (Address & (0x0fffffff)),Size) != HAL_OK)
{
__set_PRIMASK(1); //disable interrupts
return LOADER_FAIL;
}
__set_PRIMASK(1); //disable interrupts
return LOADER_OK;
}
/**
* @brief Sector erase.
* @param EraseStartAddress : erase start address
* @param EraseEndAddress : erase end address
* @retval LOADER_OK = 1 : Operation succeeded
* @retval LOADER_FAIL = 0 : Operation failed
*/
int SectorErase(uint32_t EraseStartAddress, uint32_t EraseEndAddress) {
__set_PRIMASK(0); //enable interrupts
if(HAL_OSPI_Abort(&hospi1) != HAL_OK)
{
__set_PRIMASK(1); //disable interrupts
return LOADER_FAIL;
}
if (CSP_QSPI_EraseSector(EraseStartAddress, EraseEndAddress) != HAL_OK)
{
__set_PRIMASK(1); //disable interrupts
return LOADER_FAIL;
}
__set_PRIMASK(1); //disable interrupts
return LOADER_OK;
}
/**
* Description :
* Mass erase of external flash area
* Optional command - delete in case usage of mass erase is not planed
* Inputs :
* none
* outputs :
* none
* Note: Optional for all types of device
*/
//int MassErase(void) {
//
// __set_PRIMASK(0); //enable interrupts
//
// if(HAL_OSPI_Abort(&hospi1) != HAL_OK)
// {
// __set_PRIMASK(1); //disable interrupts
// return LOADER_FAIL;
// }
//
//
// if (CSP_QSPI_Erase_Chip() != HAL_OK)
// {
// __set_PRIMASK(1); //disable interrupts
// return LOADER_FAIL;
// }
//
// __set_PRIMASK(1); //disable interrupts
// return LOADER_OK;
//}
/**
* Description :
* Calculates checksum value of the memory zone
* Inputs :
* StartAddress : Flash start address
* Size : Size (in WORD)
* InitVal : Initial CRC value
* outputs :
* R0 : Checksum value
* Note: Optional for all types of device
*/
uint32_t CheckSum(uint32_t StartAddress, uint32_t Size, uint32_t InitVal) {
uint8_t missalignementAddress = StartAddress % 4;
uint8_t missalignementSize = Size;
int cnt;
uint32_t Val;
StartAddress -= StartAddress % 4;
Size += (Size % 4 == 0) ? 0 : 4 - (Size % 4);
for (cnt = 0; cnt < Size; cnt += 4) {
Val = *(uint32_t*) StartAddress;
if (missalignementAddress) {
switch (missalignementAddress) {
case 1:
InitVal += (uint8_t) (Val >> 8 & 0xff);
InitVal += (uint8_t) (Val >> 16 & 0xff);
InitVal += (uint8_t) (Val >> 24 & 0xff);
missalignementAddress -= 1;
break;
case 2:
InitVal += (uint8_t) (Val >> 16 & 0xff);
InitVal += (uint8_t) (Val >> 24 & 0xff);
missalignementAddress -= 2;
break;
case 3:
InitVal += (uint8_t) (Val >> 24 & 0xff);
missalignementAddress -= 3;
break;
}
} else if ((Size - missalignementSize) % 4 && (Size - cnt) <= 4) {
switch (Size - missalignementSize) {
case 1:
InitVal += (uint8_t) Val;
InitVal += (uint8_t) (Val >> 8 & 0xff);
InitVal += (uint8_t) (Val >> 16 & 0xff);
missalignementSize -= 1;
break;
case 2:
InitVal += (uint8_t) Val;
InitVal += (uint8_t) (Val >> 8 & 0xff);
missalignementSize -= 2;
break;
case 3:
InitVal += (uint8_t) Val;
missalignementSize -= 3;
break;
}
} else {
InitVal += (uint8_t) Val;
InitVal += (uint8_t) (Val >> 8 & 0xff);
InitVal += (uint8_t) (Val >> 16 & 0xff);
InitVal += (uint8_t) (Val >> 24 & 0xff);
}
StartAddress += 4;
}
return (InitVal);
}
/**
* Description :
* Verify flash memory with RAM buffer and calculates checksum value of
* the programmed memory
* Inputs :
* FlashAddr : Flash address
* RAMBufferAddr : RAM buffer address
* Size : Size (in WORD)
* InitVal : Initial CRC value
* outputs :
* R0 : Operation failed (address of failure)
* R1 : Checksum value
* Note: Optional for all types of device
*/
uint64_t Verify(uint32_t MemoryAddr, uint32_t RAMBufferAddr, uint32_t Size,uint32_t missalignement){
__set_PRIMASK(0); //enable interrupts
uint32_t VerifiedData = 0, InitVal = 0;
uint64_t checksum;
Size *= 4;
if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK)
{
__set_PRIMASK(1); //disable interrupts
return LOADER_FAIL;
}
checksum = CheckSum((uint32_t) MemoryAddr + (missalignement & 0xf),
Size - ((missalignement >> 16) & 0xF), InitVal);
while (Size > VerifiedData) {
if (*(uint8_t*) MemoryAddr++
!= *((uint8_t*) RAMBufferAddr + VerifiedData)){
__set_PRIMASK(1); //disable interrupts
return ((checksum << 32) + (MemoryAddr + VerifiedData));
}
VerifiedData++;
}
__set_PRIMASK(1); //disable interrupts
return (checksum << 32);
}