Program Code compatibility with Arduino.

Hello,

I am following the below tutorial

to control WS2811 LED lights using MadMapper and Arduino Uno. I just wanted to know if the code given in the tutorial is compatible with an Arduino Uno cause I get the error.

Sketch uses 5594 bytes (17%) of program storage space. Maximum is 32256 bytes.
Global variables use 4586 bytes (223%) of dynamic memory, leaving -2538 bytes for local variables. Maximum is 2048 bytes.
Not enough memory; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing your footprint.
Error compiling for board Arduino/Genuino Uno.

Is there any way I could modify the code so that I could use it with my Arduino?

Including the code below

#include <SPI.h>
#include <FastLED.h>

#define MAD_LED_PACKET_HEADER 0xFF
#define MAD_LED_DATA 0xBE
#define MAD_LED_DETECTION 0xAE
#define MAD_LED_DETECTION_REPLY 0xEA
#define MAD_LED_PROTOCOL_VERSION 0x01

//#define DEBUG_MODE
// To test LEDs (FastLED) without the need of MadMapper or MadRouter sending data on serial port
//#define JUST_TEST_LEDS

#define NUM_LEDS 60
#define DATA_PIN 8
#define CLOCK_PIN 6

// Fast LED Buffers
CRGB leds[NUM_LEDS];

// MadLED protocol buffer
char dataFrame[4086];
int readingFrameOnLine=-1;
bool gotNewDataFrame=false;

enum State {
  State_WaitingNextPacket,
  State_GotPacketHeader,
  State_WaitingLineNumber,
  State_WaitingChannelCountByte1,
  State_WaitingChannelCountByte2,
  State_ReadingDmxFrame
};

State inputState=State_WaitingNextPacket;
unsigned int channelsLeftToRead=0;
char* frameWritePtr=dataFrame;

void setup() { 
  Serial.begin(921600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  
  for (unsigned int i=0; i<sizeof(dataFrame); i++) dataFrame[i]=0;

FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, RGB, DATA_RATE_MHZ(2)>(leds, NUM_LEDS);
  // Here setup FastLED first LED line protocol
  // Uncomment/edit one of the following lines for your leds arrangement.
  // FastLED.addLeds<TM1803, DATA_PIN, RGB>(leds, NUM_LEDS);
  // FastLED.addLeds<TM1804, DATA_PIN, RGB>(leds, NUM_LEDS);
  // FastLED.addLeds<TM1809, DATA_PIN, RGB>(leds, NUM_LEDS);
  FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
  // FastLED.addLeds<WS2812, DATA_PIN, RGB>(leds, NUM_LEDS);
  // FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
  // FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  // FastLED.addLeds<APA104, DATA_PIN, RGB>(leds, NUM_LEDS);
  // FastLED.addLeds<UCS1903, DATA_PIN, RGB>(leds, NUM_LEDS);
  // FastLED.addLeds<UCS1903B, DATA_PIN, RGB>(leds, NUM_LEDS);
  // FastLED.addLeds<GW6205, DATA_PIN, RGB>(leds, NUM_LEDS);
  // FastLED.addLeds<GW6205_400, DATA_PIN, RGB>(leds, NUM_LEDS);
  // FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, RGB, DATA_RATE_MHZ(2)>(leds, NUM_LEDS);
  // FastLED.addLeds<WS2801, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
  // FastLED.addLeds<SM16716, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
  // FastLED.addLeds<LPD8806, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
  // FastLED.addLeds<P9813, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
  // FastLED.addLeds<DOTSTAR, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
  
  Serial.print("Setup done");
}

void processByte(unsigned char currentByte) {
  #ifdef DEBUG_MODE
    Serial.print("GOT BYTE: "); Serial.print(currentByte,HEX);
  #endif
  if (currentByte==MAD_LED_PACKET_HEADER) {
    inputState=State_GotPacketHeader;
    #ifdef DEBUG_MODE
      Serial.print("GOT PH ");
    #endif
  } else
  if (inputState == State_WaitingNextPacket) {
    // Just ignore this byte, we're not processing a packet at the moment
    // Wait for next packet start (xFF)
  } else 
  if (inputState == State_GotPacketHeader) {
    if (currentByte==MAD_LED_DETECTION) {
      // Send back detection reply
      Serial.write(MAD_LED_DETECTION_REPLY);
      Serial.write(MAD_LED_PROTOCOL_VERSION);
      inputState=State_WaitingNextPacket;
    } else if (currentByte==MAD_LED_DATA) {
      inputState=State_WaitingLineNumber;
      #ifdef DEBUG_MODE
        Serial.print("GOT LD ");
      #endif
    } else {
      // Unknown packet start, reset
      inputState=State_WaitingNextPacket;
    }
  } else 
  if (inputState == State_WaitingLineNumber) {
    if (currentByte>0x7F) {
      // Error, reset
      inputState=State_WaitingNextPacket;
      #ifdef DEBUG_MODE
        Serial.print("ErrLineNum: "); Serial.print(currentByte);
      #endif
    } else {
      readingFrameOnLine=currentByte;
      inputState=State_WaitingChannelCountByte1;
      #ifdef DEBUG_MODE
        Serial.print("GOT LN ");
      #endif
    }
  } else
  if (inputState == State_WaitingChannelCountByte1) {
    if (currentByte>0x7F) {
      // Error, reset
      inputState=State_WaitingNextPacket;
      #ifdef DEBUG_MODE
        Serial.print("ErrChCNT1: "); Serial.print(currentByte);
      #endif
    } else {
      channelsLeftToRead=currentByte;
      inputState=State_WaitingChannelCountByte2;
      #ifdef DEBUG_MODE
        Serial.print("GOT CHC1 ");
      #endif
    }
  } else
  if (inputState == State_WaitingChannelCountByte2) {
    if (currentByte>0x7F) {
      // Error, reset
      inputState=State_WaitingNextPacket;
      #ifdef DEBUG_MODE
        Serial.print("ErrChCNT2: "); Serial.print(currentByte);
      #endif
    } else {
      channelsLeftToRead+=(int(currentByte)<<7);
      if (channelsLeftToRead==0) {
        // Error, reset
        inputState=State_WaitingNextPacket;
        #ifdef DEBUG_MODE
          Serial.print("ErrChCNT=0");
        #endif
      } else {
        frameWritePtr=dataFrame;
        inputState=State_ReadingDmxFrame;
        #ifdef DEBUG_MODE
          Serial.print("GOT CHC2 ");
        #endif
      }
    }
  } else 
  if (inputState==State_ReadingDmxFrame) {
    *frameWritePtr++ = currentByte;
    channelsLeftToRead--;
    if (channelsLeftToRead==0) {
      // Finished reading DMX Frame
      inputState=State_WaitingNextPacket;
      gotNewDataFrame=true;
      #ifdef DEBUG_MODE
        Serial.print("GOT DATA ");
      #endif
    }
  }
}

void loop() {
  // We read a maximum of 30000 bytes before we should call FastLED.show again
  // This is a good setting for the teensy, it depends on CPU speed, so it should be set lower on a slower CPU (ie arduino)
  // This limit (bytesRead<30000) is useless for protocols with a clock
  // But necessary when controlling more than 600 hundred RGB leds with WS2811 / WS2812
  int bytesRead=0;
  while (Serial.available() > 0 && bytesRead<30000) {
    processByte(Serial.read()); bytesRead++;
  }

  #ifdef JUST_TEST_LEDS
    static int value=0;
    value = (value + 1) % 254;
    for (int i=0; i<NUM_LEDS; i++) leds[i]=CRGB(value,value,value);
  #else
    if (gotNewDataFrame) {
      gotNewDataFrame=false;
      char* dataPtr=dataFrame;
      // Copy the data frame we received in the correct FastLED buffer
      for (int i=0; i<NUM_LEDS; i++) {leds[i]=CRGB(dataPtr[0],dataPtr[1],dataPtr[2]); dataPtr+=3;}
    }
  #endif
  
  FastLED.show();
}

No, it's not.

char dataFrame[4086];

will eat al available memory. It's not a Core i9 with 64GB memory ;)

septillion: No, it's not.

char dataFrame[4086];

will eat al twice the available memory.

:D

So is there anything that I can do? Other than getting the hardware required cause it is not available where I am located.

Yeah, get rid of the dataFrame ;) Don't know if it's possible (no idea what MadMapper is) but yeah.

The MadMapper SW looks to be aimed at controlling very large numbers of LEDs. At (about) 3 bytes/led NECESSARY storage, an Arduino Uno (with 2k total memory) is going to be pretty limited in the number of LEDs. The code talks about 600+ leds, and reading up to 30k at a time (at 921600bps, which an Uno can’t do, either.) I’d think that with a smaller number of LEDs, you could also reduce the size of dataFrame, but it would take some fiddling.

(The code is aimed at a Teensy3.1 or better. It might work on one of the other ARM arduinos (Due, Zero, MKRxxx, etc.))

If MadMapper needs to send you 4086 bytes there's nothing you can do except get a better Arduino/Teensy.

You could try reducing dataframe to say 1024 bytes and see if that still gets you enough information to be useful. I'm guessing that the message size depends on how much you have set up in MadMapper but I could be wrong.

Steve

Decreasing the data frame to 1024 worked. The Arduino takes up the code now but when I run it through Madmapper I have no control over LEDs. They just go crazy