Announcement

Collapse
No announcement yet.

8243(4) timer interrupts

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • 8243(4) timer interrupts

    I am trying to understand how to use the 8253/4 timer to output
    a pulse train of a desired frequency. I know about int 08,and 1C.
    I know that I write a control word to &h43 to set mode,timer
    channel and then load lobyte,hibyte to &h40. This sets the timer
    to something other than the standard 18.2 ticks per second.

    What I don't know is how to use the resulting timer ticks to
    accomplish my goal: Delay the output routine until the tick!

    I am writing a DOS process control routine which needs to send
    out a stream of pulses which speed up and slow down at programmed
    rates with accel/decel ramps.

    My first implementation(s) used delay loops. I'd like to move to
    a hardware based solution.

    The ideal situation would be have microsecond granularity. Rates will not
    usually exceed 20k hz. Most everything I've found relates to timing
    an event, like the typical use of PB35/dos MTIMER.

    What I want is to process through my program, setting things up
    and then waiting until the tick/interrupt comes and branches to
    my pulse output code. Set the p-port bit(s),clear them ,then set
    up and do it again, smoothly.

    I tried to use the PB WAIT cmd with port &H40, but using mtimer
    to measure results did not work well. I still think this sparsely
    documented command (in PB35) could work??

    I have lurked here for some time and I know there's a LOT of
    experience out there! I have tried to read everything in the
    forum re: timing,delays that I could think of to search upon.

    So how about it Guys (and Gals), anybody have a simple dos interrupt
    routine for microsecond rate creation. We can reprogram the timer
    tick on exit, and reset the clock from the cmos realtime clock?
    Or chain the 08 int to our sped up ticker. Either way will work
    for me.


    I dont want to use the pentium cputicker, still a lot of 486's
    doing control work.

    Thank you in advance for any help.


    OOPS! 8253/4 Arghh! And in my first post

    ------------------


    [This message has been edited by Randal Milota (edited August 11, 2000).]

  • #2
    Probably not what you want, exactly, but an old assembler routine I
    first saw doing HeathKit stuff for my H89 S/N 669 that might help
    you. It has both the key line code for the serial port control
    as well as sound for the CW. From it maybe you will get some idea
    of what you wamt. Since you didn't post the frequency range for
    the switcher here goes nothing...

    Code:
            PAGE            ,105
            TITLE           MONKEY
            .MODEL          MEDIUM
    ;---ROUTINE TO TURN ON TRANSMITTER AND SOUND FOR TIME PASSED IN THE
    ;---AX REGISTER
           .CODE
                            PUBLIC  MONKEY
            MONKEY  PROC
                            PUSH    BP              ;push the stacp onto BP
                            MOV     BP,SP           ;move the stack pointer to BP
                            PUSH    SI
                            PUSH    DI
                            PUSH    SS
                            PUSH    DS
    
    ;---CHECK FREQUENCY:
                            MOV     BX,[BP + 8]     ;address of <fq>
                            MOV     CX,[BX]         ;value of <fq> in CX
                            CMP     CX,0            ;check for zero or negative
                            JLE     NOKEY           ;send output only if pos freq
    
    ;---TURN ON TRANSMITTER:
                            MOV     AX,40H
                            MOV     ES,AX
                            MOV     DX,ES:[0]
                            ADD     DX,3
                            MOV     AL,100O         ;move break set value into AL
                            OUT     DX,AL           ;turn on break bit/transmitter
    
    ;---ENABLE CHANNEL 2 SET PORT B OF 8255:
            PORT_B          EQU     61H             ;get address of PB on 8255 chip
                            IN      AL,PORT_B       ;get Port B
                            OR      AL,3            ;turn on 2 low bits (3=00000011B)
                            OUT     PORT_B,AL       ;send changed byte to Port B
    
    ;---SET UP I/O REGISTER:
            COMMAND_REG     EQU     43H             ;set address of command register
            CHANNEL_2       EQU     42H             ;set address of channel two
                            MOV     AL,10110110B    ;bit pattern for channel 2, 2 bytes
                            OUT     COMMAND_REG,AL  ;send byte to command register
    
    ;---SEND COUNTER TO LATCH:
                            MOV     AX,1487         ;the counter: 1190000/800 cps
                            OUT     CHANNEL_2,AL    ;send LSB
                            MOV     AL,AH           ;shift MSB, since must send from AL
                            OUT     CHANNEL_2,AL    ;send MSB
    
    ;---TIMER:
                            MOV     AH,86H          ;set function number
                            MOV     BX,[BP + 6]     ;get location of low bytes
                            ADD     BX,2            ;convert to high bytes location
                            MOV     CX,[BX]         ;put it in CX
                            MOV     BX,[BP + 6]     ;get location of low bytes
                            MOV     DX,[BX]         ;put it in DX
                            INT     15H             ;get the time of day count
    
    ;---TURN OFF SOUND:
                            IN      AL,PORT_B       ;get the byte in Port B
                            AND     AL,11111100B    ;force the two bits to 0
                            OUT     PORT_B,AL       ;send the changed byte to Port B
    
    ;---TURN OFF TRANSMITTER:
                            MOV     AX,40H
                            MOV     ES,AX
                            MOV     DX,ES:[0]
                            ADD     DX,3
                            MOV     AL,0O           ;move break bit off into Al
                            OUT     DX,AL           ;turn off break bit/transmitter
                            JMP     OUTSIDE
    
    ;---WHAT TO DO IF NO SOUND NEEDED:
            NOKEY:
    
    ;---TIMER:
                            MOV     AH,86H          ;set function number
                            MOV     CX,0            ;null CX register
                            MOV     DX,0            ;null DX register
                            MOV     BX,[BP + 6]     ;get location of low bytes
                            ADD     BX,2            ;convert to high byte location
                            MOV     CX,[BX]         ;put it in CX
                            MOV     BX,[BP + 6]     ;get location of low bytes
                            MOV     DX,[BX]         ;put it in DX
                            INT     15H             ;get the time of day count
    
    ;---MASTER RETURN:
            OUTSIDE:
                            POP     DS
                            POP     SS
                            POP     DI
                            POP     SI
                            POP     BP              ;restore the stack from BP
                            RET     4               ;Return to main
                    MONKEY  ENDP                    ;end of procedure statement
                            END
    You can then make that a part of a library you use for PowerBasic.
    From that point, once in a library, you then simply issue the CALL
    to that code:

    Code:
             DECLARE SUB MONKEY(Ifreqs%, InHigh&) ' Sound and key
    
    
    SUB KP49682(VNX1&, KRADOTS&, KWTMRK&, KWTSPC&) PUBLIC ' MAKEDOT:
             ' Globals are none
             ' It looks like Ifreqs may be BX and InHigh& may be CX
             Ifreqs! = 1'                           Make sound
             InHigh& = (VNX1& * (.455 + ((KRADOTS& - 50) / 50) * .2)) + (VNX1& * (.455 + ((KWTMRK& - 50) / 50) * .5))'      Weighted dot tone
             CALL MONKEY(Ifreqs%, InHigh&)'                         Sound and key
             Ifreqs! = 0'                           Make no sound
             InHigh& = (VNX1& * (.455 + ((KRADOTS& - 50) / 50) * .2)) + (VNX1& * (.455 + ((KWTSPC& - 50) / 50) * .5))'      Weighted silence
             CALL MONKEY(Ifreqs%, InHigh&)'                         No sound just delay
             END SUB
    
    SUB KP49683(VNX1&, KRADASH&, KWTMRK&, KWTSPC&) PUBLIC ' MAKEDASH:
             ' Globals are none
             Ifreqs! = 1'                           Make sound
             InHigh& = (VNX1& * (1.365 + ((KRADASH& - 50) / 50) * .2)) + (VNX1& * (1.365 + ((KWTMRK& - 50) / 50) * .5))
             CALL MONKEY(Ifreqs%, InHigh&)
             Ifreqs! = 0'                           Make no sound
             InHigh& = (VNX1& * (.455 + ((KRADASH& - 50) / 50) * .2)) + (VNX1& * (.455 + ((KWTSPC& - 50) / 50) * .5))
             CALL MONKEY(Ifreqs%, InHigh&)
             END SUB
    Obviously, you can in-line assembler code all of the above in our
    wonderful PowerBASIC venue! Things have change a *LOT* since I bought
    my still here - still running Heath H89!

    As well, there is a Brady book in the suggested reference section
    that comes with PowerBASIC, by Robert Jourdain. His "Programmer's
    Problem Solver for the IBM PC, XT and AT" - has a whole section on
    port control and sound in it starting on page 56 through page 87.

    That's what I studied when I started working on this stuff for port I/O
    control code back around 1986 or so. Obviously all this has changed
    somewhat since then, but the above is where I started.

    However, if you're interest, you can hear this sort of code doing its
    job any Sunday evening on 3516Khz running complete 25WPM telegraph
    bulletins at 9 pm CDT .. from PowerBASIC compiled equipment control,
    logging and total operations control code. It's modified from the
    above to do lots of different jobs, but the core thinking is in the
    above example stuff posted above.

    Looking a bit further down the road to the actual hardware interface to
    the RS-232 port, you can look into the annual indexes for QST, the
    ARRL's ham radio fraternal journal. From time to time there will be
    suggestions for schematics for simple interfaces between an RS-232
    port and relays or other solid state devices that can take the line
    status changes the above code will make in the RS-232 port and convert
    that low level voltage state change to control for whatever.

    I *THINK* it would be possible to use ASCI art to actually post the
    schematics for these simple one-transistor and few cap and resistor
    circuits here, but I'll be darned if I want to try to be the first
    to post an ASCI art schematic in this forum!

    I already cause enough trouble with some of my notions here!

    Hope This Helps, if it's not too BASIC ..





    ------------------
    Mike Luther
    [email protected]
    Mike Luther
    [email protected]

    Comment


    • #3
      Randal,
      I'm not sure what your problem is as you seem to understand all of the difficult bits.
      Perhaps the code below is what you want. Replace port 128 with the address of your own output port, change the line
      @NextVal=value%
      to
      @NextVal=[your own calculation of the next value]

      Sort out the clock yourself, I haven't.

      Remember, all of the values are Timer Ticks =0.838 micro seconds each.

      I've tested this and it works but you might not get 1us resoloution because the access to the timer chip takes longer than that.

      Paul.


      REM PB3.5 program to create hardware timed pulses

      DIM done as dword ptr,NextVal as dword ptr
      done=codeptr32(DoneFlag)
      NextVal=codeptr32(NextValue)

      @NextVal=1234 :REM this is the initial value for the timer

      REM clear the flag to indicate interrupt has not occurred
      @done=0

      REM install the code and begin the first time interval
      Install(@NextVal)

      FOR value%=1 to 1000:REM I have this many values to output

      REM get the next timer value ready from wherever they are calculated...
      @NextVal=value%

      REM wait for timer interrupt to occur
      DO
      LOOP UNTIL @done

      REM clear the DoneFlag
      @done=0

      NEXT value%

      REM unistall the interrupt routine and fix the timer
      UnInstall

      END


      SUB install(InitValue%)
      REM call this sub to install the interrupt routine by intercepting the timer interrupt

      low?=InitValue% MOD 256
      high?=InitValue \ 256

      !mov al,&h34 ;make sure PIT timer0 is in mode 2
      !out &h43,al
      !mov ax,low? ;and set to initial timer value
      !out &h40,al
      !mov al,high?
      !out &h40,al

      !les bx,Int1cV ;get address of Int1c vector
      !mov ax,es:[bx] ;copy offset to ExitVector
      !mov ExitVector[01],ax
      !mov ax,es:[bx+02] ;copy segment to ExitVector
      !mov ExitVector[03],ax

      !cli ;disable interrupts while changing interrupt vector
      !lea ax,Int1cEntry ;get int routine entry to Int1c vector
      !mov es:[bx],ax ;move offset of my routine to Int1c vector
      !mov es:[bx+02],cs ;move segment of my routine to Int1c vector
      !sti ;Enable interrupts

      END SUB

      SUB uninstall
      REM Call this SUB to restore the interrupt vectors when finished.
      REM The timer will also need to be reset, that isn't done here.

      !cli ;disable interrupts while restoring interrupt vector
      !les bx,Int1cV ;get address of Int1c vector
      !mov ax,ExitVector[01] ;Restore Int1c vector
      !mov es:[bx],ax ;restore offset
      !mov ax,ExitVector[03]
      !mov es:[bx+02],ax ;restore segment
      !sti ;Enable interrupts

      END SUB

      SUB introutine
      REM this is the actual interrupt routine that will be called on each timer
      REM interrupt.


      REM Int1c is the user exit from BIOS of the 18.2Hz interrupt routine

      Int1cEntry:
      !pushf ;save flags
      !push ax ;save ax


      !mov al,&h34 ;Write new value to timer
      !out &h43,al
      !mov ax,NextValue
      !out &h40,al
      !mov al,ah
      !out &h40,al

      !mov al,255 ;pulse the output, use your own port number
      !out 128,al
      !mov al,0
      !out 128,al


      !mov al,1
      !mov DoneFlag,al ;set a flag to let code know the interrupt has occurred


      Int1cExit:
      !pop ax ;restore ax
      !popf ;restore flags

      ExitVector:
      !jmp far ExitVector ;exit via copy of original int1c vector copied into
      :'this location immediately after the JMP byte

      Int1cV:
      !dd &h00000070 ;Int1c vector

      DoneFlag:
      !dd 0

      NextValue:
      !dd 0

      END SUB



      ------------------

      Comment


      • #4
        Randal,
        some notes on the above program:

        As posted, the timer value varies from 1 to 1000. In practice small values may not work. If the value is too small then the computer may not have time to re-load the timer before it re-interrupts so the computer may crash. This will be more of a problem on your 486's. You may need to experiment with the minimum values you can get away with. As you want 20kHz max. then this should not be a problem.

        The code will not work under Windows, only use it in DOS.

        I forgot to restore the PIT timer to its usual value on exit, use the following version of SUB uninstall, it resets the PIT to 0 to give 18Hz timer ticks when you're finished.

        Paul.


        SUB uninstall
        REM Call this SUB to restore the interrupt vectors when finished.
        REM The timer will also need to be reset, that isn't done here.

        !cli ;disable interrupts while restoring interrupt vector
        !les bx,Int1cV ;get address of Int1c vector
        !mov ax,ExitVector[01] ;Restore Int1c vector
        !mov es:[bx],ax ;restore offset
        !mov ax,ExitVector[03]
        !mov es:[bx+02],ax ;restore segment
        !sti ;Enable interrupts

        !mov al,&h34 ;restore correct timer contents
        !out &h43,al
        !mov al,0
        !out &h40,al
        !out &h40,al

        END SUB

        Comment


        • #5
          Mike and Paul,

          First, thank you both for the reply(s).

          Mike, I can't print out your code (or cut and paste)it. Using Win98
          Its too wide for the printer; and no crlf in the text file?
          I'm using the p port, and will try to get a look at the suggested
          book. It sounds (pun intended) familiar, so I may have seen it B4.

          Paul,

          I said I knew about those things, not that I understood them.
          I have not used pointers before or inline asm but most of what you
          sent makes sense.

          The clock resetting is something I don't know how to do. Just that
          it CAN be done w/ CMOS RT clock. To others reading this,
          If you know how,...

          I re-formatted your reply, pasted below. Did I break anything?
          I took out the rem statements, my editor doesn't recognize their
          syntax. Are the semicolons after asm instructions for comments,
          or code. I took 'em out, thinking the former.

          I use rm to put notes and ?!? to myself in source. And I use combos
          of ? and ! to indicate confusion and importance. If you (or others)
          could comment on these spots, it will help a lot. Thank you again.

          Randal

          'rm dixtime1.bas 8/12/00 from Paul Dixon PB forum

          'Replace port 128 with the address of your own output port
          <RM snipped>
          <to save space and confusion for others>
          <8/15/00>

          END SUB

          '---------------------------------------------------------------------------

          ------------------




          [This message has been edited by Randal Milota (edited August 15, 2000).]

          Comment


          • #6
            Randy ..

            If what I suggested is in line with what you want, simply semd me
            an Email with your address. I'll duplicate the effort in a MIME
            attach file for you...



            ------------------
            Mike Luther
            [email protected]
            Mike Luther
            [email protected]

            Comment


            • #7
              Randal,
              <<my editor doesn't recognize their syntax>>

              What editor? The code as posted is a complete PB3.5 program. Just cut and paste it into PB3.5 IDE and it'll compile and run.

              <<Are the semicolons after asm instructions for comments>>

              They are the inline assembler equivalent of a REM, again PB3.5 recognises this. You can't replace these with ' you must use ; in inline assembler.

              <<I re-formatted your reply, pasted below. Did I break anything?>>

              Yes, you broke it. The code needed no reformatting.

              <<The clock resetting is something I don't know how to do.>>

              I'm sure you'll figure it out. The best way (but not the easiest) is to intercept the Int8 vector instead of the Int1C vector that way you can exit and cause the timer to increment at about the right interval. Keep count of the total number of timer ticks you have used. Exit the interrupt directly if there are <65536 in total and exit via the old Int8 vector when the count is >65535. That way the timer will still function almost as normal and will not need correcting as it will get called every 65536 ticks as it should be.

              A few notes on the program operation.
              The PIT timer chip generates interrupts which drive the software timer and other things. The interrupt goes through the Int8 vector which points to the BIOS code which keeps the clocks etc.running and this routine exits via the vector &h1C to allow other code to use it. This program does this by copying the vector &h1C to somewhere safe (the JMP at ExitVector and replacing it with a vector to the start of my own interrupt code. Then the program exits via the copy of the original Int1C vector so I don't have to tidy up after the interrupt and other code which may also be chained to this interrupt will still work.

              SUB install swaps the vector out to intecept the interrupt and initialises the PIT timer to the first required value.
              SUB uninstall replaces the old vector and restores the timer to give the normal 18Hz interrupts again.
              SUB introutine is never called (and must never be called by the program). It contains the interrupt routine code and will be run after each timer tick interrupt.


              <<done=codeptr32 '(DoneFlag) rm rem this ?!?>>

              You've broke it. The line should read:
              done=codeptr32(DoneFlag)

              The variable 'done', which was earlier defined as a pointer to a 32 bit value, is pointed at 'DoneFlag' which is a memory location (used as a variable) within the interrupt routine. The interrupt routine sets this when an interrupt occurs:
              !mov al,1
              !mov DoneFlag,al ;set a flag to let code know the interrupt has occurred

              This is monitored by the BASIC code so it can determine when the next value can be written to the timer.

              REM wait for timer interrupt to occur
              DO
              LOOP UNTIL @done

              This loops until the thing pointed at by the pointer 'done' is no longer 0.

              <<NextVal=codeptr32 '(NextValue) rm rem this ?!?>>

              You broke this in the same way. It should read:
              NextVal=codeptr32(NextValue)

              The pointer NextVal is pointed to a location in the interrupt routine which is used as a variable to hold the next value for the timer. When the next interrupt occurs the interrupt routine will load this value into the timer and set the 'done' flag. The BASIC code see's the 'done' flag set and knows it's safe to put the next timer value into 'NextVal' using the following line:
              @NextVal=value%

              This says to put the number 'value%' into the location pointed at by the pointer 'NextVal'.


              <<@NextVal=1234 'this is the initial value for the timer rm in hex??>>

              Not in HEX. It's decimal but in your case it will be whatever number you want to initialise the timer to when it is first used i.e. the time to wait before the first pulse.

              ExitVector:
              !jmp far ExitVector 'exit via copy of original int1c vector copied into
              'this location immediately after the JMP byte
              'rm something is missing !!???


              There is nothing missing.
              The JMP is assembled to jump to itself. When SUB install is called the actual address in the int1C vector is copied to the bytes after this jmp instruction. This causes the routine to exit via the old Int1C vector.

              Int1cV:
              !dd &h00000070 ';Int1c vector rm location in vector table??

              Yes, the Int1C vector is in memory location &h00000070. This value is used in SUB install to tell the code which vector is to be replaced (i.e.which interrupt to intercept). You can try changing it to the Int8 vector location at &h00000020, the code will still work and may give less jitter as it will execute before the timer's own routine. This would also allow you to fiddle the clock as mentioned earlier so it keeps running and doesn't need to be restored when you are finished.


              I suggest you compile the code as I posted it and change the bits I pointed out to match your hardware. Do not 'reformat' it until you have run it and seen it work. Connect your output port to an oscilloscope and when you see it work it'll help you understand what it's doing because you can then experiment with it. I currently have it running here producing very smooth results.

              Paul.


              ------------------

              Comment


              • #8
                sorry about the poor formatting of that last post, the yellow face was meant to be a : followed by a )

                Paul.


                ------------------

                Comment


                • #9
                  Randal,
                  I've tweaked the program a bit. It's still basically the same except now:
                  It intercepts Int8 instead of Int1c to give better responses and allow the clock to be controlled.
                  The Timer will now run normally even though the timer chip has the wrong and variable values in it.
                  This version outputs a repeated sinusoidally varying pulse train until a key is pressed to stop it.
                  The timer value is printed on the screen to show it really is still running correctly.
                  A couple of bits have been tidied up.

                  Paul.

                  REM routine wanted by Randal in PB forum to create hardware timed pulses

                  dim done as dword ptr, NextVal as dword ptr
                  done=codeptr32(DoneFlag)
                  NextVal=codeptr32(NextValue)

                  REM install the code and begin the first time interval
                  Install(1234)

                  DO

                  REM get the next timer value ready from wherever they are calculated...
                  REM I'll produce a sine wave sweep
                  value%=(value%+1)mod 10000
                  @NextVal=10000*sin(value%/100)+10100 :REM make sure it isn't too small

                  REM wait for timer interrupt to occur
                  DO
                  LOOP UNTIL @done

                  PRINT timer :REM print timer just to show it is still running correctly

                  REM clear the DoneFlag
                  @done=0

                  REM keep looping until a key is pressed
                  LOOP UNTIL instat

                  REM unistall the interrupt routine
                  UnInstall

                  END


                  SUB install(InitValue%)
                  REM call this sub to install the interrupt routine by intercepting the timer interrupt

                  low?=InitValue% MOD 256
                  high?=InitValue \ 256

                  !mov al,&h34 ;make sure PIT timer0 is in mode 2
                  !out &h43,al
                  !mov ax,low? ;and set to initial timer value
                  !out &h40,al
                  !mov al,high?
                  !out &h40,al

                  !les bx,Int8V ;get address of Int8 vector
                  !mov ax,es:[bx] ;copy offset to ExitVector
                  !mov ExitVector[01],ax
                  !mov ax,es:[bx+02] ;copy segment to ExitVector
                  !mov ExitVector[03],ax

                  !mov ax,0
                  !mov TimeSoFar,ax ;clear count of ticks so far
                  !mov DoneFlag,ax ;and clear flag to say interrupt hasn't occured yet

                  !cli ;disable interrupts while changing interrupt vector
                  !lea ax,Int8Entry ;get int routine entry to Int8 vector
                  !mov es:[bx],ax ;move offset of my routine to Int8 vector
                  !mov es:[bx+02],cs ;move segment of my routine to Int8 vector
                  !sti ;Enable interrupts

                  END SUB

                  SUB uninstall
                  REM Call this SUB to restore the interrupt vectors when finished.
                  REM The timer will also need to be reset, that isn't done here.

                  !cli ;disable interrupts while restoring interrupt vector
                  !les bx,Int8V ;get address of Int8 vector
                  !mov ax,ExitVector[01] ;Restore Int8 vector
                  !mov es:[bx],ax ;restore offset
                  !mov ax,ExitVector[03]
                  !mov es:[bx+02],ax ;restore segment
                  !sti ;Enable interrupts

                  !mov al,&h34 ;restore correct timer contents
                  !out &h43,al
                  !mov al,0
                  !out &h40,al
                  !out &h40,al

                  END SUB

                  SUB introutine
                  REM this is the actual interrupt routine that will be called on each timer
                  REM interrupt.

                  REM Int8 is the hardware timer interrupt for the 18.2Hz clock

                  Int8Entry:
                  !pushf ;save flags
                  !push ax ;save ax

                  !mov al,&h34 ;Write new value to timer
                  !out &h43,al
                  !mov ax,NextValue
                  !out &h40,al
                  !mov al,ah
                  !out &h40,al

                  !mov al,255 ;pulse the output, use your own port number
                  !out 128,al ;my ouput port is at 128
                  !mov al,0
                  !out 128,al

                  !mov al,1
                  !mov DoneFlag,al ;set a flag to let code know the interrupt has occurred

                  !mov ax,NextValue ;update count of ticks so far
                  !add TimeSoFar,ax

                  !jnb DontChain ;if count is <65536 then don't exit through old vector

                  Int8Exit:
                  !pop ax ;restore ax
                  !popf ;restore flags

                  ExitVector:
                  !jmp far ExitVector ;exit via copy of original int8 vector copied into
                  'this location immediately after the JMP byte

                  DontChain:
                  !mov al,&h60 ;clear pending int0 from timer chip myself
                  !out &h20,al

                  !pop ax ;restore ax
                  !popf ;restore flags
                  !IRET ;direct return from interrupt

                  Int8V:
                  !dd &h00000020 ;Int8 vector location

                  DoneFlag:
                  !dd 0 ;flag to set when interrupt occurs

                  NextValue:
                  !dd 0 ;next value to be loaded into timer

                  TimeSoFar:
                  !dd 0 ;cummulative count of 0.838us ticks so far. When this
                  'exceeds 65536 then exit via the old Int8 vector to
                  'cause a timer update, else exit using IRET.
                  END SUB

                  Comment


                  • #10
                    Paul,

                    I'm not worthy! I'm not worthy! (hope you've seen Waynes World)

                    Isn't it just like a newbie to take perfectly good code and mess it up .

                    I am glad however,as the extra comments really make it all come together for me.

                    Wow! Thank you

                    ------------------

                    Comment


                    • #11
                      Paul,

                      Would you comment on the "don't use this in windows, only DOS" ?



                      ------------------

                      Comment


                      • #12
                        Randy,

                        Part of the reason one has to be cautious about codeing differences
                        in DOS vs. Windows - some kinds, is that these routines are direct
                        hardware access routines.

                        They assume, in a way, that they are the only thing that has access
                        to the hardware and they can order the timing of all things like
                        this around to their heart's content!

                        In DOS, that works fine. When you begin asking a CPU to do many things
                        at once, in a good multi-tasking system, things change. It really
                        becomes necessary for the operating system to consider just how much
                        time it should give first one task and then another, as well as to
                        consider that things change! What is the right mix for CPU load between
                        one moment and the next can vary widely depending on what the various
                        tasks need to be doing. WIN 3.1, and for what all I know about WIN-95/98
                        which is nil, isn't really a good multi-tasker, when it comes to multiple
                        port simultaneous I/O .. like you postulate! DOS, in the strict sense,
                        isn't either.

                        However, when OS/2 was first brought out and smoothed over, it was really
                        a superb multi-tasker that, for the first time on a table-top box, let
                        you operate all four com ports at once and bunches of other stuff as well.
                        In reality, what was wrong with OS/2, aside from IBM's marketing goofs,
                        was that it was too darned good, too soon, for lots of things.

                        A sort of simplistic approach to multi-tasking I/O is to think of it as
                        a system in which the COMM ports are not really hardware ports, but objects
                        of them! OS/2, for example, creates a sort of pseudo-COMM port and then
                        proceeds to splice it, in a simplistic way, to the real hardware port. A
                        COMM port really doesn't exist, until OS/2 creates it, and ... this is the
                        critical part, it may cheerfully take it away momentarily and make it wait
                        until it gets darned good and ready to create it again, all in mid stream,
                        in a sort of a kind of a way. Now the STANDARD settings for such things
                        in OS/2 for DOS-VDM's mean that you don't get REAL access to the hardware;
                        you get the traffic-cop semaphore controlled look-alike of it instead.

                        That's fine, as long as the traffic cop is faster than the robbers in a full
                        chase run! It blows up magnificently when the cop is slower than the data!
                        It's like running the data cows out of the trailer down the chute into the
                        auction pen, and ... suddenly, snatching the chute out from between the
                        trailer and the pen in mid-cow run. If there isn't appropriate buffering
                        for holding up the data cows in mid air or whatever when the chute is gone
                        for a split second ... some of them fall on the ground and get bashed!

                        Actually, OS/2 has the ability to let you have direct access to the hardware,
                        if that is what you really want. It also has the ability to be told to be
                        a specific hard time-slice task switcher like the old DesqView was. However,
                        you'll find that it does a much better job of being a traffic cop than you can,
                        huge grin .. so nobody I know of uses these things any longer.

                        I think the reason that Phil may be telling you to watch this, is that while
                        WIN-9x is more like good old DOS than not, WIN-NT isn't. It's darned good at
                        most off this, though from things posted and shown at comparative timing and
                        data throughput for massive communications projects, not at all in the league
                        with OS/2... WIN-NT, per what I have been told, also will not let you have
                        access to the actual hardware level at all, as opposed to being able to code
                        for that if you need it in OS/2.

                        Thus, you may spend a significant amount of time coding a hardware port timing
                        application like you propose in PB 3.5 for DOS, but, as one man told me a long
                        time ago, it's a whole new ball game for timing routines in WIN-NT and OS/2,
                        Mike. Brand new world. You *CAN* code critical timing applications for WIN
                        operations (and OS/2 as well). But the coding is different and I know nothing
                        about it at all in WIN-whatever. You asked specific questions about the DOS
                        world and specific chips. Thus I posted what I did.

                        The other gent is very right to let you know a bigger world awaits you where
                        you are headed!

                        May all your cows bring top price!




                        ------------------
                        Mike Luther
                        [email protected]
                        Mike Luther
                        [email protected]

                        Comment


                        • #13
                          Mike,

                          If I had my way, this would all be happening on amiga's. Fully pre-emptive
                          multi-tasking on ONE 1.44 floppy in 1985!!! But alas, Commodore is(was) even
                          worse at realizing what they had than IBM w/ os/2. I almost went there some
                          years back, but my market is MS driven.

                          Thank you for the explanation re: the cows. Got it.

                          I believe it takes a VXD (virtual device driver) to do what I am asking in
                          WIN. Obviously,that is beyond my current skill. So I stay with dos and hope
                          to find the realtime WIN answer before my competitors/clients force the issue.
                          Bluewater systems has an OCX (I think) called winRT that is supposed to provide
                          realtime hardware control on win95 and NT. I spoke with the programmer awhile
                          back but soon found myself lost in the conversation about semaphores, and system
                          level privileges.

                          In my market (machine control) there is a strong movement towards Linux, with a RT
                          kernel. This may be another way for me to go in the future, but for now, it's still
                          dos.



                          ------------------

                          Comment


                          • #14
                            Paul,

                            Your most recent code is very close to what I need. You've given me my hardware rate timer. Thank You.
                            The port bits are hard-coded in the int routine. The example uses out 128,255 (set 8 bits),out 128,0
                            (clear bits). I need to change these bits on the fly. How do I pass the value (0 to 255) to
                            send out the port to this int routine. i.e. At each interrupt(output to port), I need to set and clear
                            various bit combinations including some bit-twiddling for the p port inversions on status and control pins.

                            The twiddling I know how to do, passing an (additional) value to the ASM int routine I need help with.
                            I realize this may be a very obvious/simple thing that I should!! see, but if you would indulge me one
                            more time, I think i'll be on my way.



                            ------------------

                            Comment


                            • #15
                              Randal,
                              <<Would you comment on the "don't use this in windows, only DOS" ?>>

                              Timing in a DOS program never works well under Windows. In plain DOS, your code controls the entire
                              machine. In Windows, your program is controlled by the operating system which will switch out your DOS program
                              from time to time to do other things. During this time your code is not running so the pulse times will not
                              be updated. Try it and see, it almost works on my machine but the timing is raggy.
                              I'm not a Windows programmer so I have no idea how best to do it in Windows, but it will be possible.
                              My preferred soloution would be external hardware to produce the pulses then the operating system wouldn't
                              matter.

                              <<I'm not worthy! I'm not worthy!>>

                              The bill is in the post.

                              <<I realize this may be a very obvious/simple thing that I should!!>>

                              It is obvious, the code as posted is already passing variables back and forth between ASM and BASIC,
                              just copy the method. The way I did it is not necessarily the best but it works like this:

                              1) define a pointer to point to the variable (which will be a word of memory in the ASM code)
                              e.g. DIM ThisPointer as dword ptr

                              2) in the ASM section, reserve a few byte to act as the actual variable
                              e.g. ThisVariable:
                              !dd 0

                              3) Point the pointer at the variable
                              e.g. ThisPointer = codeptr32(ThisVariable)

                              4) The variable is then accessed from BASIC using @ThisPointer
                              e.g. @ThisIsThePointer = 1234
                              e.g. PRINT @ThisPointer

                              5) The variable is accessed in ASM using a mov instruction
                              e.g. !mov ax,ThisVariable
                              e.g. !mov ThisVariable,al

                              Paul.


                              ------------------

                              Comment


                              • #16
                                Originally posted by Paul Dixon:
                                Yes, you broke it. The code needed no reformatting.
                                Be advised that Microsoft Internet Explorer does not treat breaks in lines properly when you copy to the clipboard. So, if you try to copy code from these forums using MSIE, all of the CR/LFs disappear, and the code is left as an amorphous blob. This is presumably why Randal needed to reformat.

                                We hope to find a solution for this (in our copious free time). Suggestions (other than "don't let anyone use Internet Explorer") would be welcome.


                                ------------------
                                Tom Hanlin
                                PowerBASIC Staff

                                Comment


                                • #17
                                  Tom,
                                  I was not aware of that...but I've just tried it and the line
                                  breaks are preserved in IE5, which I have here. I'm sure I never
                                  had trouble with it before. Perhaps it's a specific version of IE?

                                  Paul.



                                  ------------------

                                  Comment


                                  • #18
                                    Nope, I'm using MSIE 5.0 here. As far as I know, it's a problem
                                    with all versions of Internet Explorer. Did you test on code
                                    that was posted using the [ code ] tag? That's where the problem
                                    comes in.

                                    ------------------
                                    Tom Hanlin
                                    PowerBASIC Staff

                                    Comment


                                    • #19
                                      Tom,
                                      <<Did you test on code that was posted using the [ code ] tag? >>

                                      No, I don't even know what the [ code ] tag is. I tested it on the code that
                                      I posted in this thread. I just cut it from a source code file and pasted it
                                      into the "your reply" box.

                                      Paul.



                                      ------------------

                                      Comment


                                      • #20
                                        Tom,

                                        Thanks for the info, but I DID break his code

                                        I'm using msie4 and,like Paul, have no problems pasting his code (and others on this site)
                                        into notepad or textpad (my editor). However, I did get the amorphous blob
                                        when trying to paste Mike Luther's first response in this thread.

                                        Glad to know you guys at PB have something to do in your FREE time
                                        Part of the problem "may" be the "when do I put a CR in this line" dilemma
                                        I encounter whenever I post to the forum. In other words, maybe they are not being stripped
                                        out, they are just not put in by people used to word wrapped text??

                                        ------------------


                                        [This message has been edited by Randal Milota (edited August 14, 2000).]

                                        Comment

                                        Working...
                                        X