diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h index 87b24e8975dff763119aa4ffe6ce336e1cb75212..a1921400cc5962dec6674449d03ead467dac1255 100644 --- a/epicardium/epicardium.h +++ b/epicardium/epicardium.h @@ -106,6 +106,8 @@ typedef _Bool bool; #define API_PERSONAL_STATE_GET 0xc1 #define API_PERSONAL_STATE_IS_PERSISTENT 0xc2 +#define API_BME_GET_DATA 0xD0 + /* clang-format on */ typedef uint32_t api_int_id_t; @@ -662,6 +664,41 @@ API(API_LEDS_SET_GAMMA_TABLE, void epic_leds_set_gamma_table( */ API(API_LEDS_CLEAR_ALL, void epic_leds_clear_all(uint8_t r, uint8_t g, uint8_t b)); +/** + * BME680 + * ====== + */ + +/** + * BME680 Sensor Data + */ +struct bme_sensor_data { + /*! Temperature in degree celsius */ + float temperature; + /*! Pressure in Pascal */ + float pressure; + /*! Humidity in % relative humidity x1000 */ + float humidity; + /*! Gas resistance in Ohms */ + float gas_resistance; +}; + +/** + * Get the current BME680 data. + * + * :param data: Where to store the environmental data. + * :return: 0 on success or ``-Exxx`` on error. The following + * errors might occur: + * + * - ``-EFAULT``: On NULL-pointer. + * - ``-EINVAL``: Invalid configuration. + * - ``-EIO``: Communication with the device failed. + * - ``-ENODEV``: Device was not found. + */ +API(API_BME_GET_DATA, int epic_bme_get_data(struct bme_sensor_data *data)); + + + /** * Personal State * ============== diff --git a/epicardium/modules/bme680.c b/epicardium/modules/bme680.c new file mode 100644 index 0000000000000000000000000000000000000000..1d0b01d7caa60de97f119e810e8316c344dc6727 --- /dev/null +++ b/epicardium/modules/bme680.c @@ -0,0 +1,120 @@ +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> + +#include "bme680.h" +#include "bosch.h" +#include "card10.h" + +#include "epicardium.h" + +#define HEATR_DUR 2000 +#define N_MEAS 6 +#define LOW_TEMP 150 +#define HIGH_TEMP 350 + +static bool initialized; +static struct bme680_dev bme; + +static int convert_error(int8_t error) +{ + switch (error) { + case BME680_E_NULL_PTR: + return EFAULT; + case BME680_E_COM_FAIL: + return EIO; + case BME680_E_DEV_NOT_FOUND: + return ENODEV; + case BME680_E_INVALID_LENGTH: + return EINVAL; + default: + return 1; + } +} + +int epic_bme_get_data(struct bme_sensor_data *data) +{ + int8_t result = BME680_OK; + uint16_t settings_sel; + + if (__builtin_expect(!initialized, 0)) { + /* + bma.intf_ptr = NULL; + bma.delay_ms = card10_bosch_delay; + bma.dev_id = BMA400_I2C_ADDRESS_SDO_LOW; + bma.read = card10_bosch_i2c_read_ex; + bma.write = card10_bosch_i2c_write_ex; + bma.intf = BMA400_I2C_INTF; + */ + result = bme680_init(&bme); + if (result != BME680_OK) { + printf("bme680_init error: %d\n", result); + return -convert_error(result); + } + + /* Select the power mode */ + /* Must be set before writing the sensor configuration */ + bme.power_mode = BME680_FORCED_MODE; + + /* Set the temperature, pressure and humidity & filter settings */ + bme.tph_sett.os_hum = BME680_OS_1X; + bme.tph_sett.os_pres = BME680_OS_16X; + bme.tph_sett.os_temp = BME680_OS_2X; + + /* Set the remaining gas sensor settings and link the heating profile */ + bme.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS; + bme.gas_sett.heatr_dur = HEATR_DUR; + + settings_sel = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_SENSOR_SEL; + + initialized = true; + } + + struct bme680_field_data raw_data[N_MEAS]; + + uint16_t profile_dur = 0; + bme680_get_profile_dur(&profile_dur, &bme); + + uint8_t i = 0; + while ((result == BME680_OK) && (i < N_MEAS)) { + if (result == BME680_OK) { + + if (i % 2 == 0) + bme.gas_sett.heatr_temp = HIGH_TEMP; /* Higher temperature */ + else + bme.gas_sett.heatr_temp = LOW_TEMP; /* Lower temperature */ + + result = bme680_set_sensor_settings(settings_sel, &bme); + if (result != BME680_OK) { + printf("bme680_set_sensor_settings error: %d\n", result); + return -convert_error(result); + } + + if (result == BME680_OK) { + + result = bme680_set_sensor_mode(&bme); /* Trigger a measurement */ + if (result != BME680_OK) { + printf("bme680_set_sensor_mode error: %d\n", result); + return -convert_error(result); + } + + bme.delay_ms(profile_dur); /* Wait for the measurement to complete */ + + result = bme680_get_sensor_data(&raw_data[i], &bme); + if (result != BME680_OK) { + printf("bme680_get_sensor_data error: %d\n", result); + return -convert_error(result); + } + } + } + + i++; + } + + data->temperature = raw_data[0].temperature; + data->humidity = raw_data[0].humidity; + data->pressure = raw_data[0].pressure; + data->gas_resistance = raw_data[0].gas_resistance; + + return 0; +} diff --git a/epicardium/modules/meson.build b/epicardium/modules/meson.build index 5b4199b1739de26ef4a633397e0aa80dabd42c5d..dc2318359ecafaae8b78566b4ec87ecf891af44b 100644 --- a/epicardium/modules/meson.build +++ b/epicardium/modules/meson.build @@ -1,4 +1,5 @@ module_sources = files( + 'bme680.c', 'buttons.c', 'dispatcher.c', 'display.c', diff --git a/pycardium/meson.build b/pycardium/meson.build index 40fabde700ce03eff4d117b7e5e87c024b5f35f5..f0a3798a6ab5ef5538673a98f6de9748e705f3b7 100644 --- a/pycardium/meson.build +++ b/pycardium/meson.build @@ -13,6 +13,7 @@ modsrc = files( 'modules/sys_display.c', 'modules/utime.c', 'modules/vibra.c', + 'modules/bme680.c' ) ################################# diff --git a/pycardium/modules/bme680.c b/pycardium/modules/bme680.c new file mode 100644 index 0000000000000000000000000000000000000000..3c781f353c3a78577b700eccbfb32eccdba5b55f --- /dev/null +++ b/pycardium/modules/bme680.c @@ -0,0 +1,37 @@ +#include "py/obj.h" +#include "py/objlist.h" +#include "py/runtime.h" + +#include "epicardium.h" + +static mp_obj_t mp_bme_get_data() +{ + struct bme_sensor_data data; + int ret = epic_bme_get_data(&data); + + if (ret < 0) { + mp_raise_OSError(-ret); + } + + mp_obj_t values_list[] = { + mp_obj_new_float(data.temperature), + mp_obj_new_float(data.humidity), + mp_obj_new_float(data.pressure), + }; + return mp_obj_new_tuple(3, values_list); +} +static MP_DEFINE_CONST_FUN_OBJ_0(bme_get_bme_data_obj, mp_bme_get_data); + +static const mp_rom_map_elem_t bme_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bme680) }, + { MP_ROM_QSTR(MP_QSTR_get_bme_data), MP_ROM_PTR(&bme_get_bme_data_obj) }, +}; +static MP_DEFINE_CONST_DICT(bme_module_globals, bme_module_globals_table); + +const mp_obj_module_t bme_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&bme_module_globals, +}; + +/* Register the module to make it available in Python */ +MP_REGISTER_MODULE(MP_QSTR_bme680, bme_module, MODULE_BME_ENABLED); \ No newline at end of file diff --git a/pycardium/modules/qstrdefs.h b/pycardium/modules/qstrdefs.h index 9e3f3979af79ebbfb16f821b7127424cadb563ff..46e9cf54536737f6cfe3c07c65f6624d2f7e00dd 100644 --- a/pycardium/modules/qstrdefs.h +++ b/pycardium/modules/qstrdefs.h @@ -74,6 +74,10 @@ Q(start) Q(get_reading) Q(stop) +/* bme680 */ +Q(bme680) +Q(get_bme_data) + /* file */ Q(__del__) Q(__enter__) diff --git a/pycardium/mpconfigport.h b/pycardium/mpconfigport.h index a1c88a7476f0b63111a4e6049aaac33f32b7fa0c..db2000b3b9c009f0d5b12beb7deec0090bb28c8b 100644 --- a/pycardium/mpconfigport.h +++ b/pycardium/mpconfigport.h @@ -55,6 +55,7 @@ int mp_hal_trng_read_int(void); #define MODULE_PERSONAL_STATE_ENABLED (1) #define MODULE_UTIME_ENABLED (1) #define MODULE_VIBRA_ENABLED (1) +#define MODULE_BME680_ENABLED (1) /* * This port is intended to be 32-bit, but unfortunately, int32_t for