Hexabitz Modular Electronics

Nature-mimicking electronic prototyping that's modular, hardy, and 3-dimensional

Jun 01, 2018

Ultimate Control

I will talk in this update about one of my favorite features so far in the BOS (Bitz Operating System) or the backend firmware in Hexabitz arrays.

Control freaks will find the level of control offered by BOS very valuable! In short, you will be able to remotely access or manipulate any memory location in any module (MCU) in the array. Basically, the BOS provides you with APIs and Messages to perform read and write operations on a memory location (SRAM or FLASH) and then you can implement these APIs/Messages on any module and target remote modules in your array. This is really useful for the following scenarios, among others:

  1. You want to synchronize different module types on the same

signal. Then you can read a button/switch input and use that to toggle an enable variable defined in an LED module and a speaker module at the same time. 2. You want different modules to share the same data. For example, a temperature sensor module has an internal temperature variable. You want a relay module to read that variable and turn a heater on/off. At the same time, you want a DC motor driver to read the same variable and turn a fan on/off and an RGB LED to continuously show you the temperature as color variations. 3. You want to distribute math calculations on multiple modules and share intermediate and final results. 4. You want multiple modules to access a constant value stored in the MCU FLASH of another module. MCU FLASH is used to emulate EEPROM in Hexabitz modules (more about this later). This means you can remotely access all settings and non-volatile configurations in an MCU and use this information to trigger other actions. 5. Right now, this only applies to SRAM and FLASH variables, but later we will also add the address space of periperal registers. Although a bit dangerous, you will literally be able to control the internal behavior of an MCU from another module (e.g., read an ADC value or trigger a timer). 6. Lots more possibilities! Share with us what you have in mind.

Implementation Details

There are two methods of addressing a remote memory location: using the absolute address or a BOS variable. BOS variables have virtual addresses 1 to N and are easier to share across the array. Let’s say you want to access an SRAM variable in another module. It’s very combersome to find out the SRAM memory location of that variable but if you link it to BOS variable 1, then any module in the array can read/write BOS variable 1 and access that SRAM variable.

When you write to a remote variable, you can choose the variable type you want this value to be cast to. When you read a remote variable, the API returns the type of that variable as well. The variable type can be: UINT8, INT8, UINT16, INT16, UINT32, INT32, FLOAT, or BOOL.

Here are some examples of the remote read API:

volatile float myremotevar = 0;
/* Reading remote address 0x2000001c from Module 2 with FLOAT format and 1000ms timeout' */
myremotevar = *(float *)ReadRemoteMemory(2, 0x2000001c, FMT_FLOAT, 1000);

volatile bool mybool;
varFormat_t format1;
/* Reading remote BOS variable 1 from Module 2 with 100ms timeout. Remote format is requested and stored in format1. It can be used to cast the variable properly in case we don't know the format beforehand */
mybool = *(bool *)ReadRemoteVar(2, 1, &format1, 100);

And the remote write API:

volatile bool mybool = true;
/* Writing the value of mybool to remote BOS variable 1 in Module 2 with a BOOL format and 0 timeout, i.e., skipping confirmation */
WriteRemote(2, (uint32_t) &mybool, 1, FMT_BOOL, 0);

volatile uint32_t mynum = 0x12ABCDEF;
/* Writing the value of mynum to remote address 0x08016000 in Module 2 with UINT32 format and 100 timeout */
WriteRemote(2, (uint32_t) &mynum, 0x08016000, FMT_UINT32, 100);

Check out this article for more implementation details.


The LED example shown in the video below demonstrates the implementation of a remote write API. We have five RGB LED modules (H01R00) and five momentary push buttons, each connected to a module. We’re only using four buttons in this example. More about building this array here. Button 1 (connected to Module 1) is used as an on/off switch for all LEDs. Button 2 is used to cycle through basic colors (WHITE, RED, BLUE, YELLOW, CYAN, MAGENTA, GREEN). Button 4 is used to increase intensity and Button 5 to decrease intensity (each click is 10%).

All modules define three BOS variables: A bool describing the LED status and two UINT8 describing intensity and color. They are initialized to ON, 50(%) and WHITE, respectively.

The main.c source code is here. Most of the code is inside the FrontEndTask. It looks lengthy, but it’s actually really simple! First of all, the global variables are linked to BOS variables so we can use addresses 1, 2 and 3 to address them across the array. Then, all four buttons are defined and a click event is enabled. Inside the click event callback, each module performs its task locally (e.g., cycling through colors) then broadcasts a RemoteWrite to the appropriate BOS variable. The indicator LED is also blinked to show the click action. Inside the infinite loop, a setColor API is used to control the local LED based on the value of BOS variables shared across the array. This example shows how to use RemoteWrite to control basically everything in the array. Of course, things are a bit buggy as seen in the video, but the overall concept works really well and we’re working on fixes and optimizations. Think about all the potential use cases!

Subscribe to the Crowd Supply newsletter, highlighting the latest creators and projects