📄 mci_lpc23xx.c
字号:
/*----------------------------------------------------------------------------
* R T L - F l a s h F i l e S y s t e m
*----------------------------------------------------------------------------
* Name: MCI_LPC23XX.C
* Purpose: Multimedia Card Interface Driver for LPC23xx
* Rev.: V3.22
*----------------------------------------------------------------------------
* This code is part of the RealView Run-Time Library.
* Copyright (c) 2004-2008 KEIL - An ARM Company. All rights reserved.
*---------------------------------------------------------------------------*/
#include "File_Config.h"
#include <LPC23xx.h> /* LPC23xx/24xx definitions */
#include "MCI_LPC23xx.h"
/* Wait timeouts, in multiples of 6 byte send over MCI (for 1 bit mode) */
#define WR_TOUT 100000 /* ~ 200 ms with MCI clk 24MHz */
#define RD_STOP_TOUT 100 /* ~ 200 us with MCI clk 24MHz */
/* Wait time in for loop cycles */
#define DMA_TOUT 10000
/* Local variables */
static U8 CardType;
static U16 CardRCA;
static U32 sernum;
/*----------------------------------------------------------------------------
* MMC Driver Functions
*----------------------------------------------------------------------------
* Required functions for MMC driver module:
* - BOOL mci_init ()
* - BOOL mci_read_sect (U32 sect, U8 *buf, U32 cnt)
* - BOOL mci_write_sect (U32 sect, U8 *buf, U32 cnt)
* - BOOL mmc_read_config (MMCFG *cfg)
*---------------------------------------------------------------------------*/
/* Local Function Prototypes */
static void mci_set_speed (U32 speed);
static void mci_bus_mode (U32 mode);
static BOOL mci_send_acmd (void);
static BOOL mci_set_address (void);
static BOOL mci_read_cid (void);
static BOOL mci_select_card (void);
static BOOL mci_set_bus_4bit (void);
static BOOL mci_set_block_len (void);
static BOOL mci_cmd_read_block (U32 block, U32 cnt);
static BOOL mci_cmd_write_block (U32 block, U32 cnt);
static U32 mci_read_status (void);
static BOOL mci_send_stop (void);
static BOOL mci_wait_for_tran (void);
static U32 mci_command (U8 cmd, U32 arg, U32 resp, U32 *rp);
static void mci_dma_start (U32 mode, U8 *buf);
/*--------------------------- mci_init --------------------------------------*/
BOOL mci_init (void) {
/* Initialize and enable the Flash Card. */
U32 i,rstat,rval[4];
/* Power Up the MCI and DMA controller. */
PCONP |= 0x30000000;
/* MCIPWR pin is active high. */
/* Required for the silicon rev. 'B' and later. */
SCS |= 0x08;
/* Enable MCI Pins on P0,P2. */
PINSEL1 &= ~0x00003FC0;
PINSEL1 |= 0x00002A80;
PINSEL4 &= ~0x0FC00000;
PINSEL4 |= 0x0A800000;
/* Clear all pending interrupts. */
MCI_COMMAND = 0;
MCI_DATA_CTRL = 0;
MCI_CLEAR = 0x7FF;
/* Power up, switch on VCC for the Flash Card. */
MCI_POWER = 0x02;
for (i = 0; i < 50000; i++);
mci_set_speed (LOW_SPEED);
/* Power on the Flash Card. */
MCI_POWER |= 0x01;
for (i = 0; i < 50000; i++);
/* Reset the card, send CMD0. */
mci_command (GO_IDLE_STATE, 0, RESP_NONE, NULL);
/* Set Open Drain output control for MMC */
mci_bus_mode (OPEN_DRAIN_MODE);
CardType = CARD_NONE;
/* First try MMC, send CMD1. */
for (i = 0; i < 100; i++) {
rstat = mci_command (SEND_OP_COND, OCR_INDEX, RESP_SHORT, &rval[0]);
if (!(rstat & MCI_CMD_TIMEOUT) && rval[0] & 0x80000000) {
CardType = CARD_MMC;
break;
}
}
if (CardType == CARD_NONE) {
/* Check for SD card, clear Open Drain output control. */
mci_bus_mode (PUSH_PULL_MODE);
for (i = 0; i < 500; i++) {
if (mci_send_acmd () == __TRUE) {
rstat = mci_command (SEND_APP_OP_COND,
OCR_INDEX, RESP_SHORT, &rval[0]);
if (!(rstat & MCI_CMD_TIMEOUT) && rval[0] & 0x80000000) {
/* OK, SD card initialized. */
CardType = CARD_SD;
break;
}
}
}
}
if (CardType == CARD_NONE) {
/* Failed, no card found. */
goto fail;
}
/* Initialize the Card to SD/MMC mode. */
if (mci_read_cid () == __FALSE) {
goto fail;
}
if (mci_set_address () == __FALSE) {
goto fail;
}
/* Disable Open Drain mode for MMC. */
if (CardType == CARD_MMC) {
mci_bus_mode (PUSH_PULL_MODE);
}
/* Data Transfer Mode, end of Card-Identification Mode. */
mci_set_speed (HIGH_SPEED);
if (mci_select_card () == __FALSE) {
goto fail;
}
if (CardType == CARD_SD) {
/* Use wide 4-bit bus for SD */
MCI_CLOCK |= 0x0800;
for (i = 0; i < 100; i++);
if (mci_set_bus_4bit () == __FALSE) {
/* Failed to enable 4-bit bus. */
goto fail;
}
}
/* Set block length to 512 bytes. */
if (mci_set_block_len () == __FALSE) {
fail: MCI_POWER = 0x00;
return (__FALSE);
}
/* Success, card initialized. */
return (__TRUE);
}
/*--------------------------- mci_set_speed ---------------------------------*/
static void mci_set_speed (U32 speed) {
/* Set a MCI clock speed to desired value. */
U32 i,clkdiv;
if (speed == HIGH_SPEED) {
/* Max. 25 MBit used for Data Transfer. */
clkdiv = 0;
}
else {
/* Max. 400 kBit used in Card Initialization. */
clkdiv = 240;
}
MCI_CLOCK = (MCI_CLOCK & ~0xFF) | 0x300 | clkdiv;
/* delay 3MCLK + 2PCLK before next write */
for ( i = 0; i < 100; i++ );
}
/*--------------------------- mci_bus_mode ----------------------------------*/
static void mci_bus_mode (U32 mode) {
/* Set MCI Bus mode to Open Drain or Push Pull. */
U32 i;
if (mode == OPEN_DRAIN_MODE) {
MCI_POWER |= 0x40;
}
else {
MCI_POWER &= ~0x40;
}
/* A small delay after switching mode. */
for (i = 0; i < 100; i++);
}
/*--------------------------- mci_send_acmd ---------------------------------*/
static BOOL mci_send_acmd (void) {
/* Send CMD55 to enable ACMD */
U32 arg,rstat,rval;
arg = 0;
if (CardType == CARD_SD) {
/* Use address from SET_RELATIVE_ADDR. */
arg = CardRCA << 16;
}
rstat = mci_command (APP_CMD, arg, RESP_SHORT, &rval);
if (rstat == 0 && (rval & STAT_ACMD_ENABLE)) {
return (__TRUE);
}
return (__FALSE);
}
/*--------------------------- mci_set_address -------------------------------*/
static BOOL mci_set_address (void) {
/* Set Relative Address, send CMD3 after CMD2. */
U32 i,arg,rstat,rval;
arg = 0;
if (CardType == CARD_MMC) {
/* Fix the RCA address for MMC card. */
arg = 0x00010000;
}
for (i = 0; i < 20; i++) {
rstat = mci_command (SET_RELATIVE_ADDR, arg, RESP_SHORT, &rval);
if (!(rstat & MCI_CMD_TIMEOUT) && (rval & 0x0F00) == 0x0500) {
/* Response is back and correct. */
CardRCA = rval >> 16;
return (__TRUE);
}
}
return (__FALSE);
}
/*--------------------------- mci_read_cid ----------------------------------*/
static BOOL mci_read_cid (void) {
/* Check CID, send CMD2 after CMD1 (MMC) or ACMD41 (SD). */
U32 i,rstat,rval[4];
for (i = 0; i < 20; i++) {
rstat = mci_command (ALL_SEND_CID, 0, RESP_LONG, &rval[0]);
if (!(rstat & MCI_CMD_TIMEOUT)) {
/* Response is back and correct. */
if (CardType == CARD_SD) {
/* Serial Number for SD Card. */
sernum = (rval[2] << 8) | (rval[3] >> 24);
}
else {
/* Serial Number for MMC Card. */
sernum = (rval[2] << 16) | (rval[3] >> 16);
}
return (__TRUE);
}
}
return (__FALSE);
}
/*--------------------------- mci_select_card -------------------------------*/
static BOOL mci_select_card (void) {
/* Select the Card, send CMD7 after CMD9, inter-change state */
/* between STBY and TRANS after this command. */
U32 i,arg,rstat,rval;
arg = 0x00010000;
if (CardType == CARD_SD) {
/* Use address from SET_RELATIVE_ADDR. */
arg = CardRCA << 16;
}
for (i = 0; i < 200; i++) {
rstat = mci_command (SELECT_CARD, arg, RESP_SHORT, &rval);
if (rstat == 0 && (rval & 0x0F00) == 0x0700) {
/* Should be in STBY state now and ready. */
return (__TRUE);
}
}
return (__FALSE);
}
/*--------------------------- mci_set_bus_4bit ------------------------------*/
static BOOL mci_set_bus_4bit (void) {
/* Select 4-bit bus width for SD Card. */
U32 i,rstat,rval;
for (i = 0; i < 20; i++) {
if (mci_send_acmd () == __FALSE) {
continue;
}
/* Send ACMD6 command to set the bus width. */
rstat = mci_command (SET_ACMD_BUS_WIDTH, BUS_WIDTH_4BITS, RESP_SHORT, &rval);
if (rstat == 0 && (rval & 0x0F00) == 0x0900) {
/* Response is back and correct. */
return (__TRUE);
}
}
return (__FALSE);
}
/*--------------------------- mci_set_block_len -----------------------------*/
static BOOL mci_set_block_len (void) {
/* Set block length to 512 bytes. */
U32 i,rstat,rval;
for (i = 0; i < 20; i++) {
/* Send ACMD6 command to set the bus width. */
rstat = mci_command (SET_BLOCK_LEN, 512, RESP_SHORT, &rval);
if (rstat == 0 && (rval & 0x0F00) == 0x0900) {
/* Response is back and correct. */
return (__TRUE);
}
}
return (__FALSE);
}
/*--------------------------- mci_cmd_read_block ----------------------------*/
static BOOL mci_cmd_read_block (U32 block, U32 cnt) {
/* Send a command to Read Single/Multiple blocks. */
U32 i,rstat,rval;
U8 cmd;
cmd = READ_BLOCK;
if (cnt > 1) {
cmd = READ_MULT_BLOCK;
}
block *= 512;
for (i = 0; i < 20; i++) {
rstat = mci_command (cmd, block, RESP_SHORT, &rval);
if (rstat == 0 && (rval & 0x0F00) == 0x0900) {
/* Ready and in TRAN state. */
return (__TRUE);
}
}
return (__FALSE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -