The better method would be configure the MCU in such that any input pin change, notify to the program via interrupt. The function that will be called when interrupt occur is called Interrupt Service Routine(ISR).
The following settings will be require to get this function to work:
- Configure input (as shown in previous lesson here)
- Configure MCU such that the input state change, it will trigger an interrupt
- Select rising/falling interrupt
- Enable interrupt
- Created ISR source code
For input interrupt, 2 configuration is possible, namely: falling interrupt or rising interrupt. This essentially represent the signal state changes. Taking button as example, idle button state will have voltage high, when user press the button, voltage will change from high to low - falling interrupt. Similarly, rising interrupt occur when user release the pressed button.
Configure MCU For Input Interrupt
We need to figure out the SFR that enable interrupt to be generated, when our input change.SYSCFG_EXTICR1:EXTI0 = 0000 Notifying MCU Tie PA0 To Interrupt Line 0 |
EXTI_IMR:MR0 = 1 Enable Line 0 Interrupt |
Select Falling/Rising Interrupt
EXTI_FTSR:TR1 Falling Trigger Enable For Button Press |
EXTI_RTSR: TR1 Rising Trigger Enable For Button Release |
Enable Interrupt
This is the best part of writing this lesson. I do not found any description on the technical document. Thus I have no choice but skip this section while writing the source code, and the result: things does not work.Scanning the document up and down doesn't have much, expect I spot a section on NVIC (Nested Vector Interrupted Controller), but no SFR at end of section. And later on I discovered this in debugging session:
NVIC Discovery in Debugger Mode |
/** \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC).
*/
typedef struct
{
__IO uint32_t ISER[1]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */
uint32_t RESERVED0[31];
__IO uint32_t ICER[1]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */
uint32_t RSERVED1[31];
__IO uint32_t ISPR[1]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */
uint32_t RESERVED2[31];
__IO uint32_t ICPR[1]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */
uint32_t RESERVED3[31];
uint32_t RESERVED4[64];
__IO uint32_t IP[8]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */
} NVIC_Type;
Above looks promising with SFR 'ISER', which finally lead to below line to enable interrupt line 0:
NVIC->ISER[0] |= (0x01<<EXTI0_1_IRQn);
And it works! The bad thing, I spend about an hour just because of the missing specification.
**After contacted with ST FAE, they have point me to the document that have description on above SFR register. I do not understand why it is in separate document, my guess is they use the same document for all M0 core, which may include other STM series.
Writing ISR
Writing ISR is a bit tedious as you have to know how to 'tell' your compiler this is an ISR. Thus it generally varies from one compiler to the other one. In our case here, the vector is define in startup file as below:ISR in startup_stm32f030.s |
Lastly, in our ISR we may need to include a checking to ensure the interrupt source is indeed from button, and not from others by checking SFR below:
EXTI_PR:PR0 Reading Interrupt Source, and clearing it |
No comments:
Post a Comment