How to place const data in K8x External QSPI flash

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to place const data in K8x External QSPI flash

Jump to solution
3,268 Views
deniscollis
Contributor V

I have a K8x and need to place large const data on external (QSPI XiP) flash. I am using an external linker script. 

deniscollis_0-1657832182374.png

Here are the relevant excerpts:

k81_memory.ld

 

 

MEMORY
{ 
  PROGRAM_FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x040000
  EXT_PGM_FLASH (rx) : ORIGIN = 0x04020000, LENGTH = 0x100000
  /*  0x04020000-0x0405FFFF is XiP alias for 0x68020000-0x6805FFFF  */
  SRAM_LOWER   (rwx) : ORIGIN = 0x1fff0000, LENGTH = 0x010000
  SRAM_UPPER   (rwx) : ORIGIN = 0x20000000, LENGTH = 0x030000
  /* First 128K infineon has 4K erase, use for Configs */
  TERM_SETTINGS (rx) : ORIGIN = 0x68000000, LENGTH = 0x018000 /* 96K */
  MODULE_CONFIG (rx) : ORIGIN = 0x68018000, LENGTH = 0x008000 /* 32K */
  XIP_RESERVED  (rx) : ORIGIN = 0x68020000, LENGTH = 0x100000 /*  1M */
  OTA_UPDATE    (rx) : ORIGIN = 0x68120000, LENGTH = 0x100000 /*  1M */
}

 

 

 

k81.ld

 

 

INCLUDE "k81_memory.ld"
STACK_SIZE  = 0x1000;
ENTRY(ResetISR)
SECTIONS
{
  /* EXTERNAL QSPI XiP FLASH */
  .text_Flash2 : ALIGN(4)
  {
    FILL(0xff)
    *(.text_Flash2*)
    *(.text_EXT_PGM_FLASH*)
    *(.text.$Flash2*)
    *(.text.$EXT_PGM_FLASH*)
  } > EXT_PGM_FLASH
    
  .data_Flash2 : ALIGN(4)
  {
    FILL(0xff)
    *(.rodata_Flash2*)
    *(.rodata_EXT_PGM_FLASH*)
    *(.rodata.$Flash2*)
    *(.rodata.$EXT_PGM_FLASH*)
  }> EXT_PGM_FLASH

 

 

 

If I place code in external flash, e.g.

 

 

void __attribute__((section (".text_Flash2"))) delay_ms(uint16_t ms)
{
    volatile uint32_t i = 0U;
    for (i = 0U; i < (10000U*ms); ++i)
    {
        __asm("NOP"); /* delay */
    }
}

 

 

... and build:

deniscollis_1-1657832734815.png

...then the function is correctly placed on the external flash.

However, if I instead place const data in external flash

 

 

const TsBigBitMap __attribute__((section (".data_Flash2"))) Logo_bmp =
{
  3,     // BitMapType
  512,   // width_pixels
  384,   // height_pixels
  192,   // width_bytes
  73728, // byte_count
  {
// Line 0
0xFF, 0xFF, 0xF0, 0x0A, ... 0xFF, 0xFF 0xFF, 0xFF, 
  }
};

 

 

.. and build:

deniscollis_2-1657833404391.png

... then it appears to NOT be placed in external flash.

 

What am I not seeing?

Labels (1)
Tags (4)
1 Solution
3,092 Views
deniscollis
Contributor V

I was able to solve this.  It has to do with the memory aliasing that's used by the K8x.  My own comment is actually the solution staring me in the face!

/* 0x04020000-0x0405FFFF is XiP alias for 0x68020000-0x6805FFFF */

EXT_PGM_FLASH is the address region used by the K8x program counter.  XIP_RESERVED is the physical QSPI mapped address region.  The internal code always uses the EXT_PGM_FLASH, but when programming the chip the debug probe must use XIP_RESERVED.  So the region must be associated with the physical location by using the AT> option. 

} > EXT_PGM_FLASH  AT> XIP_RESERVED 

 

MEMORY
{ 
  PROGRAM_FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x040000
  EXT_PGM_FLASH (rx) : ORIGIN = 0x04020000, LENGTH = 0x100000
  /*  0x04020000-0x0405FFFF is XiP alias for 0x68020000-0x6805FFFF  */
  SRAM_LOWER   (rwx) : ORIGIN = 0x1fff0000, LENGTH = 0x010000
  SRAM_UPPER   (rwx) : ORIGIN = 0x20000000, LENGTH = 0x030000
  /* First 128K infineon has 4K erase, use for Configs */
  TERM_SETTINGS (rx) : ORIGIN = 0x68000000, LENGTH = 0x018000 /* 96K */
  MODULE_CONFIG (rx) : ORIGIN = 0x68018000, LENGTH = 0x008000 /* 32K */
  XIP_RESERVED  (rx) : ORIGIN = 0x68020000, LENGTH = 0x100000 /*  1M */
  OTA_UPDATE    (rx) : ORIGIN = 0x68120000, LENGTH = 0x100000 /*  1M */
}

STACK_SIZE  = 0x1000;

ENTRY(ResetISR)

SECTIONS
{
  /* EXTERNAL QSPI XiP FLASH */
  .text_Flash2 : ALIGN(4)
  {
    FILL(0xff)
    *(.text_Flash2*)
    *(.text_EXT_PGM_FLASH*)
    *(.text.$Flash2*)
    *(.text.$EXT_PGM_FLASH*)
  }> EXT_PGM_FLASH  AT> XIP_RESERVED
    
  .data_Flash2 : ALIGN(4)
  {
    FILL(0xff)
    *(.rodata_Flash2*)
    *(.rodata_EXT_PGM_FLASH*)
    *(.rodata.$Flash2*)
    *(.rodata.$EXT_PGM_FLASH*)
  }> EXT_PGM_FLASH  AT> XIP_RESERVED

 

 

deniscollis_0-1660930197833.png

Note that EXT_PGM_FLASH and XIP_RESERVED are the same size. These are, respectively, the Alias and Physical address regions.

 

Cheers!

Denis 

   

View solution in original post

13 Replies
3,093 Views
deniscollis
Contributor V

I was able to solve this.  It has to do with the memory aliasing that's used by the K8x.  My own comment is actually the solution staring me in the face!

/* 0x04020000-0x0405FFFF is XiP alias for 0x68020000-0x6805FFFF */

EXT_PGM_FLASH is the address region used by the K8x program counter.  XIP_RESERVED is the physical QSPI mapped address region.  The internal code always uses the EXT_PGM_FLASH, but when programming the chip the debug probe must use XIP_RESERVED.  So the region must be associated with the physical location by using the AT> option. 

} > EXT_PGM_FLASH  AT> XIP_RESERVED 

 

MEMORY
{ 
  PROGRAM_FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x040000
  EXT_PGM_FLASH (rx) : ORIGIN = 0x04020000, LENGTH = 0x100000
  /*  0x04020000-0x0405FFFF is XiP alias for 0x68020000-0x6805FFFF  */
  SRAM_LOWER   (rwx) : ORIGIN = 0x1fff0000, LENGTH = 0x010000
  SRAM_UPPER   (rwx) : ORIGIN = 0x20000000, LENGTH = 0x030000
  /* First 128K infineon has 4K erase, use for Configs */
  TERM_SETTINGS (rx) : ORIGIN = 0x68000000, LENGTH = 0x018000 /* 96K */
  MODULE_CONFIG (rx) : ORIGIN = 0x68018000, LENGTH = 0x008000 /* 32K */
  XIP_RESERVED  (rx) : ORIGIN = 0x68020000, LENGTH = 0x100000 /*  1M */
  OTA_UPDATE    (rx) : ORIGIN = 0x68120000, LENGTH = 0x100000 /*  1M */
}

STACK_SIZE  = 0x1000;

ENTRY(ResetISR)

SECTIONS
{
  /* EXTERNAL QSPI XiP FLASH */
  .text_Flash2 : ALIGN(4)
  {
    FILL(0xff)
    *(.text_Flash2*)
    *(.text_EXT_PGM_FLASH*)
    *(.text.$Flash2*)
    *(.text.$EXT_PGM_FLASH*)
  }> EXT_PGM_FLASH  AT> XIP_RESERVED
    
  .data_Flash2 : ALIGN(4)
  {
    FILL(0xff)
    *(.rodata_Flash2*)
    *(.rodata_EXT_PGM_FLASH*)
    *(.rodata.$Flash2*)
    *(.rodata.$EXT_PGM_FLASH*)
  }> EXT_PGM_FLASH  AT> XIP_RESERVED

 

 

deniscollis_0-1660930197833.png

Note that EXT_PGM_FLASH and XIP_RESERVED are the same size. These are, respectively, the Alias and Physical address regions.

 

Cheers!

Denis 

   

3,086 Views
diego_charles
NXP TechSupport
NXP TechSupport

Hi @deniscollis 

Great, thanks for sharing, Denis!

Diego

0 Kudos
3,146 Views
zahidul3
Contributor III

Hi Diego,

I am taking over for Denis who is on vacation. I am able to see the build map to the correct address, but it does not load in the external flash.

Here's snippet of the map file where I try to place the const variable ipsLogo_bmp in external flash:

.text_Flash2 0x04020000 0x0
FILL mask 0xff
*(SORT_BY_ALIGNMENT(.text_Flash2*))
*(SORT_BY_ALIGNMENT(.text_EXT_PGM_FLASH*))
*(SORT_BY_ALIGNMENT(.text.$Flash2*))
*(SORT_BY_ALIGNMENT(.text.$EXT_PGM_FLASH*))

.data_Flash2 0x04020000 0x1200c
FILL mask 0xff
*(SORT_BY_ALIGNMENT(.data_Flash2*))
.data_Flash2 0x04020000 0x1200c ./source/Display/Resources/resources.o
0x04020000 ipsLogo_bmp
*(SORT_BY_ALIGNMENT(.data_EXT_PGM_FLASH*))
*(SORT_BY_ALIGNMENT(.data.$Flash2*))
*(SORT_BY_ALIGNMENT(.data.$EXT_PGM_FLASH*))

Memory region Used Size Region Size %age Used
PROGRAM_FLASH: 199388 B 256 KB 76.06%
EXT_PGM_FLASH: 73740 B 1 MB 7.03%
SRAM_LOWER: 0 GB 64 KB 0.00%
SRAM_UPPER: 79728 B 192 KB 40.55%
TERM_SETTINGS: 0 GB 96 KB 0.00%
MODULE_CONFIG: 0 GB 32 KB 0.00%
XIP_RESERVED: 0 GB 1 MB 0.00%
OTA_UPDATE: 0 GB 1 MB 0.00%

Do I have to add any drivers to download to QuadSPI flash in the project settings:

zahidul3_0-1659375900038.png

 

0 Kudos
3,242 Views
diego_charles
NXP TechSupport
NXP TechSupport

Hi @deniscollis 

I hope that you are doing awesome!

There are several alternatives to place const data on a specific flash region. 

I have not tested this yet, as currently I was locked down with no boards due to covid, but here is a method I used. 

I see that you are working with Kinetis, all the Kinetis MCUs have at structure located at 0x400 thanks to linker.

// Flash Configuration block : 16-byte flash configuration field that stores
// default protection settings (loaded on reset) and security information that
// allows the MCU to restrict access to the Flash Memory module.
// Placed at address 0x400 by the linker script.
//*****************************************************************************
__attribute__ ((used,section(".FlashConfig"))) const struct {
    unsigned int word1;
    unsigned int word2;
    unsigned int word3;
    unsigned int word4;
} Flash_Config = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFF3DFE};

 

diego_charles_0-1658188723779.png

On a similar way I created my array

__attribute__ ((used,section(".FlashConf"))) const uint8_t roarray[1024*6] = {0xAE}

I proceed to create a secondary flash space. In  the MCUXpresso it looks like this on the MCU settings.

diego_charles_1-1658188831501.png

Then, I disabled managed linker script option 

diego_charles_2-1658188905931.png

And I modified the linker to place my array at any desired offset on my secondary flash space.

diego_charles_3-1658190172620.png

Then the output was the following.

diego_charles_4-1658190217795.png

All the best, 

Diego.

 

0 Kudos
3,233 Views
deniscollis
Contributor V

Hi Diego,

This is using internal flash, which I have no problem with.  I'm having an issue trying to achieve the same with external QSPI/XiP flash. 

In any case, thanks for the useful info,

Denis

3,258 Views
bobpaddock
Senior Contributor III

The .text_flash2 section contains a .text_flash2 section.

The .data_flash2 section does not contain a .data_flash2 section.
Add 

 *(.data_Flash2*)

 

0 Kudos
3,230 Views
deniscollis
Contributor V

Hi Bob,

I fixed that, but the data is still placed in internal flash.

    .data_Flash2 : ALIGN(4)
    {
       FILL(0xff)
        *(.data_Flash2*)
        *(.data_EXT_PGM_FLASH*)
        *(.data.$Flash2*)
        *(.data.$EXT_PGM_FLASH*)
    }> EXT_PGM_FLASH
const uint8_t[] __attribute__((section (".data_Flash2"))) bigdata =
{
......
};
Building target: XXX.axf
Invoking: MCU Linker
arm-none-eabi-gcc -nostdlib -Xlinker -Map="XXX.map" -Xlinker --gc-sections -Xlinker -print-memory-usage -Xlinker --sort-section=alignment -Xlinker --cref -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -T k81.ld -L ../startup/ -o "XXX.axf" ...  
Memory region         Used Size  Region Size  %age Used
   PROGRAM_FLASH:      196340 B       256 KB     74.90%
   EXT_PGM_FLASH:          0 GB         1 MB      0.00%
      SRAM_LOWER:          0 GB        64 KB      0.00%
      SRAM_UPPER:       79688 B       192 KB     40.53%
Finished building target: XXX.axf
 

 

0 Kudos
3,200 Views
bobpaddock
Senior Contributor III

Try adding KEEP.  Example from my Linker file, below.

The gc-sections that is in your linker will cause any section of the output to be removed if the compiler thinks it is not referenced.

Also what does the XXX.sym file(s) show? 
Is there actual reference to a symbol in the external section?
Check for miss-spellings.

There are also two versions of the sym file, see blow, sorted by address and sorted by size.

KEEP example:

/* The startup code goes first into INTERNAL_FLASH: */
.isr_vector :
{
__vector_table = ABSOLUTE(.) ; /* Address of the ISR Vector Table */
__isr_vectors_start = .;

/*
* When link-time garbage collection is in use (-gc-sections), it is
* often useful to mark sections that should not be eliminated. This is
* accomplished by surrounding an input section's wild-card entry with
* KEEP(), as in KEEP(*(.init)) or KEEP(SORT(*)(.ctors)).
*/
KEEP(*(.isr_vector))

__isr_vectors_end = .;
} > VECTORS =0xFF

# Create a symbol table from ELF output file.
# Order by address.
%.$(NEW_BUILDNUMBER).sym: %.elf
echo $(SYMBOL_TABLE_MSG) $@
echo NM="$(NM)" -n $(OBJDIR)/$< > $(OBJDIR)/$@
$(NM) -n $(OBJDIR)/$< > $(OBJDIR)/$@
cp $(OBJDIR)/$@ $(TARGET_DIR)/$(TARGET).sym

# Order by size.
%.$(NEW_BUILDNUMBER).sym2: %.elf
echo $(SYMBOL_TABLE_MSG) $@
echo NM="$(NM)" -S --size-sort -s $(OBJDIR)/$< > $(OBJDIR)/$@
$(NM) -S --size-sort -s $(OBJDIR)/$< > $(OBJDIR)/$@
cp $(OBJDIR)/$@ $(TARGET_DIR)/$(TARGET).sym2

Also due to a really obscure linker bug the __Start/__End address need to be inside the section blocks, not outside of them.  Not really your issue here, just be aware of it.

0 Kudos
3,151 Views
diego_charles
NXP TechSupport
NXP TechSupport

Hi @deniscollis 

Where you able to success on this?

Best regards, 

Diego

0 Kudos
2,555 Views
greycon1
Contributor I

Hi, am writing firmware for a new board, K81 and Winbond QSPI external flash. I've never used external flash. Can you suggest where I might start, so I need to learn about memory aliasing , XIP, how to place code in that flash, etc? Thanks

0 Kudos
2,545 Views
bobpaddock
Senior Contributor III

 

I've not used the K81 and access to the documentation is restricted, so I don't know that part.
First check that the K81 does support Execute In Place (XIP).

The Reference Manual and the Data Sheets are always the place to start.
Read them thoroughly before making any schematic.

Some programming pods such as the PEMicro Universal FX will program QSPI Flash parts.

Check if the native bootloader, if there is one, supports loading such a part.
If not create such a bootloader.

As you are new here, I'll also mention that it is considered poor etiquette to hijack someone else's thread.  Always better to start a new one.  It will get more views and response that way too.

2,532 Views
zahidul3
Contributor III

We are also using K81/K82 and we can confirm it does support XIP in external QSPI flash. Also the Segger JLINK flasher we are using also supports loading into external QSPI flash as well. 

Feel free to start a new thread if needed.

2,540 Views
greycon1
Contributor I

Thanks for the pointers Bob. And for the word about etiquette - I wasn't aware, but now I am

0 Kudos