Change dmx channel information

Hi!

I am using a DMX recorder to send information to a Light Fixture. Specifically, values to channels 1, 2 and 7. I want to add another fixture, but this new fixture has the channels distributed differently, so that I would have to send values to channel 1 and 2 (which remain the same), and the values from channel 7 remap them to channel 8.

Is there a sketch to do so with Arduino and DMX shield?

There are general purpose DMX receiver / transmission libraries available, but the combination of reception and transmission could be problematic for these library methods.
You could try Conceptinetics.h for Atmega based boards. you might want a board with 2 UARTs although that is not strictly required.

Anyway it most definitely can be done and if latency is not to much of a problem, you will manage quite easily. With effort (and particularly since you are focussed on fairly low channel nrs) you will manage with almost no latency.

But there is no straight out of the box solution i can think of.

So what board do you have and which shield ? If you want to receive and transmit, you will need a transceiver for each of those things, so you may need to create something yourself.

Thank you very much for your input!

I actually do have a dmx shield (https://www.halloweenfreak.de/arduino/pdfs/DMX_Shield_Arduino_CTC-DRA-10-R2.pdf) which I guess can be used for this porpouse. It has an input and an output and is mounted on an arduino uno.

I have been using them in a very basic way, to control fog machines, indeed with conceptinetics library. I was going to look around in the library if I see any example that could help me achieve what I am doing, and at the same time, my knowledge is pretty basic, and I need to have this done today for a show in the night, so every further input is welcome!

this is the code I used for the fog machines:

#include <Conceptinetics.h>

#define DMX_MASTER_CHANNELS   1

#define RXEN_PIN              2

DMX_Master  dmx_master  (DMX_MASTER_CHANNELS, RXEN_PIN);


unsigned long previousMillis = 0;

const long interval1 = 90000; //(xx seconds pause)
const long interval2 = 15000; //(xx seconds fog)


void setup() {
  dmx_master.enable ();
  dmx_master.setChannelRange (1, 25, 127);
}


void loop()
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval1)
  {
    previousMillis = currentMillis;
    dmx_master.setChannelValue (1, 254);            // Turn on
  }
  if (currentMillis - previousMillis >= interval2)
  {
    dmx_master.setChannelValue (1, 0);              //turn off
  }
}

I dont see anything in the examples of Conceptinetics Library that I can use for this porpouse, and I honestly have no clue where to start.

Without the details of the exact shield i will be partly guessing.

That is a little bit short notice.

No i said already that there is nothing that will do this out of the box.
The workings of the Conceptinetics are such that for break generation (and i think also detection) it changes the baudrate of the UART, and because of this it can not work as a slave and master at the same time.

What you could attempt is to combine the examples for dmx slave & dmx master, where you enable the slave, read the values you want, and disable the slave, enable the master and transmit what you want to transmit, and then disable the master. and so forth, but i am not sure if this is going to work.

1 day is really a bit short on time to make sure this is going to work, but it is worth a go.

As i stated before, it would be easier to use a board with 2 UARTs.

I looked through my own examples and did find something, but i just don't quite remember if i actually got it to work properly or not (a friend of mine was trying to achieve the same thing a couple of years back)
this was the code

#define PWM_LED_PIN 5
#define DMX_PING 13
#define MAX_DMX_CHANNELS 512
#define DMX_OUTPUT_CHANNELS 512
#define NUMBER_OF_CHANNELS 512

#define BAUDDMX 250000UL
#define TRANSMIT_FORMAT 0x0E // 8N2
#define BREAK_FORMAT 0x26 // 8E1
#define RECEIVE_FORMAT 0x06 // 8N1 (could be 8N2 aswell.
#define BAUDBREAK 49950UL  // should give 176us break same as Conceptinetics
#define UBDMX ((F_CPU / (8 * BAUDDMX)) - 1)
#define UBBREAK ((F_CPU / (8 * BAUDBREAK)) - 1)


volatile uint16_t dmxaddress = 1;
volatile uint16_t i = 0;
volatile uint8_t dmxreceived = 0;
volatile uint16_t dmxcurrent = 0;
volatile uint8_t dmxvalue[NUMBER_OF_CHANNELS];
uint8_t dmxoutput[DMX_OUTPUT_CHANNELS];

volatile uint8_t dmxnewvalue = 0;
volatile uint8_t zerocounter = 0;
volatile bool storeSerial = false;

void setup() {
  pinMode(PWM_LED_PIN, OUTPUT); // first dmxchannel LED value
  pinMode(DMX_PING, OUTPUT); //ping LED
  init_uart();
  SetupTimerRegisters();
}

void loop()  {
  ReceiveDMX();
  Processing();
  SendDMX();
}

