简体   繁体   中英

Gyroscope on STM32F429-DISC1 is behaving strangely

I'm quite new in STM32 world, and I have a problem with the on-board L3GD20 gyroscope on teh STM32F429-DISC1 board.

I had troubles in getting it running (the gyroscope was constantly sending the same data, even after reset or power down) and after I finally managed to get it working (by sending instructions a couple of times), I saw strange results (both on x-axis, y and z) (see graph below).

Am I missing something, or should I do something with the raw data, that will smooth it? Is there a possibility, that the IC is defective?

I am using Atollic TrueStudio v9.0 for STM32 with STM32F429-DISC1.

Here is my code:

#include "stm32f4xx.h"
#include "stm32f429i_discovery.h"
#include "stdio.h"
volatile uint32_t elapsed = 0;

#define CS_gyro_start   GPIO_ResetBits( GPIOC, GPIO_Pin_1 )
#define CS_gyro_stop    GPIO_SetBits( GPIOC, GPIO_Pin_1 )

void DelayMS( int time ){
    elapsed = time;
    while( elapsed > 0 );
}

void SysTick_Handler(){
    if( elapsed > 0 ) --elapsed;
}

void SendChar( char ch ){
    while( USART_GetFlagStatus( USART1, USART_FLAG_TXE ) == RESET ){}
    USART_SendData( USART1, ch );
}
void sendString( const char *s ){
    while( *s ){
        SendChar( *s++ );
    }
}
int _write( int file, char *ptr, int len ){
    sendString( ptr );
return len;
}  //sadly this doesn't work with float variables


void initialize( void ){
    RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA |
                            RCC_AHB1Periph_GPIOC |
                            RCC_AHB1Periph_GPIOF, ENABLE );

    RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI5 |
                            RCC_APB2Periph_SYSCFG |
                            RCC_APB2Periph_USART1, ENABLE );

    GPIO_InitTypeDef        gpio;
    USART_InitTypeDef       usart;
    SPI_InitTypeDef         spi;

    GPIO_StructInit(    &gpio );
    USART_StructInit(   &usart );
    SPI_StructInit(     &spi );

//usart
    GPIO_PinAFConfig( GPIOA, GPIO_PinSource10, GPIO_AF_USART1 );
    GPIO_PinAFConfig( GPIOA, GPIO_PinSource9, GPIO_AF_USART1 );

    gpio.GPIO_Mode =        GPIO_Mode_AF;
    gpio.GPIO_OType =       GPIO_OType_PP;
    gpio.GPIO_PuPd =        GPIO_PuPd_NOPULL;
    gpio.GPIO_Pin =         GPIO_Pin_9 | GPIO_Pin_10;
    GPIO_Init( GPIOA, &gpio );

    usart.USART_BaudRate =  115200;
    USART_Init( USART1, &usart );

    USART_Cmd( USART1, ENABLE );

//spi
    GPIO_PinAFConfig( GPIOF, GPIO_PinSource7, GPIO_AF_SPI5 );
    GPIO_PinAFConfig( GPIOF, GPIO_PinSource9, GPIO_AF_SPI5 );
    GPIO_PinAFConfig( GPIOF, GPIO_PinSource8, GPIO_AF_SPI5 );

    //SS
    gpio.GPIO_Pin =     GPIO_Pin_1;
    gpio.GPIO_Mode =    GPIO_Mode_OUT;
    gpio.GPIO_OType =   GPIO_OType_PP;
    gpio.GPIO_PuPd =    GPIO_PuPd_NOPULL;
    GPIO_Init( GPIOC, &gpio );
    GPIO_SetBits( GPIOC, GPIO_Pin_1 );

    //SCK, MOSI
    gpio.GPIO_Pin =     GPIO_Pin_9 | GPIO_Pin_7;
    gpio.GPIO_OType =   GPIO_OType_PP;
    gpio.GPIO_Mode =    GPIO_Mode_AF;
    gpio.GPIO_Speed =   GPIO_Speed_50MHz;
    gpio.GPIO_PuPd =    GPIO_PuPd_NOPULL;
    GPIO_Init( GPIOF, &gpio );

    //MISO
    gpio.GPIO_Pin =     GPIO_Pin_8;
    gpio.GPIO_OType =   GPIO_OType_PP;
    gpio.GPIO_Mode =    GPIO_Mode_AF;
    gpio.GPIO_Speed =   GPIO_Speed_50MHz;
    gpio.GPIO_PuPd =    GPIO_PuPd_NOPULL;
    GPIO_Init( GPIOF, &gpio );

    spi.SPI_Mode =                  SPI_Mode_Master;
    spi.SPI_NSS =                   SPI_NSS_Soft;
    spi.SPI_BaudRatePrescaler =     SPI_BaudRatePrescaler_256;
    SPI_Init( SPI5, &spi );
    SPI_Cmd( SPI5, ENABLE );

}


uint8_t SPI_sendByte( uint8_t byte_ ){
    while( SPI_I2S_GetFlagStatus( SPI5, SPI_I2S_FLAG_TXE ) == RESET ){}
    SPI_I2S_SendData( SPI5, byte_ );

    while( SPI_I2S_GetFlagStatus( SPI5, SPI_I2S_FLAG_RXNE ) == RESET ){}
return SPI_I2S_ReceiveData( SPI5 );
}

void SPI_writeData( uint8_t address, uint8_t byteToWrite ){
    CS_gyro_start;
        SPI_sendByte( address );
        SPI_sendByte( byteToWrite );
    CS_gyro_stop;
}

void GetGyroValues( uint16_t *x, uint16_t *y, uint16_t *z ){
    CS_gyro_start;
        SPI_sendByte( 0x29 | 0x80 );
        *x = SPI_sendByte( 0xff );
    CS_gyro_stop;
    CS_gyro_start;
        SPI_sendByte( 0x28 | 0x80 );
        *x |= (SPI_sendByte( 0xff ) << 8);
    CS_gyro_stop;

    CS_gyro_start;
        SPI_sendByte( 0x2B | 0x80 );
        *y = SPI_sendByte( 0xff );
    CS_gyro_stop;
    CS_gyro_start;
        SPI_sendByte( 0x2A | 0x80 );
        *y |= (SPI_sendByte( 0xff ) << 8);
    CS_gyro_stop;

    CS_gyro_start;
        SPI_sendByte( 0x2D | 0x80 );
        *z = SPI_sendByte( 0xff );
    CS_gyro_stop;
    CS_gyro_start;
        SPI_sendByte( 0x2C | 0x80 );
        *z |= (SPI_sendByte( 0xff ) << 8);
    CS_gyro_stop;
}

int main( void ){
    SysTick_Config( SystemCoreClock / 1000 );
    initialize();

    SPI_writeData(0x20, 0xff);  //power on, settings from TM-library & datasheet
    SPI_writeData(0x21, 0x00);  //high-pass filter settings
    SPI_writeData(0x24, 0x10);  //high-pass filter en
    SPI_writeData(0x23, 0x20);  //scale 2000

    uint16_t x, y, z;
    while( 1 ){
        GetGyroValues( &x, &y, &z );
        printf( "x: %d\r\n", x );

        DelayMS( 100 );

    }
}


uint32_t sEE_TIMEOUT_UserCallback(void)
{
  /* TODO, implement your code here */
  while (1)
  {
  }
}//   This is required by Atollic

Here is a sample graph showing the changes on x-axis. (the discovery board was more or less at 45 degrees, when it's at 0 degrees - laying down, then the output is a stable 65000) COM端口视图

From the L3GD20 app note :

在此处输入图片说明

Note the last part "expressed as a two's complement number" ; you are incorrectly interpreting the data as unsigned . It looks like the value is hovering around zero; or actually it looks like you are holding it rather unsteadily in a position, but certainly not rotating it continuously as a steady rate. The device is a gyroscope not an accelerometer . It measures angular velocity not acceleration (or tilt - ie acceleration due to gravity). While stationary you would expect zero on all axes. What your graph shows is probably your hand shaking trying to hold it at 45 degrees.

void GetGyroValues( int16_t *x, int16_t *y, int16_t *z )

should be more sucessful, and of course:

    int16_t x, y, z;

You can get an approximate measure of change of angle by integrating angular velocity, but not absolute angle. Even then you may have to calibrate frequently for zero - a small non-zero bias in integration will manifest itself as a false slow rotation.

As from the datasheet L3GD20 , table 17, the OUT_XL is at address 0x28 and OUT_XH at address 0x29. So you have to left shift the value with address 0x29 not 0x28 and vica versa. This also with Y and Z values.

void GetGyroValues( int16_t *x, int16_t *y, int16_t *z ){
    CS_gyro_start;
    SPI_sendByte( 0x28 | 0x80 );
    *x = SPI_sendByte( 0xff );
    CS_gyro_stop;
    CS_gyro_start;
    SPI_sendByte( 0x29 | 0x80 );
    *x |= (SPI_sendByte( 0xff ) << 8);
    CS_gyro_stop;

    CS_gyro_start;
    SPI_sendByte( 0x2A | 0x80 );
    *y = SPI_sendByte( 0xff );
    CS_gyro_stop;
    CS_gyro_start;
    SPI_sendByte( 0x2B | 0x80 );
    *y |= (SPI_sendByte( 0xff ) << 8);
    CS_gyro_stop;

    CS_gyro_start;
    SPI_sendByte( 0x2C | 0x80 );
    *z = SPI_sendByte( 0xff );
    CS_gyro_stop;
    CS_gyro_start;
    SPI_sendByte( 0x2D | 0x80 );
    *z |= (SPI_sendByte( 0xff ) << 8);
    CS_gyro_stop;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM