Powered By Blogger
Showing posts with label interrupt. Show all posts
Showing posts with label interrupt. Show all posts
Tuesday, November 4, 2008

Another nice article about booting

Here is another really informative article by the Windows CE Base team.:)

http://blogs.msdn.com/ce_base/archive/2007/11/26/How-does-Windows-Embedded-CE-6.0-start_3F00_.aspx

Monday, September 29, 2008

Interrupt ... whats the big deal??

In most of the discussion forums I have seen that developers are not clear about how interrupts are handled in windows ce. I am familiar with the Xscale and arm architectures. This post will not explain about how to handle or register interrupt in drivers, as it is covered in some of the previous posts. Instead how kernel manages an interrupt in windows ce 6.0. Lets start off with the concept of EXCEPTIONS in arm architectures.

"Exceptions are generated by internal and external sources to cause the processor to handle an event, such as an externally generated interrupt or an attempt to execute an Undefined instruction."
- I took it from the arm reference manual, couldn't put it in any better way myself:)

There are seven types of exceptions supported by ARM:
  1. Reset
  2. Undefined Instruction
  3. Software Interrupt
  4. Prefetch Abort
  5. Data Abort
  6. IRQ
  7. FIQ
When an exception occurs, the processor execution is halted and branches to a predefined address called exception vector. For each exception type, there is predefined exception vector, for example, exception vector for Data abort is 0x00000010 and that of reset is 0x00000000. There is also high vectors in which the exception vectors can be moved to an alternative address range(0xFFFF0000-0xFFFF001C), using bit[13] of the coprocessor 15 register 1 .

In the exception handler the banked version of register such as R14 and SPSR are used to save and restore the processor state.

Starting point for analyzing the exception handling in Windows ce for ARM architectures can be
WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM\exvector.s



Defenition to each of this hanlders can be found in armtrap.s (WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM)
This vector table will be loaded into the higher part of physical page at 0xffff0000 (same as the High vector address), along with other kernel data in ARM_HIGH structure (WINCE600\PRIVATE\WINCEOS\COREOS\NK\INC\nkarm.h)


Here are some references that you can start off with
- ARM Architecture Reference Manual

In my previous post, I have explained how to add an interrupt when source code is available.

Now I will explain how to handle an interrupt by writing an IST in the driver. For the reason of continuity, I am using the same power button driver and the Wireless Activity Interrupt (as I explain with in post "Adding Interrupt in OAL").

1. Create an even to be associated with the interrupt

HANDLE g_WlanActiveEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if( !g_WlanActiveEvent)
{
RETAILMSG(1, (TEXT("WlanActivityMonitorStart: Failed to create Intterupt Event\r\n")));
goto CleanUp;
}

2. Associate the Interrupt with the event using SYSINTR value
UINT32 g_SysIntr = SYSINTR_WLAN;
......
result = InterruptInitialize(g_SysIntr, g_WlanActiveEvent, NULL, 0);

if(!result)
{
RETAILMSG(1, (TEXT("WlanActivityMonitorStart: InterruptInitialize() failed. GetLastError=0x%x\r
\n"),GetLastError()));

goto CleanUp;
}

3. Start a thread for handling the interrupt.
g_WlanThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) WlanThread, NULL, 0, NULL);
if ( g_WlanThread == NULL )
{
RETAILMSG(1, (TEXT("WlanActivityMonitorStart: Failed to create WlanActive
Intterupt Thread\r\n")));
goto CleanUp;
}


4. In the thread, wait for the event to happen using the WaitForSingleObject or WaitForMultipleObjects API.
INT WlanThread (VOID)
{
while(!g_FlagExitThrd)
{
WaitForSingleObject(g_WlanActiveEvent, INFINITE);
.............
}
return ERROR_SUCCESS;
}

5. Perform the necessary operations to service that interrupt. Here I am pulsing another event to notify some other sets of appication.
WaitForSingleObject(g_WlanActiveEvent, INFINITE);
InterruptMask(g_SysIntr,TRUE);

if (g_WlanEvent)
{
RETAILMSG(1, (TEXT("WlanThread: Intterupt \r\n")));
PulseEvent(g_WlanEvent);
}

Sleep (1000); // Sleep to ignore some activity as this line toggles a lot
InterruptMask(g_SysIntr,FALSE);
6. Signal the completion of interrupt handling using InterruptDone
InterruptDone(g_SysIntr);

Sunday, September 7, 2008

Adding Interrupt in OAL

When we are having the whole BSP source, there will be cases in which we may need to add interrupt in OAL. This can be accommodate a new driver or add a new functionality to the existing one.

For explaining the procedure I am using the Mainstone BSP that is available in windows ce. Lets assume that we want to add an interrupt for Wireless LAN activity. This interrupt line will be a GPIO line which is mapped to GPIO 91 of PXA.

These are the files that need modification:
* bsp_cfg.h (Src\Inc)
* intr.c (OAL)

In 'bsp_cfg.h', you need to define a SYSINTR (if needed) for the new interrupt that you are about to add.

.............
#define SYSINTR_PWRBTN (SYSINTR_FIRMWARE+14) // 30
#define SYSINTR_WLANACTIVE (SYSINTR_FIRMWARE+15) // 31 - The new interrupt
................


Now in OAL, intr.c, make the following changes:
1. In BSPIntrInit() function, add a call to OALIntrStaticTranslate() to map the
the new SYSINTR v alue to the GPIO.
...............
OALIntrStaticTranslate (SYSINTR_WLAN,IRQ_GPIOXX_2_GPIO91);
...............


2. In BSPIntrEnableIrq(), add the case of enabling the GPIO Interrupt
.................
else if (irq == IRQ_GPIOXX_2_GPIO91)
{
EnableGPIO91Irq(); // define this function for enabling falling or rising
//edge detect and clear edge detect
}

.................


3. In BSPIntrDisableIrq(), add the case of enabling the GPIO Interrupt
.................
else if (irq == IRQ_GPIOXX_2_GPIO91)
{
DisableGPIO91Irq(); // define this function for clearing falling rising
//edge detect so that interrupt wont come
}

.................

4. Define the functions for enabling and disabling the gpio interrupt
............
//~~ Function for disabling gpio91 interrupt
static void EnableGPIO91Irq(void)
{
SETREG32((PULONG)&g_pGPIORegs->GRER2, XLLP_BIT_27);
}

//~~ Function for enabling gpio91 interrupt
static void DisableGPIO91Irq(void)
{
CLRREG32((PULONG)&g_pGPIORegs->GEDR2, XLLP_BIT_27);
CLRREG32((PULONG)&g_pGPIORegs->GRER2, XLLP_BIT_27);
}


This is how we add a new interrupt in OAL.

My friend mukesh has written in his blog, how to dynamically add an interrupt handler, when OAL source code is not available.

In the next posts, I will explain how to add an IST (Interrupt Service Thread) to take care of this interrupt.