At ESC 2015 SV I gave a talk on using USB From Python, see the talk description here. This blog post is serving as a placeholder to allow me to update links to software used during the live demo.
For SuperCon 2015, there is a Project Page with these details too. You can also ask questions on the project page.
Download Slides
There is two versions of the slides. Use the SuperCon slides, but I left a copy of the ESC ones here in case you wanted the original for some reason.
Download Slides from Hackaday SuperCon 2015 (Newer Version for SAMD21) [PDF, 10MB]
Download Slides from ESC2015 (Older version for SAMD11) [PDF, 10MB]
Tools to Install
- Atmel Studio 6.2
- See Product Webpage (see latest version, registration required)
- Direct download link (no registration required)
- WinPython-2.7
- libusb-win32-devel-filter (NB: No need to open the filter install wizard when done)
- USBView
- USBView (no install, just unzip)
SAMD11 Errata
For ESC I used a SAMD11 device, which needs a bit of a hack.
There is a bit of an “oopsie” in the SAMD11 devices. This bug isn’t in the official errata yet, and I’ve been told it’s limited to engineering sample devices (which were used in some of the early dev boards).
Basically the 48MHz oscillator calibration byte is wrong, and you need to manually tune this. You’ll know this problem exists as the device won’t be detected by Windows:
The work-around isn’t super-fun. First, use the programming interface to see the starting value of the DFLL48M_COARSE_CAL fuse:
Next, search in the source code for reference to the dfll_conf.coarse_value variable. You will find where it is being setup, and you can override the value. Basically you have to experiment a bit to find a working value:
Reference Code
USB Test – Slide 87
import usb.core dev = usb.core.find(idVendor=0x03eb, idProduct=0x2402) print dev
If you get “None”, make sure you installed the “Filter Driver” using the LibUSB tools!
Control Endpoint Read – Slide 94
import usb.core dev = usb.core.find(idVendor=0x03eb, idProduct=0x2402) dev.set_configuration() data = dev.ctrl_transfer(0b10100001, 0x01, 3<<8, 0, 4) print data
If you get a “device is not functioning” error just skip this one…
Sending Output Report
import usb.core dev = usb.core.find(idVendor=0x03eb, idProduct=0x2402) print dev dev.set_configuration() data = [ord('1'), ord('1'), 0, 0, 0, 0, 0, 0] dev.write(0x02, data)
Receiving Input Data (Press button to see change)
import usb.core dev = usb.core.find(idVendor=0x03eb, idProduct=0x2402) print dev dev.set_configuration() for i in range(0, 10): while True: try: test = dev.read(0x81, 8, timeout=50) break except usb.core.USBError, e: if str(e).find("timeout") >= 0: pass else: raise IOError("USB Error: %s"%str(e)) print test
Full GUI Example
#Public domain - simple USB GUI Example by Colin O'Flynn from PySide.QtCore import * from PySide.QtGui import * import usb.core import sys class USBForm(QDialog): def __init__(self, parent=None): super(USBForm, self).__init__(parent) self.setWindowTitle("ESC 2015 Demo") layout = QVBoxLayout() self.setLayout(layout) self.pbConnect = QPushButton("Connect") self.pbConnect.clicked.connect(self.con) self.isConnected = False self.pbLED = QPushButton("LED Blinking") self.pbLED.setCheckable(True) self.pbLED.clicked.connect(self.changeLED) self.pbLED.setEnabled(False) layout.addWidget(self.pbConnect) layout.addWidget(self.pbLED) self.swStatus = QLineEdit() self.swStatus.setReadOnly(True) layout.addWidget(self.swStatus) self.butTimer = QTimer(self) self.butTimer.timeout.connect(self.pollButton) def con(self): if self.isConnected == False: #Do USB Connect Here self.dev = usb.core.find(idVendor=0x03eb, idProduct=0x2402) self.dev.set_configuration() #Sync changeLED self.changeLED() self.isConnected = True self.pbConnect.setText("Disconnect") self.pbLED.setEnabled(True) self.butTimer.start(100) else: self.isConnected = False self.pbConnect.setText("Connect") self.pbLED.setEnabled(False) self.butTimer.stop() def changeLED(self): if self.pbLED.isChecked(): #Send command to make LED on self.dev.write(0x02, [ord('1'), ord('1'), 0, 0, 0, 0, 0, 0]) self.pbLED.setText("LED On") else: #Send command to make LED blink self.dev.write(0x02, [ord('0'), ord('1'), 0, 0, 0, 0, 0, 0]) self.pbLED.setText("LED Blinking") def pollButton(self): try: data = self.dev.read(0x81, 8, timeout=50) if data[0]: self.swStatus.setText("Button Pressed") else: self.swStatus.setText("Button Released") except usb.core.USBError, e: if str(e).find("timeout") >= 0: pass else: raise IOError("USB Error: %s"%str(e)) if __name__ == "__main__": app = QApplication(sys.argv) form = USBForm() form.show() sys.exit(app.exec_())