git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@1276 35acf78f-673a-0410-8e92-d51de3d6d3f4

This commit is contained in:
gdisirio 2009-11-08 13:35:58 +00:00
parent 70e33302eb
commit 0eb3b39e5e
2 changed files with 202 additions and 7 deletions

View File

@ -55,6 +55,121 @@ void tmrfunc(void *p) {
chVTSetI(&mmcp->mmc_vt, MS2ST(MMC_POLLING_DELAY), tmrfunc, mmcp);
}
/**
* @brief Waits an idle condition.
*
* @param[in] mmcp pointer to the @p MMCDriver object
*/
static void wait(MMCDriver *mmcp) {
int i;
uint8_t buf[4];
for (i = 0; i < 16; i++) {
spiReceive(mmcp->mmc_spip, 1, buf);
if (buf[0] == 0xFF)
break;
}
/* Looks like it is a long wait.*/
while (TRUE) {
spiReceive(mmcp->mmc_spip, 1, buf);
if (buf[0] == 0xFF)
break;
#ifdef MMC_NICE_WAITING
/* Trying to be nice with the other threads.*/
chThdSleep(1);
#endif
}
}
/**
* @brief Sends a command header.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param cmd[in] the command id
* @param arg[in] the command argument
*/
static void send_hdr(MMCDriver *mmcp, uint8_t cmd, uint32_t arg) {
uint8_t buf[6];
/* Wait for the bus to become idle if a write operation was in progress. */
wait(mmcp);
buf[0] = 0x40 | cmd;
buf[1] = arg >> 24;
buf[2] = arg >> 16;
buf[3] = arg >> 8;
buf[4] = arg;
buf[5] = 0x95; /* Valid for CMD0 ignored by other commands. */
spiSend(mmcp->mmc_spip, 6, buf);
}
/**
* @brief Receives a single byte response.
*
* @param[in] mmcp pointer to the @p MMCDriver object
*
* @return The response as an @p uint8_t value.
* @retval 0xFF timed out.
*/
static uint8_t recvr1(MMCDriver *mmcp) {
int i;
uint8_t r1[1];
for (i = 0; i < 9; i++) {
spiReceive(mmcp->mmc_spip, 1, r1);
if (r1[0] != 0xFF)
return r1[0];
}
return 0xFF;
}
/**
* @brief Sends a command an returns a single byte response.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param cmd[in] the command id
* @param arg[in] the command argument
*
* @return The response as an @p uint8_t value.
* @retval 0xFF timed out.
*/
static uint8_t send_command(MMCDriver *mmcp, uint8_t cmd, uint32_t arg) {
uint8_t r1;
spiSelect(mmcp->mmc_spip);
send_hdr(mmcp, cmd, arg);
r1 = recvr1(mmcp);
spiUnselect(mmcp->mmc_spip);
return r1;
}
/**
* @brief Receives a 512 bytes block and ignores 2 CRC bytes.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param[out] buf pointer to the buffer
*
* @return The operation status.
* @retval FALSE the operation was successful.
* @retval TRUE the operation timed out.
*/
static bool_t get_data(MMCDriver *mmcp, uint8_t *buf) {
int i;
uint8_t ignored[2];
for (i = 0; i < MMC_WAIT_DATA; i++) {
spiReceive(mmcp->mmc_spip, 1, buf);
if (buf[0] == 0xFE) {
spiReceive(mmcp->mmc_spip, 512, buf);
/* CRC ignored. */
spiReceive(mmcp->mmc_spip, 2, ignored);
return FALSE;
}
}
/* Timeout.*/
return TRUE;
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
@ -119,11 +234,61 @@ void mmcStop(MMCDriver *mmcp) {
(mmcp->mmc_state != MMC_RUNNING),
"mmcStop(), #1",
"invalid state");
if (mmcp->mmc_state == MMC_READY) {
if (mmcp->mmc_state != MMC_STOP) {
mmcp->mmc_state = MMC_STOP;
chVTResetI(&mmcp->mmc_vt);
spiStop(mmcp->mmc_spip);
}
chSysUnlock();
}
/**
* @brief Performs the initialization procedure on the inserted card.
* @details This function should be invoked when a card is inserted and
* brings the driver in the @p MMC_READY state where it is possible
* to perform read and write operations.
* @note It is possible to invoke this function from the insertion event
* handler.
*
* @param[in] mmcp pointer to the @p MMCDriver object
*
* @return The operation status.
* @retval FALSE the operation was successful and the driver is now
* in the @p MMC_READY state.
* @retval TRUE the operation failed.
*/
bool_t mmcOpen(MMCDriver *mmcp) {
unsigned i;
/* Slow clock mode and 128 clock pulses.*/
spiStart(mmcp->mmc_spip, mmcp->mmc_lscfg);
/* SPI mode selection.*/
i = 0;
while (TRUE) {
if (send_command(mmcp, MMC_CMDGOIDLE, 0) == 0x01)
break;
if (++i >= MMC_CMD0_RETRY)
return TRUE;
chThdSleepMilliseconds(10);
}
/* Initialization. */
i = 0;
while (TRUE) {
uint8_t b = send_command(mmcp, MMC_CMDINIT, 0);
if (b == 0x00)
break;
if (b != 0x01)
return TRUE;
if (++i >= MMC_CMD1_RETRY)
return TRUE;
chThdSleepMilliseconds(10);
}
/* Initialization complete, full speed. */
spiStart(mmcp->mmc_spip, mmcp->mmc_hscfg);
return FALSE;
}
/** @} */

View File

@ -31,6 +31,18 @@
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Delays insertions.
* @details If enabled this options inserts delays into the MMC waiting
* routines releasing some extra CPU time for the threads with
* lower priority, this may slow down the driver a bit however.
* This option is recommended also if the SPI driver does not
* use a DMA channel and heavily loads the CPU.
*/
#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
#define MMC_NICE_WAITING TRUE
#endif
/**
* @brief Number of positive insertion queries before generating the
* insertion event.
@ -46,6 +58,23 @@
#define MMC_POLLING_DELAY 10
#endif
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define MMC_CMD0_RETRY 10
#define MMC_CMD1_RETRY 100
#define MMC_WAIT_DATA 10000
#define MMC_CMDGOIDLE 0
#define MMC_CMDINIT 1
#define MMC_CMDREADCSD 9
#define MMC_CMDSTOP 12
#define MMC_CMDREAD 17
#define MMC_CMDREADMULTIPLE 18
#define MMC_CMDWRITE 24
#define MMC_CMDWRITEMULTIPLE 25
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
@ -54,12 +83,12 @@
* @brief Driver state machine possible states.
*/
typedef enum {
MMC_UNINIT = 0, /**< @brief Not initialized. */
MMC_STOP = 1, /**< @brief Stopped. */
MMC_WAIT = 2, /**< @brief Waiting card. */
MMC_INSERTED = 3, /**< @brief Card inserted. */
MMC_READY = 4, /**< @brief Card ready. */
MMC_RUNNING = 5 /**< @brief Reading or writing. */
MMC_UNINIT = 0, /**< @brief Not initialized. *///!< MMC_UNINIT
MMC_STOP = 1, /**< @brief Stopped. *///!< MMC_STOP
MMC_WAIT = 2, /**< @brief Waiting card. *///!< MMC_WAIT
MMC_INSERTED = 3, /**< @brief Card inserted. *///!< MMC_INSERTED
MMC_READY = 4, /**< @brief Card ready. *///!< MMC_READY
MMC_RUNNING = 5 /**< @brief Reading or writing. *///!< MMC_RUNNING
} mmcstate_t;
/**
@ -139,6 +168,7 @@ extern "C" {
mmcquery_t is_protected, mmcquery_t is_inserted);
void mmcStart(MMCDriver *mmcp, const MMCConfig *config);
void mmcStop(MMCDriver *mmcp);
bool_t mmcOpen(MMCDriver *mmcp);
#ifdef __cplusplus
}
#endif