1
0
mirror of https://github.com/esphome/esphome.git synced 2025-04-14 06:40:32 +01:00

[spi] Implement octal mode (#8386)

This commit is contained in:
Clyde Stubbs 2025-04-09 09:07:59 +10:00 committed by GitHub
parent 6240bfff97
commit a866370a2e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 88 additions and 56 deletions

View File

@ -113,7 +113,7 @@ BASE_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend(
cs_pin_required=False,
default_mode="MODE0",
default_data_rate=10e6,
quad=True,
mode=spi.TYPE_QUAD,
)
)
)

View File

@ -37,6 +37,7 @@ CODEOWNERS = ["@esphome/core", "@clydebarrow"]
spi_ns = cg.esphome_ns.namespace("spi")
SPIComponent = spi_ns.class_("SPIComponent", cg.Component)
QuadSPIComponent = spi_ns.class_("QuadSPIComponent", cg.Component)
OctalSPIComponent = spi_ns.class_("OctalSPIComponent", cg.Component)
SPIDevice = spi_ns.class_("SPIDevice")
SPIDataRate = spi_ns.enum("SPIDataRate")
SPIMode = spi_ns.enum("SPIMode")
@ -78,6 +79,13 @@ CONF_INTERFACE = "interface"
CONF_INTERFACE_INDEX = "interface_index"
TYPE_SINGLE = "single"
TYPE_QUAD = "quad"
TYPE_OCTAL = "octal"
TYPE_CLASS = {
TYPE_SINGLE: SPIComponent,
TYPE_QUAD: QuadSPIComponent,
TYPE_OCTAL: OctalSPIComponent,
}
# RP2040 SPI pin assignments are complicated;
# refer to GPIO function select table in https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf
@ -230,7 +238,7 @@ def validate_spi_config(config):
):
raise cv.Invalid("Invalid pin selections for hardware SPI interface")
if CONF_DATA_PINS in spi and CONF_INTERFACE_INDEX not in spi:
raise cv.Invalid("Quad mode requires a hardware interface")
raise cv.Invalid("Quad and octal modes requires a hardware interface")
return config
@ -251,7 +259,7 @@ def get_spi_interface(index):
return "new SPIClass(HSPI)"
SPI_SCHEMA = cv.All(
SPI_SINGLE_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(SPIComponent),
@ -266,7 +274,7 @@ SPI_SCHEMA = cv.All(
lower=True,
),
cv.Optional(CONF_DATA_PINS): cv.invalid(
"'data_pins' should be used with 'type: quad' only"
"'data_pins' should be used with 'type: quad or octal' only"
),
}
),
@ -274,38 +282,41 @@ SPI_SCHEMA = cv.All(
cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]),
)
SPI_QUAD_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(QuadSPIComponent),
cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_DATA_PINS): cv.All(
cv.ensure_list(pins.internal_gpio_output_pin_number),
cv.Length(min=4, max=4),
),
cv.Optional(CONF_INTERFACE, default="hardware"): cv.one_of(
*sum(get_hw_interface_list(), ["hardware"]),
lower=True,
),
cv.Optional(CONF_MISO_PIN): cv.invalid(
"'miso_pin' should not be used with quad SPI"
),
cv.Optional(CONF_MOSI_PIN): cv.invalid(
"'mosi_pin' should not be used with quad SPI"
),
}
),
cv.only_on([PLATFORM_ESP32]),
cv.only_with_esp_idf,
)
def spi_mode_schema(mode):
if mode == TYPE_SINGLE:
return SPI_SINGLE_SCHEMA
pin_count = 4 if mode == TYPE_QUAD else 8
return cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(TYPE_CLASS[mode]),
cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_DATA_PINS): cv.All(
cv.ensure_list(pins.internal_gpio_output_pin_number),
cv.Length(min=pin_count, max=pin_count),
),
cv.Optional(CONF_INTERFACE, default="hardware"): cv.one_of(
*sum(get_hw_interface_list(), ["hardware"]),
lower=True,
),
cv.Optional(CONF_MISO_PIN): cv.invalid(
f"'miso_pin' should not be used with {mode} SPI"
),
cv.Optional(CONF_MOSI_PIN): cv.invalid(
f"'mosi_pin' should not be used with {mode} SPI"
),
}
),
cv.only_on([PLATFORM_ESP32]),
cv.only_with_esp_idf,
)
CONFIG_SCHEMA = cv.All(
cv.ensure_list(
cv.typed_schema(
{
TYPE_SINGLE: SPI_SCHEMA,
TYPE_QUAD: SPI_QUAD_SCHEMA,
},
{k: spi_mode_schema(k) for k in TYPE_CLASS},
default_type=TYPE_SINGLE,
)
),
@ -344,19 +355,17 @@ def spi_device_schema(
cs_pin_required=True,
default_data_rate=cv.UNDEFINED,
default_mode=cv.UNDEFINED,
quad=False,
mode=TYPE_SINGLE,
):
"""Create a schema for an SPI device.
:param cs_pin_required: If true, make the CS_PIN required in the config.
:param default_data_rate: Optional data_rate to use as default
:param default_mode Optional. The default SPI mode to use.
:param quad If set, will require an SPI component configured as quad data bits.
:param mode Choose single, quad or octal mode.
:return: The SPI device schema, `extend` this in your config schema.
"""
schema = {
cv.GenerateID(CONF_SPI_ID): cv.use_id(
QuadSPIComponent if quad else SPIComponent
),
cv.GenerateID(CONF_SPI_ID): cv.use_id(TYPE_CLASS[mode]),
cv.Optional(CONF_DATA_RATE, default=default_data_rate): SPI_DATA_RATE_SCHEMA,
cv.Optional(CONF_SPI_MODE, default=default_mode): cv.enum(
SPI_MODE_OPTIONS, upper=True

View File

@ -369,6 +369,7 @@ class SPIComponent : public Component {
};
using QuadSPIComponent = SPIComponent;
using OctalSPIComponent = SPIComponent;
/**
* Base class for SPIDevice, un-templated.
*/

View File

@ -211,11 +211,19 @@ class SPIBusHw : public SPIBus {
buscfg.data1_io_num = data_pins[1];
buscfg.data2_io_num = data_pins[2];
buscfg.data3_io_num = data_pins[3];
buscfg.data4_io_num = -1;
buscfg.data5_io_num = -1;
buscfg.data6_io_num = -1;
buscfg.data7_io_num = -1;
buscfg.flags |= SPICOMMON_BUSFLAG_QUAD;
if (data_pins.size() == 8) {
buscfg.data4_io_num = data_pins[4];
buscfg.data5_io_num = data_pins[5];
buscfg.data6_io_num = data_pins[6];
buscfg.data7_io_num = data_pins[7];
buscfg.flags |= SPICOMMON_BUSFLAG_OCTAL;
} else {
buscfg.data4_io_num = -1;
buscfg.data5_io_num = -1;
buscfg.data6_io_num = -1;
buscfg.data7_io_num = -1;
buscfg.flags |= SPICOMMON_BUSFLAG_QUAD;
}
}
buscfg.max_transfer_sz = MAX_TRANSFER_SIZE;
auto err = spi_bus_initialize(channel, &buscfg, SPI_DMA_CH_AUTO);

View File

@ -1,22 +1,36 @@
spi:
- id: spi_id_1
type: single
clk_pin:
number: GPIO0
ignore_strapping_warning: true
allow_other_uses: false
mosi_pin: GPIO6
interface: hardware
- id: quad_spi
type: quad
interface: spi3
clk_pin: 47
clk_pin:
number: 47
data_pins:
- number: 40
allow_other_uses: false
- 41
- 42
- 43
- allow_other_uses: true
number: 40
- allow_other_uses: true
number: 41
- allow_other_uses: true
number: 42
- allow_other_uses: true
number: 43
- id: octal_spi
type: octal
interface: hardware
clk_pin:
number: 0
data_pins:
- 36
- 37
- 38
- 39
- allow_other_uses: true
number: 40
- allow_other_uses: true
number: 41
- allow_other_uses: true
number: 42
- allow_other_uses: true
number: 43
- id: spi_id_3
interface: any
clk_pin: 8