digitalWrite during ISR wreaks havoc on external interrupt?

Hello everyone!

I’ve run across a rather interesting problem.

So I have a timer (SparkIntervalTimer) running at ~30kHz. I also have an external interrupt that happens at 120Hz. In my ISR for the 30kHz timer I write data to some shift registers.

The problem is as soon as I start writing to the shift registers, I see the 120Hz external interrupt start happening very sporadically between 140Hz and 1kHz! This 120Hz external interrupt is coming from a zero cross detector. I’ve put my scope on this line and can confirm that the signal is not changing to 1kHz. It’s rock solid.

So I’ve narrowed down the issue to 3 lines of code. 647, 668, and 672. Setting the latch pin high/low. And writing the SPI byte. If I comment out these 3 lines of code, the external interrupt stays at 120Hz. If I bring the SPI write back, or the latch pin high/low back, or both back, then my external interrupt starts acting crazy again. I really don’t know what to think about this. It would be easy enough to move the code from the ISR to the main loop and just set a flag in the ISR to run the code next time the main loop runs, but I would really like to know why this is happening? I’m not terribly familiar with interrupt do’s/don’ts so please enlighten me :slight_smile:


Update
So I just tried moving to code to the main loop and just set a flag in the ISR to say it should be executed. Same problem… Now I’m really confused. So I guess this means it doesn’t have anything to do with the interrupt, but instead purely with pin state changes…

Here is my code:

Thanks!
James

I’m not an SPI expert (like @peekay123), but you are using A2 as latchPin but this is by default also the SPI-SS pin.
Although @peekay123 has once set me right on the fact that the Core uses “soft SPI slave selecting” I would still try to use another pin (not A2…A5) as latchPin.

Another thing to consider in connection with interrupts are their priorities.
As far as I know SparkIntervalTimer and hardware SPI do use interrupts as well, and if their priorities are higher than that of your ISR these will interfere with yours. And even worse if you try to trigger (or implicitly do) an interrupt from inside an ISR (e.g. SPI inside handleDimmingTimerInterrupt()).


BTW: Recalling another question about speed and asm for this project, there would be some speed gain possible in this code

        // Build the byte. One bit for each channel in this shift register
        byte byteToSend = 0x00;
        if(*(--tempPWMValues) > currentBrightnessCounter)
        {
            byteToSend |= 0b10000000;
        }
        for(byte i2 = 1; i2 < 8; i2 ++)
        {
            byteToSend >>= 1;
            if(*(--tempPWMValues) > currentBrightnessCounter)
            {
                byteToSend |= 0b10000000;
            }
        }

@MrRocketman and @ScruffR, the interrupt priority for the SparkIntervalTimer was set to 10, above the “user” interrupts and below the most important firmware interrupts. From what I can tell, the interrupt is not masked (disabled) when noInterrupts() is called, only lower level user interrupts.

The SPI.begin() function can take an argument that specifies the SS pin, with a default being A2. All the firmware does is initialize the specified SS pin as OUTPUT and sets it HIGH. NOTHING MORE! It is up to the user to control the SS pin in their code afterwards.

One thing to note is that SPI.transfer() is a blocking call and will not return until the transfer is complete. It does not use interrupts to do this. The exception is if you enable SPI DMA but this is only available if you compile locally.

You may need to disable the SIT timer interrupt when you are servicing your 120Hz interrupt in order to prevent problems. I agree with @ScruffR about optimizing the 120Hz ISR code. If you disable the timer, then the less time you take, the better it is.

Assuming that SparkIntervalTimer allocates the first timer, TMR2, then I don’t see any reason for the GPIO calls to cause any problems. I noticed that you don’t actually set latchPin as an OUTPUT anywhere. Don’t assume SPI.begin() does it and do a pinMode(latchPin, OUTPUT) after your SPI calls in setup() OR explicitly call SPI.begin(latchPin) to force the SS pin selection.

Oh, and don’t do your testing with the Serial.print() code in the 120Hz ISR as this code is not exactly fast. Do you have a logic analyzer by any chance? :slight_smile:

1 Like

Okay, so I’ve been going crazy trying to figure this out. Thank you for the suggestions. It would seem that the problem is not with my software after all.

Here’s my setup:

Bottom left is my Core. On the top of the breadboard is a logic level converter. Right power rail on the breadboard is 5V and left power rail is 3.3V.

Top center is my old Arduino board with the zero cross circuit on it (All 5V). Top left under the white box is one of the shift registers boards. The yellow wire coming from the Arduino board (which is my zero cross signal), goes through the logic level converter, and then into D3 on my Spark Core.

So for fun I unhooked the SS, CLK, and MOSI wires going to the shift register (green, yellow, and white wires on the right side of the Core), and the problem goes away. Completely. Zero cross signal is fine with all of my code running in the interrupts like I would expect. So I poke around a little. I take the green wire (SS) and simply plug it into one of the empty rails on the breadboard and BAM the problem is back! The problem also reappears in other similarly strange circumstances.

So I have my zero cross signal fine, I plug a jumper from A2 (SS) to the the middle of the breadboard hooked up to nothing else, and the my Spark starts seeing the zero cross signal timing all over the place. I have hooked up my scope and can confirm that the zero cross signal does not change.

So there is something crazy going on that I do not understand. What could possibly be causing this? I really have no idea.

I have no idea about the reason either, nor have I got any clever explanation why you should - and @peekay123 will grind his teeth about this :wink: - but just to cross it of the list: Try using e.g D7 as your latch_pin instead of A2.
Just try it for a stubborn ol’ thickhead :blush:

1 Like

@MrRocketman, from the sounds of it, you are having noise issues, possibly on your GND or supply lines. Judging by the length of your wires, it is a definite possibility. I don’t see a common GND between the Core and the other hardware.

Do you have a fritzing diagram or schematic for your circuit you can share? A parts list would be nice also. Time to get down and dirty with your hardware! :stuck_out_tongue:

1 Like

Good idea @ScruffR. I tried D7 for the latch and there’s no more craziness when hooking a jumper to nowhere.

@peekay123 I will work on a parts list/diagram.

I’m almost convinced at this point that my Core is defective. Especially from the A2 -> D7 results. This just doesn’t seem normal.

1 Like

Okay here is the Fritzing schematic. Didn’t get the breadboard layout done but the schematic should be good. I also threw in my Eagle Project which has my main Arduino board (LightController), and the Shift Register/Triac Board (TriacBoard), since I’m actually tapping into the existing functional boards rather than building the entire thing on the breadboard.

http://mrrocketman.com/files/public/other/SparkCoreZeroCross.zip

Fritzing is very easy to learn btw! Never used it before.