Hackeando uma pulseira barata de fitness

Esta é uma tradução. Artigo publicado em 27 de maio de 2018


Rastreador de fitness antes e depois da desmontagem

Quando 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

Encontrar 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

Usando 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

Observe 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 pinParque infantilDescrição do produto
SWDIOIOSaída de dados para programação de SWD
SWDCLKCLKSaí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

Drivers 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 pinParque infantilDescrição do produto
P0.30P1GPIO digital
P0.00P2GPIO 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

Se 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

Atualizamos a tabela de correspondência:

NRF51822 pinParque infantilDescriçã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

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

Estou 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 pinParque infantilDescriçã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 pinParque infantilDescriçã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 s130s130 .

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.

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


All Articles