这是翻译。 文章发表于2018年5月27日
健身追踪器拆卸前后当我来到现任公司时,第一天给了我一套礼物。 其中包括带健身追踪器的手链。 无论您热爱运动,从纯技术角度来看,这都是一个非常酷的小工具:
- 很小的外形尺寸(约15×40毫米);
- 低功耗蓝牙(BLE);
- OLED显示屏(96×32像素);
- 电池
- USB充电
- 加速度计
- 振动马达
- 价格大约是10美元(!)。
在外面,后面板上唯一的标识符是标贴“ FCC ID:2AHFTID115”。 如果您用它搜索,它似乎与
ID115设备相对应,甚至可以找到其内部的
几张照片 。 回顾
其中一张照片 ,如果您努力尝试,您会看到最大的集成电路(IC)的名称:N51822。 这表明可能存在
Nordic微控制器(MCU)
nRF51822 ,这是一种具有内置BLE支持的32位ARM M0处理器,从理论上讲,它很容易编程为手镯应做的其他事情。
在拆卸小工具之前,我松了一口气,发现在
一些类似的手镯中 ,安装了相同的芯片,人们成功地对其进行了编程。
打开案件并非易事。 黑色塑料盖粘在灰色背景上。 我尝试使用吹风机软化胶水,然后耐心地用小刀将其切开,以免损坏塑料。 打开后,我确保确实有nRF51822。 后来我从德州仪器(TI)购买了几乎完全相同的MCU手镯。 请记住,有很多选择。
nRF51822和圆珠笔用于刻度寻找一种沟通方式
该
文档说,可以使用ARM
串行线调试 (SWD)两针接口对芯片进行编程/调试。 如果我们要与芯片建立通信通道,则意味着两件事:
- 我们需要一个SWD程序员(例如Segger J-Link )。
- 我们将需要访问微控制器上的两个SWD引脚,即SWDIO(数据)和SWDCLK(时钟脉冲)。
幸运的是,板上有几个焊盘。 尽管通过调试,测试和验证的需要可以清楚地说明它们的存在,但我更倾向于认为一些出色的工程师将它们作为礼物送给像我们这样的人。 并非所有标签都正确标记,因此我建议使用以下代码:

电路板的正面和背面。 圆珠笔,用于刻度盘和半任意名称的开口垫使用相同的廉价
USB显微镜,我拍摄了电路板正面和背面的几张照片,并试图跟踪从微控制器到焊盘的轨迹。

跟踪板正面和背面的SWDIO和SWDCLK引脚请注意,这是带有通孔的多层印刷电路板,因此您应检查电路板两侧的走线。 从这些照片中,您可以跟踪从芯片上的触点SWDIO和SWDCLK到焊盘IO和CLK的轨迹。 因此,我们将确保板上的CLK标记与MCU上的SWDCLK对应,并且未标记的触点为SWDIO引脚。 现在,您可以准备我们的第一个映射表:
NRF51822针 | 游乐场 | 内容描述 |
---|
软件 | IO | 数据输出用于SWD编程 |
时钟 | 时钟 | SWD编程的时钟输出 |
验尸手术
获得了两个SWD焊盘后,我将非常细的电线焊接到了它们以及所有其他可用的触点上。

