STM32F407 (STM32F4-DISCOVERY) - Enfoque no estándar - Biblioteca estándar parte 1. Configuración de STM32F10x SPL usando definiciones de macro

Hasta este punto, hemos utilizado la biblioteca estándar del núcleo: CMSIS. Para configurar un puerto en el modo de funcionamiento deseado, teníamos que recurrir a buscar el registro responsable de una determinada función, y también buscar en un documento de gran tamaño otra información relacionada con este proceso. Las cosas se volverán aún más dolorosas y rutinarias cuando empecemos a trabajar con un temporizador o ADC. El número de registros allí es mucho mayor que el de los puertos de E/S. Ajuste manual lleva mucho tiempo y aumenta las posibilidades de cometer un error. Por lo tanto, muchas personas prefieren trabajar con la biblioteca de periféricos estándar: StdPeriph. ¿Qué da? Es simple: el nivel de abstracción aumenta, no es necesario entrar en la documentación y pensar en los registros en su mayor parte. En esta biblioteca, todos los modos de funcionamiento y parámetros de la periferia MK se describen en forma de estructuras. Ahora, para configurar un dispositivo periférico, solo necesita llamar a la función de inicialización del dispositivo con una estructura completa.

A continuación se muestra una imagen con una representación esquemática de los niveles de abstracción.

Trabajamos con el CMSIS (que está "más cerca" del núcleo) para mostrar cómo funciona el microcontrolador. El siguiente paso es la biblioteca estándar, que aprenderemos a usar ahora. Luego vienen los controladores de dispositivos. Se entienden como archivos *.c \ *.h que proporcionan una cómoda interfaz de software para controlar cualquier dispositivo. Por ejemplo, en este curso le proporcionaremos controladores para el chip max7219 y el módulo WiFi esp8266.

Un proyecto estándar incluirá los siguientes archivos:


En primer lugar, por supuesto, estos son los archivos CMSIS que permiten que la biblioteca estándar funcione con el kernel, ya hemos hablado de ellos. En segundo lugar, los archivos de biblioteca estándar. Y en tercer lugar, los archivos de usuario.

Los archivos de la biblioteca se pueden encontrar en la página dedicada al MK de destino (para nosotros es stm32f10x4), en la sección Recursos de diseño(en CooCox IDE, estos archivos se descargan del repositorio del entorno de desarrollo). Cada periférico corresponde a dos archivos: encabezado (*.h) y código fuente(*.C). Descripción detallada se puede encontrar en el archivo de soporte, que se encuentra en el archivo de la biblioteca en el sitio web.

  • stm32f10x_conf.h: archivo de configuración de la biblioteca. El usuario puede conectar o desconectar módulos.
  • stm32f10x_ppp.h: archivo de encabezado periférico. En lugar de ppp puede haber gpio o adc.
  • stm32f10x_ppp.c: controlador de dispositivo periférico escrito en lenguaje C.
  • stm32f10x_it.h: archivo de encabezado que incluye todos los posibles controladores de interrupciones (sus prototipos).
  • stm32f10x_it.c es un archivo de código fuente de plantilla que contiene una rutina de servicio de interrupción (ISR) para situaciones de excepción en Cortex M3. El usuario puede añadir sus propios ISR para los periféricos utilizados.

La biblioteca estándar y los periféricos tienen una convención para nombrar funciones y notación.

  • PPP es un acrónimo de periféricos, como ADC.
  • Archivos de sistema, encabezado y código fuente: comience con stm32f10x_.
  • Las constantes utilizadas en un archivo se definen en ese archivo. Las constantes utilizadas en más de un archivo se definen en archivos de encabezado. Todas las constantes de la biblioteca periférica suelen escribirse en MAYÚSCULAS.
  • Los registros se tratan como constantes y también se denominan letras MAYÚSCULAS.
  • Los nombres de funciones específicas de periféricos incluyen un acrónimo, como USART_SendData() .
  • Para configurar cada dispositivo periférico se utiliza la estructura PPP_InitTypeDef, la cual se pasa a la función PPP_Init().
  • Para desinicializar (establecer el valor predeterminado), puede usar la función PPP_DeInit().
  • La función que permite habilitar o deshabilitar periféricos se llama PPP_Cmd().
  • La función de habilitar/deshabilitar interrupciones se llama PPP_ITConfig.

CON Lista llena puede volver a consultar el archivo de soporte de la biblioteca. ¡Ahora reescribamos el parpadeo del LED usando la biblioteca de periféricos estándar!

Antes de comenzar a trabajar, miremos el archivo stm32f10x.h y busquemos la línea:

#definir USE_STDPERIPH_DRIVER

Si configura el proyecto desde cero utilizando archivos de biblioteca del archivo descargado, deberá descomentar esta línea. Le permitirá utilizar la biblioteca estándar. Esta definición (macro) ordenará al preprocesador que incluya el archivo stm32f10x_conf.h:

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

Este archivo contiene módulos. Si solo necesita algunos específicos, desactive el resto, esto ahorrará tiempo durante la compilación. Nosotros, como habrás adivinado, necesitamos módulos RTC y GPIO (sin embargo, en el futuro también necesitaremos _bkp.h, _flash, _pwr.h, _rtc.h, _spi.h, _tim.h, _usart.h):

#incluye "stm32f10x_flash.h" // para init_pll() #incluye "stm32f10x_gpio.h" #incluye "stm32f10x_rcc.h"

Como la última vez, primero debe habilitar el reloj del puerto B. Esto se hace mediante la función declarada en stm32f10x_rcc.h:

Void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

La enumeración FunctionalState se define en stm32f10x.h:

Typedef enumeración (DISABLE = 0, ENABLE =! DISABLE) Estado funcional;

Declaremos una estructura para configurar nuestra pierna (puede encontrarla en el archivo stm32f10x_gpio.h):

LED GPIO_InitTypeDef;

Ahora tenemos que completarlo. Veamos el contenido de esta estructura:

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

Todas las enumeraciones y constantes necesarias se pueden encontrar en el mismo archivo. Entonces la función init_leds() reescrita tomará la siguiente forma:

Void led_init() ( // Habilitar el cronometrado RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // Declarar la estructura y llenarla GPIO_InitTypeDef LED; LED.GPIO_Pin = GPIO_Pin_0; LED.GPIO_Speed ​​​​= GPIO_Speed_2MHz; LED.GPIO_Mode = GPIO_Mode_ Out_PP; // Inicialice el puerto GPIO_Init(GPIOB, &LED); )

Reescribamos la función main():

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

Lo principal es tener una idea del orden de inicialización: encender el reloj periférico, declarar la estructura, completar la estructura, llamar al método de inicialización. Otros dispositivos periféricos suelen estar configurados de manera similar.

En esta publicación, intentaré centrarme en los puntos principales para comenzar rápidamente con los microcontroladores STM32F10x basados ​​​​en la biblioteca de periféricos estándar del fabricante STMicroelectronics.

El artículo utilizará Eclipse CDT como entorno de desarrollo. Dado que el foco principal estará en el código del programa, puedes realizar todas las manipulaciones de forma segura en Code::Blocks.

La estructura general del proyecto para microcontroladores ARM se describe en mi artículo.

Aquí les recordaré brevemente que para crear un proyecto para microcontroladores ARM (STM32F10x en particular), necesitará un script de vinculación y un archivo C-Startup.

Un script de enlace es un archivo con instrucciones para colocar el código del programa y los datos en la memoria del microcontrolador. Puede ordenar que el código de su programa se cargue en la memoria Flash del programa o en la memoria de datos SRAM.

Los microcontroladores con diferentes cantidades de memoria de programas y datos requieren diferentes scripts de diseño. Se pueden obtener del fabricante del microcontrolador: STMicroelectronics.
Desempaquete la biblioteca periférica estándar STM32F10x del archivo ARM_Toolchain/Lib/stm32f10x_stdperiph_lib.zip.
Contiene proyectos de ejemplo para varios entornos de desarrollo (IAR EWB, Keil uVision, Atollic True Studio, etc.). El más cercano para nosotros es Atollic True Studio, ya que es una modificación de Eclipse.
Vaya al directorio Project/StdPeriph_Template/TrueSTUDIO, allí hay varios subdirectorios cuyos nombres corresponden a los nombres de las placas de desarrollo STM3210x-EVAL.

Descubra cuál de estas placas utiliza la misma línea de microcontroladores que la suya. Copie el archivo stm32_flash.ld del directorio apropiado a su proyecto.

También es posible crear un script universal en el que sólo se cambiará la cantidad de memoria de programa y datos de acuerdo con el microcontrolador utilizado.

El código de inicio (C-Startup) para microcontroladores STM32 se puede escribir en C o Assembler.
Aunque la biblioteca de periféricos estándar STM32F10x (abreviada STM32F10x SPL) a menudo es criticada por sus errores, es la forma más fácil de comenzar rápidamente al iniciar la programación STM32.
Pero siempre quieres que haya algún tipo de alternativa. De hecho, hay muchos de ellos, por ejemplo, programación en lenguaje ensamblador :)

Este es el camino más difícil e inútil. La segunda forma es utilizar la biblioteca CMSIS, que proporciona sintaxis para acceder a estructuras del lenguaje C para acceder a varios periféricos de microcontroladores. La forma más sencilla y lógica (en mi opinión) es utilizar bibliotecas.

Si se opone categóricamente al STM32F10x SPL, existe otra alternativa especialmente para usted: la biblioteca libopencm3. En él, la mayor parte de los ejemplos se concentran en la serie principal de microcontroladores STM32F10x, pero es sólo cuestión de tiempo antes de que aparezcan ejemplos para otras series (STM32F2xx/4xx). Siempre puedes unirte al proyecto libopencm3 y acelerar este proceso.

El estándar CMSIS también es opcional para su uso en sus programas.
Puede prescindir de él dedicando algo de esfuerzo y tiempo a implementar el nivel HAL (Capa de abstracción de hardware) en el lenguaje de programación C.

En algunos casos este método puede ser el único. de manera accesible. Por ejemplo, su organización utiliza chips personalizados basados ​​en núcleos informáticos desarrollados por ARM y periféricos específicos de la industria.

O necesita implementar software en C para microcontroladores con núcleo ARM9, para lo cual los fabricantes se centran en utilizar productos listos para usar. sistemas operativos(Linux, QNX, Windows CE), por lo tanto, los fabricantes no pueden proporcionar bibliotecas para programar en lenguaje C en forma pura o en combinación con un RTOS más liviano.

Afortunadamente, los fabricantes de microcontroladores basados ​​​​en el núcleo Cortex-M3 ofrecen a los desarrolladores una gran cantidad de bibliotecas de códigos. Esto también se aplica a los microcontroladores STM32.
Continuaremos nuestra consideración de la biblioteca STM32F10x SPL. Lo consideraremos usando un ejemplo.
Puedes abrir este ejemplo o crear tu propio proyecto desde cero para comprender mejor todo el proceso de lo que está sucediendo.

Para el segundo caso, enumeraré los pasos necesarios:

  • Crea un nuevo proyecto vacío en Eclipse
  • Copie el script de diseño y el archivo de inicio en el proyecto.
  • Crear un nuevo Makefile o copiar una plantilla
  • Cuando utilice el Makefile de mi ejemplo como plantilla, debe crear los directorios src, inc, bin, obj dentro del proyecto y crear los subdirectorios Debug y Release dentro de los directorios bin y obj.
  • Copie los archivos fuente y de encabezado necesarios de las bibliotecas CMSIS y STM32F10x SPL.
  • Realice los cambios necesarios en la sección de configuración de usuario de la plantilla Makefile, si se utiliza.
  • Cree nuevos objetivos "Debug", "cleanDebug", "Release", "cleanRelease", "Program" en la ventana "crear objetivo" de Eclipse.
  • Inicie el objetivo "Depurar" y supervise su ejecución en la ventana "Consola".

Para comprender mejor el material, dividí el artículo en varios párrafos independientes, cada uno de los cuales describe solo un aspecto del trabajo con la biblioteca STM32F10x SPL.

Configuración de STM32F10x SPL usando definiciones de macro

Para configurar la biblioteca se utilizan valores macro predefinidos, que consideraremos ahora.
Se pueden configurar dentro de archivos de encabezado usando una directiva de preprocesador. #definir o pasar los valores de las definiciones de macros a través de la clave -D Compilador GCC.
En mi ejemplo utilizo el segundo método.
En la variable Makefile DEFINIR contiene las macros necesarias para compilar la biblioteca STM32F10x SPL.
Definición de macros STM32F10X_MD especifica si el microcontrolador utilizado pertenece a la línea Densidad media.
Esto incluye microcontroladores con memoria Flash de 64 a 128 kB.
La siguiente tabla enumera los nombres de las macros para diferentes series de microcontroladores:

Nombre de la serie Macro Descripción
Línea Value de baja densidad STM32F10X_LD_VL con capacidad de memoria Flash 16 - 32 kB
Baja densidad STM32F10X_LD
con capacidad de memoria Flash 16 - 32 kB
Línea Value de densidad media STM32F10X_MD_VL Memoria flash
64 - 128kB
Densidad media STM32F10X_MD Microcontroladores de las series STM32F101xx, STM32F102xx, STM32F103xx con memoria Flash 64 - 128 kB
Línea Value de alta densidad STM32F10X_HD_VL Microcontroladores de la serie STM32F100xx con volumen.
Flash - memoria 256 - 512kB
Alta densidad STM32F10X_HD con volumen
Memoria flash 256 - 512 kB
Densidad XL STM32F10X_XL
Memoria flash 512 - 1024 KB
Línea de conectividad STM32F10X_CL

Para configurar la frecuencia de reloj del microcontrolador, debe descomentar la macro con el valor de frecuencia de reloj requerido en el archivo system_stm32f10x.c.

#si está definido (STM32F10X_LD_VL) || (definido STM32F10X_MD_VL) || (definido 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 */ /* #definir SYSCLK_FREQ_48MHz 48000000 */ /* #definir SYSCLK_FREQ_56MHz 56000000 * / #definir SYSCLK_FREQ_72MHz 72000000 #endif

#si está definido (STM32F10X_LD_VL) || (definido STM32F10X_MD_VL) || (definido STM32F10X_HD_VL)

/* #definir SYSCLK_FREQ_HSE HSE_VALUE */

#definir SYSCLK_FREQ_24MHz 24000000

#demás

/* #definir SYSCLK_FREQ_HSE HSE_VALUE */

/* #definir SYSCLK_FREQ_24MHz 24000000 */

/* #definir SYSCLK_FREQ_36MHz 36000000 */

/* #definir SYSCLK_FREQ_48MHz 48000000 */

/* #definir SYSCLK_FREQ_56MHz 56000000 */

#definir SYSCLK_FREQ_72MHz 72000000

#terminara si

Uso previsto resonador de cuarzo con una frecuencia de 8 MHz para todos los principales
serie de microcontroladores, excepto la línea Conectividad, para la cual es necesario instalar un resonador de cuarzo de 25 MHz.
Si utiliza resonadores de cuarzo con otros valores de frecuencia, deberá cambiar el valor de la macro HSE_VALUE en el archivo de encabezado stm32f10x.h y adaptar todas las funciones dependientes en consecuencia.
El propósito de la macro USE_STDPERIPH_DRIVER no es difícil de adivinar: utilizar la biblioteca de periféricos estándar STM32F10x.
USE_FULL_ASSERT: utilice la macro ASSERT para depurar el programa.

Usando la macro afirmar_param en la biblioteca

Todas las funciones de la biblioteca STM32F10x SPL utilizan la macro afirmar_param para verificar sus argumentos.
Esta macro verifica una expresión que involucra el argumento de la función que se está probando para determinar si es igual a cero. Si el valor de la expresión es cero, entonces se llama a la función de manejo de errores de argumentos afirmar_failed; de lo contrario (la expresión no es cero), la verificación del argumento se realiza correctamente.
Necesita implementar la función afirmar_failed en su programa.
Muestra el mensaje de error, el nombre del archivo y el número de la línea de código que causó el error.
La macro debug_printf puede generarse a través de USART utilizando la biblioteca estándar new_lib o, por ejemplo, la biblioteca del Sr. Chen.

#define debug_printf xprintf /* printf */ #ifdef USE_FULL_ASSERT void afirmar_failed(archivo uint8_t*, línea uint32_t) ( debug_printf("Valor de parámetros incorrectos: archivo %s en línea %d\r\n", archivo, línea (int)) ; mientras (1) ( ) )/* afirmar_failed */ #endif/*USE_FULL_ASSERT*/

#define debug_printf xprintf /* printf */

#ifdef USE_FULL_ASSERT

void afirmar_failed (uint8_t * archivo, línea uint32_t)

debug_printf( "Valor de parámetros incorrecto: archivo %s en la línea %d\r\n", archivo, (int) línea);

mientras(1)

) /* afirmar_falló */

#endif/*USE_FULL_ASSERT*/

La función afirmar_failed implementada en su código se usa solo cuando se declara la macro USE_FULL_ASSERT. De lo contrario, todo el código de depuración se excluye del código fuente. Esta funcionalidad se implementa en el archivo de encabezado de configuración de la biblioteca del controlador stm32f10x_conf.h.

#ifdef USE_FULL_ASSERT #define afirmar_param(expr) ((expr) ? (void)0: afirmar_failed((uint8_t *)__FILE__, __LINE__)) void afirmar_failed(archivo uint8_t*, línea uint32_t); #else #define afirmar_param(expr) ((void)0) #endif /* USE_FULL_ASSERT */

#ifdef USE_FULL_ASSERT

#define afirmar_param(expr) ((expr)? (void)0: afirmar_failed((uint8_t *)__FILE__, __LINE__))

void afirmar_failed (archivo uint8_t *, línea uint32_t);

#demás

#definir afirmar_param(expr) ((void)0)

#endif /* USE_FULL_ASSERT */

No hay mucho que explicar aquí. Veamos un ejemplo del uso de afirmar_param.

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

void set_param (uint8_t * parámetro, valor uint8_t)

afirmar_param (param! = NULL);

* parámetro = valor ;

) /*set_param*/

La función establece el valor del parámetro mediante un puntero pasado como argumento. Si la macro USE_FULL_ASSERT no está declarada, entonces podemos asumir que las líneas
afirmar_param(param != NULL) simplemente no está en el código; de lo contrario, el parámetro se verifica en esta definición.
Si el puntero no está definido, entonces el valor param != NULL será falso y se ejecutará la función afirmar_failed, que generará el nombre del archivo y el número de línea con el error a través de USART, y luego se repetirá, evitando así que el valor sea asignado a una dirección indefinida en la memoria.
No es necesario que utilice la macro afirmar_param en su código, pero sí en el código de la biblioteca.
STM32F10x SPL se utiliza en todas partes.
La función set_param se puede implementar con verificación de errores de argumentos sin usar afirmar_param.

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

#definir ERROR (-1)

#definir Aceptar (0)

int set_param (uint8_t * parámetro, valor uint8_t)

int r = ERROR;

si (parámetro == NULL)

devolver r ;

* parámetro = valor ;

r=bien;

devolver r ;

) /*set_param*/

Archivo C-Startup en la biblioteca STM32F10x SPL

En el código de inicio, se inicializa inicialmente el microcontrolador, se configura la pila, se restablece la sección BSS y se llama a la función principal main().
El código inicial no tiene relación directa con la biblioteca STM32F10x SPL. Sin embargo, en este código de arranque, antes de llamar a la función main() del programa, se llama a la función de inicialización del microcontrolador SystemInit(), que forma parte de CMSIS.
Se puede encontrar fácilmente en la biblioteca CMSIS.
Vaya al directorio Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/TrueSTUDIO y copie el archivo requerido. Todo lo que queda es averiguar a qué línea pertenece el microcontrolador utilizado en su proyecto.
Para ello, mira la siguiente tabla:

Nombre de la serie Nombre del archivo Descripción
Línea Value de baja densidad startup_stm32f10x_ld_vl.s Microcontroladores de la serie STM32F100xx con volumen.
Memoria flash 16 - 32kB
Baja densidad startup_stm32f10x_ld.s Serie de microcontroladores STM32F101xx, STM32F102xx, STM32F103xx.
con capacidad de memoria Flash 16 - 32 kB
Línea Value de densidad media startup_stm32f10x_md_vl.s serie de microcontroladores STM32F100xx
Densidad media startup_stm32f10x_md.s Serie de microcontroladores STM32F101xx, STM32F102xx, STM32F103xx.
con capacidad de memoria Flash 64 - 128 kB
Línea Value de alta densidad startup_stm32f10x_hd_vl.s serie de microcontroladores STM32F100xx
Alta densidad startup_stm32f10x_hd.s Serie de microcontroladores STM32F101xx, STM32F103xx.
con capacidad de memoria Flash 256 - 512 kB
Densidad XL inicio_stm32f10x_xl.s Serie de microcontroladores STM32F101xx, STM32F103xx.
con capacidad de memoria Flash 512 - 1024 kB
Línea de conectividad inicio_stm32f10x_cl.s Microcontroladores de las series STM32F105xx y STM32F107xx.

