Skip to main content
oeliks
Associate III
January 9, 2020
Solved

How to divide word variable into 2x halfword?

  • January 9, 2020
  • 13 replies
  • 2694 views

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 :)

This topic has been closed for replies.
Best answer by Danish1

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

13 replies

Danish1
Danish1Best answer
Lead III
January 9, 2020

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
January 9, 2020

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

berendi
Principal
January 9, 2020

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;

Ozone
Principal
January 9, 2020

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.

Bob S
Super User
January 9, 2020

> 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.

Tesla DeLorean
Guru
January 9, 2020

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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
oeliks
oeliksAuthor
Associate III
January 9, 2020

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 !

Piranha
Principal III
January 9, 2020

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

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

oeliks
oeliksAuthor
Associate III
January 10, 2020

How to do this?

​

Im using dma to transfer adc1&adc2 in one transfer to a buffer. I have only 1 dma but 2 adc.

​

Thanks :)​

berendi
Principal
January 10, 2020

Declare the buffer as

uint16_t adcbuffer[N][2];

then the values from one ADC would go to adcbuffer[x][0], from the other ADC to adcbuffer[x][1]

oeliks
oeliksAuthor
Associate III
January 10, 2020

I will try this, thanks ! If it will work for me it will speed up the processing of data :)​