Jump to content

Photo

Interrupt Service Routine and the RS232

RS232 interrupts ISR TIMXT

68 replies to this topic

#51 BeeryMiller OFFLINE  

BeeryMiller

    Dragonstomper

  • 841 posts
  • Location:Campbellsburg, KY

Posted Tue Feb 12, 2019 7:21 AM

Something else to consider  With the WiModem232 and some other WiFi modems, they have configurable buffers for the Telnet connections that can be as little as 64 bytes to over 1K.

 

With MyTerm, I have at present a 9K buffer to capture characters.  There is no data overrun at 38.4K when communicating with HeatWave or Fusion BBS.  However, I do have one spot within 9640News when someone does a new file scan with the over 200 areas, there is an excess of a 16K data stream transferred faster than the present screen coding can keep up with.  So, this results in a buffer overrun.   The characters are initially captured, but then overwritten.  The user actually is never aware of it, however if I were trying to capture a 16K text document into the log buffer, then I would l miss some things.

 

My point here is that depending upon your timing and where you are in your code before looking at serial port, you could have a significant amount of data buffered ready to send from a WiFi modem to the RS232 with a significant sustained burst at whatever your WiFi modem to RS232 baud rate is configured.  If you have the room for significant buffers, you might consider using it.

 

Beery


Edited by BeeryMiller, Tue Feb 12, 2019 7:31 AM.


#52 apersson850 OFFLINE  

apersson850

    Dragonstomper

  • 591 posts

Posted Tue Feb 12, 2019 9:32 AM

This of course improves if use a slower baud rate because you have more time between characters.

 

Morning coffee talking

Yes, at a slower baud rate you always have more time between each character being completely received. But you don't necessarily have more time between the characters, i.e. from the last bit in character n to the first bit in character n+1. You can receive 20 characters per second at 38400 bits/s. You just have comparatively long time between the last bit of character n and the first in character n+1.

 

Of course, normally you want to be as efficient as possible, so you try to throw out the characters as soon as possible. Thus the delay is usually held short.

I just wanted to point out that there could be another delay here. If you design both ends of the communicating system, you do have the ability to use a high baud rate (provided the cable is short enough and the UART can handle it), and then make sure the transmitting end doesn't send the new character immediately after the previous one. This can render a higher speed than going down in baudrate and send the characters packed as much as possible.

 

I hope the coffee was good!



#53 InsaneMultitasker OFFLINE  

InsaneMultitasker

    River Patroller

  • Topic Starter
  • 2,389 posts

Posted Tue Feb 12, 2019 1:39 PM

 

282uS  / 286uS  -> 98% of CPU used by RS232 interrupt with 47 instructions in fast RAM.

 

This of course improves if use a slower baud rate because you have more time between characters.

 

Morning coffee talking

This seems pretty close to what I've observed; adding a few extra instructions to deal with the nanopeb resulted in dropped characters in some of my earlier routines. I had to really tighten up the interrupt handler by setting some immediate values via self-modifying code among other things. I never tried computing the instruction load inclusive of the ISR - might be a fun exercise for a rainy day :)



#54 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 963 posts
  • Location:The Great White North

Posted Tue Feb 12, 2019 1:54 PM

This seems pretty close to what I've observed; adding a few extra instructions to deal with the nanopeb resulted in dropped characters in some of my earlier routines. I had to really tighten up the interrupt handler by setting some immediate values via self-modifying code among other things. I never tried computing the instruction load inclusive of the ISR - might be a fun exercise for a rainy day :)

 

Cool. This is why I am curious about what would happen if you changed your GET2 routine from 11 instructions to  7 below.  That should reduce overhead a bit.

And I think you could remove the sub-routine call (?)  and lose 2 more instructions.

 

I have not got the interrupt working yet under Forth or I would measure it.  Not sure what's wrong yet :?

Q      BSS  100               buffer address. size is power of 2
  
GET2   MOV  @RLAST,R4         get current queue index
       STCR Q@(R4),8          get character from RS232 (R12 set @manip3)
       SBO  >12
       INC  R4
       ANDI R4,00FF           mask is 1 less than buffer size
       MOV  R4,@RLAST         save next buffer INDEX
       CLR  R12
       RTWP


#55 InsaneMultitasker OFFLINE  

InsaneMultitasker

    River Patroller

  • Topic Starter
  • 2,389 posts

Posted Tue Feb 12, 2019 2:16 PM

 

 

Cool. This is why I am curious about what would happen if you changed your GET2 routine from 11 instructions to  7 below.  That should reduce overhead a bit.

And I think you could remove the sub-routine call (?)  and lose 2 more instructions.

 

I have not got the interrupt working yet under Forth or I would measure it.  Not sure what's wrong yet :?

You are setting up the interrupt handler first, right?  That is an important step and one I can't predict will/won't work in the Forth environment. Be sure Forth isn't resetting any of the initial setup. Maybe post all the current flow after you've tried some things.

 

When I was testing my code initially, I changed the screen color when the interrupt fired.  I was able to visually tell whether I was in the interrupt handler, the setup, or the buffering routine.   Later I started using counters in the routines so that I could figure out if the routine was called as expected.

 

If you allow the buffer to overwrite in a terminal situation, you can lose more than the character that caused the overflow when the pointer wraps.  So I opt to just let the tail end suffer.   I haven't touched the code in a while for various reasons but hope to get back into it by summertime.

 

Looks like you are having fun ;)



#56 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 963 posts
  • Location:The Great White North

Posted Tue Feb 12, 2019 2:58 PM

You are setting up the interrupt handler first, right?  That is an important step and one I can't predict will/won't work in the Forth environment. Be sure Forth isn't resetting any of the initial setup. Maybe post all the current flow after you've tried some things.
 
When I was testing my code initially, I changed the screen color when the interrupt fired.  I was able to visually tell whether I was in the interrupt handler, the setup, or the buffering routine.   Later I started using counters in the routines so that I could figure out if the routine was called as expected.
 
If you allow the buffer to overwrite in a terminal situation, you can lose more than the character that caused the overflow when the pointer wraps.  So I opt to just let the tail end suffer.   I haven't touched the code in a while for various reasons but hope to get back into it by summertime.
 
Looks like you are having fun ;)

 
Thanks.
 
Forth doesn't do anything while sitting in the console loop. It's pretty harmless while waiting.
 
Yes I have broken out your routines so I can execute them from the console.  ;)
So RCVON,  RCVOFF and INSTALL (what you called CONFIG) are commands in Forth.
 
I already had a 9902 setup routine so I just modified it to reset the circular pointers and setup a variable with the queue buffer address.
 
I like the idea of the screen color changes!  Simple to code, little overhead and you can't miss it. 
 
For the curious here was I took from your code, ( for the actual ISR handler) re-written in structured Forth assembler.
(the 'IF', ELSE and ENDIF just translate to jump instructions)

 

Edit:  Code below now works. Had to grab the char and clear 9902 rcv buffer ASAP, just like Insane multi-tasker version.

DECIMAL
CREATE TTY1-ISR ( * this is a label, not a runnable Forth word * )
       ISRWKSP LWPI,
       R12 CLR,          \ select 9901 chip CRU address
       2 SBZ,            \ Disable VDP int prioritization
       R11 SETO,         \ 3.5.16 hinder screen timeout (should never happen)
       PORT @@ R12 MOV,  \ set CRU PORT
       16 TB,            \ interrupt received?
       EQ IF,            \ Yes; enqueue char
            R3 8 STCR,   \ read the char. into R3
            18 SBO,            \ clr rcv buffer, enable interrupts
            QTAIL @@ R4 MOV,   \ index->R4
            R3 Q R4 () MOVB,   \ "MOV R3,Q@(R4)"
            R4 INC,            \ bump the index
            R4 >00FF ANDI,     \ wrap the index
            R4 QTAIL @@ MOV,   \ save the index
            R12 CLR,
            RTWP,
       ENDIF,
       R12 CLR,        \ select 9901 chip CRU address
       3 TB,           \ check timer interrupt
       EQ IF,
            3 SBO,     \ reset timer latch int (essentially ignore it)
       ENDIF,
       RTWP,           \ Nothing to do here. Return.


