Jump to content
oPossum

How to use temperature calibration data

Recommended Posts

[tipdf]SLAU144[/tipdf] chapter 24 describes the calibration data stored as TLV (tag length value) in info segment A. There are ADC values for 30C and 85C for both 1.5V and 2.5V internal reference voltages. These temperature calibration values can be used to improve the accuracy of the internal temperature sensor. There is no explanation of how to do this, so here is how to do it...

 

Before using calibration data it would be a good idea to validate the info segment checksum. The checksum is stored in the first word and is the negative of the XOR of all of the following words. This function will return 0 for a valid checksum.

unsigned verify_info_chk(const unsigned * const begin, const unsigned * const end)
{
   const unsigned *p = begin + 1;                      // Begin at word after checksum
   unsigned chk = 0;                                   // Init checksum
   while(p < end) chk ^= *p++;                         // XOR all words in segment
   return chk + *begin;                                // Add checksum - result will be zero if checksum is valid
}

 

Each chunk of calibration data in the info segment has a unique tag. This function will search for a specified tag and return a pointer to it. It will return NULL if the tag is not found.

void const *find_tag(const unsigned * const begin, const unsigned * const end, const unsigned tag)
{
   const unsigned *p = begin + 1;                      // Begin at word after checksum
   do {                                                //
       const unsigned d = *p++;                        // Get a word
       if((d & 0xFF) == tag) return (void *)p;         // Return pointer if tag matches
       p += (d >> 9);                                  // Point to next tag
   } while(p < end);                                   // While still within segment
   return 0;                                           // Not found, return NULL pointer
}

 

A structure would be handy for using the ADC/temperature cal data...

typedef struct {
   unsigned adc_gain;                                  // ADC gain
   unsigned adc_offet;                                 // ADC offset
   unsigned ref15;                                     // ADC value of 1.5 volt input when using 1.5 volt reference
   unsigned t3015;                                     // ADC value of 30C when using 1.5 volt reference
   unsigned t8515;                                     // ADC value of 85C when using 1.5 volt reference
   unsigned ref25;                                     // ADC value of 2.5 volt input when using 2.5 volt reference
   unsigned t3025;                                     // ADC value of 30C when using 2.5 volt reference
   unsigned t8525;                                     // ADC value of 85C when using 2.5 volt reference
} TCAL;

 

Find tag 0x08 and setup a pointer to the struct...

   const TCAL * const cal = (TCAL *)find_tag(info_seg_a, info_seg_a_end, 0x08);

 

Now the scale and offset values for the temperature conversion formulas can be calculated...

   const long cc_scale = ((85L - 30) << 16) / (cal->t8515 - cal->t3015);
   const long cc_offset = -(cal->t3015 * cc_scale) + (30L << 16) + (1 << 15);
   const long ck_offset = cc_offset + (273.15 * (1L << 16));
   const long cf_scale = ((185L - 86) << 16) / (cal->t8515 - cal->t3015);
   const long cf_offset = -(cal->t3015 * cf_scale) + (86L << 16) + (1 << 15);

 

Those formulas show the derivation, they can be simplified and combined with basic error handling. The scale and offset values will be zero if the checksum is invalid or the calibration data is not found.

   const TCAL * const cal = (TCAL *)(verify_info_chk(info_seg_a, info_seg_a_end) \
        ? 0 \
        : find_tag(info_seg_a, info_seg_a_end, 0x08));
   const long cc_scale  = cal ? 3604480L / (cal->t8515 - cal->t3015) : 0;
   const long cf_scale  = cal ? 6488064L / (cal->t8515 - cal->t3015) : 0;
   const long cc_offset = cal ? 1998848L - (cal->t3015 * cc_scale) : 0;
   const long cf_offset = cal ? 5668864L - (cal->t3015 * cf_scale) : 0;
   const long ck_offset = cc_offset + 17901158L;

 

