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>
Wegen diesen Problemen nehme ich einen Raspi, wenn es was mit Ethernet-Anschluss sein soll. Ich weiss, das hift Dir nicht weiter....
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?
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.
Moin, in deiner mem.ld steht nichts von heap und stack. Sieh mal in die sections.ld was da definiert ist.
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?
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); |
Alex B. schrieb: > __Main_Stack_Size = 1024 ; Ich würde den Wert einfach mal vergrössern und das Verhalten beobachten.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.