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