From 821c1a8bbdb6b2812a36b066b28bac856768ff4b Mon Sep 17 00:00:00 2001 From: igg Date: Wed, 10 Jun 2020 13:03:11 -0700 Subject: [PATCH] making SPI CS optional (#988) * making SPI CS optional * CS pin should be declared as optional or required in CONFIG_SCHEMA * changed SPI_DEVICE_SCHEMA to a function, like i2c * added spi_device_schema() to pcd8544, lint fixes * updated max31856 with new spi_device_schema() * cleanup imports Co-authored-by: Ilya Goldberg --- esphome/components/as3935_spi/__init__.py | 4 +-- esphome/components/atm90e32/sensor.py | 2 +- esphome/components/max31855/sensor.py | 2 +- esphome/components/max31856/sensor.py | 2 +- esphome/components/max31865/sensor.py | 2 +- esphome/components/max6675/sensor.py | 2 +- esphome/components/max7219/display.py | 2 +- esphome/components/pcd8544/display.py | 2 +- esphome/components/pn532/__init__.py | 2 +- esphome/components/pn532/pn532.cpp | 3 +- esphome/components/spi/__init__.py | 22 ++++++++++---- esphome/components/spi/spi.cpp | 8 +++-- esphome/components/spi/spi.h | 30 +++++++++++-------- esphome/components/ssd1306_spi/display.py | 2 +- esphome/components/ssd1325_spi/display.py | 2 +- .../components/ssd1325_spi/ssd1325_spi.cpp | 21 ++++++++----- .../components/waveshare_epaper/display.py | 2 +- 17 files changed, 67 insertions(+), 43 deletions(-) diff --git a/esphome/components/as3935_spi/__init__.py b/esphome/components/as3935_spi/__init__.py index fa27c2b0f5..da5582c531 100644 --- a/esphome/components/as3935_spi/__init__.py +++ b/esphome/components/as3935_spi/__init__.py @@ -10,8 +10,8 @@ as3935_spi_ns = cg.esphome_ns.namespace('as3935_spi') SPIAS3935 = as3935_spi_ns.class_('SPIAS3935Component', as3935.AS3935, spi.SPIDevice) CONFIG_SCHEMA = cv.All(as3935.AS3935_SCHEMA.extend({ - cv.GenerateID(): cv.declare_id(SPIAS3935) -}).extend(cv.COMPONENT_SCHEMA).extend(spi.SPI_DEVICE_SCHEMA)) + cv.GenerateID(): cv.declare_id(SPIAS3935), +}).extend(cv.COMPONENT_SCHEMA).extend(spi.spi_device_schema(CS_PIN_required=True))) def to_code(config): diff --git a/esphome/components/atm90e32/sensor.py b/esphome/components/atm90e32/sensor.py index fc526dfbc0..f27fd3126a 100644 --- a/esphome/components/atm90e32/sensor.py +++ b/esphome/components/atm90e32/sensor.py @@ -55,7 +55,7 @@ CONFIG_SCHEMA = cv.Schema({ cv.Required(CONF_LINE_FREQUENCY): cv.enum(LINE_FREQS, upper=True), cv.Optional(CONF_CURRENT_PHASES, default='3'): cv.enum(CURRENT_PHASES, upper=True), cv.Optional(CONF_GAIN_PGA, default='2X'): cv.enum(PGA_GAINS, upper=True), -}).extend(cv.polling_component_schema('60s')).extend(spi.SPI_DEVICE_SCHEMA) +}).extend(cv.polling_component_schema('60s')).extend(spi.spi_device_schema()) def to_code(config): diff --git a/esphome/components/max31855/sensor.py b/esphome/components/max31855/sensor.py index dce28bd542..d1b5649b3e 100644 --- a/esphome/components/max31855/sensor.py +++ b/esphome/components/max31855/sensor.py @@ -11,7 +11,7 @@ CONFIG_SCHEMA = sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).extend({ cv.GenerateID(): cv.declare_id(MAX31855Sensor), cv.Optional(CONF_REFERENCE_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 2), -}).extend(cv.polling_component_schema('60s')).extend(spi.SPI_DEVICE_SCHEMA) +}).extend(cv.polling_component_schema('60s')).extend(spi.spi_device_schema()) def to_code(config): diff --git a/esphome/components/max31856/sensor.py b/esphome/components/max31856/sensor.py index 523b5301d4..4e1411a2a4 100644 --- a/esphome/components/max31856/sensor.py +++ b/esphome/components/max31856/sensor.py @@ -16,7 +16,7 @@ FILTER = { CONFIG_SCHEMA = sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).extend({ cv.GenerateID(): cv.declare_id(MAX31856Sensor), cv.Optional(CONF_MAINS_FILTER, default='60HZ'): cv.enum(FILTER, upper=True, space=''), -}).extend(cv.polling_component_schema('60s')).extend(spi.SPI_DEVICE_SCHEMA) +}).extend(cv.polling_component_schema('60s')).extend(spi.spi_device_schema()) def to_code(config): diff --git a/esphome/components/max31865/sensor.py b/esphome/components/max31865/sensor.py index ff1df9c5c8..7df36dfde4 100644 --- a/esphome/components/max31865/sensor.py +++ b/esphome/components/max31865/sensor.py @@ -20,7 +20,7 @@ CONFIG_SCHEMA = sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 2).extend({ cv.Required(CONF_RTD_NOMINAL_RESISTANCE): cv.All(cv.resistance, cv.Range(min=100, max=1000)), cv.Optional(CONF_MAINS_FILTER, default='60HZ'): cv.enum(FILTER, upper=True, space=''), cv.Optional(CONF_RTD_WIRES, default=4): cv.int_range(min=2, max=4), -}).extend(cv.polling_component_schema('60s')).extend(spi.SPI_DEVICE_SCHEMA) +}).extend(cv.polling_component_schema('60s')).extend(spi.spi_device_schema()) def to_code(config): diff --git a/esphome/components/max6675/sensor.py b/esphome/components/max6675/sensor.py index 59d24a5283..7f0c943399 100644 --- a/esphome/components/max6675/sensor.py +++ b/esphome/components/max6675/sensor.py @@ -9,7 +9,7 @@ MAX6675Sensor = max6675_ns.class_('MAX6675Sensor', sensor.Sensor, cg.PollingComp CONFIG_SCHEMA = sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).extend({ cv.GenerateID(): cv.declare_id(MAX6675Sensor), -}).extend(cv.polling_component_schema('60s')).extend(spi.SPI_DEVICE_SCHEMA) +}).extend(cv.polling_component_schema('60s')).extend(spi.spi_device_schema()) def to_code(config): diff --git a/esphome/components/max7219/display.py b/esphome/components/max7219/display.py index c96454ce8c..0657f3f042 100644 --- a/esphome/components/max7219/display.py +++ b/esphome/components/max7219/display.py @@ -14,7 +14,7 @@ CONFIG_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend({ cv.Optional(CONF_NUM_CHIPS, default=1): cv.int_range(min=1, max=255), cv.Optional(CONF_INTENSITY, default=15): cv.int_range(min=0, max=15), -}).extend(cv.polling_component_schema('1s')).extend(spi.SPI_DEVICE_SCHEMA) +}).extend(cv.polling_component_schema('1s')).extend(spi.spi_device_schema()) def to_code(config): diff --git a/esphome/components/pcd8544/display.py b/esphome/components/pcd8544/display.py index e47937e46a..8cc92065ec 100644 --- a/esphome/components/pcd8544/display.py +++ b/esphome/components/pcd8544/display.py @@ -17,7 +17,7 @@ CONFIG_SCHEMA = cv.All(display.FULL_DISPLAY_SCHEMA.extend({ cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema, cv.Required(CONF_RESET_PIN): pins.gpio_output_pin_schema, cv.Required(CONF_CS_PIN): pins.gpio_output_pin_schema, # CE -}).extend(cv.polling_component_schema('1s')).extend(spi.SPI_DEVICE_SCHEMA), +}).extend(cv.polling_component_schema('1s')).extend(spi.spi_device_schema()), cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA)) diff --git a/esphome/components/pn532/__init__.py b/esphome/components/pn532/__init__.py index c82d35b398..931b6ada6b 100644 --- a/esphome/components/pn532/__init__.py +++ b/esphome/components/pn532/__init__.py @@ -17,7 +17,7 @@ CONFIG_SCHEMA = cv.Schema({ cv.Optional(CONF_ON_TAG): automation.validate_automation({ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PN532Trigger), }), -}).extend(cv.polling_component_schema('1s')).extend(spi.SPI_DEVICE_SCHEMA) +}).extend(cv.polling_component_schema('1s')).extend(spi.spi_device_schema()) def to_code(config): diff --git a/esphome/components/pn532/pn532.cpp b/esphome/components/pn532/pn532.cpp index 792d92a6ac..36677bc729 100644 --- a/esphome/components/pn532/pn532.cpp +++ b/esphome/components/pn532/pn532.cpp @@ -31,7 +31,8 @@ void PN532::setup() { // (this may time out, but that's ok) // 3. Send SAM config command with normal mode without waiting for ready bit (IRQ not initialized yet) // 4. Probably optional, send SAM config again, this time checking ACK and return value - this->cs_->digital_write(false); + if (this->cs_) + this->cs_->digital_write(false); delay(10); // send dummy firmware version command to get synced up diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index 69899d1e84..6ced4bc80f 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -34,15 +34,25 @@ def to_code(config): cg.add(var.set_mosi(mosi)) -SPI_DEVICE_SCHEMA = cv.Schema({ - cv.GenerateID(CONF_SPI_ID): cv.use_id(SPIComponent), - cv.Required(CONF_CS_PIN): pins.gpio_output_pin_schema, -}) +def spi_device_schema(CS_PIN_required=False): + """Create a schema for an SPI device. + :param CS_PIN_required: If true, make the CS_PIN required in the config. + :return: The SPI device schema, `extend` this in your config schema. + """ + schema = { + cv.GenerateID(CONF_SPI_ID): cv.use_id(SPIComponent), + } + if CS_PIN_required: + schema[cv.Required(CONF_CS_PIN)] = pins.gpio_output_pin_schema + else: + schema[cv.Optional(CONF_CS_PIN)] = pins.gpio_output_pin_schema + return cv.Schema(schema) @coroutine def register_spi_device(var, config): parent = yield cg.get_variable(config[CONF_SPI_ID]) cg.add(var.set_spi_parent(parent)) - pin = yield cg.gpio_pin_expression(config[CONF_CS_PIN]) - cg.add(var.set_cs_pin(pin)) + if CONF_CS_PIN in config: + pin = yield cg.gpio_pin_expression(config[CONF_CS_PIN]) + cg.add(var.set_cs_pin(pin)) diff --git a/esphome/components/spi/spi.cpp b/esphome/components/spi/spi.cpp index bf2a18955a..ea6f8d68f6 100644 --- a/esphome/components/spi/spi.cpp +++ b/esphome/components/spi/spi.cpp @@ -12,9 +12,11 @@ void ICACHE_RAM_ATTR HOT SPIComponent::disable() { if (this->hw_spi_ != nullptr) { this->hw_spi_->endTransaction(); } - ESP_LOGVV(TAG, "Disabling SPI Chip on pin %u...", this->active_cs_->get_pin()); - this->active_cs_->digital_write(true); - this->active_cs_ = nullptr; + if (this->active_cs_) { + ESP_LOGVV(TAG, "Disabling SPI Chip on pin %u...", this->active_cs_->get_pin()); + this->active_cs_->digital_write(true); + this->active_cs_ = nullptr; + } } void SPIComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up SPI bus..."); diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h index ccef6192f3..ea0595c641 100644 --- a/esphome/components/spi/spi.h +++ b/esphome/components/spi/spi.h @@ -127,19 +127,21 @@ class SPIComponent : public Component { template void enable(GPIOPin *cs) { - SPIComponent::debug_enable(cs->get_pin()); + if (cs) { + SPIComponent::debug_enable(cs->get_pin()); - if (this->hw_spi_ != nullptr) { - uint8_t data_mode = (uint8_t(CLOCK_POLARITY) << 1) | uint8_t(CLOCK_PHASE); - SPISettings settings(DATA_RATE, BIT_ORDER, data_mode); - this->hw_spi_->beginTransaction(settings); - } else { - this->clk_->digital_write(CLOCK_POLARITY); - this->wait_cycle_ = uint32_t(F_CPU) / DATA_RATE / 2ULL; + if (this->hw_spi_ != nullptr) { + uint8_t data_mode = (uint8_t(CLOCK_POLARITY) << 1) | uint8_t(CLOCK_PHASE); + SPISettings settings(DATA_RATE, BIT_ORDER, data_mode); + this->hw_spi_->beginTransaction(settings); + } else { + this->clk_->digital_write(CLOCK_POLARITY); + this->wait_cycle_ = uint32_t(F_CPU) / DATA_RATE / 2ULL; + } + + this->active_cs_ = cs; + this->active_cs_->digital_write(false); } - - this->active_cs_ = cs; - this->active_cs_->digital_write(false); } void disable(); @@ -174,8 +176,10 @@ class SPIDevice { void set_cs_pin(GPIOPin *cs) { cs_ = cs; } void spi_setup() { - this->cs_->setup(); - this->cs_->digital_write(true); + if (this->cs_) { + this->cs_->setup(); + this->cs_->digital_write(true); + } } void enable() { this->parent_->template enable(this->cs_); } diff --git a/esphome/components/ssd1306_spi/display.py b/esphome/components/ssd1306_spi/display.py index 65f0df1c51..19882af6c4 100644 --- a/esphome/components/ssd1306_spi/display.py +++ b/esphome/components/ssd1306_spi/display.py @@ -13,7 +13,7 @@ SPISSD1306 = ssd1306_spi.class_('SPISSD1306', ssd1306_base.SSD1306, spi.SPIDevic CONFIG_SCHEMA = cv.All(ssd1306_base.SSD1306_SCHEMA.extend({ cv.GenerateID(): cv.declare_id(SPISSD1306), cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema, -}).extend(cv.COMPONENT_SCHEMA).extend(spi.SPI_DEVICE_SCHEMA), +}).extend(cv.COMPONENT_SCHEMA).extend(spi.spi_device_schema()), cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA)) diff --git a/esphome/components/ssd1325_spi/display.py b/esphome/components/ssd1325_spi/display.py index 4615d45393..d7c7733afc 100644 --- a/esphome/components/ssd1325_spi/display.py +++ b/esphome/components/ssd1325_spi/display.py @@ -13,7 +13,7 @@ SPISSD1325 = ssd1325_spi.class_('SPISSD1325', ssd1325_base.SSD1325, spi.SPIDevic CONFIG_SCHEMA = cv.All(ssd1325_base.SSD1325_SCHEMA.extend({ cv.GenerateID(): cv.declare_id(SPISSD1325), cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema, -}).extend(cv.COMPONENT_SCHEMA).extend(spi.SPI_DEVICE_SCHEMA), +}).extend(cv.COMPONENT_SCHEMA).extend(spi.spi_device_schema()), cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA)) diff --git a/esphome/components/ssd1325_spi/ssd1325_spi.cpp b/esphome/components/ssd1325_spi/ssd1325_spi.cpp index 399700f1dd..cd5f4a2794 100644 --- a/esphome/components/ssd1325_spi/ssd1325_spi.cpp +++ b/esphome/components/ssd1325_spi/ssd1325_spi.cpp @@ -11,7 +11,8 @@ void SPISSD1325::setup() { ESP_LOGCONFIG(TAG, "Setting up SPI SSD1325..."); this->spi_setup(); this->dc_pin_->setup(); // OUTPUT - this->cs_->setup(); // OUTPUT + if (this->cs_) + this->cs_->setup(); // OUTPUT this->init_reset_(); delay(500); // NOLINT @@ -27,19 +28,24 @@ void SPISSD1325::dump_config() { LOG_UPDATE_INTERVAL(this); } void SPISSD1325::command(uint8_t value) { - this->cs_->digital_write(true); + if (this->cs_) + this->cs_->digital_write(true); this->dc_pin_->digital_write(false); delay(1); this->enable(); - this->cs_->digital_write(false); + if (this->cs_) + this->cs_->digital_write(false); this->write_byte(value); - this->cs_->digital_write(true); + if (this->cs_) + this->cs_->digital_write(true); this->disable(); } void HOT SPISSD1325::write_display_data() { - this->cs_->digital_write(true); + if (this->cs_) + this->cs_->digital_write(true); this->dc_pin_->digital_write(true); - this->cs_->digital_write(false); + if (this->cs_) + this->cs_->digital_write(false); delay(1); this->enable(); for (uint16_t x = 0; x < this->get_width_internal(); x += 2) { @@ -56,7 +62,8 @@ void HOT SPISSD1325::write_display_data() { } } } - this->cs_->digital_write(true); + if (this->cs_) + this->cs_->digital_write(true); this->disable(); } diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index a654e55981..3e6a972742 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -50,7 +50,7 @@ CONFIG_SCHEMA = cv.All(display.FULL_DISPLAY_SCHEMA.extend({ cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_BUSY_PIN): pins.gpio_input_pin_schema, cv.Optional(CONF_FULL_UPDATE_EVERY): cv.uint32_t, -}).extend(cv.polling_component_schema('1s')).extend(spi.SPI_DEVICE_SCHEMA), +}).extend(cv.polling_component_schema('1s')).extend(spi.spi_device_schema()), validate_full_update_every_only_type_a, cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA))