STM32F407(STM32F4-DISCOVERY) - Non-standard approach - Standard library part 1. Configuring STM32F10x SPL using macro definitions

Up to this point, we have used the standard kernel library - CMSIS. To configure a port to the desired operating mode, we had to turn to to find the register responsible for a certain function, and also search through a large document for other information related to this process. Things will get even more painful and routine when we start working with a timer or ADC. The number of registers there is much greater than that of the I/O ports. Manual setting takes a lot of time and increases the chance of making a mistake. Therefore, many people prefer to work with the standard peripheral library - StdPeriph. What does it give? It's simple - the level of abstraction increases, you don't need to go into the documentation and think about registers for the most part. In this library, all operating modes and parameters of the MK periphery are described in the form of structures. Now, to configure a peripheral device, you only need to call the device initialization function with a filled structure.

Below is a picture with a schematic representation of the levels of abstraction.

We worked with the CMSIS (which is "closest" to the core) to show how the microcontroller works. The next step is the standard library, which we will learn how to use now. Next come device drivers. They are understood as *.c \ *.h files that provide a convenient software interface for controlling any device. For example, in this course we will provide you with drivers for the max7219 chip and the esp8266 WiFi module.

A standard project will include the following files:


First, of course, these are the CMSIS files that allow the standard library to work with the kernel, we have already talked about them. Secondly, the standard library files. And thirdly, user files.

The library files can be found on the page dedicated to the target MK (for us it is stm32f10x4), in the section Design Resources(in the CooCox IDE, these files are downloaded from the development environment repository). Each peripheral corresponds to two files - header (*.h) and source code(*.c). Detailed description can be found in the support file, which is in the library archive on the website.

  • stm32f10x_conf.h - library configuration file. The user can connect or disconnect modules.
  • stm32f10x_ppp.h - peripheral header file. Instead of ppp there can be gpio or adc.
  • stm32f10x_ppp.c - peripheral device driver written in C language.
  • stm32f10x_it.h - header file that includes all possible interrupt handlers (their prototypes).
  • stm32f10x_it.c is a template source code file containing interrupt service routine (ISR) for exception situations in Cortex M3. The user can add his own ISRs for the peripherals used.

The standard library and peripherals have a convention in naming functions and notation.

  • PPP is an acronym for peripherals, such as ADC.
  • System, header and source code files - start with stm32f10x_.
  • Constants used in one file are defined in that file. Constants used in more than one file are defined in header files. All constants in the peripheral library are most often written in UPPER case.
  • Registers are treated as constants and are also called CAPITAL letters.
  • Peripheral-specific function names include an acronym, such as USART_SendData() .
  • To configure each peripheral device, the PPP_InitTypeDef structure is used, which is passed to the PPP_Init() function.
  • To deinitialize (set the value to default), you can use the PPP_DeInit() function.
  • The function that allows you to enable or disable peripherals is called PPP_Cmd().
  • The interrupt enable/disable function is called PPP_ITConfig.

WITH full list you can again look at the library support file. Now let's rewrite the LED blinking using the standard peripheral library!

Before starting work, let's look at the stm32f10x.h file and find the line:

#define USE_STDPERIPH_DRIVER

If you configure the project from scratch using library files from the downloaded archive, then you will need to uncomment this line. It will allow you to use the standard library. This definition (macro) will command the preprocessor to include the stm32f10x_conf.h file:

#ifdef USE_STDPERIPH_DRIVER #include "stm32f10x_conf.h" #endif

This file contains modules. If you need only specific ones, disable the rest, this will save time during compilation. We, as you might have guessed, need RTC and GPIO modules (however, in the future we will also need _bkp.h, _flash, _pwr.h, _rtc.h, _spi.h, _tim.h, _usart.h):

#include "stm32f10x_flash.h" // for init_pll() #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h"

Like last time, first you need to enable clocking of port B. This is done by the function declared in stm32f10x_rcc.h:

Void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

The FunctionalState enum is defined in stm32f10x.h:

Typedef enum (DISABLE = 0, ENABLE = !DISABLE) FunctionalState;

Let's declare a structure for setting up our leg (you can find it in the stm32f10x_gpio.h file):

GPIO_InitTypeDef LED;

Now we have to fill it out. Let's look at the contents of this structure:

Typedef struct ( uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; ) GPIO_InitTypeDef;

All necessary enumerations and constants can be found in the same file. Then the rewritten init_leds() function will take the following form:

Void led_init() ( // Enable clocking RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // Declare the structure and fill it GPIO_InitTypeDef LED; LED.GPIO_Pin = GPIO_Pin_0; LED.GPIO_Speed ​​= GPIO_Speed_2MHz; LED.GPIO_Mode = GPIO_Mode_ Out_PP; // Initialize the port GPIO_Init( GPIOB, &LED); )

Let's rewrite the main() function:

Int main(void) ( led_init(); while (1) ( GPIO_SetBits(GPIOB, GPIO_Pin_0); delay(10000000); GPIO_ResetBits(GPIOB, GPIO_Pin_0); delay(10000000); ) )

The main thing is to get a feel for the initialization order: turn on the peripheral clock, declare the structure, fill the structure, call the initialization method. Other peripheral devices are usually configured in a similar manner.

In this publication, I will try to focus on the main points for quickly getting started with STM32F10x microcontrollers based on the library of standard peripherals from the manufacturing company STMicroelectronics.

The article will use Eclipse CDT as the development environment. Since the main focus will be on the program code, you can safely do all the manipulations in Code::Blocks.

The general project structure for ARM microcontrollers is described in my article.

Here I will briefly remind you that to build a project for ARM microcontrollers (STM32F10x in particular), you will need a linker script and a C-Startup file.

A linker script is a file with instructions for placing program code and data in the microcontroller's memory. It can command your program code to be loaded into Flash program memory or SRAM data memory.

Microcontrollers with different amounts of program and data memory require different layout scripts. They can be obtained from the microcontroller manufacturer - STMicroelectronics.
Unpack the STM32F10x standard peripheral library from the archive ARM_Toolchain/Lib/stm32f10x_stdperiph_lib.zip.
It contains example projects for various development environments (IAR EWB, Keil uVision, Atollic True Studio, etc.). The closest one for us is Atollic True Studio, since it is a modification of Eclipse.
Go to the Project/StdPeriph_Template/TrueSTUDIO directory, there are several subdirectories there, the names of which correspond to the names of the STM3210x-EVAL development boards.

Find out which of these boards uses the same microcontroller line as yours. Copy the stm32_flash.ld file from the appropriate directory to your project.

It is also possible to create a universal script in which only the amount of program and data memory will be changed in accordance with the microcontroller used.

Startup code (C-Startup) for STM32 microcontrollers can be written in C or Assembler.
Although the STM32F10x Standard Peripheral Library (abbreviated STM32F10x SPL) is often criticized for its bugs, it is the easiest way to get started quickly when starting STM32 programming.
But you always want there to be some kind of alternative. In fact, there are many of them, for example, programming in assembly language :)

This is the most difficult and pointless path. The second way is to use the CMSIS library, which provides syntax for accessing C language structures to access various microcontroller peripherals. The simplest and most logical way (in my opinion) is to use libraries.

If you are categorically opposed to the STM32F10x SPL, then there is another alternative especially for you - the libopencm3 library. In it, the main number of examples is concentrated around the main series of microcontrollers STM32F10x, but it is only a matter of time before examples for other series (STM32F2xx/4xx) appear. You can always join the libopencm3 project and speed up this process.

The CMSIS standard is also optional for use in your programs.
You can do without it by spending some effort and time to implement the HAL (Hardware Abstraction Layer) level in the C programming language.

In some cases this method may be the only one in an accessible way. For example, your organization uses custom chips based on ARM-developed compute cores and industry-specific peripherals.

Or you need to implement software in C for microcontrollers with an ARM9 core, for which manufacturers focus on using ready-made operating systems(Linux, QNX, Windows CE), therefore, manufacturers may not provide libraries for programming in the C language in pure form or in combination with a more lightweight RTOS.

Fortunately, manufacturers of microcontrollers based on the Cortex-M3 core provide developers with a large number of code libraries. This also applies to STM32 microcontrollers.
Let's continue our consideration of the STM32F10x SPL library. We will consider it using an example.
You can open this example or create your own project from scratch to better understand the whole process of what is happening.

For the second case, I will list the necessary steps:

  • Create a new empty project in Eclipse
  • Copy the layout script and start file into the project
  • Create a new or copy a template Makefile
  • When using the Makefile from my example as a template, you need to create the src, inc, bin, obj directories inside the project, and create the Debug and Release subdirectories inside the bin and obj directories.
  • Copy the necessary source and header files from the CMSIS and STM32F10x SPL libraries.
  • Make the necessary changes to the user settings section of the template Makefile, if used.
  • Create new targets “Debug”, “cleanDebug”, “Release”, “cleanRelease”, “Program” in the Eclipse “make target” window.
  • Launch the “Debug” target and monitor its execution in the “Console” window.

For a better understanding of the material, I divided the article into several independent paragraphs, each of which describes only one aspect of working with the STM32F10x SPL library.

Configuring STM32F10x SPL using macro definitions

To configure the library, predefined macro values ​​are used, which we will now consider.
They can be set inside header files using a preprocessor directive #define or pass the values ​​of macro definitions through the key -D GCC compiler.
In my example I use the second method.
In Makefile variable DEFINE contains macros necessary to compile the STM32F10x SPL library.
Macro definition STM32F10X_MD specifies whether the microcontroller used belongs to the line Medium-density.
This includes microcontrollers with Flash memory from 64 to 128 kB.
The following table lists the names of macros for different series of microcontrollers:

Series name Macro Description
Low density Value line STM32F10X_LD_VL with Flash memory capacity 16 - 32 kB
Low density STM32F10X_LD
with Flash memory capacity 16 - 32 kB
Medium density Value line STM32F10X_MD_VL Flash - memory
64 - 128kB
Medium-density STM32F10X_MD microcontrollers of the STM32F101xx, STM32F102xx, STM32F103xx series with Flash memory 64 - 128 kB
High density Value line STM32F10X_HD_VL microcontrollers of the STM32F100xx series with volume
Flash - memory 256 - 512kB
High density STM32F10X_HD with volume
Flash memory 256 - 512kB
XL-density STM32F10X_XL
Flash memory 512 - 1024 kB
Connectivity line STM32F10X_CL

To set the clock frequency of the microcontroller, you need to uncomment the macro with the required clock frequency value in the system_stm32f10x.c file.

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL) #define SYSCLK_FREQ_24MHz 24000000 #else /* #define SYSCLK_FREQ_HSE HSE_VALUE */ /* #define SYSCLK_FREQ_24MHz 24000000 */ /* #define SYSCLK_FREQ_36MHz 3600 0000 */ /* #define SYSCLK_FREQ_48MHz 48000000 */ /* #define SYSCLK_FREQ_56MHz 56000000 */ #define SYSCLK_FREQ_72MHz 72000000 #endif

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)

/* #define SYSCLK_FREQ_HSE HSE_VALUE */

#define SYSCLK_FREQ_24MHz 24000000

#else

/* #define SYSCLK_FREQ_HSE HSE_VALUE */

/* #define SYSCLK_FREQ_24MHz 24000000 */

/* #define SYSCLK_FREQ_36MHz 36000000 */

/* #define SYSCLK_FREQ_48MHz 48000000 */

/* #define SYSCLK_FREQ_56MHz 56000000 */

#define SYSCLK_FREQ_72MHz 72000000

#endif

Intended use quartz resonator with a frequency of 8 MHz for all major
series of microcontrollers, except for the Connectivity line, for which it is necessary to install a 25 MHz quartz resonator.
If you use quartz resonators with other frequency values, then you need to change the value of the HSE_VALUE macro in the stm32f10x.h header file and adapt all dependent functions accordingly.
The purpose of the USE_STDPERIPH_DRIVER macro is not difficult to guess - to use the STM32F10x standard peripheral library.
USE_FULL_ASSERT – use the ASSERT macro to debug the program.

Using the assert_param macro in the library

All STM32F10x SPL library functions use the assert_param macro to check their arguments.
This macro checks an expression involving the function argument being tested for equality to zero. If the value of the expression is zero, then the argument error handler function assert_failed is called, otherwise (the expression is not zero), the argument check succeeds.
You need to implement the assert_failed function in your program.
It displays the error message, the file name and the number of the line of code that caused the error.
The debug_printf macro can output via USART using the standard new_lib library or, for example, the library from Mr. Chen.

#define debug_printf xprintf /* printf */ #ifdef USE_FULL_ASSERT void assert_failed(uint8_t* file, uint32_t line) ( debug_printf("Wrong parameters value: file %s on line %d\r\n", file, (int)line) ; while (1) ( ) )/* assert_failed */ #endif/*USE_FULL_ASSERT*/

#define debug_printf xprintf /* printf */

#ifdef USE_FULL_ASSERT

void assert_failed (uint8_t * file , uint32_t line )

debug_printf( "Wrong parameters value: file %s on line %d\r\n", file , (int ) line ) ;

while(1)

) /* assert_failed */

#endif/*USE_FULL_ASSERT*/

The assert_failed function implemented in your code is used only when the USE_FULL_ASSERT macro is declared. Otherwise, all debugging code is excluded from the source. This functionality is implemented in the driver library settings header file stm32f10x_conf.h.

#ifdef USE_FULL_ASSERT #define assert_param(expr) ((expr) ? (void)0: assert_failed((uint8_t *)__FILE__, __LINE__)) void assert_failed(uint8_t* file, uint32_t line); #else #define assert_param(expr) ((void)0) #endif /* USE_FULL_ASSERT */

#ifdef USE_FULL_ASSERT

#define assert_param(expr) ((expr) ? (void)0: assert_failed((uint8_t *)__FILE__, __LINE__))

void assert_failed (uint8_t * file , uint32_t line ) ;

#else

#define assert_param(expr) ((void)0)

#endif /* USE_FULL_ASSERT */

There's not much to explain here. Let's look at an example of using assert_param.

void set_param(uint8_t * param, uint8_t value) ( ​​assert_param(param != NULL); *param = value; )/*set_param*/

void set_param (uint8_t * param , uint8_t value )

assert_param (param != NULL ) ;

* param = value ;

) /*set_param*/

The function sets the value of the parameter via a pointer passed as an argument. If the USE_FULL_ASSERT macro is not declared, then we can assume that the lines
assert_param(param != NULL) is simply not in the code, otherwise the parameter is checked in this definition.
If the pointer is not defined, then the value param != NULL will be false and the assert_failed function will be run, which will output the file name and line number with the error via USART, and then loop, thereby preventing the value from being assigned to an undefined address in memory.
You are not at all required to use the assert_param macro in your code, but in library code
STM32F10x SPL it is used everywhere.
The set_param function can be implemented with argument error checking without using assert_param.

#define ERROR (-1) #define OK (0) int set_param(uint8_t * param, uint8_t value) ( ​​int r = ERROR; if (param == NULL) return r; *param = value; r = OK; return r ; )/*set_param*/

#define ERROR (-1)

#define OK (0)

int set_param (uint8_t * param , uint8_t value )

int r = ERROR ;

if (param == NULL )

return r ;

* param = value ;

r = OK ;

return r ;

) /*set_param*/

C-Startup file in the STM32F10x SPL library

In the start code, the microcontroller is initially initialized, the stack is configured, the BSS section is reset, and the main function main() is called.
The starting code has no direct relation to the STM32F10x SPL library. However, in this boot code, before calling the main() function of the program, the microcontroller initialization function SystemInit() is called, which is part of the CMSIS.
It can be easily found in the CMSIS library.
Go to the Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/TrueSTUDIO directory and copy the required file. All that remains is to find out which line the microcontroller used in your project belongs to.
To do this, look at the following table:

Series name File name Description
Low density Value line startup_stm32f10x_ld_vl.s microcontrollers of the STM32F100xx series with volume
Flash memory 16 - 32kB
Low density startup_stm32f10x_ld.s microcontrollers series STM32F101xx, STM32F102xx, STM32F103xx
with Flash memory capacity 16 - 32 kB
Medium density Value line startup_stm32f10x_md_vl.s microcontrollers series STM32F100xx
Medium-density startup_stm32f10x_md.s microcontrollers series STM32F101xx, STM32F102xx, STM32F103xx
with Flash memory capacity 64 - 128 kB
High density Value line startup_stm32f10x_hd_vl.s microcontrollers series STM32F100xx
High density startup_stm32f10x_hd.s microcontrollers series STM32F101xx, STM32F103xx
with Flash memory capacity 256 - 512 kB
XL-density startup_stm32f10x_xl.s microcontrollers series STM32F101xx, STM32F103xx
with Flash memory capacity 512 - 1024 kB
Connectivity line startup_stm32f10x_cl.s microcontrollers of the STM32F105xx and STM32F107xx series

The startup file contains the names of the interrupt and exception vector handlers, but only the reset vector handler is implemented, within which all the initial initialization is performed before calling the main() function.
The implementation of all other exception handlers is the responsibility of the application programmer. If your program does not use any handlers, then there is no need to register them. If an exception occurs, the default handler will be used - looping the program code.

Composition of the CMSIS library

As was written earlier in this publication, the CMSIS library provides access to microcontroller peripheral modules using elements of C language structures.
The implementation of this library is divided into two parts. The first part provides access to the Cortex-M3 core periphery, and the second part provides access to the periphery specific model microcontroller.
Since the CMSIS standard is the same for all microcontrollers with a Cortex-M3 core, the implementation of the first part will be the same for all manufacturers, but the second part will be different for each manufacturer.
CMSIS includes several header and source files. The first part includes the files:

  • core_cm3.h
  • core_cm3.c

