Platform Builder: makeimg: FATAL ERROR: Out of buffer space


Here is an interesting makeimg error:
                makeimg: FATAL ERROR: Out of buffer space.
Seems that if the folder path for the _FLATRELEASEDIR is too long, makeimg fails with this cryptic error. I to reproduce this error I changed my release folder from:
C:\WINCE500\PBWorkspaces\xxxxxxxxxx\RelDir \xxxxxxxx_ARMV4I_Release
To
C:\WINCE500\PBWorkspaces\xxxxxxxxxx\RelDir\FolderWithLongNameToTryToCauseAnError\FolderWithLongName12345678901234\xxxxxxxx_ARMV4I_Release
And it failed. Notice the two folders named FolderWithLongNameToTryToCauseAnError, with just the first one inserted makeimg ran okay. So at 138 characters it does fails. But if I removed one character, makeimg was okay.
 
Copyright © 2009 – Bruce Eitman
All Rights Reserved

author: Bruce Eitman | posted @ Wednesday, June 17, 2009 10:18 PM | Feedback (0)

Windows CE: Keeping the Backlight On


Chris Tacke of OpenNetCF and I were talking about how to keep the backlight on in Windows CE 6.0 today. He had noticed that the function SystemIdleTimerReset() no longer kept the backlight on, but does keep the system running.   I had noticed this a while back, but didn’t have time to look into it. I did have a solution though.
The solution is to get an event name from the registry for an event that the power manager is monitoring. Then create the event and set it. Here is how I did it:
#define GWE_REG_PATH TEXT("SYSTEM\\GWE")
#define ACTIVITY_VALUE TEXT("ActivityEvent")
 
static HANDLE UserEvent = INVALID_HANDLE_VALUE;
HANDLE GetUserIdleEvent()
{
                TCHAR *EventName = NULL;
                DWORD Result;
                HKEY hKey;
                DWORD NumBytes = 0;
                DWORD Type;
 
                if( UserEvent == INVALID_HANDLE_VALUE )
                {
                                // Open the Registry Key
                                Result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCWSTR)GWE_REG_PATH, 0, 0, &hKey);
 
                                if( ERROR_SUCCESS == Result )
                                {
                                                // This is a fake read, all it does is fill in NumBytes with the number of
                                                // bytes in the string value plus the null character.
                                                Result = RegQueryValueEx( hKey, ACTIVITY_VALUE, NULL, &Type, NULL, &NumBytes );
                                                if( NumBytes > 0 )
                                                {
                                                                // Now we know how big the string is allocate and read it
                                                                EventName = (TCHAR *)malloc( NumBytes );
                                                                if( EventName != NULL )
                                                                {
                                                                                Result = RegQueryValueEx( hKey, ACTIVITY_VALUE, NULL, &Type, (LPBYTE)EventName, &NumBytes );
                                                                }
                                                }
                                                RegCloseKey( hKey );
               
                                                UserEvent = CreateEvent( NULL, FALSE, FALSE, EventName );
                                                free( EventName );
                                }
                }
                return UserEvent;
}
 
 
int UserIdleTimerReset()
{
                HANDLE hEvent = hGetUserIdleEvent();
 
                if( hEvent != INVALID_HANDLE_VALUE )
                                SetEvent( hEvent );
 
                return TRUE;
}
Now just call UserIdleTimerReset() as needed to keep the backlight on.
Chris was kind enough to post a C# version of this on his blog at Chris Tacke - Preventing the backlight from turning off in CE 6.0.
 
Copyright © 2009 – Bruce Eitman
All Rights Reserved

author: Bruce Eitman | posted @ Wednesday, June 17, 2009 6:59 PM | Feedback (0)

Platform Builder: Looking for an Engineer


Eurotech is looking for a Senior Software Engineer to port and maintain Windows CE on our single board computers.  This position is in our Columbia, MD office near Baltimore and Washington DC.
If you are looking for a change, or know a good engineer, take a look at our Eurotech Careers page.
We are not looking for application developers. We are looking for engineers with experience writing device drivers and bootloaders. We would prefer engineers with Platform Builder experience. But that is not a requirement, an experience Embedded Software Engineer and a drive to learn new technologies would also be a good candidate.
 
Copyright © 2009 – Bruce Eitman
All Rights Reserved

author: Bruce Eitman | posted @ Monday, June 15, 2009 11:09 PM | Feedback (0)

Windows CE Live Chat Tueday June 30, 2009


Another great opportunity to ask Microsoft engineers your technical questions is coming up on Tuesday, June 30th.  These chats are your opportunity to get advice and answers from the engineers at Microsoft.   You may want to review the transcripts from previous chats to get an idea what these chats are all about.
 Title:    Windows CE Live Chat!
When:  Tuesday, June 30, 2009    9:00 - 10:00 A.M. Pacific time 
Description: Do you have tough technical questions regarding Windows CE or Windows Mobile for which you're seeking answers? Do you want to tap into the deep knowledge of the talented Microsoft Embedded Devices Group members? If so, please join us for a live Windows CE chat and bring on the questions! Windows CE is the operating system that is powering the next generation of 32-bit, small-footprint and mobile devices. This chat will cover the tools and technologies used to develop devices using the Windows CE operating system.
To join this chat, please log on via the main MSDN chat page at: http://msdn.microsoft.com/chats/
 
Copyright © 2009 – Bruce Eitman
All Rights Reserved

author: Bruce Eitman | posted @ Monday, June 15, 2009 10:46 PM | Feedback (0)

Windows CE: OEMInterruptEnable() and OEMInterruptDisable()


The functions OEMInterruptEnable() and OEMInterruptDisable() are functions that a Windows CE device OEM must provide to enable and disable single interrupts. These functions receive as a parameter a SYSINTR value. They must map the SYSINTR value to an IRQ and then enable or disable the correct interrupt.
These functions are called indirectly by drivers. Drivers call functions like InterruptInitialize(), InterruptDone(), InterruptDisable(), and InterruptMask(). InterruptInitialize(), InterruptDone() and InterruptMask() indirectly call OEMInterrupteEnable(). InterruptDisable() and InterruptMask() indirectly call InterruptDisable().
To implement these functions, the Software Engineer will need to have a good understanding of how the interrupts are controlled on the hardware platform.   Some interrupts are controlled by registers in the CPU, while others may be controlled by external chips like a CPLD or FPGA. To enable and disable an interrupt is to mask or unmask the interrupt.
 It is important to realize that the functions are called when the code can be interrupted so caution should be used to ensure that changes to the mask registers must be done in an atomic way. If a register must be read, modified and written to mask or unmask an interrupt, the interrupt could be inadvertently masked or unmasked if the code is not atomic.
The BSPs that come with Platform Builder provide good examples for these functions. Depending on the BSP you may need to search in the CSP code to find the full implementations. The CSP code is in Platform\Common for CE 6.0 and in Public\Common\OAK\CSP for CE 5.0.
 
Copyright © 2009 – Bruce Eitman
All Rights Reserved

author: Bruce Eitman | posted @ Monday, June 15, 2009 10:36 PM | Feedback (0)

Windows CE: OEMInterruptHandler()


OEMInterruptHandler() is a required kernel function for ARM processors. When an interrupt occurs, the kernel calls OEMInterruptHandler() to determine which interrupt needs to be serviced. OEMInterruptHander() then returns the SYSINTR value associated with the interrupt. OEMInterruptHandler() allows Windows CE to handle interrupts on various CPUs and board designs.
There are many ways to write OEMInterruptHandler(), and the implementation will vary based on the CPU being used. Each CPU potentially implements the interrupt handling differently and therefore the software must be different to handle that. On CPUs like the Marvell PXA255 software determines the priority of the interrupt simply by the order that it looks at the interrupt sources (the first one that it looks at is the highest priority.) The PXA320 changed that by allowing software to set a register that controls many of the interrupt priorities.
The implementation of OEMInterruptHandler() takes the form of:
1.       Decode the interrupt to determine the source of the interrupt
2.       Determine the SYSINTR value associated with the interrupt
3.       Mask of the interrupt
4.       Return the SYSINTR value
Of course the first item is the most complex part of the code. This decoding can be handled in many ways depending the CPU and your creativity. The PXA255 has a register with bits set that indicates the pending interrupts, so the bits need to be examined. The PXA320 has a register with the highest priority pending interrupt number set, so the code can quickly jump to a handler for that interrupt.
Then of course the board may have other information that needs to be decoded. An example might be a programmable device like a CPLD or FPGA that multiplexes multiple interrupt sources and presents them through a single CPU interrupt.
The SYSINTR values can be handled as hardcoded settings, or they can be handled programmatically. That will depend on the needs of your system.
The interrupt usually needs to be masked so that it doesn’t continue to cause interrupts while the driver is processing interrupts. The reason is that while the driver is handling the source of the interrupt, the interrupt handling in the kernel will only slow it down. The interrupt is then re-enabled when the driver calls InterruptDone(). 
Copyright © 2009 – Bruce Eitman
All Rights Reserved

author: Bruce Eitman | posted @ Wednesday, June 10, 2009 9:06 PM | Feedback (0)

Platform Builder: error C2065: 'dpCurSettings' : undeclared identifier


So you build your BSP and it fails with an error like:
C2065:  'dpCurSettings' : undeclared identifier
Or
C2065: 'ZONE_INIT' : undeclared identifier
The easy answer is that you haven’t declared the variables, but the last time you built the BSP it built okay, so how could it be that all of a sudden there are undeclared variables?
The most likely reason is that you are building a debug build and you had previously been building a retail or release build. The difference is explained in Platform Builder: RETAILMSG vs. DEBUGMSG.   That explains it, but let’s fix it.
The problem is that when you build a debug build, you need to have some supporting code in your dll or exe. The first error says that dpCurSettings is undeclared.  The reason is that your code must declare and initialize a structure named dpCurSettings. If your code already declares  and initializes dpCurSettings, then the problem is that one of the files you are building needs to have an extern declaration available.
Here is an example of declaring and initializing dpCurSettings:
#ifdef DEBUG
DBGPARAM dpCurSettings = {
                TEXT("XXX Driver"),
                {
                                TEXT("Init"),
                                TEXT("Open"),
                                TEXT("Read"),
                                TEXT("Write"),
                                TEXT("Close"),
                                TEXT("Ioctl"),
                                TEXT("Thread"),
                                TEXT("Events"),
                                TEXT("CritSec"),
                                TEXT("Alloc"),
                                TEXT("Function"),
                                TEXT("Warning"),
                                TEXT("Error"),
                                NULL,
                                NULL,
                                NULL
                },
                0x00000001
};
#endif
 
The structure dpCurSettings is used by the OS to define strings that are displayed when changing the debug zones. These strings are passed to Platform Builder which then displays them when changing the debug mask using Target\CE Debug Zones. The last element, ulZoneMask, of the structure is a mask used to enable and disable debug messages, in this case only the Init debug messages will be output.
The error message indicating ZONE_INIT comes from a line in the code that looks like this:
DEBUGMSG( ZONE_INIT, (TEXT(“Initializing\n”)));
Where ZONE_INIT hasn’t yet been defined. ZONE_INIT should be a macro defined like:
                #define ZONE_INIT DEBUGZONE( 0)
Which uses the DEBUGZONE macro. The DEBUGZONE macro uses dpCurSettings. ulZoneMask anded with the value, in this case one, to “return” a value that is either set or not set. If the value is set, then the DEBUGMSG will output the string.
Copyright © 2009 – Bruce Eitman
All Rights Reserved

author: Bruce Eitman | posted @ Tuesday, June 09, 2009 6:58 PM | Feedback (2)

Windows CE: Kernel Interrupt Handling


What happens when an interrupt occurs? This article will focus on what the kernel does when the interrupt occurs, so this will assume that the interrupt is initialized and enabled.
1.       IRQ is signaled in hardware
2.       A vectored function is called in the kernel – the calling of the function is controlled by hardware, so the implementation is CPU family dependent. The vector table is initialized by the Kernel when it starts.
3.       Interrupts are disabled
4.       OEMInterruptHandler() is called to determine the SYSINTR value associated with the IRQ – OEMInterruptHandler() is platform dependent, so while there is some commonality, that is not guaranteed. OEMInterruptHandler() is required to identify the SYSINTR value associated with the IRQ and return the value. OEMInterruptHandler() usually disable the IRQ, to be re-enabled when the driver calls InterruptDone().
5.       Interrupts are re-enabled
6.       The event associated with the SYSINTR is signaled
7.       The scheduler schedules the highest priority thread to run
Copyright © 2009 – Bruce Eitman
All Rights Reserved

author: Bruce Eitman | posted @ Monday, June 08, 2009 8:38 PM | Feedback (0)

Platform Builder: Buildrel and Hard Links


There was an interesting newsgroup post this week that I thought I would take some time to discuss.
The question went something like this:
I have ONE BSP for my board and I build several OSDesign projects against it. When I switch between OSDesigns and run makeimg it fails with the following message “Error: Mismatched time stamp on .rel file for module nk.exe”
When I first read it, I was stumped. This is not an uncommon activity for me. I switch between projects that build against the same BSP often and have never had this problem. But, I have a Developr batch file (see Platform Builder: Using Your Developr Batch File) that I use to set BUILDREL_USE_COPY.
BUILDREL_USE_COPY tells buildrel.bat to copy files to the _FLATRELEASEDIR instead of using hard links. Hard links have some value; they reduce disk usage and speed up the build process. But, they have a downside when building multiple projects against the same BSP. The downside is that the files that are being used during makeimg might not be the files that you built with the project. That downside is a big problem for me, so ever since Platform Builder introduced hard links, I have had BUILDREL_USE_COPY set.
NOTE: The default value for BUILDREL_USE_COPY is not set.
Copyright © 2009 – Bruce Eitman
All Rights Reserved

author: Bruce Eitman | posted @ Friday, June 05, 2009 4:48 PM | Feedback (1)

New Chapter in my Career


As of this week I have changed positions within Eurotech to become a Field Application Engineer (FAE).   This is an exciting new challenge for me, and I look forward to it. 
I spent the last five years working as the Director of Windows CE Software Engineering, managing development at three offices.   This period of my career was rewarding and challenging, very challenging. I have watched the company grow and eventually be bought by a bigger company. My team has architected solutions to manage the ever changing needs of our customers, both internal and external. Our successes have been very rewarding.
It was time for a change, so when the FAE position opened up I asked to be considered.  Yes, moving to the dark side was my idea.  It is an opportunity for me to work more closely with our customers as an FAE reports to the Sales team. Actually, this has been one of my roles at Eurotech since the beginning, so it wasn’t much of a stretch of the imagination to consider me for the FAE position.
Internally, there have been many questions, like:
1.       Why did the company force you into this position? (or variation of that, some just implying the question)
The answer is that the company actually tried to talk me out of it. This was my choice.
2.       How will the Software Engineering team go on without you?
If I thought for a minute that they couldn’t, I wouldn’t make the change. I had a very competent team of Software Engineers, all with many years of experience in embedded software development. They are ready to continue without my direct involvement. My desk in the Akron office isn’t changing, so I am still very close to the action.
3.       Will you continue blogging?
Heck yes. I not only intend to keep blogging, but I suspect that I will have some down time in hotels to do some of it. I also think that the closer relationship to our customers will bring a new perspective to my blog.
4.       Will you be able to maintain your MVP award?
It may be more difficult for me to answer questions in the newsgroups, but I plan to do my best to keep active there. Also my blog doesn’t hurt any. So I think that I will continue to receive the MVP award in the future, but that is up to Microsoft.
Copyright © 2009 – Bruce Eitman
All Rights Reserved

author: Bruce Eitman | posted @ Tuesday, June 02, 2009 10:51 PM | Feedback (5)