Transmitting & Receiving DMX using nRF24L01 radio transceivers

I am now working on a much improved version of the RX/TX software. It will be one bit of code on one PCB and a jumper change will select its role as either a [DMX receiver -> wireless transmitter] or a [wireless receiver -> DMX transmitter]

  • Improved the efficiency of the software by including MatHertels dmx library in both RX & tx
  • Bicolour LED on PCB will indicate Power/DMX receive or Power/Wireless Quality on each board
  • HEX rotary switch will allow 1 of 16 channel selection (tx & rx should match)
  • On power-up the code tests the nrf24L01 board and flashes RED LED if no comms

still to do : live channel hopping & auto-role-selection

I shall publish new code as and when it is tested and functional

I have made 6 PCBs, which I will configure as one transmitter and five receivers, I have a selection of bare-bones-nrf boards and some with the SMA antenna to test

1 Like

I have extended the software further still

Automatic pairing of transmitters to all receivers on powerup, which is created by :

  • Broadcast of best (least interference / lack of carrier) channel for all receivers to pick up on
  • Random pipe generation by transmitter to be broadcast for receivers to find
  • The pairing information is sent on channel 129 using 0xFFFFFFFFFFLL as an initial pipe
  • Once the receivers discover the pairing info they will then reconfigure for that pipe and channel

There is also a manual over-ride so that a specific channel can be chosen

I have also included a very nice 'reception quality' indicator for the bi-colour LED

Once I have brought all this together and fully tested it I shall post some code and a video

:slight_smile:

Current PCB, standard mount, with plans to go to surface mount in the near future :slight_smile:

1 Like

mcnobby would you consider helping me with my project.
I have built and have a fully functional sketch which uses a 10DOF sensor(Pitch,Roll,Yaw) connected to an UNO the UNO controls three separate servos.
Ultimate goal is to transmit via xBees controlling the servos wirelessly
I have the xBees, UNOs etc but not nearly enough grey matter to complete this project.

Unfortunately I dont know anything about XBEEs, these NRF24L01's have been tricky enough to get working as I want them to

Have you considered asking for help in "project guidance", "programming questions" or "networking, protocols and devices"

I am sure there are good people that can help you with your specific requirements

Regards Bob

Video of my project working using latest prototype PCBs and new "autoPairing" software

1 Like

I have the code ready to publish if anyone is interested

1 Like

Hi...yes please publish the code,that'd be great.

I tried and it is too long, I might edit it into two shorter bits and have another go

Do you think you can email me?
Harrymaghera@gmail.com

I would much rather find a way for others to see it also, otherwise I would end up emailing several people and having private conversations, whereas ALL the conversation and detail should be public :slight_smile:

Here is the Arduino project file for the Wireless DMX using NRF24L01
It is still work in progress

  • Pairing and rePairing works perfectly for both pre-initialised and non-initialised boards
  • Packet size is reduced to 18 (16bytes DMX with 2 bytes overhead)
  • Bi-Colour LED flashing has been changed so that overall current consumption is lower (RX & TX)
  • It is my intention that Rechargeable batteries will be used.

This does not use Frequency Hopping yet, although I am looking at ways of introducing it into the system, still using the simplex/non-ack protocol

regards

WirelessDMX_6_small_packets.ino (15.6 KB)

3 Likes

I couldn't agree more. Thanks for the file.

Cool. Glad to see you aremaking progress here. I have never gotten my radios to talk to each other reliably.

I'm trying to reverse your board in my head, what's the little 8-pin DIP? is that a 485 or something like that? And then a 328P in the middle, at 16Mhz? and then what kind of connectors are on the side of the board, I see a power connector and then 2 other jacks?

Thanks!

Jimmy

I have attached a pic Jimmy,

The connectors at the top are two 'headphone' type connectors that I use for daisy chaining DMX in/out (I have small jack-to-xlr leads on my projects, its keeps the huge XLR sockets off the board !!)

between these is a standard 12v power socket

The 8 pin dip is indeed a Sn76175 rs485 interface chip, ATMeag328 @ 16mhz, bi-colour LED on 470R, SPI programming connector next to nRF24 socket, single jumper above the SPI is to control if the board is RX or TX, and the HEX switch is there for fixed channel selection

I dont use channel select at the moment as I do a full channel search looking for quiet channels, and use that as the tx/rx channel, seems to work fine, but as I am on full chat I think I should really be using channel hopping

I am working on a full version of FHSS (frequency hopping) which I hope to have done within this next week

This probably WONT require the hex switch !
I also want to be to able to determine which role it should play by listening for DMX input and making that the transmitter, but I think I have a chicken and egg situation there...

For those who are interested, I have a facebook 'club' for DIY DMX Lighting HERE

1 Like

This is a very simple (but working) 512 channel wireless DMX.

I have removed all the bells and whistles out of the code for this one and just left what actually works on a single channel

It is one piece of code that does both jobs, the role decided on if A0 is grounded or not
If A0 = grounded, the role will be a Wireless Reciever -> DMX transmitter
If A0 = high (or left pulled up) the roll will be a DMX receiver -> Wireless transmitter

I have left control of the RS485 interface chip via pins (or at least one pin) on the micro, so this changes the data flow direction

The code is set to channel 0 for both

On powerup, the Wireless transmitter will light a RED LED, if there is DMX coming in, this RED LED will flash
On powerup, the Wireless receiver will light a BLUE LED, if there is wireless being received it will flash

The DMX data coming in is compared with the previous DMX data channels and ONLY IF there has been data change will the final packet be sent for that group.

Every second ALL the DMX data is sent regardless of change. The radio data is sent virtually end to end without any breaks to give a nice smooth data flow

// FOR ATMEGA328 16mhz ONLY //
// 
// NRF24L01 connection information : http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
// Ensure 3.3v is used to supply NRF24L01 board !!
//
// SN75176 configuration : 
//   DMXrx/NRFtx : pin 2 = 0v | pin 3 = 0v
//   NRFrx/DMXtx : pin 2 = 0v | pin 3 = 5v
//   pin 6 = DMX+ 
//   pin 7 = DMX-

#include <SPI.h>
#include <nRF24L01.h> // library: https://github.com/maniacbug/RF24
#include <RF24.h>
#include <Wire.h>
#include <DMXSerial.h> // library: http://www.mathertel.de/Arduino/DMXSerial.aspx //

#define MAX_DMX_CHANNELS 512 // full DMX
#define BYTES_PER_PACKET 16 // usable bytes per packet
#define PACKET_OVERHEAD 2 // group and time stamp
#define MAXPAYLOAD (BYTES_PER_PACKET+PACKET_OVERHEAD) // max payload size for nrf24l01
#define MAXGROUPS (MAX_DMX_CHANNELS/BYTES_PER_PACKET) // 32 groups of 16 channels = 512 DMX channels

// nRF24L01 control
#define nRF_CE 9 // Chip enable
#define nRF_CSN 10 // Chip select not
// sn76175 control
#define DMX_NOT_EN 2
#define DMX_MODE 3
// LEDs
#define LED_BLUE 6 // BLUE PWM
#define LED_RED 5 // RED PWM
// other
#define ROLE A0 // if low (jumper on) then RX otherwise TX

RF24 radio(nRF_CE,nRF_CSN);

unsigned long refreshTimer, flashTimer;
uint64_t RXTXaddress = 0xF0F0F0F0F0LL;
uint8_t RXTXchannel = 0;
uint8_t payload[MAXPAYLOAD], shadow_DMX[MAX_DMX_CHANNELS];
uint8_t timeStamp; 
boolean group_send;

void setup(void)
{
  // set DMX/rs485 interface
  pinMode(DMX_NOT_EN, OUTPUT); 
  digitalWrite(DMX_NOT_EN, LOW); 
  pinMode(DMX_MODE, OUTPUT);
// other
  pinMode(ROLE, INPUT_PULLUP); 
  pinMode(LED_BLUE, OUTPUT); 
  pinMode(LED_RED, OUTPUT); 
  radio.begin();
  radio.setAutoAck(false);
  radio.setPayloadSize(MAXPAYLOAD);
  radio.setPALevel(RF24_PA_HIGH);    
  radio.setDataRate(RF24_250KBPS); 
  radio.setRetries(0,0);
  radio.setChannel(RXTXchannel); // set the channel
  DMXSerial.maxChannel(MAX_DMX_CHANNELS);
  
  if (digitalRead(ROLE)) { // Jumper OFF : this is a wireless transmitter
    digitalWrite(DMX_MODE,LOW); // enable rs485 for input
    DMXSerial.init(DMXReceiver); // enable DMX to receive
    radio.openWritingPipe(RXTXaddress); // set network address
    radio.stopListening(); // start talking !
    digitalWrite(LED_RED,1); // Red ON
    digitalWrite(LED_BLUE,0); // Ground Blue Side of LED

  }
  else { // Jumper ON : this is a wireless receiver
    digitalWrite(DMX_MODE,HIGH); // enable rs485 for output
    DMXSerial.init(DMXController); // enable DMX for output only
    radio.openReadingPipe(1,RXTXaddress); // set network address
    radio.startListening(); // start listening for data
    digitalWrite(LED_RED,0); // ground Red side of LED
    digitalWrite(LED_BLUE,1); // Blue ON
  }
  refreshTimer = flashTimer = millis(); // start timing for DMX refresh on TX
} 

void loop(void) {
/////////////////////////////// DMX IN --> WIRELESS TRANSMITTER ///////////////////////////////
  if ( digitalRead(ROLE) ) { // Jumper OFF : if a wireless transmitter
    for (uint8_t group = 0; group < MAXGROUPS; group++) { // send groups of DMX data, 16 bytes at a time
      uint16_t group_ptr = group*BYTES_PER_PACKET; // create group pointer for array
      if (millis() - refreshTimer > 1000) { // allow ALL radio data (full DMX array) to be send once per second, regardless of changes
        group_send = true; // force ALL send
        refreshTimer = millis(); // reset refresh timer
      } 
      else { 
        group_send = false; // preset flag to false, only set it if there has been a data change since last time
      } 
      for (uint8_t chan = 1; chan < BYTES_PER_PACKET+1; chan++) {
        if ( DMXSerial.read(group_ptr+chan-1) != shadow_DMX[group_ptr+chan-1] ) { // compare test : current DMX against old DMX 
          shadow_DMX[group_ptr+chan-1] = DMXSerial.read(group_ptr+chan-1); // if changed, update shadow array of DMX data and payload
          group_send = true; // set flag so that THIS group packet gets sent
        } 
        payload[chan+1] = DMXSerial.read(group_ptr+chan-1); // ensure ALL up-to-date data gets through on this packet
      } 
      if (group_send) { // only send the data that has changed, any data change in a group will result in whole group send
        payload[0] = group; // set first byte to point to group number (groups of 16 bytes)
        payload[1] = timeStamp++; // second byte helps us monitor consistency of reception at receiver with a continuous frame counter
        radio.write( payload, sizeof(payload) ); // dump payload to radio
      } 
    } 
    
    if ( (DMXSerial.noDataSince() < 2000) && (millis() > 1000) ) { // if DMX has been received within the last 2 seconds make LED flash
      if (!(millis() & 0b1100000000)) { 
        digitalWrite(LED_RED,1); // flash ON
      } 
      else { // flash OFF
        digitalWrite(LED_RED,0); 
      }  
    }
    else { // no DMX data present, no flash just ON
      digitalWrite(LED_RED,1); 
    }

  } 

/////////////////////////////// WIRELESS RECEIVER --> DMX OUT ///////////////////////////////
  else { // Jumper ON : if a wireless receiver
    if ( radio.available() ) {
      radio.read( payload, sizeof(payload) ); // get data packet from radio 
      for (uint8_t i = 0; i <BYTES_PER_PACKET; i++) {
        DMXSerial.write((BYTES_PER_PACKET*payload[0])+i, payload[i+2]); // parse radio data into dmx data array
      } 
      if (millis() - flashTimer < 750) { 
        digitalWrite(LED_BLUE,0);
      } 
      else if (millis() - flashTimer > 749) { 
        digitalWrite(LED_BLUE,1);
      } 
      if (millis() - flashTimer > 1024) { 
        flashTimer = millis(); // reset timer after 1 second(ish)
      } 
    } 
  }
}

Schematic for the above code...

1 Like

I will try this setup as a baseline. I've had trouble getting everything working with too many features! Thanks for this!

There is a mistake i noticed on the schematic (or software)

PIN 3 of the SN75176 should go to DigitalPin 3 (PD3 - actual pin 5) of the micro

OR you could change

"#define DMX_MODE 3" to read "#define DMX_MODE 2"

My bad :slight_smile: