RLP Tasks time off by factor 2 on G120

I’m using Tasks in RLP on a G120.
What I do is I call Task.Initialize, and then Task.ScheduleTimeOffset with a time of 20 micro seconds.
1st thing in the callback I call Task.ScheduleTimeOffset with 20 micro seconds again.
Then I toggle an output at the beginning and at the end of the callback.
By this I can see the result on my scope.
The callback is only called every 40 micro seconds.
The duration of the callback is less then 10 micro seconds.

The SPI clock (initialized in managed code) is correct at 5MHz.

The G120 is not overclocked for increased RAM Bandwidth.
isKernelMode is set to RLP_FALSE.

Any ideas what’s wrong here?

Edit: I’m using FW 4.3.6 and Simons RLP in Depth template with Em-Blocks.

Edit 2: it’s getting even worse:
When I set 100 microseconds, I get a cycle time of about 360 micro seconds !?

Edit 3:
In “parallel” I send 6 bytes via UART every 300ms (separate thread with sleep) from managed code.
And there is constant Ethernet traffic (ENC28)

Ok,
I removed everything else from my program.#
Now I get an actual rate of 135 micro seconds when I set 100.
But still: 35% extra time is not what I would expect.
Are Tasks really that load dependent? I thought they would stop everything else.

And here is some code:
C#

private static RLP.NativeFunction _Ltc186XInitSpi;
     private static RLP.NativeFunction _Ltc186XStart;

      public static void InitialzeRlp()
      {
         if(_isInitialized)
            return;
         _isInitialized = true;

         byte[] elfFile = Resources.GetBytes(Resources.BinaryResources.RotaryEncoder_G120_43);
         var elfImage = new RLP.ElfImage(elfFile);
         elfImage.InitializeBssRegion();

        _Ltc186XInitSpi = elfImage.FindFunction("Ltc186xInitSpi");
        _Ltc186XStart = elfImage.FindFunction("Ltc186xStart");
     }

C

void Ltc186xTaskCallback(void *arg)
{
    if (g_Ltc186xSampleCount > 1)
    {
        // setup next task 1st
        RLP->Task.ScheduleTimeOffset(&g_Ltc186xTask, g_Ltc186xTimeOffset);
    }

    if (g_Ltc186xSampleCount < 0x7fffffff)
    {
        --g_Ltc186xSampleCount;
    }
    if (g_Ltc186xSampleCount <= 0)
    {
        // done
        g_Ltc186xValue = (g_Ltc186xValue + Ltc186xReadValue()) >> 1;

        RLP->Task.Abort(&g_Ltc186xTask);
        RLP->PostManagedEvent(g_Ltc186xDoneEventId);
    }
    else
    {
        g_Ltc186xValue = (g_Ltc186xValue + Ltc186xReadValue()) >> 1;
    }
}

int Ltc186xInitSpi(void **args)
{
    g_Ltc186xChipSelectPin = *(int*)args[0];
    int spiPort = *(int*)args[1];

    if(spiPort == 1)
    {
      }
    else if(spiPort == 3)
    {
        g_Ltc186xSpi = LPC_SSP2;
    }
    else
    {
        return 0; // error
    }

    g_Ltc186xChannel = -1;
    g_Ltc186xValue = -1;

    return 1;
}

int Ltc186xStart(void **args)
{
    g_Ltc186xChannel = *(int*)args[0];
    g_Ltc186xSampleCount = *(int*)args[1];
    int sampleRate = *(int*)args[2];
    g_Ltc186xDoneEventId = *(unsigned int*)args[3];

    g_Ltc186xSamplesDone = 0;
    g_Ltc186xTimeout = 0;

    // dummy read to setup ADC and trigger next sample
    Ltc186xReadValue();
    if(g_Ltc186xTimeout != 0)
    {
        return 0;
    }
    RLP->Delay(4); // microseconds

    // read 1st value
    g_Ltc186xValue = Ltc186xReadValue();
    if(g_Ltc186xTimeout != 0)
    {
        return 0;
    }
    --g_Ltc186xSampleCount;

    if (g_Ltc186xSampleCount <= 0)
    {
        RLP->PostManagedEvent(g_Ltc186xDoneEventId);
    }
    else
    {
        g_Ltc186xTimeOffset = 1000000 / sampleRate; // offset is in micro seconds
        RLP->Task.Initialize(&g_Ltc186xTask, Ltc186xTaskCallback, &g_Ltc186xSampleCount, RLP_FALSE);
        RLP->Task.ScheduleTimeOffset(&g_Ltc186xTask, g_Ltc186xTimeOffset);
    }

    return 1;
}

All SPI initialization is done in managed code, since if I do it to the NXP datasheet I do net even get a clock signal.
When I read back the registers after managed init,
LPC_IOCON->P1_1 // MOSI of SSP2
is not configured as SSP pin, only bit 4 (pull up) is set.
And I guess there is more that is not according to the spec for SSP2.

@ Reinhard Ostermeier - When you don’t execute in kernel mode, you get put into the regular NETMF completion list. At that point, you’re essentially a thread with a time slice competing with all other threads in the system. If you have a lot going on, those threads will slow down.

If you execute in kernel mode, I believe you are executed right in the system timer ISR. You’ll want to execute as quickly as possible because you are then blocking the entire system and if you take too long you could lose data.

1 Like

@ John - In the meantime I tried the kernel mode, and then it works (nearly)
I always get an extra time of about 12 micro seconds.
Can I somehow compensate this automatically, or can I assume that this offset is fixed under any circumstances?
I don’t need the sampling rate to be very exact, but … I’m an engineer, not an artist or physicist :wink:

Also: Loosing data when it takes too long:
My callback executes a 16 bit SPI transfer at 5MHz clock plus chip-select.
It takes less then 10 micro seconds in total.
Do you see any problem here?
I could increase the clock rate and reduce my readings to 12 bit if necessary.

One more question:
I was not able to initialize SPI3 (SSP2) in RLP by setting all registers according to the datasheet.
When initializing it from Managed code, and then reading back the registers I can see, that at least LPC_IOCON->P1_1 is not set to 0x14 (SSP2 MOSI + PullUp) as expected, but it is set to 0x10 (PullUp only).
The other pins (P1_0, P1_4) are set to 0x14.
But I guess that this is not the only difference, because after setting the registers in the same way as I read them back, it did suddenly not work after a while. Then I initialized it one more from managed code, and it was working again.
Now I always initialize the SPI from Managed code.
Do you have any explanation for this?

You can’t do microseconds. If this is what you need then you need your own timer interrupt handler

@ Gus - I wanted to get down to a 20 microseconds interval, but the minimum seams to be somewhere around 36 micro seconds.
But since this is still faster then currently needed I’m happy with this.
A sampling rate of 20kHz (which gives Network, UART, … enough time to execute in parallel) is still twice as much as we got on Windows PC with bit banging over a PCI TTL IO card ;D
On some PC’s even the 10kHz are impossible to accomplish nowadays (sleepy PCI bridges I guess).