LWIP + freeRTOS + OPENER, Ethernet DMA Bus Error
I have followed the instructions in GIT to make ethernet works correctly on STM32H750 (setup TX/RX descriptors and their MPU config, also the LWIP heap and its MPU config, and the RX buffers).
Everything seems working correctly after hours of setup and debugging, but the thing that break Ethernet and make it not working is when handling the unicast UDP or the UDP IO stream of OpEner it trigger a BUS Error in MAC DMA and stop everything from working, the explicit communication based on TCP works correctly and doesn’t break the Ethernet.
I debugged for days of what could generate a bus fault error, then i find the udp when uses netconn it doesn’t copy the prepared buffer on lwip heap for sendig and in other way it give it directly the address of udp payload from the task stack, and this trigger a Bus Error when calling HAL_ETH_Transmit_IT because the task stack is not DMA accessible.

So I made a workarround in low_level_output to detect the payload from outside lwip heap and copy that payload in lwip heap, i used a linker varriables to detect the begin and the end of lwip heap:
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
uint32_t i = 0U;
struct pbuf *q = NULL;
err_t errval = ERR_OK;
ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT];
struct pbuf *dma_copy = NULL; /* tracks if we allocated a DMA-safe copy */
extern uint8_t __ETH_TX_START[];
extern uint8_t __ETH_TX_END[];
memset(Txbuffer, 0, ETH_TX_DESC_CNT * sizeof(ETH_BufferTypeDef));
/* Check if the entire pbuf chain is DMA-safe */
int needs_copy = 0;
for (q = p; q != NULL; q = q->next)
{
uint8_t *start = (uint8_t *)q->payload;
uint8_t *end = start + q->len;
if (start < __ETH_TX_START || end > __ETH_TX_END)
{
needs_copy = 1;
break;
}
}
/* If any buffer is outside the DMA region, allocate a flat DMA-safe pbuf and copy */
if (needs_copy)
{
dma_copy = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
if (dma_copy == NULL)
{
return ERR_MEM;
}
/* Verify the new pbuf landed in DMA-safe memory */
if ((uint8_t *)dma_copy->payload < __ETH_TX_START ||
((uint8_t *)dma_copy->payload + dma_copy->len) > __ETH_TX_END)
{
pbuf_free(dma_copy);
return ERR_MEM;
}
pbuf_copy(dma_copy, p);
p = dma_copy; /* use the DMA-safe copy from here on */
}
for (q = p; q != NULL; q = q->next)
{
if (i >= ETH_TX_DESC_CNT)
{
if (dma_copy != NULL) pbuf_free(dma_copy);
return ERR_IF;
}
Txbuffer[i].buffer = q->payload;
Txbuffer[i].len = q->len;
if (i > 0)
{
Txbuffer[i - 1].next = &Txbuffer[i];
}
if (q->next == NULL)
{
Txbuffer[i].next = NULL;
}
i++;
}
TxConfig.Length = p->tot_len;
TxConfig.TxBuffer = Txbuffer;
TxConfig.pData = p;
pbuf_ref(p);
if (HAL_ETH_Transmit_IT(&heth, &TxConfig) == HAL_OK)
{
errval = ERR_OK;
}
while (osSemaphoreAcquire(TxPktSemaphore, TIME_WAITING_FOR_INPUT) != osOK)
{
}
HAL_ETH_ReleaseTxPacket(&heth);
/* Free our DMA copy if we made one (decrements ref added by pbuf_ref too) */
if (dma_copy != NULL)
{
pbuf_free(dma_copy);
}
return errval;
}
I share this to help if anyone face the same issue.
