Skip to content
Snippets Groups Projects
Commit 8ecf17c6 authored by cnlohr's avatar cnlohr
Browse files

Merge branch 'master' of https://github.com/cnlohr/ch32v003fun

parents 431a2237 10ba0f30
No related branches found
No related tags found
No related merge requests found
......@@ -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
......@@ -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
......
......@@ -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
......
......@@ -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
......
//#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;
}
#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
......@@ -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
......
File moved
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"
......@@ -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>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment