Esta es una traducción. Artículo publicado el 27 de mayo de 2018
Rastreador de ejercicios antes y después del desmontajeCuando llegué a la compañía actual, el primer día me dieron un conjunto de regalos. Entre ellos estaba este brazalete con un rastreador de ejercicios. Independientemente de su amor por el ejercicio, este es un dispositivo increíblemente genial desde un punto de vista puramente técnico:
- un factor de forma realmente pequeño (aproximadamente 15 × 40 mm);
- Bluetooth de baja energía (BLE);
- Pantalla OLED (96 × 32 píxeles);
- bateria
- Carga USB
- acelerómetro
- motor de vibración;
- El precio es de aproximadamente $ 10 (!).
En el exterior, el único identificador en el panel posterior es la etiqueta "FCC ID: 2AHFTID115". Si lo buscas en Google, parece corresponder al dispositivo
ID115 e incluso puedes encontrar
varias fotos de su interior. Mirando hacia atrás en
una de estas fotografías , si te esfuerzas, puedes ver el nombre del circuito integrado (IC) más grande: N51822. Esto sugiere que puede haber un microcontrolador
nórdico (MCU)
nRF51822 , un procesador ARM M0 de 32 bits con soporte BLE incorporado, que en teoría es bastante fácil de programar para otras cosas que un brazalete debería hacer.
Antes de desarmar el dispositivo, busqué en Google un poco más y descubrí que en
algunas pulseras similares se instala el mismo chip, y las personas lo programaron con éxito.
Abrir el caso no fue tan fácil. La cubierta de plástico negro está pegada al fondo gris. Probé con un secador de pelo para suavizar el pegamento y pacientemente lo corté con un cuchillo pequeño, tratando de no dañar demasiado el plástico. Después de abrir, me aseguré de que realmente hay nRF51822. Más tarde compré una pulsera MCU casi idéntica de Texas Instrument. Tenga en cuenta que hay opciones.
nRF51822 y bolígrafo para escalaEncontrar una manera de comunicarse
La
documentación dice que el chip puede ser programado / depurado usando la
interfaz de dos pines ARM
Serial Wire Debug (SWD). Si queremos establecer un canal de comunicación con un chip, esto significa dos cosas:
- Necesitamos un programador SWD (por ejemplo, Segger J-Link ).
- Necesitaremos acceso a los dos pines SWD en el microcontrolador, a saber, SWDIO (datos) y SWDCLK (pulsos de reloj).
Afortunadamente, hay varios pads disponibles en el tablero. Aunque su existencia se explica claramente por la necesidad de depuración, prueba y verificación, prefiero pensar que algún ingeniero genial los dejó allí como pequeños obsequios para personas como nosotros. No todos están debidamente etiquetados, por lo que sugiero los siguientes códigos:

Anverso y reverso de la placa de circuito. Bolígrafo para escala y nombres semi-arbitrarios para almohadillas abiertasUsando el mismo
microscopio USB barato
, tomé varias fotos de los lados frontal y posterior de la placa e intenté rastrear las pistas desde el microcontrolador hasta las almohadillas.

Pistas a los pines SWDIO y SWDCLK en la parte frontal y posterior de la placaTenga en cuenta que esta es una placa de circuito impreso de varias capas con agujeros pasantes, por lo que debe verificar las pistas en ambos lados de la placa. A partir de estas fotos, puede rastrear las pistas desde los contactos SWDIO y SWDCLK en el chip hasta los pads IO y CLK. Por lo tanto, nos aseguraremos de que la marca CLK en la placa corresponda a SWDCLK en la MCU, y el contacto sin etiqueta es el pin SWDIO. Ahora puedes preparar nuestra primera tabla de mapeo:
NRF51822 pin | Parque infantil | Descripción |
---|
SWDIO | IO | Salida de datos para programar SWD |
SWDCLK | CLK | Salida de reloj para programación SWD |
Cirugía post mortem
Habiendo obtenido acceso a dos almohadillas SWD, soldé cables muy delgados a ellos y a todos los demás contactos disponibles.

Parpadea un poco
La siguiente tarea es intentar programar el dispositivo para alguna tarea. Para ejecutar el programa más simple, debemos asegurarnos de lo siguiente:
- Rastreamos correctamente los contactos de SWDIO / SWDCLK.
- El programador SWD se está ejecutando y la computadora puede emitir comandos.
- Podemos compilar el programa Arm y usar el SDK nórdico correctamente.
- Podemos actualizar el programa compilado en el chip.
- El chip funciona correctamente y carga nuestro programa.
En este caso, "hola, mundo" puede ser un programa que enciende y apaga el LED. E incluso esto no es elemental, porque no hay un LED incorporado en la placa, y si agrega uno externo, aún necesita averiguar a qué conectarlo. Esto agrega otra dimensión al modelo espacial del problema. De acuerdo con la falta de teorema del queso libre, acabo de conectar dos LED a los pines
P1
y
P2
con la esperanza de poder llegar a estos pads con el MCU.
Mal diaLos controladores y los programas de línea de comandos para el programador J-Link SWD se encuentran en
el sitio web de Segger . Si está en macOS y usa Homebrew, busque la fórmula de Cask en
caskroom/drivers/segger-jlink
. La comunicación con el programador SWD se establece desde la
JLinkExe
línea de comandos
JLinkExe
.
Luego descargué el
SDK nórdico nRF5 (estoy usando la
versión 12.3.0 ). A partir de los ejemplos de SDK, está claro que necesitamos un compilador capaz de compilar programas de Arm. Así que instalé
gcc-arm-embedded
(también disponible en Homebrew).
Después de examinar la documentación del SDK y los foros de desarrolladores nórdicos, descubrí que sus SDK se usan con mayor frecuencia en placas de desarrollo
como esta . El SDK está preconfigurado para varias variantes de dichos tableros. Dado que estamos en contacto directo con el controlador, deberá configurar algunos parámetros del SDK.
Pasé
mucho tiempo entendiendo el ecosistema nRF5, ¡pero al final todavía pude ejecutar el programa en un chip! El
video muestra dos LED parpadeantes. En este punto, creé
un repositorio de Github y descargué un programa con un
Makefile
funcionando
Makefile
. Uno de los principales secretos es que, de hecho, hay varias opciones para nRF51822, y en el mío solo hay 16 KB de memoria. Así que aún tenía que
arreglar el script del enlazador .
Entrada / salida digital
Como ya dije, la tarea con los LED parpadeantes proporcionó algunas esperanzas y un método de empuje, cuál de los contactos de MCU conduce a
P1
y
P2
, donde están conectados los LED. La estrategia más simple es conectar todas las salidas a su vez y aplicar alto y bajo voltaje a su vez. Para mi sorpresa, ¡ambos LED se iluminaron! ¡Estaba aún más sorprendido cuando el vibromotor comenzó a funcionar!
Entonces, el método de empuje agregado a la tabla:
NRF51822 pin | Parque infantil | Descripción |
---|
P0.30 | P1 | GPIO digital |
P0.00 | P2 | GPIO digital |
P0.01 | - | Motor de vibración |
printf
La capacidad de transferir datos a una computadora es indispensable para la depuración. El programador J-Link admite
la transmisión en tiempo real (RTT) para enviar y recibir datos desde el chip. Para usar RTT, debe
#include "SEGGER_RTT.h"
y llamar a
SEGGER_RTT_WriteString()
. Para recibir datos en una computadora, llame a la
jlinkrttlogger
línea de comando
jlinkrttlogger
, que se suministra con J-Link.
OLED
Otro desafío es hacer que OLED funcione. El OLED más común en el mercado ejecuta el controlador / controlador
ssd1306 y, por lo general, la comunicación con el MCU se realiza a través de una interfaz en serie utilizando
SPI o
I²C . Aquí hay
un ejemplo de Adafruit .
No encontré tal exhibición en ninguna de las tiendas ordinarias. Y el tamaño de 96 × 32 no es estándar. Una búsqueda por identificador QT1316P01A en la pantalla muestra sitios chinos como
Aliexpress , pero no hay documentación excepto los nombres de las conclusiones:
Nombre de PIN OLED con AliexpressSi la lista no miente, los contactos
SCL
,
SDA
y
RES#
nos dicen que esta es una opción I²C. Si hay pistas entre los tres pines de nRF51822 y estos tres pines de OLED, entonces daremos un paso adelante. Volvamos al microscopio.

