Skip to content

Commit 801b8a1

Browse files
committed
[stm32] Add type-erased Gpio wrapper
1 parent 22275c0 commit 801b8a1

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright (c) 2021, Christopher Durand
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
// ----------------------------------------------------------------------------
11+
12+
#ifndef MODM_STM32_GPIO_ACCESSOR_HPP
13+
#define MODM_STM32_GPIO_ACCESSOR_HPP
14+
15+
#include <array>
16+
17+
#include "../device.hpp"
18+
#include "base.hpp"
19+
20+
namespace modm::platform
21+
{
22+
23+
/**
24+
* Type-erased Gpio wrapper
25+
*
26+
* Example:
27+
* @code
28+
* GpioAccessor gpio = GpioAccessor::template fromGpio<GpioA1>();
29+
* gpio.toggle();
30+
* @endcode
31+
*
32+
* @author Christopher Durand
33+
* @ingroup modm_platform_gpio
34+
*/
35+
class GpioAccessor : public Gpio
36+
{
37+
private:
38+
// Store port as uintptr_t instead of GPIO_TypeDef*
39+
// because ST's GPIOx macros have an int-to-pointer cast
40+
// not possible during compile-time evaluation
41+
uintptr_t portAddress;
42+
uint16_t idBit;
43+
44+
static consteval uintptr_t
45+
getPort(Port id)
46+
{
47+
switch (id)
48+
{
49+
%% for port in ports
50+
case Port::{{ port | upper }}:
51+
return GPIO{{ port | upper }}_BASE;
52+
%% endfor
53+
}
54+
}
55+
56+
auto port() const { return reinterpret_cast<GPIO_TypeDef *>(portAddress); }
57+
58+
constexpr GpioAccessor(uintptr_t port, uint8_t position)
59+
: portAddress{port}, idBit{uint16_t(1u << position)}
60+
{}
61+
62+
public:
63+
using PortType = GPIO_TypeDef *;
64+
65+
GpioAccessor(PortType port, uint8_t position)
66+
: portAddress{reinterpret_cast<uintptr_t>(port)}, idBit{uint16_t(1u << position)}
67+
{}
68+
69+
template<class Gpio>
70+
static constexpr GpioAccessor fromGpio()
71+
{
72+
static_assert(!Gpio::isInverted, "Inverted Gpios are not supported");
73+
return GpioAccessor{getPort(Gpio::port), Gpio::pin};
74+
}
75+
76+
void set() const
77+
{
78+
port()->BSRR = idBit;
79+
}
80+
81+
void reset() const
82+
{
83+
port()->BSRR = (idBit << 16);
84+
}
85+
86+
void set(bool enable) const
87+
{
88+
if(enable) {
89+
set();
90+
} else {
91+
reset();
92+
}
93+
}
94+
95+
bool isSet() const
96+
{
97+
return (port()->ODR & idBit);
98+
}
99+
100+
void toggle() const
101+
{
102+
set(!isSet());
103+
}
104+
105+
bool read() const
106+
{
107+
return (port()->IDR & idBit);
108+
}
109+
};
110+
111+
template<typename... Gpios>
112+
constexpr auto makeGpioArray()
113+
{
114+
return std::array{ GpioAccessor::template fromGpio<Gpios>()... };
115+
}
116+
117+
}
118+
119+
#endif // MODM_STM32_GPIO_ACCESSOR_HPP

src/modm/platform/gpio/stm32/module.lb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ def build(env):
303303
env.template("unused.hpp.in")
304304
if len(env["enable_ports"]):
305305
env.template("enable.cpp.in")
306+
env.template("gpio_accessor.hpp.in")
306307

307308
env.copy("../common/inverted.hpp", "inverted.hpp")
308309
env.copy("../common/connector.hpp", "connector.hpp")

0 commit comments

Comments
 (0)