diff --git a/include/adc.h b/include/adc.h index 213f73a..6ec842e 100644 --- a/include/adc.h +++ b/include/adc.h @@ -13,7 +13,7 @@ -#define ADC_CHANNELS 6 +#define ADC_CHANNELS 5 #define ADC_HISTLEN 16 @@ -25,6 +25,8 @@ extern uint16_t adc_avg[ADC_CHANNELS]; void adc_init(); uint8_t adc_next(); +void adc_switch0(); + #endif /* _INC_ADC_H */ \ No newline at end of file diff --git a/include/probe.h b/include/probe.h new file mode 100644 index 0000000..96df621 --- /dev/null +++ b/include/probe.h @@ -0,0 +1,21 @@ +/* + * probe.c: helping you probe things + * + * file creation: 20231021 1717 + */ + +#ifndef _INC_PROBE_H +#define _INC_PROBE_H + + +#include + + + +void probe_mode_switch(uint8_t mode); + +void probe_measure(); + + + +#endif /* _INC_PROBE_H */ \ No newline at end of file diff --git a/include/testo.h b/include/testo.h index 1646590..7308312 100644 --- a/include/testo.h +++ b/include/testo.h @@ -77,9 +77,9 @@ #define ADC_PROBE 1 -#define ADC_VREF_INT 5 +#define ADC_VREF_INT 4 #define ADC_VREF_EXT 0 -#define ADC_THERM 4 +// #define ADC_THERM 4 diff --git a/include/userio.h b/include/userio.h index 67d147f..103758d 100644 --- a/include/userio.h +++ b/include/userio.h @@ -4,9 +4,33 @@ * file creation: 20231016 1505 */ +#ifndef _INC_USERIO_H +#define _INC_USERIO_H + #include +#define MODE_CONT 0 +#define MODE_CONT_TARGET 3072 // (4096 * (1 - (1 / 4))) + +#define MODE_FUN 1 +#define MODE_FUN_TARGET 2731 // (4096 * (1 - (1 / 3))) + +#define MODE_DIODE 2 +#define MODE_DIODE_TARGET 2048 // (4096 * 1 - ((1 / 2))) + + + +extern uint8_t knob[2]; + + + void userio_parse(); + +uint8_t userio_get_mode(); + + + +#endif /* _INC_USERIO_H */ \ No newline at end of file diff --git a/lib/cmsis/src/cmsis_gcc.h b/lib/cmsis/src/cmsis_gcc.h index bb89fbb..fb83ae3 100644 --- a/lib/cmsis/src/cmsis_gcc.h +++ b/lib/cmsis/src/cmsis_gcc.h @@ -161,7 +161,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PSP(void) */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PSP(uint32_t topOfProcStack) { - __ASM volatile ("MSR psp, %0\n" : : "r" (topOfProcStack) : "sp"); + __ASM volatile ("MSR psp, %0\n" : : "r" (topOfProcStack)); } @@ -187,7 +187,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_MSP(void) */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_MSP(uint32_t topOfMainStack) { - __ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) : "sp"); + __ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack)); } diff --git a/src/adc.c b/src/adc.c index 7401f43..00ca8cb 100644 --- a/src/adc.c +++ b/src/adc.c @@ -40,6 +40,7 @@ + static uint16_t adc_read[ADC_CHANNELS]; static uint16_t adc_hist[ADC_CHANNELS][ADC_HISTLEN]; @@ -61,16 +62,17 @@ void adc_init() // calibration configuration ADC1->CCSR = LL_ADC_CAL_SAMPLINGTIME_8CYCLES | ADC_CCSR_CALSEL; - // enable VREFINT and temperature sensor - ADC->CCR = ADC_CCR_TSEN | ADC_CCR_VREFEN; + // enable VREFINT + ADC->CCR = ADC_CCR_VREFEN; // ADC_CCR_TSEN | // configure scan channels, sampling time (11 = temp, 12 = vrefint) - ADC1->CHSELR = CONF_SET1_AN | PROBE_AN | // note: SET1 and PROBE are + ADC1->CHSELR = CONF_SET1_AN | PROBE_AN | // note: SET1 and VREFEXT are CONF_MODE_AN | CONF_SET0_AN | // shared and reflect one chan - ADC_CHSELR_CHSEL11 | ADC_CHSELR_CHSEL12; + ADC_CHSELR_CHSEL12; ADC1->SMPR = SAMPLE_TIME; - // run in one-shot mode (scan all channels) but with wait mode active + // run in one-shot mode (all channel conversion per trigger) + // with wait mode (anti-overrun) active ADC1->CFGR1 = ADC_CFGR1_OVRMOD | ADC_CFGR1_WAIT; // enable end of conversion interrupt @@ -188,8 +190,6 @@ uint8_t adc_next() } // check vref to determine if we need to recalibrate - // the way this is written now, - // this will always do a double-calibrate at the start w = adc_avg[ADC_VREF_INT]; if ((abs(vref - w) > 3) || (abs(w - vref) > 3)) { calibrate = 1; @@ -205,13 +205,17 @@ uint8_t adc_next() void ADC_COMP_IRQHandler() { - if (adc_seq != 0xff) { + if (adc_seq < ADC_CHANNELS) { adc_read[adc_seq++] = ADC1->DR; // is this the end of conversions? if (ADC1->ISR & ADC_ISR_EOSEQ) { adc_seq = ADC_SEQ_RDY; } + } else { + // we shouldn't be here. something with ADC fucked up. + // reset ADC, clear sequence, and start again + adc_go(); } // clear all interrupt flags diff --git a/src/led.c b/src/led.c index 590811b..0547b89 100644 --- a/src/led.c +++ b/src/led.c @@ -25,6 +25,9 @@ static uint8_t snd_buzz; // piezo sounder active? static uint16_t rgb[2][3]; // RGBLED actual values to set +static uint8_t dualtone = 0; // buzzer dualtone mode +static uint8_t dt_cntr = 0; // buzzer dualtone counter + /* @@ -57,8 +60,26 @@ void led_next() // enable selected LED if (led_sel) { - if ((led_mode == MODE_BUZZ) && !snd_buzz) return; - RGBSEL1_PORT->BRR = (1 << RGBSEL1_PIN); + switch (led_mode) { + case MODE_RGB: { + RGBSEL1_PORT->BRR = (1 << RGBSEL1_PIN); + break; + } + case MODE_BUZZ: { + if (!snd_buzz) return; + + // dual tone + dt_cntr++; + dt_cntr &= 1; + if (!dt_cntr) { + dualtone ^= 1; + } + + if (!dt_cntr || dualtone) { + RGBSEL1_PORT->BRR = (1 << RGBSEL1_PIN); + } + } + } } else { RGBSEL0_PORT->BRR = (1 << RGBSEL0_PIN); } @@ -146,9 +167,6 @@ void led_init() led_sel = 1; snd_buzz = 0; - rgb[0][0] = 100; - rgb[1][1] = 100; - // start outputting data led_next(); } \ No newline at end of file diff --git a/src/main.c b/src/main.c index 7edc5a3..bf3968c 100644 --- a/src/main.c +++ b/src/main.c @@ -12,6 +12,7 @@ #include "adc.h" #include "flash.h" #include "led.h" +#include "probe.h" #include "userio.h" @@ -143,10 +144,15 @@ __attribute__ ((long_call, section(".ramfunc"))) void SysTick_Handler(void) // adc tested to result in about 61 reads/second if (!adc_next()) { - // adc has new computed results, so we can do userio, probe, etc + // adc has new computed results if (uptime || cs) { + // figure out knobs, buttons, switches userio_parse(); + + // show probe measurement results, or if not in a measurement mode, + // run RGBLED program + probe_measure(); } } } -} \ No newline at end of file +} diff --git a/src/probe.c b/src/probe.c index 87249eb..02d375a 100644 --- a/src/probe.c +++ b/src/probe.c @@ -5,4 +5,134 @@ * continuity and diode tests from the raw analog data. * * file creation: 20231016 0255 - */ \ No newline at end of file + */ + +#include "py32f0xx_conf.h" + +#include "testo.h" + +#include "adc.h" +#include "led.h" +#include "userio.h" + + + +#define CONT_OPEN 1240 + + + +// diode measurements at 3V3 +#define DIODE_OPEN 4000 // test unit measures ~4060 +#define DIODE_STANDARD 2330 // fairchild 5V2 zener, forward biased +#define DIODE_SCHOTTKY 1960 // vishay 40V 1A SB140 +#define DIODE_LED_BLUE 3190 +#define DIODE_LED_GRN 3040 // very dim +#define DIODE_LED_RED 3020 +#define DIODE_SHORT 1900 // test unit measures ~1820 + +#define SHORT_THRESHOLD 2 + + + +static uint16_t vref; +static uint8_t latch = 0; + + + +static inline void probe_measure_cont() +{ + uint16_t probe, v_ext; + uint32_t x; + + probe = adc_avg[ADC_PROBE]; + v_ext = adc_avg[ADC_VREF_EXT]; + + // this LED will not set anything, + // but zero it out anyway + led_setrgb(1, 0, 0, 0); + + if (vref) { + x = probe << 12; // maximum possible level + x /= vref; // normalize to 4096max + if (x > 4095) x = 4095; + + if (x < 2405) { // roughly 100ohm or lower + latch = 4; // latch any continuity for a while + } + + if (latch) { + if (x >= 2420) latch--; // hysteresis + + led_setrgb(0, 0, 255, 0); + led_buzz(0); + if (knob[0] > 128) led_buzz(1); + } else { + led_setrgb(0, 64, 0, 0); + led_buzz(0); + } + } + + if (!vref) vref = v_ext; + vref += v_ext; + vref >>= 1; +} + +static inline void probe_measure_diode() +{ + uint16_t p; + + p = adc_avg[ADC_PROBE]; + + led_setrgb(0, 0, 0, 0); + + if (p < DIODE_SHORT) { + // off on short + led_setrgb(1, 0, 0, 0); + } + + if (p >= DIODE_OPEN) { + // red on open + led_setrgb(1, 255, 0, 0); + } + + if (p >= 1940 && p < 2650) { + // green on regular or schottky diodes + led_setrgb(1, 0, 255, 0); + } + if (p >= 2650 && p < 3800) { + // blue on LEDs + led_setrgb(1, 0, 0, 255); + } + + // if we haven't set a value, flash red to indicate error state +} + +void probe_measure() +{ + uint8_t mode; + + mode = userio_get_mode(); + + switch (mode) { + case MODE_CONT: probe_measure_cont(); break; + case MODE_FUN: break; // todo: run RGBLED program + case MODE_DIODE: probe_measure_diode(); break; + } +} + +/* + * switch probe mode. + * sets up LED peripheral and mode pin as necessary. + */ +void probe_mode_switch(uint8_t mode) +{ + if (mode == MODE_CONT) { + // set LED to buzzer mode, set PROBESEL low + led_mode_buzzer(); + PROBESEL_PORT->BRR = (1 << PROBESEL_PIN); + } else { + // set LED to dual RGB mode, set PROBESEL high + led_mode_rgb(); + PROBESEL_PORT->BSRR = (1 << PROBESEL_PIN); + } +} \ No newline at end of file diff --git a/src/userio.c b/src/userio.c index 82ac5e6..7d29bd2 100644 --- a/src/userio.c +++ b/src/userio.c @@ -27,63 +27,62 @@ #include #include -#include "adc.h" #include "testo.h" +#include "userio.h" + +#include "adc.h" +#include "probe.h" -#define MODE_CONT 0 -#define MODE_CONT_TARGET 3072 // (4096 * (1 - (1 / 4))) - -#define MODE_FUN 1 -#define MODE_FUN_TARGET 2731 // (4096 * (1 - (1 / 3))) - -#define MODE_DIODE 2 -#define MODE_DIODE_TARGET 2048 // (4096 * 1 - ((1 / 2))) - #define MODE_SET_LIMIT 60 // 3x worst case expected (1% tol) #define MODE_CHANGE_TICKS 4 // how many samples before switching modes #define MODE_ANALOG_MIN 20 +#ifdef TESTO_REV1 +#define SET1_MAX 2047 // 3V net feeding into 1V24 via body diode above this +#else +#define SET1_MAX 1539 // 1.24Vref +#endif -uint8_t mode; -uint8_t mode_next; -uint8_t mode_count; + + +static uint8_t mode = 0xff; +static uint8_t mode_next; +static uint8_t mode_count; static const int16_t mode_targets[] = { MODE_CONT_TARGET, MODE_FUN_TARGET, MODE_DIODE_TARGET }; uint8_t knob[2]; -uint8_t btn = 0; -uint16_t btn_held = 0; +static uint8_t btn = 0; +static uint16_t btn_held = 0; -void userio_update() -{ - -} - void userio_parse() { uint8_t i; - volatile int16_t m, w; + int16_t m, w; + uint32_t x; // button - // debounce is handled by the fact that we've had to have averaged - // about 16ms of measured hold time below the zero threshold. - m = adc_avg[ADC_SET_MODE]; - if (m < MODE_ANALOG_MIN) { - // button is pushed - btn = 1; - if (btn_held != 0xffff) btn_held++; - } else if (btn == 1) { - // button is released - btn = 0; - } + { + // debounce is handled by the fact that we've had to have averaged + // about 16ms of measured hold time below the zero threshold. + m = adc_avg[ADC_SET_MODE]; + if (m < MODE_ANALOG_MIN) { + // button is pushed + btn = 1; + if (btn_held != 0xffff) btn_held++; + } else if (btn == 1) { + // button is released + btn = 0; + } + } // mode if (!btn) { @@ -110,6 +109,14 @@ void userio_parse() // we've got enough data to do a change of mode mode = i; mode_count = 0; + + // MODE SWITCH ACTION IS HANDLED HERE + // restart ADC on mode change to update values + // to reflect selected measurement mode + adc_switch0(); + // and set the probe measurement routines + // to use the selected mode + probe_mode_switch(mode); } } else { // set the next mode to the newly selected mode @@ -121,4 +128,28 @@ void userio_parse() } } } + + // knobs + { + knob[0] = adc_avg[ADC_SET0] >> 4; + + // SET1/VREFEXT input can be SET1 or VREFEXT, depending on PROBESEL. + // only copy if not set to VREFEXT, and only if within valid range + if (PROBESEL_PORT->ODR & (1 << PROBESEL_PIN)) { + // PROBESEL is high, so SET1 is in use + if (adc_avg[ADC_SET1] > SET1_MAX) { + // knob is turned too far; warn the user. + // TODO + } else { + x = adc_avg[ADC_SET1] << 12; // maximum possible level + x /= SET1_MAX; // normalize to 4096max + knob[0] = (x >> 4) & 0xff; // reduce to 8-bit + } + } + } +} + +uint8_t userio_get_mode() +{ + return mode; } \ No newline at end of file