Search Microcontrollers

Thursday, November 1, 2012

MSP430G2 - ADC / 2 - sampling an audio signal

I thought it would have been fun to sample an audio signal using the launchpad.
Before starting : The MSP430G2 is not designed with audio sampling in mind, so if you want to develop some good digital recorder or audio sampling device, you should probably look for more suitable devices.
... still, it can be done.

One issue is the limited amount of RAM in the mcu, which would prevent us to buffer and process the audio data internally (i.e. with an FFT).
The only hope we have is to get the data from the ADC and send it as fast as possible to the serial port, then use it in the pc itself.
You can achieve the same task, much easily and better using the internal sound card of your pc, but that would not be fun at all.

First thing I prepared a stereo cable to get the audio signal out of my computers headphone connection.
I used an old internal CD cable to which I soldered a stereo jack.


Then I checked I could get signals from both channels, using my scope (yup, to play with audio signals, the scope is quite handy).


Since we are going to feed this signal to our ADC converter, we need to ensure that its values are within the limits defined by Vref- and Vref+, meaning the two reference voltages used by the converter to define the minimum and maximum values to be sampled.
Most ADCs, including the MSP430G2 ADC10, can sample only positive signals (Vref- >+0) with a maximum value normally equal to their Vcc (3.3V for the launchpad).

Audio signals are obviously AC signals and typically they have their offset at 0V (you need to check that, it was the case for me, check the image above).
[The offset voltage is the voltage you obtain when you have the jack connected and no sound is played. When sound is played the offset can be eyeballed as the median voltage level]
This means that typically half of your audio signal has negative values, which would not work with the ADC.
We need to add a positive offset in a way that the incoming signal is never negative.

The other important thing is the amplitude of the signal (which you change with the volume settings).
I saw that most of the audio coming out from a youtube video had an amplitude of about 800mV, but pumping up the volume and playing some loud music showed a higher amplitude, reaching about 2V.

The ADC10 can use different Vref values, to make things easier we will use Vref- = 0V (GND) and we need to chose from 1.5V, 2.5V, Vcc (3.3V) for Vref+.

The signal amplitude we can take, assuming we can offset it exactly in the middle of our range is equal to Vref+ - Vref- , so having Vref- = 0V, the amplitude is equal to Vref+.
I would go for 2.5V because it is a bit higher than input signal amplitude, but not too much.

As a general rule, you normally want to amplify (or attenuate) the signal to make sure it fits nicely in your ADC band.

The reason why you want to  match your reference as close as possible is that, when sampling digitally, you divide your reference in a finite number of levels (1024 for a 10 bit ADC).
If the incoming signal has an amplitude which is covering just a small portion of your sampling band, then you are wasting sampling resolution.

Audio signal are pretty much symmetric in respect of their offset, so it's in general a good idea to move the offset in the middle of the sampling range, in our case to 2.5 / 2 = 1.25 V.
The typical way to achieve this is via a simple circuit based on an op-amp, but for this example (remember, this is an experiment, don't design devices in this way, it's probably not  a good idea!) I decided I wanted something simpler.

I just needed something capable to deliver a clean 1.25V and stick it in series with my signal.
That sounds like a fully charged rechargeable AA battery to me :)


A battery holder and a couple of crocodile contacts helped to put the battery in series with the signal before entering the scope probe (easier than dealing with op-amps, right?).
I checked with the scope setting the cursors to my Vref values (0 and 2.5V), this is what I obtained :


Eureka! This looks definitely a signal that could be handled by the ADC10.

Let the fun begin

It's time to start preparing our application.
The idea is to sample both channels (stereo!!) and eventually transfer the sampled data via UART.
The msp4302553 has 8 external Analog inputs mapped on port P1 (P1.0 to P1.7), we need to select two suitable channels in a way that they do not overlap with other functions we might need.
I will use the serial port, most likely UART, so I will steer clear from the pins used by that functionality (even if for this test I am planning to use the onboard FTDI chip that sends the uart data to the usb connection).
The 2553 datasheet has it all : our A3 / A4 channels (P1.3 , P1.4) look like good candidates.

Also in the datasheet we find  that there is no real need to set the multiplex values (P1SEL, P1SEL2) or the P1DIR register when using pins as ADC channels, because the ADC10 will set them for us (everybody say with me : "Thanks mister ADC10!") using the  ADC10AE0 register.


The ADC10 can do some interesting things when sampling multiple channels :
It can automatically sample a sequence of channels (that is actually quite cool for our application).

When sampling a sequence of channels, we need to specify the highest channel  we want to sample and the mcu will start a loop in which it will sample all the channels down to A0,
from the user guide :
"A sequence of channels is sampled and converted once. The sequence begins with the channel selected by INCHx and decrements to channel A0. Each ADC result is written to ADC10MEM. The sequence stops
after conversion of channel A0."

Fortunately, despite what stated in the user guide, it seems it is possible to set how many channels must be sampled, the DTC (a sort of dma controller, dedicated to the ADC10) can transfer the values to a defined memory area.


Time to write some code.


#include <msp430g2553.h>

unsigned int sampling;
unsigned int buffer[2];

void clockConfig()
{
 // configure the CPU clock (MCLK)
 // to run from DCO @ 16MHz and SMCLK = DCO / 4
 BCSCTL1 = CALBC1_16MHZ; // Set DCO
 DCOCTL = CALDCO_16MHZ;
 BCSCTL2= DIVS_2 + DIVM_0; // divider=4 for SMCLK and 1 for MCLK
}

void adcConfig()
{

  // ADC10SSEL_0 :  ADC10OSC
  // ADC10DIV_0 : ADC10 Clock Divider Select 0. Roughly 5MHz
  // INCH_4 : highest channel we are going to sample
  // CONSEQ_1 :  Sequence of channels
  ADC10CTL1 = ADC10SSEL_0 + ADC10DIV_0 + INCH_4 +  CONSEQ_1; //
  // SREF_1 : VR+ = VREF+ and VR- = AVSS
  // ADC10SHT_0 : Sample & Hold = 4 x ADC10CLKs
  // REF2_5V : ADC10 Ref 0:1.5V / 1:2.5V;
  ADC10CTL0 =  SREF_1 + REF2_5V + REFON + ADC10SHT_0 + MSC + ADC10ON + ADC10IE;
  ADC10AE0 |= BIT3 + BIT4;  // adc option for channels 3 and 4
  ADC10DTC1 = 0x02; // number of channels to be sampled
  __delay_cycles(1000);  // Wait for ADC Ref to settle
}

// temporary interrupt routine to check that the ADC sequence is complete
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
  sampling = 0;
}

void main(void)
{
 WDTCTL = WDTPW + WDTHOLD;
 clockConfig();
 adcConfig();
 __bis_SR_register(GIE);  // Enable interrupts
 while (1)
 {
  ADC10CTL0 &= ~ENC;
  while (ADC10CTL1 & BUSY);               // Wait if ADC10 core is active
  sampling = 1;
  ADC10SA = (unsigned int)&buffer;        // Data buffer start
  ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
  while(sampling>0); // wait until the sampling sequence is complete
 }
}


At this point you should refer to the previous post in which I introduced the ADC10, if you did not read it before.

Basically I opted to use the internal ADC oscillator at its maximum frequency.
For Vref I used VRef+ = internal reference and VRef- = GND
The internal reference is configured at 2.5V (default is 1.5V) and the sample & hold time is the shortest possible (4 cycle of ADC10CLK).
The MSC bit is set, that tells the ADC to keep converting data once the encoding request is triggered, then DTC controller will post it to the buffer starting at the address of the buffer variable (ADC10SA =(unsigned int)&buffer; )
It seems that the buffer start address must be set each time before starting a new conversion.

There are four operating modes selected with the CONSEQ constants :

#define CONSEQ_0               (0*2u)         /* Single channel single conversion */
#define CONSEQ_1               (1*2u)         /* Sequence of channels */
#define CONSEQ_2               (2*2u)         /* Repeat single channel */
#define CONSEQ_3               (3*2u)         /* Repeat sequence of channels */

I chose to sample a single sequence of channels, the DTC will drop the data in my two 16 bit integer buffer.

I also use a sampling variable to check if the sequence is complete or not, this is a simple temporary solution, in future implementations we might simply use the interrupt routine to send the data via uart.

That's about it for today, I debugged the program and -surprise surprise- my buffer is actually filled with values that vary at each loop, indicating that the DTC is sending it samples.
I also notice that with no audio incoming my channels they are at values around 510, which matches pretty closely my ideal offset (1024/2 = 512).

I might develop this experiment further and actually send some data to the pc... but that's going to be another post.  

Another thing to look into is to test if we can get away without the interrupt and just poll the ADC BUSY bit, it might actually be interesting to maximize the data transfer to the pc.


Sunday, October 28, 2012

MSP430G2 - the ADC10 peripheral /1

In the previous post I illustrated a few basic concepts about Analog to Digital Converters.
Having them integrated into MCUs makes it really easier to use them, we are going to play a bit with the MSP430G2553 ADC10 converter.

The two main control registers to drive the ADC10 are ADC10CTL0 and ADC10CTL1.
Using them we can set the reference voltages, which channel to be sampled, we can turn on and off the reference voltage and the peripheral itself.

The MSP430G2 family is designed to be a low power solution, this is why the peripherals and features that may potentially use some energy are turned off by default.

Finally the sampled result can be easily recovered from the ADC10MEM register :
int mySensor = ADC10MEM;

Sample & Hold and conversion

During the sampling process, I explained in the previous post, a reference voltage is V(t) is compared with the voltage coming from the signal.
If the signal fluctuates in this process, it might be impossible to compare it with the reference.
For this reason a "sample and hold" functionality is implemented, you can see some details here.

This means that the value of the signal to be sampled is maintained constant during the conversion.

    from wikipedia

This time is defined by the SHS (Sample and Hold Source) clock which, in the MSP430 can be one of the following :


00   = ADC10SC  (ADC10 internal oscillator, about 5MHz and can be  divided from 1 to 8)
01   =  Timer_A.OUT1
10   = Timer_A.OUT0
11   = Timer_A.OUT2


In this way we basically define the maximum sampling rate which is the result of the sampling time, being the sum of the Sample and Hold phase plus the conversion phase.

from the TI MSP430 User Guide

The S&H phase is software selectable  (in ADC10CTL0) in 4,8,16 or 64 ADC10CLK cycles, a higher value would be used to reduce high frequency noise.
The conversion part is then executed in 13 ADC10CLK cycles (thanks to a series of approximations performed internally).

Playing a bit with numbers, we can verify that, at a minimum we need 4 + 13 = 17 cycles.
Assuming the ADC10CLK is the 5MHz (note : we should not expect it to be EXACTLY 5MHz, it's a digital oscillator and it might have some tolerance) Internal source

1 cycle = 1 / 5.000.000 s = 200ns

The sampling time is then 17 * 200ns = 3.5us
The sampling time is 1 / 3.5us = roughly 294 Ksps (Kilo Samples Per Second)
Data then needs about 1 or 2 MCLK cycles to be made available in the ADC10MEM register (it uses an internal DMA), so the actual rate is slightly lower and it depends on the CPU frequency.

The data sheet claims a sampling rate exceeding 200 Ksps, which is in line with what we calculated and I believe is pretty good for a 16MHz mcu.

Reference Voltages

The ADC will return 0 if the signal is lower than or equal to the Vref- voltage and will return 1023 if it is higher than or equal to Vref+.

The ADC10 has different options when it comes to Reference voltages, it can use internal precisely  generated voltages (1.5V or 2.5V) , it can use Vcc as Vref+ and Vss (Ground) as Vref- or it can get them from two external pins.
All these parameters are controlled via the ADC10CTL0 register.

In the user guide we find :


SREFx Bits 15-13 Select reference.
SREF_0 000 VR+ = VCC and VR- = VSS
SREF_1 001 VR+ = VREF+ and VR- = VSS
SREF_2 010 VR+ = VeREF+ and VR- = VSS. Devices with VeREF+ only.
SREF_3 011 VR+ = Buffered VeREF+ and VR- = VSS. Devices with VeREF+ pin only.
SREF_4 100 VR+ = VCC and VR- = VREF-/ VeREF-. Devices with VeREF- pin only.
SREF_5 101 VR+ = VREF+ and VR- = VREF-/ VeREF-. Devices with VeREF+/- pins only.
SREF_6 110 VR+ = VeREF+ and VR- = VREF-/ VeREF-. Devices with VeREF+/- pins only.
SREF_7 111 VR+ = Buffered VeREF+ and VR- = VREF-/ VeREF-. Devices with VeREF+/- pins only.


The constants SREF_0 to SREF_7 are conveniently defined in the standard .h file.
In the same file we also find the other constants needed to enable the internal reference and to set it to 1.5 or 2.5 V


REF2_5V  Reference-generator voltage. REFON must also be set.
0 1.5 V
1 2.5 V
REFON Reference generator on
0 Reference off
1 Reference on


There anyways restrictions on the voltages that can be applied to the analog input (should be between 0 and Vcc) and to the eventual external references :
Vref- (specifically for the 2553, check the DS for other devices) should be between 0 and 1.2V
Vref+ (same considerations) should be between 1.4V and Vcc

This said, if you are planning to sample a higher voltage (I tried with the mains ; 250V AC) you need to use a voltage divider (with offset regulation for AC signals) and to make sure the output of your divider is always in the expected range (check with a scope if you can).

If you don't need to sample with a high frequency and you are using an internal reference, what you may want to do is to turn on and off the internal Vref to reduce power consumption.
There is also an option to burst" it so it turns off and on as needed by the ADC, however you should be aware of the fact that the internal Vref  takes a small amount of time to settle, and the sampling can happen only when it is stable.
tref (the time Vref internal needs to settle at 99.9% of its value) is 30us.

Finally, the peripheral can fire an interrupt once the conversion is done, so it's common to start the process, enter in Low Power Mode and then wake up receiving the interrupt, get the value from ADC10MEM, do whatever needed with it and start the process again.

In the next post I will present some sample code using the ADC.


Analog to Digital Converters - 1

Analog to Digital converters are, in my opinion, one of the most fun peripheral to deal with when working with Microcontrollers.
Why?
Let's face it : most of the measurements you want to do in the real world involve an analog reading, normally a voltage or a resistance returned by some kind of sensor.

Like most of the mcus, the MSP430G2 has an ADC built in (warning : the ADC10 is not included in all the devices of the family, check the datasheet or the specs for the specific device you are dealing with).
I am going to use the MSP430G2553 supplied with the launchpad and that one definitely has an ADC10 onboard.

First of all, it's called ADC10 because it has 10 bits of resolution.
10 Bits is the typical resolution you can find in "cheap"devices, more advanced ones (such as the C2000 or Cortex M3) may have a 12bit adc instead.

What's the difference?
It's about resolution : a 12 bit device, having 2 bits more, achieves a four (2^2) times higher resolution than a 10 bit one.
It's a big difference, however in many (most?) cases it does not really matter.

Let's imagine you are sampling a temperature from a sensor such as the LM35DZ (cheap and common sensor).
This sensor increases it's output by 10mV for each Centigrade, at 0C it will provide 0V (which makes it really simple to use it with mcus).
However this sensor does not provide high accuracy since it's best accuracy is about +/- 0.5C, which can be translated into +/- 5mV.

A 10 bit adc with range between 0 and 3.3V has a resolution of 3.3 / 1024 V/bit =  3mV/bit which is already higher than the accuracy of the sensor itself, therefore a higher adc resolution would be useless.
However this setup would allow us to measure temperatures between 0 and 33C, which it might be ok for some applications, but not enough for others.
The LM35 sensor itself can read temperatures from -55C to 150C (depending of the exact model, check the datasheet) but this would generate voltages from -5.5V up to 15V.
If you apply such ranges to a 3.3V tolerant ADC, you are likely to burn it, so most people normally regard this a as a bad idea.
You can offset and "scale" the signal using a voltage divider (with 3 resistors in case you need to add the offset), but at that point, should you still aim for +/- 0.5C resolution, the 10 bits are not enough anymore.

The example with the LM35 was useful to add some context, but the issue is generic.
Imagine we have a sensor that measures a quantity X and outputs linearly a voltage V(X) = V0+kX.
The constant k is the voltage gain of the sensor, it is a constant if the sensor output is linear.
The range we want to measure is [Xmin,Xmax], which gives us DX = Xmax-Xmin.
Assuming we can exactly map Xmin to the lower reference of the ADC (i.e. 0V) and Xmax to the higher reference (i.e. 3.3V), and we know we want to obtain a specific resolution R, then we can calculate how many bits (minimum) we need to sample the signal.

Say DX = 100X and the needed resolution R is 0.01X, this means that the ADC must have 100X/0.01X = 10.000 "steps".
To get the minimum number of bits you can apply a log2(10.000) or simply compare with the resolution of finite number of bits :
8 bits -> 256
10 bits -> 1.024
12 bits -> 4.096
14 bits -> 16.384
...

in our case we would need a 14 bit ADC, not an easy requirement as very few of the mcu integrated ADCs can get that precision.
At the same time, when sampling with such accuracy, we might have additional issues such as the stability of the reference voltages, the accuracy of the resistors used in an eventual divider, electronic noise etc.
When higher precision and speed must be achieved, the common solution is to use dedicated ADC devices.

If now you feel frustrated because your mcu only supports a 10 bit sampling device, just think this : precision instruments such as Digital Oscilloscopes use 8 bit ADCs (but they are normally extremely fast and equipped with high precision input circuits).
How do they give all that flexibility and precision with 8 bit only?
They allow to set different scales by altering the offset of the signal and the parameters of the input voltage divider.

The other important parameter is the sampling frequency.
Why achieving high frequency and high resolution at the same time can be difficult?
That's related to the way the sampling happens, which I will try to explain in a simple case.
Digital devices only understand two states : on and off, so how do they convert a voltage to an on or off state?
They can compare the voltage with a reference one and say : if the reference is higher, then set to off, else set to on.
Now if the reference voltage V(t) varies starting from V- (lower reference) and linearly climbs to V+ (higher reference) and at the same time we start a timer that counts the number of cpu cycles, at a given point in time, the signal will cross the reference and the comparison will return "on".
At that point the timer count t gives us a measurement of the voltage used in the comparison V(t).
Practically, some more advanced techniques are used, but that's  pretty much the basic concept.
You understand then that the timer speed is affecting the resolution + sampling rate combination.
If we have a 10 bit resolution, the timer must be able to count up to 1024 when V(t) = V+.
Imagine the timer uses the same clock frequency as the CPU being 16MHz -> the maximum sampling rate would be 16/1024 MHz = 15KHz.
As I previously stated, some more advanced techniques (series of approximations etc) are used, allowing the adcs to achieve better performances, but you now probably understand the relation between cpu speed, sampling rate and resolution.

In the next post I am going to experiment with the ADC10 device of the MSP430G2553


Tuesday, October 16, 2012

C2000 launchpad - code skeleton

Maybe I am just lazy, maybe laziness is a bit "the geek way".

Each time I start a new project I like to copy from a skeleton, some kind of template instead of typing everything from scratch.
The real reason, I think, is that in most of the cases I cannot recall how to start and with the C2000 Launchpad I always forget something, so I created a file with all the steps and code snippets.

I am posting it here, just in case it might turn useful for others.

First, in CCS start a new project (FIle, new Project, CCS Project )


Then  set the basic project properties (see the highlighted parts)


Some tweaks are then needed in the project properties after the project is created, right click the project name in the project explorer, select properties and add the laiunchpad specific location for the include files.
You may need to adjust that path according to your ControlSuite install dir


Finally add the library


You are now good to go, open your main.c file and copy & paste the following skeleton

Update : Make sure you select the correct linker command file, by mistake I selected 28027 instead of F28027 and spent some time to figure out why the program would not fit in memory according to the linker.



//-------------------------------------------------------

#include <stdio.h>
#include <file.h>

#include "DSP28x_Project.h"     // DSP28x Headerfile

#include "f2802x_common/include/pll.h"
#include "f2802x_common/include/clk.h"
#include "f2802x_common/include/wdog.h"

#include "f2802x_common/include/flash.h"
#include "f2802x_common/include/gpio.h"
#include "f2802x_common/include/pie.h"
#include "f2802x_common/include/adc.h"
#include "f2802x_common/include/sci.h"
#include "f2802x_common/include/sci_io.h"


extern void DSP28x_usDelay(Uint32 Count);

// you probably need these
CPU_Handle myCpu;
PLL_Handle myPll;
WDOG_Handle myWDog;
CLK_Handle myClk;

// these are optional
ADC_Handle myAdc;
FLASH_Handle myFlash;
GPIO_Handle myGpio;
PIE_Handle myPie;
SCI_Handle mySci;




void setup_handles()
{

    myClk = CLK_init((void *)CLK_BASE_ADDR, sizeof(CLK_Obj));
    myPll = PLL_init((void *)PLL_BASE_ADDR, sizeof(PLL_Obj));
    myWDog = WDOG_init((void *)WDOG_BASE_ADDR, sizeof(WDOG_Obj));
    myCpu = CPU_init((void *)NULL, sizeof(CPU_Obj));

    myFlash = FLASH_init((void *)FLASH_BASE_ADDR, sizeof(FLASH_Obj));
    myGpio = GPIO_init((void *)GPIO_BASE_ADDR, sizeof(GPIO_Obj));
    myPie = PIE_init((void *)PIE_BASE_ADDR, sizeof(PIE_Obj));
    mySci = SCI_init((void *)SCIA_BASE_ADDR, sizeof(SCI_Obj));
    myAdc = ADC_init((void *)ADC_BASE_ADDR, sizeof(ADC_Obj));


}

void init_system()
{
  WDOG_disable(myWDog);
  (*Device_cal)();
  CLK_setOscSrc(myClk, CLK_OscSrc_Internal);
  PLL_setup(myPll, PLL_Multiplier_12, PLL_DivideSelect_ClkIn_by_2);

  PIE_disable(myPie);
  PIE_disableAllInts(myPie);
  CPU_disableGlobalInts(myCpu);
  CPU_clearIntFlags(myCpu);
#ifdef _FLASH
    memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
#endif
}

void main()
{
  setup_handles();
  init_system();
}
//---------------------------------------------

Note that this is just a skeleton, you may need to remove parts you may not need such as include files, handles etc (unless the linker is smart enough to get rid of them, which I think it's something we might expect).

Also, you will need to add specific peripheral initialization according to your needs and... your program.






Saturday, October 13, 2012

C2000 Piccolo - Serial communications

I was actually tempted to dig into the ADC functionality, however serial communications seemed to be a higher priority thing to learn.
Why?
Let's face it : we (normally) do not have a screen where we can output some debug information, our best bet with microcontrollers is the UART and use a terminal program on a PC to visualize some data.

As I already anticipated in a previous post, the serial interface is handled quite at "high level" with the C2000, in a similar way you would deal with it on a PC.
First of all , in the C2000 the uart is referred a SCI (Serial Communication Interface) and since there is a single module "A", it normally becomes SCI-A or SCIA.

I am starting to look around the SCIA using the demo program tha comes with the c2000 Launchpad, unfortunately that one does not cover the RX part, and therefore all the interrupt handling is not covered either.
We will need to look somewhere else for that.

One interesting thing to notice is that the uart has double buffered RX and TX functions which is kind of neat.
Unfortunately it looks like that a single hardware uart is supported in the piccolo (some devices may support  SCI-B), which is a pity since at least two serial ports are always handy, typically you would use one to communicate with a device and the other one to debug whatever you need with a PC.
At least this is what I normally do.
It should be possible and quite easy to setup a software uart if needed, I hope.

Another thing I noticed is that it looks like there is no hardware flow control functionality provided, no big deal probably as a couple of gpio lines could be eventually used for that, after all that's the beauty of dealing with an mcu.

So, this said, we expect to have only two pins to deal with :   RX and TX.
In fact they are accessible from the Launchpad expansion headers

(from the C2000 Launchpad pdf, by TI)


SCIRXDA (RX) is available on J1.3 (mode 1), J2.2 (mode 2), J2.9 (mode 2)
SCITXDA (TX) on J1.4 (mode 1), J1.7 (mode 2), J2.3 (mode 2)

J1.4 (mode 1) means header J1, pin 4 and MUX mode set to 1

Now, the pdf that came with the Launchpad explains that the board has an FTDI interface to which, by default, the serial communications are redirected.
That makes them available through the USB port.
The Switch S4 connects and disconnects the uart from the ftdi, so, normally, if you want to use the ttl uart signals (3.3V tolerant) you are supposed to switch S4 so that they are isolated from the USB.

But then I am wondering :
According to the Launchpad schematics, S4 connects and disconnects J1.3 and J1.4   (GPIO28 and GPIO29), which would mean that if we use another combination (i.e. the J2.2/3 option) normally we would be isolated from the USB.
That's something I will probably test later.

Let's start simple and imagine we want to connect the SCIA to the usb/ftdi, then we will have the S4 switch set to ON and configure properly the GPIO28 and 29 pin on the mcu.

The demo program has it all in this case :


    GPIO_setPullUp(myGpio, GPIO_Number_28, GPIO_PullUp_Enable);
    GPIO_setPullUp(myGpio, GPIO_Number_29, GPIO_PullUp_Disable);

    GPIO_setQualification(myGpio, GPIO_Number_28, GPIO_Qual_ASync);

    GPIO_setMode(myGpio, GPIO_Number_28, GPIO_28_Mode_SCIRXDA);
    GPIO_setMode(myGpio, GPIO_Number_29, GPIO_29_Mode_SCITXDA);


The RX is going to be configured as input (implicitly, that's done automatically when setting the pin to uart mode).
To avoid floating signals the pullup  resistor is enabled.
TX is obviously output, therefore pull resistors are not used.
The setQualification part is related to synchronizing and qualifying the signal with the internal clock.
I will not enter too much in the details here, but let's just say that if a signal uses a clock that is not defined internally (this is the case for the RX signal whose clock depends on the other device on the communication line), then it needs to be synchronized with the internal clock to detect the gap with it.
A number of samples (configurable) is taken and a high frequency clock (SYSCLK or a divided value) is used to assess the gap.
The process is described in the 2802X_system manual.

The final two lines set the MUX  mode for GPIO28 and 29 pins, the GPIO_28_Mode_SCIRXDA and GPIO_29_Mode_SCITXDA are two enum constants (value = 1).

If instead we would have preferred to use the J2 option (GPIO19 = RX, GPIO12 =TX) the needed code would have been :


    GPIO_setPullUp(myGpio, GPIO_Number_19, GPIO_PullUp_Enable);
    GPIO_setPullUp(myGpio, GPIO_Number_12, GPIO_PullUp_Disable);

    GPIO_setQualification(myGpio, GPIO_Number_19, GPIO_Qual_ASync);

    GPIO_setMode(myGpio, GPIO_Number_19, GPIO_19_Mode_SCIRXDA);
    GPIO_setMode(myGpio, GPIO_Number_12, GPIO_12_Mode_SCITXDA);


And presumably the S4 switch would not affect at all, however, before connecting a ttl serial device to them, I would make sure that GPIO28 and 29 are NOT configured as SCIA at the same time (!!).

Now that we have the pin configured properly, let's take a look to the function that configures the SCIA peripheral (still from the demo software)


 mySci = SCI_init((void *)SCIA_BASE_ADDR, sizeof(SCI_Obj));

This line initializes a SCI handler, which will be used later.

void scia_init()
{
    CLK_enableSciaClock(myClk);

We also initialized and configured properly the clock (check this other post for details) , now we are using the myClk handler to enable the clock for the SCI peripheral

    SCI_disableParity(mySci);
    SCI_setNumStopBits(mySci, SCI_NumStopBits_One);
    SCI_setCharLength(mySci, SCI_CharLength_8_Bits);
    
    SCI_enableTx(mySci);
    SCI_enableRx(mySci);

Ok, this part is quite obvious,  we are using the classic 8-N-1 setup and we want both RX and TX channels enabled.

    SCI_enableTxInt(mySci);
    SCI_enableRxInt(mySci);

Also we think it is cool to have interrupts on both RX and TX buffers, then we want to set the Baud Rate.
At this point, you realize that the way these libraries have been created allow you to perform all the needed configuration without knowing much about the internals of the device.
... but some details cannot hurt.

The base clock of the SCI is the low speed clock (LSPCLK), then a 16 bit register (BRR) is provided to configure a divider.
That allows up to 65535 different BR configurations, the formula is the following :


By default the LSPCLK is set to SYSCLK / 4 ( 60MHz/4 in our case = 15MHz)
According to the formula, assuming BRR = 15
-> BR = 15.000.000 / (15 +1)*8 = 15.000.000 /128 = 117.2K  which is not exactly 115.2K  but close enough.
Using BRR = 16 we would have 15.000.000 / 136 = 110.3K and using BRR = 14 : 125K
So, finally, BRR = 15 is the best option

    // Configured for 115.2kbps
#if (CPU_FRQ_60MHZ)
    SCI_setBaudRate(mySci, SCI_BaudRate_115_2_kBaud);    // value is 15
#elif (CPU_FRQ_50MHZ)
    SCI_setBaudRate(mySci, (SCI_BaudRate_e)13);
#elif (CPU_FRQ_40MHZ)
    SCI_setBaudRate(mySci, (SCI_BaudRate_e)10);
#endif

Obviously we need a different divider if the CPU is not set to 60MHz, but hey, you have the formula, you can do the math :)
The following code enables the fifo buffers for both the RX and TX channels, then it enables the TX fifo interrupt, but not the RX one.
That's because, I suppose, the sample program is not meant to receive any data, in a real world application we would probably need that one too.
Despite the fact that the TX interrupt is enabled, there is no interrupt handler function in the demo program.
I assume the interrupt is used internally by the library in order to manage properly the output buffer.

    SCI_enableFifoEnh(mySci);
    SCI_resetTxFifo(mySci);
    SCI_clearTxFifoInt(mySci);
    SCI_resetChannels(mySci);
    SCI_setTxFifoIntLevel(mySci, SCI_FifoLevel_Empty);

    SCI_resetRxFifo(mySci);
    SCI_clearRxFifoInt(mySci);
    SCI_setRxFifoIntLevel(mySci, SCI_FifoLevel_4_Words);

Finally, after clearing the interrupts, the buffers etc, a priority is set and the module enabled

    SCI_setPriority(mySci, SCI_Priority_FreeRun);
    SCI_enable(mySci);
    return;
}



checking in the header file it looks that the following priorities are available :

 
     SCI_Priority_Immediate=(0 << 3),    //!< Denotes an immediate stop
    SCI_Priority_FreeRun=(1 << 3),      //!< Denotes free running
    SCI_Priority_AfterRxRxSeq=(2 << 3)  //!< Denotes that a stop after the current receive/transmit sequence

That completes the hardware configuration, on the software side, the port is dealt with similarly to a stream (or file) :


    status = add_device("scia", _SSA, SCI_open, SCI_close, SCI_read, SCI_write, SCI_lseek, SCI_unlink, SCI_rename);
    fid = fopen("scia","w");
    freopen("scia:", "w", stdout);
    setvbuf(stdout, NULL, _IONBF, 0);

First a "device" named scia is added, then it is opened for output and finally redirected to the standard output device (stdout).
From now on, each write to stdout will actually be directed to the uart :

   putchar(0x1B);

This was a very high level first look into the serial communications of the C2000, will come back in the future with some more details and some experiments.



Thursday, October 11, 2012

BeagleBone : Serial ports and multiplexing

Some months ago I released a couple of  Youtube videos where I was illustrating the basics of using java and the comm library RXTX to drive serial communications with the beaglebone.









Since then I keep getting a few questions and from time to time I get requests for a test class.
So I figured I could do a post here to explain few things.
(Ok, ok... if you just want the code and skip the blah blah, you can get it here, good luck with it)

First thing : RXTX is an open source communication library, maybe it's not perfect, but I find it great for a number of reasons, one of them being it's portability.
Driving hardware (like serial ports) in java is a bit tricky, because you need native code (i.e. written in C, ASM...) for the specific architecture you are using.
To put it in simple words : you need some code which is not executed in the JVM, so it's not java.
This is obviously an issue : java is designed to be portable cross platform, you normally just need a jvm for the specific architecture you are using and you are normally pretty much done.

If you need to execute native code, then you need the specific version that can work on your device.
The native part of the RXTX library has been successfully ported to the bone, which makes it possible to use the library in java on this device.

I am not going to provide a tutorial on rxtx here, if you want to use it and you have no knowledge on it, I strongly suggest you search for tutorials in the web and first learn how to use it on a pc.
I have a software logging data from a RS485 every 30 seconds, running since about 3 months, it was developed and tested on a PC and finally deployed (smoothly) on the bone.

So, what's special with the bone?
Not much honestly and in fact, if you use a usb/serial converter you probably don't need any bone specific instruction : what runs on your pc is supposed to run on the bone just the same.

However, the bone offers also some "internal" ttl uarts (3.3V !! beware) and to use those you need some bone specific code.
Those uarts are physically accessible from the P8 and P9 headers of the board, their pin mapping -extracted from the bbone user manual- is the following :


i.e. P9.21.1 means pin 21 on the P9 header and multiplex value = 1

You should probably be familiar with the multiplexing concept, if not, here's a very quick explanation :

Multiplexing 

Many of the modern processors and microcontrollers, provide a wide range of functionality.
At this point the issue became to export all those functions with physical electrical contacts (pins).
A solution was found in assigning multiple functions to the same pin and allowing the processor to be configured, via software, to set a specific function to a specific pin.
The ARM cortex processors use a lot this feature.
To get back to our serial ports, this means that the RX function of uart2 will normally be located at pin xxx, however at the same pin you can eventually find other 7 functions, which could be GPIO, timer output, etc...
So, what we want to do is to configure properly the function, direction (input/ output) etc of the pins we need.

But wait... that sounds like an issue if we are using java, right?
Again we would need to access the hardware, so we would need native code...

No, the Linux OS comes in help with that.
To allow an easy access to these functionality, the OS exports a virtual file system which acts as a sort of interface for all those hardware configuration.
From the java side, we just need to deal with files and directories.

For that I created a specific helper class, it's not really finished, but it does the job for me.
It can be found here and if you can read java code it should be quite self explanatory.
I use it to interface the beaglebone headers (it can do gpio read/writes), not just for setting the multiplex values.
This class uses an external dat file (gpiomux.dat) which is actually a text file in which I list the contacts on the P8 and P9 header.
Except for the serial ports, for which I provide a specific method, to configure the other pins (should you need to), you need to refer to the user manual, discover which pin is assigned to the function you are looking for and find also the function number.
With that info, the BBMux class will do the configuration for you.

Allowing RXTX to see the ttl uart ports

The RXTX library uses a list of known port names to discover your available serial ports, unfortunately this list does not include the beaglebone internal serial ports.
No worries, there is an easy fix, no coding required!
The solution is documented here : http://rxtx.qbang.org/wiki/index.php/Trouble_shooting
Check where it says : How does rxtx detect ports? Can I override it?

In my case I decided to specify the port list when running the program.
The internal serial ports are seen by the OS as ttyOx (O stands for Omap)


java
    -classpath ./:./rxtx/RXTXcomm.jar
    -Djava.library.path=/usr/lib/jni
    -Dgnu.io.rxtx.SerialPorts=/dev/ttyO1:/dev/ttyO2:/dev/ttyO3:/dev/ttyO4:/dev/ttyO5
   MyClass

My command line sets :
- the java classpath to include the rxtx java library (jar)
- the java library path to include the rxtx native library folder
- the rxtx serial ports to the list of ports I could use in my program


Note : I created the test class TestBBSerial by ripping code from my program, I hope it works, but it's really meant just to illustrate the concepts.
You can find great rxtx examples on the web,
Unfortunately I cannot post my other programs as they would be too complex to explain, I normally use some wrappers for rxtx to handle buffers, configurations, protocols etc.
These wrappers use json, webservices for remote configurations... so I would need to post tons of classes that would just confuse you more. 

Friday, September 21, 2012

The illusive world of social media

I am Italian and, despite the fact that I am not living anymore in Italy since few years, when Italy has to renew  the government, I still vote there.

Since,after I left my country, I don't have many opportunities to meet in person with my old friends, I often used to debate with them through social media (not now, I closed my fb account)

At the last political elections, back in 2008, among my friends we were pretty convinced that Berlusconi had no chance to win.
But then the polls already had different predictions and finally, he definitely won.

The problem is that when you meet with people in real life, you tend to aggregate with those having similar interests, probably with a similar level of instruction and potentially with similar political views.
However in real life you simply MEET people of different kind.
You may not necessarily try to meet and discuss with someone, but simply as you walk down the street you need to interact with "others".

With social media it is different, you don't HAVE to bump into whoever, you CHOSE to.
If this sounds "cool" on one side, it has some serious side effects.
I believe you end up getting an illusive picture of the world, it's probably a world that resembles a lot what you already had in mind, so it gets addictive.

It is something that "proves you right" and, let's face it, we all like that.
However it fails badly in being "culturally challenging" which, I personally believe, is one of the main drivers for our cultural evolution.

My point is : social media are products, as such they need to generate profits.
In order to generate profits they need to sell and to sell they must please their customers.
What pleases you more than being surrounded by people you know, that shares your habits, interests, views...
We are fundamentally "lazy" and we normally feel at ease when others confirm our opinions, it means we do not need to over-think, to challenge them.

But in the end, is it good for us?

I have a small youtube channel and I just checked the stats :
the vast majority of the viewers are males between 35 and 44 years, just like I am.

Is there a new way of designing social media to stimulate an honest, open debate, to challenge our beliefs and at the same time being attractive to us?

Thursday, September 20, 2012

Some mice are smarter

I have two cats and I live in the countryside.




Their favorite sport is napping, but their second favorite one is chasing mice.

We have plenty of them here, they are little funny animals, and I try to save them when I can.
Lately my two furry hunters got the habit of scouting the area around the house, catch a mouse and then run back in the house with him to play, normally in my studio.
They really like me to participate to this game, especially around 3am, in that case they normally elect my bedroom as "chasing arena".

Yesterday I was discussing over the phone with a customer and one of the cats arrived running with a mouse in her mouth, she freed him under my desk and started the chase.

I recon this little fellow could be the one I already saved a couple of days ago, so he is already familiar with the environment.
I imagine him thinking "oh God... here we go again...".
He knew already that hiding behind my computer normally works, so he headed straight there while the cat was guarding the area and waiting for him to pop out.

But when they survive, they probably get smarter, so this one decided to take his revenge.
He climbed on top of my desk and eventually got to the little bag of cat treats that I keep there.

This is what happened



In the end he did not manage to open the bag, but I thought he deserved some treats, so I opened it and tossed a couple to him.

Monday, September 17, 2012

MSP430G2 & Wifly - The internet of things

In the previous two posts I explained how to interface an RN XV wifly module with a Launchpad (MSP430G2553).
In the last post I discussed an easier method that can be used to connect to a remote webserver (or any TCP based service), and today I will implement it with the Launchpad.

First thing I created a simple php page, named pp.php which looks something like this :

<?
 // connect to databse
 //...
 // get $mn and $mv from the request
 // ...
 $sql = "insert into test (tstamp,measureName,measureValue) values (now(),'".$mn."',".$mv.")";
 // execute query
 echo "[[[[ok]]]]";
?>

this page inserts a record into a mysql table called "test".
Suppose my server is http://www,myserver.com, to test the page we need to open a browser and call :

http://www,myserver.com/pp.php?mn=wifly&mv=2.32

Using the technique illustrated in the previous post, I stored the server address into the wifly configuration :


set ip proto 18
set dns name www.myserver.com
set ip address 0
set ip remote 80
set com remote 0
save
reboot

We will use the wifly gpio lines 4,5 and 6 to detect if the module is associated with a ssid, then to ask it to connect with the TCP address stored in the config and once gpio6 is high (tcp connected) we will send the get command via uart.

I connected the pins 2.0, 2.1,2.2 on the launchpad respectively to gpio4,gpio6,gpio5 on the wifly

P2.0 -> gpio4 (associated) - input
P2.1 -> gpio6 (connected) - input
P2.2 -> gpio5 (connect) - output

Let's configure the P2 port on the launchpad :

void configGpio()
{
 P2DIR |=BIT2; // P2.2 output
 // P2.2 is connected to wifly gpio5
 P2DIR &= ~(BIT0 + BIT1); // P2.0 and P2.1 input
 // P2.0 is connected to wifly gpio4
 // P2.1 is connected to wifly gpio6
 P2REN |=BIT0 + BIT1;
 // pulldown resistors
 P2OUT &= ~(BIT2);
}

Then we need a procedure to send  the GET request.
In my case I had to use HTTP/1.1 specifications and chances are that you will have to do the same unless you are working with you local webserver.
The GET command for version 1.1 of the HTTP protocol requires that the Host is always specified at each request, so the GET is someting like :

GET /pp.php?mn=wifly&mv=123.45 HTTP/1.1
Host: www.myserver.com

And this is the procedure I use


void wifly_TCPsend(char *text)
{
 if ((P2IN & BIT0)>0) // wifly is associated
 {
  if ((P2IN & BIT1)>0) // wifly is connected
  {
    UART_TX(text);
    __delay_cycles(16000000); //wait 1 second
      P2OUT &= ~BIT2; // close connection
     __delay_cycles(16000000); //wait 1 second
    wifly_enterCommandMode();
    UART_TX("sleep\0");
    __delay_cycles(160000000); //wait 10 seconds
  } else 
   // associated, but not connected -> let's connect
   P2OUT |= BIT2;  // pulls wifly gpio5 high
 } else
 { // the module is not associated
wifly_enterCommandMode();
UART_TX("join\0");
__delay_cycles(16000000); //wait 1 second
 }
}


This implementation is pretty basic, it works this way :
1) we check if the module is associated to a ssid, if not we try to send a join command. It should not be needed as we pre-configured the module to automatically join the stored ssid
2) Once the module is associated (gpio4 -P2.0- is high) we raise gpio5 (P2.2) to initiate a tcp connection
3) Once the connection has been successfully established, the gpio6 (2.1) goes high and we can send the get request via uart

The main  procedure becomes :


void main(void)
{ // stop the watchdog
 WDTCTL = WDTPW + WDTHOLD; // allow debugging
 configClock();
 configUART();
  configGpio();
 while (1)
 {  
  // do whatever you need here, like getting values from the ADC 
  // or reading sensors via SPI or I2C...
 // then customize the get call according to your needs 
   wifly_TCPsend("GET /pp.php?m=wifly&v=123.45 HTTP/1.1\nHost: www.myserver.com\n\0");
  // you may want to place this in an interrupt timer routine and sleep while waiting 
 }
}

.. and sue enough I have the values logged in my mysql table in my remote webserver. 

One tricky issue is to actually read data from the webserver.
Data is coming back, no issues with that, but the server will send you also some header information, which will force you to parse the content.
Again, parsing a text is no the best thing to do with a device with minim memory, so you may want to use some kind of TAG to identify the only part of text that should be considered.
My php webpage uses

echo "[[[[ok]]]]";

to pass back the "ok" message, so, the launchpad will disregard the incoming uart data until a series of four consecutive "[" are received.
Why would we want to pass data back to the launchpad?
Imagine you store in your webserver the configuration to manage the heating system of your Chalet.
When you decide it's a good weekend to go there, you may want to turn the heating on (or increase the temperature) few hours before, then to turn it off automatically at the end of the weekend.
Your launchpad, installed in your chalet, will read the current temperature (it has a temp sensor inside), every minute it will check with your webserver what it has to do with that temperature.
The webserver will check and will send back a "ON" or "OFF" response.


There are plenty of possible implementations, let me know your ideas! 

Friday, September 14, 2012

Roving Networks RN XV - Wifly module

In the previous post I illustrated a basic way to interface the wifly module to the MSP430G2 using the uart.
As I already anticipated in that post, the method could be improved, but for that we need to dig in a bit into the features of this module.

The wifly has the ability to store configurations, this means that we can pre-set all the needed parameters and we can avoid to send them from the mcu via uart.

Using an FTDI cable I connect to the module and set the config pars :

$$$  (to enter in command mode)
set wlan auth 3 
set wlan ssid myssid
set wlan phrase mypwd
set wlan channel 0   (0 means autoscan)
save

The configuration is now saved and it will be automatically loaded at each reboot / power up.
Once these parameters are set, to join the ssid, we will just need to issue the command

join

However we could even do better than that, in fact, if we set the auto join function to "1" (which btw is the default) the wifly will automatically try to join the ssid at each reboot.

set wlan join 1
save

Cool, not much to do for our mcu now, eh?
Just wait, it actually gets even better.

Fine, we are associated with the ssid, we got an ip address etc, now we need to establish a tcp connection to a remote server.
I quote from the RN XV user manual :


set ip proto 18 //enable html client
set dns name www.webserver.com //name of your webserver
set ip address 0 // so WiFly will use DNS
set ip remote 80 // standard webserver port
set com remote 0 // turn off the REMOTE string so it does not interfere with the post

