Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem TCP & FAT




Loading

Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by glenenglish on August 17, 2016

HI I wonder if there is a method, or preferred method for dealing with access to the network device. I am using a SPI device, and there needs to be mutex style behaviour between the HandlerTask prvEMACHandlerTask and whoever calls xNetworkInterfaceOutput. ANy light on this would be useful. Just using a mutex around the access sections would be dangerous- priority inversion I am sure would reign. it would get stuck. regards glen english


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by rtel on August 17, 2016

The best method might be to ensure only one task accesses the SPI bus, so no mutual exclusion is required, effectively handling sending and receiving data across the SPI bus from a single task. Alternatively, if you have only one sender and one receiver a simple mutex might be the simplest way, as with only one sender and one receiver it would be easy to manage (you can prioritise the sender over the receiver to prevent too many packets being queued for Tx at any one time).

Can you describe how you have allocated sending and receiving data to tasks and interrupts?

For example....

Sending:

xNetworkInterfaceOutput() should only ever be called from the IP task itself (correct me if I'm wrong!), and not application tasks, so you don't need to worry about that part.

xNetworkInterfaceOutput() will initiate an SPI communication - and then presumably the actual data transfer will be handled by an interrupt or DMA.

Does anything else in your application send data to the network? For example, could an interrupt generated when one packet has been sent initiate the sending of the next packet?

Receiving:

Presumably there is only one place in your code that is receiving packets over the SPI, then sending the received packets to the IP task for processing. Where is this being done? For example, do you create a task that is triggered by an interrupt when new data arrives, and have the task manage the reception of the data?


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by richard_damon on August 17, 2016

When I have a controller that is used by multiple tasks, because it is used to talk to multiple 'devices' (like a multi-channel SPI or I2C bus), then I find the best option is normally to just use a mutex in the code for the controller so which ever task is using it to talk to their device will have exclusive access to that device for the period of the transaction.

Yes, you do get an inversion issue if a low priority task is doing a transaction when a high priority device wants to do an operation, but this is fundamental to your archicecture. The mutex will assure that when the transaction finishes, the highest priority operation will be the one that starts.

A shared resource mrrding atomic operations (the controller) used by multiple users inherentlyy has the inversion problem, since, at least in general, we need to let the current operation complete before you can start the next. If this causes unacceptable delays, then you some measure to mitigate. Some options:

1) Make the low priority operation use small operations to minimize the latency imposed on the high priority task. 2) Implement some way to allow the high priority operation to 'abort' the low priority operation (this may or may not be possible) 3) Have the low priority operations 'get permission' from the high priority operations that the 'coast is clear' to access the channel, for example some sort of flag to indicate that no high priority operation is expected in the near future, allowing the low priority operation to proceed. This is inherently somewhat domain specific.


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by glenenglish on August 17, 2016

Hi All Yeah it's a problem (multiple access of peripherals) I am well familar with. Just wondered what was suggested in FreeRTOS+TCP land. Given that prvEMACHandlerTask could be responding to interrupts (and working the SPI) ( and remember that prvEMACHandlerTask offloads it to IPTask when it can got it) , the SPI must be guarded.

I did try a mutex when I considered the problem right in the beginning, but it got stuck, so I will need to understand the scheduler a bit better. There are a few other syncronization primatives I can use also that work a little different. Other flavors of semaphores etc used as resource counters. But they are usually 'backward to what I want" (they unblock >0). (but I could just use them backwards)

Yeah there will be an HTTP server for one client only (TCP) , and a bunch of fast UDP bidirectional traffic (approx 500 pps full to the brim) . Gratuitous broadcasts are really the scurge of networks..

with thanks

glen


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by rtel on August 17, 2016

A mutex should not get 'stuck' - are you sure you didn't get stuck in a configASSERT() failing? Which would happen if, as an example, you used the mutex from inside an interrupt.


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by glenenglish on August 17, 2016

Hi Working now with original MUTEX. was getting itself tied up in knots elsehwre and had both tasks unable to run.... No, not in a ASSERT loop, somewhere in the scheduler though, can't remember exactly where. Which I had written that down...It was in xQueueGenericReceive and it was there every time I stopped the processor. There is only right now the idle, the IP task and the prvEMACHandlerTask.

The FreeRTOS really is sensational. I am very impressed with its engine room. Also, the +TCP is well written easy to understand , also. (unlike LwIP) .

Well, if anyone is interested, now I have a working driver / ntegration using the ASIX 88796C chip. ip4, ip6, 40 Mbps SPI......quite a good chip used for a couple of years, very solid

Gimme a month and I will do some doco and post it publicly.

Need to spend more time reading/ studying the scheduler and interrupt priority variations.

cheers PS ah ha

here is where it fails configASSERT( pxTCB == pxCurrentTCB ); line 3529 tasks.c

        see below next post

Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by glenenglish on August 17, 2016

here is where it fails if it is worked a bit more (not really hard, though- I will drive some pins and see how busy it is in IDLE. putLEDs on it. Nope not very busy at all.

this is more sinister.

configASSERT( pxTCB == pxCurrentTCB ); line 3529 tasks.c in "xTaskPriorityDisinherit () " Somethign for me to look for on the weekend when I am back. pxTCB (the mutex holder)
Task : IP-task (currentTCB is EMAC) MutexsHeld : 1 priority 1 base priority : 1 eNotifystate : eNotWaitingNotification

I'll have a look at this later. I need to make sure , double sure and triple sure that the interrupt cannot occur while it is being (deferred serviced)

It is possible that the interrupt could occur that (would usually) unblock the thread (prvEMACHandlerTask) and also generates a Yield from ISR while that segment is holding onto the mutex.

Now, I removed YieldFrom ISR and it still happened.

So , in prvEMACHandlerTask , I moved where the interrupts get unmasked outside where the mutex is given up. Nup stil happens.

ahhh this time , config-assert at the same location, but pxTCB (the mutex holder) == EMAC Task :EMAC (currentTCB is IP-task) MutexsHeld : 1 priority 6 base priority : 6 eNotifystate : eNotWaitingNotification

anyway, it's after midnight. more news in a couple of days

cheers


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by rtel on August 17, 2016

configASSERT( pxTCB == pxCurrentTCB ); line 3529 tasks.c in "xTaskPriorityDisinherit () "

Asserts are placed to stop mutexes being used in interrupts, because, due to the priority inheritance, mutexes (unlike other types of semaphores) are associated with tasks.

If this is what you are doing then there is a work around I keep meaning to document....which I could describe here.


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by glenenglish on August 17, 2016

Although, the mutex is not being used in an interrupt. Although it is ASSOCIATED....

Here is the code segment, (simplified)

void EXTI3IRQHandler(void) /* handle packet or link change interrupt */ ~~~ { //LED2ON; EXTI->PR|=(1<<3);/* clear the pending interrupt / xSemaphoreGiveFromISR(AsixTaskSemaphore,NULL); //LED2_OFF; / option for faster attention */ #if 1 portYIELDFROMISR(pdTRUE); #endif } ~~~

then ....~~~

~~~ void prvEMACHandlerTask( void pvParameters ) / own task / { AsixTaskSemaphore = xSemaphoreCreateBinary(); AsixSPIMutex = xSemaphoreCreateMutex(); EXTI->IMR |= 1 << IOASTIRQBIT; /unmask ext interrupts */

for (;;) { if (xSemaphoreTake(AsixTaskSemaphore,0)==pdPASS ) {

        /* proceed through the SPI guard */
		xSemaphoreTake(AsixSPIMutex,0);
        ASIXWriteReg(ASIXREG_IMR, IMR_MASK_MASKED);	
        prvNetworkInterfaceInput();/* get packets */
        xSemaphoreGive(AsixSPIMutex);
        ASIXWriteReg(ASIXREG_IMR, IMR_MASK_NORMAL);/* permit interrupts*/
       }
}

} ~~~ ~~~

and also :

~~~ ~~~ xNetworkInterfaceOutput( () {/* belongs to IP TASK it seems */ xSemaphoreTake(AsixSPIMutex,0); result=SendPkt((uint8_t *) pxDescriptor->pucEthernetBuffer, ulTransmitSize); xSemaphoreGive(AsixSPIMutex);

} ~~~ ~~~

etc etc


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by glenenglish on August 17, 2016

It actually blows up here now, - ALWAYS !!!

in IP-Task..NetworkInterfaceOut xSemaphoreTake(AsixSPIMutex,0); result=SendPkt((uint8_t *) pxDescriptor->pucEthernetBuffer, ulTransmitSize); xSemaphoreGive(AsixSPIMutex);

call Stack

~~~ IPTask() HandleEthernetPacket ProcessEthernetPacket ReturnEthernetFrame NetworkInterfaceOut { xSemaphoreTake(AsixSPIMutex,0); result=SendPkt((uint8_t ) pxDescriptor->pucEthernetBuffer, ulTransmitSize); xSemaphoreGive(AsixSPIMutex); which calls .....xQueueGenericSend prvCopyDataToQueue xTaskPriorityDisinherit in ** bang ** ~~~


These tests are only ICMP pings at 20ms rate. More scope probes required, more understanding required.

It seems there are plenty of bullets left in my revolver to solve this one- I am by no means stuck. Still nice to have some people to comment. discuss with. comments are appreciated.

What I am not familiar with (after only 2 days with freertos) is the scheduler, the internals etc which, in time I will get to know.

I'll attach some LEDS to interrupt handler, and another LED around the mutex in EMAChandler and another LED around the mutex in the networkout and see what the concurrency is .

cheers


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by richard_damon on August 18, 2016

You ca Take on the mutex with a delay of 0, so the take will always immediately return, and indicate success or failure via its return value that you are ignoring. If the take fails you do the operation anyway and then try to give the mutex (which you don't have) back, causing the assert.

You could make the wait be 'forever' so it will always succeed, or test the return value of the take and decide what to do if the device is busy right now.


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by heinbali01 on August 18, 2016

Hi Glen,

Very glad to hear that you are developing a +TCP driver for the ASIX 88796C chip.

You mention "ip4, ip6"? Is that IPv6? +TCP will be extended soon with IPv6. If anyone is interested in testing it, please let it know.

Sorry to drop in so late in this discussion.

When you write :

xSemaphoreTake(AsixSPIMutex,0);
result=SendPkt((uint8_t *) pxDescriptor->pucEthernetBuffer, ulTransmitSize);
xSemaphoreGive(AsixSPIMutex);

Is that symbolically? I hope you always test the outcome of xSemaphoreTake()?

One thing is clear: xNetworkInterfaceOutput() will only be called from the IP-task.

Do you want xNetworkInterfaceOutput() to wait for the SPI-transfer to be finished?

Beside sending there is a second thing to do: use the same SPI-bus to receive messages. It is custom in +TCP to create an extra task called prvEMACHandlerTask(). It is a "Deferred Interrupt Handler", it handles events that were detected from within some ISR. The ISR may be triggered by the EMAC, the PHY or the DMA or a SPI controller. If any of the devices need attention, it will vTaskNotifyGiveFromISR() the prvEMACHandlerTask().

If I were you, I would let prvEMACHandlerTask() send all packets to the EMAC! You stop using the couple:

vTaskNotifyGiveFromISR();
ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );

and you start using :

xQueueSendFromISR ();
xQueueReceive();

Now xNetworkInterfaceOutput() will just forward the NetworkBuffer to the prvEMACHandlerTask() by calling xQueueSend().

Make sure FreeRTOSIPConfig.h contains :

~~~~ #define ipconfigZEROCOPYTX_DRIVER 1 ~~~~

Now when the IP-task sends a packet, the parameter bReleaseAfterSend will always be true:

~~~~ BaseTypet xNetworkInterfaceOutput( NetworkBufferDescriptort * const pxDescriptor, BaseType_t bReleaseAfterSend ) ~~~~

bReleaseAfterSend == pdTRUE means that the Network Buffer must be released by you, failing to release it would cause a memory leak.

bReleaseAfterSend == pdFALSE means that the Network Buffer may not be released and that the driver can only temporarily inspect it. After returning from xNetworkInterfaceOutput(), the contents of the Network Buffer may change.

So when ipconfigZERO_COPY_TX_DRIVER == 1, your driver will own the NetworkBuffer and it can forward them to the prvEMACHandlerTask(), who will send them.

Within prvEMACHandlerTask() you will check many things:

● Reception of packets ● Sending of packets (from the queue) ● Check the Link Status of the PHY ● Check and report any errors

If you want to implement this suggestion, please have a look at FreeRTOS_IP_Private.h for the definition of eIPEvent_t and IPStackEvent_t. You can make some equivalent enum and struct for your prvEMACHandlerTask().

Advantages: no more problems with priority inversion. You will never hold-up the IP-task while waiting for the SPI bus. Within prvEMACHandlerTask() you can easily decide which direction gets priority: TX or RX. You can let this depend on the actual working load.

If you have more questions, don't hesitate to shoot!

Good luck


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by glenenglish on August 18, 2016

Hi Richard My code segment was simplified - IE not showing the processing of the result = ..... I always check the result.

Umm doesnt Take with 0 specified wait forever (ie no timeout) ?

OH I just read it

" If tick wait is zero, the semaphore will return immediately" ooops ! My bad.

thanks for the pointer.

actually in NetworkOutput I was NOT checking the result- using timeout of ZERO I had assumed wait forever.

AHHHH so I am running right through that stop sign ! and probably then doing a GIVE when I never really TOOK . '

OK I see there is

right.... RTFM... read the f**ing manual I say to myself.

cheers


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by heinbali01 on August 18, 2016

Hi Richard

It was Hein pointing that out, not Richard :-)

I think that when usingportMAX_DELAY you also want to define:

~~~~

define INCLUDE_vTaskSuspend 1

~~~~

Here is some more text to keep you busy:

If you are sharing the same SPI-bus with other devices apart from the EMAC, it would be nicer to share it properly using a Mutex.

If the SPI-bus only serves the EMAC, I would give prvEMACHandlerTask() exclusive access to it.

For +TCP projects, it is beneficial to assign the following task priorities:

~~~~ /* highest */

prvEMACHandlerTask();
prvIPTask();

/* tasks that use +TCP */

prvIdleTask();

/* lowest */

~~~~

prvEMACHandlerTask() normally uses very little CPU-time: it starts and stops DMA or SPI transactions and it'll poll a PHY. In order to avoid an overflow of the reception buffers, it wants a high priority.

prvIPTask() typically has more work to do: it handles incoming packets and it prepares all outgoing traffic: TCP ACK's and data packets. If your EMAC can handle all checksums, that is great. Calculating CRC's in software, although heavily optimised, takes more CPU time.

User tasks that use +TCP: if given a lower priority, it'll mean that sendto() and send() will normally work immediately. There won't be much queuing of packets, because the IP-task will have a higher priority and deliver each packet upon request.

Regards.


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by glenenglish on August 18, 2016

Hi Hein Thanks very much for the information and your time to write.

Given that there is only one SPI device on this bus (it's not like I am sharing the one SPI between say a temperature sensor, and other sensors with different chip-selects) it really makes no sense for me to do what I am doing. (apart from that it is convenient). IE what I am doing is dumb but it grew that way because of the 'template'.

To change what NetworkOutput (that runs in IPTask) does I think that where I currently send a packet , I can instead, signal the EMACS thread that there is something to send , and post it the txdescriptor soemhow . Then, it can wait. Then, when EMACS has finished with the buffer, EMACS can signal IPtask (that is blocked) that it is done with the buffer and it can continue. Or I can free the buffer from the EMACS thread etc. a few options I will investigate. INetworkOutput does not wait (IE it just signals EMACS with the buffer descriptor # or ptr) then it can go about what it was doing, something else. The only requirement for that to work is to have EMACS thread waiting on both the IRQnotify or the NetworkOutput notify. Like WaitForMultipleObjects in win32 land. I did read somewhere there is a facility to wait on multiple objects. This way , only one thread needs to deal with the SPI. much better ! { which was of course the original suggestion :- ) }

cheers


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by heinbali01 on August 18, 2016

A short response now:

When xNetworkInterfaceOutput() returns, the packet has been queued to be sent by the EMAC task. You don't have to wait for that to happen, you can just return:

~~~~ BaseTypet xNetworkInterfaceOutput( NetworkBufferDescriptort * const pxDescriptor, BaseTypet bReleaseAfterSend ) { EMACEventt xEvent;

/* if ipconfigZERO_COPY_TX_DRIVER == 1 then
bReleaseAfterSend will be true. */
configASSERT( bReleaseAfterSend != pdFALSE );
configASSERT( xEMACEventQueue != NULL );

xEvent.pxDescriptor = pxDescriptor;
xEvent.eEventType = eEMACTxEvent;
xQueueSendToBack( xEMACEventQueue, &xEvent );

return 0;	/* Return value is actually ignored. */

}

~~~~


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by glenenglish on August 18, 2016

Hi Hein Yeah. I see what you mean (looking at the freertos+TCP code) I don't really have to wait, I can just dispatch the descriptor. Freeing the descriptor buffer (once i have used the data) can be done in emacs.

nice to have imbuilt queues. Something else taken care of for me. Off for 1.5 days interstate.

cheers


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by joehinkle on August 18, 2016

Glen:

May I offer my 2 cents as someone who has just gone thru the process of implementing a driver.

Use a binary semaphore to tell who has the spi bus: Either Xmit opperations or Rcv operations.

Use a task to process received messages. Make the priority of this task higher than the IP task priority.

When you receive a RCV interrupt, use xTaskNotifyFromISR to wake up the RCV task (may not be able to actually run if the Xmit operation has the SPI semaphore.

Make sure you set ipconfigZEROCOPYTX_DRIVER to one in your FreeRTOSIPConfig file. This will allow you to return from xNetworkInterfaceOutput() prior to actually completing the xmit operation.

In xNetworkInterfaceOutput() get the SPI semaphore. This will lock out the RCV task. If you are using interrupts to manage you spi transfer - start the transfer and return. This will allow the stack to continue operating -- but NOT to receive any new messages.

In the xmit complete interrupt, vNetworkBufferReleaseFromISR() to release the buffer and xSemaphoreGiveFromISR() to give back the spi semaphore.

In your RCV task ... use:

xSemaphoreTake(SPIGateSemaphore, portMAXDELAY);

You will now wait until Xmit operations are completed. Once you have the semaphore and are processing received messages, the IP task can not run because its of lower priority so there is no concern about xNetworkInterfaceOutput() being called.

When done with all the processing of received messages in the RCV task, give the semaphore back and wait for the RCV interrupt to wake you again. The IP task will most likely start running and now has access to the SPI semaphore via xNetworkInterfaceOutput().

The most important thing (to me) is the use of the ipconfigZEROCOPYTX_DRIVER set to 1.

This allows you to return from xNetworkInterfaceOutput() while your spi transmits in the background.

if ipconfigZEROCOPYTX_DRIVER is set to 0 AND xReleaseAfterSend is FALSE in the call to xNetworkInterfaceOutput() then you MUST NOT return until xmit is complete (unless you copy the message to another buffer and xmit out of it -- but that's just a waste of time and memory).

Hope that helps.

Joe


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by heinbali01 on August 18, 2016

In xNetworkInterfaceOutput() get the SPI semaphore. This will lock out the RCV task. If you are using interrupts to manage you spi transfer - start the transfer and return. This will allow the stack to continue operating -- but NOT to receive any new messages.

Joe, thanks for your input.

I wouldn't advice to use an SPI semaphore for this reason: if the SPI bus is busy, it would hold-up the IP-task. I would rather pass the Network Buffer to the EMAC task and let that task work on it. And therefore, I would replace the task-notify mechanism with the a working queue to wake up the EMAC task.


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by joehinkle on August 18, 2016

From what I understand of who has access to Glen's spi, there are only two (2) users. IP task for xmit and RCV task for receiving.

if ipconfigZEROCOPYTXDRIVER == 0 and xReleaseAfterSend == FALSE, you are going to stall the IP task no matter what. if ipconfigZEROCOPYTXDRIVER == 1, the IP task can keep running until it attempts to xmit again and then stall if the transmit operation is still active.

I personally would keep the xmit and rcv processes seperate (not have them in the RCV task). To me -- it keeps responsibilities clear a seperate. The SPI semaphore manages who runs based on hightest priority at the time SPI access is needed.


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by heinbali01 on August 18, 2016

if ipconfigZEROCOPYTX_DRIVER == 1, the IP task can keep running until it attempts to xmit again and then stall if the transmit operation is still active.

I don;t think so. Suppose that the IP-task wants to send a new packet while the first one hasn't been delivered yet, the new packet will stay in the EMAC working queue. This queue serves as a buffer between the two tasks.

Performance-wise, I think it is important that the IP-task keeps on working also when the (relatively slow) SPI bus is busy. In a high-volume TCP conversation, the IP-task has a lot of work to do.


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by joehinkle on August 18, 2016

I agree with you if stack processing is a major application concern.

I don't think there is one right answer, it comes down to what are the requirements of the application.

Queueing keeps the IP stack processing as fast as possible -- trade off is more memory usage for queues and more code complexity.

I was biased in my previous statement as I did NOT implement a SPI interface - I was interfacing directly with a ENET -- so my time delay was very small. SPI delay for xmit could be VERY long in comparison.


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by glenenglish on August 20, 2016

thanks all for the input.

My perspective is that IPTask should be busy preparing and processing packets. someone else should do the waiting. - IE in this case another thread or threads. Given that there is only one device attachment facility, if you will , IE the SPI bus, in this application, it makes sense for the EMACS task to wait on either rx interrupt OR wait new descriptor available for sending, one or the other since it can only do one or the other.

The only thing that should stop IPTask would be if there is no free buffers to do anything with. If EMACS runs out of buffers to put stuff, it still has to read and dump the packet in the ethernet chip buffers, and then it can just dump it. And of course IPTask waiting on the SPI makes the situation WORSE because the way to free up buffers is for IPTask to process receive packets- which eventually freesup the buffer.

If there are no buffers for assembling a new packet, that of course goes back to the caller and fails the send.

Now, what I DO need to look through the code is to figure out what happens in the case that the interruot handler YieldFromISR() executes but the 'target thread' in this case, EMACS, is NOT waiting- busy doing something else. I'll look at the source code and trace that one through. My feeling is that if YieldFrom ISR executes and the target thread is not blocked, then Yield from ISR should do nothing..

YieldFromISR is a very effective and handy feature in FreeRTOS. I was quite impressed when I read the feature.

see, I have 500 pps of 1kB size going in and out , (in addition to the dsp work) and the buffers are fairly small so there is little time to waste, IE my implementation needs to be efficient.

The SPI DMA timing is much tighter. (the push is on for latency also so I am just using the double-buffer feature in the STM, am not chaining say 8 buffers) ...I could probably get away with not using YieldFromISR on the ethernet IRQhandler, but on the SPI DMA completion handler, yield forn ISR is VERY handing at meeting the very strict SPI buffer deadline.

cheers


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by heinbali01 on August 20, 2016

The only thing that should stop IPTask would be if there is no free buffers to do anything with.

In the example drivers, the number of available Network Buffers is monitored and logged when it drops.

You could add a rule, e.g. stop using Network Buffers when the number drops below e.g. 3.

When the IP-task finds that there are no more Network Buffers, it will give up and wait for the next thing to do.

My feeling is that if YieldFrom ISR executes and the target thread is not blocked, then Yield from ISR should do nothing..

~~~~ void MYISR() { BaseTypet xSwitchRequired = pdFALSE;

/* Check the interrupt status. clear the necessary flags. */
xQueueSendFromISR( xQueue, &( xItem ), &( xSwitchRequired ) );
portEND_SWITCHING_ISR( xSwitchRequired );	/* formerly called portYIELD_FROM_ISR() *

} ~~~~

Sounds correct to me. If the ISR calls e.g. xQueueSendFromISR (), this might unblock your prvEMACHandlerTask(). But if that task was already in a non-blocked state, it will just carry on. The next call to xQueueReceive() will succeed without blocking.

Your prvEMACHandlerTask() will always do very short transactions and therefore I would give it a high priority. The latency between calling portEND_SWITCHING_ISR() and the unblocking of the task is very small.

Using two alternating SPI buffers sounds good.

Regards.


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by glenenglish on August 20, 2016

Hi Hein. agreed on all your comments.

I implemented a QueueSet

Queue Length of 1 for the BinarySemaphore from the ISR and Queue length of nbuffer descriptors (maybe need to think about that more) for the NetworkOutput thread. NetworkOutputThread posts a type containing the Descriptor and the bReleaseAfterSend items and returns immediately to IPTask main.

The EMACS-task waits on the QueueSet,

I could have implemented as a single queue, but then it is possible that the IRQ handler might be way down the queue if NetworkOutput pushed alot of sends into the queue... I want the irq handler semaphore to be handled next iteration, so the queue set is better for that.

It worked first go. (took about an hour) . seems to be solid. I'll have a look at the YieldFromISR rtos code. cheers


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by heinbali01 on August 20, 2016

I implemented a QueueSet

I'm not sure if that is useful / necessary.

I thought of a single working queue with each element having the size of the struct EMACEvent_t:

For example:

~~~~ typedef enum { eEMACSendPacket, eEMACCheckPHY, eEMACTXDone, eEMACRXDone, ... } eEMACEvent_t;

typedef struct { eEMACEventt eEventType; void *pxData; } EMACEventt; ~~~~

So for every event, 8 bytes will be queued. The field pxData may point to a Network Buffer or remain NULL if not in use.

The boolean parameter bReleaseAfterSend will always be pdTRUE if you define :

~~~~ #define ipconfigZEROCOPYTX_DRIVER 1 ~~~~

So xNetworkInterfaceOutput() can be implemented as I described here above. Just queue the Network Buffer.

a single queue, but then it is possible that the IRQ handler might be way down the queue if NetworkOutput pushed alot of sends into the queue

There is an alternative: you can define:

~~~~ #define ipconfigUSELINKEDRX_MESSAGES 1 ~~~~

It will add a pxNextBuffer pointer to each Network Buffer ( see include/FreeRTOS_IP.h ).

Now suppose that you receive a mix of ISR-events and packets to be sent:

You can put the packets together (link them) by setting the pxNextBuffer field:

~~~~ switch( xMsg.eEventType ) { case eEMACSendPacket: { NetworkBufferDescriptort * pxNew = ( NetworkBufferDescriptort * ) xMsg.pxData; pxNew->pxNextBuffer = NULL; if( pxFirst == NULL ) { pxFirst = pxNew; } if( pxLast != NULL ) { pxLast->pxNextBuffer = pxNew; } pxLast = pxNew; } break; case eEMACCheckPHY: ... ~~~~

In that way you can empty the working queue each time the task wakes up.

If you want you can also write me directly ( h point tibosch at freertos point org ), then maybe we can go quicker through all this. And I'm not sure if all these implementation details are interesting for everyone :-)


Controlling network driver access between prvEMACHandlerTask and xNetworkInterfaceOutput

Posted by glenenglish on August 20, 2016

Hi Hein Quite happy to keep it in forum if it is beneficial for someone doing similar and doing a search.

I'm very happy with the degree of assistnce you are providing.

OK on the ipconfigUSELINKEDRX_MESSAGES. I will read up.


Something on the queues, and similar sort of structures.... xQueueCreate() and xQueueCreateStatic()

The static version would be useful for fast access say out of TCM / or NON cached memory (instead of potentially causing a cache miss) - a nice function.


cheers


[ Back to the top ]    [ About FreeRTOS ]    [ Sitemap ]    [ ]




Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.

Latest News

FreeRTOS kernel V10 is available for immediate download. Now MIT licensed.


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

OpenRTOS and SafeRTOS