眨一下
下一个任务是尝试对设备进行编程以完成某些任务。 要运行最简单的程序,我们需要确保以下几点:
- 我们正确地跟踪了SWDIO / SWDCLK的触点。
- SWD编程器正在运行,计算机可以发出命令。
- 我们可以编译Arm程序并正确使用Nordic SDK 。
- 我们可以将编译后的程序闪存到芯片中。
- 该芯片可以正常工作并加载我们的程序。
在这种情况下,“ hello,world”可以是打开和关闭LED的程序。 甚至这都不是基本的,因为板上没有内置LED,并且如果您添加一个外部LED,您仍然需要弄清楚将其连接到什么位置。 这为问题的空间模型增加了另一个维度。 由于缺乏免费的奶酪定理,我只将两个LED连接到引脚
P1
和
P2
,希望我们可以使用MCU来连接这些焊盘。
糟糕的一天J-Link SWD编程器的驱动程序和命令行程序位于
Segger网站上 。 如果您使用macOS并使用Homebrew,请在
caskroom/drivers/segger-jlink
查找Cask公式。 通过
JLinkExe
命令行
JLinkExe
程序可建立与SWD程序员的通信。
然后,我下载了
Nordic nRF5 SDK (我正在使用
版本12.3.0 )。 从SDK示例中可以明显看出,我们需要一个能够编译Arm程序的编译器。 因此,我安装了
gcc-arm-embedded
(也可以在Homebrew上找到)。
在查看了SDK文档和Nordic开发者论坛之后,我发现他们的SDK最常与
此类开发板一起使用。 SDK已针对此类板的多种变体进行了预配置。 由于我们直接与控制器联系,因此您必须配置一些SDK参数。
我花了
很多时间来了解nRF5生态系统,但最终我仍然能够在芯片上运行该程序!
视频显示两个闪烁的LED。 至此,我创建
了一个Github存储库,并在其中转储了带有可用
Makefile
的程序。 主要秘密之一是,实际上nRF51822有多种选择,而在我的内存中只有16 KB的内存。 因此,我仍然必须
修复链接脚本 。
数字量输入/输出
就像我已经说过的那样,LED闪烁的任务提供了一些希望和解决方法,MCU触点中的哪一个通向LED所连接的
P1
和
P2
。 最简单的策略是依次连接所有输出并依次施加高低压。 令我惊讶的是,两个LED都亮了! 振动马达开始工作时,我感到更加惊讶!
因此,将poke方法添加到表中:
NRF51822针 | 游乐场 | 内容描述 |
---|
P0.30 | P1 | 数字GPIO |
P0.00 | P2 | 数字GPIO |
P0.01 | -- | 振动马达 |
打印
对于调试来说,将数据传输到计算机的能力是必不可少的。 J-Link编程器支持
实时传输(RTT),用于从芯片发送和接收数据。 要使用RTT,您需要
#include "SEGGER_RTT.h"
并调用
SEGGER_RTT_WriteString()
。 要在计算机上接收数据,请调用
jlinkrttlogger
提供的
jlinkrttlogger
命令行
jlinkrttlogger
。
有机发光二极管
另一个挑战是使OLED正常工作。 市场上最常见的OLED运行
ssd1306驱动器/控制器,通常通过使用
SPI或
I²C的串行接口与MCU进行通信。 这是
Adafruit的一个例子 。
我在任何一家普通商店中都找不到这种显示器。 96×32的尺寸为非标准尺寸。 在显示屏上按标识符QT1316P01A进行搜索可找到类似
Aliexpress的中文站点,但是除结论名称外没有任何文档:
使用Aliexpress命名OLED引脚如果列表不存在,则联系人
SCL
,
SDA
和
RES#
告诉我们这是I²C选项。 如果nRF51822的三个引脚和OLED的这三个引脚之间有走线,那么我们将向前迈出一步。 让我们回到显微镜。

