Skip to content
Snippets Groups Projects
Commit 6debe86a authored by AAC A's avatar AAC A
Browse files

GPIO example expanded by ADC functions, additional ADC example analogRead

parent fa4d6480
No related branches found
No related tags found
No related merge requests found
......@@ -3,7 +3,7 @@
#define SYSTEM_CORE_CLOCK 48000000
#include "ch32v003fun.h"
#include "wiring_digital.h"
#include "wiring.h"
#include <stdio.h>
#define APB_CLOCK SYSTEM_CORE_CLOCK
......@@ -11,37 +11,37 @@
uint32_t count;
int main() {
SystemInit48HSI();
// Enable GPIO ports
enablePort(port_C);
enablePort(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);
while (1) {
// Turn on pins
digitalWrite(pin_C0, high);
digitalWrite(pin_D4, 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);
Delay_Ms(50);
}
for (int i = pin_C7; i >= pin_C0; i--) {
digitalWrite(i, low);
Delay_Ms(50);
}
Delay_Ms(250);
count++;
}
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);
while (1) {
// Turn on pins
digitalWrite(pin_C0, high);
digitalWrite(pin_D4, 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);
Delay_Ms(50);
}
for (int i = pin_C7; i >= pin_C0; i--) {
digitalWrite(i, low);
Delay_Ms(50);
}
Delay_Ms(250);
count++;
}
}
......@@ -25,7 +25,7 @@ LDFLAGS:=-T $(CH32V003FUN)/ch32v003fun.ld -Wl,--gc-sections -L../../misc -lgcc
SYSTEM_C:=$(CH32V003FUN)/ch32v003fun.c
$(TARGET).elf : $(SYSTEM_C) $(TARGET).c wiring_digital.c
$(TARGET).elf : $(SYSTEM_C) $(TARGET).c wiring.c
$(PREFIX)-gcc -o $@ $^ $(CFLAGS) $(LDFLAGS)
$(TARGET).bin : $(TARGET).elf
......
//#include <stdio.h>
#include "wiring_digital.h"
#include "wiring.h"
#include <stdint.h>
......@@ -20,7 +20,7 @@ enum GPIOports getPort (enum GPIOpins pin) {
void enablePort(enum GPIOports port) {
void portEnable(enum GPIOports port) {
// Enable GPIOs
switch (port) {
case port_A:
......@@ -159,3 +159,93 @@ uint8_t digitalRead(uint8_t pin) {
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_DIGITAL_H
#define WIRING_DIGITAL_H
#ifndef WIRING_H
#define WIRING_H
#include "../../ch32v003fun/ch32v003fun.h"
// Define the pins that will be used for GPIO
#define MY_GPIO_PIN_1 1
#define MY_GPIO_PIN_2 2
// Add more pins as needed
enum lowhigh {
......@@ -63,11 +58,42 @@ enum GPIOpinState {
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 enablePort(enum GPIOports port);
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);
#endif // WIRING_DIGITAL_H
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
// 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++;
}
}
TARGET:=GPIO_analogRead
all : flash
PREFIX:=riscv64-unknown-elf
GPIO_Toggle:=EXAM/GPIO/GPIO_Toggle/User
EVT:=../../ch32v003evt
MINICHLINK:=../../minichlink
CH32V003FUN:=../../ch32v003fun
CFLAGS:= \
-g -Os -flto -ffunction-sections \
-static-libgcc \
-march=rv32ec \
-mabi=ilp32e \
-I/usr/include/newlib \
-I$(CH32V003FUN) \
-nostdlib \
-I. -DTINYVECTOR -Wall
LDFLAGS:=-T $(CH32V003FUN)/ch32v003fun.ld -Wl,--gc-sections -L../../misc -lgcc
SYSTEM_C:=$(CH32V003FUN)/ch32v003fun.c
$(TARGET).elf : $(SYSTEM_C) $(TARGET).c wiring.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
# 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
//#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 = 4;
if (pin <= pin_A2) {
GPIOx = GPIOA;
PinOffset *= pin;
}
else if (pin <= pin_C7) {
GPIOx = GPIOC;
PinOffset *= (pin - 2);
}
else if (pin <= pin_D7) {
GPIOx = GPIOD;
PinOffset *= (pin - 10);
}
else {
return;
}
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 - 2);
}
else if (pin <= pin_D7) {
GPIOx = GPIOD;
PinOffset = (pin - 10);
}
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 - 2);
}
else if (pin <= pin_D7) {
GPIOx = GPIOD;
PinOffset = (pin - 10);
}
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/ch32v003fun.h"
enum lowhigh {
low,
high,
};
enum GPIOports{
port_A,
port_C,
port_D,
port_none,
};
enum GPIOpins{
pin_A1,
pin_A2,
pin_C0,
pin_C1,
pin_C2,
pin_C3,
pin_C4,
pin_C5,
pin_C6,
pin_C7,
pin_D0,
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
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