From acf011bba26a1927e3bb949a742f10f534762ba0 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Tue, 11 May 2021 13:00:12 +0100 Subject: [PATCH 01/27] Merge in previous Nuvoton driver code --- drivers/CMakeLists.txt | 1 + drivers/nuvoton/CMakeLists.txt | 1 + drivers/nuvoton/nuvoton.cmake | 10 + drivers/nuvoton/nuvoton.cpp | 839 ++++++++++++++++++ drivers/nuvoton/nuvoton.hpp | 235 +++++ libraries/CMakeLists.txt | 4 + libraries/breakout_encoder/CMakeLists.txt | 1 + .../breakout_encoder/breakout_encoder.cmake | 11 + .../breakout_encoder/breakout_encoder.cpp | 5 + .../breakout_encoder/breakout_encoder.hpp | 8 + libraries/breakout_ioexpander/CMakeLists.txt | 1 + .../breakout_ioexpander.cmake | 11 + .../breakout_ioexpander.cpp | 5 + .../breakout_ioexpander.hpp | 8 + libraries/breakout_mics6814/CMakeLists.txt | 1 + .../breakout_mics6814/breakout_mics6814.cmake | 11 + .../breakout_mics6814/breakout_mics6814.cpp | 5 + .../breakout_mics6814/breakout_mics6814.hpp | 8 + .../breakout_potentiometer/CMakeLists.txt | 1 + .../breakout_potentiometer.cmake | 11 + .../breakout_potentiometer.cpp | 5 + .../breakout_potentiometer.hpp | 8 + 22 files changed, 1190 insertions(+) create mode 100644 drivers/nuvoton/CMakeLists.txt create mode 100644 drivers/nuvoton/nuvoton.cmake create mode 100644 drivers/nuvoton/nuvoton.cpp create mode 100644 drivers/nuvoton/nuvoton.hpp create mode 100644 libraries/breakout_encoder/CMakeLists.txt create mode 100644 libraries/breakout_encoder/breakout_encoder.cmake create mode 100644 libraries/breakout_encoder/breakout_encoder.cpp create mode 100644 libraries/breakout_encoder/breakout_encoder.hpp create mode 100644 libraries/breakout_ioexpander/CMakeLists.txt create mode 100644 libraries/breakout_ioexpander/breakout_ioexpander.cmake create mode 100644 libraries/breakout_ioexpander/breakout_ioexpander.cpp create mode 100644 libraries/breakout_ioexpander/breakout_ioexpander.hpp create mode 100644 libraries/breakout_mics6814/CMakeLists.txt create mode 100644 libraries/breakout_mics6814/breakout_mics6814.cmake create mode 100644 libraries/breakout_mics6814/breakout_mics6814.cpp create mode 100644 libraries/breakout_mics6814/breakout_mics6814.hpp create mode 100644 libraries/breakout_potentiometer/CMakeLists.txt create mode 100644 libraries/breakout_potentiometer/breakout_potentiometer.cmake create mode 100644 libraries/breakout_potentiometer/breakout_potentiometer.cpp create mode 100644 libraries/breakout_potentiometer/breakout_potentiometer.hpp diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 9e56c8cd..fd0ddca6 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory(sgp30) add_subdirectory(st7735) add_subdirectory(st7789) add_subdirectory(msa301) +add_subdirectory(nuvoton) add_subdirectory(rv3028) add_subdirectory(trackball) add_subdirectory(vl53l1x) diff --git a/drivers/nuvoton/CMakeLists.txt b/drivers/nuvoton/CMakeLists.txt new file mode 100644 index 00000000..395cdc9a --- /dev/null +++ b/drivers/nuvoton/CMakeLists.txt @@ -0,0 +1 @@ +include(nuvoton.cmake) diff --git a/drivers/nuvoton/nuvoton.cmake b/drivers/nuvoton/nuvoton.cmake new file mode 100644 index 00000000..bcc5ab15 --- /dev/null +++ b/drivers/nuvoton/nuvoton.cmake @@ -0,0 +1,10 @@ +set(DRIVER_NAME nuvoton) +add_library(${DRIVER_NAME} INTERFACE) + +target_sources(${DRIVER_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp) + +target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_i2c) diff --git a/drivers/nuvoton/nuvoton.cpp b/drivers/nuvoton/nuvoton.cpp new file mode 100644 index 00000000..59b3a5af --- /dev/null +++ b/drivers/nuvoton/nuvoton.cpp @@ -0,0 +1,839 @@ +#include +#include +#include +#include + +#include "nuvoton.hpp" + +namespace pimoroni { + + enum reg { + CHIP_ID_L = 0xfa, + CHIP_ID_H = 0xfb, + VERSION = 0xfc, + + // Rotary encoder + ENC_EN = 0x04, + // BIT_ENC_EN_1 = 0 + // BIT_ENC_MICROSTEP_1 = 1 + // BIT_ENC_EN_2 = 2 + // BIT_ENC_MICROSTEP_2 = 3 + // BIT_ENC_EN_3 = 4 + // BIT_ENC_MICROSTEP_3 = 5 + // BIT_ENC_EN_4 = 6 + // BIT_ENC_MICROSTEP_4 = 7 + + ENC_1_CFG = 0x05, + ENC_1_COUNT = 0x06, + ENC_2_CFG = 0x07, + ENC_2_COUNT = 0x08, + ENC_3_CFG = 0x09, + ENC_3_COUNT = 0x0A, + ENC_4_CFG = 0x0B, + ENC_4_COUNT = 0x0C, + + // Cap touch + CAPTOUCH_EN = 0x0D, + CAPTOUCH_CFG = 0x0E, + CAPTOUCH_0 = 0x0F, // First of 8 bytes from 15-22 + + // Switch counters + SWITCH_EN_P0 = 0x17, + SWITCH_EN_P1 = 0x18, + SWITCH_P00 = 0x19, // First of 8 bytes from 25-40 + SWITCH_P10 = 0x21, // First of 8 bytes from 33-49 + + USER_FLASH = 0xD0, + FLASH_PAGE = 0xF0, + DEBUG = 0xF8, + + P0 = 0x40, // protect_bits 2 # Bit addressing + SP = 0x41, // Read only + DPL = 0x42, // Read only + DPH = 0x43, // Read only + RCTRIM0 = 0x44, // Read only + RCTRIM1 = 0x45, // Read only + RWK = 0x46, + PCON = 0x47, // Read only + TCON = 0x48, + TMOD = 0x49, + TL0 = 0x4a, + TL1 = 0x4b, + TH0 = 0x4c, + TH1 = 0x4d, + CKCON = 0x4e, + WKCON = 0x4f, // Read only + P1 = 0x50, // protect_bits 3 6 # Bit addressing + SFRS = 0x51, // TA protected # Read only + CAPCON0 = 0x52, + CAPCON1 = 0x53, + CAPCON2 = 0x54, + CKDIV = 0x55, + CKSWT = 0x56, // TA protected # Read only + CKEN = 0x57, // TA protected # Read only + SCON = 0x58, + SBUF = 0x59, + SBUF_1 = 0x5a, + EIE = 0x5b, // Read only + EIE1 = 0x5c, // Read only + CHPCON = 0x5f, // TA protected # Read only + P2 = 0x60, // Bit addressing + AUXR1 = 0x62, + BODCON0 = 0x63, // TA protected + IAPTRG = 0x64, // TA protected # Read only + IAPUEN = 0x65, // TA protected # Read only + IAPAL = 0x66, // Read only + IAPAH = 0x67, // Read only + IE = 0x68, // Read only + SADDR = 0x69, + WDCON = 0x6a, // TA protected + BODCON1 = 0x6b, // TA protected + P3M1 = 0x6c, + P3S = 0xc0, // Page 1 # Reassigned from 0x6c to avoid collision + P3M2 = 0x6d, + P3SR = 0xc1, // Page 1 # Reassigned from 0x6d to avoid collision + IAPFD = 0x6e, // Read only + IAPCN = 0x6f, // Read only + P3 = 0x70, // Bit addressing + P0M1 = 0x71, // protect_bits 2 + P0S = 0xc2, // Page 1 # Reassigned from 0x71 to avoid collision + P0M2 = 0x72, // protect_bits 2 + P0SR = 0xc3, // Page 1 # Reassigned from 0x72 to avoid collision + P1M1 = 0x73, // protect_bits 3 6 + P1S = 0xc4, // Page 1 # Reassigned from 0x73 to avoid collision + P1M2 = 0x74, // protect_bits 3 6 + P1SR = 0xc5, // Page 1 # Reassigned from 0x74 to avoid collision + P2S = 0x75, + IPH = 0x77, // Read only + PWMINTC = 0xc6, // Page 1 # Read only # Reassigned from 0x77 to avoid collision + IP = 0x78, // Read only + SADEN = 0x79, + SADEN_1 = 0x7a, + SADDR_1 = 0x7b, + I2DAT = 0x7c, // Read only + I2STAT = 0x7d, // Read only + I2CLK = 0x7e, // Read only + I2TOC = 0x7f, // Read only + I2CON = 0x80, // Read only + I2ADDR = 0x81, // Read only + ADCRL = 0x82, + ADCRH = 0x83, + T3CON = 0x84, + PWM4H = 0xc7, // Page 1 # Reassigned from 0x84 to avoid collision + RL3 = 0x85, + PWM5H = 0xc8, // Page 1 # Reassigned from 0x85 to avoid collision + RH3 = 0x86, + PIOCON1 = 0xc9, // Page 1 # Reassigned from 0x86 to avoid collision + TA = 0x87, // Read only + T2CON = 0x88, + T2MOD = 0x89, + RCMP2L = 0x8a, + RCMP2H = 0x8b, + TL2 = 0x8c, + PWM4L = 0xca, // Page 1 # Reassigned from 0x8c to avoid collision + TH2 = 0x8d, + PWM5L = 0xcb, // Page 1 # Reassigned from 0x8d to avoid collision + ADCMPL = 0x8e, + ADCMPH = 0x8f, + PSW = 0x90, // Read only + PWMPH = 0x91, + PWM0H = 0x92, + PWM1H = 0x93, + PWM2H = 0x94, + PWM3H = 0x95, + PNP = 0x96, + FBD = 0x97, + PWMCON0 = 0x98, + PWMPL = 0x99, + PWM0L = 0x9a, + PWM1L = 0x9b, + PWM2L = 0x9c, + PWM3L = 0x9d, + PIOCON0 = 0x9e, + PWMCON1 = 0x9f, + ACC = 0xa0, // Read only + ADCCON1 = 0xa1, + ADCCON2 = 0xa2, + ADCDLY = 0xa3, + C0L = 0xa4, + C0H = 0xa5, + C1L = 0xa6, + C1H = 0xa7, + ADCCON0 = 0xa8, + PICON = 0xa9, // Read only + PINEN = 0xaa, // Read only + PIPEN = 0xab, // Read only + PIF = 0xac, // Read only + C2L = 0xad, + C2H = 0xae, + EIP = 0xaf, // Read only + B = 0xb0, // Read only + CAPCON3 = 0xb1, + CAPCON4 = 0xb2, + SPCR = 0xb3, + SPCR2 = 0xcc, // Page 1 # Reassigned from 0xb3 to avoid collision + SPSR = 0xb4, + SPDR = 0xb5, + AINDIDS = 0xb6, + EIPH = 0xb7, // Read only + SCON_1 = 0xb8, + PDTEN = 0xb9, // TA protected + PDTCNT = 0xba, // TA protected + PMEN = 0xbb, + PMD = 0xbc, + EIP1 = 0xbe, // Read only + EIPH1 = 0xbf, // Read only + + INT = 0xf9, + + + INT_MASK_P0 = 0x00, + INT_MASK_P1 = 0x01, + INT_MASK_P3 = 0x03, + + ADDR = 0xfd, + + CTRL = 0xfe, // 0 = Sleep, 1 = Reset, 2 = Read Flash, 3 = Write Flash, 4 = Addr Unlock + }; + + enum int_mask { + TRIG = 0x1, + OUT = 0x2, + }; + + enum int_bit { + TRIGD = 0, + OUT_EN = 1, + PIN_SWAP = 2, // 0 = P1.3, 1 = P0.0 + }; + + enum ctrl_mask { + SLEEP = 0x1, + RESET = 0x2, + FREAD = 0x4, + FWRITE = 0x8, + ADDRWR = 0x10, + }; + + static const uint8_t NUM_BIT_ADDRESSED_REGISTERS = 4; + static const uint8_t BIT_ADDRESSED_REGS[NUM_BIT_ADDRESSED_REGISTERS] = {reg::P0, reg::P1, reg::P2, reg::P3}; + static const uint8_t ENC_CFG[4] = {reg::ENC_1_CFG, reg::ENC_2_CFG, reg::ENC_3_CFG, reg::ENC_4_CFG}; + static const uint8_t ENC_COUNT[4] = {reg::ENC_1_COUNT, reg::ENC_2_COUNT, reg::ENC_3_COUNT, reg::ENC_4_COUNT}; + + const uint8_t Nuvoton::Pin::PxM1[4] = {reg::P0M1, reg::P1M1, (uint8_t)-1, reg::P3M1}; + const uint8_t Nuvoton::Pin::PxM2[4] = {reg::P0M2, reg::P1M2, (uint8_t)-1, reg::P3M2}; + const uint8_t Nuvoton::Pin::Px[4] = {reg::P0, reg::P1, (uint8_t)-1, reg::P3}; + + const uint8_t Nuvoton::Pin::PxS[4] = {reg::P0S, reg::P1S, (uint8_t)-1, reg::P3S}; + const uint8_t Nuvoton::Pin::MASK_P[4] = {reg::INT_MASK_P0, reg::INT_MASK_P1, (uint8_t)-1, reg::INT_MASK_P3}; + + const uint8_t Nuvoton::Pin::PWML[6] = {reg::PWM0L, reg::PWM1L, reg::PWM2L, reg::PWM3L, reg::PWM4L, reg::PWM5L}; + const uint8_t Nuvoton::Pin::PWMH[6] = {reg::PWM0H, reg::PWM1H, reg::PWM2H, reg::PWM3H, reg::PWM4H, reg::PWM5H}; + + static const char* MODE_NAMES[3] = {"IO", "PWM", "ADC"}; + static const char* GPIO_NAMES[4] = {"QB", "PP", "IN", "OD"}; + static const char* STATE_NAMES[2] = {"LOW", "HIGH"}; + + Nuvoton::Pin::Pin(uint8_t port, uint8_t pin) : + type(TYPE_IO), mode(0), port(port), pin(pin), adc_channel(0), pwm_channel(0), + reg_m1(PxM1[port]), reg_m2(PxM2[port]), reg_p(Px[port]), reg_ps(PxS[port]), reg_int_mask_p(MASK_P[port]), + reg_io_pwm(0), reg_pwml(0), reg_pwmh(0) { + } + + Nuvoton::Pin::Pin(uint8_t port, uint8_t pin, uint8_t pwm_channel, uint8_t reg_io_pwm) : + type(TYPE_PWM), mode(0), port(port), pin(pin), adc_channel(0), pwm_channel(pwm_channel), + reg_m1(PxM1[port]), reg_m2(PxM2[port]), reg_p(Px[port]), reg_ps(PxS[port]), reg_int_mask_p(MASK_P[port]), + reg_io_pwm(reg_io_pwm), reg_pwml(PWML[pwm_channel]), reg_pwmh(PWMH[pwm_channel]) { + } + + Nuvoton::Pin::Pin(uint8_t port, uint8_t pin, uint8_t adc_channel) : + type(TYPE_ADC), mode(0), port(port), pin(pin), adc_channel(adc_channel), pwm_channel(0), + reg_m1(PxM1[port]), reg_m2(PxM2[port]), reg_p(Px[port]), reg_ps(PxS[port]), reg_int_mask_p(MASK_P[port]), + reg_io_pwm(0), reg_pwml(0), reg_pwmh(0) { + } + + Nuvoton::Pin::Pin(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_io_pwm) : + type(TYPE_ADC_OR_PWM), mode(0), port(port), pin(pin), adc_channel(adc_channel), pwm_channel(pwm_channel), + reg_m1(PxM1[port]), reg_m2(PxM2[port]), reg_p(Px[port]), reg_ps(PxS[port]), reg_int_mask_p(MASK_P[port]), + reg_io_pwm(reg_io_pwm), reg_pwml(PWML[pwm_channel]), reg_pwmh(PWMH[pwm_channel]) { + } + + Nuvoton::Pin Nuvoton::Pin::io(uint8_t port, uint8_t pin) { + return Pin(port, pin); + } + + Nuvoton::Pin Nuvoton::Pin::pwm(uint8_t port, uint8_t pin, uint8_t channel, uint8_t reg_iopwm) { + return Pin(port, pin, channel, reg_iopwm); + } + + Nuvoton::Pin Nuvoton::Pin::adc(uint8_t port, uint8_t pin, uint8_t channel) { + return Pin(port, pin, channel); + } + + Nuvoton::Pin Nuvoton::Pin::adc_or_pwm(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm) { + return Pin(port, pin, adc_channel, pwm_channel, reg_iopwm); + } + + bool Nuvoton::Pin::mode_supported(uint8_t mode) { + bool supported = false; + if((type & TYPE_PWM) && (mode == PIN_MODE_PWM)) { + supported = true; + } + else if((type & TYPE_ADC) && (mode == PIN_MODE_ADC)) { + supported = true; + } + return supported; + } + + Nuvoton::Pin::IOType Nuvoton::Pin::get_type() { + return type; + } + + uint8_t Nuvoton::Pin::get_mode() { + return mode; + } + + void Nuvoton::Pin::set_mode(uint8_t mode) { + this->mode = mode; + } + + Nuvoton::Nuvoton(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt, uint8_t address, uint32_t timeout, bool debug) : + i2c(i2c), sda(sda), scl(scl), interrupt(interrupt), + address(address), timeout(timeout), debug(debug), vref(3.3f), + encoder_offset{0,0,0,0}, + encoder_last{0,0,0,0}, + pins{ Pin::pwm(1, 5, 5, reg::PIOCON1), + Pin::pwm(1, 0, 2, reg::PIOCON0), + Pin::pwm(1, 2, 0, reg::PIOCON0), + Pin::pwm(1, 4, 1, reg::PIOCON1), + Pin::pwm(0, 0, 3, reg::PIOCON0), + Pin::pwm(0, 1, 4, reg::PIOCON0), + Pin::adc_or_pwm(1, 1, 7, 1, reg::PIOCON0), + Pin::adc_or_pwm(0, 3, 6, 5, reg::PIOCON0), + Pin::adc_or_pwm(0, 4, 5, 3, reg::PIOCON1), + Pin::adc(3, 0, 1), + Pin::adc(0, 6, 3), + Pin::adc_or_pwm(0, 5, 4, 2, reg::PIOCON1), + Pin::adc(0, 7, 2), + Pin::adc(1, 7, 0)} { + } + + Nuvoton::Nuvoton(uint8_t address, uint32_t timeout, bool debug) : + Nuvoton(i2c0, DEFAULT_SDA_PIN, DEFAULT_SCL_PIN, DEFAULT_INT_PIN, address, timeout, debug) { + } + + bool Nuvoton::init(bool skipChipIdCheck) { + bool succeeded = true; + + i2c_init(i2c, 400000); + + 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); + 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 succeeded; + } + + uint16_t Nuvoton::get_chip_id() { + return ((uint16_t)i2c_reg_read_uint8(reg::CHIP_ID_H) << 8) | (uint16_t)i2c_reg_read_uint8(reg::CHIP_ID_L); + } + + void Nuvoton::set_addr(uint8_t address) { + set_bit(reg::CTRL, 4); + i2c_reg_write_uint8(reg::ADDR, address); + this->address = address; + sleep_ms(250); //TODO Handle addr change IOError better + //wait_for_flash() + clr_bit(reg::CTRL, 4); + } + + float Nuvoton::get_adc_vref() { + return vref; + } + + void Nuvoton::set_adc_vref(float vref) { + this->vref = vref; + } + + void Nuvoton::enable_interrupt_out(bool pin_swap) { + set_bit(reg::INT, int_bit::OUT_EN); + change_bit(reg::INT, int_bit::PIN_SWAP, pin_swap); + } + + void Nuvoton::disable_interrupt_out() { + clr_bit(reg::INT, int_bit::OUT_EN); + } + + uint8_t Nuvoton::get_interrupt_flag() { + if(interrupt != 0) + return !gpio_get(interrupt); + else + return get_bit(reg::INT, int_bit::TRIGD); + } + + void Nuvoton::clear_interrupt_flag() { + clr_bit(reg::INT, int_bit::TRIGD); + } + + bool Nuvoton::set_pin_interrupt(uint8_t pin, bool enabled) { + bool succeeded = false; + if(pin >= 1 && pin <= NUM_PINS) { + Pin& io_pin = pins[pin - 1]; + change_bit(io_pin.reg_int_mask_p, io_pin.pin, enabled); + + succeeded = true; + } + + return succeeded; + } + + void Nuvoton::set_interrupt_callback(void (*callback)()) { + if(interrupt != 0 && callback != nullptr) { + //attachInterrupt(digitalPinToInterrupt(_interruptPin), callback, FALLING); + clear_interrupt_flag(); + } + } + + void Nuvoton::pwm_load(bool wait_for_load) { + //Load new period and duty registers into buffer + uint32_t start_time = millis(); + 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 + if(millis() - start_time >= timeout) { + if(debug) + printf("Timed out waiting for PWM load!"); + return; + } + } + } + } + + bool Nuvoton::pwm_loading() { + return get_bit(reg::PWMCON0, 6); + } + + void Nuvoton::pwm_clear(bool wait_for_clear) { + uint32_t start_time = millis(); + 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 + if(millis() - start_time >= timeout) { + if(debug) + printf("Timed out waiting for PWM clear!"); + return; + } + } + } + } + + bool Nuvoton::pwm_clearing() { + return get_bit(reg::PWMCON0, 4); + } + + bool Nuvoton::set_pwm_control(uint8_t divider) { + bool divider_good = true; + uint8_t pwmdiv2 = 0; + switch(divider) { + case 1: pwmdiv2 = 0b000; break; + case 2: pwmdiv2 = 0b001; break; + case 4: pwmdiv2 = 0b010; break; + case 8: pwmdiv2 = 0b011; break; + case 16: pwmdiv2 = 0b100; break; + case 32: pwmdiv2 = 0b101; break; + case 64: pwmdiv2 = 0b110; break; + case 128: pwmdiv2 = 0b111; break; + + default: + if(debug) { + printf("ValueError: A clock divider of %d\n", divider); + } + divider_good = false; + break; + } + + 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 + + i2c_reg_write_uint8(reg::PWMCON1, pwmdiv2); + } + + return divider_good; + } + + void Nuvoton::set_pwm_period(uint16_t value, bool load) { + value &= 0xffff; + i2c_reg_write_uint8(reg::PWMPL, (uint8_t)(value & 0xff)); + i2c_reg_write_uint8(reg::PWMPH, (uint8_t)(value >> 8)); + + if(load) + pwm_load(); + } + + uint8_t Nuvoton::get_mode(uint8_t pin) { + return pins[pin - 1].get_mode(); + } + + void Nuvoton::set_mode(uint8_t pin, uint8_t mode, bool schmitt_trigger, bool invert) { + if(pin < 1 || pin > NUM_PINS) + { + printf("ValueError: Pin should be in range 1-14.\n"); + return; + } + + Pin& io_pin = pins[pin - 1]; + + 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]); + } + return; + } + + if((io_type != Pin::TYPE_IO) && !io_pin.mode_supported(mode)) { + if(debug) { + printf("Pin %d does not support %s!\n", pin, MODE_NAMES[io_type]); + } + return; + } + + io_pin.set_mode(mode); + if(debug) { + printf("Setting pin %d to mode %s %s, state: %s\n", pin, MODE_NAMES[io_type], GPIO_NAMES[gpio_mode], STATE_NAMES[initial_state]); + } + + 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 + } + else { + if(io_pin.get_type() & Pin::TYPE_PWM) + clr_bit(io_pin.reg_io_pwm, io_pin.pwm_channel); + } + + 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 + pm1 &= 255 - (1 << io_pin.pin); + pm2 &= 255 - (1 << io_pin.pin); + + //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 + 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 + i2c_reg_write_uint8(io_pin.reg_p, (initial_state << 3) | io_pin.pin); + } + + int16_t Nuvoton::input(uint8_t pin, uint32_t adc_timeout) { + if(pin < 1 || pin > NUM_PINS) + { + if(debug) + printf("ValueError: Pin should be in range 1-14.\n"); + return -1; + } + + Pin& io_pin = pins[pin - 1]; + + if(io_pin.get_mode() == PIN_MODE_ADC) { + if(debug) { + printf("Reading ADC from pin %d\n", pin); + } + + clr_bits(reg::ADCCON0, 0x0f); + set_bits(reg::ADCCON0, io_pin.adc_channel); + i2c_reg_write_uint8(reg::AINDIDS, 0); + 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 + + //Wait for the ADCF conversion complete flag to be set + unsigned long start_time = millis(); + while(!get_bit(reg::ADCCON0, 7)) { + sleep_ms(10); + if(millis() - start_time >= adc_timeout) { + if(debug) + printf("Timeout waiting for ADC conversion!"); + return -1; + } + } + + uint8_t hi = i2c_reg_read_uint8(reg::ADCRH); + uint8_t lo = i2c_reg_read_uint8(reg::ADCRL); + return (uint16_t)(hi << 4) | (uint16_t)lo; + } + else { + if(debug) { + printf("Reading IO from pin %d\n", pin); + } + + uint8_t pv = get_bit(io_pin.reg_p, io_pin.pin); + return (pv) ? 1 : 0; + } + } + + float Nuvoton::input_as_voltage(uint8_t pin, uint32_t adc_timeout) { + if(pin < 1 || pin > NUM_PINS) + { + if(debug) + printf("ValueError: Pin should be in range 1-14.\n"); + return -1; + } + + Pin& io_pin = pins[pin - 1]; + + if(io_pin.get_mode() == PIN_MODE_ADC) { + if(debug) { + printf("Reading ADC from pin %d\n", pin); + } + + clr_bits(reg::ADCCON0, 0x0f); + set_bits(reg::ADCCON0, io_pin.adc_channel); + i2c_reg_write_uint8(reg::AINDIDS, 0); + 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 + + //Wait for the ADCF conversion complete flag to be set + unsigned long start_time = millis(); + while(!get_bit(reg::ADCCON0, 7)) { + sleep_ms(1); + if(millis() - start_time >= adc_timeout) { + if(debug) + printf("Timeout waiting for ADC conversion!\n"); + return -1; + } + } + + uint8_t hi = i2c_reg_read_uint8(reg::ADCRH); + uint8_t lo = i2c_reg_read_uint8(reg::ADCRL); + return ((float)((uint16_t)(hi << 4) | (uint16_t)lo) / 4095.0f) * vref; + } + else { + if(debug) { + printf("Reading IO from pin %d\n", pin); + } + + uint8_t pv = get_bit(io_pin.reg_p, io_pin.pin); + return (pv) ? vref : 0.0f; + } + } + + void Nuvoton::output(uint8_t pin, uint16_t value, bool load) { + if(pin < 1 || pin > NUM_PINS) { + printf("Pin should be in range 1-14."); + return; + } + + Pin& io_pin = pins[pin - 1]; + + if(io_pin.get_mode() == PIN_MODE_PWM) { + if(debug) { + printf("Outputting PWM to pin: %d\n", pin); + } + + i2c_reg_write_uint8(io_pin.reg_pwml, (uint8_t)(value & 0xff)); + i2c_reg_write_uint8(io_pin.reg_pwmh, (uint8_t)(value >> 8)); + if(load) + pwm_load(); + } + else { + if(value == 0) { + if(debug) { + printf("Outputting LOW to pin: %d\n", pin); + } + + clr_bit(io_pin.reg_p, io_pin.pin); + } + else if(value == 1) { + if(debug) { + printf("Outputting HIGH to pin: %d\n", pin); + } + + set_bit(io_pin.reg_p, io_pin.pin); + } + } + } + + void Nuvoton::setup_rotary_encoder(uint8_t channel, uint8_t pinA, uint8_t pinB, uint8_t pinC, bool count_microsteps) { + channel -= 1; + set_mode(pinA, PIN_MODE_PU, true); + set_mode(pinB, PIN_MODE_PU, true); + + if(pinC != 0) { + set_mode(pinC, PIN_MODE_OD); + output(pinC, 0); + } + + i2c_reg_write_uint8(ENC_CFG[channel], pinA | (pinB << 4)); + change_bit(reg::ENC_EN, (channel * 2) + 1, count_microsteps); + set_bit(reg::ENC_EN, channel * 2); + + //Reset internal encoder count to zero + uint8_t reg = ENC_COUNT[channel]; + i2c_reg_write_uint8(reg, 0x00); + } + + int16_t Nuvoton::read_rotary_encoder(uint8_t channel) { + channel -= 1; + int16_t last = encoder_last[channel]; + uint8_t reg = ENC_COUNT[channel]; + int16_t value = (int16_t)i2c_reg_read_uint8(reg); + + if(value & 0b10000000) + value -= 256; + + if(last > 64 && value < -64) + encoder_offset[channel] += 256; + if(last < -64 && value > 64) + encoder_offset[channel] -= 256; + + encoder_last[channel] = value; + + return encoder_offset[channel] + value; + } + + uint8_t Nuvoton::i2c_reg_read_uint8(uint8_t reg) { + uint8_t value; + i2c_write_blocking(i2c, address, ®, 1, true); + i2c_read_blocking(i2c, address, (uint8_t *)&value, 1, false); + return value; + } + + void Nuvoton::i2c_reg_write_uint8(uint8_t reg, uint8_t value) { + uint8_t buffer[2] = {reg, value}; + i2c_write_blocking(i2c, address, buffer, 2, false); + } + + uint8_t Nuvoton::get_bit(uint8_t reg, uint8_t bit) { + //Returns the specified bit (nth position from right) from a register + return i2c_reg_read_uint8(reg) & (1 << bit); + } + + void Nuvoton::set_bits(uint8_t reg, uint8_t bits) { + //Set the specified bits (using a mask) in a register. + + //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) { + for(uint8_t bit = 0; bit < 8; bit++) { + if(bits & (1 << bit)) + i2c_reg_write_uint8(reg, 0b1000 | (bit & 0b111)); + } + reg_in_bit_addressed_regs = true; + break; + } + } + + //Now deal with any other registers + if(!reg_in_bit_addressed_regs) { + uint8_t value = i2c_reg_read_uint8(reg); + sleep_us(10); + i2c_reg_write_uint8(reg, value | bits); + } + } + + void Nuvoton::set_bit(uint8_t reg, uint8_t bit) { + //Set the specified bit (nth position from right) in a register. + set_bits(reg, (1 << bit)); + } + + void Nuvoton::clr_bits(uint8_t reg, uint8_t bits) { + bool reg_in_bit_addressed_regs = false; + for(uint8_t i = 0; i < NUM_BIT_ADDRESSED_REGISTERS; i++) { + if(BIT_ADDRESSED_REGS[i] == reg) { + for(uint8_t bit = 0; bit < 8; bit++) { + if(bits & (1 << bit)) + i2c_reg_write_uint8(reg, 0b0000 | (bit & 0b111)); + } + reg_in_bit_addressed_regs = true; + break; + } + } + + //Now deal with any other registers + if(!reg_in_bit_addressed_regs) { + uint8_t value = i2c_reg_read_uint8(reg); + sleep_us(10); + i2c_reg_write_uint8(reg, value & ~bits); + } + } + + void Nuvoton::clr_bit(uint8_t reg, uint8_t bit) { + //Clear the specified bit (nth position from right) in a register. + clr_bits(reg, (1 << bit)); + } + + void Nuvoton::change_bit(uint8_t reg, uint8_t bit, bool state) { + //Toggle one register bit on/off. + if(state) + set_bit(reg, bit); + else + clr_bit(reg, bit); + } + + void Nuvoton::wait_for_flash(void) { + //Wait for the IOE to finish writing non-volatile memory. + unsigned long start_time = millis(); + while(get_interrupt_flag()) { + if(millis() - start_time > timeout) { + printf("Timed out waiting for interrupt!\n"); + return; + } + sleep_ms(1); + } + + start_time = millis(); + while(!get_interrupt_flag()) { + if(millis() - start_time > timeout) { + printf("Timed out waiting for interrupt!\n"); + return; + } + sleep_ms(1); + } + } + + uint32_t Nuvoton::millis() { + return to_ms_since_boot(get_absolute_time()); + } +} \ No newline at end of file diff --git a/drivers/nuvoton/nuvoton.hpp b/drivers/nuvoton/nuvoton.hpp new file mode 100644 index 00000000..a295ffa6 --- /dev/null +++ b/drivers/nuvoton/nuvoton.hpp @@ -0,0 +1,235 @@ +#pragma once + +#include "hardware/i2c.h" +#include "hardware/gpio.h" + +namespace pimoroni { + + class Nuvoton { + //-------------------------------------------------- + // Constants + //-------------------------------------------------- + private: + //These values encode our desired pin function: IO, ADC, PWM + //alongwide the GPIO MODE for that port and pin (section 8.1) + //1st and 2nd bits encode the gpio state + //3rd and 4th bits encode the IO mode (i.e. IO, PWM, ADC) + //the 5th bit additionally encodes the default output state + static const uint8_t PIN_MODE_IO = 0b00000; //General IO mode, IE: not ADC or PWM + static const uint8_t PIN_MODE_QB = 0b00000; //Output, Quasi-Bidirectional mode + static const uint8_t PIN_MODE_PP = 0b00001; //Output, Push-Pull mode + static const uint8_t PIN_MODE_IN = 0b00010; //Input-only (high-impedance) + static const uint8_t PIN_MODE_PU = 0b10000; //Input (with pull-up) + static const uint8_t PIN_MODE_OD = 0b00011; //Output, Open-Drain mode + static const uint8_t PIN_MODE_PWM = 0b00101; //PWM, Output, Push-Pull mode + static const uint8_t PIN_MODE_ADC = 0b01010; //ADC, Input-only (high-impedance) + + public: + static const uint8_t DEFAULT_I2C_ADDRESS = 0x18; + static const uint8_t DEFAULT_SDA_PIN = 20; + static const uint8_t DEFAULT_SCL_PIN = 21; + static const uint8_t DEFAULT_INT_PIN = 22; + + static const uint16_t CHIP_ID = 0xE26A; + static const uint8_t CHIP_VERSION = 2; + + static const uint8_t PIN_IN = PIN_MODE_IN; //0b00010 + static const uint8_t PIN_IN_PULL_UP = PIN_MODE_PU; //0b10000 + static const uint8_t PIN_IN_PU = PIN_MODE_PU; //0b10000 + static const uint8_t PIN_OUT = PIN_MODE_PP; //0b00001 + static const uint8_t PIN_PWM = PIN_MODE_PWM; //0b00101 + static const uint8_t PIN_ADC = PIN_MODE_ADC; //0b01010 + + static const uint8_t NUM_PINS = 14; + + + //-------------------------------------------------- + // Subclasses + //-------------------------------------------------- + private: + class Pin { + public: + //-------------------------------------------------- + // Enums + //-------------------------------------------------- + enum IOType { + TYPE_IO = 0b00, + TYPE_PWM = 0b01, + TYPE_ADC = 0b10, + TYPE_ADC_OR_PWM = 0b11 + }; + + + //-------------------------------------------------- + // Constants + //-------------------------------------------------- + private: + //The PxM1 and PxM2 registers encode GPIO MODE + //0 0 = Quasi-bidirectional + //0 1 = Push-pull + //1 0 = Input-only (high-impedance) + //1 1 = Open-drain + static const uint8_t PxM1[4]; //[reg::P0M1, reg::P1M1, -1, reg::P3M1] + static const uint8_t PxM2[4]; //[reg::P0M2, reg::P1M2, -1, reg::P3M2] + + //The Px input register + static const uint8_t Px[4]; //[reg::P0, reg::P1, -1, reg::P3] + + //The PxS Schmitt trigger register + static const uint8_t PxS[4]; //[reg::P0S, reg::P1S, -1, reg::P3S] + static const uint8_t MASK_P[4]; //[reg::INT_MASK_P0, reg::INT_MASK_P1, -1, reg::INT_MASK_P3] + + static const uint8_t PWML[6]; //[reg::PWM0L, reg::PWM1L, reg::PWM2L, reg::PWM3L, reg::PWM4L, reg::PWM5L] + static const uint8_t PWMH[6]; //[reg::PWM0H, reg::PWM1H, reg::PWM2H, reg::PWM3H, reg::PWM4H, reg::PWM5H] + + + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: + const IOType type; + uint8_t mode; + public: + const uint8_t port; + const uint8_t pin; + const uint8_t adc_channel; + const uint8_t pwm_channel; + + const uint8_t reg_m1; + const uint8_t reg_m2; + const uint8_t reg_p; + const uint8_t reg_ps; + const uint8_t reg_int_mask_p; + + const uint8_t reg_io_pwm; + const uint8_t reg_pwml; + const uint8_t reg_pwmh; + + + //-------------------------------------------------- + // Constructors + //-------------------------------------------------- + private: + Pin(uint8_t port, uint8_t pin); //Constructor for IO pin + Pin(uint8_t port, uint8_t pin, uint8_t pwm_channel, uint8_t reg_iopwm); //Constructor for PWM pin + Pin(uint8_t port, uint8_t pin, uint8_t adc_channel); //Constructor for ADC pin + Pin(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm); //Constructor for ADC or PWM pin + + + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + static Pin io(uint8_t port, uint8_t pin); //Nicer function for creating an IO pin + static Pin pwm(uint8_t port, uint8_t pin, uint8_t channel, uint8_t reg_iopwm); //Nicer function for creating a PWM pin + static Pin adc(uint8_t port, uint8_t pin, uint8_t channel); //Nicer function for creating an ADC pin + static Pin adc_or_pwm(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm); //Nicer function for creating an ADC or PWM pin + + //-------------------------------------------------- + + IOType get_type(void); + uint8_t get_mode(void); + void set_mode(uint8_t mode); + + bool mode_supported(uint8_t mode); + }; + + + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: + i2c_inst_t *i2c; + + // interface pins with our standard defaults where appropriate + int8_t address = DEFAULT_I2C_ADDRESS; + int8_t sda = DEFAULT_SDA_PIN; + int8_t scl = DEFAULT_SCL_PIN; + int8_t interrupt = DEFAULT_INT_PIN; + + uint32_t timeout; + bool debug; + float vref; + int16_t encoder_offset[4];; + int16_t encoder_last[4]; + Pin pins[NUM_PINS]; + + + //-------------------------------------------------- + // Constructors/Destructor + //-------------------------------------------------- + public: + Nuvoton(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt, uint8_t address = DEFAULT_I2C_ADDRESS, uint32_t timeout = 1, bool debug = false); + Nuvoton(uint8_t address = DEFAULT_I2C_ADDRESS, uint32_t timeout = 1, bool debug = false); + + + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + bool init(bool skip_chip_id_check = false); + + //-------------------------------------------------- + + uint16_t get_chip_id(); + + void set_addr(uint8_t address); + + float get_adc_vref(); + void set_adc_vref(float vref); + + //-------------------------------------------------- + + void enable_interrupt_out(bool pin_swap = false); + void disable_interrupt_out(); + + uint8_t 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(); + + void pwm_clear(bool wait_for_clear = true); + bool pwm_clearing(); + + bool set_pwm_control(uint8_t divider); + void set_pwm_period(uint16_t value, bool load = true); + + //-------------------------------------------------- + + uint8_t get_mode(uint8_t pin); + void set_mode(uint8_t pin, uint8_t mode, bool schmitt_trigger = false, bool invert = false); + + int16_t input(uint8_t pin, uint32_t adc_timeout = 1); + float input_as_voltage(uint8_t pin, uint32_t adc_timeout = 1); + + 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); + int16_t read_rotary_encoder(uint8_t channel); + + //-------------------------------------------------- + private: + uint8_t i2c_reg_read_uint8(uint8_t reg); + void i2c_reg_write_uint8(uint8_t reg, uint8_t value); + + uint8_t get_bit(uint8_t reg, uint8_t bit); + void set_bits(uint8_t reg, uint8_t bits); + void set_bit(uint8_t reg, uint8_t bit); + void clr_bits(uint8_t reg, uint8_t bits); + void clr_bit(uint8_t reg, uint8_t bit); + void change_bit(uint8_t reg, uint8_t bit, bool state); + + void wait_for_flash(); + + uint32_t millis(); + }; + +} diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 62bd90c5..197851e9 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,10 +1,14 @@ add_subdirectory(breakout_dotmatrix) +add_subdirectory(breakout_encoder) +add_subdirectory(breakout_ioexpander) add_subdirectory(breakout_ltr559) add_subdirectory(breakout_colourlcd160x80) add_subdirectory(breakout_colourlcd240x240) add_subdirectory(breakout_roundlcd) add_subdirectory(breakout_rgbmatrix5x5) add_subdirectory(breakout_matrix11x7) +add_subdirectory(breakout_mics6814) +add_subdirectory(breakout_potentiometer) add_subdirectory(breakout_trackball) add_subdirectory(breakout_sgp30) add_subdirectory(breakout_as7262) diff --git a/libraries/breakout_encoder/CMakeLists.txt b/libraries/breakout_encoder/CMakeLists.txt new file mode 100644 index 00000000..3f504139 --- /dev/null +++ b/libraries/breakout_encoder/CMakeLists.txt @@ -0,0 +1 @@ +include(breakout_encoder.cmake) diff --git a/libraries/breakout_encoder/breakout_encoder.cmake b/libraries/breakout_encoder/breakout_encoder.cmake new file mode 100644 index 00000000..d3a8f311 --- /dev/null +++ b/libraries/breakout_encoder/breakout_encoder.cmake @@ -0,0 +1,11 @@ +set(LIB_NAME breakout_encoder) +add_library(${LIB_NAME} INTERFACE) + +target_sources(${LIB_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp +) + +target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib nuvoton) diff --git a/libraries/breakout_encoder/breakout_encoder.cpp b/libraries/breakout_encoder/breakout_encoder.cpp new file mode 100644 index 00000000..1536bba0 --- /dev/null +++ b/libraries/breakout_encoder/breakout_encoder.cpp @@ -0,0 +1,5 @@ +#include "breakout_encoder.hpp" + +namespace pimoroni { + +} diff --git a/libraries/breakout_encoder/breakout_encoder.hpp b/libraries/breakout_encoder/breakout_encoder.hpp new file mode 100644 index 00000000..65af31bc --- /dev/null +++ b/libraries/breakout_encoder/breakout_encoder.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "../../drivers/nuvoton/nuvoton.hpp" + +namespace pimoroni { + + typedef Nuvoton BreakoutEncoder; +} diff --git a/libraries/breakout_ioexpander/CMakeLists.txt b/libraries/breakout_ioexpander/CMakeLists.txt new file mode 100644 index 00000000..1483b234 --- /dev/null +++ b/libraries/breakout_ioexpander/CMakeLists.txt @@ -0,0 +1 @@ +include(breakout_ioexpander.cmake) diff --git a/libraries/breakout_ioexpander/breakout_ioexpander.cmake b/libraries/breakout_ioexpander/breakout_ioexpander.cmake new file mode 100644 index 00000000..8ee2bb90 --- /dev/null +++ b/libraries/breakout_ioexpander/breakout_ioexpander.cmake @@ -0,0 +1,11 @@ +set(LIB_NAME breakout_ioexpander) +add_library(${LIB_NAME} INTERFACE) + +target_sources(${LIB_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp +) + +target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib nuvoton) diff --git a/libraries/breakout_ioexpander/breakout_ioexpander.cpp b/libraries/breakout_ioexpander/breakout_ioexpander.cpp new file mode 100644 index 00000000..8f0f2524 --- /dev/null +++ b/libraries/breakout_ioexpander/breakout_ioexpander.cpp @@ -0,0 +1,5 @@ +#include "breakout_ioexpander.hpp" + +namespace pimoroni { + +} diff --git a/libraries/breakout_ioexpander/breakout_ioexpander.hpp b/libraries/breakout_ioexpander/breakout_ioexpander.hpp new file mode 100644 index 00000000..09bf993b --- /dev/null +++ b/libraries/breakout_ioexpander/breakout_ioexpander.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "../../drivers/nuvoton/nuvoton.hpp" + +namespace pimoroni { + + typedef Nuvoton BreakoutIOExpander; +} diff --git a/libraries/breakout_mics6814/CMakeLists.txt b/libraries/breakout_mics6814/CMakeLists.txt new file mode 100644 index 00000000..4ebc0c12 --- /dev/null +++ b/libraries/breakout_mics6814/CMakeLists.txt @@ -0,0 +1 @@ +include(breakout_mics6814.cmake) diff --git a/libraries/breakout_mics6814/breakout_mics6814.cmake b/libraries/breakout_mics6814/breakout_mics6814.cmake new file mode 100644 index 00000000..e977a979 --- /dev/null +++ b/libraries/breakout_mics6814/breakout_mics6814.cmake @@ -0,0 +1,11 @@ +set(LIB_NAME breakout_mics6814) +add_library(${LIB_NAME} INTERFACE) + +target_sources(${LIB_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp +) + +target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib nuvoton) diff --git a/libraries/breakout_mics6814/breakout_mics6814.cpp b/libraries/breakout_mics6814/breakout_mics6814.cpp new file mode 100644 index 00000000..64a37ebb --- /dev/null +++ b/libraries/breakout_mics6814/breakout_mics6814.cpp @@ -0,0 +1,5 @@ +#include "breakout_mics6814.hpp" + +namespace pimoroni { + +} diff --git a/libraries/breakout_mics6814/breakout_mics6814.hpp b/libraries/breakout_mics6814/breakout_mics6814.hpp new file mode 100644 index 00000000..82e015ea --- /dev/null +++ b/libraries/breakout_mics6814/breakout_mics6814.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "../../drivers/nuvoton/nuvoton.hpp" + +namespace pimoroni { + + typedef Nuvoton BreakoutMICS6814; +} diff --git a/libraries/breakout_potentiometer/CMakeLists.txt b/libraries/breakout_potentiometer/CMakeLists.txt new file mode 100644 index 00000000..ec84da9c --- /dev/null +++ b/libraries/breakout_potentiometer/CMakeLists.txt @@ -0,0 +1 @@ +include(breakout_potentiometer.cmake) diff --git a/libraries/breakout_potentiometer/breakout_potentiometer.cmake b/libraries/breakout_potentiometer/breakout_potentiometer.cmake new file mode 100644 index 00000000..53f4863e --- /dev/null +++ b/libraries/breakout_potentiometer/breakout_potentiometer.cmake @@ -0,0 +1,11 @@ +set(LIB_NAME breakout_potentiometer) +add_library(${LIB_NAME} INTERFACE) + +target_sources(${LIB_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp +) + +target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib nuvoton) diff --git a/libraries/breakout_potentiometer/breakout_potentiometer.cpp b/libraries/breakout_potentiometer/breakout_potentiometer.cpp new file mode 100644 index 00000000..d4240571 --- /dev/null +++ b/libraries/breakout_potentiometer/breakout_potentiometer.cpp @@ -0,0 +1,5 @@ +#include "breakout_potentiometer.hpp" + +namespace pimoroni { + +} diff --git a/libraries/breakout_potentiometer/breakout_potentiometer.hpp b/libraries/breakout_potentiometer/breakout_potentiometer.hpp new file mode 100644 index 00000000..7ff338f5 --- /dev/null +++ b/libraries/breakout_potentiometer/breakout_potentiometer.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "../../drivers/nuvoton/nuvoton.hpp" + +namespace pimoroni { + + typedef Nuvoton BreakoutPotentiometer; +} From 05af3e86bafa8e86b861f7159ed77b4ced2e54f2 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Tue, 11 May 2021 17:18:43 +0100 Subject: [PATCH 02/27] Renamed IOExpander and added Pot, Enc, and MICS specific classes --- drivers/CMakeLists.txt | 2 +- drivers/ioexpander/CMakeLists.txt | 1 + .../ioexpander.cmake} | 2 +- .../nuvoton.cpp => ioexpander/ioexpander.cpp} | 134 +++++++++------- .../nuvoton.hpp => ioexpander/ioexpander.hpp} | 128 +++++++-------- drivers/nuvoton/CMakeLists.txt | 1 - examples/CMakeLists.txt | 3 + examples/breakout_encoder/CMakeLists.txt | 12 ++ examples/breakout_encoder/demo.cpp | 23 +++ examples/breakout_ioexpander/CMakeLists.txt | 12 ++ examples/breakout_ioexpander/demo.cpp | 23 +++ examples/breakout_mics6814/CMakeLists.txt | 12 ++ examples/breakout_mics6814/demo.cpp | 23 +++ .../breakout_potentiometer/CMakeLists.txt | 12 ++ examples/breakout_potentiometer/demo.cpp | 23 +++ .../breakout_encoder/breakout_encoder.cmake | 2 +- .../breakout_encoder/breakout_encoder.cpp | 83 +++++++++- .../breakout_encoder/breakout_encoder.hpp | 91 ++++++++++- .../breakout_ioexpander.cmake | 2 +- .../breakout_ioexpander.hpp | 4 +- .../breakout_mics6814/breakout_mics6814.cmake | 2 +- .../breakout_mics6814/breakout_mics6814.cpp | 151 +++++++++++++++++- .../breakout_mics6814/breakout_mics6814.hpp | 101 +++++++++++- .../breakout_potentiometer.cmake | 2 +- .../breakout_potentiometer.cpp | 106 +++++++++++- .../breakout_potentiometer.hpp | 91 ++++++++++- 26 files changed, 898 insertions(+), 148 deletions(-) create mode 100644 drivers/ioexpander/CMakeLists.txt rename drivers/{nuvoton/nuvoton.cmake => ioexpander/ioexpander.cmake} (91%) rename drivers/{nuvoton/nuvoton.cpp => ioexpander/ioexpander.cpp} (80%) rename drivers/{nuvoton/nuvoton.hpp => ioexpander/ioexpander.hpp} (56%) delete mode 100644 drivers/nuvoton/CMakeLists.txt create mode 100644 examples/breakout_encoder/CMakeLists.txt create mode 100644 examples/breakout_encoder/demo.cpp create mode 100644 examples/breakout_ioexpander/CMakeLists.txt create mode 100644 examples/breakout_ioexpander/demo.cpp create mode 100644 examples/breakout_mics6814/CMakeLists.txt create mode 100644 examples/breakout_mics6814/demo.cpp create mode 100644 examples/breakout_potentiometer/CMakeLists.txt create mode 100644 examples/breakout_potentiometer/demo.cpp diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index fd0ddca6..ab9f9dcf 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -1,11 +1,11 @@ add_subdirectory(esp32spi) +add_subdirectory(ioexpander) add_subdirectory(ltp305) add_subdirectory(ltr559) add_subdirectory(sgp30) add_subdirectory(st7735) add_subdirectory(st7789) add_subdirectory(msa301) -add_subdirectory(nuvoton) add_subdirectory(rv3028) add_subdirectory(trackball) add_subdirectory(vl53l1x) diff --git a/drivers/ioexpander/CMakeLists.txt b/drivers/ioexpander/CMakeLists.txt new file mode 100644 index 00000000..57a5ff84 --- /dev/null +++ b/drivers/ioexpander/CMakeLists.txt @@ -0,0 +1 @@ +include(ioexpander.cmake) diff --git a/drivers/nuvoton/nuvoton.cmake b/drivers/ioexpander/ioexpander.cmake similarity index 91% rename from drivers/nuvoton/nuvoton.cmake rename to drivers/ioexpander/ioexpander.cmake index bcc5ab15..dbd7a67c 100644 --- a/drivers/nuvoton/nuvoton.cmake +++ b/drivers/ioexpander/ioexpander.cmake @@ -1,4 +1,4 @@ -set(DRIVER_NAME nuvoton) +set(DRIVER_NAME ioexpander) add_library(${DRIVER_NAME} INTERFACE) target_sources(${DRIVER_NAME} INTERFACE diff --git a/drivers/nuvoton/nuvoton.cpp b/drivers/ioexpander/ioexpander.cpp similarity index 80% rename from drivers/nuvoton/nuvoton.cpp rename to drivers/ioexpander/ioexpander.cpp index 59b3a5af..057cea57 100644 --- a/drivers/nuvoton/nuvoton.cpp +++ b/drivers/ioexpander/ioexpander.cpp @@ -3,7 +3,7 @@ #include #include -#include "nuvoton.hpp" +#include "ioexpander.hpp" namespace pimoroni { @@ -220,61 +220,61 @@ namespace pimoroni { static const uint8_t ENC_CFG[4] = {reg::ENC_1_CFG, reg::ENC_2_CFG, reg::ENC_3_CFG, reg::ENC_4_CFG}; static const uint8_t ENC_COUNT[4] = {reg::ENC_1_COUNT, reg::ENC_2_COUNT, reg::ENC_3_COUNT, reg::ENC_4_COUNT}; - const uint8_t Nuvoton::Pin::PxM1[4] = {reg::P0M1, reg::P1M1, (uint8_t)-1, reg::P3M1}; - const uint8_t Nuvoton::Pin::PxM2[4] = {reg::P0M2, reg::P1M2, (uint8_t)-1, reg::P3M2}; - const uint8_t Nuvoton::Pin::Px[4] = {reg::P0, reg::P1, (uint8_t)-1, reg::P3}; + const uint8_t IOExpander::Pin::PxM1[4] = {reg::P0M1, reg::P1M1, (uint8_t)-1, reg::P3M1}; + const uint8_t IOExpander::Pin::PxM2[4] = {reg::P0M2, reg::P1M2, (uint8_t)-1, reg::P3M2}; + const uint8_t IOExpander::Pin::Px[4] = {reg::P0, reg::P1, (uint8_t)-1, reg::P3}; - const uint8_t Nuvoton::Pin::PxS[4] = {reg::P0S, reg::P1S, (uint8_t)-1, reg::P3S}; - const uint8_t Nuvoton::Pin::MASK_P[4] = {reg::INT_MASK_P0, reg::INT_MASK_P1, (uint8_t)-1, reg::INT_MASK_P3}; + const uint8_t IOExpander::Pin::PxS[4] = {reg::P0S, reg::P1S, (uint8_t)-1, reg::P3S}; + const uint8_t IOExpander::Pin::MASK_P[4] = {reg::INT_MASK_P0, reg::INT_MASK_P1, (uint8_t)-1, reg::INT_MASK_P3}; - const uint8_t Nuvoton::Pin::PWML[6] = {reg::PWM0L, reg::PWM1L, reg::PWM2L, reg::PWM3L, reg::PWM4L, reg::PWM5L}; - const uint8_t Nuvoton::Pin::PWMH[6] = {reg::PWM0H, reg::PWM1H, reg::PWM2H, reg::PWM3H, reg::PWM4H, reg::PWM5H}; + const uint8_t IOExpander::Pin::PWML[6] = {reg::PWM0L, reg::PWM1L, reg::PWM2L, reg::PWM3L, reg::PWM4L, reg::PWM5L}; + const uint8_t IOExpander::Pin::PWMH[6] = {reg::PWM0H, reg::PWM1H, reg::PWM2H, reg::PWM3H, reg::PWM4H, reg::PWM5H}; static const char* MODE_NAMES[3] = {"IO", "PWM", "ADC"}; static const char* GPIO_NAMES[4] = {"QB", "PP", "IN", "OD"}; static const char* STATE_NAMES[2] = {"LOW", "HIGH"}; - Nuvoton::Pin::Pin(uint8_t port, uint8_t pin) : + IOExpander::Pin::Pin(uint8_t port, uint8_t pin) : type(TYPE_IO), mode(0), port(port), pin(pin), adc_channel(0), pwm_channel(0), reg_m1(PxM1[port]), reg_m2(PxM2[port]), reg_p(Px[port]), reg_ps(PxS[port]), reg_int_mask_p(MASK_P[port]), reg_io_pwm(0), reg_pwml(0), reg_pwmh(0) { } - Nuvoton::Pin::Pin(uint8_t port, uint8_t pin, uint8_t pwm_channel, uint8_t reg_io_pwm) : + IOExpander::Pin::Pin(uint8_t port, uint8_t pin, uint8_t pwm_channel, uint8_t reg_io_pwm) : type(TYPE_PWM), mode(0), port(port), pin(pin), adc_channel(0), pwm_channel(pwm_channel), reg_m1(PxM1[port]), reg_m2(PxM2[port]), reg_p(Px[port]), reg_ps(PxS[port]), reg_int_mask_p(MASK_P[port]), reg_io_pwm(reg_io_pwm), reg_pwml(PWML[pwm_channel]), reg_pwmh(PWMH[pwm_channel]) { } - Nuvoton::Pin::Pin(uint8_t port, uint8_t pin, uint8_t adc_channel) : + IOExpander::Pin::Pin(uint8_t port, uint8_t pin, uint8_t adc_channel) : type(TYPE_ADC), mode(0), port(port), pin(pin), adc_channel(adc_channel), pwm_channel(0), reg_m1(PxM1[port]), reg_m2(PxM2[port]), reg_p(Px[port]), reg_ps(PxS[port]), reg_int_mask_p(MASK_P[port]), reg_io_pwm(0), reg_pwml(0), reg_pwmh(0) { } - Nuvoton::Pin::Pin(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_io_pwm) : + IOExpander::Pin::Pin(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_io_pwm) : type(TYPE_ADC_OR_PWM), mode(0), port(port), pin(pin), adc_channel(adc_channel), pwm_channel(pwm_channel), reg_m1(PxM1[port]), reg_m2(PxM2[port]), reg_p(Px[port]), reg_ps(PxS[port]), reg_int_mask_p(MASK_P[port]), reg_io_pwm(reg_io_pwm), reg_pwml(PWML[pwm_channel]), reg_pwmh(PWMH[pwm_channel]) { } - Nuvoton::Pin Nuvoton::Pin::io(uint8_t port, uint8_t pin) { + IOExpander::Pin IOExpander::Pin::io(uint8_t port, uint8_t pin) { return Pin(port, pin); } - Nuvoton::Pin Nuvoton::Pin::pwm(uint8_t port, uint8_t pin, uint8_t channel, uint8_t reg_iopwm) { + IOExpander::Pin IOExpander::Pin::pwm(uint8_t port, uint8_t pin, uint8_t channel, uint8_t reg_iopwm) { return Pin(port, pin, channel, reg_iopwm); } - Nuvoton::Pin Nuvoton::Pin::adc(uint8_t port, uint8_t pin, uint8_t channel) { + IOExpander::Pin IOExpander::Pin::adc(uint8_t port, uint8_t pin, uint8_t channel) { return Pin(port, pin, channel); } - Nuvoton::Pin Nuvoton::Pin::adc_or_pwm(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm) { + IOExpander::Pin IOExpander::Pin::adc_or_pwm(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm) { return Pin(port, pin, adc_channel, pwm_channel, reg_iopwm); } - bool Nuvoton::Pin::mode_supported(uint8_t mode) { + bool IOExpander::Pin::mode_supported(uint8_t mode) { bool supported = false; if((type & TYPE_PWM) && (mode == PIN_MODE_PWM)) { supported = true; @@ -285,19 +285,19 @@ namespace pimoroni { return supported; } - Nuvoton::Pin::IOType Nuvoton::Pin::get_type() { + IOExpander::Pin::IOType IOExpander::Pin::get_type() { return type; } - uint8_t Nuvoton::Pin::get_mode() { + uint8_t IOExpander::Pin::get_mode() { return mode; } - void Nuvoton::Pin::set_mode(uint8_t mode) { + void IOExpander::Pin::set_mode(uint8_t mode) { this->mode = mode; } - Nuvoton::Nuvoton(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt, uint8_t address, uint32_t timeout, bool debug) : + IOExpander::IOExpander(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt, uint8_t address, uint32_t timeout, bool debug) : i2c(i2c), sda(sda), scl(scl), interrupt(interrupt), address(address), timeout(timeout), debug(debug), vref(3.3f), encoder_offset{0,0,0,0}, @@ -318,11 +318,11 @@ namespace pimoroni { Pin::adc(1, 7, 0)} { } - Nuvoton::Nuvoton(uint8_t address, uint32_t timeout, bool debug) : - Nuvoton(i2c0, DEFAULT_SDA_PIN, DEFAULT_SCL_PIN, DEFAULT_INT_PIN, address, timeout, debug) { + IOExpander::IOExpander(uint8_t address, uint32_t timeout, bool debug) : + IOExpander(i2c0, DEFAULT_SDA_PIN, DEFAULT_SCL_PIN, DEFAULT_INT_PIN, address, timeout, debug) { } - bool Nuvoton::init(bool skipChipIdCheck) { + bool IOExpander::init(bool skipChipIdCheck) { bool succeeded = true; i2c_init(i2c, 400000); @@ -348,11 +348,27 @@ namespace pimoroni { return succeeded; } - uint16_t Nuvoton::get_chip_id() { + i2c_inst_t* IOExpander::get_i2c() const { + return i2c; + } + + int IOExpander::get_sda() const { + return sda; + } + + int IOExpander::get_scl() const { + return scl; + } + + int IOExpander::get_int() const { + return interrupt; + } + + uint16_t IOExpander::get_chip_id() { return ((uint16_t)i2c_reg_read_uint8(reg::CHIP_ID_H) << 8) | (uint16_t)i2c_reg_read_uint8(reg::CHIP_ID_L); } - void Nuvoton::set_addr(uint8_t address) { + void IOExpander::set_addr(uint8_t address) { set_bit(reg::CTRL, 4); i2c_reg_write_uint8(reg::ADDR, address); this->address = address; @@ -361,35 +377,35 @@ namespace pimoroni { clr_bit(reg::CTRL, 4); } - float Nuvoton::get_adc_vref() { + float IOExpander::get_adc_vref() { return vref; } - void Nuvoton::set_adc_vref(float vref) { + void IOExpander::set_adc_vref(float vref) { this->vref = vref; } - void Nuvoton::enable_interrupt_out(bool pin_swap) { + void IOExpander::enable_interrupt_out(bool pin_swap) { set_bit(reg::INT, int_bit::OUT_EN); change_bit(reg::INT, int_bit::PIN_SWAP, pin_swap); } - void Nuvoton::disable_interrupt_out() { + void IOExpander::disable_interrupt_out() { clr_bit(reg::INT, int_bit::OUT_EN); } - uint8_t Nuvoton::get_interrupt_flag() { + uint8_t IOExpander::get_interrupt_flag() { if(interrupt != 0) return !gpio_get(interrupt); else return get_bit(reg::INT, int_bit::TRIGD); } - void Nuvoton::clear_interrupt_flag() { + void IOExpander::clear_interrupt_flag() { clr_bit(reg::INT, int_bit::TRIGD); } - bool Nuvoton::set_pin_interrupt(uint8_t pin, bool enabled) { + bool IOExpander::set_pin_interrupt(uint8_t pin, bool enabled) { bool succeeded = false; if(pin >= 1 && pin <= NUM_PINS) { Pin& io_pin = pins[pin - 1]; @@ -401,14 +417,14 @@ namespace pimoroni { return succeeded; } - void Nuvoton::set_interrupt_callback(void (*callback)()) { + void IOExpander::set_interrupt_callback(void (*callback)()) { if(interrupt != 0 && callback != nullptr) { //attachInterrupt(digitalPinToInterrupt(_interruptPin), callback, FALLING); clear_interrupt_flag(); } } - void Nuvoton::pwm_load(bool wait_for_load) { + void IOExpander::pwm_load(bool wait_for_load) { //Load new period and duty registers into buffer uint32_t start_time = millis(); set_bit(reg::PWMCON0, 6); //Set the "LOAD" bit of PWMCON0 @@ -425,11 +441,11 @@ namespace pimoroni { } } - bool Nuvoton::pwm_loading() { + bool IOExpander::pwm_loading() { return get_bit(reg::PWMCON0, 6); } - void Nuvoton::pwm_clear(bool wait_for_clear) { + void IOExpander::pwm_clear(bool wait_for_clear) { uint32_t start_time = millis(); set_bit(reg::PWMCON0, 4); //Set the "CLRPWM" bit of PWMCON0 if(wait_for_clear) { @@ -444,11 +460,11 @@ namespace pimoroni { } } - bool Nuvoton::pwm_clearing() { + bool IOExpander::pwm_clearing() { return get_bit(reg::PWMCON0, 4); } - bool Nuvoton::set_pwm_control(uint8_t divider) { + bool IOExpander::set_pwm_control(uint8_t divider) { bool divider_good = true; uint8_t pwmdiv2 = 0; switch(divider) { @@ -482,7 +498,7 @@ namespace pimoroni { return divider_good; } - void Nuvoton::set_pwm_period(uint16_t value, bool load) { + void IOExpander::set_pwm_period(uint16_t value, bool load) { value &= 0xffff; i2c_reg_write_uint8(reg::PWMPL, (uint8_t)(value & 0xff)); i2c_reg_write_uint8(reg::PWMPH, (uint8_t)(value >> 8)); @@ -491,11 +507,11 @@ namespace pimoroni { pwm_load(); } - uint8_t Nuvoton::get_mode(uint8_t pin) { + uint8_t IOExpander::get_mode(uint8_t pin) { return pins[pin - 1].get_mode(); } - void Nuvoton::set_mode(uint8_t pin, uint8_t mode, bool schmitt_trigger, bool invert) { + void IOExpander::set_mode(uint8_t pin, uint8_t mode, bool schmitt_trigger, bool invert) { if(pin < 1 || pin > NUM_PINS) { printf("ValueError: Pin should be in range 1-14.\n"); @@ -559,7 +575,7 @@ namespace pimoroni { i2c_reg_write_uint8(io_pin.reg_p, (initial_state << 3) | io_pin.pin); } - int16_t Nuvoton::input(uint8_t pin, uint32_t adc_timeout) { + int16_t IOExpander::input(uint8_t pin, uint32_t adc_timeout) { if(pin < 1 || pin > NUM_PINS) { if(debug) @@ -608,7 +624,7 @@ namespace pimoroni { } } - float Nuvoton::input_as_voltage(uint8_t pin, uint32_t adc_timeout) { + float IOExpander::input_as_voltage(uint8_t pin, uint32_t adc_timeout) { if(pin < 1 || pin > NUM_PINS) { if(debug) @@ -658,7 +674,7 @@ namespace pimoroni { } } - void Nuvoton::output(uint8_t pin, uint16_t value, bool load) { + void IOExpander::output(uint8_t pin, uint16_t value, bool load) { if(pin < 1 || pin > NUM_PINS) { printf("Pin should be in range 1-14."); return; @@ -677,14 +693,14 @@ namespace pimoroni { pwm_load(); } else { - if(value == 0) { + if(value == LOW) { if(debug) { printf("Outputting LOW to pin: %d\n", pin); } clr_bit(io_pin.reg_p, io_pin.pin); } - else if(value == 1) { + else if(value == HIGH) { if(debug) { printf("Outputting HIGH to pin: %d\n", pin); } @@ -694,7 +710,7 @@ namespace pimoroni { } } - void Nuvoton::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 pinA, uint8_t pinB, uint8_t pinC, bool count_microsteps) { channel -= 1; set_mode(pinA, PIN_MODE_PU, true); set_mode(pinB, PIN_MODE_PU, true); @@ -713,7 +729,7 @@ namespace pimoroni { i2c_reg_write_uint8(reg, 0x00); } - int16_t Nuvoton::read_rotary_encoder(uint8_t channel) { + int16_t IOExpander::read_rotary_encoder(uint8_t channel) { channel -= 1; int16_t last = encoder_last[channel]; uint8_t reg = ENC_COUNT[channel]; @@ -732,24 +748,24 @@ namespace pimoroni { return encoder_offset[channel] + value; } - uint8_t Nuvoton::i2c_reg_read_uint8(uint8_t reg) { + uint8_t IOExpander::i2c_reg_read_uint8(uint8_t reg) { uint8_t value; i2c_write_blocking(i2c, address, ®, 1, true); i2c_read_blocking(i2c, address, (uint8_t *)&value, 1, false); return value; } - void Nuvoton::i2c_reg_write_uint8(uint8_t reg, uint8_t value) { + void IOExpander::i2c_reg_write_uint8(uint8_t reg, uint8_t value) { uint8_t buffer[2] = {reg, value}; i2c_write_blocking(i2c, address, buffer, 2, false); } - uint8_t Nuvoton::get_bit(uint8_t reg, uint8_t bit) { + uint8_t IOExpander::get_bit(uint8_t reg, uint8_t bit) { //Returns the specified bit (nth position from right) from a register return i2c_reg_read_uint8(reg) & (1 << bit); } - void Nuvoton::set_bits(uint8_t reg, uint8_t bits) { + void IOExpander::set_bits(uint8_t reg, uint8_t bits) { //Set the specified bits (using a mask) in a register. //Deal with special case registers first @@ -773,12 +789,12 @@ namespace pimoroni { } } - void Nuvoton::set_bit(uint8_t reg, uint8_t bit) { + void IOExpander::set_bit(uint8_t reg, uint8_t bit) { //Set the specified bit (nth position from right) in a register. set_bits(reg, (1 << bit)); } - void Nuvoton::clr_bits(uint8_t reg, uint8_t bits) { + void IOExpander::clr_bits(uint8_t reg, uint8_t bits) { bool reg_in_bit_addressed_regs = false; for(uint8_t i = 0; i < NUM_BIT_ADDRESSED_REGISTERS; i++) { if(BIT_ADDRESSED_REGS[i] == reg) { @@ -799,12 +815,12 @@ namespace pimoroni { } } - void Nuvoton::clr_bit(uint8_t reg, uint8_t bit) { + void IOExpander::clr_bit(uint8_t reg, uint8_t bit) { //Clear the specified bit (nth position from right) in a register. clr_bits(reg, (1 << bit)); } - void Nuvoton::change_bit(uint8_t reg, uint8_t bit, bool state) { + void IOExpander::change_bit(uint8_t reg, uint8_t bit, bool state) { //Toggle one register bit on/off. if(state) set_bit(reg, bit); @@ -812,7 +828,7 @@ namespace pimoroni { clr_bit(reg, bit); } - void Nuvoton::wait_for_flash(void) { + void IOExpander::wait_for_flash(void) { //Wait for the IOE to finish writing non-volatile memory. unsigned long start_time = millis(); while(get_interrupt_flag()) { @@ -833,7 +849,7 @@ namespace pimoroni { } } - uint32_t Nuvoton::millis() { + uint32_t IOExpander::millis() { return to_ms_since_boot(get_absolute_time()); } } \ No newline at end of file diff --git a/drivers/nuvoton/nuvoton.hpp b/drivers/ioexpander/ioexpander.hpp similarity index 56% rename from drivers/nuvoton/nuvoton.hpp rename to drivers/ioexpander/ioexpander.hpp index a295ffa6..31e1f017 100644 --- a/drivers/nuvoton/nuvoton.hpp +++ b/drivers/ioexpander/ioexpander.hpp @@ -5,24 +5,24 @@ namespace pimoroni { - class Nuvoton { + class IOExpander { //-------------------------------------------------- // Constants //-------------------------------------------------- private: - //These values encode our desired pin function: IO, ADC, PWM - //alongwide the GPIO MODE for that port and pin (section 8.1) - //1st and 2nd bits encode the gpio state - //3rd and 4th bits encode the IO mode (i.e. IO, PWM, ADC) - //the 5th bit additionally encodes the default output state - static const uint8_t PIN_MODE_IO = 0b00000; //General IO mode, IE: not ADC or PWM - static const uint8_t PIN_MODE_QB = 0b00000; //Output, Quasi-Bidirectional mode - static const uint8_t PIN_MODE_PP = 0b00001; //Output, Push-Pull mode - static const uint8_t PIN_MODE_IN = 0b00010; //Input-only (high-impedance) - static const uint8_t PIN_MODE_PU = 0b10000; //Input (with pull-up) - static const uint8_t PIN_MODE_OD = 0b00011; //Output, Open-Drain mode - static const uint8_t PIN_MODE_PWM = 0b00101; //PWM, Output, Push-Pull mode - static const uint8_t PIN_MODE_ADC = 0b01010; //ADC, Input-only (high-impedance) + // These values encode our desired pin function: IO, ADC, PWM + // alongwide the GPIO MODE for that port and pin (section 8.1) + // 1st and 2nd bits encode the gpio state + // 3rd and 4th bits encode the IO mode (i.e. IO, PWM, ADC) + // the 5th bit additionally encodes the default output state + static const uint8_t PIN_MODE_IO = 0b00000; // General IO mode, IE: not ADC or PWM + static const uint8_t PIN_MODE_QB = 0b00000; // Output, Quasi-Bidirectional mode + static const uint8_t PIN_MODE_PP = 0b00001; // Output, Push-Pull mode + static const uint8_t PIN_MODE_IN = 0b00010; // Input-only (high-impedance) + static const uint8_t PIN_MODE_PU = 0b10000; // Input (with pull-up) + static const uint8_t PIN_MODE_OD = 0b00011; // Output, Open-Drain mode + static const uint8_t PIN_MODE_PWM = 0b00101; // PWM, Output, Push-Pull mode + static const uint8_t PIN_MODE_ADC = 0b01010; // ADC, Input-only (high-impedance) public: static const uint8_t DEFAULT_I2C_ADDRESS = 0x18; @@ -33,15 +33,18 @@ namespace pimoroni { static const uint16_t CHIP_ID = 0xE26A; static const uint8_t CHIP_VERSION = 2; - static const uint8_t PIN_IN = PIN_MODE_IN; //0b00010 - static const uint8_t PIN_IN_PULL_UP = PIN_MODE_PU; //0b10000 - static const uint8_t PIN_IN_PU = PIN_MODE_PU; //0b10000 - static const uint8_t PIN_OUT = PIN_MODE_PP; //0b00001 - static const uint8_t PIN_PWM = PIN_MODE_PWM; //0b00101 - static const uint8_t PIN_ADC = PIN_MODE_ADC; //0b01010 + static const uint8_t PIN_IN = PIN_MODE_IN; // 0b00010 + static const uint8_t PIN_IN_PULL_UP = PIN_MODE_PU; // 0b10000 + static const uint8_t PIN_IN_PU = PIN_MODE_PU; // 0b10000 + static const uint8_t PIN_OUT = PIN_MODE_PP; // 0b00001 + static const uint8_t PIN_PWM = PIN_MODE_PWM; // 0b00101 + static const uint8_t PIN_ADC = PIN_MODE_ADC; // 0b01010 static const uint8_t NUM_PINS = 14; + static const uint16_t LOW = 0; + static const uint16_t HIGH = 1; + //-------------------------------------------------- // Subclasses @@ -58,43 +61,43 @@ namespace pimoroni { TYPE_ADC = 0b10, TYPE_ADC_OR_PWM = 0b11 }; - + //-------------------------------------------------- // Constants //-------------------------------------------------- private: - //The PxM1 and PxM2 registers encode GPIO MODE - //0 0 = Quasi-bidirectional - //0 1 = Push-pull - //1 0 = Input-only (high-impedance) - //1 1 = Open-drain - static const uint8_t PxM1[4]; //[reg::P0M1, reg::P1M1, -1, reg::P3M1] - static const uint8_t PxM2[4]; //[reg::P0M2, reg::P1M2, -1, reg::P3M2] + // The PxM1 and PxM2 registers encode GPIO MODE + // 0 0 = Quasi-bidirectional + // 0 1 = Push-pull + // 1 0 = Input-only (high-impedance) + // 1 1 = Open-drain + static const uint8_t PxM1[4]; // [reg::P0M1, reg::P1M1, -1, reg::P3M1] + static const uint8_t PxM2[4]; // [reg::P0M2, reg::P1M2, -1, reg::P3M2] - //The Px input register - static const uint8_t Px[4]; //[reg::P0, reg::P1, -1, reg::P3] + // The Px input register + static const uint8_t Px[4]; // [reg::P0, reg::P1, -1, reg::P3] - //The PxS Schmitt trigger register - static const uint8_t PxS[4]; //[reg::P0S, reg::P1S, -1, reg::P3S] - static const uint8_t MASK_P[4]; //[reg::INT_MASK_P0, reg::INT_MASK_P1, -1, reg::INT_MASK_P3] + // The PxS Schmitt trigger register + static const uint8_t PxS[4]; // [reg::P0S, reg::P1S, -1, reg::P3S] + static const uint8_t MASK_P[4]; // [reg::INT_MASK_P0, reg::INT_MASK_P1, -1, reg::INT_MASK_P3] - static const uint8_t PWML[6]; //[reg::PWM0L, reg::PWM1L, reg::PWM2L, reg::PWM3L, reg::PWM4L, reg::PWM5L] - static const uint8_t PWMH[6]; //[reg::PWM0H, reg::PWM1H, reg::PWM2H, reg::PWM3H, reg::PWM4H, reg::PWM5H] + static const uint8_t PWML[6]; // [reg::PWM0L, reg::PWM1L, reg::PWM2L, reg::PWM3L, reg::PWM4L, reg::PWM5L] + static const uint8_t PWMH[6]; // [reg::PWM0H, reg::PWM1H, reg::PWM2H, reg::PWM3H, reg::PWM4H, reg::PWM5H] //-------------------------------------------------- // Variables //-------------------------------------------------- private: - const IOType type; + const IOType type; uint8_t mode; public: const uint8_t port; const uint8_t pin; const uint8_t adc_channel; const uint8_t pwm_channel; - + const uint8_t reg_m1; const uint8_t reg_m2; const uint8_t reg_p; @@ -110,24 +113,22 @@ namespace pimoroni { // Constructors //-------------------------------------------------- private: - Pin(uint8_t port, uint8_t pin); //Constructor for IO pin - Pin(uint8_t port, uint8_t pin, uint8_t pwm_channel, uint8_t reg_iopwm); //Constructor for PWM pin - Pin(uint8_t port, uint8_t pin, uint8_t adc_channel); //Constructor for ADC pin - Pin(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm); //Constructor for ADC or PWM pin + Pin(uint8_t port, uint8_t pin); // Constructor for IO pin + Pin(uint8_t port, uint8_t pin, uint8_t pwm_channel, uint8_t reg_iopwm); // Constructor for PWM pin + Pin(uint8_t port, uint8_t pin, uint8_t adc_channel); // Constructor for ADC pin + Pin(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm); // Constructor for ADC or PWM pin //-------------------------------------------------- // Methods //-------------------------------------------------- public: - static Pin io(uint8_t port, uint8_t pin); //Nicer function for creating an IO pin - static Pin pwm(uint8_t port, uint8_t pin, uint8_t channel, uint8_t reg_iopwm); //Nicer function for creating a PWM pin - static Pin adc(uint8_t port, uint8_t pin, uint8_t channel); //Nicer function for creating an ADC pin - static Pin adc_or_pwm(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm); //Nicer function for creating an ADC or PWM pin + static Pin io(uint8_t port, uint8_t pin); // Nicer function for creating an IO pin + static Pin pwm(uint8_t port, uint8_t pin, uint8_t channel, uint8_t reg_iopwm); // Nicer function for creating a PWM pin + static Pin adc(uint8_t port, uint8_t pin, uint8_t channel); // Nicer function for creating an ADC pin + static Pin adc_or_pwm(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm); // Nicer function for creating an ADC or PWM pin - //-------------------------------------------------- - - IOType get_type(void); + IOType get_type(void); uint8_t get_mode(void); void set_mode(uint8_t mode); @@ -149,7 +150,7 @@ namespace pimoroni { uint32_t timeout; bool debug; - float vref; + float vref; int16_t encoder_offset[4];; int16_t encoder_last[4]; Pin pins[NUM_PINS]; @@ -159,8 +160,8 @@ namespace pimoroni { // Constructors/Destructor //-------------------------------------------------- public: - Nuvoton(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt, uint8_t address = DEFAULT_I2C_ADDRESS, uint32_t timeout = 1, bool debug = false); - Nuvoton(uint8_t address = DEFAULT_I2C_ADDRESS, uint32_t timeout = 1, bool debug = false); + IOExpander(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt, uint8_t address = DEFAULT_I2C_ADDRESS, uint32_t timeout = 1, bool debug = false); + IOExpander(uint8_t address = DEFAULT_I2C_ADDRESS, uint32_t timeout = 1, bool debug = false); //-------------------------------------------------- @@ -169,53 +170,44 @@ namespace pimoroni { public: bool init(bool skip_chip_id_check = false); - //-------------------------------------------------- + // For print access in micropython + i2c_inst_t* get_i2c() const; + int get_sda() const; + int get_scl() const; + int get_int() const; uint16_t get_chip_id(); - + void set_addr(uint8_t address); float get_adc_vref(); void set_adc_vref(float vref); - - //-------------------------------------------------- - + void enable_interrupt_out(bool pin_swap = false); void disable_interrupt_out(); - uint8_t 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(); - void pwm_clear(bool wait_for_clear = true); bool pwm_clearing(); - bool set_pwm_control(uint8_t divider); void set_pwm_period(uint16_t value, bool load = true); - //-------------------------------------------------- - uint8_t get_mode(uint8_t pin); void set_mode(uint8_t pin, uint8_t mode, bool schmitt_trigger = false, bool invert = false); int16_t input(uint8_t pin, uint32_t adc_timeout = 1); float input_as_voltage(uint8_t pin, uint32_t adc_timeout = 1); - + 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); int16_t read_rotary_encoder(uint8_t channel); - //-------------------------------------------------- private: uint8_t i2c_reg_read_uint8(uint8_t reg); void i2c_reg_write_uint8(uint8_t reg, uint8_t value); diff --git a/drivers/nuvoton/CMakeLists.txt b/drivers/nuvoton/CMakeLists.txt deleted file mode 100644 index 395cdc9a..00000000 --- a/drivers/nuvoton/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -include(nuvoton.cmake) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 3c6a2ea8..2b11e0ec 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,9 +1,12 @@ add_subdirectory(breakout_dotmatrix) +add_subdirectory(breakout_encoder) add_subdirectory(breakout_ltr559) add_subdirectory(breakout_colourlcd160x80) add_subdirectory(breakout_roundlcd) add_subdirectory(breakout_rgbmatrix5x5) add_subdirectory(breakout_matrix11x7) +add_subdirectory(breakout_mics6814) +add_subdirectory(breakout_potentiometer) add_subdirectory(breakout_trackball) add_subdirectory(breakout_sgp30) add_subdirectory(breakout_colourlcd240x240) diff --git a/examples/breakout_encoder/CMakeLists.txt b/examples/breakout_encoder/CMakeLists.txt new file mode 100644 index 00000000..46729be4 --- /dev/null +++ b/examples/breakout_encoder/CMakeLists.txt @@ -0,0 +1,12 @@ +set(OUTPUT_NAME encoder_demo) + +add_executable( + ${OUTPUT_NAME} + demo.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_encoder) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_encoder/demo.cpp b/examples/breakout_encoder/demo.cpp new file mode 100644 index 00000000..b8e0665d --- /dev/null +++ b/examples/breakout_encoder/demo.cpp @@ -0,0 +1,23 @@ +#include "pico/stdlib.h" + +#include "breakout_encoder.hpp" + +using namespace pimoroni; + +BreakoutEncoder enc; + +int main() { + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + + enc.init(); + + while(true) { + gpio_put(PICO_DEFAULT_LED_PIN, true); + sleep_ms(1000); + gpio_put(PICO_DEFAULT_LED_PIN, false); + sleep_ms(1000); + } + + return 0; +} diff --git a/examples/breakout_ioexpander/CMakeLists.txt b/examples/breakout_ioexpander/CMakeLists.txt new file mode 100644 index 00000000..eeda7d77 --- /dev/null +++ b/examples/breakout_ioexpander/CMakeLists.txt @@ -0,0 +1,12 @@ +set(OUTPUT_NAME ioexpander_demo) + +add_executable( + ${OUTPUT_NAME} + demo.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_ioexpander) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_ioexpander/demo.cpp b/examples/breakout_ioexpander/demo.cpp new file mode 100644 index 00000000..d6477bf0 --- /dev/null +++ b/examples/breakout_ioexpander/demo.cpp @@ -0,0 +1,23 @@ +#include "pico/stdlib.h" + +#include "breakout_ioexpander.hpp" + +using namespace pimoroni; + +BreakoutIOExpander ioe; + +int main() { + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + + ioe.init(); + + while(true) { + gpio_put(PICO_DEFAULT_LED_PIN, true); + sleep_ms(1000); + gpio_put(PICO_DEFAULT_LED_PIN, false); + sleep_ms(1000); + } + + return 0; +} diff --git a/examples/breakout_mics6814/CMakeLists.txt b/examples/breakout_mics6814/CMakeLists.txt new file mode 100644 index 00000000..e8e3c20c --- /dev/null +++ b/examples/breakout_mics6814/CMakeLists.txt @@ -0,0 +1,12 @@ +set(OUTPUT_NAME mics6814_demo) + +add_executable( + ${OUTPUT_NAME} + demo.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_mics6814) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_mics6814/demo.cpp b/examples/breakout_mics6814/demo.cpp new file mode 100644 index 00000000..6d4d0c88 --- /dev/null +++ b/examples/breakout_mics6814/demo.cpp @@ -0,0 +1,23 @@ +#include "pico/stdlib.h" + +#include "breakout_mics6814.hpp" + +using namespace pimoroni; + +BreakoutMICS6814 ioe; + +int main() { + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + + ioe.init(); + + while(true) { + gpio_put(PICO_DEFAULT_LED_PIN, true); + sleep_ms(1000); + gpio_put(PICO_DEFAULT_LED_PIN, false); + sleep_ms(1000); + } + + return 0; +} diff --git a/examples/breakout_potentiometer/CMakeLists.txt b/examples/breakout_potentiometer/CMakeLists.txt new file mode 100644 index 00000000..edbf0709 --- /dev/null +++ b/examples/breakout_potentiometer/CMakeLists.txt @@ -0,0 +1,12 @@ +set(OUTPUT_NAME potentiometer_demo) + +add_executable( + ${OUTPUT_NAME} + demo.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_potentiometer) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_potentiometer/demo.cpp b/examples/breakout_potentiometer/demo.cpp new file mode 100644 index 00000000..a921bcb1 --- /dev/null +++ b/examples/breakout_potentiometer/demo.cpp @@ -0,0 +1,23 @@ +#include "pico/stdlib.h" + +#include "breakout_potentiometer.hpp" + +using namespace pimoroni; + +BreakoutPotentiometer pot; + +int main() { + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + + pot.init(); + + while(true) { + gpio_put(PICO_DEFAULT_LED_PIN, true); + sleep_ms(1000); + gpio_put(PICO_DEFAULT_LED_PIN, false); + sleep_ms(1000); + } + + return 0; +} diff --git a/libraries/breakout_encoder/breakout_encoder.cmake b/libraries/breakout_encoder/breakout_encoder.cmake index d3a8f311..765e58ab 100644 --- a/libraries/breakout_encoder/breakout_encoder.cmake +++ b/libraries/breakout_encoder/breakout_encoder.cmake @@ -8,4 +8,4 @@ target_sources(${LIB_NAME} INTERFACE target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib nuvoton) +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib ioexpander) diff --git a/libraries/breakout_encoder/breakout_encoder.cpp b/libraries/breakout_encoder/breakout_encoder.cpp index 1536bba0..08bc0959 100644 --- a/libraries/breakout_encoder/breakout_encoder.cpp +++ b/libraries/breakout_encoder/breakout_encoder.cpp @@ -1,5 +1,86 @@ #include "breakout_encoder.hpp" +#include namespace pimoroni { -} + bool BreakoutEncoder::init(bool skip_chip_id_check) { + bool success = false; + if(ioe.init(skip_chip_id_check)) { + + if(interrupt_pin != PIN_UNUSED) + ioe.enable_interrupt_out(true); + + ioe.setup_rotary_encoder(ENC_CHANNEL, ENC_TERM_A, ENC_TERM_B, ENC_TERM_C); + + // Calculate a period large enough to get 0-255 steps at the desired brightness + uint16_t period = (uint16_t)(255.0f / brightness); + + ioe.set_pwm_period(period); + ioe.set_pwm_control(2); // PWM as fast as we can to avoid LED flicker + + ioe.set_mode(LED_R, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + ioe.set_mode(LED_G, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + ioe.set_mode(LED_B, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + + success = true; + } + + return success; + } + + i2c_inst_t* BreakoutEncoder::get_i2c() const { + return ioe.get_i2c(); + } + + int BreakoutEncoder::get_sda() const { + return ioe.get_sda(); + } + + int BreakoutEncoder::get_scl() const { + return ioe.get_scl(); + } + + int BreakoutEncoder::get_int() const { + return ioe.get_int(); + } + + void BreakoutEncoder::set_addr(uint8_t i2c_addr) { + ioe.set_addr(i2c_addr); + } + + bool BreakoutEncoder::get_direction(void) { + return direction_cw; + } + + void BreakoutEncoder::set_direction(bool clockwise) { + direction_cw = clockwise; + } + + void BreakoutEncoder::set_brightness(float brightness) { + this->brightness = std::min(std::max(brightness, 0.01f), 1.0f); + + // Calculate a period large enough to get 0-255 steps at the desired brightness + uint16_t period = (uint16_t)(255.0f / this->brightness); + + ioe.set_pwm_period(period); + } + + void BreakoutEncoder::set_led(uint8_t r, uint8_t g, uint8_t b) { + ioe.output(LED_R, r, false); // Hold off pwm load until the last + ioe.output(LED_G, g, false); // Hold off pwm load until the last + ioe.output(LED_B, b); // Loads all 3 pwms + } + + bool BreakoutEncoder::available() { + return (ioe.get_interrupt_flag() > 0); + } + + int16_t BreakoutEncoder::read() { + int16_t count = ioe.read_rotary_encoder(ENC_CHANNEL); + if(!direction_cw) + count = 0 - count; + + ioe.clear_interrupt_flag(); + return count; + } +} \ No newline at end of file diff --git a/libraries/breakout_encoder/breakout_encoder.hpp b/libraries/breakout_encoder/breakout_encoder.hpp index 65af31bc..22a3b391 100644 --- a/libraries/breakout_encoder/breakout_encoder.hpp +++ b/libraries/breakout_encoder/breakout_encoder.hpp @@ -1,8 +1,93 @@ #pragma once -#include "../../drivers/nuvoton/nuvoton.hpp" +#include "../../drivers/ioexpander/ioexpander.hpp" namespace pimoroni { - typedef Nuvoton BreakoutEncoder; -} + class BreakoutEncoder { + //-------------------------------------------------- + // Enums + //-------------------------------------------------- + public: + enum Direction : bool { + DIRECTION_CW = true, + DIRECTION_CCW = false + }; + + + //-------------------------------------------------- + // Constants + //-------------------------------------------------- + public: + static const uint8_t DEFAULT_I2C_ADDRESS = 0x0F; + static constexpr float DEFAULT_BRIGHTNESS = 1.0f; //Effectively the maximum fraction of the period that the LED will be on + static const bool DEFAULT_DIRECTION = DIRECTION_CW; + static const uint8_t PIN_UNUSED = UINT8_MAX; + static const uint32_t DEFAULT_TIMEOUT = 1; + + private: + static const uint8_t LED_R = 1; + static const uint8_t LED_G = 7; + static const uint8_t LED_B = 2; + + static const uint8_t ENC_TERM_A = 12; + static const uint8_t ENC_TERM_B = 3; + static const uint8_t ENC_TERM_C = 11; + + static const uint8_t ENC_CHANNEL = 1; + + static const bool INVERT_OUTPUT = true; //true for common cathode, false for common anode + + + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: + IOExpander ioe; + bool direction_cw = DEFAULT_DIRECTION; + float brightness = DEFAULT_BRIGHTNESS; + uint8_t interrupt_pin = PIN_UNUSED; // A local copy of the value passed to the IOExpander, used in initialisation + + + //-------------------------------------------------- + // Constructors/Destructor + //-------------------------------------------------- + public: + BreakoutEncoder() : + ioe(DEFAULT_I2C_ADDRESS) {} + + BreakoutEncoder(uint8_t address) : + ioe(address) {} + + BreakoutEncoder(i2c_inst_t *i2c, uint8_t address, uint8_t sda, uint8_t scl, uint8_t interrupt = PIN_UNUSED, uint32_t timeout = DEFAULT_TIMEOUT) : + ioe(i2c, address, sda, scl, interrupt, timeout), + interrupt_pin(interrupt) {} + + + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + bool init(bool skip_chip_id_check = false); + + // For print access in micropython + i2c_inst_t* get_i2c() const; + int get_sda() const; + int get_scl() const; + int get_int() const; + + // Calls through to IOExpander class + void set_addr(uint8_t i2c_addr); + + // Encoder breakout specific + bool get_direction(); + void set_direction(bool clockwise); + + void set_brightness(float brightness); + void set_led(uint8_t r, uint8_t g, uint8_t b); + + bool available(); + int16_t read(); + }; + +} \ No newline at end of file diff --git a/libraries/breakout_ioexpander/breakout_ioexpander.cmake b/libraries/breakout_ioexpander/breakout_ioexpander.cmake index 8ee2bb90..d2a20c35 100644 --- a/libraries/breakout_ioexpander/breakout_ioexpander.cmake +++ b/libraries/breakout_ioexpander/breakout_ioexpander.cmake @@ -8,4 +8,4 @@ target_sources(${LIB_NAME} INTERFACE target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib nuvoton) +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib ioexpander) diff --git a/libraries/breakout_ioexpander/breakout_ioexpander.hpp b/libraries/breakout_ioexpander/breakout_ioexpander.hpp index 09bf993b..e6ebd0e5 100644 --- a/libraries/breakout_ioexpander/breakout_ioexpander.hpp +++ b/libraries/breakout_ioexpander/breakout_ioexpander.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../../drivers/nuvoton/nuvoton.hpp" +#include "../../drivers/ioexpander/ioexpander.hpp" namespace pimoroni { - typedef Nuvoton BreakoutIOExpander; + typedef IOExpander BreakoutIOExpander; } diff --git a/libraries/breakout_mics6814/breakout_mics6814.cmake b/libraries/breakout_mics6814/breakout_mics6814.cmake index e977a979..31b28c2e 100644 --- a/libraries/breakout_mics6814/breakout_mics6814.cmake +++ b/libraries/breakout_mics6814/breakout_mics6814.cmake @@ -8,4 +8,4 @@ target_sources(${LIB_NAME} INTERFACE target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib nuvoton) +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib ioexpander) diff --git a/libraries/breakout_mics6814/breakout_mics6814.cpp b/libraries/breakout_mics6814/breakout_mics6814.cpp index 64a37ebb..c801827a 100644 --- a/libraries/breakout_mics6814/breakout_mics6814.cpp +++ b/libraries/breakout_mics6814/breakout_mics6814.cpp @@ -1,5 +1,154 @@ #include "breakout_mics6814.hpp" +#include namespace pimoroni { -} + bool BreakoutMICS6814::init(bool skip_chip_id_check) { + bool success = false; + if(ioe.init(skip_chip_id_check)) { + + ioe.set_mode(MICS_VREF, IOExpander::PIN_ADC); + ioe.set_mode(MICS_RED, IOExpander::PIN_ADC); + ioe.set_mode(MICS_NH3, IOExpander::PIN_ADC); + ioe.set_mode(MICS_OX, IOExpander::PIN_ADC); + + ioe.set_mode(MICS_HEATER_EN, IOExpander::PIN_OUT); + ioe.output(MICS_HEATER_EN, IOExpander::LOW); + + // Calculate a period large enough to get 0-255 steps at the desired brightness + uint16_t period = (uint16_t)(255.0f / brightness); + + ioe.set_pwm_period(period); + ioe.set_pwm_control(2); // PWM as fast as we can to avoid LED flicker + + ioe.set_mode(LED_R, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + ioe.set_mode(LED_G, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + ioe.set_mode(LED_B, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + + success = true; + } + + return success; + } + + i2c_inst_t* BreakoutMICS6814::get_i2c() const { + return ioe.get_i2c(); + } + + int BreakoutMICS6814::get_sda() const { + return ioe.get_sda(); + } + + int BreakoutMICS6814::get_scl() const { + return ioe.get_scl(); + } + + int BreakoutMICS6814::get_int() const { + return ioe.get_int(); + } + + void BreakoutMICS6814::set_addr(uint8_t i2c_addr) { + ioe.set_addr(i2c_addr); + } + + float BreakoutMICS6814::get_adc_vref(void) { + return ioe.get_adc_vref(); + } + + void BreakoutMICS6814::set_adc_vref(float vref) { + ioe.set_adc_vref(vref); + } + + void BreakoutMICS6814::set_brightness(float brightness) { + this->brightness = std::min(std::max(brightness, 0.01f), 1.0f); + + // Calculate a period large enough to get 0-255 steps at the desired brightness + uint16_t period = (uint16_t)(255.0f / this->brightness); + + ioe.set_pwm_period(period); + } + + void BreakoutMICS6814::set_led(uint8_t r, uint8_t g, uint8_t b) { + ioe.output(LED_R, r, false); // Hold off pwm load until the last + ioe.output(LED_G, g, false); // Hold off pwm load until the last + ioe.output(LED_B, b); // Loads all 3 pwms + } + + void BreakoutMICS6814::set_heater(bool on) { + ioe.output(MICS_HEATER_EN, on ? IOExpander::LOW : IOExpander::HIGH); + } + + void BreakoutMICS6814::disable_heater() { + ioe.output(MICS_HEATER_EN, IOExpander::HIGH); + ioe.set_mode(MICS_HEATER_EN, IOExpander::PIN_IN); + } + + float BreakoutMICS6814::get_raw_ref(uint32_t adc_timeout) { + return ioe.input_as_voltage(MICS_VREF, adc_timeout); + } + + float BreakoutMICS6814::get_raw_red(uint32_t adc_timeout) { + return ioe.input_as_voltage(MICS_RED, adc_timeout); + } + + float BreakoutMICS6814::get_raw_nh3(uint32_t adc_timeout) { + return ioe.input_as_voltage(MICS_NH3, adc_timeout); + } + + float BreakoutMICS6814::get_raw_oxd(uint32_t adc_timeout) { + return ioe.input_as_voltage(MICS_OX, adc_timeout); + } + + BreakoutMICS6814::Reading BreakoutMICS6814::read_all(uint32_t adc_timeout) { + BreakoutMICS6814::Reading reading; + reading.reducing = read_reducing(adc_timeout); + reading.nh3 = read_nh3(adc_timeout); + reading.oxidising = read_oxidising(adc_timeout); + reading.ref = read_ref(adc_timeout); + return reading; + } + + float BreakoutMICS6814::read_ref(uint32_t adc_timeout) { + float ref = get_raw_ref(adc_timeout); + if(ref == -1) + ref = 0; + + return ref; + } + + float BreakoutMICS6814::read_reducing(uint32_t adc_timeout) { + float vref = ioe.get_adc_vref(); + + float red = get_raw_red(adc_timeout); + if((red != -1) && (vref != red)) + red = (red * 56000.0f) / (vref - red); + else + red = 0; + + return red; + } + + float BreakoutMICS6814::read_nh3(uint32_t adc_timeout) { + float vref = ioe.get_adc_vref(); + + float nh3 = get_raw_red(adc_timeout); + if((nh3 != -1) && (vref != nh3)) + nh3 = (nh3 * 56000.0f) / (vref - nh3); + else + nh3 = 0; + + return nh3; + } + + float BreakoutMICS6814::read_oxidising(uint32_t adc_timeout) { + float vref = ioe.get_adc_vref(); + + float oxd = get_raw_red(adc_timeout); + if((oxd != -1) && (vref != oxd)) + oxd = (oxd * 56000.0f) / (vref - oxd); + else + oxd = 0; + + return oxd; + } +} \ No newline at end of file diff --git a/libraries/breakout_mics6814/breakout_mics6814.hpp b/libraries/breakout_mics6814/breakout_mics6814.hpp index 82e015ea..bcd3f8e9 100644 --- a/libraries/breakout_mics6814/breakout_mics6814.hpp +++ b/libraries/breakout_mics6814/breakout_mics6814.hpp @@ -1,8 +1,103 @@ #pragma once -#include "../../drivers/nuvoton/nuvoton.hpp" +#include "../../drivers/ioexpander/ioexpander.hpp" namespace pimoroni { - typedef Nuvoton BreakoutMICS6814; -} + class BreakoutMICS6814 { + //-------------------------------------------------- + // Constants + //-------------------------------------------------- + public: + static const uint8_t DEFAULT_I2C_ADDRESS = 0x19; + static constexpr float DEFAULT_BRIGHTNESS = 1.0f; //Effectively the maximum fraction of the period that the LED will be on + static const uint8_t PIN_UNUSED = UINT8_MAX; + static const uint32_t DEFAULT_TIMEOUT = 1; + static const uint32_t DEFAULT_ADC_TIMEOUT = 1; + + private: + static const uint8_t LED_R = 3; + static const uint8_t LED_G = 7; + static const uint8_t LED_B = 2; + + static const uint8_t MICS_VREF = 14; + static const uint8_t MICS_RED = 12; + static const uint8_t MICS_NH3 = 11; + static const uint8_t MICS_OX = 13; + static const uint8_t MICS_HEATER_EN = 1; + + static const bool INVERT_OUTPUT = true; //true for common cathode, false for common anode + + + //-------------------------------------------------- + // Substructures + //-------------------------------------------------- + private: + struct Reading { + float ref; + float reducing; + float nh3; + float oxidising; + }; + + + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: + IOExpander ioe; + float brightness = DEFAULT_BRIGHTNESS; + + + //-------------------------------------------------- + // Constructors/Destructor + //-------------------------------------------------- + public: + BreakoutMICS6814() : + ioe(DEFAULT_I2C_ADDRESS) {} + + BreakoutMICS6814(uint8_t address) : + ioe(address) {} + + BreakoutMICS6814(i2c_inst_t *i2c, uint8_t address, uint8_t sda, uint8_t scl, uint8_t interrupt = PIN_UNUSED, uint32_t timeout = DEFAULT_TIMEOUT) : + ioe(i2c, address, sda, scl, interrupt, timeout) {} + + + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + bool init(bool skip_chip_id_check = false); + + // For print access in micropython + i2c_inst_t* get_i2c() const; + int get_sda() const; + int get_scl() const; + int get_int() const; + + // Calls through to IOExpander class + void set_addr(uint8_t i2c_addr); + + float get_adc_vref(); + void set_adc_vref(float vref); + + // MICS breakout specific + void set_brightness(float brightness); + void set_led(uint8_t r, uint8_t g, uint8_t b); + + void set_heater(bool on); + void disable_heater(); + + float get_raw_ref(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); + float get_raw_red(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); + float get_raw_nh3(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); + float get_raw_oxd(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); + + Reading read_all(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); + float read_ref(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); + float read_reducing(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); + float read_nh3(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); + float read_oxidising(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); + }; + +} \ No newline at end of file diff --git a/libraries/breakout_potentiometer/breakout_potentiometer.cmake b/libraries/breakout_potentiometer/breakout_potentiometer.cmake index 53f4863e..434970ce 100644 --- a/libraries/breakout_potentiometer/breakout_potentiometer.cmake +++ b/libraries/breakout_potentiometer/breakout_potentiometer.cmake @@ -8,4 +8,4 @@ target_sources(${LIB_NAME} INTERFACE target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib nuvoton) +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib ioexpander) diff --git a/libraries/breakout_potentiometer/breakout_potentiometer.cpp b/libraries/breakout_potentiometer/breakout_potentiometer.cpp index d4240571..b5aec5a4 100644 --- a/libraries/breakout_potentiometer/breakout_potentiometer.cpp +++ b/libraries/breakout_potentiometer/breakout_potentiometer.cpp @@ -1,5 +1,109 @@ #include "breakout_potentiometer.hpp" +#include namespace pimoroni { -} + bool BreakoutPotentiometer::init(bool skip_chip_id_check) { + bool success = false; + if(ioe.init(skip_chip_id_check)) { + + ioe.set_mode(POT_TERM_A, IOExpander::PIN_OUT); + ioe.set_mode(POT_TERM_B, IOExpander::PIN_OUT); + ioe.set_mode(POT_INPUT, IOExpander::PIN_ADC); + + if(direction_cw) { + // Clockwise increasing + ioe.output(POT_TERM_A, IOExpander::LOW); + ioe.output(POT_TERM_B, IOExpander::HIGH); + } + else { + // Counter clockwise increasing + ioe.output(POT_TERM_A, IOExpander::HIGH); + ioe.output(POT_TERM_B, IOExpander::LOW); + } + + // Calculate a period large enough to get 0-255 steps at the desired brightness + uint16_t period = (uint16_t)(255.0f / brightness); + + ioe.set_pwm_period(period); + ioe.set_pwm_control(2); // PWM as fast as we can to avoid LED flicker + + ioe.set_mode(LED_R, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + ioe.set_mode(LED_G, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + ioe.set_mode(LED_B, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + + success = true; + } + + return success; + } + + i2c_inst_t* BreakoutPotentiometer::get_i2c() const { + return ioe.get_i2c(); + } + + int BreakoutPotentiometer::get_sda() const { + return ioe.get_sda(); + } + + int BreakoutPotentiometer::get_scl() const { + return ioe.get_scl(); + } + + int BreakoutPotentiometer::get_int() const { + return ioe.get_int(); + } + + void BreakoutPotentiometer::set_addr(uint8_t i2c_addr) { + ioe.set_addr(i2c_addr); + } + + float BreakoutPotentiometer::get_adc_vref(void) { + return ioe.get_adc_vref(); + } + + void BreakoutPotentiometer::set_adc_vref(float vref) { + ioe.set_adc_vref(vref); + } + + bool BreakoutPotentiometer::get_direction(void) { + return direction_cw; + } + + void BreakoutPotentiometer::set_direction(bool clockwise) { + if(clockwise) { + // Clockwise increasing + ioe.output(POT_TERM_A, IOExpander::LOW); + ioe.output(POT_TERM_B, IOExpander::HIGH); + } + else { + // Counter clockwise increasing + ioe.output(POT_TERM_A, IOExpander::HIGH); + ioe.output(POT_TERM_B, IOExpander::LOW); + } + direction_cw = clockwise; + } + + void BreakoutPotentiometer::set_brightness(float brightness) { + this->brightness = std::min(std::max(brightness, 0.01f), 1.0f); + + // Calculate a period large enough to get 0-255 steps at the desired brightness + uint16_t period = (uint16_t)(255.0f / this->brightness); + + ioe.set_pwm_period(period); + } + + void BreakoutPotentiometer::set_led(uint8_t r, uint8_t g, uint8_t b) { + ioe.output(LED_R, r, false); // Hold off pwm load until the last + ioe.output(LED_G, g, false); // Hold off pwm load until the last + ioe.output(LED_B, b); // Loads all 3 pwms + } + + int16_t BreakoutPotentiometer::read(uint32_t adc_timeout) { + return ioe.input(POT_INPUT, adc_timeout); + } + + float BreakoutPotentiometer::read_as_percent(uint32_t adc_timeout) { + return (ioe.input_as_voltage(POT_INPUT, adc_timeout) / ioe.get_adc_vref()); + } +} \ No newline at end of file diff --git a/libraries/breakout_potentiometer/breakout_potentiometer.hpp b/libraries/breakout_potentiometer/breakout_potentiometer.hpp index 7ff338f5..28b899b3 100644 --- a/libraries/breakout_potentiometer/breakout_potentiometer.hpp +++ b/libraries/breakout_potentiometer/breakout_potentiometer.hpp @@ -1,8 +1,93 @@ #pragma once -#include "../../drivers/nuvoton/nuvoton.hpp" +#include "../../drivers/ioexpander/ioexpander.hpp" namespace pimoroni { - typedef Nuvoton BreakoutPotentiometer; -} + class BreakoutPotentiometer { + //-------------------------------------------------- + // Enums + //-------------------------------------------------- + public: + enum Direction : bool { + DIRECTION_CW = true, + DIRECTION_CCW = false + }; + + + //-------------------------------------------------- + // Constants + //-------------------------------------------------- + public: + static const uint8_t DEFAULT_I2C_ADDRESS = 0x0E; + static constexpr float DEFAULT_BRIGHTNESS = 1.0f; //Effectively the maximum fraction of the period that the LED will be on + static const bool DEFAULT_DIRECTION = DIRECTION_CW; + static const uint8_t PIN_UNUSED = UINT8_MAX; + static const uint32_t DEFAULT_TIMEOUT = 1; + static const uint32_t DEFAULT_ADC_TIMEOUT = 1; + + private: + static const uint8_t LED_R = 1; + static const uint8_t LED_G = 7; + static const uint8_t LED_B = 2; + + static const uint8_t POT_TERM_A = 12; + static const uint8_t POT_TERM_B = 3; + static const uint8_t POT_INPUT = 11; + + static const bool INVERT_OUTPUT = true; //true for common cathode, false for common anode + + + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: + IOExpander ioe; + bool direction_cw = DEFAULT_DIRECTION; + float brightness = DEFAULT_BRIGHTNESS; + + + //-------------------------------------------------- + // Constructors/Destructor + //-------------------------------------------------- + public: + BreakoutPotentiometer() : + ioe(DEFAULT_I2C_ADDRESS) {} + + BreakoutPotentiometer(uint8_t address) : + ioe(address) {} + + BreakoutPotentiometer(i2c_inst_t *i2c, uint8_t address, uint8_t sda, uint8_t scl, uint8_t interrupt = PIN_UNUSED, uint32_t timeout = DEFAULT_TIMEOUT) : + ioe(i2c, address, sda, scl, interrupt, timeout) {} + + + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + bool init(bool skip_chip_id_check = false); + + // For print access in micropython + i2c_inst_t* get_i2c() const; + int get_sda() const; + int get_scl() const; + int get_int() const; + + // Calls through to IOExpander class + void set_addr(uint8_t i2c_addr); + + float get_adc_vref(); + void set_adc_vref(float vref); + + // Potentiometer breakout specific + bool get_direction(); + void set_direction(bool clockwise); + + void set_brightness(float brightness); + void set_led(uint8_t r, uint8_t g, uint8_t b); + + int16_t read(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); + float read_as_percent(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); + }; + +} \ No newline at end of file From f527b25fedba3f23c48d67e4c330ba048088d408 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Tue, 11 May 2021 20:02:18 +0100 Subject: [PATCH 03/27] Micropython bindings for Encoder and Pot breakouts --- .../breakout_encoder/breakout_encoder.c | 58 +++++ .../breakout_encoder/breakout_encoder.cpp | 210 ++++++++++++++++ .../breakout_encoder/breakout_encoder.h | 16 ++ .../breakout_encoder/micropython.cmake | 20 ++ .../modules/breakout_encoder/micropython.mk | 13 + .../breakout_potentiometer.c | 62 +++++ .../breakout_potentiometer.cpp | 233 ++++++++++++++++++ .../breakout_potentiometer.h | 18 ++ .../breakout_potentiometer/micropython.cmake | 20 ++ .../breakout_potentiometer/micropython.mk | 13 + micropython/modules/micropython.cmake | 2 + 11 files changed, 665 insertions(+) create mode 100644 micropython/modules/breakout_encoder/breakout_encoder.c create mode 100644 micropython/modules/breakout_encoder/breakout_encoder.cpp create mode 100644 micropython/modules/breakout_encoder/breakout_encoder.h create mode 100644 micropython/modules/breakout_encoder/micropython.cmake create mode 100755 micropython/modules/breakout_encoder/micropython.mk create mode 100644 micropython/modules/breakout_potentiometer/breakout_potentiometer.c create mode 100644 micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp create mode 100644 micropython/modules/breakout_potentiometer/breakout_potentiometer.h create mode 100644 micropython/modules/breakout_potentiometer/micropython.cmake create mode 100755 micropython/modules/breakout_potentiometer/micropython.mk diff --git a/micropython/modules/breakout_encoder/breakout_encoder.c b/micropython/modules/breakout_encoder/breakout_encoder.c new file mode 100644 index 00000000..1497018a --- /dev/null +++ b/micropython/modules/breakout_encoder/breakout_encoder.c @@ -0,0 +1,58 @@ +#include "breakout_encoder.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// BreakoutEncoder Class +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Methods *****/ +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoder_set_addr_obj, 2, BreakoutEncoder_set_addr); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoder_get_direction_obj, BreakoutEncoder_get_direction); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoder_set_direction_obj, 2, BreakoutEncoder_set_direction); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoder_set_brightness_obj, 2, BreakoutEncoder_set_brightness); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoder_set_led_obj, 4, BreakoutEncoder_set_led); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoder_available_obj, BreakoutEncoder_available); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoder_read_obj, BreakoutEncoder_read); + +/***** Binding of Methods *****/ +STATIC const mp_rom_map_elem_t BreakoutEncoder_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_set_addr), MP_ROM_PTR(&BreakoutEncoder_set_addr_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_direction), MP_ROM_PTR(&BreakoutEncoder_get_direction_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_direction), MP_ROM_PTR(&BreakoutEncoder_set_direction_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_brightness), MP_ROM_PTR(&BreakoutEncoder_set_brightness_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&BreakoutEncoder_set_led_obj) }, + { MP_ROM_QSTR(MP_QSTR_available), MP_ROM_PTR(&BreakoutEncoder_available_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&BreakoutEncoder_read_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(BreakoutEncoder_locals_dict, BreakoutEncoder_locals_dict_table); + +/***** Class Definition *****/ +const mp_obj_type_t breakout_encoder_BreakoutEncoder_type = { + { &mp_type_type }, + .name = MP_QSTR_breakout_encoder, + .print = BreakoutEncoder_print, + .make_new = BreakoutEncoder_make_new, + .locals_dict = (mp_obj_dict_t*)&BreakoutEncoder_locals_dict, +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// breakout_encoder Module +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Globals Table *****/ +STATIC const mp_map_elem_t breakout_encoder_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_encoder) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutEncoder), (mp_obj_t)&breakout_encoder_BreakoutEncoder_type }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_encoder_globals, breakout_encoder_globals_table); + +/***** Module Definition *****/ +const mp_obj_module_t breakout_encoder_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_breakout_encoder_globals, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +MP_REGISTER_MODULE(MP_QSTR_breakout_encoder, breakout_encoder_user_cmodule, MODULE_BREAKOUT_ENCODER_ENABLED); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_encoder/breakout_encoder.cpp b/micropython/modules/breakout_encoder/breakout_encoder.cpp new file mode 100644 index 00000000..b6c35209 --- /dev/null +++ b/micropython/modules/breakout_encoder/breakout_encoder.cpp @@ -0,0 +1,210 @@ +#include "../../../pimoroni-pico/libraries/breakout_encoder/breakout_encoder.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_encoder.h" + +/***** Variables Struct *****/ +typedef struct _breakout_encoder_BreakoutEncoder_obj_t { + mp_obj_base_t base; + BreakoutEncoder *breakout; +} breakout_encoder_BreakoutEncoder_obj_t; + +/***** Print *****/ +void BreakoutEncoder_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; //Unused input parameter + breakout_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_encoder_BreakoutEncoder_obj_t); + BreakoutEncoder* breakout = self->breakout; + mp_print_str(print, "BreakoutEncoder("); + + 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 BreakoutEncoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + breakout_encoder_BreakoutEncoder_obj_t *self = nullptr; + + if(n_args == 0) { + mp_arg_check_num(n_args, n_kw, 0, 0, true); + self = m_new_obj(breakout_encoder_BreakoutEncoder_obj_t); + self->base.type = &breakout_encoder_BreakoutEncoder_type; + self->breakout = new BreakoutEncoder(); + } + 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_encoder_BreakoutEncoder_obj_t); + self->base.type = &breakout_encoder_BreakoutEncoder_type; + + self->breakout = new BreakoutEncoder(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 = BreakoutEncoder::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_encoder_BreakoutEncoder_obj_t); + self->base.type = &breakout_encoder_BreakoutEncoder_type; + + i2c_inst_t *i2c = (i2c_id == 0) ? i2c0 : i2c1; + self->breakout = new BreakoutEncoder(i2c, args[ARG_address].u_int, sda, scl, args[ARG_interrupt].u_int); + } + + self->breakout->init(); + + return MP_OBJ_FROM_PTR(self); +} + +/***** Methods *****/ +mp_obj_t BreakoutEncoder_set_addr(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_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_encoder_BreakoutEncoder_obj_t); + + self->breakout->set_addr(args[ARG_address].u_int); + + return mp_const_none; +} + +mp_obj_t BreakoutEncoder_get_direction(mp_obj_t self_in) { + breakout_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_encoder_BreakoutEncoder_obj_t); + return mp_obj_new_bool(self->breakout->get_direction()); +} + +mp_obj_t BreakoutEncoder_set_direction(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_clockwise }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_clockwise, 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_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_encoder_BreakoutEncoder_obj_t); + + self->breakout->set_direction(args[ARG_clockwise].u_bool); + + return mp_const_none; +} + +mp_obj_t BreakoutEncoder_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_brightness }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_brightness, 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_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_encoder_BreakoutEncoder_obj_t); + + float brightness = mp_obj_get_float(args[ARG_brightness].u_obj); + if(brightness < 0 || brightness > 1.0f) + mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); + else + self->breakout->set_brightness((uint8_t)(brightness * 255.0f)); + + return mp_const_none; +} + +mp_obj_t BreakoutEncoder_set_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_r, ARG_g, ARG_b, ARG_w }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_b, 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_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_encoder_BreakoutEncoder_obj_t); + + int r = args[ARG_r].u_int; + int g = args[ARG_g].u_int; + int b = args[ARG_b].u_int; + + if(r < 0 || r > 255) + mp_raise_ValueError("r out of range. Expected 0 to 255"); + else if(g < 0 || g > 255) + mp_raise_ValueError("g out of range. Expected 0 to 255"); + else if(b < 0 || b > 255) + mp_raise_ValueError("b out of range. Expected 0 to 255"); + else + self->breakout->set_led(r, g, b); + + return mp_const_none; +} + +mp_obj_t BreakoutEncoder_available(mp_obj_t self_in) { + breakout_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_encoder_BreakoutEncoder_obj_t); + return mp_obj_new_bool(self->breakout->available()); +} + +mp_obj_t BreakoutEncoder_read(mp_obj_t self_in) { + breakout_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_encoder_BreakoutEncoder_obj_t); + return mp_obj_new_int(self->breakout->read()); +} +} \ No newline at end of file diff --git a/micropython/modules/breakout_encoder/breakout_encoder.h b/micropython/modules/breakout_encoder/breakout_encoder.h new file mode 100644 index 00000000..f380b4a7 --- /dev/null +++ b/micropython/modules/breakout_encoder/breakout_encoder.h @@ -0,0 +1,16 @@ +// Include MicroPython API. +#include "py/runtime.h" + +/***** Extern of Class Definition *****/ +extern const mp_obj_type_t breakout_encoder_BreakoutEncoder_type; + +/***** Extern of Class Methods *****/ +extern void BreakoutEncoder_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); +extern mp_obj_t BreakoutEncoder_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 BreakoutEncoder_set_addr(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutEncoder_get_direction(mp_obj_t self_in); +extern mp_obj_t BreakoutEncoder_set_direction(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutEncoder_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutEncoder_set_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutEncoder_available(mp_obj_t self_in); +extern mp_obj_t BreakoutEncoder_read(mp_obj_t self_in); \ No newline at end of file diff --git a/micropython/modules/breakout_encoder/micropython.cmake b/micropython/modules/breakout_encoder/micropython.cmake new file mode 100644 index 00000000..f1d80836 --- /dev/null +++ b/micropython/modules/breakout_encoder/micropython.cmake @@ -0,0 +1,20 @@ +set(MOD_NAME breakout_encoder) +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}) \ No newline at end of file diff --git a/micropython/modules/breakout_encoder/micropython.mk b/micropython/modules/breakout_encoder/micropython.mk new file mode 100755 index 00000000..674b2889 --- /dev/null +++ b/micropython/modules/breakout_encoder/micropython.mk @@ -0,0 +1,13 @@ +set(MOD_NAME breakout_encoder) +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++ \ No newline at end of file diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.c b/micropython/modules/breakout_potentiometer/breakout_potentiometer.c new file mode 100644 index 00000000..603f5bcf --- /dev/null +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.c @@ -0,0 +1,62 @@ +#include "breakout_potentiometer.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// BreakoutPotentiometer Class +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Methods *****/ +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPotentiometer_set_addr_obj, 2, BreakoutPotentiometer_set_addr); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutPotentiometer_get_adc_vref_obj, BreakoutPotentiometer_get_adc_vref); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPotentiometer_set_adc_vref_obj, 2, BreakoutPotentiometer_set_adc_vref); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutPotentiometer_get_direction_obj, BreakoutPotentiometer_get_direction); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPotentiometer_set_direction_obj, 2, BreakoutPotentiometer_set_direction); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPotentiometer_set_brightness_obj, 2, BreakoutPotentiometer_set_brightness); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPotentiometer_set_led_obj, 4, BreakoutPotentiometer_set_led); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutPotentiometer_read_obj, BreakoutPotentiometer_read); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutPotentiometer_read_as_percent_obj, BreakoutPotentiometer_read_as_percent); + +/***** Binding of Methods *****/ +STATIC const mp_rom_map_elem_t BreakoutPotentiometer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_set_addr), MP_ROM_PTR(&BreakoutPotentiometer_set_addr_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_adc_vref), MP_ROM_PTR(&BreakoutPotentiometer_get_adc_vref_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_adc_vref), MP_ROM_PTR(&BreakoutPotentiometer_set_adc_vref_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_direction), MP_ROM_PTR(&BreakoutPotentiometer_get_direction_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_direction), MP_ROM_PTR(&BreakoutPotentiometer_set_direction_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_brightness), MP_ROM_PTR(&BreakoutPotentiometer_set_brightness_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&BreakoutPotentiometer_set_led_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&BreakoutPotentiometer_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_as_percent), MP_ROM_PTR(&BreakoutPotentiometer_read_as_percent_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(BreakoutPotentiometer_locals_dict, BreakoutPotentiometer_locals_dict_table); + +/***** Class Definition *****/ +const mp_obj_type_t breakout_potentiometer_BreakoutPotentiometer_type = { + { &mp_type_type }, + .name = MP_QSTR_breakout_potentiometer, + .print = BreakoutPotentiometer_print, + .make_new = BreakoutPotentiometer_make_new, + .locals_dict = (mp_obj_dict_t*)&BreakoutPotentiometer_locals_dict, +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// breakout_potentiometer Module +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Globals Table *****/ +STATIC const mp_map_elem_t breakout_potentiometer_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_potentiometer) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutPotentiometer), (mp_obj_t)&breakout_potentiometer_BreakoutPotentiometer_type }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_potentiometer_globals, breakout_potentiometer_globals_table); + +/***** Module Definition *****/ +const mp_obj_module_t breakout_potentiometer_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_breakout_potentiometer_globals, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +MP_REGISTER_MODULE(MP_QSTR_breakout_potentiometer, breakout_potentiometer_user_cmodule, MODULE_BREAKOUT_POTENTIOMETER_ENABLED); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp new file mode 100644 index 00000000..beb5c766 --- /dev/null +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp @@ -0,0 +1,233 @@ +#include "../../../pimoroni-pico/libraries/breakout_potentiometer/breakout_potentiometer.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_potentiometer.h" + +/***** Variables Struct *****/ +typedef struct _breakout_potentiometer_BreakoutPotentiometer_obj_t { + mp_obj_base_t base; + BreakoutPotentiometer *breakout; +} breakout_potentiometer_BreakoutPotentiometer_obj_t; + +/***** Print *****/ +void BreakoutPotentiometer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; //Unused input parameter + breakout_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_potentiometer_BreakoutPotentiometer_obj_t); + BreakoutPotentiometer* breakout = self->breakout; + mp_print_str(print, "BreakoutPotentiometer("); + + 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 BreakoutPotentiometer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + breakout_potentiometer_BreakoutPotentiometer_obj_t *self = nullptr; + + if(n_args == 0) { + mp_arg_check_num(n_args, n_kw, 0, 0, true); + self = m_new_obj(breakout_potentiometer_BreakoutPotentiometer_obj_t); + self->base.type = &breakout_potentiometer_BreakoutPotentiometer_type; + self->breakout = new BreakoutPotentiometer(); + } + 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_potentiometer_BreakoutPotentiometer_obj_t); + self->base.type = &breakout_potentiometer_BreakoutPotentiometer_type; + + self->breakout = new BreakoutPotentiometer(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 = BreakoutPotentiometer::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_potentiometer_BreakoutPotentiometer_obj_t); + self->base.type = &breakout_potentiometer_BreakoutPotentiometer_type; + + i2c_inst_t *i2c = (i2c_id == 0) ? i2c0 : i2c1; + self->breakout = new BreakoutPotentiometer(i2c, args[ARG_address].u_int, sda, scl, args[ARG_interrupt].u_int); + } + + self->breakout->init(); + + return MP_OBJ_FROM_PTR(self); +} + +/***** Methods *****/ +mp_obj_t BreakoutPotentiometer_set_addr(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_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_potentiometer_BreakoutPotentiometer_obj_t); + + self->breakout->set_addr(args[ARG_address].u_int); + + return mp_const_none; +} + +mp_obj_t BreakoutPotentiometer_get_adc_vref(mp_obj_t self_in) { + breakout_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_potentiometer_BreakoutPotentiometer_obj_t); + return mp_obj_new_float(self->breakout->get_adc_vref()); +} + +mp_obj_t BreakoutPotentiometer_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_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_potentiometer_BreakoutPotentiometer_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 BreakoutPotentiometer_get_direction(mp_obj_t self_in) { + breakout_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_potentiometer_BreakoutPotentiometer_obj_t); + return mp_obj_new_bool(self->breakout->get_direction()); +} + +mp_obj_t BreakoutPotentiometer_set_direction(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_clockwise }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_clockwise, 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_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_potentiometer_BreakoutPotentiometer_obj_t); + + self->breakout->set_direction(args[ARG_clockwise].u_bool); + + return mp_const_none; +} + +mp_obj_t BreakoutPotentiometer_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_brightness }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_brightness, 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_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_potentiometer_BreakoutPotentiometer_obj_t); + + float brightness = mp_obj_get_float(args[ARG_brightness].u_obj); + if(brightness < 0 || brightness > 1.0f) + mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); + else + self->breakout->set_brightness((uint8_t)(brightness * 255.0f)); + + return mp_const_none; +} + +mp_obj_t BreakoutPotentiometer_set_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_r, ARG_g, ARG_b, ARG_w }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_b, 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_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_potentiometer_BreakoutPotentiometer_obj_t); + + int r = args[ARG_r].u_int; + int g = args[ARG_g].u_int; + int b = args[ARG_b].u_int; + + if(r < 0 || r > 255) + mp_raise_ValueError("r out of range. Expected 0 to 255"); + else if(g < 0 || g > 255) + mp_raise_ValueError("g out of range. Expected 0 to 255"); + else if(b < 0 || b > 255) + mp_raise_ValueError("b out of range. Expected 0 to 255"); + else + self->breakout->set_led(r, g, b); + + return mp_const_none; +} + +mp_obj_t BreakoutPotentiometer_read(mp_obj_t self_in) { + breakout_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_potentiometer_BreakoutPotentiometer_obj_t); + return mp_obj_new_bool(self->breakout->read()); +} + +mp_obj_t BreakoutPotentiometer_read_as_percent(mp_obj_t self_in) { + breakout_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_potentiometer_BreakoutPotentiometer_obj_t); + return mp_obj_new_float(self->breakout->read_as_percent()); +} +} \ No newline at end of file diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.h b/micropython/modules/breakout_potentiometer/breakout_potentiometer.h new file mode 100644 index 00000000..15c8c1dd --- /dev/null +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.h @@ -0,0 +1,18 @@ +// Include MicroPython API. +#include "py/runtime.h" + +/***** Extern of Class Definition *****/ +extern const mp_obj_type_t breakout_potentiometer_BreakoutPotentiometer_type; + +/***** Extern of Class Methods *****/ +extern void BreakoutPotentiometer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); +extern mp_obj_t BreakoutPotentiometer_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 BreakoutPotentiometer_set_addr(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutPotentiometer_get_adc_vref(mp_obj_t self_in); +extern mp_obj_t BreakoutPotentiometer_set_adc_vref(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutPotentiometer_get_direction(mp_obj_t self_in); +extern mp_obj_t BreakoutPotentiometer_set_direction(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutPotentiometer_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutPotentiometer_set_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutPotentiometer_read(mp_obj_t self_in); +extern mp_obj_t BreakoutPotentiometer_read_as_percent(mp_obj_t self_in); \ No newline at end of file diff --git a/micropython/modules/breakout_potentiometer/micropython.cmake b/micropython/modules/breakout_potentiometer/micropython.cmake new file mode 100644 index 00000000..dac1d6c9 --- /dev/null +++ b/micropython/modules/breakout_potentiometer/micropython.cmake @@ -0,0 +1,20 @@ +set(MOD_NAME breakout_potentiometer) +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}) \ No newline at end of file diff --git a/micropython/modules/breakout_potentiometer/micropython.mk b/micropython/modules/breakout_potentiometer/micropython.mk new file mode 100755 index 00000000..74d29ae6 --- /dev/null +++ b/micropython/modules/breakout_potentiometer/micropython.mk @@ -0,0 +1,13 @@ +set(MOD_NAME breakout_potentiometer) +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++ \ No newline at end of file diff --git a/micropython/modules/micropython.cmake b/micropython/modules/micropython.cmake index 5b0ca6db..0fc73824 100644 --- a/micropython/modules/micropython.cmake +++ b/micropython/modules/micropython.cmake @@ -1,6 +1,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_ltr559/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_colourlcd160x80/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_as7262/micropython.cmake) @@ -8,6 +9,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/breakout_roundlcd/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_rgbmatrix5x5/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_matrix11x7/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_msa301/micropython.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/breakout_potentiometer/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_trackball/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_sgp30/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_colourlcd240x240/micropython.cmake) From eb95bb0ffe36880a494d9d42f94e08241c3064de Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Tue, 11 May 2021 20:08:04 +0100 Subject: [PATCH 04/27] Reorder of variables to make MP happy --- drivers/ioexpander/ioexpander.cpp | 18 +++++++++++------- drivers/ioexpander/ioexpander.hpp | 8 +++++--- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/ioexpander/ioexpander.cpp b/drivers/ioexpander/ioexpander.cpp index 057cea57..697107af 100644 --- a/drivers/ioexpander/ioexpander.cpp +++ b/drivers/ioexpander/ioexpander.cpp @@ -297,9 +297,17 @@ namespace pimoroni { this->mode = mode; } - IOExpander::IOExpander(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt, uint8_t address, uint32_t timeout, bool debug) : - i2c(i2c), sda(sda), scl(scl), interrupt(interrupt), - address(address), timeout(timeout), debug(debug), vref(3.3f), + IOExpander::IOExpander() : + IOExpander(i2c0, DEFAULT_I2C_ADDRESS, DEFAULT_SDA_PIN, DEFAULT_SCL_PIN, DEFAULT_INT_PIN) { + } + + IOExpander::IOExpander(uint8_t address, uint32_t timeout, bool debug) : + IOExpander(i2c0, address, DEFAULT_SDA_PIN, DEFAULT_SCL_PIN, DEFAULT_INT_PIN, timeout, debug) { + } + + IOExpander::IOExpander(i2c_inst_t *i2c, uint8_t address, uint8_t sda, uint8_t scl, uint8_t interrupt, uint32_t timeout, bool debug) : + i2c(i2c), address(address), sda(sda), scl(scl), interrupt(interrupt), + timeout(timeout), debug(debug), vref(3.3f), encoder_offset{0,0,0,0}, encoder_last{0,0,0,0}, pins{ Pin::pwm(1, 5, 5, reg::PIOCON1), @@ -318,10 +326,6 @@ namespace pimoroni { Pin::adc(1, 7, 0)} { } - IOExpander::IOExpander(uint8_t address, uint32_t timeout, bool debug) : - IOExpander(i2c0, DEFAULT_SDA_PIN, DEFAULT_SCL_PIN, DEFAULT_INT_PIN, address, timeout, debug) { - } - bool IOExpander::init(bool skipChipIdCheck) { bool succeeded = true; diff --git a/drivers/ioexpander/ioexpander.hpp b/drivers/ioexpander/ioexpander.hpp index 31e1f017..c2177425 100644 --- a/drivers/ioexpander/ioexpander.hpp +++ b/drivers/ioexpander/ioexpander.hpp @@ -29,6 +29,7 @@ namespace pimoroni { static const uint8_t DEFAULT_SDA_PIN = 20; static const uint8_t DEFAULT_SCL_PIN = 21; static const uint8_t DEFAULT_INT_PIN = 22; + static const uint8_t PIN_UNUSED = UINT8_MAX; static const uint16_t CHIP_ID = 0xE26A; static const uint8_t CHIP_VERSION = 2; @@ -151,7 +152,7 @@ namespace pimoroni { uint32_t timeout; bool debug; float vref; - int16_t encoder_offset[4];; + int16_t encoder_offset[4]; int16_t encoder_last[4]; Pin pins[NUM_PINS]; @@ -160,8 +161,9 @@ namespace pimoroni { // Constructors/Destructor //-------------------------------------------------- public: - IOExpander(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt, uint8_t address = DEFAULT_I2C_ADDRESS, uint32_t timeout = 1, bool debug = false); - IOExpander(uint8_t address = DEFAULT_I2C_ADDRESS, uint32_t timeout = 1, bool debug = false); + IOExpander(); + IOExpander(uint8_t address, uint32_t timeout = 1, bool debug = false); + IOExpander(i2c_inst_t *i2c, uint8_t address, uint8_t sda, uint8_t scl, uint8_t interrupt = PIN_UNUSED, uint32_t timeout = 1, bool debug = false); //-------------------------------------------------- From 0ce424275fd1a64e2d21afc8cd9f43d8001e9c7c Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Tue, 11 May 2021 20:14:13 +0100 Subject: [PATCH 05/27] Removed some whitespaces --- .../breakout_encoder/breakout_encoder.cpp | 14 +++++++------- .../breakout_potentiometer.cpp | 18 +++++++++--------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/micropython/modules/breakout_encoder/breakout_encoder.cpp b/micropython/modules/breakout_encoder/breakout_encoder.cpp index b6c35209..7188c911 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.cpp +++ b/micropython/modules/breakout_encoder/breakout_encoder.cpp @@ -62,8 +62,8 @@ mp_obj_t BreakoutEncoder_make_new(const mp_obj_type_t *type, size_t n_args, size self = m_new_obj(breakout_encoder_BreakoutEncoder_obj_t); self->base.type = &breakout_encoder_BreakoutEncoder_type; - - self->breakout = new BreakoutEncoder(args[ARG_address].u_int); + + self->breakout = new BreakoutEncoder(args[ARG_address].u_int); } else { enum { ARG_i2c, ARG_address, ARG_sda, ARG_scl, ARG_interrupt }; @@ -93,11 +93,11 @@ mp_obj_t BreakoutEncoder_make_new(const mp_obj_type_t *type, size_t n_args, size 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_encoder_BreakoutEncoder_obj_t); self->base.type = &breakout_encoder_BreakoutEncoder_type; - + i2c_inst_t *i2c = (i2c_id == 0) ? i2c0 : i2c1; self->breakout = new BreakoutEncoder(i2c, args[ARG_address].u_int, sda, scl, args[ARG_interrupt].u_int); } @@ -117,7 +117,7 @@ mp_obj_t BreakoutEncoder_set_addr(size_t n_args, const mp_obj_t *pos_args, mp_ma 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_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_encoder_BreakoutEncoder_obj_t); self->breakout->set_addr(args[ARG_address].u_int); @@ -139,7 +139,7 @@ mp_obj_t BreakoutEncoder_set_direction(size_t n_args, const mp_obj_t *pos_args, 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_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_encoder_BreakoutEncoder_obj_t); self->breakout->set_direction(args[ARG_clockwise].u_bool); @@ -179,7 +179,7 @@ mp_obj_t BreakoutEncoder_set_led(size_t n_args, const mp_obj_t *pos_args, mp_map 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_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_encoder_BreakoutEncoder_obj_t); int r = args[ARG_r].u_int; diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp index beb5c766..f73b6eba 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp @@ -62,8 +62,8 @@ mp_obj_t BreakoutPotentiometer_make_new(const mp_obj_type_t *type, size_t n_args self = m_new_obj(breakout_potentiometer_BreakoutPotentiometer_obj_t); self->base.type = &breakout_potentiometer_BreakoutPotentiometer_type; - - self->breakout = new BreakoutPotentiometer(args[ARG_address].u_int); + + self->breakout = new BreakoutPotentiometer(args[ARG_address].u_int); } else { enum { ARG_i2c, ARG_address, ARG_sda, ARG_scl, ARG_interrupt }; @@ -93,11 +93,11 @@ mp_obj_t BreakoutPotentiometer_make_new(const mp_obj_type_t *type, size_t n_args 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_potentiometer_BreakoutPotentiometer_obj_t); self->base.type = &breakout_potentiometer_BreakoutPotentiometer_type; - + i2c_inst_t *i2c = (i2c_id == 0) ? i2c0 : i2c1; self->breakout = new BreakoutPotentiometer(i2c, args[ARG_address].u_int, sda, scl, args[ARG_interrupt].u_int); } @@ -117,7 +117,7 @@ mp_obj_t BreakoutPotentiometer_set_addr(size_t n_args, const mp_obj_t *pos_args, 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_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_potentiometer_BreakoutPotentiometer_obj_t); self->breakout->set_addr(args[ARG_address].u_int); @@ -139,7 +139,7 @@ mp_obj_t BreakoutPotentiometer_set_adc_vref(size_t n_args, const mp_obj_t *pos_a 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_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_potentiometer_BreakoutPotentiometer_obj_t); float vref = mp_obj_get_float(args[ARG_vref].u_obj); @@ -162,7 +162,7 @@ mp_obj_t BreakoutPotentiometer_set_direction(size_t n_args, const mp_obj_t *pos_ 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_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_potentiometer_BreakoutPotentiometer_obj_t); self->breakout->set_direction(args[ARG_clockwise].u_bool); @@ -179,7 +179,7 @@ mp_obj_t BreakoutPotentiometer_set_brightness(size_t n_args, const mp_obj_t *pos 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_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_potentiometer_BreakoutPotentiometer_obj_t); float brightness = mp_obj_get_float(args[ARG_brightness].u_obj); @@ -202,7 +202,7 @@ mp_obj_t BreakoutPotentiometer_set_led(size_t n_args, const mp_obj_t *pos_args, 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_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_potentiometer_BreakoutPotentiometer_obj_t); int r = args[ARG_r].u_int; From fd38343924d5f3da98b00cce6b96af5695939770 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Tue, 11 May 2021 20:56:35 +0100 Subject: [PATCH 06/27] Micropython bindings for MICS breakout --- .../breakout_mics6814/breakout_mics6814.hpp | 2 +- .../breakout_mics6814/breakout_mics6814.c | 80 +++++ .../breakout_mics6814/breakout_mics6814.cpp | 278 ++++++++++++++++++ .../breakout_mics6814/breakout_mics6814.h | 32 ++ .../breakout_mics6814/micropython.cmake | 20 ++ .../modules/breakout_mics6814/micropython.mk | 13 + micropython/modules/micropython.cmake | 1 + 7 files changed, 425 insertions(+), 1 deletion(-) create mode 100644 micropython/modules/breakout_mics6814/breakout_mics6814.c create mode 100644 micropython/modules/breakout_mics6814/breakout_mics6814.cpp create mode 100644 micropython/modules/breakout_mics6814/breakout_mics6814.h create mode 100644 micropython/modules/breakout_mics6814/micropython.cmake create mode 100755 micropython/modules/breakout_mics6814/micropython.mk diff --git a/libraries/breakout_mics6814/breakout_mics6814.hpp b/libraries/breakout_mics6814/breakout_mics6814.hpp index bcd3f8e9..5d0a10d0 100644 --- a/libraries/breakout_mics6814/breakout_mics6814.hpp +++ b/libraries/breakout_mics6814/breakout_mics6814.hpp @@ -32,7 +32,7 @@ namespace pimoroni { //-------------------------------------------------- // Substructures //-------------------------------------------------- - private: + public: struct Reading { float ref; float reducing; diff --git a/micropython/modules/breakout_mics6814/breakout_mics6814.c b/micropython/modules/breakout_mics6814/breakout_mics6814.c new file mode 100644 index 00000000..f4d11686 --- /dev/null +++ b/micropython/modules/breakout_mics6814/breakout_mics6814.c @@ -0,0 +1,80 @@ +#include "breakout_mics6814.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// BreakoutMICS6814 Class +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Methods *****/ +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutMICS6814_set_addr_obj, 2, BreakoutMICS6814_set_addr); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutMICS6814_get_adc_vref_obj, BreakoutMICS6814_get_adc_vref); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutMICS6814_set_adc_vref_obj, 2, BreakoutMICS6814_set_adc_vref); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutMICS6814_set_brightness_obj, 2, BreakoutMICS6814_set_brightness); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutMICS6814_set_led_obj, 4, BreakoutMICS6814_set_led); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutMICS6814_set_heater_obj, 2, BreakoutMICS6814_set_heater); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutMICS6814_disable_heater_obj, BreakoutMICS6814_disable_heater); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutMICS6814_get_raw_ref_obj, BreakoutMICS6814_get_raw_ref); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutMICS6814_get_raw_red_obj, BreakoutMICS6814_get_raw_red); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutMICS6814_get_raw_nh3_obj, BreakoutMICS6814_get_raw_nh3); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutMICS6814_get_raw_oxd_obj, BreakoutMICS6814_get_raw_oxd); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutMICS6814_read_all_obj, BreakoutMICS6814_read_all); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutMICS6814_read_ref_obj, BreakoutMICS6814_read_ref); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutMICS6814_read_reducing_obj, BreakoutMICS6814_read_reducing); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutMICS6814_read_nh3_obj, BreakoutMICS6814_read_nh3); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutMICS6814_read_oxidising_obj, BreakoutMICS6814_read_oxidising); + +/***** Binding of Methods *****/ +STATIC const mp_rom_map_elem_t BreakoutMICS6814_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_set_addr), MP_ROM_PTR(&BreakoutMICS6814_set_addr_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_adc_vref), MP_ROM_PTR(&BreakoutMICS6814_get_adc_vref_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_adc_vref), MP_ROM_PTR(&BreakoutMICS6814_set_adc_vref_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_brightness), MP_ROM_PTR(&BreakoutMICS6814_set_brightness_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&BreakoutMICS6814_set_led_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_heater), MP_ROM_PTR(&BreakoutMICS6814_set_heater_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_heater), MP_ROM_PTR(&BreakoutMICS6814_disable_heater_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_raw_ref), MP_ROM_PTR(&BreakoutMICS6814_get_raw_ref_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_raw_red), MP_ROM_PTR(&BreakoutMICS6814_get_raw_red_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_raw_nh3), MP_ROM_PTR(&BreakoutMICS6814_get_raw_nh3_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_raw_oxd), MP_ROM_PTR(&BreakoutMICS6814_get_raw_oxd_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_all), MP_ROM_PTR(&BreakoutMICS6814_read_all_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_ref), MP_ROM_PTR(&BreakoutMICS6814_read_ref_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_reducing), MP_ROM_PTR(&BreakoutMICS6814_read_reducing_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_nh3), MP_ROM_PTR(&BreakoutMICS6814_read_nh3_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_oxidising), MP_ROM_PTR(&BreakoutMICS6814_read_oxidising_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(BreakoutMICS6814_locals_dict, BreakoutMICS6814_locals_dict_table); + +/***** Class Definition *****/ +const mp_obj_type_t breakout_mics6814_BreakoutMICS6814_type = { + { &mp_type_type }, + .name = MP_QSTR_breakout_mics6814, + .print = BreakoutMICS6814_print, + .make_new = BreakoutMICS6814_make_new, + .locals_dict = (mp_obj_dict_t*)&BreakoutMICS6814_locals_dict, +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// breakout_mics6814 Module +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Globals Table *****/ +STATIC const mp_map_elem_t breakout_mics6814_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_mics6814) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutMICS6814), (mp_obj_t)&breakout_mics6814_BreakoutMICS6814_type }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_mics6814_globals, breakout_mics6814_globals_table); + +/***** Module Definition *****/ +const mp_obj_module_t breakout_mics6814_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_breakout_mics6814_globals, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +MP_REGISTER_MODULE(MP_QSTR_breakout_mics6814, breakout_mics6814_user_cmodule, MODULE_BREAKOUT_MICS6814_ENABLED); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_mics6814/breakout_mics6814.cpp b/micropython/modules/breakout_mics6814/breakout_mics6814.cpp new file mode 100644 index 00000000..fe217367 --- /dev/null +++ b/micropython/modules/breakout_mics6814/breakout_mics6814.cpp @@ -0,0 +1,278 @@ +#include "../../../pimoroni-pico/libraries/breakout_mics6814/breakout_mics6814.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_mics6814.h" + +/***** Variables Struct *****/ +typedef struct _breakout_mics6814_BreakoutMICS6814_obj_t { + mp_obj_base_t base; + BreakoutMICS6814 *breakout; +} breakout_mics6814_BreakoutMICS6814_obj_t; + +/***** Print *****/ +void BreakoutMICS6814_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; //Unused input parameter + breakout_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_mics6814_BreakoutMICS6814_obj_t); + BreakoutMICS6814* breakout = self->breakout; + mp_print_str(print, "BreakoutMICS6814("); + + 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 BreakoutMICS6814_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + breakout_mics6814_BreakoutMICS6814_obj_t *self = nullptr; + + if(n_args == 0) { + mp_arg_check_num(n_args, n_kw, 0, 0, true); + self = m_new_obj(breakout_mics6814_BreakoutMICS6814_obj_t); + self->base.type = &breakout_mics6814_BreakoutMICS6814_type; + self->breakout = new BreakoutMICS6814(); + } + 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_mics6814_BreakoutMICS6814_obj_t); + self->base.type = &breakout_mics6814_BreakoutMICS6814_type; + + self->breakout = new BreakoutMICS6814(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 = BreakoutMICS6814::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_mics6814_BreakoutMICS6814_obj_t); + self->base.type = &breakout_mics6814_BreakoutMICS6814_type; + + i2c_inst_t *i2c = (i2c_id == 0) ? i2c0 : i2c1; + self->breakout = new BreakoutMICS6814(i2c, args[ARG_address].u_int, sda, scl, args[ARG_interrupt].u_int); + } + + self->breakout->init(); + + return MP_OBJ_FROM_PTR(self); +} + +/***** Methods *****/ +mp_obj_t BreakoutMICS6814_set_addr(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_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_mics6814_BreakoutMICS6814_obj_t); + + self->breakout->set_addr(args[ARG_address].u_int); + + return mp_const_none; +} + +mp_obj_t BreakoutMICS6814_get_adc_vref(mp_obj_t self_in) { + breakout_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_mics6814_BreakoutMICS6814_obj_t); + return mp_obj_new_float(self->breakout->get_adc_vref()); +} + +mp_obj_t BreakoutMICS6814_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_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_mics6814_BreakoutMICS6814_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 BreakoutMICS6814_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_brightness }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_brightness, 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_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_mics6814_BreakoutMICS6814_obj_t); + + float brightness = mp_obj_get_float(args[ARG_brightness].u_obj); + if(brightness < 0 || brightness > 1.0f) + mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); + else + self->breakout->set_brightness((uint8_t)(brightness * 255.0f)); + + return mp_const_none; +} + +mp_obj_t BreakoutMICS6814_set_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_r, ARG_g, ARG_b, ARG_w }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_b, 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_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_mics6814_BreakoutMICS6814_obj_t); + + int r = args[ARG_r].u_int; + int g = args[ARG_g].u_int; + int b = args[ARG_b].u_int; + + if(r < 0 || r > 255) + mp_raise_ValueError("r out of range. Expected 0 to 255"); + else if(g < 0 || g > 255) + mp_raise_ValueError("g out of range. Expected 0 to 255"); + else if(b < 0 || b > 255) + mp_raise_ValueError("b out of range. Expected 0 to 255"); + else + self->breakout->set_led(r, g, b); + + return mp_const_none; +} + +mp_obj_t BreakoutMICS6814_set_heater(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_on }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_on, 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_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_mics6814_BreakoutMICS6814_obj_t); + + self->breakout->set_heater(args[ARG_on].u_bool); + + return mp_const_none; +} + +mp_obj_t BreakoutMICS6814_disable_heater(mp_obj_t self_in) { + breakout_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_mics6814_BreakoutMICS6814_obj_t); + self->breakout->disable_heater(); + + return mp_const_none; +} + +mp_obj_t BreakoutMICS6814_get_raw_ref(mp_obj_t self_in) { + breakout_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_mics6814_BreakoutMICS6814_obj_t); + return mp_obj_new_float(self->breakout->get_raw_ref()); +} + +mp_obj_t BreakoutMICS6814_get_raw_red(mp_obj_t self_in) { + breakout_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_mics6814_BreakoutMICS6814_obj_t); + return mp_obj_new_float(self->breakout->get_raw_red()); +} + +mp_obj_t BreakoutMICS6814_get_raw_nh3(mp_obj_t self_in) { + breakout_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_mics6814_BreakoutMICS6814_obj_t); + return mp_obj_new_float(self->breakout->get_raw_nh3()); +} + +mp_obj_t BreakoutMICS6814_get_raw_oxd(mp_obj_t self_in) { + breakout_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_mics6814_BreakoutMICS6814_obj_t); + return mp_obj_new_float(self->breakout->get_raw_oxd()); +} + +mp_obj_t BreakoutMICS6814_read_all(mp_obj_t self_in) { + breakout_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_mics6814_BreakoutMICS6814_obj_t); + BreakoutMICS6814::Reading reading = self->breakout->read_all(); + + mp_obj_t tuple[4]; + tuple[REF] = mp_obj_new_float(reading.ref); + tuple[REDUCING] = mp_obj_new_float(reading.reducing); + tuple[NH3] = mp_obj_new_float(reading.nh3); + tuple[OXIDISING] = mp_obj_new_float(reading.oxidising); + + return mp_obj_new_tuple(4, tuple); +} + +mp_obj_t BreakoutMICS6814_read_ref(mp_obj_t self_in) { + breakout_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_mics6814_BreakoutMICS6814_obj_t); + return mp_obj_new_float(self->breakout->read_ref()); +} + +mp_obj_t BreakoutMICS6814_read_reducing(mp_obj_t self_in) { + breakout_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_mics6814_BreakoutMICS6814_obj_t); + return mp_obj_new_float(self->breakout->read_reducing()); +} + +mp_obj_t BreakoutMICS6814_read_nh3(mp_obj_t self_in) { + breakout_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_mics6814_BreakoutMICS6814_obj_t); + return mp_obj_new_float(self->breakout->read_nh3()); +} + +mp_obj_t BreakoutMICS6814_read_oxidising(mp_obj_t self_in) { + breakout_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_mics6814_BreakoutMICS6814_obj_t); + return mp_obj_new_float(self->breakout->read_oxidising()); +} +} \ No newline at end of file diff --git a/micropython/modules/breakout_mics6814/breakout_mics6814.h b/micropython/modules/breakout_mics6814/breakout_mics6814.h new file mode 100644 index 00000000..3e53ca92 --- /dev/null +++ b/micropython/modules/breakout_mics6814/breakout_mics6814.h @@ -0,0 +1,32 @@ +// Include MicroPython API. +#include "py/runtime.h" + +enum { + REF = 0, + REDUCING, + NH3, + OXIDISING +}; + +/***** Extern of Class Definition *****/ +extern const mp_obj_type_t breakout_mics6814_BreakoutMICS6814_type; + +/***** Extern of Class Methods *****/ +extern void BreakoutMICS6814_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); +extern mp_obj_t BreakoutMICS6814_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 BreakoutMICS6814_set_addr(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutMICS6814_get_adc_vref(mp_obj_t self_in); +extern mp_obj_t BreakoutMICS6814_set_adc_vref(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutMICS6814_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutMICS6814_set_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutMICS6814_set_heater(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutMICS6814_disable_heater(mp_obj_t self_in); +extern mp_obj_t BreakoutMICS6814_get_raw_ref(mp_obj_t self_in); +extern mp_obj_t BreakoutMICS6814_get_raw_red(mp_obj_t self_in); +extern mp_obj_t BreakoutMICS6814_get_raw_nh3(mp_obj_t self_in); +extern mp_obj_t BreakoutMICS6814_get_raw_oxd(mp_obj_t self_in); +extern mp_obj_t BreakoutMICS6814_read_all(mp_obj_t self_in); +extern mp_obj_t BreakoutMICS6814_read_ref(mp_obj_t self_in); +extern mp_obj_t BreakoutMICS6814_read_reducing(mp_obj_t self_in); +extern mp_obj_t BreakoutMICS6814_read_nh3(mp_obj_t self_in); +extern mp_obj_t BreakoutMICS6814_read_oxidising(mp_obj_t self_in); \ No newline at end of file diff --git a/micropython/modules/breakout_mics6814/micropython.cmake b/micropython/modules/breakout_mics6814/micropython.cmake new file mode 100644 index 00000000..73850414 --- /dev/null +++ b/micropython/modules/breakout_mics6814/micropython.cmake @@ -0,0 +1,20 @@ +set(MOD_NAME breakout_mics6814) +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}) \ No newline at end of file diff --git a/micropython/modules/breakout_mics6814/micropython.mk b/micropython/modules/breakout_mics6814/micropython.mk new file mode 100755 index 00000000..8a533b71 --- /dev/null +++ b/micropython/modules/breakout_mics6814/micropython.mk @@ -0,0 +1,13 @@ +set(MOD_NAME breakout_mics6814) +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++ \ No newline at end of file diff --git a/micropython/modules/micropython.cmake b/micropython/modules/micropython.cmake index 0fc73824..1a4a58c3 100644 --- a/micropython/modules/micropython.cmake +++ b/micropython/modules/micropython.cmake @@ -9,6 +9,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/breakout_roundlcd/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_rgbmatrix5x5/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_matrix11x7/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_msa301/micropython.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/breakout_mics6814/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_potentiometer/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_trackball/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_sgp30/micropython.cmake) From 3b9927fbefe57ebae720a6b58cc88df1223f590f Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Tue, 11 May 2021 21:38:44 +0100 Subject: [PATCH 07/27] Added initialisation check to Enc, Pot and MICS MP bindings --- micropython/modules/breakout_encoder/breakout_encoder.cpp | 4 +++- micropython/modules/breakout_mics6814/breakout_mics6814.cpp | 4 +++- .../modules/breakout_potentiometer/breakout_potentiometer.cpp | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/micropython/modules/breakout_encoder/breakout_encoder.cpp b/micropython/modules/breakout_encoder/breakout_encoder.cpp index 7188c911..2c8585ba 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.cpp +++ b/micropython/modules/breakout_encoder/breakout_encoder.cpp @@ -102,7 +102,9 @@ mp_obj_t BreakoutEncoder_make_new(const mp_obj_type_t *type, size_t n_args, size self->breakout = new BreakoutEncoder(i2c, args[ARG_address].u_int, sda, scl, args[ARG_interrupt].u_int); } - self->breakout->init(); + if(!self->breakout->init()) { + mp_raise_msg(&mp_type_RuntimeError, "Encoder breakout not found when initialising"); + } return MP_OBJ_FROM_PTR(self); } diff --git a/micropython/modules/breakout_mics6814/breakout_mics6814.cpp b/micropython/modules/breakout_mics6814/breakout_mics6814.cpp index fe217367..f154d601 100644 --- a/micropython/modules/breakout_mics6814/breakout_mics6814.cpp +++ b/micropython/modules/breakout_mics6814/breakout_mics6814.cpp @@ -102,7 +102,9 @@ mp_obj_t BreakoutMICS6814_make_new(const mp_obj_type_t *type, size_t n_args, siz self->breakout = new BreakoutMICS6814(i2c, args[ARG_address].u_int, sda, scl, args[ARG_interrupt].u_int); } - self->breakout->init(); + if(!self->breakout->init()) { + mp_raise_msg(&mp_type_RuntimeError, "MICS6814 breakout not found when initialising"); + } return MP_OBJ_FROM_PTR(self); } diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp index f73b6eba..5a9e8301 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp @@ -102,7 +102,9 @@ mp_obj_t BreakoutPotentiometer_make_new(const mp_obj_type_t *type, size_t n_args self->breakout = new BreakoutPotentiometer(i2c, args[ARG_address].u_int, sda, scl, args[ARG_interrupt].u_int); } - self->breakout->init(); + if(!self->breakout->init()) { + mp_raise_msg(&mp_type_RuntimeError, "Potentiometer breakout not found when initialising"); + } return MP_OBJ_FROM_PTR(self); } From 31edcf8f9343c3b7c403ecac3c49333e21cf303e Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Tue, 11 May 2021 21:58:44 +0100 Subject: [PATCH 08/27] Renamed IOE's set_addr method to set_address --- drivers/ioexpander/ioexpander.cpp | 2 +- drivers/ioexpander/ioexpander.hpp | 2 +- libraries/breakout_encoder/breakout_encoder.cpp | 4 ++-- libraries/breakout_encoder/breakout_encoder.hpp | 2 +- libraries/breakout_mics6814/breakout_mics6814.cpp | 4 ++-- libraries/breakout_mics6814/breakout_mics6814.hpp | 2 +- libraries/breakout_potentiometer/breakout_potentiometer.cpp | 4 ++-- libraries/breakout_potentiometer/breakout_potentiometer.hpp | 2 +- micropython/modules/breakout_encoder/breakout_encoder.c | 4 ++-- micropython/modules/breakout_encoder/breakout_encoder.cpp | 4 ++-- micropython/modules/breakout_encoder/breakout_encoder.h | 2 +- micropython/modules/breakout_mics6814/breakout_mics6814.c | 4 ++-- micropython/modules/breakout_mics6814/breakout_mics6814.cpp | 4 ++-- micropython/modules/breakout_mics6814/breakout_mics6814.h | 2 +- .../modules/breakout_potentiometer/breakout_potentiometer.c | 4 ++-- .../modules/breakout_potentiometer/breakout_potentiometer.cpp | 4 ++-- .../modules/breakout_potentiometer/breakout_potentiometer.h | 2 +- 17 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/ioexpander/ioexpander.cpp b/drivers/ioexpander/ioexpander.cpp index 697107af..c2129ee6 100644 --- a/drivers/ioexpander/ioexpander.cpp +++ b/drivers/ioexpander/ioexpander.cpp @@ -372,7 +372,7 @@ namespace pimoroni { return ((uint16_t)i2c_reg_read_uint8(reg::CHIP_ID_H) << 8) | (uint16_t)i2c_reg_read_uint8(reg::CHIP_ID_L); } - void IOExpander::set_addr(uint8_t address) { + void IOExpander::set_address(uint8_t address) { set_bit(reg::CTRL, 4); i2c_reg_write_uint8(reg::ADDR, address); this->address = address; diff --git a/drivers/ioexpander/ioexpander.hpp b/drivers/ioexpander/ioexpander.hpp index c2177425..d308962c 100644 --- a/drivers/ioexpander/ioexpander.hpp +++ b/drivers/ioexpander/ioexpander.hpp @@ -180,7 +180,7 @@ namespace pimoroni { uint16_t get_chip_id(); - void set_addr(uint8_t address); + void set_address(uint8_t address); float get_adc_vref(); void set_adc_vref(float vref); diff --git a/libraries/breakout_encoder/breakout_encoder.cpp b/libraries/breakout_encoder/breakout_encoder.cpp index 08bc0959..1d746274 100644 --- a/libraries/breakout_encoder/breakout_encoder.cpp +++ b/libraries/breakout_encoder/breakout_encoder.cpp @@ -44,8 +44,8 @@ namespace pimoroni { return ioe.get_int(); } - void BreakoutEncoder::set_addr(uint8_t i2c_addr) { - ioe.set_addr(i2c_addr); + void BreakoutEncoder::set_address(uint8_t address) { + ioe.set_address(address); } bool BreakoutEncoder::get_direction(void) { diff --git a/libraries/breakout_encoder/breakout_encoder.hpp b/libraries/breakout_encoder/breakout_encoder.hpp index 22a3b391..d2747568 100644 --- a/libraries/breakout_encoder/breakout_encoder.hpp +++ b/libraries/breakout_encoder/breakout_encoder.hpp @@ -77,7 +77,7 @@ namespace pimoroni { int get_int() const; // Calls through to IOExpander class - void set_addr(uint8_t i2c_addr); + void set_address(uint8_t address); // Encoder breakout specific bool get_direction(); diff --git a/libraries/breakout_mics6814/breakout_mics6814.cpp b/libraries/breakout_mics6814/breakout_mics6814.cpp index c801827a..921f98c3 100644 --- a/libraries/breakout_mics6814/breakout_mics6814.cpp +++ b/libraries/breakout_mics6814/breakout_mics6814.cpp @@ -47,8 +47,8 @@ namespace pimoroni { return ioe.get_int(); } - void BreakoutMICS6814::set_addr(uint8_t i2c_addr) { - ioe.set_addr(i2c_addr); + void BreakoutMICS6814::set_address(uint8_t address) { + ioe.set_address(address); } float BreakoutMICS6814::get_adc_vref(void) { diff --git a/libraries/breakout_mics6814/breakout_mics6814.hpp b/libraries/breakout_mics6814/breakout_mics6814.hpp index 5d0a10d0..0a0e3612 100644 --- a/libraries/breakout_mics6814/breakout_mics6814.hpp +++ b/libraries/breakout_mics6814/breakout_mics6814.hpp @@ -76,7 +76,7 @@ namespace pimoroni { int get_int() const; // Calls through to IOExpander class - void set_addr(uint8_t i2c_addr); + void set_address(uint8_t address); float get_adc_vref(); void set_adc_vref(float vref); diff --git a/libraries/breakout_potentiometer/breakout_potentiometer.cpp b/libraries/breakout_potentiometer/breakout_potentiometer.cpp index b5aec5a4..0f0f9e47 100644 --- a/libraries/breakout_potentiometer/breakout_potentiometer.cpp +++ b/libraries/breakout_potentiometer/breakout_potentiometer.cpp @@ -54,8 +54,8 @@ namespace pimoroni { return ioe.get_int(); } - void BreakoutPotentiometer::set_addr(uint8_t i2c_addr) { - ioe.set_addr(i2c_addr); + void BreakoutPotentiometer::set_address(uint8_t address) { + ioe.set_address(address); } float BreakoutPotentiometer::get_adc_vref(void) { diff --git a/libraries/breakout_potentiometer/breakout_potentiometer.hpp b/libraries/breakout_potentiometer/breakout_potentiometer.hpp index 28b899b3..624cd2d7 100644 --- a/libraries/breakout_potentiometer/breakout_potentiometer.hpp +++ b/libraries/breakout_potentiometer/breakout_potentiometer.hpp @@ -74,7 +74,7 @@ namespace pimoroni { int get_int() const; // Calls through to IOExpander class - void set_addr(uint8_t i2c_addr); + void set_address(uint8_t address); float get_adc_vref(); void set_adc_vref(float vref); diff --git a/micropython/modules/breakout_encoder/breakout_encoder.c b/micropython/modules/breakout_encoder/breakout_encoder.c index 1497018a..4a3aaa6f 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.c +++ b/micropython/modules/breakout_encoder/breakout_encoder.c @@ -5,7 +5,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// /***** Methods *****/ -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoder_set_addr_obj, 2, BreakoutEncoder_set_addr); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoder_set_address_obj, 2, BreakoutEncoder_set_address); MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoder_get_direction_obj, BreakoutEncoder_get_direction); MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoder_set_direction_obj, 2, BreakoutEncoder_set_direction); MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoder_set_brightness_obj, 2, BreakoutEncoder_set_brightness); @@ -15,7 +15,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoder_read_obj, BreakoutEncoder_read); /***** Binding of Methods *****/ STATIC const mp_rom_map_elem_t BreakoutEncoder_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_set_addr), MP_ROM_PTR(&BreakoutEncoder_set_addr_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_address), MP_ROM_PTR(&BreakoutEncoder_set_address_obj) }, { MP_ROM_QSTR(MP_QSTR_get_direction), MP_ROM_PTR(&BreakoutEncoder_get_direction_obj) }, { MP_ROM_QSTR(MP_QSTR_set_direction), MP_ROM_PTR(&BreakoutEncoder_set_direction_obj) }, { MP_ROM_QSTR(MP_QSTR_set_brightness), MP_ROM_PTR(&BreakoutEncoder_set_brightness_obj) }, diff --git a/micropython/modules/breakout_encoder/breakout_encoder.cpp b/micropython/modules/breakout_encoder/breakout_encoder.cpp index 2c8585ba..2f7e5006 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.cpp +++ b/micropython/modules/breakout_encoder/breakout_encoder.cpp @@ -110,7 +110,7 @@ mp_obj_t BreakoutEncoder_make_new(const mp_obj_type_t *type, size_t n_args, size } /***** Methods *****/ -mp_obj_t BreakoutEncoder_set_addr(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t BreakoutEncoder_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 }, @@ -122,7 +122,7 @@ mp_obj_t BreakoutEncoder_set_addr(size_t n_args, const mp_obj_t *pos_args, mp_ma breakout_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_encoder_BreakoutEncoder_obj_t); - self->breakout->set_addr(args[ARG_address].u_int); + self->breakout->set_address(args[ARG_address].u_int); return mp_const_none; } diff --git a/micropython/modules/breakout_encoder/breakout_encoder.h b/micropython/modules/breakout_encoder/breakout_encoder.h index f380b4a7..cfeca433 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.h +++ b/micropython/modules/breakout_encoder/breakout_encoder.h @@ -7,7 +7,7 @@ extern const mp_obj_type_t breakout_encoder_BreakoutEncoder_type; /***** Extern of Class Methods *****/ extern void BreakoutEncoder_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); extern mp_obj_t BreakoutEncoder_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 BreakoutEncoder_set_addr(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutEncoder_set_address(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t BreakoutEncoder_get_direction(mp_obj_t self_in); extern mp_obj_t BreakoutEncoder_set_direction(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t BreakoutEncoder_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); diff --git a/micropython/modules/breakout_mics6814/breakout_mics6814.c b/micropython/modules/breakout_mics6814/breakout_mics6814.c index f4d11686..6f657490 100644 --- a/micropython/modules/breakout_mics6814/breakout_mics6814.c +++ b/micropython/modules/breakout_mics6814/breakout_mics6814.c @@ -5,7 +5,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// /***** Methods *****/ -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutMICS6814_set_addr_obj, 2, BreakoutMICS6814_set_addr); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutMICS6814_set_address_obj, 2, BreakoutMICS6814_set_address); MP_DEFINE_CONST_FUN_OBJ_1(BreakoutMICS6814_get_adc_vref_obj, BreakoutMICS6814_get_adc_vref); MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutMICS6814_set_adc_vref_obj, 2, BreakoutMICS6814_set_adc_vref); MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutMICS6814_set_brightness_obj, 2, BreakoutMICS6814_set_brightness); @@ -24,7 +24,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(BreakoutMICS6814_read_oxidising_obj, BreakoutMICS6814_ /***** Binding of Methods *****/ STATIC const mp_rom_map_elem_t BreakoutMICS6814_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_set_addr), MP_ROM_PTR(&BreakoutMICS6814_set_addr_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_address), MP_ROM_PTR(&BreakoutMICS6814_set_address_obj) }, { MP_ROM_QSTR(MP_QSTR_get_adc_vref), MP_ROM_PTR(&BreakoutMICS6814_get_adc_vref_obj) }, { MP_ROM_QSTR(MP_QSTR_set_adc_vref), MP_ROM_PTR(&BreakoutMICS6814_set_adc_vref_obj) }, { MP_ROM_QSTR(MP_QSTR_set_brightness), MP_ROM_PTR(&BreakoutMICS6814_set_brightness_obj) }, diff --git a/micropython/modules/breakout_mics6814/breakout_mics6814.cpp b/micropython/modules/breakout_mics6814/breakout_mics6814.cpp index f154d601..39477864 100644 --- a/micropython/modules/breakout_mics6814/breakout_mics6814.cpp +++ b/micropython/modules/breakout_mics6814/breakout_mics6814.cpp @@ -110,7 +110,7 @@ mp_obj_t BreakoutMICS6814_make_new(const mp_obj_type_t *type, size_t n_args, siz } /***** Methods *****/ -mp_obj_t BreakoutMICS6814_set_addr(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t BreakoutMICS6814_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 }, @@ -122,7 +122,7 @@ mp_obj_t BreakoutMICS6814_set_addr(size_t n_args, const mp_obj_t *pos_args, mp_m breakout_mics6814_BreakoutMICS6814_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_mics6814_BreakoutMICS6814_obj_t); - self->breakout->set_addr(args[ARG_address].u_int); + self->breakout->set_address(args[ARG_address].u_int); return mp_const_none; } diff --git a/micropython/modules/breakout_mics6814/breakout_mics6814.h b/micropython/modules/breakout_mics6814/breakout_mics6814.h index 3e53ca92..7526fe1d 100644 --- a/micropython/modules/breakout_mics6814/breakout_mics6814.h +++ b/micropython/modules/breakout_mics6814/breakout_mics6814.h @@ -14,7 +14,7 @@ extern const mp_obj_type_t breakout_mics6814_BreakoutMICS6814_type; /***** Extern of Class Methods *****/ extern void BreakoutMICS6814_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); extern mp_obj_t BreakoutMICS6814_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 BreakoutMICS6814_set_addr(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutMICS6814_set_address(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t BreakoutMICS6814_get_adc_vref(mp_obj_t self_in); extern mp_obj_t BreakoutMICS6814_set_adc_vref(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t BreakoutMICS6814_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.c b/micropython/modules/breakout_potentiometer/breakout_potentiometer.c index 603f5bcf..3c5ce6fa 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.c +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.c @@ -5,7 +5,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// /***** Methods *****/ -MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPotentiometer_set_addr_obj, 2, BreakoutPotentiometer_set_addr); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPotentiometer_set_address_obj, 2, BreakoutPotentiometer_set_address); MP_DEFINE_CONST_FUN_OBJ_1(BreakoutPotentiometer_get_adc_vref_obj, BreakoutPotentiometer_get_adc_vref); MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPotentiometer_set_adc_vref_obj, 2, BreakoutPotentiometer_set_adc_vref); MP_DEFINE_CONST_FUN_OBJ_1(BreakoutPotentiometer_get_direction_obj, BreakoutPotentiometer_get_direction); @@ -17,7 +17,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(BreakoutPotentiometer_read_as_percent_obj, BreakoutPot /***** Binding of Methods *****/ STATIC const mp_rom_map_elem_t BreakoutPotentiometer_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_set_addr), MP_ROM_PTR(&BreakoutPotentiometer_set_addr_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_address), MP_ROM_PTR(&BreakoutPotentiometer_set_address_obj) }, { MP_ROM_QSTR(MP_QSTR_get_adc_vref), MP_ROM_PTR(&BreakoutPotentiometer_get_adc_vref_obj) }, { MP_ROM_QSTR(MP_QSTR_set_adc_vref), MP_ROM_PTR(&BreakoutPotentiometer_set_adc_vref_obj) }, { MP_ROM_QSTR(MP_QSTR_get_direction), MP_ROM_PTR(&BreakoutPotentiometer_get_direction_obj) }, diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp index 5a9e8301..799bb4a5 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp @@ -110,7 +110,7 @@ mp_obj_t BreakoutPotentiometer_make_new(const mp_obj_type_t *type, size_t n_args } /***** Methods *****/ -mp_obj_t BreakoutPotentiometer_set_addr(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +mp_obj_t BreakoutPotentiometer_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 }, @@ -122,7 +122,7 @@ mp_obj_t BreakoutPotentiometer_set_addr(size_t n_args, const mp_obj_t *pos_args, breakout_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_potentiometer_BreakoutPotentiometer_obj_t); - self->breakout->set_addr(args[ARG_address].u_int); + self->breakout->set_address(args[ARG_address].u_int); return mp_const_none; } diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.h b/micropython/modules/breakout_potentiometer/breakout_potentiometer.h index 15c8c1dd..f72f65fc 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.h +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.h @@ -7,7 +7,7 @@ extern const mp_obj_type_t breakout_potentiometer_BreakoutPotentiometer_type; /***** Extern of Class Methods *****/ extern void BreakoutPotentiometer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); extern mp_obj_t BreakoutPotentiometer_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 BreakoutPotentiometer_set_addr(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutPotentiometer_set_address(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t BreakoutPotentiometer_get_adc_vref(mp_obj_t self_in); extern mp_obj_t BreakoutPotentiometer_set_adc_vref(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t BreakoutPotentiometer_get_direction(mp_obj_t self_in); From d45a92fef390ffcae348414ef18e604977df2346 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Wed, 12 May 2021 00:01:35 +0100 Subject: [PATCH 09/27] Micropython bindings for IOExpander breakout --- drivers/ioexpander/ioexpander.cpp | 110 ++-- drivers/ioexpander/ioexpander.hpp | 5 +- .../breakout_ioexpander/breakout_ioexpander.c | 90 ++++ .../breakout_ioexpander.cpp | 482 ++++++++++++++++++ .../breakout_ioexpander/breakout_ioexpander.h | 38 ++ .../breakout_ioexpander/micropython.cmake | 20 + .../breakout_ioexpander/micropython.mk | 13 + micropython/modules/micropython.cmake | 1 + 8 files changed, 700 insertions(+), 59 deletions(-) create mode 100644 micropython/modules/breakout_ioexpander/breakout_ioexpander.c create mode 100644 micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp create mode 100644 micropython/modules/breakout_ioexpander/breakout_ioexpander.h create mode 100644 micropython/modules/breakout_ioexpander/micropython.cmake create mode 100755 micropython/modules/breakout_ioexpander/micropython.mk diff --git a/drivers/ioexpander/ioexpander.cpp b/drivers/ioexpander/ioexpander.cpp index c2129ee6..ca8cd74f 100644 --- a/drivers/ioexpander/ioexpander.cpp +++ b/drivers/ioexpander/ioexpander.cpp @@ -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) { diff --git a/drivers/ioexpander/ioexpander.hpp b/drivers/ioexpander/ioexpander.hpp index d308962c..75e67a81 100644 --- a/drivers/ioexpander/ioexpander.hpp +++ b/drivers/ioexpander/ioexpander.hpp @@ -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: diff --git a/micropython/modules/breakout_ioexpander/breakout_ioexpander.c b/micropython/modules/breakout_ioexpander/breakout_ioexpander.c new file mode 100644 index 00000000..368ea75b --- /dev/null +++ b/micropython/modules/breakout_ioexpander/breakout_ioexpander.c @@ -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); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp b/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp new file mode 100644 index 00000000..206c1b58 --- /dev/null +++ b/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp @@ -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; +} +} \ No newline at end of file diff --git a/micropython/modules/breakout_ioexpander/breakout_ioexpander.h b/micropython/modules/breakout_ioexpander/breakout_ioexpander.h new file mode 100644 index 00000000..6bec8472 --- /dev/null +++ b/micropython/modules/breakout_ioexpander/breakout_ioexpander.h @@ -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); \ No newline at end of file diff --git a/micropython/modules/breakout_ioexpander/micropython.cmake b/micropython/modules/breakout_ioexpander/micropython.cmake new file mode 100644 index 00000000..e41f93ef --- /dev/null +++ b/micropython/modules/breakout_ioexpander/micropython.cmake @@ -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}) \ No newline at end of file diff --git a/micropython/modules/breakout_ioexpander/micropython.mk b/micropython/modules/breakout_ioexpander/micropython.mk new file mode 100755 index 00000000..f632c809 --- /dev/null +++ b/micropython/modules/breakout_ioexpander/micropython.mk @@ -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++ \ No newline at end of file diff --git a/micropython/modules/micropython.cmake b/micropython/modules/micropython.cmake index 1a4a58c3..3493560c 100644 --- a/micropython/modules/micropython.cmake +++ b/micropython/modules/micropython.cmake @@ -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) From 41056e011db5451b8b16ad0c2c049e75c418bd73 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Wed, 12 May 2021 00:02:39 +0100 Subject: [PATCH 10/27] Added old pot and encoder examples (will tidy up later) --- examples/CMakeLists.txt | 5 + examples/ioe_adc_bg/CMakeLists.txt | 14 ++ examples/ioe_adc_bg/ioe_adc_bg.cpp | 177 ++++++++++++++++++ examples/ioe_adc_min_case/CMakeLists.txt | 14 ++ .../ioe_adc_min_case/ioe_adc_min_case.cpp | 48 +++++ examples/ioe_bg/CMakeLists.txt | 14 ++ examples/ioe_bg/ioe_bg.cpp | 176 +++++++++++++++++ examples/ioe_enc_min_case/CMakeLists.txt | 14 ++ .../ioe_enc_min_case/ioe_enc_min_case.cpp | 57 ++++++ 9 files changed, 519 insertions(+) create mode 100644 examples/ioe_adc_bg/CMakeLists.txt create mode 100644 examples/ioe_adc_bg/ioe_adc_bg.cpp create mode 100644 examples/ioe_adc_min_case/CMakeLists.txt create mode 100644 examples/ioe_adc_min_case/ioe_adc_min_case.cpp create mode 100644 examples/ioe_bg/CMakeLists.txt create mode 100644 examples/ioe_bg/ioe_bg.cpp create mode 100644 examples/ioe_enc_min_case/CMakeLists.txt create mode 100644 examples/ioe_enc_min_case/ioe_enc_min_case.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 2b11e0ec..26b90865 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -12,6 +12,11 @@ add_subdirectory(breakout_sgp30) add_subdirectory(breakout_colourlcd240x240) add_subdirectory(breakout_msa301) +add_subdirectory(ioe_adc_bg) +add_subdirectory(ioe_adc_min_case) +add_subdirectory(ioe_bg) +add_subdirectory(ioe_enc_min_case) + add_subdirectory(pico_display) add_subdirectory(pico_unicorn) add_subdirectory(pico_unicorn_plasma) diff --git a/examples/ioe_adc_bg/CMakeLists.txt b/examples/ioe_adc_bg/CMakeLists.txt new file mode 100644 index 00000000..3ab39235 --- /dev/null +++ b/examples/ioe_adc_bg/CMakeLists.txt @@ -0,0 +1,14 @@ +add_executable( + ioe_adc_bg + ioe_adc_bg.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(ioe_adc_bg pico_stdlib pico_explorer ioexpander) + +# disable usb output, enable uart output +pico_enable_stdio_usb(ioe_adc_bg 0) +pico_enable_stdio_uart(ioe_adc_bg 1) + +# create map/bin/hex file etc. +pico_add_extra_outputs(ioe_adc_bg) diff --git a/examples/ioe_adc_bg/ioe_adc_bg.cpp b/examples/ioe_adc_bg/ioe_adc_bg.cpp new file mode 100644 index 00000000..a2b06091 --- /dev/null +++ b/examples/ioe_adc_bg/ioe_adc_bg.cpp @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include +#include +#include "pico/stdlib.h" + +#include "pico_explorer.hpp" +#include "ioexpander.hpp" + +static const uint8_t PIN_RED = 1; +static const uint8_t PIN_GREEN = 7; +static const uint8_t PIN_BLUE = 2; + +static const uint8_t PIN_TERM_A = 12; +static const uint8_t PIN_TERM_B = 3; +static const uint8_t PIN_INPUT = 11; + +static const bool INVERT_OUTPUT = true; //true for common cathode, false for common anode + +using namespace pimoroni; + +uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; +PicoExplorer pico_explorer(buffer); + +IOExpander ioe(0x0e); +bool toggle = false; + +void HSVtoRGB(float hue, float sat, float val, uint8_t& rOut, uint8_t& gOut, uint8_t& bOut) +{ + //////////////////////////////// + // Convert HSV values to RGB + // H(Hue): 0-360 degrees + // S(Saturation): 0-100 percent + // V(Value): 0-100 percent + // + // RGB out is in range 0->255. + // This method was found at: + // https://www.codespeedy.com/hsv-to-rgb-in-cpp/ + //////////////////////////////// + if(hue > 360.0f || hue < 0.0f || sat > 100.0f || sat < 0.0f || val > 100.0f || val < 0.0f) { + //The given HSV values are not in valid range + rOut = 0; + gOut = 0; + bOut = 0; + return; + } + + float s = sat / 100.0f; + float v = val / 100.0f; + float c = s * v; + float x = c * (1.0f - fabsf(fmodf(hue / 60.0f, 2.0f) - 1.0f)); + float m = v - c; + + float r, g, b; + if(hue >= 0.0f && hue < 60.0f) + r = c, g = x, b = 0.0f; + else if(hue >= 60.0f && hue < 120.0f) + r = x, g = c, b = 0.0f; + else if(hue >= 120.0f && hue < 180.0f) + r = 0.0f, g = c, b = x; + else if(hue >= 180.0f && hue < 240.0f) + r = 0.0f, g = x, b = c; + else if(hue >= 240.0f && hue < 300.0f) + r = x, g = 0.0f, b = c; + else + r = c, g = 0.0f, b = x; + + rOut = (uint8_t)((r + m) * 255.0f); + gOut = (uint8_t)((g + m) * 255.0f); + bOut = (uint8_t)((b + m) * 255.0f); +} + +int main() { + pico_explorer.init(); + pico_explorer.update(); + stdio_init_all(); + + sleep_ms(5000); + + const uint LED_PIN = 25; + gpio_init(LED_PIN); + gpio_set_dir(LED_PIN, GPIO_OUT); + + const uint DBG_PIN = 26; + gpio_init(DBG_PIN); + gpio_set_dir(DBG_PIN, GPIO_OUT); + + float brightness = 1.0f; + + int16_t count = 0; + if(ioe.init()) { + printf("IOExpander found...\n"); + + ioe.set_mode(PIN_TERM_A, IOExpander::PIN_OUT); + ioe.set_mode(PIN_TERM_B, IOExpander::PIN_OUT); + ioe.set_mode(PIN_INPUT, IOExpander::PIN_ADC); + + ioe.output(PIN_TERM_A, 0); + ioe.output(PIN_TERM_B, 1); + + //Calculate a period large enough to get 0-255 steps at the desired brightness + unsigned int period = (unsigned int)(255.0f / brightness); + + ioe.set_pwm_period(period); + ioe.set_pwm_control(2); //PWM as fast as we can to avoid LED flicker + + ioe.set_mode(PIN_RED, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + ioe.set_mode(PIN_GREEN, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + ioe.set_mode(PIN_BLUE, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + + sleep_ms(1000); + + while (true) { + gpio_put(LED_PIN, toggle); + toggle = !toggle; + + float analog = ioe.input_as_voltage(PIN_INPUT) / ioe.get_adc_vref(); + + float h = (analog * 240.0f); + uint8_t r, g, b; + HSVtoRGB(h, 100.0f, 100.0f, r, g, b); + + ioe.output(PIN_RED, r, false); //Hold off pwm load until the last + ioe.output(PIN_GREEN, g, false); //Hold off pwm load until the last + ioe.output(PIN_BLUE, b); //Loads all 3 pwms + + + + pico_explorer.set_pen(0, 0, 0); + pico_explorer.clear(); + + { + pico_explorer.set_pen(255, 0, 0); + std::ostringstream ss; + ss << "R = "; + ss << (int)r; + std::string s(ss.str()); + pico_explorer.text(s, Point(10, 10), 220, 6); + } + + { + pico_explorer.set_pen(0, 255, 0); + std::ostringstream ss; + ss << "G = "; + ss << (int)g; + std::string s(ss.str()); + pico_explorer.text(s, Point(10, 70), 220, 6); + } + + { + pico_explorer.set_pen(0, 0, 255); + std::ostringstream ss; + ss << "B = "; + ss << (int)b; + std::string s(ss.str()); + pico_explorer.text(s, Point(10, 130), 220, 6); + } + pico_explorer.update(); + + sleep_ms(10); + } + } + else { + printf("IOExpander not found :'(\n"); + + while(true) { + gpio_put(LED_PIN, 1); + sleep_ms(250); + gpio_put(LED_PIN, 0); + sleep_ms(250); + } + } + + return 0; +} diff --git a/examples/ioe_adc_min_case/CMakeLists.txt b/examples/ioe_adc_min_case/CMakeLists.txt new file mode 100644 index 00000000..018c1307 --- /dev/null +++ b/examples/ioe_adc_min_case/CMakeLists.txt @@ -0,0 +1,14 @@ +add_executable( + ioe_adc_min_case + ioe_adc_min_case.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(ioe_adc_min_case pico_stdlib ioexpander) + +# disable usb output, enable uart output +pico_enable_stdio_usb(ioe_adc_min_case 1) +pico_enable_stdio_uart(ioe_adc_min_case 0) + +# create map/bin/hex file etc. +pico_add_extra_outputs(ioe_adc_min_case) diff --git a/examples/ioe_adc_min_case/ioe_adc_min_case.cpp b/examples/ioe_adc_min_case/ioe_adc_min_case.cpp new file mode 100644 index 00000000..0c0b27fc --- /dev/null +++ b/examples/ioe_adc_min_case/ioe_adc_min_case.cpp @@ -0,0 +1,48 @@ +#include +#include "pico/stdlib.h" +#include "ioexpander.hpp" + +static const uint8_t PIN_TERM_A = 12; +static const uint8_t PIN_TERM_B = 3; +static const uint8_t PIN_INPUT = 11; + +using namespace pimoroni; + +IOExpander ioe(0x0e); + +int main() { + stdio_init_all(); + + sleep_ms(5000); //Delay to give chance to connect terminal + + const uint LED_PIN = 25; + gpio_init(LED_PIN); + gpio_set_dir(LED_PIN, GPIO_OUT); + + if(ioe.init()) { + printf("IOExpander found...\n"); + + ioe.set_mode(PIN_TERM_A, IOExpander::PIN_OUT); + ioe.set_mode(PIN_TERM_B, IOExpander::PIN_OUT); + ioe.set_mode(PIN_INPUT, IOExpander::PIN_ADC); + + ioe.output(PIN_TERM_A, 0); + ioe.output(PIN_TERM_B, 1); + + bool toggle = false; + while(true) { + gpio_put(LED_PIN, toggle); + toggle = !toggle; + + printf("%d\n", ioe.input(PIN_INPUT)); + + sleep_ms(20); + } + } + else { + printf("IOExpander not found :'(\n"); + gpio_put(LED_PIN, 1); + } + + return 0; +} diff --git a/examples/ioe_bg/CMakeLists.txt b/examples/ioe_bg/CMakeLists.txt new file mode 100644 index 00000000..1dc5901d --- /dev/null +++ b/examples/ioe_bg/CMakeLists.txt @@ -0,0 +1,14 @@ +add_executable( + ioe_bg + ioe_bg.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(ioe_bg pico_stdlib pico_explorer ioexpander) + +# disable usb output, enable uart output +pico_enable_stdio_usb(ioe_bg 0) +pico_enable_stdio_uart(ioe_bg 1) + +# create map/bin/hex file etc. +pico_add_extra_outputs(ioe_bg) diff --git a/examples/ioe_bg/ioe_bg.cpp b/examples/ioe_bg/ioe_bg.cpp new file mode 100644 index 00000000..ba983ccf --- /dev/null +++ b/examples/ioe_bg/ioe_bg.cpp @@ -0,0 +1,176 @@ +#include +#include +#include +#include +#include +#include +#include "pico/stdlib.h" + +#include "pico_explorer.hpp" +#include "ioexpander.hpp" + +static const uint8_t PIN_RED = 1; +static const uint8_t PIN_GREEN = 7; +static const uint8_t PIN_BLUE = 2; + +static const uint8_t PIN_ENC_A = 12; +static const uint8_t PIN_ENC_B = 3; +static const uint8_t PIN_ENC_C = 11; + +static const uint8_t ENC_CHANNEL = 1; + +static const bool INVERT_OUTPUT = true; //true for common cathode, false for common anode + +using namespace pimoroni; + +uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; +PicoExplorer pico_explorer(buffer); + +IOExpander ioe(0x0f); +bool toggle = false; + +void HSVtoRGB(float hue, float sat, float val, uint8_t& rOut, uint8_t& gOut, uint8_t& bOut) +{ + //////////////////////////////// + // Convert HSV values to RGB + // H(Hue): 0-360 degrees + // S(Saturation): 0-100 percent + // V(Value): 0-100 percent + // + // RGB out is in range 0->255. + // This method was found at: + // https://www.codespeedy.com/hsv-to-rgb-in-cpp/ + //////////////////////////////// + if(hue > 360.0f || hue < 0.0f || sat > 100.0f || sat < 0.0f || val > 100.0f || val < 0.0f) { + //The given HSV values are not in valid range + rOut = 0; + gOut = 0; + bOut = 0; + return; + } + + float s = sat / 100.0f; + float v = val / 100.0f; + float c = s * v; + float x = c * (1.0f - fabsf(fmodf(hue / 60.0f, 2.0f) - 1.0f)); + float m = v - c; + + float r, g, b; + if(hue >= 0.0f && hue < 60.0f) + r = c, g = x, b = 0.0f; + else if(hue >= 60.0f && hue < 120.0f) + r = x, g = c, b = 0.0f; + else if(hue >= 120.0f && hue < 180.0f) + r = 0.0f, g = c, b = x; + else if(hue >= 180.0f && hue < 240.0f) + r = 0.0f, g = x, b = c; + else if(hue >= 240.0f && hue < 300.0f) + r = x, g = 0.0f, b = c; + else + r = c, g = 0.0f, b = x; + + rOut = (uint8_t)((r + m) * 255.0f); + gOut = (uint8_t)((g + m) * 255.0f); + bOut = (uint8_t)((b + m) * 255.0f); +} + +int main() { + pico_explorer.init(); + pico_explorer.update(); + stdio_init_all(); + + sleep_ms(5000); + + const uint LED_PIN = 25; + gpio_init(LED_PIN); + gpio_set_dir(LED_PIN, GPIO_OUT); + + const uint DBG_PIN = 26; + gpio_init(DBG_PIN); + gpio_set_dir(DBG_PIN, GPIO_OUT); + + float brightness = 1.0f; + + int16_t count = 0; + if(ioe.init()) { + printf("IOExpander found...\n"); + + ioe.setup_rotary_encoder(ENC_CHANNEL, PIN_ENC_A, PIN_ENC_B, PIN_ENC_C); + + //Calculate a period large enough to get 0-255 steps at the desired brightness + unsigned int period = (unsigned int)(255.0f / brightness); + + ioe.set_pwm_period(period); + ioe.set_pwm_control(2); //PWM as fast as we can to avoid LED flicker + + ioe.set_mode(PIN_RED, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + ioe.set_mode(PIN_GREEN, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + ioe.set_mode(PIN_BLUE, IOExpander::PIN_PWM, false, INVERT_OUTPUT); + + sleep_ms(1000); + + while(true) { + gpio_put(LED_PIN, toggle); + toggle = !toggle; + + if(ioe.get_interrupt_flag() > 0) { //This should work but + gpio_put(DBG_PIN, 1); + count = ioe.read_rotary_encoder(ENC_CHANNEL); + ioe.clear_interrupt_flag(); + gpio_put(DBG_PIN, 0); + } + + while(count < 0) + count += 24; + + float h = ((float)(count % 24) * 360.0f) / 24.0f; + uint8_t r, g, b; + HSVtoRGB(h, 100.0f, 100.0f, r, g, b); + + ioe.output(PIN_RED, r, false); //Hold off pwm load until the last + ioe.output(PIN_GREEN, g, false); //Hold off pwm load until the last + ioe.output(PIN_BLUE, b); //Loads all 3 pwms + + + + pico_explorer.set_pen(0, 0, 0); + pico_explorer.clear(); + + { + pico_explorer.set_pen(255, 0, 0); + std::ostringstream ss; + ss << "R = "; + ss << (int)r; + std::string s(ss.str()); + pico_explorer.text(s, Point(10, 10), 220, 6); + } + + { + pico_explorer.set_pen(0, 255, 0); + std::ostringstream ss; + ss << "G = "; + ss << (int)g; + std::string s(ss.str()); + pico_explorer.text(s, Point(10, 70), 220, 6); + } + + { + pico_explorer.set_pen(0, 0, 255); + std::ostringstream ss; + ss << "B = "; + ss << (int)b; + std::string s(ss.str()); + pico_explorer.text(s, Point(10, 130), 220, 6); + } + pico_explorer.update(); + + sleep_ms(10); + } + } + else { + printf("IOExpander not found :'(\n"); + gpio_put(LED_PIN, 1); + } + + return 0; +} diff --git a/examples/ioe_enc_min_case/CMakeLists.txt b/examples/ioe_enc_min_case/CMakeLists.txt new file mode 100644 index 00000000..9cc97ae3 --- /dev/null +++ b/examples/ioe_enc_min_case/CMakeLists.txt @@ -0,0 +1,14 @@ +add_executable( + ioe_enc_min_case + ioe_enc_min_case.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(ioe_enc_min_case pico_stdlib ioexpander) + +# disable usb output, enable uart output +pico_enable_stdio_usb(ioe_enc_min_case 1) +pico_enable_stdio_uart(ioe_enc_min_case 0) + +# create map/bin/hex file etc. +pico_add_extra_outputs(ioe_enc_min_case) diff --git a/examples/ioe_enc_min_case/ioe_enc_min_case.cpp b/examples/ioe_enc_min_case/ioe_enc_min_case.cpp new file mode 100644 index 00000000..1b1c2eab --- /dev/null +++ b/examples/ioe_enc_min_case/ioe_enc_min_case.cpp @@ -0,0 +1,57 @@ +#include +#include "pico/stdlib.h" +#include "ioexpander.hpp" + +static const uint8_t PIN_ENC_A = 12; +static const uint8_t PIN_ENC_B = 3; +static const uint8_t PIN_ENC_C = 11; + +static const uint8_t ENC_CHANNEL = 1; + +using namespace pimoroni; + +IOExpander ioe(0x0f); + +int main() { + stdio_init_all(); + + sleep_ms(5000); //Delay to give chance to connect terminal + + const uint LED_PIN = 25; + gpio_init(LED_PIN); + gpio_set_dir(LED_PIN, GPIO_OUT); + + if(ioe.init()) { + printf("IOExpander found...\n"); + + ioe.setup_rotary_encoder(ENC_CHANNEL, PIN_ENC_A, PIN_ENC_B, PIN_ENC_C); + + bool toggle = false; + int16_t count = 0; + while(true) { + gpio_put(LED_PIN, toggle); + toggle = !toggle; + + //Polling encoder directly works + //printf("%d\n", ioe.read_rotary_encoder(ENC_CHANNEL)); + + //Only reading encoder when the interrupt pin changes does not. + if(ioe.get_interrupt_flag()) { + printf("new count: "); + count = ioe.read_rotary_encoder(ENC_CHANNEL); + ioe.clear_interrupt_flag(); + } + + printf("%d\n", count); + + + sleep_ms(20); + } + } + else { + printf("IOExpander not found :'(\n"); + gpio_put(LED_PIN, 1); + } + + return 0; +} From 42f2bff6c7defb4c6bbdf718358837d3b7e48d2f Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Wed, 12 May 2021 17:20:42 +0100 Subject: [PATCH 11/27] Fixed pot read from returning bool to returning a float, and removed read_as_percent for read_raw --- .../breakout_potentiometer/breakout_potentiometer.cpp | 10 +++++----- .../breakout_potentiometer/breakout_potentiometer.hpp | 4 ++-- .../breakout_potentiometer/breakout_potentiometer.c | 4 ++-- .../breakout_potentiometer/breakout_potentiometer.cpp | 6 +++--- .../breakout_potentiometer/breakout_potentiometer.h | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/libraries/breakout_potentiometer/breakout_potentiometer.cpp b/libraries/breakout_potentiometer/breakout_potentiometer.cpp index 0f0f9e47..07c8ffe3 100644 --- a/libraries/breakout_potentiometer/breakout_potentiometer.cpp +++ b/libraries/breakout_potentiometer/breakout_potentiometer.cpp @@ -99,11 +99,11 @@ namespace pimoroni { ioe.output(LED_B, b); // Loads all 3 pwms } - int16_t BreakoutPotentiometer::read(uint32_t adc_timeout) { - return ioe.input(POT_INPUT, adc_timeout); - } - - float BreakoutPotentiometer::read_as_percent(uint32_t adc_timeout) { +float BreakoutPotentiometer::read(uint32_t adc_timeout) { return (ioe.input_as_voltage(POT_INPUT, adc_timeout) / ioe.get_adc_vref()); } + + int16_t BreakoutPotentiometer::read_raw(uint32_t adc_timeout) { + return ioe.input(POT_INPUT, adc_timeout); + } } \ No newline at end of file diff --git a/libraries/breakout_potentiometer/breakout_potentiometer.hpp b/libraries/breakout_potentiometer/breakout_potentiometer.hpp index 624cd2d7..f8c42583 100644 --- a/libraries/breakout_potentiometer/breakout_potentiometer.hpp +++ b/libraries/breakout_potentiometer/breakout_potentiometer.hpp @@ -86,8 +86,8 @@ namespace pimoroni { void set_brightness(float brightness); void set_led(uint8_t r, uint8_t g, uint8_t b); - int16_t read(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); - float read_as_percent(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); + float read(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); + int16_t read_raw(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT); }; } \ No newline at end of file diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.c b/micropython/modules/breakout_potentiometer/breakout_potentiometer.c index 3c5ce6fa..7c834101 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.c +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.c @@ -13,7 +13,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPotentiometer_set_direction_obj, 2, BreakoutP MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPotentiometer_set_brightness_obj, 2, BreakoutPotentiometer_set_brightness); MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutPotentiometer_set_led_obj, 4, BreakoutPotentiometer_set_led); MP_DEFINE_CONST_FUN_OBJ_1(BreakoutPotentiometer_read_obj, BreakoutPotentiometer_read); -MP_DEFINE_CONST_FUN_OBJ_1(BreakoutPotentiometer_read_as_percent_obj, BreakoutPotentiometer_read_as_percent); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutPotentiometer_read_raw_obj, BreakoutPotentiometer_read_raw); /***** Binding of Methods *****/ STATIC const mp_rom_map_elem_t BreakoutPotentiometer_locals_dict_table[] = { @@ -25,7 +25,7 @@ STATIC const mp_rom_map_elem_t BreakoutPotentiometer_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_set_brightness), MP_ROM_PTR(&BreakoutPotentiometer_set_brightness_obj) }, { MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&BreakoutPotentiometer_set_led_obj) }, { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&BreakoutPotentiometer_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_read_as_percent), MP_ROM_PTR(&BreakoutPotentiometer_read_as_percent_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_raw), MP_ROM_PTR(&BreakoutPotentiometer_read_raw_obj) }, }; STATIC MP_DEFINE_CONST_DICT(BreakoutPotentiometer_locals_dict, BreakoutPotentiometer_locals_dict_table); diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp index 799bb4a5..ee3a2bdc 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp @@ -225,11 +225,11 @@ mp_obj_t BreakoutPotentiometer_set_led(size_t n_args, const mp_obj_t *pos_args, mp_obj_t BreakoutPotentiometer_read(mp_obj_t self_in) { breakout_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_potentiometer_BreakoutPotentiometer_obj_t); - return mp_obj_new_bool(self->breakout->read()); + return mp_obj_new_float(self->breakout->read()); } -mp_obj_t BreakoutPotentiometer_read_as_percent(mp_obj_t self_in) { +mp_obj_t BreakoutPotentiometer_read_raw(mp_obj_t self_in) { breakout_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_potentiometer_BreakoutPotentiometer_obj_t); - return mp_obj_new_float(self->breakout->read_as_percent()); + return mp_obj_new_int(self->breakout->read_raw()); } } \ No newline at end of file diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.h b/micropython/modules/breakout_potentiometer/breakout_potentiometer.h index f72f65fc..7aca57a6 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.h +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.h @@ -15,4 +15,4 @@ extern mp_obj_t BreakoutPotentiometer_set_direction(size_t n_args, const mp_obj_ extern mp_obj_t BreakoutPotentiometer_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t BreakoutPotentiometer_set_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t BreakoutPotentiometer_read(mp_obj_t self_in); -extern mp_obj_t BreakoutPotentiometer_read_as_percent(mp_obj_t self_in); \ No newline at end of file +extern mp_obj_t BreakoutPotentiometer_read_raw(mp_obj_t self_in); \ No newline at end of file From 4a206a9b7011f718466d93b8d34292092f197786 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Wed, 12 May 2021 17:51:54 +0100 Subject: [PATCH 12/27] Fix for set brightness not working --- micropython/modules/breakout_encoder/breakout_encoder.cpp | 2 +- micropython/modules/breakout_mics6814/breakout_mics6814.cpp | 2 +- .../modules/breakout_potentiometer/breakout_potentiometer.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/micropython/modules/breakout_encoder/breakout_encoder.cpp b/micropython/modules/breakout_encoder/breakout_encoder.cpp index 2f7e5006..a9922ce0 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.cpp +++ b/micropython/modules/breakout_encoder/breakout_encoder.cpp @@ -165,7 +165,7 @@ mp_obj_t BreakoutEncoder_set_brightness(size_t n_args, const mp_obj_t *pos_args, if(brightness < 0 || brightness > 1.0f) mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); else - self->breakout->set_brightness((uint8_t)(brightness * 255.0f)); + self->breakout->set_brightness(brightness); return mp_const_none; } diff --git a/micropython/modules/breakout_mics6814/breakout_mics6814.cpp b/micropython/modules/breakout_mics6814/breakout_mics6814.cpp index 39477864..7ffc9800 100644 --- a/micropython/modules/breakout_mics6814/breakout_mics6814.cpp +++ b/micropython/modules/breakout_mics6814/breakout_mics6814.cpp @@ -166,7 +166,7 @@ mp_obj_t BreakoutMICS6814_set_brightness(size_t n_args, const mp_obj_t *pos_args if(brightness < 0 || brightness > 1.0f) mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); else - self->breakout->set_brightness((uint8_t)(brightness * 255.0f)); + self->breakout->set_brightness(brightness); return mp_const_none; } diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp index ee3a2bdc..30338763 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp @@ -188,7 +188,7 @@ mp_obj_t BreakoutPotentiometer_set_brightness(size_t n_args, const mp_obj_t *pos if(brightness < 0 || brightness > 1.0f) mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); else - self->breakout->set_brightness((uint8_t)(brightness * 255.0f)); + self->breakout->set_brightness(brightness); return mp_const_none; } From d4ba1d97d990d5e8082d7c43ded571e5f0f78a8f Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Wed, 12 May 2021 18:27:03 +0100 Subject: [PATCH 13/27] Switch C++ to use Direction enum for functions and added Direction contants to MP --- libraries/breakout_encoder/breakout_encoder.cpp | 10 +++++----- libraries/breakout_encoder/breakout_encoder.hpp | 8 ++++---- .../breakout_potentiometer.cpp | 14 +++++++------- .../breakout_potentiometer.hpp | 8 ++++---- .../modules/breakout_encoder/breakout_encoder.c | 2 ++ .../modules/breakout_encoder/breakout_encoder.cpp | 2 +- .../breakout_potentiometer.c | 2 ++ .../breakout_potentiometer.cpp | 2 +- 8 files changed, 26 insertions(+), 22 deletions(-) diff --git a/libraries/breakout_encoder/breakout_encoder.cpp b/libraries/breakout_encoder/breakout_encoder.cpp index 1d746274..cc4cdd74 100644 --- a/libraries/breakout_encoder/breakout_encoder.cpp +++ b/libraries/breakout_encoder/breakout_encoder.cpp @@ -48,12 +48,12 @@ namespace pimoroni { ioe.set_address(address); } - bool BreakoutEncoder::get_direction(void) { - return direction_cw; + BreakoutEncoder::Direction BreakoutEncoder::get_direction() { + return direction; } - void BreakoutEncoder::set_direction(bool clockwise) { - direction_cw = clockwise; + void BreakoutEncoder::set_direction(Direction direction) { + this->direction = direction; } void BreakoutEncoder::set_brightness(float brightness) { @@ -77,7 +77,7 @@ namespace pimoroni { int16_t BreakoutEncoder::read() { int16_t count = ioe.read_rotary_encoder(ENC_CHANNEL); - if(!direction_cw) + if(direction != DIRECTION_CW) count = 0 - count; ioe.clear_interrupt_flag(); diff --git a/libraries/breakout_encoder/breakout_encoder.hpp b/libraries/breakout_encoder/breakout_encoder.hpp index d2747568..f371a40e 100644 --- a/libraries/breakout_encoder/breakout_encoder.hpp +++ b/libraries/breakout_encoder/breakout_encoder.hpp @@ -21,7 +21,7 @@ namespace pimoroni { public: static const uint8_t DEFAULT_I2C_ADDRESS = 0x0F; static constexpr float DEFAULT_BRIGHTNESS = 1.0f; //Effectively the maximum fraction of the period that the LED will be on - static const bool DEFAULT_DIRECTION = DIRECTION_CW; + static const Direction DEFAULT_DIRECTION = DIRECTION_CW; static const uint8_t PIN_UNUSED = UINT8_MAX; static const uint32_t DEFAULT_TIMEOUT = 1; @@ -44,7 +44,7 @@ namespace pimoroni { //-------------------------------------------------- private: IOExpander ioe; - bool direction_cw = DEFAULT_DIRECTION; + Direction direction = DEFAULT_DIRECTION; float brightness = DEFAULT_BRIGHTNESS; uint8_t interrupt_pin = PIN_UNUSED; // A local copy of the value passed to the IOExpander, used in initialisation @@ -80,8 +80,8 @@ namespace pimoroni { void set_address(uint8_t address); // Encoder breakout specific - bool get_direction(); - void set_direction(bool clockwise); + Direction get_direction(); + void set_direction(Direction direction); void set_brightness(float brightness); void set_led(uint8_t r, uint8_t g, uint8_t b); diff --git a/libraries/breakout_potentiometer/breakout_potentiometer.cpp b/libraries/breakout_potentiometer/breakout_potentiometer.cpp index 07c8ffe3..445d3f92 100644 --- a/libraries/breakout_potentiometer/breakout_potentiometer.cpp +++ b/libraries/breakout_potentiometer/breakout_potentiometer.cpp @@ -11,7 +11,7 @@ namespace pimoroni { ioe.set_mode(POT_TERM_B, IOExpander::PIN_OUT); ioe.set_mode(POT_INPUT, IOExpander::PIN_ADC); - if(direction_cw) { + if(direction == DIRECTION_CW) { // Clockwise increasing ioe.output(POT_TERM_A, IOExpander::LOW); ioe.output(POT_TERM_B, IOExpander::HIGH); @@ -58,7 +58,7 @@ namespace pimoroni { ioe.set_address(address); } - float BreakoutPotentiometer::get_adc_vref(void) { + float BreakoutPotentiometer::get_adc_vref() { return ioe.get_adc_vref(); } @@ -66,12 +66,12 @@ namespace pimoroni { ioe.set_adc_vref(vref); } - bool BreakoutPotentiometer::get_direction(void) { - return direction_cw; + BreakoutPotentiometer::Direction BreakoutPotentiometer::get_direction() { + return direction; } - void BreakoutPotentiometer::set_direction(bool clockwise) { - if(clockwise) { + void BreakoutPotentiometer::set_direction(Direction direction) { + if(direction == DIRECTION_CW) { // Clockwise increasing ioe.output(POT_TERM_A, IOExpander::LOW); ioe.output(POT_TERM_B, IOExpander::HIGH); @@ -81,7 +81,7 @@ namespace pimoroni { ioe.output(POT_TERM_A, IOExpander::HIGH); ioe.output(POT_TERM_B, IOExpander::LOW); } - direction_cw = clockwise; + this->direction = direction; } void BreakoutPotentiometer::set_brightness(float brightness) { diff --git a/libraries/breakout_potentiometer/breakout_potentiometer.hpp b/libraries/breakout_potentiometer/breakout_potentiometer.hpp index f8c42583..dad658b2 100644 --- a/libraries/breakout_potentiometer/breakout_potentiometer.hpp +++ b/libraries/breakout_potentiometer/breakout_potentiometer.hpp @@ -21,7 +21,7 @@ namespace pimoroni { public: static const uint8_t DEFAULT_I2C_ADDRESS = 0x0E; static constexpr float DEFAULT_BRIGHTNESS = 1.0f; //Effectively the maximum fraction of the period that the LED will be on - static const bool DEFAULT_DIRECTION = DIRECTION_CW; + static const Direction DEFAULT_DIRECTION = DIRECTION_CW; static const uint8_t PIN_UNUSED = UINT8_MAX; static const uint32_t DEFAULT_TIMEOUT = 1; static const uint32_t DEFAULT_ADC_TIMEOUT = 1; @@ -43,7 +43,7 @@ namespace pimoroni { //-------------------------------------------------- private: IOExpander ioe; - bool direction_cw = DEFAULT_DIRECTION; + Direction direction = DEFAULT_DIRECTION; float brightness = DEFAULT_BRIGHTNESS; @@ -80,8 +80,8 @@ namespace pimoroni { void set_adc_vref(float vref); // Potentiometer breakout specific - bool get_direction(); - void set_direction(bool clockwise); + Direction get_direction(); + void set_direction(Direction direction); void set_brightness(float brightness); void set_led(uint8_t r, uint8_t g, uint8_t b); diff --git a/micropython/modules/breakout_encoder/breakout_encoder.c b/micropython/modules/breakout_encoder/breakout_encoder.c index 4a3aaa6f..8d6622cd 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.c +++ b/micropython/modules/breakout_encoder/breakout_encoder.c @@ -22,6 +22,8 @@ STATIC const mp_rom_map_elem_t BreakoutEncoder_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&BreakoutEncoder_set_led_obj) }, { MP_ROM_QSTR(MP_QSTR_available), MP_ROM_PTR(&BreakoutEncoder_available_obj) }, { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&BreakoutEncoder_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_DIRECTION_CW), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_DIRECTION_CCW), MP_ROM_INT(0) }, }; STATIC MP_DEFINE_CONST_DICT(BreakoutEncoder_locals_dict, BreakoutEncoder_locals_dict_table); diff --git a/micropython/modules/breakout_encoder/breakout_encoder.cpp b/micropython/modules/breakout_encoder/breakout_encoder.cpp index a9922ce0..ac8f501b 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.cpp +++ b/micropython/modules/breakout_encoder/breakout_encoder.cpp @@ -144,7 +144,7 @@ mp_obj_t BreakoutEncoder_set_direction(size_t n_args, const mp_obj_t *pos_args, breakout_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_encoder_BreakoutEncoder_obj_t); - self->breakout->set_direction(args[ARG_clockwise].u_bool); + self->breakout->set_direction(args[ARG_clockwise].u_bool ? BreakoutEncoder::DIRECTION_CW : BreakoutEncoder::DIRECTION_CCW); return mp_const_none; } diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.c b/micropython/modules/breakout_potentiometer/breakout_potentiometer.c index 7c834101..67ada0d6 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.c +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.c @@ -26,6 +26,8 @@ STATIC const mp_rom_map_elem_t BreakoutPotentiometer_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&BreakoutPotentiometer_set_led_obj) }, { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&BreakoutPotentiometer_read_obj) }, { MP_ROM_QSTR(MP_QSTR_read_raw), MP_ROM_PTR(&BreakoutPotentiometer_read_raw_obj) }, + { MP_ROM_QSTR(MP_QSTR_DIRECTION_CW), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_DIRECTION_CCW), MP_ROM_INT(0) }, }; STATIC MP_DEFINE_CONST_DICT(BreakoutPotentiometer_locals_dict, BreakoutPotentiometer_locals_dict_table); diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp index 30338763..99b5106b 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp @@ -167,7 +167,7 @@ mp_obj_t BreakoutPotentiometer_set_direction(size_t n_args, const mp_obj_t *pos_ breakout_potentiometer_BreakoutPotentiometer_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_potentiometer_BreakoutPotentiometer_obj_t); - self->breakout->set_direction(args[ARG_clockwise].u_bool); + self->breakout->set_direction(args[ARG_clockwise].u_bool ? BreakoutPotentiometer::DIRECTION_CW : BreakoutPotentiometer::DIRECTION_CCW); return mp_const_none; } From 1b860840a344d00b20d3248323e7badb6013ba57 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Wed, 12 May 2021 18:39:21 +0100 Subject: [PATCH 14/27] MP path fixes --- micropython/modules/breakout_encoder/breakout_encoder.cpp | 2 +- micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp | 2 +- micropython/modules/breakout_mics6814/breakout_mics6814.cpp | 2 +- .../modules/breakout_potentiometer/breakout_potentiometer.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/micropython/modules/breakout_encoder/breakout_encoder.cpp b/micropython/modules/breakout_encoder/breakout_encoder.cpp index ac8f501b..72a28253 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.cpp +++ b/micropython/modules/breakout_encoder/breakout_encoder.cpp @@ -1,4 +1,4 @@ -#include "../../../pimoroni-pico/libraries/breakout_encoder/breakout_encoder.hpp" +#include "../../../libraries/breakout_encoder/breakout_encoder.hpp" #define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) diff --git a/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp b/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp index 206c1b58..ad733ed5 100644 --- a/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp +++ b/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp @@ -1,4 +1,4 @@ -#include "../../../pimoroni-pico/libraries/breakout_ioexpander/breakout_ioexpander.hpp" +#include "../../../libraries/breakout_ioexpander/breakout_ioexpander.hpp" #define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) diff --git a/micropython/modules/breakout_mics6814/breakout_mics6814.cpp b/micropython/modules/breakout_mics6814/breakout_mics6814.cpp index 7ffc9800..6a744610 100644 --- a/micropython/modules/breakout_mics6814/breakout_mics6814.cpp +++ b/micropython/modules/breakout_mics6814/breakout_mics6814.cpp @@ -1,4 +1,4 @@ -#include "../../../pimoroni-pico/libraries/breakout_mics6814/breakout_mics6814.hpp" +#include "../../../libraries/breakout_mics6814/breakout_mics6814.hpp" #define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp index 99b5106b..fcae6661 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp @@ -1,4 +1,4 @@ -#include "../../../pimoroni-pico/libraries/breakout_potentiometer/breakout_potentiometer.hpp" +#include "../../../libraries/breakout_potentiometer/breakout_potentiometer.hpp" #define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) From 4b850b9290179d237189b5faa70b983038fce834 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Wed, 12 May 2021 20:03:50 +0100 Subject: [PATCH 15/27] Added micropython examples for Pot and Enc --- .../breakout_encoder/breakout_encoder.cpp | 8 +++ .../breakout_encoder/breakout_encoder.hpp | 2 + micropython/examples/breakout_encoder/demo.py | 55 +++++++++++++++++++ .../examples/breakout_potentiometer/demo.py | 45 +++++++++++++++ .../breakout_encoder/breakout_encoder.c | 4 ++ .../breakout_encoder/breakout_encoder.cpp | 12 ++++ .../breakout_encoder/breakout_encoder.h | 2 + 7 files changed, 128 insertions(+) create mode 100644 micropython/examples/breakout_encoder/demo.py create mode 100644 micropython/examples/breakout_potentiometer/demo.py diff --git a/libraries/breakout_encoder/breakout_encoder.cpp b/libraries/breakout_encoder/breakout_encoder.cpp index cc4cdd74..0882dd14 100644 --- a/libraries/breakout_encoder/breakout_encoder.cpp +++ b/libraries/breakout_encoder/breakout_encoder.cpp @@ -47,6 +47,14 @@ namespace pimoroni { void BreakoutEncoder::set_address(uint8_t address) { ioe.set_address(address); } + + bool BreakoutEncoder::get_interrupt_flag() { + return ioe.get_interrupt_flag(); + } + + void BreakoutEncoder::clear_interrupt_flag() { + ioe.clear_interrupt_flag(); + } BreakoutEncoder::Direction BreakoutEncoder::get_direction() { return direction; diff --git a/libraries/breakout_encoder/breakout_encoder.hpp b/libraries/breakout_encoder/breakout_encoder.hpp index f371a40e..7283a74b 100644 --- a/libraries/breakout_encoder/breakout_encoder.hpp +++ b/libraries/breakout_encoder/breakout_encoder.hpp @@ -78,6 +78,8 @@ namespace pimoroni { // Calls through to IOExpander class void set_address(uint8_t address); + bool get_interrupt_flag(); + void clear_interrupt_flag(); // Encoder breakout specific Direction get_direction(); diff --git a/micropython/examples/breakout_encoder/demo.py b/micropython/examples/breakout_encoder/demo.py new file mode 100644 index 00000000..c8337453 --- /dev/null +++ b/micropython/examples/breakout_encoder/demo.py @@ -0,0 +1,55 @@ +from breakout_encoder import BreakoutEncoder + +steps_per_rev = 24 + +enc = BreakoutEncoder() + +enc.set_brightness(1.0) +# enc.set_direction(BreakoutEncoder.DIRECTION_CCW) # Uncomment this to flip the direction + + +# From CPython Lib/colorsys.py +def hsv_to_rgb(h, s, v): + if s == 0.0: + return v, v, v + i = int(h * 6.0) + f = (h * 6.0) - i + p = v * (1.0 - s) + q = v * (1.0 - s * f) + t = v * (1.0 - s * (1.0 - f)) + i = i % 6 + if i == 0: + return v, t, p + if i == 1: + return q, v, p + if i == 2: + return p, v, t + if i == 3: + return p, q, v + if i == 4: + return t, p, v + if i == 5: + return v, p, q + + +def count_changed(count): + print("Count: ", count, sep="") + h = ((count % steps_per_rev) * 360.0) / steps_per_rev # Convert the count to a colour hue + r, g, b = [int(255 * c) for c in hsv_to_rgb(h / 360.0, 1.0, 1.0)] # rainbow magic + enc.set_led(r, g, b) + + +count = 0 + +count_changed(count) +enc.clear_interrupt_flag() + +while True: + if enc.get_interrupt_flag(): + count = enc.read() + enc.clear_interrupt_flag() + + while count < 0: + count += steps_per_rev + + count_changed(count) diff --git a/micropython/examples/breakout_potentiometer/demo.py b/micropython/examples/breakout_potentiometer/demo.py new file mode 100644 index 00000000..ec354b72 --- /dev/null +++ b/micropython/examples/breakout_potentiometer/demo.py @@ -0,0 +1,45 @@ +import time +from breakout_potentiometer import BreakoutPotentiometer + +pot = BreakoutPotentiometer() + +pot.set_brightness(1.0) +# pot.set_direction(BreakoutPotentiometer.DIRECTION_CCW) # Uncomment this to flip the direction + + +# From CPython Lib/colorsys.py +def hsv_to_rgb(h, s, v): + if s == 0.0: + return v, v, v + i = int(h * 6.0) + f = (h * 6.0) - i + p = v * (1.0 - s) + q = v * (1.0 - s * f) + t = v * (1.0 - s * (1.0 - f)) + i = i % 6 + if i == 0: + return v, t, p + if i == 1: + return q, v, p + if i == 2: + return p, v, t + if i == 3: + return p, q, v + if i == 4: + return t, p, v + if i == 5: + return v, p, q + + +val = 0 + +while True: + val = pot.read() + h = val * 240.0 # Colour range from red to blue + + r, g, b = [int(255 * c) for c in hsv_to_rgb(h / 360.0, 1.0, 1.0)] # rainbow magic + + print("Percent: ", int(val * 100), "%", sep="") + pot.set_led(r, g, b) + + time.sleep(0.02) diff --git a/micropython/modules/breakout_encoder/breakout_encoder.c b/micropython/modules/breakout_encoder/breakout_encoder.c index 8d6622cd..dd3973a5 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.c +++ b/micropython/modules/breakout_encoder/breakout_encoder.c @@ -6,6 +6,8 @@ /***** Methods *****/ MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoder_set_address_obj, 2, BreakoutEncoder_set_address); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoder_get_interrupt_flag_obj, BreakoutEncoder_get_interrupt_flag); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoder_clear_interrupt_flag_obj, BreakoutEncoder_clear_interrupt_flag); MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoder_get_direction_obj, BreakoutEncoder_get_direction); MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoder_set_direction_obj, 2, BreakoutEncoder_set_direction); MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoder_set_brightness_obj, 2, BreakoutEncoder_set_brightness); @@ -16,6 +18,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoder_read_obj, BreakoutEncoder_read); /***** Binding of Methods *****/ STATIC const mp_rom_map_elem_t BreakoutEncoder_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_set_address), MP_ROM_PTR(&BreakoutEncoder_set_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_interrupt_flag), MP_ROM_PTR(&BreakoutEncoder_get_interrupt_flag_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear_interrupt_flag), MP_ROM_PTR(&BreakoutEncoder_clear_interrupt_flag_obj) }, { MP_ROM_QSTR(MP_QSTR_get_direction), MP_ROM_PTR(&BreakoutEncoder_get_direction_obj) }, { MP_ROM_QSTR(MP_QSTR_set_direction), MP_ROM_PTR(&BreakoutEncoder_set_direction_obj) }, { MP_ROM_QSTR(MP_QSTR_set_brightness), MP_ROM_PTR(&BreakoutEncoder_set_brightness_obj) }, diff --git a/micropython/modules/breakout_encoder/breakout_encoder.cpp b/micropython/modules/breakout_encoder/breakout_encoder.cpp index 72a28253..e9ade1c0 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.cpp +++ b/micropython/modules/breakout_encoder/breakout_encoder.cpp @@ -127,6 +127,18 @@ mp_obj_t BreakoutEncoder_set_address(size_t n_args, const mp_obj_t *pos_args, mp return mp_const_none; } +mp_obj_t BreakoutEncoder_get_interrupt_flag(mp_obj_t self_in) { + breakout_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_encoder_BreakoutEncoder_obj_t); + return mp_obj_new_bool(self->breakout->get_interrupt_flag()); +} + +mp_obj_t BreakoutEncoder_clear_interrupt_flag(mp_obj_t self_in) { + breakout_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_encoder_BreakoutEncoder_obj_t); + self->breakout->clear_interrupt_flag(); + + return mp_const_none; +} + mp_obj_t BreakoutEncoder_get_direction(mp_obj_t self_in) { breakout_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_encoder_BreakoutEncoder_obj_t); return mp_obj_new_bool(self->breakout->get_direction()); diff --git a/micropython/modules/breakout_encoder/breakout_encoder.h b/micropython/modules/breakout_encoder/breakout_encoder.h index cfeca433..50c88e0a 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.h +++ b/micropython/modules/breakout_encoder/breakout_encoder.h @@ -8,6 +8,8 @@ extern const mp_obj_type_t breakout_encoder_BreakoutEncoder_type; extern void BreakoutEncoder_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); extern mp_obj_t BreakoutEncoder_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 BreakoutEncoder_set_address(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutEncoder_get_interrupt_flag(mp_obj_t self_in); +extern mp_obj_t BreakoutEncoder_clear_interrupt_flag(mp_obj_t self_in); extern mp_obj_t BreakoutEncoder_get_direction(mp_obj_t self_in); extern mp_obj_t BreakoutEncoder_set_direction(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t BreakoutEncoder_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); From fd3ef973b6bbf0442053ebe250839051393c83ca Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 12 May 2021 20:16:42 +0100 Subject: [PATCH 16/27] Fix MICS6814 heater enable, improve demo --- drivers/ioexpander/ioexpander.hpp | 1 + examples/breakout_mics6814/demo.cpp | 14 +++++++++----- libraries/breakout_mics6814/breakout_mics6814.cpp | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/ioexpander/ioexpander.hpp b/drivers/ioexpander/ioexpander.hpp index 75e67a81..0edaa369 100644 --- a/drivers/ioexpander/ioexpander.hpp +++ b/drivers/ioexpander/ioexpander.hpp @@ -38,6 +38,7 @@ namespace pimoroni { static const uint8_t PIN_IN_PULL_UP = PIN_MODE_PU; // 0b10000 static const uint8_t PIN_IN_PU = PIN_MODE_PU; // 0b10000 static const uint8_t PIN_OUT = PIN_MODE_PP; // 0b00001 + static const uint8_t PIN_OD = PIN_MODE_OD; // 0b00001 static const uint8_t PIN_PWM = PIN_MODE_PWM; // 0b00101 static const uint8_t PIN_ADC = PIN_MODE_ADC; // 0b01010 diff --git a/examples/breakout_mics6814/demo.cpp b/examples/breakout_mics6814/demo.cpp index 6d4d0c88..31a9de42 100644 --- a/examples/breakout_mics6814/demo.cpp +++ b/examples/breakout_mics6814/demo.cpp @@ -1,21 +1,25 @@ #include "pico/stdlib.h" +#include "stdio.h" #include "breakout_mics6814.hpp" using namespace pimoroni; -BreakoutMICS6814 ioe; +BreakoutMICS6814 mics6814; int main() { + stdio_init_all(); + gpio_init(PICO_DEFAULT_LED_PIN); gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); - ioe.init(); + mics6814.init(); + mics6814.set_heater(true); + mics6814.set_led(0, 0, 255); while(true) { - gpio_put(PICO_DEFAULT_LED_PIN, true); - sleep_ms(1000); - gpio_put(PICO_DEFAULT_LED_PIN, false); + BreakoutMICS6814::Reading reading = mics6814.read_all(); + printf("OX: %f Red: %f NH3: %f\n", reading.oxidising, reading.reducing, reading.nh3); sleep_ms(1000); } diff --git a/libraries/breakout_mics6814/breakout_mics6814.cpp b/libraries/breakout_mics6814/breakout_mics6814.cpp index 921f98c3..4b1c886c 100644 --- a/libraries/breakout_mics6814/breakout_mics6814.cpp +++ b/libraries/breakout_mics6814/breakout_mics6814.cpp @@ -12,7 +12,7 @@ namespace pimoroni { ioe.set_mode(MICS_NH3, IOExpander::PIN_ADC); ioe.set_mode(MICS_OX, IOExpander::PIN_ADC); - ioe.set_mode(MICS_HEATER_EN, IOExpander::PIN_OUT); + ioe.set_mode(MICS_HEATER_EN, IOExpander::PIN_OD); ioe.output(MICS_HEATER_EN, IOExpander::LOW); // Calculate a period large enough to get 0-255 steps at the desired brightness From 7202926fbbfec83462c981043cc289c9c220a75c Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 12 May 2021 21:10:34 +0100 Subject: [PATCH 17/27] Add mics6814 python demo --- .../breakout_mics6814/mics6814_demo.py | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 micropython/examples/breakout_mics6814/mics6814_demo.py diff --git a/micropython/examples/breakout_mics6814/mics6814_demo.py b/micropython/examples/breakout_mics6814/mics6814_demo.py new file mode 100644 index 00000000..b8af41c6 --- /dev/null +++ b/micropython/examples/breakout_mics6814/mics6814_demo.py @@ -0,0 +1,54 @@ +import time +from breakout_mics6814 import BreakoutMICS6814 + +OUTPUT_FREQUENCY = 0.5 + +gas = BreakoutMICS6814() + +gas.set_brightness(1.0) + + +# From CPython Lib/colorsys.py +def hsv_to_rgb(h, s, v): + if s == 0.0: + return v, v, v + i = int(h * 6.0) + f = (h * 6.0) - i + p = v * (1.0 - s) + q = v * (1.0 - s * f) + t = v * (1.0 - s * (1.0 - f)) + i = i % 6 + if i == 0: + return v, t, p + if i == 1: + return q, v, p + if i == 2: + return p, v, t + if i == 3: + return p, q, v + if i == 4: + return t, p, v + if i == 5: + return v, p, q + + +h = 0 + +last_output = time.time() + +while True: + oxd = gas.read_oxidising() + red = gas.read_reducing() + nh3 = gas.read_nh3() + + r, g, b = [int(255 * c) for c in hsv_to_rgb(h / 360.0, 1.0, 1.0)] # rainbow magic + + if time.time() - last_output > OUTPUT_FREQUENCY: + print("OX: {} Red: {} NH3: {}".format(oxd, red, nh3)) + last_output = time.time() + + gas.set_led(r, g, b) + + h += 1 + + time.sleep(0.02) From 370167f0f4f6634e68eaf685f209ea267d814919 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Wed, 12 May 2021 22:08:07 +0100 Subject: [PATCH 18/27] Renamed MICS demo file to match other breakouts --- .../examples/breakout_mics6814/{mics6814_demo.py => demo.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename micropython/examples/breakout_mics6814/{mics6814_demo.py => demo.py} (100%) diff --git a/micropython/examples/breakout_mics6814/mics6814_demo.py b/micropython/examples/breakout_mics6814/demo.py similarity index 100% rename from micropython/examples/breakout_mics6814/mics6814_demo.py rename to micropython/examples/breakout_mics6814/demo.py From e9a96ceb8a0cb1391e525a0da6b270aa8811d09f Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Wed, 12 May 2021 23:34:43 +0100 Subject: [PATCH 19/27] PicoExplorer C demos for Enc and Pot --- examples/CMakeLists.txt | 2 + examples/pico_enc_explorer/CMakeLists.txt | 12 ++ examples/pico_enc_explorer/demo.cpp | 127 ++++++++++++++++++++++ examples/pico_pot_explorer/CMakeLists.txt | 12 ++ examples/pico_pot_explorer/demo.cpp | 111 +++++++++++++++++++ 5 files changed, 264 insertions(+) create mode 100644 examples/pico_enc_explorer/CMakeLists.txt create mode 100644 examples/pico_enc_explorer/demo.cpp create mode 100644 examples/pico_pot_explorer/CMakeLists.txt create mode 100644 examples/pico_pot_explorer/demo.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 26b90865..9bdc4786 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -21,7 +21,9 @@ add_subdirectory(pico_display) add_subdirectory(pico_unicorn) add_subdirectory(pico_unicorn_plasma) add_subdirectory(pico_scroll) +add_subdirectory(pico_enc_explorer) add_subdirectory(pico_explorer) +add_subdirectory(pico_pot_explorer) add_subdirectory(pico_rgb_keypad) add_subdirectory(pico_rtc_display) add_subdirectory(pico_tof_display) diff --git a/examples/pico_enc_explorer/CMakeLists.txt b/examples/pico_enc_explorer/CMakeLists.txt new file mode 100644 index 00000000..a082bef9 --- /dev/null +++ b/examples/pico_enc_explorer/CMakeLists.txt @@ -0,0 +1,12 @@ +set(OUTPUT_NAME encoder_explorer) + +add_executable( + ${OUTPUT_NAME} + demo.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_encoder pico_explorer) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/pico_enc_explorer/demo.cpp b/examples/pico_enc_explorer/demo.cpp new file mode 100644 index 00000000..75250a30 --- /dev/null +++ b/examples/pico_enc_explorer/demo.cpp @@ -0,0 +1,127 @@ +#include "pico/stdlib.h" +#include +#include +#include +#include + +#include "pico_explorer.hpp" +#include "breakout_encoder.hpp" + +using namespace pimoroni; + +uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; +PicoExplorer pico_explorer(buffer); + +static const uint8_t STEPS_PER_REV = 24; + +BreakoutEncoder enc; +bool toggle = false; + +// HSV Conversion expects float inputs in the range of 0.00-1.00 for each channel +// Outputs are rgb in the range 0-255 for each channel +void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) { + float i = floor(h * 6.0f); + float f = h * 6.0f - i; + v *= 255.0f; + uint8_t p = v * (1.0f - s); + uint8_t q = v * (1.0f - f * s); + uint8_t t = v * (1.0f - (1.0f - f) * s); + + switch (int(i) % 6) { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + } +} + +void count_changed(int16_t count) { + printf("Count: %d\n", count); + float h = (count % STEPS_PER_REV) / (float)STEPS_PER_REV; + uint8_t r, g, b; + from_hsv(h, 1.0f, 1.0f, r, g, b); + enc.set_led(r, g, b); + + pico_explorer.set_pen(0, 0, 0); + pico_explorer.clear(); + + { + pico_explorer.set_pen(255, 0, 0); + std::ostringstream ss; + ss << "R = "; + ss << (int)r; + std::string s(ss.str()); + pico_explorer.text(s, Point(10, 10), 220, 6); + } + + { + pico_explorer.set_pen(0, 255, 0); + std::ostringstream ss; + ss << "G = "; + ss << (int)g; + std::string s(ss.str()); + pico_explorer.text(s, Point(10, 70), 220, 6); + } + + { + pico_explorer.set_pen(0, 0, 255); + std::ostringstream ss; + ss << "B = "; + ss << (int)b; + std::string s(ss.str()); + pico_explorer.text(s, Point(10, 130), 220, 6); + } + + { + pico_explorer.set_pen(r, g, b); + std::ostringstream ss; + ss << "#"; + ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)r; + ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)g; + ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)b; + std::string s(ss.str()); + pico_explorer.text(s, Point(10, 190), 220, 5); + } + pico_explorer.update(); +} + +int main() { + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + + stdio_init_all(); + + pico_explorer.init(); + pico_explorer.update(); + + int16_t count = 0; + if(enc.init()) { + printf("Encoder found...\n"); + + count_changed(count); + enc.clear_interrupt_flag(); + + while(true) { + gpio_put(PICO_DEFAULT_LED_PIN, toggle); + toggle = !toggle; + + if(enc.get_interrupt_flag()) { + count = enc.read(); + enc.clear_interrupt_flag(); + + while(count < 0) + count += STEPS_PER_REV; + + count_changed(count); + } + } + } + else { + printf("Encoder not found :'(\n"); + gpio_put(PICO_DEFAULT_LED_PIN, true); + } + + return 0; +} diff --git a/examples/pico_pot_explorer/CMakeLists.txt b/examples/pico_pot_explorer/CMakeLists.txt new file mode 100644 index 00000000..dc5649d4 --- /dev/null +++ b/examples/pico_pot_explorer/CMakeLists.txt @@ -0,0 +1,12 @@ +set(OUTPUT_NAME potentiometer_explorer) + +add_executable( + ${OUTPUT_NAME} + demo.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_potentiometer pico_explorer) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/pico_pot_explorer/demo.cpp b/examples/pico_pot_explorer/demo.cpp new file mode 100644 index 00000000..14752a3c --- /dev/null +++ b/examples/pico_pot_explorer/demo.cpp @@ -0,0 +1,111 @@ +#include "pico/stdlib.h" +#include +#include +#include +#include + +#include "pico_explorer.hpp" +#include "breakout_potentiometer.hpp" + +using namespace pimoroni; + +uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; +PicoExplorer pico_explorer(buffer); + +BreakoutPotentiometer pot; +bool toggle = false; + +// HSV Conversion expects float inputs in the range of 0.00-1.00 for each channel +// Outputs are rgb in the range 0-255 for each channel +void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) { + float i = floor(h * 6.0f); + float f = h * 6.0f - i; + v *= 255.0f; + uint8_t p = v * (1.0f - s); + uint8_t q = v * (1.0f - f * s); + uint8_t t = v * (1.0f - (1.0f - f) * s); + + switch (int(i) % 6) { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + } +} + +int main() { + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + + stdio_init_all(); + + pico_explorer.init(); + pico_explorer.update(); + + int16_t count = 0; + if(pot.init()) { + printf("Potentiometer found...\n"); + + while(true) { + gpio_put(PICO_DEFAULT_LED_PIN, toggle); + toggle = !toggle; + + float percent = pot.read(); + + printf("Percent: %d\n", (int)(percent * 100)); + uint8_t r, g, b; + from_hsv(percent, 1.0f, 1.0f, r, g, b); + pot.set_led(r, g, b); + + pico_explorer.set_pen(0, 0, 0); + pico_explorer.clear(); + + { + pico_explorer.set_pen(255, 0, 0); + std::ostringstream ss; + ss << "R = "; + ss << (int)r; + std::string s(ss.str()); + pico_explorer.text(s, Point(10, 10), 220, 6); + } + + { + pico_explorer.set_pen(0, 255, 0); + std::ostringstream ss; + ss << "G = "; + ss << (int)g; + std::string s(ss.str()); + pico_explorer.text(s, Point(10, 70), 220, 6); + } + + { + pico_explorer.set_pen(0, 0, 255); + std::ostringstream ss; + ss << "B = "; + ss << (int)b; + std::string s(ss.str()); + pico_explorer.text(s, Point(10, 130), 220, 6); + } + + { + pico_explorer.set_pen(r, g, b); + std::ostringstream ss; + ss << "#"; + ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)r; + ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)g; + ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (int)b; + std::string s(ss.str()); + pico_explorer.text(s, Point(10, 190), 220, 5); + } + pico_explorer.update(); + } + } + else { + printf("Encoder Potentiometer found :'(\n"); + gpio_put(PICO_DEFAULT_LED_PIN, true); + } + + return 0; +} From 151daf1c7b230471ecb34b70c0890e2166c03b89 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Wed, 12 May 2021 23:46:36 +0100 Subject: [PATCH 20/27] Standalone C demos for Enc and Pot --- examples/breakout_encoder/CMakeLists.txt | 4 ++ examples/breakout_encoder/demo.cpp | 67 +++++++++++++++++-- .../breakout_potentiometer/CMakeLists.txt | 4 ++ examples/breakout_potentiometer/demo.cpp | 51 ++++++++++++-- 4 files changed, 116 insertions(+), 10 deletions(-) diff --git a/examples/breakout_encoder/CMakeLists.txt b/examples/breakout_encoder/CMakeLists.txt index 46729be4..5cb31bfc 100644 --- a/examples/breakout_encoder/CMakeLists.txt +++ b/examples/breakout_encoder/CMakeLists.txt @@ -5,6 +5,10 @@ add_executable( demo.cpp ) +# enable usb output, disable uart output +pico_enable_stdio_usb(${OUTPUT_NAME} 1) +pico_enable_stdio_uart(${OUTPUT_NAME} 0) + # Pull in pico libraries that we need target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_encoder) diff --git a/examples/breakout_encoder/demo.cpp b/examples/breakout_encoder/demo.cpp index b8e0665d..ae57882f 100644 --- a/examples/breakout_encoder/demo.cpp +++ b/examples/breakout_encoder/demo.cpp @@ -1,22 +1,79 @@ #include "pico/stdlib.h" +#include +#include #include "breakout_encoder.hpp" using namespace pimoroni; +static const uint8_t STEPS_PER_REV = 24; + BreakoutEncoder enc; +bool toggle = false; + +// HSV Conversion expects float inputs in the range of 0.00-1.00 for each channel +// Outputs are rgb in the range 0-255 for each channel +void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) { + float i = floor(h * 6.0f); + float f = h * 6.0f - i; + v *= 255.0f; + uint8_t p = v * (1.0f - s); + uint8_t q = v * (1.0f - f * s); + uint8_t t = v * (1.0f - (1.0f - f) * s); + + switch (int(i) % 6) { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + } +} + +void count_changed(int16_t count) { + printf("Count: %d\n", count); + float h = (count % STEPS_PER_REV) / (float)STEPS_PER_REV; + uint8_t r, g, b; + from_hsv(h, 1.0f, 1.0f, r, g, b); + enc.set_led(r, g, b); +} int main() { gpio_init(PICO_DEFAULT_LED_PIN); gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); - enc.init(); + stdio_init_all(); - while(true) { + int16_t count = 0; + if(enc.init()) { + printf("Encoder found...\n"); + + //enc.set_direction(BreakoutEncoder::DIRECTION_CCW); // Uncomment this to flip the direction + + count_changed(count); + enc.clear_interrupt_flag(); + + while(true) { + gpio_put(PICO_DEFAULT_LED_PIN, toggle); + toggle = !toggle; + + if(enc.get_interrupt_flag()) { + count = enc.read(); + enc.clear_interrupt_flag(); + + while(count < 0) + count += STEPS_PER_REV; + + count_changed(count); + } + + sleep_ms(20); + } + } + else { + printf("Encoder not found :'(\n"); gpio_put(PICO_DEFAULT_LED_PIN, true); - sleep_ms(1000); - gpio_put(PICO_DEFAULT_LED_PIN, false); - sleep_ms(1000); } return 0; diff --git a/examples/breakout_potentiometer/CMakeLists.txt b/examples/breakout_potentiometer/CMakeLists.txt index edbf0709..e7067e04 100644 --- a/examples/breakout_potentiometer/CMakeLists.txt +++ b/examples/breakout_potentiometer/CMakeLists.txt @@ -5,6 +5,10 @@ add_executable( demo.cpp ) +# enable usb output, disable uart output +pico_enable_stdio_usb(${OUTPUT_NAME} 1) +pico_enable_stdio_uart(${OUTPUT_NAME} 0) + # Pull in pico libraries that we need target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_potentiometer) diff --git a/examples/breakout_potentiometer/demo.cpp b/examples/breakout_potentiometer/demo.cpp index a921bcb1..a7cf1c6e 100644 --- a/examples/breakout_potentiometer/demo.cpp +++ b/examples/breakout_potentiometer/demo.cpp @@ -1,22 +1,63 @@ #include "pico/stdlib.h" +#include +#include #include "breakout_potentiometer.hpp" using namespace pimoroni; BreakoutPotentiometer pot; +bool toggle = false; + +// HSV Conversion expects float inputs in the range of 0.00-1.00 for each channel +// Outputs are rgb in the range 0-255 for each channel +void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) { + float i = floor(h * 6.0f); + float f = h * 6.0f - i; + v *= 255.0f; + uint8_t p = v * (1.0f - s); + uint8_t q = v * (1.0f - f * s); + uint8_t t = v * (1.0f - (1.0f - f) * s); + + switch (int(i) % 6) { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + } +} int main() { gpio_init(PICO_DEFAULT_LED_PIN); gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); - pot.init(); + stdio_init_all(); - while(true) { + int16_t count = 0; + if(pot.init()) { + printf("Potentiometer found...\n"); + + //pot.set_direction(BreakoutPotentiometer::DIRECTION_CCW); // Uncomment this to flip the direction + + while(true) { + gpio_put(PICO_DEFAULT_LED_PIN, toggle); + toggle = !toggle; + + float percent = pot.read(); + + printf("Percent: %d\n", (int)(percent * 100)); + uint8_t r, g, b; + from_hsv(percent, 1.0f, 1.0f, r, g, b); + pot.set_led(r, g, b); + + sleep_ms(20); + } + } + else { + printf("Encoder Potentiometer found :'(\n"); gpio_put(PICO_DEFAULT_LED_PIN, true); - sleep_ms(1000); - gpio_put(PICO_DEFAULT_LED_PIN, false); - sleep_ms(1000); } return 0; From ef256e11736120acdffc415d67031cb1951c92ca Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Thu, 13 May 2021 12:13:41 +0100 Subject: [PATCH 21/27] Print text fix --- examples/breakout_potentiometer/demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/breakout_potentiometer/demo.cpp b/examples/breakout_potentiometer/demo.cpp index a7cf1c6e..2892f314 100644 --- a/examples/breakout_potentiometer/demo.cpp +++ b/examples/breakout_potentiometer/demo.cpp @@ -56,7 +56,7 @@ int main() { } } else { - printf("Encoder Potentiometer found :'(\n"); + printf("Potentiometer not found :'(\n"); gpio_put(PICO_DEFAULT_LED_PIN, true); } From 2f3c6fc8787d3dac9b91143f16b467d2d7aafcb2 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Thu, 13 May 2021 14:35:11 +0100 Subject: [PATCH 22/27] Added C++ examples for IOExpander --- examples/CMakeLists.txt | 1 + examples/breakout_ioexpander/CMakeLists.txt | 15 +---- .../breakout_ioexpander/adc/CMakeLists.txt | 16 +++++ examples/breakout_ioexpander/adc/adc.cpp | 42 +++++++++++++ .../breakout_ioexpander/button/CMakeLists.txt | 16 +++++ .../breakout_ioexpander/button/button.cpp | 49 +++++++++++++++ examples/breakout_ioexpander/demo.cpp | 23 ------- .../breakout_ioexpander/servo/CMakeLists.txt | 16 +++++ examples/breakout_ioexpander/servo/servo.cpp | 60 +++++++++++++++++++ 9 files changed, 203 insertions(+), 35 deletions(-) create mode 100644 examples/breakout_ioexpander/adc/CMakeLists.txt create mode 100644 examples/breakout_ioexpander/adc/adc.cpp create mode 100644 examples/breakout_ioexpander/button/CMakeLists.txt create mode 100644 examples/breakout_ioexpander/button/button.cpp delete mode 100644 examples/breakout_ioexpander/demo.cpp create mode 100644 examples/breakout_ioexpander/servo/CMakeLists.txt create mode 100644 examples/breakout_ioexpander/servo/servo.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 9bdc4786..03d9b7c5 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(breakout_dotmatrix) add_subdirectory(breakout_encoder) +add_subdirectory(breakout_ioexpander) add_subdirectory(breakout_ltr559) add_subdirectory(breakout_colourlcd160x80) add_subdirectory(breakout_roundlcd) diff --git a/examples/breakout_ioexpander/CMakeLists.txt b/examples/breakout_ioexpander/CMakeLists.txt index eeda7d77..a6c814cd 100644 --- a/examples/breakout_ioexpander/CMakeLists.txt +++ b/examples/breakout_ioexpander/CMakeLists.txt @@ -1,12 +1,3 @@ -set(OUTPUT_NAME ioexpander_demo) - -add_executable( - ${OUTPUT_NAME} - demo.cpp -) - -# Pull in pico libraries that we need -target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_ioexpander) - -# create map/bin/hex file etc. -pico_add_extra_outputs(${OUTPUT_NAME}) +add_subdirectory(adc) +add_subdirectory(button) +add_subdirectory(servo) \ No newline at end of file diff --git a/examples/breakout_ioexpander/adc/CMakeLists.txt b/examples/breakout_ioexpander/adc/CMakeLists.txt new file mode 100644 index 00000000..ecba6fa9 --- /dev/null +++ b/examples/breakout_ioexpander/adc/CMakeLists.txt @@ -0,0 +1,16 @@ +set(OUTPUT_NAME ioexpander_adc) + +add_executable( + ${OUTPUT_NAME} + adc.cpp +) + +# enable usb output, disable uart output +pico_enable_stdio_usb(${OUTPUT_NAME} 1) +pico_enable_stdio_uart(${OUTPUT_NAME} 0) + +# Pull in pico libraries that we need +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_ioexpander) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_ioexpander/adc/adc.cpp b/examples/breakout_ioexpander/adc/adc.cpp new file mode 100644 index 00000000..0e8de8ef --- /dev/null +++ b/examples/breakout_ioexpander/adc/adc.cpp @@ -0,0 +1,42 @@ +#include "pico/stdlib.h" +#include + +#include "breakout_ioexpander.hpp" + +using namespace pimoroni; + +static const uint8_t IOE_ADC_PIN = 10; + +BreakoutIOExpander ioe(0x18); +bool toggle = false; + +int main() { + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + + stdio_init_all(); + + if(ioe.init()) { + printf("IOExpander found...\n"); + + // ioe.set_adc_vref(5.0f); //Uncomment this if running the IOExpander off a 5V supply + ioe.set_mode(IOE_ADC_PIN, IOExpander::PIN_ADC); + + while(true) { + gpio_put(PICO_DEFAULT_LED_PIN, toggle); + toggle = !toggle; + + float voltage = ioe.input_as_voltage(IOE_ADC_PIN); + + printf("Voltage: %f\n", voltage); + + sleep_ms(20); + } + } + else { + printf("IOExpander not found :'(\n"); + gpio_put(PICO_DEFAULT_LED_PIN, true); + } + + return 0; +} diff --git a/examples/breakout_ioexpander/button/CMakeLists.txt b/examples/breakout_ioexpander/button/CMakeLists.txt new file mode 100644 index 00000000..c20a8f08 --- /dev/null +++ b/examples/breakout_ioexpander/button/CMakeLists.txt @@ -0,0 +1,16 @@ +set(OUTPUT_NAME ioexpander_button) + +add_executable( + ${OUTPUT_NAME} + button.cpp +) + +# enable usb output, disable uart output +pico_enable_stdio_usb(${OUTPUT_NAME} 1) +pico_enable_stdio_uart(${OUTPUT_NAME} 0) + +# Pull in pico libraries that we need +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_ioexpander) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_ioexpander/button/button.cpp b/examples/breakout_ioexpander/button/button.cpp new file mode 100644 index 00000000..03035c71 --- /dev/null +++ b/examples/breakout_ioexpander/button/button.cpp @@ -0,0 +1,49 @@ +#include "pico/stdlib.h" +#include + +#include "breakout_ioexpander.hpp" + +using namespace pimoroni; + +//Connect a button between this pin and ground +static const uint8_t IOE_BUTTON_PIN = 14; + +BreakoutIOExpander ioe(0x18); +bool last_state = true; + +int main() { + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + + stdio_init_all(); + + if(ioe.init()) { + printf("IOExpander found...\n"); + + ioe.set_mode(IOE_BUTTON_PIN, IOExpander::PIN_IN_PULL_UP); + + while(true) { + bool state = ioe.input(IOE_BUTTON_PIN); + if(state != last_state) { + if(state) { + printf("Button has been released\n"); + gpio_put(PICO_DEFAULT_LED_PIN, false); + } + else { + printf("Button has been pressed\n"); + gpio_put(PICO_DEFAULT_LED_PIN, true); + } + + last_state = state; + } + + sleep_ms(20); + } + } + else { + printf("IOExpander not found :'(\n"); + gpio_put(PICO_DEFAULT_LED_PIN, true); + } + + return 0; +} diff --git a/examples/breakout_ioexpander/demo.cpp b/examples/breakout_ioexpander/demo.cpp deleted file mode 100644 index d6477bf0..00000000 --- a/examples/breakout_ioexpander/demo.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "pico/stdlib.h" - -#include "breakout_ioexpander.hpp" - -using namespace pimoroni; - -BreakoutIOExpander ioe; - -int main() { - gpio_init(PICO_DEFAULT_LED_PIN); - gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); - - ioe.init(); - - while(true) { - gpio_put(PICO_DEFAULT_LED_PIN, true); - sleep_ms(1000); - gpio_put(PICO_DEFAULT_LED_PIN, false); - sleep_ms(1000); - } - - return 0; -} diff --git a/examples/breakout_ioexpander/servo/CMakeLists.txt b/examples/breakout_ioexpander/servo/CMakeLists.txt new file mode 100644 index 00000000..bb2bb7b7 --- /dev/null +++ b/examples/breakout_ioexpander/servo/CMakeLists.txt @@ -0,0 +1,16 @@ +set(OUTPUT_NAME ioexpander_servo) + +add_executable( + ${OUTPUT_NAME} + servo.cpp +) + +# enable usb output, disable uart output +pico_enable_stdio_usb(${OUTPUT_NAME} 1) +pico_enable_stdio_uart(${OUTPUT_NAME} 0) + +# Pull in pico libraries that we need +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_ioexpander) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_ioexpander/servo/servo.cpp b/examples/breakout_ioexpander/servo/servo.cpp new file mode 100644 index 00000000..860cb17f --- /dev/null +++ b/examples/breakout_ioexpander/servo/servo.cpp @@ -0,0 +1,60 @@ +#include "pico/stdlib.h" +#include +#include + +#include "breakout_ioexpander.hpp" + +using namespace pimoroni; + +static const uint8_t IOE_SERVO_PIN = 1; + +// Settings to produce a 50Hz output from the 24MHz clock. +// 24,000,000 Hz / 8 = 3,000,000 Hz +// 3,000,000 Hz / 60,000 Period = 50 Hz +static const uint8_t DIVIDER = 8; +static const uint16_t PERIOD = 60000; +static constexpr float CYCLE_TIME = 5.0f; +static constexpr float SERVO_RANGE = 1000.0f; // Between 1000 and 2000us (1-2ms) + +BreakoutIOExpander ioe(0x18); +bool toggle = false; + +int main() { + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + + stdio_init_all(); + + if(ioe.init()) { + printf("IOExpander found...\n"); + + ioe.set_pwm_period(PERIOD); + ioe.set_pwm_control(DIVIDER); + + ioe.set_mode(IOE_SERVO_PIN, IOExpander::PIN_PWM); + + while(true) { + gpio_put(PICO_DEFAULT_LED_PIN, toggle); + toggle = !toggle; + + absolute_time_t at = get_absolute_time(); + float t = to_us_since_boot(at) / 1000000.0f; + float s = sinf((t * M_PI * 2.0f) / CYCLE_TIME) / 2.0f; + float servo_us = 1500.0f + (s * SERVO_RANGE); + + float duty_per_microsecond = (float)PERIOD / (float)(20 * 1000); // Default is 3 LSB per microsecond + + uint16_t duty_cycle = (uint16_t)(roundf(servo_us * duty_per_microsecond)); + printf("Cycle Time: %.2f, Pulse: %.1fus, Duty Cycle: %d\n", fmodf(t, CYCLE_TIME), servo_us, duty_cycle); + ioe.output(IOE_SERVO_PIN, duty_cycle); + + sleep_ms(20); + } + } + else { + printf("IOExpander not found :'(\n"); + gpio_put(PICO_DEFAULT_LED_PIN, true); + } + + return 0; +} From 7eb8197e4599203071a575673de8ed68ea2482e3 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Thu, 13 May 2021 15:30:18 +0100 Subject: [PATCH 23/27] Added micropython examples for IOExpander --- .../examples/breakout_ioexpander/adc.py | 14 ++++++++ .../examples/breakout_ioexpander/button.py | 21 +++++++++++ .../examples/breakout_ioexpander/servo.py | 35 +++++++++++++++++++ .../breakout_ioexpander/breakout_ioexpander.c | 13 ++++--- .../breakout_ioexpander.cpp | 2 +- .../breakout_ioexpander/breakout_ioexpander.h | 19 ++++++---- 6 files changed, 93 insertions(+), 11 deletions(-) create mode 100644 micropython/examples/breakout_ioexpander/adc.py create mode 100644 micropython/examples/breakout_ioexpander/button.py create mode 100644 micropython/examples/breakout_ioexpander/servo.py diff --git a/micropython/examples/breakout_ioexpander/adc.py b/micropython/examples/breakout_ioexpander/adc.py new file mode 100644 index 00000000..290a83ba --- /dev/null +++ b/micropython/examples/breakout_ioexpander/adc.py @@ -0,0 +1,14 @@ +import time +from breakout_ioexpander import BreakoutIOExpander + +ioe_adc_pin = 10 + +ioe = BreakoutIOExpander(0x18) + +ioe.set_mode(ioe_adc_pin, BreakoutIOExpander.PIN_ADC) + +while True: + voltage = ioe.input_as_voltage(ioe_adc_pin) + print("Voltage: ", voltage, sep="") + + time.sleep(0.02) diff --git a/micropython/examples/breakout_ioexpander/button.py b/micropython/examples/breakout_ioexpander/button.py new file mode 100644 index 00000000..2c9eef6c --- /dev/null +++ b/micropython/examples/breakout_ioexpander/button.py @@ -0,0 +1,21 @@ +import time +from breakout_ioexpander import BreakoutIOExpander + +ioe_button_pin = 14 + +ioe = BreakoutIOExpander(0x18) + +ioe.set_mode(ioe_button_pin, BreakoutIOExpander.PIN_IN_PU) + +last_state = True + +while True: + state = ioe.input(ioe_button_pin) + if state != last_state: + if state == True: + print("Button has been released") + else: + print("Button has been pressed") + last_state = state + + time.sleep(0.02) diff --git a/micropython/examples/breakout_ioexpander/servo.py b/micropython/examples/breakout_ioexpander/servo.py new file mode 100644 index 00000000..7ca012fc --- /dev/null +++ b/micropython/examples/breakout_ioexpander/servo.py @@ -0,0 +1,35 @@ +import time +import math +from breakout_ioexpander import BreakoutIOExpander + +ioe_servo_pin = 1 + +# Settings to produce a 50Hz output from the 24MHz clock. +# 24,000,000 Hz / 8 = 3,000,000 Hz +# 3,000,000 Hz / 60,000 Period = 50 Hz +divider = 8 +period = 60000 +cycle_time = 5.0 +servo_range = 1000.0 # Between 1000 and 2000us (1-2ms) + +ioe = BreakoutIOExpander(0x18) + +ioe.set_pwm_period(period) +ioe.set_pwm_control(divider) + +ioe.set_mode(ioe_servo_pin, BreakoutIOExpander.PIN_PWM) + +t = 0 + +while True: + s = math.sin((t * math.pi * 2.0) / cycle_time) / 2.0 + servo_us = 1500.0 + (s * servo_range) + + duty_per_microsecond = period / (20 * 1000) # Default is 3 LSB per microsecond + + duty_cycle = round(servo_us * duty_per_microsecond) + print("Cycle Time: ", t % cycle_time, ", Pulse: ", servo_us, ", Duty Cycle: ", duty_cycle, sep="") + ioe.output(ioe_servo_pin, duty_cycle) + + time.sleep(0.02) + t += 0.02 diff --git a/micropython/modules/breakout_ioexpander/breakout_ioexpander.c b/micropython/modules/breakout_ioexpander/breakout_ioexpander.c index 368ea75b..3ee8e6e4 100644 --- a/micropython/modules/breakout_ioexpander/breakout_ioexpander.c +++ b/micropython/modules/breakout_ioexpander/breakout_ioexpander.c @@ -50,10 +50,15 @@ STATIC const mp_rom_map_elem_t BreakoutIOExpander_locals_dict_table[] = { { 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) }, + { MP_ROM_QSTR(MP_QSTR_PIN_IN), MP_ROM_INT(IOE_PIN_IN) }, + { MP_ROM_QSTR(MP_QSTR_PIN_IN_PU), MP_ROM_INT(IOE_PIN_IN_PU) }, + { MP_ROM_QSTR(MP_QSTR_PIN_OUT), MP_ROM_INT(IOE_PIN_OUT) }, + { MP_ROM_QSTR(MP_QSTR_PIN_OD), MP_ROM_INT(IOE_PIN_OD) }, + { MP_ROM_QSTR(MP_QSTR_PIN_PWM), MP_ROM_INT(IOE_PIN_PWM) }, + { MP_ROM_QSTR(MP_QSTR_PIN_ADC), MP_ROM_INT(IOE_PIN_ADC) }, + { MP_ROM_QSTR(MP_QSTR_NUM_PINS), MP_ROM_INT(IOE_NUM_PINS) }, + { MP_ROM_QSTR(MP_QSTR_LOW), MP_ROM_INT(IOE_LOW) }, + { MP_ROM_QSTR(MP_QSTR_HIGH), MP_ROM_INT(IOE_HIGH) }, }; STATIC MP_DEFINE_CONST_DICT(BreakoutIOExpander_locals_dict, BreakoutIOExpander_locals_dict_table); diff --git a/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp b/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp index ad733ed5..c31ed4fb 100644 --- a/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp +++ b/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp @@ -401,7 +401,7 @@ mp_obj_t BreakoutIOExpander_output(size_t n_args, const mp_obj_t *pos_args, mp_m { 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_QSTR_load, MP_ARG_BOOL, {.u_bool = true} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; diff --git a/micropython/modules/breakout_ioexpander/breakout_ioexpander.h b/micropython/modules/breakout_ioexpander/breakout_ioexpander.h index 6bec8472..7d8a48e7 100644 --- a/micropython/modules/breakout_ioexpander/breakout_ioexpander.h +++ b/micropython/modules/breakout_ioexpander/breakout_ioexpander.h @@ -1,12 +1,19 @@ // Include MicroPython API. #include "py/runtime.h" -// enum { -// REF = 0, -// REDUCING, -// NH3, -// OXIDISING -// }; +enum { + IOE_PIN_IN = 0b00010, + IOE_PIN_IN_PU = 0b10000, + IOE_PIN_OUT = 0b00001, + IOE_PIN_OD = 0b00011, + IOE_PIN_PWM = 0b00101, + IOE_PIN_ADC = 0b01010, + + IOE_NUM_PINS = 14, + + IOE_LOW = 0, + IOE_HIGH = 1, +}; /***** Extern of Class Definition *****/ extern const mp_obj_type_t breakout_ioexpander_BreakoutIOExpander_type; From 524e59029830f9f7f1a0884a97f6c6a398d427e4 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Thu, 13 May 2021 15:33:39 +0100 Subject: [PATCH 24/27] Removed old test cases for IOExpander --- examples/CMakeLists.txt | 5 - examples/ioe_adc_bg/CMakeLists.txt | 14 -- examples/ioe_adc_bg/ioe_adc_bg.cpp | 177 ------------------ examples/ioe_adc_min_case/CMakeLists.txt | 14 -- .../ioe_adc_min_case/ioe_adc_min_case.cpp | 48 ----- examples/ioe_bg/CMakeLists.txt | 14 -- examples/ioe_bg/ioe_bg.cpp | 176 ----------------- examples/ioe_enc_min_case/CMakeLists.txt | 14 -- .../ioe_enc_min_case/ioe_enc_min_case.cpp | 57 ------ 9 files changed, 519 deletions(-) delete mode 100644 examples/ioe_adc_bg/CMakeLists.txt delete mode 100644 examples/ioe_adc_bg/ioe_adc_bg.cpp delete mode 100644 examples/ioe_adc_min_case/CMakeLists.txt delete mode 100644 examples/ioe_adc_min_case/ioe_adc_min_case.cpp delete mode 100644 examples/ioe_bg/CMakeLists.txt delete mode 100644 examples/ioe_bg/ioe_bg.cpp delete mode 100644 examples/ioe_enc_min_case/CMakeLists.txt delete mode 100644 examples/ioe_enc_min_case/ioe_enc_min_case.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 03d9b7c5..18bb4c93 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -13,11 +13,6 @@ add_subdirectory(breakout_sgp30) add_subdirectory(breakout_colourlcd240x240) add_subdirectory(breakout_msa301) -add_subdirectory(ioe_adc_bg) -add_subdirectory(ioe_adc_min_case) -add_subdirectory(ioe_bg) -add_subdirectory(ioe_enc_min_case) - add_subdirectory(pico_display) add_subdirectory(pico_unicorn) add_subdirectory(pico_unicorn_plasma) diff --git a/examples/ioe_adc_bg/CMakeLists.txt b/examples/ioe_adc_bg/CMakeLists.txt deleted file mode 100644 index 3ab39235..00000000 --- a/examples/ioe_adc_bg/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -add_executable( - ioe_adc_bg - ioe_adc_bg.cpp -) - -# Pull in pico libraries that we need -target_link_libraries(ioe_adc_bg pico_stdlib pico_explorer ioexpander) - -# disable usb output, enable uart output -pico_enable_stdio_usb(ioe_adc_bg 0) -pico_enable_stdio_uart(ioe_adc_bg 1) - -# create map/bin/hex file etc. -pico_add_extra_outputs(ioe_adc_bg) diff --git a/examples/ioe_adc_bg/ioe_adc_bg.cpp b/examples/ioe_adc_bg/ioe_adc_bg.cpp deleted file mode 100644 index a2b06091..00000000 --- a/examples/ioe_adc_bg/ioe_adc_bg.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "pico/stdlib.h" - -#include "pico_explorer.hpp" -#include "ioexpander.hpp" - -static const uint8_t PIN_RED = 1; -static const uint8_t PIN_GREEN = 7; -static const uint8_t PIN_BLUE = 2; - -static const uint8_t PIN_TERM_A = 12; -static const uint8_t PIN_TERM_B = 3; -static const uint8_t PIN_INPUT = 11; - -static const bool INVERT_OUTPUT = true; //true for common cathode, false for common anode - -using namespace pimoroni; - -uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; -PicoExplorer pico_explorer(buffer); - -IOExpander ioe(0x0e); -bool toggle = false; - -void HSVtoRGB(float hue, float sat, float val, uint8_t& rOut, uint8_t& gOut, uint8_t& bOut) -{ - //////////////////////////////// - // Convert HSV values to RGB - // H(Hue): 0-360 degrees - // S(Saturation): 0-100 percent - // V(Value): 0-100 percent - // - // RGB out is in range 0->255. - // This method was found at: - // https://www.codespeedy.com/hsv-to-rgb-in-cpp/ - //////////////////////////////// - if(hue > 360.0f || hue < 0.0f || sat > 100.0f || sat < 0.0f || val > 100.0f || val < 0.0f) { - //The given HSV values are not in valid range - rOut = 0; - gOut = 0; - bOut = 0; - return; - } - - float s = sat / 100.0f; - float v = val / 100.0f; - float c = s * v; - float x = c * (1.0f - fabsf(fmodf(hue / 60.0f, 2.0f) - 1.0f)); - float m = v - c; - - float r, g, b; - if(hue >= 0.0f && hue < 60.0f) - r = c, g = x, b = 0.0f; - else if(hue >= 60.0f && hue < 120.0f) - r = x, g = c, b = 0.0f; - else if(hue >= 120.0f && hue < 180.0f) - r = 0.0f, g = c, b = x; - else if(hue >= 180.0f && hue < 240.0f) - r = 0.0f, g = x, b = c; - else if(hue >= 240.0f && hue < 300.0f) - r = x, g = 0.0f, b = c; - else - r = c, g = 0.0f, b = x; - - rOut = (uint8_t)((r + m) * 255.0f); - gOut = (uint8_t)((g + m) * 255.0f); - bOut = (uint8_t)((b + m) * 255.0f); -} - -int main() { - pico_explorer.init(); - pico_explorer.update(); - stdio_init_all(); - - sleep_ms(5000); - - const uint LED_PIN = 25; - gpio_init(LED_PIN); - gpio_set_dir(LED_PIN, GPIO_OUT); - - const uint DBG_PIN = 26; - gpio_init(DBG_PIN); - gpio_set_dir(DBG_PIN, GPIO_OUT); - - float brightness = 1.0f; - - int16_t count = 0; - if(ioe.init()) { - printf("IOExpander found...\n"); - - ioe.set_mode(PIN_TERM_A, IOExpander::PIN_OUT); - ioe.set_mode(PIN_TERM_B, IOExpander::PIN_OUT); - ioe.set_mode(PIN_INPUT, IOExpander::PIN_ADC); - - ioe.output(PIN_TERM_A, 0); - ioe.output(PIN_TERM_B, 1); - - //Calculate a period large enough to get 0-255 steps at the desired brightness - unsigned int period = (unsigned int)(255.0f / brightness); - - ioe.set_pwm_period(period); - ioe.set_pwm_control(2); //PWM as fast as we can to avoid LED flicker - - ioe.set_mode(PIN_RED, IOExpander::PIN_PWM, false, INVERT_OUTPUT); - ioe.set_mode(PIN_GREEN, IOExpander::PIN_PWM, false, INVERT_OUTPUT); - ioe.set_mode(PIN_BLUE, IOExpander::PIN_PWM, false, INVERT_OUTPUT); - - sleep_ms(1000); - - while (true) { - gpio_put(LED_PIN, toggle); - toggle = !toggle; - - float analog = ioe.input_as_voltage(PIN_INPUT) / ioe.get_adc_vref(); - - float h = (analog * 240.0f); - uint8_t r, g, b; - HSVtoRGB(h, 100.0f, 100.0f, r, g, b); - - ioe.output(PIN_RED, r, false); //Hold off pwm load until the last - ioe.output(PIN_GREEN, g, false); //Hold off pwm load until the last - ioe.output(PIN_BLUE, b); //Loads all 3 pwms - - - - pico_explorer.set_pen(0, 0, 0); - pico_explorer.clear(); - - { - pico_explorer.set_pen(255, 0, 0); - std::ostringstream ss; - ss << "R = "; - ss << (int)r; - std::string s(ss.str()); - pico_explorer.text(s, Point(10, 10), 220, 6); - } - - { - pico_explorer.set_pen(0, 255, 0); - std::ostringstream ss; - ss << "G = "; - ss << (int)g; - std::string s(ss.str()); - pico_explorer.text(s, Point(10, 70), 220, 6); - } - - { - pico_explorer.set_pen(0, 0, 255); - std::ostringstream ss; - ss << "B = "; - ss << (int)b; - std::string s(ss.str()); - pico_explorer.text(s, Point(10, 130), 220, 6); - } - pico_explorer.update(); - - sleep_ms(10); - } - } - else { - printf("IOExpander not found :'(\n"); - - while(true) { - gpio_put(LED_PIN, 1); - sleep_ms(250); - gpio_put(LED_PIN, 0); - sleep_ms(250); - } - } - - return 0; -} diff --git a/examples/ioe_adc_min_case/CMakeLists.txt b/examples/ioe_adc_min_case/CMakeLists.txt deleted file mode 100644 index 018c1307..00000000 --- a/examples/ioe_adc_min_case/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -add_executable( - ioe_adc_min_case - ioe_adc_min_case.cpp -) - -# Pull in pico libraries that we need -target_link_libraries(ioe_adc_min_case pico_stdlib ioexpander) - -# disable usb output, enable uart output -pico_enable_stdio_usb(ioe_adc_min_case 1) -pico_enable_stdio_uart(ioe_adc_min_case 0) - -# create map/bin/hex file etc. -pico_add_extra_outputs(ioe_adc_min_case) diff --git a/examples/ioe_adc_min_case/ioe_adc_min_case.cpp b/examples/ioe_adc_min_case/ioe_adc_min_case.cpp deleted file mode 100644 index 0c0b27fc..00000000 --- a/examples/ioe_adc_min_case/ioe_adc_min_case.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include "pico/stdlib.h" -#include "ioexpander.hpp" - -static const uint8_t PIN_TERM_A = 12; -static const uint8_t PIN_TERM_B = 3; -static const uint8_t PIN_INPUT = 11; - -using namespace pimoroni; - -IOExpander ioe(0x0e); - -int main() { - stdio_init_all(); - - sleep_ms(5000); //Delay to give chance to connect terminal - - const uint LED_PIN = 25; - gpio_init(LED_PIN); - gpio_set_dir(LED_PIN, GPIO_OUT); - - if(ioe.init()) { - printf("IOExpander found...\n"); - - ioe.set_mode(PIN_TERM_A, IOExpander::PIN_OUT); - ioe.set_mode(PIN_TERM_B, IOExpander::PIN_OUT); - ioe.set_mode(PIN_INPUT, IOExpander::PIN_ADC); - - ioe.output(PIN_TERM_A, 0); - ioe.output(PIN_TERM_B, 1); - - bool toggle = false; - while(true) { - gpio_put(LED_PIN, toggle); - toggle = !toggle; - - printf("%d\n", ioe.input(PIN_INPUT)); - - sleep_ms(20); - } - } - else { - printf("IOExpander not found :'(\n"); - gpio_put(LED_PIN, 1); - } - - return 0; -} diff --git a/examples/ioe_bg/CMakeLists.txt b/examples/ioe_bg/CMakeLists.txt deleted file mode 100644 index 1dc5901d..00000000 --- a/examples/ioe_bg/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -add_executable( - ioe_bg - ioe_bg.cpp -) - -# Pull in pico libraries that we need -target_link_libraries(ioe_bg pico_stdlib pico_explorer ioexpander) - -# disable usb output, enable uart output -pico_enable_stdio_usb(ioe_bg 0) -pico_enable_stdio_uart(ioe_bg 1) - -# create map/bin/hex file etc. -pico_add_extra_outputs(ioe_bg) diff --git a/examples/ioe_bg/ioe_bg.cpp b/examples/ioe_bg/ioe_bg.cpp deleted file mode 100644 index ba983ccf..00000000 --- a/examples/ioe_bg/ioe_bg.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "pico/stdlib.h" - -#include "pico_explorer.hpp" -#include "ioexpander.hpp" - -static const uint8_t PIN_RED = 1; -static const uint8_t PIN_GREEN = 7; -static const uint8_t PIN_BLUE = 2; - -static const uint8_t PIN_ENC_A = 12; -static const uint8_t PIN_ENC_B = 3; -static const uint8_t PIN_ENC_C = 11; - -static const uint8_t ENC_CHANNEL = 1; - -static const bool INVERT_OUTPUT = true; //true for common cathode, false for common anode - -using namespace pimoroni; - -uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; -PicoExplorer pico_explorer(buffer); - -IOExpander ioe(0x0f); -bool toggle = false; - -void HSVtoRGB(float hue, float sat, float val, uint8_t& rOut, uint8_t& gOut, uint8_t& bOut) -{ - //////////////////////////////// - // Convert HSV values to RGB - // H(Hue): 0-360 degrees - // S(Saturation): 0-100 percent - // V(Value): 0-100 percent - // - // RGB out is in range 0->255. - // This method was found at: - // https://www.codespeedy.com/hsv-to-rgb-in-cpp/ - //////////////////////////////// - if(hue > 360.0f || hue < 0.0f || sat > 100.0f || sat < 0.0f || val > 100.0f || val < 0.0f) { - //The given HSV values are not in valid range - rOut = 0; - gOut = 0; - bOut = 0; - return; - } - - float s = sat / 100.0f; - float v = val / 100.0f; - float c = s * v; - float x = c * (1.0f - fabsf(fmodf(hue / 60.0f, 2.0f) - 1.0f)); - float m = v - c; - - float r, g, b; - if(hue >= 0.0f && hue < 60.0f) - r = c, g = x, b = 0.0f; - else if(hue >= 60.0f && hue < 120.0f) - r = x, g = c, b = 0.0f; - else if(hue >= 120.0f && hue < 180.0f) - r = 0.0f, g = c, b = x; - else if(hue >= 180.0f && hue < 240.0f) - r = 0.0f, g = x, b = c; - else if(hue >= 240.0f && hue < 300.0f) - r = x, g = 0.0f, b = c; - else - r = c, g = 0.0f, b = x; - - rOut = (uint8_t)((r + m) * 255.0f); - gOut = (uint8_t)((g + m) * 255.0f); - bOut = (uint8_t)((b + m) * 255.0f); -} - -int main() { - pico_explorer.init(); - pico_explorer.update(); - stdio_init_all(); - - sleep_ms(5000); - - const uint LED_PIN = 25; - gpio_init(LED_PIN); - gpio_set_dir(LED_PIN, GPIO_OUT); - - const uint DBG_PIN = 26; - gpio_init(DBG_PIN); - gpio_set_dir(DBG_PIN, GPIO_OUT); - - float brightness = 1.0f; - - int16_t count = 0; - if(ioe.init()) { - printf("IOExpander found...\n"); - - ioe.setup_rotary_encoder(ENC_CHANNEL, PIN_ENC_A, PIN_ENC_B, PIN_ENC_C); - - //Calculate a period large enough to get 0-255 steps at the desired brightness - unsigned int period = (unsigned int)(255.0f / brightness); - - ioe.set_pwm_period(period); - ioe.set_pwm_control(2); //PWM as fast as we can to avoid LED flicker - - ioe.set_mode(PIN_RED, IOExpander::PIN_PWM, false, INVERT_OUTPUT); - ioe.set_mode(PIN_GREEN, IOExpander::PIN_PWM, false, INVERT_OUTPUT); - ioe.set_mode(PIN_BLUE, IOExpander::PIN_PWM, false, INVERT_OUTPUT); - - sleep_ms(1000); - - while(true) { - gpio_put(LED_PIN, toggle); - toggle = !toggle; - - if(ioe.get_interrupt_flag() > 0) { //This should work but - gpio_put(DBG_PIN, 1); - count = ioe.read_rotary_encoder(ENC_CHANNEL); - ioe.clear_interrupt_flag(); - gpio_put(DBG_PIN, 0); - } - - while(count < 0) - count += 24; - - float h = ((float)(count % 24) * 360.0f) / 24.0f; - uint8_t r, g, b; - HSVtoRGB(h, 100.0f, 100.0f, r, g, b); - - ioe.output(PIN_RED, r, false); //Hold off pwm load until the last - ioe.output(PIN_GREEN, g, false); //Hold off pwm load until the last - ioe.output(PIN_BLUE, b); //Loads all 3 pwms - - - - pico_explorer.set_pen(0, 0, 0); - pico_explorer.clear(); - - { - pico_explorer.set_pen(255, 0, 0); - std::ostringstream ss; - ss << "R = "; - ss << (int)r; - std::string s(ss.str()); - pico_explorer.text(s, Point(10, 10), 220, 6); - } - - { - pico_explorer.set_pen(0, 255, 0); - std::ostringstream ss; - ss << "G = "; - ss << (int)g; - std::string s(ss.str()); - pico_explorer.text(s, Point(10, 70), 220, 6); - } - - { - pico_explorer.set_pen(0, 0, 255); - std::ostringstream ss; - ss << "B = "; - ss << (int)b; - std::string s(ss.str()); - pico_explorer.text(s, Point(10, 130), 220, 6); - } - pico_explorer.update(); - - sleep_ms(10); - } - } - else { - printf("IOExpander not found :'(\n"); - gpio_put(LED_PIN, 1); - } - - return 0; -} diff --git a/examples/ioe_enc_min_case/CMakeLists.txt b/examples/ioe_enc_min_case/CMakeLists.txt deleted file mode 100644 index 9cc97ae3..00000000 --- a/examples/ioe_enc_min_case/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -add_executable( - ioe_enc_min_case - ioe_enc_min_case.cpp -) - -# Pull in pico libraries that we need -target_link_libraries(ioe_enc_min_case pico_stdlib ioexpander) - -# disable usb output, enable uart output -pico_enable_stdio_usb(ioe_enc_min_case 1) -pico_enable_stdio_uart(ioe_enc_min_case 0) - -# create map/bin/hex file etc. -pico_add_extra_outputs(ioe_enc_min_case) diff --git a/examples/ioe_enc_min_case/ioe_enc_min_case.cpp b/examples/ioe_enc_min_case/ioe_enc_min_case.cpp deleted file mode 100644 index 1b1c2eab..00000000 --- a/examples/ioe_enc_min_case/ioe_enc_min_case.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include "pico/stdlib.h" -#include "ioexpander.hpp" - -static const uint8_t PIN_ENC_A = 12; -static const uint8_t PIN_ENC_B = 3; -static const uint8_t PIN_ENC_C = 11; - -static const uint8_t ENC_CHANNEL = 1; - -using namespace pimoroni; - -IOExpander ioe(0x0f); - -int main() { - stdio_init_all(); - - sleep_ms(5000); //Delay to give chance to connect terminal - - const uint LED_PIN = 25; - gpio_init(LED_PIN); - gpio_set_dir(LED_PIN, GPIO_OUT); - - if(ioe.init()) { - printf("IOExpander found...\n"); - - ioe.setup_rotary_encoder(ENC_CHANNEL, PIN_ENC_A, PIN_ENC_B, PIN_ENC_C); - - bool toggle = false; - int16_t count = 0; - while(true) { - gpio_put(LED_PIN, toggle); - toggle = !toggle; - - //Polling encoder directly works - //printf("%d\n", ioe.read_rotary_encoder(ENC_CHANNEL)); - - //Only reading encoder when the interrupt pin changes does not. - if(ioe.get_interrupt_flag()) { - printf("new count: "); - count = ioe.read_rotary_encoder(ENC_CHANNEL); - ioe.clear_interrupt_flag(); - } - - printf("%d\n", count); - - - sleep_ms(20); - } - } - else { - printf("IOExpander not found :'(\n"); - gpio_put(LED_PIN, 1); - } - - return 0; -} From 707aeba5aace3524e1bba3307a462fcc221a1cc4 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Thu, 13 May 2021 15:38:00 +0100 Subject: [PATCH 25/27] MP linting fix --- micropython/examples/breakout_ioexpander/button.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/micropython/examples/breakout_ioexpander/button.py b/micropython/examples/breakout_ioexpander/button.py index 2c9eef6c..624306a6 100644 --- a/micropython/examples/breakout_ioexpander/button.py +++ b/micropython/examples/breakout_ioexpander/button.py @@ -11,8 +11,8 @@ last_state = True while True: state = ioe.input(ioe_button_pin) - if state != last_state: - if state == True: + if state is not last_state: + if state: print("Button has been released") else: print("Button has been pressed") From 0c34de23f53ec23ea852560d873fbce65a09d949 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 14 May 2021 12:49:48 +0100 Subject: [PATCH 26/27] Tidy up include paths --- libraries/breakout_encoder/breakout_encoder.hpp | 2 +- libraries/breakout_ioexpander/breakout_ioexpander.hpp | 2 +- libraries/breakout_mics6814/breakout_mics6814.hpp | 2 +- libraries/breakout_msa301/breakout_msa301.hpp | 2 +- libraries/breakout_potentiometer/breakout_potentiometer.hpp | 2 +- micropython/modules/breakout_encoder/breakout_encoder.cpp | 2 +- micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp | 2 +- micropython/modules/breakout_mics6814/breakout_mics6814.cpp | 2 +- micropython/modules/breakout_msa301/breakout_msa301.cpp | 2 +- .../modules/breakout_potentiometer/breakout_potentiometer.cpp | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/breakout_encoder/breakout_encoder.hpp b/libraries/breakout_encoder/breakout_encoder.hpp index 7283a74b..e85099d8 100644 --- a/libraries/breakout_encoder/breakout_encoder.hpp +++ b/libraries/breakout_encoder/breakout_encoder.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../../drivers/ioexpander/ioexpander.hpp" +#include "drivers/ioexpander/ioexpander.hpp" namespace pimoroni { diff --git a/libraries/breakout_ioexpander/breakout_ioexpander.hpp b/libraries/breakout_ioexpander/breakout_ioexpander.hpp index e6ebd0e5..e3e2ab09 100644 --- a/libraries/breakout_ioexpander/breakout_ioexpander.hpp +++ b/libraries/breakout_ioexpander/breakout_ioexpander.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../../drivers/ioexpander/ioexpander.hpp" +#include "drivers/ioexpander/ioexpander.hpp" namespace pimoroni { diff --git a/libraries/breakout_mics6814/breakout_mics6814.hpp b/libraries/breakout_mics6814/breakout_mics6814.hpp index 0a0e3612..6940e5dd 100644 --- a/libraries/breakout_mics6814/breakout_mics6814.hpp +++ b/libraries/breakout_mics6814/breakout_mics6814.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../../drivers/ioexpander/ioexpander.hpp" +#include "drivers/ioexpander/ioexpander.hpp" namespace pimoroni { diff --git a/libraries/breakout_msa301/breakout_msa301.hpp b/libraries/breakout_msa301/breakout_msa301.hpp index c16c34b4..54c6647c 100644 --- a/libraries/breakout_msa301/breakout_msa301.hpp +++ b/libraries/breakout_msa301/breakout_msa301.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../../drivers/msa301/msa301.hpp" +#include "drivers/msa301/msa301.hpp" namespace pimoroni { diff --git a/libraries/breakout_potentiometer/breakout_potentiometer.hpp b/libraries/breakout_potentiometer/breakout_potentiometer.hpp index dad658b2..93263384 100644 --- a/libraries/breakout_potentiometer/breakout_potentiometer.hpp +++ b/libraries/breakout_potentiometer/breakout_potentiometer.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../../drivers/ioexpander/ioexpander.hpp" +#include "drivers/ioexpander/ioexpander.hpp" namespace pimoroni { diff --git a/micropython/modules/breakout_encoder/breakout_encoder.cpp b/micropython/modules/breakout_encoder/breakout_encoder.cpp index e9ade1c0..0b442df0 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.cpp +++ b/micropython/modules/breakout_encoder/breakout_encoder.cpp @@ -1,4 +1,4 @@ -#include "../../../libraries/breakout_encoder/breakout_encoder.hpp" +#include "libraries/breakout_encoder/breakout_encoder.hpp" #define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) diff --git a/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp b/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp index c31ed4fb..785caf58 100644 --- a/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp +++ b/micropython/modules/breakout_ioexpander/breakout_ioexpander.cpp @@ -1,4 +1,4 @@ -#include "../../../libraries/breakout_ioexpander/breakout_ioexpander.hpp" +#include "libraries/breakout_ioexpander/breakout_ioexpander.hpp" #define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) diff --git a/micropython/modules/breakout_mics6814/breakout_mics6814.cpp b/micropython/modules/breakout_mics6814/breakout_mics6814.cpp index 6a744610..5b89d6b7 100644 --- a/micropython/modules/breakout_mics6814/breakout_mics6814.cpp +++ b/micropython/modules/breakout_mics6814/breakout_mics6814.cpp @@ -1,4 +1,4 @@ -#include "../../../libraries/breakout_mics6814/breakout_mics6814.hpp" +#include "libraries/breakout_mics6814/breakout_mics6814.hpp" #define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) diff --git a/micropython/modules/breakout_msa301/breakout_msa301.cpp b/micropython/modules/breakout_msa301/breakout_msa301.cpp index 17f91cf7..3b07f0d3 100644 --- a/micropython/modules/breakout_msa301/breakout_msa301.cpp +++ b/micropython/modules/breakout_msa301/breakout_msa301.cpp @@ -1,4 +1,4 @@ -#include "../../../libraries/breakout_msa301/breakout_msa301.hpp" +#include "libraries/breakout_msa301/breakout_msa301.hpp" #define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp index fcae6661..d505b846 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp @@ -1,4 +1,4 @@ -#include "../../../libraries/breakout_potentiometer/breakout_potentiometer.hpp" +#include "libraries/breakout_potentiometer/breakout_potentiometer.hpp" #define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) From d9d37df06835bb56f37b68b089ff7b92af45cdd2 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 14 May 2021 12:58:16 +0100 Subject: [PATCH 27/27] Enable stdio UART for IOE examples --- examples/breakout_encoder/CMakeLists.txt | 2 +- examples/breakout_ioexpander/adc/CMakeLists.txt | 2 +- examples/breakout_ioexpander/button/CMakeLists.txt | 2 +- examples/breakout_ioexpander/servo/CMakeLists.txt | 2 +- examples/breakout_potentiometer/CMakeLists.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/breakout_encoder/CMakeLists.txt b/examples/breakout_encoder/CMakeLists.txt index 5cb31bfc..af459279 100644 --- a/examples/breakout_encoder/CMakeLists.txt +++ b/examples/breakout_encoder/CMakeLists.txt @@ -7,7 +7,7 @@ add_executable( # enable usb output, disable uart output pico_enable_stdio_usb(${OUTPUT_NAME} 1) -pico_enable_stdio_uart(${OUTPUT_NAME} 0) +pico_enable_stdio_uart(${OUTPUT_NAME} 1) # Pull in pico libraries that we need target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_encoder) diff --git a/examples/breakout_ioexpander/adc/CMakeLists.txt b/examples/breakout_ioexpander/adc/CMakeLists.txt index ecba6fa9..89a1da66 100644 --- a/examples/breakout_ioexpander/adc/CMakeLists.txt +++ b/examples/breakout_ioexpander/adc/CMakeLists.txt @@ -7,7 +7,7 @@ add_executable( # enable usb output, disable uart output pico_enable_stdio_usb(${OUTPUT_NAME} 1) -pico_enable_stdio_uart(${OUTPUT_NAME} 0) +pico_enable_stdio_uart(${OUTPUT_NAME} 1) # Pull in pico libraries that we need target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_ioexpander) diff --git a/examples/breakout_ioexpander/button/CMakeLists.txt b/examples/breakout_ioexpander/button/CMakeLists.txt index c20a8f08..6b702f74 100644 --- a/examples/breakout_ioexpander/button/CMakeLists.txt +++ b/examples/breakout_ioexpander/button/CMakeLists.txt @@ -7,7 +7,7 @@ add_executable( # enable usb output, disable uart output pico_enable_stdio_usb(${OUTPUT_NAME} 1) -pico_enable_stdio_uart(${OUTPUT_NAME} 0) +pico_enable_stdio_uart(${OUTPUT_NAME} 1) # Pull in pico libraries that we need target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_ioexpander) diff --git a/examples/breakout_ioexpander/servo/CMakeLists.txt b/examples/breakout_ioexpander/servo/CMakeLists.txt index bb2bb7b7..611f2335 100644 --- a/examples/breakout_ioexpander/servo/CMakeLists.txt +++ b/examples/breakout_ioexpander/servo/CMakeLists.txt @@ -7,7 +7,7 @@ add_executable( # enable usb output, disable uart output pico_enable_stdio_usb(${OUTPUT_NAME} 1) -pico_enable_stdio_uart(${OUTPUT_NAME} 0) +pico_enable_stdio_uart(${OUTPUT_NAME} 1) # Pull in pico libraries that we need target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_ioexpander) diff --git a/examples/breakout_potentiometer/CMakeLists.txt b/examples/breakout_potentiometer/CMakeLists.txt index e7067e04..a2484df1 100644 --- a/examples/breakout_potentiometer/CMakeLists.txt +++ b/examples/breakout_potentiometer/CMakeLists.txt @@ -7,7 +7,7 @@ add_executable( # enable usb output, disable uart output pico_enable_stdio_usb(${OUTPUT_NAME} 1) -pico_enable_stdio_uart(${OUTPUT_NAME} 0) +pico_enable_stdio_uart(${OUTPUT_NAME} 1) # Pull in pico libraries that we need target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_potentiometer)