mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik STM32 Prioritäten


Autor: Philipp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich arbeite mit einem STM32 und FreeRTOS.

Ich habe die Tasks mit der PRIO configKERNEL_INTERRUPT_PRIORITY und die 
Interruptroutine mit PRIO configMAX_SYSCALL_INTERRUPT_PRIORITY laufen 
(ruft eine API Funktion).

Nach unbestimter Zeit (2 Sekunden - 3 Minuten) hängt das System - die 
Tasks werden nicht mehr ausgeführt, die Interrupt Routine schon.

Hat jemand Ahnung, wie die PRIOs eingestellt gehören? Ich habe alles 
durchgelesen und nach den Vorgaben eingestellt, aber ohne Erfolg.

Hier die Interrupt-Routine :

void USART1_IRQHandler(void)
{
    taskDISABLE_INTERRUPTS();

    portCHAR cChar;
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    
    extern xQueueHandle xQueue;

    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)   
    {   
       /* Read one byte from the receive data register */   
       cChar = USART_ReceiveData(USART1);            
       xQueueSendFromISR( xQueue, &cChar, &xHigherPriorityTaskWoken );
    }   

    /* Clear the USART1 Receive interrupt */   
    USART_ClearITPendingBit(USART1, USART_IT_RXNE);   
    USART_ClearFlag(USART1, USART_IT_RXNE); 

    if (USART_GetFlagStatus(USART1, USART_FLAG_TXE) != RESET)
    {
        // not implemented

    }

    // Clear the USART1 Receive interrupt 
    USART_ClearITPendingBit(USART1, USART_IT_TC); 
    USART_ClearFlag(USART1, USART_IT_TXE);
    USART_ClearFlag(USART1, USART_IT_PE);    

    taskENABLE_INTERRUPTS();
    portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}


Und einen Task :

xTaskCreate( vTaskA, "TASKA", 256, NULL, configKERNEL_INTERRUPT_PRIORITY, NULL );

---

void vTaskA( void *pvParameters )
{
    portCHAR sMessage[128];
    portCHAR cReceivedChar;
    uint8_t byRecBufferIndex = 0;

    for( ;; )
    {
        if (xQueueReceive( xQueue, &(cReceivedChar), (portTickType)100))
        {
            if (byRecBufferIndex >= 128) byRecBufferIndex = 0;
                        
            sMessage[byRecBufferIndex++] = cReceivedChar;

            if (cReceivedChar == 10)
            {
                if (strncmp(sMessage, "$GPGGA", 6) == 0)
                {
                    // received right GPS Message
                    GPIO_WriteBit(GPIOC, GPIO_Pin_12, Bit_RESET);
                    vTaskDelay( 100 / portTICK_RATE_MS );
                    GPIO_WriteBit(GPIOC, GPIO_Pin_12, Bit_SET);
                }
                byRecBufferIndex = 0;
            }
        }
    }
}


Hilferufend,
Philipp

Autor: Clemens Gerlach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh, ich glaube Du verwechselst da was. Die Interrupt-Prioritäten haben 
nichts mit den Task-Prioritäten zu tun.

Interrupt-Prioritäten (FreeRTOS auf Cortex-M3):
Du willst:

Eigentlich immer:
#define configKERNEL_INTERRUPT_PRIORITY  255
Setzt die Task-Wechsel-Routine auf niedrigste Priorität. Nur daran 
rumspielen, wenn Du genau weißt, wie der Taskwechsel von FreeRTOS auf 
dem CM3 funktioniert.

Bei dem hier hast Du Spielraum:
#define configMAX_SYSCALL_INTERRUPT_PRIORITY    (8<<4) //only 4 bits 
implem. in STM32

Wenn Du jetzt eine Interruptroutine hast, die FreeRTOS-Syscalls macht 
(wie Deine Empfangsroutine) dann muss sie eine niedrigere oder gleiche 
Priorität als configMAX_SYSCALL_INTERRUPT_PRIORITY haben (Cortex-M3: 
niegerigere Priorität -> größerer Wert).

Und zwar im NVIC. Also z.b. so:

NVIC_SetPriority(USART1_IRQn, 9);

