From: Erich W. <ew....@na...> - 2010-07-05 19:29:29
|
Hello, Interrupt Handling in amforth: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ http://amforth.sourceforge.net/howto.html says: > 1. The low-level interrupt routine stores the > index of the interrupt in a RAM cell (not directly > accessible from amforth) > 2. sets the T-flag in the status register to signal > the inner interpreter that an interrupt needs attention. In other words: **lower half** a "default isr (interrupt service routine)" is registered to every interrupt with the exception of the rx/tx for your serial connection. e.g. in amforth/core/devices/atmega32/device.asm you find .org $002 rcall isr ; External Interrupt Request 0 .org $004 rcall isr ; External Interrupt Request 1 ... where isr is defined in amforth/core/drivers/generic-isr.asm as It determines the interrupt number and stores that on the stack, and it sets the T flag in the status register. **upper half** The inner interpreter loop will react on the T flag and call the registered amforth ISR from a table of ISR functions (exec tokens, that is). The default entry in this table points to "' noop", hence does nothing. So there are 3 options for interrupt handling: 1. write an ISR in forth and register it it the upper half dispatch table 2. write an ISR in assembler and register it to the lower half addresses 3. write an ISR in forth and do some tricky return stack juggling to have your ISR called sooner than in 2. 1. write an ISR in forth and register it it the upper half dispatch table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ simple example: --- clock_tick.frt --- \ count clock ticks from timer2 overflows: variable timer2 hex \ overflow2 interupt service routine \ increment tick : tick_isr 1 timer2 +! ; \ enable ticks \ crystal: 32768 /sec \ clock src: 32768 /sec \ overflow: 32768/256 = 128 /sec =^= 7.8125 milli-sec ticks : +ticks 1 TCCR2 c! ( 001 = clock_ts2/1 ) 8 ASSR c! ( source: 32 kiHz crystal ) ['] tick_isr TIMER2_OVFAddr int! ( register interupt ) TIMSK c@ 40 or TIMSK c! ( enable timer2 interupt ) ; \ disable ticks : -ticks TIMSK c@ [ 40 invert ff and ] literal and TIMSK c! ( clr Timer 2 ) ; --- end --- The function "tick_isr" does nothing else but increment a forth variable, namely timer2. This function is registered ['] tick_isr TIMER2_OVAddr int! when +ticks is called. After that reading the variable timer2 will result in changing values as time goes by. HOWEVER: the interrupt is taken care of when the inner interpreter loop is entered again. So if your program is stuck somewhere such that this loop is not reached any more, you are out of luck. AND HOWEVER: in the case of timer overflows, there is no interrupt flag to clear in any register. For pretty much everything else, you need to clear the corresponding flag. Then you need to do it differently: 2. write an ISR in assembler and register it to the lower half addresses ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Go to read the relevant files dealing with the serial interface. 3. write an ISR in forth and do some tricky return stack juggling to have your ISR called sooner than in 2. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There is another way to handle interrupts: the lower half isr will determine not only which interrupt was triggered, but also the execution token XT of the word registered to handle this interrupt. This XT is put onto the return stack. SO when the current word is completed, the return stack is consulted to determine, where to jump back to. Now this will call the ISR sooner than entering the inner interpreter loop. At least, this is how I understood it. An example can be found here: http://www.forth-ev.de/filemgmt/visit.php?lid=294 4th Dimension, issue 1/2010, Text in German, Code in amforth on an atmega162 I would like to mention one more thing: There is a multitasker available in in amforth. It is a cooperative multitasker, so every task needs to call "pause" at interruptible places. Then some stack acrobatik will switch to a different set of data and return stack and correct the relevant pointers. The next task is running up to the next pause. At the end of the list, the first task is serviced again. I use this setup: timer2 creates a clock (clock source is a crystal at 32768 Hz) and drives a counter. Task 1 in a loop checks the counter, does all the bookkeeping for ticks, seconds, minutes .... and dispatches calls to jobs associated with these intervalls. E.g. job.sec will read sensors if the second is a multiple of 10. Task 2 just services the serial interface. Thus I can talk to the controller, e.g. requesting it to send data, while Task 1 keeps on working. This is sufficient for everything I am doing so far. Check the amforth/applications/ewlib directory for pieces of code. Please, correct me if I'm wrong on any of the above. Hope this helps. Cheers, Erich On 07/05/2010 12:22 AM, pito wrote: > Hi dear friends, > finally I started to read the docs. The chapter on interrupts is for > me too difficult to understand so my Q: > 1. how are actually interrupts handled? I've seen the source of Lubos > Pekny's keyboard driver, but it is too complex to understand the concept > 2. I am running the sieve demo and e.g. I'd like to unterrupt simply > the interations by ctrl-C. How shall this be done? > 3. Is there an access to ISR? Can I put something in it? > 4. How the OS is using interrupts? Any periodic activity (ticks, heartbeat..) > 5. How to write a simple interrupt routine? Any simple example? E.g. > from rx? > Thanks a lot, Pito > > > ------------------------------------------------------------------------------ > This SF.net email is sponsored by Sprint > What will you do first with EVO, the first 4G phone? > Visit sprint.com/first -- http://p.sf.net/sfu/sprint-com-first > _______________________________________________ > Amforth-devel mailing list > Amf...@li... > https://lists.sourceforge.net/lists/listinfo/amforth-devel |