Search

Technical Discussion Group Forum

This forum is provided for user discussion. While Beacon EmbeddedWorks support staff and engineers participate, Beacon EmbeddedWorks does not guarantee the accuracy of all information within in the Technical Discussion Group (TDG).

The "Articles" forums provide brief Articles written by Beacon EmbeddedWorks engineers that address the most frequently asked technical questions.

To receive email notifications when updates are posted for a Beacon EmbeddedWorks product download, please subscribe to the TDG Forum of interest.

TDG Forum

PrevPrev Go to previous topic
NextNext Go to next topic
Last Post 21 Dec 2005 01:05 AM by  siju@hdmedigroup.com
Working MMC driver
 4 Replies
Sort:
You are not authorized to post a reply.
Author Messages
picman@uk2.net
New Member
New Member
Posts:


--
16 Feb 2004 08:58 AM
    Hi,

    Ok, i have been trying to get the sharp sdk MMC driver and FAT16 driver working on the Zoom starter kit...

    I could get it to read a file but not write...

    I have finally figured out why the sharp mmc driver will not work!

    Its to do with the MMC_driver.c

    in there you will find a function:

    INT_32 mmcif_is_card_busy (void)
    {
    return 0;
    }



    Replace it with this one and it will work fine....


    INT_32 mmcif_is_card_busy (void)
    {
    INT_32 i;
    for(i=0;i<2300;i++); //needs a delay here for mmc
    return 0;
    }





    I have tried various values and 2300 seems to work the best..

    Some timming problem.. SPI running too fast?? Dunno, but it works now...


    So the FAT16 driver now works for the zoom board....

    4 days to sus it!!!!

    Hope this helps someone else....
    picman@uk2.net
    New Member
    New Member
    Posts:


    --
    16 Feb 2004 12:47 PM
    opps
    SDK-LH7A400-10
    New Member
    New Member
    Posts:


    --
    27 May 2004 01:51 PM
    Picman ( or anyone else for that matter)

    read your MMC post and would like to know where you got the mmc_driver.c from? the lastest bsp from sharp does not have this file. I need to use the mmc function, so this file woudl be a great help.

    I can't tell, but are you using linux or CE? we need a solution for CE.

    thanks,

    Gerard
    senthil@atlabs.net
    New Member
    New Member
    Posts:


    --
    21 Dec 2005 12:16 AM
    /***********************************************************************
    * $Workfile: LH7A400_mmc_driver.c $
    * $Revision: 1.6 $
    * $Author: WellsK $
    * $Date: Mar 17 2003 12:06:12 $
    *
    * Project: Basic Multimedia controller interface driver
    *
    * Description:
    * This driver reads and writes raw 'sectors' in the MMC card via
    * the Logical Block addressing (LBA) mechanism. Support functions for
    * initializing and locating the card are available. All bookkeeping
    * functions related to supporting the MMC interface must be performed
    * at a higher driver level. Multitasking in the MMC interface is not
    * supported. If a read operation is performed, the data should be
    * read from the card before another operation is performed.
    *
    * Notes:
    * The MMC card detection logic can be performed via the function
    * supplied in the CPLD driver. To reduce dependency on that driver,
    * the function has been added in this driver.
    * MMC clock speed scales with bus speed and is presently locked to
    * bus speed / 6. At 100MHz, the MMC clock speed is 16.67Mbps.
    *
    * Revision History:
    * $Log: //smaicnt2/pvcs/VM/CHIPS/archives/LH7A400/MMC/Drivers/LH7A400_mmc_driver.c-arc $
    *
    * Rev 1.6 Mar 17 2003 12:06:12 WellsK
    * Corrected MMC init sequence. Many minor tweaks and
    * adjustments. Updated ad corrected comments.
    *
    * Rev 1.5 Feb 19 2003 18:39:00 BarnettH
    * Replaced Revision History elements which had been deleted.
    * Used LH7A400_evb.h
    * Revised manifest constant names throughout to agree with revised LH7A400_mmc.h
    * Revised register structure member references throughout to agree with revised LH7A400_mmc.h
    *
    * Rev 1.4 Feb 06 2003 11:52:32 LeeLen
    * Completed mmcif_start_sector_write() and mmcif_write_data() to support data writes to MMC
    *
    * Rev 1.3 Sep 22 2002 14:21:40 WellsK
    * Remove call to shutdown if MMC card was not detected.
    *
    * Rev 1.2 Sep 14 2002 08:52:34 WellsK
    * Corrected OCR check logic
    * Corrected card select/deselect logic
    * Used types and defines from MMC structure header file
    * Other minor tweaks
    *
    * Rev 1.1 Sep 07 2002 12:05:40 WellsK
    * Changed HCLK rate retrieve function. Added code to perform
    * init with 4 retries before driver init fails.
    *
    * Rev 1.0 Aug 28 2002 13:51:08 WellsK
    * Initial revision.
    *
    *
    * SHARP MICROELECTRONICS OF THE AMERICAS MAKES NO REPRESENTATION
    * OR WARRANTIES WITH RESPECT TO THE PERFORMANCE OF THIS SOFTWARE,
    * AND SPECIFICALLY DISCLAIMS ANY RESPONSIBILITY FOR ANY DAMAGES,
    * SPECIAL OR CONSEQUENTIAL, CONNECTED WITH THE USE OF THIS SOFTWARE.
    *
    * SHARP MICROELECTRONICS OF THE AMERICAS PROVIDES THIS SOFTWARE SOLELY
    * FOR THE PURPOSE OF SOFTWARE DEVELOPMENT INCORPORATING THE USE OF A
    * SHARP MICROCONTROLLER OR SYSTEM-ON-CHIP PRODUCT. USE OF THIS SOURCE
    * FILE IMPLIES ACCEPTANCE OF THESE CONDITIONS.
    *
    * COPYRIGHT (C) 2003 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
    * CAMAS, WA
    **********************************************************************/
    #include "LH7A400_evb.h"
    #include "LH7A400_mmc_driver.h"
    #include "LH7A400_CSC_driver.h"

    //**********************************************************************
    // Local defines
    //**********************************************************************
    // CPLD register bits and addresses
    #define CPLD_BOOTMMC_ST 0x20000006 // Boot/MMC status register address
    #define CPLD_MMC_DETECT 0x0001 // CPLD MMC card detect

    // Other defines
    #define MMC_BPS_CLK 20000000 // Best MMC bit/second rate
    #define MMC_BASE_ADDR 0x80000100 // MMC register set base
    #define VRANGE_OCR 0x001C0000 // MMC cards allowed at 3.0 to 3.3v
    #define MMC_BLK_SIZE 512 // MMC sector size
    #define OCR_RDY_MASK 0x0080 // Mask to check OCR ready bit
    #define MAX_OCR_RET 80 // Maximum OCR request retries

    //**********************************************************************
    // MMC structures
    //**********************************************************************
    // Possible commands (send operations are 'sent' from the card to the
    // MultiMedia Controller (MMC)
    typedef enum
    {
    MMC_IDLE, // Put card in idle mode
    MMC_SOP_COND, // Send operating condition (OCR)
    MMC_ALL_SEND_CID, // All send CID data
    MMC_SRA, // Set relative address
    MMC_DES_CARD, // Delselect card
    MMC_SEND_CSD, // Send CSD data
    MMC_SEND_CID, // Send CID register data (with rel. addr)
    MMC_READ_UNTIL_STOP, // Read data until stop command
    MMC_STOP_TRAN, // Stop data transfer
    MMC_SSTAT, // Send status
    MMC_INACTIVE, // Put card in inactive state
    MMC_SET_BLEN, // Set block transfer length
    MMC_READ_SINGLE, // Read a single block
    MMC_READ_MULTIPLE, // Read multiple blocks
    MMC_WRITE_SINGLE, // Write a single block
    MMC_WRITE_MULTIPLE, // Write multiple blocks
    MMC_INVALID_CMD // Invalid command
    } mmc_command_type;

    // Each command enumeration has a MMC command number (used by the card)
    // and a MMC command/control word (used by the controller). This
    // structure defines this word pair.
    typedef struct
    {
    UNS_32 cmd;
    UNS_32 cmdctl;
    } cmd_ctrl_type;

    //**********************************************************************
    // MMC structured data returned from card commands (responses)
    // These structures are not used in the code, but are placed here for
    // informational purposes only.
    //**********************************************************************
    // OCR register data (response R1)
    typedef struct
    {
    UNS_32 end_bit : 1;
    UNS_32 crc7 : 7;
    UNS_32 rsv1 : 8;
    UNS_32 volts_20__21 : 1;
    UNS_32 volts_21__22 : 1;
    UNS_32 volts_22__23 : 1;
    UNS_32 volts_23__24 : 1;
    UNS_32 volts_24__25 : 1;
    UNS_32 volts_25__26 : 1;
    UNS_32 volts_26__27 : 1;
    UNS_32 volts_27__28 : 1;
    UNS_32 volts_28__29 : 1;
    UNS_32 volts_29__30 : 1;
    UNS_32 volts_30__31 : 1;
    UNS_32 volts_31__32 : 1;
    UNS_32 volts_32__33 : 1;
    UNS_32 volts_33__34 : 1;
    UNS_32 volts_34__35 : 1;
    UNS_32 volts_35__36 : 1;
    UNS_32 rsv2 : 7;
    UNS_32 card_not_busy : 1;
    UNS_32 cmd_index : 6;
    UNS_32 start_tran_bits : 2;
    } ocr_register_type;

    // CID register data (not used, information only), 128 bits
    typedef struct
    {
    UNS_32 rsv : 1;
    UNS_32 crc : 7;
    UNS_32 date : 8;
    UNS_32 serial_number : 32;
    UNS_32 product_rev : 8;
    UNS_32 product_name_b : 32;
    UNS_32 product_name_a : 16;
    UNS_32 oem_id : 16;
    UNS_32 manufacturer_id : 8;
    } mmc_cid_type;

    // CSD register data (not used, information only)
    typedef struct
    {
    UNS_32 end_bit : 1;
    UNS_32 crc7 : 7;
    UNS_32 rsv1 : 1;
    UNS_32 crc : 7;
    UNS_32 ecc : 2;
    UNS_32 rsv2 : 2;
    UNS_32 wr_protect_tmp : 1;
    UNS_32 wr_protect_perm : 1;
    UNS_32 copy : 1;
    UNS_32 rsv3 : 6;
    UNS_32 wr_blk_partial : 1;
    UNS_32 wr_blk_len : 4;
    UNS_32 r2w_factor : 3;
    UNS_32 default_ecc : 2;
    UNS_32 wp_grp_enable : 1;
    UNS_32 wp_grp_size : 5;
    UNS_32 erase_grp_size : 5;
    UNS_32 sector_size : 5;
    UNS_32 c_size_mult : 3;
    UNS_32 wr_curr_max : 3;
    UNS_32 wr_curr_min : 3;
    UNS_32 rd_curr_max : 3;
    UNS_32 rd_curr_min : 3;
    UNS_32 c_size_h : 2;
    UNS_32 c_size_l : 10;
    UNS_32 rsv4 : 2;
    UNS_32 dsr_imp : 1;
    UNS_32 rd_blk_misalgn : 1;
    UNS_32 wr_blk_misalgn : 1;
    UNS_32 rd_blk_partial : 1;
    UNS_32 rd_blk_len : 4;
    UNS_32 ccc : 12;
    UNS_32 tran_speed : 8;
    UNS_32 nsac : 8;
    UNS_32 taac : 8;
    UNS_32 rsv5 : 2;
    UNS_32 mmc_prot : 4;
    UNS_32 csd_struct : 2;
    UNS_32 cmd_index : 6;
    UNS_32 start_tran_bits : 2;
    } mmc_csd_type;

    // Status register data
    typedef struct
    {
    UNS_32 rsv1 : 5;
    UNS_32 app_cmd : 1;
    UNS_32 rsv2 : 2;
    UNS_32 buff_empty : 1;
    UNS_32 card_state : 4;
    UNS_32 erase_reset : 1;
    UNS_32 card_ecc_dis : 1;
    UNS_32 wp_erase_skip : 1;
    UNS_32 csd_overwrite : 1;
    UNS_32 int_error : 1;
    UNS_32 overrun : 1;
    UNS_32 underrun : 1;
    UNS_32 general_error : 1;
    UNS_32 cc_error : 1;
    UNS_32 card_ecc_failed : 1;
    UNS_32 illegal_cmd : 1;
    UNS_32 crc_error : 1;
    UNS_32 lock_ulock_fail : 1;
    UNS_32 card_locked : 1;
    UNS_32 wr_volation : 1;
    UNS_32 erase_sel_error : 1;
    UNS_32 erase_seq_error : 1;
    UNS_32 invalid_blk_len : 1;
    UNS_32 misalgn_addr : 1;
    UNS_32 cmd_out_of_rnge : 1;
    } mmc_status_type;

    //**********************************************************************
    // Package data
    //**********************************************************************
    // MMC register set base addresses
    MMCREGS *mmc_regs;

    // CPLD MMC status register
    volatile UNS_32 *cpld_boot_mmc_status;

    // Card identifier number (128 bits)
    UNS_32 cid [5], acid [5];

    // Card-specific data register (128 bits)
    UNS_32 csd [5];

    // Relative card address
    UNS_32 rca;

    // OCR register status
    //ocr_register_type ocr;
    UNS_16 ocr [3];

    // Next sector operation pointer
    UNS_32 next_sector;

    // The following list maps a command enumeration to a MMC command
    // number and command/control word
    cmd_ctrl_type const cmd_data [MMC_INVALID_CMD] =
    {
    {0, (MMC_CMD_INITIALIZE | MMC_CMD_RESPONSE_FORMAT (0))}, // MMC_IDLE
    {1, (MMC_CMD_RESPONSE_FORMAT (3))}, // MMC_SOP
    {2, (MMC_CMD_RESPONSE_FORMAT (2))}, // MMC_ALL_SEND_CID
    {3, (MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_SRA
    {7, (MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_DES_CARD
    {9, (MMC_CMD_RESPONSE_FORMAT (2))}, // MMC_SCSD
    {10, (MMC_CMD_RESPONSE_FORMAT (2))}, // MMC_SCID
    {11, (MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_READ_UNTIL_STOP
    {12, (MMC_CMD_BUSY | MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_STOP_TRAN
    {13, (MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_SSTAT
    {15, (MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_INACTIVE
    {16, (MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_SET_BLEN
    {17, (MMC_CMD_DATA_EN | MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_READ_SINGLE
    {18, (MMC_CMD_DATA_EN | MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_READ_MULTIPLE
    {24, (MMC_CMD_BUSY | MMC_CMD_WRITE | MMC_CMD_DATA_EN | MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_WRITE_SINGLE
    {25, (MMC_CMD_BUSY | MMC_CMD_WRITE | MMC_CMD_DATA_EN | MMC_CMD_RESPONSE_FORMAT (1))} // MMC_WRITE_MULTIPLE
    };

    /***********************************************************************
    *
    * Function: mmcif_data_swap
    *
    * Purpose:
    * Swaps the low and high bytes of the MMC data. This function may not
    * be needed by the MMC driver, and is based on whether the higher
    * level code passes the code down pre-swaped.
    *
    * Processing:
    * See function.
    *
    * Parameters:
    * val : Value to swap
    *
    * Outputs:
    * None
    *
    * Returns:
    * THe byte swapped value of 'val'.
    *
    * Notes:
    * This function is private to this module.
    *
    **********************************************************************/
    UNS_16 mmcif_data_swap (UNS_16 val)
    {
    UNS_16 hi, lo;
    hi = ((UNS_16) val & 0x00FF) << 8;
    lo = ((UNS_16) val & 0xFF00) >> 8;
    return (lo + hi);
    }

    /***********************************************************************
    *
    * Function: mmc_clock_stop
    *
    * Purpose:
    * Stops the MMC clock.
    *
    * Processing:
    * See function.
    *
    * Parameters:
    * None
    *
    * Outputs:
    * None
    *
    * Returns:
    * Nothing
    *
    * Notes:
    * This function is private to this module.
    *
    **********************************************************************/
    void mmc_clock_stop (void)
    {
    // Stop the clock
    mmc_regs->clock_control = MMC_STOP_CLOCK;

    // Wait for MMC clock to stop
    while ((mmc_regs->status & MMC_STATUS_CLOCK_ENABLED) == 0);
    }

    /***********************************************************************
    *
    * Function: mmc_clock_start
    *
    * Purpose:
    * Starts the MMC clock.
    *
    * Processing:
    * See function.
    *
    * Parameters:
    * None
    *
    * Outputs:
    * None
    *
    * Returns:
    * Nothing
    *
    * Notes:
    * This function is private to this module.
    *
    **********************************************************************/
    void mmc_clock_start (void)
    {
    // Stop the clock
    mmc_regs->clock_control = MMC_START_CLOCK;
    }

    /***********************************************************************
    *
    * Function: mmc_command
    *
    * Purpose:
    * Issues the MMC command to the MM card.
    *
    * Processing:
    * The clock is stopped, while the MMC command, MMC data word, and
    * controller command are updated. Then the clock is re-started to
    * send the command to the card.
    *
    * Parameters:
    * cmd : Command enumeration
    * arg : Command argument
    *
    * Outputs:
    * None
    *
    * Returns:
    * Nothing
    *
    * Notes:
    * This function is private to this module.
    *
    **********************************************************************/
    void mmc_command (UNS_32 cmd, UNS_32 arg)
    {
    // Stop the clock
    mmc_clock_stop ();

    // Place the command and argument in the command number and
    // argument registers
    mmc_regs->command = cmd_data [cmd].cmd;
    mmc_regs->argument = arg;

    // Update controller command/control word
    mmc_regs->cmd_control = cmd_data [cmd].cmdctl;

    // Restart clock
    mmc_clock_start ();
    }

    /***********************************************************************
    *
    * Function: mmc_get_response
    *
    * Purpose:
    * The expected response is read from the MMC response FIFO.
    *
    * Processing:
    * See function.
    *
    * Parameters:
    * buf : Address of where to place response
    * bytes : Number of response bytes to copy
    *
    * Outputs:
    * None
    *
    * Returns:
    * Nothing
    *
    * Notes:
    * This function is private to this module.
    *
    **********************************************************************/
    void mmc_get_response (void *buf, INT_32 resp_size)
    {
    UNS_16 *response;
    INT_32 index;

    response = (UNS_16 *) buf;

    // Wait for response
    while ((mmc_regs->status & MMC_STATUS_END_COMMAND_RESPONSE) == 0);

    // Read the necessary number of response words from the response
    // FIFO
    for (index = 0; index < (resp_size / 2); index++)
    {
    response [index] = mmc_regs->response_fifo;
    }
    }

    /***********************************************************************
    *
    * Function: mmcif_init
    *
    * Purpose:
    * Initialize the MMC interface.
    *
    * Processing:
    * 1. Determine if an MMC card is inserted. If a card is not inserted,
    * retur with a '0' status.
    * 2. If inserted, configure the MMC interface to talk to an MMC
    * card at a low clock rate (as bus is in open drain mode).
    * 3. Issue the MMC_IDLE command (MMC CMD0) to place the card into a
    * known reset state.
    * 4. Allow a small delay with the MMC clock running to allow the card
    * to correctly initialize.
    * 5. Attempt to read the OCR word from the card until either the
    * number of requests exceeds the request count, or until the OCR
    * is valid.
    * 6. If the OCR is invalid or there are too many OCR requests, then
    * stop the MMC controller clock and exit wih a '0' status.
    * 7. If the OCR is valid, send the 'request CID (all)' command.
    * 8. Issue the 'set relative card address' command to the card.
    * 9. Update the MMC controller clock speed to a much faster speed.
    * 10. Read the CSD and CID from the card (just for information).
    * 11. Deselect the card (just in case, not needed).
    * 12. Stop the MMC controller clock and return with a '1' status.
    *
    * Parameters:
    * None
    *
    * Outputs:
    * None
    *
    * Returns:
    * '1' if a MMC card has been initialized, '0' otherwise.
    *
    * Notes:
    * None
    *
    **********************************************************************/
    INT_32 mmcif_init (void)
    {
    INT_32 i, successful_init, ocr_attempts;
    mmc_status_type cstatus;

    // Set register address for CPLD interface
    cpld_boot_mmc_status = (UNS_32 *) CPLD_BOOTMMC_ST;

    // Set mmc base address to point to MMC register set
    mmc_regs = (MMCREGS *) MMC_BASE_ADDR;

    // Check to see if card is inserted
    successful_init = mmcif_is_card_inserted ();

    // Continue if a card is available
    if (successful_init == 1)
    {
    successful_init = 0;

    // Disable controller
    mmc_regs->clock_prediv = 0;

    // Disable SPI mode control functions
    mmc_regs->spi = 0;

    // Disable interrupts, polling mode only
    mmc_regs->int_mask = -1;

    // Enable the PCLK to the MMC, enable FIFO reads via APB,
    // and set predivider to HCLK / 4
    mmc_regs->clock_prediv =
    (MMC_PREDIV_EN | MMC_PREDIV_APB_RD_EN | MMC_PREDIV(6));

    // Set the clock divider to the initialization clock value
    // (With a prediv of HCLK / 4 and and clkdiv of 6
    // (1/64 divider), the maximum bit speed (at 100MHz HCLK)
    // will be 390KBps
    mmc_regs->clock_rate = 6;

    // Set timeout values for data and response
    mmc_regs->response_to = 0xFF;
    mmc_regs->read_to = 0x01FF;

    // Disable the MMC clock
    mmc_clock_stop ();

    // Place card in idle mode
    mmc_command (MMC_IDLE, 0);

    // This delay allows a minimum of 80 clocks between the CMD0
    // request and the initiation of CMD1 and will work with
    // code execution speeds as high as 200MHZ (CPU) and bus
    // speeds as low as 25MHz. In a OS, this should be replaced
    // with a non-blocking timed delay (if possible)
    // CYCLES = (80 init clock + 32 command clocks) *
    // (200M CPU clocks / 390K MMC clocks) * 4 (bus speed adjusts)
    // = 229743 instructions (looped, cached)
    for (i = 0; i < 229743; i++);

    // Poll card until it has completed the power-up sequence
    ocr [0] = 0;
    ocr_attempts = MAX_OCR_RET;
    while (ocr_attempts > 0)
    {
    mmc_command (MMC_SOP_COND, VRANGE_OCR);
    mmc_get_response (&ocr, sizeof (ocr));
    ocr_attempts--;

    if ((ocr [0] & OCR_RDY_MASK) != 0)
    {
    ocr_attempts = 0;
    successful_init = 1;
    }
    }

    if (successful_init == 1)
    {
    // Request the CID from the MMC card(s)
    mmc_command (MMC_ALL_SEND_CID, 0);
    mmc_get_response (&acid, sizeof (acid));

    // Set the relative address of this card (only 1 card is
    // presently supported)
    rca = 0x00010000;
    mmc_command (MMC_SRA, rca);
    mmc_get_response (&cstatus, sizeof (cstatus));

    // Use faster response timeout after init
    mmc_regs->response_to = 0x10;

    mmc_regs->clock_prediv =
    (MMC_PREDIV_EN | MMC_PREDIV_APB_RD_EN | MMC_PREDIV(3));
    mmc_regs->clock_rate = 1; // (100 / 6) Mbps max

    // The CID and CSD are read (but never used)
    mmc_command (MMC_SEND_CID, rca);
    mmc_get_response (&cid, sizeof (cid));
    mmc_command (MMC_SEND_CSD, rca);
    mmc_get_response (&csd, sizeof (csd));

    // Deselect all cards
    mmc_command (MMC_DES_CARD, 0);
    mmc_get_response (&cstatus, sizeof (cstatus));
    }

    // Leave the clock disabled until needed
    mmc_clock_stop ();
    }

    return successful_init;
    }

    /***********************************************************************
    *
    * Function: mmcif_shutdown
    *
    * Purpose:
    * Shutdown the MMC interface.
    *
    * Processing:
    * Set the MMC card inactive and disable the MMC clock(s).
    *
    * Parameters:
    * None
    *
    * Outputs:
    * None
    *
    * Returns:
    * Nothing
    *
    * Notes:
    * None
    *
    **********************************************************************/
    void mmcif_shutdown (void)
    {
    mmc_status_type cstatus;

    // Put the card in inactive state - normally this is not
    // needed, but if this init sequence is called more than once,
    // the second time will fail without this sequence
    mmc_command (MMC_INACTIVE, 0);
    mmc_get_response (&cstatus, sizeof (cstatus));

    // Disable the MMC clock
    mmc_regs->clock_control = MMC_STOP_CLOCK;

    // Wait for clock to stop
    while ((mmc_regs->status & MMC_STATUS_CLOCK_ENABLED) == 0);

    // Disable PCLK to the device
    mmc_regs->clock_prediv = mmc_regs->clock_prediv & ~MMC_PREDIV_EN;
    }

    /***********************************************************************
    *
    * Function: mmcif_is_card_inserted
    *
    * Purpose:
    * Determine if a card is inserted.
    *
    * Processing:
    * Query the CPLD MMC card insertion bit to determine if an MMC card
    * is inserted into the EVB.
    *
    * Parameters:
    * None
    *
    * Outputs:
    * None
    *
    * Returns:
    * '1' if a card is inserted, '0' otherwise.
    *
    * Notes:
    * None
    *
    **********************************************************************/
    INT_32 mmcif_is_card_inserted (void)
    {
    return ((*cpld_boot_mmc_status & CPLD_MMC_DETECT) != 0);
    }

    /***********************************************************************
    *
    * Function: mmcif_set_sector
    *
    * Purpose:
    * Set the sector number for the next operation.
    *
    * Processing:
    * See function.
    *
    * Parameters:
    * None
    *
    * Outputs:
    * None
    *
    * Returns:
    * Nothing
    *
    * Notes:
    * None
    *
    **********************************************************************/
    void mmcif_set_sector (UNS_32 sectorno)
    {
    next_sector = (UNS_32) sectorno * MMC_BLK_SIZE;
    }

    /***********************************************************************
    *
    * Function: mmcif_is_card_ready
    *
    * Purpose:
    * Determines if the card is ready for a new command.
    *
    * Processing:
    * Use the busy status function as the card ready indicator.
    *
    * Parameters:
    * None
    *
    * Outputs:
    * None
    *
    * Returns:
    * '1' if the card is ready for a new command, '0' otherwise.
    *
    * Notes:
    * None
    *
    **********************************************************************/
    INT_32 mmcif_is_card_ready (void)
    {
    return (1 - mmcif_is_card_busy ());
    }

    /***********************************************************************
    *
    * Function: mmcif_is_card_busy
    *
    * Purpose:
    * Determine if a card is busy (processing a command).
    *
    * Processing:
    * This function is not used and is simply a placeholder for higher
    * level drivers.
    *
    * Parameters:
    * None
    *
    * Outputs:
    * None
    *
    * Returns:
    * '1' if the card is busy, '0' otherwise.
    *
    * Notes:
    * This function is not used. (Specific waits are performed in other
    * places in the driver.)
    *
    **********************************************************************/
    INT_32 mmcif_is_card_busy (void)
    {
    return 0;
    }

    /***********************************************************************
    *
    * Function: mmcif_start_sector_read
    *
    * Purpose:
    * Starts the read of a sector.
    *
    * Processing:
    * Set the (only) MMC card as the active card and set the data block
    * size to a single sector size. Pre-empty the data FIFO (safety).
    * Issue the 'read single' command to the MMC card with the requested
    * sector as the argument.
    *
    * Parameters:
    * None
    *
    * Outputs:
    * None
    *
    * Returns:
    * Nothing
    *
    * Notes:
    * None
    *
    **********************************************************************/
    void mmcif_start_sector_read (void)
    {
    mmc_status_type cstatus;
    UNS_16 dummy;

    // Select card 'rca' as the active card
    mmc_command (MMC_DES_CARD, rca);
    mmc_get_response (&cstatus, sizeof (cstatus));

    // Send block length command to card
    mmc_command (MMC_SET_BLEN, MMC_BLK_SIZE);
    mmc_get_response (&cstatus, sizeof (cstatus));

    // Pre-empty the data FIFO
    while ((mmc_regs->status & MMC_STATUS_FIFO_EMPTY) == 0)
    {
    dummy = mmc_regs->data_fifo;
    }

    // Issue the read block command
    mmc_command (MMC_READ_SINGLE, next_sector);
    mmc_get_response (&cstatus, sizeof (cstatus));
    }

    /***********************************************************************
    *
    * Function: mmcif_start_sector_write
    *
    * Purpose:
    * Starts the write of a sector.
    *
    * Processing:
    * Set the (only) MMC card as the active card and set the data block
    * size to a single sector size. Set the controller write size and
    * block count (different from the card block size). Issue the 'write
    * single' command to the MMC card with the requested sector as the
    * argument.
    *
    * Parameters:
    * None
    *
    * Outputs:
    * None
    *
    * Returns:
    * Nothing
    *
    * Notes:
    * None
    *
    **********************************************************************/
    void mmcif_start_sector_write (void)
    {
    mmc_status_type cstatus;

    // Select card 'rca' as the active card
    mmc_command (MMC_DES_CARD, rca);
    mmc_get_response (&cstatus, sizeof (cstatus));

    // Send block length command to card
    mmc_command (MMC_SET_BLEN, MMC_BLK_SIZE);
    mmc_get_response (&cstatus, sizeof (cstatus));

    mmc_regs->block_len = 512;
    mmc_regs->nob = 0x01;

    // Issue the write block command
    mmc_command (MMC_WRITE_SINGLE, next_sector);
    mmc_get_response (&cstatus, sizeof (cstatus));

    }

    /***********************************************************************
    *
    * Function: mmcif_read_data
    *
    * Purpose:
    * Read a block of data from the MMC card.
    *
    * Processing:
    * This function MUST be called after the 'mmcif_start_sector_read'
    * command has been issued. The function will first wait for the data
    * transfer to complete. When complete, the data will be read from the
    * FIFO into the data buffer. The MMC cards will then be deselected and
    * the controller clock will be stopped.
    *
    * Parameters:
    * data : Pointer to where to put read data from the MMC card
    * bytes : Number of bytes to read
    *
    * Outputs:
    * The data pointed to by data will be updated.
    *
    * Returns:
    * The number of bytes read from the card.
    *
    * Notes:
    * Byte swapping of the read data may not be necessary in all systems.
    *
    **********************************************************************/
    INT_32 mmcif_read_data (void *data, INT_32 bytes)
    {
    INT_32 i = 0;
    mmc_status_type cstatus;
    UNS_16 *buf = (UNS_16 *) data;

    // Wait until transfer is complete
    while ((mmc_regs->status & MMC_STATUS_DATA_TRANFER_DONE) == 0);

    // Continue reading data until FIFO is empty
    while (((mmc_regs->status & MMC_STATUS_FIFO_EMPTY) == 0) &&
    (i < (bytes / 2)))
    {
    // Any data in the FIFO
    if ((mmc_regs->status & MMC_STATUS_FIFO_EMPTY) == 0)
    {
    buf [i] = mmcif_data_swap (mmc_regs->data_fifo);
    i++;
    }
    }

    // Set card 'rca' as an inactive card
    mmc_command (MMC_DES_CARD, 0);
    mmc_get_response (&cstatus, sizeof (cstatus));

    // Stop the MMC clock
    mmc_clock_stop ();

    return bytes;
    }

    /***********************************************************************
    *
    * Function: mmcif_write_data
    *
    * Purpose:
    * Write a block of data to the MMC card.
    *
    * Processing:
    * This function MUST be called after the 'mmcif_start_sector_write'
    * command has been issued. The function will first wait for the data
    * transfer to complete. When complete, the data will be read from the
    * FIFO into the data buffer. The MMC cards will then be deselected.
    *
    * Parameters:
    * data : Pointer to where to get data to write to the MMC card
    * bytes : Number of bytes to write
    *
    * Outputs:
    * None
    *
    * Returns:
    * The number of bytes written from the card.
    *
    * Notes:
    * None
    *
    **********************************************************************/
    INT_32 mmcif_write_data (void *data, INT_32 bytes)
    {
    INT_32 i;
    mmc_status_type cstatus;
    UNS_16 *buf = (UNS_16 *) data;

    // Write to the FIFO
    for (i = 0; i < (bytes / 2); i++)
    {
    mmc_regs->data_fifo = mmcif_data_swap (buf [i]);
    }

    // Wait until write operation has ended
    while ((mmc_regs->status & MMC_STATUS_PROGRAM_DONE) == 0);

    // Set all cards inactive
    mmc_command (MMC_DES_CARD, 0);
    mmc_get_response (&cstatus, sizeof (cstatus));

    return bytes;
    }
    siju@hdmedigroup.com
    New Member
    New Member
    Posts:


    --
    21 Dec 2005 01:05 AM
    read your MMC post and would like to know where you got thefatdriver?
    You are not authorized to post a reply.