10DOF e U-blox NEO-6M GPS modules
Dopo circa 30 giorni ho finalmente ricevuto il pacco dalla Cina, acquisto di pochi dollari su eBay, con i due moduli ordinati:
- 10DOF Module 9-axis Attitude Indicator L3G4200D ADXL345 HMC5883L BMP085 Module
- GPS U-blox NEO-6M Module
Questa sera ho deciso di giocare un po’ con il 10DOF, un piccolo moduletto molto compatto con a bordo:
- L3G4200D - Giroscopio 3 assi (L3G4200D Datasheet)
- ADXL345 - Accelerometro tre assi (ADXL345 Datasheet)
- HMC5883L – Compasso digitale 3 assi (HMC5883L Datasheet)
- BMP085 – Sensore barometrico e termometro (BMP085 Datasheet)
10DOF I2C pinouts
Il tutto accessibile mediante il medesimo bus I2C, ai seguenti indirizzi:
I2C Address 0x1E è il HMC5883L
I2C Address 0×53 è il ADXL345
I2C Address 0×69 è il L3G4200D
I2C Address 0×77 è il BMP085
BMP085
Per iniziare ho deciso di provare a collegare il modulo al mio BeagleBone Black, via bus I2C, e provare ad interrogare il sensore barometrico/termometro BMP085.
Connessioni
Per prima cosa, i cablaggi. Cercando lo schema “pinouts” della BeagleBoard Black, scopro che ci sono ben due bus I2C disponibili, sul bus P9 (posto a sinistra, con il connettore RJ45 in alto):
- I2C BUS 1 ai pin 17 (SCL) e 18 (SDA)
- I2C BUS 2 ai pin 19 (SCL) e 20 (SDA)
Considerando che il modulo può essere alimentato direttamente dai 3.3V forniti dalla BeagleBoard, ho preso la mia bella breadboard ed ho collegato i 4 fili richiesti per iniziare a giocare:
- PIN 2 = GND
- PIN 4 = Vcc 3V
- PIN 17 = SCL
- PIN 18 = SDA
Gli altri piedini del 10 DOF non sono utilizzati. Accendiamo ovviamente la BBB e, da root, abilitiamo il bus I2C con il seguente comando:
echo BB-I2C1 > /sys/devices/bone_capemgr.9/slots
A questo punto possiamo iniziare ad esplorare il fantastico bus i2c con il comando ‘i2cdetect‘:
root@arm:~/C# i2cdetect -l i2c-0 i2c OMAP I2C adapter I2C adapter i2c-1 i2c OMAP I2C adapter I2C adapter i2c-2 i2c OMAP I2C adapter I2C adapter root@arm:~/C#
In questo caso ci interessa il bus 2 (i2c-2):
root@arm:~/C# i2cdetect -r 2 WARNING! This program can confuse your I2C bus, cause data loss and worse! I will probe file /dev/i2c-2 using read byte commands. I will probe address range 0x03-0x77. Continue? [Y/n] 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- 1e -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- 53 -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- 69 -- -- -- -- -- -- 70: -- -- -- -- -- -- -- 77 root@arm:~/C#
Come vedete, il sistema identifica con successo i dispotivi agli indirizzi 0x1e, 0×53,0×69 e 0×77 (descritti prima, all’inizio dell’articolo).
A questa pagina trovate molta documentazione in merito alle implementazioni su Linux delll’interfaccia I2C: https://www.kernel.org/doc/Documentation/i2c/dev-interfaceA questo punto si tratta di scrivere qualche riga di codice per vedere se il tutto funziona. Cercando in rete, ho trovato qualche pagina con gli algoritmi per interrogare il BMP085 in uno pseudo-C per Arduino, dai quali ho preso spunto per scrivere questo veloce programmino compilato direttamente sulla BBB, che potete usare come base per i vostri esperimenti:
/* I2C test */ #include #include #include #include #define DEBUG // Calibration values int ac1; int ac2; int ac3; unsigned int ac4; unsigned int ac5; unsigned int ac6; int b1; int b2; int mb; int mc; int md; unsigned char I2C_readByte(int file, __u8 regs) { unsigned char res; usleep(5000); // Wait some time... res = i2c_smbus_read_byte_data(file, regs); if (res < 0) { printf("Error reading data from 0x%x register on i2c bus\n", regs); return -1; } #ifdef DEBUG printf("[DEBUG] 0x%x => 0x%x\n",regs,res); #endif return res; } int I2C_readWord(int file, __u8 regs) { unsigned char msb,lsb; int res; msb = I2C_readByte(file,regs); lsb = I2C_readByte(file,regs+1); res = (int)msb << 8 | lsb; #ifdef DEBUG printf("[DEBUG] %d\n",res); #endif return res; } int I2C_writeWord(int file, __u8 regs, __u16 value) { int res; res = i2c_smbus_write_word_data(file, regs, value); if(res < 0) { printf("Error writing 0x%x to 0x%x register on i2c bus\n",value, regs); return -1; } return 1; } float BMP085_readTemp(file) { long x1, x2, b5; int res; float temp; I2C_writeWord(file,0xF4,0x2E); usleep(45000); // Wait at least 4,5 ms res = I2C_readWord(file,0xF6); x1 = ((long)res - (long)ac6)*(long)ac5 >> 15; x2 = ((long)mc << 11)/(x1 + md); b5 = x1 + x2; temp = ((b5 + 8) >> 4); // Temp in 0.1°C // temp = temp / 10; return temp; } void BMP085_getCalibration(file) { /* ac1 = 408; ac2 = -72; ac3 = -14383; ac4 = 32741; ac5 = 32757; ac6 = 23153; b1 = 6190; b2 = 4; mb = -32767; mc = -8711; md = 2868; */ ac1 = I2C_readWord(file,0xAA); ac2 = I2C_readWord(file,0xAC); ac3 = I2C_readWord(file,0xAE); ac4 = I2C_readWord(file,0xB0); ac5 = I2C_readWord(file,0xB2); ac6 = I2C_readWord(file,0xB4); b1 = I2C_readWord(file,0xB6); b2 = I2C_readWord(file,0xB8); mb = I2C_readWord(file,0xBA); mc = I2C_readWord(file,0xBC); md = I2C_readWord(file,0xBE); } void main() { int file; int adapter_nr = 2; int addr = 0x77; char filename[20]; float temp; printf("Open BMP085 I2C device @ 0x77..."); snprintf(filename, 19, "/dev/i2c-%d", adapter_nr); file = open(filename, O_RDWR); if (file < 0) { printf("Error while opening device %s: %d error\n",filename,errno); exit(1); } if (ioctl(file, I2C_SLAVE, addr) < 0) { printf("Error while set I2C address: %d error\n",errno); exit(1); } printf("OK !\nGet calibration data..."); BMP085_getCalibration(file); printf("OK !\n"); while(1) { temp = BMP085_readTemp(file); printf("Temperature: %4.2f °C\n",temp); sleep(1); } }
compilatelo con un semplice “gcc i2c.c -o i2c”.
Prima di poter compilare il programma dovete installare sulla BBB le build-essential e la libreria di sviluppo libi2c-devVai, le sperimentazioni sono iniziate: buon divertimento !