Assembly timing woes! Anyone know DMX?
Hi all
I'm in the process of creating a DMX receiver using my propellor kit and I'm having a few problems!
First of all, a little background information. DMX is a communications protocol used in the entertainment industry to control lighting. It uses RS485 balanced transmission, at 250,000 bits per second. The DMX data is sent in 'packets' of upto 513 bytes. The first byte is the start code and is used to define what sort of data is being transmitted. Currently, only zero has been defined as a valid start code. The remaining bytes are used to define channel levels.
A DMX packet is made up of the following parts :
First of all there is the break. This is *at least* 22 consecutive low bits, but could be longer
Then we have the Mark After Break (MAB), which is *at least* 2 high bits, but again could be longer
After that, we have the data frames. There could be *upto* 513 of them (1 start code and 512 data frames), but there could also be less. Each frame starts with 1 low start bit, then 8 data bits, and finally 2 high stop bits. Between each frame there is what is known as the Mark Time Between Frames (MTBF, yes I know....). This can be anywhere from 0 to 1 second and is indicated by consecutive high bits.
The problem I am having is that I think my timing code is wrong. Heres part of my code :
Dmx_clock_step is set to 320 because I have the propellor running at 80Mhz and DMX is transmitted at 250,000 bps, so 80,000,000/250,000 = 320.
I have a little test program set up to display things like break size, MAB size, etc and I am getting what I think are very strange values. I get a consistent 780 bits in the break and 22 bits in the MAB. After that my code does not work and it will not read the rest of the packet correctly. It reads the start bit and 8 low bits of the start code, but does not get any valid stop bits. It continues to read the break and MAB though...
I am using an Analog Devices ADM3485E to interface to a Zero88 Linebacker which I am using to generate the DMX signals.
Many Thanks
Mark
I'm in the process of creating a DMX receiver using my propellor kit and I'm having a few problems!

First of all, a little background information. DMX is a communications protocol used in the entertainment industry to control lighting. It uses RS485 balanced transmission, at 250,000 bits per second. The DMX data is sent in 'packets' of upto 513 bytes. The first byte is the start code and is used to define what sort of data is being transmitted. Currently, only zero has been defined as a valid start code. The remaining bytes are used to define channel levels.
A DMX packet is made up of the following parts :
First of all there is the break. This is *at least* 22 consecutive low bits, but could be longer
Then we have the Mark After Break (MAB), which is *at least* 2 high bits, but again could be longer
After that, we have the data frames. There could be *upto* 513 of them (1 start code and 512 data frames), but there could also be less. Each frame starts with 1 low start bit, then 8 data bits, and finally 2 high stop bits. Between each frame there is what is known as the Mark Time Between Frames (MTBF, yes I know....). This can be anywhere from 0 to 1 second and is indicated by consecutive high bits.
The problem I am having is that I think my timing code is wrong. Heres part of my code :
DAT
'
'
' Assembly program
'
org
asm_entry mov asm_cnt,cnt ' prepare for WAITCNT loop
add asm_cnt,dmx_clock_step
:loop waitcnt asm_cnt,dmx_clock_step ' wait for next CNT value (timing is determinant after WAITCNT)
mov dmx_bit, ina ' Read input port A
Dmx_clock_step is set to 320 because I have the propellor running at 80Mhz and DMX is transmitted at 250,000 bps, so 80,000,000/250,000 = 320.
I have a little test program set up to display things like break size, MAB size, etc and I am getting what I think are very strange values. I get a consistent 780 bits in the break and 22 bits in the MAB. After that my code does not work and it will not read the rest of the packet correctly. It reads the start bit and 8 low bits of the start code, but does not get any valid stop bits. It continues to read the break and MAB though...
I am using an Analog Devices ADM3485E to interface to a Zero88 Linebacker which I am using to generate the DMX signals.
Many Thanks
Mark

Comments
I've done·DMX receivers in 8052, I used UART in mode 2, I think you must get a driver for UART at 11 bits.
One start bit, 8 data bits (LSB first), and 2 stop bits.
working·with the Propeller serial driver published here, you'll get that DMX reciever work fine and easy !!.
Best regards.
Alberto.
Bear in mind that although it might be looping at a given frequency you may need to syncronize it or something.
Graham
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Chip Gracey
Parallax, Inc.
DAT ' ' ' Assembly program ' org asm_entry mov asm_cnt,cnt ' prepare for WAITCNT loop add asm_cnt,dmx_clock_step :loop waitcnt asm_cnt,dmx_clock_step ' wait for next CNT value (timing is determinant after WAITCNT) mov dmx_bit, ina ' Read input port A cmp read_state,state_count_break wz ' Are we counting the break bits? if_nz jmp #:count_mab ' Jump forward if not... and dmx_bit, asm_pin_mask wz,nr ' Read the dmx pin. Set Z flag to indicate high or low bit if_z add low_bit_count,#1 ' If the bit is low, increment low_bit_count if_z jmp #:loop ' and jump back to the top cmp low_bit_count,#22 ' If the bit is high, have we had 22 or more low bits beforehand? if_z_or_nc mov hi_bit_count, #1 ' If we have, we now have a valid 22 bit break and the first MAB hi bit... if_z_or_nc mov read_state,state_count_mab ' ...so we can start counting the MAB bits if_z_or_nc jmp #:loop mov low_bit_count,#0 ' If not, reset low bit count... jmp #:loop ' ...and jump back to the top :count_mab cmp read_state,state_count_mab wz ' Are we counting the MAB? if_nz jmp #:read_byte ' Jump forward if not... and dmx_bit, asm_pin_mask wz,nr ' Read the dmx pin. Set Z flag to indicate high or low bit if_nz add hi_bit_count,#1 ' If we have a high bit, increment the high bit count if_nz jmp #:loop ' and jump back to the start cmp hi_bit_count, #2 ' If we have a low bit, have we had 2 or more high bits? if_nz_or_c mov low_bit_count, #1 ' If not, then DMX ERROR! MAB too small, so lets start again if_nz_or_c mov read_state,state_count_break if_nz_or_c jmp #:loop mov low_bit_count,#1 ' Valid MAB, and we've just had a low bit for the start bit mov dmx_byte,#0 ' Get ready to start reading a packet mov dmx_byte_no,#0 mov dmx_byte_bit_count,#0 mov read_state,state_read_byte jmp #:loop :read_byte cmp read_state,state_read_byte wz ' Are we reading a byte ? if_nz jmp #:count_stop ' Jump forward if not... shl dmx_byte,#1 ' Add the bit to the byte. Start by shifting it left one bit.. and dmx_bit, asm_pin_mask wz,nr ' Read the dmx pin. Set Z flag to indicate high or low bit if_nz add dmx_byte,#1 ' If we have a high bit, add it to the byte if_z add low_bit_count,#1 ' If the bit is low, increment the low bit count add dmx_byte_bit_count,#1 cmp dmx_byte_bit_count,#8 wz if_z mov read_state,state_count_stop ' If we've read 8 bits, lets count the stop bits if_z mov stop_bit_count,#0 jmp #:loop :count_stop cmp read_state,state_count_stop wz ' Are we counting the stop bits? if_nz jmp #:catch_start ' Jump forwards if not... and dmx_bit, asm_pin_mask wz,nr ' Read the dmx pin. Set Z flag to indicate high or low bit if_nz jmp #:hi_stop_bit ' Jump forwards if we have a high stop bit cmp dmx_byte,#0 wz ' If we have a low bit here, it may be an error if_z cmp stop_bit_count,#0 wz ' If the byte we just read is 0, and we have no stop bits if_z mov low_bit_count,#10 ' then we have the start of a new break. Set low bit count to 10 ' (1 start bit + 8 low bits for the byte + the low bit we just read) if_nz mov low_bit_count, #1 ' Otherwise, we have a dmx error. Time to start again either way... mov read_state,state_count_break jmp #:loop :hi_stop_bit add stop_bit_count,#1 ' We have a high stop bit, so increment the counter cmp stop_bit_count,#2 wz ' If we don't have two high stop bits yet... if_nz jmp #:loop ' ...jump back to the start... ' ...but if we do, we have a valid byte cmp dmx_byte_no,#0 wz ' The first dmx byte is a special case. if_nz jmp #:valid_packet ' If we've gone past it, skip forwards cmp dmx_byte,#0 wz ' If we have the first byte, is it zero? if_nz mov low_bit_count,#0 ' If it isn't, then we aren't interested in this packet... if_nz mov read_state,state_count_break '...so lets start again if_nz jmp #:loop add dmx_byte_no,#1 ' If the first dmx byte is zero, then we are interested in this packet mov read_state,state_catch_start ' Prepare to catch the start bit of the next byte jmp #:loop :valid_packet cmp dmx_byte_no,dmx_byte_to_store wz ' Is this the byte we are interested in? if_z wrlong dmx_byte,result_ptr ' If it is, store it in main memory add dmx_byte_no,#1 ' Either way, increment the dmx byte counter mov read_state,state_catch_start ' and prepare to catch the start bit of the next byte cmp dmx_byte_no,full_packet wz ' Have we read 512 dmx bytes? if_z mov low_bit_count,#0 if_z mov read_state,state_count_break ' If we have, start reading a new packet jmp #:loop :catch_start and dmx_bit, asm_pin_mask wz,nr ' Read the dmx pin. Set Z flag to indicate high or low bit if_nz jmp #:loop ' High bit. The DMX standard allows for Mark Time Between Frames ' which is indicated by continuous high bits mov low_bit_count,#1 ' Valid stop bit, so set low bit counter... mov read_state,state_read_byte ' ...and the rest of the variables to prepare for the next byte mov dmx_byte,#0 mov dmx_byte_bit_count,#0 jmp #:loop ' ' ' Data ' ' At 80MHz the interval between succesive DMX bits is 320 clock ticks (80_000_000 / 250_000) ' since DMX is transmitted at 250khz dmx_clock_step long 320 asm_pin_mask long 0 ' Pin to read dmx from. dmx_bit long 0 ' Read the bit into here low_bit_count long 0 hi_bit_count long 0 read_state long state_count_break dmx_byte long 0 ' The byte we are currently reading dmx_byte_bit_count long 0 dmx_byte_no long 0 ' Which byte we are receving dmx_byte_to_store long 1 ' The byte we are interested in stop_bit_count long 0 asm_cnt long 0 ' Counter result_ptr long 0 ' Write the data to this pointer full_packet long 513 test_byte long 100 ' Read states state_count_break long 0 state_count_mab long 1 state_read_byte long 2 state_count_stop long 3 state_catch_start long 4Did you see the post I made about DMX? Overall I thought it was fairly simple to create the hardware and software. I have not been back to DMX since I created this post. It would be neat to add RDM support.
http://forums.parallax.com/forums/default.aspx?f=25&m=132052
I used the Propeller manual and example code to cook up my design. I tested it with a handheld DMX unit and a USB DMX unit I have. Things worked great!
Hope this helps,
-Tim
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Timothy D. Swieter
tdswieter.com
One little spark is all it takes for an idea to explode
No, I had not seen you DMX code. In fact I didn't even look for any as I had already designed the code on paper before deciding on which processor I was going to use. I must say though, your code is way more efficient than mine is. You've gone about doing it in a way I would never had thought of. Many thanks.
However, I think I have discovered why my code doesn't work. When I ran your demo using my hardware there were fluctuations in the dmx values. I can only assume that my dmx-ttl interface is at fault. I am using an Analog Devices ADM3485E. I chose it because it is designed to run on only 3.3v, therefore simplifying any circuit I might make. I have connected it directly to my Propellor, though I noticed that in Timothys design he has used a 1k resistor between his chip and his Propellor. His dmx-ttl chip runs on 5 volts though, so is that why he has used a resistor?