In this section, we highlight the BTstack components that need to be
adjusted for different hardware platforms.

Time Abstraction Layer

BTstack requires a way to learn about passing time.
btstack_run_loop_embedded.c supports two different modes: system ticks or a
system clock with millisecond resolution. BTstack’s timing requirements
are quite low as only Bluetooth timeouts in the second range need to be
handled.

Tick Hardware Abstraction

If your platform doesn’t require a system clock or if you already have a
system tick (as it is the default with CMSIS on ARM Cortex devices), you
can use that to implement BTstack’s time abstraction in
include/btstack/hal_tick.h>.

For this, you need to define HAVE_EMBEDDED_TICK in btstack_config.h:

#define HAVE_EMBEDDED_TICK

Then, you need to implement the functions hal_tick_init and
hal_tick_set_handler, which will be called during the
initialization of the run loop.

After BTstack calls hal_tick_init() and
hal_tick_set_handler(tick_handler), it expects that the
tick_handler gets called every
hal_tick_get_tick_period_in_ms() ms.

Time MS Hardware Abstraction

If your platform already has a system clock or it is more convenient to
provide such a clock, you can use the Time MS Hardware Abstraction in
include/btstack/hal_time_ms.h.

For this, you need to define HAVE_EMBEDDED_TIME_MS in btstack_config.h:

#define HAVE_EMBEDDED_TIME_MS

Then, you need to implement the function hal_time_ms(), which will
be called from BTstack’s run loop and when setting a timer for the
future. It has to return the time in milliseconds.

uint32_t hal_time_ms(void);

Bluetooth Hardware Control API

The Bluetooth hardware control API can provide the HCI layer with a
custom initialization script, a vendor-specific baud rate change
command, and system power notifications. It is also used to control the
power mode of the Bluetooth module, i.e., turning it on/off and putting
to sleep. In addition, it provides an error handler hw_error that is
called when a Hardware Error is reported by the Bluetooth module. The
callback allows for persistent logging or signaling of this failure.

Overall, the struct btstack_control_t encapsulates common functionality
that is not covered by the Bluetooth specification. As an example, the
btstack_chipset_cc256x_in-stance function returns a pointer to a control
struct suitable for the CC256x chipset.

HCI Transport Implementation

On embedded systems, a Bluetooth module can be connected via USB or an
UART port. BTstack implements three UART based protocols for carrying HCI
commands, events and data between a host and a Bluetooth module: HCI
UART Transport Layer (H4), H4 with eHCILL support, a lightweight
low-power variant by Texas Instruments, and the Three-Wire UART Transport Layer (H5).

HCI UART Transport Layer (H4)

Most embedded UART interfaces operate on the byte level and generate a
processor interrupt when a byte was received. In the interrupt handler,
common UART drivers then place the received data in a ring buffer and
set a flag for further processing or notify the higher-level code, i.e.,
in our case the Bluetooth stack.

Bluetooth communication is packet-based and a single packet may contain
up to 1021 bytes. Calling a data received handler of the Bluetooth stack
for every byte creates an unnecessary overhead. To avoid that, a
Bluetooth packet can be read as multiple blocks where the amount of
bytes to read is known in advance. Even better would be the use of
on-chip DMA modules for these block reads, if available.

The BTstack UART Hardware Abstraction Layer API reflects this design
approach and the underlying UART driver has to implement the following
API:

The main HCI H4 implementations for embedded system is
hci_h4_transport-_dma function. This function calls the following
sequence: hal_uart_dma_init, hal_uart_dma_set_block_received
and hal_uart_dma_set_block_sent functions. this sequence, the HCI
layer will start packet processing by calling
hal_uart-_dma_receive_block function. The HAL implementation is
responsible for reading the requested amount of bytes, stopping incoming
data via the RTS line when the requested amount of data was received and
has to call the handler. By this, the HAL implementation can stay
generic, while requiring only three callbacks per HCI packet.

H4 with eHCILL support

With the standard H4 protocol interface, it is not possible for either
the host nor the baseband controller to enter a sleep mode. Besides the
official H5 protocol, various chip vendors came up with proprietary
solutions to this. The eHCILL support by Texas Instruments allows both
the host and the baseband controller to independently enter sleep mode
without loosing their synchronization with the HCI H4 Transport Layer.
In addition to the IRQ-driven block-wise RX and TX, eHCILL requires a
callback for CTS interrupts.

H5

H5, makes use of the SLIP protocol to transmit a packet and can deal
with packet loss and bit-errors by retransmission. Since it can recover
from packet loss, it's also possible for either side to enter sleep
mode without loosing synchronization.

The use of hardware flow control in H5 is optional, however, since
BTstack uses hardware flow control to avoid packet buffers, it's
recommended to only use H5 with RTS/CTS as well.

For porting, the implementation follows the regular H4 protocol described above.

Persistent Storage APIs

On embedded systems there is no generic way to persist data like link
keys or remote device names, as every type of a device has its own
capabilities, particularities and limitations. The persistent storage
APIs provides an interface to implement concrete drivers for a particular
system.

Link Key DB

As an example and for testing purposes, BTstack provides the
memory-only implementation btstack_link_key_db_memory. An
implementation has to conform to the interface in Listing below.