У меня есть устройство I2C, подключенное к Raspberry Pi 3. Устройство I2C хранит 9 сэмплов в своем буфере FIFO на частоте 104 Гц. Я опрашиваю устройство на количество сохраненных образцов. Каждый образец составляет 2 байта. Когда буфер FIFO достигает выборок 2016 года, я считываю все 4032 байта за один раз, выдав 126 32-байтовых считываний данных блока i2c.
Во время чтения устройство все еще заполняет FIFO. Так что, когда я закончу читать все образцы 2016 года, я могу сразу же опросить и увидеть, что есть 630 новых образцов.
Если я распечатаю количество сэмплов в FIFO, тогда время чтения блока будет меньше, чем если бы я не печатал. В этом случае я получаю только 387 новых образцов.
Я не понимаю, как оператор print заставляет мой IO читать быстрее.
Я попытался изменить пороговое значение. Кроме того, перемещение печати внутри оператора if снова замедлило процесс. Печать с промывкой = 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
Без утверждения print я получаю:
прошедшее время: 0,661 с
количество образцов после прочтения: 621
Я ожидал, что удаление отпечатка ускорит процесс, а не замедлит его. Я сбрасываю FIFO при первом запуске, поэтому программа всегда сначала печатает «FIFO EMPTY».
Редактировать: Включено достаточно кода для автономной работы. Проблема в функции read_fifo (BUS, LSM). Я работаю на Python 3.4.2 и использую модуль smbus2: https://pypi.org/project/smbus2/