OpenEdv-开源电子网

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

DMA及中断对SD卡读写

[复制链接]

3

主题

18

帖子

0

精华

限制会员

积分
-106
金钱
-106
注册时间
2012-3-31
在线时间
0 小时
发表于 2012-4-30 23:04:33 | 显示全部楼层 |阅读模式


原发及代码下载 http://sites.google.com/site/btvnlue/stm32/dmasd

本文对STM32的SPI3读写SD卡进行讨论,读写使用直接模式,DMA模式,和DMA中断模式,并尝试对各种模式进行比较

一般来讲,使用DMA模式的优点在于,节省主程序资源,在直接对CPU/MCU编程的环境中,DMA模式类似于线程的效果。尤其在对实时处理比较严格的环境,如视频播放或采集,DMA会发挥重要作用,主程序更着眼于进行资源分配和流程控制。

  • SPI初始化DMA和中断
使用SPI的DMA功能,需要首先对相关寄存器初始化
SPI3使用DMA2的Channel1接收数据,Channel2发送数据,(参照STM32参考手册)

rcc->ahbenr |= 0x02; //enable dma2
spi3->cr2 = 0x3; // enable spi3 dma

使用DMA的中断功能,需要对NVIC和系统向量表vtor初始化
这里只使用SPI3接受中断,DMA2的Channel1,IRQ56

nvic->iser.at[1] = 0x01000000; //enable IRQ56
scb->vtor = (unsigned int)(&__Vectors) & 0x3FFFFF80;

  • SPI的直接读写模式
直接读写模式的特点就是结构简单,易于调试,但数据传输效率相对较低,并且完全占用主程序资源
SPI操作MOSI写数据的同时采样MISO,所以读写操作是同一个函数

unsigned char sd_bytedata(unsigned char cmd) {
   unsigned char output;

   while (((spi3->sr)&0x2)==0)   {} //TXE empty
   spi3->dr = cmd;
   while (((spi3->sr)&0x1)==0) {} //RXNE empty
   output = (unsigned char)(spi3->dr);

   return output;
}

  • SPI的DMA模式
DMA模式的优点在于,释放主程序资源,并且读取效率高,但相对设定复杂,调试困难
基于DMA的参数特性,可以将SPI的读写操作分开处理,以节省资源

DMA接受,读操作,接收缓存的内存指针自动增移,发送缓存为固定,数据长度相同

   dma2->ch1.ccr = 0x0080; //MINC:yes P->M
   dma2->ch1.cndtr = cnt;
   dma2->ch1.cpar = (unsigned int)&(spi3->dr);
   dma2->ch1.cmar = (unsigned int)rtn;

   dma2->ch2.ccr = 0x0010; //MINC:no M->
   dma2->ch2.cndtr = cnt;
   dma2->ch2.cpar = (unsigned int)&(spi3->dr);
   dma2->ch2.cmar = (unsigned int)cmd;

DMA发送,写操作,发送缓存的内存指针自动增移,接收缓存为固定,数据长度相同

   dma2->ch1.ccr = 0x0000; //MINC:no P->M
   dma2->ch1.cndtr = cnt;
   dma2->ch1.cpar = (unsigned int)&(spi3->dr);
   dma2->ch1.cmar = (unsigned int)rtn;

   dma2->ch2.ccr |= 0x0090; //MINC:yes M->
   dma2->ch2.cndtr = cnt;
   dma2->ch2.cpar = (unsigned int)&(spi3->dr);
   dma2->ch2.cmar = (unsigned int)cmd;

主程序通过监视DMA的EVENT事件标志进行流程控制

   while ((dma2->isr & 0x20) == 0); //check finish event
   while ((dma2->isr & 0x02) == 0); //check finish event

停止DMA,清除事件控制器,消除对下次操作影响

   dma2->ifcr = 0xFF; //clear event

  • SPI的DMA中断模式

中断模式可以在中断函数中加入流程控制逻辑,更多节省主程序资源,对于像SD卡操作逻辑,在没有SDIO专用控制器帮助的情况下,DMA中断模式似乎是必须的选择。但程序难度增加,调试更加困难,尤其在纠错处理方面,需要更大的精力投入。

中断函数由于没有参数,犹如数据缓冲,及控制变量最好设置成全局变量
使用中断函数不再监视事件寄存器,流程控制可以使用用户变量,定义各个状态变量

unsigned int dma_inv_state;

#define SD_DMA_DAT_ONCE 0x1
#define SD_DMA_RESPONSE 0x2
#define SD_DMA_DATATOKEN 0x4
#define SD_DMA_READDATA 0x10
#define SD_DMA_WRITEDATA 0x20
#define SD_DMA_COMPLETE 0x100

DMA读写操作前对中断标志设置

   if (dma_inv_state) {
      dma2->ch1.ccr |= 0x2; // interrupt setup
   }

中断处理程序首先等待发送结束,然后清除事件,否则中断会不断被触发
然后可以进行用户的流程操作

   while ((dma2->isr & 0x20) == 0); //check finish event channel2

   sd_stop_dma();

   if (dma_inv_state & SD_DMA_RESPONSE) {

   } else if (dma_inv_state & SD_DMA_DATATOKEN) {

   } else if (dma_inv_state & SD_DMA_READDATA) {

   } else if (dma_inv_state & SD_DMA_COMPLETE) {

   }

主程序中对状态变量进行监控

   while (dma_inv_state & SD_DMA_DAT_ONCE);

  • 主程序功能

本程序实现DMA对双缓冲的读入,读入SD卡中的所有页,主程序对缓存页执行CRC校对

   while ((ii<sd_inf->page)||(cc+ee<ii)) {
         if (buf_free) {
               rtn = sd_read_pagedata_dma_inv_sss(addr, dbf, 514);
               ii++;
         }
      }
      if (buf_done) {
         if (buf_done&0x1) {
            dbf = common_buf1;
         } else {
            dbf = common_buf2;
         }
         jj = crc16(dbf, 512);
         if (((jj>>8)==dbf[512])&&((jj&0xFF)==dbf[513])) {
         }
         buf_free |= (buf_done&0x1)?0x1:0x2;
         buf_done &= (buf_done&0x1)?(~0x1)~0x2);
      }
      if (buf_proc) {
         if (dma_inv_state == 0x0) {
            buf_done = buf_proc;
            buf_proc = 0x0;
         }
      }
   }

http://sites.google.com/site/btvnlue/stm32
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165371
金钱
165371
注册时间
2010-12-1
在线时间
2110 小时
发表于 2012-5-1 01:50:07 | 显示全部楼层
有没有具体的数据对比?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

3

主题

18

帖子

0

精华

限制会员

积分
-106
金钱
-106
注册时间
2012-3-31
在线时间
0 小时
 楼主| 发表于 2012-5-1 09:24:42 | 显示全部楼层
不好意思,没有做实际时测
实际上,对SD卡的读写速度取决于卡本身的速度,各种方式的差异并不是很大,
这里DMA和中断试验的目的是让主程序有时间执行用户逻辑,比如例程中,CRC计算的所有时间都可以在DMA方式下节省下来
CRC的执行时间取决于算法和MCU的主频速度
卡数据的读写和CRC计算的长者决定了缓冲的填充周期


http://sites.google.com/site/btvnlue/stm32
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165371
金钱
165371
注册时间
2010-12-1
在线时间
2110 小时
发表于 2012-5-1 10:07:33 | 显示全部楼层
回复【3楼】btvnlue:
---------------------------------
CRC是一个可选项目,不是必须的项目.在SD卡读写的时候,可以不经过CRC计算的.只需要初始化的时候关闭即可.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

3

主题

18

帖子

0

精华

限制会员

积分
-106
金钱
-106
注册时间
2012-3-31
在线时间
0 小时
 楼主| 发表于 2012-5-1 20:37:35 | 显示全部楼层
回复【4楼】正点原子:
---------------------------------
这里也不是必须的,只是给主程序找点事做而已
例程没有太多实际的意义,以后会增添一些实用的功能
http://sites.google.com/site/btvnlue/stm32
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-2-25 19:35

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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