For debugging, pausing one task only, but gracefully

STM32 debugging, CubeMX environment.

I have an interrupt that loads a queue with data from an NRF24L01. That queue is read by another task.

I’d like to have the queue completely loaded before the packet assembly task starts. Placing a breakpoint in the packet assembly task stops the entire processor, of course.

Any way to create something (may not need to be a breakpoint) that would accomplish this gracefully?

I could set a memory variable, loop on that in the assembly task, then when the queue is full, change the variable manually, and thus continue the packet task. Seems awkward, though.

While I do know the end of the packet stream, and I could put a semaphore in there once received, pausing the assembly until that… that also seems perhaps a bit complicated.

I’d want to watch the complete assembly process once, but the NRF chip only has a 3 deep fifo for packets, the message is more than that.

Any thoughts about the utility of this? Should it be an added feature in FreeRTOS?

To be honest I don’t think this would be a very useful RTOS feature and worth the effort.
I’d probably use something as you suggested (spin-waiting for uxQueueSpacesAvailable going down to 0) if this is what you want to verify.

I’d be interested in why you think it’s not useful. Not enough similar situations? Infrequent use?

Well, if I got you right you want to simulate that a queue is getting full.
That’s usually no use case since a queue shouldn’t get full/overflow.

If you don’t want the receiving task to take items out of the queue until a “full” message is in it, perhaps the semaphore (or a similar direct-to-task notification) is what you want.

It does make me wonder if you really need the queue, or if you could just assemble the full message in a buffer then signal the sending. You would only need the queue if a second message might start coming in before the first is processed.

Oh, no, that’s somewhat the idea, but not all of it.

What I’m looking for is a method to pause only one task (as in a breakpoint), then gracefully resume that task.

What else I was talking about were various methods of implementing the effective result given the particular programming situation I’m in.

It’s not a queue getting full. Timing wise, it could be that queue becoming empty. However, that’s not a definitive event. The message is a header followed by tagged data blocks, and the last data block is tagged as an end.

To watch the entire “build message from packets” task, the easiest way is to pause the building while letting the queue stuffing continue. Hence the “pause one task”.

Breakpoints, of course, pause the entire machine. I can work around it, however.

I do want a feature in the system where packets can arrive at any time, being fed by different sources, and then execute. There is no full message (see below), since “process message” is defined by receiving an end packet (if building a block). Otherwise, the packet is tagged as an “only packet”.
These are all received packets. (NRF has a maximum size of 32 bytes, 16 bytes are used for routing, sequence, packet ID and checksum.) Since the packet comes in over a mesh network (worse case), I don’t guarantee anything but the first and last packet. (and I can fix the last packet problem).
As mentioned, I can work around this, but I was looking for an elegant solution that might be of use to others.

@richard-damon’s suggestion of assembling a packet in a buffer and then signal the receiver when the end packet is received, seems a reasonable solution to your problem. Does that work for you?

It likely can help. However, what I wanted to see was the process of putting the buffer together. At the end packet, I do an integrity check to see if all packets have arrived, then execute. His solution does not address that issue. Having the packet assembly task on hold, loading up the queue, then letting the packet task build the buffer was the idea.

Why so? Does the following pseudo code not address this -

void PacketProcessorTask( void * pvParams )
{
    Packet_t * pkt;
    for( ;; )
    {
        xQueueReceive( pktQueue, &( pkt ), portMAX_DELAY );

        /* Process packet. */

        /* Free the memory associated with packet. */
        vPortFree( pkt );
    }
}

Packet_t * g_pkt = NULL;

void PacketReceiverTask( void * pvParams )
{
    for( ;; )
    {
        /* Allocate memory for a packet. */
        if( g_pkt == NULL )
        {
            g_pkt = pvPortMalloc( sizeof( Packet_t ) );
        }

        /* Receive packet and keep assembling in g_pkt. */

        if( endPacket )
        {
            /* Do integrity checks. */

            /* Send the g_Pkt to the queue. */
            xQueueSend( pktQueue, &( g_pkt ), 0 );

            /* Ready to receive next packet. */
            g_pkt = NULL;
        }
    }
}

It both does and does not. There are some factors that prevent the solution from working as you’d think.

  1. what is sending the packet is a separate processor on another board. It sends a packet stream and cannot gracefully be stopped.
  2. the hardware that receives the packet is a separate subsystem, and while it has a FIFO, the depth is only 3 deep and the packet stream is 8 packets or so.
  3. the way the software currently works is that the RF packet (8 of them) trigger an interrupt, that interrupt handler loads the system queue.
  4. a separate task reads the system queue and builds the overall block data. It was that task I wanted to disable temporarily.
  5. once the block data is complete and verified, it is executed.

It looks as if you create a queue which contains the main block data, which by nature is variable length. That’s awkward at best.

Since this is a single core processor, I can’t attend to the incoming packet stream and keep it intact since breakpoints pause the entire system but not the packet source.

Where does it build that overall block of data? Can you share code? Why do you want to disable that task?

The queue does not contain the block of the data but a pointer to it (hence alloc and free). What is awkward?

Breakpoint is a debugging mechanism - are you trying to debug something or are you looking to solve a problem?

I have an entire system that works as follows:

  1. assign a device (display, led, etc) at the system level. The location is either on board or off board. If off board, the interface is specified and the node address on that network (NRF mesh) is specified.
  2. call a system handler to access that device. For an LED, for instance, one data packet (16 bytes available) is sufficient. For a display, considering the complexity of the instructions for the graphics object to be drawn, about 140 bytes.
  3. depending on the location of the device, the on board drivers are either accessed, or the block data/data is packetized and put on a main system queue.
  4. the main system queue is read by a task (the one I wish to pause). It is either (at the destination), used to rebuild the block/data or the packet is forwarded to another node up or down the network tree.
  5. for an incoming packet through the NRF network, the packet is either forwarded with address adjustments up or down the network, or if the packet has reached the destination, it is placed on the system queue.
  6. As an option, any packet, even if locally generated and used, can be placed on the main system queue. This effectively simulates a packet arriving over the mesh network and at the proper destination. Because of the use of a queue, and packetizing data, it’s slower.
  7. what I wanted to do is monitor, packet by packet, the assembly of that packet. It’s easy to monitor the execution of the packet data, but building is another matter since I’m dealing with asynchronous systems.

Next: I don’t do queues with pointers to data, just don’t like it.

Lastly: I’m trying to debug something, and noting an awkwardness in FreeRTOS (stopping an individual task, the system queue reader). I have ways to work around not being able to do that in FreeRTOS, but I was suggesting a feature and trying to illustrate a reason why this might be useful.

The problem is that IMHO, FreeRTOS could be missing a feature. It would be nice to click on the task view window and individually disable a task. That would solve the problem in this case. As I mentioned, here are ways to get around this lack of feature, but they are workarounds.

Thank you for the details - I get your ask now. The feature of clicking a task in task view window and disable it, would need to be implemented in the debugger and if you are using STM32Cude IDE, I’d suggest to post this request to ST forums.

This is interesting and could certainly be done with a tight integration of debugger and scheduler. However it sounds like a specific use-case. In my past when debugging things with many parallel actions (generally interrupts). Even breakpoints become less useful because the real-world events (usually timers) are still running and the embedded system is no longer controlling them.

One memorable occasion we started a fire on an engineers desk by stopping a UPS at a breakpoint while the inverter was running. The PWM output to the transistors stopped and without a current limit (running on a battery) the transistors immediately popped and caught fire.

A typical system level debugger just can’t do what you want, as at the system/cpu level, “Tasks” don’t exist, they are just the creation of the program, via a library it is using, namely FreeRTOS.

If you want to do this sort of stepping inside an application, that also keeps the rest of the system running, you will need to build an APPLICATION level debugger. It likely has a seperate task to allow you to enter operations while the task being debugged is running, but it also can set breakpoints within the task to let you single step the task, while the rest of the system is running.

Yes, something like this could be useful to a number of people, and might make an interesting FreeRTOS Plus project, one issue is that parts of it will be VERY processor specific (how to set a breakpoint, and step/resume the task), and application specific (where to get commands/print results).

I’ll ask for that specific implementation. However, I suspect that some FreeRTOS work is needed as well to make it a graceful solution.

Agreed on the tight coupling of debugger and scheduler. That would be the most convenient way. In this case, the breakpoints disable the timers, so I need not worry about the PWM failing (and who designed it so that a software crash could destroy the unit? I’d have thrown enough hardware at it to keep that from happening.

DO know the breakpoint problem, which is why I asked for a pause on a specific task (however implemented) rather than the entire system. I do have ideas, see next post please.

This I know, and so it is why I was suggesting a FreeRTOS feature. Even a call to a routine that gracefully pauses a task would help, since that can be enabled/disabled. My thought would be to access the task block to put it on pause. Not graceful, but could give a hook for later development.

I’ll have to look to see what I can do for an applications level debugger, but the way things are going, it would have to be a separate piece of hardware. I’m still working on the basics.

As to processor specific, yes, very specific if you want to do this at the processor level. I’d want to avoid that and deal with it at the OS level, which is where it needs to be. As to application specific, I’d think that the same system you use to add trace points might be quite adaptable to this. The implementation of how to do this is hardware specific, though. Then again, so are trace points.

A second thought, serial port and superuser mode? or the equivalent…

For expert use there is vTaskSuspend.
Why expert use (in my opinion at least) ?
It’s critical regarding race conditions and because it’s asynchronous (when used by an other task) and suspending a suspended tasks does nothing and the same applies to resume.
But … it might be helpful for special purposes.