summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2025-08-08 16:14:41 +1000
committerjacqueline <me@jacqueline.id.au>2025-08-08 16:14:41 +1000
commit73baf2f88f61e307afd6cd17f6727da4e446b64c (patch)
treed13241937786b3d422423cc2b804e0ec42b21335 /src
parent2b2e595a8fb28e34ec33a98035c31bd4cba76808 (diff)
downloadtangara-fw-73baf2f88f61e307afd6cd17f6727da4e446b64c.tar.gz
Migrate to the new esp-idf I2C driver
It's a better, less verbose driver, and also this fixes an occasional crash on boot.
Diffstat (limited to 'src')
-rw-r--r--src/drivers/CMakeLists.txt2
-rw-r--r--src/drivers/gpios.cpp34
-rw-r--r--src/drivers/haptics.cpp46
-rw-r--r--src/drivers/i2c.cpp85
-rw-r--r--src/drivers/include/drivers/gpios.hpp3
-rw-r--r--src/drivers/include/drivers/haptics.hpp3
-rw-r--r--src/drivers/include/drivers/i2c.hpp80
-rw-r--r--src/drivers/include/drivers/samd.hpp2
-rw-r--r--src/drivers/include/drivers/touchwheel.hpp1
-rw-r--r--src/drivers/include/drivers/wm8523.hpp2
-rw-r--r--src/drivers/samd.cpp111
-rw-r--r--src/drivers/touchwheel.cpp33
-rw-r--r--src/drivers/wm8523.cpp39
-rw-r--r--src/tangara/system_fsm/booting.cpp2
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>(