Binho Atira: Protocols
Examples of using the Binho Atira for SWD debug, SPI flash programming and the UART bridge, and of flashing a target with pyOCD.
Examples (PyCosmicSDK)
Section titled “Examples (PyCosmicSDK)”Install the SDK:
pip install "pycosmicsdk>=1.7.0"On Linux, install the udev rule first; see Binho Atira hardware setup.
Probe info
Section titled “Probe info”from pycosmicsdk import DebugProbe, list_debug_probes
for found in list_debug_probes(): print(found.serial_number, found.path)
with DebugProbe.open() as probe: # first probe found; or open(serial="...") info = probe.info print(f"Serial: {probe.serial_number}") print(f"Firmware: {info.fw_major}.{info.fw_minor}.{info.fw_patch}")open() raises UnsupportedFirmwareError when the probe runs firmware older than 1.0, and DeviceNotFoundError when no probe matched, another program holds it, or the current user has no access to it.
Target power and reading
Section titled “Target power and reading”import timefrom pycosmicsdk import DebugProbe
with DebugProbe.open() as probe: power = probe.power() power.set_output(True) time.sleep(0.5) # the reading lags the switch by ~0.5 s r = power.reading() print(f"{r.voltage_mv} mV, {r.current_ua / 1000:.2f} mA, {r.power_mw} mW") print("rail on:", power.output())SWD: attach, halt, registers, memory, breakpoint
Section titled “SWD: attach, halt, registers, memory, breakpoint”Connect the target to J4 with a straight 10-pin cable.
import structimport timefrom pycosmicsdk import DebugProbe
REG_SP, REG_PC = 13, 15 # 0-12 = r0-r12, 13 = sp, 14 = lr, 15 = pcSCB_VTOR = 0xE000_ED08 # vector table base, on every Cortex-M
with DebugProbe.open() as probe: probe.power().set_output(True) # the SWD level shifters run from the rail time.sleep(0.5)
debug = probe.debug() debug.attach() state = debug.halt() print(f"halted at PC 0x{state.pc:08X}") print(f"SP 0x{debug.read_register(REG_SP):08X}")
(vtor,) = struct.unpack("<I", debug.read_memory(SCB_VTOR, 4)) print("vector table:", debug.read_memory(vtor, 64).hex())
stepped = debug.step() # one instruction bp = debug.set_breakpoint(stepped.pc) # hardware (FPB) breakpoint debug.run() deadline = time.monotonic() + 2.0 while not (hit := debug.state()).halted and time.monotonic() < deadline: time.sleep(0.01) if hit.halted: print(f"breakpoint hit at 0x{hit.pc:08X} ({hit.stop_reason.name})") else: debug.halt() debug.clear_breakpoint(bp)
debug.run() debug.detach() # target keeps runningwrite_memory() writes RAM only; program flash with pyOCD (below). A read that runs past the end of a memory region raises DebugError.
SPI flash: detect, erase, program, verify
Section titled “SPI flash: detect, erase, program, verify”Wire the flash to J4 as in J4 as an SPI flash header, with no SWD target on J4.
import timefrom pycosmicsdk import DebugProbe, FlashVerifyMethodfrom pycosmicsdk.enums import ( SpiBitOrder, SpiChipSelect, SpiChipSelectPolarity, SpiDataWidth, SpiMode,)
ADDR = 0x10_0000image = open("firmware.bin", "rb").read()
with DebugProbe.open() as probe: probe.power().set_output(True) # powers the flash on J4 pin 1 time.sleep(0.5)
spi = probe.spi() spi.initialize( bit_order=SpiBitOrder.MSB, mode=SpiMode.MODE_0, data_width=SpiDataWidth.BITS_8, chip_select=SpiChipSelect.CS_2, # J4 pin 9 chip_select_polarity=SpiChipSelectPolarity.ACTIVE_LOW, frequency_hz=8_000_000, # maximum ) try: flash = probe.flash() part = flash.detect() print(f"{part.name or '(unnamed)'}: {part.capacity // 1024} KiB, page {part.page_size} B")
flash.erase(ADDR, len(image)) flash.program(ADDR, image) print("transport:", flash.last_transport)
check = flash.verify(ADDR, image, method=FlashVerifyMethod.HASH) if check.passed: print("verify OK") else: print(f"first mismatch at 0x{check.first_mismatch:X}") finally: spi.release()program()uses the USB bulk interface when available and falls back to HID otherwise.flash.last_transportshows which ran.FlashVerifyMethod.HASHcompares a CRC-32 computed on the probe and reads the flash back only to locate a mismatch.FlashVerifyMethod.READBACKreads the whole span back.erase()erases whole sectors, so it can clear data on either side of the span passed.
UART bridge port
Section titled “UART bridge port”from pycosmicsdk import DebugProbe
with DebugProbe.open() as probe: print(probe.uart().bridge_port) # e.g. /dev/ttyACM0 or COM7; empty if not foundOpen that port with any serial library, for example pySerial: serial.Serial(port, 115200). Switch the target rail on first.
Asyncio
Section titled “Asyncio”AsyncDebugProbe has the same calls with await:
import asynciofrom pycosmicsdk import AsyncDebugProbe
async def main(): async with AsyncDebugProbe.open() as probe: power = probe.power() await power.set_output(True) await asyncio.sleep(0.5) r = await power.reading() print(f"{r.voltage_mv} mV, {r.current_ua} uA")
debug = probe.debug() await debug.attach() state = await debug.halt() print(f"halted at 0x{state.pc:08X}") await debug.run() await debug.detach()
asyncio.run(main())The probe answers one command at a time, so calls on one probe never overlap.
C++ (CosmicSDK)
Section titled “C++ (CosmicSDK)”#include <cstdio>#include "debugprobe/DebugProbe.hpp"
using namespace debugprobe;
int main() { DebugProbe probe; auto boards = DebugProbe::listDevices(); if (boards.empty() || !probe.connect("", boards[0].serial)) { return 1; } DeviceInfo info; if (probe.getDeviceInfo(info) == SUCCESS) { std::printf("firmware %u.%u.%u\n", info.fw_major, info.fw_minor, info.fw_patch); } probe.powerSetOutput(true); return 0;}Build: c++ -std=c++17 -Iinclude app.cpp -Llib -ldebugprobe -o app. More in the CosmicSDK debug probe guide.
Flashing a target MCU with pyOCD
Section titled “Flashing a target MCU with pyOCD”The Atira is a standard CMSIS-DAP probe. pyOCD programs the target’s internal flash with no plugin.
-
Close any program that holds the probe (for example an SDK script). Only one program can own the probe’s debug interface.
-
Switch the target rail on. pyOCD does not switch it, and the rail stays on after the script exits:
python -c "from pycosmicsdk import DebugProbe; p = DebugProbe.open(); p.power().set_output(True); p.close()" -
Install pyOCD and the target’s device pack, then flash. Example for an STM32H503RB:
python -m pip install pyocdpyocd list # shows the probe and its serialpyocd pack install stm32h503rbpyocd flash -u <serial> -t stm32h503rbtx --base-address 0x08000000 firmware.bin -
Read flash back only while the core is halted:
pyocd cmd -u <serial> -t stm32h503rbtx -c halt -c "savemem 0x08000000 131072 out.bin"
Verified: STM32H503RB on Linux with pyOCD 0.44.1, 11/11 program + verify + chip-erase cycles, about 6.5 s per 128 KiB. Other Cortex-M devices with a CMSIS pack should work the same way; they are not verified yet.

