diff --git a/examples/GPIO/GPIO.c b/examples/GPIO/GPIO.c index 148aa0198a1710d1b298fbf2f6c038201a90b6e6..a761850c339f8e445fc38585064b58a92c73a6ec 100644 --- a/examples/GPIO/GPIO.c +++ b/examples/GPIO/GPIO.c @@ -1,47 +1,199 @@ -// blink, but with arduino-like HAL -// Could be defined here, or in the processor defines. +// 2023-06-07 recallmenot + +#define DEMO_GPIO_blink 1 +#define DEMO_GPIO_out 0 +#define DEMO_GPIO_in_btn 0 +#define DEMO_ADC_bragraph 0 +#define DEMO_PWM_dayrider 0 + +#if ((DEMO_GPIO_blink + DEMO_GPIO_out + DEMO_GPIO_in_btn + DEMO_ADC_bragraph + DEMO_PWM_dayrider) > 1 \ + || (DEMO_GPIO_blink + DEMO_GPIO_out + DEMO_GPIO_in_btn + DEMO_ADC_bragraph + DEMO_PWM_dayrider) < 1) +#error "please enable ONE of the demos by setting it to 1 and the others to 0" +#endif + + #define SYSTEM_CORE_CLOCK 48000000 +#define APB_CLOCK SYSTEM_CORE_CLOCK #include "ch32v003fun.h" -#include "wiring.h" + +#include "ch32v003_GPIO_branchless.h" + #include <stdio.h> -#define APB_CLOCK SYSTEM_CORE_CLOCK -uint32_t count; int main() { SystemInit48HSI(); - // Enable GPIO ports - portEnable(port_C); - portEnable(port_D); - - for (int i = pin_C0; i <= pin_C7; i++) { - pinMode(i, pinMode_O_pushPull); +#if DEMO_GPIO_blink == 1 + GPIO_portEnable(GPIO_port_C); + GPIO_portEnable(GPIO_port_D); + // GPIO D0 Push-Pull + GPIO_pinMode(GPIO_port_D, 0, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz); + // GPIO D4 Push-Pull + GPIO_pinMode(GPIO_port_D, 4, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz); + // GPIO C0 Push-Pull + GPIO_pinMode(GPIO_port_C, 0, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz); +#elif DEMO_GPIO_out == 1 + GPIO_portEnable(GPIO_port_C); + GPIO_portEnable(GPIO_port_D); + // GPIO D4 Push-Pull + GPIO_pinMode(GPIO_port_D, 4, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz); + // GPIO C0 - C7 Push-Pull + for (int i = 0; i <= 7; i++) { + GPIO_pinMode(GPIO_port_C, i, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz); } - +#elif DEMO_GPIO_in_btn == 1 + GPIO_portEnable(GPIO_port_C); + GPIO_portEnable(GPIO_port_D); + // GPIO D4 Push-Pull + GPIO_pinMode(GPIO_port_D, 3, GPIO_pinMode_I_pullUp, GPIO_SPEED_IN); + // GPIO C0 - C7 Push-Pull + for (int i = 0; i <= 7; i++) { + GPIO_pinMode(GPIO_port_C, i, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz); + } +#elif DEMO_ADC_bragraph == 1 + GPIO_portEnable(GPIO_port_C); + GPIO_portEnable(GPIO_port_D); // GPIO D4 Push-Pull - pinMode(pin_D4, pinMode_O_pushPull); + GPIO_pinMode(GPIO_port_D, 4, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz); + // GPIO D6 analog in + GPIO_pinMode(GPIO_port_D, 6, GPIO_pinMode_I_analog, GPIO_SPEED_IN); + // GPIO C0 - C7 Push-Pull + for (int i = 0; i<= 7; i++) { + GPIO_pinMode(GPIO_port_C, i, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz); + } + GPIO_ADCinit(); +#elif DEMO_PWM_dayrider == 1 + //SetupUART( UART_BRR ); + GPIO_portEnable(GPIO_port_C); + GPIO_portEnable(GPIO_port_D); + // GPIO D4 Push-Pull + GPIO_pinMode(GPIO_port_D, 4, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz); + // GPIO D6 analog in + GPIO_pinMode(GPIO_port_D, 6, GPIO_pinMode_I_analog, GPIO_SPEED_IN); + // GPIO C0 - C7 Push-Pull + for (int i = 0; i<= 7; i++) { + GPIO_pinMode(GPIO_port_C, i, GPIO_pinMode_O_pushPullMux, GPIO_Speed_50MHz); + } + GPIO_tim2_map(GPIO_tim2_output_set_1__C5_C2_D2_C1); + GPIO_tim2_init(); + GPIO_tim2_enableCH(4); + GPIO_tim2_enableCH(2); + GPIO_tim2_enableCH(1); + GPIO_tim1_map(GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1); + GPIO_tim1_init(); + GPIO_tim1_enableCH(3); + GPIO_tim1_enableCH(4); +#endif + + while (1) { - // Turn on pins - digitalWrite(pin_C0, high); - digitalWrite(pin_D4, high); +#if DEMO_GPIO_blink == 1 + GPIO_digitalWrite(GPIO_port_D, 0, high); + GPIO_digitalWrite(GPIO_port_D, 4, high); + GPIO_digitalWrite(GPIO_port_C, 0, high); + Delay_Ms( 250 ); + GPIO_digitalWrite(GPIO_port_D, 0, low); + GPIO_digitalWrite(GPIO_port_D, 4, low); + GPIO_digitalWrite(GPIO_port_C, 0, low); + Delay_Ms( 250 ); +#elif DEMO_GPIO_out == 1 + GPIO_digitalWrite(GPIO_port_D, 4, low); + Delay_Ms(1000); + GPIO_digitalWrite(GPIO_port_D, 4, high); Delay_Ms(250); - // Turn off pins - digitalWrite(pin_C0, low); - digitalWrite(pin_D4, low); - Delay_Ms(250); - for (int i = pin_C0; i <= pin_C7; i++) { - digitalWrite(i, high); + for (int i = 0; i <= 7; i++) { + GPIO_digitalWrite_hi(GPIO_port_C, i); Delay_Ms(50); } - for (int i = pin_C7; i >= pin_C0; i--) { - digitalWrite(i, low); + for (int i = 7; i >= 0; i--) { + GPIO_digitalWrite_lo(GPIO_port_C, i); Delay_Ms(50); } - Delay_Ms(250); - count++; +#elif DEMO_GPIO_in_btn == 1 + uint8_t button_is_pressed = !GPIO_digitalRead(GPIO_port_D, 3); + static uint8_t leds_to_turn_on; + if (button_is_pressed && leds_to_turn_on < 8) { + leds_to_turn_on++; + } + else if (!button_is_pressed && leds_to_turn_on > 0) { + leds_to_turn_on--; + } + uint8_t led_i = 0; + for (int i = 0; i<= 7; i++) { + if (led_i < leds_to_turn_on) { + GPIO_digitalWrite_hi(GPIO_port_C, i); + } + else { + GPIO_digitalWrite_lo(GPIO_port_C, i); + } + led_i++; + } + Delay_Ms(50); +#elif DEMO_ADC_bragraph == 1 + GPIO_digitalWrite(GPIO_port_D, 4, high); + uint16_t analog_result = GPIO_analogRead(GPIO_Ain6_D6); + analog_result = analog_result > 10 ? + (analog_result < ((1 << 10) - 42) ? analog_result + 42 : (1 << 10)) + : 0; + uint8_t leds_to_turn_on = analog_result >> 7; + uint8_t led_i = 0; + for (int i = 0; i<= 7; i++) { + if (led_i < leds_to_turn_on) { + GPIO_digitalWrite_hi(GPIO_port_C, i); + } + else { + GPIO_digitalWrite_lo(GPIO_port_C, i); + } + led_i++; + } + GPIO_digitalWrite(GPIO_port_D, 4, low); + Delay_Ms(50); +#elif DEMO_PWM_dayrider == 1 + #define NUMLEDS 5 + #define TICKS_NEXT 149 // lower = faster scanning + #define TICK_i 2143 // lower = faster fade-out + GPIO_digitalWrite(GPIO_port_D, 4, high); + static uint8_t led_focus = 0; + static uint8_t direction = 0; + + static uint16_t led_PW[NUMLEDS]; + + static uint32_t tick; + + for (uint8_t i = 0; i < NUMLEDS; i++) { + if ((i == led_focus) && ((tick % TICKS_NEXT) == 0)) { + led_PW[i] = 1023; + //printf("focus %u, tick %u, direction %u\r\n", led_focus, tick, direction); + if (direction == 0) { + led_focus++; + if (led_focus >= (NUMLEDS - 1)) { + direction = 1; + } + } + else { + led_focus--; + if (led_focus == 0) { + direction = 0; + } + } + tick++; + } + else { + led_PW[i] = (led_PW[i] > 2) ? (led_PW[i] - 3) : 0; + } + } + GPIO_tim2_analogWrite(4, led_PW[0]); + GPIO_tim2_analogWrite(2, led_PW[1]); + GPIO_tim1_analogWrite(3, led_PW[2]); + GPIO_tim1_analogWrite(4, led_PW[3]); + GPIO_tim2_analogWrite(1, led_PW[4]); + GPIO_digitalWrite(GPIO_port_D, 4, low); + tick++; + Delay_Us(TICK_i); +#endif } } diff --git a/examples/GPIO/Makefile b/examples/GPIO/Makefile index 87347371d38e65e7c05f84225b553f957d5d1eca..7e60f814bb33181340eca2ad204cee695088fcc8 100644 --- a/examples/GPIO/Makefile +++ b/examples/GPIO/Makefile @@ -3,7 +3,7 @@ all : flash TARGET:=GPIO CFLAGS+=-DTINYVECTOR -ADDITIONAL_C_FILES+=../../extralibs/wiring.c +CFLAGS+=-DSTDOUT_UART include ../../ch32v003fun/ch32v003fun.mk diff --git a/examples/GPIO/README.md b/examples/GPIO/README.md index a6c23799ff7e6df932b10774273f86094daac8b3..33ac22d79daecb0e64c0c96c8df2f0d50450934a 100644 --- a/examples/GPIO/README.md +++ b/examples/GPIO/README.md @@ -1,14 +1,22 @@ -# GPIO Libaray -On the shoulders of the Blink example, this Arduino-like GPIO library stands. +# one GPIO libaray to rule them all -All pins are adressable as outputs, inputs, with pull-up, etc. -The pins are in an enum, so you can call them by their name and iterate over them. +This Arduino-like GPIO library offers + * digital IO + * analog-to-digital + * digital-to-analog (PWM) -It's your responsibility to not blow up a pin. -Only use one pin for one thing and you should be fine. +Great care has been taken to make the resulting code as fast and tiny as possible. Let the compiler suffer! +Hand-written blink compiles to 500 bytes, blink using this library compiles to 504 bytes! # GPIO Example -Connect LED + 1k resistor to each pin (C0 to C7 and D4) and GND. -Marvel at the colorful glory. -https://user-images.githubusercontent.com/104343143/231585338-725f1197-dfa0-484d-8707-f0824af80b7e.mp4 +Connect LED + 1k resistor to each LED pin (C0 to C7 and D4) and GND. +Connect a button to GND and D3. +Connect a 10k pot between GND and VCC, wiper to D6. + +The desired demo may be selected in GPIO.c by setting it to 1 and the others to 0. +Marvel at the colorful glory. + + + +https://github.com/recallmenot/ch32v003fun/assets/104343143/afb4027d-a609-467a-96c5-0cc3283366a4 diff --git a/examples/GPIO_analogRead/GPIO_analogRead.c b/examples/GPIO_analogRead/GPIO_analogRead.c deleted file mode 100644 index 76df1facacafbbf45260486402d91266f1f93d7a..0000000000000000000000000000000000000000 --- a/examples/GPIO_analogRead/GPIO_analogRead.c +++ /dev/null @@ -1,47 +0,0 @@ -// blink, but with arduino-like HAL -// Could be defined here, or in the processor defines. -#define SYSTEM_CORE_CLOCK 48000000 - -#include "ch32v003fun.h" -#include "wiring.h" -#include <stdio.h> - -#define APB_CLOCK SYSTEM_CORE_CLOCK - -uint32_t count; - -int main() { - SystemInit48HSI(); - - // Enable GPIO ports - portEnable(port_C); - portEnable(port_D); - - for (int i = pin_C0; i <= pin_C7; i++) { - pinMode(i, pinMode_O_pushPull); - } - - // GPIO D4 Push-Pull - pinMode(pin_D4, pinMode_O_pushPull); - - pinMode(pin_D6, pinMode_I_analog); - ADCinit(); - - while (1) { - digitalWrite(pin_D4, high); - uint8_t leds_to_turn_on = (uint8_t)(((float)(analogRead(Ain6_D6)) / 1024.f) * 8.f * 1.2 - 1.f); - uint8_t led_i = 0; - for (int i = pin_C0; i <= pin_C7; i++) { - if (led_i < leds_to_turn_on) { - digitalWrite(i, high); - } - else { - digitalWrite(i, low); - } - led_i++; - } - digitalWrite(pin_D4, low); - Delay_Ms(250); - count++; - } -} diff --git a/examples/GPIO_analogRead/Makefile b/examples/GPIO_analogRead/Makefile deleted file mode 100644 index a965d90a0e3e624237b8b7234cfce7e09475c44e..0000000000000000000000000000000000000000 --- a/examples/GPIO_analogRead/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -all : flash - -TARGET:=GPIO_analogRead - -CFLAGS+=-DTINYVECTOR -ADDITIONAL_C_FILES+=../../extralibs/wiring.c - -include ../../ch32v003fun/ch32v003fun.mk - -flash : cv_flash -clean : cv_clean - diff --git a/examples/GPIO_analogRead/README.md b/examples/GPIO_analogRead/README.md deleted file mode 100644 index 3b9e1b6ca6799c77987e830cf7ea868d095601b5..0000000000000000000000000000000000000000 --- a/examples/GPIO_analogRead/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# GPIO Libaray -On the shoulders of the Blink and the adc_polled example, this Arduino-like GPIO + ADC library stands. - -All pins are adressable as outputs, inputs, with pull-up, etc. but now you can also read the eight muxed inputs. -The pins are in an enum, so you can call them by their name and iterate over them. - -It has been extended by an arduino-like analogRead function. - -It's your responsibility to not blow up a pin. -Only use one pin for one thing and you should be fine. - -# GPIO Example -Connect LED + 1k resistor to each pin (C0 to C7 and D4) and GND. -Connect a 10k pot between GND and VCC, wiper to D6. -Marvel at the colorful glory. - -https://user-images.githubusercontent.com/104343143/231814680-d41ae68f-dc7b-4c9c-a3c7-0b88cc82e541.mp4 diff --git a/examples/blink/blink.bin b/examples/blink/blink.bin index 9d2f625331af46afe752e4c674ea3ca6a67b5f49..b2c6174d1dac1759b26f345f4dde42f709e0e59e 100755 Binary files a/examples/blink/blink.bin and b/examples/blink/blink.bin differ diff --git a/extralibs/ch32v003_GPIO_branchless.h b/extralibs/ch32v003_GPIO_branchless.h new file mode 100644 index 0000000000000000000000000000000000000000..455716b669f8438108fccdfd0c9f27feb82c263f --- /dev/null +++ b/extralibs/ch32v003_GPIO_branchless.h @@ -0,0 +1,474 @@ +// 2023-06-07 recallmenot + +//######## necessities + +// include guards +#ifndef CH32V003_GPIO_BR_H +#define CH32V003_GPIO_BR_H + +// includes +#include <stdint.h> //uintN_t support +#include "../ch32v003fun/ch32v003fun.h" + + + +/*######## library description +This is a speedy and light GPIO library due to + static inlining of most functions + compile-time abstraction + branchless where it counts +*/ + + + +/*######## library usage and configuration + +first, enable the desired port. + +digital usage is quite Arduino-like: +pinMode +digitalWrite +digitalWrite_lo +digitalWrite_hi +digitalRead + + + +analog-to-digital usage is almost Arduino-like: +pinMode +ADCinit +analogRead + +By default, this library inserts a delay of 300 µs between configuration of the ADC input mux and the time the conversion starts. +This serves to counteract the high input impedance of the ADC, especially if it is increased by external resistors. +The input impedance of port A appears to be especially large. +You may modify it to your liking using the following define before including this library. +#define GPIO_ADC_MUX_DELAY 1200 + +GPIO_ADC_sampletime controls the time each conversion is granted, by default it is GPIO_ADC_sampletime_241cy_default, all options originate from the GPIO_ADC_sampletimes enum. +To alter it, you have 3 options: + * `#define GPIO_ADC_sampletime GPIO_ADC_sampletime_43cy` before including this library + * call the GPIO_ADC_set_sampletime function-like macro to momentarrily set it for one channel + * call the GPIO_ADC_set_sampletimes_all function-like macro to to momentarrily set it for all channels + +You may also disable the ADC to save power between infrequent measurements. + + + +digital-to-analog (PWM) usage is quite different: +pinMode +GPIO_timX_map +GPIO_timX_init +GPIO_timX_enableCH +GPIO_timX_analogWrite + +This is due to the fact that the CH32V003 has 2 timers, which each can be connected to 4 pre-defined sets (mappings) of pins. +Then you address the 4 channels of the timers, instead of the pins. + +By default, the timers will be configured to count up to 2^10, which is 10 bits or 1024 discrete steps. +You may alter this to suit your needs, for example to an 8 bit resolution (256 discrete steps). +Insert this before including this library: +#define GPIO_timer_resolution (1 << 8) + +By default, the timers will operate with a clock prescaler of 2 but you may choose 1 or 4 if you wish to alter the speed. +Insert this before including this library: +#define GPIO_timer_prescaler TIM_CKD_DIV1; // APB_CLOCK / 1024 / 1 = 46.9kHz + +You may calculate the base frequency of the timer (the rate of repetition of your signal) like follows: +fpwm = APB_CLOCK / resolution / prescaler +This puts the defaults at an inaudible 23.4kHz. +The higher the frequency, the greater the EMI radiation will be. +With low frequencies, say below 1000Hz, LEDs may exhibit perceivable flicker. + +*/ + + + +//######## ports, pins and states: use these for the functions below! + +enum GPIO_port_n { + GPIO_port_A = 0b00, + GPIO_port_C = 0b10, + GPIO_port_D = 0b11, +}; + +enum GPIO_pinModes { + GPIO_pinMode_I_floating, + GPIO_pinMode_I_pullUp, + GPIO_pinMode_I_pullDown, + GPIO_pinMode_I_analog, + GPIO_pinMode_O_pushPull, + GPIO_pinMode_O_openDrain, + GPIO_pinMode_O_pushPullMux, + GPIO_pinMode_O_openDrainMux, +}; + +enum lowhigh { + low, + high, +}; + +// analog inputs +enum GPIO_analog_inputs { + GPIO_Ain0_A2, + GPIO_Ain1_A1, + GPIO_Ain2_C4, + GPIO_Ain3_D2, + GPIO_Ain4_D3, + GPIO_Ain5_D5, + GPIO_Ain6_D6, + GPIO_Ain7_D4, + GPIO_AinVref, + GPIO_AinVcal, +}; + +// how many cycles the ADC shall sample the input for (speed vs precision) +enum GPIO_ADC_sampletimes { + GPIO_ADC_sampletime_3cy, + GPIO_ADC_sampletime_9cy, + GPIO_ADC_sampletime_15cy, + GPIO_ADC_sampletime_30cy, + GPIO_ADC_sampletime_43cy, + GPIO_ADC_sampletime_57cy, + GPIO_ADC_sampletime_73cy, + GPIO_ADC_sampletime_241cy_default, +}; + +enum GPIO_tim1_output_sets { + GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1, + GPIO_tim1_output_set_1__C6_C7_C0_D3__C3_C4_D1, + GPIO_tim1_output_set_2__D2_A1_C3_C4__D0_A2_D1, + GPIO_tim1_output_set_3__C4_C7_C5_D4__C3_D2_C6, +}; + +enum GPIO_tim2_output_sets { + GPIO_tim2_output_set_0__D4_D3_C0_D7, + GPIO_tim2_output_set_1__C5_C2_D2_C1, + GPIO_tim2_output_set_2__C1_D3_C0_D7, + GPIO_tim2_output_set_3__C1_C7_D6_D5, +}; + + + +//######## interface function overview: use these! +// most functions have been reduced to function-like macros, actual definitions downstairs + +// setup +#define GPIO_portEnable(GPIO_port_n) +#define GPIO_pinMode(GPIO_port_n, pin, pinMode, GPIO_Speed) + +// digital +#define GPIO_digitalWrite_hi(GPIO_port_n, pin) +#define GPIO_digitalWrite_lo(GPIO_port_n, pin) +#define GPIO_digitalWrite(GPIO_port_n, pin, lowhigh) +#define GPIO_digitalWrite_branching(GPIO_port_n, pin, lowhigh) +#define GPIO_digitalRead(GPIO_port_n, pin) + +// analog to digital +static inline void GPIO_ADCinit(); +#define GPIO_ADC_set_sampletime(GPIO_analog_input, GPIO_ADC_sampletime) +#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) +#define GPIO_ADC_set_power(enable) +#define GPIO_ADC_calibrate() +static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input); + +// digital to analog (PWM) +#define GPIO_tim1_map(GPIO_tim1_output_set) +#define GPIO_tim2_map(GPIO_tim2_output_set) +static inline void GPIO_tim1_init(); +static inline void GPIO_tim2_init(); +#define GPIO_tim1_enableCH(channel) +#define GPIO_tim2_enableCH(channel) +#define GPIO_tim1_analogWrite(channel, value) +#define GPIO_tim2_analogWrite(channel, value) + + + +//######## internal function declarations + + + +//######## internal variables + + + +//######## preprocessor macros + +#define CONCAT(a, b) a ## b +#define CONCAT_INDIRECT(a, b) CONCAT(a, b) + +#define GPIOx_to_port_n2(GPIOx) GPIOx_to_port_n_##GPIOx +#define GPIOx_to_port_n(GPIOx) GPIOx_to_port_n2(GPIOx) +#define GPIOx_to_port_n_GPIO_port_A 0b00 +#define GPIOx_to_port_n_GPIO_port_C 0b10 +#define GPIOx_to_port_n_GPIO_port_D 0b11 + +#define GPIO_port_n_to_GPIOx2(GPIO_port_n) GPIO_port_n_to_GPIOx_##GPIO_port_n +#define GPIO_port_n_to_GPIOx(GPIO_port_n) GPIO_port_n_to_GPIOx2(GPIO_port_n) +#define GPIO_port_n_to_GPIOx_GPIO_port_A GPIOA +#define GPIO_port_n_to_GPIOx_GPIO_port_C GPIOC +#define GPIO_port_n_to_GPIOx_GPIO_port_D GPIOD + +#define GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph_##GPIO_port_n +#define GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n) +#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_A RCC_APB2Periph_GPIOA +#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_C RCC_APB2Periph_GPIOC +#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_D RCC_APB2Periph_GPIOD + +#define GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG_##GPIO_pinMode(GPIO_Speed) +#define GPIO_pinMode_to_CFG(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed) +#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_floating(GPIO_Speed) (GPIO_SPEED_IN | GPIO_CNF_IN_FLOATING) +#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullUp(GPIO_Speed) (GPIO_SPEED_IN | GPIO_CNF_IN_PUPD) +#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullDown(GPIO_Speed) (GPIO_SPEED_IN | GPIO_CNF_IN_PUPD) +#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_analog(GPIO_Speed) (GPIO_SPEED_IN | GPIO_CNF_IN_ANALOG) +#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPull(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP) +#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrain(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_OD) +#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPullMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP_AF) +#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrainMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_IN_ANALOG) + +#define GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n, pin) GPIO_pinMode_set_PUPD_##GPIO_pinMode(GPIO_port_n, pin) +#define GPIO_pinMode_set_PUPD(GPIO_pinMode, GPIO_port_n, pin) GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n, pin) +#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_floating(GPIO_port_n, pin) +#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIO_port_n, pin) GPIO_port_n_to_GPIOx(GPIO_port_n)->BSHR = (1 << pin) +#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIO_port_n, pin) GPIO_port_n_to_GPIOx(GPIO_port_n)->BSHR = (1 << (pin + 16)) +#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_analog(GPIO_port_n, pin) +#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPull(GPIO_port_n, pin) +#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrain(GPIO_port_n, pin) +#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPullMux(GPIO_port_n, pin) +#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrainMux(GPIO_port_n, pin) + +#if !defined(GPIO_ADC_MUX_DELAY) +#define GPIO_ADC_MUX_DELAY 200 +#endif + +#if !defined(GPIO_ADC_sampletime) +#define GPIO_ADC_sampletime GPIO_ADC_sampletime_241cy_default +#endif + +#if !defined(GPIO_timer_resolution) +#define GPIO_timer_resolution (1 << 10) +#endif + +#if !defined(GPIO_timer_prescaler) +#define GPIO_timer_prescaler TIM_CKD_DIV2 // APB_CLOCK / 1024 / 2 = 23.4kHz +#endif + +// maintenance define +#if !defined(SYSTEM_CORE_CLOCK) +#define SYSTEM_CORE_CLOCK 48000000 +#define APB_CLOCK SYSTEM_CORE_CLOCK +#endif + + + +//######## define requirements / maintenance defines + + + +//######## small function definitions, static inline + + +#undef GPIO_portEnable +#define GPIO_portEnable(GPIO_port_n) RCC->APB2PCENR |= GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n); + +#undef GPIO_pinMode +#define GPIO_pinMode(GPIO_port_n, pin, pinMode, GPIO_Speed) ({ \ + GPIO_port_n_to_GPIOx(GPIO_port_n)->CFGLR &= ~(0b1111 << (4 * pin)); \ + GPIO_port_n_to_GPIOx(GPIO_port_n)->CFGLR |= (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * pin)); \ + GPIO_pinMode_set_PUPD(pinMode, GPIO_port_n, pin); \ +}) + +#undef GPIO_digitalWrite_hi +#define GPIO_digitalWrite_hi(GPIO_port_n, pin) GPIO_port_n_to_GPIOx(GPIO_port_n)->BSHR = (1 << pin) +#undef GPIO_digitalWrite_lo +#define GPIO_digitalWrite_lo(GPIO_port_n, pin) GPIO_port_n_to_GPIOx(GPIO_port_n)->BSHR = (1 << (pin + 16)) + +#undef GPIO_digitalWrite +#define GPIO_digitalWrite2(GPIO_port_n, pin, lowhigh) GPIO_digitalWrite_##lowhigh(GPIO_port_n, pin) +#define GPIO_digitalWrite(GPIO_port_n, pin, lowhigh) GPIO_digitalWrite2(GPIO_port_n, pin, lowhigh) +#define GPIO_digitalWrite_low(GPIO_port_n, pin) GPIO_digitalWrite_lo(GPIO_port_n, pin) +#define GPIO_digitalWrite_0(GPIO_port_n, pin) GPIO_digitalWrite_lo(GPIO_port_n, pin) +#define GPIO_digitalWrite_high(GPIO_port_n, pin) GPIO_digitalWrite_hi(GPIO_port_n, pin) +#define GPIO_digitalWrite_1(GPIO_port_n, pin) GPIO_digitalWrite_hi(GPIO_port_n, pin) + +#undef GPIO_digitalWrite_branching +#define GPIO_digitalWrite_branching(GPIO_port_n, pin, lowhigh) (lowhigh ? GPIO_digitalWrite_hi(GPIO_port_n, pin) : GPIO_digitalWrite_lo(GPIO_port_n, pin)) + +#undef GPIO_digitalRead +#define GPIO_digitalRead(GPIO_port_n, pin) ((GPIO_port_n_to_GPIOx(GPIO_port_n)->INDR >> pin) & 0b1) + + +#undef GPIO_ADC_set_sampletime +// 0:7 => 3/9/15/30/43/57/73/241 cycles +#define GPIO_ADC_set_sampletime(GPIO_analog_input, GPIO_ADC_sampletime) ({ \ + ADC1->SAMPTR2 &= ~(0b111) << (3 * GPIO_analog_input); \ + ADC1->SAMPTR2 |= GPIO_ADC_sampletime << (3 * GPIO_analog_input); \ +}) + +#undef GPIO_ADC_set_sampletimes_all +#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({ \ + ADC1->SAMPTR2 &= 0; \ + ADC1->SAMPTR2 |= \ + GPIO_ADC_sampletime << (0 * 3) \ + | GPIO_ADC_sampletime << (1 * 3) \ + | GPIO_ADC_sampletime << (2 * 3) \ + | GPIO_ADC_sampletime << (3 * 3) \ + | GPIO_ADC_sampletime << (4 * 3) \ + | GPIO_ADC_sampletime << (5 * 3) \ + | GPIO_ADC_sampletime << (6 * 3) \ + | GPIO_ADC_sampletime << (7 * 3) \ + | GPIO_ADC_sampletime << (8 * 3) \ + | GPIO_ADC_sampletime << (9 * 3); \ + ADC1->SAMPTR1 &= 0; \ + ADC1->SAMPTR1 |= \ + GPIO_ADC_sampletime << (0 * 3) \ + | GPIO_ADC_sampletime << (1 * 3) \ + | GPIO_ADC_sampletime << (2 * 3) \ + | GPIO_ADC_sampletime << (3 * 3) \ + | GPIO_ADC_sampletime << (4 * 3) \ + | GPIO_ADC_sampletime << (5 * 3); \ +}) + +#undef GPIO_ADC_set_power +#define GPIO_ADC_set_power2(enable) GPIO_ADC_set_power_##enable +#define GPIO_ADC_set_power(enable) GPIO_ADC_set_power2(enable) +#define GPIO_ADC_set_power_1 ADC1->CTLR2 |= ADC_ADON +#define GPIO_ADC_set_power_0 ADC1->CTLR2 &= ~(ADC_ADON) + +#undef GPIO_ADC_calibrate +#define GPIO_ADC_calibrate() ({ \ + ADC1->CTLR2 |= ADC_RSTCAL; \ + while(ADC1->CTLR2 & ADC_RSTCAL); \ + ADC1->CTLR2 |= ADC_CAL; \ + while(ADC1->CTLR2 & ADC_CAL); \ +}) + +// large but will likely only ever be called once +static inline void GPIO_ADCinit() { + // select ADC clock source + // ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2 + RCC->CFGR0 &= ~(0x1F<<11); + + // enable clock to the ADC + RCC->APB2PCENR |= RCC_APB2Periph_ADC1; + + // Reset the ADC to init all regs + RCC->APB2PRSTR |= RCC_APB2Periph_ADC1; + RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1; + + // set sampling time for all inputs to 241 cycles + GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime); + + // set trigger to software + ADC1->CTLR2 |= ADC_EXTSEL; + + // pre-clear conversion queue + ADC1->RSQR1 = 0; + ADC1->RSQR2 = 0; + ADC1->RSQR3 = 0; + + // power the ADC + GPIO_ADC_set_power(1); + GPIO_ADC_calibrate(); +} + +static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input) { + // set mux to selected input + ADC1->RSQR3 = input; + // allow everything to precharge + Delay_Us(GPIO_ADC_MUX_DELAY); + // start sw conversion (auto clears) + ADC1->CTLR2 |= ADC_SWSTART; + // wait for conversion complete + while(!(ADC1->STATR & ADC_EOC)) {} + // get result + return ADC1->RDATAR; +} + + + +#undef GPIO_tim1_map +#define GPIO_tim1_map(GPIO_tim1_output_set) ({ \ + RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \ + AFIO->PCFR1 |= ((GPIO_tim1_output_set & 0b11) << 6); \ +}) + +#undef GPIO_tim2_map +#define GPIO_tim2_map(GPIO_tim2_output_set) ({ \ + RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \ + AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8); \ +}) + +static inline void GPIO_tim1_init() { + // enable TIM1 + RCC->APB2PCENR |= RCC_APB2Periph_TIM1; + // reset TIM1 to init all regs + RCC->APB2PRSTR |= RCC_APB2Periph_TIM1; + RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1; + // SMCFGR: default clk input is CK_INT + // set clock prescaler divider + TIM1->PSC = GPIO_timer_prescaler; + // set PWM total cycle width + TIM1->ATRLR = GPIO_timer_resolution; + // CTLR1: default is up, events generated, edge align + // enable auto-reload of preload + TIM1->CTLR1 |= TIM_ARPE; + // initialize counter + TIM1->SWEVGR |= TIM_UG; + // disengage brake + TIM1->BDTR |= TIM_MOE; + // Enable TIM1 + TIM1->CTLR1 |= TIM_CEN; +} +static inline void GPIO_tim2_init() { + // enable TIM2 + RCC->APB1PCENR |= RCC_APB1Periph_TIM2; + // reset TIM2 to init all regs + RCC->APB1PRSTR |= RCC_APB1Periph_TIM2; + RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM2; + // SMCFGR: default clk input is CK_INT + // set clock prescaler divider + TIM2->PSC = GPIO_timer_prescaler; + // set PWM total cycle width + TIM2->ATRLR = GPIO_timer_resolution; + // CTLR1: default is up, events generated, edge align + // enable auto-reload of preload + TIM2->CTLR1 |= TIM_ARPE; + // initialize counter + TIM2->SWEVGR |= TIM_UG; + // Enable TIM2 + TIM2->CTLR1 |= TIM_CEN; +} + +#define GPIO_timer_channel_set2(timer, channel) GPIO_timer_channel_set_##channel(timer) +#define GPIO_timer_channel_set(timer, channel) GPIO_timer_channel_set2(timer, channel) +#define GPIO_timer_channel_set_1(timer) timer->CHCTLR1 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable) +#define GPIO_timer_channel_set_2(timer) timer->CHCTLR1 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8) +#define GPIO_timer_channel_set_3(timer) timer->CHCTLR2 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable) +#define GPIO_timer_channel_set_4(timer) timer->CHCTLR2 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8) + +#undef GPIO_tim1_enableCH +#define GPIO_tim1_enableCH(channel) ({ \ + GPIO_timer_channel_set(TIM1, channel); \ + TIM1->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \ +}) +#undef GPIO_tim2_enableCH +#define GPIO_tim2_enableCH(channel) ({ \ + GPIO_timer_channel_set(TIM2, channel); \ + TIM2->CCER |= (TIM_OutputState_Enable ) << (4 * (channel - 1)); \ +}) + +#define GPIO_timer_CVR(channel) CONCAT_INDIRECT(CH, CONCAT_INDIRECT(channel, CVR)) + +#undef GPIO_tim1_analogWrite +#define GPIO_tim1_analogWrite(channel, value) ({ \ + TIM1->GPIO_timer_CVR(channel) = value; \ + TIM1->SWEVGR |= TIM_UG; \ +}) +#undef GPIO_tim2_analogWrite +#define GPIO_tim2_analogWrite(channel, value) ({ \ + TIM2->GPIO_timer_CVR(channel) = value; \ + TIM2->SWEVGR |= TIM_UG; \ +}) + +#endif // CH32V003_GPIO_BR_H diff --git a/extralibs/wiring.c b/extralibs/wiring.c deleted file mode 100644 index b04f8e46dc07a1832b4332edbc3a0e44b02e427b..0000000000000000000000000000000000000000 --- a/extralibs/wiring.c +++ /dev/null @@ -1,238 +0,0 @@ -//#include <stdio.h> - -#include "wiring.h" -#include <stdint.h> - - - -enum GPIOports getPort (enum GPIOpins pin) { - if (pin <= pin_A2) { - return port_A; - } - else if (pin <= pin_C7) { - return port_C; - } - else if (pin <= pin_D7) { - return port_D; - } - return port_none; -} - - - -void portEnable(enum GPIOports port) { - // Enable GPIOs - switch (port) { - case port_A: - RCC->APB2PCENR |= RCC_APB2Periph_GPIOA; - break; - case port_C: - RCC->APB2PCENR |= RCC_APB2Periph_GPIOC; - break; - case port_D: - RCC->APB2PCENR |= RCC_APB2Periph_GPIOD; - break; - case port_none: - break; - } -} - - - -void pinMode(enum GPIOpins pin, enum GPIOpinMode mode) { - GPIO_TypeDef * GPIOx; - uint16_t PinOffset; - - GPIOx = (GPIO_TypeDef *)(((uint8_t*)(GPIOA))+(pin>>3)*0x0400); - PinOffset = (pin & 0x7)<<2; - - GPIOx->CFGLR &= ~(0b1111<<PinOffset); // zero the 4 configuration bits - - uint8_t target_pin_state = pinState_nochange; // by default, pin shall retain its state - - uint8_t modeMask = 0; // configuration mask - - switch (mode) { - case pinMode_I_floating: - modeMask = GPIO_CNF_IN_FLOATING; - break; - case pinMode_I_pullUp: - modeMask = GPIO_CNF_IN_PUPD; - target_pin_state = pinState_high; - break; - case pinMode_I_pullDown: - modeMask = GPIO_CNF_IN_PUPD; - target_pin_state = pinState_low; - break; - case pinMode_I_analog: - modeMask = GPIO_CNF_IN_ANALOG; - break; - case pinMode_O_pushPull: - modeMask = GPIO_Speed_10MHz | GPIO_CNF_OUT_PP; - break; - case pinMode_O_openDrain: - modeMask = GPIO_Speed_10MHz | GPIO_CNF_OUT_OD; - break; - case pinMode_O_pushPullMux: - modeMask = GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF; - break; - case pinMode_O_openDrainMux: - modeMask = GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF; - break; - } - - // wirte mask to CFGR - GPIOx->CFGLR |= modeMask<<PinOffset; - - // set pin state - if (target_pin_state > pinState_nochange) { - digitalWrite(pin, target_pin_state - 1); - } -} - - - -void digitalWrite(enum GPIOpins pin, uint8_t value) { - // no checks given whether pin is currently being toggled by timer! your output trannys are in your hands! beware the magic smoke! - GPIO_TypeDef * GPIOx; - uint16_t PinOffset = 0; - - if (pin <= pin_A2) { - GPIOx = GPIOA; - PinOffset = pin; - } - else if (pin <= pin_C7) { - GPIOx = GPIOC; - PinOffset = (pin - 16); - } - else if (pin <= pin_D7) { - GPIOx = GPIOD; - PinOffset = (pin - 24); - } - else { - return; - } - - if (value) { - GPIOx-> BSHR |= 1 << PinOffset; - } - else { - GPIOx-> BSHR |= 1 << (16 + PinOffset); - } -} - - - -uint8_t digitalRead(uint8_t pin) { - GPIO_TypeDef * GPIOx; - uint16_t PinOffset = 0; - - if (pin <= pin_A2) { - GPIOx = GPIOA; - PinOffset = pin; - } - else if (pin <= pin_C7) { - GPIOx = GPIOC; - PinOffset = (pin - 16); - } - else if (pin <= pin_D7) { - GPIOx = GPIOD; - PinOffset = (pin - 24); - } - else { - return 0; - } - - int8_t result = (GPIOx->INDR >> PinOffset) & 1; - return result; -} - - - - - -void ADCinit() { - // select ADC clock source - // ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2 - RCC->CFGR0 &= ~(0x1F<<11); - - // enable clock to the ADC - RCC->APB2PCENR |= RCC_APB2Periph_ADC1; - - // Reset the ADC to init all regs - RCC->APB2PRSTR |= RCC_APB2Periph_ADC1; - RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1; - - // set sampling time for all inputs to 241 cycles - for (uint8_t i = Ain0_A2; i <= AinVcal; i++) { - ADCsetSampletime(i, Ast_241cy_default); - } - - // set trigger to software - ADC1->CTLR2 |= ADC_EXTSEL; - - // pre-clear conversion queue - ADC1->RSQR1 = 0; - ADC1->RSQR2 = 0; - ADC1->RSQR3 = 0; - - // power the ADC - ADCsetPower(1); -} - - - -void ADCsetSampletime(enum ANALOGinputs input, enum ANALOGsampletimes time) { - // clear - ADC1->SAMPTR2 &= ~(0b111)<<(3*input); - // set - ADC1->SAMPTR2 |= time<<(3*input); // 0:7 => 3/9/15/30/43/57/73/241 cycles -} - - - -void ADCsetPower(uint8_t enable) { - if (enable) { - ADC1->CTLR2 |= ADC_ADON; - if (enable == 1) { - // auto-cal each time after turning on the ADC - // can be overridden by calling with enable > 1. - ADCcalibrate(); - } - } - else { - ADC1->CTLR2 &= ~(ADC_ADON); - } -} - - - -void ADCcalibrate() { - // reset calibration - ADC1->CTLR2 |= ADC_RSTCAL; - while(ADC1->CTLR2 & ADC_RSTCAL); - - // calibrate - ADC1->CTLR2 |= ADC_CAL; - while(ADC1->CTLR2 & ADC_CAL); -} - - - -// inspired by arduinos analogRead() -uint16_t analogRead(enum ANALOGinputs input) { - // set mux to selected input - ADC1->RSQR3 = input; - - // may need a delay right here for the mux to actually finish switching?? - // Arduino inserts a full ms delay right here! - - // start sw conversion (auto clears) - ADC1->CTLR2 |= ADC_SWSTART; - - // wait for conversion complete - while(!(ADC1->STATR & ADC_EOC)); - - // get result - return ADC1->RDATAR; -} diff --git a/extralibs/wiring.h b/extralibs/wiring.h deleted file mode 100644 index 3b7d0d74e0a1a8f1d41fca115b4aaeb3901cc8e2..0000000000000000000000000000000000000000 --- a/extralibs/wiring.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef WIRING_H -#define WIRING_H - -#include "ch32v003fun.h" - - - -enum lowhigh { - low, - high, -}; - - - -enum GPIOports{ - port_A, - port_C, - port_D, - port_none, -}; - -enum GPIOpins{ - pin_A1 = 1, - pin_A2, - pin_C0 = 16, - pin_C1, - pin_C2, - pin_C3, - pin_C4, - pin_C5, - pin_C6, - pin_C7, - pin_D0 = 24, - pin_D1, - pin_D2, - pin_D3, - pin_D4, - pin_D5, - pin_D6, - pin_D7, - pin_none, -}; - -enum GPIOpinMode { - pinMode_I_floating, - pinMode_I_pullUp, //pull-mode + ODR(1) - pinMode_I_pullDown, //pull-mode + ODR(0) - pinMode_I_analog, - pinMode_O_pushPull, - pinMode_O_openDrain, - pinMode_O_pushPullMux, - pinMode_O_openDrainMux, -}; - -enum GPIOpinState { - pinState_nochange, - pinState_low, - pinState_high, -}; - -enum ANALOGinputs { - Ain0_A2, - Ain1_A1, - Ain2_C4, - Ain3_D2, - Ain4_D3, - Ain5_D5, - Ain6_D6, - Ain7_D4, - AinVref, - AinVcal, -}; - -enum ANALOGsampletimes { - Ast_3cy, - Ast_9cy, - Ast_15cy, - Ast_30cy, - Ast_43cy, - Ast_57cy, - Ast_73cy, - Ast_241cy_default, -}; - - -enum GPIOports getPort (enum GPIOpins pin); - -void portEnable(enum GPIOports port); -void pinMode(enum GPIOpins pin, enum GPIOpinMode mode); -void digitalWrite(enum GPIOpins pin, uint8_t value); -uint8_t digitalRead(uint8_t pin); - -void ADCinit(); -void ADCsetPower(uint8_t enable); -void ADCsetSampletime(enum ANALOGinputs input, enum ANALOGsampletimes time); -void ADCcalibrate(); -uint16_t analogRead(enum ANALOGinputs input); - -#endif // WIRING_H diff --git a/platformio.ini b/platformio.ini index 263b6ac00e167e52572d7cda8edff404de3f7e12..3edc591904e025923f2883664a83269f1e1840eb 100644 --- a/platformio.ini +++ b/platformio.ini @@ -39,9 +39,6 @@ build_src_filter = ${fun_base.build_src_filter} +<examples/external_crystal> [env:GPIO] build_src_filter = ${fun_base.build_src_filter} ${fun_base.extra_libs_srcs} +<examples/GPIO> -[env:GPIO_analogRead] -build_src_filter = ${fun_base.build_src_filter} ${fun_base.extra_libs_srcs} +<examples/GPIO_analogRead> - [env:optionbytes] build_src_filter = ${fun_base.build_src_filter} +<examples/optionbytes>