Adding a Background UART to SX/B?
I would like to be able to send and receive serial data in the background while running a main program on an SX in the foreground. I know that this can be done in assembly using virtual peripherals. I know also that this is not a built-in capability of SX/B. However, I would like to add an interrupt driven background UART capability to my SX/B programs! ![smile.gif](http://forums.parallax.com/images/smilies/smile.gif)
The most obvious question to ask is, “Has anyone already done something like this?” If no one has then I may be naive enough to begin to attempt it myself.
What I think might work is to modify either the “Dual UART Virtual Peripheral Implementation” code or the “Easily Implement UART Capabilities” code (both found on Parallax’s SX downloads page) in the hopes of making it “play nicely” with the rest of my SX/B programs.
Does anyone have any insightful comments about this possibility?
- Sparks
![smile.gif](http://forums.parallax.com/images/smilies/smile.gif)
The most obvious question to ask is, “Has anyone already done something like this?” If no one has then I may be naive enough to begin to attempt it myself.
What I think might work is to modify either the “Dual UART Virtual Peripheral Implementation” code or the “Easily Implement UART Capabilities” code (both found on Parallax’s SX downloads page) in the hopes of making it “play nicely” with the rest of my SX/B programs.
Does anyone have any insightful comments about this possibility?
- Sparks
Comments
There has been several threads on this subject. Basically you create an interrupt that runs 3x your required baud rate. Then you need to keep track of the data and the bit count.
It's not too hard, but you will cause timing issues with commands in your main code.
What baud rate do you need ?
What frequency are you running the SX ?
Bean
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Cheap used 4-digit LED display with driver IC·www.hc4led.com
Low power SD Data Logger www.sddatalogger.com
SX-Video Display Modules www.sxvm.com
·
I have both 4Mhz and 50Mhz resonators on hand that I can use. The main program is not timing critical as chip-to-chip communications are handled over an I2C bus. Everything else runs as fast as it can in a main loop with cycle times of a few hundred Hz being sufficient for processing I/O state changes.
The “tricky” part is that this is the first project I have worked on where the SX might be both sending and receiving serial data at the same time. I hope that when I get this functionality working I will be able to apply it to other projects probably operating around 9600 baud.
Rsadeika,
The idea of a serial VP seems somewhat familiar. If it came from JonnyMac I can not find where it is buried among his 86 posting. If you are thinking of his thread on a servo VP it has no serial routines in it.
Bean,
Upon further searching I found in this thread an interrupt driven 3X sampling serial routine by you that I am examining now. I did not mention this earlier but I think I would like it to have some type of buffer for incoming and outgoing data. This project sends data in 23 character packets.
I hope I am not making this too hard. I am just looking for advise on the best way to start.
- Sparks
I either had the wrong search terms or did not think to look there because of the title.
Thanks again.
- Sparks
P.S. To embed a URL place something like {URL=http://www.parallax.com} click this text description {/URL} in the message body. (Only use square brackets instead!)
And if you get really good at it, maybe you could present an example of how to have a UART VP running at 57600 baud, and a SIRC VP working at the same time. When I was looking into this I got lost when I tried to change either freq·or baud or both. And to add in a VP that needed some different timing requirements, like SIRC, I had a very severe headache. Never even got close to making it work.
I used HyperTerminal and confirmed it worked at all supported baud rates.
Post Edited (JonnyMac) : 3/2/2007 12:44:57 AM GMT
Just set the cpufreq, maxbaud and THREADS parameter.
Then do View List and scroll down.
Towards the bottom of the listview are constants BAUD_x_y
where x is the baudrate and y is the number of threads.
Combinations of threads and bauds that do not give a usable constant
are not listed.
regards peter
Okay, Ray, you owe me a beer -- maybe a six-pack -- and my preference is Guinness (I'm Irish!). I took the UART code that runs at 57.6K and folded in an ISR-driven SIRCS decoder (that I sent you back in 2005). The only update I made to the SIRCS decoder is that now it does the full 12 bits so you can differentiate between devices (device and key codes end up in separate bytes). I've attached the program and a screen shot of a HyperTerminal session with it.
Have fun!
Jon
Post Edited (JonnyMac) : 3/2/2007 9:22:42 PM GMT
edit< I just had chance to give the code a closer look, I would have never figured it out. I hope you use this in some way in your book, where you could give it some extensive explanation.>
Post Edited (Rsadeika) : 3/2/2007 10:34:18 PM GMT
Keys to remember: The UART ISR should run at 1/4 the bit period or faster for reliable RX sampling. Since you wanted 57.6K that gives us a bit period of 17.36 uS, so the interrupt should run every 4.34 uS (or 230,400 times per second -- this is where SX/B make using interrupts easy with the ISR rate value). The SIRCS decoding that I had done in the past used a 26.04 uS rate; I'm not sure why I selected that back then, but I suspect it would allow me to keep the bit timing measurements in a single byte to simplify things. This turned out to be fortuitous for addition to the UART code, as the SIRCS rate is 1/6th the UART rate, so all I had to do is divide the ISR by six. This is accomplished with a simple counter that gets updated/tested after the UART section is complete. BTW, the bit measurement in the SIRCS section uses 80% of the expected bit width to allow for device-to-device variances, hence 2400 uS (start bit) x 0.8 = 1920 / 26 = 74 (you'll see this value in the code).
So, thank you for the challenge -- this program is going to end up in my book, "Practical SX/B," though I suspect explaining it will be harder than writing it....
?JonnyMac! I lost my 50MHz resonator and all I have is a 4MHz. I tried your UART code in a stand-alone, and it does not seem to work. Oh, and I want to use 115200 baud, that does not seem to work either. Oh, and I tried it without any external resonator, that did not seem to work.
?JonnyMac! I went to Radioshack, and I bought an IR detector, the label says something about 950nm. Well, anyway I soldered that in, and the program does not work. Does the problem have anything to do with 950nm. Since it is soldered in I want to use that.
?JonnyMac! To bad SX/B only supports two VP's. I purchased, from Parallax, an 36KHz object detector kit. How can I add that, as a VP, to the SIRCS_UART code. Of course I want to use my 950nm detector as a seperate VP.
Their are probably a lot more questions, but I am sure that you have that covered.
Thanks
The engineering axiom "Cheap, Fast, Easy -- pick two." holds true. The book won't (can't possibly) answer every possible question, but I think that if it is given a fair chance it will help those that want to step up to the SX, without going fully into assembly programming, do the kinds of things they want to do.
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Cheap used 4-digit LED display with driver IC·www.hc4led.com
Low power SD Data Logger www.sddatalogger.com
SX-Video Display Modules www.sxvm.com
Coming soon! Propeller based OSD module www.hittconsulting.com
·
If you look into the start-up code generated by the compiler you'll see the OPTION register set there; you'll also find appropriate TRIS and related settings that are connected the the PIN declaration (when specifying pins as outputs, for example).
It took me awhile to figure out 1/x, but when I did,·my thought was, boy is that a simple formula. The thing that threw me off at first, were the .9999 ....·values I kept coming up with, and it could not be that simple. Now I am trying to figure out a formula, using paper and pencil, how to get the interrupt period, and then the interrupt itself, when the freq changes to 4_000_000MHz, or any other value,·as an example. I guess their is some other stuff that has to be solved first. I am not ready for the 'delay' concept just yet, when two different VPs are involved.
The rate parameter of INTERRUPT makes things really easy to get started because the value for OPTION is handled automatiaclly and is based on your FREQ setting -- all you have to do is know that rate, and it's based on what your hardware needs to do, not what the SX's oscillator is doing (if there's a conflict, the compiler will tell you). When you're mixing VPs, as I did above, it takes a little more thought, but it's really not very difficult so long as one rate can be evenly divided into the other; just put the VP that runs more frequently first, then the divider code, then the slower VP.
Try with something simple first, like flashing three LEDs at different rates (see attached) using the ISR and ISR divisor tricks like I used. Once you understand the concept, the rest will fall into place.
Post Edited (JonnyMac) : 3/4/2007 9:08:34 PM GMT
The background serial send and receive SX/B subroutines Bean posted in another thread are working fine for me… using Bean’s demo program. Presently they are not working in my own program. Guess who’s fault that is!
The example background VPs of pjv and JonnyMac are both interesting to me. I will be exploring them separately. The cooperative environment produced by pjv is taking me a while to wrap my head around. I was not taught to program that way, though I do understand state machines (or at least I thought I did)!
The background processing information the SX community has offered so far has been very helpful. Please continue as additional insights come to mind!
- Sparks
Robert
Since my last entry on this thread I have been successfully sending and receiving serial data with background UARTs. In one application I also have a Delta-Sigma Analog-to-Digital Converter (ADC) process running concurrently with the background UART as well as the main application in the foreground. The fact that these tasks are working and working well is a tribute to the support I have received from many people on these forums!
The short answer to your question about “tweaking” UART code to run with a slower clock is to simply adjust the interrupt rate or at least the rate at which you call the UART code. It really can be just that simple!
In my case I only needed to exchange a few serial bytes to signal or reflect changes to the system state. So I settled upon 4800 baud. The code I used samples serial data at three times the baud rate. So I initially set my interrupt rate to 4800 x 3 = 14400. Later I added a user-control potentiometer for controlling the speed of a motor. To sense the potentiometer position I added the Delta-Sigma ADC code to my interrupt service routine. I wanted this to run a little faster than 14400 times per second so I doubled the interrupt rate to 14400 * 2 = 28800. To insure that the UART code was still being called at the correct rate I added a few statements so that it would only be called once every other time the interrupt occurs. I arranged it so that both code segments were being called at the appropriate rates. That is a key to interrupt happiness! (Other keys include exiting with sufficient time remaining for foreground tasks before the next interrupt occurs and, if necessary, assuring accurate timing through various branches of the interrupt path.) The ADC code was always called first as it takes the same number of clock cycles to run regardless of any branches that may occur within it.
I was using a 20Mhz clock for all of that while also reading and writing to an external EEPROM, reading and debouching user input buttons and updating an LCD. I have found the SX to be a very powerful chip indeed!
To directly address your mention of running a 9600 baud background UART, consider the timing requirements for a 4MHz clock. You will need to sample your data at three times the baud rate or higher. At a 3X rate you will need to have an interrupt occur 9600 x 3 = 28800 times per second. At 4MHz that leaves time to execute 40,000,000 / 28800 = 1388 instructions before the next interrupt occurs. So you should be just fine running a 9600 baud UART in the background with a 4MHz clock.
To summarize…
Spark's Three Keys to Interrupt Happiness
- 1. Ensure time sensitive code is called at the right time. (Usually done by setting the proper interrupt rate.)
- 2. Ensure the longest possible path through the interrupt code can return with sufficient time before the next interrupt occurs.
- 3. Ensure that extremely time sensitive code runs at EXACTLY the same time every time it is run. (A Delta-Sigma ADC is an example of code that must have the exact same run time every time it is called.)
One last thing to mention is that you should be sure to use an external resonator or oscillator for accurate serial timing.- Sparks
Post Edited (Sparks-R-Fun) : 10/29/2007 8:06:30 PM GMT
This is for a robot similar to the one I wrote about in the November issue of SERVO due out soon.
Best Regards,
Robert
I've been looking at the latest background Serial code (Buf_RX9600.SXB) and was able pull it into my program and am now able to compile it with out errors. At first I had to re-arrange a few of my variables and put some in an array to free up some variable space. I also added checks for the encoder in the Interrupt code and that seems to work great! I have the foreground code displaying the encoder value on the LEDs for testing and can tell it is working. I am using a 20Mhz resonator.
This may be a silly question but doesn't the SX/B compiler automatically keep the same interrupt timing since i've specified a 20Mhz resonator? If not is there a better Interrupt rate to use at 20Mhz for the Serial code? 9600 baud is what i'm going to use to talk to the SX48 chip.
It was really cool to see a lot of this project working so far and was glad to see that the old encoder board on the robot actually works. It probably hasn't had anything connected to it for at least 20 years...
Robert
Why? Your scan is in the Main more than in the interupt. If Packets are a set size adjusting the machine interupt timing to make up for Comms is easy, this can be done in the simulator. Hand shake from the interupt subroutine places it in a good position for timing adjustments.
How? Jump from the Main and handle the pin state for the first byte, then receive the rest of the packet nomally.
Error Checking? Valid commands or first and last byte.
HandShake? Oh yes, your application should conclude the data was transmitted succesfully and it's a good place to pass variables up stream, do that from the interupt subroutine. ( make sure it fits between interupts )
RS485, LAN, or multichip? That would be part of a packet ID.
http://forums.parallax.com/forums/default.aspx?f=7&m=223702
Comms is set for 38400.
SX 50mhz.
Packets can be timed to fit between interupts to avoid timing interuptions.( Not done above though. )
Since the ISR rate and number of instructions are the same, increasing the oscillator frequency will simply get through the ISR code faster leaving more time for the foreground stuff. You asked for something that would run at 4 MHz so I verified that my code would. I'm doing a project for a friend that has three UARTs and a servo controller in the ISR -- it's running at 50 MHz.
·· I've had good success with packet assembly, my next project will use modbus addressing. If the subroutine can be developed that is small enough maybe it can be offered with SX/B.