OLED数据接触轨迹我们更新对应表:
NRF51822针 | 游乐场 | 内容描述 |
---|
P0.21 | -- | OLED SDA输出 |
P0.22 | -- | OLED SCL引脚 |
P0.24 | -- | 输出OLED RES# |
I²C协议比任何简单的串行协议(如
UART)都要先进得多。 优点之一是它在同一总线上支持多个主设备和从设备。 这使事情变得有些复杂:至少您需要告诉MCU发出了哪些从属命令。 因此,在高层次上,除了物理接触之外,OLED显示器还有一个“逻辑”地址。
幸运的是,nRF5 SDK中的一个示例是I²C扫描仪。 他从所有可能的逻辑地址中询问,并报告是否在其中安装了某些内容。 我的修改版本在
这里 。 它产生以下日志:
$ make
# ...
$ make flash
# ...
$ make log
# ...
TWI scanner.
TWI device detected at 0x3c.
好消息! 我们有充分的理由相信显示器可以正确识别,并且确实是I²C变体。
0x3c
搜索显示
0x3c
是此类设备的典型地址。
现在我们准备将一些像素发送到显示器。 在这个级别上,没有通过库的抽象。
有关传输数据的低级方法,
请参见ssd1306文档。 该过程由一系列配置命令组成,这些命令可设置显示方向,记录模式,大小等。 然后,将屏幕上显示的字节序列发送到图形显示内存(GDDRAM)。
为了获得正确的配置,我研究
了Adafruit的ssd1306库,并尝试模拟类似的命令。 这就是该项目中大部分时间所花费的时间。 找出所有细节是一项非常耗时的任务,但我仍然无法解释某些事情。 但是,它有效!
显示硬编码位图此示例的代码
在此处 。
通过这些设置,显示分为4行(页面)和96列。 因此页面高8像素。 发送的第一个字节将“垂直”位于第一页的第一列中。 当第二个字节
返回并从第二页的第一列开始时,它将占据第二列,然后是第三列,依此类推,直到第96列。
这是
预期的行为。 如
视频所示 ,
观察到的行为是不同的:首先填充奇数列,然后填充偶数列,然后返回第二页。
我花了很多时间来了解这种愚蠢的显示行为的原因,然后花更多的时间来配置它来解决它。 最后,我吞下了骄傲,仍然在程序中实现了一个奇怪的渲染逻辑来完成它。
前往Arduino
深入研究Arduino
的Adafruit ssd1306库 ,我一直认为,有一种方法可以“模拟”特定的Arduino位以在nRF51822上对其进行测试,将是一件很不错的事情。 事实证明,更多有经验的人也想到了这个主题-这就是惊人的
sandeepmistry / arduino-nRF5项目
所做的 。 它使用nRF5 SDK实现了主要的Arduino库。
通过这个项目,我们可以打开Arduino IDE,选择nRF5开发板,并使用丰富的Arduino生态系统。 我
分叉了该项目,并从我们的手镯中添加了对董事会的支持。 您可以从“
Tools > Board > ID115 Fitness Bracelet (nRF51822)
下拉菜单中选择它。

原始格式的Adafruit ssd1306库(上)和带补丁的库(下)这也意味着现在我们可以使用
Adafruit OLED库 。 令我惊讶和欣慰的是,同样的奇怪行为发生在首先填充奇数甚至偶数OLED列时! 我很高兴地
分叉了图书馆并实施了同样的修改。 与低级方法相比,我们现在可以访问各种很酷的抽象,例如文本输出:
比较熟悉的“世界,您好!”模拟量输入/输出
除了数字开/关信号外,nRF51822还具有10个用于模拟输入的引脚。 例如,这对于读取当前电池电量很有用。 根据文档判断,读取模拟触点会产生一个10位的值。 因此,如果输入端有
0V
,那么我们将读取
0
,如果有
VCC
,我们将读取
1023
其中有中间值。
我定期读取模拟输入的值并绘制最有趣的信号:

