# Tips and Tricks Community-sourced recipes for common tasks. Many of these originate from questions raised in the issue tracker. (signed-integer-conversion)= ## Signed Integer Conversion smbus2 always returns **unsigned** integer values, matching the raw bytes from the bus. To interpret a value as a signed integer, use Python's `ctypes` ([#11](https://github.com/kplindegaard/smbus2/issues/11)): ```python from ctypes import c_int8, c_uint8, c_int16, c_uint16 from smbus2 import SMBus with SMBus(1) as bus: # Read an unsigned byte and convert to signed unsigned_byte = bus.read_byte_data(0x50, 0x00) # e.g. 200 signed_byte = c_int8(unsigned_byte).value # → -56 # Convert a signed Python integer to the unsigned byte value sent on the wire signed_value = -123 bus.write_byte_data(0x50, 0x00, c_uint8(signed_value).value) # writes 133 # Same pattern for 16-bit words unsigned_word = bus.read_word_data(0x50, 0x02) signed_word = c_int16(unsigned_word).value ``` (endianness-byte-order-conversion)= ## Endianness / Byte-Order Conversion `read_word_data` returns a 16-bit integer assembled by the Linux kernel following the SMBus convention (low byte first). If your device sends the high byte first (big-endian), swap the bytes manually ([#86](https://github.com/kplindegaard/smbus2/issues/86)): ```python # Bit-manipulation swap value = bus.read_word_data(0x50, 0x00) swapped = ((value & 0xFF) << 8) | ((value >> 8) & 0xFF) # Alternatively, use the struct module import struct raw = bus.read_word_data(0x50, 0x00) (big_endian_value,) = struct.unpack('>H', struct.pack(' SMBus: """Return the shared SMBus instance.""" return _BusHolder() ``` For multi-threaded code, add a `threading.Lock` around each operation — see {doc}`best_practices` for an example. (asyncio-async-support)= ## asyncio / Async Support smbus2 itself is **synchronous**. For `asyncio` applications, a community library wraps smbus2 with async/await support ([#18](https://github.com/kplindegaard/smbus2/issues/18)): - **smbus2_asyncio** — https://github.com/jabdoa2/smbus2_asyncio (Python 3.4+) Note that because I2C operations are typically short and infrequent, running them in a thread pool executor (`asyncio.get_event_loop().run_in_executor`) is often sufficient without a dedicated async library: ```python import asyncio from smbus2 import SMBus async def read_sensor(): loop = asyncio.get_event_loop() with SMBus(1) as bus: value = await loop.run_in_executor( None, bus.read_byte_data, 0x50, 0x00 ) return value ``` (setting-i2c-bus-clock-speed-baud-rate)= ## Setting I2C Bus Clock Speed (Baud Rate) smbus2 does not expose a clock-speed setting ([#77](https://github.com/kplindegaard/smbus2/issues/77)). The I2C clock is controlled at the kernel/hardware level: - **Raspberry Pi** — add `dtparam=i2c_arm_baudrate=100000` to `/boot/config.txt` (replaces `i2c_arm` overlay parameter). - **Other SBCs** — consult the board's device-tree documentation. - **Kernel module parameter** — some drivers accept a `baudrate` or `speed` parameter via `modprobe`. Clock stretching (the slave holding SCL low to pause the master) is also handled entirely by the kernel driver.