Adafruit ssd1306 display clashes with TinyDMXSerial

n.b MegaAVR 4809 'Nano Every' NOT REGULAR NANO.

Hi,
Has anyone found this: I am running TinyDMXSerial on a large sketch with complete success, including with other interrupt sources from TCB0, TCB1, and 3x pin CHANGE interrupts. DMX reception appears to be completely reliable.

However, I had to entirely comment out my display AdaFruit SSD1306 function.
Just the line display.begin(SSD1306_SWITCHCAPVCC, 0x3c); on its own breaks DMX reception BUT IN A WEIRD WAY: After a hard reset I reliably receive one DMX packet. Subsequent passes do not refresh the dmx buffer.
TinyDMXSerial uses USART1 interrupts. Adafruit SSD1306 does not use any interrupts.
I have tried to find common problems such as naming duplicates to no avail.

Any ideas?

My code has all display functions commented out, and it works like that. If I only uncomment line 566 it will still run but only receive one packet of dmx immediatley after reset. Subsequent loops return the same dmx values frozen from the first packet, everything else works.

sorry for the long listing.

//MiniML version 1 board V1

const int version_number = 100; //Version 1.0.0

#include "TinyDMXSerial.h"

#include "Arduino.h"

#include "avr/interrupt.h"
#include "avr/io.h"


#include <Adafruit_SSD1306.h>
#include <splash.h>


#include <Adafruit_GFX.h>

#include <gfxfont.h>
#include <Wire.h>

#include <avr/pgmspace.h>
#include <EEPROM.h>
#include <avr/wdt.h> // required for watchdog


#define CPUclock 16000000
//BAUD = ((64 x CPUclk)/(S x fBAUD))  S=16 for normal asynch.  Atmega4809 datasheet page 288
#define Baud250k (64 * CPUclock)/(16 * 250000)
#define Baud57600 (64 * CPUclock)/(16 * 57600)
//

//setup I/O pin definitions

//#define DMX_DIR 2 //output, commented out becuase is used inside TinyDMXSerial
#define PAN_STEP 3 //output
#define PAN_DIR 4 //output
#define headerD5 5 //output
#define TILT_STEP 6 //output
#define TILT_DIR 7 //output
#define headerD8 8 //output
#define lampRelay 9 //output

#define buzzer 10 //output

#define ledGreen 11 //output
#define ledRed 12 //output
#define ledBlue 13 //output

//inputs

#define readSwitchA 14 
#define readSwitchB 15 
#define readSwitchC 16 
#define dipSwitchEnable 17

//SDA and SCL on pins 18&19

#define encoderEnable 20
#define uiButton 21

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 32  // OLED display height, in pixels

#define SCREEN_ADDRESS 0x3C  ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32

//ram variables
const byte lamp_legend_bitmap[] PROGMEM = 
{
  0b00000000,0b00000000,
  0b10001110,0b00100000,
  0b01010001,0b01000000,
  0b00010001,0b00000000,
  0b11010001,0b01100000,
  0b00001010,0b00000000,
  0b01001010,0b01000000,
  0b10000100,0b00100000,
  0b00000000,0b00000000
};

unsigned int eepromWriteCount = 0; //the 0 value is only used when the eeprom.get is bypassed for first initialisation

byte eepromFormat = 0; //0 indicates internal eeprom 256 bytes.

byte resetReason;
int CRC = 0;
bool debugStatus = 0;

volatile bool firstpass = true;

//User interface:
//
volatile bool buttonPlus = 1;   // variable to store the + button read value
volatile bool buttonMinus = 1;  // variable to store the - button read value
volatile bool buttonEnter = 1;  // variable to store the > button read value
//
volatile bool oldbuttonPlus = 1;   // variable to detect button change
volatile bool oldbuttonMinus = 1;  // variable to detect button change
volatile bool oldButtonEnter = 1;  // variable to detect button change

