nRF5 SDK v13: nrf_drv_timer extended compare event only triggers for COMPARE1, not COMPARE0 (TIMER3 instance)

Hello Nordic DevZone,

I am having a persistent problem using hardware timers on the nRF52832 with nRF5 SDK v13.

Summary of Issue:

  • I am using NRF_DRV_TIMER_INSTANCE(3) to create a TIMER3 instance.

  • I set up both COMPARE0 (for 1sec interval) and COMPARE1 (for 100ms interval).

  • Only the COMPARE1 event triggers—COMPARE0 never fires.

  • I made sure to avoid hardcoding NRF_TIMER0 and am using TIMER_INSTANCE.p_reg for all register accesses as recommended in similar posts.

  • Interrupts, SHORTS, and compare setup are all being performed with the SDK driver functions and macros.

Troubleshooting attempts:

  • Replaced all direct register access to use appropriate instance pointer.

  • Verified tick values are correct for both channels.

  • Checked that nrf_drv_timer_enable() is called.

  • Handler pointer is correct and COMPARE1 triggers as expected.

  • No error codes returned from API calls.

What am I missing?

  • Is there any known errata or hidden gotcha with configuring multiple COMPARE events using nrf_drv_timer on a TIMER instance other than TIMER0?

  • Is there any additional configuration or sequence needed for COMPARE0 compared to COMPARE1+?

  • Any sample code or checklist known to work for COMPARE0/COMPARE1 on TIMER3 would be appreciated.

Thank you in advance for reviewing and helping resolve this issue.

#define TIMER_INSTANCE_ID 3
static const nrf_drv_timer_t TIMER_INSTANCE = NRF_DRV_TIMER_INSTANCE(TIMER_INSTANCE_ID);

void timer_handler(nrf_timer_event_t event_type, void *p_context)
{
    switch (event_type)
    {
    case NRF_TIMER_EVENT_COMPARE0:
        // never hits
        break;
    case NRF_TIMER_EVENT_COMPARE1:
        // always hits (100ms)
        break;
    }
}

void timer_channel_control(uint8_t channel, bool enable, uint32_t millis)
{
    nrf_timer_cc_channel_t comp_ch;
    nrf_timer_short_mask_t short_msk;
    nrf_timer_int_mask_t int_mask;
    switch (channel) {
        case 0:
            comp_ch = NRF_TIMER_CC_CHANNEL0;
            short_msk = NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK;
            int_mask = NRF_TIMER_INT_COMPARE0_MASK;
            break;
        case 1:
            comp_ch = NRF_TIMER_CC_CHANNEL1;
            short_msk = NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK;
            int_mask = NRF_TIMER_INT_COMPARE1_MASK;
            break;
        default:
            return;
    }

    uint32_t time_ticks = nrf_drv_timer_ms_to_ticks(&TIMER_INSTANCE, millis);
    NRF_TIMER_Type *timer_reg = TIMER_INSTANCE.p_reg;
    if (enable) {
        nrf_drv_timer_extended_compare(&TIMER_INSTANCE, comp_ch, time_ticks, short_msk, true);
    } else {
        timer_reg->INTENCLR = int_mask;
        timer_reg->SHORTS &= ~short_msk;
    }
}

void hw_timer_init(void)
{
    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.frequency = NRF_TIMER_FREQ_62500Hz;
    timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
    timer_cfg.mode = NRF_TIMER_MODE_TIMER;
    timer_cfg.interrupt_priority = APP_IRQ_PRIORITY_LOW;

    ret_code_t err_code = nrf_drv_timer_init(&TIMER_INSTANCE, &timer_cfg, timer_handler);
    APP_ERROR_CHECK(err_code);

    timer_channel_control(0, true, 1000);  // 1s interval, does NOT trigger
    timer_channel_control(1, true, 100);   // 100ms interval, works fine

    nrf_drv_timer_enable(&TIMER_INSTANCE);
}

