This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2540串口无法收到数据



我们的业务场景:定期扫描所有蓝牙设备,收到串口请求后,发送蓝牙设备信息。

技术实现:在BLE-CC254x-1.4.0的Demo程序SimpleBLECentral的基础上,参考SimpleBLEPeripheral。使用UART DMA ,在配置里关掉POWER_SAVING,串口接收数据使用Poll模式。蓝牙发现间隔为200ms,发现周期为2000ms。上位机发送串口请求蓝牙设备的频率为1000ms一次。

调试的时候发现一个奇怪的问题,系统运行正常,串口会隔几分钟收不到来自上位机的数据,大约1分钟后自动恢复正常。如果关闭发现蓝牙设备,串口通讯就会很正常,从不出错。

看到有人说可以修改官方的DMA Buffer的处理,在blog.itpub.net/.../ 找到一个例子,试验了一下发现没有效果。

大家有没有遇到过类似的问题呢?不胜感激。

===================================================================================================================

问题备忘录:

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


  • 头文件

    #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

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

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