Forum: Mikrocontroller und Digitale Elektronik STM32F4 Discovery IRQ Handler


von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Morgääääähn!

Habe einen kleinen Code geschrieben bei dem ein Interrupt gesetzt werden 
soll. Allerdings scheint es so, als ob er nicht mehr resettet wird.

Als IDE verwende ich hierfür EMBlocks.

"main.c":
1
#include "stm32f4xx.h"
2
#include "stm32f4xx_conf.h"
3
4
int main(void)
5
{
6
7
///* Set Clocks *///
8
    //* AHB1 - GPIO-A, GPIO-C, GPIO-D *//
9
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD, ENABLE);
10
    //* APB1 - Timer2 *//
11
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
12
    //* APB2 - SYSCFG *//
13
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
14
15
///* GPIO *///
16
    //* Port A *//
17
    /* PA0 - UserButtonInput */
18
    GPIO_InitTypeDef GPIO_ButtonInput;
19
    GPIO_ButtonInput.GPIO_Pin   = GPIO_Pin_0; // PA0
20
    GPIO_ButtonInput.GPIO_Mode  = GPIO_Mode_IN;
21
    GPIO_ButtonInput.GPIO_OType = GPIO_OType_PP;
22
    GPIO_ButtonInput.GPIO_Speed = GPIO_Speed_2MHz;
23
    GPIO_ButtonInput.GPIO_PuPd  = GPIO_PuPd_NOPULL;
24
    GPIO_Init(GPIOA, &GPIO_ButtonInput);
25
    /* PA15 - PhaseInput */
26
    GPIO_InitTypeDef GPIO_PhaseInput;
27
    GPIO_PhaseInput.GPIO_Pin    = GPIO_Pin_15; // PA15
28
    GPIO_PhaseInput.GPIO_Mode   = GPIO_Mode_IN;
29
    GPIO_PhaseInput.GPIO_OType  = GPIO_OType_PP;
30
    GPIO_PhaseInput.GPIO_Speed  = GPIO_Speed_100MHz;
31
    GPIO_PhaseInput.GPIO_PuPd   = GPIO_PuPd_NOPULL;
32
    GPIO_Init(GPIOA, &GPIO_PhaseInput);
33
    //* Port C *///
34
    /* PC9 - SysClock Output */
35
    GPIO_InitTypeDef GPIO_SysClock;
36
    GPIO_SysClock.GPIO_Pin      = GPIO_Pin_9; // PC9
37
    GPIO_SysClock.GPIO_Mode     = GPIO_Mode_AF;
38
    GPIO_SysClock.GPIO_OType    = GPIO_OType_PP;
39
    GPIO_SysClock.GPIO_Speed    = GPIO_Speed_100MHz;
40
    GPIO_SysClock.GPIO_PuPd     = GPIO_PuPd_NOPULL;
41
    GPIO_Init(GPIOC, &GPIO_SysClock);
42
    //* Port D *//
43
    /* PD12,13,14,15 - LEDsOutput */
44
    GPIO_InitTypeDef GPIO_LEDsOutput;
45
    GPIO_LEDsOutput.GPIO_Pin   = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; // PD12, PD13, PD14, PD15
46
    GPIO_LEDsOutput.GPIO_Mode  = GPIO_Mode_OUT;
47
    GPIO_LEDsOutput.GPIO_OType = GPIO_OType_PP;
48
    GPIO_LEDsOutput.GPIO_Speed = GPIO_Speed_2MHz;
49
    GPIO_LEDsOutput.GPIO_PuPd  = GPIO_PuPd_NOPULL;
50
    GPIO_Init(GPIOD, &GPIO_LEDsOutput);
51
52
///* Interrupts *///
53
    //* Interrupt PA15*//
54
    /* Set PA15 to EXTI Line 15 */
55
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource15);
56
    /* Set ExternTriggerLine 15 */
57
    EXTI_InitTypeDef EXTI_PA15;
58
    EXTI_PA15.EXTI_Line    = EXTI_Line15;
59
    EXTI_PA15.EXTI_Mode    = EXTI_Mode_Interrupt;
60
    EXTI_PA15.EXTI_Trigger = EXTI_Trigger_Rising;
61
    EXTI_PA15.EXTI_LineCmd = ENABLE;
62
    EXTI_Init(&EXTI_PA15);
63
    /* Set Trigger to ExternTriggerLine10:15 */
64
    NVIC_InitTypeDef NVIC_Line10_15;
65
    NVIC_Line10_15.NVIC_IRQChannel                   = EXTI15_10_IRQn;
66
    NVIC_Line10_15.NVIC_IRQChannelPreemptionPriority = 0;
67
    NVIC_Line10_15.NVIC_IRQChannelSubPriority        = 0;
68
    NVIC_Line10_15.NVIC_IRQChannelCmd                = ENABLE;
69
    NVIC_Init(&NVIC_Line10_15);
70
71
///* Timers *///
72
    //* Timer2 Configuration - max loopTime 4294.967296s; set to: LoopTime 5s - 1µs per step *//
73
    //int TimerStepInt = 0.000001;    // in seconds
74
    //int TimerPeriod  = 5;           // in seconds
75
    //TIM_TimeBaseInitTypeDef TIM_Timer2;
76
    //TIM_Timer2.TIM_ClockDivision      = TIM_CKD_DIV1;
77
    //TIM_Timer2.TIM_CounterMode        = TIM_CounterMode_Up;
78
    //TIM_Timer2.TIM_Period             = (TimerPeriod / TimerStepInt) - 1;
79
    //TIM_Timer2.TIM_Prescaler          = (SystemCoreClock / (1 / TimerStepInt)) - 1;
80
    //TIM_Timer2.TIM_RepetitionCounter  = 0;
81
    //TIM_TimeBaseInit(TIM2, &TIM_Timer2);
82
83
///* Set SysClock Output On*///
84
    RCC_MCO2Config(RCC_MCO2Source_SYSCLK, RCC_MCO2Div_5); // PC9 Sysclock Output On
85
86
87
    while(1)
88
    {
89
90
        /* Set BLUE LED Off from switch */
91
        int PA0BIT = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0);
92
        if (PA0BIT == Bit_SET)
93
        {
94
            GPIO_WriteBit(GPIOD, GPIO_Pin_15, Bit_RESET); //PD15 LED Off
95
        }
96
        else
97
        {
98
            GPIO_WriteBit(GPIOD, GPIO_Pin_15, Bit_SET); //PD15 LED On
99
        }
100
101
    }
102
}

In die "stm32f4xx_conf.h" habe ich noch die "stm32fxx_it.h" eingebunden.

Letzter Abschnitt der "stm32fxx_it.c":
1
/******************************************************************************/
2
/*                 STM32F4xx Peripherals Interrupt Handlers                   */
3
/*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */
4
/*  available peripheral interrupt handler's name please refer to the startup */
5
/*  file (startup_stm32f4xx.s).                                               */
6
/******************************************************************************/
7
8
/**
9
  * @brief  This function handles PPP interrupt request.
10
  * @param  None
11
  * @retval None
12
  */
13
/*void PPP_IRQHandler(void)
14
{
15
}*/
16
17
/**
18
  * @brief IRQ Line 15
19
  */
20
void EXT15_10_IRQHandler(void)
21
{
22
    if(EXTI_GetITStatus(EXTI_Line15) != RESET)
23
    {
24
         GPIO_ToggleBits(GPIOD, GPIO_Pin_12); // PD12 LED On / Off
25
         EXTI_ClearFlag(EXTI_Line15); // Clear IRQ Line 15
26
    }
27
}
28
29
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

In meinem Startup-File ist dieser Handler auch drin.

Solange ich keine steigende Flanke an den GPIO PA15 schicke, 
funktioniert alles wie es soll. Sobald aber die Flanke vorbeischaut 
bleibt GPIO PD12, je nachdem ob PA0 auf High oder Low lag, in seiner 
Stellung und meine while Schleife wird nicht mehr ausgeführt. Fühlt sich 
für mich als Anhänger danach an, dass der IRQ nicht mehr resettet wird. 
Weiß jemand Rat? Bestimmt beachte ich wieder irgendwas nicht.

Libe Grüße
Reggie


EDIT: Was mir auch noch nicht so klar ist: Der Compiler durchsucht alle 
von mir angegebenen Dateien und Pfade nach den benötigten Funktionen / 
Variablen? Oder woher holt er sich den Handler?

: Bearbeitet durch User
von Esam (Gast)


Lesenswert?

Reginald L. schrieb:
> EDIT: Was mir auch noch nicht so klar ist: Der Compiler durchsucht alle
> von mir angegebenen Dateien und Pfade nach den benötigten Funktionen /
> Variablen? Oder woher holt er sich den Handler?

Der Name des Interrupt-Handlers sollte in der IVT (Interrupt Vector 
Table) auftauchen. Ist das nicht der Fall, wird das wahrscheinlich in 
einem HardFault enden. Ich hab dein Programm nicht darauf hin überprüft, 
nur soviel dazu.

Im Normalfall macht kein Compiler irgendwas von allein sondern strikt 
das, was man ihm sagt. Natürlich muss man seine Sprache sprechen, sonst 
sind "Mißverständnisse" vorprogrammiert.

von pitschu (Gast)


Lesenswert?

Hallo reggie,

sieht alles korrekt aus, bis mir auffiel, dass Du den Handler falsche 
gschrieben hast: er heißt EXTI15_10_IRQHandler, bei Dir fehlt das I. 
Dadurch wird nicht deiner, sondern der Default handler (in einem der 
Startup files als weak definiert), aufgerufen und der geht in eine 
Endlos while()-Schleife.

pitschu

von Stephan (Gast)


Lesenswert?

Hi Reginald Leonczuk,
ist zwar nicht der gleiche MC, aber schau mal hier:
http://www.keil.com/forum/19705/clear-of-external-interrupt-pending-bit/
1
void EXTI15_10_IRQHandler (void) __irq
2
{
3
  if(EXTI_GetITStatus(EXTI_Line15) != RESET)
4
  {
5
    /* Clear the EXTI line 15 pending bit */
6
    EXTI_ClearITPendingBit(EXTI_Line15);
7
8
    /*Send Semaphore */
9
    isr_sem_send (semaphore1);
10
11
    /* Re-clears the interrupt */
12
    NVIC_ClearPendingIRQ(EXTI15_10_IRQn);
13
  }
14
}

Hilft dir das weiter?

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Das soll laut Manual "EXTI15_10" sein. In der Startup-File steht das 
zwar auch, aber angehängt ist daran "_IRQHANDLER", so wie in meinem 
Script auch. Bei den ganzen Beispielen die ich durchforstet habe, ist 
das Handler auch so angegeben wie bei mir. Warum das vom Manual 
abweicht, verstehe ich nicht wirklich, da ich mich durch die Startup 
Routinen noch nicht durchgelesen habe.

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

pitschu schrieb:
> Hallo reggie,
>
> sieht alles korrekt aus, bis mir auffiel, dass Du den Handler falsche
> gschrieben hast: er heißt EXTI15_10_IRQHandler, bei Dir fehlt das I.
> Dadurch wird nicht deiner, sondern der Default handler (in einem der
> Startup files als weak definiert), aufgerufen und der geht in eine
> Endlos while()-Schleife.
>
> pitschu


Das Thema "Problematik" zur Error-Ausgabe, in Bezug auf die Interrupts, 
habe ich schon im Internet gefunden. Daran habe ich schon gedacht. Vom 
Denken allein ist der Code trotzdem nicht weitergelaufen.


pitschu, mein drittes Auge, vielen lieben Dank! Wieder was gelernt!

An alle Anderen auch ein liebes Dankeschön für eure Mühe :)

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Neues Problem, in diesem Zusammenhang:
Meine Interrupts werden zwar korrekt ausgelöst, allerdings schleicht 
sich von Zeit zu Zeit ein zusätzlicher Interrupt ein. Meine Vermutung 
ist, dass mein IRQ-Handler nochmals zusätzlich ausgelöst wird, sobald 
der Timer einmal durchgelaufen ist (der läuft wohl intern trotzdem bis 
zum Schluss, obwohl ich ihn per TIM_SetCounter(TIM2, 0) resette?)

Versuche schon seit gestern, entweder den Timer komplett neu zu starten, 
oder wenigstens den zusätzlichen Interrupt anderweitig zu unterbinden, 
ohne Erfolg. Bisher habe ich mir mit einem if-Block weitergeholfen, kann 
ja aber nicht die Lösung des Problems sein.

Immer noch STM32F4 Discovery, CrossWorks IDE
1
/// PA15 IRQ ///
2
    NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;
3
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
4
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
5
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
6
    NVIC_Init(&NVIC_InitStruct);
7
8
/// TIMER 2 - Phase Trigger///
9
    TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
10
    TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
11
    TIM_InitStruct.TIM_Period = 5000000 - 1; // Count to 5s
12
    TIM_InitStruct.TIM_Prescaler = 84 - 1;   // Interval 1µs
13
    TIM_TimeBaseInit(TIM2, &TIM_InitStruct);
14
    // Set TIMER 2 Extern Trigger //
15
    TIM_SelectInputTrigger(TIM2, TIM_TS_ETRF);
16
    TIM_ETRConfig(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);
17
    TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Trigger);
18
    // Enable TIMER 2 IRQ //
19
    TIM_ITConfig(TIM2, TIM_IT_Trigger, ENABLE);
20
21
/** TIMER 2 IRQ **/
22
void TIM2_IRQHandler(void)
23
{
24
        if (TIM_GetCounter(TIM2) > 10000)
25
        {
26
        TriggerValue = TIM_GetCounter(TIM2);
27
        }
28
        TIM_SetCounter(TIM2, 0);
29
        TIM_ClearITPendingBit(TIM2, TIM_IT_Trigger);
30
31
}

von Little B. (lil-b)


Lesenswert?

ich kenne das Phänomen, habe selbst schonmal damit gekämpft, wobei es 
bei mir TIM6 war.

Das Problem sollte durch folgende Code-Änderung lösbar sein:
Setze das Interrupt Bit nicht am Ende der ISR zurück, sondern früher.
Ich setze es immer als erste Anweisung in der ISR zurück.

Folgender Hintergrund: (so erkläre ich mir das Phänomen)
Die Timer hängen an den langsamen APB1/2. Ein Registerzugriff ist 
enstprechend langsam. Bis die Anweisung, das Bit zu löschen, im 
Timerregister angekommen ist, kann der Prozessor schon deutlich weiter 
sein. Bis dann auch der NVIC gemerkt hat, dass kein Interrupt mehr 
ansteht, kann der Core bereits aus der ISR rausgesprungen sein und 
springt daher direkt wieder rein.

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Jetzt wo dus sagst, das habe ich schon irgendwo gelesen :>
Vielen Dank für den Tipp, ich werds gleich mal ausprobieren!

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Hehe, das wird nur noch schlimmer :)
Jetzt kommt der Interrupt, den ich eigentlich nicht haben mag, nur noch 
öfters. Normalerweise bekomme ich Timerwerte zwischen 30k - 1M. Es 
kommen aber immer wieder mal die Werte 0 und 1 vor. Wenn ich nun das 
InterruptBit gleich zu Anfang der ISR zurücksetze, kommen diese nicht 
gewollten Werte öfter, auch die 2 ist dann schon mal aufgetaucht. Die 
Werte kommen dann auch nicht mehr alle 5s, sondern öfter. Ich steh aufm 
Schlauch :>

EDIT: Achso, der gewollte Interrupt löst mit etwa 1-50Hz aus, also 
zeitlich is da nicht viel los.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.