bluekitchen文件树结构:
可以看出:
1)chipset下是bluekitchen目前所支持的所有bt chip集合
2)platform下是可供选择的跑bluekitchen协议栈的软件平台,比如embedded(即裸机系统),freertos,posix,windows等
3)example下是各种profile和service demo
我们在port下添加stm32f103zet6_csr8x11例程。这样platform对应embedded,chipset对应csr,我们需要做的是实现hci driver,hci log driver以及用来管理连接设备信息的flash driver。
platform->embedded
btstack_port.c中的几个关键函数:
(1)实现gcc下printf的底层io函数_write
int _write(int file, char *ptr, int len){
#if 1
uint8_t cr = '\r';
int i;
if (file == STDOUT_FILENO || file == STDERR_FILENO) {
#if 1
for (i = 0; i < len; i++) {
if (ptr[i] == '\n') {
HAL_UART_Transmit( &huart1, &cr, 1, HAL_MAX_DELAY );
}
HAL_UART_Transmit( &huart1, (uint8_t *) &ptr[i], 1, HAL_MAX_DELAY );
}
#endif
return i;
}
errno = EIO;
return -1;
#else
return len;
#endif
}
(2)实现HCI driver (UART2) TX & RX callback的设置接口
//stm32 UART2 hal tx complete callback,tx完成时调用,这个函数会替代stm32 hal中的同名weak symbol
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
if (huart == &huart2){
(*tx_done_handler)();
}
}
//stm32 UART2 hal rx complete callback,rx完成时调用,这个函数会替代stm32 hal中的同名weak symbol
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
if (huart == &huart2){
(*rx_done_handler)();
}
}
//设置rx callback
void hal_uart_dma_set_block_received( void (*the_block_handler)(void)){
rx_done_handler = the_block_handler;
}
//设置tx callback
void hal_uart_dma_set_block_sent( void (*the_block_handler)(void)){
tx_done_handler = the_block_handler;
}
(3)实现HCI driver TX & RX函数,以及HCI log driver
void hal_uart_dma_send_block(const uint8_t *data, uint16_t size){
HAL_UART_Transmit_DMA( &huart2, (uint8_t *) data, size);
}
void hal_uart_dma_receive_block(uint8_t *data, uint16_t size){
HAL_UART_Receive_DMA( &huart2, data, size );
}
void hal_uart_dma_send_block_for_hci(const uint8_t *data, uint16_t size){
HAL_UART_Transmit( &huart3, (uint8_t *) data, size, HAL_MAX_DELAY );
}
bluekitchen TX & RX数据流大致如下:
(4)为了简化问题,我们先不实现flash driver,内容全部放空
(5)最后是协议栈的配置:
void port_main(void){
// start with BTstack init - especially configure HCI Transport
btstack_memory_init();
btstack_run_loop_init(btstack_run_loop_embedded_get_instance());
// uncomment to enable packet logger
#ifdef ENABLE_SEGGER_RTT
// hci_dump_init(hci_dump_segger_rtt_stdout_get_instance());
#else
hci_dump_init(hci_dump_embedded_stdout_get_instance());
#endif
// init HCI
hci_init(hci_transport_h4_instance(btstack_uart_block_embedded_instance()), (void*) &config);
hci_set_chipset(btstack_chipset_csr_instance());
#if 0
// setup TLV Flash Sector implementation
const hal_flash_bank_t * hal_flash_bank_impl = hal_flash_bank_stm32_init_instance(
&hal_flash_bank_context,
HAL_FLASH_BANK_SIZE,
HAL_FLASH_BANK_0_SECTOR,
HAL_FLASH_BANK_1_SECTOR,
HAL_FLASH_BANK_0_ADDR,
HAL_FLASH_BANK_1_ADDR);
const btstack_tlv_t * btstack_tlv_impl = btstack_tlv_flash_bank_init_instance(
&btstack_tlv_flash_bank_context,
hal_flash_bank_impl,
&hal_flash_bank_context);
// setup global tlv
btstack_tlv_set_instance(btstack_tlv_impl, &btstack_tlv_flash_bank_context);
// setup Link Key DB using TLV
const btstack_link_key_db_t * btstack_link_key_db = btstack_link_key_db_tlv_get_instance(btstack_tlv_impl, &btstack_tlv_flash_bank_context);
hci_set_link_key_db(btstack_link_key_db);
// setup LE Device DB using TLV
le_device_db_tlv_configure(btstack_tlv_impl, &btstack_tlv_flash_bank_context);
#endif
#ifdef HAVE_HAL_AUDIO
// setup audio
btstack_audio_sink_set_instance(btstack_audio_embedded_sink_get_instance());
btstack_audio_source_set_instance(btstack_audio_embedded_source_get_instance());
#endif
// inform about BTstack state
hci_event_callback_registration.callback = &packet_handler;
hci_add_event_handler(&hci_event_callback_registration);
// hand over to btstack embedded code
btstack_main(0, NULL);
// go
btstack_run_loop_execute();
}
编译工程后开始调试,记录下遇到的几个问题。
Q1:controller有上报event,但是格式不正确:(开机后会重新调整波特率,导致波特率不匹配)
首先需要解决2个问题:
1)system log重叠和丢失的问题 <uart1 tx & rx开DMA>
2)hci logging tool crash问题(看现象似乎是波特率太快,tool收不过来)
已解决:波特率太高,丢包,导致logging tool内存越界
Q2:似乎uart1 & uart2 DMA通道有冲突,使用uart1 DMA来传输log时,uart2无法正确收controller event?
暂无法解释。简化问题,只开uart2 RX & TX DMA。
Q3:在下完hci_reset_cm后,下read_local_version_cmd,无法收到正确的hci_evt,流程中断?
奇怪的现象,关闭uart1 hci dump后,就正常了。
更进一步,在如下函数中只打印message type就可以正常接收controller event:
太诡异了,无法理解!!!!!!
会不会是因为在UART2 RX ISR中调用printf???
可以排除这个猜想。
Q4:将波特率改为921600后,无法工作,收不到event。
暂未解决。
Q5:开启可见性后,使用手机去连接设备,会遇到event | acl解析错误:
对比正常的log:(红框中的就是丢失数据的hci event)
从发送完Read_Remote_Supported_Features cmd开始,event packet就丢失偶数次序的byte?
问题的原因终于找到了,在bluekitchen原始仓库的closed issue中,发现有人遇到了同样的问题,参考bluekitchen团队写的开发blog:https://bluekitchen-gmbh.com/btstack-port-for-stm32-f4-discovery-board-with-cc256x/
发现是UART2 RX DMA的使用上出了问题,bluekitchen hci_transport_h4.c 读数据的策略是分批次读取,1)hci_packet_type, 2)packet_header, 3)payload,在1)和2)之间的数据会丢失:
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(huart);
/* Set Reception type to Standard reception */
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
return(UART_Start_Receive_DMA(huart, pData, Size));
}
else
{
return HAL_BUSY;
}
}
HAL_StatusTypeDef UART_Start_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
uint32_t *tmp;
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
/* Set the UART DMA transfer complete callback */
huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt;
/* Set the UART DMA Half transfer complete callback */
huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt;
/* Set the DMA error callback */
huart->hdmarx->XferErrorCallback = UART_DMAError;
/* Set the DMA abort callback */
huart->hdmarx->XferAbortCallback = NULL;
/* Enable the DMA stream */
tmp = (uint32_t *)&pData;
HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t *)tmp, Size);
/* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */
//__HAL_UART_CLEAR_OREFLAG(huart);
/* Process Unlocked */
__HAL_UNLOCK(huart);
/* Enable the UART Parity Error Interrupt */
SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);
/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
SET_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* Enable the DMA transfer for the receiver request by setting the DMAR bit
in the UART CR3 register */
SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);
return HAL_OK;
}
#define __HAL_UART_CLEAR_OREFLAG(__HANDLE__) __HAL_UART_CLEAR_PEFLAG(__HANDLE__)
#define __HAL_UART_CLEAR_PEFLAG(__HANDLE__) \
do{ \
__IO uint32_t tmpreg = 0x00U; \
tmpreg = (__HANDLE__)->Instance->SR; \
tmpreg = (__HANDLE__)->Instance->DR; \
UNUSED(tmpreg); \
} while(0U)
__HAL_UART_CLEAR_OREFLAG(HANDLE)
这个宏会读uart状态寄存器和数据寄存器,当然会丢失数据。。。。。
屏蔽掉这段代码一切问题都解决了。
版权声明:本文为CSDN博主「熟能生巧啊」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_38177846/article/details/122573119
bluekitchen文件树结构:
可以看出:
1)chipset下是bluekitchen目前所支持的所有bt chip集合
2)platform下是可供选择的跑bluekitchen协议栈的软件平台,比如embedded(即裸机系统),freertos,posix,windows等
3)example下是各种profile和service demo
我们在port下添加stm32f103zet6_csr8x11例程。这样platform对应embedded,chipset对应csr,我们需要做的是实现hci driver,hci log driver以及用来管理连接设备信息的flash driver。
platform->embedded
btstack_port.c中的几个关键函数:
(1)实现gcc下printf的底层io函数_write
int _write(int file, char *ptr, int len){
#if 1
uint8_t cr = '\r';
int i;
if (file == STDOUT_FILENO || file == STDERR_FILENO) {
#if 1
for (i = 0; i < len; i++) {
if (ptr[i] == '\n') {
HAL_UART_Transmit( &huart1, &cr, 1, HAL_MAX_DELAY );
}
HAL_UART_Transmit( &huart1, (uint8_t *) &ptr[i], 1, HAL_MAX_DELAY );
}
#endif
return i;
}
errno = EIO;
return -1;
#else
return len;
#endif
}
(2)实现HCI driver (UART2) TX & RX callback的设置接口
//stm32 UART2 hal tx complete callback,tx完成时调用,这个函数会替代stm32 hal中的同名weak symbol
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
if (huart == &huart2){
(*tx_done_handler)();
}
}
//stm32 UART2 hal rx complete callback,rx完成时调用,这个函数会替代stm32 hal中的同名weak symbol
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
if (huart == &huart2){
(*rx_done_handler)();
}
}
//设置rx callback
void hal_uart_dma_set_block_received( void (*the_block_handler)(void)){
rx_done_handler = the_block_handler;
}
//设置tx callback
void hal_uart_dma_set_block_sent( void (*the_block_handler)(void)){
tx_done_handler = the_block_handler;
}
(3)实现HCI driver TX & RX函数,以及HCI log driver
void hal_uart_dma_send_block(const uint8_t *data, uint16_t size){
HAL_UART_Transmit_DMA( &huart2, (uint8_t *) data, size);
}
void hal_uart_dma_receive_block(uint8_t *data, uint16_t size){
HAL_UART_Receive_DMA( &huart2, data, size );
}
void hal_uart_dma_send_block_for_hci(const uint8_t *data, uint16_t size){
HAL_UART_Transmit( &huart3, (uint8_t *) data, size, HAL_MAX_DELAY );
}
bluekitchen TX & RX数据流大致如下:
(4)为了简化问题,我们先不实现flash driver,内容全部放空
(5)最后是协议栈的配置:
void port_main(void){
// start with BTstack init - especially configure HCI Transport
btstack_memory_init();
btstack_run_loop_init(btstack_run_loop_embedded_get_instance());
// uncomment to enable packet logger
#ifdef ENABLE_SEGGER_RTT
// hci_dump_init(hci_dump_segger_rtt_stdout_get_instance());
#else
hci_dump_init(hci_dump_embedded_stdout_get_instance());
#endif
// init HCI
hci_init(hci_transport_h4_instance(btstack_uart_block_embedded_instance()), (void*) &config);
hci_set_chipset(btstack_chipset_csr_instance());
#if 0
// setup TLV Flash Sector implementation
const hal_flash_bank_t * hal_flash_bank_impl = hal_flash_bank_stm32_init_instance(
&hal_flash_bank_context,
HAL_FLASH_BANK_SIZE,
HAL_FLASH_BANK_0_SECTOR,
HAL_FLASH_BANK_1_SECTOR,
HAL_FLASH_BANK_0_ADDR,
HAL_FLASH_BANK_1_ADDR);
const btstack_tlv_t * btstack_tlv_impl = btstack_tlv_flash_bank_init_instance(
&btstack_tlv_flash_bank_context,
hal_flash_bank_impl,
&hal_flash_bank_context);
// setup global tlv
btstack_tlv_set_instance(btstack_tlv_impl, &btstack_tlv_flash_bank_context);
// setup Link Key DB using TLV
const btstack_link_key_db_t * btstack_link_key_db = btstack_link_key_db_tlv_get_instance(btstack_tlv_impl, &btstack_tlv_flash_bank_context);
hci_set_link_key_db(btstack_link_key_db);
// setup LE Device DB using TLV
le_device_db_tlv_configure(btstack_tlv_impl, &btstack_tlv_flash_bank_context);
#endif
#ifdef HAVE_HAL_AUDIO
// setup audio
btstack_audio_sink_set_instance(btstack_audio_embedded_sink_get_instance());
btstack_audio_source_set_instance(btstack_audio_embedded_source_get_instance());
#endif
// inform about BTstack state
hci_event_callback_registration.callback = &packet_handler;
hci_add_event_handler(&hci_event_callback_registration);
// hand over to btstack embedded code
btstack_main(0, NULL);
// go
btstack_run_loop_execute();
}
编译工程后开始调试,记录下遇到的几个问题。
Q1:controller有上报event,但是格式不正确:(开机后会重新调整波特率,导致波特率不匹配)
首先需要解决2个问题:
1)system log重叠和丢失的问题 <uart1 tx & rx开DMA>
2)hci logging tool crash问题(看现象似乎是波特率太快,tool收不过来)
已解决:波特率太高,丢包,导致logging tool内存越界
Q2:似乎uart1 & uart2 DMA通道有冲突,使用uart1 DMA来传输log时,uart2无法正确收controller event?
暂无法解释。简化问题,只开uart2 RX & TX DMA。
Q3:在下完hci_reset_cm后,下read_local_version_cmd,无法收到正确的hci_evt,流程中断?
奇怪的现象,关闭uart1 hci dump后,就正常了。
更进一步,在如下函数中只打印message type就可以正常接收controller event:
太诡异了,无法理解!!!!!!
会不会是因为在UART2 RX ISR中调用printf???
可以排除这个猜想。
Q4:将波特率改为921600后,无法工作,收不到event。
暂未解决。
Q5:开启可见性后,使用手机去连接设备,会遇到event | acl解析错误:
对比正常的log:(红框中的就是丢失数据的hci event)
从发送完Read_Remote_Supported_Features cmd开始,event packet就丢失偶数次序的byte?
问题的原因终于找到了,在bluekitchen原始仓库的closed issue中,发现有人遇到了同样的问题,参考bluekitchen团队写的开发blog:https://bluekitchen-gmbh.com/btstack-port-for-stm32-f4-discovery-board-with-cc256x/
发现是UART2 RX DMA的使用上出了问题,bluekitchen hci_transport_h4.c 读数据的策略是分批次读取,1)hci_packet_type, 2)packet_header, 3)payload,在1)和2)之间的数据会丢失:
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(huart);
/* Set Reception type to Standard reception */
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
return(UART_Start_Receive_DMA(huart, pData, Size));
}
else
{
return HAL_BUSY;
}
}
HAL_StatusTypeDef UART_Start_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
uint32_t *tmp;
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
/* Set the UART DMA transfer complete callback */
huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt;
/* Set the UART DMA Half transfer complete callback */
huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt;
/* Set the DMA error callback */
huart->hdmarx->XferErrorCallback = UART_DMAError;
/* Set the DMA abort callback */
huart->hdmarx->XferAbortCallback = NULL;
/* Enable the DMA stream */
tmp = (uint32_t *)&pData;
HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t *)tmp, Size);
/* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */
//__HAL_UART_CLEAR_OREFLAG(huart);
/* Process Unlocked */
__HAL_UNLOCK(huart);
/* Enable the UART Parity Error Interrupt */
SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);
/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
SET_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* Enable the DMA transfer for the receiver request by setting the DMAR bit
in the UART CR3 register */
SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);
return HAL_OK;
}
#define __HAL_UART_CLEAR_OREFLAG(__HANDLE__) __HAL_UART_CLEAR_PEFLAG(__HANDLE__)
#define __HAL_UART_CLEAR_PEFLAG(__HANDLE__) \
do{ \
__IO uint32_t tmpreg = 0x00U; \
tmpreg = (__HANDLE__)->Instance->SR; \
tmpreg = (__HANDLE__)->Instance->DR; \
UNUSED(tmpreg); \
} while(0U)
__HAL_UART_CLEAR_OREFLAG(HANDLE)
这个宏会读uart状态寄存器和数据寄存器,当然会丢失数据。。。。。
屏蔽掉这段代码一切问题都解决了。
版权声明:本文为CSDN博主「熟能生巧啊」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_38177846/article/details/122573119
暂无评论