mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 10:12:52 +00:00
[esp32_can] Support 20 kbit/s on ESP32 revision 2 or later (#20426)
This commit is contained in:
@@ -6,6 +6,8 @@ import esphome.codegen as cg
|
||||
from esphome.components import canbus
|
||||
from esphome.components.canbus import CONF_BIT_RATE, CanbusComponent, CanSpeed
|
||||
from esphome.components.esp32 import (
|
||||
CONF_MINIMUM_CHIP_REVISION,
|
||||
KEY_ESP32,
|
||||
VARIANT_ESP32,
|
||||
VARIANT_ESP32C3,
|
||||
VARIANT_ESP32C5,
|
||||
@@ -20,6 +22,8 @@ from esphome.components.esp32 import (
|
||||
)
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_ADVANCED,
|
||||
CONF_FRAMEWORK,
|
||||
CONF_ID,
|
||||
CONF_MODE,
|
||||
CONF_RX_PIN,
|
||||
@@ -27,6 +31,7 @@ from esphome.const import (
|
||||
CONF_TX_PIN,
|
||||
CONF_TX_QUEUE_LEN,
|
||||
)
|
||||
import esphome.final_validate as fv
|
||||
from esphome.types import ConfigType
|
||||
|
||||
CODEOWNERS = ["@Sympatron"]
|
||||
@@ -49,6 +54,7 @@ CAN_MODES = {
|
||||
# See ESP-IDF Programming Guide --> API Reference --> Two-Wire Automotive Interface (TWAI)
|
||||
|
||||
CAN_SPEEDS_ESP32 = {
|
||||
"20KBPS": CanSpeed.CAN_20KBPS,
|
||||
"25KBPS": CanSpeed.CAN_25KBPS,
|
||||
"50KBPS": CanSpeed.CAN_50KBPS,
|
||||
"100KBPS": CanSpeed.CAN_100KBPS,
|
||||
@@ -114,6 +120,22 @@ CONFIG_SCHEMA = canbus.CANBUS_SCHEMA.extend(
|
||||
)
|
||||
|
||||
|
||||
def _final_validate(config: ConfigType) -> None:
|
||||
if get_esp32_variant() == VARIANT_ESP32 and config[CONF_BIT_RATE] == "20KBPS":
|
||||
esp32_config = fv.full_config.get()[KEY_ESP32]
|
||||
min_revision = esp32_config[CONF_FRAMEWORK][CONF_ADVANCED].get(
|
||||
CONF_MINIMUM_CHIP_REVISION
|
||||
)
|
||||
if min_revision is None or min_revision < "2.0":
|
||||
raise cv.Invalid(
|
||||
"20KBPS on ESP32 requires esp32.framework.advanced.minimum_chip_revision: '2.0' or higher",
|
||||
path=[CONF_BIT_RATE],
|
||||
)
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||
|
||||
|
||||
def get_default_tx_enqueue_timeout(bit_rate: str) -> int:
|
||||
bit_rate_numeric = canbus.get_rate(bit_rate)
|
||||
bits_per_packet = 140 # ~max CAN message length
|
||||
|
||||
@@ -33,6 +33,10 @@ static bool get_bitrate(canbus::CanSpeed bitrate, twai_timing_config_t *t_config
|
||||
case canbus::CAN_16KBPS:
|
||||
*t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_16KBITS();
|
||||
return true;
|
||||
#endif
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32C61) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S3) || (defined(USE_ESP32_VARIANT_ESP32) && CONFIG_ESP32_REV_MIN_FULL >= 200)
|
||||
case canbus::CAN_20KBPS:
|
||||
*t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_20KBITS();
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
esp32:
|
||||
framework:
|
||||
advanced:
|
||||
minimum_chip_revision: "2.0"
|
||||
|
||||
canbus:
|
||||
- platform: esp32_can
|
||||
rx_pin: GPIO14
|
||||
tx_pin: GPIO12
|
||||
can_id: 4
|
||||
bit_rate: 20kbps
|
||||
@@ -0,0 +1,54 @@
|
||||
"""Tests for ESP32 CAN bitrate validation."""
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome.components.esp32 import KEY_ESP32, KEY_VARIANT
|
||||
from esphome.components.esp32_can import canbus
|
||||
import esphome.config_validation as cv
|
||||
from esphome.core import CORE
|
||||
import esphome.final_validate as fv
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("revision", "supported"),
|
||||
[
|
||||
(None, False),
|
||||
("0.0", False),
|
||||
("1.0", False),
|
||||
("1.1", False),
|
||||
("2.0", True),
|
||||
("3.0", True),
|
||||
("3.1", True),
|
||||
],
|
||||
)
|
||||
def test_esp32_20kbps_minimum_revision(revision: str | None, supported: bool) -> None:
|
||||
"""Require the chip revision needed by the ESP-IDF timing macro."""
|
||||
CORE.data[KEY_ESP32] = {KEY_VARIANT: "ESP32"}
|
||||
advanced = {} if revision is None else {"minimum_chip_revision": revision}
|
||||
token = fv.full_config.set({"esp32": {"framework": {"advanced": advanced}}})
|
||||
try:
|
||||
config = {"bit_rate": canbus.validate_bit_rate("20kbps")}
|
||||
if supported:
|
||||
canbus.FINAL_VALIDATE_SCHEMA(config)
|
||||
else:
|
||||
with pytest.raises(cv.Invalid, match="minimum_chip_revision") as error:
|
||||
canbus.FINAL_VALIDATE_SCHEMA(config)
|
||||
assert error.value.path == ["bit_rate"]
|
||||
finally:
|
||||
fv.full_config.reset(token)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("variant", ["ESP32", "ESP32C3", "ESP32S3"])
|
||||
def test_other_bitrates(variant: str) -> None:
|
||||
"""Existing bitrates must not require a minimum chip revision."""
|
||||
CORE.data[KEY_ESP32] = {KEY_VARIANT: variant}
|
||||
config = {"bit_rate": canbus.validate_bit_rate("25kbps")}
|
||||
canbus.FINAL_VALIDATE_SCHEMA(config)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("variant", ["ESP32C3", "ESP32S2", "ESP32S3", "ESP32C6"])
|
||||
def test_other_variants_20kbps(variant: str) -> None:
|
||||
"""Other supported ESP32 variants must retain 20 kbit/s support."""
|
||||
CORE.data[KEY_ESP32] = {KEY_VARIANT: variant}
|
||||
config = {"bit_rate": canbus.validate_bit_rate("20kbps")}
|
||||
canbus.FINAL_VALIDATE_SCHEMA(config)
|
||||
Reference in New Issue
Block a user