Hi Nordic,
I am implementing a micros() in the arduino using nrfx driver.
Below is test code and I got some questions.
#include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/devicetree.h> #include <zephyr/types.h> #include <zephyr/drivers/gpio.h> #include <zephyr/sys/util.h> #include <zephyr/logging/log.h> #include <zephyr/pm/device.h> #include <zephyr/sys/poweroff.h> #include <zephyr/sys/util.h> #include <nrfx_timer.h> #include <stdio.h> // Include for printf (or use printk for Zephyr) #define NRFX_LOG_MODULE EXAMPLE #define NRFX_EXAMPLE_CONFIG_LOG_ENABLED 1 #define NRFX_EXAMPLE_CONFIG_LOG_LEVEL 3 #include <nrfx_log.h> #define TIMER_INST_IDX 1 // Timer instance static nrfx_timer_t timer = NRFX_TIMER_INSTANCE(TIMER_INST_IDX); // Timer handler static void timer_handler(nrf_timer_event_t event_type, void *p_context) { printk("timer_handler() \n"); if (event_type == NRF_TIMER_EVENT_COMPARE0) { char *p_msg = p_context; printk("Timer finished. Context passed to the handler: >%s<", p_msg); // NRFX_LOG_INFO("Timer finished."); } if (event_type == NRF_TIMER_EVENT_COMPARE1) { char *p_msg = p_context; printk("Timer finished. Context passed to the handler: >%s<", p_msg); // NRFX_LOG_INFO("Timer finished."); } } // Initialize timer for high-resolution timing uint32_t ticks; void timer_init(void) { nrfx_err_t status; /* configure IRQ */ IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TIMER_INST_GET(TIMER_INST_IDX)), IRQ_PRIO_LOWEST, NRFX_TIMER_INST_HANDLER_GET(TIMER_INST_IDX), 0, 0); /* get base frequency of given timer (in our case timer-0) */ uint32_t base_frequency = NRF_TIMER_BASE_FREQUENCY_GET(timer.p_reg); nrfx_timer_config_t config = NRFX_TIMER_DEFAULT_CONFIG(base_frequency); config.bit_width = NRF_TIMER_BIT_WIDTH_32; // 32-bit timer config.p_context = "Some context"; // printk("config.frequency: %d\n", config.frequency); // note: .frequency represents base frequency not a prescaler factor // config.frequency = NRF_TIMER_FREQ_1MHz; // Set timer frequency to 1 MHz (1 us resolution) // config.frequency = NRF_TIMER_FREQ_500kHz; // Set timer frequency to 1 MHz (1 us resolution) // config.frequency = NRF_TIMER_FREQ_250kHz; // Set timer frequency to 1 MHz (1 us resolution) // config.frequency = NRF_TIMER_FREQ_125kHz; // Set timer frequency to 1 MHz (1 us resolution) /* init timer */ status = nrfx_timer_init(&timer, &config, timer_handler); if (status != NRFX_SUCCESS) { printk("Timer initialization failed: %d\n", status); // Use printk() if in Zephyr return; } nrfx_timer_clear(&timer); /* configure prescaler */ nrf_timer_prescaler_set(timer.p_reg, NRF_TIMER_FREQ_1MHz); // nrf_timer_prescaler_set(timer.p_reg, NRF_TIMER_FREQ_16MHz); // Convert 3,000,000 microseconds (3 seconds) to ticks // uint32_t ticks = nrfx_timer_us_to_ticks(&timer, (uint32_t)3000000); ticks = nrfx_timer_us_to_ticks(&timer, (uint32_t)3000000); printk("ticks: %d\n", ticks); // nrfx_timer_extended_compare(&timer, NRF_TIMER_CC_CHANNEL0, ticks, NRF_TIMER_SHORT_COMPARE0_STOP_MASK, true); nrfx_timer_extended_compare(&timer, NRF_TIMER_CC_CHANNEL1, ticks, NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK, true); // nrfx_timer_clear(&timer); nrfx_timer_enable(&timer); } // Get current time in microseconds uint32_t micros(void) { // Capture the current timer value return nrfx_timer_capture(&timer, NRF_TIMER_CC_CHANNEL0); } int main(void) { set_led_color_cyan(); /* init button irq */ int ret = init_button_irq(); if (ret != 0) { printk("Error init_button_irq()\n"); return 0; } timer_init(); while (1) { uint32_t time_us = micros(); printf("Current time: %u us (%u)\n", time_us, ticks); // Use printk() if in Zephyr // if (time_us > ticks) // { // nrfx_timer_disable(&timer); // } // Add a delay to avoid flooding the output k_msleep(100); // Sleep for 100 milli second, if using Zephyr // k_msleep(1000); // Sleep for 1 second, if using Zephyr } }
[Question 1]
Timer 1 and Timer 2 works perfectly as I expected. You can check it on the Segger RTT Viewer (upper image)
However, Timer 0 doesn't cleared correctly and just keep increasing it's value. Can you please chek on your side?
FYI, I am using SPIM and TWIM simultaneously. Could it impact on Timer 0's unexpected behavior?
[Question 2]:
A timer could have multiple C/C (=Capture and Compare) channel (=register).
So by having multiple channel, we can capture (=read timer value) and configure compare mode (=configure interrupt on/off or clear/stop a timer).
Please see below method's signature.
// nrfx_timer_extended_compare(&timer, NRF_TIMER_CC_CHANNEL0, ticks, NRF_TIMER_SHORT_COMPARE0_STOP_MASK, true);
nrfx_timer_extended_compare(&timer, NRF_TIMER_CC_CHANNEL1, ticks, NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK, true);
Is there any case that 2nd arg (=channel) and 3rd arg (=action) not to be the same channel?
If not it's prone to make a human error on the application side.
How do you think?