Forum: Mikrocontroller und Digitale Elektronik STM32F103 nach Interrupt im Nirvana


von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich arbeite mit Embitz und debugge mich grad durch meine Funkanwendung. 
Soweit so gut, die Daten kommen auch rein aber seltsamerweise hängt sich 
die CPU dann irgendwie auf. D.h. Breakpoints im Hauptprogramm werden 
nicht mehr erkannt aber die Interrupts die LEDs blinken lasse laufen 
munter weiter.

Im Debug Mode lässt sich das Problem soweit einkreisen, wie im Bild zu 
sehen. D.h. dsas Funkmodul hat gültige Daten empfangen, es wurde ein INT 
ausgelöst und die CPU holt sich diese rein. Tippe ich mich bis zum Ende 
durch ist bei der Klammer Schluss, danach ist er "weg". Kein gelber 
Balken mehr, keine Reaktion auf Breakpoints. Callstack stimmt aber 
soweit.

Ich habe beim Linken übrigens LTO eigeschaltet, benutze die Nano Lib.

Kennt das jemand?

Gruss,
Christian

von DraconiX (Gast)


Lesenswert?

Den Interrupt Handler hast du ordnungsgemäß zurückgesetzt?! Die 
Komplette ISR zur Posten wäre eventuell Sinnvoll. ;-)

von hans im glück (Gast)


Lesenswert?

Einfach mal pausieren? Wo steht er dann?

von Aruinoquäler (Gast)


Lesenswert?

DraconiX schrieb:
> Den Interrupt Handler hast du ordnungsgemäß zurückgesetzt?!

Den Interrupt Handler kann man nicht zurücksetzen. Allenfalls
kann und sollte man ein Interrupt Flag zurücksetzen wenn es
gesetzt wurde.

von DraconiX (Gast)


Lesenswert?

Aruinoquäler schrieb:
> DraconiX schrieb:
> Den Interrupt Handler hast du ordnungsgemäß zurückgesetzt?!
>
> Den Interrupt Handler kann man nicht zurücksetzen. Allenfalls
> kann und sollte man ein Interrupt Flag zurücksetzen wenn es
> gesetzt wurde.

Ja gut, dann halt im Interrupt-Handler die Interrupt-Flag zurück 
gesetzt. :-D

Und ja, wenn ein Int ausgelöst wurde, wurde die Flag ja auch sicherlich 
gesetzt. Gibt es denn beim STM32 ein Interrupt der ausgelöst werden 
kann, welcher nicht zurück gesetzt werden muss? Ist mir bis dato noch 
nicht übern Weg gelaufen, wäre aber Interessant zu wissen.

von Christian J. (Gast)


Lesenswert?

Ich kapier es nicht!

In der for Schleife landet er im HardFault Handler! Das war doch vorher 
nicht....


/* Startet die RTC */
void Init_RTC()
{
        volatile uint32_t i;
        /* Enable PWR and BKP clocks */
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, 
ENABLE);
        /* LSI clock stabilization time */
        for(i=0;i<5000;i++);

von Christian J. (Gast)


Lesenswert?

DraconiX schrieb:
> Den Interrupt Handler hast du ordnungsgemäß zurückgesetzt?! Die
> Komplette ISR zur Posten wäre eventuell Sinnvoll. ;-)

Ähm...... Den setze ich nicht zurück, der soll ja zur Laufzeit umgebogen 
sein. Ich setze nur die INT Flags zurück.....

Problem ist: Das Laufzeitverhalten ist anders als wenn ich rum debugge.
Mein Master sendet 150 Datensätze, die stehen beim "Run" im Debug Mode 
auch alle fein im Array of struct drin, läuft nichts über etc. Alle 3 
Timer lösen ihren Int aus, der RTC Int auch, die Dimmung über die PWM 
Outsputs läuft auch....  setze ich einen roten Break Punkt klebt er 
sofort da dran.
aber er ist aus main while (1) {...} einfach raus. Da kommt er gar nicht 
mehr hin.

Der Stop Knopf zum Pausieren geht nicht mehr, da passiert gar nichts 
mehr.

Habe testweise mal die Libs verändert, nehme ich die Link Time 
Optimization raus schmiert er mit hardFault ganz ab.


Hier die Int Routine:
1
/* ====================== Interrupt Handler RF Modul ============================*/
2
3
void IRQ_ROUTINE(void)
4
{
5
6
    static uint8_t tcnt = 0;
7
8
    if(EXTI_GetITStatus(IRQ_LINE)!=RESET)
9
    {
10
            // ISR Code.....
11
        if (RF_DataReady())
12
        {
13
            SetRedLED(ENABLE);
14
            // RF_CE_Enable(ENABLE);                    // TEST & FIXXXME !!!!
15
16
            /* In welcher Pipe sind Daten? */
17
            uint8_t pipe = RF_GetFilledPipe();
18
            /* Wie viele Bytes sind da ?*/
19
            uint8_t nrBytes = RF_GetPayloadSize();
20
21
            if ((pipe == 1) && (nrBytes <= sizeof(actual_data)))
22
            {
23
                f_RF_Timeout = false;
24
                ReceivedDataBlocks++;
25
26
                /* Daten auslesen */
27
                RF_ReadPayload((uint8_t*)&actual_data,nrBytes);
28
29
                if (actual_data.Feuchte_Now > 90)
30
                    actual_data.Feuchte_Now = 100;
31
32
                /* ----- Sind es historische Daten? ------------ */
33
                // Sind es historische Daten?
34
                if (actual_data.command == RX_CMD_HISTORY)
35
                {
36
                    // Neue Daten in Historie kopieren
37
                    uint8_t index = actual_data.nrDataSet;
38
                    if (index <= HISTORY_MAX_IDX)
39
                    {
40
                       /* Zeit gelegentlich neu setzen */
41
                        if (++tcnt >= 60) {
42
                            Set_NewTime(actual_data.unix);
43
                            tcnt = 0;
44
                        }
45
                       /* Daten aus Struct einsortieren usw */
46
                       Manage_RF_Data(index);
47
                       f_GotData = true;
48
                    }
49
                }
50
51
                /* ----- Sind es Daten für das E2PROM ? --------- */
52
                // ......
53
            }
54
55
            /* Fifo löschen, egal was noch drin war */
56
              RF_FlushRX();
57
              RF_ClearStatus();
58
              RF_CE_Enable(ENABLE);
59
60
              SetRedLED(DISABLE);
61
       }
62
63
    EXTI_ClearITPendingBit(IRQ_LINE);   // Remove LINE interrupt flag bit
64
    }
65
}

von Christian J. (Gast)


Lesenswert?

Und hier der Init des Handlers für externe Pin Interrupst an GPIO A2.
DMA des AD Wandlers spielt auch noch munter weiter.
1
void RF_Init_Handler()
2
{
3
4
    /* PC1 Interrupt Pin konfigurieren auf Line 0 EXTI0_IRQn für Funbkmodul
5
6
        Line 0-4 haben einen eigenen Handler, 5-9 haben den Gleichen
7
        und 10-15 ebenfalls. Alle Px0 sind auf Line 0 angebunden usw.
8
9
        EXTI0_IRQn  EXTI0_IRQHandler  Handler for pins connected to line 0
10
        EXTI1_IRQn  EXTI1_IRQHandler  Handler for pins connected to line 1
11
        EXTI2_IRQn  EXTI2_IRQHandler  Handler for pins connected to line 2
12
        EXTI3_IRQn  EXTI3_IRQHandler  Handler for pins connected to line 3
13
        EXTI4_IRQn  EXTI4_IRQHandler  Handler for pins connected to line 4
14
        EXTI9_5_IRQn  EXTI9_5_IRQHandler  Handler for pins connected to line 5 to 9
15
        EXTI15_10_IRQn  EXTI15_10_IRQHandler  Handler for pins connected to line 10 to 15
16
17
    */
18
19
    GPIO_InitTypeDef GPIO_InitStruct;
20
    EXTI_InitTypeDef EXTI_InitStruct;
21
    NVIC_InitTypeDef NVIC_InitStruct;
22
23
    if (!spi_initialized)
24
       RF_Init_SPI();
25
26
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
27
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
28
29
    /* PA2 als Input */
30
    GPIO_StructInit (&GPIO_InitStruct);
31
    GPIO_InitStruct.GPIO_Pin    = IRQ_PIN;
32
    GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_IN_FLOATING;
33
    GPIO_InitStruct.GPIO_Speed  = GPIO_Speed_50MHz;
34
    GPIO_Init(IRQ_PORT, &GPIO_InitStruct);
35
36
    // Line einem Port und Pin zuordnen, hier Port A, Pin 2 = PA2
37
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource2);
38
39
    /* Line 2 der External IRQs 2 konfigurieren */
40
    EXTI_InitStruct.EXTI_Line    = IRQ_LINE;                        /* PA2 ist verbunden mit EXTI_Line2 */
41
    EXTI_InitStruct.EXTI_LineCmd = ENABLE;                          /* Enable interrupt */
42
    EXTI_InitStruct.EXTI_Mode    = EXTI_Mode_Interrupt;             /* Interrupt mode */
43
    EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;            /* Trigger auf fallende Flanke */
44
    EXTI_Init(&EXTI_InitStruct);                                    /* Aktivieren und zu EXTI hinzufügen */
45
46
    /* NVIC einbinden: PA2 ist auf EXTI_Line1 und hat den Vector EXT2_IRQn */
47
    NVIC_InitStruct.NVIC_IRQChannel = IRQ_HDL;
48
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;          /* Höchste Priorität */
49
    NVIC_InitStruct.NVIC_IRQChannelSubPriority        = 0;          /* Sub Priorität */
50
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;                    /* Enable Interrupt */
51
    NVIC_Init(&NVIC_InitStruct);                                    /* Zum NVIC hinzufügen */
52
53
    NVIC_EnableIRQ(IRQ_HDL);                                     /* Interrupt ein */
54
55
}

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Globale Linker Settings

von (º°)·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.· (Gast)


Lesenswert?

Setz halt einen Brechpunkt in den Hardfaulthandler...

Dann kannst du dich mit den Moeglichkeiten beschaeftigen,
aus dem dort vorgefundenen Zustand auf den Fehler zu
schliessen.

von Christian J. (Gast)


Lesenswert?

(º°)·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.· schrieb im Beitrag 
#5105152:
> Dann kannst du dich mit den Moeglichkeiten beschaeftigen,
> aus dem dort vorgefundenen Zustand auf den Fehler zu
> schliessen.

Das lasse ich dann doch lieber sein, da ich mir dabei schon mal einen 
abgebrochen habe. Bisher hat eine Umschreibung mancher Probleme auf eine 
andere Art geholfen. Oder halt nested Interrupts verbieten, das 
eleminiert auch schon viele Fehler.

Wenn ich das unten auskommentiere ist das problem weg. Also ist da was 
strubbelig und sobald ich einen kaffee fertig habe geht die Nachtschicht 
weiter. Habe ja Urlaub und das Wetter ist mies :-)

1
                   // Neue Daten in Historie kopieren
2
                    uint8_t index = actual_data.nrDataSet;
3
                    if (index <= HISTORY_MAX_IDX)
4
                    {
5
                       /* Zeit gelegentlich neu setzen */
6
//                        if (++tcnt >= 60) {
7
//                            Set_NewTime(actual_data.unix);
8
//                            tcnt = 0;
9
//                        }
10
                       /* Daten aus Struct einsortieren usw */
11
//                       Manage_RF_Data(index);

PS:

Da liegt der Wurm drin... aber bisher lief die beanstandungsfrei
1
/* Zeit neu einstellen, läuft allein weiter per RTC ISR */
2
void Set_NewTime(uint32_t newtime)
3
{
4
   /* Unix Zeit für localtime casten */
5
   time_t value = (time_t)newtime;
6
7
   /* Interne RTC auf Masterstation sychronisieren */
8
   RTC_SetCounter(value);
9
10
   /* Unixzeit umwandeln */
11
   struct tm *ptr = localtime(&value);
12
13
   /* Zeit atomar in eigenen Struct holen */
14
   NVIC_DisableIRQ(RTC_IRQn);
15
   memcpy((void*)&mytime,ptr,sizeof(struct tm));  // mytime <- localtime Buffer
16
   NVIC_EnableIRQ(RTC_IRQn);
17
}

von (º°)·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.· (Gast)


Lesenswert?

Einen Brechpunkt im Hardfaulthandler zu setzen ist nun keine
Raketenwissenschaft.

Von TI gibt es eine recht informative Appnote wie Mann mit
den Informationen im Hardfault umgeht:

http://www.ti.com/lit/pdf/SPMA043

Da das alles ARM Systemregister sind, gilt das was dort steht
ohne Einschraenkungen auch fuer den M3 von ST (von der
Driverlib im ROM mal abgesehen...).

Aus der Appnote:
"The Stellaris Cortex-M processor provides a powerful fault
handling system and several features to help you find the
cause of a fault. After debugging a few faults, you will be
more comfortable handling and troubleshooting faults as they
happen, and will be able to find the cause in a few minutes."

Denk mal drueber nach!

von Christian J. (Gast)


Lesenswert?

(º°)·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.· schrieb im Beitrag 
#5105189:
> Einen Brechpunkt im Hardfaulthandler zu setzen ist nun keine
> Raketenwissenschaft.

Ich werde es mir mal anschauen, damals habe ich aber nur Bahnhof 
verstanden vor gut 1 Jahr. Dazu braucht man ja erstmal einen Einstieg 
und anschliessend "den Blick für das Wesentliche" um die Urache zu 
finden. Einen hardFault Handler schreiben ist easy, der Roohbau ist ja 
schon fertig.

PS: Habs! Auch ohne den Hardfault:

Diese Set_NewTime Routine rief localtime auf. Allerdings hatte ich in 
dieser die RTC Ints nicht abgeschaltet, so dass immer mal einer 
dazwischen haute. Die Routine ist nicht reentrant. Dachte der Compiler 
merkt das. Jetzt sind die aus und erstmal läuft es :-)

von Nop (Gast)


Lesenswert?

Zum Hardfault Handler, da setzt man einen Breakpoint, greift sich den SP 
und guckt nach, was an der Adresse SP+24 steht. Das ist nämlich die 
Adresse, an der die Exception ausgelöst wurde.

Dann greift man sich das Mapfile und guckt, in welcher Funktion das ist. 
Oder man ist bequem und lädt die Firmware per Debugger und klickt sich 
dann zu der Adresse vor, dann sieht man auch gleich die Quelltextzeile.

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.