abse/smart-ring-flex
A tscircuit package created by abse.
- Version
- 0.0.24
- License
- unset
- Stars
- 0
firmware/onboard-programmer/ring-service-candidate/src/gpio.h
// ===================================================================================
// Basic GPIO, PWM and ADC Functions for CH551, CH552 and CH554 * v1.5 *
// ===================================================================================
//
// Pins must be defined as P10, P11, P12, etc. - e.g.:
// #define PIN_LED P33 // LED on pin P3.3
//
// Functions available:
// --------------------
// PIN_input(PIN) set PIN as INPUT (high impedance, no pullup)
// PIN_input_PU(PIN) set PIN as INPUT with internal PULLUP
// PIN_output(PIN) set PIN as OUTPUT (push-pull)
// PIN_output_OD(PIN) set PIN as OUTPUT (open-drain)
//
// PIN_low(PIN) set PIN output value to LOW
// PIN_high(PIN) set PIN output value to HIGH
// PIN_toggle(PIN) TOGGLE PIN output value
// PIN_read(PIN) read PIN input value
// PIN_write(PIN, val) write PIN output value (0 = LOW / 1 = HIGH)
//
// PIN_asm(PIN) convert PIN for inline assembly: setb PIN_asm(PIN_LED)
// PIN_set(PIN) convert PIN for direct manipulation: PIN_set(PIN_LED) = 1;
//
// PIN_WAKE_enable(PIN) enable wake-up from sleep by PIN low (P13, P14, P15 only)
// PIN_WAKE_disable(PIN) disable wake-up from sleep by PIN low
//
// PWM_start(PIN) start PWM output on PIN, can be (P15 or P30) and (P34 or P31)
// PWM_stop(PIN) stop PWM output on PIN
// PWM_write(PIN, val) set PWM output active level duty cycle on PIN
//
// PWM_pol_normal(PIN) set normal PWM polarity on PIN (default low and active high)
// PWM_pol_reverse(PIN) set reverse PWM polarity on PIN (default high and active low)
// PWM_set_freq(FREQ) set global PWM frequency (in Hertz)
//
// ADC_enable() enable ADC
// ADC_disable() disable ADC
// ADC_fast() set ADC fast mode ( 96 clock cycles per sample, less accurate)
// ADC_slow() set ADC slow mode (384 clock cycles per sample, more accurate)
// ADC_input(PIN) set ADC input pin (P11, P14, P15, P32 only)
// ADC_read() sample and read ADC value (0..255)
//
// CMP_enable() enable comparator
// CMP_disable() disable comparator
// CMP_positive(PIN) set CMP non-inverting input pin (P11, P14, P15, P32 only)
// CMP_negative(PIN) set CMP inverting input pin (P14, P32 only)
// CMP_read() read CMP output (0: pos < neg, 1: pos > neg)
//
// Notes:
// ------
// Pins used for PWM should be set as OUTPUT beforehand.
// Pins used for ADC or CMP must have been set as INPUT (high impedance) beforehand.
//
// 2022 by Stefan Wagner: https://github.com/wagiminator
#pragma once
#include <stdint.h>
#include "ch554.h"
// ===================================================================================
// Enumerate pin designators (use these designators to define pins)
// ===================================================================================
enum{P10, P11, P12, P13, P14, P15, P16, P17, P30, P31, P32, P33, P34, P35, P36, P37};
// ===================================================================================
// Helper Defines (these are for internal use only)
// ===================================================================================
// Define pins for direct bit manipulation
SBIT(PP10, 0x90, 0);
SBIT(PP11, 0x90, 1);
SBIT(PP12, 0x90, 2);
SBIT(PP13, 0x90, 3);
SBIT(PP14, 0x90, 4);
SBIT(PP15, 0x90, 5);
SBIT(PP16, 0x90, 6);
SBIT(PP17, 0x90, 7);
SBIT(PP30, 0xB0, 0);
SBIT(PP31, 0xB0, 1);
SBIT(PP32, 0xB0, 2);
SBIT(PP33, 0xB0, 3);
SBIT(PP34, 0xB0, 4);
SBIT(PP35, 0xB0, 5);
SBIT(PP36, 0xB0, 6);
SBIT(PP37, 0xB0, 7);
// 2nd-stage glue defines
#define PIN_h_a(PIN) _P##PIN
#define PIN_h_s(PIN) P##PIN
#define PORT_h_i(PORT, PIN) (P##PORT##_DIR_PU &= ~(1<<PIN), P##PORT##_MOD_OC &= ~(1<<PIN))
#define PORT_h_iP(PORT, PIN) (P##PORT##_MOD_OC |= (1<<PIN), P##PORT##_DIR_PU |= (1<<PIN))
#define PORT_h_o(PORT, PIN) (P##PORT##_MOD_OC &= ~(1<<PIN), P##PORT##_DIR_PU |= (1<<PIN))
#define PORT_h_oO(PORT, PIN) (P##PORT##_MOD_OC |= (1<<PIN), P##PORT##_DIR_PU &= ~(1<<PIN))
#define PORT_h_l(PORT, PIN) PP##PORT##PIN = 0
#define PORT_h_h(PORT, PIN) PP##PORT##PIN = 1
#define PORT_h_t(PORT, PIN) PP##PORT##PIN = !PP##PORT##PIN
#define PORT_h_r(PORT, PIN) (PP##PORT##PIN)
#define PORT_h_w(PORT,PIN,val) PP##PORT##PIN = val
// ===================================================================================
// Set pin as INPUT (high impedance, no pullup)
// ===================================================================================
#define PIN_input(PIN) \
((PIN>=P10)&&(PIN<=P17) ? (P1_DIR_PU &= ~(1<<(PIN&7)), P1_MOD_OC &= ~(1<<(PIN&7))) : \
((PIN>=P30)&&(PIN<=P37) ? (P3_DIR_PU &= ~(1<<(PIN&7)), P3_MOD_OC &= ~(1<<(PIN&7))) : \
(0)))
#define PIN_input_HI PIN_input
#define PIN_input_FL PIN_input
// ===================================================================================
// Set pin as INPUT with internal PULLUP resistor (also open-drain output,
// when output changes from LOW to HIGH, it will drive HIGH for 2 clock cycles)
// ===================================================================================
#define PIN_input_PU(PIN) \
((PIN>=P10)&&(PIN<=P17) ? (P1_MOD_OC |= (1<<(PIN&7)), P1_DIR_PU |= (1<<(PIN&7))) : \
((PIN>=P30)&&(PIN<=P37) ? (P3_MOD_OC |= (1<<(PIN&7)), P3_DIR_PU |= (1<<(PIN&7))) : \
(0)))
// ===================================================================================
// Set pin as OUTPUT (push-pull)
// ===================================================================================
#define PIN_output(PIN) \
((PIN>=P10)&&(PIN<=P17) ? (P1_MOD_OC &= ~(1<<(PIN&7)), P1_DIR_PU |= (1<<(PIN&7))) : \
((PIN>=P30)&&(PIN<=P37) ? (P3_MOD_OC &= ~(1<<(PIN&7)), P3_DIR_PU |= (1<<(PIN&7))) : \
(0)))
#define PIN_output_PP PIN_output
// ===================================================================================
// Set pin as OPEN-DRAIN OUTPUT (also high-impedance input, no pullup)
// ===================================================================================
#define PIN_output_OD(PIN) \
((PIN>=P10)&&(PIN<=P17) ? (P1_MOD_OC |= (1<<(PIN&7)), P1_DIR_PU &= ~(1<<(PIN&7))) : \
((PIN>=P30)&&(PIN<=P37) ? (P3_MOD_OC |= (1<<(PIN&7)), P3_DIR_PU &= ~(1<<(PIN&7))) : \
(0)))
// ===================================================================================
// Pin manipulation macros
// ===================================================================================
#define PIN_low(PIN) PIN_h_s(PIN) = 0 // set pin to LOW
#define PIN_high(PIN) PIN_h_s(PIN) = 1 // set pin to HIGH
#define PIN_toggle(PIN) PIN_h_s(PIN) = !PIN_h_s(PIN) // TOGGLE pin
#define PIN_read(PIN) (PIN_h_s(PIN)) // READ pin
#define PIN_write(PIN, val) PIN_h_s(PIN) = val // WRITE pin value
// ===================================================================================
// (PORT, PIN) manipulation macros
// ===================================================================================
#define PORT_input(PORT, PIN) PORT_h_i(PORT, PIN) // set pin as INPUT
#define PORT_input_PU(PORT, PIN) PORT_h_iP(PORT, PIN) // set pin as INPUT PULLUP
#define PORT_output(PORT, PIN) PORT_h_o(PORT, PIN) // set pin as OUTPUT
#define PORT_output_OD(PORT, PIN) PORT_h_oO(PORT, PIN) // set pin as OUTPUT OPEN-DRAIN
#define PORT_low(PORT, PIN) PORT_h_l(PORT, PIN) // set pin to LOW
#define PORT_high(PORT, PIN) PORT_h_h(PORT, PIN) // set pin to HIGH
#define PORT_toggle(PORT, PIN) PORT_h_t(PORT, PIN) // TOGGLE pin
#define PORT_read(PORT, PIN) PORT_h_r(PORT, PIN) // READ pin
#define PORT_write(PORT,PIN,val) PORT_h_w(PORT, PIN, val) // WRITE pin value
// ===================================================================================
// Convert pin for inline assembly and direct manipulation
// ===================================================================================
#define PIN_asm(PIN) PIN_h_a(PIN)
#define PIN_set(PIN) PIN_h_s(PIN)
// ===================================================================================
// Enable/disable WAKE-up from sleep by pin LOW (P13, P14, P15 only)
// ===================================================================================
#define WAKE_PIN_enable(PIN) \
((PIN == P13) ? (WAKE_CTRL |= bWAK_P1_3_LO) : \
((PIN == P14) ? (WAKE_CTRL |= bWAK_P1_4_LO) : \
((PIN == P15) ? (WAKE_CTRL |= bWAK_P1_5_LO) : \
(0)))))
#define WAKE_PIN_disable(PIN) \
((PIN == P13) ? (WAKE_CTRL &= ~bWAK_P1_3_LO) : \
((PIN == P14) ? (WAKE_CTRL &= ~bWAK_P1_4_LO) : \
((PIN == P15) ? (WAKE_CTRL &= ~bWAK_P1_5_LO) : \
(0)))))
// ===================================================================================
// Start PWM on pin, must be a PWM-capable pin: (P15 or P30) and (P34 or P31)
// ===================================================================================
#define PWM_start(PIN) \
((PIN == P15) ? (PWM_CTRL &= ~bPWM_CLR_ALL, PIN_FUNC &= ~bPWM1_PIN_X, PWM_CTRL |= bPWM1_OUT_EN) : \
((PIN == P34) ? (PWM_CTRL &= ~bPWM_CLR_ALL, PIN_FUNC &= ~bPWM2_PIN_X, PWM_CTRL |= bPWM2_OUT_EN) : \
((PIN == P30) ? (PWM_CTRL &= ~bPWM_CLR_ALL, PIN_FUNC |= bPWM1_PIN_X, PWM_CTRL |= bPWM1_OUT_EN) : \
((PIN == P31) ? (PWM_CTRL &= ~bPWM_CLR_ALL, PIN_FUNC |= bPWM2_PIN_X, PWM_CTRL |= bPWM2_OUT_EN) : \
(0)))))
// ===================================================================================
// Set PWM output active level duty cycle on pin
// ===================================================================================
#define PWM_write(PIN, val) \
((PIN == P15) ? (PWM_DATA1 = val) : \
((PIN == P34) ? (PWM_DATA2 = val) : \
((PIN == P30) ? (PWM_DATA1 = val) : \
((PIN == P31) ? (PWM_DATA2 = val) : \
(0)))))
// ===================================================================================
// Stop PWM on pin
// ===================================================================================
#define PWM_stop(PIN) \
((PIN == P15) ? (PWM_CTRL &= ~bPWM1_OUT_EN) : \
((PIN == P34) ? (PWM_CTRL &= ~bPWM2_OUT_EN) : \
((PIN == P30) ? (PWM_CTRL &= ~bPWM1_OUT_EN) : \
((PIN == P31) ? (PWM_CTRL &= ~bPWM2_OUT_EN) : \
(0)))))
// ===================================================================================
// Set normal PWM polarity on pin (default low and active high)
// ===================================================================================
#define PWM_pol_normal(PIN) \
((PIN == P15) ? (PWM_CTRL &= ~bPWM1_POLAR) : \
((PIN == P34) ? (PWM_CTRL &= ~bPWM2_POLAR) : \
((PIN == P30) ? (PWM_CTRL &= ~bPWM1_POLAR) : \
((PIN == P31) ? (PWM_CTRL &= ~bPWM2_POLAR) : \
(0)))))
// ===================================================================================
// Set reverse PWM polarity on pin (default high and active low)
// ===================================================================================
#define PWM_pol_reverse(PIN) \
((PIN == P15) ? (PWM_CTRL |= bPWM1_POLAR) : \
((PIN == P34) ? (PWM_CTRL |= bPWM2_POLAR) : \
((PIN == P30) ? (PWM_CTRL |= bPWM1_POLAR) : \
((PIN == P31) ? (PWM_CTRL |= bPWM2_POLAR) : \
(0)))))
// ===================================================================================
// Set global PWM frequency (in Hertz, range: F_CPU/65536 - F_CPU/256)
// ===================================================================================
#define PWM_set_freq(FREQ) \
(((FREQ) >= F_CPU / 256) ? (PWM_CK_SE = 0) : \
(((F_CPU / 256 / (FREQ) - 1) > 255) ? (PWM_CK_SE = 255) : \
(PWM_CK_SE = (uint8_t)(F_CPU / 256 / (FREQ) - 1)) \
))
// ===================================================================================
// Pin to ADC channel conversion (P11, P14, P15, P32 only)
// ===================================================================================
#define ADC_channel(PIN) \
((PIN == P11) ? (0) : \
((PIN == P14) ? (1) : \
((PIN == P15) ? (2) : \
((PIN == P32) ? (3) : \
(0)))))
// ===================================================================================
// ADC functions (P11, P14, P15, P32 only)
// ===================================================================================
#define ADC_enable() ADC_CFG |= bADC_EN
#define ADC_disable() ADC_CFG &= ~bADC_EN
#define ADC_fast() ADC_CFG |= bADC_CLK
#define ADC_slow() ADC_CFG &= ~bADC_CLK
#define ADC_input(PIN) \
((PIN == P11) ? (ADC_CHAN1 = 0, ADC_CHAN0 = 0) : \
((PIN == P14) ? (ADC_CHAN1 = 0, ADC_CHAN0 = 1) : \
((PIN == P15) ? (ADC_CHAN1 = 1, ADC_CHAN0 = 0) : \
((PIN == P32) ? (ADC_CHAN1 = 1, ADC_CHAN0 = 1) : \
(0)))))
inline uint8_t ADC_read(void) {
ADC_START = 1;
while(ADC_START);
return ADC_DATA;
}
// ===================================================================================
// Pin to comparator inverting input conversion (P14, P32 only)
// ===================================================================================
#define CMP_channel(PIN) \
((PIN == P14) ? (0) : \
((PIN == P32) ? (1) : \
(0)))
// ===================================================================================
// Comparator functions (positive: P11, P14, P15, P32, negative: P14, P32 only)
// ===================================================================================
#define CMP_enable() ADC_CFG |= bCMP_EN
#define CMP_disable() ADC_CFG &= ~bCMP_EN
#define CMP_read() (CMPO)
#define CMP_positive(PIN) ADC_input(PIN)
#define CMP_negative(PIN) \
((PIN == P14) ? (CMP_CHAN = 0) : \
((PIN == P32) ? (CMP_CHAN = 1) : \
(0)))