Skip to content

Instantly share code, notes, and snippets.

@RickKimball
Last active July 24, 2019 07:33
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save RickKimball/7d9a5bd278c8ea2e4d8e to your computer and use it in GitHub Desktop.
Save RickKimball/7d9a5bd278c8ea2e4d8e to your computer and use it in GitHub Desktop.
c++ template blink using register level gpio access
// 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);
}
// 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