ijlc1314 发表于 2011-6-17 18:04:16

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)

huayuliang 发表于 2011-6-17 23:17:43

MMC。。用 winimage 弄。我发过一个帖子的。

aiqinger 发表于 2011-6-17 23:21:05

好资料

cargle 发表于 2011-6-17 23:30:22

mark

DoubleE 发表于 2011-6-20 10:03:00

ding

wangqh1983 发表于 2011-6-20 15:01:20

回复【楼主位】ijlc1314夜猫
-----------------------------------------------------------------------

mark

ijlc1314 发表于 2011-8-16 16:54:39

现在自己想做个小东西,不知道放到实际可行不?

well1122 发表于 2011-8-26 21:05:16

没入门,认为很强大

hubaixdl 发表于 2011-10-19 11:53:02

哪位大侠可以帮帮忙,用PROTEUS仿真,对MMC写入CMD25命令后,卡返回的值中不是0X00,但CMD24命令的返回却是正确的。两天没的搞定。
是MMC不支持CMD25吗?还是我的程序有问题?还是PROTEUS不支持?
点击此处下载 ourdev_686303SY4DX6.rar(文件大小:189K) (原文件名:lpc2131 proteus.rar)

-----------------------------------------------------------------------

raohao101 发表于 2011-10-24 21:03:37

mark,我也不知道,帮顶!

ijlc1314 发表于 2011-10-25 09:14:09

回复【8楼】hubaixdl
-----------------------------------------------------------------------

比较久了,我也忘了,不过MMC和SD记得是有个命令不一样的,你查查就知道了,可以参考上面的程序

hubaixdl 发表于 2011-11-1 18:01:15

回复【10楼】ijlc1314 夜猫
-----------------------------------------------------------------------

我查过楼主的程序,里面没有关于CM25的内容,后来只好用CMD24进行多次写。有兴趣的朋友可以看一下我的程序,点击此处下载 ourdev_690787Q353C2.rar(文件大小:1.20M) (原文件名:08B5.rar)

当我用硬件进行仿真时,可以对卡进行初始化,读0扇区的内容,前面部分只是00,后面的64个才可以读到正确的数,但是用PROTEUS进行仿真却没有问题。软件仿真用的是PROTEUS7.8,KEIL4.12.

ijlc1314 发表于 2011-11-2 13:37:24

回复【11楼】hubaixdl
-----------------------------------------------------------------------


仿真与实际应用总是有那么些差别,随着自己买的东西越来越多,也越来越不用仿真了

woshixinshou 发表于 2012-1-9 21:55:30

mark

zhengdf 发表于 2012-1-11 09:41:39

Mark

hlfqzy 发表于 2012-8-1 11:56:27

不错 谢谢

茅山小道士 发表于 2012-8-17 01:47:25

PROTEUS仿真,对MMC写入CMD25命令后,卡返回的值中不是0X00,我也遇到了这个问题,求解

glyhw 发表于 2014-5-11 13:32:37

hubaixdl 发表于 2011-10-19 11:53
哪位大侠可以帮帮忙,用PROTEUS仿真,对MMC写入CMD25命令后,卡返回的值中不是0X00,但CMD24命令的返回却是 ...

Proteus
多块写用CMD25 返回0x05不对呀,怎么都是0xFF

请教您怎么解决的?

glyhw 发表于 2014-5-11 18:40:10

Protwus 的MMC仿真到底能不能用CMD25多快写呀

glyhw 发表于 2014-5-11 18:41:21

楼主多快写CMD25 能不能用?

哈哈嘻嘻 发表于 2015-1-12 22:30:07

不错很是受启发

dgdzas 发表于 2015-2-26 09:10:43

学习了,不错。
页: [1]
查看完整版本: Proteus 仿真MMC成功,将图和全部程序贴上