0

我有一个 I2C 设备连接到我的 Raspberry Pi 3。I2C 设备在其 FIFO 缓冲区中以 104Hz 存储 9 个样本。我轮询设备以了解存储的样本量。每个样本为 2 个字节。当 FIFO 缓冲区达到 2016 个样本时,我通过发出 126 个 32 字节 i2c 块数据读取,一口气读取了所有 4032 个字节。

在读取期间,设备仍在填充 FIFO。因此,当我阅读完所有 2016 年样本后,我可以立即进行调查,发现有 630 个新样本。

如果我打印 FIFO 中的样本数,则块读取的运行时间比不打印时快。在这种情况下,我只得到 387 个新样本。

我不明白打印语句如何使我的 IO 读取速度更快。

我试过改变阈值。此外,在下面的 if 语句中移动打印会使事情再次变慢。使用 flush=True 打印什么都不做,无论是在达到阈值之前还是之后。
我试图在数据读取之前打印一些虚拟字符串(在 tic() 上方)。这导致前几次缓冲区读取速度很快(0.410 秒),然后一直很慢(0.661 秒)。快速读取的数量似乎随着打印语句的数量而增加。

import numpy as np
from time import sleep
from time import time
from smbus2 import SMBus


# Helper timing functions
_tstart_stack = []

def tic():
    _tstart_stack.append(time())

def toc(fmt="Elapsed: %s s"):
    print(fmt % (time() - _tstart_stack.pop()))


# Datasheet: https://www.pololu.com/file/0J1087/LSM6DS33.pdf
# REGISTER DEFINITIONS:
WHO_AM_I = 0x0F  # page 46
WHO_AM_I_VAL = 0b01101001
# FIFO registers
FIFO_STATUS1 = 0x3A  # page 59
FIFO_STATUS2 = 0x3B  # page 60
FIFO_STATUS3 = 0x3C  # page 60
FIFO_STATUS4 = 0x3D  # page 61
FIFO_CTRL1 = 0x06  # page 40
FIFO_CTRL2 = 0x07  # page 40
FIFO_CTRL3 = 0x08  # page 41
FIFO_CTRL4 = 0x09  # page 42
FIFO_CTRL5 = 0x0A  # page 43
FIFO_DATA_OUT_L = 0x3E  # page 61
FIFO_DATA_OUT_H = 0x3F  # page 61
# Control registers
CTRL1_XL = 0x10  # page 46
CTRL2_G = 0x11  # page 48
CTRL3_C = 0x12  # page 49
CTRL4_C = 0x13  # page 50
CTRL5_C = 0x14  # page 50
CTRL6_C = 0x15  # page 51
CTRL7_G = 0x16  # page 52
CTRL8_XL = 0x17  # page 52
CTRL9_XL = 0x18  # page 53
CTRL10_C = 0x19  # page 54
TAP_CFG = 0x58  # page 64
WAKE_UP_DUR = 0x5C  # page 66
# Accelerometer read
OUTX_L_XL = 0x28  # page 58
OUTX_H_XL = 0x29  # page 58
OUTY_L_XL = 0x2A  # page 58
OUTY_H_XL = 0x2B  # page 59
OUTY_L_XL = 0x2C  # page 59
OUTY_H_XL = 0x2D  # page 59
# Gyro read
OUTX_L_G = 0x22  # page 56
OUTX_H_G = 0x23  # page 57
OUTY_L_G = 0x24  # page 57
OUTY_H_G = 0x25  # page 57
OUTY_L_G = 0x26  # page 58
OUTY_H_G = 0x27  # page 58

# BIT DEFINITION MASKS
FIFO_THRESHOLD  = 0b10000000  # FTH in FIFO_STATUS2, 1 when threshold is crossed.
FIFO_OVER_RUN   = 0b01000000  # FIFO FULL + 1 sample
FIFO_FULL       = 0b00100000  # in FIFO_STATUS2, FIFO full on next sample
FIFO_EMPTY      = 0b00010000  # in FIFO_STATUS2


