DM: almost working temp sensor

This commit is contained in:
dean 2018-09-11 18:03:18 -04:00
parent 9c33db5f8f
commit f00a1609ba
7 changed files with 169 additions and 17 deletions

View file

@ -5,6 +5,8 @@
#define CONFIG_NO_EEPROM
#define CONFIG_TEMP_SENSOR 1
//* ============== POOL SIZES =================== *//
#define EVT_SIZE_SMALL 16
#define EVT_SIZE_MEDIUM 32

View file

@ -1,5 +1,38 @@
#include "bsp_adc.h"
#define ADC_TEMP_SAMPLE_LENGTH 4
#define INT1V_VALUE_FLOAT 1.0
#define INT1V_DIVIDER_1000 1000.0
#define ADC_10BIT_FULL_SCALE_VALUE_FLOAT 1023.0
static uint32_t tempR; // Production Room temperature
static uint32_t tempH; // Production Hot temperature
static int32_t VADCR; // Room temperature ADC voltage
static int32_t VADCH; // Hot temperature ADC voltage
static uint32_t INT1VR; // Room temp 2's complement of the internal 1V reference value
static uint32_t INT1VH; // Hot temp 2's complement of the internal 1V reference value
static void adc_set_defaults()
{
ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV64 | // Divide Clock by 64.
ADC_CTRLB_RESSEL_10BIT; // 10 bits resolution as default
ADC->SAMPCTRL.reg = 0x3f; // Set max Sampling Time Length
while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains
ADC->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND; // No Negative input (Internal Ground)
// Averaging (see datasheet table in AVGCTRL register description)
ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // 1 sample only (no oversampling nor averaging)
ADC_AVGCTRL_ADJRES(0x0ul); // Adjusting result by 0
ADC->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_DIV2_Val;
ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; // 1/2 VDDANA = 0.5* 3V3 = 1.65V
}
void adc_init()
{
// Initialize Analog Controller
@ -16,21 +49,7 @@ void adc_init()
while( ADC->STATUS.bit.SYNCBUSY == 1 || ADC->CTRLA.bit.SWRST == 1);
ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV64 | // Divide Clock by 64.
ADC_CTRLB_RESSEL_10BIT; // 10 bits resolution as default
ADC->SAMPCTRL.reg = 0x3f; // Set max Sampling Time Length
while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains
ADC->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND; // No Negative input (Internal Ground)
// Averaging (see datasheet table in AVGCTRL register description)
ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // 1 sample only (no oversampling nor averaging)
ADC_AVGCTRL_ADJRES(0x0ul); // Adjusting result by 0
ADC->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_DIV2_Val;
ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; // 1/2 VDDANA = 0.5* 3V3 = 1.65V
adc_set_defaults();
}
void adc_set_freerunning(bool mode)
@ -93,4 +112,104 @@ uint16_t adc_read(uint8_t channel)
syncADC();
return valueRead;
}
}
void init_temp() {
volatile uint32_t val1; /* Temperature Log Row Content first 32 bits */
volatile uint32_t val2; /* Temperature Log Row Content another 32 bits */
uint8_t room_temp_val_int; /* Integer part of room temperature in °C */
uint8_t room_temp_val_dec; /* Decimal part of room temperature in °C */
uint8_t hot_temp_val_int; /* Integer part of hot temperature in °C */
uint8_t hot_temp_val_dec; /* Decimal part of hot temperature in °C */
int8_t room_int1v_val; /* internal 1V reference drift at room temperature */
int8_t hot_int1v_val; /* internal 1V reference drift at hot temperature*/
uint16_t ADCR; // Production Room temperature ADC value
uint16_t ADCH; // Production Hot temperature ADC value
uint32_t *temp_log_row_ptr = (uint32_t *)NVMCTRL_TEMP_LOG;
val1 = *temp_log_row_ptr;
temp_log_row_ptr++;
val2 = *temp_log_row_ptr;
room_temp_val_int = (uint8_t)((val1 & FUSES_ROOM_TEMP_VAL_INT_Msk) >> FUSES_ROOM_TEMP_VAL_INT_Pos);
room_temp_val_dec = (uint8_t)((val1 & FUSES_ROOM_TEMP_VAL_DEC_Msk) >> FUSES_ROOM_TEMP_VAL_DEC_Pos);
hot_temp_val_int = (uint8_t)((val1 & FUSES_HOT_TEMP_VAL_INT_Msk) >> FUSES_HOT_TEMP_VAL_INT_Pos);
hot_temp_val_dec = (uint8_t)((val1 & FUSES_HOT_TEMP_VAL_DEC_Msk) >> FUSES_HOT_TEMP_VAL_DEC_Pos);
room_int1v_val = (int8_t)((val1 & FUSES_ROOM_INT1V_VAL_Msk) >> FUSES_ROOM_INT1V_VAL_Pos);
hot_int1v_val = (int8_t)((val2 & FUSES_HOT_INT1V_VAL_Msk) >> FUSES_HOT_INT1V_VAL_Pos);
ADCR = (uint16_t)((val2 & FUSES_ROOM_ADC_VAL_Msk) >> FUSES_ROOM_ADC_VAL_Pos);
ADCH = (uint16_t)((val2 & FUSES_HOT_ADC_VAL_Msk) >> FUSES_HOT_ADC_VAL_Pos);
tempR = ((uint32_t)room_temp_val_int << 16) + ((1UL << 16)/10 * room_temp_val_dec); //this is gonna be decimal val 1-10?
tempH = ((uint32_t)hot_temp_val_int << 16) + ((1UL << 16)/10 * hot_temp_val_dec);
INT1VR = ((1UL << 16) - 1) - (int16_t)room_int1v_val * 66; //1/1000 V step
INT1VH = ((1UL << 16) - 1) - (int16_t)hot_int1v_val * 66;
VADCR = ((((uint64_t)ADCR << 4) * (uint64_t)INT1VR) >> 16);
VADCH = ((((uint64_t)ADCH << 4) * (uint64_t)INT1VH) >> 16);
}
int32_t calculate_temperature()
{
int32_t VADC; /* Voltage calculation using ADC result for Coarse Temp calculation */
//uint32_t VADCM; /* Voltage calculation using ADC result for Fine Temp calculation. */
//uint32_t INT1VM; /* Voltage calculation for reality INT1V value during the ADC conversion */
ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV32 | // Divide Clock by 32.
ADC_CTRLB_RESSEL_12BIT; // 12 bits resolution
ADC->SAMPCTRL.reg = 0x3f; // Set max Sampling Time Length
while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains
ADC->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND; // No Negative input (Internal Ground)
ADC->INPUTCTRL.bit.GAIN = 0;
// Averaging (see datasheet table in AVGCTRL register description)
ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_4 |
ADC_AVGCTRL_ADJRES(0);
ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INT1V_Val;
SYSCTRL->VREF.bit.TSEN = 1;
//read the ADC channel
uint32_t raw_value = adc_read(ADC_INPUTCTRL_MUXPOS_TEMP_Val);
VADC = (raw_value << 4);
// calculate fine temperature using Equation1 and Equation
// 1b as mentioned in data sheet section "Temperature Sensor Characteristics"
// of Electrical Characteristics. (adapted from ASF sample code).
// Coarse Temp Calculation by assume INT1V=1V for this ADC conversion
int64_t numerator = ( ((int64_t)(VADC - VADCR) * (int64_t)(tempH - tempR)) >> 16 );
int32_t coarse_temp = tempR + ( ( numerator << 16 ) / (VADCH - VADCR) );
return coarse_temp;
#if 0
// Calculation to find the real INT1V value during the ADC conversion
numerator = ( ((int64_t)(INT1VH - INT1VR) * (int64_t)(coarse_temp - tempR)) >> 16);
INT1VM = INT1VR + ( ( numerator << 16 ) / (tempH - tempR));
VADCM = ((int64_t)VADC * INT1VM) >> 16;
// Fine Temp Calculation by replace INT1V=1V by INT1V = INT1Vm for ADC conversion
numerator = ( ((int64_t)(VADCM - VADCR) * (int64_t)(tempH - tempR)) >> 16 );
int32_t fine_temp = tempR + ( ( numerator << 16 ) / (VADCH - VADCR) );
adc_set_defaults();
return fine_temp;
#endif
}

