Reputation: 31
I am trying to generate two outputs: a 20Hz square wave and a 30Hz square wave in assembly using a 6502 micro controller instruction set. So far, I can output on 20Hz wave:
%uasm65,title="SQUARES"
org 0200h
lda #1d
sta 0a200h
Main:
;jump to the subroutine Delay and do it
jsr Delay
lda 0a200h
inc Count1
lda Count1
cmp #3d
beq Reset1
jmp Main
Reset1:
lda #0d
sta Count1
lda 0a200h
eor #00000001b
sta 0a200h
jmp Main
Reset2:
jmp Main
Delay:
;Save registers on the stack.
pha
txa
pha
tya
pha
;Change the number that is being loaded into the
; 'A' register in order to change the delay time.
lda #01h
OutLoop:
ldx #04h
InLoop1:
ldy #0ffh
InLoop2:
dey
bne InLoop2
dex
bne InLoop1
sec
sbc #1d
bne OutLoop
;Restore registers from the stack.
pla
tay
pla
tax
pla
rts
Count1:
dbt 0d
Count2:
dbt 0d
end
%/uasm65
From my understanding, what I can do to accomplish this is to take a 60Hz square wave and use it to get a 30Hz and a 20Hz. How would output a 20Hz square wave to bit 5 of PortA and a 30Hz square wave to bit 6 of PortA without affecting the state of the other bits in the port? In other words, how do I get 20 and 30 from 60 here? Do I let the count check for 7 and increment count 2? any help would be greatly appreciated.
Upvotes: 1
Views: 365
Reputation: 364128
According to my reading of the instruction set, this should work and be shorter than Tommylee's code. (I used that as a starting point).
Counting towards zero is preferable in asm, if you use a decrement that sets the zero flag when the result reaches zero. Then you don't need a separate compare. This can get the code-size down to 0x1D
bytes (for my 2nd version).
I'm assuming that dec
with a memory operand still sets flags according to the result. I haven't looked at any 6502 docs other than wikipedia. :P The code in the question uses dey
/bne
, so I assume that's correct and sets flags.
Assuming that optimizing for fewer instructions is better, you should try to cut down the delay loop a lot. Maybe just nested loops of memory decrements with bne
as the loop condition (so you loop 2^n times)? Unless using memory costs more power?
Main:
ldx #3d ; 60/20 = 3: toggle every 3 iterations
; stx Count5 ; Count5 is for the 20 Hz bit wave on pin5
ldy #2d ; 60/30 = 2: toggle every 2 iteration
; sty Count6 ; Count6 is for the 30 Hz bit wave on pin6
; omit the stores: Count5 and Count6 are already initialized.
; lda 0a200h ; start with the initial state of the I/O port
lda #1d ; constant initial state
squarewave_loop:
jsr Delay
; lda 0a200h ; or do this here, so Delay doesn't have to save/restore A
dec Count1
bne skip1 ; toggle when it reaches zero
toggle_pin5:
stx Count5 ; reload first countdown counter
eor #00000001b
skip1:
dec Count2
bne skip2 ; toggle when it reaches zero
toggle_pin6:
sty Count6
eor #00000010b ; FIXME: which bit maps to bit6 of Port A?
skip2:
sta 0a200h ; always store, even if there was no state change
jmp squarewave_loop
Delay: [ ... ]
Count1:
dbt 3d
Count2:
dbt 2d
dey
/ dex
for count1/count2Then we don't need any memory to store the counters, and I assume instructions with memory operands have a longer encoding
Main:
ldx #3d ; 60/20 = 3: toggle every 3 iterations
ldy #2d ; 60/30 = 2: toggle every 2 iteration
; lda 0a200h ; start with the initial state of the I/O port
lda #1d ; constant initial state
squarewave_loop:
jsr Delay
; lda 0a200h ; or do this here, so Delay doesn't have to save/restore A
dex
bne skip1
;toggle_pin5: ; runs when 1st down-counter hits zero
ldx #3d ; reload the countdown
eor #00000001b
skip1:
dey
bne skip2
;toggle_pin6: ; runs when 2nd down-counter hits zero
ldy #2d
eor #00000010b ; FIXME: which bit maps to bit6 of Port A?
skip2:
sta 0a200h ; always store, even if there was no state change
jmp squarewave_loop
Delay: [ ... ]
This assembles on http://www.masswerk.at/6502/assembler.html, if I strip out the comments and remove the :
character from the end of labels. The total size, not counting the delay loop, is 0x1D bytes of code.
Upvotes: 2
Reputation: 2731
you need 2 separate counters, one for each pin
Main:
;jump to the subroutine Delay and do it
jsr Delay
lda 0a200h ; ?? what's this doing here?
inc Count1 ; count1 is for the 20 Hz bit pin
lda Count1
cmp #3d ; 60/20 = 3, so counter1 will have to reach 3
bne Skip1 ; otherwise skip toggling
toggle_pin5:
lda #0d ; reload first Counter
sta Count1
lda 0a200h
eor #00000001b
sta 0a200h
skip1:
inc Count2 ; count2 is for the 30 Hz bit pin
lda Count2
cmp #2d ; 60/30 = 2, so counter2 will have to reach 2
bne Skip2 ; you could also "bne Main" here
toggle_pin6:
lda #0d ; reload 2nd Counter
sta Count2
lda 0a200h
eor #00000010b ; you will want to change this for the correct value to "set bit6 of PortA"
sta 0a200h
skip2:
jmp Main
Reset1: ; not needed anymore
Reset2: ; not needed anymore
Delay: [ ... ]
Inside your loop, branching to Reset1 (or Reset2), and the jumping back to Main isn't such a good idea, you'd skip the 2nd check for the 2nd pin. Better just branch over the few instructions (as I did), or use a JSR/RET:
cmp #3d
bne SkipCall ; counter value NOT reached, so skip "Reset"
jsr Reset
SkipCall:
<...>
Reset:
lda #0d
sta Count1
<...>
ret
Upvotes: 3