Forum: Mikrocontroller und Digitale Elektronik FreeRTOS Mutex aus ISR zurückgeben?


von Holger K. (holgerkraehe)


Lesenswert?

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

von holger (Gast)


Lesenswert?


von Holger K. (holgerkraehe)


Lesenswert?

holger schrieb:
> http://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html

Danke, das ist jedoch der umgekehrte weg.

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?

von Carl D. (jcw2)


Lesenswert?

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."

von Christian K. (the_kirsch)


Lesenswert?

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

von Carl D. (jcw2)


Lesenswert?

> Kann man prüfen ob die Semaphore voll ist?

uxSemaphoreGetCount()

: Bearbeitet durch User
von Christian K. (the_kirsch)


Lesenswert?

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.

von Holger K. (holgerkraehe)


Lesenswert?

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

von Holger K. (holgerkraehe)


Lesenswert?

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);

: Bearbeitet durch User
von Holger K. (holgerkraehe)


Lesenswert?

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!

von Christian K. (the_kirsch)


Lesenswert?

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.

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.