View file

@ -13,4 +13,8 @@ void adc_set_inputscan(uint8_t channels);
uint16_t adc_read(uint8_t channel);
void init_temp();
int32_t calculate_temperature();
#endif

View file

@ -11,6 +11,8 @@
#define SEESAW_STATUS_OPTIONS 0x03
#define SEESAW_STATUS_TEMP 0x04
#define SEESAW_STATUS_SWRST 0x7F
//* ============== GPIO =================== *//

View file

@ -606,6 +606,10 @@
#define CONFIG_ADDR 0ul
#endif
#ifndef CONFIG_TEMP_SENSOR
#define CONFIG_TEMP_SENSOR 0
#endif
#ifndef CONFIG_NO_EEPROM
#define CONFIG_EEPROM 1ul
#endif

View file

@ -40,6 +40,7 @@
#include "bsp_gpio.h"
#include "bsp_sercom.h"
#include "bsp_adc.h"
#include "bsp_nvmctrl.h"
#include "bsp_sercom.h"
@ -195,6 +196,18 @@ QState Delegate::Started(Delegate * const me, QEvt const * const e) {
QF::PUBLISH(evt, me);
break;
}
#if CONFIG_TEMP_SENSOR
case SEESAW_STATUS_TEMP: {
int32_t data = calculate_temperature();
uint8_t ret[4];
me->break32Bit(data, ret);
fifo->Write(ret, 4);
Evt *evt = new DelegateDataReady(req.getRequesterId());
QF::PUBLISH(evt, me);
break;
}
#endif
default:
//Unrecognized command or unreadable register. Do nothing.
Evt *evt = new DelegateDataReady(req.getRequesterId());

View file

@ -36,11 +36,13 @@
#include "RegisterMap.h"
#if CONFIG_POWER_SENSE || CONFIG_TEMP_SENSOR
#include "bsp_adc.h"
#if CONFIG_POWER_SENSE
#include "bsp_gpio.h"
#include "bsp_adc.h"
#include "bsp_neopix.h"
#endif
#endif
#include "bsp_sercom.h"
@ -464,6 +466,12 @@ QState System::Starting(System * const me, QEvt const * const e) {
neopix_show_800k(CONFIG_POWER_SENSE_NEOPIX_PIN, (uint8_t *)&color, 4);
adc_init();
pinPeripheral(CONFIG_POWER_SENSE_ADC_PIN, 1);
#elif CONFIG_TEMP_SENSOR
adc_init();
#endif
#if CONFIG_TEMP_SENSOR
init_temp();
#endif
status = Q_HANDLED();