/*! \brief closes an opened spi communication port \param fd - file descriptor of an opened SPI channel \return upon successful completion, the function shall return 0. Otherwise, -1 shall be returned \sa spi_Open \note \warning */ int spi_Close(Fd_t fd) { unsigned long ulBase = LSPI_BASE; g_SpiFd = 0; if(g_ucDMAEnabled) { //Simplelink_UDMADeInit(); #ifdef SL_PLATFORM_MULTI_THREADED osi_InterruptDeRegister(INT_LSPI); osi_MsgQDelete(&DMAMsgQ); #else SPIIntUnregister(ulBase); g_cDummy = 0; #endif SPIFIFODisable(ulBase,SPI_RX_FIFO); SPIFIFODisable(ulBase,SPI_TX_FIFO); SPIDmaDisable(ulBase,SPI_RX_DMA); SPIDmaDisable(ulBase,SPI_TX_DMA); } //Disable Chip Select SPICSDisable(LSPI_BASE); //Disable SPI Channel SPIDisable(ulBase); // Reset SPI SPIReset(ulBase); // Enable SPI Peripheral PRCMPeripheralClkDisable(PRCM_LSPI,PRCM_RUN_MODE_CLK|PRCM_SLP_MODE_CLK); return 0; }
//the following command reads multiple blocks from the sd card starting at the specified block/sector void SD_read_multiple_blocks(uint32_t sector,uint8_t* data,int numOfBlocks){ PortEx_OUTCLR(BIT3_bm, PS_BANKB); //pull SD cs low SPIInit(SPI_MODE_0_gc); SPICS(TRUE); while(SD_command(SDHC_CMD_READ_MULTIPLE_BLOCKS,sector,SDHC_DUMMY_BYTE,8) != SDHC_CMD_SUCCESS); //send command to read data //do the following for however many sectors to be read in for (int j=0;j<numOfBlocks;j++){ Buffer[1]=SDHC_DUMMY_BYTE; while(Buffer[1] != SDHC_DATA_TOKEN){ Buffer[1] = SPI_write(SDHC_DUMMY_BYTE); //wait for start of data token } for (int i=0;i<SDHC_SECTOR_SIZE;i++){ data[(i+(j*SDHC_SECTOR_SIZE))] = SPI_write(SDHC_DUMMY_BYTE); //read in the data } for (int i=0;i<2;i++){ Buffer[i] = SPI_write(SDHC_DUMMY_BYTE); //read in the 2 CRC bytes } } SD_command(SDHC_CMD_STOP_TRANSMISSION,SDHC_NO_ARGUMENTS,SDHC_DUMMY_BYTE,8); //send command to stop reading data Buffer[0] = SPI_write(SDHC_DUMMY_BYTE); //read the stuff byte Buffer[1] = FILLER_BYTE; while (Buffer[1] != SDHC_DUMMY_BYTE) Buffer[1] = SPI_write(SDHC_DUMMY_BYTE); //wait for card to finish internal processes SPICS(FALSE); SPIDisable(); PortEx_OUTSET(BIT3_bm, PS_BANKB); //pull SD cs high }
//the following command reads one sector from the sdhc card void SD_read_block(uint32_t sector,uint8_t* arrayOf512Bytes){ PortEx_OUTCLR(BIT3_bm, PS_BANKB); //pull SD cs low SPIInit(SPI_MODE_0_gc); SPICS(TRUE); for(int i=0;SD_command(SDHC_CMD_READ_SINGLE_BLOCK,sector,SDHC_DUMMY_BYTE,8) != SDHC_CMD_SUCCESS; i++) { //send command to read data if (i >= 10) { //there was no response to the command while(1); } } while(Buffer[0] != SDHC_DATA_TOKEN){ Buffer[0] = SPI_write(SDHC_DUMMY_BYTE); } for (int i=0;i<SDHC_SECTOR_SIZE;i++){ arrayOf512Bytes[i] = SPI_write(SDHC_DUMMY_BYTE); //read in the data } Buffer[12] = FILLER_BYTE; while (Buffer[12] != SDHC_DUMMY_BYTE){ Buffer[12] = SPI_write(SDHC_DUMMY_BYTE); } SPICS(FALSE); SPIDisable(); PortEx_OUTSET(BIT3_bm, PS_BANKB); //pull SD cs high }
//the following command writes one sector to the sdhc card void SD_write_block(uint32_t sector,uint8_t* data, int lengthOfData){ PortEx_OUTCLR(BIT3_bm, PS_BANKB); //pull SD cs low SPIInit(SPI_MODE_0_gc); SPICS(TRUE); int fillerBytes = SDHC_SECTOR_SIZE - lengthOfData; if (fillerBytes==SDHC_SECTOR_SIZE) fillerBytes = 0; for(int i=0;SD_command(SDHC_CMD_WRITE_SINGLE_BLOCK,sector,SDHC_DUMMY_BYTE,8) != SDHC_CMD_SUCCESS; i++){ //write to specified sector if (i >= 10) { //there was no response to the command while(1); } } Buffer[0] = SPI_write(SDHC_DUMMY_BYTE); //send 1 dummy byte as spacer SPI_write(SDHC_DATA_TOKEN); //send data token for (int i=0;i<lengthOfData;i++){ //write the data segment 1 byte at a time Buffer[i%13] = SPI_write(data[i]); } for (int i=0;i<fillerBytes;i++){ //fill the rest of the sector with filler bytes Buffer[i%13] = SPI_write(FILLER_BYTE); } Buffer[0] = SDHC_DUMMY_BYTE; for(int i=0; (i<2) || (Buffer[0] == SDHC_DUMMY_BYTE);i++){ Buffer[0] = SPI_write(SDHC_DUMMY_BYTE); //send 2 CRC dummy bytes and keep reading bytes until a response is seen } if ((Buffer[0] & SDHC_RESPONSE_STATUS_MASK) == 0x02){ //data was written successfully } while(Buffer[0] != SDHC_DUMMY_BYTE) Buffer[0] = SPI_write(SDHC_DUMMY_BYTE); //wait for card to finish internal processes SPICS(FALSE); SPIDisable(); PortEx_OUTSET(BIT3_bm, PS_BANKB); //pull SD cs high }
//this function deselects the sd card and turns off power to the port expander and the sd card void SD_disable(){ PortEx_DIRSET(BIT3_bm, PS_BANKB); //pull SD card CS high PortEx_OUTSET(BIT3_bm, PS_BANKB); SPIInit(SPI_MODE_0_gc); SPICS(TRUE); SPI_write(SDHC_DUMMY_BYTE); //must write a byte to spi when cd card cs is high to have sd card release MISO line SPICS(FALSE); //stop spi SPIDisable(); ADCPower(FALSE); //turn off portEX power Ext1Power(FALSE); //power down SD card }
//the following command writes multiple blocks/sectors to the sd card starting at a specified sector (in the sd card) void SD_write_multiple_blocks(uint32_t sector,uint8_t* data,int lengthOfData){ PortEx_OUTCLR(BIT3_bm, PS_BANKB); //pull SD cs low SPIInit(SPI_MODE_0_gc); SPICS(TRUE); int numSectors = lengthOfData/SDHC_SECTOR_SIZE; int fillerBytes = SDHC_SECTOR_SIZE - lengthOfData%SDHC_SECTOR_SIZE; if (fillerBytes==SDHC_SECTOR_SIZE) fillerBytes = 0; else numSectors++; while(SD_command(SDHC_CMD_WRITE_MULTIPLE_BLOCKS,sector,SDHC_DUMMY_BYTE,8) != SDHC_CMD_SUCCESS); //write starting at specified sector for (int j=0;j<numSectors;j++){ Buffer[1] = SPI_write(SDHC_DUMMY_BYTE); //send dummy byte Buffer[1] = SPI_write(SDHC_MULT_WRITE_DATA_TOKEN); //send data token if(j == (numSectors-1)){ for (int i=0;i<(SDHC_SECTOR_SIZE-fillerBytes);i++){ Buffer[i%12] = SPI_write(data[(i+(j*SDHC_SECTOR_SIZE))]); } for (int i=0;i<fillerBytes;i++){ Buffer[i%12] = SPI_write(FILLER_BYTE); } } else{ for (int i=0;i<SDHC_SECTOR_SIZE;i++){ Buffer[i%12] = SPI_write(data[(i+(j*SDHC_SECTOR_SIZE))]); } } for (int i=0;i<2;i++) Buffer[1] = SPI_write(SDHC_DUMMY_BYTE); //write 2 CRC token Buffer[1] = FILLER_BYTE; while(Buffer[1] != SDHC_DUMMY_BYTE) Buffer[1] = SPI_write(SDHC_DUMMY_BYTE); //wait for card to store the data it received } for(int i=0;i<4;i++){ Buffer[1] = SPI_write(SDHC_DUMMY_BYTE); //write dummy byte } Buffer[1] = SPI_write(SDHC_MULT_WRITE_STOP_TOKEN); //write stop token for(int i=0;i<4;i++){ Buffer[1] = SPI_write(SDHC_DUMMY_BYTE); //write dummy byte } Buffer[1] = FILLER_BYTE; while (Buffer[1] != SDHC_DUMMY_BYTE) Buffer[1] = SPI_write(SDHC_DUMMY_BYTE); //wait for card to finish internal processes SPICS(FALSE); SPIDisable(); PortEx_OUTSET(BIT3_bm, PS_BANKB); //pull SD cs high }
/*! \brief open spi communication port to be used for communicating with a SimpleLink device Given an interface name and option flags, this function opens the spi communication port and creates a file descriptor. This file descriptor can be used afterwards to read and write data from and to this specific spi channel. The SPI speed, clock polarity, clock phase, chip select and all other attributes are all set to hardcoded values in this function. \param ifName - points to the interface name/path. The interface name is an optional attributes that the simple link driver receives on opening the device. in systems that the spi channel is not implemented as part of the os device drivers, this parameter could be NULL. \param flags - option flags \return upon successful completion, the function shall open the spi channel and return a non-negative integer representing the file descriptor. Otherwise, -1 shall be returned \sa spi_Close , spi_Read , spi_Write \note \warning */ Fd_t spi_Open(char *ifName, unsigned long flags) { unsigned long ulBase; //NWP master interface ulBase = LSPI_BASE; //Enable MCSPIA2 PRCMPeripheralClkEnable(PRCM_LSPI,PRCM_RUN_MODE_CLK|PRCM_SLP_MODE_CLK); //Disable Chip Select SPICSDisable(ulBase); //Disable SPI Channel SPIDisable(ulBase); // Reset SPI SPIReset(ulBase); // // Configure SPI interface // SPIConfigSetExpClk(ulBase,PRCMPeripheralClockGet(PRCM_LSPI), SPI_IF_BIT_RATE,SPI_MODE_MASTER,SPI_SUB_MODE_0, (SPI_SW_CTRL_CS | SPI_4PIN_MODE | SPI_TURBO_OFF | SPI_CS_ACTIVEHIGH | SPI_WL_32)); if(PRCMPeripheralStatusGet(PRCM_UDMA)) { g_ucDMAEnabled = (HWREG(UDMA_BASE + UDMA_O_CTLBASE) != 0x0) ? 1 : 0; } else { g_ucDMAEnabled = 0; } #ifdef SL_CPU_MODE g_ucDMAEnabled = 0; #endif if(g_ucDMAEnabled) { memset(g_ucDinDout,0xFF,sizeof(g_ucDinDout)); //g_ucDout[0]=0xFF; //Simplelink_UDMAInit(); // Set DMA channel cc_UDMAChannelSelect(UDMA_CH12_LSPI_RX); cc_UDMAChannelSelect(UDMA_CH13_LSPI_TX); SPIFIFOEnable(ulBase,SPI_RX_FIFO); SPIFIFOEnable(ulBase,SPI_TX_FIFO); SPIDmaEnable(ulBase,SPI_RX_DMA); SPIDmaEnable(ulBase,SPI_TX_DMA); SPIFIFOLevelSet(ulBase,1,1); #if defined(SL_PLATFORM_MULTI_THREADED) osi_InterruptRegister(INT_LSPI, (P_OSI_INTR_ENTRY)DmaSpiSwIntHandler,INT_PRIORITY_LVL_1); SPIIntEnable(ulBase,SPI_INT_EOW); osi_MsgQCreate(&DMAMsgQ,"DMAQueue",sizeof(int),1); #else IntRegister(INT_LSPI,(void(*)(void))DmaSpiSwIntHandler); IntPrioritySet(INT_LSPI, INT_PRIORITY_LVL_1); IntEnable(INT_LSPI); SPIIntEnable(ulBase,SPI_INT_EOW); g_cDummy = 0x0; #endif } SPIEnable(ulBase); g_SpiFd = 1; return g_SpiFd; }
//the following function turns on power to the sd card and port expander and initializes the sdhc card in spi mode //returns 0 if successful or 1 if not uint8_t SD_init(void){ ADCPower(TRUE); //power up portEX Ext1Power(TRUE); //power up SD card _delay_ms(100); //wait for bootup uint8_t errorCode = 0; PortEx_DIRSET(BIT3_bm, PS_BANKB); //SD card CS PortEx_OUTSET(BIT3_bm, PS_BANKB); //pull SD cs high SPIInit2(SPI_MODE_0_gc,SPI_LOWEST_CLOCKRATE_PRESCALAR); SPICS(TRUE); for(int i=0; i<10; i++){ // idle for 10 bytes / 80 clocks SPIC.DATA=SDHC_DUMMY_BYTE; while(!(SPIC.STATUS & SPI_IF_bm)); //wait for byte to be sent Buffer[12] = SPIC.DATA; //read SPI data register to reset status flag } SPICS(FALSE); SPIDisable(); PortEx_OUTCLR(BIT3_bm, PS_BANKB); //pull SD cs low SPIInit2(SPI_MODE_0_gc,SPI_LOWEST_CLOCKRATE_PRESCALAR); SPICS(TRUE); for(int i=0;SD_command(SDHC_CMD_RESET,SDHC_NO_ARGUMENTS,SDHC_CMD_RESET_CRC,8) != SDHC_IDLE_STATE; i++){ //send command 0 to put card in idle state and read 8 next bytes sent back or until response read if (i >= 10) { //try command 10 times before timing out //there was no response to the first command errorCode = 1; break; } } _delay_ms(100); for(int i=0;SD_command(SDHC_CHECK_VOLTAGE_CMD,SDHC_CHECK_VOLTAGE_ARGUMENT,SDHC_CHECK_VOLTAGE_CRC,8) != SDHC_IDLE_STATE; i++){ //check voltage range (used to indicate to sd card that we know it is an sdhc card) if (i >= 10) { //there was no response to the command errorCode = 1; break; } } for(int i=0;i<4;i++){ Buffer[i+2] = SPI_write(SDHC_DUMMY_BYTE); } if((Buffer[4] != 0x01) || (Buffer[5] != 0xAA)){ //check that the response is the same as the argument sent in //broken card or voltage out of operating range bounds errorCode = 1; } //send second initialization command do{ SD_command(SDHC_ADV_COMMAND,SDHC_NO_ARGUMENTS,SDHC_DUMMY_BYTE,8); //next command will be advanced SD_command(SDHC_INITIALIZATION_CMD,SDHC_INITIALIZATION_CMD_ARGUMENT,SDHC_DUMMY_BYTE,8); //initialize the SDHC card in SPI mode } while(Buffer[1]!= 0x00); for(int i=0;SD_command(SDHC_CMD_READ_OCR,SDHC_NO_ARGUMENTS,SDHC_DUMMY_BYTE,8) != SDHC_CMD_SUCCESS; i++){ //check OCR register if (i >= 10) { //there was no response to the command errorCode = 1; break; } } for (int i=0;i<4;i++){ Buffer[i] = SPI_write(SDHC_DUMMY_BYTE); } if (Buffer[0] & 0x40){ //the card is addressed in 512 byte sectors } SPICS(FALSE); SPIDisable(); PortEx_OUTSET(BIT3_bm, PS_BANKB); //pull SD cs high return errorCode; }