• 欢迎大家分享资料!前往留言板评论即可!

编写三轴加速度传感器KXTJ3-1057 for LuaTask 驱动

合宙 模组资料网 2年前 (2021-05-15) 631次浏览 0个评论 扫描二维码
文章目录[隐藏]

三轴加速度传感器KXTJ3-1057 for LuaTask 驱动 手把手教程

KXTJ3-1057简介

KXTJ3-1057和KXTJ2-1009 pin to pin 兼容,驱动也兼容。原是Kionix出品的一款手机上非常常用的三轴加速度传感器,后被ROHM收购。产品数据手册: https://atta.szlcsc.com/upload/public/pdf/source/20191031/C442603_12AC3C8489586CE5186C5DB6A78C43C5.pdf?Expires=4070880000&OSSAccessKeyId=LTAIJDIkh7KmGS1H&Signature=xO%2B7CeKnGRDmRCYs1IojjqVATtw%3D&response-content-disposition=attachment%3Bfilename%3DC442603_KXTJ3-1057_2019-10-31.PDF

概述:

ROHM Semiconductor 的 KXTJ3-1057 是三轴 ±2g、±4g、±8g 或 ±16g 微加工硅晶加速计。这些元件采用 Kionix 的专有等离子微加工工艺技术制造。加速度使这些元件运动,进而产生电容器差是这些元件的加速度检测的基本原理,而且使用共模消除法减少由于工艺变化、温度和环境影响造成的误差。利用玻璃浆料将另一片盖形晶圆与该器件粘结在一起,使这些元件实现晶圆级密封。独立的 ASIC 器件与感测元件封装在一起,用于进行信号调节和数字化通讯。
这种加速计采用 2 mm x 2 mm x 0.9 mm LGA 塑料封装,由 1.71 VDC 至 3.6 VDC 电源供电。稳压器用于在输入电源电压范围内保持内部工作电压恒定。这样就能在输入电压范围内保持稳定的工作特性,而且实现几乎检测不到的比率误差。I2C 数字协议用于与芯片进行通讯,以便对该部件进行配置并监视输出。

  • 内部结构图:
    编写三轴加速度传感器KXTJ3-1057 for LuaTask 驱动

  • 参考电路图:
    编写三轴加速度传感器KXTJ3-1057 for LuaTask 驱动

特性:

  • 体积小:2 mm x 2 mm x 0.9 mm LGA 封装
  • 低电流消耗:待机状态 0.9 µA,低功耗状态 10 µA,高分辨率模式 155 µA
  • 电源电压范围宽:1.71 V 至 3.6 V,且内置稳压器
  • 更宽用户可宽展配置 g 范围:±2 g、±4 g、±8 g 或 ±16 g
  • I2C 数字通讯接口,高达 3.4 MHz
  • 高分辨率环形功能,阈值可配置,低至 3.9 mg
  • 用户可配置输出数据速率:0.781 Hz 至 1600 Hz
  • 采用改进型设计,几乎消除了回流焊后偏移和灵敏度漂移
  • 高度可配置的中断控制功能
  • 符合 RoHS/REACH 规范

编写KXTJ3-1057 for LuaTask 驱动

抽象驱动所用到的函数

  • I2C 通信自检函数
  • KXTJ3-1057 寄存器定义
  • KXTJ3-1057 读寄存器函数
  • KXTJ3-1057 写寄存器函数
  • KXTJ3-1057 读中断状态函数
  • KXTJ3-1057 清中断函数
  • KXTJ3-1057 初始化函数
  • KXTJ3-1057 功能自检函数

KXTJ3-1057 的寄存器地址

local KXTJ3_ADDR = 0x0E --KXTJ3 的地址
local KXTJ3_DCST_RESP = 0x0C -- KXTJ3 的数字通自检寄存器
-- 加速度输出寄存器
local KXTJ3_XOUT_L  = 0x06
local KXTJ3_XOUT_H = 0x07
local KXTJ3_YOUT_L = 0x08
local KXTJ3_YOUT_H = 0x09
local KXTJ3_ZOUT_L = 0x0A
local KXTJ3_ZOUT_H = 0x0B
-- 中断寄存器
local KXTJ3_INT_SOURCE1 = 0x16
local KXTJ3_INT_SOURCE2 = 0x17
local KXTJ3_STATUS_REG = 0x18
local KXTJ3_INT_REL = 0x1A
-- 控制寄存器
local KXTJ3_CTRL_REG1 = 0x1B -- KXTJ3的CTRL_REG1地址
local KXTJ3_CTRL_REG2 = 0x1D
local KXTJ3_INT_CTRL_REG1 = 0x1E
local KXTJ3_INT_CTRL_REG2 = 0x1F
local KXTJ3_DATA_CTRL_REG = 0x21
local KXTJ3_WAKEUP_COUNTER = 0x29
local KXTJ3_WAKEUP_THRESHOLD_H = 0x6A
local KXTJ3_WAKEUP_THRESHOLD_L = 0x6B

KXTJ3 的7位从机地址,请参阅你购买的产品手册给的规格书,通常是0x0E 或 0x0F 。

KXTJ3-1057 读写寄存器函数

LuaTask 的I2C 调用的是内部的硬件I2C,所以core给了几个API:https://wiki.openluat.com/doc/luatApi4G/#i2c

-- 初始化并打开I2C操作
-- @param I2C 内部ID
-- @return number ,I2C的速率
local function i2c_open(id, speed)
    if i2c.setup(id, speed or i2c.SLOW) ~= i2c.SLOW then
        i2c.close(id)
        return i2c.setup(id, speed or i2c.SLOW)
    end
    return i2c.SLOW
end

--- 读取寄存器值
-- @number id: I2C端口号
-- @number addr:KXTJ3-1057的从机地址
-- @number reg: KXTJ3-1057的寄存器地址
-- @return number: 寄存器当前值
function readRegister(id, addr, reg)
    log.info("I2C OPEN Result:", i2c_open(id))
    i2c.send(id, addr, reg)
    local _, val = pack.unpack(i2c.recv(id, addr, 1), 'b')
    i2c.close(id)
    log.info("读取", string.format("寄存器:0x%02x 当前值:0x%02x", reg, val or 0))
    return val;
end

--- 写寄存器方法
-- @number  id: I2C端口号
-- @number addr:KXTJ3-1057的从机地址
-- @number reg: KXTJ3-1057的寄存器地址
-- @number ...: 要写入寄存器其他值
-- @return number:  寄存当前值
function writeReg(id, addr, reg, ...)
    log.info("I2C OPEN Result:", i2c_open(id))
    i2c.send(id, addr, {reg, ...})
    local _, val = pack.unpack(i2c.recv(id, addr, 1), 'b')
    log.info("重读", string.format("寄存器:0x%02x 当前值:0x%02x", reg, val or 0))
    i2c.close(id)
    return val
end

为了规避I2C异常,提高I2C抗干扰能力,建议I2C使用完后就立刻关闭。如上代码,每次读取寄存器1个字节。读写寄存器的函数可以根据实际情况,一次读取或写入两个字节,写寄存器函数每次写完后,会重读当前寄存器,方便调试。

I2C 数字通信自检函数

参考KXTJ3-1057 数据手册,可以找到寄存器“DCST_RESP” 专门用来做 KXTJ3-1057 数字通信验证的,如果接线正常,I2C工作正常, 那么读取该寄存器 KXTJ3-1057 会返回0x55,依据这个可以判断LuaTask的I2C和KXTJ3-1057的数字接线、数字通信是否正常,如果不返回0x55,要检查硬件和I2C端口号是否正确。

--- 数字通信自检验证
-- number id: I2C端口号
-- return number 正常返回0x55,其他值为异常
function dcst(id)
    local val = readRegister(id, KXTJ3_ADDR, DCST_RESP)
    log.info("KXTJ3C DCST Result:", string.format("0x%02x", val or 0))
    return val;
end

读取和复位状态寄存器

当中断源寄存器1的DRDY和WUFS位被置位时,该寄存器Bit4置位,表示有位移或者加速度变化产生。当读取加速度数据或读取中断释放寄存器(INT_REL)时,Bit4复位。

--- 读中断状态
-- number id: I2C端口号
-- return number 返回状态寄存器当前值
function readStatus(id)
    local val = readRegister(id, KXTJ3_ADDR, KXTJ3_STATUS_REG)
    log.info("KXTJ3C read interrupt status:", string.format("0x%02x", val or 0))
    return val;
end

--- 清中断状态
-- number id: I2C端口号
-- return nil
function clearStatus(id)
    readRegister(id, KXTJ3_ADDR, KXTJ3_INT_REL)
    log.info("Clear Interrupt status register:", "OK")
end

读取中断源寄存器

实际上读取寄存器的操作可以直接用readRegister函数直接实现,这里演示的是二次封装该方法,方便跨页面调用。

--- 读取中断源寄存器
-- number id: I2C端口号
-- @number src: 1 读中断源1寄存器, 2读中断源2寄存器
-- @return number: 返中断源寄存器的值
function readInterrupt(id, src)
    local val = 0
    if src == 2 then
        val = readRegister(id, KXTJ3_ADDR, KXTJ3_INT_SOURCE2)
    else
        val = readRegister(id, KXTJ3_ADDR, KXTJ3_INT_SOURCE1)
    end
    log.info("readInterrupt register:", string.format("%02x", val or 0))
    return val
end

KXTJ3-1057 工作模式切换

KXTJ3-1057 部分寄存器写入数据必须在准备模式才能写入,工作模式写入无效。配置CTRL_REG1寄存器Bit7的值可切换工作模式:

  • 0 = stand-by mode
  • 1 = operating mode
--- 配置 KXTJ3工作模式
-- number id: I2C端口号
-- @number mode: 0 准备模式, 1工作模式
-- @return number: 返中断源寄存器的值
function setMode(id, mode)
    log.info("-------->I2C OPEN Result:", i2c_open(id))
    i2c.send(id, KXTJ3_ADDR, KXTJ3_CTRL_REG1)
    local _, val = pack.unpack(i2c.recv(id, KXTJ3_ADDR, 1), 'b')
    i2c.send(id, KXTJ3_ADDR, {KXTJ3_CTRL_REG1, mode == 0 and bit.clear(val, 7) or bit.set(val, 7)})
    val = readRegister(id, KXTJ3_ADDR, KXTJ3_CTRL_REG1)
    i2c.close(id)
    log.info("读取CTRL_REG1寄存器:", string.format("当前值:0x%02x", val or 0))
end

实际应用中,也可以在准备模式配置玩寄存器后,配置CTRL_REG1的同时切换KXTJ3为工作模式。

读取三轴加速度数据

--- 读取三轴输出值,注意结果是 Tri-axis 数字量
-- @param  axis: 'x','y','z' 分别表示x,y,z轴
-- @number n: 分辨率,可选值8,12,14(CTRL_REG1配置)
-- @return number: Tri-axis Digital
function readAxis(id, axis, n)
    local val, recv, reg = 0, {}, {}
    if axis == 'x' then
        reg[1] = KXTJ3_XOUT_L
        reg[2] = KXTJ3_XOUT_H
    elseif axis == 'y' then
        reg[1] = KXTJ3_YOUT_L
        reg[2] = KXTJ3_YOUT_H
    elseif axis == 'z' then
        reg[1] = KXTJ3_ZOUT_L
        reg[2] = KXTJ3_ZOUT_H
    else
        return 0
    end
    recv[1] = readRegister(id, KXTJ3_ADDR, reg[1])
    recv[2] = readRegister(id, KXTJ3_ADDR, reg[2])
    val = recv[2] * 256 + recv[1]
    if n == 8 then
        return recv[2]
    elseif n == 12 then
        return (recv[2] > 0x7F) and bit.bor(bit.rshift(val, 4), 0xF000) or bit.band(bit.rshift(val, 4), 0x0FFF)
    elseif n == 14 then
        return (recv[2] > 0x7F) and bit.bor(bit.rshift(val, 4), 0xC000) or bit.band(bit.rshift(val, 4), 0x3FFF)
    end
    return 0;
end

这部分没啥好说的,就是读取加速度三轴的高低位寄存器的值,根据CTRL_REG1寄存器配置的分辨率,然后换算成Tri-axis 数字量。

KXTJ3-1057 三轴功能自检函数

KXTJ3-1057 提供了一套功能自检逻辑,帮助用户判断三轴传感器是否正常工作。当写入0xCA到SELF_TEST寄存器,内部测量自检方法被启用, 加速度的静电驱动会让X,Y,Z三轴产生偏移,对该寄存器写入0x00,则关闭自建并恢复正常工作。

-- KXTJ3-1057 功自检
-- number id: I2C端口号
-- @return nil
function selfTest(id)
    setMode(id, 0)
    writeRegister(id, KXTJ3_ADDR, KXTJ3_SELF_TEST, 0xCA)
    setMode(id, 1)
    log.info("on self test axis-x: ", readAxis(id, 'x', 8))
    log.info("on self test axis-y: ", readAxis(id, 'y', 8))
    log.info("on self test axis-z: ", readAxis(id, 'z', 8))
    setMode(id, 0)
    writeRegister(id, KXTJ3_ADDR, KXTJ3_SELF_TEST, 0x00)
    setMode(id, 1)
    log.info("out self test axis-x: ", readAxis(id, 'x', 8))
    log.info("out self test axis-y: ", readAxis(id, 'y', 8))
    log.info("out self test axis-z: ", readAxis(id, 'z', 8))
end

KXTJ3-1057 初始化示例

下面介绍 KXTJ3-1057 初始化的例子, 读者可根据自己的实际情况和项目需求进行更改,其中一些直接用writeRegister写寄存器的方法, 大家可以自己动手封装成方法,方便在其他页面调用。

--- 初始化配置
-- number id: I2C端口号
-- @return nil
function init(id)
    -- 进入配置模式
    setMode(id, 0)
    -- 复位控制寄存器2
    writeRegister(id, KXTJ3_ADDR, KXTJ3_CTRL_REG2, 0x86)
    -- 配置控制寄存器2 为50HZ
    writeRegister(id, KXTJ3_ADDR, KXTJ3_CTRL_REG2, 0x06)
    -- 配置唤醒延时和唤阈值
    writeRegister(id, KXTJ3_ADDR, KXTJ3_WAKEUP_COUNTER, 50)
    writeRegister(id, KXTJ3_ADDR, KXTJ3_WAKEUP_THRESHOLD_H, (1500 - (1500 % 256)) / 256)
    writeRegister(id, KXTJ3_ADDR, KXTJ3_WAKEUP_THRESHOLD_L, 1500 % 256)
    writeRegister(id, KXTJ3_ADDR, KXTJ3_DATA_CTRL_REG, 0x02)
    -- 配置控制寄存器1 配置唤中断,(B0010 0010)
    writeRegister(id, KXTJ3_ADDR, KXTJ3_CTRL_REG1, 0x82)
    -- 清中断
    clearStatus(id)
    log.info("KXTJ3C init done: ", "ok!")
end

源码

--[[
Author: 稀饭放姜
Date: 2020-12-18 15:50:05
LastEditors: 稀饭放姜
LastEditTime: 2020-12-25 12:24:25
FilePath: \HeFeiYunShi-Air724\user\sensor.lua
--]]
require "utils"
module(..., package.seeall)
-- 初始化并打开I2C操作
-- @param I2C 内部ID
-- @return number ,I2C的速率
local function i2c_open(id, speed)
    if i2c.setup(id, speed or i2c.SLOW) ~= i2c.SLOW then
        i2c.close(id)
        return i2c.setup(id, speed or i2c.SLOW)
    end
    return i2c.SLOW
end

--- 读取寄存器值
-- @number id: I2C端口号
-- @number addr:从机地址
-- @number reg: 寄存器地址
-- @return number: 寄存器当前值
function readRegister(id, addr, reg)
    log.info("-------->I2C OPEN Result:", i2c_open(id))
    i2c.send(id, addr, reg)
    local _, val = pack.unpack(i2c.recv(id, addr, 1), 'b')
    i2c.close(id)
    log.info("读取", string.format("寄存器:0x%02x 当前值:0x%02x", reg, val or 0))
    return val;
end

--- 写寄存器方法
-- @number  id: I2C端口号
-- @number addr:从机地址
-- @number reg: 寄存器地址
-- @number ...: 要写入寄存器其他值
-- @return number:  寄存当前值
function writeRegister(id, addr, reg, ...)
    log.info("-------->I2C OPEN Result:", i2c_open(id))
    i2c.send(id, addr, {reg, ...})
    local _, val = pack.unpack(i2c.recv(id, addr, 1), 'b')
    log.info("重读", string.format("寄存器:0x%02x 当前值:0x%02x", reg, val or 0))
    i2c.close(id)
    return val
end

-------------------------------------- KXTJ3-1057 驱动代码开始 --------------------------------------
local KXTJ3_ADDR = 0x0E --KXTJ3 的地址
local KXTJ3_DCST_RESP = 0x0C -- KXTJ3 的数字通自检寄存器
local KXTJ3_SELF_TEST = 0x3A -- KXTJ3 的功自检寄存器
-- 加速度输出寄存器
local KXTJ3_XOUT_L = 0x06
local KXTJ3_XOUT_H = 0x07
local KXTJ3_YOUT_L = 0x08
local KXTJ3_YOUT_H = 0x09
local KXTJ3_ZOUT_L = 0x0A
local KXTJ3_ZOUT_H = 0x0B
-- 中断寄存器
local KXTJ3_INT_SOURCE1 = 0x16
local KXTJ3_INT_SOURCE2 = 0x17
local KXTJ3_STATUS_REG = 0x18
local KXTJ3_INT_REL = 0x1A
-- 控制寄存器
local KXTJ3_CTRL_REG1 = 0x1B -- KXTJ3的CTRL_REG1地址
local KXTJ3_CTRL_REG2 = 0x1D
local KXTJ3_INT_CTRL_REG1 = 0x1E
local KXTJ3_INT_CTRL_REG2 = 0x1F
local KXTJ3_DATA_CTRL_REG = 0x21
local KXTJ3_WAKEUP_COUNTER = 0x29
local KXTJ3_WAKEUP_THRESHOLD_H = 0x6A
local KXTJ3_WAKEUP_THRESHOLD_L = 0x6B

--- 数字通信自检验证
-- number id: I2C端口号
-- return number 正常返回0x55,其他值为异常
function dcst(id)
    local val = readRegister(id, KXTJ3_ADDR, KXTJ3_DCST_RESP)
    log.info("KXTJ3C DCST Result:", string.format("0x%02x", val or 0))
    return val;
end

--- 读中断状态
-- number id: I2C端口号
-- return number 返回状态寄存器当前值
function readStatus(id)
    local val = readRegister(id, KXTJ3_ADDR, KXTJ3_STATUS_REG)
    log.info("KXTJ3C read interrupt status:", string.format("0x%02x", val or 0))
    return val;
end

--- 清中断状态
-- number id: I2C端口号
-- return nil
function clearStatus(id)
    readRegister(id, KXTJ3_ADDR, KXTJ3_INT_REL)
    log.info("Clear Interrupt status register:", "OK")
end

--- 读取中断源寄存器
-- number id: I2C端口号
-- @number src: 1 读中断源1寄存器, 2读中断源2寄存器
-- @return number: 返中断源寄存器的值
function readInterrupt(id, src)
    local val = 0
    if src == 2 then
        val = readRegister(id, KXTJ3_ADDR, KXTJ3_INT_SOURCE2)
    else
        val = readRegister(id, KXTJ3_ADDR, KXTJ3_INT_SOURCE1)
    end
    log.info("readInterrupt register:", string.format("%02x", val or 0))
    return val
end

--- 配置 KXTJ3工作模式
-- number id: I2C端口号
-- @number mode: 0 准备模式, 1工作模式
-- @return number: 返中断源寄存器的值
function setMode(id, mode)
    log.info("-------->I2C OPEN Result:", i2c_open(id))
    i2c.send(id, KXTJ3_ADDR, KXTJ3_CTRL_REG1)
    local _, val = pack.unpack(i2c.recv(id, KXTJ3_ADDR, 1), 'b')
    i2c.send(id, KXTJ3_ADDR, {KXTJ3_CTRL_REG1, mode == 0 and bit.clear(val, 7) or bit.set(val, 7)})
    val = readRegister(id, KXTJ3_ADDR, KXTJ3_CTRL_REG1)
    i2c.close(id)
    log.info("读取CTRL_REG1寄存器:", string.format("当前值:0x%02x", val or 0))
end

--- 读取三轴输出值,注意结果是 Tri-axis 数字量
-- @param  axis: 'x','y','z' 分别表示x,y,z轴
-- @number n: 分辨率,可选值8,12,14(CTRL_REG1配置)
-- @return number: Tri-axis Digital
function readAxis(id, axis, n)
    local val, recv, reg = 0, {}, {}
    if axis == 'x' then
        reg[1] = KXTJ3_XOUT_L
        reg[2] = KXTJ3_XOUT_H
    elseif axis == 'y' then
        reg[1] = KXTJ3_YOUT_L
        reg[2] = KXTJ3_YOUT_H
    elseif axis == 'z' then
        reg[1] = KXTJ3_ZOUT_L
        reg[2] = KXTJ3_ZOUT_H
    else
        return 0
    end
    recv[1] = readRegister(id, KXTJ3_ADDR, reg[1])
    recv[2] = readRegister(id, KXTJ3_ADDR, reg[2])
    val = recv[2] * 256 + recv[1]
    if n == 8 then
        return recv[2]
    elseif n == 12 then
        return (recv[2] > 0x7F) and bit.bor(bit.rshift(val, 4), 0xF000) or bit.band(bit.rshift(val, 4), 0x0FFF)
    elseif n == 14 then
        return (recv[2] > 0x7F) and bit.bor(bit.rshift(val, 4), 0xC000) or bit.band(bit.rshift(val, 4), 0x3FFF)
    end
    return 0;
end

-- KXTJ3-1057 功自检
-- number id: I2C端口号
-- @return nil
function selfTest(id)
    setMode(id, 0)
    writeRegister(id, KXTJ3_ADDR, KXTJ3_SELF_TEST, 0xCA)
    setMode(id, 1)
    log.info("on self test axis-x: ", readAxis(id, 'x', 8))
    log.info("on self test axis-y: ", readAxis(id, 'y', 8))
    log.info("on self test axis-z: ", readAxis(id, 'z', 8))
    setMode(id, 0)
    writeRegister(id, KXTJ3_ADDR, KXTJ3_SELF_TEST, 0x00)
    setMode(id, 1)
    log.info("out self test axis-x: ", readAxis(id, 'x', 8))
    log.info("out self test axis-y: ", readAxis(id, 'y', 8))
    log.info("out self test axis-z: ", readAxis(id, 'z', 8))
end
-------------------------------------- KXTJ3-1057 驱动代码结束 --------------------------------------
--- 初始化配置
-- number id: I2C端口号
-- @return nil
function init(id)
    -- 进入配置模式
    setMode(id, 0)
    -- 复位控制寄存器2
    writeRegister(id, KXTJ3_ADDR, KXTJ3_CTRL_REG2, 0x86)
    -- 配置控制寄存器2 为50HZ
    writeRegister(id, KXTJ3_ADDR, KXTJ3_CTRL_REG2, 0x06)
    -- 配置唤醒延时和唤阈值
    writeRegister(id, KXTJ3_ADDR, KXTJ3_WAKEUP_COUNTER, 50)
    writeRegister(id, KXTJ3_ADDR, KXTJ3_WAKEUP_THRESHOLD_H, (1500 - (1500 % 256)) / 256)
    writeRegister(id, KXTJ3_ADDR, KXTJ3_WAKEUP_THRESHOLD_L, 1500 % 256)
    writeRegister(id, KXTJ3_ADDR, KXTJ3_DATA_CTRL_REG, 0x02)
    -- 配置控制寄存器1 配置唤中断,(B0010 0010)
    writeRegister(id, KXTJ3_ADDR, KXTJ3_CTRL_REG1, 0x82)
    -- 清中断
    clearStatus(id)
    log.info("KXTJ3C init done: ", "ok!")
end


喜欢 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址