; PIC 16F688 code for a simple "hello world": blink an LED
;
; ### license
;

        list p = 16f688
        include p16f688.inc
        errorlevel  -302        ; suppress banksel warning (302) from listing

        constant USING_WAIT_MACROS = 1
        include ../include/handy.inc

        __config DEFAULT_CONFIG

        ; This code runs at reset (and powerup)
        org     0x0000
reset:
        goto    main

        org     0x0004
interrupt:
        ; Interrupt handler: unused
        retfie


main:
        ; STATUS starts with b00011xxx. (note: bank0)
        ; OPTION_REG starts with 0xFF.
        ; INTCON starts with 0x00.
        ; PIE1 is ignored due to PEIE == 0
        ; OSCCON starts with b-110x000. (note: SCS == 0)

        ; Note: bank is ENOCARE. This will force bank 0.
        ; Disable comparators. We're going to use all RA* as OUTPUTS.
        disable_comparators
        ; Now in Bank 0

        ; Initialize PORTA/C (output-maybe) latches to the LOW state.
        clrf    PORTA
        clrf    PORTC

        bank1s
        no_analog               ; We want digital pins, not analog.

        ; TRISA/C start with b--111111. Set only RA0 as an OUTPUT
        bcf     TRISA, RA0

        ; Move to Bank 0 for the various blinking code scenarios.
        bank0s

  constant CYCLE = 1
  constant WDT = 2
  constant BLOCK = 3
; Compile-time switch to use a busy loop or the watchdog timer
if (STYLE == CYCLE)

BLINKY  equ     0x20

blink:
        movlw   5               ; 500k instructions @ 4 MHz == 0.5 seconds
        movwf   BLINKY
spin:
        call    delay100k

        decfsz  BLINKY, f
        goto    spin

        ; skip delay100k and head to flipping the LED
        goto    flip

DELAY_O equ     0x21            ; outer delay counter
DELAY_I equ     0x22            ; inner delay counter

; burn 99,934 cycles
delay100k:
        ; function will consume 2 + 99930 + 2 instructions (99,934)
        movlw   D'30'
        movwf   DELAY_O

        ; loop1 will consume 30*(1 + 3327 + 3) + 2 instructions (99,930)
loop1:
        clrf    DELAY_I

        ; loop2 will consume 255*(10 + 1 + 2) + 10 + 2 instructions (3,327)
loop2:
        wait_10
        decfsz  DELAY_I, f
        goto    loop2

        decfsz  DELAY_O, f
        goto    loop1

        return


else ; STYLE == CYCLE
if (STYLE == WDT)

        ; Continuation of 'main' function.

        ; Prepare WDT to wake us from sleep every 0.5 seconds
        ; Note: TIMER0/1 cannot wake the chip from sleep. Only WDT.

        ; Note: OPTION_REG is configured properly for our needs.

        ; Set WDTPS to 1:128, and (software-)enable the WDT:
        movlw   0x05
        movwf   WDTCON

        ; WDT input is 31 kHz, divided by 128 (WDTPS), and again by 128 (PS)
        ; gives us 1.89 wakeups per second.

blink:
        ; Good night!!
        sleep

        ; Did we wake due to WDT? (not sure why else, but check anyways)
        btfsc   STATUS, NOT_TO
        goto    blink
        ; FALLTHRU


else ; STYLE == WDT
if (STYLE == BLOCK)

        ; Continuation of 'main' function.
        bank1s
        prepare_timer0
        bank0s

blink:
        ; How many loops of 32.6ms should we run?
        ; NOTE: we're running at 4Mhz, so divide by 2.
        movlw   D'5000' / D'326' / 2 ; 500.0ms / 32.6ms / 2
        call    blockwait

else
 error "unknown style"
endif ; BLOCK
endif ; WDT
endif ; CYCLE

flip:
        ; flip the LED connected to RA0
        movlw   1 << RA0
        xorwf   PORTA, F

        goto    blink


; stupid assemblers don't realize EOF means *end*
        end
