Proteus 仿真MMC成功,将图和全部程序贴上
刚刚学ARM7,正好想一下SD卡,用的是Proteus里面的MMC卡,使用的只是单一的对扇区的读写操作,还不懂得文件系统驱动用的SPI,好奇怪,刚开始的时候用SPI根本就行,然后转用软件模拟的SPI却又行,最后再做一些调整后和参考别人的一些程序,硬件的SPI也就可以了
看看图片
http://cache.amobbs.com/bbs_upload782111/files_41/ourdev_649772DE8A57.jpg
(原文件名:液晶显示.jpg)
由于不知道里面的MMC文件要怎么生成,所以是用的记事本“另存为……”的方法做的
http://cache.amobbs.com/bbs_upload782111/files_41/ourdev_649774LRVPWL.jpg
(原文件名:MMC.jpg)
仿真时的效果
http://cache.amobbs.com/bbs_upload782111/files_41/ourdev_649775Z0O45J.jpg
(原文件名:效果.jpg)
下面是SPI方式操作MMC卡的程序:
#include "INCLUDES.h"
/*****************************************************
SPI方式读取MMC(SD)卡
*****************************************************/
typedef struct
{
uint16 size_m;
uint8 sector_multiply;
uint16 sector_count;
uint8 mmcname;
} 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;
uint8temp;
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;
uint8mmccmd;
uint8MMCStatus;
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 = 0x40; //复位命令
mmccmd = 0x00;
mmccmd = 0x00;
mmccmd = 0x00;
mmccmd = 0x00;
mmccmd = 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 = 0x41; //进入SPI模式命令
mmccmd = 0x00;
mmccmd = 0x00;
mmccmd = 0x00;
mmccmd = 0x00;
mmccmd = 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 = 0x41; //设置块大小的命令
mmccmd = 0x00;
mmccmd = 0x00;
mmccmd = 0x02; //设置为512 bytes
mmccmd = 0x00;
mmccmd = 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;
uint8 table;
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 & 0x03; //获取扇区的总数
mmc->sector_count<<= 8;
mmc->sector_count += buffer;
mmc->sector_count<<= 2;
mmc->sector_count += (buffer & 0xc0) >> 6;
table = '\0';
table = mmc->sector_count % 10 + 1 + '0';
table = mmc->sector_count / 10% 10 + '0';
table = mmc->sector_count /100 % 10 + '0';
table = mmc->sector_count / 1000 % 10 + '0';
table = mmc->sector_count / 10000 % 10 + '0';
LCDDisCharStr( 3, 0, "Section:" );
LCDDisCharStr( 3, 8, table );
mmc->sector_multiply = buffer & 0x03; //获取层数
mmc->sector_multiply <<= 1;
mmc->sector_multiply += ( buffer & 0x80 ) >> 7;
//获取MMC的容量
mmc->size_m = mmc->sector_count >> ( 9 - mmc->sector_multiply );
table = '\0';
table = mmc->size_m % 10 + 1 + '0';
table = mmc->size_m / 10% 10 + '0';
table = mmc->size_m /100 % 10 + '0';
table = mmc->size_m / 1000 % 10 + '0';
table = 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;
uint8MMCStatus;
uint8mmccmd;
addl = ( (Address & 0x003F) << 9 );
addh = ( (Address & 0xFFC0) >> 7 );
mmccmd = 0x51;
mmccmd = addh >> 8;
mmccmd = addh;
mmccmd = addl >> 8;
mmccmd = addl;
mmccmd = 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;
uint8MMCStatus;
uint8mmccmd;
addl=( (Address & 0x003F) << 9 );
addh=( (Address & 0xFFC0) >> 7 );
mmccmd = 0x58;
mmccmd = addh >> 8;
mmccmd = addh;
mmccmd = addl >> 8;
mmccmd = addl;
mmccmd = 0xff;
CS_0;
SPI_Send( mmccmd, 6 ); //写命令
if ( MMC_Response( 0x00 ) ) //等待回应
{
MMCStatus = 1;
CS_1;
return MMCStatus;
}
mmccmd = 0xfe;
SPI_Send( mmccmd, 1 ); //写令牌
SPI_Send( MMCWRData, 512 ); //写512字节到MMC
mmccmd = 0xff; //CRC7用
mmccmd = 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
http://cache.amobbs.com/bbs_upload782111/files_41/ourdev_649776CLL43T.jpg
(原文件名:接口.jpg) MMC。。用 winimage 弄。我发过一个帖子的。 好资料 mark ding 回复【楼主位】ijlc1314夜猫
-----------------------------------------------------------------------
mark 现在自己想做个小东西,不知道放到实际可行不? 没入门,认为很强大 哪位大侠可以帮帮忙,用PROTEUS仿真,对MMC写入CMD25命令后,卡返回的值中不是0X00,但CMD24命令的返回却是正确的。两天没的搞定。
是MMC不支持CMD25吗?还是我的程序有问题?还是PROTEUS不支持?
点击此处下载 ourdev_686303SY4DX6.rar(文件大小:189K) (原文件名:lpc2131 proteus.rar)
----------------------------------------------------------------------- mark,我也不知道,帮顶! 回复【8楼】hubaixdl
-----------------------------------------------------------------------
比较久了,我也忘了,不过MMC和SD记得是有个命令不一样的,你查查就知道了,可以参考上面的程序 回复【10楼】ijlc1314 夜猫
-----------------------------------------------------------------------
我查过楼主的程序,里面没有关于CM25的内容,后来只好用CMD24进行多次写。有兴趣的朋友可以看一下我的程序,点击此处下载 ourdev_690787Q353C2.rar(文件大小:1.20M) (原文件名:08B5.rar)
当我用硬件进行仿真时,可以对卡进行初始化,读0扇区的内容,前面部分只是00,后面的64个才可以读到正确的数,但是用PROTEUS进行仿真却没有问题。软件仿真用的是PROTEUS7.8,KEIL4.12. 回复【11楼】hubaixdl
-----------------------------------------------------------------------
仿真与实际应用总是有那么些差别,随着自己买的东西越来越多,也越来越不用仿真了 mark Mark 不错 谢谢 PROTEUS仿真,对MMC写入CMD25命令后,卡返回的值中不是0X00,我也遇到了这个问题,求解 hubaixdl 发表于 2011-10-19 11:53
哪位大侠可以帮帮忙,用PROTEUS仿真,对MMC写入CMD25命令后,卡返回的值中不是0X00,但CMD24命令的返回却是 ...
Proteus
多块写用CMD25 返回0x05不对呀,怎么都是0xFF
请教您怎么解决的? Protwus 的MMC仿真到底能不能用CMD25多快写呀 楼主多快写CMD25 能不能用? 不错很是受启发 学习了,不错。
页:
[1]