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

Zephyr Counter Driver Limitations for Short Delay Generation on Ambiq Apollo3 EVB #87539

Open
AlienSarlak opened this issue Mar 24, 2025 · 0 comments
Assignees
Labels
area: Counter bug The issue is a bug, or the PR is fixing a bug platform: Ambiq Ambiq priority: low Low impact/importance bug

Comments

@AlienSarlak
Copy link

An issue has been identified with the use of the Zephyr counter API on the Ambiq Apollo3 microcontroller. When configuring counter0 with clock source 2 CTIMER_CTRL0_TMRA0CLK_HFRC_DIV16, which yields a timer frequency of 3 MHz, the expected timing resolution should be approximately 334 ns. However, attempts to generate short delays using the standard Zephyr counter sample code revealed that the (ISR) is not invoked for delays shorter than approximately 10 µs. This behavior limits the ability to achieve fine-grained timing control, and the underlying cause of this limitation remains unknown to me.

What target platform are you using?

  • Target platform is Ambiq Apollo3 Blue EVB

What have you tried to diagnose or workaround this issue?

  • As a workaround, I used (HAL) directly within the Zephyr environment, bypassing the counter API. This approach enabled the successful generation of precise pulses with durations below 1 µs, including those as short as 334 ns, indicating that the hardware is capable of such resolution.

Furthermore, I observed that setting alarm_cfg.flags = 0 results in deteriorated timing accuracy, while using COUNTER_ALARM_CFG_ABSOLUTE leads to improved precision for delays greater than 50 µs. This result was unexpected, as the default relative alarm mode was initially assumed to provide better accuracy.

To Reproduce
apollo3_evb.overlay:

/ {
    aliases {
        timer0 = &counter0;
        pin0 = &gpio17;
    };

    my_gpio{
        compatible = "gpio-leds";
        gpio17: gpio_17 {
            gpios = <&gpio0_31 17 GPIO_ACTIVE_HIGH>;
        };
    };
};

&counter0 {
    clock-frequency = <DT_FREQ_M(12)>;
    clk-source = <1>;
    status = "okay";
};

&gpio0_31 {
    status = "okay";
};

code: https://github.com/zephyrproject-rtos/zephyr/tree/main/samples/drivers/counter/alarm

modify main.c as:

#include <zephyr/device.h>
#include <zephyr/sys/printk.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/counter.h>
#include <zephyr/drivers/gpio.h>

// Delay in uS
#define DELAY 10
#define ALARM_CHANNEL_ID 0

#if defined(CONFIG_BOARD_APOLLO3_EVB)
#define TIMER DT_ALIAS(timer0)
#define PIN_GPIO DT_ALIAS(pin0)
#else
#error Unable to find a counter device node in devicetree
#endif

// Hardware related devices
const struct device *const counter_dev = DEVICE_DT_GET(TIMER);
const struct gpio_dt_spec gpio_pin = GPIO_DT_SPEC_GET(PIN_GPIO, gpios);

void test_counter_interrupt_fn(const struct device *counter_dev,
                               uint8_t chan_id, uint32_t ticks,
                               void *user_data)
{
    if (gpio_pin_toggle_dt(&gpio_pin) < 0)
    {
        printk("GPIO could not be toggle!\n");
    }
}

int main(void)
{

    // User Data Struct
    struct counter_alarm_cfg alarm_cfg;

    // GPIO

    if (!gpio_is_ready_dt(&gpio_pin))
    {
        printk("device not ready.\n");
        return -ENODEV;
    }

    if (gpio_pin_configure_dt(&gpio_pin, GPIO_OUTPUT_ACTIVE) < 0)
    {
        printk("GPIO Configuration is not supported!\n");
        return 0;
    }


    printk("Counter alarm sample\n\n");

    if (!device_is_ready(counter_dev))
    {
        printk("device not ready.\n");
        return -ENODEV;
    }

    // Free run mode
    counter_start(counter_dev);

    // alarm_cfg.flags = COUNTER_ALARM_CFG_ABSOLUTE;
    alarm_cfg.flags = 0;
    alarm_cfg.ticks = counter_us_to_ticks(counter_dev, DELAY);
    alarm_cfg.callback = test_counter_interrupt_fn;
    alarm_cfg.user_data = &alarm_cfg;

    /* Single shot alarm */
    int err = counter_set_channel_alarm(counter_dev,
                                        ALARM_CHANNEL_ID,
                                        &alarm_cfg);

    if (-EINVAL == err)
    {
        printk("Alarm settings invalid\n");
    }
    else if (-ENOTSUP == err)
    {
        printk("Alarm setting request not supported\n");
    }
    else if (0 != err)
    {
        printk("Unknown Error\n");
    }

    printk("tick = %d\n", alarm_cfg.ticks);
    printk("SLEEP FOREVER .... -_-\n");

    while (1)
    {
        k_sleep(K_FOREVER);
    }
    return 0;
}

prj.conf

CONFIG_LOG=y
CONFIG_GPIO=y

CONFIG_PRINTK=y
CONFIG_COUNTER=y

Expected behavior

With a 3 MHz timer (334 ns resolution), the counter should generate accurate delays. A configured delay of 10 µs should produce a 10 µs pulse, and a 5 µs delay should result in a 5 µs pulse. This precision is expected given the hardware capabilities and timer resolution.

Impact

The lack of precise timing support has effectively blocked further development of my project.

Environment

  • OS: Ubuntu 22.04.4 LTS (Linux kernel 6.8.0-52) (inside a docker container)
  • Toolchain (Zephyr SDK)
  • Commit SHA (1207ccf)

Additional context
Delay of 50 µs when using alarm_cfg.flags = COUNTER_ALARM_CFG_ABSOLUTE;
Image
Delay of 50 µs when using alarm_cfg.flags = 0;
Image

@AlienSarlak AlienSarlak added the bug The issue is a bug, or the PR is fixing a bug label Mar 24, 2025
@nashif nashif added platform: Ambiq Ambiq area: Counter priority: low Low impact/importance bug labels Mar 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Counter bug The issue is a bug, or the PR is fixing a bug platform: Ambiq Ambiq priority: low Low impact/importance bug
Projects
None yet
Development

No branches or pull requests

3 participants