From c00d22498f945ed0f8d2dcaa9fffbaf96342ccda Mon Sep 17 00:00:00 2001 From: Rahix <rahix@rahix.de> Date: Sat, 6 Jul 2019 23:26:06 +0200 Subject: [PATCH] feat(bma400): Add basic API and pycardium module Signed-off-by: Rahix <rahix@rahix.de> --- Documentation/pycardium.rst | 1 + Documentation/pycardium/bma400.rst | 8 +++ epicardium/epicardium.h | 33 +++++++++++ epicardium/modules/bma400.c | 93 ++++++++++++++++++++++++++++++ epicardium/modules/meson.build | 1 + pycardium/meson.build | 1 + pycardium/modules/bma400.c | 37 ++++++++++++ pycardium/modules/qstrdefs.h | 4 ++ pycardium/mpconfigport.h | 1 + 9 files changed, 179 insertions(+) create mode 100644 Documentation/pycardium/bma400.rst create mode 100644 epicardium/modules/bma400.c create mode 100644 pycardium/modules/bma400.c diff --git a/Documentation/pycardium.rst b/Documentation/pycardium.rst index c51f7d9d..f25c229d 100644 --- a/Documentation/pycardium.rst +++ b/Documentation/pycardium.rst @@ -9,5 +9,6 @@ These modules are documented in this section. :maxdepth: 1 :caption: Modules: + pycardium/bma400 pycardium/color pycardium/leds diff --git a/Documentation/pycardium/bma400.rst b/Documentation/pycardium/bma400.rst new file mode 100644 index 00000000..77e5390a --- /dev/null +++ b/Documentation/pycardium/bma400.rst @@ -0,0 +1,8 @@ +``bma400`` - Accelerometer +========================== + +.. py:function:: bma400.get_accel() + + Get acceleration vector. + + :return: Tuple containing ``x``, ``y``, and ``z`` acceleration. diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h index 21ce07ec..b3cb7433 100644 --- a/epicardium/epicardium.h +++ b/epicardium/epicardium.h @@ -1,6 +1,7 @@ #ifndef _EPICARDIUM_H #define _EPICARDIUM_H #include <stdint.h> +#include <errno.h> #ifndef API #define API(id, def) def @@ -11,6 +12,7 @@ #define API_UART_READ 0x2 #define API_LEDS_SET 0x3 #define API_VIBRA_SET 0x4 +#define API_BMA_GET_ACCEL 0x5 /* clang-format on */ /** @@ -66,4 +68,35 @@ API(API_LEDS_SET, void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b)); */ API(API_VIBRA_SET, void epic_vibra_set(int status)); +/** + * BMA400 + * ====== + */ + +/** + * An acceleration vector. + */ +struct acceleration { + /** Acceleration component along x axis. */ + float x; + /** Acceleration component along y axis. */ + float y; + /** Acceleration component along z axis. */ + float z; +}; + +/** + * Get the current acceleration vector. + * + * :param data: Where to store the acceleration vector. + * :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_BMA_GET_ACCEL, int epic_bma_get_accel(struct acceleration *data)); + #endif /* _EPICARDIUM_H */ diff --git a/epicardium/modules/bma400.c b/epicardium/modules/bma400.c new file mode 100644 index 00000000..b355a6f3 --- /dev/null +++ b/epicardium/modules/bma400.c @@ -0,0 +1,93 @@ +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> + +#include "bma400.h" +#include "bosch.h" +#include "card10.h" + +#include "epicardium.h" + +static bool initialized; +static struct bma400_dev bma; + +#define GRAVITY_EARTH (9.80665f) /* Earth's gravity in m/s^2 */ +static float lsb_to_ms2(int16_t val, float g_range, uint8_t bit_width) +{ + float half_scale = (float)(1 << bit_width) / 2.0f; + return GRAVITY_EARTH * val * g_range / half_scale; +} + +static int convert_error(int8_t error) +{ + switch (error) { + case BMA400_E_NULL_PTR: + return EFAULT; + case BMA400_E_COM_FAIL: + return EIO; + case BMA400_E_DEV_NOT_FOUND: + return ENODEV; + case BMA400_E_INVALID_CONFIG: + return EINVAL; + default: + return 1; + } +} + +int epic_bma_get_accel(struct acceleration *data) +{ + uint8_t result; + + 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 = bma400_init(&bma); + if (result != BMA400_OK) { + printf("bma400_init error: %d\n", result); + return -convert_error(result); + } + + struct bma400_sensor_conf conf; + result = bma400_get_sensor_conf(&conf, 1, &bma); + if (result != BMA400_OK) { + printf("bma400_get_sensor_conf error: %d\n", result); + return -convert_error(result); + } + + conf.param.accel.odr = BMA400_ODR_100HZ; + conf.param.accel.range = BMA400_2G_RANGE; + conf.param.accel.data_src = BMA400_DATA_SRC_ACCEL_FILT_1; + + result = bma400_set_sensor_conf(&conf, 1, &bma); + if (result != BMA400_OK) { + printf("bma400_set_sensor_conf error: %d\n", result); + return -convert_error(result); + } + + result = bma400_set_power_mode(BMA400_LOW_POWER_MODE, &bma); + if (result != BMA400_OK) { + printf("bma400_set_power_mode error: %d\n", result); + return -convert_error(result); + } + + initialized = true; + } + + struct bma400_sensor_data data_in; + result = bma400_get_accel_data(BMA400_DATA_SENSOR_TIME, &data_in, &bma); + if (result != BMA400_OK) { + printf("bma400_get_accel_data error: %d\n", result); + return -convert_error(result); + } + + data->x = lsb_to_ms2(data_in.x, 2, 12); + data->y = lsb_to_ms2(data_in.y, 2, 12); + data->z = lsb_to_ms2(data_in.z, 2, 12); + + return 0; +} diff --git a/epicardium/modules/meson.build b/epicardium/modules/meson.build index 9f2d2c07..cd4d7aaa 100644 --- a/epicardium/modules/meson.build +++ b/epicardium/modules/meson.build @@ -1,4 +1,5 @@ module_sources = files( + 'bma400.c', 'leds.c', 'pmic.c', 'serial.c', diff --git a/pycardium/meson.build b/pycardium/meson.build index 67698112..371a0017 100644 --- a/pycardium/meson.build +++ b/pycardium/meson.build @@ -2,6 +2,7 @@ name = 'pycardium' modsrc = files( 'modules/utime.c', + 'modules/bma400.c', 'modules/leds.c', 'modules/vibra.c', ) diff --git a/pycardium/modules/bma400.c b/pycardium/modules/bma400.c new file mode 100644 index 00000000..1c85ea4b --- /dev/null +++ b/pycardium/modules/bma400.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_bma_get_accel() +{ + struct acceleration values; + int ret = epic_bma_get_accel(&values); + + if (ret < 0) { + mp_raise_OSError(-ret); + } + + mp_obj_t values_list[] = { + mp_obj_new_float(values.x), + mp_obj_new_float(values.y), + mp_obj_new_float(values.z), + }; + return mp_obj_new_tuple(3, values_list); +} +static MP_DEFINE_CONST_FUN_OBJ_0(bma_get_accel_obj, mp_bma_get_accel); + +static const mp_rom_map_elem_t bma_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bma400) }, + { MP_ROM_QSTR(MP_QSTR_get_accel), MP_ROM_PTR(&bma_get_accel_obj) }, +}; +static MP_DEFINE_CONST_DICT(bma_module_globals, bma_module_globals_table); + +const mp_obj_module_t bma_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&bma_module_globals, +}; + +/* Register the module to make it available in Python */ +MP_REGISTER_MODULE(MP_QSTR_bma400, bma_module, MODULE_BMA_ENABLED); diff --git a/pycardium/modules/qstrdefs.h b/pycardium/modules/qstrdefs.h index 37d5082b..b0be6944 100644 --- a/pycardium/modules/qstrdefs.h +++ b/pycardium/modules/qstrdefs.h @@ -4,6 +4,10 @@ #define Q(x) #endif +/* bma400 */ +Q(bma400) +Q(get_accel) + /* leds */ Q(leds) Q(BOTTOM_LEFT) diff --git a/pycardium/mpconfigport.h b/pycardium/mpconfigport.h index a6aafcb8..04334006 100644 --- a/pycardium/mpconfigport.h +++ b/pycardium/mpconfigport.h @@ -36,6 +36,7 @@ /* Modules */ #define MODULE_UTIME_ENABLED (1) #define MODULE_LEDS_ENABLED (1) +#define MODULE_BMA_ENABLED (1) #define MODULE_VIBRA_ENABLED (1) /* -- GitLab