ISR assembly code

Go To Last Post
48 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is a real newbie question.
I am trying to understand how to use an ISR (interrupt service routine)in assembly code. I can write the ISR code however I am not fully understanding how to link the code to an interrupt vector ie. one of the 10 or so included in the list of interrupt for the particular avr.

Thanks in advance for any help with this.[/u]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In assembler, simply put a jump statement in the vector location.

For example, if you want to respond to Timer0 overflow, put a jump statement in the Timer0 Overflow vector location. Make this jump to the ISR that handles that event.

The system has already put the return address on the stack by the time it reaches the vector, so all you need is an reti at the end. That returns execution to the point where it was interrupted.

Watch out for the space allocated for each vector. If it is just one word, then you need to do a relative jump.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just googled for a link to some example Asm code (I don't know why I forgot about the obvious www.avebeginners.net !) and I happened to hit this PDF that looks very useful:

www.avr-asm-download.de/beginner...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you both for your help.
Jim, I'm almost there but I don't quite understand how and where to write the assembly code to do this. Let's say my avr has and external interrupt at INT0 address $001. Do I write this after the origin at $000? I follow the RETI and the stack but am not getting where and how to place the jump to the code. I know to place the IRS outside of the main code.
Thank you again.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
simply put a jump statement in the vector location
Or rjmp on smaller AVRs.
Quote:
Jim, I'm almost there but I don't quite understand how and where to write the assembly code to do this.
In the vector table. The table starts at 0. Simply put

JMP your_isr

at the proper address for the vector you need. Again, larger AVRs use jump and require two words per vector, and smaller AVRs use relative jump and take one word per vector.

Quote:
I don't know why I forgot about the obvious www.avebeginners.net !)
You also forgot how to spell it ;)

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
I just googled for a link to some example Asm code (I don't know why I forgot about the obvious www.avebeginners.net !) and I happened to hit this PDF that looks very useful:

www.avr-asm-download.de/beginner...


Yes, that does look useful. However, regarding the OP's question, it could be misleading. The doc has reti instructions at every unused vector location. That only works for AVRs that us 1-word vector jump instructions. A more universal practice would be to have a jump to unused vector instruction in every unused vector, with the jump being 1 or 2 words depending on the AVR (in particular, depending on the word spacing between vectors).

The OP can see this word spacing on the datasheet by looking at the table(s) of interrupt vectors. For example, for the ATmega48, the vectors are spaced 1 program word apart, but for the ATmega168 the vectors are spaced 2 words apart.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I follow the RETI and the stack but am not getting where and how to place the jump to the code.

Get into the habit of taking the time to create a complete vector table, using the names of the vectors from the chip-include file each with a .ORG .

If you don't do that, you >>will<< eventually end up with a very confusing problem.

Example: https://www.avrfreaks.net/index.p...

That is www.avrbeginners.net btw.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Isn't there an example of a vector table in every AVR data sheet?

(You know, when everything else fails - read the documentation... :wink:)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you all. I might be missing something very simple here. If the Attiny26 vector list names $001 as EXT_INT0, then I would simply write a sub-routine later on called:
EXT_INT0
code
reti
Presumable after it returned from the ISR (sorry for the misspelling)it would continue with the main program where it left off. The address was pushed to the stack at the time of the rjmp call.
Still not sure where to work in the org. call.
Am I getting any closer.
Thank you all.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Isn't there an example of a vector table in every AVR data sheet?

Well, yes--but it of the form

The most typical and general program setup for the Reset and Interrupt Vector Addresses in
ATmega328/328P is:
Address Labels Code Comments
0x0000 jmp RESET ; Reset Handler
0x0002 jmp EXT_INT0 ; IRQ0 Handler
0x0004 jmp EXT_INT1 ; IRQ1 Handler
0x0006 jmp PCINT0 ; PCINT0 Handler
0x0008 jmp PCINT1 ; PCINT1 Handler
0x000A jmp PCINT2 ; PCINT2 Handler
...

which is a bit different from what I'm trying to encourage OP to do:

   .org 0
   rjmp   RESET      ; Reset Handler
   .org INT0addr
   reti   ;EXT_INT0   ;IRQ0 Handler
   .org INT1addr
   reti   ;EXT_INT1   ; IRQ1 Handler
   .org INT2addr
   reti   ;EXT_INT2   ; IRQ2 Handler
   .org OC2addr   
   reti   ;TIM2_COMP   ; Timer2 Compare Handler
   .org OVF2addr 
...

But yes, OP should have a study of that datasheet chapter, at the minimum.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, but my snide remark was re the

Quote:
how to link the code to an interrupt vector

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

then I would simply write a sub-routine later on called:

No. Did you read this:

http://www.avrbeginners.net/arch...

or section 8.6 of the PDF I linked previously. As other here have been trying to tell you, you'd use:

   .org 0
   rjmp   RESET      ; Reset Handler
   .org INT0addr
   rjmp  EXT_INT0_handler   ;IRQ0 Handler
...
RESET:
   ; execution gets here at power on
...

EXT_INT0_handler:
   ; execution gets here after you enable
   ; INT0- and then the external trigger conditions
   ; occur
 ...
   reti ; this returns back to the code that was interrupted

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you are writing entirely in assembler, you have to explicitly create the vector table as well as the ISR functions. In Atmel assembler, this is usually a series of jmp or rjmp instructions following a ".org 0" directive, or with each jump having its own .org if you're being particularly careful. In the gnu assembler, its probably a series of jmp/rjmp instructions in a ".section ".vectors"" section.

If you are writing an assembly language ISR for a C program, then the vector table is something that is provided for you by the "startup files", and you just have to make sure your ISR has the correct name (to match the startup file.)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's not necessary to write the vector table if you use gcc and avr-libc's pre-defined vector table.
Just define your ISR as global with the appropriate name.

.global TIMER2_COMPA_vect
TIMER2_COMPA_vect:
push tmp8
in tmp8, SREG
push tmp8 ; save SREG
...

For more details, read my blog post on wirting AVR ISRs.
http://nerdralph.blogspot.ca/201...

I have no special talents.  I am only passionately curious. - Albert Einstein

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Which brings up the question as to which assembler the OP is using.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have to digest all of this.
Using studio 6, asm
Not writing in C.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This

Quote:
Using studio 6, asm

does not answer
Quote:
the question as to which assembler the OP is using.

Both Atmel Assembler and the GNU assembler is available in Studio.

If you created your project as a "AVR Assembler" project then its Atmel Assembler.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

It's not necessary to write the vector table if you use gcc and avr-libc's pre-defined vector table.
Just define your ISR as global with the appropriate name.

Only when -nostartfiles is not being used. Asm programmers tend to prefer a "clean machine" so don't want the CRT and therefore would tend to use -nostartfiles.

(if size is important to them why would they want a complete vector table if they only plan to use a couple of vectors in it? They can begin code right after the last used vector or even stuff some code/data into the gap between used ones).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello again and thank you for your patience.  I think I am getting it.  After reviewing all you comments and the very helpful tutorial from "avrbeginners.net" I think I see what is going on.

Using "org 0xnnnn" tell the process this is the address where the next line of code will be read from.  This address being an interrupt vector means that when the interrupt occurs (hard wired) the processor will read what to do from this address.  At the same time it places the address the processor is at on the stack so it can return there later.  Since the vector is only 1 word long the best bet is to tell the processor to make a relative jump (rjmp) to another location where the vector name is used as the title of an interrupt service routine (ISR).  When the ISR is completed you use a return from interrupt (reti) to return to the address where the processor left the original routine it was processing (probably "main").

Apparently when you put "rjmp reset" on the next line after .org 0x0000 it is read as coming from that address not the next address 0x0001 where it appears to be.

 

I understand using ".org" ahead of the interrupt vectors to be used, however the tutorial suggestion of placing an "reti" at the other interrupt vectors not being used seemed to insure an incorrect vector would not be used if a mistaken interrupt occurs on one of the unused vectors.

 

Thanks to all of you for your help.  Please le me know if you thin I am missing something here.

 

Larry

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

LaurenceR wrote:

...

Since the vector is only 1 word long the best bet is to tell the processor to make a relative jump (rjmp) to another location where the vector name is used as the title of an interrupt service routine (ISR).

The vector (that is, the code space reserved for the vector) is not always 1 word long.  In AVRs that have more program memory than an rjmp can access, the vector is 2 words long, to allow for a jump that can reach any part of code.  That was the point of my example with the ATmega48 vs ATmega168.

 

Quote:
...the tutorial suggestion of placing an "reti" at the other interrupt vectors not being used seemed to insure an incorrect vector would not be used if a mistaken interrupt occurs on one of the unused vectors.

But if you're using a 2-word-vector part, one reti per vector location will cause your vector table to be out of sync.  e.g. your 5th vector location will be at location 0x0004 when it should be at 0x0008.  Using a .ORG for each vector will prevent that (assuming, of course, that the values used for the .ORGs correctly take into account the vector locations for the given chip!).

 

Another way to do the vector table is to have either an rjmp or jmp for each vector (1 or 2 words, as required), and have the unused ones all point to a catch-all ISR (which could just be an reti, or it could set an error LED, or whatever you want).  The point is to use the same 1 or 2 word jump instruction for both used and unused vectors.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Still not sure where to work in the org. call

An example:

//internal osc. 8 Mhz
.nolist
#include<tn26def.inc> 
.list


.cseg
.org 0
   rjmp main       ; jump over used interrupt vectors

.org INT0addr      ; INT0addr equ 0x01, see "tn26def.inc" 
   rjmp INT0_isr   ; jmp to interrupt service routine    

;============================

main:

   ;init stack 
   ldi   r16, RAMEND   
   out   SP,  r16   

   ;init ports
   sbi   DDRB,1          ;Led on PORTB.1
   
   ;init INT0
   in    r16, GIMSK
   sbr   r16, (1<<INT0)
   out   GIMSK, r16      ;enable INT0 interrupt 
   in    r16, MCUCR
   sbr   r16, (1<<ISC01) ;falling edge
   out   MCUCR, r16

   sei                   ;global interrupt enable

mainloop:
   sbis  PINB,1          ;if Led=on
   brne  end
   rcall delay_1sec      ;wait 1s
   cbi   PORTB,1         ;Led = off 

end:   
rjmp mainloop

;============================


;Subroutines:

delay_1sec:
; delaying 7999992 cycles:

   ldi   R17, $48
WGLOOP0:
   ldi   R18, $BC
WGLOOP1:
   ldi   R19, $C4
WGLOOP2:
   dec   R19
   brne  WGLOOP2
   dec   R18
   brne  WGLOOP1
   dec   R17
   brne  WGLOOP0
ret          

; --------------------------- 

INT0_isr:
   ;save SREG (not needed here, SBI doesn't affect SREG)
   ;save used registers (no used)
   sbi   PORTB,1          ;Led on
reti

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry for the delay got tied up with projects for a few days.

I am understanding the two word long vectors for some controllers and can therefore appreciate having to accommodate two words for each interrupt.  I suppose you could use two "reti" for each interrupt or it would better make sense to use:

org. 0x0000

rjmp main

org. int0

rjmp int0

org. int1

reti

org. int2

reti

etc.....

When you write "org. int0" that is at the 0x0001 location, when you write the following "reti" that is in the nest location (0x0002).  However when you write org.0x0000 that is at address 0x0000 and the following "rjmp main" does not take up the 0x0001 address.  Is that correct?  Trying to understand the correct spacing mechanism when writing directives.

Thanks again for all you help and patience.

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The assembler directive is .ORG beginning with the period, as is the syntax for compiler directives.

 

Why don't you take your piece of code and assemble it and look at the listing?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When you write "org. int0" that is at the 0x0001 location, when you write the following "reti" that is in the nest location (0x0002).

No, the directive ".org x" means:

Place the folowing instruction on adr x.

 

.include<tn26def.inc> 
.list 

.cseg 

.org 0 
   rjmp main          // this instruction is on adr 0 

.org INT0addr         // same as ".org 1" 
   rjmp  INT0_isr     // this instruction is on adr 1 

.org 6                // timer0 overflow interrupt
   rjmp  T0ovf_isr    // this instruction is on adr 6 
   rjmp  USIstart_isr // this instruction is on adr 7 
   
.org 5                // error, not possible to go back
   reti 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is exactly what I was looking to understand.

Atmel says directives are not translated into any machine code, therefore they must exist somewhere else and do not take up program address locations.

This was a big help.

Thank you.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

therefore they must exist somewhere else

What a very curious comment. They only exist in (a) the mid of the programmer and (b) a line of text in the source file. A "directive" is an instruction from the programmer to the assembler to say "I need you to do this ... for me me here". It seldom has anything to do with the actual generation of hex codes except that it might influence how subsequent ones are produced or where they are placed. Think about something like .def. You use it like:

.def foo = r16

That hasn't actually generated any code or reserved any storage in the program. It's just saying to the assembler "from now on when I say "foo" I really mean you to use "r16", OK?". You then:

ldi foo, 0x55

and the assembler interprets this as:

ldi r16, 0x55

The ".def" was simply an instruction from you to the assembler to tell it how you wanted it work. .org is another directive like this. It's an instruction from you to the assembler to say "from now on I want the code you output to be placed at address N onwards". It doesn't "exist" anywhere. It's just a chat between you and the assembler. So when you type:

.org INT0_addr
rjmp 0x1234

It's just saying "after this .org I want the next stuff you output to be at the address given by whatever number "INT0_addr" represents. The RJMP will then lead to an opcode being generated at it will be generated at that given address.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I understand what you are saying and it makes it much clearer for me to write code.  Having worked a lot with 3D modeling I tend to expect every line is attached to something at either end.  I guess I was trying to follow the thread of where the code goes. 

If the program is loaded into "flash memory" which starts with 0x0000 then the next line of code has to be at 0x0001 one might assume.  When you write code you have to start at 0x0000 then skip over the Interrupts that occupy the next 10 or so register spaces.   It appear however that directives beginning with .xxx are not occupying code space rather they must be picked up by the cpu or something that tells the cpu the line of code following the .xxx directive will be placed at the address given in the directive and executed from that point.

 

I don't mean to start a useless discussion but I was curious.  You have certainly given me enough understanding to be able to write appropriate code.

Thanks again,

 

Laurence

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 It appear however that directives beginning with .xxx are not occupying code space rather they must be picked up by the cpu or something that tells the cpu the line of code following the .xxx directive will be placed at the address given in the directive and executed from that point.

Have you read the Atmel Assembler2 manual?  If not, how do you expect to write a complete app with .ORG, .DEF, .THIS, .THAT... ?

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 It appear however that directives beginning with .xxx are not occupying code space rather they must be picked up by the cpu or something that tells the cpu the line of code following the .xxx directive will be placed at the address given in the directive and executed from that point.

 No. The CPU has no clue what a directive is or that they ever existed in the creation of the code. Directives tell the assembler how to behave when it generates the machine code. The .org directive simply tells the assembler that the next machine code that it generates is put at that address.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The "foo" analogy was really good.  Yes I am reading the atmel assembly manual which confirms what you are all saying.  I understood how to write the code but wasn't really sure where it was going, or coming from.  Using .def, .equ etc. didn't imply taking up any space.  However .org made me think about the spacing as the next line of code took you back to the .org address.  I think the main point here is that the assembler is taking the directions from the program and creating the machine code.  Even though assembly code is considered to translate 1:1 to machine code, that doesn't mean line for line.  Clearly some of the instructions such as .org, .def as simply telling the assembler what changes to make when generating the machine code and do not result in lines of machine code in themselves.

You have all made this much clearer for me.  I have always believed that if you get the fundamentals right the rest will follow.  This forum has helped a lot.  Now I think I'll go light up a few LEDs.

 

Many thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Even though assembly code is considered to translate 1:1 to machine code, that doesn't mean line for line.  Clearly some of the instructions such as .org, .def - See more at: https://www.avrfreaks.net/forum/i...

 .org, .def are not instructions.  All that begins with .(period) is an assembler directive.

Instruction is only what is listed in the Instruction set.

We must distinguish between them.

 

Indeed all instructions are translated 1:1 to machine code.

But the directives are there for us to tell the assembler what and how we want it to do.

Using directives simplifies writing the code.

 

Just imagine that we have not the directive .org.

Then instead the code

.cseg
.org 0
    jmp main
.org 16
    jmp label2

We would have to write

jmp main
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
jmp label2

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I see exactly what you are saying.  So the assembler turns the assembly code along with its directives into machine code which is essentially the hex code.  Therefore as one gentleman said " I should assemble the code and look at the hex code it generates".  This would show all the commands in the correct position and none of the directives would take up any register space.

As you illustrated above, the first choice would be the easiest.  However it might be even safer to add .org xx, reti for the unused interrupts in order to prevent the program from jumping to the next jmp instruction when an interrupt error occurs. 

I think I'm getting it, just have to start working with it.

Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well after three hours trying to figure out why this wouldn't work, clearly I was missing something! I must just not understand this at all!

 

And, of course, it was just cause the simulator won't handle interrupts when using the "Step in" function. Switched to breakpoints and worked fine.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You elected to uproot a 4 year old thread to hang your first post on to with no real information?

 

 

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Note that if your CPU has less than 16K of flash then you use RJMP in the interrupt vector table found at flash address 0x0000. 

However if your CPU is 16K or larger, you use JMP. 

The bytes are stored in flash little-endian, meaning the least significant byte of the 16-bit address is written to flash first.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

8K not 16K

 

(and you can use RJMP in the big ones anyway)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

add:

And for bigger than 8k rjmp from the vectors can still reach the top (almost) 4k of flash.

 

It's just that for 8k and smaller rjmp can reach all flash, so no need to use jmp (and as I remember the first chips like 8515 did not have the jmp instruction).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

(and you can use RJMP in the big ones anyway)

But note that if you put RJMP instructions in the vector table, you may have to add padding, since each vector is 4bytes long to accommodate the JMP, instead of just two bytes long.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

!

This is ASM not C.

An AVR don't have ISR vectors, but have an address for ecah ISR it jump to.

Så for each ISR you use you normally have a ORG.

Last Edited: Thu. Mar 7, 2019 - 08:11 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

for each ISR you use you normally have a ORG.

Really?   I could swear I've seen ".org 0" followed by string of rcall or call vectors.

But I guess I really haven't seen many "large" ASM programs :-(

 

I did find:

.org 1
	 rcall isr ; External Interrupt Request 0
.org 2
	 rcall isr ; External Interrupt Request 1
.org 3
	 rcall isr ; Timer/Counter2 Compare Match
.org 4
	 rcall isr ; Timer/Counter2 Overflow

in AMFORTH, which is equally bad...   (sigh)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

I did find:

.org 1
	 rcall isr ; External Interrupt Request 0
.org 2
	 rcall isr ; External Interrupt Request 1
.org 3
	 rcall isr ; Timer/Counter2 Compare Match
.org 4
	 rcall isr ; Timer/Counter2 Overflow

in AMFORTH, which is equally bad...   (sigh)

 

 

I can think of a valid reason why you might do that. Once you get to the ISR handler the stack will contain a return address which can be used to determine which interrupt it is servicing. So you could write ISRs which deal with multiple interrupts.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was complaining about the numeric constants for the .ORG statements, not the common destinations.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Atmel's def.inc files deliberately define things like INTOaddr so you can org to those without hard coding absolute addresses. Anyone using ".org 12" or similar should be shot!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

clawson wrote:
Atmel's def.inc files deliberately define things like INTOaddr so you can org to those without hard coding absolute addresses. Anyone using ".org 12" or similar should be shot!
That's a bit excessive ;-)

 

For those of us who use GCC and the GNU Assembler, the device header included via <avr/io.h> has macros associating each interrupt source with its vector number.  For example, the t4 has:

/* Interrupt vectors */
/* Vector 0 is the reset vector */
#define INT0_vect_num  1
#define PCINT0_vect_num  2
#define TIM0_CAPT_vect_num  3
#define TIM0_OVF_vect_num  4
#define TIM0_COMPA_vect_num  5
#define TIM0_COMPB_vect_num  6
#define ANA_COMP_vect_num  7
#define WDT_vect_num  8
#define VLM_vect_num  9

It also provides:

#define _VECTOR_SIZE 2 /* Size of individual vector. */
#define _VECTORS_SIZE (10 * _VECTOR_SIZE)

I add:

#define VECT(v) (v * _VECTOR_SIZE)

... so I can:

; RESET.
.org VECT(0)
reset:
	rjmp	reset_vect

; INT0.
.org VECT(INT0_vect_num)
int0:
	rjmp	int0_vect

; PCINT0.
.org VECT(PCINT0_vect_num)
pcint0:
	rjmp	pcint0_vect

; TIM0_CAPT.
.org VECT(TIM0_CAPT_vect_num)
tim0_capt:
	rjmp	tim0_capt_vect

; TIM0_OVF.
.org VECT(TIM0_OVF_vect_num)
tim0_ovf:
	rjmp	tim0_ovf_vect

; TIM0_COMPA.
.org VECT(TIM0_COMPA_vect_num)
tim0_compa:
	rjmp	tim0_compa_vect

; TIM0_COMPB.
.org VECT(TIM0_COMPB_vect_num)
tim0_compb:
	rjmp	tim0_compb_vect

; ANA_COMP.
.org VECT(ANA_COMP_vect_num)
ana_comp:
	rjmp	ana_comp_vect

; WDT.
.org VECT(WDT_vect_num)
wdt:
	rjmp	wdt_vect

; VLM.
.org VECT(VLM_vect_num)
vlm:
	rjmp	vlm_vect

; First non-vector word.
.org _VECTORS_SIZE

.
.
.

reset_vect:

.
.
.

int0_vect:

.
.
.

... etc.

 

I omit the vectors I don't need/use, and locate other code in their place if I'm >>really<< tight on flash.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Thu. Mar 7, 2019 - 08:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For those of us who use GCC and the GNU Assembler, the device header included via <avr/io.h> has macros associating each interrupt source with its vector number.  For example, the t4 has:

#define INT0_vect_num  1
:

 

... so I can:

; INT0.
.org VECT(INT0_vect_num)
int0:
	rjmp	int0_vect

Does that work?   I thought that with the gnu assembler, "absolute addressing" (with ".org") was either "not allowed" or "undid by the linker anyway."

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:
Does that work?
It works inasmuch as .org works with the GNU Assembler to begin with.  No, it's not absolute addressing, but relative to the section being assembled.  As long as the section is linked to 0 (the default for AVR at least) then yes it works.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
As long as the section is linked to 0 (the default for AVR at least) then yes it works.
And that's the point. You want to use (with the default .x):

.section .vectors
.org VECT(INT0_vect_num)
int0:

The linker scripts deliberately position .vectors at 0 because (surprise, surprise) that is where the vectors are.

 

Of course you could just rely on the default .text on the basis that (with -nostartfiles) nothing is using .vectors, so it's empty so .text (or rather all the .ini's then .text) come next so end up being at 0 anyway. But I'd say a .section to .vectors is a safer bet.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
with -nostartfiles
Which is what I usually do when writing in assembler anyway.  After all:

joeymorin wrote:
the t4
With 256 words of flash, I'm not sanguine about the compiler doing much of anything for me ;-)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]