Tool/software: Code Composer Studio
Hello folks,
I'm trying to read the sensor values from the MPU6050 module, but sometimes the code hangs (forcing me to power cycle the Tiva, reseting is futile) or reads wrong values (appears to be consistent, but not what it should be).
I've already tried using Arduino and the sensor works perfectly with the Uno. I've also interfaced the sensor with an ATmega328P on a breadboard using 3V3 to see if it's the voltage that was causing the problem, but it worked there also. So no problems working with 3V3.
Since the sensorlib poorly explains how to read from MPU6050 (not trying to be mean here, but there are problems including the files, adapting the I²C code to use the I2CM, etc), I've decided to make the readings myself using the I²C the "traditional way", reading/writing from/to registers manually.
Here is my code:
#include <stdbool.h> #include <stdint.h> #include "inc/hw_i2c.h" #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "driverlib/gpio.h" #include "driverlib/i2c.h" #include "driverlib/interrupt.h" #include "driverlib/pin_map.h" #include "driverlib/sysctl.h" #include "driverlib/uart.h" #include "uartstdio.h" #include "driverlib/rom.h" #include "driverlib/rom_map.h" #define SLAVE_ADDRESS 0x68 volatile int32_t g_ACXH; volatile int32_t g_ACXL; volatile int32_t g_ACX; volatile int32_t g_ACYH; volatile int32_t g_ACYL; volatile int32_t g_ACY; volatile int32_t g_ACZH; volatile int32_t g_ACZL; volatile int32_t g_ACZ; volatile int32_t g_TempH; volatile int32_t g_TempL; volatile int32_t g_Temp; volatile int32_t g_temperature = 0; volatile int32_t g_GCXH; volatile int32_t g_GCXL; volatile int32_t g_GCX; volatile int32_t g_GCYH; volatile int32_t g_GCYL; volatile int32_t g_GCY; volatile int32_t g_GCZH; volatile int32_t g_GCZL; volatile int32_t g_GCZ; //init the UART console baud 115200 inline void InitConsole(void) { // // Enable GPIO port A which is used for UART0 pins. // TODO: change this to whichever GPIO port you are using. // MAP_SysCtlPeripheralDisable(SYSCTL_PERIPH_GPIOA); MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOA); MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA)); // // Configure the pin muxing for UART0 functions on port A0 and A1. // This step is not necessary if your part does not support pin muxing. // TODO: change this to select the port/pin you are using. // MAP_GPIOPinConfigure(GPIO_PA0_U0RX); MAP_GPIOPinConfigure(GPIO_PA1_U0TX); // // Enable UART0 so that we can configure the clock. // MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); // // Use the internal 16MHz oscillator as the UART clock source. // MAP_UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC); // // Select the alternate (UART) function for these pins. // TODO: change this to select the port/pin you are using. // MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); // // Initialize the UART for console I/O. // UARTStdioConfig(0, 115200, 16000000); } //main program int main(void) { //set system clock to 80 MHz MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN); //init the UART InitConsole(); //clears screen UARTprintf("\033[2J"); //move cursor to position 0,0 UARTprintf("\033[0;0H"); //init the I2C0 and GPIOB MAP_SysCtlPeripheralDisable(SYSCTL_PERIPH_I2C0); MAP_SysCtlPeripheralDisable(SYSCTL_PERIPH_GPIOB); MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0); MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOB); MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0); MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_I2C0) || !MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB)); //configure PB2 to SCL and PB3 SDA MAP_GPIOPinConfigure(GPIO_PB2_I2C0SCL); MAP_GPIOPinConfigure(GPIO_PB3_I2C0SDA); MAP_GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2); MAP_GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3); //init I2C Master with 100kbps (if true would be 400kbps) MAP_I2CMasterInitExpClk(I2C0_BASE, MAP_SysCtlClockGet(), true); //sets slave adress, and master is reading from slave (writing if false) MAP_I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS, false); //initialize the MPU I2CMasterDataPut(I2C0_BASE, 0x6B); I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START); while(I2CMasterBusy(I2C0_BASE)); I2CMasterDataPut(I2C0_BASE, 0x00); I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH); while(I2CMasterBusy(I2C0_BASE)); for(;;) { //request reading from register 0x3B I2CMasterDataPut(I2C0_BASE, 0x3B); I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND); while(I2CMasterBusy(I2C0_BASE)); //master is reading from slave MAP_I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS, true); //start reading registers I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START); while(I2CMasterBusy(I2C0_BASE)); //shift the "higher" bits g_ACXH = MAP_I2CMasterDataGet(I2C0_BASE) << 8; I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); while(I2CMasterBusy(I2C0_BASE)); g_ACXL = MAP_I2CMasterDataGet(I2C0_BASE); I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); while(I2CMasterBusy(I2C0_BASE)); g_ACYH = MAP_I2CMasterDataGet(I2C0_BASE) << 8; I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); while(I2CMasterBusy(I2C0_BASE)); g_ACYL = MAP_I2CMasterDataGet(I2C0_BASE); I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); while(I2CMasterBusy(I2C0_BASE)); g_ACZH = MAP_I2CMasterDataGet(I2C0_BASE) << 8; I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); while(I2CMasterBusy(I2C0_BASE)); g_ACZL = MAP_I2CMasterDataGet(I2C0_BASE); I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); while(I2CMasterBusy(I2C0_BASE)); g_TempH = MAP_I2CMasterDataGet(I2C0_BASE) << 8; I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); while(I2CMasterBusy(I2C0_BASE)); g_TempL = MAP_I2CMasterDataGet(I2C0_BASE); I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); while(I2CMasterBusy(I2C0_BASE)); g_GCXH = MAP_I2CMasterDataGet(I2C0_BASE) << 8; I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); while(I2CMasterBusy(I2C0_BASE)); g_GCXL = MAP_I2CMasterDataGet(I2C0_BASE); I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); while(I2CMasterBusy(I2C0_BASE)); g_GCYH = MAP_I2CMasterDataGet(I2C0_BASE) << 8; I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); while(I2CMasterBusy(I2C0_BASE)); g_GCYL = MAP_I2CMasterDataGet(I2C0_BASE); I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); while(I2CMasterBusy(I2C0_BASE)); g_GCZH = MAP_I2CMasterDataGet(I2C0_BASE) << 8; //finish reading registers I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH); while(I2CMasterBusy(I2C0_BASE)); g_GCZL = MAP_I2CMasterDataGet(I2C0_BASE); //join the two 8 bit variables into one 16 bit g_ACX = g_ACXH | g_ACXL; g_ACY = g_ACYH | g_ACYL; g_ACZ = g_ACZH | g_ACZL; g_Temp = g_TempH | g_TempL; g_GCX = g_GCXH | g_GCXL; g_GCY = g_GCYH | g_GCYL; g_GCZ = g_GCZH | g_GCZL; //master is writing to slave MAP_I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS, false); //convert to temperature g_temperature = (g_Temp/340.00f)+36.53f; UARTprintf("ACX: \t%d\n", g_ACX); UARTprintf("ACY: \t%d\n", g_ACY); UARTprintf("ACZ: \t%d\n", g_ACZ); UARTprintf("Temp: \t%d\n", g_temperature); UARTprintf("GCX: \t%d\n", g_GCX); UARTprintf("GCY: \t%d\n", g_GCY); UARTprintf("GCZ: \t%d\n", g_GCZ); //move cursor to position 0,0 UARTprintf("\033[0;0H"); MAP_SysCtlDelay(MAP_SysCtlClockGet()/3*0.01); } }
The steps I took to make the readings on the MPU6050:
- Initialized the GPIO, I²C and UART
- Initialized the I²C master writing mode 400kbps
- Initialized the MPU writing 0x00 to register 0x6B
- Sent write request to address 0x3B
- Changed I²C to read mode
- Read the registers and place the contents to the variables
- Merged the variables making 16bitvariable = 8bitvariable_H << 8 | 8bitvariable_L
- Calculated the temperature according to equation shown on MPU's register map page 30
- Printed the variables
- Changed the I²C to write, send write request to address 0x3B and do the readings all over again
Things that decreased the hangups: changed the way I was reading the variables. Instead of shifting 8 bits left on the "H" registers later in the code, I did it right in the I2CMasterDataGet() call. It only hangs occasionally when I don't insert a delay in the loop.
Output on Arduino:
Output on Tiva:
What's causing this strange behavior?