ODGIRON LIS3DH笔记

TS100的两个加速度计

基于IronOS固件的典型烙铁,比如TS100的PCB预留了两种加速度计焊盘,一种是NXP的MMA系列的MMA8652FC加速度计,一种是ST的LIS系列的LIS2DH12加速度计,实际出货时只焊接一个(这么做应该是和采购有关),大多数TS100仅焊接的是LIS2DH12加速度计,其封装为 LGA12(2.0x2.0x1.0 mm),焊盘之间实在距离太小了,又是LGA封装,和QFN封装能侧面爬锡不同,LGA封装仅底面开了焊盘,侧面无法爬锡,从网上找到TS100的PCB的加速度计如下:

TS100采用双PCB设计 小PCB通过板对板连接器与大PCB连接
TS100-72变(1) TS100-72变(2)
小PCB右加速计和STM32 确认型号与LC商城的LIS2DH12一致
TS100-guts2-525px LIS2DH12-LC

LIS3DH与LIS2DH12

ODGIRON,是我最近在开发的基于ironOS的快充T12电烙铁,由于ODGIRON双面布线,加速度盘下要走两个过孔才能布通,因此选用了封装更大的LIS3DH,封装为LGA12(3.0x3.0x1.0 mm),其焊接更友好,还更便宜,需要用到的地方与LIS2DH12几乎完全一致,要什么自行车

LIS3DH LIS2DH12
尺寸 LIS3DH-LC LIS2DH12-LC
LIS3DH-LC-BK LIS2DH12-LC-BK
供电电压 1.71 V to 3.6 V 1.71 V to 3.6 V
50Hz正常工作电流(uA) 11 11
量程(FS) ±2g/±4g/±8g/±16g ±2g/±4g/±8g/±16g
量程特性 dynamically selectable full scale selectable full scales
接口 I2C/SPI I2C/SPI
可编程中断GPIO 2 2
中断GPIO功能 free-fall and motion detection free-fall and motion detection
硬件方向检测 6D/4D orientation detection 6D/4D orientation detection
数据位数(bit) Low-power mode (8-bit data output)
Normal mode (10-bit data output)
High-resolution mode (12-bit data output)
Low-power mode (8-bit data output)
Normal mode (10-bit data output)
High-resolution mode (12-bit data output)
输出数据位数 12bit/10bit/8bit 12bit/10bit/8bit
片上温度传感器 Yes Yes
自检 Yes Yes
FIFO 16-bit, 32-level 10-bit, 32-level
ADC 多一路A/D converter
引出3路ADC GPIO
仅一路A/D converter
抗震性(g) 10000 N/A
Datasheet一样的参数 Mechanical characteristics
Temperature sensor characteristics
Electrical characteristics
Communication interface characteristics
Absolute maximum ratings
Terminology and functionality
最低价格 1.3包邮 2.3包邮

ironOS 加速度计读数不正常问题解决

ironOS跑了FreeRTOS,加速度计为MOVTask任务,与oled的GUITask共用 I2C1 总线,由二值信号量做 I2C1 互斥,具体实现请见ironOS源码

ironOS的LISDH12的加速度计驱动代码有BUG,它配置了一大堆非必要的加速度计寄存器,而实际上任务仅用到读取3轴数据和6D检测,我仔细跟了它原本的寄存器配置,得出LISDH12工作状态如下:

  • 输出数据:12bit,即 [-2048, +2048]
  • 加速度量程:±2g
  • ODR:1Hz,实际上注释是想配置成25Hz,但它实际的配置数据位写错了
  • 实际加速度输出频率:当ODR=1,ODR/9 = 0.111次/秒,运动检测很迟钝
  • 期望的加速度输出频率:当ODR=25,ODR/9 = 2.777次/秒,运动检测较迟钝
  • ODGIRON设置的加速度输出频率:ODR为100Hz,ODR/9=11.111次/秒,与MOVTask调度频率10Hz几乎同步,运动检测很灵敏

其运动检测的源代码:ironOS运动检测是由MOVTask里跑了一个阈值比较程序,它实现了运动检测,既然软件进行了运动检测,那为啥还要使能6D阈值检测的事件中断?

