diff --git a/components/st3m/st3m_imu.c b/components/st3m/st3m_imu.c index 7ae2ad8b..db9f85b4 100644 --- a/components/st3m/st3m_imu.c +++ b/components/st3m/st3m_imu.c @@ -70,19 +70,15 @@ int st3m_imu_write(uint8_t reg_addr, uint8_t *reg_data, uint8_t len) { return bmi2_i2c_write(reg_addr, reg_data, len, &_imu ); } -void st3m_imu_task(void *data) { - TickType_t last_wake = xTaskGetTickCount(); +void st3m_imu_task(void) { + esp_err_t ret; float a, b, c, temperature; uint32_t steps; - while (1) { - vTaskDelayUntil(&last_wake, pdMS_TO_TICKS(10)); // 100 Hz - - ret = flow3r_bsp_imu_update(&_imu); - if (ret != ESP_OK) { - continue; - } + ret = flow3r_bsp_imu_update(&_imu); + if (ret == ESP_OK) + { LOCK; ret = flow3r_bsp_imu_read_acc_mps(&_imu, &a, &b, &c); if (ret == ESP_OK) { diff --git a/components/st3m/st3m_imu.h b/components/st3m/st3m_imu.h index e0dd69d7..c625dd5b 100644 --- a/components/st3m/st3m_imu.h +++ b/components/st3m/st3m_imu.h @@ -7,7 +7,7 @@ esp_err_t st3m_imu_init(void); -extern void st3m_imu_task(void *data); +extern void st3m_imu_task(void); extern void st3m_imu_read_acc_mps(float *x, float *y, float *z); extern void st3m_imu_read_gyro_dps(float *x, float *y, float *z); extern void st3m_imu_read_pressure(float *pressure, float *temperature); diff --git a/drivers/micropython.cmake b/drivers/micropython.cmake index d8ddc7fa..bd571b40 100644 --- a/drivers/micropython.cmake +++ b/drivers/micropython.cmake @@ -27,5 +27,8 @@ include(${CMAKE_CURRENT_LIST_DIR}/tildagon_pin/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/tildagon/micropython.cmake) +# Add frontboard drivers +include(${CMAKE_CURRENT_LIST_DIR}/tildagon_frontboard/micropython.cmake) + # Add burnt-in HMAC include(${CMAKE_CURRENT_LIST_DIR}/tildagon_hmac/micropython.cmake) diff --git a/drivers/tildagon_frontboard/cy8cmbrx/cy8cmbrx.c b/drivers/tildagon_frontboard/cy8cmbrx/cy8cmbrx.c new file mode 100644 index 00000000..244ce0b1 --- /dev/null +++ b/drivers/tildagon_frontboard/cy8cmbrx/cy8cmbrx.c @@ -0,0 +1,93 @@ +#include "tildagon_i2c_mpless.h" +#include "cy8cmbrx.h" +#include + + +#define READ ( MP_MACHINE_I2C_FLAG_WRITE1 | MP_MACHINE_I2C_FLAG_READ | MP_MACHINE_I2C_FLAG_STOP ) +#define WRITE MP_MACHINE_I2C_FLAG_STOP + +tildagon_mux_i2c_obj_t* cy8_mux_port; +uint16_t button_prev_status = 0U; +uint16_t prox_prev_status = 0U; + +void send_command( uint8_t cmd ); +static int write_bytes( tildagon_mux_i2c_obj_t* mux_port, uint8_t reg_adr, uint8_t* data, uint8_t length ); + +void cy8cmbrx_init( tildagon_mux_i2c_obj_t* new_port ) +{ + cy8_mux_port = new_port; +} + +cy8cmbrx_status_t cy8cmbrx_run( void ) +{ + cy8cmbrx_status_t result = {0}; + /* read touch and prox current and latched status */ + uint8_t raw_buf[6] = { 0U }; + /* check we have the device present */ + if( tildagon_i2c_reg_read(TILDAGON_TOP_I2C_PORT, CY8CMBRX_ADDRESS, CY8CMBRX_BUTTON_STAT_ADR, raw_buf, 6) == ESP_OK ) + { + uint16_t button_state = ((uint16_t)raw_buf[1] << 8) + raw_buf[0]; + uint16_t button_latch = ((uint16_t)raw_buf[3] << 8) + raw_buf[2]; + uint8_t prox_state = raw_buf[4]; + uint8_t prox_latch = raw_buf[5]; + /* button detection */ + for( uint8_t i = 3U; i < 15U; i++ ) + { + if ( ( button_latch & ( 1 << i ) ) && ( ( button_prev_status & ( 1 << i ) ) == 0U ) ) + { + if ( ( button_state & ( 1 << i ) ) == 0U ) + { + result.buttons[i-3] = CY8CMBRX_PULSE; + } + else + { + result.buttons[i-3] = CY8CMBRX_RISING_EDGE; + } + } + else if ( ( button_prev_status & ( 1 << i ) ) && ( ( button_state & ( 1 << i ) ) == 0 ) ) + { + result.buttons[i-3] = CY8CMBRX_FALLING_EDGE; + } + } + button_prev_status = button_state; + /* prox detection */ + for( uint8_t i = 0U; i < 2U; i++ ) + { + if ( ( prox_latch & ( 1 << i ) ) && ( ( prox_prev_status & ( 1 << i ) ) == 0U ) ) + { + if ( ( prox_state & ( 1 << i ) ) == 0U ) + { + result.prox[i] = CY8CMBRX_PULSE; + } + else + { + result.prox[i] = CY8CMBRX_RISING_EDGE; + } + } + else if ( ( prox_prev_status & ( 1 << i ) ) && ( ( prox_state & ( 1 << i ) ) == 0 ) ) + { + result.prox[i] = CY8CMBRX_FALLING_EDGE; + } + } + prox_prev_status = prox_state; + } + /* reset latch status */ + uint8_t cmd = CY8CMBRX_CMD_RESET_LATCH; + write_bytes( cy8_mux_port, CY8CMBRX_CTRL_CMD_ADR, &cmd, 1 ); + return result; +} + + +int write_bytes( tildagon_mux_i2c_obj_t* mux_port, uint8_t reg_adr, uint8_t* data, uint8_t length ) +{ + uint8_t i2c_buffer[length+1]; + i2c_buffer[0] = reg_adr; + for ( uint8_t i = 0; i < length; i++) + { + i2c_buffer[i+1] = data[i]; + } + mp_machine_i2c_buf_t buffer[2] = { { .len = 1, .buf = ®_adr }, + { .len = length + 1, .buf = i2c_buffer } }; + tildagon_mux_i2c_transaction( mux_port, CY8CMBRX_ADDRESS, 1, &buffer[0], WRITE ); + return tildagon_mux_i2c_transaction( mux_port, CY8CMBRX_ADDRESS, 1, &buffer[1], WRITE ); +} diff --git a/drivers/tildagon_frontboard/cy8cmbrx/cy8cmbrx.h b/drivers/tildagon_frontboard/cy8cmbrx/cy8cmbrx.h new file mode 100644 index 00000000..8f0cc82e --- /dev/null +++ b/drivers/tildagon_frontboard/cy8cmbrx/cy8cmbrx.h @@ -0,0 +1,43 @@ +#ifndef CY8CMBRX_H +#define CY8CMBRX_H + + +#include "tildagon_i2c.h" + +#define CY8CMBRX_ADDRESS 0x37U +#define CY8CMBRX_BUTTON_STAT_ADR 0xAAU +#define CY8CMBRX_CTRL_CMD_ADR 0x86U + +#define CY8CMBRX_CMD_CMP_CRC_SAVE 0x02U +#define CY8CMBRX_CMD_CALC_CRC 0x03U +#define CY8CMBRX_CMD_LOW_POWER 0x07U +#define CY8CMBRX_CMD_RESET_LATCH 0x08U +#define CY8CMBRX_CMD_RESET_PS0_FILTER 0x09U +#define CY8CMBRX_CMD_RESET_PS1_FILTER 0x0AU +#define CY8CMBRX_CMD_RESET 0xFFU + +#define CY8CMBRX_CMD_ERR_OK 0x00U +#define CY8CMBRX_CMD_ERR_SAVE_FAILED 0x0DU +#define CY8CMBRX_CMD_ERR_CRC_MISMATCH 0xFEU +#define CY8CMBRX_CMD_ERR_INVALID_CMD 0xFFU + +typedef enum +{ + CY8CMBRX_NO_CHANGE, + CY8CMBRX_RISING_EDGE, + CY8CMBRX_FALLING_EDGE, + CY8CMBRX_PULSE +} cy8cmbrx_event_t; + +typedef struct +{ + cy8cmbrx_event_t buttons[16]; + cy8cmbrx_event_t prox[2]; +} cy8cmbrx_status_t; + + +extern void cy8cmbrx_init( tildagon_mux_i2c_obj_t* mux_port); +extern cy8cmbrx_status_t cy8cmbrx_run( void ); +extern void cy8cmbrx_read_differences( uint16_t buffer[16] ); + +#endif diff --git a/drivers/tildagon_frontboard/micropython.cmake b/drivers/tildagon_frontboard/micropython.cmake new file mode 100644 index 00000000..8f30f821 --- /dev/null +++ b/drivers/tildagon_frontboard/micropython.cmake @@ -0,0 +1,21 @@ +# Create an INTERFACE library for our C module. +add_library(usermod_tildagon_frontboard INTERFACE) + + +# Add our source files to the lib +target_sources(usermod_tildagon_frontboard INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/tildagon_frontboard.c + ${CMAKE_CURRENT_LIST_DIR}/cy8cmbrx/cy8cmbrx.c + ${CMAKE_CURRENT_LIST_DIR}/mp_frontboard.c +) + +# Add the current directory as an include directory. +target_include_directories(usermod_tildagon_frontboard INTERFACE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/cy8cmbrx + ${CMAKE_CURRENT_LIST_DIR}/../tildagon_imu/qmc6309 + ${CMAKE_CURRENT_LIST_DIR}/../tildagon_imu +) + +# Link our INTERFACE library to the usermod target. +target_link_libraries(usermod INTERFACE usermod_tildagon_frontboard) \ No newline at end of file diff --git a/drivers/tildagon_frontboard/mp_frontboard.c b/drivers/tildagon_frontboard/mp_frontboard.c new file mode 100644 index 00000000..a5c3ab37 --- /dev/null +++ b/drivers/tildagon_frontboard/mp_frontboard.c @@ -0,0 +1,92 @@ + +#include "py/runtime.h" +#include "py/obj.h" +#include "py/builtin.h" +#include "mp_frontboard.h" +#include "tildagon_frontboard.h" +#include "cy8cmbrx.h" + +/** + * @brief schedule the micropython callback for the event + */ +void mp_frontboard2026_push_event( uint8_t event, uint8_t trigger ) +{ + if ( MP_STATE_PORT(callbacks)[event+(trigger*MP_FB_EVENT_MAX)] != NULL ) + { + mp_sched_schedule(MP_STATE_PORT(callbacks)[event+(trigger*MP_FB_EVENT_MAX)], mp_obj_new_int(event) ); + } +} + +/** + * @brief initialise the frontboard, setting up touch and + * proximity and creating the additinal port expander + */ +static mp_obj_t mp_frontboard2026_init( mp_obj_t frontboard_id ) +{ + uint16_t id = mp_obj_get_int( frontboard_id ); + tildagon_frontboard_init(id); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(mp_frontboard2026_init_obj, mp_frontboard2026_init); + + +/** + * @brief set the callback for both rising and falling + * edge of each proximity and touch event + */ +static mp_obj_t mp_frontboard2026_set_cb( mp_obj_t index, mp_obj_t cb, mp_obj_t trigger) +{ + uint8_t i = mp_obj_get_int( index ); + uint8_t trigger_type = mp_obj_get_int(trigger); + if ( i < MP_FB_EVENT_MAX ) + { + MP_STATE_PORT(callbacks)[i+(trigger_type*MP_FB_EVENT_MAX)] = cb; + return mp_const_none; + } + return mp_obj_new_int(-1); +} +static MP_DEFINE_CONST_FUN_OBJ_3(mp_frontboard2026_set_cb_obj, mp_frontboard2026_set_cb); + +static mp_obj_t mp_frontboard2026_run( void ) +{ + cy8cmbrx_cb(NULL, 0); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_0(mp_frontboard2026_run_obj, mp_frontboard2026_run); + +static const mp_rom_map_elem_t frontboard2026_globals_table[] = +{ + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_frontboard2026) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&mp_frontboard2026_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_cb), MP_ROM_PTR(&mp_frontboard2026_set_cb_obj) }, + { MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&mp_frontboard2026_run_obj) }, + + { MP_ROM_QSTR(MP_QSTR_TOUCH1), MP_ROM_INT(MP_TOUCH_EVENT_11) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH2), MP_ROM_INT(MP_TOUCH_EVENT_12) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH3), MP_ROM_INT(MP_TOUCH_EVENT_10) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH4), MP_ROM_INT(MP_TOUCH_EVENT_9) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH5), MP_ROM_INT(MP_TOUCH_EVENT_8) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH6), MP_ROM_INT(MP_TOUCH_EVENT_7) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH7), MP_ROM_INT(MP_TOUCH_EVENT_6) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH8), MP_ROM_INT(MP_TOUCH_EVENT_5) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH9), MP_ROM_INT(MP_TOUCH_EVENT_4) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH10), MP_ROM_INT(MP_TOUCH_EVENT_3) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH11), MP_ROM_INT(MP_TOUCH_EVENT_2) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH12), MP_ROM_INT(MP_TOUCH_EVENT_1) }, + { MP_ROM_QSTR(MP_QSTR_PROX1), MP_ROM_INT(MP_PROX_EVENT_1) }, + { MP_ROM_QSTR(MP_QSTR_PROX2), MP_ROM_INT(MP_PROX_EVENT_2) }, + + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(1) }, +}; + +static MP_DEFINE_CONST_DICT(frontboard2026_globals, frontboard2026_globals_table); + +const mp_obj_module_t mp_frontboard2026_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&frontboard2026_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_frontboard2026, mp_frontboard2026_cmodule); + +MP_REGISTER_ROOT_POINTER(mp_obj_t callbacks[MP_FB_EVENT_MAX*2]); diff --git a/drivers/tildagon_frontboard/mp_frontboard.h b/drivers/tildagon_frontboard/mp_frontboard.h new file mode 100644 index 00000000..3a33c11a --- /dev/null +++ b/drivers/tildagon_frontboard/mp_frontboard.h @@ -0,0 +1,28 @@ + +#ifndef MP_FRONTBOARD_H +#define MP_FRONTBOARD_H + +#include + +#define MP_TOUCH_EVENT_1 0 +#define MP_TOUCH_EVENT_2 1 +#define MP_TOUCH_EVENT_3 2 +#define MP_TOUCH_EVENT_4 3 +#define MP_TOUCH_EVENT_5 4 +#define MP_TOUCH_EVENT_6 5 +#define MP_TOUCH_EVENT_7 6 +#define MP_TOUCH_EVENT_8 7 +#define MP_TOUCH_EVENT_9 8 +#define MP_TOUCH_EVENT_10 9 +#define MP_TOUCH_EVENT_11 10 +#define MP_TOUCH_EVENT_12 11 +#define MP_PROX_EVENT_1 12 +#define MP_PROX_EVENT_2 13 +#define MP_FB_EVENT_MAX 14 + +#define MP_FB_RISING_EDGE 0 +#define MP_FB_FALLING_EDGE 1 + +extern void mp_frontboard2026_push_event( uint8_t event, uint8_t trigger ); + +#endif diff --git a/drivers/tildagon_frontboard/tildagon_frontboard.c b/drivers/tildagon_frontboard/tildagon_frontboard.c new file mode 100644 index 00000000..6cd67807 --- /dev/null +++ b/drivers/tildagon_frontboard/tildagon_frontboard.c @@ -0,0 +1,97 @@ + + +#include "cy8cmbrx.h" +#include "aw9523b.h" +#include "qmc6309.h" +#include "driver/gpio.h" +#include "tildagon_frontboard.h" +#include "tildagon_pin.h" +#include "tildagon_imu.h" +#include "mp_frontboard.h" +#include "esp_err.h" + +#define READ ( MP_MACHINE_I2C_FLAG_WRITE1 | MP_MACHINE_I2C_FLAG_READ | MP_MACHINE_I2C_FLAG_STOP ) +#define WRITE MP_MACHINE_I2C_FLAG_STOP + +const uint8_t reset = 7U; +const uint8_t int_clear = 6U; +uint8_t iox_int = 2U; +const uint8_t ls1 = 15U; + +aw9523b_device_t top_egpio = +{ + .i2c_addr = 0x58, +}; + +static void iox_cb ( void* args, uint8_t event ); + +/** + * @brief initialise the frontboard + */ +void tildagon_frontboard_init( uint16_t board_id ) +{ + if ( ( board_id & 0x00FF ) == 0x01 ) + { + iox_int = 3; + } + /* setup frontboard port expander */ + top_egpio.mux = tildagon_get_mux_obj( TILDAGON_TOP_I2C_PORT ), + tildagon_pins_set_aux( top_egpio, 0 ); + aw9523b_init( &ext_pin[3] ); + aw9523b_pin_set_direction( &ext_pin[1], iox_int, true ); + aw9523b_irq_register( &ext_pin[1], iox_int, iox_cb, NULL ); + aw9523b_irq_enable( &ext_pin[1], iox_int ); + + /* raise reset and setup touch and proximity */ + aw9523b_pin_set_direction( &ext_pin[3], reset, false ); + aw9523b_pin_set_mode( &ext_pin[3], reset, AW9523B_PIN_MODE_GPIO ); + aw9523b_pin_set_output( &ext_pin[3], reset, true ); + + if ( qmc6309_init() == ESP_OK ) + { + tildagon_imu_register_compass( qmc6309_update, qmc6309_read ); + } + cy8cmbrx_init( tildagon_get_mux_obj( TILDAGON_TOP_I2C_PORT ) ); +} + +/** + * @brief callback for the top board port expander, + * looks for cause of interrupt and calls the relevant isr + */ +static void iox_cb ( void* args, uint8_t event ) +{ + aw9523b_irq_handler( &ext_pin[3] ); +} + +/** + * @brief callback for the cap sense + */ +void cy8cmbrx_cb( void* args ,uint8_t event ) +{ + cy8cmbrx_status_t status = cy8cmbrx_run(); + /* push events */ + for (uint8_t i = 0U; i < 2; i++) + { + if ( ( status.prox[i] == CY8CMBRX_RISING_EDGE ) || ( status.prox[i] == CY8CMBRX_PULSE )) + { + mp_frontboard2026_push_event( MP_PROX_EVENT_1 + i, MP_FB_RISING_EDGE); + } + if ( ( status.prox[i] == CY8CMBRX_FALLING_EDGE ) || ( status.prox[i] == CY8CMBRX_PULSE )) + { + mp_frontboard2026_push_event( MP_PROX_EVENT_1 + i, MP_FB_FALLING_EDGE); + } + } + for (uint8_t i = 0U; i < 12; i++) + { + if ( ( status.buttons[i] == CY8CMBRX_RISING_EDGE ) || ( status.buttons[i] == CY8CMBRX_PULSE )) + { + mp_frontboard2026_push_event( MP_TOUCH_EVENT_1 + i, MP_FB_RISING_EDGE); + } + if ( ( status.buttons[i] == CY8CMBRX_FALLING_EDGE ) || ( status.buttons[i] == CY8CMBRX_PULSE )) + { + mp_frontboard2026_push_event( MP_TOUCH_EVENT_1 + i, MP_FB_FALLING_EDGE); + } + } +} + + diff --git a/drivers/tildagon_frontboard/tildagon_frontboard.h b/drivers/tildagon_frontboard/tildagon_frontboard.h new file mode 100644 index 00000000..68d003dd --- /dev/null +++ b/drivers/tildagon_frontboard/tildagon_frontboard.h @@ -0,0 +1,7 @@ +#ifndef TILDAGON_FRONTBOARD_H +#define TILDAGON_FRONTBOARD_H + +extern void tildagon_frontboard_init( uint16_t board_id ); +extern uint16_t tildagon_frontboard_get_model( void ); +extern void cy8cmbrx_cb( void* args ,uint8_t event ); +#endif \ No newline at end of file diff --git a/drivers/tildagon_imu/lsm6ds3/lsm6ds3.c b/drivers/tildagon_imu/lsm6ds3/lsm6ds3.c index 14911085..4436ef98 100644 --- a/drivers/tildagon_imu/lsm6ds3/lsm6ds3.c +++ b/drivers/tildagon_imu/lsm6ds3/lsm6ds3.c @@ -148,47 +148,43 @@ int lsm6ds3_read(uint8_t reg_addr, uint8_t *reg_data, uint8_t len ) /** * @brief update task */ -void lsm6ds3_task( void* data ) +void lsm6ds3_task( void ) { - TickType_t last_wake = xTaskGetTickCount(); - while (1) + /* read temperature, gyro and accelerometer together to reduce i2c traffic */ + uint8_t write_buffer[2] = { OUT_TEMP_L, 0x16 }; + uint8_t read_buffer[14] = { 0U }; + mp_machine_i2c_buf_t buffer[2] = { { .len = 1, .buf = write_buffer }, + { .len = 14, .buf = read_buffer } }; + esp_err_t ret = tildagon_mux_i2c_transaction( mux_port, ADDRESS, 2, buffer, READ ); + if (ret >= 0) { - vTaskDelayUntil(&last_wake, pdMS_TO_TICKS(10)); // 100 Hz - /* read temperature, gyro and accelerometer together to reduce i2c traffic */ - uint8_t write_buffer[2] = { OUT_TEMP_L, 0x16 }; - uint8_t read_buffer[14] = { 0U }; - mp_machine_i2c_buf_t buffer[2] = { { .len = 1, .buf = write_buffer }, - { .len = 14, .buf = read_buffer } }; - esp_err_t ret = tildagon_mux_i2c_transaction( mux_port, ADDRESS, 2, buffer, READ ); - if (ret >= 0) - { - LOCK; - _temperature = (((float)((int16_t)(read_buffer[0] + ( (uint16_t)read_buffer[1] << 8 )))) * 0.001953125F) + 23.0F; - const float gyroscaling = (2000.0F / 32768.0F); - gyro_x = ((float)((int16_t)( read_buffer[2] + ( (uint16_t)read_buffer[3] << 8 ) ))) * gyroscaling; - gyro_y = ((float)((int16_t)( read_buffer[4] + ( (uint16_t)read_buffer[5] << 8 ) ))) * gyroscaling; - gyro_z = ((float)((int16_t)( read_buffer[6] + ( (uint16_t)read_buffer[7] << 8 ) ))) * gyroscaling; - /* 2g fsd, 1g = 9.80665m/s */ - const float accelscaling = (2.0F * 9.80665F) / 32768.0F; - acc_x = ((float)((int16_t)( read_buffer[8] + ( (uint16_t)read_buffer[9] << 8 ) ))) * accelscaling; - acc_y = ((float)((int16_t)( read_buffer[10] + ( (uint16_t)read_buffer[11] << 8 ) ))) * accelscaling; - acc_z = ((float)((int16_t)( read_buffer[12] + ( (uint16_t)read_buffer[13] << 8 ) ))) * accelscaling; - UNLOCK; - } - write_buffer[0] = STEP_COUNTER_L; - buffer[1].len = 2; - ret = tildagon_mux_i2c_transaction( mux_port, ADDRESS, 2, buffer, READ ); - if (ret >= 0) - { - LOCK; - _steps += read_buffer[0] + ( (uint16_t)read_buffer[1] << 8 ); - /* reset step count */ - buffer[0].len = 2; - write_buffer[0] = CTRL10_C; - tildagon_mux_i2c_transaction( mux_port, ADDRESS, 1, buffer, WRITE ); - UNLOCK; - } - } + LOCK; + _temperature = (((float)((int16_t)(read_buffer[0] + ( (uint16_t)read_buffer[1] << 8 )))) * 0.001953125F) + 23.0F; + const float gyroscaling = (2000.0F / 32768.0F); + gyro_x = ((float)((int16_t)( read_buffer[2] + ( (uint16_t)read_buffer[3] << 8 ) ))) * gyroscaling; + gyro_y = ((float)((int16_t)( read_buffer[4] + ( (uint16_t)read_buffer[5] << 8 ) ))) * gyroscaling; + gyro_z = ((float)((int16_t)( read_buffer[6] + ( (uint16_t)read_buffer[7] << 8 ) ))) * gyroscaling; + /* 2g fsd, 1g = 9.80665m/s */ + const float accelscaling = (2.0F * 9.80665F) / 32768.0F; + acc_x = ((float)((int16_t)( read_buffer[8] + ( (uint16_t)read_buffer[9] << 8 ) ))) * accelscaling; + acc_y = ((float)((int16_t)( read_buffer[10] + ( (uint16_t)read_buffer[11] << 8 ) ))) * accelscaling; + acc_z = ((float)((int16_t)( read_buffer[12] + ( (uint16_t)read_buffer[13] << 8 ) ))) * accelscaling; + UNLOCK; + } + write_buffer[0] = STEP_COUNTER_L; + buffer[1].len = 2; + ret = tildagon_mux_i2c_transaction( mux_port, ADDRESS, 2, buffer, READ ); + if (ret >= 0) + { + LOCK; + _steps += read_buffer[0] + ( (uint16_t)read_buffer[1] << 8 ); + /* reset step count */ + buffer[0].len = 2; + write_buffer[0] = CTRL10_C; + tildagon_mux_i2c_transaction( mux_port, ADDRESS, 1, buffer, WRITE ); + UNLOCK; + } + } /** diff --git a/drivers/tildagon_imu/lsm6ds3/lsm6ds3.h b/drivers/tildagon_imu/lsm6ds3/lsm6ds3.h index 1ef898bb..8fcbf4d2 100644 --- a/drivers/tildagon_imu/lsm6ds3/lsm6ds3.h +++ b/drivers/tildagon_imu/lsm6ds3/lsm6ds3.h @@ -4,7 +4,7 @@ #include extern int lsm6ds3_init( void ); -extern void lsm6ds3_task(void *data); +extern void lsm6ds3_task( void ); extern void lsm6ds3_read_acc_mps(float *x, float *y, float *z); extern void lsm6ds3_read_gyro_dps(float *x, float *y, float *z); extern void lsm6ds3_read_steps(uint32_t *steps); diff --git a/drivers/tildagon_imu/mp_imu.c b/drivers/tildagon_imu/mp_imu.c index 596a3d7c..4ebff40f 100644 --- a/drivers/tildagon_imu/mp_imu.c +++ b/drivers/tildagon_imu/mp_imu.c @@ -32,6 +32,19 @@ static mp_obj_t mp_imu_gyro_read(void) { static MP_DEFINE_CONST_FUN_OBJ_0(mp_imu_gyro_read_obj, mp_imu_gyro_read); +static mp_obj_t mp_imu_mag_read(void) { + static float x, y, z; + + // Will not overwrite old data if there is an error + tildagon_imu_compass_read(&x, &y, &z); + + mp_obj_t items[3] = { mp_obj_new_float(x), mp_obj_new_float(y), + mp_obj_new_float(z) }; + return mp_obj_new_tuple(3, items); +} + +static MP_DEFINE_CONST_FUN_OBJ_0(mp_imu_mag_read_obj, mp_imu_mag_read); + static mp_obj_t mp_imu_step_counter_read(void) { static uint32_t steps; @@ -98,6 +111,7 @@ static MP_DEFINE_CONST_FUN_OBJ_2(mp_imu_write_to_obj, mp_imu_write_to); static const mp_rom_map_elem_t globals_table[] = { { MP_ROM_QSTR(MP_QSTR_acc_read), MP_ROM_PTR(&mp_imu_acc_read_obj) }, { MP_ROM_QSTR(MP_QSTR_gyro_read), MP_ROM_PTR(&mp_imu_gyro_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_mag_read), MP_ROM_PTR(&mp_imu_mag_read_obj) }, { MP_ROM_QSTR(MP_QSTR_step_counter_read), MP_ROM_PTR(&mp_imu_step_counter_read_obj) }, { MP_ROM_QSTR(MP_QSTR_temperature_read), MP_ROM_PTR(&mp_imu_temperature_read_obj) }, { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&mp_imu_id_obj) }, diff --git a/drivers/tildagon_imu/qmc6309/qmc6309.c b/drivers/tildagon_imu/qmc6309/qmc6309.c new file mode 100644 index 00000000..8c961849 --- /dev/null +++ b/drivers/tildagon_imu/qmc6309/qmc6309.c @@ -0,0 +1,48 @@ +#include "tildagon_i2c_mpless.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +#include "qmc6309.h" + +#define ADDRESS 0x7CU +#define DATA_OUTPUT_REG 0x01U +#define CTRL_REG1 0x0AU +#define CTRL_REG2 0x0BU +static SemaphoreHandle_t _mu; +#define LOCK xSemaphoreTake(_mu, portMAX_DELAY) +#define UNLOCK xSemaphoreGive(_mu) + +static float qmc_x = 0.0F; +static float qmc_y = 0.0F; +static float qmc_z = 0.0F; + +esp_err_t qmc6309_init( void ) +{ + _mu = xSemaphoreCreateMutex(); + /* continuous sampling, oversample 8, level 1 filter and 100 Hz, 8 gauss range */ + uint8_t config[3] = { 0x03U, 0x38U }; + return tildagon_i2c_reg_write(TILDAGON_TOP_I2C_PORT, ADDRESS, CTRL_REG1, config, 2); + +} + +void qmc6309_update( void ) +{ + uint8_t buffer[6] = { 0U }; + if ( tildagon_i2c_reg_read( TILDAGON_TOP_I2C_PORT, ADDRESS, DATA_OUTPUT_REG, buffer, 6U ) == ESP_OK ) + { + LOCK; + qmc_x = ((float)((int16_t)(buffer[2] + ((uint16_t)buffer[3] << 8))))/4095.0F; + qmc_y = -((float)((int16_t)(buffer[0] + ((uint16_t)buffer[1] << 8))))/4095.0F; + qmc_z = ((float)((int16_t)(buffer[4] + ((uint16_t)buffer[5] << 8))))/4095.0F; + UNLOCK; + } +} + +void qmc6309_read( float* x, float*y, float*z ) +{ + LOCK; + *x = qmc_x; + *y = qmc_y; + *z = qmc_z; + UNLOCK; +} diff --git a/drivers/tildagon_imu/qmc6309/qmc6309.h b/drivers/tildagon_imu/qmc6309/qmc6309.h new file mode 100644 index 00000000..bb2ba059 --- /dev/null +++ b/drivers/tildagon_imu/qmc6309/qmc6309.h @@ -0,0 +1,12 @@ +#ifndef QMC6309_H +#define QMC6309_H + +#include "esp_err.h" + +esp_err_t qmc6309_init( void ); + +extern void qmc6309_update( void ); + +extern void qmc6309_read( float* x, float*y, float*z ); + +#endif \ No newline at end of file diff --git a/drivers/tildagon_imu/tildagon_imu.c b/drivers/tildagon_imu/tildagon_imu.c index 1e61d742..1968ed61 100644 --- a/drivers/tildagon_imu/tildagon_imu.c +++ b/drivers/tildagon_imu/tildagon_imu.c @@ -8,6 +8,8 @@ #include "st3m_imu.h" #include "lsm6ds3.h" +#include "tildagon_imu.h" + typedef enum { ST3M, @@ -16,13 +18,12 @@ typedef enum MAX_DEVICES, } which_imu_t; -typedef void (*updatefuncptr_t) ( void* data ); -typedef void (*accfuncptr_t) ( float* x, float*y, float*z ); -typedef void (*gyrfuncptr_t) ( float* x, float*y, float*z ); typedef void (*stepfuncptr_t) ( uint32_t* steps ); typedef void (*tempfuncptr_t) ( float* temperature ); typedef int (*i2cfuncptr_t) ( uint8_t reg_addr, uint8_t *reg_data, uint8_t len ); +void imu_run( void* data ); + i2cfuncptr_t i2c_write[MAX_DEVICES] = { /* ST3M */ st3m_imu_write, @@ -41,13 +42,13 @@ updatefuncptr_t update[MAX_DEVICES] = /* LSM6DS3 */ lsm6ds3_task, }; -accfuncptr_t accel_read[MAX_DEVICES] = +sensorfuncptr_t accel_read[MAX_DEVICES] = { /* ST3M */ st3m_imu_read_acc_mps, /* LSM6DS3 */ lsm6ds3_read_acc_mps, }; -gyrfuncptr_t gyro_read[MAX_DEVICES] = +sensorfuncptr_t gyro_read[MAX_DEVICES] = { /* ST3M */ st3m_imu_read_gyro_dps, /* LSM6DS3 */ lsm6ds3_read_gyro_dps, @@ -65,6 +66,9 @@ tempfuncptr_t temp_read[MAX_DEVICES] = /* LSM6DS3 */ lsm6ds3_read_temperature, }; +static sensorfuncptr_t compass_readptr = NULL; +static updatefuncptr_t compass_funcptr = NULL; + static char st3m_id[] = "bmi270"; static char lsm6ds3_id[] = "lsm6ds3"; static char* id_list[MAX_DEVICES] = @@ -89,7 +93,7 @@ void tildagon_imu_init( void ) if ( imu < MAX_DEVICES ) { /* create task */ - xTaskCreate( update[imu], "imu", 4096, NULL, configMAX_PRIORITIES - 2, NULL); + xTaskCreate( imu_run, "imu", 4096, NULL, configMAX_PRIORITIES - 2, NULL); } } @@ -181,3 +185,32 @@ int tildagon_imu_read( uint8_t address, uint8_t length, uint8_t* buffer ) return -MP_ENODEV; } } + +void tildagon_imu_register_compass( updatefuncptr_t compass_update, sensorfuncptr_t compass_read ) +{ + compass_funcptr = compass_update; + compass_readptr = compass_read; +} + +void tildagon_imu_compass_read( float* x, float*y, float*z ) +{ + if ( compass_readptr != NULL ) + { + compass_readptr( x, y, z ); + } +} + +void imu_run( void* data ) +{ + TickType_t last_wake = xTaskGetTickCount(); + while (1) + { + vTaskDelayUntil(&last_wake, pdMS_TO_TICKS(10)); // 100 Hz + + update[imu](); + if ( compass_funcptr != NULL ) + { + compass_funcptr(); + } + } +} diff --git a/drivers/tildagon_imu/tildagon_imu.cmake b/drivers/tildagon_imu/tildagon_imu.cmake index 9aa3ae0c..3b616e50 100644 --- a/drivers/tildagon_imu/tildagon_imu.cmake +++ b/drivers/tildagon_imu/tildagon_imu.cmake @@ -6,6 +6,7 @@ add_library(usermod_tildagon_imu INTERFACE) target_sources(usermod_tildagon_imu INTERFACE ${CMAKE_CURRENT_LIST_DIR}/tildagon_imu.c ${CMAKE_CURRENT_LIST_DIR}/lsm6ds3/lsm6ds3.c + ${CMAKE_CURRENT_LIST_DIR}/qmc6309/qmc6309.c ${CMAKE_CURRENT_LIST_DIR}/mp_imu.c ) @@ -13,6 +14,7 @@ target_sources(usermod_tildagon_imu INTERFACE target_include_directories(usermod_tildagon_imu INTERFACE ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/lsm6ds3 + ${CMAKE_CURRENT_LIST_DIR}/qmc6309 ${CMAKE_CURRENT_LIST_DIR}/../../components/st3m ) diff --git a/drivers/tildagon_imu/tildagon_imu.h b/drivers/tildagon_imu/tildagon_imu.h index 0e95ddeb..ba769e24 100644 --- a/drivers/tildagon_imu/tildagon_imu.h +++ b/drivers/tildagon_imu/tildagon_imu.h @@ -2,6 +2,9 @@ #define TILDAGON_IMU_H #include "stdint.h" +typedef void (*updatefuncptr_t) ( void ); +typedef void (*sensorfuncptr_t) ( float* x, float*y, float*z ); + extern void tildagon_imu_init( void ); extern void tildagon_imu_acc_read( float* x, float*y, float*z ); extern void tildagon_imu_gyro_read( float* x, float*y, float*z ); @@ -10,5 +13,7 @@ extern void tildagon_imu_temperature_read( float* temperature ); extern char* tildagon_imu_get_id( void ); extern int tildagon_imu_write( uint8_t address, uint8_t length, uint8_t* buffer ); extern int tildagon_imu_read( uint8_t address, uint8_t length, uint8_t* buffer ); +extern void tildagon_imu_register_compass( updatefuncptr_t compass_update, sensorfuncptr_t compass_read ); +extern void tildagon_imu_compass_read( float* x, float*y, float*z ); #endif diff --git a/drivers/tildagon_pin/aw9523b.c b/drivers/tildagon_pin/aw9523b.c index cc94fcb1..b8687eab 100644 --- a/drivers/tildagon_pin/aw9523b.c +++ b/drivers/tildagon_pin/aw9523b.c @@ -18,20 +18,17 @@ static uint8_t aw9523b_portpin(aw9523b_pin_t pin) { } static esp_err_t aw9523b_readregs(aw9523b_device_t *dev, uint8_t reg, uint8_t *regs, size_t nregs) { - - tildagon_mux_i2c_obj_t *mux = tildagon_get_mux_obj(7); mp_machine_i2c_buf_t buffer[2] = { { .len = 1, .buf = ® }, { .len = nregs, .buf = regs } }; - return tildagon_mux_i2c_transaction(mux, dev->i2c_addr, 2, (mp_machine_i2c_buf_t*)&buffer, READ); + return tildagon_mux_i2c_transaction(dev->mux, dev->i2c_addr, 2, (mp_machine_i2c_buf_t*)&buffer, READ); } static esp_err_t aw9523b_writeregs(aw9523b_device_t *dev, uint8_t reg, const uint8_t *regs, size_t nregs) { uint8_t buf[nregs+1]; buf[0] = reg; memcpy(buf+1, regs, nregs); - tildagon_mux_i2c_obj_t *mux = tildagon_get_mux_obj(7); mp_machine_i2c_buf_t buffer[1] = { { .len = nregs+1, .buf = buf } }; - return tildagon_mux_i2c_transaction(mux, dev->i2c_addr, 1, (mp_machine_i2c_buf_t*)&buffer, WRITE); + return tildagon_mux_i2c_transaction(dev->mux, dev->i2c_addr, 1, (mp_machine_i2c_buf_t*)&buffer, WRITE); } void aw9523b_init(aw9523b_device_t *dev) diff --git a/drivers/tildagon_pin/aw9523b.h b/drivers/tildagon_pin/aw9523b.h index 5b9cc83e..aa94100f 100644 --- a/drivers/tildagon_pin/aw9523b.h +++ b/drivers/tildagon_pin/aw9523b.h @@ -22,8 +22,7 @@ typedef struct typedef struct aw9523b_device { - const tca9548a_i2c_mux_t *mux; - tca9548a_i2c_port_t i2c_port; + tildagon_mux_i2c_obj_t *mux; uint16_t i2c_addr; uint8_t last_input_values[2]; uint8_t irq_enables[2]; diff --git a/drivers/tildagon_pin/gpio_ext_num.h b/drivers/tildagon_pin/gpio_ext_num.h index fc5d94d6..ddc742a9 100644 --- a/drivers/tildagon_pin/gpio_ext_num.h +++ b/drivers/tildagon_pin/gpio_ext_num.h @@ -50,7 +50,23 @@ enum GPIO_EXT_NUM{ GPIO_EXT_NUM_2_13 = 45, GPIO_EXT_NUM_2_14 = 46, GPIO_EXT_NUM_2_15 = 47, - GPIO_EXT_NUM_MAX = 48, + GPIO_EXT_NUM_3_0 = 48, + GPIO_EXT_NUM_3_1 = 49, + GPIO_EXT_NUM_3_2 = 50, + GPIO_EXT_NUM_3_3 = 51, + GPIO_EXT_NUM_3_4 = 52, + GPIO_EXT_NUM_3_5 = 53, + GPIO_EXT_NUM_3_6 = 54, + GPIO_EXT_NUM_3_7 = 55, + GPIO_EXT_NUM_3_8 = 56, + GPIO_EXT_NUM_3_9 = 57, + GPIO_EXT_NUM_3_10 = 58, + GPIO_EXT_NUM_3_11 = 59, + GPIO_EXT_NUM_3_12 = 60, + GPIO_EXT_NUM_3_13 = 61, + GPIO_EXT_NUM_3_14 = 62, + GPIO_EXT_NUM_3_15 = 63, + GPIO_EXT_NUM_MAX = 64, }; #endif // _GPIO_EXT_NUM_H_ \ No newline at end of file diff --git a/drivers/tildagon_pin/pins.c b/drivers/tildagon_pin/pins.c index 2665cd0f..e4cabd16 100644 --- a/drivers/tildagon_pin/pins.c +++ b/drivers/tildagon_pin/pins.c @@ -56,6 +56,22 @@ const tildagon_pin_obj_t tildagon_pin_obj_table[GPIO_EXT_NUM_MAX] = { [GPIO_EXT_NUM_2_13] = { .base = { .type = &tildagon_pin_type } }, [GPIO_EXT_NUM_2_14] = { .base = { .type = &tildagon_pin_type } }, [GPIO_EXT_NUM_2_15] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_0] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_1] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_2] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_3] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_4] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_5] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_6] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_7] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_8] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_9] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_10] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_11] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_12] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_13] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_14] = { .base = { .type = &tildagon_pin_type } }, + [GPIO_EXT_NUM_3_15] = { .base = { .type = &tildagon_pin_type } }, }; diff --git a/drivers/tildagon_pin/tildagon_pin.c b/drivers/tildagon_pin/tildagon_pin.c index a66639dd..17055ae8 100644 --- a/drivers/tildagon_pin/tildagon_pin.c +++ b/drivers/tildagon_pin/tildagon_pin.c @@ -56,22 +56,32 @@ // this is outside of machine.Pins defines #define EGPIO_MODE_PWM 8 -aw9523b_device_t ext_pin[3] = { +aw9523b_device_t ext_pin[4] = { { - .i2c_port = TILDAGON_SYS_I2C_PORT, .i2c_addr = 0x58, }, { - .i2c_port = TILDAGON_SYS_I2C_PORT, .i2c_addr = 0x59, }, { - .i2c_port = TILDAGON_SYS_I2C_PORT, .i2c_addr = 0x5a, + }, + { + .mux = NULL, + .i2c_addr = 0x00, } }; +uint8_t max_bank = 3U; - +void tildagon_pins_set_aux( aw9523b_device_t aux_pin, uint8_t index ) +{ + if ( index < 1 ) + { + ext_pin[ 3 + index ] = aux_pin; + max_bank = 4U; + } +} + static const tildagon_pin_obj_t *tildagon_pin_find_named(const mp_obj_dict_t *named_pins, mp_obj_t name) { const mp_map_t *named_map = &named_pins->map; mp_map_elem_t *named_elem = mp_map_lookup((mp_map_t *)named_map, name, MP_MAP_LOOKUP); @@ -85,7 +95,7 @@ void tildagon_pins_init(void) { for (int i = 0; i < 3; i++) { - ext_pin[i].mux = tildagon_get_i2c_mux(); + ext_pin[i].mux = tildagon_get_mux_obj(TILDAGON_SYS_I2C_PORT); aw9523b_init(&ext_pin[i]); } // setup outputs mux [2] 2, 4 and 5. 5v sw, usb mux and led sw @@ -95,7 +105,6 @@ void tildagon_pins_init(void) aw9523b_pin_set_output( &ext_pin[2], 4, false ); aw9523b_pin_set_direction( &ext_pin[2], 5, false ); aw9523b_pin_set_output( &ext_pin[2], 5, false ); - //memset(&MP_STATE_PORT(tildagon_pin_irq_handler[0]), 0, sizeof(MP_STATE_PORT(tildagon_pin_irq_handler))); } void tildagon_pins_generate_isr( void ) @@ -115,7 +124,7 @@ static void tildagon_pin_isr_handler(void *arg, uint8_t event) uint8_t index = PIN_OBJ_PTR_INDEX(self); if ( event == GPIO_INTR_NEGEDGE ) { - index += GPIO_PIN_COUNT; + index += GPIO_EXT_NUM_MAX; } mp_obj_t handler = MP_STATE_PORT(tildagon_pin_irq_handler)[index]; mp_sched_schedule(handler, MP_OBJ_FROM_PTR(self)); @@ -134,7 +143,7 @@ static const tildagon_pin_obj_t *tildagon_pin_find(mp_obj_t pin_in) { if (len == 2) { mp_int_t bank = mp_obj_get_int(items[0]); mp_int_t index = mp_obj_get_int(items[1]); - if (0 <= bank && bank < 3 && 0 <= index && index < 16) { + if (0 <= bank && bank < max_bank && 0 <= index && index < 16) { const tildagon_pin_obj_t *self = &tildagon_pin_obj_table[bank*16 + index]; if (self->base.type != NULL) { return self; @@ -297,7 +306,6 @@ static mp_obj_t tildagon_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map uint8_t index = PIN_OBJ_PTR_INDEX(self); mp_obj_t handler = args[ARG_handler].u_obj; mp_uint_t trigger = args[ARG_trigger].u_int; - if (handler != mp_const_none) { aw9523b_irq_register(dev, pin, tildagon_pin_isr_handler, self); @@ -313,10 +321,10 @@ static mp_obj_t tildagon_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map } if ( trigger & GPIO_INTR_NEGEDGE ) { - MP_STATE_PORT(tildagon_pin_irq_handler)[index + GPIO_PIN_COUNT] = handler; + MP_STATE_PORT(tildagon_pin_irq_handler)[index + GPIO_EXT_NUM_MAX] = handler; } if ( - ( MP_STATE_PORT(tildagon_pin_irq_handler)[index + GPIO_PIN_COUNT] == MP_OBJ_NULL ) + ( MP_STATE_PORT(tildagon_pin_irq_handler)[index + GPIO_EXT_NUM_MAX] == MP_OBJ_NULL ) && ( MP_STATE_PORT(tildagon_pin_irq_handler)[index] == MP_OBJ_NULL ) ) { @@ -429,4 +437,4 @@ MP_DEFINE_CONST_OBJ_TYPE( locals_dict, &tildagon_pin_locals_dict ); -MP_REGISTER_ROOT_POINTER(mp_obj_t tildagon_pin_irq_handler[GPIO_PIN_COUNT*2]); +MP_REGISTER_ROOT_POINTER(mp_obj_t tildagon_pin_irq_handler[64*2]); diff --git a/drivers/tildagon_pin/tildagon_pin.h b/drivers/tildagon_pin/tildagon_pin.h index c66394c7..4ae48569 100644 --- a/drivers/tildagon_pin/tildagon_pin.h +++ b/drivers/tildagon_pin/tildagon_pin.h @@ -8,7 +8,7 @@ typedef struct _tildagon_pin_obj_t { mp_obj_base_t base; } tildagon_pin_obj_t; -extern aw9523b_device_t ext_pin[3]; +extern aw9523b_device_t ext_pin[4]; extern const mp_obj_type_t tildagon_pin_type; @@ -18,4 +18,6 @@ extern const mp_obj_dict_t tildagon_pin_board_pins_locals_dict; extern void tildagon_pins_init( void ); extern void tildagon_pins_generate_isr( void ); +extern void tildagon_pins_set_aux( aw9523b_device_t aux_pin, uint8_t index ); + #endif // _MICROPY_PY_TILDAGON_PIN diff --git a/modules/events/input.py b/modules/events/input.py index 9e2b2727..1a1433c0 100644 --- a/modules/events/input.py +++ b/modules/events/input.py @@ -56,6 +56,25 @@ def find_parent_in_group(self, group): "DOWN": Button("DOWN", "System"), "LEFT": Button("LEFT", "System"), "RIGHT": Button("RIGHT", "System"), + "A": Button("A", "System"), + "B": Button("B", "System"), + "C": Button("C", "System"), + "D": Button("D", "System"), + "E": Button("E", "System"), + "LEFTPROX": Button("LEFTPROX", "System"), + "RIGHTPROX": Button("RIGHTPROX", "System"), + "TOUCH1": Button("TOUCH1", "System"), + "TOUCH2": Button("TOUCH2", "System"), + "TOUCH3": Button("TOUCH3", "System"), + "TOUCH4": Button("TOUCH4", "System"), + "TOUCH5": Button("TOUCH5", "System"), + "TOUCH6": Button("TOUCH6", "System"), + "TOUCH7": Button("TOUCH7", "System"), + "TOUCH8": Button("TOUCH8", "System"), + "TOUCH9": Button("TOUCH9", "System"), + "TOUCH10": Button("TOUCH10", "System"), + "TOUCH11": Button("TOUCH11", "System"), + "TOUCH12": Button("TOUCH12", "System"), } diff --git a/modules/frontboards/cy8cmbrx.py b/modules/frontboards/cy8cmbrx.py new file mode 100644 index 00000000..906ff8db --- /dev/null +++ b/modules/frontboards/cy8cmbrx.py @@ -0,0 +1,185 @@ +from frontboards.cy8cmbrx_defs import CY8CMBRX +from machine import I2C +# from tildagon import ePin + + +cy8cmbr3116_config = [ + CY8CMBRX.CS0_ENABLE + | CY8CMBRX.CS1_ENABLE + | CY8CMBRX.CS2_ENABLE + | CY8CMBRX.CS3_ENABLE + | CY8CMBRX.CS4_ENABLE + | CY8CMBRX.CS5_ENABLE + | CY8CMBRX.CS6_ENABLE + | CY8CMBRX.CS7_ENABLE, # 0x00 SENSOR_EN LSB + CY8CMBRX.CS8_ENABLE + | CY8CMBRX.CS9_ENABLE + | CY8CMBRX.CS10_ENABLE + | CY8CMBRX.CS11_ENABLE + | CY8CMBRX.CS12_ENABLE + | CY8CMBRX.CS13_ENABLE + | CY8CMBRX.CS14_ENABLE, # 0x01 SENSOR_EN MSB + 0x00, # 0x02 FSS_EN LSB + 0x00, # 0x03 FSS_EN MSB + 0x00, # 0x04 TOGGLE_EN LSB + 0x00, # 0x05 TOGGLE_EN MSB + 0x00, # 0x06 LED_ON_EN LSB + 0x00, # 0x07 LED_ON_EN MSB + CY8CMBRX.SENS2_X1 | CY8CMBRX.SENS3_X2, # 0x08 SENSITIVITY0 + CY8CMBRX.SENS0_X3 + | CY8CMBRX.SENS1_X4 + | CY8CMBRX.SENS2_X1 + | CY8CMBRX.SENS3_X2, # 0x09 SENSITIVITY1 + CY8CMBRX.SENS0_X3 + | CY8CMBRX.SENS1_X4 + | CY8CMBRX.SENS2_X1 + | CY8CMBRX.SENS3_X4, # 0x0A SENSITIVITY2 + CY8CMBRX.SENS0_X4 | CY8CMBRX.SENS1_X4 | CY8CMBRX.SENS2_X4, # 0x0B SENSITIVITY3 + 0x80, # 0x0C BASE_THRESHOLD0 + 0x80, # 0x0D BASE_THRESHOLD1 + 0x80, # 0x0E FINGER_THRESHOLD2 + 0x80, # 0x0F FINGER_THRESHOLD3 + 0x80, # 0x10 FINGER_THRESHOLD4 + 0x80, # 0x11 FINGER_THRESHOLD5 + 0x80, # 0x12 FINGER_THRESHOLD6 + 0x80, # 0x13 FINGER_THRESHOLD7 + 0x80, # 0x14 FINGER_THRESHOLD8 + 0x80, # 0x15 FINGER_THRESHOLD9 + 0x80, # 0x16 FINGER_THRESHOLD10 + 0x80, # 0x17 FINGER_THRESHOLD11 + 0x80, # 0x18 FINGER_THRESHOLD12 + 0x80, # 0x19 FINGER_THRESHOLD13 + 0x80, # 0x1A FINGER_THRESHOLD14 + 0x7F, # 0x1B FINGER_THRESHOLD15 + 0x03, # 0x1C SENSOR_DEBOUNCE + 0x00, # 0x1D BUTTON_HYS + 0x00, # 0x1E NOT USED + 0x00, # 0x1F BUTTON_LBR + 0x00, # 0x20 BUTTON_NNT + 0x00, # 0x21 BUTTON_NT + 0x00, # 0x22 NOT USED + 0x00, # 0x23 NOT USED + 0x00, # 0x24 NOT USED + 0x00, # 0x25 NOT USED + CY8CMBRX.CS0_ENABLE | CY8CMBRX.CS1_ENABLE, # 0x26 PROX.EN + 0x00, # 0x27 PROX.CFG + 0x06, # 0x28 PROX.CFG2 + 0x00, # 0x29 NOT USED + 0x00, # 0x2A PROX.TOUCH_TH0 LSB + 0x02, # 0x2B PROX.TOUCH_TH0 MSB + 0x00, # 0x2C PROX.TOUCH_TH1 LSB + 0x02, # 0x2D PROX.TOUCH_TH1 MSB + CY8CMBRX.RES_12_BIT, # 0x2E PROX.RESOLUTION0 + CY8CMBRX.RES_12_BIT, # 0x2F PROX.RESOLUTION1 + 0x00, # 0x30 PROX.HYS + 0x00, # 0x31 NOT USED + 0x00, # 0x32 PROX.LBR + 0x00, # 0x33 PROX.NNT + 0x00, # 0x34 PROX.NT + 0x1E, # 0x35 PROX.POSITIVE_TH0 + 0x1E, # 0x36 PROX.POSITIVE_TH1 + 0x00, # 0x37 NOT USED + 0x00, # 0x38 NOT USED + 0x1E, # 0x39 PROX.NEGATIVE_TH0 + 0x1E, # 0x3A PROX.NEGATIVE_TH1 + 0x00, # 0x3B NOT USED + 0x00, # 0x3C NOT USED + 0x00, # 0x3D LED_ON_TIME + 0x01, # 0x3E BUZZER_CFG + 0x01, # 0x3F BUZZER_ON_TIME + 0x00, # 0x40 GPO_CFG + 0xFF, # 0x41 PWM_DUTYCYCLE_CFG0 + 0xFF, # 0x42 PWM_DUTYCYCLE_CFG1 + 0xFF, # 0x43 PWM_DUTYCYCLE_CFG2 + 0xFF, # 0x44 PWM_DUTYCYCLE_CFG3 + 0xFF, # 0x45 PWM_DUTYCYCLE_CFG4 + 0xFF, # 0x46 PWM_DUTYCYCLE_CFG5 + 0xFF, # 0x47 PWM_DUTYCYCLE_CFG6 + 0xFF, # 0x48 PWM_DUTYCYCLE_CFG7 + 0x00, # 0x49 NOT USED + 0x00, # 0x4A NOT USED + 0x00, # 0x4B NOT USED + 0x00, # 0x4C SPO_CFG + CY8CMBRX.IIR_EN, # 0x4D DEVICE_CFG0 + CY8CMBRX.SYSD_EN, # 0x4E DEVICE_CFG1 + CY8CMBRX.ATH_EN | CY8CMBRX.GUARD_EN, # 0x4F DEVICE_CFG2 + 0x00, # 0x50 DEVICE_CFG3 + 0x37, # 0x51 I2C_ADDR don't change this!! + 0x01, # 0x52 REFRESH_CTRL + 0x00, # 0x53 NOT USED + 0x00, # 0x54 NOT USED + 0x0A, # 0x55 STATE_TIMEOUT + 0x00, # 0x56 NOT USED + 0x00, # 0x57 NOT USED + 0x00, # 0x58 NOT USED + 0x00, # 0x59 NOT USED + 0x00, # 0x5A NOT USED + 0x00, # 0x5B NOT USED + 0x00, # 0x5C NOT USED + 0x00, # 0x5D SLIDER_CFG + 0x00, # 0x5E NOT USED + 0x00, # 0x5F NOT USED + 0x00, # 0x60 NOT USED + 0x00, # 0x61 SLIDER1_CFG + 0x00, # 0x62 SLIDER1_RESOLUTION + 0x00, # 0x63 SLIDER1_THRESHOLD + 0x00, # 0x64 NOT USED + 0x00, # 0x65 NOT USED + 0x00, # 0x66 NOT USED + 0x00, # 0x67 SLIDER2_CFG + 0x00, # 0x68 SLIDER2_RESOLUTION + 0x00, # 0x69 SLIDER2_THRESHOLD + 0x00, # 0x6A NOT USED + 0x00, # 0x6B NOT USED + 0x00, # 0x6C NOT USED + 0x00, # 0x6D NOT USED + 0x00, # 0x6E NOT USED + 0x00, # 0x6F NOT USED + 0x00, # 0x70 NOT USED + 0x00, # 0x71 SLIDER_LBR + 0x00, # 0x72 SLIDER_NNT + 0x00, # 0x73 SLIDER_NT + 0x00, # 0x74 NOT USED + 0x00, # 0x75 NOT USED + 0x00, # 0x76 NOT USED + 0x00, # 0x77 NOT USED + 0x00, # 0x78 NOT USED + 0x00, # 0x79 NOT USED + 0x00, # 0x7A SCRATCHPAD0 + 0x00, # 0x7B SCRATCHPAD1 + 0x00, # 0x7C NOT USED + 0x00, # 0x7D NOT USED + # 0x76, #0x7E CRC_LSB - CRC is calculated using 126 bytes above and appended + # 0xBD #0X7F CRC_MSB +] + + +def cy8cmbr3116_init(): + top = I2C(0) + top.scan() + device_crc = top.readfrom_mem(0x37, 0x7E, 2) + # could look for a calibration file and alter the config to apply it + config_crc = cy8cmbr_crc(cy8cmbr3116_config) + if device_crc[0] != config_crc[0] or device_crc[1] != config_crc[1]: + print("configuring touch") + top.writeto_mem(0x37, 0x00, bytes(cy8cmbr3116_config + config_crc)) + top.writeto_mem(0x37, 0x86, bytes([0x02])) + import time + + time.sleep(0.5) + # reset moved to frontboard2026 + # todo eliminate the sleep? it only happens when the ic needs configuring. + + +def cy8cmbr_crc(config): + crc = 0xFFFF + for byte in config: + crc ^= byte << 8 + for _ in range(8): + if crc & 0x8000: + crc = (crc << 1) ^ 0x1021 + else: + crc <<= 1 + crc &= 0xFFFF + result = [crc & 0xFF, crc >> 8] + return result diff --git a/modules/frontboards/cy8cmbrx_defs.py b/modules/frontboards/cy8cmbrx_defs.py new file mode 100644 index 00000000..7586d934 --- /dev/null +++ b/modules/frontboards/cy8cmbrx_defs.py @@ -0,0 +1,94 @@ +class CY8CMBRX: + ADDRESS = 0x37 + + # CS0 enables for SENSOR_EN HIGH, SENSOR_EN LOW and PROX_EN + CS0_ENABLE = 0x01 + CS1_ENABLE = 0x02 + CS2_ENABLE = 0x04 + CS3_ENABLE = 0x08 + CS4_ENABLE = 0x10 + CS5_ENABLE = 0x20 + CS6_ENABLE = 0x40 + CS7_ENABLE = 0x80 + CS8_ENABLE = 0x01 + CS9_ENABLE = 0x02 + CS10_ENABLE = 0x04 + CS11_ENABLE = 0x08 + CS12_ENABLE = 0x10 + CS13_ENABLE = 0x20 + CS14_ENABLE = 0x40 + CS15_ENABLE = 0x80 + + # The SENSITIVITY(0-4) is in counts/(0.1pf*x) + SENS0_X1 = 0x00 + SENS0_X2 = 0x01 + SENS0_X3 = 0x02 + SENS0_X4 = 0x03 + SENS1_X1 = 0x00 + SENS1_X2 = 0x04 + SENS1_X3 = 0x08 + SENS1_X4 = 0x0C + SENS2_X1 = 0x00 + SENS2_X2 = 0x10 + SENS2_X3 = 0x20 + SENS2_X4 = 0x30 + SENS3_X1 = 0x00 + SENS3_X2 = 0x40 + SENS3_X3 = 0x80 + SENS3_X4 = 0xC0 + + # PROX_RESOLUTION + RES_16_BIT = 0x00 + RES_15_BIT = 0x01 + RES_14_BIT = 0x02 + RES_13_BIT = 0x03 + RES_12_BIT = 0x04 + + # DEVICE_CFG0 + MED_EN = 0x01 + IIR_EN = 0x02 + BUTTON_RESET_DISABLED = 0x00 + BUTTON_RESET_ENABLED_TIMEOUT_5S = 0x10 + BUTTON_RESET_ENABLED_TIMEOUT_20S = 0x20 + PROX_RESET_DISABLED = 0x00 + PROX_RESET_ENABLED_TIMEOUT_5S = 0x40 + PROX_RESET_ENABLED_TIMEOUT_20S = 0x80 + + # DEVICE_CFG1 + SYSD_EN = 0x01 + + # DEVICE_CFG2 + SHIELD_EN = 0x01 + GUARD_EN = 0x02 + EMC_EN = 0x04 + ATH_EN = 0x08 + + # DEVICE_CFG3 + SUPPLY_LOW_POWER = 0x01 + + # SPO_CFG + SPO0_DISABLED = 0x00 + SPO0_CAP_SENSE = 0x01 + SPO0_SHIELD = 0x02 + SPO0_BUZZ = 0x03 + SPO0_INTTERUPT = 0x04 + SPO0_GPO = 0x05 + SPO0_DISABLED = 0x00 + SPO1_CAP_SENSE = 0x10 + SPO1_SHIELD = 0x20 + SPO1_BUZZ = 0x30 + SPO1_INTTERUPT = 0x40 + SPO1_GPO = 0x50 + + # commands + CMD_CMP_CRC_SAVE = 0x02 + CMD_CALC_CRC = 0x03 + CMD_LOW_POWER = 0x07 + CMD_RESET_LATCH = 0x08 + CMD_RESET_PS0_FILTER = 0x09 + CMD_RESET_PS1_FILTER = 0x0A + CMD_RESET = 0xFF + CMD_ERR_OK = 0x00 + CMD_ERR_SAVE_FAILED = 0x0D + CMD_ERR_CRC_MISMATCH = 0xFE + CMD_ERR_INVALID_CMD = 0xFF diff --git a/modules/frontboards/twentysix.py b/modules/frontboards/twentysix.py new file mode 100644 index 00000000..3452b496 --- /dev/null +++ b/modules/frontboards/twentysix.py @@ -0,0 +1,282 @@ +import asyncio + +import display +from events.input import Button, BUTTON_TYPES, ButtonDownEvent, ButtonUpEvent +import machine +from system.eventbus import eventbus +from tildagon import ePin +from . import FrontBoard +from system.hexpansion.events import HexpansionInsertionEvent, HexpansionRemovalEvent +import time +import frontboard2026 +from frontboards.utils import detect_frontboard + +try: + from _sim import _sim + + sim = True +except ImportError: + sim = False + + +BUTTONS = { + "A": Button("A", "TwentyTwentySix", BUTTON_TYPES["A"]), + "B": Button("B", "TwentyTwentySix", BUTTON_TYPES["B"]), + "C": Button("C", "TwentyTwentySix", BUTTON_TYPES["C"]), + "D": Button("D", "TwentyTwentySix", BUTTON_TYPES["D"]), + "E": Button("E", "TwentyTwentySix", BUTTON_TYPES["E"]), + "CANCEL": Button("CANCEL", "TwentyTwentySix", BUTTON_TYPES["CANCEL"]), +} + +JOYSTICK = { + "UP": Button("UP", "TwentyTwentySix", BUTTON_TYPES["UP"]), + "DOWN": Button("DOWN", "TwentyTwentySix", BUTTON_TYPES["DOWN"]), + "LEFT": Button("LEFT", "TwentyTwentySix", BUTTON_TYPES["LEFT"]), + "RIGHT": Button("RIGHT", "TwentyTwentySix", BUTTON_TYPES["RIGHT"]), + "CONFIRM": Button("CONFIRM", "TwentyTwentySix", BUTTON_TYPES["CONFIRM"]), +} + + +PROX = { + "LEFTPROX": Button("LEFTPROX", "TwentyTwentySix", BUTTON_TYPES["LEFTPROX"]), + "RIGHTPROX": Button("RIGHTPROX", "TwentyTwentySix", BUTTON_TYPES["RIGHTPROX"]), +} + +TOUCH = { + "TOUCH1": Button("TOUCH1", "TwentyTwentySix", BUTTON_TYPES["TOUCH1"]), + "TOUCH2": Button("TOUCH2", "TwentyTwentySix", BUTTON_TYPES["TOUCH2"]), + "TOUCH3": Button("TOUCH3", "TwentyTwentySix", BUTTON_TYPES["TOUCH3"]), + "TOUCH4": Button("TOUCH4", "TwentyTwentySix", BUTTON_TYPES["TOUCH4"]), + "TOUCH5": Button("TOUCH5", "TwentyTwentySix", BUTTON_TYPES["TOUCH5"]), + "TOUCH6": Button("TOUCH6", "TwentyTwentySix", BUTTON_TYPES["TOUCH6"]), + "TOUCH7": Button("TOUCH7", "TwentyTwentySix", BUTTON_TYPES["TOUCH7"]), + "TOUCH8": Button("TOUCH8", "TwentyTwentySix", BUTTON_TYPES["TOUCH8"]), + "TOUCH9": Button("TOUCH9", "TwentyTwentySix", BUTTON_TYPES["TOUCH9"]), + "TOUCH10": Button("TOUCH10", "TwentyTwentySix", BUTTON_TYPES["TOUCH10"]), + "TOUCH11": Button("TOUCH11", "TwentyTwentySix", BUTTON_TYPES["TOUCH11"]), + "TOUCH12": Button("TOUCH12", "TwentyTwentySix", BUTTON_TYPES["TOUCH12"]), +} + + +def buttondown(epin): + booped = not machine.Pin(0, mode=machine.Pin.IN).value() + hexindex = 1 + for key in TwentyTwentySix.pin_assignment.keys(): + if TwentyTwentySix.pin_assignment[key] is epin: + if booped: + now = time.ticks_ms() + if TwentyTwentySix.hexpansion_states[hexindex] is None: + TwentyTwentySix.hexpansion_states[hexindex] = now + eventbus.emit(HexpansionInsertionEvent(port=hexindex)) + hexindex += 1 + else: + eventbus.emit(ButtonDownEvent(button=BUTTONS[key])) + TwentyTwentySix.button_states[key][0] = True + print(f"{key} down") + + +def buttonup(epin): + for key in TwentyTwentySix.pin_assignment.keys(): + if TwentyTwentySix.pin_assignment[key] is epin: + eventbus.emit(ButtonUpEvent(button=BUTTONS[key])) + TwentyTwentySix.button_states[key][0] = False + TwentyTwentySix.button_states[key][1] = 0 + print(f"{key} up") + + +def joy_down(epin): + for key in TwentyTwentySix.joy_assignment.keys(): + if TwentyTwentySix.joy_assignment[key] is epin: + eventbus.emit(ButtonDownEvent(button=JOYSTICK[key])) + TwentyTwentySix.joystick_states[key][0] = True + print(f"{key} down") + + +def joy_up(epin): + for key in TwentyTwentySix.joy_assignment.keys(): + if TwentyTwentySix.joy_assignment[key] is epin: + eventbus.emit(ButtonUpEvent(button=JOYSTICK[key])) + TwentyTwentySix.joystick_states[key][0] = False + TwentyTwentySix.joystick_states[key][1] = 0 + print(f"{key} up") + + +def prox_down(prox): + for key in TwentyTwentySix.PROX_INPUTS.keys(): + if TwentyTwentySix.PROX_INPUTS[key] is prox: + eventbus.emit(ButtonDownEvent(button=PROX[key])) + print(f"{key} down") + + +def prox_up(prox): + for key in TwentyTwentySix.PROX_INPUTS.keys(): + if TwentyTwentySix.PROX_INPUTS[key] is prox: + eventbus.emit(ButtonUpEvent(button=PROX[key])) + print(f"{key} up") + + +def touch_down(touch): + for key in TwentyTwentySix.TOUCH_INPUTS.keys(): + if TwentyTwentySix.TOUCH_INPUTS[key] is touch: + eventbus.emit(ButtonDownEvent(button=TOUCH[key])) + TwentyTwentySix.touch_states[key][0] = True + print(f"{key} down") + + +def touch_up(touch): + for key in TwentyTwentySix.TOUCH_INPUTS.keys(): + if TwentyTwentySix.TOUCH_INPUTS[key] is touch: + eventbus.emit(ButtonUpEvent(button=TOUCH[key])) + print(f"{key} up") + TwentyTwentySix.touch_states[key][0] = False + TwentyTwentySix.touch_states[key][1] = 0 + + +class TwentyTwentySix(FrontBoard): + JOY_PINS = { + JOYSTICK["UP"]: (2, 6), + JOYSTICK["DOWN"]: (1, 1), + JOYSTICK["LEFT"]: (1, 3), + JOYSTICK["RIGHT"]: (2, 7), + JOYSTICK["CONFIRM"]: (1, 0), + } + BUTTON_PINS = { + BUTTONS["A"]: (3, 10), + BUTTONS["B"]: (3, 9), + BUTTONS["C"]: (3, 8), + BUTTONS["D"]: (3, 13), + BUTTONS["E"]: (3, 12), + BUTTONS["CANCEL"]: (3, 11), + } + PROX_INPUTS = { + "LEFTPROX": frontboard2026.PROX1, + "RIGHTPROX": frontboard2026.PROX2, + } + TOUCH_INPUTS = { + "TOUCH1": frontboard2026.TOUCH1, + "TOUCH2": frontboard2026.TOUCH2, + "TOUCH3": frontboard2026.TOUCH3, + "TOUCH4": frontboard2026.TOUCH4, + "TOUCH5": frontboard2026.TOUCH5, + "TOUCH6": frontboard2026.TOUCH6, + "TOUCH7": frontboard2026.TOUCH7, + "TOUCH8": frontboard2026.TOUCH8, + "TOUCH9": frontboard2026.TOUCH9, + "TOUCH10": frontboard2026.TOUCH10, + "TOUCH11": frontboard2026.TOUCH11, + "TOUCH12": frontboard2026.TOUCH12, + } + + if detect_frontboard() == 0x2601: + JOY_PINS[JOYSTICK["LEFT"]] = (1, 2) + + joy_assignment = {key: None for key in JOYSTICK.keys()} + pin_assignment = {key: None for key in BUTTONS.keys()} + button_states = {key: [False, 0] for key in BUTTONS.keys()} + joystick_states = {key: [False, 0] for key in JOYSTICK.keys()} + touch_states = {key: [False, 0] for key in TOUCH_INPUTS.keys()} + hexpansion_states = {1: None, 2: None, 3: None, 4: None, 5: None, 6: None} + year = 2026 + num_pattern_leds = 12 + + async def background_task(self): + global sim + reset = ePin((3, 7)) + display.gfx_init() + # cy8cmbr3116_init() + reset.off() + reset.on() + + for key in TwentyTwentySix.joy_assignment: + gpio = self.JOY_PINS[JOYSTICK[key]] + TwentyTwentySix.joy_assignment[key] = ePin(gpio) + if not sim: + TwentyTwentySix.joy_assignment[key].irq( + handler=joy_down, trigger=ePin.IRQ_FALLING + ) + TwentyTwentySix.joy_assignment[key].irq( + handler=joy_up, trigger=ePin.IRQ_RISING + ) + + for key in TwentyTwentySix.pin_assignment: + gpio = self.BUTTON_PINS[BUTTONS[key]] + TwentyTwentySix.pin_assignment[key] = ePin(gpio) + if not sim: + TwentyTwentySix.pin_assignment[key].irq( + handler=buttondown, trigger=ePin.IRQ_FALLING + ) + TwentyTwentySix.pin_assignment[key].irq( + handler=buttonup, trigger=ePin.IRQ_RISING + ) + for key in TwentyTwentySix.PROX_INPUTS: + if not sim: + frontboard2026.set_cb( + TwentyTwentySix.PROX_INPUTS[key], + prox_down, + frontboard2026.IRQ_RISING, + ) + frontboard2026.set_cb( + TwentyTwentySix.PROX_INPUTS[key], + prox_up, + frontboard2026.IRQ_FALLING, + ) + for key in TwentyTwentySix.TOUCH_INPUTS: + if not sim: + frontboard2026.set_cb( + TwentyTwentySix.TOUCH_INPUTS[key], + touch_down, + frontboard2026.IRQ_RISING, + ) + frontboard2026.set_cb( + TwentyTwentySix.TOUCH_INPUTS[key], + touch_up, + frontboard2026.IRQ_FALLING, + ) + + while True: + frontboard2026.run() + booped = not machine.Pin(0, mode=machine.Pin.IN).value() + if booped: + now = time.ticks_ms() + for i, gpio in enumerate( + map( + lambda i: self.BUTTON_PINS[BUTTONS[i]], + ["A", "B", "C", "D", "E", "CANCEL"], + ) + ): + state = TwentyTwentySix.hexpansion_states[i + 1] + if state and time.ticks_diff(now, state) > 4000: + TwentyTwentySix.hexpansion_states[i + 1] = None + await eventbus.emit_async(HexpansionRemovalEvent(port=i + 1)) + else: + if sim: + for i, key in enumerate(TwentyTwentySix.button_states.keys()): + button_down = not _sim.buttons.state()[i] + if button_down and not TwentyTwentySix.button_states[key][0]: + await eventbus.emit_async( + ButtonUpEvent(button=BUTTONS[key]) + ) + if not button_down and TwentyTwentySix.button_states[key][0]: + await eventbus.emit_async( + ButtonDownEvent(button=BUTTONS[key]) + ) + TwentyTwentySix.button_states[key][0] = button_down + else: + for key in TwentyTwentySix.button_states.keys(): + if TwentyTwentySix.button_states[key][0]: + if TwentyTwentySix.button_states[key][1] > 4: + await eventbus.emit_async( + ButtonDownEvent(button=BUTTONS[key]) + ) + else: + TwentyTwentySix.button_states[key][1] += 1 + for key in TwentyTwentySix.joystick_states.keys(): + if TwentyTwentySix.joystick_states[key][0]: + if TwentyTwentySix.joystick_states[key][1] > 4: + await eventbus.emit_async( + ButtonDownEvent(button=JOYSTICK[key]) + ) + else: + TwentyTwentySix.joystick_states[key][1] += 1 + + await asyncio.sleep(0.15) diff --git a/modules/frontboards/utils.py b/modules/frontboards/utils.py new file mode 100644 index 00000000..067443f2 --- /dev/null +++ b/modules/frontboards/utils.py @@ -0,0 +1,77 @@ +import vfs +from machine import I2C +from system.hexpansion.util import ( + detect_eeprom_addr, + get_hexpansion_block_devices, + read_hexpansion_header, + HexpansionHeader, +) +from system.hexpansion.header import write_header + + +def populate_fb(h, addr_len): + # Ensure the board isn't mounted + mountpoint = "/frontboard" + + try: + vfs.umount(mountpoint) + except OSError: + pass + + port = 0 + addr = 0x57 + i2c = I2C(port) + + write_header(0, h, 0x57, addr_len=addr_len, page_size=h.eeprom_page_size) + + _, partition = get_hexpansion_block_devices(i2c, h, addr) + + vfs.VfsLfs2.mkfs(partition) + + +detected_frontboard = None + + +def detect_frontboard(): + global detected_frontboard + if detected_frontboard is None: + i2c = I2C(0) + + addr, addr_len = detect_eeprom_addr(i2c) + if addr is not None and addr_len is not None: + header = read_hexpansion_header( + i2c, addr, set_read_addr=True, addr_len=addr_len + ) + + if header is None: + print("detecting frontboard with i2c") + devices = i2c.scan() + if 0x58 in devices and 0x57 in devices: + header = HexpansionHeader( + manifest_version="2026", + fs_offset=32, + eeprom_page_size=32, + eeprom_total_size=1024 * 8, + vid=0xBAD3, + pid=0x2600, + unique_id=0x0, + friendly_name="Spaceagon", + ) + else: + header = HexpansionHeader( + manifest_version="2024", + fs_offset=32, + eeprom_page_size=32, + eeprom_total_size=1024 * 8, + vid=0xBAD3, + pid=0x2400, + unique_id=0x0, + friendly_name="TwentyTwentyFour", + ) + populate_fb(header, 2) + detected_frontboard = header.pid + return detected_frontboard + print("No eeprom detected, defaulting to 2024") + return 0x2400 + + return detected_frontboard diff --git a/modules/main.py b/modules/main.py index 0f77f04c..ab578470 100644 --- a/modules/main.py +++ b/modules/main.py @@ -9,12 +9,24 @@ from system.launcher.app import Launcher from system.power.handler import PowerEventHandler from system.power.app import PowerManager +from frontboards.utils import detect_frontboard +import frontboard2026 -from frontboards.twentyfour import TwentyTwentyFour - +fb = detect_frontboard() +print(hex(fb)) # Start front-board interface -scheduler.start_app(TwentyTwentyFour()) +if (fb & 0xFF00) == 0x2600: + from frontboards.twentysix import TwentyTwentySix + + frontboard2026.init(fb) + scheduler.start_app(TwentyTwentySix()) + print("entering 2026") +else: + from frontboards.twentyfour import TwentyTwentyFour + + scheduler.start_app(TwentyTwentyFour()) + print("entering 2024") # Start expansion interface scheduler.start_app(HexpansionManagerApp()) diff --git a/modules/system/hexpansion/header.py b/modules/system/hexpansion/header.py index e99205b6..e7f2612c 100644 --- a/modules/system/hexpansion/header.py +++ b/modules/system/hexpansion/header.py @@ -70,8 +70,8 @@ def from_bytes(cls, buf, validate_checksum=True): raise RuntimeError("Invalid header length, should be 32") if buf[1:4] != b"HEX": raise RuntimeError(f"Invalid magic in hexpansion header: {buf[0:4]}") - if buf[4:8] != b"2024": - raise RuntimeError("Unknown manifest version. Supported: [2024]") + if buf[4:8] != b"2024" and buf[4:8] != b"2026": + raise RuntimeError("Unknown manifest version. Supported: [2024, 2026]") unpacked = struct.unpack(cls._header_format, buf) if validate_checksum: diff --git a/modules/system/patterndisplay/app.py b/modules/system/patterndisplay/app.py index 1c480999..93728188 100644 --- a/modules/system/patterndisplay/app.py +++ b/modules/system/patterndisplay/app.py @@ -15,6 +15,7 @@ from app_components.utils import path_isfile from firmware_apps.settings_app import PAT_DIR from system.notification.events import ShowNotificationEvent +from frontboards.twentysix import TwentyTwentySix class PatternDisplay(App): @@ -31,6 +32,20 @@ def __init__(self): neopixel.ComposedNeoPixel(tildagonos.leds, -1), [self.correction] * 12 + [None] * 6, ) + self.TOUCH_KEYS = [ + "TOUCH1", + "TOUCH2", + "TOUCH3", + "TOUCH4", + "TOUCH5", + "TOUCH6", + "TOUCH7", + "TOUCH8", + "TOUCH9", + "TOUCH10", + "TOUCH11", + "TOUCH12", + ] def load_pattern(self): self.pattern = settings.get("pattern", ("rainbow", None)) @@ -112,7 +127,10 @@ async def background_task(self): next_frame = self._p.next() if self.enabled: for led in range(12): - self.leds[led] = next_frame[led] + if TwentyTwentySix.touch_states[self.TOUCH_KEYS[led]][0]: + self.leds[led] = (255, 255, 255) + else: + self.leds[led] = next_frame[led] self.leds.write() if not self._p.fps: break diff --git a/scripts/fb2026 config.py b/scripts/fb2026 config.py new file mode 100644 index 00000000..8f6c020f --- /dev/null +++ b/scripts/fb2026 config.py @@ -0,0 +1,276 @@ +# change config in cy8cmbr3116_config then run script on the badge then reset + +import time +#import power +from machine import I2C +from tildagon import ePin + +CY8CMBRX_ADDRESS = 0x37 + +# CS0 enables for SENSOR_EN HIGH, SENSOR_EN LOW and PROX_EN +CY8CMBRX_CS0_ENABLE = 0x01 +CY8CMBRX_CS1_ENABLE = 0x02 +CY8CMBRX_CS2_ENABLE = 0x04 +CY8CMBRX_CS3_ENABLE = 0x08 +CY8CMBRX_CS4_ENABLE = 0x10 +CY8CMBRX_CS5_ENABLE = 0x20 +CY8CMBRX_CS6_ENABLE = 0x40 +CY8CMBRX_CS7_ENABLE = 0x80 +CY8CMBRX_CS8_ENABLE = 0x01 +CY8CMBRX_CS9_ENABLE = 0x02 +CY8CMBRX_CS10_ENABLE = 0x04 +CY8CMBRX_CS11_ENABLE = 0x08 +CY8CMBRX_CS12_ENABLE = 0x10 +CY8CMBRX_CS13_ENABLE = 0x20 +CY8CMBRX_CS14_ENABLE = 0x40 +CY8CMBRX_CS15_ENABLE = 0x80 + +# The SENSITIVITY(0-4) is in counts/(0.1pf*x) +CY8CMBRX_SENS0_X1 = 0x00 +CY8CMBRX_SENS0_X2 = 0x01 +CY8CMBRX_SENS0_X3 = 0x02 +CY8CMBRX_SENS0_X4 = 0x03 +CY8CMBRX_SENS1_X1 = 0x00 +CY8CMBRX_SENS1_X2 = 0x04 +CY8CMBRX_SENS1_X3 = 0x08 +CY8CMBRX_SENS1_X4 = 0x0C +CY8CMBRX_SENS2_X1 = 0x00 +CY8CMBRX_SENS2_X2 = 0x10 +CY8CMBRX_SENS2_X3 = 0x20 +CY8CMBRX_SENS2_X4 = 0x30 +CY8CMBRX_SENS3_X1 = 0x00 +CY8CMBRX_SENS3_X2 = 0x40 +CY8CMBRX_SENS3_X3 = 0x80 +CY8CMBRX_SENS3_X4 = 0xC0 + +#PROX_RESOLUTION +CY8CMBRX_RES_16_BIT = 0x00 +CY8CMBRX_RES_15_BIT = 0x01 +CY8CMBRX_RES_14_BIT = 0x02 +CY8CMBRX_RES_13_BIT = 0x03 +CY8CMBRX_RES_12_BIT = 0x04 + +# DEVICE_CFG0 +CY8CMBRX_MED_EN = 0x01 +CY8CMBRX_IIR_EN = 0x02 +CY8CMBRX_BUTTON_RESET_DISABLED = 0x00 +CY8CMBRX_BUTTON_RESET_ENABLED_TIMEOUT_5S = 0x10 +CY8CMBRX_BUTTON_RESET_ENABLED_TIMEOUT_20S = 0x20 +CY8CMBRX_PROX_RESET_DISABLED = 0x00 +CY8CMBRX_PROX_RESET_ENABLED_TIMEOUT_5S = 0x40 +CY8CMBRX_PROX_RESET_ENABLED_TIMEOUT_20S = 0x80 + +# DEVICE_CFG1 +CY8CMBRX_SYSD_EN = 0x01 + +# DEVICE_CFG2 +CY8CMBRX_SHIELD_EN = 0x01 +CY8CMBRX_GUARD_EN = 0x02 +CY8CMBRX_EMC_EN = 0x04 +CY8CMBRX_ATH_EN = 0x08 + +# DEVICE_CFG3 +CY8CMBRX_SUPPLY_LOW_POWER = 0x01 + +# SPO_CFG +CY8CMBRX_SPO0_DISABLED = 0x00 +CY8CMBRX_SPO0_CAP_SENSE = 0x01 +CY8CMBRX_SPO0_SHIELD = 0x02 +CY8CMBRX_SPO0_BUZZ = 0x03 +CY8CMBRX_SPO0_INTTERUPT = 0x04 +CY8CMBRX_SPO0_GPO = 0x05 +CY8CMBRX_SPO0_DISABLED = 0x00 +CY8CMBRX_SPO1_CAP_SENSE = 0x10 +CY8CMBRX_SPO1_SHIELD = 0x20 +CY8CMBRX_SPO1_BUZZ = 0x30 +CY8CMBRX_SPO1_INTTERUPT = 0x40 +CY8CMBRX_SPO1_GPO = 0x50 + + +# commands +CY8CMBRX_CMD_CMP_CRC_SAVE = 0x02 +CY8CMBRX_CMD_CALC_CRC = 0x03 +CY8CMBRX_CMD_LOW_POWER = 0x07 +CY8CMBRX_CMD_RESET_LATCH = 0x08 +CY8CMBRX_CMD_RESET_PS0_FILTER = 0x09 +CY8CMBRX_CMD_RESET_PS1_FILTER = 0x0A +CY8CMBRX_CMD_RESET = 0xFF +CY8CMBRX_CMD_ERR_OK = 0x00 +CY8CMBRX_CMD_ERR_SAVE_FAILED = 0x0D +CY8CMBRX_CMD_ERR_CRC_MISMATCH = 0xFE +CY8CMBRX_CMD_ERR_INVALID_CMD = 0xFF + +#intending on using these as versioning +CY8CMBRX_SCRATCHPAD0 = 0x00 +CY8CMBRX_SCRATCHPAD1 = 0x00 + +# follow section 6 of https://www.infineon.com/assets/row/public/documents/30/42/infineon-an90071-cy8cmbr3xxx-capsenser-design-guide-applicationnotes-en.pdf +# to configure this. +cy8cmbr3116_config = [ +CY8CMBRX_CS0_ENABLE | CY8CMBRX_CS1_ENABLE | CY8CMBRX_CS2_ENABLE | CY8CMBRX_CS3_ENABLE | CY8CMBRX_CS4_ENABLE | CY8CMBRX_CS5_ENABLE | CY8CMBRX_CS6_ENABLE | CY8CMBRX_CS7_ENABLE, #0x00 SENSOR_EN LSB +CY8CMBRX_CS8_ENABLE | CY8CMBRX_CS9_ENABLE | CY8CMBRX_CS10_ENABLE | CY8CMBRX_CS11_ENABLE | CY8CMBRX_CS12_ENABLE | CY8CMBRX_CS13_ENABLE | CY8CMBRX_CS14_ENABLE, #0x01 SENSOR_EN MSB +0x00,#CY8CMBRX_CS3_ENABLE | CY8CMBRX_CS4_ENABLE | CY8CMBRX_CS5_ENABLE | CY8CMBRX_CS6_ENABLE | CY8CMBRX_CS7_ENABLE, #0x02 FSS_EN LSB +0x00,#CY8CMBRX_CS8_ENABLE | CY8CMBRX_CS9_ENABLE | CY8CMBRX_CS10_ENABLE | CY8CMBRX_CS11_ENABLE | CY8CMBRX_CS12_ENABLE | CY8CMBRX_CS13_ENABLE | CY8CMBRX_CS14_ENABLE, #0x03 FSS_EN MSB +0x00, #0x04 TOGGLE_EN LSB +0x00, #0x05 TOGGLE_EN MSB +0x00, #0x06 LED_ON_EN LSB +0x00, #0x07 LED_ON_EN MSB +CY8CMBRX_SENS2_X1 | CY8CMBRX_SENS3_X2, #0x08 SENSITIVITY0 lower X higher sensitivity (less capacitance) +CY8CMBRX_SENS0_X3 | CY8CMBRX_SENS1_X4 | CY8CMBRX_SENS2_X1 | CY8CMBRX_SENS3_X2, #0x09 SENSITIVITY1 +CY8CMBRX_SENS0_X3 | CY8CMBRX_SENS1_X4 | CY8CMBRX_SENS2_X1 | CY8CMBRX_SENS3_X4, #0x0A SENSITIVITY2 +CY8CMBRX_SENS0_X4 | CY8CMBRX_SENS1_X4 | CY8CMBRX_SENS2_X4, #0x0B SENSITIVITY3 +0x80, #0x0C BASE_THRESHOLD0 +0x80, #0x0D BASE_THRESHOLD1 +0x80, #0x0E FINGER_THRESHOLD2 +0x80, #0x0F FINGER_THRESHOLD3 +0x80, #0x10 FINGER_THRESHOLD4 +0x80, #0x11 FINGER_THRESHOLD5 +0x80, #0x12 FINGER_THRESHOLD6 +0x80, #0x13 FINGER_THRESHOLD7 +0x80, #0x14 FINGER_THRESHOLD8 +0x80, #0x15 FINGER_THRESHOLD9 +0x80, #0x16 FINGER_THRESHOLD10 +0x80, #0x17 FINGER_THRESHOLD11 +0x80, #0x18 FINGER_THRESHOLD12 +0x80, #0x19 FINGER_THRESHOLD13 +0x80, #0x1A FINGER_THRESHOLD14 +0x7F, #0x1B FINGER_THRESHOLD15 +0x03, #0x1C SENSOR_DEBOUNCE +0x00, #0x1D BUTTON_HYS +0x00, #0x1E NOT USED +0x00, #0x1F BUTTON_LBR +0x00, #0x20 BUTTON_NNT +0x00, #0x21 BUTTON_NT +0x00, #0x22 NOT USED +0x00, #0x23 NOT USED +0x00, #0x24 NOT USED +0x00, #0x25 NOT USED +CY8CMBRX_CS0_ENABLE | CY8CMBRX_CS1_ENABLE, #0x26 PROX_EN +0x00, #0x27 PROX_CFG +0x06, #0x28 PROX_CFG2 +0x00, #0x29 NOT USED +0x00, #0x2A PROX_TOUCH_TH0 LSB +0x02, #0x2B PROX_TOUCH_TH0 MSB +0x00, #0x2C PROX_TOUCH_TH1 LSB +0x02, #0x2D PROX_TOUCH_TH1 MSB +CY8CMBRX_RES_12_BIT, #0x2E PROX_RESOLUTION0 +CY8CMBRX_RES_12_BIT, #0x2F PROX_RESOLUTION1 +0x00, #0x30 PROX_HYS +0x00, #0x31 NOT USED +0x00, #0x32 PROX_LBR +0x00, #0x33 PROX_NNT +0x00, #0x34 PROX_NT +0x1E, #0x35 PROX_POSITIVE_TH0 +0x1E, #0x36 PROX_POSITIVE_TH1 +0x00, #0x37 NOT USED +0x00, #0x38 NOT USED +0x1E, #0x39 PROX_NEGATIVE_TH0 +0x1E, #0x3A PROX_NEGATIVE_TH1 +0x00, #0x3B NOT USED +0x00, #0x3C NOT USED +0x00, #0x3D LED_ON_TIME +0x01, #0x3E BUZZER_CFG +0x01, #0x3F BUZZER_ON_TIME +0x00, #0x40 GPO_CFG +0xFF, #0x41 PWM_DUTYCYCLE_CFG0 +0xFF, #0x42 PWM_DUTYCYCLE_CFG1 +0xFF, #0x43 PWM_DUTYCYCLE_CFG2 +0xFF, #0x44 PWM_DUTYCYCLE_CFG3 +0xFF, #0x45 PWM_DUTYCYCLE_CFG4 +0xFF, #0x46 PWM_DUTYCYCLE_CFG5 +0xFF, #0x47 PWM_DUTYCYCLE_CFG6 +0xFF, #0x48 PWM_DUTYCYCLE_CFG7 +0x00, #0x49 NOT USED +0x00, #0x4A NOT USED +0x00, #0x4B NOT USED +0x00, #0x4C SPO_CFG +CY8CMBRX_IIR_EN, #0x4D DEVICE_CFG0 +CY8CMBRX_SYSD_EN, #0x4E DEVICE_CFG1 +CY8CMBRX_ATH_EN,# | CY8CMBRX_GUARD_EN, #0x4F DEVICE_CFG2 +0x00, #0x50 DEVICE_CFG3 +0x37, #0x51 I2C_ADDR don't change this!! +0x01, #0x52 REFRESH_CTRL +0x00, #0x53 NOT USED +0x00, #0x54 NOT USED +0x0A, #0x55 STATE_TIMEOUT +0x00, #0x56 NOT USED +0x00, #0x57 NOT USED +0x00, #0x58 NOT USED +0x00, #0x59 NOT USED +0x00, #0x5A NOT USED +0x00, #0x5B NOT USED +0x00, #0x5C NOT USED +0x00, #0x5D SLIDER_CFG +0x00, #0x5E NOT USED +0x00, #0x5F NOT USED +0x00, #0x60 NOT USED +0x00, #0x61 SLIDER1_CFG +0x00, #0x62 SLIDER1_RESOLUTION +0x00, #0x63 SLIDER1_THRESHOLD +0x00, #0x64 NOT USED +0x00, #0x65 NOT USED +0x00, #0x66 NOT USED +0x00, #0x67 SLIDER2_CFG +0x00, #0x68 SLIDER2_RESOLUTION +0x00, #0x69 SLIDER2_THRESHOLD +0x00, #0x6A NOT USED +0x00, #0x6B NOT USED +0x00, #0x6C NOT USED +0x00, #0x6D NOT USED +0x00, #0x6E NOT USED +0x00, #0x6F NOT USED +0x00, #0x70 NOT USED +0x00, #0x71 SLIDER_LBR +0x00, #0x72 SLIDER_NNT +0x00, #0x73 SLIDER_NT +0x00, #0x74 NOT USED +0x00, #0x75 NOT USED +0x00, #0x76 NOT USED +0x00, #0x77 NOT USED +0x00, #0x78 NOT USED +0x00, #0x79 NOT USED +0x00, #0x7A SCRATCHPAD0 +0x00, #0x7B SCRATCHPAD1 +0x00, #0x7C NOT USED +0x00, #0x7D NOT USED +#0x76, #0x7E CRC_LSB - CRC is calculated using 126 bytes above and appended +#0xBD #0X7F CRC_MSB +] + +def cy8cmbr3116_init(): + top = I2C(0) + top.scan() + device_crc = top.readfrom_mem(0x37, 0x7E, 2) + # could look for a calibration file and alter the config to apply it + config_crc = cy8cmbr_crc(cy8cmbr3116_config) + if device_crc[0] != config_crc[0] or device_crc[1] != config_crc[1]: + print ("configuring touch") + try: + top.writeto_mem(0x37, 0x00, bytes(cy8cmbr3116_config + config_crc)) + top.writeto_mem(0x37, 0x86, bytes([0x02])) + except: + print("i2c write failed") + else: + print("touch already configured") + + +def cy8cmbr_crc( config ): + crc = 0xFFFF + for byte in config: + crc ^= (byte << 8) + for _ in range(8): + if crc & 0x8000: + crc = (crc << 1) ^ 0x1021 + else: + crc <<= 1 + crc &= 0xFFFF + result = [ crc & 0xFF, crc >> 8 ] + return result + + +reset = ePin((3, 7)) +cy8cmbr3116_init() +time.sleep(0.5) +reset.off() +reset.on() +#power.Off()