Author Topic: Interrupt processing- one time or loop  (Read 2956 times)

0 Members and 1 Guest are viewing this topic.

Offline cv007Topic starter

  • Frequent Contributor
  • **
  • Posts: 822
Interrupt processing- one time or loop
« on: December 27, 2017, 03:19:30 am »
Interrupt question.

my code (incomplete, hitting datasheet a chapter at a time, now 'stuck' in usb)
https://github.com/cv007/PIC32MM_Curiosity_CPP
https://github.com/cv007/PIC32MM_Curiosity_CPP/blob/master/Usb.hpp - line 320
(no defines or mchp headers, except I broke down to add defines/macros in Isr.hpp for easier ISR creation)

The PIC32MM has interrupt levels and many irq sources, so is it best to just run through an interrupt once, or check it until no more (specific) irq flag, letting any other higher level irq interrupt as needed, or does it make no difference.

original way, with just returning when done-

Code: [Select]
void USB_ISR(){
    Usb u; Irq ir;
    static Usb::state_t last_state; //keep track of usb state for resumes
    uint8_t flags = u.flags();      //get all irq flags
    ir.flag_clr(ir.USB);            //clear usb irq flag before early returns

    //ATTACHED->POWERED if vbus_pin high
    if(u.state == u.ATTACHED){
        if(vbus_pin.ison()) u.state = u.POWERED;
        else { //no power (not sure how we would get irq with no vbus)
            u.eflags_clr(u.ALLEFLAGS);
            u.flags_clr(u.ERROR);
            return;
        }
    }

    //more code
}

if USB flag was set again while processing, we go through isr register restore, then backup registers again since we will be right back here


OR, something like this, where it loops until usb flag no longer set (replacing early returns with continue)-
(I also changed flag getting/clearing so only needs to be done in one spot, one time- which I should do anyway)

Code: [Select]
void USB_ISR(){
    Usb u; Irq ir;
    static Usb::state_t last_state; //keep track of usb state for resumes

    for(; ir.flag(ir.USB); ir.flag_clr(ir.USB)){ //added loop

    uint8_t flags = u.flags();      //get all irq flags
    uint8_t eflags = u.eflags();    //get all irq error flags
    u.flags_clr(flags);             //clear only what we got (1=clear)
    u.eflags_clr(flags);            //clear only what we got (1=clear)

    //ATTACHED->POWERED if vbus_pin high
    if(u.state == u.ATTACHED){
        if(vbus_pin.ison()) u.state = u.POWERED;
        else continue; //no power- how we get here with no vbus?
    }

    ...
    } //for loop
}

Maybe the loop and flag check make it not worth it? or maybe its a good idea as maybe usb gets multiple consecutive irq's since the stat fifo is 4 long? The usb isr does seem to require a fair amount of code to run so most likely takes longer than normal isr's.

For a other 8bit pic's I use (only 1 isr, which is processed differently of course), when checking the rx flag I usually use a loop that to get the rx buffer flushed right away.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3137
  • Country: ca
Re: Interrupt processing- one time or loop
« Reply #1 on: December 27, 2017, 05:32:13 am »
Probably doesn't matter for practical purposes. Presumably, you process your USB interrupts faster than they occur, so fishing for more interrupts in a loop is usually redundant.
 

Offline cv007Topic starter

  • Frequent Contributor
  • **
  • Posts: 822
Re: Interrupt processing- one time or loop
« Reply #2 on: December 27, 2017, 06:38:59 am »
I think you may be right. I was trying to read the mchp usb code to get ideas how they do things (very difficult), and in the TRNIF processing (in isr) they keep that part in a loop to keep the stat fifo flushed.  But, they also have the same usb code for every usb chip they ever made (it seems) including the most under-powered 8bit they have, where its probably a lot easier to bump up against the end of the usb fifo. The PIC32MM should not have any problem I guess, and an extra prologue/epilogue from time to time is not a big deal, also simpler code is better. Their usb code is a bugger to read- I have de-macro'd it, along with the original version, and grep things from the command line- still difficult.

I don't know if I can get usb working with my own code, but I'll attempt it. At least I will probably learn something along the way. I started with an empty main for the pic32mm, took one chapter of datasheet, created a 'driver' for that peripheral, repeat. I'm also learning C++ along the way.

