DMX Receiver on ATTiny85

I have successfully written a DMX receiver for an ATTiny85, it runs at 8mhz and basically bit-sniffs the data using inline code. I tried several methods, using pin change interrupts and timer0 interrupts, but soon realised the overhead of the interrupt control used many clock cycles which were desperately needed for the serial reception.

For those who dont know, DMX uses a serial protocol of 250kbs, with 1 start bit, 2 stop bits and no parity checking. there is a break signal which goes low for 88us before the data is transmitted, so its quite easy to spot when the data is coming.

I spent quite a while tweaking commands and bit manipulation to get the best out of the timings, some of which need to be well balanced at 4us (32 clock cycles) reading intervals. For the inline code I had to switch ALL interrupts off and I used NOP's to accurately place the sample points to read the 1-8-2 bits

As I have also spent a long time interfacing with nRF24L01's, my next task will be to hook the radio modules into the DMX receiver, boards are ready !!!

Hi,

can you post the source code please ? I have already tried to receive DMX signals for ATtiny85 with internal oscilator but it doesn't work :confused: The ATtiny with 4 the 4 pwm ports is perfect for a analog RGB stripe for me.

thanks in advance

Hi, here is the one I have done for an ATTiny13 (1k flash + 64 bytes ram), its written in under 1000 bytes and runs at 9.6mhz on internal oscillator

http://forum.arduino.cc/index.php?topic=278252.0

The ATTiny85 code I wrote was no where near as good as the ATTiny13 code, so I must really update the t85 code to match the t13 - thats a new project for me sometime

In the meantime, have a good read, any questions about the code, please ask :slight_smile:

I'm sure you can use the tiny85 internal PLL clock to run the chip at 16MHz. Would that help?

Yes that would help alot, I only ran it to 9.6 on the t13 because that is its max speed on internal (I think)

Thank you. I have tried with to compile your attiny13 version to my attiny85 but it doesn't work (with internal 8mhz and 16mhz).
With 8mhz all ws2812 lights are on. when i change the value over dmx its minimal lighter or lower.
When i compile with 16mhz then only 1 led (green) is for 1s on before go off.

I think the timings or the NOP's is not optimized for 8mhz or 16 mhz,
but my asm skills are only mov a b and back mov b a :wink:

any ideas?

sorry for my bad english :confused:

Im afraid the code really IS optimised for the 9.6mhz atTiny13

for example, at 9.6mhz, each clock cycle is approximately 100ns
for DMX512 running at 250kbps, each bit will arrive every 4us
Therefore the micro is processing & delaying for each bit 40 clock cycles (ish)

Changing the crystal/resonator frequency will dramatically change these timings
You will miss the incoming DMX, either not get it at all or get ALL the wrong data

When processing the WS2812 the asm I have written should still work with 16mhz, or it may be a bit fast. The WS2812 should be driven with ~800khz signal with a delay at the end to signify 'latch' or 'load' the data into the 'lights'

I have written the ASM for the WS2812 to run as fast as possible, which was needed for 9.6mhz

Compiling code written for processor A may not work when compiled for processor B for many reasons

Why not start with just using the WS2812 assembly code and some numbers in the data array like this...

#define DIGITAL_PIN   (2)         // Digital port number
#define PORT          (PORTB)     // Digital pin's port
#define PORT_PIN      (PORTB2)    // Digital pin's bit position
#define DMX_PIN       (PORTB4)
#define NUM_CHANS     (4) // one channel more than required

uint8_t dmxData[NUM_CHANS];  

void setup(void) {
}

void loop(void) {
  cli();
  dmxData[1] = 128;
  dmxData[2] = 192;
  dmxData[3] = 255;

  for (volatile uint8_t y=1; y<NUM_CHANS; y++) {
      asm volatile(
          "ldi  %3, 8\n\t"      // reset number of bits
        "nextbit:\n\t"          // label                       
          "sbi  %0, %1\n\t"     // SET OUTPUT HIGH
          "sbrs %4, 7\n\t"      // Skip output low if HiBit in value is set  
          "cbi %0, %1\n\t"      // SET OUTPUT LOW, early for a low
          "sbrc %4, 7\n\t"      // Skip output low if HiBit in value is clear  
          "cbi %0, %1\n\t"      // SET OUTPUT LOW, late for a high
          "rol  %4\n\t"         // shift value left to get to next bit
          "dec  %3\n\t"         // decrement nBits
          "brne nextbit\n\t"    // branch if bits not finished
          ::
          // Input operands         Operand Id (w/ constraint)
          "I" (_SFR_IO_ADDR(PORT)), // %0
          "I" (PORT_PIN),           // %1
          "e" (&PORT),              // %a2
          "r" (8),                  // %3
          "r" (dmxData[y])          // %4
        ); // asm
    } // y loop
  delay(10); // 10ms delay
}

I am not that good at ASM either, I just seem to muddle through and trying to learn as I go :slight_smile:

Hi, did you use an RS485 decoding IC like the MAX488 for this project or do you read the raw RS485 data from the dmx line and process it in the attiny?
Thanks in advance :slight_smile:

I used an SN76175 chip (similar to MAX485), it doesnt decode it just converts data on a differential pair to a single line to go into the micro :slight_smile: