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

low power pulsewidth measurement: PPI & lfclk & S210 - some guidance needed

Dear all,

I need to measure a pulse width on a GPIO pin which is in between 100mseconds and 7.2 seconds long without the use of "regular" timers due to low power requirements. I am pretty sure this can be done with PPI and the 32.768 kHz lfclock ( which runs anyway due to S210 use ). But I am simply lost in the examples and driver docs. Especially as I base my work on the bikepower ANT+ example which uses the board support package and app_button. Due to this I cannot copy-paste any code example as this always conflicts with something in the BSP or app_button.

Is there a hint which drivers / app_whatever to "implement" into existing examples that use BSP and app_button to connect a GPIO via PPI to a lsclock counter/timer ?

I "simply" need to start a lsclock counter by a GPIO pin interrupt (Low-High) and stop it by a high-low interrupt. Sadly I seem to be unable to do implement this simple task into the existing example code. As my max pulsewidth is > 10 seconds, a 16 bit counter is not sufficient @ 32.768 kHz clock. I am not sure if I can handle timer overflows due to the softdevice interrupting my program at any time.

Anyhow, the RealTimeCounter is 24 bits which is enough for my purpose. So, with RTC prescaler = 0 ( as used in app_button like it seems..) I could store the current TICK count at the low-high interrupt and then compare to the TICK count at the high-low interrupt and that's it. The counter roll-over case could be handled outside the ISR.

Just: How to do it ?

Any help like "remove this driver, add that one, re-use this timer.. " is very appreciated.

Thanks a lot, Wolfgang

  • How accurate do the measurements have to be? The most accurate solution would be to use gpiote IN events to start the timer (RTC) on rising edge and stop it/capture the value at falling edge. The problem with this is that gpiote IN requires HFCLK to be on (800-900uA) so this is not applicable in your case.

    Gpiote PORT event do not require HFCLK to be on and is therefore low power. The problem with this event is that it is shared between all pins that are set up with the SENSE mechanism, this includes the button pins if app_button is used. Also, the DETECT signal generating PORT event is not cleared until all pins that are configured for SENSE mechanism and are currently active, will be deactive. Doing it automatically with PPI is therefore not easy. You can read more about the PORT event and SENSE in the Reference Manual.

    My suggestion is to use app_timer together with nrf_drv_gpiote. App_button already use this module (for button debouncing) so RTC1 is “taken”. The problem with this solution is that the SoftDevice can interrupt the reading which can lead to delays. Depending on the connection parameters this can be 0.8-6ms (old values, may be less with newer SoftDevices). This will only influence the accuracy of the reading. If you are ok with milliseconds error in the readings use app_timer.

  • Hi Ole,

    thanks for the system view advice. That's pretty much what I figured out, too. The 6msec max error are not perfect but for that application I can live with it. My problem is not the system view ( I am a hardware guy, not a software guy by profession) but how to actually define a GPIO to use Gpiote PORT event and all that based on the given bikepower example code. Whenever I try to define a new GPIO, timer, whatever, I run into a million "multiple definitions" or "don't use this driver with a softdevice" or "include file not found" or other issue the like. I used to write some bare-metal uC code in "C" on AVR processors and even in assembly on PIC. This is straightforward: Read the register definitions in the datasheet, do it, works :-)

    But I have real trouble finding my way trough your SDK. And that is where I need help.

    For the case: My application has zero buttons but:

    • 1 TWI device connected to the NRF51 ( works, after 2 weeks of wading trough #defines, macros, includes and this help forum )
    • 1 GPIO to be used as input to measure the width ( duration) of a pulse showing up there. This is the topic of this question.
    • 1 GPIO controlling the ChipSelect line of the above mentioned TWI device. Hopefully, I can solve that on my own after the Input GPIO runs....
    • S210 to send the data read via TWI to an ANT+ receiver. Again, I so far have not found the place in the example code where to feed in the actual value to be sent out via ANT+...
    • Later S310 to be BLE capable. That seems to be a big one...

    You see, that's all just small modifications / additions to the example code. I just need a SDK navigation aid....

    Thanks for the help already given, without this great support forum I already would have ditched NRF51 and taken a look to TI CCSxxx stuff... Which I do not want to use...

    Wolfgang

  • Oh, and for the HFCLK power requirements: I do not have ULTRA LOW power requirement. AND I can predict when the next to-be-measured pulse will show up. So, I could eventually awake the HFCLK just before I need it, based in a timer running on the LFCLK, and then turn it off again. Just, I am not sure that this pays off. As mentioned, i can live with the 6msec for now...

    Thanks, Wolfgang

  • E.g. I tried this, but it crashes the entire application...

    nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(false);
    		err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, WheelPulseHigh);					// this fails. Why ?
    	//  APP_ERROR_CHECK(err_code);
    
    
    nrf_drv_gpiote_in_event_enable(PIN_IN, true);				// enable event and interrupt
    
  • nrf_drv_gpiote_in_init(...) returns error? It looks like this happens either if the pin is in use by the GPIOTE already - NRF_ERROR_INVALID_STATE, or if there are no available channels (limited to 4) - NRF_ERROR_NO_MEM. Could you check the return value?

Related