Forum: Mikrocontroller und Digitale Elektronik FreeRTOS + lwIP UDP senden


von Godi S. (godi22)


Lesenswert?

Hallo,

ich habe einen AVR32 (Alvidi AVR32-Board mit einem 32UC3A0512) auf dem 
ich FreeRTOS + lwIP zum laufen gebracht habe.
DHCP und Ping funktioniert.

Jetzt will ich in einem Task der alle sekunde aufgerufen wird ein UDP 
Paket versenden.

1)
Wenn ich jetzt die Funktion udp_new() im Initialisierungsteil des Taskes 
(wie hier: http://www.ultimaserial.com/avr_lwip_udp.html) aufrufe dann 
wirft der µC eine exception (_handle_Instruction_Address).
Wenn jedoch die Funktion udp_new() in der main Funktion bevor der 
dementsprechende Task erzeugt und gestartet wird aufgerufen wird, dann 
funktioniert das Senden des UDP Packetes.

Weiß jemand warum er die Exception wirft?

2)
Nun möchte ich einen zweiten Task hinzufügen der keine delay Zeit hat.
Dieser hat eine Priorität um 1 höher als der idle Task und eine 
geringere Priorität als der sekunden Task.
Die zwei Tasks laufen auch nebeneinander, aber die Funktion udp_sendto() 
liefert den Wert -4 (Error: ERR_RTE Routing problem) zurück.
Wenn in den zweiten Task jetzt eine delay Time von 1ms eingefügt wird 
dann funtkioniert das versenden des UDP Paketes wieder.

Warum kommt es in diesem Fall zu einem Routing Problem?


Hier noch die beiden Tasks + Main:
1
#define mainRUN_TASK_PRIORITY     ( tskIDLE_PRIORITY + 2 )
2
#define mainMAIN_TASK_PRIORITY    ( tskIDLE_PRIORITY + 1 )
3
4
struct udp_pcb *udp_pcb_run;   
5
char msg[]="RUN";
6
struct pbuf *p;
7
8
static void vRunTask( void *pvParameters );
9
void vRunTask( void * pvParameters ) {    
10
11
  // Initialize the xLastWakeTime variable with the current time.
12
  portTickType xLastWakeTime = xTaskGetTickCount();
13
    
14
  err_t err;
15
  
16
  for( ;; ) {
17
    // Wait for the next cycle.
18
    vTaskDelayUntil( &xLastWakeTime, configTICK_RATE_HZ );    
19
      
20
    //Allocate packet buffer    
21
    p = pbuf_alloc(PBUF_TRANSPORT,sizeof(msg),PBUF_RAM);
22
    memcpy (p->payload, msg, sizeof(msg));    
23
    err = udp_sendto(udp_pcb_run, p, IP_ADDR_BROADCAST, 60000);    
24
    pbuf_free(p); //De-allocate packet buffer  
25
    
26
    
27
    if (err != ERR_OK)
28
      LED_On(LED1_GPIO);    
29
    else
30
      LED_Off(LED1_GPIO);
31
    
32
    LED_Toggle(LED0_GPIO);
33
    
34
  }
35
}
36
37
void vStartRunTask(void) {
38
  /* Spawn the task. */
39
  xTaskCreate( vRunTask, ( signed char * ) "RunTask", configMINIMAL_STACK_SIZE, NULL, mainRUN_TASK_PRIORITY, ( xTaskHandle * ) NULL );
40
}
41
42
43
44
static void vMainTask( void *pvParameters );
45
void vMainTask( void * pvParameters ) {    
46
  
47
  for( ;; ) {        
48
    LED_Toggle(LED2_GPIO);
49
    // test loop
50
    for (uint32_t i = 0; i<10000000; i++) {
51
       asm volatile ("nop");
52
    }
53
    LED_Toggle(LED3_GPIO);    
54
  }
55
}
56
57
void vStartMainTask(void) {
58
  /* Spawn the task. */
59
  xTaskCreate( vMainTask, ( signed char * ) "MainTask", configMINIMAL_STACK_SIZE, NULL, mainMAIN_TASK_PRIORITY, ( xTaskHandle * ) NULL );
60
}
61
62
int main( void )
63
{
64
  // Configure system clocks.
65
  sysclk_init();
66
  
67
  // Start the ethernet tasks
68
  vStartEthernetTaskLauncher( configMAX_PRIORITIES );
69
  
70
  // Start the tasks
71
  udp_pcb_run = udp_new();
72
  vStartRunTask();
73
  //vStartMainTask();
74
75
76
  // Start FreeRTOS.
77
  vTaskStartScheduler();
78
79
80
  /* Will only reach here if there was insufficient memory to create the idle task. */
81
  return 0;
82
}

godi

von Godi S. (godi22)


Lesenswert?

Hat keiner eine Idee?

von Alex E. (tecnologic) Benutzerseite


Lesenswert?

Moin,

Das klingt nach einem Stackoverflow. Hast du bei FreeRTOS die Callback 
für einen TaskStack overflow eingeschaltet und implementiert?

die minimal Stack size ist nicht viel.

MfG

Tec

von Godi S. (godi22)


Lesenswert?

Danke,

habe mir eh schon gedacht, dass es mit dem Speicher zu tun hat.

Stackoverflow habe ich nicht aktiviert/implementiert.
Ich werde es mit der Anleitung von FreeRTOS 
(http://www.freertos.org/Stacks-and-stack-overflow-checking.html) 
umsetzen wenn ich Zeit finde und mich dann wieder melden.

godi

von Godi S. (godi22)


Lesenswert?

Hallo!

Ich versuche gerade den StackOverflow Hook zu implementieren.

Dazu habe ich configCHECK_FOR_STACK_OVERFLOW auf 2 gesetzt (testweise 
auch auf 1)

In meiner main.c habe ich die Funktion vApplicationStackOverflowHook 
implementiert.
1
void vApplicationStackOverflowHook( xTaskHandle xTask, signed char *pcTaskName ) {    
2
    LED_On(LED2_GPIO);  
3
}

Leider wird die Hook-Funktion nie aufgerufen.

Ich habe es auch schon mit der IDLE-HOOK Funktion probiert. (Könnte ja 
sein dass ich gar keinen Stack Overflow habe ;) )
configUSE_IDLE_HOOK   auf 1 gesetzt und in der main.c die Funktion
1
void vApplicationIdleHook() {  
2
  LED_On(LED3_GPIO);    
3
}
implementiert.
Funktioniert leider auch nicht.

Muss ich noch irgendwelche Parameter einstellen?

godi

von Alex E. (tecnologic) Benutzerseite


Lesenswert?

Moin,

Wenn selbst der Idle-Hook nicht kommt. Dann ist der Ausgang für die LED 
nicht konfiguriert. Oder deine Tasks brauchen 100% CPUZeit. Hast du in 
jeder Task einen Block drin? oder läuft eine oder sogar mehrere in ner 
While Schleife ohne das das Task mal die CPU abgibt?

Poste mal den Code hier, oder n reduziertes Beispiel.

MfG

Tec

von Godi S. (godi22)


Lesenswert?

Der Code ist wie im ersten Post nur jetzt noch zusätzlich mit den Hook 
Funktionen in der main.c

Ich habe gerade herausgefunden wenn ich den vStartMainTask nicht aufrufe 
dann funktioniert auch die Idle Hook Funktion.

In dem vStartMainTask simuliere ich eine 100% CPU Auslastung aber der 
Task hat die geringste Priorität.
Aber der Task wird ja von höher Priorisierten Tasks unterbrochen, also 
wird dieser ja sowieso vom Scheduler ausgelagert und wenn gerade was 
frei ist wieder eingelagert. (preemtives OS) Oder verstehe ich da etwas 
falsch?

von Alex E. (tecnologic) Benutzerseite


Lesenswert?

In deiner Run Task ist auch kein einziger block drin. Da es keine höher 
oder gleich priore task gibt läuft die durch. Mach mal n vTaskDelay(10) 
oder so da rein.

von Godi S. (godi22)


Lesenswert?

Tec Nologic schrieb:
> Mach mal n vTaskDelay(10)
> oder so da rein.

godi S. schrieb:
> Wenn in den zweiten Task jetzt eine delay Time von 1ms eingefügt wird
> dann funtkioniert das versenden des UDP Paketes wieder.

Wie schon erwähnt funktioniert es mit einem Delay in dem .

Tec Nologic schrieb:
> In deiner Run Task ist auch kein einziger block drin. Da es keine höher
> oder gleich priore task gibt läuft die durch.

Was meinst du mit Block?
Der RUN Task wird jede Sekunde 1x aufgerufen. Das funktioniert auch.

Der vMainTask soll permanent laufen, wenn nichts wichtigeres zu tun ist.
Deshalb hat der vMainTask die geringste Priorität damit er unterbrochen 
wird.
Also wird der von dem RUN Task unterbrochen, was auch funktioniert, nur 
das senden des UDP Paketes funktioniert nicht mehr und der IDLE Hook 
wird auch nicht aufgerufen.

Wird der vMainTask nicht bei jedem System Tick unterbrochen,dann 
eintscheidet der Scheduler ob der Task drinn bleiben kann und wenn ja 
dann wird dieser Task weiter abgearbeitet?

von Alex E. (tecnologic) Benutzerseite


Lesenswert?

mit block meine ich so funktionen wie delay, waitforsem usw.


Dein MainTask wird zwar vom Scheduler beim Tick unterbrochen, aber er 
ist immer Ready. Du musst die Schleife mit den nops durch n Delay 
ersetzen.

Grundsätzlich sollte jede Task irgend wann mal eine Funktion wie Delay 
usw. ausführen. Wenn du die die FreeRTOS Doku ansiehst wird das Task 
dann geblockt, und der SCheduler kann ein niedrig priores task 
ausführen. im zweifel dann das IdleTask.

Solche Delay Schleifen sind mit nem Scheduler im System sowieso 
überflüssig und sogar nachteilig wie du gerade merkst.

Du willst ja sachen parallel machen, dann muss jede Task der anderen 
Task auch rechen zeit zugestehen.

Als beispiel für deine UDP pakete wäre z.b eine Konstruktion sinnvoll, 
wie Packete im Interupt in einen Buffer schaufeln, und ne semaphore 
setzen. ein Workerthread wartet auf die semaphore, und verarbeitet die 
UDP packete.
wenn er fertig ist wartet er wieder auf das signal vom Interupt. (DMA 
Halftransfer oder solche späße geht da auch.)

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.