Compare commits

...

18 commits

Author SHA1 Message Date
stephan
df870da929 avr/chaos: die(), fix read_adc()
die(): 'W" 0xd1ff   causes infinite uninteruptable sleep.
Fix adc_sum shift.
Properly account for the new adc_sum format.
Do not fault read_adc() when wdt_tick.



git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9052 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-10 12:16:12 +00:00
stephan
de6e5d2e1d avr/chaos: WDT reboot handling
Interrupts were never enabled unless 'W'.  The WDT was enabled via init_conf().
Result was constant rebooting.

Enable interrupts unconditionally in the main loop.
On boot, detect WDT reset, disable the WDT, chain load a WDT config.
Cmd 'Z' to read the `MCUSR` with the `WDRF`.

Detect WDT interrupts during `spi_slave_Rx()`, answer with an error 'EEW'

`adc_lock` to prevent the WDT ISR to call read_adc() when it is busy.
Also, `read_adc()` will discard the result in case of a `wdt_tick`.



git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9051 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-10 07:32:55 +00:00
stephan
a7504da2ff avr/spi_slave: spi_slave_Rx_wdt()
Flag a case where a WDT interrupt messed with command reception.
The user must define the `wdt_tick` flag.



git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9050 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-10 07:18:27 +00:00
stephan
7f3cb0583a avr/chaos: dac ramp
In conf_init, do dac_ramp last, it takes longest.
Do not dac_ramp in 'L' 10.
Configure dac_nominal=700V with hvosc 55,14.



git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9042 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-09 15:07:00 +00:00
stephan
c20fe169b4 avr/chaos: change R bit allocation R 1 gives integral ADC
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9040 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-09 14:21:02 +00:00
stephan
82d18d3e66 avr/chaos: rounding of adc_noise
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9036 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-09 14:04:25 +00:00
stephan
0f8632bb57 avr/chaos: use PCINT for spi_busy()
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9035 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-08 13:09:09 +00:00
stephan
71a95be193 avr/chaos: send spiu_busy only when something was interrupted
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9034 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-08 12:07:37 +00:00
stephan
2d38e63320 avr/chaos/read_adc: properly saturate the residuals
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9031 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-07 20:43:46 +00:00
stephan
7158c9f6b0 avr/chaos: read_adc optimization
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9025 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-07 17:30:27 +00:00
stephan
6f26cd9469 avr/chaos: fix sense of conf.wdt_toggle
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9020 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-06 09:26:31 +00:00
stephan
23194ceabb avr/chaos: hv_led improvements, spi_busy, …
- Do not toggle the HV LED at every command.
- Toggle with 'W' and 'H'.
- Remove `conf.wdt_save_addr`.
- Add `conf.wdt_toggle`, toggle period of the HV LED in ISR.
- 'H' etc turns the LED on, `hv_led_on()`.
- At boot, only do `hv_safe()` when `conf.safe` (EEPROM[0]).
- 'r' 1 reads `adc_hv`
- Sanitize arg `read_adc(…, n)`
- `spi_busy()`, break out of long loops when SPI SSEL is asserted.
- `clear_spi_busy()` in the main loop, when SSEL is asserted,
  answer with a busy message.



git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9019 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-06 09:24:42 +00:00
stephan
ff93d268e4 avr/spi_slave: Tx gets a const *
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9018 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-06 09:12:53 +00:00
stephan
a758c33f6f avr/chaos 'w': hv_safe()
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9016 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-01 15:03:43 +00:00
stephan
feaa93e086 avr/chaos: use WDCE to set WDIE
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9015 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-01 14:38:10 +00:00
stephan
511bfc0cce chaos/wdt: kick wdt in isr, and more wdt mods
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9014 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-01 14:01:33 +00:00
stephan
84338f287c avr/chaos: INPDIS, swap ADC channels 1,2
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9012 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-01 09:31:21 +00:00
stephan
49643bd07e avr/chaos/hvosc: init drives PWM pins 0
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm/avr@9011 bc5caf13-1734-44f8-af43-603852e9ee25
2024-07-01 09:30:50 +00:00
3 changed files with 297 additions and 159 deletions

View file

