diff --git a/ch32v003fun/ch32v003fun.c b/ch32v003fun/ch32v003fun.c index f2776fc2..7fd2b1fb 100644 --- a/ch32v003fun/ch32v003fun.c +++ b/ch32v003fun/ch32v003fun.c @@ -1472,6 +1472,46 @@ WEAK int putchar(int c) return 1; } +void funAnalogInit() +{ + //RCC->CFGR0 &= ~(0x1F<<11); // Assume ADCPRE = 0 + RCC->APB2PCENR |= RCC_APB2Periph_ADC1; + + // Reset ADC. + RCC->APB2PRSTR |= RCC_APB2Periph_ADC1; + RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1; + + // set sampling time for all channels to 15 (A good middleground) ADC_SMP0_1. + ADC1->SAMPTR2 = (ADC_SMP0_1<<(3*0)) | (ADC_SMP0_1<<(3*1)) | (ADC_SMP0_1<<(3*2)) | (ADC_SMP0_1<<(3*3)) | (ADC_SMP0_1<<(3*4)) | (ADC_SMP0_1<<(3*5)) | (ADC_SMP0_1<<(3*6)) | (ADC_SMP0_1<<(3*7)) | (ADC_SMP0_1<<(3*8)) | (ADC_SMP0_1<<(3*9)); + ADC1->SAMPTR1 = (ADC_SMP0_1<<(3*0)) | (ADC_SMP0_1<<(3*1)) | (ADC_SMP0_1<<(3*2)) | (ADC_SMP0_1<<(3*3)) | (ADC_SMP0_1<<(3*4)) | (ADC_SMP0_1<<(3*5)); + + ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL; // turn on ADC and set rule group to sw trig + + // Reset calibration + ADC1->CTLR2 |= ADC_RSTCAL; + while(ADC1->CTLR2 & ADC_RSTCAL); + + // Calibrate + ADC1->CTLR2 |= ADC_CAL; + while(ADC1->CTLR2 & ADC_CAL); + +} + + +int funAnalogRead( int nAnalogNumber ) +{ + ADC1->RSQR3 = nAnalogNumber; + + // start sw conversion (auto clears) + ADC1->CTLR2 |= ADC_SWSTART; + + // wait for conversion complete + while(!(ADC1->STATR & ADC_EOC)); + + // get result + return ADC1->RDATAR; +} + void SetupDebugPrintf() { // Clear out the sending flag. diff --git a/ch32v003fun/ch32v003fun.h b/ch32v003fun/ch32v003fun.h index 7e9a9aa2..dd9ae035 100644 --- a/ch32v003fun/ch32v003fun.h +++ b/ch32v003fun/ch32v003fun.h @@ -19,6 +19,7 @@ funPinMode( PA2, GPIO_CFGLR_OUT_10Mhz_PP ); funDigitalWrite( PA2, FUN_HIGH ); funDigitalWrite( PA2, FUN_HIGH ); + funAnalogRead( 0 ); // Not Pin number, but rather analog number. 4. Delays Delay_Us(n) @@ -13659,9 +13660,28 @@ extern "C" { #define funGpioInitA() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA ); } #define funGpioInitC() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOC ); } #define funGpioInitD() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOD ); } -#define funDigitalRead( pin ) ((GpioOf(pin)->INDR >> ((pin)&0xf)) & 1) - - +#define funDigitalRead( pin ) ((int)((GpioOf(pin)->INDR >> ((pin)&0xf)) & 1)) + + +#define ANALOG_0 0 +#define ANALOG_1 1 +#define ANALOG_2 2 +#define ANALOG_3 3 +#define ANALOG_4 4 +#define ANALOG_5 5 +#define ANALOG_6 6 +#define ANALOG_7 7 +#define ANALOG_8 8 +#define ANALOG_9 9 +#define ANALOG_10 10 +#define ANALOG_11 11 + +// Initialize the ADC calibrate it and set some sane defaults. +void funAnalogInit(); + +// Read an analog input (not a GPIO pin number) +// Be sure to call funAnalogInit first. +int funAnalogRead( int nAnalogNumber ); #if defined(__riscv) || defined(__riscv__) || defined( CH32V003FUN_BASE ) diff --git a/examples/gpio_and_adc_injection_test/Makefile b/examples/adc_injection/Makefile similarity index 71% rename from examples/gpio_and_adc_injection_test/Makefile rename to examples/adc_injection/Makefile index b4c131d9..a299d05e 100644 --- a/examples/gpio_and_adc_injection_test/Makefile +++ b/examples/adc_injection/Makefile @@ -1,6 +1,6 @@ all : flash -TARGET:=gpio_and_adc_injection_test +TARGET:=adc_injection include ../../ch32v003fun/ch32v003fun.mk diff --git a/examples/adc_injection/adc_injection.c b/examples/adc_injection/adc_injection.c new file mode 100644 index 00000000..14a1e10c --- /dev/null +++ b/examples/adc_injection/adc_injection.c @@ -0,0 +1,95 @@ +// Basic GPIO and Injection-Mode ADC Example using modern funPinMode / funDigitalWrite / etc... modes. +// +// The ADC has two modes: Rule and Injection. +// Injection allows you to read up to 4 ADCs in rapid succession. +// But there is no rule at the end for checking completion of conversion... So it's usually only good for continuous monitoring. +// +// This demo should alternate between 0 and 1023 for the first 3 channels, and the 4th channel will go a little bit up/down but only because of latent capacitance. + +#include "ch32v003fun.h" +#include + +int main() +{ + SystemInit(); + + funGpioInitAll(); + + // You can use pull-up/pull-down in conjuction with ADC. + funPinMode( PA1, GPIO_CFGLR_IN_PUPD ); + funPinMode( PA2, GPIO_CFGLR_IN_PUPD ); + funPinMode( PC4, GPIO_CFGLR_IN_PUPD ); + funPinMode( PD2, GPIO_CFGLR_IN_ANALOG ); + + // Enable ADC + RCC->APB2PCENR |= RCC_APB2Periph_ADC1; + + // Reset the ADC to init all regs + RCC->APB2PRSTR |= RCC_APB2Periph_ADC1; + RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1; + + // Setup channel conversion situation + ADC1->ISQR= + ADC_JL_0 | ADC_JL_1 | // 4 Total channels + ADC_JSQ4_1 | ADC_JSQ4_0 | // Channel 3 (PD2) + ADC_JSQ3_1 | // Channel 2 (PC4) + ADC_JSQ2_0 | // Channel 1 (PA1) + 0; // Channel 0 (PA2) + + // Once we read the analog values will be populated in the following: + // ADC1->JSQ1 = Channel 0 (PA2) + // ADC1->JSQ2 = Channel 1 (PA1) + // ADC1->JSQ3 = Channel 2 (PC4) + // ADC1->JSQ3 = Channel 3 (PD2) + + // Setup sampling time + // 0:7 => 3/9/15/30/43/57/73/241 cycles + ADC1->SAMPTR2 |= + ADC_SMP0_0 | ADC_SMP0_1 | ADC_SMP0_2 | \ + ADC_SMP1_0 | ADC_SMP1_1 | ADC_SMP1_2 | \ + ADC_SMP2_0 | ADC_SMP2_1 | ADC_SMP2_2 | \ + ADC_SMP3_1 | ADC_SMP3_1 | ADC_SMP3_2; + + // turn on ADC and set rule group to sw trig + // Additionally ADC_CONT says just continuously read the values. + ADC1->CTLR2 = ADC_ADON | ADC_JEXTSEL | ADC_CONT; + + ADC1->CTLR1 = ADC_SCAN; + + // Reset calibration + ADC1->CTLR2 |= ADC_RSTCAL; + while(ADC1->CTLR2 & ADC_RSTCAL); + + // Calibrate + ADC1->CTLR2 |= ADC_CAL; + while(ADC1->CTLR2 & ADC_CAL); + + // Tell the ADC to start converting, continously. + ADC1->CTLR2 |= ADC_JSWSTART; + + while(1) + { + funDigitalWrite( PD2, FUN_HIGH ); + funDigitalWrite( PC4, FUN_HIGH ); + funDigitalWrite( PA1, FUN_HIGH ); + funDigitalWrite( PA2, FUN_HIGH ); + + Delay_Us(50); // Give the pins about 50us to get some ADC readings in. + + printf( "1: %d %d %d %d\n", (int)ADC1->IDATAR1, (int)ADC1->IDATAR2, (int)ADC1->IDATAR3, (int)ADC1->IDATAR4 ); + + Delay_Ms(1000); + + funDigitalWrite( PD2, FUN_LOW ); + funDigitalWrite( PC4, FUN_LOW ); + funDigitalWrite( PA1, FUN_LOW ); + funDigitalWrite( PA2, FUN_LOW ); + + Delay_Us(50); // Give the pins about 50us to get some ADC readings in. + + printf( "0: %d %d %d %d\n", (int)ADC1->IDATAR1, (int)ADC1->IDATAR2, (int)ADC1->IDATAR3, (int)ADC1->IDATAR4 ); + + Delay_Ms(1000); + } +} + diff --git a/examples/gpio_and_adc_injection_test/funconfig.h b/examples/adc_injection/funconfig.h similarity index 100% rename from examples/gpio_and_adc_injection_test/funconfig.h rename to examples/adc_injection/funconfig.h diff --git a/examples/gpio_and_adc/Makefile b/examples/gpio_and_adc/Makefile new file mode 100644 index 00000000..9c88c98f --- /dev/null +++ b/examples/gpio_and_adc/Makefile @@ -0,0 +1,10 @@ +all : flash + +TARGET:=gpio_and_adc + +include ../../ch32v003fun/ch32v003fun.mk + +flash : cv_flash +clean : cv_clean + + diff --git a/examples/gpio_and_adc/funconfig.h b/examples/gpio_and_adc/funconfig.h new file mode 100644 index 00000000..998cf76f --- /dev/null +++ b/examples/gpio_and_adc/funconfig.h @@ -0,0 +1,7 @@ +#ifndef _FUNCONFIG_H +#define _FUNCONFIG_H + +#define CH32V003 1 + +#endif + diff --git a/examples/gpio_and_adc/gpio_and_adc.c b/examples/gpio_and_adc/gpio_and_adc.c new file mode 100644 index 00000000..3fcfeae3 --- /dev/null +++ b/examples/gpio_and_adc/gpio_and_adc.c @@ -0,0 +1,93 @@ +// Basic GPIO and Injection-Mode ADC Example using modern funPinMode / funDigitalWrite / etc... modes. +// +// Modes (Assume processor VCC = 3.3V) +// Push/Pull: +// * ADC Works. +// * Output 1: GPIO Sources 50mA +// * Output 0: GPIO Sinks 52mA +// Open Drain +// (PC1, 2, 5, 6, 5V tolerant pins) +// * Output 1: if 5V is applied, no current flows. +// * Output 0: Pin is driven low. +// Open Drain (Other pins) +// * Very high Z - "1" +// * Sink 52mA - "0" +// * If 5V is applied, pin sinks 20mA (or 86mA if driven low) +// Analog or Float +// * No sinking or sourcing +// * Output 0 or 1 has no effect. +// * No analog pins are 5V tolerant. +// * If 5V is applied to 5v-tolearnt pin (PC1, 2, 5, 6, 5V tolerant pins) no current flows. +// * If 5V is applied to other pins, pin sinks 20mA from 5V +// PU/PD +// * Pull-up and Pull-down. +// * Output 1: pin sources 76uA from GND. +// * Output 0: pin sinks 76uA from 3.3v. +// * I.e. If you want to have a pull-up, configure PUPD, then set output to 1. +// * If 5V is applied, pin sinks 20mA. +// * If within 0...3.3V, pretend it has 45k Ohms. + +#include "ch32v003fun.h" +#include + +int main() +{ + SystemInit(); + + funGpioInitAll(); + funAnalogInit(); + + funPinMode( PA1, GPIO_CFGLR_IN_ANALOG ); // Corresponds to analog in A0 + funPinMode( PA2, GPIO_CFGLR_IN_PUPD ); // Corresponds to analog in A1 + funPinMode( PC4, GPIO_CFGLR_OUT_50Mhz_OD ); // Corresponds to analog in A2 + funPinMode( PD2, GPIO_CFGLR_OUT_50Mhz_PP ); // Corresponds to analog in A3 + funPinMode( PC1, GPIO_CFGLR_OUT_50Mhz_OD ); // PC1 = 5V tolerant (so no ADC) + + while(1) + { + // Drive digitals high + funDigitalWrite( PA1, FUN_HIGH /* = 1 */ ); + funDigitalWrite( PA2, FUN_HIGH ); + funDigitalWrite( PC4, FUN_HIGH ); + funDigitalWrite( PD2, FUN_HIGH ); + funDigitalWrite( PC1, FUN_HIGH ); // 5v tolerant, no ADC + + Delay_Ms(1000); + + printf( "1: %d %d %d %d\n", + funAnalogRead( ANALOG_0 ), + funAnalogRead( ANALOG_1 ), + funAnalogRead( ANALOG_2 ), + funAnalogRead( ANALOG_3 ) ); + + printf( " %d %d %d %d %d\n\n", + funDigitalRead( PA1 ), + funDigitalRead( PA2 ), + funDigitalRead( PC4 ), + funDigitalRead( PD2 ), + funDigitalRead( PC1 ) ); + + // Drive digitals low + funDigitalWrite( PA1, FUN_LOW /* = 0 */ ); + funDigitalWrite( PA2, FUN_LOW ); + funDigitalWrite( PC4, FUN_LOW ); + funDigitalWrite( PD2, FUN_LOW ); + funDigitalWrite( PC1, FUN_LOW ); // 5v tolerant, no ADC + + Delay_Ms(1000); + + printf( "0: %d %d %d %d\n", + funAnalogRead( ANALOG_0 ), + funAnalogRead( ANALOG_1 ), + funAnalogRead( ANALOG_2 ), + funAnalogRead( ANALOG_3 ) ); + + printf( " %d %d %d %d %d\n\n", + funDigitalRead( PA1 ), + funDigitalRead( PA2 ), + funDigitalRead( PC4 ), + funDigitalRead( PD2 ), + funDigitalRead( PC1 ) ); + } +} + diff --git a/examples/gpio_and_adc_injection_test/gpio_and_adc_injection_test.c b/examples/gpio_and_adc_injection_test/gpio_and_adc_injection_test.c deleted file mode 100644 index 8eb5b5fa..00000000 --- a/examples/gpio_and_adc_injection_test/gpio_and_adc_injection_test.c +++ /dev/null @@ -1,105 +0,0 @@ -// Basic GPIO and Injection-Mode ADC Example using modern funPinMode / funDigitalWrite / etc... modes. -// -// Modes (Assume processor VCC = 3.3V) -// Push/Pull: -// * ADC Works. -// * Source 50mA - "1" -// * Sink 52mA - "0" -// Open Drain (PC1, 2, 5, 6) -// * If unset (open) if 5V is applied, no current flows. -// * Only doesn't draw power if set to "float" -// Open Drain (Other pins) -// * Very high Z - "1" -// * Sink 52mA - "9" -// * If 5V is applied, pin sinks 20mA (or 86mA if driven low) -// Analog -// * No sinking or sourcing -// * No analog pins are 5V tolerant. -// * If 5V is applied, pin sinks 20mA. -// PU/PD -// * If 5V is applied, pin sinks 20mA. -// * If set to high, pin sources 76uA from GND. -// * If set to low, pin sinks 76uA from 3.3v. -// * If within 0...3.3V, pretend it has 45k Ohms. - -#include "ch32v003fun.h" -#include - -void discard( int x ) -{ - asm volatile( "" : : "r"(x) : "memory" ); -} - -int main() -{ - SystemInit(); - - funGpioInitAll(); - - funPinMode( PD2, GPIO_CFGLR_OUT_50Mhz_PP ); - funPinMode( PC4, GPIO_CFGLR_OUT_50Mhz_OD ); // PC4 = Not 5V tolerant. - funPinMode( PC1, GPIO_CFGLR_OUT_50Mhz_OD ); - funPinMode( PA1, GPIO_CFGLR_IN_ANALOG ); - funPinMode( PA2, GPIO_CFGLR_IN_PUPD ); - - // Enable ADC - RCC->APB2PCENR |= RCC_APB2Periph_ADC1; - - // Reset the ADC to init all regs - RCC->APB2PRSTR |= RCC_APB2Periph_ADC1; - RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1; - - // JSQ1 = Channel 0 (PA2) - // JSQ2 = Channel 1 (PA1) - // JSQ3 = Channel 2 (PC4) - // JSQ3 = Channel 3 (PD2) - ADC1->ISQR= - ADC_JL_0 | ADC_JL_1 | // 4 Total channels - ADC_JSQ4_1 | ADC_JSQ4_0 | // Channel 3 (PD2) - ADC_JSQ3_1 | // Channel 2 (PC4) - ADC_JSQ2_0 | // Channel 1 (PA1) - 0; // Channel 0 (PA2) - - // 0:7 => 3/9/15/30/43/57/73/241 cycles - - ADC1->SAMPTR2 |= (ADC_SMP0_0 | ADC_SMP0_1 | ADC_SMP0_2 | \ - ADC_SMP1_0 | ADC_SMP1_1 | ADC_SMP1_2 | \ - ADC_SMP2_0 | ADC_SMP2_1 | ADC_SMP2_2 | \ - ADC_SMP3_1 | ADC_SMP3_1 | ADC_SMP3_2); - - // turn on ADC and set rule group to sw trig - ADC1->CTLR2 = ADC_ADON | ADC_JEXTSEL; - - ADC1->CTLR1 = ADC_SCAN; - - // Reset calibration - ADC1->CTLR2 |= ADC_RSTCAL; - while(ADC1->CTLR2 & ADC_RSTCAL); - - // Calibrate - ADC1->CTLR2 |= ADC_CAL; - while(ADC1->CTLR2 & ADC_CAL); - - while(1) - { - funDigitalWrite( PD2, 1 ); - funDigitalWrite( PC4, 1 ); - funDigitalWrite( PC1, 1 ); // 5v tolerant, no ADC - funDigitalWrite( PA1, 1 ); - funDigitalWrite( PA2, 1 ); - ADC1->CTLR2 |= ADC_JSWSTART; - // We can't do something like check JEOC here, because it is going to be true as soon as the conversion starts. - Delay_Ms(1000); - printf( "1: %d %d %d %d\n", (int)ADC1->IDATAR1, (int)ADC1->IDATAR2, (int)ADC1->IDATAR3, (int)ADC1->IDATAR4 ); - - funDigitalWrite( PD2, 0 ); - funDigitalWrite( PC4, 0 ); - funDigitalWrite( PC1, 0 ); // 5v tolerant, no ADC - funDigitalWrite( PA1, 0 ); - funDigitalWrite( PA2, 0 ); - ADC1->CTLR2 |= ADC_JSWSTART; - Delay_Ms(1000); - printf( "0: %d %d %d %d\n", (int)ADC1->IDATAR1, (int)ADC1->IDATAR2, (int)ADC1->IDATAR3, (int)ADC1->IDATAR4 ); - } -} -