Renamed IOExpander and added Pot, Enc, and MICS specific classes

pull/144/head
ZodiusInfuser 2021-05-11 17:18:43 +01:00 zatwierdzone przez Phil Howard
rodzic acf011bba2
commit 05af3e86ba
26 zmienionych plików z 898 dodań i 148 usunięć

Wyświetl plik

@ -1,11 +1,11 @@
add_subdirectory(esp32spi)
add_subdirectory(ioexpander)
add_subdirectory(ltp305)
add_subdirectory(ltr559)
add_subdirectory(sgp30)
add_subdirectory(st7735)
add_subdirectory(st7789)
add_subdirectory(msa301)
add_subdirectory(nuvoton)
add_subdirectory(rv3028)
add_subdirectory(trackball)
add_subdirectory(vl53l1x)

Wyświetl plik

@ -0,0 +1 @@
include(ioexpander.cmake)

Wyświetl plik

@ -1,4 +1,4 @@
set(DRIVER_NAME nuvoton)
set(DRIVER_NAME ioexpander)
add_library(${DRIVER_NAME} INTERFACE)
target_sources(${DRIVER_NAME} INTERFACE

Wyświetl plik

@ -3,7 +3,7 @@
#include <map>
#include <vector>
#include "nuvoton.hpp"
#include "ioexpander.hpp"
namespace pimoroni {
@ -220,61 +220,61 @@ namespace pimoroni {
static const uint8_t ENC_CFG[4] = {reg::ENC_1_CFG, reg::ENC_2_CFG, reg::ENC_3_CFG, reg::ENC_4_CFG};
static const uint8_t ENC_COUNT[4] = {reg::ENC_1_COUNT, reg::ENC_2_COUNT, reg::ENC_3_COUNT, reg::ENC_4_COUNT};
const uint8_t Nuvoton::Pin::PxM1[4] = {reg::P0M1, reg::P1M1, (uint8_t)-1, reg::P3M1};
const uint8_t Nuvoton::Pin::PxM2[4] = {reg::P0M2, reg::P1M2, (uint8_t)-1, reg::P3M2};
const uint8_t Nuvoton::Pin::Px[4] = {reg::P0, reg::P1, (uint8_t)-1, reg::P3};
const uint8_t IOExpander::Pin::PxM1[4] = {reg::P0M1, reg::P1M1, (uint8_t)-1, reg::P3M1};
const uint8_t IOExpander::Pin::PxM2[4] = {reg::P0M2, reg::P1M2, (uint8_t)-1, reg::P3M2};
const uint8_t IOExpander::Pin::Px[4] = {reg::P0, reg::P1, (uint8_t)-1, reg::P3};
const uint8_t Nuvoton::Pin::PxS[4] = {reg::P0S, reg::P1S, (uint8_t)-1, reg::P3S};
const uint8_t Nuvoton::Pin::MASK_P[4] = {reg::INT_MASK_P0, reg::INT_MASK_P1, (uint8_t)-1, reg::INT_MASK_P3};
const uint8_t IOExpander::Pin::PxS[4] = {reg::P0S, reg::P1S, (uint8_t)-1, reg::P3S};
const uint8_t IOExpander::Pin::MASK_P[4] = {reg::INT_MASK_P0, reg::INT_MASK_P1, (uint8_t)-1, reg::INT_MASK_P3};
const uint8_t Nuvoton::Pin::PWML[6] = {reg::PWM0L, reg::PWM1L, reg::PWM2L, reg::PWM3L, reg::PWM4L, reg::PWM5L};
const uint8_t Nuvoton::Pin::PWMH[6] = {reg::PWM0H, reg::PWM1H, reg::PWM2H, reg::PWM3H, reg::PWM4H, reg::PWM5H};
const uint8_t IOExpander::Pin::PWML[6] = {reg::PWM0L, reg::PWM1L, reg::PWM2L, reg::PWM3L, reg::PWM4L, reg::PWM5L};
const uint8_t IOExpander::Pin::PWMH[6] = {reg::PWM0H, reg::PWM1H, reg::PWM2H, reg::PWM3H, reg::PWM4H, reg::PWM5H};
static const char* MODE_NAMES[3] = {"IO", "PWM", "ADC"};
static const char* GPIO_NAMES[4] = {"QB", "PP", "IN", "OD"};
static const char* STATE_NAMES[2] = {"LOW", "HIGH"};
Nuvoton::Pin::Pin(uint8_t port, uint8_t pin) :
IOExpander::Pin::Pin(uint8_t port, uint8_t pin) :
type(TYPE_IO), mode(0), port(port), pin(pin), adc_channel(0), pwm_channel(0),
reg_m1(PxM1[port]), reg_m2(PxM2[port]), reg_p(Px[port]), reg_ps(PxS[port]), reg_int_mask_p(MASK_P[port]),
reg_io_pwm(0), reg_pwml(0), reg_pwmh(0) {
}
Nuvoton::Pin::Pin(uint8_t port, uint8_t pin, uint8_t pwm_channel, uint8_t reg_io_pwm) :
IOExpander::Pin::Pin(uint8_t port, uint8_t pin, uint8_t pwm_channel, uint8_t reg_io_pwm) :
type(TYPE_PWM), mode(0), port(port), pin(pin), adc_channel(0), pwm_channel(pwm_channel),
reg_m1(PxM1[port]), reg_m2(PxM2[port]), reg_p(Px[port]), reg_ps(PxS[port]), reg_int_mask_p(MASK_P[port]),
reg_io_pwm(reg_io_pwm), reg_pwml(PWML[pwm_channel]), reg_pwmh(PWMH[pwm_channel]) {
}
Nuvoton::Pin::Pin(uint8_t port, uint8_t pin, uint8_t adc_channel) :
IOExpander::Pin::Pin(uint8_t port, uint8_t pin, uint8_t adc_channel) :
type(TYPE_ADC), mode(0), port(port), pin(pin), adc_channel(adc_channel), pwm_channel(0),
reg_m1(PxM1[port]), reg_m2(PxM2[port]), reg_p(Px[port]), reg_ps(PxS[port]), reg_int_mask_p(MASK_P[port]),
reg_io_pwm(0), reg_pwml(0), reg_pwmh(0) {
}
Nuvoton::Pin::Pin(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_io_pwm) :
IOExpander::Pin::Pin(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_io_pwm) :
type(TYPE_ADC_OR_PWM), mode(0), port(port), pin(pin), adc_channel(adc_channel), pwm_channel(pwm_channel),
reg_m1(PxM1[port]), reg_m2(PxM2[port]), reg_p(Px[port]), reg_ps(PxS[port]), reg_int_mask_p(MASK_P[port]),
reg_io_pwm(reg_io_pwm), reg_pwml(PWML[pwm_channel]), reg_pwmh(PWMH[pwm_channel]) {
}
Nuvoton::Pin Nuvoton::Pin::io(uint8_t port, uint8_t pin) {
IOExpander::Pin IOExpander::Pin::io(uint8_t port, uint8_t pin) {
return Pin(port, pin);
}
Nuvoton::Pin Nuvoton::Pin::pwm(uint8_t port, uint8_t pin, uint8_t channel, uint8_t reg_iopwm) {
IOExpander::Pin IOExpander::Pin::pwm(uint8_t port, uint8_t pin, uint8_t channel, uint8_t reg_iopwm) {
return Pin(port, pin, channel, reg_iopwm);
}
Nuvoton::Pin Nuvoton::Pin::adc(uint8_t port, uint8_t pin, uint8_t channel) {
IOExpander::Pin IOExpander::Pin::adc(uint8_t port, uint8_t pin, uint8_t channel) {
return Pin(port, pin, channel);
}
Nuvoton::Pin Nuvoton::Pin::adc_or_pwm(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm) {
IOExpander::Pin IOExpander::Pin::adc_or_pwm(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm) {
return Pin(port, pin, adc_channel, pwm_channel, reg_iopwm);
}
bool Nuvoton::Pin::mode_supported(uint8_t mode) {
bool IOExpander::Pin::mode_supported(uint8_t mode) {
bool supported = false;
if((type & TYPE_PWM) && (mode == PIN_MODE_PWM)) {
supported = true;
@ -285,19 +285,19 @@ namespace pimoroni {
return supported;
}
Nuvoton::Pin::IOType Nuvoton::Pin::get_type() {
IOExpander::Pin::IOType IOExpander::Pin::get_type() {
return type;
}
uint8_t Nuvoton::Pin::get_mode() {
uint8_t IOExpander::Pin::get_mode() {
return mode;
}
void Nuvoton::Pin::set_mode(uint8_t mode) {
void IOExpander::Pin::set_mode(uint8_t mode) {
this->mode = mode;
}
Nuvoton::Nuvoton(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt, uint8_t address, uint32_t timeout, bool debug) :
IOExpander::IOExpander(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt, uint8_t address, uint32_t timeout, bool debug) :
i2c(i2c), sda(sda), scl(scl), interrupt(interrupt),
address(address), timeout(timeout), debug(debug), vref(3.3f),
encoder_offset{0,0,0,0},
@ -318,11 +318,11 @@ namespace pimoroni {
Pin::adc(1, 7, 0)} {
}
Nuvoton::Nuvoton(uint8_t address, uint32_t timeout, bool debug) :
Nuvoton(i2c0, DEFAULT_SDA_PIN, DEFAULT_SCL_PIN, DEFAULT_INT_PIN, address, timeout, debug) {
IOExpander::IOExpander(uint8_t address, uint32_t timeout, bool debug) :
IOExpander(i2c0, DEFAULT_SDA_PIN, DEFAULT_SCL_PIN, DEFAULT_INT_PIN, address, timeout, debug) {
}
bool Nuvoton::init(bool skipChipIdCheck) {
bool IOExpander::init(bool skipChipIdCheck) {
bool succeeded = true;
i2c_init(i2c, 400000);
@ -348,11 +348,27 @@ namespace pimoroni {
return succeeded;
}
uint16_t Nuvoton::get_chip_id() {
i2c_inst_t* IOExpander::get_i2c() const {
return i2c;
}
int IOExpander::get_sda() const {
return sda;
}
int IOExpander::get_scl() const {
return scl;
}
int IOExpander::get_int() const {
return interrupt;
}
uint16_t IOExpander::get_chip_id() {
return ((uint16_t)i2c_reg_read_uint8(reg::CHIP_ID_H) << 8) | (uint16_t)i2c_reg_read_uint8(reg::CHIP_ID_L);
}
void Nuvoton::set_addr(uint8_t address) {
void IOExpander::set_addr(uint8_t address) {
set_bit(reg::CTRL, 4);
i2c_reg_write_uint8(reg::ADDR, address);
this->address = address;
@ -361,35 +377,35 @@ namespace pimoroni {
clr_bit(reg::CTRL, 4);
}
float Nuvoton::get_adc_vref() {
float IOExpander::get_adc_vref() {
return vref;
}
void Nuvoton::set_adc_vref(float vref) {
void IOExpander::set_adc_vref(float vref) {
this->vref = vref;
}
void Nuvoton::enable_interrupt_out(bool pin_swap) {
void IOExpander::enable_interrupt_out(bool pin_swap) {
set_bit(reg::INT, int_bit::OUT_EN);
change_bit(reg::INT, int_bit::PIN_SWAP, pin_swap);
}
void Nuvoton::disable_interrupt_out() {
void IOExpander::disable_interrupt_out() {
clr_bit(reg::INT, int_bit::OUT_EN);
}
uint8_t Nuvoton::get_interrupt_flag() {
uint8_t IOExpander::get_interrupt_flag() {
if(interrupt != 0)
return !gpio_get(interrupt);
else
return get_bit(reg::INT, int_bit::TRIGD);
}
void Nuvoton::clear_interrupt_flag() {
void IOExpander::clear_interrupt_flag() {
clr_bit(reg::INT, int_bit::TRIGD);
}
bool Nuvoton::set_pin_interrupt(uint8_t pin, bool enabled) {
bool IOExpander::set_pin_interrupt(uint8_t pin, bool enabled) {
bool succeeded = false;
if(pin >= 1 && pin <= NUM_PINS) {
Pin& io_pin = pins[pin - 1];
@ -401,14 +417,14 @@ namespace pimoroni {
return succeeded;
}
void Nuvoton::set_interrupt_callback(void (*callback)()) {
void IOExpander::set_interrupt_callback(void (*callback)()) {
if(interrupt != 0 && callback != nullptr) {
//attachInterrupt(digitalPinToInterrupt(_interruptPin), callback, FALLING);
clear_interrupt_flag();
}
}
void Nuvoton::pwm_load(bool wait_for_load) {
void IOExpander::pwm_load(bool wait_for_load) {
//Load new period and duty registers into buffer
uint32_t start_time = millis();
set_bit(reg::PWMCON0, 6); //Set the "LOAD" bit of PWMCON0
@ -425,11 +441,11 @@ namespace pimoroni {
}
}
bool Nuvoton::pwm_loading() {
bool IOExpander::pwm_loading() {
return get_bit(reg::PWMCON0, 6);
}
void Nuvoton::pwm_clear(bool wait_for_clear) {
void IOExpander::pwm_clear(bool wait_for_clear) {
uint32_t start_time = millis();
set_bit(reg::PWMCON0, 4); //Set the "CLRPWM" bit of PWMCON0
if(wait_for_clear) {
@ -444,11 +460,11 @@ namespace pimoroni {
}
}
bool Nuvoton::pwm_clearing() {
bool IOExpander::pwm_clearing() {
return get_bit(reg::PWMCON0, 4);
}
bool Nuvoton::set_pwm_control(uint8_t divider) {
bool IOExpander::set_pwm_control(uint8_t divider) {
bool divider_good = true;
uint8_t pwmdiv2 = 0;
switch(divider) {
@ -482,7 +498,7 @@ namespace pimoroni {
return divider_good;
}
void Nuvoton::set_pwm_period(uint16_t value, bool load) {
void IOExpander::set_pwm_period(uint16_t value, bool load) {
value &= 0xffff;
i2c_reg_write_uint8(reg::PWMPL, (uint8_t)(value & 0xff));
i2c_reg_write_uint8(reg::PWMPH, (uint8_t)(value >> 8));
@ -491,11 +507,11 @@ namespace pimoroni {
pwm_load();
}
uint8_t Nuvoton::get_mode(uint8_t pin) {
uint8_t IOExpander::get_mode(uint8_t pin) {
return pins[pin - 1].get_mode();
}
void Nuvoton::set_mode(uint8_t pin, uint8_t mode, bool schmitt_trigger, bool invert) {
void IOExpander::set_mode(uint8_t pin, uint8_t mode, bool schmitt_trigger, bool invert) {
if(pin < 1 || pin > NUM_PINS)
{
printf("ValueError: Pin should be in range 1-14.\n");
@ -559,7 +575,7 @@ namespace pimoroni {
i2c_reg_write_uint8(io_pin.reg_p, (initial_state << 3) | io_pin.pin);
}
int16_t Nuvoton::input(uint8_t pin, uint32_t adc_timeout) {
int16_t IOExpander::input(uint8_t pin, uint32_t adc_timeout) {
if(pin < 1 || pin > NUM_PINS)
{
if(debug)
@ -608,7 +624,7 @@ namespace pimoroni {
}
}
float Nuvoton::input_as_voltage(uint8_t pin, uint32_t adc_timeout) {
float IOExpander::input_as_voltage(uint8_t pin, uint32_t adc_timeout) {
if(pin < 1 || pin > NUM_PINS)
{
if(debug)
@ -658,7 +674,7 @@ namespace pimoroni {
}
}
void Nuvoton::output(uint8_t pin, uint16_t value, bool load) {
void IOExpander::output(uint8_t pin, uint16_t value, bool load) {
if(pin < 1 || pin > NUM_PINS) {
printf("Pin should be in range 1-14.");
return;
@ -677,14 +693,14 @@ namespace pimoroni {
pwm_load();
}
else {
if(value == 0) {
if(value == LOW) {
if(debug) {
printf("Outputting LOW to pin: %d\n", pin);
}
clr_bit(io_pin.reg_p, io_pin.pin);
}
else if(value == 1) {
else if(value == HIGH) {
if(debug) {
printf("Outputting HIGH to pin: %d\n", pin);
}
@ -694,7 +710,7 @@ namespace pimoroni {
}
}
void Nuvoton::setup_rotary_encoder(uint8_t channel, uint8_t pinA, uint8_t pinB, uint8_t pinC, bool count_microsteps) {
void IOExpander::setup_rotary_encoder(uint8_t channel, uint8_t pinA, uint8_t pinB, uint8_t pinC, bool count_microsteps) {
channel -= 1;
set_mode(pinA, PIN_MODE_PU, true);
set_mode(pinB, PIN_MODE_PU, true);
@ -713,7 +729,7 @@ namespace pimoroni {
i2c_reg_write_uint8(reg, 0x00);
}
int16_t Nuvoton::read_rotary_encoder(uint8_t channel) {
int16_t IOExpander::read_rotary_encoder(uint8_t channel) {
channel -= 1;
int16_t last = encoder_last[channel];
uint8_t reg = ENC_COUNT[channel];
@ -732,24 +748,24 @@ namespace pimoroni {
return encoder_offset[channel] + value;
}
uint8_t Nuvoton::i2c_reg_read_uint8(uint8_t reg) {
uint8_t IOExpander::i2c_reg_read_uint8(uint8_t reg) {
uint8_t value;
i2c_write_blocking(i2c, address, &reg, 1, true);
i2c_read_blocking(i2c, address, (uint8_t *)&value, 1, false);
return value;
}
void Nuvoton::i2c_reg_write_uint8(uint8_t reg, uint8_t value) {
void IOExpander::i2c_reg_write_uint8(uint8_t reg, uint8_t value) {
uint8_t buffer[2] = {reg, value};
i2c_write_blocking(i2c, address, buffer, 2, false);
}
uint8_t Nuvoton::get_bit(uint8_t reg, uint8_t bit) {
uint8_t IOExpander::get_bit(uint8_t reg, uint8_t bit) {
//Returns the specified bit (nth position from right) from a register
return i2c_reg_read_uint8(reg) & (1 << bit);
}
void Nuvoton::set_bits(uint8_t reg, uint8_t bits) {
void IOExpander::set_bits(uint8_t reg, uint8_t bits) {
//Set the specified bits (using a mask) in a register.
//Deal with special case registers first
@ -773,12 +789,12 @@ namespace pimoroni {
}
}
void Nuvoton::set_bit(uint8_t reg, uint8_t bit) {
void IOExpander::set_bit(uint8_t reg, uint8_t bit) {
//Set the specified bit (nth position from right) in a register.
set_bits(reg, (1 << bit));
}
void Nuvoton::clr_bits(uint8_t reg, uint8_t bits) {
void IOExpander::clr_bits(uint8_t reg, uint8_t bits) {
bool reg_in_bit_addressed_regs = false;
for(uint8_t i = 0; i < NUM_BIT_ADDRESSED_REGISTERS; i++) {
if(BIT_ADDRESSED_REGS[i] == reg) {
@ -799,12 +815,12 @@ namespace pimoroni {
}
}
void Nuvoton::clr_bit(uint8_t reg, uint8_t bit) {
void IOExpander::clr_bit(uint8_t reg, uint8_t bit) {
//Clear the specified bit (nth position from right) in a register.
clr_bits(reg, (1 << bit));
}
void Nuvoton::change_bit(uint8_t reg, uint8_t bit, bool state) {
void IOExpander::change_bit(uint8_t reg, uint8_t bit, bool state) {
//Toggle one register bit on/off.
if(state)
set_bit(reg, bit);
@ -812,7 +828,7 @@ namespace pimoroni {
clr_bit(reg, bit);
}
void Nuvoton::wait_for_flash(void) {
void IOExpander::wait_for_flash(void) {
//Wait for the IOE to finish writing non-volatile memory.
unsigned long start_time = millis();
while(get_interrupt_flag()) {
@ -833,7 +849,7 @@ namespace pimoroni {
}
}
uint32_t Nuvoton::millis() {
uint32_t IOExpander::millis() {
return to_ms_since_boot(get_absolute_time());
}
}

Wyświetl plik

@ -5,24 +5,24 @@
namespace pimoroni {
class Nuvoton {
class IOExpander {
//--------------------------------------------------
// Constants
//--------------------------------------------------
private:
//These values encode our desired pin function: IO, ADC, PWM
//alongwide the GPIO MODE for that port and pin (section 8.1)
//1st and 2nd bits encode the gpio state
//3rd and 4th bits encode the IO mode (i.e. IO, PWM, ADC)
//the 5th bit additionally encodes the default output state
static const uint8_t PIN_MODE_IO = 0b00000; //General IO mode, IE: not ADC or PWM
static const uint8_t PIN_MODE_QB = 0b00000; //Output, Quasi-Bidirectional mode
static const uint8_t PIN_MODE_PP = 0b00001; //Output, Push-Pull mode
static const uint8_t PIN_MODE_IN = 0b00010; //Input-only (high-impedance)
static const uint8_t PIN_MODE_PU = 0b10000; //Input (with pull-up)
static const uint8_t PIN_MODE_OD = 0b00011; //Output, Open-Drain mode
static const uint8_t PIN_MODE_PWM = 0b00101; //PWM, Output, Push-Pull mode
static const uint8_t PIN_MODE_ADC = 0b01010; //ADC, Input-only (high-impedance)
// These values encode our desired pin function: IO, ADC, PWM
// alongwide the GPIO MODE for that port and pin (section 8.1)
// 1st and 2nd bits encode the gpio state
// 3rd and 4th bits encode the IO mode (i.e. IO, PWM, ADC)
// the 5th bit additionally encodes the default output state
static const uint8_t PIN_MODE_IO = 0b00000; // General IO mode, IE: not ADC or PWM
static const uint8_t PIN_MODE_QB = 0b00000; // Output, Quasi-Bidirectional mode
static const uint8_t PIN_MODE_PP = 0b00001; // Output, Push-Pull mode
static const uint8_t PIN_MODE_IN = 0b00010; // Input-only (high-impedance)
static const uint8_t PIN_MODE_PU = 0b10000; // Input (with pull-up)
static const uint8_t PIN_MODE_OD = 0b00011; // Output, Open-Drain mode
static const uint8_t PIN_MODE_PWM = 0b00101; // PWM, Output, Push-Pull mode
static const uint8_t PIN_MODE_ADC = 0b01010; // ADC, Input-only (high-impedance)
public:
static const uint8_t DEFAULT_I2C_ADDRESS = 0x18;
@ -33,15 +33,18 @@ namespace pimoroni {
static const uint16_t CHIP_ID = 0xE26A;
static const uint8_t CHIP_VERSION = 2;
static const uint8_t PIN_IN = PIN_MODE_IN; //0b00010
static const uint8_t PIN_IN_PULL_UP = PIN_MODE_PU; //0b10000
static const uint8_t PIN_IN_PU = PIN_MODE_PU; //0b10000
static const uint8_t PIN_OUT = PIN_MODE_PP; //0b00001
static const uint8_t PIN_PWM = PIN_MODE_PWM; //0b00101
static const uint8_t PIN_ADC = PIN_MODE_ADC; //0b01010
static const uint8_t PIN_IN = PIN_MODE_IN; // 0b00010
static const uint8_t PIN_IN_PULL_UP = PIN_MODE_PU; // 0b10000
static const uint8_t PIN_IN_PU = PIN_MODE_PU; // 0b10000
static const uint8_t PIN_OUT = PIN_MODE_PP; // 0b00001
static const uint8_t PIN_PWM = PIN_MODE_PWM; // 0b00101
static const uint8_t PIN_ADC = PIN_MODE_ADC; // 0b01010
static const uint8_t NUM_PINS = 14;
static const uint16_t LOW = 0;
static const uint16_t HIGH = 1;
//--------------------------------------------------
// Subclasses
@ -58,43 +61,43 @@ namespace pimoroni {
TYPE_ADC = 0b10,
TYPE_ADC_OR_PWM = 0b11
};
//--------------------------------------------------
// Constants
//--------------------------------------------------
private:
//The PxM1 and PxM2 registers encode GPIO MODE
//0 0 = Quasi-bidirectional
//0 1 = Push-pull
//1 0 = Input-only (high-impedance)
//1 1 = Open-drain
static const uint8_t PxM1[4]; //[reg::P0M1, reg::P1M1, -1, reg::P3M1]
static const uint8_t PxM2[4]; //[reg::P0M2, reg::P1M2, -1, reg::P3M2]
// The PxM1 and PxM2 registers encode GPIO MODE
// 0 0 = Quasi-bidirectional
// 0 1 = Push-pull
// 1 0 = Input-only (high-impedance)
// 1 1 = Open-drain
static const uint8_t PxM1[4]; // [reg::P0M1, reg::P1M1, -1, reg::P3M1]
static const uint8_t PxM2[4]; // [reg::P0M2, reg::P1M2, -1, reg::P3M2]
//The Px input register
static const uint8_t Px[4]; //[reg::P0, reg::P1, -1, reg::P3]
// The Px input register
static const uint8_t Px[4]; // [reg::P0, reg::P1, -1, reg::P3]
//The PxS Schmitt trigger register
static const uint8_t PxS[4]; //[reg::P0S, reg::P1S, -1, reg::P3S]
static const uint8_t MASK_P[4]; //[reg::INT_MASK_P0, reg::INT_MASK_P1, -1, reg::INT_MASK_P3]
// The PxS Schmitt trigger register
static const uint8_t PxS[4]; // [reg::P0S, reg::P1S, -1, reg::P3S]
static const uint8_t MASK_P[4]; // [reg::INT_MASK_P0, reg::INT_MASK_P1, -1, reg::INT_MASK_P3]
static const uint8_t PWML[6]; //[reg::PWM0L, reg::PWM1L, reg::PWM2L, reg::PWM3L, reg::PWM4L, reg::PWM5L]
static const uint8_t PWMH[6]; //[reg::PWM0H, reg::PWM1H, reg::PWM2H, reg::PWM3H, reg::PWM4H, reg::PWM5H]
static const uint8_t PWML[6]; // [reg::PWM0L, reg::PWM1L, reg::PWM2L, reg::PWM3L, reg::PWM4L, reg::PWM5L]
static const uint8_t PWMH[6]; // [reg::PWM0H, reg::PWM1H, reg::PWM2H, reg::PWM3H, reg::PWM4H, reg::PWM5H]
//--------------------------------------------------
// Variables
//--------------------------------------------------
private:
const IOType type;
const IOType type;
uint8_t mode;
public:
const uint8_t port;
const uint8_t pin;
const uint8_t adc_channel;
const uint8_t pwm_channel;
const uint8_t reg_m1;
const uint8_t reg_m2;
const uint8_t reg_p;
@ -110,24 +113,22 @@ namespace pimoroni {
// Constructors
//--------------------------------------------------
private:
Pin(uint8_t port, uint8_t pin); //Constructor for IO pin
Pin(uint8_t port, uint8_t pin, uint8_t pwm_channel, uint8_t reg_iopwm); //Constructor for PWM pin
Pin(uint8_t port, uint8_t pin, uint8_t adc_channel); //Constructor for ADC pin
Pin(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm); //Constructor for ADC or PWM pin
Pin(uint8_t port, uint8_t pin); // Constructor for IO pin
Pin(uint8_t port, uint8_t pin, uint8_t pwm_channel, uint8_t reg_iopwm); // Constructor for PWM pin
Pin(uint8_t port, uint8_t pin, uint8_t adc_channel); // Constructor for ADC pin
Pin(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm); // Constructor for ADC or PWM pin
//--------------------------------------------------
// Methods
//--------------------------------------------------
public:
static Pin io(uint8_t port, uint8_t pin); //Nicer function for creating an IO pin
static Pin pwm(uint8_t port, uint8_t pin, uint8_t channel, uint8_t reg_iopwm); //Nicer function for creating a PWM pin
static Pin adc(uint8_t port, uint8_t pin, uint8_t channel); //Nicer function for creating an ADC pin
static Pin adc_or_pwm(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm); //Nicer function for creating an ADC or PWM pin
static Pin io(uint8_t port, uint8_t pin); // Nicer function for creating an IO pin
static Pin pwm(uint8_t port, uint8_t pin, uint8_t channel, uint8_t reg_iopwm); // Nicer function for creating a PWM pin
static Pin adc(uint8_t port, uint8_t pin, uint8_t channel); // Nicer function for creating an ADC pin
static Pin adc_or_pwm(uint8_t port, uint8_t pin, uint8_t adc_channel, uint8_t pwm_channel, uint8_t reg_iopwm); // Nicer function for creating an ADC or PWM pin
//--------------------------------------------------
IOType get_type(void);
IOType get_type(void);
uint8_t get_mode(void);
void set_mode(uint8_t mode);
@ -149,7 +150,7 @@ namespace pimoroni {
uint32_t timeout;
bool debug;
float vref;
float vref;
int16_t encoder_offset[4];;
int16_t encoder_last[4];
Pin pins[NUM_PINS];
@ -159,8 +160,8 @@ namespace pimoroni {
// Constructors/Destructor
//--------------------------------------------------
public:
Nuvoton(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt, uint8_t address = DEFAULT_I2C_ADDRESS, uint32_t timeout = 1, bool debug = false);
Nuvoton(uint8_t address = DEFAULT_I2C_ADDRESS, uint32_t timeout = 1, bool debug = false);
IOExpander(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt, uint8_t address = DEFAULT_I2C_ADDRESS, uint32_t timeout = 1, bool debug = false);
IOExpander(uint8_t address = DEFAULT_I2C_ADDRESS, uint32_t timeout = 1, bool debug = false);
//--------------------------------------------------
@ -169,53 +170,44 @@ namespace pimoroni {
public:
bool init(bool skip_chip_id_check = false);
//--------------------------------------------------
// For print access in micropython
i2c_inst_t* get_i2c() const;
int get_sda() const;
int get_scl() const;
int get_int() const;
uint16_t get_chip_id();
void set_addr(uint8_t address);
float get_adc_vref();
void set_adc_vref(float vref);
//--------------------------------------------------
void enable_interrupt_out(bool pin_swap = false);
void disable_interrupt_out();
uint8_t get_interrupt_flag();
void clear_interrupt_flag();
bool set_pin_interrupt(uint8_t pin, bool enabled);
void set_interrupt_callback(void (*callback)());
//--------------------------------------------------
void pwm_load(bool wait_for_load = true);
bool pwm_loading();
void pwm_clear(bool wait_for_clear = true);
bool pwm_clearing();
bool set_pwm_control(uint8_t divider);
void set_pwm_period(uint16_t value, bool load = true);
//--------------------------------------------------
uint8_t get_mode(uint8_t pin);
void set_mode(uint8_t pin, uint8_t mode, bool schmitt_trigger = false, bool invert = false);
int16_t input(uint8_t pin, uint32_t adc_timeout = 1);
float input_as_voltage(uint8_t pin, uint32_t adc_timeout = 1);
void output(uint8_t pin, uint16_t value, bool load = true);
//--------------------------------------------------
void setup_rotary_encoder(uint8_t channel, uint8_t pinA, uint8_t pinB, uint8_t pinC = 0, bool count_microsteps = false);
int16_t read_rotary_encoder(uint8_t channel);
//--------------------------------------------------
private:
uint8_t i2c_reg_read_uint8(uint8_t reg);
void i2c_reg_write_uint8(uint8_t reg, uint8_t value);

Wyświetl plik

@ -1 +0,0 @@
include(nuvoton.cmake)

Wyświetl plik

@ -1,9 +1,12 @@
add_subdirectory(breakout_dotmatrix)
add_subdirectory(breakout_encoder)
add_subdirectory(breakout_ltr559)
add_subdirectory(breakout_colourlcd160x80)
add_subdirectory(breakout_roundlcd)
add_subdirectory(breakout_rgbmatrix5x5)
add_subdirectory(breakout_matrix11x7)
add_subdirectory(breakout_mics6814)
add_subdirectory(breakout_potentiometer)
add_subdirectory(breakout_trackball)
add_subdirectory(breakout_sgp30)
add_subdirectory(breakout_colourlcd240x240)

Wyświetl plik

@ -0,0 +1,12 @@
set(OUTPUT_NAME encoder_demo)
add_executable(
${OUTPUT_NAME}
demo.cpp
)
# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_encoder)
# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -0,0 +1,23 @@
#include "pico/stdlib.h"
#include "breakout_encoder.hpp"
using namespace pimoroni;
BreakoutEncoder enc;
int main() {
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
enc.init();
while(true) {
gpio_put(PICO_DEFAULT_LED_PIN, true);
sleep_ms(1000);
gpio_put(PICO_DEFAULT_LED_PIN, false);
sleep_ms(1000);
}
return 0;
}

Wyświetl plik

@ -0,0 +1,12 @@
set(OUTPUT_NAME ioexpander_demo)
add_executable(
${OUTPUT_NAME}
demo.cpp
)
# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_ioexpander)
# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -0,0 +1,23 @@
#include "pico/stdlib.h"
#include "breakout_ioexpander.hpp"
using namespace pimoroni;
BreakoutIOExpander ioe;
int main() {
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
ioe.init();
while(true) {
gpio_put(PICO_DEFAULT_LED_PIN, true);
sleep_ms(1000);
gpio_put(PICO_DEFAULT_LED_PIN, false);
sleep_ms(1000);
}
return 0;
}

Wyświetl plik

@ -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})

Wyświetl plik

@ -0,0 +1,23 @@
#include "pico/stdlib.h"
#include "breakout_mics6814.hpp"
using namespace pimoroni;
BreakoutMICS6814 ioe;
int main() {
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
ioe.init();
while(true) {
gpio_put(PICO_DEFAULT_LED_PIN, true);
sleep_ms(1000);
gpio_put(PICO_DEFAULT_LED_PIN, false);
sleep_ms(1000);
}
return 0;
}

Wyświetl plik

@ -0,0 +1,12 @@
set(OUTPUT_NAME potentiometer_demo)
add_executable(
${OUTPUT_NAME}
demo.cpp
)
# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_potentiometer)
# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -0,0 +1,23 @@
#include "pico/stdlib.h"
#include "breakout_potentiometer.hpp"
using namespace pimoroni;
BreakoutPotentiometer pot;
int main() {
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
pot.init();
while(true) {
gpio_put(PICO_DEFAULT_LED_PIN, true);
sleep_ms(1000);
gpio_put(PICO_DEFAULT_LED_PIN, false);
sleep_ms(1000);
}
return 0;
}

Wyświetl plik

@ -8,4 +8,4 @@ target_sources(${LIB_NAME} INTERFACE
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib nuvoton)
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib ioexpander)

Wyświetl plik

@ -1,5 +1,86 @@
#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_addr(uint8_t i2c_addr) {
ioe.set_addr(i2c_addr);
}
bool BreakoutEncoder::get_direction(void) {
return direction_cw;
}
void BreakoutEncoder::set_direction(bool clockwise) {
direction_cw = clockwise;
}
void BreakoutEncoder::set_brightness(float brightness) {
this->brightness = std::min(std::max(brightness, 0.01f), 1.0f);
// Calculate a period large enough to get 0-255 steps at the desired brightness
uint16_t period = (uint16_t)(255.0f / this->brightness);
ioe.set_pwm_period(period);
}
void BreakoutEncoder::set_led(uint8_t r, uint8_t g, uint8_t b) {
ioe.output(LED_R, r, false); // Hold off pwm load until the last
ioe.output(LED_G, g, false); // Hold off pwm load until the last
ioe.output(LED_B, b); // Loads all 3 pwms
}
bool BreakoutEncoder::available() {
return (ioe.get_interrupt_flag() > 0);
}
int16_t BreakoutEncoder::read() {
int16_t count = ioe.read_rotary_encoder(ENC_CHANNEL);
if(!direction_cw)
count = 0 - count;
ioe.clear_interrupt_flag();
return count;
}
}

Wyświetl plik

@ -1,8 +1,93 @@
#pragma once
#include "../../drivers/nuvoton/nuvoton.hpp"
#include "../../drivers/ioexpander/ioexpander.hpp"
namespace pimoroni {
typedef Nuvoton BreakoutEncoder;
}
class BreakoutEncoder {
//--------------------------------------------------
// Enums
//--------------------------------------------------
public:
enum Direction : bool {
DIRECTION_CW = true,
DIRECTION_CCW = false
};
//--------------------------------------------------
// Constants
//--------------------------------------------------
public:
static const uint8_t DEFAULT_I2C_ADDRESS = 0x0F;
static constexpr float DEFAULT_BRIGHTNESS = 1.0f; //Effectively the maximum fraction of the period that the LED will be on
static const bool DEFAULT_DIRECTION = DIRECTION_CW;
static const uint8_t PIN_UNUSED = UINT8_MAX;
static const uint32_t DEFAULT_TIMEOUT = 1;
private:
static const uint8_t LED_R = 1;
static const uint8_t LED_G = 7;
static const uint8_t LED_B = 2;
static const uint8_t ENC_TERM_A = 12;
static const uint8_t ENC_TERM_B = 3;
static const uint8_t ENC_TERM_C = 11;
static const uint8_t ENC_CHANNEL = 1;
static const bool INVERT_OUTPUT = true; //true for common cathode, false for common anode
//--------------------------------------------------
// Variables
//--------------------------------------------------
private:
IOExpander ioe;
bool direction_cw = DEFAULT_DIRECTION;
float brightness = DEFAULT_BRIGHTNESS;
uint8_t interrupt_pin = PIN_UNUSED; // A local copy of the value passed to the IOExpander, used in initialisation
//--------------------------------------------------
// Constructors/Destructor
//--------------------------------------------------
public:
BreakoutEncoder() :
ioe(DEFAULT_I2C_ADDRESS) {}
BreakoutEncoder(uint8_t address) :
ioe(address) {}
BreakoutEncoder(i2c_inst_t *i2c, uint8_t address, uint8_t sda, uint8_t scl, uint8_t interrupt = PIN_UNUSED, uint32_t timeout = DEFAULT_TIMEOUT) :
ioe(i2c, address, sda, scl, interrupt, timeout),
interrupt_pin(interrupt) {}
//--------------------------------------------------
// Methods
//--------------------------------------------------
public:
bool init(bool skip_chip_id_check = false);
// For print access in micropython
i2c_inst_t* get_i2c() const;
int get_sda() const;
int get_scl() const;
int get_int() const;
// Calls through to IOExpander class
void set_addr(uint8_t i2c_addr);
// Encoder breakout specific
bool get_direction();
void set_direction(bool clockwise);
void set_brightness(float brightness);
void set_led(uint8_t r, uint8_t g, uint8_t b);
bool available();
int16_t read();
};
}

Wyświetl plik

@ -8,4 +8,4 @@ target_sources(${LIB_NAME} INTERFACE
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib nuvoton)
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib ioexpander)

Wyświetl plik

@ -1,8 +1,8 @@
#pragma once
#include "../../drivers/nuvoton/nuvoton.hpp"
#include "../../drivers/ioexpander/ioexpander.hpp"
namespace pimoroni {
typedef Nuvoton BreakoutIOExpander;
typedef IOExpander BreakoutIOExpander;
}

Wyświetl plik

@ -8,4 +8,4 @@ target_sources(${LIB_NAME} INTERFACE
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib nuvoton)
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib ioexpander)

Wyświetl plik

@ -1,5 +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_OUT);
ioe.output(MICS_HEATER_EN, IOExpander::LOW);
// Calculate a period large enough to get 0-255 steps at the desired brightness
uint16_t period = (uint16_t)(255.0f / brightness);
ioe.set_pwm_period(period);
ioe.set_pwm_control(2); // PWM as fast as we can to avoid LED flicker
ioe.set_mode(LED_R, IOExpander::PIN_PWM, false, INVERT_OUTPUT);
ioe.set_mode(LED_G, IOExpander::PIN_PWM, false, INVERT_OUTPUT);
ioe.set_mode(LED_B, IOExpander::PIN_PWM, false, INVERT_OUTPUT);
success = true;
}
return success;
}
i2c_inst_t* BreakoutMICS6814::get_i2c() const {
return ioe.get_i2c();
}
int BreakoutMICS6814::get_sda() const {
return ioe.get_sda();
}
int BreakoutMICS6814::get_scl() const {
return ioe.get_scl();
}
int BreakoutMICS6814::get_int() const {
return ioe.get_int();
}
void BreakoutMICS6814::set_addr(uint8_t i2c_addr) {
ioe.set_addr(i2c_addr);
}
float BreakoutMICS6814::get_adc_vref(void) {
return ioe.get_adc_vref();
}
void BreakoutMICS6814::set_adc_vref(float vref) {
ioe.set_adc_vref(vref);
}
void BreakoutMICS6814::set_brightness(float brightness) {
this->brightness = std::min(std::max(brightness, 0.01f), 1.0f);
// Calculate a period large enough to get 0-255 steps at the desired brightness
uint16_t period = (uint16_t)(255.0f / this->brightness);
ioe.set_pwm_period(period);
}
void BreakoutMICS6814::set_led(uint8_t r, uint8_t g, uint8_t b) {
ioe.output(LED_R, r, false); // Hold off pwm load until the last
ioe.output(LED_G, g, false); // Hold off pwm load until the last
ioe.output(LED_B, b); // Loads all 3 pwms
}
void BreakoutMICS6814::set_heater(bool on) {
ioe.output(MICS_HEATER_EN, on ? IOExpander::LOW : IOExpander::HIGH);
}
void BreakoutMICS6814::disable_heater() {
ioe.output(MICS_HEATER_EN, IOExpander::HIGH);
ioe.set_mode(MICS_HEATER_EN, IOExpander::PIN_IN);
}
float BreakoutMICS6814::get_raw_ref(uint32_t adc_timeout) {
return ioe.input_as_voltage(MICS_VREF, adc_timeout);
}
float BreakoutMICS6814::get_raw_red(uint32_t adc_timeout) {
return ioe.input_as_voltage(MICS_RED, adc_timeout);
}
float BreakoutMICS6814::get_raw_nh3(uint32_t adc_timeout) {
return ioe.input_as_voltage(MICS_NH3, adc_timeout);
}
float BreakoutMICS6814::get_raw_oxd(uint32_t adc_timeout) {
return ioe.input_as_voltage(MICS_OX, adc_timeout);
}
BreakoutMICS6814::Reading BreakoutMICS6814::read_all(uint32_t adc_timeout) {
BreakoutMICS6814::Reading reading;
reading.reducing = read_reducing(adc_timeout);
reading.nh3 = read_nh3(adc_timeout);
reading.oxidising = read_oxidising(adc_timeout);
reading.ref = read_ref(adc_timeout);
return reading;
}
float BreakoutMICS6814::read_ref(uint32_t adc_timeout) {
float ref = get_raw_ref(adc_timeout);
if(ref == -1)
ref = 0;
return ref;
}
float BreakoutMICS6814::read_reducing(uint32_t adc_timeout) {
float vref = ioe.get_adc_vref();
float red = get_raw_red(adc_timeout);
if((red != -1) && (vref != red))
red = (red * 56000.0f) / (vref - red);
else
red = 0;
return red;
}
float BreakoutMICS6814::read_nh3(uint32_t adc_timeout) {
float vref = ioe.get_adc_vref();
float nh3 = get_raw_red(adc_timeout);
if((nh3 != -1) && (vref != nh3))
nh3 = (nh3 * 56000.0f) / (vref - nh3);
else
nh3 = 0;
return nh3;
}
float BreakoutMICS6814::read_oxidising(uint32_t adc_timeout) {
float vref = ioe.get_adc_vref();
float oxd = get_raw_red(adc_timeout);
if((oxd != -1) && (vref != oxd))
oxd = (oxd * 56000.0f) / (vref - oxd);
else
oxd = 0;
return oxd;
}
}

Wyświetl plik

@ -1,8 +1,103 @@
#pragma once
#include "../../drivers/nuvoton/nuvoton.hpp"
#include "../../drivers/ioexpander/ioexpander.hpp"
namespace pimoroni {
typedef Nuvoton BreakoutMICS6814;
}
class BreakoutMICS6814 {
//--------------------------------------------------
// Constants
//--------------------------------------------------
public:
static const uint8_t DEFAULT_I2C_ADDRESS = 0x19;
static constexpr float DEFAULT_BRIGHTNESS = 1.0f; //Effectively the maximum fraction of the period that the LED will be on
static const uint8_t PIN_UNUSED = UINT8_MAX;
static const uint32_t DEFAULT_TIMEOUT = 1;
static const uint32_t DEFAULT_ADC_TIMEOUT = 1;
private:
static const uint8_t LED_R = 3;
static const uint8_t LED_G = 7;
static const uint8_t LED_B = 2;
static const uint8_t MICS_VREF = 14;
static const uint8_t MICS_RED = 12;
static const uint8_t MICS_NH3 = 11;
static const uint8_t MICS_OX = 13;
static const uint8_t MICS_HEATER_EN = 1;
static const bool INVERT_OUTPUT = true; //true for common cathode, false for common anode
//--------------------------------------------------
// Substructures
//--------------------------------------------------
private:
struct Reading {
float ref;
float reducing;
float nh3;
float oxidising;
};
//--------------------------------------------------
// Variables
//--------------------------------------------------
private:
IOExpander ioe;
float brightness = DEFAULT_BRIGHTNESS;
//--------------------------------------------------
// Constructors/Destructor
//--------------------------------------------------
public:
BreakoutMICS6814() :
ioe(DEFAULT_I2C_ADDRESS) {}
BreakoutMICS6814(uint8_t address) :
ioe(address) {}
BreakoutMICS6814(i2c_inst_t *i2c, uint8_t address, uint8_t sda, uint8_t scl, uint8_t interrupt = PIN_UNUSED, uint32_t timeout = DEFAULT_TIMEOUT) :
ioe(i2c, address, sda, scl, interrupt, timeout) {}
//--------------------------------------------------
// Methods
//--------------------------------------------------
public:
bool init(bool skip_chip_id_check = false);
// For print access in micropython
i2c_inst_t* get_i2c() const;
int get_sda() const;
int get_scl() const;
int get_int() const;
// Calls through to IOExpander class
void set_addr(uint8_t i2c_addr);
float get_adc_vref();
void set_adc_vref(float vref);
// MICS breakout specific
void set_brightness(float brightness);
void set_led(uint8_t r, uint8_t g, uint8_t b);
void set_heater(bool on);
void disable_heater();
float get_raw_ref(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT);
float get_raw_red(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT);
float get_raw_nh3(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT);
float get_raw_oxd(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT);
Reading read_all(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT);
float read_ref(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT);
float read_reducing(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT);
float read_nh3(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT);
float read_oxidising(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT);
};
}

Wyświetl plik

@ -8,4 +8,4 @@ target_sources(${LIB_NAME} INTERFACE
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib nuvoton)
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib ioexpander)

Wyświetl plik

@ -1,5 +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_cw) {
// Clockwise increasing
ioe.output(POT_TERM_A, IOExpander::LOW);
ioe.output(POT_TERM_B, IOExpander::HIGH);
}
else {
// Counter clockwise increasing
ioe.output(POT_TERM_A, IOExpander::HIGH);
ioe.output(POT_TERM_B, IOExpander::LOW);
}
// Calculate a period large enough to get 0-255 steps at the desired brightness
uint16_t period = (uint16_t)(255.0f / brightness);
ioe.set_pwm_period(period);
ioe.set_pwm_control(2); // PWM as fast as we can to avoid LED flicker
ioe.set_mode(LED_R, IOExpander::PIN_PWM, false, INVERT_OUTPUT);
ioe.set_mode(LED_G, IOExpander::PIN_PWM, false, INVERT_OUTPUT);
ioe.set_mode(LED_B, IOExpander::PIN_PWM, false, INVERT_OUTPUT);
success = true;
}
return success;
}
i2c_inst_t* BreakoutPotentiometer::get_i2c() const {
return ioe.get_i2c();
}
int BreakoutPotentiometer::get_sda() const {
return ioe.get_sda();
}
int BreakoutPotentiometer::get_scl() const {
return ioe.get_scl();
}
int BreakoutPotentiometer::get_int() const {
return ioe.get_int();
}
void BreakoutPotentiometer::set_addr(uint8_t i2c_addr) {
ioe.set_addr(i2c_addr);
}
float BreakoutPotentiometer::get_adc_vref(void) {
return ioe.get_adc_vref();
}
void BreakoutPotentiometer::set_adc_vref(float vref) {
ioe.set_adc_vref(vref);
}
bool BreakoutPotentiometer::get_direction(void) {
return direction_cw;
}
void BreakoutPotentiometer::set_direction(bool clockwise) {
if(clockwise) {
// Clockwise increasing
ioe.output(POT_TERM_A, IOExpander::LOW);
ioe.output(POT_TERM_B, IOExpander::HIGH);
}
else {
// Counter clockwise increasing
ioe.output(POT_TERM_A, IOExpander::HIGH);
ioe.output(POT_TERM_B, IOExpander::LOW);
}
direction_cw = clockwise;
}
void BreakoutPotentiometer::set_brightness(float brightness) {
this->brightness = std::min(std::max(brightness, 0.01f), 1.0f);
// Calculate a period large enough to get 0-255 steps at the desired brightness
uint16_t period = (uint16_t)(255.0f / this->brightness);
ioe.set_pwm_period(period);
}
void BreakoutPotentiometer::set_led(uint8_t r, uint8_t g, uint8_t b) {
ioe.output(LED_R, r, false); // Hold off pwm load until the last
ioe.output(LED_G, g, false); // Hold off pwm load until the last
ioe.output(LED_B, b); // Loads all 3 pwms
}
int16_t BreakoutPotentiometer::read(uint32_t adc_timeout) {
return ioe.input(POT_INPUT, adc_timeout);
}
float BreakoutPotentiometer::read_as_percent(uint32_t adc_timeout) {
return (ioe.input_as_voltage(POT_INPUT, adc_timeout) / ioe.get_adc_vref());
}
}

Wyświetl plik

@ -1,8 +1,93 @@
#pragma once
#include "../../drivers/nuvoton/nuvoton.hpp"
#include "../../drivers/ioexpander/ioexpander.hpp"
namespace pimoroni {
typedef Nuvoton BreakoutPotentiometer;
}
class BreakoutPotentiometer {
//--------------------------------------------------
// Enums
//--------------------------------------------------
public:
enum Direction : bool {
DIRECTION_CW = true,
DIRECTION_CCW = false
};
//--------------------------------------------------
// Constants
//--------------------------------------------------
public:
static const uint8_t DEFAULT_I2C_ADDRESS = 0x0E;
static constexpr float DEFAULT_BRIGHTNESS = 1.0f; //Effectively the maximum fraction of the period that the LED will be on
static const bool DEFAULT_DIRECTION = DIRECTION_CW;
static const uint8_t PIN_UNUSED = UINT8_MAX;
static const uint32_t DEFAULT_TIMEOUT = 1;
static const uint32_t DEFAULT_ADC_TIMEOUT = 1;
private:
static const uint8_t LED_R = 1;
static const uint8_t LED_G = 7;
static const uint8_t LED_B = 2;
static const uint8_t POT_TERM_A = 12;
static const uint8_t POT_TERM_B = 3;
static const uint8_t POT_INPUT = 11;
static const bool INVERT_OUTPUT = true; //true for common cathode, false for common anode
//--------------------------------------------------
// Variables
//--------------------------------------------------
private:
IOExpander ioe;
bool direction_cw = DEFAULT_DIRECTION;
float brightness = DEFAULT_BRIGHTNESS;
//--------------------------------------------------
// Constructors/Destructor
//--------------------------------------------------
public:
BreakoutPotentiometer() :
ioe(DEFAULT_I2C_ADDRESS) {}
BreakoutPotentiometer(uint8_t address) :
ioe(address) {}
BreakoutPotentiometer(i2c_inst_t *i2c, uint8_t address, uint8_t sda, uint8_t scl, uint8_t interrupt = PIN_UNUSED, uint32_t timeout = DEFAULT_TIMEOUT) :
ioe(i2c, address, sda, scl, interrupt, timeout) {}
//--------------------------------------------------
// Methods
//--------------------------------------------------
public:
bool init(bool skip_chip_id_check = false);
// For print access in micropython
i2c_inst_t* get_i2c() const;
int get_sda() const;
int get_scl() const;
int get_int() const;
// Calls through to IOExpander class
void set_addr(uint8_t i2c_addr);
float get_adc_vref();
void set_adc_vref(float vref);
// Potentiometer breakout specific
bool get_direction();
void set_direction(bool clockwise);
void set_brightness(float brightness);
void set_led(uint8_t r, uint8_t g, uint8_t b);
int16_t read(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT);
float read_as_percent(uint32_t adc_timeout = DEFAULT_ADC_TIMEOUT);
};
}