I am thoroughly puzzled about a problem I’m having with a P1. I have it mounted on a custom board, and I’m feeding it a pulse train. This train is modulated with a square wave at 40khz (25 us period), and I need to detect exactly when the first rising edge is. If I feed it a short train (1.5ms) and wait for it to pick it up with this pseudocode,
It doesn’t even register that the pin’s state has changed. I’ve timed the execution of the loop, and it seems to be around 0.07 us; more than enough to capture the 25us pulse.
I’ve tried turning off wifi and noInterrupts() to see if it’s some kind of background process, but I still haven’t found the problem. I’ve tried linking an interrupt to the pin’s state. Same thing. Just too slow.
With your code above you are driving the pin HIGH, how do you expect the line to get pulled LOW?
If you manage, you might strain the GPIO or your ext signal source.
Next pinReadFast() assumes the pinMode() to be set for INPUT (no sanity check - unlike digitalRead()).
I’d definetly go for an interrupt and avoid polling as the code snippet shows.
@Arthur_dent_42_121, @ScruffR and @Bspranger are correct about using an interrupt. Polling is often a hit and miss method and requires that you sample at least twice as fast as the rate of change of the signal (Nyquist) or an edge may be missed. Using interrupts guarantees the capture of the edge.
I do have the pin set as an input, and if I send a really long signal it will pick it up eventually. Sorry for the confusing digitalWrite(), that’s to trigger the pulse train from an external source.
I’m pretty sure that I’m sampling at least 100 times faster than the switching frequency, so that shouldn’t be a problem in this case. However, I have also tried an interrupt, and still had the same problem. I’ll get some scope traces so it’s easier to see what’s going on.
Here’s a scope trace of the polling method. The blue trace goes high when I start polling, and then the thing just completely misses the ~5000 20us pulses:
And now this is just getting crazy. I put this code on it in the main loop:
delay(100);
//trigger pulse
digitalWrite(D0,HIGH); // just for timing testing
delayMicroseconds(1);
for(int i=0;i<400000;i++){
digitalWriteFast(D0, pinReadFast(D3));
}
digitalWrite(D0,HIGH);
delayMicroseconds(1); // just for timing testing
Literally just setting one pin to the other pin’s state. I timed this, and the full 400,000 samples run in 57 ms, so 0.11 us per sample; 105 samples per pulse. Should be impossible to miss the pulse. Yet it misses the >5000 pulses in the train almost all the time:
It should be copying the yellow trace exactly on the blue trace.
I get a signal-response delay of 800ns and can pick up and mirror a 200kHz 20% to 80% duty cycle square wave. When I change the duty cycle below 20% or above 80% the interrupt seems to stop being triggered.
Just a very heretic thought Could you double check if you’ve got the correct pins wired - I just tried another Photon and got odd readings, till I relized I was checking triggering D2 and had D3 floating (INPUT instead of INPUT_PULLDOWN)
Yup, the code I tested above was yours, with my triggering code.
In regards to your previous comment, I have confirmed that the pin I’m using is the right one, and I’ve tried using a different one.
D1 drives a h-bridge at 40khz, sending an ultrasonic ping out of a transducer. This bounces off a wall and goes into another transducer. Then, I have a notch filter and a two stage amplifier that brings the recieved pulse to 3.3v amplitude so we can detect it on D3 digitally. DAC1 sets the threshold on a comparator on the receiver.
I’m very puzzled about this and since I can even reduce to delayMicroseconds(1); and still get a near perfect mirror response on my Photon(s), I’d have to hand this over to someone who can test this on a P1 (or have you got a Photon you could repeat your tests?)