2
\$\begingroup\$

Hi I'm currently attempting to write a simple program using the STM32 Nucleo development board, based around the STM32F334R8. The application sets up the GPIO ports A and C and reads the state of the button. If the button is pressed, it turns on the LED. If not, it turns it off.

From ST's documentation (STM Nucleo 64) I've verified that the button is wired to Pin C13 and LED2 is wired to Pin A5.

From the datasheet, I've been reading through the registers for the GPIO (Long STM32F334 Datasheet) and see there are three that seem to be related to the output; ODR, BSRR, and BRR.

When implementing the application mentioned above, my first thought was to write the GPIO pin state for the output LED using ODR, like so:

SET_BIT(GPIOA->ODR, GPIO_ODR_5);
CLEAR_BIT(GPIOA->ODR, GPIO_ODR_5);

This did not appear to work. My button presses were detected, as I could verify this in the debugger by seeing it follow different paths. Here's my setup code for the GPIO:

// set one to input
CLEAR_BIT(GPIOC->MODER, GPIO_MODER_MODER13_0);
CLEAR_BIT(GPIOC->MODER, GPIO_MODER_MODER13_1);
// set another to output
SET_BIT(GPIOA->MODER, GPIO_MODER_MODER5_0);
CLEAR_BIT(GPIOA->MODER, GPIO_MODER_MODER5_1);
// set output to push-pull
CLEAR_BIT(GPIOA->OTYPER, GPIO_OTYPER_OT_5);
// set input with pull-up
SET_BIT(GPIOC->PUPDR, GPIO_PUPDR_PUPDR13_1);
CLEAR_BIT(GPIOC->PUPDR, GPIO_PUPDR_PUPDR13_0);

// enable GPIOA and GPIOC clock
SET_BIT(RCC->AHBENR, RCC_AHBENR_GPIOAEN);
SET_BIT(RCC->AHBENR, RCC_AHBENR_GPIOCEN);

I also saw a piece of example code that worked on my board that uses the BSRR and BRR bits, like so:

// set output high
SET_BIT(GPIOA->BSRR, GPIO_BSRR_BS_5);
// set output low
SET_BIT(GPIOA->BRR, GPIO_BRR_BR_5);

... But this didn't work.

I'm not sure I understand the difference between the three registers and their functions.

What are the use cases for each? Which one is suited to my application?

\$\endgroup\$
3
\$\begingroup\$

The most obvious problem I see in your code is that you're writing to the GPIO registers before enabling the clocks for the appropriate peripherals.

Peripherals won't respond correctly if their clocks haven't been enabled. Enable all peripheral clocks before you try to do anything with the peripherals.

That all being said: the differences between ODR and BSRR/BRR are minimal. If you only need to change one bit, though, a single write to BSRR (or BRR) is faster, and uses less code space, than a read/modify/write cycle on ODR. However, if you actually do want to set the state of the whole port at once, or if you need to check the current output state, ODR is the way to go.

\$\endgroup\$
  • \$\begingroup\$ You are 100% right, moving the clock setup to the top of that function fixed the problem and the application works! It hadn't occurred to me that the clocks needed to be enabled first as I thought they would only govern the sampling of the pins, not enable the peripheral entirely which. Thanks! \$\endgroup\$ – Shane Snover Oct 24 '17 at 20:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.