Email: Password: Remember Me | Create Account (Free)

Back to Subject List

Old thread has been locked -- no new posts accepted in this thread
???
11/23/06 21:58
Read: times


 
Msg Score: +1
 +1 Good Answer/Helpful
#128469 - DMX
Responding to: ???'s previous message
DMX is a strange protocol - it was adapted from the original AMX192 protocol which was like a video signal, long pulse frame, short pulse channel then analog level. Anyway, DMX frames start with a break signal which is a '0' bit for longer than 1 character time. The DMX spec outlines how wide this break signal should be, my recollection is 88uS but this was from the original spec when I wrote my code back in 1990! A normal character has a start bit,8 data bits and a stop bit - this stop bit is a '1' (also termed an idle). In the case of a break, we get a start bit, 8 data bits of '0' and the stop bit is still '0' - in this instance the stop bit appears in the uart bit RB8. If this bit is '0', it is most likely a break, if it is '1' it is a character.

The basic format of a DMX frame is:

[BREAK] [0x00 for start code] [channel level]......up to 512 channel levels

I just dug up my old code for a demux unit:
;
;
;	CODE IS FOR INTEL 80C31 CPU @16MHZ
;
;	PORT DEFINITIONS../=ACTIVE LOW
;
;	P1.0		/BCD SWITCH BIT0,MUX ADDRESS 0
;	P1.1		/BCD SWITCH BIT1,MUX ADDRESS 1
;	P1.2		/BCD SWITCH BIT2,MUX ADDRESS 2
;	P1.3		/BCD SWITCH BIT3,MUX ADDRESS 3
;	P1.4		/ENABLE 100'S BCD SWITCH
;	P1.5		/ENABLE 10'S BCD SWITCH
;	P1.6		/ENABLE 1'S BCD SWITCH
;	P1.7		/ENABLE SAMPLE & HOLD
;
;	P3.0		RXD. DMX INPUT
;	P3.1		TXD. NOT USED YET
;	P3.2		/AMX SYNC IN
;	P3.3		/START CONVERSION ON ADC
;	P3.4		MUX OK LED (RED)
;	P3.5		AMX RECEIVED,/DMX RECEIVED
;	P3.6		/RD
;	P3.7		/WR
;
ADA	EQU	0000H	;analog to digital to analog converter AD7569
MEM	EQU	8000H	;optional external ram-not used for this code.
;
;	internal ram allocation..
;
CHANNEL	EQU	40H
CHAN1	EQU	CHANNEL+0	;channel storage
CHAN2	EQU	CHANNEL+1
CHAN3	EQU	CHANNEL+2
CHAN4	EQU	CHANNEL+3
CHAN5	EQU	CHANNEL+4
CHAN6	EQU	CHANNEL+5
CHAN7	EQU	CHANNEL+6
CHAN8	EQU	CHANNEL+7
CHAN9	EQU	CHANNEL+8
CHAN10	EQU	CHANNEL+9
CHAN11	EQU	CHANNEL+10
CHAN12	EQU	CHANNEL+11
LODIM	EQU	050H		;base channel number storage
HIDIM	EQU	051H
TIMEOUT	EQU	052H		;count for no mux timeout
;
COMSTAT	EQU	20H		;incoming dmx&amx status
AD	EQU	COMSTAT.0	;1 means AMX is being received
SBRK	EQU	COMSTAT.1	;1 means we got a break
STRT	EQU	COMSTAT.2	;1 means we have got a valid start code
MUXOK	EQU	COMSTAT.3	;1 means mux is ok
;
;	others..
;
PCON	EQU	087H		;this assembler doesn't know about PCON
TOUT	EQU	60		;time out for no mux *50ms @16mhz
;TOUT	EQU	30		;time out for no mux *100mS@8 mhz
TOUT1	EQU	10		;timeout for mux input select *50mS @ 16mhz
;
	ORG	0000H
	LJMP	START		;GOTO START OF CODE
;
;	INTERUPT VECTORS
;
	ORG	0003H
IRQ0	LJMP	AMX		;amx receive routine
	ORG	000BH
;
;	if timer0 rolls over, we have lost mux input
;

TIM0	LJMP	TIME
	ORG	0013H
IRQ1				;not used
	ORG	001BH
TIM1				;not used
	ORG	0023H
	LJMP	DMX		;goto dmx routine
;
;	Timer zero has timed out as we have had no mux.
;	Decrement timer count and reload the timer
;	If the timer count gets to zero,then we take action
;
TIME	DJNZ	TIMEOUT,TIME1		;dec timeout count
;	timeout=0..
	CLR	TCON.4			;stop timer0
	CLR	P3.4			;turn off mux ok led
	CLR	SBRK			;reset comms system
	CLR	STRT			;clear start status
	CLR	MUXOK			;mux is definitely not ok
	CPL	AD			;goto alternate input
	JB	AD,GAMX			;setup amx for input
;
;	setup dmx for input
;
	MOV	TIMEOUT,#TOUT1		;reload select timeout
	CLR	P3.5			;turn off AMX led
	MOV	IE,#092H		;start DMX
	SJMP	TIME1
;
;	setup amx for input
;
GAMX	MOV	TIMEOUT,#TOUT1		;reload select timeout
	SETB	P3.5			;turn on AMX led
	MOV	IE,#83H			;start AMX
	SJMP	TIME1
;
;
TEX	RETI
TIME1	CLR	TCON.4			;stop timer
	MOV	TL0,#00
	MOV	TH0,#00			;reload timer0
	SETB	TCON.4			;start timer0
	RETI
;
;	the show starts here...
;
START	MOV	IE,#00		;turn off all ints
	MOV	R0,#CHANNEL	;setup channel pointer
	MOV	P1,#0FFH	;disable s/h
	ACALL	READSW		;read switches,set dimmer base number
	CLR	P3.4		;turn off MUX-OK led
	CLR	P3.5		;turn off AMX/DMX led
	MOV	TMOD,#31H	;setup timer0
	MOV	TCON,#01	;stop timers,select edge detect for int0
	MOV	IP,#10H		;set serial int to higher priority
	MOV	SCON,#90H	;set serial port to mode 2
;	MOV	PCON,#80H	;set to divide by clk by 32,baud rate=250kbs
	MOV	PCON,#00H	;set to divide clk by 64,baud rate=250kbs @16mhz
	MOV	DPTR,#ADA	;DPTR->analog converter
;
;	setup interupts,clear channel levels and go!
;
	MOV	IE,#00		;stop everything!!
	MOV	TIMEOUT,#TOUT1	;load select timeout
	CLR	TCON.4		;stop timer0
	MOV	TH0,#00
	MOV	TL0,#00		;reload timer0
	SETB	TCON.4		;start timer0
	MOV	COMSTAT,#00	;clear comms status
	MOV	A,#00		;clear Acc
	MOV	R0,#CHANNEL	;clear channel storage
CCHAN	MOV	@R0,A		;clear channel
	INC	R0		;goto next
	CJNE	R0,#(CHAN12+1),CCHAN	;check for last channel
	MOV	IE,#82H		;enable timer0 ints
;
;
;	we should be receiving DMX or AMX by this point..
;	even if we're not,output the channel levels to the sample & holds
;
GO	MOV	R7,#250		;do 250 outputs till we update
OUTCHAN	MOV	R1,#CHANNEL	;R1->channels
CLOOP	MOV	A,@R1		;get channel level
	MOVX	@DPTR,A		;output it to the dac
	MOV	A,R1		;channel into a
	ANL	A,#0FH		;only the lower 4 bits for mux address
	ORL	A,#0F0H		;set switch enable bits
	MOV	P1,A		;output mux address
	CLR	P1.7		;enable s/h
	NOP			;allow capacitor to charge to channel level
	NOP
	SETB	P1.7		;disable s/h
    	INC	R1		;next channel
	CJNE	R1,#(CHAN12+1),CLOOP	;see if its the last channel
	DJNZ	R7,OUTCHAN	;output 100 times then update dimmer base etc.
;
;	update dimmer base number & see if mux is still ok
;
	LCALL	READSW		;read dimmer base number from switches
	JB	MUXOK,GO	;keep on outputting channels if muxok
;
;	NO MUX SIGNAL RECEIVED
;
	MOV	A,#00		;clear A
	MOV	R0,#CHANNEL	;R0->CHANNELS
CCLOOP	MOV	@R0,A		;clear channel level
	INC	R0		;next channel
	CJNE	R0,#(CHAN12+1),CCLOOP		;until all channels done
	SJMP	GO		;look for input again
;
;	read dimmer base number switches and store them into lodim &hidim
;	we also kick the watchdog whilst doing this
;
READSW	MOV	R6,#00		;R6 has dimmer base hi
	MOV	R7,#00		;R7 has dimmer base low
;
;	GET 100'S SWITCH SETTING
;
	MOV	P1,#0FFH	;set bits high(input),& disable s/h
	CLR	P1.4		;enable 100's switch
	MOV	A,P1		;read switch setting
	CPL	A		;invert it (hardware thing)
	ANL	A,#0FH		;we only want low 4 bits
	MOV	B,#100		;multiply it by 100
	MUL	AB		;result in b(hi) A(low)
	ADD	A,R7		;add into base number low
	MOV	R7,A		;save result into base num low
	MOV	A,B		:get msb of multiply into a
	ADDC	A,R6		;add into base number hi
	MOV	R6,A		;save into dimmer base number
	SETB	P1.4		;turn off 100s switch
;
;	GET 10'S SWITCH SETTING
;
	CLR	P1.5		;enable 10's switch
	MOV	A,P1		;read switch
	CPL	A		;invert it
	ANL	A,#0FH		;mask for low 4 bits
	MOV	B,#10		;multiply by 10
	MUL	AB		;result in b(hi),A(low)
	ADD	A,R7		;add to dimmer base number
	MOV	R7,A		;save result into dimmer base number
	CLR	A		;A=0. we never get a result above 90 dec
	ADDC	A,R6		;add in the carry (if any)
	MOV	R6,A		;save into dimmer base number
	SETB	P1.5		;turn off 10's switch
;
;	GET 1'S SWITCH SETTING
;
	CLR	P1.6		;turn on units switch
	MOV	A,P1		;read switch
	CPL	A		;turn it upside down
	ANL	A,#0FH		;lower nibble only
	ADD	A,R7		;add into dimmer base number
	MOV	R7,A		;save it
	MOV	A,#00		;add in carry (if any)
	ADDC	A,R6		;
	MOV	R6,A		;save it
;
;	MINUS 1 TO CORRECT THINGS
;
	CLR	C		;clear borrow(carry)
	MOV	A,R7		;get dimmber base low
	SUBB	A,#1		;minus 1
	MOV	R7,A		;save result
	MOV	A,R6		;get dimmber base hi
	SUBB	A,#00		;subtract borrow (if any)
	MOV	R6,A		;save it
;
;	UPDATE GLOBAL DIMMBER BASE NUMBER
;
	CLR	IE.7		;stop interupts for a tick
	MOV	LODIM,R7
	MOV	HIDIM,R6
	SETB	IE.7		;start interupts again...
	RET





;
;	dmx reception routine.
;

DMX	PUSH	0D0H		;save PSW
	CLR	SCON.0		;reset recv int
	CLR	SCON.1		;reset tx int
	MOV	R2,SBUF		;read receive date into A
	JNB	SCON.2,BRKORBAD	;IF RECV BIT8=0,EITHER A BREAK OR OVERRUN
;
;	received char must be good then..
;
	JB	SBRK,BROK	;jump if we've received a break
	POP	0D0H		;restore PSW
	RETI			;we haven't got a break yet,do nothing
;
BROK	JB	STRT,STOK	;jump if we've got a good start code
;
;	we haven't yet received a start code,check for byte=00
;
	CJNE	R2,#00,BADST	;jump if we got a bad start code
;
;	start code is good,set start flag
;
	SETB	STRT		;set start code ok flag
	POP	0D0H		;restore PSW
	RETI
;
;	start code was bad,go back to looking for a break
;
BADST	CLR	SBRK		;no break
	CLR	STRT		;just in case
	POP	0D0H		;restore PSW
	RETI
;
;	we've already got a break and a start code
;	figure out if we want this channel..
;
;	on break we load channel countdown with our dimmer base number
;	on each dimmer level received,we decrement this count
;	upon reaching zero,we then grab the next 12 channels
;	and put them into ram
;
STOK
	CJNE	R4,#00,CDEC	;SEE IF CHANNEL COUNTDOWN HI=0
	CJNE	R3,#00,CDEC	;see if channel countdown low=0
;
;	the countdown=0,time to grab the channels we want.
;
	CJNE	R0,#(CHAN12+1),GETCHAN	;compare channel count with last channel
;
;	we've got all the channels we want,so discard all others
;
	POP	0D0H		;restore PSW
	RETI
;
;	decrement the channel countdown
;
CDEC
	CJNE	R3,#00,COUNTHI		;R3=00?
	DEC	R3			;decrement count low
	CJNE	R4,#00,COUNTZ		;jump if count hi=0
	POP	0D0H			;restore PSW
	RETI				;if R4=00 return
COUNTZ
	DEC	R4
	POP	0D0H			;restore PSW
	RETI
;
COUNTHI	DEC	R3			;decrement count low
	POP	0D0H			;restore PSW
	RETI	
;
;	channel countdown=0 and we haven't got all our channels yet
;
GETCHAN	JC	GTCHAN1		;R0<=CHAN12
	POP	0D0H		;restore PSW
	RETI			;R0>CHAN12
;
GTCHAN1	PUSH	0E0H		;save accumulator
	MOV	A,R2		;get channel level into A
	MOV	@R0,A		;move received channel to ram
	INC	R0		;R0->next channel
	POP	0E0H		;restore accumulator
	POP	0D0H		;restore PSW
	RETI
;
;	now we process either data overrun or break
;	
		
BRKORBAD MOV	R5,#8		;number of loops =4@8mhz,=8 @16mhz
;	see if RxD changes within 30 us. If it does,there
;	was a data overrun error,else it must be a break
;
LOOP	JB	P3.0,OVER	;jump if RxD changes
	DJNZ	R5,LOOP		;try again until R5=0
;
;	must be a break,as RxD has been marking >88us
;
	CLR	STRT		;so that we look for a start code
	SETB	SBRK		;we got a break
	SETB	MUXOK
	SETB	P3.4		;Turn on MUX-OK led
	MOV	TIMEOUT,#TOUT	;reload timeout
	CLR	TCON.4		;stop timer 0
	MOV	TL0,#00
	MOV	TH0,#00		;reload timer0
	SETB	TCON.4		;start timer0
	MOV	R0,#CHAN1	;reset channel pointer
	MOV	R4,HIDIM	;reload countdown
	MOV	R3,LODIM	;with dimmer base number
	POP	0D0H		;restore PSW
	RETI
;
;	data must have overrun
;
OVER	CLR	STRT		;go back to looking for a
	CLR	SBRK		;break/start code
	POP	0D0H		;restore PSW
	RETI


;
;	AMX reception routine.
;

AMX	NOP			;delay 6us @ 16mhz
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP			;delay 6 us @ 16mhz
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP			;delay 6us @ 16mhz
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP			;delay 6 us @ 16mhz
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	JB	P3.2,GETAMX	;if sync=1 must be a channel sync
;
;	sync must still be low, frame sync it is
;
	CLR	STRT		;so that we look for a start code
	SETB	SBRK		;we got a break(frame sync)
	SETB	P3.4		;Turn on MUX-OK led
	SETB	MUXOK		;MUX is ok
	MOV	TIMEOUT,#TOUT	;reload timeout
	CLR	TCON.4		;stop timer 0
	MOV	TL0,#00
	MOV	TH0,#00		;reload timer0
	SETB	TCON.4		;start timer0
	MOV	R0,#CHAN1	;reset channel pointer
	MOV	R4,HIDIM	;reload countdown
	MOV	R3,LODIM	;with dimmer base number
	RETI
;
;	we got a channel sync
;
GETAMX	CLR	P3.3		;start analog->digital conversion
	SETB	P3.3
	NOP			;wait 3us approx
	NOP
	NOP
	NOP
	PUSH	0D0H		;push psw
	PUSH	0E0H		;push acc
	MOVX	A,@DPTR		;read adc value
	JB	SBRK,ASTOK	;we've already got the frame sync
;	discard level until we've got frame sync
	POP	0E0H		;restore accumulator
	POP	0D0H		;restore psw
	RETI
;
;	on break we load channel countdown with our dimmer base number
;	on each dimmer level received,we decrement this count
;	upon reaching zero,we then grab the next 12 channels
;	and put them into ram
;
ASTOK	CJNE	R4,#00,ACDEC	;SEE IF CHANNEL COUNTDOWN HI=0
	CJNE	R3,#00,ACDEC	;see if channel countdown low=0
;
;	the countdown=0,time to grab the channels we want.
;
	CJNE	R0,#(CHAN12+1),AGETCHAN	;compare channel count with last channel
;
;	we've got all the channels we want,so discard all others
;
	POP	0E0H		;restore accumulator
	POP	0D0H		;restore psw
	RETI
;
;	decrement the channel countdown
;
ACDEC	CJNE	R3,#00,ACOUNTHI	;R3=00?
	DEC	R3		;decrement count low
	CJNE	R4,#00,ACOUNTZ	;jump if count hi=0
	POP	0E0H		;restore accumulator
	POP	0D0H		;restore PSW
	RETI
ACOUNTZ	DEC	R4
	POP	0E0H		;restore accumulator
	POP	0D0H		;restore psw
	RETI
;
ACOUNTHI	DEC	R3	;decrement count low
	POP	0E0H		;restore accumulator
	POP	0D0H		;restore psw
	RETI

;	channel countdown=0 and we haven't got all our channels yet
;
AGETCHAN	JC	AGTCHAN1 	;R0<=CHAN12
	POP	0E0H		;R0>CHAN12
	POP	0D0H		;restore psw
	RETI
AGTCHAN1	MOV	@R0,A	;move received channel to ram
	INC	R0		;R0->next channel
	POP	0E0H		;restore accumulator
	POP	0D0H		;restore psw
	RETI
	END




List of 5 messages in thread
TopicAuthorDate
Kathy Quinlan's DMX            01/01/70 00:00      
   I guess...            01/01/70 00:00      
   Any help?            01/01/70 00:00      
   Any help?            01/01/70 00:00      
   DMX            01/01/70 00:00      

Back to Subject List