DMX512 Reception + 3 * 8-Bit PWM Outputs


Closed Thread
Results 1 to 6 of 6
  1. #1
    Join Date
    Nov 2004
    Posts
    61

    Default DMX512 Reception + 3 * 8-Bit PWM Outputs

    Code is written for a 14-pin 16F688 using the internal 8 MHz oscillator.

    It receives DMX-512 and outputs 3 channels of PWM at a nearly 100 Hz refresh rate. Resolution is 8 bits minus 1, or 255 discrete states. PWM data comes from three consecutive DMX channels, and the start address can be set at compile time.

    No crystal required! The internal PLL module in the EUSART oversamples the incoming serial data string at a high enough rate that the reception is very, very stable.

    I tried like crazy to make this all work in PicBasic Pro, but even using assembly interrupts the timing wasn't working out. The PWM routine needs a 40 uS tick and it was just taking too long (even with an assembly interrupt routine) to get things done smoothly.

    Nice thing is that it compiles to just a few hundred words. The chip has 4K of space, so there's lots of room for expansion.

    This is my first-ever 100% assembly program, so there may be some rough edges in the code.

    Source code, schematics & more can be found here:

    http://www.response-box.com/rgblights

    Comments and suggestions are always appreciated.

    - JEC

  2. #2
    Join Date
    Aug 2007
    Posts
    7


    Did you find this post helpful? Yes | No

    Smile DMX512 to pwm

    JEC,
    Do you sell these pcbs and devices?
    Ray

  3. #3
    Join Date
    Nov 2004
    Posts
    61


    Did you find this post helpful? Yes | No

    Default

    Hi Ray,

    We're working on a group buy for the pixels through an overseas fabricator.

    I've ordered samples and they should be here shortly.

    Pricing isn't final yet but there's a very good chance we'll be under $10 per pixel, assembled and tested. You provide a stable +12v supply and valid DMX.

    The discussion about the group buy is over here:

    http://www.christmasinshirley.com/fo...opic.php?t=563

    John

  4. #4
    Join Date
    Nov 2004
    Posts
    61


    Did you find this post helpful? Yes | No

    Default

    EDIT: Pixels are for sale now.

    www.response-box.com/rgblights

  5. #5
    Join Date
    Feb 2015
    Posts
    1


    Did you find this post helpful? Yes | No

    Default Re: DMX512 Reception + 3 * 8-Bit PWM Outputs

    hi,
    is it possible to still get to see the code for this project? link does not work.
    thanks

  6. #6
    Join Date
    Nov 2004
    Posts
    61


    Did you find this post helpful? Yes | No

    Default Re: DMX512 Reception + 3 * 8-Bit PWM Outputs

    Quote Originally Posted by picchip View Post
    hi,
    is it possible to still get to see the code for this project? link does not work.
    thanks
    Wow, it's been a long time since I wrote this. Sorry for the dead link. You might be interested in www.response-box.com/rgb these days.

    This code was written to compile under MPLAB 8.6 (?) or so. No idea how it will run under the new X complier, but it's probably fine.

    The code is pretty raw. Not a lot of error correction. But since I was controlling the DMX TX side as well, it was ok. My 25 copies have run flawlessly for six weeks every Christmas season since then. Back in 2006-2007 we shipped many hundreds of circuit boards with this code loaded inside, to say nothing of what people may have designed and programmed themselves. I expect there are thousands of copies floating around out there.


    Code:
    ; -------------------------------------------------------------
    ; JECPWM_3.asm											
    ; (c) 2007 John Chapman, Engineering Solutions Inc
    ; Inspired somewhat by Microchip's application notes
    ; for receiving DMX and generating software PWM.
    ; Note: The reference designs for these pixels are distributed 
    ; under a Creative Commons license Attribution-ShareAlike 2.5
    
    ; 
    ;
    ; 16F688 Chip Connections
    ;
    ; PORT		PIN		CONFIGURATION
    ; ==================================
    ; A0        13      PGM Header 
    ; A1        12      PGM Header 
    ; A2        11      N/C
    ; C0        10      Red Drive
    ; C1        9       Green Drive
    ; C2        8       Blue Drive
    ; C3        7       N/C
    ; C4        6       N/C
    ; C5        5       DMX512 RX
    ; MCLR      4       Vcc w/4.7K pullup
    ; OSC2      3       N/C
    ; OSC1      2       N/C
    ; GND       14		GND
    ; VCC       1		Vcc
    ;
    
    	list      p=16F688        ; list directive to define processor
    	#include <p16F688.inc>   ; REMOVE THE EXTRA SPACES BETWEEN < and > - processor specific variable definitions
    	errorlevel  -302          ; suppress message 302 from list file
    
    ; Here include Configuration settings
    
    ; OSC = INTOSCIO
    ; Watchdog = Disabled
    ; Power up Timer  = Disabled
    ; MCLR = Reset
    ; Brownout = Enabled, SBODEN disabled
    ; Switchover = Disabled
    ; Failsave = Disabled
    ; Code = As needed
    ; EEPROM = As needed
     	
    	CBLOCK 0x20
    
    	wsave	
    	ssave	
    	psave	
    	redval
     	greenval
    	blueval
    	pwmpins
    	rednew
    	greennew
    	bluenew
    	IntCount
    	dmxhighbyte
    	dmxlowbyte
    	skiphigh	
    	skiplow	
    	temp
    
    	ENDC
    
    	#define		BANK0	bcf		STATUS,RP0
    	#define		BANK1	bsf		STATUS,RP0
    
    	ORG 0x000				; Main Program
    
    	clrf PCLATH
    	goto start
    
    	ORG 0x004				; Interrupt handler goes here
    
    pwmdrive
     	movwf	wsave				; Store the usual bits when interrupting
     	swapf	STATUS, w
     	clrf	STATUS
     	movwf	ssave
     	movf	PCLATH, w
     	movwf	psave
    
    ; ------- Actual Interrupt Routine Here --------------------
    
     	movlw 	D'223'			; TMR0 will roll over every 40.0 uS
     	movwf 	TMR0			; which allows for 97.65 Hz PWM frequency
    					; Nice thing here is that even if we're receiving
    					; full-on DMX (44, 512-byte frames per second)
    					; the PWM routine can easily keep up.  So some 
    					; exciting effects should be possible.
    
    DecIntCount						
    	decfsz	IntCount,F		; Decrement IntCount register.  If it's zero, reset 
    	goto	redcheck		; the PWM routine.  Otherwise, check each PWM value
    
    PWMReset				; We've been through 256 cycles of PWM, so it's time
    	bcf	pwmpins,0		; to reset everything
    	bcf	pwmpins,1		; pwmpins is a byte variable.  Bytes are cleared
    	bcf	pwmpins,2		; here (turning off red, gren and blue drive pins)
    	movf	pwmpins,w		; and the entire byte is pushed out to PORTC.
    	movwf	PORTC
    	movlw	D'255'			; Reset the counter to allow 255 values per channel 
    	movwf	IntCount		; Also, since we're resetting, it's time to transfer
        	movf  	rednew,w		; the *new variables (which came from the DMX routine)
        	movwf 	redval			; to the working PWM variables.
        	movf  	greennew,w		; If the transfer takes place at any time *other* than
        	movwf 	greenval		; during a PWM reset, the LEDs flicker unflatteringly
        	movf  	bluenew,w		; We're guaranteed that new DMX data is made available
        	movwf	blueval			; to the PWM routine as soon as possible
        	goto	pwmexit			; Exit ISR
    
    ; Here we compare each of the duty cycles to the IntCount.  If the values
    ; match, the corresponding pin is driven high.  It's a bit counter-intuitive
    ; but it works.  Note that if a value of 255 is received, it won't work.  So 
    ; the DMX routine limits PWM values to [0 254].  Which is good enough.
    
    redcheck
    	movf	redval,w
    	subwf	IntCount,w
    	btfss	STATUS,Z	 	; Are they equal?
    	goto	greencheck		; Note that the *val variables are used only within
    	bsf	pwmpins,0		; the PWM routine.  The actual DMX data is stored	
    greencheck				; in the *new variables, and transferred to these
    	movf	greenval,w		; working variables only when the PWM rolls over
    	subwf	IntCount,w			         
    	btfss	STATUS,Z            	; If the values are equal, set the bit (which turns         
    	goto	bluecheck		; on the corresponding drive pin)
    	bsf	pwmpins,1
    
    bluecheck
    	movf	blueval,w			         
    	subwf	IntCount,w		
    	btfsc	STATUS,Z             
    	bsf	pwmpins,2	
    	movf	pwmpins,w		; move the pin variable out to PORTC
    	movwf	PORTC			; which will drive / clear the LEDs as needed
    
    pwmexit
     
     	BCF    INTCON,T0IF      	; Clear the TMR0 interrupt flag
     	movf	psave,w			; Restore whatever was happening prior
     	movwf	PCLATH			; to the interrupt and get back to
     	swapf	ssave,w			; gathering DMX data.
     	movwf	STATUS
     	swapf	wsave,f
     	swapf	wsave,w
     
     	retfie				; Back to gathering DMX data
    
    
    
    ; ---------- Main Program Starts Here ----------------------------
    
    start
    	
    	call	chipinit		; Initialize pins, oscillator, etc
    	call	pwminit			; Initialize TIMER0 and enable TMRO interrupts
    	call 	rxinit			; Set up the EUSART to receive DMX at 250,000 baud
    
    ; ---------- Set DMX Start Address Here -------------------------
    	movlw	D'0'			; Set the DMX Address here.  It's a 16 bit
    	movwf	dmxhighbyte		; number in two 8-bit bytes.  Highbyte can be
    	movlw	D'7'			; [0 2] and lowbyte can be [0 255].  Overall, then,
    	movwf	dmxlowbyte		; the range is from [0 512].
    ; ---------- End DMX Start Address Programming -------------------
    
    	BANK0
    
    dmxcapture
    
    	movf	dmxhighbyte,w		; Skipcounter is used to detmine how many
    	movwf	skiphigh		; received data bytes are skipped before the RGB
    	movf	dmxlowbyte,w		; data is collected.  Load skipcounter with
    	movwf	skiplow			; the DMX address from above...
    
    	movf  	skiplow,f		; ... then decrement it by one
      	btfsc	STATUS,Z		; so we know how many channels to ignore before the
       	decf  	skiphigh,f		; useful data arrives.  We'll see more of the 
      	decf  	skiplow,f		; skipcounter a bit farther down the page.
    
    waitbreak
    	btfsc	PIR1,RCIF		; Here we're waiting to see if a break occurs
    	movf	RCREG,w			; in the data signal.  Since we're *only*
    	btfss	RCSTA,FERR		; receiving DMX, anything which generates a 
    	goto	waitbreak		; framing error in the EUSART will count as a break.
    	movf	RCREG,w			; If a byte is received correctly, dump it and loop				
    					; back until we get the error we need
    					; without being able to synchronize to the break signal
    					; there's no way to extract valid DMX data
    waitforstart
    	btfss	PIR1,RCIF		; Now that a break signal is detected, 
    	goto 	waitforstart		; loop until a new byte is received *without*
    	btfsc	RCSTA,FERR		; a framing error.  If all is well AND the
    	goto 	waitforstart		; new byte is zero (which means the start code
    	movf	RCREG,w			; is also zero, it's okay to begin gethering channel
    					; data
    
    	; RIGHT NOW WE'RE NOT TESTING FOR A ZERO START CODE. THIS WILL BE CHANGED IN FUTURE
    	; VERSIONS OF THE CODE.  BUYER BEWARE!
    
    	movf	dmxhighbyte,1		; Here check to see if the highbyte is
    	btfss	STATUS,Z		; zero. If it is,check to see if the	
    	goto 	bytecapture		; lowbyte is 1.  If 1, grab the next three bytes
    	movf	dmxlowbyte,w		; which come through.  If <> 1, go to the routine
    	xorlw	D'1'			; which receives and discards bytes until the 
    	btfsc	STATUS,Z		; DMX address has been reached.
    	goto 	waitforred		
    
    bytecapture	
    
    	btfss	PIR1,RCIF		; If we're here, it's because the start address is
    	goto  	bytecapture		; greater than one. Hover until a byte is received.
    	movf	RCREG,w			; Then, capture & move to 'w'...	
    								
     	movf  	skiplow,f		; ...decrement the skip counter... 
      	btfsc	STATUS,Z	 	; (all sixteen bits of it)
       	decf  	skiphigh,f
      	decf  	skiplow,f
    					; ...and see if we've reached the start address.
    	movf	skiplow,1		; If the skip counter now equals zero, we know
    	btfss	STATUS,Z		; that we need to gather the next three bytes	
    	goto 	bytecapture		; and save them as RGB data.  If the counter is
    	movf	skiphigh,1		; still nonzero, loop back and do it again.
    	btfss	STATUS,Z
    	goto	bytecapture
    
    waitforred
    	btfss	PIR1,RCIF		; Wait until 'red' byte is received
    	goto 	waitforred		; once it arrives, store it in 'temp'
    	movf	RCREG,w			; and call the 'maxcheck'  routine.  Since the		
    	movwf	temp			; PWM code only works for values between [0 254]
    	call	maxcheck		; maxcheck will set levels of 0xFF to 0xFE
    	movwf	rednew			; then store them in the proper bit bucket.
    					; remember the the *new variables are converted
    					; to *val variables when the PWM routine resets 
    					; itself
    waitforgreen	
    	btfss	PIR1,RCIF		; process is repeated for green data
    	goto 	waitforgreen
    	movf	RCREG,w
    	movwf	temp
    	call	maxcheck
    	movwf	greennew
    
    waitforblue				; ...and for blue data
    	btfss	PIR1,RCIF		; It is assumed that there will be enough DMX
    	goto 	waitforblue		; channels available to capture three bytes
    	movf	RCREG,w			; per pixel.  For this reason, we don't check to
    	movwf	temp			; see if the DMX string has timed out anywhere.
    	call	maxcheck		; Rather, once all three bytes have been received,
    	movwf 	bluenew			; the code loops back and waits for a new start code.
    					; Were we to 'run out' of channel data in here somewhere
    					; the code may behave strangely.  Caveat Emptor!
    
    	goto 	dmxcapture		; Got all three bytes?  Repeat Ad Absurdum.
    
     
    ; ----------- Routines for Starting the Chip ---------
    
    chipinit
    	BANK0				; Memory bank 0
    	clrf	PORTC			; All PORTC Pins off
    	clrf	CMCON0			; Comparators aren't used either
    
    	BANK1				; Switch to memory bank 1
    	bcf	TRISC,0			; Red Drive Pin
    	bcf	TRISC,1			; Green Drive Pin
    	bcf	TRISC,2			; Blue Drive Pin
    	clrf	ANSEL			; Turn off A/D Converters
    	bsf	OSCCON,6		; Set these three
    	bsf	OSCCON,5		; bits to enable the
    	bsf	OSCCON,4		; 8 MHz internal oscillator
    	bcf	TRISA,0			; PORTA.0 and PORTA.1 were used
    	bcf	TRISA,1			; for testing and debugging, so set as outputs
    	return
    
    rxinit
    	BANK0
    	bsf	TRISC,5			; PORTC.5 is input for DMX data to EUSART
    	clrf	TXSTA			; Clear TXSTA register
    	movlw 	B'10010000'		; Serial Port and continuous receive enabled
    	movwf	RCSTA				
    	movlw	D'1'			; for baud rate generator
    	movwf	SPBRG			
    	clrf	SPBRGH			; This combination assures 0% error when
    	bsf	BAUDCTL,BRG16		; receiving DMX at 250,000 bits per second
    	return				; the PLL makes it possible to grab such
    					; high speed data without any error
    
    pwminit
    	movlw	B'10100000'		; Enable global and TMR0 interrupts
    	movwf	INTCON
    	BANK1
    	clrf	OPTION_REG		; No prescaler for TMR0 needed
    	BANK0	
    	return
    
    
    
    ; ----------------- Other Subroutines Go Here
    
    maxcheck
    
    	; Processes value which is stored in W. 
    	; New value is also in W when routine exits
    
    	xorlw	D'255'			; Here we're checking to see if a received
    	btfsc	STATUS,Z		; byte is greater than 254.  If it is,
    	goto 	exit			; set it to 254.  If it's less than 254
    	movf	temp,w			; leave it alone and the PWM routine will deal with
    	return				; it shortly
    exit
    	movlw	D'254'
    	return
    
    	END

Similar Threads

  1. Bits, Bytes Words and Arrays
    By Melanie in forum FAQ - Frequently Asked Questions
    Replies: 24
    Last Post: - 14th June 2016, 08:55
  2. Half-bridge PWM with a 16F684 ?
    By Byte_Butcher in forum General
    Replies: 7
    Last Post: - 17th January 2010, 23:18
  3. PICBasic newbie problem
    By ELCouz in forum mel PIC BASIC Pro
    Replies: 32
    Last Post: - 12th February 2008, 01:55
  4. Microcontroller with 2 way paging application problem
    By oneohthree in forum mel PIC BASIC Pro
    Replies: 30
    Last Post: - 20th April 2007, 18:27
  5. DMX512 Problem ..Schema+Code
    By programmer07 in forum mel PIC BASIC Pro
    Replies: 21
    Last Post: - 21st March 2007, 16:39

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts