mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-06-19 04:15:06 +00:00
Compare commits
7 Commits
5f52372b82
...
b216ba8595
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b216ba8595 | ||
|
|
37be031f3f | ||
|
|
a6571f815d | ||
|
|
133215664c | ||
|
|
023b220bfb | ||
|
|
e131b5343d | ||
|
|
8dabda2b5b |
@ -37,4 +37,6 @@ CONFIG_FATFS_SECTOR_512=y
|
||||
CONFIG_WL_SECTOR_SIZE_512=y
|
||||
CONFIG_WL_SECTOR_SIZE=512
|
||||
CONFIG_WL_SECTOR_MODE_SAFE=y
|
||||
CONFIG_WL_SECTOR_MODE=1
|
||||
CONFIG_WL_SECTOR_MODE=1
|
||||
# Allow new i2c_master API (used by Tab5Keyboard for LP_I2C_NUM_0) to coexist with legacy i2c driver
|
||||
CONFIG_I2C_SKIP_LEGACY_CONFLICT_CHECK=y
|
||||
|
||||
@ -58,7 +58,7 @@ bool initBoot() {
|
||||
std::vector<tt::hal::gps::GpsConfiguration> gps_configurations;
|
||||
gps_service->getGpsConfigurations(gps_configurations);
|
||||
if (gps_configurations.empty()) {
|
||||
if (gps_service->addGpsConfiguration(tt::hal::gps::GpsConfiguration {.uartName = "uart1", .baudRate = 38400, .model = tt::hal::gps::GpsModel::UBLOX10})) {
|
||||
if (gps_service->addGpsConfiguration(tt::hal::gps::GpsConfiguration {.uartName = "uart0", .baudRate = 38400, .model = tt::hal::gps::GpsModel::UBLOX10})) {
|
||||
LOGGER.info("Configured internal GPS");
|
||||
} else {
|
||||
LOGGER.error("Failed to configure internal GPS");
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include <tactility/bindings/root.h>
|
||||
#include <tactility/bindings/esp32_ble.h>
|
||||
#include <tactility/bindings/esp32_gpio.h>
|
||||
#include <tactility/bindings/esp32_grove.h>
|
||||
#include <tactility/bindings/esp32_i2c.h>
|
||||
#include <tactility/bindings/esp32_i2s.h>
|
||||
#include <tactility/bindings/esp32_spi.h>
|
||||
@ -30,15 +31,6 @@
|
||||
pin-scl = <&gpio0 8 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
i2c_external: i2c1 {
|
||||
compatible = "espressif,esp32-i2c";
|
||||
status = "disabled";
|
||||
port = <I2C_NUM_1>;
|
||||
clock-frequency = <400000>;
|
||||
pin-sda = <&gpio0 43 GPIO_FLAG_NONE>;
|
||||
pin-scl = <&gpio0 44 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
i2s0 {
|
||||
compatible = "espressif,esp32-i2s";
|
||||
port = <I2S_NUM_0>;
|
||||
@ -55,7 +47,7 @@
|
||||
pin-sclk = <&gpio0 40 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
uart1 {
|
||||
uart0 {
|
||||
compatible = "espressif,esp32-uart";
|
||||
port = <UART_NUM_1>;
|
||||
pin-tx = <&gpio0 43 GPIO_FLAG_NONE>;
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "devices/TpagerKeyboard.h"
|
||||
#include "devices/TpagerPower.h"
|
||||
#include <driver/gpio.h>
|
||||
#include <tactility/device.h>
|
||||
|
||||
#include <Tactility/hal/Configuration.h>
|
||||
#include <Bq25896.h>
|
||||
@ -14,17 +15,18 @@ bool tpagerInit();
|
||||
using namespace tt::hal;
|
||||
|
||||
static DeviceVector createDevices() {
|
||||
auto bq27220 = std::make_shared<Bq27220>(I2C_NUM_0);
|
||||
auto* i2c = device_find_by_name("i2c0");
|
||||
auto bq27220 = std::make_shared<Bq27220>(i2c);
|
||||
auto power = std::make_shared<TpagerPower>(bq27220);
|
||||
|
||||
auto tca8418 = std::make_shared<Tca8418>(I2C_NUM_0);
|
||||
auto tca8418 = std::make_shared<Tca8418>(i2c);
|
||||
auto keyboard = std::make_shared<TpagerKeyboard>(tca8418);
|
||||
|
||||
return std::vector<std::shared_ptr<tt::hal::Device>> {
|
||||
tca8418,
|
||||
std::make_shared<Bq25896>(I2C_NUM_0),
|
||||
std::make_shared<Bq25896>(i2c),
|
||||
bq27220,
|
||||
std::make_shared<Drv2605>(I2C_NUM_0),
|
||||
std::make_shared<Drv2605>(i2c),
|
||||
power,
|
||||
createTpagerSdCard(),
|
||||
createDisplay(),
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "devices/CardputerPower.h"
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#include <tactility/device.h>
|
||||
#include <Tactility/hal/Configuration.h>
|
||||
|
||||
#include <PwmBacklight.h>
|
||||
@ -16,7 +17,7 @@ static bool initBoot() {
|
||||
}
|
||||
|
||||
static DeviceVector createDevices() {
|
||||
auto tca8418 = std::make_shared<Tca8418>(I2C_NUM_0);
|
||||
auto tca8418 = std::make_shared<Tca8418>(device_find_by_name("i2c_internal"));
|
||||
return {
|
||||
createSdCard(),
|
||||
createDisplay(),
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#include "CardputerKeyboard.h"
|
||||
#include <Tactility/hal/i2c/I2c.h>
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
|
||||
constexpr auto* TAG = "CardputerKeyb";
|
||||
|
||||
@ -151,5 +151,5 @@ bool CardputerKeyboard::stopLvgl() {
|
||||
}
|
||||
|
||||
bool CardputerKeyboard::isAttached() const {
|
||||
return tt::hal::i2c::masterHasDeviceAtAddress(keypad->getPort(), keypad->getAddress(), 100);
|
||||
return i2c_controller_has_device_at_address(keypad->getController(), keypad->getAddress(), 100) == ERROR_NONE;
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include <tactility/bindings/root.h>
|
||||
#include <tactility/bindings/esp32_ble.h>
|
||||
#include <tactility/bindings/esp32_gpio.h>
|
||||
#include <tactility/bindings/esp32_grove.h>
|
||||
#include <tactility/bindings/esp32_i2c.h>
|
||||
#include <tactility/bindings/esp32_i2s.h>
|
||||
#include <tactility/bindings/esp32_spi.h>
|
||||
@ -36,12 +37,14 @@
|
||||
};
|
||||
};
|
||||
|
||||
i2c_port_a {
|
||||
compatible = "espressif,esp32-i2c";
|
||||
port = <I2C_NUM_1>;
|
||||
clock-frequency = <400000>;
|
||||
pin-sda = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||
pin-scl = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||
port_a: grove0 {
|
||||
compatible = "espressif,esp32-grove";
|
||||
defaultMode = <GROVE_MODE_I2C>;
|
||||
pinSdaRx = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||
pinSclTx = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||
uartPort = <UART_NUM_1>;
|
||||
i2cPort = <I2C_NUM_1>;
|
||||
i2cClockFrequency = <400000>;
|
||||
};
|
||||
|
||||
display_spi: spi0 {
|
||||
@ -68,12 +71,4 @@
|
||||
pin-data-out = <&gpio0 42 GPIO_FLAG_NONE>;
|
||||
pin-data-in = <&gpio0 46 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
uart_port_a: uart1 {
|
||||
compatible = "espressif,esp32-uart";
|
||||
status = "disabled";
|
||||
port = <UART_NUM_1>;
|
||||
pin-tx = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||
pin-rx = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||
};
|
||||
};
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include <tactility/bindings/root.h>
|
||||
#include <tactility/bindings/esp32_ble.h>
|
||||
#include <tactility/bindings/esp32_gpio.h>
|
||||
#include <tactility/bindings/esp32_grove.h>
|
||||
#include <tactility/bindings/esp32_i2c.h>
|
||||
#include <tactility/bindings/esp32_i2s.h>
|
||||
#include <tactility/bindings/esp32_spi.h>
|
||||
@ -22,12 +23,14 @@
|
||||
gpio-count = <49>;
|
||||
};
|
||||
|
||||
i2c_port_a {
|
||||
compatible = "espressif,esp32-i2c";
|
||||
port = <I2C_NUM_0>;
|
||||
clock-frequency = <400000>;
|
||||
pin-sda = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||
pin-scl = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||
port_a: grove0 {
|
||||
compatible = "espressif,esp32-grove";
|
||||
defaultMode = <GROVE_MODE_I2C>;
|
||||
pinSdaRx = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||
pinSclTx = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||
uartPort = <UART_NUM_1>;
|
||||
i2cPort = <I2C_NUM_0>;
|
||||
i2cClockFrequency = <400000>;
|
||||
};
|
||||
|
||||
display_spi: spi0 {
|
||||
@ -55,12 +58,4 @@
|
||||
pin-data-out = <&gpio0 42 GPIO_FLAG_NONE>;
|
||||
pin-data-in = <&gpio0 46 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
uart_port_a: uart1 {
|
||||
compatible = "espressif,esp32-uart";
|
||||
status = "disabled";
|
||||
port = <UART_NUM_1>;
|
||||
pin-tx = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||
pin-rx = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
#include <Axp192.h>
|
||||
#include <tactility/device.h>
|
||||
|
||||
static std::shared_ptr<Axp192> axp192 = nullptr;
|
||||
|
||||
std::shared_ptr<Axp192> createAxp192() {
|
||||
assert(axp192 == nullptr);
|
||||
auto configuration = std::make_unique<Axp192::Configuration>(I2C_NUM_0);
|
||||
auto configuration = std::make_unique<Axp192::Configuration>(device_find_by_name("i2c_internal"));
|
||||
axp192 = std::make_shared<Axp192>(std::move(configuration));
|
||||
return axp192;
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include <tactility/bindings/root.h>
|
||||
#include <tactility/bindings/esp32_gpio.h>
|
||||
#include <tactility/bindings/esp32_grove.h>
|
||||
#include <tactility/bindings/esp32_i2c.h>
|
||||
#include <tactility/bindings/esp32_i2s.h>
|
||||
#include <tactility/bindings/esp32_spi.h>
|
||||
@ -37,12 +38,14 @@
|
||||
};
|
||||
};
|
||||
|
||||
i2c_port_a {
|
||||
compatible = "espressif,esp32-i2c";
|
||||
port = <I2C_NUM_1>;
|
||||
clock-frequency = <400000>;
|
||||
pin-sda = <&gpio0 32 GPIO_FLAG_NONE>;
|
||||
pin-scl = <&gpio0 33 GPIO_FLAG_NONE>;
|
||||
port_a: grove0 {
|
||||
compatible = "espressif,esp32-grove";
|
||||
defaultMode = <GROVE_MODE_I2C>;
|
||||
pinSdaRx = <&gpio0 32 GPIO_FLAG_NONE>;
|
||||
pinSclTx = <&gpio0 33 GPIO_FLAG_NONE>;
|
||||
uartPort = <UART_NUM_1>;
|
||||
i2cPort = <I2C_NUM_1>;
|
||||
i2cClockFrequency = <400000>;
|
||||
};
|
||||
|
||||
spi0 {
|
||||
@ -63,12 +66,4 @@
|
||||
pin-data-out = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||
pin-data-in = <&gpio0 34 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
uart_port_a: uart1 {
|
||||
compatible = "espressif,esp32-uart";
|
||||
status = "disabled";
|
||||
port = <UART_NUM_1>;
|
||||
pin-tx = <&gpio0 33 GPIO_FLAG_NONE>;
|
||||
pin-rx = <&gpio0 32 GPIO_FLAG_NONE>;
|
||||
};
|
||||
};
|
||||
|
||||
@ -146,8 +146,9 @@ bool initPowerControl() {
|
||||
bool initBoot() {
|
||||
LOGGER.info("initBoot()");
|
||||
|
||||
axp2101 = std::make_shared<Axp2101>(I2C_NUM_0);
|
||||
aw9523 = std::make_shared<Aw9523>(I2C_NUM_0);
|
||||
auto controller = device_find_by_name("i2c_internal");
|
||||
axp2101 = std::make_shared<Axp2101>(controller);
|
||||
aw9523 = std::make_shared<Aw9523>(controller);
|
||||
|
||||
return initPowerControl() && initGpioExpander();
|
||||
}
|
||||
@ -3,6 +3,7 @@
|
||||
#include <tactility/bindings/root.h>
|
||||
#include <tactility/bindings/esp32_ble.h>
|
||||
#include <tactility/bindings/esp32_gpio.h>
|
||||
#include <tactility/bindings/esp32_grove.h>
|
||||
#include <tactility/bindings/esp32_i2c.h>
|
||||
#include <tactility/bindings/esp32_i2s.h>
|
||||
#include <tactility/bindings/esp32_spi.h>
|
||||
@ -42,30 +43,34 @@
|
||||
};
|
||||
};
|
||||
|
||||
i2c_port_a {
|
||||
compatible = "espressif,esp32-i2c";
|
||||
port = <I2C_NUM_1>;
|
||||
clock-frequency = <400000>;
|
||||
pin-sda = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||
pin-scl = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||
port_a: grove0 {
|
||||
compatible = "espressif,esp32-grove";
|
||||
defaultMode = <GROVE_MODE_I2C>;
|
||||
pinSdaRx = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||
pinSclTx = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||
uartPort = <UART_NUM_1>;
|
||||
i2cPort = <I2C_NUM_1>;
|
||||
i2cClockFrequency = <400000>;
|
||||
};
|
||||
|
||||
i2c_port_b {
|
||||
compatible = "espressif,esp32-i2c";
|
||||
status = "disabled";
|
||||
port = <I2C_NUM_1>;
|
||||
clock-frequency = <400000>;
|
||||
pin-sda = <&gpio0 9 GPIO_FLAG_NONE>;
|
||||
pin-scl = <&gpio0 8 GPIO_FLAG_NONE>;
|
||||
port_b: grove1 {
|
||||
compatible = "espressif,esp32-grove";
|
||||
defaultMode = <GROVE_MODE_UART>;
|
||||
pinSdaRx = <&gpio0 9 GPIO_FLAG_NONE>;
|
||||
pinSclTx = <&gpio0 8 GPIO_FLAG_NONE>;
|
||||
uartPort = <UART_NUM_1>;
|
||||
i2cPort = <I2C_NUM_1>;
|
||||
i2cClockFrequency = <400000>;
|
||||
};
|
||||
|
||||
i2c_port_c {
|
||||
compatible = "espressif,esp32-i2c";
|
||||
status = "disabled";
|
||||
port = <I2C_NUM_1>;
|
||||
clock-frequency = <400000>;
|
||||
pin-sda = <&gpio0 18 GPIO_FLAG_NONE>;
|
||||
pin-scl = <&gpio0 17 GPIO_FLAG_NONE>;
|
||||
port_c: grove2 {
|
||||
compatible = "espressif,esp32-grove";
|
||||
defaultMode = <GROVE_MODE_UART>;
|
||||
pinSdaRx = <&gpio0 17 GPIO_FLAG_NONE>;
|
||||
pinSclTx = <&gpio0 18 GPIO_FLAG_NONE>;
|
||||
uartPort = <UART_NUM_2>;
|
||||
i2cPort = <I2C_NUM_1>;
|
||||
i2cClockFrequency = <400000>;
|
||||
};
|
||||
|
||||
spi0 {
|
||||
@ -89,12 +94,4 @@
|
||||
pin-data-in = <&gpio0 14 GPIO_FLAG_NONE>;
|
||||
pin-mclk = <&gpio0 0 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
uart_port_a: uart1 {
|
||||
compatible = "espressif,esp32-uart";
|
||||
status = "disabled";
|
||||
port = <UART_NUM_1>;
|
||||
pin-tx = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||
pin-rx = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||
};
|
||||
};
|
||||
|
||||
@ -231,7 +231,7 @@ bool initBoot() {
|
||||
}
|
||||
|
||||
// Keep Axp2101 C++ wrapper alive for Axp2101Power (backlight + battery)
|
||||
axp2101 = std::make_shared<Axp2101>(I2C_NUM_0);
|
||||
axp2101 = std::make_shared<Axp2101>(i2c);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -67,30 +67,43 @@
|
||||
// TODO: BMM150 magnetometer @ 0x10 — accessible only via BMI270 aux I2C
|
||||
};
|
||||
|
||||
i2c_port_a {
|
||||
compatible = "espressif,esp32-i2c";
|
||||
port = <I2C_NUM_1>;
|
||||
clock-frequency = <400000>;
|
||||
pin-sda = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||
pin-scl = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||
// TODO: Servo UART (SCS9009, 1 Mbaud) — TX=GPIO6, RX=GPIO7
|
||||
uart_port_a: uart1 {
|
||||
compatible = "espressif,esp32-uart";
|
||||
status = "disabled";
|
||||
port = <UART_NUM_1>;
|
||||
pin-tx = <&gpio0 6 GPIO_FLAG_NONE>;
|
||||
pin-rx = <&gpio0 7 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
i2c_port_b {
|
||||
compatible = "espressif,esp32-i2c";
|
||||
status = "disabled";
|
||||
port = <I2C_NUM_1>;
|
||||
clock-frequency = <400000>;
|
||||
pin-sda = <&gpio0 9 GPIO_FLAG_NONE>;
|
||||
pin-scl = <&gpio0 8 GPIO_FLAG_NONE>;
|
||||
port_a: grove0 {
|
||||
compatible = "espressif,esp32-grove";
|
||||
defaultMode = <GROVE_MODE_I2C>;
|
||||
pinSdaRx = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||
pinSclTx = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||
uartPort = <UART_NUM_2>;
|
||||
i2cPort = <I2C_NUM_1>;
|
||||
i2cClockFrequency = <400000>;
|
||||
};
|
||||
|
||||
i2c_port_c {
|
||||
compatible = "espressif,esp32-i2c";
|
||||
status = "disabled";
|
||||
port = <I2C_NUM_1>;
|
||||
clock-frequency = <400000>;
|
||||
pin-sda = <&gpio0 18 GPIO_FLAG_NONE>;
|
||||
pin-scl = <&gpio0 17 GPIO_FLAG_NONE>;
|
||||
port_b: grove1 {
|
||||
compatible = "espressif,esp32-grove";
|
||||
defaultMode = <GROVE_MODE_UART>;
|
||||
pinSdaRx = <&gpio0 9 GPIO_FLAG_NONE>;
|
||||
pinSclTx = <&gpio0 8 GPIO_FLAG_NONE>;
|
||||
uartPort = <UART_NUM_2>;
|
||||
i2cPort = <I2C_NUM_1>;
|
||||
i2cClockFrequency = <400000>;
|
||||
};
|
||||
|
||||
port_c: grove2 {
|
||||
compatible = "espressif,esp32-grove";
|
||||
defaultMode = <GROVE_MODE_DISABLED>;
|
||||
pinSdaRx = <&gpio0 17 GPIO_FLAG_NONE>;
|
||||
pinSclTx = <&gpio0 18 GPIO_FLAG_NONE>;
|
||||
uartPort = <UART_NUM_2>;
|
||||
i2cPort = <I2C_NUM_1>;
|
||||
i2cClockFrequency = <400000>;
|
||||
};
|
||||
|
||||
spi0 {
|
||||
@ -111,13 +124,4 @@
|
||||
pin-data-in = <&gpio0 14 GPIO_FLAG_NONE>;
|
||||
pin-mclk = <&gpio0 0 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
// TODO: Servo UART (SCS9009, 1 Mbaud) — TX=GPIO6, RX=GPIO7
|
||||
uart_port_a: uart1 {
|
||||
compatible = "espressif,esp32-uart";
|
||||
status = "disabled";
|
||||
port = <UART_NUM_1>;
|
||||
pin-tx = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||
pin-rx = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
#include <Axp192.h>
|
||||
#include <tactility/device.h>
|
||||
|
||||
static std::shared_ptr<Axp192> axp192 = nullptr;
|
||||
|
||||
std::shared_ptr<Axp192> createAxp192() {
|
||||
assert(axp192 == nullptr);
|
||||
auto configuration = std::make_unique<Axp192::Configuration>(I2C_NUM_0);
|
||||
auto configuration = std::make_unique<Axp192::Configuration>(device_find_by_name("i2c_internal"));
|
||||
axp192 = std::make_shared<Axp192>(std::move(configuration));
|
||||
return axp192;
|
||||
}
|
||||
|
||||
@ -14,11 +14,12 @@ using namespace tt::hal;
|
||||
static constexpr auto* TAG = "Tab5";
|
||||
|
||||
static DeviceVector createDevices() {
|
||||
::Device* i2c2 = device_find_by_name("i2c2");
|
||||
return {
|
||||
createPower(),
|
||||
createDisplay(),
|
||||
createSdCard(),
|
||||
std::make_shared<Tab5Keyboard>()
|
||||
std::make_shared<Tab5Keyboard>(i2c2)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -13,7 +13,9 @@
|
||||
|
||||
static const auto LOGGER = tt::Logger("Tab5Display");
|
||||
|
||||
constexpr auto LCD_PIN_RESET = GPIO_NUM_0; // Match P4 EV board reset line
|
||||
// LCD reset is wired to the PI4IOE5V6408 IO expander (io_expander0, bit 4), pulsed in
|
||||
// Configuration.cpp's initExpander0() before display creation - not a direct SoC GPIO.
|
||||
constexpr auto LCD_PIN_RESET = GPIO_NUM_NC;
|
||||
constexpr auto LCD_PIN_BACKLIGHT = GPIO_NUM_22;
|
||||
|
||||
static std::shared_ptr<tt::hal::touch::TouchDevice> createGt911Touch() {
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#include "Tab5Keyboard.h"
|
||||
#include <Tactility/app/App.h>
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/log.h>
|
||||
#include <esp_timer.h>
|
||||
#include <lvgl.h>
|
||||
|
||||
@ -135,19 +137,14 @@ static uint32_t tab5TranslateKey(uint8_t keycode, uint8_t modifier, bool ctrl) {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// I2C helpers - direct i2c_master API (LP_I2C_NUM_0, GPIO 0/1)
|
||||
// I2C helpers - use Tactility I2C controller API
|
||||
// ---------------------------------------------------------------------------
|
||||
bool Tab5Keyboard::readReg(uint8_t reg, uint8_t& value) const {
|
||||
if (!i2cDev) return false;
|
||||
const esp_err_t err = i2c_master_transmit_receive(i2cDev, ®, 1, &value, 1, pdMS_TO_TICKS(50));
|
||||
return err == ESP_OK;
|
||||
bool Tab5Keyboard::readReg(uint8_t reg, uint8_t& value) {
|
||||
return i2c_controller_read_register(i2cController, I2C_ADDRESS, reg, &value, 1, pdMS_TO_TICKS(50)) == ERROR_NONE;
|
||||
}
|
||||
|
||||
bool Tab5Keyboard::writeReg(uint8_t reg, uint8_t value) const {
|
||||
if (!i2cDev) return false;
|
||||
const uint8_t buf[2] = { reg, value };
|
||||
const esp_err_t err = i2c_master_transmit(i2cDev, buf, 2, pdMS_TO_TICKS(50));
|
||||
return err == ESP_OK;
|
||||
bool Tab5Keyboard::writeReg(uint8_t reg, uint8_t value) {
|
||||
return i2c_controller_write_register(i2cController, I2C_ADDRESS, reg, &value, 1, pdMS_TO_TICKS(50)) == ERROR_NONE;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -161,11 +158,7 @@ void Tab5Keyboard::updateLeds() {
|
||||
0x00, 0x00, aaSticky ? uint8_t(0xA0) : uint8_t(0x00), // LED1: red if Aa latched
|
||||
};
|
||||
// Write 7-byte block starting at REG_RGB_BASE
|
||||
const uint8_t reg = REG_RGB_BASE;
|
||||
uint8_t tx[8];
|
||||
tx[0] = reg;
|
||||
for (int i = 0; i < 7; i++) tx[i + 1] = buf[i];
|
||||
i2c_master_transmit(i2cDev, tx, 8, pdMS_TO_TICKS(50));
|
||||
i2c_controller_write_register(i2cController, I2C_ADDRESS, REG_RGB_BASE, buf, 7, pdMS_TO_TICKS(50));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -371,41 +364,10 @@ bool Tab5Keyboard::startLvgl(lv_display_t* display) {
|
||||
LOG_E("Tab5Keyboard", "Input queue allocation failed — cannot start");
|
||||
return false;
|
||||
}
|
||||
// Create LP I2C master bus (LP_I2C_NUM_0, GPIO 0/1) via new i2c_master API
|
||||
i2c_master_bus_config_t bus_cfg = {
|
||||
.i2c_port = LP_I2C_NUM_0,
|
||||
.sda_io_num = GPIO_NUM_0,
|
||||
.scl_io_num = GPIO_NUM_1,
|
||||
.clk_source = static_cast<i2c_clock_source_t>(LP_I2C_SCLK_DEFAULT),
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = { .enable_internal_pullup = true },
|
||||
};
|
||||
if (i2c_new_master_bus(&bus_cfg, &i2cBus) != ESP_OK) {
|
||||
LOG_E("Tab5Keyboard", "Failed to create LP I2C master bus");
|
||||
return false;
|
||||
}
|
||||
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = I2C_ADDRESS,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
if (i2c_master_bus_add_device(i2cBus, &dev_cfg, &i2cDev) != ESP_OK) {
|
||||
LOG_E("Tab5Keyboard", "Failed to add keyboard device to LP I2C bus");
|
||||
i2c_del_master_bus(i2cBus);
|
||||
i2cBus = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set Normal mode explicitly — device may power up in a different mode
|
||||
if (!writeReg(REG_KEYBOARD_MODE, 0x00)) {
|
||||
LOG_E("Tab5Keyboard", "Failed to set keyboard mode");
|
||||
i2c_master_bus_rm_device(i2cDev);
|
||||
i2c_del_master_bus(i2cBus);
|
||||
i2cDev = nullptr;
|
||||
i2cBus = nullptr;
|
||||
return false;
|
||||
}
|
||||
writeReg(REG_EVENT_NUM, 0x00); // flush event queue
|
||||
@ -426,10 +388,6 @@ bool Tab5Keyboard::startLvgl(lv_display_t* display) {
|
||||
// Enable Normal-mode interrupt (bit 0)
|
||||
if (!writeReg(REG_INT_CFG, 0x01)) {
|
||||
LOG_E("Tab5Keyboard", "Failed to configure interrupt register");
|
||||
i2c_master_bus_rm_device(i2cDev);
|
||||
i2c_del_master_bus(i2cBus);
|
||||
i2cDev = nullptr;
|
||||
i2cBus = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -470,38 +428,9 @@ bool Tab5Keyboard::stopLvgl() {
|
||||
lv_indev_delete(kbHandle);
|
||||
kbHandle = nullptr;
|
||||
|
||||
if (i2cDev) {
|
||||
i2c_master_bus_rm_device(i2cDev);
|
||||
i2cDev = nullptr;
|
||||
}
|
||||
if (i2cBus) {
|
||||
i2c_del_master_bus(i2cBus);
|
||||
i2cBus = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tab5Keyboard::isAttached() const {
|
||||
// If already started, just probe via the open bus handle
|
||||
if (i2cBus) {
|
||||
return i2c_master_probe(i2cBus, I2C_ADDRESS, pdMS_TO_TICKS(100)) == ESP_OK;
|
||||
}
|
||||
// Otherwise open a temporary bus to probe (LP I2C is not accessible via legacy API)
|
||||
i2c_master_bus_config_t bus_cfg = {
|
||||
.i2c_port = LP_I2C_NUM_0,
|
||||
.sda_io_num = GPIO_NUM_0,
|
||||
.scl_io_num = GPIO_NUM_1,
|
||||
.clk_source = static_cast<i2c_clock_source_t>(LP_I2C_SCLK_DEFAULT),
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = { .enable_internal_pullup = true },
|
||||
};
|
||||
i2c_master_bus_handle_t probe_bus = nullptr;
|
||||
if (i2c_new_master_bus(&bus_cfg, &probe_bus) != ESP_OK) {
|
||||
return false;
|
||||
}
|
||||
const esp_err_t ret = i2c_master_probe(probe_bus, I2C_ADDRESS, pdMS_TO_TICKS(100));
|
||||
i2c_del_master_bus(probe_bus);
|
||||
return ret == ESP_OK;
|
||||
return i2c_controller_has_device_at_address(i2cController, I2C_ADDRESS, pdMS_TO_TICKS(100)) == ERROR_NONE;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include <Tactility/hal/keyboard/KeyboardDevice.h>
|
||||
#include <Tactility/Timer.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <tactility/device.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <freertos/queue.h>
|
||||
|
||||
@ -13,8 +13,7 @@ class Tab5Keyboard final : public tt::hal::keyboard::KeyboardDevice {
|
||||
static constexpr uint32_t REPEAT_INITIAL_MS = 400;
|
||||
static constexpr uint32_t REPEAT_RATE_MS = 80;
|
||||
|
||||
i2c_master_bus_handle_t i2cBus = nullptr;
|
||||
i2c_master_dev_handle_t i2cDev = nullptr;
|
||||
::Device* i2cController = nullptr;
|
||||
|
||||
lv_indev_t* kbHandle = nullptr;
|
||||
QueueHandle_t queue = nullptr;
|
||||
@ -37,8 +36,8 @@ class Tab5Keyboard final : public tt::hal::keyboard::KeyboardDevice {
|
||||
uint32_t repeatStartMs = 0;
|
||||
uint32_t repeatLastMs = 0;
|
||||
|
||||
bool readReg(uint8_t reg, uint8_t& value) const;
|
||||
bool writeReg(uint8_t reg, uint8_t value) const;
|
||||
bool readReg(uint8_t reg, uint8_t& value);
|
||||
bool writeReg(uint8_t reg, uint8_t value);
|
||||
void updateLeds();
|
||||
|
||||
bool configureIrqPin();
|
||||
@ -50,7 +49,7 @@ class Tab5Keyboard final : public tt::hal::keyboard::KeyboardDevice {
|
||||
static void readCallback(lv_indev_t* indev, lv_indev_data_t* data);
|
||||
|
||||
public:
|
||||
Tab5Keyboard() {
|
||||
explicit Tab5Keyboard(::Device* i2cController) : i2cController(i2cController) {
|
||||
queue = xQueueCreate(20, sizeof(uint32_t));
|
||||
// queue == nullptr on OOM; startLvgl() checks and refuses to start
|
||||
}
|
||||
|
||||
@ -49,5 +49,3 @@ CONFIG_CACHE_L2_CACHE_256KB=y
|
||||
CONFIG_LVGL_PORT_ENABLE_PPA=y
|
||||
CONFIG_LV_DRAW_BUF_ALIGN=64
|
||||
CONFIG_LV_DEF_REFR_PERIOD=15
|
||||
# Allow new i2c_master API (used by Tab5Keyboard for LP_I2C_NUM_0) to coexist with legacy i2c driver
|
||||
CONFIG_I2C_SKIP_LEGACY_CONFLICT_CHECK=y
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include <tactility/bindings/esp32_ble.h>
|
||||
#include <tactility/bindings/esp32_gpio.h>
|
||||
#include <tactility/bindings/esp32_i2c.h>
|
||||
#include <tactility/bindings/esp32_i2c_master.h>
|
||||
#include <tactility/bindings/esp32_i2s.h>
|
||||
#include <tactility/bindings/esp32_spi.h>
|
||||
#include <tactility/bindings/esp32_uart.h>
|
||||
@ -68,6 +69,15 @@
|
||||
pin-scl = <&gpio0 54 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
i2c_keyboard: i2c2 {
|
||||
compatible = "espressif,esp32-i2c-master";
|
||||
port = <LP_I2C_NUM_0>;
|
||||
clock-frequency = <100000>;
|
||||
clock-source = <LP_I2C_SCLK_DEFAULT>;
|
||||
pin-sda = <&gpio0 0 GPIO_FLAG_PULL_UP>;
|
||||
pin-scl = <&gpio0 1 GPIO_FLAG_PULL_UP>;
|
||||
};
|
||||
|
||||
sdcard_spi: spi0 {
|
||||
compatible = "espressif,esp32-spi";
|
||||
host = <SPI2_HOST>;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#include "UnPhoneFeatures.h"
|
||||
#include <tactility/device.h>
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/LogMessages.h>
|
||||
#include <Tactility/Preferences.h>
|
||||
@ -160,7 +161,7 @@ static bool unPhonePowerOn() {
|
||||
bootStats.printInfo();
|
||||
bootStats.notifyBootStart();
|
||||
|
||||
bq24295 = std::make_shared<Bq24295>(I2C_NUM_0);
|
||||
bq24295 = std::make_shared<Bq24295>(device_find_by_name("i2c_internal"));
|
||||
|
||||
unPhoneFeatures = std::make_shared<UnPhoneFeatures>(bq24295);
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ class Aw9523 : public tt::hal::i2c::I2cDevice {
|
||||
|
||||
public:
|
||||
|
||||
explicit Aw9523(i2c_port_t port) : I2cDevice(port, AW9523_ADDRESS) {}
|
||||
explicit Aw9523(::Device* controller) : I2cDevice(controller, AW9523_ADDRESS) {}
|
||||
|
||||
std::string getName() const final { return "AW9523"; }
|
||||
std::string getDescription() const final { return "GPIO expander with LED driver and I2C interface."; }
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <axp192/axp192.h>
|
||||
#include <tactility/device.h>
|
||||
#include <Tactility/hal/power/PowerDevice.h>
|
||||
#include <Tactility/hal/i2c/I2c.h>
|
||||
|
||||
@ -14,7 +15,7 @@ class Axp192 final : public tt::hal::power::PowerDevice {
|
||||
public:
|
||||
|
||||
struct Configuration {
|
||||
i2c_port_t port;
|
||||
::Device* controller;
|
||||
TickType_t readTimeout = 50 / portTICK_PERIOD_MS;
|
||||
TickType_t writeTimeout = 50 / portTICK_PERIOD_MS;
|
||||
};
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
#include "Axp192.h"
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
|
||||
constexpr auto TAG = "Axp192Power";
|
||||
|
||||
int32_t Axp192::i2cRead(void* handle, uint8_t address, uint8_t reg, uint8_t* buffer, uint16_t size) {
|
||||
const auto* device = static_cast<Axp192*>(handle);
|
||||
if (tt::hal::i2c::masterReadRegister(device->configuration->port, address, reg, buffer, size, device->configuration->readTimeout)) {
|
||||
if (i2c_controller_read_register(device->configuration->controller, address, reg, buffer, size, device->configuration->readTimeout) == ERROR_NONE) {
|
||||
return AXP192_OK;
|
||||
} else {
|
||||
return 1;
|
||||
@ -13,7 +14,7 @@ int32_t Axp192::i2cRead(void* handle, uint8_t address, uint8_t reg, uint8_t* buf
|
||||
|
||||
int32_t Axp192::i2cWrite(void* handle, uint8_t address, uint8_t reg, const uint8_t* buffer, uint16_t size) {
|
||||
const auto* device = static_cast<Axp192*>(handle);
|
||||
if (tt::hal::i2c::masterWriteRegister(device->configuration->port, address, reg, buffer, size, device->configuration->writeTimeout)) {
|
||||
if (i2c_controller_write_register(device->configuration->controller, address, reg, buffer, size, device->configuration->writeTimeout) == ERROR_NONE) {
|
||||
return AXP192_OK;
|
||||
} else {
|
||||
return 1;
|
||||
|
||||
@ -54,5 +54,5 @@ bool Axp2101::getVBusVoltage(float& out) const {
|
||||
}
|
||||
|
||||
bool Axp2101::setRegisters(uint8_t* bytePairs, size_t bytePairsSize) const {
|
||||
return tt::hal::i2c::masterWriteRegisterArray(port, address, bytePairs, bytePairsSize, DEFAULT_TIMEOUT);
|
||||
return i2c_controller_write_register_array(controller, address, bytePairs, bytePairsSize, DEFAULT_TIMEOUT) == ERROR_NONE;
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ public:
|
||||
CHARGE_STATUS_STANDBY = 0b00
|
||||
};
|
||||
|
||||
explicit Axp2101(i2c_port_t port) : I2cDevice(port, AXP2101_ADDRESS) {}
|
||||
explicit Axp2101(::Device* controller) : I2cDevice(controller, AXP2101_ADDRESS) {}
|
||||
|
||||
std::string getName() const override { return "AXP2101"; }
|
||||
std::string getDescription() const override { return "Power management with I2C interface."; }
|
||||
|
||||
@ -22,7 +22,7 @@ public:
|
||||
Enabled160s = 0b110000
|
||||
};
|
||||
|
||||
explicit Bq24295(i2c_port_t port) : I2cDevice(port, BQ24295_ADDRESS) {}
|
||||
explicit Bq24295(::Device* controller) : I2cDevice(controller, BQ24295_ADDRESS) {}
|
||||
|
||||
bool getWatchDogTimer(WatchDogTimer& out) const;
|
||||
bool setWatchDogTimer(WatchDogTimer in) const;
|
||||
|
||||
@ -8,7 +8,7 @@ class Bq25896 final : public tt::hal::i2c::I2cDevice {
|
||||
|
||||
public:
|
||||
|
||||
explicit Bq25896(i2c_port_t port) : I2cDevice(port, BQ25896_ADDRESS) {
|
||||
explicit Bq25896(::Device* controller) : I2cDevice(controller, BQ25896_ADDRESS) {
|
||||
powerOn();
|
||||
}
|
||||
|
||||
|
||||
@ -89,7 +89,7 @@ public:
|
||||
|
||||
std::string getDescription() const override { return "I2C-controlled CEDV battery fuel gauge"; }
|
||||
|
||||
explicit Bq27220(i2c_port_t port) : I2cDevice(port, BQ27220_ADDRESS), accessKey(0xFFFFFFFF) {}
|
||||
explicit Bq27220(::Device* controller) : I2cDevice(controller, BQ27220_ADDRESS), accessKey(0xFFFFFFFF) {}
|
||||
|
||||
bool configureCapacity(uint16_t designCapacity, uint16_t fullChargeCapacity);
|
||||
bool getVoltage(uint16_t &value);
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
static const auto LOGGER = tt::Logger("DRV2605");
|
||||
|
||||
Drv2605::Drv2605(i2c_port_t port, bool autoPlayStartupBuzz) : I2cDevice(port, ADDRESS), autoPlayStartupBuzz(autoPlayStartupBuzz) {
|
||||
Drv2605::Drv2605(::Device* controller, bool autoPlayStartupBuzz) : I2cDevice(controller, ADDRESS), autoPlayStartupBuzz(autoPlayStartupBuzz) {
|
||||
check(init(), "Initialize DRV2605");
|
||||
|
||||
if (autoPlayStartupBuzz) {
|
||||
|
||||
@ -62,7 +62,7 @@ class Drv2605 : public tt::hal::i2c::I2cDevice {
|
||||
|
||||
public:
|
||||
|
||||
explicit Drv2605(i2c_port_t port, bool autoPlayStartupBuzz = true);
|
||||
explicit Drv2605(::Device* controller, bool autoPlayStartupBuzz = true);
|
||||
|
||||
std::string getName() const final { return "DRV2605"; }
|
||||
std::string getDescription() const final { return "Haptic driver for ERM/LRA with waveform library & auto-resonance tracking"; }
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include <Tactility/hal/touch/TouchDevice.h>
|
||||
#include <Tactility/TactilityCore.h>
|
||||
#include <tactility/device.h>
|
||||
#include <driver/i2c.h>
|
||||
|
||||
#include <EspLcdTouch.h>
|
||||
|
||||
@ -45,7 +45,7 @@ public:
|
||||
|
||||
std::string getDescription() const final { return "I2C-controlled keyboard scan IC"; }
|
||||
|
||||
explicit Tca8418(i2c_port_t port) : I2cDevice(port, TCA8418_ADDRESS) {
|
||||
explicit Tca8418(::Device* controller) : I2cDevice(controller, TCA8418_ADDRESS) {
|
||||
delta_micros = 0;
|
||||
last_update_micros = 0;
|
||||
this_update_micros = 0;
|
||||
|
||||
@ -6,7 +6,7 @@ idf_component_register(
|
||||
SRCS ${SOURCES}
|
||||
INCLUDE_DIRS "include/"
|
||||
PRIV_INCLUDE_DIRS "private/"
|
||||
REQUIRES TactilityKernel driver vfs fatfs
|
||||
REQUIRES TactilityKernel driver esp_driver_i2c vfs fatfs
|
||||
)
|
||||
|
||||
idf_component_optional_requires(PRIVATE bt usb espressif__usb_host_hid espressif__usb_host_msc)
|
||||
|
||||
@ -7,14 +7,14 @@ properties:
|
||||
type: int
|
||||
required: true
|
||||
description: "One of enum Esp32GroveMode"
|
||||
pinSclTx:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: SCL (I2C) or TX (UART) pin
|
||||
pinSdaRx:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: SDA (I2C) or RX (UART) pin
|
||||
pinSclTx:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: SCL (I2C) or TX (UART) pin
|
||||
uartPort:
|
||||
type: int
|
||||
required: true
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
description: ESP32 I2C Controller
|
||||
|
||||
include: ["i2c-controller.yaml"]
|
||||
|
||||
compatible: "espressif,esp32-i2c-master"
|
||||
|
||||
properties:
|
||||
port:
|
||||
type: int
|
||||
required: true
|
||||
description: |
|
||||
The port number, defined by i2c_port_t.
|
||||
Depending on the hardware, these values are available: I2C_NUM_0, I2C_NUM_1, LP_I2C_NUM_0
|
||||
clock-frequency:
|
||||
type: int
|
||||
required: true
|
||||
description: Initial clock frequency in Hz
|
||||
clock-source:
|
||||
type: int
|
||||
default: 0
|
||||
description: |
|
||||
Clock source for the I2C peripheral.
|
||||
If not specified, a default clock source will be used.
|
||||
pin-sda:
|
||||
type: phandle-array
|
||||
required: true
|
||||
pin-scl:
|
||||
type: phandle-array
|
||||
required: true
|
||||
@ -10,7 +10,7 @@ properties:
|
||||
required: true
|
||||
description: |
|
||||
The port number, defined by i2c_port_t.
|
||||
Depending on the hardware, these values are available: I2C_NUM_0, I2C_NUM_1, LP_I2C_NUM_0
|
||||
Depending on the hardware, these values are available: I2C_NUM_0, I2C_NUM_1
|
||||
clock-frequency:
|
||||
type: int
|
||||
required: true
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/bindings/bindings.h>
|
||||
#include <tactility/drivers/esp32_i2c_master.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DEFINE_DEVICETREE(esp32_i2c_master, struct Esp32I2cMasterConfig)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -12,8 +12,8 @@ extern "C" {
|
||||
|
||||
struct Esp32GroveConfig {
|
||||
enum GroveMode defaultMode;
|
||||
struct GpioPinSpec pinSclTx;
|
||||
struct GpioPinSpec pinSdaRx;
|
||||
struct GpioPinSpec pinSclTx;
|
||||
uart_port_t uartPort;
|
||||
i2c_port_t i2cPort;
|
||||
uint32_t i2cClockFrequency;
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/drivers/gpio.h>
|
||||
#include <driver/i2c_types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Esp32I2cMasterConfig {
|
||||
i2c_port_num_t port;
|
||||
uint32_t clockFrequency;
|
||||
int32_t clkSource;
|
||||
struct GpioPinSpec pinSda;
|
||||
struct GpioPinSpec pinScl;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -1,24 +1,24 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/drivers/esp32_grove.h>
|
||||
|
||||
#include "../../../../TactilityKernel/include/tactility/check.h"
|
||||
#include <tactility/drivers/esp32_i2c.h>
|
||||
#include <tactility/drivers/esp32_i2c_master.h>
|
||||
#include <tactility/drivers/esp32_uart.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
#include <tactility/drivers/esp32_i2c.h>
|
||||
#include <tactility/drivers/esp32_uart.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#define TAG "esp32_grove"
|
||||
|
||||
struct Esp32GroveInternal {
|
||||
struct Device* child_device = nullptr;
|
||||
Device* child_device = nullptr;
|
||||
void* child_config = nullptr;
|
||||
char* child_name = nullptr;
|
||||
enum GroveMode current_mode = GROVE_MODE_DISABLED;
|
||||
GroveMode current_mode = GROVE_MODE_DISABLED;
|
||||
};
|
||||
|
||||
#define GET_CONFIG(device) ((const struct Esp32GroveConfig*)device->config)
|
||||
@ -26,7 +26,7 @@ struct Esp32GroveInternal {
|
||||
|
||||
extern "C" {
|
||||
|
||||
static error_t stop_child(struct Device* device) {
|
||||
static error_t stop_child(Device* device) {
|
||||
auto* data = GET_DATA(device);
|
||||
if (!data) return ERROR_NONE;
|
||||
|
||||
@ -52,9 +52,9 @@ static error_t stop_child(struct Device* device) {
|
||||
|
||||
if (data->child_config) {
|
||||
if (data->current_mode == GROVE_MODE_UART) {
|
||||
delete (struct Esp32UartConfig*)data->child_config;
|
||||
delete static_cast<Esp32UartConfig*>(data->child_config);
|
||||
} else if (data->current_mode == GROVE_MODE_I2C) {
|
||||
delete (struct Esp32I2cConfig*)data->child_config;
|
||||
delete static_cast<Esp32I2cMasterConfig*>(data->child_config);
|
||||
}
|
||||
data->child_config = nullptr;
|
||||
}
|
||||
@ -66,7 +66,7 @@ static error_t stop_child(struct Device* device) {
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t start_child(struct Device* device, enum GroveMode mode) {
|
||||
static error_t start_child(Device* device, GroveMode mode) {
|
||||
const auto* config = GET_CONFIG(device);
|
||||
auto* data = GET_DATA(device);
|
||||
|
||||
@ -76,11 +76,11 @@ static error_t start_child(struct Device* device, enum GroveMode mode) {
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
data->child_device = new(std::nothrow) struct Device();
|
||||
data->child_device = new(std::nothrow) Device();
|
||||
if (!data->child_device) {
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
std::memset(data->child_device, 0, sizeof(struct Device));
|
||||
std::memset(data->child_device, 0, sizeof(Device));
|
||||
|
||||
size_t name_len = std::strlen(device->name) + 10;
|
||||
data->child_name = new(std::nothrow) char[name_len];
|
||||
@ -89,13 +89,15 @@ static error_t start_child(struct Device* device, enum GroveMode mode) {
|
||||
data->child_device = nullptr;
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
std::snprintf(data->child_name, name_len, "%s_child", device->name);
|
||||
data->child_device->name = data->child_name;
|
||||
data->child_device->parent = device;
|
||||
|
||||
data->child_device->parent = device;
|
||||
const char* compatible = nullptr;
|
||||
|
||||
if (mode == GROVE_MODE_UART) {
|
||||
// Device name
|
||||
std::snprintf(data->child_name, name_len, "%s_uart", device->name);
|
||||
data->child_device->name = data->child_name;
|
||||
// Device config
|
||||
auto* uart_cfg = new(std::nothrow) struct Esp32UartConfig();
|
||||
if (!uart_cfg) {
|
||||
delete[] data->child_name;
|
||||
@ -104,7 +106,7 @@ static error_t start_child(struct Device* device, enum GroveMode mode) {
|
||||
data->child_device = nullptr;
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
std::memset(uart_cfg, 0, sizeof(struct Esp32UartConfig));
|
||||
std::memset(uart_cfg, 0, sizeof(Esp32UartConfig));
|
||||
uart_cfg->port = config->uartPort;
|
||||
uart_cfg->pin_tx = config->pinSclTx;
|
||||
uart_cfg->pin_rx = config->pinSdaRx;
|
||||
@ -114,7 +116,11 @@ static error_t start_child(struct Device* device, enum GroveMode mode) {
|
||||
compatible = "espressif,esp32-uart";
|
||||
LOG_I(TAG, "%s: starting UART mode on port %d", device->name, (int)uart_cfg->port);
|
||||
} else if (mode == GROVE_MODE_I2C) {
|
||||
auto* i2c_cfg = new(std::nothrow) struct Esp32I2cConfig();
|
||||
// Device name
|
||||
std::snprintf(data->child_name, name_len, "%s_i2c", device->name);
|
||||
data->child_device->name = data->child_name;
|
||||
// Device config
|
||||
auto* i2c_cfg = new (std::nothrow) struct Esp32I2cMasterConfig();
|
||||
if (!i2c_cfg) {
|
||||
delete[] data->child_name;
|
||||
data->child_name = nullptr;
|
||||
@ -122,18 +128,21 @@ static error_t start_child(struct Device* device, enum GroveMode mode) {
|
||||
data->child_device = nullptr;
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
std::memset(i2c_cfg, 0, sizeof(struct Esp32I2cConfig));
|
||||
i2c_cfg->port = config->i2cPort;
|
||||
std::memset(i2c_cfg, 0, sizeof(Esp32I2cMasterConfig));
|
||||
i2c_cfg->port = static_cast<i2c_port_num_t>(config->i2cPort);
|
||||
i2c_cfg->clockFrequency = config->i2cClockFrequency;
|
||||
i2c_cfg->pinSda = config->pinSdaRx;
|
||||
i2c_cfg->pinScl = config->pinSclTx;
|
||||
i2c_cfg->clkSource = 0; // Default
|
||||
data->child_config = i2c_cfg;
|
||||
compatible = "espressif,esp32-i2c";
|
||||
LOG_I(TAG, "%s: starting I2C mode on port %d", device->name, (int)i2c_cfg->port);
|
||||
compatible = "espressif,esp32-i2c-master";
|
||||
LOG_I(TAG, "%s: starting I2C mode on port %d", device->name, (int)config->i2cPort);
|
||||
} else {
|
||||
LOG_E(TAG, "%s: unknown mode %d", device->name, mode);
|
||||
delete[] data->child_name;
|
||||
data->child_name = nullptr;
|
||||
if (data->child_name != nullptr) {
|
||||
delete[] data->child_name;
|
||||
data->child_name = nullptr;
|
||||
}
|
||||
delete data->child_device;
|
||||
data->child_device = nullptr;
|
||||
return ERROR_INVALID_ARGUMENT;
|
||||
@ -152,8 +161,9 @@ static error_t start_child(struct Device* device, enum GroveMode mode) {
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t start_device(struct Device* device) {
|
||||
static error_t start_device(Device* device) {
|
||||
const auto* config = GET_CONFIG(device);
|
||||
|
||||
auto* data = new(std::nothrow) Esp32GroveInternal();
|
||||
if (!data) return ERROR_OUT_OF_MEMORY;
|
||||
device_set_driver_data(device, data);
|
||||
@ -161,7 +171,7 @@ static error_t start_device(struct Device* device) {
|
||||
return start_child(device, config->defaultMode);
|
||||
}
|
||||
|
||||
static error_t stop_device(struct Device* device) {
|
||||
static error_t stop_device(Device* device) {
|
||||
auto* data = GET_DATA(device);
|
||||
if (!data) return ERROR_NONE;
|
||||
|
||||
@ -172,7 +182,7 @@ static error_t stop_device(struct Device* device) {
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t esp32_grove_set_mode(struct Device* device, enum GroveMode mode) {
|
||||
static error_t esp32_grove_set_mode(Device* device, enum GroveMode mode) {
|
||||
auto* data = GET_DATA(device);
|
||||
if (data->current_mode == mode) return ERROR_NONE;
|
||||
|
||||
@ -182,18 +192,18 @@ static error_t esp32_grove_set_mode(struct Device* device, enum GroveMode mode)
|
||||
return start_child(device, mode);
|
||||
}
|
||||
|
||||
static error_t esp32_grove_get_mode(struct Device* device, enum GroveMode* mode) {
|
||||
static error_t esp32_grove_get_mode(Device* device, enum GroveMode* mode) {
|
||||
auto* data = GET_DATA(device);
|
||||
*mode = data->current_mode;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static const struct GroveApi esp32_grove_api = {
|
||||
static const GroveApi esp32_grove_api = {
|
||||
.set_mode = esp32_grove_set_mode,
|
||||
.get_mode = esp32_grove_get_mode
|
||||
};
|
||||
|
||||
extern struct Module platform_esp32_module;
|
||||
extern Module platform_esp32_module;
|
||||
|
||||
Driver esp32_grove_driver = {
|
||||
.name = "esp32_grove",
|
||||
|
||||
@ -175,16 +175,12 @@ static error_t start(Device* device) {
|
||||
check(gpio_descriptor_get_native_pin_number(sda_descriptor, &sda_pin) == ERROR_NONE);
|
||||
check(gpio_descriptor_get_native_pin_number(scl_descriptor, &scl_pin) == ERROR_NONE);
|
||||
|
||||
gpio_flags_t sda_flags, scl_flags;
|
||||
check(gpio_descriptor_get_flags(sda_descriptor, &sda_flags) == ERROR_NONE);
|
||||
check(gpio_descriptor_get_flags(scl_descriptor, &scl_flags) == ERROR_NONE);
|
||||
|
||||
i2c_config_t esp_config = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = sda_pin,
|
||||
.scl_io_num = scl_pin,
|
||||
.sda_pullup_en = (sda_flags & GPIO_FLAG_PULL_UP) != 0,
|
||||
.scl_pullup_en = (scl_flags & GPIO_FLAG_PULL_UP) != 0,
|
||||
.sda_pullup_en = (sda_spec.flags & GPIO_FLAG_PULL_UP) != 0,
|
||||
.scl_pullup_en = (scl_spec.flags & GPIO_FLAG_PULL_UP) != 0,
|
||||
.master {
|
||||
.clk_speed = dts_config->clockFrequency
|
||||
},
|
||||
|
||||
311
Platforms/platform-esp32/source/drivers/esp32_i2c_master.cpp
Normal file
311
Platforms/platform-esp32/source/drivers/esp32_i2c_master.cpp
Normal file
@ -0,0 +1,311 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <driver/i2c_master.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <tactility/error_esp32.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/drivers/gpio_controller.h>
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/drivers/esp32_i2c_master.h>
|
||||
#include <tactility/log.h>
|
||||
#include <tactility/time.h>
|
||||
|
||||
#define TAG "esp32_i2c_master"
|
||||
|
||||
struct Esp32I2cMasterInternal {
|
||||
Mutex mutex {};
|
||||
GpioDescriptor* sda_descriptor = nullptr;
|
||||
GpioDescriptor* scl_descriptor = nullptr;
|
||||
i2c_master_bus_handle_t bus_handle = nullptr;
|
||||
i2c_master_dev_handle_t dev_handle = nullptr;
|
||||
int current_address = -1;
|
||||
|
||||
Esp32I2cMasterInternal(GpioDescriptor* sda_descriptor, GpioDescriptor* scl_descriptor) :
|
||||
sda_descriptor(sda_descriptor),
|
||||
scl_descriptor(scl_descriptor)
|
||||
{
|
||||
mutex_construct(&mutex);
|
||||
}
|
||||
|
||||
~Esp32I2cMasterInternal() {
|
||||
mutex_destruct(&mutex);
|
||||
}
|
||||
};
|
||||
|
||||
#define GET_CONFIG(device) ((Esp32I2cMasterConfig*)device->config)
|
||||
#define GET_DATA(device) ((Esp32I2cMasterInternal*)device_get_driver_data(device))
|
||||
|
||||
#define lock(data) mutex_lock(&data->mutex);
|
||||
#define unlock(data) mutex_unlock(&data->mutex);
|
||||
|
||||
// Switches the device's target address only when it differs from the currently configured one.
|
||||
static esp_err_t ensure_address(Esp32I2cMasterInternal* driver_data, uint8_t address, int timeout_ms) {
|
||||
if (driver_data->current_address == address) {
|
||||
return ESP_OK;
|
||||
}
|
||||
esp_err_t esp_error = i2c_master_device_change_address(driver_data->dev_handle, address, timeout_ms);
|
||||
if (esp_error == ESP_OK) {
|
||||
driver_data->current_address = address;
|
||||
}
|
||||
return esp_error;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
static int ticks_to_ms(TickType_t ticks) {
|
||||
if (ticks == portMAX_DELAY) return -1;
|
||||
return (int)pdTICKS_TO_MS(ticks);
|
||||
}
|
||||
|
||||
static error_t read(Device* device, uint8_t address, uint8_t* data, size_t data_size, TickType_t timeout) {
|
||||
if (xPortInIsrContext()) return ERROR_ISR_STATUS;
|
||||
if (data_size == 0) return ERROR_INVALID_ARGUMENT;
|
||||
auto* driver_data = GET_DATA(device);
|
||||
int timeout_ms = ticks_to_ms(timeout);
|
||||
|
||||
lock(driver_data);
|
||||
esp_err_t esp_error = ensure_address(driver_data, address, timeout_ms);
|
||||
if (esp_error != ESP_OK) {
|
||||
LOG_E(TAG, "change_address(0x%02X) failed: %s", address, esp_err_to_name(esp_error));
|
||||
} else {
|
||||
esp_error = i2c_master_receive(driver_data->dev_handle, data, data_size, timeout_ms);
|
||||
if (esp_error != ESP_OK) {
|
||||
LOG_E(TAG, "receive(0x%02X) failed: %s", address, esp_err_to_name(esp_error));
|
||||
}
|
||||
}
|
||||
unlock(driver_data);
|
||||
return esp_err_to_error(esp_error);
|
||||
}
|
||||
|
||||
static error_t write(Device* device, uint8_t address, const uint8_t* data, uint16_t data_size, TickType_t timeout) {
|
||||
if (xPortInIsrContext()) return ERROR_ISR_STATUS;
|
||||
if (data_size == 0) return ERROR_INVALID_ARGUMENT;
|
||||
auto* driver_data = GET_DATA(device);
|
||||
int timeout_ms = ticks_to_ms(timeout);
|
||||
|
||||
lock(driver_data);
|
||||
esp_err_t esp_error = ensure_address(driver_data, address, timeout_ms);
|
||||
if (esp_error != ESP_OK) {
|
||||
LOG_E(TAG, "change_address(0x%02X) failed: %s", address, esp_err_to_name(esp_error));
|
||||
} else {
|
||||
esp_error = i2c_master_transmit(driver_data->dev_handle, data, data_size, timeout_ms);
|
||||
if (esp_error != ESP_OK) {
|
||||
LOG_E(TAG, "transmit(0x%02X) failed: %s", address, esp_err_to_name(esp_error));
|
||||
}
|
||||
}
|
||||
unlock(driver_data);
|
||||
return esp_err_to_error(esp_error);
|
||||
}
|
||||
|
||||
static error_t write_read(Device* device, uint8_t address, const uint8_t* write_data, size_t write_data_size, uint8_t* read_data, size_t read_data_size, TickType_t timeout) {
|
||||
if (xPortInIsrContext()) return ERROR_ISR_STATUS;
|
||||
if (write_data_size == 0 || read_data_size == 0) return ERROR_INVALID_ARGUMENT;
|
||||
auto* driver_data = GET_DATA(device);
|
||||
int timeout_ms = ticks_to_ms(timeout);
|
||||
|
||||
lock(driver_data);
|
||||
esp_err_t esp_error = ensure_address(driver_data, address, timeout_ms);
|
||||
if (esp_error != ESP_OK) {
|
||||
LOG_E(TAG, "change_address(0x%02X) failed: %s", address, esp_err_to_name(esp_error));
|
||||
} else {
|
||||
esp_error = i2c_master_transmit_receive(driver_data->dev_handle, write_data, write_data_size, read_data, read_data_size, timeout_ms);
|
||||
if (esp_error != ESP_OK) {
|
||||
LOG_E(TAG, "transmit_receive(0x%02X) failed: %s", address, esp_err_to_name(esp_error));
|
||||
}
|
||||
}
|
||||
unlock(driver_data);
|
||||
return esp_err_to_error(esp_error);
|
||||
}
|
||||
|
||||
static error_t read_register(Device* device, uint8_t address, uint8_t reg, uint8_t* data, size_t data_size, TickType_t timeout) {
|
||||
if (xPortInIsrContext()) return ERROR_ISR_STATUS;
|
||||
if (data_size == 0) return ERROR_INVALID_ARGUMENT;
|
||||
auto* driver_data = GET_DATA(device);
|
||||
int timeout_ms = ticks_to_ms(timeout);
|
||||
|
||||
lock(driver_data);
|
||||
esp_err_t esp_error = ensure_address(driver_data, address, timeout_ms);
|
||||
if (esp_error != ESP_OK) {
|
||||
LOG_E(TAG, "change_address(0x%02X) failed: %s", address, esp_err_to_name(esp_error));
|
||||
} else {
|
||||
esp_error = i2c_master_transmit_receive(driver_data->dev_handle, ®, 1, data, data_size, timeout_ms);
|
||||
if (esp_error != ESP_OK) {
|
||||
LOG_E(TAG, "read_register(0x%02X, reg=0x%02X) failed: %s", address, reg, esp_err_to_name(esp_error));
|
||||
}
|
||||
}
|
||||
unlock(driver_data);
|
||||
return esp_err_to_error(esp_error);
|
||||
}
|
||||
|
||||
static error_t write_register(Device* device, uint8_t address, uint8_t reg, const uint8_t* data, uint16_t data_size, TickType_t timeout) {
|
||||
if (xPortInIsrContext()) return ERROR_ISR_STATUS;
|
||||
if (data_size == 0) return ERROR_INVALID_ARGUMENT;
|
||||
auto* driver_data = GET_DATA(device);
|
||||
int timeout_ms = ticks_to_ms(timeout);
|
||||
|
||||
lock(driver_data);
|
||||
esp_err_t esp_error = ensure_address(driver_data, address, timeout_ms);
|
||||
if (esp_error != ESP_OK) {
|
||||
LOG_E(TAG, "change_address(0x%02X) failed: %s", address, esp_err_to_name(esp_error));
|
||||
} else {
|
||||
i2c_master_transmit_multi_buffer_info_t buffers[2] = {
|
||||
{.write_buffer = ®, .buffer_size = 1},
|
||||
{.write_buffer = data, .buffer_size = data_size}
|
||||
};
|
||||
esp_error = i2c_master_multi_buffer_transmit(driver_data->dev_handle, buffers, 2, timeout_ms);
|
||||
if (esp_error != ESP_OK) {
|
||||
LOG_E(TAG, "write_register(0x%02X, reg=0x%02X) failed: %s", address, reg, esp_err_to_name(esp_error));
|
||||
}
|
||||
}
|
||||
unlock(driver_data);
|
||||
return esp_err_to_error(esp_error);
|
||||
}
|
||||
|
||||
static error_t probe(Device* device, uint8_t address, TickType_t timeout) {
|
||||
if (xPortInIsrContext()) return ERROR_ISR_STATUS;
|
||||
auto* driver_data = GET_DATA(device);
|
||||
int timeout_ms = ticks_to_ms(timeout);
|
||||
|
||||
lock(driver_data);
|
||||
esp_err_t esp_error = i2c_master_probe(driver_data->bus_handle, address, timeout_ms);
|
||||
if (esp_error == ESP_ERR_NOT_FOUND) {
|
||||
// Expected outcome when no device acks - e.g. hot-plug attach polling
|
||||
LOG_D(TAG, "probe(0x%02X): not found", address);
|
||||
} else if (esp_error != ESP_OK) {
|
||||
LOG_E(TAG, "probe(0x%02X) failed: %s", address, esp_err_to_name(esp_error));
|
||||
}
|
||||
unlock(driver_data);
|
||||
return esp_err_to_error(esp_error);
|
||||
}
|
||||
|
||||
static error_t start(Device* device) {
|
||||
ESP_LOGI(TAG, "start %s", device->name);
|
||||
auto dts_config = GET_CONFIG(device);
|
||||
|
||||
auto& sda_spec = dts_config->pinSda;
|
||||
auto& scl_spec = dts_config->pinScl;
|
||||
auto* sda_descriptor = gpio_descriptor_acquire(sda_spec.gpio_controller, sda_spec.pin, GPIO_OWNER_GPIO);
|
||||
if (!sda_descriptor) {
|
||||
LOG_E(TAG, "Failed to acquire pin %u", sda_spec.pin);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
auto* scl_descriptor = gpio_descriptor_acquire(scl_spec.gpio_controller, scl_spec.pin, GPIO_OWNER_GPIO);
|
||||
if (!scl_descriptor) {
|
||||
LOG_E(TAG, "Failed to acquire pin %u", scl_spec.pin);
|
||||
gpio_descriptor_release(sda_descriptor);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
gpio_num_t sda_pin, scl_pin;
|
||||
check(gpio_descriptor_get_native_pin_number(sda_descriptor, &sda_pin) == ERROR_NONE);
|
||||
check(gpio_descriptor_get_native_pin_number(scl_descriptor, &scl_pin) == ERROR_NONE);
|
||||
|
||||
i2c_master_bus_config_t bus_config = {
|
||||
.i2c_port = dts_config->port,
|
||||
.sda_io_num = sda_pin,
|
||||
.scl_io_num = scl_pin,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = {
|
||||
.enable_internal_pullup = ((sda_spec.flags & GPIO_FLAG_PULL_UP) != 0) || ((scl_spec.flags & GPIO_FLAG_PULL_UP) != 0),
|
||||
.allow_pd = 0,
|
||||
}
|
||||
};
|
||||
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
if (dts_config->port == LP_I2C_NUM_0) {
|
||||
bus_config.lp_source_clk = (dts_config->clkSource == 0) ? LP_I2C_SCLK_DEFAULT : static_cast<lp_i2c_clock_source_t>(dts_config->clkSource);
|
||||
} else {
|
||||
bus_config.clk_source = (dts_config->clkSource == 0) ? I2C_CLK_SRC_DEFAULT : static_cast<i2c_clock_source_t>(dts_config->clkSource);
|
||||
}
|
||||
#else
|
||||
bus_config.clk_source = (dts_config->clkSource == 0) ? I2C_CLK_SRC_DEFAULT : static_cast<i2c_clock_source_t>(dts_config->clkSource);
|
||||
#endif
|
||||
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
esp_err_t error = i2c_new_master_bus(&bus_config, &bus_handle);
|
||||
if (error != ESP_OK) {
|
||||
LOG_E(TAG, "Failed to create I2C bus at port %d: %s", (int)dts_config->port, esp_err_to_name(error));
|
||||
gpio_descriptor_release(sda_descriptor);
|
||||
gpio_descriptor_release(scl_descriptor);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
i2c_device_config_t dev_config = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = 0, // Will be changed at runtime
|
||||
.scl_speed_hz = dts_config->clockFrequency,
|
||||
.scl_wait_us = 0,
|
||||
.flags = {
|
||||
.disable_ack_check = 0,
|
||||
}
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
error = i2c_master_bus_add_device(bus_handle, &dev_config, &dev_handle);
|
||||
if (error != ESP_OK) {
|
||||
LOG_E(TAG, "Failed to add I2C device: %s", esp_err_to_name(error));
|
||||
i2c_del_master_bus(bus_handle);
|
||||
gpio_descriptor_release(sda_descriptor);
|
||||
gpio_descriptor_release(scl_descriptor);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
auto* data = new(std::nothrow) Esp32I2cMasterInternal(sda_descriptor, scl_descriptor);
|
||||
if (data == nullptr) {
|
||||
i2c_master_bus_rm_device(dev_handle);
|
||||
i2c_del_master_bus(bus_handle);
|
||||
gpio_descriptor_release(sda_descriptor);
|
||||
gpio_descriptor_release(scl_descriptor);
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
data->bus_handle = bus_handle;
|
||||
data->dev_handle = dev_handle;
|
||||
|
||||
device_set_driver_data(device, data);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t stop(Device* device) {
|
||||
ESP_LOGI(TAG, "stop %s", device->name);
|
||||
auto* driver_data = GET_DATA(device);
|
||||
|
||||
i2c_master_bus_rm_device(driver_data->dev_handle);
|
||||
i2c_del_master_bus(driver_data->bus_handle);
|
||||
|
||||
gpio_descriptor_release(driver_data->sda_descriptor);
|
||||
gpio_descriptor_release(driver_data->scl_descriptor);
|
||||
|
||||
device_set_driver_data(device, nullptr);
|
||||
delete driver_data;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static constexpr I2cControllerApi ESP32_I2C_MASTER_API = {
|
||||
.read = read,
|
||||
.write = write,
|
||||
.write_read = write_read,
|
||||
.read_register = read_register,
|
||||
.write_register = write_register,
|
||||
.probe = probe
|
||||
};
|
||||
|
||||
extern Module platform_esp32_module;
|
||||
|
||||
Driver esp32_i2c_master_driver = {
|
||||
.name = "esp32_i2c_master",
|
||||
.compatible = (const char*[]) { "espressif,esp32-i2c-master", nullptr },
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = &ESP32_I2C_MASTER_API,
|
||||
.device_type = &I2C_CONTROLLER_TYPE,
|
||||
.owner = &platform_esp32_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
@ -13,6 +13,7 @@ extern "C" {
|
||||
|
||||
extern Driver esp32_gpio_driver;
|
||||
extern Driver esp32_i2c_driver;
|
||||
extern Driver esp32_i2c_master_driver;
|
||||
extern Driver esp32_i2s_driver;
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
extern Driver esp32_sdmmc_driver;
|
||||
@ -38,6 +39,7 @@ static error_t start() {
|
||||
* there is no guarantee that the previously constructed drivers can be destroyed */
|
||||
check(driver_construct_add(&esp32_gpio_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_i2c_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_i2c_master_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_i2s_driver) == ERROR_NONE);
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
check(driver_construct_add(&esp32_sdmmc_driver) == ERROR_NONE);
|
||||
@ -77,6 +79,7 @@ static error_t stop() {
|
||||
#endif
|
||||
check(driver_remove_destruct(&esp32_gpio_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_i2c_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_i2c_master_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_i2s_driver) == ERROR_NONE);
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
check(driver_remove_destruct(&esp32_sdmmc_driver) == ERROR_NONE);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <tactility/hal/Device.h>
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include "I2c.h"
|
||||
|
||||
namespace tt::hal::i2c {
|
||||
@ -10,12 +11,13 @@ namespace tt::hal::i2c {
|
||||
* It helps to read and write registers.
|
||||
*
|
||||
* All read and write calls are thread-safe.
|
||||
* @deprecated Use the device API from the Kernel project
|
||||
*/
|
||||
class I2cDevice : public Device {
|
||||
|
||||
protected:
|
||||
|
||||
i2c_port_t port;
|
||||
::Device* controller;
|
||||
uint8_t address;
|
||||
|
||||
static constexpr TickType_t DEFAULT_TIMEOUT = 1000 / portTICK_PERIOD_MS;
|
||||
@ -36,11 +38,11 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
explicit I2cDevice(i2c_port_t port, uint32_t address) : port(port), address(address) {}
|
||||
explicit I2cDevice(::Device* controller, uint32_t address) : controller(controller), address(address) {}
|
||||
|
||||
Type getType() const override { return Type::I2c; }
|
||||
|
||||
i2c_port_t getPort() const { return port; }
|
||||
::Device* getController() const { return controller; }
|
||||
|
||||
uint8_t getAddress() const { return address; }
|
||||
};
|
||||
|
||||
@ -3,12 +3,14 @@
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
struct Device;
|
||||
|
||||
namespace tt::app::i2cscanner {
|
||||
|
||||
std::string getAddressText(uint8_t address);
|
||||
|
||||
std::string getPortNamesForDropdown();
|
||||
|
||||
bool getActivePortAtIndex(int32_t index, int32_t& out);
|
||||
bool getActivePortAtIndex(int32_t index, struct Device** out);
|
||||
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
#include "Tactility/app/i2cscanner/I2cHelpers.h"
|
||||
|
||||
#include <Tactility/StringUtils.h>
|
||||
#include <Tactility/hal/i2c/I2c.h>
|
||||
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
@ -19,31 +20,36 @@ std::string getAddressText(uint8_t address) {
|
||||
|
||||
std::string getPortNamesForDropdown() {
|
||||
std::vector<std::string> config_names;
|
||||
for (int port = 0; port < I2C_NUM_MAX; ++port) {
|
||||
auto native_port = static_cast<i2c_port_t>(port);
|
||||
if (hal::i2c::isStarted(native_port)) {
|
||||
auto* name = hal::i2c::getName(native_port);
|
||||
if (name != nullptr) {
|
||||
config_names.push_back(name);
|
||||
}
|
||||
device_for_each_of_type(&I2C_CONTROLLER_TYPE, &config_names, [](auto* device, auto* context) {
|
||||
auto* names = static_cast<std::vector<std::string>*>(context);
|
||||
if (device_is_ready(device)) {
|
||||
names->push_back(device->name);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return string::join(config_names, "\n");
|
||||
}
|
||||
|
||||
bool getActivePortAtIndex(int32_t index, int32_t& out) {
|
||||
int current_index = -1;
|
||||
for (int port = 0; port < I2C_NUM_MAX; ++port) {
|
||||
auto native_port = static_cast<i2c_port_t>(port);
|
||||
if (hal::i2c::isStarted(native_port)) {
|
||||
current_index++;
|
||||
if (current_index == index) {
|
||||
out = port;
|
||||
return true;
|
||||
bool getActivePortAtIndex(int32_t index, struct Device** out) {
|
||||
struct Context {
|
||||
int32_t targetIndex;
|
||||
int32_t currentIndex;
|
||||
struct Device* foundDevice;
|
||||
} context = { index, 0, nullptr };
|
||||
|
||||
device_for_each_of_type(&I2C_CONTROLLER_TYPE, &context, [](auto* device, auto* ctx) {
|
||||
auto* c = static_cast<Context*>(ctx);
|
||||
if (device_is_ready(device)) {
|
||||
if (c->currentIndex == c->targetIndex) {
|
||||
c->foundDevice = device;
|
||||
return false;
|
||||
}
|
||||
c->currentIndex++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
*out = context.foundDevice;
|
||||
return context.foundDevice != nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
#include <Tactility/Assets.h>
|
||||
#include <Tactility/app/AppContext.h>
|
||||
#include <Tactility/hal/i2c/I2cDevice.h>
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/LogMessages.h>
|
||||
#include <Tactility/lvgl/LvglSync.h>
|
||||
@ -33,7 +33,7 @@ class I2cScannerApp final : public App {
|
||||
std::unique_ptr<Timer> scanTimer = nullptr;
|
||||
// State
|
||||
ScanState scanState = ScanStateInitial;
|
||||
i2c_port_t port = I2C_NUM_0;
|
||||
struct Device* portDevice = nullptr;
|
||||
std::vector<uint8_t> scannedAddresses;
|
||||
// Widgets
|
||||
lv_obj_t* scanButtonLabelWidget = nullptr;
|
||||
@ -54,7 +54,7 @@ class I2cScannerApp final : public App {
|
||||
void onScanTimer();
|
||||
|
||||
bool shouldStopScanTimer();
|
||||
bool getPort(i2c_port_t* outPort);
|
||||
bool getPort(struct Device** outPort);
|
||||
bool addAddressToList(uint8_t address);
|
||||
bool hasScanThread();
|
||||
void startScanning();
|
||||
@ -140,8 +140,10 @@ void I2cScannerApp::onShow(AppContext& app, lv_obj_t* parent) {
|
||||
lv_obj_add_flag(scan_list, LV_OBJ_FLAG_HIDDEN);
|
||||
scanListWidget = scan_list;
|
||||
|
||||
int32_t first_port;
|
||||
if (getActivePortAtIndex(0, first_port)) {
|
||||
struct Device* dummy;
|
||||
if (getActivePortAtIndex(selected_bus, &dummy)) {
|
||||
selectBus(selected_bus);
|
||||
} else if (getActivePortAtIndex(0, &dummy)) {
|
||||
lv_dropdown_set_selected(port_dropdown, 0);
|
||||
selectBus(0);
|
||||
}
|
||||
@ -184,9 +186,9 @@ void I2cScannerApp::onPressScanCallback(lv_event_t* event) {
|
||||
|
||||
// endregion Callbacks
|
||||
|
||||
bool I2cScannerApp::getPort(i2c_port_t* outPort) {
|
||||
bool I2cScannerApp::getPort(struct Device** outPort) {
|
||||
if (mutex.lock(100 / portTICK_PERIOD_MS)) {
|
||||
*outPort = this->port;
|
||||
*outPort = this->portDevice;
|
||||
mutex.unlock();
|
||||
return true;
|
||||
} else {
|
||||
@ -219,21 +221,21 @@ bool I2cScannerApp::shouldStopScanTimer() {
|
||||
void I2cScannerApp::onScanTimer() {
|
||||
logger.info("Scan thread started");
|
||||
|
||||
i2c_port_t safe_port;
|
||||
struct Device* safe_port;
|
||||
if (!getPort(&safe_port)) {
|
||||
logger.error("Failed to get I2C port");
|
||||
onScanTimerFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hal::i2c::isStarted(safe_port)) {
|
||||
if (!device_is_ready(safe_port)) {
|
||||
logger.error("I2C port not started");
|
||||
onScanTimerFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint8_t address = 0; address < 128; ++address) {
|
||||
if (hal::i2c::masterHasDeviceAtAddress(safe_port, address, 10 / portTICK_PERIOD_MS)) {
|
||||
if (i2c_controller_has_device_at_address(safe_port, address, 10 / portTICK_PERIOD_MS) == ERROR_NONE) {
|
||||
logger.info("Found device at address 0x{:02X}", address);
|
||||
if (!shouldStopScanTimer()) {
|
||||
addAddressToList(address);
|
||||
@ -305,14 +307,14 @@ void I2cScannerApp::onSelectBus(lv_event_t* event) {
|
||||
}
|
||||
|
||||
void I2cScannerApp::selectBus(int32_t selected) {
|
||||
int32_t found_port;
|
||||
if (!getActivePortAtIndex(selected, found_port)) {
|
||||
struct Device* found_device;
|
||||
if (!getActivePortAtIndex(selected, &found_device)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mutex.lock(100 / portTICK_PERIOD_MS)) {
|
||||
scannedAddresses.clear();
|
||||
port = static_cast<i2c_port_t>(found_port);
|
||||
portDevice = found_device;
|
||||
scanState = ScanStateInitial;
|
||||
mutex.unlock();
|
||||
}
|
||||
@ -334,16 +336,6 @@ void I2cScannerApp::onPressScan(lv_event_t* event) {
|
||||
updateViews();
|
||||
}
|
||||
|
||||
static bool findDeviceName(const std::vector<std::shared_ptr<hal::i2c::I2cDevice>>& devices, i2c_port_t port, uint8_t address, std::string& outName) {
|
||||
for (auto& device : devices) {
|
||||
if (device->getPort() == port && device->getAddress() == address) {
|
||||
outName = device->getName();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void I2cScannerApp::updateViews() {
|
||||
if (mutex.lock(100 / portTICK_PERIOD_MS)) {
|
||||
if (scanState == ScanStateScanning) {
|
||||
@ -358,18 +350,10 @@ void I2cScannerApp::updateViews() {
|
||||
if (scanState == ScanStateStopped) {
|
||||
lv_obj_remove_flag(scanListWidget, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
auto devices = hal::findDevices<hal::i2c::I2cDevice>(hal::Device::Type::I2c);
|
||||
|
||||
if (!scannedAddresses.empty()) {
|
||||
for (auto address: scannedAddresses) {
|
||||
std::string address_text = getAddressText(address);
|
||||
std::string device_name;
|
||||
if (findDeviceName(devices, port, address, device_name)) {
|
||||
auto text = std::format("{} - {}", address_text, device_name);
|
||||
lv_list_add_text(scanListWidget, text.c_str());
|
||||
} else {
|
||||
lv_list_add_text(scanListWidget, address_text.c_str());
|
||||
}
|
||||
lv_list_add_text(scanListWidget, address_text.c_str());
|
||||
}
|
||||
} else {
|
||||
lv_list_add_text(scanListWidget, "No devices found");
|
||||
|
||||
@ -5,24 +5,24 @@
|
||||
namespace tt::hal::i2c {
|
||||
|
||||
bool I2cDevice::read(uint8_t* data, size_t dataSize, TickType_t timeout) {
|
||||
return masterRead(port, address, data, dataSize, timeout);
|
||||
return i2c_controller_read(controller, address, data, dataSize, timeout) == ERROR_NONE;
|
||||
}
|
||||
|
||||
bool I2cDevice::write(const uint8_t* data, uint16_t dataSize, TickType_t timeout) {
|
||||
return masterWrite(port, address, data, dataSize, timeout);
|
||||
return i2c_controller_write(controller, address, data, dataSize, timeout) == ERROR_NONE;
|
||||
}
|
||||
|
||||
bool I2cDevice::writeRead(const uint8_t* writeData, size_t writeDataSize, uint8_t* readData, size_t readDataSize, TickType_t timeout) {
|
||||
return masterWriteRead(port, address, writeData, writeDataSize, readData, readDataSize, timeout);
|
||||
return i2c_controller_write_read(controller, address, writeData, writeDataSize, readData, readDataSize, timeout) == ERROR_NONE;
|
||||
}
|
||||
|
||||
bool I2cDevice::writeRegister(uint8_t reg, const uint8_t* data, uint16_t dataSize, TickType_t timeout) {
|
||||
return masterWriteRegister(port, address, reg, data, dataSize, timeout);
|
||||
return i2c_controller_write_register(controller, address, reg, data, dataSize, timeout) == ERROR_NONE;
|
||||
}
|
||||
|
||||
bool I2cDevice::readRegister12(uint8_t reg, float& out) const {
|
||||
std::uint8_t data[2] = {0};
|
||||
if (masterReadRegister(port, address, reg, data, 2, DEFAULT_TIMEOUT)) {
|
||||
if (i2c_controller_read_register(controller, address, reg, data, 2, DEFAULT_TIMEOUT) == ERROR_NONE) {
|
||||
out = (data[0] & 0x0F) << 8 | data[1];
|
||||
return true;
|
||||
} else {
|
||||
@ -32,7 +32,7 @@ bool I2cDevice::readRegister12(uint8_t reg, float& out) const {
|
||||
|
||||
bool I2cDevice::readRegister14(uint8_t reg, float& out) const {
|
||||
std::uint8_t data[2] = {0};
|
||||
if (masterReadRegister(port, address, reg, data, 2, DEFAULT_TIMEOUT)) {
|
||||
if (i2c_controller_read_register(controller, address, reg, data, 2, DEFAULT_TIMEOUT) == ERROR_NONE) {
|
||||
out = (data[0] & 0x3F) << 8 | data[1];
|
||||
return true;
|
||||
} else {
|
||||
@ -42,7 +42,7 @@ bool I2cDevice::readRegister14(uint8_t reg, float& out) const {
|
||||
|
||||
bool I2cDevice::readRegister16(uint8_t reg, uint16_t& out) const {
|
||||
std::uint8_t data[2] = {0};
|
||||
if (masterReadRegister(port, address, reg, data, 2, DEFAULT_TIMEOUT)) {
|
||||
if (i2c_controller_read_register(controller, address, reg, data, 2, DEFAULT_TIMEOUT) == ERROR_NONE) {
|
||||
out = data[0] << 8 | data[1];
|
||||
return true;
|
||||
} else {
|
||||
@ -51,11 +51,11 @@ bool I2cDevice::readRegister16(uint8_t reg, uint16_t& out) const {
|
||||
}
|
||||
|
||||
bool I2cDevice::readRegister8(uint8_t reg, uint8_t& result) const {
|
||||
return masterWriteRead(port, address, ®, 1, &result, 1, DEFAULT_TIMEOUT);
|
||||
return i2c_controller_write_read(controller, address, ®, 1, &result, 1, DEFAULT_TIMEOUT) == ERROR_NONE;
|
||||
}
|
||||
|
||||
bool I2cDevice::writeRegister8(uint8_t reg, uint8_t value) const {
|
||||
return masterWriteRegister(port, address, reg, &value, 1, DEFAULT_TIMEOUT);
|
||||
return i2c_controller_write_register(controller, address, reg, &value, 1, DEFAULT_TIMEOUT) == ERROR_NONE;
|
||||
}
|
||||
|
||||
bool I2cDevice::bitOn(uint8_t reg, uint8_t bitmask) const {
|
||||
|
||||
@ -21,7 +21,7 @@ extern "C" {
|
||||
#define GPIO_FLAG_DIRECTION_INPUT (1 << 1)
|
||||
#define GPIO_FLAG_DIRECTION_OUTPUT (1 << 2)
|
||||
#define GPIO_FLAG_DIRECTION_INPUT_OUTPUT (GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_DIRECTION_OUTPUT)
|
||||
#define GPIO_FLAG_PULL_UP (0 << 3)
|
||||
#define GPIO_FLAG_PULL_UP (1 << 3)
|
||||
#define GPIO_FLAG_PULL_DOWN (1 << 4)
|
||||
#define GPIO_FLAG_INTERRUPT_BITMASK (0b111 << 5) // 3 bits to hold the values [0, 5]
|
||||
#define GPIO_FLAG_INTERRUPT_FROM_OPTIONS(options) (gpio_int_type_t)((options & GPIO_FLAG_INTERRUPT_BITMASK) >> 5)
|
||||
|
||||
@ -19,6 +19,9 @@ enum GroveMode {
|
||||
|
||||
/**
|
||||
* @brief API for Grove drivers.
|
||||
*
|
||||
* The grove driver is meant for external interfaces with two wires that can be used as UART, I2C or GPIO as needed.
|
||||
* It can be used with the Grove connector, but also with others such as Stemma QT.
|
||||
*/
|
||||
struct GroveApi {
|
||||
/**
|
||||
|
||||
@ -82,6 +82,17 @@ struct I2cControllerApi {
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t (*write_register)(struct Device* device, uint8_t address, uint8_t reg, const uint8_t* data, uint16_t dataSize, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Checks if a device responds at the given address, without performing a data transfer.
|
||||
* Optional: set to NULL if the driver does not support a dedicated probe operation, in which case
|
||||
* @ref i2c_controller_has_device_at_address falls back to a generic write-based probe.
|
||||
* @param[in] device the I2C controller device
|
||||
* @param[in] address the 7-bit I2C address to probe
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when a device acknowledged the address
|
||||
*/
|
||||
error_t (*probe)(struct Device* device, uint8_t address, TickType_t timeout);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -73,8 +73,12 @@ error_t i2c_controller_write_register_array(Device* device, uint8_t address, con
|
||||
|
||||
error_t i2c_controller_has_device_at_address(Device* device, uint8_t address, TickType_t timeout) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
auto* api = I2C_DRIVER_API(driver);
|
||||
if (api->probe != nullptr) {
|
||||
return api->probe(device, address, timeout);
|
||||
}
|
||||
uint8_t message[2] = { 0, 0 };
|
||||
return I2C_DRIVER_API(driver)->write(device, address, message, 2, timeout);
|
||||
return api->write(device, address, message, 2, timeout);
|
||||
}
|
||||
|
||||
error_t i2c_controller_register16le_get(Device* device, uint8_t address, uint8_t reg, uint16_t* value, TickType_t timeout) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user