Extraño comportamiento de los datos

0

Declaro variables globales para leer el sensor MPU9250.

typedef struct MPU_data{
    //Accelerometer
    int16_t ax;
    int16_t ay;
    int16_t az;
    //Gyroscope
    int16_t gx;
    int16_t gy;
    int16_t gz;
    //magnetometer
    int16_t mx;
    int16_t my;
    int16_t mz;
}MPU_data;
MPU_data mpu;

int16_t mpu_array[9];

En el bucle principal, leo datos

while(true)
{
    uint8_t Buf[14];
    I2C_Read(MPU9250_ADDRESS,0x3B,Buf,14);

    // Create 16 bits values from 8 bits data

    // Accelerometer
    int16_t ax=-(Buf[0]<<8 | Buf[1]);
    int16_t ay=-(Buf[2]<<8 | Buf[3]);
    int16_t az=Buf[4]<<8 | Buf[5];

    // Gyroscope
    int16_t gx=-(Buf[8]<<8 | Buf[9]);
    int16_t gy=-(Buf[10]<<8 | Buf[11]);
    int16_t gz=Buf[12]<<8 | Buf[13];

    uint8_t ST1;
    do
    {
        I2C_Read(MAG_ADDRESS,0x02,&ST1,1);
    }
    while (!(ST1&0x01));

    // Read magnetometer data
    uint8_t Mag[7];
    I2C_Read(MAG_ADDRESS,0x03,Mag,7);

    // Create 16 bits values from 8 bits data

    // Magnetometer
    int16_t mx=-(Mag[3]<<8 | Mag[2]); mx += 200;
    int16_t my=-(Mag[1]<<8 | Mag[0]); my -= 70;
    int16_t mz=-(Mag[5]<<8 | Mag[4]); mz -= 700;

    uint8_t mpu_data[48];
    sprintf(mpu_data, "%i, %i, %i; %i, %i, %i; %i, %i, %i;\n", ax,ay,az,gx,gy,gz,mx,my,mz);
    USART_Send_t(mpu_data);

Obtengo los datos normales

3454, -79, -7349; -85, -26, -41; -268, -200, 218;
3450, -76, -7355; -88, -27, -45; -258, -188, 216;
3440, -63, -7364; -84, -26, -43; -259, -195, 219;
3441, -70, -7355; -85, -23, -40; -259, -199, 219;

Si escribo en variables globales, obtengo un comportamiento diferente.

uint8_t Buf[14];
I2C_Read(MPU9250_ADDRESS,0x3B,Buf,14);

// Create 16 bits values from 8 bits data

// Accelerometer
mpu.ax=-(Buf[0]<<8 | Buf[1]);
mpu.ay=-(Buf[2]<<8 | Buf[3]);
mpu.az=Buf[4]<<8 | Buf[5];

// Gyroscope
mpu.gx=-(Buf[8]<<8 | Buf[9]);
mpu.gy=-(Buf[10]<<8 | Buf[11]);
mpu.gz=Buf[12]<<8 | Buf[13];

uint8_t ST1;
do
{
    I2C_Read(MAG_ADDRESS,0x02,&ST1,1);
}
while (!(ST1&0x01));

// Read magnetometer data
uint8_t Mag[7];
I2C_Read(MAG_ADDRESS,0x03,Mag,7);

// Create 16 bits values from 8 bits data

// Magnetometer
mpu.mx=-(Mag[3]<<8 | Mag[2]); mpu.mx += 200;
mpu.my=-(Mag[1]<<8 | Mag[0]); mpu.my -= 70;
mpu.mz=-(Mag[5]<<8 | Mag[4]); mpu.mz -= 700;

uint8_t mpu_data[48];
sprintf(mpu_data, "%i, %i, %i; %i, %i, %i; %i, %i, %i;\n", mpu.ax,mpu.ay,mpu.az,mpu.gx,mpu.gy,mpu.gz,mpu.mx,mpu.my,mpu.mz);
USART_Send_t(mpu_data);

Resultado

3370, -512, 0; 0, -23, 0; -68, -270, -472;
3369, -513, 0; 0, -24, 0; -68, -270, -472;
3365, -510, 0; 0, -24, 0; -68, -270, -472;
3359, -508, 0; 0, -23, 0; -62, -262, -476;

¿Qué estoy haciendo mal?

EDIT 1 (otro comportamiento extraño)

Como dije, creé una función. En los comentarios, noté un lugar que causa un comportamiento extraño.

inline void MPU_ReadAll(){
    uint8_t Buf[14];
    I2C_Read(MPU9250_ADDRESS,0x3B,Buf,14);

    // Create 16 bits values from 8 bits data

    // Accelerometer
    mpu_array[0]=-(Buf[0]<<8 | Buf[1]);
    mpu_array[1]=-(Buf[2]<<8 | Buf[3]);
    mpu_array[2]=Buf[4]<<8 | Buf[5];

    // Gyroscope
    mpu_array[3]=-(Buf[8]<<8 | Buf[9]);
    mpu_array[4]=-(Buf[10]<<8 | Buf[11]);
    mpu_array[5]=Buf[12]<<8 | Buf[13];
    uint8_t ST1;
    do
    {
        I2C_Read(MAG_ADDRESS,0x02,&ST1,1);
    }
    while (!(ST1&0x01));

    // Read magnetometer data
    uint8_t Mag[7];
    I2C_Read(MAG_ADDRESS,0x03,Mag,7);

    // Create 16 bits values from 8 bits data

    // Magnetometer
    mpu_array[6]=-(Mag[3]<<8 | Mag[2]); mpu_array[6] += 200;
    mpu_array[7]=-(Mag[1]<<8 | Mag[0]); mpu_array[7] -= 70;
    mpu_array[8]=-(Mag[5]<<8 | Mag[4]); mpu_array[8] -= 700;

    //If I delete the comments here, the program will work fine. 
    //If the data sending is commented out, the program gets stuck in this function.
    //However, I get zeros, as I wrote above.
    /*
    uint8_t mpu_data[48];
    sprintf(mpu_data, "%i, %i, %i; %i, %i, %i; %i, %i, %i;\n", mpu_array[0],mpu_array[1],mpu_array[2],mpu_array[3],mpu_array[4],mpu_array[5],mpu_array[6],mpu_array[7],mpu_array[8]);
    USART_Send_t(mpu_data);
    */
}
    
pregunta Marat Gareev

2 respuestas

1

Aquí solo hay 2 causas posibles: desbordamiento de la pila o errores de comportamiento no definidos.

Usar sprintf en un AVR pésimo es como liberar un elefante en una tienda de porcelana. Podría tener un desbordamiento de pila, en cuyo caso el problema es el programa en su totalidad y no una línea específica.

También, ten cuidado con la extraña arquitectura de Harvard. Cuando mueva las variables al alcance del archivo, puede que, paradójicamente, necesite usar la pila más , ya que el compilador tendrá que generar todo tipo de código extraño de "datos de acceso". Exactamente lo que hace, no lo sé. Desmontar y echar un vistazo. Este es un problema solo de AVR que no tendrá en CPU menos exóticas.

Ahora que sucede, también tienes tienes un comportamiento indefinido en todo el lugar.

En una MCU de 8 bits como AVR, el código como my_uint8_t << 8 invoca un comportamiento indefinido si el uint8_t contiene valores mayores que 0x7F , debido a la promoción implícita de enteros. Usted termina con datos de desplazamiento de bits en los bits de signo de un tipo de 16 bits int que está firmado. Auge. GCC tiene un optimizador agresivo, por lo que podría comenzar a hacer todo tipo de suposiciones extrañas. (Acabo de responder una pregunta muy similar aquí ).

Lo más sensato es eliminar todas las promociones implícitas del código. Hay varias formas posibles de hacer esto:

// messy one-liner
mpu.ax= -(int16_t) ((uint16_t)Buf[0]<<8 | (uint16_t)Buf[1]);

o

// readable version
uint16_t tmp = (uint16_t)Buf[0]<<8 | (uint16_t)Buf[1];
mpu.ax = -(int16_t)tmp;
    
respondido por el Lundin
0

Entonces, el problema de tal comportamiento inadecuado fue la optimización del compilador. Por defecto era Optimize (-O1) , lo cambié a None (-O0) . Ahora el programa se comporta de manera más predecible. También hice esto

volatile int16_t mpu_array[9] = {[0 ... 8] = 0};

Pero aún con estos cambios y la optimización incluida, el programa se bloquea.

    
respondido por el Marat Gareev

Lea otras preguntas en las etiquetas