;
;  Octave synthesizer PIC program series
;
;  OCT54ALL.ASM copyright (c) by Scott Rider 1997, all rights reserved
;
;  Octave tone source:12 equally-tempered semitones in parallel.
   Waveform is 50% duty (square) pulse for each pitch.
;  PIC uses 16MHz crystal, so use a fast PIC. ^^
;
;   12__
;   \/2 = 1.059463094
;
;  The top octave of frequencies:
;
;  C=/239 = 4186.01, B=/253 = 3951.07, A#=/268 = 3729.31, A=/284 = 3520.00
;  G#=/301 = 3322.44, G=/319 = 3135.96, F#=/338 = 2959.96, F=/358 = 2793.83, 
;  E=/379 = 2637.02, D#=/402 = 2489.02, D=/426 = 2349.32, C#=/451 = 2217.46
;  (C=/478 = 2093.00)
;
;  This program generates the scale down 4 octaves:
;
;  C3 (middle C) = 261.62Hz, B2 = 246.94Hz, A#2 = 233.08Hz
;  A2 = 220.00Hz, G#2 = 207.65Hz, G2 = 196.00, F#2 = 185.00Hz
;  F2 = 174.61Hz, E2 = 164.81Hz, D#2 = 155.56Hz, D2 = 146.83Hz
;  C#2 = 138.59Hz, (C2 = 130.81Hz)
;
;
;  The PIC16C54 as an octave divider looks like this:
;
;                     ________  ________
;                    |        \/        |
;               B2 --+ RA2          RA1 +-- A#2
;                    |                  |
;               C3 --+ RA3          RA0 +-- A2
;                    |                  |
;              N/C --+ RTCC     CLKI/X1 +--  \
;                    |                  |     16MHz crystal w/33pF caps
;       Tie to Vdd --+ !MCLR    CLKO/X2 +--  /  or 16MHz clock to CLKI
;                    |                  |
;              GND --+ Vss          Vdd +-- +5V
;                    |                  |
;              C#2 --+ RB0          RB7 +-- G#2
;                    |                  |
;               D2 --+ RB1          RB6 +-- G2
;                    |                  |
;              D#2 --+ RB2          RB5 +-- F#2
;                    |                  |
;               E2 --+ RB3          RB4 +-- F2
;                    |__________________|
;
;
	list    p=16c54
	radix   dec
	include "p16c5x.inc"

	__FUSES _CP_OFF & _WDT_OFF & _HS_OSC

C3      equ     60      ;31250 / 60 / 2 = 260.42 (261.62, -1.21) 0.46%
B2      equ     63      ;31250 / 63 / 2 = 248.02 (246.94, +1.08) 0.43%
AS2     equ     67      ;31250 / 67 / 2 = 233.21 (233.08, +0.13) 0.06%
A2      equ     71      ;31250 / 71 / 2 = 220.07 (220.00, +0.07) 0.03%       
GS2     equ     75      ;31250 / 75 / 2 = 208.34 (207.65, +0.69) 0.33%
G2      equ     80      ;31250 / 80 / 2 = 195.32 (196.00, -0.68) 0.35%

FS2     equ     84      ;31250 / 84 / 2 = 186.01 (185.00, +1.01) 0.54%
F2      equ     89      ;31250 / 89 / 2 = 175.56 (174.61, +0.95) 0.54%
E2      equ     95      ;31250 / 93 / 2 = 164.48 (164.81, -0.73) 0.21%
DS2     equ     101     ;31250 / 101 / 2 = 154.71 (155.56, -0.54) 0.55%
D2      equ     107     ;31250 / 107 / 2 = 146.03 (146.83, -0.50) 0.54%
CS2     equ     113     ;31250 / 113 / 2 = 138.28 (138.59, -0.31) 0.22%

C3mask  equ     b'00001000'
B2mask  equ     b'00000100'
AS2mask equ     b'00000010'
A2mask  equ     b'00000001'
GS2mask equ     b'10000000'
G2mask  equ     b'01000000'
FS2mask equ     b'00100000'
F2mask  equ     b'00010000'
E2mask  equ     b'00001000'
DS2mask equ     b'00000100'
D2mask  equ     b'00000010'
CS2mask equ     b'00000001'

tonesA  equ     PORTA
tonesB  equ     PORTB

	cblock  0x08
		C3reg
		B2reg
		AS2reg
		A2reg
		GS2reg
		G2reg
		FS2reg
		F2reg
		E2reg
		DS2reg
		D2reg
		CS2reg
		temp
	endc
;
;
;   Main code area
;
;
	org     0x100

start   movlw   b'00000110'     ;TMR0 clock = 1:128 of Fosc/4
	option                  ;31.25KHz TMR0 @ xtal=16MHz

	movlw   b'00000000'     ;Clear tone bits
	movwf   tonesA          ; /
	movwf   tonesB          ;/
	tris    tonesA          ;Tone bits are outputs
	tris    tonesB          ;/

	movlw   C3              ;Load tone period counters
	movwf   C3reg
	movlw   B2
	movwf   B2reg
	movlw   AS2
	movwf   AS2reg
	movlw   A2
	movwf   A2reg
	movlw   GS2
	movwf   GS2reg
	movlw   G2
	movwf   G2reg
	movlw   FS2
	movwf   FS2reg
	movlw   F2
	movwf   F2reg
	movlw   E2
	movwf   E2reg
	movlw   DS2
	movwf   DS2reg
	movlw   D2
	movwf   D2reg
	movlw   CS2
	movwf   CS2reg
;
;   Main loop.  TMR0 is set for 32us intervals (31,250Hz).  128 instruction
; cycles are available between successive ticks of TMR0 to check tone
; counters and toggle tone outputs.  Higher pitches are possible; the
; tradeoff being fewer tones can be implemented per PIC.  See other
; versions of the PIC octave divider in this series.
;
main    movf    TMR0,W          ;wait for clock tick
	movwf   temp

tick    movf    TMR0,W
	xorwf   temp,W
	btfsc   STATUS,Z
	goto    tick            ;/

m_c3    decfsz  C3reg,F         ;Check each tone counter...
	goto    m_b2
;
;  C3 ready to toggle
;
	movf    tonesA,W
	xorlw   C3mask          ;toggle C3 tone pin
	movwf   tonesA
	movlw   C3
	movwf   C3reg

m_b2    decfsz  B2reg,F
	goto    m_as2
;
;  B2 ready to toggle
;
	movf    tonesA,W
	xorlw   B2mask          ;toggle B2 tone pin
	movwf   tonesA
	movlw   B2
	movwf   B2reg

m_as2   decfsz  AS2reg,F
	goto    m_a2
;
;  A sharp 2 ready to toggle
;
	movf    tonesA,W
	xorlw   AS2mask         ;toggle AS2 tone pin
	movwf   tonesA
	movlw   AS2
	movwf   AS2reg

m_a2    decfsz  A2reg,F
	goto    m_gs2
;
;  A2 ready to toggle
;
	movf    tonesA,W
	xorlw   A2mask          ;toggle A2 tone pin
	movwf   tonesA
	movlw   A2
	movwf   A2reg

m_gs2   decfsz  GS2reg,F
	goto    m_g2
;
;  G sharp 2 ready to toggle
;
	movf    tonesB,W
	xorlw   GS2mask         ;toggle GS2 tone pin
	movwf   tonesB
	movlw   GS2
	movwf   GS2reg

m_g2    decfsz  G2reg,F
	goto    m_fs2
;
;  G2 ready to toggle
;
	movf    tonesB,W
	xorlw   G2mask          ;toggle G2 tone pin
	movwf   tonesB
	movlw   G2
	movwf   G2reg

m_fs2   decfsz  FS2reg,F
	goto    m_f2
;
;  F sharp 2 ready to toggle
;
	movf    tonesB,W
	xorlw   FS2mask         ;toggle FS3 tone pin
	movwf   tonesB
	movlw   FS2
	movwf   FS2reg

m_f2    decfsz  F2reg,F
	goto    m_e2
;
;  F2 ready to toggle
;
	movf    tonesB,W
	xorlw   F2mask          ;toggle F2 tone pin
	movwf   tonesB
	movlw   F2
	movwf   F2reg

m_e2    decfsz  E2reg,F 
	goto    m_ds2
;
;  E2 ready to toggle
;
	movf    tonesB,W
	xorlw   E2mask          ;toggle E2 tone pin
	movwf   tonesB
	movlw   E2
	movwf   E2reg

m_ds2   decfsz  DS2reg,F
	goto    m_d2
;
;  D sharp 2 ready to toggle
; 
	movf    tonesB,W
	xorlw   DS2mask         ;toggle DS2 tone pin
	movwf   tonesB
	movlw   DS2
	movwf   DS2reg

m_d2    decfsz  D2reg,F
	goto    m_cs2
;
;  D2 ready to toggle
;
	movf    tonesB,W
	xorlw   D2mask          ;toggle D2 tone pin
	movwf   tonesB
	movlw   D2
	movwf   D2reg

m_cs2   decfsz  CS2reg,F
	goto    main
;
;  C sharp 2 ready to toggle
;
	movf    tonesB,W
	xorlw   CS2mask         ;toggle CS2 tone pin
	movwf   tonesB
	movlw   CS2
	movwf   CS2reg

	goto    main            ;Worst case=86 cycles
;
;  Reset vector, 0x1FF
;
	org     0x1FF

	goto    start

	end
								      
