Pages: [1] 2   Go Down
Author Topic: DMX woes...  (Read 4714 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 23
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi

I am trying to adapt Hendrik Hoelschers DMX code which he created for the ATMega8515. His code can be found here : http://www.hoelscher-hi.de/hendrik/english/ressources.htm.

I have tried to port his code to my Arduino, which is just an ATMega8 I've put together on stripboard. I program it using a parallel port programmer, so the Rx and Tx pins are free. I've used a Maxim Max487 RS485 transceiver chip which I have successfully used on other DMX projects. It is wired up only to receive DMX and is hooked up to the Rx pin of my ATMega8.

Anyway, heres my version of the code. :

Code:
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>

// ********************* local definitions *********************
#define DMX_CHANNELS    (32)                        //use at least 2ch

enum {IDLE, BREAK, STARTB, STARTADR};                  //DMX states

  uint8_t  gDmxState;
  uint8_t  *gDmxPnt;
  uint16_t DmxCount;

  uint8_t  DmxField[DMX_CHANNELS]; //array of DMX vals (raw)
  uint16_t DmxAddress;                  //start address

int ledPin = 13;                // LED connected to digital pin 13

void setup()                    // run once, when the sketch starts
{
  // sets the digital pin as output
  pinMode(ledPin, OUTPUT);      
  
  // Disable interrupts
  cli();    
  
  // 250kbps baud
  UBRRH = 0;
  UBRRL = ((F_CPU /4000) - 1);
      
  // enable rx and interrupt on complete reception of a byte
  UCSRC |= (1<<URSEL)|(3<<UCSZ0)|(1<<USBS);
  UCSRB |= (1<<RXEN)|(1<<RXCIE);
      
  // Enable interrupts
  sei();

  gDmxState= IDLE;

  uint8_t i;
  for (i=0; i<DMX_CHANNELS; i++)
  {
    DmxField[i]= 0;
  }
  DmxAddress= 10;
  if (!(UCSRB &(1<<RXCIE)))                              //if receiver was disabled -> enable and wait for break
  {
    gDmxState= IDLE;
    UCSRB |= (1<<RXCIE);
  }
}

void loop()                     // run over and over again
{
  if(DmxField[0] >=127)
  {
    digitalWrite(ledPin, HIGH);   // sets the LED on
  }
  else
  {
    digitalWrite(ledPin, LOW);    // sets the LED off
  }
}

// *************** DMX Reception ISR ****************
ISR (UART_RX_vect)
{
uint8_t USARTstate= UCSRA;                                    //get state
uint8_t DmxByte= UDR;                                          //get data
uint8_t DmxState= gDmxState;                              //just get once from SRAM!!!
 
if (USARTstate &(1<<FE))                                    //check for break
      {
      UCSRA &= ~(1<<FE);                                          //reset flag
      DmxCount= DmxAddress;                                    //reset frame counter
      gDmxState= BREAK;
      }

else if (DmxState == BREAK)
      {
      if (DmxByte == 0)
            {
            gDmxState= STARTB;                                    //normal start code detected
            gDmxPnt= ((uint8_t*)DmxField +1);
            }
      else gDmxState= IDLE;
      }
      
else if (DmxState == STARTB)
      {
      if (--DmxCount == 0)                                    //start address reached?
            {
            gDmxState= STARTADR;
            DmxField[0]= DmxByte;
            }
      }

else if (DmxState == STARTADR)
      {
      uint8_t *DmxPnt;
      DmxPnt= gDmxPnt;
      *DmxPnt= DmxByte;
      if (++DmxPnt >= (DmxField +DMX_CHANNELS))       //all ch received?
            {
            gDmxState= IDLE;
            }
      else gDmxPnt= DmxPnt;
      }                                          
}

It just grabs 32 DMX values starting at 10. If DMX channel 10 goes over 127, the LED is turned on. At the moment though, nothing happens. I've tried turning the LED on only when the ISR() function is called, but it never is.  :-? My transceiver chip appears to be wired up correctly, so I guess the issue is with the code somewhere. Given that I am very much a beginner when it comes to coding on an Arduino I would appreciate it if any of you could give me pointers as to where I am going wrong.


Thanks


Logged

London
Offline Offline
Faraday Member
**
Karma: 8
Posts: 6240
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Not sure if you have already been there or not, but would it be easier to use some of the Arduino code posted in the playground to do what you want? http://www.arduino.cc/playground/Learning/DMX
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 23
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Unfortunately the code examples and tutorials are for sending DMX with an Arduino, not receiving it...
Logged

London
Offline Offline
Faraday Member
**
Karma: 8
Posts: 6240
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here are a few guesses for things you can try. Hopefully someone with experience doing what you want can pitch in if the following doesn't work.

I am not sure what state the interrupt mask is in when you set it but you could try the following:
// enable rx and interrupt on complete reception of a byte
  UCSRC = (1<<URSEL)|(3<<UCSZ0)|(1<<USBS);  // these were|=
  UCSRB = (1<<RXEN)|(1<<RXCIE);

If that doesn't help, you may want to check the ATmega8 data sheet to verify the mask parameters

Also, although it probably compiles to the same thing, the Arduino code uses:
  SIGNAL(SIG_UART_RECV)
where you have
 ISR (UART_RX_vect)
 
If the Interrupt handler is not being called its worth trying the latter form. And you did say you tested with an led in the handler to verify it was not being called? If you connect the UART to a serial port it may be worth setting a standard baud rate and testing to see if that will trigger Interrupts.

You could also start with the initialization and ISR code in wiring_serial.c, validate it works with a standard serial port, then modify that code for DMX use.

Good luck!
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 23
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

IT WORKS! YAY!!!

I turns out that I wasn't setting the baud rate correctly. Anyway, heres the working code :

Code:
// ********************* local definitions *********************
#define DMX_CHANNELS    (32)            //Define the number of DMX values to store

enum {IDLE, BREAK, STARTB, STARTADR};      //DMX states

uint8_t  gDmxState;
uint8_t  *gDmxPnt;
uint16_t DmxCount;

uint8_t  DmxField[DMX_CHANNELS];     //array of DMX vals (raw)
uint16_t DmxAddress;                   //start address

int ledPin = 13;                       // LED connected to digital pin 13

void setup()                           // run once, when the sketch starts
{
  // sets the digital pin as output
  pinMode(ledPin, OUTPUT);      
  
  // Disable interrupts
  cli();    
  
  // 250kbps baud - only works for 16MHz clock frequency. See the ATMega8 datasheet if you are using a different clock speed
  UBRRH = 0;
  UBRRL = 3;
      
  // enable rx and interrupt on complete reception of a byte
  UCSRB = (1<<RXEN)|(1<<RXCIE);
  UCSRC = (1<<URSEL)|(3<<UCSZ0)|(1<<USBS);
      
  // Enable interrupts
  sei();

  gDmxState= IDLE;

  uint8_t i;
  for (i=0; i<DMX_CHANNELS; i++)
  {
    DmxField[i]= 0;
  }

  DmxAddress= 10;  //Set the base DMX address. Could use DIP switches for this.
}

void loop()                     // run over and over again
{
  if(DmxField[0] >=127)
  {
    digitalWrite(ledPin, HIGH);   // sets the LED on
  }
  else
  {
    digitalWrite(ledPin, LOW);    // sets the LED off
  }
}

// *************** DMX Reception ISR ****************
SIGNAL(SIG_UART_RECV)
{
uint8_t USARTstate= UCSRA;                              //get state
uint8_t DmxByte= UDR;                                    //get data
uint8_t DmxState= gDmxState;                              //just get once from SRAM!!!
 
if (USARTstate &(1<<FE))                              //check for break
      {
      UCSRA &= ~(1<<FE);                              //reset flag
      DmxCount= DmxAddress;                              //reset frame counter
      gDmxState= BREAK;
      }

else if (DmxState == BREAK)
      {
      if (DmxByte == 0)
            {
            gDmxState= STARTB;                        //normal start code detected
            gDmxPnt= ((uint8_t*)DmxField +1);
            }
      else gDmxState= IDLE;
      }
      
else if (DmxState == STARTB)
      {
      if (--DmxCount == 0)                              //start address reached?
            {
            gDmxState= STARTADR;
            DmxField[0]= DmxByte;
            }
      }

else if (DmxState == STARTADR)
      {
      uint8_t *DmxPnt;
      DmxPnt= gDmxPnt;
      *DmxPnt= DmxByte;
      if (++DmxPnt >= (DmxField +DMX_CHANNELS))             //all ch received?
            {
            gDmxState= IDLE;
            }
      else gDmxPnt= DmxPnt;
      }                                          
}



Many thanks to Hendrik Hoelscher for the original code, and to those who've helped me on this forum.

At the moment, this code only works on the ATMega8 CPU, not the ATMega168 as the register names are different. I don't have a 168-based Arduino to play with so if anyone wants to add to the code to make it work with the 168, be my guest. Also I think this might be worth putting into a separate library once it is made to work with the 168-based boards.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 3
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


 I modify this DMX routine for the ATMega168.The register names are different ...now are;
  UBRR0H
  UBRR0L
  UCSR0B
  UCSR0C
  UCSR0A....etc
I change the register names ,but this code don't works .!
I would appreciate it if any help me.
Thanks smiley
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 50
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I haven´t tryed it yet ,but I have change all registernames for atmega168 and it complies, so it i could work  .

Here´s the whole code:
Code:
// ********************* local definitions *********************
#define DMX_CHANNELS    (32)            //Define the number of DMX values to store

enum {IDLE, BREAK, STARTB, STARTADR};      //DMX states

uint8_t  gDmxState;
uint8_t  *gDmxPnt;
uint16_t DmxCount;

uint8_t  DmxField[DMX_CHANNELS];     //array of DMX vals (raw)
uint16_t DmxAddress;                   //start address

int ledPin = 13;                       // LED connected to digital pin 13

void setup()                           // run once, when the sketch starts
{
  // sets the digital pin as output
  pinMode(ledPin, OUTPUT);

  // Disable interrupts
  cli();

  // 250kbps baud - only works for 16MHz clock frequency. See the ATMega8 datasheet if you are using a different clock speed
  UBRR0H = 0;
  UBRR0L = 3;

  // enable rx and interrupt on complete reception of a byte
  UCSR0B = (1<<RXEN0)|(1<<RXCIE0);
  UCSR0C = (1<<UMSEL01)|(3<<UCSZ00)|(1<<USBS0);

  // Enable interrupts
  sei();

  gDmxState= IDLE;

  uint8_t i;
  for (i=0; i<DMX_CHANNELS; i++)
  {
    DmxField[i]= 0;
  }

  DmxAddress= 10;  //Set the base DMX address. Could use DIP switches for this.
}

void loop()                     // run over and over again
{
  if(DmxField[0] >=127)
  {
    digitalWrite(ledPin, HIGH);   // sets the LED on
  }
  else
  {
    digitalWrite(ledPin, LOW);    // sets the LED off
  }
}

// *************** DMX Reception ISR ****************
SIGNAL(SIG_UART_RECV)
{
uint8_t USARTstate= UCSR0A;                              //get state
uint8_t DmxByte= UDR0;                                    //get data
uint8_t DmxState= gDmxState;                              //just get once from SRAM!!!

if (USARTstate &(1<<FE0))                              //check for break
      {
      UCSR0A &= ~(1<<FE0);                              //reset flag
      DmxCount= DmxAddress;                              //reset frame counter
      gDmxState= BREAK;
      }

else if (DmxState == BREAK)
      {
      if (DmxByte == 0)
            {
            gDmxState= STARTB;                        //normal start code detected
            gDmxPnt= ((uint8_t*)DmxField +1);
            }
      else gDmxState= IDLE;
      }

else if (DmxState == STARTB)
      {
      if (--DmxCount == 0)                              //start address reached?
            {
            gDmxState= STARTADR;
            DmxField[0]= DmxByte;
            }
      }

else if (DmxState == STARTADR)
      {
      uint8_t *DmxPnt;
      DmxPnt= gDmxPnt;
      *DmxPnt= DmxByte;
      if (++DmxPnt >= (DmxField +DMX_CHANNELS))             //all ch received?
            {
            gDmxState= IDLE;
            }
      else gDmxPnt= DmxPnt;
      }
}


Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 50
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

it seems that i cant make this to work but i´m not shure if its hardware or the software thats wrong. i have used arduino program above and the conection Circuit to the arduino board looks like this:


 im using arduino Duemilanove board.
so please help me! what did i do wrong?
Logged

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 508
Posts: 31390
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Have you tried swapping PIN2 and Pin3 on the DMX connector. Make sure something is sending DMX commands and then run a simple sketch that just flashes the LED every time it receives a byte. (you can't use serial.print() as you are using the input pin with the DMX)
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 50
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have tried swapping pin2 and 3 but its not working. but have yet not tried with a simple byte reading sketch.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 50
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

is not the rx LED supose flash when the arduino receives data thru the RX input.
Logged

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 508
Posts: 31390
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

No it only does that when the data comes from the USB not from an outside source.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 50
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hi again and thanks Grumpy_mike for the tipp.
I have now tryed the hardware for the dmx connection and it works.

i used the software serial libary example and change the baud rate to 250K and the LED is flashing woha!!!. finally i know the arduino can read the data stream.

so do anyone know what could be the problem with the sketch?
« Last Edit: February 04, 2009, 05:39:10 pm by gaggenau » Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 177
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just for the sake of curiosity, I knew DMX is a protocol to control complex lighting. What can you do by receiving and not sending it?
Logged

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 508
Posts: 31390
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
so do anyone know what could be the problem with the sketch

Well I can't follow it too well. I always find that lots of "else if" can be confusing and easy misunderstood. Try and re arrange this part maybe using a switch construct.
Logged

Pages: [1] 2   Go Up
Jump to: