From 8697e9aa352429b976ab4f5eca7326b676e04d92 Mon Sep 17 00:00:00 2001
From: cnlohr <lohr85@gmail.com>
Date: Wed, 13 Sep 2023 03:45:14 -0400
Subject: [PATCH] Move touch to header.

---
 examples/cap_touch_adc/cap_touch_adc.c | 123 +--------------------
 extralibs/ch32v003_touch.h             | 147 +++++++++++++++++++++++++
 2 files changed, 148 insertions(+), 122 deletions(-)
 create mode 100644 extralibs/ch32v003_touch.h

diff --git a/examples/cap_touch_adc/cap_touch_adc.c b/examples/cap_touch_adc/cap_touch_adc.c
index 2bde0c9..98457e9 100644
--- a/examples/cap_touch_adc/cap_touch_adc.c
+++ b/examples/cap_touch_adc/cap_touch_adc.c
@@ -21,101 +21,7 @@
 #include "ch32v003fun.h"
 #include <stdio.h>
 
-#define ADC_SAMPLE_TIME 2  // Tricky: Don't change this without a lot of experimentation.
-#define MAX_SCALECHECK  4
-
-// Can either be 0 or 1.
-// If 0: Measurement low and rises high.  So more pressed is smaller number.
-// If 1: Higher number = harder press. Good to pair with TOUCH_FLAT.
-// If you are doing more prox, use mode 0, otherwise, use mode 1.
-#define TOUCH_SLOPE     1
-
-// If you set this to 1, it will glitch the line, so it will only read
-// anything reasonable if the capacitance can overcome that initial spike.
-// Typically, it seems if you use this you probbly don't need to do
-// any pre-use calibration.
-#define TOUCH_FLAT      0
-
-void InitTouchADC( )
-{
-	// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
-	RCC->CFGR0 &= ~(0x1F<<11);
-
-	// Set up single conversion on chl 2
-	ADC1->RSQR1 = 0;
-	ADC1->RSQR2 = 0;
-
-	// turn on ADC and set rule group to sw trig
-	ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
-	
-	// Reset calibration
-	ADC1->CTLR2 |= ADC_RSTCAL;
-	while(ADC1->CTLR2 & ADC_RSTCAL);
-	
-	// Calibrate
-	ADC1->CTLR2 |= ADC_CAL;
-	while(ADC1->CTLR2 & ADC_CAL);
-}
-
-// Run from RAM to get even more stable timing.
-// This function call takes about 8.1uS to execute.
-uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
-uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
-{
-	uint32_t ret = 0;
-
-	ADC1->RSQR3 = adcno;
-	ADC1->SAMPTR2 = ADC_SAMPLE_TIME<<(3*adcno);
-
-	uint32_t CFGBASE = io->CFGLR & (~(0xf<<(4*portpin)));
-	uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | CFGBASE;
-	uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | CFGBASE;
-
-	// If we run multiple times with slightly different wait times, we can
-	// reduce the impact of the ADC's DNL.
-
-
-#if TOUCH_FLAT == 1
-#define RELEASEIO io->OUTDR = 1<<(portpin+16*TOUCH_SLOPE); io->CFGLR = CFGFLOAT;
-#else
-#define RELEASEIO io->CFGLR = CFGFLOAT; io->OUTDR = 1<<(portpin+16*TOUCH_SLOPE);
-#endif
-
-#define INNER_LOOP( 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 )                                                         \
-                                                                                \
-		RELEASEIO                                                               \
-																			    \
-		/* Sampling actually starts here, somewhere, so we can let other        \
-			interrupts run */                                                   \
-		__enable_irq();                                                         \
-		while(!(ADC1->STATR & ADC_EOC));                                        \
-		io->CFGLR = CFGDRIVE;                                                   \
-		io->OUTDR = 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( 0 );
-		INNER_LOOP( 2 );
-		INNER_LOOP( 4 );
-	}
-
-	return ret;
-}
+#include "ch32v003_touch.h"
 
 int main()
 {
@@ -133,8 +39,6 @@ int main()
 	{
 		uint32_t sum[8] = { 0 };
 
-		int j;
-
 		uint32_t start = SysTick->CNT;
 
 		// Sampling all touch pads, 3x should take 6030 cycles, and runs at about 8kHz
@@ -156,28 +60,3 @@ int main()
 	}
 }
 
-/*
- * MIT License
- * 
- * Copyright (c) 2023 Valve Corporation
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- * 
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-
diff --git a/extralibs/ch32v003_touch.h b/extralibs/ch32v003_touch.h
new file mode 100644
index 0000000..b0c3e90
--- /dev/null
+++ b/extralibs/ch32v003_touch.h
@@ -0,0 +1,147 @@
+#ifndef _CH32V003_TOUCH_H
+#define _CH32V003_TOUCH_H
+
+/** ADC-based Capactive Touch Control.
+
+	see cap_touch_adc.c for an example.
+
+	// Enable GPIOD, C and ADC
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1;
+	InitTouchADC();
+
+
+	// Then do this any time you want to read some touches.
+	sum[0] += ReadTouchPin( GPIOA, 2, 0, iterations );
+	sum[1] += ReadTouchPin( GPIOA, 1, 1, iterations );
+	sum[2] += ReadTouchPin( GPIOC, 4, 2, iterations );
+	sum[3] += ReadTouchPin( GPIOD, 2, 3, iterations );
+	sum[4] += ReadTouchPin( GPIOD, 3, 4, iterations );
+	sum[5] += ReadTouchPin( GPIOD, 5, 5, iterations );
+	sum[6] += ReadTouchPin( GPIOD, 6, 6, iterations );
+	sum[7] += ReadTouchPin( GPIOD, 4, 7, iterations );
+*/
+
+
+
+#define TOUCH_ADC_SAMPLE_TIME 2  // Tricky: Don't change this without a lot of experimentation.
+
+// Can either be 0 or 1.
+// If 0: Measurement low and rises high.  So more pressed is smaller number.
+// If 1: Higher number = harder press. Good to pair with TOUCH_FLAT.
+// If you are doing more prox, use mode 0, otherwise, use mode 1.
+#define TOUCH_SLOPE     1
+
+// If you set this to 1, it will glitch the line, so it will only read
+// anything reasonable if the capacitance can overcome that initial spike.
+// Typically, it seems if you use this you probbly don't need to do
+// any pre-use calibration.
+#define TOUCH_FLAT      0
+
+static void InitTouchADC( );
+void InitTouchADC( )
+{
+	// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
+	RCC->CFGR0 &= ~(0x1F<<11);
+
+	// Set up single conversion on chl 2
+	ADC1->RSQR1 = 0;
+	ADC1->RSQR2 = 0;
+
+	// turn on ADC and set rule group to sw trig
+	ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
+	
+	// Reset calibration
+	ADC1->CTLR2 |= ADC_RSTCAL;
+	while(ADC1->CTLR2 & ADC_RSTCAL);
+	
+	// Calibrate
+	ADC1->CTLR2 |= ADC_CAL;
+	while(ADC1->CTLR2 & ADC_CAL);
+}
+
+// Run from RAM to get even more stable timing.
+// This function call takes about 8.1uS to execute.
+static uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
+uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
+{
+	uint32_t ret = 0;
+
+	ADC1->RSQR3 = adcno;
+	ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
+
+	uint32_t CFGBASE = io->CFGLR & (~(0xf<<(4*portpin)));
+	uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | CFGBASE;
+	uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | CFGBASE;
+
+	// If we run multiple times with slightly different wait times, we can
+	// reduce the impact of the ADC's DNL.
+
+
+#if TOUCH_FLAT == 1
+#define RELEASEIO io->OUTDR = 1<<(portpin+16*TOUCH_SLOPE); io->CFGLR = CFGFLOAT;
+#else
+#define RELEASEIO io->CFGLR = CFGFLOAT; io->OUTDR = 1<<(portpin+16*TOUCH_SLOPE);
+#endif
+
+#define INNER_LOOP( 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 )                                                         \
+                                                                                \
+		RELEASEIO                                                               \
+																			    \
+		/* Sampling actually starts here, somewhere, so we can let other        \
+			interrupts run */                                                   \
+		__enable_irq();                                                         \
+		while(!(ADC1->STATR & ADC_EOC));                                        \
+		io->CFGLR = CFGDRIVE;                                                   \
+		io->OUTDR = 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( 0 );
+		INNER_LOOP( 2 );
+		INNER_LOOP( 4 );
+	}
+
+	return ret;
+}
+
+#endif
+
+/*
+ * MIT License
+ * 
+ * Copyright (c) 2023 Valve Corporation
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
-- 
GitLab