|
刚刚学ARM7,正好想一下SD卡,用的是Proteus里面的MMC卡,使用的只是单一的对扇区的读写操作,还不懂得文件系统
驱动用的SPI,好奇怪,刚开始的时候用SPI根本就行,然后转用软件模拟的SPI却又行,最后再做一些调整后和参考别人的一些程序,硬件的SPI也就可以了
看看图片
(原文件名:液晶显示.jpg)
由于不知道里面的MMC文件要怎么生成,所以是用的记事本“另存为……”的方法做的
(原文件名:MMC.jpg)
仿真时的效果
(原文件名:效果.jpg)
下面是SPI方式操作MMC卡的程序:
#include "INCLUDES.h"
/*****************************************************
SPI方式读取MMC(SD)卡
*****************************************************/
typedef struct
{
uint16 size_m;
uint8 sector_multiply;
uint16 sector_count;
uint8 mmcname[6];
} MMC_INFO;
#define MMC_CMD_ERROR 'A'
#define MMC_DATA_ERROR 'B'
#define DELAY 500
#define SCK_1 IO0SET=( 1<<4 )
#define SCK_0 IO0CLR=( 1<<4 )
#define MOSI_1 IO0SET=( 1<<6 )
#define MOSI_0 IO0CLR=( 1<<6 )
#define CS_1 IO0SET=( 1<<8 )
#define CS_0 IO0CLR=( 1<<8 )
#define MISO 5
/*
**SPI初始化
*/
void SPIInit( void )
{
PINSEL0 &= 0xFFFF00FF;
PINSEL0 |= ( 1<<(4*2) ) //P0.4设为SPI 时钟引脚
|( 1<<(5*2) ) //P0.5设为SPI 数据输入引脚
|( 1<<(6*2) ) //P0.6设为SPI 数据输出引脚
|( 1<<(7*2) );
PINSEL0 &= 0xFFFCFFFF;
IO0DIR |= ( 1<<8 );
IO0DIR &= ~( 1<<5 );
IO0SET = ( 1<<8 );
CS_1;
S0SPCCR = 254;
S0SPCR = 0x20;
}
/*
**SPI读取数据
*/
uint8 SPI_WR( uint8 data )
{
S0SPDR = data;
while ( 0 == ( S0SPSR & 0x80 ) );
return ( S0SPDR );
}
/*
**SPI发送串数据
*/
void SPI_Send( const uint8 *pdata,
uint16 Length )
{
uint16 i;
for ( i = 0; i < Length; i++ )
{
SPI_WR( *pdata++ );
}
}
/*
**SPI接收串数据
*/
void SPI_Receive( uint8 *buffer,
uint16 Length )
{
uint16 i;
for ( i = 0; i < Length; i++ )
{
*buffer = SPI_WR( 0xff );
buffer++;
}
return ;
}
/*
**SPI接收一个字节的数据
*/
uint8 SPI_ReceiveByte( void )
{
uint8 data;
data = SPI_WR( 0xff );
return ( data );
}
/*
**MMC应答
*/
uint8 MMC_Response( uint8 response )
{
uint16 count;
count = 0xff;
while ( (SPI_ReceiveByte() != response) && count )
{
count--;
}
if ( count )
{
return 0;
}
else
{
return 1;
}
}
/*
**MMC等待写完成
*/
uint8 MMC_Wait_Finish( void )
{
uint16 count;
uint8 temp;
count = 0xffff;
temp = 0;
while ( (temp == 0) && count )
{
temp = SPI_ReceiveByte();
count--;
}
if ( count )
{
return 0;
}
else
{
return 1;
}
}
/*
**MMC初始化
*/
uint8 MMCInit( void )
{
uint16 i;
uint8 mmccmd[6];
uint8 MMCStatus;
MMCStatus = 0; //初始化状态为0
CS_1; //禁止MMC卡
for ( i = 0; i < 512; i++ )
{
MMCWRData = i;
MMCRDData = ~i;
}
for ( i = 0; i < 10; i++ )
{
MMCRDData = 0xff;
}
SPI_Send( MMCRDData, 10 ); //80个时钟信号
mmccmd[0] = 0x40; //复位命令
mmccmd[1] = 0x00;
mmccmd[2] = 0x00;
mmccmd[3] = 0x00;
mmccmd[4] = 0x00;
mmccmd[5] = 0x95;
CS_0; //使能MMC卡
SPI_Send( mmccmd, 6 ); //发送复位命令
if ( MMC_Response( 0x01 ) ) //判断是否超时
{
MMCStatus = 1;
CS_1;
return MMCStatus; //返回错误代码
}
CS_1; //禁止MMC卡
SPI_ReceiveByte(); //八个时钟信号
LCDDisCharStr( 0,0,"Reset Succeed" );
mmccmd[0] = 0x41; //进入SPI模式命令
mmccmd[1] = 0x00;
mmccmd[2] = 0x00;
mmccmd[3] = 0x00;
mmccmd[4] = 0x00;
mmccmd[5] = 0xff;
i = 0xff;
CS_0; //使能MMC卡
do{
SPI_Send( mmccmd, 6 ); //走入SPI模式的命令
i--;
}while( MMC_Response( 0x00 ) && i );
if ( i == 0 ) //判断进入SPI是否成功
{
MMCStatus = 1;
CS_1;
return MMCStatus; //返回错误代码
}
CS_1;
SPI_ReceiveByte(); //八个时钟信号
LCDDisCharStr( 1,0,"SPI Mode Succeed" );
mmccmd[0] = 0x41; //设置块大小的命令
mmccmd[1] = 0x00;
mmccmd[2] = 0x00;
mmccmd[3] = 0x02; //设置为512 bytes
mmccmd[4] = 0x00;
mmccmd[5] = 0xff;
CS_0;
SPI_Send( mmccmd, 6 ); //发送命令,设置块大小为512字节
if ( MMC_Response( 0x00 ) )
{
MMCStatus = 1;
CS_1;
return MMCStatus;
}
CS_1;
SPI_ReceiveByte();
LCDDisCharStr( 2, 0, "Block Set 512 Bytes Succeed" );
S0SPCCR = 8; //让SPI走入高速模式
return 0; //返回0,操作成功
}
/*
**读取MMC卡上CID信息
*/
uint8 MMC_Read_CID( uint8 *RegData )
{
uint8 temp;
uint8 mmccmd[]={0x4a,0x00,0x00,
0x00,0x00,0xff};
temp = MMC_Read_Register( mmccmd, RegData, 16 );
return temp;
}
/*
**读取MMC卡的CSD信息
*/
uint8 MMC_Read_CSD( uint8 *RegData )
{
uint8 temp;
uint8 mmccmd[]={0x49,0x00,0x00,
0x00,0x00,0xff};
temp = MMC_Read_Register( mmccmd, RegData, 16 );
return temp;
}
/*
**读取MMC卡寄存器的信息
*/
uint8 MMC_Read_Register( uint8 *pcmd, //读取相应寄存器的命令
uint8 *data, //寄存器信息的存放
uint8 Length ) //要读取的信息的字节长度
{
uint8 MMCStatus;
MMCStatus = 0;
CS_0;
SPI_Send( pcmd, 6 ); //发送读取的命令
if ( MMC_Response( 0x00 ) )
{
MMCStatus = 1; //命令写入失败
CS_1;
return MMCStatus;
}
if ( MMC_Response( 0xfe ) ) //判断是否返回令牌0xfe
{
MMCStatus = 1;
CS_1;
return MMCStatus;
}
SPI_Receive( data, Length );
CS_1;
SPI_ReceiveByte();
return 0; //返回0,说明读取成功
}
/*
**读取MMC卡的信息
*/
void MMC_Information( void )
{
uint8 temp;
uint8 buffer[17];
uint8 table[6];
MMC_INFO mmc_information;
MMC_INFO *mmc;
mmc = &mmc_information;
temp = MMC_Read_CSD( buffer );
if ( temp )
{
LCDDisCharStr( 3, 0 , "Read MMC Information Fail" );
return ;
}
mmc->sector_count = buffer[6] & 0x03; //获取扇区的总数
mmc->sector_count <<= 8;
mmc->sector_count += buffer[7];
mmc->sector_count <<= 2;
mmc->sector_count += (buffer[8] & 0xc0) >> 6;
table[5] = '\0';
table[4] = mmc->sector_count % 10 + 1 + '0';
table[3] = mmc->sector_count / 10 % 10 + '0';
table[2] = mmc->sector_count /100 % 10 + '0';
table[1] = mmc->sector_count / 1000 % 10 + '0';
table[0] = mmc->sector_count / 10000 % 10 + '0';
LCDDisCharStr( 3, 0, "Section:" );
LCDDisCharStr( 3, 8, table );
mmc->sector_multiply = buffer[9] & 0x03; //获取层数
mmc->sector_multiply <<= 1;
mmc->sector_multiply += ( buffer[10] & 0x80 ) >> 7;
//获取MMC的容量
mmc->size_m = mmc->sector_count >> ( 9 - mmc->sector_multiply );
table[5] = '\0';
table[4] = mmc->size_m % 10 + 1 + '0';
table[3] = mmc->size_m / 10 % 10 + '0';
table[2] = mmc->size_m /100 % 10 + '0';
table[1] = mmc->size_m / 1000 % 10 + '0';
table[0] = mmc->size_m / 10000 % 10 + '0';
LCDDisCharStr( 4, 0, "MMC Size:" );
LCDDisCharStr( 4, 9, table );
LCDDisCharStr( 4, 14, "M" );
}
/*
**读取一个扇区的内容
*/
uint8 MMC_Read_Block( uint16 Address )
{
uint16 CheckSum;
uint16 addh;
uint16 addl;
uint8 MMCStatus;
uint8 mmccmd[6];
addl = ( (Address & 0x003F) << 9 );
addh = ( (Address & 0xFFC0) >> 7 );
mmccmd[0] = 0x51;
mmccmd[1] = addh >> 8;
mmccmd[2] = addh;
mmccmd[3] = addl >> 8;
mmccmd[4] = addl;
mmccmd[5] = 0xff;
CS_0;
SPI_Send( mmccmd, 6 );
if ( MMC_Response( 0x00 ) ) //等待MMC的回应
{
MMCStatus = 1;
CS_1;
return MMCStatus;
}
if ( MMC_Response( 0xfe ) ) //等待令牌信息
{
MMCStatus = 1;
CS_1;
return MMCStatus;
}
SPI_Receive( MMCRDData, 512 ); //读取512字节的数据
CheckSum = SPI_ReceiveByte();
CheckSum = (CheckSum<<8) | SPI_ReceiveByte();
CS_1;
SPI_ReceiveByte();
return 0;
}
/*
**写一个扇区的内容
*/
uint8 MMC_Write_Block( uint16 Address )
{
uint16 addh;
uint16 addl;
uint8 MMCStatus;
uint8 mmccmd[6];
addl=( (Address & 0x003F) << 9 );
addh=( (Address & 0xFFC0) >> 7 );
mmccmd[0] = 0x58;
mmccmd[1] = addh >> 8;
mmccmd[2] = addh;
mmccmd[3] = addl >> 8;
mmccmd[4] = addl;
mmccmd[5] = 0xff;
CS_0;
SPI_Send( mmccmd, 6 ); //写命令
if ( MMC_Response( 0x00 ) ) //等待回应
{
MMCStatus = 1;
CS_1;
return MMCStatus;
}
mmccmd[0] = 0xfe;
SPI_Send( mmccmd, 1 ); //写令牌
SPI_Send( MMCWRData, 512 ); //写512字节到MMC
mmccmd[0] = 0xff; //CRC7用
mmccmd[0] = 0xff;
SPI_Send( mmccmd, 2 );
MMCStatus = SPI_ReceiveByte();
if ( ( MMCStatus & 0x0f ) != 0x05 )
{
MMCStatus = 1;
CS_1;
return MMCStatus;
}
if ( MMC_Wait_Finish() )
{
MMCStatus = 1;
CS_1;
return MMCStatus;
}
CS_1;
SPI_ReceiveByte();
return 0;
}
这个是串口程序
#include "INCLUDES.h"
/************************************************
串口0初始化
波特率:57600
************************************************/
void UARTInit( void )
{
PINSEL0 &= 0xfffffff5;
PINSEL0 |= 0x00000005;
// IO0DIR &= 0xfffffffe;
U0LCR = 0x83;
// U0DLM = ( ( 44236800/16 ) / 57600 ) / 256;
// U0DLL = ( ( 44236800/16 ) / 57600 ) % 256;
// U0DLM = 0x00;
U0DLL = 60;
U0LCR = 0x03;
}
/************************************************
串口发送数据给PC
************************************************/
void UartSend( const uint8 *pchar )
{
while ( *pchar != '\0' )
{
U0THR = *pchar++;
while ( ( U0LSR & 0x40 ) == 0 )
{
}
}
}
/************************************************
串口发送非常量
************************************************/
void UartPrintf( uint8 *pchar,
uint16 Length )
{
while ( Length-- )
{
U0THR = *pchar++;
while ( ( U0LSR & 0x40 ) == 0 )
{
}
}
}
单片机用的是LPC2124
(原文件名:接口.jpg) |
阿莫论坛20周年了!感谢大家的支持与爱护!!
你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。
|