Photon interrupt latency


#1

I need to write a set of very simple ISR interrupt service routines. Basically they will each set a flag, remember the current TICKS count, and turn off interrupts for that ISR. (Not sure: Maybe the interrupt is already turned off by the act of the incoming interrupt taking place.)

So what is the latency? If the Photon firmware is running something critical, like some wifi function, what can I count on for time between the external event happening and reading the TICKS counter?

My interrupt will be attached to a digital input pin. I am a novice Photon user working with the Particle Build IDE.
–jim


Interrupts: #, priority, architecture
#2

If you want to get many interrupts from the digital pin, then you leave the interrupt enabled.
Be sure to declared the shared flag and the shared ticks counter as volatile, e.g,.,
volatile uint8_t flag;
volatile uint32_t ticksAtInterrupt;

Code your ISR to be very fast and don’t call libraries from the ISR. The call to get the tick count can be safe if it does not alter interrupts or call some library code.

Another way to do this is with an input capture counter where it interrupts with the capture counter count and you use that rather than the system tick (1mSec) counter. The capture counter can resolve finer than 1mSec depending on how you setup the clock freq. for the capture counter.

Latency: if you mean the time delay from the pin change to when your ISR notes the tick/counter count, you are speaking of the system interrupt latency. This is normally an average of about 5 microseconds. But some badly written applications or ISRs can cause some or frequent latency increased to 10’s or 100’s of microseconds. Some non-ISR code can disable interrupts for imprudently long times.

There are ways to use DMA to store the input capture counter values without an interrupt. But you likely don’t need this complexity.


#3
  1. I don’t think there are enough input capture registers available. I need six. I currently use the PIC 24E chip which DOES have enough IC registers. On that system, it’s counting in 25ns clicks.

2 FIVE microseconds? Ouch. That’s horrible. I would have hoped for, say, 10 machine instructions. Do you know if the Photon firmware (the stuff built into flash by the Particle folks) has such “imprudent” long times? My application needs accuracy at the roughly half microsecond level or better.


#4

System.ticks() has not got a 1ms resolution but does in fact count the clock cycles, so each tick is about 8.3ns on the Photon.
https://docs.particle.io/reference/firmware/photon/#system-ticks-

micros() in turn returns µs since system start derived from the system ticks.
https://docs.particle.io/reference/firmware/photon/#micros-

I’m not sure about the 5µs interrupt latency either, it sounds a bit much, since it’d equal to 550+ clock cycles.
It might turn out that some interrupt events might be serviced that slowly in case of higher priority ISRs being active (and slow), but I wouldn’t think this is the general rule.

If @stevech is refering to something like this post
HAL Hardware Timer Library Development

I think the issue there is that interrupts firing every 5µs would be prone to be missed from time to time or interfere with the overall system performance.

But after some tests I have to say, that you’re looking at something of 1.8µs - which is still way more than I anticipated.
I used this code to test the timing

SYSTEM_MODE(SEMI_AUTOMATIC)

const int pinInt  = D1;
const int pinTrig = D0;

volatile uint32_t trig;
volatile uint32_t start;

uint32_t correct;

uint32_t ms;

void ISR()
{
  pinResetFast(pinTrig);
  trig = System.ticks();
  digitalWriteFast(D7, !pinReadFast(D7));
}

void setup()
{
  Serial.begin(115200);
  pinMode(pinInt, INPUT);
  pinMode(pinTrig, OUTPUT);
  pinMode(D7, OUTPUT);

  start = System.ticks();
  pinSetFast(trig);         // these actions are required for the test and 
  pinResetFast(trig);       // add to the timing, but are not to be considered
  trig = System.ticks();    // part of the actual interrupt latency
  correct = trig - start;

  //Particle.connect();
  //waitUntil(Particle.connected);

  attachInterrupt(pinInt, ISR, RISING);
}

void loop()
{
  if (trig != 0)
  {
    Serial.print("Interrupt latency including extra time for trigger test ");
    Serial.print((trig - start - correct) * 8.333, 3);
    Serial.println(" ns");
    Serial.printlnf("(%4.3f corrected)", correct * 8.333);
    trig = 0;
  }

  if (millis() - ms > 500)
  {
    ms = millis();
    start = System.ticks();
    pinSetFast(pinTrig);
  }
}

#5

Hi!

