V0.3 by Kevin Sangeelee with changes for V2 of RPi board
1 parent 8f4b7a4 commit 60cd43cce319b4677d352bb334056be4d5c698d7
@Andy Andy authored on 4 Jun 2014
Showing 7 changed files
View
19
Makefile 0 → 100755
CC=gcc
CFLAGS=-c -Wall
 
all: wh1080_rf
 
wh1080_rf: wh1080_rf.o bcm2835.o bmp085.o
$(CC) -lm wh1080_rf.o bcm2835.o bmp085.o -o wh1080_rf
 
wh1080_rf.o: wh1080_rf.c
$(CC) $(CFLAGS) wh1080_rf.c
 
bcm2835.o: bcm2835.c
$(CC) $(CFLAGS) bcm2835.c
 
bmp085.o: bmp085.c
$(CC) $(CFLAGS) bmp085.c
 
clean:
rm -f wh1080_rf.o bcm2835.o bmp085.o wh1080_rf
View
124
bcm2835.c 0 → 100755
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
 
#include "bcm2835.h"
 
struct bcm2835_peripheral gpio = {GPIO_BASE, 0};
struct bcm2835_peripheral bsc0 = {BSC0_BASE, 0};
struct bcm2835_peripheral timer_arm = {TIMER_ARM_BASE, 0};
 
// Exposes the physical address defined in the passed structure using mmap on /dev/mem
int map_peripheral(struct bcm2835_peripheral *p)
{
if(p->init_count > 0) {
p->init_count++;
return 0;
}
 
// Open /dev/mem
if ((p->mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("Failed to open /dev/mem, try checking permissions.\n");
return -1;
}
 
p->map = mmap(
NULL,
BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED,
p->mem_fd, // File descriptor to physical memory virtual file '/dev/mem'
p->addr_p // Address in physical map that we want this memory block to expose
);
 
if (p->map == MAP_FAILED) {
perror("mmap");
return -1;
}
 
p->addr = (volatile unsigned int *)p->map;
p->init_count++;
 
return 0;
}
 
 
void unmap_peripheral(struct bcm2835_peripheral *p) {
 
p->init_count--;
if(p->init_count == 0) {
munmap(p->map, BLOCK_SIZE);
close(p->mem_fd);
}
}
 
// Function to wait for the I2C transaction to complete
void wait_i2c_done() {
 
while((!((BSC0_S) & BSC_S_DONE))) {
usleep(100);
}
}
 
// Function to write data to an I2C device via the FIFO. This doesn't refill the FIFO, so writes are limited to 16 bytes
// including the register address. len specifies the number of bytes in the buffer.
void i2c_write(char dev_addr, char reg_addr, char *buf, unsigned short len) {
 
int idx;
BSC0_A = dev_addr;
BSC0_DLEN = len + 1; // one byte for the register address, plus the buffer length
BSC0_FIFO = reg_addr; // start register address
for(idx=0; idx < len; idx++)
BSC0_FIFO = buf[idx];
BSC0_S = CLEAR_STATUS; // Reset status bits (see #define)
BSC0_C = START_WRITE; // Start Write (see #define)
 
wait_i2c_done();
}
 
// Function to read a number of bytes into a buffer from the FIFO of the I2C controller
void i2c_read(char dev_addr, char reg_addr, char *buf, unsigned short len) {
 
i2c_write(dev_addr, reg_addr, NULL, 0);
unsigned short bufidx = 0;
 
memset(buf, 0, len); // clear the buffer
 
BSC0_DLEN = len;
BSC0_S = CLEAR_STATUS; // Reset status bits (see #define)
BSC0_C = START_READ; // Start Read after clearing FIFO (see #define)
 
do {
// Wait for some data to appear in the FIFO
while((BSC0_S & BSC_S_TA) && !(BSC0_S & BSC_S_RXD));
 
// Consume the FIFO
while((BSC0_S & BSC_S_RXD) && (bufidx < len)) {
buf[bufidx++] = BSC0_FIFO;
}
} while((!(BSC0_S & BSC_S_DONE)));
}
 
void dump_bsc_status() {
unsigned int s = BSC0_S;
printf("BSC0_S: ERR=%d RXF=%d TXE=%d RXD=%d TXD=%d RXR=%d TXW=%d DONE=%d TA=%d\n",
(s & BSC_S_ERR) != 0,
(s & BSC_S_RXF) != 0,
(s & BSC_S_TXE) != 0,
(s & BSC_S_RXD) != 0,
(s & BSC_S_TXD) != 0,
(s & BSC_S_RXR) != 0,
(s & BSC_S_TXW) != 0,
(s & BSC_S_DONE) != 0,
(s & BSC_S_TA) != 0 );
}
View
97
bcm2835.h 0 → 100755
#define PAGESIZE 4096
#define BLOCK_SIZE 4096
 
#define IOBASE 0x20000000
 
#define GPIO_BASE (IOBASE + 0x200000)
#define BSC0_BASE (IOBASE + 0x205000)
#define TIMER_ARM_BASE (IOBASE + 0x00B000)
 
 
/*
* Defines for ARM Timer peripheral
*/
#define TIMER_ARM_LOAD *(timer_arm.addr + 0x100)
#define TIMER_ARM_VALUE *(timer_arm.addr + 0x101)
#define TIMER_ARM_CONTROL *(timer_arm.addr + 0x102)
#define TIMER_ARM_IRQ_CLEAR *(timer_arm.addr + 0x103)
#define TIMER_ARM_IRQ_RAW *(timer_arm.addr + 0x104)
#define TIMER_ARM_IRQ_MASK *(timer_arm.addr + 0x105)
#define TIMER_ARM_RELOAD *(timer_arm.addr + 0x106)
#define TIMER_ARM_PREDIVIDE *(timer_arm.addr + 0x107)
#define TIMER_ARM_COUNT *(timer_arm.addr + 0x108)
 
// Zero-shifts are here for code readability, where a zero-bit holds significant
// meaning other than just a negated state, or where the negated state is notable.
 
#define TIMER_ARM_C_16BIT (0 << 1)
#define TIMER_ARM_C_23BIT (1 << 1)
#define TIMER_ARM_C_PS1 (0 << 2)
#define TIMER_ARM_C_PS16 (1 << 2)
#define TIMER_ARM_C_PS256 (2 << 2)
#define TIMER_ARM_C_PS1_1 (3 << 2)
#define TIMER_ARM_C_INTEN (1 << 5)
#define TIMER_ARM_C_DISABLE (0 << 7)
#define TIMER_ARM_C_ENABLE (1 << 7)
#define TIMER_ARM_C_DBGHALT (1 << 8)
#define TIMER_ARM_C_FREE_EN (1 << 9)
#define TIMER_ARM_C_FPS(n) ((n & 0xff) << 16)
#define TIMER_ARM_C_FPS_MASK (0xff << 16)
 
 
/*
* Defines for I2C peripheral (aka BSC, or Broadcom Serial Controller)
*/
#define BSC0_C *(bsc0.addr + 0x00)
#define BSC0_S *(bsc0.addr + 0x01)
#define BSC0_DLEN *(bsc0.addr + 0x02)
#define BSC0_A *(bsc0.addr + 0x03)
#define BSC0_FIFO *(bsc0.addr + 0x04)
 
#define BSC_C_I2CEN (1 << 15)
#define BSC_C_INTR (1 << 10)
#define BSC_C_INTT (1 << 9)
#define BSC_C_INTD (1 << 8)
#define BSC_C_ST (1 << 7)
#define BSC_C_CLEAR (1 << 4)
#define BSC_C_READ 1
 
#define START_READ BSC_C_I2CEN|BSC_C_ST|BSC_C_CLEAR|BSC_C_READ
#define START_WRITE BSC_C_I2CEN|BSC_C_ST
 
#define BSC_S_CLKT (1 << 9)
#define BSC_S_ERR (1 << 8)
#define BSC_S_RXF (1 << 7)
#define BSC_S_TXE (1 << 6)
#define BSC_S_RXD (1 << 5)
#define BSC_S_TXD (1 << 4)
#define BSC_S_RXR (1 << 3)
#define BSC_S_TXW (1 << 2)
#define BSC_S_DONE (1 << 1)
#define BSC_S_TA 1
 
#define CLEAR_STATUS BSC_S_CLKT|BSC_S_ERR|BSC_S_DONE
 
 
 
struct bcm2835_peripheral {
unsigned long addr_p; // Physical address
unsigned long init_count;
int mem_fd; // File Descriptor for /dev/mem
void *map; // The mmap()
volatile unsigned int *addr;
};
 
extern struct bcm2835_peripheral gpio;
extern struct bcm2835_peripheral bsc0;
extern struct bcm2835_peripheral timer_arm;
 
extern void wait_i2c_done();
extern void i2c_read(char dev_addr, char reg_addr, char *buf, unsigned short len);
extern void i2c_write(char dev_addr, char reg_addr, char *buf, unsigned short len);
extern void dump_bsc_status();
 
extern int map_peripheral(struct bcm2835_peripheral *p);
extern void unmap_peripheral(struct bcm2835_peripheral *p);
 
View
146
bmp085.c 0 → 100755
/*
* 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;
}
View
rfm01.h 0 → 100755
View
wh1080_rf.c 0 → 100755
View
wh1080_rf.h 0 → 100755