Setting two structures at the same adress

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • melle
    New Member
    • May 2010
    • 8

    Setting two structures at the same adress

    I'm trying to set two bitfield structures on the same adres. These two structures represent two different functions. And they control a register of 8 bits off a microcontroller . Which on their turn, they drive 8 outputs.

    Why I use bitfields... is because I want to quickly set a variable to an individual port or to a defined set off ports. Depending of the function and a hardware switch.

    So the first structure is nested in a header file that was giving with the compiler and example projects. This header contains all references to registers and such. It contains the first struct part with individual variables per port...

    Code:
    typedef union{   /*  PORT DATA */
        IO_BYTE	byte;
        struct{
        IO_BYTE P00 :1;
        IO_BYTE P01 :1;
        IO_BYTE P02 :1;
        IO_BYTE P03 :1;
        IO_BYTE P04 :1;
        IO_BYTE P05 :1;
        IO_BYTE P06 :1;
        IO_BYTE P07 :1;
      }bit;
    }PDR0STR;
    
    __IO_EXTERN __io PDR0STR _pdr0
    #define PDR0 _pdr0.byte
    #define PDR0_P00 _pdr0.bit.P00
    #define PDR0_P01 _pdr0.bit.P01
    #define PDR0_P02 _pdr0.bit.P02
    #define PDR0_P03 _pdr0.bit.P03
    #define PDR0_P04 _pdr0.bit.P04
    #define PDR0_P05 _pdr0.bit.P05
    #define PDR0_P06 _pdr0.bit.P06
    #define PDR0_P07 _pdr0.bit.P07
    Now within my main program file I've built a second struct and I want link it to the same adres. And this is the part where I'm clueless...

    Code:
    #include "mb90560.h"
    #include "prototypes.h"
    
    struct myport{
       int adc_act: 7;
       int adc_indicator : 1;
    };
    
    void main(void)
    {
    myport = &PDR0
    and so on...
    I've also tried things like a struct pointer and load that with the adress off &PDR0 but that doesn't work either. I've read some things about casting, but I can't seem to understand what that does and why it's necesarry.

    Simply put, I've tried a different approach with bitmasking but in combination with interrupts... i don't like the idea that an interrupt happens in the middle of the bitmasking proces.

    I hope someone can shine a little light on where I'm stuck. A second bitfield struct seemed the best solution, but it is also the hardest (for me then) to make it work at the same register location.
  • weaknessforcats
    Recognized Expert Expert
    • Mar 2007
    • 9214

    #2
    Carefully read section 6.9 of The C Programming Language -2nd Edition.

    Then explain why you can't use a bitshifted unsigned int for this.

    Comment

    • alexis4
      New Member
      • Dec 2009
      • 113

      #3
      You are messing it too much. First of all an interrupt will not come in the middle of a command! The command will be executed and then the interrupt will come. But even if you were right, what is the actual problem? After the interrupt, registers will be restored and that's the end of it, program flow will continue normally!

      And the bitfield way is not the quick way as you imply. C commands are split into assembly commands. Giving value to bitfields is not the exception of this rule. So your code can still be paused for interrupt handling routine. Or you can disable interrupts, make the bit operations and then re-enable interrupts, something totally unnecessary.

      Here is an easier way with same speed and memory consumption:

      Code:
      #define PORTA_0     0
      #define PORTA_1     1
      #define PORTA_2     2
      //and so on.....
      
      PORTA |=    (1 << PORTA_0);     //set pin A0
      PORTA &= ~(1 << PORTA_4); //clear pin A4
      Or:

      Code:
      #define PORTA_0     1
      #define PORTA_1     2
      #define PORTA_2     4
      //and so on.....
      
      PORTA |=    PORTA_0;     //set pin A0
      PORTA &= ~PORTA_4; //clear pin A4
      But if you insist on the bitfields way, then you should absolutely use an unsigned char:

      Code:
      typedef union
      {
        unsigned char value;
        struct 
        {
          unsigned char 
                  Bit0 : 1,
                  Bit1 : 1,
                  Bit2 : 1,
                  Bit3 : 1,
                  Bit4 : 1,
                  Bit5 : 1,
                  Bit6 : 1,
                  Bit7 : 1;
        };
      } port;
      
      port myPort;
      
      myPort.value = 0xFF;
      myPort.Bit3 = true;
      I don't know what compiler you are using, so I can't tell you how you will make this union to point to a port, search for it into your compiler's guide. A pointer is likely an impossible way, pointers to ports are usually not allowed (at list for my compiler).

      Finally if you need a second structure pointing at the same address, then declare this structure inside the union. But really, stick to the simple way at the top of my post.

      Comment

      • melle
        New Member
        • May 2010
        • 8

        #4
        Ok, thx for the help so far...

        Could someone please explain why it is necessary to please an unsigned char within the union ? I'm not quite sure, but does it has something to do with the port containing 8 outputs ? I kinda understand the meaning of a union, but not the practical use of it.

        Second, when using typecasting to load p_struct2 with the adres of struct1. That is adres 0x00. I can't seem to understand the logic off it...

        p_struct2 = (struct1*) &struct2

        To me, it's seems like I'm loading the adres of struct2 into it's own pointer. And what am I exactly converting ? It alters the pointer type, but into what ?

        Comment

        • donbock
          Recognized Expert Top Contributor
          • Mar 2008
          • 2427

          #5
          C89 allows bit fields to be of type unsigned int, signed int, or int (where int has a very different meaning than it does for regular variables). C99 added the capability to also use type _Bool for bit fields. Anything else (including IO_BYTE or unsigned char) relies on nonstandard extensions. I don't know about C++.

          The rules for how members are packed into a structure are implementation-dependent. The rules for bit fields are notoriously fickle. While these rules vary from one compiler to another, they are required to be stable and predictable for any particular compiler. Therefore, you will have to experiment with your compiler to discover how to get the bit fields to line up the way you want them -- and you can expect them to line up differently when you use a different compiler.

          In my opinion, bit fields are never a good idea. Much better to do the bit manipulations explicitly so they are portable and reliable.

          Comment

          • melle
            New Member
            • May 2010
            • 8

            #6
            Originally posted by donbock
            C89 allows bit fields to be of type unsigned int, signed int, or int (where int has a very different meaning than it does for regular variables). C99 added the capability to also use type _Bool for bit fields. Anything else (including IO_BYTE or unsigned char) relies on nonstandard extensions. I don't know about C++.

            The rules for how members are packed into a structure are implementation-dependent. The rules for bit fields are notoriously fickle. While these rules vary from one compiler to another, they are required to be stable and predictable for any particular compiler. Therefore, you will have to experiment with your compiler to discover how to get the bit fields to line up the way you want them -- and you can expect them to line up differently when you use a different compiler.

            In my opinion, bit fields are never a good idea. Much better to do the bit manipulations explicitly so they are portable and reliable.

            thx for your reply. Could you please give me a simple example on how to make bit manipulation portable and reliable ?

            Comment

            • donbock
              Recognized Expert Top Contributor
              • Mar 2008
              • 2427

              #7
              Suppose the width of your I/O port is the same size as long.
              Suppose that the I/O port is read/write.
              Suppose that you want to manipulate the least-significant bit.
              Code:
              static volatile unsigned long * const pPort = <some address>;
              static const unsigned long bit0 = 0x00000001uL;
              
              // Read from a long-sized I/O port
              unsigned long readLongPort(volatile unsigned long *addr) {
                  unsigned long value;
                  value = *addr;
                  <fix endianness of 'value' if necessary>
                  return value;
                  }
              
              // Write to a long-sized I/O port
              void writeLongPort(volatile unsigned long *addr, unsigned long value) {
                  <fix endianness of 'value' if necessary>
                  *addr = value;
                  }
              
              // Set the bit
              writeLongPort(pPort, readLongPort(pPort) | bit0);
              
              // Reset the bit
              writeLongPort(pPort, readLongPort(pPort) & ~bit0);
              
              // Test if the bit is set
              if ((readLongPort(pPort) & bit0) != 0)
                  ...
              
              // Test if the bit is reset
              if ((readLongPort(pPort) & bit0) == 0)
                  ...
              You need to do a little more work for wider bit-fields.

              I recommend you handle endian mismatches between your compiler and your I/O device in access functions as shown above rather than sprinkle endian-swap logic throughout your application.

              Comment

              Working...