Question
Confused about casting and order of operations
This is a very specific problem and I haven't heard back from the author, so I thought I would throw this out and see if my sanity is intact or not.
This is in regard to this video regarding DMA on a particular ARM processor STM32F407 and casting 16 bit words to 32 bit. I used to consider myself an expert in C but something is wrong here or my thinking is wrong.
Now around 16:46, you will see this setup for the DMA:
uint16_t rxBuf[8];
uint16_t txBuf[8];
...
HAL_I2SEx_TransmitReceive_DMA(&hi2s2, txBuf, rxBuf, 4);
And around 19:05 you will see this in the callback routine:
int lsample = (int) (rxBuf[0]<<16)|rxBuf[1];
int rsample = (int) (rxBuf[2]<<16)|rxBuf[3];
Now, what's going on is that the STM32F407 can only do DMA using 16-bit words, even if the data on the serial bus (I2S) is 24-bit or 32-bit data. I am sure (or assuming) that type int
is the same as int32_t
. The value in rxBuf[0]
contains the upper 16 bits of a sample and rxBuf[1]
has the lower 16 bits of the 32-bit left-channel sample.
My problem is the parenths surrounding rxBuf[0]<<16
do not include the cast (int)
to its left.
How can that possibly work? The cast to 32 bits applies to the result (rxBuf[0]<<16)
but what is inside the pareths is only a 16-bit unsigned value being shifted left by 16 bits. There should be nothing but zeros left in that 16-bit value when it is cast to 32 bits.
I think the two lines of code should be
int32_t lsample = (int32_t) ( ( (uint32_t)rxBuf[0]<<16 ) | (uint32_t)rxBuf[1] );
int32_t rsample = (int32_t) ( ( (uint32_t)rxBuf[2]<<16 ) | (uint32_t)rxBuf[3] );
First you must cast the value rxBuf[0]
into (uint32_t)
, then shift it left 16 bits. C will naturally cast the 16-bit value rxBuf[1]
to 32 bits since the left operand is now 32 bits, but it's good to be explicit with the cast anyway.
But that is not the code shown and the guy's project obviously works. But I cannot see how you can get anything other than zeros in the upper 16 bits of the word.
Is it that the compiler isn't working correctly and serendipitously treating these 16-bit values as a 32-bit word? Or am I (after 4 decades of coding in C) just not understanding the correct syntax for casting in C? The C reference manual seems to support my understanding of the correct syntax.