feat: Enhance MPU6050Slave I2C handling with improved WHO_AM_I read tracking; update tests for clarity
This commit is contained in:
parent
a76f7b51fd
commit
4667c8bb3b
|
|
@ -43,7 +43,13 @@ class MPU6050Slave:
|
||||||
# WRITE, as happens with Adafruit BusIO write-then-read) returns 0x68.
|
# WRITE, as happens with Adafruit BusIO write-then-read) returns 0x68.
|
||||||
self.reg_ptr = 0x75
|
self.reg_ptr = 0x75
|
||||||
self.first_byte = True
|
self.first_byte = True
|
||||||
self._first_read_done = False # True after begin() WHO_AM_I is read
|
# Adafruit_I2CDevice::begin() fires TWO WHO_AM_I reads before the
|
||||||
|
# library moves on to actual data reads:
|
||||||
|
# 1. detected() uses requestFrom as fallback — fires START+READ
|
||||||
|
# 2. chip_id_register.read() — fires START+READ
|
||||||
|
# Only after both have returned 0x68 do we switch reg_ptr to 0x3B
|
||||||
|
# (start of accel/gyro/temp block) for subsequent data transactions.
|
||||||
|
self._who_am_i_count = 0
|
||||||
|
|
||||||
# WHO_AM_I
|
# WHO_AM_I
|
||||||
self.regs[0x75] = 0x68
|
self.regs[0x75] = 0x68
|
||||||
|
|
@ -68,13 +74,17 @@ class MPU6050Slave:
|
||||||
|
|
||||||
if op == I2C_START:
|
if op == I2C_START:
|
||||||
self.first_byte = True
|
self.first_byte = True
|
||||||
if self._first_read_done:
|
# picsimlab does not fire WRITE callbacks for write-then-read
|
||||||
# picsimlab does not fire WRITE callbacks for write-then-read
|
# transactions (endTransmission(false) + requestFrom).
|
||||||
# transactions (endTransmission(false) + requestFrom). After
|
# Adafruit_I2CDevice::begin() fires TWO START+READ sequences
|
||||||
# begin() has succeeded, reset reg_ptr to the accel/gyro/temp
|
# before any data reads:
|
||||||
# block so data reads return the right bytes even without a
|
# 1. detected() → requestFrom fallback → START+READ(WHO_AM_I)
|
||||||
# prior WRITE setting the register address.
|
# 2. chip_id_register.read() → START+READ(WHO_AM_I)
|
||||||
self.reg_ptr = 0x3B
|
# Only after both have returned 0x68 do we switch to data mode.
|
||||||
|
if self._who_am_i_count >= 2:
|
||||||
|
self.reg_ptr = 0x3B # sensor data block
|
||||||
|
else:
|
||||||
|
self.reg_ptr = 0x75 # WHO_AM_I register
|
||||||
return 1 # ACK — device present
|
return 1 # ACK — device present
|
||||||
elif op in _I2C_WRITE_CODES:
|
elif op in _I2C_WRITE_CODES:
|
||||||
if self.first_byte:
|
if self.first_byte:
|
||||||
|
|
@ -90,8 +100,10 @@ class MPU6050Slave:
|
||||||
return 1 # ACK
|
return 1 # ACK
|
||||||
elif op == I2C_READ:
|
elif op == I2C_READ:
|
||||||
val = self.regs[self.reg_ptr]
|
val = self.regs[self.reg_ptr]
|
||||||
|
# Track WHO_AM_I reads to know when begin() has confirmed device
|
||||||
|
if self.reg_ptr == 0x75 and val == 0x68:
|
||||||
|
self._who_am_i_count += 1
|
||||||
self.reg_ptr = (self.reg_ptr + 1) & 0xFF
|
self.reg_ptr = (self.reg_ptr + 1) & 0xFF
|
||||||
self._first_read_done = True
|
|
||||||
return val
|
return val
|
||||||
else: # STOP / unknown
|
else: # STOP / unknown
|
||||||
self.first_byte = True
|
self.first_byte = True
|
||||||
|
|
|
||||||
|
|
@ -400,16 +400,27 @@ class TestMPU6050Slave(unittest.TestCase):
|
||||||
f"Expected WHO_AM_I=0x68 without WRITE, got 0x{result:02x}")
|
f"Expected WHO_AM_I=0x68 without WRITE, got 0x{result:02x}")
|
||||||
|
|
||||||
def test_data_read_after_begin(self):
|
def test_data_read_after_begin(self):
|
||||||
"""After begin() succeeds, START should reset reg_ptr to 0x3B (accel block)."""
|
"""After begin() succeeds (two WHO_AM_I reads), START resets reg_ptr to 0x3B.
|
||||||
|
|
||||||
|
Adafruit_I2CDevice::begin() fires TWO START+READ sequences before data reads:
|
||||||
|
1. detected() requestFrom fallback → START+READ(WHO_AM_I)
|
||||||
|
2. chip_id_register.read() → START+READ(WHO_AM_I)
|
||||||
|
Only after both return 0x68 does the slave switch to data mode.
|
||||||
|
"""
|
||||||
m = MPU6050Slave()
|
m = MPU6050Slave()
|
||||||
# Simulate begin(): START + READ (no WRITE) → gets WHO_AM_I
|
# First WHO_AM_I read: detected() requestFrom fallback
|
||||||
m.handle_event(I2C_START)
|
m.handle_event(I2C_START)
|
||||||
m.handle_event(I2C_READ) # _first_read_done = True
|
r1 = m.handle_event(I2C_READ)
|
||||||
# Next transaction: START should reset reg_ptr to 0x3B
|
self.assertEqual(r1, 0x68, "First WHO_AM_I read must return 0x68")
|
||||||
|
# Second WHO_AM_I read: actual chip_id check — count reaches 2
|
||||||
|
m.handle_event(I2C_START)
|
||||||
|
r2 = m.handle_event(I2C_READ)
|
||||||
|
self.assertEqual(r2, 0x68, "Second WHO_AM_I read must return 0x68")
|
||||||
|
# Now _who_am_i_count=2 → next START switches to data mode
|
||||||
m.handle_event(I2C_START)
|
m.handle_event(I2C_START)
|
||||||
first_accel_byte = m.handle_event(I2C_READ)
|
first_accel_byte = m.handle_event(I2C_READ)
|
||||||
self.assertEqual(first_accel_byte, m.regs[0x3B],
|
self.assertEqual(first_accel_byte, m.regs[0x3B],
|
||||||
"After begin(), START should reset reg_ptr to 0x3B (accel block)")
|
"After two WHO_AM_I reads, START should reset reg_ptr to 0x3B (accel block)")
|
||||||
|
|
||||||
def test_accel_z_default_1g(self):
|
def test_accel_z_default_1g(self):
|
||||||
"""ACCEL_Z should default to +1g = 0x4000 (MSB=0x40, LSB=0x00)."""
|
"""ACCEL_Z should default to +1g = 0x4000 (MSB=0x40, LSB=0x00)."""
|
||||||
|
|
@ -454,6 +465,7 @@ if __name__ == '__main__':
|
||||||
TestDS1307Slave,
|
TestDS1307Slave,
|
||||||
TestDS3231Slave,
|
TestDS3231Slave,
|
||||||
TestI2CWriteSink,
|
TestI2CWriteSink,
|
||||||
|
TestMPU6050Slave,
|
||||||
]:
|
]:
|
||||||
suite.addTests(loader.loadTestsFromTestCase(cls))
|
suite.addTests(loader.loadTestsFromTestCase(cls))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue