CC2540串口无法收到数据
我们的业务场景:定期扫描所有蓝牙设备,收到串口请求后,发送蓝牙设备信息。
技术实现:在BLE-CC254x-1.4.0的Demo程序SimpleBLECentral的基础上,参考SimpleBLEPeripheral。使用UART DMA ,在配置里关掉POWER_SAVING,串口接收数据使用Poll模式。蓝牙发现间隔为200ms,发现周期为2000ms。上位机发送串口请求蓝牙设备的频率为1000ms一次。
调试的时候发现一个奇怪的问题,系统运行正常,串口会隔几分钟收不到来自上位机的数据,大约1分钟后自动恢复正常。如果关闭发现蓝牙设备,串口通讯就会很正常,从不出错。
看到有人说可以修改官方的DMA Buffer的处理,在http://blog.itpub.net/29285470/viewspace-1172403/ 找到一个例子,试验了一下发现没有效果。
大家有没有遇到过类似的问题呢?不胜感激。
===================================================================================================================
问题备忘录:
2014年7月18日,推测官方的DMA处理中,关于接收和发送的逻辑没有处理好,所以我就索性关闭了接收功能,定期把发现的蓝牙设备发送给上位机,再测试,没发现过死掉的情况。以后需要的话再继续研究DMA Buffer处理的函数。
非常感谢各位的回复。
Jiang,
请尝试一下在init里面把下面的代码注释掉
HCI_EXT_ClkDivOnHaltCmd( HCI_EXT_ENABLE_CLK_divIDE_ON_HALT );
看看效果如何?
贴一个我的uart代码,请参考:
#include "bcomdef.h"
#include "OSAL.h"
#include "OSAL_PwrMgr.h"
#include "OnBoard.h"
#include "hal_adc.h"
#include "hal_led.h"
#include "hal_key.h"
#include "hal_lcd.h"
#include "gatt.h"
#include "gapgattserver.h"
#include "gattservapp.h"
#include "devinfoservice.h"
#include "simpleGATTprofile.h"
#include "peripheral.h"
#include "gapbondmgr.h"
#include "serialAppPeripheral.h"
#include "serialAppUtil.h"
#include "hal_uart.h"
#define reportQEmpty() ( firstQIdx == lastQIdx )
/*********************************************************************
* CONSTANTS
*/
#define MAX_SAPP_PACKET_LEN 20
#define MAX_SAPP_NUM_ENTRIES 30
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
static uint8 sendMsgTo_TaskID;
static uint8 firstQIdx = 0;
static uint8 lastQIdx = 0;
static attHandleValueNoti_t packetQ[MAX_SAPP_NUM_ENTRIES];
/*********************************************************************
* LOCAL FUNCTIONS
*/
static void SerialAppEnqueue( attHandleValueNoti_t* );
static attHandleValueNoti_t *packetDequeue( void );
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/*********************************************************************
* @fn SerialApp_Init
*
* @brief Serial app initialization
*
* @param none
* @param none
*
*
* @return none
*/
void SerialApp_Init( uint8 taskID )
{
SerialAppInitTransport();
sendMsgTo_TaskID = taskID;
}
/*********************************************************************
* @fn SerialAppInitTransport
*
* @brief Initialize serial trans port
*
* @param none
* @param none
*
*
* @return none
*/
void SerialAppInitTransport(void)
{
halUARTCfg_t uartConfig;
/* configure UART */
uartConfig.configured = TRUE;
uartConfig.baudRate = SBP_UART_BR;
uartConfig.flowControl = SBP_UART_FC;
uartConfig.flowControlThreshold = SBP_UART_FC_THRESHOLD;
uartConfig.rx.maxBufSize = SBP_UART_RX_BUF_SIZE;
uartConfig.tx.maxBufSize = SBP_UART_TX_BUF_SIZE;
uartConfig.idleTimeout = SBP_UART_IDLE_TIMEOUT;
uartConfig.intEnable = SBP_UART_INT_ENABLE;
uartConfig.callBackFunc = SerialAppPacketParserCB;
(void)HalUARTOpen( SBP_UART_PORT, &uartConfig );
return;
}
/*******************************************************************************
* @fn SerialAppPacketParserCB
*
* @brief UART回调函数 从串口接收一个BLE命令或者数据包(由数据类型决定).
*
* SAPP command packet format:
* Packet Type + Command opcode + lengh + command payload
* | 1 octet | 2 | 1 | n |
*
* SAPP data packet format:
* Packet Type + Conn Handle + lengh + data payload
* | 1 octet | 2 | 2 | n |
*
* input parameters
*
* @param port - UART callback serial port.
* @param event - UART callback event number.
*
* output parameters
*
* @param None.
*
* @return None.
*/
void SerialAppPacketParserCB( uint8 port,uint8 event )
{
static uint8 sappPktState = SAPP_PARSER_STATE_PKT_TYPE;
static uint8 pktType;
static uint16 param1;
static uint16 pktLen;
uint16 numBytes;
(void)event;
/* 检查是否有串口数据等待处理 */
if ( (numBytes = Hal_UART_RxBufLen(port)) > 0 )
{
/* 检查是否开始处理一个新的数据包 */
if ( sappPktState == SAPP_PARSER_STATE_PKT_TYPE )
{
/* 读取数据包类型 */
(void)HalUARTRead (port, &pktType, 1);
numBytes -= 1;
/* 在数据包类型的基础上设置下一个状态 */
switch( pktType )
{
/* 数据包类型是命令 */
case SAPP_CMD_PACKET:
sappPktState = SAPP_CMD_PARSER_STATE_OPCODE;
break;
/* 数据包类型是数据 */
case SAPP_ACL_DATA_PACKET:
case SAPP_SCO_DATA_PACKET:
sappPktState = SAPP_DATA_PARSER_STATE_HANDLE;
break;
default:
return;
}
}
/* 处理串口字节建立命令或者数据包 */
switch( sappPktState )
{
/* 命令操作码 */
case SAPP_CMD_PARSER_STATE_OPCODE:
if (numBytes < 2) break;
/* 读取操作码 */
(void)HalUARTRead (port, (uint8 *)¶m1, 2);
numBytes -= 2;
sappPktState = SAPP_CMD_PARSER_STATE_LENGTH;
/* 命令长度 */
case SAPP_CMD_PARSER_STATE_LENGTH:
if (numBytes < 1) break;
/* 在设置之前清除 */
pktLen = 0;
/* 读取长度 */
(void)HalUARTRead (port, (uint8 *)&pktLen, 1);
numBytes -= 1;
sappPktState = SAPP_CMD_PARSER_STATE_DATA;
/* 有效命令 */
case SAPP_CMD_PARSER_STATE_DATA:
/* 检查是否有足够的串口数据来填充命令包 */
if ( numBytes >= pktLen )
{
sappPacket_t *pMsg;
/* 判断有足够的串口数据来填充命令包, 分配内存 */
pMsg = (sappPacket_t *)osal_msg_allocate( sizeof (sappPacket_t) + SAPP_CMD_MIN_LENGTH + pktLen );
/* 是否有一个分配的内存块, 有则填充 */
if ( pMsg )
{
/* 填充pMsg命令 */
pMsg->pData = (uint8*)(pMsg+1);
pMsg->pData[0] = pktType;
pMsg->pData[1] = ((uint8 *)¶m1)[0]; // opcode (LSB)
pMsg->pData[2] = ((uint8 *)¶m1)[1]; // opcode (MSB)
pMsg->pData[3] = ((uint8 *)&pktLen)[0]; // one byte of length for cmd
/* 拷贝串口数据到pMsg */
(void)HalUARTRead (port, &pMsg->pData[4], pktLen);
/* 设置特定标志 */
pMsg->hdr.status = 0xFF;
/* 检查是否是一个链路层命令 */
if ( ((param1 >> 10) == VENDOR_SPECIFIC_OGF) &&
(((param1 >> 7) & 0x07) != SAPP_OPCODE_CSG_LINK_LAYER) )
{
/* 这是一个供应商的特定命令 */
pMsg->hdr.event = SAPP_EXT_CMD_EVENT;
/* 提取OGF */
pMsg->pData[2] &= 0x03;
(void)osal_msg_send( sendMsgTo_TaskID, (uint8 *)pMsg );
}
else
{
/* 这是一个普通的主机控制器事件 */
pMsg->hdr.event = SAPP_HOST_TO_CTRL_CMD_EVENT;
/* 发送SAPP处理程序 */
(void)osal_msg_send( sendMsgTo_TaskID, (uint8 *)pMsg );
}
/* 准备开始下一个数据包的处理 */
sappPktState = SAPP_PARSER_STATE_PKT_TYPE;
}
}
break;
case SAPP_DATA_PARSER_STATE_HANDLE:
if (numBytes < 2) break;
/* 读取数据连接句柄 */
(void)HalUARTRead (port, (uint8 *)¶m1, 2);
numBytes -= 2;
sappPktState = SAPP_DATA_PARSER_STATE_LENGTH;
case SAPP_DATA_PARSER_STATE_LENGTH:
if (numBytes < 1) break;
pktLen = 0;
/* 读取长度 */
(void)HalUARTRead (port, (uint8 *)&pktLen, 1);
/* 验证数据包的长度被SBP_UART_RX_BUF_SIZE允许 */
if ( pktLen >= SBP_UART_RX_BUF_SIZE )
{
/* 出错 重新开始 */
sappPktState = SAPP_PARSER_STATE_PKT_TYPE;
break;
}
numBytes -= 1;
sappPktState = SAPP_DATA_PARSER_STATE_DATA;
case SAPP_DATA_PARSER_STATE_DATA:
/* 检查是否有足够的串口数据来填充数据包 */
if ( numBytes >= pktLen )
{
sappDataPacket_t *pMsg;
/* 有足够的串口数据来填充命令包, 分配内存 */
pMsg = (sappDataPacket_t *)osal_msg_allocate( sizeof(sappDataPacket_t) );
/* 是否有一个分配的内存块, 有则填充 */
if ( pMsg )
{
pMsg->hdr.event = SAPP_HOST_TO_CTRL_DATA_EVENT;
pMsg->hdr.status = 0xFF;
/* 填充pMsg数据 */
pMsg->pktType = pktType;
pMsg->connHandle = param1 & 0x0FFF;
pMsg->pbFlag = (param1 & 0x3000) >> 12;
pMsg->pktLen = pktLen;
pMsg->pData = osal_mem_alloc(pktLen);
if ( pMsg->pData )
{
/* 拷贝串口数据到pMsg */
(void)HalUARTRead (port, pMsg->pData, pktLen);
/* 发送消息 */
(void)osal_msg_send( sendMsgTo_TaskID, (uint8 *)pMsg );
(void)osal_msg_deallocate( (uint8 *)pMsg );
(void)osal_mem_free( pMsg->pData );
}
else
{
/* 释放消息 */
(void)osal_msg_deallocate( (uint8 *)pMsg );
(void)osal_mem_free( pMsg->pData );
}
/* 准备开始下一个数据包处理 */
sappPktState = SAPP_PARSER_STATE_PKT_TYPE;
}
}
break;
default:
break;
}
}
return;
}
/*********************************************************************
* @fn Send GATT Notification
*
* @brief 发送GATT通知
*
* @param OSAL定期调用该函数
* @param none
*
*
* @return none
*/
void SerialAppSendNotification(void)
{
uint8 i = 0;
static attHandleValueNoti_t *pReport= NULL;
static volatile uint16 counterOut=0;
if ( pReport == NULL)
{
pReport = packetDequeue();
if ( pReport == NULL )
{
return;
}
}
/* 每一个连接事件尝试发送3个package */
for ( i = 0; i<3 ; i++)
{
if ( GATT_Notification( 0, pReport, FALSE )==SUCCESS)
{
HalUARTWrite(SBP_UART_PORT, "DOUT:", 5);
++counterOut;
char hex[] = "0123456789";
char buf[4];
buf[0] = hex[counterOut/1000];
buf[1] = hex[counterOut%1000/100];
buf[2] = hex[counterOut%100/10];
buf[3] = hex[counterOut%10];
HalUARTWrite(SBP_UART_PORT, (uint8 *)buf, 4);
HalUARTWrite(SBP_UART_PORT, "\r\n", 2);
LCD_WRITE_STRING_VALUE( "DOUT ", ++counterOut, 10,2 );
pReport = packetDequeue();
if ( pReport == NULL )
{
i=3;
}
}
else
{
pReport = NULL;
i=3;
}
}
}
/*********************************************************************
* @fn SerialAppSendData
*
* @brief Send Gatt notifications
*
* @param pPkt - Gatt notification
* @param none
*
*
* @return none
*/
void SerialAppSendData2( sappExtCmd_t *pPkt )
{
static uint16 counter=0;
counter++;
attHandleValueNoti_t noti;
noti.len = pPkt->len;
noti.handle = 0;
osal_memcpy( ¬i.value, &pPkt->pData[0], noti.len );
SerialAppEnqueue( ¬i );
}
/*********************************************************************
* @fn SerialAppSendData
*
* @brief Send Gatt notifications
*
* @param pPkt - Gatt notification
* @param none
*
*
* @return none
*/
void SerialAppSendData1( sappDataPacket_t *pPkt )
{
static uint16 counter=0;
counter++;
attHandleValueNoti_t noti;
noti.len = pPkt->pktLen;
noti.handle = pPkt->connHandle;
osal_memcpy( ¬i.value, &pPkt->pData[0], noti.len );
SerialAppEnqueue( ¬i );
}
/*********************************************************************
* @fn SerialAPpEnqueue
*
* @brief Enqueue a report te be sent later
*
* @param pData
* @param none
*
*
* @return none
*/
static void SerialAppEnqueue( attHandleValueNoti_t *pData )
{
static volatile uint16 counterIn = 0;
/* 更新最后的索引 */
lastQIdx = ( lastQIdx + 1 ) % MAX_SAPP_NUM_ENTRIES;
if ( lastQIdx == firstQIdx )
{
/* 队列溢出 丢弃最旧的报告*/
firstQIdx = ( firstQIdx + 1 ) % MAX_SAPP_NUM_ENTRIES;
}
/* 存储为 Notification */
packetQ[lastQIdx].len =pData->len;
osal_memcpy( &packetQ[lastQIdx], pData, pData->len+3 );
HalUARTWrite(SBP_UART_PORT, "DIN:", 4);
++counterIn;
char hex[] = "0123456789";
char buf[4];
buf[0] = hex[counterIn/1000];
buf[1] = hex[counterIn%1000/100];
buf[2] = hex[counterIn%100/10];
buf[3] = hex[counterIn%10];
HalUARTWrite(SBP_UART_PORT, (uint8 *)buf, 4);
HalUARTWrite(SBP_UART_PORT, "\r\n", 2);
LCD_WRITE_STRING_VALUE( "DIN ", ++counterIn, 10,3 );
}
/*********************************************************************
* @fn packetDequeue
*
* @brief Dequeue a report to be sent out.
*
* @param none
* @param none
*
* @return None.
*/
static attHandleValueNoti_t *packetDequeue(void)
{
if ( reportQEmpty() )
{
return NULL;
}
/* 更新最先的索引 */
firstQIdx = ( firstQIdx + 1 ) % MAX_SAPP_NUM_ENTRIES;
return ( &(packetQ[firstQIdx]) );
}
头文件
#ifndef SERIALAPPUTIL_H
#define SERIALAPPUTIL_H
#ifdef __cplusplus
extern "C"
{
#endif
/* UART port */
#define SBP_UART_PORT HAL_UART_PORT_0
#define SBP_UART_FC FALSE
#define SBP_UART_FC_THRESHOLD 48
#define SBP_UART_RX_BUF_SIZE 128
#define SBP_UART_TX_BUF_SIZE 128
#define SBP_UART_IDLE_TIMEOUT 6
#define SBP_UART_INT_ENABLE TRUE
#define SBP_UART_BR HAL_UART_BR_57600
#define SAPP_EXT_LL_SUBGRP 0x00
#define SAPP_EXT_L2CAP_SUBGRP 0x01
#define SAPP_EXT_ATT_SUBGRP 0x02
#define SAPP_EXT_GATT_SUBGRP 0x03
#define SAPP_EXT_GAP_SUBGRP 0x04
#define SAPP_EXT_UTIL_SUBGRP 0x05
#define SAPP_EXT_PROFILE_SUBGRP 0x07
#define SAPP_EXT_UTIL_RESET 0x00
#define SAPP_EXT_UTIL_NV_READ 0x01
#define SAPP_EXT_UTIL_NV_WRITE 0x02
#define SAPP_EXT_UTIL_FORCE_BOOT 0x03
/* HCI - Messages IDs (0x90 - 0x9F) */
#define SAPP_DATA_EVENT 0x90 //!< HCI Data Event message
#define SAPP_GAP_EVENT_EVENT 0x91 //!< GAP Event message
#define SAPP_SMP_EVENT_EVENT 0x92 //!< SMP Event message
#define SAPP_EXT_CMD_EVENT 0x93 //!< HCI Extended Command Event message
/*
Minimum length for CMD packet is 1+2+1
| Packet Type (1) | OPCode(2) | Length(1) |
*/
#define SAPP_CMD_MIN_LENGTH 4
/*
Minimum length for DATA packet is 1+2+1
| Packet Type (1) | Handle(2) | Length(1) |
*/
#define SAPP_DATA_MIN_LENGTH 4
/* States for Command and Data packet parser */
#define SAPP_PARSER_STATE_PKT_TYPE 0
#define SAPP_CMD_PARSER_STATE_OPCODE 1
#define SAPP_CMD_PARSER_STATE_LENGTH 2
#define SAPP_CMD_PARSER_STATE_DATA 3
#define SAPP_DATA_PARSER_STATE_HANDLE 4
#define SAPP_DATA_PARSER_STATE_LENGTH 5
#define SAPP_DATA_PARSER_STATE_DATA 6
#define SAPP_OPCODE_CSG_LINK_LAYER 0
#define SAPP_OPCODE_CSG_CSG_L2CAP 1
#define SAPP_OPCODE_CSG_CSG_ATT 2
#define SAPP_OPCODE_CSG_CSG_GATT 3
#define SAPP_OPCODE_CSG_CSG_GAP 4
#define SAPP_OPCODE_CSG_CSG_SM 5
#define SAPP_OPCODE_CSG_CSG_Reserved 6
#define SAPP_OPCODE_CSG_CSG_USER_PROFILE 7
/* Vendor Specific OGF */
#define VENDOR_SPECIFIC_OGF 0x3F
/* Event Mask Default Values */
#define BT_EVT_MASK_BYTE0 0xFF
#define BT_EVT_MASK_BYTE1 0xFF
#define BT_EVT_MASK_BYTE2 0xFF
#define BT_EVT_MASK_BYTE3 0xFF
#define BT_EVT_MASK_BYTE4 0xFF
#define BT_EVT_MASK_BYTE5 0x9F
#define BT_EVT_MASK_BYTE6 0x00
#define BT_EVT_MASK_BYTE7 0x20
#define LE_EVT_MASK_DEFAULT 0x1F
/* SAPP Packet Types */
#define SAPP_CMD_PACKET 0x01
#define SAPP_ACL_DATA_PACKET 0x02
#define SAPP_SCO_DATA_PACKET 0x03
#define SAPP_EVENT_PACKET 0x04
/* Serial Events */
#define SAPP_CONTROLLER_TO_HOST_EVENT 0x01
#define SAPP_HOST_TO_CTRL_CMD_EVENT 0x02
#define SAPP_HOST_TO_CTRL_DATA_EVENT 0x04
#define SAPP_BDADDR_LEN 6
#if HAL_LCD == TRUE
#define LCD_WRITE_STRING(str, option) HalLcdWriteString( (str), (option))
#define LCD_WRITE_SCREEN(line1, line2) HalLcdWriteScreen( (line1), (line2) )
#define LCD_WRITE_STRING_VALUE(title, value, format, line) HalLcdWriteStringValue( (title), (value), (format), (line) )
#else
#define LCD_WRITE_STRING(str, option)
#define LCD_WRITE_SCREEN(line1, line2)
#define LCD_WRITE_STRING_VALUE(title, value, format, line)
#endif
typedef struct
{
uint8 pktType;
uint16 opCode;
uint8 len;
uint8 *pData;
} sappExtCmd_t;
typedef struct
{
osal_event_hdr_t hdr;
uint8 *pData;
} sappPacket_t;
typedef struct
{
osal_event_hdr_t hdr;
uint8 pktType;
uint16 connHandle;
uint8 pbFlag;
uint8 pktLen;
uint8 *pData;
} sappDataPacket_t;
extern void SerialApp_Init( uint8 taskID );
extern void SerialAppPacketParserCB( uint8 port, uint8 event );
extern void SerialAppInitTransport(void);
extern void SerialAppSendData1( sappDataPacket_t *pPkt );
extern void SerialAppSendData2( sappExtCmd_t *pMsg );
extern void SerialAppSendNotification(void);
extern void SerialAppSendOutUART( attHandleValueNoti_t *noti) ;
extern uint8 ProcessExtMsg1( sappDataPacket_t *pMsg );
extern uint8 ProcessExtMsg2( sappPacket_t *pMsg );
#ifdef __cplusplus
}
#endif
#endif
你好,并没有找到有本段代码。不过问题已经解决了,还是谢谢你。
非常感谢你的回复,我的问题已经间接的解决了。