📄 ffsport_spi.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 + -