Teensy 4.1 EXTMEM not working in header file, section attribute not allowed.

Status
Not open for further replies.

joeribraams

New member
Hello, I've soldered 2 PSRAM chips on my T4.1, the memory test program works and shows both chips, and when I make an EXTMEM array in the main .ino file it works. However if I try to make an EXTMEM array in an class in a seperate .h file, if gives me this error (with verbose output this is the only relevant part):

Code:
\sketch\FxLooper.h:110:41: error: section attribute not allowed for 'bufferL'
EXTMEM int16_t bufferL[LOOPER_MAX_SIZE];
                                       ^

This is my code for the class:

Code:
#ifndef Looper_h
#define Looper_h

#include "Arduino.h"

#define LOOPER_MAX_SIZE 441000

class Looper
{
public:


// Constructor and destructor ////////////////////////////////////////////////////////////////

  Looper(uint16_t blockSize, bool killDry)
  {
    this->blockSize = blockSize;
    this->killDry = killDry;
  }
  ~Looper() {}
  

// Process a block of samples ////////////////////////////////////////////////////////////////

  void processBlock(int16_t * inL, int16_t * inR, int16_t * outL, int16_t * outR)
  {
    for(uint16_t i = 0; i < blockSize; i++)
    {
      if(recording)
      {
        bufferL[bufStep] = (bufferL[bufStep] * playing) + inL[i];
        bufferR[bufStep] = (bufferR[bufStep] * playing) + inR[i];
        checkLength();
      }

      bufStep <= bufLen ? bufStep++ : bufStep = 0; // Increment and wrap index

      killDry ? dryOut = !playing : dryOut = true;
    
      outL[i] = (inL[i] * dryOut) + (bufferL[bufStep] * playing);
      outR[i] = (inL[i] * dryOut) + (bufferR[bufStep] * playing);
    }
  }


// Setters for footswitch control ////////////////////////////////////////////////////////////////

  void fsClick()
  {
    if(playing)
    {
      initLooper();
    }
    else // A short tap when not playing can also start the loop
    {
      fsStop();
    }
  }
  
  void fsHold()
  {
    if(!blockRec && millis() > (debounce + 50))
    {
      recording = true;
      blockRec = true;
    }
  }
  
  void fsStop()
  {
    recording = false;
    playing = true;
    blockRec = false;
    debounce = millis();
  }

  void initLooper()
  {
    playing = false;
    recording = false;
    blockRec = false;
    debounce = millis();
    bufStep = 0;
    bufLen = 0;
  }


// Getter for the led state ////////////////////////////////////////////////////////////////

  uint8_t checkLeds()
  {
    return recording ? 2 : playing;
  }

private:


// To prevent buffer overflow ////////////////////////////////////////////////////////////////

  void checkLength()
  {
    if(!playing)
    {
      bufLen < LOOPER_MAX_SIZE ? bufLen++ : playing = true;
    }
  }

  
// Stores the samples in PSRAM ////////////////////////////////////////////////////////////////

  EXTMEM int16_t bufferL[LOOPER_MAX_SIZE];
  EXTMEM int16_t bufferR[LOOPER_MAX_SIZE];

  
// Place in and length of loop ////////////////////////////////////////////////////////////////

  uint32_t bufStep = 0;
  uint32_t bufLen = 0;


// Stores state of system ////////////////////////////////////////////////////////////////

  bool recording = false;
  bool playing = false;
  bool blockRec = false;
  bool killDry;
  bool dryOut = true;
  uint32_t debounce;
  uint16_t blockSize;
};

#endif

Does anyone here have any idea what causes this? I've searched the forums and elsewhere online but no luck so far. Does my suspicion that it's caused by the buffer being inside a class make any sense? Can I solve this in the class or will I have to move the buffer outside of the class somehow?
 
Not sure - but seems that is going to end up as dynamic code at runtime for each instance - which can't work on a fixed resource?

See :: learncpp.in/memory-allocation-in-cpp/#static_memory_allocation_in_C

That doesn't actually show using 'static' in an example after an explanation that may help/apply. This has a simple example : geeksforgeeks.org/memory-allocation-in-static-data-members-in-c/

perhaps:
Code:
// Stores the samples in PSRAM ////////////////////////////////////////////////////////////////

  static EXTMEM int16_t bufferL[LOOPER_MAX_SIZE];
  static EXTMEM int16_t bufferR[LOOPER_MAX_SIZE];
 
I think @defragster's answer is correct. And again not sure if you would specify that within the class definition.

That is your current version is trying to say part of my object data is defined somewhere else. Which probably would not work there.

My guess and again only a guess is that you would in header file simpley say:
Code:
  static int16_t bufferL[LOOPER_MAX_SIZE];
  static int16_t bufferR[LOOPER_MAX_SIZE];

And in the code file you would put in:
EXTMEM int16_t Looper::bufferL[LOOPER_MAX_SIZE];
EXTMEM int16_t Looper::bufferR[LOOPER_MAX_SIZE];

But warning this makes them class variables... I.e. only one set of these buffers, not one per each instance of this class.

If you are planning for multiple instances for these objects and each needs their own buffer, than you probably need to do something like:
simply define it in your code as a pointer to each buffer, and then allocate the buffer for each one.
the extmem_malloc functions and the like that have been added to core... Not sure if these are in a build yet.
 
I agree with KurtE and Defragster. It simply doesn't work to have parts of a class in a different memory section. At the end of the day the compiler needs to be able to calculate the size of the class in memory to be able to do e.g. arrays of objects. The suggested static buffer will only work if you ever have only one object of this class because static variables are shared between objects as defragster mentioned.

I suggest to simply put the whole object into EXMEM. Something like that:

Code:
#include "looper.h"

EXTMEM Looper myLooper1(42, false);
EXTMEM Looper myLooper2(17, false);

void setup()
{   

}


void loop()
{

}

Or allocate the storage dynamically (you'll need TD 1.54beta for that). Edit: just saw that KurtE already proposed that...
 
Ah great, putting the objects into extmem works just perfectly, so simple but I hadn't thought of that at all. Thank you all so much!
 
Ahhh okay! Starting to make sense. Wish I could add a PSRAM chip to the Teensy Audio Shield, but I guess I can add a Teensy Audio Shield to a Teensy 4.1 with the ram chips soldered in.
 
PSRAM on T_4.1 chip pads runs at QSPI - 4 data I/O Quad mod with inbuilt processor addressing interface mapping it into memory space.

Putting the chip on the Audio card would be single bit SPI mode ...
 
Status
Not open for further replies.
Back
Top