SPI inside an ISR to refresh multiplexing?

I was trying to wrap up my multiplexing driver code in a routine that could be refreshed via timerone, but it refuses to update the display. I dug around a bit and found people saying you can't use SPI inside an ISR (and therefore inside a routine timerone is calling). But DigitShield sets up an ISR and updates its display shield using SPI (shiftout) without issues, which is why I wasn't expecting this to be a problem.

So... is the DigitShield library breaking the rules and getting away with it somehow, or is there a trick to getting this to work? (it doesn't use timerone, it sets up the isr manually) By the time I get this into a proper library I'd like to have just a Service routine for the user to call to do each wave of the multiplexing sweep, either by calls from inside their loops OR by the user using timerone etc to call it.

Since you can't instantiate more than one instance of timerone, I don't want to explicitely use that in my library, if the user wants to call my Service with timerone, they can establish one use of timerone and have it do all their servicing, including calling my library to service the multiplexing. But I can't offer that option unless I can get my code to work from within an ISR call chain. How can I get my shiftout to work inside an ISR that timerone provides? I'm hoping there's something inside timerone that is disabling my use of shiftout that I can work around?

I dug around a bit and found people saying you can't use SPI inside an ISR

That is rubbish, you can.

I certainly may be doing something wrong, but when I try to shiftout inside a timerone callback, nothing happens on the display. I know some things just silently fail inside ISRs, like delay()

(FWIW I ran into the same exact problem with my work on my compass, trying to pull data over SPI in an ISR, in that case it hung waiting for the data)

nevermind. gremlins. I spent some time shuffling code around and tried to retest the issue and it went away. There may be something very subtle there like order of function declaration going on.

This is an 8 character 8 segment display, that is multiplexed by sending a specific segment patern to a group of displays every refresh. Depending on what pattern is on each display, I have to refresh once (if they are all the same) or eight separate times ( if each display contains a different segment pattern)

So I noticed early on that when displaying all of the same thing, or only one or two characters, the display was much brighter than if I was displaying say an 8 digit number with mostly different digits in each position.

My fix for that was to collect a list of patterns that were required, and refresh them in sequence, and then to refresh any remaining (of the 8) cycles with no segments lit. That worked well to even out the brightness. Before I made that change, a pattern like "88888888" was blinding compared to "12345678". This adjustment dialed the brightness on the 8's down to match the sequence. (I noticed this feature isn't present in DigitShield, as it displays " 8" MUCH brighter than say "1234")

So in thinking about this, I thought my idea of refreshing several characters at a time if possible was clever, but now that I consider I'm having to display blank refreshes to even it out, maybe I would have just been better off discretely refreshing one place at a time every time?

maybe I would have just been better off discretely refreshing one place at a time every time?

Well that is the conventional way of doing things, and for exactly that reason.

Grumpy_Mike:
Well that is the conventional way of doing things, and for exactly that reason.

Yeah, I was thinking "oh if I can refresh multiple characters at the same time they should be brighter!", which in theory sounds good.

But then you realize that (1) it's actually a little bit TOO bright, and (2) the brightness varies with the content. So I recoded it to do single place refreshes and it's looking good. I'm a little surprised that the necessary refresh interval is as wide as it is. My current code switches characters every 1ms, which means each character gets lit for 1 ms every 8ms, (13% duty) for a refresh rate around 125hz. I start to notice flicker at 3ms, 24ms per, 42hz. I also checked the maintenance cost, and each character refresh takes 368uS, so it's actually pretty taxing, taking 36% of processor time when set at 1uS. Not good to do if you have other things to work on, but OK I guess if you're in a busy loop or waiting on a user or something. I recall the required persistence on a CRT is 25hz, not surprisingly LEDs require a faster refresh.

I'm in the process of adding support functions for DisplayFloat, DisplayLong, Stopwatch, etc, lots of nice possibilities. I'm going to go hunt for a usable 7 segment alphabet now. Some chars are quite a challenge in 7 segments... :stuck_out_tongue:

I recall the required persistence on a CRT is 25hz, not surprisingly LEDs require a faster refresh.

No the 25Hz is the frame refresh rate for the perception of motion, it is 32Hz which is where flicker starts to disappear. Hence TVs showed two frame scans of interlaced lines at 50Hz (or 60 Hz in other countries ), this gave a flicker rate at 50Hz but did not waist bandwidth sending frames much faster then the 18 frames per second for the persistence of vision.

In the same way a film projector flashes the same frame on the screen three times before the film advances to the next frame. So when you go to the cinema half the time you are in the dark and two thirds of the time you are watching repeats.

LEDs can flash faster but the rules of refresh are still the same because we are still the same.