当前位置:文档之家› 基于STM32的FATFS文件系统移植

基于STM32的FATFS文件系统移植

基于STM32的FATFS文件系统移植
基于STM32的FATFS文件系统移植

基于STM32的FATFS文件系统移植

经过将近1个月的时间,终于完成了STM32是FATFS文件系统移植,说来是够艰辛的,SDIO章节是我学习cortex m3以来消耗时间最多的章节。这里说一些个人对于SDIO的看法,其实SDIO属于意法半导体公司在cortex m3内核之外(在芯片之内)添加的功能外设,完全属于意法的杰作了。关于SD卡的读写,分为SPI模式和SD模式(专用模式),这两种模式都必须遵循SD2.0协议。SPI模式控制方法相对较为简单,操作简洁,但失去了速度;SD模式控制方法相对较为复杂一点,操作繁琐,但具有高速的特点。

FATFS文件系统是一种兼容性比较高的文件管理系统,兼容

FAT32、FAT16。关于文件系统的细节,如果认真研究的话,应该会觉得作者的伟大,惊叹代码的绝妙。

我们要想移植FATFS,首先要做的是编写基于SDIO模式的SD卡底层驱动,这部份完整的驱动代码较多,大概有2000多行,但我们首先需要克服心理作用,再长的代码只要理解之后,都很简单。意法在参考手册中介绍SDIO时,上下文比较乱,其中还夹杂讲解了一些SD2.0协议,使得初学者云里雾里。因为SDIO是属于一种完全的外设接口,所以在讲解的过程中必须与实际的外设SD卡联系起来。

STM32的SDIO接口兼容性很高,可以兼容SD1.0卡、2.0卡、MMC 卡、多媒体卡等,与多媒体卡4.2支持三种不同的数据总线模式:1位、4位和8位,在8位的模式下速度可以达到48MHZ,但在SD2.0协议中只支持两种总数总线模式:1位和4位,在SDIO中存在两种状态机:命令状态机(CPSM)和数据状态机(DPSM),两者的使能信号独立,用于控制外部双向驱动器,命令是通过CMD命令线单线串行发送的,而数据是由于DATx数据线传输(1位或4位),每当CPSM发送一条命令给卡时,如工作正常的话,卡都会有与CPSM中设置响应格式相对应的响应内容(短响应与长响应),两者的细节在下面讲到。

SDIO功能分为两个部分,一个就是SDIO适配器模块,可以实现所有MMC/SD/SD I/O卡的相关功能,如时钟的产生、命令和数据的传输;还有就是AHB总线接口操作SDIO适配器模块中的寄存器,并产生中断和DMA请求信号。上面提到的数据总线的宽度为分为1位或4位(本文是针对SD2.0协议进行主要说明),在上电复位后,系统缺省为1位数据宽度——DAT0用于数据传输。SD卡或SD I/O卡可以使用两种数据宽度模式,这两种卡的所有数据线都需要设置为复用推挽模式。命令线CMD有两种操作模式:1、MMC卡V3.31或之前版本的卡在初始化时为

复用开路模式;2、SD卡或SD I/O卡或MMC V4.2在初始化时命令传输线工作在复用推挽模式。还有就是卡的时钟线(SDIO_CK),这个时钟频率对于不同的卡需要工作在不同的范围,这个我们就不细说了。SDIO的时钟可以分为两个,分为SDIO适配器时钟

(SDIOCLK=HCLK)和AHB总线时钟(HCLK/2),还有HCLK就是SYSCLK。既然提到外设接口,那就要清楚一共有几根线与主控芯片相连,分为SDIO_CK\SDIO_CMD\SDIO_D[7:0],本文是对SD2.0卡进行论述,所以只用到了SDIO_CK/SDIO_CMD/SDIO_D[3:0],因为SD卡不支持8线模式。

SDIO适配器主要全为5个部分:适配器寄存器模块、控制单元、命令通道、数据通道、数据FIFO。这5个部分中,不同部分使用的时钟也有不同,适配器寄存器和FIFO使用HCLK/2,控制单元、命令通道和数据通道使用的是SDIOCLK=HCLK。其实这5个部分,对于初学者来说,根本分不清有何具体区别。适配器寄存器模块包含所有系统寄存器,如用于存放状态位的SDIO_STA和清除中断寄存器SDIO_ICR,对相应寄存器写入清除中断标志(产生清除信号);控制单元有于电源管理和卡的时钟分频设置;命令通道(CPSM)主要用于向卡发送相应的命令并从卡接收相应的响应内容,实现主机与卡之间的控制信息交互,这里就必须提到SDIO_CMD命令寄存器,这个寄存器就是负责向发送命令的,与该寄存器相配合的还有一个参数寄存器(发送命令参数)SDIO_ARG,命令寄存器中存放了命令索引(命令号)和对应命令的等待响应设置和CPSM等待中断请求设置(这个设置一般使用无等待,关闭命令超时控制,改为中断清除方式,关于这个命令超时控制就是设定了一定的时间,在这个时间之间必须得到响应,否则状态机将进入空闲状态),还有就是命令响应了,命令响应寄存器SDIO_RESPCMD用于保存接收到的响应命令索引(如命令发送正常,得到响应命令索引和发送的一致,作为一个控制命令的回应),对于一些带响应的命令(只有cmd0没有响应),都会返回一些参数(如返回卡状态寄存器、CSD、CID),这些参数保存在响应寄存(SDIO_RESPx 1--4)中,该寄存器有4个,对于命令的短响应只用到SDIO_RESP1,其他3个寄存器不用,对于命令长响应,4个寄存器都用到,其实命令本身就决定了是否需要响应和响应的类型,48位(短响应:参数只有32位)还是136位(长响应,参数只有127位)。命令通道每发送一个命令,都有相应的通道状态标志来反应当前命令通道的状态,如CMDREND(响应的CRC正确)CCRCFAIL (响应的CRC错误)CMDSENT(命令已经发出,命令指不需要响应的命令)CTIMEOUT(响应超时)CMDACT(正在发送命

令)。在我们编写SD卡底层驱动时最常用的就是这些标志了,每发送一次命令,都要观察这个标志位的情况,以便程序员了解当前卡对刚发的命令的反应。数据通道(DPSM)用于主机与卡之间的数据通信,这与CPSM中的命令信息都是一些二进制“数据”,其实数据与命令之间本质上是一样的,但只是用户或设备对这些二进制的定义不同,用于控制设备的二进制串称为命令,而用于交互一些具体信息的二进制串称为数据。DPSM可以选择数据总线宽度,如1位数据宽度是指每个时钟数据线D0有一位数据传输,而4位数据宽度是指每个时钟数据线D4_0有四位数据传输,8位宽度则一次8位数据传输喽(SD卡不能使用8位,一般用于多媒体卡),而系统缺省为1位宽度,还有一点要说明的就是命令线和数据线都是双向传输的,而时钟线是单向传输的。在使能数据发送或接收时,DPSM就是进行Wait_S或Wait_R状态,如发送FIFO中有数据,就会进行发送状态,或接收FIFO接收到开始位,就会进入接收状态。但这个等待发送或等待接收不能一直等,等待时间是有限制的,由相关寄存器SDIO_DTIMER设置,当DPSM进行等待状态(发送或接收)时,一个计数器从该寄存器中加载数据,进行倒计时,当计数到0时,将设置超时标志关进入空闲状态。数据状态机也有反应数据传输状态的标志位,发送FIFO状态标志有

TXFIFOF/TXFIFOE/TXFIFOHE/TXDAVL/TXUNDERR和接收FIFO状态标志有RXFIFOF/RXFIFOE/RXFIFOHF/RXDAVL/RXOVERR。关于FIFO这个名词,其实是像数据结构中讲到的队列一样,先进先出,称为数据缓冲区,用户操作时只需直接读取SDIO->FIFO即可。FIFO的数据传输分为块传输和流传输,一般使用块传输。这个数据缓冲区一共有32个字的空间,如流传输下接收的数据超过32个字,而用户没有读取的话,将产生上溢错误。在与SD卡进行数据通信时,为保证数据的高速传输,我们一般使用DMA来将FIFO中的数据搬到内存中,而不需要人为的去读取。SDIO的数据通道是半双工通信,不能同时接收和发送,有两个标志位表示当前数据通道的状态:TXACT和RXACT,前者标志数据通道在发送FIFO,后者标志数据通道正在接收数据,这两个标志位是互斥的。到这里SDIO适配器已经基本了解了,就需要对SD卡通行操作了。

上述内容,作为初学者想真正理解,还是需要在下面对SD卡进行实际操作时才能真正了解其中的含义。

首先应设置与SD相连的GPIO的模式,使用SD卡的话,就需要设置CK/CMD/DAT3/DAT2/DAT1/DAT0为复用推挽输出,开启相应端口的时钟和SDIO时钟,如使用DMA的话,还需开启DMA2时钟。接下来就

是对SDIO中断进行配置(中断优先级分组和设置优先级,并在NVIC中使能SDIO向量中断),并对SDIO所有相关寄存器初始化(全部赋0)。

SD卡上电识别过程。需要通过时钟控制寄存器设置SDIO的时钟、数据线宽度和一些设置。SD卡在识别模式时频率低于400KHZ,将CLKDIV位设置为0xb2,SDIOCLK的上升沿产生SDIO_CK时钟,关闭硬件流控制,识别总线宽度为1线,关闭旁路时钟分频器,在空闲时仍输出SDIO_CK时钟,然后给SD上电,最后SDIO_CK时钟使能。这样就将系统时钟设置好了,之后就要向SD卡发送命令来为SD卡上电初始化。发送cmd0命令(无响应,无等待),复位所有卡到空闲状态;发送cmd8(短响应,无等待),发送卡接口条件,命令参数中包涵电压范围和校验码,发送这个命令的同时,SDIO将产生相应的电压,该命令用于询问卡是否支持参数中所指的电压范围(主机的电压),如支持则发送参数中的低八位的CRC校验码原样返回。通过cmd8命令,让我们知道卡是否支持主机电压。之后,就一直向卡发送ACMD41命令,等待卡上电。主机在发送ACMD41命令时,将一直产生主机的供电电压,不支持该电压的卡将自动进入非激活状态。ACMD41命令属于应用命令,需要先发送cmd55命令,再发送ACMD41命令。如SD2.0协议中说明了cmd55命令发送之后,卡将期待一个应用命令,如在cmd55之后发送一个非定义的应用命令,则将发送的命令当作普通命令处理,如是定义的应用命令,则当做应用命令执行。这里发送cmd55命令时,参数应该是RCA地址,而此时卡还没有成功上电,所以先使用0x00代替。ACMD41命令的参数中【31】保留位【30】测试卡容量【29:24】保留位【23:0】电压范围,【30】用于向卡表明主机可以支持的卡容量,在实验中将参数设置成了0x80100000|SD_Type(0x40000000),该命令R3响应,响应内容为ODR寄存器,该寄存器是卡的操作条件寄存器,其中包涵了卡的电压范围。ODR【31】为1表示SD卡成功上电,支持主机的提供的工作电压,【30】为1表明卡是SDHC卡,为0表明卡是SDSC 卡。通过ACMD41命令让程序员知道了卡的操作条件(工作电压)和卡的类型,完成卡的上电识别。接下来,我们就可以读取卡的特殊功能寄存器(CSD\CID\RCA地址)。

SD卡特殊寄存器读取。在卡完成上电识别的基础上,通过发送cmd2命令(参数:任意R2长响应响应内容为CID寄存器(127位)),通过发送cmd3命令(参数任意,R6短响应,响应内容为RCA 地址,就是卡的相对寻址地址),下面通过发送cmd9命令(参数高16位为RCA,低16位为任意《0x0000》,R2长响应,响应内容为CSD寄存器),关于长响应与短响应上面已经提到了,短响应只用到

SDIO_RESPx的低32位,高位保留,长响应全部使用。CSD、CID寄存器中包涵了卡的全部信息,如生产厂家,产品序列号等。

在卡完成上电识别之后,随即就读取了卡的特殊功能寄存器,也得到了卡的相对寻址地址RCA,基于完成了卡的初始化。协议规定卡在识别过程中速度必须低于400KHZ,而此时已经完成上电识别,所以需要提高速度,其他时钟设置不变。由于刚刚读取的CSD和CID寄存器在SD 卡存放时是以大端模式存放的,所以读取到的数据需要进行一次转换。大端模式是数据的低字节在高字节位,高字节在低字节位,而小端与其他相反,正常使用的都是小端模式(在ARM7中也提到了这个问题)。接下来是需要开启卡的四线模式,因为SD卡支持4位模式。想开启在四线模式,首先应该先选中卡,通过cmd7命令(参数为RCA地址,R1b短响应,R1响应内容都是卡状态寄存器,其他包括了卡的相关的状态)来选中需要操作的卡,靠RCA地址来区别各个卡。主机与卡之间的通信是需要对称的,如卡使用一线模式,那主机必须也要使用一线模式,所以应该先设置卡为四线模式,随后主机再开启四线模式,MMC不支持4线模式。当前卡也不一定支持4线模式的,这个信息通过卡SCR寄存器反应出来,SCR寄存器的值是通过数据方式传送给主机的,而不是像以上的寄存器是以命令响应的方式反应给主机,所以读取之前,还有判断卡是否上锁,这个信息是R1响应的卡状态寄存器中反应出来,如没有上锁,就可以读取SCR寄存器。那这里就不得不提前提到DPSM数据状态机了,读取数据之前一般需要发送一个cmd16命令(参数是数据块的大小《字节单位》,短响应)来设置数据块大小(此处也反应了主机与卡的之间的通信标准,双方相关设置需一样,先设置块大小,再设置主机传输的块大小),在之后的大数据量通信时,我们一般使用DMA方式传输数据,在这种情况下,数据传输之前,不设置块大小,程序将完死在等待DMA传输,这一点在各个电子论坛中已有提到。设置了卡块大小之后,再在SDIO_DCTRL寄存器中开启主机的数据传输块大小,还需要设置数值传输方向(卡到控制器)、传输模式(块传输)、数据块长度(0011 8字节),这里就可以看到SCR寄存器是8个字节的,设置完主机数据控制信息之后,能过命令通道发送ACMD51命令来要求卡向主机发送SCR寄存器数据。这里同样需要将数据转换一下(大小端)。读取了SCR值之后,就可以判断当前卡是否支持4线模式,如是SD2.0卡是支持4线模式的。之后发送ACMD6命令(参数为0x2表示4线,0表示1线,短响应)来开启卡的4线模式,在发送ACMD6命令之前,不要忘记发送一个CMD55命令(参数此时与上电识别时不知RCA地址不同了,需将参数设置为高16位为RCA地址,表示对指定地址的卡操作)。这时,我

