diff --git a/Documentation/pycardium.rst b/Documentation/pycardium.rst index c51f7d9de3c733cea1767b4c8df8dc86bd34f4b7..f25c229d8c3ad1acbdb9dbac7ccb715d1a6a69e2 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 0000000000000000000000000000000000000000..77e5390a57c88edc97b0376e92444cf0d47a8ba1 --- /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 21ce07ec662863067b34d3a7dedd71e7842379ad..b3cb743303a25aff031a5872df836fe2543057cd 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 0000000000000000000000000000000000000000..b355a6f3dbdacf344db3c73c9f3b898941cb4421 --- /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 9f2d2c070b0978786fa00f1390f8d36788099427..cd4d7aaa60a022a89c4e43109e2acb8061c2ca87 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 67698112ed8be52f569fec2d4d087371bbe5cb91..371a0017ccd525990e0495fbf78acb3d49bccc13 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 0000000000000000000000000000000000000000..1c85ea4b4d0cd7ea959aca4beb776354b2304a80 --- /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 37d5082b7b7c00b14e11e28fd7a11ea2c64292b0..b0be6944f855d115a1efa4be0634279420c8d3eb 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 a6aafcb868d1b01dc1bd103015e3acb413225237..043340062eeeb078d220f32773104f1a7a04b427 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) /*