# **Basic IO - GPIO** Original authors: Alex Chan, Leo Wong and Christopher Kwan Further Modified by: William Lam *** ## **Basics** ### **Fundamental Program Structure Example: Do something every 100ms** ```c int main(void) { // Initialize Everything Here, this is like setup() in Arduino HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); //Initialize most GPIOs on board MX_DMA_Init(); //Initialize DMA // the following is like loop() in Arduino also //Run code in an infinite loop: this is like loop() in Arduino while (1) { static uint32_t last_ticks = 0; //This variable keeps its stored value through every iteration //Everything inside this if-statements gets called every 100ms if((HAL_GetTick() - last_ticks) >= 100){ //Write your code here.... // sth .... // bruh.... last_ticks = HAL_GetTick(); } } } ``` * The **`HAL_GetTick`** function is the main thing to use for timing control in software. It counts up by one every millisecond(ms). *** ### **Data Types** In embedded system programming, Data type `int`, `long`, `long long`, `float`, `double` are not suggested to use. Instead, use the followings: | Short form | Full name | Meaning | | :--------: | :----------------- | :----------------------- | | `uint8_t` | unsigned char | unsigned 8 bits integer | | uint16_t | unsigned short | unsigned 16 bits integer | | uint32_t | unsigned long | unsigned 32 bits integer | | uint64_t | unsigned long long | unsigned 64 bits integer | | int8_t | signed char | signed 8 bits integer | | int16_t | signed short | signed 16 bits integer | | int32_t | signed long | signed 32 bits integer | | int64_t | signed long long | signed 64 bits integer | Both full name and short form work. **Note:** * The value of a `signed` number is typically less than half the value of an `unsigned` number because the most significant bit (MSB) in the signed representation is used to indicate the sign of the number. * `float` and `double` should only be used when necessary as floating point calculation normally takes more time. *** ## **What is GPIO?** >A **general-purpose input/output (GPIO)** is an digital signal pin on an integrated circuit or electronic circuit board whose behavior — including whether it acts as an input or output — is controllable by the user at run time. >In short, GPIO is for ***outputting and reading HIGH [1] and LOW [0] values***. (Sometimes we will use GPIO for analogue values but don't worry about that for now) ### **GPIO Configuration** * Every pin on the MCU can be used as GPIO, they are divided into a blocks of 16 pins due to internal structure * Each block is named by letters: `GPIOA`, `GPIOB`, `GPIOC`... * Each pin within the block is numbered from 0: `GPIO_PIN_0`, `GPIO_PIN_1`, `GPIO_PIN_2`... * So every pin is referred to by a pair of values: the port and the pin: `GPIOE, GPIO_PIN_3` or when humans are talking we say `PE3` *** ### **`Macro`s for GPIO** We will often use `#define` to give more meaningful names to the ports and pins, for ease of use: ```c /* main.h */ #define UP_BTN_GPIO_Port GPIOE #define UP_BTN_Pin GPIO_PIN_3 #define LED1_GPIO_Port GPIOE #define LED1_Pin GPIO_PIN_4 #define LED2_GPIO_Port GPIOE #define LED2_PIN GPIO_PIN_5 #define LED3_GPIO_Port GPIOE #define LED3_PIN GPIO_PIN_6 ``` *** ### **GPIO Function in the Program** The `HAL_GPIO_ReadPin` function reads the GPIO input. ```c /* stm32f4xx_hal_gpio.h */ GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); ``` The `HAL_GPIO_WritePin` function write the GPIO output. ```c /* stm32f4xx_hal_gpio.h */ void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState); ``` * The `GPIO_PIN` parameter can be `GPIO_PIN_RESET` (0) or `GPIO_PIN_SET` (1). The `HAL_GPIO_TogglePin` function toggle the GPIO output. ```c /* stm32f4xx_hal_gpio.h */ void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin); ``` *** #### Readability (Macro): * Writing `HAL_GPIO_ReadPin(XXX_GPIO_Port, XXX_Pin)` every time may seem tidious. However with the help of magical c prepocessor, we can make it easier ```c /* main.h */ #define gpio_read(gpio) HAL_GPIO_ReadPin(gpio##_GPIO_Port, gpio##_Pin) // usage uint8_t state = gpio_read(BTN1); ``` #### **Writing GPIO Output in the Program** The following macros can be found in `main.h` * The `gpio_set(gpio)` macro sets the GPIO pin to be 1. * The `gpio_reset(gpio)` macro resets the GPIO pin to 0. * The `gpio_toggle(gpio)` macro toggles the GPIO pin. (i.e. changes the GPIO pin state to 1 if it was originally 0 and vice versa) #### **Examples:** ```c // Turns off the LED gpio_set(LED1); // Turns on the LED gpio_reset(LED1); // Toggles the LED gpio_toggle(LED1); ``` ### **Full Example (Flickering the LED1 for every 500 ticks)** ```c /* main.c */ int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); volatile uint32_t last_ticks = HAL_GetTick(); while (1) { if (HAL_GetTick() - last_ticks > 500) { last_ticks = HAL_GetTick(); gpio_toggle(LED1); // flickering the LED1 } } return 0; } ``` *** ## **_In Class Exercise_**: ### There are few step before using GPIO pins in your program: 1. Find which GPIO you want to use in `main.h` (if you can't find one, define it yourself). 2. Initialize the GPIO marco by yourself in `gpio.h`. Remember which GPIO function you need for the LED control. 3. Use the GPIO marco to control the LED. ### **Requirement** 1. Turning on the LED in the first 5 seconds. 2. Flashing the LED for every 500 between 5 - 10 seconds. 3. Flashing the LED for every 100 between 10 - 15 seconds. 4. Turning off the LED