Author Topic: How do interrupts work stm32f0 discovery board, coming from PIC background  (Read 752 times)

0 Members and 1 Guest are viewing this topic.

Offline Etesla

  • Regular Contributor
  • *
  • Posts: 94
  • Country: us
Hi all,
I come from a PIC microcontroller background. On a PIC, in C, you use a function called "void __interrupt () isr(void)" to catch all interrupts. You then have a bunch of if statements inside of this function to determine which interrupt has occurred. As far as I understand from some quick googling, this is not how interrupts work with these newfangled arm micros. It seems as though each possible interrupt triggers its own function to be called, like a timer1 overflow interrupt would have a function associated with it called something like tmr1Overflow_handler(), and an ADC ready interrupt would have a function called something like ADCReady_handler(). My question is twofold. Am I understanding this correctly, and how do you know what these pre-associated functions are named to begin with? I learn best through examples, so if someone would be willing to write out the C code to set up a timer compare match interrupt or something super simple like that, that would be great. Thank you in advance!
 

Offline jhpadjustable

  • Frequent Contributor
  • **
  • Posts: 295
  • Country: us
  • Salt 'n' pepper beard
Quote
this is not how interrupts work with these newfangled arm micros
That's a library layer you can often mostly ignore, if you would prefer. Take a look at the assembler startup file for your build environment or skeleton project. In a project generated by STM32CubeMX for an F103, for example, the vector table is placed at the correct flash address by the linker script and looks a bit like:
Code: [Select]
  .word _estack
  .word Reset_Handler
  .word NMI_Handler
  .word HardFault_Handler
  .word MemManage_Handler
  .word BusFault_Handler
  .word UsageFault_Handler
...
  .word USB_HP_CAN1_TX_IRQHandler
  .word USB_LP_CAN1_RX0_IRQHandler
  .word CAN1_RX1_IRQHandler
  .word CAN1_SCE_IRQHandler
  .word EXTI9_5_IRQHandler
  .word TIM1_BRK_IRQHandler
  .word TIM1_UP_IRQHandler
  .word TIM1_TRG_COM_IRQHandler
  .word TIM1_CC_IRQHandler
  .word TIM2_IRQHandler
  .word TIM3_IRQHandler
  .word TIM4_IRQHandler
  .word I2C1_EV_IRQHandler
...
where each name refers to a void function returning void, no pragmas required:
Code: [Select]
void
TIM1_TRG_COM_IRQHandler(void)
{
  if (TIM1->DIFR & CC1IF) { // made up names just for illustration
    tmr1CaptureCompare_Handler();
    TIM1->DIFR = CC1IF;
  }
    ...
}
The documentation for ST's HAL for the 32F0 is available as ST document UM1785. Each HAL chapter lists the names of the callbacks which it allows you to implement, e. g. HAL_TIM_IC_CaptureCallback(). You could also provide your own implementation for the IRQHandler functions if you want to do it by hand, the old fashioned way. I usually use the ST HAL, because it's free, saves a bit of effort, and it hasn't gotten too much in the way yet. :)
"There are more things in heaven and earth, Arduino, than are dreamt of in your philosophy."
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 7405
  • Country: us
Google for 'stm32f0 timer interrupt example' - there are many responses.

There is no comparison between the interrupt structure of a PIC and that of the modern ARM.  The good news is that you don't have to tell the compiler that the function is an interrupt handler on these newer Cortex chips.  All interrupt handlers are just void functions with void parameters.

http://eleceng.dit.ie/frank/arm/BareMetalSTM32F0Discovery/timerirq.html

Notice in the vector table at the bottom of the page that all vectors are branching to DefaultHandler + 1 (which isn't shown) except for the active vector that points to Timer1ISR.  This means every time you add an interrupt handler, you have to modify the startup code.

Sometimes the vector table has code to branch to actual functions for every interrupt, each function has a specific name.  Later on in the code, all of those functions will be defined at a single entry point like DefaultHandler except that they are labeled as 'weak'.  The target address in the vector can be overridden at link time when a real handler is defined.  As a result, you never have to modify the startup code, the existence of a named function will override the 'weak' definition.
 

Online emece67

  • Regular Contributor
  • *
  • Posts: 222
  • Country: es
Look for the startup_stm32f051x8.s file on your disk. It contains the vector table:

Code: [Select]
__Vectors       DCD     __initial_sp                   ; Top of Stack
                DCD     Reset_Handler                  ; Reset Handler
                DCD     NMI_Handler                    ; NMI Handler
                DCD     HardFault_Handler              ; Hard Fault Handler
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     SVC_Handler                    ; SVCall Handler
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     PendSV_Handler                 ; PendSV Handler
                DCD     SysTick_Handler                ; SysTick Handler

                ; External Interrupts
                DCD     WWDG_IRQHandler                ; Window Watchdog
                DCD     PVD_IRQHandler                 ; PVD through EXTI Line detect
                DCD     RTC_IRQHandler                 ; RTC through EXTI Line
                DCD     FLASH_IRQHandler               ; FLASH
                DCD     RCC_IRQHandler                 ; RCC
                DCD     EXTI0_1_IRQHandler             ; EXTI Line 0 and 1
                DCD     EXTI2_3_IRQHandler             ; EXTI Line 2 and 3
                DCD     EXTI4_15_IRQHandler            ; EXTI Line 4 to 15
                DCD     TSC_IRQHandler                 ; TS
                DCD     DMA1_Channel1_IRQHandler       ; DMA1 Channel 1
                DCD     DMA1_Channel2_3_IRQHandler     ; DMA1 Channel 2 and Channel 3
                DCD     DMA1_Channel4_5_IRQHandler     ; DMA1 Channel 4 and Channel 5
                DCD     ADC1_COMP_IRQHandler           ; ADC1, COMP1 and COMP2
                DCD     TIM1_BRK_UP_TRG_COM_IRQHandler ; TIM1 Break, Update, Trigger and Commutation
                DCD     TIM1_CC_IRQHandler             ; TIM1 Capture Compare
                DCD     TIM2_IRQHandler                ; TIM2
                DCD     TIM3_IRQHandler                ; TIM3
                DCD     TIM6_DAC_IRQHandler            ; TIM6 and DAC
                DCD     0                              ; Reserved
                DCD     TIM14_IRQHandler               ; TIM14
                DCD     TIM15_IRQHandler               ; TIM15
                DCD     TIM16_IRQHandler               ; TIM16
                DCD     TIM17_IRQHandler               ; TIM17
                DCD     I2C1_IRQHandler                ; I2C1
                DCD     I2C2_IRQHandler                ; I2C2
                DCD     SPI1_IRQHandler                ; SPI1
                DCD     SPI2_IRQHandler                ; SPI2
                DCD     USART1_IRQHandler              ; USART1
                DCD     USART2_IRQHandler              ; USART2
                DCD     0                              ; Reserved
                DCD     CEC_IRQHandler                 ; CEC
where you can read the IRQ handler names. Then, simply, define your handler as a function taking void and returning void., e.g.:

Code: [Select]
volatile uint32_t  ticks = 0;

void SysTick_Handler(void) {
  ticks++;
}

Of course you also need to turn on the peripheral, configure it, enable its IRQ,...

Note that the previous startup_stm32f051x8.s file weakly defines the handlers as:
Code: [Select]
Default_Handler PROC

                EXPORT  WWDG_IRQHandler                [WEAK]
                EXPORT  PVD_IRQHandler                 [WEAK]
                EXPORT  RTC_IRQHandler                 [WEAK]
                EXPORT  FLASH_IRQHandler               [WEAK]
                EXPORT  RCC_IRQHandler                 [WEAK]
                EXPORT  EXTI0_1_IRQHandler             [WEAK]
                EXPORT  EXTI2_3_IRQHandler             [WEAK]
                EXPORT  EXTI4_15_IRQHandler            [WEAK]
                EXPORT  TSC_IRQHandler                 [WEAK]
                EXPORT  DMA1_Channel1_IRQHandler       [WEAK]
                EXPORT  DMA1_Channel2_3_IRQHandler     [WEAK]
                EXPORT  DMA1_Channel4_5_IRQHandler     [WEAK]
                EXPORT  ADC1_COMP_IRQHandler           [WEAK]
                EXPORT  TIM1_BRK_UP_TRG_COM_IRQHandler [WEAK]
                EXPORT  TIM1_CC_IRQHandler             [WEAK]
                EXPORT  TIM2_IRQHandler                [WEAK]
                EXPORT  TIM3_IRQHandler                [WEAK]
                EXPORT  TIM6_DAC_IRQHandler            [WEAK]
                EXPORT  TIM14_IRQHandler               [WEAK]
                EXPORT  TIM15_IRQHandler               [WEAK]
                EXPORT  TIM16_IRQHandler               [WEAK]
                EXPORT  TIM17_IRQHandler               [WEAK]
                EXPORT  I2C1_IRQHandler                [WEAK]
                EXPORT  I2C2_IRQHandler                [WEAK]
                EXPORT  SPI1_IRQHandler                [WEAK]
                EXPORT  SPI2_IRQHandler                [WEAK]
                EXPORT  USART1_IRQHandler              [WEAK]
                EXPORT  USART2_IRQHandler              [WEAK]
                EXPORT  CEC_IRQHandler                 [WEAK]


WWDG_IRQHandler
PVD_IRQHandler
RTC_IRQHandler
FLASH_IRQHandler
RCC_IRQHandler
EXTI0_1_IRQHandler
EXTI2_3_IRQHandler
EXTI4_15_IRQHandler
TSC_IRQHandler
DMA1_Channel1_IRQHandler
DMA1_Channel2_3_IRQHandler
DMA1_Channel4_5_IRQHandler
ADC1_COMP_IRQHandler
TIM1_BRK_UP_TRG_COM_IRQHandler
TIM1_CC_IRQHandler
TIM2_IRQHandler
TIM3_IRQHandler
TIM6_DAC_IRQHandler
TIM14_IRQHandler
TIM15_IRQHandler
TIM16_IRQHandler
TIM17_IRQHandler
I2C1_IRQHandler
I2C2_IRQHandler
SPI1_IRQHandler
SPI2_IRQHandler
USART1_IRQHandler
USART2_IRQHandler
CEC_IRQHandler

                B       .

                ENDP

So any handler you do not define is short circuited to this default handler that, if called, simply hangs.

Also, file stm32f051x8.h contains the names for peripheral registers and their bits/fields, take a look at it. The core peripherals are instead in core_cm0.h (_cm0 as the stm32f051 has a Cortex-M0 core).

Regards.
« Last Edit: August 27, 2019, 05:06:30 pm by emece67 »
Information must flow.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf