STM32F103 i2c won't work with MPU6050

Discussions and support about ChibiOS/HAL, the MCU Hardware Abstraction Layer.
Fulcrum Mike
Posts: 14
Joined: Fri Dec 23, 2016 3:33 am

STM32F103 i2c won't work with MPU6050

Post by Fulcrum Mike »

I hate to open new posts, yet its been over 12 hours and I can't solve this issue.
I have an STM32F103 Minimal board. I dont know much about i2c protocol. So I copied an example from testhal/STM32/STM32F1xx. The example code configures and reads data from LIS3 accelerometer. Here is my modified code for MPU6050 module:

Code: Select all

#include "ch.h"
#include "hal.h"
#include "stdio.h"   //sprintf
//#include "mpu6050.h"

#define MPU_addr 0x68
char ab[22];      //string for sprintf storage
void serialSendString(const char * s);
static uint8_t tx_data[14];
static uint8_t address;

//=====Global Config Structures=======

//---serial config structure---
static SerialConfig my_serial_cfg =
{
      115200,
};

///---i2c config structure---
static const I2CConfig i2cfg1 = {
    OPMODE_I2C,
    400000,
    FAST_DUTY_CYCLE_2,
};

void serialSendString(const char * s){
    while (*s){
        sdPut(&SD2, *(s++));
    }
}

