cancel
Showing results for 
Search instead for 
Did you mean: 

I have created an External Loader for my custom board with IS25LP064D connected to an STM32H730IB via OCTOSPI 1. I am able to successfully Read, Sector Erase and Mass Erase via Cube Programmer BUT Programming a Binary File into the Flash returns ERROR.

Nandagopal
Associate II

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:

0693W00000Kd6fIQAR.pngAn Interesting thing is that The file does get written till Address 0x900037FF but it fails afterwards as shown here:

0693W00000Kd6fXQAR.png 

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

6 REPLIES 6

Will check log when at a PC later.

Best to test and debug the BSP code thoroughly outside of the loader before integrating it.​

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

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?

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 ! 🙂

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

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

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

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.

0693W00000KdLbQQAV.pngAlso attaching the OSPI Parameters that I have used.

0693W00000KdLbpQAF.png 

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);
}