.. _lab1_3: Core feature: Interrupt ======================= **Purpose** - To get familiar with the interrupt handling in |nuclei_ncore| - To know how to use external interrupt **Requirements** The following hardware and source codes are required: * PC host * Nuclei board (|rv_star|) * USB Type-C cable * ``nuclei-sdk/board-labs/rvstar/exti_key_interrupt`` **Content** - Through learning the `Chapter 6 of Nuclei RISCV ISA Spec `_ and `Interrupt and Exception Handling File in NMSIS `_ to get familar with interrput handling in |nuclei_ncore|. - Through learning the `Chapter 6 EXTI of GD32VF103 MCU User Mannual `_ to get familar with the usage of EXTI. - Programming the EXTI peripheral registers of SoC and ECLIC registers of Core to setup an external interrupt which is triggered by pressing the on-board user key. Set this interrupt to non-vectored processing mode, and the corresponding interrupt service routine can change the status of on-board RGB LED. **Principles** Interrupt mechanism, that is, the core is suddenly interrupted by other requests during the execution of current program, and current program is stopped, then the core turns to handle other requests. After handling other requests, the core goes back and continue to execute the previous program. About interrupts processing, it's an important part in processor design. The RISC-V processor in |gd_mcu| is Bumblebee Core, it integrates the Enhancement Core-Local Interrupt Controller (ECLIC) for efficient interrupts processing. The ECLIC is designed to provide low-latency, vectored, pre-emptive interrupts for RISC-V systems. It can be used to manage multiple interrupt sources. .. note:: In Nuclei processor core, ECLIC supports interrupt preemption, non-vectored and vectored processing mode. Please see `(CLIC mode) Interrupt Preemption `_ for more details about interrupt preemption, and see `(CLIC mode) Vectored and Non-Vectored Processing Mode of Interrupts `_ for more details about non-vectored and vectored processing mode. In this lab, we just show how to implement single non-vectored interrupt handling. About how to implement interrupt preemption, please refer to :ref:`Core feature: Nesting of Interrupts `. About how to deal with vectored interrupt, please refer to :ref:`Core feature: Vectored Interrupt `. If the interrupt is set to non-vectored processing mode, once it is taken, the core will jump to the common base entry shared by all non-vectored interrupts, and the processing flow is as the figure below. .. _figure_lab1_3_1: .. figure:: /asserts/medias/lab1_3_fig1.jpg :width: 800 :alt: lab1_3_fig1 Example for non-vectored interrupt The types of interrupts supported by the Bumblebee Core are shown in following figure. .. _figure_lab1_3_2: .. figure:: /asserts/medias/lab1_3_fig2.jpg :width: 600 :alt: lab1_3_fig2 Interrupt types External interrupt is an interrupt initiated from outside the core (other peripherals in SoC). External interrupts allow user to connect to an external interrupt source, such as an interrupt generated by an external device like UART, GPIO and so on. In SoC level, EXTI (interrupt/event controller) of |gd_mcu| contains up to 19 independent edge detectors and generates interrupt requests or events to the processer. It's used to manage these trigger sources: 16 external lines from GPIO pins and 3 lines from internal modules (including LVD, RTC Alarm, USB Wakeup). The EXTI has three trigger types: rising edge, falling edge and both edges. Each edge detector in the EXTI can be configured and masked independently. The architecture of EXTI module is shown in following figure. .. _figure_lab1_3_3: .. figure:: /asserts/medias/lab1_3_fig3.jpg :alt: lab1_3_fig3 :width: 500 Block diagram of EXTI In |nuclei_sdk|, ``gd32vf103_rvstar.h`` provides API to operate the on-board peripherals, ``gd32vf103_exti.h`` provides API to operate the SoC EXTI, ``core_feature_eclic.h`` provides API to config ECLIC feature for Nuclei Processor Core. The code for this lab is located in ``nuclei-sdk/board-labs/rvstar/exti_key_interrupt``. You can see it in the :ref:`appendix `. It can be divided into 4 parts: * Part1 : Board config, initialize on-board RGB LED and user key * Part2 : EXTI config, set *PA0* to used as EXTI source and enable EXTI interrupt in SoC level * Part3 : ECLIC config, interrupt config in Processor level for specified interrupt source (interrupt enable, level and priority, non-vectored or vectored) * Part4 : EXTI interrupt service routine, change the status of on-board RGB LED (Red-Off or Off-Red) The program flow is shown below: .. _figure_lab1_3_4: .. figure:: /asserts/medias/lab1_3_fig4.jpg :width: 500 :alt: lab1_3_fig4 Programming flow of extern interrupt **Steps** 1. Connect |rv_star| and your computer with the USB Type-C cable. .. _figure_lab1_3_5: .. figure:: /asserts/medias/lab1_3_fig5.jpg :width: 500 :alt: lab1_3_fig5 Connect with PC .. note:: When connect your board with the PC, just keep the on-board jumpers as default. About on-board jumpers' function, please refer to :ref:`Jumper Section `. 2. Compile and run the ``nuclei-sdk/board-labs/rvstar/exti_key_interrupt`` example. About the develop environment, you can choose |nuclei_sdk| or |ses|. * |nuclei_sdk| Using the following commands: .. code-block:: shell cd /nuclei-sdk/board-labs/rvstar/exti_key_interrupt make SOC=gd32vf103 BOARD=gd32vf103v_rvstar upload .. note:: a. About the acquisition of source codes, please refer to :ref:`Software Source Codes `. b. About the detailed usage of |nuclei_sdk|, please refer to `How to develop with Nuclei SDK `_. * |ses| Using the following actions: .. _figure_lab1_3_6: .. figure:: /asserts/medias/lab1_3_fig6.jpg :width: 900 :alt: lab1_3_fig6 Operations in Embedded Studio .. note:: a. About the acquisition of |ses| solutions, please refer to :ref:`Software Source Codes `. b. About the detailed usage of |ses|, please refer to `How to develop with Segger Embedded Studio `_. 3. Press the on-board User Key(PA0-WKUP), then check the status of on-board RGB LED. .. _figure_lab1_3_7: .. figure:: /asserts/medias/lab1_3_fig7.jpg :alt: lab1_3_fig7 :width: 600 Experimental results **Exercises** Try to create you own application to use the internal interrupt of |nuclei_ncore| with non-vectored processing mode. .. _appendix_lab1_3: **Appendix** ``rvstar/exti_key_interrupt/main.c`` .. code-block:: c /** \brief main function \param[in] none \param[out] none \retval none */ int main(void) { int32_t returnCode; /* Board Config */ gd_rvstar_led_init(LED3); gd_rvstar_key_init(WAKEUP_KEY_GPIO_PORT,KEY_MODE_EXTI); /* EXIT config */ key_exti_init(); /* ECLIC config */ returnCode = ECLIC_Register_IRQ(EXTI0_IRQn, ECLIC_NON_VECTOR_INTERRUPT, ECLIC_LEVEL_TRIGGER, 1, 0, NULL); /* Enable interrupts in general */ __enable_irq(); while(1); return 0; } /** \brief initialize the EXTI configuration of the key \param[in] none \param[out] none \retval none */ void key_exti_init(void) { /* enable the AF clock */ rcu_periph_clock_enable(RCU_AF); /* connect key EXTI line to key GPIO pin */ gpio_exti_source_select(WAKEUP_KEY_EXTI_PORT_SOURCE, WAKEUP_KEY_EXTI_PIN_SOURCE); /* configure key EXTI line */ exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_FALLING); exti_interrupt_flag_clear(EXTI_0); } /** \brief EXTI line0 interrupt service routine \param[in] none \param[out] none \retval none */ void EXTI0_IRQHandler(void) { if (RESET != exti_interrupt_flag_get(WAKEUP_KEY_PIN)){ if(RESET == gd_rvstar_key_state_get(KEY_WAKEUP)){ /* toggle RED led */ gd_rvstar_led_toggle(LED3); } } /* clear EXTI lines pending flag */ exti_interrupt_flag_clear(WAKEUP_KEY_PIN); }