Recieving DMX on an Arduino MEGA

Hi everyone,

This is my first post on this forum, I REALLY hope someone can help me.
I’m porting the DMX project from

to the Arduino MEGA (ATMEGA1280, lots of outputs), but so far without success .
Can someone take a look at this code?
So far the ISR(TIMER2_COMPA_vect) seems to trigger, ISR(USART3_RX_vect) doesn’t
( I put a serial.writeln in ISR(USART3_RX_vect), I get no response)

I want to know If I’ve done something wrong in hardwareserial.cpp; adapted code included below (line 65 to 110);
or if it’s in another part of my code
I’m using TX3, RX3, pen2 & 10, and have blanked out the define at line 85 in hardwareserial.cpp.

Alvast bedankt,
Tim.

/***********************************************************
* DMX-512 Reception For Arduino MEGA                       *
* Based on:                                                *
* DMX-512 Reception                                        *
* Developed by Max Pierson                                 *
* Version Rev15 9 Oct 2010                                 *
* Released under the WTFPL license, although I would       *
* appreciate Attribution and Share-Alike                   *
* See blog.wingedvictorydesign.com for the latest version. *
************************************************************/



/******************************* Addressing variable declarations *****************************/

// #include <EEPROM.h>
#define NUMBER_OF_CHANNELS 16
//the number of channels we want to receive (16 by default).

// #define SWITCH_PIN_0 11 //the pin number of our "0" switch
// #define SWITCH_PIN_1 12 //the pin number of our "1" switch
unsigned int dmxaddress = 3;
/* The dmx address we will be listening to.  The value of this will be set in the Addressing()
*  function and read from EEPROM addresses 510 and 511.

/******************************* MAX485 variable declarations *****************************/

#define RECEIVER_OUTPUT_ENABLE 2
/* receiver output enable (pin2) on the max485.  
*  will be left low to set the max485 to receive data. */

#define DRIVER_OUTPUT_ENABLE 10  // this is OC2A, On PEN 10 of the MEGA
/* driver output enable (pin3) on the max485.  
*  will left low to disable driver output. */

#define RX3_PIN 15   // serial receive pin, which takes the incoming data from the MAX485.
#define TX3_PIN 14   // serial transmission pin

/******************************* DMX variable declarations ********************************/

volatile byte intTimerCheck = 0;  //variable for making sure timer2 int is only announced once
volatile byte intISRCheck = 0;    //variable for making sure usart int is only announced once
volatile byte i = 0;              //dummy variable for dmxvalue[]
volatile byte dmxreceived = 0;    //the latest received value
volatile unsigned int dmxcurrent = 0;     //counter variable that is incremented every time we receive a value.
volatile byte dmxvalue[NUMBER_OF_CHANNELS];     
/*  stores the DMX values we're interested in using-- 
 *  keep in mind that this is 0-indexed. */
volatile boolean dmxnewvalue = false; 
/*  set to 1 when updated dmx values are received 
 *  (even if they are the same values as the last time). */

/******************************* Timer2 variable declarations *****************************/

volatile byte zerocounter = 0;          
/* a counter to hold the number of zeros received in sequence on the serial receive pin.  
*  When we've received a minimum of 11 zeros in a row, we must be in a break.  */