Edited by TheBF, Thu Feb 14, 2019 10:51 PM.


#57 tschak909 ONLINE  

tschak909

    River Patroller

  • 3,160 posts
  • Location:USA

Posted Thu Feb 14, 2019 6:32 PM

I _really_ need some help getting some RS232 routines that I can use from C. *beg*

 

-Thom



#58 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 963 posts
  • Location:The Great White North

Posted Thu Feb 14, 2019 8:26 PM

I _really_ need some help getting some RS232 routines that I can use from C. *beg*

 

-Thom

 

I feel your pain.  I am trying to get receive interrupts working under Forth.

 

I am taking the approach that interrupts are only really needed for receive.

Does that work for your needs?

 

I don't have GCC installed, but from what I see on GITHUB, Tursi wrote the same kind of thing that I did for NON-interrupt driven routines.



#59 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 963 posts
  • Location:The Great White North

Posted Thu Feb 14, 2019 11:18 PM

I finally got this working. I was trying to be a little too creative. :-)

 

But!  I did manage to reduce the size of the "GET2" part of the routine that reads a character and stuffs it into the queue.

 

Changes:

  1. I used indexed addressing and binary wrapping for the byte-queue pointers.
  2. I removed the over-run jump to RSINX by just letting the tail over-run the head. It's up to me to get the data out fast enough or use a bigger queue.
  3. I don't count the bytes in the ISR. I can get that in the program by subtracting the queue pointers if I need it .  ABS(TAIL-HEAD) 

The  queue memory ("Q") itself is an address that is  set when you INIT eveyrthing.

 

These changes should work in Insanemultitasker's code as well.

 

Original "GET2" routine:  (12 Instructions)

GET2   STCR R3,8              get character from RS232 (R12 set @manip3)
       SBO  >12
       C    @RBYTES,@BMAX     buffer at max?
       JEQ  RSINX             yes, trash the rcvd character. :(
       MOV  @RLAST,R4         get current ^loc pointer
       CI   R4,BEND           at end?
       JL   ADDROK            no
       LI   R4,BSTART         yes, wrap
ADDROK MOVB R3,*R4+           stuff char into buffer
       MOV  R4,@RLAST         save next buffer loc
       INC  @RBYTES           inc total bytes in buffer
       CLR  R12
*      NOP               debug
       RTWP
RSINX  SBO  >12          Just to be safe
       CLR  R12          Reset for re-entry (probably not needed any more)
       RTWP

"New and Improved" GET2  (8 instructions and no jumps so it should be a bit faster)

 

Forth assembler format with a translation comment for indexed addressing

        R3 8 STCR,         \ read the char. into R3
        18 SBO,            \ clr rcv buffer, enable interrupts
        QTAIL @@ R4 MOV,   \ index->R4
        R3 Q R4 () MOVB,   \ "MOVB R3,Q@(R4)"
        R4 INC,            \ bump the index
        R4 >00FF ANDI,     \ wrap the index
        R4 QTAIL @@ MOV,   \ save the index
        R12 CLR,
        RTWP,


#60 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 963 posts
  • Location:The Great White North

Posted Thu Feb 14, 2019 11:48 PM

Here is the complete ISR Handler and I made it a little smaller by setting R4 to the tail pointer before testing the CRU bit.

That way I can read the byte from CRU directly to the Q@(R4). Saves 1 move to R3.

DECIMAL
CREATE TTY1-ISR ( * this is a label, not a runnable Forth word * )
       ISRWKSP LWPI,
       R12 CLR,          \ select 9901 chip CRU address
       2 SBZ,            \ Disable VDP int prioritization
       R11 SETO,         \ 3.5.16 hinder screen timeout (should never happen)
       PORT @@ R12 MOV,  \ set CRU PORT
       QTAIL @@ R4 MOV,   \ index->R4
       16 TB,            \ interrupt received?
       EQ IF,            \ Yes; enqueue char
            Q R4 () 8 STCR,
            18 SBO,            \ clr rcv buffer, enable interrupts
            R4 INC,            \ bump the index
            R4 >00FF ANDI,     \ wrap the index
            R4 QTAIL @@ MOV,   \ save the index
            R12 CLR,
            RTWP,
       ENDIF,
       R12 CLR,        \ select 9901 chip CRU address
       3 TB,           \ check timer interrupt
       EQ IF,
            3 SBO,     \ reset timer latch int (essentially ignore it)
       ENDIF,
       RTWP,           \ Nothing to do here. Return.



#61 InsaneMultitasker OFFLINE  

InsaneMultitasker

    River Patroller

  • Topic Starter
  • 2,389 posts

Posted Fri Feb 15, 2019 12:22 AM

Nice work.  May I ask you to "translate" the enhanced routine for the Forth-deficient?  ;)   

 

Remember that if you want this code to work with the nano devices, you'll either need to turn the nano serial port on/off in the interrupt handler or you can leave the card enabled so long as you track every possible instance where a DSRLNK could be called or some other device in the system could be turned on in the same address space @ 0x4000.

 

Also, if you want to use the TI disk controller (or nano/cf7/CorComp variants) you must remember to restore GPLWS R15 to the VDPWA address.  In TI MXT I handle this by saving R15 within the DSRLNK routine, setting R15 to the expected VDPWA address, then restoring the mungled R15 before exiting the DSRLNK routine. The save step happens at the start of the CRU scan. While an interrupt is extremely unlikely to happen at this point in the DSRLNK, I play it safe with a LIMI 0.  See code.

 

Spoiler


#62 Tursi OFFLINE  

Tursi

    Quadrunner

  • 5,572 posts
  • HarmlessLion
  • Location:BUR

Posted Fri Feb 15, 2019 3:36 AM

I feel your pain.  I am trying to get receive interrupts working under Forth.
 
I am taking the approach that interrupts are only really needed for receive.
Does that work for your needs?
 
I don't have GCC installed, but from what I see on GITHUB, Tursi wrote the same kind of thing that I did for NON-interrupt driven routines.


Yeah, I wrote that for Thom, but you know, he wants things that actually WORK for Plato... ;)

I was always under the impression that the overhead for RS232 interrupts wasn't worth the effort - how are you finding it works in practice? What are the caveats?

#63 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 963 posts
  • Location:The Great White North

Posted Fri Feb 15, 2019 6:56 AM

No surprises IMHO.  I don't require sending interrupts and I think they are overrated, since that is under the sender's control.

 

My application is sending to the Forth compiler over serial link.

Without interrupts at 9600 BPS the protocol is:  delay each char 1 mS and delay each line 275 mS (waiting to be sure the line compiled.)

Effectively <1K BPS :-(

 

With interrupts I can send a line at full speed and then wait for compile still remains at 275mS.

So this is an big improvement in this narrow application. 

 

I have only been testing the ISR to date, but will re-build the Forth Kernel with ISR driven receive.  It will then be a pretty functional way to code. I suspect compile times to be about the same as floppy disk with serial rcv interrupts.  It's painfully slow without them.

 

I have not fully explored the caveats.  I don't fully grok the ramifications of all the VDP interrupt shenanigans in the code, but that would be the thing I would be wary of.

 

I suppose the one thing I notice is that people want to push the old 9900 to 38.4K BPS with huge buffers. 

This will have the effect of consuming the entire CPU which kind of negates the reason to have interrupts. (but its still amazing to see it work  :) )



#64 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 963 posts
  • Location:The Great White North

