|
Interrupts are asynchronous **hardware signals** that can be handled in software. They are handled by the microcontroller immediately, therefore **interrupting** whatever was being executed before the interrupt.
|
|
Interrupts are asynchronous **hardware signals** that can be handled in software. They are handled by the microcontroller immediately, therefore **interrupting** whatever was being executed before the interrupt.
|
|
|
|
|
|
Interrupts can be generated by different events, such as exceptions, timer counter overflows, incoming messages on a bus, GPIO level change etc... All these events generate an **Interrupt REQuest (IRQ)**, which is managed in software by the corresponding IRQHandler().
|
|
Interrupts can be generated by different events, such as exceptions, timer counter overflows, incoming messages on a bus, GPIO level change etc...
|
|
|
|
All these events generate an **Interrupt REQuest (IRQ)**, which is managed in software by the corresponding **Interrupt Request Handler** (_IRQHandler_): a software function which is called every time the interrupt takes place.
|
|
|
|
|
|
This page gives some quick information on how to use Interrupts with MIOSIX in STM32 boards.
|
|
This page gives some quick information on how to use Interrupts with MIOSIX in STM32 boards.
|
|
|
|
|
... | @@ -25,9 +26,24 @@ TIM2->CR1 |= TIM_CR1_CEN; |
... | @@ -25,9 +26,24 @@ TIM2->CR1 |= TIM_CR1_CEN; |
|
|
|
|
|
#### 1.2 GPIO interrupts (EXTI peripheral)
|
|
#### 1.2 GPIO interrupts (EXTI peripheral)
|
|
|
|
|
|
To generate an interrupt on a GPIO rising/falling edge you will have configure the EXTI and SYSCFG->EXTICR registers. Pins that end with the same number are part of the same interrupt **line** (e.g. PA1, PB1, PC1 -> line 1). Each line can be associated to only one pin (e.g. for line 1 you can generate an interrupt for PA1 **or** PB1 etc...).
|
|
To generate an interrupt on a GPIO rising/falling edge you will have configure the `EXTI` and `SYSCFG->EXTICR` registers.
|
|
|
|
|
|
This is an example of how to enable interrupt generation on the falling edge of `PC4`. More details can be found in the SYSCFG section of the STM32 reference manual.
|
|
GPIOs with the same pin number are part of the same **interrupt line** (e.g. `PA1`, `PB1`, `PC1` are assigned to `line 1`). There exist 16 lines (from 0 to 15).
|
|
|
|
Each line can be associated to only one pin at a time: for line 1 you can generate an interrupt for `PA1` **or** `PB1`, but not for both of them. In fact pins on the same line are multiplexed. But for example you can enable the interrupt both for `PA1` and `PC3` since they are on different lines (1 and 3).
|
|
|
|
Finally consider that only lines from 0 to 4 have their dedicated interrupt handler function (one handler for each line 0-4). Lines 5-9 and 10-15 are associated to the same interrupt handler (one for lines 5-9 and one for lines 10-15).
|
|
|
|
|
|
|
|
<!---<div align="center"><img src="images/interrupts/interrupt_lines.png" height="250"/><br/><i></i></div><br>--->
|
|
|
|
|
|
|
|
Anyway, if you have to enable multiple interrupts on the same line or on those lines that have a shared handler, when the interrupt is received you can check the `EXTI->PR` register to know which line triggered the interrupt. The same is done in _skyward-boardcore_ when an interrupt is triggered on lines 5-9 or 10-15, in `src/shared/drivers/interrupt/external_interrupts.cpp`: after checking on which line the interrupt was triggered, a specific function is called for each interrupt line from 5 to 9 or from 10 to 15.
|
|
|
|
|
|
|
|
This is an example of how to enable interrupt generation on the falling edge of `PC4`. More details can be found in the `SYSCFG` section of the STM32 reference manual (see references below). There you can find the way in which the `SYSCFG->EXTICR` register has to be configured to assign the interrupt to a specific GPIO. `SYSCFG->EXTICR` is an array of four elements (`SYSCFG->EXTICR1` to `SYSCFG->EXTICR4`).
|
|
|
|
|
|
|
|
<!--- Here you find the correlation among `SYSCFG->EXTICR` and the GPIOs:
|
|
|
|
- `SYSCFG->EXTICR[0]`: EXTI from 0 to 3
|
|
|
|
- `SYSCFG->EXTICR[1]`: EXTI from 4 to 7
|
|
|
|
- `SYSCFG->EXTICR[2]`: EXTI from 8 to 11
|
|
|
|
- `SYSCFG->EXTICR[3]`: EXTI from 12 to 15
|
|
|
|
The value to be assigned is: 0 for `PAx`, 1 for `PBx`, 2 for `PCx`, 3 for `PDx`, 4 for `PEx`, 5 for `PFx` --->
|
|
|
|
|
|
```cpp
|
|
```cpp
|
|
// Clear the mask on line 4
|
|
// Clear the mask on line 4
|
... | @@ -42,12 +58,13 @@ EXTI->FTSR |= EXTI_FTSR_TR4; |
... | @@ -42,12 +58,13 @@ EXTI->FTSR |= EXTI_FTSR_TR4; |
|
EXTI->PR |= EXTI_PR_PR4; // Reset pending register of line 4
|
|
EXTI->PR |= EXTI_PR_PR4; // Reset pending register of line 4
|
|
|
|
|
|
// Assign the interrupt of line 4 to GPIOC (=> PC4)
|
|
// Assign the interrupt of line 4 to GPIOC (=> PC4)
|
|
SYSCFG->EXTICR[2] = 0x2;
|
|
// this sets the SYSCFG->EXTICR2 register to 0010 (bits 0:3 refer to EXTI4)
|
|
|
|
SYSCFG->EXTICR[1] = 0x2;
|
|
```
|
|
```
|
|
|
|
|
|
## Step 2: Enable IRQ Handling
|
|
## Step 2: Enable IRQ Handling
|
|
|
|
|
|
After enabling the interrupt generation, you also have to enable the interrupt **handling** in the NVIC (Nested Vector Interrupt Controller), giving it a priority. More information on NVIC can be found on the datasheet.
|
|
After enabling the interrupt generation, you also have to enable the **interrupt handling** in the **NVIC** (_Nested Vector Interrupt Controller_), giving it a priority (lower value, higher priority). More information on NVIC can be found on the datasheet.
|
|
|
|
|
|
```cpp
|
|
```cpp
|
|
// Enable the interrupt called EXTI4
|
|
// Enable the interrupt called EXTI4
|
... | @@ -58,11 +75,11 @@ NVIC_SetPriority(EXTI4_IRQn, 15); |
... | @@ -58,11 +75,11 @@ NVIC_SetPriority(EXTI4_IRQn, 15); |
|
|
|
|
|
## Step 3: Writing an IRQHandler
|
|
## Step 3: Writing an IRQHandler
|
|
|
|
|
|
In the `core/stage_1_boot.cpp` file of your board (located in `miosix-kernel/miosix/arch/<ARCH>/<BOARD>/`) all the possible IRQHandlers are defined. They are all defined with `__attribute__((weak))`: this means that if you provide your own implementation of the same function in a .cpp file and compile it, the default one will be overridden by yours.
|
|
In the `core/stage_1_boot.cpp` file of your board (located in `miosix-kernel/miosix/arch/<ARCH>/<BOARD>/`) all the possible IRQHandlers are defined. They are all defined with `__attribute__((weak))`: this means that if you provide your own implementation of the same function in a `.cpp` file and compile it, the default one will be overridden by yours.
|
|
|
|
|
|
To do this you will have to write the following code, which contains some magic related to [GCC name mangling](https://en.wikipedia.org/wiki/Name_mangling), in a .cpp file.
|
|
To do this you will have to write the following code, which contains some magic related to [GCC name mangling](https://en.wikipedia.org/wiki/Name_mangling), in a `.cpp` file.
|
|
|
|
|
|
> :warning: **RESET PENDING BIT REGISTER in your IRQHandler, otherwise you will enter an infinite loop.**
|
|
> :warning: **RESET THE INTERRUPT PENDING BIT REGISTER in your IRQHandler, otherwise you will enter an infinite loop.**
|
|
|
|
|
|
> :warning: **DON'T USE BLOCKING OR "HEAVY" FUNCTIONS (e.g. *printf()*) inside your interrupt. Remember that the CPU will stall for the whole time it will execute your IRQHandler. Most of the times, the only thing you will need in your IRQHandler is to set a global variable or to operate with registers.**
|
|
> :warning: **DON'T USE BLOCKING OR "HEAVY" FUNCTIONS (e.g. *printf()*) inside your interrupt. Remember that the CPU will stall for the whole time it will execute your IRQHandler. Most of the times, the only thing you will need in your IRQHandler is to set a global variable or to operate with registers.**
|
|
|
|
|
... | @@ -85,3 +102,11 @@ void __attribute__((used)) EXTI4_IRQHandlerImpl() |
... | @@ -85,3 +102,11 @@ void __attribute__((used)) EXTI4_IRQHandlerImpl() |
|
// Write me!
|
|
// Write me!
|
|
}
|
|
}
|
|
```
|
|
```
|
|
|
|
|
|
|
|
## References
|
|
|
|
|
|
|
|
* [RM0090, Reference Manual - Section 9, System Configuration Controller](https://www.st.com/resource/en/reference_manual/dm00031020-stm32f405-415-stm32f407-417-stm32f427-437-and-stm32f429-439-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf)
|
|
|
|
|
|
|
|
* [STM32F4 External Interrupts Tutorial](https://stm32f4-discovery.net/2014/08/stm32f4-external-interrupts-tutorial/)
|
|
|
|
|
|
|
|
* [Intro to Hardware Interrupts](https://vivonomicon.com/2018/04/28/bare-metal-stm32-programming-part-4-intro-to-hardware-interrupts/) |
|
|
|
\ No newline at end of file |