们已经开启了卡的4线模式,之后就应该开启主机的4线模式了。注:命令是单独在CMD线上单线传输的,与这里的4线模式不相干,这时提到的4线模式是指传输用户数据的数据线DAT【4:0】。开启卡的4线模式之后,卡就可以完成高速率的数据传输了。

以后完成整个卡的初始化,接下来就可以进行正常的数据传输了。需要编写文件系统所需要的卡的底层操作函数了,FATFS文件系统使用非常灵活,完全摆脱了硬件操作,只需要提供卡的底层驱动函数就是将该系统轻松移植到嵌入式处理器上,如ARM、PIC、AVR、51等,基于做到了不需要修改代码,就可以成功移植,虽然整个文件系统的代码也有几万行,这与Linux的移植比起来就简单多了。

文件系统需要程序员提供的函数有:块擦除函数、单数据块读取、多数据块读取、单数据块写入、多数据块写入,如:u8 SD_Erase(u32 startaddr,u32 endaddr);u8 SD_WriteBlock(u8 *WriteBuff,u32 WriteAddr,u32 BlockSize);u8 SD_ReadBlock(u8 *ReadBuff,u32 ReadAddr,u32 BlockSize);u8 SD_ReadMultiBlocks(u8* readbuff,u32 Readaddr,u16 BlockSize,u32 NumberOfBlock);u8 SD_WriteMultiBlocks(u8 *writebuff,u32 Writeaddr,u16 BlockSize,u32 NumberOfBlock);

数据块擦除还需要查看卡是否支持擦除操作,这一信息在CSD寄存器中反应出来,如卡上锁了,那也不能执行擦除操作。执行块擦除操作之后,所谓块擦除肯定关系到块的大小,而SDHC卡的块是固定大小,CMD16命令的设置将无效。通过cmd32命令向卡发送擦除的起始块地址(注:是块地址),通过cmd33命令向卡发送擦除的结束块地址(当前地址的块也擦除),这样做先将需要擦除的范围确定下来,再发送cmd38命令正式执行擦除操作。在程序设计时,刚发送完cmd38命令时,最好延时一段时间,再执行其他操作,因为执行大范围的擦除操作,卡的内部执行需要一段时间,这一段时间卡处于BUSY状态,将忽略其他命令,当卡不处于接收状态,也不处于编程状态(擦除也是这个动作),再执行其他操作。

单数据块读写,数据写之前一定要发送一个cmd16命令设置一下卡的数据块大小,SDHC卡的块大小固定,不受该命令影响,被忽略。然后发送cmd24命令,使进入相对应的接收状态,再设置SDIO_DCTRL数据控制寄存器,为了提高数据传输和程序的效率,将使能DMA,数据控制寄存器需要设置其数据块长度,传输模式(块传输)、传输方向(控制器到卡),还要设置数据长度寄存器(该寄存器在数据传输开始时,值被加载到数据计数器中)和数据定时器寄存器(超时时间)。在

对应的DMA设置中也存在一个细节要注意,数据数量寄存器应设置一为数据总字节的四分之一,因为DMA数据宽度最高为32位(4个字节),是按字节数计算数据量的,也因为SDIO_FIFO也是32位的。之后等待DMA数据传输结束,并查询卡的状态,直到卡处于发送状态(这一点我也不是很清楚)。单数据块读取基于跟发送相同,只有传输方向有变化,还有一个就是设置主机,使主机处于Wait_R状态,后通过命令通道发送命令要求卡向主机发送数据。读取单数据块相关命令有cmd17命令(单数据块读取)。

多数据块读写。与单数据块的读写也有相同原理,使用的命令也不同。但主要有两点要注意,第一个就是多数据写入时,为了提高效率,需要发送一个预擦除命令(可以不用),数据的写入,其他卡内部执行了两个操作(先操作,再编程),预擦除只是提前让卡执行擦除操作,这个问题只有在多数据块写入时,需要注意,读取就不需要了。第二点就是数据传输结束时,需要发送一个停止数据传输命令cmd12,停止卡与主机之间的通信,因为多数据块写入命令执行过后,不执行停止命令,卡将一直从主机接收数据,即使主机已经停止,但卡仍认为有数据传输(主机停止时,数据处于释放状态,卡为认为数据全是1),相反读取多数据块数据也相似。多数据读写相关命令有ACMD23(预擦除命令)、CMD25(连续数据块写入)、CMD18(连续数据块读取)。

在以上使用DMA的数据传输的这此函数中,还有一个细节需要注间:SD_DMA_TxConfig((u32 *)writebuff,(NumberOfBlock*BlockSize));其中的参数writebuff在定义的时候u8*类型的,而这里将它强制转换成了u32*,这一点其实没有错误,数组在内存中存放是线性连续的,而本来的u8* writebuff中的writebuff标识的是该数组中内存中存放的首地址,并数据宽度以为1字节存放的,也就是说writebuff是字节地址,使用

u32*将其转换成了字地址,如果这块空间中存放的是00 01 02 03 04 05 06 07,这样本为原来的*writebuff的值是00,而转换之后的*writebuff的值将变为00010203,这样再使用DMA传输,设置数据宽度为32位,将大大提高数据传输效率。

以上完成了基于SDIO模式的SD底层驱动函数,现在就可以移植文件系统了,我们将文件的文件拷到当前工程的文件下,添加进工程,再作简单修改就可以使用文件系统的接口函数完成文件的新建、打开、修改和关毕了,如新建一个DEMO.TXT文件,再在里面写入“文件系统成功移植”这样的汉字,再关毕文件,这个文件就存放在SD卡中了,可以由PC机在Windows系统正常打开了,文件的类型可以很多,不一定是TXT,如DOC也是可以的(我亲手测试过)。需要修改的文件系统代码

是diskio.c,将SD卡的底层函数按要求填入相应位置,再将diskio.c中的添加头文件sdio.h(这是我的底层函数的头文件)。我在官网下载的程序,发现其中还添加了stm32f10x.h,这个头文件不能添加,需要删掉,不然将出现很多重定义的错误。

到这里就成功完成FATFS文件系统的移植,是不是也感觉很简单呢。刚开始学SDIO时,的确是不懂。因为SDIO是属于一种完全的外设接口,主要功能还需要根据外部器件来使用,所以意法半导体公司在Datasheet中也讲解到了很多SD2.0协议的内容,搞得内容很乱。但真正明白协议之后,就可以拨云见日了。

孙为

2013年1月17日21:26:29

LINUX文件系统制作详细

Linux文件系统制作流程 关键词:ARM Linux yaffs文件系统移植 Linux文件系统简介 Linux支持多种文件系统,包括ext2、ext3、vfat、ntfs、iso9660、jffs、romfs和nfs等,为了对各类文件系统进行统一管理,Linux引入了虚拟文件系统VFS(Virtual File System),为各类文件系统提供一个统一的操作界面和应用编程接口。 Linux下的文件系统结构如下: Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。之后可以自动或手动挂载其他的文件系统。因此,一个系统中可以同时存在不同的文件系统。 不同的文件系统类型有不同的特点,因而根据存储设备的硬件特性、系统需求等有不同的应用场合。在嵌入式Linux应用中,主要的存储设备为RAM(DRAM,

SDRAM)和ROM(常采用FLASH存储器),常用的基于存储设备的文件系统类型包括:jffs2,yaffs,cramfs,romfs,ramdisk,ramfs/tmpfs等。 >基于FLASH的文件系统 Flash(闪存)作为嵌入式系统的主要存储媒介,有其自身的特性。Flash的写入操作只能把对应位置的1修改为0,而不能把0修改为1(擦除Flash就是把对应存储块的内容恢复为1),因此,一般情况下,向Flash写入内容时,需要先擦除对应的存储区间,这种擦除是以块(block)为单位进行的。 闪存主要有NOR和NAND两种技术(简单比较见附录)。Flash存储器的擦写次数是有限的,NAND闪存还有特殊的硬件接口和读写时序。因此,必须针对Flash 的硬件特性设计符合应用要求的文件系统;传统的文件系统如ext2等,用作Flash的文件系统会有诸多弊端。 在嵌入式Linux下,MTD(Memory Technology Device,存储技术设备)为底层硬件(闪存)和上层(文件系统)之间提供一个统一的抽象接口,即Flash的文件系统都是基于MTD驱动层的(参见上面的Linux下的文件系统结构图)。使用MTD 驱动程序的主要优点在于,它是专门针对各种非易失性存储器(以闪存为主)而设计的,因而它对Flash有更好的支持、管理和基于扇区的擦除、读/写操作接口。 顺便一提,一块Flash芯片可以被划分为多个分区,各分区可以采用不同的文件系统;两块Flash芯片也可以合并为一个分区使用,采用一个文件系统。即文件系统是针对于存储器分区而言的,而非存储芯片。 1.jffs2 JFFS文件系统最早是由瑞典Axis Communications公司基于Linux2.0的内核为嵌入式系统开发的文件系统。JFFS2是RedHat公司基于JFFS开发的闪存文件系统,最初是针对RedHat公司的嵌入式产品eCos开发的嵌入式文件系统,所以JFFS2也可以用在Linux,uCLinux中。 Jffs2:日志闪存文件系统版本2(Journalling Flash FileSystem v2) 主要用于NOR型闪存,基于MTD驱动层,特点是:可读写的、支持数据压缩的、基于哈希表的日志型文件系统,并提供了崩溃/掉电安全保护,提供“写平衡”支持等。缺点主要是当文件系统已满或接近满时,因为垃圾收集的关系而使jffs2的运行速度大大放慢。 目前jffs3正在开发中。关于jffs系列文件系统的使用详细文档,可参考MTD补丁包中mtd-jffs-HOWTO.txt。 jffsx不适合用于NAND闪存主要是因为NAND闪存的容量一般较大,这样导致jffs为维护日志节点所占用的内存空间迅速增大,另外,jffsx文件系统在

STM32学习笔记

输入模式初始化GPIOE2,3,4 ①IO口初始化:GPIO_InitTypeDef GPIO_InitStructure; ②使能PORTA,PORTE时钟: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE); ③PE.2.3.4端口配置:GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4; ④设置成(上拉)输入:GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; ⑤GPIO_Init(GPIOE, &GPIO_InitStructure); 输出模式初始化 ①IO口初始化:GPIO_InitTypeDef GPIO_InitStructure; ②使能PB,PE端口时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); ③3LED0-->PB.5 端口配置GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; ④设置(推挽)输出模式GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; ⑤设置IO口速度为50MHz GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; ⑥说明初始化哪个端口GPIO_Init(GPIOB, &GPIO_InitStructure); 在LED灯试验中初始为高电平灭GPIO_SetBits(GPIOB,GPIO_Pin_5); 再初始化相同发输出模式时③④⑤可省略例如(经实验初始化恰好为不同IO口相同IO序号③可省略,应该不规范吧) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED1-->PE.5 端口配置, 推挽输出GPIO_Init(GPIOE, &GPIO_InitStructure); //推挽输出,IO口速度为50MHz GPIO_SetBits(GPIOE,GPIO_Pin_5); //PE.5 输出高 1,头文件可以定义所用的函数列表,方便查阅你可以调用的函数; 2,头文件可以定义很多宏定义,就是一些全局静态变量的定义,在这样的情况下,只要修改头文件的内容,程序就可以做相应的修改,不用亲自跑到繁琐的代码内去搜索。 3,头文件只是声明,不占内存空间,要知道其执行过程,要看你头文件所申明的函数是在哪个.c文件里定义的,才知道。 4,他并不是C自带的,可以不用。 5,调用了头文件,就等于赋予了调用某些函数的权限,如果你要算一个数的N次方,就要调用Pow()函数,而这个函数是定义在math.c里面的,要用这个函数,就必需调用math.h 这个头文件。

实验四Linux内核移植实验

合肥学院 嵌入式系统设计实验报告 (2013- 2014第二学期) 专业: 实验项目:实验四 Linux内核移植实验 实验时间: 2014 年 5 月 12 实验成员: _____ 指导老师:干开峰 电子信息与电气工程系 2014年4月制

一、实验目的 1、熟悉嵌入式Linux的内核相关代码分布情况。 2、掌握Linux内核移植过程。 3、学会编译和测试Linux内核。 二、实验内容 本实验了解Linux2.6.32代码结构,基于S3C2440处理器,完成Linux2.6.32内核移植,并完成编译和在目标开发板上测试通过。 三、实验步骤 1、使用光盘自带源码默认配置Linux内核 ⑴在光盘linux文件夹中找到linux-2.6.32.2-mini2440.tar.gz源码文件。 输入命令:#tar –jxvf linux-2.6.32.2-mini2440-20110413.tar对其进行解压。 ⑵执行以下命令来使用缺省配置文件config_x35 输入命令#cp config_mini2440_x35 .config;(注意:x35后面有个空格,然后有个“.”开头的 config ) 然后执行“make menuconfig”命令,但是会出现出现缺少ncurses libraries的错误,如下图所示: 解决办法:输入sudo apt-get install libncurses5-dev 命令进行在线安装ncurses libraries服务。

安装好之后在make menuconfig一下就会出现如下图所示。 ⑶配置内核界面,不用做任何更改,在主菜单里选择退出,并选“Yes”保存设置返回到刚命令行界面,生成相应配置的头文件。 编译内核: #make clean #make zImage 在执行#make zImage命令时会出现如下错误: 错误:arch/arm/mach-s3c2440/mach-mini2440.c:156: error: unknown field 'sets' specified in initializer 通过网上查找资料 于是在自己的mach-mini2440.c中加入 #include

文件系统移植

嵌入式linux内核上文件系统的移植 实验目的:在已经能运行的内核上架构文件系统 其实,虽然 root_qtopia 这个文件系统的GUI 是基于Qtopia 的,但其初始化启动过程 却是由大部分由busybox 完成,Qtopia(qpe)只是在启动的最后阶段被开启。由于默认的内核命令行上有 init=/linuxrc, 因此,在文件系统被挂载后,运行的第一个程 序是根目录下的linuxrc。这是一个指向/bin/busybox 的链接,也就是说,系统起来后运行的 第一个程序也就是busybox 本身。 这种情况下,busybox 首先将试图解析/etc/inittab 来获取进一步的初始化配置信息(参 考busybox 源代码init/init.c 中的parse_inittab()函数)。而事实上,root_qtopia 中并没有/et c/inittab 这个配置文件,根据busybox 的逻辑,它将生成默认的配置 实验过程: 一、获取yaffs2源代码 现在大部分开发板都可以支持 yaffs2 文件系统,它是专门针对嵌入式设备,特别是使用nand flash 作为存储器的嵌入式设备而创建的一种 文件系统,早先的yaffs 仅支持小页(512byte/page)的nand flash,现 在的开发板大都配备了更大容量的nand flash,它们一般是大页模式 (2K/page),使用yaffs2 就可以支持大页的nand flash,下面是yaffs2 的移植详细步骤。 在https://www.doczj.com/doc/5b1693642.html,/node/346 可以下载到最新的yaffs2 源代码,需要使用git工具( 安装方法见本手册第一章),在命令行输入:#git clone git://https://www.doczj.com/doc/5b1693642.html,/yaffs2 稍等片刻,就可以下载到最新的yaffs2 的源代码目录,本光盘中也有单独的yaffs2 源代码包( 文件名为:yaffs2-src-20100329.tar.gz)

STM32学习笔记_STM32F103ZET6

STM32F103 系列芯片的系统架构: 系统结构: 在每一次复位以后,所有除SRAM 和FLITF 以外的外设都被关闭,在使用一个外设之前,必须设置寄存器RCC_AHBENR 来打开该外设的时钟。

GPIO 输入输出,外部中断,定时器,串口。理解了这四个外设,基本就入门了一款MCU。 时钟控制RCC: -4~16M 的外部高速晶振 -内部8MHz 的高速RC 振荡器 -内部40KHz低速RC 振荡器,看门狗时钟 -内部锁相环(PLL,倍频),一般系统时钟都是外部或者内部高速时钟经过PLL 倍频后得到 - 外部低速32.768K 的晶振,主要做RTC 时钟源

ARM存储器映像: 数据字节以小端格式存放在存储器中。一个字里的最低地址字节被认为是该字的最低有效字节,而最高地址字节是最高有效字节。

存储器映像与寄存器映射: ARM 存储器映像 4GB 0X0000 00000X1FFF FFFF 0X2000 00000X3FFF FFFF 0X4000 00000X5FFF FFFF

寄存器说明: 寄存器名称 相对外设基地址的偏移值 编号 位表 读写权限 寄存器位 功能说明 使用C语言封装寄存器: 1、总线和外设基地址封装利用地址偏移 (1)定义外设基地址(Block2 首地址) (2)定义APB2总线基地址(相对外设基地址偏移固定) (3)定义GPIOX外设基地址(相对APB2总线基地址偏移固定)(4)定义GPIOX寄存器地址(相对GPIOX外设基地址偏移固定)(5)使用 C 语言指针操作寄存器进行读/写 //定义外设基地址 #define PERIPH_BASE ((unsigned int)0x40000000) 1) //定义APB2 总线基地址 #define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000) 2) //定义GPIOC 外设基地址 #define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800) 3) //定义寄存器基地址这里以GPIOC 为例 #define GPIOC_CRL *(unsigned int*)(GPIOC_BASE+0x00) 4) #define GPIOC_CRH *(unsigned int*)(GPIOC_BASE+0x04) #define GPIOC_IDR *(unsigned int*)(GPIOC_BASE+0x08) #define GPIOC_ODR *(unsigned int*)(GPIOC_BASE+0x0C) #define GPIOC_BSRR *(unsigned int*)(GPIOC_BASE+0x10) #define GPIOC_BRR *(unsigned int*)(GPIOC_BASE+0x14) #define GPIOC_LCKR *(unsigned int*)(GPIOC_BASE+0x18) //控制GPIOC 第0 管脚输出一个低电平5) GPIOC_BSRR = (0x01<<(16+0)); //控制GPIOC 第0 管脚输出一个高电平 GPIOC_BSRR = (0x01<<0);

FAT文件系统原理详细介绍

FAT文件系统原理详细介绍 2012-03-29 23:09 434人阅读评论(0) 收藏举报 FAT文件起源于70年代末80年代初,用于微软的MS-DOS操作系统。它开始被设计成一个简单的文件系统用于小于500K的软件盘。后来被功能被大大增强用于支持越来越大的媒质。现在的文件系统有FAT12,FAT16和FAT32三种子类。 FAT12是最早的一版,主要用于软盘,它对簇的编址采用12bit宽度的数,所以称为FAT12。12bit的地址可以寻址4096个簇,事实上在FAT12中只能寻址4078个簇(在Linux 下可寻址4084个簇),有一些簇号是不能用的,在后面会给出具体的说明。磁盘的扇区是用16bit的数进行计算的,所以磁盘的容量就被局限在32M空间之内。 在FAT16中,采用了16bit宽的簇地址,32bit宽扇区地址。虽然32bit的扇区地址可以寻址2^32*512,约2个TB的容量,但于由规定每簇最大的容量不超过1024*32,所以FAT16文件系统的容量也就限制到了2^16*1024*32,大约2.1GB的空量,并且实际还达不到这个值。 FAT32文件系统使用了32bit宽的簇地址,所以称为FAT32。但在微软件的文件系统中只使用了低28位,最大容量为2^28*1024*32,约8.7TB的空量。有的人认为32bit全用,最大容量为2^32*1024*32,这种说法是不正确的。 虽然FAT32具有容纳近乎8.7TB的容量,但实际应用中通常不使用超过32GB的FAT32分区。WIN2000及之上的OS已经不直接支持对超过32GB的分区格式化成FAT32,但WIN98依然可以格式化大到127GB的FAT32分区,但不推荐这样做。 下面是一个FAT分区的构成概况 需要说明的是: 1.引导扇区和其他保留扇区一起称为保留扇区,而其他保留扇区是可选的,当没有时候,引导扇区后紧跟的就是FAT表1 2.根目录区是仅FAT12/16才有,FAT32的目录项位于数据区。由于FAT12/16的根目录区是一个固定的区域,所以它的根目录的项数是有限制的,意即不能在根录建立超过这个定数的目录项数。 (一)引导扇区与BPB BPB(BIOS Parametre Block)是FAT文件系统中第一个重要的数据结构,它位于该FAT分区的第一个扇区,同时也属于FAT文件系统基本区域的保留区, 在下面的描述中。凡名称以BPB_开头的都是BPB的一部分,凡名称与BS_开头的项

根文件系统移植

实验五根文件系统移植 实验目的: 通过本次实验,使大家学会根文件系统移植的具体步骤,并对根文件系统有更近一步的感官认识。让同学理解由于根文件系统是内核启动时挂在的第一个文件系统,那么根文件系统就要包括Linux启动时所必须的目录和关键性的文件,任何包括这些Linux 系统启动所必须的文件都可以成为根文件系统。 实验硬件条件: 1、实验PC机一台,TINY6410开发板一台 2、电源线,串口线,数据线。 实验软件条件: 1、VMware Workstation, 2、Ubuntu10.04 3、mktools-20110720.tar.gz 4、busybox-1.13.3-mini2440.tgz, 5、SecureCRT以及dnw烧写工具 实验步骤: 一、实验步骤 1.进入rootfs目录,查看压缩文件,具体操作指令如下:

2.发现有两个压缩文件夹,分别进行解压: 3.tar xvzf busybox-1.13.3-mini2440.tgz, 4.tar xvzf mktools-20110720.tar.gz,解压完成后, 5.查看文件夹#ls

二、实验步骤 1.修改架构,编译器#cd busybox-1.13.3/ 2.进入后查看#ls 3.#gedit Makefile 4.修改 164行 CROSS_COMPILE ?=arm-linux- 5.修改190行 ARCH ?= arm 6.保存后,退出!

三、实验步骤 1.修改配置 #make menuconfig 2.若出现如下提示

3.需调整到最大化。

4.把Busybox Settings -----→>Build Option ------→> Build BusyBox as astatic binary (no shared libs) 选择上,其他的默认即可。 然后一直退出,保存即可 5.接着执行 make接着执行 make install 6.最终生成的文件在_install 中 #cd _install

stm32学习 c语言笔记

这是前段时间做彩屏显示时候遇到的难题, *(__IO uint16_t *) (Bank1_LCD_C)这个就是将后面的数据转换为地址,然后对地址单元存放数据。可如下等效: __IO uint16_t *addr; addr = (__IO uint16_t *) Bank1_LCD_C; #ifdef和#elif连用,语法和if。。。else if语句一样 推挽输出增加驱动,可以驱动LED起来 static int count=0 count++ 这个语句中,count仅仅被初始化一次 以后加加一次期中的值就不会变化了 SysTick_CTRL(控制和状态寄存器) SysTick_LOAD(重装载寄存器) SysTick_VAL(当前值寄存器) SysTick_CALIB(校准值寄存器)

TFT经验:弄多大的相片,必须先把那个相片的尺寸改掉,再去取模,才可以,要不会有重影的嘿嘿嘿嘿 VBAT 是电池供电的引脚 VBAT和ADD同时都掉电时才能让备份区复位。 volatile一个变量的存储单元可以在定义该变量的程序之外的某处被引用。 volatile主要是程序员要告诉编译器不要对其定义的这个变量进行优化,防止其不能被引用,不能被改变。 VDDA>2.4V ADC才能工作 VDDA>2.7V USB才能工作 VDD(1.8-3.6v) VBAT=1.8-3.6v VSS VSSA VREF必须接到地线 没有外部电源供电时必须VBAT接上VDD 使用PLL时,VDDA必须供电

printf("abs(x)=%d\n",x<0?(-1)*x:x) 条件编译是问号前边为真则取冒号前边的值,为假的,则取后边的值。 所以说上边这条打印的语句是打印x的绝对值。 //stm32f10x_nvic.c stm32f10x_lib.c stm32f10x_gpio.c stm32f10x_flash.c stm32f10x_rcc.c TIM6 TIM7基本定时器 (只有这两个定时器不能产生PWM) TIM1 TIM8高级控制定时器 TIM2 TIM3 TIM4 TIM5为通用定时器 其中高级定时器TIM1和TIM8可以同时产生多达7路的PWM输出。而通用定时器也能同时产生多达4路的PWM输出,这样,STM32最多可以同时产生30路PWM输出! 修改和自己写代码时候

FATFS深入理解

一、通过格式化命令-看磁盘文件系统的建立过程 1、添加format命令,单步调试 所有的底层驱动函数都已经准备好。添加格式化命令format后,编译下载。 Format命令的执行主要是调用f_mkfs()函数,下面进行单步调试。 以下主要列出函数的主要执行步骤: res=f_mkfs( 0, 1, 4096 ); //1表示不需要引导扇区。4096是8个扇区。 进入f_mkfs()函数,这里只列出主要执行步骤: if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_part) != RES_OK || n_part < MIN_SECTOR) return FR_MKFS_ABORTED;这个函数调用后,n_part=0x000F,3400 = 996 352,这是SD的总块数。allocsize /= SS(fs); 等于8/*Number of sectors per cluster */ n_clst = n_part / allocsize; //等于0x1E680 = 124 544 簇。 if (n_clst >= 0xFFF5) fmt = FS_FAT32; 所以文件系统确定为FAT32类型。 n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs); 等于0x3CE = 974,表示FAT要占据974个扇区。 n_rsv = 33 - partition; 保留扇区32个。 n_dir = 0; b_fat = b_part + n_rsv; /* FATs start sector 32扇区*/ b_dir = b_fat + n_fat * N_FATS; /* Directory start sector 0x3EE =1006,由于FAT表个数设为1个,所以目录区=FAT起始+FAT占用扇区数*/ b_data = b_dir + n_dir; /* Data start sector */ 以上三项确定FAT区域、根目录区、数据区的起始扇区。 disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK,这个函数调用没有正确返回可擦出扇区的总数。接下来程序会出错,因此退出,修改disk_ioctl()函数后,再次分析。把这个函数返回值直接改为32。并且把FAT表的个数定义为2. N_FATS改为2后,根目录区、数据区的起始扇区的起始扇区变为0x7BC=1980扇区。继续往下执行。 n = (b_data + n - 1) & ~(n - 1); n_fat += (n - b_data) / N_FATS;这两句话对fat所占扇区数进行了修正,保证擦除时,以32个扇区为一个单位。 n_clst = (n_part - n_rsv - n_fat * N_FATS - n_dir) / allocsize; =0x1E588。 tbl = fs->win; /* Clear buffer */ mem_set(tbl, 0, SS(fs)); 清零文件系统缓冲区。 mem_set(tbl, 0, SS(fs)); ST_DWORD(tbl+BS_jmpBoot, 0x90FEEB); /* Boot code (jmp $, nop) */ ST_WORD(tbl+BPB_BytsPerSec, SS(fs)); /* Sector size */ tbl[BPB_SecPerClus] = (BYTE)allocsize; /* Sectors per cluster */ ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */ 上面的工作主要是填充引导扇区缓冲区,也就是常说的DBR扇区缓冲,等所有的参数写好,就可以写回磁盘。 ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature */ if (disk_write(drv, tbl, b_part+0, 1) != RES_OK) return FR_DISK_ERR; //这就是在写有效引导标志sec[510]=0x55, sec[511]=0xAA。 if (fmt == FS_FAT32) disk_write(drv, tbl, b_part+6, 1); //FAT32在第六扇区有个备份引导扇区。 for (m = 0; m < N_FATS; m++) { mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */ if (fmt != FS_FAT32) { n = (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00; n |= partition; ST_DWORD(tbl, n); /* Reserve cluster #0-1 (FAT12/16) */ } else { ST_DWORD(tbl+0, 0xFFFFFFF8); /* Reserve cluster #0-1 (FAT32) */

FATFS文件系统移植和应用

