# TinyGo drivers: a device library for sensors, displays and actuators

> tinygo.org/x/drivers is a BSD 3-clause licensed collection of more than a hundred and forty-five hardware drivers for TinyGo, covering sensors, displays, wireless adaptors and actuators over I2C, SPI, GPIO, ADC and UART. The judgement is that the value is in the breadth and the uniformity of the API, and that the pinning of the example code to a specific board is the one step every user has to do themselves.

**tinygo-org/drivers** — TinyGo drivers for sensors, displays, wireless adaptors, and other devices that use I2C, SPI, GPIO, ADC, and UART interfaces.

- Repository: https://github.com/tinygo-org/drivers
- Website: https://tinygo.org
- Stars: 757 · Forks: 257
- Language: Go
- License: BSD-3-Clause
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/tinygo-org-drivers

## One package holding a hundred and forty-five device drivers

tinygo.org/x/drivers is a collection of over 145 different hardware drivers for devices such as sensors, displays, wireless adaptors and actuators, usable together with TinyGo.

That number is the main argument for the package. A driver for an accelerometer or an e-paper display is not interesting work, and there is a lot of it. Collecting it into one module means the pin handling, the register protocol and the scaling arithmetic are written once per part, and the person using it gets to write the part of the code that is actually about their product.

The complete list is published separately, on the TinyGo device reference page, and the readme points there rather than trying to reproduce a list of that size. The topics on the repository give a flavour of the range, with familiar part names such as the ADXL345 and MMA8653 accelerometers, the MPU6050, the BMP180, BMP280 and BMP388 pressure sensors, the BME280, the DS3231 real time clock, the AHT20 and DHT temperature sensors, the WS2812 and APA102 addressable LEDs, the SSD1306 style displays, the FT6336 touch controller, the ESP8266 radio and the LoRaWAN parts.

The licence is the BSD 3-clause, and the readme notes that this is the same licence the Go project itself uses, which makes the code easy to move in and out of other Go code without a licence negotiation.

## The barometer example shows the shape of every driver

The readme shows a complete program using the BMP180 digital barometer, and it is best read as a description of the API convention rather than as a barometer tutorial.

The program configures the I2C bus on the machine package, creates the sensor with bmp180.New(machine.I2C0), configures it, and then asks the driver whether the part is actually there with sensor.Connected(). That check is the first thing you want on a real board, because a miswired I2C bus and a missing sensor look identical from the firmware's point of view.

The readings then come back in fixed point integers, and the example does the scaling in the program: the temperature is divided by a thousand to get degrees Celsius, and the pressure by a hundred thousand to get hectopascals. Keeping the driver in integer arithmetic is the right choice for a microcontroller, and the consequence is that the caller has to know the scale, which the example shows.

The loop sleeps for two seconds between readings, which is a reminder that these drivers do not schedule anything for you, the firmware is the scheduler. The example is written so that it should work on any board that supports I2C, which is the portability promise of the package in one sentence.

## The pin constants are the part you have to change

The examples that use GPIO or SPI come with a warning that is more useful than it first appears.

The readme says that if you compile these examples directly you are likely to need to make minor changes to the defined variables to map the pins for the board you are using, and it shows the block that has to change:

```golang
var (
        spi   = machine.SPI0
        csPin = machine.D5
)
```

Then it gives the version for a Raspberry Pi Pico with typical wiring, where the chip select pin becomes machine.GP17 rather than machine.D5, and it makes the point that this is not obvious: you need to change the definitions to match how you wired your specific board.

The reason is in the naming. The constants are defined for each supported microcontroller, so the same driver source is shared across boards with completely different pin naming schemes, and the driver layer has no way of knowing which pins you actually connected. The cost of that portability is one small edit per board, and the benefit is that the driver code itself is never forked per target.

It is a design choice that deserves understanding, because it is the difference between a driver library and a board support package, and it is why the examples are provided as starting points rather than as finished programs.

## The directory listing is the catalogue, and some entries are unusual

Because the package is a directory per device, the repository tree is a catalogue you can read in one pass, and the shape of it says something about the scope.

Alongside the sensors and displays there are directories for actuators and other peripherals, a buzzer, a stepper motor driver named easystepper, an ultrasonic sensor named hcsr04, a character display in both parallel and I2C form as hd44780 and hd44780i2c, an LCD controller as ili9341, a GPS module, a hub75 driver for the large LED panels, an encoder directory, and a dotstar panel driver.

Two entries stand out because they are infrastructure rather than a part. There is an i2csoft directory, which is a software implementation of I2C for the boards whose hardware pins are better spent on something else, and there is a cmd directory, which usually holds command line utilities for talking to a device from a normal computer.

At the root of the package there are shared files: drivers.go, i2c.go and displayer.go, which are the common interfaces and helpers that let a display driver, an I2C driver and the rest of the collection look the same from the outside.

