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();
|
||||
}
|
||||
}
|
||||
57
sbc_fw/adc.h
Normal file
57
sbc_fw/adc.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* @file adc.h
|
||||
* @brief
|
||||
*
|
||||
* Created: 27.09.2025 05:06:42
|
||||
* Author: ThePetrovich
|
||||
*
|
||||
* Copyright YKSA - Sakha Aerospace Systems, LLC.
|
||||
* See the LICENSE file for details.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ADC_H_
|
||||
#define ADC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Enable ADC for fast radiation detection
|
||||
*/
|
||||
void adc_enable_fast(void);
|
||||
|
||||
/**
|
||||
* @brief Restore ADC to default settings
|
||||
*/
|
||||
void adc_restore_default(void);
|
||||
|
||||
/**
|
||||
* @brief Convert ADC reading to temperature in 0.1°C
|
||||
* @param adc_value 12-bit ADC reading
|
||||
* @return Temperature in 0.1°C
|
||||
*/
|
||||
int16_t adc_to_temperature_c(uint16_t adc_value);
|
||||
|
||||
/**
|
||||
* @brief Convert ADC reading to voltage in mV
|
||||
* @param adc_value ADC reading
|
||||
* @return Voltage in mV
|
||||
*/
|
||||
uint16_t adc_to_voltage_mv(uint16_t adc_value);
|
||||
|
||||
/**
|
||||
* @brief Read ADC with oversampling
|
||||
* @param pin Analog pin to read
|
||||
* @param samples Number of samples for oversampling
|
||||
* @return Averaged ADC value
|
||||
*/
|
||||
uint16_t adc_read_oversampled(uint8_t pin, uint8_t samples);
|
||||
|
||||
/**
|
||||
* @brief Command to calibrate ADC and read reference values
|
||||
*/
|
||||
void adc_cmd_calibrate(void);
|
||||
|
||||
#endif // ADC_H_
|
||||
|
|
@ -20,36 +20,23 @@
|
|||
|
||||
// Serial communication
|
||||
#define SERIAL_BAUD_RATE 38400
|
||||
#define SERIAL_BUFFER_CLEAR() \
|
||||
do { \
|
||||
while (Serial.available()) { \
|
||||
Serial.read(); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SERIAL_SEND_OK() \
|
||||
do { \
|
||||
Serial.print("ok\n"); \
|
||||
Serial.flush(); \
|
||||
SERIAL_BUFFER_CLEAR(); \
|
||||
} while (0)
|
||||
|
||||
// Timing constants
|
||||
#define STATUS_LED_BLINK_PERIOD 500U
|
||||
#define MAIN_LOOP_DELAY 10
|
||||
#define CPM_UPDATE_PERIOD 10000U
|
||||
|
||||
// ADC and detector settings
|
||||
#define ADC_OVERSAMPLING_BITS 2 // 16x oversampling -> 2 extra bits
|
||||
#define ADC_CHANNEL_16_MASK 0x7FFU // 11-bit channel mask
|
||||
#define ADC_CHANNEL_32_MASK 0x3FFU // 10-bit channel mask
|
||||
#define DETECTOR_CHANNEL_COUNT 2048
|
||||
#define DETECTOR_CHANNEL_32_COUNT 1024
|
||||
#define RSENSE_CHANNEL_16_MASK 0x7FFU // 11-bit channel mask
|
||||
#define RSENSE_CHANNEL_32_MASK 0x3FFU // 10-bit channel mask
|
||||
#define RSENSE_CHANNEL_COUNT 2048
|
||||
#define RSENSE_CHANNEL_32_COUNT 1024
|
||||
|
||||
// Temperature sensor constants (MCP9700)
|
||||
#define TEMP_SENSOR_OFFSET_MV 500L // 500 mV at 0°C
|
||||
#define TEMP_SENSOR_SCALE_MV 10L // 10 mV per degree
|
||||
#define MCP9700_OFFSET_MV 500L // 500 mV at 0°C
|
||||
#define MCP9700_SCALE_MV 10L // 10 mV per degree
|
||||
#define ADC_OVERSAMPLING_BITS 2 // 16x oversampling -> 2 extra bits
|
||||
#define ADC_VREF_MV 3000L // 3.0V reference
|
||||
#define ADC_RESOLUTION 4096L // 12-bit effective resolution
|
||||
#define ADC_RESOLUTION 1024L // 10-bit ADC
|
||||
|
||||
// Voltage divider constants
|
||||
#define VOLTAGE_DIVIDER_RATIO 20.0f // 200k and 10k resistors
|
||||
|
|
@ -70,4 +57,43 @@
|
|||
#define LSENSE_EXPECTED_ID 0xE0
|
||||
#define LSENSE_DATA_SIZE 12
|
||||
|
||||
typedef struct config_t {
|
||||
uint8_t magic1; // 0xA5 to indicate valid config
|
||||
uint8_t magic2; // 0x5A to indicate valid config
|
||||
uint8_t pot_hv;
|
||||
uint8_t pot_amp;
|
||||
uint8_t pot_det;
|
||||
struct {
|
||||
uint16_t adccal0; // ADC offset at GND
|
||||
uint16_t adccal3; // ADC reading at 3.0V reference
|
||||
uint16_t tempcal;
|
||||
uint16_t tempdrift_mvK; // SiPM temperature drift compensation in mV/K, normally around 20 mV/K
|
||||
float gainlow; // gain value for pot_amp = 0
|
||||
float gainhigh; // gain value for pot_amp = 255
|
||||
} calibration __attribute__((packed));
|
||||
union {
|
||||
struct {
|
||||
uint8_t spectrum_oversample_bits
|
||||
: 2; // 0, 1, 2, or 3 for 1x, 4x, 16x, or 64x oversampling, only for spectrum measurement
|
||||
uint8_t spectrum_channel_bits : 1; // 0 for 16-bit channels, 1 for 32-bit channels
|
||||
uint8_t temperature_drift_compensation
|
||||
: 1; // 0 to disable, 1 to enable temperature compensation
|
||||
uint8_t adc_oversample_bits : 2; // 0, 1, 2, or 3 for 1x, 4x, 16x, or 64x ADC oversampling for
|
||||
// temperature and voltage measurements
|
||||
uint8_t reserved : 2;
|
||||
} fields __attribute__((packed));
|
||||
uint8_t value;
|
||||
} flags __attribute__((packed));
|
||||
struct {
|
||||
uint8_t tempdrift_pot_hv_low;
|
||||
uint8_t tempdrift_pot_hv_high;
|
||||
uint8_t tempdrift_pot_amp_low;
|
||||
uint8_t tempdrift_pot_amp_high;
|
||||
uint8_t tempdrift_pot_det_low;
|
||||
uint8_t tempdrift_pot_det_high;
|
||||
} temp_drift_compensation_ranges __attribute__((packed));
|
||||
} __attribute__((packed)) config_t;
|
||||
|
||||
extern config_t config;
|
||||
|
||||
#endif // CONFIG_H
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
#include <Arduino.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
config_t config;
|
||||
|
||||
void eeprom_init(void)
|
||||
{
|
||||
if (EEPROM.read(EEPROM_MAGIC_ADDR) != EEPROM_MAGIC_VALUE) {
|
||||
|
|
|
|||
308
sbc_fw/protocol.h
Normal file
308
sbc_fw/protocol.h
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* @file protocol.h
|
||||
* @brief
|
||||
*
|
||||
* Created: 07.05.2026 10:15:36
|
||||
* Author: ThePetrovich
|
||||
*
|
||||
* Copyright YKSA - Sakha Aerospace Systems, LLC.
|
||||
* See the LICENSE file for details.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef PROTOCOL_H
|
||||
#define PROTOCOL_H
|
||||
|
||||
#include "config.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* @details
|
||||
* General Protocol Description:
|
||||
* - All commands are initiated by the host
|
||||
* - Command format: [CMD (2 bytes)][Length (2 bytes)][Payload (variable)][CRC16 (2 bytes)]
|
||||
* - CMD: 2 bytes command identifier (e.g., 'HV' for set potentiometers)
|
||||
* - Length: 2 bytes unsigned integer indicating the length of the payload in bytes
|
||||
* - Payload: Variable length data specific to the command
|
||||
* - CRC16: 2 bytes CRC16-XMODEM checksum of the CMD, Length, and Payload fields
|
||||
* - Response: For commands that require a response, the device will send back a similar structured
|
||||
* message with the appropriate CMD and payload. Otherwise, it should send an acknowledgment
|
||||
* (e.g., 'ACK') or an error response if the command is invalid.
|
||||
* - If a valid command is received, but cannot be executed (e.g. locked state, parameters out of range),
|
||||
* the device should send a command failure response (e.g., 'NAK') without performing any action.
|
||||
* - Error Handling: If a command is malformed (e.g., incorrect CRC, invalid length), the device will
|
||||
* ignore the command and should send an error response (e.g., 'ERR') to the host.
|
||||
* The device should not perform any action if the command is invalid.
|
||||
* Example Command: Set Potentiometers
|
||||
* - CMD: 'HV' (0x48 0x56)
|
||||
* - Length: 3 (0x00 0x03)
|
||||
* - Payload: [HV_POT (1 byte)][AMP_POT (1 byte)][DET_POT (1 byte)]
|
||||
* - CRC16: Calculated over 'HV', Length, and Payload
|
||||
* Response: 'ACK' if successful, 'NAK' if parameters are out of safe range, 'ERR' if command is malformed
|
||||
*/
|
||||
|
||||
uint16_t protocol_crc16_xmodem(uint8_t *data, uint16_t len);
|
||||
|
||||
typedef struct protocol_header_t {
|
||||
uint16_t cmd;
|
||||
uint16_t length;
|
||||
} __attribute__((packed)) protocol_header_t;
|
||||
|
||||
void protocol_send_header(uint16_t cmd, uint16_t length);
|
||||
|
||||
void protocol_send_ack(void);
|
||||
void protocol_send_nak(void);
|
||||
void protocol_send_error(void);
|
||||
|
||||
void protocol_send_message(uint16_t cmd, void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Firmware version command and response structure
|
||||
* @param[out] major Firmware major version
|
||||
* @param[out] minor Firmware minor version
|
||||
*/
|
||||
#define CMD_FIRMWARE_VERSION 0x7600
|
||||
typedef struct protocol_firmware_version_response_t {
|
||||
uint8_t major;
|
||||
uint8_t minor;
|
||||
} __attribute__((packed)) protocol_firmware_version_response_t;
|
||||
|
||||
void handle_version_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Light sensor presence command and response structure
|
||||
* @param[out] total_detected Total number of sensors detected across all buses
|
||||
* @param[out] bus_x_count Number of sensors detected on bus X
|
||||
* @param[out] bus_x_neg_addr I2C address of negative sensor on bus X (0 if not present)
|
||||
* @param[out] bus_x_pos_addr I2C address of positive sensor on bus X (0 if not present)
|
||||
* @param[out] bus_y_count Number of sensors detected on bus Y
|
||||
* @param[out] bus_y_neg_addr I2C address of negative sensor on bus Y (0 if not present)
|
||||
* @param[out] bus_y_pos_addr I2C address of positive sensor on bus Y (0 if not present)
|
||||
* @param[out] bus_z_count Number of sensors detected on bus Z
|
||||
* @param[out] bus_z_neg_addr I2C address of negative sensor on bus Z (0 if not present)
|
||||
* @param[out] bus_z_pos_addr I2C address of positive sensor on bus Z (0 if not present)
|
||||
*/
|
||||
#define CMD_LIGHT_SENSOR_PRESENCE 0x6C00
|
||||
typedef struct protocol_light_sensor_presence_response_t {
|
||||
uint8_t total_detected;
|
||||
uint8_t bus_x_count;
|
||||
uint8_t bus_x_neg_addr;
|
||||
uint8_t bus_x_pos_addr;
|
||||
uint8_t bus_y_count;
|
||||
uint8_t bus_y_neg_addr;
|
||||
uint8_t bus_y_pos_addr;
|
||||
uint8_t bus_z_count;
|
||||
uint8_t bus_z_neg_addr;
|
||||
uint8_t bus_z_pos_addr;
|
||||
} __attribute__((packed)) protocol_light_sensor_presence_response_t;
|
||||
|
||||
void handle_light_sensor_presence_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Read light sensor data command and response structure
|
||||
* @param[in] channel Spectral channel (0 = red, 1 = green, 2 = blue, 3 = IR, 4 = green2, 5 = composite visible, 6 =
|
||||
* composite all)
|
||||
* @param[out] bus_x_neg_channel_value Channel value for negative sensor on bus X
|
||||
* @param[out] bus_x_pos_channel_value Channel value for positive sensor on bus X
|
||||
* @param[out] bus_y_neg_channel_value Channel value for negative sensor on bus Y
|
||||
* @param[out] bus_y_pos_channel_value Channel value for positive sensor on bus Y
|
||||
* @param[out] bus_z_neg_channel_value Channel value for negative sensor on bus Z
|
||||
* @param[out] bus_z_pos_channel_value Channel value for positive sensor on bus Z
|
||||
*/
|
||||
#define CMD_READ_LIGHT_SENSORS 0x7200
|
||||
typedef struct protocol_read_light_sensors_command_t {
|
||||
uint8_t channel;
|
||||
} __attribute__((packed)) protocol_read_light_sensors_command_t;
|
||||
|
||||
typedef struct protocol_read_light_sensors_response_t {
|
||||
uint16_t bus_x_neg_channel_value;
|
||||
uint16_t bus_x_pos_channel_value;
|
||||
uint16_t bus_y_neg_channel_value;
|
||||
uint16_t bus_y_pos_channel_value;
|
||||
uint16_t bus_z_neg_channel_value;
|
||||
uint16_t bus_z_pos_channel_value;
|
||||
} __attribute__((packed)) protocol_read_light_sensors_response_t;
|
||||
|
||||
void handle_read_light_sensors_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Get configuration command and response structure
|
||||
* @param[out] config Current device configuration
|
||||
*/
|
||||
#define CMD_GET_CONFIGURATION 0x6D00
|
||||
typedef struct protocol_get_configuration_response_t {
|
||||
config_t config;
|
||||
} __attribute__((packed)) protocol_get_configuration_response_t;
|
||||
|
||||
void handle_get_configuration_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Set configuration command and response structure
|
||||
* @param[in] config New device configuration to apply
|
||||
*/
|
||||
#define CMD_SET_CONFIGURATION 0x7D00
|
||||
typedef struct protocol_set_configuration_command_t {
|
||||
config_t config;
|
||||
} __attribute__((packed)) protocol_set_configuration_command_t;
|
||||
|
||||
void handle_set_configuration_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Set potentiometers command and response structure
|
||||
* @param[in] hv_pot High voltage potentiometer value
|
||||
* @param[in] amp_pot Amplifier potentiometer value
|
||||
* @param[in] det_pot Detector potentiometer value
|
||||
*/
|
||||
#define CMD_SET_POTENTIOMETERS 0x7D01
|
||||
typedef struct protocol_set_potentiometers_command_t {
|
||||
uint8_t hv_pot;
|
||||
uint8_t amp_pot;
|
||||
uint8_t det_pot;
|
||||
} __attribute__((packed)) protocol_set_potentiometers_command_t;
|
||||
|
||||
void handle_set_potentiometers_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Set calibration data command and response structure
|
||||
* @param[in] adccal0 ADC offset at GND
|
||||
* @param[in] adccal3 ADC reading at 3.0V reference
|
||||
* @param[in] tempcal Temperature calibration value
|
||||
* @param[in] tempdrift_mvK Temperature drift compensation in mV/K
|
||||
*/
|
||||
#define CMD_SET_CALIBRATION 0x7D02
|
||||
typedef struct protocol_set_calibration_command_t {
|
||||
uint16_t adccal0;
|
||||
uint16_t adccal3;
|
||||
uint16_t tempcal;
|
||||
uint16_t tempdrift_mvK;
|
||||
} __attribute__((packed)) protocol_set_calibration_command_t;
|
||||
|
||||
void handle_set_calibration_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Set flags command and response structure
|
||||
* @param[in] flags Configuration flags to set (e.g., oversampling, channel mode, temperature compensation)
|
||||
*/
|
||||
#define CMD_SET_FLAGS 0x7D03
|
||||
typedef struct protocol_set_flags_command_t {
|
||||
uint8_t flags;
|
||||
} __attribute__((packed)) protocol_set_flags_command_t;
|
||||
|
||||
/*
|
||||
* @brief Set temperature drift compensation ranges command and response structure
|
||||
* @param[in] tempdrift_pot_hv_low Low threshold for high voltage potentiometer
|
||||
* @param[in] tempdrift_pot_hv_high High threshold for high voltage potentiometer
|
||||
* @param[in] tempdrift_pot_amp_low Low threshold for amplifier potentiometer
|
||||
* @param[in] tempdrift_pot_amp_high High threshold for amplifier potentiometer
|
||||
* @param[in] tempdrift_pot_det_low Low threshold for detector potentiometer
|
||||
* @param[in] tempdrift_pot_det_high High threshold for detector potentiometer
|
||||
*/
|
||||
#define CMD_SET_TEMP_DRIFT_COMPENSATION_RANGES 0x7D04
|
||||
typedef struct protocol_set_temp_drift_compensation_ranges_command_t {
|
||||
uint8_t tempdrift_pot_hv_low;
|
||||
uint8_t tempdrift_pot_hv_high;
|
||||
uint8_t tempdrift_pot_amp_low;
|
||||
uint8_t tempdrift_pot_amp_high;
|
||||
uint8_t tempdrift_pot_det_low;
|
||||
uint8_t tempdrift_pot_det_high;
|
||||
} __attribute__((packed)) protocol_set_temp_drift_compensation_ranges_command_t;
|
||||
|
||||
void handle_set_flags_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Get telemetry command and response structure
|
||||
* @param[out] hv_temp_c High voltage component temperature in 0.1°C
|
||||
* @param[out] amp_temp_c Amplifier component temperature in 0.1°C
|
||||
* @param[out] det_temp_c Detector component temperature in 0.1°C
|
||||
* @param[out] mcu_temp_c MCU temperature in 0.1°C
|
||||
* @param[out] vbias_mv SiPM bias voltage in mV
|
||||
* @param[out] hv_pot Current high voltage potentiometer setting
|
||||
* @param[out] amp_pot Current amplifier potentiometer setting
|
||||
* @param[out] det_pot Current detector potentiometer setting
|
||||
* @param[out] cps Current counts per second (CPM/60)
|
||||
* @param[out] cp10s Counts in the last 10 seconds
|
||||
* @param[out] total_counts Total counts since last reset
|
||||
*/
|
||||
#define CMD_GET_TELEMETRY 0x7400
|
||||
typedef struct protocol_get_telemetry_response_t {
|
||||
uint16_t hv_temp_c;
|
||||
uint16_t amp_temp_c;
|
||||
uint16_t det_temp_c;
|
||||
uint16_t mcu_temp_c;
|
||||
uint16_t vbias_mv;
|
||||
uint8_t hv_pot;
|
||||
uint8_t amp_pot;
|
||||
uint8_t det_pot;
|
||||
uint16_t cps;
|
||||
uint32_t cp10s;
|
||||
uint32_t total_counts;
|
||||
} __attribute__((packed)) protocol_get_telemetry_response_t;
|
||||
|
||||
void handle_get_telemetry_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Flush counters command
|
||||
* @details Resets total counts and 10-second counts to zero
|
||||
*/
|
||||
#define CMD_FLUSH_COUNTERS 0x7401
|
||||
void handle_flush_counters_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Flush spectrum command
|
||||
* @details Clears all channel data and resets total counts to zero
|
||||
*/
|
||||
#define CMD_FLUSH_SPECTRUM 0x7402
|
||||
void handle_flush_spectrum_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Turn on the spectrometer circutry and enable fast ADC mode for radiation detection
|
||||
*/
|
||||
#define CMD_RSENSE_ENABLE 0x7500
|
||||
void handle_rsense_enable_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Turn off the spectrometer circutry and disable fast ADC mode for radiation detection
|
||||
*/
|
||||
#define CMD_RSENSE_DISABLE 0x7501
|
||||
void handle_rsense_disable_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Freeze spectrum data for reading
|
||||
*/
|
||||
#define CMD_SPECTRUM_FREEZE 0x7502
|
||||
void handle_spectrum_freeze_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Unfreeze spectrum data after reading
|
||||
*/
|
||||
#define CMD_SPECTRUM_UNFREEZE 0x7503
|
||||
void handle_spectrum_unfreeze_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Get counts since last request
|
||||
*/
|
||||
#define CMD_GET_COUNTS 0x7504
|
||||
typedef struct protocol_get_counts_response_t {
|
||||
uint32_t counts;
|
||||
} __attribute__((packed)) protocol_get_counts_response_t;
|
||||
|
||||
void handle_get_counts_command(void *payload, uint16_t length);
|
||||
|
||||
/*
|
||||
* @brief Read spectrum data (arbitrary chunking for large data)
|
||||
*/
|
||||
#define CMD_READ_SPECTRUM_DATA 0x7505
|
||||
typedef struct protocol_read_spectrum_chunk_command_t {
|
||||
uint16_t offset;
|
||||
uint16_t length;
|
||||
} __attribute__((packed)) protocol_read_spectrum_chunk_command_t;
|
||||
|
||||
typedef struct protocol_read_spectrum_chunk_response_t {
|
||||
uint16_t offset;
|
||||
uint16_t length;
|
||||
// Followed by 'length' bytes of spectrum data
|
||||
} __attribute__((packed)) protocol_read_spectrum_chunk_response_t;
|
||||
void handle_read_spectrum_chunk_command(void *payload, uint16_t length);
|
||||
|
||||
#endif /* PROTOCOL_H */
|
||||
|
|
@ -23,13 +23,15 @@
|
|||
#include "iodefs.h"
|
||||
#include "rsense.h"
|
||||
#include "utils.h"
|
||||
#include "adc.h"
|
||||
|
||||
static volatile union __attribute__((packed)) {
|
||||
uint16_t channels_16[DETECTOR_CHANNEL_COUNT];
|
||||
uint32_t channels_32[DETECTOR_CHANNEL_32_COUNT];
|
||||
uint16_t channels_16[RSENSE_CHANNEL_COUNT];
|
||||
uint32_t channels_32[RSENSE_CHANNEL_32_COUNT];
|
||||
} g_detector_counts = {0};
|
||||
|
||||
static uint8_t g_spectrum_mode = 0; // 0 = 16-bit, 1 = 32-bit
|
||||
static uint8_t g_oversampling_bits = config.flags.adc_oversample_bits;
|
||||
|
||||
static uint16_t g_read_pointer = 0;
|
||||
static uint32_t g_total_counts = 0;
|
||||
|
|
@ -44,8 +46,6 @@ static potentiometer_settings_t g_current_pot_settings;
|
|||
|
||||
static void apply_potentiometer_settings(const potentiometer_settings_t *settings);
|
||||
static void initialize_event_system(void);
|
||||
static void enable_fast_adc(void);
|
||||
static void restore_default_adc(void);
|
||||
static inline void handle_analog_read_interrupt(void);
|
||||
static void clear_detector_counters(void);
|
||||
static void clear_channel_data(void);
|
||||
|
|
@ -110,61 +110,6 @@ static void initialize_event_system(void)
|
|||
Event2.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable ADC for fast radiation detection
|
||||
*/
|
||||
static void enable_fast_adc(void)
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||
{
|
||||
ADC0.CTRLA |= ADC_ENABLE_bm;
|
||||
|
||||
// Enable oversampling x16 for 12-bit result
|
||||
#if ADC_OVERSAMPLING_BITS == 1
|
||||
ADC0.CTRLB |= ADC_SAMPNUM_ACC4_gc;
|
||||
#elif ADC_OVERSAMPLING_BITS == 2
|
||||
ADC0.CTRLB |= ADC_SAMPNUM_ACC16_gc;
|
||||
#elif ADC_OVERSAMPLING_BITS == 3
|
||||
ADC0.CTRLB |= ADC_SAMPNUM_ACC64_gc;
|
||||
#else
|
||||
#error "Unsupported ADC oversampling setting"
|
||||
#endif
|
||||
|
||||
ADC0.CTRLC = 0; // reset
|
||||
ADC0.CTRLC |= ADC_PRESC_DIV32_gc | ADC_REFSEL_VDDREF_gc; // CLK_PER/32, VDD as reference
|
||||
|
||||
// Enable interrupt on conversion complete
|
||||
ADC0.EVCTRL |= ADC_STARTEI_bm; // Start event input
|
||||
ADC0.INTCTRL |= ADC_RESRDY_bm;
|
||||
|
||||
// Configure VREF, Microchip DS40002015B page 424
|
||||
VREF.CTRLA |= VREF_ADC0REFSEL_4V34_gc;
|
||||
|
||||
// Select ADC channel
|
||||
ADC0.MUXPOS = ADC_MUXPOS_AIN3_gc; // DET_SIG_PIN
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Restore ADC to default settings
|
||||
*/
|
||||
static void restore_default_adc(void)
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||
{
|
||||
// Disable oversampling
|
||||
ADC0.CTRLB &= ~ADC_SAMPNUM_gm;
|
||||
|
||||
// Set reference back to VREFA
|
||||
ADC0.CTRLC &= ~ADC_REFSEL_gm;
|
||||
ADC0.CTRLC |= ADC_REFSEL_VREFA_gc; // VREFA as reference
|
||||
|
||||
// Disable interrupt on conversion complete
|
||||
ADC0.EVCTRL &= ~ADC_STARTEI_bm; // Start event input
|
||||
ADC0.INTCTRL &= ~ADC_RESRDY_bm;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle ADC conversion results for radiation detection
|
||||
*/
|
||||
|
|
@ -188,7 +133,7 @@ static inline void handle_analog_read_interrupt(void)
|
|||
#error "Unsupported ADC oversampling setting"
|
||||
#endif
|
||||
|
||||
g_detector_counts.channels_16[channel & ADC_CHANNEL_16_MASK]++;
|
||||
g_detector_counts.channels_16[channel & RSENSE_CHANNEL_16_MASK]++;
|
||||
} else {
|
||||
// 32-bit spectrum mode
|
||||
// 2 extra bits from oversampling + averaging x2
|
||||
|
|
@ -203,7 +148,7 @@ static inline void handle_analog_read_interrupt(void)
|
|||
#error "Unsupported ADC oversampling setting"
|
||||
#endif
|
||||
|
||||
g_detector_counts.channels_32[channel & ADC_CHANNEL_32_MASK]++;
|
||||
g_detector_counts.channels_32[channel & RSENSE_CHANNEL_32_MASK]++;
|
||||
}
|
||||
|
||||
g_total_counts++;
|
||||
|
|
@ -231,7 +176,7 @@ static void clear_detector_counters(void)
|
|||
*/
|
||||
static void clear_channel_data(void)
|
||||
{
|
||||
for (int i = 0; i < DETECTOR_CHANNEL_COUNT; i++) {
|
||||
for (int i = 0; i < RSENSE_CHANNEL_COUNT; i++) {
|
||||
g_detector_counts.channels_16[i] = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -294,7 +239,7 @@ static void set_potentiometer_values(uint8_t hv, uint8_t amp, uint8_t det)
|
|||
|
||||
void rsense_cmd_telemetry(void)
|
||||
{
|
||||
restore_default_adc();
|
||||
adc_restore_default();
|
||||
|
||||
// Send total counts as 4 bytes
|
||||
Serial.write(g_total_counts & 0xFF);
|
||||
|
|
@ -303,7 +248,7 @@ void rsense_cmd_telemetry(void)
|
|||
Serial.write((g_total_counts >> 24) & 0xFF);
|
||||
|
||||
// 2 bytes of voltage in mV
|
||||
uint16_t voltage_raw = read_adc_oversampled(V28V0_FB_PIN, 16);
|
||||
uint16_t voltage_raw = adc_read_oversampled(V28V0_FB_PIN, 16);
|
||||
uint16_t voltage_mv = adc_to_voltage_mv(voltage_raw);
|
||||
Serial.write(voltage_mv & 0xFF);
|
||||
Serial.write(voltage_mv >> 8);
|
||||
|
|
@ -318,7 +263,7 @@ void rsense_cmd_telemetry(void)
|
|||
|
||||
Serial.flush();
|
||||
SERIAL_BUFFER_CLEAR();
|
||||
enable_fast_adc();
|
||||
adc_enable_fast();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -326,9 +271,9 @@ void rsense_cmd_telemetry(void)
|
|||
*/
|
||||
static void send_temperature_data(void)
|
||||
{
|
||||
int16_t hv_temp_c = adc_to_temperature_c(read_adc_oversampled(HV_TEMP_PIN, 16));
|
||||
int16_t amp_temp_c = adc_to_temperature_c(read_adc_oversampled(AMP_TEMP_PIN, 16));
|
||||
int16_t det_temp_c = adc_to_temperature_c(read_adc_oversampled(DET_TEMP_PIN, 16));
|
||||
int16_t hv_temp_c = adc_to_temperature_c(adc_read_oversampled(HV_TEMP_PIN, 16));
|
||||
int16_t amp_temp_c = adc_to_temperature_c(adc_read_oversampled(AMP_TEMP_PIN, 16));
|
||||
int16_t det_temp_c = adc_to_temperature_c(adc_read_oversampled(DET_TEMP_PIN, 16));
|
||||
|
||||
Serial.write(hv_temp_c & 0xFF);
|
||||
Serial.write(hv_temp_c >> 8);
|
||||
|
|
@ -359,7 +304,7 @@ void rsense_cmd_enable(void)
|
|||
digitalWrite(HV_EN, HIGH);
|
||||
digitalWrite(DET_EN, HIGH);
|
||||
|
||||
enable_fast_adc();
|
||||
adc_enable_fast();
|
||||
|
||||
SERIAL_SEND_OK();
|
||||
}
|
||||
|
|
@ -369,7 +314,7 @@ void rsense_cmd_disable(void)
|
|||
digitalWrite(DET_EN, LOW);
|
||||
digitalWrite(HV_EN, LOW);
|
||||
|
||||
restore_default_adc();
|
||||
adc_restore_default();
|
||||
|
||||
SERIAL_SEND_OK();
|
||||
}
|
||||
|
|
@ -383,7 +328,7 @@ void rsense_cmd_flush(void)
|
|||
|
||||
void rsense_cmd_dump_channels(void)
|
||||
{
|
||||
restore_default_adc();
|
||||
adc_restore_default();
|
||||
|
||||
uint16_t read_from = 0;
|
||||
|
||||
|
|
@ -398,8 +343,8 @@ void rsense_cmd_dump_channels(void)
|
|||
Serial.write(g_read_pointer >> 8);
|
||||
|
||||
g_read_pointer = read_from;
|
||||
if (g_read_pointer >= (DETECTOR_CHANNEL_32_COUNT - 32)) {
|
||||
g_read_pointer = DETECTOR_CHANNEL_32_COUNT - 32;
|
||||
if (g_read_pointer >= (RSENSE_CHANNEL_32_COUNT - 32)) {
|
||||
g_read_pointer = RSENSE_CHANNEL_32_COUNT - 32;
|
||||
}
|
||||
|
||||
// Send 2 bytes of CRC16 checksum for the 32 channels
|
||||
|
|
@ -408,7 +353,7 @@ void rsense_cmd_dump_channels(void)
|
|||
Serial.write(crc16 >> 8);
|
||||
|
||||
// Send 32 channel values (128 bytes total)
|
||||
for (uint16_t i = 0; i < 32 && g_read_pointer < DETECTOR_CHANNEL_32_COUNT; i++, g_read_pointer++) {
|
||||
for (uint16_t i = 0; i < 32 && g_read_pointer < RSENSE_CHANNEL_32_COUNT; i++, g_read_pointer++) {
|
||||
uint32_t channel_value = g_detector_counts.channels_32[g_read_pointer];
|
||||
Serial.write(channel_value & 0xFF);
|
||||
Serial.write((channel_value >> 8) & 0xFF);
|
||||
|
|
@ -422,7 +367,7 @@ void rsense_cmd_dump_channels(void)
|
|||
|
||||
Serial.flush();
|
||||
SERIAL_BUFFER_CLEAR();
|
||||
enable_fast_adc();
|
||||
adc_enable_fast();
|
||||
}
|
||||
|
||||
void rsense_cmd_get_cpm(void)
|
||||
|
|
@ -433,10 +378,10 @@ void rsense_cmd_get_cpm(void)
|
|||
SERIAL_BUFFER_CLEAR();
|
||||
}
|
||||
|
||||
void rsense_cmd_set_mode(void)
|
||||
void rsense_cmd_set_configuration(void)
|
||||
{
|
||||
// Wait for 1 byte specifying mode
|
||||
while (Serial.available() < 1)
|
||||
while (Serial.available() < 8)
|
||||
;
|
||||
uint8_t mode = Serial.read();
|
||||
|
||||
|
|
@ -446,6 +391,8 @@ void rsense_cmd_set_mode(void)
|
|||
SERIAL_SEND_OK();
|
||||
}
|
||||
|
||||
// 7 bytes reserved for future use
|
||||
|
||||
Serial.flush();
|
||||
SERIAL_BUFFER_CLEAR();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ void rsense_cmd_get_cpm(void);
|
|||
/**
|
||||
* @brief Set spectrum mode (16-bit or 32-bit)
|
||||
*/
|
||||
void rsense_cmd_set_mode(void);
|
||||
void rsense_cmd_set_configuration(void);
|
||||
|
||||
/**
|
||||
* @brief Periodic tasks for radiation sensor
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ void handle_serial_command(char command)
|
|||
rsense_cmd_telemetry();
|
||||
break;
|
||||
case 'm': // Set spectrum mode (16-bit or 32-bit)
|
||||
rsense_cmd_set_mode();
|
||||
rsense_cmd_set_configuration();
|
||||
break;
|
||||
default:
|
||||
// Unknown command - ignore
|
||||
|
|
|
|||
|
|
@ -33,25 +33,3 @@ uint16_t calculate_crc16_xmodem(uint8_t *data, uint16_t len)
|
|||
|
||||
return crc;
|
||||
}
|
||||
|
||||
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
|
||||
return (int16_t)((adc_value * ADC_VREF_MV / ADC_RESOLUTION - TEMP_SENSOR_OFFSET_MV));
|
||||
}
|
||||
|
||||
uint16_t adc_to_voltage_mv(uint16_t adc_value) { return (uint16_t)(adc_value * VOLTAGE_MV_PER_STEP); }
|
||||
|
||||
uint16_t read_adc_oversampled(uint8_t pin, uint8_t samples)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,19 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SERIAL_BUFFER_CLEAR() \
|
||||
do { \
|
||||
while (Serial.available()) { \
|
||||
Serial.read(); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SERIAL_SEND_OK() \
|
||||
do { \
|
||||
Serial.print("ok\n"); \
|
||||
Serial.flush(); \
|
||||
SERIAL_BUFFER_CLEAR(); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Calculate CRC16 using XMODEM polynomial
|
||||
* @param data Pointer to data buffer
|
||||
|
|
@ -24,26 +37,4 @@
|
|||
*/
|
||||
uint16_t calculate_crc16_xmodem(uint8_t *data, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Convert ADC reading to temperature in 0.1°C
|
||||
* @param adc_value 12-bit ADC reading
|
||||
* @return Temperature in 0.1°C
|
||||
*/
|
||||
int16_t adc_to_temperature_c(uint16_t adc_value);
|
||||
|
||||
/**
|
||||
* @brief Convert ADC reading to voltage in mV
|
||||
* @param adc_value ADC reading
|
||||
* @return Voltage in mV
|
||||
*/
|
||||
uint16_t adc_to_voltage_mv(uint16_t adc_value);
|
||||
|
||||
/**
|
||||
* @brief Read ADC with oversampling
|
||||
* @param pin Analog pin to read
|
||||
* @param samples Number of samples for oversampling
|
||||
* @return Averaged ADC value
|
||||
*/
|
||||
uint16_t read_adc_oversampled(uint8_t pin, uint8_t samples);
|
||||
|
||||
#endif // UTILS_H
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue