Arduino DMX-512 troubleshoot (RS-485)

Hi !
I built an Arduino DMX transmitter shield (Arduino Playground - DMX) with a SN75176B and loaded the code from Arduino Playground - Examples to the arduino.
But I get mixed results: When I test the DMX signal with a battery operated MicroTech DMX tester, the signal is good, I can monitor every channel and the refresh rate is around 25Hz.
But if I connect the Arduino DMX output to any real DMX slave like Lightwave LX lamps, the lamp either doesn't light at all, or lights up for a few seconds then starts to blink very fast, and then shuts off.

I tried adding resistors to the DMX pins like in the Enttec Open DMX schematic, I tried fiddling with he timing of the arduino code. I tried a different 75176 chip and I'm not sure what to try next...

Do you have any idea of what I'm doing wrong? I wish I had an oscilloscope right now.
Thanks a lot

hej,

since your dmx tester works pretty well, i would askpact that there is some thing wrong with the wirreing or the slave.

last week i was testing the code with arduino 006 and 007 on a luzifer dimmer pack, i just had the time to do a fast test but i seems to work pretty well,
At least i tested all code examples from the arduino page with with arduino 005 and a couple of different slaves.

did you testet the lightwave LX with some other dmx master device?
did you also have some other dmx slaves to test the code?
since you have so a nice equpment i guess you know and checkt the wirring a couple of times.

ha det bra
tomek

p.s. maybe you can discrib your problem and your slave device (i didn't found in the internet) a little bit more

Hi Tomek,
I recently tested the Arduino DMX with a Lanbox and it was working fine. The Lanbox was receiving perfectly on every channel. And the Lightwave LX (http://www.illumivision.com/products/?product_ID=5) works perfectly with the microTechDMX and the Lanbox, so why not with the Arduino? It just seems illogical.

I found the major problem: the arduino delayMicroseconds() is imprecise as noticed by Tomek Ness but some DMX equipement are more tolerant to imprecise timing than others. So i had to modify Tomek Ness's code:

...
int theDelay = 1;
// DMX starts with a start-bit that must always be zero
_SFR_BYTE(_SFR_IO8(portNumber)) &= ~_BV(pinNumber);
//we need a delay of 4us (then one bit is transfered)
// at the arduino just the delay for 1us is precise every thing between 2 and 12 is imprecise
// to get excatly 4us we have do delay 1us 4 times
delayMicroseconds(theDelay);
delayMicroseconds(theDelay);
delayMicroseconds(theDelay);
delayMicroseconds(theDelay);

to:
int theDelay = 1;
// DMX starts with a start-bit that must always be zero
_SFR_BYTE(_SFR_IO8(portNumber)) &= ~_BV(pinNumber);
//we need a delay of 4us (then one bit is transfert)
// at the arduino just the delay for 1us is precise every thing between 2 and 12 is imprecise
// to get excatly 4us we have do delay 1us 4 times
delayMicroseconds(theDelay);
delayMicroseconds(theDelay);
delayMicroseconds(theDelay);

for (wasteTime =0; wasteTime <2; wasteTime++) {
}

so that the start bit is even more exactly 4us.

Now it works almost perfectly, altough one strange problem remains: when I send low values it's perfect but high values (near 255) makes the light flicker. Another timing issue?

mhhh,

did you checked this with a oscilloscope?

i was asspecting i just have to do this with the bits which contains the value information (data-bits), because they have a if/else statement which need some time.

but thanks a lot, that you fixed the code, i will change the code on the playground a.s.a.p.

I was asppecting that a slave like the lightwave LX, who seems do be made for longtime, outdoor applications, should work a little bit better with not so clean singals...

for your problems with high values:

maybe you should add a delay for the stop- and relis-bit which will be the mark between bytes. (this break is have to be between 8 us and 1 sec). we didn't set a delay for this both bits because normaly operation we do between sending different byte takes more then 8 us. maybe it doesn't in your code, or maybe you do other operations which take more then 1 sek. ???

by the way: if you creat some nice funktions, objekts, installations etc. with dmx and arduino, feel free to add a new topic in the dmx tutorial or palyground in generall, i think it would be a great help for people if you would show your work at the playground. it is such a anoying shit with this code so it can be nice to see some nice projekts to motivate other people.

ha det bra
tomek

mmhhh again,

there is still a question left.

why is the "for loop" for the start bit shorter then the "for loop" for the data-bits (bit that carry the value).
The data-bit are having a if/else statment which takes some time the start bit is having nothing ....

I can not check this, because i don't have a oscilloscope ( and actually i don't know how to use it), but did you checkt the hole code on timeing issues ?

if not could some one do it?

david and me did it ones for the arduino 003 code but since arduino004 the microseconds delay changed a little bit, and i fixed the code with my well proved "try and error" skills. i testet the code on different slave but we know it is not perfekt jet.

thanks
tomek

One thing I've noticed working on digitalWrite() is that the code you are using to set the pin can be much more than the one instruction you might expect. For instance, if "pinNumber" and "portNumber" are variables in your code then _SFR_BYTE(_SFR_IO8(portNumber)) &= ~_BV(pinNumber); takes 26 clock cycles, slightly more than 1.5 microseconds.

I just documented an oscilloscope-free way of measuring small time intervals to the software troubleshooting topic: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1175115259

Salut a tous,
I didn't check with an oscilloscope, but I might have access to one soon. I just did the trial and error method until the lights came up.
Thanks Jims for the timing code trick. I'll try it out.

According to the timing code trick (Great tool by the way!)

delayMicroseconds(theDelay);
delayMicroseconds(theDelay);
delayMicroseconds(theDelay);
for (wasteTime =0; wasteTime <2; wasteTime++) {}

takes 56 clocks

So I did some tests for individual lines:

delayMicroseconds(1); takes 15 clocks

for (wasteTime =0; wasteTime <2; wasteTime++) {} oscillates between 9 and 10 clocks
but then 15*3+(9 or 10) = 54 or 55, which is not exactly the 56 clocks measured above

maybe this oscillation can cause some flickering combined with other imprecise timing? :-/

I also got it working with:

delayMicroseconds(theDelay);
delayMicroseconds(theDelay);
delayMicroseconds(theDelay);
for (wasteTime =0; wasteTime <3; wasteTime++) {}

which takes 61 clock cycles.

I slowed down the transmission so I can check what happens during the light flickering on the Lightwave, whose output I monitor. When I send a value of 3 on all channels, I get 3 on most channels but some 7 also. Same thing for value 4 (I get 4s and 12s), etc...The biggest flickers happens on multiples of 16
So if we change the decimals in binary, we can see that some channels get an extra high bit and that is what causes the flickering. Now where does these extra ones come from?

I finally got it working perfectly. Thank you guys!
Here is the modified code:

void shiftDmxOut(int pin, int theByte){

int theDelay = 1;
int wasteTime = 0;
int count = 0; //simple counter
int portNumber = port_to_output[digital_pin_to_port[pin].port];
int pinNumber = digital_pin_to_port[pin].bit;

// disable interrupts, otherwise the timer 0 overflow interrupt that
// tracks milliseconds will make us delay longer than we want.
cli();

// the first thing we do is to write te pin to high
// it will be the mark between bytes. It may be also
// high from before
_SFR_BYTE(_SFR_IO8(portNumber)) |= _BV(pinNumber);
//delayMicroseconds(4); //changed from 10 microseconds

// DMX starts with a start-bit that must always be zero
_SFR_BYTE(_SFR_IO8(portNumber)) &= ~_BV(pinNumber);
//we need a delay of 4us (then one bit is transfert)
// at the arduino just the delay for 1us is precise every thing between 2 and 12 is imprecise
// to get excatly 4us we have do delay 1us 4 times
delayMicroseconds(1);
delayMicroseconds(1);
delayMicroseconds(1);

for (wasteTime =0; wasteTime <2; wasteTime++) {}

for (count = 0; count < 8; count++) {

if (theByte & 01) {
_SFR_BYTE(_SFR_IO8(portNumber)) |= _BV(pinNumber);
}
else {
_SFR_BYTE(_SFR_IO8(portNumber)) &= ~_BV(pinNumber);
}
delayMicroseconds(1);
delayMicroseconds(1);
delayMicroseconds(1);
// to write every bit exactly 4 microseconds, we have to waste some time here.
//thats why we are doing some assembly nops
asm(
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
);
theByte>>=1; //bit shifting
}
// the last thing we do is to write the pin to high
// it will be the mark between bytes. (this break has to be between 8 us and 1 sec)
_SFR_BYTE(_SFR_IO8(portNumber)) |= _BV(pinNumber);
delayMicroseconds(8);

// reenable interrupts.
sei();
}