4 years, 11 months ago.

NRF52 Timers using nrf drivers from the NRF SDK 14.2

I'm using an nRF52_DK and trying the timer peripheral using the nRF52 SDK 14.2. I was hoping to use the nrf drivers without needing to code at the register levels.

The mbed-os version is 5.12.1 and IDE is Visual Studio Code.

The code builds without any error but running halts after calling the nrf_drv_timer_enable() function. The LED's change states if called before the function but not after.

The project is here https://github.com/shane-taurean/nRF52_Timer_Mbed

main.cpp

#include <stdbool.h>
#include <stdint.h>
//#include <my_config.h>
#include <mbed.h>
#include <nrf.h>
extern "C" {
#include "nrf_drv_timer.h"
}
//#include <nrf_delay.h>

DigitalOut led1(LED1);
DigitalOut led2(LED2);

const nrf_drv_timer_t TIMER_LED = NRF_DRV_TIMER_INSTANCE(2);

void timer_led_event_handler(nrf_timer_event_t event_type, void* p_context)
{
    switch (event_type)
    {
        case NRF_TIMER_EVENT_COMPARE0:
            break;

        default:
            //Do nothing.
            break;
    }
}

// -----------------------------------------------------------------------------
int main()
{
    uint32_t time_us = 100; //Time(in microseconds) between consecutive compare events.
    uint32_t time_ticks;
    
    led1 = 0;
    led2 = 0;

    if (NRF_ASSERT_PRESENT == 1)    led2 = 1;

    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    nrf_drv_timer_init(&TIMER_LED, &timer_cfg, timer_led_event_handler);    

    time_ticks = nrf_drv_timer_ms_to_ticks(&TIMER_LED, time_us);
    nrf_drv_timer_compare(&TIMER_LED, NRF_TIMER_CC_CHANNEL0, time_ticks, true);

    nrf_drv_timer_enable(&TIMER_LED); // This line causes problems, everything above it works but nothing below it

    while(1) {        
        wait_ms(500);
        led1 = !led1;
    }
}

I have the following defines in the sdk_config.h file for TARGET_MCU_NRF52832

sdk_config.h snippet

#define TIMER_ENABLED 1
#define TIMER_DEFAULT_CONFIG_BIT_WIDTH 3
#define TIMER2_ENABLED 1

I first tried out TIMER0 and TIMER1 but faced the same problem. I suppose mbed reserves TIMER0 for BLE and TIMER1 for ticker operations, so I'm now trying TIMER2.

The contents of the mbed_app.json in the root directory are

mbed_app.json

{
    "target_overrides": {
        "NRF52_DK": {
            "target.features_remove": ["BLE"],
            "target.uart_hwfc": 0,
            "target.extra_labels_add": ["SOFTDEVICE_NONE", "SDK_14_2"],
            "target.extra_labels_remove": ["SOFTDEVICE_COMMON", "SOFTDEVICE_S132_FULL", "NORDIC_SOFTDEVICE", "NORDIC_CORDIO", "CORDIO", "CORDIO_LL"]            
        }        
    }
}

I suspect the program halts due to ASSERT calls in the nrf_drv_timer_enable() function. I modified the release build profile by removing the "-DNDEBUG" option and changing it to "-DDEBUG_NRF" but it didn't solve the problem.

What could I be doing wrong?

1 Answer

4 years, 11 months ago.

Hi Shane,

I believe Mbed OS has already provided similar function for what you wanna do with nrf_drv_timer, it's called Ticker, please refer here. https://os.mbed.com/docs/mbed-os/v5.12/apis/ticker.html

There is an example there, you just need to set callback and interval, the callback will be called periodically.

Please let me know if you have any questions!

Desmond

Hi Desmond

Thanks for the suggestion. I had tried the Ticker and Timeout before attempting to use the nrf drivers, unfortunately they didn't seem to match my needs.

My actual end application needs to generate a pulse of around 100us without blocking the main loop. It doesn't have to be precisely 100us, but needs be consistent, i.e. Things are fine if I program the Timeout for 100us but instead get 120us with a +/- 3us error consistently. The problem with using the Ticker or Timeout is that the ISR was called inconsistently, quite often overshooting by upwards of 20-50us.

The only way I was able to get a consistent pulse was if I did the following

core_util_critical_section_enter(); 
wait_us(100);
core_util_critical_section_exit(); 

But this blocks the main loop.

So I thought I should try the nRF52 SDK drivers but the test code halts after calling nrf_drv_timer_enable().

posted by Shane Lobo 30 Apr 2019

Actually, you can use thread to complete the function. The documentation is here.

https://os.mbed.com/docs/mbed-os/v5.12/apis/thread.html

You can refer to this example, create a thread and use wait_us(100) in that thread, so that the main thread won't be blocked.

Let me know how it goes.

Thanks,

Desmond

posted by Desmond Chen 02 May 2019

Hi Desmond, sorry for the late reply. I tried using threads and wait_us as suggested.

My implementation using threads is at https://os.mbed.com/users/punkisnail/code/nRF52_Pulse_Threads/ The pulse fluctuates within 113us to 119us. I haven't noticed bigger jumps than that, but during this time, i.e. during the CH_BOOSTING state, the main loop now has iteration counts as low as 11.

My implementations with Timeouts and wait_us are below. https://os.mbed.com/users/punkisnail/code/nRF52_Pulse_Timeouts/ https://os.mbed.com/users/punkisnail/code/nRF52_Pulse_WaitUS/ But with both I sometimes see jumps of more than 20us. For example, using Timeouts the pulse width is mostly 128us, occassionally jumping to 145us or 155us.

I wish I could get the timers running using nRF drivers as in the opening question, just to see the results. Although I still feel threads may be unavoidable once I add BLE features.

Let me know if you have more suggestions.

posted by Shane Lobo 10 May 2019

Hi,

Just wanted to update regarding my findings on getting consistent 100 us pulses, maybe it would help anyone who may have similar troubles.

I think the problem is more to do with the underlying nRF5 SDK or the core itself. I put Mbed aside for the moment and tried things out with Segger Embedded Studio using the SDK, I faced a similar problem there. I came to understand that using plain timer interrupts just wouldn't give the required consistency due to the CPU being busy with other tasks causing a latency in servicing the interrupts. Even changing interrupt priorities did not help much and the latency may be worse with the SoftDevice enabled.

Luckily the nRF52 has peripherals like the PPI and GPIOTE which when used with a TIMER allows to generate more precise pulses without CPU intervention. Alternatively, it has an advanced PWM unit which could be used for more complex waveforms. Unfortunately, I guess this is not currently directly available in Mbed for the nRF52 (I may be wrong), but may be possible to still implement using the HAL drivers or coding at lower levels. Maybe I'll revisit my initial question when I get the time.

posted by Shane Lobo 22 May 2019