@ -8,7 +8,6 @@ const char *revision =
"$Id$";
#define PIN_SSEL (PIND & (1<<PD3))
#include "spi_slave.h"
#include "ads8688.h"
@ -16,7 +15,6 @@ const char *revision =
unsigned char read_adc(unsigned char c, unsigned char n);
void adc_read(unsigned char chs, unsigned char n);
unsigned int read_auxadc();
unsigned int read_hvadc();
void dac_ramp(unsigned int target);
void ads8688_cmd(const unsigned char *c, unsigned char *r);
void ltc1655_cmd(const unsigned char *c);
@ -27,6 +25,17 @@ void ads8688_config();
#include "hvosc.h"
#include <avr/interrupt.h>
#include <avr/sleep.h>
void die()
{
while (1) {
cli();
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_enable();
sleep_cpu();
}
}
static inline unsigned char disable_irq()
{
@ -66,7 +75,7 @@ static inline void avrdac_set(unsigned int d)
#include <avr/wdt.h>
void wdt_init(unsigned char mode);
unsigned char wdt_count;
unsigned char wdt_saved;
volatile unsigned char wdt_tick;
enum {
WDT_MODE_LIVE = 2, // = any command kick
@ -82,52 +91,54 @@ static inline void wdt_kick()
}
// ADS8688 gains Channels:
// 0: ±2.5 Vref = ± 10.24V 0: Iprim, 0.5V/A, ± 0.64V
// 1: ±1.25 Vref = ± 5.12V 1: HV Mon, ±5V
// 2: ±0.625 Vref = ± 2.56V 2: Vdrv, 0…10V
// 3: ±0.3125 Vref = ± 1.28V 3: NTC, 0…5V
// b: ±0.15625 Vref = ± 0.64V 4: Vprim/11, 0…5V
// 5: 0…2.5 Vref = 0…10.24V 5: 5V/2, 0…5V
// 6: 0.1,25 Vref = 0… 5.12V 6: I_bias, ±2.56V
// 7: 0.625 Vref = 0… 2.56V 7: Idrv, 0…10V
// 0: ±2.5 Vref = ± 10.24V 0: b: Iprim, 0.5V/A, ± 0.64V
// 1: ±1.25 Vref = ± 5.12V 1: 5: Vdrv, 0…10V
// 2: ±0.625 Vref = ± 2.56V 2: 1: HV Mon, ±5V
// 3: ±0.3125 Vref = ± 1.28V 3: 6: NTC, 0…5V
// b: ±0.15625 Vref = ± 0.64V 4: 6: Vprim/11, 0…5V
// 5: 0…2.5 Vref = 0…10.24V 5: 6: 5V/2, 0…5V
// 6: 0.1,25 Vref = 0… 5.12V 6: 2: I_bias, ±2.56V
// 7: 0.625 Vref = 0… 2.56V 7: 5: Idrv, 0…10V
// f: 0.3125 Vref = 0… 1.28V A: dac
#ifndef ADC_GAIN
# define ADC_GAINS 0x5266651bUL
# define ADC_GAINS 0x5266615bUL
#endif
#define MAGIC 0xc05c
#define VERSION 2
#define VERSION 4
struct conf {
unsigned int magic;
unsigned char version;
unsigned char flags;
unsigned char flags2;
unsigned int dac;
unsigned int dac_nominal;
unsigned int dac_off;
unsigned int tick_period;
unsigned char wdt_timeout;
unsigned char wdt_mode;
unsigned char wdt_save_addr;
unsigned char avradc;
unsigned int avrdac;
unsigned int adcconf;
unsigned long adcgain;
unsigned char auxadc_n;
unsigned char hvadc_ch;
unsigned char hvadc_n;
unsigned char safe;
unsigned int hvadc_safe;
unsigned char ddrc;
unsigned char portc;
unsigned char portc_on;
unsigned char portc_off;
unsigned char hvosc_freq;
unsigned char hvosc_dc;
unsigned char padding[3];
} conf;
unsigned int magic; // 0
unsigned char version; // 2
unsigned char flags; // 3
unsigned char flags2; // 4
unsigned int dac; // 5
unsigned int dac_nominal; // 7
unsigned int dac_off; // 9
unsigned int tick_period; // 11
unsigned char wdt_timeout; // 13
unsigned char wdt_mode; // 14
unsigned char wdt_toggle; // 15
unsigned char avradc; // 16
unsigned int avrdac; // 17
unsigned int adcconf; // 19
unsigned long adcgain; // 21
unsigned char auxadc_n; // 25
unsigned char hvadc_ch; // 26
unsigned char hvadc_n; // 27
unsigned char safe; // 28
unsigned int hvadc_safe; // 29
unsigned char ddrc; // 31
unsigned char portc; // 32
unsigned char portc_on; // 33
unsigned char portc_off; // 34
unsigned char hvosc_freq; // 35
unsigned char hvosc_dc; // 36
unsigned char inpdis; // 37
unsigned char wdt_load; // 38
unsigned char padding; // 39
} conf; // 40
enum {
FLAG_WDT = 1,
@ -141,6 +152,7 @@ enum {
FLAG2_PC_HV = 2,
FLAG2_HVOSC = 4,
FLAG2_HVLED = 8,
FLAG2_INPDIS = 16,
};
__attribute__((section(".eeprom")))
@ -148,55 +160,64 @@ const struct conf runconf[] = {
[0] = { // Default
.magic = MAGIC,
.version = VERSION,
.flags = FLAG_RAMP | FLAG_ADCCONF | FLAG_DACADC,
.flags2 = FLAG2_HVOSC | FLAG2_HVLED | FLAG2_INPDIS,
.wdt_mode = 1,
.wdt_timeout = 120, // 2 min
.tick_period = TICK_NS(10000000L), // 10ms ramp
.wdt_toggle = 8, // sec
.tick_period = TICK_NS(1000000L), // 1ms ramp
.avradc = 0x7f, // off
.adcconf = 0x8500,// RST
.ddrc = 2, // OC1B HVOSC
.adcgain = ADC_GAINS,
.auxadc_n = 4,
.hvadc_ch = 1,
.hvadc_n = 4,
.hvadc_safe = 0x8100,
.hvadc_ch = 2,
.hvadc_n = 2,
.hvadc_safe = 0,
.inpdis = 0x3f,
.wdt_load = 20,
},
[1] = { // ON
.magic = MAGIC,
.version = VERSION,
.flags = FLAG_WDT | FLAG_RAMP | FLAG_ADCCONF | FLAG_DACADC,
.flags2 = FLAG2_HVOSC | FLAG2_HVLED,
.flags = FLAG_WDT | FLAG_ADCCONF | FLAG_DACADC,
.flags2 = FLAG2_HVOSC | FLAG2_HVLED | FLAG2_INPDIS,
.wdt_mode = 4,
.wdt_timeout = 120, // 2 min
.tick_period = TICK_NS(10000000L), // 10ms ramp
.wdt_toggle = 8, // sec
.tick_period = TICK_NS(1000000L), // 1ms ramp
.avradc = 0x7f, // off
.adcconf = 0x8500,// RST
.adcgain = ADC_GAINS,
.auxadc_n = 4,
.hvadc_ch = 1,
.hvadc_n = 4,
.hvadc_safe = 0x8100,
.hvadc_ch = 2,
.hvadc_n = 2,
.hvadc_safe = 0,
.ddrc = 2, // OC1B HVOSC
.hvosc_freq = 64,
.hvosc_dc = 19,
.dac_nominal = 100,
.hvosc_freq = 55,
.hvosc_dc = 14,
.dac_off = 1000,
.dac_nominal = 34832, // 700 V
.inpdis = 0x3f,
},
[2] = { // SAFE
.magic = MAGIC,
.version = VERSION,
.safe = 1,
.flags = FLAG_WDT | FLAG_RAMP | FLAG_ADCCONF | FLAG_DACADC,
.flags2 = FLAG2_HVOSC | FLAG2_HVLED,
.flags = FLAG_WDT | FLAG_RAMP | FLAG_ADCCONF,
.flags2 = FLAG2_HVOSC | FLAG2_HVLED | FLAG2_INPDIS,
.wdt_timeout = 120, // 2 min
.tick_period = TICK_NS(10000000L), // 10ms ramp
.wdt_toggle = 8, // sec
.tick_period = TICK_NS(1000000L), // 1ms ramp
.avradc = 0x7f, // off
.adcconf = 0x8500,// RST
.adcgain = ADC_GAINS,
.auxadc_n = 4,
.hvadc_ch = 1,
.hvadc_n = 4,
.hvadc_safe = 0x8100,
.hvadc_ch = 2,
.hvadc_n = 2,
.hvadc_safe = 683 + 0x8000, // 30V
.ddrc = 2, // OC1B HVOSC
.hvosc_freq = 0,
.hvosc_dc = 0,
.dac_nominal = 0,
.inpdis = 0x3f,
},
};
@ -213,20 +234,23 @@ void conf_init()
ads8688_config();
if (conf.flags & FLAG_DACADC)
conf.dac = read_auxadc(conf.auxadc_n);
if (conf.flags & FLAG_RAMP)
dac_ramp(conf.dac_nominal);
if (conf.flags & FLAG_ADC)
avradc_enable(conf.avradc);
if (conf.flags & FLAG_DAC)
avrdac_set(conf.avrdac);
if (conf.flags2 & FLAG2_HVLED) {
conf.ddrc |= LED_MASK;
led_init();
}
if (conf.flags2 & FLAG2_PORTC) {
PORTC = conf.portc;
DDRC = conf.ddrc;
}
if (conf.flags2 & FLAG2_INPDIS) {
DIDR0 = conf.inpdis << 5;
DIDR1 = conf.inpdis >> 3;
}
if (conf.flags & FLAG_RAMP)
dac_ramp(conf.dac_nominal);
}
#include <avr/eeprom.h>
@ -253,7 +277,8 @@ int hv_is_safe()
{
return !hvosc_is_on()
&& conf.dac <= conf.dac_off
&& adc_hv <= conf.hvadc_safe
&& (!conf.hvadc_safe
|| adc_hv <= conf.hvadc_safe)
;
}
@ -267,6 +292,45 @@ void toggle_hv_led()
}
}
void hv_led_on()
{
if (conf.flags2 & FLAG2_HVLED) {
if (hv_is_safe())
led_on(LED_GREEN);
else
led_on(LED_RED);
}
}
char spi_was_busy;
static inline
void spi_busy_init()
{
PCMSK2 |= 8; // PIND3 PCINT19
while (!(PIND & 8));
PCIFR = 4;
}
static inline
unsigned char spi_busy()
{
// Return true if the SSEL pin became low
unsigned char f = PCIFR & 4;
PCIFR = 4;
spi_was_busy = f && !(PIND & 8);
return spi_was_busy;
}
static inline
void clear_spi_busy()
{
const unsigned char *busy_msg = (const unsigned char *) "\xff\xff\xff" "EEY";
if (spi_was_busy && !(PIND & 8))
spi_slave_Tx(busy_msg, 6);
spi_was_busy = 0;
}
__attribute__((noinline))
void hv_safe()
{
@ -278,17 +342,33 @@ void hv_safe()
ltc1655_cmd(INT2FRAME(conf.dac_off));
conf.dac = conf.dac_off;
unsigned int adc_last = 0xffff;
while (!read_hvadc()) {
if (adc_hv < conf.hvadc_safe || adc_hv >= adc_last)
break;
adc_last = adc_hv;
unsigned int toggle = 0;
if (conf.hvadc_safe) {
spi_busy_init();
while (!read_adc(conf.hvadc_ch, conf.hvadc_n)) {
if (spi_busy())
break;
wdt_reset();
if (adc_hv < conf.hvadc_safe || adc_hv >= adc_last)
break;
adc_last = adc_hv;
toggle++;
if (!toggle)
toggle_hv_led();
}
}
enable_irq(sreg);
toggle_hv_led();
hv_led_on();
}
unsigned char wdt_killed_us;
int main()
{
wdt_killed_us = MCUSR;
MCUSR = 0;
wdt_init(0);
// turn of unused IO modules
PRR = (1<<PRPSC)|(1<<PRCAN)|(1<<PRTIM1)|(1<<PRLIN)|(1<<PRADC);
@ -296,20 +376,33 @@ int main()
DDRB |= (1<<PB0); // make MISO an output
ads8688_init();
ltc1655_init();
hv_safe();
eeprom_load(0);
if (conf.magic == MAGIC && conf.version == VERSION)
if (conf.wdt_load
&& wdt_killed_us & (1<<WDRF)
&& conf.magic == MAGIC
&& conf.version == VERSION)
eeprom_load(conf.wdt_load);
if (conf.magic == MAGIC && conf.version == VERSION) {
conf_init();
if (conf.safe)
hv_safe();
}
while (1) {
sei();
clear_spi_busy();
unsigned char cmd[3];
unsigned char resp[3];
unsigned char c;
unsigned char sreg;
const char *p;
spi_slave_Rx(cmd, 3);
if (spi_slave_Rx_wdt(cmd, 3)) {
const unsigned char *wdt_msg =
(const unsigned char *) "\xff\xff\xff" "EEW";
spi_slave_Tx(wdt_msg, 6);
continue;
}
cli();
resp[0] = cmd[0];
toggle_hv_led();
sreg = disable_irq();
if (conf.wdt_mode == WDT_MODE_LIVE)
wdt_kick();
switch (cmd[0]) {
@ -328,15 +421,11 @@ int main()
int2frame(conf.dac_nominal, resp+1);
conf.dac_nominal = frame2int(cmd+1);
break;
case 'w':
int2frame(conf.dac_off, resp+1);
conf.dac_off = frame2int(cmd+1);
break;
case 'H':
int2frame(conf.dac, resp+1);
if (conf.wdt_mode >= WDT_MODE_HV)
wdt_kick();
enable_irq(sreg);
sei();
spi_slave_Tx(resp, 3);
dac_ramp(frame2int(cmd+1));
continue;
@ -348,7 +437,7 @@ int main()
int2frame(conf.dac, resp+1);
if (conf.wdt_mode >= WDT_MODE_HV)
wdt_kick();
enable_irq(sreg);
sei();
spi_slave_Tx(resp, 3);
dac_ramp(conf.dac_nominal);
continue;
@ -361,6 +450,7 @@ int main()
conf.hvosc_dc = cmd[2];
}
hvosc_init(conf.hvosc_freq, conf.hvosc_dc);
hv_led_on();
conf.safe = 0;
break;
case 'I':
@ -378,7 +468,7 @@ int main()
case 't':
resp[1] = adc_status;
resp[2] = adc_error;
enable_irq(sreg);
sei();
spi_slave_Tx(resp, 3);
if (cmd[1]) {
if (upcase(cmd[0])) {
@ -395,20 +485,17 @@ int main()
if (c>8)
c = 8;
switch (cmd[2]) {
case 1: int2frame(adc_sum[c], resp+1); break;
case 2: resp[1] = adc_sum[c] >> 16; resp[2] = adc_n[c]; break;
case 1: int2frame(adc_sum[c] >> 8, resp+1); break;
case 2: resp[1] = adc_sum[c]; resp[2] = adc_n[c]; break;
case 3: int2frame(adc_noise[c], resp+1); break;
default: resp[1] = adc_status; resp[2] = adc_error; break;
}
break;
case 'r':
if (adc_error) {
resp[0] = 'E';
resp[1] = 'r';
resp[2] = adc_error;
break;
}
int2frame(adc_aux, resp+1);
if (cmd[1])
int2frame(adc_hv, resp+1);
else
int2frame(adc_aux, resp+1);
break;
case 'V':
p = revision;
@ -420,18 +507,26 @@ int main()
resp[1] = *p;
resp[2] = cmd[1]-c;
break;
case 'w':
resp[1] = conf.wdt_mode;
resp[2] = wdt_count;
sei();
spi_slave_Tx(resp, 3);
hv_safe();
break;
case 'W':
if (cmd[1]==0xff && cmd[2]==0xd1)
die();
resp[1] = conf.wdt_mode;
resp[2] = conf.wdt_timeout;
if (cmd[2])
conf.wdt_timeout = cmd[2];
if (cmd[1]) {
if (cmd[1])
wdt_init(cmd[1]);
sreg = (1<<SREG_I);
}
else {
resp[2] = wdt_count;
wdt_kick();
toggle_hv_led();
}
break;
case 'm':
@ -449,7 +544,7 @@ int main()
case 'S':
resp[1] = cmd[1];
resp[2] = sizeof(conf);
enable_irq(sreg);
sei();
spi_slave_Tx(resp, 3);
eeprom_save(cmd[1]);
continue;
@ -465,7 +560,7 @@ int main()
break;
}
if (cmd[1] && upcase(cmd[1])) {
enable_irq(sreg);
sei();
spi_slave_Tx(resp, 3);
conf_init();
continue;
@ -533,8 +628,20 @@ int main()
if (!upcase(cmd[0]))
*(unsigned char *)(cmd[1]+0) = cmd[2];
break;
case 'Z':
case 'z':
resp[1] = cmd[1];
switch (cmd[1]) {
case 0: resp[2] = wdt_killed_us; break;
}
if (upcase(cmd[0]))
break;
switch (cmd[1]) {
case 0: wdt_killed_us = cmd[2]; break;
}
break;
}
enable_irq(sreg);
sei();
spi_slave_Tx(resp, 3);
}
}
@ -555,8 +662,13 @@ void ads8688_config()
}, r);
}
volatile unsigned char adc_lock;
unsigned char read_adc(unsigned char c, unsigned char n)
{
unsigned char e = 0;
if (n>8)
n=8;
unsigned char nn = (1<<n) - 1;
unsigned char cc;
if (c >= 8) {
@ -566,42 +678,58 @@ unsigned char read_adc(unsigned char c, unsigned char n)
else
cc = 1<<c;
spi_int_init();
unsigned char cmd[2] = {0, 0xc0 | (c << 2)};
unsigned char resp[2];
unsigned char i;
adc_lock = 1;
unsigned char sreg = disable_irq();
for (i=0; i<3; i++)
ads8688_cmd(cmd, resp);
enable_irq(sreg);
unsigned int s0 = frame2int(resp);
unsigned long s = s0;
int r = 0;
unsigned long q = 0;
spi_busy_init();
for (i=0; i<nn; i++) {
if (spi_int())
return adc_error |= cc;
unsigned char sreg = disable_irq();
if (spi_busy()) {
e = adc_error |= cc;
goto out;
}
sreg = disable_irq();
ads8688_cmd(cmd, resp);
enable_irq(sreg);
unsigned int s1 = frame2int(resp);
s += s1;
char d = s1 - s0;
int dd = s1 - s0;
if (dd > 127)
dd = 127;
if (dd < -127)
dd = -127;
signed char d = dd;
r += d;
q += d * d;
}
unsigned long rr = (long)r*r;
unsigned long qq = (nn+1)*q;
unsigned long chi2 = qq-rr;
adc_sum[c] = s;
adc_noise[c] = chi2 >> n;
unsigned long qq = q << n;
unsigned long chi2 = qq - rr;
adc_sum[c] = s << (8-n);
chi2 >>= 2*n - 1;
chi2 += 1;
chi2 >>= 1;
adc_noise[c] = chi2;
adc_n[c] = n;
adc_status |= cc;
return 0;
if (c == conf.hvadc_ch)
adc_hv = adc_sum[c] >> 8;
out:
adc_lock = 0;
return e;
}
void adc_read(unsigned char chs, unsigned char n)
{
spi_int_init();
adc_status = 0;
adc_error = 0;
unsigned char c;
@ -610,34 +738,24 @@ void adc_read(unsigned char chs, unsigned char n)
continue;
if (read_adc(c, n))
return;
if (c==conf.hvadc_ch)
adc_hv = adc_sum[c] >> n;
}
}
unsigned int read_hvadc()
{
unsigned char n = conf.hvadc_n;
unsigned char c = conf.hvadc_ch;
if (!read_adc(c, n))
adc_hv = adc_sum[c] >> n;
return adc_hv;
}
unsigned int read_auxadc()
{
unsigned char n = conf.auxadc_n;
if (!read_adc(8, n))
adc_aux = adc_sum[8] >> n;
adc_aux = adc_sum[8] >> 8;
return adc_aux;
}
void dac_ramp(unsigned int target)
{
conf.safe = 0;
spi_int_init();
unsigned char toggle = 0;
spi_busy_init();
while (conf.dac != target) {
if (spi_int())
if (spi_busy())
return;
if (!tick(TICKO))
continue;
@ -649,24 +767,36 @@ void dac_ramp(unsigned int target)
conf.dac = target;
ltc1655_cmd(INT2FRAME(conf.dac));
enable_irq(sreg);
toggle++;
if (!toggle)
toggle_hv_led();
}
hv_led_on();
}
ISR(WDT_vect)
{
if (conf.safe && !hv_is_safe())
read_hvadc();
toggle_hv_led();
if (wdt_count++ < conf.wdt_timeout)
goto wdt_out;
hv_safe();
wdt_reset();
if (conf.wdt_save_addr && !wdt_saved) {
wdt_saved = 1;
eeprom_save(conf.wdt_save_addr);
wdt_count++;
if (wdt_count >= conf.wdt_toggle) {
if (conf.safe && conf.hvadc_safe && !adc_lock) {
adc_hv = 0;
read_adc(conf.hvadc_ch, conf.hvadc_n);
}
toggle_hv_led();
}
if (wdt_count < conf.wdt_timeout)
goto wdt_out;
wdt_count = 0;
hv_safe();
wdt_out:
WDTCSR |= WDIE;
__asm__("STS %[CSR], %[CE]" "\n\t"
"STS %[CSR], %[IE]" "\n"
::[CSR] "n" (&WDTCSR),
[CE] "r" ((unsigned char)(1<<WDCE | 1<<WDE | 1<<WDP2 | 1<<WDP1)),
[IE] "r" ((unsigned char)(1<<WDIE | 1<<WDE | 1<<WDP2 | 1<<WDP1))
);
wdt_tick = 1;
}
void wdt_init(unsigned char mode)
@ -674,7 +804,12 @@ void wdt_init(unsigned char mode)
conf.wdt_mode = mode;
wdt_reset();
if (mode < WDT_MODE_LIVE) {
WDTCSR = 0;
__asm__("STS %[CSR], %[CE]" "\n\t"
"STS %[CSR], %[IE]" "\n"
::[CSR] "n" (&WDTCSR),
[CE] "r" ((unsigned char)(1<<WDCE | 1<<WDIE | 1<<WDE | 1<<WDP2 | 1<<WDP1)),
[IE] "r" ((unsigned char)(1<<WDP2 | 1<<WDP1))
);
return;
}
// 1s timeout, WDT interrupt enabled
@ -713,10 +848,4 @@ void avradc_enable(unsigned char c)
if (!(c&0x80))
ADCSRA |= 1<<ADEN;
ADCSRA |= 1<<ADSC;
if (cc==4)
; // SPI SCK
else if (cc<8)
DIDR0 = 1<<cc;
else if (cc<11)
DIDR1 = 1<<(cc&3);
}

View file

@ -2,13 +2,15 @@
static inline void hvosc_init(unsigned char freq, unsigned char dc)
{
PORTC &=~ (1<<PC1);
PORTD &=~ (1<<PD2);
DDRC |= (1<<PC1);
DDRD |= (1<<PD2);
if (!dc || freq <= dc) {
TCCR1A = 0;
return;
}
PRR &=~ (1<<PRTIM1);
DDRC |= (1<<PC1);
DDRD |= (1<<PD2);
TCCR1A = (2<<COM1A0) | (3<<COM1B0) | (2<<WGM10);
TCCR1B = (1<<CS10) | (2<<WGM12);
ICR1H = 0;

View file

@ -32,7 +32,28 @@ static inline void spi_slave_Rx(unsigned char d[], unsigned char n)
}
}
static inline void spi_slave_Tx(unsigned char d[], unsigned char n)
extern volatile unsigned char wdt_tick;
static inline char spi_slave_Rx_wdt(unsigned char d[], unsigned char n)
{
SPSR;
SPDR;
register unsigned char b;
do {
while (!(SPSR & SPSR_IF));
wdt_tick = 0;
SPDR = 0xff;
b = SPDR;
} while (b&0x80);
*d++ = b;
while (--n) {
while (!(SPSR & SPSR_IF));
SPDR = 0xff;
*d++ = SPDR;
}
return wdt_tick;
}
static inline void spi_slave_Tx(const unsigned char d[], unsigned char n)
{
SPSR;
SPDR;
@ -55,17 +76,3 @@ static inline unsigned int frame2int(unsigned char *f)
}
#define INT2FRAME(i) ((unsigned char []){i, i>>8})
#ifdef PIN_SSEL
static inline unsigned int spi_int()
{
// Return true if the SSEL pin is low
return !PIN_SSEL;
}
static inline void spi_int_init()
{
while (spi_int());
}
#endif