; file: f12.asm ; ; This is an output-only program to blink all 5 available ; outputs of the p12f509 8-pin chip in interesting ways. ; poly@omino.com, 2007 June ; ; About the patterns: ; * There are a collection of separate patterns ; * They play in some sequence ; * They are influenced by a very, very feeble ; pseudorandom number generator (see Rnd) ; * Some use a 1-bit dac with 8-bits resolution, to fade ; * They share a few subroutines down low, as is ; the 12f509 way. ; * The code is heavily macro'd, stay sharp. ; ; Interesting aspects of the PIC12F509 include: ; * CALL instruction has 8 bit range, so subroutines ; must be in the first 256 instructions ; * GOTO instruction has 9 bit range, so jumps must ; be in the first 512 instructions ; * Ok, actually, you can use the STATUS bit 5 "PA0" ; to set bit *nine* before either a GOTO or a ; CALL. So with care you can GOTO anywhere, ; or CALL 0x000-0x0ff and 0x200-0x2ff. So two ; quadrants cannot be CALLed at all. ; * File registers 0x07-0x1F are accessible normally ; * File registers 0x30-0x3F accessible only by FSR/INDF. ; * Two level subroutine stack ; * No interrupts ; INCLUDE "P12F509.INC" INCLUDE "macross12f509.inc" ; config ; ; NOTE! 20090429 Watchdog Timer Must Be ON! ; the end of the patterns sits and waits for the timeout, ; which is cool, because we get extra randomness from the ; two disparate clocks. ; __CONFIG _MCLRE_OFF & _CP_OFF & _WDT_ON & _IntRC_OSC ; available file registers 0x7-0x1f (25 registers) ; (there are more at 0x30-0x3f but only by ; FSR indirect addressing.) CBLOCK 0x07 ; t must be low, to map the same in both ; banks during indirect writes. t ; mm, temp for tiny macros led0:3 ; 1st: linear brightness, 2nd: running sum, 3rd: target brightness led1:3 led2:3 led4:3 led5:3 bitsOut rnd patternCount ; for any pattern, how many patternTime ; for any pattern, the main delay time. r0,r1 ; oh, usually delay registers, fadeout & glide patternVal1 ; owned by the pattern patternVal2 ; owned by the pattern ENDC CBLOCK 0x30 powerBump ; for pattern5 score:12 ; score in 3 groups of 4 each cblock30End ; keep this last ENDC IF cblock30End > 0x40 ERROR "CBLOCK30 exceeded" ENDIF ; stash to one of our indirect registers from W ; uses t! MOVWI MACRO _iReg MOVWF t MOVLF _iReg,FSR MOVFF t,INDF CLRF FSR ; otherwise upper bits affect MOVs ENDM ; Each 1-bit dac is maintained as 2 bytes: ; the brightness and the running-sum. ; (a third byte is sometimes the "target brightness") ; Rotate the current 1-bit dac on-offness ; into the right side of "dest". StepDac MACRO dacState,dest MOVFW dacState ADDWF dacState+1,F RLF dest,F ; put led in low bit ENDM LedsOff MACRO MOVLF 0xff,GPIO ; lights off while we rethink ENDM ; Poke a random value into a file register ; mask is anded, and min is added ; RANDF x,31,10 to get 10..41 RANDF MACRO fregdst,mask,min CALL Rnd MOVFW rnd IF mask != 0xff ANDLW mask ENDIF MOVWF fregdst IF min != 0 MOVLW min ADDWF fregdst,f ENDIF ENDM ORG 0 ; lets begin GOTO Start ; | ; | Keep subroutines down low, due to ; | address-range limitations of ; | P12F509 RefreshLeds: ; advance each dac CLRF bitsOut StepDac led5,bitsOut StepDac led4,bitsOut ; just a zero for bit 3 BCF STATUS,C RLF bitsOut,f StepDac led2,bitsOut StepDac led1,bitsOut StepDac led0,bitsOut MOVFW bitsOut XORLW 0xFF ; invert for sink led MOVWF GPIO CLRWDT RETLW 0 ; ; Put a (very psuedo) random number into ; the 'rnd' file register. Rnd: MOVFW rnd ADDWF TMR0,w RLF rnd,f RLF rnd,f ADDWF rnd,f RETLW 0 ; ; Bring all the dacs down to zero ; Note -- nested subroutine call here! ; All _two_ of our stack is used up ; when you call this. ; uses: r0, r1 ; FadeoutLeds: CLRF r0 CLRF r1 _fadeoutLoop CALL RefreshLeds DECFPIN led0 ; 3 cycles CALL RefreshLeds DECFPIN led1 CALL RefreshLeds DECFPIN led2 CALL RefreshLeds DECFPIN led4 CALL RefreshLeds DECFPIN led5 ; and spin a while at same brightnesses _fadeoutLoop2 CALL RefreshLeds DECFSZ r1,f GOTO _fadeoutLoop2 CALL RefreshLeds ; keep the beat... DECFSZ r0,f GOTO _fadeoutLoop ; theoretically, they're all off now. RETLW 0 ; move each LED to its target value, pausing ; patternTime tween each step. ; do 256 steps to be sure. ; uses: r0, r1. GlideLeds: CLRF r0 ; outer counter, make sure we do 256 altogether _glideLedsLoop1: CALL RefreshLeds MIGFPIN led0,led0+2 CALL RefreshLeds MIGFPIN led1,led1+2 CALL RefreshLeds MIGFPIN led2,led2+2 CALL RefreshLeds MIGFPIN led4,led4+2 CALL RefreshLeds MIGFPIN led5,led5+2 ; now delay by patternTime refreshes... CALL RefreshLeds MOVFF patternTime,r1 ; 2 NOPS 6 _glideLedsLoop: CALL RefreshLeds NOPS 5 DECFSZ r1,f GOTO _glideLedsLoop NOP CALL RefreshLeds NOPS 5 DECFSZ r0,f GOTO _glideLedsLoop1 RETLW 0 Start: ; All five outputs to "out" ; GPIO 3 can only be "in" MOVLW 0 TRIS GPIO MOVLW b'11011111' ; 0xDF, internal timer, no pullups, slowest watchdog OPTION PatternsStart: Pattern7: GOTOHILO Pattern7High _p7b: Pattern6: RANDF patternCount,0x3f,10 RANDF patternTime,0x1f,4 MOVLF 1,patternVal1 ; our light mask _p6loop: ; set each LED target according to the mask RANDF led0+2,0x7f,40 RANDF led1+2,0x7f,40 RANDF led2+2,0x7f,40 RANDF led4+2,0x7f,40 RANDF led5+2,0x7f,40 ; clear the ones that should be off ; (5 bits, but leds 0,1,2,4,5) IFBC patternVal1,0 CLRF led0+2 IFBC patternVal1,1 CLRF led1+2 IFBC patternVal1,2 CLRF led2+2 IFBC patternVal1,3 CLRF led4+2 IFBC patternVal1,4 CLRF led5+2 CALL GlideLeds CALL GlideLeds CALL GlideLeds ; now, choose a new set that matches none ; of the previous set ; note we have a random-number retry going on. ; sure hope the random number thingie doesnt ; get stuck. uck. ; (WDT would help here.) _p6nextLights RANDF patternVal2,0x1f,0 ; new random set MOVFW patternVal1 ; clear out any that were on.. XORLW 0x1f ANDWF patternVal2,f ; done IFZ GOTO _p6nextLights ; no? try again MOVFF patternVal2,patternVal1 DECFSZ patternCount,f GOTO _p6loop CALL FadeoutLeds CALL FadeoutLeds CALL FadeoutLeds Pattern5: ; upper 2 power up the lower 3 RANDF r0,0x07,1 MOVFI r0,powerBump ; bump lower 3 this much. RANDF patternTime,0x3f,0x3 MOVLF 0,patternCount ; when it hits ff we are done _p5loop: ; upper two MOVLF 0,led4+2 RANDF led5,0xff,0 RANDF led5+2,0x7f,0x20 MOVFW patternCount MOVWF led0+2 MOVWF led1+2 MOVWF led2+2 RANDF r0,0x1f,0 SUBFF r0,led0 RANDF r0,0x1f,0 SUBFF r0,led1 RANDF r0,0x1f,0 SUBFF r0,led2 CALL GlideLeds LedsOff RANDF led4,0xff,0 RANDF led4+2,0x7f,0x20 MOVLF 0,led5+2 MOVFW patternCount MOVWF led0+2 MOVWF led1+2 MOVWF led2+2 RANDF r0,0x1f,0 SUBFF r0,led0 RANDF r0,0x1f,0 SUBFF r0,led1 RANDF r0,0x1f,0 SUBFF r0,led2 CALL GlideLeds MOVIW powerBump ADDWF patternCount,f IFNC GOTO _p5loop Pattern1: ; set repeats and rate (randomly) RANDF patternCount,0x3f,100 RANDF patternTime,0x07,0x05 MOVFF patternTime,r1 ; (preset counter for first go round) _pattern1Loop ; set new brightnesses for each RANDF led0,0xff,0 RANDF led1,0xff,0 RANDF led2,0xff,0 RANDF led4,0xff,0 RANDF led5,0xff,0 _pattern1Loop2: CALL RefreshLeds DECFSZ r0,f GOTO _pattern1Loop2 DECFSZ r1,f GOTO _pattern1Loop2 MOVFF patternTime,r1 LedsOff ; lights off while we rethink DECFSZ patternCount,f GOTO _pattern1Loop CALL FadeoutLeds CALL FadeoutLeds Pattern2: ; swimmy fades RANDF patternCount,0xf,0x10 RANDF patternTime,0x7f,0x10 p2loop: ; make a random target value for each led RANDF led0+2,0xff,0 RANDF led1+2,0xff,0 RANDF led2+2,0xff,0 RANDF led4+2,0xff,0 RANDF led5+2,0xff,0 CALL GlideLeds LedsOff ; lights off while we rethink DECFSZ patternCount,f GOTO p2loop CALL FadeoutLeds CALL FadeoutLeds pattern3: ; on, in sequence RANDF patternTime,0x7f,0x40 RANDF patternCount,0x7,1 _p3loop: CLRF led0+2 CLRF led1+2 CLRF led2+2 CLRF led4+2 CLRF led5+2 MOVLF 0xff,led0+2 CALL GlideLeds MOVLF 0xff,led1+2 CALL GlideLeds MOVLF 0xff,led2+2 CALL GlideLeds MOVLF 0xff,led4+2 CALL GlideLeds MOVLF 0xff,led5+2 CALL GlideLeds CALL FadeoutLeds CALL FadeoutLeds ; make count faster each time BCF STATUS,C RRF patternTime,f INCF patternTime,f DECFSZ patternCount,f GOTO _p3loop Pattern4: ; various groups on RANDF patternTime,0x3f,0x80 RANDF patternCount,0x7,13 _p4loop: ; set each led to 0 or 80 RANDF led0+2,0x80,0 RANDF led1+2,0x80,0 RANDF led2+2,0x80,0 RANDF led4+2,0x80,0 RANDF led5+2,0x80,0 CALL GlideLeds CALL FadeoutLeds DECFSZ patternCount,f GOTO _p4loop ; now, we wait for the Watch Dog Timer ; to fire. since its on a separatre clock, ; it lets the timer advance a very random ; amount, increasing our diversity. WaitUntilTimeout: GOTO WaitUntilTimeout GOTO PatternsStart ; ----------------------------- ; High Code ; Code up here in needs to track STATUS:PA0 for ; the 9th bit of the address on GOTO or CALL. We ; keep it set while up here. We clear it to GOTO ; a low address, and temporarily clear it to ; CALL a low address ; ORG 0x200 Pattern7High: MOVLF 0xf0,led0 MOVLF 0x80,led1 MOVLF 0x40,led2 MOVLF 0x20,led4 MOVLF 0x10,led5 CALLLO FadeoutLeds GOTOHILO _p7b END ; EOF CLRF led4+2 CLRF led5+2 MOVLF 0xff,led0+2 CALL GlideLeds MOVLF 0xff,led1+2 CALL GlideLeds MOVLF 0xff,led2+2 CALL GlideLeds MOVLF 0xff,led4+2 CALL GlideLeds MOVLF 0xff,led5+2 CALL GlideLeds CALL FadeoutLeds CALL FadeoutLeds ; make count faster each time BCF STATUS,C RRF patternTime,f INCF patternTime,f DECFSZ patternCount,f GOTO _p3loop Pattern4: ; various groups on RANDF patternTime,0x3f,0x80 RANDF patternCount,0x7,13 _p4loop: ; set each led to 0 or 80 RANDF led0+2,0x80,0 RANDF led1+2,0x80,0 RANDF led2+2,0x80,0 RANDF led4+2,0x80,0 RANDF led5+2,0x80,0 CALL GlideLeds CALL FadeoutLeds DECFSZ patternCount,f GOTO _p4loop ; now, we wait for the Watch Dog Timer ; to fire. since its on a separatre clock, ; it lets the timer advance a very random ; amount, increasing our diversity. WaitUntilTimeout: GOTO WaitUntilTimeout GOTO PatternsStart END ; EOF