FreeRTOS Support Archive
The FreeRTOS support forum is used to obtain active support directly from Real
Time Engineers Ltd. In return for using our top quality software and services for
free, we request you play fair and do your bit to help others too! Sign up
to receive notifications of new support topics then help where you can.
This is a read only archive of threads posted to the FreeRTOS support forum.
The archive is updated every week, so will not always contain the very latest posts.
Use these archive pages to search previous posts. Use the Live FreeRTOS Forum
link to reply to a post, or start a new support thread.
[FreeRTOS Home] [Live FreeRTOS Forum] [FAQ] [Archive Top] [January 2017 Threads] Implementing prvEMACDeferredInterruptHandlerTaskPosted by orifai01 on January 3, 2017 Hello, I'm trying to pass received data to the TCP/IP in a deferred interrupt handler task.
I've implemented an ISR called xEthernetHandler as described in xTimerPendFunctionCallFromISR web page:
void xEthernetHandler( void )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
NVIC_ClearPendingIRQ(ETHERNET_IRQn);
if(smsc9220_RxStatusFifoLevelIrq())
{
xTimerPendFunctionCallFromISR( prvEMACDeferredInterruptHandlerTask,
NULL,
1,
&xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
}
void prvEMACDeferredInterruptHandlerTask( void * pvParameter1, uint32t ulParameter2 )
{
NetworkBufferDescriptort *pxBufferDescriptor;
size_t xBytesReceived;
unsigned int index = 0;
/* Used to indicate that xSendEventStructToIPTask() is being called because
of an Ethernet receive event. */
IPStackEvent_t xRxEvent;
for( ;; )
{
/* Wait for the Ethernet MAC interrupt to indicate that another packet
has been received. The task notification is used in a similar way to a
counting semaphore to count Rx events, but is a lot more efficient than
a semaphore. */
ulTaskNotifyTake( pdFALSE, portMAX_DELAY );
/* See how much data was received. Here it is assumed ReceiveSize() is
a peripheral driver function that returns the number of bytes in the
received Ethernet frame. */
xBytesReceived = smsc9220_recv_size();
if( xBytesReceived > 0 )
{
/* Allocate a network buffer descriptor that points to a buffer
large enough to hold the received frame. As this is the simple
rather than efficient example the received data will just be copied
into this buffer. */
pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( xBytesReceived, 0 );
if( pxBufferDescriptor != NULL )
{
if(smsc9220_recv_packet((unsigned int *)pxBufferDescriptor->pucEthernetBuffer, &index))
{
printf("Packet receive failed.\n");
vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
}
else
{
pxBufferDescriptor->xDataLength = xBytesReceived;
/* See if the data contained in the received Ethernet frame needs
to be processed. NOTE! It is preferable to do this in
the interrupt service routine itself, which would remove the need
to unblock this task for packets that don't need processing. */
if( eConsiderFrameForProcessing( pxBufferDescriptor->pucEthernetBuffer )
== eProcessBuffer )
{
/* The event about to be sent to the TCP/IP is an Rx event. */
xRxEvent.eEventType = eNetworkRxEvent;
/* pvData is used to point to the network buffer descriptor that
now references the received data. */
xRxEvent.pvData = ( void * ) pxBufferDescriptor;
/* Send the data to the TCP/IP stack. */
if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE )
{
/* The buffer could not be sent to the IP task so the buffer
must be released. */
vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
/* Make a call to the standard trace macro to log the
occurrence. */
iptraceETHERNET_RX_EVENT_LOST();
}
else
{
/* The message was successfully sent to the TCP/IP stack.
Call the standard trace macro to log the occurrence. */
iptraceNETWORK_INTERFACE_RECEIVE();
}
}
else
{
/* The Ethernet frame can be dropped, but the Ethernet buffer
must be released. */
vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
}
}
}
else
{
iptraceETHERNET_RX_EVENT_LOST();
}
}
}
}
I'm using BufferAllocation2.c. ipconfigIPTASKPRIORITY is set to (configMAXPRIORITIES - 1).
Two questions:
1. I don't understand why ulTaskNotifyTake() is necessary, as we already got an Ethernet MAC interrupt (that's the reason we entered handllerTask function).
2.Althugh xTimerPendFunctionCallFromISR changes xHigherPriorityTaskWoken to be pdTRUE, prvEMACDeferredInterruptHandlerTask is not being called and all task seem to be stuck.
Thank you for your help
Implementing prvEMACDeferredInterruptHandlerTaskPosted by heinbali01 on January 3, 2017 The library FreeRTOS+TCP does not make use of FreeRTOS' timer functions.
In all published versions of NetworkInterface.c , the TaskNotify mechanism is used to wake-up the prvEMACDeferredInterruptHandlerTask .
~~~~
void xEthernetHandler( void )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
NVIC_ClearPendingIRQ(ETHERNET_IRQn);
if(smsc9220_RxStatusFifoLevelIrq())
{
TaskNotifyGiveFromISR( xDeferredInterruptTaskHandle, ( BaseType_t * ) &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
}
~~~~
- I don't understand why
ulTaskNotifyTake() is necessary
The function will go sleeping until an interrupt has occurred, which is soon after TaskNotifyGiveFromISR() . Note the for(;;) loop.
Normally I would let it sleep for a limited amount of time: the PHY's Link Status (LS) must be checked. When the LS goes low, transmission of packets is impossible and should be inhibited.
2.Although xTimerPendFunctionCallFromISR changes xHigherPriorityTaskWoken
to be pdTRUE, prvEMACDeferredInterruptHandlerTask is not being called and
all task seem to be stuck.
I'm not sure what the reason is for that, but I would use the 'lighter' method of TaskNotify .
Regards.
Implementing prvEMACDeferredInterruptHandlerTaskPosted by orifai01 on January 3, 2017 Hi Hein,
Thank you for your answer.
- But the Ethernet interrupt has already occurred. That's the reason you've entered xEthernetHandler. At that point I would like to read the received bytes but ulTaskNotifyTake() forces me to wait for additional interrupt. Shouldn't it be at the end of the loop?
I have two additional questions:
2. Shall I disable & clean the interrupt at the begging of xEthernetHandler and enable it somewhere?
3. Is this task running from scheduler startup or only from the first time Ethernet interrupt occures? What happens after receiving the second interrupt?
Thank you,
Orit
Implementing prvEMACDeferredInterruptHandlerTaskPosted by heinbali01 on January 3, 2017 Hi Orit,
But the Ethernet interrupt has already occurred.
That's the reason you've entered xEthernetHandler.
At that point I would like to read the received bytes
but ulTaskNotifyTake() forces me to wait for additional
interrupt. Shouldn't it be at the end of the loop?
It doesn't matter if the ulTaskNotifyTake() is placed at the beginning or at the end. The function will be sleeping 99.9% of the time.
The following will be the order of events, it all happens within micro seconds:
● The interrupt handler xEthernetHandler() is called
● It will call TaskNotifyGiveFromISR() to make prvEMACDeferredInterruptHandlerTask() runnable again
● xHigherPriorityTaskWoken will be pdTRUE, and the YIELD will succeed
● The task running prvEMACDeferredInterruptHandlerTask() is unblocked immediately ( unless there are other runnable tasks with a higher priority ).
- Shall I disable & clean the interrupt at the beginning of xEthernetHandler and enable it somewhere?
I would think that it doesn't make any difference.
- Is this task running from scheduler startup or only
from the first time Ethernet interrupt occures?
What happens after receiving the second interrupt?
Please have a good look at any of the other versions of NetworkInterface.c : you will see that prvEMACDeferredInterruptHandlerTask() will be started up once and that will will run for ever.
Implementing prvEMACDeferredInterruptHandlerTaskPosted by orifai01 on January 4, 2017 Hi Hein,
I changed the xTimerPendFunctionCallFromISR() to TaskNotifyGiveFromISR() in the irq and rewrote xNetworkInterfaceInitialise so now it creates the deferred interrupt handler task.
I've encountered a different problem. Context switch occurs but I keep receiving interrupts that preventing me from continuing.
TaskHandle_t xDeferredInterruptTaskHandle = NULL;
portBASETYPE xNetworkInterfaceInitialise(void)
{
portBASETYPE xreturn;
xreturn = xTaskCreate( xDeferredInterruptHandlerTask,
"RCV",
configMINIMALSTACKSIZE * 3,
NULL,
mainDEFERREDIRQTASK_PRIORITY,
&xDeferredInterruptTaskHandle );
Common_EnableIrq(ETHERNET_IRQn, 223);
return xreturn;
}
void xEthernetHandler( void )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
Common_DisableIrq(ETHERNET_IRQn);
NVIC_ClearPendingIRQ(ETHERNET_IRQn);
if(smsc9220_RxStatusFifoLevelIrq())
{
vTaskNotifyGiveFromISR( xDeferredInterruptTaskHandle, ( BaseType_t * ) &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
Common_EnableIrq(ETHERNET_IRQn, configMAX_SYSCALL_INTERRUPT_PRIORITY);
}
What shall be the ETHERNETIRQn irq priority if configKERNELINTERRUPTPRIORITY equals to 255 and configMAXSYSCALLINTERRUPTPRIORITY equals to 191.
Thank you,
Orit
Implementing prvEMACDeferredInterruptHandlerTaskPosted by rtel on January 4, 2017 Interrupt priorities on Cortex-M cores is often the cause of some
confusion, so we have tried to explain it on the following page:
http://www.freertos.org/RTOS-Cortex-M3-M4.html
Implementing prvEMACDeferredInterruptHandlerTaskPosted by heinbali01 on January 5, 2017 Hi Orit,
I would be curious to see smsc9220_RxStatusFifoLevelIrq() .
In general: there are many possible triggers for ETHERNET_IRQn . Only the triggers that you need (RX, error?) should be enabled (the others are said to be "masked off"). Now if your interrupt-handler is called, the cause of the interrupt must be reset / cleared. How it is to be cleared depends on the peripheral.
In some cases it suffices to read the STATUS bits, sometimes a logical 0 or 1 must be written to the status-bit in order to reset it. Yet in other cases, nothing has to be done.
So if you observe that the interrupt keeps on being called, try to make clear what the reason is and how it can be cleared.
I do not think it is necessary to call Common_DisableIrq() and Common_EnableIrq() from within the interrupt handler.
Implementing prvEMACDeferredInterruptHandlerTaskPosted by orifai01 on January 5, 2017 Hi Hein,
The Trigger I need is "RX FIFO Status Interrupt Level". smsc9220_RxStatusFifoLevelIrq() simply checks the "RX FIFO Status Interrupt Level" bit in interrupt status register:
int smsc9220RxStatusFifoLevelIrq(void)
{
return CHECKBIT(SMSC9220->INT_STS, 3);
}
I would like the task function to read received bytes everytime interrupt occurs. I do not want the interrupt to occur during the reading process so I disable it, and enable it after reading a packet.
The problem is that the interrupt keeps on being called because I receive a lot of packets, and no other task can run. Is it better to implement this listener as a simple reading function (without a loop) and call xTimerPendFunctionCallFromISR() instead of a task?
Implementing prvEMACDeferredInterruptHandlerTaskPosted by heinbali01 on January 6, 2017 Hi Orit,
~~~~
int smsc9220RxStatusFifoLevelIrq(void)
{
/* HT : if CHECKBIT() is only testing the value of a bit,
this action will probably not reset the cause of the interrupt.
It is documented as a R/WC bit: Read/Write Clear:
A register bit with this attribute can be read and written.
However, a write of a 1 clears (sets to 0) the corresponding
bit and a write of a 0 has no effect
*/
return CHECKBIT(SMSC9220->INTSTS, 3);
}
~~~~
I would like the task function to read received bytes every time
interrupt occurs. I do not want the interrupt to occur during the
reading process so I disable it, and enable it after reading a packet.
You better leave the interrupt enabled all the time, no problem. All it does is make your task runnable. The next call to ulTaskNotifyTake() will succeed immediately without blocking.
If you disable the RX interrupt, you might miss data or receive them too late.
The problem is that the interrupt keeps on being called because I
receive a lot of packets, and no other task can run.
I dare to doubt this theory :-)
Please check which interrupt bits are enabled in INT_EN and make sure that during the interrupt, the corresponding bits in INT_STS will be cleared.
That will stop the heavy load of interrupts.
If you still see too many RX data, make sure that the MAC filtering is OK: do not use promiscuous mode but set certain MAC addresses that are used by your device.
Is it better to implement this listener as a simple reading function
(without a loop) and call xTimerPendFunctionCallFromISR() instead of a task?
I don't think so.
The proposal is as follows:
~~~~
for( ;; )
{
ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
for( ;; )
{
xBytesReceived = smsc9220recvsize();
if( xBytesReceived <= 0 )
{
break;
}
/* send the received packet to the IP-task. */
}
}
~~~~
The ETH interrupt remains active (enabled) all the time. If an interrupt occurs while reading RX packets, that is no problem. Only vTaskNotifyGiveFromISR() will be called, causing the next ulTaskNotifyTake() to "fall through".
Please have a look of one of the other ports, such as:
FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c
Its interrupt handlers will also set a (volatile) bit to indicate what type of interrupt has occurred. This is tested later in the task.
Implementing prvEMACDeferredInterruptHandlerTaskPosted by orifai01 on January 8, 2017 First of all, thank you very much for your time and efforts!
- I've check INTEN. only RX Fifo level interrupt is enabled (INTEN = 0b1000).
- I tried to clean the RX interrupt by setting the third bit in INT_STS. For some reason it remains 1. I even tried to clear all interrupts but it didn't help. What could be the reason for that?
- In order to set the perfect filtering mode, the following bits in MACCR were cleared at smsc initialization: MCPAS (19), PRMS (18), INVFILT (17), HO (15), HPFILT (13). MACCR = 0x1000000C.
- In two cases I stop receiving too many RX data: When setting BCAST in MACCR or when setting RX level to FF (i.e. setting FIFOINT to 0xFFFFFFFF).
- I've checked MACADDRH and MACADDRL and they seem to be correct.
If you have additional ideas of what could be wrong, I'll be very glad to hear.
Implementing prvEMACDeferredInterruptHandlerTaskPosted by heinbali01 on January 8, 2017 Hi Orit,
I've check INTEN. only RX Fifo level interrupt is enabled (INTEN = 0x1000).
Setting 0x1000 would set bit 12, which is marked as reserved and RO. Did you mean INT_EN = b'00001000' or 0x08 ?
I tried to clean the RX interrupt by setting the third bit in INT_STS.
For some reason it remains 1. I even tried to clear all interrupts but
it didn't help. What could be the reason for that?
That is unexpected.
What happens if within the interrupt you clear INT_EN bit 3, and re-enable the same bit from within the task, after emptying the RX FIFO?
In order to set the perfect filtering mode, the following bits in MACCR were
cleared at smsc initialisation: MCPAS (19), PRMS (18), INVFILT (17), HO (15),
HPFILT (13). MACCR = 0x10 00 00 0C.
Did you set bit 28 your self? It is described as reserved.
I would set bit 23: "Disable Receive Own (RCVOWN)", if not you will receive your own packets as well.
Later on, you might want to set Pass All Multicast (MCPAS) , in case you want to enable LLMNR protocol.
In two cases I stop receiving too many RX data: When setting BCAST
in MACCR or when setting RX level to FF (i.e. setting FIFOINT to 0xFFFFFFFF).
With 0xFFFFFFFF you would be writing 1's to reserved bits, which is normally 'not done'.
Wouldn't you set it to e.g. 0x48000030 ?
'0x30' or 48 bytes is assumed to be a minimum frame length.
What I can not find is: how do you know when a received frame is complete?
If you have additional ideas of what could be wrong, I'll be very glad to hear.
BCAST disables broadcast. Can you check the following: run WireShark on your laptop, connected to the same LAN, and see if there is an abundant amount of broadcast messages. These messages have the MAC address ff:ff:ff:ff:ff:ff as a target.
UDP broadcast messages can be quite disturbing for small embedded applications. Solution: filter them as soon as possible, preferably in the 'deferred interrupt handler task'. The function xPortHasUDPSocket() tells whether a UDP port number is bound to a socket.
Implementing prvEMACDeferredInterruptHandlerTaskPosted by orifai01 on January 9, 2017 Hi Hein,
1. Thanks. I ment 0b1000.
2. Apparently this behavior caused by packets accumulation in TX FIFO. I let it run + changed FIFOINT to 0x4800000C ( 12 dwords, 48 bytes, as the length is specify in dwords).
3. I've changed MACCR to 0x90000C (disable receive own, disable heartbeat, enable xmit and enable receiver) and I've added xPortHasUDPSocket() to task function as you advised. Thank you very much!
As you mentioned, interrupt shall occur when a full packet is received. I thought maybe "Magic Packet Detection" would fit but it detects reception of a specific pattern. I continue to investigate...
Implementing prvEMACDeferredInterruptHandlerTaskPosted by orifai01 on January 10, 2017 I found the solution. RX Status level represents the number of words in RX status (not in RX data), so it is actually represents the number of received packets. Changed RX Status level to 0.
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.
|