FATFS文件系统的移植 作者:LJ 时间:2010年11月12日 随着信息技术的发展,目前常用文件系统主要有微软的FAT12、FAT16、FAT32、NTES文件系统,以及Linux系统的EXT2、EXT3等。由于Windows操作系统的广泛应用,当前很多嵌入式产品中用的最多的还是FAT文件系统。所以,选择一款容易移植和使用,并且占用资源少而功能全面的文件系统就显得非常重要了。 FATFS文件系统是一个完全免费且开源的FAT文件系统模块,由小日本工程师编写,它支持FAT12、FAT16和FAT32文件系统,专门为小型的嵌入式系统而设计。模块用标准的C语言编写,可以很容易地移植到各种硬件平台。 在“驱动程序”文件夹中有一个“FatFs R0.07c”文件夹,这是官方提供的FATFS文件系统的源码和文档,版本为R0.07c。打开“doc”文件夹下的“00index_e.html”英文网页文档,里面有FATFS文件系统的全部API函数说明,相对应的应用实例和如何编写硬件接口程序的说明。如果您的英文不怎么好,建议您先装一个有道词典,使用屏幕取词功能,能帮助我们阅读和理解。“00index_j.html”则是日文版的网页,毕竟是小日本写的。“src”文件夹存放有FATFS文件系统源码,下面是该文件夹下各个文件或文件夹存放的内容说明:“ff.h”文件:FATFS文件系统的配置和API函数声明; “ff.c”文件:FATFS源码;

“diskio.h”文件:FATFS与存储设备接口函数的声明; “diskio.c”文件:FATFS与存储设备接口函数; “integer.h”文件:FATFS用到的所有变量类型的定义; “option”文件夹:存放一些外接函数,下一实例有实际的讲解; “00readme.txt”文件:FATFS版本及相关信息说明; 编译工程,没有通过,根据编译信息提示在“diskio.c”文件中在几个函数没有定义。这很正常,因为我们还没有编写文件系统与存储设备的接口函数。下面来分析“diskio.c”文件中各个函数的功能:“DSTATUS disk_initialize ( BYTE drv )”是存储媒介的初始化函数,由于我们使用的是SD卡,所以实际上是对SD卡的初始化; “DSTATUS disk_status ( BYTE drv )”状态检测函数,检测是否支持当前的存储设备,支持返回0; “DRESULT disk_read (BYTE drv, BYTE *buff, DWORD sector, BYTE count)”是读扇区函数,drv是要读扇区的存储媒介号,*buff 存储读取的数据,sector是读数据的开始扇区,count是要读的扇区数。在SD卡的驱动程序中,分别提供了读一个扇区和读多个扇区的函数。当count == 1时,用读一个扇区函数;当 count > 1时,用读多个扇区的函数,这样提高了文件系统读效率。操作成功返回0。 “DRESULT disk_write(BYTE drv, BYTE *buff, DWORD sector, BYTE count)”写扇区函数,drv是要写扇区的存储媒介号,*buff存储写入的数据,sector是写开始扇区,count是要写的扇区数。同样在SD卡的驱动程序中,分别提供了写一个扇区和写多个扇区的函数。

FATFS文件系统剖析1

FATFS文件系统剖析1: FAT16: 数据按照其不同的特点和作用大致可分为5部分:MBR区、DBR区、FAT区、DIR区和DATA区,相比fat12多了DBR区 Main boot record: MBR(0--1bdh)磁盘参数存放 DPT(1beh--1fdh)磁盘分区表 55,aa 分区结束标志 DBR(Dos Boot Record)是操作系统引导记录区的意思 FAT区(有两个,一个备份):对于fat16,每一个fat项16位,所以可寻址的簇项数为65535(2的16次方)。而其每簇大小不超过32k,所以其每个分区最大容量为2G。fat32,每一个fat项32位,可寻址簇数目为2的32次方。 DIR区(根目录区):紧接着第二FAT表(即备份的FAT表)之后,记录着根目录下每个文件(目录)的起始单元,文件的属性等。定位文件位置时,操作系统根据DIR中的起始单元,结合FAT表就可以知道文件在硬盘中的具体位置和大小了。 DATA区:实际文件内容存放区。 FAT32: 暂时放在这里,不讨论! Fatfs:嵌入式fat文件系统,支持fat16,fat32。 包含有ff.h,diskio.h,integer.h,ffconf.h 四个头文件以及ff.c 文件系统实现。当然要实现具体的应用移植,自己要根据diskio.h实现其diskio。c 底层驱动。 diskio.h : 底层驱动头文件 ff.h : 文件系统实现头文件,定义有文件系统所需的数据结构 ff.c : 文件系统的具体实现

如下开始逐个文件加以分析: integer.h :仅实现数据类型重定义,增加系统的可移植性。 ffconf.h : 文件系统配置---逐个配置,先配置实现一个最小的fat文件系统,下面来分析各配置选项: #define _FFCONF 8255 //版本号 #define _FS_TINY 0 /* 0:Normal or 1:Tiny */ //在这里与先前版本有些许变化,是通过配置头配置两种不同大小的文件系统,这里配置为0。 #define _FS_READONLY 1//定义文件系统只读,也就不能写修改,在此定义为1,这样文件系统会大大缩小,简化学习理解过程。 #define _FS_MINIMIZE 3 /* 0 to 3 */ 这个选项是用于过滤掉一些文件系统功能,为0时是全功能,3是功能实现最小 #define _USE_STRFUNC 0 /* 0:Disable or 1/2:Enable */ 是否使用字符串文件接口,为0,不使用 #define _USE_MKFS 0 /* 0:Disable or 1:Enable */ 制作文件系统,这个功能实现是还要_FS_READONLY=0 #define _USE_FORWARD 0 /* 0:Disable or 1:Enable */ f_forward function 实现还需_FS_TINY =1 #define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */ 快速查找功 能 #define _CODE_PAGE 936 // 936 - Simplified Chinese GBK (DBCS, OEM, Windows) #define _USE_LFN 0/* 0 to 3 */ 0:不使用长文件名 #define _MAX_LFN 255/* Maximum LFN length to handle (12 to 255) */ #define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */

petit_fatfs文件系统移植

FatFS文件系统的优点我就不赘述了,我需要的功能不多,所以我移植是FatFS的精简版petit fatfs,现将我的一直步骤写下来供大家参考。工程暂不能分享,见谅。 1、移植的文件系统为petit fatfs R0.02。 下载地址:https://www.doczj.com/doc/5b1693642.html,/fsw/ff/pff2.zip 2、本人选用的单片机是STC12C5A56S2(容量够大)。 3、选用的SD卡为macro SD,容量512M,格式化为fat32文件系统,分配大小为512字节。 Petit fatfs文件系统的修改步骤及说明如下: 一、integer.h,pff.c,diskio.h这三个文件不需要修改。 二、pff.h的修改: 1、使能FAT32文件系统的支持#define_FS_FAT321 2、选择简体中文编码格式#define_CODE_PAGE936 三、diskio.c的修改: 1、添加必要头文件:reg51.h,sd.h,spi.h。 2、填写设备初始化函数DSTATUS disk_initialize(void) 这个函数我是参考别人写的: DSTATUS disk_initialize(void) { DSTATUS stat; //Put your code here stat=STA_NOINIT; if(!SD_Init()) { stat&=~STA_NOINIT; } return stat; } 3、填写读函数:DRESULT disk_readp(BYTE*dest,DWORD sector,WORD sofs,WORD count) 这个函数写法各异,就不具体说了, BYTE*dest这个就是指你要讲读出来的数据存在哪里的指针变量。 DWORD sector是要读扇区的地址,看一下SD卡的读写命令你就知道了。 WORD sofs是偏移量,简单就是说,要读的数据相对于扇区开始的字节数,这个读出来,直接忽略掉。 WORD count是要读的字节个数,读完偏移量的字节数,就是要读这个,将读出来的数据存在干才说的那个BYTE*dest。 最后还有一个剩余字节数即(512-sofs-count),这个也不是需要的数据,读出来忽略掉就行了。 4、我做的东西不需要向SD写入,所以disk_writep就没有动。 具体操作,以及在主函数中的调用可参考https://www.doczj.com/doc/5b1693642.html,/tlptotop/blog/item/21c30b2ae0c9a4f5e7cd40de.html

