cancel
Showing results for 
Search instead for 
Did you mean: 

How to divide word variable into 2x halfword?

oeliks
Senior

Hi? I set my ADC1&2 in simultanous mode. I write these 2 data halfword to 1 - 32 bit variable word.

How can I divi​de this 32 bit variable into 2 separate variables? To get values of ADC1 and ADC2 separate?

ADC is 12 bit.

Thank You 🙂

1 ACCEPTED SOLUTION

Accepted Solutions
Danish1
Lead II

This is more to do with the C language than stm32 microcontrollers in particular. But I shouldn't criticise your question for that.

There are a few ways to do this.

The low 16 bits may be obtained by anding the 32-bit value with 0xffff. And the high bits by right-shifting by 16 then anding with 0xffff.

uint16_t low16 = adcResult & 0xffff;
uint16_t high16 = (adcResult >> 16) & 0xffff;

Some might regard this as inefficient because of the shifting and anding. Another way to do this is by way of a union:

union u_tag {
    uint32_t adc32;
    uint16_t adc16[2];
} u;
u.adc32 = adcResult;
/* results are now in u.adc16[0] and u.adc16[1]; */

I'm sure others can suggest yet more ways to do this.

Hope this helps,

Danish

View solution in original post

13 REPLIES 13
Danish1
Lead II

This is more to do with the C language than stm32 microcontrollers in particular. But I shouldn't criticise your question for that.

There are a few ways to do this.

The low 16 bits may be obtained by anding the 32-bit value with 0xffff. And the high bits by right-shifting by 16 then anding with 0xffff.

uint16_t low16 = adcResult & 0xffff;
uint16_t high16 = (adcResult >> 16) & 0xffff;

Some might regard this as inefficient because of the shifting and anding. Another way to do this is by way of a union:

union u_tag {
    uint32_t adc32;
    uint16_t adc16[2];
} u;
u.adc32 = adcResult;
/* results are now in u.adc16[0] and u.adc16[1]; */

I'm sure others can suggest yet more ways to do this.

Hope this helps,

Danish

berendi
Principal

bitwise operators

uint32_t cdr;
uint16_t high, low;
 
    cdr = ADCx->CDR;
    low = cdr & 0xFFFF;
    high = cdr >> 16;

through a union

union hl {
    uint32_t word;
    struct {
        uint16_t low;
        uint16_t high;
    };
} cdr;
uint16_t h, l;
 
    cdr.word = ADCx->CDR;
    h = cdr.high;
    l = cdr.low;

Neither approach is more efficient than the other, todays compilers are able to recognize what's going on, and produce equally efficient code for both.

https://godbolt.org/z/wLx7sg

In an evironment were portability is an issue, the union is the preferred solution. Think multiple platforms/architectures with 16 bit and 32 bit size.

The union example makes an explicit endianess assumption ('low', 'high'), which could be corrected with platform-dependant definitions.

Bit shifting makes an implicit endianess assumption, thus causing code portability issues.

The CM3 core also has bit field insertion/extraction commands. Also byte and half-word extend.

The barrel-shifter on the ARM architecture is very efficient.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
oeliks
Senior

Thank You @Danish @berendi​ @Ozone​ @Community member​ 

​For very elaborate ansvers ! So informational !

​//

​I used

uint16_t low16 = adcResult & 0xffff;
uint16_t high16 = (adcResult >> 16) & 0xffff;

And it works fine 🙂 Thanks again !

> Bit shifting makes an implicit endianess assumption, thus causing code portability issues.

No, it does not. In any architecture, given a 32-bit value, by definition the lower 16 bits are always stored in the "lower" 16 bits of the 32 bit word so masking the 32-bit value with 0xffff (or 0x0000ffff) will always give you the lower 16 bits. It does not matter how the 32-bit data is actually stored in RAM, which is what "endiness" refers to.

    uint32_t cdr;
    uint16_t high, low;
     
        cdr = ADCx->CDR;
        low = cdr & 0xFFFF;
        high = cdr >> 16;

These lines (as posted above) will work correctly on any CPU with any endiness. The compiler knows whether the target machine is big or little endian, and generates code accordingly when reading the "cdr" value from RAM (presuming is hasn't been optimized into a register variable). No "source code" level changes are needed, unlike the union example, which needs a different layout depending on big or little endiness.

Guys, both approaches are useful, depending on what is needed. For example, for a low halfword union gives the lowest address halfword and shifting gives the least significant halfword.

Piranha
Chief II

> I write these 2 data halfword to 1 - 32 bit variable word.

Why not to an array of two 16-bit halfwords?