MustafaMulla29/rp2040-bldc-motor-controller-new

A USB‑C PD–powered RP2040 BLDC motor controller PCB with 3.3 V logic, MCT8329A sensorless commutation, three MOSFET half-bridges, protected power switching, USB data, controls, and motor connectors.

Version
0.3.82
License
unset
Stars
0

firmware/pd_nvm.py

"""STUSB4500 NVM transport; no writes happen on import.

Implements the register protocol in ST's USBPD_CUST_NVM_API.c / USB_PD_defines.h:
https://github.com/usb-c/STUSB4500/tree/master/NVM_Flasher/Src/NVM
Only sectors 3 and 4 are erased/programmed; sectors 0..2 stay untouched.
Every operation is bounded, and the complete image is read back after programming.
"""
import time
from pd_profile import nvm_9v_image, nvm_is_9v


class NVM:
    def __init__(self, bus, address=0x28, clock=time):
        self.bus, self.address, self.clock = bus, address, clock

    def _write(self, reg, value):
        self.bus.writeto_mem(self.address, reg, bytes((value,)))

    def _read(self, reg, size=1):
        return self.bus.readfrom_mem(self.address, reg, size)

    def _wait(self):
        start = self.clock.ticks_ms()
        while self._read(0x96)[0] & 0x10:
            if self.clock.ticks_diff(self.clock.ticks_ms(), start) >= 1000:
                raise OSError("STUSB4500 NVM operation timed out")
            self.clock.sleep_ms(1)

    def _enter(self):
        self._write(0x95, 0x47)
        self._write(0x96, 0)
        self._write(0x96, 0xC0)

    def _exit(self):
        try:
            self.bus.writeto_mem(self.address, 0x96, b"\x40\x00")
        finally:
            self._write(0x95, 0)

    def _command(self, opcode, sector=0):
        self._write(0x97, opcode)
        self._write(0x96, 0xD0 | sector)
        self._wait()

    def read(self):
        try:
            self._enter()
            image = bytearray()
            for sector in range(5):
                self._write(0x96, 0xC0)
                self._command(0, sector)
                image.extend(self._read(0x53, 8))
                self._write(0x96, 0)
            return bytes(image)
        finally:
            self._exit()

    def provision_9v(self):
        original = self.read()
        if nvm_is_9v(original):
            return False  # already provisioned: no erase/write cycle
        desired = nvm_9v_image(original)
        try:
            self._write(0x95, 0x47)
            self._write(0x53, 0)  # required for partial-sector erase
            self._write(0x96, 0)
            self._write(0x96, 0xC0)
            self._command((0x18 << 3) | 2)  # select sectors 3,4 (WRITE_SER)
            self._command(7)  # SOFT_PROG_SECTOR
            self._command(5)  # ERASE_SECTOR
            for sector in (3, 4):
                self.bus.writeto_mem(self.address, 0x53, desired[8*sector:8*sector+8])
                self._write(0x96, 0xC0)
                self._command(1)  # load programming register
                self._command(6, sector)  # program selected sector
        finally:
            self._exit()
        if self.read() != desired:
            raise OSError("NVM readback mismatch; do not connect a PD charger")
        return True