11 votos

El problema de Endian en STM32

Estoy usando el brazo gcc (CooCox) para programar un STM32F4discovery, y he estado luchando con un problema de endian

Estoy tomando muestras con un ADC de 24 bits a través de SPI. Como están entrando tres bytes, MSB primero tuve la idea de cargarlos en una unión para hacerlos (¡esperaba, de todos modos!) un poco más fáciles de usar.

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

Cargo los datos usando lecturas de spi en analogin0.spibytes[0]-[2], con [0] como el MSB, luego los escupo vía USART a un megabarril, 8 bits a la vez. Sin problemas.

Los problemas comenzaron cuando intenté pasar los datos a un DAC de 12 bits. Este DAC SPI quiere palabras de 16 bits, que consisten en un prefijo de 4 bits que comienza en el MSB, seguido de 12 bits de datos.

Los primeros intentos fueron convertir los dos complementos que me dio la ADC para compensar el binario, mediante xor-ing analogin0.spihalfwords[0] con 0x8000, desplazando el resultado a los 12 bits inferiores, y luego agregando el prefijo en aritmética.

Increíblemente frustrante, hasta que noto que para analogin0.spibytes[0]=0xFF y y analogin0.spibytes[1]=0xB5, analogin0.halfwords[0] era igual a 0xB5FF y no 0xFFB5!!!!!

Después de notar esto, dejé de usar operaciones aritméticas y la media palabra, y me apegué a la lógica de bits y los 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)

...y esto funcionó bien. Cuando miro la temperatura después de la primera línea del código, es 0xFFB5, y no 0xB5FF, así que todo está bien.

Así que, para las preguntas...

  • La corteza es nueva para mí. No recuerdo que el PIC haya cambiado de byte en los int16, aunque ambas plataformas son Little Endian. ¿Esto es correcto?

  • ¿Hay una forma más elegante de manejar esto? Sería genial si pudiera poner el ARM7 en modo big-endian. Estoy viendo muchas referencias a que la Corteza M4 es bi-endiana, pero todas las fuentes parecen no llegar a decirme cómo . Más específicamente, ¿cómo pongo el STM32f407 en modo big-endian incluso mejor si se puede hacer en GCC. ¿Es sólo cuestión de poner el bit apropiado en el registro del AIRCR? ¿Hay alguna ramificación, como tener que ajustar el compilador para que coincida, o errores matemáticos posteriores con bibliotecas inconsistentes?

7voto

gilly Puntos 11

Los sistemas incorporados siempre tendrán el problema de los grandes y pequeños incendios. Mi enfoque personal ha sido siempre codificar la memoria interna con la idoneidad nativa y hacer cualquier intercambio justo cuando los datos entran o salen.

Cargo los datos usando lecturas de spi en analogin0.spibytes[0]-[2], con [0] como el MSB

Al cargar [0] como el MSB, estás codificando el valor como big-endian.

analogin0.spibytes[0]=0xFF y y analogin0.spibytes[1]=0xB5, analogin0.halfwords[0] era igual a 0xB5FF

Esto indica que el procesador es "little-endian".

Si en cambio, cargas el primer valor en [2] y vuelves a trabajar en [0], entonces has codificado el número entrante como little-endian, esencialmente haciendo el intercambio a medida que el número entra. Una vez que trabajas con la representación nativa, puedes volver a tu enfoque original de usar operaciones aritméticas. Sólo asegúrate de volver a big-endian cuando transmitas el valor.

6voto

Nam G VU Puntos 3494

En cuanto a la recompensa "Realmente quiero saber sobre el modo big endian srm32f4", no hay ningún modo big endian en este chip. STM32F4 hace todo el acceso a la memoria en Little Edian.

El manual de instrucciones http://www.st.com/web/en/resource/technical/document/programming_manual/DM00046982.pdf menciona esto en la página 25. Pero hay más. En la página 93 puedes ver que hay instrucciones de intercambio de los indios. REV y REVB para el bit de reversa y reversa. REV cambiará a ENDIANESS por 32 bits y REV16 lo hará por datos de 16 bits.

1voto

MANOVAboard Puntos 48

Para el CooCox STM32F429 esto está bien:

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);

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X