/* * pcf8563_i2c_rtc.c - example of accessing a PCF8563 via the BSC0 (I2C) peripheral on a BCM2835 (Raspberry Pi) * * Copyright 2012 Kevin Sangeelee. * Released as GPLv2, see <http://www.gnu.org/licenses/> * * This is intended as an example of using Raspberry Pi hardware registers to drive an RTC chip. Use at your own risk or * not at all. As far as possible, I've omitted anything that doesn't relate to the RTC or the Raspi registers. There are more * conventional ways of doing this using kernel drivers, though these are harder to follow. */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <stdint.h> #include <time.h> #include <math.h> #include <fcntl.h> #include <sys/mman.h> #include "bcm2835.h" //////////////// // main() //////////////// char eeprom[22] = { 0, 0, }; short ac1, ac2, ac3, b1, b2, mb, mc, md; unsigned short ac4, ac5, ac6; float temperature_deg_c; float pressure_hpa; int read_bmp085(float altitude) { if(map_peripheral(&gpio) == -1) { printf("Failed to map the physical GPIO registers into the virtual memory space.\n"); return -1; } if(map_peripheral(&bsc0) == -1) { printf("Failed to map the physical BSC0 (I2C) registers into the virtual memory space.\n"); return -1; } /* BSC0 is on GPIO 0 & 1 */ *gpio.addr &= ~0x3f; // Mask out bits 0-5 of FSEL0 (i.e. force to zero) *gpio.addr |= 0x24; // Set bits 0-5 of FSEL0 to binary '100100' // Read eeprom data if the array is empty // I2C Device Address 0x77 (hardwired into the chip, 0xEE & 0xEF) if((unsigned short)*eeprom == 0) { // Device 0x77, register 0xaa, read into buf, 22 bytes i2c_read(0x77, 0xaa, eeprom, 22); ac1 = (short)eeprom[0] << 8 | eeprom[1]; ac2 = (short)eeprom[2] << 8 | eeprom[3]; ac3 = (short)eeprom[4] << 8 | eeprom[5]; ac4 = (unsigned short)eeprom[6] << 8 | eeprom[7]; ac5 = (unsigned short)eeprom[8] << 8 | eeprom[9]; ac6 = (unsigned short)eeprom[10] << 8 | eeprom[11]; b1 = (short)eeprom[12] << 8 | eeprom[13]; b2 = (short)eeprom[14] << 8 | eeprom[15]; mb = (short)eeprom[16] << 8 | eeprom[17]; mc = (short)eeprom[18] << 8 | eeprom[19]; md = (short)eeprom[20] << 8 | eeprom[21]; // Test values //ac1 = 408, ac2 = -72, ac3 = -14383, ac4 = 32741, ac5 = 32757, ac6 = 23153; //b1 = 6190, b2 = 4, mb = -32768, mc = -8711, md = 2868; // Also include 'ut = 27898' , 'up = 23843', and 'oss = 0' //printf("%d %d %d %d %d %d\n", ac1, ac2, ac3, ac4, ac5, ac6); //printf("%d %d %d %d %d\n", b1, b2, mb, mc, md); } char ut_buf[2]; char up_buf[2]; char cmd_ut = 0x2e; char cmd_up[] = {0x34, 0x74, 0xb4, 0xf4}; int oss_delay[] = {4500, 7500, 13500, 25500}; int oss = 1; // This is an index into the above array /* * Get Uncompensated Temperature from BMP085 */ i2c_write(0x77, 0xf4, &cmd_ut, 1); usleep(4500); // just wait the maximum possible time for conversion i2c_read(0x77, 0xf6, ut_buf, 2); long ut = (long)ut_buf[0] << 8 | ut_buf[1]; // Temperature compensation algorithm (derived from datasheet) long x1 = ((ut - ac6) * ac5) >> 15; long x2 = (mc * (1 << 11)) / (x1 + md); long b5 = x1 + x2; long t = (b5 + 8) >> 4; temperature_deg_c = (float)t / 10; printf("Temperature: %0.1fC\n", temperature_deg_c); int idx; float p0 = 0; for(idx=0; idx < 2; idx++) { /* * Get Uncompensated Pressure from BMP085, based on the OverSampling Setting * of (0, 1, 2, or 3). This determines accuracy, conversion delay, and power consumption. */ i2c_write(0x77, 0xf4, &cmd_up[oss], 1); usleep(oss_delay[oss]); // wait according to the chosen oss mode i2c_read(0x77, 0xf6, up_buf, 3); long up = (((long)up_buf[0] << 16) | ((long)up_buf[1] << 8) | up_buf[2]) >> (8 - oss); // Pressure compensation algorithm (derived from datasheet) long b6 = b5 - 4000; x1 = (b2 * (b6 * b6 >> 12)) >> 11; x2 = ac2 * b6 >> 11; long x3 = x1 + x2; long b3 = (((ac1 * 4 + x3) << oss) + 2) >> 2; x1 = ac3 * b6 >> 13; x2 = (b1 * (b6 * b6 >> 12)) >> 16; x3 = ((x1 + x2) + 2) >> 2; unsigned long b4 = ac4 * (unsigned long)(x3 + 32768) >>15; unsigned long b7 = ((unsigned long)up - b3) * (50000 >> oss); long p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2; x1 = (p >> 8) * (p >> 8); x1 = (x1 * 3038) >> 16; x2 = (-7357 * p) >> 16; p = p + (x1 + x2 + 3791) / 16; p0 += (float)p / powf(1.0f - (altitude / 44330), 5.255f); usleep(100000); } p0 /= 2; pressure_hpa = p0 / 100; printf("Pressure p0 (sea level): %0.1f hPa\n", pressure_hpa); unmap_peripheral(&gpio); unmap_peripheral(&bsc0); return 0; }