Added module and tests for BMP180

master
Richard Meadows 2015-10-01 13:07:22 +01:00
rodzic f3ad018de1
commit 0e01b2a786
4 zmienionych plików z 420 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,42 @@
/*
* BMP180 (also BMP085)
* Copyright (C) 2014 Richard Meadows <richardeoin>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef BMP180_H
#define BMP180_H
#include "samd20.h"
/**
* Barometer data structure
*/
struct barometer {
double temperature;
int32_t pressure;
int valid; // 1 = valid, 0 = invalid
};
struct barometer* get_barometer(void);
void bmp180_init(void);
#endif /* BMP180_H */

Wyświetl plik

@ -0,0 +1,303 @@
/*
* BMP180 (also BMP085)
* Copyright (C) 2014 Richard Meadows <richardeoin>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdbool.h>
#include <stdint.h>
#include "samd20.h"
#include "bmp180.h"
#include "sercom/i2c_master.h"
#define BMP180_ADDRESS 0xEE
#define BMP180_REG_ID 0xD0
#define BMP180_REG_SOFTRESET 0xE0
#define BMP180_REG_CTRLMEAS 0xF4
#define BMP180_REG_DATA 0xF6
/**
* Control Register Values
*/
typedef enum {
TEMPERATURE = 0x2E,
PRESSURE_ULTRALOW = 0x34, // 4500µS Delay
PRESSURE_STANDARD = 0x74, // 7500µS Delay
PRESSURE_HIGHRES = 0xB4, // 13500µS Delay
PRESSURE_ULTRAHIGHRES = 0xF4 // 22500µS Delay
} bmp085_command;
/**
* The mode of pressure measurement
*/
#define PRESSURE_MODE PRESSURE_HIGHRES// PRESSURE_STANDARD
#define PRESSURE_DELAY 13500//7500
#define TEMPERATURE_DELAY 4500
/**
* Barometer data structure
*/
struct barometer barometer;
/**
* Calibration Values
*/
struct calibration {
int16_t AC1, AC2, AC3, B1, B2, MB, MC, MD;
uint16_t AC4, AC5, AC6;
} calibration;
/**
* Lookup table for oversampling values.
*/
uint8_t oversampling(void) {
switch(PRESSURE_MODE) {
case PRESSURE_ULTRALOW:
return 0;
case PRESSURE_HIGHRES:
return 2;
case PRESSURE_ULTRAHIGHRES:
return 3;
default: // PRESSURE_STANDARD
return 1;
}
}
/**
* Implements a microsecond delay
*/
void delay_us(uint16_t microseconds) {
int32_t i = microseconds * 16;
while(i--);
}
void master_transfer(uint16_t address, uint8_t* data, uint16_t data_length,
uint8_t read_not_write)
{
uint32_t timeout = 0;
struct i2c_master_packet packet = {
.address = address,
.data_length = data_length,
.data = data,
.ten_bit_address = false,
.high_speed = false,
.hs_master_code = 0x0,
};
if (read_not_write) {
while (i2c_master_read_packet_wait(&packet) !=
I2C_STATUS_OK) {
/* Increment timeout counter and check if timed out. */
if (timeout++ > 1000) {
break;
}
}
} else {
while (i2c_master_write_packet_wait(&packet) !=
I2C_STATUS_OK) {
/* Increment timeout counter and check if timed out. */
if (timeout++ > 1000) {
break;
}
}
}
}
/**
* Utility function to read from a 8-bit register
*/
uint8_t read_8(char address) {
uint8_t buffer[3];
buffer[0] = address;
/* Set regsiter to read */
master_transfer(BMP180_ADDRESS >> 1, buffer, 1, false);
/* Read it */
master_transfer(BMP180_ADDRESS >> 1, buffer, 1, true);
return buffer[0];
}
/**
* Utility function to read a 16-bit register.
*/
uint16_t read_16(char address) {
uint8_t buffer[3];
buffer[0] = address;
/* Set regsiter to read */
master_transfer(BMP180_ADDRESS, buffer, 1, false);
/* Read it */
master_transfer(BMP180_ADDRESS | 1, buffer, 2, true);
return (buffer[0] << 8) | buffer[1];
}
/**
* Reads off the BMP180's calibration values.
*/
void get_cal_param(struct calibration *c) {
c->AC1 = read_16(0xAA);
c->AC2 = read_16(0xAC);
c->AC3 = read_16(0xAE);
c->AC4 = read_16(0xB0);
c->AC5 = read_16(0xB2);
c->AC6 = read_16(0xB4);
c->B1 = read_16(0xB6);
c->B2 = read_16(0xB8);
c->MB = read_16(0xBA);
c->MC = read_16(0xBC);
c->MD = read_16(0xBE);
}
/**
* Writes a command to the BMP085's control register.
*/
void write_command(bmp085_command command) {
uint8_t buffer[3];
buffer[0] = BMP180_REG_CTRLMEAS;
buffer[1] = command;
/* Write to command register */
master_transfer(BMP180_ADDRESS, buffer, 2, true);
}
/**
* Takes a temperature measurement and returns the uncompensated value.
*/
int32_t get_ut(void) {
write_command(TEMPERATURE);
delay_us(TEMPERATURE_DELAY);
return read_16(BMP180_REG_DATA);
}
/**
* Takes a pressure measurement and returns the uncompenstated value.
*/
int32_t get_up(void) {
uint8_t buffer[3];
write_command(PRESSURE_MODE);
delay_us(PRESSURE_DELAY);
buffer[0] = BMP180_REG_DATA;
/* Set regsiter to read */
master_transfer(BMP180_ADDRESS, buffer, 1, false);
/* Read it */
master_transfer(BMP180_ADDRESS | 1, buffer, 3, true);
return ((buffer[0] << 16) | (buffer[1] << 8) |
buffer[2]) >> (8 - oversampling());
}
/* -----------------------------------------------------------------------------
* Calculations
*/
/**
* Returns the variable B5, which is used for both temperature and
* pressure calculations.
*/
int32_t get_b5(struct calibration *c, int32_t ut) {
int32_t x1, x2;
x1 = ((ut - c->AC6) * c->AC5) >> 15;
x2 = (double)(c->MC << 11) / (x1 + c->MD);
return x1 + x2; // B5
}
/**
* Returns the temperature in °C using variable B5
*/
double get_temperature(int32_t B5) {
return (double)((B5 + 8) >> 4) / 10;
}
/**
* Returns the pressure in pascals using the calibration and variable
* B5.
*/
int32_t get_pressure(struct calibration *c, int32_t B5, int32_t up) {
int64_t B6, X1, X2, X3, B3, pressure;
uint64_t B4, B7;
B6 = B5 - 4000;
X1 = (c->B2 * ((B6 * B6) >> 12)) >> 11;
X2 = (c->AC2 * B6) >> 11;
X3 = X1 + X2;
B3 = ((((((int64_t)(c->AC1) * 4) + X3) << oversampling()) + 2) >> 2);
X1 = (c->AC3 * B6) >> 13;
X2 = (c->B1 * ((B6 * B6) >> 12)) >> 16;
X3 = ((X1 + X2) + 2) >> 2;
B4 = (c->AC4 * (uint64_t)(X3 + 32768)) >> 15;
B7 = ((uint64_t)(up - B3) * (50000 >> oversampling()));
if (B7 < 0x80000000) {
pressure = (B7 << 1) / B4;
} else {
pressure = (B7 / B4) << 1;
}
X1 = (pressure >> 8);
X1 *= X1;
X1 = (X1 * 3038) >> 16;
X2 = (-7357 * pressure) >> 16;
pressure += (X1 + X2 + 3791) >> 4;
return pressure;
}
struct barometer* get_barometer(void)
{
int32_t ut = get_ut();
int32_t up = get_up();
int32_t b5 = get_b5(&calibration, ut);
barometer.temperature = get_temperature(b5);
barometer.pressure = get_pressure(&calibration, b5, up);
return &barometer;
}
/**
* Assume twi_master_init has already been called
*/
void bmp180_init(void)
{
/* Read and check id */
uint8_t id = read_8(BMP180_REG_ID);
if (id != 0x55) while (1);
/* Get the calibration parameters */
//get_cal_param(&calibration);
}