You guessed that, you can save this too in the internal config!

save

To make the connection the command would be:
open
or inline you can send open www.webserver.com 80
The user’s microprocessor should write to the uart:
GET /ob.php?obvar=WEATHER \n\n

So, finally this makes things way easier, but it's not the end of the story...
What if we could check from a gpio pin if the wifly is associated, then raise another gpio to ask it to connect to the remote tcp port and finally get from a third gpio if it successfully connected?


Yup, that's another nice feature which is actually available.
The specific gpio pins are the 4,5 and 6 and must be configured to be used in this way.

set sys iofunc 0x70 // enable alternate function for GPIO 6, 5 and 4
save

With all this set and saved in the configuration, at power on the wifly module will try to associate to the ssid. once it is ready to perform a tcp connection it will raise gpio4 (which we will check from our mcu).
At that point, when we need to contact the remote server, we will raise the gpio5 and check gpio6 to verify that the connection was established.
At that point, if we are contacting a web server, we will send the GET request through the uart and will receive the answer from there.

... and we did not even need to enter in command mode!

Nice eh?
Will implement this with the launchpad in the next days.


MSP430G2 - Interfacing a wifly (RN XV) module

Do you like "the internet of things" concept?

The RN XV, from Roving Networks is a versatile little device.
It is basically a wifi card with a serial port, designed to be easily connected to microcontrollers.
I previously used on my Arduino and even on my BeagleBone, where I used java (RXTX) to drive it.
I have a youtube video about the BeagleBone / wifly, but it's mainly about the Bone and RXTX than the RN XV, so I will not embed it here.

Did you ever work with old modems?
If so you are probably familiar with the Hayes protocol  and the AT commands you sent over the serial port.
No, the RN XV does not use Hayes, but the concept is similar : you send commands in ASCII format to the serial port and in that way instruct the module to connect to a ssid, perform a http get etc.

The good thing about this is that it's easy to test the protocol just using an hyperterminal kind of software.
In windows I like to use Realterm, it's open source.
To connect the wifly to a PC you will need an FTDI usb interface (get yourself a couple of those from ebay if you don't have them already, they are extremely handy).

To easily work with the RN XV (other compatible modules might be slightly different in this regard, so check carefully your specific case) you will also need (or "you will be better of with") a breakout board for it. (it is cheap, no worries).
The reason you may want the breakout board is that the pin pitch of the RN XV is designed to match the XBee standard, which would not work with the common headers you normally use.

Final consideration : the wifly modules work at 3.3V which makes them perfect to work with the MSP430G2, should you use an AVR or other MCUs, make sure the serial communication runs ar 3.3V, else you need a logic level converter.

Let's connect the RN XV with the Launchpad :


In my example I am powering the wifly module from the Launchpad, the 3,3V is taken from pin 1 on the lp.
Besides Vcc and GND for now we will just need the UART rx and tx signals.

You may wonder why the wifly has so many pins.
Like Dave would say : "I am glad you asked!".
The Roving Networks wifi interface contains an MCU which obviously has GPIO and other features (including an ADC which I never tried so far, but it promises 14 bit resolution !!!).
The functionality of the contained mcu are accessible through the various pins, we will probably need to use some of those later on.

As a general consideration, a text based protocol is normally handy to implement an interface, it makes it easier to debug and it's normally quite flexible.
Unfortunately it may become difficult to manage if the amount of RAM you have at your disposal is limited, like in the case of the MSP430G2.

We then need to design the handling routines accordingly, we will not be able to allocate a big buffer to store incoming data to be processed asynchronously.
In general a synchronous approach would probably reduce the amount of needed memory and it could eventually work with the wifly protocol, however I am going for a simple asynchronous implementation, using the uart interrupt on the MSP430G2, just to make sure we do not miss any incoming char.

By default, the wifly uart starts at 9600 baud, 8 N 1.
Let's start configuring the clock and uart on the launchpad (details here) :


#include <msp430g2553.h>

 // configure the CPU clock (MCLK)
 // to run from DCO @ 16MHz and SMCLK = DCO / 4
void configClock()
{
BCSCTL1 = CALBC1_16MHZ; // Set DCO
DCOCTL = CALDCO_16MHZ;
BCSCTL2= DIVS_2 + DIVM_0; // divider=4 for SMCLK and 1 for MCLK
}


void configUART()
{
// set the pin mode 3 for pins 1 & 2 of port 1 (Uart mode)
P1SEL |= BIT1 + BIT2; // low bit = 1 for pin 1 and 2
P1SEL2 |= BIT1 + BIT2; // high bit = 1 for pin 1 and 2
// configure the UART
UCA0CTL0 = 0; //UART mode, No parity, LSB first, 8 data, 1 stop
UCA0CTL1 = UCSSEL_2; //use SCLK
UCA0BR0 = 0x1A; //lower byte of UCBR0. 26dec
                //(4MHz / 9600 baud)  see table 15-5
UCA0BR1 = 0x0; //upper byte of UCBR0.set to 0
UCA0MCTL = UCBRF_1 + UCBRS_0 + UCOS16; //sets UCBRFx to 1,
                                // UCBRSx tto 0 , UCOS16=1
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI **
UC0IE |= UCA0RXIE; // Enable USCI_A1 RX interrupt
_EINT(); // global enable interrupts
}

Now we need to create a simple interrupt handling procedure for the uart rx, it will fill a receive buffer.
Normally I would allocate 4Kb of ram for a uart rx buffer, but there is no way we can do that on the G2, so we will need to limit it to 256 bytes, if we play it smart, it should be enough.

char UART_buffer[256];
unsigned char bufPtr = 0;


Together with the buffer I declare a buffer pointer, now, there are different ways to manage a buffer, I am going for a "circular management" approach which is quite common in these situations.
The receiving (interrupt) routine will store the incoming char in UART_buffer[bufPtr] and then increment bufPtr, when the end of the buffer is reached, since bufPtr is a byte (unsigned char) it will restart automatically from 0.
If we wanted a buffer size different from 256 we would have needed an if statement to check if the end of the buffer was reached and in that case reset the pointer.


#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
 char c = UCA0RXBUF;
 if ((c!='\n')&&(c!='\r'))
  UART_buffer[bufPtr++] = c;
 else
  if (c=='\r') wifly_process(bufPtr);
}


