cancel
Showing results for 
Search instead for 
Did you mean: 

Caching External NOR FLASH, not uploading code - bad linker

PAdam.11
Associate III

Hi, I'm trying to find adress space for not memory mapped 16MB NOR.

I have external PSRAM IS66WVE4M16EBLL + NOR MT28EW128ABA1LPC-0SIT with STM32H753ZIT6. They are both on the same bus:

PAdam11_1-1694695782099.png

FMC: NOR 0x60000000,PSRAM 0x68000000. Not using MPU. I use raw addresses of PSRAM as memory mapped, and HAL functions to transfer data to NOR. I tested memory integrity, R/W - all fine.

So far I had TouchGFX running with internal FLASH for graphics + doublebuffers in external PSRAM - it was working fine with stable 32 FPS @ 480 x 272px RGB565.

Now I want to use external FLASH for storing graphics. Seems it is not memory mapped so I started with this article and to cache most of graphics to external PSRAM and faced this section:

"In this example we will put the image data in the ExtFlashSection at address 0x24000000. You can select any address that is otherwise unused (not part of the code or data address space)."

I grab 288k of RAM_D2 to test (0x30000000) as unused address space. Then I added to FrontendApplication.cpp the buffer and attached in the constructor:

#define FRONTEND_CACHE_SIZE_HALFWORLDS (600*1024)
static __attribute__ ((section(".external_cache"), used)) uint16_t external_ram_cache[FRONTEND_CACHE_SIZE_HALFWORLDS];
uint16_t* frontend_cache = external_ram_cache;

...
Bitmap::setCache(frontend_cache, FRONTEND_CACHE_SIZE_BYTES);
Bitmap::cache(BITMAP_BUTTON_ID);

Linker script:

MEMORY
{
  FLASH (rx)     : ORIGIN = 0x08000000, LENGTH = 2048K
  DTCMRAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 128K
  RAM_D1 (xrw)   : ORIGIN = 0x24000000, LENGTH = 512K
  RAM_D2 (xrw)   : ORIGIN = 0x30000000, LENGTH = 288K
  RAM_D3 (xrw)   : ORIGIN = 0x38000000, LENGTH = 64K
  ITCMRAM (xrw)  : ORIGIN = 0x00000000, LENGTH = 64K
  EXT_RAM (xrw)  : ORIGIN = 0x68000000, LENGTH = 8M
  EXT_FLASH_DUMMY (r)  : ORIGIN = 0x30000000, LENGTH = 16M
}
...
  .framebuffer(NOLOAD) :
  {
  	. = ALIGN(2);
  	. = ABSOLUTE(0x68000000);
  	*(.framebuffer_1)
  	. = ALIGN(2);
  	. = ABSOLUTE(0x68040000);
  	*(.framebuffer_2)
  	. = ABSOLUTE(0x68080000);
  } >EXT_RAM
  
  
  .ext_data(NOLOAD) :
  {
  	. = ALIGN(1);
  	. = ABSOLUTE(0x68080090);
  	*(.external_cache)
  } >EXT_RAM
  
ExtFlashSection :
{
   *(ExtFlashSection ExtFlashSection.*)
} >EXT_FLASH_DUMMY

Because both SDRAM and NOR are connected to the same data/address bus I created internal RAM buffer to let transfer the data in chunks:

bool TouchGFXHAL::blockCopy(void* RESTRICT dest, const void* RESTRICT src, uint32_t numBytes) {
	const uint32_t dummy_address = 0x30000000;
	const uint32_t srcVal = (uint32_t)(src);
	  if ((srcVal >= dummy_address) && srcVal < (dummy_address + 16*1024*1024)) {
		  const uint32_t localAddress = srcVal - dummy_address;
		  const uint32_t fullBlocksCount = numBytes / GFX_COPY_BLOCK_SIZE;

		  for(uint32_t block=0; block<fullBlocksCount; ++block) {
			  const uint32_t offset = block * GFX_COPY_BLOCK_SIZE;
			  const uint32_t blockAddress = localAddress + offset;
			  memset(copyBlockBuffer, 0, sizeof(copyBlockBuffer));
			  mem_manager_read_ext_flash(blockAddress, copyBlockBuffer, GFX_COPY_BLOCK_SIZE);
			  memcpy((void*)((uint8_t*)dest + offset), (void*)copyBlockBuffer, GFX_COPY_BLOCK_SIZE);
		  }
	    return true;
	  }
	  else {
	    return HAL::blockCopy(dest, src, numBytes);
	  }
    return TouchGFXGeneratedHAL::blockCopy(dest, src, numBytes);
}

It is working fine.

But adress space of RAM_D2 is only 64k and I need about 16M of graphics. Looking at RM0433 I dont really see any block of memory in which I could store 16M of unused adressed space.

I triend many addresses to try fit at least 500k of graphics and it always fails during uploading with Failed to execute MI command load.

PAdam11_0-1694695717056.png

All caching logic is working fine. I only need to understand how to treat addresses managed by linker. Could you give me a hint?

 

1 ACCEPTED SOLUTION

Accepted Solutions
FBL
ST Employee

Hello @PAdam.11 

You may need to check the definition of external NOR Flash memory in the linker script.

 

MEMORY
{
  ..
  EXT_NOR (xrw)  : ORIGIN = 0x60000000, LENGTH = 16M
  EXT_PSRAM (rw)  : ORIGIN = 0x68000000, LENGTH = 8M
}

 

In the article, assuming that you want to store your bitmaps in non-memory mapped flash. This can be e.g. USB storage, NAND flash etc. In your case, you are locating the bitmaps in memory mapped region! 

You should place the external flash section which contains all the bitmaps into a virtual memory.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

View solution in original post

5 REPLIES 5
PAdam.11
Associate III

It seems linker script attribute UNLOAD is required. Adresses are generated becouse in output binary information about graphics data is preserved. But they will not populate selected memory region's section. So variables will have some invalid pointers which can be then mapped to external memory. So IMO in the example of TouchGFX it will be better to have:

ExtFlashSection(UNLOAD) :
{
*(ExtFlashSection ExtFlashSection.*)
} >USB

But I'm not sure, I'm not linker expert 🙂 

FBL
ST Employee

Hello @PAdam.11 

You may need to check the definition of external NOR Flash memory in the linker script.

 

MEMORY
{
  ..
  EXT_NOR (xrw)  : ORIGIN = 0x60000000, LENGTH = 16M
  EXT_PSRAM (rw)  : ORIGIN = 0x68000000, LENGTH = 8M
}

 

In the article, assuming that you want to store your bitmaps in non-memory mapped flash. This can be e.g. USB storage, NAND flash etc. In your case, you are locating the bitmaps in memory mapped region! 

You should place the external flash section which contains all the bitmaps into a virtual memory.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

For the debugger / system to download content into external PSRAM of FLASH you'd need to provide an external loader to enable the pins, interface, etc

You could also perhaps just stage things in the External NOR, and copy them from there into PSRAM once you've brought that up in startup.s

Expect you'll need to use linker symbols and directives to effect that.

  .ext_data(NOLOAD) :
  {
    . = ALIGN(4);
    _s_extdata = .;        /* create a global symbol at data start */
...
    . = ALIGN(4);
    _e_extdata = .;        /* define a global symbol at data end */
  } >EXT_RAM AT> EXT_FLASH /* Ends up in EXT_RAM, staged in EXT_FLASH */
 
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
sss343
Associate II

Adresses are generated becouse in output binary information about graphics data is preserved.

https://www.creativesolutionservices.com/web-development.php

@sss343  Yup exacly. It is all working fine now 🙂

Firstly I uploaded code with (UNLOAD) attribute to target. Then without (UNLOAD) I extracted graphics data from .elf file as in the article

arm-none-eabi-objcopy --dump-section ExtFlashSection=images.bin ../Debug/HMI.elf

Then function to cache NOR FLASH to PSRAM with use of transfer buffer in internal RAM. Transfering 1.5M takes not much time at starting of the device. About 1 sec. 8M PSRAM is sufficient to store all the graphics.

With use of USBX MSC Host and FileX I added option to program NOR from USB Drive, by discovering "iages.bin" and reading filesystem-programming NOR.

	const result_t erase_flash_result = mem_erase_ext_flash();
	if(erase_flash_result != RESULT_OK) {
		graphics_are_upgraded = BOOL_FALSE;
		fx_file_close(&my_file);
		return FX_ERROR_NOT_FIXED;
	}

	/* Seek start of File */
	fx_file_seek(&my_file, 0);

	const uint32_t file_bytes = (uint32_t)(my_file.fx_file_current_file_size);
	const uint32_t full_chunks_count = file_bytes / TRANSFER_BUFFER_SIZE;
	const uint32_t remaining_bytes = file_bytes - TRANSFER_BUFFER_SIZE * full_chunks_count;
	const uint32_t chunks_count = full_chunks_count + (remaining_bytes > 0 ? 1 : 0);

	/* Read the file in blocks */
	for(uint32_t chunk_index; chunk_index < chunks_count; ++chunk_index) {
		status = fx_file_read(&my_file, (VOID *)transfer_buffer, TRANSFER_BUFFER_SIZE, &requested_length);
		if(status != FX_SUCCESS) {
			graphics_are_upgraded = BOOL_FALSE;
			fx_file_close(&my_file);
			return status;
		}

		/* Program FLASH */
		const uint32_t nBytes = (uint32_t)(requested_length);
		const uint32_t local_address = 0 + chunk_index * TRANSFER_BUFFER_SIZE;
		const result_t program_flash_result = mem_program_ext_flash(local_address, transfer_buffer, nBytes);
		if(program_flash_result != RESULT_OK) {
			graphics_are_upgraded = BOOL_FALSE;
			fx_file_close(&my_file);
			return FX_FILE_CORRUPT;
		}
	}

@FBL thank you, seems I've done what you advised.

@Tesla DeLorean also thank you for the advice. USD Drive should be sufficient now, soon I'l try method with loader.

PAdam11_0-1695220281386.png