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