Dynamically create OctoWS2811 object within in a class's constructor

Status
Not open for further replies.
Also posted here:
https://stackoverflow.com/questions...library-object-within-in-a-classs-constructor

I am trying to create a object for a LED matrix which could have a varying size throughout a program's runtime. To do this I am trying to dynamically create an object from the OctoWS2811 library and define it's size within the constructor of a display class. How would I do this properly? Is this possible? Thank you

Here is the normal way an OctoWS2811 object is created:

Code:
const int ledsPerPin = 120 * (32 / 8);

DMAMEM int displayMemory[ledsPerPin * 6];
int drawingMemory[ledsPerPin * 6];
const int config = WS2811_GRB | WS2811_800kHz;
OctoWS2811 leds(ledsPerPin, displayMemory, drawingMemory, config);

And here is an example of what I am trying to do:

Code:
#include <Arduino.h>
#include <OctoWS2811.h>

class Display
{
  OctoWS2811 *leds; // Dynamically allocated
  DMAMEM int *displayMemory;
  int *drawingMemory;
  const int config = WS2811_GRB | WS2811_800kHz;
  int width, height;

public:
  Display(int w, int h);
  void Draw();
};

Display::Display(int w, int h)
{
  width = w;
  height = h; //Must be multiple of 8
  int ledsPerPin = (height / 8) * width;
  displayMemory = new DMAMEM int[ledsPerPin * 6];
  drawingMemory = new int[ledsPerPin * 6];

  OctoWS2811 temp(ledsPerPin, displayMemory, drawingMemory, config);

  *leds = temp; //How do I do this properly?
}

void Display::Draw() {
  // Draw stuff with the object
  leds.setPixel(56, 0xFF0000);
}

void setup()
{
  Display Test(120, 32);
  // put your setup code here, to run once:
}

void loop()
{
  // put your main code here, to run repeatedly:
}
 
I am not sure how well that library works with stuff created on the heap... But the first thing I would do is:

Code:
Display::Display(int w, int h)
{
  width = w;
  height = h; //Must be multiple of 8
  int ledsPerPin = (height / 8) * width;
  displayMemory = new DMAMEM int[ledsPerPin * 6];
  drawingMemory = new int[ledsPerPin * 6];

[COLOR="#FF0000"]  leds = new OctoWS2811(ledsPerPin, displayMemory, drawingMemory, config);[/COLOR]
}

void Display::Draw() {
  // Draw stuff with the object
[COLOR="#FF0000"]  leds->setPixel(56, 0xFF0000);[/COLOR]
}

void setup()
{
  Display Test(120, 32);
  // put your setup code here, to run once:
}

Actually personally I don't like my constructors doing stuff like create other objects or the like as not sure what things are init or not...
So I would probably move all of the stuff out of your constructor other than keep the width/height, and create a new method with a name like setup or init
Which I would call during setup, that allocated the memory and created the octo... object.

But again I have never used the OCTO... board or library, so not sure what else you might run in to.
 
Thanks! That's a great tip! That worked well except I am now getting an error to do with the DMAMEM array. Here is the error:

Code:
src/main.cpp:7:15: error: section attribute not allowed for 'displayMemory'
   DMAMEM int *displayMemory;
               ^
src/main.cpp:7:15: warning: 'used' attribute ignored [-Wattributes]
src/main.cpp: In constructor 'Display::Display(int, int)':
src/main.cpp:22:48: warning: 'section' attribute does not apply to types [-Wattributes]
   displayMemory = new DMAMEM int[ledsPerPin * 6];
                                                ^
src/main.cpp:22:48: warning: 'used' attribute does not apply to types [-Wattributes]
*** [.pio/build/teensy36/src/main.cpp.o] Error 1
 
New Full Code:

After the changes, this is my new code

Code:
#include <Arduino.h>
#include <OctoWS2811.h>

class Display
{
  OctoWS2811 *leds; // Dynamically allocated
  DMAMEM int *displayMemory;         //This is the line it is yelling at me about
  int *drawingMemory;
  const int config = WS2811_GRB | WS2811_800kHz;
  int width, height;

public:
  Display(int w, int h);
  void Draw();
};

Display::Display(int w, int h)
{
  width = w;
  height = h; //Must be multiple of 8
  int ledsPerPin = (height / 8) * width;
  displayMemory = new DMAMEM int[ledsPerPin * 6];
  drawingMemory = new int[ledsPerPin * 6];

  leds = new OctoWS2811(ledsPerPin, displayMemory, drawingMemory, config);

}

void Display::Draw() {
  // Draw stuff with the object
  leds->setPixel(56, 0xFF0000);
}

void setup()
{
  Display Test(120, 32);
  Test.Draw();
  // put your setup code here, to run once:
}

void loop()
{
  // put your main code here, to run repeatedly:
}
 
DMAMEM is compile time directive - gives static ram alloc in the heap area just like 'new' at runtime.

At runtime just doing 'new' should do what is needed without DMAMEM decoration.

pjrc.com/store/teensy40.html

teensy4_memory.png
 
At best, this:
Code:
DMAMEM int *displayMemory;
would just give you a pointer variable in the DMAMEM area. When you dynamically allocate the memory, it may or may not be located in the DMAMEM area. That depends on how much of that memory has already been allocated there at the time (either statically or dynamically).
 
as noted in p#5 and p#6 above DMAMEM is being misused leading to the compiler complaints.

All 32 bit ARM pointers are 'FLAT' - they can reach all of memory RAM1 or RAM2 or FLASH, and any device memory etc.

The only reason to use DMAMEM is getting the compiler/linker to reserve a static block of memory at compile/link time in the RAM2 area. As noted that is the same area new/malloc() allocate heap memory from.

If the size of the desired block is known at compile time - DMAMEM can be used to reserve that block and get a ptr* to it. If memory is allocated at runtime with new/malloc() it will come from RAM2 - same as DMAMEM - but by the runtime allocation process.
 
Might be easiest to just statically allocate all the DMAMEM for the largest LED count you're going to need. Then just create the OctoWS2811 object and tell it the ledsPerPin count. It will use as much of the allocated memory as it needs.
 
Might be easiest to just statically allocate all the DMAMEM for the largest LED count you're going to need. Then just create the OctoWS2811 object and tell it the ledsPerPin count. It will use as much of the allocated memory as it needs.

Exactly!

https://github.com/DirectOutput/TeensyStripController/blob/master/TeensyStripController.ino

I found this gem and use the same method to change my length from a web based config. Once they put in the pixels per strip settings etc the command is sent to the teensy that immediately stores the value in eeprom and then reboots to load the new setting. I use a linux sbc and tytools / tycommander to manage my teensy boards and push settings / firmware from a web interface.
 
Status
Not open for further replies.
Back
Top