Alright! I figured out my own question :)
1) I was indeed going about the process the wrong way. There is a much easier way to do that and I will show how in detail.
2) I was not reading from the correct registers. I'll show what to do below.
So, connecting to the Magnetometer is super easy, but not intuitive at all. It does act like its own slave with its own slave address, but that address is inaccessible initially.
Since I'm cross compiling with uClinux, I can use the bash command i2cdetect 0
(when screening into my SmartFusion2) to check all the slaves on my i2C 0 bus. When I execute this command after resetting my board, I get the following address map printed out:
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
So you can see that only the address for the IMU(0x68) is showing. To get the magnetometer showing up properly, you have to enable a bypass bit on INT_PIN_CFG(0x37). I've attached my code below in case anyone needs to replicate this.
#include <stdio.h>
//#include <linux/i2c-dev.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define IMU_ADDR 0x68
#define IMU_WHO_AM_I 0x75
int file;
void i2c_init();
void write_register(uint8_t register_address, uint8_t value);
uint8_t read_register(uint8_t register_address);
void i2c_init(address){
int adapter_nr = 0;
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
file = open(filename, O_RDWR);
if(file < 0)
printf("Error: Failed to open file %s\n", filename);
int success= (ioctl(file, I2C_SLAVE, address));
if(file < 0) {
printf("Error: IMU I2C Failed to Open\n");
//return -1;
}
}
void write_register(uint8_t register_address, uint8_t value){
uint8_t data[]={register_address,value};
write(file, data,ARRAY_SIZE(data));
}
uint8_t read_register(uint8_t register_address){
uint8_t value;
if(write(file, ®ister_address, sizeof(register_address)) !=1)
{
printf("%d\n",write(file, ®ister_address, sizeof(register_address)));
printf("Failed to send data\n");
}
read(file, &value, sizeof(value));
return value;
}
int main(){
i2c_init(IMU_ADDR);
printf("\nNow testing the 'Who am I?' IMU register. Output should be 0x71\n");
printf("Register 0x75: 0x%02X \n", read_register(IMU_WHO_AM_I));
write_register(0x37, 0x22);
i2c_init(0x0C);
printf("\nNow testing the 'Who am I?' Magnetometer register. Output should be 0x48\n");
printf("Register 0x00: 0x%02x\n", read_register(0x00));
return 0;
}
Once the code is compiled and run, the command i2cdetect 0
returns the following datamap.
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- 0c -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
The program also returns 0x48, the correct value when reading from the magnetometer's 'who am I?' register. The magnetometer can now be read just like any other register. Hope this helps!!