En este artículo en profundidad aprenderá a desarrollar firmware integrado para microcontroladores STM32 Cortex-M de 32 bits utilizando las diversas herramientas de desarrollo.
La serie STM32 es uno de los microcontroladores más populares utilizados en una amplia variedad de productos. También tienen una excelente base de soporte de múltiples foros de desarrollo de microcontroladores.
Esta familia de microcontroladores de STMicroelectronics se basa en el núcleo del procesador ARM Cortex-M de 32 bits.
Los microcontroladores STM32 ofrecen una gran cantidad de periféricos de comunicación en serie y en paralelo que se pueden interconectar con todo tipo de componentes electrónicos, incluidos sensores, pantallas, cámaras, motores, etc. Todas las variantes STM32 vienen con memoria Flash interna y RAM.
El rango de rendimiento disponible con el STM32 es bastante amplio. Algunas de las variantes más básicas incluyen las sub-series STM32F0 y STM32F1 que comienzan con una frecuencia de reloj de solo 24 MHz, y están disponibles en paquetes con tan solo 16 pines.
En el otro extremo de rendimiento, el STM32H7 funciona a hasta 400 MHz y está disponible en paquetes con hasta 240 pines.
Los modelos más avanzados están disponibles con unidades de coma flotante (FPU) para aplicaciones con requisitos de procesamiento numérico serios. Estos modelos más avanzados difuminan la línea entre un microcontrolador y un microprocesador.
Finalmente, la sub-serie STM32L está diseñada específicamente para aplicaciones portátiles de baja potencia que se ejecutan desde una batería pequeña.
Herramientas de desarrollo
Se requieren herramientas de desarrollo para desarrollar el código, programar el microcontrolador y probar/depurar el código. Las herramientas de desarrollo incluyen:
- Compilador
- Depurador
- Programador en Serie en Circuito (ICSP)
Programación del STM32 a través del Programador en Serie en Circuito (ICSP).
Hay varias herramientas de desarrollo de software disponibles para el desarrollo de código en microcontroladores STM32. Las herramientas de software están disponibles como Entornos de Desarrollo Integrados (IDE) que combinan todas las herramientas necesarias en un entorno integrado.
Dos paquetes de desarrollo comunes incluyen:
- Keil MDK ARM (uVison5 IDE) – El IDE MDK ARM es un entorno de desarrollo muy estable que se puede descargar de forma gratuita. Permite el desarrollo de código hasta un tamaño de programa de 32 KB. Para desarrollar programas más grandes, es necesario comprar una versión con licencia aquí.
- CoIDE: Una cadena de herramientas gratuita que se basa en una versión recortada del IDE de Eclipse integrada junto con una versión ARM integrada del compilador GCC gratuito.
También hay varios otros IDE disponibles para su uso con microcontroladores STM32. Sin embargo, este artículo se centra en el desarrollo y flasheo de un programa que utiliza el muy popular IDE Keil MDK ARM uVision5.
Además de las herramientas de software, se requiere un Programador Serie en Circuito (ICSP) para programar y probar el código en el microcontrolador real. El ICSP es necesario para conectar el microcontrolador a las herramientas de software de PC a través de un puerto USB.
Los microcontroladores ARM Cortex-M son compatibles con dos protocolos de programación: JTAG (denominado por la asociación de la industria electrónica Joint Test Action Group) y Serial Wire Debug (SWD).
Hay varios programadores ICSP disponibles que admiten estos protocolos, incluidos:
- Keil U-Link 2
- Segger J-Link
- ST-Link
Desarrollar la primera aplicación
Siempre es más fácil comenzar con un marco de código básico fácilmente disponible. Luego, agregue el código que se requiere para la aplicación y el modelo específicos del microcontrolador.
Afortunadamente, STMicroelectronics proporciona una herramienta gráfica muy útil llamada STM32CubeMX que ayuda a crear un proyecto de aplicación básico para cualquier microcontrolador STM32 de su elección. También se puede utilizar para configurar los periféricos en los pines multiplexados del microcontrolador.
La herramienta STM32CubeMX se puede descargar desde aquí. El STM32Cube viene con un amplio conjunto de controladores para todo tipo de periféricos y soporte para un FreeRTOS opcional (un Sistema Operativo gratuito en Tiempo Real) preintegrado con el código.
La siguiente sección describe en detalle cómo crear una aplicación UART sencilla para el microcontrolador STM32F030 que haga eco de lo que se escriba en una ventana de terminal.
- Instale el software STM32CubeMX.
- Ejecute la aplicación y seleccione Nuevo Proyecto. A continuación, se abrirá la ventana del Selector de MCU como se muestra a continuación.
- Haga doble clic para seleccionar el modelo de microcontrolador que se está utilizando. En este caso estamos usando el STM32F030K6. A continuación, te lleva a la página de pinout del microcontrolador seleccionado.
El STM32F030K6 es un núcleo ARM Cortex-M0 con 32 KB de memoria Flash y 4 KB de memoria RAM. El código de ejemplo habilita el UART que utiliza los pines PA9 y PA10 para recibir y transmitir datos en serie como se muestra a continuación con los pines verdes.
Configure los ajustes de UART en la pestaña Configuración y elija los ajustes de UART como se muestra a continuación. Habilite la opción de interrupción global de NVIC en la pestaña Configuración de NVIC.
A continuación, vaya a Project–>Settings para agregar el nuevo nombre del proyecto y seleccionar el IDE de cadena de herramientas que se utilizará. Para este ejemplo, establezca el nombre del proyecto en ‘UARTEcho’ y seleccione el IDE Keil-MDK5 para el desarrollo del proyecto.
Finalmente, genere el código del proyecto haciendo clic en Proyecto – > Generar código.
Crear y flashear el código
Ahora abra el archivo de proyecto MDK-ARM generado UARTEcho\MDK-ARM\UartEcho.uprojx.
Este programa hasta ahora solo inicializa el periférico UART y se detiene en un bucle infinito.
Es importante tener en cuenta que el STM32Cube genera bloques de comentario /* CÓDIGO DE USUARIO BEGIN x */ y /* CÓDIGO DE USUARIO END x */ para implementar el código específico del usuario. El código de usuario debe estar escrito dentro de estos bloques de comentarios. Siempre que el código se vuelve a generar con configuraciones modificadas, la herramienta STMCube retiene el código de usuario dentro de estos bloques de comentarios de usuario.
A continuación, defina una variable global para recibir un byte de la UART en la principal.archivo de origen en c:
/* USER CODE BEGIN PV *//* Private variables ———————————————————*/static uint8_t recv_data;/* USER CODE END PV */
Después de todo el código de inicialización, habilite el controlador para recibir 1 byte. La siguiente función habilita el bit de interrupción RXNE.
/* USER CODE BEGIN 2 */HAL_UART_Receive_IT(&huart1, &recv_data, 1);/* USER CODE END 2 */
Ahora, agregue una función de devolución de llamada para manejar la interrupción de recepción y transmitir el byte recibido.
/* USER CODE BEGIN 0 */void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){HAL_UART_Transmit(huart, huart->pRxBuffPtr, 1, 1000);}/* USER CODE END 0 */
Finalmente, necesitamos compilar el código y flashearlo (descargarlo) al microcontrolador.
Cuando se instala el IDE ARM Keil MDK, están disponibles los controladores para ST-LINK V2, J-Link y Ulink2. El depurador ST-Link se seleccionará de forma predeterminada. Vaya a Proyectos – >Opciones de Destino y en la pestaña de depuración seleccione el programador ICSP utilizado.
Flashea el código seleccionando Flash – > Descargar.
El microcontrolador ahora hará eco de cualquier dato recibido a través de la UART. Se puede conectar a un PC mediante un convertidor USB a Serie. En el PC, abra el puerto COM con una aplicación de terminal utilizando la configuración de 115200-8-N-1. Ahora cualquier cosa que se envíe desde el terminal hará eco a través del microcontrolador.
Sistema de interrupción
El sistema de interrupción STM32 se basa en el periférico NVIC del núcleo ARM Cortex M. Las MCU STM32 admiten múltiples canales de interrupción enmascarables, aparte de los 16 canales de interrupción del núcleo ARM.
Por ejemplo, la serie MCU STM32F0 admite 32 interrupciones enmascarables. La tabla de vectores de excepción y de interrupción para esta familia de MCU se muestra en la tabla siguiente.
Interrupt | Description | Vector Address |
– | Reserved | 0x00000000 |
Reset | Reset | 0x00000004 |
NMI | Non maskable interrupt. The RCC clock security system (CSS) is linked to the NMI vector | 0x00000008 |
HardFault | All class of faults | 0x0000000C |
SVCall | System service call via SWI Instruction | 0x0000002C |
PendSV | Pendable request for system service | 0x00000038 |
SysTick | System tick timer | 0x0000003C |
WWDG | Window watchdog interrupt | 0x00000040 |
PVD_VDDIO2 | PVD and VDDIO2 supply comparator interrupt (combined with EXTI lines 16 and 31) | 0x00000044 |
RTC | RTC interrupts (combined EXTI lines 17, 19 and 20) | 0x00000048 |
Flash | Flash global interrupt | 0x0000004C |
RCC_CRS | RCC and CRS global interrupts | 0x00000050 |
EXTI0_1 | EXTI line interrupts | 0x00000054 |
EXTI2_3 | EXTI line interrupts | 0x00000058 |
EXTI4_15 | EXTI line interrupts | 0x0000005C |
TSC | Touch sensing interrupt | 0x00000060 |
DMA_CH1 | DMA channel 1 interrupt | 0x00000064 |
DMA_CH2_3 DMA2_CH1_2 |
DMA channels 2 and 3 interrupts DMA2 channel1 and 2 interrupts |
0x00000068 |
DMA_CH4_5_6_7 DMA2_CH3_4_5 |
DMA channel 4,5,6 and 7 interrupts DMA2 channel 3, 4, and 5 interrupts |
0x0000006C |
ADC_COMP | ADC and COMP interrupts (Combined EXTI lines 21 and 22) | 0x00000070 |
TIM1_BRK_UP_TRG_COM | TIM1 break, update, trigger and commutation interrupts | 0x00000074 |
TIM1_CC | TIM1 capture compare interrupt | 0x00000078 |
TIM2 | TIM2 global interrupt | 0x0000007C |
TIM3 | TIM3 global interrupt | 0x00000080 |
TIM6_DAC | TIM6 global interrupt and DAC underrun interrupt | 0x00000084 |
TIM7 | TIM7 global interrupt | 0x00000088 |
TIM14 | TIM14 global interrupt | 0x0000008C |
TIM15 | TIM15 global interrupt | 0x00000090 |
TIM16 | TIM16 global interrupt | 0x00000094 |
TIM17 | TIM17 global interrupt | 0x00000098 |
I2C1 | I2C1 global interrupt (combined with EXTI line 23) | 0x0000009C |
I2C2 | I2C2 global interrupt | 0x000000A0 |
SPI1 | SPI1 global interrupt | 0x000000A4 |
SPI2 | SPI2 global interrupt | 0x000000A8 |
USART1 | USART1 global interrupt (combined with EXTI line 25) | 0x000000AC |
UART2 | USART2 global interrupt (combined with EXTI line 26) | 0x000000B0 |
USART3_4_5_6_7_ 8 | USART3, USART4, USART5, USART6, USART7, USART8 global interrupts (combined with EXTI line 28) | 0x000000B4 |
CEC_CAN | CEC and CAN global interrupts (combined with EXTI line 27 | 0x000000B8 |
USB | USB global interrupt (combined with EXTI line 18) | 0x000000BC |
Extended Controlador de Interrupciones y Eventos (EXTI)
Las MCU STM32 tienen un controlador de interrupciones y Eventos extendido que administra los eventos/interrupciones asincrónicos externos e internos y genera la solicitud de eventos al Controlador de Interrupciones/CPU y una solicitud de activación al Administrador de energía.
Cada una de las líneas EXTI se asigna a uno de los vectores de interrupción NVIC.
Para las líneas de interrupción externas, para generar una interrupción, la línea de interrupción debe configurarse y habilitarse. Esto se hace programando los dos registros de activación con la detección de bordes deseada y habilitando la solicitud de interrupción escribiendo un ‘1’ en el bit correspondiente en el registro de máscara de interrupción.
Asignación de interrupciones externas y GPIO
Cada GPIO disponible en el sistema se puede configurar para generar una interrupción. Pero cada una de las líneas de interrupción EXTI se asigna a varios pines GPIO. Por ejemplo, PIO0 en todos los puertos GPIO disponibles(A, B, C, etc.) se asignará a la línea EXT0. PIO1 para todos los puertos se asignará a la línea EXTI1 y así sucesivamente.
Algunas de las líneas EXTI se combinan en un único vector NVIC. Por ejemplo, EXTI4_15 se asigna a una sola dirección vectorial, por lo que habrá una única rutina de interrupciones para todas las interrupciones de PIO4 a PIO15. Pero la fuente de la interrupción se puede identificar leyendo el registro pendiente de interrupción.
Una cosa importante a considerar al diseñar un sistema que utilice las MCU STM32 es la selección de los pines GPIO para las interrupciones. La MCU puede tener más de 16 GPIOs disponibles en el dispositivo, pero solo hay 16 líneas de interrupción externas disponibles.
Por ejemplo, EXTI_0 se puede asignar a PA0 o PB0, pero no a ambos. Por lo tanto, al elegir los pines para interrupciones externas, deben elegirse de manera que puedan asignarse de forma única a una de las líneas EX.
En la siguiente sección se describe cómo configurar una interrupción mediante el cubo STM32.
Seleccione la pestaña Configuración y elija el módulo de hardware para el que se debe configurar la interrupción. Se abre la ventana de configuración del módulo.
A continuación, seleccione la pestaña Configuración de NVIC y habilite la interrupción global.
El código para habilitar la interrupción del módulo se generará en el stm32f0xx_hal_msp.c en la función HAL_< module> _MSPInit (function).
/* USART1 interrupt Init */HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);HAL_NVIC_EnableIRQ(USART1_IRQn);
El código generado por el Cubo STM32 tendrá la implementación IRQ_Handler de todas las interrupciones. Cuando la interrupción está habilitada, el código se incluirá en la aplicación.
Por lo general, el código generado ya maneja la IRQ y borra el indicador que generó la interrupción. A continuación, llama a una devolución de llamada de aplicación que corresponde al evento que generó la interrupción para el módulo.
El STM32 HAL (Capa de abstracción de hardware) implementa una devolución de llamada para cada uno de los tipos de eventos dentro de cada módulo como parte del controlador. En este ejemplo, la devolución de llamada completa de Transferencia Rx debe copiarse del stm32f0xx_hal_UART.archivo c.
Las funciones de devolución de llamada dentro del controlador se implementarán con un atributo de enlazador débil__. El usuario necesita implementar una copia de la función de devolución de llamada necesaria eliminando el atributo _ _ weak en uno de los archivos de la aplicación y luego escribiendo el manejo específico requerido dentro de esa función.
/*** @brief Rx Transfer completed callback.* @param huart UART handle.* @retval None*/__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){/* Prevent unused argument(s) compilation warning */UNUSED(huart);/* NOTE : This function should not be modified, when the callback is needed,the HAL_UART_RxCpltCallback can be implemented in the user file.*/}
Conclusión
Este tutorial es una introducción a la escritura de una aplicación que funciona con la familia de microcontroladores STM32. Hay varios otros métodos para escribir una aplicación, pero el STM32Cube discutido es un método fácil e intuitivo para comenzar.
Esta herramienta simplifica la inicialización de los periféricos del microcontrolador. También mejora la capacidad de mantenimiento del código, especialmente cuando hay revisiones de hardware que requieren la reasignación de las señales a diferentes pines.
Otra ventaja de usar la herramienta STM32Cube es que genera un informe de la configuración de usuario para el microcontrolador. En este informe se detalla el árbol de reloj, la asignación de pines y la configuración del módulo de hardware, que son muy útiles.
También hay varias bibliotecas de código y programas de ejemplo disponibles para todas las variantes de STM32. También se incluye soporte para varios IDE.
Si su proyecto requiere un microcontrolador sofisticado de 32 bits, le recomiendo encarecidamente la serie STM32. No solo son potentes y populares, sino que los microcontroladores STM32 también son bastante asequibles.
¿Necesita más capacitación en programación de microcontroladores STM32? Si es así, aquí hay un curso introductorio más profundo que debe consultar.
Este artículo fue escrito por Mohan Kashivasi de Vithamas Technologies. También es uno de los expertos disponibles para ayudarlo con su producto dentro de la Academia de Hardware.
Por último, no olvides descargar tu PDF gratuito: Guía Definitiva para Desarrollar y Vender Su Nuevo Producto de Hardware Electrónico. También recibirás mi boletín semanal donde comparto contenido premium que no está disponible en mi blog.
Otro contenido que te puede gustar:
- Introducción a los Microcontroladores STM32CubeIDE para STM32
- Cómo Seleccionar el Microcontrolador para tu Nuevo Producto
- Usando Arduino como Plataforma de Desarrollo Integrada
- Revisión de la Hoja de datos: Entry-Level STM32 Cortex-M0 Microcontroller (Blog + Video)
- Introduction to the Ultra High-Performance STM32H7 32-bit Microcontroller