📄 mmc.h
字号:
/*! \file mmc.h \brief MultiMedia and SD Flash Card Interface. */
//*****************************************************************************
//
// File Name : 'mmc.h'
// Title : MultiMedia and SD Flash Card Interface
// Author : Pascal Stang - Copyright (C) 2004
// Created : 2004.09.22
// Revised : 2004.09.22
// Version : 0.1
// Target MCU : Atmel AVR Series
// Editor Tabs : 4
//
/// \ingroup driver_hw
/// \defgroup mmc MultiMedia and SD Flash Card Interface (mmc.c)
/// \code #include "mmc.h" \endcode
/// \par Description
/// This library offers some simple functions which can be used
/// to read and write data on a MultiMedia or SecureDigital (SD) Flash
/// Card. Although MM and SD Cards are designed to operate with their own
/// special bus wiring and protocols, both types of cards also provide a
/// simple SPI-like interface mode which is exceptionally useful when
/// attempting to use the cards in embedded systems.
///
/// \par Wiring
/// To work with this library, the card must be wired to the SPI port of
/// the Atmel microcontroller as described below. Typical cards can
/// operate at up to 25MHz maximum SPI clock rate (thus faster than most
/// AVR's maximum SPI clock rate).
/// <pre>
/// _________________
/// / 1 2 3 4 5 6 78 | <- view of MMC/SD card looking at contacts
/// / 9 | Pins 8 and 9 are present only on SD cards
/// | MMC/SD Card |
/// | |
/// /\/\/\/\/\/\/\/\/\/\
/// 1 - CS (chip select) - wire to any available I/O pin(*)
/// 2 - DIN (data in, card<-host) - wire to SPI MOSI pin
/// 3 - VSS (ground) - wire to ground
/// 4 - VDD (power, 3.3V only?) - wire to power (MIGHT BE 3.3V ONLY!)
/// 5 - SCLK (data clock) - wire to SPI SCK pin
/// 6 - VSS (ground) - wire to ground
/// 7 - DOUT (data out, card->host) - wire to SPI MISO pin
///
/// (*) you must define this chip select I/O pin in mmcconf.h
/// </pre>
/// \note This code is currently below version 1.0, and therefore is considered
/// to be lacking in some functionality or documentation, or may not be fully
/// tested. Nonetheless, you can expect most functions to work.
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************
//@{
#ifndef MMC_H
#define MMC_H
#include "global.h"
#include <spi.h>
// constants/macros/typdefs
// MMC commands (taken from sandisk MMC reference)
#define MMC_GO_IDLE_STATE 0 ///< initialize card to SPI-type access
#define MMC_SEND_OP_COND 1 ///< set card operational mode
#define MMC_SEND_CSD 9 ///< get card's CSD
#define MMC_SEND_CID 10 ///< get card's CID
#define MMC_SEND_STATUS 13
#define MMC_SET_BLOCKLEN 16 ///< Set number of bytes to transfer per block
#define MMC_READ_SINGLE_BLOCK 17 ///< read a block
#define MMC_WRITE_BLOCK 24 ///< write a block
#define MMC_PROGRAM_CSD 27
#define MMC_SET_WRITE_PROT 28
#define MMC_CLR_WRITE_PROT 29
#define MMC_SEND_WRITE_PROT 30
#define MMC_TAG_SECTOR_START 32
#define MMC_TAG_SECTOR_END 33
#define MMC_UNTAG_SECTOR 34
#define MMC_TAG_ERASE_GROUP_START 35 ///< Sets beginning of erase group (mass erase)
#define MMC_TAG_ERARE_GROUP_END 36 ///< Sets end of erase group (mass erase)
#define MMC_UNTAG_ERASE_GROUP 37 ///< Untag (unset) erase group (mass erase)
#define MMC_ERASE 38 ///< Perform block/mass erase
#define MMC_CRC_ON_OFF 59 ///< Turns CRC check on/off
// R1 Response bit-defines
#define MMC_R1_BUSY 0x80 ///< R1 response: bit indicates card is busy
#define MMC_R1_PARAMETER 0x40
#define MMC_R1_ADDRESS 0x20
#define MMC_R1_ERASE_SEQ 0x10
#define MMC_R1_COM_CRC 0x08
#define MMC_R1_ILLEGAL_COM 0x04
#define MMC_R1_ERASE_RESET 0x02
#define MMC_R1_IDLE_STATE 0x01
// Data Start tokens
#define MMC_STARTBLOCK_READ 0xFE ///< when received from card, indicates that a block of data will follow
#define MMC_STARTBLOCK_WRITE 0xFE ///< when sent to card, indicates that a block of data will follow
#define MMC_STARTBLOCK_MWRITE 0xFC
// Data Stop tokens
#define MMC_STOPTRAN_WRITE 0xFD
// Data Error Token values
#define MMC_DE_MASK 0x1F
#define MMC_DE_ERROR 0x01
#define MMC_DE_CC_ERROR 0x02
#define MMC_DE_ECC_FAIL 0x04
#define MMC_DE_OUT_OF_RANGE 0x04
#define MMC_DE_CARD_LOCKED 0x04
// Data Response Token values
#define MMC_DR_MASK 0x1F
#define MMC_DR_ACCEPT 0x05
#define MMC_DR_REJECT_CRC 0x0B
#define MMC_DR_REJECT_WRITE_ERROR 0x0D
// functions
//! Initialize AVR<->MMC hardware interface.
/// Prepares hardware for MMC access.
void mmcInit(void);
//! Initialize the card and prepare it for use.
/// Returns zero if successful.
u08 mmcReset(void);
//! Send card an MMC command.
/// Returns R1 result code.
u08 mmcSendCommand(u08 cmd, u32 arg);
//! Read 512-byte sector from card to buffer
/// Returns zero if successful.
u08 mmcRead(u32 sector, u08* buffer);
//! Write 512-byte sector from buffer to card
/// Returns zero if successful.
u08 mmcWrite(u32 sector, u08* buffer);
//! Internal command function.
/// Issues a generic MMC command as specified by cmd and arg.
u08 mmcCommand(u08 cmd, u32 arg);
#endif
// Functions
#define Enable_CS() PORTB.4 = 0;
#define Disable_CS() PORTB.4 = 1;
void mmcInit(void)
{
// initialize SPI interface
//spiInit();
// release chip select
//sbi(MMC_CS_DDR, MMC_CS_PIN);
//sbi(MMC_CS_PORT,MMC_CS_PIN);
Disable_CS();
}
u08 mmcReset(void)
{
u08 i;
u08 retry;
u08 r1=0;
retry = 0;
do
{
// send dummy bytes with CS high before accessing
for(i=0;i<10;i++) spi(0xFF);
// resetting card, go to SPI mode
r1 = mmcSendCommand(MMC_GO_IDLE_STATE, 0);
printf("MMC_GO_IDLE_STATE: R1=0x%x\r\n", r1);
// do retry counter
retry++;
if(retry>10) return -1;
} while(r1 != 0x01);
// TODO: check card parameters for voltage compliance
// before issuing initialize command
/*retry = 0;
do
{
// initializing card for operation
r1 = mmcSendCommand(0x58,0);//MMC_SEND_OP_COND, 0);
printf("MMC_SEND_OP_COND: R1=0x%x\r\n", r1);
// do retry counter
retry++;
if(retry>100) return -1;
} while(r1);
*/
// turn off CRC checking to simplify communication
r1 = mmcSendCommand(MMC_CRC_ON_OFF, 0);
printf("MMC_CRC_ON_OFF: R1=0x%x\r\n", r1);
// set block length to 512 bytes
r1 = mmcSendCommand(MMC_SET_BLOCKLEN, 100);
printf("MMC_SET_BLOCKLEN: R1=0x%x\r\n", r1);
// return success
return 0;
}
u08 mmcSendCommand(u08 cmd, u32 arg)
{
u08 r1;
// assert chip select
///////////////////////////////cbi(MMC_CS_PORT,MMC_CS_PIN);
Enable_CS()
// issue the command
r1 = mmcCommand(cmd, arg);
// release chip select
///////////////////////////////sbi(MMC_CS_PORT,MMC_CS_PIN);
Disable_CS();
return r1;
}
u08 mmcRead(u32 sector, u08* buffer)
{
u08 r1;
u16 i;
// assert chip select
///////////////////////////////////////////////////cbi(MMC_CS_PORT,MMC_CS_PIN);
Enable_CS()
// issue command
r1 = mmcCommand(MMC_READ_SINGLE_BLOCK, sector<<9);
printf("MMC Read Block R1=0x%x\r\n", r1);
// check for valid response
if(r1 != 0x00)
return r1;
// wait for block start
while(spi(0xFF) != MMC_STARTBLOCK_READ);
// read in data
for(i=0; i<0x200; i++)
{
*buffer++ = spi(0xFF);
}
// read 16-bit CRC
spi(0xFF);
spi(0xFF);
// release chip select
//////////////////////////////////////////////////////sbi(MMC_CS_PORT,MMC_CS_PIN);
Disable_CS();
// return success
return 0;
}
u08 mmcWrite(u32 sector, u08* buffer)
{
u08 r1;
u16 i;
// assert chip select
/////////////////////////////////////////////////////cbi(MMC_CS_PORT,MMC_CS_PIN);
Enable_CS();
// issue command
r1 = mmcCommand(MMC_WRITE_BLOCK, sector<<9);
printf("MMC Write Block R1=0x%x\r\n", r1);
// check for valid response
if(r1 != 0x00)
return r1;
// send dummy
spi(0xFF);
// send data start token
spi(MMC_STARTBLOCK_WRITE);
// write data
for(i=0; i<0x200; i++)
{
spi(*buffer++);
}
// write 16-bit CRC (dummy values)
spi(0xFF);
spi(0xFF);
// read data response token
r1 = spi(0xFF);
if( (r1&MMC_DR_MASK) != MMC_DR_ACCEPT)
return r1;
printf("Data Response Token=0x%x\r\n", r1);
// wait until card not busy
while(!spi(0xFF));
// release chip select
//////////////////////////////////sbi(MMC_CS_PORT,MMC_CS_PIN);
Disable_CS();
// return success
return 0;
}
u08 mmcCommand(u08 cmd, u32 arg)
{
u08 r1;
u08 retry=0;
// send command
spi(cmd | 0x40);
spi(arg>>24);
spi(arg>>16);
spi(arg>>8);
spi(arg);
spi(0x95); // crc valid only for MMC_GO_IDLE_STATE
// end command
// wait for response
// if more than 8 retries, card has timed-out
// return the received 0xFF
while((r1 = spi(0xFF)) == 0xFF)
if(retry++ > 8) break;
// return response
return r1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -