Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 10 of 10

Thread: Dynamically create OctoWS2811 object within in a class's constructor

  1. #1
    Junior Member
    Join Date
    Oct 2019
    Posts
    5

    Dynamically create OctoWS2811 object within in a class's constructor

    Also posted here:
    https://stackoverflow.com/questions/...ss-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:
    }

  2. #2
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,306
    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];
    
      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);
      // 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.

  3. #3
    Junior Member
    Join Date
    Oct 2019
    Posts
    5
    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

  4. #4
    Junior Member
    Join Date
    Oct 2019
    Posts
    5

    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:
    }

  5. #5
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,907
    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

    Click image for larger version. 

Name:	teensy4_memory.png 
Views:	0 
Size:	52.2 KB 
ID:	19471

  6. #6
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,464
    You can't use DMAMEM with malloc() or C++ new. It's for static allocation only. Just leave it out.

  7. #7
    Senior Member
    Join Date
    Feb 2017
    Posts
    364
    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).

  8. #8
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,907
    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.

  9. #9
    Senior Member
    Join Date
    Feb 2017
    Posts
    364
    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.

  10. #10
    Senior Member crees's Avatar
    Join Date
    Dec 2016
    Location
    Utah
    Posts
    214
    Quote Originally Posted by gfvalvo View Post
    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/Teen...Controller.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.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •