Freeze
This commit is contained in:
parent
70798b6bf7
commit
3e77d34ccc
10 changed files with 669 additions and 146 deletions
214
sbc_fw/adc.cpp
Normal file
214
sbc_fw/adc.cpp
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* @file adc.cpp
|
||||
* @brief
|
||||
*
|
||||
* Created: 27.09.2025 05:06:33
|
||||
* Author: ThePetrovich
|
||||
*
|
||||
* Copyright YKSA - Sakha Aerospace Systems, LLC.
|
||||
* See the LICENSE file for details.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "adc.h"
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
#include <Arduino.h>
|
||||
#include <util/atomic.h>
|
||||
|
||||
uint8_t adc_flags = 0;
|
||||
|
||||
int16_t adc_to_temperature_c(uint16_t adc_value)
|
||||
{
|
||||
// MCP9700: 500 mV at 0°C, 10 mV per degree, vref = 3.0V
|
||||
// Result in 0.1°C units
|
||||
uint16_t adc_resolution = ADC_RESOLUTION
|
||||
<< config.flags.adc_oversample_bits; // Adjust resolution based on oversampling
|
||||
return (int16_t)((adc_value * ADC_VREF_MV / adc_resolution - config.tempcal));
|
||||
}
|
||||
|
||||
uint16_t adc_to_voltage_mv(uint16_t adc_value) { return (uint16_t)(adc_value * VOLTAGE_MV_PER_STEP); }
|
||||
|
||||
uint16_t adc_read_oversampled(uint8_t pin, uint8_t samples)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
|
||||
// unrolled loop
|
||||
uint8_t shift = ((samples == 64) ? 3 : (samples == 16) ? 2 : (samples == 4) ? 1 : 0);
|
||||
|
||||
for (uint8_t i = 0; i < samples; i++) {
|
||||
sum += analogRead(pin);
|
||||
}
|
||||
|
||||
return (uint16_t)(sum >> shift);
|
||||
}
|
||||
|
||||
void adc_enable_fast(void)
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||
{
|
||||
ADC0.CTRLA |= ADC_ENABLE_bm;
|
||||
|
||||
// Enable oversampling x16 for 12-bit result
|
||||
ADC0.CTRLB |= (config.flags.adc_oversample_bits << 2); // 2, 4, or 6 for 4x, 16x, or 64x oversampling
|
||||
|
||||
ADC0.CTRLC = 0; // reset
|
||||
ADC0.CTRLC |= ADC_PRESC_DIV32_gc | ADC_REFSEL_VREFA_gc; // CLK_PER/32, VREFA as reference
|
||||
|
||||
ADC0.EVCTRL |= ADC_STARTEI_bm; // EVSYS input to start conversion
|
||||
ADC0.INTCTRL |= ADC_RESRDY_bm; // Enable interrupt on conversion complete
|
||||
|
||||
// Configure VREF, Microchip DS40002015B page 424
|
||||
VREF.CTRLA |= VREF_ADC0REFSEL_4V34_gc;
|
||||
|
||||
ADC0.MUXPOS = ADC_MUXPOS_AIN3_gc; // DET_SIG_PIN
|
||||
|
||||
adc_flags |= 0x01; // Fast mode enabled
|
||||
}
|
||||
}
|
||||
|
||||
void adc_restore_default(void)
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||
{
|
||||
// Disable oversampling
|
||||
ADC0.CTRLB &= ~ADC_SAMPNUM_gm;
|
||||
|
||||
ADC0.CTRLC &= ~ADC_REFSEL_gm;
|
||||
ADC0.CTRLC |= ADC_REFSEL_VREFA_gc; // VREFA as reference
|
||||
|
||||
ADC0.EVCTRL &= ~ADC_STARTEI_bm;
|
||||
ADC0.INTCTRL &= ~ADC_RESRDY_bm;
|
||||
|
||||
adc_flags &= ~0x01; // Fast mode disabled
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t adc_conversion(void)
|
||||
{
|
||||
ADC0.COMMAND = ADC_STCONV_bm;
|
||||
while (!(ADC0.INTFLAGS & ADC_RESRDY_bm))
|
||||
;
|
||||
return ADC0.RES;
|
||||
}
|
||||
|
||||
static uint16_t adc_read_tempsense(void)
|
||||
{
|
||||
/* DS40002015B-page 425
|
||||
1. Configure the internal voltage reference to 1.1V by configuring the VREF peripheral.
|
||||
2. Select the internal voltage reference by writing the REFSEL bits in ADCn.CTRLC to 0x0.
|
||||
3. Select the ADC temperature sensor channel by configuring the MUXPOS register
|
||||
(ADCn.MUXPOS). This enables the temperature sensor.
|
||||
5. In ADCn.SAMPCTRL select INITDLY ≥ 32 µs × CLK_ADC
|
||||
6. In ADCn.CTRLC select SAMPLEN ≥ 32 µs × CLK_ADC
|
||||
7. Acquire the temperature sensor output voltage by starting a conversion.
|
||||
8. Process the measurement result as described below.
|
||||
*/
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||
{
|
||||
ADC0.CTRLA |= ADC_ENABLE_bm;
|
||||
|
||||
ADC0.CTRLB |= ADC_SAMPNUM_ACC16_gc;
|
||||
|
||||
ADC0.CTRLC = 0; // reset
|
||||
ADC0.CTRLC |= ADC_PRESC_DIV32_gc | ADC_REFSEL_INTREF_gc;
|
||||
|
||||
// Configure VREF, Microchip DS40002015B page 424
|
||||
VREF.CTRLA |= VREF_ADC0REFSEL_1V1_gc;
|
||||
|
||||
// Select temperature sensor channel
|
||||
ADC0.MUXPOS = ADC_MUXPOS_TEMPSENSE_gc;
|
||||
}
|
||||
|
||||
delay(10);
|
||||
|
||||
int8_t sigrow_offset = SIGROW.TEMPSENSE1; // Read signed value from signature row
|
||||
uint8_t sigrow_gain = SIGROW.TEMPSENSE0;
|
||||
// Read unsigned value from signature row
|
||||
uint16_t adc_reading = adc_conversion() >> 4;
|
||||
// ADC conversion result with 1.1 V internal reference
|
||||
uint32_t temp = adc_reading - 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
|
||||
uint16_t temperature_in_K = temp;
|
||||
|
||||
adc_restore_default();
|
||||
|
||||
if (adc_flags & 0x01) {
|
||||
adc_enable_fast();
|
||||
}
|
||||
|
||||
return temperature_in_K;
|
||||
}
|
||||
|
||||
void adc_cmd_calibrate(void)
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||
{
|
||||
ADC0.EVCTRL &= ~ADC_STARTEI_bm; // Start event input
|
||||
ADC0.INTCTRL &= ~ADC_RESRDY_bm;
|
||||
|
||||
ADC0.CTRLB |= ADC_SAMPNUM_ACC16_gc; // 16 samples for oversampling to get 12-bit result from 10-bit ADC
|
||||
|
||||
ADC0.CTRLC = 0; // reset
|
||||
ADC0.CTRLC |= ADC_PRESC_DIV32_gc | ADC_REFSEL_VDDREF_gc; // CLK_PER/32, VDD as reference
|
||||
|
||||
// Configure VREF, Microchip DS40002015B page 424
|
||||
VREF.CTRLA |= VREF_ADC0REFSEL_4V34_gc;
|
||||
}
|
||||
|
||||
delay(10); // Wait for VREF to stabilize
|
||||
|
||||
// set MUX to gnd and read offset
|
||||
ADC0.MUXPOS = ADC_MUXPOS_GND_gc;
|
||||
delay(1);
|
||||
uint16_t offset = adc_conversion() >> 2; // 12-bit result
|
||||
|
||||
Serial.write(offset & 0xFF);
|
||||
Serial.write(offset >> 8);
|
||||
|
||||
if (config.adccal0 == 0xFFFF) {
|
||||
config.adccal0 = offset;
|
||||
}
|
||||
|
||||
// set MUX to external AREF and read 3.0V value
|
||||
ADC0.MUXPOS = ADC_MUXPOS_AIN7_gc; // AREF pin
|
||||
delay(1);
|
||||
|
||||
uint16_t aref = adc_conversion() >> 2; // 12-bit result
|
||||
|
||||
Serial.write(aref & 0xFF);
|
||||
Serial.write(aref >> 8);
|
||||
|
||||
if (config.adccal3 == 0xFFFF) {
|
||||
config.adccal3 = aref;
|
||||
}
|
||||
|
||||
// set MUX to DACREF0 and read
|
||||
ADC0.MUXPOS = ADC_MUXPOS_DACREF_gc;
|
||||
delay(1);
|
||||
|
||||
uint16_t dacref = adc_conversion() >> 2; // 12-bit result
|
||||
Serial.write(dacref & 0xFF);
|
||||
Serial.write(dacref >> 8);
|
||||
|
||||
uint16_t tempsense = adc_read_tempsense();
|
||||
Serial.write(tempsense & 0xFF);
|
||||
Serial.write(tempsense >> 8);
|
||||
|
||||
Serial.write(SIGROW.TEMPSENSE1);
|
||||
Serial.write(SIGROW.TEMPSENSE0);
|
||||
|
||||
Serial.flush();
|
||||
SERIAL_BUFFER_CLEAR();
|
||||
|
||||
adc_restore_default();
|
||||
|
||||
if (adc_flags & 0x01) {
|
||||
adc_enable_fast();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue