librfn
An ad-hoc utility library
console_cmd_gpio.c
Go to the documentation of this file.
1 /*
2  * Part of librfn (a general utility library from redfelineninja.org.uk)
3  *
4  * Copyright (C) 2014 Daniel Thompson <daniel@redfelineninja.org.uk>
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <librfn/console.h>
21 
22 #include <string.h>
23 #include <libopencm3/stm32/gpio.h>
24 #include <libopencm3/stm32/rcc.h>
25 #include <librfn/time.h>
26 #include <librfn/util.h>
27 
28 enum {
29  on = 0,
30  off,
35  hiz,
40 };
41 
42 static int parse_args(console_t *c, console_gpio_t *gpio)
43 {
44  int action;
45 
46  /* argument parsing */
47  if (0 == strcmp(c->argv[1], "on"))
48  action = on;
49  else if (0 == strcmp(c->argv[1], "off"))
50  action = off;
51  else if (0 == strcmp(c->argv[1], "toggle"))
52  action = toggle;
53  else if (0 == strcmp(c->argv[1], "pulse"))
54  action = pulse;
55  else if (0 == strcmp(c->argv[1], "read"))
56  action = read_state;
57  else if (0 == strcmp(c->argv[1], "float"))
58  action = hiz;
59  else if (0 == strcmp(c->argv[1], "pullupdown"))
60  action = pullup;
61  else if (0 == strcmp(c->argv[1], "opendrain"))
62  action = opendrain;
63  else if (0 == strcmp(c->argv[1], "pushpull"))
64  action = pushpull;
65  else if (0 == strcmp(c->argv[1], "detect"))
66  action = detect;
67  else
68  action = usage;
69 
70  /* update any flags */
71  if ((action <= off) && (gpio->flags & console_gpio_active_low))
72  action = !action;
73  if ((action > usage) && !(gpio->flags & console_gpio_explore))
74  action = usage;
75 
76  return action;
77 }
78 
79 /*
80  * Returns true is there is something connected to the pin (including
81  * a large capacitance) that can defeat the weak pull up/downs.
82  */
83 #ifdef STM32F1
84 static bool gpio_is_connected(uint32_t gpioport, uint16_t gpio)
85 {
86  int i;
87  uint32_t readings = 0;
88 
89  gpio_set_mode(gpioport, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN,
90  gpio);
91  gpio_set(gpioport, gpio);
92  for (i = 0; i < 8; i++)
93  readings = (readings << 1) | !gpio_get(gpioport, gpio);
94  gpio_clear(gpioport, gpio);
95  for (i = 0; i < 8; i++)
96  readings = (readings << 1) | !!gpio_get(gpioport, gpio);
97  gpio_set_mode(gpioport, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, gpio);
98 
99  return readings;
100 }
101 #endif
102 
103 /* This section is a rather nasty workaround until I figure out how to get
104  * open drain pins to work correctly on STM32F4.
105  */
106 #ifdef STM32F4
107 static void do_opendrain_toggle(uintptr_t port, uint32_t pin)
108 {
109  for (int i=0; i<32; i++) {
110  if (pin & (1 << i)) {
111  if (GPIO_MODER(port) & GPIO_MODE_MASK(i))
112  gpio_mode_setup(port, GPIO_MODE_INPUT,
113  GPIO_PUPD_NONE, 1 << i);
114  else
115  gpio_mode_setup(port, GPIO_MODE_OUTPUT,
116  GPIO_PUPD_NONE, 1 << i);
117  }
118  }
119 }
120 
121 static pt_state_t do_opendrain_cmd(console_t *c)
122 {
123  console_gpio_t *gpio = containerof(c->cmd, console_gpio_t, cmd);
124  uint32_t *t = &c->scratch.u32[0];
125 
126  PT_BEGIN(&c->pt);
127 
128  int action = parse_args(c, gpio);
129  if (action == on) {
130  gpio_mode_setup(gpio->port, GPIO_MODE_INPUT, GPIO_PUPD_NONE,
131  gpio->pin);
132  } else if (action == off) {
133  gpio_mode_setup(gpio->port, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,
134  gpio->pin);
135  } else if (action == toggle) {
136  do_opendrain_toggle(gpio->port, gpio->pin);
137  } else if (action == pulse) {
138  do_opendrain_toggle(gpio->port, gpio->pin);
139  *t = time_now() + 1000000;
141  do_opendrain_toggle(gpio->port, gpio->pin);
142  } else {
143  fprintf(c->out, "Usage: %s on|off|toggle|pulse\n",
144  c->cmd->name);
145  }
146 
147  PT_END();
148 }
149 #endif
150 
152 {
153  console_gpio_t *gpio = containerof(c->cmd, console_gpio_t, cmd);
154  uint32_t *t = &c->scratch.u32[0];
155 
156 #ifdef STM32F4
157  if (gpio->flags & console_gpio_open_drain)
158  return do_opendrain_cmd(c);
159 #endif
160 
161  PT_BEGIN(&c->pt);
162 
163  int action = parse_args(c, gpio);
164  if (action == on) {
165  gpio_set(gpio->port, gpio->pin);
166  } else if (action == off) {
167  gpio_clear(gpio->port, gpio->pin);
168  } else if (action == toggle) {
169  gpio_toggle(gpio->port, gpio->pin);
170  } else if (action == pulse) {
171  gpio_toggle(gpio->port, gpio->pin);
172  *t = time_now() + 1000000;
174  gpio_toggle(gpio->port, gpio->pin);
175  } else if (action == read_state) {
176  fprintf(c->out, "%s %d\n", gpio->cmd.name,
177  (int) gpio_get(gpio->port, gpio->pin));
178 #ifdef STM32F1
179  } else if (action == hiz) {
180  gpio_set_mode(gpio->port, GPIO_MODE_INPUT,
181  GPIO_CNF_INPUT_FLOAT, gpio->pin);
182  } else if (action == pullup) {
183  gpio_set_mode(gpio->port, GPIO_MODE_INPUT,
184  GPIO_CNF_INPUT_PULL_UPDOWN, gpio->pin);
185  } else if (action == opendrain) {
186  gpio_set_mode(gpio->port, GPIO_MODE_OUTPUT_2_MHZ,
187  GPIO_CNF_OUTPUT_OPENDRAIN, gpio->pin);
188  } else if (action == pushpull) {
189  gpio_set_mode(gpio->port, GPIO_MODE_OUTPUT_2_MHZ,
190  GPIO_CNF_OUTPUT_PUSHPULL, gpio->pin);
191  } else if (action == detect) {
192  fprintf(c->out, "%s is %s\n", gpio->cmd.name,
193  gpio_is_connected(gpio->port, gpio->pin) ? "connected"
194  : "floating");
195  } else {
196  fprintf(c->out, "Usage: %s "
197  "on|off|toggle|pulse|hiz|pullup|opendrain|"
198  "pushpull|detect\n",
199  c->cmd->name);
200  }
201 #else
202  } else {
203  fprintf(c->out, "Usage: %s on|off|toggle|pulse\n",
204  c->cmd->name);
205  }
206 #endif
207 
208  PT_END();
209 }
210 
212 {
213  switch (gpio->port) {
214 #ifdef GPIOA
215  case GPIOA:
216  rcc_periph_clock_enable(RCC_GPIOA);
217  break;
218 #endif
219 #ifdef GPIOB
220  case GPIOB:
221  rcc_periph_clock_enable(RCC_GPIOB);
222  break;
223 #endif
224 #ifdef GPIOC
225  case GPIOC:
226  rcc_periph_clock_enable(RCC_GPIOC);
227  break;
228 #endif
229 #ifdef GPIOD
230  case GPIOD:
231  rcc_periph_clock_enable(RCC_GPIOD);
232  break;
233 #endif
234 #ifdef GPIOE
235  case GPIOE:
236  rcc_periph_clock_enable(RCC_GPIOE);
237  break;
238 #endif
239 #ifdef GPIOF
240  case GPIOF:
241  rcc_periph_clock_enable(RCC_GPIOF);
242  break;
243 #endif
244  }
245 
246  if (!!(gpio->flags & console_gpio_active_low) ^
247  !!(gpio->flags & console_gpio_default_on))
248  gpio_set(gpio->port, gpio->pin);
249  else
250  gpio_clear(gpio->port, gpio->pin);
251 
252 #if defined(STM32F1)
253  int mode = GPIO_MODE_OUTPUT_2_MHZ;
254  int cnf = GPIO_CNF_OUTPUT_PUSHPULL;
255  if (gpio->flags & console_gpio_open_drain)
256  cnf = GPIO_CNF_OUTPUT_OPENDRAIN;
257  if (gpio->flags & console_gpio_explore) {
258  mode = GPIO_MODE_INPUT;
259  cnf = GPIO_CNF_INPUT_FLOAT;
260  }
261  gpio_set_mode(gpio->port, mode, cnf, gpio->pin);
262 #elif defined(STM32F4)
263  int mode = GPIO_MODE_OUTPUT;
264  if (gpio->flags & console_gpio_open_drain)
265  mode = GPIO_MODE_INPUT;
266  gpio_mode_setup(gpio->port, mode, GPIO_PUPD_NONE, gpio->pin);
267 #else
268 #error Unsupported part
269 #endif
270 
271  return console_register(&gpio->cmd);
272 }
273 
#define containerof(ptr, type, member)
Definition: util.h:35
struct charlie c
Console descriptor.
Definition: console.h:66
const char * name
Definition: console.h:48
uint32_t u32[SCRATCH_SIZE/4]
Definition: console.h:85
#define PT_WAIT_UNTIL(c)
Definition: protothreads.h:116
#define PT_BEGIN(pt)
Definition: protothreads.h:93
#define PT_END()
Definition: protothreads.h:100
const console_cmd_t * cmd
Definition: console.h:93
int console_gpio_register(const console_gpio_t *gpio)
Register a new GPIO command.
union console::@0 scratch
FILE * out
Definition: console.h:69
console_cmd_t cmd
Definition: console.h:252
char * argv[4]
Definition: console.h:91
int console_register(const console_cmd_t *cmd)
Register a new command.
Definition: console.c:151
uint32_t pin
Definition: console.h:254
uint32_t time_now(void)
pt_state_t
Definition: protothreads.h:80
pt_t pt
Definition: console.h:94
pt_state_t console_gpio_do_cmd(console_t *c)
uintptr_t port
Definition: console.h:253
bool fibre_timeout(uint32_t duetime)
Definition: fibre.c:208
GPIO command descriptor.
Definition: console.h:251