/* * spreadspace avr utils * * * Copyright (C) 2016 Bernhard Tittelbach * Thanks to Adafruit for writing a great example. Go buy their stuff! * * This file is part of spreadspace avr utils. * * spreadspace avr utils 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 3 of the License, or * any later version. * * spreadspace avr utils 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 spreadspace avr utils. If not, see . */ #include #include #include #include "bmp280.h" void bmp280_cs(bmp280_sensor *sensor, uint8_t select) { if (!select) *(sensor->cs_port) |= _BV(sensor->cs_pin); else *(sensor->cs_port) &= ~ _BV(sensor->cs_pin); } void bmp280_write8(bmp280_sensor *sensor, uint8_t reg, uint8_t value) { bmp280_cs(sensor, true); SPI_SendByte(reg & ~0x80); //bit 7 needs to be low for write mode SPI_SendByte(value); bmp280_cs(sensor, false); } uint8_t bmp280_read8(bmp280_sensor *sensor, uint8_t reg) { bmp280_cs(sensor, true); SPI_SendByte(reg | 0x80); //bit 7 high for read mode uint8_t value = SPI_ReceiveByte(); bmp280_cs(sensor, false); return value; } uint16_t bmp280_read16(bmp280_sensor *sensor, uint8_t reg) { uint16_t value = 0; bmp280_cs(sensor, true); SPI_SendByte(reg | 0x80); //bit 7 high for read mode value |= ((uint16_t) SPI_ReceiveByte() & 0xFF) << 8; value |= (uint16_t) SPI_ReceiveByte() & 0xFF; bmp280_cs(sensor, false); return value; } uint32_t bmp280_read24(bmp280_sensor *sensor, uint8_t reg) { uint32_t value = 0; bmp280_cs(sensor, true); SPI_SendByte(reg | 0x80); //bit 7 high for read mode value |= ((uint32_t) SPI_ReceiveByte() & 0xFF) << 16; value |= ((uint32_t) SPI_ReceiveByte() & 0xFF) << 8; value |= (uint32_t) SPI_ReceiveByte() & 0xFF; bmp280_cs(sensor, false); return value; } int16_t bmp280_readS16(bmp280_sensor *sensor, uint8_t reg) { return (int16_t) bmp280_read16(sensor, reg); } uint16_t bmp280_read16_LE(bmp280_sensor *sensor, uint8_t reg) { uint16_t value = bmp280_read16(sensor, reg); return (value >> 8) | (value << 8); } int16_t bmp280_readS16_LE(bmp280_sensor *sensor, uint8_t reg) { return (int16_t)bmp280_read16_LE(sensor, reg); } void bmp280_readCoefficients(bmp280_sensor *sensor) { sensor->dig_T1 = bmp280_read16_LE(sensor,BMP280_REGISTER_DIG_T1); sensor->dig_T2 = bmp280_readS16_LE(sensor,BMP280_REGISTER_DIG_T2); sensor->dig_T3 = bmp280_readS16_LE(sensor,BMP280_REGISTER_DIG_T3); sensor->dig_P1 = bmp280_read16_LE(sensor,BMP280_REGISTER_DIG_P1); sensor->dig_P2 = bmp280_readS16_LE(sensor,BMP280_REGISTER_DIG_P2); sensor->dig_P3 = bmp280_readS16_LE(sensor,BMP280_REGISTER_DIG_P3); sensor->dig_P4 = bmp280_readS16_LE(sensor,BMP280_REGISTER_DIG_P4); sensor->dig_P5 = bmp280_readS16_LE(sensor,BMP280_REGISTER_DIG_P5); sensor->dig_P6 = bmp280_readS16_LE(sensor,BMP280_REGISTER_DIG_P6); sensor->dig_P7 = bmp280_readS16_LE(sensor,BMP280_REGISTER_DIG_P7); sensor->dig_P8 = bmp280_readS16_LE(sensor,BMP280_REGISTER_DIG_P8); sensor->dig_P9 = bmp280_readS16_LE(sensor,BMP280_REGISTER_DIG_P9); } uint8_t bmp280_check_chipid(bmp280_sensor *sensor) { uint8_t chip_id = bmp280_read8(sensor, BMP280_REGISTER_CHIPID); return chip_id == 0x58; } //need to init SPI beforehand uint8_t bmp280_init(bmp280_sensor *sensor, volatile uint8_t *cs_port, uint8_t cs_pin) { memset(sensor,0,sizeof(bmp280_sensor)); sensor->cs_port = cs_port; sensor->cs_pin = cs_pin; uint8_t sensor_available = bmp280_check_chipid(sensor); if (!sensor_available) return sensor_available; //don't talk with chip, it doesn't speak our language bmp280_readCoefficients(sensor); bmp280_write8(sensor, BMP280_REGISTER_CONTROL, 0x3F); return sensor_available; } int32_t bmp280_readFineTemp(bmp280_sensor *sensor) { int32_t var1, var2; int32_t adc_T = bmp280_read24(sensor, BMP280_REGISTER_TEMPDATA); adc_T >>= 4; var1 = ((((adc_T>>3) - ((int32_t)sensor->dig_T1 <<1))) * ((int32_t)sensor->dig_T2)) >> 11; var2 = (((((adc_T>>4) - ((int32_t)sensor->dig_T1)) * ((adc_T>>4) - ((int32_t)sensor->dig_T1))) >> 12) * ((int32_t)sensor->dig_T3)) >> 14; return var1 + var2; } float bmp280_convertTempToCelsius(int32_t bmp280_t_fine) { float T = (bmp280_t_fine * 5 + 128) >> 8; return T/100; } float bmp280_readTemp(bmp280_sensor *sensor) { return bmp280_convertTempToCelsius(bmp280_readFineTemp(sensor)); } bmp280_result bmp280_readTempAndPressure(bmp280_sensor *sensor) { bmp280_result result; result.temperature = 0; result.pressure = 0; int64_t var1, var2, p; int32_t bmp280_t_fine = bmp280_readFineTemp(sensor); result.temperature = bmp280_convertTempToCelsius(bmp280_t_fine); int32_t adc_P = bmp280_read24(sensor, BMP280_REGISTER_PRESSUREDATA); adc_P >>= 4; var1 = ((int64_t)bmp280_t_fine) - 128000; var2 = var1 * var1 * (int64_t)sensor->dig_P6; var2 = var2 + ((var1*(int64_t)sensor->dig_P5)<<17); var2 = var2 + (((int64_t)sensor->dig_P4)<<35); var1 = ((var1 * var1 * (int64_t)sensor->dig_P3)>>8) + ((var1 * (int64_t)sensor->dig_P2)<<12); var1 = (((((int64_t)1)<<47)+var1))*((int64_t)sensor->dig_P1)>>33; if (var1 == 0) { return result; // avoid exception caused by division by zero } p = 1048576 - adc_P; p = (((p<<31) - var2)*3125) / var1; var1 = (((int64_t)sensor->dig_P9) * (p>>13) * (p>>13)) >> 25; var2 = (((int64_t)sensor->dig_P8) * p) >> 19; p = ((p + var1 + var2) >> 8) + (((int64_t)sensor->dig_P7)<<4); result.pressure = (float)p/256; return result; } float bmp280_readPressure(bmp280_sensor *sensor) { bmp280_result result = bmp280_readTempAndPressure(sensor); return result.pressure; } float bmp280_calcAltitude(float pressure, float sealevelp) { pressure /= 100; return 44330 * (1.0 - pow(pressure / sealevelp, 0.1903)); } float bmp280_readAltitude(bmp280_sensor *sensor, float sealevelp) { return bmp280_calcAltitude(bmp280_readTempAndPressure(sensor).pressure, sealevelp); }