156 lines
4.4 KiB
C
156 lines
4.4 KiB
C
#include <math.h>
|
|
|
|
#include "temp_sensor.h"
|
|
#include "fxp.h"
|
|
|
|
#include <libopencm3/cm3/common.h>
|
|
#include <libopencm3/stm32/adc.h>
|
|
#include <libopencm3/stm32/dma.h>
|
|
|
|
#define ADC_NUM_CHANNELS 2
|
|
static volatile int16_t adc_values[ADC_NUM_CHANNELS];
|
|
|
|
static fxp_t m_temperature_internal = 0;
|
|
static fxp_t m_temperature_ntc = 0;
|
|
|
|
/* Temperature sensor calibration value address */
|
|
#define TEMP110_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FFFF7C2))
|
|
#define TEMP30_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FFFF7B8))
|
|
#define VDD_CALIB ((int32_t) (330)) /* calibration voltage = 3,30V - DO NOT CHANGE */
|
|
#define VDD_APPLI ((int32_t) (330)) /* actual supply voltage */
|
|
|
|
/* function for temperature conversion */
|
|
static fxp_t calc_temperature(uint16_t adc_val)
|
|
{
|
|
int32_t temperature_raw = ((int32_t)adc_val * VDD_APPLI / VDD_CALIB)
|
|
- (int32_t)(*TEMP30_CAL_ADDR);
|
|
|
|
fxp_t temperature = FXP_FROM_INT(temperature_raw);
|
|
|
|
fxp_t scale_dividend = FXP_FROM_INT(110 - 30);
|
|
fxp_t scale_divisor = FXP_FROM_INT((int32_t)(*TEMP110_CAL_ADDR - *TEMP30_CAL_ADDR));
|
|
|
|
fxp_t scale = fxp_div(scale_dividend, scale_divisor);
|
|
|
|
return fxp_add(fxp_mult(temperature, scale), FXP_FROM_INT(30));
|
|
}
|
|
|
|
|
|
static fxp_t adc_val_to_pin_voltage(uint16_t adc_val)
|
|
{
|
|
return fxp_div(
|
|
fxp_mult(FXP_FROM_INT((int32_t)adc_val), fxp_div(FXP_FROM_INT(33), FXP_FROM_INT(10))),
|
|
FXP_FROM_INT(4096));
|
|
}
|
|
|
|
|
|
static fxp_t calc_temperature_ntc(uint16_t adc_val)
|
|
{
|
|
static const fxp_t ln_r_ntc_nom = 705030; // ln(47kΩ) converted to fxp_t with 16 fractional bits
|
|
static const fxp_t r1 = FXP_FROM_INT(10000);
|
|
static const fxp_t b_constant = FXP_FROM_INT(4125);
|
|
static const fxp_t ntc_temp_nom = 19539558; // (273.15+25) * 2**16
|
|
static const fxp_t celsius2kelvin = 17901158; // (273.15) * 2**16
|
|
|
|
fxp_t v_r1 = adc_val_to_pin_voltage(adc_val);
|
|
fxp_t v_ref = fxp_div(FXP_FROM_INT(33), FXP_FROM_INT(10));
|
|
|
|
fxp_t r_ntc = fxp_div(fxp_mult(fxp_sub(v_ref, v_r1), r1), v_r1);
|
|
|
|
fxp_t ln_r_ntc = fxp_from_float(logf(fxp_to_float(r_ntc)));
|
|
|
|
fxp_t temp_k = fxp_div(FXP_FROM_INT(1.0),
|
|
fxp_div(
|
|
fxp_add(
|
|
fxp_div(
|
|
fxp_sub(
|
|
ln_r_ntc,
|
|
ln_r_ntc_nom),
|
|
b_constant),
|
|
FXP_FROM_INT(1)),
|
|
ntc_temp_nom));
|
|
|
|
return fxp_sub(temp_k, celsius2kelvin);
|
|
}
|
|
|
|
|
|
void temp_sensor_init(void)
|
|
{
|
|
uint8_t channels[ADC_NUM_CHANNELS] = {
|
|
0, // The NTC is connected to ADC_IN0
|
|
ADC_CHANNEL_TEMP // Temperature sensor
|
|
};
|
|
|
|
// Prepare the ADC
|
|
adc_power_off(ADC1);
|
|
|
|
// enable the temperature sensor
|
|
adc_enable_temperature_sensor();
|
|
|
|
// configure ADC
|
|
//adc_enable_scan_mode(ADC1);
|
|
//adc_set_clk_source(ADC1, ADC_CLKSOURCE_PCLK_DIV2); // -> 1.05 MHz @ 2.1 MHz ABP
|
|
ADC_CFGR2(ADC1) = ADC_CFGR2_CKMODE_PCLK_DIV2;
|
|
adc_set_single_conversion_mode(ADC1);
|
|
adc_set_resolution(ADC1, ADC_CFGR1_RES_12_BIT);
|
|
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_12DOT5CYC);
|
|
//adc_disable_external_trigger_regular(ADC1);
|
|
adc_set_right_aligned(ADC1);
|
|
adc_set_regular_sequence(ADC1, ADC_NUM_CHANNELS, channels);
|
|
|
|
adc_calibrate(ADC1);
|
|
|
|
// configure DMA for ADC
|
|
|
|
//nvic_enable_irq(NVIC_DMA1_CHANNEL1_IRQ);
|
|
//dma_channel_reset(DMA1, DMA_CHANNEL1);
|
|
dma_set_priority(DMA1, DMA_CHANNEL1, DMA_CCR_PL_LOW);
|
|
dma_set_memory_size(DMA1, DMA_CHANNEL1, DMA_CCR_MSIZE_16BIT);
|
|
dma_set_peripheral_size(DMA1, DMA_CHANNEL1, DMA_CCR_PSIZE_16BIT);
|
|
dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL1);
|
|
dma_enable_circular_mode(DMA1, DMA_CHANNEL1);
|
|
dma_set_read_from_peripheral(DMA1, DMA_CHANNEL1);
|
|
dma_set_peripheral_address(DMA1, DMA_CHANNEL1, (uint32_t) &ADC_DR(ADC1));
|
|
/* The array adc_values[] is filled with the waveform data to be output */
|
|
dma_set_memory_address(DMA1, DMA_CHANNEL1, (uint32_t) adc_values);
|
|
dma_set_number_of_data(DMA1, DMA_CHANNEL1, ADC_NUM_CHANNELS);
|
|
//dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL1);
|
|
dma_enable_channel(DMA1, DMA_CHANNEL1);
|
|
|
|
adc_enable_dma(ADC1);
|
|
|
|
adc_power_on(ADC1);
|
|
}
|
|
|
|
|
|
void temp_sensor_trigger_update(void)
|
|
{
|
|
// start the ADC conversion sequency. The result will be transferred to RAM
|
|
// by the DMA.
|
|
adc_start_conversion_regular(ADC1);
|
|
}
|
|
|
|
|
|
bool temp_sensor_has_new_values(void)
|
|
{
|
|
if(dma_get_interrupt_flag(DMA1, DMA_CHANNEL1, DMA_TCIF)) {
|
|
dma_clear_interrupt_flags(DMA1, DMA_CHANNEL1, DMA_TCIF);
|
|
|
|
// TODO: calculate temperature values and cache them here.
|
|
m_temperature_internal = calc_temperature(adc_values[1]);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
fxp_t temp_sensor_get_ntc_temperature(void)
|
|
{
|
|
}
|
|
|
|
|
|
fxp_t temp_sensor_get_internal_temperature(void)
|
|
{
|
|
}
|