Planet 1 Ltd

cog wheels 2125178 640

Zepto Elements is a collection or toolbox of Embedded System Infrastructure modules.

These modules have been developed for Planet 1's embedded system designs, they have been written by experienced embedded system engineers for embedded system engineers encompassing the limitations and good practices required for developing reliable, efficient and high performance embedded systems.

Zepto Elements is provided as a complete set, you use only the modules you require for your product.

mark 516277 640Overview

These modules have common features required for high performance small embedded systems:
  • All software modules written in portable 'C', will easily port to virtually any processor with a 'C' compiler
  • Static memory usage, no dynamic memory used
  • Fast execution
  • Low and efficient RAM and program memory usage
  • Deterministic execution time
  • Designed for high-reliability systems
  • Ideal for battery powered systems
  • Non-blocking state machine approach (where applicable) for bare-metal, super-loop, RTOS or Event Scheduler system designs
  • Full embedded 'C' source code
  • Inexpensive, per product royality free licence

checklist 1622517 640z_evt - Event Scheduler

Replaces a traditional RTOS or basic Super-Loop with a light and fast Event Scheduler which is designed specifically for bare-metal embedded systems. The event scheduler organises tasks and events and only executes a non-blocking task when it has an event pending. Events can be signalled from any task or ISR.

Why use this Event Scheduler instead of an RTOS? Most Embedded System are not hard real-time and do not warrant the complexities involved in an RTOS based system. Why make your product more expensive and time consuming to develop, more prone to bugs, more difficult to debug and requiring a more expensive microcontroller? With an RTOS your number of tasks will be limited because each task requires its own stack space and so it will require a larger and more expensive microcontroller to perform the same functionality. As tasks are premptable by other tasks every shared resource and data must be protected by mutexes, semaphores or critical sections - any omissions will cause a bug which may not occur very often, making it very hard to debug and so take a long time - costing money and reputation. Are you confident your system will be reliable?

With this Event Scheduler tasks are synchronous and are only preempted by interrupts, if you need real time response then service it in an interrupt service routine. For instance when receiving data from a serial port or sampling data from an ADC port then perform this in an interrupt service routine (ISR), add the data to a queue (z_que, see below), signal your receive event, exit the ISR then process the data in the task signalled by the event. This keeps the ISR blocking time very short and decouples the data processing from the ISR.

This event scheduler uses a simple user configuration file and compile time tool to define the events, tasks and which tasks should receive which events - this saves precious RAM and ROM/flash space.

All the LUTs are ROMable and takes no RAM space.


  • Highly efficient in CPU time, memory and code space
  • Only one stack for all tasks and interrupts (stack sharing), enabling a system to have many more tasks than a traditional RTOS.
  • Prioritised task/event scheduling
  • Any number of task and events can be used (within memory limits)
  • An event can be signalled to multiple tasks from any task or interrupt service routine
  • Architecture independent

stopwatch 3699317 640z_tmr - Generic Timers

The z_tmr module provides a simple and elegant timer system using only one hardware timer. It is independent of any operating system and can be used standalone, with a simple super-loop scheduler, virtually any OS/RTOS and Zepto z_evt Event Scheduler.

The user can set as many timers as required using globally or statically declared z_tmr_t structures, one for each required timer. This structure holds all the timer information.

Each timer can execute a user's callback function, which is called when the timer times-out or "fires". The user can also set a callback data value that is sent to the callback function.

Each timer can be set to timeout or fire from 1 to a number of times, or forever.


  • Highly efficient in CPU time, memory and code space
  • Only requires a single hardware timer and interrupt
  • Accuracy as fine as the underlying hardware timer, no course OS-Tick granularity
  • Deterministic, hardware timer interrupt acceptance to callback is always the same time
  • OS Tick-less time, no unnecessary and wasteful interrupts
  • No unnecessary wakeup from sleep for OS ticks, thus saving cycles and power
  • Any number of timers can be used (within memory limits)
  • Architecture independent, uses z_hw_time module
  • Operating System independent, can be used with or without an OS/RTOS, Super-Loop or the z_evt Event Scheduler
  • User specified time value size (8, 16, 32 or 64 bits), default 32-bits
  • Time value size is independent of hardware timer size and automatically catered for, e.g. you can have many 32-bit timers, from a single 8-bit hardware timer
  • Fractional timing or a fixed (binary) point time variable can be specified (in bits), used for more accurate long time repeating timers, e.g. Real Time Clock 

binary 1071776 640z_que - Queue Container

A queue is a way of containing data or data structures in a linearly ordered First In First Out (FIFO) queue. The queue has little overhead compared to a linked list, but lacks the linked list flexibility, see z_lst container. Use this queue with a event to create a data stream, for instance serial port USART receive buffer.

The queue data is an array of data or data structures with management data. The data has zero overhead per element and a fixed additional size per queue for the management data stored in z_que_t.

Data Queue Diagram

Write and     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+     Read and
add data      |  |  |  |  |  |  |  |  |  |  |  |  |  |  |     remove data
to end of --->|END  |  |  |  |QUEUE ARRAY|  |  |  | HEAD|---> from head
queue         |  |  |  |  |  |  |  |  |  |  |  |  |  |  |     of queue


  • Highly efficient in CPU time, memory and code space.
  • No multiplies or divides in run-time pointer calculations.
  • Simple queue operations.
  • Manages queues of different lengths.
  • Manages queues of different element sizes (one size per queue).
  • Can be used in ISR/Task transfer without disabling interrupts (only if management pointer reads and writes are themselves atomic).

z_lst - Circular Double Way Linked List Container

A linked list is a way of containing and ordering data structures. The size of a list changes as data structures are added or removed, the list size is only limited by the memory available.

Unlike an array the data structures can be in any order and at any address in memory. Data structure are easily and quickly inserted or removed from the list by only updating the link pointers.

The disadvantage compared to an array is that every data structure must contain the double way link pointers and so this method becomes inefficient in terms of memory space if the data being contained is small, for example a queue of characters received from or transmitted to a serial port (where the data is 1 byte and the link pointers are 4 bytes). In this case the z_que Queue Container is better suited.

Linear Double Way Linked List Diagram

+------+      +-+------+-+    +-+------+-+    +-+------+-+
| List |----->| | Data |----->| | Data |----->| | Data |---->X END MARKER
| Ptr  |  X<----|   1  | |<-----|  2   | |<-----|  5   | |
+------+      +-+------+-+    +-+------+-+    +-+------+-+

Many functions are implemented as macros or inline functions. again for efficiency reasons.


  • Highly efficient in CPU time, memory and code space.
  • Simple list operations are performed using macro or inline functions.
  • There are no NULL pointers, so there is no need for NULL pointer checks.
  • All node pointers can be dereferenced.
  • The single node typedef can be used in any user data structures.
  • A linked list may contain different user data structures in the same list.
  • Can remove a node from a list without knowing which list it is (or is not) in.
  • Can empty a list in one operation.
  • Can insert one list in to another in two operations.

z_flg - Prioritised Flag Management

A flag can be used to represent something that has happened (i.e. an event), in a similar way that an interrupt is a flag. Flags may represents error codes, system inputs and outputs, inter-process communication, tasks ready to run, etc.

These flag management functions store each flag as a single bit in a bit array. The flags are prioritised and can be disabled or masked off.


  • Highly efficient in CPU time, memory and code space.
  • One flag is one bit.
  • One flag mask is one bit.
  • Flag masking is optional on a per flag structure level.
  • Flag masking is removed by default at compile time to save code space, if required define Z_FLG_MSK to 1.

binary 1607203 640z_bit - Bit Manipulation Functions

Bit manipulation functions optimised for the supported CPU architectures. Some architectures provide specific instructions to efficiently perform the following functions, others do not. These routines provide the desired CPU instruction or high optimised alternatives where no CPU support is provided.

Current Functions

z_bit_cnt(word) - Count the number of set bits in word.
z_bit_ctz(word) - Count the number of trailing (LS) zero bits in word.
z_bit_msk(word) - Create a bit mask with a '1' in bit position word.


  • Highly efficient in CPU time, memory and code space.
  • Deterministic execution time (does not vary much with the data being processed)
  • User can force default word size for all bit manipulation functions
  • User can include other (non-default) word size bit manipulation functions
  • User can choose which functions to include (or not include)

abstract 2023969 640z_atm - Atomic Primitives

This header file defines the atomic primitives that enable critical sections of code to run atomically (without interruption) and for more advanced CPU architectures allow defines primitives to simulate critical sections without disabling interrupts.