关于LiteOS UART1 DMA发送的疑问

问题描述:

  1. 采用DMA1 channel4 作为uart1发送DMA

  2. 发现如果启动DMA1 channel4 发送后,如果不查询等待发送结束,接收数据完整

  3. 疑问是:DMA是用来释放CPU资源,但是现在还需要等待DMA发送完成,不能释放CPU,DMA存在的意义在哪里?

完整代码:

icon_rar.gifLiteOS_m.zip

代码截取如下:

static void DMA_TX_INIT(uint16_t cnt) {

    DMA_InitTypeDef DMA_InitStructure = { 0 };

    USART_DMACmd(USART1, USART_DMAReq_Tx, DISABLE); //关闭UART1 DMA发送

    DMA_Cmd(DMA1_Channel4, DISABLE); /* DMA1 Channel4 关闭 */

    DMA_DeInit(DMA1_Channel4);

    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32) (&USART1->DATAR); 

    DMA_InitStructure.DMA_MemoryBaseAddr = (u32) TxBuffer1;//发送数据地址

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

    DMA_InitStructure.DMA_BufferSize = cnt;//发送数据长度

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel4, &DMA_InitStructure);

    DMA_Cmd(DMA1_Channel4, ENABLE); /* 使能DMA1 Channel4 */

    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); //使能UART1 DMA发送

    while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET) /* 等待发送完成,如果去掉这一句,接收就不完整 */

        {

        }


}

void UART1_DMA_Send(u8 *buf, u16 cnt) {

    if (cnt > TxSize1)

        return;

    memcpy(TxBuffer1, buf, cnt);

    DMA_TX_INIT(cnt);

}


VOID RFBLE_Task(VOID) {

    while(1) {

        //LOS_WAIT_FOREVER

        uint32_t ret=LOS_SemPend(g_semId, 100);//信号量超时

        if(ret==LOS_OK)

            UART1_DMA_Send(RxBuffer1Handle,rxDataCnt);//接收回环测试,实际上不给单片机发数据不会触发

        else if(ret==LOS_ERRNO_SEM_TIMEOUT)//信号量超时,发送下面内容

        {

            u8 * RxBuffer1Handle1="hello harmonyOS\r\n";//发送内容

            UART1_DMA_Send(RxBuffer1Handle1,strlen(RxBuffer1Handle1));

        }

    }

}


问题复现100%:

1.去掉红色代码,接收乱了

[12:14:12.889]接收←hel

[12:14:13.140]接收←lo 

[12:14:14.078]接收←harmhe

[12:14:14.328]接收←llo

[12:14:15.278]接收← harhe

[12:14:15.528]接收←llo

[12:14:16.484]接收← harhe

[12:14:16.720]接收←llo

[12:14:17.675]接收← harhe

[12:14:17.925]接收←llo

[12:14:18.863]接收← harhe

[12:14:19.123]接收←llo

[12:14:20.070]接收← harhe

[12:14:20.318]接收←llo

[12:14:21.256]接收← harhe

[12:14:21.506]接收←llo


2.加上红色代码,接收正常

[12:15:36.330]接收←hello harmonyOS

                    

[12:15:37.533]接收←hello harmonyOS

                    

[12:15:38.721]接收←hello harmonyOS

                    

[12:15:39.915]接收←hello harmonyOS




CH32V203c8t6


您好,关于你的问题,若不加查询等待接收异常,可能是由于你程序中使用了操作系统,进行多线程操作时,该传输若不加判断可能会被其他线程或自己打断,导致传输出现错误。此外关于DMA,正常在使用的时候都会对传输是否完成加个判断,若你不想使用while方式,可以使用中断方式,当传输完成之后进入传输完成中断。此外,若不想查询等待,可尝试在传输过程中加个缓冲区试一下。后续若有问题,可通过邮箱(lzs@wch.cn)和我沟通,关于你的工程,若需要我这边看一下建议将SRC文件夹一起压缩到压缩包发过来,否则工程缺少文件编译报错。


问题似乎已经找到,出在litesOS调度上,在DMA尚未完成传输的时候,已经进入idleTask,IdleTask又进入低功耗模式(__WIFI),导致DMA传输尚未完成,就被终止了,当前用while查询方式解决,算是比较好的方式了。即使用DMA中断方式,仍然需要告知liteOS在传输完成之前不能进入低功耗模式,这样好像更复杂了。

icon_rar.gifSRC.zip



只有登录才能回复,可以选择微信账号登录