TI中文支持网
TI专业的中文技术问题搜集分享网站

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处理的函数。

非常感谢各位的回复。

Yan:

Jiang,

请尝试一下在init里面把下面的代码注释掉

HCI_EXT_ClkDivOnHaltCmd( HCI_EXT_ENABLE_CLK_DIVIDE_ON_HALT );

看看效果如何?

xiang zhang4:

贴一个我的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 *)&param1, 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 *)&param1)[0]; // opcode (LSB) pMsg->pData[2] = ((uint8 *)&param1)[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 *)&param1, 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( &noti.value, &pPkt->pData[0], noti.len ); SerialAppEnqueue( &noti ); }

/********************************************************************** @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( &noti.value, &pPkt->pData[0], noti.len ); SerialAppEnqueue( &noti ); }

/********************************************************************** @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]) );}

xiang zhang4:

头文件

#ifndef SERIALAPPUTIL_H#define SERIALAPPUTIL_H

#ifdef __cplusplusextern "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

Jiang Eric:

回复 Yan:

你好,并没有找到有本段代码。不过问题已经解决了,还是谢谢你。

Jiang Eric:

回复 xiang zhang4:

非常感谢你的回复,我的问题已经间接的解决了。

赞(0)
未经允许不得转载:TI中文支持网 » CC2540串口无法收到数据
分享到: 更多 (0)