Teensy 4.x: F() ? how to keep strings in flash and not in the ITCM?

KurtE

Senior Member+
Supposed we have a constant table of items that also contain strings, that we would like to keep out of the ITCM or DTCM memory how best to do it?

Example:
Code:
PROGMEM static const struct chipinfo {
	uint8_t id[3];
	uint8_t addrbits;	// number of address bits, 24 or 32
	uint16_t progsize;	// page size for programming, in bytes
	uint32_t erasesize;	// sector size for erasing, in bytes
	uint8_t  erasecmd;	// command to use for sector erase
	uint32_t chipsize;	// total number of bytes in the chip
	uint32_t progtime;	// maximum microseconds to wait for page programming
	uint32_t erasetime;	// maximum microseconds to wait for sector erase
	const char *pn;		//flash name
} known_chips[] = {
	//NAND
	//{{0xEF, 0xAA, 0x21}, 24, 2048, 131072, 134217728,   2000, 15000},  //Winbond W25N01G
	//Upper 24 blocks * 128KB/block will be used for bad block replacement area
	//so reducing total chip size: 134217728 - 24*131072
    {{0xEF, 0xAA, 0x21}, 24, 2048, 131072, 0, 131596288, 2000, 15000, "W25N01GVZEIG"},  //Winbond W25N01G
	//{{0xEF, 0xAA, 0x22}, 24, 2048, 131072, 134217728*2, 2000, 15000},  //Winbond W25N02G
	{{0xEF, 0xAA, 0x22}, 24, 2048, 131072, 0, 265289728, 2000, 15000, "W25N02KVZEIR"},  //Winbond W25N02G
    {{0xEF, 0xBB, 0x21}, 24, 2048, 131072, 0, 265289728, 2000, 15000, "W25M02"},  //Winbond W25M02
};
If I remember correctly the known_chips array will stay in flash, but those strings will not....

I thought one solution to this was using the F() were setup to do this...
like:
Code:
	{{0xEF, 0xAA, 0x22}, 24, 2048, 131072, 0, 265289728, 2000, 15000, F("W25N02KVZEIR")},  //Winbond W25N02G

This leads to a compiler error saying, it can not convert a (const __FlashStringHelper *) to a (const char *)
You can fix this error by casting...

However this still does not appear to leave the string in flash...
At least if I run the sketch:

Code:
void setup()
{
  while (!Serial) ;
  Serial.begin(115200);

  const char *p;

  p = "abcd";
  Serial.printf("%p - %s\n", (uint32_t)p, p);

  p = (const char *)F("efgh");
  Serial.printf("%p - %s\n",  (uint32_t)p, p);

  const __FlashStringHelper *pf = F("ijkl");
  Serial.printf("%p - %s\n",  (uint32_t)pf, pf);
}

void loop() { }

Output:
Code:
0x200004b8 - abcd
0x200004cc - efgh
0x200004d4 - ijkl

Note: if I add
Code:
const char PROGMEM name1[] = "In Flash";
...
  p = name1;
  Serial.printf("%p - %s\n",  (uint32_t)p, p);

Code:
0x200004b8 - abcd
0x200004cc - efgh
0x200004d4 - ijkl
0x60001aa4 - In Flash
So is the only way to do the table with keeping strings out of memory to either
a) define the strings as individual strings like I mentioned and reference them
b) or maybe instead of structure having (const char *) instead have const char[10] where the 10 is size of largest one

Am I missing something obvious?

Edit, should mention this run was using MMOD
 
For global variables, I do not know of any way to use the convenient "string literal" syntax for a char pointer. I believe both of the ways you mentioned work, though using the fixed array size means always allocating the maximum size. But it always avoids allocating 4 bytes for a pointer, so maybe a good trade-off for small strings.
 
For global variables, I do not know of any way to use the convenient "string literal" syntax for a char pointer. I believe both of the ways you mentioned work, though using the fixed array size means always allocating the maximum size. But it always avoids allocating 4 bytes for a pointer, so maybe a good trade-off for small strings.

