FreeRTOS Mutex aus ISR zurückgeben?

OP #4527225
Hallo zusammen

Ich möchte mir die SPI Schnitstelle in meinem System teilen.
Ich verwende FreeRTOS nun zum ersten mal.

Damit die tasks nicht gleichzeitig auf die SPI Schnitstelle zugreifen, 
wollte ich einen Mutex verwenden.

TaskA nimmt den Mutex und startet den transfer
Dieser läuft mittels DMA im Hintergund.
TaskA soll also in den Blocked State und RTOS soll was anderes machen.

Wenn der DMA fertig ist, gibts einen interrupt. Nun soll der DMA 
Interrupt den Mutex zurückgeben.

Leider aber sagt die Dokud das ich xSemaphoreGiveFromISR() nicht für 
Mutex verwenden soll.

Wie soll ich mein Problem denn nun sonst lösen?
Und was ist das Problem am MutexGeben aus dem Interrupt?

Danke
#4527234
Die FreeRTOS-Doku sagt:
"Mutex type semaphores (those created using a call to 
xSemaphoreCreateMutex()) must not be used with this macro"
Und
"They (Mutexes) include a priority inheritance mechanism which only 
makes sense if the mutex is given and taken from a task, not an 
interrupt."
#4527235
Nimm zwei BinarySemaphore. Eine für jeden Task.
http://www.freertos.org/xSemaphoreCreateBinary.html


In der ISR jeden jeweiligen Task mit xSemaphoreGiveFromISR aufwecken.
ISR(){
static signed BaseType_t xHigherPriorityTaskWoken;
...
xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR( xSemaphore1, &xHigherPriorityTaskWoken );
...
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
http://www.freertos.org/a00124.html



"Mutexes and binary semaphores are very similar but have some subtle 
differences: Mutexes include a priority inheritance mechanism, binary 
semaphores do not. This makes binary semaphores the better choice for 
implementing synchronisation (between tasks or between tasks and an 
interrupt), and mutexes the better choice for implementing simple mutual 
exclusion."
http://www.freertos.org/CreateMutex.html
#4527239
Holger K. schrieb:
> Ich möchte ja nicht nach dem Interrupt einen Task ausführen.
> Oder soll ich im ausgeführten Task dann den Mutex zurückgeben?
>
> Kann man prüfen ob die Semaphore voll ist?

Normaler weiße geht der Task schlafen wenn er auf eine Ressource wartet,
wenn er in der Zwischenzeit was anderes machen soll kannst du mit
uxSemaphoreGetCount() den Semaphore abfragen, statt mit Take schlafen zu 
gehen.

http://www.freertos.org/uxSemaphoreGetCount.html


Ein BinarySemaphore nimmt nur die Werte 0 und 1 an, ist er schon auf 1 
und machst ein Give darauf bleibt er bei 1.
OP #4527258
Vielen Dank

Sollte funktionieren.

Nun habe ich jedoch ein Problem mit dem Interrupt.

Ich definiere den Interrupt wie folgt:
1
void NVIC_Config_DMA_OLED(void)
2
{
3
   NVIC_InitTypeDef NVIC_InitStricture;
4

5
   NVIC_InitStricture.NVIC_IRQChannel = DMA1_Channel5_IRQn;
6
   NVIC_InitStricture.NVIC_IRQChannelPreemptionPriority = 15;
7
   NVIC_InitStricture.NVIC_IRQChannelSubPriority = 8;
8
   NVIC_InitStricture.NVIC_IRQChannelCmd = ENABLE;
9
   NVIC_Init(&NVIC_InitStricture);
10
}

Doch ich lande immer hier:
1
configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );

Current Priority scheint immer 0 zu sein (die höchst mögliche)

Ich verwende den CM3 Port von FreeRTOS
OP #4527269
GUt, problem gefunden:

NVIC_SetPriority(DMA1_Channel5_IRQn,15);

Nun blockiert irgendwas irgendwas -.-

So sieht mein Code aus:
1
void taskOLEDUpdate(void *pvParameters)
2
{
3
  while(1)
4
  {
5
    //Warte auf den Befehl zum refresh
6
    xSemaphoreTake(xOLEDSyncSemaphore,portMAX_DELAY);
7

8
    //Warte auf die SPI freigabe!
9
    xSemaphoreTake(xSPISyncSemaphore,portMAX_DELAY);
10
    OLED_Refresh();
11
  }
12
}

Dies wird regelmässig ausgeführt:
1
xSemaphoreGive(xOLEDSyncSemaphore);

Dies wurde einmal ausgeführt.
Aber leider kommt er oben nicht mehr in "taskOLEDUpdate" hinein.
1
xSemaphoreGiveFromISR(xSPISyncSemaphore,&xHigherPrioTaskWoken);
OP #4527276
Der Trick liegt in der Kombination:
1
void NVIC_Config_DMA_OLED(void)
2
{
3
   NVIC_InitTypeDef NVIC_InitStricture;
4

5
   NVIC_InitStricture.NVIC_IRQChannel = DMA1_Channel5_IRQn;
6
   NVIC_InitStricture.NVIC_IRQChannelPreemptionPriority = 0x0F;
7
   NVIC_InitStricture.NVIC_IRQChannelSubPriority = 0x0F;
8
   NVIC_InitStricture.NVIC_IRQChannelCmd = ENABLE;
9
   NVIC_Init(&NVIC_InitStricture);
10

11
   NVIC_SetPriority(DMA1_Channel5_IRQn,15);
12
}

Der Interrupt wurde zuvor eben noch nicht angesprungen.

Jetzt funktioniert das ganze!
#4527289
Holger K. schrieb:
> Doch ich lande immer hier:
> configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
>
> Current Priority scheint immer 0 zu sein (die höchst mögliche)
>
> Ich verwende den CM3 Port von FreeRTOS

In der FreeRTOS-Config ist definiert das alle Interrupts mit Prio 4 und 
kleiner keine RTOS-API-Aufrufe machen dürfen.

Das sollte man auch so lassen.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 10 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.