This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Timers not working when using C++?

So. After countless hours of messing around, reading SDK, examples and stuff I'm begginning to feel kind of frustrated. I want a microsecond timer. For that I tried a number of different approaches: app_timer, timer driver API and accessing the timers directly. So far app_timer seems to be the only one that worked, but it lacks in resolution I need.

Approach 1:

nrf_drv_timer_t timerThing = NRF_DRV_TIMER_INSTANCE(1);

void timerHandler(nrf_timer_events_t event)
{
	if(event == NRF_TIMER_EVENTS_COMPARE0) log("time!\r\n");
}

void main()
{
	log("init\r\n");
	uint32_t ticks, ms = 2000;
	
	nrf_drv_timer_init(&timerThing, NULL, timerHandler);
	ticks = nrf_drv_timer_ms_to_ticks(&timerThing, ms);
	nrf_drv_timer_extended_compare(&timerThing, NRF_TIMER_CC_CHANNEL0, ticks, NRF_TIMER_SHORTS_COMPARE0_CLEAR_MASK, true);
	nrf_drv_timer_enable(&timerThing);
	
	while(1);
	return 0;
}

I looked into 'examples/peripheral/timer', basically copied the code just to get it running. Well.. The handler IS called just fine, the problem however is the fact that it's being called constantly. It doesn't matter what value I set for 'ms' variable. I checked the value returned by ms to ticks conversion function and it appears to be correct.

So I started to look around the devzone and I noticed that people were usually using these timers directly (if what I'm saying makes any sense).

volatile bool foobar = false;

void TIMER1_IRQHandler()
{
    if(NRF_TIMER1->EVENTS_COMPARE[0])
    {
        NRF_TIMER1->EVENTS_COMPARE[0] = 0;
        foobar = true;
    }
}

void uartEventHandler(app_uart_evt_t *event) {}

int main()
{
    uint32_t errorCode;
    
    app_uart_comm_params_t uartParams =
    {
        RX_PIN_NUMBER,
        TX_PIN_NUMBER,
        RTS_PIN_NUMBER,
        CTS_PIN_NUMBER,
        APP_UART_FLOW_CONTROL_DISABLED,
        false,
        UART_BAUDRATE_BAUDRATE_Baud115200 // 57600 // 115200
    };

    APP_UART_FIFO_INIT(&uartParams, 32, 256, uartEventHandler, APP_IRQ_PRIORITY_LOW, errorCode);
    
    debugOut("Hello World!\r\n");
    
    NRF_TIMER1->EVENTS_COMPARE[0] = 0;
    NRF_TIMER1->EVENTS_COMPARE[1] = 0;
    NRF_TIMER1->EVENTS_COMPARE[2] = 0;
    NRF_TIMER1->EVENTS_COMPARE[3] = 0;
    
    NRF_TIMER1->TASKS_STOP  = 1;
    NRF_TIMER1->MODE        = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos;
    NRF_TIMER1->BITMODE     = TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos;
    NRF_TIMER1->PRESCALER   = 9;
    NRF_TIMER1->TASKS_CLEAR = 1;
    NRF_TIMER1->CC[0] = 31250;
    NRF_TIMER1->INTENSET    = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;
    NRF_TIMER1->SHORTS      = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
    NVIC_EnableIRQ(TIMER1_IRQn);
    NRF_TIMER1->TASKS_START = 1;
    
    while(1)
    {
        if(foobar)
        {
            debugOut("foo\r\n");
            foobar = false;
        }
        else debugOut("no\r\n");
    }
    
    return 0;
}

This at first wasn't working. It appeared as if it got stuck inside the interrupt or something. After compiling it with Keil it worked at first but then I did something that made it stop. Now I can't get it to work again:

image description

I'm obviously doing something very wrong, I'm just unable to find out what exactly it is. What am I missing here? Please forgive me if it's something rather silly, I'm still trying to learn the way everything works here.

EDIT:

I found something interesting. This is the code that orginally worked: http://pastebin.com/CGGxRLhs

It's C. After putting in in a .cpp file (compiling as C++) it doesn't work. Putting in in a .c file makes it work just fine...

  • I saw a comment about Keil not doing more than 32kB but I don't see it now - that code is at most 1.5kB, so not sure why keil thinks it's bigger.

  • Yeah, unfortunately that's not it. I'm still not getting anything :( Infact, it still looks like it's getting interrupted after a few milliseconds.

  • other things to try - put the logging back inside the interrupt handler but also in there disable the IRQ and disable the interrupt, then you'll get it once and once only. Or perhaps set up a counter for 100 and after 10 trips through the handler, log one message then turn it off.

    I still think your timer (with the EVENTS_COUNTER[0] being properly cleared) is working fine but you have such a frequency of logging going on that bit's not working properly (although it ought to be). So cutting the interrupt down to one only or reducing the frequency massively might help you out a bit.

  • How do I disable the interrupt though? Unless just doing "NVIC_DisableIRQ(TIMER1_IRQn);" is enough

  • just one other thing to do in your code before you turn the timer on, clear the event there too, it may start already at 1 (this is where debuggers help). The slowest you can get is prescaler of 15, count of 65535 which ought to be 134 seconds. If you have lots of patience you could try that.

    I just don't see what you're doing wrong here, this stuff works and this is an insanely simple example too, timers work in conjunction with other things and in way more complicated situations.

Related