The command protocol of the wifly uses ASCII text responses terminated by CR LF (\r\n) so we will use that to acknowledge that a response has been received and needs to be processed.
While we process a text returned from the wifly, other chars could be incoming at the same time, therefore we need to pass the position of the end of the text to be processed in this iteration.

So, what's happening is that while we are filling the uart rx buffer, in parallel we have a procedure that at each CRLF received extracts a single response line.
The process procedure knows up to which char it has to process since this is passed by the interrupt routine, but if also needs to know from which char to START processing.
In the current implementation (it can be improved) I am copying a single returned line into a separate buffer that will be processed later on.
Also I added a flag to identify if there is a complete text line ready to be processed.

char wifly_rx[128];
unsigned char processPtr = 0;
unsigned char commComplete = 0;


void wifly_process(unsigned char i)
{
 unsigned char cnt = 0;
 while (processPtr!=i)
wifly_rx[cnt++] = UART_buffer[processPtr++];
 wifly_rx[cnt] = '\0';
 commComplete=1;
 }


I am adding a char 0 at the end of the buffer as it is needed by the string handling routines I created.

The first (a bit painful) thing you have to know when working with the wifly protocol is that it has two functioning modes :
The data mode and the command mode.
To send commands you need to enter in the command mode (fair, no?) which, via the UART is achieved by sending three dollar isngs ( $$$ ) not followed by a crlf and wait for 250 ms.
That's fairly easy and the module will answer with "CMD".
Practically it's less obvious than you may think.
Firts, you may already be in command mode and in that case you will not get any answer until you send a crlf, second in some cases the module may not respond (it improved with the latest firmware releases).
A typical case is while establishing a connection to a ssid.
For this reason in the latest firmware releases an alternative method to enter in command mode, was implemented and it is based on pulses sent through the GPIO.
We will not implement that one right now.


void UART_SendChar(unsigned char txChar)
{
 while (!(IFG2&UCA0TXIFG));                // USCI_A0 TX buffer ready?
 UCA0TXBUF=txChar;
}

void UART_TX(char *txStr)
{
    unsigned int i=0;
    while(txStr[i]!=0)
    UART_SendChar((unsigned char)txStr[i++]);
}


unsigned char wifly_waitForText(char *text)
{
 unsigned char retry = 255;
 unsigned char matched = 0;
 while ((retry-->0)&&(commComplete==0))
  __delay_cycles(160000);
 if (commComplete==0) return 0;
 while ((text[matched]==wifly_rx[matched])&&(matched<255))
 {
  matched++;
  if (text[matched]=='\0') return 1;
 }
 return 0;
}

unsigned int wifly_enterCommandMode()
{
  unsigned char retry=20;
  while (retry-->0)
  {
   UART_TX("\r\n\0"); 
   __delay_cycles(250 * 16000);
   UART_TX("\r\n\0"); // we send 2 times cr lf
 // since the first one is only used to clear the wifly command buffer
   if (wifly_waitForText("<2.32>\0")==1) return 1;
   UART_TX("$$$\0");
   __delay_cycles(250 * 16000);
  // should receive "CMD"
   if (wifly_waitForText("CMD\0")==1) return 1;
  }
  return 0;
}



The enterCommandMode procedure checks first if we are already in command mode.
In that case the wifly will respond to an empty command with a prompt with the version number, in my case this would be "<2.32>".

Once we are in command mode we can connect to a ssid

void wifly_connect(char *ssid,char *pwd)
{
UART_TX("set wlan auth 3\r\n\0"); // WPA mixed, might be different for you, 
       // check the RN XV user manual
__delay_cycles(160000);
UART_TX("set wlan ssid \0");
UART_TX(ssid);
UART_TX("\r\n\0");
__delay_cycles(160000);
UART_TX("set wlan phrase \0"); // you may need key instead, 
       // depending on your configuration 
UART_TX(pwd);
UART_TX("\r\n\0");
__delay_cycles(160000);
UART_TX("join\r\n\0");
__delay_cycles(48000000); // wait 3 seconds, might actually take longer



void main(void)
{ // stop the watchdog
 WDTCTL = WDTPW + WDTHOLD; // allow debugging
 configClock();
 configUART();
 while (1)
 {

if (wifly_enterCommandMode()==1)
{
   wifly_connect("myssid\0","mypwd\0");
           // do stuff here
          // make sure you do not keep trying to connect if 
         // it is already connecting
}
  }
}


Ok, this implementation is quite basic, but was enough in my case to see the wifly pop up with a dhcp assigned ip in the admin page of my router.

I will fine tune and expand this implementation in the next days and hopefully interface it with a simple webservice page to send and receive some data.