diff --git a/drivers/ioexpander/ioexpander.cpp b/drivers/ioexpander/ioexpander.cpp index 30d10574..dd98a1ea 100644 --- a/drivers/ioexpander/ioexpander.cpp +++ b/drivers/ioexpander/ioexpander.cpp @@ -320,8 +320,21 @@ namespace pimoroni { Pin::adc(1, 7, 0)} {} - bool IOExpander::init(bool skipChipIdCheck) { - bool succeeded = true; + bool IOExpander::init(bool skipChipIdCheck, bool perform_reset) { + if(!skipChipIdCheck) { + uint16_t chip_id = get_chip_id(); + if(chip_id != CHIP_ID) { + if(debug) { + printf("Chip ID invalid: %04x expected: %04x\n", chip_id, CHIP_ID); + } + return false; + } + } + + // Reset the chip if requested, to put it into a known state + if(perform_reset && !reset()) { + return false; + } if(interrupt != PIN_UNUSED) { gpio_set_function(interrupt, GPIO_FUNC_SIO); @@ -331,17 +344,36 @@ namespace pimoroni { enable_interrupt_out(true); } - if(!skipChipIdCheck) { - uint16_t chip_id = get_chip_id(); - if(chip_id != CHIP_ID) { - if(debug) { - printf("Chip ID invalid: %04x expected: %04x\n", chip_id, CHIP_ID); - } - succeeded = false; + return true; + } + + uint8_t IOExpander::check_reset() { + uint8_t user_flash_reg = reg::USER_FLASH; + uint8_t value; + if(i2c_write_blocking(i2c->get_i2c(), address, &user_flash_reg, 1, false) == PICO_ERROR_GENERIC) { + return 0x00; + } + if(i2c_read_blocking(i2c->get_i2c(), address, (uint8_t *)&value, sizeof(uint8_t), false) == PICO_ERROR_GENERIC) { + return 0x00; + } + + return value; + } + + bool IOExpander::reset() { + uint32_t start_time = millis(); + set_bits(reg::CTRL, ctrl_mask::RESET); + // Wait for a register to read its initialised value + while(check_reset() != 0x78) { + sleep_ms(1); + if(millis() - start_time >= timeout) { + if(debug) + printf("Timed out waiting for Reset!"); + return false; } } - return succeeded; + return true; } i2c_inst_t* IOExpander::get_i2c() const { diff --git a/drivers/ioexpander/ioexpander.hpp b/drivers/ioexpander/ioexpander.hpp index eb4809d1..3143ab38 100644 --- a/drivers/ioexpander/ioexpander.hpp +++ b/drivers/ioexpander/ioexpander.hpp @@ -171,7 +171,12 @@ namespace pimoroni { // Methods //-------------------------------------------------- public: - bool init(bool skip_chip_id_check = false); + bool init(bool skip_chip_id_check = false, bool perform_reset = false); + + private: + uint8_t check_reset(); + public: + bool reset(); // For print access in micropython i2c_inst_t* get_i2c() const; diff --git a/libraries/breakout_encoder_wheel/breakout_encoder_wheel.cpp b/libraries/breakout_encoder_wheel/breakout_encoder_wheel.cpp index 29d1464e..a1e684eb 100644 --- a/libraries/breakout_encoder_wheel/breakout_encoder_wheel.cpp +++ b/libraries/breakout_encoder_wheel/breakout_encoder_wheel.cpp @@ -6,35 +6,29 @@ namespace pimoroni { bool BreakoutEncoderWheel::init(bool skip_chip_id_check) { bool success = false; - if(ioe.init(skip_chip_id_check)) { + if(ioe.init(skip_chip_id_check, true) && led_ring.init()) { - if(interrupt_pin != PIN_UNUSED) { - ioe.enable_interrupt_out(true); - } - - ioe.setup_rotary_encoder(ENC_CHANNEL, ENC_TERM_A, ENC_TERM_B); - - if(led_ring.init()) { - led_ring.enable({ - 0b00000000, 0b10111111, - 0b00111110, 0b00111110, - 0b00111111, 0b10111110, - 0b00000111, 0b10000110, - 0b00110000, 0b00110000, - 0b00111111, 0b10111110, - 0b00111111, 0b10111110, - 0b01111111, 0b11111110, - 0b01111111, 0b00000000 - }, 0); - - success = true; - } + ioe.setup_rotary_encoder(ENC_CHANNEL, ENC_TERM_A, ENC_TERM_B, 0, true); // count microsteps ioe.set_mode(SW_UP, IOExpander::PIN_IN_PU); ioe.set_mode(SW_DOWN, IOExpander::PIN_IN_PU); ioe.set_mode(SW_LEFT, IOExpander::PIN_IN_PU); ioe.set_mode(SW_RIGHT, IOExpander::PIN_IN_PU); ioe.set_mode(SW_CENTRE, IOExpander::PIN_IN_PU); + + led_ring.enable({ + 0b00000000, 0b10111111, + 0b00111110, 0b00111110, + 0b00111111, 0b10111110, + 0b00000111, 0b10000110, + 0b00110000, 0b00110000, + 0b00111111, 0b10111110, + 0b00111111, 0b10111110, + 0b01111111, 0b11111110, + 0b01111111, 0b00000000 + }, 0); + + success = true; } return success; @@ -67,7 +61,7 @@ namespace pimoroni { void BreakoutEncoderWheel::set_ioe_address(uint8_t address) { ioe.set_address(address); } - + bool BreakoutEncoderWheel::get_interrupt_flag() { return ioe.get_interrupt_flag(); } @@ -93,36 +87,50 @@ namespace pimoroni { } } - int BreakoutEncoderWheel::count() { - return 0; // TODO + int16_t BreakoutEncoderWheel::count() { + take_encoder_reading(); + return enc_count; } - int BreakoutEncoderWheel::delta() { - return 0; // TODO - } + int16_t BreakoutEncoderWheel::delta() { + take_encoder_reading(); - int BreakoutEncoderWheel::step() { - return 0; // TODO - } + // Determine the change in counts since the last time this function was performed + int16_t change = enc_count - last_delta_count; + last_delta_count = enc_count; - int BreakoutEncoderWheel::turn() { - return 0; // TODO + return change; } void BreakoutEncoderWheel::zero() { + ioe.clear_rotary_encoder(ENC_CHANNEL); + enc_count = 0; + enc_step = 0; + enc_turn = 0; + last_raw_count = 0; + last_delta_count = 0; + } + int16_t BreakoutEncoderWheel::step() { + take_encoder_reading(); + return enc_step; + } + + int16_t BreakoutEncoderWheel::turn() { + take_encoder_reading(); + return enc_turn; } float BreakoutEncoderWheel::revolutions() { - return 0; // TODO + return (float)count() / (float)ENC_COUNTS_PER_REV; } float BreakoutEncoderWheel::degrees() { - return 0; // TODO + return revolutions() * 360.0f; } float BreakoutEncoderWheel::radians() { - return 0; // TODO + return revolutions() * M_PI * 2.0f; } Direction BreakoutEncoderWheel::direction() { @@ -209,19 +217,31 @@ namespace pimoroni { return 0; // TODO } - /* - bool BreakoutEncoderWheel::wheel_available() { - return (ioe.get_interrupt_flag() > 0); - } + void BreakoutEncoderWheel::take_encoder_reading() { + // Read the current count + int16_t raw_count = ioe.read_rotary_encoder(ENC_CHANNEL) / ENC_COUNT_DIVIDER; + int16_t raw_change = raw_count - last_raw_count; + last_raw_count = raw_count; - int16_t BreakoutEncoderWheel::read_wheel() { - //int16_t count = ioe.read_rotary_encoder(ENC_CHANNEL); - //if(direction != DIRECTION_CW) - // count = 0 - count; + // Invert the change + if(enc_direction == REVERSED_DIR) { + raw_change = 0 - raw_change; + } - ioe.clear_interrupt_flag(); - //return count; - return 0; + enc_count += raw_change; + + enc_step += raw_change; + if(raw_change > 0) { + while(enc_step >= ENC_COUNTS_PER_REV) { + enc_step -= ENC_COUNTS_PER_REV; + enc_turn += 1; + } + } + else if(raw_change < 0) { + while(enc_step < 0) { + enc_step += ENC_COUNTS_PER_REV; + enc_turn -= 1; + } + } } - */ } \ No newline at end of file diff --git a/libraries/breakout_encoder_wheel/breakout_encoder_wheel.hpp b/libraries/breakout_encoder_wheel/breakout_encoder_wheel.hpp index df8f95b9..378813ea 100644 --- a/libraries/breakout_encoder_wheel/breakout_encoder_wheel.hpp +++ b/libraries/breakout_encoder_wheel/breakout_encoder_wheel.hpp @@ -29,6 +29,8 @@ namespace pimoroni { static const uint8_t ENC_CHANNEL = 1; static const uint8_t ENC_TERM_A = 12; static const uint8_t ENC_TERM_B = 3; + static const uint8_t ENC_COUNTS_PER_REV = 24; + static const uint8_t ENC_COUNT_DIVIDER = 2; static const uint8_t SW_UP = 13; static const uint8_t SW_DOWN = 4; @@ -73,9 +75,14 @@ namespace pimoroni { private: IOExpander ioe; IS31FL3731 led_ring; - //Direction direction = DEFAULT_DIRECTION; - uint interrupt_pin = PIN_UNUSED; // A local copy of the value passed to the IOExpander, used in initialisation + Direction enc_direction = DEFAULT_DIRECTION; + int16_t enc_count = 0; + int16_t enc_step = 0; + int16_t enc_turn = 0; + int16_t last_raw_count = 0; + int16_t last_delta_count = 0; + //-------------------------------------------------- // Constructors/Destructor @@ -109,11 +116,11 @@ namespace pimoroni { // Encoder breakout specific bool pressed(uint button); - int count(); - int delta(); - int step(); - int turn(); + int16_t count(); + int16_t delta(); void zero(); + int16_t step(); + int16_t turn(); float revolutions(); float degrees(); float radians(); @@ -131,6 +138,9 @@ namespace pimoroni { void gpio_pin_value(int gpio, int value, bool load = true, bool wait_for_load = false); void gpio_pwm_load(bool wait_for_load = false); int gpio_pwm_frequency(float frequency, bool load = true, bool wait_for_load = false); + + private: + void take_encoder_reading(); }; } \ No newline at end of file diff --git a/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.c b/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.c index dabb5301..06e1de3c 100644 --- a/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.c +++ b/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.c @@ -5,7 +5,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// /***** Methods *****/ -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoderWheel_set_address_obj, 2, BreakoutEncoderWheel_set_address); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoderWheel_set_ioe_address_obj, 2, BreakoutEncoderWheel_set_ioe_address); MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoderWheel_get_interrupt_flag_obj, BreakoutEncoderWheel_get_interrupt_flag); MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoderWheel_clear_interrupt_flag_obj, BreakoutEncoderWheel_clear_interrupt_flag); @@ -32,7 +32,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoderWheel_gpio_pwm_frequency_obj, 2, Break /***** Binding of Methods *****/ STATIC const mp_rom_map_elem_t BreakoutEncoderWheel_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_set_address), MP_ROM_PTR(&BreakoutEncoderWheel_set_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_ioe_address), MP_ROM_PTR(&BreakoutEncoderWheel_set_ioe_address_obj) }, { MP_ROM_QSTR(MP_QSTR_get_interrupt_flag), MP_ROM_PTR(&BreakoutEncoderWheel_get_interrupt_flag_obj) }, { MP_ROM_QSTR(MP_QSTR_clear_interrupt_flag), MP_ROM_PTR(&BreakoutEncoderWheel_clear_interrupt_flag_obj) }, @@ -92,7 +92,7 @@ STATIC const mp_rom_map_elem_t breakout_encoder_wheel_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_encoder_wheel) }, { MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutEncoderWheel), (mp_obj_t)&breakout_encoder_wheel_BreakoutEncoderWheel_type }, - { MP_ROM_QSTR(MP_QSTR_I2C_ADDR), MP_ROM_INT(0x13) }, + { MP_ROM_QSTR(MP_QSTR_DEFAULT_IOE_I2C_ADDR), MP_ROM_INT(0x13) }, { MP_ROM_QSTR(MP_QSTR_DEFAULT_LED_I2C_ADDR), MP_ROM_INT(0x77) }, { MP_ROM_QSTR(MP_QSTR_ALTERNATE_LED_I2C_ADDR), MP_ROM_INT(0x74) }, diff --git a/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.cpp b/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.cpp index 809848ed..c3b678b5 100644 --- a/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.cpp +++ b/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.cpp @@ -48,7 +48,7 @@ mp_obj_t BreakoutEncoderWheel_make_new(const mp_obj_type_t *type, size_t n_args, } /***** Methods *****/ -mp_obj_t BreakoutEncoderWheel_set_address(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t BreakoutEncoderWheel_set_ioe_address(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_self, ARG_address }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, diff --git a/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.h b/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.h index c03926f2..069e5126 100644 --- a/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.h +++ b/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.h @@ -6,7 +6,7 @@ extern const mp_obj_type_t breakout_encoder_wheel_BreakoutEncoderWheel_type; /***** Extern of Class Methods *****/ extern mp_obj_t BreakoutEncoderWheel_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); -extern mp_obj_t BreakoutEncoderWheel_set_address(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutEncoderWheel_set_ioe_address(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t BreakoutEncoderWheel_get_interrupt_flag(mp_obj_t self_in); extern mp_obj_t BreakoutEncoderWheel_clear_interrupt_flag(mp_obj_t self_in);