void mpu6050_get_address(void){
    msg_t status = MSG_OK;
    systime_t tmo = MS2ST(4);
    //uint8_t address;
    //memset(address, 0x55, sizeof(address));
    tx_data[0] = 0x75;      //WHO_AM_I register
    //tx_data[0] = 0x6B;      //POWER_MNGMNT_1
    i2cAcquireBus(&I2CD2);
    status = i2cMasterTransmitTimeout(&I2CD2, MPU_addr,
                            tx_data, 1, address, 1, tmo);
    i2cReleaseBus(&I2CD2);
    if (status == MSG_TIMEOUT){
        chprintf((BaseSequentialStream*)&SD2, "Timeout\n\r");
    else if (status == MSG_RESET)
            chprintf((BaseSequentialStream*)&SD2, "Reset\n\r");
        else
            chprintf((BaseSequentialStream*)&SD2, "Done\n\r");
    chThdSleepMilliseconds(1000);
    //chprintf((BaseSequentialStream*)&SD2, "Address: %d\n\r", address);
    //chThdSleepMilliseconds(1000);
    chprintf((BaseSequentialStream*)&SD2, "Status: %D\n\r", status);
}

int main(void){
    halInit();
    chSysInit();

    static uint8_t mpu6050_data_buffer[14];
    // Activates the Serial driver 2, PA2(TX) and PA3(RX) are routed to USART2, 115200 8N1.
    sdStart(&SD2, &my_serial_cfg);
    palSetPadMode(GPIOA, 2, PAL_MODE_STM32_ALTERNATE_PUSHPULL );
    palSetPadMode(GPIOA, 3, PAL_MODE_INPUT_PULLUP );

    //Activates the I2CD2 driver, PB10(SCL) and PB11(SDA) are routed to I2CD2
    i2cStart(&I2CD2, &i2cfg1);   
    palSetPadMode(GPIOB, 10,  PAL_MODE_STM32_ALTERNATE_OPENDRAIN );
    palSetPadMode(GPIOB, 11,  PAL_MODE_STM32_ALTERNATE_OPENDRAIN );
   
    chThdSleepMilliseconds(100);
       
    sprintf(ab,"Alive..!!\n\r");
    serialSendString(ab);
    chThdSleepMilliseconds(1000);
    mpu6050_get_address();
    chThdSleepMilliseconds(1000);
    chprintf((BaseSequentialStream*)&SD2, "B: %04x\n\r", i2cGetErrors(&I2CD2) );
    chThdSleepMilliseconds(1000);

    while (TRUE)
    {
   chThdSleepMilliseconds(1000);
   palTogglePad(GPIOC,GPIOC_LED);
        mpu6050_get_address();       
    }
}


I have used different i2c bus rates (100kHz and 400kHz), different i2c drivers (I2CD1 and I2CD2) and tried to read different registers. For instance, reg 0x6B (Power_management_1) has a default value of 0x40. In all these scenarios I failed to get any output at all. Most of the times, all the outputs are zero. The result from the above code is:

Code: Select all

Alive..!!
Timeout
Status: -1
B: 0000
Timeout
Status: -1
Timeout
Status: -1
Timeout
Status: -1
Timeout
Status: -1
Timeout
Status: -1
Timeout
Status: -1


MPU6050 sensor is working. I hooked it up with raspberry pi and it worked flawlessly with i2c-tools package.

STM32F103 board doesn't seem to be faulty. I tested an ultrasonic ranging module yesterday and it worked as expected. I am already using external pullup resistors on SDA and SCl (as suggested by Giovanni on i2c-troubleshooting).

I don't have an oscilloscope at home to view the wave forms, but I can test that SDA and SCL remain high before initialization, and voltages do vary during data transfer.

Another interesting finding for me. If I remove 3V3, SCL or SDA wires from the MPU6050 module during execution, the code jams. LED blinking stops too. (May be its standard procedure?)
User avatar
RoccoMarco
Posts: 655
Joined: Wed Apr 24, 2013 4:11 pm
Has thanked: 83 times
Been thanked: 67 times

Re: STM32F103 i2c won't work with MPU6050

Post by RoccoMarco »

Check if i2c pins are set as alternate open drain. Try to read known register and check if i2cMasterTransmit return msg_ok
Fulcrum Mike
Posts: 14
Joined: Fri Dec 23, 2016 3:33 am

Re: STM32F103 i2c won't work with MPU6050

Post by Fulcrum Mike »

Check if i2c pins are set as alternate open drain.


Code: Select all

    //Activates the I2CD2 driver, PB10(SCL) and PB11(SDA) are routed to I2CD2
    i2cStart(&I2CD2, &i2cfg1);   
    palSetPadMode(GPIOB, 10,  PAL_MODE_STM32_ALTERNATE_OPENDRAIN );
    palSetPadMode(GPIOB, 11,  PAL_MODE_STM32_ALTERNATE_OPENDRAIN );


Try to read known register

That's what I am trying to do:

Code: Select all

   tx_data[0] = 0x75;      //WHO_AM_I register
    //tx_data[0] = 0x6B;      //POWER_MNGMNT_1
    i2cAcquireBus(&I2CD2);
    status = i2cMasterTransmitTimeout(&I2CD2, MPU_addr,
                            tx_data, 1, address, 1, tmo);
    i2cReleaseBus(&I2CD2);


check if i2cMasterTransmit return msg_ok

This is the funny part. I am using two different chprintf commands to output the result of i2cMasterTransmitTimeout function:

Output 1:

Code: Select all

   if (status == MSG_TIMEOUT){
        chprintf((BaseSequentialStream*)&SD2, "Timeout\n\r");
    else if (status == MSG_RESET)
            chprintf((BaseSequentialStream*)&SD2, "Reset\n\r");
        else
            chprintf((BaseSequentialStream*)&SD2, "Done\n\r");

And, the result from the above code is:

Code: Select all

Timeout

Which infers that the returned value is MSG_TIMEOUT.

Output 2:
After printing the above value, I use this line to print the content of 'status' variable:

Code: Select all

    chprintf((BaseSequentialStream*)&SD2, "Status: %D\n\r", status);

Whose output is:

Code: Select all

Status: -1

According to this docs page, MSG_TIMEOUT's value is '-2' while I am getting '-1'.

So, the two outputs are reporting different results. So I don't know if the failure is due to MSG_TIMEOUT or MSG_RESET. Using i2cGetErrors returns 0.
User avatar
RoccoMarco
Posts: 655
Joined: Wed Apr 24, 2013 4:11 pm
Has thanked: 83 times
Been thanked: 67 times

Re: STM32F103 i2c won't work with MPU6050

Post by RoccoMarco »

The doc is releating to chibios_trunk. I suppose you are using 161.

An application note says to add 4.7k pull up resistor and 100R on each line.
Are you sure about the slave address. The function requires the slave address without the write/read bit.
Fulcrum Mike
Posts: 14
Joined: Fri Dec 23, 2016 3:33 am

Re: STM32F103 i2c won't work with MPU6050

Post by Fulcrum Mike »

Yes, I have already installed the required resistors.

I just skimmed through the source code of MPU6050-ChibiOS and STM32F4-ChibiOS/i2c github repositories. Both these codes use the same address for MPU6050 i.e, 0x68 (When pin AD0 is connected to GND, just like my setup).

I even created a new main.c file to try MPU6050-ChibiOS code. It produces the exact same problem. The relevant portion of the code, that is used to read address byte from MPU6050 is:

Code: Select all

int8_t I2CdevreadBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout) {
   //uint8_t mpu_txbuf[1], mpu_rxbuf[I2CDEV_BUFFER_LENGTH], i;
   msg_t rdymsg;
   if(length > I2CDEV_BUFFER_LENGTH) {
      chprintf((BaseChannel *)&SD2,"ERROR readBytes: length > I2CDEV BUFFERLENGTH\n");
      return FALSE;
   }
   i2cAcquireBus(&I2C_MPU);
   rdymsg = i2cMasterTransmitTimeout(&I2C_MPU, devAddr, &regAddr, 1, data, length, MS2ST(timeout));
   i2cReleaseBus(&I2C_MPU);
   if(rdymsg == MSG_TIMEOUT || rdymsg == MSG_RESET) {
      chprintf((BaseChannel *)&SD2,"I2C ERROR: %d\n", i2cGetErrors(&I2CD2));
      return FALSE;
   }
   return TRUE;
}

And after running this code, I get:

Code: Select all

I2C ERROR: 0


I had the same issue with my own code: No data transmission, i2cMasterTransmitTimeout doesn't return MSG_OK, yet i2cGetErrors returns 0.
User avatar
RoccoMarco
Posts: 655
Joined: Wed Apr 24, 2013 4:11 pm
Has thanked: 83 times
Been thanked: 67 times

Re: STM32F103 i2c won't work with MPU6050

Post by RoccoMarco »

The problem is not an error but a timeout. So error is 0. Please increase the timeout.
Fulcrum Mike
Posts: 14
Joined: Fri Dec 23, 2016 3:33 am

Re: STM32F103 i2c won't work with MPU6050

Post by Fulcrum Mike »

Earlier I tried to increase the default timeout from 4ms to 10ms. Didn't make a difference.

However, I am now able to communicate with the MPU6050 module. All I did was start the I2C driver after initializing SCL and SDA pins. Unfortunately, I am only able to make a single transaction (either read or write).

After the first transaction, I start getting 'I2C Error: 0' messages. Made various modifications, and tried to read/write different registers. But every time only a single transaction happens without getting error.

Can't remember the last time I was this frustrated :x
User avatar
RoccoMarco
Posts: 655
Joined: Wed Apr 24, 2013 4:11 pm
Has thanked: 83 times
Been thanked: 67 times

Re: STM32F103 i2c won't work with MPU6050

Post by RoccoMarco »

Error 0 means no error. Still pretty sure you are stopping the communication before it ends. Change timeout to TIME_INFINITE.

About i2cstart it could be since the early i2c cell from stm32 is buggy.
Fulcrum Mike
Posts: 14
Joined: Fri Dec 23, 2016 3:33 am

Re: STM32F103 i2c won't work with MPU6050

Post by Fulcrum Mike »

Error 0 means no error.

The i2c read function in MPU6050-ChibiOS is implemented so that a successful transaction doesn't produce any log. Error is shown only if i2cMasterTransmitTimeout return a value other than MSG_OK. Since you are saying that Error 0 means no error, I understand that the problem is with timeout.
Change timeout to TIME_INFINITE.

Changing timeout to TIME_INFINITE didn't change anything. Even after this change, only the first operation is successful. Afterwards, I start getting the same error. Here is the i2c read function provided by MPU6050-ChibiOS (with infinite timeout):

Code: Select all

   i2cAcquireBus(&I2C_MPU);
   rdymsg = i2cMasterTransmitTimeout(&I2C_MPU, devAddr, &regAddr, 1, data, length, TIME_INFINITE );
   i2cReleaseBus(&I2C_MPU);
   if(rdymsg == MSG_TIMEOUT || rdymsg == MSG_RESET) {
      chprintf((BaseChannel *)&SD2,"I2C STATUS: %d\n\r", rdymsg);
      chprintf((BaseChannel *)&SD2,"I2C ERROR: %d\n\r", i2cGetErrors(&I2CD2));
      return FALSE;
   }

Trying to read 2 different registers (WHO_AM_I and POWER_MNGMNT_1):

Code: Select all

    i2cStart(&I2CD2, &i2cfg1);   
    chprintf((BaseSequentialStream*)&SD2, "Init error: %d\n\r",    i2cGetErrors(&I2CD2));    //See if any problem in initialization
    chThdSleepMilliseconds(1000);
    MPU6050(MPU6050_ADDRESS_AD0_LOW);   //MPU6050 address is 0x68
    chThdSleepMilliseconds(2000);
    chprintf((BaseSequentialStream*)&SD2, "Add: %x\n\r", MPUgetDeviceID()); //Read WHO_AM_I byte
    chThdSleepMilliseconds(2000);
    chprintf((BaseSequentialStream*)&SD2, "Sleep: %x\n\r", MPUgetSleepEnabled()); // Read Sleep bit in POWER_MGMNT_1 register


And the corresponding output is:

Code: Select all

Init error: 0   //No problem in initialization
Add: 34      //1st read operation. Correct value. No error or timeout.
I2C STATUS: -1   //2nd read attempt. i2cMasterTransmitTimout != MSG_OK
I2C ERROR: 0   //2nd read attempt. i2cGetErrors returns 0
Sleep: 0      // Wrong value returned. It should be '1'. If I remove the 1st read operation, then this value is returned correctly.


Changing timeout to TIME_INFINITE didn't change anything. Even after this change, only the first operation is successful. Afterwards, I start getting the same error.
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32F103 i2c won't work with MPU6050

Post by Giovanni »

Hi,

Try increasing I2C IRQ priorities above the other sources, 5 for example, and see if it makes a difference.

Some other common issues are listed in this article: http://wiki.chibios.org/dokuwiki/doku.p ... e_shooting

Giovanni
Post Reply