From 18b8d202bdd4f4f581cab881dd80674ea3dee8e2 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 15:21:34 +0100 Subject: [PATCH 01/46] cpu/esp32: variant independent bootloader makefile Bootloader makefile that can be used for different ESP32x variants --- cpu/esp32/bootloader/Makefile | 75 +++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 22 deletions(-) diff --git a/cpu/esp32/bootloader/Makefile b/cpu/esp32/bootloader/Makefile index 2203ebaee2b4..d3d55e90a952 100644 --- a/cpu/esp32/bootloader/Makefile +++ b/cpu/esp32/bootloader/Makefile @@ -57,7 +57,6 @@ ESP_SDK_BOOTLOADER_SRCS = \ components/esp_hw_support/port/$(CPU)/rtc_pm.c \ components/esp_hw_support/port/$(CPU)/rtc_sleep.c \ components/esp_hw_support/port/$(CPU)/rtc_time.c \ - components/esp_hw_support/port/$(CPU)/rtc_wdt.c \ components/esp_rom/patches/esp_rom_crc.c \ components/esp_rom/patches/esp_rom_sys.c \ components/esp_rom/patches/esp_rom_tjpgd.c \ @@ -71,38 +70,56 @@ ESP_SDK_BOOTLOADER_SRCS = \ components/log/log_noos.c \ components/newlib/syscalls.c \ components/soc/$(CPU)/adc_periph.c \ - components/soc/$(CPU)/dac_periph.c \ components/soc/$(CPU)/gpio_periph.c \ components/soc/$(CPU)/i2c_periph.c \ components/soc/$(CPU)/i2s_periph.c \ components/soc/$(CPU)/interrupts.c \ - components/soc/$(CPU)/lcd_periph.c \ components/soc/$(CPU)/ledc_periph.c \ - components/soc/$(CPU)/mcpwm_periph.c \ - components/soc/$(CPU)/pcnt_periph.c \ components/soc/$(CPU)/rmt_periph.c \ - components/soc/$(CPU)/rtc_io_periph.c \ - components/soc/$(CPU)/sdio_slave_periph.c \ - components/soc/$(CPU)/sdmmc_periph.c \ components/soc/$(CPU)/sigmadelta_periph.c \ components/soc/$(CPU)/spi_periph.c \ components/soc/$(CPU)/timer_periph.c \ - components/soc/$(CPU)/touch_sensor_periph.c \ components/soc/$(CPU)/uart_periph.c \ components/soc/lldesc.c \ components/spi_flash/$(CPU)/spi_flash_rom_patch.c \ - components/xtensa/eri.c \ - components/xtensa/xt_trax.c \ + # + +ifneq (,$(filter xtensa%,$(TARGET_ARCH))) + ESP_SDK_BOOTLOADER_SRCS += components/esp_hw_support/port/$(CPU)/rtc_wdt.c + ESP_SDK_BOOTLOADER_SRCS += components/soc/$(CPU)/lcd_periph.c + ESP_SDK_BOOTLOADER_SRCS += components/soc/$(CPU)/pcnt_periph.c + ESP_SDK_BOOTLOADER_SRCS += components/soc/$(CPU)/rtc_io_periph.c + ESP_SDK_BOOTLOADER_SRCS += components/soc/$(CPU)/touch_sensor_periph.c + ESP_SDK_BOOTLOADER_SRCS += components/xtensa/eri.c + ESP_SDK_BOOTLOADER_SRCS += components/xtensa/xt_trax.c +else + ESP_SDK_BOOTLOADER_SRCS += components/esp_hw_support/port/$(CPU)/cpu_util_$(CPU).c +endif + +ifneq (,$(filter esp32 esp32s2,$(CPU))) + ESP_SDK_BOOTLOADER_SRCS += components/soc/$(CPU)/dac_periph.c +endif + +ifneq (,$(filter esp32 esp32s3,$(CPU))) + ESP_SDK_BOOTLOADER_SRCS += components/soc/$(CPU)/mcpwm_periph.c + ESP_SDK_BOOTLOADER_SRCS += components/soc/$(CPU)/sdio_slave_periph.c + ESP_SDK_BOOTLOADER_SRCS += components/soc/$(CPU)/sdmmc_periph.c +endif + +ifneq (,$(filter esp32c3 esp32h2 esp32s3,$(CPU))) + ESP_SDK_BOOTLOADER_SRCS += components/efuse/$(CPU)/esp_efuse_rtc_calib.c +endif ifneq (,$(filter esp32,$(CPU))) ESP_SDK_BOOTLOADER_SRCS += components/efuse/src/esp_efuse_api_key_esp32.c + ESP_SDK_BOOTLOADER_ASMSRC = components/esp_rom/patches/esp_rom_longjmp.S else ESP_SDK_BOOTLOADER_SRCS += components/efuse/src/esp_efuse_api_key_esp32xx.c + ESP_SDK_BOOTLOADER_SRCS += components/soc/$(CPU)/dedic_gpio_periph.c + ESP_SDK_BOOTLOADER_SRCS += components/soc/$(CPU)/gdma_periph.c + ESP_SDK_BOOTLOADER_SRCS += components/soc/soc_include_legacy_warn.c endif -ESP_SDK_BOOTLOADER_ASMSRC = \ - components/esp_rom/patches/esp_rom_longjmp.S \ - # Bootloader sdkconfig.h defined in CURDIR directory. INCLUDES = \ -I$(dir $(RIOTBUILD_CONFIG_HEADER_C)) \ @@ -136,14 +153,27 @@ INCLUDES = \ -I$(ESP32_SDK_DIR)/components/soc/include \ -I$(ESP32_SDK_DIR)/components/spi_flash/include \ -I$(ESP32_SDK_DIR)/components/spi_flash/include/spi_flash \ - -I$(ESP32_SDK_DIR)/components/xtensa/$(CPU)/include \ - -I$(ESP32_SDK_DIR)/components/xtensa/include \ # +CFLAGS = -include '$(RIOTBUILD_CONFIG_HEADER_C)' \ + +ifneq (,$(filter riscv32%,$(TARGET_ARCH))) + INCLUDES += -I$(ESP32_SDK_DIR)/components/riscv/include + CFLAGS += -DCONFIG_IDF_TARGET_ARCH_RISCV + CFLAGS += -march=rv32imc + CFLAGS += -Wno-error=format= + CFLAGS += -nostartfiles + CFLAGS += -Wno-format +endif + +ifneq (,$(filter xtensa%,$(TARGET_ARCH))) + INCLUDES += -I$(ESP32_SDK_DIR)/components/xtensa/include + INCLUDES += -I$(ESP32_SDK_DIR)/components/xtensa/$(CPU)/include + CFLAGS += -mlongcalls -mtext-section-literals +endif + # BOOTLOADER_BUILD=1 signals to the SDK that's a bootloader build. -CFLAGS = \ - -include '$(RIOTBUILD_CONFIG_HEADER_C)' \ - -mlongcalls \ +CFLAGS += \ -Wno-frame-address \ -ffunction-sections \ -fdata-sections \ @@ -176,11 +206,13 @@ CFLAGS = \ -MT \ # -ifneq (,$(filter esp32 esp32s2 esp32s3,$(CPU))) +ifneq (,$(filter xtensa%,$(TARGET_ARCH))) + LINKFLAGS = -mlongcalls ESP_SDK_BOOTLOADER_ADD_LINK_FLAGS += -L$(ESP32_SDK_DIR)/components/xtensa/$(CPU) -lxt_hal endif ifneq (,$(filter esp32 esp32s2,$(CPU))) + LINKFLAGS = ESP_SDK_BOOTLOADER_ADD_LINK_FLAGS += \ -T$(ESP32_SDK_DIR)/components/esp_rom/$(CPU)/ld/$(CPU).rom.newlib-funcs.ld \ -T$(ESP32_SDK_DIR)/components/esp_rom/$(CPU)/ld/$(CPU).rom.spiflash.ld \ @@ -190,8 +222,7 @@ endif # Bootloader link flags. We use the SDK source and linking files instead of the # RIOT-OS ones to link the bootloader. Note that we also use the unmodified # SDK libraries. -LINKFLAGS = \ - -mlongcalls \ +LINKFLAGS += \ -Wno-frame-address \ -o $(ESP_SDK_BOOTLOADER_DIR)/bootloader.elf \ -Wl,--cref \ From 2d3e8bfe5540343c4cab51c1b18a927dcb2dee8d Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 16:22:28 +0100 Subject: [PATCH 02/46] cpu/esp_common: add FreeRTOS functionality required by ESP-IDF 4.4 --- cpu/esp32/Makefile.dep | 1 - cpu/esp_common/Kconfig | 1 + cpu/esp_common/Makefile.dep | 4 + cpu/esp_common/Makefile.include | 7 + cpu/esp_common/freertos/queue.c | 140 +++++++++++- cpu/esp_common/freertos/ringbuf.c | 104 +++++++++ cpu/esp_common/freertos/semphr.c | 102 ++++++--- cpu/esp_common/freertos/task.c | 232 +++++++++++++++++--- cpu/esp_common/freertos/timers.c | 11 +- cpu/esp_common/include/freertos/FreeRTOS.h | 9 +- cpu/esp_common/include/freertos/portmacro.h | 7 +- cpu/esp_common/include/freertos/queue.h | 7 +- cpu/esp_common/include/freertos/ringbuf.h | 27 +++ cpu/esp_common/include/freertos/semphr.h | 3 + cpu/esp_common/include/freertos/task.h | 29 +++ 15 files changed, 593 insertions(+), 91 deletions(-) create mode 100644 cpu/esp_common/freertos/ringbuf.c diff --git a/cpu/esp32/Makefile.dep b/cpu/esp32/Makefile.dep index bb96004bc392..2c28193b938c 100644 --- a/cpu/esp32/Makefile.dep +++ b/cpu/esp32/Makefile.dep @@ -70,7 +70,6 @@ endif ifneq (,$(filter periph_i2c,$(USEMODULE))) ifneq (,$(filter esp_i2c_hw,$(USEMODULE))) - USEMODULE += core_thread_flags USEMODULE += ztimer_msec USEMODULE += periph_i2c_hw else diff --git a/cpu/esp_common/Kconfig b/cpu/esp_common/Kconfig index c6668b1f6cd6..f2093d3c988e 100644 --- a/cpu/esp_common/Kconfig +++ b/cpu/esp_common/Kconfig @@ -81,6 +81,7 @@ config MODULE_ESP_COMMON select MODULE_LOG # override default log implementation by default select MODULE_PERIPH select MODULE_ESP_IDF + select MODULE_CORE_THREAD_FLAGS if MODULE_ZTIMER_MSEC help Common code module for ESP SoCs. diff --git a/cpu/esp_common/Makefile.dep b/cpu/esp_common/Makefile.dep index 021d0ebda978..240c01e6211f 100644 --- a/cpu/esp_common/Makefile.dep +++ b/cpu/esp_common/Makefile.dep @@ -93,3 +93,7 @@ ifneq (,$(filter esp_wifi_any,$(USEMODULE))) USEMODULE += netopt USEMODULE += ztimer_msec endif + +ifneq (,$(filter ztimer_msec,$(USEMODULE))) + USEMODULE += core_thread_flags +endif diff --git a/cpu/esp_common/Makefile.include b/cpu/esp_common/Makefile.include index 9f7f45257e6a..33c466081e12 100644 --- a/cpu/esp_common/Makefile.include +++ b/cpu/esp_common/Makefile.include @@ -53,6 +53,13 @@ ifneq (,$(filter esp_qemu,$(USEMODULE))) CFLAGS += -DQEMU endif +ifneq (,$(filter esp_freertos_common,$(USEMODULE))) + # thread_t.name required by FreeRTOS adaptation layer and esp_gdbstub + CFLAGS += -DCONFIG_THREAD_NAMES + # thread_t.stack_start required by FreeRTOS adaptation layer + CFLAGS += -DSCHED_TEST_STACK +endif + # use 32 priority levels if any WiFi interface or the ETH interface is used ifneq (,$(filter esp_wifi_any esp_eth,$(USEMODULE))) CFLAGS += -DSCHED_PRIO_LEVELS=32 diff --git a/cpu/esp_common/freertos/queue.c b/cpu/esp_common/freertos/queue.c index 0f59db2d6aa4..59342b9c2566 100644 --- a/cpu/esp_common/freertos/queue.c +++ b/cpu/esp_common/freertos/queue.c @@ -24,6 +24,9 @@ #include "rmutex.h" #include "syscalls.h" #include "thread.h" +#if IS_USED(MODULE_ZTIMER_MSEC) +#include "ztimer.h" +#endif #include "rom/ets_sys.h" @@ -55,7 +58,7 @@ QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) { - DEBUG("%s pid=%d len=%u size=%u type=%u ", __func__, + DEBUG("%s pid=%d len=%u size=%u type=%u\n", __func__, thread_getpid(), uxQueueLength, uxItemSize, ucQueueType); uint32_t queue_size = uxQueueLength * uxItemSize; @@ -110,13 +113,91 @@ void vQueueDelete( QueueHandle_t xQueue ) free(xQueue); } +BaseType_t IRAM_ATTR xQueueReset( QueueHandle_t xQueue ) +{ + DEBUG("%s pid=%d queue=%p\n", __func__, thread_getpid(), xQueue); + + assert(xQueue != NULL); + + vTaskEnterCritical(0); + + _queue_t* queue = (_queue_t*)xQueue; + queue->item_front = 0; + queue->item_tail = 0; + queue->item_level = 0; + + /* return if there is no waiting sending thread */ + if (queue->sending.next == NULL) { + DEBUG("%s pid=%d queue=%p return pdPASS\n", __func__, + thread_getpid(), xQueue); + vTaskExitCritical(0); + return pdPASS; + } + + /* otherwise unlock the waiting sending thread */ + list_node_t *next = list_remove_head(&queue->sending); + thread_t *proc = container_of((clist_node_t*)next, thread_t, rq_entry); + sched_set_status(proc, STATUS_PENDING); + + /* test whether context switch is required */ + bool ctx_switch = proc->priority < sched_threads[thread_getpid()]->priority; + + DEBUG("%s pid=%d queue=%p unlock waiting pid=%d switch=%d\n", + __func__, thread_getpid(), xQueue, proc->pid, ctx_switch); + + if (ctx_switch) { + vTaskExitCritical(0); + /* sets only the sched_context_switch_request in ISRs */ + sched_switch(proc->priority); + } + else { + vTaskExitCritical(0); + } + + return pdPASS; +} + +#if IS_USED(MODULE_ZTIMER_MSEC) + +/* descriptor for timeout handling for a thread that is waiting in a queue */ +typedef struct { + thread_t *thread; /* the thread */ + list_node_t *queue; /* the queue in which it is waiting */ + bool timeout; /* timeout occurred */ +} _queue_waiting_thread_t; + +static void _queue_timeout(void *arg) +{ + _queue_waiting_thread_t *wtd = arg; + + assert(wtd != NULL); + assert(wtd->queue != NULL); + assert(wtd->thread != NULL); + + vTaskEnterCritical(0); + + /* remove the thread from the waiting queue */ + list_node_t *node = (list_node_t *)&(wtd->thread->rq_entry); + list_remove(wtd->queue, node); + + /* unblock the waintg thread */ + sched_set_status(wtd->thread, STATUS_PENDING); + sched_context_switch_request = + wtd->thread->priority < sched_threads[thread_getpid()]->priority; + + wtd->timeout = true; + + vTaskExitCritical(0); +} +#endif + BaseType_t IRAM_ATTR _queue_generic_send(QueueHandle_t xQueue, const void * const pvItemToQueue, const BaseType_t xCopyPosition, TickType_t xTicksToWait, BaseType_t * const pxHigherPriorityTaskWoken) { - DEBUG("%s pid=%d prio=%d queue=%p pos=%d wait=%u woken=%p isr=%d\n", __func__, + DEBUG("%s pid=%d prio=%d queue=%p pos=%d wait=%"PRIu32" woken=%p isr=%d\n", __func__, thread_getpid(), sched_threads[thread_getpid()]->priority, xQueue, xCopyPosition, xTicksToWait, pxHigherPriorityTaskWoken, irq_is_in()); @@ -204,10 +285,33 @@ BaseType_t IRAM_ATTR _queue_generic_send(QueueHandle_t xQueue, DEBUG("%s pid=%d queue=%p suspended calling thread\n", __func__, thread_getpid(), xQueue); + +#if IS_USED(MODULE_ZTIMER_MSEC) + _queue_waiting_thread_t wdt = { .queue = &queue->sending, + .thread = me, + .timeout = false }; + ztimer_t tm = { .callback = _queue_timeout, + .arg = &wdt }; + if (xTicksToWait < portMAX_DELAY) { + ztimer_set(ZTIMER_MSEC, &tm, xTicksToWait * portTICK_PERIOD_MS); + } +#else + assert((xTicksToWait == 0) || (xTicksToWait == portMAX_DELAY)); +#endif vTaskExitCritical(0); thread_yield_higher(); - /* TODO timeout handling with xTicksToWait */ +#if IS_USED(MODULE_ZTIMER_MSEC) + vTaskEnterCritical(0); + if (xTicksToWait < portMAX_DELAY) { + ztimer_remove(ZTIMER_MSEC, &tm); + if (wdt.timeout) { + vTaskExitCritical(0); + return errQUEUE_FULL; + } + } + vTaskExitCritical(0); +#endif DEBUG("%s pid=%d queue=%p continue calling thread\n", __func__, thread_getpid(), xQueue); } @@ -222,7 +326,7 @@ BaseType_t IRAM_ATTR _queue_generic_recv (QueueHandle_t xQueue, const BaseType_t xJustPeeking, BaseType_t * const pxHigherPriorityTaskWoken) { - DEBUG("%s pid=%d prio=%d queue=%p wait=%u peek=%u woken=%p isr=%d\n", __func__, + DEBUG("%s pid=%d prio=%d queue=%p wait=%"PRIu32" peek=%u woken=%p isr=%d\n", __func__, thread_getpid(), sched_threads[thread_getpid()]->priority, xQueue, xTicksToWait, xJustPeeking, pxHigherPriorityTaskWoken, irq_is_in()); @@ -310,10 +414,32 @@ BaseType_t IRAM_ATTR _queue_generic_recv (QueueHandle_t xQueue, DEBUG("%s pid=%d queue=%p suspended calling thread\n", __func__, thread_getpid(), xQueue); +#if IS_USED(MODULE_ZTIMER_MSEC) + _queue_waiting_thread_t wdt = { .queue = &queue->receiving, + .thread = me, + .timeout = false }; + ztimer_t tm = { .callback = _queue_timeout, + .arg = &wdt }; + if (xTicksToWait < portMAX_DELAY) { + ztimer_set(ZTIMER_MSEC, &tm, xTicksToWait * portTICK_PERIOD_MS); + } +#else + assert((xTicksToWait == 0) || (xTicksToWait == portMAX_DELAY)); +#endif vTaskExitCritical(0); thread_yield_higher(); - /* TODO timeout handling with xTicksToWait */ +#if IS_USED(MODULE_ZTIMER_MSEC) + vTaskEnterCritical(0); + if (xTicksToWait < portMAX_DELAY) { + ztimer_remove(ZTIMER_MSEC, &tm); + if (wdt.timeout) { + vTaskExitCritical(0); + return errQUEUE_FULL; + } + } + vTaskExitCritical(0); +#endif DEBUG("%s pid=%d queue=%p continue calling thread\n", __func__, thread_getpid(), xQueue); } @@ -326,7 +452,7 @@ BaseType_t IRAM_ATTR xQueueGenericSend( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ) { - DEBUG("%s pid=%d prio=%d queue=%p wait=%u pos=%d\n", __func__, + DEBUG("%s pid=%d prio=%d queue=%p wait=%"PRIu32" pos=%d\n", __func__, thread_getpid(), sched_threads[thread_getpid()]->priority, xQueue, xTicksToWait, xCopyPosition); @@ -352,7 +478,7 @@ BaseType_t IRAM_ATTR xQueueGenericReceive (QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xJustPeeking) { - DEBUG("%s pid=%d prio=%d queue=%p wait=%u peek=%d\n", __func__, + DEBUG("%s pid=%d prio=%d queue=%p wait=%"PRIu32" peek=%d\n", __func__, thread_getpid(), sched_threads[thread_getpid()]->priority, xQueue, xTicksToWait, xJustPeeking); diff --git a/cpu/esp_common/freertos/ringbuf.c b/cpu/esp_common/freertos/ringbuf.c new file mode 100644 index 000000000000..8d68cc6ff591 --- /dev/null +++ b/cpu/esp_common/freertos/ringbuf.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2022 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. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#include +#include + +#include "irq_arch.h" +#include "ringbuffer.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/ringbuf.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +typedef struct { + ringbuffer_t rbuf; + uint16_t item_size; + char *buf; +} rbuf_handle_t; + +RingbufHandle_t xRingbufferCreate(size_t xBufferSize, RingbufferType_t xBufferType) +{ + /* only byte buffer supported for now */ + assert(xBufferType == RINGBUF_TYPE_BYTEBUF); + + /* allocate the space for rbuf_handle_t including the buffer */ + rbuf_handle_t *handle = malloc(xBufferSize + sizeof(uint16_t) + sizeof(ringbuffer_t)); + if (handle == NULL) { + return NULL; + } + handle->item_size = 0; + ringbuffer_init((ringbuffer_t *)handle, handle->buf, xBufferSize); + + return handle; +} + +void vRingbufferDelete(RingbufHandle_t xRingbuffer) +{ + assert(xRingbuffer != NULL); + free(xRingbuffer); +} + +void *xRingbufferReceiveUpToFromISR(RingbufHandle_t xRingbuffer, + size_t *pxItemSize, size_t xMaxSize) +{ + rbuf_handle_t *handle = xRingbuffer; + size_t data_len = 0; + + assert(handle != NULL); + + /* determine the number of bytes to be read */ + if (handle->rbuf.avail) { + data_len = ((xMaxSize == 0) || (handle->rbuf.avail < xMaxSize)) ? handle->rbuf.avail + : xMaxSize; + } + /* ESP-IDF ring buffers require two read operation if the data wrap around */ + if (data_len > (handle->rbuf.size - handle->rbuf.start)) { + data_len = handle->rbuf.size - handle->rbuf.start; + } + handle->item_size = data_len; + *pxItemSize = data_len; + + return handle->rbuf.buf + handle->rbuf.start; +} + +void *xRingbufferReceiveFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize) +{ + return xRingbufferReceiveUpToFromISR(xRingbuffer, pxItemSize, 0); +} + +void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, + BaseType_t *pxHigherPriorityTaskWoken) +{ + rbuf_handle_t *handle = xRingbuffer; + if (handle->item_size) { + ringbuffer_remove(&handle->rbuf, handle->item_size); + } +} + +BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, + const void *pvItem, + size_t xItemSize, + BaseType_t *pxHigherPriorityTaskWoken) +{ + rbuf_handle_t *handle = xRingbuffer; + + assert(handle != NULL); + + /* return immediately if there is not enough space in the ring buffer */ + if (ringbuffer_get_free(&handle->rbuf) < xItemSize) { + return pdFALSE; + } + + /* add data to the ringbuffer */ + return ringbuffer_add(&handle->rbuf, pvItem, xItemSize) == xItemSize; +} diff --git a/cpu/esp_common/freertos/semphr.c b/cpu/esp_common/freertos/semphr.c index 5beb02410fe1..32a8fbd9c9ea 100644 --- a/cpu/esp_common/freertos/semphr.c +++ b/cpu/esp_common/freertos/semphr.c @@ -32,26 +32,29 @@ * objects. */ typedef struct { - uint8_t type; /* type of the mutex, MUST be the first element */ - mutex_t mutex; /* the mutex */ -} _mutex_t; + uint8_t type; /* type of the mutex, MUST be the first element */ + kernel_pid_t pid; /* PID of the holder if the mutex is locked */ + mutex_t mutex; /* the RIOT mutex */ +} _sem_t; typedef struct { - uint8_t type; /* type of the mutex, MUST be the first element */ - rmutex_t rmutex; /* the mutex */ -} _rmutex_t; + uint8_t type; /* type of the mutex, MUST be the first element */ + kernel_pid_t pid; /* PID of the holder if the mutex is locked */ + rmutex_t rmutex; /* the RIOT mutex */ +} _rsem_t; SemaphoreHandle_t xSemaphoreCreateMutex(void) { - _mutex_t* _tmp = (_mutex_t*)malloc (sizeof(_mutex_t)); + _sem_t* _tmp = (_sem_t*)malloc (sizeof(_sem_t)); _tmp->type = queueQUEUE_TYPE_MUTEX; + _tmp->pid = KERNEL_PID_UNDEF; mutex_init(&_tmp->mutex); DEBUG("%s mutex=%p\n", __func__, _tmp); return _tmp; } -void vSemaphoreDelete( SemaphoreHandle_t xSemaphore ) +void vSemaphoreDelete(SemaphoreHandle_t xSemaphore) { DEBUG("%s mutex=%p\n", __func__, xSemaphore); @@ -59,21 +62,23 @@ void vSemaphoreDelete( SemaphoreHandle_t xSemaphore ) free(xSemaphore); } -BaseType_t xSemaphoreGive (SemaphoreHandle_t xSemaphore) +BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore) { DEBUG("%s mutex=%p\n", __func__, xSemaphore); assert(xSemaphore != NULL); - uint8_t type = ((_mutex_t*)xSemaphore)->type; - mutex_t* mutex= &((_mutex_t*)xSemaphore)->mutex; + _sem_t* sem = (_sem_t*)xSemaphore; - switch (type) { + switch (sem->type) { case queueQUEUE_TYPE_MUTEX: - mutex_unlock(mutex); + mutex_unlock(&sem->mutex); + if (sem->mutex.queue.next == NULL) { + sem->pid = KERNEL_PID_UNDEF; + } break; case queueQUEUE_TYPE_RECURSIVE_MUTEX: - return xSemaphoreGiveRecursive (xSemaphore); + return xSemaphoreGiveRecursive(xSemaphore); default: return xQueueGenericSend(xSemaphore, NULL, 0, queueSEND_TO_BACK); } @@ -81,31 +86,37 @@ BaseType_t xSemaphoreGive (SemaphoreHandle_t xSemaphore) return pdTRUE; } -BaseType_t xSemaphoreTake (SemaphoreHandle_t xSemaphore, - TickType_t xTicksToWait) +BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, + TickType_t xTicksToWait) { - DEBUG("%s mutex=%p wait=%u\n", __func__, xSemaphore, xTicksToWait); + DEBUG("%s mutex=%p wait=%"PRIu32"\n", __func__, xSemaphore, xTicksToWait); assert(xSemaphore != NULL); - uint8_t type = ((_mutex_t*)xSemaphore)->type; - mutex_t* mutex= &((_mutex_t*)xSemaphore)->mutex; + _sem_t* sem = (_sem_t*)xSemaphore; - switch (type) { + switch (sem->type) { case queueQUEUE_TYPE_MUTEX: { if (xTicksToWait == 0) { - return (mutex_trylock(mutex) == 1) ? pdPASS : pdFAIL; + if (mutex_trylock(&sem->mutex) == 1) { + sem->pid = thread_getpid(); + return pdPASS; + } + else { + return pdFAIL; + } } else { - mutex_lock(mutex); + mutex_lock(&sem->mutex); + sem->pid = thread_getpid(); /* TODO timeout handling */ return pdTRUE; } break; } case queueQUEUE_TYPE_RECURSIVE_MUTEX: - return xSemaphoreTakeRecursive (xSemaphore, xTicksToWait); + return xSemaphoreTakeRecursive(xSemaphore, xTicksToWait); default: return xQueueGenericReceive(xSemaphore, NULL, xTicksToWait, pdFALSE); @@ -114,8 +125,9 @@ BaseType_t xSemaphoreTake (SemaphoreHandle_t xSemaphore, SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void) { - _rmutex_t* _tmp = (_rmutex_t*)malloc (sizeof(_rmutex_t)); + _rsem_t* _tmp = (_rsem_t*)malloc (sizeof(_rsem_t)); _tmp->type = queueQUEUE_TYPE_RECURSIVE_MUTEX; + _tmp->pid = KERNEL_PID_UNDEF; rmutex_init(&_tmp->rmutex); DEBUG("%s rmutex=%p\n", __func__, _tmp); @@ -123,39 +135,57 @@ SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void) return _tmp; } -BaseType_t xSemaphoreGiveRecursive (SemaphoreHandle_t xSemaphore) +BaseType_t xSemaphoreGiveRecursive(SemaphoreHandle_t xSemaphore) { DEBUG("%s rmutex=%p\n", __func__, xSemaphore); - assert(xSemaphore != NULL); - assert(((_rmutex_t*)xSemaphore)->type == queueQUEUE_TYPE_RECURSIVE_MUTEX); + _rsem_t* rsem = (_rsem_t*)xSemaphore; + + assert(rsem != NULL); + assert(rsem->type == queueQUEUE_TYPE_RECURSIVE_MUTEX); - rmutex_unlock(&((_rmutex_t*)xSemaphore)->rmutex); + rmutex_unlock(&rsem->rmutex); + if (rsem->rmutex.mutex.queue.next == NULL) { + rsem->pid = KERNEL_PID_UNDEF; + } return pdTRUE; } -BaseType_t xSemaphoreTakeRecursive (SemaphoreHandle_t xSemaphore, - TickType_t xTicksToWait) +BaseType_t xSemaphoreTakeRecursive(SemaphoreHandle_t xSemaphore, + TickType_t xTicksToWait) { - DEBUG("%s rmutex=%p wait=%u\n", __func__, xSemaphore, xTicksToWait); + DEBUG("%s rmutex=%p wait=%"PRIu32"\n", __func__, xSemaphore, xTicksToWait); - assert(xSemaphore != NULL); - assert(((_rmutex_t*)xSemaphore)->type == queueQUEUE_TYPE_RECURSIVE_MUTEX); + _rsem_t* rsem = (_rsem_t*)xSemaphore; + + assert(rsem != NULL); + assert(rsem->type == queueQUEUE_TYPE_RECURSIVE_MUTEX); BaseType_t ret = pdTRUE; - rmutex_t* rmutex = &((_rmutex_t*)xSemaphore)->rmutex; if (xTicksToWait == 0) { - ret = (rmutex_trylock(rmutex) == 1) ? pdPASS : pdFAIL; + ret = (rmutex_trylock(&rsem->rmutex) == 1) ? pdPASS : pdFAIL; + if (ret == pdPASS) { + rsem->pid = thread_getpid(); + } } else { - rmutex_lock(&((_rmutex_t*)xSemaphore)->rmutex); + rmutex_lock(&rsem->rmutex); + rsem->pid = thread_getpid(); /* TODO timeout handling */ } return ret; } +TaskHandle_t xSemaphoreGetMutexHolder(SemaphoreHandle_t xMutex) +{ + DEBUG("%s mutex=%p\n", __func__, xMutex); + + assert(xMutex != NULL); + return (TaskHandle_t)(0L + ((_sem_t*)xMutex)->pid); +} + void vPortCPUAcquireMutex(portMUX_TYPE *mux) { DEBUG("%s pid=%d prio=%d mux=%p\n", __func__, diff --git a/cpu/esp_common/freertos/task.c b/cpu/esp_common/freertos/task.c index 089ef2778670..4d1f2d431d50 100644 --- a/cpu/esp_common/freertos/task.c +++ b/cpu/esp_common/freertos/task.c @@ -21,7 +21,7 @@ #include "log.h" #include "syscalls.h" #include "thread.h" -#if defined(MODULE_ESP_WIFI_ANY) || defined(MODULE_ESP_ETH) +#if defined(MODULE_ZTIMER_MSEC) || defined(MODULE_ZTIMER_USEC) #include "ztimer.h" #endif #include "timex.h" @@ -48,10 +48,11 @@ typedef struct { uint32_t saved_int_state; uint32_t critical_nesting; uint32_t notification_value; - bool notification_wait_for; + bool notification_waiting; + bool notification_pending; } thread_arch_ext_t; -volatile thread_arch_ext_t threads_arch_exts[KERNEL_PID_LAST + 1] = {}; +volatile thread_arch_ext_t threads_arch_exts[KERNEL_PID_LAST + 1] = { }; BaseType_t xTaskCreatePinnedToCore(TaskFunction_t pvTaskCode, const char * const pcName, @@ -66,14 +67,14 @@ BaseType_t xTaskCreatePinnedToCore(TaskFunction_t pvTaskCode, /* FreeRTOS priority values have to be inverted */ uxPriority = SCHED_PRIO_LEVELS - uxPriority - 1; - DEBUG("%s name=%s size=%d prio=%d pvCreatedTask=%p xCoreId=%d", + DEBUG("%s name=%s size=%"PRIu32" prio=%u pvCreatedTask=%p xCoreId=%d\n", __func__, pcName, usStackDepth, uxPriority, pvCreatedTask, xCoreID); char* stack = malloc(usStackDepth + sizeof(thread_t)); if (!stack) { LOG_TAG_ERROR("freertos", "not enough memory to create task %s with " - "stack size of %d bytes\n", pcName, usStackDepth); + "stack size of %"PRIu32" bytes\n", pcName, usStackDepth); abort(); return pdFALSE; } @@ -114,19 +115,16 @@ void vTaskDelete(TaskHandle_t xTaskToDelete) extern volatile thread_t *sched_active_thread; DEBUG("%s pid=%d task=%p\n", __func__, thread_getpid(), xTaskToDelete); - assert(xTaskToDelete != NULL); - uint32_t pid = (uint32_t)xTaskToDelete; + assert(pid_is_valid(pid)); - /* remove old task from scheduling */ + /* remove the task from scheduling */ thread_t* thread = (thread_t*)sched_threads[pid]; sched_set_status(thread, STATUS_STOPPED); sched_threads[pid] = NULL; sched_num_threads--; - sched_active_thread = NULL; - /* determine the new running task */ - sched_run(); + free(thread->stack_start); } void vTaskSuspend(TaskHandle_t xTaskToSuspend) @@ -134,19 +132,17 @@ void vTaskSuspend(TaskHandle_t xTaskToSuspend) extern volatile thread_t *sched_active_thread; DEBUG("%s pid=%d task=%p\n", __func__, thread_getpid(), xTaskToSuspend); - uint32_t pid = (xTaskToSuspend == NULL) ? (uint32_t)thread_getpid() - : (uint32_t)xTaskToSuspend; - - assert(pid <= KERNEL_PID_LAST); + thread_t *thread = thread_get((xTaskToSuspend == NULL) ? (uint32_t)thread_getpid() + : (uint32_t)xTaskToSuspend); + assert(thread != NULL); /* set status to sleeping to suspend it */ - thread_t* thread = (thread_t*)sched_threads[pid]; sched_set_status(thread, STATUS_SLEEPING); - /* trigger rescheduling */ - sched_active_thread = NULL; - /* determine the new running task */ - sched_run(); + /* trigger rescheduling if a task suspends itself */ + if (xTaskToSuspend == NULL) { + thread_yield_higher(); + } } void vTaskResume(TaskHandle_t xTaskToResume) @@ -155,10 +151,23 @@ void vTaskResume(TaskHandle_t xTaskToResume) DEBUG("%s pid=%d task=%p\n", __func__, thread_getpid(), xTaskToResume); uint32_t pid = (uint32_t)xTaskToResume; - assert(pid <= KERNEL_PID_LAST); + assert(pid_is_valid(pid)); thread_wakeup (pid); } +void vTaskDelay(const TickType_t xTicksToDelay) +{ + DEBUG("%s xTicksToDelay=%"PRIu32"\n", __func__, xTicksToDelay); + +#if defined(MODULE_ZTIMER_MSEC) + uint64_t ms = xTicksToDelay * portTICK_PERIOD_MS; + ztimer_sleep(ZTIMER_MSEC, ms); +#elif defined(MODULE_ZTIMER_USEC) + uint64_t us = xTicksToDelay * portTICK_PERIOD_MS * US_PER_MS; + ztimer_sleep(ZTIMER_USEC, us); +#endif +} + TaskHandle_t xTaskGetCurrentTaskHandle(void) { DEBUG("%s pid=%d\n", __func__, thread_getpid()); @@ -167,14 +176,50 @@ TaskHandle_t xTaskGetCurrentTaskHandle(void) return (TaskHandle_t)pid; } -void vTaskDelay( const TickType_t xTicksToDelay ) +const char *pcTaskGetTaskName(TaskHandle_t xTaskToQuery) { - DEBUG("%s xTicksToDelay=%d\n", __func__, xTicksToDelay); -#if defined(MODULE_ESP_WIFI_ANY) || defined(MODULE_ESP_ETH) - uint64_t ms = xTicksToDelay * MS_PER_SEC / xPortGetTickRateHz(); - ztimer_sleep(ZTIMER_MSEC, ms); -#endif + DEBUG("%s pid=%d task=%p\n", __func__, thread_getpid(), xTaskToQuery); + + thread_t *thread = thread_get((xTaskToQuery == NULL) ? (uint32_t)thread_getpid() + : (uint32_t)xTaskToQuery); + assert(thread != NULL); + return thread->name; +} + +#ifdef DEVELHELP +UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t xTask) +{ + DEBUG("%s pid=%d task=%p\n", __func__, thread_getpid(), xTask); + + thread_t *thread = thread_get((xTask == NULL) ? (uint32_t)thread_getpid() + : (uint32_t)xTask); + assert(thread != NULL); + return thread_measure_stack_free(thread->stack_start); +} + +void *pvTaskGetThreadLocalStoragePointer(TaskHandle_t xTaskToQuery, + BaseType_t xIndex) +{ + (void)xTaskToQuery; + (void)xIndex; + + /* TODO define TLS using thread_arch_t */ + return NULL; +} + +void vTaskSetThreadLocalStoragePointerAndDelCallback(TaskHandle_t xTaskToSet, + BaseType_t xIndex, + void *pvValue, + TlsDeleteCallbackFunction_t pvDelCallback) +{ + (void)xTaskToSet; + (void)xIndex; + (void)pvValue; + (void)pvDelCallback; + + /* TODO define TLS using thread_arch_t */ } +#endif /* DEVELHELP */ TickType_t xTaskGetTickCount (void) { @@ -249,7 +294,7 @@ void vTaskExitCritical( portMUX_TYPE *mux ) void vTaskStepTick(const TickType_t xTicksToJump) { - DEBUG("%s xTicksToJump=%d\n", __func__, xTicksToJump); + DEBUG("%s xTicksToJump=%"PRIu32"\n", __func__, xTicksToJump); /* * TODO: * At the moment, only the calling task is set to sleep state. Usually, the @@ -269,6 +314,120 @@ TickType_t prvGetExpectedIdleTime(void) return 0; } +BaseType_t xTaskNotify(TaskHandle_t xTaskToNotify, uint32_t ulValue, + eNotifyAction eAction) +{ + uint32_t pid = (uint32_t)xTaskToNotify; + thread_t* thread = thread_get(pid); + + DEBUG("%s task=%d notifies=%"PRIu32" value=%"PRIu32" action=%u\n", __func__, + thread_getpid(), pid, ulValue, eAction); + + assert(pid_is_valid(pid)); + assert(thread != NULL); + + vTaskEnterCritical(0); + + switch (eAction) { + case eSetBits: + threads_arch_exts[pid].notification_value |= ulValue; + break; + case eIncrement: + threads_arch_exts[pid].notification_value++; + break; + case eSetValueWithoutOverwrite: + if (threads_arch_exts[pid].notification_pending) { + /* if a notificatoin is pending, return with error */ + vTaskExitCritical(0); + return pdFALSE; + } + /* fallthrough */ + case eSetValueWithOverwrite: + threads_arch_exts[pid].notification_value = ulValue; + break; + default: + /* no action */ + break; + } + + if (threads_arch_exts[pid].notification_waiting) { + /* if the task is waiting for a notification, wake it up */ + sched_set_status(thread, STATUS_PENDING); + vTaskExitCritical(0); + thread_yield_higher(); + return pdTRUE; + } + + threads_arch_exts[pid].notification_pending = true; + + vTaskExitCritical(0); + return pdTRUE; +} + +BaseType_t xTaskNotifyWait(uint32_t ulBitsToClearOnEntry, + uint32_t ulBitsToClearOnExit, + uint32_t *pulNotificationValue, + TickType_t xTicksToWait) +{ + kernel_pid_t pid = thread_getpid(); + + DEBUG("%s task=%d entry=%08"PRIx32" exit=%08"PRIx32" wait=%u\n", __func__, + pid, ulBitsToClearOnEntry, ulBitsToClearOnExit, xTicksToWait); + + assert(pid_is_valid(pid)); + assert((xTicksToWait != 0) && !irq_is_in()); + + vTaskEnterCritical(0); + + if (!threads_arch_exts[pid].notification_pending) { + /* bits to clear on entry if notification was not pending */ + threads_arch_exts[pid].notification_value ^= ulBitsToClearOnEntry; + + /* suspend the calling thread to wait for notification */ + threads_arch_exts[pid].notification_waiting = true; + thread_t *me = thread_get_active(); + sched_set_status(me, STATUS_SLEEPING); + + DEBUG("%s pid=%d suspend calling thread\n", __func__, pid); + +#if IS_USED(MODULE_ZTIMER_MSEC) + ztimer_t tm = { }; + uint32_t to = xTicksToWait * portTICK_PERIOD_MS; + /* set the timeout if given */ + if (xTicksToWait < portMAX_DELAY) { + ztimer_set_timeout_flag(ZTIMER_MSEC, &tm, to); + ztimer_set_wakeup(ZTIMER_MSEC, &tm, to + 1, pid); + } +#else + assert(xTicksToWait == portMAX_DELAY); +#endif + vTaskExitCritical(0); + thread_yield_higher(); + +#if IS_USED(MODULE_ZTIMER_MSEC) + vTaskEnterCritical(0); + if (xTicksToWait < portMAX_DELAY) { + ztimer_remove(ZTIMER_MSEC, &tm); + if (me->flags & THREAD_FLAG_TIMEOUT) { + vTaskExitCritical(0); + return pdFALSE; + } + } +#else + assert(xTicksToWait == portMAX_DELAY); +#endif + } + + if (pulNotificationValue) { + /* save the notification value before clearing bits on exit */ + *pulNotificationValue = threads_arch_exts[pid].notification_value; + } + threads_arch_exts[pid].notification_value ^= ulBitsToClearOnExit; + + vTaskExitCritical(0); + return pdTRUE; +} + BaseType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify) { DEBUG("%s pid=%d task=%p\n", __func__, thread_getpid(), xTaskToNotify); @@ -279,19 +438,20 @@ BaseType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify) void vTaskNotifyGiveFromISR(TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken) { - DEBUG("%s pid=%d task=%p\n", __func__, thread_getpid(), xTaskToNotify); - uint32_t pid = (uint32_t)xTaskToNotify; + thread_t* thread = thread_get(pid); + + DEBUG("%s task=%d notifies=%"PRIu32"\n", __func__, thread_getpid(), pid); - assert(pid <= KERNEL_PID_LAST); + assert(pid_is_valid(pid)); + assert(thread); vTaskEnterCritical(0); threads_arch_exts[pid].notification_value++; - if (threads_arch_exts[pid].notification_wait_for) { + if (threads_arch_exts[pid].notification_waiting) { /* if the task is waiting for notification, set its status to pending */ - thread_t* thread = (thread_t*)sched_threads[pid]; sched_set_status(thread, STATUS_PENDING); if (thread->priority < sched_threads[thread_getpid()]->priority) { @@ -316,7 +476,7 @@ uint32_t ulTaskNotifyTake(BaseType_t xClearCountOnExit, kernel_pid_t pid = thread_getpid(); - assert((pid >= 0) && (pid <= KERNEL_PID_LAST)); + assert(pid_is_valid(pid)); vTaskEnterCritical(0); @@ -334,7 +494,7 @@ uint32_t ulTaskNotifyTake(BaseType_t xClearCountOnExit, } else { /* suspend the calling thread to wait for notification */ - threads_arch_exts[pid].notification_wait_for = true; + threads_arch_exts[pid].notification_waiting = true; thread_t *me = thread_get_active(); sched_set_status(me, STATUS_SLEEPING); @@ -346,7 +506,7 @@ uint32_t ulTaskNotifyTake(BaseType_t xClearCountOnExit, /* TODO timeout handling with xTicksToWait */ DEBUG("%s pid=%d continue calling thread\n", __func__, thread_getpid()); } - threads_arch_exts[pid].notification_wait_for = false; + threads_arch_exts[pid].notification_waiting = false; if (xClearCountOnExit) { threads_arch_exts[pid].notification_value = 0; } diff --git a/cpu/esp_common/freertos/timers.c b/cpu/esp_common/freertos/timers.c index fc62edb03f09..aea3e9c464d6 100644 --- a/cpu/esp_common/freertos/timers.c +++ b/cpu/esp_common/freertos/timers.c @@ -71,13 +71,14 @@ TimerHandle_t xTimerCreate (const char * const pcTimerName, timer->ztimer.callback = _ztimer_callback; timer->ztimer.arg = timer; - DEBUG("%s %p %s %d %u\n", __func__, timer, pcTimerName, xTimerPeriod, uxAutoReload); + DEBUG("%s %p %s %"PRIu32" %u\n", + __func__, timer, pcTimerName, xTimerPeriod, uxAutoReload); return timer; } BaseType_t xTimerDelete(TimerHandle_t xTimer, TickType_t xBlockTime) { - DEBUG("%s %p %d\n", __func__, xTimer, xBlockTime); + DEBUG("%s %p %"PRIu32"\n", __func__, xTimer, xBlockTime); assert(xTimer != NULL); freertos_ztimer_t* timer = (freertos_ztimer_t*)xTimer; @@ -89,7 +90,7 @@ BaseType_t xTimerDelete(TimerHandle_t xTimer, TickType_t xBlockTime) BaseType_t xTimerStart (TimerHandle_t xTimer, TickType_t xBlockTime) { - DEBUG("%s %p %d\n", __func__, xTimer, xBlockTime); + DEBUG("%s %p %"PRIu32"\n", __func__, xTimer, xBlockTime); assert(xTimer != NULL); freertos_ztimer_t* timer = (freertos_ztimer_t*)xTimer; @@ -100,7 +101,7 @@ BaseType_t xTimerStart (TimerHandle_t xTimer, TickType_t xBlockTime) BaseType_t xTimerStop (TimerHandle_t xTimer, TickType_t xBlockTime) { - DEBUG("%s %p %d\n", __func__, xTimer, xBlockTime); + DEBUG("%s %p %"PRIu32"\n", __func__, xTimer, xBlockTime); assert(xTimer != NULL); freertos_ztimer_t* timer = (freertos_ztimer_t*)xTimer; @@ -111,7 +112,7 @@ BaseType_t xTimerStop (TimerHandle_t xTimer, TickType_t xBlockTime) BaseType_t xTimerReset (TimerHandle_t xTimer, TickType_t xBlockTime) { - DEBUG("%s %p %d\n", __func__, xTimer, xBlockTime); + DEBUG("%s %p %"PRIu32"\n", __func__, xTimer, xBlockTime); assert(xTimer != NULL); freertos_ztimer_t* timer = (freertos_ztimer_t*)xTimer; diff --git a/cpu/esp_common/include/freertos/FreeRTOS.h b/cpu/esp_common/include/freertos/FreeRTOS.h index 28e71e6743fe..30e8df6f6558 100644 --- a/cpu/esp_common/include/freertos/FreeRTOS.h +++ b/cpu/esp_common/include/freertos/FreeRTOS.h @@ -27,16 +27,19 @@ extern "C" { #endif #define portTICK_PERIOD_MS 10 -#define portTickType TickType_t #define portTICK_RATE_MS portTICK_PERIOD_MS #define BaseType_t portBASE_TYPE -#define UBaseType_t unsigned portBASE_TYPE +#define UBaseType_t portUBASE_TYPE +#define TickType_t portTICK_TYPE +#define StackType_t portSTACK_TYPE + +#define portTickType TickType_t #define pdMS_TO_TICKS(ms) ((TickType_t)(ms / portTICK_PERIOD_MS)) -typedef uint32_t TickType_t; +#define xSemaphoreHandle SemaphoreHandle_t uint32_t xPortGetTickRateHz(void); BaseType_t xPortInIsrContext(void); diff --git a/cpu/esp_common/include/freertos/portmacro.h b/cpu/esp_common/include/freertos/portmacro.h index a00ed89e59a0..0683b30ce4a6 100644 --- a/cpu/esp_common/include/freertos/portmacro.h +++ b/cpu/esp_common/include/freertos/portmacro.h @@ -17,6 +17,7 @@ #include "stdint.h" #ifndef MCU_ESP8266 +#include "esp_heap_caps.h" #include "esp_timer.h" #endif @@ -29,8 +30,10 @@ extern "C" { #define portBASE_TYPE int #define portUBASE_TYPE unsigned portBASE_TYPE +#define portTICK_TYPE uint32_t +#define portSTACK_TYPE uint8_t -#define portMAX_DELAY 0xFFFFFFFF +#define portMAX_DELAY 0xFFFFFFFFUL #define portMUX_TYPE mutex_t #define portMUX_INITIALIZE mutex_init @@ -50,6 +53,8 @@ extern "C" { #define portSET_INTERRUPT_MASK_FROM_ISR xPortSetInterruptMaskFromISR #define portCLEAR_INTERRUPT_MASK_FROM_ISR vPortClearInterruptMaskFromISR +#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 ) + #ifdef MCU_ESP32 #define portNUM_PROCESSORS 2 diff --git a/cpu/esp_common/include/freertos/queue.h b/cpu/esp_common/include/freertos/queue.h index f215245202a1..b3557c7077f2 100644 --- a/cpu/esp_common/include/freertos/queue.h +++ b/cpu/esp_common/include/freertos/queue.h @@ -32,7 +32,7 @@ QueueHandle_t xQueueCreateCountingSemaphore (const UBaseType_t uxMaxCount, void vQueueDelete (QueueHandle_t xQueue); -BaseType_t xQueueGenericReset (QueueHandle_t xQueue, BaseType_t xNewQueue); +BaseType_t xQueueReset (QueueHandle_t xQueue); BaseType_t xQueueGenericReceive (QueueHandle_t xQueue, void * const pvBuffer, @@ -108,7 +108,10 @@ UBaseType_t uxQueueMessagesWaiting( QueueHandle_t xQueue ); ( pxHigherPriorityTaskWoken ), \ queueSEND_TO_BACK ) -#define xQueueReset( xQueue ) xQueueGenericReset( xQueue, pdFALSE ) +#define xQueueOverwriteFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) \ + xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), \ + ( pxHigherPriorityTaskWoken ), \ + queueOVERWRITE ) #ifdef __cplusplus } diff --git a/cpu/esp_common/include/freertos/ringbuf.h b/cpu/esp_common/include/freertos/ringbuf.h index 10f3dccd3ade..2e34f58edbb1 100644 --- a/cpu/esp_common/include/freertos/ringbuf.h +++ b/cpu/esp_common/include/freertos/ringbuf.h @@ -21,6 +21,33 @@ extern "C" { #endif +#define RINGBUF_TYPE_BYTEBUF 2 + +typedef unsigned RingbufferType_t; +typedef void * RingbufHandle_t; + +RingbufHandle_t xRingbufferCreate(size_t xBufferSize, RingbufferType_t xBufferType); + +void vRingbufferDelete(RingbufHandle_t xRingbuffer); + +void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer, + size_t *pxItemSize, + TickType_t xTicksToWait, + size_t xMaxSize); + +BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, + const void *pvItem, + size_t xItemSize, + BaseType_t *pxHigherPriorityTaskWoken); + +void *xRingbufferReceiveUpToFromISR(RingbufHandle_t xRingbuffer, + size_t *pxItemSize, size_t xMaxSize); + +void *xRingbufferReceiveFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize); + +void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, + BaseType_t *pxHigherPriorityTaskWoken); + #ifdef __cplusplus } #endif diff --git a/cpu/esp_common/include/freertos/semphr.h b/cpu/esp_common/include/freertos/semphr.h index 8b725b27e059..ded9e5de923a 100644 --- a/cpu/esp_common/include/freertos/semphr.h +++ b/cpu/esp_common/include/freertos/semphr.h @@ -14,6 +14,7 @@ #ifndef DOXYGEN #include "freertos/FreeRTOS.h" +#include "freertos/task.h" #include #include "mutex.h" @@ -36,6 +37,8 @@ BaseType_t xSemaphoreGiveRecursive (SemaphoreHandle_t xSemaphore); BaseType_t xSemaphoreTakeRecursive (SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait); +TaskHandle_t xSemaphoreGetMutexHolder(SemaphoreHandle_t xMutex); + #define vPortCPUInitializeMutex(m) mutex_init(m) void vPortCPUAcquireMutex (portMUX_TYPE *mux); diff --git a/cpu/esp_common/include/freertos/task.h b/cpu/esp_common/include/freertos/task.h index 261146224cca..4b51c716e97f 100644 --- a/cpu/esp_common/include/freertos/task.h +++ b/cpu/esp_common/include/freertos/task.h @@ -31,7 +31,18 @@ extern "C" { #define taskENTER_CRITICAL portENTER_CRITICAL #define taskEXIT_CRITICAL portEXIT_CRITICAL +#define taskSCHEDULER_RUNNING 2 + +typedef enum { + eNoAction = 0, + eSetBits, + eIncrement, + eSetValueWithOverwrite, + eSetValueWithoutOverwrite, +} eNotifyAction; + typedef void (*TaskFunction_t)(void *); +typedef void (*TlsDeleteCallbackFunction_t)( int, void * ); typedef void* TaskHandle_t; @@ -58,11 +69,29 @@ void vTaskSuspendAll(void); TaskHandle_t xTaskGetCurrentTaskHandle(void); +const char *pcTaskGetTaskName(TaskHandle_t xTaskToQuery); + +UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t xTask); + +void *pvTaskGetThreadLocalStoragePointer(TaskHandle_t xTaskToQuery, + BaseType_t xIndex); +void vTaskSetThreadLocalStoragePointerAndDelCallback(TaskHandle_t xTaskToSet, + BaseType_t xIndex, + void *pvValue, + TlsDeleteCallbackFunction_t pvDelCallback); + void vTaskEnterCritical(portMUX_TYPE *mux); void vTaskExitCritical(portMUX_TYPE *mux); TickType_t xTaskGetTickCount(void); +BaseType_t xTaskNotify(TaskHandle_t xTaskToNotify, uint32_t ulValue, + eNotifyAction eAction); +BaseType_t xTaskNotifyWait(uint32_t ulBitsToClearOnEntry, + uint32_t ulBitsToClearOnExit, + uint32_t *pulNotificationValue, + TickType_t xTicksToWait); + BaseType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify); void vTaskNotifyGiveFromISR(TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken); From d625f91af82fcdb6f7fdca8c5a99094fb5c3fdec Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 16:10:17 +0100 Subject: [PATCH 03/46] cpu/esp_common: remove ESP32 spi_flash_* funcs in periph/flash Updates `cpu/esp_common/periph/flash` for ESP-IDF 4.4. `spi_flash_*` functions for ESP32 are removed since these functions are now used from ESP-IDF. DEBUG output are changed to be platform independent. --- cpu/esp32/esp-idf/include/sdkconfig.h | 1 + cpu/esp_common/periph/flash.c | 326 +++++--------------------- 2 files changed, 54 insertions(+), 273 deletions(-) diff --git a/cpu/esp32/esp-idf/include/sdkconfig.h b/cpu/esp32/esp-idf/include/sdkconfig.h index 7832885caa28..77d664427175 100644 --- a/cpu/esp32/esp-idf/include/sdkconfig.h +++ b/cpu/esp32/esp-idf/include/sdkconfig.h @@ -181,6 +181,7 @@ extern "C" { * SPI Flash driver configuration (DO NOT CHANGE) */ #define CONFIG_SPI_FLASH_ROM_DRIVER_PATCH 1 +#define CONFIG_SPI_FLASH_USE_LEGACY_IMPL 1 /** * Ethernet driver configuration (DO NOT CHANGE) diff --git a/cpu/esp_common/periph/flash.c b/cpu/esp_common/periph/flash.c index 2a648b1a5b31..16b5d2de90dc 100644 --- a/cpu/esp_common/periph/flash.c +++ b/cpu/esp_common/periph/flash.c @@ -33,7 +33,7 @@ #include "esp_partition.h" -#ifdef MCU_ESP32 +#ifndef MCU_ESP8266 #include "esp_flash_partitions.h" #include "esp_spi_flash.h" @@ -41,13 +41,13 @@ #include "rom/spi_flash.h" #include "soc/soc.h" -#else /* MCU_ESP32 */ +#else /* !MCU_ESP8266 */ #include "esp_flash_data_types.h" #include "rom_functions.h" #include "spi_flash.h" -#endif /* MCU_ESP32 */ +#endif /* !MCU_ESP8266 */ #define ENABLE_DEBUG 0 #include "debug.h" @@ -81,13 +81,13 @@ extern uint32_t spi_flash_get_id(void); #endif /* MCU_ESP8266 */ /* forward declaration of mtd functions */ -static int _flash_init (mtd_dev_t *dev); -static int _flash_read (mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size); -static int _flash_write (mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size); -static int _flash_write_page (mtd_dev_t *dev, const void *buff, uint32_t page, +static int _flash_init(mtd_dev_t *dev); +static int _flash_read(mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size); +static int _flash_write(mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size); +static int _flash_write_page(mtd_dev_t *dev, const void *buff, uint32_t page, uint32_t offset, uint32_t size); -static int _flash_erase (mtd_dev_t *dev, uint32_t addr, uint32_t size); -static int _flash_power (mtd_dev_t *dev, enum mtd_power_state power); +static int _flash_erase(mtd_dev_t *dev, uint32_t addr, uint32_t size); +static int _flash_power(mtd_dev_t *dev, enum mtd_power_state power); static uint32_t _flash_beg; /* first byte addr of the flash drive in SPI flash */ static uint32_t _flash_end; /* first byte addr after the flash drive in SPI flash */ @@ -108,7 +108,7 @@ static const uint32_t flash_sizes[] = { }; #endif -void spi_flash_drive_init (void) +void spi_flash_drive_init(void) { DEBUG("%s\n", __func__); @@ -154,7 +154,7 @@ void spi_flash_drive_init (void) spi_flash_read (part_addr, (void*)part_buf, ESP_PART_ENTRY_SIZE); if (part->magic == ESP_PART_ENTRY_MAGIC) { - DEBUG("%s partition @%08x size=%08x label=%s\n", __func__, + DEBUG("%s partition @%08"PRIx32" size=%08"PRIx32" label=%s\n", __func__, part->pos.offset, part->pos.size, part->label); if (part->pos.offset + part->pos.size > part_top) { part_top = part->pos.offset + part->pos.size; @@ -166,19 +166,19 @@ void spi_flash_drive_init (void) } } -#ifdef MCU_ESP32 +#ifndef MCU_ESP8266 /* map the partition top address to next higher multiple of 0x100000 (1 MB) */ part_top = (part_top + 0x100000) & ~0xfffff; -#else /* MCU_ESP32 */ +#else /* !MCU_ESP8266 */ /* map the partition top address to next higher multiple of 0x80000 (512 kB) */ part_top = (part_top + 0x80000) & ~0x7ffff; -#endif /* MCU_ESP32 */ +#endif /* !MCU_ESP8266 */ /* * if flash drive start address is not configured, use the determined * one otherwise check the configured one and use it */ - #if SPI_FLASH_DRIVE_START +#if SPI_FLASH_DRIVE_START if (part_top > SPI_FLASH_DRIVE_START) { LOG_TAG_ERROR("spi_flash", "configured MTD start address in SPI Flash is to less\n"); } @@ -191,15 +191,16 @@ void spi_flash_drive_init (void) else { part_top = SPI_FLASH_DRIVE_START; } - #endif +#endif /* second, change flash parameters according to partition table */ _flash_beg = part_top; _flash_end = _flashchip->chip_size - 5 * _flashchip->sector_size; _flash_size = _flash_end - _flash_beg; /* MUST be at least 3 sectors (0x3000) */ - LOG_TAG_DEBUG("spi_flash", "MTD in SPI flash starts at address 0x%08x " - "with a size of %d kbytes\n", _flash_beg, _flash_size >> 10); + LOG_TAG_DEBUG("spi_flash", "MTD in SPI flash starts at address " + "0x%08"PRIx32" with a size of %"PRIu32" kbytes\n", + _flash_beg, _flash_size >> 10); _flash_dev.driver = &_flash_driver; _flash_dev.sector_count = _flash_size / _flashchip->sector_size; @@ -212,241 +213,17 @@ void spi_flash_drive_init (void) * performance */ _flash_dev.write_size = 4; - DEBUG("%s flashchip chip_size=%d block_size=%d sector_size=%d page_size=%d\n", __func__, + DEBUG("%s flashchip chip_size=%"PRIu32" block_size=%"PRIu32 + " sector_size=%"PRIu32" page_size=%"PRIu32"\n", __func__, _flashchip->chip_size, _flashchip->block_size, _flashchip->sector_size, _flashchip->page_size); - DEBUG("%s flash_dev sector_count=%d pages_per_sector=%d page_size=%d\n", __func__, + DEBUG("%s flash_dev sector_count=%"PRIu32" pages_per_sector=%"PRIu32 + " page_size=%"PRIu32"\n", __func__, _flash_dev.sector_count, _flash_dev.pages_per_sector, _flash_dev.page_size); DEBUG("\n"); } -#ifdef MCU_ESP32 - -#define RETURN_WITH_ESP_ERR_CODE(err) do { \ - switch (err) { \ - case ESP_ROM_SPIFLASH_RESULT_OK : return ESP_OK; \ - case ESP_ROM_SPIFLASH_RESULT_ERR : return ESP_ERR_FLASH_OP_FAIL; \ - case ESP_ROM_SPIFLASH_RESULT_TIMEOUT: return ESP_ERR_FLASH_OP_TIMEOUT; \ - } \ - return ESP_FAIL; \ -} while(0) - -static uint32_t _flash_buf[ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM / sizeof(uint32_t)]; - -esp_err_t IRAM_ATTR spi_flash_read(size_t addr, void *buff, size_t size) -{ - DEBUG("%s addr=%08x size=%u buf=%p\n", __func__, addr, size, buff); - - CHECK_PARAM_RET (buff != NULL, -ENOTSUP); - - /* size must be within the flash address space */ - CHECK_PARAM_RET (addr + size <= _flash_end, -EOVERFLOW); - - int result = ESP_ROM_SPIFLASH_RESULT_OK; - uint32_t len = size; - - /* if addr is not 4 byte aligned, we need to read the first full word */ - if (addr & 0x3) { - uint32_t word_addr = addr & ~0x3; - uint32_t pos_in_word = addr & 0x3; - uint32_t len_in_word = 4 - pos_in_word; - len_in_word = (len_in_word < len) ? len_in_word : len; - - /* disable interrupts and the cache */ - critical_enter(); - Cache_Read_Disable(PRO_CPU_NUM); - - result = esp_rom_spiflash_read(word_addr, _flash_buf, 4); - memcpy(buff, (uint8_t *)_flash_buf + pos_in_word, len_in_word); - - /* enable interrupts and the cache */ - Cache_Read_Enable(PRO_CPU_NUM); - critical_exit(); - - buff = (uint8_t*)buff + len_in_word; - addr += len_in_word; - len -= len_in_word; - } - - /* read all full words, maximum ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM - in one read operation */ - while (len > 4 && result == ESP_ROM_SPIFLASH_RESULT_OK) { - uint32_t len_full_words = len & ~0x3; - if (len_full_words > ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM) { - len_full_words = ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM; - } - - /* disable interrupts and the cache */ - critical_enter(); - Cache_Read_Disable(PRO_CPU_NUM); - - result |= esp_rom_spiflash_read(addr, _flash_buf, len_full_words); - memcpy(buff, _flash_buf, len_full_words); - - /* enable interrupts and the cache */ - Cache_Read_Enable(PRO_CPU_NUM); - critical_exit(); - - buff = (uint8_t*)buff + len_full_words; - addr += len_full_words; - len -= len_full_words; - } - - /* if there is some remaining, we need to prepare last word */ - if (len && result == ESP_ROM_SPIFLASH_RESULT_OK) { - /* disable interrupts and the cache */ - critical_enter(); - Cache_Read_Disable(PRO_CPU_NUM); - - result |= esp_rom_spiflash_read(addr, _flash_buf, 4); - memcpy(buff, _flash_buf, len); - - /* enable interrupts and the cache */ - Cache_Read_Enable(PRO_CPU_NUM); - critical_exit(); - } - - /* return with the ESP-IDF error code that is mapped from ROM error code */ - RETURN_WITH_ESP_ERR_CODE(result); -} - -esp_err_t IRAM_ATTR spi_flash_write(size_t addr, const void *buff, size_t size) -{ - DEBUG("%s addr=%08x size=%u buf=%p\n", __func__, addr, size, buff); - - CHECK_PARAM_RET (buff != NULL, -ENOTSUP); - - /* size must be within the flash address space */ - CHECK_PARAM_RET (addr + size <= _flash_end, -EOVERFLOW); - - /* prepare for write access */ - int result = esp_rom_spiflash_unlock(); - uint32_t len = size; - - /* if addr is not 4 byte aligned, we need to prepare first full word */ - if (addr & 0x3 && result == ESP_ROM_SPIFLASH_RESULT_OK) { - uint32_t word_addr = addr & ~0x3; - uint32_t pos_in_word = addr & 0x3; - uint32_t len_in_word = 4 - pos_in_word; - len_in_word = (len_in_word < len) ? len_in_word : len; - - /* disable interrupts and the cache */ - critical_enter(); - Cache_Read_Disable(PRO_CPU_NUM); - - result |= esp_rom_spiflash_read(word_addr, _flash_buf, 4); - memcpy((uint8_t *)_flash_buf + pos_in_word, buff, len_in_word); - result |= esp_rom_spiflash_write(word_addr, _flash_buf, 4); - - /* enable interrupts and the cache */ - Cache_Read_Enable(PRO_CPU_NUM); - critical_exit(); - - buff = (uint8_t*)buff + len_in_word; - addr += len_in_word; - len -= len_in_word; - } - - /* write all full words, maximum ESP_ROM_SPIFLASH_BUFF_BYTE_WRITE_NUM - in one write operation */ - while (len > 4 && result == ESP_ROM_SPIFLASH_RESULT_OK) { - uint32_t len_full_words = len & ~0x3; - if (len_full_words > ESP_ROM_SPIFLASH_BUFF_BYTE_WRITE_NUM) { - len_full_words = ESP_ROM_SPIFLASH_BUFF_BYTE_WRITE_NUM; - } - - /* disable interrupts and the cache */ - critical_enter(); - Cache_Read_Disable(PRO_CPU_NUM); - - memcpy(_flash_buf, buff, len_full_words); - result |= esp_rom_spiflash_write(addr, _flash_buf, len_full_words); - - /* enable interrupts and the cache */ - Cache_Read_Enable(PRO_CPU_NUM); - critical_exit(); - - buff = (uint8_t*)buff + len_full_words; - addr += len_full_words; - len -= len_full_words; - } - - /* if there is some remaining, we need to prepare last word */ - if (len && result == ESP_ROM_SPIFLASH_RESULT_OK) { - /* disable interrupts and the cache */ - critical_enter(); - Cache_Read_Disable(PRO_CPU_NUM); - - result |= esp_rom_spiflash_read(addr, _flash_buf, 4); - memcpy(_flash_buf, buff, len); - result |= esp_rom_spiflash_write(addr, _flash_buf, 4); - - /* enable interrupts and the cache */ - Cache_Read_Enable(PRO_CPU_NUM); - critical_exit(); - } - - /* reset write access */ - esp_rom_spiflash_lock(); - - /* return with the ESP-IDF error code that is mapped from ROM error code */ - RETURN_WITH_ESP_ERR_CODE(result); -} - -#if !IS_USED(MODULE_ESP_IDF_SPI_FLASH) -esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sector) -{ - return spi_flash_erase_range(sector * _flashchip->sector_size, 1); -} -#endif - -esp_err_t IRAM_ATTR spi_flash_erase_range(size_t addr, size_t size) -{ - /* size must be within the flash address space */ - CHECK_PARAM_RET (addr + size <= _flash_end, -EOVERFLOW); - - /* size must be a multiple of sector_size && at least one sector */ - CHECK_PARAM_RET (size >= _flashchip->sector_size, -ENOTSUP); - CHECK_PARAM_RET (size % _flashchip->sector_size == 0, -ENOTSUP) - - /* prepare for write access */ - uint32_t result = esp_rom_spiflash_unlock(); - - /* erase as many sectors as necessary */ - uint32_t sec = addr / _flashchip->sector_size; - uint32_t cnt = size / _flashchip->sector_size; - uint32_t sec_per_block = _flashchip->block_size / _flashchip->sector_size; - - while (cnt && result == ESP_ROM_SPIFLASH_RESULT_OK) { - /* disable interrupts and the cache */ - critical_enter(); - Cache_Read_Disable(PRO_CPU_NUM); - - /* erase block-wise (64 kByte) if cnt is at least sec_per_block */ - if (cnt >= sec_per_block) { - result = esp_rom_spiflash_erase_block (sec / sec_per_block); - sec += sec_per_block; - cnt -= sec_per_block; - } - else { - result = esp_rom_spiflash_erase_sector (sec++); - cnt--; - } - - /* enable interrupts and the cache */ - Cache_Read_Enable(PRO_CPU_NUM); - critical_exit(); - } - - /* reset write access */ - esp_rom_spiflash_lock(); - - /* return with the ESP-IDF error code that is mapped from ROM error code */ - RETURN_WITH_ESP_ERR_CODE(result); -} - -#endif /* MCU_ESP32 */ - +#ifdef MCU_ESP8266 const esp_partition_t* esp_partition_find_first(esp_partition_type_t type, esp_partition_subtype_t subtype, const char* label) @@ -461,10 +238,10 @@ const esp_partition_t* esp_partition_find_first(esp_partition_type_t type, esp_partition_t* part; while (info_read && info_addr < ESP_PART_TABLE_ADDR + ESP_PART_TABLE_SIZE) { - spi_flash_read (info_addr, (void*)info_buf, ESP_PART_ENTRY_SIZE); + spi_flash_read(info_addr, (void*)info_buf, ESP_PART_ENTRY_SIZE); if (info->magic == ESP_PART_ENTRY_MAGIC) { - DEBUG("%s partition @%08x size=%08x label=%s\n", __func__, + DEBUG("%s partition @%08"PRIx32" size=%08"PRIx32" label=%s\n", __func__, info->pos.offset, info->pos.size, info->label); if ((info->type == type) && (info->subtype == subtype || subtype == ESP_PARTITION_SUBTYPE_ANY) && @@ -503,15 +280,16 @@ esp_err_t esp_partition_erase_range(const esp_partition_t* part, return spi_flash_erase_range(part->address + addr, size); } +#endif /* MCU_ESP8266 */ -static int _flash_init (mtd_dev_t *dev) +static int _flash_init(mtd_dev_t *dev) { DEBUG("%s dev=%p driver=%p\n", __func__, dev, &_flash_driver); - CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV); + CHECK_PARAM_RET(dev == &_flash_dev, -ENODEV); if (_flashchip->chip_size <= _flash_beg) { - LOG_ERROR("Flash size is equal or less than %d Byte, " + LOG_ERROR("Flash size is equal or less than %"PRIu32" Byte, " "SPIFFS cannot be used\n", _flash_beg); return -ENODEV; } @@ -519,38 +297,40 @@ static int _flash_init (mtd_dev_t *dev) return 0; } -static int _flash_read (mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size) +static int _flash_read(mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size) { - DEBUG("%s dev=%p addr=%08x size=%u buf=%p\n", __func__, dev, addr, size, buff); + DEBUG("%s dev=%p addr=%08"PRIx32" size=%"PRIu32" buf=%p\n", + __func__, dev, addr, size, buff); - CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV); - CHECK_PARAM_RET (buff != NULL, -ENOTSUP); + CHECK_PARAM_RET(dev == &_flash_dev, -ENODEV); + CHECK_PARAM_RET(buff != NULL, -ENOTSUP); /* size must be within the flash address space */ - CHECK_PARAM_RET (_flash_beg + addr + size <= _flash_end, -EOVERFLOW); + CHECK_PARAM_RET(_flash_beg + addr + size <= _flash_end, -EOVERFLOW); return (spi_flash_read(_flash_beg + addr, buff, size) == ESP_OK) ? 0 : -EIO; } -static int _flash_write (mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size) +static int _flash_write(mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size) { - DEBUG("%s dev=%p addr=%08x size=%u buf=%p\n", __func__, dev, addr, size, buff); + DEBUG("%s dev=%p addr=%08"PRIx32" size=%"PRIu32" buf=%p\n", + __func__, dev, addr, size, buff); - CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV); - CHECK_PARAM_RET (buff != NULL, -ENOTSUP); + CHECK_PARAM_RET(dev == &_flash_dev, -ENODEV); + CHECK_PARAM_RET(buff != NULL, -ENOTSUP); /* size must be within the flash address space */ - CHECK_PARAM_RET (_flash_beg + addr + size <= _flash_end, -EOVERFLOW); + CHECK_PARAM_RET(_flash_beg + addr + size <= _flash_end, -EOVERFLOW); /* addr + size must be within a page */ - CHECK_PARAM_RET (size <= _flashchip->page_size, -EOVERFLOW); - CHECK_PARAM_RET ((addr % _flashchip->page_size) + size <= _flashchip->page_size, -EOVERFLOW); + CHECK_PARAM_RET(size <= _flashchip->page_size, -EOVERFLOW); + CHECK_PARAM_RET((addr % _flashchip->page_size) + size <= _flashchip->page_size, -EOVERFLOW); return (spi_flash_write(_flash_beg + addr, buff, size) == ESP_OK) ? 0 : -EIO; } -static int _flash_write_page (mtd_dev_t *dev, const void *buff, uint32_t page, uint32_t offset, - uint32_t size) +static int _flash_write_page(mtd_dev_t *dev, const void *buff, uint32_t page, uint32_t offset, + uint32_t size) { uint32_t addr = _flash_beg + page * _flashchip->page_size + offset; uint32_t remaining = _flashchip->page_size - offset; @@ -559,23 +339,23 @@ static int _flash_write_page (mtd_dev_t *dev, const void *buff, uint32_t page, return (spi_flash_write(addr, buff, size) == ESP_OK) ? (int) size : -EIO; } -static int _flash_erase (mtd_dev_t *dev, uint32_t addr, uint32_t size) +static int _flash_erase(mtd_dev_t *dev, uint32_t addr, uint32_t size) { - DEBUG("%s dev=%p addr=%08x size=%u\n", __func__, dev, addr, size); + DEBUG("%s dev=%p addr=%08"PRIx32" size=%"PRIu32"\n", __func__, dev, addr, size); - CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV); + CHECK_PARAM_RET(dev == &_flash_dev, -ENODEV); /* size must be within the flash address space */ - CHECK_PARAM_RET (_flash_beg + addr + size <= _flash_end, -EOVERFLOW); + CHECK_PARAM_RET(_flash_beg + addr + size <= _flash_end, -EOVERFLOW); /* size must be a multiple of sector_size && at least one sector */ - CHECK_PARAM_RET (size >= _flashchip->sector_size, -EOVERFLOW); - CHECK_PARAM_RET (size % _flashchip->sector_size == 0, -EOVERFLOW) + CHECK_PARAM_RET(size >= _flashchip->sector_size, -EOVERFLOW); + CHECK_PARAM_RET(size % _flashchip->sector_size == 0, -EOVERFLOW) return (spi_flash_erase_range(_flash_beg + addr, size) == ESP_OK) ? 0 : -EIO; } -static int _flash_power (mtd_dev_t *dev, enum mtd_power_state power) +static int _flash_power(mtd_dev_t *dev, enum mtd_power_state power) { DEBUG("%s\n", __func__); From ed5a14b38b69c5d67c09f82c708762b049a72953 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 16:40:21 +0100 Subject: [PATCH 04/46] cpu/esp_common: inverse MCU_* conditionals to deal with ESP32 variants The MCU_* conditionals are inverted so that they can be tested for ESP8266. In all other cases the MCU is any ESP32x SoC --- cpu/esp_common/esp-wifi/esp_wifi_netdev.c | 4 +- cpu/esp_common/include/esp_common.h | 2 +- cpu/esp_common/include/gpio_arch_common.h | 4 +- cpu/esp_common/periph/i2c_sw.c | 48 +++++++++++------------ 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/cpu/esp_common/esp-wifi/esp_wifi_netdev.c b/cpu/esp_common/esp-wifi/esp_wifi_netdev.c index 81580a63e368..26b162317f8d 100644 --- a/cpu/esp_common/esp-wifi/esp_wifi_netdev.c +++ b/cpu/esp_common/esp-wifi/esp_wifi_netdev.c @@ -615,7 +615,7 @@ static int _esp_wifi_send(netdev_t *netdev, const iolist_t *iolist) /* send the the packet to the peer(s) mac address */ if (esp_wifi_internal_tx(ESP_IF_WIFI_STA, dev->tx_buf, dev->tx_len) == ESP_OK) { #endif -#ifdef MCU_ESP32 +#ifndef MCU_ESP8266 /* for ESP8266 it is done in _esp_wifi_tx_cb */ _esp_wifi_send_is_in = false; netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE); @@ -872,7 +872,7 @@ void esp_wifi_setup (esp_wifi_netdev_t* dev) #ifndef MODULE_ESP_NOW /* if module esp_now is used, the following part is already done */ -#ifdef MCU_ESP32 +#ifndef MCU_ESP8266 extern portMUX_TYPE g_intr_lock_mux; mutex_init(&g_intr_lock_mux); #endif diff --git a/cpu/esp_common/include/esp_common.h b/cpu/esp_common/include/esp_common.h index f3f848a0cae3..5942e24c09b1 100644 --- a/cpu/esp_common/include/esp_common.h +++ b/cpu/esp_common/include/esp_common.h @@ -45,7 +45,7 @@ extern "C" { #define RTC_BSS_ATTR __attribute__((section(".rtc.bss"))) #endif -#ifndef MCU_ESP32 +#ifdef MCU_ESP8266 #ifndef RTC_DATA_ATTR #define RTC_DATA_ATTR __attribute__((section(".rtc.data"))) #endif diff --git a/cpu/esp_common/include/gpio_arch_common.h b/cpu/esp_common/include/gpio_arch_common.h index 8a0088b2f10e..f4b154188051 100644 --- a/cpu/esp_common/include/gpio_arch_common.h +++ b/cpu/esp_common/include/gpio_arch_common.h @@ -39,12 +39,12 @@ extern "C" { typedef enum { _GPIO = 0, /**< pin used as standard GPIO */ -#ifdef MCU_ESP32 +#ifndef MCU_ESP8266 _ADC, /**< pin is used as ADC input */ _CAN, /**< pin is used as CAN signal */ _DAC, /**< pin is used as DAC output */ _EMAC, /**< pin is used as EMAC signal */ -#endif /* MCU_ESP32 */ +#endif /* !MCU_ESP8266 */ _I2C, /**< pin is used as I2C signal */ _PWM, /**< pin is used as PWM output */ _SPI, /**< pin is used as SPI interface */ diff --git a/cpu/esp_common/periph/i2c_sw.c b/cpu/esp_common/periph/i2c_sw.c index 940f6168166c..791c98b5911a 100644 --- a/cpu/esp_common/periph/i2c_sw.c +++ b/cpu/esp_common/periph/i2c_sw.c @@ -45,7 +45,7 @@ #include "gpio_arch.h" #include "rom/ets_sys.h" -#ifdef MCU_ESP32 +#ifndef MCU_ESP8266 #include "soc/gpio_reg.h" #include "soc/gpio_struct.h" @@ -57,7 +57,7 @@ #define GPIO_SET(l,h,b) if (b < 32) GPIO.l = BIT(b); else GPIO.h.val = BIT(b-32) #define GPIO_GET(l,h,b) ((b < 32) ? GPIO.l & BIT(b) : GPIO.h.val & BIT(b-32)) -#else /* MCU_ESP32 */ +#else /* MCU_ESP8266 */ #include "esp/gpio_regs.h" #include "sdk/ets.h" @@ -79,7 +79,7 @@ extern uint8_t system_get_cpu_freq(void); extern bool system_update_cpu_freq(uint8_t freq); -#endif /* MCU_ESP32 */ +#endif /* MCU_ESP8266 */ typedef struct { @@ -203,7 +203,7 @@ void i2c_init(i2c_t dev) } /* Configure and initialize SDA and SCL pin. */ -#ifdef MCU_ESP32 +#ifndef MCU_ESP8266 /* * ESP32 pins are used in input/output mode with open-drain output driver. * Signal levels are then realized as following: @@ -225,7 +225,7 @@ void i2c_init(i2c_t dev) } gpio_set(i2c_config[dev].sda); -#else /* MCU_ESP32 */ +#else /* !MCU_ESP8266 */ /* * Due to critical timing required by the I2C software implementation, * the ESP8266 GPIOs can not be used directly in GPIO_OD_PU mode. @@ -245,7 +245,7 @@ void i2c_init(i2c_t dev) gpio_init(_i2c_bus[dev].sda, GPIO_IN_PU)) { return; } -#endif /* MCU_ESP32 */ +#endif /* !MCU_ESP8266 */ /* store the usage type in GPIO table */ gpio_set_pin_usage(_i2c_bus[dev].scl, _I2C); @@ -438,29 +438,29 @@ static inline void _i2c_delay(_i2c_bus_t* bus) static inline bool _i2c_scl_read(_i2c_bus_t* bus) { /* read SCL status (pin is in open-drain mode and set) */ -#ifdef MCU_ESP32 +#ifndef MCU_ESP8266 return GPIO_GET(in, in1, bus->scl); -#else /* MCU_ESP32 */ +#else /* !MCU_ESP8266 */ return GPIO.IN & bus->scl_bit; -#endif /* MCU_ESP32 */ +#endif /* !MCU_ESP8266 */ } static inline bool _i2c_sda_read(_i2c_bus_t* bus) { /* read SDA status (pin is in open-drain mode and set) */ -#ifdef MCU_ESP32 +#ifndef MCU_ESP8266 return GPIO_GET(in, in1, bus->sda); -#else /* MCU_ESP32 */ +#else /* !MCU_ESP8266 */ return GPIO.IN & bus->sda_bit; -#endif /* MCU_ESP32 */ +#endif /* !MCU_ESP8266 */ } static inline void _i2c_scl_high(_i2c_bus_t* bus) { -#ifdef MCU_ESP32 +#ifndef MCU_ESP8266 /* set SCL signal high (pin is in open-drain mode and pulled-up) */ GPIO_SET(out_w1ts, out1_w1ts, bus->scl); -#else /* MCU_ESP32 */ +#else /* !MCU_ESP8266 */ #if I2C_CLOCK_STRETCH > 0 /* * set SCL signal high (switch back to GPIO_IN_PU mode, that is the pin is @@ -471,15 +471,15 @@ static inline void _i2c_scl_high(_i2c_bus_t* bus) /* No clock stretching supported, always drive the SCL pin. */ GPIO.OUT_SET = bus->scl_bit; #endif /* I2C_CLOCK_STRETCH > 0 */ -#endif /* MCU_ESP32 */ +#endif /* !MCU_ESP8266 */ } static inline void _i2c_scl_low(_i2c_bus_t* bus) { -#ifdef MCU_ESP32 +#ifndef MCU_ESP8266 /* set SCL signal low (actively driven to low) */ GPIO_SET(out_w1tc, out1_w1tc, bus->scl); -#else /* MCU_ESP32 */ +#else /* !MCU_ESP8266 */ #if I2C_CLOCK_STRETCH > 0 /* * set SCL signal low (switch temporarily to GPIO_OD_PU where the @@ -490,35 +490,35 @@ static inline void _i2c_scl_low(_i2c_bus_t* bus) /* No clock stretching supported, always drive the SCL pin. */ GPIO.OUT_CLEAR = bus->scl_bit; #endif /* I2C_CLOCK_STRETCH > 0 */ -#endif /* MCU_ESP32 */ +#endif /* !MCU_ESP8266 */ } static inline void _i2c_sda_high(_i2c_bus_t* bus) { -#ifdef MCU_ESP32 +#ifndef MCU_ESP8266 /* set SDA signal high (pin is in open-drain mode and pulled-up) */ GPIO_SET(out_w1ts, out1_w1ts, bus->sda); -#else /* MCU_ESP32 */ +#else /* !MCU_ESP8266 */ /* * set SDA signal high (switch back to GPIO_IN_PU mode, that is the pin is * in open-drain mode and pulled-up to high) */ GPIO.ENABLE_OUT_CLEAR = bus->sda_bit; -#endif /* MCU_ESP32 */ +#endif /* !MCU_ESP8266 */ } static inline void _i2c_sda_low(_i2c_bus_t* bus) { -#ifdef MCU_ESP32 +#ifndef MCU_ESP8266 /* set SDA signal low (actively driven to low) */ GPIO_SET(out_w1tc, out1_w1tc, bus->sda); -#else /* MCU_ESP32 */ +#else /* !MCU_ESP8266 */ /* * set SDA signal low (switch temporarily to GPIO_OD_PU where the * written output value 0 drives the pin actively to low) */ GPIO.ENABLE_OUT_SET = bus->sda_bit; -#endif /* MCU_ESP32 */ +#endif /* !MCU_ESP8266 */ } static void _i2c_clear(_i2c_bus_t* bus) From 9282e055ae32cedb5944b6b803f6c51efbbd0b36 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 16:49:50 +0100 Subject: [PATCH 05/46] cpu/esp32: ESP32 variant independent makefiles --- cpu/esp32/Makefile.dep | 5 ++ cpu/esp32/Makefile.include | 85 ++++++++++++++++++++------- cpu/esp32/esp-idf/Makefile | 4 +- cpu/esp32/esp-idf/common/Makefile | 87 ++++++++++++++++++++++++++-- cpu/esp32/esp-idf/esp_idf.mk | 51 +++++++++------- cpu/esp32/esp-idf/esp_idf_cflags.mk | 18 +++++- cpu/esp32/esp-idf/nvs_flash/Makefile | 6 ++ cpu/esp32/esp-idf/spi_flash/Makefile | 18 ++++-- cpu/esp32/esp-idf/wifi/Makefile | 3 - 9 files changed, 220 insertions(+), 57 deletions(-) diff --git a/cpu/esp32/Makefile.dep b/cpu/esp32/Makefile.dep index 2c28193b938c..cdfc1ef21762 100644 --- a/cpu/esp32/Makefile.dep +++ b/cpu/esp32/Makefile.dep @@ -5,6 +5,7 @@ include $(RIOTCPU)/esp_common/Makefile.dep USEPKG += esp32_sdk USEMODULE += esp_idf_common +USEMODULE += esp_idf_efuse USEMODULE += esp_bootloader ifneq (,$(filter newlib,$(USEMODULE))) @@ -40,6 +41,10 @@ ifneq (,$(filter esp_wifi_any,$(USEMODULE))) USEMODULE += pthread endif +ifneq (,$(filter esp_hw_counter,$(USEMODULE))) + FEATURES_REQUIRED += esp_hw_counter +endif + ifneq (,$(filter esp_idf_heap,$(USEMODULE))) # The ESP-IDF heap component uses the TLSF implementation that is part of # the component. To avoid conflicts with modules and packages that use the diff --git a/cpu/esp32/Makefile.include b/cpu/esp32/Makefile.include index 2ec31ca5bb9e..b7991075d09c 100644 --- a/cpu/esp32/Makefile.include +++ b/cpu/esp32/Makefile.include @@ -1,9 +1,17 @@ -# ESP32 specific flashing options +# ESP32x specific flashing options FLASH_CHIP = $(CPU) -FLASH_MODE ?= dout -FLASH_FREQ = 40m # DO NOT CHANGE -FLASH_SIZE ?= 4 -BOOTLOADER_POS = 0x1000 +ifneq (,$(filter esp32,$(CPU))) + FLASH_MODE ?= dout + FLASH_FREQ = 40m # DO NOT CHANGE + FLASH_SIZE ?= 4 + BOOTLOADER_POS = 0x1000 +endif +ifneq (,$(filter esp32c3,$(CPU))) + FLASH_MODE ?= dio + FLASH_FREQ = 80m # DO NOT CHANGE + FLASH_SIZE ?= 4 + BOOTLOADER_POS = 0x0000 +endif ESPTOOL ?= $(RIOTTOOLS)/esptools/esptool_v3.2.py @@ -11,7 +19,13 @@ include $(RIOTCPU)/esp_common/Makefile.include # regular Makefile -TARGET_ARCH_$(CPU) ?= xtensa-$(CPU)-elf +ifneq (,$(filter esp32,$(CPU))) + TARGET_ARCH_$(CPU) ?= xtensa-$(CPU)-elf +endif +ifneq (,$(filter esp32c3,$(CPU))) + TARGET_ARCH_$(CPU) ?= riscv32-esp-elf +endif + TARGET_ARCH ?= $(TARGET_ARCH_$(CPU)) CPU_UC = $(shell echo '$(CPU)' | tr '[:lower:]' '[:upper:]') @@ -19,6 +33,7 @@ CPU_UC = $(shell echo '$(CPU)' | tr '[:lower:]' '[:upper:]') PSEUDOMODULES += esp_bootloader PSEUDOMODULES += esp_gdbstub PSEUDOMODULES += esp_hw_counter +PSEUDOMODULES += esp_idf_gpio_hal PSEUDOMODULES += esp_i2c_hw PSEUDOMODULES += esp_jtag PSEUDOMODULES += esp_rtc_timer_32k @@ -28,13 +43,16 @@ PSEUDOMODULES += esp_wifi_enterprise INCLUDES += -I$(RIOTCPU)/$(CPU)/esp-idf/include INCLUDES += -I$(RIOTCPU)/$(CPU)/esp-idf/include/log -INCLUDES += -I$(ESP32_SDK_DIR)/components/ +INCLUDES += -I$(ESP32_SDK_DIR)/components +INCLUDES += -I$(ESP32_SDK_DIR)/components/bootloader_support/include INCLUDES += -I$(ESP32_SDK_DIR)/components/driver/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_common/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/include/soc INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_rom/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_rom/include/$(CPU) +INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_system/include +INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_system/port/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_timer/include INCLUDES += -I$(ESP32_SDK_DIR)/components/hal/$(CPU)/include INCLUDES += -I$(ESP32_SDK_DIR)/components/hal/include @@ -44,15 +62,21 @@ INCLUDES += -I$(ESP32_SDK_DIR)/components/log/include INCLUDES += -I$(ESP32_SDK_DIR)/components/newlib/platform_include INCLUDES += -I$(ESP32_SDK_DIR)/components/soc/include INCLUDES += -I$(ESP32_SDK_DIR)/components/soc/$(CPU)/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/xtensa/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/xtensa/$(CPU)/include + +ifneq (,$(filter riscv32%,$(TARGET_ARCH))) + INCLUDES += -I$(ESP32_SDK_DIR)/components/riscv/include +endif + +ifneq (,$(filter xtensa%,$(TARGET_ARCH))) + INCLUDES += -I$(ESP32_SDK_DIR)/components/xtensa/include + INCLUDES += -I$(ESP32_SDK_DIR)/components/xtensa/$(CPU)/include +endif ifneq (,$(filter esp_spi_ram,$(USEMODULE))) INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/include/soc/$(CPU) endif ifneq (,$(filter esp_idf_spi_flash,$(USEMODULE))) - INCLUDES += -I$(ESP32_SDK_DIR)/components/bootloader_support/include INCLUDES += -I$(ESP32_SDK_DIR)/components/spi_flash/include endif @@ -61,7 +85,6 @@ ifneq (,$(filter esp_wifi_any,$(USEMODULE))) INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_eth/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_event/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_netif/include - INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_system/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_wifi/include INCLUDES += -I$(ESP32_SDK_DIR)/components/nvs_flash/include INCLUDES += -I$(ESP32_SDK_DIR)/components/spi_flash/include @@ -93,28 +116,48 @@ CFLAGS += -Dasm=__asm CFLAGS += -Dtypeof=__typeof__ CFLAGS += -D_CONST=const -LINKFLAGS += -L$(ESP32_SDK_DIR)/components/xtensa/$(CPU) -ARCHIVES += -lxt_hal +# TODO no relaxation yet +ifneq (,$(filter riscv%,$(TARGET_ARCH))) + CFLAGS += -mno-relax -march=rv32imc -mabi=ilp32 -DRISCV_NO_RELAX +endif + +ifneq (,$(filter xtensa%,$(TARGET_ARCH))) + LINKFLAGS += -L$(ESP32_SDK_DIR)/components/xtensa/$(CPU) + ARCHIVES += -lxt_hal +endif LINKFLAGS += -L$(RIOTCPU)/$(CPU)/ld/ +LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/memory.ld +LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/sections.ld LINKFLAGS += -T$(ESP32_SDK_DIR)/components/soc/$(CPU)/ld/$(CPU).peripherals.ld LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/$(CPU)/ld/$(CPU).rom.api.ld LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/$(CPU)/ld/$(CPU).rom.ld -LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/$(CPU)/ld/$(CPU).rom.newlib-data.ld -LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/$(CPU)/ld/$(CPU).rom.newlib-funcs.ld -LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/$(CPU)/ld/$(CPU).rom.newlib-time.ld -LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/$(CPU)/ld/$(CPU).rom.spiflash.ld -LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/$(CPU)/ld/$(CPU).rom.redefined.ld -LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/memory.ld -LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/sections.ld + +ifneq (,$(filter xtensa%,$(TARGET_ARCH))) + LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/$(CPU)/ld/$(CPU).rom.newlib-data.ld + LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/$(CPU)/ld/$(CPU).rom.newlib-funcs.ld + LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/$(CPU)/ld/$(CPU).rom.newlib-time.ld + LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/$(CPU)/ld/$(CPU).rom.spiflash.ld +endif + +ifneq (,$(filter riscv%,$(TARGET_ARCH))) + LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/esp32c3/ld/esp32c3.rom.libgcc.ld + LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld + LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/esp32c3/ld/esp32c3.rom.version.ld + LINKFLAGS += -T$(ESP32_SDK_DIR)/components/esp_rom/esp32c3/ld/esp32c3.rom.eco3.ld +endif + LINKFLAGS += -nostdlib -lgcc -Wl,-gc-sections # Libraries needed when using esp_wifi_any pseudomodule ifneq (,$(filter esp_wifi_any,$(USEMODULE))) LINKFLAGS += -L$(ESP32_SDK_LIB_WIFI_DIR)/$(CPU) LINKFLAGS += -L$(ESP32_SDK_LIB_PHY_DIR)/$(CPU) - ARCHIVES += -lcore -lrtc -lnet80211 -lpp -lcoexist + ARCHIVES += -lcoexist -lcore -lmesh -lnet80211 -lpp ARCHIVES += -lphy -lstdc++ + ifneq (,$(filter esp32,$(CPU))) + ARCHIVES += -lrtc + endif endif # Libraries needed when using esp_now module diff --git a/cpu/esp32/esp-idf/Makefile b/cpu/esp32/esp-idf/Makefile index 89fee493226b..d11426322205 100644 --- a/cpu/esp32/esp-idf/Makefile +++ b/cpu/esp32/esp-idf/Makefile @@ -2,7 +2,9 @@ MODULE=esp_idf # Add a list of subdirectories, that should also be built: -DIRS += common +ifneq (,$(filter esp_idf_common,$(USEMODULE))) + DIRS += common +endif ifneq (,$(filter esp_idf_efuse,$(USEMODULE))) DIRS += efuse diff --git a/cpu/esp32/esp-idf/common/Makefile b/cpu/esp32/esp-idf/common/Makefile index 80e3c7a74df8..57686c0545e2 100644 --- a/cpu/esp32/esp-idf/common/Makefile +++ b/cpu/esp32/esp-idf/common/Makefile @@ -2,32 +2,107 @@ MODULE = esp_idf_common # source files required from ESP-IDF in any case, regardless of additional modules ESP32_SDK_SRC = \ + components/bootloader_support/src/bootloader_flash_config_$(CPU).c \ + components/bootloader_support/src/bootloader_flash.c \ + components/bootloader_support/src/bootloader_efuse_$(CPU).c \ + components/bootloader_support/src/bootloader_mem.c \ + components/bootloader_support/src/bootloader_random_$(CPU).c \ components/driver/periph_ctrl.c \ components/esp_hw_support/cpu_util.c \ - components/esp_hw_support/sleep_modes.c \ - components/esp_hw_support/port/$(CPU)/rtc_sleep.c \ components/esp_hw_support/esp_clk.c \ components/esp_hw_support/port/$(CPU)/rtc_clk.c \ components/esp_hw_support/port/$(CPU)/rtc_clk_init.c \ components/esp_hw_support/port/$(CPU)/rtc_init.c \ + components/esp_hw_support/port/$(CPU)/rtc_sleep.c \ components/esp_hw_support/port/$(CPU)/rtc_time.c \ - components/esp_hw_support/port/$(CPU)/rtc_wdt.c \ components/esp_hw_support/regi2c_ctrl.c \ + components/esp_hw_support/sleep_modes.c \ components/esp_pm/pm_impl.c \ + components/esp_rom/patches/esp_rom_uart.c \ components/esp_system/esp_err.c \ components/esp_system/esp_system.c \ + components/esp_system/port/cpu_start.c \ + components/esp_system/port/soc/$(CPU)/cache_err_int.c \ components/esp_system/port/soc/$(CPU)/clk.c \ components/esp_system/port/soc/$(CPU)/reset_reason.c \ components/esp_system/system_time.c \ + components/esp_timer/src/esp_timer.c \ + components/esp_timer/src/system_time.c \ + components/hal/cpu_hal.c \ components/hal/mpu_hal.c \ + components/hal/timer_hal.c \ + components/hal/uart_hal.c \ components/hal/wdt_hal_iram.c \ components/newlib/port/esp_time_impl.c \ - components/soc/$(CPU)/rtc_io_periph.c \ components/spi_flash/cache_utils.c \ - components/esp_timer/src/esp_timer.c \ - components/esp_timer/src/esp_timer_impl_frc_legacy.c \ + components/spi_flash/flash_ops.c \ # +ifneq (,$(filter periph_adc periph_dac,$(USEMODULE))) + ESP32_SDK_SRC += components/hal/rtc_io_hal.c +endif + +# TODO separate module +ifneq (,$(filter periph_can,$(USEMODULE))) + ESP32_SDK_SRC += components/hal/twai_hal.c + ESP32_SDK_SRC += components/hal/twai_hal_iram.c +endif + +# TODO separate module +ifneq (,$(filter periph_dac,$(USEMODULE))) + ESP32_SDK_SRC += components/driver/dac_common.c + ESP32_SDK_SRC += components/soc/$(CPU)/dac_periph.c +endif + +# TODO separate module +ifneq (,$(filter periph_hwrng,$(USEMODULE))) + ESP32_SDK_SRC += components/esp_hw_support/hw_random.c +endif + +# TODO separate module +ifneq (,$(filter periph_i2c%,$(USEMODULE))) + ESP32_SDK_SRC += components/driver/i2c.c + ESP32_SDK_SRC += components/hal/i2c_hal.c + ESP32_SDK_SRC += components/hal/i2c_hal_iram.c + ESP32_SDK_SRC += components/soc/$(CPU)/i2c_periph.c +endif + +# TODO separate module +ifneq (,$(filter periph_pwm%,$(USEMODULE))) + ESP32_SDK_SRC += components/hal/ledc_hal.c + ESP32_SDK_SRC += components/hal/ledc_hal_iram.c + ESP32_SDK_SRC += components/soc/$(CPU)/ledc_periph.c +endif + +# TODO separate module +ifneq (,$(filter periph_spi,$(USEMODULE))) + ESP32_SDK_SRC += components/hal/spi_hal.c + ESP32_SDK_SRC += components/soc/$(CPU)/spi_periph.c +endif + +ifneq (,$(filter xtensa%,$(TARGET_ARCH))) + ESP32_SDK_SRC += components/esp_hw_support/port/$(CPU)/rtc_wdt.c + ESP32_SDK_SRC += components/soc/$(CPU)/rtc_io_periph.c +endif + +ifneq (,$(filter riscv%,$(TARGET_ARCH))) + ESP32_SDK_SRC += components/riscv/interrupt.c + ESP32_SDK_ASMSRC += components/freertos/port/riscv/portasm.S + ESP32_SDK_ASMSRC += components/riscv/vectors.S +endif + +ifneq (,$(filter esp32,$(CPU))) + ESP32_SDK_SRC += components/esp_timer/src/esp_timer_impl_frc_legacy.c +endif + +ifneq (,$(filter esp32c3,$(CPU))) + ESP32_SDK_SRC += components/esp_hw_support/port/$(CPU)/cpu_util_$(CPU).c + ESP32_SDK_SRC += components/esp_hw_support/sleep_retention.c + ESP32_SDK_SRC += components/esp_timer/src/esp_timer_impl_systimer.c + ESP32_SDK_SRC += components/hal/$(CPU)/rtc_cntl_hal.c + ESP32_SDK_SRC += components/hal/systimer_hal.c +endif + include $(RIOTBASE)/Makefile.base ESP32_SDK_BIN = $(BINDIR)/$(MODULE) diff --git a/cpu/esp32/esp-idf/esp_idf.mk b/cpu/esp32/esp-idf/esp_idf.mk index 9f32cf23c6dc..2912aa755638 100644 --- a/cpu/esp32/esp-idf/esp_idf.mk +++ b/cpu/esp32/esp-idf/esp_idf.mk @@ -1,33 +1,30 @@ # common definitions for all ESP-IDF modules +# additional include pathes required by als ESP-IDF module INCLUDES += -I$(ESP32_SDK_DIR)/components/bootloader_support/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/driver/esp32/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/driver/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/efuse/esp32/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_common/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/include/soc -INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/port/esp32 -INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/port/esp32/private_include +INCLUDES += -I$(ESP32_SDK_DIR)/components/bootloader_support/include_bootloader +INCLUDES += -I$(ESP32_SDK_DIR)/components/driver/$(CPU)/include +INCLUDES += -I$(ESP32_SDK_DIR)/components/efuse/include +INCLUDES += -I$(ESP32_SDK_DIR)/components/efuse/$(CPU)/include +INCLUDES += -I$(ESP32_SDK_DIR)/components/efuse/$(CPU)/private_include +INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/port/$(CPU) +INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/port/$(CPU)/private_include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_ipc/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_pm/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_rom/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_rom/include/esp32 -INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_system/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_system/port/public_compat INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_timer/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_timer/private_include -INCLUDES += -I$(ESP32_SDK_DIR)/components/hal/esp32/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/hal/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/hal/platform_port/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/heap/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/log/include INCLUDES += -I$(ESP32_SDK_DIR)/components/newlib/priv_include -INCLUDES += -I$(ESP32_SDK_DIR)/components/soc/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/soc/esp32/include INCLUDES += -I$(ESP32_SDK_DIR)/components/spi_flash/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/xtensa/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/xtensa/esp32/include + +ifneq (,$(filter xtensa%,$(TARGET_ARCH))) + INCLUDES += -I$(ESP32_SDK_DIR)/components/xtensa/include + INCLUDES += -I$(ESP32_SDK_DIR)/components/xtensa/$(CPU)/include +endif + +ifneq (,$(filter esp32c3 esp32h2 esp32s3,$(CPU))) + INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/port/$(CPU)/private_include +endif SRC := $(addprefix $(ESP32_SDK_DIR)/,$(ESP32_SDK_SRC)) SRCXX := $(addprefix $(ESP32_SDK_DIR)/,$(ESP32_SDK_SRCXX)) @@ -36,7 +33,7 @@ OBJC_LTO := $(ESP32_SDK_SRC:%.c=$(ESP32_SDK_BIN)/%.o) OBJC_NOLTO := $(ESP32_SDK_SRC_NOLTO:%.c=$(ESP32_SDK_BIN)/%.o) OBJC := $(OBJC_NOLTO) $(OBJC_LTO) OBJCXX := $(ESP32_SDK_SRCXX:%.$(SRCXXEXT)=$(ESP32_SDK_BIN)/%.o) -ASMOBJ := $(ESP32_SDK_ASMSRC:%.s=$(ESP32_SDK_BIN)/%.o) +ASMOBJ := $(ESP32_SDK_ASMSRC:%.S=$(ESP32_SDK_BIN)/%.o) OBJ := $(OBJC) $(OBJCXX) $(ASMOBJ) $(ASSMOBJ) $(GENOBJC) DEP := $(OBJC:.o=.d) $(OBJCXX:.o=.d) $(ASSMOBJ:.o=.d) @@ -70,4 +67,16 @@ ifneq (,$(SHOULD_RUN_KCONFIG)) $(Q)mv $(@:.o=.tmp) $(@:.o=.d) endif +$(ASMOBJ): $(BINDIR)/$(MODULE)/%.o: $(ESP32_SDK_DIR)/%.S $(OBJ_DEPS) \ + | $(if $(SHOULD_RUN_KCONFIG),$(KCONFIG_GENERATED_AUTOCONF_HEADER_C)) + $(Q)mkdir -p $(dir $@) + $(Q)$(CCACHE) $(CC) \ + -DRIOT_FILE_RELATIVE=\"$(patsubst $(RIOTBASE)/%,%,$(abspath $<))\" \ + -DRIOT_FILE_NOPATH=\"$(notdir $<)\" \ + $(CFLAGS) $(INCLUDES) -MQ '$@' -MD -MP -c $(abspath $<) -o $@ +ifneq (,$(SHOULD_RUN_KCONFIG)) + $(Q)$(FIXDEP) $(@:.o=.d) $@ $(KCONFIG_SYNC_DIR) > $(@:.o=.tmp) + $(Q)mv $(@:.o=.tmp) $(@:.o=.d) +endif + -include $(DEP) diff --git a/cpu/esp32/esp-idf/esp_idf_cflags.mk b/cpu/esp32/esp-idf/esp_idf_cflags.mk index 74e100664476..3e7ac6b896a4 100644 --- a/cpu/esp32/esp-idf/esp_idf_cflags.mk +++ b/cpu/esp32/esp-idf/esp_idf_cflags.mk @@ -16,11 +16,27 @@ CFLAGS += -Wno-implicit-function-declaration # required for esp_wifi (components/esp_event/esp_event.c) CFLAGS += -Wno-old-style-declaration -# required for esp-wifi (components/efuse/esp32/esp_efuse_utility.c) +# required for esp_wifi (components/efuse/esp32/esp_efuse_utility.c) # required for esp_idf_heap (components/heap/multi_heap.c) # required for esp_idf_wpa_supplicant CFLAGS += -Wno-old-style-definition +# required for esp_idf_common (components/bootloader_support/src/bootloader_flash.c) +CFLAGS += -Wno-unused-variable + +# required for esp_idf_spi_flash (components/spi_flash/partition.c) +CFLAGS += -Wno-enum-compare + # vendor code contains casts that increase alignment requirements. Let's hope # those are false positives. CFLAGS += -Wno-cast-align + +# additional CFLAGS required for RISC-V architecture +ifneq (,$(filter riscv32%,$(TARGET_ARCH))) + INCLUDES += -I$(ESP32_SDK_DIR)/components/riscv/include + CFLAGS += -DCONFIG_IDF_TARGET_ARCH_RISCV + CFLAGS += -march=rv32imc + CFLAGS += -Wno-error=format= + CFLAGS += -nostartfiles + CFLAGS += -Wno-format +endif diff --git a/cpu/esp32/esp-idf/nvs_flash/Makefile b/cpu/esp32/esp-idf/nvs_flash/Makefile index 111ed1c54261..f7fbae5155e7 100644 --- a/cpu/esp32/esp-idf/nvs_flash/Makefile +++ b/cpu/esp32/esp-idf/nvs_flash/Makefile @@ -28,3 +28,9 @@ include ../esp_idf.mk # vendor code contains casts that increase alignment requirements. Let's hope # those are false positives. CFLAGS += -Wno-cast-align + +# additional CFLAGS required for RISC-V architecture +ifneq (,$(filter riscv32%,$(TARGET_ARCH))) + CFLAGS += -Wno-error=format= + CFLAGS += -Wno-format +endif diff --git a/cpu/esp32/esp-idf/spi_flash/Makefile b/cpu/esp32/esp-idf/spi_flash/Makefile index de77e18bd405..ba4c6bedaf58 100644 --- a/cpu/esp32/esp-idf/spi_flash/Makefile +++ b/cpu/esp32/esp-idf/spi_flash/Makefile @@ -3,16 +3,26 @@ MODULE = esp_idf_spi_flash # source files to be compiled for this module ESP32_SDK_SRC = \ components/bootloader_support/src/bootloader_common.c \ - components/bootloader_support/src/bootloader_efuse_$(CPU).c \ - components/bootloader_support/src/bootloader_flash_config_$(CPU).c \ components/driver/spi_common.c \ - components/soc/$(CPU)/spi_periph.c \ + components/spi_flash/$(CPU)/flash_ops_$(CPU).c \ components/spi_flash/$(CPU)/spi_flash_rom_patch.c \ - components/spi_flash/flash_ops.c \ + components/spi_flash/esp_flash_api.c \ + components/spi_flash/partition.c \ # +ifeq (,$(filter periph_spi,$(USEMODULE))) + # no need to compile it here if it is already compiled for periph_spi + ESP32_SDK_SRC += components/soc/$(CPU)/spi_periph.c +endif + +ifneq (,$(filter esp32,$(CPU))) + ESP32_SDK_SRC += components/spi_flash/flash_mmap.c +endif + # additional include pathes required by this module +INCLUDES += -I$(ESP32_SDK_DIR)/components/app_update/include INCLUDES += -I$(ESP32_SDK_DIR)/components/bootloader_support/include_bootloader +INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_rom/$(CPU) INCLUDES += -I$(ESP32_SDK_DIR)/components/spi_flash/include/spi_flash include $(RIOTBASE)/Makefile.base diff --git a/cpu/esp32/esp-idf/wifi/Makefile b/cpu/esp32/esp-idf/wifi/Makefile index a2759bc42d83..d1efdfacd60e 100644 --- a/cpu/esp32/esp-idf/wifi/Makefile +++ b/cpu/esp32/esp-idf/wifi/Makefile @@ -2,10 +2,7 @@ MODULE = esp_idf_wifi # source files to be compiled for this module ESP32_SDK_SRC = \ - components/driver/adc_common.c \ - components/driver/rtc_module.c \ components/esp_event/event_send.c \ - components/esp_hw_support/hw_random.c \ components/esp_hw_support/port/$(CPU)/dport_access.c \ components/esp_phy/src/phy_init.c \ components/esp_wifi/$(CPU)/esp_adapter.c \ From 4a286c50e9e8a17167b044723d6a72cba92e2262 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 16:50:33 +0100 Subject: [PATCH 06/46] cpu/esp_common: ESP32 variant independent makefiles --- cpu/esp_common/Makefile | 5 ++++- cpu/esp_common/Makefile.dep | 4 +++- cpu/esp_common/Makefile.include | 18 ++++++++++-------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/cpu/esp_common/Makefile b/cpu/esp_common/Makefile index 98aa75ff8e7a..a22cd8e91134 100644 --- a/cpu/esp_common/Makefile +++ b/cpu/esp_common/Makefile @@ -1,6 +1,9 @@ # add a list of subdirectories, that should also be build DIRS += periph -DIRS += vendor + +ifneq (,$(filter xtensa%,$(TARGET_ARCH))) + DIRS += vendor +endif ifneq (,$(filter esp_freertos_common,$(USEMODULE))) DIRS += freertos diff --git a/cpu/esp_common/Makefile.dep b/cpu/esp_common/Makefile.dep index 240c01e6211f..0d835404cb13 100644 --- a/cpu/esp_common/Makefile.dep +++ b/cpu/esp_common/Makefile.dep @@ -20,7 +20,9 @@ ifeq (,$(filter stdio_% slipdev_stdio,$(USEMODULE))) USEMODULE += stdio_uart endif -USEMODULE += xtensa +ifneq (,$(filter esp8266 esp32 esp32s%,$(CPU))) + USEMODULE += xtensa +endif # Features used by ESP* diff --git a/cpu/esp_common/Makefile.include b/cpu/esp_common/Makefile.include index 33c466081e12..df767a915d84 100644 --- a/cpu/esp_common/Makefile.include +++ b/cpu/esp_common/Makefile.include @@ -27,9 +27,16 @@ INCLUDES += -I$(RIOTCPU)/esp_common/vendor/esp # Flags -CFLAGS += -Wno-unused-parameter -Wformat=0 -CFLAGS += -mlongcalls -mtext-section-literals -fstrict-volatile-bitfields -CFLAGS += -fdata-sections -ffunction-sections -fzero-initialized-in-bss +CFLAGS += -Wno-unused-parameter +CFLAGS += -Wformat=0 +CFLAGS += -fstrict-volatile-bitfields +CFLAGS += -fdata-sections +CFLAFS += -ffunction-sections +CFLAGS += -fzero-initialized-in-bss + +ifeq (,$(filter esp32c% esp32h%,$(CPU))) + CFLAGS += -mlongcalls -mtext-section-literals +endif OPTIONAL_CFLAGS_BLACKLIST += -Wformat-overflow OPTIONAL_CFLAGS_BLACKLIST += -Wformat-truncation @@ -88,11 +95,6 @@ CFLAGS += $(if $(findstring dout,$(FLASH_MODE)),-DFLASH_MODE_DOUT=1) ARCHIVES += -lg -lc LINKFLAGS += $(CFLAGS_OPT) $(CFLAGS_DBG) -#ifneq ($(CPU),esp8266) -# esp8266 flags are added by the SDK pkg in pkg/esp8266_sdk -#LINKFLAGS += -L$(ESP_SDK_DIR)/components/$(CPU) -#LINKFLAGS += -L$(ESP_SDK_DIR)/components/$(CPU)/lib -#endif LINKFLAGS += -nostdlib -Wl,-gc-sections -Wl,-static # use the wrapper functions for calloc to add correct overflow detection missing From 2eb98994fe64dcf5587600b2d40d8bab87c060ab Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 16:58:51 +0100 Subject: [PATCH 07/46] cpu/esp32: replace startup by architecture dependent ESP-IDF startup --- cpu/esp32/startup.c | 217 +++++++++++--------------------------------- 1 file changed, 53 insertions(+), 164 deletions(-) diff --git a/cpu/esp32/startup.c b/cpu/esp32/startup.c index f2425b354c8c..47e42b0c98f2 100644 --- a/cpu/esp32/startup.c +++ b/cpu/esp32/startup.c @@ -45,24 +45,33 @@ /* ESP-IDF headers */ #include "driver/periph_ctrl.h" #include "esp_attr.h" +#include "esp_clk_internal.h" #include "esp_heap_caps_init.h" #include "esp_log.h" +#include "esp_private/startup_internal.h" +#include "esp_private/esp_clk.h" +#include "esp_rom_uart.h" #include "esp_sleep.h" #include "esp_timer.h" +#include "hal/interrupt_controller_types.h" +#include "hal/interrupt_controller_ll.h" #include "rom/cache.h" #include "rom/ets_sys.h" #include "rom/rtc.h" #include "rom/uart.h" #include "soc/apb_ctrl_reg.h" #include "soc/cpu.h" -#include "soc/dport_reg.h" -#include "soc/dport_access.h" #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" #include "soc/rtc_cntl_struct.h" #include "soc/timer_group_struct.h" + +#if __xtensa__ +#include "soc/dport_reg.h" +#include "soc/dport_access.h" #include "xtensa/core-macros.h" #include "xtensa/xtensa_api.h" +#endif #if IS_USED(MODULE_ESP_SPI_RAM) #include "spiram.h" @@ -101,70 +110,46 @@ extern uint8_t _rtc_bss_rtc_end; extern uint8_t _iram_start; /* external esp function declarations */ -extern void esp_clk_init(void); -extern void esp_perip_clk_init(void); -extern void esp_reent_init(struct _reent* r); extern uint32_t hwrand (void); -extern void bootloader_clock_configure(void); - -/* external RTC function declarations since they are not declared in headers */ -/* components/esp_hw_support/include/esp_private/esp_clk.h */ -extern int esp_clk_apb_freq(void); -extern int esp_clk_cpu_freq(void); -extern int esp_clk_xtal_freq(void); -extern uint32_t esp_clk_slowclk_cal_get(void); -/* components/esp_hw_support/include/soc/esp32/rtc.h */ -extern uint64_t esp_rtc_get_time_us(void); - -/* components/esp_system/port/include/esp_clk_internal.h */ -extern void IRAM_ATTR rtc_clk_select_rtc_slow_clk(rtc_slow_freq_t slow_clk); /* forward declarations */ -static void system_init(void); -static void intr_matrix_clear(void); - -typedef int32_t esp_err_t; +static void IRAM system_startup_cpu0(void); +static void IRAM system_init(void); +extern void IRAM_ATTR thread_yield_isr(void* arg); uint64_t g_startup_time = 0; +const sys_startup_fn_t g_startup_fn[1] = { system_startup_cpu0 }; + +#if CONFIG_ESP_TIMER_IMPL_FRC2 +/* dummy function required if FRC2 (legacy) timer of the ESP32 is used */ +esp_err_t esp_timer_impl_early_init(void) +{ + return ESP_OK; +} +#endif /** - * @brief CPU startup function + * @brief System startup function * * This function is the entry point in the user application. It is called - * after a system reset to startup the system. + * after a CPU initialization to startup the system. */ -NORETURN void IRAM call_start_cpu0 (void) +static NORETURN void IRAM system_startup_cpu0(void) { +#if __xtensa__ register uint32_t *sp __asm__ ("a1"); (void)sp; - - esp_cpu_configure_region_protection(); - - /* move exception vectors to IRAM */ - asm volatile ("wsr %0, vecbase\n" ::"r"(&_iram_start)); - - RESET_REASON reset_reason = rtc_get_reset_reason(PRO_CPU_NUM); - - /* reset from panic handler by RWDT or TG0WDT */ - if (reset_reason == RTCWDT_SYS_RESET || reset_reason == TG0WDT_SYS_RESET) { - /* TODO esp_panic_wdt_stop was called here in former versions */ - } - -#ifdef MODULE_PUF_SRAM - puf_sram_init((uint8_t *)&_sheap, SEED_RAM_LEN); +#endif +#if __riscv + register uint32_t *sp __asm__ ("x2"); (void)sp; #endif - /* Clear BSS. Please do not attempt to do any complex stuff */ - /* (like early logging) before this. */ - /* cppcheck-suppress comparePointers */ - memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); + /* initialize stdio */ + esp_rom_uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM); + stdio_init(); - /* if we are not waking up from deep sleep, clear RTC bss */ - if (reset_reason != DEEPSLEEP_RESET) { - /* cppcheck-suppress comparePointers */ - memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start)); - } + RESET_REASON reset_reason = rtc_get_reset_reason(PRO_CPU_NUM); - /* initialize RTC data after power on */ + /* initialize RTC data after power on or RTC WDT reset */ if (reset_reason == POWERON_RESET || reset_reason == RTCWDT_RTC_RESET) { /* cppcheck-suppress comparePointers */ memset(&_rtc_bss_rtc_start, 0, (&_rtc_bss_rtc_end - &_rtc_bss_rtc_start)); @@ -174,8 +159,7 @@ NORETURN void IRAM call_start_cpu0 (void) cpuid_get ((void*)cpu_id); #if IS_USED(MODULE_ESP_LOG_STARTUP) - ets_printf("\n"); - LOG_STARTUP("Starting ESP32 with ID: "); + LOG_STARTUP("\nStarting ESP32x with ID: "); for (unsigned i = 0; i < CPUID_LEN; i++) { ets_printf("%02x", cpu_id[i]); } @@ -211,132 +195,47 @@ NORETURN void IRAM call_start_cpu0 (void) LOG_STARTUP("PRO cpu is up (single core mode, only PRO cpu is used)\n"); - /* disable APP cpu */ - DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); - - if (IS_ACTIVE(MODULE_ESP_IDF_HEAP)) { - /* init heap */ - heap_caps_init(); - if (IS_ACTIVE(ENABLE_DEBUG)) { - ets_printf("Heap free: %u byte\n", get_free_heap_size()); - } - } - - /* init SPI RAM if enabled */ -#if CONFIG_SPIRAM_SUPPORT && CONFIG_SPIRAM_BOOT_INIT - if (esp_spiram_init() != ESP_OK) { - LOG_STARTUP("Failed to initialize SPI RAM\n"); - exit(1); +#if IS_USED(MODULE_ESP_IDF_HEAP) + /* init heap */ + heap_caps_init(); + if (IS_ACTIVE(ENABLE_DEBUG)) { + ets_printf("Heap free: %u byte\n", get_free_heap_size()); } #endif + /* init esp_timer implementation */ + esp_timer_early_init(); + LOG_STARTUP("PRO cpu starts user code\n"); system_init(); UNREACHABLE(); } -static void IRAM system_clk_init (void) -{ - /* first initialize RTC with default configuration */ - rtc_config_t rtc_cfg = RTC_CONFIG_DEFAULT(); - rtc_init_module(rtc_cfg); - - /* configure main crystal frequency if necessary */ - if (CONFIG_ESP32_XTAL_FREQ != RTC_XTAL_FREQ_AUTO && - CONFIG_ESP32_XTAL_FREQ != rtc_clk_xtal_freq_get()) { - bootloader_clock_configure(); - } - - /* set FAST_CLK to internal low power clock of 8 MHz */ - rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M); - -#if IS_USED(MODULE_ESP_RTC_TIMER_32K) - /* set SLOW_CLK to external 32.768 kHz crystal clock */ - rtc_clk_select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL); -#else - /* set SLOW_CLK to internal low power clock of 150 kHz */ - rtc_clk_32k_enable(false); - rtc_clk_select_rtc_slow_clk(RTC_SLOW_FREQ_RTC); -#endif - - LOG_STARTUP("Switching system clocks can lead to some unreadable characters\n"); - - /* wait until UART is idle to avoid losing output */ - uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM); - - /* determine configured CPU clock frequency from sdk_conf.h */ - rtc_cpu_freq_t freq; - switch (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) { - case 40: freq = RTC_CPU_FREQ_XTAL; /* derived from external crystal */ - break; /* normally 40 MHz */ - case 80: freq = RTC_CPU_FREQ_80M; /* derived from PLL */ - break; - case 160: freq = RTC_CPU_FREQ_160M; /* derived from PLL */ - break; - case 240: freq = RTC_CPU_FREQ_240M; /* derived from PLL */ - break; - default: freq = RTC_CPU_FREQ_2M; /* frequencies <= 8 MHz are - set to 2 MHz and handled later */ - } - - uint32_t freq_before = esp_clk_cpu_freq() / MHZ; - - if (freq_before != CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) { - rtc_cpu_freq_config_t clk_cfg; - rtc_clk_cpu_freq_to_config(freq, &clk_cfg); - - /* set configured CPU frequency */ - rtc_clk_cpu_freq_set_config(&clk_cfg); - - /* Recalculate the ccount to make time calculation correct. */ - uint32_t freq_after = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; - XTHAL_SET_CCOUNT( XTHAL_GET_CCOUNT() * freq_after / freq_before ); - } -} - -extern void IRAM_ATTR thread_yield_isr(void* arg); - static NORETURN void IRAM system_init (void) { +#if defined(MCU_ESP32) /* enable cached read from flash */ Cache_Read_Enable(PRO_CPU_NUM); +#endif /* initialize the ISR stack for usage measurements */ thread_isr_stack_init(); - /* initialize clocks (CPU_CLK, APB_CLK, SLOW and FAST) */ - system_clk_init(); - - /* disable clocks of peripherals that are not needed at startup */ - esp_perip_clk_init(); - g_startup_time = esp_rtc_get_time_us(); - - /* set configured console UART baudrate */ - const int uart_clk_freq = rtc_clk_apb_freq_get(); - uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM); - uart_div_modify(CONFIG_CONSOLE_UART_NUM, - (uart_clk_freq << 4) / STDIO_UART_BAUDRATE); - - /* initialize system call tables of ESP32 rom and newlib */ + /* initialize system call tables of ESP32x rom and newlib */ syscalls_init(); /* install exception handlers */ init_exceptions(); - /* clear interrupt matrix */ - intr_matrix_clear(); - /* systemwide UART initialization */ extern void uart_system_init (void); uart_system_init(); - /* Disable the hold flag of all RTC GPIO pins */ - RTCCNTL.hold_force.val = 0; - /* set log levels for SDK library outputs */ extern void esp_log_level_set(const char* tag, esp_log_level_t level); esp_log_level_set("wifi", LOG_DEBUG); + esp_log_level_set("gpio", LOG_DEBUG); /* init watchdogs */ system_wdt_init(); @@ -359,10 +258,9 @@ static NORETURN void IRAM system_init (void) rtc_clk_slow_freq_get_hz()); LOG_STARTUP("XTAL calibration value: %d\n", esp_clk_slowclk_cal_get()); LOG_STARTUP("Heap free: %u bytes\n", get_free_heap_size()); - uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM); - /* initialize stdio */ - stdio_init(); + /* initialize architecture specific interrupt handling */ + esp_irq_init(); /* disable buffering in stdio */ setvbuf(_stdout_r(_REENT), NULL, _IONBF, 0); @@ -398,8 +296,8 @@ static NORETURN void IRAM system_init (void) /* route a software interrupt source to CPU as trigger for thread yields */ intr_matrix_set(PRO_CPU_NUM, ETS_FROM_CPU_INTR0_SOURCE, CPU_INUM_SOFTWARE); /* set thread yield handler and enable the software interrupt */ - xt_set_interrupt_handler(CPU_INUM_SOFTWARE, thread_yield_isr, NULL); - xt_ints_on(BIT(CPU_INUM_SOFTWARE)); + intr_cntrl_ll_set_int_handler(CPU_INUM_SOFTWARE, thread_yield_isr, NULL); + intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_SOFTWARE)); /* initialize ESP system event loop */ extern void esp_event_handler_init(void); @@ -411,19 +309,10 @@ static NORETURN void IRAM system_init (void) /* starting RIOT */ #if IS_USED(MODULE_ESP_LOG_STARTUP) LOG_STARTUP("Starting RIOT kernel on PRO cpu\n"); - uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM); + esp_rom_uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM); #else puts(""); #endif kernel_init(); UNREACHABLE(); } - -static void intr_matrix_clear(void) -{ - /* attach all peripheral interrupt sources (Technical Reference, Table 7) */ - /* to an arbitrary CPU interrupt number (Technical Reference, Table 8) */ - for (int i = ETS_WIFI_MAC_INTR_SOURCE; i <= ETS_CACHE_IA_INTR_SOURCE; i++) { - intr_matrix_set(PRO_CPU_NUM, i, ETS_INVALID_INUM); - } -} From 7d6e417a1d29ddb1aec5556ac4ce7da46aa271d4 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 17:01:14 +0100 Subject: [PATCH 08/46] cpu/esp32: ESP32 variant independent irq_arch implementation --- cpu/esp32/include/irq_arch.h | 9 +- cpu/esp32/irq_arch.c | 206 ++++++++++++++++++++++++++++------- cpu/esp_common/irq_arch.c | 24 ++-- 3 files changed, 191 insertions(+), 48 deletions(-) diff --git a/cpu/esp32/include/irq_arch.h b/cpu/esp32/include/irq_arch.h index 2122a2cf8a8b..d4cf08109b9a 100644 --- a/cpu/esp32/include/irq_arch.h +++ b/cpu/esp32/include/irq_arch.h @@ -39,15 +39,22 @@ extern "C" { #define CPU_INUM_GPIO 2 /**< Level interrupt with low priority 1 */ #define CPU_INUM_CAN 3 /**< Level interrupt with low priority 1 */ #define CPU_INUM_UART 5 /**< Level interrupt with low priority 1 */ -#define CPU_INUM_RTC 9 /**< Level interrupt with low priority 1 */ +#define CPU_INUM_RTT 9 /**< Level interrupt with low priority 1 */ #define CPU_INUM_I2C 12 /**< Level interrupt with low priority 1 */ #define CPU_INUM_WDT 13 /**< Level interrupt with low priority 1 */ #define CPU_INUM_SOFTWARE 17 /**< Level interrupt with low priority 1 */ #define CPU_INUM_ETH 18 /**< Level interrupt with low priority 1 */ #define CPU_INUM_TIMER 19 /**< Level interrupt with medium priority 2 */ #define CPU_INUM_FRC2 20 /**< Level interrupt with medium priority 2 */ +#define CPU_INUM_SYSTIMER 20 /**< Level interrupt with medium priority 2 */ +#define CPU_INUM_CACHEERR 25 /**< Level interrupt with high priority 4 */ /** @} */ +/** + * @brief Initialize architecture specific interrupt handling + */ +void esp_irq_init(void); + #ifdef __cplusplus } #endif diff --git a/cpu/esp32/irq_arch.c b/cpu/esp32/irq_arch.c index e7b86e33ca70..541f55555600 100644 --- a/cpu/esp32/irq_arch.c +++ b/cpu/esp32/irq_arch.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2022 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 @@ -19,58 +19,106 @@ */ #include "irq_arch.h" + +#include "esp_attr.h" #include "esp_err.h" -#include "esp32/rom/ets_sys.h" +#include "freertos/FreeRTOS.h" +#include "hal/interrupt_controller_types.h" +#include "hal/interrupt_controller_ll.h" +#include "rom/ets_sys.h" +#include "soc/periph_defs.h" +#include "esp_intr_alloc.h" + +#if __xtensa__ #include "soc/dport_reg.h" #include "xtensa/xtensa_api.h" +#endif #define ENABLE_DEBUG 0 #include "debug.h" -struct _irq_alloc_table_t { +#ifndef ETS_CAN_INTR_SOURCE +#define ETS_CAN_INTR_SOURCE ETS_TWAI_INTR_SOURCE +#endif + +typedef struct intr_handle_data_t { int src; /* peripheral interrupt source */ uint32_t intr; /* interrupt number */ + uint8_t level; +} intr_handle_data_t; + +/* TODO change to a clearer approach */ +static struct intr_handle_data_t _irq_data_table[] = { + { ETS_FROM_CPU_INTR0_SOURCE, CPU_INUM_SOFTWARE, 1 }, + { ETS_TG0_WDT_LEVEL_INTR_SOURCE, CPU_INUM_WDT, 1 }, + { ETS_TG0_T0_LEVEL_INTR_SOURCE, CPU_INUM_RTT, 1 }, +#if defined(MCU_ESP32) || defined(MCU_ESP32S2) || defined(MCU_ESP32S3) + { ETS_TG0_T1_LEVEL_INTR_SOURCE, CPU_INUM_TIMER, 2 }, +#endif +#if defined(MCU_ESP32) || defined(MCU_ESP32S2) + { ETS_TG0_LACT_LEVEL_INTR_SOURCE, CPU_INUM_TIMER, 2 }, +#endif +#if !defined(MCU_ESP32C2) + { ETS_TG1_T0_LEVEL_INTR_SOURCE, CPU_INUM_TIMER, 2 }, +#endif +#if defined(MCU_ESP32) || defined(MCU_ESP32S2) || defined(MCU_ESP32S3) + { ETS_TG1_T1_LEVEL_INTR_SOURCE, CPU_INUM_TIMER, 2 }, +#endif + { ETS_UART0_INTR_SOURCE, CPU_INUM_UART, 1 }, + { ETS_UART1_INTR_SOURCE, CPU_INUM_UART, 1 }, +#if defined(MCU_ESP32) || defined(MCU_ESP32S2) || defined(MCU_ESP32S3) + { ETS_UART2_INTR_SOURCE, CPU_INUM_UART, 1 }, +#endif + { ETS_GPIO_INTR_SOURCE, CPU_INUM_GPIO, 1 }, + { ETS_I2C_EXT0_INTR_SOURCE, CPU_INUM_I2C, 1 }, +#if defined(MCU_ESP32) || defined(MCU_ESP32S2) || defined(MCU_ESP32S3) + { ETS_I2C_EXT1_INTR_SOURCE, CPU_INUM_I2C, 1 }, +#endif +#if defined(MCU_ESP32) + { ETS_ETH_MAC_INTR_SOURCE, CPU_INUM_ETH, 1 }, +#endif +#if !defined(MCU_ESP32C2) + { ETS_TWAI_INTR_SOURCE, CPU_INUM_CAN, 1 }, + { ETS_TIMER2_INTR_SOURCE, CPU_INUM_FRC2, 2 }, +#endif +#if !defined(MCU_ESP32) + { ETS_SYSTIMER_TARGET2_EDGE_INTR_SOURCE, CPU_INUM_SYSTIMER, 2 }, +#endif }; -static const struct _irq_alloc_table_t _irq_alloc_table[] = { - { ETS_FROM_CPU_INTR0_SOURCE, CPU_INUM_SOFTWARE }, - { ETS_TG0_WDT_LEVEL_INTR_SOURCE, CPU_INUM_WDT }, - { ETS_TG0_LACT_LEVEL_INTR_SOURCE, CPU_INUM_RTC }, - { ETS_TG0_T1_LEVEL_INTR_SOURCE, CPU_INUM_TIMER }, - { ETS_TG1_T0_LEVEL_INTR_SOURCE, CPU_INUM_TIMER }, - { ETS_TG1_T1_LEVEL_INTR_SOURCE, CPU_INUM_TIMER }, - { ETS_UART0_INTR_SOURCE, CPU_INUM_UART }, - { ETS_UART1_INTR_SOURCE, CPU_INUM_UART }, - { ETS_UART2_INTR_SOURCE, CPU_INUM_UART }, - { ETS_GPIO_INTR_SOURCE, CPU_INUM_GPIO }, - { DPORT_PRO_RTC_CORE_INTR_MAP_REG, CPU_INUM_RTC }, - { ETS_I2C_EXT0_INTR_SOURCE, CPU_INUM_I2C }, - { ETS_I2C_EXT1_INTR_SOURCE, CPU_INUM_I2C }, - { ETS_ETH_MAC_INTR_SOURCE, CPU_INUM_ETH }, - { ETS_CAN_INTR_SOURCE, CPU_INUM_CAN }, - { ETS_TIMER2_INTR_SOURCE, CPU_INUM_FRC2 }, -}; +#define IRQ_DATA_TABLE_SIZE ARRAY_SIZE(_irq_data_table) -typedef void (*intr_handler_t)(void *arg); +void esp_irq_init(void) +{ +#ifdef SOC_CPU_HAS_FLEXIBLE_INTC + /* to avoid to do it in every component, we initialize levels here once */ + for (unsigned i = 0; i < IRQ_DATA_TABLE_SIZE; i++) { + intr_cntrl_ll_set_int_level(_irq_data_table[i].intr, _irq_data_table[i].level); + } +#endif +} -#define IRQ_ALLOC_TABLE_SIZE ARRAY_SIZE(_irq_alloc_table) -#define ESP_INTR_FLAG_INTRDISABLED (1<<11) +void esp_intr_enable_source(int inum) +{ + intr_cntrl_ll_enable_interrupts(BIT(inum)); +} -typedef unsigned intr_handle_t; +void esp_intr_disable_source(int inum) +{ + intr_cntrl_ll_disable_interrupts(BIT(inum)); +} esp_err_t esp_intr_enable(intr_handle_t handle) { - assert(handle < IRQ_ALLOC_TABLE_SIZE); - const struct _irq_alloc_table_t *entry = &_irq_alloc_table[handle]; - xt_ints_on(BIT(entry->intr)); + assert(handle != NULL); + esp_intr_enable_source(handle->intr); return ESP_OK; } esp_err_t esp_intr_disable(intr_handle_t handle) { - assert(handle < IRQ_ALLOC_TABLE_SIZE); - const struct _irq_alloc_table_t *entry = &_irq_alloc_table[handle]; - xt_ints_off(BIT(entry->intr)); + assert(handle != NULL); + esp_intr_disable_source(handle->intr); return ESP_OK; } @@ -88,29 +136,34 @@ esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *arg, intr_handle_t *ret_handle) { unsigned i; - for (i = 0; i < IRQ_ALLOC_TABLE_SIZE; i++) { - if (_irq_alloc_table[i].src == source) { + for (i = 0; i < IRQ_DATA_TABLE_SIZE; i++) { + if (_irq_data_table[i].src == source) { break; } } - if (i == IRQ_ALLOC_TABLE_SIZE) { + if (i == IRQ_DATA_TABLE_SIZE) { return ESP_ERR_NOT_FOUND; } /* route the interrupt source to the CPU interrupt */ - intr_matrix_set(PRO_CPU_NUM, _irq_alloc_table[i].src, _irq_alloc_table[i].intr); + intr_matrix_set(PRO_CPU_NUM, _irq_data_table[i].src, _irq_data_table[i].intr); /* set the interrupt handler */ - xt_set_interrupt_handler(_irq_alloc_table[i].intr, handler, arg); + intr_cntrl_ll_set_int_handler(_irq_data_table[i].intr, handler, arg); + +#ifdef SOC_CPU_HAS_FLEXIBLE_INTC + /* set interrupt level given by flags */ + intr_cntrl_ll_set_int_level(_irq_data_table[i].intr, esp_intr_flags_to_level(flags)); +#endif /* enable the interrupt if ESP_INTR_FLAG_INTRDISABLED is not set */ if ((flags & ESP_INTR_FLAG_INTRDISABLED) == 0) { - xt_ints_on(BIT(_irq_alloc_table[i].intr)); + intr_cntrl_ll_enable_interrupts(BIT(_irq_data_table[i].intr)); } if (ret_handle) { - *((intr_handle_t *)ret_handle) = i; + *((intr_handle_t *)ret_handle) = &_irq_data_table[i]; } return ESP_OK; @@ -120,3 +173,80 @@ esp_err_t esp_intr_free(intr_handle_t handle) { return esp_intr_disable(handle); } + +int esp_intr_get_cpu(intr_handle_t handle) +{ + return PRO_CPU_NUM; +} + +#if __riscv + +#define RVHAL_EXCM_LEVEL 4 + +/** + * @brief Disable all maskable interrupts + */ +unsigned int IRAM_ATTR irq_disable(void) +{ + uint32_t mstatus; + /* clear MIE bit in register mstatus */ + __asm__ volatile ("csrrc %0, mstatus, %1" : "=r"(mstatus) : "rK"(MSTATUS_MIE) : "memory"); + + /* save interrupt priority level threshold */ + uint32_t state = *((volatile uint32_t *)INTERRUPT_CORE0_CPU_INT_THRESH_REG); + /* set interrupt priority level threshold to exception level */ + *((volatile uint32_t *)INTERRUPT_CORE0_CPU_INT_THRESH_REG) = RVHAL_EXCM_LEVEL; + + /* set MIE bit in register mstatus */ + __asm__ volatile ("csrrs %0, mstatus, %1" : "=r"(mstatus) : "rK"(MSTATUS_MIE) : "memory"); + + DEBUG("%s %02x(%02x)\n", __func__, RVHAL_EXCM_LEVEL, (unsigned)state); + return state; +} + +/** + * @brief Enable all maskable interrupts + */ +unsigned int IRAM_ATTR irq_enable(void) +{ + uint32_t state = *((volatile uint32_t *)INTERRUPT_CORE0_CPU_INT_THRESH_REG); + + /* set interrupt priority level threshold to 0 */ + *((volatile uint32_t *)INTERRUPT_CORE0_CPU_INT_THRESH_REG) = 0; + + /* small delay needed here */ + __asm__ volatile ( "nop" ); + __asm__ volatile ( "nop" ); + __asm__ volatile ( "nop" ); + + DEBUG("%s %02x(%02x)\n", __func__, 0, (unsigned)state); + return state; +} + +/** + * @brief Restore the state of the IRQ flags + */ +void IRAM_ATTR irq_restore(unsigned int state) +{ + uint32_t old = *((volatile uint32_t *)INTERRUPT_CORE0_CPU_INT_THRESH_REG); + + /* set interrupt priority level threshold to old level */ + *((volatile uint32_t *)INTERRUPT_CORE0_CPU_INT_THRESH_REG) = state; + + /* small delay needed here */ + __asm__ volatile ( "nop" ); + __asm__ volatile ( "nop" ); + __asm__ volatile ( "nop" ); + + DEBUG("%s %02x(%02x)\n", __func__, (unsigned)state, (unsigned)old); +} + +/** + * @brief Test if IRQs are currently enabled + */ +bool IRAM_ATTR irq_is_enabled(void) +{ + return *((volatile uint32_t *)INTERRUPT_CORE0_CPU_INT_THRESH_REG) == 0; +} + +#endif /* __riscv__ */ diff --git a/cpu/esp_common/irq_arch.c b/cpu/esp_common/irq_arch.c index 0786baced8cc..6e3173a1ef24 100644 --- a/cpu/esp_common/irq_arch.c +++ b/cpu/esp_common/irq_arch.c @@ -26,8 +26,11 @@ #include "esp_common.h" #include "esp/common_macros.h" + +#if __xtensa__ #include "esp/xtensa_ops.h" #include "xtensa/xtensa_context.h" +#endif #define ENABLE_DEBUG 0 #include "debug.h" @@ -37,6 +40,7 @@ */ volatile uint32_t irq_interrupt_nesting = 0; +#if __xtensa__ /** * @brief Disable all maskable interrupts */ @@ -91,15 +95,6 @@ void IRAM irq_restore(unsigned int state) DEBUG("%s %02x(%02x)\n", __func__, state, old & 0xf); } -/** - * @brief See if the current context is inside an ISR - */ -bool IRAM irq_is_in(void) -{ - DEBUG("irq_interrupt_nesting = %d\n", irq_interrupt_nesting); - return irq_interrupt_nesting; -} - /** * @brief Test if IRQs are currently enabled */ @@ -110,3 +105,14 @@ bool IRAM irq_is_enabled(void) RSR(reg, 230); return (reg & 0xf) == 0; } + +#endif /* __xtensa__ */ + +/** + * @brief See if the current context is inside an ISR + */ +bool IRAM irq_is_in(void) +{ + DEBUG("irq_interrupt_nesting = %" PRIu32 "\n", irq_interrupt_nesting); + return irq_interrupt_nesting; +} From 6cca58a6d1f15b589312c80e8a47c85bb59546c5 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 17:07:55 +0100 Subject: [PATCH 09/46] cpu/esp32: port periph/rtt_hw_rtc to ESP-IDF interrupt HAL --- cpu/esp32/periph/rtt_hw_rtc.c | 39 ++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/cpu/esp32/periph/rtt_hw_rtc.c b/cpu/esp32/periph/rtt_hw_rtc.c index 809687aa00c3..5694942b13cf 100644 --- a/cpu/esp32/periph/rtt_hw_rtc.c +++ b/cpu/esp32/periph/rtt_hw_rtc.c @@ -33,10 +33,16 @@ /* ESP-IDF headers */ #include "esp_attr.h" #include "esp_sleep.h" +#include "hal/interrupt_controller_types.h" +#include "hal/interrupt_controller_ll.h" #include "rom/ets_sys.h" -#include "soc/dport_reg.h" +#include "soc/periph_defs.h" #include "soc/rtc_cntl_struct.h" + +#if __xtensa__ +#include "soc/dport_reg.h" #include "xtensa/xtensa_api.h" +#endif #define ENABLE_DEBUG 0 #include "debug.h" @@ -74,30 +80,37 @@ static void _rtc_init(void) static void _rtc_poweron(void) { /* route all interrupt sources to the same RTT level type interrupt */ - intr_matrix_set(PRO_CPU_NUM, ETS_RTC_CORE_INTR_SOURCE, CPU_INUM_RTC); + intr_matrix_set(PRO_CPU_NUM, ETS_RTC_CORE_INTR_SOURCE, CPU_INUM_RTT); /* set interrupt handler and enable the CPU interrupt */ - xt_set_interrupt_handler(CPU_INUM_RTC, _rtc_isr, NULL); - xt_ints_on(BIT(CPU_INUM_RTC)); + intr_cntrl_ll_set_int_handler(CPU_INUM_RTT, _rtc_isr, NULL); + intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_RTT)); } static void _rtc_poweroff(void) { /* reset interrupt handler and disable the CPU interrupt */ - xt_ints_off(BIT(CPU_INUM_RTC)); - xt_set_interrupt_handler(CPU_INUM_RTC, NULL, NULL); + intr_cntrl_ll_disable_interrupts(BIT(CPU_INUM_RTT)); + intr_cntrl_ll_set_int_handler(CPU_INUM_RTT, NULL, NULL); } uint64_t _rtc_get_counter(void) { /* trigger timer register update */ RTCCNTL.time_update.update = 1; +#if defined(MCU_ESP32) /* wait until values in registers are valid */ while (!RTCCNTL.time_update.valid) { ets_delay_us(1); } /* read the time from 48-bit counter and return */ return (((uint64_t)RTCCNTL.time1.val) << 32) + RTCCNTL.time0; +#elif defined(MCU_ESP32C3) + /* read the time from 48-bit counter and return */ + return (((uint64_t)RTCCNTL.time_high0.val) << 32) + RTCCNTL.time_low0; +#else +#error "MCU implementation is missing" +#endif } static void _rtc_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) @@ -109,8 +122,9 @@ static void _rtc_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) /* use computed time difference directly to set the RTC counter alarm */ uint64_t rtc_alarm = (rtc_counter + rtt_diff) & RTT_HW_COUNTER_MAX; - DEBUG("%s alarm=%u rtt_diff=%u rtc_alarm=%llu @rtc=%llu\n", - __func__, alarm, rtt_diff, rtc_alarm, rtc_counter); + DEBUG("%s alarm=%" PRIu32 " rtt_diff=%" PRIu32 + " rtc_alarm=%" PRIu64 " @rtc=%" PRIu64 "\n", + __func__, alarm, rtt_diff, rtc_alarm, rtc_counter); /* save the alarm configuration for interrupt handling */ _rtc_alarm.alarm_set = alarm; @@ -121,8 +135,13 @@ static void _rtc_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) RTCCNTL.slp_timer0 = rtc_alarm & 0xffffffff; RTCCNTL.slp_timer1.slp_val_hi = rtc_alarm >> 32; +#if __xtensa__ DEBUG("%s %08x%08x \n", __func__, RTCCNTL.slp_timer1.slp_val_hi, RTCCNTL.slp_timer0); +#else + DEBUG("%s %08x%08x \n", __func__, + (unsigned)RTCCNTL.slp_timer1.slp_val_hi, (unsigned)RTCCNTL.slp_timer0); +#endif /* enable RTC timer alarm */ RTCCNTL.slp_timer1.main_timer_alarm_en = 1; @@ -168,10 +187,10 @@ static void IRAM _rtc_isr(void *arg) /* save the lower 32 bit of the current counter value */ uint32_t counter = _rtc_get_counter(); - DEBUG("%s %u\n", __func__, counter); + DEBUG("%s %" PRIu32 "\n", __func__, counter); if (_rtc_alarm.alarm_cb) { - DEBUG("%s alarm %u\n", __func__, counter); + DEBUG("%s alarm %" PRIu32 "\n", __func__, counter); rtt_cb_t alarm_cb = _rtc_alarm.alarm_cb; void *alarm_arg = _rtc_alarm.alarm_arg; From 2a9ffee7610ab569d8f933765fddc52cae5b9143 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 17:23:07 +0100 Subject: [PATCH 10/46] cpu/esp32: port periph/rtt_hw_sys to ESP-IDF timer HAL --- cpu/esp32/periph/rtt_hw_sys.c | 73 +++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/cpu/esp32/periph/rtt_hw_sys.c b/cpu/esp32/periph/rtt_hw_sys.c index bf8b646fe937..1deb9094e755 100644 --- a/cpu/esp32/periph/rtt_hw_sys.c +++ b/cpu/esp32/periph/rtt_hw_sys.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Gunar Schorcht + * Copyright (C) 2022 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 @@ -32,20 +32,28 @@ /* ESP-IDF headers */ #include "esp_attr.h" #include "esp_sleep.h" +#include "hal/interrupt_controller_types.h" +#include "hal/interrupt_controller_ll.h" +#include "hal/timer_hal.h" #include "rom/ets_sys.h" +#include "soc/periph_defs.h" #include "soc/timer_group_struct.h" + +#if __xtensa__ #include "xtensa/xtensa_api.h" +#endif #define ENABLE_DEBUG 0 #include "debug.h" -#define TIMER_SYSTEM_GROUP TIMERG0 -#define TIMER_SYSTEM_INT_MASK BIT(0) -#define TIMER_SYSTEM_INT_SRC ETS_TG0_T0_LEVEL_INTR_SOURCE +#define TIMER_SYSTEM_INT_MASK BIT(TIMER_SYSTEM_INDEX) #define SYS_US_TO_TICKS(us) ((((uint64_t)us) << 15) / US_PER_SEC) #define SYS_TICKS_TO_US(cnt) (((uint64_t)cnt * US_PER_SEC) >> 15) +/* system timer is defined and initialized in syscalls.c */ +extern timer_hal_context_t sys_timer; + typedef struct { uint32_t alarm_set; /**< alarm set at interface */ rtt_cb_t alarm_cb; /**< alarm callback */ @@ -74,18 +82,18 @@ static void _sys_init(void) static void _sys_poweron(void) { /* route all interrupt sources to the same RTT level type interrupt */ - intr_matrix_set(PRO_CPU_NUM, TIMER_SYSTEM_INT_SRC, CPU_INUM_RTC); + intr_matrix_set(PRO_CPU_NUM, TIMER_SYSTEM_INT_SRC, CPU_INUM_RTT); /* set interrupt handler and enable the CPU interrupt */ - xt_set_interrupt_handler(CPU_INUM_RTC, _sys_isr, NULL); - xt_ints_on(BIT(CPU_INUM_RTC)); + intr_cntrl_ll_set_int_handler(CPU_INUM_RTT, _sys_isr, NULL); + intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_RTT)); } static void _sys_poweroff(void) { /* reset interrupt handler and disable the CPU interrupt */ - xt_ints_off(BIT(CPU_INUM_RTC)); - xt_set_interrupt_handler(CPU_INUM_RTC, NULL, NULL); + intr_cntrl_ll_disable_interrupts(BIT(CPU_INUM_RTT)); + intr_cntrl_ll_set_int_handler(CPU_INUM_RTT, NULL, NULL); } static uint64_t _sys_get_counter(void) @@ -108,8 +116,8 @@ static void _sys_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) uint64_t _sys_time = system_get_time_64(); uint64_t _sys_alarm_time = _sys_time + _sys_diff; - DEBUG("%s alarm=%u rtt_diff=%u " - "sys_diff=%llu sys_alarm=%llu @sys_time=%llu\n", __func__, + DEBUG("%s alarm=%" PRIu32 " rtt_diff=%" PRIu32 " " + "sys_diff=%" PRIu64 " sys_alarm=%" PRIu64 " @sys_time=%" PRIu64 "\n", __func__, alarm, rtt_diff, _sys_diff, _sys_alarm_time, _sys_time); /* save the alarm configuration for interrupt handling */ @@ -118,27 +126,24 @@ static void _sys_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) _sys_alarm.alarm_arg = arg; /* set the timer value */ - TIMER_SYSTEM.alarm_high = (uint32_t)(_sys_alarm_time >> 32); - TIMER_SYSTEM.alarm_low = (uint32_t)(_sys_alarm_time & 0xffffffff); + timer_hal_set_alarm_value(&sys_timer, _sys_alarm_time); /* clear the bit in status and set the bit in interrupt enable */ - TIMER_SYSTEM_GROUP.int_clr_timers.val |= TIMER_SYSTEM_INT_MASK; - TIMER_SYSTEM_GROUP.int_ena.val |= TIMER_SYSTEM_INT_MASK; + timer_hal_clear_intr_status(&sys_timer); + timer_hal_intr_enable(&sys_timer); /* enable the timer alarm */ - TIMER_SYSTEM.config.level_int_en = 1; - TIMER_SYSTEM.config.alarm_en = 1; + timer_hal_set_alarm_enable(&sys_timer, true); } static void _sys_clear_alarm(void) { /* disable alarms first */ - TIMER_SYSTEM.config.level_int_en = 0; - TIMER_SYSTEM.config.alarm_en = 0; + timer_hal_intr_disable(&sys_timer); + timer_hal_set_alarm_enable(&sys_timer, false); - /* clear the bit in interrupt enable and status register */ - TIMER_SYSTEM_GROUP.int_ena.val &= ~TIMER_SYSTEM_INT_MASK; - TIMER_SYSTEM_GROUP.int_clr_timers.val |= TIMER_SYSTEM_INT_MASK; + /* clear the bit in interrupt status register */ + timer_hal_clear_intr_status(&sys_timer); /* reset the alarm configuration for interrupt handling */ _sys_alarm.alarm_set = 0; @@ -156,7 +161,7 @@ static void _sys_save_counter(void) critical_exit(); - DEBUG("%s rtc_time_saved=%llu sys_time_saved=%llu\n", __func__, + DEBUG("%s rtc_time_saved=%" PRIu64 " sys_time_saved=%" PRIu64 "\n", __func__, _rtc_counter_saved, _sys_counter_saved); } @@ -171,34 +176,36 @@ static void _sys_restore_counter(bool in_init) critical_exit(); - DEBUG("%s rtc_time_saved=%llu rtc_time_diff=%llu " - "sys_time_saved=%llu sys_time_offset=%llu\n", __func__, + DEBUG("%s rtc_time_saved=%" PRIu64 " rtc_time_diff=%" PRIu64 " " + "sys_time_saved=%" PRIu64 " sys_time_offset=%" PRIu64 "\n", __func__, _rtc_counter_saved, _rtc_time_diff, _sys_counter_saved, _sys_counter_offset); } static void IRAM _sys_isr(void *arg) { - if (!(TIMER_SYSTEM_GROUP.int_st_timers.val & TIMER_SYSTEM_INT_MASK)) { + uint32_t int_status; + + timer_hal_get_intr_status(&sys_timer, &int_status); + if (!(int_status & TIMER_SYSTEM_INT_MASK)) { /* return in case of another timer interrupt */ return; } /* disable alarms first */ - TIMER_SYSTEM.config.level_int_en = 0; - TIMER_SYSTEM.config.alarm_en = 0; + timer_hal_intr_disable(&sys_timer); + timer_hal_set_alarm_enable(&sys_timer, false); - /* clear the bit in interrupt enable and status register */ - TIMER_SYSTEM_GROUP.int_ena.val &= ~TIMER_SYSTEM_INT_MASK; - TIMER_SYSTEM_GROUP.int_clr_timers.val |= TIMER_SYSTEM_INT_MASK; + /* clear the bit in interrupt status register */ + timer_hal_clear_intr_status(&sys_timer); /* save the lower 32 bit of the current counter value */ uint32_t counter = _sys_get_counter(); - DEBUG("%s %u\n", __func__, counter); + DEBUG("%s %" PRIu32 "\n", __func__, counter); if (_sys_alarm.alarm_cb) { - DEBUG("%s alarm %u\n", __func__, counter); + DEBUG("%s alarm %" PRIu32 "\n", __func__, counter); rtt_cb_t alarm_cb = _sys_alarm.alarm_cb; void *alarm_arg = _sys_alarm.alarm_arg; From 55e98a18fe7f8b2057055f2bb37f32f03a45851e Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 17:30:54 +0100 Subject: [PATCH 11/46] cpu/esp32: port syscalls to ESP-IDF timer HAL --- cpu/esp32/include/periph_cpu.h | 20 +++- cpu/esp32/syscalls.c | 175 +++++++++++++++++++++------------ 2 files changed, 128 insertions(+), 67 deletions(-) diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index 865fea3e2163..133f7fcfc21a 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -504,18 +504,28 @@ typedef struct { * configured here. * @{ */ + #ifdef MODULE_ESP_HW_COUNTER -/** hardware ccount/ccompare registers are used for timer implementation */ +/** Hardware ccount/ccompare registers are used for timer implementation */ #define TIMER_NUMOF (2) #define TIMER_CHANNEL_NUMOF (1) #else -/** hardware timer modules are used for timer implementation (default) */ -#define TIMER_NUMOF (3) +/** + * @brief Hardware timer modules are used for timer implementation (default) + * + * Since one timer is used for the system time, there is one timer less than + * the total number of timers. + */ +#define TIMER_NUMOF (SOC_TIMER_GROUP_TOTAL_TIMERS - 1) #define TIMER_CHANNEL_NUMOF (1) #endif -/** Timer used for system time */ -#define TIMER_SYSTEM TIMERG0.hw_timer[0] +/** Timer group used for system time */ +#define TIMER_SYSTEM_GROUP TIMER_GROUP_0 +/** Index of the timer in the timer timer group used for system time */ +#define TIMER_SYSTEM_INDEX TIMER_0 +/** System time interrupt source */ +#define TIMER_SYSTEM_INT_SRC ETS_TG0_T0_LEVEL_INTR_SOURCE /** @} */ diff --git a/cpu/esp32/syscalls.c b/cpu/esp32/syscalls.c index 41118fb17e72..c18954aadd11 100644 --- a/cpu/esp32/syscalls.c +++ b/cpu/esp32/syscalls.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2022 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 @@ -30,14 +30,24 @@ #include "sys/lock.h" #include "timex.h" +#include "hal/interrupt_controller_types.h" +#include "hal/interrupt_controller_ll.h" +#include "hal/timer_hal.h" +#include "hal/wdt_hal.h" +#include "hal/wdt_types.h" #include "rom/ets_sys.h" #include "rom/libc_stubs.h" +#include "soc/periph_defs.h" #include "soc/rtc.h" +#include "soc/rtc_cntl_reg.h" #include "soc/rtc_cntl_struct.h" #include "soc/timer_group_reg.h" #include "soc/timer_group_struct.h" #include "sdkconfig.h" + +#if __xtensa__ #include "xtensa/xtensa_api.h" +#endif #ifdef MODULE_ESP_IDF_HEAP #include "esp_heap_caps.h" @@ -46,6 +56,15 @@ #define ENABLE_DEBUG 0 #include "debug.h" +#if IS_USED(MODULE_CPP) +/* weak function that have to be overridden, otherwise DEFAULT_ARENA_SIZE would + * be allocated that would consume the whole heap memory */ +size_t __cxx_eh_arena_size_get(void) +{ + return 0; +} +#endif + #if IS_USED(MODULE_ESP_IDF_HEAP) /* if module esp_idf_heap is used, this function has to be defined for ESP32 */ @@ -188,6 +207,9 @@ static struct syscall_stub_table s_stub_table = ._link_r = (void*)&_no_sys_func, ._rename_r = (void*)&_no_sys_func, +#if defined(MCU_ESP32) || \ + defined(MCU_ESP32S2) || \ + (defined(MCU_ESP32H2) && !defined(_RETARGETABLE_LOCKING)) ._lock_init = &_lock_init, ._lock_init_recursive = &_lock_init_recursive, ._lock_close = &_lock_close, @@ -198,7 +220,18 @@ static struct syscall_stub_table s_stub_table = ._lock_try_acquire_recursive = &_lock_try_acquire_recursive, ._lock_release = &_lock_release, ._lock_release_recursive = &_lock_release_recursive, - +#else + ._retarget_lock_init = &__retarget_lock_init, + ._retarget_lock_init_recursive = &__retarget_lock_init_recursive, + ._retarget_lock_close = &__retarget_lock_close, + ._retarget_lock_close_recursive = &__retarget_lock_close_recursive, + ._retarget_lock_acquire = &__retarget_lock_acquire, + ._retarget_lock_acquire_recursive = &__retarget_lock_acquire_recursive, + ._retarget_lock_try_acquire = &__retarget_lock_try_acquire, + ._retarget_lock_try_acquire_recursive = &__retarget_lock_try_acquire_recursive, + ._retarget_lock_release = &__retarget_lock_release, + ._retarget_lock_release_recursive = &__retarget_lock_release_recursive, +#endif #if CONFIG_NEWLIB_NANO_FORMAT ._printf_float = &_printf_float, ._scanf_float = &_scanf_float, @@ -208,23 +241,33 @@ static struct syscall_stub_table s_stub_table = #endif /* CONFIG_NEWLIB_NANO_FORMAT */ }; +timer_hal_context_t sys_timer = { + .dev = TIMER_LL_GET_HW(TIMER_SYSTEM_GROUP), + .idx = TIMER_SYSTEM_INDEX, +}; + void IRAM syscalls_init_arch(void) { - /* enable the system timer in us (TMG0 is enabled by default) */ - TIMER_SYSTEM.config.divider = rtc_clk_apb_freq_get() / MHZ; - TIMER_SYSTEM.config.autoreload = 0; - TIMER_SYSTEM.config.enable = 1; - + /* initialize and enable the system timer in us (TMG0 is enabled by default) */ + timer_hal_init(&sys_timer, TIMER_SYSTEM_GROUP, TIMER_SYSTEM_INDEX); + timer_hal_set_divider(&sys_timer, rtc_clk_apb_freq_get() / MHZ); + timer_hal_set_counter_increase(&sys_timer, true); + timer_hal_set_auto_reload(&sys_timer, false); + timer_hal_set_counter_enable(&sys_timer, true); + +#if defined(MCU_ESP32) syscall_table_ptr_pro = &s_stub_table; syscall_table_ptr_app = &s_stub_table; +#elif defined(MCU_ESP32S2) + syscall_table_ptr_pro = &s_stub_table; +#else + syscall_table_ptr = &s_stub_table; +#endif } uint32_t system_get_time(void) { - /* latch 64 bit timer value before read */ - TIMER_SYSTEM.update = 0; - /* read the current timer value */ - return TIMER_SYSTEM.cnt_low; + return system_get_time_64(); } uint32_t system_get_time_ms(void) @@ -234,80 +277,88 @@ uint32_t system_get_time_ms(void) int64_t system_get_time_64(void) { - uint64_t ret; - /* latch 64 bit timer value before read */ - TIMER_SYSTEM.update = 0; - /* read the current timer value */ - ret = TIMER_SYSTEM.cnt_low; - ret += ((uint64_t)TIMER_SYSTEM.cnt_high) << 32; + uint64_t ret; + timer_hal_get_counter_value(&sys_timer, &ret); return ret; } +wdt_hal_context_t mwdt; +wdt_hal_context_t rwdt; + static IRAM void system_wdt_int_handler(void *arg) { - TIMERG0.int_clr_timers.wdt=1; /* clear interrupt */ - system_wdt_feed(); + wdt_hal_handle_intr(&mwdt); + wdt_hal_write_protect_disable(&mwdt); + wdt_hal_feed(&mwdt); + wdt_hal_write_protect_enable(&mwdt); } void IRAM system_wdt_feed(void) { - DEBUG("%s\n", __func__); - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */ - TIMERG0.wdt_feed=1; /* reset MWDT */ - TIMERG0.wdt_wprotect=0; /* enable write protection */ + wdt_hal_write_protect_disable(&mwdt); + wdt_hal_feed(&mwdt); + wdt_hal_write_protect_enable(&mwdt); } void system_wdt_init(void) { - /* disable boot watchdogs */ - TIMERG0.wdt_config0.flashboot_mod_en = 0; - RTCCNTL.wdt_config0.flashboot_mod_en = 0; - - /* enable system watchdog */ - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */ - TIMERG0.wdt_config0.stg0 = TIMG_WDT_STG_SEL_INT; /* stage0 timeout: interrupt */ - TIMERG0.wdt_config0.stg1 = TIMG_WDT_STG_SEL_RESET_SYSTEM; /* stage1 timeout: sys reset */ - TIMERG0.wdt_config0.sys_reset_length = 7; /* sys reset signal length: 3.2 us */ - TIMERG0.wdt_config0.cpu_reset_length = 7; /* sys reset signal length: 3.2 us */ - TIMERG0.wdt_config0.edge_int_en = 0; - TIMERG0.wdt_config0.level_int_en = 1; - - /* MWDT clock = 80 * 12,5 ns = 1 us */ - TIMERG0.wdt_config1.clk_prescale = 80; - - /* define stage timeouts */ - TIMERG0.wdt_config2 = 2 * US_PER_SEC; /* stage 0: 2 s (interrupt) */ - TIMERG0.wdt_config3 = 4 * US_PER_SEC; /* stage 1: 4 s (sys reset) */ - - TIMERG0.wdt_config0.en = 1; /* enable MWDT */ - TIMERG0.wdt_feed = 1; /* reset MWDT */ - TIMERG0.wdt_wprotect = 0; /* enable write protection */ - - DEBUG("%s TIMERG0 wdt_config0=%08x wdt_config1=%08x wdt_config2=%08x\n", - __func__, TIMERG0.wdt_config0.val, TIMERG0.wdt_config1.val, - TIMERG0.wdt_config2); + /* initialize and disable boot watchdogs MWDT and RWDT */ + wdt_hal_init(&mwdt, WDT_MWDT0, 80, true); + wdt_hal_init(&rwdt, WDT_RWDT, 0, false); + + /* disable write protection for MWDT and RWDT */ + wdt_hal_write_protect_disable(&mwdt); + wdt_hal_write_protect_disable(&rwdt); + + /* configure stages */ + wdt_hal_config_stage(&mwdt, WDT_STAGE0, 2 * US_PER_SEC, WDT_STAGE_ACTION_INT); + wdt_hal_config_stage(&mwdt, WDT_STAGE1, 2 * US_PER_SEC, WDT_STAGE_ACTION_RESET_SYSTEM); + wdt_hal_config_stage(&mwdt, WDT_STAGE2, 0, WDT_STAGE_ACTION_OFF); + wdt_hal_config_stage(&mwdt, WDT_STAGE3, 0, WDT_STAGE_ACTION_OFF); + + /* enable the watchdog */ + wdt_hal_enable(&mwdt); + + /* enable write protection for MWDT and RWDT */ + wdt_hal_write_protect_enable(&mwdt); + wdt_hal_write_protect_enable(&rwdt); + +#if defined(MCU_ESP32) + DEBUG("%s TIMERG0 wdtconfig0=%08x wdtconfig1=%08x wdtconfig2=%08x " + "wdtconfig3=%08x wdtconfig4=%08x regclk=%08x\n", __func__, + TIMERG0.wdt_config0.val, TIMERG0.wdt_config1.val, + TIMERG0.wdt_config2, TIMERG0.wdt_config3, + TIMERG0.wdt_config4, TIMERG0.clk.val); +#else + DEBUG("%s TIMERG0 wdtconfig0=%08"PRIx32" wdtconfig1=%08"PRIx32 + " wdtconfig2=%08"PRIx32" wdtconfig3=%08"PRIx32 + " wdtconfig4=%08"PRIx32" regclk=%08"PRIx32"\n", __func__, + TIMERG0.wdtconfig0.val, TIMERG0.wdtconfig1.val, + TIMERG0.wdtconfig2.val, TIMERG0.wdtconfig3.val, + TIMERG0.wdtconfig4.val, TIMERG0.regclk.val); +#endif /* route WDT peripheral interrupt source to CPU_INUM_WDT */ intr_matrix_set(PRO_CPU_NUM, ETS_TG0_WDT_LEVEL_INTR_SOURCE, CPU_INUM_WDT); /* set the interrupt handler and activate the interrupt */ - xt_set_interrupt_handler(CPU_INUM_WDT, system_wdt_int_handler, NULL); - xt_ints_on(BIT(CPU_INUM_WDT)); + intr_cntrl_ll_set_int_handler(CPU_INUM_WDT, system_wdt_int_handler, NULL); + intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_WDT)); } void system_wdt_stop(void) { - xt_ints_off(BIT(CPU_INUM_WDT)); - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */ - TIMERG0.wdt_config0.en = 0; /* disable MWDT */ - TIMERG0.wdt_feed = 1; /* reset MWDT */ - TIMERG0.wdt_wprotect = 0; /* enable write protection */ + intr_cntrl_ll_disable_interrupts(BIT(CPU_INUM_WDT)); + + wdt_hal_write_protect_disable(&mwdt); + wdt_hal_disable(&mwdt); + wdt_hal_write_protect_enable(&mwdt); } void system_wdt_start(void) { - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */ - TIMERG0.wdt_config0.en = 1; /* disable MWDT */ - TIMERG0.wdt_feed = 1; /* reset MWDT */ - TIMERG0.wdt_wprotect = 0; /* enable write protection */ - xt_ints_on(BIT(CPU_INUM_WDT)); + wdt_hal_write_protect_disable(&mwdt); + wdt_hal_enable(&mwdt); + wdt_hal_write_protect_enable(&mwdt); + + intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_WDT)); } From f01f56ac32af270498b66d42c400bca471382361 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 17:37:53 +0100 Subject: [PATCH 12/46] cpu/esp32: add ESP-IDF interface API Implements an interface for ESP-IDF types and functions that are required by RIOT-OS but cannot be included directly due to name conflicts. --- cpu/esp32/Makefile | 1 + cpu/esp32/Makefile.dep | 1 + cpu/esp32/esp-idf-api/Makefile | 18 ++++++++++++++++++ cpu/esp32/esp-idf-api/doc.txt | 23 +++++++++++++++++++++++ 4 files changed, 43 insertions(+) create mode 100644 cpu/esp32/esp-idf-api/Makefile create mode 100644 cpu/esp32/esp-idf-api/doc.txt diff --git a/cpu/esp32/Makefile b/cpu/esp32/Makefile index 621be88e25e1..a75705dd87d4 100644 --- a/cpu/esp32/Makefile +++ b/cpu/esp32/Makefile @@ -7,6 +7,7 @@ SRC = irq_arch.c startup.c syscalls.c DIRS += $(RIOTCPU)/esp_common DIRS += periph DIRS += esp-idf +DIRS += esp-idf-api ifneq (, $(filter esp_bootloader, $(USEMODULE))) DIRS += bootloader diff --git a/cpu/esp32/Makefile.dep b/cpu/esp32/Makefile.dep index cdfc1ef21762..2da66c7c369f 100644 --- a/cpu/esp32/Makefile.dep +++ b/cpu/esp32/Makefile.dep @@ -4,6 +4,7 @@ include $(RIOTCPU)/esp_common/Makefile.dep USEPKG += esp32_sdk +USEMODULE += esp_idf_api USEMODULE += esp_idf_common USEMODULE += esp_idf_efuse USEMODULE += esp_bootloader diff --git a/cpu/esp32/esp-idf-api/Makefile b/cpu/esp32/esp-idf-api/Makefile new file mode 100644 index 000000000000..621fc5e6b3d9 --- /dev/null +++ b/cpu/esp32/esp-idf-api/Makefile @@ -0,0 +1,18 @@ +MODULE = esp_idf_api + +# ESP-IDF header files must be found first in this module. Therefore, +# the ESP-IDF include paths must come before the RIOT include paths. +PRE_INCLUDES += -I$(ESP32_SDK_DIR)/components/driver/include +PRE_INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_common/include +PRE_INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/include +PRE_INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_rom/include +PRE_INCLUDES += -I$(ESP32_SDK_DIR)/components/hal/include +PRE_INCLUDES += -I$(ESP32_SDK_DIR)/components/hal/platform_port/include +PRE_INCLUDES += -I$(ESP32_SDK_DIR)/components/soc/include + +PRE_INCLUDES += -I$(ESP32_SDK_DIR)/components/hal/$(CPU)/include +PRE_INCLUDES += -I$(ESP32_SDK_DIR)/components/soc/$(CPU)/include + +include $(RIOTBASE)/Makefile.base + +INCLUDES := $(PRE_INCLUDES) $(INCLUDES) diff --git a/cpu/esp32/esp-idf-api/doc.txt b/cpu/esp32/esp-idf-api/doc.txt new file mode 100644 index 000000000000..d6129637a45e --- /dev/null +++ b/cpu/esp32/esp-idf-api/doc.txt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @defgroup cpu_esp32_esp_idf_api ESP-IDF Interface API + * @ingroup cpu_esp32 + * @brief ESP-IDF Interface API + * + * This module implements an interface for ESP-IDF types and functions that are + * required by RIOT-OS but cannot be included directly due to name conflicts. + * + * For this purpose, the header files of this module declare all the types and + * functions that are required from the ESP-IDF, but without using the ESP-IDF + * header files with conflicting names. The implementation of the module then + * uses the ESP-IDF. In most cases, simple wrapper functions are sufficient. + * + * @author Gunar Schorcht + */ From 520f4061008f9c0a0b69785d8d4ef0dbfa6d6d44 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 18:14:35 +0100 Subject: [PATCH 13/46] cpu/esp32: add adc to ESP-IDF initerface API --- cpu/esp32/esp-idf-api/adc.c | 65 +++++++++++++++++++++++++++++ cpu/esp32/esp-idf/Makefile | 4 ++ cpu/esp32/esp-idf/adc/Kconfig | 16 +++++++ cpu/esp32/esp-idf/adc/Makefile | 25 +++++++++++ cpu/esp32/include/esp_idf_api/adc.h | 57 +++++++++++++++++++++++++ 5 files changed, 167 insertions(+) create mode 100644 cpu/esp32/esp-idf-api/adc.c create mode 100644 cpu/esp32/esp-idf/adc/Kconfig create mode 100644 cpu/esp32/esp-idf/adc/Makefile create mode 100644 cpu/esp32/include/esp_idf_api/adc.h diff --git a/cpu/esp32/esp-idf-api/adc.c b/cpu/esp32/esp-idf-api/adc.c new file mode 100644 index 000000000000..46a11f535b23 --- /dev/null +++ b/cpu/esp32/esp-idf-api/adc.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32_esp_idf_api + * @{ + * + * @file + * @brief Interface for the ESP-IDF ADC HAL API + * + * @author Gunar Schorcht + * @} + */ + +#include + +#include "driver/adc.h" + +void esp_idf_adc_power_acquire(void) +{ + adc_power_acquire(); +} + +void esp_idf_adc_power_release(void) +{ + adc_power_release(); +} + +esp_err_t esp_idf_adc1_config_width(adc_bits_width_t width_bit) +{ + return adc1_config_width(width_bit); +} + +esp_err_t esp_idf_adc1_config_channel_atten(adc_channel_t channel, + adc_atten_t atten) +{ + return adc1_config_channel_atten(channel, atten); +} + +int esp_idf_adc1_get_raw(adc1_channel_t channel) +{ + return adc1_get_raw(channel); +} + +esp_err_t esp_idf_adc2_config_channel_atten(adc_channel_t channel, + adc_atten_t atten) +{ + return adc2_config_channel_atten(channel, atten); +} + +esp_err_t esp_idf_adc2_get_raw(adc2_channel_t channel, + adc_bits_width_t width_bit, int *raw_out) +{ + return adc2_get_raw(channel, width_bit, raw_out); +} + +esp_err_t esp_idf_adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio) +{ + return adc_vref_to_gpio(adc_unit, gpio); +} diff --git a/cpu/esp32/esp-idf/Makefile b/cpu/esp32/esp-idf/Makefile index d11426322205..de1e25ec3ea6 100644 --- a/cpu/esp32/esp-idf/Makefile +++ b/cpu/esp32/esp-idf/Makefile @@ -2,6 +2,10 @@ MODULE=esp_idf # Add a list of subdirectories, that should also be built: +ifneq (,$(filter esp_idf_adc,$(USEMODULE))) + DIRS += adc +endif + ifneq (,$(filter esp_idf_common,$(USEMODULE))) DIRS += common endif diff --git a/cpu/esp32/esp-idf/adc/Kconfig b/cpu/esp32/esp-idf/adc/Kconfig new file mode 100644 index 000000000000..c58ed528aeef --- /dev/null +++ b/cpu/esp32/esp-idf/adc/Kconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2022 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. +# + +config MODULE_ESP_IDF_ADC + bool + depends on TEST_KCONFIG + depends on MODULE_ESP_IDF + + default y if MODULE_PERIPH_ADC + + help + ESP-IDF code for ADC peripherals. diff --git a/cpu/esp32/esp-idf/adc/Makefile b/cpu/esp32/esp-idf/adc/Makefile new file mode 100644 index 000000000000..c0d17f9e8766 --- /dev/null +++ b/cpu/esp32/esp-idf/adc/Makefile @@ -0,0 +1,25 @@ +MODULE = esp_idf_adc + +# source files to be compiled for this module +ESP32_SDK_SRC = \ + components/driver/adc.c \ + components/driver/adc_common.c \ + components/hal/adc_hal.c \ + components/soc/$(CPU)/adc_periph.c \ + # + +ifneq (,$(filter esp32c3 esp32s3,$(CPU))) + ESP32_SDK_SRC += components/driver/$(CPU)/adc2_init_cal.c + INCLUDES += -I$(ESP32_SDK_DIR)/components/driver/include/driver +endif + +ifneq (,$(filter esp32c3 esp32h2 esp32s3,$(CPU))) + ESP32_SDK_SRC += components/efuse/$(CPU)/esp_efuse_rtc_calib.c +endif + +include $(RIOTBASE)/Makefile.base + +ESP32_SDK_BIN = $(BINDIR)/$(MODULE) + +include ../esp_idf.mk +include ../esp_idf_cflags.mk diff --git a/cpu/esp32/include/esp_idf_api/adc.h b/cpu/esp32/include/esp_idf_api/adc.h new file mode 100644 index 000000000000..5ddaac5f0424 --- /dev/null +++ b/cpu/esp32/include/esp_idf_api/adc.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32_esp_idf_api + * @{ + * + * @file + * @brief Interface for the ESP-IDF ADC HAL API + * + * @author Gunar Schorcht + * @} + */ + +#ifndef ESP_IDF_API_ADC_H +#define ESP_IDF_API_ADC_H + +#include "esp_err.h" +#include "hal/adc_types.h" +#include "hal/gpio_types.h" + +#ifndef DOXYGEN /* Hide implementation details from doxygen */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name ESP-IDF interface mapper functions + * @{ + */ +/** @} */ +void esp_idf_adc_power_acquire(void); +void esp_idf_adc_power_release(void); + +esp_err_t esp_idf_adc1_config_width(adc_bits_width_t width_bit); +esp_err_t esp_idf_adc1_config_channel_atten(adc_channel_t channel, + adc_atten_t atten); +int esp_idf_adc1_get_raw(adc_channel_t channel); + +esp_err_t esp_idf_adc2_config_channel_atten(adc_channel_t channel, + adc_atten_t atten); +esp_err_t esp_idf_adc2_get_raw(adc_channel_t channel, + adc_bits_width_t width_bit, int *raw_out); +esp_err_t esp_idf_adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio); + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* ESP_IDF_API_ADC_H */ From b86b2bb8891822b0f9fef8c465a0c92632b94459 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 18:15:31 +0100 Subject: [PATCH 14/46] cpu/esp32: port periph/adc to ESP-IDF interface API --- cpu/esp32/Kconfig | 6 +- cpu/esp32/Makefile.dep | 15 +- cpu/esp32/Makefile.features | 2 +- cpu/esp32/include/adc_arch.h | 78 +++++-- cpu/esp32/include/adc_arch_private.h | 65 ++++++ cpu/esp32/include/adc_ctrl.h | 90 -------- cpu/esp32/include/periph_cpu.h | 24 +- cpu/esp32/periph/adc.c | 318 +++++++++++++-------------- cpu/esp32/periph/adc_arch.c | 109 +++++++++ cpu/esp32/periph/adc_ctrl.c | 169 -------------- 10 files changed, 405 insertions(+), 471 deletions(-) create mode 100644 cpu/esp32/include/adc_arch_private.h delete mode 100644 cpu/esp32/include/adc_ctrl.h create mode 100644 cpu/esp32/periph/adc_arch.c delete mode 100644 cpu/esp32/periph/adc_ctrl.c diff --git a/cpu/esp32/Kconfig b/cpu/esp32/Kconfig index 544e2dd41290..f04fc30ffed8 100644 --- a/cpu/esp32/Kconfig +++ b/cpu/esp32/Kconfig @@ -16,7 +16,7 @@ config CPU_FAM_ESP32 select HAS_ARCH_ESP32 select HAS_CPU_ESP32 select HAS_ESP_WIFI_ENTERPRISE - select HAS_PERIPH_ADC_CTRL + select HAS_PERIPH_ADC_ARCH select HAS_PUF_SRAM select PACKAGE_ESP32_SDK if TEST_KCONFIG @@ -75,10 +75,10 @@ config HAS_ESP_SPI_RAM Indicates that an external RAM is connected via the FSPI interface in the board. -config HAS_PERIPH_ADC_CTRL +config HAS_PERIPH_ADC_ARCH bool help - Indicates that an ESP32 ADC controller peripheral is present. + Indicates that architecure specific ADC peripherals are present. ## Common CPU symbols config CPU_CORE diff --git a/cpu/esp32/Makefile.dep b/cpu/esp32/Makefile.dep index 2da66c7c369f..4b7e34fef54d 100644 --- a/cpu/esp32/Makefile.dep +++ b/cpu/esp32/Makefile.dep @@ -62,16 +62,21 @@ ifneq (,$(filter esp_idf_nvs_flash,$(USEMODULE))) USEMODULE += mtd endif +ifneq (,$(filter esp_idf_wifi,$(USEMODULE))) + # add additional modules required by esp_idf_nvs_flash + USEMODULE += esp_idf_adc +endif + ifneq (,$(filter periph_rtc,$(USEMODULE))) - FEATURES_OPTIONAL += esp_rtc_timer_32k + FEATURES_OPTIONAL += esp_rtc_timer_32k endif ifneq (,$(filter esp_rtc_timer_32k,$(FEATURES_USED))) - USEMODULE += esp_rtc_timer_32k + USEMODULE += esp_rtc_timer_32k endif ifneq (,$(filter periph_adc periph_dac,$(USEMODULE))) - FEATURES_REQUIRED += periph_adc_ctrl + FEATURES_REQUIRED += periph_adc_arch endif ifneq (,$(filter periph_i2c,$(USEMODULE))) @@ -100,6 +105,10 @@ ifneq (,$(filter mtd,$(USEMODULE))) USEMODULE += esp_idf_spi_flash endif +ifneq (,$(filter periph_adc,$(USEMODULE))) + USEMODULE += esp_idf_adc +endif + ifneq (,$(filter periph_rtc,$(USEMODULE))) USEMODULE += rtt_rtc endif diff --git a/cpu/esp32/Makefile.features b/cpu/esp32/Makefile.features index b38e1bf8c6a6..b905ca2a705e 100644 --- a/cpu/esp32/Makefile.features +++ b/cpu/esp32/Makefile.features @@ -6,7 +6,7 @@ include $(RIOTCPU)/esp_common/Makefile.features FEATURES_PROVIDED += arch_esp32 FEATURES_PROVIDED += esp_wifi_enterprise -FEATURES_PROVIDED += periph_adc_ctrl +FEATURES_PROVIDED += periph_adc_arch FEATURES_PROVIDED += puf_sram ifneq (,$(filter esp32-wrover%,$(CPU_MODEL))) diff --git a/cpu/esp32/include/adc_arch.h b/cpu/esp32/include/adc_arch.h index ec167c250815..7601ea11262c 100644 --- a/cpu/esp32/include/adc_arch.h +++ b/cpu/esp32/include/adc_arch.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2022 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 @@ -11,7 +11,14 @@ * @{ * * @file - * @brief Architecture specific ADC functions for ESP32 + * @brief Architecture specific ADC definitions and functions for ESP32 + * + * All ESP32x SoCs have two SAR ADC units each. However, these have + * functionalities as well as specific properties that vary between the + * ESP32x SoC and therefore require different handling for each ESP32x SoC. + * This is already taken into account in the high-level API of the ESP-IDF. + * To avoid having to reimplement these specifics and the different handling, + * the high-level API of the ESP-IDF is used directly for the ADC peripherals. * * @author Gunar Schorcht * @} @@ -24,17 +31,25 @@ extern "C" { #endif -#include "periph/gpio.h" #include "periph/adc.h" +#include "periph/gpio.h" + +#include "hal/adc_types.h" + +#include "esp_idf_api/adc.h" /** * @brief Attenuations that can be set for ADC lines + * + * Event though ESP-IDF type `adc_atten_t` and `ADC_ATTEN_DB_*` are used + * now, the `adc_attenuation_t` type with constants `ADC_ATTENUATION_*_DB` are + * kept for compatibility. */ typedef enum { - ADC_ATTENUATION_0_DB = 0, /**< full-range is about 1.1 V (Vref) */ - ADC_ATTENUATION_3_DB, /**< full-range is about 1.5 V */ - ADC_ATTENUATION_6_DB, /**< full-range is about 2.2 V */ - ADC_ATTENUATION_11_DB /**< full-range is about 3.3 V */ + ADC_ATTENUATION_0_DB = ADC_ATTEN_DB_0, /**< full-range is about 1.1 V (Vref) */ + ADC_ATTENUATION_3_DB = ADC_ATTEN_DB_2_5, /**< full-range is about 1.5 V */ + ADC_ATTENUATION_6_DB = ADC_ATTEN_DB_6, /**< full-range is about 2.2 V */ + ADC_ATTENUATION_11_DB = ADC_ATTEN_DB_11, /**< full-range is about 3.3 V */ } adc_attenuation_t; /** @@ -51,32 +66,57 @@ typedef enum { * * Attenuation | Voltage Range | Symbol * ----------------|-------------------|---------------------- - * 0 dB | 0 ... 1.1V (Vref) | ADC_ATTENUATION_0_DB - * 3 dB | 0 ... 1.5V | ADC_ATTENUATION_3_DB - * 6 dB | 0 ... 2.2V | ADC_ATTENUATION_6_DB - * 11 dB (default) | 0 ... 3.3V | ADC_ATTENUATION_11_DB + * 0 dB | 0 ... 1.1V (Vref) | ADC_ATTEN_DB_0 + * 2.5 dB | 0 ... 1.5V | ADC_ATTEN_DB_2_5 + * 6 dB | 0 ... 2.2V | ADC_ATTEN_DB_6 + * 11 dB (default) | 0 ... 3.3V | ADC_ATTEN_DB_11 * * * - * Please note: The reference voltage Vref can vary from device to device in - * the range of 1.0V and 1.2V. The Vref of a device can be read with the - * function *adc_vref_to_gpio25* at the pin GPIO 25. The results of the ADC - * input can then be adjusted accordingly. + * @note: The reference voltage Vref can vary from ADC unit to ADC unit in + * the range of 1.0V and 1.2V. The Vref of a unit can be routed with + * function *adc_vref_to_gpio* to a GPIO pin. * * @param line ADC line for which the attenuation is set * @param atten Attenuation, see type definition of *adc_attenuation_t - * @return 0 on success - * @return -1 on invalid ADC line + * @return 0 on success + * @return -1 on error + */ +int adc_set_attenuation(adc_t line, adc_atten_t atten); + +/** + * @brief Output reference voltage of a ADC line to GPIO n + * + * The Vref of the ADC unit of the given ADC line is routed to a GPIO pin n. + * This allows to measure the Vref used by the ADC unit to adjusted the + * results of the conversions accordingly. + * + * @note + * - The given GPIO must be a valid ADC channel of ADC2 unit. + * - For ESP32 and ESP32C3, the given ADC line has to be a channel of ADC2 unit. + * + * @param line ADC line for which Vref of its ADC unit is routed to the GPIO + * @param gpio GPIO to which Vref is routed (ADC2 channel GPIOs only) + * + * @return 0 on success + * @return -1 on error */ -int adc_set_attenuation(adc_t line, adc_attenuation_t atten); +int adc_line_vref_to_gpio(adc_t line, gpio_t gpio); +#if defined(MCU_ESP32) /** * @brief Output ADC reference voltage to GPIO25 * + * This function is deprecated and will be removed in future versions. + * * @return 0 on success * @return -1 on invalid ADC line */ -int adc_vref_to_gpio25 (void); +static inline int adc_vref_to_gpio25 (void) +{ + return esp_idf_adc_vref_to_gpio(ADC_UNIT_2, GPIO25); +} +#endif #ifdef __cplusplus } diff --git a/cpu/esp32/include/adc_arch_private.h b/cpu/esp32/include/adc_arch_private.h new file mode 100644 index 000000000000..f0b36854eefd --- /dev/null +++ b/cpu/esp32/include/adc_arch_private.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32 + * @{ + * + * @file + * @brief Architecture specific internal ADC functions for ESP32 + * + * @author Gunar Schorcht + * @} + */ + +#ifndef ADC_ARCH_PRIVATE_H +#define ADC_ARCH_PRIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "hal/adc_types.h" +#include "periph/gpio.h" + +#ifndef DOXYGEN /* hide implementation details from doxygen */ + +#define RTCIO_GPIO(n) n /* n-th RTCIO GPIO */ +#define RTCIO_NA UINT8_MAX /* RTCIO pin not available */ + +/** + * @brief ADC hardware descriptor (for internal use only) + */ +typedef struct { + uint8_t rtc_gpio; /**< RTC GPIO number */ + gpio_t gpio; /**< GPIO */ + adc_unit_t adc_ctrl; /**< ADC controller */ + adc_channel_t adc_channel; /**< channel of ADC controller */ + char* pad_name; /**< symbolic name of pad */ +} _adc_hw_desc_t; + +/** + * @brief ADC hardware descriptor table (for internal use only) + * + * @note The index of entries in the table MUST correspond to the + * RTCIO GPIO number. + */ +extern const _adc_hw_desc_t _adc_hw[]; + +/** + * @brief GPIO to RTC IO map (for internal use only) + */ +extern const gpio_t _gpio_rtcio_map[]; + +#endif /* !DOXYGEN */ + +#ifdef __cplusplus +} +#endif + +#endif /* ADC_ARCH_PRIVATE_H */ diff --git a/cpu/esp32/include/adc_ctrl.h b/cpu/esp32/include/adc_ctrl.h deleted file mode 100644 index 856fa7cd4022..000000000000 --- a/cpu/esp32/include/adc_ctrl.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -/** - * @ingroup cpu_esp32 - * @{ - * - * @file - * @brief ADC controller functions used by ADC and DAC peripherals - * - * @author Gunar Schorcht - * @} - */ - -#ifndef ADC_CTRL_H -#define ADC_CTRL_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "periph/gpio.h" - -/** - * @brief ADC controllers - */ -enum { - ADC1_CTRL, /**< ADC1 controller */ - ADC2_CTRL /**< ADC2 controller */ -}; - -/** - * @brief RTC IO pin type (does not correspond to RTC gpio num order) - */ -enum { - - RTCIO_TOUCH0 = 0, /**< touch sensor 0 */ - RTCIO_TOUCH1, /**< touch sensor 1 */ - RTCIO_TOUCH2, /**< touch sensor 2 */ - RTCIO_TOUCH3, /**< touch sensor 3 */ - RTCIO_TOUCH4, /**< touch sensor 4 */ - RTCIO_TOUCH5, /**< touch sensor 5 */ - RTCIO_TOUCH6, /**< touch sensor 6 */ - RTCIO_TOUCH7, /**< touch sensor 7 */ - RTCIO_TOUCH8, /**< touch sensor 8, 32K_XP */ - RTCIO_TOUCH9, /**< touch sensor 9, 32K_XN */ - - RTCIO_ADC_ADC1, /**< VDET_1 */ - RTCIO_ADC_ADC2, /**< VDET_2 */ - - RTCIO_SENSOR_SENSE1, /**< SENSOR_VP */ - RTCIO_SENSOR_SENSE2, /**< SENSOR_CAPP */ - RTCIO_SENSOR_SENSE3, /**< SENSOR_CAPN */ - RTCIO_SENSOR_SENSE4, /**< SENSOR_VN */ - - RTCIO_DAC1, /**< DAC output */ - RTCIO_DAC2, /**< DAC output */ - - RTCIO_NA, /**< RTC pad not available */ -}; - -/** - * @brief ADC pin hardware information type (for internal use only) - */ -struct _adc_hw_t { - gpio_t gpio; /**< GPIO */ - uint8_t rtc_gpio; /**< corresponding RTC GPIO */ - uint8_t adc_ctrl; /**< ADC controller */ - uint8_t adc_channel; /**< channel of ADC controller */ - char* pad_name; /**< symbolic name of pad */ -}; - -/** - * @brief RTC hardware map - * - * The index corresponds to RTC pin type _rtcio_pin_t (Table 19 in Technical - * Reference) - */ -extern const struct _adc_hw_t _adc_hw[]; - -#ifdef __cplusplus -} -#endif - -#endif /* ADC_CTRL_H */ diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index 133f7fcfc21a..168877bb2e8d 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2022 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 @@ -21,6 +21,8 @@ #include #include "sdkconfig.h" +#include "soc/periph_defs.h" +#include "soc/soc_caps.h" #ifdef __cplusplus extern "C" { @@ -238,24 +240,6 @@ typedef enum { * @{ */ -#ifndef DOXYGEN -/** - * @brief Possible ADC resolution settings - */ -#define HAVE_ADC_RES_T -typedef enum { - ADC_RES_6BIT = 0xf0, /**< ADC resolution: 6 bit is not supported */ - ADC_RES_8BIT = 0xf1, /**< ADC resolution: 8 bit is not supported */ - ADC_RES_9BIT = 0, /**< ADC resolution: 9 bit */ - ADC_RES_10BIT = 1, /**< ADC resolution: 10 bit */ - ADC_RES_11BIT = 2, /**< ADC resolution: 11 bit */ - ADC_RES_12BIT = 3, /**< ADC resolution: 12 bit */ - ADC_RES_14BIT = 0xf2, /**< ADC resolution: 14 bit is not supported */ - ADC_RES_16BIT = 0xf3, /**< ADC resolution: 16 bit is not supported */ -} adc_res_t; -/** @} */ -#endif /* ndef DOXYGEN */ - /** * @brief Number of ADC channels that could be used at maximum * @@ -263,7 +247,7 @@ typedef enum { * therefore not usable. The maximum number of ADC channels (ADC_NUMOF_MAX) * is therefore set to 16. */ -#define ADC_NUMOF_MAX 16 +#define ADC_NUMOF_MAX (SOC_ADC_CHANNEL_NUM(0) + SOC_ADC_CHANNEL_NUM(1)) /** @} */ diff --git a/cpu/esp32/periph/adc.c b/cpu/esp32/periph/adc.c index 1b88ac05604a..733c15d9ca01 100644 --- a/cpu/esp32/periph/adc.c +++ b/cpu/esp32/periph/adc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2022 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 @@ -14,61 +14,115 @@ * @file * @brief Low-level ADC driver implementation * + * All ESP32x SoCs have two SAR ADC units each. However, these have + * functionalities as well as specific properties that vary between the + * ESP32x SoC and therefore require different handling for each ESP32x SoC. + * This is already taken into account in the high-level API of the ESP-IDF. + * To avoid having to reimplement these specifics and the different handling, + * the high-level API of the ESP-IDF is used directly for the ADC peripherals. + * * @author Gunar Schorcht * * @} */ +#include + #include "board.h" #include "periph/adc.h" #include "adc_arch.h" -#include "adc_ctrl.h" +#include "adc_arch_private.h" #include "esp_common.h" #include "gpio_arch.h" -#include "soc/rtc_io_struct.h" -#include "soc/rtc_cntl_struct.h" -#include "soc/sens_reg.h" -#include "soc/sens_struct.h" + +#include "esp_idf_api/adc.h" #define ENABLE_DEBUG 0 #include "debug.h" -/* declaration of external functions */ -extern void _adc1_ctrl_init(void); -extern void _adc2_ctrl_init(void); - /* forward declarations of internal functions */ static bool _adc_conf_check(void); -static void _adc_module_init(void); -static bool _adc_module_initialized = false; +static void _adc1_ctrl_init(void); +static void _adc2_ctrl_init(void); /* external variable declarations */ extern const gpio_t _gpio_rtcio_map[]; +/* + * Structure for mapping RIOT's ADC resolutions to ESP-IDF resolutions + * of the according ESP32x SoC. + */ +typedef struct { + adc_bits_width_t res; /* used ESP-IDF resolution */ + unsigned shift; /* bit shift number for results */ +} _adc_esp_res_map_t; + +/* + * Table for resolution mapping + */ +_adc_esp_res_map_t _adc_esp_res_map[] = { +#if defined(MCU_ESP32) + { .res = ADC_WIDTH_BIT_9, .shift = 3 }, /* ADC_RES_6BIT */ + { .res = ADC_WIDTH_BIT_9, .shift = 1 }, /* ADC_RES_8BIT */ + { .res = ADC_WIDTH_BIT_10, .shift = 0 }, /* ADC_RES_10BIT */ + { .res = ADC_WIDTH_BIT_12, .shift = 0 }, /* ADC_RES_12BIT */ + { .res = ADC_WIDTH_MAX }, /* ADC_RES_14BIT */ + { .res = ADC_WIDTH_MAX }, /* ADC_RES_16BIT */ +#elif SOC_ADC_MAX_BITWIDTH == 12 + { .res = ADC_WIDTH_BIT_12, .shift = 6 }, /* ADC_RES_6BIT */ + { .res = ADC_WIDTH_BIT_12, .shift = 4 }, /* ADC_RES_8BIT */ + { .res = ADC_WIDTH_BIT_12, .shift = 2 }, /* ADC_RES_10BIT */ + { .res = ADC_WIDTH_BIT_12, .shift = 0 }, /* ADC_RES_12BIT */ + { .res = ADC_WIDTH_MAX }, /* ADC_RES_14BIT */ + { .res = ADC_WIDTH_MAX }, /* ADC_RES_16BIT */ +#elif SOC_ADC_MAX_BITWIDTH == 13 + { .res = ADC_WIDTH_BIT_13, .shift = 7 }, /* ADC_RES_6BIT */ + { .res = ADC_WIDTH_BIT_13, .shift = 5 }, /* ADC_RES_8BIT */ + { .res = ADC_WIDTH_BIT_13, .shift = 3 }, /* ADC_RES_10BIT */ + { .res = ADC_WIDTH_BIT_13, .shift = 1 }, /* ADC_RES_12BIT */ + { .res = ADC_WIDTH_MAX }, /* ADC_RES_14BIT */ + { .res = ADC_WIDTH_MAX }, /* ADC_RES_16BIT */ +#endif +}; + +static bool _adc_module_initialized = false; + +static inline void _adc1_ctrl_init(void) +{ + /* nothing to do for the moment */ +} + +static inline void _adc2_ctrl_init(void) +{ + /* nothing to do for the moment */ +} + int adc_init(adc_t line) { - CHECK_PARAM_RET (line < ADC_NUMOF, -1) + DEBUG("[adc] line=%u\n", line); + + if (line >= ADC_NUMOF) { + return -1; + } if (!_adc_module_initialized) { /* do some configuration checks */ if (!_adc_conf_check()) { return -1; } - _adc_module_init(); _adc_module_initialized = true; } + /* get the RTCIO pin number for the given GPIO defined as ADC channel */ uint8_t rtcio = _gpio_rtcio_map[adc_channels[line]]; - if (_adc_hw[rtcio].adc_ctrl == ADC1_CTRL) { - _adc1_ctrl_init(); - } - if (_adc_hw[rtcio].adc_ctrl == ADC2_CTRL) { - _adc2_ctrl_init(); + /* check whether the GPIO is avalid ADC channel pin */ + if (rtcio == RTCIO_NA) { + return -1; } - /* try to initialize the pin as ADC input */ + /* check whether the pin is not used for other purposes */ if (gpio_get_pin_usage(_adc_hw[rtcio].gpio) != _GPIO) { LOG_TAG_ERROR("adc", "GPIO%d is used for %s and cannot be used as " "ADC input\n", _adc_hw[rtcio].gpio, @@ -76,73 +130,25 @@ int adc_init(adc_t line) return -1; } - uint8_t idx; - - /* disable the pad output */ - RTCIO.enable_w1tc.val = BIT(_adc_hw[rtcio].rtc_gpio); - - /* route pads to RTC and if possible, disable input, pull-up/pull-down */ - switch (rtcio) { - case RTCIO_SENSOR_SENSE1: /* GPIO36, RTC0 */ - RTCIO.sensor_pads.sense1_mux_sel = 1; /* route to RTC */ - RTCIO.sensor_pads.sense1_fun_sel = 0; /* function ADC1_CH0 */ - break; - case RTCIO_SENSOR_SENSE2: /* GPIO37, RTC1 */ - RTCIO.sensor_pads.sense2_mux_sel = 1; /* route to RTC */ - RTCIO.sensor_pads.sense2_fun_sel = 0; /* function ADC1_CH1 */ - break; - case RTCIO_SENSOR_SENSE3: /* GPIO38, RTC2 */ - RTCIO.sensor_pads.sense3_mux_sel = 1; /* route to RTC */ - RTCIO.sensor_pads.sense3_fun_sel = 0; /* function ADC1_CH2 */ - break; - case RTCIO_SENSOR_SENSE4: /* GPIO39, RTC3 */ - RTCIO.sensor_pads.sense4_mux_sel = 1; /* route to RTC */ - RTCIO.sensor_pads.sense4_fun_sel = 0; /* function ADC1_CH3 */ - break; - - case RTCIO_TOUCH0: /* GPIO4, RTC10 */ - case RTCIO_TOUCH1: /* GPIO0, RTC11 */ - case RTCIO_TOUCH2: /* GPIO2, RTC12 */ - case RTCIO_TOUCH3: /* GPIO15, RTC13 */ - case RTCIO_TOUCH4: /* GPIO13, RTC14 */ - case RTCIO_TOUCH5: /* GPIO12, RTC15 */ - case RTCIO_TOUCH6: /* GPIO14, RTC16 */ - case RTCIO_TOUCH7: /* GPIO27, RTC17 */ - case RTCIO_TOUCH8: /* GPIO33, RTC8 */ - case RTCIO_TOUCH9: /* GPIO32, RTC9 */ - idx = rtcio - RTCIO_TOUCH0; - RTCIO.touch_pad[idx].mux_sel = 1; /* route to RTC */ - RTCIO.touch_pad[idx].fun_sel = 0; /* function ADC2_CH0..ADC2_CH9 */ - RTCIO.touch_pad[idx].fun_ie = 0; /* input disabled */ - RTCIO.touch_pad[idx].rue = 0; /* pull-up disabled */ - RTCIO.touch_pad[idx].rde = 0; /* pull-down disabled */ - RTCIO.touch_pad[idx].xpd = 0; /* touch sensor powered off */ - break; - - case RTCIO_ADC_ADC1: /* GPIO34, RTC4 */ - RTCIO.adc_pad.adc1_mux_sel = 1; /* route to RTC */ - RTCIO.adc_pad.adc1_fun_sel = 0; /* function ADC1_CH6 */ - break; - case RTCIO_ADC_ADC2: /* GPIO35, RTC5 */ - RTCIO.adc_pad.adc2_mux_sel = 1; /* route to RTC */ - RTCIO.adc_pad.adc2_fun_sel = 0; /* function ADC1_CH7 */ - break; - - case RTCIO_DAC1: /* GPIO25, RTC6 */ - case RTCIO_DAC2: /* GPIO26, RTC7 */ - idx = rtcio - RTCIO_DAC1; - RTCIO.pad_dac[idx].mux_sel = 1; /* route to RTC */ - RTCIO.pad_dac[idx].fun_sel = 0; /* function ADC2_CH8, ADC2_CH9 */ - RTCIO.pad_dac[idx].fun_ie = 0; /* input disabled */ - RTCIO.pad_dac[idx].rue = 0; /* pull-up disabled */ - RTCIO.pad_dac[idx].rde = 0; /* pull-down disabled */ - RTCIO.pad_dac[idx].xpd_dac = 0; /* DAC powered off */ - break; - - default: return -1; + if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_1) { + /* initialize the ADC1 unit if needed */ + _adc1_ctrl_init(); + /* set the attenuation and configure its associated GPIO pin mux */ + esp_idf_adc1_config_channel_atten(_adc_hw[rtcio].adc_channel, + ADC_ATTEN_DB_11); + } + else if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_2) { + /* initialize the ADC2 unit if needed */ + _adc2_ctrl_init(); + /* set the attenuation and configure its associated GPIO pin mux */ + esp_idf_adc2_config_channel_atten(_adc_hw[rtcio].adc_channel, + ADC_ATTEN_DB_11); + } + else { + return -1; } - /* set pin usage type */ + /* set pin usage type */ gpio_set_pin_usage(_adc_hw[rtcio].gpio, _ADC); return 0; @@ -150,95 +156,87 @@ int adc_init(adc_t line) int32_t adc_sample(adc_t line, adc_res_t res) { - CHECK_PARAM_RET (line < ADC_NUMOF, -1) - CHECK_PARAM_RET (res <= ADC_RES_12BIT, -1) - - uint8_t rtcio = _gpio_rtcio_map[adc_channels[line]]; + DEBUG("[adc] line=%u res=%u\n", line, res); - if (_adc_hw[rtcio].adc_ctrl == ADC1_CTRL) { - /* set the resolution for the measurement */ - SENS.sar_start_force.sar1_bit_width = res; - SENS.sar_read_ctrl.sar1_sample_bit = res; - - /* enable the pad in the pad enable bitmap */ - SENS.sar_meas_start1.sar1_en_pad = (1 << _adc_hw[rtcio].adc_channel); - while (SENS.sar_slave_addr1.meas_status != 0) {} - - /* start measurement by toggling the start bit and wait until the - measurement has been finished */ - SENS.sar_meas_start1.meas1_start_sar = 0; - SENS.sar_meas_start1.meas1_start_sar = 1; - while (SENS.sar_meas_start1.meas1_done_sar == 0) {} - - /* read out the result and return */ - return SENS.sar_meas_start1.meas1_data_sar; + if (_adc_esp_res_map[res].res == ADC_WIDTH_MAX) { + return -1; } - else { - /* set the resolution for the measurement */ - SENS.sar_start_force.sar2_bit_width = res; - SENS.sar_read_ctrl2.sar2_sample_bit = res; - - /* enable the pad in the pad enable bitmap */ - SENS.sar_meas_start2.sar2_en_pad = (1 << _adc_hw[rtcio].adc_channel); - /* start measurement by toggling the start bit and wait until the - measurement has been finished */ - SENS.sar_meas_start2.meas2_start_sar = 0; - SENS.sar_meas_start2.meas2_start_sar = 1; - while (SENS.sar_meas_start2.meas2_done_sar == 0) {} + uint8_t rtcio = _gpio_rtcio_map[adc_channels[line]]; + int raw; - /* read out the result and return */ - return SENS.sar_meas_start2.meas2_data_sar; + if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_1) { + esp_idf_adc1_config_width(_adc_esp_res_map[res].res); + raw = esp_idf_adc1_get_raw(_adc_hw[rtcio].adc_channel); + if (raw < 0) { + return -1; + } + } + else if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_2) { + if (esp_idf_adc2_get_raw(_adc_hw[rtcio].adc_channel, + _adc_esp_res_map[res].res, &raw) < 0) { + return -1; + } } + + return raw >> _adc_esp_res_map[res].shift; } -int adc_set_attenuation(adc_t line, adc_attenuation_t atten) +int adc_set_attenuation(adc_t line, adc_atten_t atten) { - CHECK_PARAM_RET (line < ADC_NUMOF, -1) + DEBUG("[adc] line=%u atten=%u\n", line, atten); uint8_t rtcio = _gpio_rtcio_map[adc_channels[line]]; - if (_adc_hw[rtcio].adc_ctrl == ADC1_CTRL) { - SENS.sar_atten1 &= ~(0x3 << (_adc_hw[rtcio].adc_channel << 1)); - SENS.sar_atten1 |= (atten << (_adc_hw[rtcio].adc_channel << 1)); + assert(rtcio != RTCIO_NA); + + if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_1) { + return esp_idf_adc1_config_channel_atten(_adc_hw[rtcio].adc_channel, + atten); } - else { - SENS.sar_atten2 &= ~(0x3 << (_adc_hw[rtcio].adc_channel << 1)); - SENS.sar_atten2 |= (atten << (_adc_hw[rtcio].adc_channel << 1)); + else if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_2) { + return esp_idf_adc2_config_channel_atten(_adc_hw[rtcio].adc_channel, + atten); } - return 0; + + return -1; } -int adc_vref_to_gpio25 (void) +int adc_line_vref_to_gpio(adc_t line, gpio_t gpio) { - /* determine ADC line for GPIO25 */ - adc_t line = ADC_UNDEF; - for (unsigned i = 0; i < ADC_NUMOF; i++) { \ - if (adc_channels[i] == GPIO25) { \ - line = i; - break; - } + uint8_t rtcio_vref = _gpio_rtcio_map[adc_channels[line]]; + uint8_t rtcio_out = _gpio_rtcio_map[gpio]; + + /* both the ADC line and the GPIO for the output must be ADC channels */ + assert(rtcio_vref != RTCIO_NA); + assert(rtcio_out != RTCIO_NA); + /* avoid compilation problems with NDEBUG defined */ + (void)rtcio_out; + + /* the GPIO for the output must be a channel of ADC2 */ + assert(_adc_hw[rtcio_out].adc_ctrl == ADC_UNIT_2); +#if defined(MCU_ESP32) || defined(MCU_ESP32C3) + /* for ESP32 and ESP32C3, given ADC line has to be a channel of ADC2 */ + assert(_adc_hw[rtcio_vref].adc_ctrl == ADC_UNIT_2); +#endif + + esp_err_t res = ESP_OK; + + if (_adc_hw[rtcio_vref].adc_ctrl == ADC_UNIT_1) { + res = esp_idf_adc_vref_to_gpio(ADC_UNIT_1, gpio); } - - if (line == ADC_UNDEF) { - LOG_TAG_ERROR("adc", "Have no ADC line for GPIO25\n"); - return -1; + else if (_adc_hw[rtcio_vref].adc_ctrl == ADC_UNIT_2) { + res = esp_idf_adc_vref_to_gpio(ADC_UNIT_2, gpio); } - - if (adc_init(line) == 0) - { - uint8_t rtcio = _gpio_rtcio_map[adc_channels[line]]; - RTCCNTL.bias_conf.dbg_atten = 0; - RTCCNTL.test_mux.dtest_rtc = 1; - RTCCNTL.test_mux.ent_rtc = 1; - SENS.sar_start_force.sar2_en_test = 1; - SENS.sar_meas_start2.sar2_en_pad = (1 << _adc_hw[rtcio].adc_channel); - LOG_TAG_INFO("adc", "You can now measure Vref at GPIO25\n"); - return 0; + if (res != ESP_OK) { + LOG_TAG_ERROR("adc", "Could not route Vref of ADC line %d to GPIO%d\n", + line, gpio); + return -1; } else { - LOG_TAG_ERROR("adc", "Could not init GPIO25 as Vref output\n"); - return -1; + LOG_TAG_ERROR("adc", "Vref of ADC%d can now be measured at GPIO %d\n", + _adc_hw[rtcio_vref].adc_ctrl, gpio); + return 0; } } @@ -255,18 +253,6 @@ static bool _adc_conf_check(void) return true; } -static void _adc_module_init(void) -{ - RTCIO.enable_w1tc.val = ~0x0; - - /* always power on */ - SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; - - /* disable temperature sensor */ - SENS.sar_tctrl.tsens_power_up_force = 1; /* controlled by SW */ - SENS.sar_tctrl.tsens_power_up = 0; /* power down */ -} - void adc_print_config(void) { printf("\tADC\t\tpins=[ "); diff --git a/cpu/esp32/periph/adc_arch.c b/cpu/esp32/periph/adc_arch.c new file mode 100644 index 000000000000..1a9182be2152 --- /dev/null +++ b/cpu/esp32/periph/adc_arch.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32 + * @{ + * + * @file + * @brief Architecture-specific ADC/DAC definitions for ESP32 variant (family) + * + * @author Gunar Schorcht + * + * @} + */ + +#include "board.h" + +#include "adc_arch_private.h" +#include "esp_common.h" +#include "soc/adc_channel.h" + + +#define ENABLE_DEBUG 0 +#include "debug.h" + +/** + * @brief ADC hardware descriptor table (for internal use only) + * + * Reference: Technical Reference Manual, Section 4.11 Table 19 + * https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf + * + * @note The index of entries in the table MUST correspond to the + * RTCIO GPIO number. + */ +const _adc_hw_desc_t _adc_hw[] = { + /* rtcio, gpio, adc_ctrl, adc_channel, pad_name */ + { RTCIO_GPIO(0), ADC1_CHANNEL_0_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_0, "SENSOR_VP" }, + { RTCIO_GPIO(1), ADC1_CHANNEL_1_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_1, "SENSOR_CAPP" }, + { RTCIO_GPIO(2), ADC1_CHANNEL_2_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_2, "SENSOR_CAPN" }, + { RTCIO_GPIO(3), ADC1_CHANNEL_3_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_3, "SENSOR_VN" }, + { RTCIO_GPIO(4), ADC1_CHANNEL_6_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_6, "VDET_1" }, + { RTCIO_GPIO(5), ADC1_CHANNEL_7_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_7, "VDET_2" }, + { RTCIO_GPIO(6), ADC2_CHANNEL_8_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_8, "GPIO25" }, + { RTCIO_GPIO(7), ADC2_CHANNEL_9_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_9, "GPIO26" }, + { RTCIO_GPIO(8), ADC1_CHANNEL_5_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_5, "32K_XN" }, + { RTCIO_GPIO(9), ADC1_CHANNEL_4_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_4, "32K_XP" }, + { RTCIO_GPIO(10), ADC2_CHANNEL_0_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_0, "GPIO4" }, + { RTCIO_GPIO(11), ADC2_CHANNEL_1_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_1, "GPIO0" }, + { RTCIO_GPIO(12), ADC2_CHANNEL_2_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_2, "GPIO2" }, + { RTCIO_GPIO(13), ADC2_CHANNEL_3_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_3, "MTDO" }, + { RTCIO_GPIO(14), ADC2_CHANNEL_4_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_4, "MTCK" }, + { RTCIO_GPIO(15), ADC2_CHANNEL_5_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_5, "MTDI" }, + { RTCIO_GPIO(16), ADC2_CHANNEL_6_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_6, "MTMS" }, + { RTCIO_GPIO(17), ADC2_CHANNEL_7_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_7, "GPIO27" }, +}; + +/** + * @brief GPIO to RTC IO map (for internal use only) + * + * Reference: Technical Reference Manual, Section 4.11 Table 19 + * https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf + */ +const gpio_t _gpio_rtcio_map[] = { + RTCIO_GPIO(11), /* GPIO0 */ + RTCIO_NA, /* GPIO1 */ + RTCIO_GPIO(12), /* GPIO2 */ + RTCIO_NA, /* GPIO3 */ + RTCIO_GPIO(10), /* GPIO4 */ + RTCIO_NA, /* GPIO5 */ + RTCIO_NA, /* GPIO6 */ + RTCIO_NA, /* GPIO7 */ + RTCIO_NA, /* GPIO8 */ + RTCIO_NA, /* GPIO9 */ + RTCIO_NA, /* GPIO10 */ + RTCIO_NA, /* GPIO11 */ + RTCIO_GPIO(15), /* GPIO12 MTDI */ + RTCIO_GPIO(14), /* GPIO13 MTCK */ + RTCIO_GPIO(16), /* GPIO14 MTMS */ + RTCIO_GPIO(13), /* GPIO15 MTDO */ + RTCIO_NA, /* GPIO16 */ + RTCIO_NA, /* GPIO17 */ + RTCIO_NA, /* GPIO18 */ + RTCIO_NA, /* GPIO19 */ + RTCIO_NA, /* GPIO20 */ + RTCIO_NA, /* GPIO21 */ + RTCIO_NA, /* GPIO22 */ + RTCIO_NA, /* GPIO23 */ + RTCIO_NA, /* GPIO24 */ + RTCIO_GPIO(6), /* GPIO25 */ + RTCIO_GPIO(7), /* GPIO26 */ + RTCIO_GPIO(17), /* GPIO27 */ + RTCIO_NA, /* GPIO28 */ + RTCIO_NA, /* GPIO29 */ + RTCIO_NA, /* GPIO30 */ + RTCIO_NA, /* GPIO31 */ + RTCIO_GPIO(9), /* GPIO32 32K_XP */ + RTCIO_GPIO(8), /* GPIO33 32K_XN */ + RTCIO_GPIO(4), /* GPIO34 VDET_1 */ + RTCIO_GPIO(5), /* GPIO35 VDET_2 */ + RTCIO_GPIO(0), /* GPIO36 SENSOR_VP */ + RTCIO_GPIO(1), /* GPIO37 SENSOR_CAPP */ + RTCIO_GPIO(2), /* GPIO38 SENSOR_CAPN */ + RTCIO_GPIO(3), /* GPIO39 SENSOR_VN */ +}; diff --git a/cpu/esp32/periph/adc_ctrl.c b/cpu/esp32/periph/adc_ctrl.c deleted file mode 100644 index 2c7655157897..000000000000 --- a/cpu/esp32/periph/adc_ctrl.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -/** - * @ingroup cpu_esp32 - * @{ - * - * @file - * @brief ADC controller functions used by ADC and DAC peripherals - * - * @author Gunar Schorcht - * - * @} - */ - -#include "board.h" - -#include "adc_ctrl.h" -#include "esp_common.h" -#include "soc/rtc_io_struct.h" -#include "soc/rtc_cntl_struct.h" -#include "soc/sens_reg.h" -#include "soc/sens_struct.h" - -#define ENABLE_DEBUG 0 -#include "debug.h" - -/** - * @brief RTC hardware map - * - * The index corresponds to RTC pin type _rtcio_pin_t (Table 19 in Technical - * Reference) - */ -const struct _adc_hw_t _adc_hw[] = -{ - /* gpio rtc_gpio adc_ctrl adc_channel, pad_name */ - { GPIO4, 10, ADC2_CTRL, 0, "GPIO4" }, /* RTCIO_TOUCH0 */ - { GPIO0, 11, ADC2_CTRL, 1, "GPIO0" }, /* RTCIO_TOUCH1 */ - { GPIO2, 12, ADC2_CTRL, 2, "GPIO2" }, /* RTCIO_TOUCH2 */ - { GPIO15, 13, ADC2_CTRL, 3, "MTDO" }, /* RTCIO_TOUCH3 */ - { GPIO13, 14, ADC2_CTRL, 4, "MTCK" }, /* RTCIO_TOUCH4 */ - { GPIO12, 15, ADC2_CTRL, 5, "MTDI" }, /* RTCIO_TOUCH5 */ - { GPIO14, 16, ADC2_CTRL, 6, "MTMS" }, /* RTCIO_TOUCH6 */ - { GPIO27, 17, ADC2_CTRL, 7, "GPIO27" }, /* RTCIO_TOUCH7 */ - { GPIO33, 8, ADC1_CTRL, 5, "32K_XN" }, /* RTCIO_TOUCH8 */ - { GPIO32, 9, ADC1_CTRL, 4, "32K_XP" }, /* RTCIO_TOUCH9 */ - { GPIO34, 4, ADC1_CTRL, 6, "VDET_1" }, /* RTCIO_ADC_ADC1 */ - { GPIO35, 5, ADC1_CTRL, 7, "VDET_2" }, /* RTCIO_ADC_ADC2 */ - { GPIO36, 0, ADC1_CTRL, 0, "SENSOR_VP" }, /* RTCIO_SENSOR_SENSE1 */ - { GPIO37, 1, ADC1_CTRL, 1, "SENSOR_CAPP" }, /* RTCIO_SENSOR_SENSE2 */ - { GPIO38, 2, ADC1_CTRL, 2, "SENSOR_CAPN" }, /* RTCIO_SENSOR_SENSE3 */ - { GPIO39, 3, ADC1_CTRL, 3, "SENSOR_VN" }, /* RTCIO_SENSOR_SENSE4 */ - { GPIO25, 6, ADC2_CTRL, 8, "GPIO25" }, /* RTCIO_DAC1 */ - { GPIO26, 7, ADC2_CTRL, 9, "GPIO26" } /* RTCIO_DAC2 */ -}; - -/* maps GPIO pin to RTC pin, this index is used to access ADC hardware table - (Table 19 in Technical Reference) */ -const gpio_t _gpio_rtcio_map[] = { - RTCIO_TOUCH1, /* GPIO0 */ - RTCIO_NA , /* GPIO1 */ - RTCIO_TOUCH2, /* GPIO2 */ - RTCIO_NA, /* GPIO3 */ - RTCIO_TOUCH0, /* GPIO4 */ - RTCIO_NA, /* GPIO5 */ - RTCIO_NA, /* GPIO6 */ - RTCIO_NA, /* GPIO7 */ - RTCIO_NA, /* GPIO8 */ - RTCIO_NA, /* GPIO9 */ - RTCIO_NA, /* GPIO10 */ - RTCIO_NA, /* GPIO11 */ - RTCIO_TOUCH5, /* GPIO12 MTDI */ - RTCIO_TOUCH4, /* GPIO13 MTCK */ - RTCIO_TOUCH6, /* GPIO14 MTMS */ - RTCIO_TOUCH3, /* GPIO15 MTDO */ - RTCIO_NA, /* GPIO16 */ - RTCIO_NA, /* GPIO17 */ - RTCIO_NA, /* GPIO18 */ - RTCIO_NA, /* GPIO19 */ - RTCIO_NA, /* GPIO20 */ - RTCIO_NA, /* GPIO21 */ - RTCIO_NA, /* GPIO22 */ - RTCIO_NA, /* GPIO23 */ - RTCIO_NA, /* GPIO24 */ - RTCIO_DAC1, /* GPIO25 */ - RTCIO_DAC2, /* GPIO26 */ - RTCIO_TOUCH7, /* GPIO27 */ - RTCIO_NA, /* GPIO28 */ - RTCIO_NA, /* GPIO29 */ - RTCIO_NA, /* GPIO30 */ - RTCIO_NA, /* GPIO31 */ - RTCIO_TOUCH9, /* GPIO32 32K_XP */ - RTCIO_TOUCH8, /* GPIO33 32K_XN */ - RTCIO_ADC_ADC1, /* GPIO34 VDET_1 */ - RTCIO_ADC_ADC2, /* GPIO35 VDET_2 */ - RTCIO_SENSOR_SENSE1, /* GPIO36 SENSOR_VP */ - RTCIO_SENSOR_SENSE2, /* GPIO37 SENSOR_CAPP */ - RTCIO_SENSOR_SENSE3, /* GPIO38 SENSOR_CAPN */ - RTCIO_SENSOR_SENSE4, /* GPIO39 SENSOR_VN */ -}; - -/* flags to indicate whether the according controller is already initialized */ -static bool _adc1_ctrl_initialized = false; -static bool _adc2_ctrl_initialized = false; - -void _adc1_ctrl_init(void) -{ - /* return if already initialized */ - if (_adc1_ctrl_initialized) { - return; - } - - /* always power on */ - SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; - - /* power off LN amp */ - SENS.sar_meas_wait2.sar2_rstb_wait = 2; - SENS.sar_meas_ctrl.amp_rst_fb_fsm = 0; - SENS.sar_meas_ctrl.amp_short_ref_fsm = 0; - SENS.sar_meas_ctrl.amp_short_ref_gnd_fsm = 0; - SENS.sar_meas_wait1.sar_amp_wait1 = 1; - SENS.sar_meas_wait1.sar_amp_wait2 = 1; - SENS.sar_meas_wait2.sar_amp_wait3 = 1; - SENS.sar_meas_wait2.force_xpd_amp = SENS_FORCE_XPD_AMP_PD; - - /* SAR ADC1 controller configuration */ - SENS.sar_read_ctrl.sar1_dig_force = 0; /* SAR ADC1 controlled by RTC */ - SENS.sar_meas_start1.meas1_start_force = 1; /* SAR ADC1 started by SW */ - SENS.sar_meas_start1.sar1_en_pad_force = 1; /* pad enable bitmap controlled by SW */ - SENS.sar_touch_ctrl1.xpd_hall_force = 1; /* XPD HALL is controlled by SW */ - SENS.sar_touch_ctrl1.hall_phase_force = 1; /* HALL PHASE is controlled by SW */ - SENS.sar_read_ctrl.sar1_data_inv = 1; /* invert data */ - SENS.sar_atten1 = 0xffffffff; /* set attenuation to 11 dB for all pads - (input range 0 ... 3,3 V) */ - /* power off built-in hall sensor */ - RTCIO.hall_sens.xpd_hall = 0; - - /* set default resolution */ - SENS.sar_start_force.sar1_bit_width = ADC_RES_12BIT; - SENS.sar_read_ctrl.sar1_sample_bit = ADC_RES_12BIT; - - _adc1_ctrl_initialized = true; -} - -void _adc2_ctrl_init(void) -{ - /* return if already initialized */ - if (_adc2_ctrl_initialized) { - return; - } - - /* SAR ADC2 controller configuration */ - SENS.sar_read_ctrl2.sar2_dig_force = 0; /* SAR ADC2 controlled by RTC not DIG*/ - SENS.sar_meas_start2.meas2_start_force = 1; /* SAR ADC2 started by SW */ - SENS.sar_meas_start2.sar2_en_pad_force = 1; /* pad enable bitmap controlled by SW */ - SENS.sar_read_ctrl2.sar2_data_inv = 1; /* invert data */ - SENS.sar_atten2 = 0xffffffff; /* set attenuation to 11 dB for all pads - (input range 0 ... 3,3 V) */ - /* set default resolution */ - SENS.sar_start_force.sar2_bit_width = ADC_RES_12BIT; - SENS.sar_read_ctrl2.sar2_sample_bit = ADC_RES_12BIT; - - _adc2_ctrl_initialized = true; -} From 3a2e361afb088f8db4fd9292dcb1dd6aedca22de Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 18:18:08 +0100 Subject: [PATCH 15/46] cpu/esp32: add periph_ctrl to ESP-IDF interface API --- cpu/esp32/esp-idf-api/periph_ctrl.c | 30 ++++++++++++++++ cpu/esp32/include/esp_idf_api/periph_ctrl.h | 39 +++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 cpu/esp32/esp-idf-api/periph_ctrl.c create mode 100644 cpu/esp32/include/esp_idf_api/periph_ctrl.h diff --git a/cpu/esp32/esp-idf-api/periph_ctrl.c b/cpu/esp32/esp-idf-api/periph_ctrl.c new file mode 100644 index 000000000000..d9e69b2e925c --- /dev/null +++ b/cpu/esp32/esp-idf-api/periph_ctrl.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32_esp_idf_api + * @{ + * + * @file + * @brief Interface for ESP-IDF peripherals control API + * + * @author Gunar Schorcht + * @} + */ + +#include "driver/periph_ctrl.h" + +void esp_idf_periph_module_enable(periph_module_t periph) +{ + periph_module_enable(periph); +} + +void esp_idf_periph_module_disable(periph_module_t periph) +{ + periph_module_disable(periph); +} diff --git a/cpu/esp32/include/esp_idf_api/periph_ctrl.h b/cpu/esp32/include/esp_idf_api/periph_ctrl.h new file mode 100644 index 000000000000..017ab009cfd1 --- /dev/null +++ b/cpu/esp32/include/esp_idf_api/periph_ctrl.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32_esp_idf_api + * @{ + * + * @file + * @brief Interface for ESP-IDF peripherals control API + * + * @author Gunar Schorcht + * @} + */ + +#ifndef ESP_IDF_API_PERIPH_CTRL_H +#define ESP_IDF_API_PERIPH_CTRL_H + +#ifndef DOXYGEN /* Hide implementation details from doxygen */ + +#include "soc/periph_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void esp_idf_periph_module_enable(periph_module_t periph); +void esp_idf_periph_module_disable(periph_module_t periph); + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* ESP_IDF_API_PERIPH_CTRL_H */ From 0631f146c76385df82d1d06d69616bc6e4a4d87c Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 18:19:11 +0100 Subject: [PATCH 16/46] cpu/esp32: add gpio to ESP-IDF interface API --- cpu/esp32/esp-idf-api/gpio.c | 133 +++++++++++++++++++++++++++ cpu/esp32/esp-idf/gpio/Makefile | 3 + cpu/esp32/include/esp_idf_api/gpio.h | 62 +++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 cpu/esp32/esp-idf-api/gpio.c create mode 100644 cpu/esp32/include/esp_idf_api/gpio.h diff --git a/cpu/esp32/esp-idf-api/gpio.c b/cpu/esp32/esp-idf-api/gpio.c new file mode 100644 index 000000000000..1f99013eacb0 --- /dev/null +++ b/cpu/esp32/esp-idf-api/gpio.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32_esp_idf_api + * @{ + * + * @file + * @brief Interface for the ESP-IDF GPIO HAL API + * + * @author Gunar Schorcht + * @} + */ + +#include + +#include "driver/gpio.h" +#include "driver/rtc_io.h" +#include "hal/gpio_hal.h" +#include "esp_sleep.h" + +#include "esp_idf_api/gpio.h" + +esp_err_t esp_idf_gpio_config(const gpio_config_t *cfg) +{ + return gpio_config(cfg); +} + +esp_err_t esp_idf_gpio_intr_enable(gpio_num_t gpio_num) +{ + return gpio_intr_enable(gpio_num); +} + +esp_err_t esp_idf_gpio_intr_disable(gpio_num_t gpio_num) +{ + return gpio_intr_disable(gpio_num); +} + +esp_err_t esp_idf_gpio_set_intr_type(gpio_num_t gpio_num, + gpio_int_type_t intr_type) +{ + return gpio_set_intr_type(gpio_num, intr_type); +} + +esp_err_t esp_idf_gpio_install_isr_service(int intr_alloc_flags) + +{ + return gpio_install_isr_service(intr_alloc_flags); +} + +esp_err_t esp_idf_gpio_isr_handler_add(gpio_num_t gpio_num, + gpio_isr_t isr_handler, void *args) + +{ + return gpio_isr_handler_add(gpio_num, isr_handler, args); +} + +esp_err_t esp_idf_gpio_wakeup_enable(gpio_num_t gpio_num, + gpio_int_type_t intr_type) + +{ + return gpio_wakeup_enable(gpio_num, intr_type); +} + +#ifdef ESP_PM_GPIO_HOLD +esp_err_t esp_idf_gpio_deep_sleep_hold(void) +{ +#if SOC_RTCIO_HOLD_SUPPORTED + extern esp_err_t rtc_gpio_force_hold_en_all(void); + return rtc_gpio_force_hold_en_all(); +#elif SOC_GPIO_SUPPORT_FORCE_HOLD + gpio_deep_sleep_hold_en(); + return ESP_OK; +#else + _Static_assert(0, "ESP32x SoC does not support hold feature in deep sleep"); + return ESP_FAIL; +#endif +#if CPU_FAM_ESP32 + /* isolating GPIO12 from external circuits is especially recommended for + * ESP32-WROVER that have an external pullup on GPIO12 */ + rtc_gpio_isolate(GPIO_NUM_12); +#endif +} +#endif /* ESP_PM_GPIO_HOLD */ + +#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED +esp_err_t esp_idf_rtc_gpio_deinit(gpio_num_t gpio_num) + +{ + if (!rtc_gpio_is_valid_gpio(gpio_num)) { + return ESP_ERR_INVALID_ARG; + } + return rtc_gpio_deinit(gpio_num); +} + +esp_err_t esp_idf_rtc_gpio_pullup_en(gpio_num_t gpio_num) +{ + if (!rtc_gpio_is_valid_gpio(gpio_num)) { + return ESP_ERR_INVALID_ARG; + } + return rtc_gpio_pullup_en(gpio_num); +} + +esp_err_t esp_idf_rtc_gpio_pullup_dis(gpio_num_t gpio_num) +{ + if (!rtc_gpio_is_valid_gpio(gpio_num)) { + return ESP_ERR_INVALID_ARG; + } + return rtc_gpio_pullup_dis(gpio_num); +} + +esp_err_t esp_idf_rtc_gpio_pulldown_en(gpio_num_t gpio_num) +{ + if (!rtc_gpio_is_valid_gpio(gpio_num)) { + return ESP_ERR_INVALID_ARG; + } + return rtc_gpio_pulldown_en(gpio_num); +} + +esp_err_t esp_idf_rtc_gpio_pulldown_dis(gpio_num_t gpio_num) +{ + if (!rtc_gpio_is_valid_gpio(gpio_num)) { + return ESP_ERR_INVALID_ARG; + } + return rtc_gpio_pulldown_dis(gpio_num); +} + +#endif diff --git a/cpu/esp32/esp-idf/gpio/Makefile b/cpu/esp32/esp-idf/gpio/Makefile index d0b5d0a233d0..d6612517a378 100644 --- a/cpu/esp32/esp-idf/gpio/Makefile +++ b/cpu/esp32/esp-idf/gpio/Makefile @@ -3,6 +3,9 @@ MODULE = esp_idf_gpio # source files to be compiled for this module ESP32_SDK_SRC = \ components/driver/gpio.c \ + components/driver/rtc_io.c \ + components/driver/rtc_module.c \ + components/hal/gpio_hal.c \ components/soc/$(CPU)/gpio_periph.c \ # diff --git a/cpu/esp32/include/esp_idf_api/gpio.h b/cpu/esp32/include/esp_idf_api/gpio.h new file mode 100644 index 000000000000..d5b349204407 --- /dev/null +++ b/cpu/esp32/include/esp_idf_api/gpio.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32_esp_idf_api + * @{ + * + * @file + * @brief Interface for the ESP-IDF GPIO API + * + * @author Gunar Schorcht + * @} + */ + +#ifndef ESP_IDF_API_GPIO_H +#define ESP_IDF_API_GPIO_H + +#include "esp_err.h" + +#ifndef DOXYGEN /* Hide implementation details from doxygen */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name ESP-IDF interface wrapper functions + * @{ + */ +esp_err_t esp_idf_gpio_config(const gpio_config_t *cfg); + +esp_err_t esp_idf_gpio_intr_enable(gpio_num_t gpio_num); +esp_err_t esp_idf_gpio_intr_disable(gpio_num_t gpio_num); +esp_err_t esp_idf_gpio_set_intr_type(gpio_num_t gpio_num, + gpio_int_type_t intr_type); +esp_err_t esp_idf_gpio_install_isr_service(int intr_alloc_flags); +esp_err_t esp_idf_gpio_isr_handler_add(gpio_num_t gpio_num, + gpio_isr_t isr_handler, void *args); + +esp_err_t esp_idf_gpio_wakeup_enable(gpio_num_t gpio_num, + gpio_int_type_t intr_type); +esp_err_t esp_idf_gpio_deep_sleep_hold(void); + +esp_err_t esp_idf_rtc_gpio_deinit(gpio_num_t gpio_num); +esp_err_t esp_idf_rtc_gpio_pullup_en(gpio_num_t gpio_num); +esp_err_t esp_idf_rtc_gpio_pullup_dis(gpio_num_t gpio_num); +esp_err_t esp_idf_rtc_gpio_pulldown_en(gpio_num_t gpio_num); +esp_err_t esp_idf_rtc_gpio_pulldown_dis(gpio_num_t gpio_num); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* ESP_IDF_API_GPIO_H */ From 07d731a01cd3b3afdf917b0dcd105136a68be440 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 18:20:19 +0100 Subject: [PATCH 17/46] cpu/esp32: add dac to ESP-IDF interface API --- cpu/esp32/esp-idf-api/dac.c | 37 +++++++++++++++++++++++ cpu/esp32/include/esp_idf_api/dac.h | 47 +++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 cpu/esp32/esp-idf-api/dac.c create mode 100644 cpu/esp32/include/esp_idf_api/dac.h diff --git a/cpu/esp32/esp-idf-api/dac.c b/cpu/esp32/esp-idf-api/dac.c new file mode 100644 index 000000000000..33ff6cdd9f7b --- /dev/null +++ b/cpu/esp32/esp-idf-api/dac.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32_esp_idf_api + * @{ + * + * @file + * @brief Interface for the ESP-IDF DAC HAL API + * + * @author Gunar Schorcht + * @} + */ + +#include + +#include "driver/dac_common.h" + +esp_err_t esp_idf_dac_output_voltage(dac_channel_t channel, uint8_t dac_value) +{ + return dac_output_voltage(channel, dac_value); +} + +esp_err_t esp_idf_dac_output_enable(dac_channel_t channel) +{ + return dac_output_enable(channel); +} + +esp_err_t esp_idf_dac_output_disable(dac_channel_t channel) +{ + return dac_output_disable(channel); +} diff --git a/cpu/esp32/include/esp_idf_api/dac.h b/cpu/esp32/include/esp_idf_api/dac.h new file mode 100644 index 000000000000..8ee0b7de9c48 --- /dev/null +++ b/cpu/esp32/include/esp_idf_api/dac.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32_esp_idf_api + * @{ + * + * @file + * @brief Interface for the ESP-IDF DAC HAL API + * + * @author Gunar Schorcht + * @} + */ + +#ifndef ESP_IDF_API_DAC_H +#define ESP_IDF_API_DAC_H + +#include "esp_err.h" +#include "hal/dac_types.h" + +#ifndef DOXYGEN /* Hide implementation details from doxygen */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name ESP-IDF interface wrapper functions + * @{ + */ +esp_err_t esp_idf_dac_output_voltage(dac_channel_t channel, uint8_t dac_value); +esp_err_t esp_idf_dac_output_enable(dac_channel_t channel); +esp_err_t esp_idf_dac_output_disable(dac_channel_t channel); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* ESP_IDF_API_DAC_H */ From 246349233395dd9bc29930d5b03fa103c2527f0c Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 18:20:51 +0100 Subject: [PATCH 18/46] cpu/esp32: add ledc to ESP-IDF interface API --- cpu/esp32/esp-idf-api/ledc.c | 44 +++++++++++++++++++++++++ cpu/esp32/include/esp_idf_api/ledc.h | 48 ++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 cpu/esp32/esp-idf-api/ledc.c create mode 100644 cpu/esp32/include/esp_idf_api/ledc.h diff --git a/cpu/esp32/esp-idf-api/ledc.c b/cpu/esp32/esp-idf-api/ledc.c new file mode 100644 index 000000000000..74a3dcb140ca --- /dev/null +++ b/cpu/esp32/esp-idf-api/ledc.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32_esp_idf_api + * @{ + * + * @file + * @brief Interface for the ESP-IDF LEDC HAL API + * + * @author Gunar Schorcht + * @} + */ + +#include + +#include "driver/ledc.h" + +int esp_ledc_channel_config(const ledc_channel_config_t* ledc_conf) +{ + return ledc_channel_config(ledc_conf); +} + +int esp_ledc_timer_config(const ledc_timer_config_t* timer_conf) +{ + return ledc_timer_config(timer_conf); +} + +int esp_ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel) +{ + return ledc_update_duty(speed_mode, channel); +} + +int esp_ledc_set_duty_with_hpoint(ledc_mode_t speed_mode, + ledc_channel_t channel, + uint32_t duty, uint32_t hpoint) +{ + return ledc_set_duty_with_hpoint(speed_mode, channel, duty, hpoint); +} diff --git a/cpu/esp32/include/esp_idf_api/ledc.h b/cpu/esp32/include/esp_idf_api/ledc.h new file mode 100644 index 000000000000..442360ff55c1 --- /dev/null +++ b/cpu/esp32/include/esp_idf_api/ledc.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32_esp_idf_api + * @{ + * + * @file + * @brief Interface for the ESP-IDF LEDC HAL API + * + * @author Gunar Schorcht + * @} + */ + +#ifndef ESP_IDF_API_LEDC_H +#define ESP_IDF_API_LEDC_H + +#include "hal/ledc_types.h" + +#ifndef DOXYGEN /* Hide implementation details from doxygen */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name ESP-IDF interface wrapper functions + * @{ + */ +int esp_ledc_channel_config(const ledc_channel_config_t* ledc_conf); +int esp_ledc_timer_config(const ledc_timer_config_t* timer_conf); +int esp_ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel); +int esp_ledc_set_duty_with_hpoint(ledc_mode_t speed_mode, + ledc_channel_t channel, + uint32_t duty, uint32_t hpoint); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* ESP_IDF_API_LEDC_H */ From ec3937f3510a4343977510ba2bbf0411432afe16 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 18:21:34 +0100 Subject: [PATCH 19/46] cpu/esp32: add uart to ESP-IDF interface API --- cpu/esp32/esp-idf-api/uart.c | 51 ++++++++++++++++++++++++++++ cpu/esp32/include/esp_idf_api/uart.h | 36 ++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 cpu/esp32/esp-idf-api/uart.c create mode 100644 cpu/esp32/include/esp_idf_api/uart.h diff --git a/cpu/esp32/esp-idf-api/uart.c b/cpu/esp32/esp-idf-api/uart.c new file mode 100644 index 000000000000..143bb41c698b --- /dev/null +++ b/cpu/esp32/esp-idf-api/uart.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32_esp_idf_api + * @{ + * + * @file + * @brief Interface for the ESP-IDF UART HAL API + * + * @author Gunar Schorcht + * @} + */ + +#include +#include + +#include "driver/uart.h" +#include "hal/uart_hal.h" + +#include "esp_idf_api/uart.h" + +static uart_hal_context_t _uart_hal_ctx[] = { +#if UART_NUM_MAX >= 1 + { + .dev = UART_LL_GET_HW(0), + }, +#endif +#if UART_NUM_MAX >= 2 + { + .dev = UART_LL_GET_HW(1), + }, +#endif +#if UART_NUM_MAX >= 3 + { + .dev = UART_LL_GET_HW(2), + }, +#endif +}; + +void esp_idf_uart_set_wakeup_threshold(unsigned uart_num, uint32_t threshold) +{ + assert(uart_num < sizeof(_uart_hal_ctx)/sizeof(_uart_hal_ctx[0])); + uart_hal_set_wakeup_thrd(&_uart_hal_ctx[uart_num], threshold); +} + diff --git a/cpu/esp32/include/esp_idf_api/uart.h b/cpu/esp32/include/esp_idf_api/uart.h new file mode 100644 index 000000000000..22b370cef721 --- /dev/null +++ b/cpu/esp32/include/esp_idf_api/uart.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32_esp_idf_api + * @{ + * + * @file + * @brief Interface for the ESP-IDF UART HAL API + * + * @author Gunar Schorcht + * @} + */ + +#ifndef ESP_IDF_API_UART_H +#define ESP_IDF_API_UART_H + +#ifndef DOXYGEN /* Hide implementation details from doxygen */ + +#ifdef __cplusplus +extern "C" { +#endif + +void esp_idf_uart_set_wakeup_threshold(unsigned uart_num, uint32_t threshold); + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* ESP_IDF_API_UART_H */ From e969017b2910db384734716c010457cc2d8fe0ce Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 26 May 2022 14:12:10 +0200 Subject: [PATCH 20/46] cpu/esp32: port periph/gpio to ESP-IDF gpio HAL --- cpu/esp32/Makefile.dep | 5 + cpu/esp32/include/gpio_arch.h | 9 +- cpu/esp32/include/periph_cpu.h | 18 +- cpu/esp32/periph/gpio.c | 674 +++++++++++++-------------------- cpu/esp32/periph/gpio_arch.c | 129 +++++++ 5 files changed, 414 insertions(+), 421 deletions(-) create mode 100644 cpu/esp32/periph/gpio_arch.c diff --git a/cpu/esp32/Makefile.dep b/cpu/esp32/Makefile.dep index 4b7e34fef54d..cbd4b2f46e4f 100644 --- a/cpu/esp32/Makefile.dep +++ b/cpu/esp32/Makefile.dep @@ -79,6 +79,11 @@ ifneq (,$(filter periph_adc periph_dac,$(USEMODULE))) FEATURES_REQUIRED += periph_adc_arch endif +ifneq (,$(filter periph_gpio,$(USEMODULE))) + USEMODULE += esp_idf_gpio + USEMODULE += periph_gpio_arch +endif + ifneq (,$(filter periph_i2c,$(USEMODULE))) ifneq (,$(filter esp_i2c_hw,$(USEMODULE))) USEMODULE += ztimer_msec diff --git a/cpu/esp32/include/gpio_arch.h b/cpu/esp32/include/gpio_arch.h index 7b9a98480631..6c037ac2bf30 100644 --- a/cpu/esp32/include/gpio_arch.h +++ b/cpu/esp32/include/gpio_arch.h @@ -23,19 +23,12 @@ #include #include "gpio_arch_common.h" +#include "periph/gpio.h" #ifdef __cplusplus extern "C" { #endif -#ifndef DOXYGEN -/** - * @brief Returns the RTCIO pin number or -1 if the pin is not an RTCIO pin - */ -int8_t gpio_is_rtcio (gpio_t pin); - -#endif /* DOXYGEN */ - /** * @brief Called before the power management enters a light or deep sleep mode * @param mode sleep mode that is entered diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index 168877bb2e8d..fe87da3c7269 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -98,7 +98,7 @@ typedef unsigned int gpio_t; * @brief Define CPU specific number of GPIO pins * @{ */ -#define GPIO_PIN_NUMOF (40) +#define GPIO_PIN_NUMOF (SOC_GPIO_PIN_COUNT) /** @} */ #ifndef DOXYGEN @@ -109,14 +109,13 @@ typedef unsigned int gpio_t; */ #define HAVE_GPIO_FLANK_T typedef enum { - GPIO_NONE = 0, - GPIO_RISING = 1, /**< emit interrupt on rising flank */ - GPIO_FALLING = 2, /**< emit interrupt on falling flank */ - GPIO_BOTH = 3, /**< emit interrupt on both flanks */ - GPIO_LOW = 4, /**< emit interrupt on low level */ - GPIO_HIGH = 5 /**< emit interrupt on low level */ + GPIO_NONE, + GPIO_RISING, /**< emit interrupt on rising flank */ + GPIO_FALLING, /**< emit interrupt on falling flank */ + GPIO_BOTH, /**< emit interrupt on both flanks */ + GPIO_LOW, /**< emit interrupt on low level */ + GPIO_HIGH /**< emit interrupt on low level */ } gpio_flank_t; - /** @} */ /** @@ -134,9 +133,10 @@ typedef enum { GPIO_OD_PU, /**< open-drain output with pull-up */ GPIO_IN_OUT, /**< input and output */ GPIO_IN_OD, /**< input and open-drain output */ - GPIO_IN_OD_PU /**< input and open-drain output */ + GPIO_IN_OD_PU /**< input and open-drain output with pull-up */ } gpio_mode_t; /** @} */ + #endif /* ndef DOXYGEN */ /** @} */ diff --git a/cpu/esp32/periph/gpio.c b/cpu/esp32/periph/gpio.c index 3b24fe8e0306..1955861de652 100644 --- a/cpu/esp32/periph/gpio.c +++ b/cpu/esp32/periph/gpio.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2022 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 @@ -18,231 +18,55 @@ * @} */ -#define ENABLE_DEBUG 0 -#include "debug.h" - #include #include #include "log.h" #include "periph/gpio.h" /* RIOT gpio.h */ +#include "hal/gpio_hal.h" +#include "hal/gpio_types.h" +#include "hal/rtc_io_types.h" #include "esp/common_macros.h" +#include "esp_intr_alloc.h" #include "rom/ets_sys.h" #include "soc/gpio_reg.h" #include "soc/gpio_sig_map.h" #include "soc/gpio_struct.h" #include "soc/io_mux_reg.h" #include "soc/rtc_cntl_reg.h" -#include "soc/rtc_io_reg.h" -#include "soc/rtc_io_struct.h" +#include "soc/rtc_io_periph.h" + +#if __xtensa__ #include "xtensa/xtensa_api.h" +#endif + +#include "esp_idf_api/gpio.h" +#include "adc_arch_private.h" #include "esp_common.h" #include "esp_sleep.h" -#include "adc_arch.h" -#include "adc_ctrl.h" #include "gpio_arch.h" #include "irq_arch.h" #include "syscalls.h" +#define ENABLE_DEBUG 0 +#include "debug.h" + #define ESP_PM_WUP_PINS_ANY_HIGH ESP_EXT1_WAKEUP_ANY_HIGH #define ESP_PM_WUP_PINS_ALL_LOW ESP_EXT1_WAKEUP_ALL_LOW #ifndef ESP_PM_WUP_LEVEL -#define ESP_PM_WUP_LEVEL ESP_PM_WUP_PINS_ANY_HIGH +#define ESP_PM_WUP_LEVEL ESP_PM_WUP_PINS_ANY_HIGH #endif -#define GPIO_PRO_CPU_INTR_ENA (BIT(2)) - -/* GPIO to IOMUX register mapping (see Technical Reference, Section 4.12 Register Summary) - https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf */ - -const uint32_t _gpio_to_iomux_reg[GPIO_PIN_NUMOF] = -{ - PERIPHS_IO_MUX_GPIO0_U, /* GPIO0 */ - PERIPHS_IO_MUX_U0TXD_U, /* GPIO1 */ - PERIPHS_IO_MUX_GPIO2_U, /* GPIO2 */ - PERIPHS_IO_MUX_U0RXD_U, /* GPIO3 */ - PERIPHS_IO_MUX_GPIO4_U, /* GPIO4 */ - PERIPHS_IO_MUX_GPIO5_U, /* GPIO5 */ - PERIPHS_IO_MUX_SD_CLK_U, /* GPIO6 used for FLASH */ - PERIPHS_IO_MUX_SD_DATA0_U, /* GPIO7 used for FLASH */ - PERIPHS_IO_MUX_SD_DATA1_U, /* GPIO8 used for FLASH */ - PERIPHS_IO_MUX_SD_DATA2_U, /* GPIO9 used for FLASH in qio or qout mode */ - PERIPHS_IO_MUX_SD_DATA3_U, /* GPIO10 used for FLASH in qio or qout mode */ - PERIPHS_IO_MUX_SD_CMD_U, /* GPIO11 used for FLASH */ - PERIPHS_IO_MUX_MTDI_U, /* GPIO12 used as JTAG for OCD */ - PERIPHS_IO_MUX_MTCK_U, /* GPIO13 used as JTAG for OCD */ - PERIPHS_IO_MUX_MTMS_U, /* GPIO14 used as JTAG for OCD */ - PERIPHS_IO_MUX_MTDO_U, /* GPIO15 used as JTAG for OCD */ - PERIPHS_IO_MUX_GPIO16_U, /* GPIO16 used as CS for PSRAM TODO */ - PERIPHS_IO_MUX_GPIO17_U, /* GPIO17 */ - PERIPHS_IO_MUX_GPIO18_U, /* GPIO18 */ - PERIPHS_IO_MUX_GPIO19_U, /* GPIO19 */ - 0, /* GPIO20 not available */ - PERIPHS_IO_MUX_GPIO21_U, /* GPIO21 */ - PERIPHS_IO_MUX_GPIO22_U, /* GPIO22 */ - PERIPHS_IO_MUX_GPIO23_U, /* GPIO23 */ - 0, /* GPIO24 not available */ - PERIPHS_IO_MUX_GPIO25_U, /* GPIO25 */ - PERIPHS_IO_MUX_GPIO26_U, /* GPIO26 */ - PERIPHS_IO_MUX_GPIO27_U, /* GPIO27 */ - 0, /* GPIO28 not available */ - 0, /* GPIO29 not available */ - 0, /* GPIO30 not available */ - 0, /* GPIO31 not available */ - PERIPHS_IO_MUX_GPIO32_U, /* GPIO32 */ - PERIPHS_IO_MUX_GPIO33_U, /* GPIO33 */ - PERIPHS_IO_MUX_GPIO34_U, /* GPIO34 */ - PERIPHS_IO_MUX_GPIO35_U, /* GPIO35 */ - PERIPHS_IO_MUX_GPIO36_U, /* GPIO36 */ - PERIPHS_IO_MUX_GPIO37_U, /* GPIO37 */ - PERIPHS_IO_MUX_GPIO38_U, /* GPIO38 */ - PERIPHS_IO_MUX_GPIO39_U, /* GPIO39 */ -}; +#define GPIO_PRO_CPU_INTR_ENA (BIT(2)) -/* - * Following table defines which GPIOs have to be handled using RTC_GPIO - * registers since pull-up and pull-down resistors for pads with both GPIO - * and RTC_GPIO functionality can only be controlled via RTC_GPIO registers - * https://www.espressif.com/sites/default/files/documentation/eco_and_workarounds_for_bugs_in_esp32_en.pdf - * - * The table contains the RTC_GPIO num or -1 if it is not an RTC_GPIO pin. - */ - -static const int8_t _gpio_to_rtc[GPIO_PIN_NUMOF] = { - 11, /* gpio0 */ - -1, /* gpio1 */ - 12, /* gpio2 */ - -1, /* gpio3 */ - 10, /* gpio4 */ - -1, /* gpio5 */ - -1, /* gpio6 */ - -1, /* gpio7 */ - -1, /* gpio8 */ - -1, /* gpio9 */ - -1, /* gpio10 */ - -1, /* gpio11 */ - 15, /* gpio12 */ - 14, /* gpio13 */ - 16, /* gpio14 */ - 13, /* gpio15 */ - -1, /* gpio16 */ - -1, /* gpio17 */ - -1, /* gpio18 */ - -1, /* gpio19 */ - -1, /* gpio20 */ - -1, /* gpio21 */ - -1, /* gpio22 */ - -1, /* gpio23 */ - -1, /* gpio24 */ - 6, /* gpio25 */ - 7, /* gpio26 */ - 17, /* gpio27 */ - -1, /* gpio28 */ - -1, /* gpio29 */ - -1, /* gpio30 */ - -1, /* gpio31 */ - 9, /* gpio32 */ - 8, /* gpio33 */ - 4, /* gpio34 */ - 5, /* gpio35 */ - 0, /* gpio36 */ - 1, /* gpio37 */ - 2, /* gpio38 */ - 9 /* gpio39 */ -}; - -/** - * @brief Register information type for RTCIO GPIO pins (for internal use only) - */ -struct _rtc_gpio_t { - uint8_t num; /**< RTC_GPIO pin number */ - uint32_t reg; /**< register of the RTC_GPIO pin */ - uint8_t mux; /**< mux io/rtc bit [0..31] in the register, 32 - no mux */ - uint8_t pullup; /**< pullup bit [0..31] in the register, 32 - no pullup */ - uint8_t pulldown; /**< pulldown bit [0..31] in the register, 32 - no pulldown */ - uint8_t drive; /**< drive strength start bit [0..30] in the register */ -}; - -/* Table of RTCIO GPIO pins information */ -static const struct _rtc_gpio_t _rtc_gpios[] = { - { 0, RTC_IO_SENSOR_PADS_REG, 27, 32, 32, 32 }, /* rtc0 (gpio36) SENSOR_VP/SENSE 1 */ - { 1, RTC_IO_SENSOR_PADS_REG, 26, 32, 32, 32 }, /* rtc1 (gpio37) SENSOR_CAPP/SENSE 2 */ - { 2, RTC_IO_SENSOR_PADS_REG, 25, 32, 32, 32 }, /* rtc2 (gpio38) SENSOR_CAPN/SENSE 3 */ - { 3, RTC_IO_SENSOR_PADS_REG, 24, 32, 32, 32 }, /* rtc3 (gpio39) SENSOR_VN/SENSE 4*/ - { 4, RTC_IO_ADC_PAD_REG, 29, 32, 32, 32 }, /* rtc4 (gpio34) VDET_1/ADC1 */ - { 5, RTC_IO_ADC_PAD_REG, 28, 32, 32, 32 }, /* rtc5 (gpio35) VDET_2/ADC2 */ - { 6, RTC_IO_PAD_DAC1_REG, 17, 27, 28, 30 }, /* rtc6 (gpio25) DAC1 */ - { 7, RTC_IO_PAD_DAC2_REG, 17, 27, 28, 30 }, /* rtc7 (gpio26) DAC1 */ - { 8, RTC_IO_XTAL_32K_PAD_REG, 18, 27, 28, 30 }, /* rtc8 (gpio33) XTAL_32K_N */ - { 9, RTC_IO_XTAL_32K_PAD_REG, 17, 22, 23, 25 }, /* rtc9 (gpio32) XTAL_32K_P */ - { 10, RTC_IO_TOUCH_PAD0_REG, 19, 27, 28, 29 }, /* rtc10 (gpio4) TOUCH0 */ - { 11, RTC_IO_TOUCH_PAD1_REG, 19, 27, 28, 29 }, /* rtc11 (gpio0) TOUCH1 */ - { 12, RTC_IO_TOUCH_PAD2_REG, 19, 27, 28, 29 }, /* rtc12 (gpio2) TOUCH2 */ - { 13, RTC_IO_TOUCH_PAD3_REG, 19, 27, 28, 29 }, /* rtc13 (gpio15) TOUCH3 */ - { 14, RTC_IO_TOUCH_PAD4_REG, 19, 27, 28, 29 }, /* rtc14 (gpio13) TOUCH4 */ - { 15, RTC_IO_TOUCH_PAD5_REG, 19, 27, 28, 29 }, /* rtc15 (gpio12) TOUCH5 */ - { 16, RTC_IO_TOUCH_PAD6_REG, 19, 27, 28, 29 }, /* rtc16 (gpio14) TOUCH6 */ - { 17, RTC_IO_TOUCH_PAD7_REG, 19, 27, 28, 29 } /* rtc17 (gpio27) TOUCH7 */ -}; - -/* Table of the usage type of each GPIO pin */ -gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF] = { - _GPIO, /* gpio0 */ - _UART, /* gpio1 configured as direct I/O UART0 RxD */ - _GPIO, /* gpio2 */ - _UART, /* gpio3 configured as direct I/O UART0 TxD */ - _GPIO, /* gpio4 */ - _GPIO, /* gpio5 configurable as direct I/O VSPI CS0 */ - _SPIF, /* gpio6 not configurable, used as SPI SCK */ - _SPIF, /* gpio7 not configurable, used as SPI MISO */ - _SPIF, /* gpio8 not configurable, used as SPI MOSI */ - #if defined(FLASH_MODE_QIO) || defined(FLASH_MODE_QOUT) - /* in qio and qout mode these pins are used for quad SPI */ - _SPIF, /* gpio9 not configurable, used as SPI HD */ - _SPIF, /* gpio10 not configurable, used as SPI WP */ - #else - /* otherwise these pins can be used as GPIO */ - _GPIO, /* gpio9 */ - _GPIO, /* gpio10 */ - #endif - _SPIF, /* gpio11 not configurable, used as SPI CS0 */ - _GPIO, /* gpio12 configurable as direct I/O HSPI MISO */ - _GPIO, /* gpio13 configurable as direct I/O HSPI MOSI */ - _GPIO, /* gpio14 configurable as direct I/O HSPI SCK */ - _GPIO, /* gpio15 configurable as direct I/O HSPI CS0 */ - _GPIO, /* gpio16 */ - _GPIO, /* gpio17 */ - _GPIO, /* gpio18 configurable as direct I/O VSPI SCK */ - _GPIO, /* gpio19 configurable as direct I/O VSPI MISO */ - _NOT_EXIST, /* gpio20 */ - _GPIO, /* gpio21 */ - _GPIO, /* gpio22 */ - _GPIO, /* gpio23 configurable as direct I/O VSPI MOSI */ - _NOT_EXIST, /* gpio24 */ - _GPIO, /* gpio25 */ - _GPIO, /* gpio26 */ - _GPIO, /* gpio27 */ - _NOT_EXIST, /* gpio28 */ - _NOT_EXIST, /* gpio29 */ - _NOT_EXIST, /* gpio30 */ - _NOT_EXIST, /* gpio31 */ -#if MODULE_ESP_RTC_TIMER_32K - _NOT_EXIST, /* gpio32 used for external 32K crystal */ - _NOT_EXIST, /* gpio33 used for external 32K crystal */ -#else - _GPIO, /* gpio32 */ - _GPIO, /* gpio33 */ +/* architecture specific tables */ +extern gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF]; +#if !IS_USED(MODULE_ESP_IDF_GPIO_HAL) +extern const uint32_t _gpio_to_iomux_reg[GPIO_PIN_NUMOF]; #endif - _GPIO, /* gpio34 */ - _GPIO, /* gpio35 */ - _GPIO, /* gpio36 */ - _GPIO, /* gpio37 */ - _GPIO, /* gpio38 */ - _GPIO /* gpio39 */ -}; /* String representation of usage types */ const char* _gpio_pin_usage_str[] = @@ -250,21 +74,36 @@ const char* _gpio_pin_usage_str[] = "GPIO", "ADC", "CAN", "DAC", "EMAC", "I2C", "PWM", "SPI", "SPI Flash", "UART", "N/A" }; -#define FUN_GPIO 2 /* the function number for all GPIOs */ +#ifdef ESP_PM_WUP_PINS +/* for saving the pullup/pulldown settings of wakeup pins in deep sleep mode */ +static bool _gpio_pin_pu[GPIO_PIN_NUMOF] = { }; +static bool _gpio_pin_pd[GPIO_PIN_NUMOF] = { }; +#endif -#define GPIO_PIN_SET(b) if (b < 32) GPIO.out_w1ts = BIT(b); else GPIO.out1_w1ts.val = BIT(b-32) -#define GPIO_PIN_CLR(b) if (b < 32) GPIO.out_w1tc = BIT(b); else GPIO.out1_w1tc.val = BIT(b-32) -#define GPIO_PIN_GET(b) (b < 32) ? (GPIO.out >> b) & 1 : (GPIO.out1.val >> (b-32)) & 1 +#if defined(MCU_ESP32) -#define GPIO_REG_BIT_GET(l,h,b) ((b < 32) ? GPIO.l & BIT(b) : GPIO.h.val & BIT(b-32)) -#define GPIO_REG_BIT_SET(l,h,b) if (b < 32) GPIO.l |= BIT(b); else GPIO.h.val |= BIT(b-32) -#define GPIO_REG_BIT_CLR(l,h,b) if (b < 32) GPIO.l &= ~BIT(b); else GPIO.h.val &= ~BIT(b-32) -#define GPIO_REG_BIT_XOR(l,h,b) if (b < 32) GPIO.l ^= BIT(b); else GPIO.h.val ^= BIT(b-32) -#define REG_SET_CLR_BIT(c,r,f) if (c) REG_SET_BIT(r,f); else REG_CLR_BIT(r,f) +#define GPIO_IN_GET(b) (b < 32) ? GPIO.in & BIT(b) : GPIO.in1.val & BIT(b-32) +#define GPIO_OUT_SET(b) if (b < 32) GPIO.out_w1ts = BIT(b); else GPIO.out1_w1ts.val = BIT(b-32) +#define GPIO_OUT_CLR(b) if (b < 32) GPIO.out_w1tc = BIT(b); else GPIO.out1_w1tc.val = BIT(b-32) +#define GPIO_OUT_XOR(b) if (b < 32) GPIO.out ^= BIT(b); else GPIO.out1.val ^= BIT(b-32) +#define GPIO_OUT_GET(b) (b < 32) ? (GPIO.out >> b) & 1 : (GPIO.out1.val >> (b-32)) & 1 -int gpio_init(gpio_t pin, gpio_mode_t mode) +#elif defined(MCU_ESP32C3) + +#define GPIO_IN_GET(b) GPIO.in.val & BIT(b) +#define GPIO_OUT_SET(b) GPIO.out_w1ts.val = BIT(b) +#define GPIO_OUT_CLR(b) GPIO.out_w1tc.val = BIT(b) +#define GPIO_OUT_XOR(b) GPIO.out.val ^= BIT(b) +#define GPIO_OUT_GET(b) (GPIO.out.val >> b) & 1 + +#else +#error "Platform implementation is missing" +#endif + +#ifndef NDEBUG +int _gpio_init_mode_check(gpio_t pin, gpio_mode_t mode) { - CHECK_PARAM_RET(pin < GPIO_PIN_NUMOF, -1); + assert(pin < GPIO_PIN_NUMOF); /* check if the pin can be used as GPIO or if it is used for something else */ if (_gpio_pin_usage[pin] != _GPIO) { @@ -272,251 +111,268 @@ int gpio_init(gpio_t pin, gpio_mode_t mode) _gpio_pin_usage_str[_gpio_pin_usage[pin]]); return -1; } + return 0; +} +#endif - /* check additional limitations for GPIOs 34 ... 39 */ - if (pin > GPIO33) { - switch (mode) { - case GPIO_OUT: - case GPIO_OD: - case GPIO_OD_PU: - case GPIO_IN_OUT: - case GPIO_IN_OD: - case GPIO_IN_OD_PU: - /* GPIOs 34 ... 39 cannot be used as output */ - LOG_TAG_ERROR("gpio", - "GPIO%d can only be used as input\n", pin); - return -1; - - case GPIO_IN_PD: - case GPIO_IN_PU: - /* GPIOs 34 ... 39 have no software controllable pullups/pulldowns */ - LOG_TAG_ERROR("gpio", - "GPIO%d has no pullups/pulldowns\n", pin); - return -1; - default: break; - } - } +int gpio_init(gpio_t pin, gpio_mode_t mode) +{ + DEBUG("%s: gpio=%d mode=%d\n", __func__, pin, mode); + assert(_gpio_init_mode_check(pin, mode) == 0); + assert(pin < GPIO_PIN_NUMOF); + + gpio_config_t cfg = { }; - const struct _rtc_gpio_t* rtc = (_gpio_to_rtc[pin] != -1) ? - &_rtc_gpios[_gpio_to_rtc[pin]] : NULL; +#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED + /* if we come from deep sleep, the GPIO is configured as RTC IO */ + esp_idf_rtc_gpio_deinit(pin); +#endif - /* if pin is a RTC_GPIO, reset RTC function to route RTC pin to GPIO pin */ - if (rtc) { - REG_CLR_BIT(rtc->reg, BIT(rtc->mux)); - } + cfg.pin_bit_mask = (1ULL << pin); switch (mode) { + case GPIO_IN: + case GPIO_IN_PD: + case GPIO_IN_PU: + cfg.mode = GPIO_MODE_DEF_INPUT; + break; + case GPIO_IN_OD: + case GPIO_IN_OD_PU: + cfg.mode = (GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD); + break; + case GPIO_IN_OUT: + cfg.mode = (GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT); + break; + case GPIO_OUT: + cfg.mode = GPIO_MODE_DEF_OUTPUT; + break; + case GPIO_OD: + case GPIO_OD_PU: + cfg.mode = (GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD); + break; + } - case GPIO_IN: - case GPIO_IN_PD: - case GPIO_IN_PU: - /* according to Technical Reference it is not necessary - to configure the GPIO matrix to read GPIOs from - GPIO_IN_REG/GPIO_IN1_REG */ - #if 0 - /* configure the GPIO matrix for the inputs */ - GPIO.func_in_sel_cfg[signal].sig_in_sel = 0; /* route through GPIO matrix */ - GPIO.func_in_sel_cfg[signal].sig_in_inv = 0; /* do not invert input */ - GPIO.func_in_sel_cfg[signal].func_sel = pin; /* connect signal to GPIOx */ - #endif - - /* disable the output for input-only signals */ - GPIO.func_out_sel_cfg[pin].oen_sel = 1; - GPIO_REG_BIT_SET(enable_w1tc, enable1_w1tc, pin); - - /* set the FUN_IE bit for input */ - REG_SET_BIT(_gpio_to_iomux_reg[pin], FUN_IE); - - /* FUN_GPIO / FUN_WPU / FUN_WPD are set later */ - break; - - case GPIO_OUT: - case GPIO_OD: - case GPIO_OD_PU: - /* configure GPIO signal in the GPIO matrix */ - GPIO.func_out_sel_cfg[pin].func_sel = SIG_GPIO_OUT_IDX; - - /* enable the output */ - GPIO.func_out_sel_cfg[pin].oen_sel = 1; - GPIO_REG_BIT_SET(enable_w1ts, enable1_w1ts, pin); - - /* set pad driver to one for open drain outputs */ - GPIO.pin[pin].pad_driver = (mode == GPIO_OD || mode == GPIO_OD_PU) ? 1 : 0; - - /* set pad driver also for RTC pin if it is a RTC_GPIO */ - if (rtc) { - RTCIO.pin[rtc->num].pad_driver = GPIO.pin[pin].pad_driver; - } + /* digital GPIO configuration */ + cfg.pull_up_en = ((mode == GPIO_IN_PU) || + (mode == GPIO_OD_PU) || + (mode == GPIO_IN_OD_PU)) ? GPIO_PULLUP_ENABLE + : GPIO_PULLUP_DISABLE; + cfg.pull_down_en = (mode == GPIO_IN_PD) ? GPIO_PULLUP_ENABLE + : GPIO_PULLUP_DISABLE; + cfg.intr_type = GPIO_INTR_DISABLE; - /* clear the FUN_IE bit */ - REG_CLR_BIT(_gpio_to_iomux_reg[pin], FUN_IE); +#ifdef ESP_PM_WUP_PINS +/* for saving the pullup/pulldown settings of wakeup pins in deep sleep mode */ + _gpio_pin_pu[pin] = cfg.pull_up_en; + _gpio_pin_pd[pin] = cfg.pull_down_en; +#endif - /* FUN_GPIO / FUN_WPU / FUN_WPD are set later */ - break; + return (esp_idf_gpio_config(&cfg) == ESP_OK) ? 0 : -1; +} - case GPIO_IN_OUT: - case GPIO_IN_OD: - case GPIO_IN_OD_PU: - /* configure GPIO signal in the GPIO matrix */ - GPIO.func_out_sel_cfg[pin].func_sel = SIG_GPIO_OUT_IDX; +#if MODULE_PERIPH_GPIO_IRQ - /* enable the output */ - GPIO.func_out_sel_cfg[pin].oen_sel = 1; - GPIO_REG_BIT_SET(enable_w1ts, enable1_w1ts, pin); +/* interrupt enabled state is required for sleep modes */ +static bool gpio_int_enabled_table[GPIO_PIN_NUMOF] = { }; - /* set pad driver to one for open drain outputs */ - GPIO.pin[pin].pad_driver = (mode == GPIO_IN_OD || mode == GPIO_IN_OD_PU) ? 1 : 0; +static bool _isr_installed = false; - /* set pad driver also for RTC pin if it is a RTC_GPIO */ - if (rtc) { - RTCIO.pin[rtc->num].pad_driver = GPIO.pin[pin].pad_driver; - } +int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, + gpio_cb_t cb, void *arg) +{ + DEBUG("%s: gpio=%d mode=%d flank=%d\n", __func__, pin, mode, flank); + assert(_gpio_init_mode_check(pin, mode) == 0); - /* enable the input */ - REG_SET_BIT(_gpio_to_iomux_reg[pin], FUN_IE); + if (gpio_init(pin, mode) != 0) { + return -1; + } - /* FUN_GPIO / FUN_WPU / FUN_WPD are set later */ - break; + gpio_int_type_t type = GPIO_INTR_DISABLE; + + switch (flank) { + case GPIO_NONE: + type = GPIO_INTR_DISABLE; + break; + case GPIO_RISING: + type = GPIO_INTR_POSEDGE; + break; + case GPIO_FALLING: + type = GPIO_INTR_NEGEDGE; + break; + case GPIO_BOTH: + type = GPIO_INTR_ANYEDGE; + break; + case GPIO_LOW: + type = GPIO_INTR_LOW_LEVEL; + break; + case GPIO_HIGH: + type = GPIO_INTR_HIGH_LEVEL; + break; } - /* select GPIO as IO_MUX function (FUN_GPIO) */ - REG_SET_FIELD(_gpio_to_iomux_reg[pin], MCU_SEL, FUN_GPIO); - - /* enable/disable the pull-up resistor (FUN_WPU) */ - REG_SET_CLR_BIT(mode == GPIO_IN_PU || mode == GPIO_OD_PU || mode == GPIO_IN_OD_PU, - _gpio_to_iomux_reg[pin], FUN_PU); - - /* enable/disable the pull-down resistor (FUN_WPD) */ - REG_SET_CLR_BIT(mode == GPIO_IN_PD, _gpio_to_iomux_reg[pin], FUN_PD); - - /* handle pull-up/pull-down resistors for RTC_GPIOs */ - if (rtc) { - /* enable/disable the pull-up resistor (FUN_WPU) */ - REG_SET_CLR_BIT(mode == GPIO_IN_PU || mode == GPIO_OD_PU || mode == GPIO_IN_OD_PU, - rtc->reg, BIT(rtc->pullup)); - /* enable/disable the pull-down resistor (FUN_WPD) */ - REG_SET_CLR_BIT(mode == GPIO_IN_PD, rtc->reg, BIT(rtc->pulldown)); + + if (esp_idf_gpio_set_intr_type(pin, type) != ESP_OK) { + return -1; } - return 0; -} + if (!_isr_installed && + esp_idf_gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1) != ESP_OK) { + return -1; + } + _isr_installed = true; -#if MODULE_PERIPH_GPIO_IRQ + if (esp_idf_gpio_isr_handler_add(pin, cb, arg) != ESP_OK) { + return -1; + } + + gpio_irq_enable(pin); -static gpio_isr_ctx_t gpio_isr_ctx_table [GPIO_PIN_NUMOF] = { }; -static bool gpio_int_enabled_table [GPIO_PIN_NUMOF] = { }; + return (gpio_int_enabled_table[pin]) ? 0 : -1; +} -void IRAM gpio_int_handler (void* arg) +void gpio_irq_enable(gpio_t pin) { - irq_isr_enter(); - (void)arg; + DEBUG("%s: gpio=%d\n", __func__, pin); + assert(pin < GPIO_PIN_NUMOF); - for (unsigned i = 0; i < GPIO_PIN_NUMOF; i++) { - if (GPIO_REG_BIT_GET(status, status1, i)) { - GPIO_REG_BIT_SET(status_w1tc, status1_w1tc, i); - if (gpio_int_enabled_table[i] && GPIO.pin[i].int_type) { - gpio_isr_ctx_table[i].cb (gpio_isr_ctx_table[i].arg); - } - } + if (esp_idf_gpio_intr_enable(pin) == ESP_OK) { + gpio_int_enabled_table[pin] = true; } - irq_isr_exit(); } -int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, - gpio_cb_t cb, void *arg) +void gpio_irq_disable(gpio_t pin) { - if (gpio_init(pin, mode)) { - return -1; + DEBUG("%s: gpio=%d\n", __func__, pin); + assert(pin < GPIO_PIN_NUMOF); + + if (esp_idf_gpio_intr_disable(pin) == ESP_OK) { + gpio_int_enabled_table[pin] = false; } +} - gpio_isr_ctx_table[pin].cb = cb; - gpio_isr_ctx_table[pin].arg = arg; +#endif /* MODULE_PERIPH_GPIO_IRQ */ - GPIO.pin[pin].int_type = flank; - if (flank != GPIO_NONE) { - gpio_int_enabled_table [pin] = (gpio_isr_ctx_table[pin].cb != NULL); - GPIO.pin[pin].int_ena = GPIO_PRO_CPU_INTR_ENA; - GPIO.pin[pin].int_type = flank; - GPIO.pin[pin].wakeup_enable = 1; +#if IS_USED(MODULE_ESP_IDF_GPIO_HAL) - intr_matrix_set(PRO_CPU_NUM, ETS_GPIO_INTR_SOURCE, CPU_INUM_GPIO); - xt_set_interrupt_handler(CPU_INUM_GPIO, gpio_int_handler, NULL); - xt_ints_on(BIT(CPU_INUM_GPIO)); - } +static gpio_hal_context_t _gpio_hal_ctx = { + .dev = GPIO_HAL_GET_HW(GPIO_PORT_0) +}; - return 0; +/* + * Since `gpio_hal_get_level` returns the current pin level and not the value + * last written to the output, we have to handle the state of each pin in a + * separate static variable. + */ +uint64_t _output = 0; + +int gpio_read(gpio_t pin) +{ + assert(pin < GPIO_PIN_NUMOF); + + /* if the pin is not an input, it alsways returns 0 */ + /* TODO: not really clear whether it should return the last written value + * in this case. */ + int value = gpio_hal_get_level(&_gpio_hal_ctx, pin); + + DEBUG("%s gpio=%u val=%d\n", __func__, pin, value); + return value; } -void gpio_irq_enable (gpio_t pin) +void gpio_write(gpio_t pin, int value) { - CHECK_PARAM(pin < GPIO_PIN_NUMOF); + DEBUG("%s gpio=%u val=%d\n", __func__, pin, value); + assert(pin < GPIO_PIN_NUMOF); - gpio_int_enabled_table [pin] = true; + _output = value ? _output | (1ULL << pin) : _output & ~(1ULL << pin); + gpio_hal_set_level(&_gpio_hal_ctx, pin, value); } -void gpio_irq_disable (gpio_t pin) +void gpio_set(gpio_t pin) { - CHECK_PARAM(pin < GPIO_PIN_NUMOF); + DEBUG("%s gpio=%u\n", __func__, pin); + assert(pin < GPIO_PIN_NUMOF); - gpio_int_enabled_table [pin] = false; + _output |= (1ULL << pin); + gpio_hal_set_level(&_gpio_hal_ctx, pin, 1); } -#endif /* MODULE_PERIPH_GPIO_IRQ */ +void gpio_clear(gpio_t pin) +{ + DEBUG("%s gpio=%u\n", __func__, pin); + assert(pin < GPIO_PIN_NUMOF); -int gpio_read (gpio_t pin) + _output &= ~(1ULL << pin); + gpio_hal_set_level(&_gpio_hal_ctx, pin, 0); +} + +void gpio_toggle(gpio_t pin) +{ + DEBUG("%s gpio=%u\n", __func__, pin); + assert(pin < GPIO_PIN_NUMOF); + + _output ^= (1ULL << pin); + gpio_hal_set_level(&_gpio_hal_ctx, pin, (_output && (1ULL << pin)) ? 1 : 0); +} + +#else /* IS_USED(MODULE_ESP_IDF_GPIO_HAL) */ + +int gpio_read(gpio_t pin) { - CHECK_PARAM_RET(pin < GPIO_PIN_NUMOF, -1); + assert(pin < GPIO_PIN_NUMOF); + int value; if (REG_GET_BIT(_gpio_to_iomux_reg[pin], FUN_IE)) { /* in case the pin is any kind of input, read from input register */ - value = GPIO_REG_BIT_GET(in, in1, pin) ? 1 : 0; + value = (GPIO_IN_GET(pin)) ? 1 : 0; } else { /* otherwise read the last value written to the output register */ - value = GPIO_PIN_GET(pin); + value = GPIO_OUT_GET(pin); } DEBUG("%s gpio=%u val=%d\n", __func__, pin, value); return value; } -void gpio_write (gpio_t pin, int value) +void gpio_write(gpio_t pin, int value) { DEBUG("%s gpio=%u val=%d\n", __func__, pin, value); - CHECK_PARAM(pin < GPIO_PIN_NUMOF); + assert(pin < GPIO_PIN_NUMOF); if (value) { - GPIO_PIN_SET(pin); + GPIO_OUT_SET(pin); } else { - GPIO_PIN_CLR(pin); + GPIO_OUT_CLR(pin); } } -void gpio_set (gpio_t pin) +void gpio_set(gpio_t pin) { DEBUG("%s gpio=%u\n", __func__, pin); - CHECK_PARAM(pin < GPIO_PIN_NUMOF); - GPIO_PIN_SET(pin); + assert(pin < GPIO_PIN_NUMOF); + GPIO_OUT_SET(pin); } -void gpio_clear (gpio_t pin) +void gpio_clear(gpio_t pin) { DEBUG("%s gpio=%u\n", __func__, pin); - CHECK_PARAM(pin < GPIO_PIN_NUMOF); - GPIO_PIN_CLR(pin); + assert(pin < GPIO_PIN_NUMOF); + GPIO_OUT_CLR(pin); } -void gpio_toggle (gpio_t pin) +void gpio_toggle(gpio_t pin) { DEBUG("%s gpio=%u\n", __func__, pin); - CHECK_PARAM(pin < GPIO_PIN_NUMOF); - GPIO_REG_BIT_XOR(out, out1, pin); + assert(pin < GPIO_PIN_NUMOF); + GPIO_OUT_XOR(pin); } +#endif /* IS_USED(MODULE_ESP_IDF_GPIO_HAL) */ + int gpio_set_pin_usage(gpio_t pin, gpio_pin_usage_t usage) { - CHECK_PARAM_RET(pin < GPIO_PIN_NUMOF, -1); - _gpio_pin_usage [pin] = usage; + assert(pin < GPIO_PIN_NUMOF); + _gpio_pin_usage[pin] = usage; return 0; } @@ -530,34 +386,22 @@ const char* gpio_get_pin_usage_str(gpio_t pin) return _gpio_pin_usage_str[_gpio_pin_usage[((pin < GPIO_PIN_NUMOF) ? pin : _NOT_EXIST)]]; } -int8_t gpio_is_rtcio (gpio_t pin) -{ - return _gpio_to_rtc[pin]; -} - #if MODULE_PERIPH_GPIO_IRQ static uint32_t gpio_int_saved_type[GPIO_PIN_NUMOF]; #endif void gpio_pm_sleep_enter(unsigned mode) { - /* - * Activate the power domain for RTC peripherals either when - * ESP_PM_GPIO_HOLD is defined or when light sleep mode is activated. - * As long as the RTC peripherals are active, the pad state of RTC GPIOs - * is held in deep sleep and the pad state of all GPIOs is held in light - * sleep. - */ + if (mode == ESP_PM_DEEP_SLEEP) { #ifdef ESP_PM_GPIO_HOLD - SET_PERI_REG_BITS(RTC_CNTL_HOLD_FORCE_REG, 0x3FFFF, 0x3FFFF, 0); - esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); -#else - if (mode == ESP_PM_LIGHT_SLEEP) { + /* + * Activate the power domain for RTC peripherals when + * ESP_PM_GPIO_HOLD is defined for deep sleep mode. + */ + esp_idf_gpio_deep_sleep_hold(); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - } #endif - if (mode == ESP_PM_DEEP_SLEEP) { #ifdef ESP_PM_WUP_PINS static const gpio_t wup_pins[] = { ESP_PM_WUP_PINS }; /* @@ -567,26 +411,51 @@ void gpio_pm_sleep_enter(unsigned mode) uint64_t wup_pin_mask = 0; for (unsigned i = 0; i < ARRAY_SIZE(wup_pins); i++) { wup_pin_mask |= 1ULL << wup_pins[i]; + +#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED + /* If internal pullups/pulldowns are used, they have to be + activated also in deep sleep mode in RTC power domain */ + bool pu_pd_used = false; + + assert(rtc_io_num_map[wup_pins[i]] >= 0); + if (_gpio_pin_pu[wup_pins[i]]) { + pu_pd_used = true; + esp_idf_rtc_gpio_pullup_en(wup_pins[i]); + } + else { + esp_idf_rtc_gpio_pullup_dis(wup_pins[i]); + } + if (_gpio_pin_pd[wup_pins[i]]) { + pu_pd_used = true; + esp_idf_rtc_gpio_pulldown_en(wup_pins[i]); + } + else { + esp_idf_rtc_gpio_pulldown_dis(wup_pins[i]); + } + if (pu_pd_used) { + /* If internal pullups/pulldowns are used, the RTC power domain + * must remain active in deep sleep mode */ + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + } +#endif /* SOC_RTCIO_INPUT_OUTPUT_SUPPORTED */ } esp_sleep_enable_ext1_wakeup(wup_pin_mask, ESP_PM_WUP_LEVEL); #endif /* ESP_PM_WUP_PINS */ } else { #if MODULE_PERIPH_GPIO_IRQ - esp_sleep_enable_gpio_wakeup(); for (unsigned i = 0; i < GPIO_PIN_NUMOF; i++) { - const struct _rtc_gpio_t* rtc = - (_gpio_to_rtc[i] != -1) ? &_rtc_gpios[_gpio_to_rtc[i]] : NULL; - if (gpio_int_enabled_table[i] && GPIO.pin[i].int_type) { gpio_int_saved_type[i] = GPIO.pin[i].int_type; - switch (GPIO.pin[i].int_type) { + switch (gpio_int_saved_type[i]) { + case GPIO_LOW: case GPIO_FALLING: - GPIO.pin[i].int_type = GPIO_LOW; + esp_idf_gpio_wakeup_enable(i, GPIO_INTR_LOW_LEVEL); DEBUG("%s gpio=%u GPIO_LOW\n", __func__, i); break; + case GPIO_HIGH: case GPIO_RISING: - GPIO.pin[i].int_type = GPIO_HIGH; + esp_idf_gpio_wakeup_enable(i, GPIO_INTR_HIGH_LEVEL); DEBUG("%s gpio=%u GPIO_HIGH\n", __func__, i); break; case GPIO_BOTH: @@ -596,12 +465,9 @@ void gpio_pm_sleep_enter(unsigned mode) default: break; } - if (rtc) { - RTCIO.pin[rtc->num].wakeup_enable = 1; - RTCIO.pin[rtc->num].int_type = GPIO.pin[i].int_type; - } } } + esp_sleep_enable_gpio_wakeup(); #endif } } diff --git a/cpu/esp32/periph/gpio_arch.c b/cpu/esp32/periph/gpio_arch.c new file mode 100644 index 000000000000..034af6164554 --- /dev/null +++ b/cpu/esp32/periph/gpio_arch.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32 + * @ingroup drivers_periph_gpio + * @{ + * + * @file + * @brief Architecture-specific GPIO definitions for ESP32 variant (family) + * + * @author Gunar Schorcht + * @} + */ + +#include "gpio_arch.h" +#include "soc/io_mux_reg.h" + +#if !IS_USED(MODULE_ESP_IDF_GPIO_HAL) + +/* GPIO to IOMUX register mapping (see Technical Reference, Section 4.12 Register Summary) + https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf */ + +const uint32_t _gpio_to_iomux_reg[GPIO_PIN_NUMOF] = +{ + PERIPHS_IO_MUX_GPIO0_U, /* GPIO0 */ + PERIPHS_IO_MUX_U0TXD_U, /* GPIO1 */ + PERIPHS_IO_MUX_GPIO2_U, /* GPIO2 */ + PERIPHS_IO_MUX_U0RXD_U, /* GPIO3 */ + PERIPHS_IO_MUX_GPIO4_U, /* GPIO4 */ + PERIPHS_IO_MUX_GPIO5_U, /* GPIO5 */ + PERIPHS_IO_MUX_SD_CLK_U, /* GPIO6 is used for Flash */ + PERIPHS_IO_MUX_SD_DATA0_U, /* GPIO7 is used for Flash */ + PERIPHS_IO_MUX_SD_DATA1_U, /* GPIO8 is used for Flash */ + PERIPHS_IO_MUX_SD_DATA2_U, /* GPIO9 is used for Flash in qio or qout mode */ + PERIPHS_IO_MUX_SD_DATA3_U, /* GPIO10 is used for Flash in qio or qout mode */ + PERIPHS_IO_MUX_SD_CMD_U, /* GPIO11 is used for Flash */ + PERIPHS_IO_MUX_MTDI_U, /* GPIO12 is used as JTAG for OCD */ + PERIPHS_IO_MUX_MTCK_U, /* GPIO13 is used as JTAG for OCD */ + PERIPHS_IO_MUX_MTMS_U, /* GPIO14 is used as JTAG for OCD */ + PERIPHS_IO_MUX_MTDO_U, /* GPIO15 is used as JTAG for OCD */ + PERIPHS_IO_MUX_GPIO16_U, /* GPIO16 is used as CS for PSRAM TODO */ + PERIPHS_IO_MUX_GPIO17_U, /* GPIO17 */ + PERIPHS_IO_MUX_GPIO18_U, /* GPIO18 */ + PERIPHS_IO_MUX_GPIO19_U, /* GPIO19 */ + 0, /* GPIO20 is not available */ + PERIPHS_IO_MUX_GPIO21_U, /* GPIO21 */ + PERIPHS_IO_MUX_GPIO22_U, /* GPIO22 */ + PERIPHS_IO_MUX_GPIO23_U, /* GPIO23 */ + 0, /* GPIO24 is not available */ + PERIPHS_IO_MUX_GPIO25_U, /* GPIO25 */ + PERIPHS_IO_MUX_GPIO26_U, /* GPIO26 */ + PERIPHS_IO_MUX_GPIO27_U, /* GPIO27 */ + 0, /* GPIO28 is not available */ + 0, /* GPIO29 is not available */ + 0, /* GPIO30 is not available */ + 0, /* GPIO31 is not available */ + PERIPHS_IO_MUX_GPIO32_U, /* GPIO32 */ + PERIPHS_IO_MUX_GPIO33_U, /* GPIO33 */ + PERIPHS_IO_MUX_GPIO34_U, /* GPIO34 */ + PERIPHS_IO_MUX_GPIO35_U, /* GPIO35 */ + PERIPHS_IO_MUX_GPIO36_U, /* GPIO36 */ + PERIPHS_IO_MUX_GPIO37_U, /* GPIO37 */ + PERIPHS_IO_MUX_GPIO38_U, /* GPIO38 */ + PERIPHS_IO_MUX_GPIO39_U, /* GPIO39 */ +}; + +#endif /* !IS_USED(MODULE_ESP_IDF_GPIO_HAL) */ + +/* Table of the usage type of each GPIO pin */ +gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF] = { + _GPIO, /* GPIO0 */ + _UART, /* GPIO1 is used as direct I/O UART0 RxD */ + _GPIO, /* GPIO2 */ + _UART, /* GPIO3 is used as direct I/O UART0 TxD */ + _GPIO, /* GPIO4 */ + _GPIO, /* GPIO5 */ + _SPIF, /* GPIO6 is used as direct I/O SPI SCK for Flash */ + _SPIF, /* GPIO7 is used as direct I/O SPI MISO for Flash */ + _SPIF, /* GPIO8 is used as direct I/O SPI MOSI for Flash */ + #if defined(FLASH_MODE_QIO) || defined(FLASH_MODE_QOUT) + /* in qio and qout mode these pins are used in Flash */ + _SPIF, /* GPIO9 is used as direct I/O SPI HD for Flash */ + _SPIF, /* GPIO10 is used as direct I/O SPI WP for Flash */ + #else + /* otherwise these pins can be used as GPIO */ + _GPIO, /* GPIO9 */ + _GPIO, /* GPIO10 */ + #endif + _SPIF, /* GPIO11 is used as direct I/O SPI CS0 for Flash */ + _GPIO, /* GPIO12 */ + _GPIO, /* GPIO13 */ + _GPIO, /* GPIO14 */ + _GPIO, /* GPIO15 */ + _GPIO, /* GPIO16 */ + _GPIO, /* GPIO17 */ + _GPIO, /* GPIO18 */ + _GPIO, /* GPIO19 */ + _NOT_EXIST, /* GPIO20 does not exist */ + _GPIO, /* GPIO21 */ + _GPIO, /* GPIO22 */ + _GPIO, /* GPIO23 */ + _NOT_EXIST, /* GPIO24 does not exist */ + _GPIO, /* GPIO25 */ + _GPIO, /* GPIO26 */ + _GPIO, /* GPIO27 */ + _NOT_EXIST, /* GPIO28 does not exist */ + _NOT_EXIST, /* GPIO29 does not exist */ + _NOT_EXIST, /* GPIO30 does not exist */ + _NOT_EXIST, /* GPIO31 does not exist */ +#if MODULE_ESP_RTC_TIMER_32K + _NOT_EXIST, /* GPIO32 is used for external 32K crystal */ + _NOT_EXIST, /* GPIO33 is used for external 32K crystal */ +#else + _GPIO, /* GPIO32 */ + _GPIO, /* GPIO33 */ +#endif + _GPIO, /* GPIO34 */ + _GPIO, /* GPIO35 */ + _GPIO, /* GPIO36 */ + _GPIO, /* GPIO37 */ + _GPIO, /* GPIO38 */ + _GPIO /* GPIO39 */ +}; From c31c7a9cb6d160a9b955f2f6d649b96b8b72c91e Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 18:27:01 +0100 Subject: [PATCH 21/46] cpu/esp32: port periph/can to ESP-IDF twai HAL --- cpu/esp32/include/can_esp.h | 16 +- cpu/esp32/periph/can.c | 559 +++++++++++++++++------------------- 2 files changed, 263 insertions(+), 312 deletions(-) diff --git a/cpu/esp32/include/can_esp.h b/cpu/esp32/include/can_esp.h index 935153232d04..565d9788f5e1 100644 --- a/cpu/esp32/include/can_esp.h +++ b/cpu/esp32/include/can_esp.h @@ -74,19 +74,9 @@ typedef struct can { uint32_t rx_frames_num; /**< number of frames in ring buffer */ uint32_t rx_filter_num; /**< number of acceptance filters */ - bool powered_up; /**< device is powered up */ - - gpio_t tx_pin; /**< CAN transceiver TX pin */ - gpio_t rx_pin; /**< CAN transceiver RX pin */ -#ifdef ESP_CAN_CLK_OUT - gpio_t clk_out_pin; /**< optional CLK_OUT pin */ -#endif -#ifdef ESP_CAN_BUS_ON_OFF - gpio_t bus_on_off_pin; /**< optional BUS_ON_OFF pin */ -#endif + bool powered_up; /**< device is powered up */ uint32_t events; /**< events triggered by the last interrupt */ - } can_t; /** CAN device type can_t is redefined by ESP CAN */ @@ -99,10 +89,10 @@ typedef struct { uint32_t bitrate; /**< Bitrate */ gpio_t tx_pin; /**< CAN transceiver TX pin */ gpio_t rx_pin; /**< CAN transceiver RX pin */ -#ifdef ESP_CAN_CLK_OUT +#ifdef CAN_CLK_OUT gpio_t clk_out_pin; /**< optional CLK_OUT pin */ #endif -#ifdef ESP_CAN_BUS_ON_OFF +#ifdef CAN_BUS_ON_OFF gpio_t bus_on_off_pin; /**< optional BUS_ON_OFF pin */ #endif } can_conf_t; diff --git a/cpu/esp32/periph/can.c b/cpu/esp32/periph/can.c index 30a827ac353c..1bc7e1e0215c 100644 --- a/cpu/esp32/periph/can.c +++ b/cpu/esp32/periph/can.c @@ -22,28 +22,17 @@ #include "can_esp.h" #include "can_params.h" #include "esp_attr.h" -#include "esp_common.h" #include "gpio_arch.h" #include "irq_arch.h" -#include "tools.h" -#include "can/common.h" -#include "can/device.h" #include "driver/periph_ctrl.h" -#include "freertos/FreeRTOS.h" +#include "esp_rom_gpio.h" +#include "hal/interrupt_controller_types.h" +#include "hal/interrupt_controller_ll.h" +#include "hal/twai_hal.h" #include "log.h" #include "rom/ets_sys.h" - -#include "periph/can.h" -#include "periph/gpio.h" - -#include "hal/twai_ll.h" #include "soc/gpio_sig_map.h" -#include "soc/gpio_struct.h" -#include "soc/twai_struct.h" -#include "soc/soc.h" - -#include "xtensa/xtensa_api.h" #define ENABLE_DEBUG 0 #include "debug.h" @@ -88,28 +77,13 @@ #define ESP_CAN_MAX_DATA_LEN 8 /* 8 data bytes at maximum */ #define ESP_CAN_FRAME_LEN 13 /* 13 bytes at maximum */ -typedef union esp_can_frame { - struct { - struct { - uint8_t dlc :4; /* frame payload length */ - uint8_t zero:2; /* don't care, should be zero */ - uint8_t rtr :1; /* remote transmission request frame */ - uint8_t eff :1; /* extended ID frame format */ - }; - union { - struct { - uint8_t id[ESP_CAN_SFF_ID_LEN]; /* 11 bit standard frame identifier */ - uint8_t data[ESP_CAN_MAX_DATA_LEN]; /* data bytes */ - uint8_t reserved8[2]; - } standard; - struct { - uint8_t id[ESP_CAN_EFF_ID_LEN]; /* 29 bit standard frame identifier */ - uint8_t data[ESP_CAN_MAX_DATA_LEN]; /* data bytes */ - } extended; - }; - }; - uint8_t bytes[ESP_CAN_FRAME_LEN]; -} _esp_can_frame_t; +#if !defined(CAN_CLK_OUT) && !defined(CAN_CLK_OUT_DIV) +/* if CAN_CLK_OUT is not used, CAN_CLKOUT_DIV is set to 0 */ +#define CAN_CLK_OUT_DIV 0 +#elif defined(CAN_CLK_OUT) && !defined(CAN_CLK_OUT_DIV) +/* if CAN_CLK_OUT is used, CAN_CLK_OUT_DIV has to be defined */ +#error "CAN_CLK_OUT pin defined but not the CAN_CLK_OUT_DIV" +#endif /* driver interface functions */ static int _esp_can_init(candev_t *candev); @@ -121,13 +95,16 @@ static int _esp_can_abort(candev_t *candev, const struct can_frame *frame); static int _esp_can_set_filter(candev_t *candev, const struct can_filter *filter); static int _esp_can_remove_filter(candev_t *candev, const struct can_filter *filter); -/* internal function declarations, we don't need device since we habe only one */ -static void _esp_can_set_bittiming (can_t *dev); +/* internal function declarations, we don't need the device since we have only one */ +static void _esp_can_set_bittiming(can_t *dev); +static void _esp_can_start(can_t *dev); +static void _esp_can_stop(can_t *dev); static void _esp_can_power_up(can_t *dev); static void _esp_can_power_down(can_t *dev); -static void _esp_can_init_pins(can_t *dev); static int _esp_can_set_mode(can_t *dev, canopt_state_t state); -static void IRAM_ATTR _esp_can_intr_handler (void *arg); +static void _esp_can_init_pins(void); +static void _esp_can_deinit_pins(void); +static void IRAM_ATTR _esp_can_intr_handler(void *arg); /** ESP32 CAN low level device driver data */ static const candev_driver_t _esp_can_driver = { @@ -163,26 +140,26 @@ static void _esp_can_isr(candev_t *candev) assert(dev->candev.event_callback); if (dev->events & ESP_CAN_EVENT_BUS_OFF) { - dev->events &= ~ESP_CAN_EVENT_BUS_OFF; + dev->events ^= ESP_CAN_EVENT_BUS_OFF; dev->candev.event_callback(&dev->candev, CANDEV_EVENT_BUS_OFF, NULL); } if (dev->events & ESP_CAN_EVENT_ERROR_PASSIVE) { - dev->events &= ~ESP_CAN_EVENT_ERROR_PASSIVE; + dev->events ^= ESP_CAN_EVENT_ERROR_PASSIVE; dev->candev.event_callback(&dev->candev, CANDEV_EVENT_ERROR_PASSIVE, NULL); } if (dev->events & ESP_CAN_EVENT_ERROR_WARNING) { - dev->events &= ~ESP_CAN_EVENT_ERROR_WARNING; + dev->events ^= ESP_CAN_EVENT_ERROR_WARNING; dev->candev.event_callback(&dev->candev, CANDEV_EVENT_ERROR_WARNING, NULL); } if (dev->events & ESP_CAN_EVENT_TX_ERROR) { /* a pending TX confirmation has also to be deleted on TX bus error */ - dev->events &= ~ESP_CAN_EVENT_TX_ERROR; - dev->events &= ~ESP_CAN_EVENT_TX_CONFIRMATION; + dev->events ^= ESP_CAN_EVENT_TX_ERROR; + dev->events ^= ESP_CAN_EVENT_TX_CONFIRMATION; if (dev->tx_frame) { /* handle the event only if there is still a frame in TX buffer */ dev->candev.event_callback(&dev->candev, @@ -192,7 +169,7 @@ static void _esp_can_isr(candev_t *candev) } if (dev->events & ESP_CAN_EVENT_TX_CONFIRMATION) { - dev->events &= ~ESP_CAN_EVENT_TX_CONFIRMATION; + dev->events ^= ESP_CAN_EVENT_TX_CONFIRMATION; if (dev->tx_frame) { /* handle the event only if there is still a frame in TX buffer */ dev->candev.event_callback(&dev->candev, @@ -203,12 +180,12 @@ static void _esp_can_isr(candev_t *candev) } if (dev->events & ESP_CAN_EVENT_RX_ERROR) { - dev->events &= ~ESP_CAN_EVENT_RX_ERROR; + dev->events ^= ESP_CAN_EVENT_RX_ERROR; dev->candev.event_callback(&dev->candev, CANDEV_EVENT_RX_ERROR, NULL); } if (dev->events & ESP_CAN_EVENT_RX_INDICATION) { - dev->events &= ~ESP_CAN_EVENT_RX_INDICATION; + dev->events ^= ESP_CAN_EVENT_RX_INDICATION; while (dev->rx_frames_num) { dev->candev.event_callback(&dev->candev, @@ -221,6 +198,8 @@ static void _esp_can_isr(candev_t *candev) } } +twai_hal_context_t hw; + static int _esp_can_init(candev_t *candev) { can_t *dev = container_of(candev, can_t, candev); @@ -229,12 +208,12 @@ static int _esp_can_init(candev_t *candev) assert(dev); - /* initialize used GPIOs */ - _esp_can_init_pins(dev); - - /* power up and configure the CAN controller */ + /* power up and configure the CAN controller and initialize the pins */ _esp_can_power_up(dev); + /* start the CAN controller in configured operation mode */ + _esp_can_start(dev); + return 0; } @@ -259,18 +238,18 @@ static int _esp_can_send(candev_t *candev, const struct can_frame *frame) dev->tx_frame = (struct can_frame*)frame; /* prepare the frame as expected by ESP32 */ - _esp_can_frame_t esp_frame = {}; + twai_hal_frame_t esp_frame = { }; esp_frame.dlc = frame->can_dlc; esp_frame.rtr = (frame->can_id & CAN_RTR_FLAG); - esp_frame.eff = (frame->can_id & CAN_EFF_FLAG); + esp_frame.frame_format = (frame->can_id & CAN_EFF_FLAG); /* esp_frame is a union that provides two views on the same memory: one * tailored for efficient access and the other for readable code. Likely * due to cppcheck not finding all headers it wrongly assumes that values * are assigned but never read again (unreadVariable). But the union members * are read via the aliases to the same memory. */ - if (esp_frame.eff) { + if (esp_frame.frame_format) { uint32_t id = frame->can_id & CAN_EFF_MASK; /* cppcheck-suppress unreadVariable */ esp_frame.extended.id[0] = (id >> 21) & 0xff; @@ -289,16 +268,17 @@ static int _esp_can_send(candev_t *candev, const struct can_frame *frame) esp_frame.standard.id[1] = (id << 5) & 0xff; } - memcpy(esp_frame.eff ? &esp_frame.extended.data - : &esp_frame.standard.data, frame->data, ESP_CAN_MAX_DATA_LEN); - - /* place the frame in TX buffer of ESP32 */ - for (unsigned i = 0; i < ESP_CAN_FRAME_LEN; i++) { - CAN.tx_rx_buffer[i].val = esp_frame.bytes[i]; - } + /* copy data from can_frame to esp_frame */ + memcpy(esp_frame.frame_format ? &esp_frame.extended.data + : &esp_frame.standard.data, + frame->data, ESP_CAN_MAX_DATA_LEN); /* set the single shot transmit command without self-receiption */ - CAN.command_reg.val = ESP_CMD_TX_SINGLE_SHOT; + esp_frame.single_shot = 1; + esp_frame.self_reception = 0; + + /* place the frame in TX buffer and trigger the command */ + twai_hal_set_tx_buffer_and_transmit(&hw, &esp_frame); critical_exit(); @@ -322,32 +302,48 @@ static int _esp_can_set(candev_t *candev, canopt_t opt, void *value, size_t valu return -EOVERFLOW; } dev->candev.bittiming = *((struct can_bittiming*)value); + _esp_can_stop(dev); _esp_can_set_bittiming(dev); + _esp_can_start(dev); res = sizeof(struct can_bittiming); break; case CANOPT_STATE: - DEBUG("%s CANOPT_STATE\n", __func__); + DEBUG("%s CANOPT_STATE %d\n", __func__, *((canopt_state_t *)value)); + if (dev->powered_up) { + _esp_can_stop(dev); + } res = _esp_can_set_mode(dev, *((canopt_state_t *)value)); + if (dev->powered_up) { + _esp_can_start(dev); + } if (res == 0) { res = sizeof(uint16_t); } break; case CANOPT_TEC: - case CANOPT_REC: - DEBUG("%s %s\n", __func__, (opt == CANOPT_TEC) ? "CANOPT_TEC" : "CANOPT_REC"); + DEBUG("%s %s\n", __func__, "CANOPT_TEC"); if (value_len < sizeof(uint16_t)) { DEBUG("%s size error\n", __func__); return -EOVERFLOW; } - if (opt == CANOPT_TEC) { - CAN.tx_error_counter_reg.txerr = *((uint16_t*)value); - } - else { - CAN.rx_error_counter_reg.rxerr = *((uint16_t*)value); + _esp_can_stop(dev); + twai_ll_set_tec(hw.dev, *((uint16_t*)value)); + _esp_can_start(dev); + res = sizeof(uint16_t); + break; + + case CANOPT_REC: + DEBUG("%s %s\n", __func__, "CANOPT_REC"); + if (value_len < sizeof(uint16_t)) { + DEBUG("%s size error\n", __func__); + return -EOVERFLOW; } + _esp_can_stop(dev); + twai_ll_set_rec(hw.dev, *((uint16_t*)value)); + _esp_can_start(dev); res = sizeof(uint16_t); break; @@ -406,20 +402,26 @@ static int _esp_can_get(candev_t *candev, canopt_t opt, void *value, size_t max_ break; case CANOPT_TEC: - case CANOPT_REC: - DEBUG("%s %s\n", __func__, (opt == CANOPT_TEC) ? "CANOPT_TEC" : "CANOPT_REC"); + DEBUG("%s %s\n", __func__, "CANOPT_TEC"); if (max_len < sizeof(uint16_t)) { res = EOVERFLOW; break; } - if (opt == CANOPT_TEC) { - *((uint16_t *)value) = CAN.tx_error_counter_reg.txerr; - } - else { - *((uint16_t *)value) = CAN.rx_error_counter_reg.rxerr; + *((uint16_t *)value) = twai_ll_get_tec(hw.dev); + + res = sizeof(uint16_t); + break; + + case CANOPT_REC: + DEBUG("%s %s\n", __func__, "CANOPT_REC"); + if (max_len < sizeof(uint16_t)) { + res = EOVERFLOW; + break; } + *((uint16_t *)value) = twai_ll_get_rec(hw.dev); + res = sizeof(uint16_t); break; @@ -461,7 +463,7 @@ static int _esp_can_abort(candev_t *candev, const struct can_frame *frame) assert(frame); /* abort transmission command */ - CAN.command_reg.val = ESP_CMD_ABORT_TX; + twai_ll_set_cmd_abort_tx(hw.dev); /* mark the transmitter as free */ dev->tx_frame = NULL; @@ -503,6 +505,7 @@ static int _esp_can_set_filter(candev_t *candev, const struct can_filter *filter /* set the filter and return the filter index */ dev->rx_filters[i] = *filter; dev->rx_filter_num++; + return i; } @@ -530,111 +533,95 @@ static int _esp_can_remove_filter(candev_t *candev, const struct can_filter *fil } /** - * Internal functions. All these functions have no dev parameter since - * they directly access the only one existing CAN controller. + * Internal functions. */ -static void _esp_can_set_reset_mode(void) +static void _esp_can_start(can_t *dev) { - DEBUG("%s\n", __func__); + DEBUG("%s dev=%p\n", __func__, dev); + assert(dev); - while (CAN.mode_reg.rm != 1) { - CAN.mode_reg.rm = 1; + /* start the CAN controller in configured mode */ + switch (dev->state) { + case CANOPT_STATE_LISTEN_ONLY: + twai_hal_start(&hw, TWAI_MODE_LISTEN_ONLY); + break; + case CANOPT_STATE_SLEEP: + /* sleep mode is not supported, the normal mode is used instead */ + case CANOPT_STATE_ON: + twai_hal_start(&hw, TWAI_MODE_NORMAL); + break; + default: + break; } } -static void _esp_can_set_operating_mode(void) +static void _esp_can_stop(can_t *dev) { - DEBUG("%s\n", __func__); + DEBUG("%s dev=%p\n", __func__, dev); + assert(dev); - while (CAN.mode_reg.rm != 0) { - CAN.mode_reg.rm = 0; - } + /* stop the CAN controller by entering the reset mode */ + twai_hal_stop(&hw); } -static int _esp_can_config(can_t *dev) +static void _esp_can_power_up(can_t *dev) { - DEBUG("%s dev=%p\n", __func__, dev); + /** + * Function esp_can_power_up + * - powers up the CAN controller, + * - initializes the HAL context, + * - sets the timing and the acceptance filters according to configuration + * - resets the error counters and sets the warning limit + * + * The CAN controller must be started in configured mode explicitly + * afterwards using function _esp_can_start(). + */ + DEBUG("%s dev=%p\n", __func__, dev); assert(dev); - critical_enter(); - - /* reset mode to be able to write configuration registers */ - _esp_can_set_reset_mode(); - - /* configuration is done in listen only mode */ - CAN.mode_reg.stm = 0; - CAN.mode_reg.lom = 1; - - /* Use SJA1000 PeliCAN mode and registers layout */ - CAN.clock_divider_reg.cm = 1; - -#ifndef ESP_CAN_CLK_OUT - CAN.clock_divider_reg.co = 1; - CAN.clock_divider_reg.cd = 0; -#else - uint32_t clk_out_div = ESP_CAN_CLK_OUT_DIV / 2 - 1; - clk_out_div = (clk_out_div < 7) ? clk_out_div : 7; - CAN.clock_divider_reg.co = 0; - CAN.clock_divider_reg.cd = clk_out_div; -#endif + /* just return when already powered up */ + if (dev->powered_up) { + return; + } - /* set error counter values and warning limits */ - CAN.error_warning_limit_reg.ewl = ESP_CAN_ERROR_WARNING_LIMIT; - CAN.tx_error_counter_reg.txerr = 0; - CAN.rx_error_counter_reg.rxerr = 0; + critical_enter(); - /* accept all CAN messages, filtering is done by software */ - CAN.mode_reg.afm = 0; /* single filter */ - CAN.acceptance_filter.amr[0].byte = 0xff; /* all bits masked */ - CAN.acceptance_filter.amr[1].byte = 0xff; - CAN.acceptance_filter.amr[2].byte = 0xff; - CAN.acceptance_filter.amr[3].byte = 0xff; + /* power up the peripheral */ + periph_module_reset(PERIPH_TWAI_MODULE); + periph_module_enable(PERIPH_TWAI_MODULE); - /* clear interrupt status register by read and enable all interrupts */ - uint32_t tmp = CAN.interrupt_reg.val; (void)tmp; - CAN.interrupt_enable_reg.val = ESP_CAN_INTR_MASK; + /* initialize the HAL context, on return the CAN controller is in listen + * only mode but not yet started, the error counters are reset and + * pending interrupts cleared */ - /* route CAN interrupt source to CPU interrupt and enable it */ - intr_matrix_set(PRO_CPU_NUM, ETS_CAN_INTR_SOURCE, CPU_INUM_CAN); - xt_set_interrupt_handler(CPU_INUM_CAN, _esp_can_intr_handler, (void*)(uintptr_t)dev); - xt_ints_on(BIT(CPU_INUM_CAN)); + if (!twai_hal_init(&hw)) { + assert(false); + } /* set bittiming from parameters as given in device data */ _esp_can_set_bittiming(dev); - /* switch to operating mode */ - _esp_can_set_operating_mode(); - - critical_exit(); - - return 0; -} - -static void _esp_can_power_up(can_t *dev) -{ - assert(dev); - - /* just return when already powered up */ - if (dev->powered_up) { - return; - } + /* set warning limit */ + twai_ll_set_err_warn_lim(hw.dev, ESP_CAN_ERROR_WARNING_LIMIT); - DEBUG("%s dev=%p\n", __func__, dev); + /* route CAN interrupt source to CPU interrupt and enable it */ + intr_matrix_set(PRO_CPU_NUM, ETS_TWAI_INTR_SOURCE, CPU_INUM_CAN); + intr_cntrl_ll_set_int_handler(CPU_INUM_CAN, _esp_can_intr_handler, (void*)(uintptr_t)dev); + intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_CAN)); - critical_enter(); + /* initialize used GPIOs */ + _esp_can_init_pins(); - /* power up and (re)configure the CAN controller */ - periph_module_enable(PERIPH_CAN_MODULE); dev->powered_up = true; - _esp_can_config (dev); critical_exit(); } static void _esp_can_power_down(can_t *dev) { + DEBUG("%s dev=%p\n", __func__, dev); assert(dev); /* just return when already powered down */ @@ -642,43 +629,76 @@ static void _esp_can_power_down(can_t *dev) return; } - DEBUG("%s dev=%p\n", __func__, dev); + /* deinitialize used GPIOs */ + _esp_can_deinit_pins(); + + /* stop the CAN controller and deinitialize the HAL context */ + twai_hal_stop(&hw); + twai_hal_deinit(&hw); /* power down the CAN controller */ periph_module_disable(PERIPH_CAN_MODULE); + dev->powered_up = false; } -static void _esp_can_init_pins(can_t *dev) +static void _esp_can_init_pins(void) { - DEBUG("%s dev=%p\n", __func__, dev); + DEBUG("%s\n", __func__); - assert(dev); + const can_conf_t *cfg = &candev_conf[0]; /* Init TX pin */ - gpio_init(dev->tx_pin, GPIO_OUT); - gpio_set_pin_usage(dev->tx_pin, _CAN); - GPIO.func_out_sel_cfg[dev->tx_pin].func_sel = TWAI_TX_IDX; + gpio_init(cfg->tx_pin, GPIO_OUT); + esp_rom_gpio_connect_out_signal(cfg->tx_pin, TWAI_TX_IDX, false, false); + esp_rom_gpio_pad_select_gpio(cfg->tx_pin); + gpio_set_pin_usage(cfg->tx_pin, _CAN); /* Init RX pin */ - gpio_init(dev->rx_pin, GPIO_IN); - gpio_set_pin_usage(dev->rx_pin, _CAN); - GPIO.func_in_sel_cfg[CAN_RX_IDX].sig_in_sel = 1; - GPIO.func_in_sel_cfg[CAN_RX_IDX].sig_in_inv = 0; - GPIO.func_in_sel_cfg[CAN_RX_IDX].func_sel = dev->rx_pin; + gpio_init(cfg->rx_pin, GPIO_IN); + esp_rom_gpio_connect_in_signal(cfg->rx_pin, TWAI_RX_IDX, false); + esp_rom_gpio_pad_select_gpio(cfg->rx_pin); + gpio_set_pin_usage(cfg->rx_pin, _CAN); -#ifdef ESP_CAN_CLK_OUT +#ifdef CAN_CLK_OUT /* Init CLK_OUT pin (optional) if defined */ - gpio_init(dev->clk_out_pin, GPIO_OD); - gpio_set_pin_usage(dev->clk_out_pin, _CAN); - GPIO.func_out_sel_cfg[dev->clk_out_pin].func_sel = TWAI_CLKOUT_IDX; + gpio_init(cfg->clk_out_pin, GPIO_OD); + esp_rom_gpio_connect_out_signal(cfg->clk_out_pin, TWAI_CLKOUT_IDX, false, false); + esp_rom_gpio_pad_select_gpio(cfg->clk_out_pin); + gpio_set_pin_usage(cfg->clk_out_pin, _CAN); #endif +#ifdef CAN_BUS_ON_OFF /* Init BUS_ON_OFF pin pin (optional) if defined */ -#ifdef ESP_CAN_BUS_ON_OFF - gpio_init(dev->bus_on_of_pin, GPIO_OD); - gpio_set_pin_usage(dev->bus_on_of_pin, _CAN); - GPIO.func_out_sel_cfg[dev->bus_on_of_pin].func_sel = TWAI_BUS_OFF_ON_IDX; + gpio_init(cfg->bus_on_of_pin, GPIO_OD); + esp_rom_gpio_connect_out_signal(cfg->bus_on_of_pin, TWAI_BUS_OFF_ON_IDX, false, false); + esp_rom_gpio_pad_select_gpio(cfg->bus_on_of_pin); + gpio_set_pin_usage(cfg->bus_on_of_pin, _CAN); +#endif +} + +static void _esp_can_deinit_pins(void) +{ + const can_conf_t *cfg = &candev_conf[0]; + + /* Reset TX pin */ + gpio_set_pin_usage(cfg->tx_pin, _GPIO); + gpio_init(cfg->tx_pin, GPIO_IN_PU); + + /* Reset RX pin */ + gpio_set_pin_usage(cfg->rx_pin, _GPIO); + gpio_init(cfg->rx_pin, GPIO_IN_PU); + +#ifdef CAN_CLK_OUT + /* Reset CLK_OUT pin (optional) if defined */ + gpio_set_pin_usage(cfg->clk_out_pin, _GPIO); + gpio_init(cfg->clk_out_pin, GPIO_IN); +#endif + +#ifdef CAN_BUS_ON_OFF + /* Reset BUS_ON_OFF pin pin (optional) if defined */ + gpio_set_pin_usage(cfg->bus_on_of_pin, _GPIO); + gpio_init(cfg->bus_on_of_pin, GPIO_IN_PD); #endif } @@ -690,48 +710,30 @@ static int _esp_can_set_mode(can_t *dev, canopt_state_t state) critical_enter(); + /* set the new mode */ + dev->state = state; + switch (state) { case CANOPT_STATE_OFF: - /* just power down the CAN controller */ + /* stop and power down the CAN controller */ _esp_can_power_down(dev); break; - case CANOPT_STATE_LISTEN_ONLY: - /* power up and (re)configure the CAN controller if necessary */ - _esp_can_power_up(dev); - /* set the new mode (has to be done in reset mode) */ - _esp_can_set_reset_mode(); - CAN.mode_reg.stm = 0; - CAN.mode_reg.lom = 1; - _esp_can_set_operating_mode (); - break; - case CANOPT_STATE_SLEEP: - /* Sleep mode is not supported by ESP32, State On is used instead. */ - #if 0 - /* power up and (re)configure the CAN controller if necessary */ - _esp_can_power_up(dev); - /* set the sleep mode (not necessary to set reset mode before) */ - CAN.mode_reg.sleep_mode = 1; - break; - #endif - + /* sleep mode is not supported, so CAN can't be powered down */ + case CANOPT_STATE_LISTEN_ONLY: case CANOPT_STATE_ON: /* power up and (re)configure the CAN controller if necessary */ _esp_can_power_up(dev); - /* set the new mode (has to be done in reset mode) */ - _esp_can_set_reset_mode(); - CAN.mode_reg.stm = 0; - CAN.mode_reg.lom = 0; - _esp_can_set_operating_mode (); + /* restart the CAN controller in new mode */ + _esp_can_stop(dev); + _esp_can_start(dev); break; default: LOG_TAG_ERROR ("esp_can", "state value %d not supported\n", state); break; } - dev->state = state; - critical_exit(); return 0; @@ -745,99 +747,71 @@ static void IRAM_ATTR _esp_can_intr_handler(void *arg) critical_enter(); - /* read the registers to clear them */ - uint32_t sta_reg = CAN.status_reg.val; - uint32_t int_reg = CAN.interrupt_reg.val; + uint32_t events = twai_hal_get_events(&hw); - DEBUG("%s int=%08x sta=%08x\n", __func__, int_reg, sta_reg); - - /* Wake-Up Interrupt (not supported by ESP32) */ - if (int_reg & BIT(4)) { - DEBUG("%s wake-up interrupt\n", __func__); - dev->events |= ESP_CAN_EVENT_WAKE_UP; - } + DEBUG("%s events=%08"PRIx32"\n", __func__, events); /* Arbitration Lost Interrupt */ - if (int_reg & TWAI_LL_INTR_ALI) { + if (events & TWAI_HAL_EVENT_ARB_LOST) { DEBUG("%s arbitration lost interrupt\n", __func__); /* can only happen during transmission, handle it as error in single shot transmission */ dev->events |= ESP_CAN_EVENT_TX_ERROR; } - /* bus or error status has changed, handle this first */ - if (int_reg & TWAI_LL_INTR_EI) { - - /* BUS_OFF state condition */ - if ((sta_reg & TWAI_LL_STATUS_ES) && (sta_reg & TWAI_LL_STATUS_BS)) { - DEBUG("%s bus-off state interrupt\n", __func__); - /* switch to listen only mode to freeze the RX error counter */ - _esp_can_set_mode (dev, CANOPT_STATE_LISTEN_ONLY); - /* save the event */ - dev->events |= ESP_CAN_EVENT_BUS_OFF; - } + /* BUS_OFF state condition */ + if (events & TWAI_HAL_EVENT_BUS_OFF) { + DEBUG("%s bus-off state interrupt\n", __func__); + /* save the event */ + dev->events |= ESP_CAN_EVENT_BUS_OFF; + } - /* ERROR_WARNING state condition, RX/TX error counter are > 96 */ - else if ((sta_reg & TWAI_LL_STATUS_ES) && !(sta_reg & TWAI_LL_STATUS_BS)) { - DEBUG("%s error warning interrupt\n", __func__); - /* save the event */ - dev->events |= ESP_CAN_EVENT_ERROR_WARNING; - } + /* ERROR_WARNING state condition, RX/TX error counter are > 96 */ + if (events & TWAI_HAL_EVENT_ABOVE_EWL) { + DEBUG("%s error warning interrupt\n", __func__); + /* save the event */ + dev->events |= ESP_CAN_EVENT_ERROR_WARNING; } /* enter to / return from ERROR_PASSIVE state */ - if (int_reg & TWAI_LL_INTR_EPI) { - /* enter to the ERROR_PASSIVE state when one of the error counters is >= 128 */ - if (CAN.tx_error_counter_reg.txerr >= ESP_CAN_ERROR_PASSIVE_LIMIT || - CAN.rx_error_counter_reg.rxerr >= ESP_CAN_ERROR_PASSIVE_LIMIT) { - DEBUG("%s error passive interrupt %d %d\n", __func__, - CAN.tx_error_counter_reg.txerr, - CAN.rx_error_counter_reg.rxerr); - /* save the event */ - dev->events |= ESP_CAN_EVENT_ERROR_PASSIVE; - } + if (events & TWAI_HAL_EVENT_ERROR_PASSIVE) { + DEBUG("%s error passive interrupt %"PRIu32" %"PRIu32"\n", __func__, + twai_ll_get_tec(hw.dev), twai_ll_get_rec(hw.dev)); + /* save the event */ + dev->events |= ESP_CAN_EVENT_ERROR_PASSIVE; } /* * Bus Error Interrupt (bit, stuff, crc, form, ack), details are captured * in ECC register (see SJA1000 Data sheet, Table 20 and 21) */ - - if (int_reg & TWAI_LL_INTR_BEI) { + if (events & TWAI_HAL_EVENT_BUS_ERR) { + DEBUG("%s bus error interrupt\n", __func__); /* save the event */ - DEBUG("%s bus error interrupt, ecc=%08x\n", __func__, - CAN.error_code_capture_reg.val); - dev->events |= CAN.error_code_capture_reg.dir ? ESP_CAN_EVENT_RX_ERROR - : ESP_CAN_EVENT_TX_ERROR; + dev->events |= ESP_CAN_EVENT_TX_ERROR; } /* TX buffer becomes free */ - if (int_reg & TWAI_LL_INTR_TI) { + if (events & TWAI_HAL_EVENT_TX_BUFF_FREE) { DEBUG("%s transmit interrupt\n", __func__); /* save the event */ dev->events |= ESP_CAN_EVENT_TX_CONFIRMATION; } /* RX buffer has one or more frames */ - if (int_reg & TWAI_LL_INTR_RI) { + if (events & TWAI_HAL_EVENT_RX_BUFF_FRAME) { /* get the number of messages in receive buffer */ - uint32_t msg_cnt = CAN.rx_message_counter_reg.val; + uint32_t msg_cnt = twai_hal_get_rx_msg_count(&hw); - DEBUG("%s receive interrupt, msg_cnt=%d\n", __func__, msg_cnt); + DEBUG("%s receive interrupt, msg_cnt=%"PRIu32"\n", __func__, msg_cnt); for (unsigned i = 0; i < msg_cnt; i++) { - _esp_can_frame_t esp_frame; - /* fetch the frame from RX buffer of ESP32 */ - for (unsigned j = 0; j < ESP_CAN_FRAME_LEN; j++) { - esp_frame.bytes[j] = CAN.tx_rx_buffer[j].val; - } - /* clear RX buffer at read position */ - CAN.command_reg.val = ESP_CMD_RELEASE_RX_BUFF; - - if (dev->rx_frames_num < ESP_CAN_MAX_RX_FRAMES) { + twai_hal_frame_t esp_frame; + if (twai_hal_read_rx_buffer_and_clear(&hw, &esp_frame) && + (dev->rx_frames_num < ESP_CAN_MAX_RX_FRAMES)) { /* prepare the CAN frame from ESP32 CAN frame */ struct can_frame frame = {}; - if (esp_frame.eff) { + if (esp_frame.frame_format) { frame.can_id = esp_frame.extended.id[0]; frame.can_id = (frame.can_id << 8) | esp_frame.extended.id[1]; frame.can_id = (frame.can_id << 8) | esp_frame.extended.id[2]; @@ -850,7 +824,7 @@ static void IRAM_ATTR _esp_can_intr_handler(void *arg) memcpy(frame.data, &esp_frame.standard.data, CAN_MAX_DLEN); } frame.can_id |= esp_frame.rtr ? CAN_RTR_FLAG : 0; - frame.can_id |= esp_frame.eff ? CAN_EFF_FLAG : 0; + frame.can_id |= esp_frame.frame_format ? CAN_EFF_FLAG : 0; frame.can_dlc = esp_frame.dlc; /* apply acceptance filters only if they are set */ @@ -877,27 +851,20 @@ static void IRAM_ATTR _esp_can_intr_handler(void *arg) dev->rx_frames_num++; dev->rx_frames_wptr++; dev->rx_frames_wptr &= ESP_CAN_MAX_RX_FRAMES-1; - } + + /* at least one RX frame has been saved */ + dev->events |= ESP_CAN_EVENT_RX_INDICATION; + } } else { DEBUG("%s receive buffer overrun\n", __func__); /* we use rx error since there is no separate overrun error */ dev->events |= ESP_CAN_EVENT_RX_ERROR; } - } - /* save the event */ - dev->events |= ESP_CAN_EVENT_RX_INDICATION; - } - - /* data overrun interrupts are not handled */ - if (int_reg & BIT(3)) { - DEBUG("%s data overrun interrupt\n", __func__); - /* we use rx error since there is no separate overrun error */ - dev->events |= ESP_CAN_EVENT_RX_INDICATION; } - DEBUG("%s events=%08x\n", __func__, dev->events); + DEBUG("%s events=%08"PRIx32"\n", __func__, dev->events); /* inform the upper layer that there are events to be handled */ if (dev->events && dev->candev.event_callback) { @@ -907,34 +874,38 @@ static void IRAM_ATTR _esp_can_intr_handler(void *arg) critical_exit(); } +/* accept all CAN messages by default, filtering is done by software */ +static const twai_filter_config_t twai_filter = { + .single_filter = false, /* single filter */ + .acceptance_mask = UINT32_MAX, /* all bits masked */ +}; + static void _esp_can_set_bittiming(can_t *dev) { + /* sets the bus timing, the CAN controller has to stopped before using + * function _esp_can_stop(dev) and has to be restartet using + * function _esp_can_start() afterwards */ + assert(dev); struct can_bittiming* timing = &dev->candev.bittiming; - DEBUG("%s %p bitrate=%d, brp=%d, sample_point=%d, tq=%d, " - "prop_seg=%d phase_seg1=%d, phase_seg2=%d, sjw =%d\n", __func__, dev, + DEBUG("%s %p bitrate=%"PRIu32", brp=%"PRIu32", sample_point=%"PRIu32", " + "tq=%"PRIu32", prop_seg=%"PRIu32" phase_seg1=%"PRIu32", " + "phase_seg2=%"PRIu32", sjw =%"PRIu32"\n", __func__, dev, timing->bitrate, timing->brp, timing->sample_point, timing->tq, timing->prop_seg, timing->phase_seg1, timing->phase_seg2, timing->sjw); - _esp_can_set_reset_mode(); - - /* Again cppcheck gets off rails due to missing concept of union (see - * explanation above), so we suppress false unreadVariable here */ - /* cppcheck-suppress unreadVariable */ - CAN.bus_timing_0_reg.brp = (timing->brp / 2) - 1; - /* cppcheck-suppress unreadVariable */ - CAN.bus_timing_0_reg.sjw = timing->sjw - 1; - /* cppcheck-suppress unreadVariable */ - CAN.bus_timing_1_reg.tseg1 = (timing->prop_seg + timing->phase_seg1) - 1; - /* cppcheck-suppress unreadVariable */ - CAN.bus_timing_1_reg.tseg2 = timing->phase_seg2 - 1; - /* cppcheck-suppress unreadVariable */ - CAN.bus_timing_1_reg.sam = 0; - - _esp_can_set_operating_mode(); + twai_timing_config_t twai_timing = { + .brp = timing->brp, + .sjw = timing->sjw, + .tseg_1 = timing->prop_seg + timing->phase_seg1, + .tseg_2 = timing->phase_seg2, + }; + + twai_hal_configure(&hw, &twai_timing, &twai_filter, + ESP_CAN_INTR_MASK, CAN_CLK_OUT_DIV); } void can_init(can_t *dev, const can_conf_t *conf) @@ -947,20 +918,11 @@ void can_init(can_t *dev, const can_conf_t *conf) dev->candev.driver = &_esp_can_driver; dev->candev.bittiming.bitrate = conf->bitrate; - dev->tx_pin = conf->tx_pin; - dev->rx_pin = conf->rx_pin; -#ifdef ESP_CAN_CLK_OUT - dev->clk_out_pin = conf->clk_out_pin; -#endif -#ifdef ESP_CAN_BUS_ON_OFF - dev->bus_on_off_pin = conf->bus_on_off_pin; -#endif - /* determine the hardware bittiming constants */ struct can_bittiming_const timing_const = bittiming_const; /* calculate the initial bittimings from the bittiming constants */ - can_device_calc_bittiming (ESP_CAN_CLOCK, &timing_const, &dev->candev.bittiming); + can_device_calc_bittiming(ESP_CAN_CLOCK, &timing_const, &dev->candev.bittiming); /* initialize other members */ dev->state = CAN_STATE_SLEEPING; @@ -970,7 +932,6 @@ void can_init(can_t *dev, const can_conf_t *conf) dev->rx_frames_num = 0; dev->rx_filter_num = 0; dev->powered_up = false; - } void can_print_config(void) From c8dcdda4238927829d442ad01ce5cd6e8a390e5d Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 18:32:22 +0100 Subject: [PATCH 22/46] cpu/esp32: port periph/dac to ESP-IDF dac API --- cpu/esp32/include/periph_cpu.h | 2 +- cpu/esp32/periph/dac.c | 97 +++++++++++----------------------- 2 files changed, 32 insertions(+), 67 deletions(-) diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index fe87da3c7269..c58163a104ae 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -278,7 +278,7 @@ typedef enum { /** * @brief Number of DAC channels that could be used at maximum. */ -#define DAC_NUMOF_MAX 2 +#define DAC_NUMOF_MAX (SOC_DAC_PERIPH_NUM) /** @} */ diff --git a/cpu/esp32/periph/dac.c b/cpu/esp32/periph/dac.c index d17fff3a22c0..4ee55d92ac7d 100644 --- a/cpu/esp32/periph/dac.c +++ b/cpu/esp32/periph/dac.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Gunar Schorcht + * Copyright (C) 2022 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 @@ -22,108 +22,73 @@ #include "board.h" #include "periph/dac.h" -#include "adc_arch.h" -#include "adc_ctrl.h" #include "esp_common.h" -#include "gpio_arch.h" -#include "soc/rtc_io_struct.h" -#include "soc/rtc_cntl_struct.h" -#include "soc/sens_reg.h" -#include "soc/sens_struct.h" +#include "soc/dac_periph.h" +#include "esp_idf_api/dac.h" #define ENABLE_DEBUG 0 #include "debug.h" -/* declaration of external functions */ -extern void _adc2_ctrl_init(void); - /* forward declarations of internal functions */ static bool _dac_conf_check(void); static bool _dac_module_initialized = false; -/* external variable declarations */ -extern const gpio_t _gpio_rtcio_map[]; +/* RIOT DAC line to ESP-IDF channel map, filled during initialization */ +dac_channel_t _dac_channels[DAC_NUMOF] = { DAC_CHANNEL_MAX }; -int8_t dac_init (dac_t line) +int8_t dac_init(dac_t line) { - CHECK_PARAM_RET (line < DAC_NUMOF, DAC_NOLINE) - if (!_dac_module_initialized) { - /* do some configuration checks */ + /* do some configuration checks and fill _dac_channel */ if (!_dac_conf_check()) { return DAC_NOLINE; } _dac_module_initialized = true; } - _adc2_ctrl_init(); - - uint8_t rtcio = _gpio_rtcio_map[dac_channels[line]]; - uint8_t idx; - - /* try to initialize the pin as DAC output */ - if (gpio_get_pin_usage(_adc_hw[rtcio].gpio) != _GPIO) { - LOG_TAG_ERROR("dac", "GPIO%d is used for %s and cannot be used as " - "DAC output\n", _adc_hw[rtcio].gpio, - gpio_get_pin_usage_str(_adc_hw[rtcio].gpio)); + if ((line >= DAC_NUMOF) || (_dac_channels[line] == DAC_CHANNEL_MAX)) { + LOG_TAG_ERROR("dac", "Line %u is an invalid DAC line\n", line); return DAC_NOLINE; } - /* disable the output of the pad */ - RTCIO.enable_w1tc.val = BIT(_adc_hw[rtcio].rtc_gpio); - - switch (rtcio) { - case RTCIO_DAC1: /* GPIO25, RTC6 */ - case RTCIO_DAC2: /* GPIO26, RTC7 */ - idx = rtcio - RTCIO_DAC1; - RTCIO.pad_dac[idx].mux_sel = 1; /* route to RTC */ - RTCIO.pad_dac[idx].fun_sel = 0; /* function ADC2_CH8, ADC2_CH9 */ - RTCIO.pad_dac[idx].fun_ie = 0; /* input disabled */ - RTCIO.pad_dac[idx].rue = 0; /* pull-up disabled */ - RTCIO.pad_dac[idx].rde = 0; /* pull-down disabled */ - - RTCIO.pad_dac[idx].dac_xpd_force = 1; /* use RTC pad not the FSM*/ - RTCIO.pad_dac[idx].xpd_dac = 1; /* DAC powered on */ - break; - - default: return DAC_NOLINE; - } - - /* set pin usage type */ - gpio_set_pin_usage(_adc_hw[rtcio].gpio, _DAC); - - /* don't use DMA */ - SENS.sar_dac_ctrl1.dac_dig_force = 0; - - /* disable CW generators and invert DAC signal */ - SENS.sar_dac_ctrl1.sw_tone_en = 0; - SENS.sar_dac_ctrl2.dac_cw_en1 = 0; - SENS.sar_dac_ctrl2.dac_cw_en2 = 0; + dac_poweron(line); + dac_set(line, 0); return DAC_OK; } -void dac_set (dac_t line, uint16_t value) +void dac_set(dac_t line, uint16_t value) { - CHECK_PARAM (line < DAC_NUMOF); - RTCIO.pad_dac[_gpio_rtcio_map[dac_channels[line]] - RTCIO_DAC1].dac = value >> 8; + assert(line < DAC_NUMOF); + assert(_dac_channels[line] != DAC_CHANNEL_MAX); + esp_idf_dac_output_voltage(_dac_channels[line], + value >> (16 - SOC_DAC_RESOLUTION)); } -void dac_poweroff (dac_t line) +void dac_poweroff(dac_t line) { - CHECK_PARAM (line < DAC_NUMOF); + assert(line < DAC_NUMOF); + assert(_dac_channels[line] != DAC_CHANNEL_MAX); + esp_idf_dac_output_disable(_dac_channels[line]); } -void dac_poweron (dac_t line) +void dac_poweron(dac_t line) { - CHECK_PARAM (line < DAC_NUMOF); + assert(line < DAC_NUMOF); + assert(_dac_channels[line] != DAC_CHANNEL_MAX); + esp_idf_dac_output_enable(_dac_channels[line]); } static bool _dac_conf_check(void) { for (unsigned i = 0; i < DAC_NUMOF; i++) { - if (_gpio_rtcio_map[dac_channels[i]] != RTCIO_DAC1 && - _gpio_rtcio_map[dac_channels[i]] != RTCIO_DAC2) { + for (unsigned j = 0; i < SOC_DAC_PERIPH_NUM; j++) { + if (dac_channels[i] == dac_periph_signal.dac_channel_io_num[j]) { + _dac_channels[i] = j; + break; + } + } + if (_dac_channels[i] == DAC_CHANNEL_MAX) { LOG_TAG_ERROR("dac", "GPIO%d cannot be used as DAC line\n", dac_channels[i]); return false; From fc3b749f00e857f33ee6c8d041608df02f967c11 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 9 Mar 2022 18:36:15 +0100 Subject: [PATCH 23/46] cpu/esp32: port periph/i2c_hw to ESP-IDF i2c HAL --- .../common/esp32/include/periph_conf_common.h | 40 +- cpu/esp32/include/periph_cpu.h | 5 +- cpu/esp32/periph/i2c_hw.c | 944 +++++++----------- ...e-the-include-gpio.h-in-i2c.h-header.patch | 38 + ...expose-i2c_hw_fsm_reset-to-RIOT-code.patch | 34 + 5 files changed, 449 insertions(+), 612 deletions(-) create mode 100644 pkg/esp32_sdk/patches/0015-driver-i2c-remove-the-include-gpio.h-in-i2c.h-header.patch create mode 100644 pkg/esp32_sdk/patches/0016-driver-i2c.h-expose-i2c_hw_fsm_reset-to-RIOT-code.patch diff --git a/boards/common/esp32/include/periph_conf_common.h b/boards/common/esp32/include/periph_conf_common.h index 437ba58f4947..c50f386b5036 100644 --- a/boards/common/esp32/include/periph_conf_common.h +++ b/boards/common/esp32/include/periph_conf_common.h @@ -100,24 +100,48 @@ static const gpio_t dac_channels[] = DAC_GPIOS; * @{ */ +#if defined(I2C0_SCL) && !defined(I2C0_SCL_PULLUP) +/** Define SCL pullup enabled by default */ +#define I2C0_SCL_PULLUP true +#endif +#if defined(I2C0_SDA) && !defined(I2C0_SDA_PULLUP) +/** Define SDA pullup enabled by default */ +#define I2C0_SDA_PULLUP true +#endif + +#if defined(I2C1_SCL) && !defined(I2C1_SCL_PULLUP) +/** Define SCL pullup enabled by default */ +#define I2C1_SCL_PULLUP true +#endif +#if defined(I2C1_SDA) && !defined(I2C1_SDA_PULLUP) +/** Define SDA pullup enabled by default */ +#define I2C1_SDA_PULLUP true +#endif + /** * @brief Static array with configuration for declared I2C devices */ static const i2c_conf_t i2c_config[] = { - #if defined(I2C0_SCL) && defined(I2C0_SDA) && defined(I2C0_SPEED) +#if defined(I2C0_SCL) && defined(I2C0_SDA) && defined(I2C0_SPEED) { + .module = PERIPH_I2C0_MODULE, .speed = I2C0_SPEED, .scl = I2C0_SCL, .sda = I2C0_SDA, + .scl_pullup = I2C0_SCL_PULLUP, + .sda_pullup = I2C0_SCL_PULLUP, }, - #endif - #if defined(I2C1_SCL) && defined(I2C1_SDA) && defined(I2C1_SPEED) +#endif +#if defined(I2C1_SCL) && defined(I2C1_SDA) && defined(I2C1_SPEED) { + .module = PERIPH_I2C1_MODULE, .speed = I2C1_SPEED, .scl = I2C1_SCL, .sda = I2C1_SDA, + .scl_pullup = I2C1_SCL_PULLUP, + .sda_pullup = I2C1_SCL_PULLUP, }, - #endif +#endif }; /** @@ -228,18 +252,18 @@ static const uart_conf_t uart_config[] = { .txd = UART0_TXD, .rxd = UART0_RXD, }, - #if defined(UART1_TXD) && defined(UART1_RXD) +#if defined(UART1_TXD) && defined(UART1_RXD) { .txd = UART1_TXD, .rxd = UART1_RXD, }, - #endif - #if defined(UART2_TXD) && defined(UART2_RXD) +#endif +#if defined(UART2_TXD) && defined(UART2_RXD) { .txd = UART2_TXD, .rxd = UART2_RXD, }, - #endif +#endif }; /** diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index c58163a104ae..92208108870a 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -328,15 +328,18 @@ typedef enum { * @brief I2C configuration structure type */ typedef struct { + uint8_t module; /**< I2C module identifier */ i2c_speed_t speed; /**< I2C bus speed */ gpio_t scl; /**< GPIO used as SCL pin */ gpio_t sda; /**< GPIO used as SDA pin */ + bool scl_pullup; /**< Pullup enabled for SCL pin */ + bool sda_pullup; /**< Pullup enabled for SDA pin */ } i2c_conf_t; /** * @brief Maximum number of I2C interfaces that can be used by board definitions */ -#define I2C_NUMOF_MAX (2) +#define I2C_NUMOF_MAX (SOC_I2C_NUM) #define PERIPH_I2C_NEED_READ_REG /**< i2c_read_reg required */ #define PERIPH_I2C_NEED_READ_REGS /**< i2c_read_regs required */ diff --git a/cpu/esp32/periph/i2c_hw.c b/cpu/esp32/periph/i2c_hw.c index 2e14589eeb5c..fb8388a4e69b 100644 --- a/cpu/esp32/periph/i2c_hw.c +++ b/cpu/esp32/periph/i2c_hw.c @@ -25,266 +25,175 @@ * @} */ -#if defined(MODULE_ESP_I2C_HW) /* hardware implementation used */ - -/** - * PLEASE NOTE: - * - * Some parts of the implementation were inspired by the Espressif IoT - * Development Framework [ESP-IDF](https://github.com/espressif/esp-idf.git) - * implementation of I2C. These partes are marked with an according copyright - * notice. -*/ - -#define ENABLE_DEBUG 0 -#include "debug.h" - -#include +/* + * The I2C peripheral driver uses a mixture of the high level functions and + * the HAL driver. While complex functions like the configuration of the I2C + * interface use the high level interface, the HAL interface is used by data + * transfer functions for better performance and better control. + */ #include -#include -#include -#include "cpu.h" +#include "gpio_arch.h" +#include "irq_arch.h" #include "log.h" +#include "macros/units.h" #include "mutex.h" #include "periph_conf.h" -#include "periph/gpio.h" #include "periph/i2c.h" -#include "thread_flags.h" +#include "ztimer.h" -#include "esp_common.h" #include "esp_attr.h" -#include "gpio_arch.h" -#include "driver/periph_ctrl.h" -#include "irq_arch.h" +#include "driver/i2c.h" +#include "hal/i2c_hal.h" +#include "hal/interrupt_controller_types.h" +#include "hal/interrupt_controller_ll.h" #include "rom/ets_sys.h" -#include "soc/gpio_reg.h" -#include "soc/gpio_sig_map.h" -#include "soc/gpio_struct.h" #include "soc/i2c_reg.h" -#include "soc/i2c_struct.h" -#include "soc/rtc.h" -#include "soc/soc.h" -#include "syscalls.h" -#include "xtensa/xtensa_api.h" - -#undef MHZ -#include "macros/units.h" - -#if defined(I2C0_SPEED) || defined(I2C1_SPEED) - -/* operation codes used for commands */ -#define I2C_CMD_RSTART 0 -#define I2C_CMD_WRITE 1 -#define I2C_CMD_READ 2 -#define I2C_CMD_STOP 3 -#define I2C_CMD_END 4 -/* maximum number of data that can be written / read in one transfer */ -#define I2C_MAX_DATA 30 - -#define I2C_FIFO_USED 1 +#define ENABLE_DEBUG 0 +#include "debug.h" -struct i2c_hw_t { - i2c_dev_t* regs; /* pointer to register data struct of the I2C device */ - uint8_t mod; /* peripheral hardware module of the I2C interface */ - uint8_t int_src; /* peripheral interrupt source used by the I2C device */ - uint8_t signal_scl_in; /* SCL signal to the controller */ - uint8_t signal_scl_out; /* SCL signal from the controller */ - uint8_t signal_sda_in; /* SDA signal to the controller */ - uint8_t signal_sda_out; /* SDA signal from the controller */ +typedef struct { + i2c_speed_t clk_freq; /* clock freuency in Hz according to bus speed */ + uint8_t cmd; /* command index of a transfer*/ + uint8_t cmd_op; /* main command op code of a transfer */ + uint8_t len; /* data length of a transfer */ + uint32_t status; /* results of a transfer */ + mutex_t cmd_lock; /* command execution locking */ + mutex_t dev_lock; /* device locking */ +} _i2c_bus_t; + +static i2c_hal_context_t _i2c_hw[] = { +#if defined(I2C0_SPEED) + { .dev = I2C_LL_GET_HW(0) }, +#endif +#if defined(I2C1_SPEED) + { .dev = I2C_LL_GET_HW(1) }, +#endif }; -static const struct i2c_hw_t _i2c_hw[] = { +static _i2c_bus_t _i2c_bus[I2C_NUMOF] = { +#if defined(I2C0_SPEED) { - .regs = &I2C0, - .mod = PERIPH_I2C0_MODULE, - .int_src = ETS_I2C_EXT0_INTR_SOURCE, - .signal_scl_in = I2CEXT0_SCL_IN_IDX, - .signal_scl_out = I2CEXT0_SCL_OUT_IDX, - .signal_sda_in = I2CEXT0_SDA_IN_IDX, - .signal_sda_out = I2CEXT0_SDA_OUT_IDX, + .cmd_lock = MUTEX_INIT_LOCKED, + .dev_lock = MUTEX_INIT, }, +#endif +#if defined(I2C1_SPEED) { - .regs = &I2C1, - .mod = PERIPH_I2C1_MODULE, - .int_src = ETS_I2C_EXT1_INTR_SOURCE, - .signal_scl_in = I2CEXT1_SCL_IN_IDX, - .signal_scl_out = I2CEXT1_SCL_OUT_IDX, - .signal_sda_in = I2CEXT1_SDA_IN_IDX, - .signal_sda_out = I2CEXT1_SDA_OUT_IDX, - } -}; - -struct _i2c_bus_t -{ - i2c_speed_t speed; /* bus speed */ - uint8_t cmd; /* command index */ - uint8_t data; /* index in RAM for data */ - mutex_t lock; /* mutex lock */ - kernel_pid_t pid; /* PID of thread that triggered a transfer */ - uint32_t results; /* results of a transfer */ + .cmd_lock = MUTEX_INIT_LOCKED, + .dev_lock = MUTEX_INIT, + }, +#endif }; -static struct _i2c_bus_t _i2c_bus[I2C_NUMOF] = {}; +/* functions used from ESP-IDF driver that are not exposed in API */ +extern esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num); /* forward declaration of internal functions */ - -static int _i2c_init_pins (i2c_t dev); -static void _i2c_start_cmd (i2c_t dev); -static void _i2c_stop_cmd (i2c_t dev); -static void _i2c_end_cmd (i2c_t dev); -static void _i2c_write_cmd (i2c_t dev, const uint8_t* data, uint8_t len); -static void _i2c_read_cmd (i2c_t dev, uint8_t* data, uint8_t len, bool last); -static void _i2c_transfer (i2c_t dev); -static void _i2c_reset_hw (i2c_t dev); -static void _i2c_clear_bus (i2c_t dev); -static void _i2c_intr_handler (void *arg); -static inline void _i2c_delay (uint32_t delay); - -/* implementation of i2c interface */ +static void _i2c_start_cmd(i2c_t dev); +static void _i2c_stop_cmd(i2c_t dev); +static void _i2c_end_cmd(i2c_t dev); +static void _i2c_write_cmd(i2c_t dev, const uint8_t* data, uint8_t len); +static void _i2c_read_cmd(i2c_t dev, uint8_t len, bool last); +static void _i2c_transfer(i2c_t dev); +static void _i2c_intr_handler(void *arg); +static int _i2c_status_to_errno(i2c_t dev); void i2c_init(i2c_t dev) { + _Static_assert(I2C_NUMOF <= I2C_NUMOF_MAX, "Too many I2C devices defined"); + _Static_assert(I2C_NUMOF == ARRAY_SIZE(_i2c_hw), + "Number of hardware descriptors doesn't match the I2C_NUMOF"); + assert(dev < I2C_NUMOF); /* According to the Technical Reference Manual, only FAST mode is supported, * but FAST PLUS mode seems to work also. */ assert(i2c_config[dev].speed <= I2C_SPEED_FAST_PLUS); - mutex_init(&_i2c_bus[dev].lock); + if (gpio_get_pin_usage(i2c_config[dev].scl) == _I2C) { + gpio_set_pin_usage(i2c_config[dev].scl, _GPIO); + } + if (gpio_get_pin_usage(i2c_config[dev].sda) == _I2C) { + gpio_set_pin_usage(i2c_config[dev].sda, _GPIO); + } - i2c_acquire(dev); + if ((gpio_get_pin_usage(i2c_config[dev].scl) != _GPIO) || + (gpio_get_pin_usage(i2c_config[dev].sda) != _GPIO)) { + LOG_TAG_ERROR("i2c", "GPIO%u and/or GPIO%u are used for %s/%s and " + "cannot be used as I2C interface\n", + i2c_config[dev].scl, i2c_config[dev].sda, + gpio_get_pin_usage_str(i2c_config[dev].scl), + gpio_get_pin_usage_str(i2c_config[dev].sda)); + assert(0); + } _i2c_bus[dev].cmd = 0; - _i2c_bus[dev].data = 0; - _i2c_bus[dev].speed = i2c_config[dev].speed; + _i2c_bus[dev].len = 0; - DEBUG ("%s scl=%d sda=%d speed=%d\n", __func__, - i2c_config[dev].scl, i2c_config[dev].sda, _i2c_bus[dev].speed); + i2c_acquire(dev); - /* enable (power on) the according I2C module */ - periph_module_enable(_i2c_hw[dev].mod); + i2c_config_t cfg = {}; - /* initialize pins */ - if (_i2c_init_pins(dev) != 0) { - return; + cfg.mode = I2C_MODE_MASTER; + cfg.sda_io_num = i2c_config[dev].sda; + cfg.scl_io_num = i2c_config[dev].scl; + cfg.sda_pullup_en = i2c_config[dev].sda_pullup; + cfg.scl_pullup_en = i2c_config[dev].scl_pullup; +#if SOC_I2C_SUPPORT_RTC + cfg.clk_flags = I2C_SCLK_SRC_FLAG_LIGHT_SLEEP; +#endif + + switch (i2c_config[dev].speed) { + case I2C_SPEED_LOW: + cfg.master.clk_speed = 10 * KHZ(1); + break; + case I2C_SPEED_NORMAL: + cfg.master.clk_speed = 100 * KHZ(1); + break; + case I2C_SPEED_FAST: + cfg.master.clk_speed = 400 * KHZ(1); + break; + case I2C_SPEED_FAST_PLUS: + cfg.master.clk_speed = 1000 * KHZ(1); + break; + case I2C_SPEED_HIGH: + cfg.master.clk_speed = 3400 * KHZ(1); + break; + default: + LOG_TAG_ERROR("i2c", "Invalid speed value in %s\n", __func__); + assert(0); } - /* set master mode */ - _i2c_hw[dev].regs->ctr.ms_mode = 1; + _i2c_bus[dev].clk_freq = cfg.master.clk_speed; - /* set bit order to MSB first */ - _i2c_hw[dev].regs->ctr.tx_lsb_first = 0; - _i2c_hw[dev].regs->ctr.rx_lsb_first = 0; + /* configures the GPIOs, sets the bus timing and enables the periphery */ + i2c_param_config(dev, &cfg); - /* determine the half period of clock in APB clock cycles */ - uint32_t half_period = 0; +#if defined(SOC_I2C_SUPPORT_APB) + /* If I2C clock is derived from APB clock, the bus timing parameters + * have to be corrected if the APB clock is less than 80 MHz */ + extern uint32_t rtc_clk_apb_freq_get(void); uint32_t apb_clk = rtc_clk_apb_freq_get(); - if (apb_clk == MHZ(2)) { - /* CPU clock frequency of 2 MHz requires special handling */ - switch (_i2c_bus[dev].speed) { - case I2C_SPEED_LOW: - /* 10 kbps (period 100 us) */ - half_period = 95; - break; - - case I2C_SPEED_NORMAL: - /* 100 kbps (period 10 us) */ - /* NOTE: Correct value for half_period would be 6 to produce a - * 100 kHz clock. However, a value of at least 18 is - * necessary to work correctly which corresponds to a - * I2C clock speed of 30 kHz. - */ - half_period = 18; - break; - - default: - LOG_TAG_ERROR("i2c", "I2C clock speed not supported in " - "hardware with CPU clock 2 MHz, use the " - "software implementation instead\n"); - assert(0); - } + if (apb_clk < MHZ(80)) { + i2c_clk_cal_t clk_cfg; + i2c_ll_cal_bus_clk(apb_clk, cfg.master.clk_speed, &clk_cfg); + i2c_ll_set_bus_timing(_i2c_hw[dev].dev, &clk_cfg); } - else { - switch (_i2c_bus[dev].speed) { - case I2C_SPEED_LOW: - /* 10 kbps (period 100 us) */ - half_period = (apb_clk / 10000) >> 1; - break; - - case I2C_SPEED_NORMAL: - /* 100 kbps (period 10 us) */ - half_period = (apb_clk / 100000) >> 1; - break; - - case I2C_SPEED_FAST: - /* 400 kbps (period 2.5 us) */ - half_period = (apb_clk / 400000) >> 1; - break; - - case I2C_SPEED_FAST_PLUS: - /* 1 Mbps (period 1 us) */ - half_period = (apb_clk / 1000000) >> 1; - break; - - case I2C_SPEED_HIGH: - /* 3.4 Mbps (period 0.3 us) not working */ - half_period = (apb_clk / 3400000) >> 1; - break; - - default: - LOG_TAG_ERROR("i2c", "Invalid speed value in %s\n", __func__); - assert(0); - } - } - - /* set an timeout which is at least 16 times of half cycle */ - _i2c_hw[dev].regs->timeout.tout = half_period << 4; - - /* timing for SCL (low and high time in APB clock cycles) */ - _i2c_hw[dev].regs->scl_low_period.period = half_period; - _i2c_hw[dev].regs->scl_high_period.period = half_period; - - /* timing for SDA (sample time after rising edge and hold time after falling edge) */ - _i2c_hw[dev].regs->sda_sample.time = half_period >> 1; - _i2c_hw[dev].regs->sda_hold.time = half_period >> 1; - - /* timing for START condition (START hold and repeated START setup time) */ - _i2c_hw[dev].regs->scl_start_hold.time = half_period >> 1; - _i2c_hw[dev].regs->scl_rstart_setup.time = half_period >> 1; - - /* timing for STOP condition (STOP hold and STOP setup time) */ - _i2c_hw[dev].regs->scl_stop_hold.time = half_period >> 1; - _i2c_hw[dev].regs->scl_stop_setup.time = half_period >> 1; - - /* configure open drain outputs */ - _i2c_hw[dev].regs->ctr.scl_force_out = 1; - _i2c_hw[dev].regs->ctr.sda_force_out = 1; - - /* sample data during high level */ - _i2c_hw[dev].regs->ctr.sample_scl_level = 0; - - /* enable non FIFO access and disable slave FIFO address offset */ - #if I2C_FIFO_USED - _i2c_hw[dev].regs->fifo_conf.nonfifo_en = 0; - #else - _i2c_hw[dev].regs->fifo_conf.nonfifo_en = 1; - _i2c_hw[dev].regs->fifo_conf.nonfifo_rx_thres = 0; - _i2c_hw[dev].regs->fifo_conf.nonfifo_tx_thres = 0; - _i2c_hw[dev].regs->fifo_conf.rx_fifo_full_thrhd = 0; - _i2c_hw[dev].regs->fifo_conf.tx_fifo_empty_thrhd = 0; +#endif - #endif - _i2c_hw[dev].regs->fifo_conf.fifo_addr_cfg_en = 0; + /* store the usage type in GPIO table */ + gpio_set_pin_usage(i2c_config[dev].scl, _I2C); + gpio_set_pin_usage(i2c_config[dev].sda, _I2C); /* route all I2C interrupt sources to same the CPU interrupt */ - intr_matrix_set(PRO_CPU_NUM, _i2c_hw[dev].int_src, CPU_INUM_I2C); + intr_matrix_set(PRO_CPU_NUM, i2c_periph_signal[dev].irq, CPU_INUM_I2C); - /* set the interrupt handler and enable the interrupt */ - xt_set_interrupt_handler(CPU_INUM_I2C, _i2c_intr_handler, NULL); - xt_ints_on(BIT(CPU_INUM_I2C)); + /* set interrupt handler and enable the CPU interrupt */ + intr_cntrl_ll_set_int_handler(CPU_INUM_I2C, _i2c_intr_handler, NULL); + intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_I2C)); i2c_release(dev); } @@ -292,88 +201,19 @@ void i2c_init(i2c_t dev) void i2c_acquire(i2c_t dev) { DEBUG ("%s\n", __func__); - assert(dev < I2C_NUMOF); - mutex_lock(&_i2c_bus[dev].lock); - _i2c_reset_hw(dev); + mutex_lock(&_i2c_bus[dev].dev_lock); } void i2c_release(i2c_t dev) { DEBUG ("%s\n", __func__); - assert(dev < I2C_NUMOF); - _i2c_reset_hw (dev); - mutex_unlock(&_i2c_bus[dev].lock); + mutex_unlock(&_i2c_bus[dev].dev_lock); } -/* - * This macro checks the result of a read transfer. In case of an error, - * the hardware is reset and returned with a corresponding error code. - * - * @note: - * In a read transfer, an ACK is only expected for the address field. Thus, - * an ACK error can only happen for the address field. Therefore, we always - * return -ENXIO in case of an ACK error. - */ -#define _i2c_return_on_error_read(dev) \ - if (_i2c_bus[dev].results & I2C_ARBITRATION_LOST_INT_ENA) { \ - LOG_TAG_DEBUG("i2c", "arbitration lost dev=%u\n", dev); \ - _i2c_reset_hw (dev); \ - __asm__ volatile ("isync"); \ - return -EAGAIN; \ - } \ - else if (_i2c_bus[dev].results & I2C_ACK_ERR_INT_ENA) { \ - LOG_TAG_DEBUG("i2c", "ack error dev=%u\n", dev); \ - _i2c_reset_hw (dev); \ - __asm__ volatile ("isync"); \ - return -ENXIO; \ - } \ - else if (_i2c_bus[dev].results & I2C_TIME_OUT_INT_ENA) { \ - LOG_TAG_DEBUG("i2c", "bus timeout dev=%u\n", dev); \ - _i2c_reset_hw (dev); \ - __asm__ volatile ("isync"); \ - return -ETIMEDOUT; \ - } - -/* - * This macro checks the result of a write transfer. In case of an error, - * the hardware is reset and returned with a corresponding error code. - * - * @note: - * In a write transfer, an ACK error can happen for the address field - * as well as for data. If the FIFO still contains all data bytes, - * (i.e. _i2c_hw[dev].regs->status_reg.tx_fifo_cnt >= len), the ACK error - * happened in address field and we have to returen -ENXIO. Otherwise, the - * ACK error happened in data field and we have to return -EIO. - */ -#define _i2c_return_on_error_write(dev) \ - if (_i2c_bus[dev].results & I2C_ARBITRATION_LOST_INT_ENA) { \ - LOG_TAG_DEBUG("i2c", "arbitration lost dev=%u\n", dev); \ - _i2c_reset_hw (dev); \ - __asm__ volatile ("isync"); \ - return -EAGAIN; \ - } \ - else if (_i2c_bus[dev].results & I2C_ACK_ERR_INT_ENA) { \ - LOG_TAG_DEBUG("i2c", "ack error dev=%u\n", dev); \ - _i2c_reset_hw (dev); \ - __asm__ volatile ("isync"); \ - if (_i2c_hw[dev].regs->status_reg.tx_fifo_cnt >= len) { \ - return -ENXIO; \ - } \ - else { \ - return -EIO; \ - } \ - } \ - else if (_i2c_bus[dev].results & I2C_TIME_OUT_INT_ENA) { \ - LOG_TAG_DEBUG("i2c", "bus timeout dev=%u\n", dev); \ - _i2c_reset_hw (dev); \ - __asm__ volatile ("isync"); \ - return -ETIMEDOUT; \ - } - int i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len, uint8_t flags) { DEBUG ("%s dev=%u addr=%02x data=%p len=%d flags=%01x\n", @@ -383,80 +223,86 @@ int i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len, uint8_t fla assert(len > 0); assert(data != NULL); + int res; + + _i2c_bus[dev].cmd_op = I2C_LL_CMD_READ; + _i2c_bus[dev].cmd = 0; + + /* reset TX/RX FIFO queue */ + i2c_hal_txfifo_rst(&_i2c_hw[dev]); + i2c_hal_rxfifo_rst(&_i2c_hw[dev]); + /* if I2C_NOSTART is not set, START condition and ADDR is used */ if (!(flags & I2C_NOSTART)) { - /* send START condition */ - _i2c_start_cmd (dev); + _i2c_start_cmd(dev); /* address handling */ if (flags & I2C_ADDR10) { /* prepare 10 bit address bytes */ uint8_t addr10[2]; - addr10[0] = 0xf0 | (addr & 0x0300) >> 7 | I2C_READ; + addr10[0] = 0xf0 | (addr & 0x0300) >> 7 | I2C_MASTER_READ; addr10[1] = addr & 0xff; /* send ADDR with read flag */ - _i2c_write_cmd (dev, addr10, 2); + _i2c_write_cmd(dev, addr10, 2); } else { /* send ADDR with read flag */ uint8_t addr7 = (addr << 1 | I2C_READ); - _i2c_write_cmd (dev, &addr7, 1); + _i2c_write_cmd(dev, &addr7, 1); } } - /* read data bytes in blocks of I2C_MAX_DATA bytes */ - + /* read data bytes in blocks of SOC_I2C_FIFO_LEN bytes */ uint32_t off = 0; - /* if len > I2C_MAX_DATA read blocks I2C_MAX_DATA bytes at a time */ - while (len > I2C_MAX_DATA) { - + /* if len > SOC_I2C_FIFO_LEN read SOC_I2C_FIFO_LEN bytes at a time */ + while (len > SOC_I2C_FIFO_LEN) { /* read one block of data bytes command */ - _i2c_read_cmd (dev, data, I2C_MAX_DATA, false); - _i2c_end_cmd (dev); - _i2c_transfer (dev); - _i2c_return_on_error_read (dev); + _i2c_bus[dev].len = SOC_I2C_FIFO_LEN; + _i2c_read_cmd(dev, SOC_I2C_FIFO_LEN, false); + _i2c_end_cmd(dev); + _i2c_transfer(dev); + + res = _i2c_status_to_errno(dev); + if (res) { + return res; + } /* if transfer was successful, fetch the data from I2C RAM */ - for (unsigned i = 0; i < I2C_MAX_DATA; i++) { - #if I2C_FIFO_USED - ((uint8_t*)data)[i + off] = _i2c_hw[dev].regs->fifo_data.data; - #else - ((uint8_t*)data)[i + off] = _i2c_hw[dev].regs->ram_data[i]; - #endif - } + i2c_hal_read_rxfifo(&_i2c_hw[dev], data + off, len); - len -= I2C_MAX_DATA; - off += I2C_MAX_DATA; + /* reset RX FIFO queue */ + i2c_hal_rxfifo_rst(&_i2c_hw[dev]); + + len -= SOC_I2C_FIFO_LEN; + off += SOC_I2C_FIFO_LEN; } /* read remaining data bytes command with a final NAK */ - _i2c_read_cmd (dev, data, len, true); + _i2c_bus[dev].len = len; + _i2c_read_cmd(dev, len, true); /* if I2C_NOSTOP flag is not set, send STOP condition is used */ if (!(flags & I2C_NOSTOP)) { /* send STOP condition */ - _i2c_stop_cmd (dev); + _i2c_stop_cmd(dev); } else { /* otherwise place end command in pipeline */ - _i2c_end_cmd (dev); + _i2c_end_cmd(dev); } /* finish operation by executing the command pipeline */ - _i2c_transfer (dev); - _i2c_return_on_error_read (dev); - - /* if transfer was successful, fetch data from I2C RAM */ - for (unsigned i = 0; i < len; i++) { - #if I2C_FIFO_USED - ((uint8_t*)data)[i + off] = _i2c_hw[dev].regs->fifo_data.data; - #else - ((uint8_t*)data)[i + off] = _i2c_hw[dev].regs->ram_data[i]; - #endif + _i2c_transfer(dev); + + if ((res = _i2c_status_to_errno(dev))) { + return res; } + /* fetch the data from RX FIFO */ + i2c_hal_read_rxfifo(&_i2c_hw[dev], data + off, len); + /* return 0 on success */ return 0; } @@ -470,106 +316,142 @@ int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len, uint assert(len > 0); assert(data != NULL); + int res; + + _i2c_bus[dev].cmd_op = I2C_LL_CMD_WRITE; + _i2c_bus[dev].cmd = 0; + + /* reset TX FIFO queue */ + i2c_hal_txfifo_rst(&_i2c_hw[dev]); + /* if I2C_NOSTART is not set, START condition and ADDR is used */ if (!(flags & I2C_NOSTART)) { /* send START condition */ - _i2c_start_cmd (dev); + _i2c_start_cmd(dev); /* address handling */ if (flags & I2C_ADDR10) { /* prepare 10 bit address bytes */ uint8_t addr10[2]; - addr10[0] = 0xf0 | (addr & 0x0300) >> 7; + addr10[0] = 0xf0 | (addr & 0x0300) >> 7 | I2C_MASTER_WRITE; addr10[1] = addr & 0xff; /* send ADDR without read flag */ - _i2c_write_cmd (dev, addr10, 2); + _i2c_write_cmd(dev, addr10, 2); } else { /* send ADDR without read flag */ uint8_t addr7 = addr << 1; - _i2c_write_cmd (dev, &addr7, 1); + _i2c_write_cmd(dev, &addr7, 1); } } - /* send data bytes in blocks of I2C_MAX_DATA bytes */ + /* send data bytes in blocks of SOC_I2C_FIFO_LEN bytes */ uint32_t off = 0; + uint32_t tx_fifo_free; + + /* get available TX FIFO space */ + i2c_hal_get_txfifo_cnt(&_i2c_hw[dev], &tx_fifo_free); + + /* if len > SOC_I2C_FIFO_LEN write SOC_I2C_FIFO_LEN bytes at a time */ + while (len > tx_fifo_free) { + /* send one block of data bytes */ + _i2c_bus[dev].len = tx_fifo_free; + _i2c_write_cmd(dev, (uint8_t*)data + off, tx_fifo_free); + _i2c_end_cmd(dev); + _i2c_transfer(dev); + res = _i2c_status_to_errno(dev); + + if (res) { + return res; + } - /* if len > I2C_MAX_DATA write blocks I2C_MAX_DATA bytes at a time */ - while (len > I2C_MAX_DATA) { + len -= tx_fifo_free; + off += tx_fifo_free; - /* send on block of data bytes */ - _i2c_write_cmd (dev, ((uint8_t*)data) + off, I2C_MAX_DATA); - _i2c_end_cmd (dev); - _i2c_transfer (dev); - _i2c_return_on_error_write (dev); + /* reset TX FIFO queue */ + i2c_hal_txfifo_rst(&_i2c_hw[dev]); - len -= I2C_MAX_DATA; - off += I2C_MAX_DATA; + /* update available TX FIFO space */ + i2c_hal_get_txfifo_cnt(&_i2c_hw[dev], &tx_fifo_free); } /* write remaining data bytes command */ - _i2c_write_cmd (dev, ((uint8_t*)data), len); + _i2c_bus[dev].len = len; + _i2c_write_cmd(dev, (uint8_t*)data + off, len); /* if I2C_NOSTOP flag is not set, send STOP condition is used */ if (!(flags & I2C_NOSTOP)) { /* send STOP condition */ - _i2c_stop_cmd (dev); + _i2c_stop_cmd(dev); } else { /* otherwise place end command in pipeline */ - _i2c_end_cmd (dev); + _i2c_end_cmd(dev); } /* finish operation by executing the command pipeline */ - _i2c_transfer (dev); - _i2c_return_on_error_write (dev); + _i2c_transfer(dev); - /* return 0 on success */ - return 0; + return _i2c_status_to_errno(dev); } -/* internal functions */ +#if defined(MCU_ESP32) +#define I2C_NACK_INT_ENA_M I2C_ACK_ERR_INT_ENA_M +#endif -static int _i2c_init_pins(i2c_t dev) +/* + * @note: + * It is a known problem that the ESP32x I2C hardware implementation checks + * the ACK when the next command in the pipeline is executed. That is, + * for a segmented write operation of type `START ADDR DATA0 STOP` the + * `I2C_END_DETECT_INT` and the `I2C_NACK_INT` are triggered simultaneously + * in case of acknowledge errors. In this case it is not clear from the + * interrupt status whether the acknolegdement error has occurred for the + * ADDR or the DATA0 byte. The only way to find out is to check the remaining + * TX FIFO length. If the number of bytes in the TX-FIFO is still higher + * (for two-byte addresses) or equal (for one-byte addresses) to the length of + * the data, the acknolegdement error occurred for the ADDR field. + */ +static int _i2c_status_to_errno(i2c_t dev) { - /* - * reset GPIO usage type if the pins were used already for I2C before to - * make it possible to reinitialize I2C - */ - if (gpio_get_pin_usage(i2c_config[dev].scl) == _I2C) { - gpio_set_pin_usage(i2c_config[dev].scl, _GPIO); - } - if (gpio_get_pin_usage(i2c_config[dev].sda) == _I2C) { - gpio_set_pin_usage(i2c_config[dev].sda, _GPIO); + if (_i2c_bus[dev].status & I2C_ARBITRATION_LOST_INT_ENA_M) { + LOG_TAG_DEBUG("i2c", "arbitration lost dev=%u\n", dev); + return -EAGAIN; } - /* try to configure SDA and SCL pin as GPIO in open-drain mode with enabled pull-ups */ - if (gpio_init (i2c_config[dev].scl, GPIO_IN_OD_PU) || - gpio_init (i2c_config[dev].sda, GPIO_IN_OD_PU)) { - return -ENODEV; + if (_i2c_bus[dev].status & I2C_NACK_INT_ENA_M) { + LOG_TAG_DEBUG("i2c", "ack error dev=%u\n", dev); + if (_i2c_bus[dev].cmd_op == I2C_LL_CMD_WRITE) { + /* + * @note: In a write transfer, an ACK error can happen for the + * address field as well as for data. If the FIFO still contains + * all data bytes, the ACK error happened in address field and we + * have to return -ENXIO. Otherwise, the ACK error happened in data + * field and we have to return -EIO. + */ + uint32_t cnt; + + i2c_hal_get_txfifo_cnt(&_i2c_hw[dev], &cnt); + return ((SOC_I2C_FIFO_LEN - cnt) >= _i2c_bus[dev].len) ? -ENXIO : -EIO; + } + else { + /* + * @note: In a read transfer, an ACK is only expected for the + * address field. Thus, an ACK error can only happen for the address + * field. Therefore, we always return -ENXIO in case of an ACK + * error. + */ + return -ENXIO; + } } - /* bring signals to high */ - gpio_set(i2c_config[dev].scl); - gpio_set(i2c_config[dev].sda); - - /* store the usage type in GPIO table */ - gpio_set_pin_usage(i2c_config[dev].scl, _I2C); - gpio_set_pin_usage(i2c_config[dev].sda, _I2C); - - /* connect SCL and SDA pins to output signals through the GPIO matrix */ - GPIO.func_out_sel_cfg[i2c_config[dev].scl].func_sel = _i2c_hw[dev].signal_scl_out; - GPIO.func_out_sel_cfg[i2c_config[dev].sda].func_sel = _i2c_hw[dev].signal_sda_out; - - /* connect SCL and SDA input signals to pins through the GPIO matrix */ - GPIO.func_in_sel_cfg[_i2c_hw[dev].signal_scl_in].sig_in_sel = 1; - GPIO.func_in_sel_cfg[_i2c_hw[dev].signal_scl_in].sig_in_inv = 0; - GPIO.func_in_sel_cfg[_i2c_hw[dev].signal_scl_in].func_sel = i2c_config[dev].scl; - GPIO.func_in_sel_cfg[_i2c_hw[dev].signal_sda_in].sig_in_sel = 1; - GPIO.func_in_sel_cfg[_i2c_hw[dev].signal_sda_in].sig_in_inv = 0; - GPIO.func_in_sel_cfg[_i2c_hw[dev].signal_sda_in].func_sel = i2c_config[dev].sda; + if (_i2c_bus[dev].status & I2C_TIME_OUT_INT_ENA_M) { + LOG_TAG_DEBUG("i2c", "bus timeout dev=%u\n", dev); + i2c_hw_fsm_reset(dev); + return -ETIMEDOUT; + } return 0; } @@ -579,73 +461,67 @@ static void _i2c_start_cmd(i2c_t dev) DEBUG ("%s\n", __func__); /* place START condition command in command queue */ - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].val = 0; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].op_code = I2C_CMD_RSTART; + i2c_hw_cmd_t cmd = { .op_code = I2C_LL_CMD_RESTART }; + i2c_hal_write_cmd_reg(&_i2c_hw[dev], cmd, _i2c_bus[dev].cmd); /* increment the command counter */ _i2c_bus[dev].cmd++; } -static void _i2c_stop_cmd (i2c_t dev) +static void _i2c_stop_cmd(i2c_t dev) { DEBUG ("%s\n", __func__); /* place STOP condition command in command queue */ - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].val = 0; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].op_code = I2C_CMD_STOP; + i2c_hw_cmd_t cmd = { .op_code = I2C_LL_CMD_STOP }; + i2c_hal_write_cmd_reg(&_i2c_hw[dev], cmd, _i2c_bus[dev].cmd); /* increment the command counter */ _i2c_bus[dev].cmd++; } -static void _i2c_end_cmd (i2c_t dev) +static void _i2c_end_cmd(i2c_t dev) { DEBUG ("%s\n", __func__); /* place END command for continues data transmission in command queue */ - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].val = 0; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].op_code = I2C_CMD_END; + i2c_hw_cmd_t cmd = { .op_code = I2C_LL_CMD_END }; + i2c_hal_write_cmd_reg(&_i2c_hw[dev], cmd, _i2c_bus[dev].cmd); /* increment the command counter */ _i2c_bus[dev].cmd++; } -static void _i2c_write_cmd (i2c_t dev, const uint8_t* data, uint8_t len) +static void _i2c_write_cmd(i2c_t dev, const uint8_t* data, uint8_t len) { DEBUG ("%s dev=%u data=%p len=%d\n", __func__, dev, data, len); - if (_i2c_bus[dev].data + len > I2C_MAX_DATA) { + if (len > SOC_I2C_FIFO_LEN) { LOG_TAG_ERROR("i2c", "Maximum number of bytes (32 bytes) that can be " "sent with on transfer reached\n"); return; } - /* store the byte in RAM of I2C controller and increment the data counter */ - for (int i = 0; i < len; i++) { - #if I2C_FIFO_USED - WRITE_PERI_REG(I2C_DATA_APB_REG(dev), data[i]); - #else - _i2c_hw[dev].regs->ram_data[_i2c_bus[dev].data++] = (uint32_t)data[i]; - #endif - } + /* store the data in TX FIFO */ + i2c_hal_write_txfifo(&_i2c_hw[dev], (uint8_t *)data, len); /* place WRITE command for multiple bytes in command queue */ - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].val = 0; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].byte_num = len; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].ack_en = 1; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].ack_exp = 0; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].ack_val = 0; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].op_code = I2C_CMD_WRITE; + i2c_hw_cmd_t cmd = { .op_code = I2C_LL_CMD_WRITE, + .byte_num = len, + .ack_en = 1, + .ack_exp = 0, + .ack_val = 0 }; + i2c_hal_write_cmd_reg(&_i2c_hw[dev], cmd, _i2c_bus[dev].cmd); /* increment the command counter */ _i2c_bus[dev].cmd++; } -static void _i2c_read_cmd (i2c_t dev, uint8_t* data, uint8_t len, bool last) +static void _i2c_read_cmd(i2c_t dev, uint8_t len, bool last) { - DEBUG ("%s dev=%u data=%p len=%d\n", __func__, dev, data, len); + DEBUG ("%s dev=%u len=%d\n", __func__, dev, len); - if (len < 1 || len > I2C_MAX_DATA) { + if (len < 1 || len > SOC_I2C_FIFO_LEN) { /* at least one byte has to be read */ LOG_TAG_ERROR("i2c", "At least one byte has to be read\n"); return; @@ -654,262 +530,124 @@ static void _i2c_read_cmd (i2c_t dev, uint8_t* data, uint8_t len, bool last) if (len > 1) { /* place READ command for len-1 bytes with positive ack in command queue*/ - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].val = 0; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].byte_num = len-1; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].ack_en = 0; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].ack_exp = 0; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].ack_val = 0; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].op_code = I2C_CMD_READ; + i2c_hw_cmd_t cmd = { .op_code = I2C_LL_CMD_READ, + .byte_num = len-1, + .ack_en = 0, + .ack_exp = 0, + .ack_val = 0 }; + i2c_hal_write_cmd_reg(&_i2c_hw[dev], cmd, _i2c_bus[dev].cmd); /* increment the command counter */ _i2c_bus[dev].cmd++; } /* place READ command for last byte with negative ack in last segment in command queue*/ - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].val = 0; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].byte_num = 1; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].ack_en = 0; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].ack_exp = 0; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].ack_val = last ? 1 : 0; - _i2c_hw[dev].regs->command[_i2c_bus[dev].cmd].op_code = I2C_CMD_READ; + i2c_hw_cmd_t cmd = { .op_code = I2C_LL_CMD_READ, + .byte_num = 1, + .ack_en = 0, + .ack_exp = 0, + .ack_val = last ? 1 : 0 }; + i2c_hal_write_cmd_reg(&_i2c_hw[dev], cmd, _i2c_bus[dev].cmd); /* increment the command counter */ _i2c_bus[dev].cmd++; } -static inline void _i2c_delay (uint32_t cycles) -{ - /* produces a delay of 0,0625 us per cycle for -O2 compile option */ - /* 1 us = ca. 16 cycles (80 MHz) / 1 us = 32 cycles (160 MHz) */ - - if (cycles) { - __asm__ volatile ("1: _addi.n %0, %0, -1 \n" - " bnez %0, 1b \n" : "=r" (cycles) : "0" (cycles)); - } -} - -/* transfer related interrupts handled by the driver */ -static const uint32_t transfer_int_mask = I2C_TRANS_COMPLETE_INT_ENA - | I2C_END_DETECT_INT_ENA - | I2C_ACK_ERR_INT_ENA - | I2C_ARBITRATION_LOST_INT_ENA - | I2C_TIME_OUT_INT_ENA; - -/* at I2C_SPEED_NORMAL a transfer takes at most 33 byte * 9 clock cycles * 1/100000 s */ -#define I2C_TRANSFER_TIMEOUT_MS 3 +/* a maximum transfer 33 byte * 9 clock cycles * 1/100000 s takes at + * I2C_SPEED_NORMAL about 450 us, at I2C_SPEED_NORMAL_LOW about 4.5 ms */ +#define I2C_TRANSFER_TIMEOUT 640 -#define I2C_THREAD_FLAG BIT (0) +/* combination of all transfer interrupts */ +#define I2C_LL_MASTER_INT (I2C_LL_MASTER_TX_INT | I2C_LL_MASTER_RX_INT) -#include "ztimer.h" - -void _i2c_transfer_timeout (void *arg) +void _i2c_transfer_timeout(void *arg) { i2c_t dev = (i2c_t)(uintptr_t)arg; - /* reset the hardware if it I2C got stuck */ - _i2c_reset_hw(dev); + /* reset the hardware if I2C got stuck */ + i2c_hw_fsm_reset(dev); /* set result to timeout */ - _i2c_bus[dev].results |= I2C_TIME_OUT_INT_ST; + _i2c_bus[dev].status = I2C_TIME_OUT_INT_ENA_M; /* wake up the thread that is waiting for the results */ - thread_flags_set((thread_t*)thread_get(_i2c_bus[dev].pid), I2C_THREAD_FLAG); + mutex_unlock(&_i2c_bus[dev].cmd_lock); } /* Transfer of commands in I2C controller command pipeline */ -static void _i2c_transfer (i2c_t dev) +static void _i2c_transfer(i2c_t dev) { DEBUG("%s cmd=%d\n", __func__, _i2c_bus[dev].cmd); - #if FIFO_USED - /* reset RX FIFO queue */ - _i2c_hw[dev].regs->fifo_conf.rx_fifo_rst = 1; - /* cppcheck-suppress redundantAssignment - * Likely due to cppcheck not being able to located all headers, it misses - * the volatile qualifier. The assignments are to trigger a reset, but - * look like dead writes to tools unaware of volatile */ - _i2c_hw[dev].regs->fifo_conf.rx_fifo_rst = 0; - #endif - /* disable and enable all transmission interrupts and clear current status */ - _i2c_hw[dev].regs->int_ena.val &= ~transfer_int_mask; - _i2c_hw[dev].regs->int_ena.val |= transfer_int_mask; - _i2c_hw[dev].regs->int_clr.val = transfer_int_mask; + i2c_hal_clr_intsts_mask(&_i2c_hw[dev], I2C_LL_MASTER_INT); + i2c_hal_enable_intr_mask(&_i2c_hw[dev], I2C_LL_MASTER_INT); /* set a timer for the case the I2C hardware gets stuck */ - ztimer_t i2c_timeout = {}; - i2c_timeout.callback = _i2c_transfer_timeout; - i2c_timeout.arg = (void*)(uintptr_t)dev; - ztimer_set(ZTIMER_MSEC, &i2c_timeout, I2C_TRANSFER_TIMEOUT_MS); +#if defined(MODULE_ZTIMER_MSEC) + uint32_t timeout = ((I2C_TRANSFER_TIMEOUT * KHZ(1)) / _i2c_bus[dev].clk_freq) + 1; + ztimer_t timer = { .callback = _i2c_transfer_timeout, + .arg = (void*)(uintptr_t)dev }; + ztimer_set(ZTIMER_MSEC, &timer, timeout); +#endif + + /* start the execution of commands in command pipeline */ + _i2c_bus[dev].status = 0; - /* start execution of commands in command pipeline registers */ - _i2c_bus[dev].pid = thread_getpid(); - _i2c_bus[dev].results = 0; - _i2c_hw[dev].regs->ctr.trans_start = 0; - _i2c_hw[dev].regs->ctr.trans_start = 1; + i2c_hal_update_config(&_i2c_hw[dev]); + i2c_hal_trans_start(&_i2c_hw[dev]); /* wait for transfer results and remove timeout timer*/ - thread_flags_wait_one(I2C_THREAD_FLAG); - ztimer_remove(ZTIMER_MSEC, &i2c_timeout); + mutex_lock(&_i2c_bus[dev].cmd_lock); - /* returned from transmission */ - DEBUG("%s results=%08x\n", __func__, _i2c_bus[dev].results); + critical_enter(); +#if defined(MODULE_ZTIMER_MSEC) + ztimer_remove(ZTIMER_MSEC, &timer); +#endif + critical_exit(); - #if FIFO_USED - /* reset TX FIFO queue */ - _i2c_hw[dev].regs->fifo_conf.tx_fifo_rst = 1; - /* cppcheck-suppress redundantAssignment - * Likely due to cppcheck not being able to located all headers, it misses - * the volatile qualifier. The assignments are to trigger a reset, but - * look like dead writes to tools unaware of volatile */ - _i2c_hw[dev].regs->fifo_conf.tx_fifo_rst = 0; - #endif + /* returned from transmission */ + DEBUG("%s status=%08"PRIx32"\n", __func__, _i2c_bus[dev].status); /* reset command and data index */ _i2c_bus[dev].cmd = 0; - _i2c_bus[dev].data = 0; } -static void IRAM_ATTR _i2c_intr_handler (void *arg) +static void IRAM_ATTR _i2c_intr_handler(void *arg) { /* to satisfy the compiler */ (void)arg; - irq_isr_enter (); + irq_isr_enter(); /* all I2C peripheral interrupt sources are routed to the same interrupt, so we have to use the status register to distinguish interruptees */ for (unsigned dev = 0; dev < I2C_NUMOF; dev++) { + uint32_t mask = i2c_ll_get_intsts_mask(_i2c_hw[dev].dev); /* test for transfer related interrupts */ - if (_i2c_hw[dev].regs->int_status.val & transfer_int_mask) { - /* set transfer result */ - _i2c_bus[dev].results |= _i2c_hw[dev].regs->int_status.val; - /* disable all interrupts and clear them and left them disabled */ - _i2c_hw[dev].regs->int_ena.val &= ~transfer_int_mask; - _i2c_hw[dev].regs->int_clr.val = transfer_int_mask; + if (mask) { + _i2c_bus[dev].status = mask; + /* disable all interrupts and clear pending interrupts */ + i2c_hal_clr_intsts_mask(&_i2c_hw[dev], I2C_LL_MASTER_INT); + i2c_hal_disable_intr_mask(&_i2c_hw[dev], I2C_LL_MASTER_INT); + /* wake up the thread that is waiting for the results */ - thread_flags_set((thread_t*)thread_get(_i2c_bus[dev].pid), I2C_THREAD_FLAG); - } - else if (_i2c_hw[dev].regs->int_status.val) { - /* if there are any other interrupts, clear them */ - _i2c_hw[dev].regs->int_clr.val = ~0x0U; + mutex_unlock(&_i2c_bus[dev].cmd_lock); } } - irq_isr_exit (); -} - -#if 1 /* TODO */ -/* Some slave devices will die by accident and keep the SDA in low level, - * in this case, master should send several clock to make the slave release - * the bus. - */ -static void _i2c_clear_bus(i2c_t dev) -{ - /* reset the usage type in GPIO table */ - gpio_set_pin_usage(i2c_config[dev].scl, _GPIO); - gpio_set_pin_usage(i2c_config[dev].sda, _GPIO); - - /* configure SDA and SCL pin as GPIO in open-drain mode temporarily */ - gpio_init (i2c_config[dev].scl, GPIO_IN_OD_PU); - gpio_init (i2c_config[dev].sda, GPIO_IN_OD_PU); - - /* master send some clock pulses to make the slave release the bus */ - gpio_set (i2c_config[dev].scl); - gpio_set (i2c_config[dev].sda); - gpio_clear (i2c_config[dev].sda); - for (int i = 0; i < 20; i++) { - gpio_toggle(i2c_config[dev].scl); - } - gpio_set(i2c_config[dev].sda); - - /* store the usage type in GPIO table */ - gpio_set_pin_usage(i2c_config[dev].scl, _I2C); - gpio_set_pin_usage(i2c_config[dev].sda, _I2C); - - /* connect SCL and SDA pins to output signals through the GPIO matrix */ - GPIO.func_out_sel_cfg[i2c_config[dev].scl].func_sel = _i2c_hw[dev].signal_scl_out; - GPIO.func_out_sel_cfg[i2c_config[dev].sda].func_sel = _i2c_hw[dev].signal_sda_out; - - /* connect SCL and SDA input signals to pins through the GPIO matrix */ - GPIO.func_in_sel_cfg[_i2c_hw[dev].signal_scl_in].sig_in_sel = 1; - GPIO.func_in_sel_cfg[_i2c_hw[dev].signal_scl_in].sig_in_inv = 0; - GPIO.func_in_sel_cfg[_i2c_hw[dev].signal_scl_in].func_sel = i2c_config[dev].scl; - GPIO.func_in_sel_cfg[_i2c_hw[dev].signal_sda_in].sig_in_sel = 1; - GPIO.func_in_sel_cfg[_i2c_hw[dev].signal_sda_in].sig_in_inv = 0; - GPIO.func_in_sel_cfg[_i2c_hw[dev].signal_sda_in].func_sel = i2c_config[dev].sda; - - return; -} -#endif - -/* - * PLEASE NOTE: Following function is from the ESP-IDF and is licensed - * under the Apache License, Version 2.0 (the "License"). - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD - */ -static void _i2c_reset_hw (i2c_t dev) -{ - /* save current configuration */ - uint32_t ctr = _i2c_hw[dev].regs->ctr.val; - uint32_t fifo_conf = _i2c_hw[dev].regs->fifo_conf.val; - uint32_t scl_low_period = _i2c_hw[dev].regs->scl_low_period.val; - uint32_t scl_high_period = _i2c_hw[dev].regs->scl_high_period.val; - uint32_t scl_start_hold = _i2c_hw[dev].regs->scl_start_hold.val; - uint32_t scl_rstart_setup = _i2c_hw[dev].regs->scl_rstart_setup.val; - uint32_t scl_stop_hold = _i2c_hw[dev].regs->scl_stop_hold.val; - uint32_t scl_stop_setup = _i2c_hw[dev].regs->scl_stop_setup.val; - uint32_t sda_hold = _i2c_hw[dev].regs->sda_hold.val; - uint32_t sda_sample = _i2c_hw[dev].regs->sda_sample.val; - uint32_t timeout = _i2c_hw[dev].regs->timeout.val; - uint32_t scl_filter_cfg = _i2c_hw[dev].regs->scl_filter_cfg.val; - uint32_t sda_filter_cfg = _i2c_hw[dev].regs->sda_filter_cfg.val; - - /* reset hardware mpdule */ - periph_module_disable(_i2c_hw[dev].mod); - _i2c_clear_bus(dev); - periph_module_enable(_i2c_hw[dev].mod); - - /* restore configuration */ - _i2c_hw[dev].regs->int_ena.val = 0; - _i2c_hw[dev].regs->ctr.val = ctr & (~I2C_TRANS_START_M); - _i2c_hw[dev].regs->fifo_conf.val = fifo_conf; - _i2c_hw[dev].regs->scl_low_period.val = scl_low_period; - _i2c_hw[dev].regs->scl_high_period.val = scl_high_period; - _i2c_hw[dev].regs->scl_start_hold.val = scl_start_hold; - _i2c_hw[dev].regs->scl_rstart_setup.val = scl_rstart_setup; - _i2c_hw[dev].regs->scl_stop_hold.val = scl_stop_hold; - _i2c_hw[dev].regs->scl_stop_setup.val = scl_stop_setup; - _i2c_hw[dev].regs->sda_hold.val = sda_hold; - _i2c_hw[dev].regs->sda_sample.val = sda_sample; - _i2c_hw[dev].regs->timeout.val = timeout; - _i2c_hw[dev].regs->scl_filter_cfg.val = scl_filter_cfg; - _i2c_hw[dev].regs->sda_filter_cfg.val = sda_filter_cfg; - - /* disable and clear all interrupt sources */ - _i2c_hw[dev].regs->int_ena.val = 0; - _i2c_hw[dev].regs->int_clr.val = ~0x0U; - - return; + irq_isr_exit(); } void i2c_print_config(void) { - for (unsigned dev = 0; dev < I2C_NUMOF; dev++) { - printf("\tI2C_DEV(%u)\tscl=%d sda=%d\n", - dev, i2c_config[dev].scl, i2c_config[dev].sda); + if (I2C_NUMOF) { + for (unsigned dev = 0; dev < I2C_NUMOF; dev++) { + printf("\tI2C_DEV(%u)\tscl=%d sda=%d\n", + dev, i2c_config[dev].scl, i2c_config[dev].sda); + } + } + else { + LOG_TAG_INFO("i2c", "no I2C devices\n"); } } - -#else /* defined(I2C0_SPEED) || defined(I2C1_SPEED) */ - -void i2c_print_config(void) -{ - LOG_TAG_INFO("i2c", "no I2C devices\n"); -} - -#endif /* defined(I2C0_SPEED) || defined(I2C1_SPEED) */ - -#endif /* MODULE_ESP_I2C_HW */ diff --git a/pkg/esp32_sdk/patches/0015-driver-i2c-remove-the-include-gpio.h-in-i2c.h-header.patch b/pkg/esp32_sdk/patches/0015-driver-i2c-remove-the-include-gpio.h-in-i2c.h-header.patch new file mode 100644 index 000000000000..53355e611207 --- /dev/null +++ b/pkg/esp32_sdk/patches/0015-driver-i2c-remove-the-include-gpio.h-in-i2c.h-header.patch @@ -0,0 +1,38 @@ +From 25509b8b61b329d3c4ae5b3874704dae55d62ccd Mon Sep 17 00:00:00 2001 +From: Gunar Schorcht +Date: Tue, 8 Mar 2022 11:34:13 +0100 +Subject: [PATCH 15/17] driver/i2c: remove the include gpio.h in i2c.h header + +Including driver/i2c.h by RIOT code leads to type conflicts with RIOT gpio_t type. +--- + components/driver/i2c.c | 1 + + components/driver/include/driver/i2c.h | 1 - + 2 files changed, 1 insertion(+), 1 deletion(-) + +diff --git a/components/driver/i2c.c b/components/driver/i2c.c +index 438d1efc12d..be26fdeffc3 100644 +--- a/components/driver/i2c.c ++++ b/components/driver/i2c.c +@@ -21,6 +21,7 @@ + #include "hal/i2c_hal.h" + #include "hal/gpio_hal.h" + #include "soc/i2c_periph.h" ++#include "driver/gpio.h" + #include "driver/i2c.h" + #include "driver/periph_ctrl.h" + #include "esp_rom_gpio.h" +diff --git a/components/driver/include/driver/i2c.h b/components/driver/include/driver/i2c.h +index 22dcc8ab241..e668bba2acd 100644 +--- a/components/driver/include/driver/i2c.h ++++ b/components/driver/include/driver/i2c.h +@@ -19,7 +19,6 @@ extern "C" { + #include "freertos/task.h" + #include "freertos/queue.h" + #include "freertos/ringbuf.h" +-#include "driver/gpio.h" + #include "soc/soc_caps.h" + #include "hal/i2c_types.h" + +-- +2.17.1 + diff --git a/pkg/esp32_sdk/patches/0016-driver-i2c.h-expose-i2c_hw_fsm_reset-to-RIOT-code.patch b/pkg/esp32_sdk/patches/0016-driver-i2c.h-expose-i2c_hw_fsm_reset-to-RIOT-code.patch new file mode 100644 index 000000000000..bd10337ca004 --- /dev/null +++ b/pkg/esp32_sdk/patches/0016-driver-i2c.h-expose-i2c_hw_fsm_reset-to-RIOT-code.patch @@ -0,0 +1,34 @@ +From cd8688a55e62094cb6605ee8594985f862d57a95 Mon Sep 17 00:00:00 2001 +From: Gunar Schorcht +Date: Tue, 8 Mar 2022 11:35:11 +0100 +Subject: [PATCH 16/17] driver/i2c.h: expose i2c_hw_fsm_reset to RIOT code + +--- + components/driver/i2c.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/components/driver/i2c.c b/components/driver/i2c.c +index be26fdeffc3..cff410b9d1b 100644 +--- a/components/driver/i2c.c ++++ b/components/driver/i2c.c +@@ -209,7 +209,7 @@ static i2c_clk_alloc_t i2c_clk_alloc[I2C_SCLK_MAX] = { + static i2c_obj_t *p_i2c_obj[I2C_NUM_MAX] = {0}; + static void i2c_isr_handler_default(void *arg); + static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num); +-static esp_err_t IRAM_ATTR i2c_hw_fsm_reset(i2c_port_t i2c_num); ++esp_err_t IRAM_ATTR i2c_hw_fsm_reset(i2c_port_t i2c_num); + + static void i2c_hw_disable(i2c_port_t i2c_num) + { +@@ -595,7 +595,7 @@ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num) + * If we remove the power supply for the slave during I2C is reading, or directly connect SDA or SCL to ground, + * this would cause the I2C FSM get stuck in wrong state, all we can do is to reset the I2C hardware in this case. + **/ +-static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num) ++esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num) + { + #if !SOC_I2C_SUPPORT_HW_FSM_RST + int scl_low_period, scl_high_period; +-- +2.17.1 + From 794cc207fad709baf94e4e8f0004807dd42ebf1b Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 10 Mar 2022 04:56:43 +0100 Subject: [PATCH 24/46] cpu/esp32: port periph/pwm to ESP-IDF ledc HAL --- .../common/esp32/include/periph_conf_common.h | 85 ++- cpu/esp32/include/periph_cpu.h | 87 ++- cpu/esp32/periph/pwm.c | 591 ++++++++---------- 3 files changed, 401 insertions(+), 362 deletions(-) diff --git a/boards/common/esp32/include/periph_conf_common.h b/boards/common/esp32/include/periph_conf_common.h index c50f386b5036..20d412c9e415 100644 --- a/boards/common/esp32/include/periph_conf_common.h +++ b/boards/common/esp32/include/periph_conf_common.h @@ -162,33 +162,92 @@ static const i2c_conf_t i2c_config[] = { */ /** - * @brief Static array of GPIOs that can be used as channels of PWM0 + * @brief GPIOs used as channels for the according PWM device */ #ifdef PWM0_GPIOS -static const gpio_t pwm0_channels[] = PWM0_GPIOS; +static const gpio_t pwm0_gpios[] = PWM0_GPIOS; #endif + /** - * @brief Static array of GPIOs that can be used as channels of PWM0 + * @brief GPIOs used as channels for the according PWM device */ #ifdef PWM1_GPIOS -static const gpio_t pwm1_channels[] = PWM1_GPIOS; +static const gpio_t pwm1_gpios[] = PWM1_GPIOS; +#endif + +/** + * @brief GPIOs used as channels for the according PWM device + */ +#ifdef PWM2_GPIOS +static const gpio_t pwm2_gpios[] = PWM2_GPIOS; +#endif + +/** + * @brief GPIOs used as channels for the according PWM device + */ +#ifdef PWM3_GPIOS +static const gpio_t pwm3_gpios[] = PWM3_GPIOS; #endif +/** + * @brief PWM device configuration based on defined PWM channel GPIOs + */ +static const pwm_config_t pwm_config[] = +{ +#ifdef PWM0_GPIOS + { + .module = PERIPH_LEDC_MODULE, + .group = LEDC_LOW_SPEED_MODE, + .timer = LEDC_TIMER_0, + .ch_numof = ARRAY_SIZE(pwm0_gpios), + .gpios = pwm0_gpios, + }, +#endif +#ifdef PWM1_GPIOS + { + .module = PERIPH_LEDC_MODULE, +#ifdef SOC_LEDC_SUPPORT_HS_MODE + .group = LEDC_HIGH_SPEED_MODE, +#else + .group = LEDC_LOW_SPEED_MODE, +#endif + .timer = LEDC_TIMER_1, + .ch_numof = ARRAY_SIZE(pwm1_gpios), + .gpios = pwm1_gpios, + }, +#endif +#ifdef PWM2_GPIOS + { + .module = PERIPH_LEDC_MODULE, + .group = LEDC_LOW_SPEED_MODE, + .timer = LEDC_TIMER_2, + .ch_numof = ARRAY_SIZE(pwm2_gpios), + .gpios = pwm2_gpios, + }, +#endif +#ifdef PWM3_GPIOS + { + .module = PERIPH_LEDC_MODULE, +#ifdef SOC_LEDC_SUPPORT_HS_MODE + .group = LEDC_HIGH_SPEED_MODE, +#else + .group = LEDC_LOW_SPEED_MODE, +#endif + .timer = LEDC_TIMER_3, + .ch_numof = ARRAY_SIZE(pwm3_gpios), + .gpios = pwm3_gpios, + }, +#endif +}; + /** * @brief Number of PWM devices * - * The number of PWM devices is determined from the PWM0_GPIOS and PWM1_GPIOS - * definitions. + * The number of PWM devices is determined from the PWM device configuration. * * @note PWM_NUMOF definition must not be changed. */ -#if defined(PWM0_GPIOS) && defined(PWM1_GPIOS) -#define PWM_NUMOF (2) -#elif defined(PWM0_GPIOS) || defined(PWM1_GPIOS) -#define PWM_NUMOF (1) -#else -#define PWM_NUMOF (0) -#endif +#define PWM_NUMOF ARRAY_SIZE(pwm_config) /** @} */ diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index 92208108870a..1e700199f63d 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -21,6 +21,8 @@ #include #include "sdkconfig.h" +#include "hal/ledc_types.h" +#include "soc/ledc_struct.h" #include "soc/periph_defs.h" #include "soc/soc_caps.h" @@ -350,39 +352,86 @@ typedef struct { /** * @name PWM configuration * - * PWM implementation uses ESP32's high-speed MCPWM modules. ESP32 has 2 such - * modules, each with up to 6 channels (PWM_CHANNEL_NUM_DEV_MAX). Thus, the - * maximum number of PWM devices is 2 and the maximum total number of PWM - * channels is 12. + * The implementation of the PWM peripheral driver uses the LED PWM Controller + * (LEDC) module of the ESP32x SoC. This LEDC module has one or two channel + * groups with 6 or 8 channels each. The channels of each channel group can + * use one of 4 timers as clock source. Thus, it is possible to define at + * 4 or 8 virtual PWM devices in RIOT with different frequencies and + * resolutions. Regardless of whether the LEDC module of the ESP32x SoC has + * one or two channel groups, the PWM driver implementation allows to organize + * the available channels into up to 4 virtual PWM devices. + * + * The assignment of the available channels to the virtual PWM devices is + * done in the board-specific peripheral configuration by defining the + * macros `PWM0_GPIOS`, `PWM1_GPIOS`, `PWM2_GPIOS` and `PWM3_GPIOS` These + * macros specify the GPIOs that are used as channels for the available + * virtual PWM devices PWM_DEV(0) ... PWM_DEV(3) in RIOT. The mapping of + * these channels to the available channel groups and channel group timers + * is done by the driver automatically as follows. * - * PWM0_GPIOS and PWM1_GPIOS in the board-specific peripheral configuration - * each define a list of GPIOs that can be used with the respective PWM - * devices as PWM channels. The order of the listed GPIOs determines the - * association between the RIOT PWM channels and the GPIOs. + *
+ * Macro | 1 Channel Group | 2 Channel Groups | Timer + * -------------|-----------------------|------------------------|--------------- + * `PWM0_GPIOS` | `LEDC_LOW_SPEED_MODE` | `LEDC_LOW_SPEED_MODE` | `LEDC_TIMER_0` + * `PWM1_GPIOS` | `LEDC_LOW_SPEED_MODE` | `LEDC_HIGH_SPEED_MODE` | `LEDC_TIMER_1` + * `PWM2_GPIOS` | `LEDC_LOW_SPEED_MODE` | `LEDC_LOW_SPEED_MODE` | `LEDC_TIMER_2` + * `PWM3_GPIOS` | `LEDC_LOW_SPEED_MODE` | `LEDC_HIGH_SPEED_MODE` | `LEDC_TIMER_3` * - * @note The definition of PWM0_GPIOS and PWM1_GPIOS can be omitted or - * empty. In the latter case, they must at least contain the curly braces. - * The corresponding PWM device can not be used in this case. + *
+ * For example, if the LEDC module of the ESP32x SoC has two channel groups, + * two virtual PWM devices with 2 x 6/8 channels could be used by defining + * 'PWM0_GPIOS' and 'PWM1_GPIOS' with 6/8 GPIOs each. + * + * @note + * - The total number of channels defined for a channel group must not exceed + * #PWM_CH_NUMOF_MAX. + * - The definition of `PWM0_GPIOS`, `PWM1_GPIOS`, `PWM2_GPIOS` and + * `PWM3_GPIOS` can be omitted. In this case the existing macros should + * be defined in ascending order, as the first defined macro is assigned + * to PWM_DEV(0), the second defined macro is assigned to PWM_DEV(1) + * and so on. So the minimal configuration would define all channels by + * `PWM0_GPIOS` as PWM_DEV(0). + * - #PWM_NUMOF is determined automatically. + * - The order of the GPIOs in these macros determines the mapping between + * RIOT's PWM channels and the GPIOs. + * - As long as the GPIOs listed in `PWM0_GPIOS`, `PWM1_GPIOS`, + * `PWM2_GPIOS` and `PWM3_GPIOS` are not initialized as PWM channels with + * the #pwm_init function, they can be used for other purposes. * - * PWM_NUMOF is determined automatically from the PWM0_GPIOS and PWM1_GPIOS - * definitions. + * @{ + */ + +/** + * @brief PWM configuration structure type * - * @note As long as the GPIOs listed in PWM0_GPIOS and PMW1_GPIOS are not - * initialized as PWM channels with the *pwm_init* function, they can be used - * other purposes. + * The implementation of the PWM peripheral driver uses the LED PWM Controller + * (LEDC) module of the ESP32x SoC. The LEDC module has up to 2 channel groups + * with 6 or 8 channels each, which can use one of 4 timers. * - * @{ + * Based on these maximum 2 channel groups with 6 or 8 channels each and 4 + * timers, up to 4 PWM devices can be configured in RIOT. The configuration + * structure defines static parameters for each virtual PWM device, i.e. + * the channel group used, the timer used, the number of channels used and + * the GPIOs assigned to the channels. The number of channels used by a PWM + * device corresponds to the number of GPIOs assigned to this PWM device. */ +typedef struct { + uint8_t module; /**< LEDC module identifier */ + ledc_mode_t group; /**< LEDC channel group used (low/high speed) */ + ledc_timer_t timer; /**< LEDC timer used by this device */ + uint8_t ch_numof; /**< Number of channels used by this device */ + const gpio_t *gpios; /**< GPIOs used as channels of this device */ +} pwm_config_t; /** * @brief Maximum number of PWM devices */ -#define PWM_NUMOF_MAX (2) +#define PWM_NUMOF_MAX (4) /** * @brief Maximum number of channels per PWM device. */ -#define PWM_CHANNEL_NUM_DEV_MAX (6) +#define PWM_CH_NUMOF_MAX (SOC_LEDC_CHANNEL_NUM) /** @} */ diff --git a/cpu/esp32/periph/pwm.c b/cpu/esp32/periph/pwm.c index 4e4f6b9af188..966a0ea0dbd2 100644 --- a/cpu/esp32/periph/pwm.c +++ b/cpu/esp32/periph/pwm.c @@ -18,410 +18,352 @@ * @} */ -#define ENABLE_DEBUG 0 -#include "debug.h" - +#include "bitarithm.h" #include "board.h" #include "cpu.h" +#include "gpio_arch.h" +#include "kernel_defines.h" #include "log.h" #include "irq_arch.h" #include "periph/pwm.h" #include "periph/gpio.h" #include "esp_common.h" -#include "gpio_arch.h" +#include "esp_rom_gpio.h" +#include "hal/ledc_hal.h" +#include "soc/ledc_struct.h" +#include "soc/rtc.h" -#include "driver/periph_ctrl.h" -#include "soc/gpio_struct.h" -#include "soc/gpio_sig_map.h" -#include "soc/mcpwm_reg.h" -#include "soc/mcpwm_struct.h" - -#if defined(PWM0_GPIOS) || defined(PWM1_GPIOS) - -#define PWM_CLK (160000000UL) /* base clock of PWM devices */ -#define PWM_CPS_MAX (10000000UL) /* maximum cycles per second supported */ -#define PWM_CPS_MIN (2500UL) /* minimum cycles per second supported */ - -#define PWM_TIMER_MOD_FREEZE 0 /* timer is disabled */ -#define PWM_TIMER_MOD_UP 1 /* timer counts up */ -#define PWM_TIMER_MOD_DOWN 2 /* timer counts down */ -#define PWM_TIMER_MOD_UP_DOWN 3 /* timer counts up and then down */ - -#define PWM_TIMER_STOPS_AT_TEZ 0 /* PWM starts, then stops at next TEZ */ -#define PWM_TIMER_STOPS_AT_TEP 1 /* PWM starts, then stops at next TEP */ -#define PWM_TIMER_RUNS_ON 2 /* PWM runs on */ -#define PWM_TIMER_STARTS_STOPS_AT_TEZ 3 /* PWM starts and stops at next TEZ */ -#define PWM_TIMER_STARTS_STOPS_AT_TEP 4 /* PWM starts and stops at next TEP */ - -#define PWM_TIMER_UPDATE_IMMIDIATE 0 /* update period immediately */ -#define PWM_TIMER_UPDATE_AT_TEZ 1 /* update period at TEZ */ -#define PWM_TIMER_UPDATE_AT_SYNC 2 /* update period at sync */ -#define PWM_TIMER_UPDATE_AT_TEZ_SYNC 3 /* update period at TEZ and sync */ - -#define PWM_OP_ACTION_NO_CHANGE 0 /* do not change output */ -#define PWM_OP_ACTION_LOW 1 /* set the output to high */ -#define PWM_OP_ACTION_HIGH 2 /* set the output to low */ -#define PWM_OP_ACTION_TOGGLE 3 /* toggle the output */ - -#define PWM_OP_CHANNEL_A 0 /* operator channel A */ -#define PWM_OP_CHANNEL_B 0 /* operator channel B */ - -/* forward declaration of internal functions */ -static void _pwm_start(pwm_t pwm); -static void _pwm_stop(pwm_t pwm); -static bool _pwm_configuration(void); - -/* data structure for static configuration of PWM devices */ -struct _pwm_hw_t { - mcpwm_dev_t* regs; /* PWM's registers set address */ - uint8_t mod; /* PWM's hardware module */ - uint8_t int_src; /* PWM's peripheral interrupt source */ - uint32_t signal_group; /* PWM's base peripheral signal index */ - uint8_t gpio_num; /* number of GPIOs used as channels outputs */ - const gpio_t* gpios; /* GPIOs used as channel outputs */ -}; - -#ifdef PWM0_GPIOS -static const gpio_t _pwm_channel_gpios_0[] = PWM0_GPIOS; -#endif +#include "esp_idf_api/periph_ctrl.h" -#ifdef PWM1_GPIOS -static const gpio_t _pwm_channel_gpios_1[] = PWM1_GPIOS; -#endif +#define ENABLE_DEBUG 0 +#include "debug.h" -/* static configuration of PWM devices */ -static const struct _pwm_hw_t _pwm_hw[] = -{ -#ifdef PWM0_GPIOS - { - .regs = &MCPWM0, - .mod = PERIPH_PWM0_MODULE, - .int_src = ETS_PWM0_INTR_SOURCE, - .signal_group = PWM0_OUT0A_IDX, - .gpio_num = ARRAY_SIZE(_pwm_channel_gpios_0), - .gpios = _pwm_channel_gpios_0, - }, -#endif -#ifdef PWM1_GPIOS - { - .regs = &MCPWM1, - .mod = PERIPH_PWM1_MODULE, - .int_src = ETS_PWM1_INTR_SOURCE, - .signal_group = PWM1_OUT0A_IDX, - .gpio_num = ARRAY_SIZE(_pwm_channel_gpios_1), - .gpios = _pwm_channel_gpios_1, - }, -#endif -}; +#if defined(PWM0_GPIOS) || defined(PWM1_GPIOS) || defined(PWM2_GPIOS) || defined(PWM3_GPIOS) -/* data structure dynamic channel configuration */ -typedef struct { - bool used; - uint32_t duty; -} _pwm_chn_t; +#define SOC_LEDC_CLK_DIV_BIT_NUM 18 +#define SOC_LEDC_CLK_DIV_INT_BIT_NUM 10 /* integral part of CLK divider */ +#define SOC_LEDC_CLK_DIV_FRAC_BIT_NUM 8 /* fractional part of CLK divider */ + +#define PWM_HW_RES_MAX ((uint32_t)1 << SOC_LEDC_TIMER_BIT_WIDE_NUM) +#define PWM_HW_RES_MIN ((uint32_t)1 << 1) -/* data structure for dynamic configuration of PWM devices */ -struct _pwm_dev_t { - uint16_t res; - uint32_t freq; - pwm_mode_t mode; - uint8_t chn_num; - _pwm_chn_t chn[PWM_CHANNEL_NUM_DEV_MAX]; -}; +#define _DEV _pwm_dev[pwm] /* shortcut for PWM device descriptor */ +#define _CFG pwm_config[pwm] /* shortcut for PWM device configuration */ -/* dynamic configuration of PWM devices */ -static struct _pwm_dev_t _pwm_dev[PWM_NUMOF_MAX] = {}; +/* data structure for dynamic channel parameters */ +typedef struct { + bool used; /* true if the channel is set by pwm_set */ + uint8_t ch; /* actual channel index within used channel group */ + uint32_t duty; /* actual duty value */ + uint32_t hpoint; /* actual hpoing value */ +} _pwm_ch_t; -/* if pwm_init is called first time, it checks the overall pwm configuration */ -static bool _pwm_init_first_time = true; +/* data structure for device handling at runtime */ +typedef struct { + uint32_t freq; /* specified frequency parameter */ + uint32_t res; /* specified resolution parameter */ + pwm_mode_t mode; /* specified mode */ + uint32_t hw_freq; /* used hardware frequency */ + uint32_t hw_res; /* used hardware resolution */ + ledc_timer_bit_t hw_res_bit; /* used hardware resolution in bit */ + uint32_t hw_clk_div; /* used hardware clock divider */ + ledc_hal_context_t hw; /* used hardware device context */ + bool enabled; /* true if the device is used (powered on) */ + _pwm_ch_t ch[PWM_CH_NUMOF_MAX]; /* dynamic channel parameters at runtime */ +} _pwm_dev_t; + +static _pwm_dev_t _pwm_dev[PWM_NUMOF] = { }; + +/* if pwm_init is called first time, it checks the pwm configuration */ +static bool _pwm_initialized = false; + +/* static configuration checks and initialization on first pwm_init */ +static bool _pwm_initialize(void); /* Initialize PWM device */ uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res) { - DEBUG ("%s pwm=%u mode=%u freq=%u, res=%u\n", __func__, pwm, mode, freq, res); - - CHECK_PARAM_RET (pwm < PWM_NUMOF, 0); - CHECK_PARAM_RET (freq > 0, 0); + _Static_assert(PWM_NUMOF <= PWM_NUMOF_MAX, "Too many PWM devices defined"); - if (_pwm_init_first_time) { - if (!_pwm_configuration()) + if (!_pwm_initialized) { + if (!_pwm_initialize()) { return 0; + } + _pwm_initialized = true; + } + + assert(pwm < PWM_NUMOF); + assert(freq > 0); + + _DEV.enabled = true; + _DEV.res = res; + _DEV.freq = freq; + _DEV.mode = mode; + + if ((res < PWM_HW_RES_MIN) || (_DEV.res > PWM_HW_RES_MAX)) { + LOG_TAG_ERROR("pwm", "Resolution of PWM device %u to be in " + "range [%"PRIu32", %"PRIu32"]\n", + pwm, PWM_HW_RES_MIN, PWM_HW_RES_MAX); + return 0; } - if (_pwm_hw[pwm].gpio_num == 0) { - LOG_TAG_ERROR("pwm", "PWM device %d has no assigned pins\n", pwm); + /* + * The hardware resolution must be a power of two, so we determine the + * next power of two, which covers the desired resolution + */ + ledc_timer_bit_t hw_res_bit = bitarithm_msb(res - 1); + if (hw_res_bit < SOC_LEDC_TIMER_BIT_WIDE_NUM) { + hw_res_bit++; + } + + uint32_t hw_res = 1 << hw_res_bit; + + uint32_t hw_ticks_max = rtc_clk_apb_freq_get(); + uint32_t hw_ticks_min = hw_ticks_max / (1 << SOC_LEDC_CLK_DIV_INT_BIT_NUM); + uint32_t hw_freq_min = hw_ticks_min / (1 << SOC_LEDC_TIMER_BIT_WIDE_NUM) + 1; + + if (freq < hw_freq_min) { + LOG_TAG_ERROR("pwm", "Frequency of %"PRIu32" Hz is too less, minimum " + "frequency is %"PRIu32" Hz\n", freq, hw_freq_min); return 0; } - /* reset by disabling and enable the PWM module */ - periph_module_disable(_pwm_hw[pwm].mod); - periph_module_enable(_pwm_hw[pwm].mod); + /* number of hardware ticks required, at maximum it can be APB clock */ + uint32_t hw_ticks = MIN(freq * hw_res, rtc_clk_apb_freq_get()); + + /* + * if the number of required ticks is less than minimum ticks supported by + * the hardware supports, we have to increase the resolution. + */ + while (hw_ticks < hw_ticks_min) { + hw_res_bit++; + hw_res = 1 << hw_res_bit; + hw_ticks = freq * hw_res; + } + + /* LEDC_CLK_DIV is given in Q10.8 format */ + uint32_t hw_clk_div = + ((uint64_t)rtc_clk_apb_freq_get() << SOC_LEDC_CLK_DIV_FRAC_BIT_NUM) / hw_ticks; - _pwm_dev[pwm].res = res; - _pwm_dev[pwm].freq = freq; - _pwm_dev[pwm].mode = mode; - _pwm_dev[pwm].chn_num = _pwm_hw[pwm].gpio_num; + _DEV.freq = freq; + _DEV.res = res; + _DEV.hw_freq = hw_ticks / hw_res; + _DEV.hw_res = hw_res; + _DEV.hw_res_bit = hw_res_bit; + _DEV.hw_clk_div = hw_clk_div; - for (int i = 0; i < _pwm_dev[pwm].chn_num; i++) { + DEBUG("%s hw_freq=%"PRIu32" hw_res=%"PRIu32" hw_ticks=%"PRIu32 + " hw_clk_div=%"PRIu32"\n", __func__, + _DEV.hw_freq, _DEV.hw_res, hw_ticks, _DEV.hw_clk_div); + + for (int i = 0; i < _CFG.ch_numof; i++) { /* initialize channel data */ - _pwm_dev[pwm].chn[i].used = false; - _pwm_dev[pwm].chn[i].duty = 0; + _DEV.ch[i].used = false; + _DEV.ch[i].duty = 0; /* reset GPIO usage type if the pins were used already for PWM before to make it possible to reinitialize PWM with new parameters */ - if (gpio_get_pin_usage(_pwm_hw[pwm].gpios[i]) == _PWM) { - gpio_set_pin_usage(_pwm_hw[pwm].gpios[i], _GPIO); + if (gpio_get_pin_usage(_CFG.gpios[i]) == _PWM) { + gpio_set_pin_usage(_CFG.gpios[i], _GPIO); } - if (gpio_get_pin_usage(_pwm_hw[pwm].gpios[i]) != _GPIO) { - LOG_TAG_ERROR("pwm", "GPIO%d is used for %s and cannot be used as PWM output\n", i, - gpio_get_pin_usage_str(_pwm_hw[pwm].gpios[i])); + if (gpio_get_pin_usage(_CFG.gpios[i]) != _GPIO) { + LOG_TAG_ERROR("pwm", "GPIO%d is used for %s and cannot be used as " + "PWM output\n", + i, gpio_get_pin_usage_str(_CFG.gpios[i])); return 0; } - if (gpio_init(_pwm_hw[pwm].gpios[i], GPIO_OUT) < 0) { + /* initialize the GPIOs and route the PWM signal output to the GPIO */ + if (gpio_init(_CFG.gpios[i], GPIO_OUT) < 0) { return 0; } - /* initialize the GPIO and route the PWM signal output to the GPIO */ - gpio_set_pin_usage(_pwm_hw[pwm].gpios[i], _GPIO); - gpio_clear (_pwm_hw[pwm].gpios[i]); - GPIO.func_out_sel_cfg[_pwm_hw[pwm].gpios[i]].func_sel = _pwm_hw[pwm].signal_group + i; + gpio_set_pin_usage(_CFG.gpios[i], _PWM); + gpio_clear(_CFG.gpios[i]); + + esp_rom_gpio_connect_out_signal( + _CFG.gpios[i], + ledc_periph_signal[_CFG.group].sig_out0_idx + _DEV.ch[i].ch, 0, 0); + } - /* start the PWM device */ - _pwm_start(pwm); + pwm_poweron(pwm); - return freq; + return _DEV.hw_freq; } uint8_t pwm_channels(pwm_t pwm) { - CHECK_PARAM_RET (pwm < PWM_NUMOF, 0); - - return _pwm_hw[pwm].gpio_num; + assert(pwm < PWM_NUMOF); + return _CFG.ch_numof; } void pwm_set(pwm_t pwm, uint8_t channel, uint16_t value) { DEBUG("%s pwm=%u channel=%u value=%u\n", __func__, pwm, channel, value); - CHECK_PARAM (pwm < PWM_NUMOF); - CHECK_PARAM (channel < _pwm_dev[pwm].chn_num); - CHECK_PARAM (value <= _pwm_dev[pwm].res); - - uint32_t state = irq_disable(); + assert(pwm < PWM_NUMOF); + assert(channel < _CFG.ch_numof); - _pwm_dev[pwm].chn[channel].duty = value; - _pwm_dev[pwm].chn[channel].used = true; + value = MIN(value, _DEV.res); - /* determine used operator and operator output */ - uint8_t op_idx = channel >> 1; - uint8_t op_out = channel & 0x01; + _DEV.ch[channel].used = true; + _DEV.ch[channel].duty = value * _DEV.hw_res / _DEV.res; + _DEV.ch[channel].hpoint = 0; - /* compute and set shadow register (compare) )value of according channel */ - uint16_t cmp = 0; - switch (_pwm_dev[pwm].mode) { - case PWM_LEFT: cmp = value; - break; - case PWM_RIGHT: cmp = value - 1; - break; - case PWM_CENTER: cmp = _pwm_hw[pwm].regs->timer[0].timer_cfg0.timer_period - value; - break; - } - _pwm_hw[pwm].regs->operators[op_idx].timestamp[op_out].gen = cmp; - - /* set actions for timing events (reset all first) */ - _pwm_hw[pwm].regs->operators[op_idx].generator[op_out].val = 0; - - if (op_out == 0) - { - /* channel/output A is used -> set actions for channel A */ - switch (_pwm_dev[pwm].mode) - { - case PWM_LEFT: - _pwm_hw[pwm].regs->operators[op_idx].generator[op_out].gen_utez = PWM_OP_ACTION_HIGH; - _pwm_hw[pwm].regs->operators[op_idx].generator[op_out].gen_utea = PWM_OP_ACTION_LOW; - break; - - case PWM_RIGHT: - _pwm_hw[pwm].regs->operators[op_idx].generator[op_out].gen_dtea = PWM_OP_ACTION_HIGH; - _pwm_hw[pwm].regs->operators[op_idx].generator[op_out].gen_dtep = PWM_OP_ACTION_LOW; - break; - - case PWM_CENTER: - _pwm_hw[pwm].regs->operators[op_idx].generator[op_out].gen_utea = PWM_OP_ACTION_HIGH; - _pwm_hw[pwm].regs->operators[op_idx].generator[op_out].gen_dtea = PWM_OP_ACTION_LOW; - break; - } - } - else { - /* channel/output B is used -> set actions for channel B */ - switch (_pwm_dev[pwm].mode) - { - case PWM_LEFT: - _pwm_hw[pwm].regs->operators[op_idx].generator[op_out].gen_utez = PWM_OP_ACTION_HIGH; - _pwm_hw[pwm].regs->operators[op_idx].generator[op_out].gen_uteb = PWM_OP_ACTION_LOW; - break; - - case PWM_RIGHT: - _pwm_hw[pwm].regs->operators[op_idx].generator[op_out].gen_dteb = PWM_OP_ACTION_HIGH; - _pwm_hw[pwm].regs->operators[op_idx].generator[op_out].gen_dtep = PWM_OP_ACTION_LOW; - break; - - case PWM_CENTER: - _pwm_hw[pwm].regs->operators[op_idx].generator[op_out].gen_uteb = PWM_OP_ACTION_HIGH; - _pwm_hw[pwm].regs->operators[op_idx].generator[op_out].gen_dteb = PWM_OP_ACTION_LOW; - break; - } + switch (_DEV.mode) { + case PWM_LEFT: + _DEV.ch[channel].hpoint = 0; + break; + case PWM_RIGHT: + _DEV.ch[channel].hpoint = _DEV.hw_res - 1 - _DEV.ch[channel].duty; + break; + case PWM_CENTER: + _DEV.ch[channel].hpoint = (_DEV.hw_res - _DEV.ch[channel].duty) >> 1; + break; } - irq_restore(state); + DEBUG("%s pwm=%u duty=%"PRIu32" hpoint=%"PRIu32"\n", + __func__, pwm, _DEV.ch[channel].duty, _DEV.ch[channel].hpoint); + + unsigned ch = _DEV.ch[channel].ch; /* internal channel mapping */ + + critical_enter(); + ledc_hal_set_duty_int_part(&_DEV.hw, ch, _DEV.ch[channel].duty); + ledc_hal_set_hpoint(&_DEV.hw, ch, _DEV.ch[channel].hpoint); + ledc_hal_set_sig_out_en(&_DEV.hw, ch, true); + ledc_hal_ls_channel_update(&_DEV.hw, ch); + ledc_hal_set_duty_start(&_DEV.hw, ch, true); + critical_exit(); } void pwm_poweron(pwm_t pwm) { - CHECK_PARAM (pwm < PWM_NUMOF); - periph_module_enable(_pwm_hw[pwm].mod); - _pwm_start(pwm); + DEBUG("%s pwm=%u\n", __func__, pwm); + + /* enable and init the module and select the right clock source */ + esp_idf_periph_module_enable(_CFG.module); + ledc_hal_init(&_DEV.hw, _CFG.group); + ledc_hal_set_slow_clk_sel(&_DEV.hw, LEDC_SLOW_CLK_APB); + ledc_hal_set_clock_source(&_DEV.hw, _CFG.timer, LEDC_APB_CLK); + + /* update the timer according to determined parameters */ + ledc_hal_set_clock_divider(&_DEV.hw, _CFG.timer, _DEV.hw_clk_div); + ledc_hal_set_duty_resolution(&_DEV.hw, _CFG.timer, _DEV.hw_res_bit); + ledc_hal_ls_timer_update(&_DEV.hw, _CFG.timer); + ledc_hal_timer_rst(&_DEV.hw, _CFG.timer); + + critical_enter(); + for (unsigned i = 0; i < _CFG.ch_numof; i++) { + /* static configuration of the channel, no fading */ + ledc_hal_set_duty_direction(&_DEV.hw, _DEV.ch[i].ch, 1); + ledc_hal_set_duty_num(&_DEV.hw, _DEV.ch[i].ch, 1); + ledc_hal_set_duty_cycle(&_DEV.hw, _DEV.ch[i].ch, 1); + ledc_hal_set_duty_scale(&_DEV.hw, _DEV.ch[i].ch, 0); + ledc_hal_set_fade_end_intr(&_DEV.hw, _DEV.ch[i].ch, 0); + + /* bind the channel to the timer and disable the output for now */ + ledc_hal_bind_channel_timer(&_DEV.hw, _DEV.ch[i].ch, _CFG.timer); + + /* restore used parameters */ + ledc_hal_set_duty_int_part(&_DEV.hw, _DEV.ch[i].ch, _DEV.ch[i].duty); + ledc_hal_set_hpoint(&_DEV.hw, _DEV.ch[i].ch, _DEV.ch[i].hpoint); + ledc_hal_set_sig_out_en(&_DEV.hw, _DEV.ch[i].ch, _DEV.ch[i].used); + ledc_hal_ls_channel_update(&_DEV.hw, _DEV.ch[i].ch); + ledc_hal_set_duty_start(&_DEV.hw, _DEV.ch[i].ch, _DEV.ch[i].used); + } + _DEV.enabled = true; + critical_exit(); } void pwm_poweroff(pwm_t pwm) { - CHECK_PARAM (pwm < PWM_NUMOF); - _pwm_stop (pwm); - periph_module_disable(_pwm_hw[pwm].mod); -} - -static void _pwm_start(pwm_t pwm) -{ - pwm_mode_t mode = _pwm_dev[pwm].mode; - uint16_t res = _pwm_dev[pwm].res; - uint32_t freq = _pwm_dev[pwm].freq; - uint32_t period = 0; + DEBUG("%s pwm=%u\n", __func__, pwm); - /* set timer mode */ - switch (mode) { - case PWM_LEFT: - period = res; - _pwm_hw[pwm].regs->timer[0].timer_cfg1.timer_mod = PWM_TIMER_MOD_UP; - break; - case PWM_RIGHT: - period = res; - _pwm_hw[pwm].regs->timer[0].timer_cfg1.timer_mod = PWM_TIMER_MOD_DOWN; - break; - case PWM_CENTER: - period = res * 2; - _pwm_hw[pwm].regs->timer[0].timer_cfg1.timer_mod = PWM_TIMER_MOD_UP_DOWN; - break; + if (!_pwm_dev[pwm].enabled) { + return; } - uint32_t cps = period * freq; - /* maximum number of timer clock cycles per second (freq*period) must not - be greater than PWM_CPS_MAX, reduce the freq if necessary and keep - the resolution */ - if (cps > PWM_CPS_MAX) { - freq = PWM_CPS_MAX / period; - _pwm_dev[pwm].freq = freq; - DEBUG("%s freq*res was to high, freq was reduced to %d Hz\n", - __func__, freq); - } - /* minimum number of timer clock cycles per second (freq*period) must not - be less than PWM_CPS_MIN, increase the freq if necessary and keep - the resolution */ - else if (cps < PWM_CPS_MIN) { - freq = PWM_CPS_MIN / period; - _pwm_dev[pwm].freq = freq; - DEBUG("%s freq*res was to low, freq was increased to %d Hz\n", - __func__, freq); - } + unsigned i; - /* determine a suitable pwm clock prescale */ - uint32_t prescale; - if (cps > 1000000) { - /* pwm clock is not scaled, - 8 bit timer prescaler can scale down timer clock to 625 kHz */ - prescale = 1; + /* disable the signal of all channels */ + critical_enter(); + for (i = 0; i < _CFG.ch_numof; i++) { + ledc_hal_set_idle_level(&_DEV.hw, _DEV.ch[i].ch, 0); + ledc_hal_set_sig_out_en(&_DEV.hw, _DEV.ch[i].ch, false); + ledc_hal_set_duty_start(&_DEV.hw, _DEV.ch[i].ch, false); + ledc_hal_ls_channel_update(&_DEV.hw, _DEV.ch[i].ch); } - else if (cps > 100000) { - /* pwm clock is scaled down to 10 MHz, - 8 bit timer prescaler can scale down timer clock to 39,0625 kHz */ - prescale = 16; - } - else if (cps > 10000) { - /* pwm clock is scaled down to 1 MHz - 8 bit timer prescaler can scale down timer clock to 3,90625 kHz */ - prescale = 160; - } - else { - /* pwm clock is scaled down to 640 kHz - 8 bit timer prescaler can scale down timer clock to 2,5 kHz */ - prescale = 250; - } - _pwm_hw[pwm].regs->clk_cfg.clk_prescale = prescale - 1; - - /* set timing parameters (only timer0 is used) */ - _pwm_hw[pwm].regs->timer[0].timer_cfg0.timer_prescale = (PWM_CLK / prescale / cps) - 1; - _pwm_hw[pwm].regs->timer[0].timer_cfg0.timer_period = (mode == PWM_CENTER) ? res : res - 1; - _pwm_hw[pwm].regs->timer[0].timer_cfg0.timer_period_upmethod = PWM_TIMER_UPDATE_IMMIDIATE; - - /* start the timer */ - _pwm_hw[pwm].regs->timer[0].timer_cfg1.timer_start = PWM_TIMER_RUNS_ON; - - /* set timer sync phase and enable timer sync input */ - _pwm_hw[pwm].regs->timer[0].timer_sync.timer_phase = 0; - _pwm_hw[pwm].regs->timer[0].timer_sync.timer_synci_en = 1; + _DEV.enabled = false; + critical_exit(); - /* set the duty for all channels to start them */ - for (int i = 0; i < _pwm_dev[pwm].chn_num; i++) { - if (_pwm_dev[pwm].chn[i].used) - pwm_set(pwm, i, _pwm_dev[pwm].chn[i].duty); + /* check whether all devices of the same hardware module are disabled */ + for (i = 0; i < PWM_NUMOF; i++) { + if ((_CFG.module == pwm_config[i].module) && _pwm_dev[i].enabled) { + break; + } } - /* sync all timers */ - for (unsigned i = 0; i < PWM_NUMOF; i++) { - _pwm_hw[i].regs->timer[0].timer_sync.timer_sync_sw = - ~_pwm_hw[i].regs->timer[0].timer_sync.timer_sync_sw; + /* if all devices of the same hardware module are disable, it is powered off */ + if (i == PWM_NUMOF) { + esp_idf_periph_module_disable(_CFG.module); } } -static void _pwm_stop(pwm_t pwm) +void pwm_print_config(void) { - /* disable the timer */ - _pwm_hw[pwm].regs->timer[0].timer_cfg1.timer_mod = PWM_TIMER_MOD_FREEZE; + for (unsigned pwm = 0; pwm < PWM_NUMOF; pwm++) { + printf("\tPWM_DEV(%d)\tchannels=[ ", pwm); + for (int i = 0; i < _CFG.ch_numof; i++) { + printf("%d ", _CFG.gpios[i]); + } + printf("]\n"); + } } -/* do some static initialization and configuration checks */ -static bool _pwm_configuration(void) +/* do static configuration checks */ +static bool _pwm_initialize(void) { - if (PWM_NUMOF > PWM_NUMOF_MAX) { - LOG_TAG_ERROR("pwm", "%d PWM devices were defined, only %d PWM are " - "supported\n", PWM_NUMOF, PWM_NUMOF_MAX); - return false; - } + unsigned ch_numof[2] = {}; - for (unsigned i = 0; i < PWM_NUMOF; i++) { - if (_pwm_hw[i].gpio_num > PWM_CHANNEL_NUM_DEV_MAX) { + for (unsigned pwm = 0; pwm < PWM_NUMOF; pwm++) { + /* compute the channel indices */ + for (unsigned i = 0; i < _CFG.ch_numof; i++) { + _pwm_dev[pwm].ch[i].ch = ch_numof[_CFG.group] + i; + } + ch_numof[_CFG.group] += _CFG.ch_numof; + if (_CFG.ch_numof > PWM_CH_NUMOF_MAX) { LOG_TAG_ERROR("pwm", "Number of PWM channels of device %d is %d, " - "at maximum only %d channels per PWM device are " - "supported\n", - i, _pwm_hw[i].gpio_num, PWM_CHANNEL_NUM_DEV_MAX); + "only %d channels per PWM device are supported\n", + pwm, _CFG.ch_numof, PWM_CH_NUMOF_MAX); return false; } } + + unsigned total_ch_numof = ch_numof[0] + ch_numof[1]; + + if (total_ch_numof > (SOC_LEDC_CHANNEL_NUM * ARRAY_SIZE(ledc_periph_signal))) { + LOG_TAG_ERROR("pwm", "Total number of PWM channels is %d, only " + "%d channels are supported at maximum\n", total_ch_numof, + PWM_CH_NUMOF_MAX * ARRAY_SIZE(ledc_periph_signal)); + return false; + } + bool multiple_used = false; - for (unsigned i = 0; i < PWM_NUMOF; i++) { - for (unsigned j = 0; j < PWM_NUMOF; j++) { - if (i != j) { - for (unsigned k = 0; k < _pwm_hw[i].gpio_num >> 2; k++) { - for (unsigned l = 0; l < _pwm_hw[j].gpio_num >> 2; l++) { - if (_pwm_hw[i].gpios[k] == _pwm_hw[j].gpios[l]) { - LOG_TAG_ERROR("pwm", "GPIO%d is used multiple times in " - "PWM devices %d and %d\n", - _pwm_hw[i].gpios[k], i, j); - multiple_used = true; - } + for (unsigned pi = 0; pi < PWM_NUMOF; pi++) { + for (unsigned ci = 0; ci < pwm_config[pi].ch_numof; ci++) { + for (unsigned pj = 0; pj < PWM_NUMOF; pj++) { + if (pi == pj) { + continue; + } + for (unsigned cj = 0; cj < pwm_config[pj].ch_numof; cj++) { + if (pwm_config[pi].gpios[ci] == pwm_config[pj].gpios[cj]) { + LOG_TAG_ERROR("pwm", "GPIO%d is used multiple times in " + "PWM devices %d and %d\n", + pwm_config[pi].gpios[ci], pi, pj); + multiple_used = true; } } } @@ -434,22 +376,11 @@ static bool _pwm_configuration(void) return true; } -void pwm_print_config(void) -{ - for (unsigned pwm = 0; pwm < PWM_NUMOF; pwm++) { - printf("\tPWM_DEV(%d)\tchannels=[ ", pwm); - for (int i = 0; i < _pwm_hw[pwm].gpio_num; i++) { - printf("%d ", _pwm_hw[pwm].gpios[i]); - } - printf("]\n"); - } -} - -#else /* defined(PWM0_GPIOS) || defined(PWM1_GPIOS) */ +#else void pwm_print_config(void) { LOG_TAG_INFO("pwm", "no PWM devices\n"); } -#endif /* defined(PWM0_GPIOS) || defined(PWM1_GPIOS) */ +#endif From 128d91d94280b70c83d65a1d1d001bb0730496d2 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 10 Mar 2022 04:59:41 +0100 Subject: [PATCH 25/46] cpu/esp32: port periph/pm to ESP-IDF sleep API --- cpu/esp32/periph/pm.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/cpu/esp32/periph/pm.c b/cpu/esp32/periph/pm.c index 4f6c10dd1d9f..6768f13312d4 100644 --- a/cpu/esp32/periph/pm.c +++ b/cpu/esp32/periph/pm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2022 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 @@ -21,10 +21,14 @@ /* RIOT headers have to be included before ESP-IDF headers! */ #include "esp_attr.h" #include "gpio_arch.h" +#include "irq.h" #include "periph/rtc.h" #include "rtt_arch.h" #include "syscalls.h" +#include "periph/rtc.h" +#include "periph/uart.h" + /* ESP-IDF headers */ #include "esp_sleep.h" #include "rom/rtc.h" @@ -32,6 +36,8 @@ #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" +#include "esp_idf_api/uart.h" + #define ENABLE_DEBUG 0 #include "debug.h" @@ -62,8 +68,15 @@ static inline void pm_set_lowest_normal(void) #ifndef MODULE_ESP_QEMU /* passive wait for interrupt to leave lowest power mode */ +#if __xtensa__ __asm__ volatile ("waiti 0"); - +#else + /* This function is entered with interrupts disabled, so we have to enable + * interrupts here to wait for an interrupt. */ + irq_enable(); + __asm__ volatile ("wfi"); + irq_disable(); +#endif /* reset system watchdog timer */ system_wdt_feed(); #endif @@ -119,7 +132,8 @@ void pm_set(unsigned mode) return; } - DEBUG ("%s enter to power mode %d @%u\n", __func__, mode, system_get_time()); + DEBUG ("%s enter to power mode %d @%" PRIu32 "\n", + __func__, mode, system_get_time()); /* flush stdout */ fflush(stdout); @@ -148,6 +162,16 @@ void pm_set(unsigned mode) /* Prepare GPIOs as wakeup source */ gpio_pm_sleep_enter(mode); + extern esp_err_t esp_sleep_enable_uart_wakeup(int uart); +#if (ESP_PM_WUP_UART0 > 2) + esp_idf_uart_set_wakeup_threshold(UART_DEV(0), ESP_PM_WUP_UART0); + esp_sleep_enable_uart_wakeup(0); +#endif +#if (ESP_PM_WUP_UART1 > 2) + esp_idf_uart_set_wakeup_threshold(UART_DEV(1), ESP_PM_WUP_UART0); + esp_sleep_enable_uart_wakeup(1); +#endif + if (mode == ESP_PM_DEEP_SLEEP) { esp_deep_sleep_start(); /* waking up from deep-sleep leads to a DEEPSLEEP_RESET */ @@ -165,8 +189,8 @@ void pm_set(unsigned mode) gpio_pm_sleep_exit(wakeup_reason); rtt_pm_sleep_exit(wakeup_reason); - DEBUG ("%s exit from power mode %d @%u with reason %d\n", __func__, - mode, system_get_time(), wakeup_reason); + DEBUG ("%s exit from power mode %d @%" PRIu32 " with reason %d\n", + __func__, mode, system_get_time(), wakeup_reason); /* restart WiFi if necessary */ if (IS_USED(MODULE_ESP_WIFI_ANY) && (esp_wifi_start() != ESP_OK)) { From 3bdcbca17c3539579f293ad580bbe75ff84acfe5 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 10 Mar 2022 05:02:10 +0100 Subject: [PATCH 26/46] cpu/common: port periph/hwrng to ESP random API --- cpu/esp32/include/periph_cpu.h | 2 +- cpu/esp_common/periph/hwrng.c | 49 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index 1e700199f63d..9e521eeb2ab1 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -443,7 +443,7 @@ typedef struct { /** * @brief The address of the register for accessing the hardware RNG. */ -#define RNG_DATA_REG_ADDR (0x3ff75144) +#define RNG_DATA_REG_ADDR (WDEV_RND_REG) /** @} */ /** diff --git a/cpu/esp_common/periph/hwrng.c b/cpu/esp_common/periph/hwrng.c index ecc5bbc76214..e90798643ead 100644 --- a/cpu/esp_common/periph/hwrng.c +++ b/cpu/esp_common/periph/hwrng.c @@ -23,13 +23,40 @@ #include "periph_conf.h" #include "periph/hwrng.h" +#if !defined(MCU_ESP8266) +#include "bootloader_random.h" +#include "esp_random.h" +#include "soc/wdev_reg.h" + +#define ESP32_USE_ESP_IDF_RANDOM 1 + +#endif + #define RNG_DATA_REG (*(volatile uint32_t *)RNG_DATA_REG_ADDR) void hwrng_init(void) { +#if defined(MCU_ESP8266) /* no need for initialization */ +#else + if (!IS_USED(MODULE_WIFI_ANY)) { + /* + * The hardware RNG generates random numbers uses the noise in the + * RF system of the WiFi or the BT interface as entropy source. + * If both are disabled, the random number generator just returns + * pseudo-random numbers. + * However, the bootloader use an internal non-RF entropy source, + * the internal reference voltage noise. This can be re-enabled + * after startup as entropy source for applications that don't + * use the WiFi or the BT interface. + */ + bootloader_random_enable(); + } +#endif } +#if defined(MCU_ESP8266) || !defined(ESP32_USE_ESP_IDF_RANDOM) + void hwrng_read(void *buf, unsigned int num) { unsigned int count = 0; @@ -53,3 +80,25 @@ uint32_t hwrand(void) hwrng_read(&_tmp, sizeof(uint32_t)); return _tmp; } + +#else + +/** + * The RNG implementation of the ESP-IDF also uses the hardware RNG register + * RNG_DATA_REG (WDEV_RND_REG) for random number generation, which adds 2 bits + * of entropy at each APB clock cycle when WiFi or BT are enabled. However, + * it ensures that the random numbers are not read faster than generated + * in hardware by including some busy waiting. We therefore use this + * implementation here. + */ +void hwrng_read(void *buf, unsigned int num) +{ + esp_fill_random(buf, num); +} + +uint32_t hwrand(void) +{ + return esp_random(); +} + +#endif From 8370a3064aed5ebcaa4703dcbb094e34968b126a Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 10 Mar 2022 05:06:05 +0100 Subject: [PATCH 27/46] cpu/esp_common: move periph/spi to cpu/esp8266 periph/spi implementation can be used for ESP8266 only from now. An implementation using the ESP-IDF spi HAL interface is required for ESP32x SoCs. --- cpu/{esp_common => esp8266}/periph/spi.c | 134 +++-------------------- 1 file changed, 17 insertions(+), 117 deletions(-) rename cpu/{esp_common => esp8266}/periph/spi.c (75%) diff --git a/cpu/esp_common/periph/spi.c b/cpu/esp8266/periph/spi.c similarity index 75% rename from cpu/esp_common/periph/spi.c rename to cpu/esp8266/periph/spi.c index 211af830cb34..6beb525bee8f 100644 --- a/cpu/esp_common/periph/spi.c +++ b/cpu/esp8266/periph/spi.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2022 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 @@ -7,12 +7,12 @@ */ /** - * @ingroup cpu_esp_common + * @ingroup cpu_esp8266 * @ingroup drivers_periph_spi * @{ * * @file - * @brief Low-level SPI driver implementation for ESP SoCs + * @brief Low-level SPI driver implementation for ESP8266 * * @author Gunar Schorcht * @@ -28,6 +28,7 @@ #include "cpu.h" #include "mutex.h" #include "periph/spi.h" +#include "macros/units.h" #include "esp_attr.h" #include "gpio_arch.h" @@ -35,67 +36,30 @@ #define ENABLE_DEBUG 0 #include "debug.h" -#ifdef MCU_ESP32 - -#include "driver/periph_ctrl.h" -#include "rom/ets_sys.h" -#include "soc/gpio_reg.h" -#include "soc/gpio_sig_map.h" -#include "soc/gpio_struct.h" -#include "soc/io_mux_reg.h" -#include "soc/rtc.h" -#include "soc/spi_reg.h" -#include "soc/spi_struct.h" - -#else /* MCU_ESP32 */ - #include "esp/iomux_regs.h" #include "esp8266/spi_register.h" #include "esp8266/spi_struct.h" #define SPI_DOUTDIN (BIT(0)) -#endif /* MCU_ESP32 */ - -#define KHZ (1000) - #define SPI_BLOCK_SIZE 64 /* number of bytes per SPI transfer */ -/* pins of FSI are fixed */ -#define FSPI_SCK GPIO6 -#define FSPI_MISO GPIO7 -#define FSPI_MOSI GPIO8 - /** structure which describes all properties of one SPI bus */ struct _spi_bus_t { spi_dev_t* regs; /* pointer to register data struct of the SPI device */ mutex_t lock; /* mutex for each possible SPI interface */ bool initialized; /* interface already initialized */ bool pins_initialized; /* pins interface initialized */ -#ifdef MCU_ESP32 - uint8_t mod; /* peripheral hardware module of the SPI interface */ - uint8_t int_src; /* peripheral interrupt source used by the SPI device */ - uint8_t signal_sck; /* SCK signal from the controller */ - uint8_t signal_mosi; /* MOSI signal from the controller */ - uint8_t signal_miso; /* MISO signal to the controller */ -#endif /* MCU_ESP32 */ }; static struct _spi_bus_t _spi[] = { - #ifdef SPI0_CTRL - { - .initialized = false, - .pins_initialized = false, - .lock = MUTEX_INIT - }, - #endif - #ifdef SPI1_CTRL +#ifdef SPI0_CTRL { .initialized = false, .pins_initialized = false, .lock = MUTEX_INIT }, - #endif +#endif }; /* @@ -107,34 +71,17 @@ static struct _spi_bus_t _spi[] = { * the *spi_init_cs* function or the *spi_acquire* function when the interface * is used for the first time. */ -void IRAM_ATTR spi_init (spi_t bus) +void IRAM_ATTR spi_init(spi_t bus) { assert(bus < SPI_NUMOF_MAX); assert(bus < SPI_NUMOF); - switch (spi_config[bus].ctrl) { -#ifdef MCU_ESP32 - case HSPI: _spi[bus].regs = &SPI2; - _spi[bus].mod = PERIPH_HSPI_MODULE; - _spi[bus].int_src = ETS_SPI2_INTR_SOURCE; - _spi[bus].signal_sck = HSPICLK_OUT_IDX; - _spi[bus].signal_mosi = HSPID_OUT_IDX; - _spi[bus].signal_miso = HSPIQ_IN_IDX; - break; - case VSPI: _spi[bus].regs = &SPI3; - _spi[bus].mod = PERIPH_VSPI_MODULE; - _spi[bus].int_src = ETS_SPI3_INTR_SOURCE; - _spi[bus].signal_sck = VSPICLK_OUT_IDX; - _spi[bus].signal_mosi = VSPID_OUT_IDX; - _spi[bus].signal_miso = VSPIQ_IN_IDX; - break; -#else /* MCU_ESP32 */ - case HSPI: _spi[bus].regs = &SPI1; - break; -#endif /* MCU_ESP32 */ - default: LOG_TAG_ERROR("spi", "invalid SPI interface controller " - "used for SPI_DEV(%d)\n", bus); - break; + if (spi_config[bus].ctrl == HSPI) { + _spi[bus].regs = &SPI1; + } + else { + LOG_TAG_ERROR("spi", "invalid SPI interface controller " + "used for SPI_DEV(%d)\n", bus); } return; } @@ -164,11 +111,6 @@ static void IRAM_ATTR _spi_init_internal(spi_t bus) return; } -#ifdef MCU_ESP32 - /* enable (power on) the according SPI module */ - periph_module_enable(_spi[bus].mod); -#endif /* MCU_ESP32 */ - /* bring the bus into a defined state */ _spi[bus].regs->user.val = SPI_USR_MOSI | SPI_CK_I_EDGE | SPI_DOUTDIN | SPI_CS_SETUP | SPI_CS_HOLD; @@ -189,9 +131,6 @@ static void IRAM_ATTR _spi_init_internal(spi_t bus) /* disable fast read mode and write protection */ _spi[bus].regs->ctrl.fastrd_mode = 0; -#ifdef MCU_ESP32 - _spi[bus].regs->ctrl.wp = 0; -#endif /* MCU_ESP32 */ /* acquire and release to set default parameters */ spi_acquire(bus, GPIO_UNDEF, SPI_MODE_0, SPI_CLK_1MHZ); @@ -215,9 +154,9 @@ void spi_init_pins(spi_t bus) DEBUG("%s bus=%u\n", __func__, bus); - if (gpio_init (spi_config[bus].sck, GPIO_OUT) || - gpio_init (spi_config[bus].mosi, GPIO_OUT) || - gpio_init (spi_config[bus].miso, GPIO_IN)) { + if (gpio_init(spi_config[bus].sck, GPIO_OUT) || + gpio_init(spi_config[bus].mosi, GPIO_OUT) || + gpio_init(spi_config[bus].miso, GPIO_IN)) { LOG_TAG_ERROR("spi", "SPI_DEV(%d) pins could not be initialized\n", bus); return; @@ -234,15 +173,6 @@ void spi_init_pins(spi_t bus) gpio_set_pin_usage(spi_config[bus].mosi, _SPI); gpio_set_pin_usage(spi_config[bus].miso, _SPI); -#ifdef MCU_ESP32 - /* connect SCK and MOSI pins to the output signal through the GPIO matrix */ - GPIO.func_out_sel_cfg[spi_config[bus].sck].func_sel = _spi[bus].signal_sck; - GPIO.func_out_sel_cfg[spi_config[bus].mosi].func_sel = _spi[bus].signal_mosi; - /* connect MISO input signal to the MISO pin through the GPIO matrix */ - GPIO.func_in_sel_cfg[_spi[bus].signal_miso].sig_in_sel = 1; - GPIO.func_in_sel_cfg[_spi[bus].signal_miso].sig_in_inv = 0; - GPIO.func_in_sel_cfg[_spi[bus].signal_miso].func_sel = spi_config[bus].miso; -#else /* MCU_ESP32 */ /* * CS is handled as normal GPIO output. Due to the small number of GPIOs * we have, we do not initialize the default CS pin here. Either the app @@ -258,7 +188,6 @@ void spi_init_pins(spi_t bus) IOMUX.PIN[_gpio_to_iomux[spi_config[bus].miso]] |= iomux_func; IOMUX.PIN[_gpio_to_iomux[spi_config[bus].mosi]] |= iomux_func; IOMUX.PIN[_gpio_to_iomux[spi_config[bus].sck]] |= iomux_func; -#endif /* MCU_ESP32 */ } int spi_init_cs(spi_t bus, spi_cs_t cs) @@ -319,7 +248,7 @@ void IRAM_ATTR spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t cl /* * set SPI mode - * see ESP32 Technical Reference, Table 25 and Section 7.4.2 + * see ESP32 Technical Reference, Table 27 and Section 7.4.1 */ _spi[bus].regs->pin.ck_idle_edge = (mode == SPI_MODE_2 || mode == SPI_MODE_3); _spi[bus].regs->user.ck_out_edge = (mode == SPI_MODE_1 || mode == SPI_MODE_2); @@ -336,23 +265,6 @@ void IRAM_ATTR spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t cl uint32_t spi_clkdiv_pre; uint32_t spi_clkcnt_N; -#ifdef MCU_ESP32 - uint32_t apb_clk = rtc_clk_apb_freq_get(); - spi_clkcnt_N = 2; - switch (clk) { - case SPI_CLK_10MHZ: spi_clkdiv_pre = apb_clk / (10 * MHZ) / 2; - break; - case SPI_CLK_5MHZ: spi_clkdiv_pre = apb_clk / (5 * MHZ) / 2; - break; - case SPI_CLK_1MHZ: spi_clkdiv_pre = apb_clk / MHZ / 2; - break; - case SPI_CLK_400KHZ: spi_clkdiv_pre = apb_clk / (400 * KHZ) / 2; - break; - case SPI_CLK_100KHZ: /* fallthrough intentionally */ - default: spi_clkdiv_pre = apb_clk / (100 * KHZ) / 2; - } - assert(spi_clkdiv_pre > 0); -#else switch (clk) { case SPI_CLK_10MHZ: spi_clkdiv_pre = 2; /* predivides 80 MHz to 40 MHz */ spi_clkcnt_N = 4; /* 4 cycles results into 10 MHz */ @@ -372,7 +284,6 @@ void IRAM_ATTR spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t cl default: spi_clkdiv_pre = 20; /* predivides 80 MHz to 4 MHz */ spi_clkcnt_N = 40; /* 20 cycles results into 100 kHz */ } -#endif /* register values are set to deviders-1 */ spi_clkdiv_pre--; @@ -381,9 +292,7 @@ void IRAM_ATTR spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t cl DEBUG("%s spi_clkdiv_prev=%u spi_clkcnt_N=%u\n", __func__, spi_clkdiv_pre, spi_clkcnt_N); -#ifdef MCU_ESP8266 IOMUX.CONF &= ~IOMUX_CONF_SPI1_CLOCK_EQU_SYS_CLOCK; -#endif /* SPI clock is derived from APB clock by dividers */ _spi[bus].regs->clock.clk_equ_sysclk = 0; @@ -408,11 +317,7 @@ void IRAM_ATTR spi_release(spi_t bus) mutex_unlock(&_spi[bus].lock); } -#ifdef MCU_ESP32 -static const char* _spi_names[] = { "CSPI", "FSPI", "HSPI", "VSPI" }; -#else /* MCU_ESP32 */ static const char* _spi_names[] = { "FSPI", "HSPI" }; -#endif /* MCU_ESP32 */ void spi_print_config(void) { @@ -438,13 +343,8 @@ inline static void IRAM_ATTR _set_size(uint8_t bus, uint8_t bytes) { uint32_t bits = ((uint32_t)bytes << 3) - 1; -#ifdef MCU_ESP32 - _spi[bus].regs->mosi_dlen.val = bits; - _spi[bus].regs->miso_dlen.val = bits; -#else /* MCU_ESP32 */ _spi[bus].regs->user1.usr_mosi_bitlen = bits; _spi[bus].regs->user1.usr_miso_bitlen = bits; -#endif /* MCU_ESP32 */ } inline static void IRAM_ATTR _wait(uint8_t bus) From 2ed0e06b00fff27bbeaa9e7ca24e1adf648e6c27 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 10 Mar 2022 05:07:52 +0100 Subject: [PATCH 28/46] cpu/esp32: port periph/spi to ESP-IDF spi LL API --- cpu/esp32/include/periph_cpu.h | 7 +- cpu/esp32/periph/spi.c | 432 +++++++++++++++++++++++++++++++++ 2 files changed, 436 insertions(+), 3 deletions(-) create mode 100644 cpu/esp32/periph/spi.c diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index 9e521eeb2ab1..893876dfbf6f 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -22,6 +22,7 @@ #include #include "sdkconfig.h" #include "hal/ledc_types.h" +#include "hal/spi_types.h" #include "soc/ledc_struct.h" #include "soc/periph_defs.h" #include "soc/soc_caps.h" @@ -508,8 +509,8 @@ typedef struct { * @brief SPI controllers that can be used for peripheral interfaces */ typedef enum { - HSPI = 2, /**< HSPI interface controller */ - VSPI = 3, /**< VSPI interface controller */ + HSPI = HSPI_HOST, /**< HSPI interface controller */ + VSPI = VSPI_HOST, /**< VSPI interface controller */ } spi_ctrl_t; /** @@ -526,7 +527,7 @@ typedef struct { /** * @brief Maximum number of SPI interfaces that can be used by board definitions */ -#define SPI_NUMOF_MAX 2 +#define SPI_NUMOF_MAX (SOC_SPI_PERIPH_NUM - 1) #define PERIPH_SPI_NEEDS_TRANSFER_BYTE /**< requires function spi_transfer_byte */ #define PERIPH_SPI_NEEDS_TRANSFER_REG /**< requires function spi_transfer_reg */ diff --git a/cpu/esp32/periph/spi.c b/cpu/esp32/periph/spi.c new file mode 100644 index 000000000000..24f468d6b27f --- /dev/null +++ b/cpu/esp32/periph/spi.c @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2022 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. + */ + +/** + * @ingroup cpu_esp32 + * @ingroup drivers_periph_spi + * @{ + * + * @file + * @brief Low-level SPI driver implementation for ESP32 SoCs + * + * The implementation uses the ESP-IDF Low level interface in polling mode + * without DMA. + * + * @TODO + * - transaction interrupts to avoid busy waiting in polling mode + * - DMA transfer + * + * @author Gunar Schorcht + * + * @} + */ + +#include +#include + +#include "esp_common.h" +#include "log.h" + +#include "cpu.h" +#include "gpio_arch.h" +#include "mutex.h" +#include "periph/spi.h" +#include "syscalls.h" + +#include "esp_attr.h" +#include "esp_rom_gpio.h" +#include "hal/spi_hal.h" +#include "hal/spi_types.h" +#include "soc/rtc.h" + +#include "esp_idf_api/periph_ctrl.h" + +#undef MHZ +#include "macros/units.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +/* SPI bus descriptor structure */ +struct _spi_bus_t { + mutex_t lock; /* mutex for each SPI interface */ + bool pins_initialized; /* SPI pins initialized */ + spi_host_device_t hostid; /* SPI hostid as used by ESP-IDF */ + const spi_signal_conn_t *periph; /* SPI peripheral descriptor */ + spi_hal_timing_conf_t timing; /* calculated SPI timing parameters */ + uint32_t clk_last; /* SPI clock speed used last time in Hz */ + uint8_t mode_last; /* SPI mode used last time */ +}; + +static struct _spi_bus_t _spi[] = { +#ifdef SPI0_CTRL + { + .pins_initialized = false, + .lock = MUTEX_INIT, + .hostid = spi_config[0].ctrl, + .periph = &spi_periph_signal[spi_config[0].ctrl], + .clk_last = 0, + .mode_last = UINT8_MAX, + }, +#endif +#ifdef SPI1_CTRL + { + .pins_initialized = false, + .lock = MUTEX_INIT, + .hostid = spi_config[1].ctrl, + .periph = &spi_periph_signal[spi_config[1].ctrl], + .clk_last = 0, + .mode_last = UINT8_MAX, + }, +#endif +}; + +_Static_assert(SPI_NUMOF == ARRAY_SIZE(_spi), + "Size of bus descriptor table doesn't match SPI_NUMOF"); + +void IRAM_ATTR spi_init(spi_t bus) +{ + DEBUG("%s bus=%u\n", __func__, bus); + + assert(bus < SPI_NUMOF_MAX); + assert(bus < SPI_NUMOF); + + /* initialize pins */ + spi_init_pins(bus); + + /* check whether pins could be initialized, otherwise return, CS is not + initialized in spi_init_pins */ + if (gpio_get_pin_usage(spi_config[bus].sck) != _SPI && + gpio_get_pin_usage(spi_config[bus].miso) != _SPI && + gpio_get_pin_usage(spi_config[bus].mosi) != _SPI && + gpio_get_pin_usage(spi_config[bus].cs) != _SPI) { + return; + } + + /* enable (power on) the according SPI module */ + esp_idf_periph_module_enable(_spi[bus].periph->module); + + /* initialize SPI peripheral */ + spi_ll_master_init(_spi[bus].periph->hw); + + /* bring the bus into a defined state (one-line mode) */ + spi_ll_master_set_line_mode(_spi[bus].periph->hw, (spi_line_mode_t){ 1, 1, 1 }); + spi_ll_set_rx_lsbfirst(_spi[bus].periph->hw, false); + spi_ll_set_tx_lsbfirst(_spi[bus].periph->hw, false); + + /* acquire and release to set default parameters */ + spi_acquire(bus, GPIO_UNDEF, SPI_MODE_0, SPI_CLK_100KHZ); + spi_release(bus); + + return; +} + +void spi_init_pins(spi_t bus) +{ + assert(bus < SPI_NUMOF); + + /* avoid multiple pin initializations */ + if (_spi[bus].pins_initialized) { + return; + } + _spi[bus].pins_initialized = true; + + DEBUG("%s bus=%u\n", __func__, bus); + + if (gpio_init(spi_config[bus].sck, GPIO_OUT) || + gpio_init(spi_config[bus].mosi, GPIO_OUT) || + gpio_init(spi_config[bus].miso, GPIO_IN)) { + LOG_TAG_ERROR("spi", + "SPI_DEV(%d) pins could not be initialized\n", bus); + return; + } + if (spi_init_cs(bus, spi_config[bus].cs) != SPI_OK) { + LOG_TAG_ERROR("spi", + "SPI_DEV(%d) CS signal could not be initialized\n", + bus); + return; + } + + /* store the usage type in GPIO table */ + gpio_set_pin_usage(spi_config[bus].sck, _SPI); + gpio_set_pin_usage(spi_config[bus].mosi, _SPI); + gpio_set_pin_usage(spi_config[bus].miso, _SPI); + + /* TODO the IO_MUX should be used instead of GPIO matrix routing for + lower delays and higher clock rates whenever possible */ + + /* connect SCK and MOSI pins to the output signal through the GPIO matrix */ + esp_rom_gpio_connect_out_signal(spi_config[bus].sck, + _spi[bus].periph->spiclk_out, false, false); + esp_rom_gpio_connect_out_signal(spi_config[bus].mosi, + _spi[bus].periph->spid_out, false, false); + + /* connect MISO input signal to the MISO pin through the GPIO matrix */ + esp_rom_gpio_connect_in_signal(spi_config[bus].miso, + _spi[bus].periph->spiq_in, false); +} + +void spi_deinit_pins(spi_t bus) +{ + /* TODO */ +#if IS_USED(MODULE_SPI_RECONFIGURE) +#error not yet implemented +#endif +} + +int spi_init_cs(spi_t bus, spi_cs_t cs) +{ + DEBUG("%s bus=%u cs=%u\n", __func__, bus, cs); + + assert(bus < SPI_NUMOF); + + /* return if pin is already initialized as SPI CS signal */ + if (gpio_get_pin_usage(cs) == _SPI) { + return SPI_OK; + } + + /* check whether CS pin is used otherwise */ + if (gpio_get_pin_usage(cs) != _GPIO) { + return SPI_NOCS; + } + + /* initialize the pin */ + gpio_init(cs, GPIO_OUT); + gpio_set(cs); + + /* pin cannot be used for anything else */ + gpio_set_pin_usage(cs, _SPI); + + return SPI_OK; +} + +static const uint32_t _spi_clk_freq_hz[] = { + 100 * KHZ(1), /* SPI_CLK_100KHZ */ + 400 * KHZ(1), /* SPI_CLK_400KHZ */ + 1 * MHZ(1), /* SPI_CLK_1KHZ */ + 5 * MHZ(1), /* SPI_CLK_5MHZ */ + 10 * MHZ(1), /* SPI_CLK_10MHZ */ +}; + +void IRAM_ATTR spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +{ + DEBUG("%s bus=%u cs=%u mode=%u clk=%u\n", __func__, bus, cs, mode, clk); + + assert(bus < SPI_NUMOF); + + /* if parameter cs is GPIO_UNDEF, the default CS pin is used */ + cs = (cs == GPIO_UNDEF) ? spi_config[bus].cs : cs; + + /* if the CS pin used is not yet initialized, we do it now */ + if (gpio_get_pin_usage(cs) != _SPI && spi_init_cs(bus, cs) != SPI_OK) { + LOG_TAG_ERROR("spi", + "SPI_DEV(%d) CS signal could not be initialized\n", + bus); + assert(0); + } + + /* lock the bus */ + mutex_lock(&_spi[bus].lock); + + assert(clk < ARRAY_SIZE(_spi_clk_freq_hz)); + + /* + * set SPI mode + * see ESP32 Technical Reference, Section 7.4.1, Table 27 + * https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf + */ + + /* hardware CS not used (TODO) */ + spi_ll_master_select_cs(_spi[bus].periph->hw, INT_MAX); + spi_ll_master_set_cs_setup(_spi[bus].periph->hw, 2); + spi_ll_master_set_mode(_spi[bus].periph->hw, mode); + spi_ll_set_half_duplex(_spi[bus].periph->hw, false); + + int delay_mode = (mode == SPI_MODE_0 || mode == SPI_MODE_3) ? 2 : 1; + spi_ll_set_miso_delay(_spi[bus].periph->hw, delay_mode, 0); + spi_ll_set_mosi_delay(_spi[bus].periph->hw, 0, 0); + + /* + * set SPI clock + * see ESP32 Technical Reference, Section 7.8 SPI_CLOCK_REG + * https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf + */ + + /* check whether timing has to be recalculated (time consuming) */ + if (_spi_clk_freq_hz[clk] != _spi[bus].clk_last) { + uint32_t apb_clk = rtc_clk_apb_freq_get(); + uint32_t clk_reg; + + if (apb_clk / 5 < _spi_clk_freq_hz[clk]) { + LOG_TAG_ERROR("spi", "APB clock rate (%"PRIu32" Hz) has to be at " + "least 5 times SPI clock rate (%"PRIu32" Hz)\n", + apb_clk, _spi_clk_freq_hz[clk]); + assert(false); + } + + /* duty cycle is measured in is 1/256th, 50% = 128 */ + int _clk = spi_ll_master_cal_clock(apb_clk, _spi_clk_freq_hz[clk], + 128, &clk_reg); + + _spi[bus].clk_last = _spi_clk_freq_hz[clk]; + _spi[bus].timing.clock_reg = clk_reg; + _spi[bus].timing.timing_miso_delay = 0; + _spi[bus].timing.timing_dummy = 0; + + DEBUG("%s bus %d: SPI clock frequency: clk=%"PRIu32" eff=%d " + "reg=%08"PRIx32"\n", + __func__, bus, _spi_clk_freq_hz[clk], _clk, clk_reg); + } + spi_ll_master_set_clock_by_reg(_spi[bus].periph->hw, + &_spi[bus].timing.clock_reg); + +#if defined(MCU_ESP32C3) + /* + * If the SPI mode has been changed, the clock signal is only set to the + * correct level at the beginning of the transfer on the ESP32C3. However, + * if a generic GPIO is used as CS signal instead of the hardware CS, + * the CS signal is already LOW at this time. Thus, the clock signal will + * have the wrong level when the SPI mode is changed and the CS signal + * becomes LOW. + * The following is a workaround by receiving a dummy byte without pulling + * the CS signal LOW when the mode has been changed. + */ + if (_spi[bus].mode_last != mode) { + uint8_t temp = 0xff; + spi_transfer_bytes(bus, GPIO_UNDEF, false, &temp, &temp, 1); + _spi[bus].mode_last = mode; + } +#elif defined(MCU_ESP32) + /* This workaround isn't needed on ESP32 */ +#else +#error Platform implementation is missing +#endif + +} + +void IRAM_ATTR spi_release(spi_t bus) +{ + DEBUG("%s bus=%u\n", __func__, bus); + + assert(bus < SPI_NUMOF); + + /* release the bus */ + mutex_unlock(&_spi[bus].lock); +} + +#if defined(MCU_ESP32) +static const char* _spi_names[] = { "CSPI/FSPI", "HSPI", "VSPI" }; +#elif defined(MCU_ESP32C3) +static const char* _spi_names[] = { "SPI", "FSPI" }; +#else +#error Platform implementation required +#endif + +_Static_assert(ARRAY_SIZE(_spi_names) == SOC_SPI_PERIPH_NUM, + "Number of _spi_names doesn't match SOC_SPI_PERIPH_NUM"); + +void spi_print_config(void) +{ + for (unsigned bus = 0; bus < SPI_NUMOF; bus++) { + printf("\tSPI_DEV(%u)\t%s ", bus, _spi_names[_spi[bus].hostid]); + printf("sck=%d " , spi_config[bus].sck); + printf("miso=%d ", spi_config[bus].miso); + printf("mosi=%d ", spi_config[bus].mosi); + printf("cs0=%d\n", spi_config[bus].cs); + } +} + +static const uint8_t _spi_empty_out[SOC_SPI_MAXIMUM_BUFFER_SIZE] = { 0 }; + +static void IRAM_ATTR _spi_transfer(uint8_t bus, + const void *out, void *in, size_t len) +{ + /* transfer one block with a maximum size of SOC_SPI_MAXIMUM_BUFFER_SIZE */ + + DEBUG("%s bus=%u out=%p in=%p len=%u\n", __func__, bus, out, in, len); + + /* wait until an existing transfer is finished */ + while (spi_ll_get_running_cmd(_spi[bus].periph->hw)) {} + + /* prepare the transfer */ + spi_ll_set_half_duplex(_spi[bus].periph->hw, false); + spi_ll_set_command_bitlen(_spi[bus].periph->hw, 0); + spi_ll_set_addr_bitlen(_spi[bus].periph->hw, 0); + spi_ll_set_mosi_bitlen(_spi[bus].periph->hw, (uint32_t)len << 3); + spi_ll_set_miso_bitlen(_spi[bus].periph->hw, (uint32_t)len << 3); + spi_ll_enable_mosi(_spi[bus].periph->hw, 1); + + /* write output data to the buffer of the SPI controller */ + spi_ll_write_buffer(_spi[bus].periph->hw, out ? out : _spi_empty_out, len << 3); + + /* start the transfer */ + spi_ll_master_user_start(_spi[bus].periph->hw); + + /* wait until the transfer is finished */ + while (spi_ll_get_running_cmd(_spi[bus].periph->hw)) {} + + /* read input data from the buffer of the SPI controller */ + if (in) { + spi_ll_read_buffer(_spi[bus].periph->hw, in, len << 3); + } +} + +void IRAM_ATTR spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) +{ + assert(bus < SPI_NUMOF); + + DEBUG("%s bus=%u cs=%u cont=%d out=%p in=%p len=%u\n", + __func__, bus, cs, cont, out, in, len); + + if (!len) { + return; + } + + if (IS_ACTIVE(ENABLE_DEBUG)) { + if (out) { + DEBUG("out = "); + for (size_t i = 0; i < len; i++) { + DEBUG("%02x ", ((const uint8_t *)out)[i]); + } + DEBUG("\n"); + } + } + + if (cs != SPI_CS_UNDEF) { + gpio_clear(cs); + } + + const uint8_t *blk_out = out; + uint8_t *blk_in = in; + size_t idx = 0; + + while (idx < len) { + /* maximum non-DMA transfer size is SOC_SPI_MAXIMUM_BUFFER_SIZE */ + size_t blk_len = MIN(len - idx, SOC_SPI_MAXIMUM_BUFFER_SIZE); + _spi_transfer(bus, blk_out, blk_in, blk_len); + blk_out = (out) ? blk_out + blk_len : NULL; + blk_in = (in) ? blk_in + blk_len : NULL; + idx += blk_len; + system_wdt_feed(); + } + + if (!cont && (cs != SPI_CS_UNDEF)) { + gpio_set (cs); + } + + if (IS_ACTIVE(ENABLE_DEBUG)) { + if (in) { + DEBUG("in = "); + for (size_t i = 0; i < len; i++) { + DEBUG("%02x ", ((const uint8_t *)in)[i]); + } + DEBUG("\n"); + } + } +} From 9928c1f296b69bd57ae17def21594770f40de8a4 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 10 Mar 2022 05:10:12 +0100 Subject: [PATCH 29/46] cpu/esp32: port priph/timer to ESP-IDF interface API --- cpu/esp32/periph/timer.c | 407 +++++++++++++++++++-------------------- 1 file changed, 202 insertions(+), 205 deletions(-) diff --git a/cpu/esp32/periph/timer.c b/cpu/esp32/periph/timer.c index d3ffddaba4fc..1ba0f7c1884d 100644 --- a/cpu/esp32/periph/timer.c +++ b/cpu/esp32/periph/timer.c @@ -24,148 +24,131 @@ * WARNING! enable debugging will have timing side effects and can lead * to timer underflows, system crashes or system dead locks in worst case. */ -#define ENABLE_DEBUG 0 -#include "debug.h" - #include "periph/timer.h" -#include "driver/periph_ctrl.h" #include "esp/common_macros.h" +#include "hal/interrupt_controller_types.h" +#include "hal/interrupt_controller_ll.h" +#include "hal/timer_hal.h" #include "rom/ets_sys.h" +#include "soc/periph_defs.h" #include "soc/rtc.h" #include "soc/timer_group_struct.h" + +#if __xtensa__ #include "xtensa/hal.h" #include "xtensa/xtensa_api.h" +#endif + +#include "esp_idf_api/periph_ctrl.h" #include "esp_common.h" #include "irq_arch.h" #include "syscalls.h" +#define ENABLE_DEBUG 0 +#include "debug.h" + #define RTC_PLL_480M 480 /* PLL with 480 MHz at maximum */ -#define RTC_PLL_320M 320 /* PLL with 480 MHz at maximum */ +#define RTC_PLL_320M 320 /* PLL with 320 MHz at maximum */ #ifndef MODULE_ESP_HW_COUNTER /* hardware timer modules used */ /** - * ESP32 has four 64 bit hardware timers: - * two timer groups TMG0 and TMG1 with 2 timers each - * - * TMG0, timer 0 is used for system time in us and is therefore not - * available as low level timer. Timers have only one channel. Timer devices - * are mapped to hardware timer as following: - * - * 0 -> TMG0 timer 1 - * 1 -> TMG1 timer 0 - * 2 -> TMG1 timer 1 - * - * The reason for this mapping is, that if only one timer is needed, - * TMG1 is left disabled. TMG1 is only enabled when more than one - * timer device is needed. - * - * PLEASE NOTE: Don't use ETS timer functions ets_timer_* in and this hardware - * timer implementation together! - */ + * ESP32 has four 64 bit hardware timers: + * two timer groups TMG0 and TMG1 with 2 timers each + * + * TMG0, timer 0 is used for system time in us and is therefore not + * available as low level timer. Timers have only one channel. Timer devices + * are mapped to hardware timer as following: + * + * 0 -> TMG0 timer 1 + * 1 -> TMG1 timer 0 + * 2 -> TMG1 timer 1 + * + * The reason for this mapping is, that if only one timer is needed, + * TMG1 is left disabled. TMG1 is only enabled when more than one + * timer device is needed. + * + * PLEASE NOTE: Don't use ETS timer functions ets_timer_* in and this hardware + * timer implementation together! + */ + +#if defined(MCU_ESP32) -#define HW_TIMER_NUMOF 3 -#define HW_TIMER_CHANNELS 1 -#define HW_TIMER_CLK_DIV (rtc_clk_apb_freq_get() / 1000000) #define HW_TIMER_CORRECTION (RTC_PLL_320M / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) #define HW_TIMER_DELTA_MIN (MAX(HW_TIMER_CORRECTION << 1, 5)) -#define HW_TIMER_FREQUENCY (1000000UL) /* only 1MHz is supported */ -struct hw_timer_regs_t { - /* see Technical Reference, section 17.4 */ - struct { - uint32_t unused : 10; - uint32_t ALARM_EN : 1; /* alarms are enabled */ - uint32_t LEVEL_INT_EN: 1; /* alarms will generate level type interrupt */ - uint32_t EDGE_INT_EN : 1; /* alarms will generate edge type interrupt */ - uint32_t DIVIDER : 16; /* timer clock prescale value (basis is ABP) */ - uint32_t AUTORELOAD : 1; /* auto-reload on alarms */ - uint32_t INCREASE : 1; /* count up */ - uint32_t EN : 1; /* timer is enabled */ - } CONFIG_REG; - uint32_t LO_REG; /* time-base counter value low 32 bits */ - uint32_t HI_REG; /* time-base counter value high 32 bits */ - uint32_t UPDATE_REG; /* time-base counter value update trigger */ - uint32_t ALARMLO_REG; /* alarm trigger time-base counter value, low 32 bits */ - uint32_t ALARMHI_REG; /* alarm trigger time-base counter value, high 32 bits */ - uint32_t LOADLO_REG; /* reload value, low 32 bits */ - uint32_t LOADHI_REG; /* reload value, high 32 bits */ - uint32_t LOAD_REG; /* reload trigger */ -}; +#else +#error "MCU implementation needed" +#endif -struct hw_timer_ints_t { - /* see Technical Reference, section 17.4 */ - uint32_t INT_ENA_REG; /* interrupt enable bits */ - uint32_t INT_RAW_REG; /* raw interrupt status */ - uint32_t INT_STA_REG; /* masked interrupt status */ - uint32_t INT_CLR_REG; /* interrupt clear bits */ -}; +#define HW_TIMER_CLK_DIV (rtc_clk_apb_freq_get() / 1000000) +#define HW_TIMER_FREQUENCY (1000000UL) /* only 1MHz is supported */ +#define HW_TIMER_NUMOF ARRAY_SIZE(_timers_desc) +#define HW_TIMER_CHANNELS 1 -struct hw_timer_t { +struct _hw_timer_t { bool initialized; /* indicates whether timer is already initialized */ bool started; /* indicates whether timer is already started */ - timer_isr_ctx_t isr_ctx; + timer_isr_ctx_t isr_ctx; /* registered ISR */ + timer_hal_context_t hw; /* timer hardware reference */ }; -struct hw_timer_hw_t { - volatile struct hw_timer_regs_t* regs; /* timer configuration regs */ - volatile struct hw_timer_ints_t* int_regs; /* timer interrupt regs */ - uint8_t int_mask; /* timer interrupt bit mask in interrupt regs */ - uint8_t int_src; /* timer interrupt source */ +struct _hw_timer_desc_t { + uint8_t module; /* hardware module identifier */ + timer_group_t group; /* timer group identifier */ + timer_idx_t index; /* timer index in timer group */ + uint8_t int_mask; /* timer interrupt bit mask in interrupt regs */ + uint8_t int_src; /* timer interrupt source */ }; -static struct hw_timer_t timers[HW_TIMER_NUMOF] = { }; -static const struct hw_timer_hw_t timers_hw[HW_TIMER_NUMOF] = +static const struct _hw_timer_desc_t _timers_desc[] = { +#if defined(MCU_ESP32) { - .regs = (struct hw_timer_regs_t*)&TIMERG0.hw_timer[1], - .int_regs = (struct hw_timer_ints_t*)&TIMERG0.int_ena, - .int_mask = BIT(1), - .int_src = ETS_TG0_T1_LEVEL_INTR_SOURCE + .module = PERIPH_TIMG0_MODULE, + .group = TIMER_GROUP_0, + .index = TIMER_1, + .int_mask = BIT(TIMER_1), + .int_src = ETS_TG0_T1_LEVEL_INTR_SOURCE, }, { - .regs = (struct hw_timer_regs_t*)&TIMERG1.hw_timer[0], - .int_regs = (struct hw_timer_ints_t*)&TIMERG1.int_ena, - .int_mask = BIT(0), - .int_src = ETS_TG1_T0_LEVEL_INTR_SOURCE + .module = PERIPH_TIMG1_MODULE, + .group = TIMER_GROUP_1, + .index = TIMER_0, + .int_mask = BIT(TIMER_0), + .int_src = ETS_TG1_T0_LEVEL_INTR_SOURCE, }, { - .regs = (struct hw_timer_regs_t*)&TIMERG1.hw_timer[1], - .int_regs = (struct hw_timer_ints_t*)&TIMERG1.int_ena, - .int_mask = BIT(1), - .int_src = ETS_TG1_T1_LEVEL_INTR_SOURCE + .module = PERIPH_TIMG1_MODULE, + .group = TIMER_GROUP_1, + .index = TIMER_1, + .int_mask = BIT(TIMER_1), + .int_src = ETS_TG1_T1_LEVEL_INTR_SOURCE, } +#else +#error "MCU implementation needed" +#endif }; +static struct _hw_timer_t _timers[HW_TIMER_NUMOF] = { }; + /** Latches the current counter value and return only the low part */ -static inline uint32_t timer_get_counter_lo(tim_t dev) +static inline uint32_t _timer_get_counter_lo(tim_t dev) { - /* latch the current timer value by writing any value to the update reg */ - timers_hw[dev].regs->UPDATE_REG = 0; - /* read high and low part of counter */ - return timers_hw[dev].regs->LO_REG; -} + /* latch the current timer value and get current timer value */ + uint64_t value; + timer_hal_get_counter_value(&_timers[dev].hw, &value); -/** Latches the current counter value and return the high and the low part */ -static inline void timer_get_counter(tim_t dev, uint32_t* hi, uint32_t* lo) -{ - /* parameter check */ - if (!hi || !lo) { - return; - } - /* latch the current timer value by writing any value to the update reg */ - timers_hw[dev].regs->UPDATE_REG = 0; - /* read high and low part of counter */ - *hi = timers_hw[dev].regs->HI_REG; - *lo = timers_hw[dev].regs->LO_REG; + /* return high and low part of timer */ + return value; } -void IRAM hw_timer_handler(void* arg) +void IRAM_ATTR _timer_int_handler(void* arg) { (void)arg; @@ -176,62 +159,78 @@ void IRAM hw_timer_handler(void* arg) for (unsigned dev = 0; dev < HW_TIMER_NUMOF; dev++) { /* iterate over all devices and check what interrupt flags are set */ - if (timers_hw[dev].int_regs->INT_STA_REG & timers_hw[dev].int_mask) { + + if (!_timers[dev].initialized) { + continue; + } + uint32_t int_status; + timer_hal_get_intr_status(&_timers[dev].hw, &int_status); + + if (int_status & _timers_desc[dev].int_mask) { DEBUG("%s dev=%d\n", __func__, dev); + /* disable alarms */ - timers_hw[dev].regs->CONFIG_REG.LEVEL_INT_EN = 0; - timers_hw[dev].regs->CONFIG_REG.ALARM_EN = 0; - /* clear the bit in interrupt enable and status register */ - timers_hw[dev].int_regs->INT_ENA_REG &= ~timers_hw[dev].int_mask; - timers_hw[dev].int_regs->INT_CLR_REG |= timers_hw[dev].int_mask; + timer_hal_set_alarm_enable(&_timers[dev].hw, false); + + /* disable interrupt source and clear the bit in interrupt status */ + timer_hal_set_level_int_enable(&_timers[dev].hw, false); + timer_hal_intr_disable(&_timers[dev].hw); + timer_hal_clear_intr_status(&_timers[dev].hw); + /* execute the callback function */ - timers[dev].isr_ctx.cb(timers[dev].isr_ctx.arg, 0); + _timers[dev].isr_ctx.cb(_timers[dev].isr_ctx.arg, 0); } } irq_isr_exit(); } -int timer_init (tim_t dev, uint32_t freq, timer_cb_t cb, void *arg) +int timer_init(tim_t dev, uint32_t freq, timer_cb_t cb, void *arg) { + _Static_assert(HW_TIMER_NUMOF == TIMER_NUMOF, + "Number of timer descriptors does not match with TIMER_NUMOF"); + DEBUG("%s dev=%u freq=%" PRIu32 " cb=%p arg=%p\n", __func__, dev, freq, cb, arg); - CHECK_PARAM_RET (dev < HW_TIMER_NUMOF, -1); - CHECK_PARAM_RET (freq == HW_TIMER_FREQUENCY, -1); - CHECK_PARAM_RET (cb != NULL, -1); + assert(dev < HW_TIMER_NUMOF); + assert(freq == HW_TIMER_FREQUENCY); + assert(cb != NULL); - if (timers[dev].initialized) { + if (_timers[dev].initialized) { DEBUG("%s timer dev=%u is already initialized (used)\n", __func__, dev); return -1; } /* initialize timer data structure */ - timers[dev].initialized = true; - timers[dev].started = false; - timers[dev].isr_ctx.cb = cb; - timers[dev].isr_ctx.arg = arg; + _timers[dev].initialized = true; + _timers[dev].started = false; + _timers[dev].isr_ctx.cb = cb; + _timers[dev].isr_ctx.arg = arg; /* route all timer interrupt sources to the same level type interrupt */ - intr_matrix_set(PRO_CPU_NUM, timers_hw[dev].int_src, CPU_INUM_TIMER); + intr_matrix_set(PRO_CPU_NUM, _timers_desc[dev].int_src, CPU_INUM_TIMER); /* we have to enable therefore the interrupt here */ - xt_set_interrupt_handler(CPU_INUM_TIMER, hw_timer_handler, NULL); - xt_ints_on(BIT(CPU_INUM_TIMER)); + intr_cntrl_ll_set_int_handler(CPU_INUM_TIMER, _timer_int_handler, NULL); + intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_TIMER)); - if (dev) { - /* if dev > 0 we have to enable TMG1 module */ - periph_module_enable(PERIPH_TIMG1_MODULE); - } + /* enable TMG module */ + esp_idf_periph_module_enable(_timers_desc[dev].module); /* hardware timer configuration */ - timers_hw[dev].regs->CONFIG_REG.EN = 0; - timers_hw[dev].regs->CONFIG_REG.AUTORELOAD = 0; - timers_hw[dev].regs->CONFIG_REG.INCREASE = 1; - timers_hw[dev].regs->CONFIG_REG.DIVIDER = HW_TIMER_CLK_DIV; - timers_hw[dev].regs->CONFIG_REG.EDGE_INT_EN = 0; - timers_hw[dev].regs->CONFIG_REG.LEVEL_INT_EN = 0; - timers_hw[dev].regs->CONFIG_REG.ALARM_EN = 0; + timer_hal_init(&_timers[dev].hw, _timers_desc[dev].group, _timers_desc[dev].index); + + timer_hal_set_counter_enable(&_timers[dev].hw, false); + timer_hal_set_counter_increase(&_timers[dev].hw, true); + timer_hal_set_divider(&_timers[dev].hw, HW_TIMER_CLK_DIV); + timer_hal_set_auto_reload(&_timers[dev].hw, false); + + /* disable alarm and interrupt source */ + timer_hal_set_alarm_enable(&_timers[dev].hw, false); + timer_hal_intr_disable(&_timers[dev].hw); + timer_hal_set_level_int_enable(&_timers[dev].hw, false); + timer_hal_set_edge_int_enable(&_timers[dev].hw, false); /* start the timer */ timer_start(dev); @@ -239,47 +238,45 @@ int timer_init (tim_t dev, uint32_t freq, timer_cb_t cb, void *arg) return 0; } -int IRAM timer_set(tim_t dev, int chn, unsigned int delta) +int IRAM_ATTR timer_set(tim_t dev, int chn, unsigned int delta) { DEBUG("%s dev=%u channel=%d delta=%u\n", __func__, dev, chn, delta); - CHECK_PARAM_RET (dev < HW_TIMER_NUMOF, -1); - CHECK_PARAM_RET (chn < HW_TIMER_CHANNELS, -1); + assert(dev < HW_TIMER_NUMOF); + + if (chn >= HW_TIMER_CHANNELS) { + return -1; + } /* disable interrupts */ int state = irq_disable (); - /* disable alarms */ - timers_hw[dev].regs->CONFIG_REG.LEVEL_INT_EN = 0; - timers_hw[dev].regs->CONFIG_REG.ALARM_EN = 0; + /* disable alarms and interrupt source */ + timer_hal_set_alarm_enable(&_timers[dev].hw, false); + timer_hal_set_level_int_enable(&_timers[dev].hw, false); + timer_hal_intr_disable(&_timers[dev].hw); delta = (delta > HW_TIMER_DELTA_MIN) ? delta : HW_TIMER_DELTA_MIN; delta = (delta > HW_TIMER_CORRECTION) ? delta - HW_TIMER_CORRECTION : HW_TIMER_CORRECTION; - /* read the current value */ - uint32_t count_lo; - uint32_t count_hi; - timer_get_counter(dev, &count_hi, &count_lo); - - /* determine the alarm time */ + /* latch and read current timer value */ uint64_t alarm; - alarm = count_lo; - alarm += ((uint64_t)count_hi) << 32; - alarm += delta; + timer_hal_get_counter_value(&_timers[dev].hw, &alarm); - timers_hw[dev].regs->ALARMHI_REG = (uint32_t)(alarm >> 32); - timers_hw[dev].regs->ALARMLO_REG = (uint32_t)(alarm & 0xffffffff); + /* determine the alarm time and set the alarm */ + alarm += delta; + timer_hal_set_alarm_value(&_timers[dev].hw, alarm); - /* enable alarms */ - timers_hw[dev].regs->CONFIG_REG.LEVEL_INT_EN = 1; - timers_hw[dev].regs->CONFIG_REG.ALARM_EN = 1; + /* enable alarms and interrupt sources */ + timer_hal_set_alarm_enable(&_timers[dev].hw, true); - /* wait until instructions have been finished */ - timers_hw[dev].regs->CONFIG_REG.EN = 1; + /* clear possible pending interrupts and enable interrupt source */ + timer_hal_set_level_int_enable(&_timers[dev].hw, true); + timer_hal_intr_enable(&_timers[dev].hw); + timer_hal_clear_intr_status(&_timers[dev].hw); - /* clear the bit in status and set the bit in interrupt enable */ - timers_hw[dev].int_regs->INT_CLR_REG |= timers_hw[dev].int_mask; - timers_hw[dev].int_regs->INT_ENA_REG |= timers_hw[dev].int_mask; + /* enable the counter */ + timer_hal_set_counter_enable(&_timers[dev].hw, true); /* restore interrupts enabled state */ irq_restore (state); @@ -287,60 +284,60 @@ int IRAM timer_set(tim_t dev, int chn, unsigned int delta) return 0; } -int IRAM timer_set_absolute(tim_t dev, int chn, unsigned int value) +int IRAM_ATTR timer_set_absolute(tim_t dev, int chn, unsigned int value) { DEBUG("%s dev=%u channel=%d value=%u\n", __func__, dev, chn, value); - return timer_set (dev, chn, value - timer_read(dev)); + return timer_set(dev, chn, value - timer_read(dev)); } int timer_clear(tim_t dev, int chn) { DEBUG("%s dev=%u channel=%d\n", __func__, dev, chn); - CHECK_PARAM_RET (dev < HW_TIMER_NUMOF, -1); - CHECK_PARAM_RET (chn < HW_TIMER_CHANNELS, -1); + assert(dev < HW_TIMER_NUMOF); + + if (chn >= HW_TIMER_CHANNELS) { + return -1; + } /* disable alarms */ - timers_hw[dev].regs->CONFIG_REG.LEVEL_INT_EN = 0; - timers_hw[dev].regs->CONFIG_REG.ALARM_EN = 0; - /* clear the bit in interrupt enable and status register */ - timers_hw[dev].int_regs->INT_ENA_REG &= ~timers_hw[dev].int_mask; - timers_hw[dev].int_regs->INT_CLR_REG |= timers_hw[dev].int_mask; + timer_hal_set_alarm_enable(&_timers[dev].hw, false); + + /* disable interrupt source and clear possible pending interrupts */ + timer_hal_set_level_int_enable(&_timers[dev].hw, false); + timer_hal_intr_disable(&_timers[dev].hw); + timer_hal_clear_intr_status(&_timers[dev].hw); return 0; } -unsigned int IRAM timer_read(tim_t dev) +unsigned int IRAM_ATTR timer_read(tim_t dev) { - CHECK_PARAM_RET (dev < HW_TIMER_NUMOF, -1); + assert(dev < HW_TIMER_NUMOF); if (IS_ACTIVE(ENABLE_DEBUG)) { - uint32_t count_lo = timer_get_counter_lo(dev); - DEBUG("%s %u\n", __func__, count_lo); + uint32_t count_lo = _timer_get_counter_lo(dev); + DEBUG("%s %" PRIu32 "\n", __func__, count_lo); return count_lo; } else { - return timer_get_counter_lo(dev); + return _timer_get_counter_lo(dev); } } -void IRAM timer_start(tim_t dev) +void IRAM_ATTR timer_start(tim_t dev) { - DEBUG("%s dev=%u @%u\n", __func__, dev, system_get_time()); - - CHECK_PARAM (dev < HW_TIMER_NUMOF); - - timers_hw[dev].regs->CONFIG_REG.EN = 1; + DEBUG("%s dev=%u @%" PRIu32 "\n", __func__, dev, system_get_time()); + assert(dev < HW_TIMER_NUMOF); + timer_hal_set_counter_enable(&_timers[dev].hw, true); } -void IRAM timer_stop(tim_t dev) +void IRAM_ATTR timer_stop(tim_t dev) { DEBUG("%s dev=%u\n", __func__, dev); - - CHECK_PARAM (dev < HW_TIMER_NUMOF); - - timers_hw[dev].regs->CONFIG_REG.EN = 0; + assert(dev < HW_TIMER_NUMOF); + timer_hal_set_counter_enable(&_timers[dev].hw, false); } #else /* MODULE_ESP_HW_COUNTER */ @@ -372,8 +369,8 @@ void IRAM timer_stop(tim_t dev) #define HW_TIMER_CORRECTION (RTC_PLL_480M / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) #define HW_TIMER_DELTA_MIN (MAX(HW_TIMER_CORRECTION, 5)) -#define US_TO_HW_TIMER_TICKS(t) (t * system_get_cpu_freq()) -#define HW_TIMER_TICKS_TO_US(t) (t / system_get_cpu_freq()) +#define US_TO_HW_TIMER_TICKS(t) (t * system_get_cpu_freq()) +#define HW_TIMER_TICKS_TO_US(t) (t / system_get_cpu_freq()) struct hw_channel_t { bool used; /* indicates whether the channel is used */ @@ -383,7 +380,7 @@ struct hw_channel_t { uint32_t remainder; /* remainder timer value */ }; -struct hw_timer_t { +struct _hw_timer_t { tim_t dev; /* the timer device num */ bool initialized; /* indicates whether timer is already initialized */ bool started; /* indicates whether timer is already started */ @@ -391,16 +388,16 @@ struct hw_timer_t { struct hw_channel_t channels[HW_TIMER_CHANNELS]; }; -static struct hw_timer_t timers[HW_TIMER_NUMOF] = { }; +static struct _hw_timer_t _timers[HW_TIMER_NUMOF] = { }; static const uint8_t timers_int[HW_TIMER_NUMOF] = { XCHAL_TIMER0_INTERRUPT, XCHAL_TIMER1_INTERRUPT, XCHAL_TIMER2_INTERRUPT }; -static void __timer_channel_start (struct hw_timer_t* timer, struct hw_channel_t* channel); -static void __timer_channel_stop (struct hw_timer_t* timer, struct hw_channel_t* channel); +static void __timer_channel_start (struct _hw_timer_t* timer, struct hw_channel_t* channel); +static void __timer_channel_stop (struct _hw_timer_t* timer, struct hw_channel_t* channel); -static uint32_t __hw_timer_ticks_max; -static uint32_t __hw_timer_ticks_min; +static uint32_t ___hw_timer_ticks_max; +static uint32_t ___hw_timer_ticks_min; void IRAM hw_timer_handler(void* arg) { @@ -415,12 +412,12 @@ void IRAM hw_timer_handler(void* arg) DEBUG("%s arg=%p\n", __func__, arg); - struct hw_timer_t* timer = &timers[dev]; + struct _hw_timer_t* timer = &_timers[dev]; struct hw_channel_t* channel = &timer->channels[chn]; if (channel->cycles) { channel->cycles--; - xthal_set_ccompare(dev, xthal_get_ccount() + __hw_timer_ticks_max); + xthal_set_ccompare(dev, xthal_get_ccount() + ___hw_timer_ticks_max); } else if (channel->remainder >= HW_TIMER_DELTA_MIN) { xthal_set_ccompare (dev, xthal_get_ccount() + @@ -446,23 +443,23 @@ int timer_init (tim_t dev, uint32_t freq, timer_cb_t cb, void *arg) CHECK_PARAM_RET (freq == HW_TIMER_FREQUENCY, -1); CHECK_PARAM_RET (cb != NULL, -1); - if (timers[dev].initialized) { + if (_timers[dev].initialized) { DEBUG("%s timer dev=%u is already initialized (used)\n", __func__, dev); return -1; } - timers[dev].dev = dev; - timers[dev].initialized = true; - timers[dev].started = false; - timers[dev].isr_ctx.cb = cb; - timers[dev].isr_ctx.arg = arg; + _timers[dev].dev = dev; + _timers[dev].initialized = true; + _timers[dev].started = false; + _timers[dev].isr_ctx.cb = cb; + _timers[dev].isr_ctx.arg = arg; xt_set_interrupt_handler(timers_int[dev], hw_timer_handler, (void *)dev); for (int i = 0; i < HW_TIMER_CHANNELS; i++) { - timers[dev].channels[i].used = false; - timers[dev].channels[i].cycles = 0; - timers[dev].channels[i].remainder = 0; + _timers[dev].channels[i].used = false; + _timers[dev].channels[i].cycles = 0; + _timers[dev].channels[i].remainder = 0; } timer_start(dev); @@ -479,7 +476,7 @@ int IRAM timer_set(tim_t dev, int chn, unsigned int delta) int state = irq_disable (); - struct hw_timer_t* timer = &timers[dev]; + struct _hw_timer_t* timer = &_timers[dev]; struct hw_channel_t* channel = &timer->channels[chn]; /* set delta time and channel used flag */ @@ -510,7 +507,7 @@ int timer_clear(tim_t dev, int chn) int state = irq_disable (); /* stop running timer channel */ - __timer_channel_stop (&timers[dev], &timers[dev].channels[chn]); + __timer_channel_stop (&_timers[dev], &_timers[dev].channels[chn]); irq_restore (state); @@ -529,14 +526,14 @@ void IRAM timer_start(tim_t dev) DEBUG("%s dev=%u @%u\n", __func__, dev, system_get_time()); CHECK_PARAM (dev < HW_TIMER_NUMOF); - CHECK_PARAM (!timers[dev].started); + CHECK_PARAM (!_timers[dev].started); int state = irq_disable (); - __hw_timer_ticks_max = US_TO_HW_TIMER_TICKS(HW_TIMER_DELTA_MAX); - __hw_timer_ticks_min = US_TO_HW_TIMER_TICKS(HW_TIMER_DELTA_MIN); + ___hw_timer_ticks_max = US_TO_HW_TIMER_TICKS(HW_TIMER_DELTA_MAX); + ___hw_timer_ticks_min = US_TO_HW_TIMER_TICKS(HW_TIMER_DELTA_MIN); - struct hw_timer_t* timer = &timers[dev]; + struct _hw_timer_t* timer = &_timers[dev]; timer->started = true; @@ -555,7 +552,7 @@ void IRAM timer_stop(tim_t dev) int state = irq_disable (); - struct hw_timer_t* timer = &timers[dev]; + struct _hw_timer_t* timer = &_timers[dev]; timer->started = false; @@ -566,7 +563,7 @@ void IRAM timer_stop(tim_t dev) irq_restore (state); } -static void IRAM __timer_channel_start (struct hw_timer_t* timer, struct hw_channel_t* channel) +static void IRAM __timer_channel_start (struct _hw_timer_t* timer, struct hw_channel_t* channel) { if (!timer->started || !channel->used) { return; @@ -583,7 +580,7 @@ static void IRAM __timer_channel_start (struct hw_timer_t* timer, struct hw_chan /* start timer either with full cycles, remaining or minimum time */ if (channel->cycles) { channel->cycles--; - xthal_set_ccompare(timer->dev, xthal_get_ccount() + __hw_timer_ticks_max); + xthal_set_ccompare(timer->dev, xthal_get_ccount() + ___hw_timer_ticks_max); } else if (channel->remainder > HW_TIMER_DELTA_MIN) { xthal_set_ccompare(timer->dev, xthal_get_ccount() + @@ -592,13 +589,13 @@ static void IRAM __timer_channel_start (struct hw_timer_t* timer, struct hw_chan } else { channel->remainder = 0; - xthal_set_ccompare(timer->dev, xthal_get_ccount() + __hw_timer_ticks_min); + xthal_set_ccompare(timer->dev, xthal_get_ccount() + ___hw_timer_ticks_min); } xt_ints_on(BIT(timers_int[timer->dev])); } -static void IRAM __timer_channel_stop (struct hw_timer_t* timer, struct hw_channel_t* channel) +static void IRAM __timer_channel_stop (struct _hw_timer_t* timer, struct hw_channel_t* channel) { if (!channel->used) { return; From 8de78cca14ff736985fc6e455d861fe535e3fb46 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 10 Mar 2022 07:35:47 +0100 Subject: [PATCH 30/46] cpu/esp_common: inverse MCU_* conditionals to deal with ESP32 variants The MCU_* conditionals are inverted so that they can be tested for ESP8266. In all other cases the MCU is any ESP32x SoC --- cpu/esp_common/periph/uart.c | 166 +++++++++++++++++++++-------------- 1 file changed, 98 insertions(+), 68 deletions(-) diff --git a/cpu/esp_common/periph/uart.c b/cpu/esp_common/periph/uart.c index 1367bae82cf5..02cb96140794 100644 --- a/cpu/esp_common/periph/uart.c +++ b/cpu/esp_common/periph/uart.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2022 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 @@ -35,26 +35,16 @@ #include "esp/common_macros.h" #include "rom/ets_sys.h" -#include "xtensa/xtensa_api.h" #include "gpio_arch.h" +#if __xtensa__ +#include "xtensa/xtensa_api.h" +#endif + #define ENABLE_DEBUG 0 #include "debug.h" -#ifdef MCU_ESP32 - -#include "driver/periph_ctrl.h" -#include "soc/gpio_reg.h" -#include "soc/gpio_sig_map.h" -#include "soc/gpio_struct.h" -#include "soc/rtc.h" -#include "soc/uart_reg.h" -#include "soc/uart_struct.h" - -#undef UART_CLK_FREQ -#define UART_CLK_FREQ rtc_clk_apb_freq_get() /* APB_CLK is used */ - -#else /* MCU_ESP32 */ +#if defined(MCU_ESP8266) #include "esp/iomux_regs.h" #include "esp8266/uart_struct.h" @@ -67,7 +57,24 @@ #define UART1 uart1 #define CPU_INUM_UART ETS_UART_INUM -#endif /* MCU_ESP32 */ +#else /* defined(MCU_ESP8266) */ + +#include "hal/interrupt_controller_types.h" +#include "hal/interrupt_controller_ll.h" +#include "soc/gpio_reg.h" +#include "soc/gpio_sig_map.h" +#include "soc/gpio_struct.h" +#include "soc/periph_defs.h" +#include "soc/rtc.h" +#include "soc/uart_reg.h" +#include "soc/uart_struct.h" + +#include "esp_idf_api/periph_ctrl.h" + +#undef UART_CLK_FREQ +#define UART_CLK_FREQ rtc_clk_apb_freq_get() /* APB_CLK is used */ + +#endif /* defined(MCU_ESP8266) */ struct uart_hw_t { uart_dev_t* regs; /* pointer to register data struct of the UART device */ @@ -77,7 +84,7 @@ struct uart_hw_t { uart_stop_bits_t stop; /* used stop bits */ uart_parity_t parity; /* used parity bits */ uart_isr_ctx_t isr_ctx; /* callback functions */ -#ifdef MCU_ESP32 +#if !defined(MCU_ESP8266) uint8_t mod; /* peripheral hardware module of the UART interface */ uint8_t signal_txd; /* TxD signal from the controller */ uint8_t signal_rxd; /* RxD signal to the controller */ @@ -94,14 +101,14 @@ static struct uart_hw_t _uarts[] = { .data = UART_DATA_BITS_8, .stop = UART_STOP_BITS_1, .parity = UART_PARITY_NONE, -#ifdef MCU_ESP32 +#if !defined(MCU_ESP8266) .mod = PERIPH_UART0_MODULE, .signal_txd = U0TXD_OUT_IDX, .signal_rxd = U0RXD_IN_IDX, .int_src = ETS_UART0_INTR_SOURCE -#endif /* MCU_ESP32 */ +#endif /* !MCU_ESP8266 */ }, -#if defined(UART1_TXD) || defined(MCU_ESP32) +#if defined(UART1_TXD) || !defined(MCU_ESP8266) { .regs = &UART1, .used = false, @@ -109,15 +116,15 @@ static struct uart_hw_t _uarts[] = { .data = UART_DATA_BITS_8, .stop = UART_STOP_BITS_1, .parity = UART_PARITY_NONE, -#ifdef MCU_ESP32 +#if !defined(MCU_ESP8266) .mod = PERIPH_UART1_MODULE, .signal_txd = U1TXD_OUT_IDX, .signal_rxd = U1RXD_IN_IDX, .int_src = ETS_UART1_INTR_SOURCE -#endif /* MCU_ESP32 */ +#endif /* !MCU_ESP8266 */ }, -#endif /* defined(UART1_TXD) || defined(MCU_ESP32) */ -#ifdef MCU_ESP32 +#endif /* defined(UART1_TXD) || !defined(MCU_ESP8266) */ +#if defined(MCU_ESP32) { .regs = &UART2, .used = false, @@ -130,7 +137,7 @@ static struct uart_hw_t _uarts[] = { .signal_rxd = U2RXD_IN_IDX, .int_src = ETS_UART2_INTR_SOURCE }, -#endif /* MCU_ESP32 */ +#endif /* defined(MCU_ESP32) */ }; /* declaration of external functions */ @@ -148,7 +155,8 @@ static void IRAM _uart_intr_handler(void *para); int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) { - DEBUG("%s uart=%d, rate=%d, rx_cb=%p, arg=%p\n", __func__, uart, baudrate, rx_cb, arg); + DEBUG("%s uart=%d, rate=%" PRIu32 ", rx_cb=%p, arg=%p\n", __func__, + uart, baudrate, rx_cb, arg); assert(uart < UART_NUMOF_MAX); assert(uart < UART_NUMOF); @@ -177,15 +185,7 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) gpio_set_pin_usage(uart_config[uart].txd, _UART); gpio_set_pin_usage(uart_config[uart].rxd, _UART); -#ifdef MCU_ESP32 - /* connect TxD pin to the TxD output signal through the GPIO matrix */ - GPIO.func_out_sel_cfg[uart_config[uart].txd].func_sel = _uarts[uart].signal_txd; - - /* connect RxD input signal to the RxD pin through the GPIO matrix */ - GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].sig_in_sel = 1; - GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].sig_in_inv = 0; - GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].func_sel = uart_config[uart].rxd; -#else +#ifdef MCU_ESP8266 if (uart_config[uart].txd != GPIO_UNDEF) { uint8_t mux = _gpio_to_iomux[uart_config[uart].txd]; IOMUX.PIN[mux] = (IOMUX.PIN[mux] & ~IOMUX_PIN_FUNC_MASK) | @@ -198,7 +198,15 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) IOMUX.PIN[mux] = (IOMUX.PIN[mux] & ~IOMUX_PIN_FUNC_MASK) | IOMUX_FUNC(4); } -#endif +#else /* MCU_ESP8266 */ + /* connect TxD pin to the TxD output signal through the GPIO matrix */ + GPIO.func_out_sel_cfg[uart_config[uart].txd].func_sel = _uarts[uart].signal_txd; + + /* connect RxD input signal to the RxD pin through the GPIO matrix */ + GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].sig_in_sel = 1; + GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].sig_in_inv = 0; + GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].func_sel = uart_config[uart].rxd; +#endif /* MCU_ESP8266 */ } _uarts[uart].baudrate = baudrate; @@ -233,8 +241,8 @@ void uart_poweron(uart_t uart) { assert(uart < UART_NUMOF); -#ifdef MCU_ESP32 - periph_module_enable(_uarts[uart].mod); +#ifndef MCU_ESP8266 + esp_idf_periph_module_enable(_uarts[uart].mod); #endif _uart_config(uart); } @@ -243,8 +251,8 @@ void uart_poweroff(uart_t uart) { assert(uart < UART_NUMOF); -#ifdef MCU_ESP32 - periph_module_disable(_uarts[uart].mod); +#ifndef MCU_ESP8266 + esp_idf_periph_module_disable(_uarts[uart].mod); #endif } @@ -260,7 +268,7 @@ void uart_system_init(void) void uart_print_config(void) { for (unsigned uart = 0; uart < UART_NUMOF; uart++) { - printf("\tUART_DEV(%u)\ttxd=%d rxd=%d\n", uart, + printf("\tUART_DEV(%" PRIu32 ")\ttxd=%d rxd=%d\n", (uint32_t)uart, uart_config[uart].txd, uart_config[uart].rxd); } } @@ -277,7 +285,7 @@ static void IRAM _uart_intr_handler(void *arg) for (unsigned uart = 0; uart < UART_NUMOF; uart++) { if (_uarts[uart].used) { DEBUG("%s uart=%d int_st=%08x\n", __func__, - uart, _uarts[uart].regs->int_st.val); + uart, (unsigned)_uarts[uart].regs->int_st.val); if (_uarts[uart].used && _uarts[uart].regs->int_st.rxfifo_full) { /* read one byte of data */ @@ -314,8 +322,13 @@ static uint8_t IRAM _uart_rx_one_char(uart_t uart) /* wait until at least von byte is in RX FIFO */ while (!_uarts[uart].regs->status.rxfifo_cnt) {} +#if defined(MCU_ESP32) || defined(MCU_ESP8266) /* read the lowest byte from RX FIFO register */ return _uarts[uart].regs->fifo.rw_byte; +#else + /* read the lowest byte from RX FIFO register */ + return _uarts[uart].regs->ahb_fifo.rw_byte; +#endif #endif } @@ -327,15 +340,15 @@ static void _uart_tx_one_char(uart_t uart, uint8_t data) while (_uarts[uart].regs->status.txfifo_cnt >= UART_FIFO_MAX) {} /* send the byte by placing it in the TX FIFO using MPU */ -#ifdef MCU_ESP32 - WRITE_PERI_REG(UART_FIFO_AHB_REG(uart), data); -#else /* MCU_ESP32 */ +#ifdef MCU_ESP8266 #ifdef MODULE_ESP_QEMU UART(uart).FIFO = data; #else /* MODULE_ESP_QEMU */ _uarts[uart].regs->fifo.rw_byte = data; #endif /* MODULE_ESP_QEMU */ -#endif /* MCU_ESP32 */ +#else /* MCU_ESP8266 */ + WRITE_PERI_REG(UART_FIFO_AHB_REG(uart), data); +#endif /* MCU_ESP8266 */ } static void _uart_intr_enable(uart_t uart) @@ -344,7 +357,7 @@ static void _uart_intr_enable(uart_t uart) _uarts[uart].regs->int_clr.rxfifo_full = 1; _uarts[uart].used = true; - DEBUG("%s %08x\n", __func__, _uarts[uart].regs->int_ena.val); + DEBUG("%s %08x\n", __func__, (unsigned)_uarts[uart].regs->int_ena.val); } static void _uart_config(uart_t uart) @@ -376,20 +389,27 @@ static void _uart_config(uart_t uart) /* enable the RX FIFO FULL interrupt */ _uart_intr_enable(uart); -#ifdef MCU_ESP32 - /* route all UART interrupt sources to same the CPU interrupt */ - intr_matrix_set(PRO_CPU_NUM, _uarts[uart].int_src, CPU_INUM_UART); -#endif /* MCU_ESP32 */ - +#ifdef MCU_ESP8266 /* we have to enable therefore the CPU interrupt here */ xt_set_interrupt_handler(CPU_INUM_UART, _uart_intr_handler, NULL); xt_ints_on(BIT(CPU_INUM_UART)); +#else /* MCU_ESP8266 */ + /* route all UART interrupt sources to same the CPU interrupt */ + intr_matrix_set(PRO_CPU_NUM, _uarts[uart].int_src, CPU_INUM_UART); + /* we have to enable therefore the CPU interrupt here */ + intr_cntrl_ll_set_int_handler(CPU_INUM_UART, _uart_intr_handler, NULL); + intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_UART)); +#ifdef SOC_CPU_HAS_FLEXIBLE_INTC + /* set interrupt level */ + intr_cntrl_ll_set_int_level(CPU_INUM_UART, 1); +#endif +#endif /* MCU_ESP8266 */ } } static int _uart_set_baudrate(uart_t uart, uint32_t baudrate) { - DEBUG("%s uart=%d, rate=%d\n", __func__, uart, baudrate); + DEBUG("%s uart=%d, rate=%" PRIu32 "\n", __func__, uart, baudrate); assert(uart < UART_NUMOF); @@ -400,17 +420,27 @@ static int _uart_set_baudrate(uart_t uart, uint32_t baudrate) _uarts[uart].baudrate = baudrate; +#ifdef MCU_ESP8266 + + /* compute and set clock divider */ + uint32_t clk_div = UART_CLK_FREQ / _uarts[uart].baudrate; + _uarts[uart].regs->clk_div.val = clk_div & 0xFFFFF; + +#else + +/* TODO look for an HAL/LL API function */ #ifdef MCU_ESP32 /* use APB_CLK */ _uarts[uart].regs->conf0.tick_ref_always_on = 1; +#endif +#ifdef MCU_ESP32C3 + _uarts[uart].regs->clk_conf.sclk_sel = 1; /* APB clock used instead of XTAL */ +#endif /* compute and set the integral and the decimal part */ uint32_t clk_div = (UART_CLK_FREQ << 4) / _uarts[uart].baudrate; _uarts[uart].regs->clk_div.div_int = clk_div >> 4; _uarts[uart].regs->clk_div.div_frag = clk_div & 0xf; -#else - /* compute and set clock divider */ - uint32_t clk_div = UART_CLK_FREQ / _uarts[uart].baudrate; - _uarts[uart].regs->clk_div.val = clk_div & 0xFFFFF; + #endif critical_exit(); @@ -442,7 +472,15 @@ static int _uart_set_mode(uart_t uart, uart_data_bits_t data_bits, _uarts[uart].data = data_bits; /* set number of stop bits */ - #ifdef MCU_ESP32 +#ifdef MCU_ESP8266 + switch (stop_bits) { + case UART_STOP_BITS_1: _uarts[uart].regs->conf0.stop_bit_num = 1; break; + case UART_STOP_BITS_2: _uarts[uart].regs->conf0.stop_bit_num = 3; break; + default: LOG_TAG_ERROR("uart", "invalid number of stop bits\n"); + critical_exit(); + return UART_NOMODE; + } +#else /* workaround for hardware bug when stop bits are set to 2-bit mode. */ switch (stop_bits) { case UART_STOP_BITS_1: _uarts[uart].regs->conf0.stop_bit_num = 1; @@ -455,15 +493,7 @@ static int _uart_set_mode(uart_t uart, uart_data_bits_t data_bits, critical_exit(); return UART_NOMODE; } - #else - switch (stop_bits) { - case UART_STOP_BITS_1: _uarts[uart].regs->conf0.stop_bit_num = 1; break; - case UART_STOP_BITS_2: _uarts[uart].regs->conf0.stop_bit_num = 3; break; - default: LOG_TAG_ERROR("uart", "invalid number of stop bits\n"); - critical_exit(); - return UART_NOMODE; - } - #endif +#endif /* store changed number of stop bits in configuration */ _uarts[uart].stop = stop_bits; From 19114f16f375855c1e1324823c0a8928843dcf08 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 10 Mar 2022 07:43:34 +0100 Subject: [PATCH 31/46] cpu/esp32: periph/uart port to ESP-IDF uart HAL --- cpu/esp32/esp-idf-api/uart.c | 5 ++--- cpu/esp32/include/periph_cpu.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cpu/esp32/esp-idf-api/uart.c b/cpu/esp32/esp-idf-api/uart.c index 143bb41c698b..1d73617601c6 100644 --- a/cpu/esp32/esp-idf-api/uart.c +++ b/cpu/esp32/esp-idf-api/uart.c @@ -36,7 +36,7 @@ static uart_hal_context_t _uart_hal_ctx[] = { .dev = UART_LL_GET_HW(1), }, #endif -#if UART_NUM_MAX >= 3 +#if UART_NUM_MAX >= 3 { .dev = UART_LL_GET_HW(2), }, @@ -45,7 +45,6 @@ static uart_hal_context_t _uart_hal_ctx[] = { void esp_idf_uart_set_wakeup_threshold(unsigned uart_num, uint32_t threshold) { - assert(uart_num < sizeof(_uart_hal_ctx)/sizeof(_uart_hal_ctx[0])); + assert(uart_num < ARRAY_SIZE(_uart_hal_ctx)); uart_hal_set_wakeup_thrd(&_uart_hal_ctx[uart_num], threshold); } - diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index 893876dfbf6f..b9c2faeb7c96 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -607,7 +607,7 @@ typedef struct { /** * @brief Maximum number of UART interfaces */ -#define UART_NUMOF_MAX (3) +#define UART_NUMOF_MAX (SOC_UART_NUM) /** @} */ #ifdef MODULE_PERIPH_CAN From 25017e11064d1364325ca4ea370fe3aac4c6ed8c Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 10 Mar 2022 07:45:20 +0100 Subject: [PATCH 32/46] cpu/esp32: DEBUG messages with portable formatting --- cpu/esp32/esp_ztimer.c | 2 +- cpu/esp32/periph/rtt.c | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/cpu/esp32/esp_ztimer.c b/cpu/esp32/esp_ztimer.c index b64d2d8c60c9..5187fc3d8ea7 100644 --- a/cpu/esp32/esp_ztimer.c +++ b/cpu/esp32/esp_ztimer.c @@ -141,7 +141,7 @@ void ets_timer_done(ETSTimer *ptimer) void ets_timer_arm_us(ETSTimer *timer, uint32_t tmout, bool repeat) { - DEBUG("%s timer=%p tmout=%u repeat=%d\n", __func__, timer, tmout, repeat); + DEBUG("%s timer=%p tmout=%"PRIu32" repeat=%d\n", __func__, timer, tmout, repeat); struct _ets_to_ztimer* e2xt = _ets_to_ztimer_get(timer); diff --git a/cpu/esp32/periph/rtt.c b/cpu/esp32/periph/rtt.c index 1d9165d8379c..fac348177dc2 100644 --- a/cpu/esp32/periph/rtt.c +++ b/cpu/esp32/periph/rtt.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Gunar Schorcht + * Copyright (C) 2022 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 @@ -82,7 +82,8 @@ void rtt_init(void) } } - DEBUG("%s rtt_offset=%u @rtc=%llu rtc_active=%d @sys_time=%llu\n", __func__, + DEBUG("%s rtt_offset=%" PRIu32 " @rtc=%" PRIu64 + " rtc_active=%d @sys_time=%" PRIi64 "\n", __func__, _rtt_offset, _rtc_get_counter(), (_rtt_hw == &_rtt_hw_sys_driver) ? 1 : 0, system_get_time_64()); @@ -132,7 +133,8 @@ uint32_t rtt_get_counter(void) { /* we use only the lower 32 bit of the 48-bit RTC counter */ uint32_t counter = _rtt_hw->get_counter() + _rtt_offset; - DEBUG("%s counter=%u @sys_time=%u\n", __func__, counter, system_get_time()); + DEBUG("%s counter=%" PRIu32 " @sys_time=%" PRIu32" \n", + __func__, counter, system_get_time()); return counter; } @@ -141,7 +143,7 @@ void rtt_set_counter(uint32_t counter) uint32_t _rtt_current = _rtt_hw->get_counter(); _rtt_offset = counter - _rtt_current; - DEBUG("%s set=%u rtt_offset=%u @rtt=%u\n", + DEBUG("%s set=%" PRIu32 " rtt_offset=%" PRIu32 " @rtt=%" PRIu32 "\n", __func__, counter, _rtt_offset, _rtt_current); _rtt_update_hw_alarm(); @@ -154,7 +156,7 @@ void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) rtt_counter.alarm_cb = cb; rtt_counter.alarm_arg = arg; - DEBUG("%s alarm=%u @rtt=%u\n", __func__, alarm, counter); + DEBUG("%s alarm=%" PRIu32 " @rtt=%" PRIu32 "\n", __func__, alarm, counter); _rtt_update_hw_alarm(); } @@ -166,7 +168,7 @@ void rtt_clear_alarm(void) rtt_counter.alarm_cb = NULL; rtt_counter.alarm_arg = NULL; - DEBUG("%s @rtt=%u\n", __func__, (uint32_t)_rtt_hw->get_counter()); + DEBUG("%s @rtt=%" PRIu32 "\n", __func__, (uint32_t)_rtt_hw->get_counter()); _rtt_update_hw_alarm(); } @@ -197,7 +199,7 @@ uint64_t rtt_pm_sleep_enter(unsigned mode) uint32_t counter = rtt_get_counter(); uint64_t t_diff = RTT_TICKS_TO_US(rtt_counter.alarm_active - counter); - DEBUG("%s rtt_alarm=%u @rtt=%u t_diff=%llu\n", __func__, + DEBUG("%s rtt_alarm=%" PRIu32 " @rtt=%" PRIu32 " t_diff=%llu\n", __func__, rtt_counter.alarm_active, counter, t_diff); if (t_diff) { @@ -250,7 +252,7 @@ static void IRAM_ATTR _rtt_isr(void *arg) if (rtt_counter.wakeup) { rtt_counter.wakeup = false; - DEBUG("%s wakeup alarm alarm=%u rtt_alarm=%u @rtt=%u\n", + DEBUG("%s wakeup alarm alarm=%" PRIu32 " rtt_alarm=%" PRIu32 " @rtt=%" PRIu32 "\n", __func__, alarm, rtt_counter.alarm_active, rtt_get_counter()); } @@ -276,7 +278,7 @@ static void IRAM_ATTR _rtt_isr(void *arg) } } - DEBUG("%s next rtt=%u\n", __func__, rtt_counter.alarm_active); + DEBUG("%s next rtt=%" PRIu32 "\n", __func__, rtt_counter.alarm_active); } uint32_t _rtt_hw_to_rtt_counter(uint32_t hw_counter) From b3142a447e4ca8a2dc42f6132a755142f71d83f5 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 10 Mar 2022 08:06:12 +0100 Subject: [PATCH 33/46] cpu/esp_common: conditional Xtensa code In preparation for porting to other ESP32x SoCs, some of which use the RISC-V architecture, the Xtensa architecture-specific code is compiled only conditionally. --- cpu/esp_common/exceptions.c | 4 + cpu/esp_common/periph/i2c_sw.c | 7 ++ cpu/esp_common/thread_arch.c | 137 +++++++++++++++++---------------- 3 files changed, 81 insertions(+), 67 deletions(-) diff --git a/cpu/esp_common/exceptions.c b/cpu/esp_common/exceptions.c index 8287714b5d1a..1fd0b146510d 100644 --- a/cpu/esp_common/exceptions.c +++ b/cpu/esp_common/exceptions.c @@ -17,6 +17,8 @@ * @} */ +#if __xtensa__ + #include #include #include @@ -216,3 +218,5 @@ void _panic_handler(uint32_t addr) pm_off(); while (1) { }; } + +#endif /* __xtensa__ */ diff --git a/cpu/esp_common/periph/i2c_sw.c b/cpu/esp_common/periph/i2c_sw.c index 791c98b5911a..199a00010500 100644 --- a/cpu/esp_common/periph/i2c_sw.c +++ b/cpu/esp_common/periph/i2c_sw.c @@ -418,8 +418,15 @@ static inline void _i2c_delay(_i2c_bus_t* bus) /* produces a delay */ uint32_t cycles = bus->delay; if (cycles) { +#if __xtensa__ __asm__ volatile ("1: _addi.n %0, %0, -1 \n" " bnez %0, 1b \n" : "=r" (cycles) : "0" (cycles)); +#endif +#if __riscv + uint32_t zero = 0; + __asm__ volatile ("1: add %0, %0, -1 \n" + " bne %0, %2, 1b \n" : "=r" (cycles) : "0" (cycles), "r" (zero)); +#endif } } diff --git a/cpu/esp_common/thread_arch.c b/cpu/esp_common/thread_arch.c index ec76da981f74..27c006b570f2 100644 --- a/cpu/esp_common/thread_arch.c +++ b/cpu/esp_common/thread_arch.c @@ -61,22 +61,24 @@ #include "tools.h" #include "esp_attr.h" -#include "esp/xtensa_ops.h" #include "rom/ets_sys.h" -#ifdef MCU_ESP32 +#if defined(MCU_ESP32) #include "soc/dport_access.h" #include "soc/dport_reg.h" -#else /* MCU_ESP32 */ +#elif defined(MCU_ESP8266) #include "esp8266/rom_functions.h" #include "sdk/sdk.h" #endif /* MCU_ESP32 */ -#include "xtensa/xtensa_context.h" - #define ENABLE_DEBUG 0 #include "debug.h" +#if __xtensa__ + +#include "esp/xtensa_ops.h" +#include "xtensa/xtensa_context.h" + /* User exception dispatcher when exiting */ extern void _xt_user_exit(void); @@ -315,7 +317,6 @@ void thread_stack_print(void) #if defined(DEVELHELP) thread_t* task = thread_get_active(); if (task) { - char* stack_top = task->stack_start + task->stack_size; int size = stack_top - task->sp; printf("Printing current stack of thread %" PRIkernel_pid "\n", thread_getpid()); @@ -334,67 +335,6 @@ void thread_print_stack(void) return; } -#ifdef DEVELHELP - -extern uint8_t port_IntStack; -extern uint8_t port_IntStackTop; - -void thread_isr_stack_init(void) -{ - /* code from thread.c, please see the copyright notice there */ -#ifdef MCU_ESP32 - #define sp (&port_IntStackTop) -#else /* MCU_ESP32 */ - register uint32_t *sp __asm__ ("a1"); -#endif /* MCU_ESP32 */ - - /* assign each int of the stack the value of it's address. We can safely - * cast, as stack is aligned. Use an intermediate cast to uintptr_t to - * silence -Wcast-align false positive */ - uintptr_t *stackmax = (uintptr_t *)(uintptr_t)sp; - uintptr_t *stackp = (uintptr_t *)(uintptr_t)&port_IntStack; - - /* cppcheck-suppress comparePointers */ - while (stackp < stackmax) { - *stackp = (uintptr_t) stackp; - stackp++; - } -} - -int thread_isr_stack_usage(void) -{ - /* cppcheck-suppress comparePointers - * (reason: comes from ESP-SDK, so should be valid) */ - return &port_IntStackTop - &port_IntStack - - thread_measure_stack_free((char*)&port_IntStack); -} - -void *thread_isr_stack_pointer(void) -{ - /* Get the current ISR stack pointer. */ - return &port_IntStackTop; -} - -void *thread_isr_stack_start(void) -{ - /* Get the start of the ISR stack. */ - return &port_IntStack; -} - -void thread_isr_stack_print(void) -{ - printf("Printing current ISR\n"); - /* cppcheck-suppress comparePointers - * (reason: comes from ESP-SDK, so should be valid) */ - esp_hexdump(&port_IntStack, &port_IntStackTop-&port_IntStack, 'w', 8); -} - -#else /* DEVELHELP */ - -void thread_isr_stack_init(void) {} - -#endif /* DEVELHELP */ - #ifndef __XTENSA_CALL0_ABI__ static bool _initial_exit = true; #endif /* __XTENSA_CALL0_ABI__ */ @@ -465,3 +405,66 @@ NORETURN void task_exit(void) UNREACHABLE(); } #endif /* __XTENSA_CALL0_ABI__ */ +#endif /* __xtensa__ */ + +#ifdef DEVELHELP + +extern uint8_t port_IntStack; +extern uint8_t port_IntStackTop; + +void thread_isr_stack_init(void) +{ + /* code from thread.c, please see the copyright notice there */ +#ifndef MCU_ESP8266 + #define sp (&port_IntStackTop) +#else /* !MCU_ESP8266 */ + register uint32_t *sp __asm__ ("a1"); +#endif /* !MCU_ESP8266 */ + + /* assign each int of the stack the value of it's address. We can safely + * cast, as stack is aligned. Use an intermediate cast to uintptr_t to + * silence -Wcast-align false positive */ + uintptr_t *stackmax = (uintptr_t *)(uintptr_t)sp; + uintptr_t *stackp = (uintptr_t *)(uintptr_t)&port_IntStack; + + /* cppcheck-suppress comparePointers */ + while (stackp < stackmax) { + *stackp = (uintptr_t) stackp; + stackp++; + } +} + +int thread_isr_stack_usage(void) +{ + /* cppcheck-suppress comparePointers + * (reason: comes from ESP-SDK, so should be valid) */ + return &port_IntStackTop - &port_IntStack - + thread_measure_stack_free((char*)&port_IntStack); +} + +void *thread_isr_stack_pointer(void) +{ + /* Get the current ISR stack pointer. */ + return &port_IntStackTop; +} + +void *thread_isr_stack_start(void) +{ + /* Get the start of the ISR stack. */ + return &port_IntStack; +} + +void thread_isr_stack_print(void) +{ + printf("Printing current ISR stack\n"); + /* cppcheck-suppress comparePointers + * (reason: comes from ESP-SDK, so should be valid) */ + esp_hexdump(&port_IntStack, &port_IntStackTop-&port_IntStack, 'w', 8); +} + + +#else /* DEVELHELP */ + +void thread_isr_stack_init(void) {} + +#endif /* DEVELHELP */ From bc724a00592fc3b899d2e1acb18a8757334a9b30 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 10 Mar 2022 07:57:50 +0100 Subject: [PATCH 34/46] cpu/esp_common: calculated delays in periph/i2c_sw Fixed delay values are replaced by calculated delays measured in CPU cycles in I2C software implementation. The advantage is that for each ESP SoC only a clock calibration offset has to be specified. The delay measured in CPU cycles are then then derived from current CPU frequency for the given bus speed. The disadvantage is that the calculated delays are not as precise as the predefined fixed delays. --- cpu/esp_common/periph/i2c_sw.c | 106 ++++++++++++++++----------------- 1 file changed, 50 insertions(+), 56 deletions(-) diff --git a/cpu/esp_common/periph/i2c_sw.c b/cpu/esp_common/periph/i2c_sw.c index 199a00010500..1690bda77a3f 100644 --- a/cpu/esp_common/periph/i2c_sw.c +++ b/cpu/esp_common/periph/i2c_sw.c @@ -12,7 +12,7 @@ * @{ * * @file - * @brief Low-level I2C driver software implementation using for ESP SoCs + * @brief Low-level I2C driver software implementation for ESP SoCs * * @author Gunar Schorcht * @@ -35,6 +35,7 @@ #include "cpu.h" #include "log.h" +#include "macros/units.h" #include "mutex.h" #include "periph_conf.h" #include "periph/gpio.h" @@ -42,11 +43,15 @@ #include "esp_attr.h" #include "esp_common.h" +#if !defined(MCU_ESP8266) +#include "esp_private/esp_clk.h" +#endif #include "gpio_arch.h" #include "rom/ets_sys.h" #ifndef MCU_ESP8266 +#include "hal/cpu_hal.h" #include "soc/gpio_reg.h" #include "soc/gpio_struct.h" @@ -104,38 +109,21 @@ static _i2c_bus_t _i2c_bus[I2C_NUMOF] = {}; /* to ensure that I2C is always optimized with -O2 to use the defined delays */ #pragma GCC optimize ("O2") -#ifdef MCU_ESP32 -static const uint32_t _i2c_delays[][5] = -{ - /* values specify one half-period and are only valid for -O2 option */ - /* value = [period - 0.25 us (240 MHz) / 0.5us(160MHz) / 1.0us(80MHz)] */ - /* * cycles per second / 2 */ - /* 1 us = 16 cycles (80 MHz) / 32 cycles (160 MHz) / 48 cycles (240) */ - /* max clock speeds 2 MHz CPU clock: 19 kHz */ - /* 40 MHz CPU clock: 308 kHz */ - /* 80 MHz CPU clock: 516 kHz */ - /* 160 MHz CPU clock: 727 kHz */ - /* 240 MHz CPU clock: 784 kHz */ - /* values for 80, 160, 240, 2, 40 MHz */ - [I2C_SPEED_LOW] = {790, 1590, 2390, 10, 390 }, /* 10 kbps (period 100 us) */ - [I2C_SPEED_NORMAL] = { 70, 150, 230, 0, 30 }, /* 100 kbps (period 10 us) */ - [I2C_SPEED_FAST] = { 11, 31, 51, 0, 0 }, /* 400 kbps (period 2.5 us) */ - [I2C_SPEED_FAST_PLUS] = { 0, 0, 0, 0, 0 }, /* 1 Mbps (period 1 us) */ - [I2C_SPEED_HIGH] = { 0, 0, 0, 0, 0 } /* 3.4 Mbps (period 0.3 us) not working */ -}; -#else /* MCU_ESP32 */ -static const uint32_t _i2c_delays[][2] = -{ - /* values specify one half-period and are only valid for -O2 option */ - /* value = [period - 0.5us(160MHz) or 1.0us(80MHz)] * cycles per second / 2 */ - /* 1 us = 20 cycles (80 MHz) / 40 cycles (160 MHz) */ - [I2C_SPEED_LOW] = {989, 1990}, /* 10 kbps (period 100 us) */ - [I2C_SPEED_NORMAL] = { 89, 190}, /* 100 kbps (period 10 us) */ - [I2C_SPEED_FAST] = { 15, 40}, /* 400 kbps (period 2.5 us) */ - [I2C_SPEED_FAST_PLUS] = { 0, 13}, /* 1 Mbps (period 1 us) */ - [I2C_SPEED_HIGH] = { 0, 0} /* 3.4 Mbps (period 0.3 us) is not working */ +#if defined(MCU_ESP32) +#define I2C_CLK_CAL 62 /* clock calibration offset */ +#elif defined(MCU_ESP8266) +#define I2C_CLK_CAL 47 /* clock calibration offset */ +#else +#error "Platform implementation is missing" +#endif + +static const uint32_t _i2c_clocks[] = { + 10 * KHZ(1), /* I2C_SPEED_LOW */ + 100 * KHZ(1), /* I2C_SPEED_NORMAL */ + 400 * KHZ(1), /* I2C_SPEED_FAST */ + 1000 * KHZ(1), /* I2C_SPEED_FAST_PLUS */ + 3400 * KHZ(1), /* I2C_SPEED_HIGH */ }; -#endif /* MCU_ESP32 */ /* forward declaration of internal functions */ @@ -156,6 +144,13 @@ static int _i2c_arbitration_lost(_i2c_bus_t* bus, const char* func); static void _i2c_abort(_i2c_bus_t* bus, const char* func); static void _i2c_clear(_i2c_bus_t* bus); +#if defined(MCU_ESP8266) +static inline int esp_clk_cpu_freq(void) +{ + return ets_get_cpu_frequency() * MHZ(1); +} +#endif + /* implementation of i2c interface */ void i2c_init(i2c_t dev) @@ -177,19 +172,10 @@ void i2c_init(i2c_t dev) _i2c_bus[dev].sda_bit = BIT(_i2c_bus[dev].sda); /* store bit mask for faster access */ _i2c_bus[dev].started = false; /* for handling of repeated start condition */ - switch (ets_get_cpu_frequency()) { - case 80: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][0]; break; - case 160: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][1]; break; -#ifdef MCU_ESP32 - case 240: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][2]; break; - case 2: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][3]; break; - case 40: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][4]; break; -#endif - default : LOG_TAG_INFO("i2c", "I2C software implementation is not " - "supported for this CPU frequency: %d MHz\n", - ets_get_cpu_frequency()); - return; - } + uint32_t delay; + delay = esp_clk_cpu_freq() / _i2c_clocks[_i2c_bus[dev].speed] / 2; + delay = (delay > I2C_CLK_CAL) ? delay - I2C_CLK_CAL : 0; + _i2c_bus[dev].delay = delay; DEBUG("%s: scl=%d sda=%d speed=%d\n", __func__, _i2c_bus[dev].scl, _i2c_bus[dev].sda, _i2c_bus[dev].speed); @@ -418,14 +404,17 @@ static inline void _i2c_delay(_i2c_bus_t* bus) /* produces a delay */ uint32_t cycles = bus->delay; if (cycles) { -#if __xtensa__ - __asm__ volatile ("1: _addi.n %0, %0, -1 \n" - " bnez %0, 1b \n" : "=r" (cycles) : "0" (cycles)); -#endif -#if __riscv - uint32_t zero = 0; - __asm__ volatile ("1: add %0, %0, -1 \n" - " bne %0, %2, 1b \n" : "=r" (cycles) : "0" (cycles), "r" (zero)); +#ifdef MCU_ESP8266 + uint32_t ccount; + __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); + uint32_t wait_until = ccount + cycles; + while (ccount < wait_until) { + __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); + } +#else + uint32_t start = cpu_hal_get_cycle_count(); + uint32_t wait_until = start + cycles; + while (cpu_hal_get_cycle_count() < wait_until) { } #endif } } @@ -844,8 +833,13 @@ static IRAM_ATTR int _i2c_read_byte(_i2c_bus_t* bus, uint8_t *byte, bool ack) void i2c_print_config(void) { - for (unsigned dev = 0; dev < I2C_NUMOF; dev++) { - printf("\tI2C_DEV(%u)\tscl=%d sda=%d\n", - dev, i2c_config[dev].scl, i2c_config[dev].sda); + if (I2C_NUMOF) { + for (unsigned dev = 0; dev < I2C_NUMOF; dev++) { + printf("\tI2C_DEV(%u)\tscl=%d sda=%d\n", + dev, i2c_config[dev].scl, i2c_config[dev].sda); + } + } + else { + LOG_TAG_INFO("i2c", "no I2C devices\n"); } } From 306d2e0518fa5dd3fdca55c8710a1b2104984d36 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 10 Mar 2022 10:39:09 +0100 Subject: [PATCH 35/46] boards/esp32: cleanup board_init_common board_init_common isn't needed any longer. --- boards/common/esp32/board_common.c | 4 ---- boards/common/esp32/include/board_common.h | 10 ---------- boards/esp32-ttgo-t-beam/board.c | 2 -- boards/esp32-wrover-kit/board.c | 3 --- 4 files changed, 19 deletions(-) diff --git a/boards/common/esp32/board_common.c b/boards/common/esp32/board_common.c index 33103dabbbca..2e3916a0875e 100644 --- a/boards/common/esp32/board_common.c +++ b/boards/common/esp32/board_common.c @@ -30,10 +30,6 @@ extern "C" { #endif -void board_init_common(void) -{ -} - extern void adc_print_config(void); extern void dac_print_config(void); extern void pwm_print_config(void); diff --git a/boards/common/esp32/include/board_common.h b/boards/common/esp32/include/board_common.h index 12d89918a436..38dcef80ed34 100644 --- a/boards/common/esp32/include/board_common.h +++ b/boards/common/esp32/include/board_common.h @@ -147,13 +147,6 @@ extern mtd_dev_t *mtd0; /** @} */ #endif /* MODULE_SPIFFS || DOXYGEN */ -/** - * @brief Initialize the hardware that is common for all ESP32 boards. - * - * This function has to be called from the board specific `board_init` function. - */ -void board_init_common(void); - /** * @brief Print the board configuration in a human readable format */ @@ -171,9 +164,6 @@ void print_board_config(void); extern "C" #endif -/* declaration of `board_init_common` is required when compiling vendor code */ -extern void board_init_common(void); - #ifdef __cplusplus } #endif diff --git a/boards/esp32-ttgo-t-beam/board.c b/boards/esp32-ttgo-t-beam/board.c index 3ec40076573f..5e1a29b4c089 100644 --- a/boards/esp32-ttgo-t-beam/board.c +++ b/boards/esp32-ttgo-t-beam/board.c @@ -33,8 +33,6 @@ void board_init(void) { - board_init_common(); - #if MODULE_ESP32_TTGO_T_BEAM_V1_0 uint8_t reg; diff --git a/boards/esp32-wrover-kit/board.c b/boards/esp32-wrover-kit/board.c index 880b5107f606..ad5ea859f16d 100644 --- a/boards/esp32-wrover-kit/board.c +++ b/boards/esp32-wrover-kit/board.c @@ -23,7 +23,4 @@ void board_init(void) #if MODULE_ILI9341 gpio_init(LCD_BACKLIGHT, GPIO_OUT); #endif - - /* there is nothing special to initialize on this board */ - board_init_common(); } From 3bf016bba41649af69efd4cd2843331b3569b809 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 10 Mar 2022 15:34:19 +0100 Subject: [PATCH 36/46] cpu/esp32: split esp_idf_wpa_supplicant into several modules --- cpu/esp32/Makefile.dep | 10 ++ cpu/esp32/esp-idf/Makefile | 2 + cpu/esp32/esp-idf/wpa_supplicant/Makefile | 150 ++---------------- .../wpa_supplicant/esp_idf_wpa_supplicant.mk | 39 +++++ .../wpa_supplicant/esp_supplicant/Makefile | 14 ++ .../esp-idf/wpa_supplicant/port/Makefile | 8 + .../esp-idf/wpa_supplicant/src/ap/Makefile | 11 ++ .../wpa_supplicant/src/common/Makefile | 10 ++ .../wpa_supplicant/src/crypto/Makefile | 46 ++++++ .../wpa_supplicant/src/eap_peer/Makefile | 17 ++ .../wpa_supplicant/src/rsn_supp/Makefile | 10 ++ .../esp-idf/wpa_supplicant/src/tls/Makefile | 24 +++ .../esp-idf/wpa_supplicant/src/utils/Makefile | 15 ++ .../esp-idf/wpa_supplicant/src/wps/Makefile | 16 ++ 14 files changed, 233 insertions(+), 139 deletions(-) create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/esp_idf_wpa_supplicant.mk create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/esp_supplicant/Makefile create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/port/Makefile create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/ap/Makefile create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/common/Makefile create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/crypto/Makefile create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/eap_peer/Makefile create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/rsn_supp/Makefile create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/tls/Makefile create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/utils/Makefile create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/wps/Makefile diff --git a/cpu/esp32/Makefile.dep b/cpu/esp32/Makefile.dep index cbd4b2f46e4f..d8357e008b79 100644 --- a/cpu/esp32/Makefile.dep +++ b/cpu/esp32/Makefile.dep @@ -39,6 +39,16 @@ ifneq (,$(filter esp_wifi_any,$(USEMODULE))) USEMODULE += esp_idf_spi_flash USEMODULE += esp_idf_wifi USEMODULE += esp_idf_wpa_supplicant + USEMODULE += esp_idf_wpa_supplicant_esp_supplicant + USEMODULE += esp_idf_wpa_supplicant_port + USEMODULE += esp_idf_wpa_supplicant_ap + USEMODULE += esp_idf_wpa_supplicant_common + USEMODULE += esp_idf_wpa_supplicant_crypto + USEMODULE += esp_idf_wpa_supplicant_eap_peer + USEMODULE += esp_idf_wpa_supplicant_rsn_supp + USEMODULE += esp_idf_wpa_supplicant_tls + USEMODULE += esp_idf_wpa_supplicant_utils + USEMODULE += esp_idf_wpa_supplicant_wps USEMODULE += pthread endif diff --git a/cpu/esp32/esp-idf/Makefile b/cpu/esp32/esp-idf/Makefile index de1e25ec3ea6..9dccfe8d6cca 100644 --- a/cpu/esp32/esp-idf/Makefile +++ b/cpu/esp32/esp-idf/Makefile @@ -1,5 +1,7 @@ MODULE=esp_idf +export ESP_IDF_PATH = $(shell pwd) + # Add a list of subdirectories, that should also be built: ifneq (,$(filter esp_idf_adc,$(USEMODULE))) diff --git a/cpu/esp32/esp-idf/wpa_supplicant/Makefile b/cpu/esp32/esp-idf/wpa_supplicant/Makefile index 0927bf5a2c78..e812c6b394de 100644 --- a/cpu/esp32/esp-idf/wpa_supplicant/Makefile +++ b/cpu/esp32/esp-idf/wpa_supplicant/Makefile @@ -1,146 +1,18 @@ MODULE = esp_idf_wpa_supplicant -# source file list to be compiled as configured in component.mk -ESP32_SDK_SRC = \ - components/wpa_supplicant/esp_supplicant/src/esp_dpp.c \ - components/wpa_supplicant/esp_supplicant/src/esp_hostap.c \ - components/wpa_supplicant/esp_supplicant/src/esp_wpa2.c \ - components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c \ - components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c \ - components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.c \ - components/wpa_supplicant/esp_supplicant/src/esp_wps.c \ - components/wpa_supplicant/port/os_xtensa.c \ - components/wpa_supplicant/src/ap/ap_config.c \ - components/wpa_supplicant/src/ap/ieee802_1x.c \ - components/wpa_supplicant/src/ap/wpa_auth.c \ - components/wpa_supplicant/src/ap/wpa_auth_ie.c \ - components/wpa_supplicant/src/common/dpp.c \ - components/wpa_supplicant/src/common/sae.c \ - components/wpa_supplicant/src/common/wpa_common.c \ - components/wpa_supplicant/src/crypto/aes-cbc.c \ - components/wpa_supplicant/src/crypto/aes-ccm.c \ - components/wpa_supplicant/src/crypto/aes-ctr.c \ - components/wpa_supplicant/src/crypto/aes-gcm.c \ - components/wpa_supplicant/src/crypto/aes-internal.c \ - components/wpa_supplicant/src/crypto/aes-internal-dec.c \ - components/wpa_supplicant/src/crypto/aes-internal-enc.c \ - components/wpa_supplicant/src/crypto/aes-omac1.c \ - components/wpa_supplicant/src/crypto/aes-siv.c \ - components/wpa_supplicant/src/crypto/aes-unwrap.c \ - components/wpa_supplicant/src/crypto/aes-wrap.c \ - components/wpa_supplicant/src/crypto/ccmp.c \ - components/wpa_supplicant/src/crypto/crypto_internal.c \ - components/wpa_supplicant/src/crypto/crypto_internal-cipher.c \ - components/wpa_supplicant/src/crypto/crypto_internal-modexp.c \ - components/wpa_supplicant/src/crypto/crypto_internal-rsa.c \ - components/wpa_supplicant/src/crypto/crypto_ops.c \ - components/wpa_supplicant/src/crypto/des-internal.c \ - components/wpa_supplicant/src/crypto/dh_group5.c \ - components/wpa_supplicant/src/crypto/dh_groups.c \ - components/wpa_supplicant/src/crypto/md4-internal.c \ - components/wpa_supplicant/src/crypto/md5.c \ - components/wpa_supplicant/src/crypto/md5-internal.c \ - components/wpa_supplicant/src/crypto/ms_funcs.c \ - components/wpa_supplicant/src/crypto/rc4.c \ - components/wpa_supplicant/src/crypto/sha1.c \ - components/wpa_supplicant/src/crypto/sha1-internal.c \ - components/wpa_supplicant/src/crypto/sha1-pbkdf2.c \ - components/wpa_supplicant/src/crypto/sha1-prf.c \ - components/wpa_supplicant/src/crypto/sha1-tlsprf.c \ - components/wpa_supplicant/src/crypto/sha256.c \ - components/wpa_supplicant/src/crypto/sha256-internal.c \ - components/wpa_supplicant/src/crypto/sha256-kdf.c \ - components/wpa_supplicant/src/crypto/sha256-prf.c \ - components/wpa_supplicant/src/crypto/sha256-tlsprf.c \ - components/wpa_supplicant/src/crypto/sha384-internal.c \ - components/wpa_supplicant/src/crypto/sha384-prf.c \ - components/wpa_supplicant/src/crypto/sha384-tlsprf.c \ - components/wpa_supplicant/src/crypto/sha512-internal.c \ - components/wpa_supplicant/src/eap_peer/chap.c \ - components/wpa_supplicant/src/eap_peer/eap.c \ - components/wpa_supplicant/src/eap_peer/eap_common.c \ - components/wpa_supplicant/src/eap_peer/eap_mschapv2.c \ - components/wpa_supplicant/src/eap_peer/eap_peap.c \ - components/wpa_supplicant/src/eap_peer/eap_peap_common.c \ - components/wpa_supplicant/src/eap_peer/eap_tls.c \ - components/wpa_supplicant/src/eap_peer/eap_tls_common.c \ - components/wpa_supplicant/src/eap_peer/eap_ttls.c \ - components/wpa_supplicant/src/eap_peer/mschapv2.c \ - components/wpa_supplicant/src/rsn_supp/pmksa_cache.c \ - components/wpa_supplicant/src/rsn_supp/wpa.c \ - components/wpa_supplicant/src/rsn_supp/wpa_ie.c \ - components/wpa_supplicant/src/tls/asn1.c \ - components/wpa_supplicant/src/tls/bignum.c \ - components/wpa_supplicant/src/tls/pkcs1.c \ - components/wpa_supplicant/src/tls/pkcs5.c \ - components/wpa_supplicant/src/tls/pkcs8.c \ - components/wpa_supplicant/src/tls/rsa.c \ - components/wpa_supplicant/src/tls/tls_internal.c \ - components/wpa_supplicant/src/tls/tlsv1_client.c \ - components/wpa_supplicant/src/tls/tlsv1_client_read.c \ - components/wpa_supplicant/src/tls/tlsv1_client_write.c \ - components/wpa_supplicant/src/tls/tlsv1_common.c \ - components/wpa_supplicant/src/tls/tlsv1_cred.c \ - components/wpa_supplicant/src/tls/tlsv1_record.c \ - components/wpa_supplicant/src/tls/tlsv1_server.c \ - components/wpa_supplicant/src/tls/tlsv1_server_read.c \ - components/wpa_supplicant/src/tls/tlsv1_server_write.c \ - components/wpa_supplicant/src/tls/x509v3.c \ - components/wpa_supplicant/src/utils/base64.c \ - components/wpa_supplicant/src/utils/bitfield.c \ - components/wpa_supplicant/src/utils/common.c \ - components/wpa_supplicant/src/utils/ext_password.c \ - components/wpa_supplicant/src/utils/json.c \ - components/wpa_supplicant/src/utils/uuid.c \ - components/wpa_supplicant/src/utils/wpabuf.c \ - components/wpa_supplicant/src/utils/wpa_debug.c \ - components/wpa_supplicant/src/wps/wps_attr_build.c \ - components/wpa_supplicant/src/wps/wps_attr_parse.c \ - components/wpa_supplicant/src/wps/wps_attr_process.c \ - components/wpa_supplicant/src/wps/wps.c \ - components/wpa_supplicant/src/wps/wps_common.c \ - components/wpa_supplicant/src/wps/wps_dev_attr.c \ - components/wpa_supplicant/src/wps/wps_enrollee.c \ - components/wpa_supplicant/src/wps/wps_registrar.c \ - components/wpa_supplicant/src/wps/wps_validate.c \ - # +export ESP_IDF_WPA_SUPPLICANT_PATH = $(shell pwd) -# additional include pathes required by this module -INCLUDES += -I$(ESP32_SDK_DIR)/components/wpa_supplicant/esp_supplicant/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/wpa_supplicant/esp_supplicant/src -INCLUDES += -I$(ESP32_SDK_DIR)/components/wpa_supplicant/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/wpa_supplicant/port/include -INCLUDES += -I$(ESP32_SDK_DIR)/components/wpa_supplicant/src -INCLUDES += -I$(ESP32_SDK_DIR)/components/wpa_supplicant/src/utils +DIRS += esp_supplicant +DIRS += port +DIRS += src/ap +DIRS += src/common +DIRS += src/crypto +DIRS += src/eap_peer +DIRS += src/rsn_supp +DIRS += src/tls +DIRS += src/utils +DIRS += src/wps include $(RIOTBASE)/Makefile.base ESP32_SDK_BIN = $(BINDIR)/$(MODULE) - -# definitions for wpa_supplicant from components/wpa_supplicant/component.mk -CFLAGS += -D__ets__ -CFLAGS += -DCONFIG_DPP -CFLAGS += -DCONFIG_ECC -CFLAGS += -DCONFIG_IEEE80211W -CFLAGS += -DCONFIG_SHA256 -CFLAGS += -DCONFIG_WNM -CFLAGS += -DCONFIG_WPS_PIN -CFLAGS += -DCONFIG_WPS2 -CFLAGS += -DEAP_MSCHAPv2 -CFLAGS += -DEAP_PEAP -CFLAGS += -DEAP_PEER_METHOD -CFLAGS += -DEAP_TLS -CFLAGS += -DEAP_TTLS -CFLAGS += -DESP_SUPPLICANT -CFLAGS += -DESP32_WORKAROUND -CFLAGS += -DESPRESSIF_USE -CFLAGS += -DIEEE8021X_EAPOL -CFLAGS += -DUSE_WPA2_TASK -CFLAGS += -DUSE_WPS_TASK -CFLAGS += -Wno-strict-aliasing -CFLAGS += -Wno-format-nonliteral -CFLAGS += -Wno-format-security -CFLAGS += -std=gnu99 - -include ../esp_idf.mk -include ../esp_idf_cflags.mk diff --git a/cpu/esp32/esp-idf/wpa_supplicant/esp_idf_wpa_supplicant.mk b/cpu/esp32/esp-idf/wpa_supplicant/esp_idf_wpa_supplicant.mk new file mode 100644 index 000000000000..9b1a00d437e5 --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/esp_idf_wpa_supplicant.mk @@ -0,0 +1,39 @@ +# additional include pathes required by this module +INCLUDES += -I$(ESP32_SDK_DIR)/components/wpa_supplicant/esp_supplicant/include +INCLUDES += -I$(ESP32_SDK_DIR)/components/wpa_supplicant/esp_supplicant/src +INCLUDES += -I$(ESP32_SDK_DIR)/components/wpa_supplicant/include +INCLUDES += -I$(ESP32_SDK_DIR)/components/wpa_supplicant/port/include +INCLUDES += -I$(ESP32_SDK_DIR)/components/wpa_supplicant/src +INCLUDES += -I$(ESP32_SDK_DIR)/components/wpa_supplicant/src/utils + +include $(RIOTBASE)/Makefile.base + +ESP32_SDK_BIN = $(BINDIR)/$(MODULE) + +# definitions for wpa_supplicant from components/wpa_supplicant/component.mk +CFLAGS += -D__ets__ +CFLAGS += -DCONFIG_DPP +CFLAGS += -DCONFIG_ECC +CFLAGS += -DCONFIG_IEEE80211W +CFLAGS += -DCONFIG_SHA256 +CFLAGS += -DCONFIG_WNM +CFLAGS += -DCONFIG_WPS_PIN +CFLAGS += -DCONFIG_WPS2 +CFLAGS += -DEAP_MSCHAPv2 +CFLAGS += -DEAP_PEAP +CFLAGS += -DEAP_PEER_METHOD +CFLAGS += -DEAP_TLS +CFLAGS += -DEAP_TTLS +CFLAGS += -DESP_SUPPLICANT +CFLAGS += -DESP32_WORKAROUND +CFLAGS += -DESPRESSIF_USE +CFLAGS += -DIEEE8021X_EAPOL +CFLAGS += -DUSE_WPA2_TASK +CFLAGS += -DUSE_WPS_TASK +CFLAGS += -Wno-strict-aliasing +CFLAGS += -Wno-format-nonliteral +CFLAGS += -Wno-format-security +CFLAGS += -std=gnu99 + +include $(ESP_IDF_PATH)/esp_idf.mk +include $(ESP_IDF_PATH)/esp_idf_cflags.mk diff --git a/cpu/esp32/esp-idf/wpa_supplicant/esp_supplicant/Makefile b/cpu/esp32/esp-idf/wpa_supplicant/esp_supplicant/Makefile new file mode 100644 index 000000000000..e9be2f82f800 --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/esp_supplicant/Makefile @@ -0,0 +1,14 @@ +MODULE = esp_idf_wpa_supplicant_esp_supplicant + +# source file list to be compiled as configured in component.mk +ESP32_SDK_SRC = \ + components/wpa_supplicant/esp_supplicant/src/esp_dpp.c \ + components/wpa_supplicant/esp_supplicant/src/esp_hostap.c \ + components/wpa_supplicant/esp_supplicant/src/esp_wpa2.c \ + components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c \ + components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c \ + components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.c \ + components/wpa_supplicant/esp_supplicant/src/esp_wps.c \ + # + +include $(ESP_IDF_WPA_SUPPLICANT_PATH)/esp_idf_wpa_supplicant.mk diff --git a/cpu/esp32/esp-idf/wpa_supplicant/port/Makefile b/cpu/esp32/esp-idf/wpa_supplicant/port/Makefile new file mode 100644 index 000000000000..a2d0c8112565 --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/port/Makefile @@ -0,0 +1,8 @@ +MODULE = esp_idf_wpa_supplicant_port + +# source file list to be compiled as configured in component.mk +ESP32_SDK_SRC = \ + components/wpa_supplicant/port/os_xtensa.c \ + # + +include $(ESP_IDF_WPA_SUPPLICANT_PATH)/esp_idf_wpa_supplicant.mk diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/ap/Makefile b/cpu/esp32/esp-idf/wpa_supplicant/src/ap/Makefile new file mode 100644 index 000000000000..8a58668e9834 --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/ap/Makefile @@ -0,0 +1,11 @@ +MODULE = esp_idf_wpa_supplicant_ap + +# source file list to be compiled as configured in component.mk +ESP32_SDK_SRC = \ + components/wpa_supplicant/src/ap/ap_config.c \ + components/wpa_supplicant/src/ap/ieee802_1x.c \ + components/wpa_supplicant/src/ap/wpa_auth.c \ + components/wpa_supplicant/src/ap/wpa_auth_ie.c \ + # + +include $(ESP_IDF_WPA_SUPPLICANT_PATH)/esp_idf_wpa_supplicant.mk diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/common/Makefile b/cpu/esp32/esp-idf/wpa_supplicant/src/common/Makefile new file mode 100644 index 000000000000..5d6e036f5ef8 --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/common/Makefile @@ -0,0 +1,10 @@ +MODULE = esp_idf_wpa_supplicant_common + +# source file list to be compiled as configured in component.mk +ESP32_SDK_SRC = \ + components/wpa_supplicant/src/common/dpp.c \ + components/wpa_supplicant/src/common/sae.c \ + components/wpa_supplicant/src/common/wpa_common.c \ + # + +include $(ESP_IDF_WPA_SUPPLICANT_PATH)/esp_idf_wpa_supplicant.mk diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/crypto/Makefile b/cpu/esp32/esp-idf/wpa_supplicant/src/crypto/Makefile new file mode 100644 index 000000000000..06841c8977bd --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/crypto/Makefile @@ -0,0 +1,46 @@ +MODULE = esp_idf_wpa_supplicant_crypto + +# source file list to be compiled as configured in component.mk +ESP32_SDK_SRC = \ + components/wpa_supplicant/src/crypto/aes-cbc.c \ + components/wpa_supplicant/src/crypto/aes-ccm.c \ + components/wpa_supplicant/src/crypto/aes-ctr.c \ + components/wpa_supplicant/src/crypto/aes-gcm.c \ + components/wpa_supplicant/src/crypto/aes-internal.c \ + components/wpa_supplicant/src/crypto/aes-internal-dec.c \ + components/wpa_supplicant/src/crypto/aes-internal-enc.c \ + components/wpa_supplicant/src/crypto/aes-omac1.c \ + components/wpa_supplicant/src/crypto/aes-siv.c \ + components/wpa_supplicant/src/crypto/aes-unwrap.c \ + components/wpa_supplicant/src/crypto/aes-wrap.c \ + components/wpa_supplicant/src/crypto/ccmp.c \ + components/wpa_supplicant/src/crypto/crypto_internal.c \ + components/wpa_supplicant/src/crypto/crypto_internal-cipher.c \ + components/wpa_supplicant/src/crypto/crypto_internal-modexp.c \ + components/wpa_supplicant/src/crypto/crypto_internal-rsa.c \ + components/wpa_supplicant/src/crypto/crypto_ops.c \ + components/wpa_supplicant/src/crypto/des-internal.c \ + components/wpa_supplicant/src/crypto/dh_group5.c \ + components/wpa_supplicant/src/crypto/dh_groups.c \ + components/wpa_supplicant/src/crypto/md4-internal.c \ + components/wpa_supplicant/src/crypto/md5.c \ + components/wpa_supplicant/src/crypto/md5-internal.c \ + components/wpa_supplicant/src/crypto/ms_funcs.c \ + components/wpa_supplicant/src/crypto/rc4.c \ + components/wpa_supplicant/src/crypto/sha1.c \ + components/wpa_supplicant/src/crypto/sha1-internal.c \ + components/wpa_supplicant/src/crypto/sha1-pbkdf2.c \ + components/wpa_supplicant/src/crypto/sha1-prf.c \ + components/wpa_supplicant/src/crypto/sha1-tlsprf.c \ + components/wpa_supplicant/src/crypto/sha256.c \ + components/wpa_supplicant/src/crypto/sha256-internal.c \ + components/wpa_supplicant/src/crypto/sha256-kdf.c \ + components/wpa_supplicant/src/crypto/sha256-prf.c \ + components/wpa_supplicant/src/crypto/sha256-tlsprf.c \ + components/wpa_supplicant/src/crypto/sha384-internal.c \ + components/wpa_supplicant/src/crypto/sha384-prf.c \ + components/wpa_supplicant/src/crypto/sha384-tlsprf.c \ + components/wpa_supplicant/src/crypto/sha512-internal.c \ + # + +include $(ESP_IDF_WPA_SUPPLICANT_PATH)/esp_idf_wpa_supplicant.mk diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/eap_peer/Makefile b/cpu/esp32/esp-idf/wpa_supplicant/src/eap_peer/Makefile new file mode 100644 index 000000000000..ed3190febd6a --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/eap_peer/Makefile @@ -0,0 +1,17 @@ +MODULE = esp_idf_wpa_supplicant_eap_peer + +# source file list to be compiled as configured in component.mk +ESP32_SDK_SRC = \ + components/wpa_supplicant/src/eap_peer/chap.c \ + components/wpa_supplicant/src/eap_peer/eap.c \ + components/wpa_supplicant/src/eap_peer/eap_common.c \ + components/wpa_supplicant/src/eap_peer/eap_mschapv2.c \ + components/wpa_supplicant/src/eap_peer/eap_peap.c \ + components/wpa_supplicant/src/eap_peer/eap_peap_common.c \ + components/wpa_supplicant/src/eap_peer/eap_tls.c \ + components/wpa_supplicant/src/eap_peer/eap_tls_common.c \ + components/wpa_supplicant/src/eap_peer/eap_ttls.c \ + components/wpa_supplicant/src/eap_peer/mschapv2.c \ + # + +include $(ESP_IDF_WPA_SUPPLICANT_PATH)/esp_idf_wpa_supplicant.mk diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/rsn_supp/Makefile b/cpu/esp32/esp-idf/wpa_supplicant/src/rsn_supp/Makefile new file mode 100644 index 000000000000..07b2f32254ba --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/rsn_supp/Makefile @@ -0,0 +1,10 @@ +MODULE = esp_idf_wpa_supplicant_rsn_supp + +# source file list to be compiled as configured in component.mk +ESP32_SDK_SRC = \ + components/wpa_supplicant/src/rsn_supp/pmksa_cache.c \ + components/wpa_supplicant/src/rsn_supp/wpa.c \ + components/wpa_supplicant/src/rsn_supp/wpa_ie.c \ + # + +include $(ESP_IDF_WPA_SUPPLICANT_PATH)/esp_idf_wpa_supplicant.mk diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/tls/Makefile b/cpu/esp32/esp-idf/wpa_supplicant/src/tls/Makefile new file mode 100644 index 000000000000..b1df3a7ee2f5 --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/tls/Makefile @@ -0,0 +1,24 @@ +MODULE = esp_idf_wpa_supplicant_tls + +# source file list to be compiled as configured in component.mk +ESP32_SDK_SRC = \ + components/wpa_supplicant/src/tls/asn1.c \ + components/wpa_supplicant/src/tls/bignum.c \ + components/wpa_supplicant/src/tls/pkcs1.c \ + components/wpa_supplicant/src/tls/pkcs5.c \ + components/wpa_supplicant/src/tls/pkcs8.c \ + components/wpa_supplicant/src/tls/rsa.c \ + components/wpa_supplicant/src/tls/tls_internal.c \ + components/wpa_supplicant/src/tls/tlsv1_client.c \ + components/wpa_supplicant/src/tls/tlsv1_client_read.c \ + components/wpa_supplicant/src/tls/tlsv1_client_write.c \ + components/wpa_supplicant/src/tls/tlsv1_common.c \ + components/wpa_supplicant/src/tls/tlsv1_cred.c \ + components/wpa_supplicant/src/tls/tlsv1_record.c \ + components/wpa_supplicant/src/tls/tlsv1_server.c \ + components/wpa_supplicant/src/tls/tlsv1_server_read.c \ + components/wpa_supplicant/src/tls/tlsv1_server_write.c \ + components/wpa_supplicant/src/tls/x509v3.c \ + # + +include $(ESP_IDF_WPA_SUPPLICANT_PATH)/esp_idf_wpa_supplicant.mk diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/utils/Makefile b/cpu/esp32/esp-idf/wpa_supplicant/src/utils/Makefile new file mode 100644 index 000000000000..787b4adec81e --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/utils/Makefile @@ -0,0 +1,15 @@ +MODULE = esp_idf_wpa_supplicant_utils + +# source file list to be compiled as configured in component.mk +ESP32_SDK_SRC = \ + components/wpa_supplicant/src/utils/base64.c \ + components/wpa_supplicant/src/utils/bitfield.c \ + components/wpa_supplicant/src/utils/common.c \ + components/wpa_supplicant/src/utils/ext_password.c \ + components/wpa_supplicant/src/utils/json.c \ + components/wpa_supplicant/src/utils/uuid.c \ + components/wpa_supplicant/src/utils/wpabuf.c \ + components/wpa_supplicant/src/utils/wpa_debug.c \ + # + +include $(ESP_IDF_WPA_SUPPLICANT_PATH)/esp_idf_wpa_supplicant.mk diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/wps/Makefile b/cpu/esp32/esp-idf/wpa_supplicant/src/wps/Makefile new file mode 100644 index 000000000000..301d31a2ebbc --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/wps/Makefile @@ -0,0 +1,16 @@ +MODULE = esp_idf_wpa_supplicant_wps + +# source file list to be compiled as configured in component.mk +ESP32_SDK_SRC = \ + components/wpa_supplicant/src/wps/wps_attr_build.c \ + components/wpa_supplicant/src/wps/wps_attr_parse.c \ + components/wpa_supplicant/src/wps/wps_attr_process.c \ + components/wpa_supplicant/src/wps/wps.c \ + components/wpa_supplicant/src/wps/wps_common.c \ + components/wpa_supplicant/src/wps/wps_dev_attr.c \ + components/wpa_supplicant/src/wps/wps_enrollee.c \ + components/wpa_supplicant/src/wps/wps_registrar.c \ + components/wpa_supplicant/src/wps/wps_validate.c \ + # + +include $(ESP_IDF_WPA_SUPPLICANT_PATH)/esp_idf_wpa_supplicant.mk From bc75e5635d9bc45f8be684c9073a1f3acd2b04f2 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 11 Mar 2022 07:31:01 +0100 Subject: [PATCH 37/46] cpu/esp32: small doc fixes --- cpu/esp32/doc.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cpu/esp32/doc.txt b/cpu/esp32/doc.txt index 0a6d8750eb09..856165307500 100644 --- a/cpu/esp32/doc.txt +++ b/cpu/esp32/doc.txt @@ -702,15 +702,15 @@ Attenuation | Voltage Range | Symbol
@note The reference voltage Vref can vary from device to device in the range of 1.0V and 1.2V. The - Vref of a device can be read with the `#adc_vref_to_gpio25` function at GPIO 25.
+ Vref of a device can be read with the `#adc_line_vref_to_gpio` function at GPIO 25.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c} -extern int adc_vref_to_gpio25 (void); +extern int adc_line_vref_to_gpio(adc_t line, gpio_t gpio); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For that purpose GPIO25 is initialized automatically as ADC channel and is connected internally to Vref to measure the current voltage. Once the initialization is finished and the function returns with success, the current voltage can be read from GPIO25. The results of the ADC input can then be -adjusted accordingly. The `#adc_vref_to_gpio25` function can be used to determine the current +adjusted accordingly. The `#adc_line_vref_to_gpio` function can be used to determine the current voltage at ESP32. [Back to table of contents](#esp32_toc) @@ -879,13 +879,13 @@ used. Example: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c} -#define SPI0_CTRL VSPI +#define SPI0_CTRL VSPI #define SPI0_SCK GPIO18 // SCK Periphery #define SPI0_MISO GPIO19 // MISO Periphery #define SPI0_MOSI GPIO23 // MOSI Periphery #define SPI0_CS0 GPIO5 // CS0 Periphery -#define SPI1_CTRL HSPI +#define SPI1_CTRL HSPI #define SPI1_SCK GPIO14 // SCK Camera #define SPI1_MISO GPIO12 // MISO Camera #define SPI1_MOSI GPIO13 // MOSI Camera @@ -1119,7 +1119,7 @@ supports the following operating modes: - In **Deep-sleep** the CPU and the SRAM are powered down. The RTC memory can be retained. The system must be restarted when it returns from this mode. -Since the peripherals are not working during _Light-sleep_/_Deep-sleep_, the +Since the peripherals are not working during _Light-sleep_ and _Deep-sleep_, the CPU cannot be woken up by internal interrupt sources such as timers. Therefore, RIOT's layered power management can't select them as idle power mode. They are therefore blocked for normal operation. The application has to select them @@ -1145,7 +1145,7 @@ as parameter. To exit from these modes, several wake-up sources can be used. [Back to table of contents](#esp32_toc) -#### Wake-up Sources in _Light-sleep_ Mode +#### Wake-up Sources in _Light-sleep_ Possible wake-up sources for the _Light-sleep_ mode are: @@ -1165,7 +1165,7 @@ entering _Light-sleep_ mode. [Back to table of contents](#esp32_toc) -#### Wake-up Sources in _Light-sleep_ Mode +#### Wake-up Sources in _Deep-sleep_ Mode Possible Wake-up sources for the _Deep-sleep_ mode are: From 39dee55938ef04152da3f21e11a260df7059d99b Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 11 Mar 2022 09:44:00 +0100 Subject: [PATCH 38/46] cpu/esp32: cleanup of makefiles for peripherals --- cpu/esp32/Makefile.dep | 8 -------- cpu/esp32/Makefile.features | 2 +- cpu/esp32/periph/Makefile | 8 ++++++++ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cpu/esp32/Makefile.dep b/cpu/esp32/Makefile.dep index d8357e008b79..a5fa2e7f5a8f 100644 --- a/cpu/esp32/Makefile.dep +++ b/cpu/esp32/Makefile.dep @@ -18,7 +18,6 @@ ifneq (,$(filter cpp,$(USEMODULE))) endif ifneq (,$(filter esp_eth,$(USEMODULE))) - USEMODULE += esp_idf_efuse USEMODULE += esp_idf_eth USEMODULE += esp_idf_event USEMODULE += esp_idf_gpio @@ -32,7 +31,6 @@ ifneq (,$(filter esp_wifi_any,$(USEMODULE))) # add additional modules and packages used for any WiFi interface USEPKG += esp32_sdk_lib_phy USEPKG += esp32_sdk_lib_wifi - USEMODULE += esp_idf_efuse USEMODULE += esp_idf_event USEMODULE += esp_idf_heap USEMODULE += esp_idf_nvs_flash @@ -85,13 +83,8 @@ ifneq (,$(filter esp_rtc_timer_32k,$(FEATURES_USED))) USEMODULE += esp_rtc_timer_32k endif -ifneq (,$(filter periph_adc periph_dac,$(USEMODULE))) - FEATURES_REQUIRED += periph_adc_arch -endif - ifneq (,$(filter periph_gpio,$(USEMODULE))) USEMODULE += esp_idf_gpio - USEMODULE += periph_gpio_arch endif ifneq (,$(filter periph_i2c,$(USEMODULE))) @@ -109,7 +102,6 @@ endif ifneq (,$(filter esp_spi_ram,$(USEMODULE))) FEATURES_REQUIRED += esp_spi_ram - USEMODULE += esp_idf_efuse USEMODULE += esp_idf_gpio USEMODULE += esp_idf_heap USEMODULE += esp_idf_spi_flash diff --git a/cpu/esp32/Makefile.features b/cpu/esp32/Makefile.features index b905ca2a705e..5b38766fa0bb 100644 --- a/cpu/esp32/Makefile.features +++ b/cpu/esp32/Makefile.features @@ -6,7 +6,7 @@ include $(RIOTCPU)/esp_common/Makefile.features FEATURES_PROVIDED += arch_esp32 FEATURES_PROVIDED += esp_wifi_enterprise -FEATURES_PROVIDED += periph_adc_arch +FEATURES_PROVIDED += esp_hw_counter FEATURES_PROVIDED += puf_sram ifneq (,$(filter esp32-wrover%,$(CPU_MODEL))) diff --git a/cpu/esp32/periph/Makefile b/cpu/esp32/periph/Makefile index d6a5d0455c5d..c0f49828dd1c 100644 --- a/cpu/esp32/periph/Makefile +++ b/cpu/esp32/periph/Makefile @@ -1,3 +1,11 @@ MODULE = periph +ifneq (,$(filter periph_adc periph_dac,$(USEMODULE))) + SRC += adc_arch.c +endif + +ifneq (,$(filter periph_gpio,$(USEMODULE))) + SRC += gpio_arch.c +endif + include $(RIOTMAKE)/periph.mk From 6181459c1b3c521db388e1561a8a67633dfc18a7 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 26 May 2022 14:17:01 +0200 Subject: [PATCH 39/46] cpu/esp32: required changes in Kconfig --- cpu/esp32/Kconfig | 14 +++++++------- cpu/esp32/esp-idf-api/Kconfig | 14 ++++++++++++++ cpu/esp32/esp-idf/Kconfig | 2 ++ cpu/esp32/esp-idf/gpio/Kconfig | 3 +++ cpu/esp32/esp-idf/nvs_flash/Kconfig | 3 ++- cpu/esp32/esp-idf/wifi/Kconfig | 3 +++ cpu/esp32/esp-idf/wpa_supplicant/Kconfig | 11 +++++++++++ .../esp-idf/wpa_supplicant/esp_supplicant/Kconfig | 13 +++++++++++++ cpu/esp32/esp-idf/wpa_supplicant/port/Kconfig | 13 +++++++++++++ cpu/esp32/esp-idf/wpa_supplicant/src/ap/Kconfig | 13 +++++++++++++ .../esp-idf/wpa_supplicant/src/common/Kconfig | 13 +++++++++++++ .../esp-idf/wpa_supplicant/src/crypto/Kconfig | 13 +++++++++++++ .../esp-idf/wpa_supplicant/src/eap_peer/Kconfig | 13 +++++++++++++ .../esp-idf/wpa_supplicant/src/rsn_supp/Kconfig | 13 +++++++++++++ cpu/esp32/esp-idf/wpa_supplicant/src/tls/Kconfig | 13 +++++++++++++ cpu/esp32/esp-idf/wpa_supplicant/src/utils/Kconfig | 13 +++++++++++++ cpu/esp32/esp-idf/wpa_supplicant/src/wps/Kconfig | 13 +++++++++++++ cpu/esp32/periph/Kconfig | 6 +----- 18 files changed, 173 insertions(+), 13 deletions(-) create mode 100644 cpu/esp32/esp-idf-api/Kconfig create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/esp_supplicant/Kconfig create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/port/Kconfig create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/ap/Kconfig create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/common/Kconfig create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/crypto/Kconfig create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/eap_peer/Kconfig create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/rsn_supp/Kconfig create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/tls/Kconfig create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/utils/Kconfig create mode 100644 cpu/esp32/esp-idf/wpa_supplicant/src/wps/Kconfig diff --git a/cpu/esp32/Kconfig b/cpu/esp32/Kconfig index f04fc30ffed8..bea16225628d 100644 --- a/cpu/esp32/Kconfig +++ b/cpu/esp32/Kconfig @@ -15,8 +15,8 @@ config CPU_FAM_ESP32 select CPU_CORE_XTENSA_LX6 select HAS_ARCH_ESP32 select HAS_CPU_ESP32 + select HAS_ESP_HW_COUNTER select HAS_ESP_WIFI_ENTERPRISE - select HAS_PERIPH_ADC_ARCH select HAS_PUF_SRAM select PACKAGE_ESP32_SDK if TEST_KCONFIG @@ -63,6 +63,11 @@ config HAS_CPU_ESP32 help Indicates that the current CPU is 'esp32'. +config HAS_ESP_HW_COUNTER + bool + help + Indicates that HW counters can be used. + config HAS_ESP_RTC_TIMER_32K bool help @@ -75,11 +80,6 @@ config HAS_ESP_SPI_RAM Indicates that an external RAM is connected via the FSPI interface in the board. -config HAS_PERIPH_ADC_ARCH - bool - help - Indicates that architecure specific ADC peripherals are present. - ## Common CPU symbols config CPU_CORE default "xtensa-lx6" if CPU_CORE_XTENSA_LX6 @@ -120,7 +120,6 @@ menu "ESP32 specific configurations" config MODULE_ESP_SPI_RAM bool "SPI RAM support" depends on HAS_ESP_SPI_RAM - select MODULE_ESP_IDF_EFUSE select MODULE_ESP_IDF_GPIO select MODULE_ESP_IDF_HEAP select MODULE_ESP_IDF_SPI_FLASH @@ -136,5 +135,6 @@ endmenu rsource "bootloader/Kconfig" rsource "esp-idf/Kconfig" +rsource "esp-idf-api/Kconfig" rsource "periph/Kconfig" source "$(RIOTCPU)/esp_common/Kconfig" diff --git a/cpu/esp32/esp-idf-api/Kconfig b/cpu/esp32/esp-idf-api/Kconfig new file mode 100644 index 000000000000..82f1f6cac058 --- /dev/null +++ b/cpu/esp32/esp-idf-api/Kconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2022 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. +# + +config MODULE_ESP_IDF_API + bool + depends on TEST_KCONFIG + depends on HAS_ARCH_ESP32 + default y + help + ESP-IDF interface API diff --git a/cpu/esp32/esp-idf/Kconfig b/cpu/esp32/esp-idf/Kconfig index d74711087f9c..86b10841dd04 100644 --- a/cpu/esp32/esp-idf/Kconfig +++ b/cpu/esp32/esp-idf/Kconfig @@ -12,10 +12,12 @@ config MODULE_ESP_IDF depends on HAS_ARCH_ESP32 default y select MODULE_ESP_IDF_COMMON + select MODULE_ESP_IDF_EFUSE select MODULE_ESP_IDF_SPI_FLASH if MODULE_MTD help Espressif IoT Development Framework. +rsource "adc/Kconfig" rsource "common/Kconfig" rsource "efuse/Kconfig" rsource "eth/Kconfig" diff --git a/cpu/esp32/esp-idf/gpio/Kconfig b/cpu/esp32/esp-idf/gpio/Kconfig index 89cbea13209d..0fe2ba2739e2 100644 --- a/cpu/esp32/esp-idf/gpio/Kconfig +++ b/cpu/esp32/esp-idf/gpio/Kconfig @@ -9,5 +9,8 @@ config MODULE_ESP_IDF_GPIO bool depends on TEST_KCONFIG depends on MODULE_ESP_IDF + + default y if MODULE_PERIPH_GPIO + help ESP-IDF code for peripheral GPIO. diff --git a/cpu/esp32/esp-idf/nvs_flash/Kconfig b/cpu/esp32/esp-idf/nvs_flash/Kconfig index 09c88c5aa283..33c6fad9700e 100644 --- a/cpu/esp32/esp-idf/nvs_flash/Kconfig +++ b/cpu/esp32/esp-idf/nvs_flash/Kconfig @@ -9,8 +9,9 @@ config MODULE_ESP_IDF_NVS_FLASH bool depends on TEST_KCONFIG depends on MODULE_ESP_IDF - select MODULE_CPP + select MODULE_MTD + help ESP-IDF non-volatile storage library. This library is required if the WiFi interface is used. diff --git a/cpu/esp32/esp-idf/wifi/Kconfig b/cpu/esp32/esp-idf/wifi/Kconfig index 7609e8dbe93a..f971e02809dc 100644 --- a/cpu/esp32/esp-idf/wifi/Kconfig +++ b/cpu/esp32/esp-idf/wifi/Kconfig @@ -9,5 +9,8 @@ config MODULE_ESP_IDF_WIFI bool depends on TEST_KCONFIG depends on MODULE_ESP_IDF + + select MODULE_ESP_IDF_ADC + help ESP-IDF code required for accessing the WiFi interface. diff --git a/cpu/esp32/esp-idf/wpa_supplicant/Kconfig b/cpu/esp32/esp-idf/wpa_supplicant/Kconfig index b3c590821823..7faa85116457 100644 --- a/cpu/esp32/esp-idf/wpa_supplicant/Kconfig +++ b/cpu/esp32/esp-idf/wpa_supplicant/Kconfig @@ -12,3 +12,14 @@ config MODULE_ESP_IDF_WPA_SUPPLICANT depends on MODULE_ESP_IDF help ESP-IDF WPA supplicant. + +rsource "esp_supplicant/Kconfig" +rsource "port/Kconfig" +rsource "src/ap/Kconfig" +rsource "src/common/Kconfig" +rsource "src/crypto/Kconfig" +rsource "src/eap_peer/Kconfig" +rsource "src/rsn_supp/Kconfig" +rsource "src/tls/Kconfig" +rsource "src/utils/Kconfig" +rsource "src/wps/Kconfig" diff --git a/cpu/esp32/esp-idf/wpa_supplicant/esp_supplicant/Kconfig b/cpu/esp32/esp-idf/wpa_supplicant/esp_supplicant/Kconfig new file mode 100644 index 000000000000..cd3cb566201f --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/esp_supplicant/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2021 HAW Hamburg +# +# 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. +# + +config MODULE_ESP_IDF_WPA_SUPPLICANT_ESP_SUPPLICANT + bool + depends on TEST_KCONFIG + depends on MODULE_ESP_IDF + help + Additional ESP supplicant code for ESP-IDF WPA supplicant. diff --git a/cpu/esp32/esp-idf/wpa_supplicant/port/Kconfig b/cpu/esp32/esp-idf/wpa_supplicant/port/Kconfig new file mode 100644 index 000000000000..2f0b7999b5ce --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/port/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2021 HAW Hamburg +# +# 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. +# + +config MODULE_ESP_IDF_WPA_SUPPLICANT_PORT + bool + depends on TEST_KCONFIG + depends on MODULE_ESP_IDF + help + ESP-IDF WPA supplicant port code. diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/ap/Kconfig b/cpu/esp32/esp-idf/wpa_supplicant/src/ap/Kconfig new file mode 100644 index 000000000000..4607821bcec1 --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/ap/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2021 HAW Hamburg +# +# 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. +# + +config MODULE_ESP_IDF_WPA_SUPPLICANT_AP + bool + depends on TEST_KCONFIG + depends on MODULE_ESP_IDF + help + AP code for ESP-IDF WPA supplicant. diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/common/Kconfig b/cpu/esp32/esp-idf/wpa_supplicant/src/common/Kconfig new file mode 100644 index 000000000000..233121658065 --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/common/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2021 HAW Hamburg +# +# 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. +# + +config MODULE_ESP_IDF_WPA_SUPPLICANT_COMMON + bool + depends on TEST_KCONFIG + depends on MODULE_ESP_IDF + help + Common code for ESP-IDF WPA supplicant. diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/crypto/Kconfig b/cpu/esp32/esp-idf/wpa_supplicant/src/crypto/Kconfig new file mode 100644 index 000000000000..477149e3fc41 --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/crypto/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2021 HAW Hamburg +# +# 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. +# + +config MODULE_ESP_IDF_WPA_SUPPLICANT_CRYPTO + bool + depends on TEST_KCONFIG + depends on MODULE_ESP_IDF + help + Crypto code for ESP-IDF WPA supplicant. diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/eap_peer/Kconfig b/cpu/esp32/esp-idf/wpa_supplicant/src/eap_peer/Kconfig new file mode 100644 index 000000000000..cd96b13d6244 --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/eap_peer/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2021 HAW Hamburg +# +# 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. +# + +config MODULE_ESP_IDF_WPA_SUPPLICANT_RSN_SUPP + bool + depends on TEST_KCONFIG + depends on MODULE_ESP_IDF + help + RSN support code for ESP-IDF WPA supplicant. diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/rsn_supp/Kconfig b/cpu/esp32/esp-idf/wpa_supplicant/src/rsn_supp/Kconfig new file mode 100644 index 000000000000..4607821bcec1 --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/rsn_supp/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2021 HAW Hamburg +# +# 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. +# + +config MODULE_ESP_IDF_WPA_SUPPLICANT_AP + bool + depends on TEST_KCONFIG + depends on MODULE_ESP_IDF + help + AP code for ESP-IDF WPA supplicant. diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/tls/Kconfig b/cpu/esp32/esp-idf/wpa_supplicant/src/tls/Kconfig new file mode 100644 index 000000000000..b948f3574d70 --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/tls/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2021 HAW Hamburg +# +# 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. +# + +config MODULE_ESP_IDF_WPA_SUPPLICANT_TLS + bool + depends on TEST_KCONFIG + depends on MODULE_ESP_IDF + help + TLS code for ESP-IDF WPA supplicant. diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/utils/Kconfig b/cpu/esp32/esp-idf/wpa_supplicant/src/utils/Kconfig new file mode 100644 index 000000000000..70c8279df84a --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/utils/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2021 HAW Hamburg +# +# 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. +# + +config MODULE_ESP_IDF_WPA_SUPPLICANT_UTILS + bool + depends on TEST_KCONFIG + depends on MODULE_ESP_IDF + help + Utilities code for ESP-IDF WPA supplicant. diff --git a/cpu/esp32/esp-idf/wpa_supplicant/src/wps/Kconfig b/cpu/esp32/esp-idf/wpa_supplicant/src/wps/Kconfig new file mode 100644 index 000000000000..a8a58ac17338 --- /dev/null +++ b/cpu/esp32/esp-idf/wpa_supplicant/src/wps/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2021 HAW Hamburg +# +# 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. +# + +config MODULE_ESP_IDF_WPA_SUPPLICANT_WPS + bool + depends on TEST_KCONFIG + depends on MODULE_ESP_IDF + help + WPS code for ESP-IDF WPA supplicant. diff --git a/cpu/esp32/periph/Kconfig b/cpu/esp32/periph/Kconfig index ec121a59e278..3003eb3a45ae 100644 --- a/cpu/esp32/periph/Kconfig +++ b/cpu/esp32/periph/Kconfig @@ -14,11 +14,6 @@ config MODULE_ESP_RTC_TIMER_32K help Use RTC timer with external 32.768 kHz crystal as RTT. -config MODULE_PERIPH_ADC_CTRL - bool - depends on HAS_PERIPH_ADC_CTRL - default y if MODULE_PERIPH_ADC || MODULE_PERIPH_DAC - config MODULE_PERIPH_RTT_HW_SYS bool default y if MODULE_PERIPH_RTT @@ -29,6 +24,7 @@ config MODULE_PERIPH_RTT_HW_RTC config MODULE_ESP_HW_COUNTER bool "Use hardware counter" + depends on HAS_ESP_HW_COUNTER depends on MODULE_PERIPH_TIMER endif # TEST_KCONFIG From cff2d909d18769f3a0deb86341272275f774f9fe Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sat, 12 Mar 2022 15:40:51 +0100 Subject: [PATCH 40/46] cpu/esp32: port periph/cpu_id to ESP-IDF read_mac --- cpu/esp32/include/periph_cpu.h | 2 +- cpu/esp32/periph/cpuid.c | 33 ++++++++++++++++++--------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index b9c2faeb7c96..3208fee470af 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -59,7 +59,7 @@ extern "C" { /** * @brief Length of the CPU_ID in octets */ -#define CPUID_LEN (7U) +#define CPUID_LEN (6U) /** * @name GPIO configuration diff --git a/cpu/esp32/periph/cpuid.c b/cpu/esp32/periph/cpuid.c index 3ddf9a8a2d74..5799af54c9b4 100644 --- a/cpu/esp32/periph/cpuid.c +++ b/cpu/esp32/periph/cpuid.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2022 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 @@ -22,22 +22,25 @@ #include #include -#include "periph/cpuid.h" -#include "soc/efuse_reg.h" +#include "periph_cpu.h" +#include "esp_mac.h" + +/* + * ESP32x SoCs don't have a real chip id. The factory-programmed default MAC + * address from EFUSE is used instead. + */ void cpuid_get(void *id) { - /* since ESP32 has two cores, the default MAC address is used as CPU id */ - uint32_t rdata1 = REG_READ(EFUSE_BLK0_RDATA1_REG); - uint32_t rdata2 = REG_READ(EFUSE_BLK0_RDATA2_REG); - - uint8_t *tmp = id; +#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 */ + _Static_assert(CPUID_LEN == 8, + "CPUID_LEN hast to be 8 if IEEE 802.15.4 interface enabled"); +#else + _Static_assert(CPUID_LEN == 6, "CPU_ID_LEN hast to be 6"); +#endif - tmp[0] = rdata2 >> 16; - tmp[1] = rdata2 >> 8; - tmp[2] = rdata2; - tmp[3] = rdata1 >> 24; - tmp[4] = rdata1 >> 16; - tmp[5] = rdata1 >> 8; - tmp[6] = rdata1; + esp_efuse_mac_get_default(id); } From f2fcbcc7d374ff3074ad53074a1c2fde2dfb47f5 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sun, 20 Mar 2022 23:04:48 +0100 Subject: [PATCH 41/46] cpu/esp_common: inverse MCU_* conditionals to deal with ESP32 variants The MCU_* conditionals are inverted so that they can be tested for ESP8266. In all other cases the MCU is any ESP32x SoC. --- cpu/esp_common/thread_arch.c | 10 +++++----- makefiles/tools/esptool.inc.mk | 25 ++++++++++++------------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/cpu/esp_common/thread_arch.c b/cpu/esp_common/thread_arch.c index 27c006b570f2..96f6c3a92e3b 100644 --- a/cpu/esp_common/thread_arch.c +++ b/cpu/esp_common/thread_arch.c @@ -276,15 +276,15 @@ void IRAM_ATTR thread_yield_higher(void) } #endif if (!irq_is_in()) { -#ifdef MCU_ESP32 - /* generate the software interrupt to switch the context */ - DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, DPORT_CPU_INTR_FROM_CPU_0); -#else /* MCU_ESP32 */ +#ifdef MCU_ESP8266 critical_enter(); ets_soft_int_type = ETS_SOFT_INT_YIELD; WSR(BIT(ETS_SOFT_INUM), interrupt); critical_exit(); -#endif /* MCU_ESP32 */ +#else /* MCU_ESP8266 */ + /* generate the software interrupt to switch the context */ + DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, DPORT_CPU_INTR_FROM_CPU_0); +#endif /* MCU_ESP8266 */ } else { /* set the context switch flag */ diff --git a/makefiles/tools/esptool.inc.mk b/makefiles/tools/esptool.inc.mk index 97414561cb50..2b26de72bc23 100644 --- a/makefiles/tools/esptool.inc.mk +++ b/makefiles/tools/esptool.inc.mk @@ -1,14 +1,13 @@ -ifneq ($(CPU),esp32) - -ifneq (,$(filter esp_log_colored,$(USEMODULE))) - BOOTLOADER_COLOR = _colors -endif -ifneq (,$(filter esp_log_startup,$(USEMODULE))) - BOOTLOADER_INFO = _info -endif -# Full path to the bootloader binary. In the ESP32 case this is set by the -# esp_bootloader module. -BOOTLOADER_BIN ?= $(RIOTCPU)/$(CPU)/bin/bootloader$(BOOTLOADER_COLOR)$(BOOTLOADER_INFO).bin +ifeq ($(CPU),esp8266) + ifneq (,$(filter esp_log_colored,$(USEMODULE))) + BOOTLOADER_COLOR = _colors + endif + ifneq (,$(filter esp_log_startup,$(USEMODULE))) + BOOTLOADER_INFO = _info + endif + # Full path to the bootloader binary. In the ESP32 case this is set by the + # esp_bootloader module. + BOOTLOADER_BIN ?= $(RIOTCPU)/$(CPU)/bin/bootloader$(BOOTLOADER_COLOR)$(BOOTLOADER_INFO).bin endif ESPTOOL ?= $(RIOTTOOLS)/esptools/esptool.py @@ -33,7 +32,7 @@ endif .PHONY: esp-qemu esp-qemu: -ifneq (,$(filter esp32,$(CPU_FAM))) +ifneq (,$(filter esp32,$(CPU))) $(Q)echo \ "--flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) " \ "--flash_size $(FLASH_SIZE)MB" \ @@ -41,7 +40,7 @@ ifneq (,$(filter esp32,$(CPU_FAM))) "0x8000 $(BINDIR)/partitions.bin" \ "0x10000 $(FLASHFILE)" > $(BINDIR)/qemu_flash_args $(Q)$(ESPTOOL) \ - --chip esp32 merge_bin \ + --chip $(CPU_FAM) merge_bin \ --fill-flash-size 4MB \ -o $(BINDIR)/qemu_flash_image.bin @$(BINDIR)/qemu_flash_args $(Q)cp $(RIOTCPU)/$(CPU)/bin/rom_0x3ff90000_0x00010000.bin $(BINDIR)/rom1.bin From 156817e3199ee222e4368fbf82ec6491c2cfb399 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Tue, 22 Mar 2022 13:13:31 +0100 Subject: [PATCH 42/46] drivers/ws281x: use ESP-IDF CPU HAL --- drivers/ws281x/esp32.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/ws281x/esp32.c b/drivers/ws281x/esp32.c index ee4accdaf503..ba870902609f 100644 --- a/drivers/ws281x/esp32.c +++ b/drivers/ws281x/esp32.c @@ -12,7 +12,7 @@ * @{ * * @file - * @brief Implementation of `ws281x_write_buffer()` for the ESP32 CPU + * @brief Implementation of `ws281x_write_buffer()` for the ESP32x CPU * * @author Christian Friedrich Coors * @@ -27,19 +27,14 @@ #include "ws281x_params.h" #include "ws281x_constants.h" #include "periph_cpu.h" + #include "esp_private/esp_clk.h" -#include "xtensa/core-macros.h" +#include "hal/cpu_hal.h" #include "soc/rtc.h" #define ENABLE_DEBUG 0 #include "debug.h" -static inline __attribute__((always_inline)) uint32_t get_cycle_count(void) { - uint32_t ccount; - __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); - return ccount; -} - void ws281x_write_buffer(ws281x_t *dev, const void *buf, size_t size) { assert(dev); @@ -74,14 +69,14 @@ void ws281x_write_buffer(ws281x_t *dev, const void *buf, size_t size) on_wait = zero_on; off_wait = zero_off; } - start = get_cycle_count(); + start = cpu_hal_get_cycle_count(); gpio_set(dev->params.pin); current_wait = start + on_wait; - while (get_cycle_count() < current_wait) { } + while (cpu_hal_get_cycle_count() < current_wait) { } gpio_clear(dev->params.pin); - start = get_cycle_count(); + start = cpu_hal_get_cycle_count(); current_wait = start + off_wait; - while (get_cycle_count() < current_wait) { } + while (cpu_hal_get_cycle_count() < current_wait) { } data <<= 1; } pos++; From 761ac07db1e7dfd512656eb42997719aed992dc1 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sat, 4 Jun 2022 11:16:43 +0200 Subject: [PATCH 43/46] boards/esp32: PWM configuration cleanup --- boards/esp32-ethernet-kit-v1_0/include/periph_conf.h | 4 ---- boards/esp32-mh-et-live-minikit/include/periph_conf.h | 4 ---- boards/esp32-olimex-evb/include/periph_conf.h | 5 ----- boards/esp32-wemos-lolin-d32-pro/include/periph_conf.h | 4 ---- boards/esp32-wrover-kit/include/periph_conf.h | 4 ---- 5 files changed, 21 deletions(-) diff --git a/boards/esp32-ethernet-kit-v1_0/include/periph_conf.h b/boards/esp32-ethernet-kit-v1_0/include/periph_conf.h index d8f7682a9ab4..5c5663fef521 100644 --- a/boards/esp32-ethernet-kit-v1_0/include/periph_conf.h +++ b/boards/esp32-ethernet-kit-v1_0/include/periph_conf.h @@ -88,10 +88,6 @@ #endif #endif /* PWM0_GPIOS */ -/** PWM_DEV(1) is not used */ -#ifndef PWM1_GPIOS -#define PWM1_GPIOS { } -#endif /** @} */ /** diff --git a/boards/esp32-mh-et-live-minikit/include/periph_conf.h b/boards/esp32-mh-et-live-minikit/include/periph_conf.h index 719eb0490479..15fe2760aec1 100644 --- a/boards/esp32-mh-et-live-minikit/include/periph_conf.h +++ b/boards/esp32-mh-et-live-minikit/include/periph_conf.h @@ -101,10 +101,6 @@ #define PWM0_GPIOS { GPIO2, GPIO0, GPIO4, GPIO15 } #endif -/** PWM_DEV(1) is not used */ -#ifndef PWM1_GPIOS -#define PWM1_GPIOS { } -#endif /** @} */ /** diff --git a/boards/esp32-olimex-evb/include/periph_conf.h b/boards/esp32-olimex-evb/include/periph_conf.h index 6ab9fd4e6e40..3f3cfe610d65 100644 --- a/boards/esp32-olimex-evb/include/periph_conf.h +++ b/boards/esp32-olimex-evb/include/periph_conf.h @@ -134,14 +134,9 @@ extern "C" { #else #error Configuration problem: Flash mode qio or qout is used, \ GPIO9 and GPIO10 cannot be used as PWM channels as configured -#define PWM0_GPIOS { } #endif #endif -/** PWM_DEV(1) is not used */ -#ifndef PWM1_GPIOS -#define PWM1_GPIOS { } -#endif /** @} */ /** diff --git a/boards/esp32-wemos-lolin-d32-pro/include/periph_conf.h b/boards/esp32-wemos-lolin-d32-pro/include/periph_conf.h index 5c79d3ba134a..9b6ec7001d29 100644 --- a/boards/esp32-wemos-lolin-d32-pro/include/periph_conf.h +++ b/boards/esp32-wemos-lolin-d32-pro/include/periph_conf.h @@ -119,10 +119,6 @@ #define PWM0_GPIOS { GPIO0, GPIO2 } #endif -/** PWM_DEV(1) is not used */ -#ifndef PWM1_GPIOS -#define PWM1_GPIOS { } -#endif /** @} */ /** diff --git a/boards/esp32-wrover-kit/include/periph_conf.h b/boards/esp32-wrover-kit/include/periph_conf.h index acccc5a673ac..0b1010cdd931 100644 --- a/boards/esp32-wrover-kit/include/periph_conf.h +++ b/boards/esp32-wrover-kit/include/periph_conf.h @@ -127,10 +127,6 @@ #endif #endif -/** PWM_DEV(1) is not used */ -#ifndef PWM1_GPIOS -#define PWM1_GPIOS { } -#endif /** @} */ /** From ae31cb193cffa6df30ec99288289293418cdef07 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sat, 4 Jun 2022 11:19:31 +0200 Subject: [PATCH 44/46] cpu/esp32: doc changs for PWM --- cpu/esp32/doc.txt | 62 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/cpu/esp32/doc.txt b/cpu/esp32/doc.txt index 856165307500..86ac27471f02 100644 --- a/cpu/esp32/doc.txt +++ b/cpu/esp32/doc.txt @@ -99,6 +99,8 @@ Parameter | Short Description [I2C1_SDA](#esp32_i2c_interfaces) | GPIO used as SCL for I2C_DEV(1) | o [PWM0_GPIOS](#esp32_pwm_channels) | GPIOs that can be used at channels of PWM_DEV(0) | o [PWM1_GPIOS](#esp32_pwm_channels) | GPIOs that can be used at channels of PWM_DEV(1) | o +[PWM3_GPIOS](#esp32_pwm_channels) | GPIOs that can be used at channels of PWM_DEV(2) | o +[PWM4_GPIOS](#esp32_pwm_channels) | GPIOs that can be used at channels of PWM_DEV(3) | o [SPI0_CTRL](#esp32_spi_interfaces) | SPI Controller used for SPI_DEV(0), can be `VSPI` `HSPI` | o [SPI0_SCK](#esp32_spi_interfaces) | GPIO used as SCK for SPI_DEV(0) | o [SPI0_MOSI](#esp32_spi_interfaces) | GPIO used as MOSI for SPI_DEV(0) | o @@ -184,8 +186,8 @@ The key features of ESP32 are: | Ethernet | MAC interface with dedicated DMA and IEEE 1588 support | yes | | CAN | version 2.0 | yes | | IR | up to 8 channels TX/RX | no | -| Motor PWM | 2 devices x 6 channels | yes | -| LED PWM | 16 channels | no | +| Motor PWM | 2 devices x 6 channels | no | +| LED PWM | 16 channels | yes | | Crypto | Hardware acceleration of AES, SHA-2, RSA, ECC, RNG | no | | Vcc | 2.5 - 3.6 V | | | Documents | [Datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf)
[Technical Reference](https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf) | | @@ -810,6 +812,62 @@ waiting. ESP supports two types of PWM generators +The implementation of the PWM peripheral driver uses the LED PWM Controller +(LEDC) module of the ESP32x SoC. This LEDC module has one or two channel +groups with 6 or 8 channels each. The channels of each channel group can +use one of 4 timers as clock source. Thus, it is possible to define at +4 or 8 virtual PWM devices in RIOT with different frequencies and +resolutions. Regardless of whether the LEDC module of the ESP32x SoC has +one or two channel groups, the PWM driver implementation allows to organize +the available channels into up to 4 virtual PWM devices. + +The assignment of the available channels to the virtual PWM devices is +done in the board-specific peripheral configuration by defining the +macros `PWM0_GPIOS`, `PWM1_GPIOS`, `PWM2_GPIOS` and `PWM3_GPIOS` These +macros specify the GPIOs that are used as channels for the available +virtual PWM devices PWM_DEV(0) ... PWM_DEV(3) in RIOT. The mapping of +these channels to the available channel groups and channel group timers +is done by the driver automatically as follows: + +
+Macro | 1 Channel Group | 2 Channel Groups | Timer +-------------|-----------------------|------------------------|--------------- +`PWM0_GPIOS` | `LEDC_LOW_SPEED_MODE` | `LEDC_LOW_SPEED_MODE` | `LEDC_TIMER_0` +`PWM1_GPIOS` | `LEDC_LOW_SPEED_MODE` | `LEDC_HIGH_SPEED_MODE` | `LEDC_TIMER_1` +`PWM2_GPIOS` | `LEDC_LOW_SPEED_MODE` | `LEDC_LOW_SPEED_MODE` | `LEDC_TIMER_2` +`PWM3_GPIOS` | `LEDC_LOW_SPEED_MODE` | `LEDC_HIGH_SPEED_MODE` | `LEDC_TIMER_3` + +
+For example, if the LEDC module of the ESP32x SoC has two channel groups, +two virtual PWM devices with 2 x 6/8 channels could be used by defining +'PWM0_GPIOS' and 'PWM1_GPIOS' with up to 6 or 8 GPIOs each. + +Example: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c} +#define PWM0_GPIOS { GPIO0, GPIO2, GPIO4, GPIO16, GPIO17 } +#define PWM1_GPIOS { GPIO27, GPIO32, GPIO33 } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This configuration can be changed by +[application specific configurations](#esp32_application_specific_configurations). + +@note +- The total number of channels defined for a channel group must not exceed + #PWM_CH_NUMOF_MAX. +- The definition of `PWM0_GPIOS`, `PWM1_GPIOS`, `PWM2_GPIOS` and + `PWM3_GPIOS` can be omitted. In this case the existing macros should + be defined in ascending order, as the first defined macro is assigned + to PWM_DEV(0), the second defined macro is assigned to PWM_DEV(1) + and so on. So the minimal configuration would define all channels by + `PWM0_GPIOS` as PWM_DEV(0). +- #PWM_NUMOF is determined automatically. +- The order of the GPIOs in these macros determines the mapping between + RIOT's PWM channels and the GPIOs. +- As long as the GPIOs listed in `PWM0_GPIOS`, `PWM1_GPIOS`, + `PWM2_GPIOS` and `PWM3_GPIOS` are not initialized as PWM channels with + the #pwm_init function, they can be used for other purposes. + + - one LED PWM controller (LEDPWM) with 16 channels, and - two high-speed Motor Control PWM controllers (MCPWM) with 6 channels each. From 10c7a773f17354c16d59b7703f2afc7c93b5be02 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sun, 19 Jun 2022 14:03:56 +0200 Subject: [PATCH 45/46] fixup! cpu/esp32: port syscalls to ESP-IDF timer HAL --- cpu/esp32/syscalls.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpu/esp32/syscalls.c b/cpu/esp32/syscalls.c index c18954aadd11..040550ac845b 100644 --- a/cpu/esp32/syscalls.c +++ b/cpu/esp32/syscalls.c @@ -207,9 +207,7 @@ static struct syscall_stub_table s_stub_table = ._link_r = (void*)&_no_sys_func, ._rename_r = (void*)&_no_sys_func, -#if defined(MCU_ESP32) || \ - defined(MCU_ESP32S2) || \ - (defined(MCU_ESP32H2) && !defined(_RETARGETABLE_LOCKING)) +#if !defined(ESP_ROM_HAS_RETARGETABLE_LOCKING) ._lock_init = &_lock_init, ._lock_init_recursive = &_lock_init_recursive, ._lock_close = &_lock_close, From ebec3b1f22f0acd3deab5197384bf5f43443bb2e Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sun, 19 Jun 2022 17:02:58 +0200 Subject: [PATCH 46/46] fixup! cpu/esp32: port syscalls to ESP-IDF timer HAL --- cpu/esp32/Makefile.include | 1 + cpu/esp32/syscalls.c | 1 + 2 files changed, 2 insertions(+) diff --git a/cpu/esp32/Makefile.include b/cpu/esp32/Makefile.include index b7991075d09c..5719dfda8925 100644 --- a/cpu/esp32/Makefile.include +++ b/cpu/esp32/Makefile.include @@ -49,6 +49,7 @@ INCLUDES += -I$(ESP32_SDK_DIR)/components/driver/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_common/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/include/soc +INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_rom/$(CPU) INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_rom/include INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_rom/include/$(CPU) INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_system/include diff --git a/cpu/esp32/syscalls.c b/cpu/esp32/syscalls.c index 040550ac845b..7c2282e48f5f 100644 --- a/cpu/esp32/syscalls.c +++ b/cpu/esp32/syscalls.c @@ -30,6 +30,7 @@ #include "sys/lock.h" #include "timex.h" +#include "esp_rom_caps.h" #include "hal/interrupt_controller_types.h" #include "hal/interrupt_controller_ll.h" #include "hal/timer_hal.h"