OpenEdv-开源电子网

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

SPI2使用DMA方式,效率未有明显改善

[复制链接]

1

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2014-12-27
在线时间
8 小时
发表于 2015-10-15 16:45:41 | 显示全部楼层 |阅读模式
5金钱
CPU:stm32F103vct6
现象:spi2操作enc28j60芯片。使用普通方式操作、使用DMA方式操作均正常。但通过发送数据包测试(每包
        1000个字节,500包),发现两种方式所用的总时间完全一样。理论上DMA方式所用的时间应该短一些才
        对,有谁遇到过类似的现象吗?

最佳答案

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

LZ的情况,大概相当于这样: 机枪一次打1000发子弹, 但每次打完之后,要重新装弹,甚至要重新造子弹。 所以,要缩短造弹、装弹的时间。 方法是双缓冲,或者多缓冲。 但如果必须现造,那就只能这么快了。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

58

主题

6294

帖子

1

精华

资深版主

Rank: 8Rank: 8

积分
11553
金钱
11553
注册时间
2014-4-1
在线时间
1317 小时
发表于 2015-10-15 16:45:42 | 显示全部楼层
LZ的情况,大概相当于这样:

机枪一次打1000发子弹,
但每次打完之后,要重新装弹,甚至要重新造子弹。

所以,要缩短造弹、装弹的时间。

方法是双缓冲,或者多缓冲。

但如果必须现造,那就只能这么快了。
回复

使用道具 举报

58

主题

6294

帖子

1

精华

资深版主

Rank: 8Rank: 8

积分
11553
金钱
11553
注册时间
2014-4-1
在线时间
1317 小时
发表于 2015-10-15 17:19:30 | 显示全部楼层
DMA是需要触发的,
触发慢,自然就慢。
回复

使用道具 举报

1

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2014-12-27
在线时间
8 小时
 楼主| 发表于 2015-10-16 09:06:22 | 显示全部楼层
“触发慢,自然就慢”这句没太明白。
(1)DMA功能平时是关闭的,只有在使用时才启用。
(2)在使用时传入实际的数据缓存、长度,开启DMA(此时就是马上触发了,不知道触发快慢是如
       何控制的),等待操作完毕后,再关闭DMA功能。

我把相关代码贴出来,麻烦大家帮看看。可以正常使用,就是速度无任何改善。

宏定义:
[mw_shl_code=c,true]#ifdef SPI2_DMA #define SPI_MASTER_DMA DMA1 #define SPI_MASTER_DMA_CLK RCC_AHBPeriph_DMA1 #define SPI_MASTER_Rx_DMA_Channel DMA1_Channel4 #define SPI_MASTER_Rx_DMA_FLAG DMA1_FLAG_TC4 #define SPI_MASTER_Tx_DMA_Channel DMA1_Channel5 #define SPI_MASTER_Tx_DMA_FLAG DMA1_FLAG_TC5 #endif //SPI2_DMA [/mw_shl_code]
DMA基本配置:
[mw_shl_code=c,true]#ifdef SPI2_DMA /* SPI_MASTER_Rx_DMA_Channel configuration ------------------------*/ DMA_DeInit(SPI_MASTER_Rx_DMA_Channel); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)uip_buf; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 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_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(SPI_MASTER_Rx_DMA_Channel, &DMA_InitStructure); /* SPI_MASTER_Tx_DMA_Channel configuration -------------------------------*/ DMA_DeInit(SPI_MASTER_Tx_DMA_Channel); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)uip_buf;[/mw_shl_code] [mw_shl_code=c,true]
[mw_shl_code=c,true] DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;[/mw_shl_code]
[/mw_shl_code] [mw_shl_code=c,true] 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_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(SPI_MASTER_Tx_DMA_Channel, &DMA_InitStructure); #endif //SPI2_DMA[/mw_shl_code]

写缓存:

