Atmel made great ASF framework powered by linux GCC compiler. Everything works out-of-box. No matter what IDE you use: Eclipse based ( ver 2.6 ) or VS based ( ver 6.0 ).
I have one project with EVK 1100 board as industrial PLC. It drive seven PWM output at 25 kHz rate. This frequency give 40 microseconds clock for main loop task. Main loop itself tooks about 15 microseconds. There is 25 microseconds left for interrupts. It is pretty short period.
First thing that I had to optimize is ISR routine for PWM module: I rewrite code in pure assembly. That is cool, but did not approve interrupt latency time. I had to change exception.x file that came in ASF framework for handling interrupts.
Originaly, Atmel ASF work this way:
.balign 4
.irp priority,0,1,2,3
_int\priority:
mov r12, \priority
call _get_interrupt_handler
cp.w r12, 0
movne pc, r12
rete
.endr
I did not know this assembly directive, until I look in debuger, what you realy get with this code:
_int0:
mov r12, 0
call _get_interrupt_handler
cp.w r12, 0
movne pc, r12
rete
_int1:
mov r12, 1
call _get_interrupt_handler
cp.w r12, 0
movne pc, r12
rete
_int2:
mov r12, 2
call _get_interrupt_handler
cp.w r12, 0
movne pc, r12
rete
_int3:
mov r12, 3
call _get_interrupt_handler
cp.w r12, 0
movne pc, r12
rete
Now it make sense ! You have one block for every priority level. COOL !
Here comes possibility for hacking. Lets give PWM ISR routine highest priority LEVEL_3 and then you have to change only block for LEVEL_3
You dont mind at all for lower priority level, it can stay as is. Now we can write this:
.balign 4
.irp priority,0,1,2
_int\priority:
mov r12, \priority
call _get_interrupt_handler
cp.w r12, 0
movne pc, r12
rete
.endr
.balign 4
_int3:
mov r12, _lo_pwm_isr_handler
orh r12, _hi_pwm_isr_handler
mov pc, r12
You see – first three priority levels are same – only LEVEL_3 is changed ! There is no call to _get_interrupt_handler routine at all ! Just use one and only handler we need !
Bad news – avr-gcc compiler have no complain about global variable defined in C. But I did not get correct value. Very strange ! Never mind – I skip that part and put immidiate values in r12 register, for lo and hi part of ISR handler pointer. It is clumsy little bit – but it works !
We got FAST interrupt response, as we wanted !
EDIT ( two days later ):
ok – now I understand what is going on.
I can use C variables in assembly. but I have to know some basic. First of all, MOV command is for load IMMIDIATE values only. So – this one will not work:
mov r12, _lo_pwm_isr_handler
Here is solution:
mov r12, 0
ld.w r12, r12[_pwm_isr_handler]
cp.w r12, 0
movne pc, r12
rete
one more thing. This one is not trivial at all. If I don’t have mkII debuger I will never find what is going on. This command fire _handle_Data_Address_Read exception
ld.w r12, r12[_pwm_isr_handler]
and default handler for all exceptions are infinite loop – bad luck !
so – I have to change default behaviour, like this:
.org 0x034
// Data Address (Read).
_handle_Data_Address_Read:
rete
// rjmp $
and that’s it !
regards to all – merry hacking !