void setup() {
  
  /******************************* Max485 configuration ***********************************/
  
  pinMode(RECEIVER_OUTPUT_ENABLE, OUTPUT);
  pinMode(DRIVER_OUTPUT_ENABLE, OUTPUT);
  digitalWrite(RECEIVER_OUTPUT_ENABLE, LOW);
  digitalWrite(DRIVER_OUTPUT_ENABLE, LOW);    //sets pins 3 and 4 to low to enable reciever mode on the MAX485.

  pinMode(RX3_PIN, INPUT);  //sets serial pin to receive data

  /******************************* Addressing subroutine *********************************/

  //pinMode(SWITCH_PIN_0, INPUT);           //sets pin for '0' switch to input
  //digitalWrite(SWITCH_PIN_0, HIGH);       //turns on the internal pull-up resistor for '0' switch pin
  //pinMode(SWITCH_PIN_1, INPUT);           //sets pin for '1' switch to input  
  //digitalWrite(SWITCH_PIN_1, HIGH);       //turns on the internal pull-up resistor for '1' switch pin
  
  /* Call the addressing subroutine.  Three behaviors are possible:
  *  1. Neither switch is pressed, in which case the value previously stored in EEPROM
  *  510 and 511 is recalled,
  *  2. Both switches are pressed, in which case the address is reset to 1.
  *  3. Either switch is pressed (but not both), in which case the new address may 
  *  be entered by the user.
  */
  //set this equal to a constant value if you just want to hardcode the address.
  //dmxaddress = Addressing();
  
  /******************************* USART configuration ************************************/
  Serial.begin(9600); // just used for errorchecking etc.
  Serial3.begin(250000);
  /* Each bit is 4uS long, hence 250Kbps baud rate */
  
  cli(); //disable interrupts while we're setting bits in registers
  
  bitClear(UCSR3B, RXCIE3);  //disable USART reception interrupt
  
  /******************************* Timer2 configuration ***********************************/
  
  //NOTE:  this will disable PWM on pins 3 and 11.
  bitClear(TCCR2A, COM2A1);
  bitClear(TCCR2A, COM2A0); //disable compare match output A mode
  bitClear(TCCR2A, COM2B1);
  bitClear(TCCR2A, COM2B0); //disable compare match output B mode
  bitSet(TCCR2A, WGM21);
  bitClear(TCCR2A, WGM20);  //set mode 2, CTC.  TOP will be set by OCRA.
  
  bitClear(TCCR2B, FOC2A);
  bitClear(TCCR2B, FOC2B);  //disable Force Output Compare A and B.
  bitClear(TCCR2B, WGM22);  //set mode 2, CTC.  TOP will be set by OCRA.
  bitClear(TCCR2B, CS22);
  bitClear(TCCR2B, CS21);
  bitSet(TCCR2B, CS20);   // no prescaler means the clock will increment every 62.5ns (assuming 16Mhz clock speed).
  
  OCR2A = 64;                
  /* Set output compare register to 64, so that the Output Compare Interrupt will fire
  *  every 4uS.  */
  
  bitClear(TIMSK2, OCIE2B);  //Disable Timer/Counter2 Output Compare Match B Interrupt
  bitSet(TIMSK2, OCIE2A);    //Enable Timer/Counter2 Output Compare Match A Interrupt
  bitClear(TIMSK2, TOIE2);   //Disable Timer/Counter2 Overflow Interrupt Enable          
  
  sei();                     //reenable interrupts now that timer2 has been configured. 
  Serial.println("End of Setup");
}  //end setup()


void loop()  {
  // the processor gets parked here while the ISRs are doing their thing. 
  if (dmxnewvalue == 1) {    //when a new set of values are received, jump to action loop...
    Serial.println("Value received");
    action();
    dmxnewvalue = 0;
    dmxcurrent = 0;
    zerocounter = 0;      //and then when finished reset variables and enable timer2 interrupt
    i = 0;
    bitSet(TIMSK2, OCIE2A);    //Enable Timer/Counter2 Output Compare Match A Interrupt
  }
} //end loop()


//Timer2 compare match interrupt vector handler
ISR(TIMER2_COMPA_vect) {
  if (intTimerCheck = 0) {
    Serial.println("Timer2 interrupt");
    intTimerCheck = 1;
  }
  if (bitRead(PIND, PIND0)) {  // if a one is detected, we're not in a break, reset zerocounter.
    zerocounter = 0;
    }
  else {
    zerocounter++;             // increment zerocounter if a zero is received.
    if (zerocounter == 20)     // if 20 0's are received in a row (80uS break)
      {   
      bitClear(TIMSK2, OCIE2A);    //disable this interrupt and enable reception interrupt now that we're in a break.
      bitSet(UCSR3B, RXCIE3);
      }
  }
} //end Timer2 ISR



ISR(USART3_RX_vect){
  dmxreceived = UDR3;
  /* The receive buffer (UDR0) must be read during the reception ISR, or the ISR will just 
  *  execute again immediately upon exiting. */
 
  dmxcurrent++;                        //increment address counter
 
  if(dmxcurrent > dmxaddress) {         //check if the current address is the one we want.
    dmxvalue[i] = dmxreceived;
    i++;
    if(i == NUMBER_OF_CHANNELS) {
      bitClear(UCSR3B, RXCIE3); 
      dmxnewvalue = 1;                        //set newvalue, so that the main code can be executed.
    } 
  }
} // end ISR