ironOS读取加速度计的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

/**
* @brief 读取三轴数据
* @param 传x、y、z数据的引用
* @retval none
*/
void LIS2DH12::getAxisReadings(int16_t &x, int16_t &y, int16_t &z) {
std::array<int16_t, 3> sensorData; //三组16bit用于存储三个轴12bit数据

FRToSI2C::Mem_Read(
truetrue LIS2DH_I2C_ADDRESS,
truetrue 0xA8, //注意,0xA8是OUT_X_L的0x28 与 连续读取的0x80 两者按位与运算得到的
//这里它连续读取 OUT_X_L 到 OUT_Z_H 共六个相邻的只读寄存器
truetruetruetruetrue reinterpret_cast<uint8_t *>(sensorData.begin()), // 将定位到容器首元素iterator强制转换为unit8_t*,炫技操作?
truetruetruetruetrue sensorData.size() * sizeof(int16_t)
truetruetruetruetrue);

//依次赋值
x = sensorData[0];
y = sensorData[1];
z = sensorData[2];
}

由于12bit数据是左对齐的,可见,在 //依次赋值 的地方,未作 >> 4 运算,直接输出的xyz结果范围不是[-2048, +2048],而是有时候数据能到 ±10000以外,离谱

我补上 >> 4运算,使劲晃动时输出数据也不正常,很难到 ±2000附近:

ironOS的加速度计-剧烈摇晃,将读数左移位4bit运算结果

这与arduino的Sparkfun 的LIS3DH例程非常不同,arduino的例程跑起来,若水平放置加速度计,z方向会在-1024附近,即能显示地球的重力加速度1g,奇怪的是ironOS的跑起来没有1g的加速度,读出数据如下:

20210220005151

这是为什么呢?排查出错原因是仅配置了LIS_CTRL_REG2的FDS位,使能了High-pass filter ,这之后输出的三轴数据,是经高通滤波后的

1
2
3
4
{LIS_CTRL_REG2, 0b00001000, 0}, //default:00000000 // Highpass filter off          // 		 FDS[3:3] = 1:
//筛选数据选择。默认值:0
// 0:绕过内部滤波器
// 1:来自内部滤波器的数据发送到输出寄存器和FIFO

我将该配置取消掉,之后水平静置读数正常,换算z方向的加速度是正常的1g左右:

实际上,后面运动检测也可以读经过高通滤波器的值,ironOS没有将经过高通滤波器的值 做<<4运算,即实际传入运动检测程序的值大了2^4 = 16倍,这就能解释为啥我默认打印xyz读到的数据剧烈晃动时可以到±10000,能触发运动检测,但<<4后摇晃时读数稳如泰山,摇晃得很厉害也无法触发运动检测

所以,是否按ironOS的原始代码启用高通滤波器看你的喜好,个人感觉数据不过滤波器运动检测舒服一些

注意:数据经过滤波器对6D阈值无影响,6D阈值是取原始读数的

LIS3DH的滤波器还有很多高级特性供配置,可以作用于中断、敲击检测,更多请参考手册的 8.9节 CTRL_REG2 (21h)

根据加速读计旋转oled

LIS3DH带有6D阈值事件中断功能。

加速度计坐标轴

注意TS100的LIS2DH12和我ODGIRON的LIS3DH的轴向坐标不同:

LIS3DH LIS2DH12
轴向 LIS3DH轴向 LIS2DH12轴向

我对原本TS100的 LIS3DH::getOrientation() 函数进行修改,使之符合LIS3DH的坐标轴,明细请见源代码。

右手与左手的旋转与加速度计坐标关系

我根据加速度计相对烙铁的安装的位置,画了ODGIRON和TS100的加速读坐标两张纸贴在烙铁上,下文都按照左边ODGIRON贴纸上的坐标

右手模式水平静置 右手模式旋转 +90°
右手模式旋转(1) 右手模式旋转(2)
左手模式水平静置 左手模式旋转 -90°
左手模式旋转(2) 左手模式旋转(1)

INT2_THS 阈值寄存器

THS 即 threshold 阈值

ironOS 的 INT2_THS 寄存器 设置值为0x28,根据datasheet:

  • 由 Table 68. INT2_THS description:LIS3DH工作在12bit ±2g,则 THS[6:0] 的 1LSB = 16mg,计算触发阈值:先将0x28转换为10进制:0x28 = 40DEC , 再乘以16msg 得到触发阈值为±640mg,

  • 由 Table 4. Mechanical characteristics的Sensitivity部分:LIS3DH工作在12bit ±2g时 ,加速度输出数据的1LSB = 1mg,则读数为±640触发临界点

测试,0x28的640mg实际旋转触发时以z轴值主导,z的阈值为±640附近,而x阈值为±830附近:

左手阈值触发临界点附近: 右手阈值触发临界点附近:
0x28左手阈值触发临界点 0x28右手阈值触发临界点.png

将0x28改为0x20,0x20为512mg,实际旋转触发时以z轴值主导,z的阈值为±640附近,x阈值为±910附近:

左手阈值触发临界点附近: 右手阈值触发临界点附近:
20210219234731 20210219234715

改为50,50为800mg,实际旋转触发时以x轴值为主导,z的阈值为±640附近,x阈值为±800附近:

左手阈值触发临界点附近: 右手阈值触发临界点附近:
20210220000410 20210220000425

所以这很奇怪,INT2_THS的值可能由z轴也可能为x轴的阈值事件触发,但最终手性的判断是OK的

那么旋转oled阈值事件到底是以x还是z轴触发判断?

设xoy面水平,即烙铁屏幕水平,当烙铁沿y轴旋转时,z轴加速度读数 与 旋转角度 存在函数关系,推导一下

规定屏幕水平向上时,沿y轴的旋转角度为0,则烙铁沿y轴旋转时,垂直于屏幕的法线与旋转角度为0时的法线存在夹角θ,令该法线通过原点,则该法线的参数方程为:

