The C/C++ bindings for microcontrollers allow you to control Bricks and Bricklets with a C/C++ programm running on a microcontroller. The ZIP file for the bindings contains:
source/bindings
the source code of the bindingssource/hal_*
the source code of HALs for common platforms.examples/
the examples for every supported Brick and BrickletThe C/C++ bindings for microcontrollers support Co-processor Bricklets (i.e. those with a 7-pole connector), as well as the HAT Brick and HAT Zero Brick. The older 10-pole Bricklets and other Bricks are not supported. See here for a complete list of supported devices.
As host (i.e. the device running your C/C++ program that uses the bindings), you can currently use the ESP32 Brick and ESP32 Ethernet Brick. Support for other hosts will be added in the future.
The bindings require a hardware abstraction layer (HAL). See here for details.
Because there is no precompiled library for the bindings there is nothing to install as such. The recommended way of using the bindings is to include their bindings and your preferred HAL directly into your C/C++ project.
The examples for each supported Brick and Bricklet are not self-contained, as they depend on the host hardware (and its HAL) you want to use. Many HALs contain an example driver that can run any example. See the specific HAL documentation for examples.
All device *_create
functions take a uid_or_port_name
parameter allowing
the program to specify which device to communicate with. This can be done in three
ways:
NULL
selects the first unused device with matching type, regardless of UID or port name.In this case unused means the device is not attached to a device object. For example,
there are two Temperature Bricklet 2.0, one connected to port A and one to port B.
With passing NULL
the first tf_temperature_v2_create
call picks the one on
port A, the second call picks the one on port B, because the one on port A is in use already.
The C/C++ bindings for microcontrollers work somewhat different to the other available bindings. While other bindings, that communicate to a Brick Daemon over TCP/IP, require a IP connection, the C/C++ bindings for microcontrollers require usage of a hardware abstraction layer (HAL). The HAL is an abstraction over the platform specific way to communicate over SPI.
The bindings already contain HALs for the following platforms. For other platforms, a custom HAL must be implemented (see below).
If you want to use the bindings on another platform, you have to implement a custom HAL. This guide shows how.
Callbacks in the C/C++ bindings for microcontrollers work differently than
those in the other bindings. As there is no multi-threading on many of the
target platforms, there is no automatic polling for callbacks. Instead, if
you want to receive callbacks, you have to poll for them yourself with the
tf_hal_callback_tick
available in every HAL. This function will poll any
device with a registered callback handler for new packets.
Callbacks are not dispatched by another thread, but instead while
executing a getter, setter or the tf_hal_callback_tick
function.
Because of this, callback handlers will run while the internal state
machines of the bindings are in states, that do not support sending other
packets. Because of this,
calling getters, setters or tick functions inside a callback handler is not allowed.
As the primary target for these bindings are microcontrollers,
the bindings are not thread safe. Some HALs support cooperative
multi-tasking, however no calls to the bindings API are allowed when
they have yielded. All functions will return TF_E_LOCKED
if called inside a callback handler or while the bindings are yielded.
To get the best performance out of the bindings, you can follow this list of optimizations:
tf_hal_callback_tick
, instead use your own scheduling to poll
with the specific tf_[device]_callback_tick
functions. This allows spending
more time on other tasks instead of polling the devices all the time.
tf_hal_callback_tick
uses a round-robin scheduler to poll
all devices with a registered callback handler.To fit a firmware using the bindings onto smaller platforms, such
as the Arduino Uno, you can change the following configuration options
in bindings/config.h
:
TF_INVENTORY_SIZE
:
This is the size of the inventory i.e. the mapping from
UIDs to the ports under which they are reachable.
If you know exactly how many devices you want to communicate with,
set the inventory size to this number. Note that the HAL initialization
will return TF_E_TOO_MANY_DEVICES
if the inventory size is too small.TF_IMPLEMENT_CALLBACKS
:
If you don't want to use callbacks, remove this define to remove the
callback implementation.TF_LOG_LEVEL
:
Reducing the log level will remove string constants at compile time.
Valid values areTF_LOG_LEVEL_NONE
: Disables the logging completelyTF_LOG_LEVEL_ERROR
: Logs only some HAL specific errors if they occur.TF_LOG_LEVEL_INFO
: Additionally logs the initial list of detected devices (default)TF_LOG_LEVEL_DEBUG
: Additionally logs all internal state changes in the SPITFP state machineTF_IMPLEMENT_STRERROR
:
If you remove this define, the tf_hal_strerror function will not be implemented. This saves about
500 bytes of flash or RAM, depending on the HAL.Links to the API reference for the HALs, Bricks and Bricklets as well as the examples from the ZIP file of the bindings are listed in the following table. Further project descriptions can be found in the Kits section.