diff --git a/conf/messages.xml b/conf/messages.xml index 09fddea031..692914de17 100644 --- a/conf/messages.xml +++ b/conf/messages.xml @@ -761,8 +761,24 @@ - - + + + + + + + + + + + + + + + + + + diff --git a/conf/modules/baro_ms5611_i2c.xml b/conf/modules/baro_ms5611_i2c.xml new file mode 100644 index 0000000000..d3bbf48f7e --- /dev/null +++ b/conf/modules/baro_ms5611_i2c.xml @@ -0,0 +1,21 @@ + + + + + +
+ +
+ + + + + + + + +
+ diff --git a/sw/airborne/modules/sensors/baro_ms5611_i2c.c b/sw/airborne/modules/sensors/baro_ms5611_i2c.c new file mode 100644 index 0000000000..a77eeba8b2 --- /dev/null +++ b/sw/airborne/modules/sensors/baro_ms5611_i2c.c @@ -0,0 +1,235 @@ +/* + * $Id$ + * + * Copyright (C) 2011 Martin Mueller + * + * This file is part of paparazzi. + * + * paparazzi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * paparazzi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/** \file baro_ms5611_i2c.c + * \brief Measurement Specialties (Intersema) MS5611-01BA pressure/temperature sensor interface for I2C + * + */ + + +#include "modules/sensors/baro_ms5611_i2c.h" + +#include "sys_time.h" +#include "mcu_periph/i2c.h" +#include "mcu_periph/uart.h" +#include "messages.h" +#include "downlink.h" + +#ifndef DOWNLINK_DEVICE +#define DOWNLINK_DEVICE DOWNLINK_AP_DEVICE +#endif + +#ifndef MS5611_I2C_DEV +#define MS5611_I2C_DEV i2c0 +#endif + +/* address can be 0xEC or 0xEE (CSB\ high = 0xEC) */ +#define MS5611_SLAVE_ADDR 0xEC + +#if PERIODIC_FREQUENCY > 60 +#error baro_ms5611_i2c assumes a PERIODIC_FREQUENCY of 60Hz +#endif + +struct i2c_transaction ms5611_trans; +uint8_t ms5611_status; +uint16_t ms5611_c[PROM_NB]; +uint32_t ms5611_d1, ms5611_d2; +int32_t prom_cnt; +float fbaroms, ftempms; + + +static int8_t baro_ms5611_crc(uint16_t* prom) { + int32_t i, j; + uint32_t res = 0; + uint8_t crc = prom[7] & 0xF; + prom[7] &= 0xFF00; + for (i = 0; i < 16; i++) { + if (i & 1) res ^= ((prom[i>>1]) & 0x00FF); + else res ^= (prom[i>>1]>>8); + for (j = 8; j > 0; j--) { + if (res & 0x8000) res ^= 0x1800; + res <<= 1; + } + } + prom[7] |= crc; + if (crc == ((res >> 12) & 0xF)) return 0; + else return -1; +} + +void baro_ms5611_init(void) { + ms5611_status = MS5611_UNINIT; + prom_cnt = 0; +} + +void baro_ms5611_periodic( void ) { + if (cpu_time_sec > 1) { + if (ms5611_status >= MS5611_IDLE) { + /* start D1 conversion */ + ms5611_status = MS5611_CONV_D1; + ms5611_trans.buf[0] = MS5611_START_CONV_D1; + I2CTransmit(MS5611_I2C_DEV, ms5611_trans, MS5611_SLAVE_ADDR, 1); + RunOnceEvery((4*30), DOWNLINK_SEND_MS5611_COEFF(DefaultChannel, + &ms5611_c[0], &ms5611_c[1], &ms5611_c[2], &ms5611_c[3], + &ms5611_c[4], &ms5611_c[5], &ms5611_c[6], &ms5611_c[7])); + } + else if (ms5611_status == MS5611_UNINIT) { + /* reset sensor */ + ms5611_status = MS5611_RESET; + ms5611_trans.buf[0] = MS5611_SOFT_RESET; + I2CTransmit(MS5611_I2C_DEV, ms5611_trans, MS5611_SLAVE_ADDR, 1); + } + else if (ms5611_status == MS5611_RESET_OK) { + /* start getting prom data */ + ms5611_status = MS5611_PROM; + ms5611_trans.buf[0] = MS5611_PROM_READ | (prom_cnt << 1); + I2CTransceive(MS5611_I2C_DEV, ms5611_trans, MS5611_SLAVE_ADDR, 1, 2); + } + } +} + +void baro_ms5611_d1( void ) { + if (cpu_time_sec > 1) { + if (ms5611_status == MS5611_CONV_D1_OK) { + /* read D1 adc */ + ms5611_status = MS5611_ADC_D1; + ms5611_trans.buf[0] = MS5611_ADC_READ; + I2CTransceive(MS5611_I2C_DEV, ms5611_trans, MS5611_SLAVE_ADDR, 1, 3); + } + } +} + +void baro_ms5611_d2( void ) { + if (cpu_time_sec > 1) { + if (ms5611_status == MS5611_CONV_D2_OK) { + /* read D2 adc */ + ms5611_status = MS5611_ADC_D2; + ms5611_trans.buf[0] = MS5611_ADC_READ; + I2CTransceive(MS5611_I2C_DEV, ms5611_trans, MS5611_SLAVE_ADDR, 1, 3); + } + } +} + +void baro_ms5611_event( void ) { + if (ms5611_trans.status == I2CTransSuccess) { + switch (ms5611_status) { + + case MS5611_RESET: + ms5611_status = MS5611_RESET_OK; + ms5611_trans.status = I2CTransDone; + break; + + case MS5611_PROM: + /* read prom data */ + ms5611_c[prom_cnt++] = (ms5611_trans.buf[0] << 8) | ms5611_trans.buf[1]; + if (prom_cnt < PROM_NB) { + /* get next prom data */ + ms5611_trans.buf[0] = MS5611_PROM_READ | (prom_cnt << 1); + I2CTransceive(MS5611_I2C_DEV, ms5611_trans, MS5611_SLAVE_ADDR, 1, 2); + } + else { + /* done reading prom */ + ms5611_trans.status = I2CTransDone; + /* check prom crc */ + if (baro_ms5611_crc(ms5611_c) == 0) { + DOWNLINK_SEND_MS5611_COEFF(DefaultChannel, + &ms5611_c[0], &ms5611_c[1], &ms5611_c[2], &ms5611_c[3], + &ms5611_c[4], &ms5611_c[5], &ms5611_c[6], &ms5611_c[7]); + ms5611_status = MS5611_IDLE; + } + else { + /* checksum error, try again */ + baro_ms5611_init(); + } + } + break; + + case MS5611_CONV_D1: + ms5611_status = MS5611_CONV_D1_OK; + ms5611_trans.status = I2CTransDone; + break; + + case MS5611_ADC_D1: + /* read D1 (pressure) */ + ms5611_d1 = (ms5611_trans.buf[0] << 16) | + (ms5611_trans.buf[1] << 8) | + ms5611_trans.buf[2]; + /* start D2 conversion */ + ms5611_status = MS5611_CONV_D2; + ms5611_trans.buf[0] = MS5611_START_CONV_D2; + I2CTransmit(MS5611_I2C_DEV, ms5611_trans, MS5611_SLAVE_ADDR, 1); + break; + + case MS5611_CONV_D2: + ms5611_status = MS5611_CONV_D2_OK; + ms5611_trans.status = I2CTransDone; + break; + + case MS5611_ADC_D2: { + int64_t dt, baroms, tempms, off, sens, t2, off2, sens2; + /* read D2 (temperature) */ + ms5611_d2 = (ms5611_trans.buf[0] << 16) | + (ms5611_trans.buf[1] << 8) | + ms5611_trans.buf[2]; + ms5611_status = MS5611_IDLE; + ms5611_trans.status = I2CTransDone; + + /* difference between actual and ref temperature */ + dt = ms5611_d2 - (int64_t)ms5611_c[5] * (1<<8); + /* actual temperature */ + tempms = 2000 + ((int64_t)dt * ms5611_c[6]) / (1<<23); + /* offset at actual temperature */ + off = ((int64_t)ms5611_c[2] * (1<<16)) + ((int64_t)ms5611_c[4] * dt) / (1<<7); + /* sensitivity at actual temperature */ + sens = ((int64_t)ms5611_c[1] * (1<<15)) + ((int64_t)ms5611_c[3] * dt) / (1<<8); + /* second order temperature compensation */ + if (tempms < 2000) { + t2 = (dt*dt) / (1<<31); + off2 = 5 * ((int64_t)(tempms-2000)*(tempms-2000)) / (1<<1); + sens2 = 5 * ((int64_t)(tempms-2000)*(tempms-2000)) / (1<<2); + if (tempms < -1500) { + off2 = off2 + 7 * (int64_t)(tempms+1500)*(tempms+1500); + sens2 = sens2 + 11 * ((int64_t)(tempms+1500)*(tempms+1500)) / (1<<1); + } + tempms = tempms - t2; + off = off - off2; + sens = sens - sens2; + } + /* temperature compensated pressure */ + baroms = (((int64_t)ms5611_d1 * sens) / (1<<21) - off) / (1<<15); +#ifdef SENSOR_SYNC_SEND + ftempms = tempms / 100.; + fbaroms = baroms / 100.; + DOWNLINK_SEND_BARO_MS5611(DefaultChannel, + &ms5611_d1, &ms5611_d2, &fbaroms, &ftempms); +#endif + break; + } + + default: + ms5611_trans.status = I2CTransDone; + break; + } + } +} + diff --git a/sw/airborne/modules/sensors/baro_ms5611_i2c.h b/sw/airborne/modules/sensors/baro_ms5611_i2c.h new file mode 100644 index 0000000000..6acef006a7 --- /dev/null +++ b/sw/airborne/modules/sensors/baro_ms5611_i2c.h @@ -0,0 +1,35 @@ +#ifndef BARO_MS56111_I2C_H +#define BARO_MS56111_I2C_H + +#include "std.h" + +/* we use OSR=4096 for maximum resolution */ +#define MS5611_SOFT_RESET 0x1E +#define MS5611_PROM_READ 0xA0 +#define MS5611_START_CONV_D1 0x48 +#define MS5611_START_CONV_D2 0x58 +#define MS5611_ADC_READ 0x00 + +#define PROM_NB 8 + +enum ms5611_stat{ + MS5611_UNINIT, + MS5611_RESET, + MS5611_RESET_OK, + MS5611_PROM, + MS5611_IDLE, + MS5611_CONV_D1, + MS5611_CONV_D1_OK, + MS5611_ADC_D1, + MS5611_CONV_D2, + MS5611_CONV_D2_OK, + MS5611_ADC_D2 +}; + +void baro_ms5611_init(void); +void baro_ms5611_periodic(void); +void baro_ms5611_d1(void); +void baro_ms5611_d2(void); +void baro_ms5611_event(void); + +#endif