///////////////////////////////// // // FastLED6502 // by Mark Kriegsman // // Device driver and animation // library for connecting addressable // LED strips to an Apple II. // The full "FastLED" library is // available for Arduino and related // microcontrollers. // ///////////////////////////////// // // HOST COMPATIBILITY: // Apples with 16-pin DIP "game ports" // are fully supported; Apples with only // 9-pin "game ports" are NOT supported. // // Apple ][ fully supported // Apple ][+ fully supported // Apple //e fully supported // // Apple //c and //c+ NOT supported // as they lack the required 16-pin // DIP game port for digital I/O. // // Apple //gs: // motherboard game port IS supported // back panel connector NOT supported // See Notes section below. // // C64, PET, VIC-20, Atari400/800, // NES, SYM, KIM-1, and other 6502 // systems are NOT supported at this // time, but porting should be // relatively easy for someone familiar // with each target platform. // // // LED STRIP COMPATIBILITY: // In general, "four-wire" (clocked) // LED strips can be supported, but // "three-wire" (clockless) LED strips // cannot be supported. // // APA102 tested & working // Adafruit DotStar tested & working // LPD8806 should work (untested) // WS2801 should work (untested) // // WS2811/WS2812/NeoPixel can NOT work // due to timing incompatibilities, // namely that the 1MHz Apple is far // too slow to drive them correctly. // // // USAGE - HARDWARE: // Connect an external power source to // +5 and GND on the LED strip. // Connect GND on the LED strip to GND // on the game port connector (pin 8) // Connect DATA IN on the LED strip to // pin 12, 13, or 14 on the game port. // Connect CLOCK IN on the LED strip to // pin 5 (preferred), 12, 13, or 14 on // the game port. Note: Apple //gs users // cannot use pin 5. // // // USAGE - SOFTWARE: // At build time provide definitions for // CHIPSET, DATA_PIN, CLOCK_PIN, // NUM_LEDS, & BRIGHTNESS. // Inside "Setup": // Store LED count into // FastLED_NumPixels, // Store brightness into // FastLED_Brightness // Inside "Loop": // Update the leds array, found in // ledsR, ledsG, and ledsB // Call FastLED_Show // Jump back to top of "Loop" // // // REFERENCE: // FastLED_Show: // display led array on LED strip // FastLED_FillBlack: // fill led array to black // FastLED_FillSolid_RGB_AXY: // fill led array with RGB color // FastLED_FillSolid_Hue_X: // fill led array with solid HSV Hue // FastLED_Random8: // return a pseudorandom number in A // FastLED_FillRainbow_XY: // fill led array with HSV rainbow // starting at hue X, incrementing by // huedelta Y each pixel. // FastLED_SetHue_XY: // set pixel Y to HSV hue X // FastLED_Beat8: // takes a speed increment in A, and // returns a triangle wave in A. // // // NOTES: // For speed and size, there IS some // self-modifying code in this // library, so it cannot be burned // into ROM without modification. // Brightness control only works on // APA102 at this point. // Pin 15 is currently used as a // 'frame start' signal for protocol // diagnostics - makes frames more // visible with an oscilloscope. // If Pin 5 is specified for the CLOCK // output pin, FastLED6502 will // automatically use the high speed // C040STROBE signal for clock. Note // that the Apple //gs lacks this // signal, even on the motherboard // game port. // The Apple joystick/mouse port on the // rear of the //c, //c+, and //gs // can NOT be used for LED connections // because it lacks the necessary // digital output pins. // This library can drive 100 LED pixels // at more than 30 frames per second. // // // VERSION HISTORY // 2015-02-07 - first version, by MEK // assembled with xa65 // www.floodgap.com/retrotech/xa/ ///////////////////////////////// // // ENTRY POINT // FastLED_Entry jsr FastLED_FillBlack jmp Setup ///////////////////////////////// // // FASTLED6502 GLOBALS // FastLED_NumPixels .byt NUM_LEDS FastLED_Brightness .byt BRIGHTNESS FastLED_RandomState .byt 17 FastLED_BeatState .byt 0 ///////////////////////////////// // // API FUNCTIONS // FastLED_FillBlack lda FastLED_NumPixels pha lda #255 sta FastLED_NumPixels lda #0 tax tay jsr FastLED_FillSolid_RGB_AXY jsr FastLED_Show pla sta FastLED_NumPixels rts FastLED_FillRainbow_XY sty rbHueDelta ldy #0 FR1 lda FastLED_RainbowR,x sta ledsR,y lda FastLED_RainbowG,x sta ledsG,y lda FastLED_RainbowB,x sta ledsB,y txa clc adc rbHueDelta tax iny cpy FastLED_NumPixels bne FR1 rts rbHueDelta .byt 0 FastLED_SetHue_XY lda FastLED_RainbowR,x sta ledsR,y lda FastLED_RainbowG,x sta ledsG,y lda FastLED_RainbowB,x sta ledsB,y rts FastLED_FillSolid_RGB_AXY sta ledsR stx ledsG sty ledsB ldy #0 FillSolidRGBAXY1 lda ledsR sta ledsR,y lda ledsG sta ledsG,y lda ledsB sta ledsB,y iny cpy FastLED_NumPixels bne FillSolidRGBAXY1 rts FastLED_FillSolid_Hue_X ldy #0 FillSolidHX1 lda FastLED_RainbowR,x sta ledsR,y lda FastLED_RainbowG,x sta ledsG,y lda FastLED_RainbowB,x sta ledsB,y iny cpy FastLED_NumPixels bne FillSolidHX1 rts ; NOTE: USES SELF-MODIFYING CODE FastLED_Random8 inc Random8GetLo bne Random8Get inc Random8GetHi bne Random8Get lda #$F8 sta Random8GetHi lda #03 sta Random8GetLo Random8Get Random8GetLo = Random8Get + 1 Random8GetHi = Random8Get + 2 lda $F803 adc FastLED_RandomState sta FastLED_RandomState rts FastLED_Beat8 clc adc FastLED_BeatState sta FastLED_BeatState bit FastLED_BeatState bmi FastLED_Beat8Neg asl rts FastLED_Beat8Neg lda #$ff sec sbc FastLED_BeatState sbc FastLED_BeatState rts FastLED_Show jmp CHIPSET ///////////////////////////////// // // HARDWARE INTERFACING // PINOFF_BASE = PIN15OFF PINON_BASE = PIN15ON #define PINON(P) PINON_BASE+((15-P)*2) #define PINOFF(P) PINOFF_BASE+((15-P)*2) DATAOFF = PINOFF(DATA_PIN) DATAON = PINON(DATA_PIN) CLKOFF = PINOFF(CLOCK_PIN) CLKON = PINON(CLOCK_PIN) // Special handling if CLOCK_PIN // is 5: the C040STROBE line. #if CLOCK_PIN = 5 #define CLOCK_ON bit PIN5STROBE #define CLOCK_OFF #else #define CLOCK_ON bit CLKON #define CLOCK_OFF bit CLKOFF #endif FRAMEON = PINON(15) FRAMEOFF = PINOFF(15) ///////////////////////////////// APA102 bit FRAMEON jsr FastLED_Send00 jsr FastLED_Send00 jsr FastLED_Send00 jsr FastLED_Send00 lda FastLED_Brightness lsr lsr lsr ora #$E0 tax ldy FastLED_NumPixels APA102PX txa jsr FastLED_SendA lda ledsB,y jsr FastLED_SendA lda ledsG,y jsr FastLED_SendA lda ledsR,y jsr FastLED_SendA dey bne APA102PX lda FastLED_NumPixels lsr lsr lsr lsr lsr lsr tay iny APA102CL jsr FastLED_SendFF jsr FastLED_Send00 jsr FastLED_Send00 jsr FastLED_Send00 dey bne APA102CL bit FRAMEOFF rts ///////////////////////////////// LPD8806 bit FRAMEON ldy FastLED_NumPixels LPD8806PX lda ledsG,y lsr ora #$80 jsr FastLED_SendA lda ledsR,y lsr ora #$80 jsr FastLED_SendA lda ledsB,y lsr ora #$80 jsr FastLED_SendA dey bne LPD8806PX bit FRAMEOFF rts ///////////////////////////////// WS2801 bit FRAMEON ldy FastLED_NumPixels WS2801PX lda ledsG,y jsr FastLED_SendA lda ledsR,y jsr FastLED_SendA lda ledsB,y jsr FastLED_SendA dey bne WS2801PX bit FRAMEOFF rts ///////////////////////////////// FastLED_SendFF bit DATAON jmp FastLED_SendXX ; FastLED_Send00 bit DATAOFF ; FastLED_SendXX CLOCK_ON CLOCK_OFF CLOCK_ON CLOCK_OFF CLOCK_ON CLOCK_OFF CLOCK_ON CLOCK_OFF CLOCK_ON CLOCK_OFF CLOCK_ON CLOCK_OFF CLOCK_ON CLOCK_OFF CLOCK_ON CLOCK_OFF rts FastLED_SendA cmp #0 beq FastLED_Send00 cmp #$FF beq FastLED_SendFF asl bcc S0x0 S0x1 bit DATAON bcs S0xK S0x0 bit DATAOFF S0xK CLOCK_ON CLOCK_OFF asl bcc S1x0 S1x1 bit DATAON bcs S1xK S1x0 bit DATAOFF S1xK CLOCK_ON CLOCK_OFF asl bcc S2x0 S2x1 bit DATAON bcs S2xK S2x0 bit DATAOFF S2xK CLOCK_ON CLOCK_OFF asl bcc S3x0 S3x1 bit DATAON bcs S3xK S3x0 bit DATAOFF S3xK CLOCK_ON CLOCK_OFF asl bcc S4x0 S4x1 bit DATAON bcs S4xK S4x0 bit DATAOFF S4xK CLOCK_ON CLOCK_OFF asl bcc S5x0 S5x1 bit DATAON bcs S5xK S5x0 bit DATAOFF S5xK CLOCK_ON CLOCK_OFF asl bcc S6x0 S6x1 bit DATAON bcs S6xK S6x0 bit DATAOFF S6xK CLOCK_ON CLOCK_OFF asl bcc S7x0 S7x1 bit DATAON bcs S7xK S7x0 bit DATAOFF S7xK CLOCK_ON CLOCK_OFF rts ///////////////////////////////// // // Force page allignment for speed // for leds array and Rainbow table // .dsb 256-(* & $FF),0 ///////////////////////////////// // // LED ARRAY // ledsR .dsb 256,0 ledsG .dsb 256,0 ledsB .dsb 256,0 ///////////////////////////////// // // HSV RAINBOW DEFINITION // // Generated directly from FastLED. // FastLED_RainbowR .byt $FF,$FD,$FA,$F8,$F5,$F2,$F0,$ED .byt $EA,$E8,$E5,$E2,$E0,$DD,$DA,$D8 .byt $D5,$D2,$D0,$CD,$CA,$C8,$C5,$C2 .byt $C0,$BD,$BA,$B8,$B5,$B2,$B0,$AD .byt $AB,$AB,$AB,$AB,$AB,$AB,$AB,$AB .byt $AB,$AB,$AB,$AB,$AB,$AB,$AB,$AB .byt $AB,$AB,$AB,$AB,$AB,$AB,$AB,$AB .byt $AB,$AB,$AB,$AB,$AB,$AB,$AB,$AB .byt $AB,$A6,$A1,$9C,$96,$91,$8C,$86 .byt $81,$7C,$76,$71,$6C,$66,$61,$5C .byt $56,$51,$4C,$47,$41,$3C,$37,$31 .byt $2C,$27,$21,$1C,$17,$11,$0C,$07 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$02,$05,$07,$0A,$0D,$0F,$12 .byt $15,$17,$1A,$1D,$1F,$22,$25,$27 .byt $2A,$2D,$2F,$32,$35,$37,$3A,$3D .byt $3F,$42,$45,$47,$4A,$4D,$4F,$52 .byt $55,$57,$5A,$5C,$5F,$62,$64,$67 .byt $6A,$6C,$6F,$72,$74,$77,$7A,$7C .byt $7F,$82,$84,$87,$8A,$8C,$8F,$92 .byt $94,$97,$9A,$9C,$9F,$A2,$A4,$A7 .byt $AB,$AD,$B0,$B2,$B5,$B8,$BA,$BD .byt $C0,$C2,$C5,$C8,$CA,$CD,$D0,$D2 .byt $D5,$D8,$DA,$DD,$E0,$E2,$E5,$E8 .byt $EA,$ED,$F0,$F2,$F5,$F8,$FA,$FD FastLED_RainbowG .byt $00,$02,$05,$07,$0A,$0D,$0F,$12 .byt $15,$17,$1A,$1D,$1F,$22,$25,$27 .byt $2A,$2D,$2F,$32,$35,$37,$3A,$3D .byt $3F,$42,$45,$47,$4A,$4D,$4F,$52 .byt $55,$57,$5A,$5C,$5F,$62,$64,$67 .byt $6A,$6C,$6F,$72,$74,$77,$7A,$7C .byt $7F,$82,$84,$87,$8A,$8C,$8F,$92 .byt $94,$97,$9A,$9C,$9F,$A2,$A4,$A7 .byt $AB,$AD,$B0,$B2,$B5,$B8,$BA,$BD .byt $C0,$C2,$C5,$C8,$CA,$CD,$D0,$D2 .byt $D5,$D8,$DA,$DD,$E0,$E2,$E5,$E8 .byt $EA,$ED,$F0,$F2,$F5,$F8,$FA,$FD .byt $FF,$FD,$FA,$F8,$F5,$F2,$F0,$ED .byt $EA,$E8,$E5,$E2,$E0,$DD,$DA,$D8 .byt $D5,$D2,$D0,$CD,$CA,$C8,$C5,$C2 .byt $C0,$BD,$BA,$B8,$B5,$B2,$B0,$AD .byt $AB,$A6,$A1,$9C,$96,$91,$8C,$86 .byt $81,$7C,$76,$71,$6C,$66,$61,$5C .byt $56,$51,$4C,$47,$41,$3C,$37,$31 .byt $2C,$27,$21,$1C,$17,$11,$0C,$07 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 FastLED_RainbowB .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$00,$00,$00,$00,$00,$00,$00 .byt $00,$02,$05,$07,$0A,$0D,$0F,$12 .byt $15,$17,$1A,$1D,$1F,$22,$25,$27 .byt $2A,$2D,$2F,$32,$35,$37,$3A,$3D .byt $3F,$42,$45,$47,$4A,$4D,$4F,$52 .byt $55,$5A,$5F,$64,$6A,$6F,$74,$7A .byt $7F,$84,$8A,$8F,$94,$9A,$9F,$A4 .byt $AA,$AF,$B4,$B9,$BF,$C4,$C9,$CF .byt $D4,$D9,$DF,$E4,$E9,$EF,$F4,$F9 .byt $FF,$FD,$FA,$F8,$F5,$F2,$F0,$ED .byt $EA,$E8,$E5,$E2,$E0,$DD,$DA,$D8 .byt $D5,$D2,$D0,$CD,$CA,$C8,$C5,$C2 .byt $C0,$BD,$BA,$B8,$B5,$B2,$B0,$AD .byt $AB,$A9,$A6,$A4,$A1,$9E,$9C,$99 .byt $96,$94,$91,$8E,$8C,$89,$86,$84 .byt $81,$7E,$7C,$79,$76,$74,$71,$6E .byt $6C,$69,$66,$64,$61,$5E,$5C,$59 .byt $55,$53,$50,$4E,$4B,$48,$46,$43 .byt $40,$3E,$3B,$38,$36,$33,$30,$2E .byt $2B,$28,$26,$23,$20,$1E,$1B,$18 .byt $16,$13,$10,$0E,$0B,$08,$06,$03