
La microelectrónica se ha convertido en una moda en los últimos años gracias al mágico Arduino. Pero hay un problema: con el interés adecuado, uno puede rápidamente dejar atrás DigitalWrite(), y no está claro qué hacer después. Los desarrolladores de Arduino han realizado importantes esfuerzos para reducir la barrera de entrada en su ecosistema, pero fuera de él todavía existe un bosque oscuro de complicada electrónica, poco accesible para el aficionado.
Por ejemplo, las hojas de datos. Aparentemente, allí hay todo lo que necesitas; simplemente agarra y usa. Pero sus autores claramente no tienen como objetivo popularizar los microcontroladores; a veces parece, que abusan intencionadamente de términos y acrónimos confusos al describir cosas simples, para confundir al profano al máximo. Sin embargo, no todo está tan mal, con un poco de deseo se puede abrir el caparazón.
En este artículo compartiré mi experiencia como humanista interactuando con hojas de datos con fines de hobby. El texto está destinado a quienes han evolucionado más allá de Arduino, presuponiendo cierto conocimiento sobre los principios de funcionamiento de los microcontroladores.
Empezaré con lo tradicional
Haciendo parpadear un LED en Arduino
Y aquí está el código:
void setup() {
DDRB |= (1<<5);
}
void loop() {
PINB = (1<<5);
for (volatile uint32_t k=0; k<100000; k++);
}«¿Qué es esto? – Preguntará el lector experimentado. – ¿Por qué escribes algo en el registro de entrada PINB? ¡Sólo se puede leer!» En efecto, , al igual que la mayoría de los artículos educativos en internet, afirma que este registro es de solo lectura. Yo también lo pensé, hasta que volví a leer el Atmega328p, preparando este artículo. Y allí dice:

Es una funcionalidad relativamente nueva, no estaba en el Atmega8; no todos la conocen o la mencionan por razones de compatibilidad hacia atrás. Pero es sin duda útil para demostrar la idea de que se deben leer las hojas de datos para aprovechar todas las capacidades del chip, incluidas las menos conocidas. Y esta no es la única razón.
¿Por qué leer más hojas de datos?
Usualmente, los arduinoistas, después de haber jugado con LEDs y AnalogWrite, comienzan a conectar varios módulos y chips a la placa, para los cuales ya existen bibliotecas escritas. Tarde o temprano aparece una biblioteca que no funciona como debería. Entonces el aficionado empieza a investigarla para arreglarla, y allí...
Allí sucede algo completamente incomprensible, por lo que es necesario recurrir a Google, leer numerosos tutoriales, extraer fragmentos de código de alguien que lo haya hecho antes y finalmente lograrlo. Esto da una poderosa sensación de logro, pero en realidad el proceso se asemeja a inventar una bicicleta mediante la ingeniería inversa de una motocicleta. Y, además, no se aumenta el entendimiento de cómo funciona esta bicicleta. Lo sé porque yo mismo me he dedicado a ello durante bastante tiempo.
Si en lugar de esta fascinante tarea hubiera pasado un par de días estudiando la documentación de Atmega328, habría ahorrado una enorme cantidad de tiempo. Al fin y al cabo, es un microcontrolador bastante simple.
Por lo tanto, es necesario leer las hojas de datos al menos para hacerse una idea de cómo está construido el microcontrolador y qué puede hacer. Y además:
para verificar y optimizar las bibliotecas de otros. A menudo son escritas por aficionados similares que inventan la bicicleta; o, por el contrario, los autores intencionadamente añaden una protección excesiva contra errores. Que sea tres veces más grande y lento, pero que funcione seguro;
para poder utilizar en el proyecto chips para los cuales nadie ha escrito una biblioteca;
para facilitar la tarea de migrar de una serie de MC a otra;
para finalmente optimizar mi viejo código que no encajaba en Arduino;
para aprender a manejar cualquier chip directamente a través de sus registros, sin complicarse con el estudio de la estructura de sus bibliotecas, si es que existen.
¿Por qué escribir directamente en los registros cuando hay HAL y LL?
Glosario
HAL, Capa de Alta Abstracción – biblioteca para controlar el microcontrolador con un alto nivel de abstracción. Si se necesita utilizar la interfaz SPI1, solo hay que configurarla y activarla, sin pensar en qué registros responden a qué.
LL, API de Bajo Nivel – biblioteca que contiene macros o estructuras con direcciones de registros, lo que permite acceder a ellos por nombre. DDRx, PORTx, PINx en Atmega son LL.
Las disputas sobre "HAL, LL o registros" ocurren regularmente en los comentarios de Habr. Sin pretender tener acceso a conocimiento astral, simplemente compartiré mi experiencia y reflexiones de aficionado.
Después de entender más o menos cómo funciona el ATmega y leer artículos sobre las maravillas del STM32, compré media docena de placas diferentes: tanto la Discovery como las 'Tabletas Azules', e incluso simplemente chips para mis propios proyectos. Todas han estado acumulando polvo en una caja durante dos años. A veces me decía: 'bueno, a partir de este fin de semana voy a aprender STM', abría CubeMX, generaba una configuración para SPI, miraba la pared de texto resultante, abundantemente cargada de copyright de STM, y decidía que todo eso era un poco demasiado.

Por supuesto, se puede entender lo que CubeMX ha producido. Pero al mismo tiempo es evidente que recordar todas las formulaciones para poder escribirlas de memoria es irreal. Y depurarlo, si por casualidad olvido activar alguna opción en Cube, es un verdadero desafío.
Han pasado dos años y sigo deseando los chips sabrosos, pero que no entiendo, y de repente me topé con un , aunque sea sobre STM8. Y sorpresivamente me di cuenta de que todo este tiempo estaba llamando a una puerta abierta: los registros del STM están organizados de la misma manera que los de cualquier otro microcontrolador, y no es necesario usar Cube para trabajar con ellos. ¿Y qué, se podía hacer así?
HAL y, específicamente, STM32CubeMX son herramientas para ingenieros profesionales que trabajan intensamente con los chips STM32. La característica principal es el alto nivel de abstracción, la posibilidad de migrar rápidamente de un microcontrolador a otro e incluso de un núcleo a otro, permaneciendo dentro de la familia STM32. Los aficionados rara vez se enfrentan a tales tareas; nuestra elección de microcontroladores generalmente está limitada a lo que hay disponible en AliExpress, y más a menudo migramos entre chips completamente diferentes: pasamos del ATmega al STM, del STM al ESP, o lo que sea que nos traigan los amigos chinos. HAL aquí no ayuda, y el tiempo que toma aprenderlo es considerable.
Nos queda LL, pero está a un paso de los registros. Personalmente, encuentro útil escribir mis propios macros con las direcciones de los registros: estudio el datasheet más detenidamente, pienso en lo que podría necesitar en el futuro y lo que definitivamente no, estructuro mejor mis programas, y en general el esfuerzo de hacerlo contribuye a la memorización.
Además, hay un matiz con el popular STM32F103: existen dos versiones de LL incompatibles, una oficial de STM y otra de Leaf Labs, utilizada en el proyecto STM32duino. Si se va a escribir una biblioteca de código abierto (y ese era exactamente ), hay que hacer dos versiones o dirigirse directamente a los registros.
Finalmente, la renuncia a LL, en mi opinión, simplifica la migración, especialmente si se contempla desde el inicio del proyecto. Un ejemplo exagerado: escribiremos un blink de Arduino en Atmel Studio sin LL:
#include <stdint.h>
#define _REG(addr) (*(volatile uint8_t*)(addr))
#define DDR_B 0x24
#define OUT_B 0x25
int main(void)
{
volatile uint32_t k;
_REG(DDR_B) |= (1<<5);
while(1)
{
_REG(OUT_B) |= (1<<5);
for (k=0; k<50000; k++);
_REG(OUT_B) &= ~(1<<5);
for (k=0; k<50000; k++);
}
}Para que este código haga parpadear un LED en una placa china con STM8 (de ST Visual Desktop), es suficiente con cambiar dos direcciones:
#define DDR_B 0x5007
#define OUT_B 0x5005Sí, estoy utilizando una característica de conexión del LED en una placa específica, parpadeará muy lentamente, ¡pero lo hará!
Tipos de hojas de datos
En artículos y foros, tanto en ruso como en inglés, bajo 'hojas de datos' se entiende cualquier documentación técnica sobre chips, y así lo hago yo en este texto. Formalmente, son solo uno de los tipos de dicha documentación:
Datasheet – TTX, características tácticas y técnicas. Siempre está disponible para cualquier componente electrónico. Información de referencia, útil tener a mano, pero no hay mucho que leer detenidamente. Sin embargo, los chips más simples a menudo se limitan a la hoja de datos para no generar documentos adicionales; en este caso Manual de referencia se incluye aquí también.
Manual de referencia – la propia guía, un libro extenso de más de 1000 páginas. Detalla el funcionamiento de todo lo que se ha colocado en el chip. Es el documento principal para dominar el microcontrolador. A diferencia de datasheet, las guías se escriben para una amplia gama de MC, contienen mucha información sobre periféricos que faltan en su modelo específico.
Manual de Programación o Manual del Conjunto de Instrucciones – instrucciones para comandos únicos del microcontrolador. Está destinada a quienes programan en ensamblador. Los autores de compiladores la utilizan activamente para optimizar el código, por lo que, en general, no la necesitaremos. Pero es útil echarle un vistazo para una comprensión general, sobre algunos comandos específicos como la salida de interrupciones, así como al utilizar activamente el depurador.
Nota de Aplicación – consejos útiles para resolver tareas específicas, a menudo con ejemplos de código.
Hoja de Erratas – descripción de casos de comportamiento no estándar del chip con opciones de solución, si las hay.
Qué hay en las hojas de datos
Directamente en Datasheet podemos necesitar secciones como:
Resumen del Dispositivo – la primera página de la hoja de datos describe brevemente el dispositivo. Muy útil en situaciones cuando has encontrado un chip (lo viste en la tienda, lo desoldaste, te encontraste con una mención) y quieres entender qué es.
Descripción General – una descripción más detallada de las capacidades de los chips de la serie.
Pinouts – diagramas de conexión para todos los posibles encapsulados del chip (qué pin está en qué pata).
Descripción de pines – descripción de la función y capacidades de cada pin.
Memory Map – el mapa de direcciones en la memoria probablemente no lo necesitemos, pero a veces incluye también una tabla de direcciones de bloques de registros.
Register Map – la tabla de direcciones de bloques de registros generalmente se encuentra en la hoja de datos, y en Ref Manual – solo desplazamientos (address offsets).
Electrical Characteristics – en esta sección nos interesa principalmente valores máximos absolutos, que enumeran las cargas máximas en el chip. A diferencia de la indestructible Atmega328p, la mayoría de los microcontroladores no permiten conectar cargas significativas a los pines, lo que puede resultar una sorpresa desagradable para los usuarios de Arduino.
Package Information – diagramas de los encapsulados disponibles, útiles al diseñar tus propias placas.
Manual de referencia se compone estructuralmente de secciones dedicadas a la periferia específica indicada en sus encabezados. Cada capítulo se puede dividir en tres partes:
Resumen, Introducción, Features – una visión general de las capacidades de la periferia;
Functional Description, Usage Guide o simplemente el bloque principal de la sección – una descripción textual detallada de los principios de funcionamiento de la periferia y cómo utilizarla;
Registers – descripción de los registros de control. En casos sencillos como GPIO o SPI, esto puede ser suficiente para comenzar a usar la periferia, pero a menudo es necesario leer las partes anteriores.
Cómo leer hojas de datos
Las hojas de datos pueden asustar con su volumen y la abundancia de términos desconocidos. En realidad, no es tan complicado si conoces algunos trucos.
Instala un buen lector de PDF. Las hojas de datos se redactan en las gloriosas tradiciones de las instrucciones en papel, es genial imprimirlas, marcarlas con separadores de plástico y encuadernarlas. El hipertexto se presenta en cantidades mínimas. Afortunadamente, al menos la estructura del documento está organizada con marcadores, por lo que un lector adecuado con buena navegación es muy útil.
Una hoja de datos no es un libro de texto de Stroustrup, en ella no es necesario leerlo todo de una vez. Si seguiste el consejo anterior, simplemente busca en el panel de marcadores la sección que necesitas.
Las hojas de datos, especialmente Reference Manuals, pueden describir las capacidades no de un chip específico, sino de toda la serie. Esto significa que la mitad, si no dos tercios de la información, no tiene relación con tu chip. Antes de estudiar los registros del TIM7, verifica en Descripción General, ¿lo tienen ustedes?
Saber inglés es suficiente en un nivel básico. Las hojas de datos constan a partes iguales de términos desconocidos para el hablante medio y de frases simples de conexión. También hay excelentes hojas de datos chinas en inglés chino, donde la mitad son términos y la otra mitad son una mezcla aleatoria de palabras.
Si encuentras una palabra desconocida, no intentes traducirla con un diccionario inglés-ruso. Si te confunde histeresis, la traducción de «histeresis» no te hará sentir mejor. Usa Google, Stack Overflow, Wikipedia, foros donde el concepto necesario esté .
La mejor manera de entender lo que has leído es probarlo en la práctica. Por lo tanto, mantén a mano la placa de depuración con la que te estás familiarizando, o mejor aún, dos, por si acaso no entiendes algo y ves un humo mágico.
Es útil tener a mano la hoja de datos cuando lees el tutorial de alguien o estudias una biblioteca ajena. Es muy posible que encuentres una solución más óptima a tu problema en ella. Y viceversa, si no puedes entender cómo funciona el registro a partir de la hoja de datos, búscalo en Google: probablemente alguien ya lo haya explicado con palabras sencillas o dejado un código claro en GitHub.
Glosario
Unos pocos términos y notaciones útiles que ayudan a familiarizarse más rápidamente con las hojas de datos. Lo que recuerda de los últimos días, se agradecen adiciones y correcciones.
Electricidad
Vcc, Vdd – «más», alimentación
Vss, Vee – «menos», tierra
corriente – corriente
voltaje – voltaje
sacar corriente – funcionar como «tierra» para una carga externa
proveer corriente – alimentar una carga externa
punto de conexión de alta tensión/fuente – pin con «tolerancia» elevada a la carga
IO
H, Alto – en el pin Vcc
L, Bajo – en el pin Vss
Alta Impedancia, Hi-Z, flotante – en el pin no hay nada, «alta resistencia», es prácticamente invisible para el mundo exterior.
débil pull up, débil pull down – resistor pull-up/down incorporado, aproximadamente equivalente a 50 kOhm (ver la hoja de datos). Se utiliza, por ejemplo, para que el pin de entrada no se quede en el aire, provocando activaciones erróneas. Débil – porque es fácil de «anular».
empuje tirar – modo de salida del pin donde se alterna entre Alto y Bajo – OUTPUT normal con Arduino.
drenaje abierto – designación del modo de salida donde el pin puede ser o bien Bajo, o Alta Impedancia/Flojo. Sin embargo, casi siempre esto no es un "verdadero" drenaje abierto, hay diodos de protección, resistencias y otras cosas. Simplemente es una indicación de que está en modo tierra/nada.
drenaje abierto verdadero – y este ya es un verdadero drenaje abierto: el pin va directamente a tierra si está abierto, o permanece en un estado flotante si está cerrado. Esto significa que a través de él se puede aplicar un voltaje mayor que Vcc, pero el máximo sigue estando especificado en la hoja de datos en la sección Clasificaciones máximas absolutas / Voltaje.
Interfaces
en serie – conectados en serie
a cadena – ensamblar chips en cadena conectándolos en serie, aumentando el número de salidas.
shift – desplazamiento, normalmente indica desplazamiento de bits. Por consiguiente, para desplazar dentro y para desplazar fuera – recibir y transmitir datos bit a bit.
latch – válvula que cubre el búfer mientras se desplazan los bits a través de él. Cuando la transmisión ha terminado, la válvula se abre y los bits comienzan a funcionar.
para hacer un clock in – ejecutar una transmisión bit a bit, desplazar todos los bits a sus lugares adecuados.
doble búfer, registro sombra, registro de carga previa – indicaciones de historia, cuando un registro debe poder aceptar nuevos datos, pero retenerlos hasta cierto momento. Por ejemplo, para un funcionamiento correcto del PWM, sus parámetros (ciclo de trabajo, frecuencia) no deben cambiar hasta que termine el ciclo actual, pero ya se pueden haber transmitido nuevos parámetros. Por consiguiente, los actuales se mantienen en registro sombra, mientras que los nuevos llegan a registro de carga previa, siendo escritos en el registro correspondiente del chip.
Cualquier cosa
prescaler – divisor de frecuencia
para establecer un bit – establecer el bit en 1
para borrar/restablecer un bit – restablecer el bit a 0 (reset – función de las hojas de datos STM)
¿Qué sigue?
En realidad, se planeó una parte práctica con la demostración de tres proyectos en STM32 y STM8, realizados específicamente para este artículo utilizando hojas de datos, con luces, SPI, temporizadores, PWM e interrupciones:

Pero el texto es demasiado extenso, así que los proyectos se enviarán a la segunda parte.
La habilidad de leer hojas de datos te ayudará con tu pasatiempo, pero apenas reemplazará la comunicación cara a cara con colegas entusiastas en foros y chats. Para eso, primero hay que mejorar el inglés. Así que para los que han llegado hasta aquí, hay un premio especial: dos lecciones gratuitas en Skyeng con el primer pago utilizando el código HABR2.
Fuente: habr.com
