Problem with DmxSimple.h

Hello everyone,

I confess I am an Arduino noob but I do catch on fast :slight_smile:

I have a program that reads and parses line by line a CSV file on a SD Card. It includes String.h and SD.h. and appears to work properly. I want to use the values on a line to determine a delay and the values of the intensity of fixtures on a DMX system. Sounds easy enough, right? Well as soon as I try to include DmxSimple.h, #include <DmxSimple.h>, well the previously working programs starts to behave very strangely, erratically and sometimes appears to freeze up. Remember, I have not included any DMX functions, just included the header in my program. I am at wits end. I have no new hypothesis to try and solve this. So if anyone here has an idea, all reasonable suggestions will be accepted and welcome.

Regards

Simon

//Program by Pascal-Simon Houle

//SD CSV File Read

#include <SD.h>
#include <String.h>
//#include <DmxSimple.h>

//Set by default for the SD Card Library
//MOSI = Pin 11
//MISO = Pin 12
//SCLK = PIN 13
//We always need to set the CS Pin
int CS_Pin = 10;
//int PowerPin = 8;

// Declare DMXValues Array and DMXValueIndex Counter. Keep Unsigned Integers below 65535
unsigned int DMXValues[15] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int DMXValueIndex = 0;
int IterationCounter = 0;
int AvailableCounter = 0;

// Declare CSVStringBuffer Input Character Buffer, SimpleToken "container" and IntermediateBuffer Temporary Location for Read char from File
char CSVStringBuffer[80];
char *SimpleToken = NULL;
char IntermediateBuffer = NULL;

void setup()
{
  Serial.begin(9600);
  Serial.println("Initializing Card");
  //CS Pin is an output
  pinMode(CS_Pin, OUTPUT);
  
  //Card will Draw Power from Pin 8, so set it high
  //Strange Arduino Idea... Arrrrggghhh them Software Designer they're so naughty!
  //This May not survive in Final Design
  //pinMode(PowerPin, OUTPUT);  
  //digitalWrite(PowerPin, HIGH);
  
  if (!SD.begin(CS_Pin))
  {
      Serial.println("Card Failure");
      return;
  }
  Serial.println("Card Ready");
  
  // Read DMX Sequence information (CSVTest1.csv)
  File CSVCommandFile = SD.open("CSVTest1.csv");
  if (CSVCommandFile)
  {
    Serial.println("Reading DMXSequence File");
    
    AvailableCounter = CSVCommandFile.available();
    Serial.print("Available Character(s): ");
    Serial.println(AvailableCounter);
   
   // As long as there are characters and that the Index is less than 80 characters read the file 
   while(CSVCommandFile.available() && (IterationCounter <= 79))
   {
     IntermediateBuffer = CSVCommandFile.read();
      // Look for the first exception, 0x0D or carriage return. May be absent in a Mac generated CSV file
     if (IntermediateBuffer == 0x0D)
     {
       continue; // If found, re-iterate the while loop
     }
     // Look for the second exception, 0x0A or line feed 
     else if (IntermediateBuffer == 0x0A)
     {
       CSVStringBuffer[IterationCounter] = NULL;
       
       // Put strtok and atoi processing here
       
       // Actual Parsing of CSVStringBuffer to find Tokens
       // This is where the magic happens :-)
       SimpleToken = strtok(CSVStringBuffer, ",");
       while(SimpleToken)
       {
         // Do something with this token
         DMXValues[DMXValueIndex] = atoi(SimpleToken);
         
         Serial.print(DMXValues[DMXValueIndex]);
         Serial.print(" was read into Integer Array at position ");
         Serial.println(DMXValueIndex);
         
         DMXValueIndex++;
         
         // Get the next token...
         SimpleToken = strtok(NULL, ",");
       }
       
       // Various progress messages 
       Serial.println("Done Acquiring Character from 1 Line in CSVTest1.csv");
       
       Serial.print("Integer Array is: ");
       for(int j = 0; j <= (DMXValueIndex - 1); j++)
       {
         Serial.print(DMXValues[j]);
         Serial.print(" ");
       }
       Serial.println(" ");
       
       // Reset Index for Values Array before exiting and re-looping for the next line in CSVCommandFile
       DMXValueIndex = 0;

       // Reset Index for CharBuffer before exiting and re-looping for the next line in CSVCommandFile
       IterationCounter = 0;
     }
     
     // This section is where the CSVStringBuffer is filled with the characters from the file
     else
     {
       CSVStringBuffer[IterationCounter] = IntermediateBuffer;
       Serial.println(CSVStringBuffer[IterationCounter]);
       //Serial.print("Iteration Counter = ");
       //Serial.println(IterationCounter);
       IterationCounter++;
     }
   }
  }
  
  // If upon exit of while loop i hasn't been reset there was a problem. Should test to determine the problem and print to log file
  if (IterationCounter != 0)
  {
    Serial.println("Aborted Character Acquisition");
    Serial.print("IterationCounter= ");
    Serial.println(IterationCounter);
    Serial.print("Available Character(s): ");
    Serial.println(AvailableCounter);
  }
  // Succes message
  else
  {
    Serial.print("Read total of ");
    Serial.print(AvailableCounter);
    Serial.println(" characters");
    Serial.print("DMXValueIndex= ");
    Serial.println(DMXValueIndex);
    Serial.println("Operation Succesful");
  }
}

void loop()
{
}

The inclusion of the library (which is what you do with #include <DmxSimple.h>) creates an object which then could be used as well as some global variables. I guess this uses just a small bit too much memory because the rest of your code uses also plenty of RAM (for Serial.print()s for example). Try to wrap your constant strings with the F() macro to save some RAM.

Thank you pylon, I'll give this a try right away and report on the result. However I did include other libraries and did not have the problem I am observing with DmxSimple. In the final code all those Serial.print's won.'t be there as these are just for debug.

Thanks

Simon

DmxSimple allocates a buffer of 512 bytes (on a UNO at least) which is a quarter of the whole space available on that board. The library looks not very elaborated a quick overlook showed several mistakes although it might work anyway. Just a strange quality.

pylon you're a genius. Thanks. I am unfamiliar with your F() so I simply commented most of the Serial.print's and it is now operational.

Can you tell me where to go to learn about F()?

Thanks again

Simon

Try this description:

It gives you a short introduction in that area.

Hi pylon. Are you getting reasonable speed with this setup?

I was hoping to be able to address all 512 channels at a decent fps, and while I can read from the sd fast enough for this, I can barely achieve 2 fps with dmx simple, even with all the sd stuff taken out!

I don't use DMX myself, but keep in mind DMX communicates with 250kBaud, giving 25000 bytes to be sent every second by the standard. Not knowing the details of your setup, 512 channels seems quite a lot (I think it's the maximum allowed but not sure about that), there is a maximum of 45 bytes per channel per second (if there's no pause).

The way DMXSimple is communicating it uses up to 25% of the available CPU to handle the protocol plus you loose another 25% (of the 25%) for the start pulse, giving about 20% of the maximum for you best case. So best case you get 9 bytes per second (or 9fps) if you do the rest of the programming very clever (25% of the processor's time is used in a ISR in the library, a value that should never be used for interrupt service routines).

If you wanna get more, go for a faster processor (the Arduino Due would be a candidate as soon as it's available, I'd go for a IteadMaple in the meantime) and for a better library that does the protocol with more hardware acceleration (given the hardware has the potential).