Dabei ist zu beachten: Im STM32 sind nur 4 Bits an Prioritäten 
implementiert. Mit NVIC_SetPriority() setzt Du nur die wichtigen oberen 
4 Bits. configMAX_SYSCALL_INTERRUPT_PRIORITY bezieht sich aber auf das 
ganze Byte. Darum wie in obigem Beispiel das shift-left um 4.


FreeRTOS 5.3.0 hatte noch ein bisschen Schluckauf mit der 
ST-Firmware-Lib 3.0 bei den high-density devices. Da gabs großes 
Stack-Durcheinander. Ob das mittlerweile besser/korrigiert ist, weiß ich 
nicht: http://sourceforge.net/forum/message.php?msg_id=7447039

Task-Prioritäten (z.b. bei xTaskCreate()):
Hier gehts nur drum welcher Task wann Prozessorzeit bekommt. Das ist 
immer ein Wert zwischen 0 (idle Task) und configMAX_PRIORITIES-1.

Gruß
Clemens

Autor: Philipp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich habe nun alles so gemacht, wie du es beschrieben hast. Ohne Erfolg. 
Nach ca. 30 Sekunden bleibt er für immer dort hängen :
/* *** NOTE ***********************************************************
    If you find your application is crashing here then likely causes are:
      1) Stack overflow - 
         see http://www.freertos.org/Stacks-and-stack-overflow-checking.html
      2) Incorrect interrupt priority assignment, especially on Cortex M3 
         parts where numerically high priority values denote low actual 
         interrupt priories, which can seem counter intuitive.  See 
         configMAX_SYSCALL_INTERRUPT_PRIORITY on http://www.freertos.org/a00110.html
      3) Calling an API function from within a critical section or when
         the scheduler is suspended.
      4) Using a queue or semaphore before it has been initialised or
         before the scheduler has been started (are interrupts firing
         before vTaskStartScheduler() has been called?).
    See http://www.freertos.org/FAQHelp.html for more tips. 
    **********************************************************************/


Wie komme ich drauf, was schuld ist. Ich habe schon alles ausprobiert. 
Was ich nicht verstehe ist, wenn der Kenel die niedrigste Priorität hat 
und die Tasks die gesamte Zeit brauchen, wie soll der Kernel dann alles 
managen? Sollte er nicht die höhste haben?

Philipp

Autor: Philipp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also kannst du mir sagen, ob daß stimmt :
// Configure the NVIC Preemption Priority Bits 
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 9;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init( &NVIC_InitStructure );


Philipp

Autor: Clemens Gerlach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für mich sieht das erstmal gut aus.

Zum Thema Prioritäten:
Deine Task-Prioritäten haben NIX mit den Interrupt-Prioritäten zu tun. 
Deine Tasks sind keine Interrupts! Die haben Ihre eigene Hierarchie.

Die Task-Wechsel-Routine vom FreeRTOS muss die kleinste 
INTERRUPT-Priorität haben, da es sonst Stackgewurschtel gibt. Dadurch 
werden die Tasks erst
umgeschalten wenn kein Interrupt mehr bearbeitet wird.

Ich würde mal vor allem das hier aus Deiner ISR rausnehmen:

taskDISABLE_INTERRUPTS();
taskENABLE_INTERRUPTS();

Ich weiß nicht ob das was macht, aber brauchen tust Du's nicht.

Sonst würde ich mal testen ob eine einfach blinkende LED läuft. oder ob 
tatsächlich die IRQ-routine schuld ist.
Tut das, dann die UART ISR mal einfach die Empfangsdaten aus dem 
Empfangsregister auslesen lassen und keine FreeRTOS-Syscalls machen 
lassen.

...und halt langsam an den Fehler rantasten.

Autor: Dirk B. (garag)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

nur mal so ein Gedanke:

In der IRQ Routine wird zwar TXE abgefragt aber nichts weiter gemacht. 
Muß das interrupt Enable nicht abgeschaltet werden für TXE ?

Ich habe auch den STM32 mit FreeRTOS am laufen. Jedoch spreche ich die 
Serielle Schnittstelle direkt an und nicht über die Library.

