Skip to main content
Brother Theo
Associate III
April 29, 2018
Question

STM32F4 Endianess and 24 bit data

  • April 29, 2018
  • 3 replies
  • 2358 views
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
    This topic has been closed for replies.

    3 replies

    T J
    Senior III
    April 29, 2018
    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];

    Vladimir Tsichevski
    Visitor II
    June 10, 2018
    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
    Associate II
    June 10, 2018
    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......

    T J
    Senior III
    June 11, 2018
    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

    henry.dick
    Associate II
    June 11, 2018
    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.