我有一个 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/