I've been playing around with an arduino for the past few weeks now (no concrete project just messing around with the hardware and software) and in the last few days I've delved heavily into assembly language programming, so I wanted to share my experiences and programs, with two goals in mind. To educate others who want to start learning assembler, and to have others who are knowlegeable in low level programming to evaluate it.
The first Program I wrote was basically a copy of the helloworld (blink on/blink off) program listed elsewehere on these forums, I wont go indepth for the initial setup for compilers/editors. I am running gnu-linux (Gentoo) and I installed an avr assembler (avra) and avrdude to burn to the chip. I wrote a simple script to invoke both programs without having to constantly retype the command parameters. All my programing was done in a low-level text editor (nano) with no syntax highlighting or error checking.
Here is a dissection of my "hello world2" program.
The arduino is set up with two LED's on arduino pin 12 and pin 13, and a push switch (wired to +5v with a pull-down to ground) on pin PIN2. The basic idea is that the lights switch based on the status of the switch.
all my commentary/descriptions are done in code
;; Simple program to read a switch pin, and turn on an LED if the switch
;; is pressed, uses Arduino pin 13 (PORTB5) as the on LED
;; and pin 12 (PORTB4) as the off LED, pin 2 (PORTD2) as the switch pin
.nolist
.include "m168def2.inc" ; Assembly include statement
.list
.equ ONPin = 5 ;equivelant of a #define statement, makes it easier to remember the name
.equ OFFPin = 4
rjmp main
main:
;; the next few lines of code set up the pins on the arduino
;;ldi, is the command LoaDImediate, i.e. save the value to the specified register.
;; NOTE: this command only works on the registers r16-r32(general use registers) registers r1-r15, are
;; program registers (used as working space for calculations by the program) and above r32 are all the
;; ports/special purpose registers and sram
;; the command out, is used to write the contents of the specified register to the portregister,
;;NOTE this command only works on the first 32 ports registers, the rest are memory mapped (linked to
;;sram registers, and you have to use commands like lds and sts to read and store their values (the
;;proccesor treats those ports as though they are part of the sram), check the .inc file (m168def.inc) or
;; or the atmega 168 datasheet to see which ports are memory mapped (all the serial intergace stuff is
;; memory mapped)
ldi r16,255
out DDRB,r16 ;B ports (pins 8-13) are out
com r16
out DDRD,r16 ;D ports pins (0-7) are in
;; the following loop polls the status of the "D" port pin number 2 with the command
;;"sbic port,bit#" if the bit is clear i.e. 0, it skips over the next command (which in this case is a jump
;; to the label "on"
loop:
sbic PIND,2 ;skip next command if switch is off
rjmp on ;jump to on
rjmp off
on:
sbi PORTB,ONPin ;set ONPIN status to HIGH
cbi PORTB,OFFPin ;set OFFPIN status to LOW
rjmp loop ;back to the beginning
off:
sbi PORTB,OFFPin
cbi PORTB,ONPin
rjmp loop
The equivelant in arduino pseudo c code would be
int ONLed = 13;
int OFFLed = 12;
int SwitchPin = 2;
int switchVal=0;
void setup(){
PinMode(ONLed,OUT);
PinMode(OFFLed,OUT);
PinMode(SwitchPin,IN);
}
void loop(){
val = digitalRead(SwitchPin)
if(val==HIGH){
DigitalWrite(ONLed,HIGH);
DigitalWrite(OFFLed,LOW);
}
else{
DigitalWrite(OFFLed,HIGH);
DigtalWrite(ONLed,LOW);
}
}
The two invaluable resources that I had where the atmega168 datasheet (invaluable in the example I will post next), and this Website, which is a bit hard to navigate and understand at times, but is enormous help. Just do not take copy his examples word for word, some of the ports (the serial ports and ADC ports) are not memory mapped on the chip he uses, so the commands he uses are incompatible with the atmega 168