*****
*
*  This file contains all Examples for section 10 of the User's Manual
*
*****

** Equates - Registers will be addressed with Ind,X mode
*
REGBAS	EQU	$1000	Starting address for register block
PORTB	EQU	$04	Output port B
OC1M	EQU	$0C	OC1M7,OC1M6,OC1M5,OC1M4;OC1M3,-,-,-
OC1D	EQU	$0D	OC1D7,OC1D6,OC1D5,OC1D4;OC1D3,-,-,-
TCNT	EQU	$0E	Free running counter (16-bit)
TIC1	EQU	$10	IC1 register (16-bit)
TOC1	EQU	$16	OC1 register (16-bit)
TOC2	EQU	$18	OC2 register (16-bit)
TOC3	EQU	$1A	OC3 register (16-bit)
TCTL1	EQU	$20	OM2,OL2,OM3,OL3;OM4,OL4,OM5,OL5
TCTL2	EQU	$21	-,-,EDG1B,EDG1A;EDG2B,EDG2A,EDG3B,EDG3A
TMSK1	EQU	$22	OC1I,OC2I,OC3I,OC4I;OC5I,IC1I,IC2I,IC3I
TFLG1	EQU	$23	OC1F,OC2F,OC3F,OC4F;OC5F,IC1F,IC2F,IC3F
TMSK2	EQU	$24	TOI,RTII,PAOVI,PAII;-,-,PR1,PR0
TFLG2	EQU	$25	TOF,RTIF,PAOVF,PAIF;-,-,-,-

*** EVB Routine Addresses & Pseudo Vector Equates

.OUTA	EQU	$FFB8	Print character in A-reg
.OUTCRL	EQU	$FFC4	Output <cr><lf>
.OUTSTO	EQU	$FFCA	Output Msg seg (no <cr,lf>)
.OUTSTR	EQU	$FFC7	Output Msg w/ leading <cr,lf>

PVIC1	EQU	$00E8	EVB Pseudo Vector for IC1
PVTOF	EQU	$00D0	EVB Pseudo Vector for TOF
PVOC2	EQU	$00DC	EVB Pseudo Vector for OC2
PVOC1	EQU	$00DF	EVB Pseudo Vector for OC1

*** RAM Variable Assignments

	ORG	$D000	Start variables in EVB RAM (upper half)
	
HDLY	RMB	2	Half-cycle delay (in 0.5S increments)
PWMP1P	RMB	1	1% of PWM period (1 to 256 cycles) Ex 10-7
PWMDC1	RMB	1	Duty cycle for PWM signal at OC2 pin
PWMDC2	RMB	1	Duty cycle for PWM signal at OC3 pin
IC1DUN	RMB	1	flag: 0-not done,1-pulse measured
IC1MOD	RMB	1	s/w mode flag: FF-off,0-1st,1-last edge
OVCNT1	RMB	1	Overflow count (upper 8-bits of result)
RES1	RMB	2	Pulse Width in cycles (16-bits)
HTEMP	RMB	3	Temp for H6TOD8 (3 bytes)
FRSTE	RMB	2	Time of first edge (16-bits)
PERC	RMB	2	Period in cycles (16-bits)
TEMP1	RMB	2	Temp for conversion (16-bits)
FREQH	RMB	2	Freq in Hex (16-bits)
HPW	RMB	2	Pulse Width (16-bits hex)
DBUFR	RMB	8	Decimal result buffer (8 bytes ASCII)
* Some routines use only first 5 bytes of DBUFR
PWMPER	RMB	2	Period of PWM signals in (cycles)
OFFHI	RMB	2	OC2 high offset (calculated)
OFFLO	RMB	2	OC2 low offset (calculated)

	ORG	$C000	Prog starts in EVB RAM at $C000

***
*  TIMER EXAMPLE 10-1a  Measuring Period with Input Capture
*
* Uses polling rather than interrupts.
* Measures period between two rising edges at IC1 pin.
* Overflows not considered so max period is 65,535 cyc
* Min period measurable with this program is about 27 cyc
*
* This program runs on an EVB board and displays results
* on the EVB terminal display.
***

PERTOP	LDS	#$0047	Top of User's stack area on EVB
	LDX	#REGBAS	Point to register block
	LDAA	#%00010000
	STAA	TCTL2,X	EDG1B:EDG1A = 0:1, rising edges
	LDAA	#$04
	STAA	TFLG1,X	Clear any old OC1 flag

* Ready to detect first rising edge
	BRCLR	TFLG1,X	$04 *	Loop here until edge

