?? cfmm.c
字號:
/*-----------------------------------------------------------------------*/
/* CompactFlash/MMC combo control module (C)ChaN, 2007 */
/*-----------------------------------------------------------------------*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>
#include "diskio.h"
#define CFC 0 /* Physical drive number for CompactFlash Card */
#define MMC 1 /* Physical drive number for Multi Media Card */
/*---------------------------------------------------*/
/* Definitions for CF card */
/* ATA command */
#define CMD_RESET 0x08 /* DEVICE RESET */
#define CMD_READ 0x20 /* READ SECTOR(S) */
#define CMD_WRITE 0x30 /* WRITE SECTOR(S) */
#define CMD_IDENTIFY 0xEC /* DEVICE IDENTIFY */
#define CMD_SETFEATURES 0xEF /* SET FEATURES */
/* ATA register bit definitions */
#define LBA 0xE0
#define BSY 0x80
#define DRDY 0x40
#define DF 0x20
#define DRQ 0x08
#define ERR 0x01
#define SRST 0x40
#define nIEN 0x20
/* Contorl Ports */
#define CTRL_PORT PORTA
#define CTRL_DDR DDRA
#define CF_SOCK_PORT PORTC
#define CF_SOCK_DDR DDRC
#define CF_SOCK_PIN PINC
#define DAT0_PORT PORTD
#define DAT0_DDR DDRD
#define DAT0_PIN PIND
#define CF_SOCKINS 0x03
#define CF_SOCKPWR 0x04
/* Bit definitions for Control Port */
#define CTL_READ 0x20
#define CTL_WRITE 0x40
#define CTL_RESET 0x80
#define REG_DATA 0xF0
#define REG_ERROR 0xF1
#define REG_FEATURES 0xF1
#define REG_COUNT 0xF2
#define REG_SECTOR 0xF3
#define REG_CYLL 0xF4
#define REG_CYLH 0xF5
#define REG_DEV 0xF6
#define REG_COMMAND 0xF7
#define REG_STATUS 0xF7
#define REG_DEVCTRL 0xEE
#define REG_ALTSTAT 0xEE
/*---------------------------------------------------*/
/* Definitions for MMC */
/* MMC/SD command (in SPI) */
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
#define CMD1 (0x40+1) /* SEND_OP_COND */
#define CMD8 (0x40+8) /* SEND_IF_COND */
#define CMD9 (0x40+9) /* SEND_CSD */
#define CMD10 (0x40+10) /* SEND_CID */
#define CMD12 (0x40+12) /* STOP_TRANSMISSION */
#define CMD16 (0x40+16) /* SET_BLOCKLEN */
#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
#define CMD23 (0x40+23) /* SET_BLOCK_COUNT */
#define CMD24 (0x40+24) /* WRITE_BLOCK */
#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */
#define CMD41 (0x40+41) /* SEND_OP_COND (ACMD) */
#define CMD55 (0x40+55) /* APP_CMD */
#define CMD58 (0x40+58) /* READ_OCR */
/* Control signals (Platform dependent) */
#define SELECT() PORTB &= ~1 /* MMC CS = L */
#define DESELECT() PORTB |= 1 /* MMC CS = H */
#define MM_SOCKPORT PINB /* Socket contact port */
#define MM_SOCKWP 0x20 /* Write protect switch (PB5) */
#define MM_SOCKINS 0x10 /* Card detect switch (PB4) */
/*--------------------------------------------------------------------------
Module Private Functions
---------------------------------------------------------------------------*/
static volatile
DSTATUS Stat[2] = { STA_NOINIT, STA_NOINIT }; /* Disk status {CFC, MMC}*/
static volatile
BYTE Timer1, Timer2; /* 100Hz decrement timers */
static
BYTE CardType; /* b0:MMC, b1:SDC, b2:Block addressing */
/*-----------------------------------------------------------------------*/
/* Read an ATA register (Platform dependent) */
/*-----------------------------------------------------------------------*/
static
BYTE CF_read_ata (
BYTE reg /* Register to be read */
)
{
BYTE rd;
CTRL_PORT = reg;
CTRL_PORT &= ~CTL_READ;
CTRL_PORT &= ~CTL_READ;
CTRL_PORT &= ~CTL_READ;
rd = DAT0_PIN;
CTRL_PORT |= CTL_READ;
return rd;
}
/*-----------------------------------------------------------------------*/
/* Write a byte to an ATA register (Platform dependent) */
/*-----------------------------------------------------------------------*/
static
void CF_write_ata (
BYTE reg, /* Register to be written */
BYTE dat /* Data to be written */
)
{
CTRL_PORT = reg;
DAT0_PORT = dat;
DAT0_DDR = 0xFF;
CTRL_PORT &= ~CTL_WRITE;
CTRL_PORT &= ~CTL_WRITE;
CTRL_PORT |= CTL_WRITE;
DAT0_PORT = 0xFF;
DAT0_DDR = 0;
}
/*-----------------------------------------------------------------------*/
/* Read a part of data block (Platform dependent) */
/*-----------------------------------------------------------------------*/
static
void CF_read_part (
BYTE *buff, /* Data buffer to store read data */
BYTE ofs, /* Offset of the part of data in unit of word */
BYTE count /* Number of word to pick up */
)
{
BYTE c = 0, dl, dh;
CTRL_PORT = REG_DATA; /* Select Data register */
do {
CTRL_PORT &= ~CTL_READ; /* IORD = L */
CTRL_PORT &= ~CTL_READ; /* delay */
dl = DAT0_PIN; /* Read Even data */
CTRL_PORT |= CTL_READ; /* IORD = H */
CTRL_PORT &= ~CTL_READ; /* IORD = L */
CTRL_PORT &= ~CTL_READ; /* delay */
dh = DAT0_PIN; /* Read Odd data */
CTRL_PORT |= CTL_READ; /* IORD = H */
if (count && (c >= ofs)) { /* Pick up a part of block */
*buff++ = dl;
*buff++ = dh;
count--;
}
} while (++c);
CF_read_ata(REG_ALTSTAT);
CF_read_ata(REG_STATUS);
}
/*-----------------------------------------------------------------------*/
/* Wait for Data Ready (Platform dependent) */
/*-----------------------------------------------------------------------*/
static
BOOL CF_wait_data (void)
{
BYTE s;
Timer1 = 100; /* Time out = 1 sec */
do {
if (!Timer1) return FALSE; /* Abort when timeout occured */
s = CF_read_ata(REG_STATUS); /* Get status */
} while ((s & (BSY|DRQ)) != DRQ); /* Wait for BSY goes low and DRQ goes high */
CF_read_ata(REG_ALTSTAT);
return TRUE;
}
/*-----------------------------------------------------------------------*/
/* Transmit a byte to MMC via SPI (Platform dependent) */
/*-----------------------------------------------------------------------*/
#define MM_xmit_spi(dat) SPDR=(dat); loop_until_bit_is_set(SPSR,SPIF)
/*-----------------------------------------------------------------------*/
/* Receive a byte from MMC via SPI (Platform dependent) */
/*-----------------------------------------------------------------------*/
static
BYTE MM_rcvr_spi (void)
{
SPDR = 0xFF;
loop_until_bit_is_set(SPSR, SPIF);
return SPDR;
}
/* Alternative macro to receive data fast */
#define MM_rcvr_spi_m(dst) SPDR=0xFF; loop_until_bit_is_set(SPSR,SPIF); *(dst)=SPDR
/*-----------------------------------------------------------------------*/
/* Wait for card ready */
/*-----------------------------------------------------------------------*/
static
BYTE MM_wait_ready (void)
{
BYTE res;
Timer2 = 50; /* Wait for ready in timeout of 500ms */
MM_rcvr_spi();
do
res = MM_rcvr_spi();
while ((res != 0xFF) && Timer2);
return res;
}
/*-----------------------------------------------------------------------*/
/* Receive a data packet from MMC */
/*-----------------------------------------------------------------------*/
static
BOOL MM_rcvr_datablock (
BYTE *buff, /* Data buffer to store received data */
UINT btr /* Byte count (must be even number) */
)
{
BYTE token;
Timer1 = 10;
do { /* Wait for data packet in timeout of 100ms */
token = MM_rcvr_spi();
} while ((token == 0xFF) && Timer1);
if(token != 0xFE) return FALSE; /* If not valid data token, retutn with error */
do { /* Receive the data block into buffer */
MM_rcvr_spi_m(buff++);
MM_rcvr_spi_m(buff++);
} while (btr -= 2);
MM_rcvr_spi(); /* Discard CRC */
MM_rcvr_spi();
return TRUE; /* Return with success */
}
/*-----------------------------------------------------------------------*/
/* Send a data packet to MMC */
/*-----------------------------------------------------------------------*/
#if _READONLY == 0
static
BOOL MM_xmit_datablock (
const BYTE *buff, /* 512 byte data block to be transmitted */
BYTE token /* Data/Stop token */
)
{
BYTE resp, wc = 0;
if (MM_wait_ready() != 0xFF) return FALSE;
MM_xmit_spi(token); /* Xmit data token */
if (token != 0xFD) { /* Is data token */
do { /* Xmit the 512 byte data block to MMC */
MM_xmit_spi(*buff++);
MM_xmit_spi(*buff++);
} while (--wc);
MM_xmit_spi(0xFF); /* CRC (Dummy) */
MM_xmit_spi(0xFF);
resp = MM_rcvr_spi(); /* Reveive data response */
if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */
return FALSE;
}
return TRUE;
}
#endif /* _READONLY */
/*-----------------------------------------------------------------------*/
/* Send a command packet to MMC */
/*-----------------------------------------------------------------------*/
static
BYTE MM_send_cmd (
BYTE cmd, /* Command byte */
DWORD arg /* Argument */
)
{
BYTE n, res;
if (MM_wait_ready() != 0xFF) return 0xFF;
/* Send command packet */
MM_xmit_spi(cmd); /* Command */
MM_xmit_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
MM_xmit_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
MM_xmit_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
MM_xmit_spi((BYTE)arg); /* Argument[7..0] */
MM_xmit_spi(0x95); /* CRC (valid for only CMD0) */
/* Receive command response */
if (cmd == CMD12) MM_rcvr_spi(); /* Skip a stuff byte when stop reading */
n = 10; /* Wait for a valid response in timeout of 10 attempts */
do
res = MM_rcvr_spi();
while ((res & 0x80) && --n);
return res; /* Return with the response value */
}
/*-----------------------------------------------------------------------*/
/* Power control (Platform dependent) */
/*-----------------------------------------------------------------------*/
static
void MM_power_off (void)
{
SELECT();
MM_wait_ready();
DESELECT();
MM_rcvr_spi();
SPCR = 0; /* Disable SPI function */
DDRB = 0b11000000; /* Disable drivers */
PORTB = 0b10110000;
PORTE |= 0x80; /* Socket power OFF */
Stat[1] |= STA_NOINIT;
}
static
void MM_power_on (void)
{
PORTE &= ~0x80; /* Socke power (PE7) */
for (Timer1 = 3; Timer1; ); /* Wait for 30ms */
PORTB = 0b10110101; /* Enable drivers */
DDRB = 0b11000111;
SPCR = 0b01010000; /* Initialize SPI port (Mode 0) */
SPSR = 0b00000001;
}
static
void CF_power_off()
{
CF_SOCK_PORT = 0xFF;
CF_SOCK_DDR = CF_SOCKPWR;
DAT0_PORT = 0;
CTRL_DDR = 0;
}
static
void CF_power_on(void)
{
CF_SOCK_PORT &= ~CF_SOCKPWR; /* Power ON */
CTRL_PORT = CTL_READ | CTL_WRITE;
for (Timer1 = 1; Timer1; ); /* 10ms */
CTRL_DDR = 0xFF;
DAT0_PORT = 0xFF; /* Pull-up D0-D7 */
for (Timer1 = 5; Timer1; ); /* 50ms */
CTRL_PORT |= CTL_RESET; /* Deassert RESET */
for (Timer1 = 2; Timer1; ); /* 20ms */
}
/*--------------------------------------------------------------------------
Public Functions
---------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive */
/*-----------------------------------------------------------------------*/
static
DSTATUS CF_disk_initialize (void)
{
Stat[0] |= STA_NOINIT;
CF_power_off(); /* Power OFF */
for (Timer1 = 5; Timer1; ); /* 50ms */
if (Stat[0] & STA_NODISK) return Stat[0];
CF_power_on(); /* Power ON */
CF_write_ata(REG_DEV, 0); /* Select Device 0 */
Timer1 = 100;
do {
if (!Timer1) return Stat[0];
} while (!(CF_read_ata(REG_STATUS) & (BSY | DRQ)));
CF_write_ata(REG_DEVCTRL, SRST | nIEN); /* Software reset */
for (Timer1 = 2; Timer1; );
CF_write_ata(REG_DEVCTRL, nIEN);
for (Timer1 = 2; Timer1; );
Timer1 = 100;
do {
if (!Timer1) return Stat[0];
} while ((CF_read_ata(REG_STATUS) & (DRDY|BSY)) != DRDY);
CF_write_ata(REG_FEATURES, 0x01); /* Select 8-bit PIO transfer mode */
CF_write_ata(REG_COMMAND, CMD_SETFEATURES);
Timer1 = 100;
do {
if (!Timer1) return Stat[0];
} while (CF_read_ata(REG_STATUS) & BSY);
Stat[0] &= ~STA_NOINIT; /* When device goes ready, clear STA_NOINIT */
return Stat[0];
}
static
DSTATUS MM_disk_initialize (void)
{
BYTE n, ty, ocr[4];
if (Stat[1] & STA_NODISK) /* No card in the socket */
return Stat[1];
MM_power_on(); /* Force socket power ON */
for (n = 10; n; n--) MM_rcvr_spi(); /* 80 dummy clocks */
SELECT(); /* CS = L */
ty = 0;
if (MM_send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
Timer1 = 100; /* Initialization timeout of 1000 msec */
if (MM_send_cmd(CMD8, 0x1AA) == 1) { /* SDC Ver2+ */
for (n = 0; n < 4; n++) ocr[n] = MM_rcvr_spi();
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
do {
if (MM_send_cmd(CMD55, 0) <= 1 && MM_send_cmd(CMD41, 1UL << 30) == 0) break; /* ACMD41 with HCS bit */
} while (Timer1);
if (Timer1 && MM_send_cmd(CMD58, 0) == 0) { /* Check CCS bit */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -