Janet language bindings to FTDI's libMPSSE library for I2C and Serial communications on Windows & Linux.
LibMPSSE is a library written by FTDI to simplify I2C, SPI development, as configuring the underlying MPSSE hardware is fairly complex.
The Multi-Protocol Synchronous Serial Engine (MPSSE) is a piece of hardware available in some FTDI chips and cables that allows for configurable serial communication with devices, such as I2C, SPI, and JTAG, through their D2XX driver. Commands are sent to the MPSSE to execute, such as sending data, setting the clock, protocol features, or setting GPIO lines. While the chip will also appear as a Virtual COM port, that feature is not used here.
This module is an alpha-phase project written by a hobbyist -- all comments and nitpicks encouraged.
API is documented in api.md and is in flux. Function naming and usage generally follows libMPSSE, though some changes were made for ergonomics, e.g, I2C_GetChannelInfo -> (i2c/info)
A demo driver for an MPU6050 gyro is in the
/examplesfolder
The module can be imported in a script or the REPL:
(use libmpsse)which loads two submodules, i2c/ and spi/ which are generally the same, except the I2C functions take a 7-bit I2C address. Many functions can also be called as methods on an opened channel, such as (i2c/err) or (:err chan) and (:close chan)
Getting a channel's information:
(use libmpsse)
(i2c/channels) # Number of hardware channels; some devices have multiple
# => 1
(i2c/info 1)
# => {:description "C232HM-EDHSL-0"
# :flags 2
# :id 67330068
# :locid 28
# :serial "00000000"
# :type 8}This is an example flow for opening a new I2C channel:
(if (> (i2c/channels) 0)
(with [chan (i2c/open 1)] # Open the first channel
(-> chan
(:write-opt :start :stop) # Transfer settings can be changed prior to each read/write call
(:read-opt :start :stop :nak-last-byte)
(:init :fast) # Initialize to 400kbs
(:write 0x3C @"\x40\x00" 2)) # Write 2 bytes to address 0x3C
(def buf @"some data: ")
(:read chan 0x3C buf 2) # Append 2 bytes from address 0x3C to buffer
(:close chan)) # Currently a closed channel object cannot be reopened; use (i2c/open) to create a new one
(print "no channel found"))The various transfer and config options are lightly documented in api-i2c.md and api-spi.md, but for a full description see the FTDI libMPSSE Application Notes 177 (i2c) and 178 (spi) as some options are only available on specific devices.
The
/readand/writefunctions are blocking, and/channelsand/infoare not thread-safe
This module has been primarily written and tested on:
- Windows 10 x64
- lighly tested on Debian 12.11/Proxmox VM with usb passthru.
- Fedora 44 amd64
Documentation is generated using documentarian.
- FTDI D2xx drivers. Available for Win/Linux/Mac but commonly installed on Windows when connecting a usb cable
jpmPackage manager- Visual Studio Build Tools for Windows
- or
build-essentialtools for Linux
Instructions for building jpm and Janet on Windows can be found on the Janet Docs page.
libMPSSE can be installed via jpm in a Windows Native Tools Command Prompt:
jpm install https://github.com/strangepete/janet-libMPSSE.gitor built manually:
jpm build
jpm test
jpm installEnable debug with set "INFRA_DEBUG=1" or, optionally set INFRA_DEBUG_LEVEL=7 to a range of 0-7, with 7 being the most verbose. The ASan DLL needs to be found in PATH, or Janet will return a generic "The Specified Module Cannot Be Found." This path should be setup by using the Developer Console.
The underlying d2xx library uses libusb and requires kernel level access to the device, which means any use of the library, including
jpm testneeds to be run withsudoor as root. There are work-arounds but they are beyond the scope of this document.
Build with jpm as shown above, then install the D2XX linux driver as root or using sudo:
# FOLLOW THE README
cp libftd2xx.* /usr/local/lib
chmod 0755 /usr/local/lib/libftd2xx.*
ln -sf /usr/local/lib/libftd2xx.so.1.4.33 /usr/local/lib/libftd2xx.so
cp ftd2xx.h /usr/local/include
cp WinTypes.h /usr/local/include
ldconfig -vOn many distributions, an ftdi_sio module is enabled (responsible for creating a serial device) but prevents d2xx use and must be disabled:
# Check if enabled
sudo lsmod | grep ftdi_sio
# Unload temporarily
# The readme demonstrates alternate options to disable permanently
sudo rmmod ftdi_sio
sudo rmmod usbserial- libMPSSE can only operate as an I2C/SPI bus master. Many GPS devices also talk as master, and as such cannot be used to get nema messages :(
- JTAG is no longer planned, the library is no longer developed by FTDI.
- On linux, libftdi is not d2xx; I think it would be worth targeting next, being open source and easily cross-platform.
- LibMPSSE reports misleading
invalid index 0 (valid range: 0 to 4294967295)when no channels found - Underlying libusb or USB device presence/permission issues may show as functions returning
:other-error - Rapid hot-plugging can result in an
:insufficient-resourceserror, and possible communications issues with SPI. MPSSE is not properly reset, in addition to uninitialized memory use in ftd2xx channel list.
- C232HM-EDHSL 5v cable