scale_diag.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #!/usr/bin/env python3
  2. """NAU7802 Scale Diagnostic — ported from SpoolBuddy Rust firmware.
  3. I2C address: 0x2A
  4. Bus: /dev/i2c-0 (GPIO0/GPIO1 on RPi)
  5. """
  6. import struct
  7. import sys
  8. import time
  9. import smbus2
  10. I2C_BUS = 0
  11. NAU7802_ADDR = 0x2A
  12. # Register addresses
  13. REG_PU_CTRL = 0x00
  14. REG_CTRL1 = 0x01
  15. REG_CTRL2 = 0x02
  16. REG_ADCO_B2 = 0x12 # ADC output MSB
  17. REG_ADCO_B1 = 0x13
  18. REG_ADCO_B0 = 0x14 # ADC output LSB
  19. REG_ADC = 0x15
  20. REG_PGA = 0x1B
  21. REG_PWR_CTRL = 0x1C
  22. REG_REVISION = 0x1F
  23. # PU_CTRL bits
  24. PU_RR = 0x01 # Register reset
  25. PU_PUD = 0x02 # Power up digital
  26. PU_PUA = 0x04 # Power up analog
  27. PU_PUR = 0x08 # Power up ready (read-only)
  28. PU_CS = 0x10 # Cycle start
  29. PU_CR = 0x20 # Cycle ready (read-only)
  30. PU_OSCS = 0x40 # Oscillator select
  31. PU_AVDDS = 0x80 # AVDD source select
  32. class NAU7802:
  33. def __init__(self, bus=I2C_BUS, addr=NAU7802_ADDR):
  34. self._bus = smbus2.SMBus(bus)
  35. self._addr = addr
  36. def close(self):
  37. self._bus.close()
  38. def read_reg(self, reg: int) -> int:
  39. return self._bus.read_byte_data(self._addr, reg)
  40. def write_reg(self, reg: int, val: int):
  41. self._bus.write_byte_data(self._addr, reg, val & 0xFF)
  42. def init(self):
  43. """Initialize NAU7802 — matches Rust firmware init sequence."""
  44. revision = self.read_reg(REG_REVISION)
  45. print(f" Revision: 0x{revision:02X}")
  46. # Reset
  47. self.write_reg(REG_PU_CTRL, PU_RR)
  48. time.sleep(0.010)
  49. self.write_reg(REG_PU_CTRL, 0x00)
  50. # Power up digital + analog
  51. self.write_reg(REG_PU_CTRL, PU_PUD | PU_PUA)
  52. # Wait for power-up ready
  53. for _ in range(100):
  54. status = self.read_reg(REG_PU_CTRL)
  55. if status & PU_PUR:
  56. print(" Power-up ready")
  57. break
  58. time.sleep(0.001)
  59. else:
  60. raise TimeoutError("NAU7802 power-up timeout")
  61. # Sample rate: 10 SPS (bits 6:4 of CTRL2 = 0b000)
  62. ctrl2 = self.read_reg(REG_CTRL2)
  63. self.write_reg(REG_CTRL2, (ctrl2 & 0x8F) | (0 << 4))
  64. print(" Sample rate: 10 SPS")
  65. # Gain: 128x (bits 2:0 of CTRL1 = 0b111)
  66. ctrl1 = self.read_reg(REG_CTRL1)
  67. self.write_reg(REG_CTRL1, (ctrl1 & 0xF8) | 7)
  68. print(" Gain: 128x")
  69. # LDO: 3.3V (bits 5:3 of CTRL1 = 0b100)
  70. ctrl1 = self.read_reg(REG_CTRL1)
  71. self.write_reg(REG_CTRL1, (ctrl1 & 0xC7) | (0b100 << 3))
  72. # Enable internal LDO (bit 7 of CTRL1)
  73. ctrl1 = self.read_reg(REG_CTRL1)
  74. self.write_reg(REG_CTRL1, ctrl1 | 0x80)
  75. print(" LDO: 3.3V (internal)")
  76. # Start conversion cycle
  77. pu_ctrl = self.read_reg(REG_PU_CTRL)
  78. self.write_reg(REG_PU_CTRL, pu_ctrl | PU_CS)
  79. print(" Conversion started")
  80. def data_ready(self) -> bool:
  81. return bool(self.read_reg(REG_PU_CTRL) & PU_CR)
  82. def read_raw(self) -> int:
  83. """Read 24-bit signed ADC value."""
  84. b2 = self.read_reg(REG_ADCO_B2)
  85. b1 = self.read_reg(REG_ADCO_B1)
  86. b0 = self.read_reg(REG_ADCO_B0)
  87. raw = (b2 << 16) | (b1 << 8) | b0
  88. # Sign extend 24-bit to 32-bit
  89. if raw & 0x800000:
  90. raw |= 0xFF000000
  91. raw = struct.unpack("i", struct.pack("I", raw))[0]
  92. return raw
  93. def main():
  94. print("=" * 60)
  95. print("NAU7802 Scale Diagnostic")
  96. print("=" * 60)
  97. scale = NAU7802()
  98. try:
  99. print("[1] Initializing...")
  100. scale.init()
  101. print("[2] Waiting for first reading...")
  102. for _ in range(200):
  103. if scale.data_ready():
  104. break
  105. time.sleep(0.010)
  106. else:
  107. print(" Timeout waiting for data ready")
  108. sys.exit(1)
  109. print("[3] Reading 10 samples (10 SPS = ~1 second)...")
  110. readings = []
  111. for i in range(10):
  112. # Wait for data ready
  113. for _ in range(200):
  114. if scale.data_ready():
  115. break
  116. time.sleep(0.010)
  117. raw = scale.read_raw()
  118. readings.append(raw)
  119. print(f" Sample {i + 1:2d}: {raw:>10d}")
  120. avg = sum(readings) / len(readings)
  121. spread = max(readings) - min(readings)
  122. print(f"\n Average: {avg:>10.0f}")
  123. print(f" Min: {min(readings):>10d}")
  124. print(f" Max: {max(readings):>10d}")
  125. print(f" Spread: {spread:>10d}")
  126. print("\n" + "=" * 60)
  127. print("Diagnostic complete!")
  128. print("=" * 60)
  129. except Exception as e:
  130. print(f"\nERROR: {e}")
  131. import traceback
  132. traceback.print_exc()
  133. sys.exit(1)
  134. finally:
  135. scale.close()
  136. if __name__ == "__main__":
  137. main()