Just starting with a Photon. I am trying to measure pulse times via a low triggered interrupt. I think it’s a pretty simple handler.
I started getting occasional random errors, and began storing the micros() values into an array, so when I got a bad value I could print the timings. The bit errors come in different places, but each time it appears there is a reading with an extra 1ms, and the next delta is negative because the reading gets back on track. Time jumping ahead leads me to believe I’m not missing counts, and since it jumps backwards, not missing an interrupt.
How are you attaching the interrupt?
Since you see a 1ms glitch from time to time I could be that higher priority interrupts (e.g. WiFi communication) get in your way and cause some “out of order” execution due to queueing same priority interrupts.
Could you try to elevate the priority of your interrupt?
But this might still be something for @mdma to look at.
BTW: Try to have all your micros variables unsigned long and volatile.
I’ve been thinking about how millis() is implemented, and that it’s totally reliant upon the SysTick interrupt, which may be delayed/unsurped by a higher IRQ. Also, millis() isn’t ticked while the device is in stop-mode sleep.
OK?
I would have thought it to be the other way round.
After all if millis() not get updated inside ISRs how would micros() do the magic of counting 1000th fractions of a frozen variable and get updated anyhow?
Last night I had tried making the micros variables volatile, after reading an article on code reordering. It seemed to be working, even as I was convincing myself that wouldn’t explain the issue, but then more failures.
I have not tried changing the interrupt priority. I understand that tick interrupts could possibly be missed, but looking at the firmware code, I think that would only delay millis(), and in no case cause a jump forward, and then backwards by micros(). The only way I could see this happening is if the GetSystem1UsTick() call was out of order, but its variables are volatile.
I see it now. If my interrupt is higher priority, it could interrupt System1MsTick() between its two statements, which would cause me to be off 1ms.
I’m having a hard time finding the priority level of the SysTick interrupt, so I can set my interrupt to be a lower priority. Where could I find this information?
Letting the code run for about 9 hours, which should have read the sensor about 32k times, I still had 8 readings where delta micros() jumped forward and then went negative to correct itself.
Should priority 14 have kept my code from interrupting the system timer? Any other ideas?
Has this changed anything on the frequency of that glitch at all?
Since micros() returns a uint32_t it will have roled over 7 to 8 times during your 9 hours (once every 71 minutes).
While unsigned subtractions should not show this behaviour, this could well be a possible reason.
Have you printed the readings causing the error?
It seems to be less frequent. However looking at the micros value where it happened previously, it does not appear to be when the value crosses the word boundary. From example 1 above, the values were:
The error was in the high byte of the low word, and isn’t a case of being caught incremented before the low byte was updated, F6 is larger than the target value of F3. I stopped logging the current micros value, but each second I am logging how many errors I have seen with a line like Temp: 21.5C Humidity: 36.8% badChecksums: 55 negativeMicros: 9
If this only occurred at rollover, it should never happen with fewer than about 4260 samples (71 minutes * 60). But I do see if more frequently than that.
So it went as few as 619 seconds without error, and erred five times total under 71 minutes, not counting the last sample which wasn’t complete.
I am going to connect another Arduino as a waveform generator that I don’t have to trigger, and see if I can repeat this with a simpler case. I’ll also go back to logging the current micros value to see when it is happening.
Ok, stripped down my code to an example. Removed the sensor I was reading, and used a Bus Pirate to put a 10kHz pulse on D1. Only thing connected is USB and GND/D1 to the Bus Pirate. Once per second (roughly) I attached the interrupt, and measure 40 pulses before disconnecting the interrupt. It went a while with no problem, but then had quite a few, sometimes more than one per minute, so I don’t think it was either counter doing a rollover.
@mdma, should setting the interrupt priority to SYSTICK_IRQ_PRIORITY + 1 take the millis counter issue out of the problem like I’m thinking?
Setting the priority will certainly remove one possible cause of delaying the systick interrupt, but presently the millis/micros code is not thread safe so an interrupt at just the right (wrong?) time can cause the data to be computed incorrectly.