Forum: Mikrocontroller und Digitale Elektronik RTOS Ethernet


von Bernd S. (mms)


Lesenswert?

Hallo,

hab mich grad mal mit freeRTOS eingearbeitet. Momentan scheint es so, 
dass dieses OS einen relativ großen Overhead besitzt, so dass bei einem 
AT91SAM9263 die Ethernet Packete nicht mehr in der passenden Zeit 
abgearbeitet werden können.

Bei einer Datenrate von 6MBit/s läuft alles gut, aber bei einer 
Datenrate von 20MBit/s bekomm ich Buffer-Not-Available Interrupts. Diese 
Fehlermeldungen treten bereits nach sehr kurzer Zeit auf (< 1s). Der 
Task wird genau wie in den Beispielanwendungen über eine Semaphore 
informiert, dass ein neues Pkt angekommen ist. Beim Aufruf 
(xSemaphoreGiveFromISR) in der ISR hab ich auch sehr viele Anfragen, die 
angeben, dass die Queue bereits voll ist. Auch varriert die Anzahl der 
Aufrufe der ISR von den Aufrufen des eigentlichen Tasks (hier sind es 
nämlich einige weniger, was auch die BNA-Fehler erklärt).

Die ankommenden Pakete werden zur Zeit nur gesucht und anschlíeßend 
sofort wieder gelöscht, so dass die DMA wieder Zugriff darauf hat. Es 
finden also keine TCP/IP Stack Operationen statt. Ohne RTOS läuft dieser 
Code einwandfrei.

Als ganz minimalistisches Beispiel hab ich einfach mal im Ethernet-Task 
bei jedem ankommenden Pkt alle zur Verfügung stehenden Buffer 
gelöscht... dann bekomm ich zwar keine Buffer-Not-Available 
Fehlermeldungen, aber die  Queue (xSemaphoreGiveFromISR) wird trotzdem 
ab und zu als voll angezeigt.

Hat hier jmd schon andere (bessere) Erfahrungen sammeln können mit 
freeRTOS? Gibt es andere RTOS die schneller sind?

Gruß
Bernd

von PimpIt (Gast)


Lesenswert?

Der Kern wird schon laufen, ich denke ungesehen der Treiber ist zu lahm 
und eigentlich auch nicht Teil des Kerns. Ich würde mal sagen: Treiber 
optimieren ;-)

von Bernd S. (mms)


Lesenswert?

mit Treiber meinst du wahrscheinlich meinen hinzugefügten Code: Hier ist 
die komplette Task


low_level_input() function:
1
if( xRxSemaphore == NULL )
2
   vSemaphoreCreateBinary( xRxSemaphore );
3
4
/* Access to the emac is guarded using a semaphore. */
5
if( xSemaphoreTake( xRxSemaphore, netifGUARD_BLOCK_TIME ) )
6
{
7
    j = StartSearch; 
8
    /* find start SOF */
9
    while(((Emac_RxBufDesc[j].status & EMAC_RXBUF_SOF_MASK) == 0) || 
10
  ((Emac_RxBufDesc[j].address & EMAC_RXBUF_SW_OWNED) == 0))
11
    {
12
  j++; 
13
  if(j >= EMAC_RX_N_BUFS)
14
  j=0; 
15
    }
16
17
    Startbuf = j; 
18
    /* find EOF */
19
    while(((Emac_RxBufDesc[j].status & EMAC_RXBUF_EOF_MASK) == 0) || 
20
  ((Emac_RxBufDesc[j].address & EMAC_RXBUF_SW_OWNED) == 0))
21
    {      
22
  j++; 
23
  if(j >= EMAC_RX_N_BUFS)
24
  j=0; 
25
26
    }
27
28
     Endbuf = j; 
29
     StartSearch = Endbuf + 1; 
30
     if(StartSearch >= EMAC_RX_N_BUFS)
31
         StartSearch = 0; 
32
    
33
     /* delete all used buffers */
34
     j = Startbuf; 
35
     for(i=0; i<12; i++)
36
     {
37
        Emac_RxBufDesc[j].address &= ~EMAC_RXBUF_SW_OWNED;
38
        if(j == Endbuf)
39
          break;
40
   
41
       j++;
42
       if(j >= EMAC_RX_N_BUFS)
43
       j=0; 
44
     }
45
46
     xSemaphoreGive( xRxSemaphore );
47
48
     return(pbuf); /* da nicht definiert == NULL */
49
}

Diese Funktion wird wie in den mitgelieferten Beispieln aufgerufen:
1
for( ;; )
2
{
3
   do
4
   {
5
    /* move received packet into a new pbuf */
6
   pbuf = low_level_input( );
7
8
   if( pbuf == NULL )
9
   {
10
     /* No packet could be read.  Wait a for an interrupt to tell us 
11
     there is more data available. */
12
     vEmac_WaitForInput();
13
    }
14
15
    } while( pbuf == NULL );
16
}

Gruß
Bernd

von PimpIt (Gast)


Lesenswert?

Aha,

kannst du mal dein xSemaphoreGive( xRxSemaphore ); entfernen ? Das wäre 
dann schon der erste Fehler.

Wer blockt denn in der Task den Emac_RxBufDesc vor dem Interrupt ? Ich 
kenn den Aufbau jetzt nicht, sieht aber nach einem Ringbuffer aus der 
vom Interrupt/DMA geschrieben und von der Task gelesen werden soll !?

von Bernd S. (mms)


Lesenswert?

in der Task wird hier auf das Semaphore gewartet:
1
void vEmac_WaitForInput( void )
2
{
3
/* Just wait until we are signled from an ISR that data is available, or
4
   we simply time out. */
5
   xSemaphoreTake( xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT );
6
}

In der ISR dazu wird, falls ein Pkt received worden ist, dem Task 
signalisiert, dass es was zum arbeiten gibt
1
xSwitchRequired = xSemaphoreGiveFromISR( xSemaphore, pdFALSE );

>kannst du mal dein xSemaphoreGive( xRxSemaphore ); entfernen ? Das wäre
>dann schon der erste Fehler.
ich dachte für den Zugriff auf den Emac holt man sich zuerst eine 
Semaphore und am Schluss gibt man diese wieder zurück, damit diese 
Ressource wieder vorhanden ist.

In der Init für den Emac gibt man der DMA den ersten Buffer bekannt.
1
typedef struct
2
{
3
  unsigned int address;    // receive buffer address
4
  unsigned int status;    // status
5
} EMAC_RXBUF_HDR;
Der letzte Buffer im "Buffer-Array" besitzt ein ein Flag, welches 
angibt, dass jetzt weider im ersten Buffer gespeichert werden muss, 
falls dieser frei ist für die DMA.

Gruß
Bernd

von PimpIt (Gast)


Lesenswert?

Du lässt dir über xSemaphore vom Interrupt den Empfang signalisieren ? 
Rufst du nach

xSwitchRequired = xSemaphoreGiveFromISR( xSemaphore, pdFALSE );

Auch diese yieldWasWeissIch Funktion auf ?

> ich dachte für den Zugriff auf den Emac holt man sich zuerst eine
> Semaphore und am Schluss gibt man diese wieder zurück, damit diese
> Ressource wieder vorhanden ist.

Wo wird denn xRxSemaphore abgefragt/geblockt ? Die DMA sollte ja einfach 
in den Speicher blasen ohne auf sowas zu achten !? Dann hättest du 
Probleme mit Overflows und wenn du die DMA blockst dann mit Underflows, 
wenn die Task zu lahm ist.

von Bernd S. (mms)


Lesenswert?

>Auch diese yieldWasWeissIch Funktion auf ?
das müsste diese sein, die ganz zum schluss von der isr aufgerufen wird.
1
if( xSwitchRequired )
2
{
3
   portYIELD_FROM_ISR();
4
}

>Wo wird denn xRxSemaphore abgefragt/geblockt
hab mir gad nochmal ein anderes beispiel angeschaut, und die haben diese 
xRxSemaphoren-Geschichte auch nicht dabei; hab es jetzt komplett 
weggelassen, leider aber noch ohne Erfolg.

von PimpIt (Gast)


Lesenswert?

Vergrößer einfach mal das EMAC_RX_N_BUFS !?

von Bernd S. (mms)


Lesenswert?

momentan ist EMAC_RX_N_BUFS = 150 -> jeder dieser Buffer beinhaltet 
128Byte (entspricht einem DMA-Transport).

Nachdem der Fehler sehr schnell kommt (weniger als 1sec), wird eine 
Vergrößerung nichts bringen; zumal ohne RTOS es ja einwandfrei läuft.

Gruß
Bernd

von Bernd S. (mms)


Lesenswert?

ich glaub nicht, dass es an meinem Code liegt, sondern eher, dass bei 
der Portierung von einem SAM7 (beispieldateien von freeRTOS) auf einen 
SAM9 irgendetwas innerhalb des Kernels verändert werden muss.

Beim Durchsuchen der portable.h und portmacro.h sind mir aber keine 
großartigen Eingriffe die verschieden wären, aufgefallen.

Der Instruction-Cache ist auch enabled und funktioniert (hab es ohne 
diesem probiert, und der Prozessor arbeitet um einiges langsamer...).

Gruß
Bernd

von tuppes (Gast)


Lesenswert?

> ich dachte für den Zugriff auf den Emac holt man sich
> zuerst eine Semaphore und am Schluss gibt man diese
> wieder zurück, damit diese Ressource wieder vorhanden ist.

Das ist eine Möglichkeit, ein Semaphor zu verwenden.

Eine andere ist, einer Task ein Signal zu geben, dass es eine Aufgabe zu 
erledigen gibt. Wird gerne eingesetzt, wenn der Signalgeber eine 
Interrupt-Serviceroutine ist, die schnell das Allernötigste erledigt und 
die längere Auswertung einer Task überlässt.

Das "Verriegeln" des Emac gegen konkurrierende Zugriffe kann trotzdem 
erforderlich sein. Es kann dann aber nicht mit demselben Semaphor 
erledigt werden.

Näheres über Semaphore hier: 
http://de.wikipedia.org/wiki/Semaphor_(Informatik)

Übrigens heißt es "der" oder "das Semaphor".

> ich glaub nicht, dass es an meinem Code liegt, sondern eher,
> dass bei der Portierung von einem SAM7 (beispieldateien von
> freeRTOS) auf einen SAM9 irgendetwas innerhalb des Kernels
> verändert werden muss.

Dann bau doch erst mal ein einfacheres FreeRTOS-Beispiel, das dir zeigt, 
ob der Kernel prinzipiell läuft. Damit kannst du dann auch die 
Semaphor-Mechanismen studieren.

von Bernd S. (mms)


Lesenswert?

>Eine andere ist, einer Task ein Signal zu geben, dass es eine Aufgabe zu
>erledigen gibt. Wird gerne eingesetzt, wenn der Signalgeber eine
>Interrupt-Serviceroutine ist, die schnell das Allernötigste erledigt und
>die längere Auswertung einer Task überlässt.

unter welchem Begriff / Namen fällt diese Art einem Task zu 
signalisieren, dass es eine Aufgabe gibt?


>Dann bau doch erst mal ein einfacheres FreeRTOS-Beispiel, das dir zeigt,
>ob der Kernel prinzipiell läuft. Damit kannst du dann auch die
>Semaphor-Mechanismen studieren.

Das RTOS funktioniert ja prinzipiell - auch die Übergabe mit der 
Semaphore - allerdings ist beides zu langsam... Hab auch gelesen, dass 
man das Semaphor bei einer ISR nicht mehr zurückgeben muss...

Gruß
Bernd

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.