\left\{ \begin{align} x&=tcos(\frac{\pi}{2}-\theta)\\ y&=tsin(\frac{\pi}{2}-\theta)\\ \end{align} \right. \space\space\space\space,\space\space\theta∈[-\frac{\pi}{2},\frac{\pi}{2}]

如图所示,建立与x轴加速度读数有关的圆,直径是1g时,读数为1024,则半径为512,那么该的圆的方程为: $$ x^2+(y-512)^2=512^2 $$ 该圆上任一点 (x,y) 到原点 (0,0) 的距离为: $$ d=\sqrt{x^2+y^2} $$ 联立以上公式: $$ \left\{ \begin{align} x&=tcos(\frac{\pi}{2}-\theta)\\ y&=tsin(\frac{\pi}{2}-\theta)\\ x^2+(y-512)^2&=512^2\\ d&=\sqrt{x^2+y^2}\\ \end{align} \right. \space\space\space\space,\space\space\theta∈[-\frac{\pi}{2},\frac{\pi}{2}] $$ 整理后,只有一个sin: $$ d=1024\cdot sin(\frac{\pi}{2}-\theta) \space\space\space\space,\space\space\theta∈[-\frac{\pi}{2},\frac{\pi}{2}] $$ 由于z轴于屏幕显示方向刚好相反,所以 $$ z轴加速度读数=-1024\cdot sin(\frac{\pi}{2}-\theta) \space\space\space\space,\space\space\theta∈[-\frac{\pi}{2},\frac{\pi}{2}] $$ 类似地,可以写出 $$ x轴加速度读数=1024\cdot sin(\theta) \space\space\space\space,\space\space\theta∈[-\frac{\pi}{2},\frac{\pi}{2}] $$

那么把旋转角度θ带入x轴加速度读数函数求得的值,再由 THS[6:0] 的 1LSB = 16mg 计算触发阈值,设置为INT2_THS的值,就可指定旋转角度触发中断了

sw

可以画出x轴和z轴读数随沿y轴旋转角度(-90度到90度)的图像:

发现x与z轴的事件 受INT2_THS的值范围 会出现先后触发的情况,在x=-π/4x=π/4的附近,即旋转-45度和45度附近,在-45度的左边时,z轴比x轴先触发,在-45度右边时,则相反,但实际x轴和z轴事件的先后顺序却相反,应该是加速度计片内电路判断成反序了

注意:使能了IN2中断锁存:LIR_INT2[7:7] = 1:在INT2_SRC(35h)寄存器上锁存中断请求,对此没有影响

为了最佳旋转触发,我45度作为临界点:

$$ 1024\cdot sin(\pi/2)≈724.08 $$

然后再除以寄存器的分辨率16mg/LSB:

$$ 724.08/16≈45 $$

那么将INT2_THS设置为45即可

剩下oled驱动、旋转oled的命令不是重点,略

INT2_DURATION寄存器有没有用?

会增加一个消抖时间,可开可不开,实际效果无明显变化

1
/*开了没开一样,没卵用?*/	{LIS_INT2_DURATION, 64, 0},    //default:00000000 // 64 = 0b01000000	// 超出阈值持续多少时间才触发INT2的中断(相当于按键延时消抖)

运动检测

1
currentPointer = (currentPointer + 1) % MOVFilter // 每8次MOVTask调度,currentPointer归0

串口打印currentPointer随MOVTAsk调度次数变化:ptr是currentPointer, time是调度次数

20210220230512

读到的轴数据在滑动滤波器数组里的变化情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//第1次:
currentPointer = 0
datax[] = {111, 111, 111, 111, 111, 111, 111, 111} //首次会将每一个元素都赋值为第一次的x轴数据,之后不会
// ^ ^ ^ ^ ^ ^ ^ ^
// 第1次 第1次 第1次 第1次 第1次 第1次 第1次 第1次
//第2次:
currentPointer = 1
datax[] = {111, 222, 111, 111, 111, 111, 111, 111}
// ^ ^ ^ ^ ^ ^ ^ ^
// 第1次 第2次 第1次 第1次 第1次 第1次 第1次 第1次
......
//第7次:
currentPointer = 7
datax[] = {111, 222, 333, 444, 555, 666, 777, 111} //xxx表示x轴的随机取值
// ^ ^ ^ ^ ^ ^ ^ ^
// 第1次 第2次 第3次 第4次 第5次 第6次 第7次 第1次
//第8次:
currentPointer = 0 //整除归零,重新计数
datax[] = {111, 222, 333, 444, 555, 666, 777, 888}
// ^ ^ ^ ^ ^ ^ ^ ^
// 第1次 第2次 第3次 第4次 第5次 第6次 第7次 第8次
//第9次:
currentPointer = 1
datax[] = {999, 222, 333, 444, 555, 666, 777, 888}
// ^ ^ ^ ^ ^ ^ ^ ^
// 第9次 第2次 第3次 第4次 第5次 第6次 第7次 第8次
......

然后每次求一次8个元素的平均值,即变量avgx,使用abs(avgx - 本次读到的x数据),得到x轴变化量的绝对值,以同样的方式计算y和z轴,求和为三轴的总变化值,即变量error,将error与threshold比较,若大于,则更新运动检测的时间戳,即变量lastMovementTime,详细见代码,以下节选部分:

1
2
3
4
5
6
7
8
9
// 求三轴变化量绝对值的总和 //Sum the deltas	//abs()求传入数据的绝对值
int32_t error = (abs(avgx - axisData.x) + abs(avgy - axisData.y) + abs(avgz - axisData.z));
// So now we have averages, we want to look if these are different by more
// than the threshold
// If movement has occurred then we update the tick timer
// 如果发生了移动,那么我们更新滴答计时器
if (error > threshold) {
lastMovementTime = xTaskGetTickCount();
}

综合测试

一边读3轴数据,一边6D旋转阈值检测,一边运动检测的瞬间,OK:

20210220011749

相关链接

ODGIRON_开源PD电烙铁

IronOS开源烙铁固件github

美与质量共存——TS100袖珍迷你烙铁评测

AD:加速度计技术规格——快速定义

LIS3DH Datashee- STMicroelectronics

LIS2DH12 Datasheet - STMicroelectronics