cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 Endianess and 24 bit data

Brother Theo
Associate II
Posted on April 29, 2018 at 02:12

Hi, trying to get I2S working with 24 bit data. The function call HAL_I2S_Transmit takes a pointer to unsigned 16 bit var so there needs to be 2 transfers to get 24 bits into the I2S. I am using an unsigned 32 bit var and putting the 24 bit value into it, left justified. When the HAL driver unpacks the 32 bit data it does so backwards. Example:

      thisData = 0x12345678;

      uint16_t *pData = (uint16_t *) &thisData;

      uint16_t data1 = (*pData++);

      uint16_t data2 = (*pData++);

data1 gets the lower 16 bits: 0x5678

data2 gets the upper 16 bits: 0x1234

I need to take a 24 bit number and put it into a 32 bit variable, left justified, and send a 16 bit pointer to the HAL I2S function. How do I do this? What am I missing?

Thanks!

#endianness
5 REPLIES 5
T J
Lead
Posted on April 29, 2018 at 02:59

You have a 32bit value and you are reading the first half, then the second half.

We all like Big Indians, it use to be these processors had an option to switch Indians,

but its not supported by the DMA hardware

In the RM0090 reference manual, it shows this:

2.2 Memory organization

The bytes are coded in memory in little endian format. The lowest numbered byte in a word

is considered the word’s least significant byte and the highest numbered byte, the word’s

most significant.

10.3.10 Programmable data width, packing/unpacking, endianess

The DMA controller only copes with little-endian addressing for both source and

destination. This is described in Table 46: Packing/unpacking & endian behavior (bit

PINC = MINC = 1).

Change the type ...

I use a Union operator.

union cacheDataConverter {      // 8bit to 64bit converter

    uint64_t    d64[1];

    uint32_t    d32[2];

    uint16_t    d16[4];

    uint8_t      d8[8];          // byte data read/write buffer

    char     string[8];

};

in your case:

I would use a 32bit pointer:

cacheDataConverter  cacheData;

uint32_t *pData = (uint32_t *) &thisDataTable;

.

.

   cacheData.d32[0] = *pData++;

   data1 = cacheData.d16[1];

   data2 = cacheData.d16[0];

Posted on June 10, 2018 at 12:25

First, you example value  0x12345678 does not fit into 24-bits. Second, you have to change the byte order according to the section 'I2S Philips standard' of the Reference Manual (section 28.4.3.) and the example in the same section.

henry.dick
Senior II
Posted on June 10, 2018 at 13:22

Lots of ways to do it. Like left shift it to a 32 bit type first and use the code pieces you posted earlier.

Or a union......

Posted on June 11, 2018 at 00:59

You could use the Assembler REV instruction. this will reverse your data in one cycle.

excerpt from

Turvey.Clive.002

/**

\brief Reverse byte order (32 bit)

\details Reverses the byte order in integer value.

\param [in] value Value to reverse

\return Reversed value

*/

#define __REV __rev

/**

\brief Reverse byte order (16 bit)

\details Reverses the byte order in two unsigned short values.

\param [in] value Value to reverse

\return Reversed value

*/

#ifndef __NO_EMBEDDED_ASM

__attribute__((section('.rev16_text'))) __STATIC_INLINE __ASM uint32_t __REV16(uint32_t value)

{

rev16 r0, r0

bx lr

}

#endif

/**

\brief Reverse byte order in signed short value

\details Reverses the byte order in a signed short value with sign extension to integer.

\param [in] value Value to reverse

\return Reversed value

*/

#ifndef __NO_EMBEDDED_ASM

__attribute__((section('.revsh_text'))) __STATIC_INLINE __ASM int32_t __REVSH(int32_t value)

{

revsh r0, r0

bx lr

}

#endif

Posted on June 11, 2018 at 01:45

'

You could use the Assembler REV instruction. this will reverse your data in one cycle.'

no point in doing it yourself - it is part of cmsis.

anyway, the OP's ask is not about reversing the order but fast-packing / unpacking a 24-bit type to 16-bit types.