In some cases you may want to default to the uncalibrated values...

   const TCAL * const cal = (TCAL *)(verify_info_chk(info_seg_a, info_seg_a_end) \
        ? 0 \
        : find_tag(info_seg_a, info_seg_a_end, 0x08));
   const long cc_scale  = cal ? 3604480L / (cal->t8515 - cal->t3015) : 27069L;
   const long cf_scale  = cal ? 6488064L / (cal->t8515 - cal->t3015) : 48724L;
   const long cc_offset = cal ? 1998848L - (cal->t3015 * cc_scale) : -18169625L;
   const long cf_offset = cal ? 5668864L - (cal->t3015 * cf_scale) : -30634388L;
   const long ck_offset = cc_offset + 17901158L;

 

 

Now the actual scaled temperature values can be calculated with the usual scale/offset formulas...

       dcc = ((cc_scale * adc) + cc_offset) >> 16;     // C calibrated
       dkc = ((cc_scale * adc) + ck_offset) >> 16;     // K calibrated
       dfc = ((cf_scale * adc) + cf_offset) >> 16;     // F calibrated

 

Code for Nokia 7110 that will show uncalibrated (left) and calibrated (right) temperature in F, C, and K.

 

post-2341-135135546262_thumb.jpg

 

main.cpp

#include 
#include 

#include "nokia7110tl.h"

using namespace nokia7110;


/*
   P1.0    Reset
   P1.3    Temp Sensor (Not used)
   P2.0    Serial Data
   P2.1    Backlight
   P2.2    Chip Select
   P2.3    Data/Command
   P2.4    Serial Clock
   P2.5    Button
*/

// P1
static const unsigned LCD_RESET = BIT0;
static const unsigned RXD = BIT2;
static const unsigned SWITCH = BIT3;

// P2
static const unsigned LCD_DATA = BIT0;
static const unsigned LCD_BACKLIGHT = BIT1;
static const unsigned LCD_CE = BIT2;
static const unsigned LCD_DC = BIT3;
static const unsigned LCD_CLK = BIT4;
static const unsigned LCD_BTN = BIT5;


Nokia7110 lcd;

// Print integer from -999 to 9999 using 12 x 16 font
void print_int(int i, unsigned x, const unsigned y)
{
   if(i < -999 || i > 9999) return;
   const unsigned e = x;
   x += 48;
   const unsigned neg = i < 0;
   if(neg) i = -i;
   div_t d; d.quot = i;
   do {
       d = div(d.quot, 10);
       lcd.pd12(d.rem, x -= 12, y);
   } while(d.quot);
   if(neg) lcd.pd12(14, x -= 12, y);
   while(x > e) lcd.pd12(10, x -= 12, y);
}

// Print integer from -999 to 9999 using 6 x 8 font
void print_int_small(int i, unsigned x, const unsigned y)
{
   if(i < -999 || i > 9999) return;
   const unsigned e = x;
   x += 24;
   const unsigned neg = i < 0;
   if(neg) i = -i;
   div_t d; d.quot = i;
   do {
       d = div(d.quot, 10);
       lcd.print(x -= 6, y, '0' + d.rem);
   } while(d.quot);
   if(neg) lcd.print(x -= 6, y, '-');
   while(x > e) lcd.print(x -= 6, y, ' ');
}

#pragma vector = ADC10_VECTOR                           // ADC conversion complete interrupt
__interrupt void ADC10_ISR(void)                        //
{                                                       //
   __bic_SR_register_on_exit(LPM0_bits);               // Wakeup main code
}                                                       //

unsigned verify_info_chk(const unsigned * const begin, const unsigned * const end)
{
   const unsigned *p = begin + 1;                      // Begin at word after checksum
   unsigned chk = 0;                                   // Init checksum
   while(p < end) chk ^= *p++;                         // XOR all words in segment
   return chk + *begin;                                // Add checksum - result will be zero if checksum is valid
}

void const *find_tag(const unsigned * const begin, const unsigned * const end, const unsigned tag)
{
   const unsigned *p = begin + 1;                      // Begin at word after checksum
   do {                                                //
       const unsigned d = *p++;                        // Get a word
       if((d & 0xFF) == tag) return (void *)p;         // Return pointer if tag matches
       p += (d >> 9);                                  // Point to next tag
   } while(p < end);                                   // While still within segment
   return 0;                                           // Not found, return NULL pointer
}

typedef struct {
   unsigned adc_gain;                                  // ADC gain
   unsigned adc_offet;                                 // ADC offset
   unsigned ref15;                                     // ADC value of 1.5 volt input when using 1.5 volt reference
   unsigned t3015;                                     // ADC value of 30C when using 1.5 volt reference
   unsigned t8515;                                     // ADC value of 85C when using 1.5 volt reference
   unsigned ref25;                                     // ADC value of 2.5 volt input when using 2.5 volt reference
   unsigned t3025;                                     // ADC value of 30C when using 2.5 volt reference
   unsigned t8525;                                     // ADC value of 85C when using 2.5 volt reference
} TCAL;

int main(void)
{
   unsigned adc;
   int dc, dk, df;                                     // Temperature in degrees C, K, and F
   int dcc, dkc, dfc;                                  // Calibrated temperatures

   const unsigned * const info_seg_a = (unsigned *)0x10C0;     // Address of info segement A
   const unsigned * const info_seg_a_end = info_seg_a + 32;    // 32 words in each segment

   WDTCTL = WDTPW | WDTHOLD;

   P1REN = RXD | SWITCH;
   P1DIR = LCD_RESET; 
   P1OUT = RXD | SWITCH | LCD_RESET;

   P2DIR = LCD_DC | LCD_CE | LCD_CLK | LCD_BACKLIGHT | LCD_DATA;
   P2REN = LCD_BTN;
   P2OUT = LCD_CLK | LCD_DC | LCD_CE | LCD_BACKLIGHT | LCD_BTN;

   ADC10CTL0 = 0;                                      // Configure ADC
   ADC10CTL1 = INCH_10 | ADC10DIV_3;                   //
   ADC10CTL0 = SREF_1 | ADC10SHT_3 | REFON | ADC10ON | ADC10IE;
   ADC10CTL0 |= ADC10IE;                               // Enable ADC conversion complete interrupt
                                                       //
   _EINT();                                            // Enable interrupts
                                                       //

   const TCAL * const cal = (TCAL *)(verify_info_chk(info_seg_a, info_seg_a_end) \
        ? 0 \
        : find_tag(info_seg_a, info_seg_a_end, 0x08));
   const long cc_scale  = cal ? 3604480L / (cal->t8515 - cal->t3015) : 0;
   const long cf_scale  = cal ? 6488064L / (cal->t8515 - cal->t3015) : 0;
   const long cc_offset = cal ? 1998848L - (cal->t3015 * cc_scale) : 0;
   const long cf_offset = cal ? 5668864L - (cal->t3015 * cf_scale) : 0;
   const long ck_offset = cc_offset + 17901158L;

   lcd.reset();                                        //
   lcd.init();                                         //
                                                       //
   lcd.clear();                                        //
                                                       //
   for(; {                                           // for-ever
       ADC10CTL0 |= (ENC | ADC10SC);                   // Begin ADC conversion
       __bis_SR_register(LPM0_bits + GIE);             // Sleep until conversion complete
       adc = ADC10MEM;                                 // Read ADC
                                                       //
                                                       // Convert to temperature
       dc = ((27069L * adc) - 18169625L) >> 16;        // C
       dk = ((27069L * adc) - 268467L) >> 16;          // K
       df = ((48724L * adc) - 30634388L) >> 16;        // F
                                                       //
       dcc = ((cc_scale * adc) + cc_offset) >> 16;     // C calibrated
       dkc = ((cc_scale * adc) + ck_offset) >> 16;     // K calibrated
       dfc = ((cf_scale * adc) + cf_offset) >> 16;     // F calibrated
                                                       //                                                              
                                                       // Display on LCD
       print_int(df, 0, 0);                            // Degrees F
       print_int(dfc, 48, 0);                          // Degrees F calibrated
       print_int(dc, 0, 3);                            // Degrees C
       print_int(dcc, 48, 3);                          // Degrees C calibrated
       print_int(dk, 0, 6);                            // Degrees K
       print_int(dkc, 48, 6);                          // Degrees K calibrated
   }                                                   //

   return 0;
}

 

nokia7110tl.h

namespace nokia7110 {

unsigned char PNONE;

typedef enum {
lcd_command = 0,		// Array of one or more commands
lcd_data = 1,			// Array of one or more bytes of data
lcd_data_repeat = 2		// One byte of data repeated
} lcd_cmd_type;

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
struct Nokia7110
{
void write(const unsigned char *cmd, unsigned len, const lcd_cmd_type type = lcd_data);
void reset(void);
void init(void);
void home(void);
void pos(unsigned char x, unsigned char y);
void clear(unsigned char x = 0);
void fill(unsigned x, unsigned y, unsigned w, unsigned h, unsigned char z);
void bitmap(const unsigned char *bmp, signed char x, signed char y, unsigned char w, unsigned char h);
inline void bitmap(const unsigned char *bmp, signed char x, signed char y) { bitmap(bmp + 2, x, y, bmp[0], bmp[1]); };
void print(char c);
inline void print(unsigned char x, unsigned char y, char c) { pos(x, y); print(c); };
void print(const char *s);
inline void print(unsigned char x, unsigned char y, const char *s) { pos(x, y); print(s); };
void print(const char *s, unsigned char m);
void printv(unsigned char x, unsigned char y, char *s);
void pd12(unsigned n, unsigned x, unsigned y);
};

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::write(const unsigned char *cmd, unsigned len, const lcd_cmd_type type)
{
register unsigned mask;

if(&_EP != &PNONE) _EP &= ~_CE;
do {
    mask = 0x0080;
    do {
        if(*cmd & mask) {
        	_SP |= _DATA;
	        _SP &= ~_CLK;
        } else {
        	_SP &= ~(_CLK | _DATA);
        }
        _SP |= _CLK;
        mask >>= 1;
    } while(!(mask & 1));
    if(!type) {
	    if(&_CP == &PNONE) {
	    	__delay_cycles(_DC);
	    } else {
			_CP &= ~_DC;
	    }
    }
    if(*cmd & mask) {
    	_SP |= _DATA;
        _SP &= ~_CLK;
    } else {
    	_SP &= ~(_CLK | _DATA);
    }
    _SP |= _CLK;
    if(&_CP != &PNONE) _CP |= _DC;
    if(!(type & 2)) ++cmd;
} while(--len);
  	if(&_EP != &PNONE) _EP |= _CE;
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::reset(void)
{
if(&_RP == &PNONE) {
									// --- Set initial state of CLK, DC and CE as needed
									// * = output used for reset
	if(&_CP == &PNONE) {
		if(&_EP != &PNONE) {		// CLK*, DATA, CE
			_EP |= _CE;
		} // else					// CLK*, DATA
	} else {
		if(&_EP != &PNONE) {		// CLK, DATA, DC*, CE
			if(&_SP == &_EP) {
				_SP |= (_CLK | _CE);
			} else {
				_SP |= _CLK;
				_EP |= _CE;
			}
		} else {					// CLK, DATA, DC*
			_SP |= _CLK;
		}
	}
									// --- Reset pulse on CLK or DC as needed
	if(&_CP == &PNONE) {			// No DC port, use CLK to reset
		_SP &= ~_CLK;
		__delay_cycles(_RD);
		_SP |= _CLK;
	} else {						// Use DC to reset
		_CP &= ~_DC;
		__delay_cycles(_RD);
		_CP |= _DC;
	}
} else {
	_RP &= ~_RST;
	if(&_EP != &PNONE) {
		if(&_SP == &_EP) {
			_SP |= (_CLK | _CE);
		} else {
			_SP |= _CLK;
			_EP |= _CE;
		}
	} else {
		_SP |= _CLK;
	}
	__delay_cycles(_RD);
	_RP |= _RST;
}
__delay_cycles(_RD);
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::init(void)
{
/*	static const unsigned char init[] = {
   	0x20 | 0x01,		// Function set - extended instructions enabled
   	//0x80 | 64,			// Set vop (contrast) 0 - 127
   	0x80 | 70,			// Higher contrast improves animation
   	0x04 | 2,			// Temperature control
   	0x10 | 3,			// Set bias system
   	0x20 | 0x00,		// Function set - chip active, horizontal addressing, basic instructions
   	0x08 | 0x04			// Display control - normal mode
};
*/	
static const unsigned char init[] = {
	0xA6, //Display: Normal
	0xA3, //LCD Bias Settings: 1/7
	0xA1, //ADC Selection: Reverse
	0xC0, //Common Output: Normal Direction
	//0xC8, //Common Output: Upside Down
	0x22, //Set the V5 output Voltage
	0x81, //Set Electronic Volume Register
	0x2E, //Power Controller Set
			// Booster circuit: ON
			// Voltage regulator circuit: ON
			// Voltage follower circuit: OFF
	0x2F, //Power Controller Set
			// Voltage follower circuit: ON
	0xE3, //Non-OPeration Command
	0x40, //Set the start line
	0xAF, //LCD On
	//0xA5, //Display All Points: ON
	0xA4, //Display All Points: NORMAL
};

write(init, sizeof(init), lcd_command);
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::home(void)
{
//static const unsigned char home[] = { 0x40, 0x80 };
static const unsigned char home[] = { 0xB0, 0x11, 0x02 };
   write(home, sizeof(home), lcd_command);
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::pos(unsigned char x, unsigned char y)
{
unsigned char c[3];
/*c[0] = 0x80 | x;
c[1] = 0x40 | y;*/
x += 18;
c[0] = 0xB0 | y;
c[1] = 0x10 | (x >> 4);
c[2] = x & 0x0F;
write(c, sizeof(c), lcd_command);
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::clear(unsigned char x)
{
#if 0
   home();
write(&x, 504, lcd_data_repeat);
   home();
#else
for(unsigned y = 0; y < 9; ++y) {
	pos(0, y);
	write(&x, 96, lcd_data_repeat);
}
#endif
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::fill(unsigned x, unsigned y, unsigned w, unsigned h, unsigned char z)
{
#if 0	
unsigned yy = y + h;
unsigned char c[2];
c[0] = 0x80 | x;
for(;y < yy; ++y) {
	c[1] = 0x40 | y;
	write(c, sizeof(c), lcd_command);
	write(&z, w, lcd_data_repeat);
}
#else
unsigned yy = y + h;
unsigned char c[3];
x += 18;
c[1] = 0x10 | (x >> 4);
c[2] = (x & 0x0F);
for(;y < yy; ++y) {
	c[0] = 0xB0 | y;
	write(c, sizeof(c), lcd_command);
	write(&z, w, lcd_data_repeat);
}
#endif
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::bitmap(const unsigned char *bmp, signed char x, signed char y, unsigned char w, unsigned char h)
{
unsigned char c[3];
unsigned char ww;
if(x < 0) {
	ww = w + x;
	bmp -= x;
	x = 0;
} else if(x + w >= 96) {
	ww = (96 - x);
} else {
	ww = w;
}
/*c[0] = 0x80 | x;
c[1] = 0x40 | y;*/
x += 18;
c[0] = 0xB0 | y;
c[1] = 0x10 | (x >> 4);
c[2] = x & 0x0F;
while(h--) {
	write(c, sizeof(c), lcd_command);
	write(bmp, ww);
	bmp += w;
	//++c[1];
	++c[0];
}
}

static const unsigned char font[96][5] = {
0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x5F, 0x00, 0x00, // !
0x00, 0x07, 0x00, 0x07, 0x00, // "
0x14, 0x7F, 0x14, 0x7F, 0x14, // #
0x24, 0x2A, 0x7F, 0x2A, 0x12, // $
0x23, 0x13, 0x08, 0x64, 0x62, // %
0x36, 0x49, 0x56, 0x20, 0x50, // &
0x00, 0x08, 0x07, 0x03, 0x00, // '
0x00, 0x1C, 0x22, 0x41, 0x00, // (
0x00, 0x41, 0x22, 0x1C, 0x00, // )
0x2A, 0x1C, 0x7F, 0x1C, 0x2A, // *
0x08, 0x08, 0x3E, 0x08, 0x08, // +
0x00, 0x40, 0x38, 0x18, 0x00, // ,
0x08, 0x08, 0x08, 0x08, 0x08, // -
0x00, 0x00, 0x60, 0x60, 0x00, // .
0x20, 0x10, 0x08, 0x04, 0x02, // /
0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
0x00, 0x42, 0x7F, 0x40, 0x00, // 1
0x42, 0x61, 0x51, 0x49, 0x46, // 2
0x21, 0x41, 0x49, 0x4D, 0x33, // 3
0x18, 0x14, 0x12, 0x7F, 0x10, // 4
0x27, 0x45, 0x45, 0x45, 0x39, // 5
0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
0x41, 0x21, 0x11, 0x09, 0x07, // 7
0x36, 0x49, 0x49, 0x49, 0x36, // 8
0x06, 0x49, 0x49, 0x29, 0x1E, // 9
0x00, 0x00, 0x14, 0x00, 0x00, // :
0x00, 0x00, 0x40, 0x34, 0x00, // ;
0x00, 0x08, 0x14, 0x22, 0x41, // <
0x14, 0x14, 0x14, 0x14, 0x14, // =
0x00, 0x41, 0x22, 0x14, 0x08, // >
0x02, 0x01, 0x51, 0x09, 0x06, // ?
0x3E, 0x41, 0x5D, 0x59, 0x4E, // @
0x7C, 0x12, 0x11, 0x12, 0x7C, // A
0x7F, 0x49, 0x49, 0x49, 0x36, // B
0x3E, 0x41, 0x41, 0x41, 0x22, // C
0x7F, 0x41, 0x41, 0x41, 0x3E, // D
0x7F, 0x49, 0x49, 0x49, 0x41, // E
0x7F, 0x09, 0x09, 0x09, 0x01, // F
0x3E, 0x41, 0x49, 0x49, 0x7A, // G
0x7F, 0x08, 0x08, 0x08, 0x7F, // H
0x00, 0x41, 0x7F, 0x41, 0x00, // I
0x20, 0x40, 0x41, 0x3F, 0x01, // J
0x7F, 0x08, 0x14, 0x22, 0x41, // K
0x7F, 0x40, 0x40, 0x40, 0x40, // L
0x7F, 0x02, 0x1C, 0x02, 0x7F, // M
0x7F, 0x04, 0x08, 0x10, 0x7F, // N
0x3E, 0x41, 0x41, 0x41, 0x3E, // O
0x7F, 0x09, 0x09, 0x09, 0x06, // P
0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
0x7F, 0x09, 0x19, 0x29, 0x46, // R
0x26, 0x49, 0x49, 0x49, 0x32, // S
0x01, 0x01, 0x7F, 0x01, 0x01, // T
0x3F, 0x40, 0x40, 0x40, 0x3F, // U
0x1F, 0x20, 0x40, 0x20, 0x1F, // V
0x3F, 0x40, 0x38, 0x40, 0x3F, // W
0x63, 0x14, 0x08, 0x14, 0x63, // X
0x03, 0x04, 0x78, 0x04, 0x03, // Y
0x61, 0x51, 0x49, 0x45, 0x43, // Z
0x00, 0x7F, 0x41, 0x41, 0x41, // [
0x02, 0x04, 0x08, 0x10, 0x20, // '\'
0x00, 0x41, 0x41, 0x41, 0x7F, // ]
0x04, 0x02, 0x01, 0x02, 0x04, // ^
0x80, 0x80, 0x80, 0x80, 0x80, // _
0x00, 0x03, 0x07, 0x08, 0x00, // '
0x20, 0x54, 0x54, 0x54, 0x78, // a
0x7F, 0x28, 0x44, 0x44, 0x38, // b
0x38, 0x44, 0x44, 0x44, 0x28, // c
0x38, 0x44, 0x44, 0x28, 0x7F, // d
0x38, 0x54, 0x54, 0x54, 0x18, // e
0x00, 0x08, 0x7E, 0x09, 0x02, // f
0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
0x7F, 0x08, 0x04, 0x04, 0x78, // h
0x00, 0x44, 0x7D, 0x40, 0x00, // i
0x00, 0x20, 0x40, 0x40, 0x3D, // j
0x00, 0x7F, 0x10, 0x28, 0x44, // k
0x00, 0x41, 0x7F, 0x40, 0x00, // l
0x7C, 0x04, 0x78, 0x04, 0x78, // m
0x7C, 0x08, 0x04, 0x04, 0x78, // n
0x38, 0x44, 0x44, 0x44, 0x38, // o
0xFC, 0x18, 0x24, 0x24, 0x18, // p
0x18, 0x24, 0x24, 0x18, 0xFC, // q
0x7C, 0x08, 0x04, 0x04, 0x08, // r
0x48, 0x54, 0x54, 0x54, 0x24, // s
0x04, 0x04, 0x3F, 0x44, 0x24, // t
0x3C, 0x40, 0x40, 0x20, 0x7C, // u
0x1C, 0x20, 0x40, 0x20, 0x1C, // v
0x3C, 0x40, 0x30, 0x40, 0x3C, // w
0x44, 0x28, 0x10, 0x28, 0x44, // x
0x4C, 0x90, 0x90, 0x90, 0x7C, // y
0x44, 0x64, 0x54, 0x4C, 0x44, // z
0x00, 0x08, 0x36, 0x41, 0x00, // {
0x00, 0x00, 0x77, 0x00, 0x00, // |
0x00, 0x41, 0x36, 0x08, 0x00, // }
0x02, 0x01, 0x02, 0x04, 0x02, // ~
0x00, 0x06, 0x09, 0x09, 0x06, // degrees
};

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::print(char c)
{
  	write(&font[c - 32][0], 5);
  	write(&font[0][0], 1);
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::print(const char *s)
{
while(*s) {
   	write(&font[*s - 32][0], 5);
   	write(&font[0][0], 1);
   	++s;
}
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::print(const char *s, unsigned char m)
{
unsigned char c;
while(*s) {
	c = font[*s - 32][0] ^ m; write(&c, 1);
	c = font[*s - 32][1] ^ m; write(&c, 1);
	c = font[*s - 32][2] ^ m; write(&c, 1);
	c = font[*s - 32][3] ^ m; write(&c, 1);
	c = font[*s - 32][4] ^ m; write(&c, 1);
   	write(&m, 1);
   	++s;
}
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::printv(unsigned char x, unsigned char y, char *s)
{
while(*s) {
	pos(x, y);
	++y;
   	write(&font[*s - 32][0], 5);
   	write(&font[0][0], 1);
   	++s;
}
}

static const unsigned char num11x16[19][11 * 2] = {
0x00,0xF0,0xFC,0xFE,0x06,0x02,0x06,0xFE,0xFC,0xF0,0x00,	// 0
0x00,0x07,0x1F,0x3F,0x30,0x20,0x30,0x3F,0x1F,0x07,0x00,
0x00,0x00,0x08,0x0C,0xFC,0xFE,0xFE,0x00,0x00,0x00,0x00,	// 1
0x00,0x20,0x20,0x20,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x00,
0x00,0x0C,0x0E,0x06,0x02,0x02,0x86,0xFE,0x7C,0x38,0x00,	// 2
0x00,0x30,0x38,0x3C,0x36,0x33,0x31,0x30,0x30,0x38,0x00,
0x00,0x0C,0x0E,0x86,0x82,0x82,0xC6,0xFE,0x7C,0x38,0x00,	// 3
0x00,0x18,0x38,0x30,0x20,0x20,0x31,0x3F,0x1F,0x0E,0x00,
0x00,0x00,0xC0,0x20,0x18,0x04,0xFE,0xFE,0xFE,0x00,0x00,	// 4
0x00,0x03,0x02,0x02,0x02,0x22,0x3F,0x3F,0x3F,0x22,0x02,
0x00,0x00,0x7E,0x7E,0x46,0x46,0xC6,0xC6,0x86,0x00,0x00,	// 5
0x00,0x18,0x38,0x30,0x20,0x20,0x30,0x3F,0x1F,0x0F,0x00,
0x00,0xC0,0xF0,0xF8,0xFC,0x4C,0xC6,0xC2,0x82,0x00,0x00,	// 6
0x00,0x0F,0x1F,0x3F,0x30,0x20,0x30,0x3F,0x1F,0x0F,0x00,
0x00,0x06,0x06,0x06,0x06,0x06,0xC6,0xF6,0x3E,0x0E,0x00,	// 7
0x00,0x00,0x00,0x30,0x3C,0x0F,0x03,0x00,0x00,0x00,0x00,
0x00,0x38,0x7C,0xFE,0xC6,0x82,0xC6,0xFE,0x7C,0x38,0x00,	// 8
0x00,0x0E,0x1F,0x3F,0x31,0x20,0x31,0x3F,0x1F,0x0E,0x00,
0x00,0x78,0xFC,0xFE,0x86,0x02,0x86,0xFE,0xFC,0xF8,0x00,	// 9
0x00,0x00,0x00,0x21,0x21,0x31,0x1D,0x1F,0x0F,0x03,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	// 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x70,0x70,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	// :
0x00,0x0E,0x0E,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	// .
0x00,0x38,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xC0,0x30,0x0C,0x00,0x00,0x00,0x00,	// /
0x00,0x30,0x0C,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,	// -
0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x00,0x18,0x3C,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00, // 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xF0,0xF8,0x0C,0x06,0x02,0x02,0x02,0x02,0x0E,0x0C,0x00, // C
0x03,0x07,0x0C,0x18,0x10,0x10,0x10,0x10,0x1C,0x0C,0x00,
0xFE,0xFE,0x42,0x42,0x42,0x42,0x42,0x42,0x00,0x00,0x00, // F
0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xFE,0xFE,0x40,0xE0,0xB0,0x18,0x0C,0x06,0x02,0x00,0x00, // K
0x1F,0x1F,0x00,0x00,0x01,0x03,0x06,0x0C,0x18,0x10,0x00
};

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::pd12(unsigned n, unsigned x, unsigned y)
{
pos(x, y);   write(num11x16[n], 11, lcd_data);
pos(x, ++y); write(num11x16[n] + 11, 11, lcd_data);
}

} // namespace

Share this post


Link to post
Share on other sites

Brilliant. Will try now.

Thank you!!

 

[edit]

Your code works perfectly.

Before calibration: 29C

After calibration: 23C

 

My (messy breadboard) talking clock now has a thermometer feature- thanks to you!

 

P.S.

"there is no dark side in the moon, really. As a matter of fact it's all dark"

Share this post


Link to post
Share on other sites

That's a larger difference that I would expect. Does the calibrated value seem to be closer to correct?

 

Use extreme caution when reading docs for another MSP430 family. They are often very similar, but have some very significant differences. The code in this thread, for example, will not work on F5000/F6000 chips due to differences in the TLV structure and tags.

Share this post


Link to post
Share on other sites
That's a larger difference that I would expect. Does the calibrated value seem to be closer to correct?

Yes it does - 23 Celcius is normal room temperature. I'll check with Maxim DS1624 though.

 

Use extreme caution when reading docs for another MSP430 family. They are often very similar, but have some very significant differences. The code in this thread, for example, will not work on F5000/F6000 chips due to differences in the TLV structure and tags.

 

Actually SLAU144 has the same formulas for MSP430x2xx - page 597 - 600.

http://www.ti.com/lit/ug/slau144i/slau144i.pdf

Share this post


Link to post
Share on other sites

Hi oPossum,

 

Thank you for sharing this code and explaining how it works.

 

I couldn't get this to work on a 2553. According to slas735e, page 15, calibration data for ADC10 is at offset 0x10DA, tag 0x10. The checksum for the segment passes, but I don't see any calibration data there. cal->t8515 is 0, and other values don't make any sense either.

 

Could it be that not all chips are calibrated at the factory?

Share this post


Link to post
Share on other sites

The 0x10 tag is not well documented by TI - it is not in SLAU144. SLAS735 refers to is simply as ADC calibration, but shows temperature calibration in the structure. It may be just for ADC scale/offset calibration and not for temperature calibration. I looked at a few G2553 chips and they did not seem to have valid temperature cal data.

 

The only G series chip that I know has valid temperature calibration is the G2452 - they have tag 0x08.

Share this post


Link to post
Share on other sites

Very cool, finally found a project where I could use the internal temp sensor and this is a good reference. Thanks
Also, pretty sweet html in the forloop there =D . First time i've seen C and HTML mesh.

I checked my memory and had 0s for all 85 measurements but there was data for the 30C measurements. Going to see if I can work something out linear interpolation.

Share this post


Link to post
Share on other sites

Hey I know old thread but...

If we read an ADCraw value, using the 1V5 reference (not necessary the temp sensor). Do we first apply 1V5 gain correction, get an ADC1V5raw and then apply ADC gain and offset correction to that value, getting an ADCcorrected value?

And if we're dealing with the temp sensor, do we take the ADCcorrected value and apply temp correction to that?

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...