Search Microcontrollers

Showing posts with label Technology. Show all posts
Showing posts with label Technology. Show all posts

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.


Wednesday, August 29, 2012

DYI PCB

Today I made my first homemade Printed Circuit Board (PCB).

In the past I was lucky enough I could get access to some lab to produce them for me and today, does it still make sense to etch your PCB at home?

You probably get a much better result by using one of the many available online services that can produce professional grade PCBs for a reasonable price.... but that might eventually work if you know what you are doing... which, sadly, it's not my case.

By that I mean that any circuit I design and then test on a breadboard, has good chances it will not work once transferred on a PCB.
Why?
The answer is really simple : lack of experience which you can build up with the most classical process called "trial and error".

Now, if for every try and probable error I need to wait weeks for the pcb to be delivered to me I would consider that sub-optimal, it would not provide me a really steep learning curve.

I remember some years ago I saw a great BC comic strip :
BC (or was it Thor?) is pushing a square stone with a hole in the middle and says something like : "I had a wonderful Idea! This thing is called wheel and it will change the world as we know it".
In the next panel he comes back with  a triangular stone and goes : "I made a great improvement to my invention" and the other guy : "Uh? Where's the improvement?".
The answer is "I eliminated one of the four bumps".

So, to set the stage, I am pretty much there now : bumps optimization.
Not much, I agree, but it's always a good start to know were you stand.

I usually build circuit prototypes with breadboards, but it 's becoming more and more cumbersone since most of the components are now available in SMD packages.
I know there are adapters, but in the end I figured it's easier to be able to etch a quick PCB and use it instead... would have been fun anyway, so I thought.


Before I dig in further more : it actually worked, better than I expected (maybe my expectations were pretty low).
The board in the picture is 4 x 2.5 cm, pretty small... those pads on the bottom are for smd 805 components.
This should give you an idea of the size of the traces.

This one is just a test, my very first test, so I am pretty sure every step, from design onwards can be improved and yes, I could have started with something "simpler", maybe with bigger traces etc, but the purpose of this one was really to see where's the limit.

I still need to apply solder mask, so the process is not over yet.

How this was achieved :

I designed the pcb using Eagle Cad.
Nice tool, I chose this one mainly because you can type commands instead of clicking icons, I know it might sound silly to you, but it helps me a lot since my eyes make it difficult for me to use icons.
I created my own library with the two packages I needed, in that way I was able to design the pads with the shape I thought best to ease the soldering afterwards.
Soldering those tiny chips (and mainly the LDO on the right) will be difficult, hopefully I will have a good solder mask soon, without that I would not even try.
I designed the pads a bit longer than the suggested measure, I probably should have done more than that.
The idea is that it should be used to drag the solder away after applying it.
I suppose I will need to use the solder wick to remove shorts between the pins, but that's still to be discovered (wow, isn't that fun? So many things to try out!)
  
The circuit itself is really simple, it's a RS485 driver with a 3.3V LDO voltage regulator, nothing fancy, it should replace the one I am using on a breadboard.
It is also a part of a bigger circuit I am designing to host a MSP430G2553 (TSSOP). 



Once the PCB design was done I "panelized" 6 circuits (they are tiny, makes sense to run a batch of 6 at least) and printed some tests on plain paper, checking also that the solder mask overlapped nicely to the pads once printed.
Another check I did was to place the two chips on the paper and verify the contacts were sitting nicely on the pads (I designed the footprints in Eagle, had to test it).

To transfer the design to the copper I found two options you are probably familiar with :
- Photo resit and UV  light
- Toner Transfer

I have the equipment for the UV thing, a built myself a nice bromograph (I am quite proud of it :) Simple but apparently reliable), with 4 8W UVA lamps with ballasts and nice reflecting white inside. 
Yeah, told you I was proud of it, no? :)
But finally opted for the toner transfer as I found in the web people very happy with the results.
I will still use the bromograph for the solder mask.


   
The panel is laser printed (mirrored) on the toner transfer sheet (I had A5 sheets, managed to cut one in half for this test, to reduce the wasted material).
After cleaning the copper surface (dish soap first to remove finger prints etc, then a metallic wool sponge -gently- and water) I placed the pcb on a tempered glass (you can get them really cheap at Ikea, just look for shelves) with a bit of bi-adhesive.


Using a glass there helps a lot, it's a smooth solid surface, thermally suitable for this job and helps a lot also in aligning the toner transfer sheet with the board, I left on purpose some black borders around, to easily overlap the two parts.
Once the board was placed on the glass, I cleaned it with isopropilic alcohol.


You cannot see it properly in the picture, because of the flash, but placing the glass against a light source it is possible to use the black border to center the sheet and than secure it with some tape.