The second part of CMSIS includes the C-Startup file, as well as the following files:

  • stm32f10x.h
  • system_stm32f10x.h
  • system_stm32f10x.c

The header file stm32f10x.h contains macro definitions for accessing peripheral modules of stm32f10x microcontrollers.
The files system_stm32f10x.h and system_stm32f10x.c implement the initial initialization of the microcontroller.

Composition and configuration of the STM32F10x SPL library

The library consists of source and header files of the same name as peripheral modules with the prefix stm32f10x_.
For example, the implementation of interaction with the USART module is contained in the files stm32f10x_usart.h and stm32f10x_usart.c.
There are conventions for naming library elements and certain encoding rules, which are described in the documentation.
The library contains the implementation of drivers for peripheral microcontroller modules.
The names of library elements use the following acronyms for peripheral modules:

Acronym Peripheral module
ADC analog-to-digital converter
BKP backup registers
CAN CAN interface
CEC consumption controller
CRC checksum calculation module
DAC digital-to-analog converter
DBGMCU microcontroller debugging
DMA direct memory access controller
EXTI external interrupt controller
FSMC external memory controller
FLASH Flash program memory
GPIO general purpose I/O ports
I2C I2C interface
I2S I2S (Sound) interface
IWDG independent watchdog timer
NVIC nested interrupt controller
PWR power controller
RCC reset and clock controller
RTC real time controller (clock)
SDIO SDIO interface
SPI SPI interface
SysTick system timer
TIM basic or advanced timer
USART universal serial synchronous-asynchronous
transceiver
WWDG window watchdog

Based on these acronyms, the names of the library's software modules are formed. You don't have to use all the modules in the library.
In order to use only the necessary modules in the project, the library must be configured.
For these purposes, each project that uses the STM32F10x SPL library must have a header file stm32f10x_conf.h.

#include "stm32f10x_gpio.h" //#include "stm32f10x_i2c.h" //#include "stm32f10x_iwdg.h" //#include "stm32f10x_pwr.h" #include "stm32f10x_rcc.h"

#include "stm32f10x_gpio.h"

//#include "stm32f10x_i2c.h"

//#include "stm32f10x_iwdg.h"

//#include "stm32f10x_pwr.h"

#include "stm32f10x_rcc.h"

To enable the required module, you need to uncomment the directive #include with the corresponding header files.
The header file stm32f10x_conf.h is included in stm32f10x.h, so to use the functions of the STM32F10x SPL library, you only need to include only one header file stm32f10x.h in your source code

// in the file stm32f10x.h #ifdef USE_STDPERIPH_DRIVER #include "stm32f10x_conf.h" #endif

I repeat that the project must also define the macros USE_STDPERIPH_DRIVER, USE_FULL_ASSERT and a macro that specifies the series of the microcontroller used (for example, STM32F10X_MD for the Medium density line).
If you use the standard quartz frequency value and the controller operates at a maximum clock frequency of 72 MHz, then you will not have to change anything else.
You need to add a list of library files to compile to the Makefile.
For example:

SRC += stm32f10x_rcc.c SRC += stm32f10x_gpio.c

SRC += stm32f10x_rcc . c

SRC += stm32f10x_gpio . c

Using the STM32F10x SPL library. Working mechanisms

To start programming using the peripheral library, the easiest way is to look at the examples supplied with the library. But still, to understand the code of these examples, you must have basic knowledge of the syntax and use of the library.
All of the previously listed peripheral microcontroller modules are initially deactivated, a clock signal is not supplied to them and they do not consume electricity.
To use a peripheral module, you first need to provide a clock signal to it. The clock signal is supplied by the RCC clock and reset module.
For these purposes, the library has the following functions:

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_PPPx, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_PPPx, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_PPPx, ENABLE);

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_PPPx, ENABLE);

RCC_APB2PeriphClockCmd (RCC_APB2Periph_PPPx, ENABLE) ;

RCC_APB1PeriphClockCmd (RCC_APB1Periph_PPPx, ENABLE) ;

Here PPP denotes the name of the module actonym (for example ADC or USART), and x is the number of the peripheral module.
First of all, you need to find out which bus the module you are using is connected to.
In total, microcontrollers with Cortex-M3 core architecture have three buses:
instruction bus, data bus and system bus. The instruction bus connects the core to Flash program memory. The data and system buses are combined into an AHB (ARM Hi-Speed ​​Bus) bus matrix, which operates at the core frequency. However, the AHB bus frequency can be reduced by installing dividers. The AHB bus connects high-speed devices such as the core and the DMA module.
I/O devices are connected to the AHB bus via intermediate buses APB1 and APB2 (ARM Peripheral Bus).
The maximum operating frequency of the APB2 bus is 72 MHz, the frequency of the APB1 bus
limited to 36MHz.
You can find out which of the buses the peripheral module you are using is connected to from the documentation or look in the header file stm32f10x_rcc.h.
Open this file and search for RCC_AHBPeriph, RCC_APB1Periph and RCC_APB2Periph values ​​in sequence.

#define RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001) #define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002) #define RCC_AHBPeriph_SRAM ((uint32_t)0x00000004) #define RCC_AHBPeriph_FLITF ((uint32_t) 0x00000010) #define RCC_AHBPeriph_CRC ((uint32_t)0x00000040)

#define RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001)

#define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002)

#define RCC_AHBPeriph_SRAM ((uint32_t)0x00000004)

#define RCC_AHBPeriph_FLITF ((uint32_t)0x00000010)

#define RCC_AHBPeriph_CRC ((uint32_t)0x00000040)

By the names of the macros we determine which modules are connected to which buses. You can also use common sense to determine which tire belongs to one of the three. For example, the USART module is an input/output device, which means it is connected to one of the APB buses. USART is a fairly low-speed interface, so it is probably connected to the APB1 bus.

#define RCC_APB1Periph_USART2 ((uint32_t)0x00020000) #define RCC_APB1Periph_USART3 ((uint32_t)0x00040000) #define RCC_APB1Periph_UART4 ((uint32_t)0x00080000) #define RCC_APB1Periph_UART5 ((uint32_t)0x00100000)

After sending a clock signal to the peripheral module, you can configure its parameters by calling the initialization function:

PPP_Init(PPP, &PPP_InitStructure);

PPP_Init (PPP , & amp ; PPP_InitStructure ) ;

Since many parameters must be passed to the initialization function to initialize a peripheral module, a pointer to a structure is used as an argument. The structure itself with initialization parameters must be created in memory before calling the initialization function; the elements of the structure must be assigned the necessary values:

PPP_InitTypeDef PPP_InitStructure = (val1, val2, ..., valN);/* initialization of the structure when declared */

You can first create a structure and then assign the necessary values ​​to its elements:

PPP_InitTypeDef PPP_InitStructure; PPP_InitStructure.member1 = val1; PPP_InitStructure.member2 = val2; PPP_InitStructure.memberN = valN;

PPP_InitTypeDef PPP_InitStructure ;

PPP_InitStructure . member1 = val1 ;

PPP_InitStructure . member2 = val2 ;

PPP_InitStructure . memberN = valN ;

Let's look at an example from the stm32f10xQuickstart project:

GPIO_InitTypeDef GPIO_InitStructure; #ifdef USE_STM32H_103 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &GPIO_InitStructure);

GPIO_InitTypeDef GPIO_InitStructure ;

#ifdef USE_STM32H_103

RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC, ENABLE) ;

GPIO_InitStructure . GPIO_Pin = GPIO_Pin_12 ;

GPIO_InitStructure . GPIO_Speed ​​= GPIO_Speed_50MHz ;

GPIO_InitStructure . GPIO_Mode = GPIO_Mode_Out_PP ;

GPIO_Init(GPIOC, & GPIO_InitStructure);

The elements of the GPIO_InitStructure structure are assigned the value of the pin number, mode and speed of the port.
By calling the GPIO_Init function, line 12 of GPIOC port is initialized.
The first argument to the GPIO_Init function is a pointer to the GPIOC peripheral's memory area, converted to a pointer to a GPIO_TypeDef structure.

// stm32f10x.h #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) #define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) #define PERIPH_BASE ((uint32_t)0x40000000) typedef struct ( __IO uint32_t CRL; __IO uint32_t CRH ; __IO uint32_t IDR; __IO uint32_t ODR; __IO uint32_t BSRR; __IO uint32_t BRR; __IO uint32_t LCKR; ) GPIO_TypeDef;

// stm32f10x.h

#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)

#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)

#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)

#define PERIPH_BASE ((uint32_t)0x40000000)

typedef struct

IO uint32_t CRL ;

IO uint32_t CRH ;

IO uint32_t IDR ;

IO uint32_t ODR ;

IO uint32_t BSRR ;

IO uint32_t BRR ;

IO uint32_t LCKR ;

) GPIO_TypeDef ;

The GPIO_InitStructure structure is of type GPIO_InitTypeDef, described in the header file
stm32f10x_gpio.h:

//stm32f10x_gpio.h typedef struct ( uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; )GPIO_InitTypeDef; typedef enum ( GPIO_Speed_10MHz = 1, GPIO_Speed_2MHz, GPIO_Speed_50MHz )GPIOSpeed_TypeDef; typedef enum ( GPIO_Mode_AIN = 0x0, GPIO_Mode_IN_FLOATING = 0x04, GPIO_Mode_IPD = 0x28, GPIO_Mode_IPU = 0x48, GPIO_Mode_Out_OD = 0x14, GPIO_Mode_Out_PP = 0x10, GPIO_Mode_AF_OD = 0x1C, GPIO_Mode_AF_PP = 0x18 )GPIOMode_TypeDef;

//stm32f10x_gpio.h

typedef struct

uint16_t GPIO_Pin ;

GPIOSpeed_TypeDef GPIO_Speed ​​;

GPIOMode_TypeDef GPIO_Mode ;

) GPIO_InitTypeDef ;

typedef enum

GPIO_Speed_10MHz = 1,

GPIO_Speed_2MHz,

GPIO_Speed_50MHz

) GPIOSpeed_TypeDef ;

typedef enum

(GPIO_Mode_AIN = 0x0,

GPIO_Mode_IN_FLOATING = 0x04 ,

GPIO_Mode_IPD = 0x28,

GPIO_Mode_IPU = 0x48,

GPIO_Mode_Out_OD = 0x14,

GPIO_Mode_Out_PP = 0x10,

GPIO_Mode_AF_OD = 0x1C ,

GPIO_Mode_AF_PP = 0x18

) GPIOMode_TypeDef ;

As you can see, the data types of the initialized structure can be used as custom types, like GPIOSpeed_TypeDef, and data types with specific values ​​for the convenience of initializing peripheral registers, like GPIOMode_TypeDef.
4 bits are allocated for configuring each GPIO pin.
The following picture shows the format for the zero bit of GPIO:

Mode – output operating mode (input/output). More precisely, these values ​​are slightly larger; ports configured as output ports have a limitation on the maximum frequency of the output signal.

Mode Description
00 entrance
01 output frequency up to 10 MHz
10 output frequency up to 2 MHz
11 output frequency up to 50 MHz

CNF – output configuration bits. Depends on operating mode:

Agree that with this structure of the pin configuration register, setting all the bits for the configuration yourself will be extremely inconvenient. It will be much easier to do this using the GPIO_Init library function.
After you initialize the peripheral module, it must be activated using the PPP_Cmd function:

PPP_Cmd(PPP, ENABLE);

PPP_Cmd(PPP, ENABLE);

