Arduino Timer

Hello Community!

I am trying to build a custom Arduino MicroBlaze driver that uses the built-in timer library (timer.c). I’m having some issues locating the correct files to include… specifically, in which Xilinx source is the “XPAR_XTMRCTR_NUM_INSTANCES” parameter defined?

Board: Pynq-Z1
Tools:

  • Vitis 2020.2 on Ubuntu 20.04
  • Using VS Code as editor (need to add timer src to includePath)
  • Build using makefiles (copied existing peripheral directory)

Status: The toolflow seems to work fine for most of my usecases so far. I’m able to build and deploy drivers without issue; I am able to get data to and from the Arduino microblaze just fine.

Problem: I’ve discovered that my delay_us() is limited to 10 us (probably because the microblaze is running at 100kHz), but I need at least 1 us resolution.

From the summary above it should be clear that I am only getting 10 us timing resolution when using the “built-in” delay_us() function, but 1 us resolution is needed. Another question I have: is this expected behavior from the dealy_us() function?

XPAR* defines are in the “xparameters.h” file. When you create a MircoBlaze, this file is auto-generated when building the standalone BSP for the MicroBlaze.

Have you changed the clock of the MicroBlaze?
If you look at the code for the timer there will be some overhead associated with the calls to the time. Accuracy s also dependant on the MB clock.

Cathal

Thanks Cathal!

  1. This is what I needed to correct the missing XPAR (I was including the wrong path to xparameters.h, instead of pointing to the BSP path).
  2. You mentioned that “Accuracy s also dependant on the MB clock” – is there an easy way to increase the MB clock to 2MHz? Specifcally, when building everything from the command line… or will I be required to open up the base overlay Vivado project and adjust the MB parameters through the GUI? I am trying to keep everything scripted…

EDIT: It seems I may have misread one of the specs… I see in other docs that the MB clock is at 100MHz, so this is not my issue (I thought I had read it was 100kHz, and I have not changed the clock speed). So I should be able to setup a custom timer to compensate for the ~10us overhead incurred through the dealy_us() timer.

Thanks again for your help!

Adding a scope shot. This is just a simple test where I toggle the Arduino digital output HIGH and LOW, with a delay_us(1) – you can see that it is consistently HIGH (and LOW) for 10us instead of 1us.

Thanks for letting us know the first part is OK. :slight_smile:

No, this is not expected behaviour. delay_us() should give you lower resolution than this. You can see the code for the delay_us() here: PYNQ/timer.c at 3af0198220c1d2909b3b5c20920c102d14126347 · Xilinx/PYNQ · GitHub

How are you calling delay_us()?

Cathal

Here is the simple code I’m using to profile the delay_us() function. This is what produces the waveform in the image I provided above.

// make sure our direction is out
gpio_set_direction(dht11_gpio, GPIO_OUT);
for (u8 k = 0; k <= 20; k++)
{
        gpio_write(dht11_gpio, LOW);
        delay_us(1);
        gpio_write(dht11_gpio, HIGH);
        delay_us(1);
}

Edit: For the generic DHT11 sensor I have, I need to be able to count how many us the pulse is (~22us high is a zero, ~70us high is a one, ~50us low is a break between bits, etc.). This is when I discovered I had a 10us offset for all of my counts…

Just checking back in to see if you have any suggestions/tips as to why I’m not getting 1us timing.

Sorry for delay getting back. I’ve tested and I see ~6.7us pulse width for your loop.
A quick “hack” would be to increase the MB frequency to 200MHz which should half the pulse width, but this might have a wider impact on your design. Really you should rebuild the overlay at this speed to make sure it meets timing. It make break existing code.

Clocks.fclk0_mhz = 200

If you take out the delay and do this:

       gpio_write(gpio0, 0);
       gpio_write(gpio0, 1);

I see a pulse of ~2.2us which I can get down to ~1.1us by increasing the clock.

The lower limit of delay_us() seems to be around ~7us. I’ll try look into this in more detail and post back if I have any more info.

Cathal

I was testing this with the MB magic:

from pynq.overlays.base import BaseOverlay
base = BaseOverlay('base.bit')
%%microblaze base.PMODA
#include <timer.h>
#include <gpio.h>
#include <pmod_grove.h>

void toggle_gpio_us() {
    gpio gpio0 = gpio_open(PMOD_G1_A);
    gpio_set_direction(gpio0, GPIO_OUT);
    int state = 0;
    while (1) {
        gpio_write(gpio0, 0);
        gpio_write(gpio0, 1);
    }
}```

Excellent, Cathal, it is good to see that you are getting similar results. I appreciate you taking the time to dig into this. I will explore increasing the clock speed in the overlay after I have prototyped my system at the lower clock speed (it would be a good experience for me).