Author Topic: Event triggered by Interrupt  (Read 3266 times)

0 Members and 1 Guest are viewing this topic.

Offline T3sl4co1lTopic starter

  • Super Contributor
  • ***
  • Posts: 21658
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Event triggered by Interrupt
« on: June 09, 2018, 12:27:31 pm »
I'm thinking about a method, which works fine on a lot of platforms, but which happens to be kind of actively defeated by the XMEGA hardware.

So, the general dilemma I have is: either I need to escalate my methods (hack around the limitation), or, probably more wisely -- I need to find an alternative method that's more common and general.

The exact situation is this: I have a periodic timer interrupt.  Every, say, 256th interrupt, I want to fire an additional low-priority operation.

The operation could potentially run for a long time, so:
1. Interrupts are enabled during it.  (Including the timer interrupt, in which case it momentarily ends up on the stack twice.)
2. It's blocked with an "in-function" flag.

The heavy-weight method would be a full task switch, so it runs as an alternate main(), and the various low-priority tasks (including main() itself proper) run whenever.  But I'd rather not write or import an RTOS here, that's way overkill...

So what's the matter?  The XMEGA has an interrupt controller which apparently cannot be defeated (the status registers are read only).  All it's watching for, is that RETI instruction at the end of the ISR.

Simply enabling interrupts, works perfectly fine on an ATMEGA, which has simple interrupt control.  It even works on a PC*, give or take what commands you have to send to the PIC to acknowledge the interrupt.

*Old PCs, as in MS-DOS era.  Embedded MCUs have more than eclipsed the old PC in capabilities now; I think of vintage PCs more as historic examples of quirky, bulky embedded systems, that happen to have a couple fairly rich peripherals on them (notably, relatively large RAM, graphical output, and disk I/O).

What approach to follow?

It seems to me, a tail call would do just fine.  Push the destination function address on the stack, then RETI.  The interrupt flag clears, the destination is jumped to, and any interrupt can fire.  I don't think this is something I can convince GCC to do, though... sure, it'll do that optimization automatically in a function, but in an ISR?

I could write the ASM, no problem.  Not worried about that.  But that's admitting I need a hack.  As far as I know, this is an uncommon method/problem/situation, but it doesn't feel so uncommon that that kind of hack should be required to solve it.

I don't want to set a flag and check it in main(), because that requires a polling loop.  If I ever execute blocking functions in main(), that goes in the crapper.  And I already intend on doing just that, and I'd rather not muck up those blocking functions with polling thrown in everywhere...

I could trigger a low-priority interrupt; if there were software interrupts, that'd have potential.  There's a dozen peripherals I'm not using at the moment, which could serve as an interrupt source; but that's not very general.  What if I end up needing one?

Same goes for pin change interrupts.  I do happen to have free GPIOs I could use for this, but that seems hacky as well.

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Online ajb

  • Super Contributor
  • ***
  • Posts: 2601
  • Country: us
Re: Event triggered by Interrupt
« Reply #1 on: June 09, 2018, 05:56:10 pm »
Sounds like you've managed to talk yourself out of all of the available options on an AVR, sooo... switch to an ARM and use PendSV?  Atmel's SAM D (M0+) parts are quite nice as a step up from the XMEGA class of AVRs.

Really, though, the kind of task switching you're talking about is RTOS territory.  If you don't want the "hack" of writing your own pseudo context switching, then the other option is to not write blocking functions, or at least split them up into state machines so that they can yield while blocked and let your main polling loop run fast enough to hit the longer task however promptly you need.  Actually, since you mentioned other tasks still needing to run in the new context, rolling your own task switching could get messy unless you can guarantee that an in-progress task can complete atomically before the switch is made, and at that point you're not much better off than a superloop. 
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3143
  • Country: ca
Re: Event triggered by Interrupt
« Reply #2 on: June 09, 2018, 10:26:22 pm »
I could write the ASM, no problem.  Not worried about that.  But that's admitting I need a hack.  As far as I know, this is an uncommon method/problem/situation, but it doesn't feel so uncommon that that kind of hack should be required to solve it.

If you used RTOS, it would have assembler routines for context switching. So, you get the "hack" either way.
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 825
Re: Event triggered by Interrupt
« Reply #3 on: June 10, 2018, 01:31:53 am »
If you inline asm the call to long task/reti as you indicate, the compiler will not know about it and may not have saved all the caller-saved registers.

« Last Edit: June 10, 2018, 04:03:30 pm by cv007 »
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: Event triggered by Interrupt
« Reply #4 on: June 10, 2018, 07:53:23 am »
Quote
So what's the matter?  The XMEGA has an interrupt controller which apparently cannot be defeated (the status registers are read only).  All it's watching for, is that RETI instruction at the end of the ISR.
Are you sure?  The status register is read-only, but there's a separate control register that claims to have enable/disable bits for the different levels of interrupts...
You said "every 256 timer cycles", but you also said the low-level process runs for multiple timer ticks, so I'd guess that isn't a critical ratio.  Unless you're really using all the myriad timers (including RTC and anything else that might be re-interpreted as a timer) it seems like it would be a lot easier to simply set up a separate timer (at low priority) for the less frequent process.  Driving everything from a single clock tick is swell, but it's really just an admission that it would have been nice to have more hardware timers.

I guess you've mentioned this, but...

It seems like the multi-level interrupt system should make this easier; run your normal interrupts at medium or high level, and when you want to run your low-priority process, have the medium level ISR trigger a low-level interrupt.  When the normal ISR returns, the low-level interrupt will trigger, and it will be interruptable by the high/medium level interrupts. (or, I think it's possible to have this all happen via the event system, though I'm not familiar with it, so I'm not sure exactly how.)
I think that in the absence of "software interrupt" triggers or something like ARM's PENDSV, I think "hacks" are your only choice.
 

Offline T3sl4co1lTopic starter

  • Super Contributor
  • ***
  • Posts: 21658
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: Event triggered by Interrupt
« Reply #5 on: June 10, 2018, 09:39:53 am »
Are you sure?  The status register is read-only, but there's a separate control register that claims to have enable/disable bits for the different levels of interrupts...

Yeah, but I don't want to disable it, that's the whole point. :P  Unless disabling it resets the flag, and enabling it again leaves none the wiser?  Hmm, maybe worth a try.

Quote
You said "every 256 timer cycles", but you also said the low-level process runs for multiple timer ticks, so I'd guess that isn't a critical ratio.  Unless you're really using all the myriad timers (including RTC and anything else that might be re-interpreted as a timer) it seems like it would be a lot easier to simply set up a separate timer (at low priority) for the less frequent process.  Driving everything from a single clock tick is swell, but it's really just an admission that it would have been nice to have more hardware timers.

I'd like some well-timed operations at the front, then whatever for the rest of the routine, so it should still start ~synchronously.

Well.  I suppose by definition, I should put those in the primary timer routine...

Point taken about the timers; and the XMEGA are better stocked on them than the old kind, including more compare-capture registers which I'm certainly not using all of on the timer channel.  I could disable that most of the time except during the special 256th cycle, that would work well.

Quote
It seems like the multi-level interrupt system should make this easier; run your normal interrupts at medium or high level, and when you want to run your low-priority process, have the medium level ISR trigger a low-level interrupt.  When the normal ISR returns, the low-level interrupt will trigger, and it will be interruptable by the high/medium level interrupts. (or, I think it's possible to have this all happen via the event system, though I'm not familiar with it, so I'm not sure exactly how.)
I think that in the absence of "software interrupt" triggers or something like ARM's PENDSV, I think "hacks" are your only choice.

Yeah, that's why I'm interested, it feels so close to possible, and would be reasonably convenient.

It looks like you can strobe the hardware event system from software, but there is no interrupt source from the system.  (That would've been cool, but I guess they figured it wasn't necessary.)

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 825
Re: Event triggered by Interrupt
« Reply #6 on: June 10, 2018, 01:43:29 pm »
__attribute((naked)) void enable_this_irqlevel(){ asm("reti"); }
 

Offline T3sl4co1lTopic starter

  • Super Contributor
  • ***
  • Posts: 21658
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: Event triggered by Interrupt
« Reply #7 on: June 11, 2018, 10:42:42 am »
__attribute((naked)) void enable_this_irqlevel(){ asm("reti"); }

Gave this a try, I'm getting random dropped characters from the serial output.  Thoughts?

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 825
Re: Event triggered by Interrupt
« Reply #8 on: June 11, 2018, 02:16:29 pm »
Quote
gave this a try, I'm getting random dropped characters from the serial output.  Thoughts?
I'll assume isr is something like-

ISR(some_timer){
  static uint8_t counter;
  static uint8_t long_task_busy;
  clear_timer_flag_here();
  if(++counter || long_task_busy) return;
  long_task_busy = 1;
  enable_this_irqlevel();
  long_task();
  long_task_busy = 0;
}

you can check the asm output to make sure 'enable_this_irqlevel()' compiles to a call to a single reti - I don't think it would be optimized away since it has an asm statement, but you have to check.

if it is correct- a call to a reti, then you got what you asked for :)

typical thread- (attempt at humor)
q: how do I take a wheel off of my car?
a: why do you want to take the wheel off? what engine does it have? is the car inside the garage or outdoors? do you have the manual? what color is the car?
me: jack up the car until the wheel is off the ground, remove the wheel nuts

q: ok, I got the wheels off, but why is my air conditioner still not working?

:)
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 11859
  • Country: us