Sorry for that, when I'm stuck on a project it's hard to imagine the rest of the world not working on the same thing :grin:

Well, so far the ISR(TIMER2_COMPA_vect) seems to trigger, ISR(USART3_RX_vect) doesn't ( I put a serial.writeln in ISR(USART3_RX_vect), I get no response)

I want to know If I've done something wrong in hardwareserial.cpp; adapted code included below (line 65 to 110); or if it's in another part of my code

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)

SIGNAL(SIG_USART0_RECV)
{
  unsigned char c = UDR0;
  store_char(c, &rx_buffer);
}

SIGNAL(SIG_USART1_RECV)
{
  unsigned char c = UDR1;
  store_char(c, &rx_buffer1);
}

SIGNAL(SIG_USART2_RECV)
{
  unsigned char c = UDR2;
  store_char(c, &rx_buffer2);
}

/*SIGNAL(SIG_USART3_RECV)
{
  unsigned char c = UDR3;
  store_char(c, &rx_buffer3);
}
*/

#else

#if defined(__AVR_ATmega8__)
SIGNAL(SIG_UART_RECV)
#else
SIGNAL(USART_RX_vect)
#endif
{
#if defined(__AVR_ATmega8__)
  unsigned char c = UDR;
#else
  unsigned char c = UDR0;
#endif
  store_char(c, &rx_buffer);
}


#endif

So far I'm still stuck with the UART ISR not firing. I've notice the MAX485 giving about +/- 1.65V, is this enough for the Atmega1280 to fire? Maybe it's the frequency, time for some calculations. All comments are appreciated.

Hello,

I didn't see that you worked on it, and I port the code on mega1280 from my side too ... I didn't change anything on the hardware part and you can see my code change as comment in the original post : http://blog.wingedvictorydesign.com/2009/03/20/receive-dmx-512-with-an-arduino/

For your problem are you sure that ISR(USART3_RX_vect){ is the good one ? I'll put ISR(SIG_USART3_RECV){

Good luck !

Hi loull, Thank you for your reply. I discovered that the signal from the MAX485 (with VCC=5V) was actually too low for the ISR to trigger. Standard RxTx communication with the terminal window turned out to be about 5V top-to-top, and my incoming DMX-signal (working with DMXIS from enttec) about 4V. With a direct connection, I FINALLY HAD RECEPTION!!! :D ->party time. :D There are still some bugs:

if (bitRead(PIND, PIND0))

should be changed to

if (bitRead(PINE, PINE5)) {

as I'm working on PORT E

One more bug: If I test my reception on channel 1, I get the correct value, then a zero, then the correct value, then zero, ... Sometimes my received value is the sent value minus 1 (this also happens with my port of ArDmx), I suspect timing might be a little off (not every XTAL is as exact as the next one I suppose) but this is of minor importance.

I'm cleaning up my code, and will post here and probably on blogspot

jimbojones: One more bug: If I test my reception on channel 1, I get the correct value, then a zero, then the correct value, then zero, ...

I don't understand the reason but you have to add 3 to your dmxaddress ... like done in Addressing() method ... I lost time with this ... For testing channel 1 you have to put dmxaddress = 4. I understand adding 1 for the break ... but others ???

I

I don't understand the reason but you have to add 3 to your dmxaddress ... like done in Addressing() method ... I lost time with this ... For testing channel 1 you have to put dmxaddress = 4. I understand adding 1 for the break ... but others ???

I don't have to add 3. My comment about channel 1 was just an example. In the code I posted before, I was indeed working with channel 3.

My final (and working) code will be posted tomorrow

Hi jimbojones,

I am working on a port for the Seeeduino (sort of atmega). Sofar, I not get it to work. I try to have the dmx input on uart3. DMX seems ok, coming from a tester, producing a steady signal. You were mentioning posting your code here. Maybe it would help me to get me going with it.

Thanks! mrdevis

I am also working on trying to get this running on an arduino mega (2560), and can not manege to get it to work. Does anyone have this successfully running on a 2560? Any help would be be greatly appreciated as far as any changes in the HardwareSerial and or main reception software etc.

Thanks.