El archivo de inicio contiene los nombres de los controladores de vectores de interrupción y excepción, pero solo se implementa el controlador de vector de reinicio, dentro del cual se realiza toda la inicialización inicial antes de llamar a la función main().
La implementación de todos los demás controladores de excepciones es responsabilidad del programador de la aplicación. Si su programa no utiliza ningún controlador, no es necesario registrarlo. Si se produce una excepción, se utilizará el controlador predeterminado: repetir el código del programa.

Composición de la biblioteca CMSIS

Como se escribió anteriormente en esta publicación, la biblioteca CMSIS proporciona acceso a módulos periféricos de microcontroladores que utilizan elementos de estructuras del lenguaje C.
La implementación de esta biblioteca se divide en dos partes. La primera parte proporciona acceso a la periferia del núcleo Cortex-M3 y la segunda parte proporciona acceso a la periferia. modelo específico microcontrolador.
Dado que el estándar CMSIS es el mismo para todos los microcontroladores con núcleo Cortex-M3, la implementación de la primera parte será la misma para todos los fabricantes, pero la segunda parte será diferente para cada fabricante.
CMSIS incluye varios archivos de encabezado y fuente. La primera parte incluye los archivos:

  • núcleo_cm3.h
  • núcleo_cm3.c

La segunda parte de CMSIS incluye el archivo C-Startup, así como los siguientes archivos:

  • stm32f10x.h
  • sistema_stm32f10x.h
  • sistema_stm32f10x.c

El archivo de encabezado stm32f10x.h contiene definiciones de macros para acceder a módulos periféricos de microcontroladores stm32f10x.
Los archivos system_stm32f10x.h y system_stm32f10x.c implementan la inicialización inicial del microcontrolador.

Composición y configuración de la biblioteca STM32F10x SPL

La biblioteca consta de archivos fuente y de encabezado con el mismo nombre que los módulos periféricos con el prefijo stm32f10x_.
Por ejemplo, la implementación de la interacción con el módulo USART está contenida en los archivos stm32f10x_usart.h y stm32f10x_usart.c.
Existen convenciones para nombrar elementos de la biblioteca y ciertas reglas de codificación, que se describen en la documentación.
La biblioteca contiene la implementación de controladores para módulos de microcontroladores periféricos.
Los nombres de los elementos de la biblioteca utilizan las siguientes siglas para módulos periféricos:

Acrónimo módulo periférico
CAD Conversor analógico a digital
BKP registros de respaldo
PODER Interfaz CAN
CCA controlador de consumo
CDN módulo de cálculo de suma de comprobación
CAD convertidor digital a analógico
DBGMCU depuración del microcontrolador
DMA controlador de acceso directo a memoria
EXTI controlador de interrupción externo
FMC controlador de memoria externa
DESTELLO memoria flash de programa
GPIO Puertos de E/S de uso general
I2C interfaz I2C
I2S Interfaz I2S (sonido)
IWDG temporizador de vigilancia independiente
NVIC controlador de interrupciones anidado
PWR controlador de potencia
RCC controlador de reinicio y reloj
RTC controlador en tiempo real (reloj)
SDIO Interfaz SDIO
SPI interfaz SPI
sistematick temporizador del sistema
tim temporizador básico o avanzado
USART serie universal síncrona-asíncrona
transceptor
WWDG perro guardián de la ventana

A partir de estas siglas se forman los nombres de los módulos de software de la biblioteca. No es necesario utilizar todos los módulos de la biblioteca.
Para utilizar solo los módulos necesarios en el proyecto, se debe configurar la biblioteca.
Para estos fines, cada proyecto que utilice la biblioteca STM32F10x SPL debe tener un archivo de encabezado stm32f10x_conf.h.

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

#incluir "stm32f10x_gpio.h"

//#incluye "stm32f10x_i2c.h"

//#incluye "stm32f10x_iwdg.h"

//#incluye "stm32f10x_pwr.h"

#incluir "stm32f10x_rcc.h"

Para habilitar el módulo requerido, debe descomentar la directiva #incluir con los archivos de encabezado correspondientes.
El archivo de encabezado stm32f10x_conf.h está incluido en stm32f10x.h, por lo que para usar las funciones de la biblioteca STM32F10x SPL, solo necesita incluir un archivo de encabezado stm32f10x.h en su código fuente.

// en el archivo stm32f10x.h #ifdef USE_STDPERIPH_DRIVER #include "stm32f10x_conf.h" #endif

Repito que el proyecto también debe definir las macros USE_STDPERIPH_DRIVER, USE_FULL_ASSERT y una macro que especifique la serie del microcontrolador utilizado (por ejemplo, STM32F10X_MD para la línea de densidad Media).
Si utiliza el valor de frecuencia de cuarzo estándar y el controlador funciona a una frecuencia de reloj máxima de 72 MHz, no tendrá que cambiar nada más.
Debe agregar una lista de archivos de biblioteca para compilar en Makefile.
Por ejemplo:

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

SRC += stm32f10x_rcc. C

SRC += stm32f10x_gpio. C

Usando la biblioteca STM32F10x SPL. Mecanismos de trabajo

Para comenzar a programar utilizando la biblioteca de periféricos, la forma más sencilla es consultar los ejemplos suministrados con la biblioteca. Pero aún así, para comprender el código de estos ejemplos, debes tener conocimientos básicos de la sintaxis y el uso de la biblioteca.
Todos los módulos de microcontroladores periféricos enumerados anteriormente están inicialmente desactivados, no se les suministra señal de reloj y no consumen electricidad.
Para utilizar un módulo periférico, primero debe proporcionarle una señal de reloj. La señal del reloj es suministrada por el módulo de reinicio y reloj RCC.
A estos efectos, la biblioteca tiene las siguientes funciones:

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

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_PPPx, HABILITAR);

RCC_APB2PeriphClockCmd (RCC_APB2Periph_PPPx, HABILITAR);

RCC_APB1PeriphClockCmd (RCC_APB1Periph_PPPx, HABILITAR);

Aquí PPP indica el nombre del módulo actónimo (por ejemplo, ADC o USART) y x es el número del módulo periférico.
En primer lugar, debe averiguar a qué bus está conectado el módulo que está utilizando.
En total, los microcontroladores con arquitectura central Cortex-M3 tienen tres buses:
bus de instrucciones, bus de datos y bus de sistema. El bus de instrucciones conecta el núcleo a la memoria del programa Flash. Los buses de datos y del sistema se combinan en una matriz de bus AHB (ARM Hi-Speed ​​​​Bus), que opera en la frecuencia central. Sin embargo, la frecuencia del bus AHB se puede reducir instalando divisores. El bus AHB conecta dispositivos de alta velocidad como el núcleo y el módulo DMA.
Los dispositivos de E/S se conectan al bus AHB a través de los buses intermedios APB1 y APB2 (ARM Peripheral Bus).
La frecuencia máxima de funcionamiento del bus APB2 es 72 MHz, la frecuencia del bus APB1
Limitado a 36 MHz.
Puede averiguar a cuál de los buses está conectado el módulo periférico que está utilizando en la documentación o buscar en el archivo de encabezado stm32f10x_rcc.h.
Abra este archivo y busque los valores RCC_AHBPeriph, RCC_APB1Periph y RCC_APB2Periph en secuencia.

#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) #definir RCC_AHBPeriph_CRC ((uint32_t)0x00000040)

#definir RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001)

#definir RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002)

#definir RCC_AHBPeriph_SRAM ((uint32_t)0x00000004)

#definir RCC_AHBPeriph_FLITF ((uint32_t)0x00000010)

#definir RCC_AHBPeriph_CRC ((uint32_t)0x00000040)

Por los nombres de las macros determinamos qué módulos están conectados a qué buses. También puedes utilizar el sentido común para determinar qué neumático pertenece a uno de los tres. Por ejemplo, el módulo USART es un dispositivo de entrada/salida, lo que significa que está conectado a uno de los buses APB. USART es una interfaz de velocidad bastante baja, por lo que probablemente esté conectada al bus APB1.

#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)

Después de enviar una señal de reloj al módulo periférico, puede configurar sus parámetros llamando a la función de inicialización:

PPP_Init(PPP, &PPP_InitEstructura);

PPP_Init (PPP, & amp; PPP_InitStructure);

Dado que se deben pasar muchos parámetros a la función de inicialización para inicializar un módulo periférico, se utiliza un puntero a una estructura como argumento. La estructura misma con los parámetros de inicialización debe crearse en la memoria antes de llamar a la función de inicialización; a los elementos de la estructura se les deben asignar los valores necesarios:

PPP_InitTypeDef PPP_InitStructure = (val1, val2, ..., valN);/* inicialización de la estructura cuando se declara */

Primero puedes crear una estructura y luego asignar los valores necesarios a sus elementos:

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

PPP_InitTypeDef PPP_InitStructure;

PPP_InitEstructura. miembro1 = val1;

PPP_InitEstructura. miembro2 = val2;

PPP_InitEstructura. miembroN = valN;

Veamos un ejemplo del proyecto stm32f10xQuickstart:

GPIO_InitTypeDef GPIO_InitStructure; #ifdef USE_STM32H_103 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, HABILITAR); 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, HABILITAR);

GPIO_InitStructure. GPIO_Pin = GPIO_Pin_12;

GPIO_InitStructure. GPIO_Velocidad = GPIO_Velocidad_50MHz;

GPIO_InitStructure. GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOC y GPIO_InitStructure);

A los elementos de la estructura GPIO_InitStructure se les asigna el valor del número de pin, modo y velocidad del puerto.
Al llamar a la función GPIO_Init, se inicializa la línea 12 del puerto GPIOC.
El primer argumento de la función GPIO_Init es un puntero al área de memoria del periférico GPIOC, convertido en un puntero a una estructura 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 u int32_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

#definir GPIOC ((GPIO_TypeDef *) GPIOC_BASE)

#definir GPIOC_BASE (APB2PERIPH_BASE + 0x1000)

#definir APB2PERIPH_BASE (PERIPH_BASE + 0x10000)

#definir PERIPH_BASE ((uint32_t)0x40000000)

estructura typedef

IO uint32_t CRL;

IOuint32_tCRH;

IO uint32_tIDR;

IO uint32_t ODR;

IO uint32_t BSRR;

IO uint32_t BRR;

IO uint32_t LCKR;

) GPIO_TypeDef;

La estructura GPIO_InitStructure es de tipo GPIO_InitTypeDef, descrita en el archivo de encabezado
stm32f10x_gpio.h:

//stm32f10x_gpio.h estructura typedef ( uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; )GPIO_InitTypeDef; enumeración typedef (GPIO_Speed_10MHz = 1, GPIO_Speed_2MHz, GPIO_Speed_50MHz)GPIOSpeed_TypeDef; enumeración typedef (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

estructura typedef

uint16_t GPIO_Pin;

GPIOSpeed_TypeDef GPIO_Speed ​​​​;

GPIOMode_TypeDef GPIO_Mode;

) GPIO_InitTypeDef;

enumeración typedef

GPIO_Speed_10MHz = 1,

GPIO_Velocidad_2MHz,

GPIO_Velocidad_50MHz

) GPIOSpeed_TypeDef;

enumeración typedef

(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;

Como puede ver, los tipos de datos de la estructura inicializada se pueden utilizar como tipos personalizados, como GPIOSpeed_TypeDef, y tipos de datos con valores específicos para facilitar la inicialización de registros periféricos, como GPIOMode_TypeDef.
Se asignan 4 bits para configurar cada pin GPIO.
La siguiente imagen muestra el formato del bit cero de GPIO:

Modo – modo de funcionamiento de salida (entrada/salida). Más precisamente, estos valores son ligeramente mayores; los puertos configurados como puertos de salida tienen una limitación en la frecuencia máxima de la señal de salida.

Modo Descripción
00 entrada
01 frecuencia de salida hasta 10 MHz
10 frecuencia de salida hasta 2 MHz
11 frecuencia de salida hasta 50 MHz

CNF – bits de configuración de salida. Depende del modo de funcionamiento:

Esté de acuerdo en que con esta estructura del registro de configuración de pines, configurar usted mismo todos los bits para la configuración será extremadamente inconveniente. Será mucho más fácil hacer esto usando la función de biblioteca GPIO_Init.
Después de inicializar el módulo periférico, debe activarse usando la función PPP_Cmd:

PPP_Cmd(PPP, HABILITAR);

PPP_Cmd(PPP, HABILITAR);

Esta función no existe para los módulos GPIO; después de la inicialización, puede usar inmediatamente los pines GPIO. Hay que recordar que la biblioteca sólo proporciona una interfaz para el hardware del microcontrolador. Si el módulo de hardware no tiene un indicador de activación/desactivación, entonces la llamada a la función PPP_Cmd(PPP, HABILITAR) imposible.
Para controlar el estado del pin GPIOx en modo de salida y leer el valor en modo de entrada o salida, la biblioteca proporciona las siguientes funciones:

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);

anular GPIO_SetBits (GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin);

anular 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) ;

El resto de módulos periféricos se configuran y funcionan de la misma forma. Sin embargo, existen algunas diferencias debido a las características específicas del módulo de hardware específico, por lo que le recomiendo encarecidamente que primero vea ejemplos de uso del módulo seleccionado para la biblioteca STM32F10x SPL.

Manejo de interrupciones y excepciones.

El núcleo Cortex-M3 incluye un controlador de interrupciones vectorizado anidado. El controlador admite hasta 240 fuentes que pueden provocar interrupciones en el núcleo del procesador. La cantidad de vectores de 240 posibles que se implementan en un modelo de microcontrolador específico depende del fabricante. Los microcontroladores Stm32f10x pueden tener hasta 43 de estos vectores. Estas líneas de interrupción se denominan enmascarables. Además, hay 15 vectores de interrupción del núcleo Cortex-M3 y una interrupción EXTI externa no enmascarable.
El controlador admite interrupciones anidadas, donde puede ocurrir otra interrupción dentro de un controlador. En este sentido, cada fuente de interrupción tiene su propia prioridad. Se admiten 16 niveles de prioridad de interrupción.
Los vectores de interrupción del núcleo Cortex-M3 tienen los valores de prioridad más altos.
Los tres niveles de interrupción más altos están asignados a vectores y no se pueden cambiar:

Número Manipulador Una prioridad Descripción
1 Reiniciar_Handler -3 (más alto) Restablecer vectores
2 NMI_Handler -2 Interrupción no enmascarable
3 HardFault_Handler -1 Condiciones de emergencia

A todos los demás vectores de interrupción se les pueden asignar niveles de prioridad de 0 a 15.
El nivel de prioridad más alto corresponde a un valor más bajo. El nivel de prioridad se puede asignar no sólo a un vector individual, sino también a un grupo completo de vectores. Esta característica facilita el trabajo con una gran cantidad de vectores de interrupción.
Para configurar el grupo de prioridad, se utiliza una función de la biblioteca STM32F10x SPL.

Durante mucho tiempo, incluso mucho tiempo, no ha habido artículos nuevos en nuestro artículo, así que es hora de ponerse al día 😉 Hoy comenzaremos a estudiar el STM32F4. Y, probablemente, comenzaremos creando un nuevo proyecto para estos controladores, aunque, para ser honesto, no quería escribir un artículo sobre eso, porque nuevo proyecto aquí se crea, en principio, de la misma manera que para STM32F103 (). Pero todavía sucede que surgen algunas dificultades con el STM32F4, así que, sin embargo, consideremos este proceso en detalle)

Entonces, lancemos Keil, creemos un nuevo proyecto... Proyecto -> Nuevo Proyecto uVision. Guardamos el nuevo proyecto en alguna carpeta, y luego se nos pedirá que seleccionemos el microcontrolador a utilizar. Bueno, elijamos, que sea STM32F407VG:

Listo, en el cuadro de diálogo que aparece, haga clic en "Sí" y el primer archivo se agregará a nuestro proyecto - inicio_stm32f4xx.s. Al igual que antes, usaremos bibliotecas. CMSIS Y Biblioteca de periféricos estándar, pero, por supuesto, ya para controladores STM32F4xx. Así que definitivamente necesitamos descargarlos y agregar los archivos necesarios a nuestro proyecto aún vacío. Por cierto, más de una vez escuché de diferentes personas que se encontraron con algunas bibliotecas "no tan" para F4, e incluso el proyecto más simple no se puede armar. Yo mismo no he encontrado esto, sin embargo, aquí están las bibliotecas probadas que yo uso:

Entonces lo descargamos, todo está listo, ahora agregamos los archivos al proyecto. La imagen muestra lo que necesitará:

Bueno, la preparación está completa, ahora creemos un nuevo archivo .c, que contendrá nuestro código. Vamos a Archivo->Nuevo, se abre un archivo vacío en Keil, haga clic en Archivo->Guardar como y guárdelo con el nombre test.c, por ejemplo. Al guardar, no olvide especificar la extensión del archivo (.c). El archivo fue creado, genial, pero también necesitamos agregarlo a nuestro proyecto. Bueno, en realidad, no tiene nada de complicado 😉 Escribamos un programa de prueba vacío en este archivo:

#incluye "stm32f4xx.h" #incluye "stm32f4xx_rcc.h" #incluye "stm32f4xx_gpio.h" /*******************************************************************/ int principal() ( mientras (1 ) ( __NOP() ; ) ) /*******************************************************************/

Casi todo está listo, solo queda mirar la configuración del proyecto. Proyecto->Opciones para destino… Se abre una ventana con muchas pestañas, aquí solo nos interesan unas pocas. Abre la pestaña C/C++ y en el campo Definir escribimos:

Bueno, abajo en el campo debe agregar rutas a absolutamente todos los archivos incluidos en el proyecto. Después de completar este paso, puede presionar F7 (Compilar) y el proyecto se compilará sin errores ni advertencias. Como puedes ver, nada complicado)

Pero, en general, personalmente hago las cosas de forma un poco diferente. Mire la desventaja de este enfoque. Así que descargamos las bibliotecas CMSIS y SPL en algún lugar, agregamos archivos de estas carpetas, escribimos las rutas a los archivos, todo está bien. ¡PERO! El proyecto no se construirá en otra computadora, ya que todas las rutas son absolutas, es decir, apuntan a carpetas específicas en su computadora. Y en otra máquina tendrás que volver a realizar los pasos para crear un nuevo proyecto. Esto es un gran inconveniente. Por lo tanto, normalmente creo una carpeta separada para un nuevo proyecto, en ella creo subcarpetas para CMSIS, SPL y otras bibliotecas utilizadas, y en estas carpetas pongo todos los archivos que necesito en cada proyecto específico. Por ejemplo, creemos la carpeta STM32F4_Test para nuestro nuevo proyecto y las siguientes carpetas en ella:

Puse todos los archivos necesarios que agregamos al crear el proyecto al principio del artículo en las carpetas CMSIS y SPL. Ahora iniciamos Keil, creamos un nuevo proyecto y lo guardamos en nuestra subcarpeta Proyecto para que todos los archivos del proyecto estén en un solo lugar y no causen caos)

El proyecto ha sido creado, ahora, como antes, simplemente le agregamos todos los archivos de las carpetas STM32F4_CMSIS y STM32F4_SPL. Colocamos nuestro archivo .c de prueba con la función main() en la carpeta Fuente y también lo agregamos al proyecto. Todo lo que queda es configurar los ajustes =) Todo es igual: en el campo definir escribimos:

USE_STDPERIPH_DRIVER, STM32F4XX



Montamos el proyecto: no hay errores, ¡el vuelo es normal! En principio, al final obtuvimos lo mismo, pero ahora el proyecto se ensamblará inmediatamente en cualquier otra computadora sin ningún problema, y ​​esto es muy conveniente y útil) Absolutamente todos los archivos del proyecto ahora se encuentran cerca, en la misma carpeta, y los caminos se han vuelto relativos y no es necesario cambiarlos.
Eso es todo, de hecho, en un futuro próximo haremos algo para programar el STM32F4, definitivamente, ¡hasta pronto!;)

Proyecto completo del artículo de ejemplo:

Indiqué que la biblioteca estándar está conectada al sistema. De hecho, CMSIS está conectado, el sistema de representación estructural generalizada de MK, así como SPL, la biblioteca periférica estándar. Veamos cada uno de ellos:

CMSIS
Es un conjunto de archivos de encabezado y un pequeño conjunto de código para unificar y estructurar el trabajo con el núcleo y la periferia de MK. De hecho, sin estos archivos es imposible trabajar normalmente con MK. Puede obtener la biblioteca en la página de documentación adjunta para MK.
Esta biblioteca, según la descripción, fue creada para unificar interfaces al trabajar con cualquier MK de la familia Cortex. Sin embargo, en realidad resulta que esto sólo es cierto para un fabricante, es decir, Al cambiar a un microcontrolador de otra empresa, se ve obligado a estudiar sus periféricos casi desde cero.
Aunque los archivos que se relacionan con el núcleo del procesador MK son idénticos en todos los fabricantes (aunque solo sea porque tienen el mismo modelo de núcleo de procesador, proporcionado en forma de bloques IP por ARM).
Por lo tanto, trabajar con partes del núcleo como registros, instrucciones, interrupciones y unidades de coprocesador es estándar para todos.
En cuanto a la periferia, STM32 y STM8 (de repente) son casi similares, y esto también es parcialmente cierto para otros MK lanzados por ST. En la parte práctica mostraré lo fácil que es utilizar CMSIS. Sin embargo, las dificultades para utilizarlo están asociadas con la renuencia de las personas a leer la documentación y comprender el diseño de MK.

