Shop OBEX P1 Docs P2 Docs Learn Events
Soliciting suggestions for SX design. — Parallax Forums

Soliciting suggestions for SX design.

Jim BrainJim Brain Posts: 17
edited 2004-10-27 00:45 in General Discussion
Updated to fix timing (390nS, not 390uS)

I'm new to SX development (been doing AVR stuff lately), so I thought I'd see if more experienced SX developers have wisdom to share.

My application is a 300-230400 dual UART.· I've dloaded the Dual UART VP, and it looks like with some additions (DTR/DSR/CTS/RTS/300bps/1200bps support), I can make that code work.·

My issue is the need to watch for an asynchronous data request that must be serviced in 390nS.·(@75MHz, 13nS per cycle, I calculate 30 instructions available)

My initial thought was to spin in the main code, watching for the event, but the dual UART code looks like it takes too much of the·30 instruction alottment, meaning I could miss the trigger.

So, I thought about making the trigger the IRQ, and running the dual UART code in the main loop.· Obviously, that means I need to substantially change the VP code and use the SX48/52 timers to keep me accurate.

In the AVR, I'd have dumped both chunks of code in IRQ code, and turned IRQs on in the serial bit bang code (in case the asynch trigger came in while in IRQ code), but I've seen reams of documentation on the SX warning about not having multiple asynch IRQ sources, as they might get lost.

Anyone have other ideas, or can comment on my current idea?· Can anyone comment on why they limited the IRQ stack to one level?·

Jim





Post Edited (Jim Brain) : 10/26/2004 3:23:59 PM GMT

Comments

  • PJMontyPJMonty Posts: 983
    edited 2004-10-26 02:04
    Jim,

    I'm not quite following your concern. You have to service a data request in 390 us, or .00039 seconds. The chip is running at 75 MHz, eg. a 13 ns cycle time, which means each clock takes .000000013 seconds. When I do the math, I get the following:


    .00039 / .000000013 = 29250 cycles per 390 us period. Did you get the service time wrong? In order to have only 30 cycles, you would need to service the data request in 3.9 us, not 390 us. Can you clear up my confusion?
      Thanks, PeterM
  • BeanBean Posts: 8,129
    edited 2004-10-26 13:41
    If you use a purely interrupt driven solution:

    75,000,000 / 230,400 = 325.5 cycles per interrupt
    If you use 3 times oversampling that is 108.5 cycles per interrupt.

    I think you could easily do a single uart that way, but thats really tight to do a dual uart (but it could probably be done).

    Bean.
  • Jim BrainJim Brain Posts: 17
    edited 2004-10-26 15:35
    PJ, I fixed the post. It's 390 nS, not uS. Hope that clears up the confusion

    I've looked at the VP code, and I think I can change the VP scheduler to run as a regular task. My idea is to:

    ; poll RTCC overflow flag
    ; load RTCC with new count
    ; jump into VP code table

    That way, the VP code could still be used pretty much as is, but I'd then use the IRQ to catch the asynch event. The event can be serviced in 3 or 4 instructions, so I think it would place little to no load on the main rs232 tasks.

    The problem is, the SX datasheet gives precious little information on the RTCC usage. I can see from the VP scheduler code that the IRQ code starts at $0 (although somewhere on the net stated location $4 is the vector), and it does the jmp table stuff. All VPs end up loading W with 217 (or 108 or whatever), and the retiw. But, that leaves questions in my mind, like:

    Where is it documented that RTCC is loaded with W on return? I can't find it in the datasheet at all.
    Since you've already expended some cycles doing your IRQ routine, if you load RTCC with 217 again at the end, for example, won't that cause your IRQ handler to be delayed for the next round (In other architectures, if you used a one-shot timer to generate an IRQ, I was always instrcuted to load it again in the beginning of the IRQ handler, to avoid the "walking timebase" issue. I suppose you could subtract the cycles the VP uses from the count before loading W, but I don't see the VPs doing that. I must be missing something.

    Jim
  • PJMontyPJMonty Posts: 983
    edited 2004-10-26 16:18
    Jim,

    Yeah, when I first started playing with the SX I wondered about the whole return value as well. However, it turns out that the SX does just what you want it to do.

    mov     w, #-int_period          ;interrupt every 'int_period' clocks
    retiw                           ;exit interrupt
    



    If "int_period" is set to 152, and the RTCC is 1:1, then as long as your interrupt code is shorter than 152 cycles (actually, there a few overhead cycles for getting into and out of the interrupt as well), the intterupt period will always be 152 cycles long. It doesn't matter if your interrupt code takes 20 cycles on one interrupt, and 106 on another, the SX does the right thing. Bear in mind that the "-" in front of the interrupt period is critical, since it is the key to having the SX automatically calculate the right value for W to cause the interrupt to remain consistent. Basically it's using overflow math to do figure out the remaining number of cycles.

    As for your time issue, I'm just curious what sort of serial device needs a response in 390 ns before a timeout or problem. I would also look closely at the code to determine how much time is spent in the interrupt handler if there is no data coming in or out. While the worst case scenario might be cutting it close, how often is the code in the worst case versus the best case? I often find that interrupt code worst case is "just getting by", but that most of the time, the main code has plenty of cycles to handle its work. As long as you have enough for the worst case, then it only gets better for the best case.
      Thanks, PeterM
  • StephenStephen Posts: 53
    edited 2004-10-26 16:24
    Page 24 in the attached datasheet describes how the RETIW instruction handles the W register on return from the ISR. RETIW adds W to RTCC. This ensures that the next RTCC rollover will be 217 (or whatever number you choose) cycles from the return.

    One thing to consider is that if both external interrupts and the RTCC interrupt are enabled, you will always have the risk of adding jitter to the RTCC interrupt. As a result, the timebase for all VPs will be unreliable. To maintain jitter free operation of VPs, it is uusually better to simply poll the external interrupt sources in the ISR. There is usually some acceptable delay in responding to an asynchronous event. To help with this, the WKPND register can still be used even with external interrupts disabled - it will still show what external interrupts were triggered.
  • Guenther DaubachGuenther Daubach Posts: 1,321
    edited 2004-10-26 16:34
    Jim,

    I have copied the following text from my book, and I hope it explains how simple it is to achieve exactly timed interrupts:

    Let's assume that we want an interrupt every microsecond at a system clock frequency of 50 MHz. This means that an interrupt must be triggered every 50 clock cycles. To achieve this, it is not sufficient to load RTCC with 256-50 = 206 at the end of the ISR. You must keep in mind that the instructions within the ISR already have taken clock cycles while RTCC was incremented, and three more clock cycles were required to enter the ISR. Another thee clock cycles are "stolen" to return from the ISR.

    In order to find out the correct RTCC initialization you would have to sum all these clock cycles, and whenever you make a change in the ISR code, you would have to re-calculate the sum. Things get even more complicated when the execution time of the ISR instructions is not constant. This can easily happen when conditional skips are involved.

    Fortunately, there is no need to do all this manually because the SX keeps track of the clock cycles "used" within the ISR. Because the RTCC keeps incrementing after its overflow has triggered the interrupt, its contents at the end of the ISR exactly holds the number of clock cycles "used" so far.


    Therefore, we take the number of clock cycles that shall elapse between two interrupts (nC), subtract this value from the current contents of RTCC in order to get the correct initialization value for RTCC.

    To understand this, assume for a moment that the ISR did not "use" any clock cycles, and that the call and return do not require any clock cycles either. This would mean that RTCC contains zero, i.e. the "magic value" that has triggered the interrupt. In order to have the next interrupt triggered after RTCC has been incremented for nC cycles, it is necessary to decrement it now by nC. This is why we subtract nC.

    In reality, less than nC cycles are required until the next interrupt to be "just in time" because the ISR really did "use" clock cycles. As mentioned before, this cycle count is contained in RTCC and so the correction is done automatically.

    There is even more good news: The retiw instruction has been included to do exactly that! Similar to reti, retiw returns from an interrupt but it also adds the contents of w to the RTCC.

    In order to store (RTCC - nC) to the RTCC, we just need to store -nC to w before executing the retiw instruction.
    To achieve an interrupt period of 1 µs (50 clock cycles), for example, just write the following code:

    mov w, #-50
    retiw

    Congratulations to the SX development team - this "little trick" is one of the features that make the SX so powerful!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Greetings from Germany,


    Günther
  • Jim BrainJim Brain Posts: 17
    edited 2004-10-26 16:53
    I appreciate the link, but that's the datasheet I was looking at. I missed the one liner on page 24 (I was rather assuming the information would be noted on page 27, with the rest of the RTCC stuff, go figure).

    Reading this, I noticed in para3, it makes the ominous statement about multiple IRQ sources, but in para5, it then notes that if one has MIWU IRQs on and they occur while in the ISR routine, they WILL get serviced immediately following. However, that begs the question of how it behaves if you have 2 MIWU IRQs set, and you are servicing one of them when another one triggers.

    Maybe it is just me, but the data sheet seems lacking. The data appears to be mostly there, but the organization seems contrary in places, and the corner cases seem inadequately documented.

    I now understand how the adding works, though. If I've used 22 cycles in my ISR, adding -217 to it means the RTCC is set to -217+22 = -195, which is clever.

    As for the IRQs, since the one event happens at any time and must be serviced in 390nS, I intend on using the IRQ routine for that, since it is the shortest path, and running the VP UARTs as normal non-ISR tasks. That way, I'm only using 1 IRQ, which I can service in 100nS or so.
  • StephenStephen Posts: 53
    edited 2004-10-26 17:03
    If more than one MIWU IRQ is enabled, it is completely up to the software to determine which IRQ to service. If you enter the ISR and both bits are set, it would be best to service just one MIWU IRQ at a time and clear only that bit in the WKPND register, or else you will never know if the 2nd interrupt has occured again.

    As you can see, enabling multiple interrupt sources can get pretty complicated very quickly. There is only one level of interrupt, though if you want to get fancy you could enable interrupts again while in the ISR. This would add the support for nested interrupts, but only complicates the confusion further. To my knowledge, very few people have ever found a need for nested interupts in the SX... simply polling external interrupt sources in a SX design still nets a response time much quicker response time than what is possible with an actual interrupt in other chips.
  • Jim BrainJim Brain Posts: 17
    edited 2004-10-26 17:07
    Hi G
  • Jim BrainJim Brain Posts: 17
    edited 2004-10-26 17:27
    PJ,

    The serial ports top out at 230K, but the other end (the SX will perform an inteface function) is a 1MHz bus. As a result, the bus will expect valid data (i.e. a read cycle) 390nS following the clock signal going high.

    Given the application (a retrofit, where register mapping needs to be maintained), the complexity of remapping a 1655X UART mandated a huge CPLD, not to mention adding another IC. As well, I'm trying to control cost, and a CPLD/UART approach was quite a bit more than just a SX48/52.

    Above that, I'm curious if one can utilize a high-performance uC like the SX to replace obsolete or hard to find ICs, like PIAs, VIAs, CPUs, etc.

    Jim
  • Jim BrainJim Brain Posts: 17
    edited 2004-10-26 17:38
    Stephen,

    See, I think my application is one such example, where nested interrupts would have worked very nicely.

    I hum along, the RTCC overflows, and I enter the ISR
    Immediately after I determine the source of the IRQ, I re-enable IRQs
    I start my 17-22 cycle UART receive routine, but in the middle of that, I get an external IRQ telling me the bus is requesting data.
    *I re-enter the IRQ routine and determine the external IRQ happened, so I quickly service it and reti
    * that drops me back into my UART VP routine, which continue as normal, doing a retiw at the end

    * cannot be done in SX, due to single level stack, as far as I know.

    Sure, I can poll the external pin during the UART VP operation, but since I need to catch it pretty much as soon as it happens, I'm left with:

    ; line of UART code
    ; test for external IRQ
    ; line of UART code
    ; test for external IRQ
    ; etc.

    Which seems hardly workable to me. The idea of flipping the VPs to run as the main task and using the IRQ for the trigger seems the most workable.

    I appreciate the information on the MIWU, but I'm curious how you determined that, as I just reread that portion in the datasheet, and I couldn't come to any conclusions. I agree handling one at a time is best.

    Jim
  • James NewtonJames Newton Posts: 329
    edited 2004-10-26 18:25
    I would set up a "minimal" RTCC ISR that does nothing more than increment a register. You can poll for your bus interrupt in that if you like or just let it return and then the hardware interrupt will fire. In the main code, poll for an increment on that register and use that to time the UART. Basically that is, as you say, "flipping the VPs to run as the main task" but you still have the accuracy of the ISR timing.

    If you limit your ISR to just flipping a switch when an external event occurs, you can have as many external interrupts as you like. Then you poll for those switches in the main code, and you do the polling in the order of priority of the external interrupts. You do have to pepper the lower priorty VP code with checks for a higher priorty interrupt flag, and then call the main polling routine when one occurs. The main loop calls the main polling routine and then loops, so the main polling routine returns when it completes an interrupt. If a lower priority interrupt called it for a higher priority one, then it will return to the low priority one, otherwise, it will return to the loop.

    It would be great if an ISR could change the address that it is returning to since that would allow us to build our own stack system and not use the internal stack at all.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ---
    James Newton, Host of SXList.com
    james@sxlist.com 1-619-652-0593 fax:1-208-279-8767
    SX FAQ / Code / Tutorials / Documentation:
    http://www.sxlist.com Pick faster!



  • Jim BrainJim Brain Posts: 17
    edited 2004-10-26 19:56
    James,

    I like that idea, but what happens if the external IRQ fires, I enter the ISR, and then the RTCC overflows? According to the docs, it would appear the RTCC IRQ would be "lost".

    I'd love to do it this way, but I discarded it for the above reason.

    Jim
  • StephenStephen Posts: 53
    edited 2004-10-26 20:25
    The RTCC interrupt would not be lost, just delayed response until the ISR returns. That's the jitter...
  • Jim BrainJim Brain Posts: 17
    edited 2004-10-26 21:07
    Super!

    But, I'm confused. Since so many resources caution against using multiple IRQs due to the possibility of "lost" interrupts, I inferred that if you were in the ISR and another event occurred, it was lost, pure and simple. What I am hearing today is much better news, as the events would not be lost, just delayed. I can deal with jitter, I just can't deal with lost events.

    Now, I'm unclear when you would actually "lose" one (except in the case where you stayed in your ISR so long that the same external interrupt triggered multiple times. However, that is the case in any architecture, not specific to the SX.


    Jim
  • James NewtonJames Newton Posts: 329
    edited 2004-10-27 00:10
    The ISR always needs to check for RTCC being less than a certain value since that is the only way to know if the interrupt was caused by the timer. If you do that correctly, you will detect not only an RTCC rollover that just happened, but also one that is going to happen before you exit the ISR. Basically, you want to look at the absolute value of RTCC as if it were a 7 bit value that counts up to 127 becomes -128 and counts back down to zero. To do that, just check the high bit and if it is set, negate the value, THEN subtract a value equal to the number of cycles in your ISR and if it is less than that, service the timer interrupt.

    Stephen probably has some other, more clever way to do that.

    On the issue of dropping interrupts, the only issue I am aware of (which can be worked around) is reported at:
    http://www.sxlist.com/techref/ubicom/sxints.htm I'll copy it here:

    Alexey Vladimirov [noparse][[/noparse]avlad at mailbox.riga.lv] says:
    Typical interrupt service routine contain the following code:

    mov m,#$09 ;Set up to read wake up pending register
    clr w
    mov !rb,w ;Read WKPND_B register content and clear it after that
    ...
    reti

    Each SX instruction in turbo mode executed in a 4-stage pipeline, consisting of the following steps: fetch instruction, decode opcode, execute opcode, write result.
    In the example mov !rb, w instruction at the second step simultaneously with instruction decode also read WKPND_B register and at the fourth step clear WKPND_B register.
    If another external interrupt on different portB pin occurs exactly at this time (at the 2,3,4 steps of the mov !rb, w execution), SX will loose this interrupt (as the WKPND_B register cleared and, therefore, pending bit for this interrupt also cleared without interrupt processing).
    It mean, that it is not possible to use 2 or more asynchronous external interrupts on the SX without loosing some interrupts.
    This problem related to all current (as of Jan 2001) SX revisions.
    [noparse][[/noparse]To work around this, check the pins by reading the actual port value after the first interrupt.] If you will use polling instead of interrupts - all will works OK. You can also use one external interrupt and poll other pins. However, if you have two asynchronous signals and you need interrupt on both (bridge application, for example), the only possible workaround we found - add some external glue logic (triggers for each interrupt with separate reset from SX port, as in any typical interrupt controller, like 8259) or change from interrupts to polling.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ---
    James Newton, Host of SXList.com
    james@sxlist.com 1-619-652-0593 fax:1-208-279-8767
    SX FAQ / Code / Tutorials / Documentation:
    http://www.sxlist.com Pick faster!



  • StephenStephen Posts: 53
    edited 2004-10-27 00:34
    No matter how you check the interrupt source, there's always a way one could sneak past...

    There is one more way to check if a RTCC overflow occured (only on SX48/52)... The RTCCOV bit in the T1CNTB register. I got this one added, and this was the only place left to put it! smilewinkgrin.gif
  • Jim BrainJim Brain Posts: 17
    edited 2004-10-27 00:45
    James, that errata is VERY important information to note. Thanks. As for the timer situation, I did some testing here with the SX-Key and the debugger tonight.

    Concerning your idea of setting up a minimal rtcc timer, I implemented it, but it takes 6 cycles to get in an out of the ISR, add another cycle to increment flag to check in the main code, and some code to test if the ISR was entered due to RTCC or PORTB pins, that meant 11 cycles or so that I could be in the ISR, but not servicing the bus request. It also didn't eliminate jitter, as the main VP code did a snb FLAG, jmp $-1, which introduces some jitter. I could cut down on the delay by checking the pin status while in the ISR, but that meant more code to handle that decision tree, etc.

    So, I simply took out all the RTCC ISR code, and replaced the main loop with:

    snb RTCC.7 ; check bit 7 of RTCC
    jmp $-1 ; not rolled over.
    add RTCC,#-int_period

    int_period is 54

    This looks to provide the same stable timer functionality of the RTCC ISR, but it has no delay on servicing the bus request. The add looks atomic, so I should never get interrupted in the middle of adding -54 to the RTCC count.

    Now, 54 clocks doesn't give me much time, but I don't think I need much, and I can switch to 3x sampling if I need to.

    I did find an issue with SXSim 1.4.1, as I turned off the RTCC IRQ, and in SXSim, the RTCC quits incrementing in that situation. At least the debugger and SXSim differ in their information.

    Jim
Sign In or Register to comment.