First we are going to make our Tiny85 blink the
green LED by using a simple delay routine. Then
we will modify the program further to accomplish the blinking
by use of a timer interrupt.
JustAsm
I created this blog so I would have a place to put assembly language examples and beginners help documents. The blog will cover the Parallax Propeller, the AVR and the MSP430 uC's
Friday, July 30, 2010
Sunday, July 18, 2010
Propeller 1
The Parallax Propeller is an 8.00 USD uC that
has 8 cores (processors) inside of it. each one
can run at 100+Mhz and perform about 25,000,000
instructions per second (25mips) Each core has its
own video generating hardware!
This uC is so wonderfully different that when many first
see it they go through three stages in rapid succession. These
were pointed out by a forum member at Parallax (localroger)
WTF? OMG! LOL After this initial reaction the new initiate
is usually seen stumbling away, mumbling to himself "No
interrupts! No interrupts at all!"
And, is this chip ever rugged! Just look at this video.
Chip Temperature Test
There is a free open-source C compiler available for the
propeller and also a fine commercial C compiler. For BASIC
fans there is a great free compiler called PropBASIC. You
can also write a lot of great code using the Propeller's built-in
language called SPIN, this tiny interpreter is a compact, elegant
marvel. But for the fastest code ever you will benefit by writing
PASM code to run in the cog ram. You can have some cogs
running PASM, some running BASIC, some running C...it's
all up to you!
Here is an image of the chip's silicon wafer.
Notice the eight 512x32 ram locations across the top.
This ram is where your assembly language will be placed.
This is the fastest memory on the uC. You can page in
more asm code from the 32kb of ram you can see at the
bottom but there is a speed hit involved. Don't worry
though as a lot can be done in the 512x32 ram directly
available to each processor.
If you are not already a Parallax Propeller user you should
go the their website and download the free propeller manual.
(right click the .PDF link and choose "save link as" to download the manual)
You should also download the free Spin Tool software.
You will find it listed on the downloads page.
There is a free Propeller simulator called Gear. You should
get a copy so that you can use it to run your asm (Propeller assembly is usually called PASM) code without the need to
even have a Propeller chip. http://sourceforge.net/projects/gear-emu/
I will add to this post later...I'm busy now setting up
a large solderless breadboard for the first assembly
program for the Propeller chip. It will be a standard
turn on an LED "Hello World" type of asm program.
The circuit I have placed on the breadboard is directly
from the Propeller manual. It includes a 5.00Mhz crystal
and a 32kb eeprom chip. The eeprom is where the code
you write is stored. When the Propeller boots up it pulls
this code into the 32kb of ram you see at the bottom of
the image above
Here is the large breadboard almost done. I just need
to add the crystal and an LED and resistor to it.
This is one of those really cheap Asian import breadboards
that you get on ebay for 16.00 shipping included. I put the
5v and 3.3v regulators on the bottom beneath the terminal
blocks that you see. I used a 7905 for the 5v and a 317T
with 2 Voltage setting resistors for the 3.3 there are four
rubber feet on the bottom of the breadboard that keep the
regulators from touching whatever surface you place it on.
This cheap setup is perfect for experimenting. Later on, after
I introduce the ATmega1284p uC I will add it to this breadboard
and show how these two uC's can work together to create some
truly powerful projects. These two chips working together are
an order of magnitude more powerful than something like an
Arduino!
I am going to start off with some very minimal PASM
programs so that I can explain exactly what each and every
line does.
So, here is the smallest one possible. All it does is enter
and stay in an endless loop. So basically it does nothing :-)
And here it is as text, so you can copy it and paste
it into the Propeller Tool IDE.
cognew(@A, 0)
DAT
A jmp #A
You can actually compile this in the Propeller Tool and
output it to the eeprom. The Propeller chip will run it..but
you won't really be able to tell since it does nothing...hmm
Here is another very tiny pasm program that actually turns on
an LED connected between Pin P0 and GND. (P0 is pin 1)
See the correct pin in the upper left corner of this image?
Here is an image of this tiny PASM program running in
a Propeller chip.
Please note the resistor between the pin and GND
it is used to limit the current to the LED and is very
important! (I think I used a 1k)
You may have noticed I did not place a crystal on the
breadboard. We are running the Propeller in what is
known as RCFAST mode using its internal RC clock
oscillator. It is fast enough for these early minimal PASM
programs.
Now here is a modification of the last PASM program. This
actually blinks the LED but it is blinking so very fast that the
human eye can not discern it. Below you can see pin1 toggling
rapidly in the Logic Probe pane of the Gear simulator. This is
what it would look like if you attached an oscilloscope to pin1
and gnd.
I would post an image of this modified program running but the
image would look identical to the last one, except the LED would
be slightly dimmer since it is off half the time.
These tiny PASM programs are really rather pointless, but
they do serve the purpose of letting a newbie actually type in
some PASM code, compile it, and write it to the eeprom so they
can watch it run on a Propeller chip. This can actually be a big
hurdle sometimes and once you get past these initial baby steps
everything becomes much easier :-)
I am expecting readers to be able to figure out from the help
docs on the Parallax site how to use things like the propeller
Tool IDE and Gear. But if you do have any problems please
post a comment and I will try to clarify things.
Now I am going to explain, in detail, every single line of these
short PASM programs. I will also point out what is missing
from them that really should be there, things like comments
and more pertinent names for loops and labels. I made things
as short and sweet as possible in the hope it would not add
to the initial confusion we all have when looking at a new asm
dialect.
I have re-written the simple PASM program that toggles pin1
(P0) This version is more or less the way a seasoned PASM
coder would write a simple program like this.
The first line
{{FastBlink.spin}}Is just a comment that displays the name of the program.
Anything between {}or after a ' on a line is always a
comment, meant only for humans reading the program listing.
Comments are good! use them!
The Next Line is
CON
This marks the start of a Constant Block.
This is where you declare constants that the program
will use and where you set Propeller configuration
settings. We have no constants to define in our simple
program but we do have some configuration settings to
detail.
The next line
_clkmode = xtal1 + pll16x
Tells the compiler that we are choosing to use a crystal
for our system clock and that we want the pll (phase lock
loop) inside the Propeller to multiply the crystals frequency
by 16.
This next line tells the compiler that out chosen crystal is
a 5Mhz one so after multiplying by 16 our clock frequency
will be 80Mhz
_xinfreq = 5_000_000
The propeller executes an instruction every 4 cycles so at
80Mhz it can run up to 20,000,000 instructions a second
in each of its 8 cogs.
PUB
Declares a code section that does some work and then returns
some result value. Our simple program actually has no useful
value to return so it returns a zero. There can be several PUB
blocks within your program (Object)
This line starts a new processor (cog) and loads it with 2KB
of hub ram. The location in hub ram to fetch the code from
is located by the label "Loop" ...the compiler knows where
this 2kb of data is to be found...it always fetches exactly 2kb
starting at the location of label "Loop"
In this instance the 2kb of program data will be loaded into
cog1, cog0 is running the program we have written above.
All our program really does is cause the tiny PASM program
contained in the DAT section to be loaded into cog1 and run.
Once cog1 is running our tiny pin toggling program the SPIN
program in cog0 is finished.
Just keep in mind that this code
{{FastBlink.spin}}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB Main
{start a new cog to run our PASM code}
cognew(@Loop,0) 'launch cog, fill the cog ram with data from hub ram
Is high level interpreted SPIN language running in cog0 and
that what it does is cause this code
Loop mov dira, #1 'set pin1 to be an output
xor outa, #1 'this flips pin1 each time it runs (1 becomes 0) (0 becomes 1)
jmp #Loop 'loop forever by jumping back to A
To be placed into the ram of cog1 and run.
Now I realize that it is hard at first to get your head around the
idea that there are actually 8 separate processors running at once.
You write a high level program using SPIN in one processor to
load other programs into other processors and start them running.
It's just a totally different world than how things are done on a
single core uC like an AVR. Once this all sinks in you will simply
gasp at the power and the possibilities! :-)
Just hang in there, enlightenment will come suddenly.
DAT
The DAT declares a data block.
This code section is where all of your PASM code goes.
Various types of data also get stored in here. This all gets
loaded to cog ram when the 2kb gets pulled in from hub memory
to the cog ram space by this command cognew(@Loop,0)
This next line is pretty self explanatory.
org 0 'make the code located at Loop begin at cog mem address 0
It is not strictly required in this particular instance, but I
strongly suggest always using it, even in a simple PASM
example such as this.
Next we have this line.
Loop mov dira, #1 'set pin1 to be an output
dira is the direction register for port A
It is 32 bits long and holds the direction states for the 32
I/O pins of the Propeller chip. If a particular pin has a
corresponding 1 in its dira bit then it is set up as an output.
If 0 then it is an input. The I/O pins are numbered from 0-31
or P0-P31. All cogs have access to the I/O pins at all times.
Just how this works will be made clear in a future blog posting.
The label at the start of that line
loop
could actually have been placed on a line of its own, it would
have made no difference whatsoever, it's just a label that the
compiler takes notice of to designate a location in memory.
Loop
mov dira, #1 'set pin1 to be an output
Works just the same.
The # mark before the number 1 in that line is VERY
important, without it the code means something very different
than it does if it is included.
mov dira, #1 sets the dira register to
00000000_00000000_00000000_00000001
whereas
mov dira, 1 would set the dira register to whatever value
might be held in cog memory location 1. This is a very
different effect indeed!
Next the line
xor outa, #1 'this flips pin1 each time it runs (1 becomes 0) (0 becomes 1)
This flips the value of pin1 each time the line is executed.
xor is a very handy way to accomplish bit flipping. We will
look further at it at a later time. Again the # is very important
and without it you would be xor'ing the outa register with whatever
value was in memory location one instead of the number 1.
OUTA is the output register for PortA. Writing a 1 to a bit set
as an output on portA will cause that pin to go to VCC, setting
it to zero sets the port to gnd.
Finally, our last line is
jmp #Loop 'loop forever by jumping back to Loop
This just causes our small program to continuously jmp
back up to the line designated by the label "Loop"
Again, the # is very important!
Here is a screenshot of our toggling program now
running at 20,000,000 ips and toggling pin1 (P0) millions
of times a second. Notice that the Gear simulator can't really
keep up at that rate and the display is just a band. On a real
scope you would still see a nice square wave pattern.
couple of new AVR posts :-)
Saturday, July 17, 2010
AVR3
I just put the circuit together so you can see
the last program actually running and lighting
up the LED on a Tiny85 pin 5 (PortB 0)
I used a 7905 5v negative regulator instead of a 7805
positive regulator because that's all I could find in my
part drawer. It works fine for this. Between the regulator
top and the little orange wire are 6 socket holes. These
are where I plug the 6 wires from the STK500 programmer
into the solderless breadboard to program the flash
memory using AVR Studio. If you have a solderless
breadboard you can assemble an identical circuit from
this image. Now look at the image below, it is a blowup
of the 6 pin holes for the programming cable.
Socket hole 5 is for the VCC wire (+5v)
Socket hole 6 is for the MOSI wire
Socket hole 7 is for the GND wire
Socket hole 8 is for the RESET wire
Socket hole 9 is for the SCK wire
Socket hole 10 is for the MISO wire
Note what pins the leads for MOSI, RESET, SCK and
MISO route to on the Tiny85. The GND and VCC just
connect to any handy socket where GND and 5v are
available.
the last program actually running and lighting
up the LED on a Tiny85 pin 5 (PortB 0)
I used a 7905 5v negative regulator instead of a 7805
positive regulator because that's all I could find in my
part drawer. It works fine for this. Between the regulator
top and the little orange wire are 6 socket holes. These
are where I plug the 6 wires from the STK500 programmer
into the solderless breadboard to program the flash
memory using AVR Studio. If you have a solderless
breadboard you can assemble an identical circuit from
this image. Now look at the image below, it is a blowup
of the 6 pin holes for the programming cable.
Socket hole 5 is for the VCC wire (+5v)
Socket hole 6 is for the MOSI wire
Socket hole 7 is for the GND wire
Socket hole 8 is for the RESET wire
Socket hole 9 is for the SCK wire
Socket hole 10 is for the MISO wire
Note what pins the leads for MOSI, RESET, SCK and
MISO route to on the Tiny85. The GND and VCC just
connect to any handy socket where GND and 5v are
available.
Here is an image of my solderless board with the
makeshift programming cable connected.
Notice in the upper left corner of the breadboard where
I drilled a small hole and ran the power leads through it
for strain relief. This is handy :-)
I want you to be absolutely certain of how to connect
the wires to the end of the 10-pin programming cable.
This image shows the cable end, please note the orientation
of the connector and where the red stripe is on the cable!
Ok, starting at the top left corner and moving right. The first
pin is MOSI the center top pin is RESET the 4th pin from
left is SCK and the rightmost top row pin is MISO.
The far left pin on the lower row is VCC (5v)
and the 2nd pin from the left is GND.
The other pins need not connect to anything, only these
six are important. Some people use a smaller six pin cable
for programming, but I find it difficult to find the connectors
and sockets for the six pin cables so I use the older 10 pin
style cables. If you need help with the six pin type send me
a message and I will detail the pinout.
===========================
I will be posting some short videos so I went and got an
account on youtube today.
There is nothing there yet so be patient. I will post videos
of the next two projects running. They will both be
interrupt driven LED blinkers.
AVR2
Here is the hello world program for the Tiny85.
All this does is turn on a single LED connected
to pin 5 (Port B bit 0)
Here is the code followed by a complete description
of every line.
Ok, firstly, anything following a ; is considered by
the assembler to be just a comment. So the entire
section
; ********************************************
; * Tiny85LEDON *
; * 07/17/2010 *
; ********************************************
is nothing but a comment and means nothing to
the assembler...this is stuff just for you the programmer
to read and use.
these lines cause a large file of definitions
and such to be loaded and processed by the
assembler.
.NOLIST
.INCLUDE "tn85def.inc"
.LIST
The include file named tn85def.inc is the important
thing here. The .NOLIST and .LIST are there just to
keep the AVR Studio IDE from displaying the huge
tn85def.inc file when it produces a list file. You don't
need to see all the stuff inside that file, it's mostly
boring and you need not think about it. Each AVR
model has its own def file that details stuff like the names
of the registers, amounts of memory..etc..etc If you
don't include this file you cannot use the simple names
for things like I/O registers and would have to enter
the addresses instead, that would suck because it would
make assembly programming much more tedious.
The line
.def temp =r16
defines the word temp to mean the same thing as r16.
Now you can just type temp and the assembler will
translate that to r16 (working register 16) there are 32
working registers that each hold one byte(8 bits). Registers
16-31 are more useful than the others especially 30 and 31
because this pair can hold a word (16 bit number)
This long list of interrupt vectors is not strictly
needed but we will include it for now since it will
help you to understand that the first several bytes
of memory are meant to hold these vectors.
rjmp Start ; Reset vector
reti ; Int vector 1
reti ; Int vector 2
reti ; Int vector 3
reti ; Int vector 4
reti ; Int vector 5
reti ; Int vector 6
reti ; Int vector 7
reti ; Int vector 8
reti ; Int vector 9
reti ; Int vector 10
reti ; Int vector 11
reti ; Int vector 12
reti ; Int vector 13
reti ; Int vector 14
The first one is memory location zero, this is the first
byte of code that runs when you power up an AVR.
Putting this line
rjmp Start ; Reset vector
In this spot is not required but is much recommended!
rjmp means relative jump and it sends the AVR down to
where your actual program starts at the label Start:
It thus jumps over all the other interrupt vector bytes
which are filled with the reti command. This is the
return from interrupt code and usually is found at the
very end of an interrupt service routine. It serves well
here as a sort of placeholder that will if ever called
just bounce your program out of any interrupt that jumps
to it.
Notice the ; in each of these short lines of code, it means
that the text on the line following the ; is just a comment.
Ok, this next line is called a label. This is just a name you
make up to tell the assembler where a particular place in
memory is.
Start:
Don't forget to put labels starting in the first column and
never ever forget the : at the end! Also don't use a name
reserved by the assembler for something else such as
PORTB: all hell would break loose if you tried it! :-)
Labels don't take up memory space in the AVR, they
are simply a way for the assembler to locate a place in
memory when it assembles your source code.
ser temp ;set temp (r16) to 0b11111111
ser means SEt Register
What it does is it moves 0b11111111 into a register
quickly. It is the fastest way to do this and you will
use this instruction often. Note that it only works on
working registers 16-31 !!!
0b11111111 is the proper way to write a binary value
for the assembler to understand. Hexadecimal is written
like this 0xFF or $FF these three numbers
0b11111111
0xFF
$FF
All equal decimal 255, you can use decimal in the assembler,
it is the default base and so you could simply write 255.
(you do know computer arithmetic? I hope so because I
am not planning on reviewing it here...there are many fine
tutorials already on the web)
out DDRB,temp ;copy temp to I/O register DDRB
;making port B pins all outputs
the out instruction copies the value in a working register
into an I/O register. You cannot move a number directly
into an I/O register, you must copy it over from a working
register!
Copying the value 0b11111111 into DDRB will make
all the pins of PortB outputs. If a bit is set to a 1 then
the corresponding pin is an output, if the bit is a 0 then
that pin is an input.
clr temp ;set temp to 0b00000000
The clr instruction sets a working register to 0b00000000
clr stands for CLear Register.
out PortB,temp ;set all port B pins low
This turns off all the I/O pins on PortB. They will thus
be at ground potential. If a bit in PortB holds a zero then
it's corresponding pin is low.
Ok, now we get to the line that actually will turn
our LED on!
sbi PortB,0 ;set PortB pin 0 high
sbi sets a bit in an I/O register to a one. This makes it
high (at vcc usually 5v) so this line sets pin 0 at 5v and
if an LED is connected from this pin to ground (through
a current limiting resistor) it will light up!
loop: rjmp loop ; loop 4ever
This is the last line in our small program. It just creates
an endless loop, you can never let the AVR just wonder
off when its program ends! You must put it into some
sort of loop, or put it to sleep :-)
If you run this in the AVR Studio IDE and look at the
simulator over on the right and click on PortB you will
see this
Notice that DDRB has been set to all ones by the code line
out DDRB,temp
Remember that temp held 0b11111111 when it's value was
copied to DDRB.
And notice that pin zero of PortB is indeed turned on,
it is at vcc (usually 5v)
I will try to actually build up a small circuit for the next
post so you can actually see this program running on a
Tiny85 and lighting up an LED.
After that perhaps we will alter this program and
let an interrupt service routine turn the LED on.
It is easy to blink the LED using a Timer interrupt
or you can use a button connected to an input pin
to turn it on when a pin change interrupt is triggered.
All this does is turn on a single LED connected
to pin 5 (Port B bit 0)
Here is the code followed by a complete description
of every line.
Ok, firstly, anything following a ; is considered by
the assembler to be just a comment. So the entire
section
; ********************************************
; * Tiny85LEDON *
; * 07/17/2010 *
; ********************************************
is nothing but a comment and means nothing to
the assembler...this is stuff just for you the programmer
to read and use.
these lines cause a large file of definitions
and such to be loaded and processed by the
assembler.
.NOLIST
.INCLUDE "tn85def.inc"
.LIST
The include file named tn85def.inc is the important
thing here. The .NOLIST and .LIST are there just to
keep the AVR Studio IDE from displaying the huge
tn85def.inc file when it produces a list file. You don't
need to see all the stuff inside that file, it's mostly
boring and you need not think about it. Each AVR
model has its own def file that details stuff like the names
of the registers, amounts of memory..etc..etc If you
don't include this file you cannot use the simple names
for things like I/O registers and would have to enter
the addresses instead, that would suck because it would
make assembly programming much more tedious.
The line
.def temp =r16
defines the word temp to mean the same thing as r16.
Now you can just type temp and the assembler will
translate that to r16 (working register 16) there are 32
working registers that each hold one byte(8 bits). Registers
16-31 are more useful than the others especially 30 and 31
because this pair can hold a word (16 bit number)
This long list of interrupt vectors is not strictly
needed but we will include it for now since it will
help you to understand that the first several bytes
of memory are meant to hold these vectors.
rjmp Start ; Reset vector
reti ; Int vector 1
reti ; Int vector 2
reti ; Int vector 3
reti ; Int vector 4
reti ; Int vector 5
reti ; Int vector 6
reti ; Int vector 7
reti ; Int vector 8
reti ; Int vector 9
reti ; Int vector 10
reti ; Int vector 11
reti ; Int vector 12
reti ; Int vector 13
reti ; Int vector 14
The first one is memory location zero, this is the first
byte of code that runs when you power up an AVR.
Putting this line
rjmp Start ; Reset vector
In this spot is not required but is much recommended!
rjmp means relative jump and it sends the AVR down to
where your actual program starts at the label Start:
It thus jumps over all the other interrupt vector bytes
which are filled with the reti command. This is the
return from interrupt code and usually is found at the
very end of an interrupt service routine. It serves well
here as a sort of placeholder that will if ever called
just bounce your program out of any interrupt that jumps
to it.
Notice the ; in each of these short lines of code, it means
that the text on the line following the ; is just a comment.
Ok, this next line is called a label. This is just a name you
make up to tell the assembler where a particular place in
memory is.
Start:
Don't forget to put labels starting in the first column and
never ever forget the : at the end! Also don't use a name
reserved by the assembler for something else such as
PORTB: all hell would break loose if you tried it! :-)
Labels don't take up memory space in the AVR, they
are simply a way for the assembler to locate a place in
memory when it assembles your source code.
ser temp ;set temp (r16) to 0b11111111
ser means SEt Register
What it does is it moves 0b11111111 into a register
quickly. It is the fastest way to do this and you will
use this instruction often. Note that it only works on
working registers 16-31 !!!
0b11111111 is the proper way to write a binary value
for the assembler to understand. Hexadecimal is written
like this 0xFF or $FF these three numbers
0b11111111
0xFF
$FF
All equal decimal 255, you can use decimal in the assembler,
it is the default base and so you could simply write 255.
(you do know computer arithmetic? I hope so because I
am not planning on reviewing it here...there are many fine
tutorials already on the web)
out DDRB,temp ;copy temp to I/O register DDRB
;making port B pins all outputs
the out instruction copies the value in a working register
into an I/O register. You cannot move a number directly
into an I/O register, you must copy it over from a working
register!
Copying the value 0b11111111 into DDRB will make
all the pins of PortB outputs. If a bit is set to a 1 then
the corresponding pin is an output, if the bit is a 0 then
that pin is an input.
clr temp ;set temp to 0b00000000
The clr instruction sets a working register to 0b00000000
clr stands for CLear Register.
out PortB,temp ;set all port B pins low
This turns off all the I/O pins on PortB. They will thus
be at ground potential. If a bit in PortB holds a zero then
it's corresponding pin is low.
Ok, now we get to the line that actually will turn
our LED on!
sbi PortB,0 ;set PortB pin 0 high
sbi sets a bit in an I/O register to a one. This makes it
high (at vcc usually 5v) so this line sets pin 0 at 5v and
if an LED is connected from this pin to ground (through
a current limiting resistor) it will light up!
loop: rjmp loop ; loop 4ever
This is the last line in our small program. It just creates
an endless loop, you can never let the AVR just wonder
off when its program ends! You must put it into some
sort of loop, or put it to sleep :-)
If you run this in the AVR Studio IDE and look at the
simulator over on the right and click on PortB you will
see this
Notice that DDRB has been set to all ones by the code line
out DDRB,temp
Remember that temp held 0b11111111 when it's value was
copied to DDRB.
And notice that pin zero of PortB is indeed turned on,
it is at vcc (usually 5v)
I will try to actually build up a small circuit for the next
post so you can actually see this program running on a
Tiny85 and lighting up an LED.
After that perhaps we will alter this program and
let an interrupt service routine turn the LED on.
It is easy to blink the LED using a Timer interrupt
or you can use a button connected to an input pin
to turn it on when a pin change interrupt is triggered.
Friday, July 16, 2010
AVR1
It is my firm belief that anyone starting
out to learn to program a new processor should start
with its assembly language. My reasoning is that using assembly
forces you to learn and understand the architecture
of the processor. To be any good at assembly you must
be able to hold an image of the chip's hardware in your mind. You must
know exactly where the data is, what the assembly instructions
do with that data and how your code controls the hardware.
In short, if you want to do really good work then you had
better know how to code in assembler(asm).
Luckily assembler is the simplest of all languages to code
in. Now I did not mean it is the fastest way to write code
for a processor, just that it is the simplest and most
elementary way. Most processors have a relatively small collection
of assembly instructions and these are nearly all as easy
to understand as 1 + 1 = 2. The AVR and the MSP430 are easy to
program in assembly and the Parallax Propeller processor(the Prop)
is no exception, it too is easy to program in asm!
The easiest way to learn asm is by taking short asm programs
that are already written and known to work and making modifications
to them. We will start with the simplest of all asm programs, one
that does absolutely nothing! It is what is called a program template.
You will use such a template over and over, it saves you
from having to re enter all the preliminary stuff. Never start
an asm program from scratch, that is a waste of your time.
Here is a suitable program template for the AVR.
It is very basic and later I will create a more
complete version that sets up the stack address
and has place holders for interrupt routines.etc.
; ********************************************
; * Put program name here along with date *
; * written and any other pertinent info *
; ********************************************
.NOLIST
.INCLUDE "tn85def.inc"
.LIST
rjmp Start ; This is the reset vector
Start:
rjmp Start ; loop 4ever
Here is what this short program looks like in AVR Studio
when it is compiled.
This image shows how much memory has been used
by this short program. It only takes up 4 bytes of the
8192 bytes available in the Tiny85's flash memory.
Of course it doesn't actually do anything...it just causes
the AVR to continually execute the first instruction
that is located at the label Start: this is an identical rjmp
instruction that causes the program counter to load the
location of Start: and jump there....an infinite loop.
When powered up the Tiny85 will execute the instruction
it finds at memory location zero (the reset interrupt vector
location) it finds an instruction there that loads the program
counter with the location of the Start: label when the
Tiny85 gets to that location it finds another instruction
that simply points it again at the location of the Start:
label.
Start:
rjmp Start
This simple program can actually be made smaller.
This works just as well.
; ********************************************
; * Put program name here along with date *
; * written and any other pertinent info *
; ********************************************
.NOLIST
.INCLUDE "tn85def.inc"
.LIST
Start:
rjmp Start ; loop 4ever
This version uses only 2 bytes. But there is a very
good reason to include this line
rjmp Start ; This is the reset vector
The reason is that in the AVR the interrupt vectors
are all in low memory starting at location 0x000000
This first vector is called the reset vector and it is
the first instruction that is run whenever the Tiny85
is powered up or reset. It is best to place an rjmp
instruction here and jump to the start of your asm
program. You may need to come back and add some
rjmp instructions that point to a routine you wish to run
when another of the interrupts is triggered. The locations
that are meant to hold the vectors can be used for regular
program code as long as the interrupts will never be called!
Here is the interrupt chart from the Tiny85 datasheet
Some people just add them all as sort of placeholders
whether they use them all or not...like this
rjmp Start ; Reset vector
reti ; Int vector 1
reti ; Int vector 2
reti ; Int vector 3
reti ; Int vector 4
reti ; Int vector 5
reti ; Int vector 6
reti ; Int vector 7
reti ; Int vector 8
reti ; Int vector 9
reti ; Int vector 10
reti ; Int vector 11
reti ; Int vector 12
reti ; Int vector 13
reti ; Int vector 14
This takes up space that could be used by program
code, unless you need to use all 14 interrupts..this
is rarely the case. But some people just like to start
out with a list like this. If any interrupts are triggered
they jump to the corresponding reti (return from interrupt)
command and all is well. You can simply replace one
of the lines above with an rjmp command to cause
your code to be jumped to if a particular interrupt is
triggered...like so
reti ; Int vector 5
might be replaced by
rjmp MyTimer1OverflowCode
Here is the program with all the placeholders for
the interrupt vectors added.
This works just fine
but note that the memory usage is now at 32 bytes!
Now, probably it won't matter if you use up a few
extra bytes but I prefer to keep things trim. You
must be careful though to place a vector into the
proper location if you do not use placeholders and
later want to edit your asm and add an rjmp to a
new interrupt routine! You can use the org command to
make certain of where you place an interrupt vector.
This will place a new rjmp at the proper location
for interrupt 3, the pin change interrupt. (remember
that the memory is counted up from zero so the third
location is at $0002)
.ORG $0002
rjmp MyPinChangeCode
This entire program with the new int vector
for the pin change interrupt and the tiny
MyPinChange routine is only 8 bytes. Using
the .ORG moves your code that begins at Start:
farther up in memory so you are leaving some
bytes unused.
I think I will use the template version with the full
list of interrupt vector place holders for the time being.
I think it will be easier for newbies to understand with
them listed. Just be aware that once you get used to AVR
asm you don't have to do it this way. Just always remember
where these important vectors are in memory! The number
of interrupt vectors is different for different AVRs ..just
check the data sheet to see what and where they are.
More later...stay tuned :-)
out to learn to program a new processor should start
with its assembly language. My reasoning is that using assembly
forces you to learn and understand the architecture
of the processor. To be any good at assembly you must
be able to hold an image of the chip's hardware in your mind. You must
know exactly where the data is, what the assembly instructions
do with that data and how your code controls the hardware.
In short, if you want to do really good work then you had
better know how to code in assembler(asm).
Luckily assembler is the simplest of all languages to code
in. Now I did not mean it is the fastest way to write code
for a processor, just that it is the simplest and most
elementary way. Most processors have a relatively small collection
of assembly instructions and these are nearly all as easy
to understand as 1 + 1 = 2. The AVR and the MSP430 are easy to
program in assembly and the Parallax Propeller processor(the Prop)
is no exception, it too is easy to program in asm!
The easiest way to learn asm is by taking short asm programs
that are already written and known to work and making modifications
to them. We will start with the simplest of all asm programs, one
that does absolutely nothing! It is what is called a program template.
You will use such a template over and over, it saves you
from having to re enter all the preliminary stuff. Never start
an asm program from scratch, that is a waste of your time.
Here is a suitable program template for the AVR.
It is very basic and later I will create a more
complete version that sets up the stack address
and has place holders for interrupt routines.etc.
; ********************************************
; * Put program name here along with date *
; * written and any other pertinent info *
; ********************************************
.NOLIST
.INCLUDE "tn85def.inc"
.LIST
rjmp Start ; This is the reset vector
Start:
rjmp Start ; loop 4ever
Here is what this short program looks like in AVR Studio
when it is compiled.
This image shows how much memory has been used
by this short program. It only takes up 4 bytes of the
8192 bytes available in the Tiny85's flash memory.
Of course it doesn't actually do anything...it just causes
the AVR to continually execute the first instruction
that is located at the label Start: this is an identical rjmp
instruction that causes the program counter to load the
location of Start: and jump there....an infinite loop.
When powered up the Tiny85 will execute the instruction
it finds at memory location zero (the reset interrupt vector
location) it finds an instruction there that loads the program
counter with the location of the Start: label when the
Tiny85 gets to that location it finds another instruction
that simply points it again at the location of the Start:
label.
Start:
rjmp Start
This simple program can actually be made smaller.
This works just as well.
; ********************************************
; * Put program name here along with date *
; * written and any other pertinent info *
; ********************************************
.NOLIST
.INCLUDE "tn85def.inc"
.LIST
Start:
rjmp Start ; loop 4ever
This version uses only 2 bytes. But there is a very
good reason to include this line
rjmp Start ; This is the reset vector
The reason is that in the AVR the interrupt vectors
are all in low memory starting at location 0x000000
This first vector is called the reset vector and it is
the first instruction that is run whenever the Tiny85
is powered up or reset. It is best to place an rjmp
instruction here and jump to the start of your asm
program. You may need to come back and add some
rjmp instructions that point to a routine you wish to run
when another of the interrupts is triggered. The locations
that are meant to hold the vectors can be used for regular
program code as long as the interrupts will never be called!
Here is the interrupt chart from the Tiny85 datasheet
Some people just add them all as sort of placeholders
whether they use them all or not...like this
rjmp Start ; Reset vector
reti ; Int vector 1
reti ; Int vector 2
reti ; Int vector 3
reti ; Int vector 4
reti ; Int vector 5
reti ; Int vector 6
reti ; Int vector 7
reti ; Int vector 8
reti ; Int vector 9
reti ; Int vector 10
reti ; Int vector 11
reti ; Int vector 12
reti ; Int vector 13
reti ; Int vector 14
This takes up space that could be used by program
code, unless you need to use all 14 interrupts..this
is rarely the case. But some people just like to start
out with a list like this. If any interrupts are triggered
they jump to the corresponding reti (return from interrupt)
command and all is well. You can simply replace one
of the lines above with an rjmp command to cause
your code to be jumped to if a particular interrupt is
triggered...like so
reti ; Int vector 5
might be replaced by
rjmp MyTimer1OverflowCode
Here is the program with all the placeholders for
the interrupt vectors added.
This works just fine
but note that the memory usage is now at 32 bytes!
Now, probably it won't matter if you use up a few
extra bytes but I prefer to keep things trim. You
must be careful though to place a vector into the
proper location if you do not use placeholders and
later want to edit your asm and add an rjmp to a
new interrupt routine! You can use the org command to
make certain of where you place an interrupt vector.
This will place a new rjmp at the proper location
for interrupt 3, the pin change interrupt. (remember
that the memory is counted up from zero so the third
location is at $0002)
.ORG $0002
rjmp MyPinChangeCode
This entire program with the new int vector
for the pin change interrupt and the tiny
MyPinChange routine is only 8 bytes. Using
the .ORG moves your code that begins at Start:
farther up in memory so you are leaving some
bytes unused.
I think I will use the template version with the full
list of interrupt vector place holders for the time being.
I think it will be easier for newbies to understand with
them listed. Just be aware that once you get used to AVR
asm you don't have to do it this way. Just always remember
where these important vectors are in memory! The number
of interrupt vectors is different for different AVRs ..just
check the data sheet to see what and where they are.
More later...stay tuned :-)
Subscribe to:
Posts (Atom)