DMX Tx test module

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am developing a DMX Rx module. I thought it would be good to have a TX module that gave a known refernece signal ( it also enabled me to check the baud rate)
Thus the following code was born.
While the code may not be too glamerous, it seems to works.

If it is useful to others, that's good.

All comments on the code are welcome
Matt

(I am using a TINY231 and GCC with in Studio4)


/* io.h contains the defines for USART registers */
#include 
#include "delay_x.h"


/* Defines to calculate the UBBR value based on 12Mhz clock speed
** and 250 000 baud. */
#define F_CPU 12000000L
#define FOSC 12000000L
#define BAUD 250000
#define MYUBRR FOSC/16/BAUD-1
#define dmx_ch 192

#define LED_PORT	PORTD
#define LED_IO		PD6		// indicates program initialisation status
#define LED_USART	PD5		// Indicates USART initialieds
#define LED_TRIG	PD4		// Really for testing purposes only.  toogles with start frame
#define LED_DATA	PD3		// 
#define IO_TRIG	PD2		// Really for testing purposes only.  toogles with start frame
#define IO_TX		PD1		// Tx Pin of USART 

void USART_init(unsigned int ubrr);
void USART_tx(unsigned char data);

int main()
{
   unsigned char count;
   unsigned char x;
	DDRD = 0b01111001;  
	LED_PORT &= 0x00;

	LED_PORT |= (1<<LED_IO);		// set bit 7

	USART_init( MYUBRR );
	LED_PORT |= (1<<LED_USART);		// set bit 6

   while(1)
   {
		LED_PORT  &=~(1<<IO_TX);	// 'start' frame is low for 88 to 100 us
		LED_PORT |=(1<<IO_TRIG);	// Set trigger high for testing only
		LED_PORT |=(1<<LED_TRIG);	// turn Trigger LED on

		_delay_us(94);				// this delay is twicked  
		LED_PORT |=(1<<IO_TX);		// MAB is high for atleast 8 us
		LED_PORT  &=~(1<<IO_TRIG);	// Set the trigger pulse low  
		_delay_us(10);
		
		UCSRA = (1<<TXC);			// Clear out any 	
	   	UCSRB = (1<<TXEN);			// Enable tx portion of the USART
		LED_PORT  &=~(1<<LED_TRIG);	// Turn Trigger LED off  
		x = 0x00;
		for (count=1; count <= dmx_ch; count++)	
		{								// the first word has all 0s indication start co
			USART_tx(x);
			x=x+0x01;
		}
		while (!(UCSRA&(1<<TXC)));	// wait here until the last data bit is TXd		
		UCSRB &=~(1<<TXEN);			// disable the TX portion of the Usart

   }
   return(0);
}

/*********** USART_tx ******************************************/

void USART_tx(unsigned char data)
{
   while( !( UCSRA & (1<<UDRE)) )
      ;
   UDR = data;
}

