In this first example program we'll use the parallel port to toggle output lines to generate a square wave. This basic functionality is something we could do with a simpler PIA chip like the 6821.
We'll use Port A and just for fun we'll use all 8 output lines and output incrementing binary numbers so the PA0 line will toggle at the maximum rate, PA1 at half that rate, and so on to PA7.
The Replica 1 Multi I/O board brings these lines to a connector which you can connect to a circuit, breadboard, or in my case an oscilloscope.
The program is only a few lines of code. We need to set the Data Direction Register to all ones to make all ports outputs (1=output, 0=input). Then we simply write to the port output register to set the output (1=high, 0=low).
We want the loop to run as fast as possible to see how fast a frequency we can generate. The obvious code might be something like this:
LOOP:
CLC ; 2 cycles
ADC #$01 ; 4 cycles
STA PORTA ; 4 cycles
BVC LOOP ; 3 cycles if taken
This takes 13 cycles per loop iteration. However using an increment of the X or Y register is faster as we don't have to worry about the carry flag:
LOOP:
INX ; 2 cycles
STA PORTA ; 4 cycles
BVC LOOP ; 3 cycles if taken
This take 9 cycles. However, 9 is an odd number and 10 cycles would be a nice round value. Because the register is read/write, we can use the INC instruction to increment the timer value directly in one instruction. The absolute X addressing mode version of this instruction takes 7 cycles, which when added to the branch adds up to 10 as desired:
LDX #$00
STX PORTA
LOOP: INC PORTA,X ; 7 cycles
BVC Loop ; 3 cycles if taken
My Replica 1 has a 2MHz clock (the standard one is 1 MHz but I "overclocked" mine). With a 2MHz clock, one cycle of the square wave is two iterations of the loop, 2 * 10 or 20 clock cycles. 2000000 / 20 = 100 kHz on the PA0 line. PA1 will toggle at half that, 50 kHz, PA2 at 25 kHz, etc.
Here is the complete code.
; Experiment 1
;
; Toggle the port A output lines
; With 2MHz clock, 1 cycle is two iterations of the loop (2 * 10)
; 2000000 / 20 = 100 kHz on PA0 line.
; Could do this in 9 cycles but want a round number.
; PA1 is 50 kHz, PA2 is 25 kHz etc.
.include "6522.inc"
LDA #%11111111 ; Set port A to all outputs
STA DDRA
; Increment output to toggle all bits
CLV
LDX #$00
STX PORTA
Loop: INC PORTA,X ; 7 cycles
BVC Loop ; 3 cycles if taken
Here is my Multi I/O board showing the wire from PB7 going to my scope probe.
Multi I/O Board With Scope Probe Connected to PB7 |
Square Wave Output |
Note that this program takes all of the CPU resources to generate this square wave. In the next instalment we'll look at how the timer on the 6522 can generate pulses automatically.
OK, am I missing something?
ReplyDeleteWhy not just do:
LOOP:
INC PORTA
JMP LOOP
Would that not increase the port A value as fast as possible?
ReplyDeleteIn your second code example, you increment X but store A - typo?