单片机/MCU论坛
直播中

挽你何用

10年用户 981经验值
擅长:电源/新能源 MEMS/传感技术
私信 关注
[问答]

XMC7100 F100K4160AA Uart2 dma实例程序无法运行,使用hal驱动发送丢字符并且无法接收怎么解决?

问题1:修改SCB UART DMA Echo实例程序引脚和dma通道配置正常运行后,无法按照实例设计功能接收和显示。
问题2:使用hal驱动方式,能正常发送数据,但经常丢字符,添加了CYHAL_DMA_TRANSFER_COMPLETE 和 CYHAL_DMA_DESCRIPTOR_COMPLETE事件,并判断了cyhal_dma_is_busy状态还是丢字符。


uart2.dma_tx初始化代码

uart2.dma_tx发送代码
问题3:按tx同样的方式配置SCB2 dma_rx,只能在初始化完成触发一次CYHAL_DMA_TRANSFER_COMPLETE | CYHAL_DMA_DESCRIPTOR_COMPLETE事件,后不再触发,并不能接收数据。

uart2.dma_rx初始化配置

回帖(1)

郭大

2025-8-18 16:39:37

针对XMC7100 UART2 DMA的问题,以下是根本原因分析和解决方案:


问题根本原因:



  1. DMA接收配置问题:RX DMA触发后未重新启用导致无法持续接收。

  2. HAL库时序冲突cyhal_uart_write内部机制与DMA发送存在资源竞争。

  3. 缺失硬件流控:高波特率下未启用RTS/CTS导致数据丢失。

  4. 接收FIFO配置错误:DMA未与UART FIFO深度匹配。

  5. DMA描述符模式错误:RX应为循环模式而非单次模式。




解决方案:


1. DMA接收持续触发修复


// 修改RX DMA初始化 - 启用循环模式
cyhal_dma_set_descriptor(&dma_rx_obj,
                         NULL,
                         CYHAL_DMA_DESCRIPTOR_CONTINUOUS, // 循环模式
                         sizeof(rx_buffer));

// 添加UART回调函数
void uart_event_handler(void *arg, cyhal_uart_event_t event)
{
    if(event & CYHAL_UART_RX_DMA_DONE) {
        // 1. 处理接收数据
        process_rx_data();

        // 2. 重新配置DMA(指向新缓冲区)
        cyhal_dma_set_dst_addr(&dma_rx_obj, (uint32_t)rx_buffer);
        cyhal_dma_set_transfer(&dma_rx_obj, sizeof(rx_buffer));

        // 3. 重新启用RX DMA
        cyhal_dma_enable(&dma_rx_obj);
    }
}

// 配置UART事件
cyhal_uart_register_callback(&uart_obj, uart_event_handler, NULL);
cyhal_uart_enable_event(&uart_obj,
                       CYHAL_UART_RX_DMA_DONE,
                       3); // 优先级

2. HAL发送丢字符修复


// 直接使用DMA发送替代cyhal_uart_write
void uart_dma_send(const uint8_t *data, size_t len)
{
    // 等待上一次传输完成
    while(cyhal_dma_is_busy(&dma_tx_obj));

    // 配置DMA传输
    cyhal_dma_set_src_addr(&dma_tx_obj, (uint32_t)data);
    cyhal_dma_set_transfer(&dma_tx_obj, len);

    // 手动触发UART DMA请求
    Cy_SCB_SetRxFifoLevel(uart_obj.base, CY_SCB_FIFO_SIZE - 1);
    cyhal_dma_start_transfer(&dma_tx_obj);
}

3. 关键硬件配置优化


// 初始化UART时增加配置
cyhal_uart_cfg_t uart_cfg = {
    .data_bits = 8,
    .stop_bits = 1,
    .parity = CYHAL_UART_PARITY_NONE,
    .rx_buffer = NULL,
    .rx_buffer_size = 0,
    .flow_control = CYHAL_UART_FLOW_CTRL_RTS_CTS  // 启用硬件流控
};

// 配置FIFO深度匹配DMA
Cy_SCB_SetRxFifoLevel(uart_obj.base, 3); // 当FIFO>=3字节时触发DMA
Cy_SCB_SetTxFifoLevel(uart_obj.base, 0); // TX空时立即触发DMA

4. DMA配置完整示例


// TX DMA配置 (MEM->UART)
cyhal_dma_init(&dma_tx_obj, CYHAL_DMA_CHANNEL_0, NULL);
cyhal_dma_configure(&dma_tx_obj,
                   CYHAL_DMA_DIRECTION_MEM2PERIPH,
                   CYHAL_DMA_PRIORITY_HIGH);
cyhal_dma_set_src_addr(&dma_tx_obj, 0); // 动态设置
cyhal_dma_set_dst_addr(&dma_tx_obj, (uint32_t)&uart_obj.base->TX_FIFO_WR);

// RX DMA配置 (UART->MEM) - 循环模式
cyhal_dma_init(&dma_rx_obj, CYHAL_DMA_CHANNEL_1, NULL);
cyhal_dma_configure(&dma_rx_obj,
                   CYHAL_DMA_DIRECTION_PERIPH2MEM,
                   CYHAL_DMA_PRIORITY_VERY_HIGH,
                   CYHAL_DMA_DESCRIPTOR_CONTINUOUS); // 关键配置!!!
cyhal_dma_set_src_addr(&dma_rx_obj, (uint32_t)&uart_obj.base->RX_FIFO_RD);
cyhal_dma_set_dst_addr(&dma_rx_obj, (uint32_t)rx_buffer);
cyhal_dma_set_transfer(&dma_rx_obj, sizeof(rx_buffer));



验证步骤:



  1. 使用示波器检查TX/RX信号质量

  2. 降低波特率至115200进行基础测试

  3. 添加状态监测代码:
    printf("DMA TX State: %sn", cyhal_dma_is_busy(&dma_tx_obj) ? "Busy":"Ready");
    printf("UART Status: 0x%08lXn", Cy_SCB_GetInterruptStatus(uart_obj.base));

  4. 检查时钟配置:
    // 确保UART时钟>=4x波特率
    if(cyhal_uart_get_clock(&uart_obj) < (4 * baudrate)) {
    // 调整时钟分配器
    }



注意:在波特率超过1Mbps时必须使用硬件流控(RTS/CTS),PCB布线需保证信号完整性。如果仍存在问题,建议检查MPN配置工具生成的时钟树设置是否正确。


举报

更多回帖

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