Rust: Running a TLC5940 with an ESP32 using the RMT peripheral

The TLC5940 is a "16-channel LED driver w/EEprom dot correction & grayscale PWM control" IC, used for driving up to 16 constant current outputs (typically LEDs) using a number of control lines. It's more complex to drive than the TLC5947 which uses a simple I2C interface, but leaves more control to the application developer by letting them set the LED PWM frequency, among other things.

The TLC5940 uses SPI to transfer brightness data, but also requires an external PWM clock, as well as a periodic pulse on the BLANK pin to ensure the outputs remain enabled. This is annoying to do in software, but by abusing the RMT peripheral in an ESP32, we can let the microcontroller hardware do all of the heavy lifting for us.

Continue Reading

EtherCrab 0.4: Distributed Clocks, io_uring, Derives, Oh My

EtherCrab 0.4.0 (lib.rs), the pure Rust EtherCAT MainDevice is out! I've added a lot of features and fixes to this release, including Distributed Clocks support, an io_uring-based network driver for better performance, and a brand new set of derive-able traits to make getting data into and out of your EtherCAT network easier than ever! The full changelog including breaking changes can be found here, but for the rest of this article let's dig a little deeper into some of the headline features.

Continue Reading

Controlling an Electriq iQool AC with ESPHome and Home Assistant

I recently got a pretty neat all-in-one air conditioner to heat my frigid Scottish garage in the winter. CNC machines don't like the cold, and neither do I! My unit is an "electriQ iQool 12000 BTU Wall Mounted Air Conditioner with Heating Function", product code IQOOL-SMART15HP. I quite like it, but when I got it I really wanted to be able to shout at Siri to turn the garage heat on so it'd be warmer by the time I went out. And I succeeded in this mission! By flashing ESPHome to the integrated Tuya TYJW2S-5V-YA module, I can now control this AC perfectly from Home Assistant and, by extension, Apple's Home app.

Continue Reading

A study of Rust micro-optimisations

In working on ethercrab I found myself down the rabbit hole of trying to reduce binary size, in this case for the thumbv7m-none-eabi architecture used in embedded. This post is a collection of examples of attempted code size reductions by refactoring sometimes the most tiny of fu…

Continue Reading

Announcing EtherCrab: The 100% Rust EtherCAT controller

The EtherCrab story started with my dream of writing a motion controller in Rust to provide a modern alternative to the venerable LinuxCNC project. But motion controllers are hard, even with the right books, so I did what any good programmer would do: procrastinate by implementing an entire industrial fieldbus protocol instead! Say hello to EtherCrab - a pure Rust EtherCAT controller that supports Linux, macOS, Windows and even no_std.

Heads up! EtherCrab 0.4.0 was released in March 2024 with some breaking changes. Why not head over to the announcement post to see what's new?

Continue Reading

A const builder pattern in Rust

During the creation of EtherCrab, a pure-Rust EtherCAT master, one of the core structs in the crate started growing quite a few const generic parameters. Here's a reduced example of what I'm talking about:

struct Client<const N: usize, const D: usize, const TIMEOUT: u64> {
    foo: [u8; N],
    bar: [u8; D],
    idx: u8
}

Continue Reading

Optimising Rust: Clockwise Triangles

Welcome to another pointless tangent into the exciting world of line joints in embedded-graphics! embedded-graphics is an integer only, iterator based no-std graphics library for environments with low resource availability. This time, we'll be looking at some not-so-great optimisations made to a point sorting function.

Update: A kind Twitter user pointed out a more optimised solution for triangles which you can find here.

Continue Reading

Integer Graphics: Line Intersection

Graphics can be a tricky topic, particularly when attempting to find anything on the internet these days that provides solution in terms of integer-only maths. embedded-graphics is a (mostly) integer-only library, so in pursuing a solution to good line joints for the Polyline and Polygon shape implementations, a bit of interweb detective work was required.

Continue Reading

Embedded graphics 0.5.0

Version 0.5.0 is released! This is a pretty big one, focussed around ergonomics. There are new macros to make drawing and positioning primitives and text much less noisy, as well as changes to the Drawing trait to remove the explicit .into_iter() call when passing objects to it.

Continue Reading

XML sitemaps in React with Typescript

I maintain the Repositive website which uses React for the frontend and a server that supports server side rendering for the speed and SEO benefits of SSR. I'm currently in the process of porting it over to Typescript which is kickass, but the type checker kept borking on the XML tags used in the sitemap component. What follows is a quick "note to self" on how to fix that error. There might be much better solutions out there, but this is the one that worked for me.

Continue Reading

Embedded Graphics 0.4.7 and TinyBMP 0.1.0

Embedded graphics 0.4.7 has been released, along with a new sister crate, tinybmp! TinyBMP aims to parse BMP-format image data using no dynamic allocations. It targets embedded environments but can be used in any place a small BMP parser is required. Thanks to TinyBMP, Embedded Graphics now supports loading this simple image format. The header photo was made using Embedded Graphics and the SSD1331 driver in pure Rust. In this post, I'll talk through how the BMP file is parsed in no_std environments with nom and how to get BMP images working with embedded_graphics.

Continue Reading

Cross compiling Rust from Linux to macOS

I've recently been working on a Rust project at work which requires compiling for Linux (GNU), Linux (musl - for Alpine Linux) and macOS. I use Linux Mint nearly all the time, so building for macOS targets has required asking very nicely to borrow a spare Macbook Air. This is naturally a bit crap, so I set out to find a Linux-only solution to cross compile for macOS using osxcross. A weekend of pain later, and I have the following post. Hopefully it spares you a weekend of your own pain.

Continue Reading

Optimising out calls to new()

Rust (and LLVM) are really good at optimising things.

I have a struct, TrajectoryStep, that I pass to some methods in my program. I don't want to use positional arguments as it's impossible to tell what some_func(f32, f32, f32) might actually require. It looks like this:

Continue Reading

Default arguments for cooler testing

In my other post about creating properly typechecked helper functions in Typescript, I missed something out from the examples that's present in the real code: default parameters! There's a function, createEvent, that returns an object with a dynamically generated UUID value in it. It also includes the current timestamp. This is great from the programmer's point of view as there's no need to wire up these values manually, but it sucks for unit tests because the values always change! The solution is to use default parameters to keep the ergonomics of a clean public API, but still support unit testing and special cases gracefully.

Continue Reading

Typechecking builder functions in Typescript

I've been working on toasting a lot of our tech debt at Repositive recently. We use an event driven microservice architecture which has various benefits, but some drawbacks concerning what data is sent where due in part to the liberal use of any in our Typescript codebases. During my refactoring rampage, I encountered some places where event objects were missing fields or otherwise weren't being generated properly. To this end, I set out to create a type-checked solution to this problem.

Continue Reading

Setting the GDB safe-path cross platform

I've been developing an embedded Rust app (yay!) on Windows (blegh) recently. The Rust team have put incredible effort into making Rust itself work great in Windows environments, but the tooling around it can be difficult to get working correctly. My current problem was making GDB load a .gdbinit file from the current projecting when doing xargo run. Here's how I fixed it in .cargo/config:

Continue Reading

Elm: counting groups of items in a list

So. Elm. It's been an interesting experience for me, coming from a procedural language (JS) background. The learning curve is steep, but the functional nature of Elm, along with its compile time type safety really pays off. One of the (few!) problems I've found as a newcomer however, is that the documentation can be really frustrating sometimes. In this post, I hope to remedy that slightly by providing a newcomer's perspective on a little bit of data processing in Elm.

Continue Reading

Cloning private Github repos in Rust

Cloning a private Github repo using SSH auth in Rust has proved to be a pretty gnarly problem (for my anyway), so I thought I'd share this quick tutorial to help anyone else out that might be struggling with the same issue. I'm using git2-rs which has good interface documentation, but very few pieces of example code, so I set out to fix that somewhat with this post.

Continue Reading

Logging analytics events in a testable way with React and Redux

One of my main responsibilites at TotallyMoney was to take care of the in-house analytics/event logging framework. Like lots of companies, understanding what users do and how they interact with a product is to get good insight on. In this regard, people reinvent the logging wheel with various krimskrams attached, me being no exception. What I want to show in this post is how to integrate an event logging framework into a React/Redux application in a way that's scaleable and testable. Unit testable logging is important when the rest of the business relies heavily on the events and the data in them like many companies do.

Continue Reading

Scraping without a scraper

In between watching the rain and emptying all the shmoo out of my air compressor (long overdue), I decided to try my hand at some impromptu scraping this weekend. Matters were complicated somewhat due to me not owning a scraping tool, but I worked with what I have to make what I think are some satisfctory results. This post will be a short log of what went down and will hopefully demonstrate that one can achieve reasonably good (i.e. flat) results without having a real scraper.

Continue Reading

Parsing Logentries output safely using Rust

I'm fascinated by Rust for it's safety and speed, but also because it's simple to write low level code in what feels like a high level language. To that end, I've been working on a small Rust project at TotallyMoney.com (where I work) for the last week or so to see if it's viable for production use. It's a simple service that polls a Logentries endpoint for JSON, parses it and saves some values in a Postgres database. It's not a very complicated task, but I saw this as a good opportunity to try Rust in a production-ish role.

Continue Reading

G&G P90 hicap mag feeding fix(ish)

Disclaimer: This is an article for an airsoft gun only. None of this pertains to real firearms.

I have a G&G P90 (in tan, in case you were wondering) and like many others suffer from the hicap mags failing to feed. Half filling them kind of works, but the feed mechanism always seems to jam. I've got a half solution here in this article. It doesn't completely fix the problem, but my hicaps feed a lot more reliably now, particularly in semi-auto, than they did before.

Continue Reading

Spindle speed control using LinuxCNC 2.7 with a Huanyang inverter

Huanyang branded VFD drives are ubiquitous on eBay and other sites like AliExpress. I bought one some time ago with a 1.5KW spindle and have been controlling the speed manually with the difficult to use control panel on the front. It is, however, possible to control the VFD from within LinuxCNC using the M3 and M5 commands (I haven't been able to get M4, reverse rotation, working yet). What's also neat is we can get the machine to wait for the spindle to come up to speed before moving to the next line of GCode.

Continue Reading