4
\$\begingroup\$

A project that I'm working on involves a cycle accurate interrupt service routine. This routine is written in AVR Assembly where I just wrote:

.org oc1aadr
rjmp INTRP

(to set up the IVT) And it worked perfectly well. However I had to use both C and assembly for this project, so I switched to GCC and after looking up some documentation, found that I just have to write the routine with a label:

TIMER1_COMPA_vect:

Now the interrupt is working fine too, but the thing is that it now takes 3 cycles to enter into the ISR. On looking up the disassembler code, I saw that the IVT is like this:

+00000000:   940C002A    JMP     0x0000002A       Jump
+00000002:   940C0047    JMP     0x00000047       Jump
+00000004:   940C0047    JMP     0x00000047       Jump
+00000006:   940C0047    JMP     0x00000047       Jump
+00000008:   940C0047    JMP     0x00000047       Jump
+0000000A:   940C0047    JMP     0x00000047       Jump
+0000000C:   940C0047    JMP     0x00000047       Jump
+0000000E:   940C0049    JMP     0x00000049       Jump
+00000010:   940C0047    JMP     0x00000047       Jump

The JMP instruction takes 3 cycles unlike RJMP, which takes only 2. I've tried writing:

.org 0x0E
rjmp INTRP

But still it won't work, I've also tried writing (.section .init0) before .org, but still no effect. So, is there any way I can change the instruction to RJMP? Note: Only the interrupt routine is written in assembly.

For my second question: Is there any difference in the clock cycles required by an instruction when using different compilers/assemblers? MY entire routine takes 3 clock cycles less using GCC compared to AVR Assembler. I don't know whether GCC depends on AVR Assembler or not, but is there a possibility of this happening? (I'm asking this based on the AVR simulator output).

\$\endgroup\$
1
\$\begingroup\$

The answer is in avr/interrupt.h line 228 which decides to use jmp on ATMEGA and rjmp on other micros. Presumably you could override it back to rjmp as long as you make sure your ISR's address is within the allowable range for rjmp.

The documentation for avr/interrupt.h as mentioned in another answer explains how to mark the ISR as naked to avoid any function setup/teardown overhead. You could even write the function using inline assembly, but you can probably get exactly the instructions you want from C, too.

\$\endgroup\$
  • \$\begingroup\$ I tried that, but no effect. Anyways, I adjusted the 1 clock delay elsewhere, the problem no longer persists. Thanks for your help. \$\endgroup\$ – tecfreak Feb 14 '12 at 15:40
  • \$\begingroup\$ Interesting question "how does GCC generate the interrupt vector table"; I certainly learned something. You're right, the first part of my answer was wrong, that part of interrupt.h only defines a deprecated ISR aliasing mechanism. \$\endgroup\$ – joeforker Feb 14 '12 at 20:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.