Other Parts Discussed in Thread: HALCOGEN
Hello,
we currently have a platform where we run LwIP, with changes from the example provided by TI, essentially to prevent the processing of the IP requests by the RX IRQ. The processing is done instead in the while loop in the function main().
What we observe is that we can communicate for hours, sometimes even days, with the platform, until the RX IRQ stops being called. When this happens, we can see:
- MACSTATUS has a value of 0x80000000 (system is idle, no error)
- RXCONTROL has a value of 0x00000001 (rx is enable)
- RXINTMASKSET has a value of 0x00000001 (the RX IRQ is enable)
- MACINVECTOR has a value of 0x00000001 (there is a pending RX IRQ)
- The global IRQs are enable (the register CPSR has a good value and other IRQs can be seen being executed)
and even so, the RX IRQ is not called. It feels like we executed an IRQ that wasn't acknowledged, but we acknowledge it at every call (see handler below).
If we manually acknowledge the RX IRQ outside the IRQ (using the debugger or a periodic function), boom, the RX IRQ is called again.
We suspect that multiple messages might arrive at the same time in our setup, but couldn't see how we end up in this scenario.
Any clues on how to explain this behavior?
Many thanks
Kind regards,
Frederic.
void hdkif_rx_inthandler(struct netif * netif)
{
hdkif_t *psHdkif = netif->state;
rxch_t *psRxch = &(psHdkif->rxchptr);
volatile emac_rx_bd_t *psCurrBd, *psCurrTail, *psProcessedBd;
struct pbuf *spBuf;
uint16_t u16PacketLen, u16PayloadOffset, u16BdLen, u16BdOffset;
const void *pBdData;
/* Get the buffer descriptor which
* contains the start of the most recent received packet
* */
psCurrBd = psRxch->active_head;
psProcessedBd = psRxch->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(psCurrBd->flags_pktlen) & EMAC_BUF_DESC_SOP) == EMAC_BUF_DESC_SOP) {
/* Start processing once the packet is loaded */
if((hdkif_swizzle_data(psCurrBd->flags_pktlen) & EMAC_BUF_DESC_OWNER) != EMAC_BUF_DESC_OWNER) {
/* this bd chain will be freed after processing */
psRxch->free_head = psCurrBd;
u16PacketLen = hdkif_swizzle_data(psCurrBd->flags_pktlen) & 0xFFFF;
spBuf = pbuf_alloc(PBUF_RAW, u16PacketLen, PBUF_POOL);
/* start processing the descriptors until EOP (end of packet) is met.*/
u16PayloadOffset = 0;
while((hdkif_swizzle_data(psCurrBd->flags_pktlen) & EMAC_BUF_DESC_EOP) != EMAC_BUF_DESC_EOP)
{
u16BdOffset = (uint16_t) (hdkif_swizzle_data(psCurrBd->bufoff_len) & 0xFFFF0000) >> 16;
u16BdLen = (uint16_t) hdkif_swizzle_data(psCurrBd->bufoff_len) & 0xFFFF;
pBdData = (const void*) (hdkif_swizzle_data(psCurrBd->bufptr) + u16BdOffset);
/*Copy ethernet frame into the pbuf chain if pbuf was allocated (if the pool is big enough)
* The condition has to be here because we need to iterate through all the descriptors anyway.
* */
if ((spBuf != NULL) && (pbuf_take_at(spBuf, pBdData, u16BdLen, u16PayloadOffset) == ERR_MEM))
{
/* pbuf too small, drop packet */
pbuf_free(spBuf);
}
u16PayloadOffset += u16BdLen;
psCurrBd->flags_pktlen = (uint32_t) hdkif_swizzle_data(EMAC_BUF_DESC_OWNER);
psCurrBd->bufoff_len = (uint32_t) hdkif_swizzle_data(MAX_TRANSFER_UNIT);
psProcessedBd = psCurrBd;
/* process the next buffer descriptor that is still part of this packet*/
psCurrBd = psCurrBd->next;
}
/* Updating the last descriptor (which contained the EOP flag) */
pBdData = (const void*) hdkif_swizzle_data(psCurrBd->bufptr);
u16BdLen = (uint16_t) hdkif_swizzle_data(psCurrBd->bufoff_len);
if ((spBuf != NULL) && (pbuf_take_at(spBuf, pBdData, u16BdLen, u16PayloadOffset) == ERR_MEM))
{
/* pbuf too small, drop packet */
pbuf_free(spBuf);
}
psCurrBd->flags_pktlen = (uint32)hdkif_swizzle_data(EMAC_BUF_DESC_OWNER);
psCurrBd->bufoff_len = (uint32)hdkif_swizzle_data(MAX_TRANSFER_UNIT);
psProcessedBd = psCurrBd;
psCurrBd = hdkif_swizzle_rxp(psCurrBd->next);
/* acknowledge to the EMAC that the BD was processed */
EMACRxCPWrite(psHdkif->emac_base, (uint32_t)EMAC_CHANNELNUMBER, (uint32_t)psProcessedBd);
/* add the newly created pbuf to the queue for polling */
if ((spBuf != NULL) && (_lwIPQueueAdd(spBuf) == 0xFFUL))
{
/* queue is full, free the pbuf */
pbuf_free(spBuf);
}
/* The next buffer descriptor is the new head of the linked list. */
psRxch->active_head = psCurrBd;
/* The processed descriptor is now the tail of the linked list. */
psCurrTail = psRxch->active_tail;
psCurrTail->next = hdkif_swizzle_rxp(psRxch->free_head);
/* The last element in the already processed Rx descriptor chain is now the end of list. */
psProcessedBd->next = NULL;
/**
* 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(psCurrTail->flags_pktlen) & EMAC_BUF_DESC_EOQ) == EMAC_BUF_DESC_EOQ) {
EMACRxHdrDescPtrWrite(psHdkif->emac_base, (uint32)(psRxch->free_head), (uint32)EMAC_CHANNELNUMBER);
}
psRxch->free_head = psCurrBd;
psRxch->active_tail = psProcessedBd;
}
}
EMACCoreIntAck(psHdkif->emac_base, EMAC_INT_CORE0_RX);
}