; ------------------------------------------------------------------------
;
; Title:
;
;   PD34 -- PIC 10 MHz to 1PPS/2PPS frequency divider (4 pulse widths)
;
; Function:
;
;   This PIC program implements a digital frequency divider: cpu hardware
;   and isochronous software divide the input clock by 10 or 5 million.
;   When the external input clock is 10 MHz the output is 1 Hz or 2 Hz.
;
;   - The four outputs have the same period/frequency but different pulse
;     width: 100 us, 1 ms, 10 ms, 100 ms.
;
;   - The output frequency can be doubled by setting pin4/GP3 high. The
;     output is 1PPS (pin4 low) or 2PPS (pin4 high).
;
; Diagram:
;                                ---__---
;                5V (Vdd)  +++++|1      8|=====  Ground (Vss)
;         10 MHz clock in  ---->|2  pD  7|---->  1PPS out (100 us)
;       1PPS (100 ms) out  <----|3  34  6|---->  1PPS out (1 ms)
;               2PPS mode  o--->|4      5|---->  1PPS out (10 ms)
;                                --------
; Notes:
;
;   o Tie input pin4/GP3 to Vdd or Vss (do not leave open).
;   Output frequency accuracy is the same as clock input accuracy.
;   Output drive current is 25 mA maximum per pin.
;   Coded for Microchip 12F675 but any '609 '615 '629 '635 '675 '683 works.
;
; Version:
;
;   22-Jan-2014  Tom Van Baak (tvb)  www.LeapSecond.com/pic
;
; ------------------------------------------------------------------------

; Microchip MPLAB IDE assembler code (mpasm).

        list        p=pic12f675
        include     p12f675.inc
        __config    _EC_OSC & _MCLRE_OFF & _WDT_OFF

; Register definitions.

        cblock  0x20            ; define register base
        endc

PPa     equ     (1<<GP0)        ; bit mask for pin7/GP0 (100 us output)
PPb     equ     (1<<GP1)        ; bit mask for pin6/GP1 (1 ms output)
PPc     equ     (1<<GP2)        ; bit mask for pin5/GP2 (10 ms output)
PPd     equ     (1<<GP4)        ; bit mask for pin3/GP4 (100 ms output)

; One-time PIC 12F675 initialization.

        bcf     STATUS,RP0      ; bank 0
        movlw   0x07            ; turn comparator off
        movwf   CMCON           ;
        clrf    GPIO            ; set output latches low

        bsf     STATUS,RP0      ; bank 1
        errorlevel -302
        clrf    ANSEL           ; all digital (no analog) pins
        movlw   ~(PPa|PPb|PPc|PPd)
        movwf   TRISIO          ; set pin directions (0=output)
        errorlevel +302
        bcf     STATUS,RP0      ; bank 0

; With an external 10 MHz PIC clock the (4:1) execution rate is 2.5 MIPS.
; A 1,250,000 instruction cycle (Tcy=400 ns) loop takes exactly 0.5 second.
; A 2,500,000 instruction cycle (Tcy=400 ns) loop takes exactly 1 second.
; Generate pulse on 4 pins, each having successively wider pulse width.

loop:   movlw   PPa|PPb|PPc|PPd ; (      1)
        movwf   GPIO            ; (      1) rise: PPa PPb PPc PPd
        movlw   d'247'          ; (      1)
        call    DelayW1         ; (    247)
                                ; ---------> 250 Tcy = 100 us @ 10 MHz

        movlw   PPb|PPc|PPd     ; (      1)
        movwf   GPIO            ; (      1) fall: PPa
        movlw   d'22'           ; (      1)
        call    DelayW100       ; (   2200)
        movlw   d'46'           ; (      1)
        call    DelayW1         ; (     46)
                                ; ---------> 2500 Tcy = 1 ms @ 10 MHz

        movlw   PPc|PPd         ; (      1)
        movwf   GPIO            ; (      1) fall: PPb
        movlw   d'224'          ; (      1)
        call    DelayW100       ; (  22400)
        movlw   d'96'           ; (      1)
        call    DelayW1         ; (     96)
                                ; ---------> 25000 Tcy = 10 ms @ 10 MHz

        movlw   PPd             ; (      1)
        movwf   GPIO            ; (      1) fall: PPc
        movlw   d'22'           ; (      1)
        call    DelayW10k       ; ( 220000)
        movlw   d'49'           ; (      1)
        call    DelayW100       ; (   4900)
        movlw   d'95'           ; (      1)
        call    DelayW1         ; (     95)
                                ; ---------> 250000 Tcy = 100 ms @ 10 MHz

        movlw   0               ; (      1)
        movwf   GPIO            ; (      1) fall: PPd
        movlw   d'99'           ; (      1)
        call    DelayW10k       ; ( 990000)
        movlw   d'99'           ; (      1)
        call    DelayW100       ; (   9900)
        movlw   d'92'           ; (      1)
        call    DelayW1         ; (     92)
        btfsc   GPIO,GP3        ; (      1) check for 1 Hz vs. 2 Hz
          goto    loop          ; (      1/2)
        nop                     ; (      1)
                                ; ---------> 1250000 Tcy = 500 ms @ 10 MHz

        ; for 1 Hz output add extra 500 ms to period.

        movlw   d'124'          ; (      1)
        call    DelayW10k       ; (1240000)
        movlw   d'99'           ; (      1)
        call    DelayW100       ; (   9900)
        movlw   d'95'           ; (      1)
        call    DelayW1         ; (     95)
        goto    loop            ; (      2)
                                ; ---------> 2500000 Tcy = 1 s @ 10 MHz

        include delayw.asm      ; precise delay functions
        end
