bit bang the "i2c" protocol

This commit is contained in:
Samuel Sieb
2022-07-30 22:42:34 -07:00
parent 4733a0fa7a
commit fbee7bd8ff
4 changed files with 54 additions and 16 deletions

View File

@@ -1,11 +1,11 @@
# SM2235 LED driver
Requires a configured i2c bus
Example:
```yaml
sm2235:
- id: my_sm #optional
sda: 4
scl: 5
rgb_current: 12 #optional
cw_current: 25 #optional

View File

@@ -1,13 +1,12 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c
from esphome.const import CONF_ID, CONF_NUM_CHANNELS
from esphome import pins
from esphome.const import CONF_ID, CONF_NUM_CHANNELS, CONF_SCL, CONF_SDA
DEPENDENCIES = ["i2c"]
MULTI_CONF = True
sm2235_ns = cg.esphome_ns.namespace("sm2235")
SM2235 = sm2235_ns.class_("SM2235", cg.Component, i2c.I2CDevice)
SM2235 = sm2235_ns.class_("SM2235", cg.Component)
CONF_RGB_CURRENT = "rgb_current"
CONF_CW_CURRENT = "cw_current"
@@ -16,19 +15,23 @@ CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(SM2235),
cv.Required(CONF_SDA): pins.internal_gpio_input_pin_schema,
cv.Required(CONF_SCL): pins.internal_gpio_input_pin_schema,
cv.Optional(CONF_RGB_CURRENT, default=12): cv.int_range(min=4, max=64),
cv.Optional(CONF_CW_CURRENT, default=25): cv.int_range(min=5, max=80),
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(i2c.i2c_device_schema(0))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
pin = await cg.gpio_pin_expression(config[CONF_SDA])
cg.add(var.set_sda_pin(pin))
pin = await cg.gpio_pin_expression(config[CONF_SCL])
cg.add(var.set_scl_pin(pin))
currents = round((config[CONF_RGB_CURRENT] - 4) / 4) * 16 + round((config[CONF_CW_CURRENT] - 5) / 5)
cg.add(var.set_currents(currents))

View File

@@ -1,18 +1,44 @@
#include "sm2235.h"
#include "esphome/core/log.h"
#include "esphome/core/helpers.h"
#include "esphome/core/hal.h"
namespace esphome {
namespace sm2235 {
static const char *const TAG = "sm2235";
void SM2235::setup() {
this->sda_pin_->setup();
this->scl_pin_->setup();
this->scl_pin_->digital_write(true);
this->sda_pin_->digital_write(true);
}
void SM2235::dump_config() {
ESP_LOGCONFIG(TAG, "SM2235:");
ESP_LOGCONFIG(TAG, " Channels: %d", this->num_channels_);
}
void SM2235::start_() {
this->sda_pin_->digital_write(false);
delayMicroseconds(4);
}
void SM2235::stop_() {
this->sda_pin_->digital_write(true);
delayMicroseconds(2);
}
void SM2235::send_byte_(uint8_t value) {
for (int i = 0; i < 9; i++, value <<= 1) {
this->scl_pin_->digital_write(false);
this->sda_pin_->digital_write(value & 0x80 > 0);
delayMicroseconds(2);
this->scl_pin_->digital_write(true);
delayMicroseconds(2);
}
}
void SM2235::update_(uint8_t channel) {
uint8_t byte0 = 0xc0 + channel;
switch(this->num_channels_) {
@@ -27,12 +53,13 @@ void SM2235::update_(uint8_t channel) {
case 5:
byte0 |= 0x30; break;
}
uint8_t data[3];
data[0] = this->currents_;
this->start_();
this->send_byte_(byte0);
this->send_byte_(this->currents_);
uint16_t value = this->values_[channel];
data[1] = value >> 8;
data[2] = value & 0xff;
this->bus_->write(byte0, data, 3);
this->send_byte_(value >> 8);
this->send_byte_(value & 0xff);
this->stop_();
}
void SM2235::register_channel(SM2235Channel *channel, uint8_t num) {

View File

@@ -1,8 +1,8 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/components/output/float_output.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace sm2235 {
@@ -21,10 +21,13 @@ class SM2235Channel : public output::FloatOutput {
SM2235 *parent_;
};
class SM2235 : public Component, public i2c::I2CDevice {
class SM2235 : public Component {
public:
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::HARDWARE; }
void set_sda_pin(InternalGPIOPin *pin) { this->sda_pin_ = pin; }
void set_scl_pin(InternalGPIOPin *pin) { this->scl_pin_ = pin; }
void register_channel(SM2235Channel *channel, uint8_t num);
void set_currents(uint8_t currents) { this->currents_ = currents; }
@@ -35,7 +38,12 @@ class SM2235 : public Component, public i2c::I2CDevice {
uint8_t currents_;
uint8_t num_channels_{0};
uint16_t values_[5] = {0};
InternalGPIOPin *sda_pin_;
InternalGPIOPin *scl_pin_;
void start_();
void stop_();
void send_byte_(uint8_t value);
void update_(uint8_t channel);
};