aboutsummaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorSelene ToyKeeper2023-11-21 02:52:00 -0700
committerSelene ToyKeeper2023-11-21 02:52:00 -0700
commitfdb47b96e86924bf81852205b2b3078b8b21d040 (patch)
treeed8337b4619bb86ffb40c63767a32ae58e9b4dcc /arch
parent1.55V AA battery should not show as "white" voltage color, only purple (diff)
downloadanduril-fdb47b96e86924bf81852205b2b3078b8b21d040.tar.gz
anduril-fdb47b96e86924bf81852205b2b3078b8b21d040.tar.bz2
anduril-fdb47b96e86924bf81852205b2b3078b8b21d040.zip
got ADC voltage+temp working on avrdd... but broke all other builds/MCUs
This patch changes the ADC code to use two internal standard units, and everything else must convert to these units: - FSM Volts: centiVolts << 6 (range 0 to 10.24 V per cell) - FSM Kelvin: Kelvin << 6 (range 0 to 1024 K) UI-level voltage is still "Volts * 10", and temperature is still Celsius. FSM expects functions to be provided, to convert from the hardware's raw ADC measurements to these internal units: `voltage_raw2cooked()` and `temp_raw2cooked()`. Defaults will be provided by arch/*.[ch] for each MCU type, or the hwdef can make its own. Anyway, gotta go fix all the other MCUs and builds now. :(
Diffstat (limited to '')
-rw-r--r--arch/avr32dd20.c60
-rw-r--r--arch/avr32dd20.h15
2 files changed, 46 insertions, 29 deletions
diff --git a/arch/avr32dd20.c b/arch/avr32dd20.c
index 45923a8..998e9f6 100644
--- a/arch/avr32dd20.c
+++ b/arch/avr32dd20.c
@@ -52,19 +52,19 @@ inline void mcu_set_admux_therm() {
ADC0.SAMPCTRL = 32;
// set single-ended or differential
// set resolution to 12 bits
- // set left- or right-adjust (right)
+ // set left- or right-adjust
// set free-running mode or not (yes)
ADC0.CTRLA = ADC_CONVMODE_SINGLEENDED_gc
| ADC_RESSEL_12BIT_gc
- //| ADC_LEFTADJ_bm // not in temperature mode
+ | ADC_LEFTADJ_bm
| ADC_FREERUN_bm;
// set number of samples (requires adjustment in formula too)
ADC0.CTRLB = ADC_SAMPNUM_NONE_gc;
- // TODO: accumulate more samples for more resolution
- // (and probably set the prescale faster too)
- //ADC0.CTRLB = ADC_SAMPNUM_ACC16_gc; // 16 samples per result
+ // accumulate more samples for more resolution
+ ADC0.CTRLB = ADC_SAMPNUM_ACC16_gc; // 16 samples per result
// set a clock prescaler
- ADC0.CTRLC = ADC_PRESC_DIV64_gc;
+ //ADC0.CTRLC = ADC_PRESC_DIV64_gc; // use this when no accumulation
+ ADC0.CTRLC = ADC_PRESC_DIV4_gc; // measure faster when oversampling
// enable the ADC
ADC0.CTRLA |= ADC_ENABLE_bm;
// actually start measuring (happens in another function)
@@ -90,7 +90,7 @@ inline void mcu_set_admux_voltage() {
// set number of samples
ADC0.CTRLB = ADC_SAMPNUM_ACC16_gc; // 16 samples per result
// set a clock prescaler
- ADC0.CTRLC = ADC_PRESC_DIV16_gc; // not too fast, not too slow
+ ADC0.CTRLC = ADC_PRESC_DIV4_gc; // measure faster when oversampling
// select the positive ADC input with MUXPOS
#ifdef USE_VOLTAGE_DIVIDER // external voltage divider
// ADC input pin / Vref
@@ -113,11 +113,8 @@ inline void mcu_adc_sleep_mode() {
}
inline void mcu_adc_start_measurement() {
- // FIXME: enable this after getting ADC stuff fixed
- #if 0
ADC0.INTCTRL |= ADC_RESRDY_bm; // enable interrupt
ADC0.COMMAND |= ADC_STCONV_bm; // actually start measuring
- #endif
}
/*
@@ -135,24 +132,35 @@ inline void mcu_adc_vect_clear() {
ADC0.INTFLAGS = ADC_RESRDY_bm; // clear the interrupt
}
-inline uint16_t mcu_adc_result_temp() {
- // FIXME: better math, higher precision
- // Use the factory calibrated values in SIGROW.TEMPSENSE0 and
- // SIGROW.TEMPSENSE1 to calculate a temperature reading in Kelvin, then
- // left-align it.
- int8_t sigrow_offset = SIGROW.TEMPSENSE1; // Read signed value from signature row
- uint8_t sigrow_gain = SIGROW.TEMPSENSE0; // Read unsigned value from signature row
- uint32_t temp = ADC0.RES - sigrow_offset;
- temp *= sigrow_gain; // Result might overflow 16 bit variable (10bit+8bit)
- temp += 0x80; // Add 1/2 to get correct rounding on division below
- //temp >>= 8; // Divide result to get Kelvin
- //return temp << 6; // left align it
- return temp >> 2; // left-aligned uint16_t
+inline uint16_t mcu_adc_result() {
+ // value is 12-bit left-aligned + 16x oversampling = 16 bits total
+ return ADC0.RES;
}
-inline uint16_t mcu_adc_result_volts() {
- // voltage is 12-bit right-aligned + 16x oversampling = 16 bits total
- return ADC0.RES;
+inline uint16_t mcu_vdd_raw2cooked(uint16_t measurement) {
+ // In : 65535 * (Vbat / 10) / 1.024V
+ // Out: 65535 * (Vbat / 10) / 1.024V
+ // This MCU's native format is already correct
+ return measurement;
+}
+
+inline uint16_t mcu_temp_raw2cooked(uint16_t measurement) {
+ // convert raw ADC values to calibrated temperature
+ // In: ADC raw temperature (16-bit, or 12-bit left-aligned)
+ // Out: Kelvin << 6
+ // Precision: 1/64th Kelvin (but noisy)
+ // AVR DD datasheet section 33.3.3.8
+ uint16_t sigrow_slope = SIGROW.TEMPSENSE0; // factory calibration data
+ uint16_t sigrow_offset = SIGROW.TEMPSENSE1; // 12-bit value
+ //const uint32_t scaling_factor = 4096; // use top 12 bits of ADC data
+ //uint32_t temp = sigrow_offset - (measurement >> 4);
+ const uint32_t scaling_factor = 65536; // use all 16 bits of ADC data
+ uint32_t temp = (sigrow_offset << 4) - measurement;
+ temp *= sigrow_slope; // 24-bit result
+ temp += scaling_factor / 8; // Add 1/8th K to get correct rounding on later divisions
+ //temp = temp >> 6; // change (K << 12) to (K << 6)
+ temp = temp >> 10; // change (K << 16) to (K << 6)
+ return temp; // left-aligned uint16_t, 0 to 1023.98 Kelvin
}
inline uint8_t mcu_adc_lsb() {
diff --git a/arch/avr32dd20.h b/arch/avr32dd20.h
index 7a6b8f1..3ebb05a 100644
--- a/arch/avr32dd20.h
+++ b/arch/avr32dd20.h
@@ -50,12 +50,21 @@ inline void mcu_adc_off();
#define ADC_vect ADC0_RESRDY_vect
inline void mcu_adc_vect_clear();
+// both readings are left-aligned
+inline uint16_t mcu_adc_result();
+
// read ADC differently for temperature and voltage
-#define MCU_ADC_RESULT_PER_TYPE
+//#define MCU_ADC_RESULT_PER_TYPE
+//inline uint16_t mcu_adc_result_temp();
+//inline uint16_t mcu_adc_result_volts();
-inline uint16_t mcu_adc_result_temp();
+// return (centiVolts << 6), range 0 to 10.24V
+#define voltage_raw2cooked mcu_vdd_raw2cooked
+inline uint16_t mcu_vdd_raw2cooked(uint16_t measurement);
-inline uint16_t mcu_adc_result_volts();
+// return (temp in Kelvin << 6)
+#define temp_raw2cooked mcu_temp_raw2cooked
+inline uint16_t mcu_temp_raw2cooked(uint16_t measurement);
inline uint8_t mcu_adc_lsb();
If you find this content useful please consider a small donation via bitcoin: bitcoin:1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2?amount=0.001&message=Donation Scraping git contents via cgit is very resource intensive. The continued hosting of these git repositories is entirely financed by your bitcoin contributions. For donations of a least 1 mBTC you include your IP address in the message of your bitcoin donation. This will remove this message in the future for requests from your IP, which will significantly reduce token usage. In any case, any contributions to bitcoin address 1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2 are very welcome. Thanks in advance for you contribution to a self-sustaining ecosystem.