蓝牙技术
直播中

李静

8年用户 1071经验值
私信 关注
[问答]

Bluetooth® SPP 至 PUART 数据丢失了怎么解决?

我已经创建了一个简单的 ModbusToolBox 应用程序(通过修改“RFCOMM 串行端口”应用程序)来通过Bluetooth® SPP 接收数据并将其发送到 PUART,但我看到一些数据丢失。
请参阅附件SPP.C
我正在使用 CYBT-343026-EVAL。
我进行如下测试:
设置终端仿真器来捕获 PUART 上的输出。
通过Bluetooth®从 Android“串行Bluetooth®终端”应用程序发送一些测试数据(约 450K 文本文件)。
将终端仿真器接收到的数据与测试文件进行比较,发现缺少一些数据。
请注意,使用 EZ-Serial 而不是 ModbusToolBox 应用程序进行相同的测试可以正常工作(接收的数据与测试文件匹配)。
请问您能告诉我是否有办法防止数据丢失吗?

回帖(1)

切克切克闹

2025-8-20 17:00:32

针对您遇到的Bluetooth® SPP到PUART数据丢失问题,以下是系统的解决方案:


核心问题分析


数据丢失的根本原因是高速SPP数据流(约450KB)超过了PUART转发处理能力。可能因素包括:



  1. 缓冲区溢出:SPP接收缓冲区或中间转发缓冲区不足

  2. 流控制缺失:未启用硬件流控(RTS/CTS)导致接收方过载

  3. 处理延迟:数据转发逻辑未优化,无法处理突发数据流


解决方案步骤


1. 启用硬件流控制(关键步骤)


在PUART和SPP两端启用RTS/CTS流控:


// 修改PUART初始化配置
cyhal_uart_cfg_t uart_cfg = {
    .data_bits = 8,
    .stop_bits = 1,
    .parity = CYHAL_UART_PARITY_NONE,
    .flow_control = CYHAL_UART_FLOW_CTRL_RTSCTS, // 启用硬件流控
};
cyhal_uart_init(&uart_obj, P_UART_TX, P_UART_RX, P_UART_RTS, P_UART_CTS, NULL, &uart_cfg);

同时确保物理连接:



  • PUART_RTS ↔ 对方设备CTS

  • PUART_CTS ↔ 对方设备RTS


2. 优化缓冲区管理


增大SPP接收缓冲区并添加转发队列:


#define FORWARD_QUEUE_SIZE 4096 // 建议4KB以上

// 创建环形缓冲区
uint8_t forward_queue[FORWARD_QUEUE_SIZE];
uint32_t queue_head = 0;
uint32_t queue_tail = 0;

// SPP回调函数改造
void spp_data_callback(uint8_t *data, uint16_t len) {
    uint32_t free_space = FORWARD_QUEUE_SIZE - ((queue_head - queue_tail) % FORWARD_QUEUE_SIZE);

    if(len > free_space) {
        // 触发流控暂停(实际实现需调用RFCOMM API)
        rfcomm_flow_control(false);
    }

    for(int i=0; i         forward_queue[queue_head] = data[i];
        queue_head = (queue_head + FORWARD_QUEUE_SIZE + 1) % FORWARD_QUEUE_SIZE;
    }
    trigger_forward_task(); // 触发转发任务
}

3. 实现异步转发机制


分离数据接收和转发:


void forward_task(void) {
    while(1) {
        uint32_t data_count = (queue_head - queue_tail) % FORWARD_QUEUE_SIZE;

        if(data_count > 0) {
            uint32_t block_size = MIN(data_count, MAX_UART_BLOCK);
            uint8_t temp_buf[MAX_UART_BLOCK];

            // 从队列提取数据
            for(int i=0; i                 temp_buf[i] = forward_queue[queue_tail];
                queue_tail = (queue_tail + 1) % FORWARD_QUEUE_SIZE;
            }

            // 非阻塞方式发送
            cyhal_uart_write_async(&uart_obj, temp_buf, block_size);

            // 检查缓冲区空间恢复
            if(data_count > (FORWARD_QUEUE_SIZE * 3/4)) {
                rfcomm_flow_control(true); // 恢复数据流
            }
        }
        else {
            cyhal_system_delay_ms(1); // 短暂释放CPU
        }
    }
}

4. 关键参数调整




  • 增大RFCOMM缓冲区


    // 在wiced_bt_cfg.c中修改
    rfcomm_cb.port.rfc_mtu = 672; // 默认值330->增大到672



  • 优化线程优先级(使用RTOS时):


    #define FORWARD_TASK_PRIORITY (configMAX_PRIORITIES - 2) // 高于默认任务
    xTaskCreate(forward_task, "UART_Fwd", 1024, NULL, FORWARD_TASK_PRIORITY, NULL);



5. 流控状态监控


添加流控状态调试接口:


void print_flow_status(void) {
    bool flow_ctrl = cyhal_uart_is_tx_active(&uart_obj) ? false : true;
    printf("[FlowCTRL] PUART:%s Queue:%d/%dn",
           flow_ctrl ? "BLOCK" : "READY",
           (queue_head - queue_tail) % FORWARD_QUEUE_SIZE,
           FORWARD_QUEUE_SIZE);
}

验证方案




  1. 压力测试


    # 生成450KB测试文件
    dd if=/dev/urandom of=testfile.bin bs=450k count=1

    使用md5sum比较源文件和接收文件




  2. 实时监控



    • 用逻辑分析仪捕获RTS/CTS信号

    • 监控队列使用率:printf("Queue Usage: %d%%n", queue_usage*100/FORWARD_QUEUE_SIZE);




  3. 流量控制测试



    • 故意降低PUART波特率(如115200bps)

    • 验证RTS自动拉高时SPP数据暂停




补充建议



  • 时钟配置检查
    // 确保UART时钟≥4×波特率
    CY_ASSERT(periph_clock_hz >= (4 * 115200));

  • 错误处理增强
    cyhal_uart_write_async(/* ... */);
    if(cyhal_uart_get_tx_status(&uart_obj) != CYHAL_UART_SUCCESS) {
      queue_head = (queue_head - block_size) % FORWARD_QUEUE_SIZE; // 数据回退
    }



注意:对比EZ-Serial正常工作的情况,重点检查其:



  1. 默认启用的硬件流控设置

  2. 内置的256字节硬件FIFO使用

  3. DMA传输模式(查看Cy_SCB_UART_Init()useTxFifo参数)



实施上述优化后,数据丢失问题应能显著改善。尤其在启用硬件流控+队列缓冲的组合方案后,能有效协调高速蓝牙数据和低速串口间的速率差异。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分