When building IoT applications for a simple application space, it pays to build on top of already working systems. That’s the case for the hardware we’re showing today, the Aludel Lute Relay.
This design started as an experiment for a new form factor to plug into our Aludel Elixir Board. The unit has 4 relays capable of switching 20 amps AC or DC. This unit could be useful in remote physical access (i.e. locks), lighting control, or the application that inspired this design: smart lockers. Let’s dive into how this is built and how someone could use this latest Golioth Solutions Marketplace design to build a business.
New form factor
The Aludel platform generally assumes that you will have a somewhat tall case that can fit two different Mikroelektronika Click Boards into the case and then cover it with our Open Source board called the Aludel Ostentus. The Aludel Elixir is the main processing board and contains an nRF9160 primary processor and cellular modem and an ESP32-C3 secondary modem for Wi-Fi and Bluetooth.
If I wanted to build custom hardware to work with the Elixir board, I would probably need to make a Click board of my own. But that is somewhat space constrained. Instead, I decided to take the idea of using a PCB as a cover for this form factor (as is the case for the Ostentus) and instead put the customized components on this new ‘front panel’. The result is the Lute form factor, which can be extended beyond the current implementation. Relays are a great proving ground for large industrial-style components that can control large industrial sized machines.
Control Power from Anywhere
This hardware is a great fit for applications where you want to remotely control power. The 4 relays on board and the large 5.08 mm pitch terminal blocks means you can safely pass high currents through the board. The traces on the relay are configured for creepage and clearance required for 240V. The relays being used are marked for 120V, but the datasheet says they are capable of 240V.
This application draws on my own experience building a simple smart locker using Golioth. I built it using an nRF9160-based dev board and then point-to-point wired a bunch of off-the-shelf power controls. It worked great, as the control requirements are low: nothing more than a GPIO is required for output. However, from a manufacturing capability and scaling to a larger fleet of devices, the wiring would have been a horrendous experience. The Lute Relay board codifies the ability to switch power and enables it in a much more compact package. In my case, I was passing 12V through the relays to a set of LED lamps inside the locker and to the solenoid controlling the door latch.
The relays truly are the easy part. The important piece in the system starts from the GPIO (controlling the relays) and goes all the way back to the cloud. The firmware is built on top of Golioth’s Reference Design Template. We trigger the various GPIOs within app_settings.c, which is triggered from the Golioth Settings Service. When we change the relay setting on the console, it gets pushed out from the Golioth service down to the device over CoAP, and then the Golioth Firmware SDK translates the packet and triggers the proper GPIO.
Made for extensibility, not durability
The Lute Form factor, like most of the devices in the Solutions Marketplace, is a starting point, not an off-the-shelf product. We intend for you to take these devices to prove an idea and then modify them for the specifics of your business. You can hire Golioth Solutions Services to help you with that, tap one of our wonderful Design Partners, or take on the task yourself.
What about future Lute boards? Well, the testing of this board has created a great starting point for future designs and applications. If you have one in mind, get in touch via our forum and let us know what you’d like to see us build next.
If you ask any seasoned hardware engineer, they will tell you there are only two types of people:
Those who have accidentally swapped TX and RX
And those who will…
There’s even a fail badge of honor!
Despite our best efforts, mistakes can creep into hardware designs. Design specifications can change over time. Taking a hardware design from concept to production is a journey that nearly always involves iterating through multiple revisions of the PCB assembly.
In this post, we’ll walk through some of the tools that Zephyr & Golioth provide for managing multiple board revisions.
Let’s dive in and look at how you can support Rev A, Rev B, all the way to Rev X in your Zephyr firmware without losing your sanity!
The image above shows the 2nd hardware revision of the board (Rev B), which fixes some of the hardware issues we found when testing the 1st revision (Rev A).
Supporting the Rev B hardware requires changes to the Zephyr firmware that runs on the internal MCU in the nRF9160 SIP. However, since we have Rev A and Rev B hardware “in the wild”, we want to support building firmware for all current and future board revisions in Golioth projects—like our Reference Design Template.
Before jumping into the implementation details, it’s helpful to see how an end-user would build for a specific board revision.
We can build a Golioth Zephyr app for a specific revision of the Aludel Elixir board by simply appending a @<revision> specifier to the board name:
# Build firmware for Rev A
west build -b aludel_elixir_ns@A
# Build firmware for Rev B
west build -b aludel_elixir_ns@B
# Build firmware for the "default" revision (which is currently Rev B)
west build -b aludel_elixir_ns
Here’s the revision.cmake file for the aludel_elixir board:
board_check_revision(
FORMAT LETTER
EXACT
DEFAULT_REVISION B
VALID_REVISIONS A B
)
FORMAT LETTER tells the build system that the revision format is “Letter revision matching” (A, B, C, etc)
EXACT requires that the revision is an exact match
DEFAULT_REVISION sets the revision to be used when no revision is specified (e.g. west build -b aludel_elixir_ns)
VALID_REVISIONS defines the set of valid revisions that can be specified
Kconfig settings for specific revisions
It’s possible to specify Kconfig symbols that are specific to a particular board revision by adding optional <board>_<revision>.conf files in the board directory. These will be merged into the board’s default Kconfig configuration.
It’s also possible to describe hardware changes in devicetree that are specific to a particular board revision by adding optional <board>_<revision>.overlay files in the board directory. These will be added to the common <board>.dts devicetree file.
The golioth-zephyr-boards repo stores the Zephyr board definitions for the Aludel Elixir board revisions, allowing us to use them across multiple Zephyr projects as a Zephyr Module.
For example, here’s how it’s included in our Reference Design Template app via the west.yml manifest:
In a real-world IoT deployment, it’s likely that a fleet of devices will have multiple hardware revisions deployed simultaneously. Golioth provides support for managing different hardware revisions through a concept called “Blueprints“.
Blueprints are a flexible way to segment devices based on variations in hardware characteristics, such as the board revision. For example, when creating a new over-the-air (OTA) firmware release in the Golioth console, a blueprint can be specified to limit the scope of the release to only Rev A hardware devices.
If you’d like a step-by-step introduction to deploying a fleet of IoT devices with Zephyr and Golioth, we’d love to have you join us for a free Zephyr developer training. Our next session is just two weeks away. Sign up now!
The Hackaday Superconference returned for the second post-lockdown year. This was actually the seventh “Supercon” and Dan and Mike were on hand to represent Golioth. As badge-hacking is a large part of the social scene at the conference, we spent a fair amount of time getting data from the non-connected badge up to the cloud. What started out as a test-equipment related project ended up as a community art project.
Conference Admission with a Decades-Old Bench Tool
If you read the Golioth blog, chances are you already know about Supercon. But if not, it’s a conference aimed at people building and working with electronic hardware. Fittingly, instead of a printed plastic rectangle on a lanyard, the Supercon badge is itself an electronic device. This year it was modelled after a Vectorscope; a type of oscilloscope that plots two voltage signals along X and Y axes, instead of plotting a signal in the time domain.
Hackaday Supercon badge displaying the Golioth logo
We had high ambitions for our badge hack. The original plan was to cache the captured voltages being measured by the badge’s ADCs and send them up to the cloud so they could be replayed later. This was a pretty interesting idea, since every badge has a set of inputs and outputs. We could run custom code on the inputs of our badge and capture data from the unaltered badges of people we ran into. We could potentially catch the vector source by using jumper wires to their output pins.
Alas, the badge creators did a great job of squeezing impressive performance out of the RP2040-based hardware. A tight chain of DMA and PIO (programmable input-output) kept the pipeline of samples out of the processor. We were able to capture some lossy data, and we think we could have tapped into a data stream on the order of 50 ksps, but then RAM becomes an issue to cache that kind of throughput. This meant our original plan was not to be.
Luckily, Dan noticed that a “sketch” app was included on the badge. A static image is simpler to offload to the cloud and render on a gallery page. We had some of the Golioth Aludel-mini hardware with us that uses an nRF9160 cellular modem. So we set off to make it happen.
Badgecase: the Badge Showcase
The impatient reader can head over to Badgecase.io and see the results of our badge hacking. All of the art on that page was entered on a conference badge and uploaded over cellular.
The Gist of the Hack
The stock badges run Micropython. We compiled a custom version so that we could implement i2c peripheral mode on the badge using the RP2040 hardware peripheral. This makes it look like a sensor; Golioth is great at harvesting sensor data and sending it to the cloud. We grab the image data (ignoring all white background pixels), sliced it up into i2c packets, then combined those into CBOR packets and upload them to LightDB Stream.
This is where the cloud side of things takes over. A frontend written in Rust uses a Websocket listener to react to incoming packets. It queries the Golioth cloud for the unique ID of each image, collects all of the blocks that shared the same UID, and reassembles them into PNG files. To add a maker’s mark, a Golioth remote procedure call (RPC) was used just prior to upload to add a title/name to each piece of artwork. All is hosted on a dynamic page which we will convert to a static entry for posterity. However, we had enough fun with this that we may do more of these shenanigans using different subdomains in the future, so watch this space.
The Firmware
Alterations to the actual Micropython apps running on the badge were minimal, the majority of the work came in the i2c peripheral functions as they chopped up data into packets and handled incoming requests from the i2c controller.
def encode_point_for_upload(x, y, color):
x_high = (x << 10) & 0b1111110000000000
y_mid = (y << 4) & 0b0000001111110000
coord = x_high | y_mid
if color == gc9a01.RED:
coord |= 1
elif color == gc9a01.GREEN:
coord |= 2
elif color == gc9a01.BLUE:
coord |= 3
elif color == gc9a01.BLACK:
coord |= 4
else:
coord |= 0
print(coord >> 8, coord & 0x00FF)
return (coord & 0x00FF, coord >> 8)
def menu(key): # exit and return to menu
ostentus_i2c.fifo_init_samples()
for i,m in enumerate(model):
for j,n in enumerate(m):
if n != gc9a01.WHITE:
print(i,j,n)
coord, col = encode_point_for_upload(i, j, n)
ostentus_i2c.fifo_put_point(coord, col)
ostentus_i2c.fifo_finalize_samples()
while(ostentus_i2c.outgoing_data_available()):
time.sleep(1)
global stopflag
print("menu")
if vos_state.active:
stopflag=True
joy.detach()
btn.detach()
csel.detach()
The highlighted lines above are what was added to the stock Vectorscope sketch app. It works by capturing program flow when the user presses the “menu” button, which signals an exit from the app. The fifo_put_point(coord, col) and related functions are calling C code which was marshalled up to the Micropython layer (more on this in a sec).
The sketch app uses a 40×40 grid with five colors (white, black, red, green, blue). We assume all pixels are white and only upload pixels of a different color. Some run-length encoding could have made things a bit leaner, but a simple approach to bit-packing worked for us.
Most of the firmware work went into the C layer and custom Micropython build. The build itself is… shall we say “bespoke”? (ie. “it’s a hack!”) It was not really in a state to publish to a repo. The custom i2c stuff is an extension of the work we already did on the Golioth Ostentus faceplate. We’ll be publishing that project publicly in a few months, so for now, here’s a Gist of the pertinent code for those who are curious.
For Supercon, the i2c files implement a FIFO, into which data from the Micropython layer may be placed. Two i2c register addresses were added, one indicating data is available, the other will send the data. It forms 36-byte packets, with the first packet containing metadata.
The Software
The Rust backend leveraged Tokio, an asynchronous runtime, and its sibling web server framework, Axum. At startup, a thread was spawned to connect to Golioth over Websockets and listen for new messages. Upon receiving a message, this thread checks whether the data was fragmented by comparing the provided total point count with the number of points in the message. If so, it waits for subsequent messages until all points had been acquired for a given image.
Given the time constraints, we wanted to make the application as lean as possible to simplify connecting to external services when deploying. The information we needed to persist after processing an image included the image itself and the name that had been provided via the previously mentioned RPC. For the image data, a blob storage service was a natural solution.
As a hack around introducing another data store to maintain a list of the images, their links, and their names, we encoded the name and UID into the name of the image file in blob storage bucket. When a request arrives for badgecase.io, the server fetches a list of objects in the buckets, parses the file names to extract the user-chosen image name, and renders an HTML page from a handlebars template using the names and links. Some lightweight server-side caching reduced the overhead of accessing the bucket on every request, and the cache can easily be invalidated upon processing a new image, meaning that new images are displayed in the showcase just moments after submission.
The popular image crate made building the PNG from the encoded 16-bit coordinate points fairly straightforward.
fn build_png(data: Vec<i16>) -> image::ImageBuffer<image::Rgb<u8>, Vec<u8>> {
let mut buffer = image::DynamicImage::new_rgb8(40, 40).to_rgb8();
let mut state = [[PixelColor::White; 40]; 40];
for p in data {
let (x, y, color) = parse_point(p);
state[x as usize][y as usize] = color;
}
for x in 0..40 {
for y in 0..40 {
let pixel = buffer.get_pixel_mut(x, y);
*pixel = image::Rgb(state[x as usize][y as usize].rgb().into());
}
}
imageops::resize(&buffer, 400, 400, imageops::FilterType::Nearest)
}
Parsing the points was essentially the inverse of the operation in the firmware, but Rust’s enum support made working with our custom color scheme much more enjoyable.
Deploying the application involved building an OCI image and pushing it up to Google Artifact Registry, then with a few clicks we had it running on Google Cloud Run. Because we had chosen Google Cloud Storage for storing the images, setting up access from the Cloud Run service was seamless. The last bit was mapping the Cloudflare-managed domain to the service because what is a hack project without a proper catchy domain?
Closing Thoughts
We spent way too much time on this hack… it was so much fun! Although our initial dream of capturing the vector traces didn’t materialize, it was still a blast seeing people make a simple drawing and having it appear almost instantly on the website. It also highlights how much stuff there can be in the process from a cellular device up to Cloud, and how Golioth makes things even easier. We only just got back home and already we can’t wait to see what happens with next year’s badge!
Even people who have been living under a rock for the past couple of years know that there’s a global chip shortage. The correct response from the engineering community should be changes to our design philosophy and that’s the topic of the talk that Chris Gammell and I gave at the 2022 Zephyr Developer Summit back in June. With the right hardware and firmware approach, it’s possible to design truly modular hardware to respond to supply chain woes.
Standardization enabled the industrial revolution, and the electronics field is a direct descendant of those principles. You can rest easy in knowing that myriad parts exist to match your chosen operating voltage and communication scheme. But generally speaking it’s still quite painful to change microcontrollers and other key-components mid-way through product design.
Today’s hardware landscape has uprooted the old ways of doing things. You can’t wait out a 52-week lead time, so plan for the worst and hope for the best. Our talk covers the design philosophies we’ve adopted to make hardware “swapability” possible, while using Zephyr RTOS to manage the firmware side of things.
Meet the Golioth Aludel
Golioth exists to make IoT development straightforward and scalable–that’s not possible if you’re locked into specific hardware, especially these days. So we designed and built a modular platform to showcase this flexibility to our customers.
Called Aludel, Chris Gammell centered the design around a readily available industrial enclosure. The core concept is a PCB base that accepts any microcontroller board that uses the Feather standard. This way, every pin-location and function is standardized. Alongside the Feather you’ll find two headers that use the Click boards standard (PDF), a footprint for expansions boards facilitating i2c, SPI, UART, and more. The base includes Qwiic and Stemma headers for additional sensor connectivity, as well as terminal blocks, room for a battery, and provisions for external power.
The key customization element for Aludel is the faceplate. It’s a circuit board that can deliver a beautiful custom design to match any customer request. But on the inside, each faceplate has the same interface using a flat cable connection to the base board. Current versions of the faceplate feature a a screen, an EEPROM to identify the board, and a port expander that drives buttons, LEDs, and whatever else you need for the hardware UI.
The beauty of this is that electrically, it all just works. Need an nRF52, nRF9160, ESP32, STM32, or RP2040? They all already exist in Feather form factor. Need to change the type of temperature sensor you’re using? Want to add RS485, CANbus, MODBUS, 4-20 ma communication, or some other connectivity protocol? The hardware is ready for it–at most you might need to spin your own adapter board.
Now skeptics may look at the size of this with one abnormally high-arched eyebrow. But remember, this is a proof-of-concept platform. You can set it up for your prototyping, then take the block elements and boil them down into your final design. Prematurely optimizing for space means you will have many many more board runs as the parts change.
When you do a production run and your chip is no longer available, the same concepts will quickly allow you to test replacements and respin your production PCB to accommodate the changes.
Zephyr Alleviates your Firmware Headaches
“But wait!” you cry, “won’t someone think of the firmware?”. Indeed, someone has thought of the firmware. The Linux Foundation shepherds an amazing Real-Time Operating System called Zephyr RTOS that focuses on interoperability across a vast array of processor architectures and families. Even better, it handles the networking stack and has a standardized device model that makes it possible to switch peripherals (ie: sensors) without your C code even noticing.
We use Zephyr to maintain one firmware repository for the Aludel hardware that can be compiled for STM32F40, nRF52840, nRF9160, and ESP32 using your choice of Ethernet, WiFi, or Cellular connections. How is that even possible?
Zephyr uses the DeviceTree standard to map how all of the hardware is connected. A vast amount of work has already been done for you by the manufacturers who maintain drivers for their chips and supply .dts (DeviceTree Syntax) files that specify pin functions and mappings. When writing firmware for your projects you supply DeviceTree overlay files that indicate sensors, buttons, LEDs, and anything else connected to your design. The C code looks up each device to receive all relevant information like device address, GPIO port/pin assignment and function.
The hardware abstraction doesn’t stop there. Zephyr also specifies abstraction for sensors. For instance, an IMU will have an X, Y, and Z output — Zephyr makes accessing these the same even if you have to move to an IMU from a different manufacturer due to parts shortages. You update the overlay files for the new build, and use a configuration file to turn on any specific libraries for the change, but the code you’re maintaining can continue on as if nothing happened.
Of course there are caveats which we cover in the talk. There is no one-size-fits-all in embedded engineering so you will eventually need to define your own .dts files for custom boards, and add peripherals that are unsupported in Zephyr. This is not a deal breaker, there is a template example for adding boards (and I highly recommend watching Jared Wolff’s video on the subject). And since Zephyr is open source, your customizations can be contributed upstream so others may also benefit.
Hardware will never again be the same
Electronics manufacturing will eventually emerge from the current shortages. But there are no signs of this happening soon, and it’s been ongoing for two years. We shouldn’t be trying to return to “normal”, but planning a better future. That’s what Golioth is doing for the Internet of Things. Choosing an IoT management platform shouldn’t require you to commit to one type of hardware. Your fleets should evolve, and our talk outlines how they can evolve. Golioth helps to manage your diverse and growing hardware fleet. Golioth is designed to make it easy to keep track of and control all of that hardware, whether that’s 100 devices or 100,000. Take Golioth for a test drive today.
https://blog.golioth.io/wp-content/uploads/2022/08/golioth-aludel-faceplate.jpg10801920Mike Szczyshttps://blog.golioth.io/wp-content/uploads/2023/09/Golioth_Logo_CoralWhite_RGB-1-320x127.pngMike Szczys2022-08-16 07:37:572022-08-16 08:41:37ZDS: What Chip Shortage? How We Use Zephyr for Truly Modular Hardware