You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
3.2 KiB
141 lines
3.2 KiB
3 years ago
|
/**
|
||
|
* High voltage source control logic
|
||
|
*/
|
||
|
|
||
|
#include "high_voltage.h"
|
||
|
#include "iopins.h"
|
||
|
#include "global_state.h"
|
||
|
#include <stdbool.h>
|
||
|
#include <avr/interrupt.h>
|
||
|
#include <util/atomic.h>
|
||
|
|
||
|
static volatile bool is_pwm_on = false;
|
||
|
|
||
|
// tube starting voltage is 350V
|
||
|
#define TURN_ON_VOLTAGE 355.0
|
||
|
#define TURN_OFF_VOLTAGE 380.0
|
||
|
#define MINIMAL_VOLTAGE 350.0
|
||
|
|
||
|
// sensing via resistive divider
|
||
|
#define VREF 1.1
|
||
|
|
||
|
// in kiloohms
|
||
|
#define R_UPPER 10000.0
|
||
|
#define R_LOWER 27.0
|
||
|
|
||
|
#define ADC_MAXVAL 1023
|
||
|
|
||
|
#define RDIV_FACTOR (R_LOWER / (R_UPPER + R_LOWER))
|
||
|
|
||
|
/// ADC input voltage that's too low - PWM must start
|
||
|
#define VSEN_TURN_ON (TURN_ON_VOLTAGE * RDIV_FACTOR)
|
||
|
/// ADC input voltage that's too high - PWM must stop
|
||
|
#define VSEN_TURN_OFF (TURN_OFF_VOLTAGE * RDIV_FACTOR)
|
||
|
/// ADC input voltage that's lowest possible for the geiger tube to function
|
||
|
#define VSEN_MINIMAL (MINIMAL_VOLTAGE * RDIV_FACTOR)
|
||
|
|
||
|
// the above, but converted to ADC word
|
||
|
#define ADCVAL_TURN_ON ((uint16_t) (ADC_MAXVAL * (VSEN_TURN_ON / VREF)))
|
||
|
#define ADCVAL_TURN_OFF ((uint16_t) (ADC_MAXVAL * (VSEN_TURN_OFF / VREF)))
|
||
|
#define ADCVAL_MINIMAL ((uint16_t) (ADC_MAXVAL * (VSEN_MINIMAL / VREF)))
|
||
|
|
||
|
/// Channel used to measure VSEN
|
||
|
#define VSEN_ADC_CHANNEL 0
|
||
|
|
||
|
|
||
|
/// when capacitor was last fully charged
|
||
|
static volatile uint16_t ts_cap_charged = 0;
|
||
|
|
||
|
static void pwm_on()
|
||
|
{
|
||
|
TCCR0A |= _BV(COM0B1);
|
||
|
is_pwm_on = true;
|
||
|
}
|
||
|
|
||
|
static void pwm_off()
|
||
|
{
|
||
|
TCCR0A &= ~_BV(COM0B1);
|
||
|
is_pwm_on = false;
|
||
|
}
|
||
|
|
||
|
|
||
|
ISR(ADC_vect)
|
||
|
{
|
||
|
// Service the boost converter
|
||
|
uint16_t analog = ADCW;
|
||
|
|
||
|
if (is_pwm_on) {
|
||
|
if (analog >= ADCVAL_TURN_OFF) {
|
||
|
pwm_off();
|
||
|
ts_cap_charged = timestamp_100ms;
|
||
|
} else {
|
||
|
// If fail to reach target voltage in reasonable time,
|
||
|
// show weak battery icon and stop trying.
|
||
|
if ((timestamp_100ms - ts_cap_charged) > 10 && analog < ADCVAL_MINIMAL) {
|
||
|
is_weak_battery = true;
|
||
|
}
|
||
|
}
|
||
|
} else if (analog < ADCVAL_TURN_ON) {
|
||
|
pwm_on();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static void init_pwm_out()
|
||
|
{
|
||
|
// Output is OC0A
|
||
|
as_output(D5);
|
||
|
|
||
|
// initialize the timer
|
||
|
// Fast PWM mode, Output to OC0A
|
||
|
|
||
|
// clock is 16MHz, presc /64, counting to 80 -> freq 3125Hz
|
||
|
// Duty cycle = appx. 60%
|
||
|
|
||
|
OCR0A = 80;
|
||
|
OCR0B = 46;
|
||
|
TCCR0A = _BV(WGM00) | _BV(WGM01);
|
||
|
TCCR0B = _BV(CS01) | _BV(CS00) | _BV(WGM02);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void init_adc()
|
||
|
{
|
||
|
ADCSRA =
|
||
|
// 128 prescaler -> 125 kHz
|
||
|
_BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0)
|
||
|
// auto trigger
|
||
|
| _BV(ADATE)
|
||
|
// interrupt enable
|
||
|
| _BV(ADIE);
|
||
|
|
||
|
ADCSRB = 0; // free-running
|
||
|
DIDR0 = ADC0D; // disable the digital input buffer on the pin
|
||
|
|
||
|
ADMUX =
|
||
|
// internal ref 1.1V
|
||
|
_BV(REFS0) | _BV(REFS1)
|
||
|
// select channel
|
||
|
| VSEN_ADC_CHANNEL;
|
||
|
|
||
|
sbi(ADCSRA, ADEN); // Enable ADC
|
||
|
sbi(ADCSRA, ADSC); // Start
|
||
|
}
|
||
|
|
||
|
|
||
|
void init_high_voltage()
|
||
|
{
|
||
|
init_pwm_out();
|
||
|
init_adc();
|
||
|
}
|
||
|
|
||
|
void hv_disable()
|
||
|
{
|
||
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||
|
// if ADC is disabled, the IRQ never fires and it won't be turned on
|
||
|
cbi(ADCSRA, ADEN);
|
||
|
// Turn it off
|
||
|
pwm_off();
|
||
|
}
|
||
|
}
|