野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 9081|回复: 3

关于SD卡的Fatfs的问题

[复制链接]
发表于 2018-4-10 18:59:38 | 显示全部楼层 |阅读模式
大家好,有段代码我想了很久不知怎么也想不出来,求解答!!谢谢!!谢谢!!是SD卡FAtfs系统测试的代码,在diskio.c文件中的一个函数:
DRESULT disk_read (
        BYTE pdrv,                /* 设备物理编号(0..) */
        BYTE *buff,                /* 数据缓存区 */
        DWORD sector,        /* 扇区首地址 */
        UINT count                /* 扇区个数(1..128) */
)
{
        DRESULT status = RES_PARERR;
        SD_Error SD_state = SD_OK;
       
        switch (pdrv) {
                case ATA:        /* SD CARD */                                               
                  if((DWORD)buff&3)                     //这个是判断是否4字节对齐的吧?我不懂为什么 ”与3”  的原因
                        {
                                DRESULT res = RES_OK;
                                DWORD scratch[SD_BLOCKSIZE / 4];

                                while (count--)
                                {
                                        res = disk_read(ATA,(void *)scratch, sector++, 1);  //这个又调用了自身函数,应该怎么解释其用法?这语句不是重新执行disk_read                                                                                                                         函数吗?不是又要进行if((DWORD)buff&3)  语句判断了吗?这样                                                                                                                                          一直调用自身,下面的memcpy(buff, scratch, SD_BLOCKSIZE);语句不就一直得                                                                                                                      不到执行了吗?

                                        if (res != RES_OK)
                                        {
                                                break;
                                        }
                                        memcpy(buff, scratch, SD_BLOCKSIZE);
                                        buff += SD_BLOCKSIZE;
                    }
                    return res;
                        }
                       
                        SD_state=SD_ReadMultiBlocks(buff,(uint64_t)sector*SD_BLOCKSIZE,SD_BLOCKSIZE,count);
                  if(SD_state==SD_OK)
                        {
                                /* Check if the Transfer is finished */
                                SD_state=SD_WaitReadOperation();
                                while(SD_GetStatus() != SD_TRANSFER_OK);
                        }
                        if(SD_state!=SD_OK)
                                status = RES_PARERR;
                  else
                          status = RES_OK;       
                        break;   
                       
                case SPI_FLASH:
                break;

                default:
                        status = RES_PARERR;
        }
        return status;
}


书本解析说:对于 SD 卡,最重要是使用 SD_ReadMultiBlocks 函数读取多块数据到存储区。这里需要注意的地方是 SD 卡数据操作是使用 DMA 传输的,并设置数据尺寸为 32 位大小,为实现数据正确传输,要求存储区是 4 字节对齐。在某些情况下, FatFs 提供的 buff 地址不是 4 字节对齐,这会导致 DMA 数据传输失败,所以为保证数据传输正确,可以先判断存储区地址是否是 4 字节对齐,如果存储区地址已经是 4 字节对齐,无需其他处理,直接使用SD_ReadMultiBlocks 函数执行多块读取即可。如果判断得到地址不是 4 字节对齐,则先申请一个 4 字节对齐的临时缓冲区,即局部数组变量 scratch,通过定义为 DWORD 类型可以使得其自动 4 字节对齐, scratch 所占的总存储空间也是一个块大小,这样把一个块数据读取到 scratch 内,然后把 scratch 存储器内容拷贝到 buff 地址空间上就可以了。


但我看不懂为什么  if((DWORD)buff&3) 这条语句是判断地址4字节对齐呢?而且,为什么下面又调用自身  disk_read(ATA,(void *)scratch, sector++, 1); ?





回复

使用道具 举报

发表于 2018-4-11 09:07:30 | 显示全部楼层
通常这种是直接代几个数进去算算,代入算算就知道了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-4-11 20:52:33 | 显示全部楼层
随风 发表于 2018-4-11 09:07
通常这种是直接代几个数进去算算,代入算算就知道了

我就是不懂啊,您能解析下吗?谢谢
回复 支持 反对

使用道具 举报

发表于 2018-4-12 21:34:38 | 显示全部楼层
if((DWORD)buff&3)
如果地址不是四字节对齐的那么buff的最低两位可能是是01,10,11可能是,而如果是四字节对齐的,那么最低两位只能是00,
所以根据buff&3取得最低两位的值,如果不为0,那么就说明地址不是四字节对齐的,所以申请一个临时的空间用来存放从
SD卡读取的数据DWORD scratch[SD_BLOCKSIZE / 4]总的字节数是一个sector大小。如果我们要读取的sector数量为count,
那么通过在循环while (count--) 里面每次读取一个sector的数据存放到临时数组scratch里面,然后通过memcpy(buff, scratch, SD_BLOCKSIZE);
把scratch的数组依次存放到已buff为起始地址的连续空间里面就可以了。
while (count--)
{
          res = disk_read(ATA,(void *)scratch, sector++, 1);   这一句可以拆分为:res = disk_read(ATA,(void *)scratch, sector, 1);sector++;
         这样更好理解一些,也就是调用自身读取一个sector的数据,那么怎么理解调用的自身呢?,其实只要把本次调用的部分替换到这里就饿好理解了。
          if (res != RES_OK)
          {
                 break;
           }
          memcpy(buff, scratch, SD_BLOCKSIZE);
          buff += SD_BLOCKSIZE;              每次存放完SD_BLOCKSIZE个字节之后就更新下次存放的地址
}


替换一下递归部分


if((DWORD)buff&3)
{
    while (count--)
    {
                由于递归的时候buff&3==0,所以只会执行if((DWORD)buff&3)之后的程序,并不会再次嵌套,所以直接将那一部分替换过来


               SD_state=SD_ReadMultiBlocks(buff,(uint64_t)sector*SD_BLOCKSIZE,SD_BLOCKSIZE,count);
               if(SD_state!=SD_OK)
                   status = RES_PARERR;
               else
                    status = RES_OK;        
                break;



              以上替换掉res = disk_read(ATA,(void *)scratch, sector, 1);
            剩下:
              sector++;


           这时的res=status
              if (res != RES_OK)
              {
                    break;
              }
              memcpy(buff, scratch, SD_BLOCKSIZE);                                  将数组从缓冲区复制出来
              buff += SD_BLOCKSIZE;    }

如果buff&3!=0,那么程序最终会执行到这里就返回了,而上面嵌套调用的时候则只会执行下面深绿色的部分
    return res;
}

如果buff&3==0,那么程序只会执行一次下面深绿色的程序就结束了。
  SD_state=SD_ReadMultiBlocks(buff,(uint64_t)sector*SD_BLOCKSIZE,SD_BLOCKSIZE,count);
    if(SD_state!=SD_OK)
           status = RES_PARERR;
    else
            status = RES_OK;        
    break;




回复 支持 反对

使用道具 举报

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

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-4-26 06:41 , Processed in 0.036924 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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