Pistas de contacto de datos OLEDActualizamos la tabla de correspondencia:
NRF51822 pin | Parque infantil | Descripción |
---|
P0.21 | - | Salida OLED SDA |
P0.22 | - | Pin OLED SCL |
P0.24 | - | Salida OLED RES # |
El protocolo I²C es mucho más avanzado que cualquier protocolo serie simple como
UART . Una de las ventajas es que admite múltiples dispositivos maestros y esclavos en el mismo bus. Esto complica un poco las cosas: al menos necesita decirle a la MCU para qué comandos esclavos se emiten. Entonces, a un nivel alto, además de los contactos físicos, también hay una dirección "lógica" de la pantalla OLED.
Afortunadamente, un ejemplo en el SDK nRF5 es el escáner I²C. Él interroga desde todas las direcciones lógicas posibles e informa si algo está instalado allí. Mi versión modificada está
aquí . Produce el siguiente registro:
$ make
# ...
$ make flash
# ...
$ make log
# ...
TWI scanner.
TWI device detected at 0x3c.
¡Buenas noticias! Tenemos buenas razones para creer que la pantalla está correctamente identificada y que, de hecho, es una variante I²C. Una búsqueda en
0x3c
dice que
0x3c
es una dirección típica para tales dispositivos.
Ahora estamos listos para enviar algunos píxeles a la pantalla. En este nivel, no hay abstracción a través de la biblioteca.
Consulte la documentación de
ssd1306 para ver una forma de bajo nivel de transferir datos. El proceso consiste en una secuencia de comandos de configuración que establecen la orientación de la pantalla, el modo de grabación, el tamaño, etc. Luego, una secuencia de bytes que se muestran en la pantalla se envía a la memoria de visualización gráfica (GDDRAM).
Para la configuración correcta, estudié
la biblioteca ssd1306 de Adafruit e intenté emular comandos similares. Eso es lo que tomó la mayor parte del tiempo en este proyecto. Descubrir todos los detalles resultó ser una tarea que consume mucho tiempo, y aún así no puedo explicar algunas cosas. Sin embargo, funciona!
Mostrar un mapa de bits codificadoEl código para este ejemplo está
aquí .
Con esta configuración, la pantalla se divide en 4 filas (páginas) y 96 columnas. Entonces las páginas tienen 8 píxeles de alto. El primer byte enviado se ubicará "verticalmente" en la primera columna de la primera página. El segundo byte ocupará la segunda columna, luego la tercera y así sucesivamente, hasta la columna 96, cuando
regrese y comience desde la primera columna en la segunda página.
Este es el comportamiento
esperado . Como se
muestra en el video , el comportamiento
observado es diferente: primero se rellenan las columnas impares, luego las pares, y solo luego vuelve a la segunda página.
Pasé mucho tiempo para comprender la razón de un comportamiento de visualización tan estúpido, y luego más tiempo para configurarlo para solucionarlo. Al final, me tragué mi orgullo y todavía implementé una lógica de representación tan extraña en el programa para terminarla.
Viaja a Arduino
Al profundizar en
la biblioteca Adafruit ssd1306 para Arduino, siempre pensé que sería bueno tener una forma de "simular" bits Arduino específicos para probarlos en nRF51822. Resulta que las personas mucho más experimentadas también pensaron en este tema: esto es lo que hace el increíble proyecto de
sandeepmistry / arduino-nRF5 . Implementa las principales bibliotecas Arduino utilizando el SDK nRF5.
Con este proyecto, podemos abrir el IDE de Arduino, seleccionar la placa nRF5 y usar el rico ecosistema de Arduino.
Bifurqué el proyecto y agregué soporte para el tablero desde nuestro brazalete. Puede seleccionarlo en el menú desplegable
Tools > Board > ID115 Fitness Bracelet (nRF51822)
.

Biblioteca Adafruit ssd1306 en su forma original (arriba) y con un parche (abajo)También significa que ahora podemos usar la
biblioteca OLED Adafruit . Para mi sorpresa y alivio, ¡el mismo comportamiento extraño sucedió al completar primero columnas OLED pares e impares! Con gusto
bifurqué la biblioteca e implementé el mismo truco. En comparación con el enfoque de bajo nivel, ahora tenemos acceso a una variedad de abstracciones geniales, como la salida de texto:
El más familiar "¡Hola, mundo!"Entrada / salida analógica
Además de las señales digitales de encendido / apagado, el nRF51822 tiene 10 pines para entrada analógica. Esto es útil, por ejemplo, para leer la carga actual de la batería. A juzgar por la documentación, la lectura de contactos analógicos produce un valor de 10 bits. Por lo tanto, si hay
0V
en la entrada, entonces leeremos
0
, y si hay
VCC
, leeremos
1023
con valores intermedios entre ellos.
Periódicamente leo los valores de las entradas analógicas y trazo las señales más interesantes:

El efecto de sacudir la placa y cargar la batería de acuerdo con los datos de las entradas analógicasEstoy convencido de que el contacto
P0.05
refiere a la carga de la batería, porque el valor aumenta y disminuye a medida que se carga y descarga. Sospecho que el pin
P0.26
conectado a una de las salidas del acelerómetro, ya que se vuelve loco cuando sacude la placa. Los contactos
P0.03
y
P0.04
también se pueden conectar a varias salidas del acelerómetro, pero aquí un cierto efecto de segundo orden probablemente se superpone a la señal de la entrada. Por ejemplo, en el primer gráfico, observe cómo cambia el nivel de la batería (pin 5) cuando el acelerómetro necesita más energía. Este es un ejemplo de un efecto de segundo orden.
El código se puede encontrar
en este boceto . Los datos de origen y el guión gráfico están
aquí . Ahora podemos agregar varias filas a nuestra tabla de correspondencia:
NRF51822 pin | Parque infantil | Descripción |
---|
P0.05 | - | Entrada analógica: conectada a la batería |
P0.26 | - | Entrada analógica: acelerómetro de un eje |
P0.03 | - | Entrada analógica: un eje del acelerómetro (probable) |
P0.04 | - | Entrada analógica: un eje del acelerómetro (probable) |
Botón
En el firmware original, tocar el brazalete en cierto punto enciende la pantalla. Sosteniendo este punto comienza el cronómetro, si no recuerdo mal. Este no es un botón físico, sino una especie de cosa táctil capacitiva que funciona sorprendentemente bien. Utilizando el mismo enfoque que para buscar salidas digitales,
encontré un lugar para conectarme a la MCU (video) .
El codigo esta
aqui .
NRF51822 pin | Parque infantil | Descripción |
---|
P0.10 | - | Entrada digital - Botón incorporado |
Bluetooth de baja energía (BLE)
La funcionalidad BLE en chips nRF5 se implementa a través de algo llamado
SoftDevice . Este es un binario precompilado con una pila BLE. Se cose independientemente de la aplicación. Hay muchas versiones de SoftDevice, dependiendo de la versión del SDK y la versión del chip.
La
documentación proporciona una cierta matriz de dependencia (desafortunadamente, no puede ponerle un enlace directo). Muestra con qué SDK vienen las diferentes versiones del chip, y qué versión de SoftDevice es. En nuestro caso, el chip está marcado como QFAAH0, este chip tiene 256 KB de memoria flash, 16 KB de RAM y se declara la compatibilidad con SoftDevice s130.
Mi SDK versión 12.3 ya contiene algunos ejemplos de uso de SoftDevice s130. En comparación con los programas anteriores que están directamente conectados a microchips desde la dirección
0x0
, ahora necesita flashear SoftDevice desde la dirección
0x0
y el programa mismo desde la dirección
0x1b000
. Después de cargar e inicializar, el archivo binario SoftDevice irá a esta dirección y transferirá el control a nuestro programa. Para ilustrar, tomé el mismo ejemplo con LED parpadeantes, pero lo cambié por el firmware (
código ) de SoftDevice. El comportamiento observado no ha cambiado, excepto que debe pre-flashear SoftDevice:
$ make
# ...
$ make flash-softdevice
# ...
$ make flash
# ...
$ make log
# ...
Hello, world!
Quizás la aplicación más simple para Bluetooth es convertir el dispositivo en una
baliza . El dispositivo solo transmite su presencia. Un ejemplo de esto está en el SDK llamado
ble_app_beacon
. Se supone que SoftDevice
s130
ya
s130
.
Aquí, también, la comunicación de bajo nivel con el chip complica todo en comparación con la programación a través del SDK. Además de ajustar el tamaño de la RAM (este conocimiento fue difícil para mí en el ejemplo con LED), se reveló otro problema difícil de rastrear. Al final resultó que, la pila BLE utiliza un generador de reloj para realizar tareas urgentes. En los ejemplos de SDK, se supone un oscilador de cristal externo. Cuando me di cuenta de esto después de miles de intentos de
printf
, cambié la bandera de configuración para usar un generador de reloj sintético, y el problema se resolvió. El código fuente de la baliza está
aquí .
BLE + Arduino
Cuando el ejemplo BLE funcionó con el SDK nRF5, sabiendo las trampas con RAM y un generador, volví a mirar el entorno de Arduino. Y de nuevo, estaba el glorioso proyecto de
sandeepmistry / arduino-BLEPeripheral (del mismo tipo que arduino-nRF5!), Que proporciona excelentes abstracciones en la parte superior de la configuración interna de BLE.
Para mi sorpresa, ni siquiera tuve que bifurcar la biblioteca. El autor del proyecto arduino-nrf5 pasó tiempo y agregó la configuración de todos los tableros y configuraciones, por lo que ahora elegir el generador de reloj adecuado para SoftDevice se reduce a una opción simple en el menú desplegable
Tools > Low Frequency Clock > Synthesized
. Impresionante Rápidamente escribí
un ejemplo con el LED verde encendido a través de Bluetooth (con
esta aplicación ). Su trabajo se
muestra en el video .
Planes adicionales
Después de quejarse con esta tabla durante incontables horas, me pican las manos durante varias semanas para pegarla más lejos en la lavadora y olvidarla por un tiempo.