//
volatile byte rawEncoder = 0;
volatile byte previousEncoder = 0;
volatile byte encoder =0;
//int encodertable[16] = {0,1,-1,0,-1,0,0,1,1,0,0,-1,0,-1,1,0};  This is the fully decoded table
int encodertable[16] = {0,0,-1,0,0,0,0,0,1,0,0,0,0,0,0,0}; //this only decodes one + or one - per turn
//
int fieldCode = 0;  // menu position index, horizontal - when =0 the dial changes the screen, when nonzero the dial operates the value of the highlighted item
int screenLevel = 0; // The screen number
int functionCode = 0;  //functionCode is concatenation of encoder state and dial push button state
//the 3 resulting bits index the cases in the functionCode selector in the main loop.
//
int machineState = 0;
byte dipSwitchCode = 0;

//
bool boxcolor =0;
bool textcolor = 1;
bool forecolor = 1;
bool backcolor = 0;


volatile int pan = 0;
volatile int tilt = 0;
volatile int panTarget =0;
volatile int tiltTarget =0;
volatile byte oldSREG = 0;
volatile byte lampDimmer =0;

volatile unsigned long elapsedTime = millis();

volatile unsigned long QTime = 8000;

// to operate the buzzer
int buzzerNumber = 0;
int buzzerRate = 0;
int buzzerloop = 0;
int buzzerMode = 1;

volatile byte dmxBuffer[512];

TinyDMXSerial DMX(dmxBuffer,512);


// recorded values are read from EEPROM
// at start-up and revised values are stored to
// EEPROM in a controlled shutdown


//flags
//
int eepromWriteFlag = 0;  //if ==1 there is something to write to the EEPROM
int screenflipflag = 0; // to operate blinking features
byte demoSpeed = 0;
byte demoMode = 0;
//

volatile int screenSaverCount;
volatile int startChannel =1;

//
//interrupt routine variables
//

//
// for display routines:
int xpos;
int ypos;
int ssxpos =64; //for screenSaver
int ssypos =32; //
bool blink=false;
bool reverse = false;
bool blinkPolarity =0;
volatile int textcolour;
volatile int boxcolour;
volatile int forecolour;
volatile int backcolour;
int rad;
//
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire,0);


//****************************************************************************



//****************************************************************************
//*******************************************************************************************************
//INTERRUPTS   ******************************************************************************
//********************************************************************************************
//**********************************************************************************************
//*******************************************************************************************

//////////////////////////////////////////////////////////////////////////////////////////////////////////
// interrupt on either encoder channel or push button
void encoderUpdate()
{
  rawEncoder = digitalRead(readSwitchB)|(digitalRead(readSwitchC) << 1);
  if (rawEncoder != previousEncoder)
  {
    encoder = encoder << 2;
    encoder = encoder|rawEncoder;
    encoder = encoder & 0x0F;
  }
  previousEncoder = rawEncoder;

  if (encodertable[encoder] == 1)
  {
    buttonPlus = 0;
  }
  if (encodertable[encoder] == -1)
  {
    buttonMinus = 0;
  }

if (oldButtonEnter != digitalRead(readSwitchA))
  {
  buttonEnter = digitalRead(readSwitchA);
  oldButtonEnter = buttonEnter;
  }

  if (screenSaverCount == 0) //prevent encoder action when exiting from screensaver.
  {
    firstpass = true;
    buttonPlus = 1;
    buttonMinus = 1;
    buttonEnter = 1;
    oldButtonEnter = 1;
    previousEncoder = 0;
  }
  
//return from interrupt
}

//

// timer interrupts
//
ISR(TCB1_INT_vect)//Pan
{
  TCB1.INTFLAGS = 0b00000001; //clear int flag
  digitalWrite(PAN_STEP,LOW);
  digitalWrite(ledRed,LOW);
  digitalWrite(ledGreen,HIGH);
  if(pan < panTarget)
    {
      digitalWrite(PAN_DIR,LOW);
      digitalWrite(PAN_STEP,HIGH);
      pan ++;
    }
  if(pan > panTarget)
    {
      digitalWrite(PAN_DIR,HIGH);
      digitalWrite(PAN_STEP,HIGH);
      //digitalWrite(ledBlue,LOW);
      pan --;
    }
    //return from interrupt
    return;
} 

ISR(TCB0_INT_vect)//Tilt
{
  TCB0.INTFLAGS = 0b00000001; //clear int flag
  digitalWrite(TILT_STEP,LOW);
  digitalWrite(ledGreen,LOW);
  digitalWrite(ledRed,HIGH);
  if(tilt < tiltTarget)
  {
    digitalWrite(TILT_DIR,LOW);
    digitalWrite(TILT_STEP,HIGH);
    tilt ++;
  }
  if(tilt > tiltTarget)
  {
    digitalWrite(TILT_DIR,HIGH);
    digitalWrite(TILT_STEP,HIGH);
    tilt --;
  }
  return;
  //return from interrupt
} 

/*
********************************************************************************************************************
*********************************************************************************************************************
********************************************************************************************************************
*********************************************************************************************************************
********************************************************************************************************************
*********************************************************************************************************************
********************************************************************************************************************
*********************************************************************************************************************
*****  SUBROUTINES  ***********************************************************************************************
*********************************************************************************************************************
*/

//buzzer
int buzz(int buzzerNumber, int buzzerRate)
{
  if (buzzerMode == 1) 
  {
    for (buzzerloop = 0; buzzerloop < buzzerNumber; buzzerloop++) 
    {
      digitalWrite(buzzer, HIGH);
      delay(buzzerRate);
      digitalWrite(buzzer, LOW);
      delay(buzzerRate);
    }
  }
  return;
}

//
//*************************************************************************************************************
//read the buttons
int getButtons()
{
  if (oldButtonEnter != digitalRead(readSwitchA))
  {
    delay(10);
    buttonEnter = digitalRead(readSwitchA);
    oldButtonEnter = buttonEnter;

    if (screenSaverCount == 0)
    {
      firstpass = true;
    }

  }

}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

int digitDisp (int xpos, int ypos, bool blink, bool reverse, int numdigits, int digitsize, int dispvalue)
{
  display.setTextSize(digitsize);
  blinkSetColor(blink,reverse);
  display.fillRect(xpos,ypos,digitsize+(numdigits * 6 * digitsize),9 * digitsize,boxcolour);
  display.setTextColor(textcolour);
  display.setCursor(xpos+digitsize,ypos+digitsize);
  if (dispvalue < 0)
  {
    display.print(dispvalue);
  }
  else
  {
    switch(numdigits)
    {
      case 1:
      display.print(dispvalue);
      break;
              
      case 2:
      if(dispvalue == 0)
      {
        display.print(F("00"));
      }
      else if (dispvalue <=9)
      {
        display.print(F(" "));
        display.print(dispvalue);
      }
      else if (dispvalue >99)
      {
        display.print(F("FF"));
      }
      else
      {
        display.print(dispvalue);
      }
      break;
        
      case 3:
      if (dispvalue <=99)
      {
        display.print(F(" "));
        display.print(dispvalue);
      }
      else if (dispvalue >999)
      {
        display.print(dispvalue/1000);
        display.print(F("k"));
        display.print((dispvalue % 1000)/100);
      }
      else
      {
        display.print(dispvalue);
      }
      break;
      
      case 4:
      if (dispvalue <=999) 
      {
        display.print(F(" "));
      }
      if (dispvalue <=99) 
      {
        display.print(F(" "));
      }
      if (dispvalue <=9) 
      {
      display.print(F(" "));
      }
      
      display.print(dispvalue);

    break;
    }
  }  
}

/////////////////////////////////////////////////////////////////////////////////////////////////

int blobDisp (int xpos, int ypos, bool blink, bool reverse, bool pwrrly)
{
  blinkSetColor(blink,reverse);
  display.fillRect(xpos,ypos,7,9,boxcolour);
  display.setTextColor(textcolour);
  display.setCursor(xpos+1,ypos+1);
  if (pwrrly == true)
  {
    display.write(0x04);
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////////
int textDisp (int xpos, int ypos, bool blink, bool reverse, int stringindex)
{
  blinkSetColor(blink,reverse);
 //
  //display.fillRect(xpos,ypos,2+(6 * strlen(inputNames[stringindex])),9,boxcolour);
  display.setCursor(xpos+1,ypos+1);
  display.setTextColor(textcolour);
  display.setTextSize(1);
  //display.print(inputNames[stringindex]);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
int testDisp (int xpos, int ypos, bool blink, bool reverse, int stringindex)
{
  blinkSetColor(blink,reverse);
 //
  //display.fillRect(xpos,ypos,2+(6 * strlen(testFuncNames[stringindex])),9,boxcolour);
  display.setCursor(xpos+1,ypos+1);
  display.setTextColor(textcolour);
  display.setTextSize(1);
  //display.print(testFuncNames[stringindex]);
}

/////////////////////////////////////////////////////////////////////////////////////
int blinkSetColor(bool blink,bool reverse)
{
  if (blink == 1)
  {
    boxcolour = forecolour;
    textcolour = backcolour;
  }
  else
  {
    boxcolour = reverse; //BLACK
    textcolour = ! reverse; // WHITE
  }
}



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int activityBlink()
{
  if (fieldCode == 0)
  {
    //display.fillRect(121,54,8,8,blinkPolarity);
    display.setTextColor(WHITE);
    display.setTextSize(1);

    if (blinkPolarity == 0)
    {
      display.setCursor(122, 55);
      display.write(0x1A);
    }
    else
    {
      display.setCursor(118, 55);
      display.write(0x1B);    
    }
    
  }
  return;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
  resetReason = RSTCTRL.RSTFR; //capture reset reason
  RSTCTRL.RSTFR = 0b00111111; // reset the reset reason flags
  wdt_reset(); // call this at the beginning of setup()
  wdt_disable(); // call this at the beginning of setup()
  delay(1000);
  wdt_reset();


  
  Serial.begin(115200);


  DMX.begin(DMXMode::Receiver);

//setup pins
  //pinMode(DMX_DIR,OUTPUT);      // controlled inside TinyDMXSerial
  //digitalWrite(DMX_DIR, LOW);  // 
  pinMode(PAN_DIR, OUTPUT);
  digitalWrite(PAN_DIR, LOW);  //
  pinMode(PAN_STEP, OUTPUT);
  digitalWrite(PAN_STEP, LOW);  //
  pinMode(headerD5, INPUT);
  digitalWrite(headerD5, HIGH);  //
  pinMode(TILT_DIR, OUTPUT);     // 
  digitalWrite(TILT_DIR, LOW);  //
  pinMode(TILT_STEP, OUTPUT);
  digitalWrite(TILT_STEP,LOW);
  pinMode(headerD8, INPUT);
  digitalWrite(headerD8,HIGH);
  pinMode(lampRelay, OUTPUT);
  digitalWrite(lampRelay,LOW);
  pinMode(buzzer, OUTPUT);
  digitalWrite(buzzer,LOW);
  pinMode(ledBlue, OUTPUT);
  digitalWrite(ledBlue,LOW);
  pinMode(ledGreen, OUTPUT);
  digitalWrite(ledGreen,LOW);
  pinMode(ledRed, OUTPUT);
  digitalWrite(ledRed,LOW); 

  pinMode(readSwitchA,INPUT);
  digitalWrite(readSwitchA,HIGH);
  pinMode(readSwitchB,INPUT);
  digitalWrite(readSwitchB,HIGH);
  pinMode(readSwitchC,INPUT);
  digitalWrite(readSwitchC,HIGH);

  pinMode(dipSwitchEnable, OUTPUT);
  digitalWrite(dipSwitchEnable,LOW);
  pinMode(encoderEnable, OUTPUT);
  digitalWrite(encoderEnable, LOW); 
  
  pinMode(uiButton,INPUT);
  digitalWrite(uiButton,HIGH); //

// This line will suppress DMX reception after first pass of loop()
  //display.begin(SSD1306_SWITCHCAPVCC, 0x3c);  //Initialize with the I2C addr 0x3C for the large 128x64 display.
 

//display.clearDisplay();
//display.setTextColor(WHITE);
//display.setCursor(2,2);
//display.setTextSize(2);
//display.print(" A B MICRO");
//display.setCursor(2,24);
//display.setTextSize (1);
//display.print("    Copyright 2024");
//display.display();
//
  //EEPROM Structure
  //
  //00-07  0-7     = debug:       8x byte: int eepromwritecount, 5xbyte savedTime[], byte eepromFormat
  //08-92  8-147   = 20 x cues:   pan(int), tilt(int), lamp(b),time(int) = 20 x 7 bytes
  //93-DB  148-227 = 20 x seqs:   Q(b), lamp(b) = 20 x 2 bytes
  //DC-FF  228-255 = config :     screensaver(b),maxspeed(b),dmxaddr(int),IPaddr(bx4)

  //dont comment out this line:
  //EEPROM.get(0,eepromWriteCount);




//setup timers for pan/tilt
//TCB1 is pan, TCB0 is tilt
TCB1.CCMP = 300;
TCB1.CTRLB = 0b00000000;
TCB1.INTCTRL = 0b00000001;//enable interrupts
TCB1.CTRLA = 0b00000101; //enable with CLK_TCA (4µs)

TCB0.CCMP = 301;
TCB0.CTRLB = 0b00000000;
TCB0.INTCTRL = 0b00000001;//enable interrupts
TCB0.CTRLA = 0b00000101; //enable with CLK_TCA (4µs)


digitalWrite(ledBlue,HIGH);

 


  //display.clearDisplay();
  //display.invertDisplay(false);

  buzz(2, 100);

  screenLevel = 0;
  fieldCode = 1;

panTarget = 892;
tiltTarget = 892;
delay(3000);
panTarget = 0;
tiltTarget = 0;
delay(3000);

//go to neutral down position
panTarget = 440;
tiltTarget = 440;

  wdt_enable(WDT_PERIOD_8KCLK_gc);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() 
{

oldSREG = SREG;
cli();

detachInterrupt(digitalPinToInterrupt(readSwitchC));
detachInterrupt(digitalPinToInterrupt(readSwitchB));
detachInterrupt(digitalPinToInterrupt(readSwitchA));

digitalWrite(encoderEnable,HIGH);

digitalWrite(dipSwitchEnable,LOW);
dipSwitchCode = 7 - (digitalRead(readSwitchA) | (digitalRead(readSwitchB) << 1) | (digitalRead(readSwitchC) <<2));
digitalWrite(dipSwitchEnable,HIGH);

digitalWrite(encoderEnable,LOW);
//delay(10);
attachInterrupt(digitalPinToInterrupt(readSwitchC),encoderUpdate,CHANGE);
attachInterrupt(digitalPinToInterrupt(readSwitchB),encoderUpdate,CHANGE);
attachInterrupt(digitalPinToInterrupt(readSwitchA),encoderUpdate,CHANGE);

  functionCode = (buttonEnter | buttonMinus << 1 | buttonPlus << 2 );
  //clear button codes:
  buttonPlus = 1;
  buttonMinus = 1;
  buttonEnter = 1;
 
 SREG = oldSREG; // restore previous interrupt level
 

 unsigned long lastPacket = millis() - DMX.lastReceivedTime();

  debugStatus = 0;
  demoSpeed = 0;
  demoMode = 0;


  debugStatus = bitRead(dipSwitchCode,2);
  demoSpeed = bitRead(dipSwitchCode,1);
  demoMode = bitRead(dipSwitchCode,0);
  if(demoSpeed == 0)
  {
    TCB1.CCMP = 300;
    TCB0.CCMP = 301;
   }
  else
  {
    TCB1.CCMP = 1000;
    TCB0.CCMP = 1001;
  }
    // truth table function coding:
    //



  switch(functionCode)
  {
    //
    //switches are negative logic, so functionCode of 7 = no action
    //0 = all active (impossible with encoder)
    //1 = simultaneous + and - (impossible with encoder)
    //2 = push and +
    //3 = push
    //4 = push and -
    //5 = -
    //6 = +
    //7 = all off

    case 2:
    fieldCode++;
    break;

    case 3:
    if (fieldCode == 0)
    {
      screenLevel++;
      //display.clearDisplay();
      firstpass = true;
    }
    else //fieldCode is not zero, so operate a parameter value instead.
    {
      eepromWriteFlag = true; //mark data as dirty

      switch(screenLevel) // process the dial to operate a parameter
      {
        case 0: 
        break;

        case 1: 
        break;

        case 2: 
        break;

        case 3: 
        break;
        
        case 4: 
        break;

        case 5: 
        break;

        case 6: 
        break;
    
        case 7: 
        break;
  
        case 8: //save

        break;

        case 9: //help

        break;
          
      //end switch:
      }
    }

    break;

    case 4:
   
    break;

    case 5:
    if (fieldCode == 0)
    {
      screenLevel--;
      //display.clearDisplay();
      firstpass = true;
    }
    else
    {
      eepromWriteFlag = true;
      switch(screenLevel)
      {
        case 0:
        break;

        case 1: 
        break;

        case 2: 
        break;

        case 3: 
        break;

        case 4: 
        break;

        case 5: 
        break;

        case 6: 
        break;
 
        case 7: 
        break;
    
        case 8: 
        break;

        case 9: 
        break;
        
      //end switch:
      }
    }
 
    break;

    case 6:
    fieldCode++;
    break;

    //end switch
  }





////////////////
// temporary, to advance screenlevel with no encoder
////////////////
if (digitalRead(uiButton) == 0)
{
  screenLevel ++;
}
///////////////




  if (screenLevel <0)
  {
    screenLevel = 4;
  }
  if (screenLevel >4)
  {
    screenLevel = 0;
  }
//display.clearDisplay();
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  //    DISPLAYS   //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  //Addresses:  IP addr, DMX addr, Group memberships
  //Speed: pan max, tilt max
  //Manual: Pan, Tilt
  //Cues: Lamp, Pan, Tilt, Time
  //Lamp: On, Off
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

  switch(screenLevel)
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // LIVE VIEW  /////////////////////////////////////////////////////////////////////////////////////////////////////// 
  {
    case 0:
    if (fieldCode >1)
    {
      fieldCode = 0;
    }  
/*
  display.setTextColor(WHITE);
  display.setTextSize(1);

 
    display.fillRect(0,0,127,10,BLACK);
    display.setCursor(2,2);
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.print(F("    PAN       TILT"));
    //                              
    //display.drawLine(0,11,127,11,1);

    digitDisp(2,14,0,0,4,2,pan);
    digitDisp(66,14,0,0,4,2,tilt);
    display.setTextSize(1);    
    blobDisp(61,2,0,0,lampDimmer);
  */  
    break;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //  END LIVE VIEW  /////////////////////////////////////////////////////////////////////////////////////////////////

 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // MANUAL VIEW  /////////////////////////////////////////////////////////////////////////////////////////////////////// 
    case 1:

    /*
  display.setTextColor(WHITE);
  display.setTextSize(1);

 
    display.fillRect(0,0,127,10,BLACK);
    display.setCursor(2,2);
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.print(F("MANUAL"));
    //                              
    display.drawLine(0,11,127,11,1);

display.fillRect(0,0,127,10,BLACK);
    display.setCursor(2,14);
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.print(F("    PAN       TILT"));
    //                              
    //display.drawLine(0,11,127,11,1);

    digitDisp(2,24,0,0,4,1,panTarget);
    digitDisp(66,24,0,0,4,1,tiltTarget);
    display.setTextSize(1);    
    blobDisp(61,14,0,0,lampDimmer);
*/
    break;
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //  END MANUAL VIEW  /////////////////////////////////////////////////////////////////////////////////////////////////


    case 2:

    /*
  display.setTextColor(WHITE);
  display.setTextSize(1);

 
    display.fillRect(0,0,127,10,BLACK);
    display.setCursor(0,0);
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.print(F("CUE PAN TILT     TIME"));
    //                              
    display.drawBitmap(79,0,lamp_legend_bitmap,16,9,1);
/*
   digitDisp(4,8,0,1,2,1,1);
   digitDisp(17,8,0,0,4,1,cuePan[0]);
   digitDisp(47,8,1,0,4,1,cueTilt[0]);
   blobDisp(81,8,0,0,1);
   digitDisp(96,8,0,0,2,1,cueTime[0]/60);
   display.setCursor(109,8);
   display.print(":");
  digitDisp(114,8,0,0,2,1,cueTime[0]%60);

   digitDisp(4,16,0,1,2,1,2);
   digitDisp(17,16,0,0,4,1,cuePan[1]);
   digitDisp(47,16,1,0,4,1,cueTilt[1]);
   blobDisp(81,16,0,0,1);
   digitDisp(96,16,0,0,2,1,cueTime[1]/60);
   display.setCursor(109,16);
   display.print(":");
  digitDisp(114,16,0,0,2,1,cueTime[1]%60);

     digitDisp(4,24,0,1,2,1,3);
   digitDisp(17,24,0,0,4,1,cuePan[2]);
   digitDisp(47,24,1,0,4,1,cueTilt[2]);
   blobDisp(81,24,0,0,1);
   digitDisp(96,24,0,0,2,1,cueTime[2]/60);
   display.setCursor(109,24);
   display.print(":");
  digitDisp(114,24,0,0,2,1,cueTime[2]%60);
*/
    break;


   case 3:

   /*
  display.setTextColor(WHITE);
  display.setTextSize(1);

 
    display.fillRect(0,0,127,10,BLACK);
    display.setCursor(2,2);
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.print(F("CALIBRATE"));
    //                              
    display.drawLine(0,11,127,11,1);
   
*/
    break;

    case 4:

    /*
     display.setTextColor(WHITE);
  display.setTextSize(1);

 
    display.fillRect(0,0,127,10,BLACK);
    display.setCursor(2,2);
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.print(F("DEMO"));
    //                              
    display.drawLine(0,11,127,11,1);

    */
    break;

 

  }  // end switch statement for screens


  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  //
  //Other mainloop activities

  blinkPolarity =! blinkPolarity;
  forecolour = !blinkPolarity;
  backcolour = blinkPolarity;
if(demoMode == 1) // if not = 1 then DMX mode places values in panTarget and tiltTarget
{
  if((millis() - elapsedTime) > QTime)
  {
  panTarget = random(0,892);
  tiltTarget = random(0,892);

  digitalWrite(lampRelay,HIGH);
  elapsedTime = millis();
  }
}
else
{
  panTarget = (dmxBuffer[0] * 28) >>3 ; //0-892 steps
  tiltTarget = (dmxBuffer[1] * 28) >>3; //0-892 steps
  digitalWrite(lampRelay,dmxBuffer[2]);
}

  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  //debug display

  
  if (debugStatus == 1)
  {
    /*
    display.fillRect(0,0,127,9,1);
    display.setCursor(1,1);
    display.setTextColor(0);
    display.setTextSize(1);
    display.print(F("S"));
    display.print(screenLevel);
    display.print(F(".F"));
    display.print(fieldCode);
    display.print(F(".C"));

    display.print(dipSwitchCode);
    display.print(functionCode);

    display.print(F(".R"));
    if (bitRead(resetReason,5)==1)
    {
      display.print(F("u"));
    }
    if (bitRead(resetReason,4)==1)
    {
      display.print(F("s"));
    }
    if (bitRead(resetReason,3)==1)
    {
      display.print(F("w"));
    }
    if (bitRead(resetReason,2)==1)
    {
      display.print(F("e"));
    }
    


    if (bitRead(resetReason,0)==1)
    {
      display.print(F("p"));
    }
    //display.print(F(".E"));
    //display.print(eepromWriteFlag);
display.print(screenSaverCount);

    display.print(F(".m"));
    display.print(machineState);
*/
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // SERIAL DUMP ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Serial.print(" PAN ");
  Serial.print(pan);
  Serial.print("   TARGET ");
  Serial.print(panTarget);

  Serial.print("     TILT ");
  Serial.print(tilt);
  Serial.print("   TARGET ");
  Serial.print(tiltTarget);

    
    Serial.print("   Debug: ");
    Serial.print("  screenLevel ");
    Serial.print(screenLevel);
    Serial.print("  fieldCode ");
    Serial.print(fieldCode);
    Serial.print("  functionCode ");
    Serial.print(functionCode);
    //Serial.print("  firstpass ");
    //Serial.print(firstpass);
    //Serial.print("  screenSaver ");
    //Serial.print(screenSaverCount);
    Serial.print("    DMX1:");
    Serial.print(dmxBuffer[0]);
    Serial.print("    DMX2:");
    Serial.print(dmxBuffer[1]);
    Serial.print("    DMX3:");
    Serial.print(dmxBuffer[2]);   

    Serial.print("    ui:");
    Serial.print(digitalRead(uiButton));    

    Serial.print("  resetReason: ");
    Serial.println(resetReason);
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // END SERIAL DUMP  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
  }
//display.display();
/*
if (screenSaverCount > 0)
  {
    screenSaverCount--;
    display.display();
  }
  else
  {
    //fieldCode = 0;
    display.clearDisplay();
    xpos = ssxpos;
    ssxpos = ssxpos + random(0,25)-12;
    ypos = ssypos;
    ssypos = ssypos + random(0,13)-6;
    ssxpos = constrain(ssxpos,0,127);
    ssypos = constrain(ssypos,0,63);
    display.drawLine(xpos,ypos,ssxpos,ssypos,1);
    display.display();
  }
  */
 
delay(100);
  wdt_reset();
  // END  END

1. List item

END  END  END  END  END
}

I solved it, although I don't understand why: If I place Adafruit ssd1306 before TinyDMXSerial in setup(); it all works correctly.

1 Like

I had a similar problem using those two libraries and the same code at first. For me it was a RAM issue, as I found later, which is common with using the adafruit SSD1306 library. And this caused all kind of strange behaviours, e.g. a setup() reset loop (caused by an uncaught (yes that was bad coding) display.begin() call and subsequent use of the display), which I figured only in more detail after attaching multiple LEDs for debugging purposes.
I'm using an UNO, so it has 2048 bytes of RAM, the SSD1306 uses (from Adafruit_SSD1306.cpp: (uint8_t *)malloc(WIDTH * ((HEIGHT + 7) / 8))))) 1136 bytes already.
Then I made the same, I would now say mistake, to define an array for TinyDMXSerial of size 512 bytes, which resulted - with some other code - in 800+ bytes being used right from the start. But this is actually not needed (most likely) the TinyDMXSerial has an parameter 'startAddress' in the begin() method and an setStartAddress() method, so I needed only 1 or 2 bytes from DMX, so my DMX data array could be way smaller and with that change the program runs again.

Also there are multiple articles out there about optimizing RAM usage, one thing that saved some bytes is the use F("...") for strings (and PROGMEM for pictures (const unsigned char[]) as generated by https://javl.github.io/image2cpp/) to move them into flash (which was new to me, being a programmer but just starting out on arduino).
Also this code floats around the internet to see how much free memory there is:

// free RAM check for debugging. SRAM for ATmega328p = 2048Kb.
int availableMemory() {
    // Use 1024 with ATmega168
    int size = 2048;
    byte *buf;
    while ((buf = (byte *) malloc(--size)) == NULL);
        free(buf);
    return size;
}

So after these changes (not only did the program run) but I have 529 bytes available, which should be plenty for some variables for additional functionality.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.