LockedUsing PORTAbits_t to create a shadow variable for the port A?

Author
osours
Starting Member
  • Total Posts : 11
  • Reward points : 0
  • Joined: 2014/01/20 13:29:57
  • Location: 0
  • Status: offline
2014/01/27 15:07:12 (permalink)
5 (1)

Using PORTAbits_t to create a shadow variable for the port A?

Hi
in the header file of PIC16F690 I find:
 
// bitfield definitions
typedef union {
    struct {
        unsigned RA0                    :1;
        unsigned RA1                    :1;
        unsigned RA2                    :1;
        unsigned RA3                    :1;
        unsigned RA4                    :1;
        unsigned RA5                    :1;
    };
} PORTAbits_t;
extern volatile PORTAbits_t PORTAbits @ 0x005;
 
Now  I would like to use the struct type definition to create a shadow variable for the port A. I use
 
PORTAbits_t sPortA;
 
Is this OK? Or is there a better way to do it?
 
Thanks for helping and best regards
Urs
#1

15 Replies Related Threads

    NKurzman
    A Guy on the Net
    • Total Posts : 16662
    • Reward points : 0
    • Joined: 2008/01/16 19:33:48
    • Location: 0
    • Status: offline
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/27 15:47:53 (permalink)
    +1 (3)
    Should work.
    #2
    Ian.M
    Super Member
    • Total Posts : 13160
    • Reward points : 0
    • Joined: 2009/07/23 07:02:40
    • Location: UK
    • Status: online
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/27 16:39:03 (permalink)
    +1 (3)
    That is an elegant reuse of the standard header's types.   I suspect I'll be modding some of my code to use the same idea.
    #3
    osours
    Starting Member
    • Total Posts : 11
    • Reward points : 0
    • Joined: 2014/01/20 13:29:57
    • Location: 0
    • Status: offline
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/28 00:27:00 (permalink)
    0
    And to set all ports to 0, do I need to do this
    sPortA.RA0 = 0;
    sPortA.RA1 = 0;
    ...
    or may write
    sPortA = 0;
     
    Or is there a more straight way to set the bunch of A-ports to a defined state (0 or 1)?
     
    Regards
    Urs
     
    #4
    Ian.M
    Super Member
    • Total Posts : 13160
    • Reward points : 0
    • Joined: 2009/07/23 07:02:40
    • Location: UK
    • Status: online
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/28 03:36:16 (permalink)
    +3 (5)
    That's where it gets ugly.   The header maps two variables to the same address, but you cant do that without giving sPortA a fxed address.   You can however get exactly the same result  by casting pointers and a carefully chosen #define.  
     
    Lets call the shadow variable sPORTA for consistency with the header's naming conventions.   I am also using the standard fixed length types, so #include <stdint.h> in every file that uses them.
     
    In one and only one C file:
    volatile uint8_t sPORTA=0,sPORTB=0; // Port shadowing registers

    The must be volatile if you are going to use them in an ISR.
    In your project's header file:

    //Fake shadow port structures

    #define sPORTAbits (*(PORTAbits_t *)&sPORTA)
    #define sPORTBbits (*(PORTBbits_t *)&sPORTB)

    //psuedofunction macros

    #define updPorts() (PORTA=sPORTA, PORTB=sPORTB))  //Update ports from shadows

    //*** DECLARATIONS ***

    extern volatile uint8_t sPORTA,sPORTB; // Port shadowing

     
    And now your C files can simply include the project header and use:

    sPORTA=0b00010101; //or whatever value
    sPORTBbits.RB5=0;
    //....
    updPorts();

     
    #5
    DarioG
    Allmächtig.
    • Total Posts : 54081
    • Reward points : 0
    • Joined: 2006/02/25 08:58:22
    • Location: Oesterreich
    • Status: offline
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/28 03:52:11 (permalink)
    0
    nice you all Smile

    GENOVA :D :D ! GODO
    #6
    Ian.M
    Super Member
    • Total Posts : 13160
    • Reward points : 0
    • Joined: 2009/07/23 07:02:40
    • Location: UK
    • Status: online
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/28 04:12:06 (permalink)
    +2 (2)
    Errata:
    "The must be volatile ..." should read "They must be volatile ..."
    There's a typo in the updPorts() macro.  Its got too many ).  It should be:
    #define updPorts() (PORTA=sPORTA, PORTB=sPORTB)  //Update ports from shadows
     
    #7
    dhenry
    Super Member
    • Total Posts : 4994
    • Reward points : 0
    • Joined: 2003/11/07 12:35:12
    • Location: Colorado
    • Status: offline
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/28 05:11:29 (permalink)
    +2 (2)
    osours
    Or is there a more straight way to set the bunch of A-ports to a defined state (0 or 1)?

    Put your union to work:
    // bitfield definitions
    typedef union {
        unsigned char all;
        struct {
            unsigned RA0                    :1;
            unsigned RA1                    :1;
            unsigned RA2                    :1;
            unsigned RA3                    :1;
            unsigned RA4                    :1;
            unsigned RA5                    :1;
        };
    } PORTAbits_t;
    extern volatile PORTAbits_t PORTAbits @ 0x005;

    PORTAbits_t sPortA;

    /* ... */

    sPortA.all = 0;
    sPortA.all = ~0;

    #8
    osours
    Starting Member
    • Total Posts : 11
    • Reward points : 0
    • Joined: 2014/01/20 13:29:57
    • Location: 0
    • Status: offline
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/28 06:06:21 (permalink)
    0
    @ Ian: Thank you! The line #define sPORTAbits (*(PORTAbits_t *)&sPORTA) is hard to follow, in fact I cannot understand it.
     
    @ dhenry: This would imply a nesseary modification of the  header file of PIC16F690, what I would like to avoid. However, would this be possible:
     
    struct new_type {
    union {
        unsigned char all; 
        PORTAbits_t;
            }
    }
     
    main() {
    new_type sPortA;
    sPortA.B10 =1;
    ....
    sPortA.all = 0b111111;
    ....
    sPortA.all = ~0;
    ....
    }
     
    Best regards to both
    Urs
    #9
    Ian.M
    Super Member
    • Total Posts : 13160
    • Reward points : 0
    • Joined: 2009/07/23 07:02:40
    • Location: UK
    • Status: online
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/28 07:04:31 (permalink)
    +3 (3)
    Lets dissect #define sPORTAbits (*(PORTAbits_t *)&sPORTA)
    • &sPORTA is the address of the file register used for shadowing.  It has type uint8_t * volatile (i.e a pointer to a volatile byte).
    • (PORTAbits_t *) is a cast.  It forces the type of the address to be a pointer to a PORTAbits_t structure.
    • The * in front of the cast dereferences the pointer. i.e. it gives a PORTAbits_t structure mapped to the address of sPORTA.
    • The outer () is to prevent any other operators with higher precedence interfering with the expression *(PORTAbits_t *)&sPORTA.  Without it the . (dot) operator would grab sPORTA, and the compiler would barf as sPORTA is not of type PORTAbits_t so cannot be used that way.
    • The  #define sPORTAbits replaces every sPORTAbits in the rest of the program with the text following it, so faking the existence of a PORTAbits_t sPORTAbits @&sPORTA; which isn't legal (Error  [236]) to do directly in XC8 C.
    At the end of all that,  you can use sPORTAbits in absolutely any expression you could use PORTAbits in.  Arguably, as the sPORTn variables are volatile, I'm missing a volatile in the cast, and I should  use:

    #define sPORTAbits (*(PORTAbits_t * volatile)&sPORTA)
    #define sPORTBbits (*(PORTBbits_t * volatile)&sPORTB)

    to make sure the faked xPORTnbits structures are also volatile.
     
     


    #10
    dhenry
    Super Member
    • Total Posts : 4994
    • Reward points : 0
    • Joined: 2003/11/07 12:35:12
    • Location: Colorado
    • Status: offline
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/28 08:05:48 (permalink)
    +1 (1)
    osours
    @ dhenry: This would imply a nesseary modification of the  header file of PIC16F690, what I would like to avoid.

    Similar to how you copied from the header file to paste in your post and how I copied from your post to paste in my reply, you would copy from the header file and paste in your code, add the 'all' member, and name your new type (e.g., myPORTAbits_t).
    #11
    crossrw
    New Member
    • Total Posts : 6
    • Reward points : 0
    • Joined: 2014/01/23 02:05:44
    • Location: Moscow, Russia
    • Status: offline
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/28 08:18:05 (permalink)
    -1 (1)
    Hi!
    What do you mean by "shadow variable for the port A" ?
     
    Definition "PORTAbits_t sPortA" creates a new variable "sPortA", access individual bits of which is possible through the fields of the structure.
    An alternative is to declare their union and struct. Smile
     
     
    #12
    osours
    Starting Member
    • Total Posts : 11
    • Reward points : 0
    • Joined: 2014/01/20 13:29:57
    • Location: 0
    • Status: offline
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/28 08:18:50 (permalink)
    +1 (1)
    Thank you very much to everyone who helped me!
    @ Ian: Now I understand, but remain amazed about your code line!
    @ dhenry: OK, I understand now.
     
    Best regards
    Urs
     
    #13
    osours
    Starting Member
    • Total Posts : 11
    • Reward points : 0
    • Joined: 2014/01/20 13:29:57
    • Location: 0
    • Status: offline
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/28 08:28:52 (permalink)
    +3 (3)
    Some PIC uC have the read-modify-write problem (short rmw). The shadow variable is in fact a copy of the port and is used to avoid the rmw problem. So instead of
    PORTAbits.RA0 = 1;
    PORTAbits.RA1 = 1;
    which could cause the rmw problem you use the shadow variable
    sPORTAbits.RA0 = 1;
    sPORTAbits.RA1 = 1;
    PORTA = sPortA;
    So, modifcations are only done in the shadow variable, and then copied to the acutal port.
     
    Best regards
    Urs
    #14
    1and0
    Access is Denied
    • Total Posts : 8531
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/28 10:57:11 (permalink)
    +1 (1)
    With the union, one would have to use sPortA.all instead of simply sPortA.
     
    #15
    Ian.M
    Super Member
    • Total Posts : 13160
    • Reward points : 0
    • Joined: 2009/07/23 07:02:40
    • Location: UK
    • Status: online
    Re:Using PORTAbits_t to create a shadow variable for the port A? 2014/01/28 16:49:47 (permalink)
    0 (4)
    Also the #defined pointer cast and dereference is much easier to port from one midrange device to another as you aren't copy/pasting code from a processor specific header.   Even with the compiler in free mode, it compiles to the same code. e.g. simply setting or clearing a shadow 'pin' will use a BSF or BCF instruction respectively.
    #16
    Jump to:
    © 2018 APG vNext Commercial Version 4.5