I initially overlapped a piece of fabric as I feared the yellow paper might stick to the iron, then I realized it is made specifically to be ironed... so it does not stick, nor it burns.
Thanks to the tape and the bi-adhesive the paper did not move even if I feared it might once it was really hot.
I then realized I might have overheated it, especially in the center.
Since everything is stuck to the glass, it's quite easy to handle, I used some cold water to cool down everything before peeling off the toner transfer sheet... which proved to be quite an easy task.


As you can see, in the center there is still a bit of toner, it probably happened because I overheated that area or because of the bi-adhesive tape on the back which absorbed part of the pressure I applied.
Checking the copper side revealed further signs of overheat, the copper appeared "reddish", darker than in the other area and  the toner was not covering completely the copper in some points.


I initially thought that the two boards in the middle would have been useless, but turns out I was wrong.


 I then etched using the classic FeCl solution, if you never used it, that thing is really messy, better use protection gloves and to keep it away from any metallic thing you are not planning to corrode.
To speed up the process, while gently rocking the container with one hand (while not holding he camera), I heated the solution with a hot air gun.
Combined with the fact that I tried to optimize the design to reduce the amount of copper that needed to be removed, the process was quite fast, probably around 5 minutes.


 The board is then rinsed with a lot of cold water.
A this point you can remove the remaining toner, but, if you are not planning to go ahead with the next steps, it's probably better to leave it there at it somehow protects the copper from further oxidation.



In my case I need to first check the result and then proceed with the solder mask part.
Since I am not sure at all of the outcome of the solder mask process, I decided to split the board in two to have two chances to run through the process, I then cleaned one.


I used a regular cutter, which did the job... but was probably not the best solution.
Using an aluminium guide to ensure the cut was traight helped a lot, specially since it was secured with two clamps.
These things make the job safer and easier, they come in extremely handy and can be easily found in hardware stores.


cleaning the toner away revealed that even the middle board, which I thought was useless due to the overheating, was pretty good.
In fact the first picture on top is the middle board, probably the worse in the batch.
Ok, I know, it could have been better, but you should realize those traces are really tiny, I could not find any short or broken trace after inspecting the pcbs with a magnifier.
The worse point is the one shown in the circle below.
It's the overheated part of the middle board, not perfect, but not too bad either in the end.
Check the pad on the right (red rectangle), it's 0.4 by 0.9 millimeters, that should give you an idea of the sizes in the picture.


Overall, for being my first attempt I am quite satisfied with the result, now I need to work out the solder mask part and then... the hand soldering.
   


Thursday, August 16, 2012

C2000 Piccolo - The clock system

The TMS320F2802x has a quite flexible clock system, still providing easy ways of interacting with it.

Texas Instruments provides an extensive guide (TMS320F2802x/TMS320F2802xx Piccolo System Control and Interrupts), which covers several topics including the clock system.

There are four main options when it comes to selecting a clock source :
- Two on chip (zero pin) digital oscillators (INTOSC1 and INTOSC2)
- An on chip clock module that uses an external crystal
- An external clock signal

The two internal (10MHz) clocks can be used at the same time to feed the signal to different subsystems (CPU code, Watchdog, Timer 2).

A PLL (Phase Locked Loop) Module receives the clock signals and provides a set of multipliers and dividers to adjust the frequency as needed.
This defines the core Clock SYSCLKOUT, a slower subClock (LSPCLK Low Speed Peripheral Clock) is then obtained by pre-scaling the core clock.

Peripheral modules source SYSCLOCKOUT (eCAP,ePWM...) or  LSPCLK (SCI, SPI...) and dedicated registers are used to enable or disable their clock input.

The Low Speed Peripheral Clock has a dedicated Prescaler Register (LOSPCP) that allows a (core clock) frequency division by a range from 1 to 14.

The clock registers allow to define which peripherals are clocked or not.
Specific functions are provided (clk.h) to enable or disable the clock signal generation for the peripherals, such as CLK_enableAdcClock(myClk); or  CLK_enableSciaClock(myClk);

From a  coding point of view, when dealing with the clock system, we need at least to get a handle for the Clock and PLL modules :


 CLK_Handle myClk;
 PLL_Handle myPll;
 myClk = CLK_init((void *)CLK_BASE_ADDR, sizeof(CLK_Obj));
 myPll = PLL_init((void *)PLL_BASE_ADDR, sizeof(PLL_Obj));

As previously explained there are two internal and two external oscillators / clock signals.
To configure them two functions are provided :


void CLK_setOscSrc(CLK_Handle clkHandle,const CLK_OscSrc_e src);
//    src = CLK_OscSrc_Internal or  CLK_OscSrc_External                   

void CLK_setOsc2Src(CLK_Handle clkHandle,const CLK_Osc2Src_e src);
//    src = CLK_Osc2Src_Internal or  CLK_Osc2Src_External



As the internal oscillators have a fixed frequency of 10MHz, we need to use the PLL to multiply/divide it to match the value we need.


    PLL_setup(myPll, PLL_Multiplier_12, PLL_DivideSelect_ClkIn_by_2);

// multiplier is any number between 1 and 12 (on the tms320f28027, 
// other mcus may support different frequencies)
// divider is  [ 1,2,4 ]
// the actual frequency is  F = 10MHz * PLL_Multiplier / PLL_Divide

With this we are all done setting the CPU frequency, can we test it?
The answer is absolutely yes, and this is made easy by the fact that we can "expose" the clock signal externally through a pin of the processor, we just need to set the right value of the multiplex for the pin GPIO_18 and then eventually set a divider (prescaler) for this signal.

  GPIO_Handle myGpio;
  myGpio = GPIO_init((void *)GPIO_BASE_ADDR, sizeof(GPIO_Obj));

  GPIO_setMode(myGpio, GPIO_Number_18, GPIO_18_Mode_XCLKOUT);
  CLK_setClkOutPreScaler(myClk, CLK_ClkOutPreScaler_SysClkOut_by_4);  
// prescaler values (1,2,4,Off)
// CLK_ClkOutPreScaler_Off  turns off the clock signal on the pin

Now we need to hook up an oscilloscope probe to the GPIO_18 (J1 pin 7 on the launchpad)



The complete source code for this test is the following :

#include "DSP28x_Project.h"     // DSP28x Headerfile

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

void main()
{
 WDOG_Handle myWDog;
 myWDog = WDOG_init((void *)WDOG_BASE_ADDR, sizeof(WDOG_Obj));
 WDOG_disable(myWDog);

 CLK_Handle myClk;
 PLL_Handle myPll;
 myClk = CLK_init((void *)CLK_BASE_ADDR, sizeof(CLK_Obj));
 myPll = PLL_init((void *)PLL_BASE_ADDR, sizeof(PLL_Obj));

//Select the internal oscillator 1 as the clock source
  CLK_setOscSrc(myClk, CLK_OscSrc_Internal);

  PLL_setup(myPll, PLL_Multiplier_12, PLL_DivideSelect_ClkIn_by_2); //60MHz

  GPIO_Handle myGpio;
  myGpio = GPIO_init((void *)GPIO_BASE_ADDR, sizeof(GPIO_Obj));

  GPIO_setMode(myGpio, GPIO_Number_18, GPIO_18_Mode_XCLKOUT);
  CLK_setClkOutPreScaler(myClk, CLK_ClkOutPreScaler_SysClkOut_by_1);

  while(1)
  {
    // I was blinking a led here
  }

}

The result is visible in the picture below, you will notice the waveform is a bit weird, but I did not put the required attention on how I hooked the probe for such an high frequency signal, that might explain it.
I was mainly interested in checking the frequency which you can read in the bottom right corner of the screen.
Yup, that's a 60MHz! (note : remember to disable the 20MHz band limit on the channel :P) 



If we play a bit with the prescaler :

  CLK_setClkOutPreScaler(myClk, CLK_ClkOutPreScaler_SysClkOut_by_4); 
// 60 /4 = 15MHz



And again, besides the waveform which is probably a bit different from the real one, it's a confirmed 15MHz.

There are plenty of other interesting details to discuss about the clock system, however they tend to be specific to the peripherals that use the clock so, I believe, they are better discussed in that context.

Friday, August 10, 2012

MSP430G2 - Timers and PWM

We previously used a timer (TIMER A) to execute a procedure at regular intervals.
This is definitely a useful way of using the timers, but there is much more we can do with them.

Another interesting application is the generation of PWM (Pulse Width Modulation) signals.
I am not planning to explain here what PWM is, and I will assume you are familiar with the basic concepts (Frequency and Duty Cycle), if not you should be able to find everything here :
http://en.wikipedia.org/wiki/Pulse-width_modulation.

These signals have  a number of different practical applications, they can be used to control precisely the speed of electric motors, to drive power transistors in switching power supplies, they can be used to dim a led light etc.

A PWM signal is characterized by two parameters : Frequency and Duty Cycle.
The MSP430G2 time handles both of them.

The first thing we have to define is the period T (which also defines the frequency F=1/T).

Let's image to run the Timer A  at his full speed (16MHz) having the MCLK sourced from DCO with divider = 1 and SMCLK, also selected as clock source for Timer A, with the minimum division : 1
Let's also assume that Timer A is configured to run in "up mode", basically it will count from 0 to the values set in TACCR0.
Each count will take 1 / 16.000.000 seconds (1 cpu clock), so, if we make the timer to count 8 times, the period will be :

T =   1 / 16.000.000 * 8 = 1 / 2.000.000 s
and obviously the frequency F = 1 / T = 2MHz

TACCR0 has to be set to 7 for this (the count starts from 0)

Defining the Duty Cycle means we are defining the period for which the signal should be on (Ton) in each cycle.

Since the MSP430 has several capture/compare devices per each timer, we can use a second one (CC1) to define Ton.
The duty cycle is defined as Ton/T, but we also know that the periods are directly proportional to the number of timer counts, so, assuming we want to obtain a 25% Duty cycle

 0.25 = Ton / T

We know T = 8 -> Ton = 8 * 0.25 = 2


TACCR0 = 7;  // PWM Period (CC0)
TACCR1 = 1;  // PWM Ton   (CC1)          


In this picture, on the Y axis we have the Timer A counter value, on the X Axis each block is is a counter clock (in our case 1 / 16.000.000 s).
Since the timer is configured in "up mode", it will start from 0 and increment by one until it reaches TACCR0 (7) then it will drop again to 0.
Another action will be triggered when TACCR1 is reached.
How the CC0 and CC1 triggers can be combined is defined by choosing the "output mode" of the time as visible in fig 12-12 (from TI's MSP430 User guide).
The waveform we want to obtain is the red/green one, which matches with Mode 7.



This is chosen setting the right value in the TACCTL1 register

TACCTL1 = OUTMOD_7;

Obviously we could just set up an interrupt, check the TAR counter and drive accordingly an output pin, but that would work only for low frequencies as the cpu cycles needed to compare the values and drive the pin would affect our waveform, plus we would be using the CPU almost exclusively for this purpose.

Luckily the timer is autonomous for this and can automatically drive an output pin, using the criteria defined by the mode selected (reset/set in our case).
This means we do not need an interrupt nor we need to do anything special with the CPU which could be "sleeping" or performing other tasks.

Checking the device specific Datasheet (msp430g2553 in my case) we find that pin P1.2 supports the function TA0.1 (timer A output) with mode 1 (PSEL = 1 , PSEL2 = 0, DIR = output -1-).


The bit related to pin 1.2 is the 3rd in the registers :

7654x3210 
0000x0100
and 0100b = 0x4 in hex  (also 2^pinNbr)


P1DIR |= 0x04;     // P1.2  set as output
P1SEL |= 0x04;     // P1.2  TA0.1 option

So globally the test program is :

#include <msp430g2553.h>

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

void main(void)
{
WDTCTL = WDTPW + WDTHOLD;   // Stop WDT
clockConfig();

P1DIR |= 0x04;     // P1.2  output
P1SEL |= 0x04;     // P1.2  set to TA0.1 
TACCR0 = 7;        // PWM Period
TACCTL1 = OUTMOD_7;    // CCR1 reset/set
TACCR1 = 1;  // CCR1 PWM Ton -> duty cycle
TACTL = TASSEL_2 + MC_1;    // SMCLK, up mode
_BIS_SR(CPUOFF);      // Enter LPM0


If we hook an oscilloscope probe to P1.2 we can see this :



In the lower left rectangle you can verify that the signal frequency is correctly 2MHz.
In the next two pictures you can see the effect of changing the Duty Cycle value (via TACCR1) to 50% and to 75%.

Since the maximum clock frequency of the clock is 16MHz and we need at least an "up" value and a "down" value, it means that the maximum pwm frequency we can obtain is 16/2= 8MHz, as visible below. 


The signal appears heavily rounded mainly due to the way I connected the probe (non shielded cable, about 30cm long, definitely not the best setup to monitor a 8MHz signal).
This high frequency is not really usable for PWM purposes, unless you are happy with 3 duty cycle levels (0%,50%,100%).

This is because your Ton time is defined by a finite number of cycles, if you are working with a T defined by a large number in TACCR0 (thus increasing your period T and lowering your PWM frequency) you can probably have  a fine control over the duty clycle.

So it's a bit of trade off between maximum frequency and detailed control of the duty cycle, where to set the bar really depends on your application.
In many cases you will probably be happy with frequencies of few KHz and about 1% of Duty Cycle increments.

Let's make a numeric example :

Required F = 10KHz -> T = 1 / 10.000 s
Duty Cycle increments = 1% -> dT = 1 / 10.000 * 1 / 100 = 1 / 1.000.000 s

The easiest way to achieve this would be to set SMCLK to run at 1MHz, TACCR0 = 99 (100 cycles/period = 1MHz/100 = 10KHz) and TACCR1 between 0 and 99.

I deliberately chose the lowest possible value for SMCLK, any value equal or bigger than that would 4 do, i.e. SMCLK = 4MHz

-> TTACR0 = 4 * 100 -1 = 399;
-> TACCR1 between 0 to 399 with a minimum increment of 1/4% = 0.25%


Thursday, August 9, 2012

C2000 Launchpad - Code - First look

I finally managed to have my C2000 Launchpad up&running with CCS V5_2.

The process was not really smooth for me as I initially had double entries in controlSuite and the C2000 Launchpad examples were not showing up in CCS (but they were there if I opened controlSuite externally).

I had to uninstall everything (for controlSuite a manual delete of the files since there is no uninstall, or at least I was not able to find it).

On windows 7 64 bit few things did not work (i.e. CCS was not able to update etc) until I realized I had to run the install and later the software as Administrator.
That did the trick, both for controlSuite install and for CCS install / update.

Phew...
If you follow the instructions on the video available on the TI website, you can open the example from the Resource Explorer, load the project etc...

At step 3 I was not really sure which connection to choose, the XDS100V1 USB worked for me


Also, I switched back the 3rd dip switch to "high" since in the TI video by Trey German (thanks Trey, cool stuff! looking forward for more of your videos!) there is a mention to the fact that enables /disables the jtag debug interface.

So, compiled and debugged, no issues there.

Following the code you immediately realize, if you played before with the "little brother" MSP430G2 Launchpad, that the "piccolo" is totally another animal.

Code appears immediately mode "high level", as I expected, in line with what I found dealing with the Cortex M3 I played with.

Code seems quite "elegant" (not that I don't like the "hardcore" style of the MSP430 code, I actually love it) and probably designed to better fit in bigger applications.

This is the loop that manages the sequential blinking of the blue leds in the pre-installed demo


  //Scan the LEDs until the pushbutton is pressed
    while(GPIO_getData(myGpio, GPIO_Number_12) != 1)
    {       
        GPIO_setHigh(myGpio, GPIO_Number_0);
        GPIO_setHigh(myGpio, GPIO_Number_1);
        GPIO_setHigh(myGpio, GPIO_Number_2);
        GPIO_setLow(myGpio, GPIO_Number_3);
        DELAY_US(50000);

        GPIO_setHigh(myGpio, GPIO_Number_0);
        GPIO_setHigh(myGpio, GPIO_Number_1);
        GPIO_setLow(myGpio, GPIO_Number_2);
        GPIO_setHigh(myGpio, GPIO_Number_3);
        DELAY_US(50000);

        GPIO_setHigh(myGpio, GPIO_Number_0);
        GPIO_setLow(myGpio, GPIO_Number_1);
        GPIO_setHigh(myGpio, GPIO_Number_2);
        GPIO_setHigh(myGpio, GPIO_Number_3);
        DELAY_US(50000);

        GPIO_setLow(myGpio, GPIO_Number_0);
        GPIO_setHigh(myGpio, GPIO_Number_1);
        GPIO_setHigh(myGpio, GPIO_Number_2);
        GPIO_setHigh(myGpio, GPIO_Number_3);
        DELAY_US(500000);
    }

I would say it is definitely readable and you don't need to know the names of the registers to make sense of it.

It appears that they used a good naming convention where all the calls are prefixed with the name of the involved peripheral, which will be GPIO, ADC, CLK...

And check this :


    fid = fopen("scia","w");
    freopen("scia:", "w", stdout);
    setvbuf(stdout, NULL, _IONBF, 0);

Oh yeah, that's your serial port saying "hello" there.
How to configure the baud rate?


#if (CPU_FRQ_60MHZ)
    SCI_setBaudRate(mySci, SCI_BaudRate_115_2_kBaud);  

Want to send some bytes over the serial port?

void updateTemperature(void)
{
    // Restore cursor position
    putchar(0x1B);
    putchar('[');
    putchar('u');  
    printf("%d Celcius = Ref + %d ", currentTemp, (currentTemp - referenceTemp));   
}


Honestly I found really cool with the MSP430G2 USCI to be able to set the parameters for modulation etc... but, ok, this looks way easier.
All this is possible with the support of  various header files, there is one for each peripheral

Overall, first impression : thumbs up!


Tuesday, August 7, 2012

MSP430G2 - Timers and Low Power Modes

Like all the MCUs the MSP430 has timers.
Timers are extremely useful in various applications, a typical usage is to generate an interrupt every X micro / milli / seconds to perform a given task.

I could create a very simple project to experiment with the timer, but I decided it  would have been nicer to add some timer functionality to my last experiment, about SPI communication.

In the last experiment I sent commands to a digital pot (MCP4131) via the SPI line, moving it's wiper to generate a low frequency (~1Hz) triangle waveform.

The idea was to send a value, then delay for a number of cycles (20000), then send the next value etc.
That's ok for a simple experiment, but it is definitely not best practice.
In general you don't want the MCU just counting cycles since in real applications you may have other activities to perform in parallel and their duration would affect your delay.
Even if you are not doing anything else, it would be better to set the MCU in sleep mode (low power) and wake it up just  in time to send the new wiper value to the digital pot.

That's were timers come in help, particularly with the MSP430G2 MCUs.
These devices are designed to support very low power (sleep) modes while keeping some functionality active.
The following picture shows the typical current used by the MSP430 mcu (Fxxx for the specific chart, but we can assume a similar profile for the Gxxx ones), you can see how it drops when entering low power modes (LPM).


Ideally we would like to select the most conservative mode (LPM4), however we need to check that the set of functionality we need are active in the mode we choose.


First thing to understand is that in LPM the CPU is NOT active.
It means that code placed in a normal loop in the main function would not be executed.
So, how can we still "do something" with the CPU?
It will respond to interrupts, including those generated by timers, then it will execute the code of the interrupt functions we will provide.

The second important thing to check is that some clock systems are turned off in LP modes and in some cases also the digital oscillators could be turned off.

In all LP modes the Master Clock (MCLK) is not active, it makes sense as the CPU is off too.
However we are using SMCLK for the SPI communication, so we will need that one on.
Moreover our source oscillator is  DCO, we will need that one active too. 

Using the table 2-2 (from the MSP430 user guide) we identify LPM0 as the only LP mode that supports what we need.

Also, we will need a timer, and timers also use a clock, we will make sure that the selected one is going to be SMCLK.

Our setup procedure will be :

//Timer
void setupTimer()
{
 TACCTL0 = CCIE;   // Timer A Capture / Compare 0 interrupt enabled
 TACCR0 = delCycles; // cycles to count
 TACTL = TASSEL_2 + MC_2;  // SMCLK, contmode
}

The Timer A Capture / Compare ConTroL 0 (TACCTL0) is used to enable the interrupt generation.
The Timer A Control Register 0 (TACCR0) will hold the number of cycles needed to generate an interrupt (it's a 16 bit value ->0x0000 to 0xFFFF).
Finally the TACTL register selects which clock source is used, an eventual divider and the timer mode.

TACTL register

While the registers TACTL and TAR -the time counter- are related to the timer itself, the TACCxxx registers are related to the capture / compare devices associated to that timer.
There are up to 3 CC devices in timer A (more on timer B) and each one of them can be configured to trigger at a different counter level using their register TACCRx.
They can also be configured in different ways using their TACCTLx  control registers, in this first experimet we will just enable for them the Interrupt. 

There are four timer modes, probably for our purpose anyone of them could do, but we would need to adjust our code accordingly.
Probably mode 1 is the easiest to use, followed by mode 2.


Mode zero is just used to stop the timer, should not need any further explanation.

Mode 1 "Up" tells the timer to count up to a value stored in TACCR0, fire an interrupt if enabled and the restart from zero.

Mode 2 "Continuous" instead keeps counting up to 0xFFFF but fires the eventual interrupt when the value reaches what we store in TACCR0.

Mode 3 "Updown" acts similarly to Mode 1, but, instead of resetting when reaching TACCR0, it starts counting down to zero.

  

Since the wiper level will not be managed in a loop now, we need two global variables, one holding the wiper level and one holding the direction of the ramp, so that we can properly increment / decrease the value.
I added a third variable to hold the number of (SMCLK) cycles to wait.

 unsigned char potLevel;
 unsigned char potDir;
 unsigned int delCycles;
...
void main(void)
{
// setup
 WDTCTL = WDTPW + WDTHOLD;
 clockConfig();
 pinConfig();
 spiConfig();
 potLevel=0;
 potDir=1;
 delCycles = 20000;
 setupTimer();
 _BIS_SR(LPM0_bits + GIE);  // Enter LPM0 w/ interrupt
}

// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
  setPotValue(potLevel);// SPI communication
  potLevel += potDir; // increment or decrease
  if (potLevel>127) // potLevel is unsigned, below zero will be 255 
  {
potDir = -potDir;
potLevel +=potDir;
  }
                    // set the next interrupt delay
  TACCR0 += delCycles; // we are in continuous mode! (Mode 2)
}

The main function is updated to initialize the global variables and to set up timer A, plus an interrupt function is created to handle the timer interrupt. 

Finally the instruction _BIS_SR(LPM0_bits + GIE) sets the CPU in LPM0 with Interrupts enabled.
Notice that we don't need anymore a loop to handle the execution, the CPU will be disabled and will be awaken by the interrupt generated by Timer A.

Timers can also be used for different purposes, with these MCUs they support also PWM functionality with direct output to IO pins.
I will cover these aspects in a future post.

Note : all the images are taken from the MSP430 user guide, by Texas Instruments.
The document can be downloaded here.








Monday, August 6, 2012

C2000 Piccolo LaunchPad

The FedEx guy just left and I am holding my new C2000 Piccolo Launchpad in my hands!
While I will keep experimenting with the MSP430G2, I am also planning to give the C2000 a go, seems an interesting MCU.

I think Texas Instruments is doing a great job providing a wide range of solutions and a good support for learning and implementing them.
Don't get me wrong, I don't get any sponsorship from TI and as a matter of facts I believe Microchip and Atmel are doing nice stuff too.

What I like in this TI effort is their very low cost, easy entry point.
I think the whole launchpad idea is great, it makes it easier for beginners to discover the MCU world.
Still, it's not as easy as an Arduino, but, I believe, if you put in a bit more effort, you can also learn more.


I don't know yet how different is to code for the C2000 versus the MSP430G2, I expect it a bit more complex, but sure it helps that you can use the same tool (Code Composer Studio).
C2000 is a 32 Bit MCU, definitely more powerful than the MSP430G2 and targeted to different applications, but the concepts are pretty much the same.
I have been playing around with a Cortex M3 (an NXP), used a differen Dev environment, but still you can find some similarities.

 I expect (to be confirmed) the C2000 being a bit more like the M3 maybe.
Technically the launchpad works the same way the MSP430 one does, so I should be able to get started soon.
The board itself is similar to the previous launchpad


You can notice this one comes with (pre-assembled) double line headers.
Obviously the C2000 has a higher pin count, so this has to be reflected in the expansion headers.
MSP430 on the left, C2000 on the right

One strange thing is that the expansion headers can be accesses from both sides of the pbc, I don't know (yet) why, presumably to make it easier to connect multiple shields.
I don't think that's to plug it directly on a breadboard, as the double line would actually prevent that,


I will post an update as soon as I am able to test it.
If you are interested, you can find some more info on this product here (TI website).

Update : if you want to test the demo application, you need to setup your hardware as suggested in this video (I strongly recommend you watch it, found some info that I was not able to find in the "getting started" pdf)


To recap, you need to place 3 jumpers in -jp1,jp2,jp3- (they were not included with my launchpad, luckily I always have a few jumpers around) to enable the launchpad to be powered by the USB.
Plus you will need to place the switches as visible in the picture below.
Note that the switch 3 set to off disables the JTAG debugger, you need to turn that back on if you want to debug your code in the launchpad.



Sunday, August 5, 2012

Fingers crossed

It's going to happen soon.
Not sure if I will have popcorns with me as it will be early in the morning here in Eruope and popcorns are not my favorite breakfast.
They call it "the seven minutes of terror" and in those seven minutes the most daring, complex space probe landing will happen.
Curiosity will hit Mars, hopefully it will slow down as planned before, this is supposed to happen at around 5AM GMT on Monday August 6th 2012, few hours from now.

I know you may think : "we did that before, nothing new".
Nope, we did not, not this way.

This landing procedure is something so complex that nobody ever tried it before.
Landing an autonomous probe packed with sensors and communication devices on another planet is never an easy task.
This one is much bigger and heavier than the ones that landed before, it has the size and weight of a small car, making things ever harder.

Normally the technique used to slow down the probes before the touch down and protect them from the impact relies on parachutes and airbags.
In this case, due to the mass of the probe, Nasa realized the parachute would have not been enough to slow down  Curitosity.
They had to create a sequence of interventions to slow it down, each step will decelerate the probe in a specific speed range and will uses a different system.


Video from NASA

The first part will use a traditional approach :
The probe will enter Mars atmosphere with a precise angle, a speed of about 13.000 Miles per hour and a shield will protect it from the enormous heat generated by the friction against the atmosphere.

This phase will allow the first deceleration (most of the speed reduction is obtained this way), down to a speed at which, controlling the trajectory and orientation with small rockets, a big parachute can be deployed.
At this point the front shield is separated from the probe.
Getting closer to the surface, with a speed of about 175Mph the parachute will be detached together with the back shell and the probe, now leveled with the surface, will start a free fall descent, controlled by small rockets.
This free fall is then decelerated with rockets, much like the LEM landing in the Apollo mission, however the gravity constant on Mars is about 3.7 m/s2 which, while it is considerably lower than the Eaths's one (9.8m/s2), is roughly double of the Moon's one.
Nasa did not want all that mass attached to the probe at the moment of the touch down, so they opted for a novelty : the sky crane.
Few meters (about 30 according to the simulation) above the surface, the actual rover will detach from the device that contains the rocket engines, which will act as a crane and hopefully will gently place Curiosity on the surface, detaching itself right after the touchdown and flying away to avoid potential collisions with the rover.



While each single step has many risks and possible reasons to fail, the most critical one is probably after the back shell is detached.
Due to the time it takes to communication to travel between Mars and Earth and then back, the whole process needs to be completely autonomous and no intervention will be possible from the control center.

You can preview the whole process in a nice computer simulation here : eyes.nasa.gov
It also provides a "live" option which, while still clearly being a simulation, shows the current situation with (hopefully) the current position of the probe.


In the picture you can see the how it should look now, at the time I am writing.

I am glad that human kind can still "push the limit", dare to face complexity and learn from it.
Success in this project is not granted, there are obviously good reasons to be optimistic, but the number of variables involved suggests that anything could go wrong, anytime.
Any way this is going to end, it's a great project.
There will be a live webcast and a lot of fingers crossed.

[update after landing .: it worked!! everything was smooth and as planned, communication was solid during the process and some images were immediately sent right after the touchdown
http://mars.jpl.nasa.gov/msl/multimedia/raw/ ]


Thursday, August 2, 2012

MSP430G2 - (USCI) SPI interface 3

I learnt something and that, by itself, its awesome.

In the previous post I discussed an issue I found with my procedure that handles the SPI communication between the launchpad and a digital pot.

Communication was working until I configured the SPI master to send out bits starting from MSB instead of LSB (like it should).
At that point the digital pot was not responding anymore (before it was responding and getting wrong values as bits were reversed).
Digging into the issue I found that with the MSB setting the MOSI line was keeping the value of the last bit sent, even after the communication was over.

I think it was a fair assumption since with LSB first I saw each time the MOSI line drop to low... but it was a wrong assumption.
Since I was sending 7 bit values, when they are serialized starting from LSB, the last bit in a (8 bit) byte is always ZERO, so the mosi line was still keeping the value of the last bit sent, regardless of MSB/LSB settings.

Posted a question about this on the TI forum and that's how I learnt something!
SPI does not define any specific idle state for data (miso/mosi) lines (while it does for the clock signal), so the behavior I found is "normal".
However, since I am experimenting with one single slave on the bus, I disregarded the Chip Select (CS) management and apparently this, in combination with the mosi line changing idle state, caused the problem.
I think this has to do with the SPI mode selection of the mcp4131, but I found the datasheet a bit cryptic on this subject, so I will not quote it here.

So I added the CS management and also switched to the USCI port B.

void setPotValue(unsigned char dataOut)
{
P1OUT &= ~BIT3; // enable slave (CS to Low)
UCB0TXBUF = 0;  // Send command
while (!(IFG2 & UCB0TXIFG)); // wait for TX buffer ready
UCB0TXBUF = dataOut; // Send wiper level
while (!(IFG2 & UCB0TXIFG)); // wait for TX buffer ready
P1OUT |= BIT3; // disable Slave (CS to High)
}

The CS signal has to be driven LOW to enable the chip and high to disable it, this wraps the data transmission.

Still something did not work, and checking with the Oscilloscope I found this :
(In red the clock, in yellow the CS line)


CS is enabled correctly right before the clock starts to oscillate, but then it is disabled BEFORE the last bit is sent.
This is happening because I was just waiting for the TX buffer to complete, which does not ensure that physically the bits have been transmitted on the line.

The UCXxSTAT status register has a bit (UCBUSY) that indicates if a TX or RX operation is in process.
Adding the following line

while (UCB0STAT & UCBUSY); // wait for the tx to complete

before disabling CS fixed the issue


And the digital pot output is (used as a voltage divider between vcc and gnd) :





Finally, the overall code (uses port usci B on pins clk = 1.5 , mosi = 1.7 ) is :


#include <msp430g2553.h>
 unsigned char potLevel;

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 pinConfig()
{
 // set the pin mode 3 for pins 5,6 & 7 of port 1 (USCI mode)
 P1SEL = BIT5 + BIT6 + BIT7; // low bit = 1 for pins 5,6 and 7 BIT 3 is 0 (CS via GPIO)
 P1SEL2 = BIT5 + BIT6 + BIT7; // high bit = 1 for pins 5,6 and 7 BIT 3 is 0 (CS via GPIO)
 P1DIR |= BIT3; // p1.3 set to output to drive CS
 P1OUT |= BIT3; // pull p1.3 to high - CS high -> chip is disabled
}

// USCI
void spiConfig()
{
 UCB0CTL1 = UCSWRST; // reset
 UCB0CTL0 |= UCCKPL +UCMST  + UCSYNC +UCMSB; // synchronous (=SPI) master 3 wire SPI, clock polarity High
 UCB0CTL1 |= UCSSEL_2; //use SCLK : 4MHz (MCP4131 supports up to 10MHz write via SPI)
  // set baud rate = SMCLK, no further division
 UCB0BR0 = 0;
 UCB0BR1 = 0;
 UCB0CTL1 &= ~UCSWRST; // **Initialize USCI **
}

// drives a MCP4131 digital potentiometer via SPI
void setPotValue(unsigned char dataOut)
{
 P1OUT &= ~BIT3; // enable slave (CS to Low)
 UCB0TXBUF = 0;  // Send command
 while (!(IFG2 & UCB0TXIFG)); // wait for TX buffer ready
 UCB0TXBUF = dataOut; // Send wiper level
 while (!(IFG2 & UCB0TXIFG)); // wait for TX buffer ready
 while (UCB0STAT & UCBUSY); // wait for the tx to complete
 P1OUT |= BIT3; // disable Slave (CS to High)
}

void main(void)
{
// setup
 WDTCTL = WDTPW + WDTHOLD;
 clockConfig();
 pinConfig();
 spiConfig();
    // program execution loop
 while (1)
 {
  for (potLevel=0;potLevel<127;potLevel++)
  {
   setPotValue(potLevel);
   __delay_cycles(20000);
  }
  for (potLevel=127;potLevel>0;potLevel--)
  {
   setPotValue(potLevel);
   __delay_cycles(20000); 
  }
 }}