HAL (Hardware Abstraction Layer) Functions Reference Guide
Table of contents
- HAL (Hardware Abstraction Layer) Functions Reference Guide
- What is HAL?
- Initialization Functions
- GPIO (General Purpose Input/Output) Functions
- Timing Functions
- UART (Serial Communication) Functions
- Common HAL Status Values
- HAL in Your Project: Usage Summary
- Important HAL Patterns
- Related: The LCD Driver Functions
- Troubleshooting HAL Issues
- Quick Reference Table
This guide explains the Hardware Abstraction Layer (HAL) functions used in the Unit 3 LCD Test project. HAL functions provide easy access to the microcontroller’s hardware without needing to know low-level register details.
What is HAL?
The Hardware Abstraction Layer is a library provided by STMicroelectronics that abstracts away the complexity of the STM32 microcontroller. Instead of writing direct register access code, you call simple functions like HAL_GPIO_WritePin().
Your Code HAL Library Microcontroller Registers
┌──────────────────┐ ┌───────────────────┐ ┌──────────────────────┐
│ HAL_GPIO_Toggle │───>│ Translation to │───>│ GPIOA->BSRR = ... │
│ HAL_Delay │ │ register commands │ │ TIM2->CR1 |= TIM_... │
│ HAL_UART_Transmit│ │ (abstraction) │ │ SPI2->DR = ... │
└──────────────────┘ └───────────────────┘ └──────────────────────┘
Initialization Functions
HAL_Init()
Purpose: Initialize the HAL library. Must be called first in your program.
Syntax:
void HAL_Init(void);
What it does:
- Sets up the Systick timer (for
HAL_GetTick()andHAL_Delay()) - Initializes priority grouping which handles interupts
- Prepares the HAL for general use
Example:
int main(void) {
HAL_Init(); // Must be called first!
SystemClock_Config();
MX_GPIO_Init();
// ... rest of initialization
}
Important: Call this before any other HAL functions.
SystemClock_Config()
Purpose: Configure the system clock frequency for optimal performance.
Syntax:
void SystemClock_Config(void);
What it does:
- Enables the PLL (Phase-Locked Loop) oscillator
- Sets the system clock to 80 MHz (the maximum for STM32L476)
- Configures the AHB and APB buses
In your project: The system runs at 80 MHz, which means:
- SPI2 (for LCD) gets 80 MHz
- UART2 (for serial) gets 80 MHz
- All timers and peripherals get the full clock speed
You don’t need to understand the details - it’s auto-generated by CubeMX and just needs to be called once at startup.
MX_GPIO_Init()
Purpose: Initialize all GPIO pins as configured in CubeMX.
Syntax:
void MX_GPIO_Init(void);
What it does:
- Configures each GPIO pin as input or output
- Sets pull-up/pull-down resistors
- Sets the speed and alternate functions
- Enables the GPIO port clocks
In your project: This sets up:
- LED pin (PA5) as output
- Button pin as input
- SPI pins for LCD communication
Auto-generated: CubeMX creates this function based on your .ioc file configuration.
MX_USART2_UART_Init()
Purpose: Initialize UART2 (serial communication) for the serial console.
Syntax:
void MX_USART2_UART_Init(void);
What it does:
- Configures UART2 with 115200 baud rate
- Sets up TX (transmit) and RX (receive) pins
- Enables the UART peripheral clock
Result: This enables printf() to work by redirecting serial output.
Auto-generated: CubeMX creates this based on your configuration.
GPIO (General Purpose Input/Output) Functions
GPIO functions control digital input and output pins.
HAL_GPIO_WritePin()
Purpose: Set a GPIO pin to HIGH (3.3V) or LOW (0V).
Syntax:
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
Parameters:
GPIOx- Which port (GPIOA, GPIOB, etc.)GPIO_Pin- Which pin (GPIO_PIN_0, GPIO_PIN_1, etc.)PinState- GPIO_PIN_SET (HIGH/3.3V) or GPIO_PIN_RESET (LOW/0V)
Example: Turn on LED
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // LED on (3.3V)
HAL_Delay(500); // Wait 500ms
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // LED off (0V)
HAL_GPIO_ReadPin()
Purpose: Read the current state of a GPIO input pin.
Syntax:
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
Returns:
GPIO_PIN_SETif the pin is HIGH (3.3V)GPIO_PIN_RESETif the pin is LOW (0V)
Example: Read button state
GPIO_PinState button_state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13);
if (button_state == GPIO_PIN_SET) {
printf("Button is pressed\n");
} else {
printf("Button is not pressed\n");
}
In your project: Used to read the status of the blue button (B1) during the Magic 8Ball lab.
HAL_GPIO_TogglePin()
Purpose: Toggle a GPIO pin (switch it to the opposite state).
Syntax:
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
What it does:
- If pin is HIGH, set it LOW
- If pin is LOW, set it HIGH
Example: Blinking LED
while(1) {
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // Toggle LED
HAL_Delay(500); // Wait 500ms
}
// Result: LED blinks every 500ms
In your project: Used to flash the green LED (LD2) during the welcome message.
Timing Functions
HAL_Delay()
Purpose: Pause execution for a specified number of milliseconds.
Syntax:
void HAL_Delay(uint32_t Delay);
Parameters:
Delay- Number of milliseconds to wait (0-4,294,967,295)
Example:
printf("Starting countdown...\n");
HAL_Delay(1000); // Wait 1 second
printf("Go!\n");
In your project: Used extensively for delays between LCD refreshes and animations:
LCD_Fill_Buffer(0);
LCD_printString("Welcome", 20, 10, 1, 5);
LCD_Refresh(&cfg0);
HAL_Delay(200); // Wait 200ms before next text
Performance note: Blocking delay - the CPU does nothing else while waiting. For a 500ms delay, the CPU sits idle for 500ms.
HAL_GetTick()
Purpose: Get the current system tick count (milliseconds since startup).
Syntax:
uint32_t HAL_GetTick(void);
Returns: Number of milliseconds since HAL_Init() was called.
Example: Measure elapsed time
uint32_t start_time = HAL_GetTick();
// Do some work...
uint32_t elapsed = HAL_GetTick() - start_time;
printf("Operation took %lu ms\n", elapsed);
Use case: Game timing
uint32_t last_frame_time = 0;
while(1) {
uint32_t current_time = HAL_GetTick();
if (current_time - last_frame_time >= 50) { // 50ms = 20 FPS
// Update game frame
last_frame_time = current_time;
}
}
UART (Serial Communication) Functions
HAL_UART_Transmit()
Purpose: Send data over the serial port (UART).
Syntax:
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData,
uint16_t Size, uint32_t Timeout);
Parameters:
huart- UART handle (in your case,&huart2)pData- Pointer to data to sendSize- Number of bytes to sendTimeout- Maximum time to wait (in ms, useHAL_MAX_DELAYfor infinite)
Example: Send a string
char message[] = "Hello World\r\n";
HAL_UART_Transmit(&huart2, (uint8_t*)message, sizeof(message)-1, HAL_MAX_DELAY);
In your project: Used indirectly by printf(). The _write() function (in main.c) redirects printf output to this function:
int _write(int file, char *ptr, int len) {
HAL_UART_Transmit(&huart2, (uint8_t*)ptr, len, HAL_MAX_DELAY);
return len;
}
This is why printf() works and prints to the serial monitor!
Blocking: This function waits for transmission to complete before returning.
Common HAL Status Values
Many HAL functions return a status to indicate success or failure:
HAL_StatusTypeDef status = HAL_SPI_Transmit(&hspi2, data, length, timeout);
if (status == HAL_OK) {
// Success!
} else if (status == HAL_ERROR) {
// Error occurred
} else if (status == HAL_BUSY) {
// Peripheral is busy
} else if (status == HAL_TIMEOUT) {
// Timeout waiting for operation
}
HAL in Your Project: Usage Summary
Here’s how the HAL functions work together in your LCD test:
int main(void) {
// 1. Initialize HAL
HAL_Init();
// 2. Configure system clock for 80 MHz
SystemClock_Config();
// 3. Initialize GPIO pins
MX_GPIO_Init();
// 4. Initialize serial port
MX_USART2_UART_Init();
// 5. Now you can use HAL functions
while(1) {
// LED control
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
// Timing
HAL_Delay(500);
// Serial output (via printf)
printf("Elapsed: %lu ms\n", HAL_GetTick());
}
}
Important HAL Patterns
1. Always Initialize First
// Wrong - HAL functions won't work yet
HAL_Delay(1000);
HAL_Init();
// Correct - Initialize before using
HAL_Init();
SystemClock_Config();
HAL_Delay(1000); // Now this works
2. Use Handles for Peripherals
Most HAL functions take a “handle” - a structure containing peripheral configuration:
// UART handle (created by CubeMX)
extern UART_HandleTypeDef huart2;
// Use the handle to access the peripheral
HAL_UART_Transmit(&huart2, data, length, timeout);
3. Check Return Values
For critical operations, check if they succeeded:
HAL_StatusTypeDef status = HAL_UART_Transmit(&huart2, data, 100, 1000);
if (status != HAL_OK) {
printf("Serial transmission failed!\n");
while(1); // Hang if critical error
}
Related: The LCD Driver Functions
Note that the LCD functions (like LCD_Fill_Buffer() and LCD_Refresh()) are not HAL functions - they’re part of the ST7789V2 driver library. However, they internally use HAL functions like:
// Inside LCD driver
void LCD_Draw_Circle(...) {
// Uses HAL_Delay() for timing
// Uses HAL_SPI functions for communication
// Uses HAL_GPIO functions for control signals
}
Troubleshooting HAL Issues
| Problem | Likely Cause | Solution |
|---|---|---|
HAL_Delay() doesn’t work | Forgot HAL_Init() | Call HAL_Init() first |
| Serial output doesn’t appear | UART not initialized | Call MX_USART2_UART_Init() |
| LED doesn’t toggle | Wrong pin name | Check GPIO pin definitions in main.h |
Code hangs on HAL_Delay() | Interrupt conflict | Check if Systick interrupt is enabled |
| GPIO pin stuck on | Hardware issue | Check connections and pin configuration |
Quick Reference Table
| Function | Purpose | Example |
|---|---|---|
HAL_Init() | Initialize HAL | HAL_Init(); |
SystemClock_Config() | Set system clock to 80 MHz | SystemClock_Config(); |
MX_GPIO_Init() | Initialize GPIO pins | MX_GPIO_Init(); |
MX_USART2_UART_Init() | Initialize serial port | MX_USART2_UART_Init(); |
HAL_GPIO_WritePin() | Set pin HIGH or LOW | HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); |
HAL_GPIO_ReadPin() | Read pin state | if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET) { ... } |
HAL_GPIO_TogglePin() | Toggle pin state | HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); |
HAL_Delay() | Wait in milliseconds | HAL_Delay(500); |
HAL_GetTick() | Get elapsed milliseconds | uint32_t ms = HAL_GetTick(); |
HAL_UART_Transmit() | Send serial data | HAL_UART_Transmit(&huart2, data, len, HAL_MAX_DELAY); |