initial commit, hci_uart with usb cdc and custom commands

This commit is contained in:
Dirk Helbig
2024-06-11 22:36:18 +02:00
commit d97a8581f5
39 changed files with 1297 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
.settings
.cproject
.project
build
app.jdebug
app.jdebug.user

8
CMakeLists.txt Normal file
View File

@@ -0,0 +1,8 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(hci_uart)
target_sources(app PRIVATE src/main.c)

14
README.md Normal file
View File

@@ -0,0 +1,14 @@
# build for USB CDC
```sh
west build -b nrf5340dk_nrf5340_cpuapp -- -DDTC_OVERLAY_FILE=usb.overlay -DOVERLAY_CONFIG=overlay-usb.conf
```
# build for uart1 a.k. arduino_serial
```sh
west build -b nrf5340_audio_dk_nrf5340_cpuapp -- -DDTC_OVERLAY_FILE=uart1.overlay
```
# build for debug and uart1
```sh
west build -b nrf5340_audio_dk_nrf5340_cpuapp -- -DDTC_OVERLAY_FILE=uart1.overlay -DOVERLAY_CONFIG=debug.conf
```

192
README.rst Normal file
View File

@@ -0,0 +1,192 @@
.. _bluetooth-hci-uart-sample:
Bluetooth: HCI UART
####################
Overview
*********
Expose the Zephyr Bluetooth controller support over UART to another device/CPU
using the H:4 HCI transport protocol (requires HW flow control from the UART).
Requirements
************
* A board with BLE support
Default UART settings
*********************
By default the controller builds use the following settings:
* Baudrate: 1Mbit/s
* 8 bits, no parity, 1 stop bit
* Hardware Flow Control (RTS/CTS) enabled
Building and Running
********************
This sample can be found under :zephyr_file:`samples/bluetooth/hci_uart` in the
Zephyr tree, and it is built as a standard Zephyr application.
Using the controller with emulators and BlueZ
*********************************************
The instructions below show how to use a Nordic nRF5x device as a Zephyr BLE
controller and expose it to Linux's BlueZ. This can be very useful for testing
the Zephyr Link Layer with the BlueZ Host. The Zephyr BLE controller can also
provide a modern BLE 5.0 controller to a Linux-based machine for native
BLE support or QEMU-based development.
First, make sure you have a recent BlueZ version installed by following the
instructions in the :ref:`bluetooth_bluez` section.
Now build and flash the sample for the Nordic nRF5x board of your choice.
All of the Nordic Development Kits come with a Segger IC that provides a
debugger interface and a CDC ACM serial port bridge. More information can be
found in :ref:`nordic_segger`.
For example, to build for the nRF52832 Development Kit:
.. zephyr-app-commands::
:zephyr-app: samples/bluetooth/hci_uart
:board: nrf52dk_nrf52832
:goals: build flash
.. _bluetooth-hci-uart-qemu-posix:
Using the controller with QEMU or native_sim
============================================
In order to use the HCI UART controller with QEMU or :ref:`native_sim <native_sim>` you will need
to attach it to the Linux Host first. To do so simply build the sample and
connect the UART to the Linux machine, and then attach it with this command:
.. code-block:: console
sudo btattach -B /dev/ttyACM0 -S 1000000 -R
.. note::
Depending on the serial port you are using you will need to modify the
``/dev/ttyACM0`` string to point to the serial device your controller is
connected to.
.. note::
If using the BBC micro:bit you will need to modify the baudrate argument
from ``1000000`` to ``115200``.
.. note::
The ``-R`` flag passed to ``btattach`` instructs the kernel to avoid
interacting with the controller and instead just be aware of it in order
to proxy it to QEMU later.
If you are running :file:`btmon` you should see a brief log showing how the
Linux kernel identifies the attached controller.
Once the controller is attached follow the instructions in the
:ref:`bluetooth_qemu_native` section to use QEMU with it.
.. _bluetooth-hci-uart-bluez:
Using the controller with BlueZ
===============================
In order to use the HCI UART controller with BlueZ you will need to attach it
to the Linux Host first. To do so simply build the sample and connect the
UART to the Linux machine, and then attach it with this command:
.. code-block:: console
sudo btattach -B /dev/ttyACM0 -S 1000000
.. note::
Depending on the serial port you are using you will need to modify the
``/dev/ttyACM0`` string to point to the serial device your controller is
connected to.
.. note::
If using the BBC micro:bit you will need to modify the baudrate argument
from ``1000000`` to ``115200``.
If you are running :file:`btmon` you should see a comprehensive log showing how
BlueZ loads and initializes the attached controller.
Once the controller is attached follow the instructions in the
:ref:`bluetooth_ctlr_bluez` section to use BlueZ with it.
Debugging the controller
========================
The sample can be debugged using RTT since the UART is otherwise used by this
application. To enable debug over RTT the debug configuration file can be used.
.. code-block:: console
west build samples/bluetooth/hci_uart -- -DEXTRA_CONF_FILE='debug.conf'
Then attach RTT as described here: :ref:`Using Segger J-Link <Using Segger J-Link>`
Support for the Direction Finding
=================================
The sample can be built with the support for the BLE Direction Finding.
To enable this feature build this sample for specific board variants that provide
required hardware configuration for the Radio.
.. code-block:: console
west build samples/bluetooth/hci_uart -b nrf52833dk_nrf52833@df -- -DCONFIG_BT_CTLR_DF=y
You can use following targets:
* ``nrf5340dk_nrf5340_cpunet@df``
* ``nrf52833dk_nrf52833@df``
Check the :ref:`bluetooth_direction_finding_connectionless_rx` and the :ref:`bluetooth_direction_finding_connectionless_tx` for more details.
Using a USB CDC ACM UART
========================
The sample can be configured to use a USB UART instead. See :zephyr_file:`samples/bluetooth/hci_uart/boards/nrf52840dongle_nrf52840.conf` and :zephyr_file:`samples/bluetooth/hci_uart/boards/nrf52840dongle_nrf52840.overlay`.
Using the controller with the Zephyr host
=========================================
This describes how to hook up a board running this sample to a board running
an application that uses the Zephyr host.
On the controller side, the `zephyr,bt-c2h-uart` DTS property (in the `chosen`
block) is used to select which uart device to use. For example if we want to
keep the console logs, we can keep console on uart0 and the HCI on uart1 like
so:
.. code-block:: dts
/ {
chosen {
zephyr,console = &uart0;
zephyr,shell-uart = &uart0;
zephyr,bt-c2h-uart = &uart1;
};
};
On the host application, some config options need to be used to select the H4
driver instead of the built-in controller:
.. code-block:: kconfig
CONFIG_BT_HCI=y
CONFIG_BT_CTLR=n
CONFIG_BT_H4=y
Similarly, the `zephyr,bt-uart` DTS property selects which uart to use:
.. code-block:: dts
/ {
chosen {
zephyr,console = &uart0;
zephyr,shell-uart = &uart0;
zephyr,bt-uart = &uart1;
};
};

