Continuity and diode mode initial implementation

Reads continuity at a fixed ~100ohm or lower, and diodes with intelligent detection of LEDs vs normal diodes. Some values may need to be changed still.
This commit is contained in:
true 2023-10-21 19:45:15 -07:00
parent 859c04f782
commit 0afa454588
10 changed files with 289 additions and 53 deletions

View File

@ -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 */

21
include/probe.h Normal file
View File

@ -0,0 +1,21 @@
/*
* probe.c: helping you probe things
*
* file creation: 20231021 1717
*/
#ifndef _INC_PROBE_H
#define _INC_PROBE_H
#include <stdint.h>
void probe_mode_switch(uint8_t mode);
void probe_measure();
#endif /* _INC_PROBE_H */

View File

@ -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

View File

@ -4,9 +4,33 @@
* file creation: 20231016 1505
*/
#ifndef _INC_USERIO_H
#define _INC_USERIO_H
#include <stdint.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)))
extern uint8_t knob[2];
void userio_parse();
uint8_t userio_get_mode();
#endif /* _INC_USERIO_H */

View File

@ -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));
}

View File

@ -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

View File

@ -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;
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();
}

View File

@ -12,6 +12,7 @@
#include "adc.h"
#include "flash.h"
#include "led.h"
#include "probe.h"
#include "userio.h"
@ -143,9 +144,14 @@ __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();
}
}
}

View File

@ -6,3 +6,133 @@
*
* file creation: 20231016 0255
*/
#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);
}
}

View File

@ -27,52 +27,50 @@
#include <stdint.h>
#include <stdlib.h>
#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];
@ -84,6 +82,7 @@ void userio_parse()
// 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;
}