Wyświetl plik

@ -0,0 +1,34 @@
#ifndef __verification__
#define __verification__
#endif
/****************************//* pressure_temperature_tc *//****************************/
/**
* Write a description of your test case here
*/
/* Parameters in */
struct pressure_temperature_tc_params {
/* Input paramters to your test case go here */
uint32_t dummy;
} pressure_temperature_tc_params;
/* Results out */
struct pressure_temperature_tc_results {
/* Result values should be populated here */
float pressure, temperature;
} pressure_temperature_tc_results;
/* Function */
__verification__ void pressure_temperature_tc(void) {
/**
* The main body of the test case goes here.
*
* Use the input parameters to run the test case. Populate the
* results structure at the end
*/
}

Wyświetl plik

@ -0,0 +1,41 @@
#!/usr/bin/env python
# ------------------------------------------------------------------------------
# Imports
# ------------------------------------------------------------------------------
import sys
sys.path.append("./test")
import main
from random import randint
# ------------------------------------------------------------------------------
# Test Script
# ------------------------------------------------------------------------------
class pressure_temperature_tc:
def __init__(self):
self.name = self.__class__.__name__
self.iterations = 20
def get_test(self):
"""Returns some suitable test parameters"""
params = main.struct_pressure_temperature_tc_params()
"""
Assign input parameters here
"""
return params
def is_correct(self, params, result, print_info):
"""Returns if a result is correct for the given parameters"""
"""
Compare result and params here, decide sth.
Can use print_info
"""
return True