Cannot write to HM01B0 camera registers via I2C on Raspberry Pi Pico MicroPython

Hi all. I’ve got an HM01B0 camera hooked up to a Raspberry Pi Pico running MicroPython, and I’m stuck on I2C writes. Reads seem fine, but when I try to write to a register the value doesn’t change. Specifically I need to read register 0x1003 and then write 0x42 to it. Does anyone have a working read_16_8 / write_16_8 example for this chip?

Can you tell me a bit more about your setup? Which camera module, which Pico pins for SDA/SCL, what I2C address you’re seeing on scan, and which IDE you’re using? Also, is the camera wired up according to KB007.pdf?

Sure. It’s the HM01B0 camera module on a Raspberry Pi Pico, MicroPython in Thonny. SCL is GP5 and SDA is GP4. I2C scan shows 0x24. The camera is connected following KB007.pdf.

Thanks. Can you paste your current script and the serial output from Thonny? That’ll help see where the write is going wrong.

Here’s my current script:

from machine import Pin, I2C
import time

# MAIN
# assign Pico pins
LED = Pin(25, Pin.OUT)
Href = Pin(15,Pin.OUT)
Href.value(0)
Vsync = Pin(16,Pin.OUT)
Pclk = Pin(14,Pin.IN,Pin.PULL_UP)
D0 = Pin(6,Pin.IN,Pin.PULL_UP)
i2c = machine.I2C(0, scl=machine.Pin(5), sda=machine.Pin(4))

devices = i2c.scan()
if devices:
    for d in devices:
        print('Found device',hex(d))
else:
    print('No device found')

# put some register addresses in a list
reglist = [0x0100,0x1003]      # mode select, black level target

#read the default register values
for i in range(len(reglist)):
    val = i2c.readfrom_mem(0x24, reglist[i], 1 ,addrsize=16)
    val = hex(val[0])
    print('reg',hex(reglist[i]),'value',val)
print()

# change black level target value
i2c.writeto_mem(0x24, 0x1003, b'\x42')
print('Black level target write 0x42')
time.sleep(0.1)

# check result
for i in range(len(reglist)):
    val = i2c.readfrom_mem(0x24, reglist[i], 1 ,addrsize=16)
    val = hex(val[0])
    print('reg',hex(reglist[i]),'value',val)

And the output:

MPY: soft reboot
Found device 0x24
reg 0x100 value 0x0
reg 0x1003 value 0x20

Black level target write 0x42
reg 0x100 value 0x0
reg 0x1003 value 0x20

So 0x1003 reads 0x20, I write 0x42, and it still reads 0x20.

Thanks, that confirms it — reads work, but the write isn’t updating the register. The HM01B0 uses 16-bit register addresses with 8-bit data, and writeto_mem isn’t producing the write sequence this device expects. I’d switch to explicit helpers that pack the address and data bytes yourself. Something like this:

import struct

def write_16_8(self, reg, data, byteorder='big') -> None:
    addr_buf = bytearray(2)
    data_buf = bytearray(1)

    addr_encode = '<H' if byteorder == 'little' else '>H'
    data_encode = 'B'

    struct.pack_into(addr_encode, addr_buf, 0, reg)
    struct.pack_into(data_encode, data_buf, 0, data)

    buf = addr_buf + data_buf
    self.i2c.writeto(self.addr, buf)

def read_16_8(self, reg, byteorder='big'):
    addr_buf = bytearray(2)

    addr_encode = '<H' if byteorder == 'little' else '>H'
    data_encode = 'B'

    struct.pack_into(addr_encode, addr_buf, 0, reg)
    self.i2c.writeto(self.addr, addr_buf)
    data_buf = self.i2c.readfrom(self.addr, 1)
    data = struct.unpack_from(data_encode, data_buf, 0)[0]

    return data

You’ll need to adapt self.i2c to your i2c object and self.addr to 0x24 (or whatever you use).

Thanks. Just so I’m clear — for a write you pack the 2-byte address and the 1-byte data into one buffer and do a single writeto, and for a read you send the address first, then read 1 byte back and unpack it as ‘B’? And does the byte order matter for this camera?

Exactly. For writes, buf = addr_buf + data_buf goes out in one transaction. For reads, you first write addr_buf, then readfrom(..., 1) and unpack as unsigned byte 'B'. Byte order does matter — the default is big-endian ('>H'). If the wrong register appears to be hit, switch to '<H' little-endian. For 0x1003 you’d use write_16_8(0x1003, 0x42) and check with read_16_8(0x1003).

Got it, I’ll try that. So the original writeto_mem call was likely sending the bytes in a way the HM01B0 didn’t accept, even though addrsize=16 was set?

Right. The original writeto_mem read fine but the write never took. The working approach for this 16-bit address / 8-bit data device is to pack the register address with '>H' (big-endian, or '<H' if needed) and send the address bytes followed by the data byte in one write for writes; for reads, send the address then read 1 byte and unpack as 'B'. Try write_16_8(0x1003, 0x42) followed by read_16_8(0x1003) and let us know if the value now changes.