Call to arms | Teensy + SDRAM = true

To use EXTSDMEM on the dev board have to edit the ILI9488 library
Uncomment the following line:
Code:
//#define ENABLE_EXT_DMA_UPDATES  // This is only valid for those T4.1 which have external memory.

and change:
Code:
#ifndef ARDUINO_TEENSY41
to
#ifndef ARDUINO_TEENSY_MICROMOD
 
Oh since you asked if you use PSRAM RAFB 8bit):
Code:
Begin: CS:10, DC:9RST: 8
  Size of RAFB: 2
::begin 20002488 255 255 255
ILI9488_t3::begin - End
Time noFB: 615
Time updateScreen: 677
Time updateScreenAsync: 675
Time noFB: 615
Time updateScreen: 675
Time updateScreenAsync: 675
slower than SDRAM
 
Past test was done using the RAFB on the TMM SDRAM Dev board set at 32 bits while other tests were done at 16bit. To compare more I set it up to use RAFB = 16bits and timing improved - now its on par with using DMAMEM

Code:
Begin: CS:10, DC:9RST: 8
  Size of RAFB: 2
::begin 20002488 255 255 255
ILI9488_t3::begin - End
Time noFB: 615
Time updateScreen: 637
Time updateScreenAsync: 637
Time noFB: 615
Time updateScreen: 636
Time updateScreenAsync: 637
 
I also have the library as a stand alone version: https://github.com/mjs513/SDRAM_t4

I'm really glad you made this. Here's some quick feedback.

1: Please add sdram_malloc(). You can probably just copy extmem.c from the core library and rename the functions and get rid of the HAS_EXTRAM checks and fallback to normal malloc(), since anyone using the library would presumably have SDRAM installed. The code should be able to use the sm_malloc stuff from the core library, so you ought to just need that 1 file inside your library, and copy wiring.h lines 227-230 to SDRAM_t4.h (of course renamed and surrounded with extern "C").

2: Memory initialization should probably wipe the SDRAM to zeros after those IP commands. You might also consider renaming init() to begin(), as it's an Arduino naming convention. Maybe begin() could take an integer to configure how much memory?

3: The 3 examples are fairly long and complex for an Arduino library. All 3 appear to be some sort of memory test. They could really benefit from comments added at the top to explain what each example really does, especially with some explanation why someone would want to run it versus the other examples.

4: Adding a couple simpler and short examples focused on usage cases (rather than only hardware testing) would probably make this much more approachable for people in the future. Just 1 example showing usage of ILI9488 frame buffer (perhaps future version of the ILI9488 DMA library) would go a long way. A very simple hardware serial example with addMemoryForRead() might also be nice. Hopefully those examples would demonstrate use of sdram_malloc() as the intended way to get access to the SDRAM memory.

5: The readme could briefly mention the public functions, so people get an initial impression of how they'll really use the library when they see the github page.

6: Adding MIT license to the files would be good. Just to confirm, everything I wrote was meant to be MIT license. I'm not concerned about attribution or credit. My main concern is for people in the future to be able to understand and actually use this stuff... without needing to read 300+ forum messages.

7: The comments in SDRAM_t4.h mentioning the old MPU config should be updated or replaced with an mention newer core library with the MPU config is needed.
 
Last edited:
Past test was done using the RAFB on the TMM SDRAM Dev board set at 32 bits while other tests were done at 16bit. To compare more I set it up to use RAFB = 16bits and timing improved - now its on par with using DMAMEM
Quick notes: The ILI9488 board in SPI mode does not support 16 bit pixels. It supports 18 bit mode, which is sent as 24 bits (6 bits per byte)...
So unless RAFB is in 32 bit mode, the display code does not do DMA from the frame buffer, instead it has two smaller buffers as part of the class, that it transforms the 16 bits into 24 bits to fill those two buffers and starts DMA, when one buffer finished output, it interrupts on the completion and fills it in with the next part....

So again, you are no longer testing DMA from that memory, also while it may complete faster, it is taking up more CPU, to do the transforms, as part of the page update...
 
Opps, adding sdram_malloc() is a little more complicated than just copying extram.c and renaming functions. But hopefully this isn't too much....

You'll also need to add this in your copy of extmem.c.

Code:
struct smalloc_pool sdram_smalloc_pool;

Of course, in addition to renaming the functions from "extmem" to "sdram", also change all "extmem_smalloc_pool" to "sdram_smalloc_pool".

Then in SDRAM_t4.cpp, you'll need something like this at the top:

Code:
#include <smalloc.h>
extern "C" struct smalloc_pool sdram_smalloc_pool;

and this inside your initialization after the memory is up and running.

Code:
    sm_set_pool(&sdram_smalloc_pool, (void *)0x90000000, 0x02000000, 1, NULL);

The 0x02000000 number is the memory size. If you make begin() take an input for the connected SDRAM chip size, this is where you'll put it to good use so sdram_malloc() knows how much memory to serve up.
 
Opps, adding sdram_malloc() is a little more complicated than just copying extram.c and renaming functions. But hopefully this isn't too much....
Just so not quoting the whole message - but short answer is Tim was working on that but he is running into issues. Will work on it now that you seem amiable to incorporating it :) You realize you are making me something new again :)

edit:
You can probably just copy extmem.c
already have a extsdmem.c file that does that so should be easy to incorporate.

Memory initialization should probably wipe the SDRAM to zeros after those IP commands. You might also consider renaming init() to begin(), as it's an Arduino naming convention. Maybe begin() could take an integer to configure how much memory?
Ok can add - that should not be an issue.

The 3 examples are fairly long and complex for an Arduino library. All 3 appear to be some sort of memory test. They could really benefit from comments added at the top to explain what each example really does, especially with some explanation why someone would want to run it versus the other examples.
Only one test I added and that was for the PSRAM type test to check memory. Tim will have to comment the others

Adding a couple simpler and short examples focused on usage cases (rather than only hardware testing) would probably make this much more approachable for people in the future. Just 1 example showing usage of ILI9488 frame buffer (perhaps future version of the ILI9488 DMA library) would go a long way. A very simple hardware serial example with addMemoryForRead() might also be nice. Hopefully those examples would demonstrate use of sdram_malloc() as the intended way to get access to the SDRAM memory.

will add to the todo list maybe @defragster can do it for Hardware serial

items 5 - 6 - 7; ok to the readme, mit license should already be there - when i created the repo I selected MIT License, - forgot that the comment was there :)
 
Last edited:
So again, you are no longer testing DMA from that memory, also while it may complete faster, it is taking up more CPU, to do the transforms, as part of the page update...
Thanks Kurt - should have known but did not register when I was doing it this morning :)
 
Is there a way to specify using EXTSDMEM? from the library or would that have to be done in the core (pgmspace.h).

Static allocation requires deeper integration in the core library.

For use with the official core library, let's plan on supporting only dynamic allocation. Might revisit this decision in the (likely distant) future if use case come up which absolutely need static allocation. But I'm pretty sure people using this can just call sdram_malloc() at startup to get the memory they need.

Of course you can have #ifdefs to check for an alternative core library and adjust your call to sm_set_pool() and maybe other stuff as necessary, if you want to support static allocation. You can look to the sm_set_pool() call in startup.c for inspiration. But for use with the normal core library, please use sm_set_pool(&sdram_smalloc_pool, (void *)0x90000000, 0x02000000, 1, NULL) so the entire SDRAM is accessible with dynamic allocation only.

Now that we're using 0x90000000 and we know issues exist with part of 0x80000000, I might change the default MPU config to 0x90000000 and a smaller range.
 
Indeed, I put together a version yesterday as
To make sure it would NOT pick up old stuff I renamed to SDRAMdb_t4 as DevBoard and have worked at making it work on a clean TeensDuino 1.59.4 build with only expected edits to CORES for that build: imxrt.h {SEMC names}, startup.c {MPU}, and then needed edit to imxrt_tmm.ld {reserve/name the 0x90000000 region} (in core files folder)

Then the old SDRAM_t4 library works with noted issues like .init() and indeed has a local copy of 'extsdram.c' for the needed POOL struct and sdram_malloc() interface functions ... but I missed something ...

What I am finding is allocating 12 blocks with sdram_malloc() is not working for valid unique address return - but cycling through like this:
SUCCESS sdram.init()
SerBArr[0][0] at 0x9000000c
SerBArr[0][1] at 0x90006024
SerBArr[0][2] at 0x9000000c
SerBArr[1][0] at 0x9000000c
SerBArr[1][1] at 0x90006024
SerBArr[1][2] at 0x9000000c
SerBArr[2][0] at 0x90006024
SerBArr[2][1] at 0x9000000c
SerBArr[2][2] at 0x90006024
SerBArr[3][0] at 0x9000000c
SerBArr[3][1] at 0x90006024
SerBArr[3][2] at 0x9000000c
SerBArr[4][0] at 0x90006024
SerBArr[4][1] at 0x9000c03c
SerBArr[4][2] at 0x9000000c
And 2/3'rds of those pointer go to serial's addMemoryFor[read/write] and they stomp on each other.

So it is working to BUILD - but somewhere the pool integrity/Math is not working at this time

<edit>Code Snip (from UART_extmem_ARR.ino): each of those alloc's is 24KB and same code works with 'full integration' but the SDRAMdb_t4 version gives the above from the printf() included below:
Code:
 if (sdram.init()) {
    Serial.print( "\n\tSUCCESS sdram.init()\n");
  }
  else {
    Serial.print( "\n\tFAILED sdram.init()\n");
  }

  for ( uint32_t ii = 0; ii < USED_UARTS; ii++ ) {
    for ( uint32_t jj = 0; jj < 3; jj++ ) {
      SerBArr[ii][jj] = (char *)sdram_malloc(24 * 1024);
      Serial.printf( "\n SerBArr[%u][%u] at %p",ii, jj , SerBArr[ii][jj] );
      if ( 0 == SerBArr[ii][jj] ) flSDRAM++;
    }
  }
 
Last edited:
@PaulStoffregen
Per your instructions I moded sdram_t4 so nothing is touched in the core - some of it was also looking at what @defragster did.

Branch is here: https://github.com/mjs513/SDRAM_t4/tree/sdmalloc_sdram

I keep getting a crashreport:
Code:
CrashReport:
  A problem occurred at (system time) 15:17:43
  Code was executing from address 0x351A
  CFSR: 400
    (IMPRECISERR) Data bus error but address not related to instruction
  Temperature inside the chip was 47.48 °C
  Startup CPU clock speed is 600MHz
  Reboot was caused by auto reboot after fault or bad interrupt detected

Tim got this but don't remember what we did to fix it.

This is my test sketch:

Code:
#include <SDRAM_t4.h>
SDRAM_t4 sdram;

 
void setup()
{
    Serial.begin(115200);

    if(CrashReport) {
      Serial.print(CrashReport);
      while(1);
    }
 
    if(!sdram.begin()) {
      Serial.printf("SDRAM Init Failed!!!\n");
      while(1);
    };

    // This pointer will hold the
    // base address of the block created
    int* ptr;
    int n, i;
 
    // Get the number of elements for the array
    n = 24;
    printf("Entered number of elements: %d\n", n);
 
    // Dynamically allocate memory using malloc()
    ptr = (int*)sdram_malloc(n * sizeof(int));
 
    // Check if the memory has been successfully
    // allocated by malloc or not
    if (ptr == NULL) {
        Serial.printf("Memory not allocated.\n");
        exit(0);
    }
    else {
 
        // Memory has been successfully allocated
        printf("Memory successfully allocated using malloc.\n");
 
        // Get the elements of the array
        for (i = 0; i < n; ++i) {
            ptr[i] = i + 1;
        }
 
        // Print the elements of the array
        Serial.printf("The elements of the array are: ");
        for (i = 0; i < n; ++i) {
            Serial.printf("%d, ", ptr[i]);
        }
    }

}

void loop(){}

Have a cold and getting ready for a storm so my head is a bit foggy
 
Ok fixed output is now:
Code:
Entered number of elements: 24
Memory successfully allocated using malloc.
The elements of the array are: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,

Going to push the change now.
 
Changed the sketch a bit to print the address out as well:

Code:
#include <SDRAM_t4.h>
SDRAM_t4 sdram;

 
void setup()
{
    Serial.begin(115200);

    if(CrashReport) {
      Serial.print(CrashReport);
      while(1);
    }
 
    delay(4000);

    if(!sdram.begin()) {
      Serial.printf("SDRAM Init Failed!!!\n");
      while(1);
    };

    // This pointer will hold the
    // base address of the block created
    int* ptr;
    int n, i;
 
    // Get the number of elements for the array
    n = 24;
    printf("Entered number of elements: %d\n", n);
 
    // Dynamically allocate memory using malloc()
    ptr = (int*)sdram_malloc(n * sizeof(int));
 
    // Check if the memory has been successfully
    // allocated by malloc or not
    if (ptr == NULL) {
        Serial.printf("Memory not allocated.\n");
        exit(0);
    }
    else {
 
        // Memory has been successfully allocated
        printf("Memory successfully allocated using malloc.\n");
 
        // Get the elements of the array
        for (i = 0; i < n; ++i) {
            ptr[i] = i + 1;
        }
 
        // Print the elements of the array
        Serial.printf("The elements of the array are: ");
        for (i = 0; i < n; ++i) {
            Serial.printf("%d, %x \n", ptr[i], &ptr[i]);
        }
    }

}

void loop(){}

output:

Code:
Entered number of elements: 24
Memory successfully allocated using malloc.
The elements of the array are: 1, 9000000c
2, 90000010
3, 90000014
4, 90000018
5, 9000001c
6, 90000020
7, 90000024
8, 90000028
9, 9000002c
10, 90000030
11, 90000034
12, 90000038
13, 9000003c
14, 90000040
15, 90000044
16, 90000048
17, 9000004c
18, 90000050
19, 90000054
20, 90000058
21, 9000005c
22, 90000060
23, 90000064
24, 90000068

So at least it looks like it putting it in the right place :)
 
Note - examples need work and README has to be updated.

Also never really used malloc/calloc very often so any one has any decent examples let me know
 
Some things are STATIC on the chips (SDRAM init?) and change after POWER CYCLE.
It may be that or a filure to use 0x9--- address space and then the SPICommands don't work.

@mjs513
Trying that lib version. where is needed version of extmem.c?
What cores files are in use?
 
Trying that lib version. where is needed version of extmem.c?
What cores files are in use
Extmem.c is part of the lib - no need to add to cre.

Only core files need are imxrt.h with semc registers and the scb changes to startup.c. In other words just the changes Paul made to the core. 😀
 
Not seeing any examples using sm_alloc() ? And sm
Extmem.c is part of the lib - no need to add to cre.

Only core files need are imxrt.h with semc registers and the scb changes to startup.c. In other words just the changes Paul made to the core. 😀
didn't find an example using sm_alloc() and it needs to be included.
When build example here using that:
SUCCESS sdram.init()

SerBArr[0][0] at 0x0
SerBArr[0][1] at 0x0
SerBArr[0][2] at 0x0
SerBArr[1][0] at 0x0
SerBArr[1][1] at 0x0
SerBArr[1][2] at 0x0
SerBArr[2][0] at 0x0
SerBArr[2][1] at 0x0
SerBArr[2][2] at 0x0
SerBArr[3][0] at 0x0
SerBArr[3][1] at 0x0
SerBArr[3][2] at 0x0
SerBArr[4][0] at 0x0
SerBArr[4][1] at 0x0
SerBArr[4][2] at 0x0
Compile Time:: C:\Users\TimLabs\Documents\GitHub\EVKB_1060\mallocSDRAM - Copy\SDRAMdb_t4\examples\UART_extmem_ARR\UART_extmem_ARR.ino Jan 6 2024 13:29:09
3221225472 sdram_malloc FAILS!!
Should be a clean 1.59.4 with needed cores edits - no build warning/error
 
Look at example posted, sm_alloc is used by calling sdram_malloc. You aren’t using sm_alloc.
Support functions are defined via
Code:
void *sdram_malloc(size_t size);
void sdram_free(void *ptr);
void *sdram_calloc(size_t nmemb, size_t size);
void *sdram_realloc(void *ptr, size_t size);
}
 
Most programs needing large buffers will just call sdram_malloc(size) for each buffer in their setup() function.

For example programs, there's probably no need to demonstrate more complex usage.
 
Pulled github and not seeing : sdram_malloc
Or a example that used it ?

Is that in your repository? or the original WIP?
 
Back
Top