STM32学习笔记

STM32学习笔记——时钟频率 ******************************** 本学习笔记基于STM32固件库V3.0 使用芯片型号:STM32F103 开发环境:MDK ******************************** 第一课时钟频率 STM32F103内部8M的内部震荡,经过倍频后最高可以达到72M。目前TI的M3系列芯片最高频率可以达到80M。 在stm32固件库3.0中对时钟频率的选择进行了大大的简化,原先的一大堆操作都在后台进行。系统给出的函数为SystemInit()。但在调用前还需要进行一些宏定义的设置,具体的设置在system_stm32f10x.c文件中。 文件开头就有一个这样的定义: //#define SYSCLK_FREQ_HSE HSE_Value //#define SYSCLK_FREQ_20MHz 20000000 //#define SYSCLK_FREQ_36MHz 36000000 //#define SYSCLK_FREQ_48MHz 48000000 //#define SYSCLK_FREQ_56MHz 56000000 #define SYSCLK_FREQ_72MHz 72000000 ST 官方推荐的外接晶振是8M,所以库函数的设置都是假定你的硬件已经接了8M 晶振来运算的.以上东西就是默认晶振8M 的时候,推荐的CPU 频率选择.在这里选择了: #define SYSCLK_FREQ_72MHz 72000000 也就是103系列能跑到的最大值72M 然后这个C文件继续往下看 #elif defined SYSCLK_FREQ_72MHz const uint32_t SystemFrequency = SYSCLK_FREQ_72MHz; const uint32_t SystemFrequency_SysClk = SYSCLK_FREQ_72MHz; const uint32_t SystemFrequency_AHBClk = SYSCLK_FREQ_72MHz; const uint32_t SystemFrequency_APB1Clk = (SYSCLK_FREQ_72MHz/2); const uint32_t SystemFrequency_APB2Clk = SYSCLK_FREQ_72MHz; 这就是在定义了CPU跑72M的时候,各个系统的速度了.他们分别是:硬件频率,系统时 钟,AHB总线频率,APB1总线频率,APB2总线频率.再往下看,看到这个了: #elif defined SYSCLK_FREQ_72MHz static void SetSysClockTo72(void); 这就是定义72M 的时候,设置时钟的函数.这个函数被SetSysClock ()函数调用,而SetSysClock ()函数则是被SystemInit()函数调用.最后SystemInit()函数,就是被你调用的了

详细了解并学习FatFS文件系统的基本原理

详细了解并学习FatFS文件系统的基本原理 最近做的spi flash,本打算弄个文件系统,由于之前用过了JFFS、YAFFS和TrueFFS,代码量都相当的大,这次想找款代码量不那么吓人的,学习一下,听说配置会相对复杂一些。选来选去,最终选定了FatFS,代码量足够的小,最新的R0.09版本只有1个.c文件(当然,还有一个底层的要自己写,option文件夹里的无视),老点版本就更小了。而且更新很频繁,用户量也够大,就选定它了。尽管最后由于硬件和项目原因未能实际的移植它到vxWorks,但学过的还是要记录下。 在这里http://elm-chan/fsw/ff/00index_el下载源码,只有800多K,小的可怜,还可以下载示例程序,有A VR、Win32、lpc等多平台已实现的方案。打开看src文件夹,一个opTIon 文件夹、00readme.txt、diskio.h、ff.c、ff.h、ffconf.h和interger.h。移植时需要修改的文件主要包括ffconf.h和interger.h,后者是在它的定义与目标平台上的有冲突,或者用的不习惯时修改的。 在做具体修改之前,先大概阅读下FatFS的源代码,可以先读integer.h,了解所用的数据类型,然后是ff.h,了解文件系统所用的数据结构和各种函数声明,再就是diskio.h,了解与介质相关的数据结构和操作函数。ff.c这个文件相对较大,可以在最后将所实现的函数大致扫描一遍,之后根据用户应用层程序调用函数的次序仔细阅读相关代码。各个文件都可以直接用记事本打开查阅,非常方便。ff.h中的几个结构体十分重要,列举如下,首先是最基础的文件系统结构体: view plaincopy to clipboardprint? /* File system object structure (FATFS) */ typedef struct { BYTE fs_type; /* FAT子类型,一般在mount时用,置0表示未挂载*/ BYTE drv; /* 物理驱动号,一般为0*/ BYTE csize; /* 每个簇的扇区数目(1,2,4...128) */ BYTE n_fats; /* 文件分配表的数目(1,2) */

在STM32中移植FATFS文件系统

STM32的FATFS文件系统移植笔记 一、序言 经常在网上、群里看到很多人问关于STM32的FATFS文件系统移植的问题,刚好自己最近也在调试这个程序,为了让大家少走弯路,我把我的调试过程和方法也贡献给大家。 二、FATFS简介 FatFs Module是一种完全免费开源的FAT文件系统模块,专门为小型的嵌入式系统而设计。它完全用标准C语言编写,所以具有良好的硬件平台独立性,可以移植到8051、PIC、AVR、SH、Z80、H8、ARM等系列单片机上而只需做简单的修改。它支持FATl2、FATl6和FAT32,支持多个存储媒介;有独立的缓冲区,可以对多个文件进行读/写,并特别对8位单片机和16位单片机做了优化。 三、移植准备 1、FATFS源代码的获取,可以到官网下载:https://www.doczj.com/doc/5b1693642.html,/fsw/ff/00index_e.html最新版本是R0.09版本,我们就移植这个版本的。 2、解压文件会得到两个文件夹,一个是doc文件夹,这里是FATFS的一些使用文档和说明,以后在文件编程的时候可以查看该文档。另一个是src文件夹,里面就是我们所要的源文件。 3、建立一个STM32的工程,为方便调试,我们应重载printf()底层函数实现串口打印输出。可以参考已经建立好的printf()打印输出工程:.viewtool./bbs/foru ... d=77&extra=page%3D1 四、开始移植 1、在已经建立好的工程目录User文件夹下新建两个文件夹,FATFS_V0.09和 SPI_SD_Card,FATFS_V0.09用于存放FATFS源文件,SPI_SD_Card用于存放SPI的驱动文件。 2、如图1将ff.c添加到工程文件夹中,并新建diskio.c文件,在diskio.c文件中实现五个函数: 1.DSTATUS disk_initialize (BYTE);//SD卡的初始化 2. DSTATUS disk_status (BYTE);//获取SD卡的状态,这里可以不用管 3. DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);//从SD卡读取数据 4. DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);//将数据写入 SD卡,若该文件系统为只读文件系统则不用实现该函数 5. DRESULT disk_ioctl (BYTE, BYTE, void*);//获取SD卡文件系统相关信息 6. 复制代码

相关主题
文本预览
相关文档 最新文档