VF50 128IT 1.2B eboot 1.3 problem

Until yesterday we were using VF50 colibri modules 1.2A using our production image with eboot 1.3 and wince 6 without problems.
Now we have got some new VF50 colibri modules 1.2B and we are not able to use our production image because, after flashing, the module does not boot at all and the recovery mode must be used to restore the original bootloader (eboot 1.7).
We have also tried to flash just our wince image (nk.bin) using the eboot 1.7 but the result is the same: the module stuck and it must be recovered.
From the VF50 module revision history it seems that from release 1.2A to 1.2B there is a NAND flash change. Is there any issue concerning the VF50 1.2B NAND flash that can result into the problem we are facing?

According to Colibri VF50 128MB IT V1.2B PCN :

4.2. Software
− WinCE: The new NAND flash device reports a different product ID and device name. The Toradex
WinCE BSP checks the product ID and therefore requires a BSP update. The following BSP
version provides support for the new flash. Customers are required to update their BSPs
accordingly.
- WinCE: BSP V1.5

So you have to update eBoot and WinCE image at least to 1.5 version, though we highly recommend to use latest 1.7 release.

What a bad news! We have to build and validate a new production image :cry:

If your app doesn’t require a custom WinCE image you can

  • Flash Toradex WinCE image 1.7
  • install your app
  • Do all registry and filesystems mods
  • Backup everything using the UpdateTool included in 1.7 image.

Then you can use created backup for factorey programming. Please note that you must use the save version of UpdateTool you created backup image. Ie you can do direct update from 1.5 to 1.7 but don’t run an Update tool included in 1.5 image. Use an UpdateTool from 1.7 image instead.

After several hours testing and debugging, here is an issues brief list

Our application

  • Pit #7 interrupt stops working after a call to the system function ‘SetLocalTime’

Toradex WinCE image 1.5

  • Update Tool 7.3.0 (2.0) generates an empty registry backup file
  • RegEdit does not allow to delete registry keys: error “Can’t query key ‘…’”

Toradex WinCE image 1.7

  • Ethernet ports do not work
  • RegEdit does not allow to delete registry keys: error “Can’t query key ‘…’”

Could you please specify WInCE version you are using and exact repro steps?

We are using WinCE 6.0

PIT #7 interrupt stops working after a call to the system function SetLocalTime

On WinCE 6.0 with BSP 1.3beta4 the following sample code works fine, while with BSP 1.5 and newer does not.

#include <windows.h>
#include "coproc.h"
#include "MapMem.h"
#include "int.h"
#include "int_vyb.h"

HANDLE hEvent, hEventPIT;
HANDLE hIrqThread;
HANDLE hIntr = NULL;
BOOL threadStatus = 1;
DWORD * pCCM_CCGRn;
DWORD * pPIT_MCR;
DWORD * pPIT_LDVALn;
DWORD * pPIT_CVALn;
DWORD * pPIT_TCTRLn;
DWORD * pPIT_FLAGn;
int g_count = 0;

void PitIrqThread(DWORD *sysirq);

int WINAPI WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdLine, int cmdShow)
{
    int result = 0;
    HANDLE hMapReg = NULL;
    DWORD sysIrq, sysIrqPIT;
    int nCG = 23;
    int nCCGR = nCG >> 4;
    int nPit = 7;
    SYSTEMTIME sysTime;
    BOOL bResult;

    // Initialize MapReg Library
    hMapReg = Map_Init();
    if (hMapReg == NULL)
    {
        printf("ERROR:: MapReg init function");
        result = -1;
        goto fail_01;
    }
    
    // Map CCM_CCGRn
    // CCM_CCGRn Address: 4006_B000h base + 40h offset + (4 × i)
    pCCM_CCGRn = (DWORD *)Map_OALPAtoVA(0x4006B000 + 0x00000040 + (4 * nCCGR), FALSE);

    // Map PIT registers
    // MCR Address: 4003_7000h
    pPIT_MCR = (DWORD *)Map_OALPAtoVA(0x40037000, FALSE);
    // LOAD Address: 4003_7000h base + 100h offset + (16 × i)
    pPIT_LDVALn = (DWORD *)Map_OALPAtoVA(0x40037000 + 0x00000100 + (16 * nPit), FALSE);
    // CVAL Address: 4003_7000h base + 104h offset + (16 × i)
    pPIT_CVALn = (DWORD *)Map_OALPAtoVA(0x40037000 + 0x00000104 + (16 * nPit), FALSE);
    // CTRL Address: 4003_7000h base + 108h offset + (16 × i)
    pPIT_TCTRLn = (DWORD *)Map_OALPAtoVA(0x40037000 + 0x00000108 + (16 * nPit), FALSE);
    // FLAG Address: 4003_7000h base + 10Ch offset + (16 × i)
    pPIT_FLAGn = (DWORD *)Map_OALPAtoVA(0x40037000 + 0x0000010C + (16 * nPit), FALSE);

    // Initialize interrupt Library
    hIntr = Int_Init();
    if (hIntr == NULL)
    {
        printf("ERROR:: interrupt init function");
        result = -1;
        goto fail_02;
    }

    // Create an Event for PIT
    hEventPIT = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (hEventPIT == NULL)
    {
        printf("ERROR:: Create Event for PIT failed number %d\r\n", GetLastError());
        result = -1;
        goto fail_03;
    }
    // Get the system interrupt for the corresponding PIT Irq number
    sysIrqPIT = Int_RequestSysInterrupt(hIntr, IRQ_PIT);
    // Initialize PIT interrupt
    Int_InterruptInitialize(hIntr, sysIrqPIT, hEventPIT, NULL, 0);

    // Create an Event
    hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (hEvent == NULL)
    {
        printf("ERROR:: Create Event failed number %d\r\n", GetLastError());
        result = -1;
        goto fail_04;
    }
    // Get the system interrupt for the corresponding Irq number
    sysIrq = Int_RequestSysInterrupt(hIntr, TIMER_IRQ(nPit));
    // Initialize interrupt
    Int_InterruptInitialize(hIntr, sysIrq, hEvent, NULL, 0);

    // Create thread to handle Interrupt event
    hIrqThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PitIrqThread, &sysIrq, 0, NULL);

    // Initialize CCM_CCGRn
    printf("CCM_CCGR%d = 0x%08lX \r\n", nCCGR, *pCCM_CCGRn);
    //*pCCM_CCGRn &= ~((DWORD)0x03 << (2 * (nCG & 0x0F)));
    //printf("CCM_CCGR%d = 0x%08lX \r\n", nCCGR, *pCCM_CCGRn);
    //*pCCM_CCGRn |= ((DWORD)0x03 << (2 * (nCG & 0x0F)));
    //printf("CCM_CCGR%d = 0x%08lX \r\n", nCCGR, *pCCM_CCGRn);

    // Initialize PIT timer
    // *pPIT_MCR = 0x00000006;
    *pPIT_TCTRLn = 0x00000000; // Disable timer
    *pPIT_LDVALn = 0x007FFFFF; // Load timer value
    *pPIT_FLAGn = 0x00000001; // Clear TIF flag
    *pPIT_TCTRLn = 0x00000002; // Set TIE
    *pPIT_TCTRLn |= 0x00000001; // Set TEN
    *pPIT_MCR = 0x00000000;

    // Get current time
    GetLocalTime(&sysTime);

    printf("GetLocalTime(), Time: %02d:%02d%:%02d.%03d  Date: %02d/%02d/%04d\r\n",
        sysTime.wHour, sysTime.wMinute, sysTime.wSecond, sysTime.wMilliseconds,
        sysTime.wDay, sysTime.wMonth, sysTime.wYear);

    printf("Enter key to set time\r\n");
    getchar();

    // Change something
    sysTime.wMilliseconds = 0;
    sysTime.wSecond = 0;
    // Set current time
    bResult = SetLocalTime(&sysTime);

    printf("SetLocalTime() = %s, Time: %02d:%02d%:%02d.%03d  Date: %02d/%02d/%04d\r\n",
        bResult ? "OK" : "FAILED",
        sysTime.wHour, sysTime.wMinute, sysTime.wSecond, sysTime.wMilliseconds,
        sysTime.wDay, sysTime.wMonth, sysTime.wYear);

    // Get current time
    GetLocalTime(&sysTime);

    printf("GetLocalTime(), Time: %02d:%02d%:%02d.%03d  Date: %02d/%02d/%04d\r\n",
        sysTime.wHour, sysTime.wMinute, sysTime.wSecond, sysTime.wMilliseconds,
        sysTime.wDay, sysTime.wMonth, sysTime.wYear);

    printf("Enter key to Exit Irq test\r\n");
    getchar();

    *pPIT_TCTRLn = 0x00000000;  // Disable timer
    Sleep(1000);

    threadStatus = 0;
    SetEvent(hEvent);
    Sleep(1000);

    // It is very important to deinitalise the interrupt, otherwise it will not work the next time you start the program
    Int_InterruptDisable(hIntr, sysIrq);
    Int_ReleaseSysIntr(hIntr, sysIrq);
    CloseHandle(hEvent);
fail_04:
    Int_InterruptDisable(hIntr, sysIrqPIT);
    Int_ReleaseSysIntr(hIntr, sysIrqPIT);
    CloseHandle(hEventPIT);
fail_03:
    Int_Deinit(hIntr);
fail_02:
    Int_Deinit(hMapReg);
fail_01:

    Sleep(1000);

    return 0;
}

void PitIrqThread(DWORD *sysirq)
{
    DWORD lpdwExitCode;
    while (threadStatus)
    {
        if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, INFINITE))
        {
            g_count++;
            if ((g_count % 20) == 0)
                printf("IRQ Trigger number of %d \r\n", g_count);
            // *pPIT_FLAGn = 0x00000001; // Clear TIF flag
            Int_InterruptDone(hIntr, *sysirq);
        }
    }
    printf("IRQ Trigger number of %d \r\n", g_count);
    printf("Close Thread \r\n");
    if (hIrqThread != NULL)
    {
        GetExitCodeThread(hIrqThread, &lpdwExitCode);
        // Exit Thread
        ExitThread(lpdwExitCode);
        hIrqThread = NULL;
    }
}

Hi @gscotti,

Could you test to find out at what exact BSP verision the issue starts to happen.
Is it still working with 1.3 final or 1.4?

Dear Germano,

I’m sorry, I can’t do this test but I think you can do it by yourself using the sample source code with your Toradex WinCE images. Just in case, find attached the compiled sample code.

With Kind Regards
Int_Demo.exe (10.5 KB)

Hi @gscotti ,

I found out why the your code does not work.
It has nothing to do with the SetLocalTime() function… just very indirectly.
When you call SetLocalTime() rtcsync.exe is executed to sync the time to the external RTC chip.
The I2C uses the function DelayuS() to wait a specific us amount of time… and this function uses PIT Timer #7 which conflicts with your software.
I have no idea why this was working on older BSP versions… the DelayuS() function was always using timer #7 and it’s not just i2c that uses this, also ac97 audio, serial port, USB and ethernet uses this function.
I would suggest to change your code to use another timer.

To do a quick test you can try to disable rtcsync.exe from loading at startup (in registry under HLKM\Init). I tested and it seems to work even with you prebuilt executable… but as i said, it could be that in some other situation the DelayuS() function will be called from other parts of the OS.

Dear @germano.tx ,

it is sad and hard to believe what you say.

We start using the Colibri VF50 V1.2A late in 2015.
At that time there have been several BSP releases, some of those with new feature related to the PIT:

  1. “PIT Timers didn’t call IST”
  2. “Use ARM timer instead of PIT for scheduling and other timing-related tasks in the BSP”

We had an issue related to WC-2581 (at the time, it was tracked as “issue #9134”),
see “After ISSUE #9134 (BSP V1.3beta1) PIT interrupt stop working”,
and nobody from Toradex, neither @luka.tx nor @valter.tx, signaled us we were doing wrong using the PIT timer #7.

Now, can you please indicated us which PIT timer it is safe to use “forever”?

With Kind Regards
G. Scotti

PS: there are still other pending issues, please see.

Hi @gscotti,

Unfortunately neither Luka nor Valter work at Toradex anymore so i cannot comment on what they told you. I just checked the source code changes and saw that the implementation of the DelayuS() function was not changed since the very first release. And this function is using PIT Time #7. Most probably they forgot to update the code when the scheduling was changed from PIT to Arm timers.
What is quite surprising for me is that it started being a problem only with newer images for you… or did you just not use the time related functions so far?
Anyway the easiest workaround for you at the moment would be to just use an other PIT timer number.
I chekced the whole BSP Source code to see where we might use any other PIT channels and i did only find a reference in the CSPDDK.dll which implements the DelayuS() function that is then used in many other places. The CSPDDK.dll also implements other functions to configure and manage other PIT channels but they are not used anywhere else in the BSP.
But i found a little BUG in the implementation of DelayuS() in CSPDDK.dll that will mistakenly also access the PIT Timer #1 in addition to PIT Timer #7
So you can use any other PIT Timer other than #1 and #7.

The Can’t Query Key error is most probably beacause you’re trying to delete a Key that is in use (loaded driver?). Keys that are in use cannot be deleted.

Ethernet ports not workting: You wrote ports, are you using dual ethernet ports? i guess you have some special registry settings… i guess the setings you’re using conflict with the BSP default registry settings, can you send me your settings? Or do you have problems with the default ethernet port?

Update Tool generates an empty backup: Can you elaborate a bit more: What are you trying to backup? Regisry, FileSystem, config block? Where are you trying to save it to? \Flashdisk is not a good location to save it as it will conflict flash library accesses with filesystem accesses. Do you get any errors?