This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS570LS3137: lwIP demo halts after about 60 UDP packets

Part Number: TMS570LS3137

I'm trying to use the lwIP Demo 4.0.0 as a basis for a new firmware. However, after sending about 60 UDP packets to it, the code halts in the interruption handler, more precisely, at function hdkif_rx_inthandler, due to a NULL pointer in curr_bd->next (curr_bd being hdkif[0]->state->rxch->active_head). Trying to check for this pointer in the loop of the function prevents the break, but no more interrupts are issued.

I'm currently using  CCS 11.1.0.00011 with TI compiler v20.2.7.LTS. For easier, reference I'm pasting the interrupt handler below, with the very few alterations I've made to try to isolate the problem:

/**
 * Handler for Receive interrupt. Packet processing is done in this
 * interrupt handler itself.
 *
 * @param netif the lwip network interface structure for this ethernetif
 * @return none
 */
uint32 last_curr_bd, last_next_bd;
uint32 no_prob_last = 1;
void
hdkif_rx_inthandler(struct netif *netif) {
  struct hdkif *hdkif;
  struct rxch *rxch;
  volatile struct emac_rx_bdp *curr_bd, *processed_bd, *curr_tail, *last_bd;
  volatile struct pbuf *pbuf, *q, *new_pbuf;
  uint32 ex_len = 0, len_to_alloc = 0;
  uint16 tot_len;

  hdkif = netif->state;
  rxch = &(hdkif->rxch);

  /* Get the bd which contains the earliest filled data */
  curr_bd = rxch->active_head;
  last_bd = rxch->active_tail;


  /**
   * Process the descriptors as long as data is available
   * when the DMA is receiving data, SOP flag will be set
  */
  while((hdkif_swizzle_data(curr_bd->flags_pktlen) & EMAC_BUF_DESC_SOP)
        && (curr_bd != NULL)) {
    ex_len = 0;
    len_to_alloc = 0;

    /* Start processing once the packet is loaded */
    if((hdkif_swizzle_data(curr_bd->flags_pktlen) & EMAC_BUF_DESC_OWNER)
       != EMAC_BUF_DESC_OWNER) {

      if(rxch->free_head == NULL) {
        /* this bd chain will be freed after processing */
        rxch->free_head = curr_bd;
      }

      /* Get the total length of the packet. curr_bd points to the start
       * of the packet.
       */
      tot_len = hdkif_swizzle_data(curr_bd->flags_pktlen) & 0xFFFF;

      /* Get the start of the pbuf queue */
      q = curr_bd->pbuf;

      do {
        /* Get the pbuf pointer which is associated with the current bd */
        pbuf = curr_bd->pbuf;

        /* If the earlier pbuf ended, update the chain */
        if(pbuf->next == NULL) {
          pbuf->next = (struct pbuf*)hdkif_swizzle_rxp(curr_bd->next)->pbuf;
        }

        len_to_alloc += pbuf->len;
        /* Update the len and tot_len fields for the pbuf in the chain*/
        pbuf->len = hdkif_swizzle_data(curr_bd->bufoff_len) & 0xFFFF;
        pbuf->tot_len = tot_len - ex_len ;
        processed_bd = curr_bd;
        ex_len += pbuf->len;

        /* if(hdkif_swizzle_rxp(curr_bd->next) == NULL){ */
        /*     break; */
        /* }else{ */
            curr_bd = hdkif_swizzle_rxp(curr_bd->next);
        /* } */
      } while((hdkif_swizzle_data(processed_bd->flags_pktlen) & EMAC_BUF_DESC_EOP)
              != EMAC_BUF_DESC_EOP);

      /**
       * Close the chain for this pbuf. A full packet is received in
       * this pbuf chain. Now this pbuf can be given to upper layers for
       * processing. The start of the pbuf chain is now 'q'.
      */
      pbuf->next = NULL;

      /* Adjust the link statistics */
      LINK_STATS_INC(link.recv);

      /* Process the packet */
      if(ethernet_input((struct pbuf *)q, netif) != ERR_OK) {
        /* Adjust the link statistics */
        LINK_STATS_INC(link.memerr);
        LINK_STATS_INC(link.drop);
      }

      /* Acknowledge that this packet is processed */
      EMACRxCPWrite(hdkif->emac_base, 0, (unsigned int)processed_bd);

      rxch->active_head = curr_bd;

      /**
       * The earlier pbuf chain is freed from the upper layer. So, we need to
       * allocate a new pbuf chain and update the descriptors with the pbuf info.
       * To support chaining, the total length freed by the upper layer is tracked.
       * Care should be taken even if the allocation fails.
       */
      /**
       * now len_to_alloc will contain the length of the pbuf which was freed
       * from the upper layer
       */
      rxch->freed_pbuf_len += len_to_alloc;
      new_pbuf = pbuf_alloc(PBUF_RAW, (rxch->freed_pbuf_len), PBUF_POOL);

      /* Write the descriptors with the pbuf info till either of them expires */
      if(new_pbuf != NULL) {
        curr_bd = rxch->free_head;

        for(q = new_pbuf; (q != NULL) && (curr_bd != rxch->active_head); q = q->next) {
          curr_bd->bufptr = hdkif_swizzle_data((uint32)(q->payload));

          /* no support for buf_offset. RXBUFFEROFFEST register is 0 */
          curr_bd->bufoff_len = hdkif_swizzle_data((q->len) & 0xFFFF);
          curr_bd->flags_pktlen = hdkif_swizzle_data(EMAC_BUF_DESC_OWNER);

          rxch->freed_pbuf_len -= q->len;

          /* Save the pbuf */
          curr_bd->pbuf = q;
          last_bd = curr_bd;
          curr_bd = hdkif_swizzle_rxp(curr_bd->next);
        }

        /**
         * At this point either pbuf expired or no rxbd to allocate. If
         * there are no, enough rx bds to allocate all pbufs in the chain,
         * free the rest of the pbuf
         */
        if(q != NULL) {
          pbuf_free((struct pbuf *)q);
        }

        curr_tail = rxch->active_tail;
        last_bd->next = NULL;

        curr_tail->next = hdkif_swizzle_rxp(rxch->free_head);

        /**
         * Check if the reception has ended. If the EOQ flag is set, the NULL
         * Pointer is taken by the DMA engine. So we need to write the RX HDP
         * with the next descriptor.
         */
        if(hdkif_swizzle_data(curr_tail->flags_pktlen) & EMAC_BUF_DESC_EOQ) {
          EMACRxHdrDescPtrWrite(hdkif->emac_base, (uint32)(rxch->free_head), 0);
        }

        rxch->free_head  = curr_bd;
        rxch->active_tail = last_bd;
      }
    }
    curr_bd = rxch->active_head;
  }

  EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_RX);
  EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_TX);
}

  • Hi,

    Are you processing the UDP receive packets?
    The problem looks like due to overrun of received buffer.

    Calling example:  call the udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) function as follows.
    (void)udp_recv(pcb,OWNUDPReceive,NULL);


    where pcb is,
    struct udp_pcb* pcb;
    where OWNUDPReceive is the user function to process the UDP packet,

    static void OWNUDPReceive(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
    {
    process(p->payload); //payload is the member which holds the base address where your actual data exists.
    pbuf_free(p); //don't forget to call this function.
    }

    where process() can be defined as follows.
    void process(uint8 *Ptr)
    {

    }

    If we process the received UDP packets and free the buffer continuously then we might not end up with the halt in handler.

    --

    Thanks,

    Jagadish.

  • Thank you! Indeed, the problem is the lack of freeing of pbuf.

    To add more context, to help isolate a previous issue I had removed most of my payload, with the pbuf freeing, from inside the callback function. Everything seems to be working well now. Thanks!