From f9bce7ef88ccdd7409727f964ebdfabbb4f5ccb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Sun, 29 Dec 2024 23:54:06 +0100 Subject: [PATCH 1/4] drivers: interrupt_controller: esp32c6: mark IRQ 6 as n/a MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UART does not work reliably anymore if assigned to this IRQ. Signed-off-by: Martin Jäger --- drivers/interrupt_controller/intc_esp32c3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/interrupt_controller/intc_esp32c3.c b/drivers/interrupt_controller/intc_esp32c3.c index da889a8f0afb..f0f9a158faf3 100644 --- a/drivers/interrupt_controller/intc_esp32c3.c +++ b/drivers/interrupt_controller/intc_esp32c3.c @@ -61,7 +61,8 @@ static uint8_t esp_intr_irq_alloc[ESP32C6_INTC_AVAILABLE_IRQS][ESP32C6_INTC_SRCS [2] = {IRQ_FREE, IRQ_FREE}, [3] = {IRQ_NA, IRQ_NA}, [4] = {IRQ_NA, IRQ_NA}, - [5 ... 6] = {IRQ_FREE, IRQ_FREE}, + [5] = {IRQ_FREE, IRQ_FREE}, + [6] = {IRQ_NA, IRQ_NA}, [7] = {IRQ_NA, IRQ_NA}, [8 ... 30] = {IRQ_FREE, IRQ_FREE} }; From 1a5930de92c8ca3182eaa0bfe46d5cf4a4c9f68e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Tue, 10 Dec 2024 13:16:31 +0100 Subject: [PATCH 2/4] west.yml: update hal_espressif for IEEE 802.15.4 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PRELIMINARY: Pointing to related PR head. Signed-off-by: Martin Jäger --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 8f2b67d8c885..827cfdf95c6e 100644 --- a/west.yml +++ b/west.yml @@ -162,7 +162,7 @@ manifest: groups: - hal - name: hal_espressif - revision: 51bf6d7bb2ee053e52f09709097e2444777c868c + revision: pull/379/head path: modules/hal/espressif west-commands: west/west-commands.yml groups: From 3a3f0574b663eaa0ad65d770581826b63fb89ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Tue, 10 Dec 2024 15:54:59 +0100 Subject: [PATCH 3/4] drivers: ieee802154: Add implementation for ESP32 series (DRAFT) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Draft implementation of the IEEE 802.15.4 driver using Espressif HAL. Signed-off-by: Martin Jäger --- drivers/ieee802154/CMakeLists.txt | 1 + drivers/ieee802154/Kconfig | 2 + drivers/ieee802154/Kconfig.esp32 | 205 +++++++ drivers/ieee802154/ieee802154_esp32.c | 524 ++++++++++++++++++ drivers/ieee802154/ieee802154_esp32.h | 56 ++ .../espressif,esp32-ieee802154.yaml | 8 + soc/espressif/common/Kconfig | 6 +- 7 files changed, 799 insertions(+), 3 deletions(-) create mode 100644 drivers/ieee802154/Kconfig.esp32 create mode 100644 drivers/ieee802154/ieee802154_esp32.c create mode 100644 drivers/ieee802154/ieee802154_esp32.h create mode 100644 dts/bindings/ieee802154/espressif,esp32-ieee802154.yaml diff --git a/drivers/ieee802154/CMakeLists.txt b/drivers/ieee802154/CMakeLists.txt index 3fdb65790afe..e3cb666d1aee 100644 --- a/drivers/ieee802154/CMakeLists.txt +++ b/drivers/ieee802154/CMakeLists.txt @@ -13,6 +13,7 @@ zephyr_library_sources_ifdef(CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ ) zephyr_library_sources_ifdef(CONFIG_IEEE802154_CC2520 ieee802154_cc2520.c) zephyr_library_sources_ifdef(CONFIG_IEEE802154_DW1000 ieee802154_dw1000.c) +zephyr_library_sources_ifdef(CONFIG_IEEE802154_ESP32 ieee802154_esp32.c) zephyr_library_sources_ifdef(CONFIG_IEEE802154_KW41Z ieee802154_kw41z.c) zephyr_library_sources_ifdef(CONFIG_IEEE802154_MCR20A ieee802154_mcr20a.c) zephyr_library_sources_ifdef(CONFIG_IEEE802154_NRF5 ieee802154_nrf5.c) diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig index 447b32ccbe06..e9b3be6dc406 100644 --- a/drivers/ieee802154/Kconfig +++ b/drivers/ieee802154/Kconfig @@ -86,6 +86,8 @@ source "drivers/ieee802154/Kconfig.rf2xx" source "drivers/ieee802154/Kconfig.dw1000" +source "drivers/ieee802154/Kconfig.esp32" + source "drivers/ieee802154/Kconfig.uart_pipe" config IEEE802154_CSL_ENDPOINT diff --git a/drivers/ieee802154/Kconfig.esp32 b/drivers/ieee802154/Kconfig.esp32 new file mode 100644 index 000000000000..a5cf1fd9bc2a --- /dev/null +++ b/drivers/ieee802154/Kconfig.esp32 @@ -0,0 +1,205 @@ +# Espressif ESP32 802.15.4 configuration options + +# Copyright (c) 2024 A Labs GmbH +# SPDX-License-Identifier: Apache-2.0 + +menuconfig IEEE802154_ESP32 + bool "ESP32 series IEEE 802.15.4 Driver" + default y + depends on DT_HAS_ESPRESSIF_ESP32_IEEE802154_ENABLED + +if IEEE802154_ESP32 + +config IEEE802154_ESP32_INIT_PRIO + int "ESP32 IEEE 802.15.4 initialization priority" + default 80 + help + Set the initialization priority number. Do not mess with it unless + you know what you are doing. + +# Kconfigs copied from Espressif HAL module (ESP-IDF) below + +config IEEE802154_RX_BUFFER_SIZE + int "Number of 802.15.4 receive buffers" + default 20 + range 2 100 + help + The number of 802.15.4 receive buffers. + + This config is used in the Espressif HAL module. + +choice IEEE802154_CCA_MODE + prompt "Clear Channel Assessment (CCA) mode" + default IEEE802154_CCA_ED + help + Configure the CCA mode + + This config is used in the Espressif HAL module. + +config IEEE802154_CCA_CARRIER + bool "Carrier sense only" + help + Configure the CCA mode to Carrier sense only + +config IEEE802154_CCA_ED + bool "Energy above threshold" + help + Configure the CCA mode to Energy above threshold + +config IEEE802154_CCA_CARRIER_OR_ED + bool "Carrier sense OR energy above threshold" + help + Configure the CCA mode to Carrier sense OR energy above threshold + +config IEEE802154_CCA_CARRIER_AND_ED + bool "Carrier sense AND energy above threshold" + help + Configure the CCA mode to Carrier sense AND energy above threshold + +endchoice # IEEE802154_CCA_MODE + +config IEEE802154_CCA_MODE + int + default 0 if IEEE802154_CCA_CARRIER + default 1 if IEEE802154_CCA_ED + default 2 if IEEE802154_CCA_CARRIER_OR_ED + default 3 if IEEE802154_CCA_CARRIER_AND_ED + +config IEEE802154_CCA_THRESHOLD + int "CCA detection threshold" + range -120 0 + default -60 + help + Set the CCA threshold, in dB. + + This config is used in the Espressif HAL module. + +config IEEE802154_PENDING_TABLE_SIZE + int "Pending table size" + range 1 100 + default 20 + help + set the pending table size + +config IEEE802154_MULTI_PAN_ENABLE + bool "Multi-pan feature for frame filter" + help + Enable IEEE802154 multi-pan + + This config is used in the Espressif HAL module. + +config IEEE802154_TIMING_OPTIMIZATION + bool "Throughput optimization" + help + Enabling this option increases throughput by ~5% at the expense of ~2.1k + IRAM code size increase. + + This config is used in the Espressif HAL module. + +config IEEE802154_SLEEP_ENABLE + # Todo: Remove when support safe power-down of the power domain (IDF-7317) + bool "IEEE802154 light sleep" + depends on PM + help + Enabling this option allows the IEEE802.15.4 module to be powered down during automatic + light sleep, which reduces current consumption. + + This is currently untested in Zephyr. Use with caution. + + This config is used in the Espressif HAL module. + +menuconfig IEEE802154_DEBUG + bool "IEEE802154 Debug" + help + Enabling this option allows different kinds of IEEE802154 debug output. + All IEEE802154 debug features increase the size of the final binary. + +config IEEE802154_ASSERT + bool "Enrich the assert information with IEEE802154 state and event" + depends on IEEE802154_DEBUG + default n + help + Enabling this option to add some probe codes in the driver, and this information + will be printed when assert. + + This config is used in the Espressif HAL module. + +config IEEE802154_RECORD_EVENT + bool "Record event information for debugging" + depends on IEEE802154_DEBUG + help + Enabling this option to record event, when assert, the recorded event will be printed. + +config IEEE802154_RECORD_EVENT_SIZE + int "Record event table size" + depends on IEEE802154_RECORD_EVENT + range 1 50 + default 30 + help + Set the record event table size + + This config is used in the Espressif HAL module. + +config IEEE802154_RECORD_STATE + bool "Record state information for debugging" + depends on IEEE802154_DEBUG + help + Enabling this option to record state, when assert, the recorded state will be printed. + + This config is used in the Espressif HAL module. + +config IEEE802154_RECORD_STATE_SIZE + int "Record state table size" + depends on IEEE802154_RECORD_STATE + range 1 50 + default 10 + help + Set the record state table size. + + This config is used in the Espressif HAL module. + +config IEEE802154_RECORD_CMD + bool "Record command information for debugging" + depends on IEEE802154_DEBUG + help + Enable this option to record the command information. + + This config is used in the Espressif HAL module. + +config IEEE802154_RECORD_CMD_SIZE + int "Record command table size" + depends on IEEE802154_RECORD_CMD + range 1 50 + default 10 + help + Set the record command table size. + + This config is used in the Espressif HAL module. + +config IEEE802154_RECORD_ABORT + bool "Record abort information for debugging" + depends on IEEE802154_DEBUG + help + Enable this option to record abort information. + + This config is used in the Espressif HAL module. + +config IEEE802154_RECORD_ABORT_SIZE + int "Record abort table size" + depends on IEEE802154_RECORD_ABORT + range 1 50 + default 10 + help + Set the record abort table size. + + This config is used in the Espressif HAL module. + +config IEEE802154_TXRX_STATISTIC + bool "Record tx/rx packet information for debugging" + depends on IEEE802154_DEBUG + help + Enable this option to record tx and rx packet information. + + This config is used in the Espressif HAL module. + +endif # IEEE802154_ESP32 diff --git a/drivers/ieee802154/ieee802154_esp32.c b/drivers/ieee802154/ieee802154_esp32.c new file mode 100644 index 000000000000..dff3a6ec485e --- /dev/null +++ b/drivers/ieee802154/ieee802154_esp32.c @@ -0,0 +1,524 @@ +/* + * Copyright (c) 2024 A Labs GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT espressif_esp32_ieee802154 + +#define LOG_MODULE_NAME ieee802154_esp32 +#if defined(CONFIG_IEEE802154_DRIVER_LOG_LEVEL) +#define LOG_LEVEL CONFIG_IEEE802154_DRIVER_LOG_LEVEL +#else +#define LOG_LEVEL LOG_LEVEL_NONE +#endif + +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#if defined(CONFIG_NET_L2_OPENTHREAD) +#include +#include +#endif + +#include +#include +#include + +#include +#include + +#include "ieee802154_esp32.h" +#include +#include +#include + +#define IEEE802154_ESP32_TX_TIMEOUT_MS (100) + +static struct ieee802154_esp32_data esp32_data; + +/* override weak function in components/ieee802154/esp_ieee802154.c of ESP-IDF */ +void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info) +{ + struct net_pkt *pkt; + uint8_t *payload; + uint8_t len; + int err; + + /* The ESP-IDF HAL handles FCS already and drops frames with bad checksum. The checksum at + * the end of a valid frame is replaced with RSSI and LQI values. + * + * ToDo: Check if L2 needs a valid checksum in the frame. + */ + if (IS_ENABLED(CONFIG_IEEE802154_L2_PKT_INCL_FCS)) { + len = frame[0]; + } else { + len = frame[0] - IEEE802154_FCS_LENGTH; + } + +#if defined(CONFIG_NET_BUF_DATA_SIZE) + __ASSERT_NO_MSG(len <= CONFIG_NET_BUF_DATA_SIZE); +#endif + + payload = frame + 1; + + LOG_HEXDUMP_DBG(payload, len, "RX buffer:"); + + pkt = net_pkt_rx_alloc_with_buffer(esp32_data.iface, len, AF_UNSPEC, 0, K_NO_WAIT); + if (!pkt) { + LOG_ERR("No pkt available"); + goto exit; + } + + err = net_pkt_write(pkt, payload, len); + if (err != 0) { + LOG_ERR("Failed to write to a packet: %d", err); + net_pkt_unref(pkt); + goto exit; + } + + net_pkt_set_ieee802154_lqi(pkt, frame_info->lqi); + net_pkt_set_ieee802154_rssi_dbm(pkt, frame_info->rssi); + net_pkt_set_ieee802154_ack_fpb(pkt, frame_info->pending); + + err = net_recv_data(esp32_data.iface, pkt); + if (err != 0) { + LOG_ERR("RCV Packet dropped by NET stack: %d", err); + net_pkt_unref(pkt); + } + +exit: + esp_ieee802154_receive_handle_done(frame); +} + +static enum ieee802154_hw_caps esp32_get_capabilities(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* + * ESP32-C6 Datasheet: + * - CSMA/CA + * - active scan and energy detect + * - HW frame filter + * - HW auto acknowledge + * - HW auto frame pending + * - coordinated sampled listening (CSL) + */ + + /* ToDo: Double-check and extend */ + return IEEE802154_HW_ENERGY_SCAN | IEEE802154_HW_FILTER | IEEE802154_HW_TX_RX_ACK | + IEEE802154_HW_CSMA; +} + +/* override weak function in components/ieee802154/esp_ieee802154.c of ESP-IDF */ +void IRAM_ATTR esp_ieee802154_cca_done(bool channel_free) +{ + esp32_data.channel_free = channel_free; + k_sem_give(&esp32_data.cca_wait); +} + +static int esp32_cca(const struct device *dev) +{ + struct ieee802154_esp32_data *data = dev->data; + int err; + + if (ieee802154_cca() != 0) { + LOG_DBG("CCA failed"); + return -EBUSY; + } + + err = k_sem_take(&data->cca_wait, K_MSEC(1000)); + if (err == -EAGAIN) { + LOG_DBG("CCA timed out"); + return -EIO; + } + + LOG_DBG("Channel free? %d", data->channel_free); + + return data->channel_free ? 0 : -EBUSY; +} + +static int esp32_set_channel(const struct device *dev, uint16_t channel) +{ + int err; + + ARG_UNUSED(dev); + + LOG_DBG("Channel: %u", channel); + + if (channel > 26) { + return -EINVAL; + } else if (channel < 11) { + return -ENOTSUP; + } + + err = esp_ieee802154_set_channel(channel); + + return err == 0 ? 0 : -EIO; +} + +static int esp32_filter(const struct device *dev, bool set, enum ieee802154_filter_type type, + const struct ieee802154_filter *filter) +{ + int err; + + LOG_DBG("Applying filter %u", type); + + if (!set) { + return -ENOTSUP; + } + + switch (type) { + case IEEE802154_FILTER_TYPE_IEEE_ADDR: + err = esp_ieee802154_set_extended_address(filter->ieee_addr); + break; + case IEEE802154_FILTER_TYPE_SHORT_ADDR: + err = esp_ieee802154_set_short_address(filter->short_addr); + break; + case IEEE802154_FILTER_TYPE_PAN_ID: + err = esp_ieee802154_set_panid(filter->pan_id); + break; + default: + return -ENOTSUP; + } + + return err == 0 ? 0 : -EIO; +} + +static int esp32_set_txpower(const struct device *dev, int16_t dbm) +{ + int err; + + ARG_UNUSED(dev); + + LOG_DBG("TX power: %u dBm", dbm); + + if (dbm > CONFIG_ESP32_PHY_MAX_TX_POWER) { + return -EINVAL; + } + + err = esp_ieee802154_set_txpower(dbm); + + return err == 0 ? 0 : -EIO; +} + +static int handle_ack(struct ieee802154_esp32_data *data) +{ + uint8_t ack_len; + struct net_pkt *ack_pkt; + int err = 0; + + if (data->ack_frame == NULL || data->ack_frame_info == NULL) { + /* no ACK received, nothing to do */ + return 0; + } + + if (IS_ENABLED(CONFIG_IEEE802154_L2_PKT_INCL_FCS)) { + ack_len = data->ack_frame[0]; + } else { + ack_len = data->ack_frame[0] - IEEE802154_FCS_LENGTH; + } + + ack_pkt = net_pkt_rx_alloc_with_buffer(data->iface, ack_len, AF_UNSPEC, 0, K_NO_WAIT); + if (!ack_pkt) { + LOG_ERR("No free packet available."); + err = -ENOMEM; + goto free_esp_ack; + } + + /* Upper layers expect the frame to start at the MAC header, skip the + * PHY header (PHR byte containing the length). + */ + if (net_pkt_write(ack_pkt, data->ack_frame + 1, ack_len) < 0) { + LOG_ERR("Failed to write to a packet."); + err = -ENOMEM; + goto free_net_ack; + } + + net_pkt_set_ieee802154_lqi(ack_pkt, data->ack_frame_info->lqi); + net_pkt_set_ieee802154_rssi_dbm(ack_pkt, data->ack_frame_info->rssi); + +#if defined(CONFIG_NET_PKT_TIMESTAMP) + net_pkt_set_timestamp_ns(ack_pkt, data->ack_frame_info->time * NSEC_PER_USEC); +#endif + + net_pkt_cursor_init(ack_pkt); + + if (ieee802154_handle_ack(data->iface, ack_pkt) != NET_OK) { + LOG_INF("ACK packet not handled - releasing."); + } + +free_net_ack: + net_pkt_unref(ack_pkt); + +free_esp_ack: + esp_ieee802154_receive_handle_done(data->ack_frame); + data->ack_frame = NULL; + + return err; +} + +/* override weak function in components/ieee802154/esp_ieee802154.c of ESP-IDF */ +void IRAM_ATTR esp_ieee802154_transmit_done(const uint8_t *tx_frame, const uint8_t *ack_frame, + esp_ieee802154_frame_info_t *ack_frame_info) +{ + esp32_data.ack_frame = ack_frame; + esp32_data.ack_frame_info = ack_frame_info; + + k_sem_give(&esp32_data.tx_wait); +} + +/* override weak function in components/ieee802154/esp_ieee802154.c of ESP-IDF */ +void IRAM_ATTR esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error) +{ + k_sem_give(&esp32_data.tx_wait); +} + +static int esp32_tx(const struct device *dev, enum ieee802154_tx_mode tx_mode, struct net_pkt *pkt, + struct net_buf *frag) +{ + struct ieee802154_esp32_data *data = dev->data; + uint8_t payload_len = frag->len; + uint8_t *payload = frag->data; + uint64_t net_time_us; + int err; + + if (payload_len > IEEE802154_MTU) { + LOG_ERR("Payload too large: %d", payload_len); + return -EMSGSIZE; + } + + LOG_HEXDUMP_DBG(payload, payload_len, "TX buffer:"); + + data->tx_psdu[0] = payload_len + IEEE802154_FCS_LENGTH; + memcpy(data->tx_psdu + 1, payload, payload_len); + + k_sem_reset(&data->tx_wait); + + switch (tx_mode) { + case IEEE802154_TX_MODE_DIRECT: + err = esp_ieee802154_transmit(data->tx_psdu, false); + break; + case IEEE802154_TX_MODE_CSMA_CA: + /* + * The second parameter of esp_ieee802154_transmit is called CCA, but actually + * means CSMA/CA (see also ESP-IDF implementation of OpenThread interface). + */ + err = esp_ieee802154_transmit(data->tx_psdu, true); + break; + case IEEE802154_TX_MODE_TXTIME: + case IEEE802154_TX_MODE_TXTIME_CCA: + /** + * The Espressif HAL functions seem to expect a system uptime in us stored as + * uint32_t, which would overflow already after 1.2 hours. In addition to that, the + * network time from PTP, which is returned by net_pkt_timestamp_ns, will most + * probably have a different basis. Anyway, time-based transfers are required for + * some Thread features, so this will have to be fixed in the future. + * + * See also: + * - include/zephyr/net/net_time.h + * - ../modules/hal/espressif/components/ieee802154/driver/esp_ieee802154_dev.c + */ + net_time_us = net_pkt_timestamp_ns(pkt) / NSEC_PER_USEC; + err = esp_ieee802154_transmit_at(data->tx_psdu, + tx_mode == IEEE802154_TX_MODE_TXTIME_CCA, + (uint32_t)net_time_us); + break; + default: + LOG_ERR("TX mode %d not supported", tx_mode); + return -ENOTSUP; + } + + err = k_sem_take(&data->tx_wait, K_MSEC(IEEE802154_ESP32_TX_TIMEOUT_MS)); + + /* set the radio back to RX mode as quickly as possible */ + ieee802154_receive(); + + if (err != 0) { + LOG_ERR("TX timeout"); + } else { + handle_ack(data); + } + + return err == 0 ? 0 : -EIO; +} + +static int esp32_start(const struct device *dev) +{ + struct ieee802154_esp32_data *data = dev->data; + + if (data->is_started) { + return 0; + } else if (esp_ieee802154_enable() == 0) { + esp_ieee802154_set_promiscuous(false); + esp_ieee802154_set_rx_when_idle(true); + + /* ToDo: check if this is necessary */ + esp_ieee802154_receive(); + + data->is_started = true; + return 0; + } + + return -EIO; +} + +static int esp32_stop(const struct device *dev) +{ + struct ieee802154_esp32_data *data = dev->data; + + if (!data->is_started) { + return 0; + } else if (esp_ieee802154_disable() == 0) { + data->is_started = false; + return 0; + } + + return -EIO; +} + +/* override weak function in components/ieee802154/esp_ieee802154.c of ESP-IDF */ +void IRAM_ATTR esp_ieee802154_energy_detect_done(int8_t power) +{ + energy_scan_done_cb_t callback; + const struct device *dev; + + if (esp32_data.energy_scan_done == NULL) { + return; + } + + callback = esp32_data.energy_scan_done; + esp32_data.energy_scan_done = NULL; + dev = net_if_get_device(esp32_data.iface); + callback(dev, power); /* TODO: check scaling */ +} + +static int esp32_ed_scan(const struct device *dev, uint16_t duration, energy_scan_done_cb_t done_cb) +{ + ARG_UNUSED(dev); + + int err = 0; + + if (esp32_data.energy_scan_done == NULL) { + esp32_data.energy_scan_done = done_cb; + + /* The duration of energy detection, in symbol unit (16 us). TODO: check scaling */ + if (esp_ieee802154_energy_detect(duration * USEC_PER_MSEC / US_PER_SYMBLE) != 0) { + esp32_data.energy_scan_done = NULL; + err = -EBUSY; + } + } else { + err = -EALREADY; + } + + return err; +} + +static int esp32_configure(const struct device *dev, enum ieee802154_config_type type, + const struct ieee802154_config *config) +{ + ARG_UNUSED(dev); + ARG_UNUSED(config); + + switch (type) { + /* IEEE802154_CONFIG_ACK_FPB */ + /* IEEE802154_CONFIG_EVENT_HANDLER */ + case IEEE802154_CONFIG_PROMISCUOUS: + esp_ieee802154_set_promiscuous(config->promiscuous); + break; + case IEEE802154_CONFIG_RX_ON_WHEN_IDLE: + esp_ieee802154_set_rx_when_idle(config->rx_on_when_idle); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +/* driver-allocated attribute memory - constant across all driver instances */ +IEEE802154_DEFINE_PHY_SUPPORTED_CHANNELS(drv_attr, 11, 26); + +static int esp32_attr_get(const struct device *dev, enum ieee802154_attr attr, + struct ieee802154_attr_value *value) +{ + ARG_UNUSED(dev); + + return ieee802154_attr_get_channel_page_and_range( + attr, IEEE802154_ATTR_PHY_CHANNEL_PAGE_ZERO_OQPSK_2450_BPSK_868_915, + &drv_attr.phy_supported_channels, value); +} + +static int esp32_init(const struct device *dev) +{ + struct ieee802154_esp32_data *data = dev->data; + + k_sem_init(&data->cca_wait, 0, 1); + k_sem_init(&data->tx_wait, 0, 1); + + LOG_INF("IEEE 802154 radio initialized"); + + return 0; +} + +static void esp32_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct ieee802154_esp32_data *data = dev->data; + + esp_efuse_mac_get_default(data->mac); + net_if_set_link_addr(iface, data->mac, sizeof(data->mac), NET_LINK_IEEE802154); + + data->iface = iface; + + ieee802154_init(iface); +} + +static const struct ieee802154_radio_api esp32_radio_api = { + .iface_api.init = esp32_iface_init, + + .get_capabilities = esp32_get_capabilities, + .cca = esp32_cca, + .set_channel = esp32_set_channel, + .filter = esp32_filter, + .set_txpower = esp32_set_txpower, + .tx = esp32_tx, + .start = esp32_start, + .stop = esp32_stop, + .ed_scan = esp32_ed_scan, + .configure = esp32_configure, + .attr_get = esp32_attr_get, +}; + +#if defined(CONFIG_NET_L2_IEEE802154) +#define L2 IEEE802154_L2 +#define L2_CTX_TYPE NET_L2_GET_CTX_TYPE(IEEE802154_L2) +#define MTU IEEE802154_MTU +#elif defined(CONFIG_NET_L2_OPENTHREAD) +#define L2 OPENTHREAD_L2 +#define L2_CTX_TYPE NET_L2_GET_CTX_TYPE(OPENTHREAD_L2) +#define MTU 1280 +#endif + +#if defined(CONFIG_NET_L2_PHY_IEEE802154) +NET_DEVICE_DT_INST_DEFINE(0, esp32_init, NULL, &esp32_data, NULL, + CONFIG_IEEE802154_ESP32_INIT_PRIO, &esp32_radio_api, L2, + L2_CTX_TYPE, MTU); +#else +DEVICE_DT_INST_DEFINE(0, esp32_init, NULL, &esp32_data, NULL, POST_KERNEL, + CONFIG_IEEE802154_ESP32_INIT_PRIO, &esp32_radio_api); +#endif diff --git a/drivers/ieee802154/ieee802154_esp32.h b/drivers/ieee802154/ieee802154_esp32.h new file mode 100644 index 000000000000..2f4ab896e91a --- /dev/null +++ b/drivers/ieee802154/ieee802154_esp32.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 A Labs GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_IEEE802154_IEEE802154_ESP32_H_ +#define ZEPHYR_DRIVERS_IEEE802154_IEEE802154_ESP32_H_ + +#include + +#include + +struct ieee802154_esp32_data { + /* Pointer to the network interface. */ + struct net_if *iface; + + /* 802.15.4 HW address. */ + uint8_t mac[8]; + + /* CCA complete semaphore. Unlocked when CCA is complete. */ + struct k_sem cca_wait; + + /* CCA result. Holds information whether channel is free or not. */ + bool channel_free; + + bool is_started; + + /* TX synchronization semaphore. Unlocked when frame has been + * sent or send procedure failed. + */ + struct k_sem tx_wait; + + /* TX buffer. First byte is PHR (length), remaining bytes are + * MPDU data. + */ + uint8_t tx_psdu[1 + IEEE802154_MAX_PHY_PACKET_SIZE]; + + /* + * ACK frame (stored until esp_ieee802154_receive_handle_done is called) + * First byte is frame length (PHR), followed by payload (PSDU) + */ + const uint8_t *ack_frame; + + /* A buffer for the received ACK frame. psdu pointer be NULL if no + * ACK was requested/received. + */ + esp_ieee802154_frame_info_t *ack_frame_info; + + /* Callback handler of the currently ongoing energy scan. + * It shall be NULL if energy scan is not in progress. + */ + energy_scan_done_cb_t energy_scan_done; +}; + +#endif /* ZEPHYR_DRIVERS_IEEE802154_IEEE802154_ESP32_H_ */ diff --git a/dts/bindings/ieee802154/espressif,esp32-ieee802154.yaml b/dts/bindings/ieee802154/espressif,esp32-ieee802154.yaml new file mode 100644 index 000000000000..625275743b74 --- /dev/null +++ b/dts/bindings/ieee802154/espressif,esp32-ieee802154.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 A Labs GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: Espressif ESP32 IEEE 802.15.4 node + +compatible: "espressif,esp32-ieee802154" + +include: base.yaml diff --git a/soc/espressif/common/Kconfig b/soc/espressif/common/Kconfig index e33aa2e0f389..ad3f80c5dd0b 100644 --- a/soc/espressif/common/Kconfig +++ b/soc/espressif/common/Kconfig @@ -46,14 +46,14 @@ config ESP32_TIMER_TASK_PRIO Set the task priority for the internal high resolution ESP Timer used in Wi-Fi and BLE peripherals. -if (BT_ESP32 || WIFI_ESP32) +if (BT_ESP32 || WIFI_ESP32 || IEEE802154_ESP32) config ESP32_PHY_MAX_TX_POWER - int "Max Wi-Fi/BLE TX power (dBm)" + int "Max Wi-Fi/BLE/IEEE802154 TX power (dBm)" range 10 20 default 20 help - Set maximum transmit power for Wi-Fi radio. Actual transmit power for high + Set maximum transmit power for the ESP32 radio. Actual transmit power for high data rates may be lower than this setting. endif From 627c41e2ebca08ec8f040c098f85c80375b6f6b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Tue, 10 Dec 2024 15:56:33 +0100 Subject: [PATCH 4/4] boards: espressif: esp32c6: Add ieee802154 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable IEEE 802.15.4 driver for esp32c6_devkitc and xiao_esp32c6 boards. Signed-off-by: Martin Jäger --- boards/espressif/esp32c6_devkitc/esp32c6_devkitc.dts | 5 +++++ boards/espressif/esp32c6_devkitc/esp32c6_devkitc.yaml | 1 + boards/seeed/xiao_esp32c6/xiao_esp32c6.dts | 5 +++++ boards/seeed/xiao_esp32c6/xiao_esp32c6.yaml | 1 + dts/riscv/espressif/esp32c6/esp32c6_common.dtsi | 5 +++++ 5 files changed, 17 insertions(+) diff --git a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc.dts b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc.dts index 896ae30530cc..180d08d121e8 100644 --- a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc.dts +++ b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc.dts @@ -21,6 +21,7 @@ zephyr,shell-uart = &uart0; zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; + zephyr,ieee802154 = &ieee802154; }; aliases { @@ -71,3 +72,7 @@ &wdt0 { status = "okay"; }; + +&ieee802154 { + status = "okay"; +}; diff --git a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc.yaml b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc.yaml index f36685e8367d..a267cf284dd9 100644 --- a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc.yaml +++ b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc.yaml @@ -15,3 +15,4 @@ supported: - counter - entropy - i2c + - netif:openthread diff --git a/boards/seeed/xiao_esp32c6/xiao_esp32c6.dts b/boards/seeed/xiao_esp32c6/xiao_esp32c6.dts index d155f5aa2014..de0820523b5b 100644 --- a/boards/seeed/xiao_esp32c6/xiao_esp32c6.dts +++ b/boards/seeed/xiao_esp32c6/xiao_esp32c6.dts @@ -22,6 +22,7 @@ zephyr,shell-uart = &usb_serial; zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; + zephyr,ieee802154 = &ieee802154; }; leds: leds { @@ -76,3 +77,7 @@ pinctrl-0 = <&uart0_default>; pinctrl-names = "default"; }; + +&ieee802154 { + status = "okay"; +}; diff --git a/boards/seeed/xiao_esp32c6/xiao_esp32c6.yaml b/boards/seeed/xiao_esp32c6/xiao_esp32c6.yaml index 50a8f099a3e5..ef65d5209942 100644 --- a/boards/seeed/xiao_esp32c6/xiao_esp32c6.yaml +++ b/boards/seeed/xiao_esp32c6/xiao_esp32c6.yaml @@ -12,6 +12,7 @@ supported: - spi - entropy - i2c + - netif:openthread testing: ignore_tags: - tracing diff --git a/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi b/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi index d8049584fb17..1150658288a1 100644 --- a/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi +++ b/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi @@ -62,6 +62,11 @@ status = "disabled"; }; + ieee802154: ieee802154 { + compatible = "espressif,esp32-ieee802154"; + status = "disabled"; + }; + soc { #address-cells = <1>; #size-cells = <1>;