Friday, July 30, 2010

The LaunchPad's Example Project Ripped Open

In this post I present a broken down version of the LaunchPad's example project which only contains the software UART transmit functionality. Note: the code I present can not receive any UART data. The next post will discuss how to use this code with an FTDI breakout board from Spark Fun (which I just received in the mail) for faster communication.

For this post you will need a terminal software. HyperTerminal which comes with Windows will do fine, but I don't like it very much. I use Realterm.

A Little About UART Basics

What is UART? Universal Asynchronous Receiver/Transmitter; UART is a communication protocol. As I already mentioned this post will only implement the transmitter part.

Asynchronous means that the devices which are connected via UART do not need to be synchronized together (aka, share a clock signal). This is very useful and this is the main benefit of using UART compared to other protocols such as SPI or I2C, the downside of this though is that you sacrifice speed when running asynchronously. The UART connection can be either be full duplex, which means the device can transmit and receive at the same time, or half duplex which means the uC can not send and receive as the same time.

The serial port is one implementation of UART and RS-232 was (is) very common. The problem with a serial port on a computer is that the voltages used to transmit the bits are waaaaaay out of the acceptable input range for a typical microcomputer. Why do they do this? They do this to make the transmission more resilient to noise and interference when transmitted over longer distances. If you are hooking your device into something like the image above (from Wikipedia), make sure you have level converters! This is why I like to use USB chips like FTDI's, or the one built into the 5xx. Plus you can achieve faster speeds with those chips than you can with a typical RS-232 interface.

Last bit of theory for UART. UARTs all have some basic properties which can be changed depending on the application. The main property which can be changed is Baud Rate, we will not discuss the others here since it is beyond the scope of this post. Baud Rate directly corresponds to how fast a bite will be transmitted. The larger the baud rate, the faster a byte is sent.

Note: When sending a byte over UART your device needs to send 10 bits total, one start bit and one stop bit in addition to the 8 bit byte.

The LaunchPad and Terminal Software

The LaunchPad has the hardware built into the emulator to provide a very slow UART connection to the PC for debugging purposes. It's maximum baud rate is 9600, which I have verified. The drivers that are (hopefully) automatically installed create a virtual COM port (VCP) which a terminal program or any computer application can access. In my case it is COM9, if you don't know which one it is you can check the device manager. If you want faster communication you have to use a seperate USB device. I typicaly have used FTDI chips and will be using an MSP330F5xx chip in the future.

Sorry for all that rambling, here comes the code.

The Code

Code is also posted here. Sorry for the poor comments. Forgot to clean them up before I posted.



About the Code

I will not be going over how I condensed the example project to just contain the UART since that would require explaining how the example project works. I might do that eventually in a separate blog, but not yet. I also changed a bit of their code because there were a few things I really didn't like, or that caused problems; I tried to keep the code as similar as possible to the example code provided by TI. I would have done this a bit differently. I don't claim though that I wrote this code and I state in the comments that I only modified the code. Please keep this in mind. I also don't ever claim that any of my code will ever be perfect, though I will never post code that I haven't tested and validated.

Analysis of the Code

#define Bitime 104 //9600 Baud, SMCLK=1MHz (1MHz/9600)=104

Bitime is the number of clock ticks per bit, in the original code the clock was divided down by 8, and they used a baud rate of 2400; this code uses a baud rate of 9600. (I think they should have called it BitTime).

BCSCTL1 = CALBC1_1MHZ; // Set range
DCOCTL = CALDCO_1MHZ; // SMCLK = DCO = 1MHz

The two lines above set the internal DCO (Digitally Controlled Oscillator) to [almost] exactly 1MHz. The way this works is that CALBC1_1MHZ and CALDCO_1MHZ point to locations in memory that have been written with calibration information that is device specific. Each type of MSP430 will have different values for calibration. I was skeptical about how exact this could be, but after measuring it with my Logic Analyzer, the frequency was almost exactly 1MHz.

P1SEL |= TXD;
P1DIR |= TXD;

These two lines set the mode of the pin selected for TXD. The important thing to note here is that you can not pick a pin that does not have a Timer terminal function. For example P1.5 also can be set to be TA0.0, so you can change TXD to BIT5 and not change any other code. This is because, like in our PWM example, the Timer automatically changes the value of the TA0.0 pin when a CCR0 event happens.

The loop in main should be pretty self explanatory. Make sure you put the value you want to send into TXByte before calling Transmit().

CCTL0 = OUT;
...
CCTL0 = CCIS0 + OUTMOD0 + CCIE; // Set signal, intial value, enable interrupts
...
CCTL0 &= ~ OUTMOD2; // TX Mark`

The three lines above go together, they all handle how the output pin is set. The OUTMODX determines how the signal changes when a CCR0 event happens. We should already be familiar with OUTMOD7 (Set/Reset). When OUTMOD0 is selected, the output signal will be set to whatever value the OUT bit in CCTL0 is set to. The first line above sets this bit to 1, so the output pin will be changed to 1. When OUTMOD2 is set, whenever a CCR0 event happens the output is cleared (set to 0). You can see this in the timer interrupt function, if the bit to be sent is equal to one, OUTMOD0 is set otherwise OUTMOD2 is set. This is a fancy way of saying set the output to 1 when the bit being sent is 1, and set the output to 0 when the bit being sent is 0.

CCR0 = TAR;

The above command sets the compare register to the current value of the timer (TAR). This allows the compare register to start from the correct reference point when additional bitimes are added to the compare register.

I'm now going to explain how it all works and hopefully you can peace things together without me elaborating on every line.

Transmit() is called, this initializes the timer and compare registers, formats the byte to be sent, then starts the timer. Once the interrupt happens, it is time to change the bit. This is done in the interrupt function, which adds the needed offset to the counter first so that the next bit will transition on time even though there is processing being done within the interrupt function. The bit counter is then decremented once each interrupt; this is done until it reaches 0, which means that it is done transmitting the byte which then disables the interrupt. Meanwhile the Transmit() function is still running and is in a loop waiting for the byte to be done. It knows it is done when the timer interrupt is disabled. This loop makes it so that you can't try to send another byte while one is already being sent. Note that this is very wasteful as far as power goes, and that more care should be taken if you are worried about power consumption.

Seeing our Data on the Computer

Go to your terminal program and set the COM port, set the baud rate to 9600, make sure the display is in HEX and reconnect the terminal software to allow the changed parameters to go into effect. Run your code and you should now see values counting upward being sent to the terminal! Cool!

What Next?

Play around with some baud rates and have some fun. If you want to try and use what you've learned so far from previous posts, use the transmit function with a push button interrupt. It's important to see how code pieces together to make cool projects. Use the push button code I mentioned in a previous blog (or a version with debouncing, but this time also transmit a some value (a counter maybe) every button press.

Next post I will be going over how to achieve higher data speeds using FTDI's chip, and the problems I ran into using this code while trying to send data at 115200 baud (the code breaks when bitime is lower then about 50).

As always, comment away. Having any problems? Any cool code modifications you'd like to share? Also feel free to start threads on any of the websites I mentioned in my previous post, I will be watching them.

Have fun!

-NJC

29 comments:

  1. Thank you! I have been trying to do this as my first step on the launchpad using the MSP430G2211. Every time I tried to tear apart the TI demo code to just get the timer_A UART, I seemed to hit a wall. Your blog is exactly what the beginner hobby community for the MSP430 needs. Keep up the good work!

    Question:
    How would you go about adding receive to the chip?

    ReplyDelete
  2. Thank you! Adding receive to the chip will be a bit difficult, especially if you want full duplex communication. I'll try to quickly list what I would do to add receiving to the chip.

    The easiest way to do it would be to set up an external trigger on the pin you will be receiving the data on. Set the timer to interrupt half a baud period later, then check to make sure the start bit is correct. From this point onward decrement the bit counter and create interrupts every baud cycle like we did for the transmitter. The only difference is that when the timer interrupts you have to read the pin in instead of setting the transmit level. Make sure that you also validate the stop bit on the last interrupt; if it's not correct, the received byte is not valid.

    Things to watch out for, try to limit the number of clock cycles your code takes in the interrupt routine since this will put a limit on how small your bit period can be. You do not want an interrupt taking place while you haven't finished processing your last one! Also make sure that you do not try to send anything while receiving the data because of timing issues.

    If you want to make it full duplex this become complicated, you would have to use the second compare register. Also you would have to make sure that each direction's interrupt plays nice with each other and do not screw up timing and cause missed interrupts. If you want to do full duplex I would seriously recommend using ASM because the timing needs to be so precise. Hope that made sense, feel free to ask me about any part if I was not clear enough.

    Best of luck! Let me know how it works out for you! Glad I can help. :-)

    ReplyDelete
  3. Great!!!! It´s me again(the argentinian guy,Juan Ignacio), I change the G2211 for an F2012, hook up a potentiometer to one of the adc10 input and in less than five minutes I was sending data to the computer. THANKS A LOT!!! I was wondering If you think that could be posible to do something like the Arduinoscope (Arduino+Proccesing osciloscope) with the launchpad. it won´t be as good as a professional but it could be handy,and cheap...

    ReplyDelete
  4. I have been trying to write this code for 2 days with some success, today I switched browsers and there is the full code. In my Firefox the code is invisable!!! I am using IE now. Thanks for the code, now to give it a go

    ReplyDelete
  5. Juan, glad you got it working quickly! It is 100% possible to make a simple scope from the LaunchPad, which I actually will be kind of showing you all how to do when we get the ADC up and running. The hardest part is the interface software. I already have something small written up for my own project using the 2013, but it's too ugly of a program to share, and is very specific to my own project.

    @Anonymous #3
    Oh no! Sorry! No one should ever have to use IE :-P. I just checked on my computer and Firefox seems to see the code fine. I use Chrome though as my main browser. From now on I will also supply links to a place which had the code hosted so everyone can see for sure. I'll be updating this post in the next few minutes.

    ReplyDelete
  6. hey, NJC...
    i am also working on launch pad since last few days. And i am also done with the transmission using timer UART quite a similar modified code as you have mentioned but i am screwed up with receiving section.
    suggest me something... should i post my code if you can help me out.....?

    ReplyDelete
  7. In my comment above I mentioned how I would go about adding a receive section. I might start writing up some code to do this after I finish my next few blogs I have planed out since there seems to be a pretty large desire to have this done.

    I would be happy to help with your code, but please post in one of the three MSP430 forums I keep mentioning.

    http://43oh.com/forum
    http://e2e.ti.com/support/microcontrollers/msp43016-bit_ultra-low_power_mcus/default.aspx
    http://groups.google.com/group/ti-launchpad

    I check these three forums every few days and do my best to help out where I can.

    ReplyDelete
  8. hey NJC,

    i have posted the code with details on

    http://43oh.com/forum

    kindly have a look and help me out.

    regards
    QWERT

    ReplyDelete
  9. What is uartUpdateTimer for?

    The docstring indicates that it is used to wait until all bits (10 per char) have been sent.

    However it seems to be used very strangely in the loop. As far as I understand, it has no functionality there and can be easily removed without changing the behaviour.

    ReplyDelete
  10. Ah, sorry, I should have written in a comment on that one line of code. The uartUpdateTimer determines how often a byte is sent. It has nothing to do with the bit counter used for sending the byte.

    if ((--uartUpdateTimer == 0))

    This line of code not only checks the value and if it is 0, it will send a byte. The tricky part is that it also subtracts one from uartUpdateTimer while doing that.

    The syntax, --uartUpdateTimer, is a somewhat tricky part of c. -- before a variable ,will decrement the value by 1 after the value is read and not before.

    See http://gd.tuwien.ac.at/languages/c/programming-bbrown/c_015.htm if you are stuck.

    Hope that answers your question.

    ReplyDelete
  11. Ah okay, now I get it, thanks!


    But the whole trick sounds like guessing when the transmission is ready. I would have preferred a flag which is set e.g. in the interrupt, as the time spent in the while loop could be different depending on the assembly the compiler generates, right?

    ReplyDelete
  12. This part of the code does not have anything to do with waiting for the transmission to be ready. This can be taken out completely if one wants. One can actually call Transmit back-to-back with no delay.

    The waiting for the transmission to finish is done by checking a flag in this line:

    while ( CCTL0 & CCIE ); // Wait for TX completion

    It's possible to put this before the timer is started for example (still in the Transmit function), but I have left it here for this example.

    Hope that clears things up. Viel Glück :-)

    ReplyDelete
  13. Hi NJC,

    I'm doing a project with your Tx+Rx code. I started off with the most recent code you put up, but I'm sending out a series of 11 bytes, so I looked up your Tx code to see how you sent multiple in a row. I'm sending out at a baud rate of 38400 instead of 9600; I've modified the code so that Bit_time is 26 (1 MHz/38400) and that Bit_time_5 is 13. Do I need to have the uartUpdateTimer around each byte, or can I just set TXByte and Transmit() 11 times consecutively? And if I do need to include uartUpdateTimer around each byte that I'm sending, is 10 still the magic number, or will that have to change?

    my email is revathimurthy007@gmail.com -- I'm using your code to interface with an RFID reader running at 38400 baud, and I'm unable to recieve data back from the RFID reader (which I'm thinking is due to the way I'm sending commands to it)

    I appreciate your help a lot! I don't have many mentors on this project, and I could really use some help. Thanks.

    -Revathi

    ReplyDelete
  14. I decided to respond here so everyone can benefit from your question. Good questions btw.

    A quick answer: Yes, you can transmit 11 times consecutively. The transmit function will not return until it is done transmitting, the delay is inefficient and lowers the overall throughput for the sake of simplicity. uartUpdateTimer is specific to the Example Project from TI, you do not need it at all, I won't be including it in any of my own code snippets.

    If you are running into problems, I think it might be caused by the speed at which you are running the UART. There is a lower limit to what you can set the Bit_time to, and I have not determined that. My guess is that things will stop working at a Bit_time of 25-35 but I am not sure. This is because if the time is too short, the interrupt will not finish execution before time is up. Here is my recommendation: set your DCO to 4MHz, and the baud rate will multiple by 4 (compared to a DCO of 1MHz), everything will run 4 times as fast. Just keep in mind, that any transmission is stopped the second a receive event is start even if the transmission is not finished.

    If you have the means to, I would also recommend testing the transmitter and receiver at the correct speed with a terminal program before you hook it up to the RFID.

    Hope that answered your question. Feel free to ask any questions about my code here or on the forums. I check the 43oh.com/forum the most. I'm glad to help. :-)

    ReplyDelete
  15. Hi NJC,

    I hooked up my MSP430F2013 to an oscilloscope to see what was going out and coming in; I've verified that I'm sending out the right command at the 9600 baud rate (I just reconfigured the baud rate for the RFID reader instead).

    However, I'm still not getting any response from the Skyetek M4 reader, which uses a UART/TTL interface.

    I think it may be due to the fact that they ask to wait at least 40 ms before the host seeks a response from the reader. To deal with that scenario, I decided to disable to RXD interrupts until just after transmitting the 11 bytes in sequence, and to have a for loop that'd run for approx 40 ms. Still no response, though--what could I be doing wrong? I also tried it with the RXD still being enabled at the beginning as usual, and just having the for loop. I've verified that the logic low and high voltages are same for the MCU + the RFID reader, and to measure the baud rate, I just ran the lines TXByte = 0xFF; Transmit(); in a while(1) loop and measured the time width of the square wave that I'd see on the oscilloscope--it would correspond to the time taken to send 9 bits, since the stop bit is just after the transition from low-high.

    Am I calculating the baud rate correctly? I calculated that I'd need the width of the 9bit segment to be 940 us, and modified Bit_time till I measured 940 us as the width on my oscilloscope.

    ReplyDelete
  16. Thanks for making this available! I just got it working on my setup. Been doing C since I learned it in college in 1990 and have been playing with AVR for three years now... but the MSP430 stuff still has a learning curve, so I am glad someone is forging the trail for me!! :)

    A few comments in case they help or are of interest. Please don't take this like me being a pill. Just trying to help out. :)

    Wanted to mention UARTs are hardware devices that implement a protocol like RS-232.

    Also, re: one of your comments. In C, --v decrements variable v before it is used, while v-- decrements v after it is used.

    Anyway hope this helps and thanks again. Continuing to pour through your great blog!! --Michael

    ReplyDelete
  17. @EOTS
    I moved your question to the 43oh forums because my response was too large. Here is the link, see my answer there; I hope it helps. :-)

    http://www.43oh.com/forum/viewtopic.php?f=8&t=70&start=0

    @shimniok
    Thanks for the correction! I wish I could modify my comment somehow. It's good to have some experts double checking the information I provide, even I make mistakes :-P and quite often at that.

    ReplyDelete
  18. Hi NJC,

    I just wanted to let you know that I figured out the problem -- it seems that any time the wires were slightly shaken on the RFID reader, the reader would reset to its default baud value -- 38400. Instead of trying to change the reader's baud value, I jsut took your advice, used an 8MHz clock instead of the 1MHz one, and I was able to get a signal back on the oscilloscope. Now I'm just tweaking the bit times for Rxd so that I get the bytestream returned that I expect (and see on the oscilloscope, but not in my final receiving buffer). Thanks again so much for your advice on adjusting the clock rate!

    ReplyDelete
  19. Glad I could help! :-) If you have any more questions feel free to ask in the 43oh forums. Good luck with the rest of your project.

    ReplyDelete
  20. Hi NJC

    The following lines in the transmit function :

    CCTL0 |= OUTMOD2; // TX Space
    if (TXByte & 0x01)
    CCTL0 &= ~ OUTMOD2; // TX Mark

    puzzle me.

    It seems there is always a "TX space glitch" (few clock cycles long), independently of the TXByte bit0 setting. Even if this code works, I wonder if it is not a small design error ?

    To me, a cleaner approach would be

    if (TXByte & 0x01)
    CCTL0 &= ~ OUTMOD2; // TX Mark
    else
    CCTL0 |= OUTMOD2; // TX Space

    What do you think, please ?

    ReplyDelete
  21. Nice catch. I didn't notice that when I was going over their code. It would be interesting to see this on a logic analyzer. The reason I think TI wrote the code this way, is because the if...else might take more asm instructions to execute.

    In the end, while it might not be good practice to have unintended spikes in a data stream signal, this should not effect any UART devices. The way the spec works (as far as I understand) is that the receiver does not look at the pin while the signal is in transition between bits.

    Using the if...else might be a better option as long as the performance does not deteriorate at all.

    Thanks for the post. :-)

    ReplyDelete
  22. I've been going through these posts in more detail now that I have some time. I noticed that on line 69 you set the CCIS0 bit in CCTL0; I've been reading the Family Guide and device sheet, and can't for the life of me figure out what this bit does. It almost seems that it doesn't do anything except in capture mode, when this is being run in compare mode. Any thoughts?

    ReplyDelete
  23. Very interesting. It was present in the original example code from TI, your right though; it seems to do nothing when in compare mode. When in compare mode, the family user guide states:

    "The input signal CCI is latched into SCCI."

    I would recommend asking this question on the e2e.ti.com forums, to be honest I'm not 100% sure why it's there. Have you tried removing it from the code and seeing if everything still works?

    ReplyDelete
  24. Hi
    Thank you very much for these tutorials.
    They have helped me tremendously in understanding how to code for the launchpad.
    I'm used to working with arduinos so the transition has been quite difficult as I have little or no experience with C.
    Using this code and code that I stole from GuShH I managed to splice it together to write a small application that reads analog values and sends it to processing.
    Again, Thanks :-D

    ReplyDelete
  25. NCJ,

    I have tried to blend this TX example with the first GPIO (P1.3 LED example) found at http://mspsci.blogspot.com/2010/08/tutorial-10-b-interrupt-examples.html and have not been successful.

    I tried putting in the button interrupt in to call the transmit() function but it seems to keep getting stuck at

    while ( CCTL0 & CCIE ); // Wait for TX completion

    and never actually sending any information over serial.


    my quick implementation can be found at.
    http://pastebin.com/uMqG4C9D

    ReplyDelete
  26. Bryce - I think the problem is twofold. The first thing is that you are not debouncing your button press (if indeed you are using a button to trigger the interrupt on the input). Please read my post on buttons below.

    http://www.msp430launchpad.com/2010/07/using-buttons-and-creating-new-project.html

    Because the physical button will "bounce", the Transmit() function is called again before the transmission is finished. The UART transmission is then messed up because the Transmit function changes some important variables which are used to send out the byte. Please see this post about transmitting data.

    http://www.blogger.com/post-edit.g?blogID=2168992611451428662&postID=2065431407738314247

    I hope that helps you understand your problem a bit more. If you are still having trouble, check out the 43oh.com/forums.

    ReplyDelete
  27. Hi NJC,

    Thank you for these amazing tutorials.
    I run this example on my launchpad with g2231 and it works great. Yet, when I change the Tx output pin from P1.1 to P1.5 it does not work. According to your post and g2231 worksheet it should work?

    Thank you.

    ReplyDelete
  28. How do I do the same thing on Energia ? ?

    ReplyDelete

Note: Only a member of this blog may post a comment.