void ReceiveDMX() {
  dmxnewvalue = 0;
  dmxcurrent = 0;
  zerocounter = 0;
  i = 0;
  UCSR0C = RECEIVE_FORMAT; //0x06; // 8N1
  bitSet(UCSR0B, RXCIE0);   // enable RX
  bitSet(TIMSK2, OCIE2A);
  while (dmxnewvalue != 1);
}

void Processing() {  // main processing
  static bool pin = true;
  pin = !pin;
  analogWrite(5, dmxvalue[0]);
  digitalWrite(13, pin);
  CopyValues();
}

void CopyValues() {
  for (uint8_t j = 0; j < 3; j++) {
    for (uint8_t k = 0; k < 9; k += 3) {
      dmxoutput[k + j] = dmxvalue[j + 3];
    }
  }
}

void SendDMX() {
  UCSR0C = BREAK_FORMAT; //0x06; // 8N1
  UBRR0H = (UBBREAK >> 8);  // set baud rate
  UBRR0L = (UBBREAK & 0xFF); // HL register
  uart_write(0);
  UCSR0C = TRANSMIT_FORMAT; //0x0E;  // 8N2
  UBRR0H = (UBDMX >> 8);  // set baud rate
  UBRR0L = (UBDMX & 0xFF); // HL register
  uart_write(0);   // start code
  uart_write_buffer();
}

void uart_write(char data) {
  UDR0 = data;
  while ((UCSR0A & 1 << TXC0) == 0);
  UCSR0A |= 1 << TXC0;
}

void uart_write_buffer() {
  for (uint16_t j = 0; j < DMX_OUTPUT_CHANNELS; j++) {
    UDR0 = dmxoutput[j];
    while ((UCSR0A & 1 << TXC0) == 0);
    UCSR0A |= 1 << TXC0;
  }
}

/*  // Not used
  void uart_write_string(const char * data) {
  for (uint8_t count = 0; data[count] != 0; count++) {
    UDR0 = data[count];
    while ((UCSR0A & 1 << TXC0) == 0);
    UCSR0A |= 1 << TXC0;
  }
  }*/

void init_uart() {
  DDRD |=  (1 << PORTD1); // set TX pin  to output
  DDRD &= ~(1 << PORTD0); // set RX pin to input
  UCSR0A = 0x02; // 1<<U2X | 0<<MPCM;
  UCSR0B = 1 << RXCIE0 | 0 << TXCIE0 | 0 << UDRIE0 | 1 << RXEN0 | 1 << TXEN0 | 0 << UCSZ02; // Enable TX & RX, disable RX interrupt
  UCSR0C = RECEIVE_FORMAT; // 8N1
  UBRR0H = (UBDMX >> 8);  // set baud rate
  UBRR0L = (UBDMX & 0xFF); // HL register
}

void SetupTimerRegisters() {  // Sets up Timer2 to fire every 4us
  cli();
  bitClear(TCCR2A, COM2A1);
  bitClear(TCCR2A, COM2A0);
  bitClear(TCCR2A, COM2B1);
  bitClear(TCCR2A, COM2B0);
  bitSet(TCCR2A, WGM21);
  bitClear(TCCR2A, WGM20);
  bitClear(TCCR2B, FOC2A);
  bitClear(TCCR2B, FOC2B);
  bitClear(TCCR2B, WGM22);
  bitClear(TCCR2B, CS22);
  bitClear(TCCR2B, CS21);
  bitSet(TCCR2B, CS20);
  OCR2A = 64;
  bitClear(TIMSK2, OCIE2B);
  bitSet(TIMSK2, OCIE2A);
  bitClear(TIMSK2, TOIE2);
  sei();
}

ISR(TIMER2_COMPA_vect) {
  if (bitRead(PIND, PIND0)) {  // checks if the pin has gone HIGH
    zerocounter = 0;
  }
  else {
    zerocounter++;
    if (zerocounter == 20)  // if 80us have passed 'Break' has been detected
    {
      bitClear(TIMSK2, OCIE2A);  // disable Timer2 Interrupt
      storeSerial = true;
    }
  }
} //end Timer2 ISR

ISR(USART_RX_vect) {
  /* The receive buffer (UDR0) must be read during the reception ISR, or the ISR will just
     execute again immediately upon exiting. */
  dmxreceived = UDR0;
  if (storeSerial) {
    dmxcurrent++;     //increment address counter starts at 0
                      // and skip the start code 
    if (dmxcurrent > dmxaddress) {        //check if the current address is the one we want.
      dmxvalue[i] = dmxreceived;
      i++;
      if ((i == NUMBER_OF_CHANNELS) || (dmxcurrent > MAX_DMX_CHANNELS + 1 )) {
        bitClear(UCSR0B, RXCIE0);
        storeSerial = false;
        dmxnewvalue = 1;                        //set newvalue, so that the main code can be executed.
      }
    }
  }
} // end ISR

looking at the processing i think it copies 3 channels over a range 18 channels in a sort of RGB order, but the processing is not complex. I am just not really sure it actually worked ~o~ I prefer using an ESP8266 for transmission and reception these days, which will give me a lot better UI through a webserver.

Before anything else, i would want to have a proper look at your shield, to see if it actually has an input and an output transceiver, and how they are enabled, to make sure that it won't cause any damage when connecting both these ports.

In the end my friend wanted to do it his own way (which was a lot slower in response) but his method involved DMXSimple.h which does not use the UART for transmission and will require a different pinout for the shield.

Thank you so much for your support!
I know it is short notice, but it is either that, or no show, so I have to try.

Most of the stuff I see is chinese for me, but I will make an effort to understand as much as I can.

I open another thread where I modified a bit the content. There is also more information about the shield and I already combined Master and Slave. Should we continue there?

https://forum.arduino.cc/t/receive-modify-and-retransmit-dmx-with-conceptinetics/1381970?u=camilozk

Don't do that, it is against forum rules.

You should request the thread to be merged by the moderators, and after that we can continue.

And does that work ?

From what i can see, there is only 1 transceiver on it, so all efforts will be mute. The transceiver can not work in input and output at the same time, and the pins of the input and output plugs are simply connected. They are not separate ports physically. With this shield it just won't work i'm afraid.

I didnt know. I thought it might be cleaner for other people to find this information. I delete it then and copy the information here.

It just compiles, I didnt try to upload it to the board yet. Wanted to share it before, to see if there it makes any sense.

If this is the case, then it probably will not be possible in one day. This is what I have available today as I am on tour... What do you suggest for a possible solution in the future? do you know of a shield with these capabilities?

A small recap of the problem:
I have recorded a dmx sequence in a format that I cannot modify anymore, and now I am using new fixtures that have a different channel distribution. It would be very useful if I could write a code that receives dmx information, modifies the channel numbers, and retransmit this modified information.

for example:

  • receives information from address 1 and retransmits it as address 1
  • receives information from address 2 and retransmits it as address 3

I suppose it should be rather simple, but I have no experience with conceptinetics. I have just been using it to send DMX to a fog machine. I have the DMX Shield (https://www.halloweenfreak.de/arduino/pdfs/DMX_Shield_Arduino_CTC-DRA-10-R2.pdf)

I have now combined from the examples the Master and Slave codes, to see if it compiles correctly, and it does, so I assume that it is possible to receive and transmit at the same time, but I am not sure.

here is the code

#include <Conceptinetics.h>

#define DMX_MASTER_CHANNELS   11 
#define DMX_SLAVE_CHANNELS    11
#define RXEN_PIN              2

DMX_Master  dmx_master ( DMX_MASTER_CHANNELS, RXEN_PIN );
DMX_Slave   dmx_slave ( DMX_SLAVE_CHANNELS );


void setup() {             
  dmx_master.enable ();  
  dmx_master.setChannelRange ( 1, 25, 127 );
  dmx_slave.enable ();  
  dmx_slave.setStartAddress (1);
}


void loop() {


}

Well from an electronics point of view, DMX IN or OUT consist only of a few parts. A transceiver and a few resistors. I have always whipped up things myself, using experimentation board and a soldering iron. Transceivers are available in DIP-8 package as well,

No but there probably are shield available, though i won't be able to tell you where to look. I am willing to have a look at whatever you may find to see if it may do the trick.

Eh... no, this almost for sure won't work. First of all the slave and the master share a buffer, and the slave and the master share the UART. You would need to

  • enable the slave
  • read the buffer into your own variable
  • disable the slave
  • enable the master
  • send the values in the order you want them
  • disable the master
  • and back to the top

Like that it 'might' work, though i think i may have tried such a thing in the past, and i didn't find anything like that in my sketchbook anywhere.

Well regardless the issue with the shield remains. You can verify with a DMM that pins 2 & 3 on the XLR in & out connectors are connected, and so you should not connect it to something that is transmitting when you are transmitting from the shield as well or you may damage things,

ey!

thank you so much for all your input.

I will be considering all of these issues for the future. Right now I am not in a rush anymore, as the show last friday was already sorted out. I will anyway have to see how I do this, but I am not in a rush anymore. I am very thankful for having received your messages and support @Deva_Rishi !!

I wrote also on friday the person who created the conceptinetics shield, and he wrote back:

"You need two dmx shields , you could use one with this library for receiving the dmx input and then use something like simple dmx to send the output to the second dmx shield.

The latency could be kept very low this way but it might need some fiddling to make the two libraries work together."

That is it for now...

I would just use 2 transceivers.

I am confident that my code is better.

They will work together more or less Ok, but DMX Simple is a bit-banged method, which disables interrupts i think, which is something Conceptinetics relies on.