Last active
July 24, 2019 07:33
-
-
Save RickKimball/7d9a5bd278c8ea2e4d8e to your computer and use it in GitHub Desktop.
c++ template blink using register level gpio access
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// more fun with c++ classes and templates | |
// http://www.stm32duino.com/viewtopic.php?f=18&t=303 | |
class GPIOPort : | |
public gpio_reg_map { | |
public: | |
void high(const uint32_t pin) { | |
BSRR = 1 << pin; | |
} | |
void low(const uint32_t pin) { | |
BRR = 1 << pin; | |
} | |
void pinMode(const uint32_t pin, gpio_pin_mode mode) { | |
volatile uint32_t *cr = &CRL + (pin >> 3); | |
uint32_t shift = (pin & 0x7) * 4; | |
uint32_t tmp = *cr; | |
tmp &= ~(0xF << shift); | |
tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift; | |
*cr = tmp; | |
if (mode == GPIO_INPUT_PD) { | |
ODR &= ~(1u << pin); | |
} else if (mode == GPIO_INPUT_PU) { | |
ODR |= (1u << pin); | |
} | |
} | |
int value(const uint32_t pin) { | |
return (IDR & (1u<< pin) ? 1 : 0); | |
} | |
}; | |
#define GPIOPORT_REF(a) *((GPIOPort * const)(a)) | |
static GPIOPort & gPortA = GPIOPORT_REF(0x40010800); | |
static GPIOPort & gPortB = GPIOPORT_REF(0x40010C00); | |
static GPIOPort & gPortC = GPIOPORT_REF(0x40011000); | |
template<const uint32_t PIN> | |
class GPIOPortBPin { | |
public: | |
void high() { gPortB.high(PIN); } | |
void low() { gPortB.low(PIN); } | |
void operator=(const int value) { | |
if ( value ) | |
gPortB.high(PIN); | |
else | |
gPortB.low(PIN); | |
} | |
operator int() { | |
return gPortB.value(PIN); | |
} | |
void pinMode(WiringPinMode mode) { | |
gpio_pin_mode gpio_mode; | |
bool pwm = false; | |
switch(mode) { | |
case OUTPUT: | |
gpio_mode = GPIO_OUTPUT_PP; | |
break; | |
case OUTPUT_OPEN_DRAIN: | |
gpio_mode = GPIO_OUTPUT_OD; | |
break; | |
case INPUT: | |
case INPUT_FLOATING: | |
gpio_mode = GPIO_INPUT_FLOATING; | |
break; | |
case INPUT_ANALOG: | |
gpio_mode = GPIO_INPUT_ANALOG; | |
break; | |
case INPUT_PULLUP: | |
gpio_mode = GPIO_INPUT_PU; | |
break; | |
case INPUT_PULLDOWN: | |
gpio_mode = GPIO_INPUT_PD; | |
break; | |
case PWM: | |
gpio_mode = GPIO_AF_OUTPUT_PP; | |
pwm = true; | |
break; | |
case PWM_OPEN_DRAIN: | |
gpio_mode = GPIO_AF_OUTPUT_OD; | |
pwm = true; | |
break; | |
default: | |
return; | |
} | |
gPortB.pinMode(PIN, gpio_mode); | |
(void)pwm; // TODO: implement timer start/stop | |
} | |
}; | |
typedef GPIOPortBPin<1> PB_1; | |
typedef GPIOPortBPin<2> PB_2; | |
// ... and on and on | |
typedef GPIOPortBPin<11> PB_15; | |
PB_1 LED1; | |
#define fastWrite(pin,value) do { (value) ? pin.high() : pin.low(); } while(0) | |
// | |
void setup() { | |
LED1.pinMode(OUTPUT); | |
} | |
void loop() { | |
LED1 = 1; | |
delay(50); | |
LED1 = 0; | |
delay(250); | |
LED1.high(); | |
delay(50); | |
LED1.low(); | |
delay(450); | |
fastWrite(LED1,1); | |
delay(50); | |
fastWrite(LED1,0); | |
delay(450); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// more fun with c++ classes and templates | |
// http://www.stm32duino.com/viewtopic.php?f=18&t=303 | |
class GPIOPort : | |
public gpio_reg_map { | |
public: | |
void high(const uint32_t pin) { | |
BSRR = 1 << pin; | |
} | |
void low(const uint32_t pin) { | |
BRR = 1 << pin; | |
} | |
void pinMode(const uint32_t pin, gpio_pin_mode mode) { | |
volatile uint32_t *cr = &CRL + (pin >> 3); | |
uint32_t shift = (pin & 0x7) * 4; | |
uint32_t tmp = *cr; | |
tmp &= ~(0xF << shift); | |
tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift; | |
*cr = tmp; | |
if (mode == GPIO_INPUT_PD) { | |
ODR &= ~(1u << pin); | |
} else if (mode == GPIO_INPUT_PU) { | |
ODR |= (1u << pin); | |
} | |
} | |
int value(const uint32_t pin) { | |
return (IDR & (1u << pin) ? 1 : 0); | |
} | |
}; | |
#define GPIOPORT_REF(a) *((GPIOPort * const)(a)) | |
template<const uint8_t PORT, const uint8_t PIN> | |
class GPIOPortPin { | |
public: | |
GPIOPort & GPIOPortX() { | |
switch (PORT) { | |
case 1: return GPIOPORT_REF(0x40010800); break; // GPIOA | |
case 2: return GPIOPORT_REF(0x40010C00); break; // GPIOB | |
case 3: return GPIOPORT_REF(0x40011000); break; // GPIOC | |
case 4: return GPIOPORT_REF(0x40011400); break; // GPIOD | |
case 5: return GPIOPORT_REF(0x40011800); break; // GPIOE | |
case 6: return GPIOPORT_REF(0x40011C00); break; // GPIOF | |
case 7: return GPIOPORT_REF(0x40012000); break; // GPIOG | |
default: return GPIOPORT_REF(0x40010800); break; // ignore error, default to A | |
} | |
} | |
void high() { | |
GPIOPortX().high(PIN); | |
} | |
void low() { | |
GPIOPortX().low(PIN); | |
} | |
// set using operator overload | |
void operator=(const int value) { | |
if ( value ) | |
GPIOPortX().high(PIN); | |
else | |
GPIOPortX().low(PIN); | |
} | |
// get using operator overload | |
operator int() { | |
return GPIOPortX().value(PIN); | |
} | |
void pinMode(WiringPinMode mode) { | |
gpio_pin_mode gpio_mode; | |
bool pwm = false; | |
switch (mode) { | |
case OUTPUT: | |
gpio_mode = GPIO_OUTPUT_PP; | |
break; | |
case OUTPUT_OPEN_DRAIN: | |
gpio_mode = GPIO_OUTPUT_OD; | |
break; | |
case INPUT: | |
case INPUT_FLOATING: | |
gpio_mode = GPIO_INPUT_FLOATING; | |
break; | |
case INPUT_ANALOG: | |
gpio_mode = GPIO_INPUT_ANALOG; | |
break; | |
case INPUT_PULLUP: | |
gpio_mode = GPIO_INPUT_PU; | |
break; | |
case INPUT_PULLDOWN: | |
gpio_mode = GPIO_INPUT_PD; | |
break; | |
case PWM: | |
gpio_mode = GPIO_AF_OUTPUT_PP; | |
pwm = true; | |
break; | |
case PWM_OPEN_DRAIN: | |
gpio_mode = GPIO_AF_OUTPUT_OD; | |
pwm = true; | |
break; | |
default: | |
return; | |
} | |
GPIOPortX().pinMode(PIN, gpio_mode); | |
(void)pwm; // TODO: implement timer start/stop | |
} | |
}; | |
#define fastWrite(pin,value) do { (value) ? pin.high() : pin.low(); } while(0) | |
typedef GPIOPortPin<1, 0> PA_0; | |
typedef GPIOPortPin<1, 1> PA_1; | |
// ... and on and on | |
typedef GPIOPortPin<1, 15> PA_15; | |
typedef GPIOPortPin<2, 0> PB_0; | |
typedef GPIOPortPin<2, 1> PB_1; | |
typedef GPIOPortPin<2, 2> PB_2; | |
// ... and on and on | |
typedef GPIOPortPin<2, 15> PB_15; | |
typedef GPIOPortPin<3, 13> PC_13; | |
typedef GPIOPortPin<3, 14> PC_14; | |
typedef GPIOPortPin<3, 15> PC_15; | |
PC_13 LED1; // blue pill led | |
void setup() { | |
LED1.pinMode(OUTPUT); | |
} | |
void loop() { | |
#if 1 | |
// set using operator= | |
LED1 = LOW; | |
delay(50); | |
// set using operator=, get using operator int | |
LED1 = !LED1; | |
delay(250); | |
#endif | |
#if 1 | |
int v = 0; | |
// set using operator= | |
LED1 = v++; | |
delay(50); | |
LED1 = v--; | |
delay(250); | |
#endif | |
#if 1 | |
// set using operator= | |
LED1 = LOW; | |
delay(50); | |
LED1 = HIGH; | |
delay(250); | |
#endif | |
#if 1 | |
// set using member function call | |
LED1.low(); | |
delay(50); | |
LED1.high(); | |
delay(250); | |
#endif | |
#if 1 | |
// set using a macro calling member function | |
fastWrite(LED1, 0); | |
delay(50); | |
fastWrite(LED1, 1); | |
delay(950); | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment