mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
refactor(ulp): build the ULP coprocessor code as per-architecture components
A ULP program is built against ulp_riscv, lp_core or ulp_fsm, each stating its own sources, dependencies and memory layout. Sources shared with the driver stay in components/ulp.
This commit is contained in:
@@ -93,7 +93,7 @@ esp_err_t ulp_riscv_run(void);
|
||||
* Different than ULP FSM, the binary program has no special format, it is the ELF
|
||||
* file generated by RISC-V toolchain converted to binary format using objcopy.
|
||||
*
|
||||
* Linker script in components/ulp/ld/ulp_riscv.ld produces ELF files which
|
||||
* Linker script in components/ulp/subproject/components/ulp_riscv/ld/ulp_riscv.ld produces ELF files which
|
||||
* correspond to this format. This linker script produces binaries with load_addr == 0.
|
||||
*
|
||||
* @param program_binary pointer to program binary
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ulp_riscv_register_ops.h"
|
||||
#include "hal/adc_ll.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Start an ADC conversion and get the converted value.
|
||||
*
|
||||
* @note Will block until the conversion is completed
|
||||
*
|
||||
* @note ADC should be initialized for ULP by main CPU by calling ulp_riscv_adc_init()
|
||||
* before calling this.
|
||||
* @note When using ADC_UNIT_2, the caller must ensure that no other module (e.g., Wi-Fi or BT)
|
||||
* is accessing the ADC, as conflicts may lead to undefined behavior.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @param channel ADC channel number.
|
||||
*
|
||||
* @return Converted value, -1 if conversion failed
|
||||
*/
|
||||
int32_t ulp_riscv_adc_read_channel(adc_unit_t adc_n, int channel);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2010-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "ulp_riscv_register_ops.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "hal/rtc_io_ll.h"
|
||||
#include "ulp_riscv_interrupt.h"
|
||||
|
||||
typedef enum {
|
||||
ULP_RISCV_GPIO_INTR_DISABLE = 0, /*!< Disable RTC GPIO interrupt */
|
||||
ULP_RISCV_GPIO_INTR_POSEDGE = 1, /*!< RTC GPIO interrupt type : rising edge */
|
||||
ULP_RISCV_GPIO_INTR_NEGEDGE = 2, /*!< RTC GPIO interrupt type : falling edge */
|
||||
ULP_RISCV_GPIO_INTR_ANYEDGE = 3, /*!< RTC GPIO interrupt type : both rising and falling edge */
|
||||
ULP_RISCV_GPIO_INTR_LOW_LEVEL = 4, /*!< RTC GPIO interrupt type : input low level trigger */
|
||||
ULP_RISCV_GPIO_INTR_HIGH_LEVEL = 5, /*!< RTC GPIO interrupt type : input high level trigger */
|
||||
ULP_RISCV_GPIO_INTR_MAX
|
||||
} ulp_riscv_gpio_int_type_t;
|
||||
|
||||
typedef enum {
|
||||
RTCIO_MODE_OUTPUT = 0,
|
||||
RTCIO_MODE_OUTPUT_OD = 1,
|
||||
} rtc_io_out_mode_t;
|
||||
|
||||
static inline void ulp_riscv_gpio_init(gpio_num_t gpio_num)
|
||||
{
|
||||
#if SOC_LP_IO_CLOCK_IS_INDEPENDENT
|
||||
rtcio_ll_enable_io_clock(true);
|
||||
#endif
|
||||
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num * 4, RTC_IO_TOUCH_PAD0_MUX_SEL);
|
||||
REG_SET_FIELD(RTC_IO_TOUCH_PAD0_REG + gpio_num * 4, RTC_IO_TOUCH_PAD0_FUN_SEL, 0);
|
||||
}
|
||||
|
||||
static inline void ulp_riscv_gpio_deinit(gpio_num_t gpio_num)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num * 4, RTC_IO_TOUCH_PAD0_MUX_SEL);
|
||||
}
|
||||
|
||||
static inline void ulp_riscv_gpio_output_enable(gpio_num_t gpio_num)
|
||||
{
|
||||
REG_SET_FIELD(RTC_GPIO_ENABLE_W1TS_REG, RTC_GPIO_ENABLE_W1TS, BIT(gpio_num));
|
||||
}
|
||||
|
||||
static inline void ulp_riscv_gpio_output_disable(gpio_num_t gpio_num)
|
||||
{
|
||||
REG_SET_FIELD(RTC_GPIO_ENABLE_W1TC_REG, RTC_GPIO_ENABLE_W1TC, BIT(gpio_num));
|
||||
}
|
||||
|
||||
static inline void ulp_riscv_gpio_input_enable(gpio_num_t gpio_num)
|
||||
{
|
||||
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num * 4, RTC_IO_TOUCH_PAD0_FUN_IE);
|
||||
}
|
||||
|
||||
static inline void ulp_riscv_gpio_input_disable(gpio_num_t gpio_num)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num * 4, RTC_IO_TOUCH_PAD0_FUN_IE);
|
||||
}
|
||||
|
||||
static inline void ulp_riscv_gpio_output_level(gpio_num_t gpio_num, uint8_t level)
|
||||
{
|
||||
if (level) {
|
||||
REG_SET_FIELD(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS, BIT(gpio_num));
|
||||
} else {
|
||||
REG_SET_FIELD(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TS, BIT(gpio_num));
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint8_t ulp_riscv_gpio_get_level(gpio_num_t gpio_num)
|
||||
{
|
||||
return (uint8_t)((REG_GET_FIELD(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT) & BIT(gpio_num)) ? 1 : 0);
|
||||
}
|
||||
|
||||
static inline void ulp_riscv_gpio_set_output_mode(gpio_num_t gpio_num, rtc_io_out_mode_t mode)
|
||||
{
|
||||
REG_SET_FIELD(RTC_GPIO_PIN0_REG + gpio_num * 4, RTC_GPIO_PIN0_PAD_DRIVER, mode);
|
||||
}
|
||||
|
||||
static inline void ulp_riscv_gpio_pullup(gpio_num_t gpio_num)
|
||||
{
|
||||
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num * 4, RTC_IO_TOUCH_PAD0_RUE);
|
||||
}
|
||||
|
||||
static inline void ulp_riscv_gpio_pullup_disable(gpio_num_t gpio_num)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num * 4, RTC_IO_TOUCH_PAD0_RUE);
|
||||
}
|
||||
|
||||
static inline void ulp_riscv_gpio_pulldown(gpio_num_t gpio_num)
|
||||
{
|
||||
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num * 4, RTC_IO_TOUCH_PAD0_RDE);
|
||||
}
|
||||
|
||||
static inline void ulp_riscv_gpio_pulldown_disable(gpio_num_t gpio_num)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + gpio_num * 4, RTC_IO_TOUCH_PAD0_RDE);
|
||||
}
|
||||
|
||||
#if CONFIG_ULP_RISCV_INTERRUPT_ENABLE
|
||||
|
||||
/**
|
||||
* @brief Set RTC IO interrupt type and handler
|
||||
*
|
||||
* @param gpio_num GPIO number
|
||||
* @param intr_type Interrupt type (See rtc_io_types.h)
|
||||
* @param handler Interrupt handler
|
||||
* @param arg Interrupt handler argument
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t ulp_riscv_gpio_isr_register(gpio_num_t gpio_num, ulp_riscv_gpio_int_type_t intr_type, intr_handler_t handler, void *arg);
|
||||
|
||||
/**
|
||||
* @brief Remove RTC IO interrupt handler
|
||||
*
|
||||
* @param gpio_num GPIO number
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t ulp_riscv_gpio_isr_deregister(gpio_num_t gpio_num);
|
||||
|
||||
#endif /* CONFIG_ULP_RISCV_INTERRUPT_ENABLE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Set the I2C slave device address
|
||||
*
|
||||
* @param slave_addr I2C slave address (7 bit)
|
||||
*/
|
||||
void ulp_riscv_i2c_master_set_slave_addr(uint8_t slave_addr);
|
||||
|
||||
/**
|
||||
* @brief Set the I2C slave device sub register address
|
||||
*
|
||||
* @param slave_reg_addr I2C slave register address
|
||||
*/
|
||||
void ulp_riscv_i2c_master_set_slave_reg_addr(uint8_t slave_reg_addr);
|
||||
|
||||
/**
|
||||
* @brief Read from I2C slave device
|
||||
*
|
||||
* @note The I2C slave device address must be configured at least once before invoking this API.
|
||||
*
|
||||
* @param data_rd Buffer to hold data to be read
|
||||
* @param size Size of data to be read in bytes
|
||||
* @return esp_err_t ESP_OK when successful
|
||||
*/
|
||||
esp_err_t ulp_riscv_i2c_master_read_from_device(uint8_t *data_rd, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Write to I2C slave device
|
||||
*
|
||||
* @note The I2C slave device address must be configured at least once before invoking this API.
|
||||
*
|
||||
* @param data_wr Buffer which holds the data to be written
|
||||
* @param size Size of data to be written in bytes
|
||||
* @return esp_err_t ESP_OK when successful
|
||||
*/
|
||||
esp_err_t ulp_riscv_i2c_master_write_to_device(const uint8_t *data_wr, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "riscv/interrupt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if CONFIG_ULP_RISCV_INTERRUPT_ENABLE
|
||||
|
||||
/* ULP RISC-V Interrupt sources */
|
||||
typedef enum {
|
||||
ULP_RISCV_SW_INTR_SOURCE = 0, /**< Interrupt triggered by SW */
|
||||
ULP_RISCV_RTCIO0_INTR_SOURCE, /**< Interrupt triggered by RTCIO 0 */
|
||||
ULP_RISCV_RTCIO1_INTR_SOURCE, /**< Interrupt triggered by RTCIO 1 */
|
||||
ULP_RISCV_RTCIO2_INTR_SOURCE, /**< Interrupt triggered by RTCIO 2 */
|
||||
ULP_RISCV_RTCIO3_INTR_SOURCE, /**< Interrupt triggered by RTCIO 3 */
|
||||
ULP_RISCV_RTCIO4_INTR_SOURCE, /**< Interrupt triggered by RTCIO 4 */
|
||||
ULP_RISCV_RTCIO5_INTR_SOURCE, /**< Interrupt triggered by RTCIO 5 */
|
||||
ULP_RISCV_RTCIO6_INTR_SOURCE, /**< Interrupt triggered by RTCIO 6 */
|
||||
ULP_RISCV_RTCIO7_INTR_SOURCE, /**< Interrupt triggered by RTCIO 7 */
|
||||
ULP_RISCV_RTCIO8_INTR_SOURCE, /**< Interrupt triggered by RTCIO 8 */
|
||||
ULP_RISCV_RTCIO9_INTR_SOURCE, /**< Interrupt triggered by RTCIO 9 */
|
||||
ULP_RISCV_RTCIO10_INTR_SOURCE, /**< Interrupt triggered by RTCIO 10 */
|
||||
ULP_RISCV_RTCIO11_INTR_SOURCE, /**< Interrupt triggered by RTCIO 11 */
|
||||
ULP_RISCV_RTCIO12_INTR_SOURCE, /**< Interrupt triggered by RTCIO 12 */
|
||||
ULP_RISCV_RTCIO13_INTR_SOURCE, /**< Interrupt triggered by RTCIO 13 */
|
||||
ULP_RISCV_RTCIO14_INTR_SOURCE, /**< Interrupt triggered by RTCIO 14 */
|
||||
ULP_RISCV_RTCIO15_INTR_SOURCE, /**< Interrupt triggered by RTCIO 15 */
|
||||
ULP_RISCV_RTCIO16_INTR_SOURCE, /**< Interrupt triggered by RTCIO 16 */
|
||||
ULP_RISCV_RTCIO17_INTR_SOURCE, /**< Interrupt triggered by RTCIO 17 */
|
||||
ULP_RISCV_RTCIO18_INTR_SOURCE, /**< Interrupt triggered by RTCIO 18 */
|
||||
ULP_RISCV_RTCIO19_INTR_SOURCE, /**< Interrupt triggered by RTCIO 19 */
|
||||
ULP_RISCV_RTCIO20_INTR_SOURCE, /**< Interrupt triggered by RTCIO 20 */
|
||||
ULP_RISCV_RTCIO21_INTR_SOURCE, /**< Interrupt triggered by RTCIO 21 */
|
||||
ULP_RISCV_MAX_INTR_SOURCE, /**< Total number of ULP RISC-V interrupt sources */
|
||||
} ulp_riscv_interrupt_source_t;
|
||||
|
||||
/**
|
||||
* @brief Allocate interrupt handler for a ULP RISC-V interrupt source
|
||||
*
|
||||
* @param source ULP RISC-V interrupt source
|
||||
* @param handler Interrupt handler
|
||||
* @param arg Interrupt handler argument
|
||||
*
|
||||
* @return esp_err_t ESP_OK when successful
|
||||
*/
|
||||
esp_err_t ulp_riscv_intr_alloc(ulp_riscv_interrupt_source_t source, intr_handler_t handler, void *arg);
|
||||
|
||||
/**
|
||||
* @brief Free ULP RISC-V interrupt handler
|
||||
*
|
||||
* @param source ULP RISC-V interrupt source
|
||||
*
|
||||
* @return esp_err_t ESP_OK when successful
|
||||
*/
|
||||
esp_err_t ulp_riscv_intr_free(ulp_riscv_interrupt_source_t source);
|
||||
|
||||
#endif /* CONFIG_ULP_RISCV_INTERRUPT_ENABLE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Claire Xenia Wolf <claire@yosyshq.com>
|
||||
* SPDX-FileContributor: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This header file defines custom instructions for interrupt handling on the
|
||||
* ULP RISC-V. The architecture of the processor and therefore, the interrupt
|
||||
* handling is based on the PicoRV32 CPU. Details about the operations are
|
||||
* available at https://github.com/YosysHQ/picorv32#custom-instructions-for-irq-handling
|
||||
*/
|
||||
|
||||
/* Define encoding for all general purpose RISC-V registers */
|
||||
#define regnum_zero 0
|
||||
#define regnum_ra 1
|
||||
#define regnum_sp 2
|
||||
#define regnum_gp 3
|
||||
#define regnum_tp 4
|
||||
#define regnum_t0 5
|
||||
#define regnum_t1 6
|
||||
#define regnum_t2 7
|
||||
#define regnum_s0 8
|
||||
#define regnum_s1 9
|
||||
#define regnum_a0 10
|
||||
#define regnum_a1 11
|
||||
#define regnum_a2 12
|
||||
#define regnum_a3 13
|
||||
#define regnum_a4 14
|
||||
#define regnum_a5 15
|
||||
#define regnum_a6 16
|
||||
#define regnum_a7 17
|
||||
#define regnum_s2 18
|
||||
#define regnum_s3 19
|
||||
#define regnum_s4 20
|
||||
#define regnum_s5 21
|
||||
#define regnum_s6 22
|
||||
#define regnum_s7 23
|
||||
#define regnum_s8 24
|
||||
#define regnum_s9 25
|
||||
#define regnum_s10 26
|
||||
#define regnum_s11 27
|
||||
#define regnum_t3 28
|
||||
#define regnum_t4 29
|
||||
#define regnum_t5 30
|
||||
#define regnum_t6 31
|
||||
|
||||
/* Define encoding for special interrupt handling registers, viz., q0, q1, q2 and q3 */
|
||||
#define regnum_q0 0
|
||||
#define regnum_q1 1
|
||||
#define regnum_q2 2
|
||||
#define regnum_q3 3
|
||||
|
||||
/* All custom interrupt handling instructions follow the standard R-type instruction format from RISC-V ISA
|
||||
* with the same opcode of custom0 (0001011).
|
||||
*/
|
||||
#define r_type_insn(_f7, _rs2, _rs1, _f3, _rd, _opc) \
|
||||
.word (((_f7) << 25) | ((_rs2) << 20) | ((_rs1) << 15) | ((_f3) << 12) | ((_rd) << 7) | ((_opc) << 0))
|
||||
|
||||
/**
|
||||
* Instruction: getq rd, qs
|
||||
* Description: This instruction copies the value of Qx into a general purpose register rd
|
||||
*/
|
||||
#define getq_insn(_rd, _qs) \
|
||||
r_type_insn(0b0000000, 0, regnum_ ## _qs, 0b100, regnum_ ## _rd, 0b0001011)
|
||||
|
||||
/**
|
||||
* Instruction: setq qd, rs
|
||||
* Description: This instruction copies the value of general purpose register rs to Qx
|
||||
*/
|
||||
#define setq_insn(_qd, _rs) \
|
||||
r_type_insn(0b0000001, 0, regnum_ ## _rs, 0b010, regnum_ ## _qd, 0b0001011)
|
||||
|
||||
/**
|
||||
* Instruction: retirq
|
||||
* Description: This instruction copies the value of Q0 to CPU PC, and renables interrupts
|
||||
*/
|
||||
#define retirq_insn() \
|
||||
r_type_insn(0b0000010, 0, 0, 0b000, 0, 0b0001011)
|
||||
|
||||
/**
|
||||
* Instruction: maskirq rd, rs
|
||||
* Description: This instruction copies the value of the register IRQ Mask to the register rd, and copies the value
|
||||
* of register rs to to IRQ mask.
|
||||
*/
|
||||
#define maskirq_insn(_rd, _rs) \
|
||||
r_type_insn(0b0000011, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ulp_riscv_lock_shared.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Locks are based on the Peterson's algorithm, https://en.wikipedia.org/wiki/Peterson%27s_algorithm
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Acquire the lock, preventing the main CPU from taking until released. Spins until lock is acquired.
|
||||
*
|
||||
* @note The lock is only designed for being used by a single thread on the ULP,
|
||||
* it is not safe to try to acquire it from multiple threads.
|
||||
*
|
||||
* @param lock Pointer to lock struct, shared with main CPU
|
||||
*/
|
||||
void ulp_riscv_lock_acquire(ulp_riscv_lock_t *lock);
|
||||
|
||||
/**
|
||||
* @brief Release the lock
|
||||
*
|
||||
* @param lock Pointer to lock struct, shared with main CPU
|
||||
*/
|
||||
void ulp_riscv_lock_release(ulp_riscv_lock_t *lock);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Underlying driver function for printing a char, e.g. over UART */
|
||||
typedef void (*putc_fn_t)(const void *ctx, const char c);
|
||||
|
||||
/**
|
||||
* @brief Installs a print driver that will be used for ulp_riscv_print calls
|
||||
*
|
||||
* @param putc Underlying driver function for printing a char, e.g. over UART
|
||||
* @param putc_ctx Context that will be passed when calling the putc function
|
||||
*/
|
||||
void ulp_riscv_print_install(putc_fn_t putc, void *putc_ctx);
|
||||
|
||||
/**
|
||||
* @brief Prints a null-terminated string
|
||||
*
|
||||
* @param str String to print
|
||||
*/
|
||||
void ulp_riscv_print_str(const char *str);
|
||||
|
||||
/**
|
||||
* @brief Prints a hex number. Does not print 0x, only the digits
|
||||
*
|
||||
* @param Hex number to print
|
||||
*/
|
||||
void ulp_riscv_print_hex(int h);
|
||||
|
||||
/**
|
||||
* @brief Prints a hex number with the specified number of digits. Does not print 0x, only the digits
|
||||
*
|
||||
* @param Hex number to print
|
||||
* @param number_of_digits Number of digits to print.
|
||||
*/
|
||||
void ulp_riscv_print_hex_with_number_of_digits(int h, int number_of_digits);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//Registers Operation {{
|
||||
|
||||
/*
|
||||
* When COCPU accesses the RTC register, it needs to convert the access address.
|
||||
* When COCPU accesses the RTC memory, dont need to convert the access address.
|
||||
*/
|
||||
#define WRITE_RTC_MEM(addr, val) (*((volatile int*)(addr))) = (int) (val)
|
||||
#define READ_RTC_MEM(addr) (*(volatile int*)(addr))
|
||||
|
||||
/*
|
||||
* When COCPU accesses the RTC register, it needs to convert the access address.
|
||||
* When COCPU accesses the RTC memory, dont need to convert the access address.
|
||||
*/
|
||||
#define RISCV_REG_CONV(addr) (((addr&0xffff)<<3 & 0xe000) | (addr & 0x1fff) | 0x8000)
|
||||
#define ETS_UNCACHED_ADDR(addr) (RISCV_REG_CONV(addr))
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#define BIT(nr) (1UL << (nr))
|
||||
#else
|
||||
#define BIT(nr) (1 << (nr))
|
||||
#endif
|
||||
|
||||
//write value to register
|
||||
#define REG_WRITE(_r, _v) ({ \
|
||||
(*(volatile uint32_t *)RISCV_REG_CONV(_r)) = (_v); \
|
||||
})
|
||||
|
||||
//read value from register
|
||||
#define REG_READ(_r) ({ \
|
||||
(*(volatile uint32_t *)RISCV_REG_CONV(_r)); \
|
||||
})
|
||||
|
||||
//get bit or get bits from register
|
||||
#define REG_GET_BIT(_r, _b) ({ \
|
||||
(*(volatile uint32_t*)RISCV_REG_CONV(_r) & (_b)); \
|
||||
})
|
||||
|
||||
//set bit or set bits to register
|
||||
#define REG_SET_BIT(_r, _b) ({ \
|
||||
(*(volatile uint32_t*)RISCV_REG_CONV(_r) |= (_b)); \
|
||||
})
|
||||
|
||||
//clear bit or clear bits of register
|
||||
#define REG_CLR_BIT(_r, _b) ({ \
|
||||
(*(volatile uint32_t*)RISCV_REG_CONV(_r) &= ~(_b)); \
|
||||
})
|
||||
|
||||
//set bits of register controlled by mask
|
||||
#define REG_SET_BITS(_r, _b, _m) ({ \
|
||||
(*(volatile uint32_t*)RISCV_REG_CONV(_r) = (*(volatile uint32_t*)RISCV_REG_CONV(_r) & ~(_m)) | ((_b) & (_m))); \
|
||||
})
|
||||
|
||||
//get field from register, uses field _S & _V to determine mask
|
||||
#define REG_GET_FIELD(_r, _f) ({ \
|
||||
((REG_READ(_r) >> (_f##_S)) & (_f##_V)); \
|
||||
})
|
||||
|
||||
//set field of a register from variable, uses field _S & _V to determine mask
|
||||
#define REG_SET_FIELD(_r, _f, _v) ({ \
|
||||
(REG_WRITE((_r),((REG_READ(_r) & ~((_f##_V) << (_f##_S)))|(((_v) & (_f##_V))<<(_f##_S))))); \
|
||||
})
|
||||
|
||||
//get field value from a variable, used when _f is not left shifted by _f##_S
|
||||
#define VALUE_GET_FIELD(_r, _f) (((_r) >> (_f##_S)) & (_f))
|
||||
|
||||
//get field value from a variable, used when _f is left shifted by _f##_S
|
||||
#define VALUE_GET_FIELD2(_r, _f) (((_r) & (_f))>> (_f##_S))
|
||||
|
||||
//set field value to a variable, used when _f is not left shifted by _f##_S
|
||||
#define VALUE_SET_FIELD(_r, _f, _v) ((_r)=(((_r) & ~((_f) << (_f##_S)))|((_v)<<(_f##_S))))
|
||||
|
||||
//set field value to a variable, used when _f is left shifted by _f##_S
|
||||
#define VALUE_SET_FIELD2(_r, _f, _v) ((_r)=(((_r) & ~(_f))|((_v)<<(_f##_S))))
|
||||
|
||||
//generate a value from a field value, used when _f is not left shifted by _f##_S
|
||||
#define FIELD_TO_VALUE(_f, _v) (((_v)&(_f))<<_f##_S)
|
||||
|
||||
//generate a value from a field value, used when _f is left shifted by _f##_S
|
||||
#define FIELD_TO_VALUE2(_f, _v) (((_v)<<_f##_S) & (_f))
|
||||
|
||||
//read value from register
|
||||
#define READ_PERI_REG(addr) ({ \
|
||||
(*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr))); \
|
||||
})
|
||||
|
||||
//write value to register
|
||||
#define WRITE_PERI_REG(addr, val) ({ \
|
||||
(*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr))) = (uint32_t)(val); \
|
||||
})
|
||||
|
||||
//clear bits of register controlled by mask
|
||||
#define CLEAR_PERI_REG_MASK(reg, mask) ({ \
|
||||
WRITE_PERI_REG((reg), (READ_PERI_REG(reg)&(~(mask)))); \
|
||||
})
|
||||
|
||||
//set bits of register controlled by mask
|
||||
#define SET_PERI_REG_MASK(reg, mask) ({ \
|
||||
WRITE_PERI_REG((reg), (READ_PERI_REG(reg)|(mask))); \
|
||||
})
|
||||
|
||||
//get bits of register controlled by mask
|
||||
#define GET_PERI_REG_MASK(reg, mask) ({ \
|
||||
(READ_PERI_REG(reg) & (mask)); \
|
||||
})
|
||||
|
||||
//get bits of register controlled by highest bit and lowest bit
|
||||
// #define GET_PERI_REG_BITS(reg, hipos,lowpos) ({
|
||||
// ASSERT_IF_DPORT_REG((reg), GET_PERI_REG_BITS);
|
||||
// ((READ_PERI_REG(reg)>>(lowpos))&((1UL<<((hipos)-(lowpos)+1))-1));
|
||||
// })
|
||||
#define GET_PERI_REG_BITS(reg, bit_map, shift) ((READ_PERI_REG(reg))&((bit_map)<<(shift)))>>shift
|
||||
|
||||
//set bits of register controlled by mask and shift
|
||||
#define SET_PERI_REG_BITS(reg,bit_map,value,shift) ({ \
|
||||
(WRITE_PERI_REG((reg),(READ_PERI_REG(reg)&(~((bit_map)<<(shift))))|(((value) & bit_map)<<(shift)) )); \
|
||||
})
|
||||
|
||||
//get field of register
|
||||
#define GET_PERI_REG_BITS2(reg, mask,shift) ({ \
|
||||
((READ_PERI_REG(reg)>>(shift))&(mask)); \
|
||||
})
|
||||
//}}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "ulp_riscv_register_ops.h"
|
||||
#include "hal/touch_sens_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Read raw data of touch sensor on the ULP RISC-V core
|
||||
* @note Refer `touch_pad_read_raw_data()` for more details
|
||||
*
|
||||
* @param touch_num Touch pad index
|
||||
* @param raw_data Pointer to accept touch sensor value
|
||||
* @return esp_err_t ESP_OK when successful
|
||||
*/
|
||||
esp_err_t ulp_riscv_touch_pad_read_raw_data(int touch_num, uint32_t *raw_data);
|
||||
|
||||
/**
|
||||
* @brief Read benchmark of touch sensor on the ULP RISC-V core
|
||||
* @note Refer `touch_pad_read_benchmark()` for more details
|
||||
*
|
||||
* @param touch_num Touch pad index
|
||||
* @param benchmark Pointer to accept touch sensor benchmark value
|
||||
* @return esp_err_t ESP_OK when successful
|
||||
*/
|
||||
esp_err_t ulp_riscv_touch_pad_read_benchmark(int touch_num, uint32_t *benchmark);
|
||||
|
||||
/**
|
||||
* @brief Read the filtered (smoothened) touch sensor data on the ULP RISC-V core
|
||||
* @note Refer `touch_pad_filter_read_smooth()` for more details
|
||||
*
|
||||
* @param touch_num Touch pad index
|
||||
* @param smooth_data Pointer to accept smoothened touch sensor value
|
||||
* @return esp_err_t ESP_OK when successful
|
||||
*/
|
||||
esp_err_t ulp_riscv_touch_pad_filter_read_smooth(int touch_num, uint32_t *smooth_data);
|
||||
|
||||
/**
|
||||
* @brief Force reset benchmark to raw data of touch sensor.
|
||||
* @note Refer `touch_pad_reset_benchmark()` for more details
|
||||
*
|
||||
* @param touch_num Touch pad index (TOUCH_PAD_MAX resets baseline of all channels)
|
||||
* @return esp_err_t ESP_OK when successful
|
||||
*/
|
||||
esp_err_t ulp_riscv_touch_pad_reset_benchmark(int touch_num);
|
||||
|
||||
/**
|
||||
* @brief Read raw data of touch sensor sleep channel on the ULP RISC-V core
|
||||
* @note Refer `touch_pad_sleep_channel_read_data()` for more details
|
||||
*
|
||||
* @param touch_num Touch pad index (Only one touch sensor channel is supported in deep sleep)
|
||||
* @param raw_data Pointer to accept touch sensor value
|
||||
* @return esp_err_t ESP_OK when successful
|
||||
*/
|
||||
esp_err_t ulp_riscv_touch_pad_sleep_channel_read_data(int touch_num, uint32_t *raw_data);
|
||||
|
||||
/**
|
||||
* @brief Read benchmark of touch sensor sleep channel on the ULP RISC-V core
|
||||
* @note Refer `touch_pad_sleep_channel_read_benchmark()` for more details
|
||||
*
|
||||
* @param touch_num Touch pad index (Only one touch sensor channel is supported in deep sleep)
|
||||
* @param benchmark Pointer to accept touch sensor benchmark value
|
||||
* @return esp_err_t ESP_OK when successful
|
||||
*/
|
||||
esp_err_t ulp_riscv_touch_pad_sleep_channel_read_benchmark(int touch_num, uint32_t *benchmark);
|
||||
|
||||
/**
|
||||
* @brief Read the filtered (smoothened) touch sensor sleep channel data on the ULP RISC-V core
|
||||
* @note Refer `touch_pad_sleep_channel_read_smooth()` for more details
|
||||
*
|
||||
* @param touch_num Touch pad index (Only one touch sensor channel is supported in deep sleep)
|
||||
* @param smooth_data Pointer to accept smoothened touch sensor value
|
||||
* @return esp_err_t ESP_OK when successful
|
||||
*/
|
||||
esp_err_t ulp_riscv_touch_pad_sleep_channel_read_smooth(int touch_num, uint32_t *smooth_data);
|
||||
|
||||
/**
|
||||
* @brief Reset benchmark of touch sensor sleep channel.
|
||||
* @note Refer `touch_pad_sleep_channel_reset_benchmark()` for more details
|
||||
*
|
||||
* @return esp_err_t ESP_OK when successful
|
||||
*/
|
||||
esp_err_t ulp_riscv_touch_pad_sleep_channel_reset_benchmark(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ulp_riscv_gpio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
gpio_num_t tx_pin; // TX pin number
|
||||
} ulp_riscv_uart_cfg_t; // Config for the driver
|
||||
|
||||
typedef struct {
|
||||
uint32_t bit_duration_cycles; // Number of cycles to hold the line for each bit
|
||||
gpio_num_t tx_pin; // TX pin number
|
||||
} ulp_riscv_uart_t; // Context for the driver, initialized by ulp_riscv_uart_init
|
||||
|
||||
/**
|
||||
* @brief Initialize the bit-banged UART driver
|
||||
*
|
||||
* @note Will also initialize the underlying HW, i.e. the RTC GPIO used.
|
||||
*
|
||||
* @param uart Pointer to the struct that will contain the initialized context
|
||||
* @param cfg Pointer to the config struct which will be used to initialize the driver
|
||||
*/
|
||||
void ulp_riscv_uart_init(ulp_riscv_uart_t *uart, const ulp_riscv_uart_cfg_t *cfg);
|
||||
|
||||
/**
|
||||
* @brief Outputs a single byte on the tx pin
|
||||
*
|
||||
* @param uart Pointer to the initialized driver context
|
||||
* @param c Byte to output
|
||||
*/
|
||||
void ulp_riscv_uart_putc(const ulp_riscv_uart_t *uart, const char c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,219 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ulp_riscv_register_ops.h"
|
||||
#include "ulp_riscv_interrupt.h"
|
||||
#include "ulp_riscv_cpu_freq_shared.h"
|
||||
|
||||
/**
|
||||
* @brief Wakeup main CPU from sleep or deep sleep.
|
||||
*
|
||||
* This raises a software interrupt signal, if the
|
||||
* main CPU has configured the ULP as a wakeup source
|
||||
* calling this function will make the main CPU to
|
||||
* exit from sleep or deep sleep.
|
||||
*/
|
||||
void ulp_riscv_wakeup_main_processor(void);
|
||||
|
||||
/**
|
||||
* @brief Rescues the cpu from monitor mode
|
||||
*
|
||||
* This function cancels the low power mode
|
||||
* of the ULP-RISC-V, should be called
|
||||
* every time the co-processor starts.
|
||||
*
|
||||
* @note by convenience this function is
|
||||
* automatically called in startup code.
|
||||
*/
|
||||
void ulp_riscv_rescue_from_monitor(void);
|
||||
|
||||
/**
|
||||
* @brief Finishes the ULP program and powers down the ULP
|
||||
* until next wakeup.
|
||||
*
|
||||
* @note This function does not return. After called it will
|
||||
* fully reset the ULP.
|
||||
*
|
||||
* @note Returning from main() in the ULP program results on
|
||||
* calling this function.
|
||||
*
|
||||
* @note To stop the ULP from waking up, call ulp_riscv_timer_stop()
|
||||
* before halting.
|
||||
*
|
||||
* This function should be called after the ULP program Finishes
|
||||
* its processing, it will trigger the timer for the next wakeup,
|
||||
* put the ULP in monitor mode and triggers a reset.
|
||||
*
|
||||
*/
|
||||
void __attribute__((__noreturn__)) ulp_riscv_halt(void);
|
||||
|
||||
#define ulp_riscv_shutdown ulp_riscv_halt
|
||||
|
||||
/**
|
||||
* @brief Stop the ULP timer
|
||||
*
|
||||
* @note This will stop the ULP from waking up if halted, but will not abort any program
|
||||
* currently executing on the ULP.
|
||||
*/
|
||||
void ulp_riscv_timer_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Resumes the ULP timer
|
||||
*
|
||||
* @note This will resume an already configured timer, but does no other configuration
|
||||
*
|
||||
*/
|
||||
void ulp_riscv_timer_resume(void);
|
||||
|
||||
#define ULP_RISCV_GET_CCOUNT() ({ int __ccount; \
|
||||
asm volatile("rdcycle %0;" : "=r"(__ccount)); \
|
||||
__ccount; })
|
||||
|
||||
#define ULP_RISCV_CYCLES_PER_US ULP_RISCV_CYCLES_PER_US_NUM / ULP_RISCV_CYCLES_PER_US_DENOM
|
||||
#define ULP_RISCV_CYCLES_PER_MS 1000U * ULP_RISCV_CYCLES_PER_US
|
||||
|
||||
/**
|
||||
* @brief Retrieves the current number of CPU cycles.
|
||||
*
|
||||
* @return The current CPU cycle count.
|
||||
*/
|
||||
static inline uint32_t ulp_riscv_get_cpu_cycles(void)
|
||||
{
|
||||
return ULP_RISCV_GET_CCOUNT();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether an mcycle-based timeout has elapsed.
|
||||
*
|
||||
* @note A timeout value of -1 means "wait forever".
|
||||
* Other values are interpreted as unsigned cycle counts.
|
||||
*
|
||||
* @param start_cycle_count Cycle counter value captured at timeout start.
|
||||
* @param cycles_to_wait Timeout in CPU cycles, or -1 to disable timeout.
|
||||
*
|
||||
* @return true if timeout elapsed, false otherwise.
|
||||
*/
|
||||
static inline bool ulp_riscv_is_timeout_elapsed(uint32_t start_cycle_count, int32_t cycles_to_wait)
|
||||
{
|
||||
if (cycles_to_wait == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (ulp_riscv_get_cpu_cycles() - start_cycle_count) >= (uint32_t)cycles_to_wait;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Makes the co-processor busy-wait for a certain number of CPU cycles.
|
||||
*
|
||||
* @note This function is not accurate for delays shorter than 20 cycles because the
|
||||
* function overhead may exceed the requested delay.
|
||||
*
|
||||
* @note The maximum supported delay is 0x7FFFFFFF cycles.
|
||||
* For larger values, the behavior is undefined. Split longer delays into smaller
|
||||
* chunks if needed.
|
||||
*
|
||||
* For reference, this corresponds approximately to:
|
||||
* - ESP32-S2 ULP-RISC-V @ 8.5 MHz: 0x7FFFFFFF cycles ≈ 252.645 s
|
||||
* - ESP32-S3 ULP-RISC-V @ 17.5 MHz: 0x7FFFFFFF cycles ≈ 122.713 s
|
||||
*
|
||||
* @param cycles Number of cycles to busy-wait.
|
||||
*/
|
||||
static inline void ulp_riscv_delay_cycles(uint32_t cycles)
|
||||
{
|
||||
if (cycles <= 20U) { // estimate of cycles for this function overhead
|
||||
return;
|
||||
}
|
||||
// To improve accuracy subtract (20 + 15) cycles overhead, defined by delay calibration test
|
||||
uint32_t start = ULP_RISCV_GET_CCOUNT() - 20U - 15U;
|
||||
while ((uint32_t)(ULP_RISCV_GET_CCOUNT() - start) < cycles) {
|
||||
/* busy wait */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Makes the co-processor busy-wait for a certain number of microseconds.
|
||||
*
|
||||
* @note This function is not accurate for short delays because the function overhead
|
||||
* may exceed the requested delay. For very small delays the implementation uses
|
||||
* a fixed sequence of NOPs (chip-dependent thresholds).
|
||||
*
|
||||
* @note The maximum supported delay depends on the ULP-RISC-V cycle counter width and on
|
||||
* the internal cycles-per-microsecond conversion. For values above the limits below,
|
||||
* the computed delay may overflow and the result is undefined.
|
||||
* - ESP32-S2 ULP-RISC-V @ 8.5 MHz: delay_us must be <= 252645135 (about 252.6 s)
|
||||
* - ESP32-S3 ULP-RISC-V @ 17.5 MHz: delay_us must be <= 122713351 (about 122.7 s)
|
||||
*
|
||||
* @param delay_us Number of microseconds to busy wait.
|
||||
*/
|
||||
void ulp_riscv_delay_us(uint32_t delay_us);
|
||||
|
||||
/**
|
||||
* @brief Clears the GPIO wakeup interrupt bit
|
||||
*
|
||||
*/
|
||||
void ulp_riscv_gpio_wakeup_clear(void);
|
||||
|
||||
#if CONFIG_ULP_RISCV_INTERRUPT_ENABLE
|
||||
/**
|
||||
* @brief Enable ULP RISC-V SW Interrupt
|
||||
*
|
||||
* @param handler Interrupt handler
|
||||
* @param arg Interrupt handler argument
|
||||
*/
|
||||
void ulp_riscv_enable_sw_intr(intr_handler_t handler, void *arg);
|
||||
|
||||
/**
|
||||
* @brief Disable ULP RISC-V SW Interrupt
|
||||
*/
|
||||
void ulp_riscv_disable_sw_intr(void);
|
||||
|
||||
/**
|
||||
* @brief Trigger ULP RISC-V SW Interrupt
|
||||
*
|
||||
* @note The SW interrupt will only trigger if it has been enabled previously using ulp_riscv_enable_sw_intr().
|
||||
*/
|
||||
void ulp_riscv_trigger_sw_intr(void);
|
||||
|
||||
/**
|
||||
* @brief Enter a critical section by disabling all interrupts
|
||||
* This inline assembly construct uses the t0 register and is equivalent to:
|
||||
*
|
||||
* li t0, 0x80000007
|
||||
* maskirq_insn(zero, t0) // Mask all interrupt bits
|
||||
*/
|
||||
#define ULP_RISCV_ENTER_CRITICAL() \
|
||||
asm volatile ( \
|
||||
"li t0, 0x80000007\n" \
|
||||
".word 0x0602e00b" \
|
||||
); \
|
||||
|
||||
/**
|
||||
* @brief Exit a critical section by enabling all interrupts
|
||||
* This inline assembly construct is equivalent to:
|
||||
*
|
||||
* maskirq_insn(zero, zero) // Unmask all interrupt bits
|
||||
*/
|
||||
#define ULP_RISCV_EXIT_CRITICAL() asm volatile (".word 0x0600600b");
|
||||
|
||||
#else /* CONFIG_ULP_RISCV_INTERRUPT_ENABLE */
|
||||
|
||||
#define ULP_RISCV_ENTER_CRITICAL()
|
||||
#define ULP_RISCV_EXIT_CRITICAL()
|
||||
|
||||
#endif /* CONFIG_ULP_RISCV_INTERRUPT_ENABLE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "ulp_riscv_interrupt_ops.h"
|
||||
|
||||
.section .text
|
||||
.global __start
|
||||
|
||||
.type __start, %function
|
||||
__start:
|
||||
/* setup the stack pointer */
|
||||
la sp, __stack_top
|
||||
|
||||
#if CONFIG_ULP_RISCV_INTERRUPT_ENABLE
|
||||
/* Enable interrupts globally */
|
||||
maskirq_insn(zero, zero)
|
||||
#endif /* CONFIG_ULP_RISCV_INTERRUPT_ENABLE */
|
||||
|
||||
/* Start ULP user code */
|
||||
call ulp_riscv_rescue_from_monitor
|
||||
call main
|
||||
call ulp_riscv_halt
|
||||
loop:
|
||||
j loop
|
||||
.size __start, .-__start
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "ulp_riscv_adc_ulp_core.h"
|
||||
#include "hal/adc_ll.h"
|
||||
|
||||
int32_t ulp_riscv_adc_read_channel(adc_unit_t adc_n, int channel)
|
||||
{
|
||||
uint32_t event = (adc_n == ADC_UNIT_1) ? ADC_LL_EVENT_ADC1_ONESHOT_DONE : ADC_LL_EVENT_ADC2_ONESHOT_DONE;
|
||||
adc_oneshot_ll_clear_event(event);
|
||||
adc_oneshot_ll_disable_all_unit();
|
||||
adc_oneshot_ll_enable(adc_n);
|
||||
/* Force SW control of the channel bitmap; deep-sleep entry can clear it, which would
|
||||
* otherwise make the channel selection below take no effect. */
|
||||
adc_ll_set_controller(adc_n, ADC_LL_CTRL_RTC);
|
||||
adc_oneshot_ll_set_channel(adc_n, channel);
|
||||
|
||||
adc_oneshot_ll_start(adc_n);
|
||||
while (adc_oneshot_ll_get_event(event) != true) {
|
||||
;
|
||||
}
|
||||
int32_t out_raw = adc_oneshot_ll_get_raw_result(adc_n);
|
||||
if (adc_oneshot_ll_raw_check_valid(adc_n, out_raw) == false) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
//HW workaround: when enabling periph clock, this should be false
|
||||
adc_oneshot_ll_disable_all_unit();
|
||||
|
||||
return out_raw;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "ulp_riscv_gpio.h"
|
||||
#include "include/ulp_riscv_gpio.h"
|
||||
|
||||
#if CONFIG_ULP_RISCV_INTERRUPT_ENABLE
|
||||
esp_err_t ulp_riscv_gpio_isr_register(gpio_num_t gpio_num, ulp_riscv_gpio_int_type_t intr_type, intr_handler_t handler, void *arg)
|
||||
{
|
||||
if (gpio_num < 0 || gpio_num >= GPIO_NUM_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (intr_type < 0 || intr_type >= ULP_RISCV_GPIO_INTR_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!handler) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* Set the interrupt type */
|
||||
REG_SET_FIELD(RTC_GPIO_PIN0_REG + 4 * gpio_num, RTC_GPIO_PIN0_INT_TYPE, intr_type);
|
||||
|
||||
/* Set the interrupt handler */
|
||||
return ulp_riscv_intr_alloc(ULP_RISCV_RTCIO0_INTR_SOURCE + gpio_num, handler, arg);
|
||||
}
|
||||
|
||||
esp_err_t ulp_riscv_gpio_isr_deregister(gpio_num_t gpio_num)
|
||||
{
|
||||
return ulp_riscv_intr_free(ULP_RISCV_RTCIO0_INTR_SOURCE + gpio_num);
|
||||
}
|
||||
#endif /* CONFIG_ULP_RISCV_INTERRUPT_ENABLE */
|
||||
@@ -1,289 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_err.h"
|
||||
#include "ulp_riscv_i2c_ulp_core.h"
|
||||
#include "ulp_riscv_utils.h"
|
||||
#include "soc/rtc_i2c_reg.h"
|
||||
#include "soc/rtc_i2c_struct.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "hal/i2c_ll.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define I2C_CTRL_SLAVE_ADDR_MASK (0xFF << 0)
|
||||
#define I2C_CTRL_SLAVE_REG_ADDR_MASK (0xFF << 11)
|
||||
#define I2C_CTRL_MASTER_TX_DATA_MASK (0xFF << 19)
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#define ULP_I2C_CMD_RESTART 0 /*!<I2C restart command */
|
||||
#define ULP_I2C_CMD_WRITE 1 /*!<I2C write command */
|
||||
#define ULP_I2C_CMD_READ 2 /*!<I2C read command */
|
||||
#define ULP_I2C_CMD_STOP 3 /*!<I2C stop command */
|
||||
#define ULP_I2C_CMD_END 4 /*!<I2C end command */
|
||||
#else
|
||||
#define ULP_I2C_CMD_RESTART I2C_LL_CMD_RESTART /*!<I2C restart command */
|
||||
#define ULP_I2C_CMD_WRITE I2C_LL_CMD_WRITE /*!<I2C write command */
|
||||
#define ULP_I2C_CMD_READ I2C_LL_CMD_READ /*!<I2C read command */
|
||||
#define ULP_I2C_CMD_STOP I2C_LL_CMD_STOP /*!<I2C stop command */
|
||||
#define ULP_I2C_CMD_END I2C_LL_CMD_END /*!<I2C end command */
|
||||
#endif // CONFIG_IDF_TARGET_ESP32S3
|
||||
|
||||
/* Read/Write timeout (number of iterationis) */
|
||||
#define ULP_RISCV_I2C_RW_TIMEOUT CONFIG_ULP_RISCV_I2C_RW_TIMEOUT
|
||||
|
||||
/*
|
||||
* The RTC I2C controller follows the I2C command registers to perform read/write operations.
|
||||
* The cmd registers have the following format:
|
||||
*
|
||||
* 31 30:14 13:11 10 9 8 7:0
|
||||
* |----------|----------|---------|---------|----------|------------|---------|
|
||||
* | CMD_DONE | Reserved | OPCODE |ACK Value|ACK Expect|ACK Check En|Byte Num |
|
||||
* |----------|----------|---------|---------|----------|------------|---------|
|
||||
*/
|
||||
static void ulp_riscv_i2c_format_cmd(uint32_t cmd_idx, uint8_t op_code, uint8_t ack_val,
|
||||
uint8_t ack_expected, uint8_t ack_check_en, uint8_t byte_num)
|
||||
{
|
||||
uint32_t reg_addr = RTC_I2C_CMD0_REG + 4 * cmd_idx;
|
||||
|
||||
CLEAR_PERI_REG_MASK(reg_addr, 0xFFFFFFFF);
|
||||
|
||||
WRITE_PERI_REG(reg_addr,
|
||||
(0 << 31) | // CMD Done
|
||||
|
||||
((op_code & 0x3) << 11) | // Opcode
|
||||
|
||||
((ack_val & 0x1) << 10) | // ACK bit sent by I2C controller during READ.
|
||||
// Ignored during RSTART, STOP, END and WRITE cmds.
|
||||
|
||||
((ack_expected & 0x1) << 9) | // ACK bit expected by I2C controller during WRITE.
|
||||
// Ignored during RSTART, STOP, END and READ cmds.
|
||||
|
||||
((ack_check_en & 0x1) << 8) | // I2C controller verifies that the ACK bit sent by the slave device matches
|
||||
// the ACK expected bit during WRITE.
|
||||
// Ignored during RSTART, STOP, END and READ cmds.
|
||||
((byte_num & 0xFF) << 0)); // Byte Num
|
||||
}
|
||||
|
||||
static inline int32_t ulp_riscv_i2c_wait_for_interrupt(int32_t cycles_to_wait)
|
||||
{
|
||||
uint32_t status = 0;
|
||||
uint32_t timeout_start = ulp_riscv_get_cpu_cycles();
|
||||
|
||||
while (1) {
|
||||
status = READ_PERI_REG(RTC_I2C_INT_ST_REG);
|
||||
|
||||
/* If a NAK, Timeout, or Arbitration Loss occurs, abort immediately. */
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
if ((status & RTC_I2C_TIMEOUT_INT_ST) ||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
if ((status & RTC_I2C_TIME_OUT_INT_ST) ||
|
||||
#endif // CONFIG_IDF_TARGET_ESP32S2
|
||||
(status & RTC_I2C_ACK_ERR_INT_ST) ||
|
||||
(status & RTC_I2C_ARBITRATION_LOST_INT_ST)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Return 0 ONLY if hardware channels are error-free and data bits are latched. */
|
||||
if ((status & RTC_I2C_TX_DATA_INT_ST) ||
|
||||
(status & RTC_I2C_RX_DATA_INT_ST)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle CPU clock-cycle tracking */
|
||||
if (ulp_riscv_is_timeout_elapsed(timeout_start, cycles_to_wait)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ulp_riscv_i2c_master_set_slave_addr(uint8_t slave_addr)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, I2C_CTRL_SLAVE_ADDR_MASK);
|
||||
SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0xFF, slave_addr, 0);
|
||||
}
|
||||
|
||||
void ulp_riscv_i2c_master_set_slave_reg_addr(uint8_t slave_reg_addr)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, I2C_CTRL_SLAVE_REG_ADDR_MASK);
|
||||
SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0xFF, slave_reg_addr, 11);
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C transactions when master reads one byte of data from the slave device:
|
||||
*
|
||||
* |--------|--------|---------|--------|--------|--------|--------|---------|--------|--------|--------|--------|
|
||||
* | Master | START | SAD + W | | SUB | | SR | SAD + R | | | NACK | STOP |
|
||||
* |--------|--------|---------|--------|--------|--------|--------|---------|--------|--------|--------|--------|
|
||||
* | Slave | | | ACK | | ACK | | | ACK | DATA | | |
|
||||
* |--------|--------|---------|--------|--------|--------|--------|---------|--------|--------|--------|--------|
|
||||
*
|
||||
* I2C transactions when master reads multiple bytes of data from the slave device:
|
||||
*
|
||||
* |--------|--------|---------|--------|--------|--------|--------|---------|--------|--------|--------|--------|--------|--------|
|
||||
* | Master | START | SAD + W | | SUB | | SR | SAD + R | | | ACK | | NACK | STOP |
|
||||
* |--------|--------|---------|--------|--------|--------|--------|---------|--------|--------|--------|--------|--------|--------|
|
||||
* | Slave | | | ACK | | ACK | | | ACK | DATA | | DATA | | |
|
||||
* |--------|--------|---------|--------|--------|--------|--------|---------|--------|--------|--------|--------|--------|--------|
|
||||
*/
|
||||
esp_err_t ulp_riscv_i2c_master_read_from_device(uint8_t *data_rd, size_t size)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t cmd_idx = 0;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
if (size == 0) {
|
||||
// Quietly return
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Workaround for IDF-9145
|
||||
ULP_RISCV_ENTER_CRITICAL();
|
||||
|
||||
/* By default, RTC I2C controller is hard wired to use CMD2 register onwards for read operations */
|
||||
cmd_idx = 2;
|
||||
|
||||
/* Write slave addr */
|
||||
ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_WRITE, 0, 0, 1, 2);
|
||||
|
||||
/* Repeated START */
|
||||
ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_RESTART, 0, 0, 0, 0);
|
||||
|
||||
/* Write slave register addr */
|
||||
ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_WRITE, 0, 0, 1, 1);
|
||||
|
||||
if (size > 1) {
|
||||
/* Read n - 1 bytes */
|
||||
ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_READ, 0, 0, 1, size - 1);
|
||||
}
|
||||
|
||||
/* Read last byte + NACK */
|
||||
ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_READ, 1, 1, 1, 1);
|
||||
|
||||
/* STOP */
|
||||
ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_STOP, 0, 0, 0, 0);
|
||||
|
||||
/* Configure the RTC I2C controller in read mode */
|
||||
SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0x1, 0, 27);
|
||||
|
||||
/* Enable Rx data interrupt */
|
||||
SET_PERI_REG_MASK(RTC_I2C_INT_ENA_REG, RTC_I2C_RX_DATA_INT_ENA);
|
||||
|
||||
/* Start RTC I2C transmission */
|
||||
SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START_FORCE);
|
||||
SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START);
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
/* Poll for RTC I2C Rx Data interrupt bit to be set */
|
||||
if (!ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT)) {
|
||||
/* Read the data
|
||||
*
|
||||
* Unfortunately, the RTC I2C has no fifo buffer to help us with reading and storing
|
||||
* multiple bytes of data. Therefore, we need to read one byte at a time and clear the
|
||||
* Rx interrupt to get ready for the next byte.
|
||||
*/
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
data_rd[i] = REG_GET_FIELD(RTC_I2C_DATA_REG, RTC_I2C_RDATA);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
data_rd[i] = REG_GET_FIELD(RTC_I2C_DATA_REG, RTC_I2C_I2C_RDATA);
|
||||
#endif // CONFIG_IDF_TARGET_ESP32S2
|
||||
|
||||
/* Clear the Rx data interrupt bit */
|
||||
SET_PERI_REG_MASK(RTC_I2C_INT_CLR_REG, RTC_I2C_RX_DATA_INT_CLR);
|
||||
} else {
|
||||
/* Error in transaction */
|
||||
CLEAR_PERI_REG_MASK(RTC_I2C_INT_CLR_REG, READ_PERI_REG(RTC_I2C_INT_ST_REG));
|
||||
ret = ESP_ERR_INVALID_RESPONSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the RTC I2C transmission bits */
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START_FORCE);
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START);
|
||||
|
||||
// Workaround for IDF-9145
|
||||
ULP_RISCV_EXIT_CRITICAL();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C transactions when master writes one byte of data to the slave device:
|
||||
*
|
||||
* |--------|--------|---------|--------|--------|--------|--------|--------|--------|
|
||||
* | Master | START | SAD + W | | SUB | | DATA | | STOP |
|
||||
* |--------|--------|---------|--------|--------|--------|--------|--------|--------|
|
||||
* | Slave | | | ACK | | ACK | | ACK | |
|
||||
* |--------|--------|---------|--------|--------|--------|--------|--------|--------|
|
||||
*
|
||||
* I2C transactions when master writes multiple bytes of data to the slave device:
|
||||
*
|
||||
* |--------|--------|---------|--------|--------|--------|--------|--------|--------|--------|--------|
|
||||
* | Master | START | SAD + W | | SUB | | DATA | | DATA | | STOP |
|
||||
* |--------|--------|---------|--------|--------|--------|--------|--------|--------|--------|--------|
|
||||
* | Slave | | | ACK | | ACK | | ACK | | ACK | |
|
||||
* |--------|--------|---------|--------|--------|--------|--------|--------|--------|--------|--------|
|
||||
*/
|
||||
esp_err_t ulp_riscv_i2c_master_write_to_device(const uint8_t *data_wr, size_t size)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t cmd_idx = 0;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
if (size == 0) {
|
||||
// Quietly return
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Workaround for IDF-9145
|
||||
ULP_RISCV_ENTER_CRITICAL();
|
||||
|
||||
/* By default, RTC I2C controller is hard wired to use CMD0 and CMD1 registers for write operations */
|
||||
cmd_idx = 0;
|
||||
|
||||
/* Write slave addr + reg addr + data */
|
||||
ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_WRITE, 0, 0, 1, 2 + size);
|
||||
|
||||
/* Stop */
|
||||
ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_STOP, 0, 0, 0, 0);
|
||||
|
||||
/* Configure the RTC I2C controller in write mode */
|
||||
SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0x1, 1, 27);
|
||||
|
||||
/* Enable Tx data interrupt */
|
||||
SET_PERI_REG_MASK(RTC_I2C_INT_ENA_REG, RTC_I2C_TX_DATA_INT_ENA);
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
/* Write the data to be transmitted */
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, I2C_CTRL_MASTER_TX_DATA_MASK);
|
||||
SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0xFF, data_wr[i], 19);
|
||||
|
||||
if (i == 0) {
|
||||
/* Start RTC I2C transmission. (Needn't do it for every byte) */
|
||||
SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START_FORCE);
|
||||
SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START);
|
||||
}
|
||||
|
||||
/* Poll for RTC I2C Tx Data interrupt bit to be set */
|
||||
if (!ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT)) {
|
||||
/* Clear the Tx data interrupt bit */
|
||||
SET_PERI_REG_MASK(RTC_I2C_INT_CLR_REG, RTC_I2C_TX_DATA_INT_CLR);
|
||||
} else {
|
||||
SET_PERI_REG_MASK(RTC_I2C_INT_CLR_REG, READ_PERI_REG(RTC_I2C_INT_ST_REG));
|
||||
ret = ESP_ERR_INVALID_RESPONSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the RTC I2C transmission bits */
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START_FORCE);
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START);
|
||||
|
||||
// Workaround for IDF-9145
|
||||
ULP_RISCV_EXIT_CRITICAL();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "include/ulp_riscv_interrupt.h"
|
||||
#include "ulp_riscv_register_ops.h"
|
||||
#include "ulp_riscv_interrupt.h"
|
||||
#include "ulp_riscv_gpio.h"
|
||||
#include "soc/sens_reg.h"
|
||||
|
||||
#if CONFIG_ULP_RISCV_INTERRUPT_ENABLE
|
||||
|
||||
#define ULP_RISCV_TIMER_INT (1 << 0U) /* Internal Timer Interrupt */
|
||||
#define ULP_RISCV_EBREAK_ECALL_ILLEGAL_INSN_INT (1 << 1U) /* EBREAK, ECALL or Illegal instruction */
|
||||
#define ULP_RISCV_BUS_ERROR_INT (1 << 2U) /* Bus Error (Unaligned Memory Access) */
|
||||
#define ULP_RISCV_PERIPHERAL_INTERRUPT (1 << 31U) /* RTC Peripheral Interrupt */
|
||||
#define ULP_RISCV_INTERNAL_INTERRUPT (ULP_RISCV_TIMER_INT | ULP_RISCV_EBREAK_ECALL_ILLEGAL_INSN_INT | ULP_RISCV_BUS_ERROR_INT)
|
||||
|
||||
/* Interrupt handler structure */
|
||||
typedef struct {
|
||||
intr_handler_t handler;
|
||||
void *arg;
|
||||
} ulp_riscv_intr_handler_t;
|
||||
|
||||
/* Statically store all interrupt handlers */
|
||||
static ulp_riscv_intr_handler_t s_intr_handlers[ULP_RISCV_MAX_INTR_SOURCE];
|
||||
|
||||
esp_err_t ulp_riscv_intr_alloc(ulp_riscv_interrupt_source_t source, intr_handler_t handler, void *arg)
|
||||
{
|
||||
/* Check the validity of the interrupt source */
|
||||
if (source < 0 || source >= ULP_RISCV_MAX_INTR_SOURCE || handler == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* Register interrupt handler */
|
||||
if (s_intr_handlers[source].handler == NULL) {
|
||||
s_intr_handlers[source].handler = handler;
|
||||
s_intr_handlers[source].arg = arg;
|
||||
} else {
|
||||
/* Error: The interrupt handler for this interrupt source has already been allocated */
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ulp_riscv_intr_free(ulp_riscv_interrupt_source_t source)
|
||||
{
|
||||
/* Check the validity of the interrupt source */
|
||||
if (source < 0 || source >= ULP_RISCV_MAX_INTR_SOURCE) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* De-register interrupt handler */
|
||||
if (s_intr_handlers[source].handler != NULL) {
|
||||
s_intr_handlers[source].handler = NULL;
|
||||
s_intr_handlers[source].arg = NULL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* This function -
|
||||
* - Checks RTC peripheral interrupt status bit
|
||||
* - Calls interrupt handler if it is registered
|
||||
* - Clears interrupt bit
|
||||
*/
|
||||
static inline void ulp_riscv_handle_rtc_periph_intr(uint32_t status)
|
||||
{
|
||||
/* SW interrupt */
|
||||
if (status & SENS_COCPU_SW_INT_ST) {
|
||||
const ulp_riscv_intr_handler_t* entry = &s_intr_handlers[ULP_RISCV_SW_INTR_SOURCE];
|
||||
|
||||
if (entry->handler) {
|
||||
entry->handler(entry->arg);
|
||||
}
|
||||
|
||||
SET_PERI_REG_MASK(SENS_SAR_COCPU_INT_CLR_REG, SENS_COCPU_SW_INT_CLR);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function -
|
||||
* - Checks if one or more RTC IO interrupt status bits are set
|
||||
* - Calls the interrupt handler for the RTC IO if it is registered
|
||||
* - Clears all interrupt bits
|
||||
*/
|
||||
static inline void ulp_riscv_handle_rtc_io_intr(uint32_t status)
|
||||
{
|
||||
uint32_t handler_idx = 0;
|
||||
for (int i = 0; i < GPIO_NUM_MAX; i++) {
|
||||
if (status & (1U << i)) {
|
||||
handler_idx = ULP_RISCV_RTCIO0_INTR_SOURCE + i;
|
||||
ulp_riscv_intr_handler_t* entry = &s_intr_handlers[handler_idx];
|
||||
|
||||
if (entry->handler) {
|
||||
entry->handler(entry->arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REG_SET_FIELD(RTC_GPIO_STATUS_W1TC_REG, RTC_GPIO_STATUS_INT_W1TC, status);
|
||||
}
|
||||
|
||||
/* This is the global interrupt handler for ULP RISC-V.
|
||||
* It is called from ulp_riscv_vectors.S
|
||||
*/
|
||||
void __attribute__((weak)) _ulp_riscv_interrupt_handler(uint32_t q1)
|
||||
{
|
||||
/* Call respective interrupt handlers based on the interrupt status in q1 */
|
||||
|
||||
/* Internal Interrupts */
|
||||
if (q1 & ULP_RISCV_INTERNAL_INTERRUPT) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/* External/Peripheral interrupts */
|
||||
if (q1 & ULP_RISCV_PERIPHERAL_INTERRUPT) {
|
||||
/* RTC Peripheral interrupts */
|
||||
uint32_t cocpu_int_st = READ_PERI_REG(SENS_SAR_COCPU_INT_ST_REG);
|
||||
if (cocpu_int_st) {
|
||||
ulp_riscv_handle_rtc_periph_intr(cocpu_int_st);
|
||||
}
|
||||
|
||||
/* RTC IO interrupts */
|
||||
uint32_t rtcio_int_st = REG_GET_FIELD(RTC_GPIO_STATUS_REG, RTC_GPIO_STATUS_INT);
|
||||
if (rtcio_int_st) {
|
||||
ulp_riscv_handle_rtc_io_intr(rtcio_int_st);
|
||||
}
|
||||
|
||||
/* TODO: RTC I2C interrupt */
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ULP_RISCV_INTERRUPT_ENABLE */
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "ulp_riscv_lock.h"
|
||||
#include "ulp_riscv_lock_shared.h"
|
||||
|
||||
void ulp_riscv_lock_acquire(ulp_riscv_lock_t *lock)
|
||||
{
|
||||
lock->critical_section_flag_ulp = true;
|
||||
lock->turn = ULP_RISCV_LOCK_TURN_MAIN_CPU;
|
||||
|
||||
while (lock->critical_section_flag_main_cpu && (lock->turn == ULP_RISCV_LOCK_TURN_MAIN_CPU)) {
|
||||
}
|
||||
}
|
||||
|
||||
void ulp_riscv_lock_release(ulp_riscv_lock_t *lock)
|
||||
{
|
||||
lock->critical_section_flag_ulp = false;
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "ulp_riscv_print.h"
|
||||
#include "ulp_riscv_utils.h"
|
||||
|
||||
typedef struct {
|
||||
putc_fn_t putc_fn; // Putc function of the underlying driver, e.g. UART
|
||||
void *putc_ctx; // Context passed to the putc function
|
||||
} ulp_riscv_print_ctx_t;
|
||||
|
||||
static ulp_riscv_print_ctx_t s_print_ctx;
|
||||
|
||||
void ulp_riscv_print_install(putc_fn_t putc, void * putc_ctx)
|
||||
{
|
||||
s_print_ctx.putc_ctx = putc_ctx;
|
||||
s_print_ctx.putc_fn = putc;
|
||||
}
|
||||
|
||||
void ulp_riscv_print_str(const char *str)
|
||||
{
|
||||
if (!s_print_ctx.putc_fn) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Perform the bit-banged UART operation in a critical section */
|
||||
ULP_RISCV_ENTER_CRITICAL();
|
||||
|
||||
for (int i = 0; str[i] != 0; i++) {
|
||||
s_print_ctx.putc_fn(s_print_ctx.putc_ctx, str[i]);
|
||||
}
|
||||
|
||||
ULP_RISCV_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
void ulp_riscv_print_hex(int h)
|
||||
{
|
||||
int x;
|
||||
int c;
|
||||
|
||||
if (!s_print_ctx.putc_fn) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Perform the bit-banged UART operation in a critical section */
|
||||
ULP_RISCV_ENTER_CRITICAL();
|
||||
|
||||
// Does not print '0x', only the digits (8 digits to print)
|
||||
for (x = 0; x < 8; x++) {
|
||||
c = (h >> 28) & 0xf; // extract the leftmost byte
|
||||
if (c < 10) {
|
||||
s_print_ctx.putc_fn(s_print_ctx.putc_ctx, '0' + c);
|
||||
} else {
|
||||
s_print_ctx.putc_fn(s_print_ctx.putc_ctx, 'a' + c - 10);
|
||||
}
|
||||
h <<= 4; // move the 2nd leftmost byte to the left, to be extracted next
|
||||
}
|
||||
|
||||
ULP_RISCV_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
void ulp_riscv_print_hex_with_number_of_digits(int h, int number_of_digits)
|
||||
{
|
||||
int x;
|
||||
int c;
|
||||
|
||||
if (!s_print_ctx.putc_fn) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (number_of_digits < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (number_of_digits >= 8) {
|
||||
ulp_riscv_print_hex(h);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Perform the bit-banged UART operation in a critical section */
|
||||
ULP_RISCV_ENTER_CRITICAL();
|
||||
|
||||
// Does not print '0x', only the digits specified by the number_of_digits argument
|
||||
for (x = 0; x < number_of_digits; x++) {
|
||||
c = (h >> ((number_of_digits - 1) * 4)) & 0xf; // extract the leftmost byte
|
||||
if (c < 10) {
|
||||
s_print_ctx.putc_fn(s_print_ctx.putc_ctx, '0' + c);
|
||||
} else {
|
||||
s_print_ctx.putc_fn(s_print_ctx.putc_ctx, 'a' + c - 10);
|
||||
}
|
||||
h <<= 4; // move the 2nd leftmost byte to the left, to be extracted next
|
||||
}
|
||||
|
||||
ULP_RISCV_EXIT_CRITICAL();
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "ulp_riscv_touch_ulp_core.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/touch_sensor_ll.h"
|
||||
|
||||
/* Check Touch Channel correctness */
|
||||
#define ULP_RISCV_TOUCH_CHANNEL_CHECK_AND_RETURN(channel) \
|
||||
{ \
|
||||
if (channel >= SOC_TOUCH_MAX_CHAN_ID || \
|
||||
channel < SOC_TOUCH_MIN_CHAN_ID) { \
|
||||
return ESP_ERR_INVALID_ARG; \
|
||||
} \
|
||||
} \
|
||||
|
||||
esp_err_t ulp_riscv_touch_pad_read_raw_data(int touch_num, uint32_t *raw_data)
|
||||
{
|
||||
/* Check Arguments */
|
||||
if (!raw_data) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ULP_RISCV_TOUCH_CHANNEL_CHECK_AND_RETURN(touch_num);
|
||||
|
||||
/* Read raw touch data */
|
||||
touch_ll_read_chan_data((int)touch_num, TOUCH_LL_READ_RAW, raw_data);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ulp_riscv_touch_pad_read_benchmark(int touch_num, uint32_t *benchmark)
|
||||
{
|
||||
/* Check Arguments */
|
||||
if (!benchmark) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ULP_RISCV_TOUCH_CHANNEL_CHECK_AND_RETURN(touch_num);
|
||||
|
||||
/* Read benchmark data */
|
||||
touch_ll_read_chan_data((int)touch_num, TOUCH_LL_READ_BENCHMARK, benchmark);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ulp_riscv_touch_pad_filter_read_smooth(int touch_num, uint32_t *smooth_data)
|
||||
{
|
||||
/* Check Arguments */
|
||||
if (!smooth_data) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ULP_RISCV_TOUCH_CHANNEL_CHECK_AND_RETURN(touch_num);
|
||||
|
||||
/* Read smoothened touch sensor data */
|
||||
touch_ll_read_chan_data((int)touch_num, TOUCH_LL_READ_SMOOTH, smooth_data);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ulp_riscv_touch_pad_reset_benchmark(int touch_num)
|
||||
{
|
||||
/* Check Arguments */
|
||||
if (touch_num > SOC_TOUCH_MAX_CHAN_ID || touch_num < 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* Reset benchmark */
|
||||
touch_ll_reset_chan_benchmark(BIT(touch_num));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ulp_riscv_touch_pad_sleep_channel_read_data(int touch_num, uint32_t *raw_data)
|
||||
{
|
||||
/* Check Arguments */
|
||||
if (!raw_data) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ULP_RISCV_TOUCH_CHANNEL_CHECK_AND_RETURN(touch_num);
|
||||
|
||||
/* Read raw touch data */
|
||||
touch_ll_sleep_read_chan_data(TOUCH_LL_READ_RAW, raw_data);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ulp_riscv_touch_pad_sleep_channel_read_benchmark(int touch_num, uint32_t *benchmark)
|
||||
{
|
||||
/* Check Arguments */
|
||||
if (!benchmark) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ULP_RISCV_TOUCH_CHANNEL_CHECK_AND_RETURN(touch_num);
|
||||
|
||||
/* Read benchmark data */
|
||||
touch_ll_sleep_read_chan_data(TOUCH_LL_READ_BENCHMARK, benchmark);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ulp_riscv_touch_pad_sleep_channel_read_smooth(int touch_num, uint32_t *smooth_data)
|
||||
{
|
||||
/* Check Arguments */
|
||||
if (!smooth_data) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ULP_RISCV_TOUCH_CHANNEL_CHECK_AND_RETURN(touch_num);
|
||||
|
||||
/* Read smoothened touch sensor data */
|
||||
touch_ll_sleep_read_chan_data(TOUCH_LL_READ_SMOOTH, smooth_data);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ulp_riscv_touch_pad_sleep_channel_reset_benchmark(void)
|
||||
{
|
||||
/* Reset benchmark */
|
||||
touch_ll_sleep_reset_benchmark();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "ulp_riscv.h"
|
||||
#include "ulp_riscv_utils.h"
|
||||
#include "ulp_riscv_gpio.h"
|
||||
#include "ulp_riscv_uart_ulp_core.h"
|
||||
|
||||
/* We calculate the bit duration at compile time to speed up and avoid pulling in soft-float libs */
|
||||
#define BIT_DURATION_CYCLES ( (ULP_RISCV_CYCLES_PER_US_NUM * 1000000) / (ULP_RISCV_CYCLES_PER_US_DENOM * CONFIG_ULP_RISCV_UART_BAUDRATE) )
|
||||
|
||||
void ulp_riscv_uart_init(ulp_riscv_uart_t *uart, const ulp_riscv_uart_cfg_t *cfg)
|
||||
{
|
||||
uart->tx_pin = cfg->tx_pin;
|
||||
/* 1 bit duration with length given in clock cycles */
|
||||
uart->bit_duration_cycles = BIT_DURATION_CYCLES;
|
||||
|
||||
/* Setup GPIO used for uart TX */
|
||||
ulp_riscv_gpio_init(cfg->tx_pin);
|
||||
ulp_riscv_gpio_output_enable(cfg->tx_pin);
|
||||
ulp_riscv_gpio_set_output_mode(cfg->tx_pin, RTCIO_MODE_OUTPUT_OD);
|
||||
ulp_riscv_gpio_pullup(cfg->tx_pin);
|
||||
ulp_riscv_gpio_pulldown_disable(cfg->tx_pin);
|
||||
ulp_riscv_gpio_output_level(cfg->tx_pin, 1);
|
||||
|
||||
}
|
||||
|
||||
void ulp_riscv_uart_putc(const ulp_riscv_uart_t *uart, const char c)
|
||||
{
|
||||
ulp_riscv_gpio_output_level(uart->tx_pin, 0);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
/* Offset the delay to account for cycles spent setting the bit */
|
||||
ulp_riscv_delay_cycles(uart->bit_duration_cycles - 100);
|
||||
if ((1 << i) & c) {
|
||||
ulp_riscv_gpio_output_level(uart->tx_pin, 1);
|
||||
} else {
|
||||
ulp_riscv_gpio_output_level(uart->tx_pin, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ulp_riscv_delay_cycles(uart->bit_duration_cycles - 20);
|
||||
ulp_riscv_gpio_output_level(uart->tx_pin, 1);
|
||||
ulp_riscv_delay_cycles(uart->bit_duration_cycles);
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "ulp_riscv_utils.h"
|
||||
#include "ulp_riscv_register_ops.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/soc_ulp.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "ulp_riscv_cpu_freq_shared.h"
|
||||
|
||||
void ulp_riscv_rescue_from_monitor(void)
|
||||
{
|
||||
/* Rescue RISCV from monitor state. */
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_DONE | RTC_CNTL_COCPU_SHUT_RESET_EN);
|
||||
}
|
||||
|
||||
void ulp_riscv_wakeup_main_processor(void)
|
||||
{
|
||||
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SW_CPU_INT);
|
||||
}
|
||||
|
||||
void ulp_riscv_halt(void)
|
||||
{
|
||||
/* Setting the delay time after RISCV recv `DONE` signal, Ensure that action `RESET` can be executed in time. */
|
||||
REG_SET_FIELD(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT_2_CLK_DIS, 0x3F);
|
||||
|
||||
/* Suspends the ulp operation and reset the ULP core. Must be the final operation before going to halt. */
|
||||
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_DONE | RTC_CNTL_COCPU_SHUT_RESET_EN);
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
void ulp_riscv_timer_stop(void)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
|
||||
}
|
||||
|
||||
void ulp_riscv_timer_resume(void)
|
||||
{
|
||||
SET_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
|
||||
}
|
||||
|
||||
void ulp_riscv_gpio_wakeup_clear(void)
|
||||
{
|
||||
SET_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_GPIO_WAKEUP_CLR);
|
||||
}
|
||||
|
||||
#if CONFIG_ULP_RISCV_INTERRUPT_ENABLE
|
||||
|
||||
void ulp_riscv_enable_sw_intr(intr_handler_t handler, void *arg)
|
||||
{
|
||||
/* Enable ULP RISC-V SW interrupt */
|
||||
SET_PERI_REG_MASK(SENS_SAR_COCPU_INT_ENA_REG, SENS_COCPU_SW_INT_ENA);
|
||||
|
||||
/* Register interrupt handler */
|
||||
if (handler) {
|
||||
ulp_riscv_intr_alloc(ULP_RISCV_SW_INTR_SOURCE, handler, arg);
|
||||
}
|
||||
}
|
||||
|
||||
void ulp_riscv_disable_sw_intr(void)
|
||||
{
|
||||
/* Disable ULP RISC-V SW interrupt */
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_COCPU_INT_ENA_REG, SENS_COCPU_SW_INT_ENA);
|
||||
|
||||
/* De-register interrupt handler */
|
||||
ulp_riscv_intr_free(ULP_RISCV_SW_INTR_SOURCE);
|
||||
}
|
||||
|
||||
void ulp_riscv_trigger_sw_intr(void)
|
||||
{
|
||||
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SW_INT_TRIGGER);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ULP_RISCV_INTERRUPT_ENABLE */
|
||||
|
||||
void ulp_riscv_delay_us(uint32_t delay_us)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
/*
|
||||
* For very small delays, entering the generic cycle-count loop adds too much fixed overhead.
|
||||
* Use a short calibrated NOP path instead to improve small-delay accuracy on ESP32-S3.
|
||||
*/
|
||||
if (delay_us <= 5) {
|
||||
goto fast_return;
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
/*
|
||||
* Same principle as S3, but with a different threshold due to target-specific timing/overhead.
|
||||
*/
|
||||
if (delay_us <= 10) {
|
||||
goto fast_return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Generic delay path:
|
||||
* - Convert requested microseconds to CPU cycles using ratio macros.
|
||||
* - Pre-subtract measured function overhead (55 cycles), so observed delay is closer to request.
|
||||
*/
|
||||
uint32_t start = ulp_riscv_get_cpu_cycles() - 55U;
|
||||
uint32_t req_delay = delay_us * ULP_RISCV_CYCLES_PER_US_NUM / ULP_RISCV_CYCLES_PER_US_DENOM;
|
||||
|
||||
/*
|
||||
* Busy-wait until elapsed cycles reach req_delay.
|
||||
* uint32_t subtraction intentionally relies on wrap-around-safe arithmetic for cycle counter rollover.
|
||||
*/
|
||||
while ((uint32_t)(ulp_riscv_get_cpu_cycles() - start) < req_delay) {
|
||||
/* busy wait */
|
||||
}
|
||||
return;
|
||||
|
||||
fast_return:
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
/*
|
||||
* Fast path for tiny delays:
|
||||
* Use discrete NOP counts calibrated for this target.
|
||||
* Note: (delay_us == 0 || delay_us <= 2) is intentionally kept as-is to avoid behavior changes.
|
||||
*/
|
||||
if (delay_us == 0 || delay_us <= 2) {
|
||||
return;
|
||||
} else if (delay_us <= 3) {
|
||||
asm volatile("nop\n");
|
||||
} else if (delay_us <= 4) {
|
||||
asm volatile("nop\n nop\n");
|
||||
} else {
|
||||
asm volatile("nop\n nop\n nop\n nop\n nop\n");
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
/*
|
||||
* ESP32-S2 calibrated NOP mapping for very short delays.
|
||||
*/
|
||||
if (delay_us == 0) {
|
||||
return;
|
||||
} else if (delay_us <= 6) {
|
||||
asm volatile("nop\n");
|
||||
} else if (delay_us <= 8) {
|
||||
asm volatile("nop\n nop\n");
|
||||
} else {
|
||||
asm volatile("nop\n nop\n nop\n nop\n nop\n nop\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "ulp_riscv_interrupt_ops.h"
|
||||
|
||||
.equ SAVE_REGS, 17
|
||||
.equ CONTEXT_SIZE, (SAVE_REGS * 4)
|
||||
|
||||
/* Macro which first allocates space on the stack to save general
|
||||
* purpose registers, and then save them. GP register is excluded.
|
||||
* The default size allocated on the stack is CONTEXT_SIZE, but it
|
||||
* can be overridden.
|
||||
*
|
||||
* Note: We don't save the callee-saved s0-s11 registers to save space
|
||||
*/
|
||||
.macro save_general_regs cxt_size=CONTEXT_SIZE
|
||||
addi sp, sp, -\cxt_size
|
||||
sw ra, 0(sp)
|
||||
sw tp, 4(sp)
|
||||
sw t0, 8(sp)
|
||||
sw t1, 12(sp)
|
||||
sw t2, 16(sp)
|
||||
sw a0, 20(sp)
|
||||
sw a1, 24(sp)
|
||||
sw a2, 28(sp)
|
||||
sw a3, 32(sp)
|
||||
sw a4, 36(sp)
|
||||
sw a5, 40(sp)
|
||||
sw a6, 44(sp)
|
||||
sw a7, 48(sp)
|
||||
sw t3, 52(sp)
|
||||
sw t4, 56(sp)
|
||||
sw t5, 60(sp)
|
||||
sw t6, 64(sp)
|
||||
.endm
|
||||
|
||||
/* Restore the general purpose registers (excluding gp) from the context on
|
||||
* the stack. The context is then deallocated. The default size is CONTEXT_SIZE
|
||||
* but it can be overridden. */
|
||||
.macro restore_general_regs cxt_size=CONTEXT_SIZE
|
||||
lw ra, 0(sp)
|
||||
lw tp, 4(sp)
|
||||
lw t0, 8(sp)
|
||||
lw t1, 12(sp)
|
||||
lw t2, 16(sp)
|
||||
lw a0, 20(sp)
|
||||
lw a1, 24(sp)
|
||||
lw a2, 28(sp)
|
||||
lw a3, 32(sp)
|
||||
lw a4, 36(sp)
|
||||
lw a5, 40(sp)
|
||||
lw a6, 44(sp)
|
||||
lw a7, 48(sp)
|
||||
lw t3, 52(sp)
|
||||
lw t4, 56(sp)
|
||||
lw t5, 60(sp)
|
||||
lw t6, 64(sp)
|
||||
addi sp,sp, \cxt_size
|
||||
.endm
|
||||
|
||||
.section .text.vectors
|
||||
.global irq_vector
|
||||
.global reset_vector
|
||||
|
||||
/* The reset vector, jumps to startup code */
|
||||
reset_vector:
|
||||
j __start
|
||||
|
||||
#if CONFIG_ULP_RISCV_INTERRUPT_ENABLE
|
||||
/* Interrupt handler */
|
||||
.balign 0x10
|
||||
irq_vector:
|
||||
/* Save the general gurpose register context before handling the interrupt */
|
||||
save_general_regs
|
||||
|
||||
/* Fetch the interrupt status from the custom q1 register into a0 */
|
||||
getq_insn(a0, q1)
|
||||
|
||||
/* Call the global C interrupt handler. The interrupt status is passed as the argument in a0.
|
||||
* We do not re-enable interrupts before calling the C handler as ULP RISC-V does not
|
||||
* support nested interrupts.
|
||||
*/
|
||||
jal _ulp_riscv_interrupt_handler
|
||||
|
||||
/* Restore the register context after returning from the C interrupt handler */
|
||||
restore_general_regs
|
||||
|
||||
/* Exit interrupt handler by executing the custom retirq instruction which will restore pc and re-enable interrupts */
|
||||
retirq_insn()
|
||||
|
||||
#endif /* CONFIG_ULP_RISCV_INTERRUPT_ENABLE */
|
||||
Reference in New Issue
Block a user