kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Micropython bindings for IOExpander breakout
rodzic
31edcf8f93
commit
d45a92fef3
|
@ -334,8 +334,11 @@ namespace pimoroni {
|
|||
gpio_set_function(sda, GPIO_FUNC_I2C); gpio_pull_up(sda);
|
||||
gpio_set_function(scl, GPIO_FUNC_I2C); gpio_pull_up(scl);
|
||||
|
||||
if(interrupt != -1) {
|
||||
gpio_set_function(interrupt, GPIO_FUNC_SIO); gpio_set_dir(interrupt, GPIO_IN); gpio_pull_up(interrupt);
|
||||
if(interrupt != PIN_UNUSED) {
|
||||
gpio_set_function(interrupt, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(interrupt, GPIO_IN);
|
||||
gpio_pull_up(interrupt);
|
||||
|
||||
enable_interrupt_out(true);
|
||||
}
|
||||
|
||||
|
@ -398,11 +401,11 @@ namespace pimoroni {
|
|||
clr_bit(reg::INT, int_bit::OUT_EN);
|
||||
}
|
||||
|
||||
uint8_t IOExpander::get_interrupt_flag() {
|
||||
if(interrupt != 0)
|
||||
bool IOExpander::get_interrupt_flag() {
|
||||
if(interrupt != PIN_UNUSED)
|
||||
return !gpio_get(interrupt);
|
||||
else
|
||||
return get_bit(reg::INT, int_bit::TRIGD);
|
||||
return (get_bit(reg::INT, int_bit::TRIGD) != 0);
|
||||
}
|
||||
|
||||
void IOExpander::clear_interrupt_flag() {
|
||||
|
@ -421,21 +424,14 @@ namespace pimoroni {
|
|||
return succeeded;
|
||||
}
|
||||
|
||||
void IOExpander::set_interrupt_callback(void (*callback)()) {
|
||||
if(interrupt != 0 && callback != nullptr) {
|
||||
//attachInterrupt(digitalPinToInterrupt(_interruptPin), callback, FALLING);
|
||||
clear_interrupt_flag();
|
||||
}
|
||||
}
|
||||
|
||||
void IOExpander::pwm_load(bool wait_for_load) {
|
||||
//Load new period and duty registers into buffer
|
||||
// Load new period and duty registers into buffer
|
||||
uint32_t start_time = millis();
|
||||
set_bit(reg::PWMCON0, 6); //Set the "LOAD" bit of PWMCON0
|
||||
set_bit(reg::PWMCON0, 6); // Set the "LOAD" bit of PWMCON0
|
||||
|
||||
if(wait_for_load) {
|
||||
while(pwm_loading()) {
|
||||
sleep_ms(1); //Wait for "LOAD" to complete
|
||||
sleep_ms(1); // Wait for "LOAD" to complete
|
||||
if(millis() - start_time >= timeout) {
|
||||
if(debug)
|
||||
printf("Timed out waiting for PWM load!");
|
||||
|
@ -451,10 +447,10 @@ namespace pimoroni {
|
|||
|
||||
void IOExpander::pwm_clear(bool wait_for_clear) {
|
||||
uint32_t start_time = millis();
|
||||
set_bit(reg::PWMCON0, 4); //Set the "CLRPWM" bit of PWMCON0
|
||||
set_bit(reg::PWMCON0, 4); // Set the "CLRPWM" bit of PWMCON0
|
||||
if(wait_for_clear) {
|
||||
while(pwm_clearing()) {
|
||||
sleep_ms(1); //Wait for "CLRPWM" to complete
|
||||
sleep_ms(1); // Wait for "CLRPWM" to complete
|
||||
if(millis() - start_time >= timeout) {
|
||||
if(debug)
|
||||
printf("Timed out waiting for PWM clear!");
|
||||
|
@ -491,10 +487,10 @@ namespace pimoroni {
|
|||
|
||||
if(divider_good) {
|
||||
//TODO: This currently sets GP, PWMTYP and FBINEN to 0
|
||||
//It might be desirable to make these available to the user
|
||||
//GP - Group mode enable (changes first three pairs of pAM to PWM01H and PWM01L)
|
||||
//PWMTYP - PWM type select: 0 edge-aligned, 1 center-aligned
|
||||
//FBINEN - Fault-break input enable
|
||||
// It might be desirable to make these available to the user
|
||||
// GP - Group mode enable (changes first three pairs of pAM to PWM01H and PWM01L)
|
||||
// PWMTYP - PWM type select: 0 edge-aligned, 1 center-aligned
|
||||
// FBINEN - Fault-break input enable
|
||||
|
||||
i2c_reg_write_uint8(reg::PWMCON1, pwmdiv2);
|
||||
}
|
||||
|
@ -512,12 +508,16 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
uint8_t IOExpander::get_mode(uint8_t pin) {
|
||||
if(pin < 1 || pin > NUM_PINS) {
|
||||
printf("ValueError: Pin should be in range 1-14.\n");
|
||||
return UINT8_MAX;
|
||||
}
|
||||
|
||||
return pins[pin - 1].get_mode();
|
||||
}
|
||||
|
||||
void IOExpander::set_mode(uint8_t pin, uint8_t mode, bool schmitt_trigger, bool invert) {
|
||||
if(pin < 1 || pin > NUM_PINS)
|
||||
{
|
||||
if(pin < 1 || pin > NUM_PINS) {
|
||||
printf("ValueError: Pin should be in range 1-14.\n");
|
||||
return;
|
||||
}
|
||||
|
@ -527,7 +527,7 @@ namespace pimoroni {
|
|||
uint8_t gpio_mode = mode & 0b11;
|
||||
uint8_t io_type = (mode >> 2) & 0b11;
|
||||
uint8_t initial_state = mode >> 4;
|
||||
|
||||
|
||||
if(io_pin.get_mode() == mode) {
|
||||
if(debug) {
|
||||
printf("Mode already is %s\n", MODE_NAMES[io_type]);
|
||||
|
@ -550,7 +550,7 @@ namespace pimoroni {
|
|||
if(mode == PIN_MODE_PWM) {
|
||||
set_bit(io_pin.reg_io_pwm, io_pin.pwm_channel);
|
||||
change_bit(reg::PNP, io_pin.pwm_channel, invert);
|
||||
set_bit(reg::PWMCON0, 7); //Set PWMRUN bit
|
||||
set_bit(reg::PWMCON0, 7); // Set PWMRUN bit
|
||||
}
|
||||
else {
|
||||
if(io_pin.get_type() & Pin::TYPE_PWM)
|
||||
|
@ -560,28 +560,27 @@ namespace pimoroni {
|
|||
uint8_t pm1 = i2c_reg_read_uint8(io_pin.reg_m1);
|
||||
uint8_t pm2 = i2c_reg_read_uint8(io_pin.reg_m2);
|
||||
|
||||
//Clear the pm1 and pm2 bits
|
||||
// Clear the pm1 and pm2 bits
|
||||
pm1 &= 255 - (1 << io_pin.pin);
|
||||
pm2 &= 255 - (1 << io_pin.pin);
|
||||
|
||||
//Set the new pm1 and pm2 bits according to our gpio_mode
|
||||
// Set the new pm1 and pm2 bits according to our gpio_mode
|
||||
pm1 |= (gpio_mode >> 1) << io_pin.pin;
|
||||
pm2 |= (gpio_mode & 0b1) << io_pin.pin;
|
||||
|
||||
i2c_reg_write_uint8(io_pin.reg_m1, pm1);
|
||||
i2c_reg_write_uint8(io_pin.reg_m2, pm2);
|
||||
|
||||
//Set up Schmitt trigger mode on inputs
|
||||
// Set up Schmitt trigger mode on inputs
|
||||
if(mode == PIN_MODE_PU || mode == PIN_MODE_IN)
|
||||
change_bit(io_pin.reg_ps, io_pin.pin, schmitt_trigger);
|
||||
|
||||
//5th bit of mode encodes default output pin state
|
||||
// 5th bit of mode encodes default output pin state
|
||||
i2c_reg_write_uint8(io_pin.reg_p, (initial_state << 3) | io_pin.pin);
|
||||
}
|
||||
|
||||
int16_t IOExpander::input(uint8_t pin, uint32_t adc_timeout) {
|
||||
if(pin < 1 || pin > NUM_PINS)
|
||||
{
|
||||
if(pin < 1 || pin > NUM_PINS) {
|
||||
if(debug)
|
||||
printf("ValueError: Pin should be in range 1-14.\n");
|
||||
return -1;
|
||||
|
@ -600,10 +599,10 @@ namespace pimoroni {
|
|||
set_bit(reg::AINDIDS, io_pin.adc_channel);
|
||||
set_bit(reg::ADCCON1, 0);
|
||||
|
||||
clr_bit(reg::ADCCON0, 7); //ADCF - Clear the conversion complete flag
|
||||
set_bit(reg::ADCCON0, 6); //ADCS - Set the ADC conversion start flag
|
||||
clr_bit(reg::ADCCON0, 7); // ADCF - Clear the conversion complete flag
|
||||
set_bit(reg::ADCCON0, 6); // ADCS - Set the ADC conversion start flag
|
||||
|
||||
//Wait for the ADCF conversion complete flag to be set
|
||||
// Wait for the ADCF conversion complete flag to be set
|
||||
unsigned long start_time = millis();
|
||||
while(!get_bit(reg::ADCCON0, 7)) {
|
||||
sleep_ms(10);
|
||||
|
@ -629,8 +628,7 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
float IOExpander::input_as_voltage(uint8_t pin, uint32_t adc_timeout) {
|
||||
if(pin < 1 || pin > NUM_PINS)
|
||||
{
|
||||
if(pin < 1 || pin > NUM_PINS) {
|
||||
if(debug)
|
||||
printf("ValueError: Pin should be in range 1-14.\n");
|
||||
return -1;
|
||||
|
@ -650,10 +648,10 @@ namespace pimoroni {
|
|||
set_bit(reg::ADCCON1, 0);
|
||||
|
||||
|
||||
clr_bit(reg::ADCCON0, 7); //ADCF - Clear the conversion complete flag
|
||||
set_bit(reg::ADCCON0, 6); //ADCS - Set the ADC conversion start flag
|
||||
clr_bit(reg::ADCCON0, 7); // ADCF - Clear the conversion complete flag
|
||||
set_bit(reg::ADCCON0, 6); // ADCS - Set the ADC conversion start flag
|
||||
|
||||
//Wait for the ADCF conversion complete flag to be set
|
||||
// Wait for the ADCF conversion complete flag to be set
|
||||
unsigned long start_time = millis();
|
||||
while(!get_bit(reg::ADCCON0, 7)) {
|
||||
sleep_ms(1);
|
||||
|
@ -714,21 +712,21 @@ namespace pimoroni {
|
|||
}
|
||||
}
|
||||
|
||||
void IOExpander::setup_rotary_encoder(uint8_t channel, uint8_t pinA, uint8_t pinB, uint8_t pinC, bool count_microsteps) {
|
||||
void IOExpander::setup_rotary_encoder(uint8_t channel, uint8_t pin_a, uint8_t pin_b, uint8_t pin_c, bool count_microsteps) {
|
||||
channel -= 1;
|
||||
set_mode(pinA, PIN_MODE_PU, true);
|
||||
set_mode(pinB, PIN_MODE_PU, true);
|
||||
set_mode(pin_a, PIN_MODE_PU, true);
|
||||
set_mode(pin_b, PIN_MODE_PU, true);
|
||||
|
||||
if(pinC != 0) {
|
||||
set_mode(pinC, PIN_MODE_OD);
|
||||
output(pinC, 0);
|
||||
if(pin_c != 0) {
|
||||
set_mode(pin_c, PIN_MODE_OD);
|
||||
output(pin_c, 0);
|
||||
}
|
||||
|
||||
i2c_reg_write_uint8(ENC_CFG[channel], pinA | (pinB << 4));
|
||||
i2c_reg_write_uint8(ENC_CFG[channel], pin_a | (pin_b << 4));
|
||||
change_bit(reg::ENC_EN, (channel * 2) + 1, count_microsteps);
|
||||
set_bit(reg::ENC_EN, channel * 2);
|
||||
|
||||
//Reset internal encoder count to zero
|
||||
// Reset internal encoder count to zero
|
||||
uint8_t reg = ENC_COUNT[channel];
|
||||
i2c_reg_write_uint8(reg, 0x00);
|
||||
}
|
||||
|
@ -765,14 +763,14 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
uint8_t IOExpander::get_bit(uint8_t reg, uint8_t bit) {
|
||||
//Returns the specified bit (nth position from right) from a register
|
||||
// Returns the specified bit (nth position from right) from a register
|
||||
return i2c_reg_read_uint8(reg) & (1 << bit);
|
||||
}
|
||||
|
||||
void IOExpander::set_bits(uint8_t reg, uint8_t bits) {
|
||||
//Set the specified bits (using a mask) in a register.
|
||||
// Set the specified bits (using a mask) in a register.
|
||||
|
||||
//Deal with special case registers first
|
||||
// Deal with special case registers first
|
||||
bool reg_in_bit_addressed_regs = false;
|
||||
for(uint8_t i = 0; i < NUM_BIT_ADDRESSED_REGISTERS; i++) {
|
||||
if(BIT_ADDRESSED_REGS[i] == reg) {
|
||||
|
@ -785,7 +783,7 @@ namespace pimoroni {
|
|||
}
|
||||
}
|
||||
|
||||
//Now deal with any other registers
|
||||
// Now deal with any other registers
|
||||
if(!reg_in_bit_addressed_regs) {
|
||||
uint8_t value = i2c_reg_read_uint8(reg);
|
||||
sleep_us(10);
|
||||
|
@ -794,7 +792,7 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void IOExpander::set_bit(uint8_t reg, uint8_t bit) {
|
||||
//Set the specified bit (nth position from right) in a register.
|
||||
// Set the specified bit (nth position from right) in a register.
|
||||
set_bits(reg, (1 << bit));
|
||||
}
|
||||
|
||||
|
@ -811,7 +809,7 @@ namespace pimoroni {
|
|||
}
|
||||
}
|
||||
|
||||
//Now deal with any other registers
|
||||
// Now deal with any other registers
|
||||
if(!reg_in_bit_addressed_regs) {
|
||||
uint8_t value = i2c_reg_read_uint8(reg);
|
||||
sleep_us(10);
|
||||
|
@ -820,12 +818,12 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void IOExpander::clr_bit(uint8_t reg, uint8_t bit) {
|
||||
//Clear the specified bit (nth position from right) in a register.
|
||||
// Clear the specified bit (nth position from right) in a register.
|
||||
clr_bits(reg, (1 << bit));
|
||||
}
|
||||
|
||||
void IOExpander::change_bit(uint8_t reg, uint8_t bit, bool state) {
|
||||
//Toggle one register bit on/off.
|
||||
// Toggle one register bit on/off.
|
||||
if(state)
|
||||
set_bit(reg, bit);
|
||||
else
|
||||
|
@ -833,7 +831,7 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void IOExpander::wait_for_flash(void) {
|
||||
//Wait for the IOE to finish writing non-volatile memory.
|
||||
// Wait for the IOE to finish writing non-volatile memory.
|
||||
unsigned long start_time = millis();
|
||||
while(get_interrupt_flag()) {
|
||||
if(millis() - start_time > timeout) {
|
||||
|
|
|
@ -187,10 +187,9 @@ namespace pimoroni {
|
|||
|
||||
void enable_interrupt_out(bool pin_swap = false);
|
||||
void disable_interrupt_out();
|
||||
uint8_t get_interrupt_flag();
|
||||
bool get_interrupt_flag();
|
||||
void clear_interrupt_flag();
|
||||
bool set_pin_interrupt(uint8_t pin, bool enabled);
|
||||
void set_interrupt_callback(void (*callback)());
|
||||
|
||||
void pwm_load(bool wait_for_load = true);
|
||||
bool pwm_loading();
|
||||
|
@ -207,7 +206,7 @@ namespace pimoroni {
|
|||
|
||||
void output(uint8_t pin, uint16_t value, bool load = true);
|
||||
|
||||
void setup_rotary_encoder(uint8_t channel, uint8_t pinA, uint8_t pinB, uint8_t pinC = 0, bool count_microsteps = false);
|
||||
void setup_rotary_encoder(uint8_t channel, uint8_t pin_a, uint8_t pin_b, uint8_t pin_c = 0, bool count_microsteps = false);
|
||||
int16_t read_rotary_encoder(uint8_t channel);
|
||||
|
||||
private:
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
#include "breakout_ioexpander.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BreakoutIOExpander Class
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***** Methods *****/
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutIOExpander_get_chip_id_obj, BreakoutIOExpander_get_chip_id);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutIOExpander_set_address_obj, 2, BreakoutIOExpander_set_address);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutIOExpander_get_adc_vref_obj, BreakoutIOExpander_get_adc_vref);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutIOExpander_set_adc_vref_obj, 2, BreakoutIOExpander_set_adc_vref);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutIOExpander_enable_interrupt_out_obj, 1, BreakoutIOExpander_enable_interrupt_out);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutIOExpander_disable_interrupt_out_obj, BreakoutIOExpander_disable_interrupt_out);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutIOExpander_get_interrupt_flag_obj, BreakoutIOExpander_get_interrupt_flag);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutIOExpander_clear_interrupt_flag_obj, BreakoutIOExpander_clear_interrupt_flag);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutIOExpander_set_pin_interrupt_obj, 3, BreakoutIOExpander_set_pin_interrupt);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutIOExpander_pwm_load_obj, 1, BreakoutIOExpander_pwm_load);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutIOExpander_pwm_loading_obj, BreakoutIOExpander_pwm_loading);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutIOExpander_pwm_clear_obj, 1, BreakoutIOExpander_pwm_clear);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutIOExpander_pwm_clearing_obj, BreakoutIOExpander_pwm_clearing);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutIOExpander_set_pwm_control_obj, 2, BreakoutIOExpander_set_pwm_control);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutIOExpander_set_pwm_period_obj, 2, BreakoutIOExpander_set_pwm_period);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutIOExpander_set_mode_obj, 3, BreakoutIOExpander_set_mode);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutIOExpander_input_obj, 2, BreakoutIOExpander_input);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutIOExpander_input_as_voltage_obj, 2, BreakoutIOExpander_input_as_voltage);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutIOExpander_output_obj, 3, BreakoutIOExpander_output);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutIOExpander_setup_rotary_encoder_obj, 4, BreakoutIOExpander_setup_rotary_encoder);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutIOExpander_read_rotary_encoder_obj, 2, BreakoutIOExpander_read_rotary_encoder);
|
||||
|
||||
/***** Binding of Methods *****/
|
||||
STATIC const mp_rom_map_elem_t BreakoutIOExpander_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_chip_id), MP_ROM_PTR(&BreakoutIOExpander_get_chip_id_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_address), MP_ROM_PTR(&BreakoutIOExpander_set_address_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_adc_vref), MP_ROM_PTR(&BreakoutIOExpander_get_adc_vref_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_adc_vref), MP_ROM_PTR(&BreakoutIOExpander_set_adc_vref_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_enable_interrupt_out), MP_ROM_PTR(&BreakoutIOExpander_enable_interrupt_out_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_disable_interrupt_out), MP_ROM_PTR(&BreakoutIOExpander_disable_interrupt_out_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_interrupt_flag), MP_ROM_PTR(&BreakoutIOExpander_get_interrupt_flag_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_clear_interrupt_flag), MP_ROM_PTR(&BreakoutIOExpander_clear_interrupt_flag_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_pin_interrupt), MP_ROM_PTR(&BreakoutIOExpander_set_pin_interrupt_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pwm_load), MP_ROM_PTR(&BreakoutIOExpander_pwm_load_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pwm_loading), MP_ROM_PTR(&BreakoutIOExpander_pwm_loading_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pwm_clear), MP_ROM_PTR(&BreakoutIOExpander_pwm_clear_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pwm_clearing), MP_ROM_PTR(&BreakoutIOExpander_pwm_clearing_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_pwm_control), MP_ROM_PTR(&BreakoutIOExpander_set_pwm_control_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_pwm_period), MP_ROM_PTR(&BreakoutIOExpander_set_pwm_period_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_mode), MP_ROM_PTR(&BreakoutIOExpander_set_mode_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_input), MP_ROM_PTR(&BreakoutIOExpander_input_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_input_as_voltage), MP_ROM_PTR(&BreakoutIOExpander_input_as_voltage_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_output), MP_ROM_PTR(&BreakoutIOExpander_output_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_setup_rotary_encoder), MP_ROM_PTR(&BreakoutIOExpander_setup_rotary_encoder_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_read_rotary_encoder), MP_ROM_PTR(&BreakoutIOExpander_read_rotary_encoder_obj) },
|
||||
// { MP_ROM_QSTR(MP_QSTR_REF), MP_ROM_INT(REF) },
|
||||
// { MP_ROM_QSTR(MP_QSTR_REDUCING), MP_ROM_INT(REDUCING) },
|
||||
// { MP_ROM_QSTR(MP_QSTR_NH3), MP_ROM_INT(NH3) },
|
||||
// { MP_ROM_QSTR(MP_QSTR_OXIDISING), MP_ROM_INT(OXIDISING) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(BreakoutIOExpander_locals_dict, BreakoutIOExpander_locals_dict_table);
|
||||
|
||||
/***** Class Definition *****/
|
||||
const mp_obj_type_t breakout_ioexpander_BreakoutIOExpander_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_breakout_ioexpander,
|
||||
.print = BreakoutIOExpander_print,
|
||||
.make_new = BreakoutIOExpander_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&BreakoutIOExpander_locals_dict,
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// breakout_ioexpander Module
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***** Globals Table *****/
|
||||
STATIC const mp_map_elem_t breakout_ioexpander_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_ioexpander) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutIOExpander), (mp_obj_t)&breakout_ioexpander_BreakoutIOExpander_type },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_ioexpander_globals, breakout_ioexpander_globals_table);
|
||||
|
||||
/***** Module Definition *****/
|
||||
const mp_obj_module_t breakout_ioexpander_user_cmodule = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_breakout_ioexpander_globals,
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
MP_REGISTER_MODULE(MP_QSTR_breakout_ioexpander, breakout_ioexpander_user_cmodule, MODULE_BREAKOUT_IOEXPANDER_ENABLED);
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,482 @@
|
|||
#include "../../../pimoroni-pico/libraries/breakout_ioexpander/breakout_ioexpander.hpp"
|
||||
|
||||
#define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o))
|
||||
|
||||
// SDA/SCL on even/odd pins, I2C0/I2C1 on even/odd pairs of pins.
|
||||
#define IS_VALID_SCL(i2c, pin) (((pin) & 1) == 1 && (((pin) & 2) >> 1) == (i2c))
|
||||
#define IS_VALID_SDA(i2c, pin) (((pin) & 1) == 0 && (((pin) & 2) >> 1) == (i2c))
|
||||
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
extern "C" {
|
||||
#include "breakout_ioexpander.h"
|
||||
|
||||
/***** Variables Struct *****/
|
||||
typedef struct _breakout_ioexpander_BreakoutIOExpander_obj_t {
|
||||
mp_obj_base_t base;
|
||||
BreakoutIOExpander *breakout;
|
||||
} breakout_ioexpander_BreakoutIOExpander_obj_t;
|
||||
|
||||
/***** Print *****/
|
||||
void BreakoutIOExpander_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
(void)kind; //Unused input parameter
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
BreakoutIOExpander* breakout = self->breakout;
|
||||
mp_print_str(print, "BreakoutIOExpander(");
|
||||
|
||||
mp_print_str(print, "i2c = ");
|
||||
mp_obj_print_helper(print, mp_obj_new_int((breakout->get_i2c() == i2c0) ? 0 : 1), PRINT_REPR);
|
||||
|
||||
mp_print_str(print, ", sda = ");
|
||||
mp_obj_print_helper(print, mp_obj_new_int(breakout->get_sda()), PRINT_REPR);
|
||||
|
||||
mp_print_str(print, ", scl = ");
|
||||
mp_obj_print_helper(print, mp_obj_new_int(breakout->get_scl()), PRINT_REPR);
|
||||
|
||||
mp_print_str(print, ", int = ");
|
||||
mp_obj_print_helper(print, mp_obj_new_int(breakout->get_int()), PRINT_REPR);
|
||||
|
||||
mp_print_str(print, ")");
|
||||
}
|
||||
|
||||
/***** Constructor *****/
|
||||
mp_obj_t BreakoutIOExpander_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = nullptr;
|
||||
|
||||
if(n_args == 0) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, true);
|
||||
self = m_new_obj(breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
self->base.type = &breakout_ioexpander_BreakoutIOExpander_type;
|
||||
self->breakout = new BreakoutIOExpander();
|
||||
}
|
||||
else if(n_args == 1) {
|
||||
enum { ARG_address };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
self = m_new_obj(breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
self->base.type = &breakout_ioexpander_BreakoutIOExpander_type;
|
||||
|
||||
self->breakout = new BreakoutIOExpander(args[ARG_address].u_int);
|
||||
}
|
||||
else {
|
||||
enum { ARG_i2c, ARG_address, ARG_sda, ARG_scl, ARG_interrupt };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_i2c, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_interrupt, MP_ARG_INT, {.u_int = BreakoutIOExpander::PIN_UNUSED} },
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// Get I2C bus.
|
||||
int i2c_id = args[ARG_i2c].u_int;
|
||||
if(i2c_id < 0 || i2c_id > 1) {
|
||||
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C(%d) doesn't exist"), i2c_id);
|
||||
}
|
||||
|
||||
int sda = args[ARG_sda].u_int;
|
||||
if (!IS_VALID_SDA(i2c_id, sda)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("bad SDA pin"));
|
||||
}
|
||||
|
||||
int scl = args[ARG_scl].u_int;
|
||||
if (!IS_VALID_SCL(i2c_id, scl)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("bad SCL pin"));
|
||||
}
|
||||
|
||||
self = m_new_obj(breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
self->base.type = &breakout_ioexpander_BreakoutIOExpander_type;
|
||||
|
||||
i2c_inst_t *i2c = (i2c_id == 0) ? i2c0 : i2c1;
|
||||
self->breakout = new BreakoutIOExpander(i2c, args[ARG_address].u_int, sda, scl, args[ARG_interrupt].u_int);
|
||||
}
|
||||
|
||||
if(!self->breakout->init()) {
|
||||
mp_raise_msg(&mp_type_RuntimeError, "IOExpander breakout not found when initialising");
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
/***** Methods *****/
|
||||
mp_obj_t BreakoutIOExpander_get_chip_id(mp_obj_t self_in) {
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
return mp_obj_new_int(self->breakout->get_chip_id());
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_set_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 },
|
||||
{ MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
self->breakout->set_address(args[ARG_address].u_int);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_get_adc_vref(mp_obj_t self_in) {
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
return mp_obj_new_float(self->breakout->get_adc_vref());
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_set_adc_vref(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_vref };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_vref, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
float vref = mp_obj_get_float(args[ARG_vref].u_obj);
|
||||
self->breakout->set_adc_vref(vref);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_enable_interrupt_out(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_pin_swap };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_pin_swap, MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
bool pin_swap = args[ARG_pin_swap].u_bool;
|
||||
self->breakout->enable_interrupt_out(pin_swap);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_disable_interrupt_out(mp_obj_t self_in) {
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
self->breakout->disable_interrupt_out();
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_get_interrupt_flag(mp_obj_t self_in) {
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
return mp_obj_new_bool(self->breakout->get_interrupt_flag());
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_clear_interrupt_flag(mp_obj_t self_in) {
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
self->breakout->clear_interrupt_flag();
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_set_pin_interrupt(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_pin, ARG_enabled };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_exp_pin, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_enabled, MP_ARG_REQUIRED | MP_ARG_BOOL },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
int pin = args[ARG_pin].u_int;
|
||||
bool enabled = args[ARG_enabled].u_bool;
|
||||
if(!self->breakout->set_pin_interrupt(pin, enabled)) {
|
||||
mp_raise_ValueError("pin out of range. Expected 1 to 14");
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_pwm_load(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_wait_for_load };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_wait_for_load, MP_ARG_BOOL, {.u_bool = true} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
bool wait_for_load = args[ARG_wait_for_load].u_bool;
|
||||
self->breakout->pwm_load(wait_for_load);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_pwm_loading(mp_obj_t self_in) {
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
return mp_obj_new_bool(self->breakout->pwm_loading());
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_pwm_clear(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_wait_for_clear };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_wait_for_clear, MP_ARG_BOOL, {.u_bool = true} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
bool wait_for_clear = args[ARG_wait_for_clear].u_bool;
|
||||
self->breakout->pwm_clear(wait_for_clear);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_pwm_clearing(mp_obj_t self_in) {
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
return mp_obj_new_bool(self->breakout->pwm_clearing());
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_set_pwm_control(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_divider };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_divider, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
int divider = args[ARG_divider].u_int;
|
||||
if(!self->breakout->set_pwm_control(divider)) {
|
||||
mp_raise_ValueError("divider not valid. Available options are: 1, 2, 4, 8, 16, 32, 64, 128");
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_set_pwm_period(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_value, ARG_load };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_load, MP_ARG_BOOL, {.u_bool = true} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
int value = args[ARG_value].u_int;
|
||||
bool load = args[ARG_load].u_bool;
|
||||
if(value < 0 || value > 65535)
|
||||
mp_raise_ValueError("value out of range. Expected 0 to 65535");
|
||||
else
|
||||
self->breakout->set_pwm_period(value, load);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_get_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_pin, ARG_enabled };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_exp_pin, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
int pin = args[ARG_pin].u_int;
|
||||
uint8_t mode = self->breakout->get_mode(pin);
|
||||
if(mode == UINT8_MAX)
|
||||
mp_raise_ValueError("pin out of range. Expected 1 to 14");
|
||||
|
||||
return mp_obj_new_int(mode);
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_set_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_pin, ARG_mode, ARG_schmitt_trigger, ARG_invert };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_exp_pin, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_schmitt_trigger, MP_ARG_BOOL, {.u_bool = false} },
|
||||
{ MP_QSTR_invert, MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
int pin = args[ARG_pin].u_int;
|
||||
int mode = args[ARG_mode].u_int;
|
||||
bool schmitt_trigger = args[ARG_schmitt_trigger].u_bool;
|
||||
bool invert = args[ARG_invert].u_bool;
|
||||
|
||||
if(pin < 1 || pin > IOExpander::NUM_PINS)
|
||||
mp_raise_ValueError("pin out of range. Expected 1 to 14");
|
||||
else
|
||||
self->breakout->set_mode(pin, mode, schmitt_trigger, invert);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_input(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_pin };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_exp_pin, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
int pin = args[ARG_pin].u_int;
|
||||
|
||||
if(pin < 1 || pin > IOExpander::NUM_PINS)
|
||||
mp_raise_ValueError("pin out of range. Expected 1 to 14");
|
||||
else
|
||||
return mp_obj_new_int(self->breakout->input(pin));
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_input_as_voltage(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_pin };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_exp_pin, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
int pin = args[ARG_pin].u_int;
|
||||
|
||||
if(pin < 1 || pin > IOExpander::NUM_PINS)
|
||||
mp_raise_ValueError("pin out of range. Expected 1 to 14");
|
||||
else
|
||||
return mp_obj_new_float(self->breakout->input_as_voltage(pin));
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_output(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_pin, ARG_value, ARG_load };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_exp_pin, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_load, MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
int pin = args[ARG_pin].u_int;
|
||||
int value = args[ARG_value].u_int;
|
||||
bool load = args[ARG_load].u_bool;
|
||||
|
||||
if(pin < 1 || pin > IOExpander::NUM_PINS)
|
||||
mp_raise_ValueError("pin out of range. Expected 1 to 14");
|
||||
else if(value < 0 || value > 65535)
|
||||
mp_raise_ValueError("value out of range. Expected 0 to 65535");
|
||||
else
|
||||
self->breakout->output(pin, value, load);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_setup_rotary_encoder(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_channel, ARG_pin_a, ARG_pin_b, ARG_pin_c, ARG_count_microsteps };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_channel, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_pin_a, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_pin_b, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_pin_c, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_count_microsteps, MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
int channel = args[ARG_channel].u_int;
|
||||
int pin_a = args[ARG_pin_a].u_int;
|
||||
int pin_b = args[ARG_pin_b].u_int;
|
||||
int pin_c = args[ARG_pin_c].u_int;
|
||||
bool count_microsteps = args[ARG_count_microsteps].u_bool;
|
||||
|
||||
if(channel < 1 || channel > 4)
|
||||
mp_raise_ValueError("channel out of range. Expected 1 to 4");
|
||||
else if(pin_a < 1 || pin_a > 14)
|
||||
mp_raise_ValueError("pin_a out of range. Expected 1 to 14");
|
||||
else if(pin_b < 1 || pin_b > 14)
|
||||
mp_raise_ValueError("pin_b out of range. Expected 1 to 14");
|
||||
else if(pin_c < 1 || pin_c > 14)
|
||||
mp_raise_ValueError("pin_c out of range. Expected 1 to 14");
|
||||
else
|
||||
self->breakout->setup_rotary_encoder(channel, pin_a, pin_b, pin_c, count_microsteps);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_read_rotary_encoder(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_channel, ARG_value, ARG_load };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_channel, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
int channel = args[ARG_channel].u_int;
|
||||
if(channel < 1 || channel > 4)
|
||||
mp_raise_ValueError("channel out of range. Expected 1 to 4");
|
||||
else
|
||||
return mp_obj_new_int(self->breakout->read_rotary_encoder(channel));
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// Include MicroPython API.
|
||||
#include "py/runtime.h"
|
||||
|
||||
// enum {
|
||||
// REF = 0,
|
||||
// REDUCING,
|
||||
// NH3,
|
||||
// OXIDISING
|
||||
// };
|
||||
|
||||
/***** Extern of Class Definition *****/
|
||||
extern const mp_obj_type_t breakout_ioexpander_BreakoutIOExpander_type;
|
||||
|
||||
/***** Extern of Class Methods *****/
|
||||
extern void BreakoutIOExpander_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
||||
extern mp_obj_t BreakoutIOExpander_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 BreakoutIOExpander_get_chip_id(mp_obj_t self_in);
|
||||
extern mp_obj_t BreakoutIOExpander_set_address(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_get_adc_vref(mp_obj_t self_in);
|
||||
extern mp_obj_t BreakoutIOExpander_set_adc_vref(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_enable_interrupt_out(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_disable_interrupt_out(mp_obj_t self_in);
|
||||
extern mp_obj_t BreakoutIOExpander_get_interrupt_flag(mp_obj_t self_in);
|
||||
extern mp_obj_t BreakoutIOExpander_clear_interrupt_flag(mp_obj_t self_in);
|
||||
extern mp_obj_t BreakoutIOExpander_set_pin_interrupt(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_pwm_load(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_pwm_loading(mp_obj_t self_in);
|
||||
extern mp_obj_t BreakoutIOExpander_pwm_clear(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_pwm_clearing(mp_obj_t self_in);
|
||||
extern mp_obj_t BreakoutIOExpander_set_pwm_control(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_set_pwm_period(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_get_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_set_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_input(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_input_as_voltage(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_output(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_setup_rotary_encoder(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_read_rotary_encoder(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
|
@ -0,0 +1,20 @@
|
|||
set(MOD_NAME breakout_ioexpander)
|
||||
string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER)
|
||||
add_library(usermod_${MOD_NAME} INTERFACE)
|
||||
|
||||
target_sources(usermod_${MOD_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/${MOD_NAME}/${MOD_NAME}.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/ioexpander/ioexpander.cpp
|
||||
)
|
||||
|
||||
target_include_directories(usermod_${MOD_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
target_compile_definitions(usermod_${MOD_NAME} INTERFACE
|
||||
-DMODULE_${MOD_NAME_UPPER}_ENABLED=1
|
||||
)
|
||||
|
||||
target_link_libraries(usermod INTERFACE usermod_${MOD_NAME})
|
|
@ -0,0 +1,13 @@
|
|||
set(MOD_NAME breakout_ioexpander)
|
||||
BREAKOUT_MOD_DIR := $(USERMOD_DIR)
|
||||
|
||||
# Add our source files to the respective variables.
|
||||
SRC_USERMOD += $(BREAKOUT_MOD_DIR)/${MOD_NAME}.c
|
||||
SRC_USERMOD_CXX += $(BREAKOUT_MOD_DIR)/${MOD_NAME}.cpp
|
||||
|
||||
# Add our module directory to the include path.
|
||||
CFLAGS_USERMOD += -I$(BREAKOUT_MOD_DIR)
|
||||
CXXFLAGS_USERMOD += -I$(BREAKOUT_MOD_DIR)
|
||||
|
||||
# We use C++ features so have to link against the standard library.
|
||||
LDFLAGS_USERMOD += -lstdc++
|
|
@ -2,6 +2,7 @@ include_directories(${CMAKE_CURRENT_LIST_DIR}/../../)
|
|||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/breakout_dotmatrix/micropython.cmake)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/breakout_encoder/micropython.cmake)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/breakout_ioexpander/micropython.cmake)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/breakout_ltr559/micropython.cmake)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/breakout_colourlcd160x80/micropython.cmake)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/breakout_as7262/micropython.cmake)
|
||||
|
|
Ładowanie…
Reference in New Issue