Hello, First of all happy new year and sorry for the huge delay in replying.
Thanks for your comments. In my application I am using external libraries based on avrlibc so the approach with ffixed doesn't work, although thanks for the hint. Also, apparently the "register ..." statement in C doesn't seem to avoid other libraries (probably already compiled to use certain registers) in messing up with reserved registers. Therefore I had to use another approach like this: first, I declared a C variable which will point somewhere in RAM and then a few assembler registers that will be used to access that variable: <file counter.h> ----------------------- /* * Global register variables. */ #ifdef __ASSEMBLER__ // Syncronization counter, 32 bit value accessed through 4 CONSECUTIVE registers // In the code, these values should be loaded using the C global variable as follows # define counter_b0 r18 # define counter_b1 r19 # define counter_b2 r20 # define counter_b3 r21 // Variables used in asm subroutines to store temporary values # define counter_inc r22 # define counter_sreg r23 #else /* !ASSEMBLER */ #include <stdint.h> uint32_t counter; // this will be updated and used in both C and asm code #endif /* ASSEMBLER */ ----------------------- Then I changed the interrupt routine to do all the processing there, first retrieving the bytes from RAM, then updating them and then storing back: <file main.S> ---------------------- .global TIMER2_COMPA_vect TIMER2_COMPA_vect: push counter_sreg ; used for SREG in counter_sreg, _SFR_IO_ADDR(SREG) ; save SREG cli ; disable interrupts push counter_b0 push counter_b1 push counter_b2 push counter_b3 push counter_inc push r30 push r31 ldi r30, lo8(counter) ldi r31, hi8(counter) ld counter_b0, Z ldd counter_b1, Z+1 ldd counter_b2, Z+2 ldd counter_b3, Z+3 ldi counter_inc, 1 ; use to increment with carry add counter_b0, r22 adc counter_b1, r1 adc counter_b2, r1 adc counter_b3, r1 st Z, counter_b0 std Z+1, counter_b1 std Z+2, counter_b2 std Z+3, counter_b3 pop r31 pop r30 pop counter_inc pop counter_b3 pop counter_b2 pop counter_b1 pop counter_b0 out _SFR_IO_ADDR(SREG), counter_sreg pop counter_sreg reti ------------------------ You can then declare another assembler routine to get the variable exported into the right registers for access in C, like this: <file main.S or other.S> ------------------------ .global GetCounter GetCounter: ldi r30, lo8(counter) ldi r31, hi8(counter) ld r22, Z+ ld r23, Z+ ld r24, Z+ ld r25, Z+ ret ------------------------ <file main.h or other.h> ------------------------ uint32_t GetCounter(); ------------------------ Finally, you can access the updated counter in a C file like this: <file main.c or other.c> ------------------------ #include uint32_t counter_value; counter_value = GetCounter(); ------------------------ When you compile with avr-gcc include all .c and .S files together. Or you could of course just use the "counter" value directly, by importing the external variable <file main.c or other.c> ------------------------ #include "counter.h" extern uint32_t counter; uint32_t counter_value; counter_value = counter; ------------------------ However I prefer the first approach, although it requires extra clock cycles because is more portable and cleaner across multiple files (you just export the header file, rather than having to use the definition of the external variable). In any case, thanks to all for the help and I hope this might help others. Omar On Fri, Dec 16, 2011 at 11:35 PM, Jens Bauer <j...@bruger.mine.nu> wrote: > Hi Omar, > >>> .global IncrementCounter >>> IncrementCounter: >>> ldi r19, 1 ; use to increment with carry >>> clc >>> adc counter_b0, r19 >>> adc counter_b1, r1 >>> adc counter_b2, r1 >>> adc counter_b3, r1 >>> ret > > ... or free r19 (this is an example of a pure interrupt only, which you could > place directly in the interrupt vectors): > > TIMER2_COMPA_vect: ;[5] > sec ;[1] > adc counter_b0,r1 ;[1] > adc counter_b1,r1 ;[1] > adc counter_b2,r1 ;[1] > adc counter_b3,r1 ;[1] > reti ;[5] > > ;[15] > > Numbers in brackets are clock-cycles spent for the operation. > (eg. an interrupt takes 5 clock-cycles. If you don't place the code directly > in the interrupt-vectors, you'd probably use rjmp to jump to the code; which > means you'd need to add 2 extra clock cycles in that case. > > If you need the counter to spend as little CPU-time as possible, you could > alternatively do the following, but that means you'd get an unstable > CPU-usage: > > TIMER2_COMPA_vect: ;[5] > sec ;[1] > adc counter_b0,r1 ;[1] > brcs ad2 ;[2/1] > reti ;[5] > ;(13) > > ad2: ;[9] > adc counter_b1,r1 ;[1] > brcs ad3 ;[2/1] > reti ;[5] > ;(16) > > ad3: ;[12] > adc counter_b2,r1 ;[1] > adc counter_b3,r1 ;[1] > reti ;[5] > ;(19) > > -As I mentioned above; it would use slightly less CPU-time, but when you get > a carry, the CPU-usage would generate a spike, which might not be what you > want, so the above routine would spend between 13 and 19 clock cycles. > > > Love, > Jens _______________________________________________ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org https://lists.nongnu.org/mailman/listinfo/avr-gcc-list