RTT下spi flash+elm fat文件系统移植小记

2023-10-13 08:20

本文主要是介绍RTT下spi flash+elm fat文件系统移植小记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景:

  • MCU:STM32F207
  • SPI flash: Winbond W25Q16BV
  • OS: RTT V1.1.1
  • bsp: STM32F20x

1 将spi_core.c,spi_dev.c及spi.h三个文件加入工程


spi_core.c,spi_dev.c这两个文件位于RTT\components\drivers\spi目录下,而spi.h头文件位于RTT\\components\drivers\include\drivers目录下.

可在MKD工程的Drivers组下将上面两个源文件加进行,并将spi.h头文件所在目录添加到工程的include path下.


spi_core.c文件实现了spi的抽象操作,如注册spi总线(spi_bus),向SPI总线添加设备函数等.

注: 这里将MCU的一路spi外设虚拟成spi总线,然后总线上可以挂很多spi设备(spi_device),很个spi_device有一个片选cs.

spi总线和spi设备要在RTT中可以生效就必须先向RTT注册,因此就需要使用上面的注册SPI总线函数和向SPI总线中添加SPI设备.

spi_core.c还包含了配置SPI函数,发送和接收等通信函数,占用和释放SPI总线函数及选择SPI设备函数.这些函数都是抽象出来的,反映出SPI总线上的一些常规操作.真正执行这些操作的过程并不在spi_core.c源文件中,实际上,这些操作信息都是通过注册SPI总线和向总线添加SPI设备时这些操作集就已经"注册"下来了,真正操作时是通过注册信息内的操作函数去实现,也可以说是一种回调操作.


而spi_dev.c实现了SPI设备的一些抽象操作,比如读,写,打开,关闭,初始化等,当然当MCU操作SPI设备的时候,是需要通过SPI总线与SPI设备进行通信的,既然通信就必然会有SPI通信协议,但是通信协议并不在这里具体,spi_dev.c这里还只是SPI设备的抽象操作而已,它只是简单地调用spi_core.c源文件中的抽象通信而已,具体实现还是要靠上层通过SPI总线或SPI设备注册下来的信息而实现的.


在确保了spi_core.c,spi_dev.c和spi.h这三个源文件在MDK工程内之后,接着往下走.

2 添加stm32f20x_40x_spi.c及其对应头文件

将stm32f20x_40x_spi.c添加到Drivers组内.这个stm32f20x_40x_spi.c要在realtouch源码工程里找来,在文件系统示例代码中有.

在源文件在spi.h的基础上根据STM32F20x这款MCU的特点进行了进一步封装.这里修改的地方只有一处理:

即在config函数内配置SPI最大时钟时可根据MCU的具体特性配置为:30000000;

//#ifdef STM32F4XX
//        stm32_spi_max_clock = 37500000;
//#elif STM32F2XXstm32_spi_max_clock = 30000000;
//#endif

3 添加spi_flash_w25qxx.c进工程

由于这里使用的FLASH是Winbond的W25Q16BV,所以以此文件命名,此源文件及其头文件可以在realtouch的源文件中找到.realtouch工程正好也是使用的此flash.

顾名思义,此源文件正是针对w25q16这款芯片的特点来实现的,当然包含

在这里,具体实现了SPI通信的参数,这些参数传递给stm32f20x_4-x_spi.c文件中定义的函数,然后再进一步传递给spi_core来进行通信,spi_core的通信过程又会回调回来.

spi_flash_w25qxx.c还实现了read.write,open,close这些标准操作,这些函数就封装到一个结构体中通信注册函数注册到spi_core内部以供其回调所用.同时spi_flash_w25qxx.c还传递操作所必要的参数下去.

4 初始化 spi flash

接下来就是在RTT系统初始化时对SPI FLASH做些必要的初始化.

如下:

#ifdef RT_USING_SPIrt_hw_spi2_init();#ifdef RT_USING_DFSw25qxx_init("flash0", "spi20");
#endif /* RT_USING_DFS */

rt_hw_spi2_int()函数的作用是向RTT设备管理系统注册SPI2总线和向SPI2总线添加spi设备及其必要的IO管脚初始化. 这里仅仅只是注册设备而已.

w25qxx_init的作用是将SPI2总线上的SPI设备spi20注册成FLASH设备,也就是说将之前的设备告诉RTT其实是FLASH存储设备,然后配上相关的SPI FLASH存储设备参数.

在w25qxx_init函数内会读取spi flash的device id, 这里得根据自己所使用的具体FLASH进行修改.

rt_hw_spi_init函数如下:

这里PB12用作SPI FLASH的片选管脚.

static void rt_hw_spi2_init(void)
{/* register spi bus */{static struct stm32_spi_bus stm32_spi;GPIO_InitTypeDef GPIO_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;/*!< SPI SCK pin configuration */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;GPIO_Init(GPIOB, &GPIO_InitStructure);/* Connect alternate function */GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI2);GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);stm32_spi_register(SPI2, &stm32_spi, "spi2");}/* attach cs */{static struct rt_spi_device spi_device;static struct stm32_spi_cs  spi_cs;GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;/* spi21: PB12 */spi_cs.GPIOx = GPIOB;spi_cs.GPIO_Pin = GPIO_Pin_12;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);GPIO_InitStructure.GPIO_Pin = spi_cs.GPIO_Pin;GPIO_SetBits(spi_cs.GPIOx, spi_cs.GPIO_Pin);GPIO_Init(spi_cs.GPIOx, &GPIO_InitStructure);rt_spi_bus_attach_device(&spi_device, "spi20", "spi2", (void*)&spi_cs);}
}
注:在rt_config.h头文件中得将#define RT_USING_SPI宏打开.

5 移植ELM FAT文件系统

ELM FAT一般用不着移植,MDK工程中一般默认就有,如果没有就得自己添加了,一般包含6个C文件:

ff.c,dfs_elm.c,dfs.c,dfs_file.c,dfs_fs.c,dfs_posix.c,这些源文件在RTT\components\dfs目录下可以找到,一般不需要修改.

但是在rtconfig.h头文件中针对ELM需要做些修改,如下:

/* SECTION: device filesystem */
#define RT_USING_DFS 
#define RT_USING_DFS_ELMFAT
#define RT_DFS_ELM_REENTRANT
#define RT_DFS_ELM_WORD_ACCESS
#define RT_DFS_ELM_DRIVES			1
#define RT_DFS_ELM_USE_LFN			0 //这里一般设置为0,不使用长文件名,否则需要加入另外的源文件才能编译通过
#define RT_DFS_ELM_MAX_LFN			255
#define RT_DFS_ELM_MAX_SECTOR_SIZE  4096     //这里一定要与实际的spi flash一个扇区所包含的字节数相符,太小了会出现内存非法覆盖的情况/* the max number of mounted filesystem */
#define DFS_FILESYSTEMS_MAX			2
/* the max number of opened files 		*/
#define DFS_FD_MAX					4

此时附上MDK工程示图如下:


6  初始化文件系统及挂载文件系统

/* Filesystem Initialization */
#ifdef RT_USING_DFS{/* init the device filesystem */dfs_init();#ifdef RT_USING_DFS_ELMFAT/* init the elm chan FatFs filesystam*/elm_init();/* mount sd card fat partition 1 as root directory */if (dfs_mount("flash0", "/", "elm", 0, 0) == 0){rt_kprintf("flash0 mount to /.\n");}elsert_kprintf("flash0 mount to / failed.\n");
#endif}
#endif


7 格式化spi flash

烧录进MCU,首次时SPI FLASH是未格式化的,因此会挂载出错,此时可以在finish下使用mkfs来格式化FLASH,然后使用mkdir来创建一个目录,再使用ls指令来查看创建的目录是否存在,如果存在,则说明正常了.如下图:


通过这一步就说明SPI FLASH能正常工作了.

下面通过代码来测试.

8 通过代码来测试打开读写文件系统

在工程中加入如下测试代码:

{//文件系统测试代码int fd=0;fd =open("/myfile.txt",DFS_O_CREAT|DFS_O_RDWR,0);if(fd <0){rt_kprintf("open file failed!\r\n");}else{int count =write(fd,"123456",7);char buf[10];close(fd);fd =0;rt_thread_delay(50);rt_memset(buf,0,10);fd =open("/myfile.txt",DFS_O_RDONLY,0);if(read(fd,buf,7)){rt_kprintf("read=%s\r\n",buf);}else{rt_kprintf("read file err!\r\n");}}}

结果如下:

写进myfile.txt文件中的内容又可以原样读出来.

也可以通过ls指令再次查看/目录下的内容:



这样就验证了文件系统完全可以正常工作了.


完!




这篇关于RTT下spi flash+elm fat文件系统移植小记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/201920

相关文章

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

ZOJ Monthly, August 2014小记

最近太忙太忙,只能抽时间写几道简单题。不过我倒是明白要想水平提高不看题解是最好的了。 A  我只能死找规律了,无法证明 int a[50002][2] ;vector< vector<int> > gmax , gmin ;int main(){int n , i , j , k , cmax , cmin ;while(cin>>n){/* g

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

2014 Multi-University Training Contest 8小记

1002 计算几何 最大的速度才可能拥有无限的面积。 最大的速度的点 求凸包, 凸包上的点( 注意不是端点 ) 才拥有无限的面积 注意 :  凸包上如果有重点则不满足。 另外最大的速度为0也不行的。 int cmp(double x){if(fabs(x) < 1e-8) return 0 ;if(x > 0) return 1 ;return -1 ;}struct poin

2014 Multi-University Training Contest 7小记

1003   数学 , 先暴力再解方程。 在b进制下是个2 , 3 位数的 大概是10000进制以上 。这部分解方程 2-10000 直接暴力 typedef long long LL ;LL n ;int ok(int b){LL m = n ;int c ;while(m){c = m % b ;if(c == 3 || c == 4 || c == 5 ||

2014 Multi-University Training Contest 6小记

1003  贪心 对于111...10....000 这样的序列,  a 为1的个数,b为0的个数,易得当 x= a / (a + b) 时 f最小。 讲串分成若干段  1..10..0   ,  1..10..0 ,  要满足x非递减 。  对于 xi > xi+1  这样的合并 即可。 const int maxn = 100008 ;struct Node{int

什么是 Flash Attention

Flash Attention 是 由 Tri Dao 和 Dan Fu 等人在2022年的论文 FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness 中 提出的, 论文可以从 https://arxiv.org/abs/2205.14135 页面下载,点击 View PDF 就可以下载。 下面我

STM32内部闪存FLASH(内部ROM)、IAP

1 FLASH简介  1 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 2 通过在程序中编程(IAP)实现程序的自我更新 (OTA) 3在线编程(ICP把整个程序都更新掉) 1 系统的Bootloader写死了,只能用串口下载到指定的位置,启动方式也不方便需要配置BOOT引脚触发启动  4 IAP(自己写的Bootloader,实现程序升级) 1 比如蓝牙转串口,

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

STM32 ADC+DMA导致写FLASH失败

最近用STM32G070系列的ADC+DMA采样时,遇到了一些小坑记录一下; 一、ADC+DMA采样时进入死循环; 解决方法:ADC-dma死循环问题_stm32 adc dma死机-CSDN博客 将ADC的DMA中断调整为最高,且增大ADCHAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_Buffer_Size); 的ADC_Bu