Skip to content

Commit

Permalink
Merge branch 'feature/ulp_riscv_interrupt_handling' into 'master'
Browse files Browse the repository at this point in the history
feat(ulp-riscv): Added interrupt handling for ULP RISC-V

Closes IDFGH-9866 and IDF-1713

See merge request espressif/esp-idf!27802
  • Loading branch information
sudeep-mohanty committed Jan 19, 2024
2 parents 7f76239 + de8ee8c commit 82f2294
Show file tree
Hide file tree
Showing 21 changed files with 854 additions and 26 deletions.
8 changes: 6 additions & 2 deletions components/ulp/cmake/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,22 +57,26 @@ set(bypassWarning "${IDF_TARGET}")
if(ULP_COCPU_IS_RISCV)
#risc-v ulp uses extra files for building:
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_vectors.S"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/start.S"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_adc.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_lock.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_uart.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_print.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_i2c.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_utils.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_touch.c")
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_touch.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_gpio.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_interrupt.c")

target_link_options(${ULP_APP_NAME} PRIVATE "-nostartfiles")
target_link_options(${ULP_APP_NAME} PRIVATE -Wl,--gc-sections)
target_link_options(${ULP_APP_NAME} PRIVATE -Wl,-Map=${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}.map)
target_sources(${ULP_APP_NAME} PRIVATE ${ULP_S_SOURCES})
#Makes the csr utillies for riscv visible:
target_include_directories(${ULP_APP_NAME} PRIVATE "${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/include"
"${IDF_PATH}/components/ulp/ulp_riscv/shared/include")
"${IDF_PATH}/components/ulp/ulp_riscv/shared/include"
"${IDF_PATH}/components/riscv/include")
target_link_options(${ULP_APP_NAME} PRIVATE SHELL:-T ${IDF_PATH}/components/ulp/ld/${IDF_TARGET}.peripherals.ld)
target_link_options(${ULP_APP_NAME} PRIVATE "-Wl,--no-warn-rwx-segments")
target_compile_definitions(${ULP_APP_NAME} PRIVATE IS_ULP_COCPU)
Expand Down
2 changes: 1 addition & 1 deletion components/ulp/ld/ulp_riscv.ld
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ SECTIONS
. = ORIGIN(ram);
.text :
{
*start.S.obj(.text.vectors) /* Default reset vector must link to offset 0x0 */
*ulp_riscv_vectors.S.obj(.text.vectors) /* Default reset vector must link to offset 0x0 */
*(.text)
*(.text*)
} >ram
Expand Down
37 changes: 35 additions & 2 deletions components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_gpio.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -13,6 +13,7 @@ extern "C" {
#include "soc/rtc_io_reg.h"
#include "soc/sens_reg.h"
#include "ulp_riscv_register_ops.h"
#include "ulp_riscv_interrupt.h"

typedef enum {
GPIO_NUM_0 = 0, /*!< GPIO0, input and output */
Expand All @@ -35,10 +36,21 @@ typedef enum {
GPIO_NUM_17 = 17, /*!< GPIO17, input and output */
GPIO_NUM_18 = 18, /*!< GPIO18, input and output */
GPIO_NUM_19 = 19, /*!< GPIO19, input and output */
GPIO_NUM_20 = 20,
GPIO_NUM_20 = 20, /*!< GPIO20, input and output */
GPIO_NUM_21 = 21, /*!< GPIO21, input and output */
GPIO_NUM_MAX,
} gpio_num_t;

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,
Expand Down Expand Up @@ -119,6 +131,27 @@ 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);
}

/**
* @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);

#ifdef __cplusplus
}
#endif
67 changes: 67 additions & 0 deletions components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_interrupt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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

/* 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);

#ifdef __cplusplus
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Claire Xenia Wolf <[email protected]>
* 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
23 changes: 22 additions & 1 deletion components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_utils.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -13,6 +13,7 @@ extern "C" {
#include "sdkconfig.h"
#include <stdint.h>
#include "ulp_riscv_register_ops.h"
#include "ulp_riscv_interrupt.h"

/**
* @brief Wakeup main CPU from sleep or deep sleep.
Expand Down Expand Up @@ -112,6 +113,26 @@ void static inline ulp_riscv_delay_cycles(uint32_t cycles)
*/
void ulp_riscv_gpio_wakeup_clear(void);

/**
* @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);

#ifdef __cplusplus
}
#endif
36 changes: 17 additions & 19 deletions components/ulp/ulp_riscv/ulp_core/start.S
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
.section .text.vectors
.global irq_vector
.global reset_vector

/* The reset vector, jumps to startup code */
reset_vector:
j __start
#include "ulp_riscv_interrupt_ops.h"

/* Interrupt handler */
.balign 16
irq_vector:
ret

.section .text
.section .text
.global __start

.type __start, %function
__start:
/* setup the stack pointer */
la sp, __stack_top
call ulp_riscv_rescue_from_monitor
call main
call ulp_riscv_halt
/* setup the stack pointer */
la sp, __stack_top

/* Enable interrupts globally */
maskirq_insn(zero, zero)

/* Start ULP user code */
call ulp_riscv_rescue_from_monitor
call main
call ulp_riscv_halt
loop:
j loop
j loop
.size __start, .-__start
33 changes: 33 additions & 0 deletions components/ulp/ulp_riscv/ulp_core/ulp_riscv_gpio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ulp_riscv_gpio.h"
#include "include/ulp_riscv_gpio.h"

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);
}
Loading

0 comments on commit 82f2294

Please sign in to comment.