Bug: EXTMEM "works" without PSRAM

Frank B

Senior Member
Code:
EXTMEM int a;
 
void setup() {
 a = 123;
 Serial.print(a);
}

void loop() {}
Works, even without PSRAM.
But only as long the dcache wants that it works...
 
Easy fix: Disable that in the MPU if PSRAM is not detected. Startup.c.
The code should take care of the PSRAm Size, too. Otherwise you have the same effect with 8MB PSRAM, but you try to use more..
 
Did not test explicitly this issue, but I think there is a good chance that my old unmerged PR re: MPU fixes that already.
That time I was not aware of this issue.
 
With just removing the MPU setting, it just crashes. This is correct.
The text however could be better:
Code:
CrashReport:
  A problem occurred at (system time) 10:3:59
  Code was executing from address 0x66
  CFSR: 82
    (DACCVIOL) Data Access Violation
    (MMARVALID) Accessed Address: 0x70000000
  Temperature inside the chip was 38.17 °C
  Startup CPU clock speed is 600MHz
Would be nice when it would print "Access to PSRAM, but PSRAM not available" or something like this.
 
Yes, the cache can be misleading. It caused FALSE suggestions that QSPI FLASH was working IIRC.

Proper usage is only known at runtime:
Code:
[B]extern uint8_t external_psram_size;
[/B]EXTMEM int a;

void setup() {
  Serial.begin(1492);
[B]  if ( external_psram_size > 0 ) {[/B]
    a = 123;
    Serial.print(a);
  }
  else
    Serial.print("No PSRAM Detected on this board!");
}

void loop() {}

On the T_4.0 it builds and returns:
Code:
No PSRAM Detected on this board!
 
Yes, but that wouldn't help debug a system where a PSRAM was soldered on and not functioning?

That 'extern' is not referenced on pages below - (it might be nice to not have to know to search "startup.c"):
pjrc.com/store/teensy41.html :: Could explain the expected runtime values of : extern uint8_t external_psram_size; // will have value of 0, 8, or 16 when detected
or
pjrc.com/store/psram.html :: IDE code screen shot
 
Why wouldn't a crash message ""Access to PSRAM, but PSRAM not available" help?
Even the existing unmodified CrashReport gives a clear indication.
 
Would have to have code to check for any address or above in PSRAM ranges?

And only helps when user knows : if ( CrashReport) Serial.print( CrashReport);

That's Paul's decision - but with "C" you can break lots of stuff doing the wrong thing ... especially not having useful documentation.
 
Good news: There is nothing against doing both :)

That may be true, but it seems a lot like WORK :(

Other note would be - EXTMEM is provided to compile on T_4.0?
> Not sure if that is on purpose?

LittleFS has this code when asking for RAM drive:
Code:
  285  #if defined(__IMXRT1062__)
  286: 		return begin(extmem_malloc(size), size);
  287  #else
  288  		return begin(malloc(size), size);

And this HAS_EXTRAM is handy - lots of room for future growth - at compile time:
Code:
#if defined(ARDUINO_TEENSY41)
// Teensy 4.1 external RAM address range is 0x70000000 to 0x7FFFFFFF
#define HAS_EXTRAM
#define IS_EXTMEM(addr) (((uint32_t)ptr >> 28) == 7)
#endif
 
What work? it's an "if" in startup.c a - one or two liner. More good news, I did that already in a PR. Its also possible, to copy these lines only from there, if the rest is not desired.
And, that works on a T4, too.
Edit: Note, that the MPU confit for EXTMEM has to happen *after* the chips are detected. So, just move the corresponding line in startup.c

To consider connected flash memory (does it actually work with EXTMEM?? Never tried that) you can also simply declare the memory area as readonly.
EXTMEM can be used anyway only meaningfully if something is written in at some point in the beginning. So readonly is also ok.
 
Last edited:
Why wouldn't a crash message ""Access to PSRAM, but PSRAM not available" help?

To properly add this to CrashReport, wouldn't we need to configure the MPU to disallow access to the FlexSPI2 memory range?

While possible, one complication is we turn on the MPU pretty early in the startup process, so we can start enjoying the cache speedup. External RAM is detected much later. Code would be needed in the configure_external_ram() function do the FlexSPI2 MPU config.

If this were done somehow, then yes, it would be quite worthwhile to add more text to the CrashReport class to advise that an access violation in that range is regarding non-functional PSRAM.


And only helps when user knows : if ( CrashReport) Serial.print( CrashReport);

... especially not having useful documentation.

Yes, today few people know of CrashReport and it is (so far) only documented on a blog post and some forum conversations.


To consider connected flash memory (does it actually work with EXTMEM?? Never tried that) you can also simply declare the memory area as readonly.
EXTMEM can be used anyway only meaningfully if something is written in at some point in the beginning. So readonly is also ok.

Currently we are using EXTMEM only for RAM, and only for the 16MB range 7000,0000 to 70FF,FFFF.

Except for some very early beta test code, we're not accessing flash on FlexSPI2 as memory mapped. Flash access is always done using the FlexSPI2 "IPS Bus" path.

screenshot.png

The 3 reasons for this design are:

1: IPS Bus allows access to 512MB, compared to only 224MB as memory mapped.
2: Memory mapped access drains away cache from actual variables
3: Writing can't be done by memory mapped access, only by IPS Bus
 
To properly add this to CrashReport, wouldn't we need to configure the MPU to disallow access to the FlexSPI2 memory range?
Yes, this is, what this thread is about. Post #3. :) MPU config.
Ok, so we don't need to take care about flash.

Just use this:
Code:
    // FlexSPI2 PSRAM
    if (external_psram_size == 16) {
        SCB_MPU_RBAR = 0x70000000 | REGION(i++);
        SCB_MPU_RASR = MEM_CACHE_WBWA | READWRITE | NOEXEC | SIZE_16M;
    } else if (external_psram_size == 8) {
        SCB_MPU_RBAR = 0x70000000 | REGION(i++);
        SCB_MPU_RASR = MEM_CACHE_WBWA | READWRITE | NOEXEC | SIZE_8M;
    }
inside configure_cache().
Right, of course it does need to know the size. This can be done by moving configure_cache a few lines later, or do the PSRAM Config a few lines earlier.

If you want to harden that even more, consider a last "else" that explicitly disables this area: DEV_NOCACHE | NOACCESS


Code:
#ifdef ARDUINO_TEENSY41
    configure_external_ram();
#endif
    configure_cache();
    startup_early_hook();
    while (millis() < 20) ; // wait at least 20ms before starting USB
Or whatever.. there will be a way ;)

At least 20ms is no problem. Neither 300ms.
 
Last edited:
...and magically this crashed now - as the fix is correct.
Code:
EXTMEM int a;
 
void setup() {
  Serial.println(CrashReport);
  a = 123;
  Serial.print(a);
}

void loop() {}

Edit:Without this patch TD simply lies, and claims the value would be stored somewhere.
Code:
CrashReport:
  A problem occurred at (system time) 0:0:0
  Code was executing from address 0xB4
  CFSR: 82
    (DACCVIOL) Data Access Violation
    (MMARVALID) Accessed Address: 0x70000000
  Temperature inside the chip was 29.85 °C
  Startup CPU clock speed is 600MHz
  Reboot was caused by auto reboot after fault or bad interrupt detected

Even without CrashReport it is useful - as the Teensy restarts and does not do magic things that will go wrong much later, sometime when the cache gets invalidated. Edit: Which can be hard to debug.
 
Last edited:
Back
Top