Esta é uma tradução. Artigo publicado em 27 de maio de 2018
Rastreador de fitness antes e depois da desmontagemQuando cheguei à empresa atual, no primeiro dia, recebi um conjunto de presentes. Entre eles estava esta pulseira com um rastreador de fitness. Independentemente do seu amor pelo exercício, este é um gadget incrivelmente legal do ponto de vista puramente técnico:
- um fator de forma realmente pequeno (aproximadamente 15 × 40 mm);
- Baixa energia Bluetooth (BLE);
- Tela OLED (96 × 32 pixels);
- bateria
- Carga USB
- acelerômetro;
- motor de vibração;
- o preço é de cerca de US $ 10 (!).
Lá fora, o único identificador no painel traseiro é o adesivo “FCC ID: 2AHFTID115”. Se você pesquisar no Google, ele parece corresponder ao dispositivo
ID115 e você pode até encontrar
várias fotos de seu interior. Olhando para
uma dessas fotografias , se você se esforçar, pode ver o nome do maior circuito integrado (IC): N51822. Isso sugere que pode haver um microcontrolador
nórdico (MCU)
nRF51822 , um processador ARM M0 de 32 bits com suporte BLE integrado, o que é teoricamente bastante fácil de programar para outras coisas que uma pulseira deve fazer.
Antes de desmontar o gadget, fui ao Google um pouco mais e descobri que em
algumas pulseiras semelhantes o mesmo chip está instalado e as pessoas o programaram com sucesso.
Abrir o estojo não foi tão fácil. A tampa de plástico preta é colada ao fundo cinza. Tentei um secador de cabelo para amolecer a cola e pacientemente a cortei com uma faca pequena, tentando não danificar muito o plástico. Após a abertura, verifiquei se realmente existe o nRF51822. Mais tarde, comprei uma pulseira MCU quase idêntica da Texas Instrument. Lembre-se de que existem opções.
nRF51822 e caneta esferográfica para balançaEncontrar uma maneira de se comunicar
A
documentação diz que o chip pode ser programado / depurado usando a interface de dois pinos do ARM
Serial Wire Debug (SWD). Se queremos estabelecer um canal de comunicação com um chip, isso significa duas coisas:
- Precisamos de um programador SWD (por exemplo, Segger J-Link ).
- Nós precisaremos acessar os dois pinos SWD no microcontrolador, a saber SWDIO (dados) e SWDCLK (pulsos de clock).
Felizmente, existem vários painéis disponíveis no quadro. Embora sua existência seja explicada claramente pela necessidade de depuração, teste e verificação, prefiro pensar que algum engenheiro legal os deixou lá como pequenos presentes para pessoas como nós. Nem todos eles estão devidamente rotulados, por isso sugiro os seguintes códigos:

Lados dianteiro e traseiro da placa de circuito. Caneta esferográfica para escala e nomes semi-arbitrários para blocos abertosUsando o mesmo
microscópio USB barato
, tirei várias fotos da frente e de trás da placa e tentei rastrear as faixas do microcontrolador até as almofadas.

Faixas para os pinos SWDIO e SWDCLK na frente e atrás da placaObserve que esta é uma placa de circuito impresso de várias camadas com orifícios passantes, portanto verifique as faixas nos dois lados da placa. A partir dessas fotos, você pode acompanhar as faixas dos contatos SWDIO e SWDCLK no chip até os blocos IO e CLK. Portanto, garantiremos que a marca CLK na placa corresponda ao SWDCLK no MCU e o contato não marcado seja o pino SWDIO. Agora você pode preparar nossa primeira tabela de mapeamento:
NRF51822 pin | Parque infantil | Descrição do produto |
---|
SWDIO | IO | Saída de dados para programação de SWD |
SWDCLK | CLK | Saída de relógio para programação SWD |
Cirurgia post-mortem
Tendo obtido acesso a dois blocos de SWD, eu soldava fios muito finos a eles e a todos os outros contatos disponíveis.

Pisque um pouco
A próxima tarefa é tentar programar o dispositivo para alguma tarefa. Para executar o programa mais simples, precisamos garantir o seguinte:
- Nós rastreamos corretamente os contatos do SWDIO / SWDCLK.
- O programador SWD está em execução e o computador pode emitir comandos.
- Podemos compilar o programa Arm e usar o Nordic SDK corretamente.
- Podemos exibir o programa compilado no chip.
- O chip funciona corretamente e carrega o nosso programa.
Nesse caso, “olá, mundo” pode ser um programa que liga e desliga o LED. E mesmo isso não é fundamental, porque não há LED embutido na placa e, se você adicionar um externo, ainda precisará descobrir com o que conectá-lo. Isso adiciona outra dimensão ao modelo espacial do problema. De acordo com a falta de teorema do queijo livre, acabei de conectar dois LEDs aos pinos
P1
e
P2
com a esperança de que pudéssemos chegar a esses blocos com o MCU.
Dia ruimDrivers e programas de linha de comando para o programador J-Link SWD estão localizados no
site da Segger . Se você estiver no macOS e estiver usando o Homebrew, procure a fórmula Cask em
caskroom/drivers/segger-jlink
. A comunicação com o programador SWD é estabelecida no
JLinkExe
linha de comando
JLinkExe
.
Então baixei o
Nordic nRF5 SDK (estou usando a
versão 12.3.0 ). A partir dos exemplos do SDK, fica claro que precisamos de um compilador capaz de compilar programas Arm. Então eu instalei o
gcc-arm-embedded
(também disponível no Homebrew).
Depois de examinar a documentação do SDK e os fóruns de desenvolvedores nórdicos, descobri que seus SDKs são usados com mais freqüência em placas de desenvolvimento
como essa . O SDK é pré-configurado para várias variantes dessas placas. Como estamos em contato direto com o controlador, você terá que configurar alguns parâmetros do SDK.
Passei
muito tempo entendendo o ecossistema nRF5, mas no final ainda era capaz de executar o programa em um chip! O
vídeo mostra dois LEDs piscando. Nesse ponto, criei
um repositório do Github e joguei um programa com um
Makefile
funcionamento. Um dos principais segredos foi que, de fato, existem várias opções para o nRF51822 e, no meu, existem apenas 16 KB de memória. Então, eu ainda tinha que
corrigir o script do vinculador .
Entrada / saída digital
Como eu já disse, a tarefa com LEDs piscando forneceu algumas esperanças e um método de puxão, quais dos contatos do MCU levam a
P1
e
P2
, onde os LEDs estão conectados. A estratégia mais simples é conectar todas as saídas e aplicar alta e baixa tensão por sua vez. Para minha surpresa, os dois LEDs acenderam! Fiquei ainda mais surpreso quando o vibromotor começou a funcionar!
Portanto, o método poke adicionado à tabela:
NRF51822 pin | Parque infantil | Descrição do produto |
---|
P0.30 | P1 | GPIO digital |
P0.00 | P2 | GPIO digital |
P0.01 | - | Motor de vibração |
printf
A capacidade de transferir dados para um computador é indispensável para depuração. O programador J-Link suporta
transmissão em tempo real (RTT) para enviar e receber dados do chip. Para usar o RTT, você precisa
#include "SEGGER_RTT.h"
e chamar
SEGGER_RTT_WriteString()
. Para receber dados em um computador, chame a
jlinkrttlogger
linha de comandos
jlinkrttlogger
, fornecida com o J-Link.
OLED
Outro desafio é fazer o OLED funcionar. O OLED mais comum no mercado executa o driver / controlador
ssd1306 , e geralmente a comunicação com o MCU é via interface serial usando
SPI ou
I²C . Aqui está
um exemplo de Adafruit .
Eu não encontrei essa exibição em nenhuma loja comum. E o tamanho de 96 × 32 não é padrão. Uma pesquisa pelo identificador QT1316P01A no visor fornece sites chineses como
Aliexpress , mas não há documentação, exceto os nomes das conclusões:
Nomeação de pinos OLED com AliexpressSe a lista não aparecer, os contatos
SCL
,
SDA
e
RES#
nos dizem que essa é uma opção de I²C. Se houver faixas entre os três pinos do nRF51822 e esses três pinos do OLED, daremos um passo à frente. Vamos voltar ao microscópio.

