mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-30 04:42:19 +00:00 
			
		
		
		
	Added example(ESP32-C3), to use Bluetooth Controller through HCI UART transport
This commit is contained in:
		 wangmengyang
					wangmengyang
				
			
				
					committed by
					
						 xiongweichao
						xiongweichao
					
				
			
			
				
	
			
			
			 xiongweichao
						xiongweichao
					
				
			
						parent
						
							4a85b2256c
						
					
				
				
					commit
					9e96538a86
				
			| @@ -93,6 +93,13 @@ enum { | |||||||
|     ESP_BT_COEX_PHY_CODED_TX_RX_TIME_LIMIT_FORCE_ENABLE,         /*!< Always Enable the limit */ |     ESP_BT_COEX_PHY_CODED_TX_RX_TIME_LIMIT_FORCE_ENABLE,         /*!< Always Enable the limit */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | #define ESP_BT_HCI_TL_STATUS_OK            (0)   /*!< HCI_TL Tx/Rx operation status OK */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief callback function for HCI Transport Layer send/receive operations | ||||||
|  |  */ | ||||||
|  | typedef void (* esp_bt_hci_tl_callback_t) (void *arg, uint8_t status); | ||||||
|  |  | ||||||
| #ifdef CONFIG_BT_ENABLED | #ifdef CONFIG_BT_ENABLED | ||||||
|  |  | ||||||
| #define BT_CTRL_BLE_MAX_ACT_LIMIT           10  //Maximum BLE activity limitation | #define BT_CTRL_BLE_MAX_ACT_LIMIT           10  //Maximum BLE activity limitation | ||||||
| @@ -197,8 +204,8 @@ typedef struct { | |||||||
|     int (* _open)(void);                    /* hci tl open */ |     int (* _open)(void);                    /* hci tl open */ | ||||||
|     void (* _close)(void);                  /* hci tl close */ |     void (* _close)(void);                  /* hci tl close */ | ||||||
|     void (* _finish_transfers)(void);       /* hci tl finish trasnfers */ |     void (* _finish_transfers)(void);       /* hci tl finish trasnfers */ | ||||||
|     void (* _recv)(uint8_t *buf, uint32_t len, void (*callback) (void*, uint8_t), void* dummy); /* hci tl recv */ |     void (* _recv)(uint8_t *buf, uint32_t len, esp_bt_hci_tl_callback_t callback, void* arg); /* hci tl recv */ | ||||||
|     void (* _send)(uint8_t *buf, uint32_t len, void (*callback) (void*, uint8_t), void* dummy); /* hci tl send */ |     void (* _send)(uint8_t *buf, uint32_t len, esp_bt_hci_tl_callback_t callback, void* arg); /* hci tl send */ | ||||||
|     bool (* _flow_off)(void); /* hci tl flow off */ |     bool (* _flow_off)(void); /* hci tl flow off */ | ||||||
|     void (* _flow_on)(void); /* hci tl flow on */ |     void (* _flow_on)(void); /* hci tl flow on */ | ||||||
| } esp_bt_hci_tl_t; | } esp_bt_hci_tl_t; | ||||||
|   | |||||||
| @@ -20,12 +20,16 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include "uhci_types.h" | #include "uhci_types.h" | ||||||
| #include "soc/uhci_struct.h" | #include "soc/uhci_struct.h" | ||||||
| #include "soc/gdma_struct.h" |  | ||||||
|  |  | ||||||
| #define UHCI_DMA_INDEX 0 |  | ||||||
|  |  | ||||||
| #define UHCI_LL_GET_HW(num) (((num) == 0) ? (&UHCI0) : (NULL)) | #define UHCI_LL_GET_HW(num) (((num) == 0) ? (&UHCI0) : (NULL)) | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |     UHCI_RX_BREAK_CHR_EOF = 0x1, | ||||||
|  |     UHCI_RX_IDLE_EOF      = 0x2, | ||||||
|  |     UHCI_RX_LEN_EOF       = 0x4, | ||||||
|  |     UHCI_RX_EOF_MAX       = 0x7, | ||||||
|  | } uhci_rxeof_cfg_t; | ||||||
|  |  | ||||||
| static inline void uhci_ll_init(uhci_dev_t *hw) | static inline void uhci_ll_init(uhci_dev_t *hw) | ||||||
| { | { | ||||||
|     typeof(hw->conf0) conf0_reg; |     typeof(hw->conf0) conf0_reg; | ||||||
| @@ -38,7 +42,8 @@ static inline void uhci_ll_init(uhci_dev_t *hw) | |||||||
|  |  | ||||||
| static inline void uhci_ll_attach_uart_port(uhci_dev_t *hw, int uart_num) | static inline void uhci_ll_attach_uart_port(uhci_dev_t *hw, int uart_num) | ||||||
| { | { | ||||||
|     abort(); // TODO ESP32-C3 IDF-2117 |     hw->conf0.uart0_ce = (uart_num == 0)? 1: 0; | ||||||
|  |     hw->conf0.uart1_ce = (uart_num == 1)? 1: 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline void uhci_ll_set_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_char) | static inline void uhci_ll_set_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_char) | ||||||
| @@ -90,20 +95,6 @@ static inline void uhci_ll_set_swflow_ctrl_sub_chr(uhci_dev_t *hw, uhci_swflow_c | |||||||
|     hw->escape_conf.val = escape_conf_reg.val; |     hw->escape_conf.val = escape_conf_reg.val; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline void uhci_ll_dma_in_reset(uhci_dev_t *hw) |  | ||||||
| { |  | ||||||
|     (void)hw; |  | ||||||
|     GDMA.channel[UHCI_DMA_INDEX].in.in_conf0.in_rst = 1; |  | ||||||
|     GDMA.channel[UHCI_DMA_INDEX].in.in_conf0.in_rst = 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static inline void uhci_ll_dma_out_reset(uhci_dev_t *hw) |  | ||||||
| { |  | ||||||
|     (void)hw; |  | ||||||
|     GDMA.channel[UHCI_DMA_INDEX].out.out_conf0.out_rst = 1; |  | ||||||
|     GDMA.channel[UHCI_DMA_INDEX].out.out_conf0.out_rst = 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static inline void uhci_ll_enable_intr(uhci_dev_t *hw, uint32_t intr_mask) | static inline void uhci_ll_enable_intr(uhci_dev_t *hw, uint32_t intr_mask) | ||||||
| { | { | ||||||
|     hw->int_ena.val |= intr_mask; |     hw->int_ena.val |= intr_mask; | ||||||
| @@ -124,41 +115,6 @@ static inline uint32_t uhci_ll_get_intr(uhci_dev_t *hw) | |||||||
|     return hw->int_st.val; |     return hw->int_st.val; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline void uhci_ll_set_rx_dma(uhci_dev_t *hw, uint32_t addr) |  | ||||||
| { |  | ||||||
|     (void)hw; |  | ||||||
|     GDMA.channel[UHCI_DMA_INDEX].in.in_link.addr = addr; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static inline void uhci_ll_set_tx_dma(uhci_dev_t *hw, uint32_t addr) |  | ||||||
| { |  | ||||||
|     (void)hw; |  | ||||||
|     GDMA.channel[UHCI_DMA_INDEX].out.out_link.addr = addr; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static inline void uhci_ll_rx_dma_start(uhci_dev_t *hw) |  | ||||||
| { |  | ||||||
|     (void)hw; |  | ||||||
|     GDMA.channel[UHCI_DMA_INDEX].in.in_link.start = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static inline void uhci_ll_tx_dma_start(uhci_dev_t *hw) |  | ||||||
| { |  | ||||||
|     (void)hw; |  | ||||||
|     GDMA.channel[UHCI_DMA_INDEX].out.out_link.start = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static inline void uhci_ll_rx_dma_stop(uhci_dev_t *hw) |  | ||||||
| { |  | ||||||
|     (void)hw; |  | ||||||
|     GDMA.channel[UHCI_DMA_INDEX].in.in_link.stop = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static inline void uhci_ll_tx_dma_stop(uhci_dev_t *hw) |  | ||||||
| { |  | ||||||
|     (void)hw; |  | ||||||
|     GDMA.channel[UHCI_DMA_INDEX].out.out_link.stop = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static inline void uhci_ll_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode) | static inline void uhci_ll_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode) | ||||||
| { | { | ||||||
|   | |||||||
							
								
								
									
										54
									
								
								components/hal/esp32c3/include/hal/uhci_types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								components/hal/esp32c3/include/hal/uhci_types.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | // Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD | ||||||
|  | // | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | // you may not use this file except in compliance with the License. | ||||||
|  | // You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, software | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | // See the License for the specific language governing permissions and | ||||||
|  | // limitations under the License. | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Though the UHCI driver hasn't been published, some types are defined here | ||||||
|  | // for users to develop over the HAL. See example: controller_hci_uart_esp32c3 | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief UHCI escape sequence | ||||||
|  |  */ | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t seper_chr;        /*!< escape sequence character */ | ||||||
|  |     uint8_t sub_chr1;         /*!< escape sequence sub-character 1 */ | ||||||
|  |     uint8_t sub_chr2;         /*!< escape sequence sub-character 2 */ | ||||||
|  |     bool sub_chr_en;          /*!< enable use of sub-chaacter of escape sequence */ | ||||||
|  | } uhci_seper_chr_t; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief UHCI software flow control | ||||||
|  |  */ | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t xon_chr;          /*!< character for XON */ | ||||||
|  |     uint8_t xon_sub1;         /*!< sub-character 1 for XON */ | ||||||
|  |     uint8_t xon_sub2;         /*!< sub-character 2 for XON */ | ||||||
|  |     uint8_t xoff_chr;         /*!< character 2 for XOFF */ | ||||||
|  |     uint8_t xoff_sub1;        /*!< sub-character 1 for XOFF */ | ||||||
|  |     uint8_t xoff_sub2;        /*!< sub-character 2 for XOFF */ | ||||||
|  |     uint8_t flow_en;          /*!< enable use of software flow control */ | ||||||
|  | } uhci_swflow_ctrl_sub_chr_t; | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
| @@ -0,0 +1,6 @@ | |||||||
|  | # The following lines of boilerplate have to be in your project's | ||||||
|  | # CMakeLists in this exact order for cmake to work correctly | ||||||
|  | cmake_minimum_required(VERSION 3.5) | ||||||
|  |  | ||||||
|  | include($ENV{IDF_PATH}/tools/cmake/project.cmake) | ||||||
|  | project(controller_hci_uart_demo) | ||||||
							
								
								
									
										83
									
								
								examples/bluetooth/hci/controller_hci_uart_esp32c3/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								examples/bluetooth/hci/controller_hci_uart_esp32c3/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | |||||||
|  | ESP-IDF UART HCI Controller | ||||||
|  | ================================= | ||||||
|  | | Supported Targets | ESP32-C3 | | ||||||
|  | | ----------------- | -------- | | ||||||
|  |  | ||||||
|  | This example demonstrates how to configure the Bluetooth Low Energy Controller's HCI (Host Controller Interface) to communicate over UART. | ||||||
|  |  | ||||||
|  | Using this example, BLE radio capabilities of ESP32-C3 chip, can be: | ||||||
|  |  | ||||||
|  | 1. tested via standard HCI messages in Direct Test Mode | ||||||
|  |  | ||||||
|  | 2. used with external Bluetooth host stack installed on PC, or other MCU. | ||||||
|  |  | ||||||
|  | This example uses UHCI, GDMA together with UART to implement the HCI UART transport. | ||||||
|  |  | ||||||
|  | This example uses LL/register access directly, because the UHCI driver hasn't been implemented yet. | ||||||
|  |  | ||||||
|  | ## How to use example | ||||||
|  |  | ||||||
|  | ### Hardware Required | ||||||
|  |  | ||||||
|  | This example should be able to run on any commonly available ESP32-C3 development board. To connect UART to PC, another board such as ESP_Test Board or FT232 USB UART board is usually needed. | ||||||
|  |  | ||||||
|  | In this example, two UARTs are used: | ||||||
|  |  | ||||||
|  | - UART0 is used as normal output or by IDF monitor | ||||||
|  |  | ||||||
|  | - UART1 is used to convey HCI messages | ||||||
|  |  | ||||||
|  |  | ||||||
|  | RTS and CTS lines of UART1 are required. GPIO4, GPIO5, GPIO6, GPIO7 are used as TxD, RxD, RTS, CTS PINs of UART1, respectively. | ||||||
|  |  | ||||||
|  | In a frequently-used scenario, if ESP_Test Board is used, connect the TX0, RX0, RTS0, CTS0 and GND of ESP_Test Board to ESP32-C3 UART1 PINs, and Attach ESP_Test board to the host PC. | ||||||
|  |  | ||||||
|  | ### Configure the project | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | idf.py menuconfig | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | * Baudrate of UART1 can be configured in `Example Configuration > UART Baudrate for HCI` | ||||||
|  |  | ||||||
|  | ### Build and Flash | ||||||
|  |  | ||||||
|  | Build the project and flash it to the board, then run monitor tool to view serial output: | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | idf.py -p PORT flash monitor | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | (Replace PORT with the name of the serial port to use.) | ||||||
|  |  | ||||||
|  | (To exit the serial monitor, type ``Ctrl-]``.) | ||||||
|  |  | ||||||
|  | See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. | ||||||
|  |  | ||||||
|  | ## Example Output | ||||||
|  |  | ||||||
|  | The example sets up the HCI UART transport and enable Bluetooth Controller, after started. UART1 PIN and baudrate settings is printed at serial output: | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | I (296) gpio: GPIO[4]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 | ||||||
|  | I (296) gpio: GPIO[6]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 | ||||||
|  | I (306) gpio: GPIO[4]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 | ||||||
|  | I (316) gpio: GPIO[6]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 | ||||||
|  | I (326) BTDM_INIT: BT controller compile version [6ab3130] | ||||||
|  | I (336) coexist: coexist rom version 8459080 | ||||||
|  | I (336) phy_init: phy_version 500,985899c,Apr 19 2021,16:05:08 | ||||||
|  | I (466) system_api: Base MAC address is not set | ||||||
|  | I (466) system_api: read default base MAC address from EFUSE | ||||||
|  | I (476) BTDM_INIT: Bluetooth MAC: 7c:df:a1:40:3f:16 | ||||||
|  |  | ||||||
|  | I (476) UHCI: HCI messages can be communicated over UART1: | ||||||
|  | --PINs: TxD 4, RxD 5, RTS 6, CTS 7 | ||||||
|  | --Baudrate: 921600 | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | After these output occurs, HCI messages can be commnunicated over UART1. | ||||||
|  |  | ||||||
|  | ## Troubleshooting | ||||||
|  |  | ||||||
|  | ## Example Breakdown | ||||||
|  |  | ||||||
| @@ -0,0 +1,2 @@ | |||||||
|  | idf_component_register(SRCS "uhci_uart_demo.c" | ||||||
|  |                     INCLUDE_DIRS "") | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | menu "Example Configuration" | ||||||
|  |  | ||||||
|  |     config EXAMPLE_HCI_UART_BAUDRATE | ||||||
|  |         int "UART Baudrate for HCI" | ||||||
|  |         range 115200 921600 | ||||||
|  |         default 115200 | ||||||
|  |         help | ||||||
|  |             UART Baudrate for HCI. Please use standard baudrate. | ||||||
|  |  | ||||||
|  | endmenu | ||||||
| @@ -0,0 +1,280 @@ | |||||||
|  | /* | ||||||
|  |    This example code is in the Public Domain (or CC0 licensed, at your option.) | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, this | ||||||
|  |    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR | ||||||
|  |    CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <string.h> | ||||||
|  | #include "driver/periph_ctrl.h" | ||||||
|  | #include "driver/gpio.h" | ||||||
|  | #include "driver/uart.h" | ||||||
|  | #include "soc/lldesc.h" | ||||||
|  | #include "esp_private/gdma.h" | ||||||
|  | #include "hal/uhci_ll.h" | ||||||
|  | #include "esp_bt.h" | ||||||
|  | #include "esp_log.h" | ||||||
|  |  | ||||||
|  | static const char *tag = "UHCI"; | ||||||
|  |  | ||||||
|  | #define UART_HCI_NUM       (1) | ||||||
|  |  | ||||||
|  | #define UART_RX_THRS       (120) | ||||||
|  |  | ||||||
|  | #define GPIO_UART_TXD_OUT  (4) | ||||||
|  | #define GPIO_UART_RXD_IN   (5) | ||||||
|  | #define GPIO_UART_RTS_OUT  (6) | ||||||
|  | #define GPIO_UART_CTS_IN   (7) | ||||||
|  |  | ||||||
|  | #define GPIO_OUTPUT_PIN_SEL  ((1ULL<<GPIO_UART_TXD_OUT) | (1ULL<<GPIO_UART_RTS_OUT)) | ||||||
|  | #define GPIO_INPUT_PIN_SEL   ((1ULL<<GPIO_UART_RXD_IN) | (1ULL<<GPIO_UART_CTS_IN)) | ||||||
|  |  | ||||||
|  | // Operation functions for HCI UART Transport Layer | ||||||
|  | static bool hci_uart_tl_init(void); | ||||||
|  | static void hci_uart_tl_deinit(void); | ||||||
|  | static void hci_uart_tl_recv_async(uint8_t *buf, uint32_t size, esp_bt_hci_tl_callback_t callback, void *arg); | ||||||
|  | static void hci_uart_tl_send_async(uint8_t *buf, uint32_t size, esp_bt_hci_tl_callback_t callback, void *arg); | ||||||
|  | static void hci_uart_tl_flow_on(void); | ||||||
|  | static bool hci_uart_tl_flow_off(void); | ||||||
|  | static void hci_uart_tl_finish_transfers(void); | ||||||
|  |  | ||||||
|  | struct uart_txrxchannel { | ||||||
|  |     esp_bt_hci_tl_callback_t callback; | ||||||
|  |     void *arg; | ||||||
|  |     lldesc_t link; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct uart_env_tag { | ||||||
|  |     struct uart_txrxchannel tx; | ||||||
|  |     struct uart_txrxchannel rx; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct uart_env_tag uart_env; | ||||||
|  |  | ||||||
|  | static volatile uhci_dev_t *s_uhci_hw = &UHCI0; | ||||||
|  | static gdma_channel_handle_t s_rx_channel; | ||||||
|  | static gdma_channel_handle_t s_tx_channel; | ||||||
|  |  | ||||||
|  | static esp_bt_hci_tl_t s_hci_uart_tl_funcs = { | ||||||
|  |     ._magic = ESP_BT_HCI_TL_MAGIC_VALUE, | ||||||
|  |     ._version = ESP_BT_HCI_TL_VERSION, | ||||||
|  |     ._reserved = 0, | ||||||
|  |     ._open = (void *)hci_uart_tl_init, | ||||||
|  |     ._close = (void *)hci_uart_tl_deinit, | ||||||
|  |     ._finish_transfers = (void *)hci_uart_tl_finish_transfers, | ||||||
|  |     ._recv = (void *)hci_uart_tl_recv_async, | ||||||
|  |     ._send = (void *)hci_uart_tl_send_async, | ||||||
|  |     ._flow_on = (void *)hci_uart_tl_flow_on, | ||||||
|  |     ._flow_off = (void *)hci_uart_tl_flow_off, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static bool hci_uart_tl_init(void) | ||||||
|  | { | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void hci_uart_tl_deinit(void) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static IRAM_ATTR void hci_uart_tl_recv_async(uint8_t *buf, uint32_t size, esp_bt_hci_tl_callback_t callback, void *arg) | ||||||
|  | { | ||||||
|  |     assert(buf != NULL); | ||||||
|  |     assert(size != 0); | ||||||
|  |     assert(callback != NULL); | ||||||
|  |     uart_env.rx.callback = callback; | ||||||
|  |     uart_env.rx.arg = arg; | ||||||
|  |  | ||||||
|  |     memset(&uart_env.rx.link, 0, sizeof(lldesc_t)); | ||||||
|  |     uart_env.rx.link.buf = buf; | ||||||
|  |     uart_env.rx.link.size = size; | ||||||
|  |  | ||||||
|  |     s_uhci_hw->pkt_thres.thrs = size; | ||||||
|  |  | ||||||
|  |     gdma_start(s_rx_channel, (intptr_t)(&uart_env.rx.link)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static IRAM_ATTR void hci_uart_tl_send_async(uint8_t *buf, uint32_t size, esp_bt_hci_tl_callback_t callback, void *arg) | ||||||
|  | { | ||||||
|  |     assert(buf != NULL); | ||||||
|  |     assert(size != 0); | ||||||
|  |     assert(callback != NULL); | ||||||
|  |  | ||||||
|  |     uart_env.tx.callback = callback; | ||||||
|  |     uart_env.tx.arg = arg; | ||||||
|  |  | ||||||
|  |     memset(&uart_env.tx.link, 0, sizeof(lldesc_t)); | ||||||
|  |     uart_env.tx.link.length = size; | ||||||
|  |     uart_env.tx.link.buf = buf; | ||||||
|  |     uart_env.tx.link.eof = 1; | ||||||
|  |  | ||||||
|  |     gdma_start(s_tx_channel, (intptr_t)(&uart_env.tx.link)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void hci_uart_tl_flow_on(void) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static bool hci_uart_tl_flow_off(void) | ||||||
|  | { | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void hci_uart_tl_finish_transfers(void) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static IRAM_ATTR bool hci_uart_tl_rx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) | ||||||
|  | { | ||||||
|  |     assert(dma_chan == s_rx_channel); | ||||||
|  |     assert(uart_env.rx.callback != NULL); | ||||||
|  |     esp_bt_hci_tl_callback_t callback = uart_env.rx.callback; | ||||||
|  |     void *arg = uart_env.rx.arg; | ||||||
|  |  | ||||||
|  |     // clear callback pointer | ||||||
|  |     uart_env.rx.callback = NULL; | ||||||
|  |     uart_env.rx.arg = NULL; | ||||||
|  |  | ||||||
|  |     // call handler | ||||||
|  |     callback(arg, ESP_BT_HCI_TL_STATUS_OK); | ||||||
|  |  | ||||||
|  |     // send notification to Bluetooth Controller task | ||||||
|  |     esp_bt_h4tl_eif_io_event_notify(1); | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static IRAM_ATTR bool hci_uart_tl_tx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) | ||||||
|  | { | ||||||
|  |     assert(dma_chan == s_tx_channel); | ||||||
|  |     assert(uart_env.tx.callback != NULL); | ||||||
|  |     esp_bt_hci_tl_callback_t callback = uart_env.tx.callback; | ||||||
|  |     void *arg = uart_env.tx.arg; | ||||||
|  |  | ||||||
|  |     // clear callback pointer | ||||||
|  |     uart_env.tx.callback = NULL; | ||||||
|  |     uart_env.tx.arg = NULL; | ||||||
|  |  | ||||||
|  |     // call handler | ||||||
|  |     callback(arg, ESP_BT_HCI_TL_STATUS_OK); | ||||||
|  |  | ||||||
|  |     // send notification to Bluetooth Controller task | ||||||
|  |     esp_bt_h4tl_eif_io_event_notify(1); | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void uart_gpio_set(void) | ||||||
|  | { | ||||||
|  |     gpio_config_t io_output_conf = { | ||||||
|  |         .intr_type = GPIO_PIN_INTR_DISABLE,    //disable interrupt | ||||||
|  |         .mode = GPIO_MODE_OUTPUT,    // output mode | ||||||
|  |         .pin_bit_mask = GPIO_OUTPUT_PIN_SEL,    // bit mask of the output pins | ||||||
|  |         .pull_down_en = 0,    // disable pull-down mode | ||||||
|  |         .pull_up_en = 0,    // disable pull-up mode | ||||||
|  |     }; | ||||||
|  |     gpio_config(&io_output_conf); | ||||||
|  |  | ||||||
|  |     gpio_config_t io_input_conf = { | ||||||
|  |         .intr_type = GPIO_PIN_INTR_DISABLE,    //disable interrupt | ||||||
|  |         .mode = GPIO_MODE_INPUT,    // input mode | ||||||
|  |         .pin_bit_mask = GPIO_OUTPUT_PIN_SEL,  // bit mask of the input pins | ||||||
|  |         .pull_down_en = 0,    // disable pull-down mode | ||||||
|  |         .pull_up_en = 0,    // disable pull-down mode | ||||||
|  |     }; | ||||||
|  |     gpio_config(&io_input_conf); | ||||||
|  |  | ||||||
|  |     uart_set_pin(UART_HCI_NUM, GPIO_UART_TXD_OUT, GPIO_UART_RXD_IN, GPIO_UART_RTS_OUT, GPIO_UART_CTS_IN); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void uhci_uart_install(void) | ||||||
|  | { | ||||||
|  |     periph_module_enable(PERIPH_UHCI0_MODULE); | ||||||
|  |     periph_module_reset(PERIPH_UHCI0_MODULE); | ||||||
|  |  | ||||||
|  |     periph_module_enable(PERIPH_UART1_MODULE); | ||||||
|  |     periph_module_reset(PERIPH_UART1_MODULE); | ||||||
|  |  | ||||||
|  |     uart_gpio_set(); | ||||||
|  |  | ||||||
|  |     // configure UART1 | ||||||
|  |     uart_config_t uart_config = { | ||||||
|  |         .baud_rate = CONFIG_EXAMPLE_HCI_UART_BAUDRATE, | ||||||
|  |         .data_bits = UART_DATA_8_BITS, | ||||||
|  |         .parity = UART_PARITY_DISABLE, | ||||||
|  |         .stop_bits = UART_STOP_BITS_1, | ||||||
|  |         .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS, | ||||||
|  |         .rx_flow_ctrl_thresh = UART_RX_THRS, | ||||||
|  |         .source_clk = UART_SCLK_APB, | ||||||
|  |     }; | ||||||
|  |     ESP_ERROR_CHECK(uart_param_config(UART_HCI_NUM, &uart_config)); | ||||||
|  |  | ||||||
|  |     // install DMA driver | ||||||
|  |     gdma_channel_alloc_config_t tx_channel_config = { | ||||||
|  |         .flags.reserve_sibling = 1, | ||||||
|  |         .direction = GDMA_CHANNEL_DIRECTION_TX, | ||||||
|  |     }; | ||||||
|  |     ESP_ERROR_CHECK(gdma_new_channel(&tx_channel_config, &s_tx_channel)); | ||||||
|  |     gdma_channel_alloc_config_t rx_channel_config = { | ||||||
|  |         .direction = GDMA_CHANNEL_DIRECTION_RX, | ||||||
|  |         .sibling_chan = s_tx_channel, | ||||||
|  |     }; | ||||||
|  |     ESP_ERROR_CHECK(gdma_new_channel(&rx_channel_config, &s_rx_channel)); | ||||||
|  |  | ||||||
|  |     gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UART, 0)); | ||||||
|  |     gdma_connect(s_rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UART, 0)); | ||||||
|  |  | ||||||
|  |     gdma_strategy_config_t strategy_config = { | ||||||
|  |         .auto_update_desc = false, | ||||||
|  |         .owner_check = false | ||||||
|  |     }; | ||||||
|  |     gdma_apply_strategy(s_tx_channel, &strategy_config); | ||||||
|  |     gdma_apply_strategy(s_rx_channel, &strategy_config); | ||||||
|  |  | ||||||
|  |     gdma_rx_event_callbacks_t rx_cbs = { | ||||||
|  |         .on_recv_eof = hci_uart_tl_rx_eof_callback | ||||||
|  |     }; | ||||||
|  |     gdma_register_rx_event_callbacks(s_rx_channel, &rx_cbs, NULL); | ||||||
|  |  | ||||||
|  |     gdma_tx_event_callbacks_t tx_cbs = { | ||||||
|  |         .on_trans_eof = hci_uart_tl_tx_eof_callback | ||||||
|  |     }; | ||||||
|  |     gdma_register_tx_event_callbacks(s_tx_channel, &tx_cbs, NULL); | ||||||
|  |  | ||||||
|  |     // configure UHCI | ||||||
|  |     uhci_ll_init(s_uhci_hw); | ||||||
|  |     uhci_ll_set_eof_mode(s_uhci_hw, UHCI_RX_LEN_EOF); | ||||||
|  |     // disable software flow control | ||||||
|  |     s_uhci_hw->escape_conf.val = 0; | ||||||
|  |     uhci_ll_attach_uart_port(s_uhci_hw, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void app_main(void) | ||||||
|  | { | ||||||
|  |     esp_err_t ret; | ||||||
|  |  | ||||||
|  |     uhci_uart_install(); | ||||||
|  |  | ||||||
|  |     esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); | ||||||
|  |     bt_cfg.hci_tl_funcs = &s_hci_uart_tl_funcs; | ||||||
|  |  | ||||||
|  |     ret = esp_bt_controller_init(&bt_cfg); | ||||||
|  |     if (ret != ESP_OK) { | ||||||
|  |         ESP_LOGE(tag, "Bluetooth Controller initialize failed: %s", esp_err_to_name(ret)); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); | ||||||
|  |     if (ret != ESP_OK) { | ||||||
|  |         ESP_LOGE(tag, "Bluetooth Controller initialize failed: %s", esp_err_to_name(ret)); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ESP_LOGI(tag, "HCI messages can be communicated over UART%d: \n" | ||||||
|  |              "--PINs: TxD %d, RxD %d, RTS %d, CTS %d\n" | ||||||
|  |              "--Baudrate: %d", UART_HCI_NUM, | ||||||
|  |              GPIO_UART_TXD_OUT, GPIO_UART_RXD_IN, GPIO_UART_RTS_OUT, GPIO_UART_CTS_IN, | ||||||
|  |              CONFIG_EXAMPLE_HCI_UART_BAUDRATE); | ||||||
|  | } | ||||||
| @@ -0,0 +1,12 @@ | |||||||
|  | # | ||||||
|  | # Automatically generated file. DO NOT EDIT. | ||||||
|  | # Espressif IoT Development Framework (ESP-IDF) Project Configuration | ||||||
|  | # | ||||||
|  |  | ||||||
|  | CONFIG_BT_ENABLED=y | ||||||
|  | CONFIG_BT_CTRL_ESP32C3=y | ||||||
|  | CONFIG_BT_CTRL_HCI_MODE_UART_H4=y | ||||||
|  | CONFIG_BT_CTRL_HCI_TL=0 | ||||||
|  | CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP=n | ||||||
|  | CONFIG_BT_CTRL_BLE_SCAN_DUPL=n | ||||||
|  | # End of deprecated options | ||||||
		Reference in New Issue
	
	Block a user