⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmc.c

📁 这是一个MSP430单片机的MMC卡的读写程序。略作修改就可以用到别的型号MCU上。
💻 C
字号:

#include  <MSP430x16x.h>
#include "mmc.h"

//函数定义
void CS_LOW(void);
void CS_HIGH(void);
char mmcGetResponse(void);
char mmcGetXXResponse(const char resp);
char mmcCheckBusy(void);
void initSPI (void);
unsigned char spiSendByte(const unsigned char data);
char mmc_GoIdle();

// 全局变量
char mmc_buffer[512] = { 0 };

void CS_LOW(void)
{
    P5OUT &= ~0x10;
    return;
}
void CS_HIGH(void)
{
    P5OUT |= 0x10;
    return;
}
void initSPI (void)
{
    //8位SPI主模式
    UCTL1 = SWRST;
    //时钟源为SMCLK,3线模式,上升沿数据有效
    UTCTL1 = CKPH | SSEL1 | SSEL0 | STC;
    //设置时钟频率,0x02: UCLK/2 (4 MHz)
    UBR01 = 0x02; 
    UBR11 = 0x00;   
    //没有调整
    UMCTL1 = 0x00; 
    //8位SPI主模式
    UCTL1 = CHAR | SYNC | MM | SWRST;
    //清除SWRST
    UCTL1 &= ~SWRST;
    //使能USART1的SPI模式
    ME2 |= USPIE1;  
    //清除发送中断标志
    while (!(IFG2 & UTXIFG1)); 
}

char initMMC (void)
{
    int i;
  
    //P5.1,P5.2,P5.3设置为SPI管脚
    P5SEL |= 0x0E;
    P5SEL &= ~0x11;
    //P5.4输出高电平
    P5OUT |= 0x10;
    //P5.1,P5.3,P5.4为输出方向
    P5DIR |= 0x1A;
  
    //初始化SPI
    initSPI();
    
    //CS为高电平
    CS_HIGH();
    for(i = 0;i <= 9;i++)
    {
        spiSendByte(0xff);
    }
    //发送复位信号
    return (mmc_GoIdle());
}


char mmc_GoIdle()
{
    char response=0x01;
    CS_LOW();
    //发送复位命令,将MMC卡设置为SPI模式
    mmcSendCmd(MMC_GO_IDLE_STATE,0,0x95);
    //等待响应
    if(mmcGetResponse()!=0x01) return MMC_INIT_ERROR;
  
    while(response == 0x01)
    {
        CS_HIGH();
        spiSendByte(0xff);
        CS_LOW();
        mmcSendCmd(MMC_SEND_OP_COND,0x00,0xff);
        response=mmcGetResponse();
    }
    CS_HIGH();
    spiSendByte(0xff);
    return (MMC_SUCCESS);
}

char mmcGetResponse(void)
{
    int i=0;
  
    char response;
    while(i <= 64)
    {
        //读取响应数据
        response=spiSendByte(0xff);
        if(response == 0x00)break;
        if(response == 0x01)break;
        i++;
    }
    return response;
}

char mmcGetXXResponse(const char resp)
{
    int i=0;
  
    char response;
    while(i<=1000)
    {
        //读取响应数据
        response=spiSendByte(0xff);
        //响应一致时,退出
        if(response == resp) break;
        i++;
    }
    return response;
}
char mmcCheckBusy(void)
{
    int i=0;
  
    char response;
    char rvalue;
    while(i <= 64)
    {
        response = spiSendByte(0xff);
        response &= 0x1f;
        switch(response)
        {
          case 0x05: 
            {
                rvalue = MMC_SUCCESS;
                break;
            }
          case 0x0b: return(MMC_CRC_ERROR);
          case 0x0d: return(MMC_WRITE_ERROR);
          default:
            rvalue = MMC_OTHER_ERROR;
            break;
        }
        if(rvalue == MMC_SUCCESS) break;
        i++;
    }
    i=0;
    do
    {
        response = spiSendByte(0xff);
        i++;
    } while(response == 0);
    return response;
}

char mmcReadBlock(const unsigned long address, 
                  const unsigned long count, 
                  unsigned char *pBuffer)
{
    unsigned long i = 0;
    char rvalue = MMC_RESPONSE_ERROR;
  
    //为读操作设置块的长度
    if (mmcSetBlockLength (count) == MMC_SUCCESS)
    {
        //片选信号为低
        CS_LOW ();
        
        //发送读单块的命令
        mmcSendCmd (MMC_READ_SINGLE_BLOCK,address, 0xFF);
        
        //判断响应是否正确
        if (mmcGetResponse() == 0x00)
        {
            //得到响应数据
            if (mmcGetXXResponse(MMC_START_DATA_BLOCK_TOKEN) 
                == MMC_START_DATA_BLOCK_TOKEN)
            {
      
              //读出数据
              for (i = 0; i < count; i++)
              {
                  pBuffer[i] = spiSendByte(0xff);   
              }
              
              //取出CRC数据,本软件中没有使用
              spiSendByte(0xff);
              spiSendByte(0xff);
              //返回成功标志
              rvalue = MMC_SUCCESS;
            }
            else
            {
              //没有收到响应数据
              rvalue = MMC_DATA_TOKEN_ERROR; 
            }
        }
        else
        {
            //读命令错误
            rvalue = MMC_RESPONSE_ERROR;
        }
    }
    else
    {
        //块设置命令错误
        rvalue = MMC_BLOCK_SET_ERROR;   
    }
    CS_HIGH ();
    spiSendByte(0xff);
    return rvalue;
}


char mmcWriteBlock (const unsigned long address, 
                    const unsigned long count, 
                    unsigned char *pBuffer)
{
    unsigned long i = 0;
    char rvalue = MMC_RESPONSE_ERROR;  
    
  
    // 设置块的长度
    if (mmcSetBlockLength (count) == MMC_SUCCESS) 
    {
        //选通片选管脚
        CS_LOW ();
        //发送写命令
        mmcSendCmd (MMC_WRITE_BLOCK,address, 0xFF);
    
        //判断命令是否正确
        if (mmcGetXXResponse(MMC_R1_RESPONSE) == MMC_R1_RESPONSE)
        {
            //发送数据标志数据的起始
            spiSendByte(0xff);
            //为数据的传输提供时钟
            spiSendByte(0xfe);
            
            //写入数据
            for (i = 0; i < count; i++)
            {
                spiSendByte(pBuffer[i]);  
            }
      
            //写入CRC数据,本软件没有使用
            spiSendByte(0xff);
            spiSendByte(0xff);
            //判断状态
            mmcCheckBusy();
            rvalue = MMC_SUCCESS;
        }
        else
        {
            //写命令错误
            rvalue = MMC_RESPONSE_ERROR; 
        }
    }
    else
    {
        //块设置错误
        rvalue = MMC_BLOCK_SET_ERROR; 
    }
  
    CS_HIGH ();
    //发送8个延时脉冲
    spiSendByte(0xff);
    return rvalue;
} 

void mmcSendCmd (const char cmd, unsigned long data, const char crc)
{
    char frame[6];
    char temp;
    int i;
    //封装命令数据
    frame[0]=(cmd | 0x40);
    for(i = 3;i >= 0;i--)
    {
        temp = (char)(data >> (8 * i));
        frame[4-i] = (temp);
    }
    //CRC数据
    frame[5] = (crc);
    //发送命令数据
    for(i = 0;i < 6;i++)
    {
        spiSendByte(frame[i]);
    }
}

char mmcSetBlockLength (const unsigned long blocklength)
{  
    CS_LOW ();
    
    //发送设置块长度命令
    mmcSendCmd(MMC_SET_BLOCKLEN, blocklength, 0xFF);
  
    //得到响应,判断是否是R1响应数据
    if(mmcGetResponse()!=0x00)
    { 
        //初始化MMC卡
        initMMC();
        //发送设置块长度命令
        mmcSendCmd(MMC_SET_BLOCKLEN, blocklength, 0xFF);
        //得到响应数据
        mmcGetResponse();
    }
  
    CS_HIGH ();
  
    //发送8个延时脉冲
    spiSendByte(0xff);
  
    return MMC_SUCCESS;
} 


unsigned char spiSendByte(const unsigned char data)
{
    //等待发送中断标志
    while ((IFG2 & UTXIFG1) == 0) ; 
    //发送数据
    TXBUF1 = data;  
    //等待接收中断标志
    while ((IFG2 & URXIFG1) == 0) ; 
    //接收数据
    return (RXBUF1);
}

char mmcReadRegister (const char cmd_register, 
                      const unsigned char length, 
                      unsigned char *pBuffer)
{
    char uc = 0;
    char rvalue = MMC_TIMEOUT_ERROR;
  
    if (mmcSetBlockLength (length) == MMC_SUCCESS)
    {
        //选通片选管脚
        CS_LOW ();
        
        //发送命令数据,CRC没有使用,最后一个字节为0XFF
        mmcSendCmd(cmd_register, 0x000000, 0xff);
    
        //等待响应
        if (mmcGetResponse() == 0x00)
        {
            if (mmcGetXXResponse(0xfe)== 0xfe)
            {
                //读出内容
                for (uc = 0; uc < length; uc++)
                    pBuffer[uc] = spiSendByte(0xff); 
            
            }
            //CRC数据,本软件没有使用
            spiSendByte(0xff);
            spiSendByte(0xff);
            rvalue = MMC_SUCCESS;
        }
        else
            rvalue = MMC_RESPONSE_ERROR;
        
        //片选管脚拉高
        CS_HIGH ();
    
        //发送8个延时脉冲
        spiSendByte(0xff);
    }
    CS_HIGH ();
    return rvalue;
} 



unsigned long MMC_ReadCardSize(void)
{   
    //读出CSD寄存器的内容
    unsigned long MMC_CardSize;
    unsigned short i,j,b;
    unsigned short response;
    unsigned short mmc_C_SIZE;
  
    unsigned char mmc_READ_BL_LEN,mmc_C_SIZE_MULT;
  
    CS_LOW ();
    //发送命令
    spiSendByte(MMC_READ_CSD); 
    //发送4个空数据
    for(i = 4; i > 0; i--) spiSendByte(0);
    //发送CRC数据
    spiSendByte(0xFF);
    //取出响应数据
    response = mmcGetResponse();
    b = spiSendByte(0xFF);
  
    if(!response )
    {
        while (b != 0xFE) b = spiSendByte(0xFF);
        //位127:87
        for(j = 5; j > 0; j--) b = spiSendByte(0xff);
    
        // 位84:80
        b = spiSendByte(0xff); 
        mmc_READ_BL_LEN = b & 0x0F;
    
        b = spiSendByte(0xff);
    
        // 位 73:62  C_Size
        mmc_C_SIZE = (b & 0x03) << 10;
        b = spiSendByte(0xff);
        mmc_C_SIZE += b << 2;
        b = spiSendByte(0xff);
        mmc_C_SIZE += b >> 6;
    
        // 位 55:53
        b = spiSendByte(0xff);
    
        // 位 49:47
        mmc_C_SIZE_MULT = (b & 0x03) << 1;
        b = spiSendByte(0xff);
        mmc_C_SIZE_MULT += b >> 7;
    
        // 位 41:37
        b = spiSendByte(0xff);
        b = spiSendByte(0xff);
        b = spiSendByte(0xff);
        b = spiSendByte(0xff);
        b = spiSendByte(0xff);
  
    }
    //主机保持4个字节的时钟
    for(j=4; j>0; j--) b = spiSendByte(0xff);
                              
    b = spiSendByte(0xff);
    CS_LOW ();
  
    MMC_CardSize = (mmc_C_SIZE + 1);
    //大小计算
    for(i = 2,j = mmc_C_SIZE_MULT + 2; j > 1; j--)
    {
        i <<= 1;
    }
    MMC_CardSize *= i;
    //大小计算
    for(i = 2,j = mmc_READ_BL_LEN; j > 1; j--)      
    {
        i <<= 1;
    }
    MMC_CardSize *= i;
  
    return (MMC_CardSize);
}


char mmc_check(void)
{
    if (!(P5IN & BIT0))
    {
        return (MMC_SUCCESS);
    }
    else
    {
        return (MMC_INIT_ERROR);
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -