Arduinoinlineassembly Sample
Arduinoinlineassembly Sample
Eli
Preface........................................................................................................iv
Background
ATMEL Studio.............................................Error! Bookmark not defined.
Arduino’s Number Formats.........................Error! Bookmark not defined.
Basic asm....................................................Error! Bookmark not defined.
Extended asm ............................................................................................. 1
Clobbers......................................................Error! Bookmark not defined.
Constraints ..................................................Error! Bookmark not defined.
Basics
Ports and Pins.............................................Error! Bookmark not defined.
Status Register............................................Error! Bookmark not defined.
Basic Bit Operations ...................................Error! Bookmark not defined.
Bit Shifts ......................................................Error! Bookmark not defined.
Basic Math ..................................................Error! Bookmark not defined.
Branching ....................................................Error! Bookmark not defined.
Strings .........................................................Error! Bookmark not defined.
Applications
Functions.....................................................Error! Bookmark not defined.
Interrupts .....................................................Error! Bookmark not defined.
Tables..........................................................Error! Bookmark not defined.
ii
Examples ....................................................Error! Bookmark not defined.
Advanced
Assembly Listing .........................................Error! Bookmark not defined.
Startup Code ...............................................Error! Bookmark not defined.
Cycle Counting............................................Error! Bookmark not defined.
AVR 8-bit Instruction Set.............................Error! Bookmark not defined.
Appendix
A.AVR 8-bit Instruction Set......................Error! Bookmark not defined.
B.Modifiers and Constraints ....................Error! Bookmark not defined.
C.References...........................................Error! Bookmark not defined.
D.Port and Pin Compendium................................................................... 5
iii
Preface
Motivation
At least I did.
Hopefully this series of tutorials will help alleviate many of the discouraging
troubles I encountered while teaching myself inline assembly coding. An Arduino
Inline Assembly Tutorial was long overdue!
iv
It is important to realize this book assumes at least a basic understanding of the
underlying Arduino hardware (ports, timers, interrupts, USART, I2C, SPI, etc.).
Hopefully the reader has already written programs for the Arduino utilizing the
functionality provided by the IDE, or has a general understanding of
microcontroller programming. A wealth of information on the Arduino boards
and software is available at the website:
http://www.arduino.cc/
There are times when using assembly is needed, and however, many cases when
it is not. Here are some advantages to using inline assembly:
v
However, assembly is a very low-level language (the lowest above hand-coding
the binary instructions). This means,
Here are some general guidelines for including inline assembly code:
Even when assembly is absolutely required, you'll probably find that you can get
away with far less than you initially think need.
Legal Information
Although the electronic design of the Arduino boards is open source (Creative
Commons CC-SA-BY License) the Arduino name, logo and the graphics design of
its boards is a protected trademark of Arduino LLC.
Atmel®, the Atmel logo and combinations thereof, and others are the registered
trademarks or trademarks of Atmel Corporation of its subsidiaries.
vi
Chapter 4
Extended asm
This statement is divided by colons into (up to) four parts. While the code part is
required, the others are optional:
For now, we are going to ignore parts 2 through 4 and concentrate on the code
part of the statement.
void setup() {
Serial.begin(9600);
1
asm (
"ldi r26, 42 \n" //load register r26 with 42
"sts (a), r26 \n" //store r26 in a’s memory location
);
Serial.print("a = ");
Serial.println(a);
}
void loop() { }
To fully understand what we are doing here first we need to cover some
background.
Memory
The Arduino has 3 basic types of memory, flash, SRAM and EEPROM. Flash is
the memory where our program is stored. Arduino flash is non-volatile
storage1 where data can be retrieved even after power has been cycled (turned off
and then back on). When you upload an Arduino program, it gets loaded into
flash memory.
EEPROM2 is a form of non-volatile storage used for variable data that we want to
maintain between operations of our program.
SRAM is the memory used to store variable information and data. SRAM is
volatile storage3, and anything placed here is immediately lost when power is
removed. In our program above, variable a is stored in SRAM. For now, we are
not concerned about EEPROM or Flash memory, and will concentrate on SRAM.
1
See https://en.wikipedia.org/wiki/Non-volatile_memory.
2
See https://en.wikipedia.org/wiki/EEPROM.
3
See https://en.wikipedia.org/wiki/Volatile_memory.
2
As you can imagine, the Arduino has more than 32 registers. Registers also have
lots more specific details about them, but for now, these first 32 are more than
enough.
Assembly Instructions
Our inline assembly consisted of just two instructions, LDI and STS:
In our program, we load the value “42” into register #26, r26 (pedantically we
take note, r26 is actually the 27th register, since numbering starts at zero). We
could have chosen r18, r19 or even r24 for that matter. Later, our register
selection will become crucial, but for now #26 seems like a good choice.
The LDI instruction is followed by an STS instruction. STS is a mnemonic for
“STore direct to data Space”. STS stores one byte from a Register into SRAM, the
data space. In our inline code, we place the contents of register #26, r26 into the
memory location of variable a. Quietly, behind the scenes, the assembler replaces
“a” with the memory location of a. Neat.
Our program finishes by printing the contents of variable location a through the
Serial Terminal. Hopefully this produces the output:
a = 42
Furthermore, since the default Arduino compilation uses the –Os optimization
level, we must declare it “volatile”, so the optimizer doesn’t eliminate it. The
optimizer is very good at what it does, like when it sees code that’s not necessary,
it will artfully remove it. In our case here, we don’t want this code to be removed.
4
See https://ucexperiment.wordpress.com/2015/01/02/arduino-stack-painting/.
3
More to Come
With these two beginning chapters we have covered the fundamentals of the
inline assembler, basic syntax and a few assembler instructions. We will continue
looking at the extended inline assembler, introducing new instructions as we go.
Next, we’ll look at the “clobber list” then dive into the bizarre world of input and
output operands.
4
Appendix D
Port and Pin Compendium
analogWrite
This inline code writes an analog value (in the form of a PWM wave) to a
particular pin. After executing, the pin will generate a steady square wave of the
specified duty cycle until the next call (or call to digitalRead() or digitalWrite() on
the same pin). The frequency of the PWM signal on most pins is approximately
490 Hz. On the Uno and similar boards, pins 5 and 6 have a frequency of
approximately 980 Hz. On Arduino boards with the ATmega168/328, this
function works on pins 3, 5, 6, 9, 10, and 11. The analogWrite function has
nothing to do with the analog pins or the analogRead function.
A pinMode() call is included inside this function, so there is no need to set the pin
as an output before executing this code.
This version of AnalogWrite, with no frills saves ~542 bytes over the built-in
function:
5
//6: (TIMER0A) PD6/TCCR0A/COM0A1/OCR0A
//9: (TIMER1A) PB1/TCCR1A/COM1A1/OCR1A
//10: (TIMER1B) PB2/TCCR1A/COM1B1/OCR1B
//11: (TIMER2A) PB3/TCCR2A/COM2A1/OCR2A
//set below 6 defines per above table
#define ANALOG_PORT PORTB
#define ANALOG_PIN PORTB3
#define ANALOG_DDR DDRB
#define TIMER_REG TCCR2A
#define COMPARE_OUTPUT_MODE COM2A1
#define COMPARE_OUTPUT_REG OCR2A
asm (
"sbi %0, %1 \n" //DDR set to output (pinMode)
"_SetLow: \n"
"cbi %2, %1 \n" //set low
"rjmp _SkipPWM \n"
"_SetPWM: \n"
"ld r24, X \n"
"ori r24, %3 \n"
"st X, r24 \n" //connect pwm pin timer# & channel
"st Z, %6 \n" //set pwm duty cycle (val)
"_SkipPWM: \n"
6
analogRead
The Arduino board contains a 6 channel, 10-bit analog to digital converter which
is the brains beneath the analogRead function. It maps input voltages between 0
and 5 into integer values between 0 and 1023, thus yielding a resolution between
readings of: 5/1024 units or, 0.0049 volts (4.9 mV) per unit. The input range and
resolution can be changed through the ANALOG_V_REF define. This code reads
the value from the specified analog channel (0-7), which correspond to the analog
pins (note, do NOT use A0-A7 for the channel number in this code).
While this version of analogRead (aRead) saves a few bytes (~50), it also gives
the option of changing the speed via the ADC prescaler. However, don’t
arbitrarily change the prescale without understanding the consequences. ATMEL
advises the slowest prescale should be used (PS128). A higher speed (smaller
prescale) reduces the accuracy of the AD conversion. The Arduino sets the
prescale to 128 during initiation, just as the code below does.
asm (
"andi %1, 0x07 \n" //force pin==0 thru 7
"ori %1, (%6<<6) \n" //(pin | ADC Vref)
"sts %2, %1 \n" //set ADMUX
7
"sts %3, r18 \n" //set ADCSRA
return result;
}
pinMode(OUTPUT)
The Arduino pinMode function configures pin behavior. The code presented from
here on, has been previously explained.
asm (
"sbi %0, %1 \n" //1=OUTPUT
asm (
"cbi %0, %2 \n"
"sbi %1, %2 \n"
pinMode (INPUT)
8
asm (
"cbi %0, %2 \n"
"cbi %1, %2 \n"
digitalWrite HIGH
If a pin has been configured as an OUTPUT, its voltage will be set to the
corresponding value: 5V (or 3.3V on 3.3V boards) for HIGH, 0V (ground) for
LOW. However, if the pin is configured as an INPUT, digitalWrite enables
(HIGH) or disables (LOW) the internal pullup on the input pin.
asm (
"sbi %0, %1 \n"