Measuring phase shift of a 10kHz analog signal: need help getting started

I'm working with a prototype sensor that changes impedance when environmental conditions change (sorry, can't provide too many details on the sensor itself).

Currently the sensor is read by generating a 10kHz sine wave, and measuring the phase difference using two fast comparators and a digital 12 bit counter with a 2MHz clock. The comparators generate a pulse on zero crossing, one starting and one stopping the counter. The sensor value is read as a 12 bit value from the counter.

I was hoping to simplify the circuit a lot with just an external sine generator, generating a 1.65V centered, 3.3V sine (single supply). And use the nRF52840 comparator to detect zero crossing (using differential mode with the negative input at 1.65V), starting a timer when the reference signal (AIN0) crosses zero, and stopping it when the sensor signal (AIN1) crosses zero. That should give me a good enough resolution. The original circuit uses a 2MHz clock, and I should be able to use the 16MHz timer.

If I understand things correctly, I need to use the comparator, PPI and timer peripherals, using PPI to route events. And that's where I get lost, the only PPI example I found is for timer to timer PPI. I'm assuming I need to set the AIN0 comparator to generate an UP event when the + input is "zero crossing" the - input set at 1.65V (my reference point for the 0 point of the 3.3V signal), and use PPI to start TimerX. Then use the UP event for AIN1 (with same reference point) to stop the timer, and store the value for further processing

Am I on the right path? Is there any guidance on how to properly initialize PPI, comparators and timer for a case like mine? I'm not expecting code, just pointers to get started and avoid going down dead ends

Parents
  • Hi,

    I think you should be on a right path, yes.

    For BLE applications: Some PPI channels and groups are reserved by the SoftDevice. Those are defined in nrf_soc.h. (The same applies for the SoftDevice Controller subsystem in nRF Connect SDK.) Also, some hardware peripherals (such as TIMER0) are restricted or blocked by the SoftDevice.

    There seems to be no pre-programmed channels that could be of any help.

    As for pointers, you are right that the PPI example itself (in nRF5 SDK) handles only the timer peripheral. The approach is however similar no matter which peripherals are involved in the PPI setup. There is use of PPI also in the GPIOTE example (examples/peripheral/gpiote/main.c) and the SAADC example (examples/peripheral/saadc/main.c). Most relevant to your project should be the source code for the capacitive sensor low-level library (components/libraries/csense_drv/nrf_drv_csense.c) which uses COMP events (although slightly differently from what you need.)

    The above assumes nRF5 SDK. If you use nRF Connect SDK, let me know and I will see what pointers we have for that one.

    Regards,
    Terje

Reply
  • Hi,

    I think you should be on a right path, yes.

    For BLE applications: Some PPI channels and groups are reserved by the SoftDevice. Those are defined in nrf_soc.h. (The same applies for the SoftDevice Controller subsystem in nRF Connect SDK.) Also, some hardware peripherals (such as TIMER0) are restricted or blocked by the SoftDevice.

    There seems to be no pre-programmed channels that could be of any help.

    As for pointers, you are right that the PPI example itself (in nRF5 SDK) handles only the timer peripheral. The approach is however similar no matter which peripherals are involved in the PPI setup. There is use of PPI also in the GPIOTE example (examples/peripheral/gpiote/main.c) and the SAADC example (examples/peripheral/saadc/main.c). Most relevant to your project should be the source code for the capacitive sensor low-level library (components/libraries/csense_drv/nrf_drv_csense.c) which uses COMP events (although slightly differently from what you need.)

    The above assumes nRF5 SDK. If you use nRF Connect SDK, let me know and I will see what pointers we have for that one.

    Regards,
    Terje

Children
  • Very good information, pointers and caveats, thanks a lot. And, yes, I'm using the nRF5 SDK, sorry for not mentioning it in my question.

    I have enough to get started, will ask more specific questions if I get stuck. I'm leaving this open for now, if ok, so that I can add more once I have working code (to help others in the future)

  • Ok, I've done some more tests, and realized that there's only one COMP peripheral. So I can't do what I originally planned: use one comparator to start a timer, and another to stop it, using a different input.

    Ans the LPCOMP is shared with COMP, so no way to cheat either Slight smile

    Is there a way to use COMP on, say, AIN1 to detect an EVENTSUP and, as soon as it's detected, reconfigure COMP to now use AIN2 for the same type of event?

    I could not find a COMP library in the nRF5 SDK, so it's unclear to me how I can trigger an event handler from a COMP interrupt. 

    I managed to use PPI, COMP and timer: when COMP EVENTUP fires, I start a timer_count configured as a standard timer. Then use a different timer also with PPI to stop the timer_count and read its value. If I could use COMP instead of the second timer, I would have my working proof of concept

    I also read about the UP_STOP event, which would be helpful in speeding up the COMP reconfiguration. Use UP_STOP to start the timer using PPI, stop COMP and trigger a handler that reconfigures COMP (assuming I can do it fast enough to measure the sensor)

    What is the best way to trigger a fast interrupt handler on EVENTSUP or UPSTOP for the comparator? 

  • I could not find a COMP library in the nRF5 SDK, so it's unclear to me how I can trigger an event handler from a COMP interrupt.

    It's just the nrfx_comp.c/.h files. But they do provide a way to trigger a handler from the comp interrupt.

  • Assuming smooth input signals simply phase-shifted you can try using two digital inputs and relying on the very close matching of the switching threshold which exists on a single die (single nRF52). This works very well on detecting phase shift, and to achieve greater resolution accumulate multiple such cycles with hardware timers then average.

    Most peripherals work on the 16MHz clock, which is syncronous to the CPU 64MHz clock. Using an external sine generator generator means an uncertainty of +-1 16MHz clock cycle on each input edge, +-62.5nSecs or 250nSec overall window between the two signals. There is no DAC on the nRF52 but using a filtered PWM output to generate the sine wave reduces that uncertainty by half since then the input waveform becomes synchronous to the 16MHz clock and therefore the jitter on that window reduces.

  • That's interesting. I was actually wondering what would happen if I tried to use GPIOTE instead of COMP, relying on the digital threshold for high vs low, but I was worried about threshold matching. Based on what you say, it's well worth trying.

    I don't have a lot of experience using PWM to generate a smooth sine, but if I could use the nRF52840 to also generate the sine, it would simplify the circuit further, on top of improving uncertainty. Actually, if I can generate the sine signal cleanly enough, I only need a single input, and can use COMP. Since I'm generating the PWM using a timer, I will know by definition when the original signal crosses zero.

    I'm assuming I should use an RC filter to smooth things out. What values of RC would you suggest using to generate a smooth 10kHz sine from the nRF52 PWM output? 

Related