diff --git a/boards/debug/board_config.h b/boards/debug/board_config.h index bd3f93b..7b7d249 100644 --- a/boards/debug/board_config.h +++ b/boards/debug/board_config.h @@ -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 diff --git a/bsp/bsp_adc.cpp b/bsp/bsp_adc.cpp index 3486fe3..910c921 100644 --- a/bsp/bsp_adc.cpp +++ b/bsp/bsp_adc.cpp @@ -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; -} \ No newline at end of file +} + +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 +} diff --git a/bsp/bsp_adc.h b/bsp/bsp_adc.h index c204dae..5e7d91e 100644 --- a/bsp/bsp_adc.h +++ b/bsp/bsp_adc.h @@ -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 \ No newline at end of file diff --git a/include/RegisterMap.h b/include/RegisterMap.h index f73f05a..7fb1e89 100644 --- a/include/RegisterMap.h +++ b/include/RegisterMap.h @@ -11,6 +11,8 @@ #define SEESAW_STATUS_OPTIONS 0x03 + #define SEESAW_STATUS_TEMP 0x04 + #define SEESAW_STATUS_SWRST 0x7F //* ============== GPIO =================== *// diff --git a/include/SeesawConfig.h b/include/SeesawConfig.h index dd491ec..01c6cf5 100644 --- a/include/SeesawConfig.h +++ b/include/SeesawConfig.h @@ -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 diff --git a/source/Delegate.cpp b/source/Delegate.cpp index 44fd36b..4fbfd03 100644 --- a/source/Delegate.cpp +++ b/source/Delegate.cpp @@ -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()); diff --git a/source/System.cpp b/source/System.cpp index be7b371..861ac30 100644 --- a/source/System.cpp +++ b/source/System.cpp @@ -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();