新手上路
- 积分
- 25
- 金钱
- 25
- 注册时间
- 2020-1-19
- 在线时间
- 11 小时
|

楼主 |
发表于 2020-3-22 02:33:51
|
显示全部楼层
关于这个问题,可以结贴了:
写到63扇区的原因:
格式化时没选FM_SFD选项。新的FatFs,其格式化函数定义为FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len);其opt参数的fmt字段,其注释为/* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */因此,该选项不仅要选择FM_FAT,还要或上一个FM_SFD,即:FM_FAT | FM_SFD.
普通磁盘,由于其0扇区为MBR或GPT引导扇区,因此,其FAT文件系统数据不能写到0扇区,FatFs默认是写到63扇区(如果使能了FF_MULTI_PARTITION,会根据引导扇区内的分区表来确定其位置)。
SFD超级软盘,由于只有一个分区,因此,其FAT文件系统数据可以直接写到0扇区。
从0扇区读取数据验证的原因:
SFD超级软盘,其0扇区即为FAT文件系统数据。
普通磁盘,0扇区保存了MBR或GPT的分区表,因此,为了找到目标卷,必须从0扇区读出分区表,然后根据分区表找到目标分区(卷)所在的扇区,进而读取到FAT文件系统数据。而MBR引导扇区,其末尾2字节也是55AA(GPT引导扇区不确定,但是为了兼容,应该也是一样的,只不过其引导程序不保存在首扇区而已),因此挂载卷的时候,会首先验证引导扇区是否有效(即末尾是否55AA),无效,则返回3,即:if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3;
而我之前在SPI Flash已有出厂数据和文件系统的时候,验证首扇区末尾55AA失败。其原因还是底层IO驱动有问题。SPI的读函数,我给增加了一个ReadWriteBytes的函数,即一次读写多个数据(为了减少函数调用开销)。问题就出在该函数上。
其代码如下:
- byte SPIDriver_ReadWriteBytes(SPI_TypeDef* spi, byte* Data, ushort Count, bool WriteOrRead) {
- byte rt = 0;
- if (WriteOrRead)
- for (ushort i = 0; i < Count; ++i) {
- while ((spi->SR & SPI_I2S_FLAG_TXE) == RESET && rt++ < SPI_Driver_RetryTimes);
- if ((spi->SR & SPI_I2S_FLAG_TXE) == RESET)
- return 0xFF;
- spi->DR = Data[i];
- while ((spi->SR & SPI_I2S_FLAG_RXNE) == RESET && rt++ < SPI_Driver_RetryTimes);
- if ((spi->SR & SPI_I2S_FLAG_RXNE) == RESET)
- return 0xFF;
- rt = spi->DR;
- }
- else for (ushort i = 0; i < Count; ++i) {
- while ((spi->SR & SPI_I2S_FLAG_TXE) == RESET && rt++ < SPI_Driver_RetryTimes);
- if ((spi->SR & SPI_I2S_FLAG_TXE) == RESET)
- return 0xFF;
- spi->DR = 0xFF;
- while ((spi->SR & SPI_I2S_FLAG_RXNE) == RESET && rt++ < SPI_Driver_RetryTimes); // 总是在该处超时
- if ((spi->SR & SPI_I2S_FLAG_RXNE) == RESET)
- return 0xFF;
- Data[i] = spi->DR;
- }
- return 0;
- }
复制代码
该代码,其在读取数据时,会有一定的几率导致:前面一段数据是正常的(一般约250B左右),后面就会在注释处超时(spi->SR的SPI_I2S_FLAG_RXNE始终不置位,调试器的SPI窗口已经关闭了,非调试模式也不行),然后返回0xFF。然后调用处也没加返回值的错误判断,导致输入缓冲区后半段数据根本没有刷新,所以是0000。然后这也就能解释,为什么刚开始的时候,会有几次能够成功挂载上去了(发生超时有一定的概率,后来为什么每次都挂载不了,具体也不清楚,难道是发生超时的概率升高了?)
后来,还是老老实实地改用
- for(; len > 0; --len)
- *data++ = SPIDriver_ReadWriteByte(dev->SPI, 0xFF);
复制代码
这种方式,然后万事大吉。
所以新问题来了,为什么上面一段函数会偶尔在注释处超时? |
|