From 85863e31ef2effd6c310b5fdfaeea01aa4960401 Mon Sep 17 00:00:00 2001 From: cnlohr <lohr85@gmail.com> Date: Thu, 14 Sep 2023 06:49:57 -0400 Subject: [PATCH] Let there be a "safe" version of the touch functions that don't blow up the whole port. --- extralibs/ch32v003_touch.h | 60 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/extralibs/ch32v003_touch.h b/extralibs/ch32v003_touch.h index b0c3e90..88756af 100644 --- a/extralibs/ch32v003_touch.h +++ b/extralibs/ch32v003_touch.h @@ -78,9 +78,9 @@ uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations #if TOUCH_FLAT == 1 -#define RELEASEIO io->OUTDR = 1<<(portpin+16*TOUCH_SLOPE); io->CFGLR = CFGFLOAT; +#define RELEASEIO io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); io->CFGLR = CFGFLOAT; #else -#define RELEASEIO io->CFGLR = CFGFLOAT; io->OUTDR = 1<<(portpin+16*TOUCH_SLOPE); +#define RELEASEIO io->CFGLR = CFGFLOAT; io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); #endif #define INNER_LOOP( n ) \ @@ -101,7 +101,7 @@ uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations __enable_irq(); \ while(!(ADC1->STATR & ADC_EOC)); \ io->CFGLR = CFGDRIVE; \ - io->OUTDR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \ + io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \ ret += ADC1->RDATAR; \ } @@ -119,6 +119,60 @@ uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations return ret; } +// Run from RAM to get even more stable timing. +// This function call takes about 8.1uS to execute. +static uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata"))); +uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) +{ + uint32_t ret = 0; + + ADC1->RSQR3 = adcno; + ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno); + + // If we run multiple times with slightly different wait times, we can + // reduce the impact of the ADC's DNL. + +#define INNER_LOOP_SAFE( n ) \ + { \ + /* Only lock IRQ for a very narrow window. */ \ + __disable_irq(); \ + \ + \ + /* Tricky - we start the ADC BEFORE we transition the pin. By doing \ + this We are catching it onthe slope much more effectively. */ \ + ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \ + \ + ADD_N_NOPS( n ) \ + \ + io->CFGLR = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | (io->CFGLR & (~(0xf<<(4*portpin)))); \ + io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); \ + \ + /* Sampling actually starts here, somewhere, so we can let other \ + interrupts run */ \ + __enable_irq(); \ + while(!(ADC1->STATR & ADC_EOC)); \ + __disable_irq(); \ + io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | (io->CFGLR & (~(0xf<<(4*portpin)))); \ + __enable_irq(); \ + io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \ + ret += ADC1->RDATAR; \ + } + + int i; + for( i = 0; i < iterations; i++ ) + { + // Wait a variable amount of time based on loop iteration, in order + // to get a variety of RC points and minimize DNL. + + INNER_LOOP_SAFE( 0 ); + INNER_LOOP_SAFE( 2 ); + INNER_LOOP_SAFE( 4 ); + } + + return ret; +} + + #endif /* -- GitLab