Commit 866e3788 authored by chris007's avatar chris007 Committed by Rahix
Browse files

feat(bme680): Add bme680 support

Integrated the BME680 Sensor as Python module.  Performs a single read of
temperature (°C), humidity (% r.h.), air pressure (hPa) and gas resistance
(Ohm).
parent 6e712c77
``bme680`` - 4-in-1 Sensor
==========================
.. py:function:: bme680.init()
Before being able to read data from the sensor, you have to call init().
.. py:function:: bme680.get_data()
Does a single measurement to get environmental data.
:return: Tuple containing ``temperature`` (°C), ``humidity`` (% r.h.),
``pressure`` (hPa) and ``gas resistance`` (Ohm).
.. py:function:: bme680.deinit()
De-Initializes the sensor.
\ No newline at end of file
......@@ -107,6 +107,10 @@ typedef _Bool bool;
#define API_PERSONAL_STATE_GET 0xc1
#define API_PERSONAL_STATE_IS_PERSISTENT 0xc2
#define API_BME680_INIT 0xD0
#define API_BME680_DEINIT 0xD1
#define API_BME680_GET_DATA 0xD2
/* clang-format on */
typedef uint32_t api_int_id_t;
......@@ -673,6 +677,66 @@ 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 bme680_sensor_data {
/** Temperature in degree celsius */
float temperature;
/** Humidity in % relative humidity */
float humidity;
/** Pressure in hPa */
float pressure;
/** Gas resistance in Ohms */
float gas_resistance;
};
/**
* Initialize the BM680 sensor.
*
* :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_BME680_INIT, int epic_bme680_init());
/**
* De-Initialize the BM680 sensor.
*
* :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_BME680_DEINIT, int epic_bme680_deinit());
/**
* 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``: Sensor not initialized.
* - ``-EIO``: Communication with the device failed.
* - ``-ENODEV``: Device was not found.
*/
API(API_BME680_GET_DATA,
int epic_bme680_read_sensors(struct bme680_sensor_data *data));
/**
* Personal State
* ==============
......
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include "bme680.h"
#include "bosch.h"
#include "card10.h"
#include "epicardium.h"
#include "modules.h"
#include "modules/log.h"
#define HEATR_TEMP 320
#define HEATR_DUR 150
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_bme680_init()
{
int8_t result = BME680_OK;
if (__builtin_expect(!initialized, 0)) {
bme.dev_id = BME680_I2C_ADDR_PRIMARY;
bme.intf = BME680_I2C_INTF;
bme.read = card10_bosch_i2c_read;
bme.write = card10_bosch_i2c_write;
bme.delay_ms = card10_bosch_delay;
/* amb_temp can be set to 25 prior to configuring the gas sensor
* or by performing a few temperature readings without operating the gas sensor.
*/
bme.amb_temp = 25;
result = bme680_init(&bme);
if (result != BME680_OK) {
LOG_ERR("bme680", "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 settings */
bme.tph_sett.os_hum = BME680_OS_2X;
bme.tph_sett.os_pres = BME680_OS_4X;
bme.tph_sett.os_temp = BME680_OS_8X;
bme.tph_sett.filter = BME680_FILTER_SIZE_3;
/* Set the remaining gas sensor settings and link the heating profile */
bme.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS;
/* Create a ramp heat waveform in 3 steps */
bme.gas_sett.heatr_temp = HEATR_TEMP; /* degree Celsius */
bme.gas_sett.heatr_dur = HEATR_DUR; /* milliseconds */
/* Set the required sensor settings needed */
uint16_t settings_sel = BME680_OST_SEL | BME680_OSP_SEL |
BME680_OSH_SEL | BME680_FILTER_SEL |
BME680_GAS_SENSOR_SEL;
result = bme680_set_sensor_settings(settings_sel, &bme);
if (result != BME680_OK) {
LOG_ERR("bme680",
"bme680_set_sensor_settings error: %d\n",
result);
return -convert_error(result);
}
initialized = true;
}
return 0;
}
int epic_bme680_deinit()
{
int8_t result = BME680_OK;
result = bme680_soft_reset(&bme);
if (result != BME680_OK) {
LOG_ERR("bme680", "bme680_soft_reset error: %d\n", result);
return -convert_error(result);
}
initialized = false;
return 0;
}
int epic_bme680_read_sensors(struct bme680_sensor_data *data)
{
int8_t result = BME680_OK;
if (!initialized) {
LOG_ERR("bme680", "bme680 sensor not initialized");
return -EINVAL;
}
uint16_t profile_dur = 0;
bme680_get_profile_dur(&profile_dur, &bme);
result = bme680_set_sensor_mode(&bme); /* Trigger a measurement */
if (result != BME680_OK) {
LOG_ERR("bme680", "bme680_set_sensor_mode error: %d\n", result);
return -convert_error(result);
}
vTaskDelay(pdMS_TO_TICKS(
profile_dur)); /* Wait for the measurement to complete */
struct bme680_field_data raw_data;
result = bme680_get_sensor_data(&raw_data, &bme);
if (result != BME680_OK) {
LOG_ERR("bme680", "bme680_get_sensor_data error: %d\n", result);
return -convert_error(result);
}
data->temperature = raw_data.temperature / 100.0l;
data->humidity = raw_data.humidity / 1000.0l;
data->pressure = raw_data.pressure / 100.0l;
data->gas_resistance = raw_data.gas_resistance;
return 0;
}
......@@ -231,5 +231,10 @@ int hardware_reset(void)
*/
display_init_slim();
/*
* BME680 Sensor
*/
epic_bme680_deinit();
return 0;
}
module_sources = files(
'bme680.c',
'buttons.c',
'dispatcher.c',
'display.c',
......
......@@ -13,6 +13,7 @@ modsrc = files(
'modules/sys_display.c',
'modules/utime.c',
'modules/vibra.c',
'modules/bme680.c'
)
#################################
......
#include "py/obj.h"
#include "py/objlist.h"
#include "py/runtime.h"
#include "epicardium.h"
static mp_obj_t mp_bme680_init()
{
int ret = epic_bme680_init();
if (ret < 0) {
mp_raise_OSError(-ret);
}
return 0;
}
static MP_DEFINE_CONST_FUN_OBJ_0(bme680_init_obj, mp_bme680_init);
static mp_obj_t mp_bme680_deinit()
{
int ret = epic_bme680_deinit();
if (ret < 0) {
mp_raise_OSError(-ret);
}
return 0;
}
static MP_DEFINE_CONST_FUN_OBJ_0(bme680_deinit_obj, mp_bme680_deinit);
static mp_obj_t mp_bme680_get_data()
{
struct bme680_sensor_data data;
int ret = epic_bme680_read_sensors(&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),
mp_obj_new_float(data.gas_resistance) };
return mp_obj_new_tuple(4, values_list);
}
static MP_DEFINE_CONST_FUN_OBJ_0(bme680_get_data_obj, mp_bme680_get_data);
static const mp_rom_map_elem_t bme680_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bme680) },
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&bme680_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bme680_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_data), MP_ROM_PTR(&bme680_get_data_obj) },
};
static MP_DEFINE_CONST_DICT(bme680_module_globals, bme680_module_globals_table);
const mp_obj_module_t bme680_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&bme680_module_globals,
};
/* Register the module to make it available in Python */
MP_REGISTER_MODULE(MP_QSTR_bme680, bme680_module, MODULE_BME680_ENABLED);
......@@ -76,6 +76,12 @@ Q(start)
Q(get_reading)
Q(stop)
/* bme680 */
Q(bme680)
Q(init)
Q(deinit)
Q(get_data)
/* file */
Q(__del__)
Q(__enter__)
......
......@@ -45,6 +45,7 @@ int mp_hal_trng_read_int(void);
#define MICROPY_PY_UERRNO (1)
/* Modules */
#define MODULE_BME680_ENABLED (1)
#define MODULE_BUTTONS_ENABLED (1)
#define MODULE_DISPLAY_ENABLED (1)
#define MODULE_GPIO_ENABLED (1)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment