Wednesday, August 4, 2010

Using the USI as a UART

This post will describe how I use the USI as a UART and discuss how I hook the LaunchPad up to a MSP430F2013 on my breadboard which is connected to an FTDI breakout board. Please note that it is impossible to easily set up the USI module to receive UART data, and I will never write code to do so. For those of you who are beginners please do not get caught up in trying to understand the USI code if you are having trouble, I will not be going in depth about the USI here and will save that for another post. I hope to provide more of a mix of advanced and beginner topics over the next few weeks.

My Setup

For this post I did not use any of the chips that came with the LaunchPad. For those who are curious, it is possible to plug the MSP430F2013 directly into the socket on the LaunchPad even though I have it in a breadboard for this project; it is also possible to use this code on one of the MSP430s that came with the LaunchPad by changing the include file in the code.


I have the schematic above built up on a breadboard and I am using the FTDI breakout board from Spark Fun shown below (image from Sparkfun website). To connect the FTDI board to the 2013 I used two wires; one connecting the RX line on the FTDI board to the TX(P1.6) line on the 2013, and one to connect the GND of each device together. I do not power the 2013 from the FTDI device's power, but it is still necessary to connect the grounds together. The is because voltage is a measure of the difference in electric field between two points, so without a reference point (GND) the voltages from each source could be completely different relative to the actual ground in the earth. Example, if GND on the FTDI device is at 49.2V and the VCC is at 52.5V (relative to the earths ground), it is still providing a 3.3V supply. Sinec we hook each GND together, it forces both circuits to be referenced to the same point. Hope I explained that well enough to understand.

I powered the 2013 from the LaunchPad, but it could be powered from anything (including the FTDI board, or grapes apparently). To hook the breadboard ot the LaunchPad I connected the RST and TEST pins from the chip to the LaunchPad by taking off the jumpers which connect the emulator side of the board to the target side of the board. Make sure your jumpers are removed and you are connected to the side closest to the USB connector. I also used two wires to connect the GND and VCC from the LaunchPad to power the circuit. I used these jumper wires, but it is also fairly easy to use wire-wrap, or headers soldered to wire, or really anything.

The Code


Apparently the blogger really doesn't like syntax highlighter. It also happened to delete the rest of my post after the code section, which is now lost forever because of the autosave blogger has. I can't describe how frustrated I am. Here goes my attempt to re-write what I had. It was perfectly written. >.<

I will be using Git to display in the blog, so I hope its shown correctly. The code is also posted on Git in case someone can't see the embedded code. I think it's possible to comment on the code too. Hope the link works for everyone.

How it all Works

I will not be discussing each line in detail like I do for my other posts but I will be discussing how the USI can transmit a UART signal.

To start, it turns out that you do not need to have the SPI clock output going when using the USI. This is good because not outputting a clock saves not only power but also should allow you to have an extra I/O pin (I would assume?). The first thing I do in the code is enable the output pin, set the USI to master mode, set it to sent the lowest significant bit first, and enable the USI interrupt. I am sending the LSB first because that is how UART works, and I am enabling the USI interrupt so we can determine if the USI is busy or not when we attempt to send a byte. Notice how I do not implement a function for the USI interrupt, we only will be looking at the interrupt flag bit. For this post we will be using the SMCLK as our clock signal for the USI which is sourced from the DCO, which by default is set at 1.1MHz.

Note: The baud rate is dependent on the clock signal the USI uses; for this case the baud rate will be 1100000 because we use a 1.1MHz signal. If you want to use a standard baud rate you must set your clock to a multiple of that rate and set the correct clock divider correctly. See below for information on receiving non-standard baud rates on your PC.

In order to make the output be a UART signal we need to add a start bit and stop bit. First we add the start bit by shifting the data being sent to the left by one position. We add the stop bit by setting the last few bits to 1. Now our 8 bit value has turned into a 10 bit value which we need to send on the USI. In order to send more than 8 bits we need to set the USI to 16 bit mode otherwise it will not transmit more than 8 bits. We then start the transmission by telling the USI there are 10 bits that need to be sent.

Note: Even though the transmit function uses an unsigned integer (a 16 bit value) for the data, only the first 8 bits will be sent.

In the transmit function the while loop makes sure the USI is not currently busy before we start sending our byte. At first I had this at the end of the transmit function which caused the function to wait until the USI was done before it returned. The reason I changed the location was so that it only had to wait when it was ready to start sending the data. This means that the CPU will only sit around waiting when it really has nothing to do. We could go even further and create a buffer. I might discuss how buffers work in microcomputers in a future post.

The Results

In order to see the data on your PC you need a terminal program. I recommend Realterm (which I mentioned in a previous post) because you can set the baud rate to any value. I used a program which I wrote in C# in order to test this code, so I did not verify that it works with Realterm, but I expect it will work no problem. I will not be distributing my program sine it is a total mess and was written for my specific purpose in mind; I might post it when we go over ADC converters. Below you can see the output waveform which I captured using my logic analyzer.
So, what do you see that is bothersome about this resulting waveform? Why is there such a long delay between the two transmissions?? Everything works, so why do I think something is wrong? Well, we are running at 1100000 baud rate, but we are sending bytes at a rate of 22kHz; since a byte is 8 bits we are transferring data at a rate of 176.6kbps. This is still quite fast, but look at all the dead time between transmissions! We should be able to achieve at least 700kbps with such a simple program as this one.

I looked into the assembly code in the debugger and there seems to be nothing wrong with the code, there is no overhead causing this delay. So what is it? I think it is the USI, it seems to be taking FOREVER to finish and throw and interrupt. Why? Is this normal? I don't know. The 175.6kbps is more than enough for my project which needs to sent 16 bits at a rate of 4.5kHz (72kbps), so I will not be looking into why the USI takes so long. I will leave that up to you. If anyone finds out why there is such a long delay between transmissions, please comment and let me know. It is more than possible (quite probably) that I have a setting wrong in the USI which is causing it to mess up how the interrupt is thrown. I could also change how the USI lets the program know it's busy, but for now I will leave the code the way it is since it does everything I need it to.

Final Thoughts and Updates on the Blog

Sometimes I will write posts which correspond to what I am doing in my own project (like this one) because it is easy for me. Most of my other posts do not really relate to my project (for example, I don't use any LEDs or buttons in my project), I generally write these solely for the community. I just hope that someone out there benefits from posts like this.

If all goes to plan, my next post will present my proposal on a shield standard. Stay tuned if you are interested in seeing this and want to help make a great standard. The post after that will probably go over how to use the ADC on the 2231

As always, if you have any questions feel free to ask; I will do my best to answer every question but sometimes I won't be able to. It is quite time consuming to help people with their code unless they have a specific question or are unsure of only a few lines. If you want help with code, feel free to ask a specific question; if you post your entire program I probably wont be able to help you even if I want to.

I am very happy with the comments you guys have been posting! The back and forth is what I feel makes this blog special. Please don't stop commenting, the more comments, the better (as long as they are not completely off topic :-P). On August 8th a full month will have gone by since I started the blog! By then the blog will have had more than 2000 visits! This is amazing! I hope my blog and the community continue to grow. There is so much potential for the LaunchPad.

As always, best of luck!

12 comments:

  1. I came up with a way to connect the whole LaunchPad to a breadboard:
    http://www.flickr.com/photos/52764485@N07/4864972338/
    I made it skinny so I can still see and get to the LEDs and the buttons. I used female headers on the LaunchPad (on top, a-la Arduino), and male headers on the connecting board, but the opposite would work.
    I'd like to get a manufactured version of this board, but 1) it's my first try at Eagle and 2) the 'T' shape is very wasteful if the service only makes rectangles. I'm thinking of using the 'waste' parts to make simple breadboard power regulators.

    ReplyDelete
  2. GeekDoc,

    Very nice. Two suggestions:

    1) Use Brown, Red, Orange, Yellow, Green, Blue, Purple, Grey, White and Black wires for pin 1 (or 11), 2 (or 12), 3 (or 13), 4 (or 14), 5 (or 15), 6 (or 16), 7 (or 17), 8 (or18), 9 (or 19), and 20 respectively.

    2) Use two rectangular boards with bundled wires between them instead of a single T shape. It is less wasteful and more flexible.

    Anonymous Cow

    ReplyDelete
  3. Anonymous Cow:
    Thanks for looking, and for suggestions. In answer:
    1) I just used the wires I had from an old keyboard cable. I used black for ground (only), red for Vcc (only), then just ran through the remaining for the other 18 pins.
    2) I did think of using two boards linked by wires, but I wanted something that physically joined the LaunchPad and the breadboard. As they are, I can handle them as one unit. I'm hoping to get a few boards made so I can forgo the wires altogether. I may have to glue something along the 'spine' to reinforce them, though. If I end up making them, and have extras, I'll give them away here (to say thanks for the great tutorials!).

    ReplyDelete
  4. @Doc
    Very cool idea! Be careful with torquing the breadboard :-P I've had my fair share of header breaks. Great Idea though, you should be able program another device on your breadboard with that too! Cool!

    I would recommend looking into a home made circuit board if you have the patience, the board is very simple and could be easily made at home at a minuscule cost. There are at least 4 different ways to make homemade PCB's, if you want some advice on that topic, let me know. :-) If you decide to get them made, any idea which company you would use? I need to get boards made in the next week or so, and am having a real hard time deciding which company to use.

    Thank you so much for the support of the blog! As always, if you need any help or have any questions, ask away.

    ReplyDelete
  5. @NJC:

    I don't think I could do traces small enough at home. Even in Eagle, on a 2-layer board with 8mil traces and 8mil spacing, I had to widen the 'neck' to fit 20 traces (they have to cross each other).

    As far as source (if I can figure out Eagle), I'm definitely going to try DorkbotPDX's monthly panel order. Have a look:
    http://www.dorkbotpdx.org/wiki/pcb_order

    Loving the tutorials, BTW! Thanks!

    -Doc

    ReplyDelete
  6. Can anyone give any examples/drivers for using 1-wire communication with msp430?

    I want to connect DS18S20 to Launchpad...

    ReplyDelete
    Replies
    1. http://www.smallbulb.net/2012/238-1-wire-and-msp430

      Delete
  7. I would recommend asking that in the e2e forums on TI's website, there will probably be someone there who can help you better than I. I don't really know anything about the 1-wire interface.

    If you get stuck I would recommend finding some good app notes on how the standard works, then try writing a software 1-wire interface. Maybe look for an example of a software 1-wire interface in another microcomputer (such as PIC or AVR) and port it to the MSP430.

    Sorry I can't be of much help.

    ReplyDelete
  8. About MakePCB.com, there is a whole thread on circuitsonline.net about this boardhouse. It's all in dutch, bottomline is long delivery times (upto 2 months) and poor communication.

    http://www.circuitsonline.net/forum/view/75982

    ReplyDelete
  9. Just reading your great posts. Thank you. I didn't receive my new launchpad yet.
    Is it possible to put a alternating output f.e P1.6 inside the USI while loop and look at that pin with the analyser howmay times it cycles before USI is finished? That way you are sure if it is USI.
    Sorry that I can't test it by myself rightnow.

    I will continue reading. Thanks again.

    ReplyDelete
    Replies
    1. I'm glad that you find my posts helpful. And yes, that is indeed possible! It is also a GREAT way to debug embedded systems. Sometimes the only way to really see what is going on with your code is to hook up a logic analyzer and start toggling pins like crazy. It is a very valid approach.

      Delete