AnsweredAssumed Answered

LWIP on LPC4357, stuck in lpc_low_level_output

Question asked by Mitchell Jones on Jul 27, 2017
Latest reply on Aug 8, 2017 by jeremyzhou

Hi, I'm stuck here with the TX side of my app. It appears I am running out of descriptors. I've already modified the famous loop that is problematic as follows: 

(in lpc18xx_43xx_emac)

 volatile u32_t check = lpc_tx_ready(netif);

 

while(dn > check)
#if NO_SYS == 0
{ xSemaphoreTake(lpc_netifdata->xTXDCountSem, 0);}
#else
{
  lpc_tx_reclaim(netif);
  check = lpc_tx_ready(netif);
}

The strange thing is this is only happening when I'm sending a payload that is following a full packet. So if I'm sending anything under 1460 bytes I can do as many transmissions as I want. When I send 1460 followed by a shorter packet of say 500 then it gets stuck. It is very strange. I'll include the mechanisms I'm using to queue the data.

send_buffer(const void* pvBuffer, uint32 uiNumBytes)

struct pbuf *ptr;
ptr = pbuf_alloc(PBUF_TRANSPORT, uiNumBytes , PBUF_RAM);
pbuf_take(ptr, pvBuffer, uiNumBytes);
// std::memcpy(ptr->payload, pvBuffer, uiNumBytes);
// ptr->len = ptr->tot_len = uiNumBytes;
return AddDataAndSend(ptr);

and

 

if(mxDataSet.out_pb == NULL || mxDataSet.out_pb->tot_len == 0)
{
// load data to out_pb
if(mxDataSet.out_pb->tot_len == 0)
{
pbuf_free(mxDataSet.out_pb);
}
mxDataSet.out_pb = ptr;
}else
{
pbuf_cat(mxDataSet.out_pb, ptr);
}
return tcp_client_send_data_set(&mxDataSet);

which is implemented as follows

 

static void tcp_client_raw_send(struct EStreamDataSet* data_set)
{
struct pbuf *ptr;
err_t wr_err = ERR_OK;

while ((wr_err == ERR_OK) && (data_set->out_pb != NULL) && (data_set->out_pb->len <= tcp_sndbuf(data_set->pcb)))
{
ptr = data_set->out_pb;
/* enqueue data for transmission */
wr_err = tcp_write(data_set->pcb, ptr->payload, ptr->len, 1);
if (wr_err == ERR_OK) {
/* continue with next pbuf in chain (if any) */
data_set->out_pb = ptr->next;
if(data_set->out_pb != NULL) {
/* new reference! */
pbuf_ref(data_set->out_pb);
}
/* chop first pbuf from chain */
pbuf_free(ptr);
} else if(wr_err == ERR_MEM) {
/* we are low on memory, try later / harder, defer to poll */
data_set->out_pb = ptr;
} else {
/* other problem ?? */
}
}
}

and 

static err_t tcp_client_raw_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
struct EStreamDataSet *data_set;
data_set = (struct EStreamDataSet *)arg;

LWIP_UNUSED_ARG(len);

if(data_set->out_pb != NULL)
{
/* still got pbufs to send */
tcp_sent(tpcb, tcp_client_raw_sent);
tcp_client_raw_send(data_set);
} else
{
/* no more pbufs to send */
}
return ERR_OK;
}

Do you think I'm experiencing underflow problems? Or is this a different issue entirely? 

 

Note the payloads are getting queued in seperate calls to the send function, the first with a full buffer 1460 the second with an amount less than that. In this instance it seems that second packets descriptor is not clearing, and after 4 of these sequences of 2 (the number of descriptors I have) I get stuck in an infinite loop in emac.

 

oh and just in case, here's my poll

 

static err_t
tcp_client_raw_poll(void *arg, struct tcp_pcb *tpcb)
{
err_t ret_err;
struct EStreamDataSet *data_set;
data_set = (struct EStreamDataSet *)arg;

if (data_set != NULL)
{
if ((data_set->out_pb != NULL) && (data_set->out_pb->tot_len > 0))
{
/* there is a remaining pbuf (chain) */
tcp_client_raw_send(data_set);
} else
{
/* no remaining pbuf (chain) */
// TODO: what needs to happen here?
if (data_set->out_pb != NULL)
{
// Free the buffer.
pbuf_free(data_set->out_pb);
}
}
ret_err = ERR_OK;
} else
{
/* nothing to be done */
// tcp_abort(tpcb);
ret_err = ERR_ABRT;
}
return ret_err;
}

Outcomes