Shop OBEX P1 Docs P2 Docs Learn Events
SX/B, interrupts and serial output — Parallax Forums

SX/B, interrupts and serial output

DosManDanDosManDan Posts: 179
edited 2008-07-24 18:25 in General Discussion
I'm still trying to get my application to work with interrupts and serial output. I've programmed ISRs in assembly for PCs but I can't seem to get the hang of it on the SX.

Does anyone have an example, using SX/B that uses an interrupt while writing serial output? I'm using·9600 baud, single wire to a second SX. I'm using the interrupt as a timer, I need to write the time out to the second SX using a serial connection.

Thanks again,
Dan

·
«1

Comments

  • JonnyMacJonnyMac Posts: 9,216
    edited 2008-06-30 18:30
    I've attached a framework that I use with my Prop-SX programs; it does buffered transmit and receive, 2400 to 38.4K baud. The TX and RX portions (vars and code) are separate and you may remove one or the other if you don't need it.

    No warranty expressed or implied -- this code works fine for me, your mileage may vary.

    Post Edited (JonnyMac) : 6/30/2008 6:36:01 PM GMT
  • ZootZoot Posts: 2,227
    edited 2008-06-30 18:31
    Nuts N Volts columns 143-147 all have good examples of serial i/o while using interrupts. Generally speaking, you can not have an ISR (interrupt service routine) AND use high-level commands in SX/B that are timing dependent (such as SERIN, SEROUT, PULSIN, PULSOUT, etc). The N/V columns have examples of bit-banged serial comms that are in the ISR, so you are much more flexible.

    If you do a search in the SX forum for "Jon Williams" and buffered serial, you will also find examples of similar approaches for buffered serial comm, which might be useful as well.

    [noparse][[/noparse]edit] -- then again, Jon might just post that very code while I was typing my initial response smile.gif --

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • JonnyMacJonnyMac Posts: 9,216
    edited 2008-06-30 18:34
    Guess what I was doing while you were typing.... wink.gif
  • DosManDanDosManDan Posts: 179
    edited 2008-06-30 19:34
    Johnny Mac,

    Thanks so much!

    I had seen a similar application in SX/B help, but I wasn't able to get the timing down correctly when I added code. Basically, mine ended up sending garbage to the serial output, since my timing was off.

    Was 9600B too fast for what I'm trying to do? I noticed you have your example set at 2400B to 38.4K. also looks like I need to use a 20Mhz resonator too.

    Zoot, thanks for the tips. I actually subscribe to N&V now, and I can honestly say, it's so that I can read Jon's columns.

    You all are awesome when it comes to helping people out,

    Dan
  • ZootZoot Posts: 2,227
    edited 2008-06-30 19:58
    9600 not too fast, the issue is using SEROUT or SERIN in your main program and having an interrupt. Let's say that the SEROUT code is executing -- Bean's extremely cool generated code counts cycles at the current clock frequency and has the SEROUT code itself execute tight timing in a tight loop. That's great until you have interrupt code -- the interrupt gets serviced and by the time control returns to the partially executed SEROUT, the timing there will be screwed up.

    In fact some of the really good SX programmers have put in pretty fast Baud speeds in their apps. You will need a 20MHZ or 50MHZ resonators to run such code (so that there is enough room for instructions in the ISR *and* so the mainline program is blasting through instructions without getting bogged down by frequent interrupts.

    The general rule of thumb is -- if you need interrupts then you can't *also* use any high-level commands in the main program that depend on strict timing (e.g. SERIN, SEROUT, PULSIN, PULSOUT, RCTIME, ANALOGIN, etc). You would need to put that kind of code into the ISR itself, where strict time *is* maintained.

    This is probably a matter of style, but I think the high-level commands are good for quasi-converting existing applications from the Basic Stamp, or quickly pulling together code for apps that don't require an ISR. Anything with real ISR work, I usually leave them behind. There are some methods and timing finesses you can do (like setting a flag to ensure that a high-level SEROUT only kicks in when the ISR has just finished, and knowing you have enough time *before* the next interrupt to send the byte).

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • DosManDanDosManDan Posts: 179
    edited 2008-06-30 20:12
    Zoot,

    So, I need to write all of the high level routines using assembly and put them in the ISR code? Basically, I can't stick a SEROUT in the ISR code an expect it to work?

    I don't have an issue with assembly language, I taught it for 9 years at college. I just haven't had the time to read all of the specs for SX assembly. I bought Gunther's book, and have been reading through it, but I haven't had a chance to try and write in it yet.

    I had been using SX/B all of this time...yes, being lazy, until this current project hit. Now I'm paying for it....

    Dan
  • ZootZoot Posts: 2,227
    edited 2008-06-30 20:16
    No, not necessarily.

    Jonny's attached code IS like "serin/serout" but in assembly and in the ISR. A few regular SX/B functions allow the main program to queue and de-queue the sent/received bytes. You can use those routines in the ISR and the functions in your main program w/o change (except for pin assignments, perhaps).

    Why don't you attach your current working code? If your ISR is slow enough, it may be just easy to slip serial comm. in between interrupts as move material into the ISR.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • ZootZoot Posts: 2,227
    edited 2008-06-30 20:18
    P.S. -- remember that SX/B generates assembly code (view the list file after compiling). You'd be amazed at clear it is -- sometimes it's just as easy to write code in SX/B, then cut and paste just the pieces of generated assembly you need.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • DosManDanDosManDan Posts: 179
    edited 2008-06-30 20:27
    In the ISR, I'm simply implementing a count down clock. Counting the number of times the interrupt executes, subtracting until I hit zero.

    I need to do a live clock, showing time remaining, using an LCD serial panel. I have a second SX chip handling the LCD interface. There is a single wire serial line from the first chip (timer) to the second chip (LCD control).


    The code is stripped down to just the test pieces I'm trying to get to work. In this example, the SEROUT commands are not in the ISR. This was the point where I realized I had timing issues. Garbage started coming out of the serial line. I'm not sure if adjusting the ISR time would fix it.

    I could insert Jon's code in the ISR, load up the queues·and see if it works. I'm worried that when I add the timing code in the ISR, it will throw off the timing. I could possibly keep a small footprint, by adding a counter, then checking the counter out side of the ISR to see how much time is remaining.

    Hmmm......
    Dan

    Post Edited (DosManDan) : 6/30/2008 8:37:57 PM GMT
  • ZootZoot Posts: 2,227
    edited 2008-06-30 20:33
    Run Jonny's ISR code in the interrupt for serial comm. At the top of your interrupt put your countdown flags. Your mainline can still check those, esp. if that flag(s) are for >= 1ms (which is pretty slow). You may need a divider in the ISR (or in the mainline) given that the ISR for serial comm will be running very frequently.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • DosManDanDosManDan Posts: 179
    edited 2008-06-30 20:38
    I added to the previous post. Would I need to adjust the timing on Jon's routine to account for the counters I would be adding? Since he has everything broken down showing the timing, I assume I would need an accurate count or I would throw everything off.

    Dan
  • ZootZoot Posts: 2,227
    edited 2008-06-30 20:45
    No, the question is are there enough cycles left over in the ISR for your counts.

    Post your code smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • DosManDanDosManDan Posts: 179
    edited 2008-06-30 21:39
    I posted it with the message sent at 12:27PM. 4 messages up from this one. By the way, you busy or something? it took you almost 7 minutes to answer my last message· ;-)

    Dan
  • ZootZoot Posts: 2,227
    edited 2008-06-30 21:58
    Sorry, didn't catch the posted code... yeah, you can fit this in the ISR along with the ISR-ready serial comms.

    You'll just need something larger to hold the count until the MS comes around:

    MScntr VAR Word ' note that this is a Word value
    TicksPerMS CON 154 ' 154 6.51us interrupt "ticks" per interrupt
    
    
    ' interrupt code:
        
       ' insert ASM serial routines here
    
        
    Timer_And_Lights:
     
        If TimerOn = No Then Control_Lights
    
            INC MScntr
            IF MScntr >= TicksPerMS ' reached 1ms yet?
               MScntr = 0 ' reset counter
               INC MS ' increment MS counter
            ENDIF
        If MS <= 100 Then Control_Lights
            
           MS = 0
            If Seconds = 0 Then
            If Minutes = 0 Then
                TimerOn = No
            Else
                Dec Minutes
                Seconds = 60
            EndIf
        Else
            Dec Seconds
        EndIf
    
    Control_Lights:
        Lights = TimerOn
    
    
    



    P.S. -- there are more efficient ways to organize this kind of app, but this should be clear. Make sure the revision to your light ISR works at the faster interrupt rate required by the serial comms. THEN add in your serial code -- at least then you'll know if it "breaks" it was the addition of the serial code. Running this at 50mhz wouldn't hurt -- will help make sure the SX is blasting through instructions quickly enough that you won't get jitter in your controls or serial comms.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php


    Post Edited (Zoot) : 6/30/2008 10:03:29 PM GMT
  • DosManDanDosManDan Posts: 179
    edited 2008-06-30 22:41
    Thanks Zoot!

    I'll give it a shot tonight and let you know how it goes. I can't thank you enough for your help. I have a 50MHZ Murata resonator, I'll swap it in and give it a shot.

    Dan
  • JonnyMacJonnyMac Posts: 9,216
    edited 2008-06-30 22:43
    Since I frequently suggest that we can learn things by solving others' problems... I've solved yours (I think). I took the buffered serial code posted earlier and added a countdown timer to it. The timer can be loaded with minutes, seconds, and (optionally) tenths. A call to START_TIMER is used to load the values and start the timer in one easy step.

    The program uses a 16-bit counter (tix_LSB + tix_MSB) to count 15360 ISR cycles; this is 1/10th second. When this is reached the tix counter is reset and the timer updated, with cascading updates (if tenths rolls under, secs are decremented, and so forth). At the end of the timer section there is a test to see if all timer registers (tenths, secs, mins) are zero; when this happens the timer flag bit is cleared -- this makes testing for timer expiration easy (I left my test code in place so that you can see how I do it).

    Have fun, Dan.

    Jon

    Post Edited (JonnyMac) : 6/30/2008 11:02:44 PM GMT
  • DosManDanDosManDan Posts: 179
    edited 2008-06-30 23:03
    Jon,

    This was more than I could have hoped for. Thank you so much! Now I have to go over to EFX and buy a bunch of stuff to pay you back for the help wink.gif

    I was sitting here trying to figure out why this was giving me so much trouble. I think most of my issues were in not understanding how the actual timing values were calculated. I read, in your articles and in Gunther's book how to calculate them, but, in practice I wan't able to get them correct. The Assembly code you have is very clear, and I can see how and why you are doing it. I need to study what you did and then play with it to see if I can modify it and still get it to work. If I can do that, it will be a step in the right direction for me learning how to use interrupts on the SX.

    Also, it looks like I would have been better off just doing it in Assembly rather than trying to easy way out with SX/B. Lesson learned. I need to spend some time learning the instruction sets for the chip.

    I really do mean it, thank you very much. I hope to meet you in person sometime, I'll buy you lunch. I'm just down in Elk Grove, so when I'm up your way, I'll send you an e-mail.

    Dan
  • JonnyMacJonnyMac Posts: 9,216
    edited 2008-06-30 23:10
    Dan,

    I absolutely agree with your assertion that you should buy lots of EFX-TEK products -- everyone should! wink.gif

    I respectively disagree with your comment about SX/B. SX/B takes a lot of grunt work out of your programs versus using straight assembly, and as you've seen by my (and others') examples, adding assembly to an SX/B program is very easy -- to me, the best of both worlds. Take the ISR for example: by using the rate parameter of INTERRUPT you don't have to do any calculating to to get the RETURNINT or OPTION register values correct (this is especially handy when you start changing FREQ settings). SX/B is a great tool; don't give up on it too quickly.

    You'll have to come down to Hollywood to buy me lunch, I live in the LaLaLand. If you make it down this way, give me a call (# is on EFX-TEK site).
  • DosManDanDosManDan Posts: 179
    edited 2008-06-30 23:24
    Oh, I thought you were up in Rocklin! Well, guess I have to come down there then! I get down that way three or four times a year on business.

    I was trying to figure out why you didn't calc the RETURNINT values (I didn't realize it was going to do it for you). I didn't mean to imply I was going to give up on SX/B, but that I had avoided using the Assembly option. I should have just learned it and used it where appropriate.

    I'll post the completed program so everyone can benefit from the solution. Also, this is the first time I've used two SX chips in a solution. I'm very impressed by what these chips can do. Using the SX chip as a virtual peripheral allowed me to replace an $8.00 LCD driver chip in the design. Once I have the whole design figured out, I plan on trying the SX-48 to see if I can reduce the chips to one.

    Thanks again,
    Dan
  • JonnyMacJonnyMac Posts: 9,216
    edited 2008-07-01 00:07
    If you happened to use the serial LCD code from the help file, well... I wrote that too! (I'm updating it in my book, Practical SX/B). Gonna be a real nice lunch.... [noparse]:)[/noparse]
  • DosManDanDosManDan Posts: 179
    edited 2008-07-01 00:38
    Why yes, I did! Going to have to bring the American Express for this one....hehe. Hurry up and finish that book!

    Dan
  • DosManDanDosManDan Posts: 179
    edited 2008-07-03 08:54
    Jon,

    Where did the 153_600 come from in the interrupt? I ordered a 20MHz resonator, but it won't be here until Sat, due to the holiday. I do have a 50MHz resonator, but I'm not sure how to change the timing of the interrupt to work with it.

    The instruction rate for 50MHz is 1/50000000 or 20us, for a 20MHz it would be 1/20000000 it should be 50us (if I'm understanding this correctly).

    9600 baud is moving a bit every 104us. If we are sampling 4 times faster than the transfer rate, I'm assuming the target number we are trying to hit is 104/4 or 26us.

    At 50 MHz, the RTCC should roll over: 0.020 * 256 = 5.12us
    At 20 MHz it should roll at: 0.050 * 256 = 12.8us

    This is the part were I get stuck. What do I change to get the right timing?

    Dan
  • pjvpjv Posts: 1,903
    edited 2008-07-03 13:07
    Dan;

    For serial UARTing you are better to sample an odd number of times during one bit period. Five is great (21 uSec at 9600), three (35 uSec) is workable.

    Cheers,

    Peter (pjv)
  • BeanBean Posts: 8,129
    edited 2008-07-03 14:22
    Dan,
    You want to sample an odd number of times so that you can sample in the middle of the bit period. That allows for the most jitter and/or timing error and still get the bits correctly.

    Bean.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Uhhhm, that was on fire when I got here...

    www.iElectronicDesigns.com

    ·
  • JonnyMacJonnyMac Posts: 9,216
    edited 2008-07-03 14:38
    Dan,

    The great thing about SX/B is that you can change the FREQ directive and the INTERRUPT section will correct itself (so long as the rate parameter parameter is specified -- in this program it is). All you have to do is change the FREQ directive and you'll be set. Until you're more comfortable with programming the SX I would suggest leaving [noparse][[/noparse]working] code as-is.

    I was taught to use 4x sampling per bit, so that's where 153_600 comes from (1/4th the bit time at 38.4k baud).
  • DosManDanDosManDan Posts: 179
    edited 2008-07-03 18:06
    Thanks everyone, I'm starting to catch on..slowly!

    So the 38.4K is really 9600Baud * 4

    From that, I can now see how you get to 6.51us.

    1/38.40= 0.02604 then divide by 4 to get· 0.00651 which converts to 6.51us

    So how do you get the 153_600?
    Dan

    Post Edited (DosManDan) : 7/3/2008 6:13:04 PM GMT
  • JonnyMacJonnyMac Posts: 9,216
    edited 2008-07-03 18:24
    1 / 0.00000651 (6.51 uS) = 153_600

    If you've got a [noparse][[/noparse]1/x] key on your calculator this stuff is easy -- pop in your max baud rate, press 1/x, divide that by four, then press 1/x again.

    This will give you the ISR rate for your maximum baud, assuming you're using 4x sampling. Per PJV and Bean, you may want to use 5. The only time I've not used 4 was for DMX input when running 50 MHz, and this was just to minimize timing in the ISR -- works fine, and I have projects running at a big amusement park in SoCal that are happily using that DMX code on Prop-SX controllers.

    Post Edited (JonnyMac) : 7/3/2008 6:35:26 PM GMT
  • DosManDanDosManDan Posts: 179
    edited 2008-07-03 18:53
    I can't believe it was that simple. I'm not kidding, I was up until 2AM last night trying to figure it out.

    As always, I really appreciate your help. I learned how to calculate the interrupt time, and I hope others who have the same question now understand where the numbers come from.

    Thanks!
    Dan
  • Shawn LoweShawn Lowe Posts: 635
    edited 2008-07-03 19:14
    I know I've learned something! Thanks everyone for the education!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Shawn Lowe


    When all else fails.....procrastinate!
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2008-07-03 19:38
    IMHO introducing the bittime is only clouding the issue.
    Jon wanted 4x oversampling 38400 baud, so the isr rate becomes 4*38400 = 153600

    Using that rate, 9600 baud becomes 16x oversampled.
    For 20MHz resonator the number of ISR cycles is 20_000_000/153600 = 130
    There is only so much you can do in 130 cycles.

    If 9600 baud is all you are interested in I suggest to use 12x oversampling.
    rate = 12*9600 = 115200
    ISR cycles = 20_000_000/115200 = 174
    This gives you more cycles so you can do more inside the isr.

    regards peter
Sign In or Register to comment.