根据模拟输入的数据摇动板并为电池充电的效果我确信触点
P0.05
指的是电池电量,因为该值随充电和放电而增加和减少。 我怀疑引脚
P0.26
连接到加速度计的输出之一,因为当您摇动电路板时,它会发疯。 触点
P0.03
和
P0.04
也可以连接到加速度计的各种输出,但是在这里,某些二阶效应很可能会叠加在来自输入的信号上。 例如,在第一个图表中,请注意当加速计需要更多能量时电池电量(引脚5)如何变化。 这是二阶效应的一个例子。
代码可以
在此草图中找到。 源数据和图形脚本在
此处 。 现在我们可以在对应表中添加几行:
NRF51822针 | 游乐场 | 内容描述 |
---|
P0.05 | -- | 模拟输入-连接到电池 |
P0.26 | -- | 模拟输入-一轴加速度计 |
P0.03 | -- | 模拟输入-加速度计的一个轴(可能) |
P0.04 | -- | 模拟输入-加速度计的一个轴(可能) |
纽扣
在原始固件中,在某一点触摸手镯会打开显示屏。 如果我没记错的话,把握这一点可以启动天文钟。 这不是物理按钮,而是某种电容式触摸效果很好的东西。 使用与搜索数字输出相同的方法,我
找到了连接MCU的位置(视频) 。
代码在
这里 。
NRF51822针 | 游乐场 | 内容描述 |
---|
P0.10 | -- | 数字输入-内置按钮 |
低功耗蓝牙(BLE)
nRF5芯片上的BLE功能通过称为
SoftDevice的东西来实现。 这是带有BLE堆栈的预编译二进制文件。 无论用途如何,都可以缝制。 SoftDevice有很多版本,具体取决于SDK版本和芯片版本。
该
文档提供了一定的依赖关系矩阵(不幸的是,您不能直接对其进行链接)。 它显示了该芯片的不同版本附带哪个SDK-以及它是哪个版本的SoftDevice。 在我们的示例中,该芯片标记为QFAAH0,该芯片具有256 KB的闪存,16 KB的RAM,并声明了与SoftDevice s130的兼容性。
我的SDK版本12.3已经包含一些使用SoftDevice s130的示例。 与以前从地址
0x0
直接连接到微芯片的程序相比,现在您需要从地址
0x0
刷新SoftDevice,并从地址
0x1b000
程序本身。 加载和初始化后,SoftDevice二进制文件将转到该地址并将控制权转移到我们的程序。 为了说明这一点,我以闪烁的LED指示灯作为示例,但是将其更改为SoftDevice固件(
代码 )。 观察到的行为没有改变,除了您应该预刷新SoftDevice:
$ make
# ...
$ make flash-softdevice
# ...
$ make flash
# ...
$ make log
# ...
Hello, world!
也许最简单的蓝牙应用程序就是将设备变成
信标 。 设备仅广播其状态。 SDK名为
ble_app_beacon
就是一个这样的例子。 假定SoftDevice s130已经闪烁。
与通过SDK进行编程相比,与芯片的低级通信也使一切变得复杂。 除了调整RAM的大小(在带LED的示例中,这对我来说很难理解),还发现了另一个难以跟踪的问题。 事实证明,BLE堆栈使用时钟发生器执行对时间敏感的任务。 在SDK示例中,假定使用外部晶体振荡器。 经过数千次
printf
尝试后,当我意识到这一点时,我将配置标志更改为使用合成时钟生成器,从而解决了该问题。 信标的源代码在
这里 。
BLE + Arduino
当BLE示例与nRF5 SDK一起使用时,了解有关RAM和生成器的陷阱,我再次查看了Arduino环境。 同样,还有一个光荣的
sandeepmistry / arduino-BLEPeripheral项目 (与
arduino-nRF5来自同一个人!),它在内部BLE设置之上提供了出色的抽象性。
令我惊讶的是,我什至不必拨出图书馆。 arduino-nrf5项目的作者花费了时间,并添加了所有板卡和设置的配置,因此,现在从下拉菜单“
Tools > Low Frequency Clock > Synthesized
为“软设备”选择合适的时钟发生器可以轻松选择。 太棒了 我很快编写
了一个示例 ,该
示例通过蓝牙(带有
此应用程序 )通过绿色的LED点亮。
视频中展示了他的工作。
进一步的计划
在忙了无数小时的操作之后,我的手痒了好几个星期,将其进一步伸入洗衣机,忘记了一段时间。