This function does not exist for GPIO modules; after initialization, you can immediately use the GPIO pins. It must be remembered that the library only provides an interface to the microcontroller hardware. If the hardware module does not have an activation/deactivation flag, then the function call PPP_Cmd(PPP, ENABLE) impossible.
To control the state of the GPIOx pin in output mode and read the value in input or output mode, the library provides the following functions:

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx); uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

void GPIO_SetBits (GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin ) ;

void GPIO_ResetBits (GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin ) ;

uint8_tGPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_tGPIO_Pin) ;

uint16_tGPIO_ReadOutputData(GPIO_TypeDef* GPIOx) ;

uint8_tGPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_tGPIO_Pin) ;

uint16_tGPIO_ReadInputData(GPIO_TypeDef* GPIOx) ;

The rest of the peripheral modules are configured and worked in the same way. However, there are some differences due to the specifics of the specific hardware module, so I strongly recommend that you first view examples of using the selected module for the STM32F10x SPL library.

Handling interrupts and exceptions

The Cortex-M3 core includes a nested vectorized interrupt controller. The controller supports up to 240 sources that can cause processor core interrupts. How many vectors out of 240 possible are implemented in a specific microcontroller model depends on the manufacturer. Stm32f10x microcontrollers can have up to 43 of these vectors. These interrupt lines are called maskable. In addition, there are 15 Cortex-M3 core interrupt vectors and one external non-maskable EXTI interrupt.
The controller supports nested interrupts, where another interrupt can occur within one handler. In this regard, each interrupt source has its own priority. 16 interrupt priority levels are supported.
Cortex-M3 core interrupt vectors have the highest priority values.
The three highest interrupt levels are assigned to vectors and cannot be changed:

Number Handler A priority Description
1 Reset_Handler -3(highest) Reset vector
2 NMI_Handler -2 Non-maskable interrupt
3 HardFault_Handler -1 Emergency conditions

All other interrupt vectors can be assigned priority levels from 0 to 15.
The highest priority level corresponds to a lower value. The priority level can be assigned not only to an individual vector, but also to an entire group of vectors. This feature makes it easier to work with a large number of interrupt vectors.
To set the priority group, a function from the STM32F10x SPL library is used.

For a long time, even a very long time, there have been no new articles on our article, so it’s time to catch up 😉 Today we will begin studying the STM32F4. And, probably, we’ll start by creating a new project for these controllers, although, to be honest, I didn’t want to write an article about it, because new project here it is created, in principle, the same way as for STM32F103 (). But it still happens that some difficulties arise with the STM32F4, so, nevertheless, let’s consider this process in detail)

So, let's launch Keil, create a new project - Project -> New uVision Project. We save the new project in some folder, and then we will be asked to select the microcontroller to use. Well, let's choose, let it be STM32F407VG:

Done, in the dialog box that appears, click “Yes” and the first file will be added to our project - startup_stm32f4xx.s. Just like before, we will use libraries CMSIS And Standard Peripheral Library, but, naturally, already for STM32F4xx controllers. So we definitely need to download them and add the necessary files to our still empty project. By the way, I have heard more than once from different people that they come across some “not so” libraries for F4, and even the simplest project is not put together. I myself have not encountered this, however, here are the tested libraries that I myself use:

So, we downloaded it, everything is ready, now we add the files to the project. The picture shows what you will need:

Well, the preparation is complete, now let’s create a new .c file, which will contain our code. Let's go to File->New, an empty file opens in Keil, click File->Save as and save it under the name test.c, for example. When saving, don’t forget to specify the file extension (.c). The file was created, great, but we also need to add it to our project. Well, actually, there’s nothing complicated about it 😉 Let’s write an empty test program into this file:

#include "stm32f4xx.h" #include "stm32f4xx_rcc.h" #include "stm32f4xx_gpio.h" /*******************************************************************/ int main() ( while (1 ) ( __NOP() ; ) ) /*******************************************************************/

Almost everything is ready, all that remains is to look at the project settings - Project->Options for target… A window opens with many tabs, we are only interested in a few here. Open the tab C/C++ and in the Define field we write:

Well, down in the field you need to add paths to absolutely all files included in the project. After completing this step, you can press F7 (Build), and the project will be built without errors or warnings. As you can see, nothing complicated)

But in general, I personally do things a little differently. Look at the disadvantage of this approach. So we downloaded the CMSIS and SPL libraries somewhere, added files from these folders, wrote down the paths to the files, everything is cool. BUT! The project will not be built on another computer, since the paths are all absolute, that is, they point to specific folders on your computer. And on another machine you will actually have to re-perform the steps to create a new project. This is a huge minus. Therefore, I usually create a separate folder for a new project, in it I create subfolders for CMSIS, SPL and other libraries used, and into these folders I put all the files that I need in each specific project. For example, let’s create the STM32F4_Test folder for our new project and the following folders in it:

I put all the necessary files that we added when creating the project at the beginning of the article into the CMSIS and SPL folders. Now we launch Keil, create a new project and save it in our Project subfolder so that all project files are in one place and do not cause chaos)

The project has been created, now, as before, we simply add all the files from the STM32F4_CMSIS and STM32F4_SPL folders to it. We put our test .c file with the main() function into the Source folder and add it to the project too. All that remains is to configure the settings =) Everything is the same - in the define field we write:

USE_STDPERIPH_DRIVER,STM32F4XX



We assemble the project - there are no errors, the flight is normal! In principle, in the end we got the same thing, but now the project will be immediately assembled on any other computer without any problems, and this is very convenient and useful) Absolutely all project files are now located nearby, in the same folder, and the paths have become relative and do not have to be changed .
That's all, actually, in the near future we will do something to program the STM32F4, definitely, so see you soon!;)

Full project from example article -

I indicated that the standard library is connected to the system. In fact, CMSIS is connected - the system of generalized structural representation of MK, as well as SPL - the standard peripheral library. Let's look at each of them:

