From b429f0ddecca1b6cd3ae46a71dc325b35b780465 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 21 Sep 2022 12:10:41 +1000 Subject: [PATCH] Add a basic i2c gpio expander implementation --- main/CMakeLists.txt | 2 +- main/gay-ipod-fw.cpp | 7 +++++ main/gpio-expander.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++ main/gpio-expander.h | 46 +++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 main/gpio-expander.cpp create mode 100644 main/gpio-expander.h diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 97833c88..4a1fe814 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,2 +1,2 @@ -idf_component_register(SRCS "gay-ipod-fw.cpp" +idf_component_register(SRCS "gay-ipod-fw.cpp" "gpio-expander.cpp" INCLUDE_DIRS ".") diff --git a/main/gay-ipod-fw.cpp b/main/gay-ipod-fw.cpp index 15d7b6eb..e2bdf648 100644 --- a/main/gay-ipod-fw.cpp +++ b/main/gay-ipod-fw.cpp @@ -1,10 +1,12 @@ #include +#include "gpio-expander.h" #include "esp_log.h" #include "driver/gpio.h" #include "driver/i2c.h" #include "driver/spi_common.h" #include "driver/spi_master.h" +#include "gpio-expander.h" #include "hal/gpio_types.h" #include "hal/spi_types.h" @@ -83,4 +85,9 @@ extern "C" void app_main(void) ESP_LOGI(TAG, "Initialising peripherals"); init_i2c(); init_spi(); + + gay_ipod::GpioExpander expander; + expander.Write(); + + while (1) {} } diff --git a/main/gpio-expander.cpp b/main/gpio-expander.cpp new file mode 100644 index 00000000..3aadb63e --- /dev/null +++ b/main/gpio-expander.cpp @@ -0,0 +1,67 @@ +#include "gpio-expander.h" + +namespace gay_ipod { + +GpioExpander::GpioExpander() { +} + +GpioExpander::~GpioExpander() { +} + +esp_err_t GpioExpander::Write() { + i2c_cmd_handle_t handle = i2c_cmd_link_create(); + if (handle == NULL) { + return ESP_ERR_NO_MEM; + } + + // Technically enqueuing these commands could fail, but we don't worry about + // it because that would indicate some really very badly wrong more generally. + i2c_master_start(handle); + i2c_master_write_byte(handle, (PCA8575_ADDRESS << 1 | I2C_MASTER_WRITE), true); + i2c_master_write_byte(handle, port_a_, true); + i2c_master_write_byte(handle, port_b_, true); + i2c_master_stop(handle); + + // TODO: timeout + esp_err_t ret = i2c_master_cmd_begin(0, handle, 0); + + i2c_cmd_link_delete(handle); + return ret; +} + +esp_err_t GpioExpander::Read() { + i2c_cmd_handle_t handle = i2c_cmd_link_create(); + if (handle == NULL) { + return ESP_ERR_NO_MEM; + } + + // Technically enqueuing these commands could fail, but we don't worry about + // it because that would indicate some really very badly wrong more generally. + i2c_master_start(handle); + i2c_master_write_byte(handle, (PCA8575_ADDRESS << 1 | I2C_MASTER_READ), true); + i2c_master_read_byte(handle, &input_a_, I2C_MASTER_ACK); + i2c_master_read_byte(handle, &input_b_, I2C_MASTER_LAST_NACK); + i2c_master_stop(handle); + + // TODO: timeout + esp_err_t ret = i2c_master_cmd_begin(0, handle, 0); + + i2c_cmd_link_delete(handle); + return ret; +} + +bool GpioExpander::charge_power_ok(void) { + // Active-low. + return (input_a_ & (1 << 4)) == 0; +} + +bool GpioExpander::headphone_detect(void) { + // Active-low. + return (input_b_ & (1 << 0)) == 0; // TODO. +} + +uint8_t GpioExpander::key_states(void) { + return input_b_ & 0b00111111; +} + +} // namespace gay_ipod diff --git a/main/gpio-expander.h b/main/gpio-expander.h new file mode 100644 index 00000000..c63ee431 --- /dev/null +++ b/main/gpio-expander.h @@ -0,0 +1,46 @@ +#ifndef GPIO_EXPANDER_H +#define GPIO_EXPANDER_H + +#include + +#include "esp_check.h" +#include "esp_err.h" +#include "driver/i2c.h" + +#define PCA8575_ADDRESS (0x20) + +namespace gay_ipod { + +/** + * PCA8575 + */ +class GpioExpander { + public: + GpioExpander(); + ~GpioExpander(); + + esp_err_t Write(void); + esp_err_t Read(void); + + bool charge_power_ok(void); + bool headphone_detect(void); + uint8_t key_states(void); + + // Not copyable or movable. + // TODO: maybe this could be movable? + GpioExpander(const GpioExpander&) = delete; + GpioExpander& operator=(const GpioExpander&) = delete; + + private: + // All power switches low, both CS pins high, active-low PWR_OK high. + uint8_t port_a_ = 0b00001011; + // DAC mute output low, everything eelse is input and so held high. + uint8_t port_b_ = 0b10111111; + + uint8_t input_a_ = 0; + uint8_t input_b_ = 0; +}; + +} // namespace gay_ipod + +#endif