Another question, here is my current code (for the moment)-
Does it matter the order of clearing the flags? (usb irq flag vs the various usb flags)
Code: [Select]
void USB_ISR(){
    Usb u; Irq ir;
    static Usb::state_t last_state; //keep track of usb state for resumes

    uint8_t flags = u.flags();      //get all usb specific irq flags
    uint8_t eflags = u.eflags();    //get all usb specific irq error flags
    Usb::stat_t stat;               //get stat reg BEFORE flags cleared
    u.stat(stat);                   //pass by reference
    u.flags_clr(flags);             //clear only what we got (1=clear)
    u.eflags_clr(eflags);           //clear only what we got (1=clear)
    ir.flag_clr(ir.USB);            //clear usb irq flag

    //ATTACHED->POWERED if vbus_pin high
    if(u.state == u.ATTACHED){
        if(vbus_pin.ison()) u.state = u.POWERED;
        else { //no power (not sure how we would get here with no vbus)
            return;
        }
    }

    //more code...


edit-
this may be one of those things that I know or thought I knew, but then I doubt that I really know and question it all over.
Except for persistent flags (which does matter), I think it doesn't matter. Probably.
(or I can deduce that the datasheet and reference manual don't say anything about it except for persistent flags)


« Last Edit: December 27, 2017, 07:27:55 am by cv007 »
 

Offline voltsandjolts

  • Supporter
  • ****
  • Posts: 2277
  • Country: gb
Re: Interrupt processing- one time or loop
« Reply #3 on: December 27, 2017, 09:04:35 am »
ARM Cortex has tail-chaining, does PIC32 have a similar feature?
 

Offline andersm

  • Super Contributor
  • ***
  • Posts: 1198
  • Country: fi
Re: Interrupt processing- one time or loop
« Reply #4 on: December 27, 2017, 12:36:17 pm »
ARM Cortex has tail-chaining, does PIC32 have a similar feature?
Those with cores that implement the MIPS MCU ASE have something vaguely similar, but it's not supported by Microchip's toolchain (the features have to be enabled, and a special interrupt epilogue has to be generated). If you're noticing that you're spending most running time in ISRs there could be some advantage in using a loop, since MIPS ISRs have a fairly huge overhead compared to most architectures.
 
The following users thanked this post: voltsandjolts

Offline mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 13694
  • Country: gb
    • Mike's Electric Stuff
Re: Interrupt processing- one time or loop
« Reply #5 on: December 27, 2017, 12:54:03 pm »
You'd normally do all the ints you can in one call to save the time taken getting in & out of the int code. e.g. in a UART receive int you'd loop until you'd emptied the FIFO
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 

Offline danadak

  • Super Contributor
  • ***
  • Posts: 1875
  • Country: us
  • Reactor Operator SSN-583, Retired EE
Re: Interrupt processing- one time or loop
« Reply #6 on: December 27, 2017, 01:33:01 pm »
Just as general practice -

1) Use pointers in ISR to minimize stack push.
2) Set flags in ISR and handle processing outside ISR.
3) Wherever possible use DMA to handle ISR events.


Regards, Dana.
Love Cypress PSOC, ATTiny, Bit Slice, OpAmps, Oscilloscopes, and Analog Gurus like Pease, Miller, Widlar, Dobkin, obsessed with being an engineer
 

Offline mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 13694
  • Country: gb
    • Mike's Electric Stuff
Re: Interrupt processing- one time or loop
« Reply #7 on: December 27, 2017, 01:44:17 pm »
3) Wherever possible use DMA to handle ISR events.
I'd disagree with that unless you really need the performance, because DMA can be really hard to debug.
With an ISR, you can twiddle IO bits in the ISR so you can tell exactly when ints are called, and use scope triggers to capture rare events and observe the sequence of evends. DMA just happens and you have very little visibility of what's going on.
 
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 26751
  • Country: nl
    • NCT Developments
Re: Interrupt processing- one time or loop
« Reply #8 on: December 27, 2017, 02:02:36 pm »
Just as general practice -
2) Set flags in ISR and handle processing outside ISR.
That is a very bad idea. Better do all the processing inside the ISR because that will prevent problems with sharing data between two asynchronous processes. Not to mention the extra overhead of setting & reading the flags. Also doing time critical (microseconds) processing in the main loop makes the main loop and whatever is related to it time critical while most of it won't be time very critical at all (tens of milliseconds or more). Most microcontrollers support nested interrupts so even if one interrupt takes long, you can still service a higher priority interrupt. Either way anything time critical will need an analysis regarding response time and available processing time.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline cv007Topic starter

  • Frequent Contributor
  • **
  • Posts: 822
