请选择 进入手机版 | 继续访问电脑版
查看: 13138|回复: 9

【飞凌RT1052】串口空闲中断+接收DMA实现不定长接收详解

[复制链接]
  • TA的每日心情
    开心
    2018-4-20 15:04
  • 签到天数: 8 天

    [LV.3]偶尔看看II

    49

    主题

    188

    帖子

    1

    金牌会员

    Rank: 6Rank: 6

    积分
    2945
    最后登录
    2023-7-24
    发表于 2018-11-27 20:20:26 | 显示全部楼层 |阅读模式
    【飞凌RT1052】串口空闲中断+接收DMA实现不定长接收详解


        因为后面的Demo中需要用到8266做设备控制,因此调通板上LPUART2串口的不定长接收是很有必要的。
        在单片机中,实现串口不定长接收有两种方式,第一是循环队列+结束标志+溢出标志位,当一次接收的数据超出队列结构长度即队列满时,触发溢出标志位;当上一次的数据处理完毕后,回收内存空间,以用于下次队列周期的数据存放;判断一次接收完成的标志是结束标志字节,通常是0x0d或0x0a或0x0d+0x0a。这种方法的优势是能最大限度合理利用内存空间,缺点是必须要加结束标志位,所以还有第二种方法,即串口空闲中断+串口接收DMA通道实现的不定长接收,这种方法代码好写,易于理解,适合新手学习和串口项目的快速搭建。空闲中断的原理是当串口在一定的、很短的单位时间以后没有接收到新的数据,就触发中断,通常用于下位机串口发送一帧的场合,空闲中断能很好的判断一次或一帧串口数据的接收,但是空闲中断本身是不可以实现不定长接收的,要实现不定长接收,也只能通过结束标志位或DMA的方式实现。在空闲中断中,接收DMA的作用并不是像单片机新手教程写的那样,是为了减轻CPU负担,而是为了搬运串口外设中长度未知的数据,这帧接收到的数据到底有多长呢,就是在空闲中断触发之后结束DMA接收,用DMA通道总长度减去DMA末端未使用的长度(LPUARTx->TCD寄存器值):
    int count;
    LPUART_TransferGetReceiveCountEDMA(LPUART1, &g_lpuartEdmaHandle,&count);
    LPUART_TransferAbortReceiveEDMA(LPUART1, &g_lpuartEdmaHandle);

    硬件连接,为了测试板上十针LPUART2接口,我接了一个CH340模块,注意TX RX要反接:
    IMG_20181127_195339R.jpg
    然后就是编写程序了,首先要启用串口2的空闲中断和接收DMA(EDMA外设),并且数组还必须是非缓存优化的,不然数组的内容不会刷新:

    AT_NONCACHEABLE_SECTION_INIT(uint8_t uart2_rx_buffer[255]) = {0};

    void LPUART2_Init(int baud)
    {
            LPUART_GetDefaultConfig(&config);
      config.baudRate_Bps=115200;
      config.enableTx = true;
      config.enableRx = true;
      LPUART_Init(LPUART2, &config,BOARD_DebugConsoleSrcFreq());
            LPUART_EnableInterrupts(LPUART2,kLPUART_IdleLineInterruptEnable);
           
            IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_02_LPUART2_TX,0);
      IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_03_LPUART2_RX,0);   
           
            IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_02_LPUART2_TX,0x10B0u);
      IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_03_LPUART2_RX,0x10B0u);
           
      EnableIRQ(LPUART2_IRQn);
           
            DMAMUX_Init(DMAMUX);
      DMAMUX_SetSource(DMAMUX,1,kDmaRequestMuxLPUART2Rx);
      DMAMUX_EnableChannel(DMAMUX,1);
           
            EDMA_GetDefaultConfig(&econfig);
      EDMA_Init(DMA0,&econfig);
      EDMA_CreateHandle(&g_lpuartRxEdmaHandle,DMA0,1);

            LPUART_TransferCreateHandleEDMA(LPUART2,&g_lpuartEdmaHandle,NULL,NULL,NULL,&g_lpuartRxEdmaHandle);

      receiveXfer.data=uart2_rx_buffer;
      receiveXfer.dataSize=255;
            LPUART_ReceiveEDMA(LPUART2,&g_lpuartEdmaHandle,&receiveXfer);
    }

    在中断服务函数里面获得数据长度以及结束DMA传输,注意这个长度必须为全局变量,因为别的代码要用到:
    int count;
    void LPUART2_IRQHandler()
    {
            if((kLPUART_IdleLineFlag)&LPUART_GetStatusFlags(LPUART2))
            {
                    lpuart2_dma_flag=1;
                    LPUART_TransferGetReceiveCountEDMA(LPUART2,&g_lpuartEdmaHandle,(uint32_t*)&count);
                    printf("%d\n",count);
                    LPUART2->STAT |= LPUART_STAT_IDLE_MASK;
                    //清除空闲中断
                    LPUART_TransferAbortReceiveEDMA(LPUART2,&g_lpuartEdmaHandle);
            }
    }

    在主循环中,如果检测到串口空闲中断触发了,就在中断响应结束之后重新开启DMA传输,并且数组每次都要清空,不然数组的内容同样不会刷新:
    while(1)
    {
    ...
    LPUART_DMA_Get();
    ...
    }

    void LPUART_DMA_Get()
    {
            int i;
            if(lpuart2_dma_flag)
            {
                    lpuart2_dma_flag=0;
                    memset(uart2_rx_buffer,0,255);
                    LPUART_ReceiveEDMA(LPUART2,&g_lpuartEdmaHandle,&receiveXfer);
                    printf("%s\n",uart2_rx_buffer);
            }
    }

    观察效果,一个是LPUART1负责printf打印信息,另一个是LPUART2负责接收:
    48.jpg
    最后提醒一下,由于串口接收处理涉及到DMA接收,需要占用主循环的时间片,因此不能与DHT11 RX8010等传感器的检测工作同时开启,需要用开关切换串口接收,当串口接收开启的时候,DHT11和RX8010的检测工作暂停。
    IMG_20181127_201535R.jpg

    今天心情不错
    回复

    使用道具 举报

  • TA的每日心情

    2019-2-12 11:34
  • 签到天数: 33 天

    [LV.5]常住居民I

    10

    主题

    149

    帖子

    2

    高级会员

    Rank: 4

    积分
    673
    最后登录
    2021-9-30
    发表于 2018-11-28 10:21:59 | 显示全部楼层
    顶一个
    哎...今天够累的,签到来了~
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-12-16 09:52
  • 签到天数: 1 天

    [LV.1]初来乍到

    1

    主题

    7

    帖子

    0

    新手上路

    Rank: 1

    积分
    38
    最后登录
    2019-1-20
    发表于 2018-12-17 09:03:13 | 显示全部楼层
    楼主 为啥我没找到RT052在哪设置串口FIFO长度呢   感觉好不合理  中断触发位FifoWatermark也是只能设置为0,1,2,3 。
    how to set rt1052 LPUART fifo depth????
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-12-16 09:52
  • 签到天数: 1 天

    [LV.1]初来乍到

    1

    主题

    7

    帖子

    0

    新手上路

    Rank: 1

    积分
    38
    最后登录
    2019-1-20
    发表于 2019-1-18 17:18:26 | 显示全部楼层
    楼主程序留一个啊
    how to set rt1052 LPUART fifo depth????
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2024-4-10 22:38
  • 签到天数: 1335 天

    [LV.10]以坛为家III

    88

    主题

    4292

    帖子

    12

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    9049
    最后登录
    2024-4-13
    发表于 2019-1-19 11:22:09 | 显示全部楼层
    串口的空闲中断还是非常好用的。
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    0

    主题

    1

    帖子

    0

    新手上路

    Rank: 1

    积分
    4
    最后登录
    2019-4-25
    发表于 2019-4-25 18:05:08 | 显示全部楼层
    你好,看了你的DMA接收程序
    深有启发
    不过我在调试过程中,一直遇到问题 。
    直到将非缓存优化的数组改成普通的UINT8数组 就成功了
    请问不使用非缓存优化会带来什么缺点吗
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    1

    主题

    7

    帖子

    0

    新手上路

    Rank: 1

    积分
    28
    最后登录
    2019-9-9
    发表于 2019-8-7 18:07:38 | 显示全部楼层
    yyylonghui 发表于 2019-4-25 18:05
    你好,看了你的DMA接收程序
    深有启发
    不过我在调试过程中,一直遇到问题 。

    看一下你的分散加载文件!!!!看看你的NONCACHE段定义到哪里去了!!不出意外,你定义到了0X80000000开始了。。。。。不要怪谁,要怪就怪野火的兄弟写代码不小心!!!你肯定是用了nor_itcm_txt_ram的配置!!!! 其他配置是正常了!!!
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    1

    主题

    8

    帖子

    0

    新手上路

    Rank: 1

    积分
    25
    最后登录
    2021-9-13
    发表于 2021-9-7 15:49:25 | 显示全部楼层
    “count这个长度必须为全局变量,因为别的代码要用到”,其他还有什么地方会用到呢,我现在进不了终端服务函数,是什么原因啊楼主
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2022-10-14 11:16
  • 签到天数: 2 天

    [LV.1]初来乍到

    0

    主题

    48

    帖子

    0

    注册会员

    Rank: 2

    积分
    129
    最后登录
    2023-9-12
    发表于 2022-4-24 20:57:09 | 显示全部楼层
    楼主您好,我看您设置的DMA缓存长度,如果我一次发送的数据帧长大于DMA缓存数组长度这个怎么处理呢。希望楼主回答一下
    加油打工人
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    0

    主题

    1

    帖子

    0

    新手上路

    Rank: 1

    积分
    28
    最后登录
    2023-2-17
    发表于 2023-1-12 22:57:55 | 显示全部楼层
    楼主您好,可我只能进一次串口空闲中断不知道啥原因
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-18 08:46 , Processed in 0.147029 second(s), 31 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表