dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_dio.h
Go to the documentation of this file.
1 
24 /*
25  * This program is free software; you can redistribute it and/or modify
26  * it under the terms of the GNU General Public License as published by
27  * the Free Software Foundation; either version 3 of the License, or
28  * (at your option) any later version.
29  *
30  * This program is distributed in the hope that it will be useful, but
31  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
32  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
33  * for more details.
34  *
35  * You should have received a copy of the GNU General Public License along
36  * with this program; if not, see <http://www.gnu.org/licenses/>
37  *
38  * Additional note on redistribution: The copyright and license notices above
39  * must be maintained in each individual source file that is a derivative work
40  * of this source file; otherwise redistribution is prohibited.
41  */
42 
43 #ifndef _PIOS_DIO_H
44 #define _PIOS_DIO_H
45 
46 #if defined(STM32F4XX)
47 enum dio_drive_strength {
48  DIO_DRIVE_WEAK = 0,
49  DIO_DRIVE_LIGHT,
50  DIO_DRIVE_MEDIUM,
51  DIO_DRIVE_STRONG
52 };
53 #elif defined(STM32F30X) || defined (STM32F0XX)
54 enum dio_drive_strength {
55  DIO_DRIVE_WEAK = 0,
56  DIO_DRIVE_LIGHT = 0,
57  DIO_DRIVE_MEDIUM = 1,
58  DIO_DRIVE_STRONG = 3
59 };
60 #elif defined(STM32F10X_MD)
61 enum dio_drive_strength {
62  DIO_DRIVE_WEAK = 2, // "2MHz"
63  DIO_DRIVE_LIGHT = 1, // "10MHz"
64  DIO_DRIVE_MEDIUM = 1,
65  DIO_DRIVE_STRONG = 3 // "50MHz"
66 };
67 #else
68 #error Unknown target
69 #endif
70 
76 };
77 
78 enum dio_pull {
82 };
83 
84 typedef uintptr_t dio_tag_t;
85 
86 #define DIO_NULL ((uintptr_t) 0)
87 
96 static inline void dio_set_altfunc_output(dio_tag_t t, int alt_func,
97  bool open_collector, enum dio_drive_strength strength);
98 
106 static inline void dio_set_altfunc_input(dio_tag_t t, int alt_func,
107  enum dio_pull pull);
108 
114 static inline void dio_set_analog(dio_tag_t t);
115 
123 static inline void dio_set_output(dio_tag_t t, bool open_collector,
124  enum dio_drive_strength strength, bool first_value);
125 
130 static inline void dio_toggle(dio_tag_t t);
131 
136 static inline void dio_high(dio_tag_t t);
137 
142 static inline void dio_low(dio_tag_t t);
143 
149 static inline void dio_write(dio_tag_t t, bool high);
150 
156 static inline void dio_set_input(dio_tag_t t, enum dio_pull pull);
157 
163 static inline bool dio_read(dio_tag_t t);
164 
165 /* Implementation crud below here */
166 
167 #define DIO_BASE ( (uintptr_t) GPIOA )
168 
169 #define DIO_PORT_OFFSET(port) (((uintptr_t) (port)) - DIO_BASE)
170 
171 #define DIO_MAKE_TAG(port, pin) ((uintptr_t) ((DIO_PORT_OFFSET(port) << 16) | ((uint16_t) (pin))))
172 
173 #define GPIOA_DIO(pin_num) DIO_MAKE_TAG(GPIOA, 1<<(pin_num))
174 #define GPIOB_DIO(pin_num) DIO_MAKE_TAG(GPIOB, 1<<(pin_num))
175 #define GPIOC_DIO(pin_num) DIO_MAKE_TAG(GPIOC, 1<<(pin_num))
176 #define GPIOD_DIO(pin_num) DIO_MAKE_TAG(GPIOD, 1<<(pin_num))
177 #define GPIOE_DIO(pin_num) DIO_MAKE_TAG(GPIOE, 1<<(pin_num))
178 #define GPIOF_DIO(pin_num) DIO_MAKE_TAG(GPIOF, 1<<(pin_num))
179 
180 #define GET_DIO_PORT(dio) ( (GPIO_TypeDef *) (((dio) >> 16) + DIO_BASE) )
181 
182 #define GET_DIO_PIN(dio) ((dio) & 0xffff)
183 
184 #define _DIO_PRELUDE_RET(s) \
185  if (t == DIO_NULL) { return (s); } \
186  GPIO_TypeDef * gp = GET_DIO_PORT(t); \
187  uint16_t pin = GET_DIO_PIN(t);
188 
189 #define _DIO_PRELUDE \
190  if (t == DIO_NULL) { return; } \
191  GPIO_TypeDef * gp = GET_DIO_PORT(t); \
192  uint16_t pin = GET_DIO_PIN(t);
193 
194 static inline void dio_high(dio_tag_t t)
195 {
196  _DIO_PRELUDE;
197 
198 #ifdef STM32F4XX
199  gp->BSRRL = pin;
200 #else
201  gp->BSRR = pin;
202 #endif
203 }
204 
205 static inline void dio_low(dio_tag_t t)
206 {
207  _DIO_PRELUDE;
208 
209 #ifdef STM32F4XX
210  gp->BSRRH = pin;
211 #else
212  gp->BSRR = pin << 16;
213 #endif
214 }
215 
216 static inline void dio_write(dio_tag_t t, bool high)
217 {
218  if (high) {
219  dio_high(t);
220  } else {
221  dio_low(t);
222  }
223 }
224 
225 static inline void dio_toggle(dio_tag_t t)
226 {
227  _DIO_PRELUDE;
228 
229  dio_write(t, ! (gp->ODR & pin) );
230 }
231 
232 /* Some of the bitfields here are two bits wide; some are 1 bit wide */
233 
234 // Uses regs twice, naughty.
235 #define DIO_SETREGS_FOURWIDE(reglow, reghigh, idx, val) \
236  do { \
237  int __pos = (idx); \
238  if (__pos >= 8) { \
239  __pos -= 8; \
240  (reghigh) = ((reghigh) & ~(15 << (__pos * 4))) | ( (val) << (__pos * 4)); \
241  } else { \
242  (reglow) = ((reglow) & ~(15 << (__pos * 4))) | ( (val) << (__pos * 4)); \
243  } \
244  } while (0)
245 
246 #define DIO_SETREG_TWOWIDE(reg, idx, val) \
247  do { \
248  int __pos = (idx); \
249  (reg) = ((reg) & ~(3 << (__pos * 2))) | ( (val) << (__pos * 2)); \
250  } while (0)
251 
252 #define DIO_SETREG_ONEWIDE(reg, idx, val) \
253  do { \
254  int __pos = (idx); \
255  (reg) = ((reg) & ~(1 << (__pos))) | ( (val) << __pos); \
256  } while (0)
257 
258 /* Note all of these configuration things have atomicity problems---
259  * like underlying stdperiph. Really all of these read-modify-write things
260  * would need to disable interrupts to be safe.
261  */
262 #if defined(STM32F10X_MD)
263 static inline void _dio_remap(int alt_func)
264 {
265  if (alt_func) {
266  GPIO_PinRemapConfig(alt_func, ENABLE);
267  }
268 }
269 #endif
270 
271 static inline void dio_set_altfunc_output(dio_tag_t t, int alt_func,
272  bool open_collector, enum dio_drive_strength strength)
273 {
274  _DIO_PRELUDE;
275 
276  uint8_t pos = __builtin_ctz(pin);
277 
278 #if defined(STM32F10X_MD)
279  _dio_remap(alt_func);
280 
281  /* MODE .. CNF = 1cSS
282  * where S is strength and c is true for open collector
283  */
284  uint8_t val = 8 | strength;
285 
286  if (open_collector) {
287  val |= 4;
288  }
289 
290  DIO_SETREGS_FOURWIDE(gp->CRL, gp->CRH, pos, val);
291 #else
292  dio_set_output(t, open_collector, strength, false);
293 
294  DIO_SETREGS_FOURWIDE(gp->AFR[0], gp->AFR[1], pos, alt_func);
295  DIO_SETREG_TWOWIDE(gp->MODER, pos, DIO_PIN_ALTFUNC);
296 #endif
297 }
298 
299 static inline void dio_set_altfunc_input(dio_tag_t t, int alt_func,
300  enum dio_pull pull)
301 {
302 #if defined(STM32F10X_MD)
303  _dio_remap(alt_func);
304 #endif
305 
306  dio_set_input(t, pull);
307 
308  /* F1 altfunc inputs are just normal inputs */
309 
310 #if !defined(STM32F10X_MD)
311  _DIO_PRELUDE;
312 
313  uint8_t pos = __builtin_ctz(pin);
314 
315  DIO_SETREGS_FOURWIDE(gp->AFR[0], gp->AFR[1], pos, alt_func);
316  DIO_SETREG_TWOWIDE(gp->MODER, pos, DIO_PIN_ALTFUNC);
317 #endif
318 }
319 
320 static inline void dio_set_analog(dio_tag_t t)
321 {
322  _DIO_PRELUDE;
323  uint8_t pos = __builtin_ctz(pin);
324 #if defined(STM32F10X_MD)
325  /* 0000 Analog input */
326  DIO_SETREGS_FOURWIDE(gp->CRL, gp->CRH, pos, 0);
327 #else
328  DIO_SETREG_TWOWIDE(gp->PUPDR, pos, DIO_PULL_NONE);
329 
330  DIO_SETREG_TWOWIDE(gp->MODER, pos, DIO_PIN_ANALOG);
331 #endif
332 }
333 
334 static inline void dio_set_output(dio_tag_t t, bool open_collector,
335  enum dio_drive_strength strength, bool first_value)
336 {
337  _DIO_PRELUDE;
338 
339  uint8_t pos = __builtin_ctz(pin);
340 
341  /* Set output data register to first alue */
342  dio_write(t, first_value);
343 #if defined(STM32F10X_MD)
344  /* MODE .. CNF = 0cSS
345  * where S is strength and c is true for open collector
346  */
347  uint8_t val = strength;
348 
349  if (open_collector) {
350  val |= 4;
351  }
352 
353  DIO_SETREGS_FOURWIDE(gp->CRL, gp->CRH, pos, val);
354 #else
355 
356  if (open_collector) {
357  /* Request pullup */
358  DIO_SETREG_TWOWIDE(gp->PUPDR, pos, DIO_PULL_UP);
359  /* Set as open drain output type */
360  DIO_SETREG_ONEWIDE(gp->OTYPER, pos, 1);
361  } else {
362  /* Request no pullup / pulldown */
363  DIO_SETREG_TWOWIDE(gp->PUPDR, pos, DIO_PULL_NONE);
364 
365  /* Set as normal output */
366  DIO_SETREG_ONEWIDE(gp->OTYPER, pos, 0);
367  }
368 
369  DIO_SETREG_TWOWIDE(gp->OSPEEDR, pos, strength);
370 
371  /* Set appropriate position to output */
372  DIO_SETREG_TWOWIDE(gp->MODER, pos, DIO_PIN_OUTPUT);
373 #endif
374 }
375 
376 static inline void dio_set_input(dio_tag_t t, enum dio_pull pull)
377 {
378  _DIO_PRELUDE;
379 
380  uint8_t pos = __builtin_ctz(pin);
381 
382 #if defined(STM32F10X_MD)
383  uint8_t val;
384 
385  if (pull == DIO_PULL_NONE) {
386  val = 4; /* 0100 input floating */
387  } else {
388  val = 8; /* 1000 input pulled */
389  }
390 
391  DIO_SETREGS_FOURWIDE(gp->CRL, gp->CRH, pos, val);
392 
393  if (pull == DIO_PULL_UP) {
394  dio_high(t);
395  } else if (pull == DIO_PULL_DOWN) {
396  dio_low(t);
397  }
398 #else
399  /* Set caller-specified pullup/pulldown */
400  DIO_SETREG_TWOWIDE(gp->PUPDR, pos, pull);
401 
402  /* Set appropriate position to input */
403  DIO_SETREG_TWOWIDE(gp->MODER, pos, DIO_PIN_INPUT);
404 #endif
405 }
406 
407 static inline bool dio_read(dio_tag_t t)
408 {
409  _DIO_PRELUDE_RET(false);
410 
411  return !! (gp->IDR & pin);
412 }
413 
414 #endif /* _PIOS_DIO_H */
415 
static void dio_set_altfunc_output(dio_tag_t t, int alt_func, bool open_collector, enum dio_drive_strength strength)
Configures a GPIO as alternate function output.
Definition: pios_dio.h:271
static void dio_low(dio_tag_t t)
Sets an output GPIO low.
Definition: pios_dio.h:205
#define DIO_SETREGS_FOURWIDE(reglow, reghigh, idx, val)
Definition: pios_dio.h:235
static void dio_set_altfunc_input(dio_tag_t t, int alt_func, enum dio_pull pull)
Configures a GPIO as alternate function input.
Definition: pios_dio.h:299
static void dio_set_input(dio_tag_t t, enum dio_pull pull)
Configures a GPIO as an input.
Definition: pios_dio.h:376
static void dio_write(dio_tag_t t, bool high)
Sets an output GPIO to a chosen logical level.
Definition: pios_dio.h:216
struct _msp_pid_item pos
Definition: msp_messages.h:100
static void dio_high(dio_tag_t t)
Sets an output GPIO high.
Definition: pios_dio.h:194
#define DIO_SETREG_TWOWIDE(reg, idx, val)
Definition: pios_dio.h:246
static void dio_set_analog(dio_tag_t t)
Configures a GPIO as analog. Disables pullups/pulldowns, etc.
Definition: pios_dio.h:320
static void dio_set_output(dio_tag_t t, bool open_collector, enum dio_drive_strength strength, bool first_value)
Configures a GPIO as an output.
Definition: pios_dio.h:334
#define DIO_SETREG_ONEWIDE(reg, idx, val)
Definition: pios_dio.h:252
dio_pin_function
Definition: pios_dio.h:71
#define _DIO_PRELUDE
Definition: pios_dio.h:189
void * dio_tag_t
Definition: pios_dio.h:12
static void dio_toggle(dio_tag_t t)
Toggles an output GPIO to the opposite level.
Definition: pios_dio.h:225
static bool dio_read(dio_tag_t t)
Reads a GPIO logical value.
Definition: pios_dio.h:407
dio_pull
Definition: pios_dio.h:78
#define _DIO_PRELUDE_RET(s)
Definition: pios_dio.h:184