diff --git a/examples/adc_opamp_dma/Makefile b/examples/adc_opamp_dma/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..ac00c743ffd45a07a1f1f1361a0ee32df0419e1b
--- /dev/null
+++ b/examples/adc_opamp_dma/Makefile
@@ -0,0 +1,41 @@
+TARGET:=adc_dma_opamp
+
+all : flash
+
+PREFIX:=riscv64-unknown-elf
+
+GPIO_Toggle:=EXAM/GPIO/GPIO_Toggle/User
+
+CH32V003FUN:=../../ch32v003fun
+MINICHLINK:=../../minichlink
+
+CFLAGS:= \
+	-g -Os -flto -ffunction-sections \
+	-static-libgcc \
+	-march=rv32ec \
+	-mabi=ilp32e \
+	-I/usr/include/newlib \
+	-I$(CH32V003FUN) \
+	-nostdlib \
+	-I. -DSTDOUT_UART -Wall
+
+LDFLAGS:=-T $(CH32V003FUN)/ch32v003fun.ld -Wl,--gc-sections -L../../misc -lgcc
+
+SYSTEM_C:=$(CH32V003FUN)/ch32v003fun.c
+
+$(TARGET).elf : $(SYSTEM_C) $(TARGET).c
+	$(PREFIX)-gcc -o $@ $^ $(CFLAGS) $(LDFLAGS)
+
+$(TARGET).bin : $(TARGET).elf
+	$(PREFIX)-size $^
+	$(PREFIX)-objdump -S $^ > $(TARGET).lst
+	$(PREFIX)-objdump -t $^ > $(TARGET).map
+	$(PREFIX)-objcopy -O binary $< $(TARGET).bin
+	$(PREFIX)-objcopy -O ihex $< $(TARGET).hex
+
+flash : $(TARGET).bin
+	$(MINICHLINK)/minichlink -w $< flash -b
+
+clean :
+	rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).hex $(TARGET).lst $(TARGET).map $(TARGET).hex
+
diff --git a/examples/adc_opamp_dma/README.md b/examples/adc_opamp_dma/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..ba71af4a9b7e2bd568b1a7d25f2300f9e9fc9c05
--- /dev/null
+++ b/examples/adc_opamp_dma/README.md
@@ -0,0 +1,49 @@
+# DMA ADC & op-amp example
+This example code demonstrates the use of the CH32V003 on-chip ADC in continuous
+DMA mode wherein several analog input channels are configured on GPIO and then
+automatically digitized into a memory buffer. When software needs a channel
+reading it need only access the buffer to get the latest result.
+
+Additionally, the on-chip op-amp is enabled on one of the input channels to
+allow some gain.
+
+## Theory
+This demo will sample four channels, one of which is connected to the internal
+op-amp. Sampling will happen continuously with no processor intervention and
+results saved in a fixed-length buffer that is constantly overwritten with
+new data. When the op-amp is enabled and properly wired up then its output can
+be evaluated with respect to other analog signals input to the ADC.
+
+### ADC
+The ADC can sample from eight GPIO pins and two internal references. In this
+example we use four channels on GPIO pins. Continuous conversion is used with
+DMA enabled. The following channels are used
+* Pin PD4, A7 - op-amp output
+* Pin PD3, A4
+* Pin PD2, A3
+* Pin PC4, A2
+
+### DMA
+DMA channel 1 is dedicated to the ADC and is set up for half-words from peripheral
+to memory, circular. The buffer length is identical to the number of channels that
+are being used so reading from offset N in the buffer is equivalent to reading
+channel sequence #N results.
+
+### Op-Amp
+The op-amp is internally connected with its output on pin PD4, positive input on
+either pin PD7 or PA2 and negative input on PD0 or PA1. PA1, PA2 and PD7 are
+already in use for the crystal and NRST on the WCH eval board so it's difficult
+to test the op-amp in that system.
+* Using PA1 and PA2 requires removing the crystal and loading caps, as well as
+installing zero-ohm resistors.
+* Using PD7 as an op-amp input requires disabling the NRST function which must
+be done by accessing the user option byte in flash memory.
+
+## Use
+To test ADC DMA only, flash the code to a device and connect a serial terminal
+to pin PD5. Observe four columns of data printed for the ADC results on
+PD4, PD3, PD2 and C4. With nothing connected they will float around 1.6V and
+yield results near 500. Grounding any of those pins will force the result to 0
+while tying the pin to VDD will force it to 1023.
+
+Testing the op-amp is TBD.
diff --git a/examples/adc_opamp_dma/adc.h b/examples/adc_opamp_dma/adc.h
new file mode 100644
index 0000000000000000000000000000000000000000..87201e6edfa5a7c1ea27d4fa1e5bb2a5e520fc46
--- /dev/null
+++ b/examples/adc_opamp_dma/adc.h
@@ -0,0 +1,91 @@
+/*
+ * Single-File-Header for using ADC with DMA
+ * 04-13-2023 E. Brombaugh
+ */
+
+#ifndef _ADC_H
+#define _ADC_H
+
+#include <stdint.h>
+
+#define ADC_NUMCHLS 4
+volatile uint16_t adc_buffer[ADC_NUMCHLS];
+
+/*
+ * initialize adc for DMA
+ */
+void adc_init( void )
+{
+	// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
+	RCC->CFGR0 &= ~(0x1F<<11);
+	
+	// Enable GPIOD and ADC
+	RCC->APB2PCENR |=	RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD |
+						RCC_APB2Periph_ADC1;
+	
+	// PD4 is analog input chl 7
+	GPIOD->CFGLR &= ~(0xf<<(4*4));	// CNF = 00: Analog, MODE = 00: Input
+	
+	// PD3 is analog input chl 4
+	GPIOD->CFGLR &= ~(0xf<<(4*3));	// CNF = 00: Analog, MODE = 00: Input
+	
+	// PD2 is analog input chl 3
+	GPIOD->CFGLR &= ~(0xf<<(4*2));	// CNF = 00: Analog, MODE = 00: Input
+	
+	// PC4 is analog input chl 2
+	GPIOC->CFGLR &= ~(0xf<<(4*4));	// CNF = 00: Analog, MODE = 00: Input
+	
+	// Reset the ADC to init all regs
+	RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
+	RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
+	
+	// Set up four conversions on chl 7, 4, 3, 2
+	ADC1->RSQR1 = (ADC_NUMCHLS-1) << 20;	// four chls in the sequence
+	ADC1->RSQR2 = 0;
+	ADC1->RSQR3 = (7<<(5*0)) | (4<<(5*1)) | (3<<(5*2)) | (2<<(5*3));
+	
+	// set sampling time for chl 7, 4, 3, 2
+	// 0:7 => 3/9/15/30/43/57/73/241 cycles
+	ADC1->SAMPTR2 = (7<<(3*7)) | (7<<(3*4)) | (7<<(3*3)) | (7<<(3*2));
+
+	// turn on ADC
+	ADC1->CTLR2 |= ADC_ADON;
+	
+	// Reset calibration
+	ADC1->CTLR2 |= ADC_RSTCAL;
+	while(ADC1->CTLR2 & ADC_RSTCAL);
+	
+	// Calibrate
+	ADC1->CTLR2 |= ADC_CAL;
+	while(ADC1->CTLR2 & ADC_CAL);
+	
+	// Turn on DMA
+	RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
+	
+	//DMA1_Channel1 is for ADC
+	DMA1_Channel1->PADDR = (uint32_t)&ADC1->RDATAR;
+	DMA1_Channel1->MADDR = (uint32_t)adc_buffer;
+	DMA1_Channel1->CNTR  = ADC_NUMCHLS;
+	DMA1_Channel1->CFGR  =
+		DMA_M2M_Disable |		 
+		DMA_Priority_VeryHigh |
+		DMA_MemoryDataSize_HalfWord |
+		DMA_PeripheralDataSize_HalfWord |
+		DMA_MemoryInc_Enable |
+		DMA_Mode_Circular |
+		DMA_DIR_PeripheralSRC;
+	
+	// Turn on DMA channel 1
+	DMA1_Channel1->CFGR |= DMA_CFGR1_EN;
+	
+	// enable scanning
+	ADC1->CTLR1 |= ADC_SCAN;
+	
+	// Enable continuous conversion and DMA
+	ADC1->CTLR2 |= ADC_CONT | ADC_DMA | ADC_EXTSEL;
+	
+	// start conversion
+	ADC1->CTLR2 |= ADC_SWSTART;
+}
+
+#endif
diff --git a/examples/adc_opamp_dma/adc_dma_opamp.c b/examples/adc_opamp_dma/adc_dma_opamp.c
new file mode 100644
index 0000000000000000000000000000000000000000..0e7889ca256df8b39cd7aa968635c04a004f1dc0
--- /dev/null
+++ b/examples/adc_opamp_dma/adc_dma_opamp.c
@@ -0,0 +1,61 @@
+/*
+ * Example for using ADC with DMA and an op-amp
+ * 04-13-2023 E. Brombaugh
+ */
+
+// Could be defined here, or in the processor defines.
+#define SYSTEM_CORE_CLOCK 48000000
+#define APB_CLOCK SYSTEM_CORE_CLOCK
+
+#include "ch32v003fun.h"
+#include <stdio.h>
+#include "adc.h"
+#include "opamp.h"
+
+int main()
+{
+	SystemInit48HSI();
+
+	// start serial @ default 115200bps
+	SetupUART( UART_BRR );
+	Delay_Ms(100);
+	printf("\r\r\n\nadc_dma_opamp example\n\r");
+
+	// init adc
+	printf("initializing adc...");
+	adc_init();
+	printf("done.\n\r");
+	
+#if 0
+	printf("MADDR = 0x%08X, Buffer = 0x%08X\n\r",
+		DMA1_Channel1->CNTR, adc_buffer);
+	while(1)
+	{
+		//printf("STATR = 0x%08X, RDATAR = 0x%04X, CNTR = 0x%04X\n\r",
+			//ADC1->STATR, ADC1->RDATAR, DMA1_Channel1->CNTR);
+	}
+#endif
+
+	// init op-amp
+	printf("initializing op-amp...\n\r");
+	opamp_init();
+	printf("done.\n\r");
+	
+	// Enable GPIOs
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOC;
+
+	// GPIO C1 Push-Pull
+	GPIOC->CFGLR &= ~(0xf<<(4*1));
+	GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*1);
+
+	printf("looping...\n\r");
+	while(1)
+	{
+		GPIOC->BSHR = (1<<1);	 // Turn on GPIOs
+		Delay_Ms( 100 );
+		GPIOC->BSHR = (1<<1+16); // Turn off GPIODs
+		Delay_Ms( 100 );
+		printf( "%4d %4d ", adc_buffer[0], adc_buffer[1]);
+		printf( "%4d %4d\n\r", adc_buffer[2], adc_buffer[3]);
+	}
+}
diff --git a/examples/adc_opamp_dma/opamp.h b/examples/adc_opamp_dma/opamp.h
new file mode 100644
index 0000000000000000000000000000000000000000..78de0ecc062c98e17b5ce2cb4a1a6d0de2d38af5
--- /dev/null
+++ b/examples/adc_opamp_dma/opamp.h
@@ -0,0 +1,27 @@
+/*
+ * Single-File-Header for using op-amp
+ * 04-13-2023 E. Brombaugh
+ */
+
+#ifndef _OPAMP_H
+#define _OPAMP_H
+
+#include <stdint.h>
+
+/*
+ * initialize adc for polling
+ */
+void opamp_init( void )
+{
+	// turn on the op-amp
+	EXTEN->EXTEN_CTR |= EXTEN_OPA_EN;
+	
+	// select op-amp pos pin: 0 = PA2, 1 = PD7
+	//EXTEN->EXTEN_CTR |= EXTEN_OPA_PSEL;
+
+	// select op-amp neg pin: 0 = PA1, 1 = PD0
+	//EXTEN->EXTEN_CTR |= EXTEN_OPA_PSEL;
+
+}
+#endif
+