打印

关于TM4C123BE6P芯片UART0的uDMA接收不成功问题

[复制链接]
1617|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
pinda_|  楼主 | 2015-10-24 17:02 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 pinda_ 于 2015-10-24 17:04 编辑

问题分析:
      当前,我先使用FIFO完成了UART0的接收与发送配置,现在,我需要将uDMA加入UART0中。根据例程,我开始尝试:
第一步 - 配置uDMA时钟使能
           SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
第二步 - 在UART0的配置中,将UART0_TX与UART0_RX加入uDMA中
           UARTDMAEnable(UART0_BASE, UART_DMA_RX | UART_DMA_TX);
第三步 - 使能uDMA控制器与指定控制列表地址(用户自定义值为Udma_Control_Table)
          uDMAEnable();
          uDMAControlBaseSet(Udma_Control_Table);
ps: 这里,我暂时不需要uDMA错误中断配置,所以,没有进行配置。
第四步 - 定义主发送缓冲区(Udma_Uart0_Xmit_Buf)和主接收缓冲区与备用接收缓冲区(Udma_Uart0_Recv_Buf_A,Udma_Uart0_Recv_Buf_B)
          uchar Udma_Uart0_Xmit_Buf[256] = {0x11};
          uchar Udma_Uart0_Recv_Buf_A[256] = {0x22};
          uchar Udma_Uart0_Recv_Buf_B[256] = {0x33};
第五步 - 配置三个通道,两个采用接收通道的控制参数(PINGPONG模式),一个发送通道的控制参数(BASIC模式);同时,配置他们的通道属性:
         // 接收通道
         uDMAChannelControlSet(UDMA_CHANNEL_UART0RX | UDMA_PRI_SELECT,
                                                         UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
                                                         UDMA_ARB_8);
          uDMAChannelControlSet(UDMA_CHANNEL_UART0RX | UDMA_ALT_SELECT,
                                                          UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
                                                          UDMA_ARB_8);
         uDMAChannelAttributeDisable(UDMA_CHANNEL_UART0RX,
                                                                  UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
                                                                  UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
         uDMAChannelAttributeEnable(UDMA_CHANNEL_UART0RX,
                                                                 UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
                                                                 UDMA_ATTR_HIGH_PRIORITY);
        // 发送通道
        uDMAChannelControlSet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT,
                                                       UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |
                                                       UDMA_ARB_8);
       uDMAChannelAttributeDisable(UDMA_CHANNEL_UART0TX,
                                                                UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
                                                               UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
      uDMAChannelAttributeEnable(UDMA_CHANNEL_UART0TX,
                                                              UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY);
问题一:这里,有一点不明白,uDMAChannelControlSet库函数中的仲裁大小与UART0中的FIFO深度需要匹配,但是,在UART0中基数为16,假设我设置如下:
    UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);
那触发点不是8个字节吗?同理,在uDMA中的仲裁大小不是也应该设置UDMA_ARB_8(我认为表示的是8个数目),而TI例程中用UDMA_ARB_4,不是很理解,帮忙解释下?

第六步 - 调用uDMAChannelTransferSet和uDMAChannelEnable函数发送数据
             uDMAChannelTransferSet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT,
                                                              UDMA_MODE_BASIC,
                                                              Udma_Uart0_Xmit_Buf, (void *)(UART0_BASE + UART_O_DR),
                                                              sizeof(Udma_Uart0_Xmit_Buf));
             uDMAChannelEnable(UDMA_CHANNEL_UART0TX);

以上操作步骤都实验完成。

问题二:但是,我现在想用uDMA接收数据。上位机通过串口TTL电平发送100个数据下来,进入我的UART0中断Uart0_IntHandle,但是,uDMAChannelModeGet函数在UART0中断获取到的值一直为3,也就是PINGPONG模式,并没有得到例程中的0(STOP),也就是接收一直不完成?不明白。
问题三:对于uDMAControlBaseSet函数,其中的地址是不是只是充当uDMA的临时寄存器,该值的大小,由发送与接收通道控制结构体大小有关系?
希望给予下回答,谢谢;

以下是中断函数代码,对于例程中的中断函数,采用回环控制,但是,数据接收只是单纯的uDMAChannelTransferSet,并没有配置使能接收通道uDMAChannelEnable(UDMA_CHANNEL_UART0RX)语句,这样不是表示该功能是禁止的吗,调用发送好像没有意义,而且这里的发送,我根据源地址与目的地址理解,是将UART0数据寄存器中读取数据,写入我新定义的uDMA接收缓冲地址中,不知道这样理解对吗?

void Uart0_IntHandle(void)
{
    /* 中断状态反馈 */
        uint32 ulIntState;
        uint32 ulModeRx;
        uint32 ulModeTx;

    //! The \e ulIntState parameter is the logical OR of any of the following:
        //!
        //! - \b UART_INT_OE - Overrun Error interrupt
        //! - \b UART_INT_BE - Break Error interrupt
        //! - \b UART_INT_PE - Parity Error interrupt
        //! - \b UART_INT_FE - Framing Error interrupt
        //! - \b UART_INT_RT - Receive Timeout interrupt
        //! - \b UART_INT_RX - Receive interrupt
        ulIntState = UARTIntStatus(UART0_BASE, TRUE);

        /* Clear the interrupt flag */
        UARTIntClear(UART0_BASE, ulIntState);
       
        /* Check the DMA control table to see if the ping-pong "A" transfer is
       complete.  The "A" transfer uses receive buffer "A", and the primary
       control structure. */
        ulModeRx = uDMAChannelModeGet(UDMA_CHANNEL_UART0RX | UDMA_PRI_SELECT);
       
        ulModeTx = uDMAChannelModeGet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT);

    /* 检查当前中断状态,做出对应的处理方式 */
        switch (ulIntState)
        {
            case UART_INT_RX:
                {
                    Uart0_Recv_IntHandle();
                }
                break;
            case UART_INT_RT:
                {
                   
                }
                break;
            case UART_INT_OE:
                {
                    
                }
                break;
        case UART_INT_BE:
                {
                       
                }
                break;
        case UART_INT_PE:
                {
                    
                }
                break;
        case UART_INT_FE:
                {
                       
                }
                break;
        default: break;
        }
}

如果有什么相关资料可以参考,希望发份资料看看,争取把uDMA搞完。

评分
参与人数 1威望 +6 收起 理由
dirtwillfly + 6 赞一个!

相关帖子

沙发
dirtwillfly| | 2015-10-25 09:06 | 只看该作者
@xyz549040622 帮看看这个问题

使用特权

评论回复
板凳
xyz549040622| | 2015-10-28 16:02 | 只看该作者
你这个问题,我再查查资料,不敢贸然回答,需要实际测试的。如果楼主测试好了,也可以分享下经验。

使用特权

评论回复
地板
baimiaocun2015| | 2015-10-28 22:53 | 只看该作者
定义主发送缓冲区(Udma_Uart0_Xmit_Buf)和主接收缓冲区与备用接收缓冲区(Udma_Uart0_Recv_Buf_A,Udma_Uart0_Recv_Buf_B),,这个是很关键。

使用特权

评论回复
5
旧影子| | 2015-10-29 16:32 | 只看该作者
看不懂,给楼主支持下!

使用特权

评论回复
6
米尔豪斯| | 2015-10-29 19:09 | 只看该作者
uDMA是什么

使用特权

评论回复
7
可可球| | 2015-10-29 20:33 | 只看该作者
Ultra DMA的英文拼写为“Ultra Direct Memory Access”,一般简写为UDMA,含义是超直接存储器存取(海量存储接口)

使用特权

评论回复
8
pinda_|  楼主 | 2015-10-30 12:47 | 只看该作者
谢谢各位参与其中,正在调试中,离崩溃不远了,也离成功不远了。。。。

使用特权

评论回复
9
dirtwillfly| | 2015-10-30 14:18 | 只看该作者
pinda_ 发表于 2015-10-30 12:47
谢谢各位参与其中,正在调试中,离崩溃不远了,也离成功不远了。。。。

加油

使用特权

评论回复
10
陌小生| | 2015-10-30 23:35 | 只看该作者

其实还是DNA,TI的命名方式不同的原因。楼主的问题,好专业,不懂

使用特权

评论回复
11
pinda_|  楼主 | 2015-11-2 11:24 | 只看该作者
@dirtwillfly , 已解决,有时间更新下帖子,忙着make的事

使用特权

评论回复
12
pinda_|  楼主 | 2015-11-2 11:25 | 只看该作者
陌小生 发表于 2015-10-30 23:35
其实还是DNA,TI的命名方式不同的原因。楼主的问题,好专业,不懂

是的是的,就是一个DMA。但是,就是用一下,看看FIFO性能高还是DMA,内存利用率几方面去考虑。

使用特权

评论回复
13
cady| | 2015-11-3 23:43 | 只看该作者

版主不是万能的么

使用特权

评论回复
14
dirtwillfly| | 2015-11-4 08:03 | 只看该作者
cady 发表于 2015-11-3 23:43
版主不是万能的么

:lol肯定啊,版主也不是神仙,不可能什么都会

使用特权

评论回复
15
309030| | 2015-11-10 19:20 | 只看该作者
是的是的,就是一个DMA

是命名问题了

使用特权

评论回复
16
冰河w| | 2015-11-12 21:30 | 只看该作者
楼主调试成功了吗

使用特权

评论回复
17
pinda_|  楼主 | 2015-11-20 10:16 | 只看该作者
离上一次提问到过了好一段时间了,逗了一段时间,最近弄改官方makefile浪费了一些时间。
然而,最晚偶遇周公托梦,说我二姨家还有件事没完成,故来此结贴。(这能让我笑上一上午)

首先,要说的是,整个流程是正确的,调试不通主要体现在第五步的通道属性配置上,如下:
uDMAChannelAttributeEnable(UDMA_CHANNEL_UART0RX,
                                                                 UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
                                                                 UDMA_ATTR_HIGH_PRIORITY);
这里我们对UART0RX使用备用数据结构,突发模式,高优先级。突发模式与高优先级这里不作介绍了,主要说说备用数据结构,开始以为这里主要响应备用数据结构的启用,后来查手册,看到一段话,如下:

8.3.3.1 Configure the Channel Attributes
First, configure the channel attributes:
1. Configure bit 7 of the DMA Channel Priority Set (DMAPRIOSET) or DMA Channel Priority
Clear (DMAPRIOCLR) registers to set the channel to High priority or Default priority.
2. Set bit 7 of the DMA Channel Primary Alternate Clear (DMAALTCLR) register to select the
primary channel control structure for this transfer.
3. Set bit 7 of the DMA Channel Useburst Clear (DMAUSEBURSTCLR) register to allow the
μDMA controller to respond to single and burst requests.
4. Set bit 7 of the DMA Channel Request Mask Clear (DMAREQMASKCLR) register to allow
the μDMA controller to recognize requests for this channel.

其中第二点说设置DMAALTCLR寄存器的bit7位清除选项,DMAALTCLR寄存器中有如下说明:
Register 17: DMA Channel Primary Alternate Clear (DMAALTCLR), offset
0x034
Each bit of the DMAALTCLR register represents the corresponding μDMA channel. Setting a bit
clears the corresponding SET[n] bit in the DMAALTSET register.


Value Description
0  No effect.
1 Setting a bit clears the corresponding SET[n] bit in the
DMAALTSET register meaning that channel [n] is using the
primary control structure.

Note: For Ping-Pong and Scatter-Gather cycle types, the µDMA
controller automatically sets these bits to select the alternate
channel control data structure.


上面说明了,DMA先使用主要数据结构选项还是备用数据结构,所以更改第五步的语句为:


uDMAChannelAttributeEnable(UDMA_CHANNEL_UART0RX,
                                                      UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY);
这时候就先触发主要数据结构接收数据,通道更改后,再启用备用数据结构接收数据;

最后更新我们的中断处理程序,如下:

