Electronic – Endian problem on STM32

ccortex-mgccstm32

I'm using arm gcc (CooCox) to program an STM32F4discovery, and I've been wrestling w/ an endian problem

I'm sampling with a 24 bit ADC via SPI. Since three bytes are coming in, MSB first I had the idea of loading them into a union to make them (I hoped, anyway!) a little easier to use.

typedef union
{
int32_t spilong;
uint8_t spibytes [4];
uint16_t spihalfwords [2];} spidata;
spidata analogin0;

I load the data using spi reads into analogin0.spibytes[0]-[2], with [0] as the MSB, then I spit them out via USART at a megabaud, 8 bits at a time. No problems.

The problems started when I tried to pass the data in to a 12 bit DAC. This SPI DAC wants 16 bit words, which consist of a 4 bit prefix starting at the MSB, followed by 12 bits of data.

Initial attempts were to convert the twos complement the ADC gave me to offset binary, by xor-ing analogin0.spihalfwords[0] with 0x8000, shifting the result to the bottom 12 bits, and then adding the prefix on arithmetically.

Incredibly frustrating, until I notice that for analogin0.spibytes[0]=0xFF and and analogin0.spibytes[1]=0xB5, analogin0.halfwords[0] was equal to 0xB5FF and not 0xFFB5!!!!!

After noticing this, I stopped using arithmetic operations and the halfword, and stuck to bitwise logic and the bytes

uint16_t temp=0;
.
.
.


// work on top 16 bits
temp= (uint16_t)(analogin0.spibytes[0])<<8|(uint16_t)(analogin0.spibytes[1]);
temp=temp^0x8000; // convert twos complement to offset binary
temp=(temp>>4) | 0x3000; // shift and prepend with bits to send top 12 bits to DAC A


SPI_I2S_SendData(SPI3,temp); //send to DACa (16 bit SPI words)

… and this worked fine. When I peek at temp after the first line of code, its 0xFFB5, and not 0xB5FF, so all is good

So, for questions …

  • Cortex is new to me. I can't recall PIC ever byte swapping in int16's, even though both platforms are little endian. Is this correct?

  • Is there a more elegant way to handle this? It would be great if I could just put the ARM7 into big-endian mode. I'm seeing many references to Cortex M4 being bi-endian, but all the sources seem to stop short of actually telling me how. More specifically, how do I place the STM32f407 into big-endian mode, even better if it can be done in gcc. Is this JUST a matter of setting the appropriate bit in the AIRCR register? Are there any ramifications, such as having to set the compiler to match, or math screwups later with inconsistent libraries??

Best Answer

Embedded systems will always have the big-endian/little-endian issue. My personal approach has been to always encode internal memory with the native endianiness and make any swaps right when data enters or leaves.

I load the data using spi reads into analogin0.spibytes[0]-[2], with [0] as the MSB

By loading [0] as the MSB, you're encoding the value as big-endian.

analogin0.spibytes[0]=0xFF and and analogin0.spibytes[1]=0xB5, analogin0.halfwords[0] was equal to 0xB5FF

This indicates that the processor is little-endian.

If instead, you load the first value into [2] and work back to [0], then you've encoded the incoming number as little-endian, essentially making the swap as the number enters. Once you're working with the native representation, you can return to your original approach of using arithmetic operations. Just make sure to flip it back to big-endian when you transmit the value.