diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b088f28f4d4a6a8cd810433089afa1c1a8686d9c..fe3796b257422291f987f66aab73530f5daa60d3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,25 +35,16 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 - - name: Cache pip - uses: actions/cache@v3 + - uses: actions/cache@v3 with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - name: Cache PlatformIO - uses: actions/cache@v3 + path: | + ~/.cache/pip + ~/.platformio/.cache + key: ${{ runner.os }}-pio + - uses: actions/setup-python@v4 with: - path: ~/.platformio - key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: "3.9" - - name: Install PlatformIO - run: | - python -m pip install --upgrade pip - pip install --upgrade platformio - - name: Run PlatformIO - run: pio run + python-version: '3.9' + - name: Install PlatformIO Core + run: pip install --upgrade platformio + - name: Build PlatformIO Project + run: pio run \ No newline at end of file diff --git a/README.md b/README.md index a833ad0aeec93fe21e5c967fcb0c14db8b3439d0..fe987373a5e339f2c9b0b92d0cf3598834d58def 100644 --- a/README.md +++ b/README.md @@ -112,15 +112,20 @@ To use the WCH-Link in WSL, it is required to "attach" the USB hardware on the W 9. For unknown reasons, you must run make under root access in order to connect to the programmer with minichlink. Recommend running `sudo make` when building and programming projects using WSL. This may work too (to be confirmed): ### non-root access on linux -Unlike serial interfaces, by default, the USB device is owned by root, has group set to root and everyone else may only read. -1. Get the vendor:device ID of the WCH-Link from `lsusb`. -2. Create a udev rule with `sudo nano /etc/udev/rules.d/80-USB_WCH-Link.rules`, paste (CTRL+SHIFT+V) `SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="8010", MODE="0666"` and save, replacing the idVendor and idProduct if what you got previously was different. -3. Reboot or reload the udev rules with `sudo udevadm control --reload-rules && sudo udevadm trigger` -4. ??? -5. profit -Now anyone on your PC has access to the WCH-Link device, so you can stop using sudo for make. -I don't think there are any security risks here. -You may also tie this to the WCH-Link serial number or some other attribute from `udevadm info -a -n /dev/bus/usb/busid/deviceid` with the bus id and device id you got from lsusb earlier. +Unlike serial interfaces, by default, the USB device is owned by root, has group set to root and everyone else may only read by default. +The way to allow non-root users/groups to be able to access devices is via udev rules. + +minichlink provides a list of udev rules that allows any user in the plugdev group to be able to interact with the programmers it supports. + +You can install and load the required udev rules for minichlink by executing the following commands in the root of this Git repository: +``` +sudo cp minichlink/99-minichlink.rules /etc/udev/rules.d/ +sudo udevadm control --reload-rules && sudo udevadm trigger +``` + +If you add support for another programmer in minichlink, you will need to add more rules here. + +**Note:** This readme used to recommend manually making these rules under `80-USB_WCH-Link.rules`. If you wish to use the new rules file shipped in this repo, you may want to remove the old rules file. ## minichlink diff --git a/examples/GPIO/Makefile b/examples/GPIO/Makefile index 399d16eba5d704e10e1ce2a4c0455daf5b06477c..87347371d38e65e7c05f84225b553f957d5d1eca 100644 --- a/examples/GPIO/Makefile +++ b/examples/GPIO/Makefile @@ -3,7 +3,7 @@ all : flash TARGET:=GPIO CFLAGS+=-DTINYVECTOR -ADDITIONAL_C_FILES+=wiring.c +ADDITIONAL_C_FILES+=../../extralibs/wiring.c include ../../ch32v003fun/ch32v003fun.mk diff --git a/examples/GPIO_analogRead/Makefile b/examples/GPIO_analogRead/Makefile index e47191ea6a2a9efea0eb37aa371f0c276ec5f817..a965d90a0e3e624237b8b7234cfce7e09475c44e 100644 --- a/examples/GPIO_analogRead/Makefile +++ b/examples/GPIO_analogRead/Makefile @@ -3,7 +3,7 @@ all : flash TARGET:=GPIO_analogRead CFLAGS+=-DTINYVECTOR -ADDITIONAL_C_FILES+=wiring.c +ADDITIONAL_C_FILES+=../../extralibs/wiring.c include ../../ch32v003fun/ch32v003fun.mk diff --git a/examples/GPIO_analogRead/wiring.c b/examples/GPIO_analogRead/wiring.c deleted file mode 100644 index e0acde1977e48cc74ac45f7b33c123d25e028758..0000000000000000000000000000000000000000 --- a/examples/GPIO_analogRead/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 = GPIOA+(pin>>3); - 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/examples/GPIO_analogRead/wiring.h b/examples/GPIO_analogRead/wiring.h deleted file mode 100644 index 3b7d0d74e0a1a8f1d41fca115b4aaeb3901cc8e2..0000000000000000000000000000000000000000 --- a/examples/GPIO_analogRead/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/examples/GPIO/wiring.c b/extralibs/wiring.c similarity index 98% rename from examples/GPIO/wiring.c rename to extralibs/wiring.c index e0acde1977e48cc74ac45f7b33c123d25e028758..b04f8e46dc07a1832b4332edbc3a0e44b02e427b 100644 --- a/examples/GPIO/wiring.c +++ b/extralibs/wiring.c @@ -43,7 +43,7 @@ void pinMode(enum GPIOpins pin, enum GPIOpinMode mode) { GPIO_TypeDef * GPIOx; uint16_t PinOffset; - GPIOx = GPIOA+(pin>>3); + GPIOx = (GPIO_TypeDef *)(((uint8_t*)(GPIOA))+(pin>>3)*0x0400); PinOffset = (pin & 0x7)<<2; GPIOx->CFGLR &= ~(0b1111<<PinOffset); // zero the 4 configuration bits diff --git a/examples/GPIO/wiring.h b/extralibs/wiring.h similarity index 100% rename from examples/GPIO/wiring.h rename to extralibs/wiring.h diff --git a/minichlink/99-minichlink.rules b/minichlink/99-minichlink.rules index db763c84e4072c6488d9af1125889153f90a8e48..8cca6989adad49aceff2f035b04e8024dc76446e 100644 --- a/minichlink/99-minichlink.rules +++ b/minichlink/99-minichlink.rules @@ -1,4 +1,4 @@ -SUBSYSTEMS=="usb", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="8010", GROUP="plugdev", MODE="0666" -SUBSYSTEM=="usb", ATTR{idVendor}=="303a", ATTR{idProduct}=="4004", GROUP="users", MODE="0666" -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev" +SUBSYSTEM=="usb", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="8010", GROUP="plugdev", MODE="0660" +SUBSYSTEM=="usb", ATTRS{idVendor}=="303a", ATTRS{idProduct}=="4004", GROUP="plugdev", MODE="0660" +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="303a", ATTRS{idProduct}=="4004", GROUP="plugdev", MODE="0660" diff --git a/platformio.ini b/platformio.ini index b1626df25cd0b6ed47b99b90832676c03463dcd3..263b6ac00e167e52572d7cda8edff404de3f7e12 100644 --- a/platformio.ini +++ b/platformio.ini @@ -17,7 +17,13 @@ extends = fun_base board_build.ldscript = ch32v003fun/ch32v003fun.ld build_flags = -flto -Ich32v003fun -I/usr/include/newlib -DTINYVECTOR -lgcc -Iextralibs build_src_filter = +<ch32v003fun> +extra_libs_srcs = +<extralibs> +; If creating a new example: +; 1. Add new [env:name] +; 2. Add build_src_filter with fun base files + example folder (+ extra libraries if used) for source files +; 3. Add additional build flags as needed (see uartdemo) +; 4. Switch to new environment in VSCode bottom taskbar (https://docs.platformio.org/en/latest/integration/ide/vscode.html#project-tasks) [env:blink] build_src_filter = ${fun_base.build_src_filter} +<examples/blink> @@ -30,6 +36,12 @@ build_src_filter = ${fun_base.build_src_filter} +<examples/debugprintfdemo> [env:external_crystal] 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>