查看: 4840|回复: 11

[分享] K60 DMA软件触发只能触发minor loop 一次???

[复制链接]

该用户从未签到

21

主题

62

帖子

0

中级会员

Rank: 3Rank: 3

积分
330
最后登录
1970-1-1
发表于 2015-1-25 19:56:08 | 显示全部楼层 |阅读模式
本帖最后由 冰水混合物-347708 于 2015-1-25 19:58 编辑

本人在使用软件触发DMA时,将通道源设置为关闭的(DMAMUX_CHCFGn的SOURCE字段设置为0),设置了major loop和minor loop等配置之后将CSR寄存器的START位置位启动传输,发现只触发了一次minor loop,在芯片手册中看到这么一句:
Use explicit software re-activation. In this option, the DMA is configured to transfer
the data using both minor and major loops, but the processor is required to re-activate
the channel (by writing to the DMA registers) after every minor loop. For this option,
the DMA channel should be disabled in the DMA channel MUX.

请问如何在每一次minor loop之后重新激活DMA?minor loop结束没有中断,不知道何时重新将CSR寄存器的START位置位?
PS:因为需要将数据从内存拷贝到SPI的数据寄存器,所以每次拷贝数据4个字节,所以不能只设置major loop次数为1。




回复

使用道具 举报

该用户从未签到

7

主题

27

帖子

0

注册会员

Rank: 2

积分
110
最后登录
1970-1-1
发表于 2015-1-25 22:17:01 | 显示全部楼层
1.第一个问题,不论软件触发还是硬件触发,一次都只能触发一次minor loop。从图一可知,一个DMA request只能触发一个minor loop。
2第二个问题,要多次触发minor,可以用硬件触发,比如在你的这个情况中可以配置硬件触发源为SPI模块
3第三个问题,你要拷贝4个字节的数据,可以在一个minor loop完成。如参考手册中给的例子,如图二

minor传输多字节

minor传输多字节

minor loop触发示意

minor loop触发示意
回复 支持 1 反对 0

使用道具 举报

该用户从未签到

21

主题

62

帖子

0

中级会员

Rank: 3Rank: 3

积分
330
最后登录
1970-1-1
 楼主| 发表于 2015-1-26 09:20:51 | 显示全部楼层
本帖最后由 冰水混合物-347708 于 2015-1-26 09:40 编辑
M4 发表于 2015-1-25 22:17
1.第一个问题,不论软件触发还是硬件触发,一次都只能触发一次minor loop。从图一可知,一个DMA request只 ...

谢谢,第一个问题和第二个问题明白了,但是我现在必须使用软件触发,因为需要在中断中判断是否要进行DMA传输,所以只能用软件触发,我使用软件触发,在进行内存到内存的传输是ok的,但是我需要将数据从内存传输到SPI0的数据寄存器PUSHR,修改配置之后发现,SPI1的接收有点问题,请问有什么方法可以验证SPI0的数据发送时没有问题的啊?我现在只能通过SPI1接收然后打印出来看,但是我总觉得应该是接收那块有问题,我把我的DMA的配置发您看看,DMA0通过软件触发,DMA1通过SPI1的接收触发,运行结果是DMA0的major loop完成了触发了中断,DMA1的major loop没有完成,即没有触发中断,打印出来传输正确的数据也只有前5个数据(总共24个数据,大小96字节),您看有什么错误没:
        //DMA0初始化
        DMA_InitTypeDef dma0_init_struct;
        //DMA参数配置
        memset(&dma0_init_struct, 0, sizeof(dma0_init_struct));        
        dma0_init_struct.DMA_CHx = DMA_CH0;                                   //CH0通道
        dma0_init_struct.DMA_Req = 0;                        //触发源关闭
        dma0_init_struct.DMA_MajorLoopCnt = 1;                                //主循环计数值
        dma0_init_struct.DMA_MinorByteCnt = 96;                                //次循环传输的字节数
        
        dma0_init_struct.DMA_SourceAddr = (uint32_t)&info;        //源地址
        dma0_init_struct.DMA_SourceAddrOffset = 4;                        //源地址偏移:每次读入增加n字节
        dma0_init_struct.DMA_SourceDataSize = DMA_SRC_32BIT;//源地址数据宽度
        dma0_init_struct.DMA_LastSourceAddrAdj = -96;                        //配置源数据地址在主循环完成后的调整量
        dma0_init_struct.DMA_DestAddr = (uint32_t)&SPI0->PUSHR; //目的地址
//        dma0_init_struct.DMA_DestAddr = (uint32_t)dest;
        dma0_init_struct.DMA_DestAddrOffset = 0;                        //目的地址偏移:每次写入增加0
        dma0_init_struct.DMA_DestDataSize = DMA_SRC_32BIT;        //目的地址数据宽度
        dma0_init_struct.DMA_LastDestAddrAdj = 0;                        //配置目的数据地址在主循环完成后的调整量
        dma0_init_struct.DMA_AutoDisableReq = TRUE;                        //自动禁用请求
        dma0_init_struct.DMA_Isr = DMA0_Isr;
        dma0_init_struct.DMA_MajorCompleteIntEnable = TRUE;
        //初始化DMA
        DMA_Init(dma0_init_struct);        
        DMA_EnableIrq(dma0_init_struct);
        DMA_EnableReq(DMA_CH0);  
        
        //DMA1初始化
        DMA_InitTypeDef dma1_init_struct;
        //DMA参数配置
        memset(&dma1_init_struct, 0, sizeof(dma1_init_struct));
        dma1_init_struct.DMA_CHx = DMA_CH1;                                   //CH0通道
        dma1_init_struct.DMA_Req = SPI1_REV_DMAREQ;                        //SPI0_TRAN_DMAREQ为触发源
        dma1_init_struct.DMA_MajorLoopCnt = 24;                                //主循环计数值
        dma1_init_struct.DMA_MinorByteCnt = 4;                                //次循环传输的字节数
        
        dma1_init_struct.DMA_SourceAddr = (uint32_t)&SPI1->POPR;        //源地址
        dma1_init_struct.DMA_SourceAddrOffset = 0;                        //源地址偏移:每次读入增加n字节
        dma1_init_struct.DMA_SourceDataSize = DMA_SRC_32BIT;//源地址数据宽度
        dma1_init_struct.DMA_LastSourceAddrAdj = 0;                        //配置源数据地址在主循环完成后的调整量
        dma1_init_struct.DMA_DestAddr = (uint32_t)&dest;
        dma1_init_struct.DMA_DestAddrOffset = 4;                        //目的地址偏移:每次读入增加4
        dma1_init_struct.DMA_DestDataSize = DMA_SRC_32BIT;        //目的地址数据宽度
        dma1_init_struct.DMA_LastDestAddrAdj = -96;                        //配置目的数据地址在主循环完成后的调整量
        dma1_init_struct.DMA_AutoDisableReq = TRUE;                        //自动禁用请求
        dma1_init_struct.DMA_Isr = DMA1_Isr;
        dma1_init_struct.DMA_MajorCompleteIntEnable = TRUE;
        //初始化DMA
        DMA_Init(dma1_init_struct);        
        DMA_EnableIrq(dma1_init_struct);
        DMA_EnableReq(DMA_CH1);  

还有个问题就是之前问的:如果我设置软件触发,多次传输,那么如何重新激活DMA?(问题中红色英文描述)
Use explicit software re-activation. In this option, the DMA is configured to transfer
the data using both minor and major loops, but the processor is required to re-activate
the channel (by writing to the DMA registers) after every minor loop
. For this option,
the DMA channel should be disabled in the DMA channel MUX.
回复 支持 反对

使用道具 举报

该用户从未签到

7

主题

27

帖子

0

注册会员

Rank: 2

积分
110
最后登录
1970-1-1
发表于 2015-1-26 20:07:09 | 显示全部楼层
本帖最后由 M4 于 2015-1-26 20:15 编辑

1第一个问题验证SPI0的数据发送时没有问题的啊?,要验证这个,你可以用其他办法直接接收由SPI0的数据, 比如用spi接口的液晶屏之类的(确定液晶屏接受好用的)
2第二个问题spi1只接收到5个数据!  SPI模块我不是非常清楚,但我觉得(没验证)你DMA0一次传输96个字节,应该会导致SPI0的传送队列溢出吧!因为SPI的队列深度是4级,加上一个PUSH,恰好是5个数据(32位的),因为DMA的频率传输非常快,而spi相比于DMA则要慢的多!!
3第三个问题but the processor is required to re-activate
the channel (by writing to the DMA registers) after every minor loop.
你要软件触发的话,在每一个minor loop之后,都得去软件触发,具体就是在每次minor loop之后给寄存器TCD Control and Status (DMA_TCD_CSR)的START位写1。

软件触发

软件触发

SPI度列深度

SPI度列深度
回复 支持 反对

使用道具 举报

该用户从未签到

21

主题

62

帖子

0

中级会员

Rank: 3Rank: 3

积分
330
最后登录
1970-1-1
 楼主| 发表于 2015-1-26 20:39:04 | 显示全部楼层
本帖最后由 冰水混合物-347708 于 2015-1-26 20:41 编辑
M4 发表于 2015-1-26 20:07
1第一个问题验证SPI0的数据发送时没有问题的啊?,要验证这个,你可以用其他办法直接接收由SPI0的数据, 比 ...

谢谢,第二个问题你这么一说还真有可能,那最好的方法还是每次minor loop发1个字节,再设置major loop,那就还是要归结到第三个问题,如何re-activate 下一次的minor loop了,关于第三个问题,寄存器TCD Control and Status (DMA_TCD_CSR)的START位写1,我看了芯片手册,“Testing for minor loop completion”这一节,见图1,那我是不是触发了一次之后就要接着用while来判断TCDn_CSR[ACTIVE]位有没有被置为0来判断minor loop是否结束?这样感觉比较麻烦,芯片手册也没写其他的方法好像=。=!

图1

图1
回复 支持 反对

使用道具 举报

该用户从未签到

7

主题

27

帖子

0

注册会员

Rank: 2

积分
110
最后登录
1970-1-1
发表于 2015-1-26 20:54:44 | 显示全部楼层
冰水混合物-347708 发表于 2015-1-26 20:39
谢谢,第二个问题你这么一说还真有可能,那最好的方法还是每次minor loop发1个字节,再设置major loop,那 ...

确实是这样的,因为minor loop结束没有什么信号指示。另外也不能这样样子做,这样的cpu一直在监视DMA,DMA就没意义了。
有两种解决办法
1.将major loop所包含的minor loop的次数设置为1,且配置major loop结束时产生中断,这样每次major loop产生一次中断,在中断中去触发下一次major loop。
2.启用两个DMA通道,且配置成minor loop结束时链接模式(或者major loop结束时链接模式)。然后在链接中相互嵌套(比如DMA_CH0与DMA_CH1相互链接)
回复 支持 反对

使用道具 举报

该用户从未签到

21

主题

62

帖子

0

中级会员

Rank: 3Rank: 3

积分
330
最后登录
1970-1-1
 楼主| 发表于 2015-1-27 14:45:06 | 显示全部楼层
M4 发表于 2015-1-26 20:54
确实是这样的,因为minor loop结束没有什么信号指示。另外也不能这样样子做,这样的cpu一直在监视DMA,DM ...

谢谢了,马上试下您的建议。PS:您对DMA的理解十分深刻,给了我很多启发,谢谢!
回复 支持 反对

使用道具 举报

该用户从未签到

7

主题

27

帖子

0

注册会员

Rank: 2

积分
110
最后登录
1970-1-1
发表于 2015-1-27 21:30:46 | 显示全部楼层
冰水混合物-347708 发表于 2015-1-27 14:45
谢谢了,马上试下您的建议。PS:您对DMA的理解十分深刻,给了我很多启发,谢谢! ...

哈哈,我也是被逼无奈啊!这几天刚好要用DMA,看了很久技术手册,查了很多资料.所以正好在火候上

对了,我觉得关于DMA,K60的参考手册里给了两个例子,很生动具体! 你可以去看看,非常有助于理解的!
回复 支持 反对

使用道具 举报

该用户从未签到

21

主题

62

帖子

0

中级会员

Rank: 3Rank: 3

积分
330
最后登录
1970-1-1
 楼主| 发表于 2015-1-28 09:18:00 | 显示全部楼层
M4 发表于 2015-1-27 21:30
哈哈,我也是被逼无奈啊!这几天刚好要用DMA,看了很久技术手册,查了很多资料.所以正好在火候上

对 ...

那两个例子我看了,因为是内存到内存的搬运,所以感觉没啥问题,自己试验也做了,可是从内存到外设或者从外设到内存就不停的遇到问题了=。=!
回复 支持 反对

使用道具 举报

该用户从未签到

21

主题

62

帖子

0

中级会员

Rank: 3Rank: 3

积分
330
最后登录
1970-1-1
 楼主| 发表于 2015-1-28 09:19:04 | 显示全部楼层
M4 发表于 2015-1-27 21:30
哈哈,我也是被逼无奈啊!这几天刚好要用DMA,看了很久技术手册,查了很多资料.所以正好在火候上

对 ...

那个连接模式是啥意思啊?我看了没怎么明白,您给我介绍下呢
回复 支持 反对

使用道具 举报

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

本版积分规则

关闭

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

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

GMT+8, 2025-7-22 16:28 , Processed in 0.112098 second(s), 29 queries , MemCache On.

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.

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