mirror of
https://github.com/esphome/esphome.git
synced 2024-12-25 23:14:54 +01:00
Always execute i2c bus recovery on setup (#2379)
This commit is contained in:
parent
210a9a4162
commit
963b28181f
4 changed files with 72 additions and 0 deletions
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "i2c_bus_arduino.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <Arduino.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace esphome {
|
||||
|
@ -10,6 +11,7 @@ namespace i2c {
|
|||
static const char *const TAG = "i2c.arduino";
|
||||
|
||||
void ArduinoI2CBus::setup() {
|
||||
recover();
|
||||
#ifdef USE_ESP32
|
||||
static uint8_t next_bus_num = 0;
|
||||
if (next_bus_num == 0)
|
||||
|
@ -90,6 +92,32 @@ ErrorCode ArduinoI2CBus::writev(uint8_t address, WriteBuffer *buffers, size_t cn
|
|||
return ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
void ArduinoI2CBus::recover() {
|
||||
// Perform I2C bus recovery, see
|
||||
// https://www.analog.com/media/en/technical-documentation/application-notes/54305147357414AN686_0.pdf
|
||||
// or see the linux kernel implementation, e.g.
|
||||
// https://elixir.bootlin.com/linux/v5.14.6/source/drivers/i2c/i2c-core-base.c#L200
|
||||
|
||||
// try to get about 100kHz toggle frequency
|
||||
const auto half_period_usec = 1000000 / 100000 / 2;
|
||||
const auto recover_scl_periods = 9;
|
||||
|
||||
// configure scl as output
|
||||
pinMode(scl_pin_, OUTPUT); // NOLINT
|
||||
|
||||
// set scl high
|
||||
digitalWrite(scl_pin_, 1); // NOLINT
|
||||
|
||||
// in total generate 9 falling-rising edges
|
||||
for (auto i = 0; i < recover_scl_periods; i++) {
|
||||
delayMicroseconds(half_period_usec);
|
||||
digitalWrite(scl_pin_, 0); // NOLINT
|
||||
delayMicroseconds(half_period_usec);
|
||||
digitalWrite(scl_pin_, 1); // NOLINT
|
||||
}
|
||||
|
||||
delayMicroseconds(half_period_usec);
|
||||
}
|
||||
} // namespace i2c
|
||||
} // namespace esphome
|
||||
|
||||
|
|
|
@ -22,6 +22,9 @@ class ArduinoI2CBus : public I2CBus, public Component {
|
|||
void set_scl_pin(uint8_t scl_pin) { scl_pin_ = scl_pin; }
|
||||
void set_frequency(uint32_t frequency) { frequency_ = frequency; }
|
||||
|
||||
private:
|
||||
void recover();
|
||||
|
||||
protected:
|
||||
TwoWire *wire_;
|
||||
bool scan_;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifdef USE_ESP_IDF
|
||||
|
||||
#include "i2c_bus_esp_idf.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <cstring>
|
||||
|
||||
|
@ -13,6 +14,8 @@ void IDFI2CBus::setup() {
|
|||
static i2c_port_t next_port = 0;
|
||||
port_ = next_port++;
|
||||
|
||||
recover();
|
||||
|
||||
i2c_config_t conf{};
|
||||
memset(&conf, 0, sizeof(conf));
|
||||
conf.mode = I2C_MODE_MASTER;
|
||||
|
@ -141,6 +144,41 @@ ErrorCode IDFI2CBus::writev(uint8_t address, WriteBuffer *buffers, size_t cnt) {
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
void IDFI2CBus::recover() {
|
||||
// Perform I2C bus recovery, see
|
||||
// https://www.analog.com/media/en/technical-documentation/application-notes/54305147357414AN686_0.pdf
|
||||
// or see the linux kernel implementation, e.g.
|
||||
// https://elixir.bootlin.com/linux/v5.14.6/source/drivers/i2c/i2c-core-base.c#L200
|
||||
|
||||
// try to get about 100kHz toggle frequency
|
||||
const auto half_period_usec = 1000000 / 100000 / 2;
|
||||
const auto recover_scl_periods = 9;
|
||||
const gpio_num_t scl_pin = static_cast<gpio_num_t>(scl_pin_);
|
||||
|
||||
// configure scl as output
|
||||
gpio_config_t conf{};
|
||||
conf.pin_bit_mask = 1ULL << static_cast<uint32_t>(scl_pin_);
|
||||
conf.mode = GPIO_MODE_OUTPUT;
|
||||
conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
conf.intr_type = GPIO_INTR_DISABLE;
|
||||
|
||||
gpio_config(&conf);
|
||||
|
||||
// set scl high
|
||||
gpio_set_level(scl_pin, 1);
|
||||
|
||||
// in total generate 9 falling-rising edges
|
||||
for (auto i = 0; i < recover_scl_periods; i++) {
|
||||
delayMicroseconds(half_period_usec);
|
||||
gpio_set_level(scl_pin, 0);
|
||||
delayMicroseconds(half_period_usec);
|
||||
gpio_set_level(scl_pin, 1);
|
||||
}
|
||||
|
||||
delayMicroseconds(half_period_usec);
|
||||
}
|
||||
|
||||
} // namespace i2c
|
||||
} // namespace esphome
|
||||
|
||||
|
|
|
@ -24,6 +24,9 @@ class IDFI2CBus : public I2CBus, public Component {
|
|||
void set_scl_pullup_enabled(bool scl_pullup_enabled) { scl_pullup_enabled_ = scl_pullup_enabled; }
|
||||
void set_frequency(uint32_t frequency) { frequency_ = frequency; }
|
||||
|
||||
private:
|
||||
void recover();
|
||||
|
||||
protected:
|
||||
i2c_port_t port_;
|
||||
bool scan_;
|
||||
|
|
Loading…
Reference in a new issue