• AVR Freaks

Hot!Wrong way to clear an interrupt flag, very important

Page: 12 > Showing page 1 of 2
Author
zardoz1
Super Member
  • Total Posts : 1852
  • Reward points : 0
  • Joined: 2005/07/09 08:03:28
  • Location: 's-Hertogenbosch, The Netherlands
  • Status: offline
2008/12/21 08:05:14 (permalink)
5 (1)

Wrong way to clear an interrupt flag, very important

When working with the TCP/IP stack 4.55 I found a problem in the timer ISR which is a generic problem and therefore posted here.

When clearing a PIC32 interrupt flag never use something like  

IFS0bits.T1IF = 0;

Using PIC32, it is guaranteed this does not translate to an atomic bitclear and therefore can lead to serious problems.

Clearing interrupt flags for PIC32 may only be done using the CRL register so for this specific case use:

IFS0CLR = _IFS0_T1IF_MASK;
 
Using the first construct leads to a read-modify-write sequence. When in between the read and the write a higher priority interrupt occurs, the interrupt flag reset by this other ISR is set again when the read of the first ISR finishes. As a result the interrupt flag of the second ISR is not cleared resulting in the ISR being entered a second time which is wrong.

Note that for PIC24/33 potentially the same problem exists. It is not guaranteed that IFS0bits.T1IF = 0; translates to an atomic clear.
post edited by zardoz1 - 2008/12/22 05:54:05


AVIX
the PIC32 & dsPIC/PIC24 RTOS with:
- Zero Latency Interrupts
- The best performance!
- Integrated Power Management
Download here: http://www.avix-rt.com/
#1

