From 7ab050505f2de6f172d5524698f27a186ea7d6ec Mon Sep 17 00:00:00 2001
From: cnlohr <lohr85@gmail.com>
Date: Fri, 30 Jun 2023 17:32:21 -0400
Subject: [PATCH] Example how to use the pin-change interrupt to monitor a cap
 touch sensor with about 6 bits of accuracy.

---
 examples/touch_exti/Makefile     |   9 +++
 examples/touch_exti/funconfig.h  |  14 ++++
 examples/touch_exti/touch_exti.c | 107 +++++++++++++++++++++++++++++++
 3 files changed, 130 insertions(+)
 create mode 100644 examples/touch_exti/Makefile
 create mode 100644 examples/touch_exti/funconfig.h
 create mode 100644 examples/touch_exti/touch_exti.c

diff --git a/examples/touch_exti/Makefile b/examples/touch_exti/Makefile
new file mode 100644
index 0000000..af6caa9
--- /dev/null
+++ b/examples/touch_exti/Makefile
@@ -0,0 +1,9 @@
+all : flash
+
+TARGET:=touch_exti
+
+include ../../ch32v003fun/ch32v003fun.mk
+
+flash : cv_flash
+clean : cv_clean
+
diff --git a/examples/touch_exti/funconfig.h b/examples/touch_exti/funconfig.h
new file mode 100644
index 0000000..d6b0f54
--- /dev/null
+++ b/examples/touch_exti/funconfig.h
@@ -0,0 +1,14 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+// Though this should be on by default we can extra force it on.
+#define FUNCONF_USE_DEBUGPRINTF 1
+#define FUNCONF_DEBUGPRINTF_TIMEOUT (1<<31) // Wait for a very very long time.
+
+// high res systick.
+#define FUNCONF_SYSTICK_USE_HCLK 1
+
+#define CH32V003           1
+
+#endif
+
diff --git a/examples/touch_exti/touch_exti.c b/examples/touch_exti/touch_exti.c
new file mode 100644
index 0000000..c4a6f80
--- /dev/null
+++ b/examples/touch_exti/touch_exti.c
@@ -0,0 +1,107 @@
+/* Demo showing how to use eternal interrupts to detect touch.  This allows for
+	both low resolution touch (about 6-7 bits for a 6mm x 10mm pad) by using
+	internal pull up resistors, as well as high resolution touch (8+ bits per
+	pad) with a 560k pull up resistor.
+
+	The current configuration uses:
+
+	PORT C, pin 4 - regular touch pad, no extra components.
+	PORT C, pin 5 - high res pad, with pull-up to 3.3v with 560k resistor.
+	PORT D, pin 5 - regular touch pad, no extra components.
+
+	Note: You may want to consider including a 1k series resistor for better
+	ESD performance.
+*/
+
+#include "ch32v003fun.h"
+#include <stdio.h>
+
+uint32_t count;
+uint32_t endtime;
+
+void EXTI7_0_IRQHandler( void ) __attribute__((interrupt));
+void EXTI7_0_IRQHandler( void ) 
+{
+	endtime = SysTick->CNT;
+	EXTI->INTFR = 0xffffffff;
+}
+
+#define GPIOPortByBase( i )   ((GPIO_TypeDef *)(GPIOA_BASE + 0x0400 * (i)))
+
+
+// The "port" is:
+// 0 for Port A
+// 1 for Port B
+// 2 for Port C
+// 3 for Port D
+int MeasureTouch( int portno, int pin, int pu_mode )
+{
+	uint32_t starttime;
+	GPIO_TypeDef * port = GPIOPortByBase( portno );
+	uint32_t pinx4 = pin<<2;
+
+	// Mask out just our specific port.  This way we don't interfere with other
+	// stuff that may be on this port.
+	uint32_t base = port->CFGLR & (~(0xf<<pinx4));
+
+	// Mode for CFGLR when asserted.
+	uint32_t setmode =     base | (GPIO_CFGLR_OUT_2Mhz_PP)<<(pinx4);
+
+	// Mode for CFGLR when it drifts.
+	uint32_t releasemode = base | (pu_mode)<<(pinx4);
+
+	// Assert pin
+	port->CFGLR = setmode;
+	port->BSHR = 1<<(pin+16);
+
+	// Setup pin-change-interrupt.  This will trigger when the voltage on the
+	// pin rises above the  schmitt trigger threshold.
+	AFIO->EXTICR = portno<<(pin*2);
+	EXTI->INTENR = 0xffffffff;  // Enable EXT3
+	EXTI->RTENR = 0xffffffff;   // Rising edge trigger
+
+	// Tricky, we want the release to happen at an un-aligned address. 
+	// This actually doubles our touch sensor resolution.
+	asm volatile( ".balign 4; c.nop" );
+	port->CFGLR = releasemode;
+	starttime = SysTick->CNT;
+	endtime = starttime - 1;
+	port->BSHR = 1<<(pin);
+
+	// Allow up to 256 cycles for the pin to change.
+	#define DELAY8 \
+		asm volatile( "c.nop;c.nop;c.nop;c.nop;c.nop;c.nop;c.nop;c.nop;" );
+	DELAY8 DELAY8 DELAY8 DELAY8 DELAY8 DELAY8 DELAY8 DELAY8
+	DELAY8 DELAY8 DELAY8 DELAY8 DELAY8 DELAY8 DELAY8 DELAY8
+	DELAY8 DELAY8 DELAY8 DELAY8 DELAY8 DELAY8 DELAY8 DELAY8
+	DELAY8 DELAY8 DELAY8 DELAY8 DELAY8 DELAY8 DELAY8 DELAY8
+
+	// Disable EXTI
+	EXTI->INTENR = 0;
+
+	// Optional assert pin when done to prevent it from noodling around.
+	//port->CFGLR = setmode;
+	//port->BSHR = 1<<(pin+16);
+
+	return endtime - starttime;
+}
+
+int main()
+{
+	SystemInit();
+
+	// Enable GPIOs and pin-change interrupt.
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO;
+
+	// enable pin-change-interrupt.
+	NVIC_EnableIRQ( EXTI7_0_IRQn );
+
+	while(1)
+	{
+		printf( "%4d %4d %4d\n",
+			MeasureTouch( 2, 4, GPIO_CFGLR_IN_PUPD ), // Port C4
+			MeasureTouch( 3, 5, GPIO_CFGLR_IN_PUPD ), // Port D5
+			MeasureTouch( 2, 5, GPIO_CFGLR_IN_FLOAT ) ); // Port C5, with external pull-up.
+	}
+}
+
-- 
GitLab