Go Down

Topic: Recieving DMX on an Arduino MEGA (Read 5341 times) previous topic - next topic

jimbojones

Feb 01, 2011, 03:51 pm Last Edit: Feb 01, 2011, 05:08 pm by jimbojones Reason: 1
Hi everyone,

This is my first post on this forum, I REALLY hope someone can help me.
I'm porting the DMX project from
http://blog.wingedvictorydesign.com/2009/03/20/receive-dmx-512-with-an-arduino/
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.

Code: [Select]
/***********************************************************
* 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

jimbojones

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  :smiley-mr-green:

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

Code: [Select]

#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

jimbojones

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.

ioull

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 !

jimbojones

#4
Feb 07, 2011, 04:41 pm Last Edit: Feb 07, 2011, 04:56 pm by jimbojones Reason: 1
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:
Quote
if (bitRead(PIND, PIND0))

should be changed to  
Quote
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

ioull


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 ???


jimbojones

#6
Feb 07, 2011, 06:16 pm Last Edit: Feb 07, 2011, 06:18 pm by jimbojones Reason: 1
I
Quote
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


mrdevis

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

daslesen

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.

Go Up