Thanks Paul, but not sure what the F() is doing, for example in the sketch I mentioned...

I would have thought that:
Code:
 const __FlashStringHelper *pf = F("ijkl");
  Serial.printf("%p - %s\n",  (uint32_t)pf, pf);
Would have shown the address(0x200004d4 ) would be up still in flash, but instead it is showing in ITCM correction DTCM
 
Extended the last two strings beyond 4 characters and both still sit sequentially in ITCM:
Code:
0x200008ac - abcd
0x200008c0 - efgh
0x200008dc - ijkl
0x200008c8 - efghIJKLMN
0x200008d4 - ABCDEFGHijkl
Code:
  p = (const char *)F("efghIJKLMN");
  Serial.printf("%p - %s\n",  (uint32_t)p, p);

  const __FlashStringHelper *pf2 = F("ABCDEFGHijkl");
  Serial.printf("%p - %s\n",  (uint32_t)pf2, pf2);

Doing this puts it in a different segment group - but not FLASH:
Code:
  const char SzSZ[] = "efghIJKLMN";
  Serial.printf("const char SzSZ[]: %p - %s\n",  SzSZ, SzSZ);
Code:
const char SzSZ[]: 0x20077fd4 - efghIJKLMN
 
Some variations are causing errors like:
Code:
error: section attribute cannot be specified for local variables

error: known_chips causes a section type conflict with SzSZ

Odd not that they aren't legal expressions - but given prior expressions these can't be used in the same compilation part?
 
Some variations are causing errors like:
Code:
error: section attribute cannot be specified for local variables

error: known_chips causes a section type conflict with SzSZ

Odd not that they aren't legal expressions - but given prior expressions these can't be used in the same compilation part?

As local vars are on the stack, a section makes no sense :)

note, worst is to define a const array inside a function.
GCC will use a memcpy to copy it to the stack if you use it.. - have seen that - the worst thing i can imagine :) But hey, it just does what the user tells it to do..
 
As local vars are on the stack, a section makes no sense :)

note, worst is to define a const array inside a function.
GCC will use a memcpy to copy it to the stack if you use it.. - have seen that - the worst thing i can imagine :) But hey, it just does what the user tells it to do..

I have it now doing such like:
Code:
	const char * getPN() { 
		PROGMEM static const char pn_name[] = "PROGRAM";
		return pn_name; 
	}

And have output:
Code:
Dump Storage list(7)
store:0 storage:10001 name:Program fs:200059f0 pn:PROGRAM(0x6000373c)
store:1 storage:20001 name:RAM fs:20005abc pn:DMAMEM(0x60003744)
store:2 storage:30001 name:Flash_3 fs:20005b88 pn:W25Q128JV*Q/W25Q128FV(0x60003878)
store:3 storage:40001 name:NAND_4 fs:20005e50 pn:W25N01GVZEIG(0x60003c54)
store:4 storage:50001 name:Flash_5 fs:20006118 pn:W25Q512JV*M (DTR)(0x60003a18)
store:5 storage:60001 name:SD_Builtin fs:20006cbc pn:(0x200017a0)
store:6 storage:70001 name:SD_SPI fs:2000718c pn:(0x200017a0)
And you can see address of the string return is 0x6000373c which is up in flash...
 
As local vars are on the stack, a section makes no sense :)

note, worst is to define a const array inside a function.
GCC will use a memcpy to copy it to the stack if you use it.. - have seen that - the worst thing i can imagine :) But hey, it just does what the user tells it to do..

Sorry, code not included - those are with defines outside the func() - cannot use PROGMEM within a func()

New var char szSZ2 in one case conflicted with independent szSZ, The second szSZ conflicted with prior @mjs513 code where I was inserting this demo code.
> from FS thread : \LFS_PN_Test\LFS_PN_Test.ino
 
Back
Top