Skip to content

Commit 8839ccb

Browse files
committed
cpu/stm32: implement periph_gpio_ll_switch_dir
This implements periph_gpio_ll_switch_dir for STM32 except for STM32F1, which has a different register layout.
1 parent af61cf4 commit 8839ccb

File tree

4 files changed

+75
-0
lines changed

4 files changed

+75
-0
lines changed

cpu/stm32/Makefile.features

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ FEATURES_PROVIDED += periph_uart_nonblocking
2525

2626
ifneq (f1,$(CPU_FAM))
2727
FEATURES_PROVIDED += periph_gpio_ll_open_drain_pull_up
28+
FEATURES_PROVIDED += periph_gpio_ll_switch_dir
2829
endif
2930

3031
ifneq (,$(filter $(CPU_FAM),c0 f0 f1 f3 g0 g4 l0 l1 l4 l5 u5 wb wl))

cpu/stm32/include/gpio_ll_arch.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,31 @@ static inline void gpio_ll_write(gpio_port_t port, uword_t value)
142142
p->ODR = value;
143143
}
144144

145+
#ifdef MODULE_PERIPH_GPIO_LL_SWITCH_DIR
146+
static inline uword_t gpio_ll_prepare_switch_dir(uword_t mask)
147+
{
148+
/* implementation too large to always inline */
149+
extern uword_t gpio_ll_prepare_switch_dir_impl(uword_t mask);
150+
return gpio_ll_prepare_switch_dir_impl(mask);
151+
}
152+
153+
static inline void gpio_ll_switch_dir_output(gpio_port_t port, uword_t pins)
154+
{
155+
GPIO_TypeDef *p = (GPIO_TypeDef *)port;
156+
unsigned irq_state = irq_disable();
157+
p->MODER |= pins;
158+
irq_restore(irq_state);
159+
}
160+
161+
static inline void gpio_ll_switch_dir_input(gpio_port_t port, uword_t pins)
162+
{
163+
GPIO_TypeDef *p = (GPIO_TypeDef *)port;
164+
unsigned irq_state = irq_disable();
165+
p->MODER &= ~pins;
166+
irq_restore(irq_state);
167+
}
168+
#endif
169+
145170
static inline gpio_port_t gpio_get_port(gpio_t pin)
146171
{
147172
return pin & 0xfffffff0LU;

cpu/stm32/include/periph/cpu_gpio_ll.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ extern "C" {
3131
* public view on type */
3232
#ifndef DOXYGEN
3333

34+
#if !defined(CPU_FAM_STM32F1)
35+
/* For the STM32F1 GPIO peripheral, the gpio_ll_switch_dir is not supported */
36+
# define HAVE_GPIO_LL_PREPARE_SWITCH_DIR
37+
#endif
38+
3439
#define HAVE_GPIO_PULL_STRENGTH_T
3540
typedef enum {
3641
GPIO_PULL_WEAKEST = 0,

cpu/stm32/periph/gpio_ll.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,50 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf)
361361
return 0;
362362
}
363363

364+
uword_t gpio_ll_prepare_switch_dir_impl(uword_t mask)
365+
{
366+
/* Mask contains a bitmask containing the pins needed to change
367+
* the direction of. E.g. for pins 0 to 3 it looks like:
368+
*
369+
* 3 2 1 0
370+
* +----+----+----+----+
371+
* | P3 | P2 | P1 | P0 |
372+
* +----+----+----+----+
373+
*
374+
* We need to update the GPIOX->MODER register, which for pins 0 to 3
375+
* looks like this:
376+
*
377+
* 7 6 5 4 3 2 1 0
378+
* +---------+---------+---------+---------+
379+
* | MODE3 | MODE2 | MODE1 | MODE0 |
380+
* +---------+---------+---------+---------+
381+
*
382+
* Where each mode field will have the value `0b00` for input or `0b01`
383+
* for output (the others two values are for alternate function mode and
384+
* analog mode, which are both not relevant here). So, we need a way to
385+
* efficiently set and clear every second bit. Specifically, a bitmask
386+
* that looks like this is our goal:
387+
*
388+
* 7 6 5 4 3 2 1 0
389+
* +----+----+----+----+----+----+----+----+
390+
* | 0 | P3 | 0 | P2 | 0 | P1 | 0 | P0 |
391+
* +----+----+----+----+----+----+----+----+
392+
*
393+
* This is what below bit magic magic does (but for 16 pins instead of
394+
* 4).
395+
*/
396+
uword_t output = mask & 0xFFFF;
397+
output |= output << 8;
398+
output &= 0x00FF00FF;
399+
output |= output << 4;
400+
output &= 0x0F0F0F0F;
401+
output |= output << 2;
402+
output &= 0x33333333;
403+
output |= output << 1;
404+
output &= 0x55555555;
405+
return output;
406+
}
407+
364408
gpio_conf_t gpio_ll_query_conf(gpio_port_t port, uint8_t pin)
365409
{
366410
gpio_conf_t result = { 0 };

0 commit comments

Comments
 (0)