SPL
Biblioteca periférica estándar: biblioteca periférica estándar. Como sugiere el nombre, el propósito de esta biblioteca es crear una abstracción para la periferia de MK. La biblioteca consta de archivos de encabezado donde se declaran constantes legibles por humanos para configurar y trabajar con periféricos MK, así como archivos de código fuente recopilados en la propia biblioteca para operaciones con periféricos.
SPL es una abstracción de CMSIS, que presenta al usuario una interfaz común para todas las MCU no solo de un fabricante, sino en general para todas las MCU con un núcleo de procesador Cortex-Mxx.
Se cree que es más conveniente para principiantes, porque... le permite no pensar en cómo funcionan los periféricos, pero la calidad del código, la universalidad del enfoque y las limitaciones de las interfaces imponen ciertas restricciones al desarrollador.
Además, la funcionalidad de la biblioteca no siempre permite implementar con precisión la configuración de algunos componentes como USART (puerto serie universal síncrono-asincrónico) bajo ciertas condiciones. En la parte práctica, también describiré cómo trabajar con esta parte de la biblioteca.

Hola a todos. Como recordarás en el último artículo que configuramos paquete de software para trabajar con microcontroladores STM32 y compiló el primer programa. En este post nos familiarizaremos con la arquitectura de esta placa, el microcontrolador y las bibliotecas disponibles para trabajar.

A continuación se muestra una imagen del tablero. Descubrimiento STM32F3 , donde: 1 — sensor MEMS. Giroscopio digital de 3 ejes L3GD20. 2 - Sistema MEMS en un estuche que contiene un acelerómetro lineal digital de 3 ejes y un sensor geomagnético digital de 3 ejes LSM303DLHC. 4 – LD1 (PWR) – Fuente de alimentación de 3,3V. 5 – LD2 – LED rojo/verde. El valor predeterminado es rojo. Verde significa comunicación entre ST-LINK/v2 (o V2-B) y la PC. Tengo ST-LINK/v2-B, así como una pantalla personalizada Puerto USB. 6. -LD3/10 (rojo), LD4/9 (azul), LD5/8 (naranja) y LD6/7 (verde). En la última publicación hicimos parpadear el LED LD4. 7.- Dos botones: USUARIO personalizado y restablecer RESETEAR. 8.- USB USUARIO con conector Mini-B.

9 - Depurador/programador USB ST-LINK/V2. 1 0.- Microcontrolador STM32F303VCT6. 11. — Generador externo de alta frecuencia de 8 MHz. 12.- Aquí debería haber un generador de baja frecuencia, lamentablemente no está soldado. 13. – SWD – interfaz. 14.- Se deben quitar los puentes de selección de programación de controladores externos o internos, en el primer caso. 15 – Jumper JP3 – puente diseñado para conectar un amperímetro para medir el consumo del controlador. Está claro que si lo borramos, nuestra piedra no se iniciará. 16. – STM32F103C8T6 tiene una placa de depuración. 17. - LD3985M33R Regulador de baja caída de tensión y nivel de ruido, 150mA, 3,3V.

Ahora echemos un vistazo más de cerca a la arquitectura del microcontrolador STM32F303VCT6. Su especificaciones técnicas: Caja LQFP-100, núcleo ARM Cortex-M4, frecuencia máxima del núcleo 72 MHz, capacidad de memoria de programa 256 KB, tipo de memoria Programas FLASH, volumen memoria de acceso aleatorio SRAM 40 kbytes, RAM 8 kbytes, número de entradas/salidas 87, interfaces (CAN, I²C, IrDA, LIN, SPI, UART/USART, USB), periféricos (DMA, I2S, POR, PWM, WDT), ADC/DAC 4 *12 bit/2*12bit, tensión de alimentación 2...3,6 V, temperatura de funcionamiento –40...+85 C. En la siguiente figura hay un pinout, donde vemos 87 puertos de entrada/salida, 45 de ellos E/S normales (TC, TTa), 42 E/S tolerantes de 5 voltios (FT, FTf) – compatibles con 5 V (en la placa hay pines de 5 V a la derecha, 3,3 V a la izquierda). Cada línea de E/S digital puede servir como una línea de E/S general.
destino o función alternativa. A medida que avancen los proyectos, nos iremos familiarizando poco a poco con la periferia.

Considere el diagrama de bloques a continuación. El corazón es un núcleo ARM Cortex-M4 de 32 bits que funciona hasta 72 MHz. Tiene una unidad de punto flotante FPU incorporada y una unidad de protección de memoria MPU, celdas de seguimiento de macros incorporadas: Embedded Trace Macrocell (ETM), que se pueden utilizar para monitorear el proceso de ejecución del programa principal dentro del microcontrolador. Son capaces de generar continuamente estas observaciones a través de los contactos del ETM mientras el dispositivo esté en funcionamiento. NVIC (controlador de interrupción vectorial anidado): módulo de control de interrupciones. TPIU (Unidad de interfaz de puerto de seguimiento). Contiene memoria FLASH: 256 KB, SRAM 40 KB, RAM 8 KB. Entre el núcleo y la memoria hay una matriz de Bus, que permite conectar dispositivos directamente. También aquí vemos dos tipos de matriz de bus AHB y APB, donde la primera es más productiva y se utiliza para comunicaciones de alta velocidad. Componentes internos, y este último es para periféricos (dispositivos de entrada/salida). El controlador tiene 4 ADC de 12 bits (ADC) (5 Mbit/s) y un sensor de temperatura, 7 comparadores (GP Comparator1...7), 4 amplificadores operacionales programables (OpAmp1...4) (PGA (Programmable Gain Array) ), 2 canales DAC de 12 bits (DAC), RTC (reloj en tiempo real), dos temporizadores de vigilancia: independientes y en ventana (WinWatchdog e Ind. WDG32K), 17 temporizadores multifuncionales y de uso general.

En términos generales, analizamos la arquitectura del controlador. Ahora mire las bibliotecas de software disponibles. Realizado un repaso, podemos destacar los siguientes: CMSIS, SPL y HAL. Veamos cada uno usando un ejemplo simple de cómo parpadea un LED.

1). CMSIS(Estándar de interfaz de software del microcontrolador Cortex): biblioteca estándar para Cortex®-M. Proporciona soporte para dispositivos y simplifica interfaces de software. CMSIS proporciona consistencia y interfaces simples para el kernel, sus periféricos y sistemas operativos en tiempo real. Su uso es una forma profesional de escribir programas, porque... Implica la escritura directa en registros y, en consecuencia, es necesaria la lectura y el estudio constante de las hojas de datos. Independiente del fabricante del hardware.
CMSIS incluye los siguientes componentes:
- CMSIS-CORE: inicio consistente del sistema y acceso a periféricos;
- CMSIS-RTOS: Ejecución de software determinista en tiempo real software tiempo real);
- CMSIS-DSP: Rápida implementación del procesamiento de señales digitales procesamiento digital señales);
- CMSIS-Driver: Interfaces periféricas genéricas para middleware y código de aplicación (Interfaces periféricas generales para middleware y código de aplicación);
- CMSIS-Pack: fácil acceso a componentes de software reutilizables componentes de software);
- CMSIS-SVD: vista consistente del dispositivo y los periféricos dispositivos periféricos);
- CMSIS-DAP: Conectividad a hardware de evaluación de bajo coste. Software de depuración.

Por ejemplo, escribamos un programa: hagamos parpadear un LED. Para ello necesitamos documentación que describa los registros. En mi caso RM0316 Manual de referencia STM32F303xB/C/D/E, STM32F303x6/8, STM32F328x8, STM32F358xC, STM32F398xE MCU avanzadas basadas en ARM®, así como una descripción de la pata específica de la que es responsable DS9118: MCU+FPU Cortex®-M4 32b basado en ARM®, hasta 256 KB Flash+ 48 KB SRAM, 4 ADC, 2 canales DAC, 7 comp, 4 PGA, temporizadores, 2,0-3,6 V. Para empezar, registraremos el puerto en el programa, porque Por defecto todo está desactivado, lo que consigue un consumo de energía reducido. Abra el manual de referencia y consulte la sección Restablecimiento y control del reloj, luego el mapa de registros RCC y vea qué registro es responsable de habilitar IOPEEN.

Pasemos a la descripción del cronometrado de los periféricos de este registro. Registro de habilitación del reloj periférico AHB (RCC_AHBENR), donde vemos que este puerto está por debajo del bit 21. Actívelo RCC->AHBENR|=(1<<21) . Далее сконфигурируем регистры GPIO. Нас интересует три: GPIOE_MODER и GPIOx_ODR . C помощью них повторим программу с предыдущей статьи, затактируем PE8. Первый отвечает за конфигурацию входа выхода, выбираем 01: General purpose output mode. GPIOE->MODERNO|=0×10000 . El segundo es para girar en el nivel bajo/alto de la pierna. A continuación se muestra el programa:

#incluye "stm32f3xx.h " //Archivo de encabezado del microcontrolador
int sin firmar yo;
retraso nulo() (
para (i=0;yo<500000;i++);
}
int principal (nulo) (
RCC->AHBENR|=(1<<21);
GPIOE->MODER|=0×10000;
mientras (1)(
demora();
GPIOE->ODR|=0×100;
demora();
GPIOE->ODR&=~(0×100);
} }

2). SPL(Biblioteca de periféricos estándar)- esta biblioteca está destinada a combinar todos los procesadores de ST Electronics. Diseñado para mejorar la portabilidad del código y está dirigido principalmente a desarrolladores principiantes. ST ha estado trabajando en un reemplazo para SPL llamado "capa baja" que sea compatible con HAL. Los controladores de capa baja (LL) están diseñados para proporcionar una capa casi liviana, orientada a expertos y más cercana al hardware que HAL. Además de HAL, también están disponibles las API LL. Un ejemplo del mismo programa en SPL.

#incluir
#incluir
#incluir
#definir LED GPIO_Pin_8
int principal() (
largo i;
GPIO_InitTypeDef gpio;
// El LED azul está conectado al puerto E, pin 8 (bus AHB)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, HABILITAR);
// Configurar el puerto E (LED)
GPIO_StructInit(&gpio); //declarar e inicializar una variable de estructura de datos
gpio.GPIO_Mode = GPIO_Mode_OUT;
gpio.GPIO_Pin = LED;
GPIO_Init(GPIOE, &gpio);
// LED parpadeantes
mientras (1) (
// En
GPIO_SetBits(GPIOE, LED);
para (yo = 0; yo< 500000; i++);
// Todo apagado
GPIO_ResetBits(GPIOE, LED);
para (yo = 0; yo< 500000; i++);
} }

Cada función está descrita en la documentación técnica. UM1581 Manual de usuario Descripción de la biblioteca de periféricos estándar STM32F30xx/31xx. Aquí conectamos tres archivos de encabezado que contienen los datos necesarios, estructuras, funciones de control de reinicio y sincronización, así como para configurar puertos de entrada/salida.

3). HAL- (Nivel de acceso al hardware, capa de abstracción del hardware)- Otra biblioteca común para el desarrollo. Con lo cual también fue liberado el programa CubeMX para la configuración que utilizamos en el último artículo. Allí también escribimos un programa para hacer parpadear un LED usando esta biblioteca. Como vemos en la figura siguiente, el cubo genera controladores HAL y CMSIS. Bueno, describamos los principales archivos utilizados:
- system_stm32f3x.c y sistema_stm32f3x.h- proporcionar conjuntos mínimos de funciones para configurar el sistema de cronometraje;
— core_cm4.h – proporciona acceso a los registros del núcleo y sus periféricos;
- stm32f3x.h - archivo de encabezado del microcontrolador;
— startup_system32f3x.s — código de inicio, contiene una tabla de vectores de interrupción, etc.

#incluir "principal.h"
#incluir "stm32f3xx_hal.h"
vacío SystemClock_Config(vacío); /*Declarar funciones de configuración del reloj*/
vacío estático MX_GPIO_Init(vacío); /*Inicializar E/S*/
int principal (nulo) (
/*Reinicio de todos los periféricos, Inicializa la interfaz Flash y Systick.*/
HAL_Init();
/* Configurar el reloj del sistema */
SystemClock_Config();
/* Inicializa todos los periféricos configurados */
MX_GPIO_Init();
mientras (1) (
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_8); //Cambiar el estado de la pierna
HAL_Delay(100); )
}
anular SystemClock_Config (anular){
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;
si (HAL_RCC_OscConfig (&RCC_OscInitStruct)! = HAL_OK){

}
/**Inicializa los relojes de los buses CPU, AHB y APB */
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;
si (HAL_RCC_ClockConfig (&RCC_ClkInitStruct, FLASH_LATENCY_0)! = HAL_OK){
_Error_Handler(__FILE__, __LINE__);
}
/**Configurar el tiempo de interrupción de Systick*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configurar el Systick */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* Configuración de interrupción SysTick_IRQn */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/** Configurar pines como Entrada Salida Analógica EVENT_OUT EXTI */
vacío estático MX_GPIO_Init (vacío){
GPIO_InitTypeDef GPIO_InitStruct;
/* Habilitación del reloj de los puertos GPIO */
__HAL_RCC_GPIOE_CLK_ENABLE();
/*Configurar el nivel de salida del pin GPIO */
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);
/*Configurar pines GPIO: 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(archivo char *, línea int){
mientras (1) (
} }
#ifdef USE_FULL_ASSERT

Voidasser_failed (archivo uint8_t*, línea uint32_t){
}
#terminara si
Aquí, al igual que en el ejemplo anterior, podemos ver la descripción de cada función en la documentación, por ejemplo Manual del usuario de UM1786 Descripción de STM32F3 HAL y controladores de capa baja.

Podemos resumir que la primera opción, utilizar CMSIS, es menos engorrosa. Hay documentación para cada biblioteca. En proyectos posteriores, usaremos HAL y CMSIS usando el programa de configuración STCube y, si es posible, usaremos registros directamente, sin envoltorios de software. Detengámonos ahí hoy. En el próximo artículo veremos los principios básicos de la construcción. casa inteligente. Chau a todos.




Arriba