[原创]
lm3s8962 FatFs文件系统移植步骤总结~~
学习完了8962文件系统的移植,现在对移植的步骤做一个详细的总结。
由于学习的SD文件系统移植的过程中,SD卡的通信模式是SPI模式,8962里SSI模块是兼容SPI模式的,所以,还需要先学习一下SSI模块的配置和操作。
一.Stellaris SSI模块具有以下特性:
■ 主机或从机操作
■ 时钟位速率和预分频可编程
■ 独立的发送和接收FIFO,16位宽,8个单元深。
■ Freescale SPI、MICROWIRE、或德州仪器同步串行接口的操作可编程
■ 数据帧大小可编程,范围为4~16位
■ 内部回送测试(loopback test)模式,可进行诊断/调试测试
二. FIFO操作
1.发送FIFO
通用发送FIFO是一个16位宽、8单元深、先进先出的存储缓冲区。CPU通过写SSI数据 (SSIDR)寄存器来将数据写入发送FIFO,数据在由发送逻辑读出之前一直保存在发送FIFO中。
当SSI配置为主机或从机时,并行数据在进行串行转换并通过SSITx管脚分别发送到相关的从机或主机之前先写入发送FIFO。
2 .接收 FIFO
通用接收FIFO是一个16位宽、8单元深、先进先出的存储缓冲区。从串行接口接收到的数据在由CPU读出之前一直保存在缓冲区中,CPU通过读SSIDR寄存器来访问读FIFO。
当SSI配置为主机或从机时,从SSIRx管脚接收到的串行数据在分别并行加载到相关的从机或主机接收FIFO之前先进行记录(registered)。
三. 中断
SSI可在出现下列情况时产生中断:
■ 发送FIFO服务
■ 接收FIFO服务
■ 接收FIFO超时
■ 接收FIFO溢出
所有中断事件在发送到中断控制器之前要先执行“或”操作,因此,在任何给定的时刻SSI只能向控制器发送一个中断请求。在4个可单独屏蔽的中断中,每个都可以通过置位SSI 中断屏蔽 (SSIIM)寄存器中适当的位来屏蔽。将适当的屏蔽位置1可使能中断。
SSI提供单独的输出和组合的中断输出,这样,允许使用全局中断服务程序或组合的器件驱动程序来处理中断。发送和接收动态数据流的中断与状态中断是分开的,因此,可以根据FIFO的触发深度trigger level)对数据执行读和写操作。各个中断源的状态可从SSI 原始中断状态(SSIRIS)和SSI屏蔽后的中断状态(SSIMIS)寄存器中读取。
四.初始化和配置
在使用SSI时,必须通过置位RCGC1寄存器的SSI位来使能SSI外设时钟。
针对不同的帧格式,SSI可通过以下步骤进行配置:
1. 确保在对任何配置进行更改之前先将SSICR1寄存器中的SSE位禁止。
2. 确定SSI为主机还是从机:
a. 作为主机时,将 SSICR1 寄存器的值设为0x0000.0000。
b. 作为从机时 (输出使能),将 SSICR1 寄存器的值设为0x0000.0004。
c. 作为从机时 (输出禁止),将 SSICR1寄存器的值设为 0x0000.000C。
3. 通过写SSICPSR寄存器来配置时钟预分频除数。
4. 写SSICR0寄存器,实现以下配置:
■ 串行时钟率 (SCR)
■ 如果使用Freescale SPI模式,则配置所需的时钟相位/极性(SPH和SPO)
■ 协议模式:Freescale SPI, TI SSF, MICROWIRE (FRF)
■ 数据长度 (DSS)
5. 通过置位SSICR1寄存器的SSE位来使能SSI。
举例:假定SSI的配置如下:
■ 主机操作
■ Freescale SPI模式 (SPO=1, SPH=1)
■ 1 Mbps位速率
■ 8个数据位
如果系统时钟为20MHz,则位速率的计算如下:
FSSIClk = FSysClk / (CPSDVSR * (1 + SCR))
1x106 = 20x106 / (CPSDVSR * (1 + SCR))
在此情况下,如果CPSDVSR=2,,SCR必须为9。
具体的配置序列如下:
1. 确保SSICR1寄存器的SSE位禁止。
2. 向 SSICR1 寄存器写入0x0000.0000。
3. 向 SSICPSR 寄存器写入0x0000.0002。
4. 向 SSICR0 寄存器写入0x0000.09C7。
5. 将SSICR1寄存器的SSE位置1来使能SSI。
好,开始操作系统了~~~
一. 移植效果
1. 可以通过“超级终端”等工具呈现命令界面,并传递命令。
2. 在命令界面中实现以下文件系统操作命令:
help : 显示所有命令
h :请求帮助
? : 请求帮助
ls : 显示文件列表
chdir: 更改目录
cd : 更改目录
pwd : 显示当前工作目录
cat : 显示一个文本文件的内容
fwrite:新建文件并写入
mkdir:在当前目录下创建目录
二. 移植条件
1. 可以识别参数的串口命令界面
2. Lm3s8962评估板
3. FatFs文件系统
三,对命令界面所实现功能的描述。
1. SSCOM3.2(作者:聂小猛(丁丁))终端工具设置。
首先打开串口终端,设置波特率115200,8位数据,无奇偶校验,无流控。串口号设置成板子在你电脑上的端口号(可以在设备管理器中查看,我的是COM10).
届时,开发板复位后,终端显示:
SD Card Example Program
Type 'help' for help.
/>
然后可以输入命令执行,比如输入help命令,则会显示命令界面当前支持的所有命令,并显示输入的参数。
2. 串口终端命令输入过程。
在串口终端输入一个字符时,其工作过程为:
void
UARTStdioIntHandler(void)
{
unsigned long ulInts;
char cChar;
long lChar;
static tBoolean bLastWasCR = false;
//获得并清除中断源
ulInts = MAP_UARTIntStatus(g_ulBase, true);
MAP_UARTIntClear(g_ulBase, ulInts);
//判断被中断的TX FIFO是否有可用空间。
if(ulInts & UART_INT_TX)
{
//尽可能多的把字符装入到发送FIFO中
UARTPrimeTransmit(g_ulBase);
//输出缓冲区为空,关闭发送中断
if(TX_BUFFER_EMPTY)
{
MAP_UARTIntDisable(g_ulBase, UART_INT_TX);
}
}
//是否被收到的字符中断?
if(ulInts & (UART_INT_RX | UART_INT_RT))
{
//从UART中获取所有有效字符
while(MAP_UARTCharsAvail(g_ulBase))
{
//抽口接收一个字符一个字符
lChar = MAP_UARTCharGetNonBlocking(g_ulBase);
cChar = (unsigned char)(lChar & 0xFF);
}
部分代码省略
}
}
串口接收到字符引起中断,然后调用函数MAP_UARTCharGetNonBlocking(g_ulBase);获取字符并放入串口消息队列。
四,移植前的准备
FatFs Module一开始就是为了能在不同的单片机上使用而设计的,所以具有良好的层次结构,如图1所示。最顶层是应用层,使用者无需理会FatFs Module的内部结构和复杂的FAT协议,只需要调用FatFs Module提供给用户的一系列应用接口函数,如f_open,f_read,f_write、f_close等,就可以像在PC上读/写文件那样简单。
中间层FatFs Module实现了FAT文件读/写协议。FatFs Module的完全版提供的是ff.c、ff.h,除非有必要,使用者一般不用修改,使用时将需要版本的头文件直接包含进去即可。
需要使用者编写移植代码的是FatFs Module提供的底层接口,它包括存储媒介读/写接口DiskIO和供给文件创建修改时间的实时时钟。在这里,编写的移植代码在文件mmc-ek-lm3s8962.c中。
[
本帖最后由 xielijuan 于 2010-11-28 22:38 编辑 ]
五,移植步骤。
第一步:SPI和相关I/O的初始化
8962中的SD卡的通信模式是SPI。这就需要8962提供SPI读/写接口代码,主要包括初始化、读和写。SPI初始化包括SPI相关寄存器的初始化和相关I/O口的初始化。例程中的代码代码包含在文件mmc-ek-lm3s8962.c里。SSI模块的配置在下面这个函数里:
这个函数并不是真的打开电源,而是初始化SSI端口和SD卡需要的引脚
static
void power_on (void)
{
//打开用于在SSI上驱动SD卡的外设,以及CS引脚
SysCtlPeripheralEnable(SDC_SSI_SYSCTL_PERIPH); //打开SSI端口
SysCtlPeripheralEnable(SDC_GPIO_SYSCTL_PERIPH); //打开GPIO A端口
// #define SDC_GPIO_SYSCTL_PERIPH SYSCTL_PERIPH_GPIOA
SysCtlPeripheralEnable(SDC_CS_GPIO_SYSCTL_PERIPH); //打开芯片片选择引脚CS
(GPIOG 0)
/* 对SSI进行一系列配置*/
GPIOPinTypeSSI(SDC_GPIO_PORT_BASE, SDC_SSI_PINS);
GPIOPadConfigSet(SDC_GPIO_PORT_BASE, SDC_SSI_PINS, GPIO_STRENGTH_4MA,
GPIO_PIN_TYPE_STD_WPU); //4毫安,上拉
GPIOPinTypeGPIOOutput(SDC_CS_GPIO_PORT_BASE, SDC_CS); //把PG0设置为输出
GPIOPadConfigSet(SDC_CS_GPIO_PORT_BASE, SDC_CS, GPIO_STRENGTH_4MA,
GPIO_PIN_TYPE_STD_WPU);
DESELECT(); //在mmc-ek-lm3s8962.c文件开头的时候定义了,这个函数的作用是
//取消对对SD卡的选中。操作是对PG0赋值1
/* 配置SSI0端口 */
SSIConfigSetExpClk(SDC_SSI_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
SSI_MODE_MASTER, 400000, 8);
SSIEnable(SDC_SSI_BASE);
/* Set DI and CS high and apply more than 74 pulses to SCLK for the card to be able to accept a native command. */
send_initial_clock_train();// 这个函数也是文件中定义的,大概是对时钟进行设置,没太看懂
PowerFlag = 1;
}
上面用到的自定义的函数,这里做一下解析,库函数的作用大家可以参照库函数表:
static
void SELECT(void)
{
GPIOPinWrite(SDC_CS_GPIO_PORT_BASE, SDC_CS, 0);
}
//宏定义里有这样的定义:
//#define SDC_CS_GPIO_PORT_BASE GPIO_PORTG_BASE //PG端口
//#define SDC_CS_GPIO_SYSCTL_PERIPH SYSCTL_PERIPH_GPIOG
//#define SDC_CS GPIO_PIN_0 //0号引脚
//而在原理图的第19页的表格,我们可以看到
//Pin 19 PG0 SD card chip select
//Pin 19 PG0 OLED display chip select
//这个Pin 19 PG0就是控制SD工作的开关,它但是他同时也OLED的使能引脚,所以,这两个模块不能同时工作。原理图如下:
static
void DESELECT(void)
{
GPIOPinWrite(SDC_CS_GPIO_PORT_BASE, SDC_CS, SDC_CS);
}
//这个函数的功能刚好上一个相反,是关闭的作用。
第二步.现在就可以进行读/写了。
//下面是一些变量的定义
static volatile
DSTATUS Stat = STA_NOINIT; /* 磁盘状态 */
static volatile
BYTE Timer1, Timer2; /* 100Hz 的递减计时器*/
static
BYTE CardType; /* b0: MMC(MultiMediaCard,多媒体存储卡), b1:SD卡控制, b2:块寻址,这个变量是存储卡的类型的变量 */
static
BYTE PowerFlag = 0; /*显示电源是否打开 */
通过sPI发送一个字节到存储卡
static
void xmit_spi(BYTE dat)
{
DWORD rcvdat;
SSIDataPut(SDC_SSI_BASE, dat); /* 将数据写入发送队列tx fifo */
SSIDataGet(SDC_SSI_BASE, &rcvdat); /* 写的时候刷新读取的数据 */
}
通过sPI从存储卡读取一个字节
static
BYTE rcvr_spi (void)
{
DWORD rcvdat;
SSIDataPut(SDC_SSI_BASE, 0xFF); /* 写入虚拟数据*/
SSIDataGet(SDC_SSI_BASE, &rcvdat); /*从接收队列 rx fifo读取数据 */
return (BYTE)rcvdat;
}
static
void rcvr_spi_m (BYTE *dst)
{
*dst = rcvr_spi();
}
[
本帖最后由 xielijuan 于 2010-11-28 22:42 编辑 ]
第三步.基本接口函数
在具备SPI读/写接口的基础上编写SD卡接口代码,需要编写3个基本接口函数:
① 向SD卡发送1条命令:
Static BYTE send_cmd (BYTE cmd, DWORD arg)②向SD卡发送1个数据包:
②向SD卡发送1个数据包:
Static BOOL xmit_datablock (const BYTE *buff, BYTE token)
③从SD卡接收1个数据包:
Static BOOL rcvr_datablock (BYTE *buff, UINT btr)
这三个函数,也是在这个文件中,具体怎么实现的这里简要说一下:
(1) 向SD卡发送1条命令:
static
BYTE send_cmd (
BYTE cmd, /* 命令字节 */
DWORD arg /* 参数*/
)
{
BYTE n, res;
if (wait_ready() != 0xFF) return 0xFF;
/* 发送命令包*/
xmit_spi(cmd); /* Command */
xmit_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
xmit_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
xmit_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
xmit_spi((BYTE)arg); /* Argument[7..0] */
n = 0;
if (cmd == CMD0) n = 0x95; /* CRC for CMD0(0) */
if (cmd == CMD8) n = 0x87; /* CRC for CMD8(0x1AA) */
xmit_spi(n);
/* 接收命令响应*/
if (cmd == CMD12) rcvr_spi(); /* 如果停止读写,跳过一个字节*/
n = 10; /*10次超时等待一个有效应答 */
do
res = rcvr_spi();
while ((res & 0x80) && --n);
return res; /*返回一个响应值 */
}
②向SD卡发送1个数据包:
static
BOOL xmit_datablock (
const BYTE *buff, /*被传送的512块数据块 */
BYTE token /* 数据/停止标记*/
)
{
BYTE resp, wc;
if (wait_ready() != 0xFF) return FALSE;
xmit_spi(token); /*传送数据标记 */
if (token != 0xFD) { /* 数据传送*/
wc = 0;
do { /* 传送512字节数据块给存储卡*/
xmit_spi(*buff++);
xmit_spi(*buff++);
} while (--wc);
xmit_spi(0xFF); /* 循环*/
xmit_spi(0xFF);
resp = rcvr_spi(); /* 接收一个响应数据 */
if ((resp & 0x1F) != 0x05) /*如果不接收,返回错误 */
return FALSE;
}
return TRUE;
}
③从SD卡接收1个数据包:
static
BOOL rcvr_datablock (
BYTE *buff, /* 数据缓冲器,用来存数接收到的数据*/
UINT btr /* 字节计数器*/
)
{
BYTE token;
Timer1 = 10;
do { /* 等待数据包*/
token = rcvr_spi();
} while ((token == 0xFF) && Timer1);
if(token != 0xFE) return FALSE; /* 如果不是有效的数据标记,返回错误*/
do { /* 接收数据块到缓冲器*/
rcvr_spi_m(buff++);
rcvr_spi_m(buff++);
} while (btr -= 2);
rcvr_spi(); /* 停止循环*/
rcvr_spi();
return TRUE; /* 返回成功 */
}
//下面是一个等待函数,等待卡准备好
static
BYTE wait_ready (void)
{
BYTE res;
Timer2 = 50; /*超时等待500ms*/
rcvr_spi();
do
res = rcvr_spi();
while ((res != 0xFF) && Timer2);
return res;
}
第四步. 编写DiskIO
编写好存储媒介的接口代码后,就可以编写DiskIO了,DiskIO结构如图所示。
FatFs的移植实际上需要编写7个接口函数,分别是:
(1)DSTATUS disk_initialize(BYTE drv);
存储媒介初始化函数。由于存储媒介是SD卡,所以实际上是对SD卡的初始化。drv是物理磁盘号码,由于FatFs只支持一个物理磁盘,所以drv应恒为O。执行无误返回0,错误返回非O。程序如下
DSTATUS disk_initialize (
BYTE drv /* 物理磁盘号*/
)
{
BYTE n, ty, ocr[4];
if (drv) return STA_NOINIT; /* 只支持一个磁盘*/
if (Stat & STA_NODISK) return Stat; /*插槽里没有磁盘 */
power_on(); /* 打开插槽电源*/
send_initial_clock_train();
[
本帖最后由 xielijuan 于 2010-11-28 22:48 编辑 ]
SELECT(); /* CS为低电平,代表选中了SD卡*/
ty = 0;
if (send_cmd(CMD0, 0) == 1) { /* 进入空闲状态 */
Timer1 = 100; /* 初始化超时 1000 msec */
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDC Ver2+ */
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /*这个卡可以工作在2.7-3.6范围 do {
if (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 1UL << 30) == 0) break; /* ACMD41 with HCS bit */
} while (Timer1);
if (Timer1 && send_cmd(CMD58, 0) == 0) { /* 检查CS位*/
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
ty = (ocr[0] & 0x40) ? 6 : 2;
}
}
} else { /* SDC Ver1 or MMC */
ty = (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 0) <= 1) ? 2 : 1; /* SDC : MMC */
do {
if (ty == 2) {
if (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 0) == 0) break; /* ACMD41 */
} else {
if (send_cmd(CMD1, 0) == 0) break; /* CMD1 */
}
} while (Timer1);
if (!Timer1 || send_cmd(CMD16, 512) != 0) /* 选择读写块长度 */
ty = 0;
}
}
CardType = ty;
DESELECT(); /* CS = H */
rcvr_spi(); /* Idle (Release DO) */
if (ty) { /*初始化成功*/
Stat &= ~STA_NOINIT; /* 清零STA_NOINIT */
set_max_speed();
} else { /*初始化失败,关闭电源 */
power_off();
}
return Stat;
}
(2)DSTATUS disk_status(BYTE drV);
状态检测函数。检测是否支持当前的存储媒介,对FatFs来说,只要drv为0,就认为支持,然后返回O。程序如下:
DSTATUS disk_status (
BYTE drv /* 物理磁盘号*/
)
{
if (drv) return STA_NOINIT; /* 只支持一个物理磁盘 */
return Stat;
}
(3)DRESULT disk_read(BYTE drv,BYTE*buff,DWORD sector,BYTE.count);
读扇区函数。在SD卡读接口函数的基础上编写,*buff存储已经读取的数据,sector是开始读的起始扇区,count是需要读的扇区数。1个扇区512个字节。执行无误返回O,错误返回非0。程序如下:
DRESULT disk_read (
BYTE drv, /* 物理磁盘号 */
BYTE *buff, /* 指向数据缓存的指针*/
DWORD sector, /* 起始扇区号(LBA) */
BYTE count /* 扇区计数器 (1..255) */
)
{
if (drv || !count) return RES_PARERR;
if (Stat & STA_NOINIT) return RES_NOTRDY;
if (!(CardType & 4)) sector *= 512; /* 如果需要,转换为地址字节*/
SELECT(); /* CS 为低电平,选择SD卡*/
if (count == 1) { /* 单块读取*/
if ((send_cmd(CMD17, sector) == 0)
&& rcvr_datablock(buff, 512))
count = 0;
}
else { /* 多块读取 */
if (send_cmd(CMD18, sector) == 0) {
do {
if (!rcvr_datablock(buff, 512)) break;
buff += 512;
} while (--count);
send_cmd(CMD12, 0); /* 停止传送*/
}
}
DESELECT(); /* CS 为高电平,没有选中SD卡 */
rcvr_spi(); /* Idle (Release DO) */
return count ? RES_ERROR : RES_OK;
}
(4)DRESULT disk_write(BYTE drv,const BYTE*buff,DWORD sector,BYTE count);
写扇区函数。在SD卡写接口函数的基础上编写,*buff存储要写入的数据,sector是开始写的起始扇区count是需要写的扇区数。1个扇区512个字节。执行无误返回O,错误返回非0。
DRESULT disk_write (
BYTE drv, /* 物理磁盘号 */
const BYTE *buff, /* 指向数据缓存的指针*/
DWORD sector, /* 起始扇区号(LBA) */
BYTE count /* 扇区计数器 (1..255) */
)
{
if (drv || !count) return RES_PARERR;
if (Stat & STA_NOINIT) return RES_NOTRDY;
if (Stat & STA_PROTECT) return RES_WRPRT;
if (!(CardType & 4)) sector *= 512; /* 如果需要,转换为地址字节*/
SELECT(); /*CS为低,选中 */
if (count == 1) { /* 单块写*/
if ((send_cmd(CMD24, sector) == 0)
&& xmit_datablock(buff, 0xFE))
count = 0;
}
else { /* 多快写 */
if (CardType & 2) {
send_cmd(CMD55, 0); send_cmd(CMD23, count); /* ACMD23 */
}
if (send_cmd(CMD25, sector) == 0) {
do {
if (!xmit_datablock(buff, 0xFC)) break;
buff += 512;
} while (--count);
if (!xmit_datablock(0, 0xFD)) /*停止传送标记 */
count = 1;
}
}
DESELECT(); /* CS置位 */
rcvr_spi(); /* Idle (Release DO) */
return count ? RES_ERROR : RES_OK;
}
(5)DRESULT disk_ioctl(BYTE drv,BYTE ctrl,VoiI*buff);
存储媒介控制函数。ctrl是控制代码,*buff存储或接收控制数据。可以在此函数里编写自己需要的功能代码,比如获得存储媒介的大小、检测存储媒介的上电与否存储媒介的扇区数等。如果是简单的应用,也可以不用编写,返回O即可。
DRESULT disk_ioctl (
BYTE drv, /* 物理磁盘号*/
BYTE ctrl, /*控制代码 */
void *buff /* 发送接收的控制数据缓冲区*/
)
{
DRESULT res;
BYTE n, csd[16], *ptr = buff;
WORD csize;
if (drv) return RES_PARERR;
res = RES_ERROR;
if (ctrl == CTRL_POWER) {
switch (*ptr) {
case 0: /*子控制代码=0 (关闭) */
if (chk_power())
power_off(); /* Power off */
res = RES_OK;
break;
case 1: /*子控制代码=1 (开启)*/
power_on(); /* Power on */
res = RES_OK;
break;
case 2: /*子控制代码=2 (power get)*/
*(ptr+1) = (BYTE)chk_power();
res = RES_OK;
break;
default :
res = RES_PARERR;
}
}
else {
if (Stat & STA_NOINIT) return RES_NOTRDY;
SELECT(); /* CS = L */
switch (ctrl) {
case GET_SECTOR_COUNT : /* 获取磁盘扇区数*/
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
csize = csd[9] + ((WORD)csd[8] << 8) + 1;
*(DWORD*)buff = (DWORD)csize << 10;
} else { /* MMC or SDC ver 1.XX */
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
*(DWORD*)buff = (DWORD)csize << (n - 9);
}
res = RES_OK;
}
break;
case GET_SECTOR_SIZE : /*获取磁盘扇区大小 */
*(WORD*)buff = 512;
res = RES_OK;
break;
case CTRL_SYNC : /*确定数据被写入 */
if (wait_ready() == 0xFF)
res = RES_OK;
break;
case MMC_GET_CSD : /* 接收 CSD 作为数据块(16 bytes) */
if (send_cmd(CMD9, 0) == 0 /* READ_CSD */
&& rcvr_datablock(ptr, 16))
res = RES_OK;
break;
case MMC_GET_CID : /*接收CID 作为数据块 (16 bytes) */
if (send_cmd(CMD10, 0) == 0 /* READ_CID */
&& rcvr_datablock(ptr, 16))
res = RES_OK;
break;
case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */
if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
for (n = 0; n < 4; n++)
*ptr++ = rcvr_spi();
res = RES_OK;
}
// case MMC_GET_TYPE : /*获取卡类型的标记 (1 byte) */
// *ptr = CardType;
// res = RES_OK;
// break;
default:
res = RES_PARERR;
}
DESELECT(); /* CS = H */
rcvr_spi(); /* Idle (Release DO) */
}
return res;
}
(6) disk_timerproc (void)
设备时钟中断程序。
void disk_timerproc (void)
{
// BYTE n, s;
BYTE n;
n = Timer1; /* 100Hz递减计时器 */
if (n) Timer1 = --n;
n = Timer2;
if (n) Timer2 = --n;
}
(7)DWORD get_fattime(Void);
实时时钟函数。返回一个32位无符号整数,时钟信息包含在这32位中,如下所示:
bit31:25 年(O..127)从1980年到现在的年数
bit24:21 月(1…12)
bit20:16 日(1..31)
bitl5.1] 时(O..23)
bitl0:5 分(O..59)
bit4:0 秒/2(0..29)
如果用不到实时时钟,也可以简单地返回一个数。正确编写完DiskIO,移植工作也就基本完成了。
DWORD get_fattime (void)
{
return ((2007UL-1980) << 25) // Year = 2007
| (6UL << 21) // Month = June
| (5UL << 16) // Day = 5
| (11U << 11) // Hour = 11
| (38U << 5) // Min = 38
| (0U >> 1) // Sec = 0
;
}
第五步,接下来的工作就是对FatFs进行配置。
atFs是一款可配置可裁减的文件系统,使用者可以选择自己需要的功能。FatFs总共有5个文件,分别是ff.c、ff.h、diskio.c、diskio.h和integer.h。ff_c和integer.h一般不用改动,前面的移植工作主要更改的是diskio.c,而配置FatFs则主要修改ff.h和diskio.h。
在diskio.h中,使用者可以根据需要使能disk—write或disk_ioetl。例如diskio.h中以下代码使能disk_write
#define _READONLY 0 /* 1: Read-only mode */
在ff.h中,使用者可以根据需要对整个文件系统进行全面的配置:
① #define_MCU_ENDIAN。有1和2两个值可设,默认情况下设1,以获得较好的系统性能。如果单片机是大端模式或者设为1时系统运行不正常,则必须设为2。
② #define_FS_READONLY。设为1时将使能只读操作,程序编译时将文件系统中涉及写的操作全部去掉,以节省空间。
③#define_FS_MINIMIZE。有0、1、2、3四个选项可设。设0表示可以使用全部Tiny-FatFs提供的用户函数;设1将禁用f_stat、f_getfree、f_unlink、f_mkdir、f_chmod和f_rename;设2将在1的基础上禁用f_opendir和f_readdir;设3将在1和2的基础上再禁用f_lseek。使用者可以根据需要进行裁减,以节省空间。
其关于ff.h的解读,我在学习文件系统的时候已经做过了解,也写成了心得。
到这里,文件系统的移植就基本完成了~然后就可以编写自己的程序了,关于SD应用程序的编写,之前已经总结过了~~接下来,就是学习VS1003了~~
顶。。。mark....
我也用的8962进行的这个文件系统的移植 。。不知你是否已经进行了JPEG的解码和EBOOK功能的扩展。。。我正在进行JPEG/JPG图片的解码。希望多多交流 。。。。。。
这篇文章很不错啊,支持,我也正在使用,希望能多交流!
回复 13楼 shilaike 的帖子
呵呵~谢谢~~还没有呢;P 因为我申请的任务事做一个MP3,所以,下一步得先学习扩展芯片解码音频文件,共同学习~~~
回复 14楼 zhstars 的帖子
谢谢~~
,新手新手,多多交流~~~
回复 15楼 0212009623 的帖子
;P 谢~~~顶~~~