30 Replies Related Threads

    rmteo
    Super Member
    • Total Posts : 1007
    • Reward points : 0
    • Joined: 2007/05/02 20:33:25
    • Location: Colorado, USA
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/21 08:28:09 (permalink)
    0
    Do the PIC24/33 have an IFS0CLR register?

    #2
    zardoz1
    Super Member
    • Total Posts : 1852
    • Reward points : 0
    • Joined: 2005/07/09 08:03:28
    • Location: 's-Hertogenbosch, The Netherlands
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/21 09:12:46 (permalink)
    0
    ORIGINAL: rmteo

    Do the PIC24/33 have an IFS0CLR register?

     
    No, but an atomic operation can be created using an exclusive or on the desired bit. I have published a macro for this on this forum.
     
    Currently I am working on a set of macro's I will provide with our companies RTOS, AVIX.


    AVIX
    the PIC32 & dsPIC/PIC24 RTOS with:
    - Zero Latency Interrupts
    - The best performance!
    - Integrated Power Management
    Download here: http://www.avix-rt.com/
    #3
    danish.ali
    Super Member
    • Total Posts : 1714
    • Reward points : 0
    • Joined: 2004/11/16 02:02:02
    • Location: Surrey, UK
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/21 10:22:55 (permalink)
    0
    Hi zardoz,

    I remember reading the thread about your macro, and a point struck me at the time:
    If you are clearing a bit,
    is it better to xor with that bit,
    or to and with the complement of that bit?

    The and ensures that the bit will end up clear.
    The xor will change that bit.

    What is your opinion on this point?

    Regards,
    Danish
    #4
    zardoz1
    Super Member
    • Total Posts : 1852
    • Reward points : 0
    • Joined: 2005/07/09 08:03:28
    • Location: 's-Hertogenbosch, The Netherlands
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/21 10:52:05 (permalink)
    0
    ORIGINAL: danish.ali

    Hi zardoz,

    I remember reading the thread about your macro, and a point struck me at the time:
    If you are clearing a bit,
    is it better to xor with that bit,
    or to and with the complement of that bit?

    The and ensures that the bit will end up clear.
    The xor will change that bit.

    What is your opinion on this point?

    Regards,
    Danish

     
    The purpose of that macro was to create atomic operations for setting a bitfield to a specified value. The reason that macro uses an XOR is that this is the only way to accomplish this when the bitfield is longer than a single bit. When using AND combined with OR, it is impossible to create an atomic operation. First the field will be cleared and next the applicable bits will be set.
     
    For fields consisting of a single bit this can be used too but since PIC24/33 also support an atomic AND and OR, for a single bit I would use those since this is probably more efficient.


    AVIX
    the PIC32 & dsPIC/PIC24 RTOS with:
    - Zero Latency Interrupts
    - The best performance!
    - Integrated Power Management
    Download here: http://www.avix-rt.com/
    #5
    asmallri
    Super Member
    • Total Posts : 1864
    • Reward points : 0
    • Joined: 2004/05/26 09:00:05
    • Location: Perth, Australia
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/21 11:10:25 (permalink)
    0
    ORIGINAL: zardoz1
    Note that for PIC24/33 potentially the same problem exists. It is not guaranteed that IFS0bits.T1IF = 0; translates to an atomic clear.


    This is not the case for the PIC24/33. These instructions execute in a single instruction cycle.

    Any read/modify/write that executes in a single machine cycle does not have this problem.

    Regards, Andrew

    http://www.brushelectronics.com/index.php?page=software
    Home of Ethernet, SD Card, and Encrypted Serial and USB Bootloaders for PICs!!
    #6
    zardoz1
    Super Member
    • Total Posts : 1852
    • Reward points : 0
    • Joined: 2005/07/09 08:03:28
    • Location: 's-Hertogenbosch, The Netherlands
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/21 11:19:09 (permalink)
    0
    ORIGINAL: asmallri

    ORIGINAL: zardoz1
    Note that for PIC24/33 potentially the same problem exists. It is not guaranteed that IFS0bits.T1IF = 0; translates to an atomic clear.


    This is not the case for the PIC24/33. These instructions execute in a single instruction cycle.

    Any read/modify/write that executes in a single machine cycle does not have this problem.

     
    I know. But I consider it dangerous to rely on knowledge I don't have (and that does not exist). IFS0bits.T1IF = 0; is a C construct and there is no guarantee it translates to a bclr instruction. I just don't want to use this knowledge. Furthermore I am working on a generic solution that works for bitfields of an arbitrary length. For PIC24/33 I use the fact that an xor on an SFR is atomic so using the xor a bitfield can be set to any desired value in a single atomic instruction. Furthermore I want my code for PIC24/33 and PIC32 to be the same. So one macro that works for all cases, regardless the processor and regardless the number of bits in the bitfield.
     
    PS: I started this thread for a PIC32 problem and there it is a problem under all circumstances.


    AVIX
    the PIC32 & dsPIC/PIC24 RTOS with:
    - Zero Latency Interrupts
    - The best performance!
    - Integrated Power Management
    Download here: http://www.avix-rt.com/
    #7
    zardoz1
    Super Member
    • Total Posts : 1852
    • Reward points : 0
    • Joined: 2005/07/09 08:03:28
    • Location: 's-Hertogenbosch, The Netherlands
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/21 11:40:24 (permalink)
    0
    To come back to the issue once more. I just created a macro which does exactly what I want. Create an atomic operation for setting a bitfield and bottom line it is even more efficient (one instruction) than the basic way of doing things.
     
    Take for instance:
     
    AD1CON2bits.SMPI = 3;


    SMPI is a 4 bit field and with the highest optimization the compiler generates:
     

     019F8  BFC322     mov.b 0x0322,0x0000
     019FA  B3CC31     mov.b #0xc3,0x0002
     019FC  604001     and.b 0x0000,0x0002,0x0000
     019FE  B340C0     ior.b #0xc,0x0000
     01A00  B7E322     mov.b 0x0000,0x0322

     
    So it reads address 322 (AD1CON2bits), manipulates the desired field and writes the result back, potentially changing other bits of this register that are changed by other threads or ISR's in between the read and the write.
     
    I changed this to the macro I am currently developing and now the code looks like:
     

    avixSFR_SF(AD1CON2, SMPI, 3);

     
    Now the compiler generates (-O1 .. -O3)
     

     019F8  801910     mov.w 0x0322,0x0000
     019FA  68006C     xor.w 0x0000,#12,0x0000
     019FC  B203C0     and.w #0x3c,0x0000
     019FE  B6A322     xor.w 0x0322

     
    This is even one instruction shorter and other fields of the register which are changed by other threads or ISR's in between the read and the xor are not changed because of the xor. So as long as a certain field is used by one thread or one ISR other fields are not influenced.
     
    The macro that does this all is shown below:
     

     
    #define _avixParseStruct(a)      a##BITS
    #define _avixParseStructVar(a)   a##bits


    #define avixSFR_SF(r,f,v)           \
    {                                   \
        union                           \
        {                               \
            _avixParseStruct(r) o;      \
            unsigned int        i;      \
        } lm, lv, lc;                   \
        lm.i = 0;                       \
        lv.i = 0;                       \
        lm.o.f = -1;                    \
        lv.o.f = v;                     \
        lc.o = _avixParseStructVar(r);  \
        __asm__ __volatile__(           \
            " xor %0              "     \
            : "=U"(r)                   \
            : "a"(lm.i & (lv.i ^ lc.i)) \
        );                              \
    }


     
    In the final version this macro will work for PIC32 also


    AVIX
    the PIC32 & dsPIC/PIC24 RTOS with:
    - Zero Latency Interrupts
    - The best performance!
    - Integrated Power Management
    Download here: http://www.avix-rt.com/
    #8
    zardoz1
    Super Member
    • Total Posts : 1852
    • Reward points : 0
    • Joined: 2005/07/09 08:03:28
    • Location: 's-Hertogenbosch, The Netherlands
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/21 13:29:09 (permalink)
    0
    One more thing comes to my mind. Indeed, IFS0bits.T1IF = 0; does translate to a singe bcl and thus is atomic but when instead of a constant a variable is used for the value it is no longer atomic.
     
    so something like:
     
    IFS0bits.T1IF = var;
     
    will again result i a potential RMW problem. I don't want to be caught by al these details. So for this reason I have created my own atomic operations which are guaranteed to be atomic under all circumstances.


    AVIX
    the PIC32 & dsPIC/PIC24 RTOS with:
    - Zero Latency Interrupts
    - The best performance!
    - Integrated Power Management
    Download here: http://www.avix-rt.com/
    #9
    Deenayd
    Super Member
    • Total Posts : 905
    • Reward points : 0
    • Joined: 2004/09/08 06:15:13
    • Location: Poland
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/22 00:05:09 (permalink)
    0
    I'd like to add just one thing more:
     
    Using the first construct leads to a read-modify-write sequence. When in between the read and the write a higher priority interrupt occurs, the interrupt flag reset by this other ISR is set again when the read of the first ISR finishes. As a result the interrupt flag of the second ISR is not cleared resulting in the ISR being entered a second time which is wrong.

     
    This is not the only situation when this could be dangerous. Even if the code would execute with IPL7 or with interrupts disabled it would still be dangerous.
     
    If IFS0 contained any other interrupt flag used by the application, this flag could be set by hardware after reading register with software and before writing it back. The effect is not only r-m-w could lead to incorrect setting of interrupt flag, but also to clearing it.

    Slawek Piotrowski
    Rejestracja Czasu Pracy Ewidencja Czasu Pracy
    #10
    zardoz1
    Super Member
    • Total Posts : 1852
    • Reward points : 0
    • Joined: 2005/07/09 08:03:28
    • Location: 's-Hertogenbosch, The Netherlands
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/22 00:32:07 (permalink)
    0
    If IFS0 contained any other interrupt flag used by the application, this flag could be set by hardware after reading register with software and before writing it back. The effect is not only r-m-w could lead to incorrect setting of interrupt flag, but also to clearing it.

     
    Very true.


    AVIX
    the PIC32 & dsPIC/PIC24 RTOS with:
    - Zero Latency Interrupts
    - The best performance!
    - Integrated Power Management
    Download here: http://www.avix-rt.com/
    #11
    asmallri
    Super Member
    • Total Posts : 1864
    • Reward points : 0
    • Joined: 2004/05/26 09:00:05
    • Location: Perth, Australia
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/22 00:46:07 (permalink)
    0
    ORIGINAL: Deenayd

    I'd like to add just one thing more:

    Using the first construct leads to a read-modify-write sequence. When in between the read and the write a higher priority interrupt occurs, the interrupt flag reset by this other ISR is set again when the read of the first ISR finishes. As a result the interrupt flag of the second ISR is not cleared resulting in the ISR being entered a second time which is wrong.


    This is not the only situation when this could be dangerous. Even if the code would execute with IPL7 or with interrupts disabled it would still be dangerous.

    If IFS0 contained any other interrupt flag used by the application, this flag could be set by hardware after reading register with software and before writing it back. The effect is not only r-m-w could lead to incorrect setting of interrupt flag, but also to clearing it.


    Creating a solution for which a problem does not exist.

    The individual bit set and clear operations are atomic. The situation you are attempting to guard against is no different than any read-modify-write operation that spans multiple instruction cycles.

    If you want to manipulate interrupt flags safely on the PIC24/dsPIC33 then using the bit set/clear instructions are the fool proof way to do it.

    Regards, Andrew

    http://www.brushelectronics.com/index.php?page=software
    Home of Ethernet, SD Card, and Encrypted Serial and USB Bootloaders for PICs!!
    #12
    zardoz1
    Super Member
    • Total Posts : 1852
    • Reward points : 0
    • Joined: 2005/07/09 08:03:28
    • Location: 's-Hertogenbosch, The Netherlands
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/22 02:55:48 (permalink)
    0
    Creating a solution for which a problem does not exist.

    The individual bit set and clear operations are atomic. The situation you are attempting to guard against is no different than any read-modify-write operation that spans multiple instruction cycles.

    If you want to manipulate interrupt flags safely on the PIC24/dsPIC33 then using the bit set/clear instructions are the fool proof way to do it.

     
    I don't think that I made clear what problem I am solving. Note the original post had nothing to do with PIC24/33 but was for PIC32 where it is a problem. The problem is already recognized at hardware level there since most SFR's contain three additional registers for atomic Set, Clear and Invert of the applicble bits. On PIC32 these must be used instead of the actual SFR, a mistake that also proved to be made in the TCP/IP stack.
     
    Yes, for resetting the interrupt flag on PIC24/33 you are right, the problem does not exist but this is just one of the many SFR bit manipulation operations needed in a typical application. I created a generic solution that works for any bitfield in any SFR, regardless the size of the bitfield.
     
    Take for instance controlling an LCD. Suppose the data is transferred on E0..E3 and the other E bits are used by another thread for another purpose. When the LCD controlling thread manipulates E0..E3, this must be done in such a way the other E bits (owned by another thread) are not accidentally changed. By creating an atomic set using the xor, this is guaranteed.
     
    But on the other hand, if you think this is not a problem, no problem. Feel free to ignore the whole issue and just continue the way you always did and be happy with it. I am afraid however that by not paying attention to this issue, once you will end up with a system that fails now and then and never in a reproducable way. But, that's up to you wink
     
     


    AVIX
    the PIC32 & dsPIC/PIC24 RTOS with:
    - Zero Latency Interrupts
    - The best performance!
    - Integrated Power Management
    Download here: http://www.avix-rt.com/
    #13
    zardoz1
    Super Member
    • Total Posts : 1852
    • Reward points : 0
    • Joined: 2005/07/09 08:03:28
    • Location: 's-Hertogenbosch, The Netherlands
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/22 05:53:32 (permalink)
    5 (1)
    And here are the generic macros setting any bit field in any SFR in an atomic fashion.

    Usage: avixSFR_SF(<SFR>, <field>, <value>);

     
    For PIC32:
    So for instance:

    avixSFR_SF(LATA, LATA3, 0); translates to writing 0x00000008 to register LATACLR
    avixSFR_SF(LATA, LATA2, 1); translates to writing 0x00000004 to register LATASET

    And when specifying a field consisting of more than one bit, the macro translates to writing a value to the related INV register such that the field will contain the desired absolute value.

    Do note that atomicity is guaranteed on field level, a specific field may not be used from multiple active entities like main, ISR and/or thread. The macro guarantees atomic updates when a single SFR field is used from a single active entity.



       #define _avixParseSR(r,e)        r##e
       #define _avixParseFldDef(r,f,e)  _##r##_##f##_##e

       #define avixSFR_SF(r,f,v) {                                            \
           if (_avixParseFldDef(r,f,LENGTH) == 1) {                           \
               if(v) { _avixParseSR(r,SET) = _avixParseFldDef(r,f,MASK); }    \
               else  { _avixParseSR(r,CLR) = _avixParseFldDef(r,f,MASK); }    \
           } else {                                                           \
               _avixParseSR(r,INV) =                                          \
                   _avixParseFldDef(r,f,MASK) &                               \
                   (((v) << _avixParseFldDef(r,f,POSITION)) ^ r);             \
           }                                                                  \
       }


     
    And below the final version for PIC24/33:
     

        /* Internal helper macro
        */
        #define _avixParseStruct(a)           a##BITS
        #define _avixParseStructVar(a)        a##bits
       
       
        #define avixSFR_SF(r,f,v) {                          \
            union {                                          \
                _avixParseStruct(r) o;                       \
                unsigned int        i;                       \
            } register lcur asm("w0"), lmask={}, lval={};    \
            lmask.o.f = -1;                                  \
            if (lmask.i & (lmask.i-1)) {                     \
                lval.o.f = v;                                \
                lcur.o = _avixParseStructVar(r);             \
                __asm__ __volatile__                         \
                (    " xor %0            "                   \
                    : "=U"(r)                                \
                    : "a"(lmask.i & (lval.i ^ lcur.i))); }   \
            else {                                           \
                if (v){_avixParseStructVar(r).f = 1;}        \
                else  {_avixParseStructVar(r).f = 0;} }    }

     
     
     
     

    (I love the C preprocessor wink)

    post edited by zardoz1 - 2008/12/22 05:57:40


    AVIX
    the PIC32 & dsPIC/PIC24 RTOS with:
    - Zero Latency Interrupts
    - The best performance!
    - Integrated Power Management
    Download here: http://www.avix-rt.com/
    #14
    QKernel
    Super Member
    • Total Posts : 220
    • Reward points : 0
    • Joined: 2008/09/23 17:09:44
    • Location: Alberta Canada
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/22 14:26:19 (permalink)
    0
    Interesting discussion. I think the read-modify-write problem is one of the most common mistakes and problems are hard to find.
    We use a RTOS for almost all our products (oil-industry), so atomic instructions are important. We use atomic inline functions that generate assembler, more or less the same as the ones zardoz1 published. So things like
     
        qOR(0x0010,&LATA), qAND(~0x0010,&LATA)
     
    Other mistakes you see are things like writing a byte to the low-byte of a port
     
        LATA &= 0xFF00;
        LATA |= chr;
     
    The &= and |= construct hides the read-modify-write operation, but it is there. We use a function like this to solve this:
     
        qMOVLB(chr,&LATA).
     
    static inline void qMOVLB(char Value, volatile unsigned* pData) {
                __asm__ __volatile__("mov.b %0, [%1] " : : "r"(Value) , "r"(pData) );
    }
    static inline void qMOVHB(char Value, volatile unsigned* pData) {
                __asm__ __volatile__("mov.b %0, [%1+1] " : : "r"(Value) , "r"(pData) );
    }
     
    Q
    #15
    DaytonaFiend
    Administrator
    • Total Posts : 138
    • Reward points : 0
    • Joined: 2007/11/10 10:54:30
    • Location: Microchip Technology
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/23 02:15:14 (permalink)
    5 (1)
    It is worthwhile pointing out that the PIC32 peripheral libraries handle these case, so if you look at the definition of the macro for clearing the T1 interrupt flag in int.h you will find:


    #define mT1ClearIntFlag() (IFS0CLR = _IFS0_T1IF_MASK)
     

    So.... it may be better to stick with those since the PIC32 guys have done a good job of identifying these cases.
     
     
    ..DF
     
    #16
    zardoz1
    Super Member
    • Total Posts : 1852
    • Reward points : 0
    • Joined: 2005/07/09 08:03:28
    • Location: 's-Hertogenbosch, The Netherlands
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2008/12/23 02:32:57 (permalink)
    5 (1)
    ORIGINAL: DaytonaFiend

    It is worthwhile pointing out that the PIC32 peripheral libraries handle these case, so if you look at the definition of the macro for clearing the T1 interrupt flag in int.h you will find:


    #define mT1ClearIntFlag() (IFS0CLR = _IFS0_T1IF_MASK)


    So.... it may be better to stick with those since the PIC32 guys have done a good job of identifying these cases.


    ..DF


     
    I know these macro's exist and for resetting interrupt flags these are great. It is however also needed to change other SFR bit fields in an atomic fashion and I want code to be portable between the PIC32 and the PIC24/33 controllers.
     
    Although the starting point of this thread is based on an interrupt example from the TCP/IP stack (which does not use the mentioned macro by the way), the whole idea is to offer a generic mechanism for creating atomic bitfield manipulation.


    AVIX
    the PIC32 & dsPIC/PIC24 RTOS with:
    - Zero Latency Interrupts
    - The best performance!
    - Integrated Power Management
    Download here: http://www.avix-rt.com/
    #17
    grzegorzk
    New Member
    • Total Posts : 2
    • Reward points : 0
    • Joined: 2009/05/01 04:07:43
    • Location: 0
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2009/05/01 04:19:56 (permalink)
    0
    Hi

    Thank You zardoz1 for macros.
    I have one problem: macros generating warnings:

    source\uart1.c:227: warning: 'register' is not at beginning of declaration

    every macro, one warning, is not acceptable.

    I do not understand this macro so I cannot fix it.
    Could someone help me?

    Compiler: C30 from Microchip gcc 3.12, flags:
     
    -g -O2 -Wall -W -funsigned-char -Winline -Wsign-compare -Wcast-align -Wcast-qual -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wredundant-decls  -Wshadow -Wstrict-prototypes -Wundef  -Wwrite-strings  -mlarge-data -mlarge-code -fno-schedule-insns -fno-schedule-insns2 
    post edited by grzegorzk - 2009/05/01 04:21:43
    #18
    zardoz1
    Super Member
    • Total Posts : 1852
    • Reward points : 0
    • Joined: 2005/07/09 08:03:28
    • Location: 's-Hertogenbosch, The Netherlands
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2009/05/01 09:21:53 (permalink)
    0
    I understand the warning is cause by the fact a register variable is used and these macros typically are not only at the beginning of a block.
     
    Change the line with the register variable to:
     

          } lcur, lmask={}, lval={};    \


     
    And the macro will work as expected.  Note the real strength is setting multi bit fields in an atomic fashion and under many circumstances these macros generate code even more efficient than using the regular approach which is not atomic for multibit bit fields.
     
    However don't use the macro without optimization since then a lllooootttt of code is generated, so at least -O1


    AVIX
    the PIC32 & dsPIC/PIC24 RTOS with:
    - Zero Latency Interrupts
    - The best performance!
    - Integrated Power Management
    Download here: http://www.avix-rt.com/
    #19
    grzegorzk
    New Member
    • Total Posts : 2
    • Reward points : 0
    • Joined: 2009/05/01 04:07:43
    • Location: 0
    • Status: offline
    RE: Wrong way to clear an interrupt flag, very important 2009/05/04 04:39:04 (permalink)
    0
    ORIGINAL: zardoz1
    Note the real strength is setting multi bit fields in an atomic fashion and under many circumstances these macros generate code even more efficient than using the regular approach which is not atomic for multibit bit fields.

     
    Seems yes and no.
     
    avixSFR_SF(AD1CON2, SMPI, 0x0);
    avixSFR_SF(AD1CON2, SMPI, 0xf);
     
    both above are less efficient, any other (did not test all, roughly only) seems be more efficient.
    However is indeed proper way to use this macro.
    #20
    Page: 12 > Showing page 1 of 2
    Jump to:
    © 2019 APG vNext Commercial Version 4.5