Mutliple Virtual Peripherals - running at different rates
Tony Leyland
Posts: 71
Hi,
I've been working on utilising 2 or more VPs. I've read the Scenix PDF on VP methodology and understand the principles of
multitasking (as shown below)
inc isrMultiplex
mov w,isrMultiplex
jmp pc+w
jmp isrThread1
jmp isrThread2
jmp isrThread3
etc etc
isrThread1: ; VP 1 code here
jmp isrOut
;
isrThread2: ; VP 2 code here
jmp isrOut
;
isrThread3: ; VP 3 code here
mov isrMultiplex,#255
jmp isrOut
;
isrOut:
mov w,#-int_period
retiw
I understand how to have one VP running at 9600 (for a UART say) and having another VP running at 2,4,8 or 1/2,1/4,1/8 of the 9600 rate like this:
jmp pc+w
jmp isrThread1
jmp isrThread2
jmp isrThread1
jmp isrThread3
jmp isrThread1
jmp isrThread4
Does anybody know of a way to have 2 VPs running. One at other frequencies that are not multiples/divisions of the 9600 rate (100Khz say for example)
and another VP running at the 9600 rate ?
Thanks in advance
Tony
I've been working on utilising 2 or more VPs. I've read the Scenix PDF on VP methodology and understand the principles of
multitasking (as shown below)
inc isrMultiplex
mov w,isrMultiplex
jmp pc+w
jmp isrThread1
jmp isrThread2
jmp isrThread3
etc etc
isrThread1: ; VP 1 code here
jmp isrOut
;
isrThread2: ; VP 2 code here
jmp isrOut
;
isrThread3: ; VP 3 code here
mov isrMultiplex,#255
jmp isrOut
;
isrOut:
mov w,#-int_period
retiw
I understand how to have one VP running at 9600 (for a UART say) and having another VP running at 2,4,8 or 1/2,1/4,1/8 of the 9600 rate like this:
jmp pc+w
jmp isrThread1
jmp isrThread2
jmp isrThread1
jmp isrThread3
jmp isrThread1
jmp isrThread4
Does anybody know of a way to have 2 VPs running. One at other frequencies that are not multiples/divisions of the 9600 rate (100Khz say for example)
and another VP running at the 9600 rate ?
Thanks in advance
Tony
Comments
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
---
James Newton, Host of SXList.com
james at sxlist,com 1-619-652-0593 fax:1-208-279-8767
SX FAQ / Code / Tutorials / Documentation:
http://www.sxlist.com Pick faster!
Sure; look at my entry in the recent Parallax contest....."Small Hardware and Development Prototyping Board".
In the software I include a VERY simple minded co-operative RTOS that allows different (but consecutive multiple) timings for various tasks.
There is also a much more complicated premptive RTOS as a second contest entry. Studying that will give some ideas.
Cheers,
Peter (pjv)
What specific VPs do you have in mind? Are they all communication related?
I ask because communication related VPs tend to be more critical of timing issues than some other VPs (such as PWM) are. However, you need to also look into how critical is critical? In the case of UART VPs, you are definitely allowed some slack. In the serial data stream, each new start bit essentially re-synchronizes the receiver to the stream. This means that if there is some small timing discrepancy, as long as the error doesn't add up to over 1/2 a bit duration by the end of 10 bits (assuming an 8N1 serial stream), then you're pretty much golden.
With this in mind, you need to see if it's possible to find a common denominator for the multiple VPs you wish to run, even if it means the UART VP has some built in error. As long as the error is manageable, it won't be a problem.
Another alternative is to consider the possibility of dithering the VP execution. In other words, lets say you have a VP interrupt rate that creates too big an error in the UART stream by the end of ten bits of transmitted data. The error might get too big after only 4 or 8 bits. It is possible that you could skip an interrupt (or add one depending on which way the error is going) so that you shrink or stretch the bit length of one of the middle bits. By doing this, you could still end up with the per bit error being in the acceptable level, at the expense of a tiny bit of additional code.
Thanks, PeterM
Peter, your suggestion of un-needed UART baud clock accuracy is bang-on!
In all my software UARTs I run the clock from a multiple of interrupt based ticks, generally based on 20 uSec for 9600 baud. The receiver generally samples every 20 uSec to find the leading edge of the start bit, and then 2 ticks later (the middle fifth of the start bit) locks the data sampler to take a reading every 5th consecutive tick. This samples the data in the 3rd (middle) tick of every data bit.
The transmitter sends a bit every 5 ticks, giving 100 uSec bits instead of the standard 104 usec. To date this has worked perfectly and all UARTs I have connected to have not complained about this discreptancy.
Tighter timing can of course be provided at the expense of some greater complexity and processor overhead.
Using 20 uSec as a base tick gives all other events a nice timing reference.
Cheers,
Peter (pjv)
The VPs that I will be using (on an SX28) are:-
1) UART at 9600bps (but I may go up to 57600)
2) I2C at 100Kbps
3) General purpose timer function (which will be sub divided from the I2C "tick"
Thanks for the advice concerning how for UART comms the timing is not too critical.
From what you have said, I may have come up with a solution. I have noticed from initial tests, that the 'ticks' for the
UART and the I2C are a bit 'jittery', but I understand why that is and I can live with it. If anyone is interested, I will post the small ISR
source when I have it sussed.
Thanks again for the advice,
Regards
Tony
I am a long way from feeling comfortable around mutiple ISRs, but would enjoy trying to read your code.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"When all think alike, no one is thinking very much.' - Walter Lippmann (1889-1974)
······································································ Warm regards,····· G. Herzog [noparse][[/noparse]·黃鶴 ]·in Taiwan
Please be aware that I'm talking of the SX acting as an I²C master. When you are going to implement an I²C slave, it will be more time-critical as you may not miss the start condition, or any SCL signal changes.
I like this protocol, and I can only say "hats off" to the guys at Philips who have created it.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Greetings from Germany,
Günther
While I stated my positive experience with running virtual 9600 UARTs at 100 uSec bit times, you should not trivialize that issue. If you have yet additional "jitter" as you say on top of that, you need to do some clear observation and thinking.
I have also written virtual UARTs at numerous speeds which resync their sample clock on detection of any bit edge. This makes things yet somewat more forgiving, altough characters with bit transitions only at the end of the byte are still a concern with jitter.
For the purists who think running 9600 at 100 uSec vs 104 uSec bits is inappropriate, my simple co-operative RTOS scheme can still deal with that. Using an ISR tick time of 2 uSec will be perfect, but somewhat (unneccessarily) heady in overhead. A 5 uSec tick will fare much better on overhead, and get you to 105 uSec.
As far as I2C is concerned (master), these activities are not speed sensitive, so having interruptions in their read/write process is of no consequence.
If you would like a simple VP UART together with an I2C routine running in the simple RTOS posted, I'd be happy to oblige; though it may take a few days to get the time available. Just let me know.
Cheers,
Peter (pjv)
Thanks for pointing me in the right direction concerning having the Slave I2C routine in the ISR and the Master in the main loop. I read in your book that
your I2C example has a Slave component that can listen for Master signals at 100Khz. I noticed that the ISR tick is actually at 400Khz. Is it possible to
reduce the ISR tick to 200Khz or even 100Khz but still be able to listen and process 100Khz signals from the Master ? as I'm trying to 'slow' down the
how often the ISR occures (see below).
I agree with you about how cool & clever this protocol is. That's why I'm spending so much time to understand the inner workings ! - so I can achieve
multiple SX communications over a shared bus. Each SX being a 'black box' where I don't need to concern myself with the code running within it once created,
I just concentrate on the various I/O of the 'black box' - I bit like creating a .DLL in ASM on the PC and then including it in a VB APP.
Hi Peter (pjv),
Thanks for the offer about "simple VP UART together with an I2C routine running in the simple RTOS posted", I'll let you know if that is what is going to be best for me.
Just to explain, for this test project (so I can learn about I2C & RS232), I'm listening for 100Khz I2C traffic and converting it to RS232 at 57600 or hopefully 115200. I'm using the USB2SER module to get it on to the PC through the USB port so I can see the characters coming in to a Terminal program. Once I've learned from this
I intend to create a 'TermOut' command for use within SX/B that operates in a similar fashion to the 'Debug' command in a STAMP. In that way I can then
add STAMP like Debug lines to my future SX/B projects (things like showing variable status and arrays or strings in realtime on a Terminal on the PC).
Concerning the 'Jitter' I mentioned earlier - I've now got an ISR with zero jitter on the 2 VPs, so that's better. It gives me a tick for the I2C Slave at 403.2Khz and
a tick for RS232 TX at 57600Khz. The only thing is the RTCC value is 62 which gives an ISR interval of 1.2us - ouch ! The 'main loop' will have very little
processing so I reckon such a frequently occuring ISR should be ok, but I would like to increase the interval if i can.
BTW, the values I've come up with for the VP timing have come from a simple VB program that does the calculations. I'm going to develop this VB program
further and post it here, in case anybody else is interested (along with the an example VP Kernel).
Thanks
Tony
other to my statement in my previous post, the I²C Master in my book example is ISR-driven. For each SCL period, it requires four ticks, the first one pulls low SCL, the second pulls low, or releases SDA according to the data bit, the third releases SCL, the fourth leaves SCL and SDA stable to allow the slave to read SDA, the fifth/first again pulls low SCL again, and so on... This is why the ISR tick is actually at 400 kHz for a 100 bps bus speed.
When looking at the implementation of an I²C slave, first, it is important to detect a start condition as close to "real-time" as possible. The same is true for subsequent transitions of SDA, to make sure that the slave ony reads SDA, when SCL is high, or modifies SDA only, when SCL is low. Therefore, for a safe operation of the slave it makes sense to read samples from the bus at least four times faster than the bus speed is. On the other hand, the data-stream generated by a master must not always follow an exact timing scheme, so the question is, if the slave code might also be handled outside of the ISR but in a fast loop in the main code instead, as the ISR timing is not necessarily an advantage. I think it is hard to give a general rule of thumb here - it depends on how much execution time the ISR takes away from the main loop for other tasks, and how much execution time the main loop itself needs for other stuff.
You know my implementation of an I²C Monitor which is one feature of my RS-232/I²C Adapter. The monitor actually is a modified slave, only reading the bus activities without putting data on the bus. I have implemented this code outside the ISR in the main loop where the ISR only handles a timer, and a 115200 Baud UART.
In another application (clocked @ 50MHz), I frequently execute code in the main loop that checks for a start condition on the I²C bus. This happens fast enough to detect a start condition almost in "real-time" on an 100 kbps bus. In case, a start condition has been detected, the code branches into an I²C receiver, from where it only returns after the complete I²C communication has been handled. This is acceptable in my application because the rest of the main loop does not contain any other time-critical code, and the ISR does not "eat up" too many time-slices while the I²C slave is duing its job.
"Slaving", or monitoring events, like the ones that do occur on an I²C bus means dealing with events that must not necessarily be deterministic. In this context, don't forget the nice additional functionality of the port B inputs: The WKPNDB register bits. Besides using this register to trigger interrupts, or wake up a sleeping SX, you can nicely configure and use them to detect asynchronous rising or falling transitions on port B pins. So, when you are looking for a transition on a port B bit, instead of polling the input directly, you might consider to poll the WKPNDB register instead. This allows you to detect very short transitions, say a low-high-low transition that you might miss when polling the input pin directly. I did not use this feature for I²C so far, but it might be helpful for I²C applications as well.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Greetings from Germany,
Günther
Post Edited (Guenther Daubach) : 11/15/2005 4:36:19 PM GMT