/*********** USART_init ******************************************/
void USART_init(unsigned int ubrr)
{
   	/* set baud rate, UBRRH is not used for this example */
   	UBRRH = (unsigned char)(ubrr>>8);
   	UBRRL = (unsigned char)ubrr;

   	/* Don't enable rx and tx YET*/
//   	UCSRB = (1<<RXEN) | (1<<TXEN);
		UCSRB &= ~(1 << RXEN) ;
		UCSRB &= ~(1 << TXEN) ;


   	/* set frame settings to 8 data, 2 stop bit */
	UCSRC = (1<<USBS) | (3<<UCSZ0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Make sure you test your DMX receiver by changing the Break period and the MAB period to either end of the DMX specifications. Personally I would use a #define for these variables and perhaps even a macro to it for readability :).

Also make sure you test all sorts of channel counts and interruptions in the stream. I've seen some desks that only transmit 6 channels.

Also make sure your receiver only acts on the correct start code. I think luminare makers such as martin use different start codes to do device specific changes.

The code looks pretty ok to me, I haven't tired it though.

oddbudman

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

oddbudman wrote:
Personally I would use a #define for these variables and perhaps even a macro to it for readability :).

oddbudman

Top sugestion. Done!
I tried hooked it up on my purchased RX and now I can see how it performs. It stops when break is less than about 60us 8)
Thanx
Matt :D

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This code works. Had to set the delay with my scope first. I also have this on an atmega16 with a 16MHz xtal.

code:

#include 
#include 
#include 
#include 
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
void USART_tx(u8 data) 
{  
	while( !( UCSRA & (1<<UDRE)) );
	UDR = data; 
} 

void USART_init()
{
	UCSRA = 0; 
	/* set frame settings to 8 data, 2 stop bit */ 
	UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
	// set baud rate 
	UBRRH = 0x00; // 250kbps with a 16MHz osc 
	UBRRL = 0x03; // UBRR = 3 
 
	UCSRB &= ~(1 << TXEN); 
	UCSRB &= ~(1 << RXEN); 

}

int main(void)
{
	DDRC = 255; //port C output
	DDRD = 255; //port D output
	PORTC = 0xff;//enable transmit
	USART_init();
	while(1) 
	{ 
		// Break 
		PORTD=0x00; 
		_delay_us(1450);// Break for 88 us 
		// MAB 
		PORTD=0xFF; // MBA for 12 us 
		_delay_us(200);
		UCSRA = (1<<TXC); 
		UCSRB = (1<<TXEN); 

		USART_tx(0);
		USART_tx(50); 		
		USART_tx(100); 
		USART_tx(150); 		
		USART_tx(200); 
		while (!(UCSRA & (1<<TXC))); 
		UCSRB &= ~(1<<TXEN); 
		 
	} 
}
Last Edited: Fri. Dec 26, 2008 - 05:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
how do you make the code green like above
You use the CODE button before and AFTER pasting, this also preserves the format and makes the code easier to read. You can go back and edit your post.

Mark and delete the old code, copy the new code to the clip board, click on CODE, paste the code, click on CODE again. If you want you can preview you post to see if it worked.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, now it's easier to read. Back to the question, for some reason the output doesn't look good on my scope, and my DMX devices don't respond to it.

Does this code create the correct signal? I would have thought you would have to use the timer interrupts to get the correct BREAK and MAB?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have to set your delay with a scope to get the correct break and mab.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi All, I made a new PCB and programmed it with the above code and my output on my scope is jittery.

Is there a more precise way than to put the transmit code in the main loop?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi All, I tried something new, I thought it would make the timing more precise so my packets weren't as out of sync. Still when I connect my LED light the LEDs flicker which tells me the channels aren't lining up properly. Below is my code, any ideas? I'm using an atmega16 with a 16MHz xtal.

#include 
#include 
#include 
#include 
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
static volatile u8 count;

ISR(TIMER0_COMP_vect)
{
switch(count)
{
case 0:
	UCSRB &= ~(1<<TXEN);
	count = 1;
	TCCR0 = 0;	
	PORTD = 0;
	OCR0 = 174;			88us
	TCCR0 = (1<<CS01)|(1<<WGM01);
	break;
case 1:
	count = 3;
	TCCR0 = 0;
	PORTD = 0xff;
	OCR0=25;			15us
	TCCR0 = (1<<CS01)|(1<<WGM01);
	break;
//case 2:
//	count = 3;
//	TCCR0 = 0;
//	PORTD = 0x00;
//	OCR0=1;
//	TCCR0 = (1<<CS01)|(1<<WGM01);
//	break;
case 3:
	count = 4;
	TCCR0 = 0;
	OCR0=87;			44us
	TCCR0 = (1<<CS01)|(1<<WGM01); 
	UCSRB = (1<<TXEN); 
	USART_tx(0);	
	break;
case 4:
	count = 5;
	TCCR0 = 0;
	OCR0=87;
	TCCR0 = (1<<CS01)|(1<<WGM01);
	USART_tx(255);
	break;
case 5:
	count = 6;
	TCCR0 = 0;
	OCR0=87;
	TCCR0 = (1<<CS01)|(1<<WGM01);
	USART_tx(255);
	break;
case 6:
	count = 7;
	TCCR0 = 0;
	OCR0=87;
	TCCR0 = (1<<CS01)|(1<<WGM01);
	USART_tx(255);
	break;
case 7:
	count = 8;
	TCCR0 = 0;
	OCR0=87;
	TCCR0 = (1<<CS01)|(1<<WGM01);
	USART_tx(255);
	break;
case 8:
	count = 0;
	TCCR0 = 0;
	OCR0=87;
	TCCR0 = (1<<CS01)|(1<<WGM01);
	USART_tx(0);
	break;
}

}

void timer_init()
{
   TCNT0 = 0;
   OCR0 = 174;		88us
   TIMSK = (1<<OCIE0);
   TCCR0 = (1<<CS01)|(1<<WGM01);
}

void USART_tx(u8 data) 
{  
	while( !( UCSRA & (1<<UDRE)) );
	UDR = data; 
} 

void USART_init()
{
	UCSRA = 0; 
	/* set frame settings to 8 data, 2 stop bit */ 
	UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
	// set baud rate 
	UBRRH = 0x00; // 250kbps with a 16MHz osc 
	UBRRL = 0x03; // UBRR = 3 
 
	UCSRB &= ~(1 << TXEN); 
	UCSRB &= ~(1 << RXEN); 

}

int main(void)
{
	DDRC = 255; //port C output
	DDRD = 255; //port D output
	PORTD = 0xff;
	PORTC = 0xff;//enable transmit
	USART_init();
	timer_init();
	sei();
	count = 0;
	while(1){}

}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For some reason signal stabilizez when I take a metal screw driver and press it against the xtal 1 side of the crystal???
It also buzzed a lot??

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

say, this code works ?!?!?

_delay_us(1450);// Break for 88 us
// MAB
PORTD=0xFF; // MBA for 12 us
_delay_us(200);

when running this code you get 1450uS not 88
and you get 200uS not 12 as your comment say.

Yours: Thomas Scherrer - Denmark
OZ2CPU www.webx.dk

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's hard to trigger a scope on serial data. I find it easier to toggle a port bit and use this to trigger the scope. Your second piece of code was a bit brute force methinks. It's been over 20 years since I've done dmx, but in the early days a lot of equipment liked a longer break time. The second rev of the dmx spec made the timings a bit more generous, but I haven't read the latest spec. Also some equipment didn't like small packets of channels and too little time between packets.