Response time

Technical discussions around xCORE processors (e.g. General Purpose (L/G), xCORE-USB, xCORE-Analog, xCORE-XA).
RedDave
Member++
Posts: 18
Joined: Fri Oct 05, 2018 4:26 pm

Response time

Postby RedDave » Tue Nov 06, 2018 5:39 pm

I have some code running on an eXplorer kit. The code in question has a GPIO input (p_encoder) and a GPIO output (p_pll).

On every edge of the input I change the output to match. I drive p_encoder with a square wave. What I expect and get when I look at the two signals on an oscilloscope is p_pll is a lagged version of p_encoder.
I would expect this code to run in a couple of cycles and the lag to be some tens of nanoseconds(20/30ns). The lag is 100ns. This is on the upper end of my expectation.

So...
1) Is 100ns expected?
2) Any explanation as to what it is doing in that time?
3) Can it be reduced?

This isn't actually important in this example, but I am building understanding and it may be important in things I do later.

Code: Select all

        select {
        case t when timerafter(next_out) :> now:
//...
            break;
        case p_encoder when pinsneq(enc) :> enc :
            p_pll <: enc;
//...
            break;
        }
User avatar
mon2
XCore Legend
Posts: 1282
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Postby mon2 » Wed Nov 07, 2018 2:35 am

You could study the number of instructions taken to run your code:

https://www.xmos.com/developer/publishe ... tion-level

Code: Select all

https://www.xmos.com/developer/published/how-debug-program-machine-instruction-level


How is the behavior of the following code segment?

Code: Select all

        select {
        case t when timerafter(next_out) :> now:
//...
            break;
        default:
            p_pll <: enc;
//...
            break;
        }
RedDave
Member++
Posts: 18
Joined: Fri Oct 05, 2018 4:26 pm

Postby RedDave » Thu Nov 08, 2018 12:44 pm

Some interesting finds...

Not sure what you meant by the suggested code. With the default block as you had it enc would never change and so the code would do nothing.

I have minimised my code

Code: Select all

void encoder_task()
{
    int enc;

    while(TRUE) {
        select {
        case p_encoder when pinsneq(enc) :> enc :
            p_pll <: 1;
            p_pll <: 0;
            break;
        }
    }
}


This produces the following.
There is now a 60ns lag and a 10ns pulse produced. As well as by minimising the code, I previously got the result by using an [[ordered]] select with the p_encoder case first. Interestingly, changing the SystemFrequency in the XN file has some interesting effects. This result is at the default 500MHz. Changing it to 300 or 600 makes the lag 90ns, with an inconsistent pulse width of 10 or 20ns. 800MHz has a 60ns lag but a 20ns wide pulse. i.e. fast System clock gives a slower response, which is somewhat not expected.
Image

Now, with default:



Code: Select all

void encoder_task()
{
    int enc;

    while(TRUE) {
        select {
        default:
            p_pll <: 1;
            p_pll <: 0;
            break;
        }
    }
}


This produces a strange result. Firstly it produces a reasonable square wave with a 50ns between pulses and a 10ns pulse. This is consistent with the triggered behaviour, implying that the select:case takes 50ns to run. However, every so often (random, but averaging ~30s) it switches mode. The other mode has a 50ns space and 30ns pulse. i.e. the code behaviour is inconsistent, but it appears to run in one of two modes.

Image
Image

So, QUESTIONS:

1) Is this as fast as the response to an event can be?
My next plan is to play with pin clock timing, but I only expect that to shorten the pulse width, not to affect the response time by more than 10ns.
2) Any explanation of the two modes of pulse width in default mode?
Could this be the system clock PLL and the pin PLL coming into and out of sync?
CousinItt
Experienced Member
Posts: 72
Joined: Wed May 31, 2017 6:55 pm

Postby CousinItt » Fri Nov 09, 2018 9:11 pm

You can probably get a faster response by using a buffered output port and using your input as a clock, if that's what you need.
RedDave
Member++
Posts: 18
Joined: Fri Oct 05, 2018 4:26 pm

Postby RedDave » Fri Nov 09, 2018 10:26 pm

My example code isn't quite what I want to do in reality.
I want to do "stuff" on the edge. Outputting the pulse was my way of timing what happens.
However, this advice may be very helpful, thank you CousinItt.
CousinItt
Experienced Member
Posts: 72
Joined: Wed May 31, 2017 6:55 pm

Postby CousinItt » Fri Nov 09, 2018 10:49 pm

No problem. As mon2 says, it's a good idea to check the code the compiler is dropping. If it's not what you'd like you could try changing the optimisation level and see how the object code changes.

The maximum clock frequency is 500 MHz so bets are off if you try to set it higher. What's the clock frequency when you see the dual mode problem? Also, are you running the code using run or flash, and not debug?

And of course you can always drop the select statement from the while loop. This will keep the core busy continually, but the timing should then be solid. You may not want to do this in your final application, but it's fine for investigation.
Gothmag
Experienced Member
Posts: 121
Joined: Wed May 11, 2016 3:50 pm

Postby Gothmag » Sat Nov 10, 2018 7:59 pm

Last time I checked it was also faster to handle storing current value yourself instead of letting the select handle it (":> enc") that's likely where the reduced latency is coming from. I don't know what your program is but setting it thread fast mode on to reduce event latency response. Possibly also high priority which will keep it running 100MHz.
RedDave
Member++
Posts: 18
Joined: Fri Oct 05, 2018 4:26 pm

Postby RedDave » Mon Nov 12, 2018 11:51 am

Answer to your questions:

Optimisation level: Changing optimisation level has made no difference to the result. I have played with this.

Dual width mode: This was observed at 300 and 600MHz settings.

"The maximum clock frequency is 500 MHz": Is this fact actually written anywhere? I spent time looking for the maximum clock frequency. There are various maxima specified for intermediate frequencies. The maximum for which there is an example is 500MHz. But I could not find a maximum specified.

Dropping select: I'll perhaps give this an investigation. I need to get the data out of the core using other events on that select, so this isn't an option for production.

Removing ":> enc": Making this ":> void" and adding "enc = !enc" made no difference to timing.

"thread fast mode on" and "high priority": I will look into these, but online references to them seem few. Any pointers?
RedDave
Member++
Posts: 18
Joined: Fri Oct 05, 2018 4:26 pm

Postby RedDave » Mon Nov 12, 2018 12:08 pm

I added "set_thread_fast_mode_on()" to my task code and it had the effect that
* the pulse width became dual mode (as above). i.e. it was sometimes quicker to reset than previously, but only sometimes.
* the response time became less consistent. This is probably that the worst case was the same, but sometime it was slightly faster.
CousinItt
Experienced Member
Posts: 72
Joined: Wed May 31, 2017 6:55 pm

Postby CousinItt » Mon Nov 12, 2018 12:23 pm

The maximum clock frequency is specified in the XE216 data sheet, parameter f(MAX).

Who is online

Users browsing this forum: No registered users and 27 guests