zoukankan      html  css  js  c++  java
  • 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这两个文件位于RTTcomponentsdriversspi目录下,而spi.h头文件位于RTT\componentsdriversincludedrivers目录下.

    可在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 STM32F2XX
            stm32_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_SPI
        rt_hw_spi2_init();
    
    #ifdef RT_USING_DFS
        w25qxx_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,这些源文件在RTTcomponentsdfs目录下可以找到,一般不需要修改.

    但是在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 /.
    ");
    		}
    		else
    			rt_kprintf("flash0 mount to / failed.
    ");
    #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!
    ");
            }
            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
    ",buf);
                }
                else
                {
                    rt_kprintf("read file err!
    ");
                }
    
            }
        }


    结果如下:

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

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

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

    完!

  • 相关阅读:
    javascript 基本数据类型
    数据库管理小工具帮助
    CSS3实现32种基本图形
    面试题2:替换空格
    面试题1:二维数组中查找
    图的深度优先和广度优先搜索算法
    Spring+Maven+Dubbo+MyBatis+Linner+Handlebars—Web开发环境搭建
    Spring学习笔记—最小化Spring XML配置
    Spring学习笔记—装配Bean
    Spring学习笔记—Spring之旅
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3281378.html
Copyright © 2011-2022 走看看