diff options
Diffstat (limited to 'src/temperature')
-rw-r--r-- | src/temperature/bmp085.c | 245 | ||||
-rw-r--r-- | src/temperature/bmp085.h | 81 | ||||
-rw-r--r-- | src/temperature/i2c.c | 334 | ||||
-rw-r--r-- | src/temperature/i2c.h | 53 | ||||
-rw-r--r-- | src/temperature/main.c | 62 |
5 files changed, 753 insertions, 22 deletions
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"); + } } |