0
votes

New to Arduino and trying to make a program that will toggle an LED module connected to pins 5,4 and 3 of PORTB (13,12 and 11 on the board).

The joystick has a connection to ground and a connection, from SW to pin 7 of PORTD (7 on the board).

The idea is to use assembly programming to do this. This is the program I have made so far (it may be very wrong as I'm learning as I go)

Update

I have tweaked my code and fixed some things. The Setup part runs and turns on the blue LED when I remove the apploop part. However, the apploop component doesn't work and the red LED is not triggered when I toggle the joystick. Have tried looking at other examples but haven't been able to fix it so far

Any pointers would be much appreciated!

   #include "m328pdef.inc"
.global main
.EQU Red_Pin, 17
.EQU Green_Pin, 16
.EQU Blue_Pin, 15
.EQU Led_Port, PORTB
.EQU Switch_Pin, 11
.EQU Switch_Port, PORTD
main:
appSetup:
; Init the 3 output RGB LED's
; in
in r16, Led_Port
; sbr
sbr r16, 0b11111111
; out
out DDRB, r16


; Init the input switch, configure with internal pull up resistor

; in
in r24, DDRD
; cbr
cbr r24, 0b10000000
; out
out DDRD,r24

; in 
in r24, Switch_Port

; sbr
sbr r24, 0b11111111

; out
out Switch_Port,r24


; Turn on the Blue Led to indicate Init is done!

; sbi

sbi Led_Port,3

appLoop:

; Switch pressed = Red Led on

; sbis
sbis Switch_Port, 7

; sbi
sbi Led_Port, 3
; Switch not pressed = Red Led off
; sbic
sbic Switch_Port, 7

; cbi
cbi Led_Port,3

; rjmp appLoop ; keep doing this indefinitely

rjmp appLoop
1
sbi takes a port number (not register) as first argument. - Erik Eidt
Ever looked how a compiler would do the job? (see what avr-objdump can do for you). You can start with plain avr-gcc and ignore the arduino layer. And remove that tag :) - datafiddler

1 Answers

0
votes
in r16, Led_Port  // <-- should be in r16, DDRB
; sbr
sbr r16, 0b11111111
; out
out DDRB, r16

read from PORTB, write to DDRB. Suspicious. Why all bits are set if only 3 are used as outputs?

in r24, DDRD
cbr r24, 0b10000000
out DDRD,r24

By the way, to change single bit in registers 0...31 (all PINx, DDRx, PORTx in ATmega328P are in this range) you can use sbi and cbi instructions. E.g.:

cbi DDRB, 7 // clear 7th bit of DDRB 
; in 
in r24, Switch_Port
; sbr
sbr r24, 0b11111111
; out
out Switch_Port,r24

Again, why all 8 bits are set if you need only one?

; Turn on the Blue Led to indicate Init is done!
sbi Led_Port,3

...

; Switch pressed = Red Led on
sbi Led_Port, 3

So, bit 3 of the Led_Port (PORTB) is red? Or blue?

There is a mess in your code. Named constants mixed with immediate values. If you use some named constants. Example:

.EQU LED_RED_pinno, 5
.EQU LED_BLUE_pinno, 3
...

; Turn on the Blue Led to indicate Init is done!
sbi Led_Port, LED_BLUE_pinno

...

; Switch pressed = Red Led on
sbi Led_Port, LED_RED_pinno

Also:

; sbis
sbis Switch_Port, 7
; sbi
sbi Led_Port, 3

sbis skips next instruction, if the bit 7 in Switch_Port is set. Switch_Port equals to PORTB, and it has its bit 7 is always cleared (unless you write 1 to it).

To check the state of an input port, you need to read PINx (not PORTx!) register. In this case it should be:

; Switch pressed = Red Led on
sbis PINB, 7  // (sic!)
sbi Led_Port, 3

; Switch not pressed = Red Led off
sbic PINB, 7 // (sic!)
cbi Led_Port,3