diff options
| -rw-r--r-- | src/drivers/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/drivers/gpios.cpp | 34 | ||||
| -rw-r--r-- | src/drivers/haptics.cpp | 46 | ||||
| -rw-r--r-- | src/drivers/i2c.cpp | 85 | ||||
| -rw-r--r-- | src/drivers/include/drivers/gpios.hpp | 3 | ||||
| -rw-r--r-- | src/drivers/include/drivers/haptics.hpp | 3 | ||||
| -rw-r--r-- | src/drivers/include/drivers/i2c.hpp | 80 | ||||
| -rw-r--r-- | src/drivers/include/drivers/samd.hpp | 2 | ||||
| -rw-r--r-- | src/drivers/include/drivers/touchwheel.hpp | 1 | ||||
| -rw-r--r-- | src/drivers/include/drivers/wm8523.hpp | 2 | ||||
| -rw-r--r-- | src/drivers/samd.cpp | 111 | ||||
| -rw-r--r-- | src/drivers/touchwheel.cpp | 33 | ||||
| -rw-r--r-- | src/drivers/wm8523.cpp | 39 | ||||
| -rw-r--r-- | src/tangara/system_fsm/booting.cpp | 2 |
14 files changed, 142 insertions, 301 deletions
diff --git a/src/drivers/CMakeLists.txt b/src/drivers/CMakeLists.txt index fea5780f..da7c37cf 100644 --- a/src/drivers/CMakeLists.txt +++ b/src/drivers/CMakeLists.txt @@ -8,5 +8,5 @@ idf_component_register( "samd.cpp" "wm8523.cpp" "nvs.cpp" "haptics.cpp" "spiffs.cpp" "pcm_buffer.cpp" INCLUDE_DIRS "include" REQUIRES "esp_adc" "fatfs" "result" "lvgl" "nvs_flash" "spiffs" "bt" - "tasks" "tinyfsm" "util" "libcppbor" "driver") + "tasks" "tinyfsm" "util" "libcppbor" "driver" "esp_driver_i2c") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/drivers/gpios.cpp b/src/drivers/gpios.cpp index cf7cf14e..8b9684ab 100644 --- a/src/drivers/gpios.cpp +++ b/src/drivers/gpios.cpp @@ -5,11 +5,13 @@ */ #include "drivers/gpios.hpp" +#include <stdint.h> #include <cstdint> #include "assert.h" #include "driver/gpio.h" +#include "driver/i2c_master.h" #include "esp_attr.h" #include "esp_err.h" #include "esp_intr_alloc.h" @@ -78,6 +80,14 @@ Gpios::Gpios(bool invert_lock) inputs_(0), invert_lock_switch_(invert_lock) { gpio_set_direction(kIntPin, GPIO_MODE_INPUT); + i2c_device_config_t config = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = kPca8575Address, + .scl_speed_hz = 400'000, + .scl_wait_us = 0, + .flags = {.disable_ack_check = false}, + }; + ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_handle(), &config, &i2c_)); } Gpios::~Gpios() {} @@ -105,15 +115,9 @@ auto Gpios::ShouldRead() -> bool { auto Gpios::Flush() -> bool { std::pair<uint8_t, uint8_t> ports_ab = unpack(ports_); - - I2CTransaction transaction; - transaction.start() - .write_addr(kPca8575Address, I2C_MASTER_WRITE) - .write_ack(ports_ab.first, ports_ab.second) - .stop(); - + uint8_t data[] = {ports_ab.first, ports_ab.second}; has_written_ = true; - return transaction.Execute() == ESP_OK; + return i2c_master_transmit(i2c_, data, 2, 100) == ESP_OK; } auto Gpios::Get(Pin pin) const -> bool { @@ -130,20 +134,12 @@ auto Gpios::IsLocked() const -> bool { } auto Gpios::Read() -> bool { - uint8_t input_a, input_b; - - I2CTransaction transaction; - transaction.start() - .write_addr(kPca8575Address, I2C_MASTER_READ) - .read(&input_a, I2C_MASTER_ACK) - .read(&input_b, I2C_MASTER_LAST_NACK) - .stop(); - - esp_err_t ret = transaction.Execute(); + uint8_t data[] = {0, 0}; + esp_err_t ret = i2c_master_receive(i2c_, data, 2, 100); if (ret != ESP_OK) { return false; } - inputs_ = pack(input_a, input_b); + inputs_ = pack(data[0], data[1]); return true; } diff --git a/src/drivers/haptics.cpp b/src/drivers/haptics.cpp index 8e8e5fed..4abf13e4 100644 --- a/src/drivers/haptics.cpp +++ b/src/drivers/haptics.cpp @@ -15,6 +15,7 @@ #include "assert.h" #include "driver/gpio.h" #include "driver/i2c.h" +#include "driver/i2c_master.h" #include "drivers/nvs.hpp" #include "esp_err.h" #include "esp_log.h" @@ -30,6 +31,19 @@ static constexpr char kTag[] = "haptics"; static constexpr uint8_t kHapticsAddress = 0x5A; Haptics::Haptics(NvsStorage& nvs) { + i2c_device_config_t config = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = kHapticsAddress, + .scl_speed_hz = 100'000, + .scl_wait_us = 0, + .flags = + { + // FIXME: Why does the driver sometimes NACK? + .disable_ack_check = true, + }, + }; + ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_handle(), &config, &i2c_)); + // Bring the driver out of standby, and put it into calibration mode. WriteRegister(Register::kMode, 0b00000111); @@ -134,13 +148,8 @@ Haptics::Haptics(NvsStorage& nvs) { Haptics::~Haptics() {} void Haptics::WriteRegister(Register reg, uint8_t val) { - uint8_t regRaw = static_cast<uint8_t>(reg); - I2CTransaction transaction; - transaction.start() - .write_addr(kHapticsAddress, I2C_MASTER_WRITE) - .write_ack(regRaw, val) - .stop(); - esp_err_t res = transaction.Execute(1); + uint8_t cmd[] = {static_cast<uint8_t>(reg), val}; + esp_err_t res = i2c_master_transmit(i2c_, cmd, 2, 100); if (res != ESP_OK) { ESP_LOGW(kTag, "write failed: %s", esp_err_to_name(res)); } @@ -148,20 +157,13 @@ void Haptics::WriteRegister(Register reg, uint8_t val) { auto Haptics::ReadRegister(Register reg) -> uint8_t { uint8_t regRaw = static_cast<uint8_t>(reg); - uint8_t ret = 0; - I2CTransaction transaction; - transaction.start() - .write_addr(kHapticsAddress, I2C_MASTER_WRITE) - .write_ack(regRaw) - .start() - .write_addr(kHapticsAddress, I2C_MASTER_READ) - .read(&ret, I2C_MASTER_NACK) - .stop(); - esp_err_t res = transaction.Execute(1); + uint8_t cmd[] = {regRaw}; + uint8_t data[] = {0}; + esp_err_t res = i2c_master_transmit_receive(i2c_, cmd, 1, data, 1, 100); if (res != ESP_OK) { ESP_LOGW(kTag, "read failed: %s", esp_err_to_name(res)); } - return ret; + return data[0]; } auto Haptics::PlayWaveformEffect(Effect effect) -> void { @@ -251,14 +253,6 @@ auto Haptics::Reset() -> void { ModeMask::kDevReset); } -auto Haptics::PowerUp() -> void { - // FIXME: technically overwriting the RESERVED bits of Mode, but eh - uint8_t newMask = static_cast<uint8_t>(Mode::kInternalTrigger) & - (~ModeMask::kStandby) & (~ModeMask::kDevReset); - WriteRegister(Register::kMode, - static_cast<uint8_t>(RegisterDefaults::kMode) | newMask); -} - auto Haptics::EffectToLabel(Effect effect) -> std::string { switch (static_cast<Effect>(effect)) { case Effect::kStrongClick_100Pct: diff --git a/src/drivers/i2c.cpp b/src/drivers/i2c.cpp index 793ce9f9..5e7e7593 100644 --- a/src/drivers/i2c.cpp +++ b/src/drivers/i2c.cpp @@ -9,93 +9,36 @@ #include <cstdint> #include "assert.h" -#include "driver/i2c.h" +#include "driver/i2c_master.h" +#include "driver/i2c_types.h" #include "esp_err.h" #include "hal/i2c_types.h" +#include "soc/clk_tree_defs.h" namespace drivers { static const i2c_port_t kI2CPort = I2C_NUM_0; static const gpio_num_t kI2CSdaPin = GPIO_NUM_4; static const gpio_num_t kI2CSclPin = GPIO_NUM_2; -static const uint32_t kI2CClkSpeed = 400'000; -static constexpr int kCmdLinkSize = I2C_LINK_RECOMMENDED_SIZE(12); +static i2c_master_bus_handle_t sHandle; esp_err_t init_i2c(void) { - i2c_config_t config = { - .mode = I2C_MODE_MASTER, + i2c_master_bus_config_t config = { + .i2c_port = kI2CPort, .sda_io_num = kI2CSdaPin, .scl_io_num = kI2CSclPin, - .sda_pullup_en = false, - .scl_pullup_en = false, - .master = - { - .clk_speed = kI2CClkSpeed, - }, - // No requirements for the clock. - .clk_flags = 0, + .clk_source = I2C_CLK_SRC_DEFAULT, + .glitch_ignore_cnt = 7, + .intr_priority = 0, + .trans_queue_depth = 0, + .flags = {.enable_internal_pullup = true, .allow_pd = false}, }; - - if (esp_err_t err = i2c_param_config(kI2CPort, &config)) { - return err; - } - if (esp_err_t err = i2c_driver_install(kI2CPort, config.mode, 0, 0, 0)) { - return err; - } - if (esp_err_t err = i2c_set_timeout(kI2CPort, 400000)) { - return err; - } - - return ESP_OK; -} - -esp_err_t deinit_i2c(void) { - return i2c_driver_delete(kI2CPort); -} - -I2CTransaction::I2CTransaction() { - // Use a fixed size buffer to avoid many many tiny allocations. - buffer_ = (uint8_t*)calloc(sizeof(uint8_t), kCmdLinkSize); - handle_ = i2c_cmd_link_create_static(buffer_, kCmdLinkSize); - assert(handle_ != NULL && "failed to create command link"); -} - -I2CTransaction::~I2CTransaction() { - free(buffer_); -} - -esp_err_t I2CTransaction::Execute(int num_retries) { - esp_err_t res; - do { - res = i2c_master_cmd_begin(I2C_NUM_0, handle_, kI2CTimeout); - } while (res == ESP_ERR_TIMEOUT && num_retries-- > 0); - return res; -} - -I2CTransaction& I2CTransaction::start() { - ESP_ERROR_CHECK(i2c_master_start(handle_)); - return *this; -} - -I2CTransaction& I2CTransaction::stop() { - ESP_ERROR_CHECK(i2c_master_stop(handle_)); - return *this; -} - -I2CTransaction& I2CTransaction::write_addr(uint8_t addr, uint8_t op) { - write_ack(addr << 1 | op); - return *this; -} - -I2CTransaction& I2CTransaction::write_ack(uint8_t data) { - ESP_ERROR_CHECK(i2c_master_write_byte(handle_, data, true)); - return *this; + return i2c_new_master_bus(&config, &sHandle); } -I2CTransaction& I2CTransaction::read(uint8_t* dest, i2c_ack_type_t ack) { - ESP_ERROR_CHECK(i2c_master_read_byte(handle_, dest, ack)); - return *this; +i2c_master_bus_handle_t i2c_handle() { + return sHandle; } } // namespace drivers diff --git a/src/drivers/include/drivers/gpios.hpp b/src/drivers/include/drivers/gpios.hpp index 5010e45f..61d458a5 100644 --- a/src/drivers/include/drivers/gpios.hpp +++ b/src/drivers/include/drivers/gpios.hpp @@ -18,6 +18,7 @@ #include <utility> #include "driver/i2c.h" +#include "driver/i2c_types.h" #include "esp_check.h" #include "esp_err.h" #include "esp_log.h" @@ -138,6 +139,8 @@ class Gpios : public IGpios { private: Gpios(bool invert_lock); + i2c_master_dev_handle_t i2c_; + std::atomic<uint16_t> ports_; std::atomic<uint16_t> inputs_; const bool invert_lock_switch_; diff --git a/src/drivers/include/drivers/haptics.hpp b/src/drivers/include/drivers/haptics.hpp index e4666fad..60c54851 100644 --- a/src/drivers/include/drivers/haptics.hpp +++ b/src/drivers/include/drivers/haptics.hpp @@ -14,6 +14,7 @@ #include <string> #include <variant> +#include "driver/i2c_types.h" #include "drivers/nvs.hpp" namespace drivers { @@ -197,6 +198,7 @@ class Haptics { auto TourLibraries(Effect from, Effect to) -> void; private: + i2c_master_dev_handle_t i2c_; std::optional<Effect> current_effect_; std::mutex playing_effect_; @@ -313,7 +315,6 @@ class Haptics { kLraResonancePeriod = 0, }; - auto PowerUp() -> void; auto WriteRegister(Register reg, uint8_t val) -> void; auto ReadRegister(Register reg) -> uint8_t; diff --git a/src/drivers/include/drivers/i2c.hpp b/src/drivers/include/drivers/i2c.hpp index 0dc1e7c0..55ac49b2 100644 --- a/src/drivers/include/drivers/i2c.hpp +++ b/src/drivers/include/drivers/i2c.hpp @@ -8,86 +8,12 @@ #include <cstdint> -#include "driver/i2c.h" -#include "hal/i2c_types.h" +#include "driver/i2c_master.h" +#include "driver/i2c_types.h" namespace drivers { esp_err_t init_i2c(void); -esp_err_t deinit_i2c(void); - -/* - * Convenience wrapper for performing an I2C transaction with a reasonable - * preconfigured timeout, automatic management of a heap-based command buffer, - * and a terser API for enqueuing bytes. - * - * Any error codes from the underlying ESP IDF are treated as fatal, since they - * typically represent invalid arguments or OOMs. - */ -class I2CTransaction { - public: - static const uint8_t kI2CTimeout = pdMS_TO_TICKS(100); - - I2CTransaction(); - ~I2CTransaction(); - - /* - * Executes all enqueued commands, returning the result code. Possible error - * codes, per the ESP-IDF docs: - * - * ESP_OK Success - * ESP_ERR_INVALID_ARG Parameter error - * ESP_FAIL Sending command error, slave doesn’t ACK the transfer. - * ESP_ERR_INVALID_STATE I2C driver not installed or not in master mode. - * ESP_ERR_TIMEOUT Operation timeout because the bus is busy. - */ - esp_err_t Execute(int num_retries = 0); - - /* - * Enqueues a start condition. May also be used for repeated start - * conditions. - */ - I2CTransaction& start(); - /* Enqueues a stop condition. */ - I2CTransaction& stop(); - - /* - * Enqueues writing the given 7 bit address, followed by one bit indicating - * whether this is a read or write request. - * - * This command will expect an ACK before continuing. - */ - I2CTransaction& write_addr(uint8_t addr, uint8_t op); - - /* - * Enqueues one or more bytes to be written. The transaction will wait for - * an ACK to be returned before writing the next byte. - */ - I2CTransaction& write_ack(uint8_t data); - template <typename... More> - I2CTransaction& write_ack(uint8_t data, More... more) { - write_ack(data); - write_ack(more...); - return *this; - } - - /* - * Enqueues a read of one byte into the given uint8. Responds with the given - * ACK/NACK type. - */ - I2CTransaction& read(uint8_t* dest, i2c_ack_type_t ack); - - /* Returns the underlying command buffer. */ - i2c_cmd_handle_t handle() { return handle_; } - - // Cannot be moved or copied, since doing so is probably an error. Pass a - // reference instead. - I2CTransaction(const I2CTransaction&) = delete; - I2CTransaction& operator=(const I2CTransaction&) = delete; - - private: - i2c_cmd_handle_t handle_; - uint8_t* buffer_; -}; +i2c_master_bus_handle_t i2c_handle(); } // namespace drivers diff --git a/src/drivers/include/drivers/samd.hpp b/src/drivers/include/drivers/samd.hpp index 2bdfa5c6..ea692cda 100644 --- a/src/drivers/include/drivers/samd.hpp +++ b/src/drivers/include/drivers/samd.hpp @@ -10,6 +10,7 @@ #include <optional> #include <string> +#include "driver/i2c_types.h" #include "drivers/nvs.hpp" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" @@ -73,6 +74,7 @@ class Samd { Samd& operator=(const Samd&) = delete; private: + i2c_master_dev_handle_t i2c_; NvsStorage& nvs_; enum class RegisterName { diff --git a/src/drivers/include/drivers/touchwheel.hpp b/src/drivers/include/drivers/touchwheel.hpp index 9cd925a6..d14b3919 100644 --- a/src/drivers/include/drivers/touchwheel.hpp +++ b/src/drivers/include/drivers/touchwheel.hpp @@ -43,6 +43,7 @@ class TouchWheel { auto LowPowerMode(bool en) -> void; private: + i2c_master_dev_handle_t i2c_; TouchWheelData data_; enum Register { diff --git a/src/drivers/include/drivers/wm8523.hpp b/src/drivers/include/drivers/wm8523.hpp index a64f6bac..ac29ed81 100644 --- a/src/drivers/include/drivers/wm8523.hpp +++ b/src/drivers/include/drivers/wm8523.hpp @@ -8,6 +8,7 @@ #include <stdint.h> #include <cstdint> #include <optional> +#include "esp_err.h" namespace drivers { namespace wm8523 { @@ -45,6 +46,7 @@ enum class Register : uint8_t { kZeroDetect = 8, }; +auto Init() -> esp_err_t; auto ReadRegister(Register reg) -> std::optional<uint16_t>; auto WriteRegister(Register reg, uint16_t data) -> bool; auto WriteRegister(Register reg, uint8_t msb, uint8_t lsb) -> bool; diff --git a/src/drivers/samd.cpp b/src/drivers/samd.cpp index b4f6b88a..d8f56a46 100644 --- a/src/drivers/samd.cpp +++ b/src/drivers/samd.cpp @@ -5,18 +5,21 @@ */ #include "drivers/samd.hpp" +#include <stdint.h> #include <cstdint> #include <format> #include <optional> #include <string> +#include "driver/gpio.h" +#include "driver/i2c_master.h" +#include "drivers/i2c.hpp" #include "esp_err.h" #include "esp_log.h" #include "hal/gpio_types.h" #include "hal/i2c_types.h" -#include "drivers/i2c.hpp" #include "drivers/nvs.hpp" static const uint8_t kAddress = 0x45; @@ -54,16 +57,20 @@ Samd::Samd(NvsStorage& nvs) : nvs_(nvs) { // Being able to interface with the SAMD properly is critical. To ensure we // will be able to, we begin by checking the I2C protocol version is // compatible, and throw if it's not. - I2CTransaction transaction; - transaction.start() - .write_addr(kAddress, I2C_MASTER_WRITE) - .write_ack(registerIdx(RegisterName::kSamdFirmwareMajorVersion)) - .start() - .write_addr(kAddress, I2C_MASTER_READ) - .read(&version_major_, I2C_MASTER_ACK) - .read(&version_minor_, I2C_MASTER_NACK) - .stop(); - ESP_ERROR_CHECK(transaction.Execute(1)); + i2c_device_config_t config = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = kAddress, + .scl_speed_hz = 100'000, + .scl_wait_us = 0, + .flags = {.disable_ack_check = false}, + }; + ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_handle(), &config, &i2c_)); + + uint8_t cmd[] = {registerIdx(RegisterName::kSamdFirmwareMajorVersion)}; + uint8_t data[] = {0, 0}; + ESP_ERROR_CHECK(i2c_master_transmit_receive(i2c_, cmd, 1, data, 2, 100)); + version_major_ = data[0]; + version_minor_ = data[1]; if (version_major_ < 6) { version_minor_ = 0; @@ -85,24 +92,17 @@ auto Samd::GetChargeStatus() -> std::optional<ChargeStatus> { } auto Samd::UpdateChargeStatus() -> void { - uint8_t raw_res; - I2CTransaction transaction; - transaction.start() - .write_addr(kAddress, I2C_MASTER_WRITE) - .write_ack(registerIdx(RegisterName::kChargeStatus)) - .start() - .write_addr(kAddress, I2C_MASTER_READ) - .read(&raw_res, I2C_MASTER_NACK) - .stop(); - esp_err_t res = transaction.Execute(1); + uint8_t cmd[] = {registerIdx(RegisterName::kChargeStatus)}; + uint8_t data[] = {0}; + esp_err_t res = i2c_master_transmit_receive(i2c_, cmd, 1, data, 1, 100); if (res != ESP_OK) { return; } // Lower two bits are the usb power status, next three are the BMS status. // See 'gpio.c' in the SAMD21 firmware for how these bits get packed. - uint8_t charge_state = (raw_res & 0b11100) >> 2; - uint8_t usb_state = raw_res & 0b11; + uint8_t charge_state = (data[0] & 0b11100) >> 2; + uint8_t usb_state = data[0] & 0b11; switch (charge_state) { case 0b000: charge_status_ = ChargeStatus::kNoBattery; @@ -139,34 +139,23 @@ auto Samd::GetUsbStatus() -> UsbStatus { } auto Samd::UpdateUsbStatus() -> void { - uint8_t raw_res; - I2CTransaction transaction; - transaction.start() - .write_addr(kAddress, I2C_MASTER_WRITE) - .write_ack(registerIdx(RegisterName::kUsbStatus)) - .start() - .write_addr(kAddress, I2C_MASTER_READ) - .read(&raw_res, I2C_MASTER_NACK) - .stop(); - esp_err_t res = transaction.Execute(1); + uint8_t cmd[] = {registerIdx(RegisterName::kUsbStatus)}; + uint8_t data[] = {0}; + esp_err_t res = i2c_master_transmit_receive(i2c_, cmd, 1, data, 1, 100); if (res != ESP_OK) { return; } - if (!(raw_res & 0b1)) { + if (!(data[0] & 0b1)) { usb_status_ = UsbStatus::kDetached; } usb_status_ = - (raw_res & 0b10) ? UsbStatus::kAttachedBusy : UsbStatus::kAttachedIdle; + (data[0] & 0b10) ? UsbStatus::kAttachedBusy : UsbStatus::kAttachedIdle; } auto Samd::ResetToFlashSamd() -> void { - I2CTransaction transaction; - transaction.start() - .write_addr(kAddress, I2C_MASTER_WRITE) - .write_ack(registerIdx(RegisterName::kUsbControl), 0b100) - .stop(); - ESP_ERROR_CHECK(transaction.Execute(3)); + uint8_t cmd[] = {registerIdx(RegisterName::kUsbControl), 0b100}; + ESP_ERROR_CHECK(i2c_master_transmit(i2c_, cmd, 2, 100)); } auto Samd::SetFastChargeEnabled(bool en) -> void { @@ -178,47 +167,29 @@ auto Samd::SetFastChargeEnabled(bool en) -> void { return; } - I2CTransaction transaction; - transaction.start() - .write_addr(kAddress, I2C_MASTER_WRITE) - .write_ack(registerIdx(RegisterName::kPowerControl), (en << 1)) - .stop(); - ESP_ERROR_CHECK(transaction.Execute(3)); + uint8_t cmd[] = {registerIdx(RegisterName::kPowerControl), + static_cast<uint8_t>(en << 1)}; + ESP_ERROR_CHECK(i2c_master_transmit(i2c_, cmd, 2, 100)); } auto Samd::PowerDown() -> void { - I2CTransaction transaction; - transaction.start() - .write_addr(kAddress, I2C_MASTER_WRITE) - .write_ack(registerIdx(RegisterName::kPowerControl), 0b1) - .stop(); - ESP_ERROR_CHECK(transaction.Execute(3)); + uint8_t cmd[] = {registerIdx(RegisterName::kPowerControl), 0b1}; + ESP_ERROR_CHECK(i2c_master_transmit(i2c_, cmd, 2, 100)); } auto Samd::UsbMassStorage(bool en) -> void { - I2CTransaction transaction; - transaction.start() - .write_addr(kAddress, I2C_MASTER_WRITE) - .write_ack(registerIdx(RegisterName::kUsbControl), en) - .stop(); - ESP_ERROR_CHECK(transaction.Execute(3)); + uint8_t cmd[] = {registerIdx(RegisterName::kUsbControl), en}; + ESP_ERROR_CHECK(i2c_master_transmit(i2c_, cmd, 2, 100)); } auto Samd::UsbMassStorage() -> bool { - uint8_t raw_res; - I2CTransaction transaction; - transaction.start() - .write_addr(kAddress, I2C_MASTER_WRITE) - .write_ack(registerIdx(RegisterName::kUsbControl)) - .start() - .write_addr(kAddress, I2C_MASTER_READ) - .read(&raw_res, I2C_MASTER_NACK) - .stop(); - esp_err_t res = transaction.Execute(1); + uint8_t cmd[] = {registerIdx(RegisterName::kUsbControl)}; + uint8_t data[] = {0}; + esp_err_t res = i2c_master_transmit_receive(i2c_, cmd, 1, data, 1, 100); if (res != ESP_OK) { return false; } - return raw_res & 1; + return data[0] & 1; } auto Samd::registerIdx(RegisterName r) -> uint8_t { diff --git a/src/drivers/touchwheel.cpp b/src/drivers/touchwheel.cpp index 402b839d..bd127f47 100644 --- a/src/drivers/touchwheel.cpp +++ b/src/drivers/touchwheel.cpp @@ -36,6 +36,15 @@ auto TouchWheel::isAngleWithin(int16_t wheel_angle, } TouchWheel::TouchWheel() { + i2c_device_config_t config = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = kTouchWheelAddress, + .scl_speed_hz = 400'000, + .scl_wait_us = 0, + .flags = {.disable_ack_check = false}, + }; + ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_handle(), &config, &i2c_)); + gpio_config_t int_config{ .pin_bit_mask = 1ULL << kIntPin, .mode = GPIO_MODE_INPUT, @@ -78,32 +87,20 @@ TouchWheel::~TouchWheel() {} void TouchWheel::WriteRegister(uint8_t reg, uint8_t val) { // Addresses <= 5 are not writeable. Make sure we don't try. assert(reg > 5); - I2CTransaction transaction; - transaction.start() - .write_addr(kTouchWheelAddress, I2C_MASTER_WRITE) - .write_ack(reg, val) - .stop(); - esp_err_t res = transaction.Execute(1); + uint8_t cmd[] = {static_cast<uint8_t>(reg), val}; + esp_err_t res = i2c_master_transmit(i2c_, cmd, 2, 100); if (res != ESP_OK) { ESP_LOGW(kTag, "write failed: %s", esp_err_to_name(res)); } } uint8_t TouchWheel::ReadRegister(uint8_t reg) { - uint8_t res; - I2CTransaction transaction; - transaction.start() - .write_addr(kTouchWheelAddress, I2C_MASTER_WRITE) - .write_ack(reg) - .start() - .write_addr(kTouchWheelAddress, I2C_MASTER_READ) - .read(&res, I2C_MASTER_NACK) - .stop(); - if (transaction.Execute(1) == ESP_OK) { - return res; - } else { + uint8_t cmd[] = {static_cast<uint8_t>(reg)}; + uint8_t data[] = {0}; + if (i2c_master_transmit_receive(i2c_, cmd, 1, data, 1, 100) != ESP_OK) { return 0; } + return data[0]; } void TouchWheel::Update() { diff --git a/src/drivers/wm8523.cpp b/src/drivers/wm8523.cpp index 177679f1..428dcd87 100644 --- a/src/drivers/wm8523.cpp +++ b/src/drivers/wm8523.cpp @@ -4,9 +4,12 @@ * SPDX-License-Identifier: GPL-3.0-only */ #include "drivers/wm8523.hpp" +#include <stdint.h> #include <cstdint> +#include "driver/i2c_master.h" +#include "driver/i2c_types.h" #include "esp_err.h" #include "drivers/i2c.hpp" @@ -35,22 +38,26 @@ const uint16_t kDefaultMaxVolume = kLineLevelReferenceVolume + 12; const uint16_t kZeroDbVolume = 0x190; static const uint8_t kAddress = 0b0011010; +static i2c_master_dev_handle_t sI2C; + +auto Init() -> esp_err_t { + i2c_device_config_t config = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = kAddress, + .scl_speed_hz = 400'000, + .scl_wait_us = 0, + .flags = {.disable_ack_check = false}, + }; + return i2c_master_bus_add_device(i2c_handle(), &config, &sI2C); +} auto ReadRegister(Register reg) -> std::optional<uint16_t> { - uint8_t msb, lsb; - I2CTransaction transaction; - transaction.start() - .write_addr(kAddress, I2C_MASTER_WRITE) - .write_ack(static_cast<uint8_t>(reg)) - .start() - .write_addr(kAddress, I2C_MASTER_READ) - .read(&msb, I2C_MASTER_ACK) - .read(&lsb, I2C_MASTER_LAST_NACK) - .stop(); - if (transaction.Execute() != ESP_OK) { + uint8_t cmd[] = {static_cast<uint8_t>(reg)}; + uint8_t data[] = {0, 0}; + if (i2c_master_transmit_receive(sI2C, cmd, 1, data, 2, 100) != ESP_OK) { return {}; } - return (msb << 8) | lsb; + return (data[0] << 8) | data[1]; } auto WriteRegister(Register reg, uint16_t data) -> bool { @@ -58,12 +65,8 @@ auto WriteRegister(Register reg, uint16_t data) -> bool { } auto WriteRegister(Register reg, uint8_t msb, uint8_t lsb) -> bool { - I2CTransaction transaction; - transaction.start() - .write_addr(kAddress, I2C_MASTER_WRITE) - .write_ack(static_cast<uint8_t>(reg), msb, lsb) - .stop(); - return transaction.Execute() == ESP_OK; + uint8_t cmd[] = {static_cast<uint8_t>(reg), msb, lsb}; + return i2c_master_transmit(sI2C, cmd, 3, 100) == ESP_OK; } } // namespace wm8523 diff --git a/src/tangara/system_fsm/booting.cpp b/src/tangara/system_fsm/booting.cpp index 0bc6da8e..8373a928 100644 --- a/src/tangara/system_fsm/booting.cpp +++ b/src/tangara/system_fsm/booting.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ +#include "drivers/wm8523.hpp" #include "system_fsm/system_fsm.hpp" #include <cstdint> @@ -91,6 +92,7 @@ auto Booting::entry() -> void { sServices->touchwheel( std::unique_ptr<drivers::TouchWheel>{drivers::TouchWheel::Create()}); sServices->haptics(std::make_unique<drivers::Haptics>(sServices->nvs())); + ESP_ERROR_CHECK(drivers::wm8523::Init()); auto adc = drivers::AdcBattery::Create(); sServices->battery(std::make_unique<battery::Battery>( |