Parents Reply Children
  • Your COMPARE1 clears the timer, so that COMPARE0 does not trigger.

    Try setting this short_msk to NULL

  • I have changed as you suggested but the the 100 ms timer hit after 1 second every time
    it should be like 10 times 100 ms timer and 1 time 1 second timer hit.

    00> 1 s timer hit
    00> 100 ms s timer hit
    00> 1 s timer hit
    00> 100 ms s timer hit
    00> 1 s timer hit
    00> 100 ms s timer hit
    00> 1 s timer hit
    00> 100 ms s timer hit
    00> 1 s timer hit
    00> 100 ms s timer hit
    00> 1 s timer hit
    00> 100 ms s timer hit
    00> 1 s timer hit
    00> 100 ms s timer hit
    00> 1 s timer hit
    00> 100 ms s timer hit
    00> 1 s timer hit
    00> 100 ms s timer hit


    #define TIMER_INSTANCE_ID 3
    static const nrf_drv_timer_t TIMER_INSTANCE = NRF_DRV_TIMER_INSTANCE(TIMER_INSTANCE_ID);
    void eis_timer_handler(nrf_timer_event_t event_type, void *p_context)
    {
    	switch (event_type)
    	{
    	case NRF_TIMER_EVENT_COMPARE0:
    			uart_logf("1 s timer hit\r\n");
    		break;
    	
    	case NRF_TIMER_EVENT_COMPARE1:
    		uart_logf("100 ms timer hit\r\n");
    		break;
    
    	case NRF_TIMER_EVENT_COMPARE2:
    		break;
    	case NRF_TIMER_EVENT_COMPARE3:
    		break;
    	case NRF_TIMER_EVENT_COMPARE4:
    		break;
    	case NRF_TIMER_EVENT_COMPARE5:
    		break;
    	}
    }
    
    void eis_timer_channel_control(uint8_t channel, bool enable, uint32_t millis) {
        if (channel > 3) return;
    
        nrf_timer_cc_channel_t comp_ch;
        nrf_timer_short_mask_t short_msk;
        nrf_timer_int_mask_t int_mask;
    
        switch (channel) {
            case 0:
                comp_ch = NRF_TIMER_CC_CHANNEL0;
                short_msk = NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK;
                int_mask = NRF_TIMER_INT_COMPARE0_MASK;
                break;
            case 1:
                comp_ch = NRF_TIMER_CC_CHANNEL1;
                short_msk = 0;
                int_mask = NRF_TIMER_INT_COMPARE1_MASK;
                break;
            case 2:
                comp_ch = NRF_TIMER_CC_CHANNEL2;
                short_msk = NRF_TIMER_SHORT_COMPARE2_CLEAR_MASK;
                int_mask = NRF_TIMER_INT_COMPARE2_MASK;
                break;
            case 3:
                comp_ch = NRF_TIMER_CC_CHANNEL3;
                short_msk = NRF_TIMER_SHORT_COMPARE3_CLEAR_MASK;
                int_mask = NRF_TIMER_INT_COMPARE3_MASK;
                break;
            default:
                return;
        }
    
        uint32_t time_ticks = nrf_drv_timer_ms_to_ticks(&TIMER_INSTANCE, millis);
    
        if (enable) {
    		nrf_drv_timer_extended_compare(&TIMER_INSTANCE, comp_ch, time_ticks, short_msk, true);
        } else {
    		NRF_TIMER_Type *reg = TIMER_INSTANCE.p_reg;  // Get correct TIMER peripheral base
    		reg->INTENCLR = int_mask;
    		reg->SHORTS &= ~short_msk;
        }
    }
    void eis_hw_timer_init(void)
    {
        ret_code_t err_code;
    
        // Configure Timer
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
        timer_cfg.frequency = NRF_TIMER_FREQ_62500Hz;      // 62.5 kHz = 16 µs per tick
        timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;      // Supports long delays
    	timer_cfg.mode = NRF_TIMER_MODE_TIMER;
        timer_cfg.interrupt_priority = APP_IRQ_PRIORITY_LOW;
    
        err_code = nrf_drv_timer_init(&TIMER_INSTANCE, &timer_cfg, eis_timer_handler);
        APP_ERROR_CHECK(err_code);
    
        // Enable channels with large delays
        eis_timer_channel_control(0, true, 1000);  // 1 seconds
    	eis_timer_channel_control(1, true, 100);  // 100 ms
    
        nrf_drv_timer_enable(&TIMER_INSTANCE);
    }


  • Hi!

    I then suggest that you keep track of the amount of "100ms" in the eis_timer_handler NRF_TIMER_EVENT_COMPARE1 case, when you get 10 of these, then it's a "1 s timer hit" and also a "100 ms timer"

Related