Esta é uma tradução. Artigo publicado em 27 de maio de 2018 Rastreador de fitness antes e depois da desmontagem
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ça
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 abertos
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 placa
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 ruim
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 Aliexpress
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 OLED
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 codificado
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)
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!"
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ógicas
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.