Hackear una pulsera de fitness barata

Esta es una traducción. Artículo publicado el 27 de mayo de 2018


Rastreador de ejercicios antes y después del desmontaje

Cuando 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 escala

Encontrar 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 abiertas

Usando 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 placa

Tenga 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 pinParque infantilDescripción
SWDIOIOSalida de datos para programar SWD
SWDCLKCLKSalida 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 dia

Los 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 pinParque infantilDescripción
P0.30P1GPIO digital
P0.00P2GPIO 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 Aliexpress

Si 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 OLED

Actualizamos la tabla de correspondencia:

NRF51822 pinParque infantilDescripció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 codificado

El 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ógicas

Estoy 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 pinParque infantilDescripció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 pinParque infantilDescripció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.

Source: https://habr.com/ru/post/es413895/


All Articles