There is also a README-net.md next to the main readme, and the repository carries an AGENTS.md and a CHANGELOG.md. The examples directory mirrors the driver list, with one directory per device, which is what makes the collection navigable for someone who does not yet know which part they want.

## The Makefile tests every driver directory and smokes the whole tree

The build tooling is where the scale of the collection shows up, because testing a hundred and forty-five drivers needs a rule rather than a list.

The Makefile implements a recursive wildcard, the rwildcard function, so that it can find every test file under the tree and reduce the paths to the unique directories that contain tests. Those directories become the test set, minus an exclusion list, which currently holds the image directory and one waveshare-epd subdirectory. The unit-test target then runs go test with the verbose flag against each of those directories.

The format check is separate and simple, a gofmt -l over the whole tree that fails with the list of unformatted files. The default test target runs clean, fmt-check, unit-test and smoke-test in that order.

The smoke test is the interesting one. It runs a Go program, smoketest.go, with a shell script, smoketest.sh, and it takes an XTENSA flag that defaults to 1, which is the flag that says whether the Xtensa architecture is part of the build. The smoke test is how the whole tree is compiled for a microcontroller rather than for the host, and the XTENSA switch is how the same script covers both the Xtensa based and the RISC-V based boards.

Two more targets are useful to know, because they are how the catalogue is kept honest. drivers-count counts the driver directories while excluding the non-driver ones, build, cmd, examples, internal, lora, ndir, netdev, netlink and tester, and it also counts the waveshare-epd subdirectories separately, and drivers-list prints the same set as a sorted list.

## Dependencies reveal what the library is for

The go.mod is small and the dependency list explains the use cases the collection serves.

The module is tinygo.org/x/drivers, it declares Go 1.22.1 with a toolchain line of go1.23.1, and the direct requirements include github.com/tinygo-org/pio at v0.3.0, which is the library for driving a microcontroller's programmable input output blocks, and that is why there are addressable LED and LED matrix drivers in the collection at all, because those parts need precisely timed output that a general purpose peripheral cannot provide.

There is also tinygo.org/x/tinyfont and tinygo.org/x/tinyterm, which are for rendering text and drawing on the small displays, and orsinium-labs/tinymath for the floating point work that some sensor maths needs. The network side is covered by github.com/eclipse/paho.mqtt.golang, which is the MQTT client, and github.com/soypat/natiu-mqtt, a smaller MQTT implementation. github.com/google/shlex is a shell lexer, and it points at the LoRaWAN and other command line tooling in the tree, while frankban/quicktest and google/go-cmp are the test helpers.

The release history is regular. Version 0.34.0 was published on 2025-12-15, 0.35.0 on 2026-04-21 and 0.36.0 on 2026-09-01, with the default branch named dev and the last push on 2026-10-19.

The open source project also asks for financial contributions through OpenCollective, which is the normal arrangement for a project that depends on donations rather than on a company behind it.

## Conclusion

TinyGo drivers fits a maker or an engineer who has a sensor in hand and wants it working in a TinyGo firmware today, because the package covers the popular sensor and display parts with a consistent API and ships an example per driver, so the wiring and the register handling are already written down. It is the wrong choice if you need guarantees about a part that is not in the list, since the collection is broad but finite and a missing driver is your problem. It is also the wrong choice if you want the same code to run on every board, because the pin constants are per microcontroller and the readme is explicit that you have to change them. Before you start, read the device reference page for the complete list rather than the directory listing, pick the driver, and then copy the example and adjust the pin definitions for your own wiring.

## FAQ

### What is tinygo.org/x/drivers?

It is a collection of over 145 hardware drivers for devices such as sensors, displays, wireless adaptors and actuators, usable with TinyGo over I2C, SPI, GPIO, ADC and UART. The complete list is published on the TinyGo device reference page.

### How do I add a TinyGo driver to my project?

Run go get tinygo.org/x/drivers, then import the package for your part, for example tinygo.org/x/drivers/bmp180, configure the bus with machine.I2C0.Configure(machine.I2CConfig{}), create the sensor and call Configure on it.

### Why do I have to change the pin definitions in the examples?

The pin constants are defined per supported microcontroller, and the same driver source is shared across boards, so you have to map the variables to how you actually wired your board. The readme notes this is not obvious, and gives the Raspberry Pi Pico case as the example.

### How are the drivers tested?

The Makefile finds every directory containing a test file and runs go test against each, with an exclusion list, and it also runs a smoke test through smoketest.go and smoketest.sh with an XTENSA flag. The default test target runs clean, fmt-check, unit-test and smoke-test.

## Sources

- [License: BSD-3-Clause](https://github.com/tinygo-org/drivers/blob/dev/LICENSE)
- [Project website](https://tinygo.org)
- [README](https://github.com/tinygo-org/drivers/blob/dev/README.md)
- [Releases](https://github.com/tinygo-org/drivers/releases)
- [tinygo-org/drivers on GitHub](https://github.com/tinygo-org/drivers)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/tinygo-org-drivers
