Microblaze Demo on ML405

nxdefiant wrote on Thursday, May 08, 2008:

Hello,

I tried to run the FreeRTOS v5.0 Microblaze Demo on my Xilinx ML405 board, however it did not work as expected - no blinking LEDs. In my serial terminal I get once the string "ABCDEFGHIJKLMNOP" - and nothing more.

Since the ML405 is a bit different to the ML403, so I had to edit the system.ucf and change the FPGA type for the project.

I’m using EDK & ISE 9.1

Any ideas what does went wrong here?

nxdefiant wrote on Thursday, May 15, 2008:

Could the problem be, that the compiler is removing the "or r0, r0, r0" from portasm.s?

rtel wrote on Tuesday, May 20, 2008:

The Microblaze port was developed using version 8.x of the EDK.  Although we now have version 10.x we have not yet updated the demo application configuration. 

When you open the project in your 9.x tools it should attempt to update the project to that standard, and update the used IP to the 9.x versions.  It might be that the problem is occurring during this process. 

Alternatively, as I recall the Microblaze port requires the timer interrupt vector to be setup manually rather than using the vector table setup by the EDK.  It is quite likely that the timer interrupt (RTOS tick) is not executing.  If this is the case each task will only execute up to the point that it blocks, and then never unblock.  Can you verify that the RTOS tick interrupt is executing?  Also, can you run the application in the debugger to see where it ends?

Regards.

nxdefiant wrote on Thursday, May 22, 2008:

First, thanks for your answer.

Yes, the 9.x Version did attempt to update the project without throwing an error.
Still the might me an undetected error…

The problem actually seems to be really odd:

First of all, I reduced the main() to
prvSetupHardware();
vStartLEDFlashTasks( mainLED_TASK_PRIORITY );
vTaskStartScheduler();

Next I added a
xil_printf("start\r\n");
at the very top of the file.

Executing this, I ended up with the demo application constantly printing "start" on the serial, again and again.
So it looks to me, that the whole thing is crashing sowewhere.

About debugging:
I’m loosing the program somewhere in
vStartFirstTask();
Unfortunately, the insight debugger seems unable to step into this function, since it is not written in C.

However, stepping in XMD seems to help.
The last comment I see exeuted before it starts back into the main is
brlid r15, -10164, which is the call for xTaskGetTickCount() in flash.c, portTASK_FUNCTION(vLEDFlashTask, pvParameters).

One additional information:
The system doesn’t seem to crash when I remove the call to prvSetupTimerInterrupt() in port.c, xPortStartScheduler().

So the conclusion I jump to is, that the system does crash, as soon as the Interrupt gets called.
Unfortunately I have no idea why.

rtel wrote on Thursday, May 22, 2008:

You should be able to debug the asm code from within Insight.  I have been doing this recently on the PPC port, also using Insight.

In the Insight interface there are three drop down lists.  The left list contains all the files, the middle list the functions contained within the file.  In the left drop down list you should be able to select portasm.s, then once selected in the middle drop down list you should be able to select __FreeRTOS_interrupt_handler to take you to the start of the ISR handler function.  You can then put a break point on the entry to the ISR.  As this is an asm file you should be able to leave the right drop down list on Source.

This is complicated somewhat by the fact that the ISR starts with a macro, the first instruction after this is     ori r31, r31, 2, that might be the best point to place the break point to see if it gets hit.  If it never gets that far then something in the portSAVE_CONTEXT macro must be amiss.

Regards.

nxdefiant wrote on Thursday, May 22, 2008:

Btw, are you sure you developed the Microblaze Port under 8.x?
The system.xmp says 7.1.

I finally found a 7.1 here and installed it. It didn’t want to compile the project - too big for target.
Only after installing the updates I was to able to compile _and_ finally get FreeRTOS to run as expected.
My Leds do finally blink - yeah :slight_smile:
Xilinxs tools seem to be really funny.

Anyway, would be good if we could get the whole thing working on a recent EDK.

nxdefiant wrote on Thursday, May 22, 2008:

Back to EDK 9.1:
I’m afraid portasm.s is not in the list of files I can select.

I was unable to see ori r31, r31, 2 executed in XMD. It seems to directly jump from the vLEDFlashTask() back to main().

I also tried to set a breakpoint to __FreeRTOS_interrupt_handler in XMD, but was able to get a hit.

nxdefiant wrote on Thursday, May 22, 2008:

I think I found the root of all evil: http://www.xilinx.com/support/answers/24988.htm

Might be the point.

rtel wrote on Thursday, May 22, 2008:

Thats a good find.  I would appreciate a copy of any changes you make to fix this.

Regards.

nxdefiant wrote on Monday, May 26, 2008:

If I can fix this, you will get the patch, of course.

However right now I’m still trying to understand the original idea.
For the Microblaze port you use two interrupt routines? -I found port.c vTickISR() and portasm.s __FreeRTOS_interrupt_handler() and I can’t really explain why there are two.

I looked through your other FreeRTOS ports, especially the Atmel AVR one and it uses only one interrupt routine.

rtel wrote on Monday, May 26, 2008:

I was looking at this a bit yesterday.  I have the same thing as you, after allowing the project to update to V10.1 of the EDK I can compile and download but the code does not run correctly.  What I found is that the code does actually run, and switch between tasks, but as soon as a timer tick interrupt comes in the system resets. 

It looks like (as per your previous email) the way interrupts are setup has completely changed between versions of the EDK - what a pain. 

It might be that the PPC405 port can offer some clues as this was generated in V10.1 of the EDK - this has a function vPortInitiliazeInterruptController() in its port.c file.  The problem being that the library functions differ somewhat between the Microblaze and the PPC405.

Also, looking through the peripheral test code automatically generated by the EDK with a new project, it looks like there are more setup functions require to be called before the interrupt controller is in a state whereby it can be used successfully.  I have just stepped through the interrupt controller self test code to find these, I have not actually looked up exactly what they do.

__FreeRTOS_interrupt_Handler is the interrupt handler.   From memory it replaces the interrupt handler installed by the crt0 code.  Its job is to save the task context, determine which peripheral caused the interrupt, then just to the correct handler for that peripheral.  vTickISR() is one of the functions it jumps to so vTickISR() is not the entry point for an interrupt.

Regards.

nxdefiant wrote on Monday, May 26, 2008:

Getting the interrupt to occure is easy. The example code in this document http://www.xilinx.com/support/documentation/application_notes/xapp778.pdf (last page) is close to what we need.

What I’m stuck is what exactly todo in the isr.

I mean the basics are clear.
Something like…

portSAVE_CONTEXT()
vTaskIncrementTick()
clear_timer_interrupt()
#if configUSE_PREEMPTION == 1
    vTaskSwitchContext()
#endif
portRESTORE_CONTEXT()

…just have to get it right.

nxdefiant wrote on Monday, May 26, 2008:

btw right now I’m using this code to setup the interrupt. I hope this board keeps the source in a readable format…

void setup_isr(void) {
    /* Register External interrupt handler */
    XIntc_RegisterHandler(XPAR_OPB_INTC_0_BASEADDR, XPAR_OPB_INTC_0_OPB_TIMER_1_INTERRUPT_INTR, timer_int_handler, (void *)XPAR_OPB_TIMER_1_BASEADDR);
   
    /* Start the interrupt controller */
    XIntc_mMasterEnable(XPAR_OPB_INTC_0_BASEADDR);
   
    /* Set the number of cycles the timer counts before interrupting */
    XTmrCtr_mSetLoadReg(XPAR_OPB_TIMER_1_BASEADDR, 0, configCPU_CLOCK_HZ / configTICK_RATE_HZ);
   
    /* Reset the timers, and clear interrupts */
    XTmrCtr_mSetControlStatusReg(XPAR_OPB_TIMER_1_BASEADDR, 0, XTC_CSR_ENABLE_TMR_MASK | XTC_CSR_ENABLE_INT_MASK | XTC_CSR_AUTO_RELOAD_MASK | XTC_CSR_DOWN_COUNT_MASK );
   
    /* Enable timer and uart interrupts in the interrupt controller */
    XIntc_mEnableIntr(XPAR_OPB_INTC_0_BASEADDR, XPAR_OPB_TIMER_1_INTERRUPT_MASK);
   
    /* Enable MicroBlaze interrupts */
    microblaze_enable_interrupts();
}

rtel wrote on Monday, May 26, 2008:

You probably know all this already, but just in case.

The previous version installed __FreeRTOS_interrupt_handler as the interrupt handler, with the following code:

__FreeRTOS_interrupt_handler:
    portSAVE_CONTEXT
    /* Entered via an interrupt so interrupts must be enabled in msr. */
    ori r31, r31, 2
    /* Stack msr. */
    swi r31, r1, 8
    /* Stack the return address.  As we entered via an interrupt we do
    not need to modify the return address prior to stacking. */
    swi r14, r1, 76
    /* Now switch to use the ISR stack. */
    lwi r3, r0, pulISRStack
    add r1, r3, r0
    bralid r15, vTaskISRHandler
    or r0, r0, r0
    portRESTORE_CONTEXT

This is defined in portasm.s.  vTaskISRHandler then found the source of the interrupt and ran the correct handler, in the case of the timer interrupt this was vTickISR().  When vTickISR() is called the context has already been saved by __FreeRTOS_interrupt_handler, so this does not need to happen again.  vTickISR() is therefore (in port.c):

void vTickISR( void *pvBaseAddress )
{
unsigned portLONG ulCSR;

    /* Increment the RTOS tick - this might cause a task to unblock. */
    vTaskIncrementTick();

    /* Clear the timer interrupt */
    ulCSR = XTmrCtr_mGetControlStatusReg(XPAR_OPB_TIMER_1_BASEADDR, 0);   
    XTmrCtr_mSetControlStatusReg( XPAR_OPB_TIMER_1_BASEADDR, portCOUNTER_0, ulCSR );

    /* If we are using the preemptive scheduler then we also need to determine
    if this tick should cause a context switch. */
    #if configUSE_PREEMPTION == 1
        vTaskSwitchContext();
    #endif
}

So provided the timer interrupt is installed correctly into the interrupt controller array of handlers, it should work.

Regards.

nxdefiant wrote on Monday, May 26, 2008:

aah, so vTaskISRHandler() is the one that should call vTickISR().
So in theory - since I only have one interrupt source active right now - with __FreeRTOS_interrupt_handler as my ISR to replace all the contents of vTaskISRHandler() with a single call to vTickISR() and it should work, right?

void vTaskISRHandler( void )
{  
    vTickISR(NULL);
}

just for testing.

rtel wrote on Monday, May 26, 2008:

If this is the only interrupt then I think something close to that should work.  Looking at the existing vTaskISRHandler() handler it also acks the interrupt controller, so you would have to add that too.

Regards.

nxdefiant wrote on Monday, May 26, 2008:

hmm. This results in a _vector_sw_exception in insight.

The problem might be the stack since __FreeRTOS_interrupt_handler() doesn’t have an argument, while it should have one
since the template for an isr is void ext_int_handler(void * baseaddr_p) {}

rtel wrote on Monday, May 26, 2008:

I’m not sure that __FreeRTOS_interrupt_handler should have an argument, it is a replacement for the Xilinx provided _interrupt_handler, which is installed by crt0.s.

Handler functions called by __FreeRTOS_interrupt_handler (like vTickISR()) should have an argument.

Regards.

nxdefiant wrote on Monday, May 26, 2008:

After having read the Xilinx appnote on Interrupts I found no mention off crt0.s in it. My guess is that this file is no longer used.
In fact I’ve created a new base project for freertos and crt0.s has not been created with it.
However the ISR itself is called.

So my guess is crt0.s is no longer used, same with most parts of vTaskISRHandler(), but can’t say it for sure since I was unable to find documentation for the old style Interrupts.

The new way, using XIntc_RegisterHandler() expects a function to be ISR that has an argument.

rtel wrote on Monday, May 26, 2008:

Looking at the PowerPC port (which was created using EDK V10.1) I see that the Xilinx standard interrupt handler calls vPortISRHandler() which is where the interrupt source is located (equivalent to the Microblaze vTaskISRHandler()) and sure enough vPortISRHandler() has a parameter.  The parameter is the interrupt controller that is being serviced.  As in the PowerPC demo only one interrupt controller is included the parameter is ignored.

The crt0 file is included in the demo code itself, presumably it was copied there automatically when the V7.1 EDK generated the project structure.  The PowerPC demo does not include a crt0 file.  Startup code must exist somewhere however - I have just searcehd a new Xilxix created Microblaze project and cannot find it.  Main() does exist in a library though, so maybe that is where they have put it.  Looks like you are right in that new project are not explicity copying a crt0 file.

Unfortunately I have not got the space time to read through the app notes and try running a virgin project today :o(

Regards.