Introduction to the STMicroelectronics ecosystem

Development of embedded systems based on microcontrollers STM32 often frightens beginners with the complexity of the register and manual control of the peripherals. However, modern automation tools are radically changing the approach to programming, turning routine work into visual design. STM32CubeMX is a key tool in this ecosystem that allows you to configure chips with a graphical interface.

Using this software eliminates the need for the engineer to manually set bits in control registers, which significantly reduces the risk of errors during initialization. You simply select the desired module, configure its parameters, and the program itself generates initialization code in C. This allows you to focus on the logic of your device rather than on the low-level details.

In this tutorial we will go from setting up the environment to creating a full project with interrupts. You will learn to choose correctly microcontroller, adjust clock frequencies and connect external peripheral devices. The result will be a finished project that you can open in the IDE and immediately start writing business logic.

Installation and first launch of the development environment

The first step is to obtain the tool itself. You need to go to the official website of the company STMicroelectronics and download the utility STM32CubeMX. The program is free for all users, but requires account registration to download. The installation process is standard: run the installer, accept the license terms and select the target folder to place the files.

After launching the interface, you will see a welcome window. It is important to note here that the program automatically checks for updates to the databases microcontrollers. If you are using a new chip that came out recently, be sure to update the support packages, otherwise the device will not appear in the list. This is a critical point for correct work with modern series.

To get started, click the button New Project. A device selection window will open, where you can filter the list by family, chassis type, or the presence of certain peripheral modules. Enter the name of your microcircuit in the search bar, for example STM32F103C8, and select it from the list. Please note the color coding which indicates the chip's availability from distributors.

By selecting a model, you will be taken to the main configuration window. The interface is divided into several zones: a peripheral tree on the left, a graphical contact diagram in the center, and a settings panel on the right. Don't be intimidated by the abundance of options, we will look at each of them as we move through the lessons. The main thing now is to understand that all changes are applied dynamically.

System and Clock Configuration

One of the most common mistakes newbies make is ignoring the clock tree settings. Correct configuration system clock generator (System Core) determines the speed of the entire processor and peripherals. Go to section System Core -> RCC (Reset and Clock Control). Here you will see a diagram where you can select the clock source: an external quartz resonator or an internal RC oscillator.

For most applications requiring high precision, it is better to use an external resonator. In the block Clock Configuration you can visually adjust the multipliers and frequency dividers. The arrows on the diagram will show how the signal passes through the various dividers until the desired bus frequency is reached. APB and kernels CORE. Make sure that the frequencies do not exceed the permissible values ​​specified in the datasheet for your microcontroller.

Pay special attention to the parameter System Clock (SYSCLK). If you select too high a frequency without the appropriate supply voltage, the device may become unstable or may not start at all. The program will highlight invalid combinations of settings in red, warning of an error. Always check the frequency status in the lower right corner of the window.

⚠️ Warning: Incorrectly configured dividers can cause timers and serial ports to operate at incorrect speeds, causing failures in data transfer or control timings.

If you are using a development board, often everything is already configured by default for an external resonator. However, when designing your own board, you will have to manually specify the crystal parameters. Make sure the resonator you choose has a frequency that is a multiple of the desired system frequency to avoid fractional errors when calculating multipliers.

⚠️ Warning: If you are using an internal oscillator, be aware that its accuracy may vary with temperature and voltage, which is unacceptable for applications that require precise timing.
📊 Which clock source do you use most often?
  • Internal RC oscillator
  • External quartz resonator
  • External Generator (HSE)
  • I don't use external sources

Configuring digital ports and interrupts

The most popular scenario is controlling an LED or a button. To do this you need to configure GPIO (General Purpose Input/Output). In the left pane, select the desired contact from the graphic diagram. In the dropdown list GPIO Mode select operating mode: Output to exit or Input to enter. If it's a button, be sure to select pull-up mode Pull-up or Pull-down.

An output (eg LED) often requires adjustment of the switching speed and initial level. In parameters GPIO Output can be set Initial Valueso that the LED lights up immediately after turning on the power. This is convenient for indicating the operating status of the system. Also select the switching speed Output Typeto avoid line interference.

If you want the button to only respond when pressed, rather than constantly being polled by the processor, enable interrupt mode. Select EXTI (External Interrupt) instead of a simple login. This will make microcontroller pause execution of the main code when the input level changes. In the section NVIC (Nested Vectored Interrupt Controller) make sure interrupt is enabled.

☑️ Configuring interrupts

Done: 0 / 4

Interrupt priorities are critical in complex systems. In the window NVIC you can set the priority level for each source. The lower the number, the higher the priority. If a high priority interrupt occurs while another is running, it will interrupt the current task. This allows for an immediate response to critical events.

Working with timers and analog modules

Timers are the heart of any embedded system, responsible for delays, PWM, and timing. In the section Timer you can customize General Purpose Timer to generate pulses. Set options Prescaler and Counter Periodto get the desired frequency. The calculation formula is simple, but the visual interface STM32CubeMX immediately shows the result in Hertz, saving time on calculations.

To work with analog signals (temperature, voltage sensors), a module is used ADC (Analog-to-Digital Converter). Select a contact labeled ADCx_INy and activate it. In the settings you can select the conversion resolution (usually 12 bits) and operating mode (single or continuous). Don't forget to configure Sampling Time, on which the measurement accuracy depends.

When setting ADC It's important to keep sample timing in mind. If the signal changes too quickly and the sampling time is not enough, the result will be incorrect. For slow signals, you can increase the sampling time to reduce noise. It is also worth considering using DMA (Direct Memory Access) for transferring data from ADC to memory without the participation of the processor.

⚠️ Warning: Using ADC without filtering the input signal may result in erratic values. It is recommended to add a software or hardware filter.

If you need to control a servo or dim an LED, you will need a PWM timer channel. In timer mode, select Channel and specify the mode PWM Generation. By setting the value Duty Cycle, you will immediately see the expected pulse width. This allows you to quickly test the operation of the peripheral before writing code.

What is DMA and why is it needed?

DMA (Direct Memory Access) allows you to transfer data between peripherals and memory without the participation of the processor. This frees up the CPU to perform other tasks and improves overall system performance, especially when dealing with large amounts of data, such as from an ADC or UART.

Setting up serial interfaces

Data exchange with other devices is carried out via UART, I2C or SPI. For debugging, UART is most often used. Select the appropriate contact and activate the mode Asynchronous. In the settings, specify the transfer speed (Baud Rate), for example 115200, and stop bit parameters. The program will automatically calculate the values ​​of the divisor registers.

When setting I2C it is important to choose the right speed: standard Standard Mode (100 kHz) or fast Fast Mode (400 kHz). It is also necessary to adjust the signal rise time (Slew Rate) to avoid signal reflections on long buses. If you are connecting multiple devices, make sure they have different I2C Address.

For high-speed data transfer (for example, with display or flash memory) is used SPI. Here you can select the operating mode (CPOL, CPHA), which must match the requirements of the connected device. Errors in these settings will result in garbled data. IN STM32CubeMX you can easily switch between modes and see how the connection diagram changes.

Don't forget to activate DMA for UART and SPI interfaces if intensive data exchange is planned. This will prevent the processor from freezing while waiting for the byte transfer to complete. In the peripheral settings, just turn on the checkbox Use DMA and select a channel.

💡

Before generating the code, check that all pins used do not conflict with each other. The program will highlight conflicting pins in red.

Code generation and integration into IDE

Once all the settings are complete, it's time to generate the code. Click the button Project -> Generate Code. The IDE selection window will open. You can choose STM32CubeIDE, Keil MDK, IAR EWARM or Makefile. If you work in VS Code or Eclipse, select Makefile or SW4STM32. The program will create a project structure with all the necessary files.

It is important to understand the structure of the generated code. Main file main.c contains initialization and infinite loop while(1). Files usart.c, tim.c and others contain peripheral settings. Never edit code inside the /* USER CODE BEGIN */ and /* USER CODE END */ blocks, since when regenerating your changes will be lost. Write your code strictly between these comments.

To work with interrupts, you will need to implement handler functions. They are usually in the file stm32f1xx_it.c or are created automatically. IN main.c you can call functions HAL_GPIO_WritePin or HAL_UART_Transmit for port management. The HAL (Hardware Abstraction Layer) library provides convenient functions for working with any peripheral.

After opening the project in the IDE, make sure that all library paths are configured correctly. If you choose a third-party IDE, you may need to manually add HAL files to your project. Check your compiler and linker settings to ensure the address model matches your memory. Now you are ready to debug and launch your device.

💡

Code generation is the final configuration step in CubeMX. All configuration changes require regeneration, but custom code is saved if it is placed in special blocks.

Interface Operating mode Typical Application Settings Features
UART Asynchronous Debugging, GPS, Bluetooth Speed, data bits, stop bits
I2C Standard/Fast Sensors, EEPROM, OLED Device address, bus speed
SPI Full-Duplex Displays, SD cards, Flash Polarity, phase, speed
ADC Single/Continuous Temperature, voltage sensors Resolution, sampling time
TIM PWM/Encoder Servo drives, speed measurement Preset, Period, Channel Mode
How to update microcontroller support packages?

In the main program window, click on the gear icon (Tool Settings). Go to the tab Installed. Here you will see a list of installed packages. Click the button Check for Updatesto find new versions. If the package is not installed, go to the tab Download, find the family you need and download it. This ensures compatibility with the latest chips.

What to do if the code does not compile after generation?

Most often the problem is the absence of an included HAL library in your IDE or incorrect file paths. Check that all files with extension .c and .h are added to the project. Also make sure you select the correct one Toolchain in the IDE settings, corresponding to the one selected during generation.

Can CubeMX be used for older microcontrollers?

Yes, but only if the appropriate Legacy support packages are installed. However, STMicroelectronics is phasing out support for older families. It is recommended to use modern series STM32F4 or STM32G0 for new projects, as they have the best characteristics and active support.

How to configure multiple interrupts with different priorities?

In the section NVIC you can set the priority for each interrupt source. Use values ​​from 0 (high priority) to maximum (low). The system automatically manages the nesting of interrupts.