DMX512 Streaming Recorder & RDM Interface – A Concept

This USB device works with one DMX universe. A DMX universe is 512 channels of 256 levels. The device also has a slot for a memory card. Maximum memory card size is 32GB.

The device also works as a streaming recorder. When show is running you can simultaneously save it to memory card and output to DMX512 port. If USB connection is lost during play it rewinds automatically and starts from beginning of saved show.

With 2GB memory card maximum recording time is 4 days! Record is simple series of CSV text files on FAT file system. Starting from first subdirectory with 1.csv and so on. Each subdirectory is separate show.

Changing operating mode and choosing between saved shows can be done with onboard display and button. Display shows simple to understand symbols for recording and playback functions and numbers for choosing between memory slots. By pressing button shortly it blinks current symbol and it is possible to browse through functions. Long press chooses that function and it’s symbol stops blinking.

The device also works as a RDM interface. With compatible software on computer it allows control and monitor RDM fixtures remotely. Currently on Linux there is no any software available.

AVR Program

The device uses AtMega328PB-AUR microcontroller with 16MHz crystal. It includes two hardware serial ports and two hardware SPI port. First serial port is USB interface and second serial port is DMX/RDM interface. Speed on both serial ports must be 250000 baud. First SPI port is used only for programming and second SPI port is used to communicate with memory card. Program is written with C++ language. Microcontroller is programmed using avr-gcc and avrdude. Program is released under GNU General Public License.

This program uses:

  • Enttec DMX USB Pro protocol to communicate with PC.
    API specification: https://www.enttec.com/products/controls/usb/2-universe-usb-computer-interface-dmx/
    Copyright (c) 2007 Enttec Pty/Ltd
  • Parts from DMXSerial and DMXSerial2 libraries.
    Copyright (c) 2011-2013 by Matthias Hertel, http://www.mathertel.de
    This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
  • Parts from SdFat and Sd2Card libraries.
    Copyright (c) 2009 by William Greiman
    GNU General Public License V3.
  • Parts from Arduino SD-library.
    Copyright (c) 2010 SparkFun Electronics
    GNU General Public License V3.
  • CRC-7 routine and CRC-7 table from
    https://github.com/signal11/m-stack/blob/master/storage/src/crc.c
    Copyright (c) 2013 Alan Ott
    Copyright (c) 2013 Signal 11 Software
    GNU Lesser General Public License V3.

AVR/Arduino RFID Reader

This simple reader is based on previous post circuit and code. LCD display and custom AVR/Arduino circuit is added. Tag number is displayed on screen when detected. Detecting distance is about 2-3cm. Working voltage is 4.5V. This is maximum voltage of LCD display.

Video: https://www.youtube.com/watch?v=PWo2UU3oikA

Modified code with LCD driving:

#include <LiquidCrystal.h>

uint8_t cparity;
uint8_t numbers[5];

LiquidCrystal lcd(4,2,5,6,8,9);

void setup() {
  //Serial.begin(115200);
  pinMode(11, OUTPUT); // PWM output
  pinMode(13, OUTPUT); // Status LED

  lcd.begin(8,2);
  lcd.print("RFID");
  lcd.setCursor(0,1);
  lcd.print("reader");

  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2  = 0;
  TCCR2A = 0b01000001;
  TCCR2B = 0b00001001;
  OCR2A  = 32; // 32=125kHz, 27=143kHz == (16000000/(2*1*143000))/2
}

void wait(uint8_t t){
  uint8_t counter = 0,last = 0,next;
  do {
    next = PINB & (1 << 3);
    if (next != last) counter++;
    last = next;
  } while (counter < t);
}

uint8_t readBit(uint8_t time1, uint8_t time2) {
  
  wait(time1);
  
  uint8_t counter = 0, last = 0, state1 = PIND & (1 << 7), state2;
  do {
    uint8_t next = PINB & (1 << 3);
    if (next != last) counter++;
    last = next;
    state2 = PIND & (1 << 7);
  } while (counter <= time2 && state1 == state2);
  
  if (state1 == state2) return 2;
  if (state2 == 0) return 0; else return 1;
}

int8_t read4Bits(uint8_t time1, uint8_t time2) {
  
  uint8_t number = 0, parity = 0;
  for (uint8_t i = 4; i > 0; i--) {
    uint8_t bit1 = readBit(time1, time2);
    if (bit1 == 2) return -1;
    number = (number << 1) + bit1;
    parity += bit1;
  }
  
  uint8_t bit1 = readBit(time1, time2);
  if (bit1 == 2 || (parity & 1) != bit1) return -1;
  cparity ^= number;
  return number;
}

uint8_t readCard() {
  loop_until_bit_is_clear(PIND, 7);
  loop_until_bit_is_set(PIND, 7);
  
  uint8_t counter = 0, last = 0, next;  
  do {
    next = PINB & (1 << 3);
    if (next != last) counter++;
    last = next;
  } while (bit_is_set(PIND, 7) && counter<0xFF);
  
  if (counter == 0xFF && bit_is_set(PIND, 7)) return 1;
  
  uint8_t halfbit = counter, offset = counter >> 1;  
  if (readBit(offset, halfbit) != 1) return 1;
  
  for (uint8_t i = 7; i > 0; i--)
    if (readBit(halfbit + offset, halfbit) != 1) return 1;
    
  cparity=0;
  for (uint8_t i = 0; i < 5; i++) {
    int8_t n1 = read4Bits(halfbit + offset, halfbit),
           n2 = read4Bits(halfbit + offset, halfbit);
    if (n1 < 0 || n2 < 0) return 1;
    numbers[i] = (n1 << 4) + n2;
  }
  
  uint8_t cp = 0;
  for (uint8_t i = 4; i > 0; i--) {
    uint8_t bit1 = readBit(halfbit + offset, halfbit);
    if (bit1 == 2) return 1;
    cp = (cp << 1) + bit1;
  }
  
  if (cparity != cp) return 1;
  if (readBit(halfbit + offset, halfbit) != 0) return 1;
  
  return 0;
}

void loop() {

  uint8_t result;
  do {
    result = readCard();
    PORTB ^= (1<<5); // LED drive
  } while (result != 0);

  lcd.clear();
  lcd.print("Raw data");
  lcd.setCursor(0,1);
  //Serial.print("Raw data: ");
  for (uint8_t i=0;i<5;i++) lcd.print(numbers[i],HEX); //Serial.print(numbers[i],HEX);
  //Serial.println();

  delay(1000);
  lcd.clear();
  lcd.print("Number");
  lcd.setCursor(0,1);

  //Serial.print("Card number: ");
  uint8_t numbersr[4];
  numbersr[0]=numbers[4];
  numbersr[1]=numbers[3];
  numbersr[2]=numbers[2];
  numbersr[3]=numbers[1];
  //Serial.print(*(uint32_t*)(&numbersr),DEC);
  //Serial.println();
  lcd.print(*(uint32_t*)(&numbersr),DEC);
  
  delay(1000);
}

Part list:

  • R1, R9, R10 – 1k resistor
  • R2 – 47k resistor
  • R3, R6, R7, R8 – 22k resistor
  • R4, R5 – 2k2 resistor
  • R11 – 680 resistor
  • R12 – 10k resistor trimmer
  • C1 – 4n7 capacitor
  • C2 – 2nF capacitor
  • C3, C4, C6, C9 – 100nF capacitor
  • C5 – 47pF capacitor
  • C7, C8 – 18pF capacitor
  • D1, D2, D3 – 1N4148 diode
  • D4 – Green LED diode
  • Y1 – 16MHz crystal
  • Q1 – 2N3904 transistor
  • Q2 – 2N3906 transistor
  • U1 – LM324 operational amplifier ic
  • IC1 – AtMega328P microcontroller ic

L1 is not normal component. Instead it is hand wound coil with inductance of 375┬ÁH. It can be physically any size or shape. Only important thing is inductance. Online calculator is good tool for this. Calculator asks permeability for air in this case. It is 1.

LCD connection:

  1. GND
  2. VCC
  3. V5 – (CONTR)
  4. RS – (D4)
  5. RW – (GND)
  6. E – (D2)
  7. DB0 – (NC = No Connection)
  8. DB1 – (NC)
  9. DB2 – (NC)
  10. DB3 – (NC)
  11. DB4 – (D5)
  12. DB5 – (D6)
  13. DB6 – (B0)
  14. DB7 – (B1)

Schematics: