⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ffsport_spi.c

📁 The Fat Fs module is a middleware that written in ANSI C. There is no platform dependence, so long a
💻 C
字号:
/***********************************************************
*        MMC/SD-interface to SPI-slot of AT91SAM7xxx       *
*                                                          *
*          by  Frank Goetze  -  www.embedded-os.de         *
************************************************************
*                      FFSPort_MMC.c                       *
*                   MMC/SD TO SPI PORT                     *
************************************************************
*      - code generation            Frank Goetze   09/2007 *
*      - add support for SAM7SExx   Frank Goetze   04/2008 *
*        and DMA mode for sectors                          *
***********************************************************/

#include "../../../inc/MMC/AT91SAM7xxx/FFSPort_SPI.h"

/****************** constant variables ********************/
#define CPU_CRISTAL_CLK  18432000UL                        // processor crystal-clock in Hz

/******************* global variables *********************/
U08 FFSPort_MMC_CDi;                                       // remember a negative MMC-CD interrupt

/*
************************************************************
*          set max possible baudrate and return this
************************************************************
*/
U32 FFSPort_MMC_SetBR(U32 maxclk)
{
    U32 s_clksrc;
    U08 i, m;

    s_clksrc = CPU_CRISTAL_CLK;                                        // set start-clk (cristal-clk)
    AT91S_SPI_MR &= ~AT91S_SPI_MR_FDIV;                                // clear FDIV at calc-startup
    if((AT91S_PMC_MCKR & AT91S_PMC_PLLCLK) == AT91S_PMC_PLLCLK) {      // if PLL is enabled ..
        if((AT91S_CKGR_PLLR & AT91S_CKGR_DIV) > 0) {                   // .. if PLL-divisor set ..
            s_clksrc /= (AT91S_CKGR_PLLR & AT91S_CKGR_DIV);            // div clk with PLL-div
        }
        s_clksrc *= (((AT91S_CKGR_PLLR & AT91S_CKGR_MUL) >> 16) + 1);  // mul clk with PLL-multiplier
    }
    s_clksrc /= (0x0001UL << ((AT91S_PMC_MCKR & AT91C_PMC_PRES_CLK_M) >> 2));  // div clk with MCK-div
    for(i=1, m=1; m<32; i=1, m=32) {                                   // search lowest clk-div for SPI-speed (highest possible SPI-speed)
        while(((s_clksrc / (i * m)) > maxclk) && (i > 0)) i++;
        if(i > 0) break;
    }
    if(m > 1) AT91S_SPI_MR |= AT91S_SPI_MR_FDIV;           // if hole SPI-div greater 255 set FDIV for enable pre-div(32)
    AT91S_SPI_CSR->s[0] = (AT91S_SPI_CSR->s[0] & ~AT91S_SPI_CSR_SCBR_M) | (i << 8);
    return(s_clksrc / (i * m));                            // set SPI-div and return the used SPI-speed in Hz
}

#ifdef USE_MMC_DMA
U08 dbFF[512] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
/*
************************************************************
*            transfer a block via DMA to device
************************************************************
*/
U08 FFSPort_MMC_TxBlock(U08 OS_HUGE *block, U32 len)
{
    volatile U32 dummy;

    AT91S_SPI_RCR  = 0;                                    // no receive buffering
    AT91S_SPI_RNCR = 0;
    AT91S_SPI_TPR  = (U32)block;                           // set source ptr ...
    AT91S_SPI_TCR  = len;                                  // ... and length
    while(!(AT91S_SPI_SR & AT91S_SPI_SR_TXEMPTY));         // wait for transmit fully complete
    dummy = AT91S_SPI_RDR;                                 // empty receiver-register
    return(0);
}

/*
************************************************************
*            receive a block via DMA from device
************************************************************
*/
U08 FFSPort_MMC_RxBlock(U08 OS_HUGE *block, U32 len)
{
    AT91S_SPI_RPR  = (U32)block;                           // set destination ptr ...
    AT91S_SPI_RCR  = len;                                  // ... and length
    AT91S_SPI_RNCR = 0;
    AT91S_SPI_TPR  = (U32)dbFF;                            // set dummy-source ptr ...
    AT91S_SPI_TCR  = len;                                  // ... and length
    while(!(AT91S_SPI_SR & AT91S_SPI_SR_RXBUFF));          // wait for receive fully complete
    return(0);
}
#endif

/*
************************************************************
*            write a char and read one back
************************************************************
*/
U08 FFSPort_MMC_Send(U08 w)
{
    while(!(AT91S_SPI_SR & AT91S_SPI_SR_TDRE));            // wait up to tx-empty
    AT91S_SPI_TDR = w;                                     // write char and send
    while(!(AT91S_SPI_SR & AT91S_SPI_SR_RDRF));            // wait up to rx-full (char received)
    return((U08)AT91S_SPI_RDR);                            // return received char
}

/*
************************************************************
*              reinitialise the SPI-port
************************************************************
*/
U08 FFSPort_MMC_ReInit(void)
{
    AT91S_SPI_CR         = AT91S_SPI_CR_DIS;                              // disable SPI
    AT91S_SPI_CR         = AT91S_SPI_CR_EN | AT91S_SPI_CR_SWRST;          // enable & reset SPI
    AT91S_SPI_MR         = AT91S_SPI_MR_MODFDIS | AT91S_SPI_MR_MSTR;      // fault-off + (fix) + master
                                                                          // (warning! enable FDIV(MCK/32) here can break the communication with the card)
    AT91S_SPI_CSR->s[0]  = AT91S_SPI_CSR_SCBR_L | AT91S_SPI_CSR_BITS_8 | AT91S_SPI_CSR_CPOL;  // low-speed +  8bit + clk-pol (mode 3)
    AT91S_SPI_CR         = AT91S_SPI_CR_EN;                // enable SPI
    FFSPort_MMC_SetBR(400000);                             // set SPI-clk to max 400kHz as startup (should never be > 400kHz, says MMC)
    return(0);                                             // return actual alltimes ok.
}

