1+ #pragma once
2+
3+ #include " stm32h7xx_hal.h"
4+ #include < array>
5+ #include < span>
6+ #include < tuple>
7+
8+ using std::array;
9+ using std::size_t ;
10+ using std::span;
11+ using std::tuple;
12+
13+ namespace ST_LIB {
14+ extern void compile_error (const char *msg);
15+
16+ struct GPIODomain {
17+ enum class OperationMode : uint8_t {
18+ INPUT , // GPIO_MODE_INPUT
19+ OUTPUT_PUSHPULL , // GPIO_MODE_OUTPUT_PP
20+ OUTPUT_OPENDRAIN , // GPIO_MODE_OUTPUT_OD
21+ ANALOG , // GPIO_MODE_ANALOG
22+ ALT_PP , // GPIO_MODE_AF_PP
23+ ALT_OD , // GPIO_MODE_AF_OD
24+ EXTI_RISING , // GPIO_MODE_IT_RISING
25+ EXTI_FALLING , // GPIO_MODE_IT_FALLING
26+ EXTI_RISING_FALLING , // GPIO_MODE_IT_RISING_FALLING
27+ };
28+ static constexpr uint32_t to_hal_mode (OperationMode m) {
29+ switch (m) {
30+ case OperationMode::INPUT :
31+ return GPIO_MODE_INPUT ;
32+ case OperationMode::OUTPUT_PUSHPULL :
33+ return GPIO_MODE_OUTPUT_PP ;
34+ case OperationMode::OUTPUT_OPENDRAIN :
35+ return GPIO_MODE_OUTPUT_OD ;
36+ case OperationMode::ANALOG :
37+ return GPIO_MODE_ANALOG ;
38+ case OperationMode::ALT_PP :
39+ return GPIO_MODE_AF_PP ;
40+ case OperationMode::ALT_OD :
41+ return GPIO_MODE_AF_OD ;
42+ case OperationMode::EXTI_RISING :
43+ return GPIO_MODE_IT_RISING ;
44+ case OperationMode::EXTI_FALLING :
45+ return GPIO_MODE_IT_FALLING ;
46+ case OperationMode::EXTI_RISING_FALLING :
47+ return GPIO_MODE_IT_RISING_FALLING ;
48+ }
49+ }
50+ enum class Pull : uint8_t { None, Up, Down };
51+ static constexpr uint32_t to_hal_pull (Pull p) {
52+ switch (p) {
53+ case Pull::None:
54+ return GPIO_NOPULL ;
55+ case Pull::Up:
56+ return GPIO_PULLUP ;
57+ case Pull::Down:
58+ return GPIO_PULLDOWN ;
59+ }
60+ }
61+ enum class Speed : uint8_t { Low, Medium, High, VeryHigh };
62+ static constexpr uint32_t to_hal_speed (Speed s) {
63+ switch (s) {
64+ case Speed::Low:
65+ return GPIO_SPEED_FREQ_LOW ;
66+ case Speed::Medium:
67+ return GPIO_SPEED_FREQ_MEDIUM ;
68+ case Speed::High:
69+ return GPIO_SPEED_FREQ_HIGH ;
70+ case Speed::VeryHigh:
71+ return GPIO_SPEED_FREQ_VERY_HIGH ;
72+ }
73+ }
74+ enum class AlternateFunction : uint8_t {
75+ NO_AF = 20 ,
76+ AF0 = 15 ,
77+ AF1 = 14 ,
78+ AF2 = 13 ,
79+ AF3 = 12 ,
80+ AF4 = 11 ,
81+ AF5 = 10 ,
82+ AF6 = 9 ,
83+ AF7 = 8 ,
84+ AF8 = 7 ,
85+ AF9 = 6 ,
86+ AF10 = 5 ,
87+ AF11 = 4 ,
88+ AF12 = 3 ,
89+ AF13 = 2 ,
90+ AF14 = 1 ,
91+ AF15 = 0
92+ };
93+ enum class Port : uint8_t { A, B, C, D, E, F, G, H };
94+ static inline GPIO_TypeDef *port_to_reg (Port p) {
95+ switch (p) {
96+ case Port::A:
97+ return GPIOA ;
98+ case Port::B:
99+ return GPIOB ;
100+ case Port::C:
101+ return GPIOC ;
102+ case Port::D:
103+ return GPIOD ;
104+ case Port::E:
105+ return GPIOE ;
106+ case Port::F:
107+ return GPIOF ;
108+ case Port::G:
109+ return GPIOG ;
110+ case Port::H:
111+ return GPIOH ;
112+ default :
113+ return nullptr ;
114+ }
115+ }
116+ static inline void enable_gpio_clock (Port port) {
117+ switch (port) {
118+ case Port::A:
119+ __HAL_RCC_GPIOA_CLK_ENABLE ();
120+ break ;
121+
122+ case Port::B:
123+ __HAL_RCC_GPIOB_CLK_ENABLE ();
124+ break ;
125+
126+ case Port::C:
127+ __HAL_RCC_GPIOC_CLK_ENABLE ();
128+ break ;
129+
130+ case Port::D:
131+ __HAL_RCC_GPIOD_CLK_ENABLE ();
132+ break ;
133+
134+ case Port::E:
135+ __HAL_RCC_GPIOE_CLK_ENABLE ();
136+ break ;
137+
138+ case Port::F:
139+ __HAL_RCC_GPIOF_CLK_ENABLE ();
140+ break ;
141+
142+ case Port::G:
143+ __HAL_RCC_GPIOG_CLK_ENABLE ();
144+ break ;
145+
146+ case Port::H:
147+ __HAL_RCC_GPIOH_CLK_ENABLE ();
148+ break ;
149+ }
150+ }
151+
152+ struct Pin {
153+ GPIODomain::Port port;
154+ uint32_t pin;
155+ uint16_t afs;
156+
157+ inline constexpr bool valid_af (const AlternateFunction af) const {
158+ if (af == AlternateFunction::NO_AF )
159+ return true ;
160+ return ((1 << static_cast <uint8_t >(af)) & afs) != 0 ;
161+ }
162+ };
163+
164+ struct Entry {
165+ Port port;
166+ uint32_t pin;
167+ OperationMode mode;
168+ Pull pull;
169+ Speed speed;
170+ AlternateFunction af;
171+ };
172+
173+ struct GPIO {
174+ using domain = GPIODomain;
175+
176+ Entry e;
177+
178+ consteval GPIO (const Pin &pin, OperationMode mode, Pull pull, Speed speed,
179+ AlternateFunction af = AlternateFunction::NO_AF )
180+ : e{pin.port , pin.pin , mode, pull, speed, af} {
181+ if (!pin.valid_af (af)) {
182+ compile_error (" Alternate function not valid for this pin" );
183+ }
184+ }
185+
186+ template <class Ctx > consteval void inscribe (Ctx &ctx) const {
187+ ctx.template add <GPIODomain>(e);
188+ }
189+ };
190+
191+ static constexpr std::size_t max_instances{110 };
192+
193+ struct Config {
194+ std::tuple<Port, GPIO_InitTypeDef> init_data{};
195+ };
196+
197+ template <size_t N>
198+ static consteval array<Config, N> build (span<const Entry> pins) {
199+ array<Config, N> cfgs{};
200+ for (std::size_t i = 0 ; i < N; ++i) {
201+ const auto &e = pins[i];
202+
203+ for (std::size_t j = 0 ; j < i; ++j) {
204+ const auto &prev = pins[j];
205+ if (prev.pin == e.pin && prev.port == e.port ) {
206+ compile_error (" GPIO already inscribed" );
207+ }
208+ }
209+
210+ GPIO_InitTypeDef GPIO_InitStruct{};
211+ GPIO_InitStruct.Pin = e.pin ;
212+ GPIO_InitStruct.Mode = to_hal_mode (e.mode );
213+ GPIO_InitStruct.Pull = to_hal_pull (e.pull );
214+ GPIO_InitStruct.Speed = to_hal_speed (e.speed );
215+ if (e.mode == OperationMode::ALT_PP || e.mode == OperationMode::ALT_OD ) {
216+ GPIO_InitStruct.Alternate = static_cast <uint32_t >(e.af );
217+ }
218+
219+ cfgs[i].init_data = std::make_tuple (e.port , GPIO_InitStruct);
220+ }
221+
222+ return cfgs;
223+ }
224+
225+ // Runtime object
226+ struct Instance {
227+ private:
228+ GPIO_TypeDef *port;
229+ uint32_t pin;
230+
231+ public:
232+ constexpr Instance () : port{nullptr }, pin{0 } {}
233+ Instance (GPIO_TypeDef *p, uint32_t pin)
234+ : port{p}, pin{static_cast <uint16_t >(pin)} {}
235+
236+ void turn_on () { HAL_GPIO_WritePin (port, pin, GPIO_PIN_SET ); }
237+
238+ void turn_off () { HAL_GPIO_WritePin (port, pin, GPIO_PIN_RESET ); }
239+
240+ void toggle () { HAL_GPIO_TogglePin (port, pin); }
241+
242+ GPIO_PinState read () { return HAL_GPIO_ReadPin (port, pin); }
243+ };
244+
245+ template <std::size_t N> struct Init {
246+ static inline std::array<Instance, N> instances{};
247+
248+ static void init (std::span<const Config, N> cfgs) {
249+ static_assert (N > 0 );
250+ for (std::size_t i = 0 ; i < N; ++i) {
251+ const auto &e = cfgs[i];
252+ auto [port, gpio_init] = e.init_data ;
253+
254+ enable_gpio_clock (port);
255+ HAL_GPIO_Init (port_to_reg (port), &gpio_init);
256+
257+ instances[i] = Instance{port_to_reg (port), gpio_init.Pin };
258+ }
259+ }
260+ };
261+ };
262+ } // namespace ST_LIB
0 commit comments