Skip to content

Commit

Permalink
gpio: stm32: Use atomic set/reset in stm32_gpio_set()
Browse files Browse the repository at this point in the history
The current implementation of stm32_gpio_set() uses the GPIO output data
register to change the state of individual GPIOs. The generated
assembler needs at least 3 instructions: load / modify / store.

This opens a small race window, for example if a thread and an
interrupt both try to change the state of the same GPIO bank.

Use the GPIO bit set/reset register to perform the atomic change without
locking.

This also has the benefit of a more optimised implementation, which can
be useful for GPIO-intensive work. Compare the new version:

08000c98 <stm32_gpio_set>:
 8000c98:       f001 010f       and.w   r1, r1, #15
 8000c9c:       2301            movs    r3, #1
 8000c9e:       b902            cbnz    r2, 8000ca2 <stm32_gpio_set+0xa>
 8000ca0:       3110            adds    r1, #16
 8000ca2:       408b            lsls    r3, r1
 8000ca4:       6183            str     r3, [r0, #24]
 8000ca6:       2000            movs    r0, #0
 8000ca8:       4770            bx      lr

and the old one:

08000c98 <stm32_gpio_set>:
 8000c98:       2301            movs    r3, #1
 8000c9a:       f001 010f       and.w   r1, r1, #15
 8000c9e:       fa03 f101       lsl.w   r1, r3, r1
 8000ca2:       6943            ldr     r3, [r0, #20]
 8000ca4:       b10a            cbz     r2, 8000caa <stm32_gpio_set+0x12>
 8000ca6:       4319            orrs    r1, r3
 8000ca8:       e001            b.n     8000cae <stm32_gpio_set+0x16>
 8000caa:       ea23 0101       bic.w   r1, r3, r1
 8000cae:       6141            str     r1, [r0, #20]
 8000cb0:       2000            movs    r0, #0
 8000cb2:       4770            bx      lr

Change-Id: Ie5800d1c345016028d1b9a099f5d74cac35f592a
Signed-off-by: Florian Vaussard <florian.vaussard@heig-vd.ch>
  • Loading branch information
Florian Vaussard authored and galak committed Mar 21, 2017
1 parent ee830d7 commit 20e5b7f
Showing 1 changed file with 4 additions and 4 deletions.
8 changes: 4 additions & 4 deletions arch/arm/soc/st_stm32/stm32f4/soc_gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,12 @@ int stm32_gpio_set(uint32_t *base, int pin, int value)
{
struct stm32f4x_gpio *gpio = (struct stm32f4x_gpio *)base;

int pval = 1 << (pin & 0xf);

if (value) {
gpio->odr |= pval;
/* atomic set */
gpio->bsr = (1 << (pin & 0x0f));
} else {
gpio->odr &= ~pval;
/* atomic reset */
gpio->bsr = (1 << ((pin & 0x0f) + 0x10));
}

return 0;
Expand Down

0 comments on commit 20e5b7f

Please sign in to comment.