Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autotrigger timing #16

Open
jfedor2 opened this issue Oct 8, 2024 · 0 comments
Open

Autotrigger timing #16

jfedor2 opened this issue Oct 8, 2024 · 0 comments

Comments

@jfedor2
Copy link
Contributor

jfedor2 commented Oct 8, 2024

I was happy to discover this project as I think the community could really use a standardized standalone latency testing tool.

That said, upon taking a closer look, because of how the autotrigger timing is implemented, I don't think it gives meaningful results in its current state.

If we want to use the average pin-toggle-to-USB-packet time as the primary metric, we have to be really conscious of when the GPIO pin toggle occurs. Because of the periodic nature of USB, not only do we need to know the precise time when it occured, but when doing, say, a thousand random samples with the intent of measuring the pin-to-USB times and averaging them, the pin toggle times need to be uniformly distributed over the polling interval. Otherwise, the average will be influenced by the uneven distribution, not (just) by the characteristics of the device under test.

Looking at the code, the issue is acknowledged, but not really addressed in a satisfactory manner:

void xlat_auto_trigger_action(void)
{
    // random delay, such that we do not always perfectly align with USB timing
    srand(xTaskGetTickCount());
    int val = rand() & 0xFFF;
    for (volatile int i = 0; i < val; i++) {
        __NOP();
    }
    HAL_GPIO_WritePin(ARDUINO_D11_GPIO_Port, ARDUINO_D11_Pin, auto_trigger_level_high ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

This nop loop results in a maximum delay of around 140us, which I guess is near the duration of a High Speed microframe, but it would really need to be exactly equal to it to even work for 8000Hz devices, not to mention anything below that. If there's any alignment or synchronization between the timing at which the xlat_auto_trigger_action function is called and the USB frame timing, and it seems that there is, the results will mostly be influenced by this. If a perfect zero-latency device reports at 1ms intervals and all of our pin toggles occur within the 100us window after the data transfer occurs, then we will get an average pin-to-USB latency of around 900-1000us, even though in reality it's somewhere near 500us.

One might be tempted with a solution that goes something like this:

uint32_t wait_until = xlat_counter_1mhz_get() + (rand() % 1000);
while (xlat_counter_1mhz_get() < wait_until);

But while this would be better than the current situation, it still has certain issues. Whenever a higher priority thread or an interrupt handler run at exactly the time we want to trigger the GPIO pin, we have to wait until our thread is active again, resulting in a gap within the USB frame near the SOF packet, giving us non-uniform distribution and again influencing the average latency time.

I think we should look into using some kind of hardware functionality of the microcontroller to trigger the GPIO pin at a given time, ensuring uniform distribution of the samples and protection from our thread being preempted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant