The MSP430 DCO (And A Thermocouple)
Posted: March 14, 2015
This project started out as a simple project to connect a thermocouple to an MSP430 so the data can be displayed on a mobile device. This ended up as more of an experiment on the MSP430G2553's digitally controlled oscillator (DCO). The problem with the DCO is it's not an accurate clock source which isn't even consistent between different chips. So my goals for this project ended up being:
I posted my source code to do the calibration at the bottom of this page. Other people may find it useful for their own projects for adjusting their baud rates based on the DCO speed.
I did another project with a similar DCO issue a few months ago: MSP430 VGA with Java. This one used an MSP430F5529 to generate a VGA signal originally with the DCO and the MSP430's built in 32.768kHz crystal calibration which did create a VGA signal, but with a ton of jitter. I ended up fixing it with a real 25MHz crystal.
Related Projects @mikekohn.net
This is the thermocouple circuit with the RedBearLab BLE-Mini and a K type thermocouple.
This video shows on the left an Android phone connected over Bluetooth 2.0 to my older DS18B20 Bluetooth thermometer and on the right an iPod touch connected over BLE to the newer thermocouple circuit. I put both circuits in the freezer to show that the signal is strong enough to go through a refrigerator's wall, that the DCO remains constant, and the thermocouple reacts a lot faster. https://youtu.be/EIMklPfZ-XQ
I'll start with the thermocouple since this is really the most boring part of this project. The parts I used were:
The RedBearLab BLE-Mini wants a UART connection to the micro at 57600 baud which kind of becomes a challenge with the MSP430 DCO. The baud rate divisor is calculated by clock source / baud. For example: 16000000MHz / 9600 baud = 1666 (0x0682):
mov.b #0x82, &UCA0BR0 mov.b #0x06, &UCA0BR1
Since there is no guarantee when setting the DCO that you'll get the frequency you think you're getting, what I've done in the past while using the MSP430's UART is... well first of all I wouldn't run anything above 9600 baud. Then I would calibrate my code for the chip I'm using by looking at an output pin of on an oscilloscope, figuring out how far off my DCO is from that, and adjusting my baud rate constant for this specific chip. If I blew the chip and needed to program a new one, I had to recalibrate my code again.
I actually did think about using an Atmel ATtiny2313 (one of my other favorite chips) for this project with a 20MHz crystal or even just using a built in clock source which is still much more accurate than the DCO, but I really like the MSP430's debugging and programming tools. Also worth noting: according to the msp430x2xx user's guide, the baud rate generator can use a 32.768kHz crystal to get up to 9600 baud, but I haven't tried this yet.
The video above shows this circuit connected over BLE to an iPod touch next to my older thermometer project connected with Bluetooth 2.0. I put both in the freezer proving that the Bluetooth and BLE signals are strong enough to go through my refrigerator walls and that the the DCO appears to be stable during this temperature change. Also, it's interesting to note how much faster the thermocouple reacted to the temperature change vs. the DS18B20.
In order to figure out the speed of the DCO in software I connected a 32.768kHz crystal to Xin/Xout of my MSP430. I set up Timer A and Timer B so that Timer A interrupts every 512 cycles and gets its clock source from the DCO. Timer B interrupts every 32768 cycles and gets its clock source from the 32768 Hz crystal. Therefore Timer B should interrupt once a second and tell how many DCO interrupts there were in that interval. Multiplying the number of DCO interrupts by 512 (aka, binary shift left by 9) should tell how many CPU ticks there were, maybe off by 511 cycles or so.
I wrote some code that would do this multiplication saving the result into 4 bytes of memory and then dividing this number by the baud rate I want. In the thermocouple circut I did this at the top of the program once.
In order to set the DCO speed, there are two constants I use: DCO_x (DCO speed) and RSEL_x (range select):
;; Set MCLK to 16 MHz with DCO mov.b #DCO_4, &DCOCTL mov.b #RSEL_15, &BCSCTL1 mov.b #0, &BCSCTL2
There is also a modulator selection, which gives a frequency between two DCO frequencies. For example in my case where RSEL=15 / DCO=4 I get 14.754MHz and RSEL=15 / DCO=5 I get 15.981MHz. Using the modulator (a value between 0 and 32) I should be able to get some frequencies in between DCO_4 and DCO_5. I've never used this setting before.
So next I took the thermocouple source code and stripped it down so it was just the DCO calibration code. I programmed the chip to cycle through all DCO/RSEL combinations that it could (some ended up not working because the clock speed was too low to generate an accurate baud rate and I ended up with baud barf) and output the frequency results over UART. A Python script collects all the data and builds an HTML table which I posted below:
I ran the exact same firmware on another MSP430G2553 chip and got these quite different results:
Source code assembles with naken_asm.
Copyright 1997-2018 - Michael Kohn