Forum: Mikrocontroller und Digitale Elektronik lwIP 1.4.1 + freeRTOS 8.2.3 + stm32f107vb


von Alex B. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich versuche seit langem verzweifelt lwIP und freeRTOS zum Laufen zu 
bringen. Ich habe eine Anwendung auf vielen verschiedenen Beispielen 
zusammengebastelt, da ich für meine Vorraussetzungen kein passendes 
Beispielprojekt gefunden habe. Dau habe ich vor allem Beispiele aus 
CubeF4, also für den STM32F4xx, als Vorlage genommen.

Mein Programm startet den tcpip-Thread. Dieser schein normal zu laufen. 
Ich versuche dann eine IP-Adresse über DHCP zu beziehen. Der dhcp 
discovery request ist auf Serverseite zu sehen, also gehe ich davon aus, 
dass das Hardware-Setup korrekt ist. Die Probleme beginnen, wenn ich 
eingehende Pakete an den tcpip-Thread übergeben möchte. Die führt zu 
einem HardFault. Interessanterweise ist die Zeit bis zum Hardfault nicht 
deterministisch. Wenn ich einen Breakpoint im input-Task treffe und das 
Programm dann normal weiterlaufen lasse, dauert es länger, bis der 
Hardfault kommt. So habe ich es bereits ein mal geschafft eine 
IP-Adresse zu beziehen. Ohne den Breakpoint kommt es beinahe sofort zum 
Hardfault. Was mache ich falsch? Nachfolgend Details zu meinem Setup.

Software:

-FreeRTOSV8.2.3
-lwip-1.4.1
-STM32_ETH_Driver
-STM32F10x_StdPeriph_Lib_V3.5.0

Hardware:

- selbst gemachtes Evaluationboard mit stm32f107vb betrieben mit 25MHz
- Micrel KSZ8041TL PHY verbunden über RMII

Tasks:

-idle natürlich
-tcpip-Thread
-dhcp task, welcher dhcp_start(&netif) und stop aufruft.
-input_task, welcher über einen Semaphor von dem Ethernet-Interrupt 
geweckt wird und low_level_input() sowie netif->input() aufruft.

Ohne den input_task läuft das System stabil und versucht eine IP-Adresse 
zu erhalten. Das funktioniert natürlich nicht, da der tcpip-Thread die 
eingehenden Pakete ohne input-Task nicht sieht. Ich habe den Quellcode, 
der für dieses Problem wichtig ist mit angehängt. Unter Anderem bin ich 
unsicher, ob die sys_arch.c und sys_arch.h (Schnittstelle zw. RTOS und 
lwip) korrekt implementiert sind.

Unter dem Post ist zudem der Debug-Output das lwip-Stacks vor dem 
Absturz. Ich habe das ganze an UART geleitet. Es finden sich auch eigene 
Ausgaben darunter, wie die HighWaterMarks. Über Hilfe würde ich mich 
sehr freuen.


Danke für eure Unterstützung!
Alex

###########################################################
##         DEBUG OUTPUT
###########################################################

?<\n>
LINK UP<\n>
<\n>
<\n>
LINK UP<\n>
<\n>
sys_timeout: 0x200027dc msecs=1000 handler=ip_reass_timer arg=0x0<\n>
sys_timeout: 0x2000279c msecs=5000 handler=arp_timer arg=0x0<\n>
sys_timeout: 0x2000275c msecs=60000 handler=dhcp_timer_coarse 
arg=0x0<\n>
sys_timeout: 0x2000271c msecs=500 handler=dhcp_timer_fine arg=0x0<\n>
<\n>
<\n>
 HighWaterMark tcpip_thread: 1008 <\n>
<\n>
tcpip_thread: Netif API message 0x2000848c<\n>
netif: IP address of interface netif: netmask of interface netif: GW 
address of interface Eth_if created: success <\n>
<\n>
<\n>
<\n>
netif: added interface st IP addr 0.0.0.0 netmask 0.0.0.0 gw 0.0.0.0<\n>
netif: setting default interface st<\n>
<\n>
<\n>
 HighWaterMark tcpip_thread: 758 <\n>
<\n>
stmf calling h=dhcp_timer_fine arg=0x0<\n>
tcpip: dhcp_fine_tmr()<\n>
sys_timeout: 0x2000271c msecs=500 handler=dhcp_timer_fine arg=0x0<\n>
stmf calling h=ip_reass_timer arg=0x0<\n>
tcpip: ip_reass_tmr()<\n>
sys_timeout: 0x200027dc msecs=1000 handler=ip_reass_timer arg=0x0<\n>
stmf calling h=dhcp_timer_fine arg=0x0<\n>
tcpip: dhcp_fine_tmr()<\n>
sys_timeout: 0x2000271c msecs=500 handler=dhcp_timer_fine arg=0x0<\n>
stmf calling h=dhcp_timer_fine arg=0x0<\n>
tcpip: dhcp_fine_tmr()<\n>
sys_timeout: 0x2000271c msecs=500 handler=dhcp_timer_fine arg=0x0<\n>
<\n>
<\n>
 HighWaterMark ethernetif_input: 992 <\n>
<\n>
pbuf_alloc(length=74)<\n>
pbuf_alloc: allocated pbuf 0x200071e8<\n>
pbuf_alloc(length=74) == 0x200071e8<\n>
tcpip_thread: PACKET 0x2000269c<\n>
<\n>
<\n>
 HighWaterMark ethernetif_input: 867 <\n>
<\n>
pbuf_alloc(length=0)<\n>
pbuf_pbuf_alloc: allocated pbuf 0x20006bb0<\n>
pbuf_alloc(length=0) == 0x20006bb0<\n>

von Pete K. (pete77)


Lesenswert?

Wegen diesen Problemen nehme ich einen Raspi, wenn es was mit 
Ethernet-Anschluss sein soll.

Ich weiss, das hift Dir nicht weiter....

von hp-freund (Gast)


Lesenswert?

Hallo Alex,

auf Grund der Fehlerbeschreibung und ohne den Code zu wälzen kommt mir 
da die Heap und Stack Einstellung in den Sinn.
Du hast hoffentlich das .ld file nicht einfach vom F4 übernommen?

von Alex B. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo hp-freund,

ich habe das .ld ie nicht aus einem Beispielprojekt übernommen, sondern 
mit meiner IDE (Eclipse + OpenOCD + GNU ARM C/C++ Cross Compiler) selbst 
ein Projekt erstellt. mem.ld habe ich mal angehängt, das ist nicht das 
Problem.

FreeRTOS steht ein Heap von 15 kB zur Verfügung:

#define configTOTAL_HEAP_SIZE    ( ( size_t ) (15 * 1024 ) )

Der input_task erhält davon 4kB und der tcpip-Thread erhält ebenfalls 
4kB für den Stack. Das müsste meiner Meinung nach ausreichen.

von hp-freund (Gast)


Lesenswert?

Moin,

in deiner mem.ld steht nichts von heap und stack.
Sieh mal in die sections.ld was da definiert ist.

von Alex B. (Gast)


Angehängte Dateien:

Lesenswert?

Habe secions.ld mal angehangen. Dort finde ich die Angaben

__Main_Stack_Size = 1024 ;
_Minimum_Stack_Size = 256 ;

Jedoch kann ich damit nicht viel anfangen. Sind diese Werte 
problematisch?

von Anonymous (Gast)


Lesenswert?

Probier mal eine niedrigere Priorität für den ethernetif_input_task 
(ethernetif.c Zeile 191)
1
BaseType_t errCode = xTaskCreate(ethernetif_input_task,  "ethernetif_input", 1024, &xnetif, configMAX_PRIORITIES-3,NULL);

von hp-freund (Gast)


Lesenswert?

Alex B. schrieb:
> __Main_Stack_Size = 1024 ;

Ich würde den Wert einfach mal vergrössern und das Verhalten beobachten.

von Alex B. (Gast)


Lesenswert?

Ich habe soeben den Fehler gefunden. In ethernetif.c (Schnittstelle 
zwischen STM32_ETH_Driver und lwip) war die Funktion "low_level_input" 
das Problem. Dabei hab ich diese Schnittstelle von STM direkt übernommen 
und bin davon ausgegangen, dass diese fehlerfrei ist. Auf den Fehler bin 
ich gekommen, indem ich mir die Implementierung von ethernetif.c in 
einem Beispiel für den STM32fxx angeschaut habe.

Die Funktion sieht jetzt wie folgt aus:
1
 static struct pbuf *
2
low_level_input(struct netif *netif)
3
{
4
  struct pbuf *p, *q;
5
  u16_t len;
6
  int l =0;
7
  FrameTypeDef frame;
8
  u8 *buffer;
9
10
  p = NULL;
11
  frame = ETH_RxPkt_ChainMode();
12
  /* Obtain the size of the packet and put it into the "len"
13
     variable. */
14
  len = frame.length;
15
  buffer = (u8 *)frame.buffer;
16
17
  if(len > 0){
18
    /* We allocate a pbuf chain of pbufs from the pool. */
19
    p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
20
  }
21
22
  if (p != NULL)
23
  {
24
    for (q = p; q != NULL; q = q->next)
25
    {
26
      memcpy((u8_t*)q->payload, (u8_t*)&buffer[l], q->len);
27
      l = l + q->len;
28
    }
29
  }
30
31
  if(len > 0){
32
    /* Set Own bit of the Rx descriptor Status: gives the buffer back to ETHERNET DMA */
33
    frame.descriptor->Status = ETH_DMARxDesc_OWN;
34
  }
35
36
  /* When Rx Buffer unavailable flag is set: clear it and resume reception */
37
  if ((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET)
38
  {
39
    /* Clear RBUS ETHERNET DMA flag */
40
    ETH->DMASR = ETH_DMASR_RBUS;
41
    /* Resume DMA reception */
42
    ETH->DMARPDR = 0;
43
  }
44
  
45
  return p;
46
}

Hinzugekommen sind die beiden "if(len > 0)..." Anweisungen. Wenn man 
sich die Treiberfunktion "ETH_RxPkt_ChainMode()" genauer ansieht, steht 
dort, dass len=0 zurückgegeben wird, wenn der DMA-Deskriptor, den der 
Treiber nutzen will momentan nicht verfügbar ist, weil zB ein 
Kopiervorgang noch nicht abgeschlossen ist. Auch das Feld 
frame.descriptor ist dann NULL. In dem Fall knallt die anweisung
1
frame.descriptor->Status = ETH_DMARxDesc_OWN;

Ich bin mir bei dem letzten Absatz zwar nicht sicher, da der 
Ethernet-Treiber sehr komplex ist und ich die Funktionsweise mit dem 
DMA-Deskriptoren nicht komplett verstehe, jedoch hat der beschriebene 
Fix mein Problem gelöst. Ich kann mein Board jetzt anpingen! Echt cool! 
Ich gehe auch davon aus, dass der Rest der API von lwip jetzt 
funktionieren wird.

Lustigerweise saß ich sehr lange an diesem Problem, habe es nach diesem 
Post aber in wenigen Tagen gefunden. Danke für eure Hinweise!

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.