Must looks at that sourceboost thing more closely, looks pretty promising at the first glance, I'm already crapping my pants thinking about doing unit conversions with assembler.... not to mention the possible menu system using the ASCII display and a 5-way joystick.
The call routines are excessive, that's true. I just used the SPI library without thinking about too much. Using a subroutine call adds unnecessary latency, and all the library call really contains is a "movwf sspbuf" command plus a collision check... using "movff [data] sspbuf" directly in the routine would have less overhead and save a stack instruction. The stack is 31-deep in PIC18f though, so I'm not too worried about overflow there. Having the software to check for collisions would be "free" though, as there's 9 cycle delay after new data can be sent into SPI bus. That's not a whole lot to do anything else, though.
I do as Jean has said, I try to have everything already setup and ready for the isr and the isr just does the simple lifting based off an event.
If I understood that right, that's the sort of thing I'm attempting here; the data is stored into the ADDRx and LEDDATA registers - all the procedure does is move them to the SPI as quickly as possible, with the relevant pin status changes.
I think I should explain how I planned the whole program to work:
The first stage and of least priority is the measuring part of the main loop reads the values from the ADC circuits, pulse counters or the SPI input, depending which quantity is being measured and then stored into memory. I think each quantity needs two banks of registers; one for working out an average between several measurings and the other the output value, you don't want to make a 7-segment display to update too rapidly. These measuring procedures are run continuously in order at the main loop.
The second stage with medium priority is a display interpreter procedure, which is run once between display writes. To detect if the write has taken place, the DATA_WIDTH value is read first. If this is zero, it means the display refresh routine has been run and needs a new set of information; otherwise exit. The segment counter calls a subroutine for each display element. The subroutine takes the information from the output data registers set by the corresponding measuring routine and interprets it into the proper form, which would be a bar segment, 7-segment, or ASCII character/location information. The subroutine then writes the data into ADDRx -registers which tell which LED element the data applies to, an the actual data into memory locations starting from LEDDATA. It then sets the DATA_WIDTH byte and returns.
Finally, there's the highest priority task, the display routine, triggered by the timer overflow. The routine sketch I've written already describes how I planned it to operate, but of course there's a few changes I've figured already; The routine first needs to check if the DATA_WIDTH byte is not zero; if it is, it means the refresh kicked in before or right in the middle of the interpreter cycle, and should exit. It should be really really unlikely situation though, bordering a malfunction. Also, the display routine should not bother with the display counter, it should be done in the interpreter routine.
What is really important here is the display routine is run as quickly as possible, at precisely the due time, at the top priority. The main concern is visibility and visual appearance. There's a lot of LED's to light up in sequence - 41 different sets in this outfit - so there's not much time for each to lit. The manufacturer approved overdrive is 160mA at 10% duty cycle at 1kHz refresh time; here's the current is 125mA, but the lit time per LED is 110µs per cycle. For even and flicker free lighting, it's important each get the same amount of lit time, at regular intervals. The way I see it can be done in the main loop is to modify the stack so that upon exiting the interrupt, the program accesses the display routine instead of interrupt point, runs the routine, then restores the registers and modifies the stack again so upon return from subroutine it resumes where interrupt was encountered. But then again, how will that differ from doing it from within the isr in the first place? I only have intuition and tutorials (and the datasheet manual of course) to go by on this, I certainly would appreciate good examples how these things are made.