View File

@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: Apache-2.0 */
&uart0 {
compatible = "nordic,nrf-uart";
current-speed = <1000000>;
hw-flow-control;
status = "okay";
};

8
boards/bbc_microbit.conf Normal file
View File

@@ -0,0 +1,8 @@
CONFIG_MAIN_STACK_SIZE=512
CONFIG_IDLE_STACK_SIZE=256
CONFIG_ISR_STACK_SIZE=512
CONFIG_BT_MAX_CONN=10
# Revert values set in prj.conf, set them to their Kconfig default value
CONFIG_BT_BUF_CMD_TX_SIZE=65
CONFIG_BT_BUF_ACL_RX_SIZE=69
CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=43

View File

@@ -0,0 +1,4 @@
CONFIG_CONSOLE=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_BT_MAX_CONN=9

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
chosen {
zephyr,bt-c2h-uart = &uart1;
};
};
&pinctrl {
uart1_default: uart1_default {
group1 {
pinmux = <UART1_TX_GPIO5>,
<UART1_RX_GPIO18>,
<UART1_RTS_GPIO19>;
};
group2 {
pinmux = <UART1_CTS_GPIO23>;
bias-pull-up;
};
};
};
&uart1 {
status = "okay";
current-speed = <921600>;
pinctrl-0 = <&uart1_default>;
pinctrl-names = "default";
};

View File

@@ -0,0 +1,8 @@
CONFIG_MAIN_STACK_SIZE=512
CONFIG_BT_MAX_CONN=10
CONFIG_IDLE_STACK_SIZE=256
CONFIG_ISR_STACK_SIZE=512
# Revert values set in prj.conf, set them to their Kconfig default value
CONFIG_BT_BUF_CMD_TX_SIZE=65
CONFIG_BT_BUF_ACL_RX_SIZE=69
CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=43

View File

@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: Apache-2.0 */
&uart0 {
compatible = "nordic,nrf-uart";
current-speed = <1000000>;
status = "okay";
hw-flow-control;
};

View File

@@ -0,0 +1 @@
CONFIG_MAIN_STACK_SIZE=512

View File

@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: Apache-2.0 */
&uart0 {
compatible = "nordic,nrf-uart";
current-speed = <1000000>;
status = "okay";
hw-flow-control;
};

View File

@@ -0,0 +1 @@
CONFIG_MAIN_STACK_SIZE=512

View File

@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: Apache-2.0 */
&uart0 {
compatible = "nordic,nrf-uart";
current-speed = <1000000>;
status = "okay";
hw-flow-control;
};

View File

@@ -0,0 +1,12 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
&uart0 {
compatible = "nordic,nrf-uarte";
current-speed = <1000000>;
status = "okay";
hw-flow-control;
};

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
&uart0 {
compatible = "nordic,nrf-uarte";
current-speed = <1000000>;
status = "okay";
hw-flow-control;
};
&radio {
status = "okay";
/* This is an example number of antennas that may be available
* on antenna matrix board.
*/
dfe-antenna-num = <10>;
/* This is an example switch pattern that will be used to set an
* antenna for Tx PDU (period before start of Tx CTE).
*/
dfe-pdu-antenna = <0x0>;
/* These are example GPIO pin numbers that are provided to
* Radio peripheral. The pins will be acquired by Radio to
* drive antenna switching when AoD is enabled.
*/
dfegpio0-gpios = <&gpio0 3 0>;
dfegpio1-gpios = <&gpio0 4 0>;
dfegpio2-gpios = <&gpio0 28 0>;
dfegpio3-gpios = <&gpio0 29 0>;
};

View File

@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: Apache-2.0 */
&uart0 {
compatible = "nordic,nrf-uart";
current-speed = <1000000>;
status = "okay";
hw-flow-control;
};

View File

@@ -0,0 +1,4 @@
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_PRODUCT="Zephyr HCI UART sample"
CONFIG_USB_CDC_ACM=y
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n

View File

@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: Apache-2.0 */
&uart0 {
compatible = "nordic,nrf-uart";
current-speed = <1000000>;
status = "okay";
hw-flow-control;
};

View File

@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: Apache-2.0 */
&uart0 {
compatible = "nordic,nrf-uart";
current-speed = <1000000>;
status = "okay";
hw-flow-control;
};

View File

@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: Apache-2.0 */
&uart0 {
compatible = "nordic,nrf-uarte";
current-speed = <1000000>;
status = "okay";
hw-flow-control;
};

View File

@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: Apache-2.0 */
&uart0 {
compatible = "nordic,nrf-uarte";
current-speed = <1000000>;
status = "okay";
hw-flow-control;
};

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
&uart0 {
compatible = "nordic,nrf-uarte";
current-speed = <1000000>;
status = "okay";
hw-flow-control;
};
&radio {
status = "okay";
/* This is an example number of antennas that may be available
* on antenna matrix board.
*/
dfe-antenna-num = <10>;
/* This is an example switch pattern that will be used to set an
* antenna for Tx PDU (period before start of Tx CTE).
*/
dfe-pdu-antenna = <0x0>;
/* These are example GPIO pin numbers that are provided to
* Radio peripheral. The pins will be acquired by Radio to
* drive antenna switching when AoD is enabled.
*/
dfegpio0-gpios = <&gpio0 4 0>;
dfegpio1-gpios = <&gpio0 5 0>;
dfegpio2-gpios = <&gpio0 6 0>;
dfegpio3-gpios = <&gpio0 7 0>;
};

View File

@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: Apache-2.0 */
&uart0 {
compatible = "nordic,nrf-uarte";
current-speed = <1000000>;
status = "okay";
hw-flow-control;
};

View File

@@ -0,0 +1,4 @@
# Override prj.conf defaults
CONFIG_CONSOLE=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_UART_CONSOLE=y

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <nrf9160dk_nrf52840_reset_on_if5.dtsi>
#include <nrf9160dk_uart1_on_if0_3.dtsi>
&uart1 {
current-speed = <1000000>;
hw-flow-control;
};
/ {
chosen {
zephyr,bt-c2h-uart=&uart1;
};
};

View File

@@ -0,0 +1,8 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/* Use the reset line that is available starting from v0.14.0 of the DK. */
#include <nrf9160dk_nrf52840_reset_on_if9.dtsi>

View File

@@ -0,0 +1,7 @@
#
# Copyright 2020, NXP
#
# SPDX-License-Identifier: Apache-2.0
#
CONFIG_UART_INTERRUPT_DRIVEN=y

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2019 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
chosen {
zephyr,bt-c2h-uart = &lpuart0;
};
};
&lptmr1 {
interrupt-parent = <&intmux0_ch2>;
};
&intmux0_ch2 {
status = "okay";
};
&intmux0_ch3 {
status = "okay";
};
&generic_fsk {
interrupt-parent = <&intmux0_ch3>;
status = "okay";
};

4
boards/yd_esp32.conf Normal file
View File

@@ -0,0 +1,4 @@
CONFIG_CONSOLE=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_BT_MAX_CONN=9

34
boards/yd_esp32.overlay Normal file
View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
chosen {
zephyr,bt-c2h-uart = &uart1;
};
};
&pinctrl {
uart1_default: uart1_default {
group1 {
pinmux = <UART1_TX_GPIO5>,
<UART1_RX_GPIO18>,
<UART1_RTS_GPIO19>;
};
group2 {
pinmux = <UART1_CTS_GPIO23>;
bias-pull-up;
};
};
};
&uart1 {
status = "okay";
current-speed = <921600>;
pinctrl-0 = <&uart1_default>;
pinctrl-names = "default";
};

25
debug.conf Normal file
View File

@@ -0,0 +1,25 @@
CONFIG_ASSERT=y
#CONFIG_THREAD_NAME=y
#CONFIG_THREAD_ANALYZER=y
#CONFIG_THREAD_ANALYZER_AUTO=y
#CONFIG_THREAD_ANALYZER_RUN_UNLOCKED=y
CONFIG_HW_STACK_PROTECTION=y
CONFIG_CONSOLE=y
CONFIG_LOG=y
CONFIG_LOG_BUFFER_SIZE=4096
CONFIG_RTT_CONSOLE=y
CONFIG_LOG_BACKEND_RTT=y
CONFIG_LOG_BACKEND_RTT_MODE_DROP=n
CONFIG_USE_SEGGER_RTT=y
CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=4096
CONFIG_LOG_BACKEND_SHOW_COLOR=n
CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=1024
CONFIG_LOG_DEFAULT_LEVEL=3
CONFIG_DEBUG_OPTIMIZATIONS=y
CONFIG_DEBUG_INFO=y

View File

@@ -0,0 +1,109 @@
CONFIG_BT_BUF_EVT_RX_COUNT=16
CONFIG_BT_BUF_EVT_RX_SIZE=255
CONFIG_BT_BUF_ACL_RX_SIZE=255
CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_BUF_CMD_TX_SIZE=255
# Host and Controller common dependencies
CONFIG_BT_EXT_ADV=y
CONFIG_BT_PER_ADV=y
CONFIG_BT_PER_ADV_SYNC=y
CONFIG_BT_PER_ADV_SYNC_MAX=2
# Broadcast and Connected ISO
CONFIG_BT_ISO_BROADCASTER=y
CONFIG_BT_ISO_SYNC_RECEIVER=y
CONFIG_BT_ISO_CENTRAL=y
CONFIG_BT_ISO_PERIPHERAL=y
# ISO Streams
CONFIG_BT_ISO_MAX_CHAN=2
# Controller
CONFIG_BT_LL_SW_SPLIT=y
CONFIG_BT_CTLR_ASSERT_HANDLER=y
CONFIG_BT_CTLR_DTM_HCI=y
# Rx ACL and Adv Reports
CONFIG_BT_CTLR_RX_BUFFERS=9
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251
# Coded PHY support
CONFIG_BT_CTLR_PHY_CODED=y
# Advertising Sets and Extended Scanning
CONFIG_BT_CTLR_ADV_EXT=y
CONFIG_BT_CTLR_ADV_SET=3
CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191
CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=1650
CONFIG_BT_CTLR_ADVANCED_FEATURES=y
CONFIG_BT_CTLR_ADV_AUX_SET=3
CONFIG_BT_CTLR_ADV_AUX_PDU_BACK2BACK=y
CONFIG_BT_CTLR_ADV_SYNC_SET=3
CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK=y
CONFIG_BT_CTLR_ADV_DATA_BUF_MAX=6
# Increase the below to receive interleaved advertising chains
CONFIG_BT_CTLR_SCAN_AUX_SET=1
CONFIG_BT_CTLR_ADV_RESERVE_MAX=n
CONFIG_BT_CTLR_CENTRAL_RESERVE_MAX=n
CONFIG_BT_CTLR_SLOT_RESERVATION_UPDATE=n
CONFIG_BT_CTLR_SCAN_UNRESERVED=y
CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH=y
CONFIG_BT_TICKER_EXT=y
CONFIG_BT_TICKER_EXT_SLOT_WINDOW_YIELD=y
# Control Procedure
CONFIG_BT_CTLR_LLCP_LOCAL_PROC_CTX_BUF_NUM=6
# Direction Finding
CONFIG_BT_CTLR_DF=y
CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX=3
CONFIG_BT_CTLR_DF_PER_SCAN_CTE_NUM_MAX=3
# Direction Finding Tx
CONFIG_BT_CTLR_DF_CTE_TX=y
CONFIG_BT_CTLR_DF_CONN_CTE_TX=y
CONFIG_BT_CTLR_DF_ANT_SWITCH_TX=y
CONFIG_BT_CTLR_DF_CONN_CTE_RSP=y
# Direction Finding Rx
CONFIG_BT_CTLR_DF_CTE_RX=y
CONFIG_BT_CTLR_DF_CONN_CTE_RX=y
CONFIG_BT_CTLR_DF_ANT_SWITCH_RX=y
CONFIG_BT_CTLR_DF_CONN_CTE_REQ=y
# ISO Broadcaster Controller
CONFIG_BT_CTLR_ADV_EXT=y
CONFIG_BT_CTLR_ADV_PERIODIC=y
CONFIG_BT_CTLR_ADV_ISO=y
CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=251
CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=2
# ISO Receive Controller
CONFIG_BT_CTLR_ADV_EXT=y
CONFIG_BT_CTLR_SYNC_PERIODIC=y
CONFIG_BT_CTLR_SYNC_ISO=y
CONFIG_BT_CTLR_SYNC_ISO_PDU_LEN_MAX=251
CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=2
# ISO Connection Oriented
CONFIG_BT_CTLR_CENTRAL_ISO=y
CONFIG_BT_CTLR_PERIPHERAL_ISO=y
CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=251
CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251
# ISO Transmissions
CONFIG_BT_CTLR_ISO_TX_BUFFERS=8
CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251
CONFIG_BT_CTLR_ISOAL_SOURCES=2
# ISO Receptions
CONFIG_BT_CTLR_ISO_RX_BUFFERS=8
CONFIG_BT_CTLR_ISOAL_SINKS=2
# Tx Power Dynamic Control
CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y

