Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //******************************************************************************
- /******************************************************************************/
- //
- // temp_recorder
- //
- // Interrupt driven, after power-on initialization, the software checks
- // the first free FLASH word to see if run-length encoded data is present.
- // If not, the watchdog timer is configured as a watch crystal controlled
- // interval timer and each 8-second interrupt measures the temperature.
- // But if FLASH has run-length encoded temperature data, it dumps the
- // temperature time and values to the USB debugger terminal window and
- // log file.
- //
- // The 16-bit ADC measures the temperature using a built-in thermistor
- // device. The built-in 'short' interface is used to provide a relative
- // zero. By happy accident, the low-power, 32 oversampling values are a
- // simple offset and shift from 1/10th degree Fahrenheit values. However,
- // the low order three bits suffer from thermal noise and are shifted out.
- //
- // To smooth the data, a five-element, Gaussian filter is used on each
- // data point. This minimizes noise, yet preserves most local peak events.
- //
- // The data from the Gaussian filter is stored in a three level,
- // run-length encoded array. The three levels are the high, middle and
- // low temperatures saved as a byte value and a byte counter. When a new
- // high or new low temperature reading occurs, the last array element is
- // saved as a run-length word and the temperature arrays shift. The
- // run-length word is written to FLASH and the part goes to sleep again.
- //
- // IAR Project -> Options
- // General Options
- // Target -> MSP430F2013
- // Library Configuration -> CLIB
- // Library Options -> printf -> Small
- // C/C++ compiler
- // Optimization -> size -> High (smallest)
- // FET Debugger
- // Erase main and information memory -> to initialize part
- // Retain unchanged memory -> to dump temperature record
- //
- // NOTE: The include files are standard, unmodified, with the IAR system.
- //
- // Bob Wilson, September 19, 2006, bwilson4use@hotmail.com
- //
- /******************************************************************************/
- #include "msp430x20x3.h"
- #include "intrinsics.h"
- #include "stdio.h"
- #include "string.h"
- #include "limits.h"
- //
- // The maximum temperature in 1/10th degrees should be set by
- // the battery chemistry. As for the FLASH itself, the limit is just
- // above 100C.
- //
- #define MAX_TEMP 2200
- union rlen {
- unsigned int temp; // The run length encoded word
- unsigned char rb[2]; // The byte values
- };
- unsigned int * temp_begin; // Lowest data address
- static unsigned int temp_cnt = 0; // Highest code address
- static unsigned int temp_cur = 0; // Current index
- static unsigned char lcnt = 0; // Count of low values
- static unsigned char mcnt = 0; // Count of medium value
- static unsigned char hcnt = 0; // Count of high values
- static unsigned int ltemp = 0; // Low temperature value
- static unsigned int mtemp = 0; // Medium temperature value
- static unsigned int htemp = 0; // High temperature value
- static unsigned int wdt_cnt=0; // Interrupt counters
- static unsigned int sd16_cnt=0;
- #define tcnt 6
- static unsigned int temp[tcnt]; // Temp measurements
- //
- // FLASH operation code runs out of RAM memory in part because
- // it is so slow to write. This following 'flash' module is
- // copied over into RAM, fcode[] and then called with the data to be written
- // and location.
- //
- void flash(unsigned int stemp)
- {
- union rlen rle; // Local data
- //
- // Range testing
- //
- if ( stemp > 32687 ) // Did we measure a negative temp?
- {
- stemp = 0; // Lowest temp is 0
- }
- //
- // Shutoff if TOO HOT!
- //
- if ( stemp > MAX_TEMP ) // Have we reached limit?
- {
- _BIC_SR(GIE); // Stop interrupts
- _BIS_SR(LPM4_bits); // Save yourself, try to shutoff
- }
- //
- // Run-length encoding code
- //
- rle.temp = 0; // Nothing for now
- if ( (lcnt == 0) & (hcnt == 0) & (mcnt == 0) ) // First entry?
- {
- htemp = stemp; // Use first temp for both
- mtemp = stemp; // Medium temperature
- ltemp = stemp; // so we have a start
- lcnt = 1; // Count this one
- return; // Done for now
- }
- //
- // See if we have an ltemp match
- //
- if ( stemp == ltemp )
- {
- if (lcnt < UCHAR_MAX) // Still within count range?
- {
- lcnt++; // Count this low temp
- return;
- }
- rle.temp = ltemp >> 3; // Shift into a byte
- rle.rb[1] = lcnt; // take the count
- lcnt = 1; // Keep temp, restart counter
- }
- //
- // See if we have an mtemp match
- //
- if ( stemp == mtemp )
- {
- if (mcnt < UCHAR_MAX) // Still within count range?
- {
- mcnt++; // Count this low temp
- return;
- }
- rle.temp = mtemp >> 3; // Shift into a byte
- rle.rb[1] = mcnt; // take the count
- mcnt = 1; // Keep temp, restart counter
- }
- //
- // See if we have an htemp match
- //
- if ( stemp == htemp )
- {
- if ( hcnt < UCHAR_MAX ) // Still within count range?
- {
- hcnt++; // Count this high temp
- return;
- }
- rle.temp = htemp >> 3; // Shift into a byte
- rle.rb[1] = hcnt; // take the count
- hcnt = 1; // Keep temp, restart counter
- }
- //
- // See if a new low has arrived
- //
- if (stemp < ltemp) // New cold temperature?
- { // YES - dump the last high
- rle.temp = htemp >> 3; // Bring temp to a byte value
- rle.rb[1] = hcnt; // New RTL is ready
- htemp = mtemp; // Shift up ltemp
- mtemp = ltemp; // save the new mtemp
- hcnt = mcnt; // and counter
- mcnt = lcnt; // save in new mtemp
- ltemp = stemp; // Save the current
- lcnt = 1; // Start counting
- }
- //
- // See if a new high has arrived
- //
- if (stemp > htemp) // New hot temp?
- { // YES - dump the last low
- rle.temp = ltemp >> 3; // Bring temp to a byte value
- rle.rb[1] = lcnt; // New RTL is ready
- ltemp = mtemp; // Shift down htemp
- mtemp = htemp; // into the medium
- lcnt = mcnt; // and counter
- mcnt = hcnt; // including medium counter
- htemp = stemp; // Save the current temp
- hcnt = 1; // Start counting
- }
- //
- // Halt the watchdog, write flash, restart watchdog
- //
- WDTCTL = WDTPW + WDTHOLD; // Turn off the watchdog timer, for now, no recursion
- temp_begin[temp_cur] = rle.temp; // Save the run length encode value
- temp_cur += 1; // Point to next
- if ( temp_cur <= temp_cnt )
- {
- WDTCTL = WDTPW + // Makes the watchdog work as a timer
- WDTSSEL + // use 32,768 kHz clock, / 32768, ~9.5 sec
- WDTTMSEL ; // Puts in interval time mode
- }
- else
- {
- P1OUT = 0x01; // Enable the LED, done.
- }
- }
- void gausian(void)
- {
- unsigned long sum; // Start the conversion
- sum = (6 * temp[3]) + (4 * (temp[2]+temp[4])) + (temp[1]+temp[5]);
- sum /= 16; // Normalize
- sum += 4; // Add half of shift
- sum = sum >> 3; // Shift out lower bits
- sum = sum << 3; // Shift back to normal, *8
- flash( sum ); // Write the flash value
- }
- void start_adc(int sd16inctl0)
- {
- //
- // Configure the SD16_A to read the thermistor voltage
- //
- SD16AE = 0; // No external interfaces
- SD16INCTL0 = sd16inctl0; // Input control register
- SD16CTL = // Control register
- 0 + // clock divider
- SD16LP + // low power mode
- 0 + // clock divider
- SD16SSEL1 + // use ACLK
- 0 + // V(MID) buffer off (not in 2013?)
- SD16REFON + // reference on
- SD16OVIE ; // enable overflow interrupt
- SD16CCTL0 = // Channel 0 control register
- SD16UNI + // unipolar mod
- //SD16XOSR + // extended mode, 1024 sampling
- SD16SNGL + // single conversion
- SD16OSR1 + SD16OSR0 + // 32 oversampling
- 0 + // don't toggle on SD16MEM0 reads
- SD16LSBACC + // read the low order 16-bits
- 0 + // offset binary, not 2s complement
- SD16IE + // interrupt enable
- SD16SC ; // start conversion
- }
- //
- // This is entered via a Power On Reset and the 'glue' logic includes
- // an invisible routine to clear the RAM. By default, the watchdog
- // timer re-enters this way, thus wiping out all flags and counters.
- //
- void main(void)
- {
- WDTCTL = WDTPW + WDTHOLD; // Turn off the watchdog timer, for now, no recursion
- //
- // Setup the clocks for all functions
- //
- BCSCTL3 = 0; // Use Xtal, lowest 1 pf stablity
- BCSCTL2 = SELM1+SELM0 + DIVM1+DIVM0 + DIVS1; // Xtal drives MCLK, /8, DCO -> SCLK
- //
- // We use DCO at 1 mHz, divided by 4, for FLASH writes.
- //
- BCSCTL1 = CALBC1_1MHZ; // Set the calibrated clock value
- BCSCTL1 |= DIVA1+DIVA0; // 1 mHz, Divide Xtal / 8 for ACLK
- DCOCTL = CALDCO_1MHZ; // Set DCO step and modulation
- //
- // Find the available FLASH memory for data storage.
- //
- #pragma segment="DATA16_C"
- #pragma segment="INTVEC"
- temp_cnt = (unsigned int) __segment_end("DATA16_C"); // Grab the last byte
- temp_cnt += 1; // Move up one
- temp_cnt &= 0xfffe; // Round to word boundry
- temp_begin = (unsigned int *) temp_cnt; // Point to first FLASH word
- temp_cnt = (unsigned int) __segment_begin("INTVEC") - temp_cnt; // Remember the end
- temp_cnt /= 2; // Make it a word count
- if ( temp_begin[0] == 0xffff ) // Is first flash still unused?
- {
- FCTL1 = FWKEY + WRT; // Make flash writable
- FCTL2 = FWKEY + FSSEL_3 + FN2; // Use SCLK, / 4
- FCTL3 = FWKEY ; // Turn off the locks,
- //
- // Setup the watchdog timer as an interval timer
- //
- WDTCTL = WDTPW + // Makes the watchdog work as a timer
- WDTSSEL + // use 32,768 kHz clock, / 32768, ~9.5 sec
- WDTTMSEL ; // Puts in interval time mode
- IE1 |= WDTIE; // Enable timer interrupts when GIE enabled
- //
- // Initialize the output LED port and go to sleep
- //
- _BIS_SR(GIE); // Enable the interrupts
- //
- // Enter the lowest possible, wait state pending interrupt(s).
- //
- P1DIR |= 0xFF; // Avoid floating pins drain, set unused to output
- P1OUT = 0x01; // Enable LED
- _BIS_SR(LPM3_bits); // Turn off CPU in idle loop
- // MCLK, SMCLK, DCO osc disabled
- // DC gen. disabled
- // ACLK remains active
- // LED still flashes
- //
- }
- else // No - report the values
- {
- int i = 0; // Counter for flash memory
- unsigned long sec = 0; // Counter for elapsed time
- union rlen rle; // Local decoder for run length
- unsigned int ltemp=0; // Local time
- while ( temp_begin[i] != 0xffff ) // Pass through data
- {
- rle.temp = temp_begin[i]; // Pickup compressed into two bytes
- if ( rle.rb[1] > 0 ) // Is this a counted temperature?
- {
- printf("%ld,", sec); // Lets see the last second start
- sec += rle.rb[1]; // Add the seconds byte to new end time
- rle.rb[1] = 0; // Clear out the temp bits
- ltemp = rle.temp << 3; // Restore temperature
- printf("%d\n%ld,%d\n",
- ltemp, sec, ltemp); // Lets see the temperature
- }
- i += 1; // Point to next
- }
- }
- }
- // 0xFFF4 Watchdog Timer - start temperature measurement
- #pragma vector=WDT_VECTOR
- __interrupt void wdt_vector(void)
- {
- wdt_cnt +=1; // Count ISR
- if ( wdt_cnt >= tcnt ) // Have we reached limit of temp array?
- {
- gausian(); // Convert the gausian array
- }
- start_adc(SD16INCH2 + SD16INCH1); // Begin temperature recording
- if ( temp_begin[0] == 0xffff ) // Are we still getting started?
- {
- P1OUT ^= 0x01; // Flash LED to other state
- }
- else
- {
- P1OUT = 0; // Everything off
- }
- }
- // 0xFFEA Sigma Delta ADC
- #pragma vector=SD16_VECTOR
- __interrupt void sd16_vector(void)
- {
- sd16_cnt +=1; // Count ISR
- int i; // Counter for data shifts
- SD16IV = 0; // Suppress recursive interrupt
- i = SD16INCTL0 & (SD16INCH2+SD16INCH1+SD16INCH0) ; // Get the source bits
- if ( i == (SD16INCH2+SD16INCH1+SD16INCH0) ) // Was this a zero request?
- {
- temp[0] = temp[0] - SD16MEM0; // Adjust for zero
- temp[0] /= 4; // Scale to 0.1F
- temp[0] -= 4516; // Offset to base for 32 F.
- temp[0] += 4; // Add half of shift
- temp[0] = temp[0] >> 3; // Shift out lower bits
- temp[0] = temp[0] << 3; // Shift back to normal, *8
- for (i=tcnt-1; i > 0; i--) // Pass through existing array
- {
- temp[i] = temp[i-1]; // Shift all values up
- }
- temp[0] = 0; // Clear the low
- }
- else // No, assume a data request
- {
- temp[0] = SD16MEM0; // Get the value
- start_adc(SD16INCH2 + SD16INCH1 + SD16INCH0); // Get the zero to adjust
- }
- }
- // End of code segment?
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement