OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7474|回复: 18

STM32的SPI3的DMA,这样配置对吗?

[复制链接]

6

主题

19

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2016-4-7
在线时间
17 小时
发表于 2016-5-31 17:45:42 | 显示全部楼层 |阅读模式
5金钱
unsigned char DMA1_Init(void)
{
         DMA_InitTypeDef DMA1_Init;
               
         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2,ENABLE);

         //DMA2通道2用于RAM->SPI的数据传输
         DMA_DeInit(DMA2_Channel2);//发送
         DMA1_Init.DMA_PeripheralBaseAddr=(u32)&SPI3->DR;//SPI3_DR_Address (u32)&SPI3->DR
         //DMA1_Init.DMA_MemoryBaseAddr=...; //启动传输前装入实际RAM地址
         DMA1_Init.DMA_DIR=DMA_DIR_PeripheralDST;
         DMA1_Init.DMA_BufferSize=1028;//1028
         DMA1_Init.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
         DMA1_Init.DMA_MemoryInc=DMA_MemoryInc_Enable;
         DMA1_Init.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
         DMA1_Init.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
         DMA1_Init.DMA_Mode=DMA_Mode_Normal;
         DMA1_Init.DMA_Priority=DMA_Priority_High;
         DMA1_Init.DMA_M2M=DMA_M2M_Disable;

         DMA_Init(DMA2_Channel2,&DMA1_Init); //对DMA2通道2进行初始化
               
         //DMA通道1用于SPI->RAM的数据传输
         DMA_DeInit(DMA2_Channel1);        //接收
         DMA1_Init.DMA_PeripheralBaseAddr=(u32)&SPI3->DR;
         //DMA1_Init.DMA_MemoryBaseAddr=...; //启动传输前装入实际RAM地址
         DMA1_Init.DMA_DIR=DMA_DIR_PeripheralSRC;
         DMA1_Init.DMA_BufferSize=1028;//512
         DMA1_Init.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
         DMA1_Init.DMA_MemoryInc=DMA_MemoryInc_Enable;
         DMA1_Init.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
         DMA1_Init.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
         DMA1_Init.DMA_Mode=DMA_Mode_Normal;
         DMA1_Init.DMA_Priority=DMA_Priority_High;
         DMA1_Init.DMA_M2M=DMA_M2M_Disable;
         
         DMA_Init(DMA2_Channel1,&DMA1_Init); //对DMA通道1进行初始化
         
         SPI_I2S_DMACmd(SPI3,SPI_I2S_DMAReq_Rx,ENABLE); //使能SPI的DMA接收请求
         SPI_I2S_DMACmd(SPI3,SPI_I2S_DMAReq_Tx,ENABLE); //使能SPI的DMA发送请求

         return 0;
}

unsigned char DMA1_Star_SPI_RX(u8 *buffer,u16 len)
{
                //DMA_DeInit(DMA2_Channel1);        //接收
            unsigned char temp=0xff;
            
                DMA2_Channel1->CNDTR=len; //设置传输的数据长度
                DMA2_Channel1->CMAR=(unsigned long)buffer; //设置内存缓冲区地址
               
                /*SPI作为主机进行数据接收时必须要主动产生时钟,因此此处必须有DMA通道2的配合*/
                DMA2_Channel2->CNDTR=len;
                DMA2_Channel2->CMAR=(u32)&temp; //temp=0xff
                DMA2_Channel2->CCR&=~DMA_MemoryInc_Enable; //内存地址非自增
               
                DMA_Cmd(DMA2_Channel1,ENABLE); //首先启动DMA通道1
                DMA_Cmd(DMA2_Channel2,ENABLE); //再启动DMA通道2
                while(!DMA_GetFlagStatus(DMA2_FLAG_TC1)); //等待DMA通道1接收数据完成
                DMA_ClearFlag(DMA2_FLAG_TC1);
                DMA_ClearFlag(DMA2_FLAG_TC2); //清除DMA通道1与2的传输完成标志
                DMA_Cmd(DMA2_Channel1,DISABLE);
                DMA_Cmd(DMA2_Channel2,DISABLE); //使DMA通道1与2停止工作
               
                DMA2_Channel2->CCR|=DMA_MemoryInc_Enable; //将DMA通道2恢复为内存地址自增方式
          return 0;
}

//向sd卡写入一个数据包的内容 len字节 启动DMA传输
//buf:数据缓存区
unsigned char DMA1_Star_SPI_TX(u8 *buffer,u16 len)
{
                DMA2_Channel2->CNDTR=len; //设置要传输的数据长度//DMA2_Channel2->CNDTR=512;
                DMA2_Channel2->CMAR=(u32)buffer; //设置RAM缓冲区地址
               
                DMA_Cmd(DMA2_Channel2,ENABLE); //启动DMA传输 RAM->SPI
                while(!DMA_GetFlagStatus(DMA2_FLAG_TC2)); //等待DMA通道2传输完成
                DMA_ClearFlag(DMA2_FLAG_TC2); //清除通道2传输完成状态标记
                DMA_Cmd(DMA2_Channel2,DISABLE); //使DMA通道2停止工作
          return 0;
}


最佳答案

查看完整内容[请看2#楼]

http://www.openedv.com/thread-60866-1-1.html 看我的帖子
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

347

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
2082
金钱
2082
注册时间
2014-12-19
在线时间
711 小时
发表于 2016-5-31 17:45:43 | 显示全部楼层
回复

使用道具 举报

6

主题

19

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2016-4-7
在线时间
17 小时
 楼主| 发表于 2016-6-1 10:08:17 | 显示全部楼层
lvehe 发表于 2016-5-31 19:31
http://www.openedv.com/thread-60866-1-1.html
看我的帖子

看起来没什么差异,就是不行呀,运行会卡在while(!DMA_GetFlagStatus(DMA2_FLAG_TC2));
回复

使用道具 举报

58

主题

6294

帖子

1

精华

资深版主

Rank: 8Rank: 8

积分
11553
金钱
11553
注册时间
2014-4-1
在线时间
1317 小时
发表于 2016-6-1 10:14:58 | 显示全部楼层

1、可能SPI没有工作,或者运行次数不够、不足以触发DMA的标志;
2、DMA配置错误。


回复

使用道具 举报

6

主题

19

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2016-4-7
在线时间
17 小时
 楼主| 发表于 2016-6-1 10:32:58 | 显示全部楼层
本帖最后由 midisamboy 于 2016-6-1 10:34 编辑
xuande 发表于 2016-6-1 10:14
1、可能SPI没有工作,或者运行次数不够、不足以触发DMA的标志;
2、DMA配置错误。

1.SPI是有工作的(而且运行正常),我是因为SPI数据量过大,才想用DMA(现在就是DMA不行)。
运行次数不够?没这说法吧,主要启动就可以了。
2.DMA配置没看出哪错误,来来回回,对了好多遍了。
回复

使用道具 举报

58

主题

6294

帖子

1

精华

资深版主

Rank: 8Rank: 8

积分
11553
金钱
11553
注册时间
2014-4-1
在线时间
1317 小时
发表于 2016-6-1 10:35:16 | 显示全部楼层

去查下DMA2_FLAG_TC2标志的意义。


回复

使用道具 举报

3

主题

347

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
2082
金钱
2082
注册时间
2014-12-19
在线时间
711 小时
发表于 2016-6-1 10:37:03 | 显示全部楼层
midisamboy 发表于 2016-6-1 10:08
看起来没什么差异,就是不行呀,运行会卡在while(!DMA_GetFlagStatus(DMA2_FLAG_TC2));

差异大了去了!
你好好对比你的发送函数和接收函数,发送函数没有设置通道1。
SPI无论发送还是接收,2个通道必须同时工作,发送时接收通道也必须开启,可设置接收通道为内存地址不自增的方式。
具体代码见我的帖子附件。
回复

使用道具 举报

6

主题

19

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2016-4-7
在线时间
17 小时
 楼主| 发表于 2016-6-1 10:37:10 | 显示全部楼层
本帖最后由 midisamboy 于 2016-6-1 11:02 编辑
xuande 发表于 2016-6-1 10:35
去查下DMA2_FLAG_TC2标志的意义。

我的理解就是,DMA2的通道2传输完成,也就是SPI3的传输完成。(DMA2 Channel2 transfer complete flag)
回复

使用道具 举报

6

主题

19

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2016-4-7
在线时间
17 小时
 楼主| 发表于 2016-6-1 10:38:10 | 显示全部楼层
本帖最后由 midisamboy 于 2016-6-2 17:39 编辑
lvehe 发表于 2016-6-1 10:37
差异大了去了!
你好好对比你的发送函数和接收函数,发送函数没有设置通道1。
SPI无论发送还是接收,2 ...

试了你的方法

unsigned char DMA1_Star_SPI_TX(u8 *buffer,u16 len)
{

                #if 0
                DMA2_Channel2->CNDTR=len; //设置要传输的数据长度//DMA2_Channel2->CNDTR=512;
                DMA2_Channel2->CMAR=(u32)buffer; //设置RAM缓冲区地址
               
                DMA_Cmd(DMA2_Channel2,ENABLE); //启动DMA传输 RAM->SPI
                while(!DMA_GetFlagStatus(DMA2_FLAG_TC2)); //等待DMA通道2传输完成
                DMA_ClearFlag(DMA2_FLAG_TC2); //清除通道2传输完成状态标记
                DMA_Cmd(DMA2_Channel2,DISABLE); //使DMA通道2停止工作
          return 0;
                  #else
                  unsigned char temp=0xff;
                  
                  DMA2_Channel1->CNDTR=len; //设置传输的数据长度
                  DMA2_Channel1->CMAR=(unsigned long)&temp; //设置内存缓冲区地址
                  
                  /*SPI作为主机进行数据接收时必须要主动产生时钟,因此此处必须有DMA通道2的配合*/
                  DMA2_Channel2->CNDTR=len;
                  DMA2_Channel2->CMAR=(u32)buffer; //temp=0xff
                  DMA2_Channel1->CCR&=~DMA_MemoryInc_Enable; //内存地址非自增
                  
                  DMA_Cmd(DMA2_Channel1,ENABLE); //首先启动DMA通道1
                  DMA_Cmd(DMA2_Channel2,ENABLE); //再启动DMA通道2
                  while(!DMA_GetFlagStatus(DMA2_FLAG_TC1)); //等待DMA通道1接收数据完成(停在这里)
                  DMA_ClearFlag(DMA2_FLAG_TC1);
                  DMA_ClearFlag(DMA2_FLAG_TC2); //清除DMA通道1与2的传输完成标志
                  DMA_Cmd(DMA2_Channel1,DISABLE);
                  DMA_Cmd(DMA2_Channel2,DISABLE); //使DMA通道1与2停止工作
                  
                  DMA2_Channel1->CCR|=DMA_MemoryInc_Enable; //将DMA通道2恢复为内存地址自增方式
                return 0;


                #endif
}
发送函数放在

        SPI_FLASH_CS_LOW();
        Delay_ARMJISHU(20);
        #if 0
        for(i=0;i<bufferLength;i++)
                {
                //temp=buffer;//test
                test_temp=SPI_FLASH_SendByte(buffer);
                }
        //(不带DMA,这里发送是正常的)
        #else

        DMA1_Star_SPI_TX(buffer,bufferLength);

        #endif
        Delay_ARMJISHU(20);
        SPI_FLASH_CS_HIGH();

回复

使用道具 举报

6

主题

19

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2016-4-7
在线时间
17 小时
 楼主| 发表于 2016-6-1 17:17:04 | 显示全部楼层
有没帮忙看看的 ?谢谢
回复

使用道具 举报

6

主题

19

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2016-4-7
在线时间
17 小时
 楼主| 发表于 2016-6-2 16:50:19 | 显示全部楼层
有没帮忙看看的 ?谢谢
回复

使用道具 举报

0

主题

183

帖子

0

精华

高级会员

Rank: 4

积分
684
金钱
684
注册时间
2016-1-27
在线时间
184 小时
发表于 2016-6-2 17:13:55 | 显示全部楼层
midisamboy 发表于 2016-6-2 16:50
有没帮忙看看的 ?谢谢

你的传输完成中断开了吗?
回复

使用道具 举报

6

主题

19

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2016-4-7
在线时间
17 小时
 楼主| 发表于 2016-6-2 17:38:45 | 显示全部楼层
不吃鱼的老鼠 发表于 2016-6-2 17:13
你的传输完成中断开了吗?

加了
         DMA_ITConfig(DMA2_Channel1, DMA_IT_TC, ENABLE);
         DMA_ITConfig(DMA2_Channel2, DMA_IT_TC, ENABLE);
还是不行
回复

使用道具 举报

0

主题

183

帖子

0

精华

高级会员

Rank: 4

积分
684
金钱
684
注册时间
2016-1-27
在线时间
184 小时
发表于 2016-6-3 08:36:54 | 显示全部楼层
midisamboy 发表于 2016-6-2 17:38
加了
         DMA_ITConfig(DMA2_Channel1, DMA_IT_TC, ENABLE);
         DMA_ITConfig(DMA2_Channel2, DMA_IT_TC, ...

确定有数据在传输吗?
数据量达到设定值了吗?
回复

使用道具 举报

6

主题

19

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2016-4-7
在线时间
17 小时
 楼主| 发表于 2016-6-3 09:48:13 | 显示全部楼层
不吃鱼的老鼠 发表于 2016-6-3 08:36
确定有数据在传输吗?
数据量达到设定值了吗?

谢谢,现在可以了,但是挺奇怪的,不开DMA,SPI_BaudRatePrescaler可以为SPI_BaudRatePrescaler_2,开了DMA,SPI_BaudRatePrescaler_64才正常。
回复

使用道具 举报

5

主题

158

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
200
金钱
200
注册时间
2016-5-29
在线时间
5 小时
发表于 2016-6-4 16:11:01 | 显示全部楼层
路过帮顶
回复

使用道具 举报

16

主题

85

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2013-12-18
在线时间
64 小时
发表于 2016-6-4 17:14:14 | 显示全部楼层
路过帮顶
回复

使用道具 举报

18

主题

103

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
354
金钱
354
注册时间
2016-8-2
在线时间
79 小时
发表于 2016-9-1 18:44:45 | 显示全部楼层
midisamboy 发表于 2016-6-3 09:48
谢谢,现在可以了,但是挺奇怪的,不开DMA,SPI_BaudRatePrescaler可以为SPI_BaudRatePrescaler_2,开了D ...

楼主,你的软件现在如何了,可以正常工作了么,速度需要设置那么低才能够正常工作么
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2015-3-17
在线时间
5 小时
发表于 2017-3-29 15:06:30 | 显示全部楼层
midisamboy 发表于 2016-6-3 09:48
谢谢,现在可以了,但是挺奇怪的,不开DMA,SPI_BaudRatePrescaler可以为SPI_BaudRatePrescaler_2,开了D ...

楼主,现在我遇到了和你同样的问题,不知道你现在解决的怎么样了,我也尝试降低SPI时钟频率,但是那样的话读写速度肯定降低了许多,不知道你现在有没有更好的方法或者已经做过什么优化;我分析可能未DMA2 的发送配置问题,但是配置和你写的基本一致,很茫然呢,期待你的回复!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-18 17:41

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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