Task stack - user stack, or interrupt stack (Renesas RX MCU)

leesp wrote on Sunday, August 11, 2019:

I am a user of Renesas RX MCU, which has a Interrupt Stack pointer, and User Stack Pointer. In a non-OS program, programmers have a choice of enabling User Stack. If:

  • User Stack is not enabled: then both function call and interrupt use Interrupt Stack
  • User Stack is enable: then normal function call uses User Stack, and interrrupt service rountine (and all subsequent function call before interrupt returns) uses Interrupt Stack

But how about the case of FreeRTOS for RX? I know that each task has a task stack. Does each task has a interrupt stack, or all tasks share a common interrupt stack, or there is no concept of user stack / interrupt stack?

I mean, while a task is executing, its stack is used when functions are called. But what happen if an interrupt happens? RX MCU hardware would push PC and PSW onto Interrupt Stack. Is this Interrupt Stack common to all tasks?

Or a more fundamental question: does FreeRTOS for RX use User Stack at all?

richard_damon wrote on Sunday, August 11, 2019:

My guess is that all the tasks would use a common ISR stack for interupts, there is no reason I can think of to have multiple ISR stacks that change for each task.

While it could have all the tasks use the ISR stack also, and ports for machines that don’t have a seperate ISR stack have to do the equivalent of that, On such a machine, when you change what task is running, you reload the stack pointer to point to the new tasks saved stack.

I would suspect that FreeRTOS would use the User Stack for tasks, and just change that user stack on task switches, as that means that each tasks doesn’t need to reserve space for the interupt stack in its stack frame.

I am not familiar with that port, so I am answering on general principles. The final answer would be in the port files for that processor.

leesp wrote on Sunday, August 11, 2019:

Thanks Richard. Let’s see if anybody familiar with RX ports would answer the question

I have another related question:

In a non-OS program (single thread) for RX, when an interrupt happens, hardware will push PC and PSW onto stack. Then CPU would start executing ISR routine and callback functions. Within the ISR routine, user code (or rather, codes added by compiler at the beginning of ISR) would push some CPU registers onto the stack as well - only those CPU registers which will be used eventually in the callback function, are pushed

Question: In FreeRTOS, does the context saving, push ALL registers (PC, PSW, r1, r2, … regardless…) onto stack?
I am trying to understand the difference in “interrupt context saving in a non-OS program” and “context saving while switching tasks in FreeRTOS program”… or does my question make sense at all?

rtel wrote on Sunday, August 11, 2019:

Take a look at the yield function in the RX port layer, I think the
comments in the code answer most of your questions:


leesp wrote on Tuesday, August 13, 2019:

Dear Richard,
Ok before I drill down to the code prvYieldHandler(), could you please confirm if my understanding below is correct?

Suppose there are two tasks, TaskA and TaskB. TaskB has higher priority but it is blocked waiting for an external interrupt (e.g button push to happen)
So while TaskA is running, and the button is pushed. So buttonPushedISR() would execute. I suppose in the ISR, it should also trigger a software interrupt (by calliing vPortYield or taskYield or something along that line), in order to request for context switch?
If the above is yes, then the software interrupt is actually nested within the button push interrupt, am I right?

rtel wrote on Tuesday, August 13, 2019:

The software interrupt should be the lowest priority so it executes after all nested interrupts have completed. That way multiple nested interrupts can request a context switch but only one actually occurs.

richard_damon wrote on Tuesday, August 13, 2019:

The ISR will do the yield to implement the task switch. Exactly how the task switch happens depends on the processor, but many use a software interrupt, which will be triggered in the interrupt context. On some processors, that software interrupt won’t actually happen until the ISR ends

leesp wrote on Friday, August 23, 2019:

Dear Richard Barry/Richard Damon,

Ok I have studied vPortYield() and prvYieldHandler(). Please confirm my understanding is correct:

  1. When timer tick interrupt happens, vTickISR() starts to run. Within vTickISR(),** software interrupt (SWINT) is requested, but it is pending** because it is of lower priority than timer tick interrupt
  2. Once vTickISR()** returns from interrupt**, software interrupt would execute immediately if there is no other higher priority interrupt. PC and PSW are pushed by hardware to Interrupt Stack
  3. vSoftwareInterruptISR() starts running, which calls prvYieldHandler(). The handler would copy PC, PSW from Interrupt Stack to Task Stack (the task which is being pre-empted now), and also it would push r1-r15 to Task Stack
  4. vSoftwareInterruptISR() would then restore context of the other higher priority task

rtel wrote on Friday, August 23, 2019:

Otherthan checking the source code again to see if the register pushes/pops performed by the hardware are right - yes understanding is right.

leesp wrote on Wednesday, September 04, 2019:

Thanks Richard. I understand the flow of vTickISR() and software interrupt

I have anothe related question which I asked earlier:
TaskA: lower priority, running
TaskB: higher priority, block waiting for an I/O interrupt (push button) to happen

I understand *briefly *the concept of deferred interrupt processing and also semaphore, but I cannot link the below:
Button pushed -> I/O interrupt runs -> ??? -> ??? …-> trigger S/W interrupt -> S/W interrupt running, switch context ->…

I suppose the ISR would give semaphore, but to who…, etc?

Thank you,

richard_damon wrote on Wednesday, September 04, 2019:

The ISR would call xSemaphoreGiveFromISR(), which puts the semaphore in the ‘given’ state (i.e. someone can now succeed in a xSemaphoreTake() operation. If the process of giving the semaphore wakes up a task at higner priority then currently running, it well set the word provided by the ‘wasWoken’ parameter. The ISR at its end tests this, and if it has been set, initiates the scheduler (often via a Software Interrupt, details of how this port does it should be documented in the port files for that processor).

You don’t give a semaphore to a particular task, but but various things give and take the semaphore, and the semaphore keeps track of its state (given/taken for a binary, or a given count for a counting semaphore) and the semaphore will block tasks that ask for something that it can’t do at the time (or return a error if the timeout is 0, like it will do to an ISR, since ISRs can’t block)

rtel wrote on Wednesday, September 04, 2019:

There are some examples in the [free to download] book available here:
https://www.freertos.org/Documentation - you will also find several code
examples on the website, such as here
using a task notification instead of a semaphore, and in the API docs,
and in the demo projects in the download.