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

Change in GPIO to start/stop timer and fire interrupt

Hello all,

This is my first post to the developer zone.

I'm creating a product using RFduino, which uses the nRF51822 chip for Bluetooth LE. (See www.rfduino.com/.../rfduino.datasheet.pdf )

I'm an iOS developer with some legacy assembler experience but no experience programming the nRF51822 chip, so I apologize for the simple questions but would appreciate some guidance in finding a solution or at least where to find the documentation that would help me learn.

The product I'm developing measures the speed of a moving object and sends the result to an iOS app via Bluetooth LE for display and analysis . The object is 11 inches in diameter and it passes through a laser beam that is aimed at a phototransistor that is connected to a GPIO pin on the RFduino. I need to be able to accurately measure the time that the object breaks the beam and then calculate the speed as the distance travelled (the diameter of the object, 11 inches) divided by the time (the duration the beam was broken).

My current implementation is not accurate and, therefore, unacceptable. The RFduino provides the Arduino IDE for programming the chip. My loop routine basically watches for the phototransistor GPIO analog value to drop below a threshold value (i.e. laser beam is broken), saves the current time when it does, then watches for the value to rise above the threshold value (i.e. laser beam restored) and, again, save the current time. The duration the beam was broken is calculated as endTime - startTime and the speed is then calculated as 11 inches divided by the duration. Typical durations range from 75-250 milliseconds. My code looks something like this:

void loop() {
	
	currentPhototransistorValue = analogRead(photoResistorPin);
	
	if (currentPhototransistorValue < thresholdValue && beamCurrentlyOn == 1) {
		
		startTime = millis();
		beamCurrentlyOn = 0;

	} else if (currentPhototransistorValue > thresholdValue && beamCurrentlyOn == 0) {
		
		endTime = millis();
		beamCurrentlyOn = 1;
		
		unsigned long duration = endTime - startTime;
		
		float speed = 11.0 / duration;

		// Send speed to iOS app ...

	}

}

The problem is that the duration, as measured by the above method, is not accurate because the BT radio can pre-empt my loop and at random cause a 5 ms or so hiccup. This is unacceptable for my application.

I'm hopeful that a viable solution is to use timer2 of the chip to do the timing. I've looked at some examples here and on the RFduino forum that show how to use the timers, but they all just program the timer to fire at a precise interval. For example, the code below calls the interrupt routine TIMER2_Interrupt every 500 milliseconds.

  NRF_TIMER2->TASKS_STOP = 1;	// Stop timer
  NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;  // taken from Nordic dev zone
  NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit;
  NRF_TIMER2->PRESCALER = 9;	// 32us resolution
  NRF_TIMER2->TASKS_CLEAR = 1; // Clear timer
  // With 32 us ticks, we need to multiply by 31.25 to get milliseconds
  NRF_TIMER2->CC[0] = 500 * 31; // 500 is milliseconds to fire interrupt
  NRF_TIMER2->CC[0] += 500 / 4;  // 500 is milliseconds to fire interrupt
  NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;  // taken from Nordic dev zone
  NRF_TIMER2->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
  attachInterrupt(TIMER2_IRQn, TIMER2_Interrupt);    // also used in variant.cpp to configure the RTC1 
  NRF_TIMER2->TASKS_START = 1;	// Start TIMER

So I'm trying to determine whether or not the following is possible, and if it is, if it will be more accurate than my current implementation.

I need to program timer2 to start when the phototransistor GPIO pin value transitions down past a threshold value, then stop when the pin value transitions up past the threshold value. Then the code needs to call an interrupt in my sketch (like the above sample calls TIMER2_interrupt). Then my interrupt routine (TIMER2_interrupt) needs to read the timer value to get the duration that the beam was broken, then reset the timer to wait for the next transition down of the GPIO pin value.

If this is all possible, could I expect greater precision compared to my current approach? Plus/minus 1 ms for measuring the duration would be acceptable accuracy.

If this is possible, I need to learn how to:

  • start and stop a timer based on the change of the analog value of a GPIO pin
  • read the current timer value
  • reset the timer to wait for the next drop in GPIO pin value

I would be delighted if this is relatively simple and someone could just show me the code. Otherwise I'm happy to learn by reading the appropriate documentation. Note that I don't have the nRF51822 development kit so I don't have access to the resources (documentation and otherwise) that comes with the purchase of the kit.

Whew ... I hope this is a reasonable and clear question. I appreciate your understanding that I'm new to this.

Many thanks to anyone who can offer me some help.

Tim

Related