cceb9de300
Closes #47
351 lines
9 KiB
C
351 lines
9 KiB
C
#include "bmp180.h"
|
|
|
|
#include "FreeRTOS.h"
|
|
#include "queue.h"
|
|
#include "task.h"
|
|
|
|
#include "espressif/esp_common.h"
|
|
#include "espressif/sdk_private.h"
|
|
|
|
#include "i2c/i2c.h"
|
|
|
|
#define BMP180_RX_QUEUE_SIZE 10
|
|
#define BMP180_TASK_PRIORITY 9
|
|
|
|
#define BMP180_DEVICE_ADDRESS 0x77
|
|
|
|
#define BMP180_VERSION_REG 0xD0
|
|
#define BMP180_CONTROL_REG 0xF4
|
|
#define BMP180_RESET_REG 0xE0
|
|
#define BMP180_OUT_MSB_REG 0xF6
|
|
#define BMP180_OUT_LSB_REG 0xF7
|
|
#define BMP180_OUT_XLSB_REG 0xF8
|
|
|
|
#define BMP180_CALIBRATION_REG 0xAA
|
|
|
|
//
|
|
// Values for BMP180_CONTROL_REG
|
|
//
|
|
#define BMP180_MEASURE_TEMP 0x2E
|
|
#define BMP180_MEASURE_PRESS_OSS0 0x34
|
|
#define BMP180_MEASURE_PRESS_OSS1 0x74
|
|
#define BMP180_MEASURE_PRESS_OSS2 0xB4
|
|
#define BMP180_MEASURE_PRESS_OSS3 0xF4
|
|
|
|
#define BMP180_DEFAULT_CONV_TIME 5000
|
|
|
|
//
|
|
// CHIP ID stored in BMP180_VERSION_REG
|
|
//
|
|
#define BMP180_CHIP_ID 0x55
|
|
|
|
//
|
|
// Reset value for BMP180_RESET_REG
|
|
//
|
|
#define BMP180_RESET_VALUE 0xB6
|
|
|
|
|
|
// BMP180_Event_Command
|
|
typedef struct
|
|
{
|
|
uint8_t cmd;
|
|
const xQueueHandle* resultQueue;
|
|
} bmp180_command_t;
|
|
|
|
// Just works due to the fact that xQueueHandle is a "void *"
|
|
static xQueueHandle bmp180_rx_queue = NULL;
|
|
static xTaskHandle bmp180_task_handle = NULL;
|
|
|
|
// Calibration constants
|
|
static int16_t AC1;
|
|
static int16_t AC2;
|
|
static int16_t AC3;
|
|
static uint16_t AC4;
|
|
static uint16_t AC5;
|
|
static uint16_t AC6;
|
|
|
|
static int16_t B1;
|
|
static int16_t B2;
|
|
|
|
static int16_t MB;
|
|
static int16_t MC;
|
|
static int16_t MD;
|
|
|
|
//
|
|
// Forward declarations
|
|
//
|
|
static void bmp180_meassure(const bmp180_command_t* command);
|
|
static bool bmp180_informUser_Impl(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperature, bmp180_press_t pressure);
|
|
|
|
// Set default implementation .. User gets result as bmp180_result_t event
|
|
bool (*bmp180_informUser)(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperature, bmp180_press_t pressure) = bmp180_informUser_Impl;
|
|
|
|
// I2C Driver Task
|
|
static void bmp180_driver_task(void *pvParameters)
|
|
{
|
|
// Data to be received from user
|
|
bmp180_command_t current_command;
|
|
|
|
#ifdef BMP180_DEBUG
|
|
// Wait for commands from the outside
|
|
printf("%s: Started Task\n", __FUNCTION__);
|
|
#endif
|
|
|
|
while(1)
|
|
{
|
|
// Wait for user to insert commands
|
|
if (xQueueReceive(bmp180_rx_queue, ¤t_command, portMAX_DELAY) == pdTRUE)
|
|
{
|
|
#ifdef BMP180_DEBUG
|
|
printf("%s: Received user command %d 0x%p\n", __FUNCTION__, current_command.cmd, current_command.resultQueue);
|
|
#endif
|
|
// use user provided queue
|
|
if (current_command.resultQueue != NULL)
|
|
{
|
|
// Work on it ...
|
|
bmp180_meassure(¤t_command);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static uint8_t bmp180_readRegister8(uint8_t reg)
|
|
{
|
|
uint8_t r = 0;
|
|
|
|
if (!i2c_slave_read(BMP180_DEVICE_ADDRESS, reg, &r, 1))
|
|
{
|
|
r = 0;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
|
|
static int16_t bmp180_readRegister16(uint8_t reg)
|
|
{
|
|
uint8_t d[] = { 0, 0 };
|
|
int16_t r = 0;
|
|
|
|
if (i2c_slave_read(BMP180_DEVICE_ADDRESS, reg, d, 2))
|
|
{
|
|
r = ((int16_t)d[0]<<8) | (d[1]);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static void bmp180_start_Messurement(uint8_t cmd)
|
|
{
|
|
uint8_t d[] = { BMP180_CONTROL_REG, cmd };
|
|
|
|
i2c_slave_write(BMP180_DEVICE_ADDRESS, d, 2);
|
|
}
|
|
|
|
static int16_t bmp180_getUncompensatedMessurement(uint8_t cmd)
|
|
{
|
|
// Write Start Code into reg 0xF4 (Currently without oversampling ...)
|
|
bmp180_start_Messurement((cmd==BMP180_TEMPERATURE)?BMP180_MEASURE_TEMP:BMP180_MEASURE_PRESS_OSS0);
|
|
|
|
// Wait 5ms Datasheet states 4.5ms
|
|
sdk_os_delay_us(BMP180_DEFAULT_CONV_TIME);
|
|
|
|
return (int16_t)bmp180_readRegister16(BMP180_OUT_MSB_REG);
|
|
}
|
|
|
|
static void bmp180_fillInternalConstants(void)
|
|
{
|
|
AC1 = bmp180_readRegister16(BMP180_CALIBRATION_REG+0);
|
|
AC2 = bmp180_readRegister16(BMP180_CALIBRATION_REG+2);
|
|
AC3 = bmp180_readRegister16(BMP180_CALIBRATION_REG+4);
|
|
AC4 = bmp180_readRegister16(BMP180_CALIBRATION_REG+6);
|
|
AC5 = bmp180_readRegister16(BMP180_CALIBRATION_REG+8);
|
|
AC6 = bmp180_readRegister16(BMP180_CALIBRATION_REG+10);
|
|
|
|
B1 = bmp180_readRegister16(BMP180_CALIBRATION_REG+12);
|
|
B2 = bmp180_readRegister16(BMP180_CALIBRATION_REG+14);
|
|
|
|
MB = bmp180_readRegister16(BMP180_CALIBRATION_REG+16);
|
|
MC = bmp180_readRegister16(BMP180_CALIBRATION_REG+18);
|
|
MD = bmp180_readRegister16(BMP180_CALIBRATION_REG+20);
|
|
|
|
#ifdef BMP180_DEBUG
|
|
printf("%s: AC1:=%d AC2:=%d AC3:=%d AC4:=%u AC5:=%u AC6:=%u \n", __FUNCTION__, AC1, AC2, AC3, AC4, AC5, AC6);
|
|
printf("%s: B1:=%d B2:=%d\n", __FUNCTION__, B1, B2);
|
|
printf("%s: MB:=%d MC:=%d MD:=%d\n", __FUNCTION__, MB, MC, MD);
|
|
#endif
|
|
}
|
|
|
|
static bool bmp180_create_communication_queues()
|
|
{
|
|
// Just create them once
|
|
if (bmp180_rx_queue==NULL)
|
|
{
|
|
bmp180_rx_queue = xQueueCreate(BMP180_RX_QUEUE_SIZE, sizeof(bmp180_result_t));
|
|
}
|
|
|
|
return (bmp180_rx_queue!=NULL);
|
|
}
|
|
|
|
static bool bmp180_is_avaialble()
|
|
{
|
|
return (bmp180_readRegister8(BMP180_VERSION_REG)==BMP180_CHIP_ID);
|
|
}
|
|
|
|
static bool bmp180_createTask()
|
|
{
|
|
// We already have a task
|
|
portBASE_TYPE x = pdPASS;
|
|
|
|
if (bmp180_task_handle==NULL)
|
|
{
|
|
x = xTaskCreate(bmp180_driver_task, (signed char *)"bmp180_driver_task", 256, NULL, BMP180_TASK_PRIORITY, &bmp180_task_handle);
|
|
}
|
|
return (x==pdPASS);
|
|
}
|
|
|
|
static void bmp180_meassure(const bmp180_command_t* command)
|
|
{
|
|
int32_t T, P;
|
|
|
|
// Init result to 0
|
|
T = P = 0;
|
|
|
|
if (command->resultQueue != NULL)
|
|
{
|
|
int32_t UT, X1, X2, B5;
|
|
|
|
//
|
|
// Temperature is always needed ... Also required for pressure only
|
|
//
|
|
// Calculation taken from BMP180 Datasheet
|
|
UT = (int32_t)bmp180_getUncompensatedMessurement(BMP180_TEMPERATURE);
|
|
|
|
X1 = (UT - (int32_t)AC6) * ((int32_t)AC5) >> 15;
|
|
X2 = ((int32_t)MC << 11) / (X1 + (int32_t)MD);
|
|
B5 = X1 + X2;
|
|
|
|
T = (B5 + 8) >> 4;
|
|
|
|
#ifdef BMP180_DEBUG
|
|
printf("%s: T:= %ld.%d\n", __FUNCTION__, T/10, abs(T%10));
|
|
#endif
|
|
|
|
// Do we also need pressure?
|
|
if (command->cmd & BMP180_PRESSURE)
|
|
{
|
|
int32_t X3, B3, B6;
|
|
uint32_t B4, B7, UP;
|
|
|
|
UP = ((uint32_t)bmp180_getUncompensatedMessurement(BMP180_PRESSURE) & 0xFFFF);
|
|
|
|
// Calculation taken from BMP180 Datasheet
|
|
B6 = B5 - 4000;
|
|
X1 = ((int32_t)B2 * ((B6 * B6) >> 12)) >> 11;
|
|
X2 = ((int32_t)AC2 * B6) >> 11;
|
|
X3 = X1 + X2;
|
|
|
|
B3 = (((int32_t)AC1 * 4 + X3) + 2) >> 2;
|
|
X1 = ((int32_t)AC3 * B6) >> 13;
|
|
X2 = ((int32_t)B1 * ((B6 * B6) >> 12)) >> 16;
|
|
X3 = ((X1 + X2) + 2) >> 2;
|
|
B4 = ((uint32_t)AC4 * (uint32_t)(X3 + 32768)) >> 15;
|
|
B7 = (UP - B3) * (uint32_t)(50000UL);
|
|
|
|
if (B7 < 0x80000000)
|
|
{
|
|
P = (B7 * 2) / B4;
|
|
}
|
|
else
|
|
{
|
|
P = (B7 / B4) * 2;
|
|
}
|
|
|
|
X1 = (P >> 8) * (P >> 8);
|
|
X1 = (X1 * 3038) >> 16;
|
|
X2 = (-7357 * P) >> 16;
|
|
P = P + ((X1 + X2 + (int32_t)3791) >> 4);
|
|
|
|
#ifdef BMP180_DEBUG
|
|
printf("%s: P:= %ld\n", __FUNCTION__, P);
|
|
#endif
|
|
}
|
|
|
|
// Inform the user ...
|
|
if (!bmp180_informUser(command->resultQueue, command->cmd, ((bmp180_temp_t)T)/10.0, (bmp180_press_t)P))
|
|
{
|
|
// Failed to send info to user
|
|
printf("%s: Unable to inform user bmp180_informUser returned \"false\"\n", __FUNCTION__);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Default user inform implementation
|
|
static bool bmp180_informUser_Impl(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperature, bmp180_press_t pressure)
|
|
{
|
|
bmp180_result_t result;
|
|
|
|
result.cmd = cmd;
|
|
result.temperature = temperature;
|
|
result.pressure = pressure;
|
|
|
|
return (xQueueSend(*resultQueue, &result, 0) == pdTRUE);
|
|
}
|
|
|
|
// Just init all needed queues
|
|
bool bmp180_init(uint8_t scl, uint8_t sda)
|
|
{
|
|
// 1. Create required queues
|
|
bool result = false;
|
|
|
|
if (bmp180_create_communication_queues())
|
|
{
|
|
// 2. Init i2c driver
|
|
i2c_init(scl, sda);
|
|
|
|
// 3. Check for bmp180 ...
|
|
if (bmp180_is_avaialble())
|
|
{
|
|
// 4. Init all internal constants ...
|
|
bmp180_fillInternalConstants();
|
|
|
|
// 5. Start driver task
|
|
if (bmp180_createTask())
|
|
{
|
|
// We are finished
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void bmp180_trigger_measurement(const xQueueHandle* resultQueue)
|
|
{
|
|
bmp180_command_t c;
|
|
|
|
c.cmd = BMP180_PRESSURE + BMP180_TEMPERATURE;
|
|
c.resultQueue = resultQueue;
|
|
|
|
xQueueSend(bmp180_rx_queue, &c, 0);
|
|
}
|
|
|
|
|
|
void bmp180_trigger_pressure_measurement(const xQueueHandle* resultQueue)
|
|
{
|
|
bmp180_command_t c;
|
|
|
|
c.cmd = BMP180_PRESSURE;
|
|
c.resultQueue = resultQueue;
|
|
|
|
xQueueSend(bmp180_rx_queue, &c, 0);
|
|
}
|
|
|
|
void bmp180_trigger_temperature_measurement(const xQueueHandle* resultQueue)
|
|
{
|
|
bmp180_command_t c;
|
|
|
|
c.cmd = BMP180_TEMPERATURE;
|
|
c.resultQueue = resultQueue;
|
|
|
|
xQueueSend(bmp180_rx_queue, &c, 0);
|
|
}
|