Faixas de contato de dados OLEDAtualizamos a tabela de correspondência:
NRF51822 pin | Parque infantil | Descrição do produto |
---|
P0.21 | - | Saída OLED SDA |
P0.22 | - | Pino OLED SCL |
P0.24 | - | Saída OLED RES # |
O protocolo I²C é muito mais avançado do que qualquer protocolo serial simples como o
UART . Uma das vantagens é que ele suporta vários dispositivos mestre e escravo no mesmo barramento. Isso complica um pouco as coisas: pelo menos você precisa dizer ao MCU para o qual os comandos escravos são emitidos. Portanto, em um nível alto, além dos contatos físicos, há também um endereço "lógico" do display OLED.
Felizmente, um exemplo no nRF5 SDK é o scanner I²C. Ele interroga a partir de todos os endereços lógicos e relatórios possíveis, se algo estiver instalado lá. Minha versão modificada está
aqui . Produz o seguinte log:
$ make
# ...
$ make flash
# ...
$ make log
# ...
TWI scanner.
TWI device detected at 0x3c.
Boas notícias! Temos boas razões para acreditar que a tela está corretamente identificada e que é realmente uma variante de I²C. Uma pesquisa no
0x3c
diz que
0x3c
é um endereço típico para esses dispositivos.
Agora estamos prontos para enviar alguns pixels para a tela. Nesse nível, não há abstração na biblioteca.
Consulte a documentação do
ssd1306 para uma maneira de baixo nível de transferência de dados. O processo consiste em uma sequência de comandos de configuração que definem a orientação da tela, modo de gravação, tamanho, etc. Em seguida, uma sequência de bytes que é exibida na tela é enviada para a memória gráfica (GDDRAM).
Para a configuração correta, estudei
a biblioteca ssd1306 da Adafruit e tentei emular comandos semelhantes. Foi isso que levou a maior parte do tempo neste projeto. Descobrir todos os detalhes acabou sendo uma tarefa muito demorada, e ainda não consigo explicar algumas coisas. No entanto, funciona!
Exibir um bitmap codificadoO código para este exemplo está
aqui .
Com essas configurações, a exibição é dividida em 4 linhas (páginas) e 96 colunas. Portanto, as páginas têm 8 pixels de altura. O primeiro byte enviado será localizado "verticalmente" na primeira coluna da primeira página. O segundo byte ocupará a segunda coluna, depois a terceira e assim por diante, até a 96ª coluna, quando
retornar e iniciar a partir da primeira coluna na segunda página.
Esse é o comportamento
esperado . Como
mostrado no vídeo , o comportamento
observado é diferente: primeiro as colunas ímpares são preenchidas, depois as pares e, somente então, retorna à segunda página.
Gastei muito tempo para entender o motivo de um comportamento tão estúpido de exibição e, em seguida, mais tempo para configurá-lo para corrigi-lo. No final, engoli meu orgulho e ainda implementei uma lógica de renderização tão estranha no programa para finalizá-lo.
Viajar para Arduino
Investigando a biblioteca Adafruit ssd1306 para Arduino, sempre achei que seria bom ter uma maneira de "simular" bits específicos do Arduino para testá-los no nRF51822. Acontece que pessoas muito mais experientes também pensaram neste tópico - é isso que o incrível projeto
sandeepmistry / arduino-nRF5 faz . Ele implementa as principais bibliotecas do Arduino usando o nRF5 SDK.
Com este projeto, podemos abrir o IDE do Arduino, selecionar a placa nRF5 e usar o rico ecossistema do Arduino.
Bifurquei o projeto e adicionei suporte para o quadro usando nossa pulseira. Você pode selecioná-lo no menu suspenso
Tools > Board > ID115 Fitness Bracelet (nRF51822)
.

Biblioteca Adafruit ssd1306 em sua forma original (acima) e com um patch (abaixo)Isso também significa que agora podemos usar a
biblioteca OLED da
Adafruit . Para minha surpresa e alívio, o mesmo comportamento estranho aconteceu com o preenchimento de colunas OLED pares e ímpares primeiro! De bom grado
bifurquei a biblioteca e implementei o mesmo hack. Comparado à abordagem de baixo nível, agora temos acesso a uma variedade de abstrações interessantes, como a saída de texto:
O mais familiar "Olá, mundo!"Entrada / saída analógica
Além dos sinais on / off digitais, o nRF51822 possui 10 pinos para entrada analógica. Isso é útil, por exemplo, para ler a carga atual da bateria. A julgar pela documentação, a leitura de contatos analógicos produz um valor de 10 bits. Portanto, se houver
0V
na entrada, leremos
0
e, se houver
VCC
, leremos
1023
com valores intermediários entre eles.
Li periodicamente os valores das entradas analógicas e tracei os sinais mais interessantes:

O efeito de agitar a placa e carregar a bateria de acordo com os dados das entradas analógicasEstou convencido de que o contato
P0.05
se refere à carga da bateria, porque o valor aumenta e diminui à medida que carrega e descarrega. Suspeito que o pino
P0.26
conectado a uma das saídas do acelerômetro, pois fica louco quando você sacode a placa. Os contatos
P0.04
e
P0.04
também
podem ser conectados a várias saídas do acelerômetro, mas aqui um certo efeito de segunda ordem é provavelmente sobreposto ao sinal da entrada. Por exemplo, no primeiro gráfico, observe como o nível da bateria (pino 5) muda quando o acelerômetro precisa de mais energia. Este é um exemplo de um efeito de segunda ordem.
O código pode ser encontrado
neste esboço . Os dados de origem e o script gráfico estão
aqui . Agora podemos adicionar várias linhas à nossa tabela de correspondência:
NRF51822 pin | Parque infantil | Descrição do produto |
---|
P0.05 | - | Entrada Analógica - Conectada à Bateria |
P0.26 | - | Entrada Analógica - Acelerômetro de Um Eixo |
P0.03 | - | Entrada analógica - um eixo do acelerômetro (provável) |
P0.04 | - | Entrada analógica - um eixo do acelerômetro (provável) |
Botão
No firmware original, tocar na pulseira em um determinado momento liga o visor. Manter esse ponto inicia o cronômetro, se bem me lembro. Este não é um botão físico, mas algum tipo de toque capacitivo que funciona surpreendentemente bem. Utilizando a mesma abordagem usada para procurar saídas digitais,
encontrei um local para conectar ao MCU (vídeo) .
O código está
aqui .
NRF51822 pin | Parque infantil | Descrição do produto |
---|
P0.10 | - | Entrada Digital - Botão Integrado |
Baixa energia Bluetooth (BLE)
A funcionalidade BLE nos chips nRF5 é implementada através de algo chamado
SoftDevice . Este é um binário pré-compilado com uma pilha BLE. É costurado independentemente da aplicação. Existem muitas versões do SoftDevice, dependendo da versão do SDK e da versão do chip.
A
documentação fornece uma certa matriz de dependência (infelizmente, você não pode colocar um link direto para ela). Ele mostra com qual SDK as diferentes versões do chip são fornecidas - e qual é a versão do SoftDevice. No nosso caso, o chip está marcado como QFAAH0, este chip possui 256 KB de memória flash, 16 KB de RAM e a compatibilidade com o SoftDevice s130 é declarada.
Meu SDK versão 12.3 já contém alguns exemplos de uso do SoftDevice s130. Comparado aos programas anteriores conectados diretamente em microchips a partir do endereço
0x0
, agora você precisa atualizar o SoftDevice a partir do endereço
0x0
e o próprio programa a partir do endereço
0x1b000
. Após o carregamento e a inicialização, o arquivo binário SoftDevice irá para esse endereço e transferirá o controle para o nosso programa. Para ilustrar, tomei o mesmo exemplo com LEDs piscando, mas mudei para o firmware SoftDevice (
código ). O comportamento observado não foi alterado, exceto pelo pré-flash do SoftDevice:
$ make
# ...
$ make flash-softdevice
# ...
$ make flash
# ...
$ make log
# ...
Hello, world!
Talvez o aplicativo mais simples para Bluetooth seja transformar o dispositivo em um
farol . O dispositivo apenas transmite sua presença. Um exemplo está no SDK chamado
ble_app_beacon
. Parte do princípio que o SoftDevice
s130
já
s130
.
Aqui, também, a comunicação de baixo nível com o chip complica tudo em comparação à programação via SDK. Além de ajustar o tamanho da RAM (esse conhecimento foi difícil para mim no exemplo com LEDs), outro problema difícil de rastrear foi revelado. Como se viu, a pilha BLE usa um gerador de relógio para executar tarefas sensíveis ao tempo. Nos exemplos do SDK, é assumido um oscilador de cristal externo. Quando percebi isso depois de milhares de tentativas de
printf
, mudei o sinalizador de configuração para usar um gerador de relógio sintético e o problema foi resolvido. O código fonte do farol está
aqui .
BLE + Arduino
Quando o exemplo BLE trabalhou com o nRF5 SDK, conhecendo as armadilhas com RAM e um gerador, olhei novamente para o ambiente do Arduino. E, novamente, houve o glorioso projeto
sandeepmistry / arduino-BLEPeripheral (do mesmo cara que o arduino-nRF5!), Que fornece excelentes abstrações sobre as configurações internas do BLE.
Para minha surpresa, nem precisei bifurcar a biblioteca. O autor do projeto arduino-nrf5 gastou tempo e adicionou a configuração de todas as placas e configurações; agora, a escolha do gerador de clock certo para o SoftDevice se resume a uma escolha simples no menu suspenso
Tools > Low Frequency Clock > Synthesized
. Awesome. Eu rapidamente escrevi
um exemplo com o LED verde aceso via Bluetooth (com
este aplicativo ). Seu trabalho é
mostrado no vídeo .
Planos adicionais
Depois de mexer nesta prancha por inúmeras horas, minhas mãos coçam por várias semanas para colocá-la mais longe na máquina de lavar e esquecê-la por um tempo.