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
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?
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."
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
> Kann man prüfen ob die Semaphore voll ist?
uxSemaphoreGetCount()
:
Bearbeitet durch User
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.
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
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
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!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.