2025-05-22 12:30 AM
I am connecting a TCP/IP stack to the HAL_ETH driver of an STM32F7xx. I am using https://github.com/STMicroelectronics/STM32CubeF7/blob/master/Projects/STM32F767ZI-Nucleo/Applications/LwIP/LwIP_HTTP_Server_Netconn_RTOS/Src/ethernetif.c as a starting point.
I see that low_level_output() calls HAL_ETH_ReleaseTxPacket() only if the ethernet driver runs out of DMA descriptors:
do
{
if(HAL_ETH_Transmit_IT(&EthHandle, &TxConfig) == HAL_OK)
{
errval = ERR_OK;
}
else
{
if(HAL_ETH_GetError(&EthHandle) & HAL_ETH_ERROR_BUSY)
{
/* Wait for descriptors to become available */
osSemaphoreWait( TxPktSemaphore, ETHIF_TX_TIMEOUT);
HAL_ETH_ReleaseTxPacket(&EthHandle);
errval = ERR_BUF;
}
else
{
/* Other error */
pbuf_free(p);
errval = ERR_IF;
}
}
}while(errval == ERR_BUF);
It seems like HAL_ETH_ReleaseTxPacket() will then deallocate all completed buffers and block if none of the scheduled buffers has been completed yet. So far so good. But:
Solved! Go to Solution.
2025-07-01 3:30 AM
Hello @riwe,
The call to HAL_ETH_ReleaseTxPacket() API in the cotted code is just a WA to completely reject the previous failed transmit ops and go ahead with the next transmit one. That means the data being submitted by the upper level (Ethernet stack) will be lost (immediately deallocated) and the error will be reported the stack (ERR_BUF). I believe there should be better implementation or WA which allow recovery (resending the buff?).
Now regarding your question :
"
HAL_ETH_ReleaseTxPacket() call should be made in threaded mode not in the interrupt mode. The API processing is huge and would definitely break the ISR behavior.
The programming model is as below:
1 - HAL_ETH_Transmit(_IT)
2 - Ensure that the Transmit is completed:
2.1 : HAL_ETH_Transmit() is blocking call until the transmit is done (or fail!) --> nothing to do to sync here
2.2 : HAL_ETH_Transmit_IT() is non-blocking call: use HAL_ETH_TxCpltCallback() to sync here
3 - HAL_ETH_ReleaseTxPacket() to request App to free memory and go ahead with next transmit.
Here below a code example :
Send_Packet(...) {
...
HAL_ETH_Transmit_IT(...);
while (xSemaphoreTake(TxPktSemaphore, ULONG_MAX) != pdTRUE)
{
}
HAL_ETH_ReleaseTxPacket(...);
/* Manage errors */
HAL_StatusTypeDef hal_error = HAL_ETH_GetError(&EthHandle);
if(hal_error == HAL_ETH_ERROR_NONE)
{
}
else if(hal_error & HAL_ETH_ERROR_BUSY)
{
errval = ERR_BUF;
}
else
{
/* Other error */
/* Not sure if this is the right solution - to check upper level if
releasing 'p' is good or not - reporting 'ERR_IF' code would be enough! */
pbuf_free(p);
errval = ERR_IF;
}
....
}
void HAL_ETH_TxCpltCallback(hal_eth_handle_t *heth)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(TxPktSemaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void HAL_ETH_ErrorCallback(hal_eth_handle_t *heth)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(TxPktSemaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
2025-07-01 3:30 AM
Hello @riwe,
The call to HAL_ETH_ReleaseTxPacket() API in the cotted code is just a WA to completely reject the previous failed transmit ops and go ahead with the next transmit one. That means the data being submitted by the upper level (Ethernet stack) will be lost (immediately deallocated) and the error will be reported the stack (ERR_BUF). I believe there should be better implementation or WA which allow recovery (resending the buff?).
Now regarding your question :
"
HAL_ETH_ReleaseTxPacket() call should be made in threaded mode not in the interrupt mode. The API processing is huge and would definitely break the ISR behavior.
The programming model is as below:
1 - HAL_ETH_Transmit(_IT)
2 - Ensure that the Transmit is completed:
2.1 : HAL_ETH_Transmit() is blocking call until the transmit is done (or fail!) --> nothing to do to sync here
2.2 : HAL_ETH_Transmit_IT() is non-blocking call: use HAL_ETH_TxCpltCallback() to sync here
3 - HAL_ETH_ReleaseTxPacket() to request App to free memory and go ahead with next transmit.
Here below a code example :
Send_Packet(...) {
...
HAL_ETH_Transmit_IT(...);
while (xSemaphoreTake(TxPktSemaphore, ULONG_MAX) != pdTRUE)
{
}
HAL_ETH_ReleaseTxPacket(...);
/* Manage errors */
HAL_StatusTypeDef hal_error = HAL_ETH_GetError(&EthHandle);
if(hal_error == HAL_ETH_ERROR_NONE)
{
}
else if(hal_error & HAL_ETH_ERROR_BUSY)
{
errval = ERR_BUF;
}
else
{
/* Other error */
/* Not sure if this is the right solution - to check upper level if
releasing 'p' is good or not - reporting 'ERR_IF' code would be enough! */
pbuf_free(p);
errval = ERR_IF;
}
....
}
void HAL_ETH_TxCpltCallback(hal_eth_handle_t *heth)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(TxPktSemaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void HAL_ETH_ErrorCallback(hal_eth_handle_t *heth)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(TxPktSemaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
2025-07-03 1:01 PM
Thanks.