void Uart0_IntHandle(void)
{
    /* 中断状态反馈 */        uint32 ulIntState;
        uint32 ulModeRx;
        uint32 ulModeRx1;
        uint32 ulModeTx;

    //! The \e ulIntState parameter is the logical OR of any of the following:
        //!
        //! - \b UART_INT_OE - Overrun Error interrupt
        //! - \b UART_INT_BE - Break Error interrupt
        //! - \b UART_INT_PE - Parity Error interrupt
        //! - \b UART_INT_FE - Framing Error interrupt
        //! - \b UART_INT_RT - Receive Timeout interrupt
        //! - \b UART_INT_RX - Receive interrupt
        ulIntState = UARTIntStatus(UART0_BASE, TRUE);

        /* Clear the interrupt flag */
        UARTIntClear(UART0_BASE, ulIntState);
       
        /* Check the DMA control table to see if the ping-pong "A" transfer is
       complete.  The "A" transfer uses receive buffer "A", and the primary
       control structure. */
        ulModeRx = uDMAChannelModeGet(UDMA_CHANNEL_UART0RX | UDMA_PRI_SELECT);
        ulModeRx1 = uDMAChannelModeGet(UDMA_CHANNEL_UART0RX | UDMA_ALT_SELECT);
       
        ulModeTx = uDMAChannelModeGet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT);
        if (ulModeRx == UDMA_MODE_STOP)
        {
                MEMSET_CLEAR(Udma_Uart0_Recv_Buf_A, sizeof(Udma_Uart0_Recv_Buf_A));
               
                /* 配置uDMA传送缓冲区:包括通过UART0与主要数据结构的逻辑或,
                                                          参数为传输类型是PINGPONG
                                                                        传输源地址为UART0基址
                                                                        传输目的地址为用户自定义变量Udma_Uart0_Recv_Buf_A地址
                                                                        传输数据项目数为用户自定义变量Udma_Uart0_Recv_Buf_A大小 */
                uDMAChannelTransferSet(UDMA_CHANNEL_UART0RX | UDMA_PRI_SELECT,
                                                           UDMA_MODE_PINGPONG,
                                                           (void *)(UART0_BASE + UART_O_DR),
                                                           Udma_Uart0_Recv_Buf_A, sizeof(Udma_Uart0_Recv_Buf_A));
                /* 这里不需要重新使能UART0RX接收通道 */
        }
        if (ulModeRx1 == UDMA_MODE_STOP)
        {
                MEMSET_CLEAR(Udma_Uart0_Recv_Buf_B, sizeof(Udma_Uart0_Recv_Buf_B));
               
                /* 配置uDMA传送缓冲区:包括通过UART0与备用数据结构的逻辑或,
                                                          参数为传输类型是PINGPONG
                                                                        传输源地址为UART0基址
                                                                        传输目的地址为用户自定义变量Udma_Uart0_Recv_Buf_B地址
                                                                        传输数据项目数为用户自定义变量Udma_Uart0_Recv_Buf_B大小 */
                uDMAChannelTransferSet(UDMA_CHANNEL_UART0RX | UDMA_ALT_SELECT,
                                                           UDMA_MODE_PINGPONG,
                                                           (void *)(UART0_BASE + UART_O_DR),
                                                           Udma_Uart0_Recv_Buf_B, sizeof(Udma_Uart0_Recv_Buf_B));
        }       
}


上面的关于通道发送的中断没给出来,代码给我删掉了:'(,总之与接收类似。

最后想说的是:当前在UART上,我虽然调试出来了,但是没用,这款芯片才32K片内RAM,uDMA所需要的空间有点浪费,结果,我没用上,哈哈。
造化弄人啊,以前在DSP上弄这个,觉得很好用(片外内存大啊,随便用,完全不担心,给个10000个字节的变量,我好开森)。

该认真的时候也要认真一回,逗一点生活快乐,认真一点嘛,其实我不是很喜欢啦~~~
写得不好,请大家随便提意见,哈哈,如果对于其中说的不是很理解的地方,也可以继续留言,我偶尔来来,看到了会回复你的。

使用特权

评论回复
18
pinda_|  楼主 | 2015-11-20 10:18 | 只看该作者
@dirtwillfly 已经更新;
@冰河w 可以看看,如有疑问,继续跟贴;

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:该吃吃,该喝喝!!!

13

主题

173

帖子

0

粉丝