2

In my microcontroller I receive two uint8_t from UART. I need to parse it so that I can easily refer to its content later. The incoming data is like this:

10      |    9     8   |    7     6    |    5     4   |   3     2    1     0
TRETRY  |   DEAD_TMIE  |    OCP_MODE   |    OCP_DEG   |         VDS_LVL     

As I am a noob and can't get bit masking to work, I went for the union trick...but it does not work as expected. Here is my union:

typedef union {
    struct {
        uint8_t dont_care   :5; //b15-b11 these bits should be discarded
        uint8_t retry_time  :1; //b10
        uint8_t dead_time   :2; //b9-b8
        uint8_t ocp_mode    :2; //b7-b6
        uint8_t degl_time   :2; //b5-b4
        uint8_t vds_lvl     :4; //b3-b0
    } bits;
    uint16_t data;
    uint8_t bytes[2];
} DRV_OverCurrentProtection;

What I receive is exactly 0000000101011001

I tried to fill the union like this:

DRV_OverCurrentProtection ocp;
ocp.data = buff[0] << 8 | buff[1];

But I get this in the debugger (obviously its wrong!):

//actual data
buff[0] volatile uint8_t    1 (Binary)  
buff[1] volatile uint8_t    1011001 (Binary)    


//after assignment to the union
data    uint16_t    101011001 (Binary)  

//bits
dont_care   uint8_t 25 '\031'       
retry_time  uint8_t 0 '\0'      
dead_time   uint8_t 1 '\001'        
ocp_mode    uint8_t 1 '\001'        
degl_time   uint8_t 0 '\0'      
vds_lvl uint8_t 0 '\0'      

I am feeling hopeless and I think with unions I go no where...would you please tell me what is going wrong in my code and implementation and yet better what is the best way to do something like this? that would be a great help to a newb.

timrau
  • 22,578
  • 4
  • 51
  • 64
DEKKER
  • 877
  • 6
  • 19
  • Sounds like you are receiving exactly two bytes, so you could just copy them into ocp.data – mnistic Nov 05 '17 at 02:12
  • What do yyou expect leftshift of 8 bits to give you for an 8-bit value? – Peter Nov 05 '17 at 02:12
  • 1
    i would skip the "union trick" and just go with regular old bit masking and shifting. the definitiion of how bit fields and unions work allow the compiler some flexibility over the implementation, which might not match your expectations. – jdigital Nov 05 '17 at 02:16
  • 2
    Possible duplicate of [Order of fields when using a bit field in C](https://stackoverflow.com/questions/19376426/order-of-fields-when-using-a-bit-field-in-c) – jdigital Nov 05 '17 at 02:23
  • This:? https://stackoverflow.com/q/47110886/905902 – wildplasser Nov 05 '17 at 02:26
  • 1
    Recommend you listen to @jdigital unless this is a hobby project that doesn't ever need to work with more than one version of one compiler. It's good to learn about bit masking because it often produces tighter code than compiler-generated code for bit fields. Suppose you want to check if `degl_time` is 3. `if ((x_as_short & 0x300) == 0x300) { ... }` generates less code than `if (x_as_union.bits.degl_time == 3)` with all compilers I've checked, and that's quite a few. – Gene Nov 05 '17 at 03:01
  • @Gene Yes this code is supposed to run only using one hardware and compiler...I very much like to learn how to do it with masking and stuff but I cant wrap my head around it that quickly...I wish someone could at least show me how to do it for this example so I can build a knowledge from it! – DEKKER Nov 05 '17 at 10:59

1 Answers1

1

Your struct is packing the bit fields from low-to-high. Just reverse the order:

struct {
    uint8_t vds_lvl     :4; //b3-b0
    uint8_t degl_time   :2; //b5-b4
    uint8_t ocp_mode    :2; //b7-b6
    uint8_t dead_time   :2; //b9-b8
    uint8_t retry_time  :1; //b10
    uint8_t dont_care   :5; //b15-b11 these bits should be discarded
} bits;

That should produce the association you're looking for.

Tom Karzes
  • 22,815
  • 2
  • 22
  • 41
  • 1
    If the OP's goal is to just make this code work, then this answer would suffice. If the OP is interested in code that doesn't depend on compiler specific behavior, then see the answer for [Order of fields when using a bit field in C](https://stackoverflow.com/questions/19376426/order-of-fields-when-using-a-bit-field-in-c) – jdigital Nov 05 '17 at 02:27
  • @jdigital Yes, I agree with that. This just explains the behavior OP was seeing, and what change would make it work in that environment. – Tom Karzes Nov 05 '17 at 03:42
  • Thanks that solves the problem for now...but I really need to learn how to do it with masking and stuff – DEKKER Nov 05 '17 at 11:00
  • @DEKKER Using shifts and masks is pretty easy. To extract a field, just right shift the containing word, then mask the appropriate number of low-order bits. To set a field, first clear the bits in the word, then left shift the value and bitwise-or it into the word. Just let me know if you need more details. – Tom Karzes Nov 05 '17 at 11:23
  • @TomKarzes Thanks...I had to do another bitwise operation but I failed at that too...I have posted a question here, would be nice if you can have a look https://stackoverflow.com/questions/47128112 – DEKKER Nov 06 '17 at 00:30
  • Yeah I just happened to see it - take a look at my answer. – Tom Karzes Nov 06 '17 at 00:39