54
overlay-usb.conf Normal file
View File

@@ -0,0 +1,54 @@
#USB stuff
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_PRODUCT="Zephyr HCI UART sample"
CONFIG_USB_CDC_ACM=y
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n
#CONFIG_USB_DEVICE_LOG_LEVEL_DBG=y
# stack
#CONFIG_ISR_STACK_SIZE=8192
#CONFIG_IDLE_STACK_SIZE=8192
#CONFIG_MAIN_STACK_SIZE=8192
#CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=8192
#CONFIG_IPC_SERVICE_BACKEND_RPMSG_WQ_STACK_SIZE=8192
#CONFIG_HEAP_MEM_POOL_SIZE=8192
# Enable ISO support
CONFIG_BT_ISO_BROADCASTER=y
CONFIG_BT_ISO_TX_BUF_COUNT=10
CONFIG_BT_ISO_TX_MTU=251
CONFIG_BT_ISO_RX_BUF_COUNT=10
CONFIG_BT_ISO_RX_MTU=251
# setup rpmsg/Bluetooth buffer
CONFIG_BT_BUF_EVT_RX_COUNT=16
CONFIG_BT_BUF_EVT_RX_SIZE=255
CONFIG_BT_BUF_ACL_RX_SIZE=255
CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_BUF_CMD_TX_SIZE=255
#debug stuff
#CONFIG_ASSERT=y
#CONFIG_THREAD_NAME=y
#CONFIG_THREAD_ANALYZER=y
#CONFIG_THREAD_ANALYZER_AUTO=y
#CONFIG_THREAD_ANALYZER_RUN_UNLOCKED=y
#CONFIG_HW_STACK_PROTECTION=y
#CONFIG_CONSOLE=n
#CONFIG_LOG=y
#CONFIG_LOG_BUFFER_SIZE=4096
#CONFIG_RTT_CONSOLE=y
#CONFIG_UART_CONSOLE=n
#CONFIG_LOG_BACKEND_RTT=y
#CONFIG_LOG_BACKEND_RTT_MODE_DROP=n
#CONFIG_USE_SEGGER_RTT=y
#CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=2048
#CONFIG_LOG_BACKEND_SHOW_COLOR=n
#CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=8192
#CONFIG_LOG_DEFAULT_LEVEL=3

27
prj.conf Normal file
View File

@@ -0,0 +1,27 @@
CONFIG_CONSOLE=n
CONFIG_STDOUT_CONSOLE=n
CONFIG_UART_CONSOLE=n
CONFIG_GPIO=y
CONFIG_SERIAL=y
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_BT=y
CONFIG_BT_HCI_RAW=y
CONFIG_BT_HCI_RAW_H4=y
CONFIG_BT_HCI_RAW_H4_ENABLE=y
CONFIG_BT_BUF_ACL_RX_SIZE=255
CONFIG_BT_BUF_CMD_TX_SIZE=255
CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=255
CONFIG_BT_CTLR_ASSERT_HANDLER=y
CONFIG_BT_MAX_CONN=16
CONFIG_BT_TINYCRYPT_ECC=n
CONFIG_BT_CTLR_DTM_HCI=y
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512
# Workaround: Unable to allocate command buffer when using K_NO_WAIT since
# Host number of completed commands does not follow normal flow control.
CONFIG_BT_BUF_CMD_TX_COUNT=10
# for the timesync command
CONFIG_BT_HCI_RAW_CMD_EXT=y

60
sample.yaml Normal file
View File

@@ -0,0 +1,60 @@
sample:
name: Bluetooth HCI UART
description: Allows Zephyr to provide Bluetooth connectivity via UART
tests:
sample.bluetooth.hci_uart.nrf5:
harness: bluetooth
platform_allow:
- nrf52dk_nrf52832
tags:
- uart
- bluetooth
sample.bluetooth.hci_uart.nrf52833.df:
harness: bluetooth
platform_allow: nrf52833dk_nrf52833
extra_args: DTC_OVERLAY_FILE=./boards/nrf52833dk_nrf52833_df.overlay
extra_configs:
- CONFIG_BT_CTLR_DF=y
tags:
- uart
- bluetooth
sample.bluetooth.hci_uart.nrf5340_netcore.df:
harness: bluetooth
platform_allow: nrf5340dk_nrf5340_cpunet
extra_args: DTC_OVERLAY_FILE=./boards/nrf5340dk_nrf5340_cpunet_df.overlay
extra_configs:
- CONFIG_BT_CTLR_DF=y
tags:
- uart
- bluetooth
sample.bluetooth.hci_uart.nrf52833.df.iq_report:
harness: bluetooth
platform_allow: nrf52833dk_nrf52833
extra_args: DTC_OVERLAY_FILE=./boards/nrf52833dk_nrf52833_df.overlay
extra_configs:
- CONFIG_BT_CTLR_DF=y
- CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT=y
tags:
- uart
- bluetooth
sample.bluetooth.hci_uart.nrf5340_netcore.df.iq_report:
harness: bluetooth
platform_allow: nrf5340dk_nrf5340_cpunet
extra_args: DTC_OVERLAY_FILE=./boards/nrf5340dk_nrf5340_cpunet_df.overlay
extra_configs:
- CONFIG_BT_CTLR_DF=y
- CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT=y
tags:
- uart
- bluetooth
sample.bluetooth.hci_uart.nrf52833.all:
harness: bluetooth
platform_allow: nrf52833dk_nrf52833
integration_platforms:
- nrf52833dk_nrf52833
extra_args:
- OVERLAY_CONFIG=overlay-all-bt_ll_sw_split.conf
- DTC_OVERLAY_FILE=./boards/nrf52833dk_nrf52833_df.overlay
tags:
- uart
- bluetooth

450
src/main.c Normal file
View File

@@ -0,0 +1,450 @@
/*
* Copyright (c) 2016 Nordic Semiconductor ASA
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/arch/cpu.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/util.h>
#include <zephyr/device.h>
#include <zephyr/init.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/net/buf.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/l2cap.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/buf.h>
#include <zephyr/bluetooth/hci_raw.h>
#define LOG_MODULE_NAME hci_uart
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
static const struct device *const hci_uart_dev =
DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_c2h_uart));
static K_THREAD_STACK_DEFINE(tx_thread_stack, CONFIG_BT_HCI_TX_STACK_SIZE);
static struct k_thread tx_thread_data;
static K_FIFO_DEFINE(tx_queue);
/* RX in terms of bluetooth communication */
static K_FIFO_DEFINE(uart_tx_queue);
#define H4_CMD 0x01
#define H4_ACL 0x02
#define H4_SCO 0x03
#define H4_EVT 0x04
#define H4_ISO 0x05
/* Receiver states. */
#define ST_IDLE 0 /* Waiting for packet type. */
#define ST_HDR 1 /* Receiving packet header. */
#define ST_PAYLOAD 2 /* Receiving packet payload. */
#define ST_DISCARD 3 /* Dropping packet. */
/* Length of a discard/flush buffer.
* This is sized to align with a BLE HCI packet:
* 1 byte H:4 header + 32 bytes ACL/event data
* Bigger values might overflow the stack since this is declared as a local
* variable, smaller ones will force the caller to call into discard more
* often.
*/
#define H4_DISCARD_LEN 33
static int h4_read(const struct device *uart, uint8_t *buf, size_t len)
{
int rx = uart_fifo_read(uart, buf, len);
LOG_DBG("read %d req %d", rx, len);
return rx;
}
static bool valid_type(uint8_t type)
{
return (type == H4_CMD) | (type == H4_ACL) | (type == H4_ISO);
}
/* Function expects that type is validated and only CMD, ISO or ACL will be used. */
static uint32_t get_len(const uint8_t *hdr_buf, uint8_t type)
{
switch (type) {
case H4_CMD:
return ((const struct bt_hci_cmd_hdr *)hdr_buf)->param_len;
case H4_ISO:
return bt_iso_hdr_len(
sys_le16_to_cpu(((const struct bt_hci_iso_hdr *)hdr_buf)->len));
case H4_ACL:
return sys_le16_to_cpu(((const struct bt_hci_acl_hdr *)hdr_buf)->len);
default:
LOG_ERR("Invalid type: %u", type);
return 0;
}
}
/* Function expects that type is validated and only CMD, ISO or ACL will be used. */
static int hdr_len(uint8_t type)
{
switch (type) {
case H4_CMD:
return sizeof(struct bt_hci_cmd_hdr);
case H4_ISO:
return sizeof(struct bt_hci_iso_hdr);
case H4_ACL:
return sizeof(struct bt_hci_acl_hdr);
default:
LOG_ERR("Invalid type: %u", type);
return 0;
}
}
static void rx_isr(void)
{
static struct net_buf *buf;
static int remaining;
static uint8_t state;
static uint8_t type;
static uint8_t hdr_buf[MAX(sizeof(struct bt_hci_cmd_hdr),
sizeof(struct bt_hci_acl_hdr))];
int read;
do {
switch (state) {
case ST_IDLE:
/* Get packet type */
read = h4_read(hci_uart_dev, &type, sizeof(type));
/* since we read in loop until no data is in the fifo,
* it is possible that read = 0.
*/
if (read) {
if (valid_type(type)) {
/* Get expected header size and switch
* to receiving header.
*/
remaining = hdr_len(type);
state = ST_HDR;
} else {
LOG_WRN("Unknown header %d", type);
}
}
break;
case ST_HDR:
read = h4_read(hci_uart_dev,
&hdr_buf[hdr_len(type) - remaining],
remaining);
remaining -= read;
if (remaining == 0) {
/* Header received. Allocate buffer and get
* payload length. If allocation fails leave
* interrupt. On failed allocation state machine
* is reset.
*/
buf = bt_buf_get_tx(BT_BUF_H4, K_NO_WAIT,
&type, sizeof(type));
if (!buf) {
LOG_ERR("No available command buffers!");
state = ST_IDLE;
return;
}
remaining = get_len(hdr_buf, type);
net_buf_add_mem(buf, hdr_buf, hdr_len(type));
if (remaining > net_buf_tailroom(buf)) {
LOG_ERR("Not enough space in buffer");
net_buf_unref(buf);
state = ST_DISCARD;
} else {
state = ST_PAYLOAD;
}
}
break;
case ST_PAYLOAD:
read = h4_read(hci_uart_dev, net_buf_tail(buf),
remaining);
buf->len += read;
remaining -= read;
if (remaining == 0) {
/* Packet received */
LOG_DBG("putting RX packet in queue.");
net_buf_put(&tx_queue, buf);
state = ST_IDLE;
}
break;
case ST_DISCARD:
{
uint8_t discard[H4_DISCARD_LEN];
size_t to_read = MIN(remaining, sizeof(discard));
read = h4_read(hci_uart_dev, discard, to_read);
remaining -= read;
if (remaining == 0) {
state = ST_IDLE;
}
break;
}
default:
read = 0;
__ASSERT_NO_MSG(0);
break;
}
} while (read);
}
static void tx_isr(void)
{
static struct net_buf *buf;
int len;
if (!buf) {
buf = net_buf_get(&uart_tx_queue, K_NO_WAIT);
if (!buf) {
uart_irq_tx_disable(hci_uart_dev);
return;
}
}
len = uart_fifo_fill(hci_uart_dev, buf->data, buf->len);
net_buf_pull(buf, len);
if (!buf->len) {
net_buf_unref(buf);
buf = NULL;
}
}
static void bt_uart_isr(const struct device *unused, void *user_data)
{
ARG_UNUSED(unused);
ARG_UNUSED(user_data);
if (!(uart_irq_rx_ready(hci_uart_dev) ||
uart_irq_tx_ready(hci_uart_dev))) {
LOG_DBG("spurious interrupt");
}
if (uart_irq_tx_ready(hci_uart_dev)) {
tx_isr();
}
if (uart_irq_rx_ready(hci_uart_dev)) {
rx_isr();
}
}
static void tx_thread(void *p1, void *p2, void *p3)
{
while (1) {
struct net_buf *buf;
int err;
/* Wait until a buffer is available */
buf = net_buf_get(&tx_queue, K_FOREVER);
/* Pass buffer to the stack */
err = bt_send(buf);
if (err) {
LOG_ERR("Unable to send (err %d)", err);
net_buf_unref(buf);
}
/* Give other threads a chance to run if tx_queue keeps getting
* new data all the time.
*/
k_yield();
}
}
static int h4_send(struct net_buf *buf)
{
LOG_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf),
buf->len);
net_buf_put(&uart_tx_queue, buf);
uart_irq_tx_enable(hci_uart_dev);
return 0;
}
#if defined(CONFIG_BT_CTLR_ASSERT_HANDLER)
void bt_ctlr_assert_handle(char *file, uint32_t line)
{
uint32_t len = 0U, pos = 0U;
/* Disable interrupts, this is unrecoverable */
(void)irq_lock();
uart_irq_rx_disable(hci_uart_dev);
uart_irq_tx_disable(hci_uart_dev);
if (file) {
while (file[len] != '\0') {
if (file[len] == '/') {
pos = len + 1;
}
len++;
}
file += pos;
len -= pos;
}
uart_poll_out(hci_uart_dev, H4_EVT);
/* Vendor-Specific debug event */
uart_poll_out(hci_uart_dev, 0xff);
/* 0xAA + strlen + \0 + 32-bit line number */
uart_poll_out(hci_uart_dev, 1 + len + 1 + 4);
uart_poll_out(hci_uart_dev, 0xAA);
if (len) {
while (*file != '\0') {
uart_poll_out(hci_uart_dev, *file);
file++;
}
uart_poll_out(hci_uart_dev, 0x00);
}
uart_poll_out(hci_uart_dev, line >> 0 & 0xff);
uart_poll_out(hci_uart_dev, line >> 8 & 0xff);
uart_poll_out(hci_uart_dev, line >> 16 & 0xff);
uart_poll_out(hci_uart_dev, line >> 24 & 0xff);
while (1) {
}
}
#endif /* CONFIG_BT_CTLR_ASSERT_HANDLER */
static int hci_uart_init(void)
{
LOG_DBG("");
if (IS_ENABLED(CONFIG_USB_CDC_ACM)) {
if (usb_enable(NULL)) {
LOG_ERR("Failed to enable USB");
return -EINVAL;
}
}
if (!device_is_ready(hci_uart_dev)) {
LOG_ERR("HCI UART %s is not ready", hci_uart_dev->name);
return -EINVAL;
}
uart_irq_rx_disable(hci_uart_dev);
uart_irq_tx_disable(hci_uart_dev);
uart_irq_callback_set(hci_uart_dev, bt_uart_isr);
uart_irq_rx_enable(hci_uart_dev);
return 0;
}
SYS_INIT(hci_uart_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
#define HCI_CMD_ISO_TIMESYNC (0x100)
#include <zephyr/drivers/bluetooth/hci_driver.h>
uint8_t hci_cmd_iso_timesync_cb(struct net_buf *buf)
{
struct net_buf *rsp;
struct bt_hci_evt_cc_status *cc;
LOG_INF("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len);
LOG_INF("buf[0] = 0x%02x", buf->data[0]);
rsp = bt_hci_cmd_complete_create(BT_OP(BT_OGF_VS, HCI_CMD_ISO_TIMESYNC), sizeof(*cc));
cc = net_buf_add(rsp, sizeof(*cc));
cc->status = BT_HCI_ERR_SUCCESS;
if (IS_ENABLED(CONFIG_BT_HCI_RAW_H4)) {
net_buf_push_u8(rsp, H4_EVT);
}
h4_send( rsp );
// gpio_pin_configure_dt(&led, (buf->data[0] != 0) ? GPIO_OUTPUT_ACTIVE : GPIO_OUTPUT_INACTIVE);
return BT_HCI_ERR_SUCCESS;
}
int main(void)
{
/* incoming events and data from the controller */
K_FIFO_DEFINE(rx_queue);
int err;
LOG_DBG("Start");
__ASSERT(hci_uart_dev, "UART device is NULL");
/* Enable the raw interface, this will in turn open the HCI driver */
bt_enable_raw(&rx_queue);
if (IS_ENABLED(CONFIG_BT_WAIT_NOP)) {
/* Issue a Command Complete with NOP */
int i;
const struct {
const uint8_t h4;
const struct bt_hci_evt_hdr hdr;
const struct bt_hci_evt_cmd_complete cc;
} __packed cc_evt = {
.h4 = H4_EVT,
.hdr = {
.evt = BT_HCI_EVT_CMD_COMPLETE,
.len = sizeof(struct bt_hci_evt_cmd_complete),
},
.cc = {
.ncmd = 1,
.opcode = sys_cpu_to_le16(BT_OP_NOP),
},
};
for (i = 0; i < sizeof(cc_evt); i++) {
uart_poll_out(hci_uart_dev,
*(((const uint8_t *)&cc_evt)+i));
}
}
/* Register set_led_state command */
static struct bt_hci_raw_cmd_ext cmd_list = {
.op = BT_OP(BT_OGF_VS, HCI_CMD_ISO_TIMESYNC),
.min_len = 1,
.func = hci_cmd_iso_timesync_cb
};
bt_hci_raw_cmd_ext_register(&cmd_list, 1);
/* Spawn the TX thread and start feeding commands and data to the
* controller
*/
k_thread_create(&tx_thread_data, tx_thread_stack,
K_THREAD_STACK_SIZEOF(tx_thread_stack), tx_thread,
NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
k_thread_name_set(&tx_thread_data, "HCI uart TX");
while (1) {
struct net_buf *buf;
buf = net_buf_get(&rx_queue, K_FOREVER);
err = h4_send(buf);
if (err) {
LOG_ERR("Failed to send");
}
}
return 0;
}

12
uart1.overlay Normal file
View File

@@ -0,0 +1,12 @@
&uart1 {
status = "okay";
current-speed = <115200>;
};
/ {
chosen {
zephyr,bt-c2h-uart = &uart1;
};
};

17
usb.overlay Normal file
View File

@@ -0,0 +1,17 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
/ {
chosen {
zephyr,bt-c2h-uart = &cdc_acm_uart0;
};
};
&zephyr_udc0 {
cdc_acm_uart0: cdc_acm_uart0 {
compatible = "zephyr,cdc-acm-uart";
};
};