[mw_shl_code=c,true]void enc28j60WriteBuffer(unsigned int len, unsigned char* data) { CS28J60_Low(); // issue write command SPI2_ReadWrite(ENC28J60_WRITE_BUF_MEM); #ifndef SPI2_DMA while(len) { len--; SPI2_ReadWrite(*data); data++; } CS28J60_High(); #else ((DMA_Channel_TypeDef *)SPI_MASTER_Tx_DMA_Channel)->CMAR = (uint32_t)data; ((DMA_Channel_TypeDef *)SPI_MASTER_Tx_DMA_Channel)->CNDTR = (uint32_t)len; DMA_Cmd(SPI_MASTER_Tx_DMA_Channel, ENABLE); SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);//TX DMA request, start move data while(!DMA_GetFlagStatus(SPI_MASTER_Tx_DMA_FLAG)); DMA_ClearFlag(SPI_MASTER_Tx_DMA_FLAG); CS28J60_High(); DMA_Cmd(SPI_MASTER_Tx_DMA_Channel, DISABLE); #endif //SPI2_DMA } [/mw_shl_code]

读缓存:
[mw_shl_code=c,true]void enc28j60ReadBuffer(unsigned int len, unsigned char* data) { uint32_t mccr; CS28J60_Low(); // issue read command SPI2_ReadWrite(ENC28J60_READ_BUF_MEM); #ifndef SPI2_DMA while(len) { len--; // read data *data = (unsigned char)SPI2_ReadWrite(0); data++; } *data='\0'; CS28J60_High(); #else ((DMA_Channel_TypeDef *)SPI_MASTER_Rx_DMA_Channel)->CMAR = (uint32_t)data; ((DMA_Channel_TypeDef *)SPI_MASTER_Rx_DMA_Channel)->CNDTR = (uint32_t)len; DMA_Cmd(SPI_MASTER_Rx_DMA_Channel, ENABLE); SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);//RX DMA request, start move data /* Dummy TX to generate SPI clock for RX*/ mccr = ((DMA_Channel_TypeDef *)SPI_MASTER_Tx_DMA_Channel)->CCR; //Save DMA channel 3 configuration register ((DMA_Channel_TypeDef *)SPI_MASTER_Tx_DMA_Channel)->CCR = (mccr & 0xffffff31); // Peripheral & memory doesn't auto increment. Interrupt disable ((DMA_Channel_TypeDef *)SPI_MASTER_Tx_DMA_Channel)->CMAR = (uint32_t)data; ((DMA_Channel_TypeDef *)SPI_MASTER_Tx_DMA_Channel)->CNDTR = (uint32_t)len; DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, DISABLE);//Diable Interrupt DMA_Cmd(SPI_MASTER_Tx_DMA_Channel, ENABLE); SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);//TX DMA request, start move data while(!DMA_GetFlagStatus(SPI_MASTER_Rx_DMA_FLAG)); while(!DMA_GetFlagStatus(SPI_MASTER_Tx_DMA_FLAG)); DMA_ClearFlag(SPI_MASTER_Rx_DMA_FLAG); DMA_ClearFlag(SPI_MASTER_Tx_DMA_FLAG); // data++; // *data='\0'; CS28J60_High(); DMA_Cmd(SPI_MASTER_Rx_DMA_Channel, DISABLE); /* Restore Tx setting */ DMA_Cmd(SPI_MASTER_Tx_DMA_Channel, DISABLE); ((DMA_Channel_TypeDef *)SPI_MASTER_Tx_DMA_Channel)->CCR = mccr; DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE); #endif } [/mw_shl_code]



 


回复

使用道具 举报

11

主题

1044

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3722
金钱
3722
注册时间
2011-5-23
在线时间
2013 小时
发表于 2015-10-16 10:10:24 | 显示全部楼层
DMA并不能加快速度,SPI时钟有多快,SPI就只有多快。
但时钟太高时,DMA能比CPU轮询缩短一点传输间隔。也就几个百分点。

但DMA可以释放CPU,比如SPI1 SPI2分别连接两片SPI FLASH,CPU读取SPI1有4.8MB/s,读完SPI1再读SPI2还是4.8M/s。
但如果用DMA,则可以达到5.0MB/s,如果你还有SPI2要读,那就是5*2=10MB/s

而且,SPI传输期间,CPU还可以去干别的活。
RT-Thread RTOS 音频,WIFI,蓝牙
回复

使用道具 举报

22

主题

751

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1605
金钱
1605
注册时间
2015-6-10
在线时间
222 小时
发表于 2015-10-16 11:11:02 | 显示全部楼层
DMA只是省cpu资源
回复

使用道具 举报

1

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2014-12-27
在线时间
8 小时
 楼主| 发表于 2015-10-16 11:43:21 | 显示全部楼层
有点乱。按你们的说法,使用DMA后速度不一定有明显提升, 但网上有许多使用SPI的DMA后,速度快了很多(1楼就是),又是为什么呢。

另:用过串口的DMA,比普通方式确实节省了将近2/3的时间。
回复

使用道具 举报

233

主题

961

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1815
金钱
1815
注册时间
2011-10-9
在线时间
230 小时
发表于 2015-10-16 11:49:17 | 显示全部楼层
DMA 我理解 优势不在于提升速度 当然 也会有部分提升,
优势在于 可以传输的时候 你去干点其他事
回复

使用道具 举报

58

主题

6294

帖子

1

精华

资深版主

Rank: 8Rank: 8

积分
11553
金钱
11553
注册时间
2014-4-1
在线时间
1317 小时
发表于 2015-10-16 12:48:02 | 显示全部楼层
如果每次DMA只传输一个点,速度提高确实有限;

但它可以一次传输65536点,速度提高就不是一点了;
如果用软件这么做,要多久?

何况,还可以空出CPU来,做别的事。
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-18 23:32

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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