Taking a snapshot of the ports in an AVR (AT90CAN128)

A small inline function to take a snapshot of all the ports as simultaneously as possible, which means 7 cycles from first to last, which means less than 0.5 usec from first to last at 16 MHz. Can't be faster.

Had to be done in asm inline because if not gcc prefers to interleave the input instructions with store instructions. Done this way, the inputs come first and the storage comes later, generated automatically.

Tries to protect itself agains the possibility of the poorly-documented __SFR* macros being changed.

No clobbered-register list because the registers used are left for gcc to choose, hoping it will know better which ones are available.

The [7] in the parameter definition is rather FYI. The compiler doesn't enforce it at all.

So in fact I am thinking that this looks like a small exercise on "what is wrong with C":
  • Timing issues
  • Information available but not enforced
  • Preprocessor / #defines nastiness
  • Inline: where to put that? (inline static in an utility .h works but I can't help feeling it is dirty. But "regularizing" the situation by adding an extern inline mention doesn't make it exactly cleaner!)
  • No undefined behaviour (too short for that :P), but I don't think I can ever feel sure about that. (...fingers crossed...)

I might be starting to miss Java.

inline void PINregs_take_snapshot(uint8_t PINreg_snapshot[7]){

    #if (__SFR_OFFSET != 0x20) || (_SFR_ASM_COMPAT==1) 
        #error The PIN register addresses might not be what is expected, check the NASTY documentation for avr-libc

    asm volatile (
        "in %[snapA], %[pinA] \n\t"
        "in %[snapB], %[pinB] \n\t"
        "in %[snapC], %[pinC] \n\t"
        "in %[snapD], %[pinD] \n\t"
        "in %[snapE], %[pinE] \n\t"
        "in %[snapF], %[pinF] \n\t"
        "in %[snapG], %[pinG] \n\t"
        :    [snapA] "=r" (PINreg_snapshot[0]),
            [snapB] "=r" (PINreg_snapshot[1]),
            [snapC] "=r" (PINreg_snapshot[2]),
            [snapD] "=r" (PINreg_snapshot[3]),
            [snapE] "=r" (PINreg_snapshot[4]),
            [snapF] "=r" (PINreg_snapshot[5]),
            [snapG] "=r" (PINreg_snapshot[6])
        :    [pinA] "I" (&PINA-0x20),
            [pinB] "I" (&PINB-0x20),
            [pinC] "I" (&PINC-0x20),
            [pinD] "I" (&PIND-0x20),
            [pinE] "I" (&PINE-0x20),
            [pinF] "I" (&PINF-0x20),
            [pinG] "I" (&PING-0x20)

No comments

Post a Comment