Posted Fri Feb 15, 2019 7:15 AM

I just ran the code below, which removes the TB 3 and the JNE at the end and it seems to work fine.

 

Is there some reason we should only set the timer latch if it is = 0?
 

QSIZE EQU >100        * make this size a power of 2 (100,200,400 etc.)
QMASK EQU QSIZE-1

Q     BSS  QSIZE
QHEAD DATA 0
QTAIL DATA 0
PORT  DATA >1340      * this can be changed by a Forth program

TTY1-ISR                  
      LWPI  >83C0 
      CLR   R12           \ select 9901 chip CRU address
      SBZ   2             \ Disable VDP int prioritization
      SETO  R11           \ 3.5.16 hinder screen timeout (should never happen)
      MOV   @PORT,R12     \ set CRU PORT
      MOV   @QTAIL,R4     \ index->R4
      TB    16            \ interrupt received?
      JNE   ENDIF         \ Yes; enqueue char
      STCR  Q@(R4),8 
      SBO   18            \ clr rcv buffer, enable interrupts
      INC   R4            \ bump the index
      ANDI  R4,QMASK      \ wrap the index
      MOV   R4,@QTAIL     \ save the index
      CLR   R12
      RTWP
ENDIF CLR   R12           \ select 9901 chip CRU address
      SBO   3             \ reset timer latch int (essentially ignore it)
      RTWP                \ Nothing to do here. Return.

Edited by TheBF, Fri Feb 15, 2019 12:19 PM.


#65 InsaneMultitasker OFFLINE  

InsaneMultitasker

    River Patroller

  • Topic Starter
  • 2,389 posts

Posted Fri Feb 15, 2019 4:26 PM

 

I just ran the code below, which removes the TB 3 and the JNE at the end and it seems to work fine.

 

Is there some reason we should only set the timer latch if it is = 0?

If you are not using/enabling the 9901 timer you can ignore it. Just like you can technically ignore any other interrupts if you know you won't be generating any. I think Jeff may have been done this for completeness and to show how to do it.  At least one of his programs used the timer for other purposes.  I intended to use the timer for file transfer and keyboard input testing, coupled with an in-interrupt routine to capture characters.

 

Hmm... if you don't use any other interrupts you could assume with high confidence that the only time the interrupt routine is called is when the RS232 generates an interrupt.  No more interrupt testing.  I may have to try that for giggles.  Of course, if you encounter an interrupt the handler can't manage, your program will spin in an endless interrupt loop. 

 

TIMXT's keyboard routine currently tests for a serial interrupt between reading the columns to avoid losing characters during all of that keyboard CRU work.  This affords some level of responsiveness while the interrupt routine and interpreter are duking it out, yet sacrificing as few clock cycles as possible waiting for input. There are probably some better methods I can employ when I get back into it.

 

19.2k is probably a better, more comfortable speed but for terminal emulation, I've always wanted to see how far things can be pushed.  ;)



#66 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 963 posts
  • Location:The Great White North

Posted Sun Feb 17, 2019 8:54 AM

Although I am having trouble getting this code working inside the Forth kernel, I have continued testing and I can confirm that this minimized code works.

 

I use the 9901 timer in Forth, but it runs continuously and has the interrupt disabled.  I use it for testing only to measure the actual speed of small routines.

It's great for that because it can resolve to 21.3 uS.  Coupled with the Forth console you can compile a one line program that let's me truly compare which one of my latest brainstorms is faster. ;-)

QSIZE EQU >100        * make this size a power of 2 (100,200,400 etc.)
QMASK EQU QSIZE-1

Q     BSS  QSIZE
QHEAD DATA 0
QTAIL DATA 0
PORT  DATA >1340      * this can be changed by a Forth program

TTY1-ISR                  
      LWPI  >83C0 
      CLR   R12           \ select 9901 chip CRU address
      SBZ   2             \ Disable VDP int prioritization
*     SETO  R11           ** This should be done outside the interrupt **
      MOV   @PORT,R12     \ set CRU PORT
      MOV   @QTAIL,R4     \ index->R4
      TB    16            \ interrupt received?
      JNE   ENDIF         \ Yes; enqueue char
      STCR  Q@(R4),8 
      SBO   18            \ clr rcv buffer, enable interrupts
      INC   R4            \ bump the index
      ANDI  R4,QMASK      \ wrap the index
      MOV   R4,@QTAIL     \ save the index
      CLR   R12
ENDIF RTWP                \ Nothing to do here. Return.


#67 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 963 posts
  • Location:The Great White North

Posted Fri Feb 22, 2019 11:06 AM

I posted an update and short demo movie in the CAMEL Forth section

 

http://atariage.com/...12#entry4225063



#68 InsaneMultitasker OFFLINE  

InsaneMultitasker

    River Patroller

  • Topic Starter
  • 2,389 posts

Posted Fri Feb 22, 2019 12:27 PM

I posted an update and short demo movie in the CAMEL Forth section

 

http://atariage.com/...12#entry4225063

Well done. Certainly, 9600 seems plenty fast for the text!  

 

Your movie demo reminded me of an important context point to consider when we discussing terminal speeds.  

 

One of my primary reasons for extracting maximum speed within the terminal emulator environment is to balance the ANSI overhead needed for position and format coding.   An ANSI terminal may interpret 5-10 bytes of data to display just on character.  This loosely translates to an effective speed range of "4000-8000 baud" for the more color-intensive displays.



#69 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 963 posts
  • Location:The Great White North

Posted Fri Feb 22, 2019 2:45 PM

Well done. Certainly, 9600 seems plenty fast for the text!  

 

Your movie demo reminded me of an important context point to consider when we discussing terminal speeds.  

 

One of my primary reasons for extracting maximum speed within the terminal emulator environment is to balance the ANSI overhead needed for position and format coding.   An ANSI terminal may interpret 5-10 bytes of data to display just on character.  This loosely translates to an effective speed range of "4000-8000 baud" for the more color-intensive displays.

 

Yes there is quite a bit of overhead for those terminals.  My actual plan is to have the VDP display for graphics and games and such and replace KSCAN with the TTY connection.

It's all for my own amusement.  I do want to play around with some terminal based color and such. In some ways its more versatile than the VDP display having an attribute for every character on the screen.

 

Here is my "meta language" for Forth to do basic VT100 control. It is postfix of course but it shouldn't take too much more to write the more advanced stuff using this kind of structure.

CR .( VT100 terminal control)

DECIMAL
\ type a number in base 10, with no space
: <ARG>   ( n -- )
           BASE @ >R  
           0 <#  DECIMAL #S  #> TYPE 
           R> BASE ! ;

\ markup language for terminal control codes
: <ESC>[  ( -- )   27 EMIT  91 EMIT  ;
: <UP>    ( n -- ) <ESC>[ <ARG> ." A" ;
: <DOWN>  ( n -- ) <ESC>[ <ARG> ." B" ;
: <RIGHT> ( n -- ) <ESC>[ <ARG> ." C" ;
: <BACK>  ( n -- ) <ESC>[ <ARG> ." D" ;
: <HOME>  ( -- )   <ESC>[ ." 0;0H" ;
: <CLS>   ( n -- ) <ESC>[ ." 2J" ;
: <CLRLN> ( -- )   <ESC>[ ." K" ;

\ redefine Forth words using markup words
: AT-XY   ( col row --) 
          2DUP VROW 2!
          SWAP <ESC>[ <ARG> ." ;" <ARG> ." f" ;

: TTYPAGE ( -- ) <CLS>  <HOME> ;

AND... Thanks again for your code.

It was so much help. I am not sure I would every have figured out all the pieces that  needed to be circumvented to figure out RS232 interrupts on this convoluted old machine.  







Also tagged with one or more of these keywords: RS232, interrupts, ISR, TIMXT

0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users