This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Capture then clear timer.

Is there a way to capture and clear a timer without being interrupted. This doesn't seem possible with shortcuts. also it looks like theres no capture event with which to trigger a clear task over ppi only compare events, or are the compare events also capture events (as compare registers also seem to be capture registers). What about an event that triggers both capture and clear tasks over ppi? what event could be used for code to trigger both tasks? what about a multiple store operation in asm (specifically I think the STMDB instruction might work, writing 1 on the capture register then zeros on the other registers, then finally a 1 on the clear register) community.arm.com/.../c-c-atomic-operation-on-arm9-and-arm-cortex-m4

	NRF_TIMER2->TASKS_CAPTURE[3] = 1;
	NRF_TIMER2->TASKS_CLEAR = 1;

can be interrupted?

Parents
  • Hi

    Where there is a will there is a way ;)

    In this case I think the simplest solution is to use one of the EGU units and the PPI to trigger both tasks in the timer at the same time.

    The EGU unit is a very simple peripheral that allow you to generate an internal event by activating a corresponding task (in software or hardware). The internal event can then be connected to the PPI controller, and since each PPI channel has a secondary FORK endpoint you can connect it to two different tasks.

    As an example, in the following code I am using PPI channel 0 to connect EGU0 channel 0 to the capture and clear tasks from your example:

    NRF_PPI->CH[0].EEP = (uint32_t)&NRF_EGU0->EVENTS_TRIGGERED[0];
    NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TIMER2->TASKS_CAPTURE[3];
    NRF_PPI->FORK[0].TEP = (uint32_t)&NRF_TIMER2->TASKS_CLEAR;
    NRF_PPI->CHENSET = 1 << 0;
    

    To run the capture and clear operation, simply trigger the task of the EGU like this:

    NRF_EGU0->TASKS_TRIGGER[0] = 1; 
    

    Best regards
    Torbjørn

  • The prescaler is set to 1 MHz. I suspect it's only +/- 1 error Microsecond per capture and clear, but it captures and clears a lot.

    The first objective is to calculate offset and drift between the nRF52 timer and a remote 64 bit monotonic timer (on central) which arrives over ble (units are in microseconds). I calculate offset and a drift over many radio notifications logging the start and end of radio events (outliers get rejected). The algorithm is very complex, and uses arbitrary precision floating point math, but is a known working algorithm and I have tested those portions of the code. I believe the problem I am having lies with the fact that I am attempting to build a 64 bit timer from a 32 bit one and accumulating error over time as we have discussed.

    The second objective (and primary objective) is that the remote device (central) can send a future time stamp (64 bit) over ble to the nordic and have a task executed at that time. It currently does this by receiving the future timestamp, then runs:

    NRF_EGU0->TASKS_TRIGGER[0] = 1; last_cycle_count += (uint64_t) NRF_TIMER2->CC[2];

    next it applies offset and drift to last cycle count, this acquires a estimate of the 64 bit monotonic timer (which is on central) which can be subtracted from the future timestamp. No time is lost as it is accounted for by timer2 which is still running during calculation (it was cleared). The difference is loaded into a compare register on timer2 and triggers the start of a peripheral at that time over ppi (I also have another compare register set up for an error condition if the calculation has taken too long).

    I may be able to refactor things in such a way that the timer can run freely, the problem would be during the second objective then, time would be lost during applying offset and drift and loading the difference in the timer 2 register.

    The solution may be an additional piece of hardware: a 64bit timer ic or perhaps using an second timer as a overflow count register.

    This project has represented huge portions of my time and I very much need help on this issue.

    The Radio Notification Handler (I am using capture register 2 instead of 3 now):
    void SWI1_IRQHandler(void) {
    	m_radio_active = !m_radio_active;
    	if (m_radio_active && last_two_radio_start_events_count > 0) {
    		// Atomic capture and clear of timer 2 to the capture 3 register.
    		NRF_EGU0->TASKS_TRIGGER[0] = 1;
    		last_cycle_count += (uint64_t) NRF_TIMER2->CC[2];
    		last_two_radio_start_events_count--;
    		// 800 because we have 800 us before it starts.
    		last_two_radio_start_events[last_two_radio_start_events_count] = last_cycle_count + 800;
    	} else if (last_two_radio_end_events_count > 0) {
    		// Atomic capture and clear of timer 2 to the capture 3 register.
    		NRF_EGU0->TASKS_TRIGGER[0] = 1;
    		last_cycle_count += (uint64_t) NRF_TIMER2->CC[2];
    		last_two_radio_end_events_count--;
    		last_two_radio_end_events[last_two_radio_end_events_count] = last_cycle_count;
    	}
    }
    
Reply
  • The prescaler is set to 1 MHz. I suspect it's only +/- 1 error Microsecond per capture and clear, but it captures and clears a lot.

    The first objective is to calculate offset and drift between the nRF52 timer and a remote 64 bit monotonic timer (on central) which arrives over ble (units are in microseconds). I calculate offset and a drift over many radio notifications logging the start and end of radio events (outliers get rejected). The algorithm is very complex, and uses arbitrary precision floating point math, but is a known working algorithm and I have tested those portions of the code. I believe the problem I am having lies with the fact that I am attempting to build a 64 bit timer from a 32 bit one and accumulating error over time as we have discussed.

    The second objective (and primary objective) is that the remote device (central) can send a future time stamp (64 bit) over ble to the nordic and have a task executed at that time. It currently does this by receiving the future timestamp, then runs:

    NRF_EGU0->TASKS_TRIGGER[0] = 1; last_cycle_count += (uint64_t) NRF_TIMER2->CC[2];

    next it applies offset and drift to last cycle count, this acquires a estimate of the 64 bit monotonic timer (which is on central) which can be subtracted from the future timestamp. No time is lost as it is accounted for by timer2 which is still running during calculation (it was cleared). The difference is loaded into a compare register on timer2 and triggers the start of a peripheral at that time over ppi (I also have another compare register set up for an error condition if the calculation has taken too long).

    I may be able to refactor things in such a way that the timer can run freely, the problem would be during the second objective then, time would be lost during applying offset and drift and loading the difference in the timer 2 register.

    The solution may be an additional piece of hardware: a 64bit timer ic or perhaps using an second timer as a overflow count register.

    This project has represented huge portions of my time and I very much need help on this issue.

    The Radio Notification Handler (I am using capture register 2 instead of 3 now):
    void SWI1_IRQHandler(void) {
    	m_radio_active = !m_radio_active;
    	if (m_radio_active && last_two_radio_start_events_count > 0) {
    		// Atomic capture and clear of timer 2 to the capture 3 register.
    		NRF_EGU0->TASKS_TRIGGER[0] = 1;
    		last_cycle_count += (uint64_t) NRF_TIMER2->CC[2];
    		last_two_radio_start_events_count--;
    		// 800 because we have 800 us before it starts.
    		last_two_radio_start_events[last_two_radio_start_events_count] = last_cycle_count + 800;
    	} else if (last_two_radio_end_events_count > 0) {
    		// Atomic capture and clear of timer 2 to the capture 3 register.
    		NRF_EGU0->TASKS_TRIGGER[0] = 1;
    		last_cycle_count += (uint64_t) NRF_TIMER2->CC[2];
    		last_two_radio_end_events_count--;
    		last_two_radio_end_events[last_two_radio_end_events_count] = last_cycle_count;
    	}
    }
    
Children
No Data
Related