Flipper Zero Zig Template: Developing Type-Safe Applications for Flipper Zero
The Flipper Zero Zig Template is a development framework that enables developers to write Flipper Zero applications using the Zig programming language. By integrating Zig's build system with the Flipper Zero SDK and the Unofficial Flipper Build Tool (ufbt), the template provides a path toward type-safe and memory-safe application development on the Flipper Zero platform.
Core Architecture and Build Pipeline
The template employs a two-stage build process to bridge the gap between Zig's cross-compilation capabilities and the Flipper Zero's .fap application format.
- Zig Build Stage: The Zig compiler targets the ARM Cortex-M4 CPU (thumb architecture) using the
eabihf(Hard Float) ABI. By default, it uses theReleaseSmalloptimization level to minimize binary size, producing anapp.oobject file. - UFBT Package Stage: The Unofficial Flipper Build Tool (ufbt) links the Zig-generated object files with the Flipper SDK and packages them into the final deployable
.fapformat.
Technical Requirements and Installation
To use the template, developers require the following tools:
- Zig: Version 0.15.1 or later.
- UFBT: The Unofficial Flipper Build Tool.
- Python 3: Necessary for executing
ufbtcommands. - Flipper Zero SDK: Managed automatically via
ufbt update(stored in~/.ufbt).
Platform Configuration
The template is pre-configured for ARM64 macOS. Users on other platforms must manually adjust the arm_libc_include path in build.zig (line 31) to match their specific toolchain location.
Development Workflow
Project Initialization
Developers can initialize a project using zig build init, which triggers an interactive script to collect application metadata, including the App ID, display name, description, author, and GitHub repository URL.
Build and Deployment Commands
zig build: Compiles Zig source code into an object file located atzig-out/bin/app.o.zig build fap: Executes the full pipeline, compiling the source and invokingufbtto generate a.fappackage in thedist/directory.zig build launch: Builds, packages, and transfers the application to a connected Flipper Zero device via USB, launching it automatically.
SDK Integration and Implementation Details
Interacting with the Flipper SDK
The build system configures include paths for the core FURI (Flipper Universal Runtime Interface), the STM32WB55 Hardware Abstraction Layer (HAL), and various protocol libraries (Sub-GHz, NFC, RFID, Infrared). These are accessed in Zig via @cImport().
ARM Calling Conventions
Correct calling conventions are critical for stability on the Flipper Zero. The template specifies two primary conventions:
- AAPCS: Used for the standard ARM procedure call, such as the
start()entry point:export fn start(_: ?*anyopaque) callconv(.{ .arm_aapcs = .{} }) i32. - AAPCS-VFP: Used for callbacks requiring floating-point or vector support:
export fn draw_callback(canvas: ?*Canvas, ctx: ?*anyopaque) callconv(.{ .arm_aapcs_vfp = .{} }) void.
Handling C Compatibility Issues
Because some SDK headers contain constructs (such as unions with opaque types in input/input.h) that the Zig C translator cannot process, developers must manually declare these external functions. For example:
extern fn view_port_input_callback_set(
view_port: ?*flipper.ViewPort,
callback: ?*const fn (?*anyopaque, ?*anyopaque) callconv(.{ .arm_aapcs_vfp = .{} }) void,
context: ?*anyopaque
) callconv(.{ .arm_aapcs = .{} }) void;
Troubleshooting Common Issues
- Header Errors: If
furi.his not found, runufbt updateto ensure the SDK is installed. - Linking Errors: Undefined references to SDK functions (e.g.,
view_port_alloc) typically occur when usingzig buildinstead ofzig build fap, which is required for final linking. - Runtime Crashes: Application crashes on launch are often attributed to incorrect calling conventions or stack overflows; the latter can be resolved by increasing the
stack_sizein theapplication.fammanifest.
Community Insights
Discussion surrounding the project highlights the growing adoption of Zig for embedded systems despite its lack of a stable 1.0 release. Some users have noted that the @cImport syntax may be evolving, suggesting that developers keep their examples updated with the latest Zig version requirements.