FreeRTOS porting to ARM926ejs

nagarajukarre wrote on Tuesday, September 24, 2013:

I am portin the FreeRTOS onto ARM926 platform.
My processor gets resetting when i am creating the Task.
actually this is happening in the below code.

#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()

#define portDISABLE_INTERRUPTS() __disable_irq()
#define portENABLE_INTERRUPTS() __enable_irq()

void __disable_irq (void)
{
unsigned long old,temp;
serial_putc(‘I’);
asm volatile(“mrs %0, cpsr\n”
“orr %1, %0, #0xc0\n”
“msr cpsr_c, %1”
: “=r” (old), “=r” (temp)
:
: “memory”);

    serial_putc('J');

// return (old & 0x80) == 0;
}

Please suggest me the correct procedure.

Thanks & Regards,
Nagaraju

davedoors wrote on Tuesday, September 24, 2013:

It should be the same code as the ARM7 port.

#ifdef THUMB_INTERWORK

  extern void vPortDisableInterruptsFromThumb( void ) __attribute__ ((naked));
  extern void vPortEnableInterruptsFromThumb( void ) __attribute__ ((naked));

  #define portDISABLE_INTERRUPTS()  vPortDisableInterruptsFromThumb()
  #define portENABLE_INTERRUPTS()    vPortEnableInterruptsFromThumb()
  
#else

  #define portDISABLE_INTERRUPTS()                      \
    __asm volatile (                            \
      "STMDB  SP!, {R0}    \n\t"  /* Push R0.            */  \
      "MRS  R0, CPSR    \n\t"  /* Get CPSR.          */  \
      "ORR  R0, R0, #0xC0  \n\t"  /* Disable IRQ, FIQ.      */  \
      "MSR  CPSR, R0    \n\t"  /* Write back modified value.  */  \
      "LDMIA  SP!, {R0}      " )  /* Pop R0.            */
      
  #define portENABLE_INTERRUPTS()                        \
    __asm volatile (                            \
      "STMDB  SP!, {R0}    \n\t"  /* Push R0.            */  \
      "MRS  R0, CPSR    \n\t"  /* Get CPSR.          */  \
      "BIC  R0, R0, #0xC0  \n\t"  /* Enable IRQ, FIQ.        */  \
      "MSR  CPSR, R0    \n\t"  /* Write back modified value.  */  \
      "LDMIA  SP!, {R0}      " )  /* Pop R0.            */

#endif /* THUMB_INTERWORK */

nagarajukarre wrote on Tuesday, October 01, 2013:

Hi,

I ported the basic startup code, timer and interrupt is generating at given
period of time and serial port is working.

I have created the two tasks and started the scheduler, at this time i observed that only one task is running, both the tasks have the same priority.

If i assign one task priority is high at this time only high priority task is running i am unable to see any console messages from the task2…

I initialized one hardware timer and which is generating interrupt at 5 ms.In my timer interrupt handler i am calling the vTaskIncrementTick().

Please suggest me how do i make my scheduler has to the schedule the created tasks to make sure multitasking is happening.

Thanks,

rtel wrote on Tuesday, October 01, 2013:

Assuming the interrupt handler is formed correctly, as a naked function or as an assembly file, then it should contain the code:

if( xTaskIncrementTick() != pdFALSE )
{
vTaskSwitchContext();
}

xTaskIncrementTick() being the function that might unblock a task, and vTaskSwitchContext() being the function that selects the highest priority task to run.

This is correct for FreeRTOS V7.5.0 onwards, anyway.

Regards.

nagarajukarre wrote on Wednesday, October 02, 2013:

Thank you, Ricahrd.

Currently my timer handler code consists of the below.

void OSTimeTick( void )
{
/* Increment the tick counter. */
vTaskIncrementTick();

#if configUSE_PREEMPTION == 1
{
    /* The new tick value might unblock a task.  Ensure the highest task that
    is ready to execute is the task that will execute when the tick ISR
    exits. */
    vTaskSwitchContext();
}
#endif

}

configUSE_PREEMPTION flag is enable.I am using the FreeRTOS version 7.5.2

Thanks,

edwards3 wrote on Wednesday, October 02, 2013:

vTaskSwitchContext() does not exist in FreeRTOS V7.5.2? It is called xTaskSwitchContext().

Is your OSTimeTick() function called after the task context is stored? It should be something like this:

void OSTimeTick( void ) __attribute__((naked));
void OSTimeTick( void )
{
    /* Save the context of the current task. */
    portSAVE_CONTEXT();			

    if( xTaskIncrementTick() != pdFALSE )
    {
        vTaskSwitchContext();
    }
		
    portRESTORE_CONTEXT();
}

The yield function should also be naked.

I'm using FreeRTOS\Source\portable\GCC\ARM7_AT91SAM7S\portISR.c as a reference.

nagarajukarre wrote on Thursday, October 03, 2013:

Hi,

My Code looks to be same as you suggested.
Only i observed that the prints are coming from my ISR at peroidically.

But my taks have to through some chars on to the console when they run.

Please find my attached console log.
in this chars are ‘M’ ‘N’ ‘O’ 'P’are i am printing through the ISR routine of the timer.

Please suggest me which part of code making wrong me.

Thanks

nagarajukarre wrote on Thursday, October 03, 2013:

Please find the attached file that explains my portSAVE_CONTEXT() and portRESTORE_CONTEXT().

rtel wrote on Thursday, October 03, 2013:

Are you 100% sure the interrupt is actually being entered and executed, and that the tick count is being incremented (the tick count is held in the xTickCount variable that is accessible from inside tasks.c).

Only i observed that the prints are coming from my ISR at peroidically.

Are you printing to a console from an interrupt? If so, then that is highly likely to cause you problems.

Trying to rapidly print from tasks can also cause problems, depending on how characters are actually being output. Anything that uses semihosting on an ARM9 will cause all sorts of issues as it will probably try and use the same interrupts as FreeRTOS.

I would recommend just starting with two tasks, of the form:

volatile unsigned long ul1 = 0, ul2 = 0;

void vTask1( void *pvParameters )
{
    for( ;; )
    {
        ul1++;
    }
}

void vTask2( void *pvParameters )
{
    for( ;; )
    {
        ul2++;
    }
}

Let that run for a while then check both ul1 and ul2 are being incremented at roughly the same rate.

Regards.

berni8k wrote on Thursday, October 03, 2013:

Another thing to make sure is that you have your config file contains sets configUSE_PREEMPTION to 1 and make sure it does indeed get included in all the code correctly.

I created my port for a ARM9 by sticking the ARM7 context save routines in to a ARM Cortex R4 port of it. Only had a slight snag with interrupt enables.

nagarajukarre wrote on Thursday, October 03, 2013:

I am 100% sure that interrupt is firing and ISR routine is executing.
The xTickCount variable is getting incrementing this i have tested like in tasks.c file i am cheking this variable for a value of 1000 at that time i am entering into infinite loop and serial_put(‘D’) which coming here and contineously printing D like below.

xTaskIncrementTick()

++xTickCount

if(xTickCount == 1000)
while(1){
serial_putc(‘D’);
}

in case of ARM 9 the interrupt code like below.

void do_irq (void)
{
#ifdef CONFIG_MCS8140
if ((__read_irq_status) & (1<<IRQ_TIMER))
{
__clear_irq(IRQ_TIMER);

      if(rd_b(TIMERS_INTERRUPT_STATUS_REG)&2)
     {
            bit16_timer_interrupt_occured = 1;

/* serial_putc(‘M’);
serial_putc(‘N’);
serial_putc(‘O’);
serial_putc(‘P’);
serial_putc(’@’);*/
OSTimeTick();

     }

}

/-----------------------------------------------------------/
void OSTimeTick( void ) attribute((naked));
void OSTimeTick( void )
{

//portSAVE_CONTEXT();
/* Increment the tick counter. */
if( xTaskIncrementTick() != pdFALSE );

// #if configUSE_PREEMPTION == 1
{
/* The new tick value might unblock a task. Ensure the highest task that
is ready to execute is the task that will execute when the tick ISR
exits. */

    serial_putc('W');
    serial_putc('W');
    serial_putc('W');
    serial_putc('W');
    serial_putc('W');
    vTaskSwitchContext();
}

// #endif

//portRESTORE_CONTEXT();
}

I don’t have flexibility to run the suggested program to watch the values. Instead that when my count value equal to some 100 then i am going to infinite loop but i have not observed that.

Apart from that is there any program to check the my FreeRTOS up and running.

Here i observed that only one task is continuously running.When i change the priority of another task at that time only high priority task is runing.

Please guide me how do i make sure that my both the tasks are running simultaneously.

Thanks,

nagarajukarre wrote on Thursday, October 03, 2013:

In vTaskSwitchContext() function i am entering in to the else part in this i have not seen the defination for the below

traceTASK_SWITCHED_OUT();

and the configGENERATE_RUN_TIME_STATS is not defined not entering in to this condition.

traceTASK_SWITCHED_IN(); is also not defined and configUSE_NEWLIB_REENTRANT is defined as 0.

Please suggest me how to overcome the problem.

Regards,

nagarajukarre wrote on Friday, October 04, 2013:

Hi, I have run the below code by placing the break points in task 1 and task2.Every time task2 break point and only the varible inside the ul2 is getting updated.

volatile unsigned long ul1 = 0, ul2 = 0;

void vTask1( void *pvParameters )
{
for( ;; )
{
ul1++;
}
}

void vTask2( void *pvParameters )
{
for( ;; )
{
ul2++;
}
}

Please could you point out me why the scheduler is not scheduling my task1.
Which part of the code needs to be modified.

Regards,

nagarajukarre wrote on Friday, October 04, 2013:

Every time the break point inside the task2 is hitting and the value inside task2 getting incremented but ihave not observed that the task 1 break point is not hitting and the variable inside the task2 is not getting updated.

Please could you update me on the same, i am using FreeRTOS version 7.5.2.

Regards,

rtel wrote on Friday, October 04, 2013:

serial_putc(‘W’);
serial_putc(‘W’);
serial_putc(‘W’);
serial_putc(‘W’);
serial_putc(‘W’);
vTaskSwitchContext();

I think I already mentioned that sending serial characters from the interrupt is really not a good idea - sending 5 from the tick interrupt is positively a bad idea!

Have you removed that code?

Regards.

nagarajukarre wrote on Friday, October 04, 2013:

Hi,

I observed that my code gets hanging in portSAVE_CONTEXT() function.

Regards

nagarajukarre wrote on Wednesday, October 09, 2013:

Hi,

I have configured my interrupt handler like below.

irq:
get_irq_stack
bl portSAVE_CONTEXT
bl do_irq
bl portRESTORE_CONTEXT

my do_irq function is like below.

void do_irq (void)
{

    if ((__read_irq_status) & (1<<IRQ_TIMER))
    {
            __clear_irq(IRQ_TIMER);
           


     if(rd_b(TIMERS_INTERRUPT_STATUS_REG)&2)
     {
            OSTimeTick();

     }

}

void OSTimeTick( void ) attribute((naked));
void OSTimeTick( void )
{
/* Increment the tick counter. */
if( xTaskIncrementTick() != pdFALSE );

{
    /* The new tick value might unblock a task.  Ensure the highest task                                                                                                                                                                                                                                                                        that is ready to execute is the task that will execute when the tick ISR
    exits. */

    vTaskSwitchContext();
}

}

I have configured the timer interrupt to generate at every 5ms and i called this in my vTaskStartScheduler() function just before calling the

if( xPortStartScheduler() != pdFALSE ) with the function name

prvSetupTimerInterrupt();

Initially my processor is in SVC mode and interrupts are enabled and IRQ interrupt is firing and entering into the IRQ mode and IRQ interrupts are disabled.We dont get any further interrupts that means no further do_irq gets called.

Then entering into portSAVE_CONTEXT and hanging at the below stmfd instruction.

@ Push all the system mode registers onto the task stack.
    stmfd   LR, {R0-LR}^
    NOP
    SUB     LR, LR, #60

In my main routine i have created the two tasks of both having the same priority and both the tasks are created successfully and i have started the scheduler.

my code looks like below

portBASE_TYPE xPortStartScheduler( void )
{

    /* Start the first task. */
    serial_putc('K');
    vPortStartFirstTask();

    serial_putc('N');
    /* Should not get here! */
    return 0;

}

my vPortStartFirstTask(); calls the bl portRESTORE_CONTEXT.

First time my task2 gets scheduling and only that task running contineously but the task1 never get a chance to schedule and it is not running.

But some times at the end of instruction portRESTORE_CONTEXT bl which is jumping to the OSTimeTick function but my tasks are not gets scheduled and which is hanging at the portSAVE_CONTEXT as i mentioned above.

Please could you provide me the tips to overcome my hang issue and to scheduler to schedule my two tasks symultaneously.

Thanks

rtel wrote on Wednesday, October 09, 2013:

Ok - I’m loosing the thread here. Lets go back to the beginning and go through this step by step.

irq:
get_irq_stack
bl portSAVE_CONTEXT
bl do_irq
bl portRESTORE_CONTEXT

Broadly speaking, there are two ways the interrupt controller can work on ARM9 devices.

  1. Single vector interrupt.

In this scheme there is only one entry point into any interrupt. That single entry point performs some stack management, then looks to see what caused the interrupt, then calls the appropriate handler. The handler is just a standard C function that returns back to the single interrupt handler, which then cleans up the stack and returns back to non interrupt code.

From the code quoted above, it looks like that is the scheme you are using. Although I’m not sure what the line “get_irq_stack” is doing, as the processor should automatically switch to the IRQ stack for you.

  1. Auto vectoring

In auto vectoring the interrupt controller is clever enough to know the cause of the interrupt and jumps directly to a handler for that interrupt. In this scheme there are multiple interrupt entry points - one for each interrupt source.

The discussion in this thread so far has assumed scheme 2 was being used - auto vectoring, but the code you have just posted (and quoted in this thread) makes me think you are actually using scheme 1 - single vector interrupt.

Can you confirm which you are using. Then we can move onto the next step.

Regards.

nagarajukarre wrote on Wednesday, October 09, 2013:

Thank you for your posting.

Yes i am using the scheme1 single vector interrupt, and get_irq_stack does the STACK pointer point to particular location address.

Regards,

rtel wrote on Wednesday, October 09, 2013:

Ok - I’m going to ignore the get_irq_stack call as I’m not sure what it is doing. It is however very important that, whatever it is doing, it does not change the value of any registers before they have been saved as part of the task context (the IRQ stack pointer can be changed, as that is not used by tasks).

The other thing about your interrupt code I note is that you are branching to the save and restore context macros - these should be inline macros, not functions.

One of the STR9 demos in the FreeRTOS download uses the single vector method. Take a look at the file:

FreeRTOS\Demo\ARM9_STR91X_IAR\91x_vect.s

in that file find the IRQHandler assembly function. You will see the first thing it does is call portSAVE_CONTEXT, but portSAVE_CONTEXT is a macro - it is inlined - the CPU does not branch to it. The implementation of the macro is part of the FreeRTOS port layer (for IAR in this case) and is defined in:

\FreeRTOS\Source\portable\IAR\STR91x\ISR_Support.h.

IRQHandler likewise ends in the inline portRESTORE_CONTEXT macro.

The code between portSAVE_CONTEXT and portRESTORE_CONTEXT is specific to the chip - so ignore that.

Once your vector is set up like this then the individual functions that service peripherals become standard C functions - you don’t need the naked attribute or to do any further saving or restoring of context.

While you are in the 91x_vect.s file also take a look at the vector table. vPortYieldProcessor is installed as the SWI handler:

        LDR     PC, Reset_Addr
        LDR     PC, Undefined_Addr
        LDR     PC, SWI_Addr
        LDR     PC, Prefetch_Addr
        LDR     PC, Abort_Addr
        NOP                             ; Reserved vector
        LDR     PC, IRQ_Addr



Reset_Addr      DCD     __iar_program_start
Undefined_Addr  DCD     UndefinedHandler
SWI_Addr        DCD     vPortYieldProcessor ; <<<<<<<<<<<<<<<<
Prefetch_Addr   DCD     PrefetchAbortHandler
Abort_Addr      DCD     DataAbortHandler
                DCD     0               ; Reserved vector
IRQ_Addr        DCD     IRQHandler

Regards.