This is a library for sending and receiving DMX codes using the Arduino plattform or a ATmega168 (or similar) processor.
The library avoids timming issues on the low level protocol that typically exist when using software implementations by using the internal serial communication hardware of the chips. Therefore it is very uncritical to add you specific DMX effects on top of this communication library.
DMX sending and DMX receiving are both supported by this library. You can find a brief description of using the details of the serial hardware registers in this article.
Download the library files including 2 samples for sending and receiving DMX messages:
This sketch and library shows how to use the hardware serial interface for sending and receiving DMX data packages.
To have a minimal DMX compatible hardware you have to add a RS-485 driver chip like the MAX481 and attach it to the hardware based serial interface of the ATMEGA Microcontroller. A corresponding Arduino compatible DMX Shield can be found at DMXShield.aspx.
DMX521 or DMX in short was defined to control stage lightning effects by using XLR style cables. A good starting point for more information about the history and evolution of DMX can be found on Wikipedia: http://en.wikipedia.org/wiki/DMX512
Some Arduino related information is also available on the playground of the Arduino WebSite: http://www.arduino.cc/playground/Learning/DMX
While DMX was designed to have a single sender and multiple receivers. In 2006 a bi-directional protocol called RDM was defined that enhances DMX that enables a bi-directional communication that I like to support as well. See also: http://en.wikipedia.org/wiki/RDM_(lighting)
Both, the hardware and software decisions and designs were made to support RDM and DMX and die Arduino Shield can be used for all of it.
With this first version however only DMX Controllers (only sending) and DMX Receivers (only listening) are supported mode of operations.
Before starting the soldering and programming I did some research on existing DMX interface projects and checked for good and bad design hints.
The logical level of DMX communication is built upon serial sending with 250.000 baud according the RS-485 definition using no parity bits and 2 stop bits.

Luckily the hardware serial ports built in the ATMEGA chips used on the Arduino board supports this kind of communication and this high baud rate. see also http://en.wikipedia.org/wiki/RS-485
There is nothing really special about the levels of this communication protocol except the reset frame which is low for more than 88 µsec. The 2 stop bits have a minimum time of 8 µsecs but this time can be longer up to one second.
After a reset frame the payload bytes are transmitted by the DMX host using a start byte (value 0) and maximum of 512 channel value bytes. It is not recommended to send less than 24 channels.
This DMX and RDM specification allows sending and receiving DMX by using the built-in hardware. The tricks we need will be explained further down.
I have learned to avoid using the standard Serial implementation of the Arduino. There is a problem with it when accessing the hardware base serial interface because the serial kind of parity and stop bit handling is not set at all and the standard values are used.
Instead of using the built-in Serial object that is implemented in the HardwareSerial library this library initializes and controls all the Control Registers by itself.
There was a first approach published on http://arduino.cc/playground/Learning/DMXSerial in 2011 that used the build-in Serial implementation but it turned out that when using the Interrupt features there is a implementation conflict with the interrupt routines needed for DMX and the existing interrupt routines of the standard Serial implementation. The http://arduino.cc/playground/DMX/Ardmx site mentions that the core file has to be modified - but this is not true in Serial is not used at all.
So you have to avoid using the Serial object at all and even don't use it for debugging purpose!
There are several hardware settings that have to be implemented to enable the built-in serial interface. Her I just go through the implementation for your orientation how it's done.
Enabling the hardware has to be done by setting the corresponding bits in the USART Control and Status Register B. The following does enabling sending and the corresponding Data Register Empty Interrupt in the case of the DMXController mode:
// Enable transmitter and interrupt UCSRnB = (1<<TXENn) | (1<<UDRIEn);
Enabling the receiver and the corresponding Receive Complete Interrupt in the case of the DMXReceiver mode is very similar:
// Enable receiver and Receive interrupt UCSRnB = (1<<RXENn) | (1<<RXCEn);
Setting the baud rate is implemented in the function _DMXSerialBaud because we often have to change it when sending DMX packages. The source code of this function is very similar to the one used in the standard Serial implementation, except that it also sets the transmission mode to 2 stop bits, 8 data bits and no parity:
// initialize the Hardware serial port with the given baud rate
// using 8 data data bits an 2 stop bits.
void _DMXSerialBaud(long baud)
{
uint16_t baud_setting;
// calculate baud settings
baud_setting = (F_CPU / 8 / baud - 1) / 2;
// assign the baud_setting to the USART Baud Rate Register
UBRRnH = baud_setting >> 8;
UBRRnL = baud_setting;
// 2 stop bits and 8 bit character size, no parity
UCSRnC = (1<<USBSn) | (3<<USCZn0);
} // _DMXSerialBaud
Sending a byte using the hardware is done by writing a new value into the USART Data Register after checking that there is no current transmission.
void _DMXSerialWrite(uint8_t data)
{
// Wait for empty transmit buffer
while ( ! (UCSRnA & (1 << UDREn)) )
;
// Put data into buffer, sends the data
UDRn = data;
} // _DMXSerialWrite
In the official documentation from ATMEL for the ATmega328P microcontroller there is a chapter 20 about the internal Universal Synchronous and Asynchronous serial Receiver and Transmitter (USART) starting on page 178. There are also microcontroller chips in the ATmega family that have more than one USART, so the USART also is referenced by the USART with number 0 (USART0).
In the block diagram you can see that there are some software addressable registers (in bold) used to configure these ports. The name of the registers are UBRRn, UDRn, UCSRnA, UCSRnB and UCSRnC where n is the placeholder for the number of the USART. The concrete registers for the USART0 are:
UBRR0H and UBRR0L: Baud Rate Registers
UDRn: I/O Data Registers
UCSR0A: Control and Status Register A
UCSR0B: Control and Status Register B
UCSR0C: Control and Status Register C
In chapter 20.11 Register Description you can find a short description of each register does.
The Arduino Serial library takes care of many configuration settings when initialized by calling Serial.begin([baud rate]). In the folder \hardware\arduino\cores\arduino you can find the file HardwareSerial.cpp with the implementation of this library. You can search for the begin method and can see that the baud rate is used to calculate the values for the registers UBRR0H (_ubrrh) and UBRR0L (_ubrrl) and some bits of the register UCSR0B (_ucsrb) are set. There is no initialization of the Control and Status Register C at all.
This line of code sets the serial communication mode to asynchronous mode (UMSEL01 and UMSEL00 are not set), no parity mode (UPM01 and UPM02 are not set), 2 stop bits (1<<USBS0) and 8 bit character size (3<<UCSZ00).
Receiving a byte is not implemented using a function, instead a interrupt service routine is registered and will be called when a data package was detected and received by the hardware. No CPU cycles are needed for waiting. The received data is available in the USART Data Receive Register UDRn and a potential buffer overflow that will happen when receiving the DMX reset signal is available in USART Control State Register A UCSRnA. Both values are stored to local variables for later use:
ISR(USART_RX_vect) {
uint8_t USARTstate= UCSRnA; //get state before data!
uint8_t DmxByte = UDRn; //get data
...
}
This interrupt routine is called by the hardware just after a byte was completely sent. This routine will then check for the next byte that has to be sent out. In DMX Controller mode the routine starts again with sending the reset signal when all data of the complete package is sent.
ISR(USART_UDRE_vect) { ... }
The reset signal, that has to be sent before the channel data bytes is a little bit tricky.
This 88 µsec low signal cannot be sent by using the 250.000 baud rate. For sending the break a slower baud rate is initialized, a 0-byte is sent and the baud rate is reset to the correct 250.000 baud.
// setup a slower baud rate _DMXSerialBaud(115200); // and send a 0 byte _DMXSerialWrite((uint8_t)0);
You can find this code that starts sending a complete DMX package and the interrupt service routine continuously sends out the DMX values in the DMXController mode.
A design for a DMX Shield that works with this library can be found in the article: DMX Shield.
This page is part of the http://www.mathertel.de/ web site.