Bare-Metal STM32: comunicación asincrónica universal con UART
Una de las interfaces de comunicación más básicas y más versátiles de una MCU es UART, o receptor / transmisor asíncrono universal. Generalmente se encuentra en forma de UART o USART, el primero permite la comunicación serial asincrónica pura, mientras que el segundo agrega control de flujo. Al trabajar con MCU, también son una de las formas más comunes de producir información de depuración.
Aunque es un poco más complicado de configurar y usar que un GPIO periférico, el U (S) ART de las familias STM32 de ST es bastante simple de usar e inmediatamente proporciona a uno una manera fácil de comunicarse de forma bidireccional a través de un dispositivo. En este artículo, veremos qué se necesita para comenzar con la comunicación UART básica en microcontroladores STM32.
Elija uno, cualquiera
Qué periférico USART usar parece una elección bastante fácil, especialmente cuando las MCU STM32F0 de baja calidad tienen solo dos USART. Es decir, hasta que te des cuenta de que no todos son idénticos. Si bien todos admiten funciones básicas de UART, algunos agregan soporte USART, algunos tienen modo IrDA y Smartcard.
Funciones de USART en la MCU STM32F051.
Esta lista de la hoja de datos STM32F051 muestra que ambos periféricos son bastante distintos, con muchas características avanzadas solo en el primer periférico, con el segundo comparativamente un poco desnudos. Esto es algo que vemos mucho a través del periférico STM32, no solo para los USART, sino también para los temporizadores en particular. Elegir el periférico adecuado para las necesidades de alguien puede ser esencial, por lo que saber qué funciones necesita es una habilidad importante.
Para nuestros propósitos (UART básico sin DMA), casi todo funciona, pero si quisiéramos agregar un lector de tarjetas inteligentes más adelante, o decidimos que sería conveniente una velocidad en baudios automática, querríamos considerar eso. Especialmente cuando está diseñando para hardware personalizado, elegir un conjunto de periféricos y pines asociados para ellos puede ser terriblemente disruptivo si necesita cambiar esto en una etapa posterior o mejorar el desarrollo de productos.
Encenderlo
Al igual que con los otros periféricos, en caso de incendio, el periférico USART no funciona. Para cambiar esto, necesitamos activar levemente el registro RCC (Reset & Clock Control) apropiado para el bus en el que está encendido el periférico. Por ejemplo, si queremos usar USART1 en STM32F0-MCU, podemos ver que está en el bus APB2 cuando miramos las grabaciones del reloj RCC en el manual de referencia (RM) para la MCU relevante, en este caso RCC_APB2ENR:
RCC_APB2ENR en STM32F042 (RM0091 6.4.7).
Al escribir "1" en el bit 14, se habilitará el dominio de reloj para el periférico USART1 y podremos usar sus registros. En este punto, sin embargo, el periférico aún no está configurado y aún no está activo (activo). Para hacer esto, necesitamos trabajar en algunos pasos más:
- Habilite el banco GPIO, cuyos pines queremos usar para la comunicación con el mundo exterior.
- Establezca la velocidad en baudios en USART_BRR.
- Habilite el periférico Usart con su registro de reloj interno.
- Opcionalmente, establezca interrupciones.
- ¿A qué pines se dirige MCU para esta función?
- Manera de configurar este modo AF en el pin.
Alternar entre funciones
Los periféricos de E / S de propósito general (GPIO) no tienen una sola función. Como parte de su nombre de "propósito general", están cableados para permitir no solo E / S digitales, sino también para conectarse al controlador de interrupciones (EXTI) y otros periféricos, incluidos los USART, ADC, DAC, etc.
Estructura básica de pin de pintura en F0-MCU. (RM0091 8.3).
Debido a que queremos conectar nuestro periférico USART1 al mundo exterior, necesitamos habilitar el modo de función alternativa (AF) en los pines que queremos usar. Para esto necesitamos dos cosas:
Para STM32F0, F4, F7 y familias relacionadas, esto es bastante sencillo. Primero debemos mirar la tabla con los mapas de funciones alternativos en la hoja de datos de MCU. Para USART1 en STM32F042 MCU, por ejemplo, buscamos en su hoja de datos (aquí revisión 5, de 2017 de la pestaña Documentación) en la sección 4 ('Pinouts y descripciones de pin') donde en la Tabla 14 hemos visto los siguientes modos AF para el puerto A:
Modos AF en PA9 y PA10 para MCU STM32042.
Los encabezados fueron etiquetados AF[0..7] es para la función alternativa 0 a 7. Vemos aquí que podemos usar nuestros pines USART1-TX-RX en los pines 9 y 10 de la puerta A a través de AF1. Ahora solo necesitamos una forma de configurar esto, que se hace con los registros AFRL y AFRH del periférico GPIO. Esto significa 'Registro de función alternativa bajo' y 'Registro de función alternativa alto' respectivamente, con la mitad de los 16 pines de un banco GPIO separados en cada uno de estos registros.
Como estamos interesados en los pines 9 y 10, queremos cambiar los valores en AFSEL9 y AFSEL10 en GPIO_AFRH a AF1 (0x1):
GPIO_AFRH en STM32F042 con valores AF.
Cuando termine, estamos listos para configurar el periférico USART inmediatamente después de una nota rápida sobre la configuración de STM32F1 AF.
Cuidado con el leopardo
Aunque hay muchas cosas positivas sobre la familia de MCU STM32F1, sus GPIO periféricos no se encuentran entre ellos. La razón de esto vuelve a ser evidente cuando se fija un modo AF en un pin GPIO. Digamos que queremos configurar el modo AF en STM32F103-MCU, primero echemos un vistazo a su manual de referencia (RM0008) sección 9.3 ('Función de E / S alternativa y configuración de depuración (AFIO)') y copiar a la sección 9.3.8 (Reasignación de funciones alternativas USART), seleccione nuestra tabla USART favorita (USART1, tabla 54) y obtenga:
Reasignación de STM32F103 USART (RM0008 9.3.8, Tabla 54).
Aquí no hay capas sofisticadas en capas de modos de función alternativa, solo un "o" corto debido a la estructura de muxing limitada en el STM32F103. No parece tan malo, ¿verdad? La parte divertida aquí es que la función AF no está completamente integrada en el GPIO periférico, pero se encuentra en el AFIO. Mirando la sección 9.4.2 encontramos el AFIO_MAPR (registro de reasignación), en el que se supone que debemos alternar la entrada relevante (USART1_REMAP):
AFIO_MAPR en STM32F103 (RM0008 9.4.2).
Aunque esto puede no parecer mucho más complicado que el enfoque STM32 moderno, la parte molesta aquí es que los modos AF están asociados con el periférico en lugar del pin GPIO. En lugar de seleccionar el modo AF en GPIO_AFRH o GPIO_AFRL usando el puerto, el número de pin y el objetivo AF deseado, en las MCU F1 necesita conocer el periférico, así como su posición de entrada en AFIO_MAPR y qué pin está asociado con cada una de estas entradas. y periféricos.
Configuración de USART
Básicamente, en este punto todavía tenemos que establecer la velocidad en baudios para UART y habilitar el UART antes de que podamos enviar "Hola mundo". Por supuesto, configurar la velocidad en baudios no es tan simple como configurar el número deseado en el registro USART_BRR:
Diseño STM32F0 USART_BRR. (RM0091 27.8.4)
Sin entrar en demasiados detalles (ver, por ejemplo, 27.5.4 en RM0091), la forma sencilla de llenar este registro sin cambiar la configuración predeterminada (cómo habilitar SÚPER 8 en USART_CR1), es dividir el reloj del núcleo del sistema por la velocidad en baudios deseada, luego dividir esto por 16 dos veces, primero para obtener la fracción entera y luego usar una operación modular para obtener el resto (incorrectamente llamado "mantis" por ST) .
En codigo:
uint16_t uartdiv = SystemCoreClock / baudrate; instance.regs->BRR = (((uartdiv / 16) << USART_BRR_DIV_MANTISSA_Pos) | ((uartdiv % 16) << USART_BRR_DIV_FRACTION_Pos));
Aquí la velocidad en baudios es la velocidad en baudios deseada (por ejemplo, 9600) y SystemCoreClock es la velocidad del reloj del sistema central en Hz. Usando la posición de las posiciones "mantisa" y "fracción" en USART_BRR, sus valores se cambian ligeramente a un valor entero, que luego se escribe en el registro.
Con todo el trabajo duro, ahora podemos habilitar el USART. Esto se hace en el registro USART_CR1:
USART_CR1 en STMF0. (RM0091 27.8.1)
Los bits para cambiar a '1' están aquí RE (Activar), TE (Entregar habilitado), UE (Encienda USART) y RXNEIE (Habilitación de interrupción RXNE). Este último permite la generación de una interrupción cada vez que llegan nuevos datos y es opcional para la operación básica de UART. En este punto, deberíamos poder enviar y recibir datos, respectivamente, escribiendo o leyendo desde GPIO_DR.
Es hora de decir "hola"
La clave para enviar y recibir datos a través de UART es USART_SR (Registro de estado):
Diseño de registro STM32F0 USART_SR. (RM0091 27.6.1)
Las piezas a destacar aquí son:
- TXE (Transmitir registro de datos vacío).
- RXNE (Obtener un registro de datos que no esté vacío).
El primero (TXE) se debe verificar cada vez que queramos enviar un byte:
while (!(instance.regs->SR & USART_SR_TXE)) {}; instance.regs->DR = (uint8_t) ch;
Por el contrario, para leer debemos comprobar este último (RXNE) para saber que los datos son legibles:
if (instance.regs->SR & USART_SR_RXNE) { rxb = instance.regs->DR; instance.callback(rxb); }
Estos fragmentos de código se tomaron de la clase USART en el marco de Nodate.
Envolvente
Ser capaz de recibir y enviar bytes individuales de esta forma no es exactamente la forma óptima de utilizar UART. En artículos futuros veremos cómo agregar interrupciones, transferencias DMA y flujo de control (USART) y más para aprovechar la versatilidad de estos periféricos USART.
Aunque engañosamente simple en su esencia, los USART pueden considerarse un cuchillo militar suizo de periféricos de comunicación. Funcionan en casi todas partes y se pueden adaptar a una amplia variedad de tareas, ya sea que necesite conectar sensores, proporcionar una interfaz de usuario, controlar equipos industriales o algo más exótico. Con suerte, este artículo ha dado un primer vistazo a estas posibilidades.
Wallace Owen dice:
Un párrafo abierto define incorrectamente una definición de USART. No agrega apretones de manos. Una diferencia importante con respecto a la asincronización es que se proporciona un reloj por separado o combinado con los datos (codificación Manchester, NRZI, etc.).
James blanco dice:
Esta no es una crítica del tema principal que parece estar bien abordado.
La diferencia entre UART y USART no es el control de flujo de hardware. UART también puede admitir el control de flujo del dispositivo. USART habilita protocolos sincrónicos, en lugar de solo los protocolos asincrónicos permitidos por UART puro. Los protocolos asincrónicos requieren que cada carácter esté rodeado por un bit inicial y al menos un bit de parada. Los protocolos de señalización síncrona comienzan a transmitir con una o más señales SYN para establecer la sincronización, seguidas de un flujo continuo de bytes sin bits de inicio y parada. El flujo de bytes puede tener transiciones de señal adicionales o caracteres de sincronización adicionales insertados y eliminados automáticamente en el caso de cadenas largas de tales o ceros, de modo que no se pierda la sincronización de bits y bytes. El USART también puede depender de una señal de módem particular para ver los datos.jawnhenry dice:
Todo es muy simple, de verdad ...
UART: U (universal) SINCRÓNICO R (eceiver) -T (transmisor)
USART: U (universal) SINCRONO / ASINCRONO R (eceiver) -T (transmisor)
************************************************ * * *********************************************
El circuito integrado UART se desarrolló originalmente para reemplazar, en algunos casos, un conjunto completo de componentes (tal como lo implementaron algunos fabricantes de minicomputadoras) para impulsar el código Baudot estrictamente asíncrono de 110 baudios (un bit de inicio; ocho datos), por diseño inherente. bits; dos bits de parada) una máquina de escribir que fue EL ÚNICO Entonces, dispositivo de E / S para miniordenadores. Fue desarrollado en un esfuerzo típico para Digital Equipment Corporation (una de las miniordenadores más grandes fabricantes, por lo tanto) por un proyecto electrónico "sin nombre" llamado Western Digital.[historic note: the original Baudot code was only five bits; ‘modern teletypes’, of the type used by DEC, and all others until the end of the ‘teletype days’, used eight bits for a much richer character set]El USART fue una progresión de desarrollo posterior y mucho más capaz del UART, que además de proporcionar la función UART, podría proporcionar transmisión síncrona para lograr velocidades más altas que las disponibles mediante métodos simplemente asincrónicos.
Charles dice:
USART puede ingresar / emitir una señal de reloj separada, UART debe estar sincronizado en banda.
Grapadoras dice:
Gracias por la orientación.
Sí, agradezco que la información de alta densidad, como la hoja de datos, también esté disponible en forma ligera y digerible.
Y sí, mi (¿irracional?) Temor sobre el tamaño de las hojas de datos STM32 permanece: - /