CMSIS
It is a set of header files and a small set of code for unifying and structuring work with the core and periphery of the MK. In fact, without these files it is impossible to work normally with MK. You can get the library on the accompanying documentation page for the MK.
This library, according to the description, was created to unify interfaces when working with any MK of the Cortex family. However, in reality it turns out that this is only true for one manufacturer, i.e. By switching to a microcontroller from another company, you are forced to study its peripherals almost from scratch.
Although those files that relate to the processor core of the MK are identical from all manufacturers (if only because they have the same processor core model - provided in the form of IP blocks by ARM).
Therefore, working with such parts of the kernel as registers, instructions, interrupts and coprocessor units is standard for everyone.
As for the periphery, the STM32 and STM8 (suddenly) are almost similar, and this is also partially true for other MKs released by ST. In the practical part, I will show how easy it is to use CMSIS. However, difficulties in using it are associated with the reluctance of people to read the documentation and understand the MK design.

SPL
Standard Peripheral Library - standard peripheral library. As the name suggests, the purpose of this library is to create an abstraction for the periphery of the MK. The library consists of header files where human-readable constants for configuring and working with MK peripherals are declared, as well as source code files collected into the library itself for operations with peripherals.
SPL is an abstraction over CMSIS, presenting the user with a common interface for all MCUs not only from one manufacturer, but generally all MCUs with a Cortex-Mxx processor core.
It is believed that it is more convenient for beginners, because... allows you not to think about how the peripherals work, but the quality of the code, the universality of the approach and the constraint of the interfaces impose certain restrictions on the developer.
Also, the functionality of the library does not always allow you to accurately implement the configuration of some components such as USART (universal synchronous-asynchronous serial port) under certain conditions. In the practical part, I will also describe working with this part of the library.

Hi all. As you remember in the last article we set up software package to work with STM32 microcontrollers and compiled the first program. In this post we will get acquainted with the architecture of this board, microcontroller and available libraries for work.

Below is a picture of the board STM32F3 Discovery , where: 1 — MEMS sensor. L3GD20 3-axis digital gyroscope. 2 - MEMS system-in-a-case containing a 3-axis digital linear accelerometer and a 3-axis digital geomagnetic sensor LSM303DLHC. 4 – LD1 (PWR) – 3.3V power supply. 5 – LD2 – red/green LED. Default is red. Green means communication between ST-LINK/v2 (or V2-B) and PC. I have ST-LINK/v2-B, as well as a custom display USB port. 6. -LD3/10 (red), LD4/9 (blue), LD5/8 (orange) and LD6/7 (green). In the last post we flashed the LD4 LED. 7. – Two buttons: custom USER and reset RESET. 8. - USB USER with Mini-B connector.

9 - USB debugger/programmer ST-LINK/V2. 1 0. - Microcontroller STM32F303VCT6. 11. — External high-frequency generator 8 MHz. 12. – There should be a low-frequency generator here, unfortunately it’s not soldered. 13. – SWD – interface. 14. – Jumpers for selecting programming of external or internal controllers, in the first case must be removed. 15 – Jumper JP3 – a jumper designed to connect an ammeter to measure the controller’s consumption. It is clear that if it is deleted, then our stone will not start. 16. – STM32F103C8T6 there is a debug board on it. 17. - LD3985M33R Regulator with low voltage drop and noise level, 150mA, 3.3V.

Now let's take a closer look at the architecture of the STM32F303VCT6 microcontroller. His technical specifications: LQFP-100 case, ARM Cortex-M4 core, maximum core frequency 72 MHz, program memory capacity 256 KB, memory type FLASH programs, volume random access memory SRAM 40 kbytes, RAM 8 kbytes, number of inputs/outputs 87, interfaces (CAN, I²C, IrDA, LIN, SPI, UART/USART, USB), peripherals (DMA, I2S, POR, PWM, WDT), ADC/DAC 4 *12 bit/2*12bit, supply voltage 2...3.6 V, operating temperature –40...+85 C. In the figure below there is a pinout, where we see 87 input/output ports, 45 of them Normal I/Os (TC, TTa), 42 5-volt tolerant I/Os (FT, FTf) – compatible with 5 V. (on the board there are 5V pins on the right, 3.3V on the left). Each digital I/O line can serve as a general I/O line.
destination or alternative function. As projects progress, we will gradually get acquainted with the periphery.

Consider the block diagram below. The heart is a 32-bit ARM Cortex-M4 core operating up to 72 MHz. It has a built-in floating point unit FPU and a memory protection unit MPU, built-in macro tracing cells - Embedded Trace Macrocell (ETM), which can be used to monitor the execution process of the main program inside the microcontroller. They are capable of continuously outputting these observations through the ETM contacts as long as the device is operating. NVIC (Nested vectored interrupt controller) – interrupt control module. TPIU (Trace Port Interface Unit). Contains FLASH memory – 256 KB, SRAM 40 KB, RAM 8 KB. Between the core and memory is a Bus matrix, which allows devices to be connected directly. Also here we see two types of bus matrix AHB and APB, where the first is more productive and is used for high-speed communication internal components, and the latter is for peripherals (input/output devices). The controller has 4 12-bit ADCs (ADC) (5 Mbit/s) and a temperature sensor, 7 comparators (GP Comparator1...7), 4 programmable operational amplifiers (OpAmp1...4) (PGA (Programmable Gain Array)), 2 12-bit DAC channels (DAC), RTC (real time clock), two watchdog timers - independent and windowed (WinWatchdog and Ind. WDG32K), 17 general purpose and multifunctional timers.

In general terms, we looked at the controller architecture. Now look at the available software libraries. Having made an overview, we can highlight the following: CMSIS, SPL and HAL. Let's look at each using a simple example of blinking an LED.

