I want to create a small library for communication with I²C devices, especially the MPU6050 accelerometer / gyroscope module from scratch in C. Technically, I could use a library like wiringPi, but.. where is the fun with that. Right now I'm trying to write a function which scans all possible 7 bit addresses (0 - 127) and reads the acknowledge bit to find all 'active' addresses of connected I²C devices. To do that, I wrote a small library which can control the GPIO pins by writing to the coresponding GPIO files in /sys/class/gpio. It can for example setup a pin, set its direction (input or output), set its digital output and read a digital input from a pin. I tested all of these functions and they work great and fast.
For communication with the MPU6050 I²C slave I connected the power and ground pins of the MPU board to the Raspberry's GPIO power and ground pins and the SDA and SCL lines to GPIO pins 14 and 15. I read a lot about I²C recently and I do understand how it works. The problem is, that my code to scan through all addresses does not work. Here's my code:
#include <stdio.h>
#include <unistd.h>
#include "string.h"
#include "gpio.h"
#define SCL 14
#define SDA 15
#define FREQ 100000
#define high 1
#define low 0
char binret[8];
void scanI2C();
void charToBin(unsigned char);
void delay();
int main () {
setupPin(SCL, OUTPUT);
setupPin(SDA, OUTPUT);
scanI2C();
}
void scanI2C() {
int addr = 0;
for (int i = 90; i < 128; i++) {
charToBin(i);
// Start Condition
setPin(SDA, high);
setPin(SCL, high);
delay();
setPin(SDA, low);
for (int j = 0; j < 9; j++) {
delay();
setPin(SCL, low);
delay();
setPin(SCL, high);
if (j < 7) {
setPin(SDA, binret[j+1]);
}
// WRITE Bit
if (j == 7) {
setPin(SDA, high);
}
// Listen for ACK bit
if (j == 8) {
setPinDirection(SDA, INPUT);
printf("Checking Address %d (%d%d%d%d%d%d%d%d)", i, binret[0], binret[1], binret[2], binret[3], binret[4], binret[5], binret[6], binret[7]);
if (readPin(SDA) <= 0.5) {
printf(" Bingo!");
}
setPinDirection(SDA, OUTPUT);
printf("\n");
}
}
// Stop Condition
setPin(SCL, low);
delay();
setPin(SDA, high);
delay();
setPin(SCL, high);
delay();
delay();
delay();
delay();
delay();
}
}
void charToBin(unsigned char a) {
memset(binret, 0, sizeof(binret));
int val = 128;
for (int i = 0; i < 8; i++) {
int bit = a & val;
if (bit != 0) {
binret[i] = 1;
}
val /= 2;
}
}
void delay() {
usleep(1000000.0/FREQ);
}
Since I do actually know the address of the MPU6050 I²C slave to be 0x69 or 105 in decimal, I would expect the output to be something like this:
...
Checking Address 103 (01100111)
Checking Address 104 (01101000)
Checking Address 105 (01101001) Bingo!
Checking Address 106 (01101010)
Checking Address 107 (01101011)
Checking Address 108 (01101100)
Checking Address 109 (01101101)
Checking Address 110 (01101110)
...
But no, I don't get a Bingo!
at address 105, which means that my I²C communication is definitely not working. Advice on how to address this issue is very much appreciated! Thank you and have a nice day :)