3
\$\begingroup\$

I have a simple program basically increment the counter every time I get an interrupt. The code is something like this:

void ISR(void)
{
  static int counter=0;
  counter++;
  GPIO_SET(PIN1); // set the gpio pin
  DELAY(10); // some short delay so that we can see it in scope nicely
  GPIO_RESET(PIN1);//reset the pin
  clearFlag();

}

The event (actually it is a timer) that triggers this ISR also triggers some other stuff (DMA, basically every 8 event I should get a DMA interrupt, this is by design of the code)

In the DMA ISR code, I have another GPIO pin set/reset. Now:

  • When I look at the events (timer output on a pin and DMA toggle), on the scope I see 8 events correspond to each DMA cycle. So far so good.

  • When I look at the PIN1 at the scope, I only see 6 events two of them are lost and this is very consistent, always the same 2.

I don't have anything that takes very long time in the ISR and I am puzzled by the fact that ISR routine is not get called every time I get the event.

I am hoping this is a set up issue on my side, any ideas where to look. This is something so basic that it should just work. This is a new processor from ST, therefore there is a chance that it is a bug but I am kind of refusing to believe something this basic is not working.

The part is new STM32F2.. Compiler is Crossworks.. No optimizations, debug code.. run off the mill settings, nothing fancy.

I am really looking for a pointer to where to look.. Not hoping you guys would debug for me.. What would cause this? Under different circumstances I would assume timing of the ISR is the issue but I disable the ISR code with #if 0 to avoid these timing issues.. So, it is not timing.. What else it could be?

\$\endgroup\$
  • 2
    \$\begingroup\$ Yes, but what processor is it? Do you have a data sheet for it we can look at? Can we see your full ISR code? What language, compiler, version, etc are you programming in? What optimizations do you have enabled for said environment? There are a huge number of factors that could have a bearing on this. Please provide more background information. \$\endgroup\$ – Majenko Aug 15 '11 at 9:55
  • \$\begingroup\$ Which 2 go missing? first two? last two? some other pair? not sure this detail will help all that much, I'm just curious. \$\endgroup\$ – JustJeff Aug 15 '11 at 11:25
  • \$\begingroup\$ Guys I am highly simplifying the problem.. I am not expecting you guys to debug it for me rather point me towards a direction where I can figure out myself. \$\endgroup\$ – Frank Aug 15 '11 at 16:00
  • 1
    \$\begingroup\$ @Frank - Thank you for improving the information on your problem. While I appreciate your efforts to reduce the debugging loads, it's much more useful to actually understand and debug the problem rather than to take random guesses at things to check. \$\endgroup\$ – Kevin Vermeer Aug 15 '11 at 16:25
3
\$\begingroup\$

Putting an actual delay in an interrupt service routine is highly unusual. This may not be your problem, since you seem to have reason to believe your ISR is completing in time, but the usual practice with ISRs is to get in and get out as quickly as possible.

Just for laughs, what happens if, instead of set-delay-clear, you just toggle your output pin, with no delay?

\$\endgroup\$
  • \$\begingroup\$ my scope is fast enough so you see a pulse that takes 4-5 clock cycles. THe processor runs at 120Mhz so this takes about 20-30nsec time.. I still see the pulse. \$\endgroup\$ – Frank Aug 15 '11 at 16:05
  • \$\begingroup\$ Frank: Unless the pin is used for something else externally, I believe what JustJeff recommended is that you toggle it once per ISR, i.e. on the first interrupt set the pin high, on the 2nd set it low, and so on. Not one full on/off per ISR, which generates a very brief pulse. Instead, "long" constant levels between each interrupt. \$\endgroup\$ – unwind Mar 15 '13 at 8:43
  • \$\begingroup\$ @unwind - yes, exactly what I meant. \$\endgroup\$ – JustJeff Mar 16 '13 at 4:11
2
\$\begingroup\$

Without more details it's impossible to determine what might be going wrong. Here are some things I'd try:

  1. Use your debugger. Although I'm not familiar with the micro you're using many architectures will allow you to do cycle accurate single steps. It's very tedious to single step all the assembly instructions but you may only have to do this once.
  2. Change optimization levels on your compiler. If the system behaves differently the issue may well relate to timing.
  3. Remove dependence between asynchronous parts of the code. For example, is the GPIO_SET function/macro also used in the DMA ISR and are the gpios on the same port? Setting a GPIO is likely to involve a read/modify/write cycle and if the DMA ISR is also doing this operation and can interrupt the timer ISR, you may have a race condition.

To test your theory that the timer ISR isn't being called as often as expected, remove all references to the GPIO routines and enable interrupt counters in both DMA and timer ISRs. Leave the system running for some time and then check whether the ratio between the counters is 1:6 or 1:8 as you expect.

If you are missing timer interrupts, chances are that your response time to handle the interrupt is too great under some circumstances with the timer overflowing while the previous interrupt is still pending.

\$\endgroup\$
1
\$\begingroup\$

It would be helpful if we knew more about the timer. Often, timers are free-running and you use a compare register to generate the interrupt. If the timer rolls over or otherwise resets, then it's possible that the compare won't match that cycle and your ISR won't get called.

Try reading the timer value in both ISRs (I'm assuming an ISR is called on the DMA interrupt) and make sure the timer makes sense in each case. Since the timer may not stop while using a debugger, you may need to just store the values in an array and log them when the array fills so you don't alter the test by adding big printing delays.

\$\endgroup\$
1
\$\begingroup\$

I'd be worried you might be missing those two events because something is still happening with interrupts disabled. Can you do something like toggle a different GPIO at max rate in the foreground process (or change it whenever you enable/disable interrupts to match that setting), so you can tell when you are not in an ISR using a different channel of the scope? Or something similar with DMA still keeping things busy.

If there's another timer register or cpu cycle counter, you could read that in the ISR and log it somehow (perhaps even as a min/max using just two locations) and see if you are getting extreme interrupt latency.

\$\endgroup\$
0
\$\begingroup\$

Somebody, a very wise man in this forum once said, "Always be prepared to test your assumptions. The bug is usually in the thing you are assuming works". This was my case too. It turns out a higher priority interrupt was running at that time and preventing my ISR to get called.

My mistake was overconfidence that it was not a timing issue and not thoroughly checking interrupt priorities. Appreciate all the support guys.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.