Re: Event triggered by Interrupt
« Reply #9 on: June 11, 2018, 02:22:52 pm »
I'm having trouble understanding the difficulty.

If you were running on bare hardware without an OS, then I think you would have a main loop that can test flags and branch appropriately when a flag is set. Yes, it would be polling, but what else does it have to do?

If you were running with an OS, then I think you would use a software interrupt. The SWI would run at lower priority than the hardware interrupts and would not block them. An RTOS should usually have interrupt priorities and would be designed for just this situation.
 

Offline T3sl4co1lTopic starter

  • Super Contributor
  • ***
  • Posts: 21658
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: Event triggered by Interrupt
« Reply #10 on: June 11, 2018, 11:40:31 pm »
I'll assume isr is something like-

Yes, except clear_flag is automatic thanks to the hardware.  That's basically verbatim what it is now, before I expand it with whatever the project actually needs.

Quote
you can check the asm output to make sure 'enable_this_irqlevel()' compiles to a call to a single reti - I don't think it would be optimized away since it has an asm statement, but you have to check.

From the .lss:
Code: [Select]
00000c96 <enable_this_irqlevel>:
 c96: 18 95        reti

Quote
typical thread- (attempt at humor)
<snip>

Yeah, having replied to many X-Y Problems myself, I'm keenly aware of the X-Y Problem potential of this situation!

Unfortunately, based on the expert opinions given here, it seems that I have, in fact, exhausted all the possibilities already, and will have to compromise somehow.

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 825
Re: Event triggered by Interrupt
« Reply #11 on: June 12, 2018, 01:05:06 am »
Quote
From the .lss:
I would also make sure the call to that function is also taking place- the call is still under compiler control (I'm not sure if the optimizer would even attempt to eliminate that call). Although I guess it would probably be obvious if the timer irq is being re-enabled or not.
 

Offline Hypernova

  • Supporter
  • ****
  • Posts: 655
  • Country: tw
Re: Event triggered by Interrupt
« Reply #12 on: June 12, 2018, 01:16:01 am »
Is there any reason you can't just use two timers with different priorities with the slower one at /256'th rate of higher one? It's been 7 years since I last touched a XMEGA but I don't recall multi level nested ISR being that difficult to do.
 

Offline T3sl4co1lTopic starter

  • Super Contributor
  • ***
  • Posts: 21658
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: Event triggered by Interrupt
« Reply #13 on: June 12, 2018, 01:21:32 am »
Quote
From the .lss:
I would also make sure the call to that function is also taking place- the call is still under compiler control (I'm not sure if the optimizer would even attempt to eliminate that call). Although I guess it would probably be obvious if the timer irq is being re-enabled or not.

Well like I said, it has effects.  Serial is dropping characters when it's present, and flawless when commented out.

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline T3sl4co1lTopic starter

  • Super Contributor
  • ***
  • Posts: 21658
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: Event triggered by Interrupt
« Reply #14 on: June 12, 2018, 01:25:26 am »
Is there any reason you can't just use two timers with different priorities with the slower one at /256'th rate of higher one? It's been 7 years since I last touched a XMEGA but I don't recall multi level nested ISR being that difficult to do.

Right now, no, but if there's an application that requires a strict sequence, it would be nice to know of a solution.

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Event triggered by Interrupt
« Reply #15 on: June 12, 2018, 06:34:42 am »
Not sure if I understand the problem correctly but it sounds like you have a low prio background task that is dormant until it's triggered from an (256th) interrupt...

So the mainloop simply checks the 'run-background-task-is-active' flag - set by the interrupt handler with its timing/counting logic- and then processes slices of that task in the main loop.

Having an RTOS would help, but my low level task macro's will also work...

Hope it helps
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline NivagSwerdna

  • Super Contributor
  • ***
  • Posts: 2495
  • Country: gb
Re: Event triggered by Interrupt
« Reply #16 on: June 12, 2018, 06:55:43 am »
Sounds like you want to make your IRQ routine re-entrant.  That should be feasible.  Don't return but instead just enable the interrupt within the interrupt routine and use status flags to detect if an interrupt is currently active within the IRQ routine?
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: Event triggered by Interrupt
« Reply #17 on: June 12, 2018, 08:06:02 am »
If your timer function is based on an output compare interrupt, there's the interesting (hacky) possibility of setting the timer count to MAX-1 instead of 0, so that you (shortly) get a timer overflow interrupt (at a different priority) in addition to the usual OC match interrupts...  (but I guess the reset to 0 is automatic, and this would cause a bit of skew...)
 

Offline T3sl4co1lTopic starter

  • Super Contributor
  • ***
  • Posts: 21658
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: Event triggered by Interrupt
« Reply #18 on: June 12, 2018, 09:06:46 am »
Not sure if I understand the problem correctly but it sounds like you have a low prio background task that is dormant until it's triggered from an (256th) interrupt...

Nah, that would work fine.  The problem is that I want to avoid doing that because it makes everything else more complicated...

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline T3sl4co1lTopic starter

  • Super Contributor
  • ***
  • Posts: 21658
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: Event triggered by Interrupt
« Reply #19 on: June 12, 2018, 09:07:17 am »
Sounds like you want to make your IRQ routine re-entrant.  That should be feasible.  Don't return but instead just enable the interrupt within the interrupt routine and use status flags to detect if an interrupt is currently active within the IRQ routine?

As mentioned in OP, that works on devices without this PMIC.

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 825
Re: Event triggered by Interrupt
« Reply #20 on: June 12, 2018, 12:30:06 pm »
Quote
Serial is dropping characters when it's present, and flawless when commented out.
I assume the 'it' is the call to the reti function. If the compiled size is changing more than 4 bytes (or whatever the call is) then there is more the compiler is up to. In any case I would see what the compiler generates for the isr with/without the call. Of course the other difference, which is what you are after, is now the irq level is enabled while your long task is working (where your serial output takes place?- we don't know).
 

Offline T3sl4co1lTopic starter

  • Super Contributor
  • ***
  • Posts: 21658
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: Event triggered by Interrupt
« Reply #21 on: June 12, 2018, 02:46:09 pm »
Yes, here's the result with it in:

Code: [Select]
c66: 80 91 5a 21 lds r24, 0x215A
 c6a: 81 11        cpse r24, r1
 c6c: 0a c0        rjmp .+20      ; 0xc82 <__vector_14+0x56>
 c6e: 81 e0        ldi r24, 0x01 ; 1
 c70: 80 93 5a 21 sts 0x215A, r24
 c74: 0e 94 15 06 call 0xc2a ; 0xc2a <enable_this_irqlevel>
 c78: 78 94        sei
 c7a: 0e 94 1a 01 call 0x234 ; 0x234 <do256HeartBeat>
 c7e: 10 92 5a 21 sts 0x215A, r1

And without:

Code: [Select]
c64: 80 91 5a 21 lds r24, 0x215A
 c68: 81 11        cpse r24, r1
 c6a: 08 c0        rjmp .+16      ; 0xc7c <__vector_14+0x52>
 c6c: 81 e0        ldi r24, 0x01 ; 1
 c6e: 80 93 5a 21 sts 0x215A, r24
 c72: 78 94        sei
 c74: 0e 94 1a 01 call 0x234 ; 0x234 <do256HeartBeat>
 c78: 10 92 5a 21 sts 0x215A, r1

(enable_this_irqlevel is not called, but isn't removed from the output.  *Checking*, ah, link-time optimization removes it when commented out, I see.)

Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline Marco

  • Super Contributor
  • ***
  • Posts: 6719
  • Country: nl
Re: Event triggered by Interrupt
« Reply #22 on: June 12, 2018, 07:08:05 pm »
There already is a standard mechanism in GCC for this, the bog standard by default reentrant interrupt routine. It's the XMEGA which fucks it up with its weird hardware. So despite the problem being common, it seems unlikely there is some non hacky solution to it. Just manipulate the stack and call RETI in assembly and see if GCC handles the return from your non interrupt function back to main correctly, if not hack some more.

Hell, I see you have to jump assembly hoops to do reentrant interrupt routines in ARM as well ... if you can't do it cleanly there, it seems unlikely for XMEGA.
« Last Edit: June 12, 2018, 07:10:00 pm by Marco »
 

Offline T3sl4co1lTopic starter

  • Super Contributor
  • ***
  • Posts: 21658
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: Event triggered by Interrupt
« Reply #23 on: June 12, 2018, 10:08:06 pm »
Oh yeah, so, the problem would be the offending second RETI after when the 256-function eventually returns.

So I need a regular RET (not RETI, and not GOTO __epilogue__ i.e. continuing the normal program flow through the ISR's default RETI).

Which means the dropped serial char is when enough ISRs happen to be on the stack that one gets dropped by the double-RETI.  Or maybe it's when the serial transmit just dings ready, then gets immediately deasserted and skipped by the RETI.

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf