Ceci est une traduction. Article publié le 27 mai 2018
Tracker de fitness avant et après démontageLorsque je suis arrivée dans l'entreprise actuelle, le premier jour, on m'a gentiment offert un ensemble de cadeaux. Parmi eux se trouvait ce bracelet avec un tracker de fitness. Quel que soit votre amour de l'exercice, c'est un gadget incroyablement cool d'un point de vue purement technique:
- un très petit facteur de forme (environ 15 × 40 mm);
- Bluetooth basse énergie (BLE);
- Écran OLED (96 × 32 pixels);
- batterie
- Charge USB
- accéléromètre;
- moteur de vibration;
- le prix est d'environ 10 $ (!).
A l'extérieur, le seul identifiant sur le panneau arrière est l'autocollant «FCC ID: 2AHFTID115». Si vous le recherchez sur Google, il semble correspondre à l'appareil
ID115 et vous pouvez mĂŞme trouver
plusieurs photos de son intérieur. En regardant l'
une de ces photographies , si vous essayez dur, vous pouvez voir le nom du plus grand circuit intégré (IC): N51822. Cela suggère qu'il pourrait y avoir un microcontrôleur
nordique (MCU)
nRF51822 , un processeur ARM M0 32 bits avec prise en charge BLE intégrée, qui est théoriquement assez facile à programmer pour d'autres choses qu'un bracelet devrait faire.
Avant de démonter le gadget, je suis allé un peu plus sur Google et j'ai découvert que dans
certains bracelets similaires, la même puce est installée et que les gens l'ont programmée avec succès.
L'ouverture du boîtier n'a pas été si facile. Le couvercle en plastique noir est collé au fond gris. J'ai essayé un sèche-cheveux pour adoucir la colle et je l'ai patiemment coupé avec un petit couteau, en essayant de ne pas trop endommager le plastique. Après ouverture, je me suis assuré qu'il y avait bien du nRF51822. Plus tard, j'ai acheté un bracelet MCU presque identique à Texas Instrument. Gardez à l'esprit qu'il existe des options.
nRF51822 et stylo à bille pour échelleTrouver un moyen de communiquer
La
documentation indique que la puce peut être programmée / déboguée à l'aide de l'interface à deux broches SWD (ARM
Serial Wire Debug ). Si nous voulons établir un canal de communication avec une puce, cela signifie deux choses:
- Nous avons besoin d'un programmeur SWD (par exemple, Segger J-Link ).
- Nous aurons besoin d'accéder aux deux broches SWD du microcontrôleur, à savoir SWDIO (données) et SWDCLK (impulsions d'horloge).
Heureusement, plusieurs cartes sont disponibles sur la carte. Bien que leur existence soit clairement expliquée par le besoin de débogage, de test et de vérification, je préfère penser qu'un ingénieur cool les a laissés là comme de petits cadeaux pour des gens comme nous. Tous ne sont pas correctement étiquetés, je suggère donc les codes suivants:

Face avant et arrière de la carte de circuit imprimé. Stylo à bille pour les noms d'échelle et semi-arbitraires pour les pads ouvertsEn utilisant le même
microscope USB bon marché
, j'ai pris plusieurs photos des côtés avant et arrière de la carte et j'ai essayé de suivre les pistes du microcontrôleur aux pads.

Pistes vers les broches SWDIO et SWDCLK à l'avant et à l'arrière de la carteVeuillez noter qu'il s'agit d'une carte de circuit imprimé multicouche avec des trous traversants, vous devez donc vérifier les pistes des deux côtés de la carte. A partir de ces photos, vous pouvez suivre les traces des contacts SWDIO et SWDCLK sur la puce jusqu'aux pads IO et CLK. Nous allons donc nous assurer que la marque CLK sur la carte correspond à SWDCLK sur le MCU et que le contact sans étiquette est la broche SWDIO. Vous pouvez maintenant préparer notre première table de mappage:
NRF51822 pin | Aire de jeux | La description |
---|
SWDIO | IO | Sortie de données pour la programmation de SWD |
SWDCLK | CLK | Sortie d'horloge pour la programmation SWD |
Chirurgie post mortem
Ayant accédé à deux plots SWD, je leur ai soudé des fils très fins et à tous les autres contacts disponibles.

Clignote un peu
La tâche suivante consiste à essayer de programmer le périphérique pour une tâche. Pour exécuter le programme le plus simple, nous devons nous assurer des éléments suivants:
- Nous avons correctement suivi les contacts de SWDIO / SWDCLK.
- Le programmeur SWD est en cours d'exécution et l'ordinateur peut émettre des commandes.
- Nous pouvons compiler le programme Arm et utiliser correctement le Nordic SDK .
- Nous pouvons flasher le programme compilé dans la puce.
- La puce fonctionne correctement et charge notre programme.
Dans ce cas, «bonjour, monde» peut être un programme qui allume et éteint la LED. Et même cela n'est pas élémentaire, car il n'y a pas de LED intégrée sur la carte, et si vous en ajoutez une externe, vous devez toujours savoir à quoi la connecter. Cela ajoute une autre dimension au modèle spatial du problème. En raison du manque de théorème du fromage gratuit, je viens de connecter deux LED aux broches
P1
et
P2
dans l'espoir que nous puissions accéder à ces pads avec le MCU.
Mauvaise journéeLes pilotes et les programmes de ligne de commande pour le programmeur SWD J-Link se trouvent sur
le site Web de Segger . Si vous utilisez macOS et utilisez Homebrew, recherchez la formule Cask dans
caskroom/drivers/segger-jlink
. La communication avec le programmeur SWD est établie à partir de l'
JLinkExe
ligne de commande
JLinkExe
.
J'ai ensuite téléchargé le
Nordic nRF5 SDK (j'utilise la
version 12.3.0 ). D'après les exemples du SDK, il est clair que nous avons besoin d'un compilateur capable de compiler des programmes Arm. J'ai donc installé
gcc-arm-embedded
(également disponible sur Homebrew).
Après avoir examiné la documentation du SDK et les forums de développeurs nordiques, j'ai découvert que leurs SDK sont le plus souvent utilisés avec des cartes de développement
comme celle-ci . Le SDK est préconfiguré pour plusieurs variantes de ces cartes. Puisque nous sommes en contact direct avec le contrôleur, vous devrez configurer certains paramètres du SDK.
J'ai passé
beaucoup de temps à comprendre l'écosystème nRF5, mais au final j'ai quand même pu exécuter le programme sur une puce! La
vidéo montre deux LED clignotantes. À ce stade, j'ai créé
un référentiel Github et jeté un programme avec un
Makefile
fonctionnel
Makefile
. L'un des principaux secrets était qu'il existe en fait plusieurs options pour le nRF51822, et dans le mien, il n'y a que 16 Ko de mémoire. Je devais donc encore
corriger le script de l'éditeur de liens .
Entrée / sortie numérique
Comme je l'ai dĂ©jĂ dit, la tâche avec les LED clignotantes a fourni quelques espoirs et une mĂ©thode de poussĂ©e, qui des contacts MCU conduisent Ă
P1
et
P2
, où les LED sont connectées. La stratégie la plus simple est de connecter toutes les sorties à tour de rôle et d'appliquer tour à tour les hautes et basses tensions. À ma grande surprise, les deux LEDs se sont allumées! J'ai été encore plus surpris lorsque le vibromoteur a commencé à fonctionner!
Ainsi, la méthode poke ajoutée au tableau:
NRF51822 pin | Aire de jeux | La description |
---|
P0.30 | P1 | GPIO numérique |
P0.00 | P2 | GPIO numérique |
P0.01 | - | Moteur de vibration |
printf
La possibilité de transférer des données vers un ordinateur est indispensable pour le débogage. Le programmateur J-Link prend en charge
la transmission en temps réel (RTT) pour l'envoi et la réception de données à partir de la puce. Pour utiliser RTT, vous devez
#include "SEGGER_RTT.h"
et appeler
SEGGER_RTT_WriteString()
. Pour recevoir des données sur un ordinateur, appelez l'
jlinkrttlogger
ligne de commande
jlinkrttlogger
, fournie avec J-Link.
OLED
Un autre défi consiste à faire fonctionner l'OLED. L'OLED le plus courant sur le marché exécute le pilote / contrôleur
ssd1306 , et généralement la communication avec le MCU se fait via une interface série utilisant
SPI ou
I²C . Voici
un exemple d'Adafruit .
Je n'ai trouvé un tel affichage dans aucun des magasins ordinaires. Et la taille de 96 × 32 n'est pas standard. Une recherche par identifiant QT1316P01A sur l'affichage donne des sites chinois comme
Aliexpress , mais il n'y a pas de documentation sauf pour les noms des conclusions:
Nommage des broches OLED avec AliexpressSi la liste ne se trouve pas, alors les contacts
SCL
,
SDA
et
RES#
nous indiquent qu'il s'agit d'une option I²C. S'il y a des pistes entre les trois broches du nRF51822 et ces trois broches de l'OLED, alors nous ferons un pas en avant. Revenons au microscope.

Pistes de contact de données OLEDNous mettons à jour la table de correspondance:
NRF51822 pin | Aire de jeux | La description |
---|
P0.21 | - | Sortie OLED SDA |
P0.22 | - | Broche OLED SCL |
P0.24 | - | Sortie OLED RES # |
Le protocole I²C est beaucoup plus avancé que n'importe quel protocole série simple comme
UART . L'un des avantages est qu'il prend en charge plusieurs périphériques maître et esclave sur le même bus. Cela complique un peu les choses: au moins, vous devez indiquer au MCU pour quelles commandes esclaves sont émises. Ainsi à un niveau élevé, outre les contacts physiques, il existe également une adresse «logique» de l'écran OLED.
Heureusement, un exemple dans le SDK nRF5 est le scanner I²C. Il interroge à partir de toutes les adresses logiques possibles et signale si quelque chose y est installé. Ma version modifiée est
ici . Il produit le journal suivant:
$ make
# ...
$ make flash
# ...
$ make log
# ...
TWI scanner.
TWI device detected at 0x3c.
Bonne nouvelle! Nous avons de bonnes raisons de croire que l'affichage est correctement identifié et qu'il s'agit bien d'une variante I²C. Une recherche
0x3c
indique que
0x3c
est une adresse typique pour ces appareils.
Nous sommes maintenant prêts à envoyer quelques pixels à l'écran. A ce niveau, il n'y a pas d'abstraction via la bibliothèque.
Voir la documentation
ssd1306 pour un moyen de bas niveau de transférer des données. Le processus consiste en une séquence de commandes de configuration qui définissent l'orientation de l'affichage, le mode d'enregistrement, la taille, etc. Ensuite, une séquence d'octets affichés à l'écran est envoyée à la mémoire d'affichage graphique (GDDRAM).
Pour la configuration correcte, j'ai étudié
la bibliothèque ssd1306 d'Adafruit et essayé d'émuler des commandes similaires. C'est ce qu'a pris la part du lion dans ce projet. Découvrir tous les détails s'est avéré être une tâche très longue, et je ne peux toujours pas expliquer certaines choses. Mais ça marche!
Afficher une image bitmap codée en durLe code de cet exemple est
ici .
Avec ces paramètres, l'affichage est divisé en 4 lignes (pages) et 96 colonnes. Les pages mesurent donc 8 pixels. Le premier octet envoyé sera situé "verticalement" dans la première colonne de la première page. Le deuxième octet occupera la deuxième colonne, puis la troisième et ainsi de suite, jusqu'à la 96e colonne, quand il
reviendra et commencera à partir de la première colonne de la deuxième page.
C'est le comportement
attendu . Comme le
montre la vidéo , le comportement
observé est différent: d'abord les colonnes impaires sont remplies, puis les paires, et ensuite seulement, il revient à la deuxième page.
J'ai passé beaucoup de temps à comprendre la raison d'un tel comportement d'affichage stupide, puis un peu plus de temps pour le configurer pour le réparer. Au final, j'ai ravalé ma fierté et j'ai quand même implémenté une logique de rendu aussi étrange dans le programme pour le terminer.
Voyage Ă Arduino
En
fouillant dans
la bibliothèque Adafruit ssd1306 pour Arduino, j'ai toujours pensé qu'il serait bien d'avoir un moyen de "simuler" des bits Arduino spécifiques pour les tester sur nRF51822. Il s'avère que des gens beaucoup plus expérimentés ont également pensé à ce sujet - c'est ce que fait l'incroyable projet
sandeepmistry / arduino-nRF5 . Il implémente les principales bibliothèques Arduino en utilisant le SDK nRF5.
Avec ce projet, nous pouvons ouvrir l'IDE Arduino, sélectionner la carte nRF5 et utiliser le riche écosystème Arduino. J'ai
bifurqué le projet et ajouté le support pour la planche de notre bracelet. Vous pouvez le sélectionner dans le menu déroulant
Tools > Board > ID115 Fitness Bracelet (nRF51822)
.

