; ------------------------------------------------------------------------
;
; Title:
;
;   PG01 -- 10MHz PIC "4-wire" frequency generator: 100 kHz
;
; Function:
;
;   This PIC program uses PWM hardware to implement a digital frequency
;   divider. The external clock is divided by 100. For example if the
;   input clock is 10 MHz the output is a 100 kHz square wave.
;
; Diagram:
;                                ---__---
;                5V (Vdd)  +++++|1      8|=====  Ground (Vss)
;            10 MHz input  ---->|2  pG  7|+
;                              +|3  01  6|+
;                              *|4      5|---->  100 kHz output
;                                --------
; Notes:
;
;   Only 4 pins are required: power (2.0-5.5V), ground, input and output.
;   + Unused inputs pin7/GP0, pin6/GP1, pin3/GP4 are WPU.
;   * Optional MCLRE input pin4/GP3 is WPU (pull down to reset).
;   Input clock can be any frequency from 0 to 20 MHz.
;   Output frequency accuracy is the same as clock input accuracy.
;   Output drive current is 25 mA maximum per pin.
;   Coded for Microchip 12F683 (because it has CCP/PWM).
;
; Theory:
;
;   Some PIC dividers use software (isochronous code) to generate one
;   or more low frequency outputs. This divider uses the hardware PWM
;   feature to generate one high frequency square wave output.
;
; Version:
;
;   06-Apr-2013  Tom Van Baak (tvb)  www.LeapSecond.com/pic
;
; ------------------------------------------------------------------------

; Microchip MPLAB IDE assembler code (mpasm).

        list        p=pic12f683
        include     p12f683.inc
        __config    _EC_OSC & _FCMEN_OFF & _WDT_OFF

M_PERIOD    equ (d'25'-1)       ; period (units: Tcy)
N_WIDTH     equ d'12'           ; pulse width integer (Tcy)
F_WIDTH     equ d'2'            ; pulse width fraction (Tcy/4)

; PIC 12F683 power-on hardware initialization.

        errorlevel -302
        bsf     STATUS,RP0      ; bank 1
        clrf    ANSEL           ; all digital (no analog) pins
        clrf    OPTION_REG      ; enable WPU (NOT_GPPU=0)
        movlw   1<<GP4 | 1<<GP1 | 1<<GP0
        movwf   WPU             ; activate weak pullup input pin(s)
        movlw   ~(1<<GP2)
        movwf   TRISIO          ; set pin directions (0=output)
        movlw   M_PERIOD
        movwf   PR2             ; PWM period (Tcy units)

        errorlevel +302
        bcf     STATUS,RP0      ; bank 0
        movlw   0x07
        movwf   CMCON0          ; disable comparator
        movlw   0x00
        movwf   T2CON           ; 1x pre-scaler TMR2, not running yet
        movlw   N_WIDTH
        movwf   CCPR1L          ; PWM duty cycle integer (Tcy units)
        movlw   F_WIDTH<<4 | 0xC
        movwf   CCP1CON         ; PWM duty cycle fraction (Tcy/4 units)

; Main code does nothing (PWM toggles GP2/CCP1 pin).

        bsf     T2CON,TMR2ON    ; enable TMR2 starts PWM
        goto    $               ; cpu idle loop

        end
