STM32上的字节序问题

电器工程 C stm32 皮质-m 海合会
2022-01-31 04:54:29

我正在使用 arm gcc (CooCox) 对 STM32F4discovery 进行编程,并且一直在努力解决字节序问题

我正在通过 SPI 使用 24 位 ADC 进行采样。由于要输入三个字节,MSB 首先我想到了将它们加载到一个联合中以使它们(无论如何我希望!)更易于使用。

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

我使用 spi 读取将数据加载到类比 0.spibytes[0]-[2] 中,以 [0] 作为 MSB,然后我通过 USART 以兆波特率将它们吐出,一次 8 位。没问题。

当我尝试将数据传递到 12 位 DAC 时,问题就开始了。该 SPI DAC 需要 16 位字,其中包括从 MSB 开始的 4 位前缀,后跟 12 位数据。

最初的尝试是将 ADC 给我的二进制补码转换为偏移二进制,通过 xor-ing analogin0.spihalfwords[0] 与 0x8000,将结果移动到底部 12 位,然后在算术上添加前缀。

令人难以置信的令人沮丧,直到我注意到对于analogin0.spibytes[0]=0xFF 和analogin0.spibytes[1]=0xB5,analogin0.halfwords[0] 等于0xB5FF 而不是0xFFB5 !!!!!!

注意到这一点后,我停止使用算术运算和半字,并坚持按位逻辑和字节

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)

...这很好。当我在第一行代码之后查看 temp 时,它是 0xFFB5,而不是 0xB5FF,所以一切都很好

所以,对于问题...

  • Cortex对我来说是新的。我不记得 PIC 曾经在 int16 中进行字节交换,即使两个平台都是小端。它是否正确?

  • 有没有更优雅的方法来处理这个?如果我可以将 ARM7 置于大端模式,那就太好了。我看到很多提到 Cortex M4 是双端的,但所有消息来源似乎都没有真正告诉我如何. 更具体地说,我如何将 STM32f407 置于大端模式,如果可以在 gcc 中完成就更好了。这只是在 AIRCR 寄存器中设置适当位的问题吗?是否有任何后果,例如必须将编译器设置为匹配,或者稍后使用不一致的库搞砸数学?

4个回答

嵌入式系统总是会有大端/小端的问题。我个人的方法是始终使用本地字节序对内部存储器进行编码,并在数据进入或离开时进行任何交换。

我使用 spi 读取将数据加载到类比 0.spibytes[0]-[2] 中,其中 [0] 作为 MSB

通过加载 [0] 作为 MSB,您将值编码为大端。

类比0.spibytes[0]=0xFF 和类比0.spibytes[1]=0xB5,类比0.halfwords[0]等于0xB5FF

这表明处理器是小端的。

相反,如果您将第一个值加载到 [2] 并返回到 [0],那么您将传入的数字编码为 little-endian,本质上是在数字输入时进行交换。使用本机表示后,您可以返回使用算术运算的原始方法。只需确保在传输值时将其翻转回大端。

关于赏金“真的很想知道srm32f4大端模式”,这个芯片上没有大端模式。STM32F4 以小端序进行所有内存访问。

用户手册http://www.st.com/web/en/resource/technical/document/programming_manual/DM00046982.pdf在第 25 页提到了这一点。但还有更多。在第 93 页上,您可以看到有字节序交换指令。REV 和 REVB 用于反向和反向位。REV 会改变 32 位的字节序,而 REV16 会改变 16 位的数据。

这是一个皮质 M4 的代码片段,用 gcc 编译

/*
 * asmLib.s
 *
 *  Created on: 13 mai 2016
 */
    .syntax unified
    .cpu cortex-m4
    .thumb
    .align
    .global big2little32
    .global big2little16
    .thumb
    .thumb_func
 big2little32:
    rev r0, r0
    bx  lr
 big2little16:
    rev16   r0, r0
    bx  lr

在 C 中,调用可以是:

 extern uint32_t big2little32(uint32_t x);
 extern uint16_t big2little16(uint16_t x);

 myVar32bit = big2little32( myVar32bit );
 myVar16bit = big2little16( myVar16bit );

不知道怎么做比这更快:-)

对于 CooCox STM32F429,这是可以的:

typedef union {
  uint8_t  c[4];
  uint16_t   i[2];
  uint32_t  l[1];
}adc;

adc     adcx[8];

...

// first channel ...
    adcx[0].c[3] = 0;
    adcx[0].c[2] = UB_SPI1_SendByte(0x00);
    adcx[0].c[1] = UB_SPI1_SendByte(0x00);
    adcx[0].c[0] = UB_SPI1_SendByte(0x00);