STM32 - GPIO, Delay and Debugger
===
###### tags: `firmware_hardware` `electrical_system` `NTURT`
#### Author: @andre-liang

### Preface
General-purpose input/output (GPIO) is the easiest way for a microcontroller to communicate with outside world using digital signal.
### Create a New Project
Open up STM32CubeIDE, click on File -> New -> STM32 Project. On the target selection screen, type in **STM32F103C8T6** as commercial part number.

Then choose a project name.

Then you should see the project window.

### Configure Pins
In order for the GPIO functionality to work properly, we must tell the microcontroller we want each pin to be a input pin or a output pin, also the input/output mode.
There are two output mode and three input mode.
#### Output Mode
* Output Push-Pull
* Output Open-Drain

As the name implies, the push-pull mode is capable of driving two output levels: pull to ground and push to power supply voltage. It is implemented with a pair of switch. This configuration is most commonly used in interfaces that have unidirectional lines.
While in open-drain mode, the pin can drive it only to ground. The other possible state is high impedance (Hi-Z), which means the voltage depends on external voltage. This configuration most commonly used in communication interfaces where multiple devices are connected on the same line.
We usually use push-pull mode as default.
Further reading: [link](https://open4tech.com/open-drain-output-vs-push-pull-output/#:~:text=Push%2Dpull%20output%20is%20best,%2C%20One%2DWire%20etc.)
#### Input Mode
* None
* Pull-Up
* Pull-Down

The pull-up/pull-down resistor is used to prevent reading floating value when connected to open-circuit. In pull-up mode, the resistor keeps the input at HIGH, while in pull-down mode the resistor keeps the input at LOW.
To configure each pin to specific pin mode, open the `<project-name>.ioc` in the root of the project folder, right-click on the target pin and toggle the pin mode.

Click on Pinout & Configuration -> System Core -> GPIO to switch between input/output mode or play around with other GPIO features.

*Note: All the formentioned settings could theoretically be set by manually changing the value of different registers, but we usually let the IDE to do that tedious job for us*
**Save the `<project-name>.ioc` and let the code generation tool to apply the settings for you.**
### Code Structure
When you are learning C/C++, the first program you write probably looks like this:
```cpp
#include <iostream>
int main()
{
std::cout<<"Hello World!"<<std::endl;
}
```
The `main()` function is the entry point of the program, i.e. the program execution starts from that function call.
In a STM32CubeIDE project, the entry point is the `<project-name>/Core/Src/main.c`.
```cpp!
int main(void)
{
/* Settings for HAL library */
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
/* Only executed once */
while (1)
{
/* Executed indefinitely*/
}
}
```
You can modify the file to make the microcontroller to do what you want.
### Writing/Reading Digital Signal
#### Write Signal
To alter the digital signal output of certain pin, we use the following function:
```c
HAL_GPIO_WritePin(GPIOx, GPIO_Pin, PinState);
```

A pin is defined as `P<GPIOx><GPIO_Pin>`, and PinState could be either `GPIO_PIN_SET` for output HIGH-Voltage or `GPIO_PIN_RESET` for LOW-Voltage.
For example:
```cpp!
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
```
Means to output HIGH at pin PA0. You can type `<space>+<control>` to activate auto-complete.
#### Read Signal
To read the digital signal of certain pin, we use:
```c
var = HAL_GPIO_ReadPin(GPIOx, GPIO_Pin);
```
### Debugger
First declare a variable outside `main()` function scope, then read the pin value to that variable.
```cpp!
int buttonState;
int main(void){
// HAL init functions ommited;
while(1){
buttonState = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
}
}
```
For convenience, I use a button module to generate a input signal. When pressed down, the OUT pin will output a HIGH signal.Connect the OUT pin to PA0.

Since STM-32 don't have a screen, you can't output variables to standard output like we normally do in a console application. But we can use a dubugger to see the value of variables directly.
To use the debugger, click `Debug <project-name> Debug` (with bug icon) to start debugging.

Then click the search icon on the top-right corner, search for Live Expressions and enter the variable name you want to observe.

You should see the value changes as you press down the button.
### Delay
We can use `HAL_Delay(delayTime);` to suspends (waits) execution of the microcontroller for a given number of micro-seconds.
```cpp!
while (1){
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
HAL_Delay(200); // Stop for 0.2 second
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_Delay(200);
}
```
Then connect a LED to pin A0, remember to attach a resistor to limit the current flow.

Then you should see the LED blinks every 0.2 second.
