DragonProbe/bsp/rp2040/m_default/tempsensor.c

60 lines
1.7 KiB
C

// vim: set et:
#include "m_default/tempsensor.h"
#include <hardware/adc.h>
#include <hardware/resets.h>
#define T_SLOPE (-0.001721f)
#define T_BIAS (0.706f)
#define V_MAX (3.3f)
#define D_RANGE (4096)
#define T_OFF (27)
// convert float to x.4 fixed format
#define float2fix(x) (int)((x) * (1 << 4))
// convert x.4 fixed to 8.4 fixed
__attribute__((__const__)) inline static int16_t trunc_8fix4(int fix) {
// clang-format off
if (fix > 4095) fix = 4095;
if (fix < -4096) fix = -4096;
// clang-format on
return fix;
}
void tempsense_dev_init(void) {
adc_init();
adc_set_temp_sensor_enabled(true);
}
void tempsense_dev_deinit(void) {
adc_set_temp_sensor_enabled(false);
// call init, as it resets the ADC control register
adc_init();
// we still need to disable it again afterwards, though
reset_block(RESETS_RESET_ADC_BITS);
}
// 8.4
int16_t tempsense_dev_get_temp(void) {
adc_select_input(4); // select temp sensor
uint16_t result = adc_read();
float voltage = result * (V_MAX / D_RANGE);
float tempf = T_OFF + (voltage - T_BIAS) / T_SLOPE;
// FIXME: use fixed point instead! but something's wrong with the formula below
/*int temperature = float2fix(T_OFF - T_BIAS / T_SLOPE)
+ (int)result * float2fix(V_MAX / (D_RANGE * T_SLOPE));*/
return trunc_8fix4(/*temperature*/ float2fix(tempf));
}
// RP2040 absolute min/max are -20/85
// clang-format off
int16_t tempsense_dev_get_lower(void) { return trunc_8fix4(float2fix(-15)); }
int16_t tempsense_dev_get_upper(void) { return trunc_8fix4(float2fix( 75)); }
int16_t tempsense_dev_get_crit (void) { return trunc_8fix4(float2fix( 80)); }
// clang-format on