Lesson 3: Part 1: Interrupt - On-Board Input

Now we are able to read input status from the input pin. In the previous lesson, we have to keep reading the input pin to detect for button press. In a DVD player example, it is very unlikely user will be pressing the button(e.g. play button). But in order to cater for this user interaction, system have to keep reading the input, which is quite inefficient.

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:
  1. Configure input (as shown in previous lesson here)
  2. Configure MCU such that the input state change, it will trigger an interrupt
  3. Select rising/falling interrupt
  4. Enable interrupt
  5. Created ISR source code
The above should serve a guidelines as different interrupt architecture would require different configurations.

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
With this, I believe a section of the NVIC description has left out in technical document. Further digging into Keil header file leads me to below:

/** \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
What we need to do is just declare a function with same name to 'connect' into it.

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
Each time ISR is being called, we also need to clear the bit so that next interrupt could happen.

The Source Code

The complete source code has been push into git.

No comments:

Post a Comment