STATUS: SOLVED — Feb 2026

Programming dsPIC33CK64MC105
from Raspberry Pi 4B on Debian 13

A complete walkthrough of getting Microchip's Curiosity Nano board talking to pymcuprog on ARM Linux — without MPLAB X, without x86, without QEMU.

Host: Raspberry Pi 4B
OS: Debian 13 Trixie
Board: Curiosity Nano dsPIC33CK64MC105
Tool: pymcuprog + pyedbglib
Author: Claude.ai with Carl Wuebker testing Claude.ai's ideas on the rPi4b
// 01

Background & Goal

I'm a retired EE who has worked on analog, digital, ASIC & hardware and C, Perl & Python CAD software over my 40+ year career. I use a Raspberry Pi 4B running Debian 13 (trixie) Linux for CAD because it's fun and -- if I download software that causes problems with the system -- it's easy to swap in a backup SD and try something different. The Raspberry Pi 4B is an arm64 computer, not an amd64 computer, though, and, when I tried using a QEMU x86_64 Linux instance to run Microchip's MPLAB X IDE, it took hours to load & and hours trying to start the IDE before I gave up and asked Claude.ai for help. duck.ai allows you to run Claude Haiku 3.6 and I was happy with that. However, I found that using a free Claude.ai account and running Sonnet 4.6 was a better choice for this project. Claude.ai summarizes the problems we found & it (with a little help from me) fixed below:

Microchip's XC compiler toolchain can be compiled and run on a Raspberry Pi 4B running Debian 13 (Trixie). The missing piece was a way to download the compiled .hex file into a Curiosity Nano dsPIC33CK64MC105 evaluation board — without needing a full x86 MPLAB X installation.

Microchip provides pymcuprog, an open-source Python programming tool that supports nEDBG-based Curiosity Nano boards via the EDBG/CMSIS-DAP protocol. On paper this should work natively on ARM Linux. In practice, four distinct problems blocked it.

Problem 1

USB HID never appeared

hidraw3 was created then immediately destroyed by a USB reset triggered by the mass storage driver.

Problem 2

QEMU held the USB device

A running x86_64 QEMU instance with USB forwarding kept exclusive control of the nEDBG, causing resets.

Problem 3

Wrong packpath argument

pymcuprog expected the device scripts folder itself, not the top-level DFP version directory.

Result

Ping response: 9912 ✓

Full read/write/erase access to the dsPIC33CK64MC105 from the Raspberry Pi 4B. No x86 needed.

// 02

Problem Diagnosis

Symptom Root Cause Fix Status
Unable to connect to USB device (open failed) QEMU had exclusive USB ownership via USB forwarding Shut down the QEMU instance before using pymcuprog FIXED
/dev/hidraw3 disappears seconds after plugging in Linux automount tried to mount the nEDBG's MSD interface, FAT errors caused a USB reset destroying all interfaces udev rule with UDISKS_IGNORE; QEMU shutdown was the real fix FIXED
/dev/hidraw3 owned by root, mode 0600 No udev rule for hidraw subsystem with Atmel VID 0x03EB udev rule targeting SUBSYSTEM=="hidraw" with ATTRS{idVendor}=="03eb" FIXED
Unable to setup stack using the given packpath packpath pointed to DFP version root; pymcuprog needs the device-specific scripts subdirectory Point packpath to scripts/dspic33ck64mc105 FIXED
Note on the nEDBG USB VID

The Curiosity Nano's onboard programmer enumerates with Atmel VID 0x03EB (PID 0x2175), not Microchip VID 0x04D8. This is correct — Microchip acquired Atmel and the nEDBG firmware predates the rebrand. The pyedbglib source already handles this correctly; the issue was purely the udev rules and the QEMU conflict.

Note on the DFP scripts

The file nedbg_dspic33ck64mc105.py inside the DFP pack contains Python 2 syntax (except E, e: and xrange()). This file is a Jython script for use inside MPLAB X and is not loaded by pymcuprog. pymcuprog uses common/debugprovider.py and dspic33ck64mc105pds.py instead, which are Python 3 compatible.

// 03

Installation

Install pymcuprog and pyedbglib

BASHterminal
$ pip install pymcuprog pyedbglib --break-system-packages

Download the dsPIC33CK Device Family Pack

Download Microchip.dsPIC33CK-MC_DFP from packs.download.microchip.com and extract it. The relevant directory is the versioned subfolder — in this example, version 1.8.299.

BASHterminal
$ mkdir -p ~/microchip/packs
$ cd ~/microchip/packs
$ # Extract your downloaded .atpack file (it's a zip)
$ unzip Microchip.dsPIC33CK-MC_DFP.1.8.299.atpack -d dsPIC33CK-MC_DFP/1.8.299

$ # Verify the scripts directory exists for your device
$ ls ~/microchip/packs/dsPIC33CK-MC_DFP/1.8.299/scripts/dspic33ck64mc105/
nedbg_dspic33ck64mc105.py  dspic33ck64mc105pds.py  version.py  common/
// 04

USB & udev Setup

The Curiosity Nano nEDBG is a composite USB device presenting four interfaces: HID (CMSIS-DAP), CDC-ACM (serial), Mass Storage, and DGI. Linux needs permission rules to make the HID interface accessible to non-root users.

Create the udev rule

BASH/etc/udev/rules.d/99-microchip.rules
# Microchip / Atmel nEDBG (Curiosity Nano onboard programmer)
# VID 03eb = Atmel (used by nEDBG even on post-acquisition boards)

SUBSYSTEM=="usb",    ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2175", MODE="0666", GROUP="plugdev"
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2175", MODE="0666", GROUP="plugdev"
SUBSYSTEM=="tty",    ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2175", MODE="0666", GROUP="plugdev"
SUBSYSTEM=="block",  ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2175", ENV{UDISKS_IGNORE}="1", ENV{UDISKS_AUTO}="0"
BASHterminal
$ sudo udevadm control --reload-rules
$ # Unplug and replug the Curiosity Nano, then verify:
$ ls -la /dev/hidraw* /dev/ttyACM*
crw-rw-rw-+ 1 root plugdev 242, 3 Feb 26 16:02 /dev/hidraw3
crw-rw-rw-+ 1 root plugdev 166, 0 Feb 26 16:02 /dev/ttyACM0
QEMU USB Conflict

If you are running a QEMU virtual machine with USB device forwarding pointing at the Curiosity Nano, pymcuprog will fail and the USB device will reset repeatedly. You must shut down (not suspend) the QEMU instance before using pymcuprog. The two cannot share the device.

Verify the device is enumerated correctly

BASHterminal
$ lsusb | grep 03eb
Bus 001 Device 006: ID 03eb:2175 Atmel Corp. nEDBG CMSIS-DAP

$ python3 -c "import hid; [print(d) for d in hid.enumerate() if d['vendor_id']==0x03eb]"
{'vendor_id': 1003, 'product_id': 8565, 'serial_number': 'MC020023603FAS001511',
 'manufacturer_string': 'Microchip Technology Incorporated',
 'product_string': 'nEDBG CMSIS-DAP', ...}
What the kernel loads for this composite device

When the Curiosity Nano is plugged in you should see in dmesg: hid-generic binding hidraw3, cdc_acm binding ttyACM0, and usb-storage binding the MSD interface as sda. The key sign of success is no USB reset following these lines.

// 05

The Critical packpath Argument

This is the most counterintuitive part. pymcuprog's --packpath argument must point to the device-specific scripts directory inside the DFP, not the top-level version directory.

Internally, nvmpic.py does this:

PYTHONnvmpic.py (excerpt)
sys.path = [os.path.normpath(packpath)] + sys.path
sys.path = [os.path.normpath(packpath + "//common")] + sys.path
from common.debugprovider import provide_debugger_model

For the import to succeed, packpath must be the directory that directly contains the common/ subdirectory and the dspic33ck64mc105pds.py file.

BASHterminal — WRONG vs CORRECT
# ✗ WRONG — points to DFP version root
--packpath ~/microchip/packs/dsPIC33CK-MC_DFP/1.8.299

# ✓ CORRECT — points to device scripts directory
--packpath ~/microchip/packs/dsPIC33CK-MC_DFP/1.8.299/scripts/dspic33ck64mc105
// 06

Usage

Convenience wrapper script

Save typing with a small shell wrapper:

BASH~/bin/picprog
#!/bin/bash
PACKPATH=~/microchip/packs/dsPIC33CK-MC_DFP/1.8.299/scripts/dspic33ck64mc105
pymcuprog -t nedbg --packpath $PACKPATH -d dspic33ck64mc105 "$@"
BASHterminal
$ chmod +x ~/bin/picprog

Ping — verify connection

BASHterminal
$ picprog ping
Connecting to any nedbg
Connected to nEDBG CMSIS-DAP from Microchip (serial number MC020023603FAS001511)
Debugger firmware version 1.30.35
Debugger hardware revision 0
Device mounted: 'dspic33ck64mc105'
Pinging device...
Ping response: 9912
Done.

Write a hex file

BASHterminal
$ picprog write -m flash -f myprogram.hex --verify

Read flash memory

BASHterminal
$ picprog read -m flash

Erase the device

BASHterminal
$ picprog erase

Write with erase first (typical programming flow)

BASHterminal
$ picprog erase && picprog write -m flash -f myprogram.hex --verify
// 07

Complete Fix Summary

  • 01

    Shut down any QEMU instance that has USB forwarding to the Curiosity Nano. QEMU takes exclusive ownership of the USB device and prevents any other process from opening it. This also causes repeated USB resets visible in dmesg.

  • 02

    Install pymcuprog and pyedbglib via pip. The nEDBG's Atmel VID 0x03EB is already handled correctly in pyedbglib/hidtransport/cyhidapi.py — no source patching needed.

  • 03

    Create /etc/udev/rules.d/99-microchip.rules with rules for both SUBSYSTEM=="usb" and SUBSYSTEM=="hidraw" matching ATTRS{idVendor}=="03eb". The hidraw rule is essential — hidapi opens /dev/hidrawX, not the raw USB device.

  • 04

    Download the dsPIC33CK-MC_DFP device pack from packs.download.microchip.com and extract it. Confirm the scripts/dspic33ck64mc105/ directory exists inside the version folder.

  • 05

    Pass the device scripts directory as --packpath, not the top-level DFP directory. The correct path ends in .../scripts/dspic33ck64mc105. pymcuprog prepends this to sys.path to import the common module directly.

  • 06

    Verify with pymcuprog ping. A successful response shows Ping response: 9912 — the device ID for the dsPIC33CK64MC105 is 0x26B8 = 9912 decimal.

End Result

A complete, native ARM Linux toolchain for compiling and programming dsPIC33CK firmware. Microchip XC compiler builds the hex file on the Raspberry Pi, and pymcuprog downloads it to the Curiosity Nano — no x86 machine, no MPLAB X, no QEMU required.