The JSN-SR04 is an inexpensive ultrasonic distance sensor. There are many manufacturers, some are weather resistant, and they have somewhat different supported ranges, but usually in the range of a few centimeters to maybe a few meters. Also note: these sensors are generally not all that reliable. I would not use one in a life-safety situation and be sure to code defensively for the case when it fails.
Once characteristic of the sensor is that you need to measure the pulse width to within a microsecond or so, and measurement takes around 150 microseconds of setup time and up to 29 milliseconds of pulse width (at 5 meters). At a more reasonable 1 meter, it’s still around 9 milliseconds.
The problem on Gen 3 devices (nRF52840) is that even if you use interrupts, the interrupt latency is high, and extremely variable. The radio stack runs at a high interrupt priority and will delay other interrupts until completion. Because of the long time to sample, you don’t want to disable interrupts because it will adversely affect the BLE radio, and the reset of the system. But if you do not disable interrupts, the interrupt latency makes for very inaccurate readings.
The solution is the technique used in this library: The nRF52840 I2S, note this is I2S, as in sound, not I2C, peripheral is really just a high-speed digital input and output device with hardware DMA. The library is configured to use 32,000 samples per second, with 16 bits per sample, stereo. This works out to a bit clock of 1 MHz, or 1 µs per sample bit, which is perfect for the JSN-SR04.
It works on all Gen 3 Particle devices (Argon, Boron, B Series SoM, Tracker SoM using the nRF52840 MCU). It does so without ever disabling interrupts and it’s accurate to less than 0.3 cm even when using the BLE radio. It does not require any timer resources, which are scarce on the nRF52.
It’s completely non-blocking and you can theoretically measure a distance every 10 milliseconds with a range up to 1 meter. It only generates two MCU interrupts per measurement, and if the interrupt delayed by higher priority interrupts, or disabled interrupts, it does not affect the accuracy of the timing.
It requires a lot of GPIO (4 GPIO) and some RAM (2,080 bytes for the default maximum of 1 meter, reconfigurable).
Full documentation and more information in the Github repository