#ifndef MMC_AT91SAM7Sxx
/*
************************************************************
*            card-detect inclusive a INT
************************************************************
*/
U08 FFSPort_MMC_CD(void)
{
    if((AT91S_PIO_PDSR & AT91S_SPI_CD) || (FFSPort_MMC_CDi)) { // PA13 as card-detect
        FFSPort_MMC_CDi = 0;                               // clear INT for "was seen"
        return(1);                                         // card is/was removed
    }
    return(0);                                             // card is still detect
}
#endif

/*
************************************************************
*              initialise the SPI-port
************************************************************
*/
U08 FFSPort_MMC_Init(void)
{
    FFSPort_MMC_CDi      = 0;                               // no INT was seen
    AT91S_PIO_PDR        = AT91S_SPI_MISO | AT91S_SPI_MOSI | AT91S_SPI_SPCK;  // disable from PIO-mode
    AT91S_PIO_ASR        = AT91S_SPI_MISO | AT91S_SPI_MOSI | AT91S_SPI_SPCK;  // enable bit-functions
#ifndef MMC_AT91SAM7Sxx
    AT91S_PIO_PER        = AT91S_SPI_CD | AT91S_SPI_WP; // enable GPIO of CD & WP
    AT91S_PIO_ODR        = AT91S_SPI_CD | AT91S_SPI_WP; // output disable CD & WP
    AT91S_PIO_OWDR       = AT91S_SPI_CD | AT91S_SPI_WP; // write disable  CD & WP
    AT91S_PIO_PUER       = AT91S_SPI_CD | AT91S_SPI_WP; // pullup enable  CD & WP
    AT91S_PMC_PCER       = (1 << AT91S_ID_PIO);             // enable clock on PIO-interface A for reading

    AT91S_AIC_IDCR       = (1 << AT91S_ID_PIO);             // Disable the interrupt on the interrupt controller
    AT91S_PIO_IFER       = AT91S_SPI_CD;
    AT91S_PIO_IER        = AT91S_SPI_CD;
    AT91S_PIO_IMR        = AT91S_SPI_CD;
    AT91S_AIC_SVR->s[AT91S_ID_PIO] = (U32)(FFSPort_MMC_ISR);// Save the interrupt handler routine pointer and the interrupt priority
    AT91S_AIC_SMR->s[AT91S_ID_PIO] = AT91S_AIC_SRCTYPE_INT_HIGHLEVEL_SENSITIVE | PIOPort_INT_PRIO;   // Store the Source Mode Register
    AT91S_AIC_ICCR       = (1 << AT91S_ID_PIO);             // Clear the interrupt on the interrupt controller
    AT91S_AIC_IECR       = (1 << AT91S_ID_PIO);             // Enable the interrupt on the interrupt controller
#else
    // no direct card-present & write-protect check on AT91SAM7Sxx_DevMaster possible
#endif
    AT91S_PIO_PER        = AT91S_SPI_NPCS0;                // enable GPIO of CS-pin
    AT91S_PIO_SODR       = AT91S_SPI_NPCS0;                // set high       CS-pin
    AT91S_PIO_OER        = AT91S_SPI_NPCS0;                // output enable  CS-pin
    AT91S_PMC_PCER       = (1 << AT91S_ID_SPI);            // enable clock on SPI-interface
#ifdef USE_MMC_DMA
    AT91S_SPI_PTCR       = AT91S_PDC_TXTDIS | AT91S_PDC_RXTDIS;  // disable SPI-DMA TX/RX
    AT91S_SPI_TNPR       = 0;                              // init "next" TX
    AT91S_SPI_TNCR       = 0;
    AT91S_SPI_RNPR       = 0;                              // init "next" RX
    AT91S_SPI_RNCR       = 0;
    AT91S_SPI_TPR        = 0;                              // init TX
    AT91S_SPI_TCR        = 0;
    AT91S_SPI_RPR        = 0;                              // init RX
    AT91S_SPI_RCR        = 0;
    AT91S_SPI_PTCR       = AT91S_PDC_TXTEN | AT91S_PDC_RXTEN;  // enable SPI-DMA TX/RX
#endif
    return(FFSPort_MMC_ReInit());
}

#ifndef MMC_AT91SAM7Sxx
/***********************************************************
*       !!!!!! SPI ISR handler (card removed) !!!!!!       *
***********************************************************/
 #ifdef __IMAGECRAFT__
  #pragma interrupt_handler FFSPort_MMC_ISR
  void FFSPort_MMC_ISR(void)
 #else
  #ifdef __IAR_SYSTEMS_ICC__
   void FFSPort_MMC_ISR(void)
  #else
   #ifdef __KEIL__
    void FFSPort_MMC_ISR(void) __irq
   #else
    #ifdef __GNUC__
     void FFSPort_MMC_ISR(void) __attribute__ ((interrupt ("IRQ")));
     void FFSPort_MMC_ISR(void)
    #else
     #error "unknown compiler for USB-port"
    #endif
   #endif
  #endif
 #endif
{
    if(AT91S_PIO_ISR & AT91S_SPI_CD) {
        if(AT91S_PIO_PDSR & AT91S_SPI_CD)                  // card-lost or card-inserted
            FFSPort_MMC_CDi = 1;                           // remember a lost-card interrupt
    }
#ifndef __IAR_SYSTEMS_ICC__
    AT91S_AIC_EOICR = 0;                                   // End-of-Interrupt
#endif
}
#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -