Stm32CubeMx 通过SPIflash做一个U盘

这是一个卑微电子信息学员的开始

学习stm32

寒假开始了,卑微电子信息学员开始了stm32的学习过程。

SPI flash的注意事项

一. 擦除操作

  1. 以W25X16为例,最小Sector Erase 4KB(4096B),最大擦除全部文件,而做U盘时,每次的传输文件写入的大小为512B;
  2. 擦除需要时间,函数执行完毕不等于擦除操作完毕,当擦除操作未执行完整就进行其他操作会发生错误;

二. 写入操作

  1. 以W25X16为例,单次写入最大256B,当给出的长度超过256B时,会从开头开始覆盖先前写入的内容;
  2. 写入需要时间,函数执行完毕不等于写入操作完毕,当擦除操作未执行完整就进行其他操作会发生错误;

三.读数据操作

  1. 以W25X16为例,读数据的长度没有限制,只要你给函数的指针指向的空间有足够大的空间,就可以完成读数据操作;
  2. 读数据在任何时间都可以进行,速度远大于写或者擦除的速度,不用担心发生出错,是一个比较令人安心的函数;

容易遇到的问题

一.擦除的空间大于写入的空间

  1. 以W25X16为例,单次擦除至少4K,而写入是512B,众所周知,在进行SPI写入操作前,要进行写入操作的地址必须是被擦除过的地址,不然会无法写入;
  2. 就我个人而言,有两种思路:方法一.在每次写入前先读4KB的内容将其储存到一个数组中,再进行4KB的擦除,然后将要写入SPI的内容写到数组中,在将数组中的内容写入flash---------------------------------------------------我是分割线------------------------方法二 .在写入前先读4KB的内容将其储存到一个数组中,再进行4KB的擦除,然后将要写入SPI的内容写到数组中,不立即将数组中的内容跟新到flash,进行下一次写入操作,然后判断第二次写入的地址(512B)是否在前一次擦除的地址(4KB)内,如果在,将它赋值给数组,反之,将数组的内容更新到flash,再读4KB,擦除4KB进行循环

二.单次写入的内容只有256B而U盘单次写入512B

  1. 以W25X16为例,单次写入最大256B,想要写入更多的内容,之可以进行多次写入操作,这个比较简单,不多解释;

三.擦除操作的地址

  1. 以W25X16为例,擦除操作(4KB的)需要传入3BYTE的地址,但其实因为扇区的地址大小为4KB,不是任何的地址都可以作为扇区地址使用,必须是4KB(4096即0x1000)的整数倍;
  2. 给一个简单计算扇区首地址的简单是算法:(STORAGE_BLK_SIZ*blk_addr)&0xFFFFF000 其中STORAGE_BLK_SIZ定义为512,blk_addr为uint16_t类型的变量,表示当前的扇区号;

四.SPI函数

  1. SPi函数较上一次的函数做了一些改变,在地址的方面可以直接传输uint32_t的数据,更加方便计算,在函数的结尾都增加了检验该操作是否完成的语句,使该操作真正执行完才会进入下一个操作;

五.读操作

  1. 如果选用第一种方案,这个不用注意,该读什么读什么,但是,如果选用了第二种方案,读函数需要判断当前读的数据是在数组中还是在flash中,会麻烦一点,代码在最后面;

我用了第二种方案

因为第一种方案我开始也写了,但是因为实在效率低下,开始的时候应为在Cube中传输速度设定的太慢,导致格式化时间过长,格式化失败;后来提高传输速度勉强格式化成功,方法二的效率大约是方法一的8倍,所以我推荐在算法方面比较优秀的程序员选择第二中算法;
先给出经过改进后的SPIflash函数:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
和上次一样,有需要源代码的可以留言(我不知道怎么放代码)
然后是对U盘调用的两个读写函数的修改:
在这里插入图片描述
在这里插入图片描述
读和写的地址真的很重要,只要错一个地址基本上格式化就不会成功,我被其中的一个地址坑了好久,最后调试的时候很久才发现;
最后,这个代码有一个缺陷就是最后的一个传输的数据会储存在数组中,而不是在flash中,这就会产生掉电数据会损坏的问题,现阶段的解决方法是在main函数中一直判断是否在进行写入操作,如果发现有一段时间没有进行写入操作就将最后的几个数据写入flash,但是这样可能在写入的时候刚好U盘被拔出或者有新的数据传入,会发生冲突,希望有大佬可以帮我解答一下这一关问题,或者有更加好的想法,感激不尽;
本文仅供学习使用,希望可以对您的学习有帮助,大家除夕快乐(在除夕写的)!!