Merge pull request #144 from pimoroni/driver/nuvoton
C++ and Micropython support for IOExpander based breakouts
This commit is contained in:
commit
0549a57133
|
@ -1,4 +1,5 @@
|
|||
add_subdirectory(esp32spi)
|
||||
add_subdirectory(ioexpander)
|
||||
add_subdirectory(ltp305)
|
||||
add_subdirectory(ltr559)
|
||||
add_subdirectory(sgp30)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include(ioexpander.cmake)
|
|
@ -0,0 +1,10 @@
|
|||
set(DRIVER_NAME ioexpander)
|
||||
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)
|
|
@ -0,0 +1,857 @@
|
|||
#include <cstdlib>
|
||||
#include <math.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "ioexpander.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 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 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 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"};
|
||||
|
||||
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) {
|
||||
}
|
||||
|
||||
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]) {
|
||||
}
|
||||
|
||||
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) {
|
||||
}
|
||||
|
||||
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]) {
|
||||
}
|
||||
|
||||
IOExpander::Pin IOExpander::Pin::io(uint8_t port, uint8_t pin) {
|
||||
return Pin(port, pin);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
IOExpander::Pin IOExpander::Pin::adc(uint8_t port, uint8_t pin, uint8_t channel) {
|
||||
return Pin(port, pin, channel);
|
||||
}
|
||||
|
||||
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 IOExpander::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;
|
||||
}
|
||||
|
||||
IOExpander::Pin::IOType IOExpander::Pin::get_type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
uint8_t IOExpander::Pin::get_mode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
void IOExpander::Pin::set_mode(uint8_t mode) {
|
||||
this->mode = mode;
|
||||
}
|
||||
|
||||
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),
|
||||
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)} {
|
||||
}
|
||||
|
||||
bool IOExpander::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 != PIN_UNUSED) {
|
||||
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;
|
||||
}
|
||||
|
||||
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 IOExpander::set_address(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 IOExpander::get_adc_vref() {
|
||||
return vref;
|
||||
}
|
||||
|
||||
void IOExpander::set_adc_vref(float vref) {
|
||||
this->vref = vref;
|
||||
}
|
||||
|
||||
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 IOExpander::disable_interrupt_out() {
|
||||
clr_bit(reg::INT, int_bit::OUT_EN);
|
||||
}
|
||||
|
||||
bool IOExpander::get_interrupt_flag() {
|
||||
if(interrupt != PIN_UNUSED)
|
||||
return !gpio_get(interrupt);
|
||||
else
|
||||
return (get_bit(reg::INT, int_bit::TRIGD) != 0);
|
||||
}
|
||||
|
||||
void IOExpander::clear_interrupt_flag() {
|
||||
clr_bit(reg::INT, int_bit::TRIGD);
|
||||
}
|
||||
|
||||
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];
|
||||
change_bit(io_pin.reg_int_mask_p, io_pin.pin, enabled);
|
||||
|
||||
succeeded = true;
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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 IOExpander::pwm_loading() {
|
||||
return get_bit(reg::PWMCON0, 6);
|
||||
}
|
||||
|
||||
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) {
|
||||
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 IOExpander::pwm_clearing() {
|
||||
return get_bit(reg::PWMCON0, 4);
|
||||
}
|
||||
|
||||
bool IOExpander::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 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));
|
||||
|
||||
if(load)
|
||||
pwm_load();
|
||||
}
|
||||
|
||||
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) {
|
||||
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 IOExpander::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 IOExpander::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 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;
|
||||
}
|
||||
|
||||
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 == LOW) {
|
||||
if(debug) {
|
||||
printf("Outputting LOW to pin: %d\n", pin);
|
||||
}
|
||||
|
||||
clr_bit(io_pin.reg_p, io_pin.pin);
|
||||
}
|
||||
else if(value == HIGH) {
|
||||
if(debug) {
|
||||
printf("Outputting HIGH to pin: %d\n", pin);
|
||||
}
|
||||
|
||||
set_bit(io_pin.reg_p, io_pin.pin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(pin_a, PIN_MODE_PU, true);
|
||||
set_mode(pin_b, PIN_MODE_PU, true);
|
||||
|
||||
if(pin_c != 0) {
|
||||
set_mode(pin_c, PIN_MODE_OD);
|
||||
output(pin_c, 0);
|
||||
}
|
||||
|
||||
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
|
||||
uint8_t reg = ENC_COUNT[channel];
|
||||
i2c_reg_write_uint8(reg, 0x00);
|
||||
}
|
||||
|
||||
int16_t IOExpander::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 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 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 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 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
|
||||
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 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 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) {
|
||||
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 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 IOExpander::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 IOExpander::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 IOExpander::millis() {
|
||||
return to_ms_since_boot(get_absolute_time());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
#pragma once
|
||||
|
||||
#include "hardware/i2c.h"
|
||||
#include "hardware/gpio.h"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
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)
|
||||
|
||||
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 uint8_t PIN_UNUSED = UINT8_MAX;
|
||||
|
||||
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_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
|
||||
|
||||
static const uint8_t NUM_PINS = 14;
|
||||
|
||||
static const uint16_t LOW = 0;
|
||||
static const uint16_t HIGH = 1;
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// 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:
|
||||
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);
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// 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;
|
||||
|
||||
uint16_t get_chip_id();
|
||||
|
||||
void set_address(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();
|
||||
bool get_interrupt_flag();
|
||||
void clear_interrupt_flag();
|
||||
bool set_pin_interrupt(uint8_t pin, bool enabled);
|
||||
|
||||
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 pin_a, uint8_t pin_b, uint8_t pin_c = 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();
|
||||
};
|
||||
|
||||
}
|
|
@ -1,9 +1,13 @@
|
|||
add_subdirectory(breakout_dotmatrix)
|
||||
add_subdirectory(breakout_encoder)
|
||||
add_subdirectory(breakout_ioexpander)
|
||||
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)
|
||||
|
@ -13,7 +17,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)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
set(OUTPUT_NAME encoder_demo)
|
||||
|
||||
add_executable(
|
||||
${OUTPUT_NAME}
|
||||
demo.cpp
|
||||
)
|
||||
|
||||
# enable usb output, disable uart output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
pico_enable_stdio_uart(${OUTPUT_NAME} 1)
|
||||
|
||||
# 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})
|
|
@ -0,0 +1,80 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#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);
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
add_subdirectory(adc)
|
||||
add_subdirectory(button)
|
||||
add_subdirectory(servo)
|
|
@ -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} 1)
|
||||
|
||||
# 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})
|
|
@ -0,0 +1,42 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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} 1)
|
||||
|
||||
# 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})
|
|
@ -0,0 +1,49 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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} 1)
|
||||
|
||||
# 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})
|
|
@ -0,0 +1,60 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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})
|
|
@ -0,0 +1,27 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include "stdio.h"
|
||||
|
||||
#include "breakout_mics6814.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
BreakoutMICS6814 mics6814;
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
gpio_init(PICO_DEFAULT_LED_PIN);
|
||||
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
||||
|
||||
mics6814.init();
|
||||
mics6814.set_heater(true);
|
||||
mics6814.set_led(0, 0, 255);
|
||||
|
||||
while(true) {
|
||||
BreakoutMICS6814::Reading reading = mics6814.read_all();
|
||||
printf("OX: %f Red: %f NH3: %f\n", reading.oxidising, reading.reducing, reading.nh3);
|
||||
sleep_ms(1000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
set(OUTPUT_NAME potentiometer_demo)
|
||||
|
||||
add_executable(
|
||||
${OUTPUT_NAME}
|
||||
demo.cpp
|
||||
)
|
||||
|
||||
# enable usb output, disable uart output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
pico_enable_stdio_uart(${OUTPUT_NAME} 1)
|
||||
|
||||
# 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})
|
|
@ -0,0 +1,64 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#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);
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
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("Potentiometer not found :'(\n");
|
||||
gpio_put(PICO_DEFAULT_LED_PIN, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -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})
|
|
@ -0,0 +1,127 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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})
|
|
@ -0,0 +1,111 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include(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 ioexpander)
|
|
@ -0,0 +1,94 @@
|
|||
#include "breakout_encoder.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
void BreakoutEncoder::set_direction(Direction direction) {
|
||||
this->direction = direction;
|
||||
}
|
||||
|
||||
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 != DIRECTION_CW)
|
||||
count = 0 - count;
|
||||
|
||||
ioe.clear_interrupt_flag();
|
||||
return count;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
#pragma once
|
||||
|
||||
#include "drivers/ioexpander/ioexpander.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
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 Direction 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;
|
||||
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
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// 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_address(uint8_t address);
|
||||
bool get_interrupt_flag();
|
||||
void clear_interrupt_flag();
|
||||
|
||||
// Encoder breakout specific
|
||||
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);
|
||||
|
||||
bool available();
|
||||
int16_t read();
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
include(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 ioexpander)
|
|
@ -0,0 +1,5 @@
|
|||
#include "breakout_ioexpander.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "drivers/ioexpander/ioexpander.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
typedef IOExpander BreakoutIOExpander;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
include(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 ioexpander)
|
|
@ -0,0 +1,154 @@
|
|||
#include "breakout_mics6814.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
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_OD);
|
||||
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_address(uint8_t address) {
|
||||
ioe.set_address(address);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
#pragma once
|
||||
|
||||
#include "drivers/ioexpander/ioexpander.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
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
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
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_address(uint8_t address);
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../drivers/msa301/msa301.hpp"
|
||||
#include "drivers/msa301/msa301.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include(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 ioexpander)
|
|
@ -0,0 +1,109 @@
|
|||
#include "breakout_potentiometer.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
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 == 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_address(uint8_t address) {
|
||||
ioe.set_address(address);
|
||||
}
|
||||
|
||||
float BreakoutPotentiometer::get_adc_vref() {
|
||||
return ioe.get_adc_vref();
|
||||
}
|
||||
|
||||
void BreakoutPotentiometer::set_adc_vref(float vref) {
|
||||
ioe.set_adc_vref(vref);
|
||||
}
|
||||
|
||||
BreakoutPotentiometer::Direction BreakoutPotentiometer::get_direction() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
else {
|
||||
// Counter clockwise increasing
|
||||
ioe.output(POT_TERM_A, IOExpander::HIGH);
|
||||
ioe.output(POT_TERM_B, IOExpander::LOW);
|
||||
}
|
||||
this->direction = direction;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
#pragma once
|
||||
|
||||
#include "drivers/ioexpander/ioexpander.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
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 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;
|
||||
|
||||
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;
|
||||
Direction direction = 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_address(uint8_t address);
|
||||
|
||||
float get_adc_vref();
|
||||
void set_adc_vref(float vref);
|
||||
|
||||
// Potentiometer breakout specific
|
||||
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);
|
||||
|
||||
float read(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT);
|
||||
int16_t read_raw(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT);
|
||||
};
|
||||
|
||||
}
|
|
@ -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)
|
|
@ -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)
|
|
@ -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 is not last_state:
|
||||
if state:
|
||||
print("Button has been released")
|
||||
else:
|
||||
print("Button has been pressed")
|
||||
last_state = state
|
||||
|
||||
time.sleep(0.02)
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -0,0 +1,64 @@
|
|||
#include "breakout_encoder.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BreakoutEncoder Class
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***** 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);
|
||||
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_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) },
|
||||
{ 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);
|
||||
|
||||
/***** 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);
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,224 @@
|
|||
#include "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);
|
||||
}
|
||||
|
||||
if(!self->breakout->init()) {
|
||||
mp_raise_msg(&mp_type_RuntimeError, "Encoder breakout not found when initialising");
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
/***** Methods *****/
|
||||
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 },
|
||||
{ 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_address(args[ARG_address].u_int);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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 ? BreakoutEncoder::DIRECTION_CW : BreakoutEncoder::DIRECTION_CCW);
|
||||
|
||||
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(brightness);
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// 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_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);
|
||||
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);
|
|
@ -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})
|
|
@ -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++
|
|
@ -0,0 +1,95 @@
|
|||
#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_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);
|
||||
|
||||
/***** Class Definition *****/
|
||||
const mp_obj_type_t breakout_ioexpander_BreakoutIOExpander_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_breakout_ioexpander,
|
||||
.print = BreakoutIOExpander_print,
|
||||
.make_new = BreakoutIOExpander_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&BreakoutIOExpander_locals_dict,
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// breakout_ioexpander Module
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***** Globals Table *****/
|
||||
STATIC const mp_map_elem_t breakout_ioexpander_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_ioexpander) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutIOExpander), (mp_obj_t)&breakout_ioexpander_BreakoutIOExpander_type },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_ioexpander_globals, breakout_ioexpander_globals_table);
|
||||
|
||||
/***** Module Definition *****/
|
||||
const mp_obj_module_t breakout_ioexpander_user_cmodule = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_breakout_ioexpander_globals,
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
MP_REGISTER_MODULE(MP_QSTR_breakout_ioexpander, breakout_ioexpander_user_cmodule, MODULE_BREAKOUT_IOEXPANDER_ENABLED);
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,482 @@
|
|||
#include "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 = 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 pin = args[ARG_pin].u_int;
|
||||
int value = args[ARG_value].u_int;
|
||||
bool load = args[ARG_load].u_bool;
|
||||
|
||||
if(pin < 1 || pin > IOExpander::NUM_PINS)
|
||||
mp_raise_ValueError("pin out of range. Expected 1 to 14");
|
||||
else if(value < 0 || value > 65535)
|
||||
mp_raise_ValueError("value out of range. Expected 0 to 65535");
|
||||
else
|
||||
self->breakout->output(pin, value, load);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_setup_rotary_encoder(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_channel, ARG_pin_a, ARG_pin_b, ARG_pin_c, ARG_count_microsteps };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_channel, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_pin_a, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_pin_b, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_pin_c, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_count_microsteps, MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
int channel = args[ARG_channel].u_int;
|
||||
int pin_a = args[ARG_pin_a].u_int;
|
||||
int pin_b = args[ARG_pin_b].u_int;
|
||||
int pin_c = args[ARG_pin_c].u_int;
|
||||
bool count_microsteps = args[ARG_count_microsteps].u_bool;
|
||||
|
||||
if(channel < 1 || channel > 4)
|
||||
mp_raise_ValueError("channel out of range. Expected 1 to 4");
|
||||
else if(pin_a < 1 || pin_a > 14)
|
||||
mp_raise_ValueError("pin_a out of range. Expected 1 to 14");
|
||||
else if(pin_b < 1 || pin_b > 14)
|
||||
mp_raise_ValueError("pin_b out of range. Expected 1 to 14");
|
||||
else if(pin_c < 1 || pin_c > 14)
|
||||
mp_raise_ValueError("pin_c out of range. Expected 1 to 14");
|
||||
else
|
||||
self->breakout->setup_rotary_encoder(channel, pin_a, pin_b, pin_c, count_microsteps);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t BreakoutIOExpander_read_rotary_encoder(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_channel, ARG_value, ARG_load };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_channel, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
breakout_ioexpander_BreakoutIOExpander_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_ioexpander_BreakoutIOExpander_obj_t);
|
||||
|
||||
int channel = args[ARG_channel].u_int;
|
||||
if(channel < 1 || channel > 4)
|
||||
mp_raise_ValueError("channel out of range. Expected 1 to 4");
|
||||
else
|
||||
return mp_obj_new_int(self->breakout->read_rotary_encoder(channel));
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// Include MicroPython API.
|
||||
#include "py/runtime.h"
|
||||
|
||||
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;
|
||||
|
||||
/***** Extern of Class Methods *****/
|
||||
extern void BreakoutIOExpander_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
||||
extern mp_obj_t BreakoutIOExpander_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
|
||||
extern mp_obj_t BreakoutIOExpander_get_chip_id(mp_obj_t self_in);
|
||||
extern mp_obj_t BreakoutIOExpander_set_address(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_get_adc_vref(mp_obj_t self_in);
|
||||
extern mp_obj_t BreakoutIOExpander_set_adc_vref(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_enable_interrupt_out(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_disable_interrupt_out(mp_obj_t self_in);
|
||||
extern mp_obj_t BreakoutIOExpander_get_interrupt_flag(mp_obj_t self_in);
|
||||
extern mp_obj_t BreakoutIOExpander_clear_interrupt_flag(mp_obj_t self_in);
|
||||
extern mp_obj_t BreakoutIOExpander_set_pin_interrupt(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_pwm_load(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_pwm_loading(mp_obj_t self_in);
|
||||
extern mp_obj_t BreakoutIOExpander_pwm_clear(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_pwm_clearing(mp_obj_t self_in);
|
||||
extern mp_obj_t BreakoutIOExpander_set_pwm_control(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_set_pwm_period(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_get_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_set_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_input(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_input_as_voltage(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_output(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_setup_rotary_encoder(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t BreakoutIOExpander_read_rotary_encoder(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
|
@ -0,0 +1,20 @@
|
|||
set(MOD_NAME breakout_ioexpander)
|
||||
string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER)
|
||||
add_library(usermod_${MOD_NAME} INTERFACE)
|
||||
|
||||
target_sources(usermod_${MOD_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/${MOD_NAME}/${MOD_NAME}.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/ioexpander/ioexpander.cpp
|
||||
)
|
||||
|
||||
target_include_directories(usermod_${MOD_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
target_compile_definitions(usermod_${MOD_NAME} INTERFACE
|
||||
-DMODULE_${MOD_NAME_UPPER}_ENABLED=1
|
||||
)
|
||||
|
||||
target_link_libraries(usermod INTERFACE usermod_${MOD_NAME})
|
|
@ -0,0 +1,13 @@
|
|||
set(MOD_NAME breakout_ioexpander)
|
||||
BREAKOUT_MOD_DIR := $(USERMOD_DIR)
|
||||
|
||||
# Add our source files to the respective variables.
|
||||
SRC_USERMOD += $(BREAKOUT_MOD_DIR)/${MOD_NAME}.c
|
||||
SRC_USERMOD_CXX += $(BREAKOUT_MOD_DIR)/${MOD_NAME}.cpp
|
||||
|
||||
# Add our module directory to the include path.
|
||||
CFLAGS_USERMOD += -I$(BREAKOUT_MOD_DIR)
|
||||
CXXFLAGS_USERMOD += -I$(BREAKOUT_MOD_DIR)
|
||||
|
||||
# We use C++ features so have to link against the standard library.
|
||||
LDFLAGS_USERMOD += -lstdc++
|
|
@ -0,0 +1,80 @@
|
|||
#include "breakout_mics6814.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BreakoutMICS6814 Class
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***** Methods *****/
|
||||
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);
|
||||
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_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) },
|
||||
{ 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);
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,280 @@
|
|||
#include "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);
|
||||
}
|
||||
|
||||
if(!self->breakout->init()) {
|
||||
mp_raise_msg(&mp_type_RuntimeError, "MICS6814 breakout not found when initialising");
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
/***** Methods *****/
|
||||
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 },
|
||||
{ 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_address(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(brightness);
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
|
@ -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_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);
|
||||
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);
|
|
@ -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})
|
|
@ -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++
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
#include "breakout_potentiometer.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BreakoutPotentiometer Class
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***** Methods *****/
|
||||
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);
|
||||
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_raw_obj, BreakoutPotentiometer_read_raw);
|
||||
|
||||
/***** Binding of Methods *****/
|
||||
STATIC const mp_rom_map_elem_t BreakoutPotentiometer_locals_dict_table[] = {
|
||||
{ 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) },
|
||||
{ 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_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);
|
||||
|
||||
/***** 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);
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,235 @@
|
|||
#include "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);
|
||||
}
|
||||
|
||||
if(!self->breakout->init()) {
|
||||
mp_raise_msg(&mp_type_RuntimeError, "Potentiometer breakout not found when initialising");
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
/***** Methods *****/
|
||||
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 },
|
||||
{ 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_address(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 ? BreakoutPotentiometer::DIRECTION_CW : BreakoutPotentiometer::DIRECTION_CCW);
|
||||
|
||||
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(brightness);
|
||||
|
||||
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_float(self->breakout->read());
|
||||
}
|
||||
|
||||
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_int(self->breakout->read_raw());
|
||||
}
|
||||
}
|
|
@ -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_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);
|
||||
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_raw(mp_obj_t self_in);
|
|
@ -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})
|
|
@ -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++
|
|
@ -1,6 +1,8 @@
|
|||
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)
|
||||
|
@ -8,6 +10,8 @@ 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)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/breakout_colourlcd240x240/micropython.cmake)
|
||||
|
|
Loading…
Reference in New Issue