Newbie needs help with timer interrupt

Started by easyretter, November 26, 2005, 01:29:25 PM

Previous topic - Next topic

easyretter

Hi guys.

I have to to some programm in MASM. I have to controll a LED Matrix connected to the parallel port of the PC.
I just have to write to the portnumber of the parallel port. Thats no problem, but i have to display an arrow wanderin' from left to the right on the Display. therefore i have to do some kind of delay loop. But that yould be just kind of 'busy waiting'. It's just quick and dirty. I thought of using a timerinterrupt every second or so.
My question: how do i set up a ISR? my documentations 'bout that are really rare, i just found out that  a timer causes int 8h, so he jumps to 32h. so at address 32h has to be a jump command. but how to i tell the assembler to put the following code segment at that adress? I got some experience in programming AVRs and PICS, but MASM is completely new to me.

Thanks for answers.

ToutEnMasm

Hello,
Make a timer with masm32 is very simple.
see the sample \masm32\examples\EXAMPLE6\LCD\lcd.asm

or http://www.masmforum.com/simple/index.php?action=dlattach;topic=2544.0;id=1368

in the wndproc
in the WM_CREATE  message use
; --- Create a timer message ,every 500 ms ---
   invoke   SetTimer, hWnd, MAINTIMERID, 500, NULL

Then use the WM_TIMER message
                 ;execute actions

                      ToutEnMasm






easyretter


LL

Hi easyretter,

I'm new to programming, but I get the impression that (if by ISR, you mean: Interrupt Service Routine), wouldn't this question go in the 16 bit Dos Programming Forum. But like I said, I'm new to programming.

LL

MichaelW

If you intend to implement this as a 16-bit DOS app, synchronizing everything with a simple polling loop would be by far the easiest method. For a simple task like the one you describe the CPU would be idle most of the time anyway, so why not use it to run a polling loop? Your loop could synchronize with the system timer tick by waiting for the 32-bit timer-ticks-since-midnight count, stored in the BIOS data area at 40h:6Ch, to change. The BIOS ISR updates the count 18.2 times per second.

If instead you want to do it the hard way:

If you do not already have Ralf Brown's Interrupt list:
An HTML version is here:
http://www.ctyme.com/rbrown.htm
And the download version here:
http://www-2.cs.cmu.edu/~ralf/files.html

Rather than interrupt 8, which is actually a hardware interrupt (IRQ0), it would probably be better to use the User Timer Tick, interrupt 1Ch. To install the interrupt handler the normal sequence would be:

Use interrupt 21h, function 35h to get and save the current interrupt vector.

Use interrupt 21h, function 25h to set the vector to the new handler.

Before the program terminates, use interrupt 21h, function 25h to restore the original vector.

This is recycled from one of my posts on the old forum:

The bottom 1024 bytes of memory are used to store a 256-entry interrupt vector table, with each entry storing the far address of the corresponding interrupt handler. In response to a hardware or software interrupt, the CPU completes the current instruction, saves the current context (the flags, CS, and IP registers, in that order) to the stack, reads the appropriate vector-table entry, and jumps to the specified address. Interrupts will commonly have more than one handler installed, and when this is the case the handlers form a "chain". The vector-table entry always contains the address of the most recently installed handler. When a new handler is installed, the initialization routine will normally save the address of the current handler before it sets the vector-table entry to the address of the new handler. The new handler will normally use this saved address to "chain" to the previous handler, generally by one of two different methods. The first, and perhaps most common method, would be a far jump to the previous handler, positioned at the end of the new handler. The second method would be used when the new handler needs to perform some final operation after all of the previous handlers have returned. This would involve simulating an interrupt call to the previous handler (using a PUSHF followed by a CLI followed by a far call), and would cause the IRET at the end of the handler chain to return control to the new handler. The new handler would then complete whatever it needed to do and execute an IRET, which would cause the CPU to return control to the interrupted program.

Interrupt handlers must generally:

1. For hardware interrupt handlers; preserve all registers other than the flags register, which the CPU automatically preserves. For service program handlers called via software interrupts, preserve all registers that are not used to return a value. If a service program handler needs to return a value in the flags, then to get around the CPU's preservation of the flags register the handler must locate and modify the flags that the CPU stored on the stack.
2. Avoid calling DOS (actually, you can call DOS under very specific circumstances, but the whole thing is IMO too complex to be worth doing).
3. Avoid reentering handlers. Failure to do so can cause difficult to find, and for some hardware interrupt handlers, very serious, problems. The common method of doing this involves checking a busy flag at the entry of the handler. If the flag is not set, then the handler sets the flag, handles the interrupt, and clears the flag before chaining (normally with a far jump). If the flag is set, the handler chains (with a far jump) without further action.
4. Avoid reentrant calls to the BIOS functions. Failure to do so can cause the functions to fail because the functions are in general not designed to support reentrant calls. AFAIK the most reasonable way to do this is to install a handler for each BIOS interrupt or function that will be called and maintain a flag that indicates whether or not the interrupt or function is busy. The caller can check the flag, and if the interrupt or function is busy, either skip the call entirely (chain) or postpone it until the flag indicates not busy (usually involves setting a flag and having a timer tick handler complete the call when the function is not busy). BTW, this would be an application for the second chaining method described above.
5. When the interrupt handler receives control, the only segment register with a known value is CS. For this reason, any variables that an interrupt handler needs to access, including the address of the previous handler, should be stored in the code segment. The handler can access data in the code segment by using a CS override, or by copying the value from CS into DS. Note that the string instructions do not support a segment override.

eschew obfuscation