Bei mir sieht es wie folgt aus:
void USART1_IRQHandler(void) {
  uint16_t sr = USART1->SR;
  char ch;
  static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
  static portBASE_TYPE xTaskWokenByReceive  = pdFALSE;

  // Check for received Data
  if (sr & USART_SR_RXNE) {
    ch = (char) USART1->DR;
    xQueueSendToBackFromISR(hSerialRx, &ch, &xHigherPriorityTaskWoken);

      // Switch context if necessary.
      if( xHigherPriorityTaskWoken )
      {
          taskYIELD ();
      }
  }

  // Check if transmit buffer is empty
  if (sr & USART_SR_TXE) {
    // Send character if available
    if (pdTRUE == xQueueReceiveFromISR(hSerialTx, &ch, &xTaskWokenByReceive)) {
        USART1->DR = ch;
          // Switch context if necessary.
          if( xTaskWokenByReceive )
          {
              taskYIELD ();
          }
    } else {
      // disable TXE interrupt
      USART1->CR1 &= ~USART_CR1_TXEIE;
    }
  }
}

Gruß
Garag

Autor: Philipp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich habe deine IRQ Routine mal ausprobiert und es bleibt leider. Nach 
einigen Sekunden steht das System. Kannst du mir mal deine Prioritäten 
mitteilen. Der Stack - so wie es aussieht - kanns nicht sein.

Autor: Dirk B. (garag)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Moin moin,

ich habe mal mein kleines Projekt angehängt. Es handelt sich um zwei 
Eclipse Projekte. Das eine enthält freeRTOS, als Ergebnis wird eine 
Library erzeugt. Die Library wird vom zweiten Projekt verwendet und 
enthält neben Serieller Schnittstelle mit eigenem Task noch einen Task 
zum Blinken einer LED. Ausserdem wird noch die RTC initialisiert und ein 
Timer initialisiert, jedoch nicht wirklich benutzt.

Bei mir läuft das unter Windoof XP mit Eclipse (Ganymed), neuestem 
Yagarto und "GNU ARM Eclipse Plugin".

Ich hoffe das hilft dir weiter.

Gruß
Garag

Autor: Philipp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
so ich glaube, das Problem ist gelöst. Ich ergänze diesen Thread, falls 
jemand anderer auch das Problem hat.

Die Prioritäten für die Interrupt-Routinen (USART, ...) werden wie folgt 
definiert :
// Configure the NVIC Preemption Priority Bits 
// wichtig!, sonst stimmt nichts überein mit den neuen ST Libs (ab Version 3.1.0)
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);    
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

// entspricht 11-15, 11 ist das höchst mögliche, sonst gibt es Probleme mit dem OS
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = (configMAX_SYSCALL_INTERRUPT_PRIORITY >> 4) + 1;    
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init( &NVIC_InitStructure );

Die Interrupt-Routine dazu sieht dann wie folgt aus (als Beispiel, 
stammt von der Testapplikation - GPS Daten lesen) :

int iUSART2_IRQHandler_Index = 0;
portCHAR sUSART2_IRQHandler_Message[128];

void USART1_IRQHandler(void)
{
    portCHAR cChar;
    portBASE_TYPE xTaskWokenByReceive = pdFALSE;
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    bool bSend = 1;
    
    extern xQueueHandle xQueue;
    extern xQueueHandle xQueueOutput;

    if (iUSART1_IRQHandler_Index == 0)
    {
        // get next Message
        if (xQueueReceiveFromISR(xQueueOutput, &sUSART1_IRQHandler_Message, &xHigherPriorityTaskWoken) != pdPASS)
        {
            USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
            bSend = 0;
        }
    }

    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)   
    {   
       // Read one byte from the receive data register 
       cChar = USART_ReceiveData(USART1);            

       xQueueSendFromISR( xQueue, &cChar, &xTaskWokenByReceive );
    }   

    if (USART_GetITStatus(USART1, USART_IT_TXE) != RESET)   
    {
        if (bSend)
        {
            if (sUSART1_IRQHandler_Message[iUSART1_IRQHandler_Index] == 10 || iUSART1_IRQHandler_Index >= 128)
            {
                iUSART1_IRQHandler_Index = 0;
            }
            else
            {
                USART_SendData(USART1, sUSART1_IRQHandler_Message[iUSART1_IRQHandler_Index++]); 
            }
        }
    }
    
    portEND_SWITCHING_ISR( xTaskWokenByReceive );
    portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}


Philipp

Autor: Philipp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry :
int iUSART1_IRQHandler_Index = 0;
portCHAR sUSART1_IRQHandler_Message[128];

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.