#include #include #include #include #include #define SPI_SPEED 10000000 /* 10MHz clock*/ #define SPI_TRANSFER (AT91C_PA12_MISO | AT91C_PA13_MOSI | AT91C_PA14_SPCK) #define SPI_CS (AT91C_PA11_NPCS0) static struct process *event_process = NULL; static void init_spi() { *AT91C_SPI_CR = AT91C_SPI_SPIDIS | AT91C_SPI_SWRST; *AT91C_PMC_PCER = (1 << AT91C_ID_SPI); *AT91C_PIOA_ASR = SPI_TRANSFER | SPI_CS; *AT91C_PIOA_PDR = SPI_TRANSFER | SPI_CS; *AT91C_PIOA_PPUER = AT91C_PA12_MISO | SPI_CS; *AT91C_SPI_MR = (AT91C_SPI_MSTR | AT91C_SPI_PS_FIXED | AT91C_SPI_MODFDIS); /* It seems necessary to set the clock speed for chip select 0 even if it's not used. */ AT91C_SPI_CSR[0] = ((((MCK+SPI_SPEED/2)/SPI_SPEED)<<8) | AT91C_SPI_CPOL | AT91C_SPI_BITS_8 | AT91C_SPI_CSAAT); *AT91C_SPI_CR = AT91C_SPI_SPIEN; } void if_spiInit(hwInterface *iface) { unsigned int i; *AT91C_PIOA_SODR = AT91C_PA11_NPCS0; *AT91C_PIOA_PER = AT91C_PA11_NPCS0; for(i=0;i<20;i++) { if_spiSend(iface, 0xff); } *AT91C_PIOA_PDR = AT91C_PA11_NPCS0; } /* Borrowed from at91_spi.c (c)2006 Martin Thomas */ esint8 if_initInterface(hwInterface* file, eint8* opts) { euint32 sc; if_spiInit(file); if(sd_Init(file)<0) { DBG((TXT("Card failed to init, breaking up...\n"))); return(-1); } if(sd_State(file)<0){ DBG((TXT("Card didn't return the ready state, breaking up...\n") )); return(-2); } sd_getDriveSize(file, &sc); file->sectorCount = sc/512; if( (sc%512) != 0) { file->sectorCount--; } DBG((TXT("Card Capacity is %lu Bytes (%lu Sectors)\n"), sc, file->sectorCount)); return(0); } /* Borrowed from lpc2000_spi.c (c)2005 Martin Thomas */ esint8 if_readBuf(hwInterface* file,euint32 address,euint8* buf) { return(sd_readSector(file,address,buf,512)); } esint8 if_writeBuf(hwInterface* file,euint32 address,euint8* buf) { return(sd_writeSector(file,address, buf)); } esint8 if_setPos(hwInterface* file,euint32 address) { return(0); } euint8 if_spiSend(hwInterface *iface, euint8 outgoing) { euint8 ingoing; *AT91C_SPI_TDR = outgoing; while(!(*AT91C_SPI_SR & AT91C_SPI_RDRF)); ingoing = *AT91C_SPI_RDR; /* printf(">%02x <%02x\n", outgoing, ingoing); */ return ingoing; } static EmbeddedFileSystem sdcard_efs; PROCESS(sdcard_process, "SD card process"); PROCESS_THREAD(sdcard_process, ev , data) { static struct etimer timer; PROCESS_BEGIN(); *AT91C_PIOA_PER = AT91C_PIO_PA20 | AT91C_PIO_PA1; *AT91C_PIOA_ODR = AT91C_PIO_PA20 | AT91C_PIO_PA1; /* Card not inserted */ sdcard_efs.myCard.sectorCount = 0; init_spi(); while(1) { if (!(*AT91C_PIOA_PDSR & AT91C_PA20_IRQ0)) { if (sdcard_efs.myCard.sectorCount == 0) { if (efs_init(&sdcard_efs,0) == 0) { if (event_process) { process_post(event_process, sdcard_inserted_event, NULL); } printf("SD card inserted\n"); } else { printf("SD card insertion failed\n"); } } } else { if (sdcard_efs.myCard.sectorCount != 0) { /* Card removed */ fs_umount(&sdcard_efs.myFs); sdcard_efs.myCard.sectorCount = 0; if (event_process) { process_post(event_process, sdcard_removed_event, NULL); } printf("SD card removed\n"); } } etimer_set(&timer, CLOCK_SECOND); PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_EXIT || ev == PROCESS_EVENT_TIMER); if (ev == PROCESS_EVENT_EXIT) break; if (!(*AT91C_PIOA_PDSR & AT91C_PA20_IRQ0)) { /* Wait for card to be preperly inserted */ etimer_set(&timer,CLOCK_SECOND/2); PROCESS_WAIT_EVENT_UNTIL(ev== PROCESS_EVENT_TIMER); } } PROCESS_END(); } FileSystem * efs_sdcard_get_fs() { efs_sdcard_init(); return &sdcard_efs.myFs; } void efs_sdcard_init() { static int initialized = 0; if (!initialized) { sdcard_inserted_event = process_alloc_event(); sdcard_removed_event = process_alloc_event(); process_start(&sdcard_process, NULL); initialized = 1; } } int sdcard_ready() { return sdcard_efs.myCard.sectorCount > 0; } void sdcard_event_process(struct process *p) { event_process = p; }