/*
* 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;
}