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...

  • So the only thing I instantly see wrong there is TIMER1 and 2 don't support anything other than 16 bit mode (it's documented but it's hard to find). I'm not entirely sure what happens when you put them into 24 or 32 bit mode, it may well be that they set up the target count as 2,000,000, compare it on a 24-bit basis but never get there because the counter rolls over after 16 bits.

    So I'd try using a smaller number for a start see if that works.

    I see you said you tried it with TIMER0, that should work, are you sure when you tried it that you changed every instance of TIMER1 to TIMER0, including the IRQ handler, and the interrupt enable, it's very easy to miss one?

    You could run that code and hit break after a few seconds to see where you are, hopefully in the while() loop. Then take a look at the TIMER registers and see what they're giving you.

    You need to clear the COMPARE event or else the IRQ will keep firing, which isn't your problem yet.

    And just for testing purposes whilst doing other things, comment out the short, I'm fairly sure that doesn't affect the COMPARE event but getting down to the bare minimum is always a good idea.

    I don't think you need to start the HF Clock, but it's ok to do so.

    For consistency and to get into good habits I'd do

    NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos;
    

    It's zero anyway but I try to use this pattern every time so I don't get tripped up one day.

    The rest looks fine - I would expect that code, when restricted to 16 bit mode, to work.

    Please post what you find - if it doesn't work I'll compile and run it myself, it should do.

    EDIT:

    Actually I was bored this afternoon and did try it out and it works fine. Setting the 2,000,000 compare into TIMER1 just sets the lower 16 bits and setting it to 24bit mode doesn't seem to matter. I get (very) regular interrupts.

    I cut n' pasted your code directly into a new project, changing only log() to a Segger RTT log and adding the header imports I needed. I made no other changes, it works.

    Changing everything to TIMER0 I get the 2 second ticks you'd expect in 24 bit mode.

    So are you sure it's not working? What makes you think it's not, not logging? Are you sure log() does what you think it does and isn't just linking in the log() function from the math library? Have you put a breakpoint in the IRQ handler to see if it goes in there?

  • Yes, I'm sure the log function is working properly, which is printing stuff over UART. That part works. I think the timer is not working, because I'm not getting any output that would imply that it has successfully entered the interrupt. Unfortunately I don't have any proper debugging software, UART messages is the only thing I've been relying on so far. Anyway, if you say it should work I'll experiment a little bit more, maybe simply UART won't work on interrupts or something like that? I'll install Keil and try to debug it properly once I get back to it. Cheers

  • It definitely does work. I assume there is more code somewhere to set up the pins for the uart logging which you didn't show.

    At the least clear the event inside your interrupt handler

    EVENTS_COMPARE[0] = 0;
    

    Not knowing how your log function works, if it's interrupt based you are currently never getting out of the timer interrupt because the event doesn't get cleared.

    And yes doing this without tools is a recipe for frustration in the extreme. so getting them set up would help you a lot.

  • the log function is simply vsprintf and app_uart_put in a loop, nothing else. It works, it prints out stuff, so I doubt it has something to do with UART pins.

  • Well as I said, if that's all your code then you haven't actually set the uart up, there's no app_uart_init there so app_uart_put() won't do anything, well it won't do anything useful. You need to call the initialization function before you try using the UART, from reset the chip isn't going to know what pins you're using for UART comms or enable the UART irq or do anything else.

    If that isn't all your code and you are initializing the uart somewhere then I'll tell you one more time, you need to clear the event in the IRQ handler. Now I'm back home I can see that app_uart is interrupt driven, I have no idea what priority you gave it when you initialise it, if you initialise it, if it's lower than the default TIMER1 priority which is 0, the highest there is, then you will never get out of the timer interrupt unless you clear the event and the uart will never get to send anything.

Related