mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-24 13:43:38 +00:00
cc256x: ENABLE_CC256X_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND avoids lost bytes during baud rate change, updated docu
This commit is contained in:
parent
8eb8d46326
commit
39e7ee9f5d
@ -218,7 +218,9 @@ CC256xC | 0x9a1a | 6.12.26
|
||||
|
||||
**SCO data** is routed to the I2S/PCM interface but can be configured with the [HCI_VS_Write_SCO_Configuration](http://processors.wiki.ti.com/index.php/CC256x_VS_HCI_Commands#HCI_VS_Write_SCO_Configuration_.280xFE10.29) command.
|
||||
|
||||
**Baud rate** can be set with [HCI_VS_Update_UART_HCI_Baudrate](http://processors.wiki.ti.com/index.php/CC256x_VS_HCI_Commands#HCI_VS_Update_UART_HCI_Baudrate_.280xFF36.29). The chipset confirms the change with a command complete event after which the local UART is set to the new speed. Oddly enough, the CC256x chipsets ignore the incoming CTS line during this particular command complete response. See next paragraph for a workaround.
|
||||
**Baud rate** can be set with [HCI_VS_Update_UART_HCI_Baudrate](http://processors.wiki.ti.com/index.php/CC256x_VS_HCI_Commands#HCI_VS_Update_UART_HCI_Baudrate_.280xFF36.29). The chipset confirms the change with a command complete event after which the local UART is set to the new speed. Oddly enough, the CC256x chipsets ignore the incoming CTS line during this particular command complete response.
|
||||
|
||||
If you've implemented the hal_uart_dma.h without an additional ring buffer (as recommended!) and you have a bit of delay, e.g. because of thread switching on a RTOS, this could cause a UART overrun. If this happens, BTstack provides a workaround in the HCI H4 transport implementation by adding #define ENABLE_CC256X_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND to your btstack_config.h. If this is enabled, the H4 transport layer will resort to "deep packet inspection" to first check if its a TI controller and then wait for the HCI_VS_Update_UART_HCI_Baudrate. When detected, it will tweak the next UART read to expect the HCI Command Complete event.
|
||||
|
||||
**BD Addr** can be set with [HCI_VS_Write_BD_Addr](2.2.1 HCI_VS_Write_BD_Addr (0xFC06)) although all chipsets have an official address stored.
|
||||
|
||||
@ -237,105 +239,6 @@ The Makefile at *chipset/cc256x/Makefile.inc* is able to automatically download
|
||||
|
||||
SCO Data can be routed over HCI, so HFP Wide-Band Speech is supported.
|
||||
|
||||
**Work around for CTS bug while HCI Command Complete Event of HCI VS Update Baudrate with H4/eHCILL**
|
||||
|
||||
If you're using a RTOS port (e.g. FreeRTOS) and have implemented the *hal_uart_dma.h* API directly, chances are, you're getting a UART overrun errors in this situation, and the bootup will get stuck at this point.
|
||||
|
||||
BTstack currently cannot deal with this situation since it would need to request a read for the complete HCI Command Complete before sending the HCI VS Baudrate Command.
|
||||
|
||||
We recommend to add the following workaround in the *hal_uart_dma.h* implementation to deal with this bug in the lowest layer.
|
||||
|
||||
The idea is to detect the HCI VS Baudrate Command and then to ignore all received data for 100 ms. After that, send the appropriate HCI Command Complete Event to the HCI transport.
|
||||
|
||||
Let's assume that your hal_uart_dma.h implementation contains *hal_uart_dma_rx_complete()* and *hal_uart_dma_tx_complete* that are called when the corresponding asynchronous request has been completed, and that you've stored the registered callbacks in *rx_done_handler* and *tx_done_handler*. Please provide new functions *hal_uart_dma_sleep_ms* that just blocks (you might have needed a similar to implement the CC256x power cycle before) and *hci_uart_dma_rx_flush* that clear all errors and flushes all incoming buffers (might not be needed on most platforms).
|
||||
|
||||
// types & declaration
|
||||
static enum {
|
||||
CC256X_HACK_IDLE,
|
||||
CC256X_HACK_W4_SENT,
|
||||
CC256X_HACK_W4_READ_HEADER,
|
||||
CC256X_HACK_W4_READ_PAYLOAD,
|
||||
} cc256x_hack_state;
|
||||
|
||||
...
|
||||
|
||||
void hal_uart_dma_send_block(const uint8_t *buffer, uint16_t length){
|
||||
// detect CC256x set baudrate command
|
||||
const uint8_t baud_rate_command_prefix[] = { 0x01, 0x36, 0xff, 0x04};
|
||||
if (memcmp(data, baud_rate_command_prefix, sizeof(baud_rate_command_prefix)) == 0) {
|
||||
log_info("CC256x baud rate command detected");
|
||||
cc256x_hack_state = CC256X_HACK_W4_SENT;
|
||||
}
|
||||
|
||||
// your code to trigger buffer send follow
|
||||
...
|
||||
}
|
||||
|
||||
void hal_uart_dma_receive_block(uint8_t *buffer, uint16_t len){
|
||||
switch (cc256x_hack_state){
|
||||
case CC256X_HACK_W4_READ_HEADER:
|
||||
cc256x_hack_state = CC256X_HACK_W4_READ_PAYLOAD;
|
||||
// HCI Command Complete
|
||||
*buffer++ = 0x0e;
|
||||
*buffer++ = 0x04;
|
||||
(*rx_done_handler)();
|
||||
return;
|
||||
case CC256X_HACK_W4_READ_PAYLOAD:
|
||||
cc256x_hack_state = CC256X_HACK_IDLE;
|
||||
// commands 0, opcode 0xff36, status 0
|
||||
*buffer++ = 0x01;
|
||||
*buffer++ = 0x36;
|
||||
*buffer++ = 0xff;
|
||||
*buffer++ = 0x00;
|
||||
(*rx_done_handler)();
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// your code to trigger buffer read follows
|
||||
...
|
||||
}
|
||||
|
||||
static void hal_uart_dma_rx_complete(void){
|
||||
switch (cc256x_hack_state){
|
||||
case CC256X_HACK_W4_SENT:
|
||||
// ignore until sent & event received;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// your code to call complete handler, probably looks like
|
||||
if(rx_done_handler){
|
||||
(*rx_done_handler)();
|
||||
}
|
||||
}
|
||||
|
||||
static void tx_done_handler(void){
|
||||
// your code to call complete handler, probably looks like
|
||||
if(tx_done_handler){
|
||||
(*tx_done_handler)();
|
||||
|
||||
// cc256x hack
|
||||
switch (cc256x_hack_state){
|
||||
case CC256X_HACK_W4_SENT:
|
||||
log_info("cc256x hack: sleep");
|
||||
hal_uart_dma_sleep_ms(100);
|
||||
log_info("cc256x hack: flush");
|
||||
hal_uart_block_reset_rx();
|
||||
log_info("cc256x hack: simulate command complete");
|
||||
*read_bytes_data++ = 0x04;
|
||||
read_bytes_len--;
|
||||
cc256x_hack_state = CC256X_HACK_W4_READ_HEADER;
|
||||
(*rx_done_handler)();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## Toshiba
|
||||
|
||||
The Toshiba TC35661 Dual-Mode chipset is available in three variants: standalone incl. binary Bluetooth stack, as a module with embedded stack or with a regular HCI interface. The HCI variant has the model number TC35661–007.
|
||||
|
@ -81,7 +81,7 @@ ENABLE_LE_SECURE_CONNECTIONS | Enable LE Secure Connections using [mbed TLS libr
|
||||
ENABLE_LE_DATA_CHANNELS | Enable LE Data Channels in credit-based flow control mode
|
||||
ENABLE_LE_SIGNED_WRITE | Enable LE Signed Writes in ATT/GATT
|
||||
ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL | Enable HCI Controller to Host Flow Control, see below
|
||||
|
||||
ENABLE_CC256X_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND | Enable workaround for bug in CC256x Flow Control during baud rate change, see chipset docs.
|
||||
|
||||
### HCI Controller to Host Flow Control
|
||||
In general, BTstack relies on flow control of the HCI transport, either via Hardware CTS/RTS flow control for UART or regular USB flow control. If this is not possible, e.g on an SoC, BTstack can use HCI Controller to Host Flow Control by defining ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL. If enabled, the HCI Transport implementation must be able to buffer the specified packets. In addition, it also need to be able to buffer a few HCI Events. Using a low number of host buffers might result in less throughput.
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "btstack_debug.h"
|
||||
#include "hci.h"
|
||||
#include "hci_transport.h"
|
||||
#include "bluetooth_company_id.h"
|
||||
#include "btstack_uart_block.h"
|
||||
|
||||
#define ENABLE_LOG_EHCILL
|
||||
@ -139,6 +140,17 @@ static int read_pos;
|
||||
static uint8_t hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE + 1 + HCI_PACKET_BUFFER_SIZE]; // packet type + max(acl header + acl payload, event header + event data)
|
||||
static uint8_t * hci_packet = &hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE];
|
||||
|
||||
#ifdef ENABLE_CC256X_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND
|
||||
static const uint8_t local_version_event_prefix[] = { 0x04, 0x0e, 0x0c, 0x01, 0x01, 0x10};
|
||||
static const uint8_t baud_rate_command_prefix[] = { 0x01, 0x36, 0xff, 0x04};
|
||||
static enum {
|
||||
CC256X_WORKAROUND_IDLE,
|
||||
CC256X_WORKAROUND_CHIPSET_DETECTED,
|
||||
CC256X_WORKAROUND_BAUDRATE_COMMAND_SENT,
|
||||
CC256X_WORKAROUND_DONE
|
||||
} cc256x_workaround_state;
|
||||
#endif
|
||||
|
||||
static int hci_transport_h4_set_baudrate(uint32_t baudrate){
|
||||
log_info("hci_transport_h4_set_baudrate %u", baudrate);
|
||||
return btstack_uart->set_baudrate(baudrate);
|
||||
@ -212,12 +224,36 @@ static void hci_transport_h4_block_read(void){
|
||||
break;
|
||||
|
||||
case H4_W4_PAYLOAD:
|
||||
#ifdef ENABLE_CC256X_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND
|
||||
if (cc256x_workaround_state == CC256X_WORKAROUND_IDLE
|
||||
&& memcmp(hci_packet, local_version_event_prefix, sizeof(local_version_event_prefix)) == 0){
|
||||
if (little_endian_read_16(hci_packet, 11) == BLUETOOTH_COMPANY_ID_TEXAS_INSTRUMENTS_INC){
|
||||
// detect TI CC256x controller based on manufacturer
|
||||
log_info("Detected CC256x controller");
|
||||
cc256x_workaround_state = CC256X_WORKAROUND_CHIPSET_DETECTED;
|
||||
} else {
|
||||
// work around not needed
|
||||
log_info("Bluetooth controller not by TI");
|
||||
cc256x_workaround_state = CC256X_WORKAROUND_DONE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
packet_handler(hci_packet[0], &hci_packet[1], read_pos-1);
|
||||
hci_transport_h4_reset_statemachine();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CC256X_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND
|
||||
if (cc256x_workaround_state == CC256X_WORKAROUND_BAUDRATE_COMMAND_SENT){
|
||||
cc256x_workaround_state = CC256X_WORKAROUND_IDLE;
|
||||
// avoid flowcontrol problem by reading expected hci command complete event of 7 bytes in a single block read
|
||||
h4_state = H4_W4_PAYLOAD;
|
||||
bytes_to_read = 7;
|
||||
}
|
||||
#endif
|
||||
|
||||
hci_transport_h4_trigger_next_read();
|
||||
}
|
||||
|
||||
@ -252,11 +288,20 @@ static int hci_transport_h4_can_send_now(uint8_t packet_type){
|
||||
}
|
||||
|
||||
static int hci_transport_h4_send_packet(uint8_t packet_type, uint8_t * packet, int size){
|
||||
|
||||
// store packet type before actual data and increase size
|
||||
size++;
|
||||
packet--;
|
||||
*packet = packet_type;
|
||||
|
||||
#ifdef ENABLE_CC256X_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND
|
||||
if ((cc256x_workaround_state == CC256X_WORKAROUND_CHIPSET_DETECTED)
|
||||
&& (memcmp(packet, baud_rate_command_prefix, sizeof(baud_rate_command_prefix)) == 0)) {
|
||||
log_info("CC256x baud rate command detected, expect command complete event next");
|
||||
cc256x_workaround_state = CC256X_WORKAROUND_BAUDRATE_COMMAND_SENT;
|
||||
}
|
||||
#endif
|
||||
|
||||
// store request
|
||||
tx_len = size;
|
||||
tx_data = packet;
|
||||
|
Loading…
x
Reference in New Issue
Block a user