def init(BUS, LSM):
    # LSM6DS33 datasheet, page 46-54
    # 104 Hz (high performance), 2g accelerometer full-scale selection, 50Hz anti-aliasing filter bandwidth selection
    BUS.write_byte_data(LSM, CTRL1_XL,  0b01000011)
    # 104 Hz (high performance), 245 dps (degrees per second), full scale disabled
    BUS.write_byte_data(LSM, CTRL2_G,   0b01000000)
    # BDU enabled, auto increment address on multiple byte access.
    BUS.write_byte_data(LSM, CTRL3_C,   0b01000100)
    # high pass filter gyroscope enabled
    BUS.write_byte_data(LSM, CTRL7_G,   0b01000000)
    # low pass filter accelerometer enabled and xyz gyro enable
    BUS.write_byte_data(LSM, CTRL10_C,  0b00111100)

    # threshold on 2016 samples
    BUS.write_byte_data(LSM, FIFO_CTRL1, 0b11100000)
    # Time stamp enable, FIFO on data ready, threshold on 2016 samples
    BUS.write_byte_data(LSM, FIFO_CTRL2, 0b10000111)
    # No decimation (downsampling) for gyro and acc
    BUS.write_byte_data(LSM, FIFO_CTRL3, 0b00001001)
    # No decimation (downsampling) for timer
    BUS.write_byte_data(LSM, FIFO_CTRL4, 0b00001000)
    # FIFO ODR 104Hz, FIFO continous mode
    BUS.write_byte_data(LSM, FIFO_CTRL5, 0b00100110)

    BUS.write_byte_data(LSM, TAP_CFG,     0b10000000)  # Timer enable
    BUS.write_byte_data(LSM, WAKE_UP_DUR, 0b00000000)  # Timer resolution 6.4ms


def who_am_i(BUS, LSM):
    # whoami identification
    return BUS.read_byte_data(LSM, WHO_AM_I) == WHO_AM_I_VAL


def wait_data_ready(BUS, LSM):
    # Check Accelerometer Data Ready
    while True:  # while data not ready
        status = BUS.read_byte_data(LSM, 0x1E)
        if status & 0x01 == 1:
            return 1


def reset_timer(BUS, LSM):
    BUS.write_byte_data(LSM, 0x42, 0xAA)  # TIMESTAMP2_REG Write 0xAA to reset.


def reset_fifo(BUS, LSM):
    current_settings = BUS.read_byte_data(LSM, FIFO_CTRL5)
    bypassmode = 0b01111000 & current_settings
    BUS.write_byte_data(LSM, FIFO_CTRL5, bypassmode)  # FIFO bypass mode
    sleep(0.1)
    BUS.write_byte_data(LSM, FIFO_CTRL5, current_settings)  # Back to normal


def read_fifo(BUS, LSM):
    while 1:
        data = []
        # Read the two FIFO STATUS registers, addr is device I2C address
        status_regs = BUS.read_i2c_block_data(LSM, FIFO_STATUS1, 2)

        # Get the current number of samples in FIFO queue
        if FIFO_FULL & status_regs[1]:
            n_samp = 4095
        else:
            n_samp = (status_regs[1] & 0b00001111)*256 + status_regs[0]

        if FIFO_EMPTY & status_regs[1]:
            print("FIFO EMPTY!")

        # THIS PRINT STATEMENT SPEEDS UP THE FOR LOOP BELOW
        # print("number of samples ", n_samp)

        if FIFO_THRESHOLD & status_regs[1]:
            tic()
            # Threshold: 2016 samples=4032bytes=126 reads of 32 bytes
            for _ in range(126):
                data.extend(BUS.read_i2c_block_data(LSM, FIFO_DATA_OUT_L, 32))
            toc()

            status_regs = BUS.read_i2c_block_data(LSM, FIFO_STATUS1, 2)
            n_samp = (status_regs[1] & 0b00001111)*256 + status_regs[0]
            print("number of samples after read", n_samp)


if __name__ == "__main__":
    # I2C bus and register
    BUS = SMBus(1)
    LSM = 0x6b  # 3-axis gyroscope and 3-axis accelerometer

    print("Whoami: ", who_am_i(BUS, LSM))
    init(BUS, LSM)
    reset_fifo(BUS, LSM)
    reset_timer(BUS, LSM)
    read_fifo(BUS, LSM)

使用打印语句,我得到:
经过时间:0.410 秒
读取后的样本数:387

没有打印语句,我得到:
经过时间:0.661 s
读取后的样本数:621

我预计删除打印会加快速度,而不是减慢速度。我在第一次运行时重置了 FIFO,所以程序总是首先打印“FIFO EMPTY”。

编辑:包含足够的代码来独立运行。问题出在 read_fifo(BUS, LSM) 函数中。我在 Python 3.4.2 上运行并使用 smbus2 模块:https ://pypi.org/project/smbus2/

4

0 回答 0