A lot of what I need an MCU for is the fastest possible response times (I’m trying to put off learning to program an FPGA), so faster interrupts mean I can the photon in more places. I don’t suppose anyone has any news on this? I’m currently poking through the source to try to understand the HAL in case that’s causing the delay, but I’m suspecting it’s just an RTOS limitation. Can anyone offer some insight? I’ll of course post here if I work out anything more myself.

thanks!


#6

@morgatron, the latest firmware version (0.4.9) allows you to set an interrupt’s priority. However, you will need to plan on the impact of the ISR load on the system. There is at least one other topic on this in the forum :smile:


#7

Our project uses pin change interrupts. We have done a lot of work and believe the interrupt latency is 1900 ns. The normal user living at the HAL abstraction cannot change interrupt levels. We are diving down to increase the priority of pin change interrupts. Nobody interrupts us. That’s when we get the 1900ns latency. By using whatever interrupt priority comes standard, the 1900ns sometimes jumps way up to many microseconds worst case. By boosting our priority level we get a VERY consistent 1900ns.

Once a pin interrupts we turn interrupts off, do some special stuff in tight loops for about 10 ms, and then turn interrupts back on. We hope no other system functions suffer from that 10ms dead time. We may have to go to 20ms of dead time. So far it seems to be ok.

Our overall events happen about once every couple seconds so the rest of the system gets plenty of time to do its work in the long run.

In a sense it’s a shame that latency takes so long. The hardware chip designers worked very hard to get the latency to a minimum of instruction cycles. And of course the software guys killed it. :wink: (Hey! That’s a joke. I worked on both hw and sw.)
–jim


#8

@jim_hahn, without giving too much away of your product, how important is it for you to stay on the HAL?
If you feel comfortable with touching the bare metal, the system won’t hold you back from setting the interrupts how ST Microsystems intended it to be done, allowing you to break the 1900ns sonic barrier.

But for the interrupt priority, have you given the new overloads of attachInterrupt() a try?
If so, what did you see lacking?

@morgatron, it’s not really FreeRTOS but rather the multiple layers of indirection from the “hardwired” interrupt table to the hardware unaware (HAL) Arduino style interrupt servicing function (didn’t call it ISR on purpose to stress the “difference” ;-))


#9

There are a couple reasons not to violate, too badly, the HAL layer. First, if you do something under the covers, it’s possible the Photon sw people will find a reason in future to do things differently. Imagine for example some state table which is under the HAL level. Now, a year or so down the road the Photon engineers wish they had done things differently. So they totally rewrite it. A user who has dipped under the HAL could well be in trouble! Second, we simply want to USE the Photon; we don’t want to do computer sciene-y stuff. We want the Photon company to publish a set of functionality and “it just works.” And that’s what they have done. Which is great.

What are “the new overloads of attachInterrupt()” I never heard of them! Is this a new, supported level of functionality?

BTW it’s not a real product, it’s a hobby project. We have a set of six acoustic sensors which “listen for” the sonic crack of a bullet and triangulate where a bullet hole is on the face of the target. (Actually hyperbolize is a better word and we use a capability termed TDOA.) All the Photon does is grab the raw times; A Java based program accepts them and does the number crunching and web display to the user.

Thanks,
–jim


#10

Particle Firmware Updates Thread

This thread just above your post

https://docs.particle.io/reference/firmware/photon/#attachinterrupt-


If you are flying under the HAL directly on the bare metal, Particle can do little to squeeze in between :wink:
So you are save there as long you are not switching hardware.


#11

Thank you Peekay, Jim, and ScruffR! Such fast and helpful responses.

I wasn’t aware of the new overloads for attachInterrupt. I’ll likely use those in the long run as ~1 microsecond is good enough for most things, but for the moment I’m in the exploratory phase of playing with a new toy. Looking at the HAL code I think I see how to use low level interrupts, looks like I should be able to gain a bunch of speed by bypassing the general-purpose self-foot-shooting prevention steps.

Quick newbie question: looks like I’ll have to rebuild the firmware, is there a way to do that and send it over the cloud, or do I have to have physical access? (I ask mainly because it’s sitting on my desk at work, which is not where I am)


#12

Depending on what you exactly want to do, it might not be necessary to rebuild the system firmware.
If you just include the respective stm32f2xx header files you may be able to just do it as with any other sketch.

Maybe not with Particle Build (if they files are not provided), but with CLI or Dev.

Replacing the system OTA is possible, but not required I’d say.