aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2020-04-16 17:29:42 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2020-04-20 10:19:14 +0200
commitabab04305a4801fffa231d9b4a0fda9bf1d361f5 (patch)
tree779cb0efa2677e7264f3e5c2d113d0df9907ebd5
parent7e36b51474a641f813fad07d261b2c9a758387be (diff)
downloadglutte-o-matic-abab04305a4801fffa231d9b4a0fda9bf1d361f5.tar.gz
glutte-o-matic-abab04305a4801fffa231d9b4a0fda9bf1d361f5.tar.bz2
glutte-o-matic-abab04305a4801fffa231d9b4a0fda9bf1d361f5.zip
Add BMP085 to the temperature sw project
-rw-r--r--doc/pio.txt4
-rw-r--r--src/temperature/bmp085.c245
-rw-r--r--src/temperature/bmp085.h81
-rw-r--r--src/temperature/i2c.c334
-rw-r--r--src/temperature/i2c.h53
-rw-r--r--src/temperature/main.c62
6 files changed, 757 insertions, 22 deletions
diff --git a/doc/pio.txt b/doc/pio.txt
index 3332cc7..c64f298 100644
--- a/doc/pio.txt
+++ b/doc/pio.txt
@@ -54,6 +54,10 @@ I2C to Audio Codec
- i/o I2C1 SDA PB9
- i/o I2C1 SCL PB6
+audio codec is at I2C address 0x4A
+
+I2C to Bosch BMP085 uses same I2C, and uses 0x77.
+
STM32DISCOVERY onboard things
-----------------------------
- out Green LED (launcher) PD12
diff --git a/src/temperature/bmp085.c b/src/temperature/bmp085.c
new file mode 100644
index 0000000..65f8c9d
--- /dev/null
+++ b/src/temperature/bmp085.c
@@ -0,0 +1,245 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Matthias P. Braendli, Maximilien Cuony
+ *
+ * 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 "FreeRTOS.h"
+#include "task.h"
+#include "bmp085.h"
+#include "i2c.h"
+#include "debug.h"
+#include <stdio.h>
+
+const uint8_t mode = BMP085_MODE_ULTRAHIGHRES;
+
+static int init_ok = 0;
+static bmp085_calib_data_t bmp085_coeffs;
+
+static int bmp085_raw_temp(int32_t *raw_temp);
+static int bmp085_raw_pressure(int32_t *raw_pressure);
+static int read_u16(uint8_t reg, uint16_t *value);
+static int read_s16(uint8_t reg, int16_t *value);
+
+int read_u16(uint8_t reg, uint16_t *value)
+{
+ int success = 0;
+ if (i2c_transaction_start()) {
+ success = i2c_read_from(BMP085_ADDRESS, reg, (uint8_t*)value, 2) > 0;
+ i2c_transaction_end();
+ }
+ else {
+ debug_print("read_u16 no transaction!\n");
+ }
+ return success;
+}
+
+int read_s16(uint8_t reg, int16_t *value) {
+ uint16_t v;
+ int success = read_u16(reg, &v);
+ *value = (int16_t)v;
+ return success;
+}
+
+static void print_s16(const char *hdr, int16_t value) {
+ char t[32];
+ snprintf(t, 32, "%s=%d\n", hdr, value);
+ debug_print(t);
+}
+
+static void print_s32(const char *hdr, int32_t value) {
+ char t[32];
+ snprintf(t, 32, "%s=%ld\n", hdr, value);
+ debug_print(t);
+}
+
+static void print_u16(const char *hdr, uint16_t value) {
+ char t[32];
+ snprintf(t, 32, "%s=%d\n", hdr, value);
+ debug_print(t);
+}
+
+int bmp085_init() {
+ uint8_t id = 0;
+
+ int success = 0;
+ if (i2c_transaction_start()) {
+ success = i2c_read_from(BMP085_ADDRESS, BMP085_REGISTER_CHIPID, &id, 1) > 0;
+ i2c_transaction_end();
+ }
+ else {
+ debug_print("bmp085_init no transaction");
+ }
+
+ if (success == 0 || id != 0x55) {
+ return 0;
+ }
+
+ success &= read_s16(BMP085_REGISTER_CAL_AC1, &bmp085_coeffs.ac1);
+ success &= read_s16(BMP085_REGISTER_CAL_AC2, &bmp085_coeffs.ac2);
+ success &= read_s16(BMP085_REGISTER_CAL_AC3, &bmp085_coeffs.ac3);
+ success &= read_u16(BMP085_REGISTER_CAL_AC4, &bmp085_coeffs.ac4);
+ success &= read_u16(BMP085_REGISTER_CAL_AC5, &bmp085_coeffs.ac5);
+ success &= read_u16(BMP085_REGISTER_CAL_AC6, &bmp085_coeffs.ac6);
+ success &= read_s16(BMP085_REGISTER_CAL_B1, &bmp085_coeffs.b1);
+ success &= read_s16(BMP085_REGISTER_CAL_B2, &bmp085_coeffs.b2);
+ success &= read_s16(BMP085_REGISTER_CAL_MB, &bmp085_coeffs.mb);
+ success &= read_s16(BMP085_REGISTER_CAL_MC, &bmp085_coeffs.mc);
+ success &= read_s16(BMP085_REGISTER_CAL_MD, &bmp085_coeffs.md);
+
+ print_s16("AC1", bmp085_coeffs.ac1);
+ print_s16("AC2", bmp085_coeffs.ac2);
+ print_s16("AC3", bmp085_coeffs.ac3);
+ print_u16("AC4", bmp085_coeffs.ac4);
+ print_u16("AC5", bmp085_coeffs.ac5);
+ print_u16("AC6", bmp085_coeffs.ac6);
+ print_s16("B1", bmp085_coeffs.b1);
+ print_s16("B2", bmp085_coeffs.b2);
+ print_s16("MB", bmp085_coeffs.mb);
+ print_s16("MC", bmp085_coeffs.mc);
+ print_s16("MD", bmp085_coeffs.md);
+
+ init_ok = success;
+ return success;
+}
+
+
+int bmp085_raw_temp(int32_t *raw_temp)
+{
+ int success = 1;
+ const uint8_t data[2] = {BMP085_REGISTER_CONTROL, BMP085_COMMAND_READTEMP};
+ if (i2c_transaction_start()) {
+ success &= i2c_write(BMP085_ADDRESS, data, 2);
+ i2c_transaction_end();
+ }
+ else {
+ return 0;
+ }
+
+ vTaskDelay(15 / portTICK_PERIOD_MS);
+
+ uint16_t t;
+ success &= read_u16(BMP085_REGISTER_TEMPDATA, &t);
+ *raw_temp = t;
+ return success;
+}
+
+int bmp085_raw_pressure(int32_t *raw_pressure)
+{
+ int success = 1;
+
+ const uint8_t data[2] = {BMP085_REGISTER_CONTROL, BMP085_COMMAND_READPRESSURE | (mode << 6)};
+ if (i2c_transaction_start()) {
+ success &= i2c_write(BMP085_ADDRESS, data, 2);
+ i2c_transaction_end();
+ }
+ else {
+ return 0;
+ }
+
+ int delay = 0;
+ switch (mode) {
+ case BMP085_MODE_ULTRALOWPOWER:
+ delay = 5;
+ break;
+ case BMP085_MODE_STANDARD:
+ delay = 8;
+ break;
+ case BMP085_MODE_HIGHRES:
+ delay = 14;
+ break;
+ case BMP085_MODE_ULTRAHIGHRES:
+ default:
+ delay = 26;
+ break;
+ }
+ vTaskDelay(3*delay / portTICK_PERIOD_MS);
+
+ uint8_t p8;
+ uint16_t p16;
+ int32_t p32;
+
+ success &= read_u16(BMP085_REGISTER_PRESSUREDATA, &p16);
+ p32 = (uint32_t)p16 << 8;
+
+ if (i2c_transaction_start()) {
+ success &= i2c_read_from(BMP085_ADDRESS, BMP085_REGISTER_PRESSUREDATA+2, &p8, 1) > 0;
+ i2c_transaction_end();
+ }
+ p32 += p8;
+ p32 >>= (8 - mode);
+ *raw_pressure = p32;
+ return success;
+}
+
+int bmp085_get_temp_pressure(int32_t *temperature_deciDeg, int32_t *pressure_Pa)
+{
+ if (!init_ok) {
+ return 0;
+ }
+
+ int32_t compp = 0;
+ int32_t x1, x2, b5, b6, x3, b3, p;
+ uint32_t b4, b7;
+
+ int32_t ut = 0;
+ int success = bmp085_raw_temp(&ut);
+ print_s32("ut", ut);
+ int32_t up = 0;
+ success &= bmp085_raw_pressure(&up);
+ print_s32("up", up);
+
+ /* Temperature compensation */
+ int32_t X1 = (ut - (int32_t)bmp085_coeffs.ac6) * ((int32_t)bmp085_coeffs.ac5) >> 15;
+ int32_t X2 = ((int32_t)bmp085_coeffs.mc << 11) / (X1+(int32_t)bmp085_coeffs.md);
+ b5 = X1 + X2;
+ int32_t temp = (b5 + 8) >> 4;
+ *temperature_deciDeg = temp;
+
+ /* Pressure compensation */
+ b6 = b5 - 4000;
+ x1 = (bmp085_coeffs.b2 * ((b6 * b6) >> 12)) >> 11;
+ x2 = (bmp085_coeffs.ac2 * b6) >> 11;
+ x3 = x1 + x2;
+ b3 = (((((int32_t) bmp085_coeffs.ac1) * 4 + x3) << mode) + 2) >> 2;
+ x1 = (bmp085_coeffs.ac3 * b6) >> 13;
+ x2 = (bmp085_coeffs.b1 * ((b6 * b6) >> 12)) >> 16;
+ x3 = ((x1 + x2) + 2) >> 2;
+ b4 = (bmp085_coeffs.ac4 * (uint32_t) (x3 + 32768)) >> 15;
+ b7 = ((uint32_t) (up - b3) * (50000 >> mode));
+
+ if (b7 < 0x80000000) {
+ p = (b7 << 1) / b4;
+ }
+ else {
+ p = (b7 / b4) << 1;
+ }
+
+ x1 = (p >> 8) * (p >> 8);
+ x1 = (x1 * 3038) >> 16;
+ x2 = (-7357 * p) >> 16;
+ compp = p + ((x1 + x2 + 3791) >> 4);
+
+ /* Assign compensated pressure value */
+ *pressure_Pa = compp;
+
+ return success;
+}
diff --git a/src/temperature/bmp085.h b/src/temperature/bmp085.h
new file mode 100644
index 0000000..7ed440b
--- /dev/null
+++ b/src/temperature/bmp085.h
@@ -0,0 +1,81 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Matthias P. Braendli, Maximilien Cuony
+ *
+ * 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.
+*/
+
+#pragma once
+#include <stdint.h>
+
+#define BMP085_ADDRESS (0x77)
+
+typedef enum {
+ BMP085_REGISTER_CAL_AC1 = 0xAA,
+ BMP085_REGISTER_CAL_AC2 = 0xAC,
+ BMP085_REGISTER_CAL_AC3 = 0xAE,
+ BMP085_REGISTER_CAL_AC4 = 0xB0,
+ BMP085_REGISTER_CAL_AC5 = 0xB2,
+ BMP085_REGISTER_CAL_AC6 = 0xB4,
+ BMP085_REGISTER_CAL_B1 = 0xB6,
+ BMP085_REGISTER_CAL_B2 = 0xB8,
+ BMP085_REGISTER_CAL_MB = 0xBA,
+ BMP085_REGISTER_CAL_MC = 0xBC,
+ BMP085_REGISTER_CAL_MD = 0xBE,
+ BMP085_REGISTER_CHIPID = 0xD0,
+ BMP085_REGISTER_VERSION = 0xD1,
+ BMP085_REGISTER_SOFTRESET = 0xE0,
+ BMP085_REGISTER_CONTROL = 0xF4,
+ BMP085_REGISTER_TEMPDATA = 0xF6,
+ BMP085_REGISTER_PRESSUREDATA = 0xF6,
+} bmp085_register_address_t;
+
+typedef enum {
+ BMP085_COMMAND_READTEMP = 0x2E,
+ BMP085_COMMAND_READPRESSURE = 0x34
+} bmp085_command_t;
+
+typedef enum {
+ BMP085_MODE_ULTRALOWPOWER = 0,
+ BMP085_MODE_STANDARD = 1,
+ BMP085_MODE_HIGHRES = 2,
+ BMP085_MODE_ULTRAHIGHRES = 3
+} bmp085_mode_t;
+
+
+typedef struct {
+ int16_t ac1;
+ int16_t ac2;
+ int16_t ac3;
+ uint16_t ac4;
+ uint16_t ac5;
+ uint16_t ac6;
+ int16_t b1;
+ int16_t b2;
+ int16_t mb;
+ int16_t mc;
+ int16_t md;
+} bmp085_calib_data_t;
+
+// Returns 1 on success
+int bmp085_init();
+
+// Returns 1 on success
+int bmp085_get_temp_pressure(int32_t *temperature_deciDeg, int32_t *pressure_Pa);
diff --git a/src/temperature/i2c.c b/src/temperature/i2c.c
new file mode 100644
index 0000000..25c9166
--- /dev/null
+++ b/src/temperature/i2c.c
@@ -0,0 +1,334 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Matthias P. Braendli
+ *
+ * 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 "i2c.h"
+
+#include "stm32f4xx_conf.h"
+#include "stm32f4xx_i2c.h"
+#include "stm32f4xx.h"
+#include "FreeRTOS.h"
+#include "FreeRTOSConfig.h"
+#include "task.h"
+#include "semphr.h"
+
+/* I2C 1 on PB9 and PB6
+ * See pio.txt for PIO allocation details */
+const uint16_t GPIOB_PIN_SDA = GPIO_Pin_9;
+const uint16_t GPIOB_PIN_SCL = GPIO_Pin_6;
+
+#define trigger_fault(x) do { __asm__ volatile("nop"); } while (1);
+
+
+static int i2c_init_done = 0;
+static int i2c_error = 0;
+
+static I2C_TypeDef* const I2Cx = I2C1;
+
+static SemaphoreHandle_t i2c_semaphore;
+
+static void i2c_device_init(void);
+
+/* According to I2C spec UM10204:
+ * 3.1.16 Bus clear
+ * In the unlikely event where the clock (SCL) is stuck LOW, the preferential
+ * procedure is to reset the bus using the HW reset signal if your I2C devices
+ * have HW reset inputs. If the I2C devices do not have HW reset inputs, cycle
+ * power to the devices to activate the mandatory internal Power-On Reset (POR)
+ * circuit.
+ *
+ * If the data line (SDA) is stuck LOW, the master should send nine clock
+ * pulses. The device that held the bus LOW should release it sometime within
+ * those nine clocks. If not, then use the HW reset or cycle power to clear the
+ * bus.
+ */
+static int i2c_recover_count;
+static void i2c_recover_from_lockup(void)
+{
+ i2c_recover_count++;
+ if (i2c_recover_count > 3) {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+
+ I2C_SoftwareResetCmd(I2Cx, ENABLE);
+ for (int i = 0; i < 0x4fff; i++) {
+ __asm__ volatile("nop");
+ }
+ I2C_SoftwareResetCmd(I2Cx, DISABLE);
+}
+
+static void i2c_device_init(void)
+{
+ // Configure I2C SCL and SDA pins.
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = GPIOB_PIN_SCL | GPIOB_PIN_SDA;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
+ GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);
+
+ // Reset I2C.
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
+
+ // configure I2C1
+ I2C_InitTypeDef I2C_InitStruct;
+ I2C_InitStruct.I2C_ClockSpeed = 100000; //Hz
+ I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
+ I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 50% duty cycle
+ I2C_InitStruct.I2C_OwnAddress1 = 0x00; // not relevant in master mode
+
+ // disable acknowledge when reading (can be changed later on)
+ I2C_InitStruct.I2C_Ack = I2C_Ack_Disable;
+
+ I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
+ I2C_Init(I2C1, &I2C_InitStruct);
+
+ // enable I2C1
+ I2C_Cmd(I2C1, ENABLE);
+
+ i2c_recover_count = 0;
+}
+
+void i2c_init()
+{
+ if (i2c_init_done == 1) {
+ return;
+ }
+
+ i2c_semaphore = xSemaphoreCreateBinary();
+
+ if ( i2c_semaphore == NULL ) {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+ else {
+ xSemaphoreGive(i2c_semaphore);
+ }
+
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
+
+ i2c_device_init();
+ i2c_init_done = 1;
+}
+
+static int i2c_check_busy_flag(void)
+{
+ const TickType_t i2c_timeout = pdMS_TO_TICKS(1000);
+ const TickType_t time_start = xTaskGetTickCount();
+
+ while (I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)) {
+ const TickType_t time_now = xTaskGetTickCount();
+
+ if (time_now - time_start > i2c_timeout) {
+ i2c_error = 1;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int i2c_check_event(uint32_t event)
+{
+ const TickType_t i2c_timeout = pdMS_TO_TICKS(1000);
+ const TickType_t time_start = xTaskGetTickCount();
+
+ while (!I2C_CheckEvent(I2Cx, event)) {
+ const TickType_t time_now = xTaskGetTickCount();
+
+ if (time_start + i2c_timeout < time_now) {
+ i2c_error = 1;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int i2c_start(uint8_t device, uint8_t direction)
+{
+ I2C_GenerateSTART(I2Cx, ENABLE);
+
+ // wait for bus free
+ if (!i2c_check_event(I2C_EVENT_MASTER_MODE_SELECT)) {
+ I2C_GenerateSTART(I2Cx, DISABLE);
+ return 0;
+ }
+
+ I2C_Send7bitAddress(I2Cx, device << 1, direction);
+
+ /* wait for I2C1 EV6, check if
+ * either Slave has acknowledged Master transmitter or
+ * Master receiver mode, depending on the transmission
+ * direction
+ */
+ uint32_t event = 0;
+ if (direction == I2C_Direction_Transmitter) {
+ event = I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED;
+ }
+ else if (direction == I2C_Direction_Receiver) {
+ event = I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED;
+ }
+ else {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+
+ if (!i2c_check_event(event)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int i2c_send(uint8_t data)
+{
+ I2C_SendData(I2Cx, data);
+
+ // wait for I2C1 EV8_2 --> byte has been transmitted
+ return i2c_check_event(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
+}
+
+int i2c_write(uint8_t device, const uint8_t *txbuf, int len)
+{
+ if (i2c_init_done == 0) {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+
+ int success = i2c_check_busy_flag();
+
+ if (success) {
+ success = i2c_start(device, I2C_Direction_Transmitter);
+ }
+
+ if (success) {
+ for (int i = 0; i < len; i++) {
+ success = i2c_send(txbuf[i]);
+ if (!success) {
+ break;
+ }
+ }
+
+ I2C_GenerateSTOP(I2Cx, ENABLE);
+ success = i2c_check_event(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
+ }
+
+ return success;
+}
+
+static int i2c_read_nobuscheck(uint8_t device, uint8_t *rxbuf, int len)
+{
+ if (i2c_init_done == 0) {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+
+ if (i2c_start(device, I2C_Direction_Receiver)) {
+ for (int i = 0; i < len; i++) {
+ if (i == len-1) {
+ I2C_AcknowledgeConfig(I2Cx, DISABLE);
+ }
+ else {
+ I2C_AcknowledgeConfig(I2Cx, ENABLE);
+ }
+
+ // wait until one byte has been received, possibly timout
+ if (!i2c_check_event(I2C_EVENT_MASTER_BYTE_RECEIVED)) {
+ I2C_GenerateSTOP(I2Cx, ENABLE);
+ return 0;
+ }
+
+ if (i == len-1) {
+ I2C_GenerateSTOP(I2Cx, ENABLE);
+ }
+
+ rxbuf[i] = I2C_ReceiveData(I2Cx);
+ }
+ return len;
+ }
+
+ return 0;
+}
+
+int i2c_read(uint8_t device, uint8_t *rxbuf, int len)
+{
+ int success = i2c_check_busy_flag();
+
+ if (success) {
+ success = i2c_read_nobuscheck(device, rxbuf, len);
+ }
+
+ return success;
+}
+
+int i2c_read_from(uint8_t device, uint8_t address, uint8_t *rxbuf, int len)
+{
+ if (i2c_init_done == 0) {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+
+ int success = i2c_check_busy_flag();
+
+ if (success) {
+ success = i2c_start(device, I2C_Direction_Transmitter);
+ }
+
+ if (success) {
+ success = i2c_send(address);
+ }
+ // Don't do a STOP
+
+ if (success) {
+ success = i2c_read_nobuscheck(device, rxbuf, len);
+ }
+
+ return success;
+}
+
+
+int i2c_transaction_start()
+{
+ if (i2c_init_done == 0) {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+ return xSemaphoreTake(i2c_semaphore, portMAX_DELAY) == pdTRUE;
+}
+
+void i2c_transaction_end()
+{
+ if (i2c_init_done == 0) {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+
+ if (i2c_error) {
+ i2c_recover_from_lockup();
+
+ i2c_error = 0;
+ }
+
+ xSemaphoreGive(i2c_semaphore);
+}
+
diff --git a/src/temperature/i2c.h b/src/temperature/i2c.h
new file mode 100644
index 0000000..45a8966
--- /dev/null
+++ b/src/temperature/i2c.h
@@ -0,0 +1,53 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Matthias P. Braendli
+ *
+ * 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 __I2C_H_
+#define __I2C_H_
+
+#include <stdint.h>
+
+/* Initialise I2C on the board for both the audio codec and the barometric pressure sensor */
+void i2c_init(void);
+
+/* Do an I2C write, return 1 on success, 0 on failure */
+int i2c_write(uint8_t device, const uint8_t *txbuf, int len);
+
+/* Do an I2C read into rxbuf.
+ * Returns number of bytes received, or 0 in case of failure
+ */
+int i2c_read(uint8_t device, uint8_t *rxbuf, int len);
+
+/* Do an I2C write for the address, and then a read into rxbuf.
+ * Returns number of bytes received, or 0 in case of failure
+ */
+int i2c_read_from(uint8_t device, uint8_t address, uint8_t *rxbuf, int len);
+
+/* Start an I2C transaction, keeping exclusive access to I2C, returns 1 on success. */
+int i2c_transaction_start(void);
+
+/* End an I2C transaction, unlocking the exclusive access to I2C */
+void i2c_transaction_end(void);
+
+#endif // __I2C_H_
+
diff --git a/src/temperature/main.c b/src/temperature/main.c
index a4d9830..2ee9bc6 100644
--- a/src/temperature/main.c
+++ b/src/temperature/main.c
@@ -11,6 +11,8 @@
#include "semphr.h"
#include "temperature.h"
+#include "i2c.h"
+#include "bmp085.h"
#include "debug.h"
@@ -28,7 +30,6 @@ void init();
// Tasks
static void detect_button_press(void *pvParameters);
-static void update_temperature(void *pvParameters);
void vApplicationStackOverflowHook( TaskHandle_t xTask,
@@ -38,7 +39,10 @@ void vApplicationStackOverflowHook( TaskHandle_t xTask,
}
extern void initialise_monitor_handles(void);
-int main(void) {
+// Launcher task is here to make sure the scheduler is
+// already running when calling the init functions.
+static void launcher_task(void __attribute__ ((unused))*pvParameters)
+{
init();
xTaskCreate(
@@ -46,16 +50,28 @@ int main(void) {
"TaskButton",
4*configMINIMAL_STACK_SIZE,
(void*) NULL,
- tskIDLE_PRIORITY + 2UL,
+ tskIDLE_PRIORITY + 2UL,
NULL);
+ while (1) {
+ vTaskDelay(pdMS_TO_TICKS(1000));
+
+ GPIO_SetBits(GPIOD, GPIO_Pin_13);
+ temperature_update();
+ GPIO_ResetBits(GPIOD, GPIO_Pin_13);
+ taskYIELD();
+ }
+}
+
+int main(void) {
+ TaskHandle_t task_handle;
xTaskCreate(
- update_temperature,
- "TaskAudio",
- configMINIMAL_STACK_SIZE,
+ launcher_task,
+ "Launcher",
+ 2*configMINIMAL_STACK_SIZE,
(void*) NULL,
tskIDLE_PRIORITY + 2UL,
- NULL);
+ &task_handle);
/* Start the RTOS Scheduler */
vTaskStartScheduler();
@@ -64,12 +80,11 @@ int main(void) {
while(1);
}
-
static void detect_button_press(void *pvParameters)
{
GPIO_SetBits(GPIOD, GPIO_Pin_12);
- while (1) {
+ while (1) {
if (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)>0) {
while (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) > 0) {
@@ -84,6 +99,12 @@ static void detect_button_press(void *pvParameters)
// For debugging purposes only. snprinf has issues with %f
snprintf(t, 32, "%d.%02d", (int)temperature_get(), (int)(temperature_get() * 100.0 - (int)(temperature_get()) * 100.0));
debug_print(t);
+
+ int32_t pressure = 0;
+ int32_t temperature = 0;
+ int success = bmp085_get_temp_pressure(&temperature, &pressure);
+ snprintf(t, 32, " (%d) P=%ld, T=%ld", success, pressure, temperature);
+ debug_print(t);
debug_print("\n");
GPIO_ResetBits(GPIOD, GPIO_Pin_15);
@@ -97,19 +118,6 @@ static void detect_button_press(void *pvParameters)
}
}
-static void update_temperature(void *pvParameters)
-{
- while (1) {
- vTaskDelay(pdMS_TO_TICKS(1000));
-
- GPIO_SetBits(GPIOD, GPIO_Pin_13);
- temperature_update();
- GPIO_ResetBits(GPIOD, GPIO_Pin_13);
- taskYIELD();
- }
-}
-
-
void init() {
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
@@ -202,5 +210,15 @@ void init() {
// Enable ADC
ADC_Cmd(ADC1, ENABLE);
+ debug_print("Init ADC done\n");
+
+ // Enable I2C
+ i2c_init();
+ if (! bmp085_init() ) {
+ debug_print("Init BMP085 fail\n");
+ }
+ else {
+ debug_print("Init BMP085 ok\n");
+ }
}