diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 460df592..32c6169c 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(analog) +add_subdirectory(analogmux) add_subdirectory(esp32spi) add_subdirectory(ioexpander) add_subdirectory(ltp305) diff --git a/drivers/analogmux/CMakeLists.txt b/drivers/analogmux/CMakeLists.txt new file mode 100644 index 00000000..5265bb64 --- /dev/null +++ b/drivers/analogmux/CMakeLists.txt @@ -0,0 +1 @@ +include(analogmux.cmake) \ No newline at end of file diff --git a/drivers/analogmux/analogmux.cmake b/drivers/analogmux/analogmux.cmake new file mode 100644 index 00000000..a6feca28 --- /dev/null +++ b/drivers/analogmux/analogmux.cmake @@ -0,0 +1,11 @@ +set(DRIVER_NAME analogmux) +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) \ No newline at end of file diff --git a/drivers/analogmux/analogmux.cpp b/drivers/analogmux/analogmux.cpp new file mode 100644 index 00000000..c1e36094 --- /dev/null +++ b/drivers/analogmux/analogmux.cpp @@ -0,0 +1,80 @@ +#include "analogmux.hpp" +#include + +namespace pimoroni { + AnalogMux::AnalogMux(uint addr0_pin, uint addr1_pin, uint addr2_pin, + uint en_pin, uint muxed_pin) + : addr0_pin(addr0_pin), addr1_pin(addr1_pin), addr2_pin(addr2_pin) + , en_pin(en_pin), muxed_pin(muxed_pin), pull_ups(0), pull_downs(0) { + + gpio_init(addr0_pin); + gpio_set_dir(addr0_pin, GPIO_OUT); + max_address = 0b001; + + if(addr1_pin != PIN_UNUSED) { + gpio_init(addr1_pin); + gpio_set_dir(addr1_pin, GPIO_OUT); + max_address = 0b011; + + if(addr2_pin != PIN_UNUSED) { + gpio_init(addr2_pin); + gpio_set_dir(addr2_pin, GPIO_OUT); + max_address = 0b111; + } + } + + if(en_pin != PIN_UNUSED) { + gpio_init(en_pin); + gpio_set_dir(en_pin, GPIO_OUT); + } + } + + void AnalogMux::select(uint8_t address) { + if(address <= max_address) { + bool to_pull_up = (pull_ups & (1u << address)); + bool to_pull_down = (pull_downs & (1u << address)); + if((muxed_pin != PIN_UNUSED) && !(to_pull_up || to_pull_down)) { + gpio_disable_pulls(muxed_pin); + } + + gpio_put(addr0_pin, address & 0b001); + + if(addr1_pin != PIN_UNUSED) { + gpio_put(addr1_pin, address & 0b010); + } + + if(addr2_pin != PIN_UNUSED) { + gpio_put(addr2_pin, address & 0b100); + } + + if(en_pin != PIN_UNUSED) { + gpio_put(en_pin, true); + } + + if((muxed_pin != PIN_UNUSED) && (to_pull_up || to_pull_down)) { + gpio_set_pulls(muxed_pin, to_pull_up, to_pull_down); + } + sleep_us(10); // Add a delay to let the pins settle before taking a reading + } + } + + void AnalogMux::disable() { + if(en_pin != PIN_UNUSED) { + gpio_put(en_pin, false); + } + } + + void AnalogMux::configure_pulls(uint8_t address, bool pullup, bool pulldown) { + if(address <= max_address) { + if(pullup) + pull_ups |= (1u << address); + else + pull_ups &= ~(1u << address); + + if(pulldown) + pull_downs |= (1u << address); + else + pull_downs &= ~(1u << address); + } + } +} \ No newline at end of file diff --git a/drivers/analogmux/analogmux.hpp b/drivers/analogmux/analogmux.hpp new file mode 100644 index 00000000..63236848 --- /dev/null +++ b/drivers/analogmux/analogmux.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include "pico/stdlib.h" +#include "common/pimoroni_common.hpp" + +namespace pimoroni { + + class AnalogMux { + public: + AnalogMux(uint addr0_pin, uint addr1_pin = PIN_UNUSED, uint addr2_pin = PIN_UNUSED, + uint en_pin = PIN_UNUSED, uint muxed_pin = PIN_UNUSED); + + void select(uint8_t address); + void disable(); + void configure_pulls(uint8_t address, bool pullup, bool pulldown); + + private: + uint addr0_pin; + uint addr1_pin; + uint addr2_pin; + uint en_pin; + uint muxed_pin; + uint max_address; + uint8_t pull_ups; + uint8_t pull_downs; + }; + +} \ No newline at end of file