C/C++ für Mikrocontroller - API Bindings

Die C/C++ Bindings ermöglichen es Bricks und Bricklets mit selbst erstellen C/C++ Programmen, die auf einem Mikrocontroller laufen, zu steuern. Die ZIP Datei für die Bindings beinhaltet:

  • in source/bindings den Quelltext der Bindings

  • in source/hal_* den Quelltext der HALs für einige Plattformen

  • in examples/ die Beispiele für alle Bricks und Bricklets

Unterstützte Hardware

Die C/C++ Bindings für Mikrocontroller unterstützen Co-Prozessor-Bricklets, also diese mit einem 7-Pol-Anschluss, sowie das HAT Brick und das HAT Zero Brick. Die älteren Brickets mit 10-Pol-Anschluss, sowie andere Bricks werden nicht unterstützt. Siehe hier für eine vollständige Liste unterstützter Geräte.

Das C/C++-Programm, das die Bindings verwendet läuft auf dem Host. Als Host unterstützt werden aktuelle der ESP32 Brick und der ESP32 Ethernet Brick. In Zukunft werden weitere Mikrocontroller als Host unterstützt werden.

Die Bindings benötigen einen host-spezifischen Hardware Abstraction Layer (HAL). Siehe hier für Details.

Voraussetzungen

  • C-Compiler (C99-kompatibel) oder C++-Compiler

Installation

Da es keine vorkompilierte Bibliothek für die C/C++ Bindings für Mikrocontroller gibt, gibt es in diese Sinne auch nichts zu installieren. Die empfohlene Art und Weise die Bindings zu verwenden, ist ihren Quelltext direkt in das jeweilige C/C++ Projekt mit einzubinden.

Test eines Beispiels

Die Beispiele für jeden unterstützten Brick und Bricklet sind nicht vollständig, da diese von der verwendeten Host-Hardware (und deren HAL) abhängen. Viele HALs beinhalten einen Beispiel-Treiber der jegliches Beispiel ausführen kann. Weitere Details sind in den spezifischen HAL Dokumentationen zu finden.

UID oder Port-Name

Alle Geräte-*_create-Funktionen nehmen ein uid_or_port_name Parameter, das es dem Programm ermöglicht festzulegen mit welchem Gerät kommuniziert werden soll. Dies kann auf drei Weise erfolgen:

  • Bei Übergabe von NULL wird das erste unbenutzte Gerät des entsprechenden Typs ausgewählt unabhängig von UID und Port-Name.

  • Bei Übergabe einer UID (z.B. „XyZ“) wird das erste unbenutzte Gerät des entsprechenden Typs mit passender UID ausgewählt.

  • Bei Übergabe eines Port-Names (z.B. „A“) wird das erste unbenutzte Gerät des entsprechenden Typs mit passendem Port-Namen ausgewählt.

In diesem Fall bedeutet unbenutzt, dass das Gerät keinem Device-Objekt zugeordnet ist. Zum Beispiel sind zwei Temperature Bricklet 2.0 angeschlossen, eins an Port A und eins an Port B. Bei Übergabe von NULL wählt der erste tf_temperature_v2_create Aufruf das Bricklet an Port A aus. Der zweite Aufruf wählt das Bricklet an Port B, da das Bricklet an Port A bereits benutzt wird.

Hardware Abstraction Layer

Die C/C++ Bindings für Mikrocontroller funktionieren anders als die anderen verfügbaren Bindings. Während andere Bindings, die über TCP/IP mit einem Brick Daemon kommunizieren, eine IP Connection verwenden, benötigen die C/C++ Bindings für Mikrocontroller einen Hardware Abstraction Layer (HAL). Der HAL abstrahiert den plattformspezifischen Weg der SPI-Kommunikation.

Die Bindings beinhalten HALs für die folgenden Plattformen. Für andere Plattformen muss ein eigener HAL implementiert werden (siehe unten).

Implementieren eines eigenen HALs

Falls die Bindings auf einer anderen Plattform verwendet werden sollen, muss ein eigener HAL implementiert werden. Diese Anleitung zeigt wie.

Callbacks

Callbacks funktionieren in den C/C++ Bindings für Mikrocontroller anders als in anderen Bindings. Da es auf vielen der Zielplattformen kein Multi-Threading gibt, wird nicht automatisch nach Callbacks gepollt. Stattdessen muss, wenn Callbacks empfangen werden sollen, mit der in jedem HAL verfügbaren tf_hal_callback_tick-Funktion nach Callbacks gepollt werden. Diese Funktion pollt nur angeschlossene Geräte, für die mindestens ein Callback-Handler registriert ist.

Callback werden nicht von einem anderen Thread ausgeliefert, sondern nur, während ein Getter, Setter oder die tf_hal_callback_tick-Funktion ausgeführt wird. Die Bindings sind deshalb während der Ausführung eines Callback-Handlers in einem Zustand, der es nicht erlaubt weitere Pakete zu schicken. Es ist nicht erlaubt, Getter, Setter oder Tick-Funktionen aus einem Callback-Handler aufzurufen

Threadsicherheit

Die primäre Zielplatform für die Bindings sind Mikrocontroller, deshalb sind sie nicht thread-sicher. Einige HALs unterstützen kooperatives Multitasking, es sind aber keine Aufrufe der Bindings-API erlaubt, während sie pausiert sind. Alle Funktionen geben während die Bindings pausiert sind, oder gerade ein Callback ausgeliefert wird, TF_E_LOCKED zurück.

Performanceoptimierungen

Um die beste Performance aus den Bindings zu holen, kann der folgenden Liste von Optimierungen gefolgt werden:

  • Erhöhen der SPI-Taktfrequenz von 1,4 MHz auf so nah wie möglich an 2 MHz. Eine zu hohe Taktfrequenz wird die Performance aber wieder verschlechtern, da die angeschlossenen Geräte die Daten nicht mehr empfangen können. In unseren Tests wurde die optimale Performance bei 1,95 bis 1,96 MHz erreicht, aber das ist stark abhängig vom Aufbau, dem HAL und der Stabilität der SPI Clock des Host-Systems.

    Die SPI-Taktfrequenz kann in den HAL-Implementierungen eingestellt werden.

  • Bevorzugung von Callbacks. Die Bindings können ein angeschlossenes Gerät nach verfügbaren Callbacks fragen, indem ein einzelnes Byte über SPI geschickt wird. Wenn Getter verwendet werden um schnell veränderlichen Zustand abzufragen, muss jedes Mal eine komplette TFP-Anfrage, deren Antwort und ein Acknowledgment über SPI verschickt werden, was mindestens 23 Byte Datenverkehr bedeutet.

  • Wenn exakt bekannt ist, welche Callbacks in welchen Intervallen eintreffen werden, sollte nicht tf_hal_callback_tick verwendet werden, sondern ein eigenes Scheduling für das Pollen mit den gerätespezifischen tf_[device]_callback_tick-Funktionen verwendet werden. Das erlaubt es, mehr Zeit für andere Aufgaben aufzuwenden. tf_hal_callback_tick verwendet einen Round-Robin-Scheduler um alle Geräte mit einem registrierten Callback Handler zu pollen.

  • Falls mehrere SPI-Einheiten verfügbar sind, können, soweit unterstützt, mehrere HAL-Instanzen verwendet werden. Das erlaubt es, mit mehreren Geräten parallel zu kommunizieren. Jede HAL-Instanz darf trotzdem nur von einem Thread verwendet werden.

RAM und Flashgröße optimieren

Damit eine Firmware mit den Bindings auf kleinere Plattformen wie den Arduino Uno passt, können die folgenden Konfigurationsoptionen in bindings/config.h angepasst werden:

  • TF_INVENTORY_SIZE: Die Größe des Inventory, also des Mappings von UIDs auf die Ports unter denen die Geräte erreichbar sind. Wenn pekannt ist, mit wie vielen Geräten kommuniziert werden soll, kann die Größe auf diesen Wert gesetzt werden. Die HAL-Initialisierung gibt TF_E_TOO_MANY_DEVICES zurück, falls das Inventory zu klein war.

  • TF_IMPLEMENT_CALLBACKS: Falls keine Callbacks benutzt werden sollen, kann dieses define entfernt werden, damit der entsprechende Code nicht verwendet wird

  • TF_LOG_LEVEL: Durch reduzieren des Log-Levels werden viele String-Konstanten nicht einkompiliert. Valide Werte sind:

    • TF_LOG_LEVEL_NONE: Deaktiviert das Logging komplett

    • TF_LOG_LEVEL_ERROR: Loggt nur HAL-spezifische Fehler wenn sie auftreten

    • TF_LOG_LEVEL_INFO: Loggt zusätzlich die Liste der gefundenen Geräte bei der HAL-Initialisierung

    • TF_LOG_LEVEL_DEBUG: Loggt zusätzlich alle internen Zustandsänderungen der SPITFP-Zustandsmaschine

  • TF_IMPLEMENT_STRERROR: Wenn dieses define entfernt wird, wird die tf_hal_strerror-Funktion nicht implementiert. Damit können ungefähr 500 Bytes Speicherplatz freigemacht werden.

API Referenz und Beispiele

Links zur API Referenz der HALs, Bricks und Bricklets sowie die Beispiele aus der ZIP Datei der Bindings sind in der folgenden Tabelle aufgelistet. Anleitungen für weiterführende Projekte finden sich im Abschnitt über Kits.

, API, Beispiele

Sonstiges

HAL Arduino

API

Beispiele

HAL Arduino ESP32

API

Beispiele

HAL Arduino ESP32 Brick

API

Beispiele

HAL Arduino ESP32 Ethernet Brick

API

Beispiele

HAL Linux

API

Beispiele

HAL Raspberry Pi

API

Beispiele

Bricks

HAT

API

Beispiele

HAT Zero

API

Beispiele

Bricklets

Accelerometer 2.0

API

Beispiele

Air Quality

API

Beispiele

Ambient Light 3.0

API

Beispiele

Analog In 3.0

API

Beispiele

Analog Out 3.0

API

Beispiele

Barometer 2.0

API

Beispiele

CAN 2.0

API

Beispiele

CO2 2.0

API

Beispiele

Color 2.0

API

Beispiele

Compass

API

Beispiele

DC 2.0

API

Beispiele

Distance IR 2.0

API

Beispiele

Distance US 2.0

API

Beispiele

DMX

API

Beispiele

Dual Button 2.0

API

Beispiele

E-Paper 296x128

API

Beispiele

Energy Monitor

API

Beispiele

GPS 2.0

API

Beispiele

GPS 3.0

API

Beispiele

Hall Effect 2.0

API

Beispiele

Humidity 2.0

API

Beispiele

IMU 3.0

API

Beispiele

Industrial Analog Out 2.0

API

Beispiele

Industrial Counter

API

Beispiele

Industrial Digital In 4 2.0

API

Beispiele

Industrial Digital Out 4 2.0

API

Beispiele

Industrial Dual 0-20mA 2.0

API

Beispiele

Industrial Dual AC In

API

Industrial Dual AC Relay

API

Beispiele

Industrial Dual Analog In 2.0

API

Beispiele

Industrial Dual Relay

API

Beispiele

Industrial PTC

API

Beispiele

Industrial Quad Relay 2.0

API

Beispiele

IO-16 2.0

API

Beispiele

IO-4 2.0

API

Beispiele

Isolator

API

Beispiele

Joystick 2.0

API

Beispiele

Laser Range Finder 2.0

API

Beispiele

LCD 128x64

API

Beispiele

LED Strip 2.0

API

Beispiele

Linear Poti 2.0

API

Beispiele

Load Cell 2.0

API

Beispiele

Motion Detector 2.0

API

Beispiele

Motorized Linear Poti

API

Beispiele

Multi Touch 2.0

API

Beispiele

NFC

API

Beispiele

OLED 128x64 2.0

API

Beispiele

One Wire

API

Beispiele

Outdoor Weather

API

Beispiele

Particulate Matter

API

Beispiele

Performance DC

API

Beispiele

Piezo Speaker 2.0

API

Beispiele

Real-Time Clock 2.0

API

Beispiele

Remote Switch 2.0

API

Beispiele

RGB LED 2.0

API

Beispiele

RGB LED Button

API

Beispiele

Rotary Encoder 2.0

API

Beispiele

Rotary Poti 2.0

API

Beispiele

RS232 2.0

API

Beispiele

RS485

API

Beispiele

Segment Display 4x7 2.0

API

Beispiele

Servo 2.0

API

Beispiele

Silent Stepper 2.0

API

Beispiele

Solid State Relay 2.0

API

Beispiele

Sound Pressure Level

API

Beispiele

Temperature 2.0

API

Beispiele

Temperature IR 2.0

API

Beispiele

Thermal Imaging

API

Beispiele

Thermocouple 2.0

API

Beispiele

UV Light 2.0

API

Beispiele

Voltage/Current 2.0

API

Beispiele

XMC1400 Breakout

API

Beispiele

Bricklets (Abgekündigt)

PTC 2.0

API

Beispiele

RGB LED Matrix

API