1). CMSIS(Cortex Microcontroller Software Interface Standard) - standard library for Cortex®-M. Provides device support and simplifies software interfaces. CMSIS provides consistent and simple interfaces for the kernel, its peripherals and real-time operating systems. Its use is a professional way to write programs, because... involves direct writing to registers and, accordingly, constant reading and study of datasheets is necessary. Independent of the hardware manufacturer.
CMSIS includes the following components:
- CMSIS-CORE: Consistent system startup and peripheral access;
- CMSIS-RTOS: Deterministic Real-Time Software Execution software real time);
- CMSIS-DSP: Fast implementation of digital signal processing digital processing signals);
- CMSIS-Driver: Generic peripheral interfaces for middleware and application code (General peripheral interfaces for middleware and application code);
- CMSIS-Pack: Easy access to reusable software components software components);
- CMSIS-SVD: Consistent view to device and peripherals peripheral devices);
- CMSIS-DAP: Connectivity to low-cost evaluation hardware. Debugging software.

For example, let's write a program - blink an LED. For this we need documentation describing the registers. In my case RM0316 Reference manual STM32F303xB/C/D/E, STM32F303x6/8, STM32F328x8, STM32F358xC, STM32F398xE advanced ARM ® -based MCUs, as well as a description of the specific leg for which it is responsible DS9118: ARM®-based Cortex®-M4 32b MCU+FPU, up to 256KB Flash+ 48KB SRAM, 4 ADCs, 2 DAC ch., 7 comp, 4 PGA, timers, 2.0-3.6 V. To begin with, we will clock the port in the program, because By default, everything is disabled, which achieves reduced power consumption. Open the Reference manual and look at the Reset and clock control section, then RCC register map and see what register is responsible for enabling IOPEEN

Let's move on to the description of the clocking of the peripherals of this register AHB peripheral clock enable register (RCC_AHBENR), where we see that this port is under the 21st bit. Turn it on RCC->AHBENR|=(1<<21) . Далее сконфигурируем регистры GPIO. Нас интересует три: GPIOE_MODER и GPIOx_ODR . C помощью них повторим программу с предыдущей статьи, затактируем PE8. Первый отвечает за конфигурацию входа выхода, выбираем 01: General purpose output mode. GPIOE->MODER|=0×10000 . The second is for turning on the low/high level on the leg. Below is the program:

#include "stm32f3xx.h " //Microcontroller header file
unsigned int i;
void delay() (
for (i=0;i<500000;i++);
}
int main (void) (
RCC->AHBENR|=(1<<21);
GPIOE->MODER|=0×10000;
while (1)(
delay();
GPIOE->ODR|=0×100;
delay();
GPIOE->ODR&=~(0×100);
} }

2). SPL(Standard Peripherals Library)- this library is intended to combine all processors from ST Electronics. Designed to improve code portability and is primarily aimed at beginner developers. ST has been working on a replacement for SPL called "low layer" that is compatible with HAL. Low Layer (LL) drivers are designed to provide an almost lightweight, expert-oriented layer that is closer to the hardware than HAL. In addition to HAL, LL APIs are also available. An example of the same program in SPL.

#include
#include
#include
#define LED GPIO_Pin_8
int main() (
long i;
GPIO_InitTypeDef gpio;
// Blue LED is connected to port E, pin 8 (AHB bus)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, ENABLE);
// Configure port E (LED)
GPIO_StructInit(&gpio); //declare and initialize a data structure variable
gpio.GPIO_Mode = GPIO_Mode_OUT;
gpio.GPIO_Pin = LED;
GPIO_Init(GPIOE, &gpio);
// Blinking LEDS
while (1) (
// On
GPIO_SetBits(GPIOE, LED);
for (i = 0; i< 500000; i++);
// All off
GPIO_ResetBits(GPIOE, LED);
for (i = 0; i< 500000; i++);
} }

Each function is described in the technical documentation UM1581 User manual Description of STM32F30xx/31xx Standard Peripheral Library. Here we connect three header files that contain the necessary data, structures, reset and synchronization control functions, as well as for configuring input/output ports.

3). HAL- (Hardware Access Level, Hardware Abstraction Layer)- Another common library for development. With which the CubeMX program for the configuration that we used in the last article was also released. There we also wrote a program for blinking an LED using this library. As we see in the figure below, the cube generates HAL and CMSIS drivers. Well, let's describe the main files used:
- system_stm32f3x.c and system_stm32f3x.h- provide minimal sets of functions for configuring the timing system;
— core_cm4.h – provides access to registers of the core and its peripherals;
- stm32f3x.h - microcontroller header file;
— startup_system32f3x.s — startup code, contains a table of interrupt vectors, etc.

#include "main.h"
#include "stm32f3xx_hal.h"
void SystemClock_Config(void); /*Declare clock configuration functions*/
static void MX_GPIO_Init(void); /*Initialize I/O*/
int main (void) (
/*Reset of all peripherals, Initializes the Flash interface and the Systick.*/
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
while (1) (
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_8); //Switch the state of the leg
HAL_Delay(100); )
}
void SystemClock_Config (void){
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig (&RCC_OscInitStruct) != HAL_OK){

}
/**Initializes the CPU, AHB and APB buses clocks */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig (&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK){
_Error_Handler(__FILE__, __LINE__);
}
/**Configure the Systick interrupt time*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/** Configure pins as Analog Input Output EVENT_OUT EXTI */
static void MX_GPIO_Init (void){
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOE_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin (GPIOE, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
/*Configure GPIO pins: PE8 PE9 PE10 PE11 PE12 PE13 PE14 PE15 */
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed ​​= GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
}
void _Error_Handler(char * file, int line){
while (1) (
} }
#ifdef USE_FULL_ASSERT

Void assert_failed (uint8_t* file, uint32_t line){
}
#endif
Here, just like in the previous example, we can view the description of each function in the documentation, for example UM1786 User Manual Description of STM32F3 HAL and low-layer drivers.

We can summarize that the first option, using CMSIS, is less cumbersome. There is documentation for each library. In subsequent projects, we will use HAL and CMSIS using the STCube configuration program and, if possible, use registers directly, without software wrappers. Let's stop there today. In the next article we will look at the basic principles of construction smart home. Bye everyone.




Top