New to RTOS tick implementation

samoia wrote on Monday, May 16, 2011:

Hello everyone

I am a new FreeRTOS and I am handling a porting project based on Microblaze port. When i start porting i removed some of the related references to the Microblaze. That includes the following functions: prvSetupTimerInterrupt, vTaskISRHandler and vTickISR.
i have basically disabled all the interrupts and i managed to run tasks and do a cooperative multitasking. For now, i want to move on to the preemptive multitasking. I have a timer and i can reset it as well as get the timer count. What should i do to those functions mentioned above to get my RTOS tick setup for preempting the execution of the tasks?

any suggestion or guidance is very much appreciated, Thanks

williamdavy wrote on Tuesday, May 17, 2011:

Hi Samoia,

Please have a look at one or other of the contributed ports for the Xilinx Mircoblaze. I wrote the updated port at the following link, updated to use 12.1 EDK and FreeRTOS v7.


samoia wrote on Tuesday, May 17, 2011:

Hi William

Thanks for your reply…
Running Microblaze port is not the problem that i face, i am not working using EDK and Xilinx boards.

I am porting Microblaze port for another processor and I am a beginner in this field especially in handling the interrupt.
My questions in another word are:
what should i do to get my timer set to generate the RTOS tick?
How do i write an interrupt handler to handle the RTOS tick event? (the timer is the only interrupt source)

sorry if my questions sound general, i just need some tips to start moving

williamdavy wrote on Tuesday, May 17, 2011:

Oddly I am just writing an RTOS tick now.

Are you using the XPS Timer module? Do you have an external interrupt controller?

Basically, you need to Save the Currently running Task’s Context (see portasm.s from the project I referenced) call the interrupt handler which is usually written in C, and then Restore the currently switched in Task’s Context.

When I say context, I mean all of the register values and anything else that effects the operating of the currently executing code. For the Microblaze, that means registers r1 through r31 and the MSR. The Currently executing task is always available via the pointer ‘pxCurrentTCB’. Typically, the stack of a task is decremented, all registers pushed onto the stack, and the stack pointer saved to the first element in pxCurrentTCB, the C ISR function called, and then the operation is done in reverse.

Within the Tick ISR Handler, you simply call vTaskIncrementTick() and vTaskSwitchContext(). vTaskSwitchContext() may change the value of pxCurrentTCB, hence switch tasks.

You should be able to adapt the code from portasm.s and port.c in the project that I referenced to handle the interrupt side of things. The code to control the Timer is specific to that type of Timer, but generally speaking you configure it to periodically generate an interrupt, automatically reloading the itself.

I hope that makes more sense, there is certainly a massive learning curve associated with this stuff.

samoia wrote on Wednesday, May 18, 2011:

Hi William :slight_smile:

Thanks for the reply… you cleared some doubts yet i still have some questions regarding the existing codes.

My processor has the same use of registers and stacks as the Microblaze so it is safe to use most of the codes in port.c and portasm.s.

About the interrupt handling, did you mean to use (__FreeRTOS_interrupt_handler) from portasm.s to handle the interrupt?
I see that it does what you mentioned about saving the context and branch to an ISR (in Microblaze case is the vTaskISRHandler) then restore the context. Am I correct?

From my executable file my _vector_interrupt has no handler registered yet. How do i register one ? And since i have only one source of interrupt that is from the timer, should i branch directly to vTickISR instead of vTaskISRHandler.

Finally about the timer, for my work i use verilog to simulate the hardware of the processor, which i did not write its code myself. However, I do have two functions from the timer library that allow me to get the value of the timer and also to set it. I don’t have a control status register for that timer. With such a timer, how can i get the RTOS tick?

I hope that I am not making non-sense with what I came out and  explained :stuck_out_tongue:

Thanks again for the time you are spending in replying me

williamdavy wrote on Wednesday, May 18, 2011:

Hi Samoia,

Yes, you are correct in using __FreeRTOS_interrupt_handler. When you refer to _vector_interrupt, I think that is satisfied when __FreeRTOS_interrupt_handler is copied into that address by the code at the beginning of xPortStartScheduler()?

You could branch directly to vTickISR instead of vTaskISRHandler. Are you using the XPS Interrupt Controller? If you are then you should branch to vTaskISRHandler because that handles acknowledging the interrupt and will allow you to install more interrupt sources in the future. If the Interrupt line from the Timer is literally connected straight to the interrupt line in the Microblaze then as long as the interrupt is cleared/acknowledged from the Timer, you can branch straight to the vTickISR().

Hmmm…. The Timer needs to be able to support functions that allow you to configure it to periodically generate and interrupt. The XPS Timer is loaded with the number of ticks to count before generating an interrupt, at which point it automatically reloads the same value and starts counting again. Technically, I think the load value is a negative number which counts up until it rolls over to 0, at which point it generates the interrupt. The number of ticks to count is calculated based on how fast the Timer ticks and the rate at which you want to interrupt the OS.

Without the ability to set-up your Timer in a similar way to the XPS Timer, you are going to struggle. The automatic reload is important because that is how you keep (relatively) accurate time. If you have to manually reload the Timer, your tick interrupt will almost always be slower than you expect. If your code is in a critical section when the Timer generates an interrupt, you will have a variable amount of time before you actually service that interrupt. In theory, if the Timer keeps ticking, you could simply subtract the time delayed from your new load value but that tends to be inherently inaccurate.

Alternatively, if you can modify the VHDL that controls the Timer, you could hardcode the hardware to generate the interrupt itself, with no software interaction at all. As long as it is at a fixed periodic rate that is suitable for the RTOS (1 to 1000Hz), then there is no reason why you can’t have a fixed hardware tick.

How are you keeping time in the RTOS at the moment? You say it is co-operative but for time to advance you still need to have the RTOS tick, unless you are manually checking the time and calling vTaskIncrementTick() for each tick that has passed, perhaps from the Idle hook?

samoia wrote on Monday, May 23, 2011:

Hi William

Sorry for my late reply.
I have clear picture of how the RTOS tick should work now. Thanks to you :slight_smile:

Now, i have my timer set to generate an interrupt every 32768 cycle (timer is connected straight to the interrupt line) and I was able to handle the interrupt using the __FreeRTOS_interrupt_handler and directly branch to vTickISR() after saving all the registers.

For the cooperative multitasking, i did not use the tick as i did not have a timer and interrupt handling at that moment of project increment. Instead, i explicitly called taskYIELD() within the tasks to do a manual context switching.

Now the current issue is, when i run the tasks with different priorities, the program does not execute the tasks and it returns back to my main even after calling vTaskStartScheduler(). However, when the tasks are sharing the same priority, they tern to have a time slice for each and the program returns to the main again and exit. What could cause this problem ?

How much timer counts are needed to generating the interrupt  for freertos to work properly? could this problem be caused the period that i set for the timer to generate the interrupt ?

Thank you again William

williamdavy wrote on Monday, May 23, 2011:

Hi Samoia,

No worries.

The easy one first. The Timer needs to count as many ticks as necessary to generate an interrupt at the desired rate. For example, if your Timer was being driven by a 32768Hz clock, then counting to 32768 would generate an interrupt every second. Typically, for FreeRTOS you want your interrupt rate to be somewhere between 1 Hz and 1000Hz translating (1 second to 1 ms range).

First figure out what clock is driving your Timer and change the #define configCPU_CLOCK_HZ in FreeRTOSConfig.h to match. Then decide how often you want the interrupt to fire, I suggest 100Hz or every 10 ms, set the configTICK_RATE_HZ definition to 100. Then program the Timer Load register to configCPU_CLOCK_HZ / configTICK_RATE_HZ.

Next, I suggest that you enable the vApplicationTickHook() and define that function to toggle an LED or other GPIO pin every time it is called. Then you can attach a scope and verify your tick rate is correct. Alternatively, if you don’t have a scope, toggle the LED every 100 calls to the function and count how many times it toggles in a minute which will give you a good enough idea. Take a look into the partest.c file in the demo project for code to drive the GPIO.

With respect to your other problem with returning to main(), it sounds like the context switch is not quite right. I would imagine that the OS will end up somewhere strange if there are no available tasks to run. Can you confirm that the IDLE task is successfully being created (if it fails because you have run out of heap RAM, the FreeRTOS scheduler won’t start and vTaskStartScheduler() will return to main()) and that you are never calling a blocking API function from vApplicationIdleHook().

What Stack space are you using to execute the interrupt handler? I think that the context switch in the demo project will switch the stack pointer to a dedicated interrupt handler stack space, do you replicate this? Are you confident that you change to the Task’s stack pointer before doing the return from interrupt instruction, so jumping back to the correct place in the code.

Have you tried disabling vTaskSwitchContext() in the vTickISR()? Disabling the context switch in the Tick interrupt will make time progress (from the RTOS point of view because you call vTaskIncrementTick()) but your tasks will still run co-operatively because the context will only change when they call taskYIELD().

Have you included the various NOP (technically they are ‘OR r0, r0, r0’ instructions) instructions in your assembly. Sometimes the effects of instructions take a little while to go through the instruction pipeline so these can be important, especially at the end of the portRESTORE_CONTEXT macro.

Make sure that you aren’t modifying the return address when using the interrupt handler. When you yield, you need to modify the return address so that you jump over the instruction that caused the yield but when you are interrupted, you want to return back to exactly where you were.

Hopefully one of the above suggestions will help you. Generally speaking, vTaskStartScheduler() returns because either you have run out of RAM, accidentally called vTaskEndScheduler(), somehow returned to the stack of main() just after calling vStartFirstTask() and you have hit a return call or ended up in somewhere random that just happens to take you back to main().

samoia wrote on Thursday, June 02, 2011:

Hi William

Thanks for the tips that you have listed above.

My timer is already set to generate an interrupt at a desired rate.

About the return to the main problem, i have confirmed that the Idle task is created successfully by the return value of xTaskCreate() which is equals to 1. I have a large size of RAM and I can go up to 170 Kbytes. I am not calling vTaskEndScheduler() and I am not using vApplicationIdleHook() either (at less for the moment).

For the interrupt handler stack, yes I am using the same stack as the one provided in the microblaze port. My processor has the same registers as the microblaze and same stack growth, so i did not change portasm.s much except for the interrupt handler to branch directly to vTickISR instead of vTaskISRHandler just to get the preemptive multitasking works with the timer only.

While i did some debugging, i came across some questions that i hope you can enlighten me with some answers:

What is the use of the following values which are stored in the bottom of the stack in pxPortInitialiseStack() ? and why they are essential?

*pxTopOfStack = ( portSTACK_TYPE ) 0x11111111;
*pxTopOfStack = ( portSTACK_TYPE ) 0x22222222;
*pxTopOfStack = ( portSTACK_TYPE ) 0x33333333;

What does the code at the beginning of xPortStartScheduler() exactly do? i mean when the __FreeRTOS_interrupt_handler is copied into those addresses, what does the address 0x16 represent ?

actually i used this link to handling the interrupt, so basically I overwrote the  __FreeRTOS_interrupt_handler with the _interrupt_handler. Is that correct ?

I am suspecting that the problem of returning back to the main could be the way I handled the interrupt because the vStartFirstTask() is not functional (While it was before I implemented the interrupt) or else my program should never exits

Thanks for your help :slight_smile:

williamdavy wrote on Thursday, June 02, 2011:

Hi Samoia,

Question, is the Interrupt Stack being allocated using pvPortMalloc() or similar? I seem to recall when I was updating the port, there was a call to pvPortMalloc() in xPortStartScheduler() which erroneously enabled interrupts before the first task had been started. As far as the scheduler is concerned, once you call vTaskStartScheduler() and it calls xPortStartScheduler() the scheduler has started running, which means you need to make sure interrupts are disabled until the very first task is switched in.

Ironically, debugging the target can exacerbate the problem because when you step through the code, you practically guarantee that an interrupt will be pended (typically any delay after prvSetupTimerInterrupt()). Try placing a break point on the entry to the interrupt handler, vStartFirstTask() and the entry to your highest priority task. If you hit the interrupt handler first then you are probably enabling interrupts too early.

With respect to the stack values you mentioned, typically they are either used to mark the stack with known values so that you can see them when debugging, or possible create a specific offset when entering the prologue of the function call that is your task implementation. If you look at the disassembly of the entry to a function (the prologue) you may see some stack manipulation. (Normally this would be matched in the epilogue of a function but we never ‘return’ from a task)

I didn’t write the first little bit of assembly in xPortStartScheduler() so I didn’t look into what it does. Looking at the reference manual, I reckon it loads the address of the interrupt handler (relative to 0) into R6, stores that address to the stack, loads the halfword from the stack into R7, stores a halfword of R7 at offset 0x12 and stores the halfword of R6 at offset 0x16. Seems to me like it is updating the Microblaze vector table with the address of the __FreeRTOS_interrupt_handler. Strikes me as a little odd that it is only modifying the least significant halfwords but there maybe be a good reason for that. I suggest turning on instruction stepping and following the values in the registers whilst inspecting memory addresses 0x00000012 and 0x00000016.

Looking at the manual, when an interrupt occurs, the processor branches to 0x10, which is probably initialised with an instruction that loads/branches to the address at 0x12. Again, I don’t have the board set-up in front of me so I can’t double check. Try setting your disassembly view to look at 0x0 in memory.

You need to be a little bit careful when writing the interrupt handlers. The vector table for the Microblaze only gives you 0x10 to 0x14 (in the manual 0x16 is not defined) for instructions to load up the address of the proper interrupt handler. Therefore, you need very basic code that is capable of jumping out of the vector table to more assembly code (or possibly a naked C function) that saves the execution context before calling a C function that can deal with the cause of the interrupt. Your basic vector table interrupt code needs to be placed in the correct memory section which is probably defined as ‘.vectors.interrupt’ at 0x10 in the linker script. The compiler/environment probably has very specific code that lazy links in the address of a function called __interrupt_handler(), hence, it is possible to provide your own functionality for that function.

I hope that helps.

williamdavy wrote on Friday, June 03, 2011:

Hi Samoia,

Just a clarification on the use pvPortMalloc() in xPortStartScheduler(). I changed my port to use the generic ‘vTaskEnterCritical()’ and ‘vTaskExitCritical()’ functions by mapping portENTER_CRITICAL() and portEXIT_CRITICAL(). This means that the ‘uxCriticalNesting’ value is stored on a per task basis so removing the global ‘uxCriticalNesting.’ Hence, when calling pvPortMalloc() in xPortStartScheduler(), the first task waiting to run would have its critical nesting count inspected and of course it was initialised to 0, causing interrupts to be enabled just before that task actually started running.

Hopefully that didn’t lead you on too much of a goose chase.

samoia wrote on Monday, June 13, 2011:

Hi William

My very much gratitude for the help and the guidance you provided.
I really appreciate the time you spent. You made lots of things clearer.