This tutorial is dedicated to the implementation of few BSP functions. In the world of embedded systems, BSP stands for “Board Support Package”. In simple words, it is a collection of functions to address on-board components such as I/Os, displays, sensors, communication interfaces…
A collection of functions that simplifies the software interface with a given peripheral is also called a library, or a driver.
Nucleo boards are rather poor in terms of accessories. Basically, you have a user LED, a user button, and a serial interface through the ST-Link dongle.
LEDs and Buttons are directly interfaced with MCU pins in output or input modes. These are configured by means of GPIO (General Purpose Input Output) peripherals.
Start Eclipse and open 'my_project' project. At this step, 'my_project' is a clean starting project you've created in the 1.6 tutorial by cloning the template project. 'my_project' project will be used all long subsequent tutorials.
![]() |
![]() ![]() |
Create a new source file bsp.c under bsp/src folder, and a new header file bsp.h under bsp/inc folder:
A look at the board schematics tells us that the green user LED is connected to the pin PA5 of the MCU. Given that LED cathode goes to ground, the LED is "ON" when PA5 is at its high logic voltage.
Let us take a moment to think about what functions we would like to have in order to play with the LED:
These is no need for any argument (there’s only one LED), and these functions may return nothing. Note that it would be possible to use a single function that sets the LED state using an argument (ON/OFF/Toggle).
We know that a MCU pin needs to be configured to serve as an output. If we include the pin configuration into the previous functions, it will be done every time we want to change the LED state. This is a waste of both CPU time and power consumption as configuration does not change once it is done. Therefore, let us write a separate function to address pin configuration, that will be called only once at the beginning of the main code.
Open edit bsp.h and write the following function prototypes:
/*
* bsp.h
*
* Created on: 5 août 2017
* Author: Laurent
*/
#ifndef BSP_INC_BSP_H_
#define BSP_INC_BSP_H_
#include "stm32f0xx.h"
/*
* LED driver functions
*/
void BSP_LED_Init (void);
void BSP_LED_On (void);
void BSP_LED_Off (void);
void BSP_LED_Toggle (void);
#endif /* BSP_INC_BSP_H_ */
Note that when creating new headers, Eclipse automatically protects code from recursive inclusion:
#ifndef HEADERNAME_H_
#define HEADERNAME_H_
...
#endif
It is strongly advised to keep it…
Recursive inclusion corresponds to the situation below, that would produce an infinite inclusion loop during the build preprocess if not under the protection of the above directives:
|
|
Open bsp.c for edit and start the implementation of functions. Adopt a clear strategy in the function and variable naming. That’s VERY important when code growth.
In the following, the function belongs to the BSP, concerns the LED, and its purpose is the initialization of the MCU pin. Let’s name the function BSP_LED_Init():
/*
* bsp.c
*
* Created on: 5 août 2017
* Author: Laurent
*/
#include "bsp.h"
/*
* BSP_LED_Init()
* Initialize LED pin (PA5) as a High-Speed Push-Pull output
* Set LED initial state to OFF
*/
void BSP_LED_Init()
{
// Enable GPIOA clock
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
// Configure PA5 as output
GPIOA->MODER &= ~GPIO_MODER_MODER5_Msk;
GPIOA->MODER |= (0x01 <<GPIO_MODER_MODER5_Pos);
// Configure PA5 as Push-Pull output
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_5;
// Configure PA5 as High-Speed Output
GPIOA->OSPEEDR &= ~GPIO_OSPEEDR_OSPEEDR5_Msk;
GPIOA->OSPEEDR |= (0x03 <<GPIO_OSPEEDR_OSPEEDR5_Pos);
// Disable PA5 Pull-up/Pull-down
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5_Msk;
// Set Initial State OFF
GPIOA->BSRR |= GPIO_BSRR_BR_5;
}
You must refer to the reference manual for a complete description of RCC AHBENR register, and GPIO MODER, OTYPER, OSPEEDR, PUPDR, BSRR registers.
Next comes the three controlling functions:
/*
* BSP_LED_On()
* Turn ON LED on PA5
*/
void BSP_LED_On()
{
GPIOA->BSRR = GPIO_BSRR_BS_5;
}
/*
* BSP_LED_Off()
* Turn OFF LED on PA5
*/
void BSP_LED_Off()
{
GPIOA->BSRR = GPIO_BSRR_BR_5;
}
/*
* BSP_LED_Toggle()
* Toggle LED on PA5
*/
void BSP_LED_Toggle()
{
GPIOA->ODR ^= GPIO_ODR_5;
}
That’s it. You’ve written a LED driver. Not too hard?
Test the LED functions in the main code. The example below must be used with the debugger stepping mode, otherwise the state change is too fast to be seen (unless you probe PA5 with an oscilloscope).
/*
* main.c
*
* Created on: 5 août 2017
* Author: Laurent
*/
#include "stm32f0xx.h"
#include "bsp.h"
// Static functions
static void SystemClock_Config(void);
// Main program
void main()
{
// Configure System Clock
SystemClock_Config();
// Initialize LED pin
BSP_LED_Init();
// Turn LED On
BSP_LED_On();
// Turn LED Off
BSP_LED_Off();
while(1)
{
// Toggle LED state
BSP_LED_Toggle();
}
}
...
![]() |
![]() ![]() |
Again, we start with the board schematics. The user button is a switch that connects PC13 pin to ground when pushed down. Otherwise, PC13 pin is held at high logic level by means of the pull-up resistor R30.
In order to interface the push-button, we will write two functions:
You can add those functions prototype in bsp.h, below LED functions.
/*
* Push-Button driver functions
*/
void BSP_PB_Init (void);
uint8_t BSP_PB_GetState (void);
Edit the functions implementation in bsp.c:
/*
* BSP_PB_Init()
* Initialize Push-Button pin (PC13) as input without Pull-up/Pull-down
*/
void BSP_PB_Init()
{
// Enable GPIOC clock
RCC->AHBENR |= RCC_AHBENR_GPIOCEN;
// Configure PC13 as input
GPIOC->MODER &= ~GPIO_MODER_MODER13_Msk;
GPIOC->MODER |= (0x00 <<GPIO_MODER_MODER13_Pos);
// Disable PC13 Pull-up/Pull-down
GPIOC->PUPDR &= ~GPIO_PUPDR_PUPDR13_Msk;
}
/*
* BSP_PB_GetState()
* Returns the state of the button (0=released, 1=pressed)
*/
uint8_t BSP_PB_GetState()
{
uint8_t state;
if ((GPIOC->IDR & GPIO_IDR_13) == GPIO_IDR_13)
{
state = 0;
}
else
{
state = 1;
}
return state;
}
Then, test your new functions in main.c:
/*
* main.c
*
* Created on: 5 août 2017
* Author: Laurent
*/
#include "stm32f0xx.h"
#include "bsp.h"
// Static functions
static void SystemClock_Config(void);
// Main program
void main()
{
// Configure System Clock
SystemClock_Config();
// Initialize LED pin
BSP_LED_Init();
// Initialize User-Button pin
BSP_PB_Init();
// Turn LED On
BSP_LED_On();
// Turn LED Off
BSP_LED_Off();
while(1)
{
// Turn LED On if User-Button is pushed down
if (BSP_PB_GetState() == 1)
{
BSP_LED_On();
}
// Otherwise turn LED Off
else
{
BSP_LED_Off();
}
}
}
The LED is "ON" only when you press the user-button.
![]() |
![]() ![]() |
In this tutorial, we have written simple drivers for both LED and user-button. Associated functions manipulate GPIOs with both input and output configurations.