原创 智林STM32开发板上的FatFS移植过程分析(九)

2010-3-21 19:52 3801 4 4 分类: MCU/ 嵌入式

 


<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 


九、添加新的命令fwrite


1、继续调试程序


在昨天调试的基础上,为了解决问题,今天进行了单步调试,发现读多块指令发出后,会受到一个返回值00,然后就都是0xFF字节。


在路上骑自行车的时候,突然想到,diskread()函数是调用SD_ReadMultiBlock,但是在读的块数为1的时候,可以去调用SD读单块的函数啊,于是在读多块的函数里,加了这句  if ( BlockNum == 1 ) return SD_ReadBlock (  BlockIndex, ReadBuf );


调试结果出来,还是错误,读单块函数也读到一个00,说明不是函数的问题。


绞尽脑汁,在阅读move_window()函数源代码的时候,突然想到:其它时候调用move_window()的时候,只有读扇区的操作。而由f_write()函数调用的时候,由于文件系统结构体里的扇区为“脏的”,故先进行了写入操作,这个00可能是表示SD卡正在忙的意思,拒绝了刚才读块的指令。这里解决方法有两个:一个是写函数的后续处理,多发几个0xFF给它,让它忙完;再一个就是读块的命令持续发,直到它正确响应这个命令为止。


在修改的时候发现了:


void SD_WaitInBusy( void ){


   u8 TmpByte; 可能是它没有初始化带来的问题,改为TmpByte =0


   while ( TmpByte==0x0 )TmpByte = SPI_GetByte( );


   SPI_PutByte( 0xFF );


}


重新编译、下载程序,写文件马上成功了,所以变量正确初始化问题对程序是一个很重要的问题,以后一定要记住这个教训。因为这个时候编译不会有问题,实际执行可能就会出现千奇百怪的问题。


 


2、跟踪执行f_write()的执行流程


    在命令窗口输入fwrite aaa.txt由于目录下已经存在该文件,所以会更新。


先以写和总是创建的模式打开文件,先执行res = follow_path(&dj, path),找到了该文件,会更新目录信息结构体的一些关键信息:当前扇区sect=0x7B8,这是根目录的首扇区,目录索引index=3aaa.txt是第三个目录项。Dir指向文件系统缓冲扇区的目录项。所指向的文件系统缓冲了目录扇区。Fs.winsect等于绝对扇区号


接下来:


cl = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | (dir+DIR_FstClusLO);   /*获得文件所占用的簇号 */


       ST_WORD(dir+DIR_FstClusHI, 0);     /* 修改目录项的信息 */


       ST_WORD(dir+DIR_FstClusLO, 0);  /因为dir指向


       ST_DWORD(dir+DIR_FileSize, 0);      /* 文件大小设为0 */


       dj.fs->wflag = 1;  当前缓冲对象为根目录扇区,已经修改。缓冲扇区更改的时候,这个修改过的扇区将写回磁盘


       ps = dj.fs->winsect;                 /* 以下是删除原文件所占的簇链 */


              if (cl) {


                     res = remove_chain(dj.fs, cl); 删除簇链的时候,缓冲扇区变化,此时缓冲的实际上是FAT表的首扇区。


                     dj.fs->last_clust = cl - 1;  /* 文件系统的最后使用簇链更新,这个最新释放的簇可以用于下次分配。       }


res = move_window(dj.fs, ps);这句话实际上又更新了FAT,簇链的更新有效了。而文件系统缓冲扇区重新回到所在目录的扇区


       fp->dir_sect = dj.fs->winsect;        /* 文件目录所在扇区号*/


       fp->dir_ptr = dj.dir;  目录项在缓冲扇区内的地址。


       fp->flag = mode;                                /* File access mode */


       fp->org_clust =                   


       fp->fsize = LD_DWORD(dir+DIR_FileSize);      /* File size */


       fp->fptr = 0; fp->csect = 255;          /* 在簇内的相对扇区号 */


       fp->dsect = 0; 文件数据缓冲区对应的簇号。


以上为更新的文件信息结构体。


 


3、继续跟踪执行f_write()的执行流程


       CharWrite = Uart_GetChar();


       if ( CharWrite == 0x1B )  break;


       Uart_PutChar(CharWrite);


       for ( i="0" ; i<512 ; i++ ) WriteFileBuf = CharWrite; 将读入的字符写入缓冲区,写满一个扇区。


       res=f_write(&WriteFileInf,(void *)WriteFileBuf,512,&ByteWrite); //要进去看一看,在第二次这样做的时候,更新的信息如下:


文件的大小和指针都是512,文件相对扇区为1.


                     sect = clust2sect(fp->fs, fp->curr_clust);    /* Get current sector */


                     sect += fp->csect; 这样可以计算出当前绝对扇区号。


                     cc = btw / SS(fp->fs);   要写一个扇区


                     if (cc) {        


                            if (disk_write(fp->fs->drive, wbuff, sect, (BYTE)cc) != RES_OK) 这句话将当前缓冲区的内容写入当前扇区。


当写的内容超过8个扇区后,要重新分配新的簇,其过程如下:


              if ((fp->fptr % SS(fp->fs)) == 0) {                    /* On the sector boundary? */


                     if (fp->csect >= fp->fs->csize) {         /* On the cluster boundary? */


                            clst = create_chain(fp->fs, fp->curr_clust);跟踪进去看一看。


                            fp->curr_clust = clst;                        /* Update current cluster */


                            fp->csect = 0;        执行后分配到19号簇,当前簇指向它,相对扇区号清零,因为在新的簇开始写数据。


刚刚这个文件写了9个扇区的数据,超过了一个簇,再读一读看看,的确是刚刚写入的数据。可以说,写文件命令成功完成。


 


4、改变模式,以写和创建新文件的模式写文件


 


 


 


 


 

文章评论0条评论)

登录后参与讨论
我要评论
0
4
关闭 站长推荐上一条 /2 下一条