Re: Interrupt processing- one time or loop
« Reply #9 on: December 27, 2017, 02:18:28 pm »
Maybe using the (only) shadow register set for this irq priority would be a good idea as it will be the most used I would guess. If I ever get to workable usb code, I could wiggle a pin in the usb irq to see how often back-to-back isr actually happens. I suppose one could also calculate how often its possible to get a transaction complete flag for whatever usb configuration is used, and go from there.
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: Interrupt processing- one time or loop
« Reply #10 on: December 27, 2017, 03:25:36 pm »
Just as general practice -

1) Use pointers in ISR to minimize stack push.
This may not be necessary on ARM Cortex architectures because a second stack pointer is available for interrupt processing.

Quote
2) Set flags in ISR and handle processing outside ISR.

 :-+ Assuming you have a good way to communicate from the ISR to whatever is going to do the actual processing, and no hard realtime deadlines that will be missed. E.g., with an RTOS, you can use a Semaphore to wake a thread. In this case, it's nice to separate the handling of the interrupt from the processing.

Quote
3) Wherever possible use DMA to handle ISR events.

For things like serial protocol handlers, using DMA usually means you end up with *fewer* interrupts, which is probably a good thing. I.e., instead of getting one interrupt per byte sent/received on your I2C driver, you have one interrupt from the DMA controller when it's all done. Fewer interrupts is almost always better than more.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3137
  • Country: ca
Re: Interrupt processing- one time or loop
« Reply #11 on: December 27, 2017, 03:36:15 pm »
I suppose one could also calculate how often its possible to get a transaction complete flag for whatever usb configuration is used, and go from there.

If your transfer size is 64 bytes, then the time between interrupts cannot possibly be more than 50 us. However, it depends on your protocol. For example, if you use HID, you get only one IN transfer every millisecond (or even less frequently).

You have full control and you won't receive anything until you arm your endpoint, so you can go at your own pace. Therefore, USB is a good candidate for main loop processing.
 

Offline cv007Topic starter

  • Frequent Contributor
  • **
  • Posts: 822
Re: Interrupt processing- one time or loop
« Reply #12 on: December 27, 2017, 06:32:42 pm »
The ultimate goal will be basic audio via usb to a dac, and I 'think' audio is done every frame, so 1000 irq's/sec from usb. Actual data amount probably not too important in this case as dma will do most of the work moving incoming audio out to dac.

24,000 clocks (1ms, 24MHz clock), less whatever the usb isr code uses,  is a lot of time for the pic32mm to do other things so the original question now seems unimportant.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4196
  • Country: us
Re: Interrupt processing- one time or loop
« Reply #13 on: December 28, 2017, 07:55:32 am »
There are two parts of the overhead for servicing an interrupt
  • The inherent overhead of servicing any interrupt - saving and restoring the PC and other registers, jumping to the ISR, possibly invalidating cache and memory management, and etc.  Hardware (shadow register sets, tail chaining, tightly coupled memory and/or special cache/mmu settings, etc) can minimize this, but it's always going to be there.
  • The overhead that the ISR function needs to set up the particular context for whatever device it is actually servicing.  If you're doing a USART interrupt, this usually means setting up pointers to the UART registers, and other pointers to a memory buffer somewhere, and things like that.  It could be a relatively significant amount of code.
BOTH of these are likely to involve "many" more cycles than looping in the ISR to check for more conditions, so for maximum efficiency, you probably want to loop.  Carried to extremes, that would mean you should just poll instead of using ISRs...  You'd normally avoid (or limit) looping if you are particularly concerned with latencies that the interrupt priorities don't address, or if you're pretty sure there will never be multiple things to service...   Thinking about extremes ("what happens if for some reason the system is so loaded that I DO have multiple things to service even though I think I shouldn't?") is a good idea, but I'm not sure that there's always something useful that you can figure out!

 

Online tggzzz

  • Super Contributor
  • ***
  • Posts: 19280
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: Interrupt processing- one time or loop
« Reply #14 on: December 28, 2017, 10:51:55 am »
There are two parts of the overhead for servicing an interrupt
  • The inherent overhead of servicing any interrupt - saving and restoring the PC and other registers, jumping to the ISR, possibly invalidating cache and memory management, and etc.  Hardware (shadow register sets, tail chaining, tightly coupled memory and/or special cache/mmu settings, etc) can minimize this, but it's always going to be there.
  • The overhead that the ISR function needs to set up the particular context for whatever device it is actually servicing.  If you're doing a USART interrupt, this usually means setting up pointers to the UART registers, and other pointers to a memory buffer somewhere, and things like that.  It could be a relatively significant amount of code.
BOTH of these are likely to involve "many" more cycles than looping in the ISR to check for more conditions, so for maximum efficiency, you probably want to loop.  Carried to extremes, that would mean you should just poll instead of using ISRs...  You'd normally avoid (or limit) looping if you are particularly concerned with latencies that the interrupt priorities don't address, or if you're pretty sure there will never be multiple things to service...   Thinking about extremes ("what happens if for some reason the system is so loaded that I DO have multiple things to service even though I think I shouldn't?") is a good idea, but I'm not sure that there's always something useful that you can figure out!

That's a good summary.

Those problems are avoided by using the XMOS xCORE processors, since you dedicate one core (of up to 32) to a single I/O port, and sleep until the specified condition on the I/O port occurs. The hardware wakes up the core with a latency of 10ns (XMOS states <100ns). Add "FPGA-like" I/O, delete caches, and you have an excellent basis for hard realtime processing.

All that would be useless without tight integration with the software. The xC language, based on CSP, is the excellent solution to that.
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline danadak

  • Super Contributor
  • ***
  • Posts: 1875
  • Country: us
  • Reactor Operator SSN-583, Retired EE
Re: Interrupt processing- one time or loop
« Reply #15 on: December 31, 2017, 12:28:10 am »
nctnico,


Quote
Better do all the processing inside the ISR because that will prevent problems with sharing data between two asynchronous processes

That's an excellent point. My application did not have async processes operating on the same data,
so that issue in the design not of concern.


Quote
Not to mention the extra overhead of setting & reading the flags.

Design was Cortex M3, GNU compiler shows 1 cycle to set / clear a bit. That's not using bit banding,
just C.


Quote
main loop and whatever is related to it time critical

In this design the main loop was the primary loop.


Regards, Dana.





« Last Edit: December 31, 2017, 12:32:58 am by danadak »
Love Cypress PSOC, ATTiny, Bit Slice, OpAmps, Oscilloscopes, and Analog Gurus like Pease, Miller, Widlar, Dobkin, obsessed with being an engineer
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4196
  • Country: us
Re: Interrupt processing- one time or loop
« Reply #16 on: December 31, 2017, 12:56:26 am »
Quote
Design was Cortex M3, GNU compiler shows 1 cycle to set / clear a bit. That's not using bit banding,
I find that difficult to believe; do you have an example?  (1 cycle to set a bit in a CPU register, perhaps.  But that's of pretty limited use by itself...)
 

Offline danadak

  • Super Contributor
  • ***
  • Posts: 1875
  • Country: us
  • Reactor Operator SSN-583, Retired EE
Re: Interrupt processing- one time or loop
« Reply #17 on: December 31, 2017, 02:36:16 am »
I declared a bit struc, outside of main(), then set the bit, then cleared it
inside of main().

lst file shows a single ORR, for setting, acting on one of the registers.
Reg load apparently done during initialization. So bit permanently assigned to
the register.

To your point in a more fully implemented design that reg would have to be loaded
depending on compiler decisions.

I am not a C expert by any stretch, so I could be in error.....

"limited use", discussion is setting a flag in an ISR then leaving ISR and testing/processing
bit / thread in main().


Regards, Dana.
« Last Edit: December 31, 2017, 02:40:29 am by danadak »
Love Cypress PSOC, ATTiny, Bit Slice, OpAmps, Oscilloscopes, and Analog Gurus like Pease, Miller, Widlar, Dobkin, obsessed with being an engineer
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4196
  • Country: us
Re: Interrupt processing- one time or loop
« Reply #18 on: December 31, 2017, 07:38:44 am »
Quote
I declared a bit struc, outside of main(), then set the bit, then cleared it inside of main().

lst file shows a single ORR, for setting, acting on one of the registers.  Reg load apparently done during initialization. So bit permanently assigned to the register.

OK; that makes sense, for a sufficiently tiny program...
Thanks for providing the details!
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf