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>
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.
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?
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
staticstructpbuf*
2
low_level_input(structnetif*netif)
3
{
4
structpbuf*p,*q;
5
u16_tlen;
6
intl=0;
7
FrameTypeDefframe;
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. */
/* 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Ð_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
returnp;
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!