Bibliothèque Adafruit ssd1306 dans sa forme originale (ci-dessus) et avec un patch (ci-dessous)Cela signifie également que nous pouvons désormais utiliser la
bibliothèque OLED d'Adafruit . À ma grande surprise et soulagement, le même comportement étrange s'est produit en remplissant d'abord les colonnes OLED impaires et même paires! J'ai heureusement
bifurqué la bibliothèque et implémenté le même hack. Par rapport à l'approche de bas niveau, nous avons maintenant accès à une variété d'abstractions intéressantes, telles que la sortie de texte:
Le plus familier "Bonjour, monde!"Entrée / sortie analogique
En plus des signaux numériques marche / arrêt, le nRF51822 possède 10 broches pour l'entrée analogique. Ceci est utile, par exemple, pour lire la charge actuelle de la batterie. À en juger par la documentation, la lecture des contacts analogiques produit une valeur de 10 bits. Par conséquent, s'il y a
0V
à l'entrée, alors nous lirons
0
, et s'il y a
VCC
, nous lirons
1023
avec des valeurs intermédiaires entre elles.
J'ai lu périodiquement les valeurs des entrées analogiques et tracé les signaux les plus intéressants:

L'effet de secouer la carte et de charger la batterie en fonction des données des entrées analogiquesJe suis convaincu que le contact
P0.05
fait référence à la charge de la batterie, car la valeur augmente et diminue à mesure qu'elle se charge et se décharge. Je soupçonne que la broche
P0.26
connectée à l'une des sorties de l'accéléromètre, car elle devient folle lorsque vous secouez la carte. Les contacts
P0.03
et
P0.04
peuvent également être connectés à différentes sorties de l'accéléromètre, mais ici un certain effet de second ordre est très probablement superposé au signal de l'entrée. Par exemple, dans le premier graphique, notez comment le niveau de la batterie (broche 5) change lorsque l'accéléromètre a besoin de plus d'énergie. Ceci est un exemple d'un effet de second ordre.
Le code peut être trouvé
dans ce croquis . Les données source et le script graphique sont
ici . Nous pouvons maintenant ajouter plusieurs lignes Ă notre table de correspondance:
NRF51822 pin | Aire de jeux | La description |
---|
P0.05 | - | Entrée analogique - connectée à la batterie |
P0.26 | - | Entrée analogique - Accéléromètre à un axe |
P0.03 | - | Entrée analogique - un axe de l'accéléromètre (probable) |
P0.04 | - | Entrée analogique - un axe de l'accéléromètre (probable) |
Bouton
Dans le firmware d'origine, toucher le bracelet à un certain moment allume l'écran. Tenir ce point démarre le chronomètre, si je me souviens bien. Ce n'est pas un bouton physique, mais une sorte de tactile capacitif qui fonctionne étonnamment bien. En utilisant la même approche que pour la recherche de sorties numériques, j'ai
trouvé un endroit pour me
connecter au MCU (vidéo) .
Le code est
ici .
NRF51822 pin | Aire de jeux | La description |
---|
P0.10 | - | Entrée numérique - bouton intégré |
Bluetooth basse énergie (BLE)
La fonctionnalité BLE sur les puces nRF5 est implémentée via quelque chose appelé
SoftDevice . Il s'agit d'un binaire précompilé avec une pile BLE. Il est cousu quelle que soit l'application. Il existe de nombreuses versions de SoftDevice, selon la version du SDK et la version de la puce.
La
documentation fournit une certaine matrice de dépendances (malheureusement, vous ne pouvez pas y mettre de lien direct). Il montre avec quel SDK les différentes versions de la puce sont livrées - et de quelle version de SoftDevice il s'agit. Dans notre cas, la puce est marquée QFAAH0, cette puce possède 256 Ko de mémoire flash, 16 Ko de RAM et la compatibilité avec SoftDevice s130 est déclarée.
Mon SDK version 12.3 contient déjà quelques exemples d'utilisation de SoftDevice s130. Par rapport aux programmes précédents qui sont directement câblés dans des puces électroniques à partir de l'adresse
0x0
, vous devez maintenant flasher SoftDevice Ă partir de l'adresse
0x0
et le programme lui-mĂŞme Ă partir de l'adresse
0x1b000
. Après chargement et initialisation, le fichier binaire SoftDevice ira à cette adresse et transférera le contrôle à notre programme. Pour illustrer, j'ai pris le même exemple avec des LED clignotantes, mais je l'ai changé pour le firmware SoftDevice (
code ). Le comportement observé n'a pas changé, sauf que vous devez pré-flasher SoftDevice:
$ make
# ...
$ make flash-softdevice
# ...
$ make flash
# ...
$ make log
# ...
Hello, world!
L'application la plus simple pour Bluetooth est peut-ĂŞtre de transformer l'appareil en
balise . L'appareil diffuse uniquement sa présence. Un tel exemple est dans le SDK appelé
ble_app_beacon
. Il suppose que SoftDevice
s130
déjà flashé.
Ici aussi, la communication de bas niveau avec la puce complique tout par rapport à la programmation via le SDK. En plus d'ajuster la taille de la RAM (cette connaissance était difficile pour moi dans l'exemple avec les LED), un autre problème difficile à suivre a été révélé. Il s'est avéré que la pile BLE utilise un générateur d'horloge pour effectuer des tâches urgentes. Dans les exemples du SDK, un oscillateur à cristal externe est supposé. Quand j'ai réalisé cela après des milliers de tentatives de
printf
, j'ai changé l'indicateur de configuration pour utiliser un générateur d'horloge synthétique, et le problème a été résolu. Le code source de la balise est
ici .
BLE + Arduino
Lorsque l'exemple BLE a fonctionné avec le SDK nRF5, connaissant les pièges avec RAM et un générateur, j'ai de nouveau regardé l'environnement Arduino. Et encore une fois, il y avait le glorieux projet
sandeepmistry / arduino-BLEPeripheral (du même gars que arduino-nRF5!), Qui fournit d'excellentes abstractions en plus des paramètres BLE internes.
À ma grande surprise, je n'ai même pas eu à bifurquer la bibliothèque. L'auteur du projet arduino-nrf5 a passé du temps et ajouté la configuration de toutes les cartes et paramètres, donc maintenant choisir le bon générateur d'horloge pour SoftDevice se résume à un choix simple dans le menu déroulant
Tools > Low Frequency Clock > Synthesized
. Génial. J'ai rapidement écrit
un exemple avec la LED verte allumée via Bluetooth (avec
cette application ). Son travail est
montré dans la vidéo .
Plans supplémentaires
Après avoir agité cette planche pendant d'innombrables heures, mes mains me démangent pendant plusieurs semaines pour la coller plus loin dans la machine à laver et l'oublier pendant un certain temps.