STM32 Introduction

What are STM32 Microcontrollers?

STM32 is a family of 32-bit microcontrollers developed by STMicroelectronics based on the ARM Cortex-M processor architecture. Introduced in 2007, these microcontrollers have gained immense popularity in the embedded systems world thanks to their powerful features, flexibility, and competitive pricing.

Why Choose STM32?

New to embedded systems and wondering why choose STM32 over simpler options like Arduino? Consider these reasons:

STM32 Family Overview

image.png

image.png

Key STM32 Concepts

GPIO (General Purpose Input/Output)

GPIO pins are digital pins that can be configured as either inputs or outputs.

static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /* Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);

  /* Configure GPIO pin : PA5 (LED) */
  GPIO_InitStruct.Pin = GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

Or direct register manipulation offers the best performance and smallest code size but requires deep knowledge of the hardware.

STM32 Introduction/General-purpose I Os (GPIO)

/*
		GPIOA_MODER = 01
		GPIOA_OTYPER = 0
		GPIOA_OSPEEDR = 00
		GPIOA_PUPDR = 00
*/

#define GREEN_LED_BIT 5

int main() {
  //In Run mode, the HCLKx and PCLKx for individual peripherals and memories can be 
  //stopped at any time to reduce power consumption.
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
  // Set PA5 low (reset)
  GPIOA->BSRR = (1u << (GREEN_LED_BIT + 16));

  // Set PA5 as output (MODER5 = 0b01)
  GPIOA->MODER &= ~(2u << (GREEN_LED_BIT * 2)); // Clear bits 10
  GPIOA->MODER |=  (1u << (GREEN_LED_BIT * 2)); // Set bit 10

  // Set PA5 as push-pull (OTYPER5 = 0)
  GPIOA->OTYPER &= ~(1u << GREEN_LED_BIT);

  // Set PA5 speed to low (OSPEEDR5 = 0b00)
  GPIOA->OSPEEDR &= ~(3u << (GREEN_LED_BIT * 2)); // Clear bits 10 and 11

  // Set PA5 no pull-up/pull-down (PUPDR5 = 0b00)
  GPIOA->PUPDR &= ~(3u << (GREEN_LED_BIT * 2)); // Clear bits 10 and 11
  
 
 // just togelling the led at your cpu clock speed for fun
  GPIOA->ODR ^= (1u << 5);
  GPIOA->ODR ^= (1u << 5);
  GPIOA->ODR ^= (1u << 5);
  GPIOA->ODR ^= (1u << 5);
 }

Clock System

The main clock sources are:

example of initialization of the system clock using the system core and sysTick, in cmsis

💡 ### CMSIS (Cortex Microcontroller Software Interface Standard)

CMSIS is a hardware abstraction layer for ARM Cortex-M microcontrollers that provides:


#include <stdint.h>
#include "stm32f4xx.h"
#define GREEN_LED_BIT 5

uint32_t tick;
uint32_t _tick;

void Clcok_init(void);
void DelaySec(uint32_t seconds);

int main(void)
{
	Clcok_init();

	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
	// Set PA5 low (reset)
	GPIOA->BSRR = (1u << (GREEN_LED_BIT + 16)); // Reset PA5

	// Set PA5 as output (MODER5 = 0b01)
	GPIOA->MODER &= ~(3u << (GREEN_LED_BIT * 2)); // Clear bits 10 and 11
	GPIOA->MODER |=  (1u << (GREEN_LED_BIT * 2)); // Set bit 10

	while (1)
	{
	  GPIOA->ODR ^= (1u << 5);
	  DelaySec(1);
	}

}

void Clcok_init(void)
{
	// Update 'SystemCoreClock' variable according to Clock Register Values.
	SystemCoreClockUpdate();
	// Initializes the System Timer and its interrupt, and starts the System Tick Timer.
	// the interrrupt will be called every 1ms (that is why it is deviced by 1000)
	SysTick_Config(SystemCoreClock/1000);
	// enable all interrupts. (because the systick uses the SysTick_Handler
	//  function as a handler for the interrup that is called evry 1ms in our case)
	__enable_irq();

	return;
}

// definetion of the interrupt
void SysTick_Handler(void)
{
	++tick;
}

uint32_t getTick(void)
{
	// get tick is a critical fucntion and can't be interrupted
	__disable_irq();
	_tick = tick;
	__enable_irq();

	return _tick;
}

void DelaySec(uint32_t seconds)
{
	seconds *= 1000;
	uint32_t temp = getTick();
	while ((getTick() - temp) < seconds) {}

	return;
}

Interrupts

STM32 Introduction/Set An ISR to execute when a GPIO is set high STM32

Nested Vectored Interrupt Controller (NVIC):

The NVIC manages interrupts with minimal latency and maximum configurability:

Development Approaches

1. HAL (Hardware Abstraction Layer)

HAL
provides a high-level, portable API that simplifies microcontroller
programming. It's beginner-friendly but can be less efficient.

// HAL example: Reading an ADC value
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
uint16_t adcValue = HAL_ADC_GetValue(&hadc1);

2. LL (Low-Layer)

The LL library offers better performance than HAL but requires more understanding of the hardware.

// LL example: Setting up a GPIO pin
LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_5);

3. Register-Level Programming

Direct register manipulation offers the best performance and smallest code size but requires deep knowledge of the hardware.

// Register-level example: Toggling an LED
GPIOA->ODR ^= (1 << 5);

As a beginner, start with HAL and gradually explore LL and register-level programming as you become more comfortable.

CMSIS

CMSIS (Cortex Microcontroller Software Interface Standard) is a vendor-independent hardware abstraction layer for ARM Cortex-M microcontrollers. Developed by ARM, CMSIS provides standardized APIs, device header files, and startup code, making it easier to develop and port embedded software across different ARM Cortex-M devices. It includes components for core access, device peripheral access, DSP libraries, RTOS interfaces, and more.

STM32 Introduction/Setup a CMSIS only project in cubeIDE (no HAL)

image.png