From 3432fa8357476eaee4e9072cba601170889dc624 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Mon, 2 Jun 2025 06:48:15 +0200 Subject: [PATCH] cpu/esp32: add IEEE802.15.4 HAL driver --- cpu/esp32/Makefile | 4 + cpu/esp32/Makefile.dep | 13 + cpu/esp32/Makefile.features | 4 + cpu/esp32/Makefile.include | 15 + cpu/esp32/esp-ieee802154/Makefile | 3 + cpu/esp32/esp-ieee802154/esp_ieee802154_hal.c | 470 ++++++++++++++++++ cpu/esp32/esp-ieee802154/esp_ieee802154_hal.h | 57 +++ cpu/esp32/include/irq_arch.h | 1 + cpu/esp32/include/periph_cpu.h | 9 +- cpu/esp32/include/sdkconfig.h | 12 + cpu/esp32/irq_arch.c | 3 + 11 files changed, 590 insertions(+), 1 deletion(-) create mode 100644 cpu/esp32/esp-ieee802154/Makefile create mode 100644 cpu/esp32/esp-ieee802154/esp_ieee802154_hal.c create mode 100644 cpu/esp32/esp-ieee802154/esp_ieee802154_hal.h diff --git a/cpu/esp32/Makefile b/cpu/esp32/Makefile index ab7e91414e..f703fc3d4d 100644 --- a/cpu/esp32/Makefile +++ b/cpu/esp32/Makefile @@ -28,6 +28,10 @@ ifneq (, $(filter esp_freertos, $(USEMODULE))) DIRS += freertos endif +ifneq (, $(filter esp_ieee802154, $(USEMODULE))) + DIRS += esp-ieee802154 +endif + ifneq (, $(filter esp_lcd, $(USEMODULE))) DIRS += esp-lcd endif diff --git a/cpu/esp32/Makefile.dep b/cpu/esp32/Makefile.dep index ea844cf6ac..fc62880bde 100644 --- a/cpu/esp32/Makefile.dep +++ b/cpu/esp32/Makefile.dep @@ -33,6 +33,19 @@ ifneq (,$(filter esp_ble,$(USEMODULE))) endif endif +ifneq (,$(filter esp_ieee802154,$(USEMODULE))) + FEATURES_REQUIRED += esp_ieee802154 + USEMODULE += esp_idf_ieee802154 + USEMODULE += esp_idf_phy + USEMODULE += iolist + ifneq (,$(filter netdev,$(USEMODULE))) + USEMODULE += netdev_ieee802154_submac + endif + ifeq (esp32h2,$(CPU_FAM)) + USEPKG += esp32_sdk_lib_phy + endif +endif + ifneq (,$(filter esp_eth,$(USEMODULE))) FEATURES_REQUIRED += periph_eth USEMODULE += esp_idf_eth diff --git a/cpu/esp32/Makefile.features b/cpu/esp32/Makefile.features index 5e62d566d5..f21e21a6e7 100644 --- a/cpu/esp32/Makefile.features +++ b/cpu/esp32/Makefile.features @@ -68,6 +68,10 @@ ifneq (,$(filter esp32 esp32s3,$(CPU_FAM))) endif endif +ifeq (esp32h2,$(CPU_FAM)) + FEATURES_PROVIDED += esp_ieee802154 +endif + ifneq (,$(filter esp32-wrover% esp32s2%r2 esp32s3%r2 esp32s3%r8 esp32s3%r8v,$(CPU_MODEL))) FEATURES_PROVIDED += esp_spi_ram ifneq (,$(filter esp32s3%r8 esp32s3%r8v,$(CPU_MODEL))) diff --git a/cpu/esp32/Makefile.include b/cpu/esp32/Makefile.include index 17a159bab0..317bb61f65 100644 --- a/cpu/esp32/Makefile.include +++ b/cpu/esp32/Makefile.include @@ -243,6 +243,12 @@ ifneq (,$(filter esp_eth,$(USEMODULE))) INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_wifi/include endif +ifneq (,$(filter esp_ieee802154,$(USEMODULE))) + INCLUDES += -I$(RIOTCPU)/$(CPU)/esp-ieee802154 + INCLUDES += -I$(ESP32_SDK_DIR)/components/ieee802154/include + INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_coex/include +endif + ifneq (,$(filter periph_sdmmc,$(USEMODULE))) INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_driver_sdmmc/include INCLUDES += -I$(ESP32_SDK_DIR)/components/sdmmc/include @@ -405,6 +411,15 @@ ifneq (,$(filter esp_ble,$(USEMODULE))) endif endif +ifneq (,$(filter esp_ieee802154,$(USEMODULE))) + ifeq (esp32h2,$(CPU_FAM)) + LINKFLAGS += -L$(ESP32_SDK_LIB_PHY_DIR)/$(CPU_FAM) + LINKFLAGS += -L$(ESP32_SDK_LIB_BT_DIR) + ARCHIVES += -lbtbb + ARCHIVES += -lphy + endif +endif + ifneq (,$(filter cpp,$(USEMODULE))) ARCHIVES += -lstdc++ endif diff --git a/cpu/esp32/esp-ieee802154/Makefile b/cpu/esp32/esp-ieee802154/Makefile new file mode 100644 index 0000000000..d135d9d418 --- /dev/null +++ b/cpu/esp32/esp-ieee802154/Makefile @@ -0,0 +1,3 @@ +MODULE = esp_ieee802154 + +include $(RIOTBASE)/Makefile.base diff --git a/cpu/esp32/esp-ieee802154/esp_ieee802154_hal.c b/cpu/esp32/esp-ieee802154/esp_ieee802154_hal.c new file mode 100644 index 0000000000..8754fa62b5 --- /dev/null +++ b/cpu/esp32/esp-ieee802154/esp_ieee802154_hal.c @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2025 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#include "esp_ieee802154.h" + +#include "esp_ieee802154_hal.h" +#include "iolist.h" +#include "log.h" +#include "net/ieee802154/radio.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +/* ACK frame timeout in microseconds, should be a multiple of 16 */ +#define ESP_IEEE802154_ACK_TIMEOUT_US (3456) + +_Static_assert((3456 % 16 == 0), "ACK frame timeout should be a multiple of 16"); + +/* Although the device driver supports IEEE802154_CAP_IRQ_TX_START, + * IEEE802154_CAP_IRQ_RX_START and IEEE802154_CAP_IRQ_CCA_DONE, we are not + * using it for now to avoid unnecessary performance degradation as it is + * not used by any link layer driver */ +#define _USE_RX_START 0 +#define _USE_TX_START 0 +#define _USE_CCA_DONE 0 + +#define _USE_SET_RX 1 +#define _USE_SET_IDLE 1 + +static const ieee802154_radio_ops_t esp_ieee802154_driver; +static ieee802154_dev_t *esp_ieee802154_dev; + +static uint8_t _tx_frame[IEEE802154_FRAME_LEN_MAX + 1]; /* additional byte 0 is used for length */ +static uint8_t *_rx_frame; +static const uint8_t *_ack_frame; + +static esp_ieee802154_frame_info_t *_rx_frame_info; +static esp_ieee802154_frame_info_t *_ack_frame_info; + +static bool _channel_clear; + +static esp_ieee802154_tx_error_t _tx_error; /* error on last transmit */ + +static int _write(ieee802154_dev_t *dev, const iolist_t *psdu) +{ + (void)dev; + + DEBUG("[esp_ieee802154] %s\n", __func__); + + assert(psdu); + + /* copy packet data into the _tx_frame buffer */ + uint8_t *dst = &_tx_frame[1]; /* first byte is frame length */ + + for (; psdu; psdu = psdu->iol_next) { + if (psdu->iol_len) { + assert(((dst - &_tx_frame[1]) + + psdu->iol_len + IEEE802154_FCS_LEN) < ARRAY_SIZE(_tx_frame)); + memcpy(dst, psdu->iol_base, psdu->iol_len); + dst += psdu->iol_len; + } + } + + /* length of the package. */ + _tx_frame[0] = (dst - &_tx_frame[1]) + IEEE802154_FCS_LEN; + + DEBUG("[esp_ieee802154] %s: put %d bytes to _tx_frame\n", __func__, _tx_frame[0]); + + return 0; +} + +static int _len(ieee802154_dev_t *dev) +{ + (void)dev; + DEBUG("[esp_ieee802154] %s\n", __func__); + return _rx_frame[0] - IEEE802154_FCS_LEN; +} + +static int _read(ieee802154_dev_t *dev, void *buf, size_t size, ieee802154_rx_info_t *info) +{ + (void)dev; + + DEBUG("[esp_ieee802154] %s: buf=%p size=%u info=%p\n", + __func__, buf, size, info); + + unsigned len = _rx_frame[0] - IEEE802154_FCS_LEN; + int res = 0; + + if (size < len) { + DEBUG("[esp_ieee802154] %s: buffer to small (%u < %u)\n", + __func__, size, len); + res = -ENOBUFS; + } + else if (buf) { + DEBUG("[esp_ieee802154] %s: read packet of length %d\n", __func__, len); + if (info) { + info->rssi = ieee802154_dbm_to_rssi(_rx_frame[len]); + info->lqi = _rx_frame[len+1]; + } + memcpy(buf, &_rx_frame[1], len); + res = len; + } + + esp_ieee802154_receive_handle_done(_rx_frame); + + return res; +} + +static int _off(ieee802154_dev_t *dev) +{ + (void)dev; + DEBUG("[esp_ieee802154] %s\n", __func__); + esp_ieee802154_disable(); + return 0; +} + +static int _request_on(ieee802154_dev_t *dev) +{ + (void)dev; + DEBUG("[esp_ieee802154] %s\n", __func__); + esp_ieee802154_enable(); + return 0; +} + +static int _confirm_on(ieee802154_dev_t *dev) +{ + (void)dev; + DEBUG("[esp_ieee802154] %s\n", __func__); + return 0; +} + +static int _request_op(ieee802154_dev_t *dev, ieee802154_hal_op_t op, void *ctx) +{ + (void)dev; + (void)ctx; + + switch (op) { + case IEEE802154_HAL_OP_TRANSMIT: + DEBUG("[esp_ieee802154] %s: IEEE802154_HAL_OP_TRANSMIT\n", __func__); + _tx_error = ESP_IEEE802154_TX_ERR_NONE; + _ack_frame = NULL; + _ack_frame_info = NULL; + return esp_ieee802154_transmit(_tx_frame, true) ? -EIO : 0; + case IEEE802154_HAL_OP_SET_RX: + DEBUG("[esp_ieee802154] %s: IEEE802154_HAL_OP_SET_RX\n", __func__); + return (IS_ACTIVE(_USE_SET_RX) && esp_ieee802154_receive()) ? -EIO : 0; + case IEEE802154_HAL_OP_SET_IDLE: + /* TODO: ctx = (bool *force) */ + DEBUG("[esp_ieee802154] %s: IEEE802154_HAL_OP_SET_IDLE\n", __func__); + return (IS_ACTIVE(_USE_SET_IDLE) && esp_ieee802154_sleep()) ? -EIO : 0; + return 0; + case IEEE802154_HAL_OP_CCA: + extern esp_err_t esp_ieee802154_cca(void); + DEBUG("[esp_ieee802154] %s: IEEE802154_HAL_OP_CCA\n", __func__); + return esp_ieee802154_cca(); + } + + return -EINVAL; +} + +static int _confirm_op(ieee802154_dev_t *dev, ieee802154_hal_op_t op, void *ctx) +{ + (void)dev; + + esp_ieee802154_state_t state = esp_ieee802154_get_state(); + + switch (op) { + case IEEE802154_HAL_OP_TRANSMIT: + DEBUG("[esp_ieee802154] %s: IEEE802154_HAL_OP_TRANSMIT\n", __func__); + + if (ctx) { + ieee802154_tx_info_t *info = ctx; + + switch (_tx_error) { + case ESP_IEEE802154_TX_ERR_NONE: + info->status = TX_STATUS_SUCCESS; + if (_ack_frame_info && _ack_frame_info->pending) { + info->status = TX_STATUS_FRAME_PENDING; + } + break; + case ESP_IEEE802154_TX_ERR_CCA_BUSY: + info->status = TX_STATUS_MEDIUM_BUSY; + break; + case ESP_IEEE802154_TX_ERR_NO_ACK: + info->status = TX_STATUS_NO_ACK; + break; + default: + break; + } + } + esp_ieee802154_receive_handle_done(_ack_frame); + return 0; + case IEEE802154_HAL_OP_SET_RX: + DEBUG("[esp_ieee802154] %s: IEEE802154_HAL_OP_SET_RX\n", __func__); + return (!IS_ACTIVE(_USE_SET_RX) || + (state == ESP_IEEE802154_RADIO_RECEIVE)) ? 0 : -EAGAIN; + case IEEE802154_HAL_OP_SET_IDLE: + DEBUG("[esp_ieee802154] %s: IEEE802154_HAL_OP_SET_IDLE\n", __func__); + return (!IS_ACTIVE(_USE_SET_IDLE) || + ((state == ESP_IEEE802154_RADIO_IDLE) || + (state == ESP_IEEE802154_RADIO_SLEEP))) ? 0 : -EAGAIN; + case IEEE802154_HAL_OP_CCA: + DEBUG("[esp_ieee802154] %s: IEEE802154_HAL_OP_CCA\n", __func__); + assert(ctx); + *((bool *)ctx) = _channel_clear; + return 0; + } + + return -EINVAL; +} + +static int _set_cca_threshold(ieee802154_dev_t *dev, int8_t threshold) +{ + (void)dev; + DEBUG("[esp_ieee802154] %s: threshold %i\n", __func__, threshold); + return esp_ieee802154_set_cca_threshold(threshold) ? -EIO : 0; +} + +static int _set_cca_mode(ieee802154_dev_t *dev, ieee802154_cca_mode_t mode) +{ + (void)dev; + + switch (mode) { + case IEEE802154_CCA_MODE_ED_THRESHOLD: + DEBUG("[esp_ieee802154] %s: set IEEE802154_CCA_MODE_ED_THRESHOLD\n", __func__); + return esp_ieee802154_set_cca_mode(ESP_IEEE802154_CCA_MODE_ED) ? -EIO : 0; + case IEEE802154_CCA_MODE_CARRIER_SENSING: + DEBUG("[esp_ieee802154] %s: set IEEE802154_CCA_MODE_CARRIER_SENSING\n", __func__); + return esp_ieee802154_set_cca_mode(ESP_IEEE802154_CCA_MODE_CARRIER) ? -EIO : 0; + case IEEE802154_CCA_MODE_ED_THRESH_AND_CS: + DEBUG("[esp_ieee802154] %s: set IEEE802154_CCA_MODE_ED_THRESH_AND_CS\n", __func__); + return esp_ieee802154_set_cca_mode(ESP_IEEE802154_CCA_MODE_CARRIER_AND_ED) ? -EIO : 0; + case IEEE802154_CCA_MODE_ED_THRESH_OR_CS: + DEBUG("[esp_ieee802154] %s: IEEE802154_CCA_MODE_ED_THRESH_OR_CS\n", __func__); + return esp_ieee802154_set_cca_mode(ESP_IEEE802154_CCA_MODE_CARRIER_OR_ED) ? -EIO : 0; + } + + return -EINVAL; +} + +static int _config_phy(ieee802154_dev_t *dev, const ieee802154_phy_conf_t *conf) +{ + (void)dev; + + assert(conf); + + DEBUG("[esp_ieee802154] %s\n", __func__); + + if (esp_ieee802154_set_txpower(conf->pow) || + esp_ieee802154_set_channel(conf->channel)) { + return -EIO; + } + + return 0; +} + +static int _set_frame_retrans(ieee802154_dev_t *dev, uint8_t retrans) +{ + (void)dev; + DEBUG("[esp_ieee802154] %s\n", __func__); + return -ENOTSUP; +} + +static int _set_csma_params(ieee802154_dev_t *dev, const ieee802154_csma_be_t *bd, + int8_t retries) +{ + (void)dev; + DEBUG("[esp_ieee802154] %s\n", __func__); + return -ENOTSUP; +} + +static int _set_frame_filter_mode(ieee802154_dev_t *dev, ieee802154_filter_mode_t mode) +{ + (void)dev; + DEBUG("[esp_ieee802154] %s\n", __func__); + return -ENOTSUP; +} + +static int _config_addr_filter(ieee802154_dev_t *dev, ieee802154_af_cmd_t cmd, const void *value) +{ + (void)dev; + + assert(value); + + const uint8_t *addr = value; + + switch (cmd) { + case IEEE802154_AF_SHORT_ADDR: + DEBUG("[esp_ieee802154] %s: set IEEE802154_AF_SHORT_ADDR %02x:%02x\n", + __func__, addr[0], addr[1]); + return esp_ieee802154_set_short_address(*((const uint16_t *)value)) ? -EIO : 0; + case IEEE802154_AF_EXT_ADDR: + DEBUG("[esp_ieee802154] %s: set IEEE802154_AF_EXT_ADDR " + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", __func__, + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]); + return esp_ieee802154_set_extended_address(addr) ? -EIO : 0; + case IEEE802154_AF_PANID: + DEBUG("[esp_ieee802154] %s: set IEEE802154_AF_PANID %02x:%02x\n", + __func__, addr[1], addr[0]); + return esp_ieee802154_set_panid(*((const uint16_t *)value)) ? -EIO : 0; + case IEEE802154_AF_PAN_COORD: + DEBUG("[esp_ieee802154] %s: set IEEE802154_AF_PAN_COORD not supported\n", __func__); + return -ENOTSUP; + } + + return -EINVAL; +} + +static int _config_src_addr_match(ieee802154_dev_t *dev, ieee802154_src_match_t cmd, + const void *value) +{ + (void)dev; + + bool enable = *((bool*)value); + + switch (cmd) { + case IEEE802154_SRC_MATCH_EN: + DEBUG("[esp_ieee802154] %s: IEEE802154_SRC_MATCH_EN %d\n", __func__, enable); + return esp_ieee802154_set_pending_mode(enable + ? ESP_IEEE802154_AUTO_PENDING_ENABLE + : ESP_IEEE802154_AUTO_PENDING_DISABLE) ? -EIO : 0; + case IEEE802154_SRC_MATCH_SHORT_ADD: + DEBUG("[esp_ieee802154] %s: set IEEE802154_SRC_MATCH_SHORT_ADD\n", __func__); + return esp_ieee802154_add_pending_addr(value, true) ? -ENOMEM : 0; + case IEEE802154_SRC_MATCH_SHORT_CLEAR: + DEBUG("[esp_ieee802154] %s: set IEEE802154_SRC_MATCH_SHORT_CLEAR\n", __func__); + return esp_ieee802154_clear_pending_addr(value, true) ? -ENOENT : 0; + case IEEE802154_SRC_MATCH_EXT_ADD: + DEBUG("[esp_ieee802154] %s: set IEEE802154_SRC_MATCH_EXT_ADD\n", __func__); + return esp_ieee802154_add_pending_addr(value, false) ? -ENOMEM : 0; + case IEEE802154_SRC_MATCH_EXT_CLEAR: + DEBUG("[esp_ieee802154] %s: set IEEE802154_SRC_MATCH_EXT_CLEAR\n", __func__); + return esp_ieee802154_clear_pending_addr(value, false) ? -ENOENT : 0; + } + + return -EINVAL; +} + +/* following functions are called back from ESP-IDF driver */ + +void esp_ieee802154_cca_done(bool channel_busy) +{ + DEBUG("[esp_ieee802154] %s %d\n", __func__, channel_busy); + _channel_clear = !channel_busy; + + if (IS_ACTIVE(_USE_CCA_DONE)) { + esp_ieee802154_dev->cb(esp_ieee802154_dev, IEEE802154_RADIO_CONFIRM_CCA); + } +} + +void esp_ieee802154_receive_sfd_done(void) +{ + DEBUG("[esp_ieee802154] %s\n", __func__); + if (IS_ACTIVE(_USE_RX_START)) { + esp_ieee802154_dev->cb(esp_ieee802154_dev, IEEE802154_RADIO_INDICATION_RX_START); + } +} + +void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info) +{ + assert(frame); + assert(frame_info); + + DEBUG("[esp_ieee802154] %s: frame=%p frame_info=%p\n", + __func__, frame, frame_info); + + _rx_frame = frame; + _rx_frame_info = frame_info; + + esp_ieee802154_dev->cb(esp_ieee802154_dev, IEEE802154_RADIO_INDICATION_RX_DONE); +} + +void esp_ieee802154_transmit_sfd_done(uint8_t *frame) +{ + DEBUG("[esp_ieee802154] %s: frame=%p\n", __func__, frame); + if (IS_ACTIVE(_USE_TX_START)) { + esp_ieee802154_dev->cb(esp_ieee802154_dev, IEEE802154_RADIO_INDICATION_TX_START); + } +} + +void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, + esp_ieee802154_frame_info_t *ack_frame_info) +{ + DEBUG("[esp_ieee802154] %s: frame=%p ack_frame=%p ack_frame_info=%p\n", + __func__, frame, ack, ack_frame_info); + + _ack_frame = ack; + _ack_frame_info = ack_frame_info; + + esp_ieee802154_dev->cb(esp_ieee802154_dev, IEEE802154_RADIO_CONFIRM_TX_DONE); +} + +void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error) +{ + DEBUG("[esp_ieee802154] %s: frame=%p error=%u\n", __func__, frame, error); + + _tx_error = error; + + esp_ieee802154_dev->cb(esp_ieee802154_dev, IEEE802154_RADIO_CONFIRM_TX_DONE); +} + +void esp_ieee802154_energy_detect_done(int8_t power) +{ + DEBUG("[esp_ieee802154] %s: power %i\n", __func__, power); +} + +void esp_ieee802154_setup(ieee802154_dev_t *dev) +{ + assert(dev); + + DEBUG("[esp_ieee802154] %s: dev=%p\n", __func__, dev); + + dev->driver = &esp_ieee802154_driver; + esp_ieee802154_dev = dev; +} + +int esp_ieee802154_init(void) +{ + DEBUG("[esp_ieee802154] %s\n", __func__); + + esp_ieee802154_enable(); + esp_ieee802154_reset_pending_table(true); + esp_ieee802154_reset_pending_table(false); + esp_ieee802154_set_rx_when_idle(true); + esp_ieee802154_receive(); + esp_ieee802154_set_cca_mode(ESP_IEEE802154_CCA_MODE_ED); + esp_ieee802154_set_ack_timeout(ESP_IEEE802154_ACK_TIMEOUT_US); + esp_ieee802154_set_promiscuous(false); + + return 0; +} + +static const ieee802154_radio_ops_t esp_ieee802154_driver = { + .caps = IEEE802154_CAP_24_GHZ + | IEEE802154_CAP_PHY_OQPSK + | IEEE802154_CAP_AUTO_CSMA + | IEEE802154_CAP_SRC_ADDR_MATCH +#if _USE_CCA_DONE + | IEEE802154_CAP_IRQ_CCA_DONE +#endif +#if _USE_RX_START + | IEEE802154_CAP_IRQ_RX_START +#endif +#if _USE_TX_START + | IEEE802154_CAP_IRQ_TX_START +#endif + | IEEE802154_CAP_IRQ_TX_DONE + | IEEE802154_CAP_IRQ_ACK_TIMEOUT, + .write = _write, + .read = _read, + .request_on = _request_on, + .confirm_on = _confirm_on, + .len = _len, + .off = _off, + .request_op = _request_op, + .confirm_op = _confirm_op, + .set_cca_threshold = _set_cca_threshold, + .set_cca_mode = _set_cca_mode, + .config_phy = _config_phy, + .set_csma_params = _set_csma_params, + .config_addr_filter = _config_addr_filter, + .config_src_addr_match = _config_src_addr_match, + .set_frame_filter_mode = _set_frame_filter_mode, + .set_frame_retrans = _set_frame_retrans, +}; diff --git a/cpu/esp32/esp-ieee802154/esp_ieee802154_hal.h b/cpu/esp32/esp-ieee802154/esp_ieee802154_hal.h new file mode 100644 index 0000000000..23c6d1a9e1 --- /dev/null +++ b/cpu/esp32/esp-ieee802154/esp_ieee802154_hal.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2025 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#pragma once + +/** + * @defgroup cpu_esp32_esp_ieee802154 ESP32x IEEE 802.15.4 driver + * @ingroup drivers_netdev + * @{ + * + * @file + * @brief ESP32x IEEE 802.15.4 driver + * + * @author Gunar Schorcht + */ + +#include + +#include "net/ieee802154/radio.h" + +/** + * @brief Setup ESP32x in order to be used with the IEEE 802.15.4 Radio HAL + * + * @param[in] dev pointer to the HAL descriptor associated to the device. + */ +void esp_ieee802154_setup(ieee802154_dev_t *dev); + +/** + * @brief Initialize the ESP32x IEEE 802.15.4 module. + * + * The function + * - initializes the ESP32x 802.15.4 subsystem, + * - clears the source matching table for short and extended addresses, + * - enables the radio in idle state, + * - sets the CCA mode to energy detection only (IEEE802154_CCA_MODE_ED_THRESHOLD), + * - sets the timeout for the ACK frame, and + * - disables the promicuous mode. + * + * @retval 0 on success + * @retval negative errno on error + */ +int esp_ieee802154_init(void); + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/cpu/esp32/include/irq_arch.h b/cpu/esp32/include/irq_arch.h index 6d3a1c7898..c0caf2e1ab 100644 --- a/cpu/esp32/include/irq_arch.h +++ b/cpu/esp32/include/irq_arch.h @@ -62,6 +62,7 @@ extern "C" { #define CPU_INUM_SDMMC 21 /**< Level interrupt with medium priority 2 */ #define CPU_INUM_TIMER 22 /**< Edge interrupt with medium priority 2 */ #define CPU_INUM_WDT 23 /**< Level interrupt with medium priority 3 */ +#define CPU_INUM_ZMAC 27 /**< Level interrupt with medium priority 3 */ #define CPU_INUM_SOFTWARE 29 /**< Software interrupt with medium priority 3 */ /** @} */ diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index 9efe66560e..2343db1186 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -66,7 +66,14 @@ extern "C" { /** * @brief Length of the CPU_ID in octets */ -#define CPUID_LEN (6U) +#if defined(CPU_FAM_ESP32H2) && defined(CONFIG_IEEE802154_ENABLED) +/* ESP32H2 has IEEE802.15.4 radio which has an EUI64 address. Function + * esp_efuse_mac_get_default will return this 8 byte address if + * CONFIG_IEEE802154_ENABLED */ +# define CPUID_LEN (8U) +#else +# define CPUID_LEN (6U) +#endif /** * @name GPIO configuration diff --git a/cpu/esp32/include/sdkconfig.h b/cpu/esp32/include/sdkconfig.h index 20d3eb96f6..4ada528005 100644 --- a/cpu/esp32/include/sdkconfig.h +++ b/cpu/esp32/include/sdkconfig.h @@ -112,6 +112,18 @@ # define CONFIG_SOC_PM_SUPPORT_BT_WAKEUP SOC_PM_SUPPORT_BT_WAKEUP #endif +/** + * ESP32-H2 IEEE 802.15.4 driver configuration (DO NOT CHANGE) + */ +#if MODULE_ESP_IEEE802154 +# define CONFIG_IEEE802154_ENABLED 1 +# define CONFIG_IEEE802154_CCA_ED 1 +# define CONFIG_IEEE802154_CCA_MODE 1 +# define CONFIG_IEEE802154_CCA_THRESHOLD -60 +# define CONFIG_IEEE802154_PENDING_TABLE_SIZE 20 +# define CONFIG_IEEE802154_RX_BUFFER_SIZE 20 +#endif + /** * SPI RAM configuration (DO NOT CHANGE) */ diff --git a/cpu/esp32/irq_arch.c b/cpu/esp32/irq_arch.c index 06ce7e786d..56d214ff09 100644 --- a/cpu/esp32/irq_arch.c +++ b/cpu/esp32/irq_arch.c @@ -90,6 +90,9 @@ static const struct intr_handle_data_t _irq_data_table[] = { #if defined(SOC_EMAC_SUPPORTED) { ETS_ETH_MAC_INTR_SOURCE, CPU_INUM_ETH, 1 }, #endif +#if SOC_IEEE802154_SUPPORTED + { ETS_ZB_MAC_INTR_SOURCE, CPU_INUM_ZMAC, 3}, +#endif #if defined(SOC_RMT_SUPPORTED) { ETS_RMT_INTR_SOURCE, CPU_INUM_RMT, 1 }, #endif