Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cores/arduino/wiring.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ void init( void )

analogReference( AR_DEFAULT ) ; // Analog Reference is AREF pin (3.3v)

SYSCTRL->VREF.reg |= SYSCTRL_VREF_TSEN; // Enable the temperature sensor

while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains

// Initialize DAC
// Setting clock
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY );
Expand Down
84 changes: 84 additions & 0 deletions cores/arduino/wiring_analog.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,90 @@ void analogWrite(uint32_t pin, uint32_t value)
}
}

// Reads temperature using internal ADC channel
// Datasheet chapter 37.10.8 - Temperature Sensor Characteristics
float readInternalTemperature()
{
// Save ADC settings
uint16_t oldReadResolution = ADC->CTRLB.reg;
uint16_t oldSampling = ADC->SAMPCTRL.reg;
uint16_t oldReferenceGain = ADC->INPUTCTRL.bit.GAIN;
uint16_t oldReferenceSelect = ADC->REFCTRL.bit.REFSEL;

// Set to 12 bits resolution
ADC->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT | ADC_CTRLB_PRESCALER_DIV256;
syncADC();

// Ensure we are sampling slowly
ADC->SAMPCTRL.reg = ADC_SAMPCTRL_SAMPLEN(0x3f);
syncADC();

// Set ADC reference to internal 1v
ADC->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val;
ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INT1V_Val;
syncADC();

// Select MUXPOS as temperature channel, and MUXNEG as internal ground
ADC->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_TEMP_Val;
ADC->INPUTCTRL.bit.MUXNEG = ADC_INPUTCTRL_MUXNEG_GND_Val;
syncADC();

// Enable ADC
ADC->CTRLA.bit.ENABLE = 1;
syncADC();

// Start ADC conversion
ADC->SWTRIG.bit.START = 1;

// Clear the Data Ready flag
ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY;
syncADC();

// Start conversion again, since The first conversion after the reference is changed must not be used.
ADC->SWTRIG.bit.START = 1;

// Wait until ADC conversion is done
while (!(ADC->INTFLAG.bit.RESRDY));
syncADC();

// Get result
// This is signed so that the math later is done signed
int32_t adcReading = ADC->RESULT.reg;

// Clear result ready flag
ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY;
syncADC();

// Disable ADC
ADC->CTRLA.bit.ENABLE = 0;
syncADC();

// Restore pervious ADC settings
ADC->CTRLB.reg = oldReadResolution;
syncADC();
ADC->SAMPCTRL.reg = oldSampling;
syncADC();
ADC->INPUTCTRL.bit.GAIN = oldReferenceGain;
ADC->REFCTRL.bit.REFSEL = oldReferenceSelect;
syncADC();

// Factory room temperature readings
uint8_t roomInteger = (*(uint32_t*)FUSES_ROOM_TEMP_VAL_INT_ADDR & FUSES_ROOM_TEMP_VAL_INT_Msk) >> FUSES_ROOM_TEMP_VAL_INT_Pos;
uint8_t roomDecimal = (*(uint32_t*)FUSES_ROOM_TEMP_VAL_DEC_ADDR & FUSES_ROOM_TEMP_VAL_DEC_Msk) >> FUSES_ROOM_TEMP_VAL_DEC_Pos;
int32_t roomReading = ((*(uint32_t*)FUSES_ROOM_ADC_VAL_ADDR & FUSES_ROOM_ADC_VAL_Msk) >> FUSES_ROOM_ADC_VAL_Pos);
int32_t roomTemperature = 1000 * roomInteger + 100 * roomDecimal;

// Factory hot temperature readings
uint8_t hotInteger = (*(uint32_t*)FUSES_HOT_TEMP_VAL_INT_ADDR & FUSES_HOT_TEMP_VAL_INT_Msk) >> FUSES_HOT_TEMP_VAL_INT_Pos;
uint8_t hotDecimal = (*(uint32_t*)FUSES_HOT_TEMP_VAL_DEC_ADDR & FUSES_HOT_TEMP_VAL_DEC_Msk) >> FUSES_HOT_TEMP_VAL_DEC_Pos;
int32_t hotReading = ((*(uint32_t*)FUSES_HOT_ADC_VAL_ADDR & FUSES_HOT_ADC_VAL_Msk) >> FUSES_HOT_ADC_VAL_Pos);
int32_t hotTemperature = 1000 * hotInteger + 100 * hotDecimal;

// Linear interpolation of temperature using factory room temperature and hot temperature
int32_t temperature = roomTemperature + ((hotTemperature - roomTemperature) * (adcReading - roomReading)) / (hotReading - roomReading);
return temperature / 1000.0f;
}

#ifdef __cplusplus
}
#endif
7 changes: 7 additions & 0 deletions cores/arduino/wiring_analog.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ extern void analogWriteResolution(int res);

extern void analogOutputInit( void ) ;

/*
* \brief Read the internal temperature using the temperature ADC channel.
*
* \return Temperature (°C)
*/
extern float readInternalTemperature();

#ifdef __cplusplus
}
#endif