great, glad you got it working.
On 9/13/2012 11:50 AM, Mark Lakata wrote:
Thank you Zach. That gave me the resolve to see if I needed to rewrite
the ST demo code, and sure enough, it looks like their code is crap.
It shouldn't surprise me, this is not the first time I've encountered
bad ST demo code. They assumed that one interrupt equals exactly one
packet, but that is not the way it works. The interrupt just means at
least one packet is available. I kept the ISR the same (with a
counting semaphore), but I drain out all available rx packets in the
receiving input task, and cleaned up the error handling in
low_level_input. This works great now with debugger breaks. In fact,
it works even better than before for transferring larger amounts of
data (ie their demo webpage images load faster now too).
-Mark
These 3 functions go in ethernetif.c
// from the sample code for the STM32F4x7 ethernet FreeRTOS/lwIP demo.
/**
* Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
* @param netif the lwip network interface structure for this ethernetif
* @return a pbuf filled with the received packet (including MAC header)
* NULL on memory error
*/
static struct pbuf * low_level_input(struct netif *netif)
{
struct pbuf *p, *q;
u16_t len;
uint32_t l=0,i =0;
FrameTypeDef frame;
u8 *buffer;
__IO ETH_DMADESCTypeDef *DMARxNextDesc;
p = NULL;
/* Get received frame */
frame = ETH_Get_Received_Frame_interrupt();
if (frame.descriptor && frame.buffer) {
/* check that frame has no error */
if ((frame.descriptor->Status & ETH_DMARxDesc_ES) ==
(uint32_t)RESET)
{
/* Obtain the size of the packet and put it into the "len"
variable. */
len = frame.length;
buffer = (u8 *)frame.buffer;
/* We allocate a pbuf chain of pbufs from the pool. */
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
/* Copy received frame from ethernet driver buffer to stack
buffer */
if (p != NULL)
{
for (q = p; q != NULL; q = q->next)
{
memcpy((u8_t*)q->payload, (u8_t*)&buffer[l], q->len);
l = l + q->len;
}
}
}
/* Release descriptors to DMA */
/* Check if received frame with multiple DMA buffer segments */
if (DMA_RX_FRAME_infos->Seg_Count > 1)
{
DMARxNextDesc = DMA_RX_FRAME_infos->FS_Rx_Desc;
}
else
{
DMARxNextDesc = frame.descriptor;
}
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
for (i=0; i<DMA_RX_FRAME_infos->Seg_Count; i++)
{
DMARxNextDesc->Status = ETH_DMARxDesc_OWN;
DMARxNextDesc = (ETH_DMADESCTypeDef
*)(DMARxNextDesc->Buffer2NextDescAddr);
}
/* Clear Segment_Count */
DMA_RX_FRAME_infos->Seg_Count =0;
}
return p;
}
static void ethernet_watchdog(void) {
/* When Rx Buffer unavailable flag is set: clear it and resume
reception */
if ((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET)
{
/* Clear RBUS ETHERNET DMA flag */
ETH->DMASR = ETH_DMASR_RBUS;
/* Resume DMA reception. The register doesn't care what you
write to it. */
ETH->DMARPDR = 0;
}
}
void ethernetif_input( void * pvParameters )
{
struct pbuf *p;
for( ;; )
{
if (xSemaphoreTake( s_xSemaphore,
emacBLOCK_TIME_WAITING_FOR_INPUT)==pdTRUE)
{
while ((p = low_level_input( s_pxNetIf )) != 0) {
if (p != 0) {
if (ERR_OK != s_pxNetIf->input( p, s_pxNetIf))
{
pbuf_free(p);
p=NULL;
}
}
}
}
ethernet_watchdog();
}
}
On 9/13/2012 7:38 AM, Zachary Smith wrote:
Just to clarify...
You say the RBU flag is being cleared and then the DMARPDR register
is written to restart reception. When the RBU flag is asserted it
means all the DMA buffers have filled and are "owned" by the CPU. So
you must read from at least one of the descriptors and give it back
to the DMA (set own bit) before writing to the DMARPDR register to
restart reception. Are you doing that?
-Zach
On 9/12/2012 6:51 PM, Mark Lakata wrote:
Hi Zachary,
Thanks for the response. Unfortunately, it doesn't seem to help.
The ST code basically does what you say, except that the RBU
interrupt was not enabled. The RBU flag is cleared in the main task
if set (not in the interrupt), and the DMARPDR register is written
to restart reception.
I modified the ST code do what you said you did, which is enable the
RBU interrupt (and AIS) and send a task message to my input handler.
The input handler will then do ETH->DMARPDR=0, for either a rx
packet or RBU error. It doesn't help. It also doesn't seem to help
if I do it all in the ISR.
As a brute force measure, I added a call to
ETH_DMsARxDescChainInit() to clear up all the rx descriptors
(setting the "own" bit to the DMA). That made things better and
worse. Now, sometimes I get <1 ms ping response, and sometimes I get
no response. Obviously, I'm being pretty cavalier over writing all
of the descriptors while the DMA is running, but it was shot in the
dark to see if it made a difference. It seems like this is the right
thing to do, but in a way that is thread safe with lwIP. Someone
out there surely has done this in the right method...
thanks for any more hints,
Mark
On 9/12/2012 4:27 PM, Zachary Smith wrote:
I am using STM32F217 and I'm sure the Ethernet MAC is the same.
You are likely correct in thinking the problem is the RBUS
interrupt flag. When you hit the breakpoint the Ethernet DMA
probably fills up all the RX descriptor buffers and asserts that
interrupt flag and then is not able to receive anything else until
you take care of the interrupt and then resume reception.
You have to enable the RBU interrupt and clear it if it happens.
Also, if I remember correctly, if this interrupt happens it can
happen that you don't get a normal Receive interrupt like you
normally would so you are not triggered to read from the buffers.
enable the RBU interrupt:
ETH_DMAITConfig(ETH_DMA_IT_AIS | ETH_DMA_IT_RBU, ENABLE);
ISR: clear the flag:
if(ETH_GetDMAITStatus(ETH_DMA_IT_RBU) != RESET)
ETH_DMAClearITPendingBit(ETH_DMA_IT_RBU | ETH_DMA_IT_AIS);
Then reception will be in the suspended state until you resume
reception by writing to the DMARPDR (receive poll demand)
register. The manual says the DMA will start checking for
available descriptors again when you write to this register with
any value:
ETH->DMARPDR = 0;
In my case, if the RBU interrupt happens I clear the flag and then
send a msg to my TCP task to do an Ethernet input. My Ethernet
driver always does the resume reception command after reading from
a receive descriptor. That way the rx descriptors are read and
then reception resumed.
Hope that helps.
On 9/12/2012 4:35 PM, Mark Lakata wrote:
I've got my STM32F407 port for FreeRTOS 7.2 and lwIP1.40 running
now, with ping and HTTP working well (I started with the ST's demo
which was based on FreeRTOS6.1.0 and lwIP1.3.2, and merged it into
the latest code).
However, if I stop the program momentarily with the debugger, or
hit a breakpoint, the lwIP stack slows down a lot. The ping time
goes from <1ms to 300-500 ms typically, sometimes > 2000 ms. It is
easy to reproduce, including the original ST demo code:
1. run demo code
2. count to 5
3. do a ping from another computer
4. hit 'break' in the debugger from IAR EWARM
5. hit 'run' right away
6. do another ping
I think it is related to this problem, discusses in an earlier
thread:
http://lists.nongnu.org/archive/html/lwip-users/2012-05/msg00111.html
It seems that once you stop the CPU, the DMA engine gets tied up
in knots and doesn't recover, until a reset. It is related to the
RBUS interrupt flag (Receive Buffer unavailable) in the ETH_DMASR
status register. I see this bit go high forever once the problem
occurs. It does not self clear with the existing code.
I'm sure this can be fixed with a software workaround, but I
haven't found it or figured it out. I'm just starting out on lwIP
and the STM32F4x7 (first week).
Any ideas?
thanks,
Mark Lakata
_______________________________________________
lwip-users mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/lwip-users
_______________________________________________
lwip-users mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/lwip-users
_______________________________________________
lwip-users mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/lwip-users
_______________________________________________
lwip-users mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/lwip-users
_______________________________________________
lwip-users mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/lwip-users
_______________________________________________
lwip-users mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/lwip-users