5
\$\begingroup\$

Most standard 8052 platforms allow the user to configure interrupts to be of two possible priorities: higher, during which any pending interrupt must wait, and lower, which can be interrupted by the higher level interrupts, but lower level interrupts can wait.

Now, if you have a job to be done within the interrupt that takes some time, isn't absolutely time-critical, and can be interrupted by other interrupts, the usual approach is to drop whatever data the interrupt collected into a buffer, set a flag that there is the handling of a job pending, and then let the main loop reach a check for the flag, and perform that job.

There is, however, a trick that allows to save some time and have the job executed directly from the interrupt vector, but at main loop priority - interruptible by both interrupt levels, essentially creating a third interrupt level, below the two existing levels.

How does one achieve this?

\$\endgroup\$

2 Answers 2

5
\$\begingroup\$

Here's the trick:

  • You configure your "extra-low priority interrupt" as normal low pri interrupt: set up the vector, activate the interrupt, all the standard stuff.
  • Write the handler procedure at an arbitrary address as usual. Standard interrupt restrictions apply - saving/restoring registers, stack discipline etc. End it with RET, not RETI.
  • At the interrupt vector address perform three operations:
    • push lower byte of your handler address
    • push higher byte of your handler address
    • RETI

That way, the interrupt flag is cleared and normal execution is resumed, but not from the address where the interrupt occurred, but from your handler vector. You can perform the rest of the interrupt activity and then just resume the main loop from where it was interrupted by performing a standard RET - the address stored by the interrupt on stack is still there.

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

There is no solution that does not also respect the following constraints. First, no matter how you set up the prioritization scheme, the only way for an interrupt to be able to directly pre-empt an interrupt at lower priority on the 8051 family is for it to either be set at high priority or to come before the other interrupt in the scanning sequence at a given priority. Second, the only way you're going to be able to pre-empt an interrupt that is able to pre-empt other interrupts at yet lower priority is for the middle priority interrupt to be at low priority when it is pre-empted or else to come after the interrupt pre-empting it, in the scanning sequence, at a given priority.

That, alone, says you have to be exploiting the scanning sequence and/or to be run-time switching the actual 8051 priorities for interrupts that are at anything other than the highest or lowest priority in your scheme.

To drop down to a lower priority level for a high-priority handler, during mid-process, keep the interrupt flag activated, drop the priority flag, and do a "reti". If nothing else is awaiting interrupt handling, then it goes right back into the interrupt handler ... at lower priority. When done, with the lower priority part of the handler, set it back for high priority before doing the second "reti". Now, all you have to do is make sure you have the priorities matched up correctly with the scanning order at low priority. If not, then it might actually be necessary to set the later-scanned "low priority" interrupts at high priority.

The drop-down is what was happening here multi-threaded 8051 data collection demo (meant to be assembled with the CAS 8051 assembler), which processes the (8051FA-specific) interrupt handler for 5 timers, alongside a handler for the (8052-specific) for timer #2 in a multi-threaded setup. So, effectively the drop-down to lower priority functions as a spooler. If you use something like the demo, by the way, it could be improved upon by adding a switch of the R0-R7 address area in with the context switch (as simple as a "pop PSW" provided the register window has been initialized appropriately for the thread). The registers R0-R7 were meant to be used as thread-local variables, which is why they were designed to target multiple register windows - just like RISC processors do. Unfortunately, hardly anyone uses the R0-R7 registers that way.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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