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.
|
||||
self.reg_ptr = 0x75
|
||||
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
|
||||
self.regs[0x75] = 0x68
|
||||
|
|
@ -68,13 +74,17 @@ class MPU6050Slave:
|
|||
|
||||
if op == I2C_START:
|
||||
self.first_byte = True
|
||||
if self._first_read_done:
|
||||
# picsimlab does not fire WRITE callbacks for write-then-read
|
||||
# transactions (endTransmission(false) + requestFrom). After
|
||||
# begin() has succeeded, reset reg_ptr to the accel/gyro/temp
|
||||
# block so data reads return the right bytes even without a
|
||||
# prior WRITE setting the register address.
|
||||
self.reg_ptr = 0x3B
|
||||
# picsimlab does not fire WRITE callbacks for write-then-read
|
||||
# transactions (endTransmission(false) + requestFrom).
|
||||
# Adafruit_I2CDevice::begin() fires TWO START+READ sequences
|
||||
# before any data reads:
|
||||
# 1. detected() → requestFrom fallback → START+READ(WHO_AM_I)
|
||||
# 2. chip_id_register.read() → START+READ(WHO_AM_I)
|
||||
# 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
|
||||
elif op in _I2C_WRITE_CODES:
|
||||
if self.first_byte:
|
||||
|
|
@ -90,8 +100,10 @@ class MPU6050Slave:
|
|||
return 1 # ACK
|
||||
elif op == I2C_READ:
|
||||
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._first_read_done = True
|
||||
return val
|
||||
else: # STOP / unknown
|
||||
self.first_byte = True
|
||||
|
|
|
|||
|
|
@ -400,16 +400,27 @@ class TestMPU6050Slave(unittest.TestCase):
|
|||
f"Expected WHO_AM_I=0x68 without WRITE, got 0x{result:02x}")
|
||||
|
||||
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()
|
||||
# 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_READ) # _first_read_done = True
|
||||
# Next transaction: START should reset reg_ptr to 0x3B
|
||||
r1 = m.handle_event(I2C_READ)
|
||||
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)
|
||||
first_accel_byte = m.handle_event(I2C_READ)
|
||||
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):
|
||||
"""ACCEL_Z should default to +1g = 0x4000 (MSB=0x40, LSB=0x00)."""
|
||||
|
|
@ -454,6 +465,7 @@ if __name__ == '__main__':
|
|||
TestDS1307Slave,
|
||||
TestDS3231Slave,
|
||||
TestI2CWriteSink,
|
||||
TestMPU6050Slave,
|
||||
]:
|
||||
suite.addTests(loader.loadTestsFromTestCase(cls))
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue