mirror of
https://github.com/esphome/esphome.git
synced 2026-10-25 23:42:15 +00:00
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a5cb7d957 | ||
|
|
058d9db4dc | ||
|
|
0077231478 | ||
|
|
2faaaa4c3c | ||
|
|
371884d97e | ||
|
|
55182cda22 | ||
|
|
46fde171b6 | ||
|
|
8132569898 | ||
|
|
b41e8ff924 |
No files matched your search
@@ -4,6 +4,11 @@
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
// clang-tidy cannot parse the Realtek SDK headers behind wiring_data.h
|
||||
#if defined(USE_BK72XX) || (defined(USE_RTL87XX) && !defined(CLANG_TIDY))
|
||||
#include <wiring_data.h>
|
||||
#endif
|
||||
|
||||
namespace esphome::libretiny {
|
||||
|
||||
ESPHOME_LOG_TAG(TAG, "libretiny.gpio");
|
||||
@@ -26,16 +31,10 @@ static int IRAM_ATTR flags_to_mode(gpio::Flags flags) {
|
||||
}
|
||||
}
|
||||
|
||||
struct ISRPinArg {
|
||||
uint8_t pin;
|
||||
bool inverted;
|
||||
};
|
||||
|
||||
// The ISR copy is the pin itself, so both share the stored mode and level. Pins are never freed.
|
||||
ISRInternalGPIOPin ArduinoInternalGPIOPin::to_isr() const {
|
||||
auto *arg = new ISRPinArg{}; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
arg->pin = pin_;
|
||||
arg->inverted = inverted_;
|
||||
return ISRInternalGPIOPin((void *) arg);
|
||||
return ISRInternalGPIOPin(
|
||||
const_cast<ArduinoInternalGPIOPin *>(this)); // NOLINT(cppcoreguidelines-pro-type-const-cast)
|
||||
}
|
||||
|
||||
void ArduinoInternalGPIOPin::attach_interrupt_(void (*func)(void *), void *arg, gpio::InterruptType type) const {
|
||||
@@ -61,8 +60,59 @@ void ArduinoInternalGPIOPin::attach_interrupt_(void (*func)(void *), void *arg,
|
||||
attachInterruptParam(pin_, func, arduino_mode, arg);
|
||||
}
|
||||
|
||||
#ifdef USE_BK72XX
|
||||
// BDK GPIO config register (REG_GPIO_0_CONFIG, GCFG_OUTPUT_BIT): 0 enables the output, bit 1 is the output level
|
||||
static constexpr uintptr_t BK_GPIO_CFG_BASE = 0x00802800;
|
||||
static constexpr uint32_t BK_GPIO_OUTPUT_BIT = 1 << 1;
|
||||
|
||||
// LibreTiny's switch to output always starts the pin LOW. Enable the output at its level in one store, then update
|
||||
// LibreTiny's pin state the way its own switch does (cores/beken-72xx/arduino/src/wiring_digital.c).
|
||||
static bool bk_enter_output(uint8_t pin, bool level) {
|
||||
PinInfo *info = pinInfo(pin);
|
||||
if (info == nullptr || info->gpio > 31)
|
||||
return false;
|
||||
PinData *data = pinData(info);
|
||||
if (pinEnabled(info, PIN_GPIO) && data->gpioMode == OUTPUT)
|
||||
return false;
|
||||
pinRemoveMode(info, PIN_PWM);
|
||||
auto *cfg =
|
||||
reinterpret_cast<volatile uint32_t *>(BK_GPIO_CFG_BASE + info->gpio * 4); // NOLINT(performance-no-int-to-ptr)
|
||||
*cfg = level ? BK_GPIO_OUTPUT_BIT : 0;
|
||||
pinEnable(info, PIN_GPIO);
|
||||
data->gpioMode = OUTPUT;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_RTL87XX) && !defined(CLANG_TIDY)
|
||||
// The switch to output keeps the HAL data register, so write the level to it first
|
||||
static void rtl_preset_level(uint8_t pin, bool level) {
|
||||
PinInfo *info = pinInfo(pin);
|
||||
if (info == nullptr)
|
||||
return;
|
||||
if (info->data == nullptr || info->data->gpio == nullptr)
|
||||
pinMode(pin, INPUT); // NOLINT - LibreTiny creates the gpio_t on first use
|
||||
if (info->data != nullptr && info->data->gpio != nullptr)
|
||||
gpio_write(info->data->gpio, level);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ArduinoInternalGPIOPin::pin_mode(gpio::Flags flags) {
|
||||
pinMode(pin_, flags_to_mode(flags)); // NOLINT
|
||||
const int mode = flags_to_mode(flags);
|
||||
this->output_ = flags & gpio::FLAG_OUTPUT;
|
||||
#ifdef USE_BK72XX
|
||||
if (mode == OUTPUT && bk_enter_output(this->pin_, this->level_))
|
||||
return;
|
||||
#endif
|
||||
#if defined(USE_RTL87XX) && !defined(CLANG_TIDY)
|
||||
// The preset avoids a LOW blip when going HIGH, but a LOW only takes after the switch (measured on a BW15),
|
||||
// so the write below is still needed
|
||||
if (mode == OUTPUT)
|
||||
rtl_preset_level(this->pin_, this->level_);
|
||||
#endif
|
||||
pinMode(this->pin_, mode); // NOLINT
|
||||
if (this->output_)
|
||||
digitalWrite(this->pin_, this->level_); // NOLINT
|
||||
}
|
||||
|
||||
size_t ArduinoInternalGPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
@@ -70,10 +120,12 @@ size_t ArduinoInternalGPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
}
|
||||
|
||||
bool ArduinoInternalGPIOPin::digital_read() {
|
||||
return bool(digitalRead(pin_)) ^ inverted_; // NOLINT
|
||||
return bool(digitalRead(this->pin_)) ^ this->inverted_; // NOLINT
|
||||
}
|
||||
void ArduinoInternalGPIOPin::digital_write(bool value) {
|
||||
digitalWrite(pin_, value ^ inverted_); // NOLINT
|
||||
this->level_ = value ^ this->inverted_;
|
||||
if (this->output_)
|
||||
digitalWrite(this->pin_, this->level_); // NOLINT
|
||||
}
|
||||
void ArduinoInternalGPIOPin::detach_interrupt() const {
|
||||
detachInterrupt(pin_); // NOLINT
|
||||
@@ -86,20 +138,16 @@ namespace esphome {
|
||||
using namespace libretiny;
|
||||
|
||||
bool IRAM_ATTR ISRInternalGPIOPin::digital_read() {
|
||||
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
|
||||
return bool(digitalRead(arg->pin)) ^ arg->inverted; // NOLINT
|
||||
return reinterpret_cast<ArduinoInternalGPIOPin *>(this->arg_)->digital_read();
|
||||
}
|
||||
void IRAM_ATTR ISRInternalGPIOPin::digital_write(bool value) {
|
||||
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
|
||||
digitalWrite(arg->pin, value ^ arg->inverted); // NOLINT
|
||||
reinterpret_cast<ArduinoInternalGPIOPin *>(this->arg_)->digital_write(value);
|
||||
}
|
||||
void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() {
|
||||
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
|
||||
detachInterrupt(arg->pin);
|
||||
detachInterrupt(reinterpret_cast<ArduinoInternalGPIOPin *>(this->arg_)->get_pin());
|
||||
}
|
||||
void IRAM_ATTR ISRInternalGPIOPin::pin_mode(gpio::Flags flags) {
|
||||
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
|
||||
pinMode(arg->pin, flags_to_mode(flags)); // NOLINT
|
||||
reinterpret_cast<ArduinoInternalGPIOPin *>(this->arg_)->pin_mode(flags);
|
||||
}
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
@@ -30,7 +30,12 @@ class ArduinoInternalGPIOPin final : public GPIOPin {
|
||||
void attach_interrupt_(void (*func)(void *), void *arg, gpio::InterruptType type) const;
|
||||
|
||||
uint8_t pin_;
|
||||
bool inverted_{};
|
||||
bool inverted_ : 1 {};
|
||||
// LibreTiny drops writes to a pin that is not an output; keep the level until it becomes one.
|
||||
// Remove with bk_enter_output() and rtl_preset_level() once LibreTiny handles this.
|
||||
// These bits share a byte with the ISR copy, so a pin must not be written from an ISR and the loop at once.
|
||||
bool output_ : 1 {};
|
||||
bool level_ : 1 {};
|
||||
gpio::Flags flags_{};
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user