; filename: matrixscope.asm
; 24x16 LED Matrix Display Scope with 8x8 LED matrix displays (A-1088BS) and HEF4094B shift registers
; 221209 v0.1 Copied from LED PPM (and others)
; 221209 v0.2 Lose OE (always H). This saves clock cycles.
; 221212 v0.3 Trigger. This is a 1 µs wide positive pulse on RB0/INT pin.
; GPL Copyleft 2022 pic@polonai.se
LIST P=16F818, F=INHX8M
#include <p16f818.inc>
__CONFIG _WDT_OFF & _PWRTE_OFF & _HS_OSC & _MCLR_ON & _BODEN_OFF & _LVP_OFF & _CPD_OFF & _WRT_ENABLE_OFF & _DEBUG_OFF & _CCP1_RB2 & _CP_OFF
ERRORLEVEL -302 ; sod message about using proper bank
; Equates
RESET_V EQU 0x00 ; Address of RESET Vector
; Registers
FLAGS EQU 0x20 ; Various flags
SWP EQU 0x21 ; Sweep time value
SWPCNT EQU 0x22 ; Sweep time counter
SWPPOS EQU 0x23 ; Sweep position counter
Y EQU 0x24 ; Vertical value (4 bit)
; PORTA,0 A/D input for vertical has no name defined
#define DN PORTA,3 ; SW1 (DN) Slower sweep button
#define UP PORTA,4 ; SW2 (UP) Faster sweep button
; PORTB,0 RB0/INT input for trigger has no name defined
#define SDI PORTB,1 ; Serial Data line of HEF4094s
#define CLKX PORTB,2 ; Clock for horizontal HEF4094s (high pulse)
#define CLKY PORTB,3 ; Clock for vertical HEF4094s (high pulse)
#define STROE PORTB,4 ; Strobe for HEF4094s (high pulse)
#define HELD FLAGS,0 ; Button Held flag to provide rudimentary debounce
org 0x00
GOTO START
org 0x04
; Interrupts
; Timer0/RB0/INT Interrupt Handler ; Runs every 32768 µs and RB0/INT trigger event
BTFSC INTCON,INTF
GOTO Trigger
BCF INTCON,TMR0IF ; Clear TMR0 interrupt
BTFSS UP ; <UP> button pressed?
GOTO Sweep_INC ; Sweep faster
BTFSS DN ; <DN> button pressed?
GOTO Sweep_DEC ; Sweep slower
BCF HELD ; Debounce reset
RETFIE
Sweep_INC
BTFSC HELD ; Button held?
RETFIE ; Yes
BSF HELD
BCF STATUS,C ; Clear carry
RRF SWP,F ; Half sweep time
BTFSS STATUS,C ; Did the single one shift into the carry?
RETFIE
MOVLW B'10000000' ; Load longest sweep time
MOVWF SWP
RETFIE
Sweep_DEC
BTFSC HELD ; Button held?
RETFIE ; Yes
BSF HELD
BCF STATUS,C ; Clear carry
RLF SWP,F ; Double sweep time
BTFSS STATUS,C ; Did the single one shift into the carry?
RETFIE
MOVLW B'00000001' ; Load shortest sweep time
MOVWF SWP
RETFIE
Trigger
BCF INTCON,INTF ; Clear RB0/INT interrupt
MOVLW 0x0A
SUBWF SWPPOS,W
BTFSC STATUS,C ; Sweep position near the end?
RETFIE ; No
MOVFW SWP ; Restore sweep time
MOVWF SWPCNT
BSF CLKX
BCF CLKX
DECFSZ SWPPOS ; Clock out single zero until it's gone
GOTO $-3
MOVLW 0x20
MOVWF SWPPOS
BCF SDI ; Clock out the single 0
BSF CLKX
BCF CLKX
BSF SDI
BSF STROE
BCF STROE
RETFIE
; End interrupt routines
START
; Init stuff
CLRF STATUS ; Do initialization, Select bank 0
CLRF INTCON
CLRF PCLATH ; Keep in lower 2KByte
CLRF CCP1CON
BSF STATUS,RP0 ; Select bank 1
MOVLW B'00111101'
MOVWF TRISA ; RA7,6,1 Outputs, 5-2,0 Inputs
MOVLW B'00000001'
MOVWF TRISB ; RB7-1 Outputs, 0 Input
MOVLW B'00000110' ; Timer0, prescaler 1:128
MOVWF OPTION_REG
MOVLW B'01110000' ; 8 MHz clock
MOVWF OSCCON
MOVLW B'00001110' ; AN0 Analog input, AN1-4 Digital IO, ADRESH only (ADRESL discarded)
MOVWF ADCON1
BCF STATUS,RP0 ; Select bank 0
MOVLW B'01000001' ; AD conv ON, AN0 Selected, Fosc/8 (T(AD)=1us)
MOVWF ADCON0
CLRF PORTA ; Make all PORT A outputs low
CLRF PORTB ; Make all PORT B outputs low
CLRF TMR0 ; Reset Timer 0
MOVLW B'10000000' ; Load longest sweep time
MOVWF SWP
MOVWF SWPCNT ; and sweep counter
MOVLW 0x20
MOVWF SWPPOS ; Preload position
BSF INTCON,TMR0IE ; Enable Timer0 interrupt
BSF INTCON,INTE ; Enable external interrupt on RB0
BSF INTCON,GIE ; Enable global interrupts
MAIN
CALL YDECODE ; Determine vertical position
DECFSZ SWPCNT,F ; Next sweep point?
GOTO MAIN ; No
MOVFW SWP ; Get new sweep time
MOVWF SWPCNT
BSF CLKX
BCF CLKX
BSF STROE
BCF STROE ; Clock out the single 0 further on
DECFSZ SWPPOS
GOTO MAIN
MOVLW 0x20
MOVWF SWPPOS ; Preload position. Note that the 0 gets clocked out beyond 24 LEDs.
BCF SDI ; Clock out the single 0 to first position
BSF CLKX
BCF CLKX
BSF SDI
BSF STROE
BCF STROE
GOTO MAIN
; Subroutines
YDECODE ; Read A/D and load vertical shift register
BCF INTCON,GIE ; Disable global interrupts
BSF ADCON0,GO ; Start A/D (Vertical Input)
CONV
NOP
BTFSC ADCON0,GO ; Test if done
GOTO CONV ; Not done
MOVLW 0xF0
ANDWF ADRESH,W ; Get A/D value and blank lower nibble
MOVWF Y ; Store it in Y
MOVLW 0x80
SUBWF Y,W ; Test for 0x80. Note that IC1 and 2 were swapped in the prototype so the sequence is too.
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
MOVLW 0x90
SUBWF Y,W ; Test for 0x90
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
MOVLW 0xA0
SUBWF Y,W ; Test for 0xA0
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
MOVLW 0xB0
SUBWF Y,W ; Test for 0xB0
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
MOVLW 0xC0
SUBWF Y,W ; Test for 0xC0
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
MOVLW 0xD0
SUBWF Y,W ; Test for 0xD0
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
MOVLW 0xE0
SUBWF Y,W ; Test for 0xE0
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
MOVLW 0xF0
SUBWF Y,W ; Test for 0xF0
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
CLRW
SUBWF Y,W ; Test for 0x00
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
MOVLW 0x10
SUBWF Y,W ; Test for 0x10
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
MOVLW 0x20
SUBWF Y,W ; Test for 0x20
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
MOVLW 0x30
SUBWF Y,W ; Test for 0x30
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
MOVLW 0x40
SUBWF Y,W ; Test for 0x40
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
MOVLW 0x50
SUBWF Y,W ; Test for 0x50
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
MOVLW 0x60
SUBWF Y,W ; Test for 0x60
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
MOVLW 0x70
SUBWF Y,W ; Test for 0x70
BCF SDI
BTFSC STATUS,Z ; Match?
BSF SDI ; Yes
BSF CLKY
BCF CLKY ; Clock out bit
BSF STROE
BCF STROE
BSF SDI ; Make sure horizontal sweep works
BSF INTCON,GIE ; Re-enable interrupts
RETURN
END