* First edge detected
	LDD	TIC1,X	Read time of first edge
	STD	FRSTE	Save first capture value
	LDAA	#$04
	STAA	TFLG1,X	Clear IC1F before next edge

* Ready to capture time of second edge
	BRCLR	TFLG1,X	$04 *	Loop here until edge

* Second edge detected
	LDD	TIC1,X	Read time of second edge
	SUBD	FRSTE	2nd - 1st -> D
	STD	PERC	Save result (period in cycles)

* The period of the signal at the PA2/IC1 pin has been measured
* and the time is stored at "PERC" as a 16-bit hex number
* representing the number of CPU bus cycles that elapsed
* between two rising edges.

***
*  TIMER EXAMPLE 10-1b  Changing Period to Frequency
*
* The period found in example 10-1a is expressed as a number
* of bus cycles (@E=2MHz, 1 bus cycle=0.5S) and it is
* currently in the D-reg and at "PERC".  Values < or = $20
* will be considered too small (freq too high) to be
* accurately measured with this program and will be trapped
* out to make the period to frequency conversion program easier.
* $0021 corresponds to 60,606 Hz, $FFFF is 30.5 Hz.
***

	LDX	PERC	Period in cycles (16-bits)
	CPD	#32	($20) Check against min allowed
	BHI	OKP	Skip if OK
	JMP	OUTRNG	Else go say it was too small
OKP	LDD	#32	X=period; D=32
	FDIV		D/X -> X; r -> D
	STX	TEMP1	(Freq*16)1,000,000; radix left of MSB
*
* We now have frequency but it isn't in a good displayable
* form yet.  If we move the binary radix 16 places to the right
* we would have a 16-bit integer representing
* [(2**20)/(10**6) x freq] or [((1,048,576)/(1,000,000))*freq].
* By adding and subtracting binary multiples of the freq we
* will arrive at [((1,000,000)/(1,000,000))*freq]
*
*  1,048,576  16-bit starting value ((2**20)freq)(10**6)
* -   32,768  2**15
* -   16,384  2**14
* +      512  2**9
* +       64  2**6
* =1,000,000 * freq
*
* The limitation of 33 ($21) cycles min was selected so
* (1,048,576/1,000,000)*freq would fit in 16-bits so we would
* only need 1 FDIV.  Although it is pretty easy to extend the
* precision of an FDIV.
*
* The partial results which are added and subtracted in this
* program may have an error of 1 LSB ea. because I trunkated
* rather than rounding.
*
	LDD	TEMP1	(2**20)f; where f=freq(10**6)
	LSRD
	LSRD
	LSRD		A=(2**9)f; D=(2**17)f
	CLR	FREQH	Clear upper half of hex freq location
	STAA	FREQH+1	FREQH is a temp = 512f
	LSRD
	LSRD		now D=(2**15)f or 32,768f
	STD	TEMP1	Needs to be in mem for 16-bit subtract
	XGDX		D=(2**20)f; X=(2**15)f
	SUBD	TEMP1	First subtraction (-32K)
	XGDX		Working result -> X; D=(2**15)f
	LSRD		A=(2**6)f; D=(2**14)f
	STD	TEMP1	Put in mem so you can subtract
	ADDA	FREQH+1	(512+64)f
	STAA	FREQH+1	Update low half of FREQH
	XGDX		D=1,015,808*f; X=junk
	SUBD	TEMP1	999,424*f
	ADDD	FREQH	1,000,000*f = frequency
	STD	FREQH	Save the 16-bit binary result
*
* Since most of us don't think in hexidecimal, let's change to
* decimal before printing.  The subroutine (HTODP) is shown at
* the end of this listing.
*
* The display will look like...
*
*ppppp Cyc     fffff Hz      ---or like---
*Freq. is too high
*
* where ppppp is period in cycles & fffff is freq. (decimal)
*
* EVB subroutines will be used and when done we will jump
* back to the beginning and repeat continuously.
*
	JSR	.OUTCRL	Print a <cr,lf>
	LDX	#PERC	Point at hex period
	JSR	HTOD	Convert to 5 digit decimal
	JSR	P5DEC	Print 5 digi decimal (not leading 0s)
	LDX	#MSGCYC	Point at " Cycles     "
	JSR	.OUTSTO	Print message segment
	LDX	#FREQH	Point at hex frequency
	JSR	HTOD	Convert to 5 digit decimal
	JSR	P5DEC	Print 5 digi decimal (not leading 0s)
	LDX	#MSGHZ	Point at " Hz"
	JSR	.OUTSTO	Print message segment
JTOP	JMP	PERTOP	Go back to top & measure another period

OUTRNG	LDX 	#MSGER1	Point at "Freq. is too high"
	JSR	.OUTSTR	Print message w/ leading <cr,lf>
	BRA	JTOP	Go back to top & measure another period
*
***** END Ex 10-1b

***
*  TIMER EXAMPLE 10-2  Measuring Pulses With Input Capture
*
* Uses interrupts.
* Measures time between a rising edge and a falling edge
* (period of a positive pulse) at the IC1 pin.
* Overflows not considered so max is 65,536 cyc
* Min time measurable with this program is about __ cyc
*
* This program runs on an EVB board and displays results
* on the EVB terminal display.
***

* Initialization Portion
*
PWINZ	LDS	#$0047	Top of User's stack area on EVB
	LDAA	#$7E	Jump (extended) Opcode
	STAA	PVIC1	IC1 Pseudo Vector
	LDX	#SV2IC1	Address of IC1 service routine
	STX	PVIC1+1	Finish jump instruc to IC1 routine

* Main Program Portion of Pulse Width program
*
PWTOP	LDX	#REGBAS	Point to register block
	LDAA	#%00010000	Top of Main for PW24 prog
	STAA	TCTL2,X	EDG1B:EDG1A = 0:1, IC1 rising edges
	LDAA	#$FF
	STAA	IC1MOD	FF-IC1 off; 0-1st edge; 1-last edge
	CLR	IC1DUN	Signal pulse not done
	BCLR	TFLG1,X $FB	clear IC1F (if any)
	BSET	TMSK1,X $04	enable IC1 interrupts
	CLI		Enable Interrupts

WAITL2	LDAA	IC1DUN	Sets after pulse done
	BEQ	WAITL2	Tight loop till pulse has been timed
	SEI		Pulse done, disable interrupts

* Display pulse width as xx,xxx microseconds (32,768 max)
	JSR	.OUTCRL	Begin printing result
	LDD	HPW	number of cyc (0.5S/cyc)
	LSRD		16-bit 2 to change to S
	BCC	ARNUP2	? need to round result ?
	ADDD	#1	yes; round up
ARNUP2	STD	HPW	Update hex Pulse width
	LDX	#HPW	Point at hex pulse width
	JSR	HTOD	Convert to 5 digit decimal
	JSR	P5DEC	Print 5 digi decimal (not leading 0s)
	LDX	#MSGMS	Point at rest of display line
	JSR	.OUTSTO	Print " millieconds"
	BRA	PWTOP	Goto top of main & repeat
*
* END of Main Program Portion

***
* SV2IC1 - Input Capture 1 service routine
*
* Called first when a rising edge is detected and again when
* a falling edge is detected.
***
SV2IC1	LDX 	#REGBAS	point at top of register block
	INC	IC1MOD	$FF->0 at 1st edge; 0->1 at 2nd
	BNE	NO1ST2	if not 0, this is trailing edge

* Process leading edge of pulse
	LDD	TIC1,X	read time of first edge
	STD	FRSTE	save till next capture
* Reconfigure IC1 for trailing falling edge
	BCLR	TCTL2,X $30	EDG1B:EDG1A->0:0
	BSET	TCTL2,X $20	EDG1B:EDG1A->1:0
	BRA	OU2IC1	done processing first edge

* Process trailing edge of pulse
NO1ST2	LDD	TIC1,X	get time of trailing edge
	SUBD	FRSTE	time of last minus time of first
	STD	HPW	update result
	BCLR	TCTL2,X $30	disable IC1
	LDAA	#1
	STAA	IC1DUN	signal pulse measured
OU2IC1	BCLR	TFLG1,X $FB	clear IC1F
	RTI		** Return from IC1 service **
*
***** END Ex 10-2

***
*
*  TIMER EXAMPLE 10-3  Measuring Long Periods with IC
*
* Uses interrupts.
* Measures period between two rising edges at the IC1 pin.
* Overflows are counted so max is 16,777,215 cyc (~8.38 Sec)
* Min time measurable with this program is about 70 cyc
*
* This program runs on an EVB board and displays results
* on the EVB terminal display.
***

* Initialization Portion
*
P24INZ	LDS	#$0047	Top of User's stack area on EVB
	LDAA	#$7E	Jump (extended) Opcode
	STAA	PVTOF	TOF Pseudo Vector see manual text
	STAA	PVIC1	IC1 Pseudo Vector
	LDX	#SV3TOF	Address of TOF service routine
	STX	PVTOF+1	Finish jump instruc to TOF routine
	LDX	#SV3IC1	Address of IC1 service routine
	STX	PVIC1+1	Finish jump instruc to IC1 routine

* Main Program Portion of PER24 program
*
PER24T	LDX	#REGBAS	Point to register block
	LDAA	#%00010000	Top of Main for PER24 prog
	STAA	TCTL2,X	EDG1B:EDG1A = 0:1, IC1 rising edges
	LDAA	#$FF
	STAA	IC1MOD	FF-IC1 off; 0-1st edge; 1-last edge
	CLR	IC1DUN	Signal period not done
	BCLR	TFLG1,X $FB	clear IC1F (if any)
	BCLR	TFLG2,X $7F	clear TOF (if any)
	BSET	TMSK1,X $04	enable IC1 interrupts
	BSET	TMSK2,X $80	enable TOF interrupts
	CLI		Enable Interrupts

WAITL3	LDAA	IC1DUN	Sets after pulse done
	BEQ	WAITL3	Tight loop till pulse has been timed
	SEI		Pulse done, disable interrupts

* Display period as x.xxxxxx Seconds (to nearest S)
	LDX	#OVCNT1	Point at upper byte of 6 digit hex
	LSR	0,X	24-bit 2 to change to S
	ROR	1,X	(1cyc=0.5S)
	ROR	2,X	RORs include carry
	BCC	ARNUP3	? need to round result ?
	INC	2,X	yes; round up
	BNE	ARNUP3	carry to middle byte ?
	INC	1,X	yes
	BNE	ARNUP3	carry to high byte ?
	INC	0,X	yes
ARNUP3	JSR	H6TOD8	Convert to 8 digit decimal
	JSR	.OUTCRL	Begin printing result
	LDX	#DBUFR+1 Start at 2nd digit (1st is 0)
	LDAA	0,X	Seconds digit
	JSR	.OUTA	Print
	LDAA	#'.'	ASCII period
	JSR	.OUTA	Print
DUMPLP	INX		Advance pointer to next digt
	LDAA	0,X	get digit
	JSR	.OUTA	Print it
	CPX	#DBUFR+7	Was that the last ?
	BNE	DUMPLP	If not continue
	LDX	#MSGSEC	Point at rest of display line
	JSR	.OUTSTO	Print " Seconds"
	BRA	PER24T	Goto top of main & repeat
*
* END of Main Program Portion

***
* SV3TOF - Timer Overflow service routine
*
* Called whenever any timer overflow is detected.  If the IC1
* pulse measurement is in progress (IC1MOD positive) then
* the overflow counter (upper 8-bits of period) is incremented.
***
SV3TOF	TST	IC1MOD	if 0 or 1, IC1 active so count TOFs
	BMI	OU3TOF	if neg, IC1 not active
	INC	OVCNT1	increment IC1 overflow count
OU3TOF	LDAA	#$80
	STAA	REGBAS+TFLG2	Clear overflow flag
	RTI		** Return from TOF service **

***
* SV3IC1 - Input Capture 1 service routine
*
* Called first when a rising edge is detected and again when
* another rising edge is detected.
***
SV3IC1	LDX 	#REGBAS	point at top of register block
	INC	IC1MOD	$FF->0 at 1st edge; 0->1 at 2nd
	BNE	NO1ST3	if not 0, this is second edge

* Process first edge of pulse
	CLR	OVCNT1	Zero the overflow count
	LDD	TIC1,X	Read time of first edge
	STD	RES1	Save till next capture
	BMI	OU3IC1	Done if IC was before any overflow
	LDAA	TFLG2,X	Check for TOF in MSB
	BPL	OU3IC1	If no overflow, you're done
	DEC	OVCNT1	This TOF shouldn't count
* decrement OVCNT1 to -1, TOF svc routine will inc to zero
	BRA	OU3IC1	Done processing first edge

* Process second edge of pulse
NO1ST3	LDD	TIC1,X	Get time of second edge
	BMI	ARNOV1	If MSB=1, skip TOF check
	TST	TFLG2,X	Check for overflow
	BPL	ARNOV1	If no TOF, skip increment
	INC	OVCNT1	TOF was before edge so count it
ARNOV1	SUBD	RES1	Time of last minus time of first
	STD	RES1	Update result
	BCC	RES1OK	Check for borrow
	DEC	OVCNT1	If borrow, fix overflow count
RES1OK	BCLR	TCTL2,X $30	Disable IC1
	LDAA	#1
	STAA	IC1DUN	Signal pulse measured
OU3IC1	BCLR	TFLG1,X $FB	Clear IC1F
	RTI		** Return from IC1 service **
*
***** END Ex 10-3

***
*
*  TIMER EXAMPLE 10-4  Simple Output Compare Example
*
* Ex10-4 uses polled mode.
* Generate a 10mS period like you would use to time an EE write
* but rather than wearout the EEPROM just change an output pin
*
* Example 10-4 runs on an EVB board and drives PB0 high for
* 10mS once every 30mS so you can see on an oscilloscope.
***

INZA	LDX	#REGBAS	Point to register block
	LDAA	#$80
	STAA	TFLG1,X	Clear any pending OC1F flag
	CLR	PORTB,X	Initialize port B to zeros

TOP4A	LDAA	#1	Top of Ex10-4a
	STAA	PORTB,X	Set LSB of port B

* This is where the 10mS delay part actually starts
*
	LDD	TCNT,X	Get current timer count
	ADDD	#20000	What will count be in 10mS?
	STD	TOC1,X	Set OC1 to trigger then
LP1	BRCLR	TFLG1,X $80 LP1	Loop here till OC1F=1
*
*Delay is actually done here; rest is just support

	BCLR	TFLG1,X $7F	Clear OC1F
	CLR	PORTB,X	Clear PB0 pin
	LDY	#5710	5710*(7~/loop)= about 20mS	
DLP1	DEY		Top of software delay loop
	BNE	DLP1	Loop 'till Y is zero
	BRA	TOP4A	Repeat continuously for O-scope
*
***** END Ex 10-4

***
*
*  TIMER EXAMPLE 10-5  Square wave using Output Compare
*
* Ex10-5 uses interrupts.
* Generate a square wave at the PA6 output pin using OC2
*
* This program runs on an EVB board.  The half-cycle delay
* time is entered into the double byte variable "HDLY" at
* $D000,D001 with a memory modify before going to the program.
***

TOP5	LDS	#$0047	Top of User's stack area on EVB
	LDAA	#$7E	Jump (extended) Opcode
	STAA	PVOC2	OC2 Pseudo Vector see manual text
	LDX	#SV5OC2	Address of OC2 service routine
	STX	PVOC2+1	Finish jump instruc to TOF routine
	LDX	#REGBAS	Point to register block
	LDAA	#%01000000	OM2:OL2 = 0:1
	STAA	TCTL1,X	Setup OC2 for toggle on each compare
	STAA	TFLG1,X	Clear any pending OC2F
	STAA	TMSK1,X	Enable OC2 interrupts
	CLI		Enable Interrupts
	BRA	*	Interrupt driven; so twiddle thumbs

***
* SV5OC2 - Output Compare 2 service routine
*
* Called at each OC2 interrupt.
***
SV5OC2	LDD 	HDLY	Get delay time for 1/2 cycle
	ADDD	TOC2,X	Add to last compare value
	STD	TOC2,X	Update OC2 (schedule next edge)
	BCLR	TFLG1,X $BF	Clear OC2F
	RTI		** Return from OC2 service **
*
***** END Ex 10-5

***
*  TIMER EXAMPLE 10-6
*    OC1, OC2, and OC3 used together to produce 2 PWM signals
*
* OC1 controls two pins of port A in conjunction with OC2 and OC3
* OC1 drives the period and the scheduling of OC2 and OC3
* OC2 & OC3 automatically control pins but don't generate interrupts
* Set "PWMP1P", "PWMDC1" & "PWMDC2" manually before running this example
* "PWMP1P" sets size of a 1% segment of PWM period (cycles)
*	min PWMP1P for this program is 2 (period = 200 cycles)
* "PWMDC1" sets Duty cycle for OC2 pin in % (0 to $64 hex)
* "PWMDC2" sets Duty cycle for OC3 pin in % (0 to $64 hex)
* Duty cycle (%)  will be translated into a # of cycles offset
* and period will be calculated as (100 * PWMP1P) at prog start
* PA4 pin will toggle at each OC1 compare as a scope reference signal
*
* Produces high going PWM signals of the period and duty cycle specified.
* Note actually only produces PWMs of 50% to 100% because spec'd duty of
* 0 to 50% is changed to low going PWM w/ duty cyc = [100% - spec(0-50)]
*
* This program runs on an EVB board and drives output pins.
* An oscilloscope is used to study the results.
***

INZ6	LDS	#$0047	Top of User's stack area on EVB
	LDAA	#$7E	Jump (extended) Opcode
	STAA	PVOC1	OC1 Pseudo Vector see manual text
	LDX	#SV6OC1	Address of OC1 service routine
	STX	PVOC1+1	Finish jump instruc to OC1 routine
	LDX	#REGBAS	Point to register block
	LDAA	#%01010000	OMx:OLx = 0:1 for toggle
	STAA	TCTL1,X	OC2 and OC3 for toggle
	LDAA	#%01110000	OC1M6,5, & 4 = 1
	STAA	OC1M,X	To control OC2/PA6, OC3/PA5, & PA4
	CLRB		Build OC1D initial value in B
	LDAA	PWMDC1	Check for OC2 duty > or = 50%
	CMPA	#50
	BLS	ARNZ61	If <50% OC1 drives low, OC2 toggles high
	ADDB	#%01000000	else OC1 drives high, OC2 toggles low
ARNZ61	LDAA	PWMDC2	Check for OC3 duty > or = 50%
	CMPA	#50
	BLS	ARNZ62	If <50% OC1 drives low, OC3 toggles high
	ADDB	#%00100000	else OC1 drives high, OC3 toggles low
ARNZ62	STAB	OC1D,X	Store starting value for OC1D
* Calculate period & duty cycle as cycle count offsets
	LDAA	PWMP1P	1% of period
	LDAB	#100
	MUL		100 * PWMP1P = PWMPER
	STD	PWMPER	Store period
	STD	TOC1,X	Start first PWM period at TCNT=PWMPER
	LDAA	PWMDC1	Calculate offset for OC2
	BSR	CALOFF	Adj duty as needed and calc offset
	STD	TOC2,X	Schedule first OC2 toggle
	LDAA	PWMDC2	Calculate offset for OC3
	BSR	CALOFF	Adj duty as needed and calc offset
	STD	TOC3,X	Schedule first OC3 toggle
* Finish initialization	
	LDAA	#$80
	STAA	TFLG1,X	OC1F=1 to clear any old OC1 flag
	STAA	TMSK1,X	then OC1I=1 to enable OC1 interrupt
	CLI

	BRA	*	From now on OC1 interrupt runs PWMs

*** Local subroutine for changing  duty cycle to an offset count
*	If duty < 50% ($32) change to 100-duty
*	If duty >100% ($64) force to $64
*	Finally mult by 1% of period (cyc)
*	Enter with PWMDCx duty in A-reg, Return offset in D-reg
CALOFF	CMPA	#50	Check for 0-49%
	BHS	ARN6A	Around fixup
	TAB		If < 50% - set to 100 - duty cycle
	LDAA	#100
	SBA		A-B to A
ARN6A	CMPA	#100	Check for > 100%
	BLS	ARN6B
	LDAA	#100	If > 100% - set to 100%
ARN6B	LDAB	PWMP1P
	MUL		PWMP1P * adjusted duty cycle = OFFOCx
	RTS		** Return from CALOFF **
*
**

***
* SV6OC1 - Output Compare 1 service routine
***
SV6OC1	LDX	#REGBAS	Point to register block
	LDAA	OC1D,X	Make PA4 change state at next OC1 compare
	EORA	#%00010000	Inverts OC1D4 bit (PA4 pin control)
	STAA	OC1D,X	Update next OC1 automatic pattern
	LDD 	TOC2,X	Get last OC2 compare value
	ADDD	PWMPER	Add count equiv to period
	STD	TOC2,X	Update OC2 (schedule next OC2)
	LDD 	TOC3,X	Get last OC3 compare value
	ADDD	PWMPER	Add count equiv to period
	STD	TOC3,X	Update OC3 (schedule next OC3)	
	LDD 	TOC1,X	Get last OC1 compare value
	ADDD	PWMPER	Add count equiv to period
	STD	TOC1,X	Update OC1 (schedule next OC1)
	BCLR	TFLG1,X $7F	Clear OC1F
	RTI		** Return from OC1 service **
*
***** END Ex 10-6

***
*  TIMER EXAMPLE 10-7
*    OC2 used alone to produce one PWM signal
*
* OC2 controls period and duty cycle of one port A pin
* Set "PWMP1P" & "PWMDC1" manually before running this example
* "PWMP1P" sets size of a 1% segment of PWM period (cycles)
* "PWMDC1" sets Duty cycle for OC2 pin in % - NOTE: This program will
*   not work properly with values of duty cycle too near 0 or 100%
*   Refer to User's Manual text for discussions
* Program calculates "OFFHI" and "OFFLO" at start
*
* This program runs on an EVB board and drives the PA6/OC2 pin.
* An oscilloscope is used to study the results.
***

INZ7	LDS	#$0047	Top of User's stack area on EVB
	LDAA	#$7E	Jump (extended) Opcode
	STAA	PVOC2	OC2 Pseudo Vector
	LDX	#SV7OC2	Address of OC2 service routine
	STX	PVOC2+1	Finish jump instruc to OC2 routine
	LDX	#REGBAS	Point to register block

	LDAA	PWMDC1	Calculate OC2 high time
	LDAB	PWMP1P	1% of period
	MUL		PWMP1P * duty cycle = high part of period
	STD	OFFHI	Save high offset
	LDAA	PWMP1P	1% of period
	LDAB	#100
	MUL		100 * PWMP1P = period
	SUBD	OFFHI	period - high time = low time
	STD	OFFLO	Store low offset

* Finish initialization	
	LDAA	#%11000000	OM2:OM1 = 1:1 for set pin high
	STAA	TCTL1,X	First OC2 starts first high time
	LDD	#$0000
	STD	TOC2,X	Start first PWM period at TCNT=$0000
	LDAA	#$40
	STAA	TFLG1,X	OC2F=1 to clear any old OC2 flag
	STAA	TMSK1,X	then OC2I=1 to enable OC2 interrupt
	CLI
	
	BRA	*	From now on OC2 interrupt runs PWM

***
* SV7OC2 - Output Compare 2 service routine
***
SV7OC2	LDX	#REGBAS	Point to register block
	BRCLR	TCTL1,X %01000000 ADDLO	See which half of cyc
	LDD	OFFHI	High part so we will add OFFHI to OC2
	BRA	UPOC2
ADDLO	LDD	OFFLO	Low part so we will add OFFLO to OC2
UPOC2	ADDD	TOC2,X	Add to last compare value
	STD	TOC2,X	Update OC2 (schedule next edge)
	LDAA	TCTL1,X	Change OL2 to setup for next edge
	EORA	#%01000000	Inverts OL2 bit
	STAA	TCTL1,X	Update control reg
	BCLR	TFLG1,X $BF	Clear OC2F
	RTI		** Return from OC2 service **
*
***** END Ex 10-7

***
* General purpose subroutines
***

***
* P5DEC - Subroutine to display a five digit decimal number at "DBUFR".
*	  Prints in the form "xx,xxx" with leading zeros suppressed.
*	  Prints 6 columns, leading spaces, units always prints (0-9)
*
* Calls EVB routine ".OUTA"
* Calls "SKP1" with BSR to advance X and print a leading space
*  SKP1 subroutine immediately follows P5DEC
* All registers are unchanged upon return from P5DEC
***

P5DEC	PSHX		Save registers
	PSHB
	PSHA
	LDX	#DBUFR	Point at decimal (MS character)
	LDAA	#$30	Chk for leading 0s (ASCII)
	CMPA	0,X	Check 10,000s digit
	BNE	P10K	Start at 10k digit
	BSR	SKP1	INX & print a space
	CMPA	0,X	Check 1,000s digit (a still=ASCII<sp>)
	BNE	P1K	Start at 1k digit
	BSR	SKP1	INX & print a space
	BSR	SKP1	INX & print a space (extra 1 for ,)
	DEX		just wanted the <sp> so back up 1
	CMPA	0,X	Check 100s digit
	BNE	P100	Start at 100s digit
	BSR	SKP1	INX & print a space
	CMPA	0,X	Check 10s digit
	BNE	P10	Start at 10s digit
	BSR	SKP1	INX & print a space
	BRA	P1	Start at 1s digit (default)

P10K	LDAA	0,X	10,000s digit
	JSR	.OUTA	Print 10,000s digit
	INX		Advance pointer to next digt
P1K	LDAA	0,X	1,000s digit
	JSR	.OUTA	Print it
	LDAA	#','	ASCII comma
	JSR	.OUTA	Print
	INX		Advance pointer to next digt
P100	LDAA	0,X	100s digit
	JSR	.OUTA	Print it
	INX		Advance pointer to next digt
P10	LDAA	0,X	10s digit
	JSR	.OUTA	Print it
	INX		Advance pointer to next digt
P1	LDAA	0,X	1s digit
	JSR	.OUTA	Print it
	PULA		Restore registers
	PULB
	PULX
	RTS		** Return from P5DEC **

*** Local SKP1 subroutine (called from above with BSRs)
SKP1	PSHA		Save A
	INX		Advance X
	LDAA	#$20	ASCII <sp>
	JSR	.OUTA	Print the <sp>
	PULA		Restore A
	RTS		** Return from SKP1 **

***
* HTOD - Subroutine to convert a 16-bit hex number to a
*	  5 digit decimal number.
*
* Uses 5 byte variable "DBUFR" for decimal ASCII result
* On entry X points to hex value to be converted & displayed
* All registers are unchanged upon return
***

HTOD	PSHX		Save registers
	PSHB
	PSHA
	LDD	0,X	D=hex value to be converted
	LDX	#10000
	IDIV		freq10,000 -> X; r -> D
	XGDX		Save r in X; 10,000s digit in D (A:B)
	ADDB	#$30	Convert to ASCII
	STAB	DBUFR	Store in decimal buffer
	XGDX		r back to D
	LDX	#1000
	IDIV		r1,000 -> X; r -> D
	XGDX		Save r in X; 1,000s digit in D (A:B)
	ADDB	#$30	Convert to ASCII
	STAB	DBUFR+1	Store in decimal buffer
	XGDX		r back to D
	LDX	#100
	IDIV		r100 -> X; r -> D
	XGDX		Save r in X; 100s digit in D (A:B)
	ADDB	#$30	Convert to ASCII
	STAB	DBUFR+2	Store in decimal buffer
	XGDX		r back to D
	LDX	#10
	IDIV		r10 -> X; r in D (B is units digit)
	ADDB	#$30	Convert to ASCII
	STAB	DBUFR+4	Store to units digit
	XGDX		10s digit to D (A:B)
	ADDB	#$30	Convert to ASCII
	STAB	DBUFR+3	Store in decimal buffer
	PULA		Restore registers
	PULB
	PULX
	RTS		** Return **

***
* H6TOD8 - Subroutine to convert a 24-bit hex number to an
*	  8 digit decimal number.
*
* Uses 3 byte variable "HTEMP" for hex working value
* Uses 8 byte variable "DBUFR" for decimal ASCII result
* On entry X points to hex value to be converted & displayed
* All registers are unchanged upon return
***

H6TOD8	PSHY		Save registers
	PSHX
	PSHB
	PSHA
	LDD	1,X	Move hex to HTEMP for conversion
	STD	HTEMP+1	Two lower bytes moved
	LDAA	0,X	Upper byte
	STAA	HTEMP
	LDY	#DBUFR	Point at MS digit of decimal buffer
	LDX	#CON10M	Point at first 24-bit constant

HTDLP	CLRA		A keeps track of # of subtractions
HLPIN	INCA		Inner loop; once per subtraction
	LDAB	HTEMP+2	Start 24-bit subtract
	SUBB	2,X
	STAB	HTEMP+2	Update low byte
	LDAB	HTEMP+1	Middle byte
	SBCB	1,X	Sub with carry
	STAB	HTEMP+1	Update middle byte
	LDAB	HTEMP	High byte
	SBCB	0,X
	STAB	HTEMP	Update high byte
	BCC	HLPIN	If no borrow; subtract again

	LDAB	HTEMP+2	Last subtract too far; add back
	ADDB	2,X	
	STAB	HTEMP+2	Update low byte
	LDAB	HTEMP+1	Middle byte
	ADCB	1,X	Sub with carry
	STAB	HTEMP+1	Update middle byte
	LDAB	HTEMP	High byte
	ADCB	0,X
	STAB	HTEMP	Update high byte

	ADDA	#$2F	Convert digit to ASCII
	STAA	0,Y	Store to decimal buffer
	INY		Point to next decimal digit
	INX		Point to next 24-bit const
	INX
	INX
	CPX	#CONEND See if done yet
	BNE	HTDLP	If not done, do nxt digit

	LDAA	HTEMP+2	Get 1s digit
	ADDA	#$30	Convert to ASCII
	STAA	0,Y	Store to last decimal digit
	
	PULA		Restore registers
	PULB
	PULX
	PULY
	RTS		** Return from H6TOD8 **
*
* Display Messages & Constants
*
MSGCYC	FCC	' Cycles     '
	FCB	$04	End-of-message mark
MSGHZ	FCC	' Hz'
	FCB	$04	End-of-message mark
MSGER1	FCC	'Freq. is too high'
	FCB	$04	End-of-message mark
MSGMS	FCC	' microseconds'
	FCB	$04	End-of-message mark
MSGSEC	FCC	' Seconds'
	FCB	$04	End-of-message mark

CON10M	FCB	$98,$96,$80 = 24-bit equiv of 10,000,000 
	FCB	$0F,$42,$40 = 24-bit equiv of 1,000,000
	FCB	$01,$86,$A0 = 24-bit equiv of 100,000
	FCB	$00,$27,$10 = 24-bit equiv of 10,000
	FCB	$00,$03,$E8 = 24-bit equiv of 1,000
	FCB	$00,$00,$64 = 24-bit equiv of 100
	FCB	$00,$00,$0A = 24-bit equiv of 10
CONEND	EQU	*	Don't need 1s const


* END OF FILE
