Subversion Repositories Projects

Compare Revisions

Ignore whitespace Rev 293 → Rev 294

/FollowMe/crc16.c
0,0 → 1,48
#include "crc16.h"
#include <avr/pgmspace.h>
 
const uint16_t crc16tab[256] PROGMEM =
{
0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
};
 
uint16_t CRC16(const uint8_t *pBuffer, uint32_t len)
{
uint32_t counter;
uint16_t crc = 0;
for( counter = 0; counter < len; counter++)
crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *pBuffer++)&0x00FF];
return crc;
}
 
/FollowMe/crc16.h
0,0 → 1,8
#ifndef _CRC16_H
#define _CRC16_H
 
#include <inttypes.h>
 
extern uint16_t CRC16(const uint8_t * pBuffer, uint32_t len);
 
#endif // _CRC16_H
/FollowMe/main.c
59,6 → 59,7
#include "uart0.h"
#include "uart1.h"
#include "fat16.h"
#include "sdc.h"
#include "led.h"
#include "menu.h"
#include "printf_P.h"
102,8 → 103,6
LEDGRN_ON;
#endif
 
 
 
#ifdef USE_SDLOGGER
printf("\n\rHW: SD-Logger");
#endif
114,17 → 113,6
printf("\n\r==============================");
printf("\n\r");
 
/*
// try to initialize the SD-Card File system
printf("\n\rInit FAT16...");
if(FAT16_Init())
{
printf("ok");
}
else
{
printf("failed");
}*/
 
#ifdef USE_FOLLOWME
BeepTime = 2000;
136,7 → 124,19
while (1)
{
// check for button action
if(GetButton()) BeepTime = 200;
if(GetButton())
{
//BeepTime = 200;
printf("\n\rInit FAT16...");
if(SDC_Init())
{
printf("ok");
}
else
{
printf("failed");
}
}
 
// restart ADConversion if ready
if(ADReady)
/FollowMe/main.h
2,13 → 2,6
#define _MAIN_H
 
#include <avr/io.h>
 
/*
#if defined (__AVR_ATmega644P__)
#define SYSCLK 20000000L //crystal freqency in Hz
#endif
*/
 
#define SYSCLK F_CPU
 
 
/FollowMe/makefile
76,8 → 76,7
 
##########################################################################################################
# List C source files here. (C dependencies are automatically generated.)
SRC = main.c uart0.c uart1.c printf_P.c timer0.c menu.c led.c ubx.c analog.c button.c
#ssc.c sdc.c fat16.c
SRC = main.c uart0.c uart1.c printf_P.c timer0.c menu.c led.c ubx.c analog.c button.c crc16.c ssc.c sdc.c fat16.c
 
##########################################################################################################
 
/FollowMe/sdc.c
1,254 → 1,688
#include <avr/io.h>
#include <util/delay.h>
#include "fat16.h"
#include <string.h>
#include "sdc.h"
#include "ssc.h"
#include "timer0.h"
#include "printf_P.h"
#include "crc16.h"
 
#define _SD_DEBUG
 
#define CMD_GO_IDLE_STATE 0x00 /* CMD00: response R1 */
#define CMD_SEND_OP_COND 0x01 /* CMD01: response R1 */
#define CMD_SEND_IF_COND 0x08 /* CMD08: response R7 */
#define CMD_SEND_CSD 0x09 /* CMD09: response R1 */
#define CMD_SEND_CID 0x0A /* CMD10: response R1 */
#define CMD_SEND_STATUS 0x0D /* CMD13: response R2 */
#define CMD_SET_BLOCKLEN 0x10 /* CMD16: arg0[31:0]: block length, response R1*/
#define CMD_READ_SINGLE_BLOCK 0x11 /* CMD17: arg0[31:0]: data address, response R1 */
#define CMD_WRITE_SINGLE_BLOCK 0x18 /* CMD24: arg0[31:0]: data address, response R1 */
#define CMD_APP_CMD 0x37 /* CMD55: response R1 */
#define CMD_READ_OCR 0x3A /* CMD58: response R3 */
#define CMD_CRC_ON_OFF 0x3B /* CMD59: arg0[31:1]: stuff bits, arg0[0:0]: crc option, response R1 */
#define ACMD_SEND_OP_COND 0x29 /* ACMD41: arg0[31]: stuff bits, arg0[30]: HCS, arg0[29:0] stuff bits*, response R1 */
 
#define R1_NO_ERR 0x00
#define R1_IDLE_STATE 0x01
#define R1_ERASE_RESET 0x02
#define R1_ILLEGAL_CMD 0x04
#define R1_COM_CRC_ERR 0x08
#define R1_ERASE_SEQUENCE_ERR 0x10
#define R1_ADDRESS_ERR 0x20
#define R1_PARAMETER_ERR 0x40
#define R1_BAD_RESPONSE 0x80
 
#define R2_NO_ERR 0x00
#define R2_CARD_LOCKED 0x01
#define R2_ERASE_WRITE_PROT_ERR 0x02
#define R2_UNKOWN_ERR 0x04
#define R2_CARD_CTRL_ERR 0x08
#define R2_CARD_ECC_ERR 0x10
#define R2_WRITE_PROT_ERR 0x20
#define R2_ERASE_PARAM_ERR 0x40
#define R2_OUT_OF_RANGE_ERR 0x80
 
#define DATA_START_TOKEN 0xFE
#define DATA_RESPONSE_MASK 0x1F
#define DATA_RESPONSE_OK 0x05
#define DATA_RESPONSE_CRC_ERR 0x0B
#define DATA_RESPONSE_WRITE_ERR 0x1D
 
typedef enum
{
VER_UNKNOWN,
VER_1X,
VER_20
} SDVersion_t;
 
typedef struct
{
uint8_t Valid;
SDVersion_t Version; // HW-Version
uint32_t Capacity; // Memory capacity in bytes
uint8_t CID[16]; // CID register
uint8_t CSD[16]; // CSD register
} __attribute__((packed)) SDCardInfo_t;
 
 
volatile SDCardInfo_t SDCardInfo;
 
//________________________________________________________________________________________________________________________________________
// Module name: mmc.c
// Compiler used: avr-gcc 3.4.5
// Last Modifikation: 24.07.2007
// Version: 1.05
// Authors: Stephan Busker
// Description: Source files for connecting to an sdcard using the SSC
// Function: CRC7(uint8_t* cmd, uint32_t len);
//
//........................................................................................................................................
// Functions: u8 SDC_init(void);
// u8 SDC_PutCommand (u8*CMD);
// u8 SDC_PutSector(u32 addr,u8*Buffer);
// u8 SDC_GetSector(u32 addr,u8*Buffer);
// void SDC_GetBlock(u8*CMD,u8*Buffer,u16 Bytes);
// Description: This function calculated the CRC7 checksum used in the last byte of a spi command frame.
//
////........................................................................................................................................
// ext. functions: extern void SSC_Init(void);
// extern u8 SSC_GetChar (void);
// extern void SSC_PutChar (u8);
// extern void SSC_Enable(void);
// extern void SSC_Disable(void);
//........................................................................................................................................
//
// URL: www.Mikro-Control.de
// mailto: stephan.busker@mikro-control.de
// Returnvalue: the function returns the crc7 including bit 0 set to 1
//________________________________________________________________________________________________________________________________________
 
uint8_t CRC7(uint8_t *cmd, uint32_t len)
{
uint8_t i, a;
uint8_t crc, Data;
 
crc = 0; // init CRC buffer
for (a = 0; a < len ;a++) // for every byte in the msg
{
Data = cmd[a];
for (i=0;i<8;i++) // for every bit in the byte
{
crc <<= 1; // shift crc
if ((Data & 0x80)^(crc & 0x80)) crc ^=0x09; //xor
Data <<= 1; // shift data for next bit
}
}
crc = (crc<<1)|1; // set terminating bit to 1
return(crc);
}
 
 
uint8_t SDC_WaitForBusy(uint16_t timeout)
{
uint8_t rsp = 0;
uint16_t timestamp = 0;
 
SSC_Enable(); // enable chipselect.
timestamp = SetDelay(timeout);
do
{
rsp = SSC_GetChar();
if(CheckDelay(timestamp)) break;
}while(rsp != 0xFF); // wait while card is busy (data out low)
return(rsp);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: SDC_Init(void);
//
// Description: This function initialises the SDCard to spi-mode.
//
// Function: SDC_SendCMDR1(uint8_t CmdNo, uint32_t arg);
//
// Returnvalue: the function returns 0 if the initialisation was successfull otherwise the function returns an errorcode.
// Description: This function send a command frame to the SD-Card in spi-mode.
//
//
// Returnvalue: The function returns the first response byte like for R1 commands
//________________________________________________________________________________________________________________________________________
 
u8 SDC_Init(void)
uint8_t SDC_SendCMDR1(uint8_t CmdNo, uint32_t arg)
{
u8 Timeout = 0;
u8 CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95};
u16 a = 0;
u8 b = 0;
uint8_t r1;
uint16_t timeout = 0;
uint16_t a;
uint8_t cmd[6];
 
SSC_Init(); // Initialise SSC to transmit data to the sdcard.
cmd[0] = 0x40|CmdNo; // set command index
cmd[1] = (arg & 0xFF000000)>>24;
cmd[2] = (arg & 0x00FF0000)>>16;
cmd[3] = (arg & 0x0000FF00)>>8;
cmd[4] = (arg & 0x000000FF);
cmd[5] = CRC7(cmd, 5); // update checksum
#ifdef _SD_DEBUG
printf("\r\nCmd=%02X, arg=%04X%04X", CmdNo, (uint16_t)(arg>>16), (uint16_t)(0xFFFF & arg));
#endif
SSC_Disable(); // disable chipselect.
SSC_PutChar(0xFF); // dummy to sync
SSC_Enable(); // enable chipselect.
_delay_loop_2(200);
//SDC_WaitForBusy(500); // wait 500ms until card is busy
 
for (a = 0;a < 6; a++) // send the command sequence to the sdcard (6 bytes)
{
SSC_PutChar(cmd[a]);
_delay_loop_2(10);
}
// get response byte
do
{
r1 = SSC_GetChar(); // get byte from sd-card
if (timeout++ > 1000) break;
}while(r1 == 0xFF); // wait for the response byte from sd-card.
#ifdef _SD_DEBUG
printf("-->R1=%02X", r1);
#endif
return(r1);
}
 
_delay_ms(10); // before initialising the sdcard wait for 10ms
//________________________________________________________________________________________________________________________________________
// Function: SDC_SendACMDR1(uint8_t CmdNo, uint32_t arg);
//
// Description: This function send a application command frame to the SD-Card in spi-mode.
//
//
// Returnvalue: The function returns the first response byte like for R1 commands
//________________________________________________________________________________________________________________________________________
uint8_t SDC_SendACMDR1(uint8_t CmdNo, uint32_t arg)
{
uint8_t r1 = 0xFF;
r1 = SDC_SendCMDR1(CMD_APP_CMD, 0UL);
if(r1 & R1_BAD_RESPONSE) return(r1);
r1 = SDC_SendCMDR1(CmdNo, arg);
return(r1);
}
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_GetData(uint8_t * cmd ,u8 *Buffer, u32 len);
//
// Description: This function sneds cmd an reads a datablock of len from the sd-card
//
//
// Returnvalue: SD_Result_t
//________________________________________________________________________________________________________________________________________
 
for (b=0;b<0x0f;b++) // sending 74Clocks brings the sdcard into spimode.
SD_Result_t SDC_GetData(uint8_t CmdNo, uint32_t addr, uint8_t *Buffer, uint32_t len)
{
uint8_t rsp;
uint16_t a, crc16;
SD_Result_t result = SD_ERROR_UNKNOWN;
 
// send the command
rsp = SDC_SendCMDR1(CmdNo, addr);
if (rsp != R1_NO_ERR)
{
_delay_us(1); // wait at least 1us between the characters.
SSC_PutChar(0xff);
result = SD_ERROR_BAD_RESPONSE;
goto end;
}
while(SDC_PutCommand (CMD) !=1) // Sending CMD0 (Reset) to the sdcard.
 
do
{
if (Timeout++ > 200)
{
return(1);
rsp = SSC_GetChar();
if((rsp & 0xF0) == 0x00) // data error token
{
result = SD_ERROR_READ_DATA;
goto end;
}
}while(rsp != DATA_START_TOKEN);
// data start token received
for (a = 0; a < len; a++) // read the block from the SSC
{
Buffer[a] = SSC_GetChar();
}
Timeout = 0;
CMD[0] = 0x41;
CMD[5] = 0xFF;
while( SDC_PutCommand (CMD) !=0) // Sending CMD1 to the sdcard.
// Read two bytes CRC16-Data checksum
crc16 = SSC_GetChar(); // highbyte first
crc16 = (crc16<<8)|SSC_GetChar(); // lowbyte last
/* if(crc16 != CRC16(Buffer, len)) result = SD_ERROR_CRC_DATA;
else */result = SD_SUCCESS;
 
end:
if(result != SD_SUCCESS)
{
if (Timeout++ > 100)
{
return(2);
}
printf("Error %02X reading data from sd card (R1=%02X).\r\n", result, rsp);
}
return(result);
}
 
SSC_Disable(); // disable sdcard.
return(0);
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_PrintCID(u8 * pCID);
//
// Description: This function prints the CIS register in a human readable format.
//
//
// Returnvalue: the function returns nothing
//________________________________________________________________________________________________________________________________________
 
void SDC_PrintCID(uint8_t * pCID)
{
uint8_t pn[6];
uint16_t temp1, temp2;
 
printf("\r\n Manufacturer ID: %i\r\n", pCID[0]);
memcpy(pn, &pCID[1], 2);
pn[2] = '\0'; // terminate string
printf(" Application ID: %s\r\n",pn);
memcpy(pn, &pCID[3], 5);
pn[5] = '\0'; // terminate string
printf(" Product Name: %s\r\n",pn);
printf(" Product Rev.: %i.%i\r\n",pCID[8]>>4, pCID[8]&0xF);
printf(" Serial No.: ");
for(temp1 = 0; temp1<4; temp1++)
{
printf("%02X", pCID[9+temp1]);
}
printf("\r\n");
temp1 = pCID[14] & 0x0F; // month
temp2 = ((pCID[14]>>4)|(pCID[13]<<4)) + 2000; // year
printf(" Manufac. Date: %i/%i\r\n\r\n",temp1, temp2);
}
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_GetCID(uint8_t * pCID);
//
// Description: This function reads the CIS register form the sd card in spi mode.
//
//
// Returnvalue: the function returns error state
//________________________________________________________________________________________________________________________________________
 
SD_Result_t SDC_GetCID(uint8_t * pCID)
{
return SDC_GetData(CMD_SEND_CID, 0UL, pCID, 16);
}
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_GetCSD(uint8_t * pCSD);
//
// Description: This function reads the CSD register form the sd card in spi mode.
//
//
// Returnvalue: the function returns error state
//________________________________________________________________________________________________________________________________________
 
SD_Result_t SDC_GetCSD(uint8_t * pCSD)
{
return SDC_GetData(CMD_SEND_CSD, 0UL, pCSD, 16);
}
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: SDC_PutCommand(* CMD);
//
// Description: This function initialises the SDCard to spi-mode.
//
// Function: SDC_Init(void);
//
// Description: This function initialises the SDCard to spi-mode.
//
//
// Returnvalue: the function returns 0 if the initialisation was successfull otherwise the function returns an errorcode.
//________________________________________________________________________________________________________________________________________
 
u8 SDC_PutCommand (u8*CMD)
SD_Result_t SDC_Init(void)
{
u8 tmp = 0xff;
u8 Timeout = 0;
u16 a = 0;
uint16_t timeout = 0;
uint8_t rsp[6]; // SD-SPI response buffer
SD_Result_t result = SD_ERROR_UNKNOWN;
 
if(SD_SWITCH) // init only if the SD-Switch is indicating a card in the slot
{
printf("\r\n SSC init...");
SSC_Init();
printf("ok");
 
#ifdef SSC_RX_FIFO
SSC_ClearRxFifo();
#endif
SSC_Disable(); // disable chipselect
SSC_PutChar(0xFF); // Send 8 Clocks to the sdcard while card is not selected.
SSC_Enable(); // enable chipselect.
_delay_loop_2(1050);
 
if (*CMD == 0x41) _delay_ms(10); // if command is CMD0 generate a short delay.
for (a = 0;a<0x06;a++) // send the command sequence to the sdcard (6 bytes)
{
SSC_PutChar(*CMD++);
}
printf("\r\n SDC init...");
SDCardInfo.Valid = 0;
/* The host shall supply power to the card so that the voltage is reached to Vdd_min within 250ms and
start to supply at least 74 SD clocks to the SD card with keeping cmd line to high. In case of SPI
mode, CS shall be held to high during 74 clock cycles. */
SSC_Disable(); // set SD_CS high
for (timeout = 0; timeout < 15; timeout++) // 15*8 = 120 cycles
{
SSC_PutChar(0xFF);
}
 
#ifdef SSC_RX_FIFO
SSC_ClearRxFifo();
#endif
while (tmp == 0xff) // Wait for response from sdcard.
{
tmp = SSC_GetChar();
if (Timeout++ > 100)
// switch to idle state
#ifdef _SD_DEBUG
printf("\r\nGoing idle state..");
#endif
timeout = 0;
do
{
break; // or timeout.
rsp[0] = SDC_SendCMDR1(CMD_GO_IDLE_STATE, 0UL);
if (timeout++ > 500)
{
printf("reset timeout");
result = SD_ERROR_RESET;
goto end;
}
}while(rsp[0] != R1_IDLE_STATE);
// enable crc feature
/* if(SDC_SendCMDR1(CMD_CRC_ON_OFF, 1UL) != R1_IDLE_STATE)
{
printf("Bad cmd59 R1=%02X.", rsp[0]);
result = SD_ERROR_BAD_RESPONSE;
goto end;
}*/
// check for card hw version
// 2.7-3.6V Range = 0x01, check pattern 0xAA
rsp[0] = SDC_SendCMDR1(CMD_SEND_IF_COND, 0x000001AA);
// answer to cmd58 is an R7 response (R1+ 4Byte IFCond)
if(rsp[0] & R1_BAD_RESPONSE)
{
printf("Bad cmd8 R1=%02X.", rsp[0]);
result = SD_ERROR_BAD_RESPONSE;
goto end;
}
}
if(rsp[0] & R1_ILLEGAL_CMD)
{
//Ver1.X SD Memory Card or not a SD Memory Card
SDCardInfo.Version = VER_1X;
}
else
{
// Ver2.00 or later SD Memory Card
// reading the remaining bytes of the R7 response
SDCardInfo.Version = VER_20;
for(timeout = 1; timeout < 5; timeout++)
{
rsp[timeout] = SSC_GetChar();
}
//check pattern
if(rsp[4]!= 0xAA)
{
printf("Bad cmd8 R7 check pattern.\r\n");
result = SD_ERROR_BAD_RESPONSE;
goto end;
}
if ( (rsp[3] & 0x0F)!= 0x01 ) // voltage range is not 2.7-3.6V
{
 
return(tmp);
}
printf("Card is incompatible to 3.3V.\r\n");
result = SD_ERROR_BAD_VOLTAGE_RANGE;
goto end;
}
}
 
rsp[0] = SDC_SendCMDR1(CMD_READ_OCR, 0UL);
// answer to cmd58 is an R3 response (R1 + 4Byte OCR)
if(rsp[0] & R1_BAD_RESPONSE)
{
printf("Bad cmd58 R1 %02x.", rsp[0]);
result = SD_ERROR_BAD_RESPONSE;
goto end;
}
if(rsp[0] & R1_ILLEGAL_CMD)
{
printf("Not an SD-CARD.");
result = SD_ERROR_NO_SDCARD;
goto end;
}
// read 4 bytes of OCR register
for(timeout = 1; timeout < 5; timeout++)
{
rsp[timeout] = SSC_GetChar();
}
// FollowMe & SD-Logger uses 3.3 V, therefore check for bit 20 & 21
if((rsp[2] & 0x30) != 0x30)
{
// supply voltage is not supported by sd-card
printf("Card is incompatible to 3.3V.");
result = SD_ERROR_BAD_VOLTAGE_RANGE;
goto end;
}
 
// Initialize the sd-card sending continously ACMD_SEND_OP_COND (only supported by SD cards)
timeout = SetDelay(2000); // set timeout to 2000 ms (large cards tend to longer)
do
{
rsp[0] = SDC_SendACMDR1(ACMD_SEND_OP_COND, 0UL);
if(rsp[0] & R1_BAD_RESPONSE)
{
printf("Bad Acmd41 R1=%02X.", rsp[0]);
result = SD_ERROR_BAD_RESPONSE;
goto end;
}
if(CheckDelay(timeout))
{
printf("Init timeout.");
result = SD_ERROR_INITIALIZE;
goto end;
}
} while(rsp[0] & R1_IDLE_STATE); // loop until idle state
 
if(rsp[0] != R1_NO_ERR)
{
printf("Init error.");
result = SD_ERROR_INITIALIZE;
goto end;
}
/* set block size to 512 bytes */
if(SDC_SendCMDR1(CMD_SET_BLOCKLEN, 512UL) != R1_NO_ERR)
{
printf("Error setting block length to 512.");
result = SD_ERROR_SET_BLOCKLEN;
goto end;
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: SDC_PutSector(void);
//
// Description: This function writes one sector of data to the SSC
//
//
// Returnvalue: none
//________________________________________________________________________________________________________________________________________
//SSC_Disable(); // set SD_CS high
// here is the right place to inrease the SPI baud rate to maximum
//SSC_Enable(); // set SD_CS high
 
u8 SDC_PutSector(u32 addr,u8*Buffer)
{
u8 tmp;
u8 CMD[] = {0x58,0x00,0x00,0x00,0x00,0xFF};
addr = addr << 9; // convert sectoradress to byteadress
CMD[1] = ((addr & 0xFF000000) >>24 );
CMD[2] = ((addr & 0x00FF0000) >>16 );
CMD[3] = ((addr & 0x0000FF00) >>8 );
// read CID register
result = SDC_GetCID((uint8_t *)&SDCardInfo.CID);
if(result != SD_SUCCESS)
{
printf("Error reading CID.\r\n");
goto end;
}
 
tmp = SDC_PutCommand (CMD); // send command to sdcard.
if (tmp != 0)
{
return(tmp);
// read CSD register
result = SDC_GetCSD((uint8_t *)&SDCardInfo.CSD);
if(result != SD_SUCCESS)
{
printf("Error reading CSD.");
goto end;
}
 
printf("ok\r\n");
 
uint8_t c_size_mult, read_bl_len;
uint32_t c_size;
 
switch(SDCardInfo.CSD[0]>>6) // check CSD Version
{
case 0x00: // if CSD is V1.0 structure (2GB limit)
 
/*
memory capacity = BLOCKNR * BLOCK_LEN
BLOCKNR = (C_SIZE+1) * MULT
MULT = 2^(C_SIZE_MULT+2)
BLOCK_LEN = 2^READ_BL_LEN
 
C_SIZE is 12 bits [73:62] in CSD register
C_SIZE_MULT is 3 bits [49:47] in CSD register
READ_BL_LEN is 4 bits [83:80] in CSD register
*/
 
read_bl_len = (SDCardInfo.CSD[5] & 0x0F); //CSD[05] -> [87:80]
c_size = ((uint32_t)(SDCardInfo.CSD[6] & 0x03))<<10; //CSD[06] -> [79:72]
c_size |= ((uint32_t)SDCardInfo.CSD[7])<<2; //CSD[07] -> [71:64]
c_size |= (uint32_t)(SDCardInfo.CSD[8]>>6); //CSD[08] -> [63:56]
c_size_mult = (SDCardInfo.CSD[9] & 0x03)<<1; //CSD[09] -> [55:48]
c_size_mult |=(SDCardInfo.CSD[10] & 0x80)>>7; //CSD[10] -> [47:40]
SDCardInfo.Capacity = (uint32_t)(c_size+1)*(1L<<(c_size_mult+2))*(1L<<read_bl_len);
break;
 
case 0x01: // if CSD is V2.0 structure (HC SD-Card > 2GB)
 
/*
memory capacity = (C_SIZE+1) * 512K byte
C_SIZE is 22 bits [69:48] in CSR register
*/
 
c_size = ((uint32_t)(SDCardInfo.CSD[7] & 0x3F))<<16; //CSD[07] -> [71:64]
c_size |= ((uint32_t)SDCardInfo.CSD[8])<<8; //CSD[08] -> [63:56]
c_size |= (uint32_t)SDCardInfo.CSD[9]; //CSD[09] -> [55:48];
SDCardInfo.Capacity = (c_size + 1)* 512L * 1024L;
break;
 
default: //unknown CSD Version
SDCardInfo.Capacity = 0;
break;
}
 
switch(SDCardInfo.Version)
{
case VER_1X:
printf(" SD-CARD V1.x");
break;
case VER_20:
printf(" SD-CARD V2.0 or later");
default:
break;
}
uint16_t mb_size = (uint16_t)(SDCardInfo.Capacity/(1024L*1024L));
printf("\r\n Capacity = %i MB", mb_size);
 
SDC_PrintCID((uint8_t *)&SDCardInfo.CID);
SDCardInfo.Valid = 1;
// jump point for error condition before
end:
SSC_Disable();
}
#ifdef SSC_RX_FIFO
SSC_ClearRxFifo();
#endif
for (u8 a=0;a<100;a++) // wait until sdcard is ready
else
{
SSC_GetChar();
SSC_Deinit();
SDCardInfo.Valid = 0;
result = SD_ERROR_NOCARD;
printf("No Card in Slot.");
}
SSC_PutChar(0xFE); // send start of header to the SSC
for (u16 a=0;a<512;a++) // transmitt one sector (normaly 512bytes) of data to the sdcard.
{
SSC_PutChar(*Buffer++);
}
SSC_PutChar(0xFF); // write two bytes of crc to the sdcard (not used in spi-mode)
SSC_PutChar(0xFF);
#ifdef SSC_RX_FIFO
SSC_ClearRxFifo();
#endif
while (SSC_GetChar() != 0xff){}; // wait untile the sdcard is ready.
SSC_Disable(); // disable sdcard.
 
return(0);
return(result);
}
 
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: SDC_GetSector(u32 addr,u8*Buffer);
//
// Description: This function reads one sector of data from the SSC
//
// Function: SDC_Deinit(void);
//
// Returnvalue: none
// Description: This function deinitialises the SDCard interface.
//
//
// Returnvalue: the function returns 0 if the initialisation was successfull otherwise the function returns an errorcode.
//________________________________________________________________________________________________________________________________________
 
u8 SDC_GetSector(u32 addr,u8*Buffer)
{
u8 CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF};
addr = addr << 9; // convert sectoradress to byteadress.
SD_Result_t SDC_Deinit(void)
{
printf("\r\n SDC deinit...");
SSC_Deinit();
 
CMD[1] = ((addr & 0xFF000000) >>24 );
CMD[2] = ((addr & 0x00FF0000) >>16 );
CMD[3] = ((addr & 0x0000FF00) >>8 );
SDCardInfo.Valid = 0;
SDCardInfo.Capacity = 0;
SDCardInfo.Version = VER_UNKNOWN;
 
SDC_GetBlock(CMD,Buffer,512); // read specified sector from sdcard.
 
return(0);
printf("ok");
return(SD_SUCCESS);
}
 
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: SDC_GetBlock(void);
//
// Description: This function reads one block of data of s16 bytes from the SSC.
//
// Function: SDC_PutSector(uint32_t addr, const uint8_t *Buffer)
//
// Returnvalue: the function returns 0 if the initialisation was successfull otherwise the function returns an errorcode.
// Description: This function writes one sector of data to the SSC
//
//
// Returnvalue: SD_Result_t
//________________________________________________________________________________________________________________________________________
 
void SDC_GetBlock(u8*CMD,u8*Buffer,u16 Bytes)
{
if (SDC_PutCommand (CMD) != 0) // Send command to the sdcard.
SD_Result_t SDC_PutSector(uint32_t addr, const uint8_t *Buffer)
{
uint8_t rsp;
uint16_t a, crc16;
uint16_t timeout = 0;
SD_Result_t result = SD_ERROR_UNKNOWN;
 
addr = addr << 9; // convert sectoradress to byteadress
rsp = SDC_SendCMDR1(CMD_WRITE_SINGLE_BLOCK, addr);
if (rsp != R1_NO_ERR)
{
return;
result = SD_ERROR_BAD_RESPONSE;
goto end;
}
#ifdef SSC_RX_FIFO
SSC_ClearRxFifo();
#endif
while (SSC_GetChar() != 0xfe){}; // wait until the sdcard is ready to transmitt data.
for (u16 a=0;a<Bytes;a++) // read the block from the SSC (normaly 512Bytes)
 
for (a=0;a<20;a++) // at least one byte
{
*Buffer++ = SSC_GetChar();
SSC_GetChar();
}
SSC_GetChar(); // Read two bytes CRC- checksum (not used in spi-mode)
SSC_GetChar();
SSC_Disable(); // disable sdcard.
crc16 = CRC16(Buffer, 512); // calc checksum for data block
SSC_PutChar(DATA_START_TOKEN); // send data start of header to the SSC
 
for (a=0;a<512;a++) // transmit one sector (normaly 512bytes) of data to the sdcard.
{
SSC_PutChar(Buffer[a]);
}
// write two bytes of crc16 to the sdcard
SSC_PutChar((uint8_t)(crc16>>8)); // write high byte first
SSC_PutChar((uint8_t)(0x00FF&crc16)); // lowbyte last
 
do // wait for data response token
{
rsp = SSC_GetChar();
if(timeout++ > 500)
{
result = SD_ERROR_TIMEOUT;
goto end;
}
}while((rsp & 0x11) != 0x01 );
// analyse data response token
switch(rsp & DATA_RESPONSE_MASK)
{
case DATA_RESPONSE_OK:
result = SD_SUCCESS;
break;
case DATA_RESPONSE_CRC_ERR:
result = SD_ERROR_CRC_DATA;
goto end;
break;
case DATA_RESPONSE_WRITE_ERR:
result = SD_ERROR_WRITE_DATA;
goto end;
break;
default:
result = SD_ERROR_UNKNOWN;
goto end;
break;
 
}
// wait 2 seconds until the sdcard is busy.
rsp = SDC_WaitForBusy(2000);
if(rsp != 0xFF)
{
result = SD_ERROR_TIMEOUT;
goto end;
}
 
// check card status
rsp = SDC_SendCMDR1(CMD_SEND_STATUS, 0);
// first byte of R2 response is like R1 response
if(rsp != R1_NO_ERR)
{
result = SD_ERROR_BAD_RESPONSE;
SSC_GetChar(); // read out 2nd byte
goto end;
}
// 2nd byte of r2 response
rsp = SSC_GetChar();
if(rsp != R2_NO_ERR)
{
result = SD_ERROR_WRITE_DATA;
SSC_GetChar();
goto end;
}
end:
if(result != SD_SUCCESS)
{
printf("Error %02X writing data to sd card (R=%02X).\r\n", result, rsp);
}
return(result);
}
 
 
 
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_GetSector(uint32_t addr,uint8_t *Buffer);
//
// Description: This function reads one sector of data from the SSC
//
//
// Returnvalue: SD_Result_t
//________________________________________________________________________________________________________________________________________
 
SD_Result_t SDC_GetSector(uint32_t addr,uint8_t *Buffer)
{
addr = addr << 9; // convert sectoradress to byteadress
return SDC_GetData(CMD_READ_SINGLE_BLOCK, addr, Buffer, 512);
}
 
/FollowMe/sdc.h
1,33 → 1,30
#ifndef _SDC_H_
#define _SDC_H_
 
extern u8 SDC_Init(void);
#include <inttypes.h>
 
//________________________________________________________________________________________________________________________________________
//
// Functions needed for access to the sdcard.
//
//________________________________________________________________________________________________________________________________________
typedef enum
{
SD_SUCCESS = 0,
SD_ERROR_NOCARD,
SD_ERROR_RESET,
SD_ERROR_INITIALIZE,
SD_ERROR_BAD_RESPONSE,
SD_ERROR_BAD_VOLTAGE_RANGE,
SD_ERROR_NO_SDCARD,
SD_ERROR_TIMEOUT,
SD_ERROR_CRC_DATA,
SD_ERROR_WRITE_DATA,
SD_ERROR_READ_DATA,
SD_ERROR_SET_BLOCKLEN,
SD_ERROR_UNKNOWN
} SD_Result_t;
 
extern u8 SSC_GetChar(void);
extern void SSC_PutChar(u8);
extern void MMC_Read_Block(u8 *,u8 *,u16);
extern SD_Result_t SDC_Init(void);
extern SD_Result_t SDC_GetSector (uint32_t Addr, uint8_t *pBuffer);
extern SD_Result_t SDC_PutSector (uint32_t Addr, const uint8_t *pBuffer);
extern SD_Result_t SDC_Deinit(void);
 
 
//________________________________________________________________________________________________________________________________________
//
// Functions needed internaly for the fat16 implementation
//
//________________________________________________________________________________________________________________________________________
 
extern u8 SDC_GetSector (u32,u8 *);
extern u8 SDC_PutSector (u32,u8 *);
extern u8 SDC_PutCommand (u8 *);
extern void SDC_GetBlock(u8 *CMD,u8 *Buffer,u16 Bytes);
 
 
#define nop() __asm__ __volatile__ ("nop" ::)
 
#endif
 
 
/FollowMe/ssc.c
1,34 → 1,80
 
#include <avr/io.h>
#include "fat16.h"
#include "ssc.h"
 
//________________________________________________________________________________________________________________________________________
// Module name: fat16.c
// Compiler used: avr-gcc 3.4.5
// Last Modifikation: 24.07.2007
// Version: 1.03
// Authors: Stephan Busker
// Description: Source files for access to the synchrnous serial channel.
// Copyright (C) 2007 Stephan Busker
//........................................................................................................................................
// Functions: extern void SSC_Init(void);
// extern u8 SSC_GetChar (void);
// extern void SSC_PutChar (u8 Byte);
// extern void SSC_Disable(void);
// extern void SSC_Enable(void);
//........................................................................................................................................
// ext. functions: extern u8 SDC_GetSector (u32,u8*);
// extern u8 SDC_PutSector (u32,u8*);
//........................................................................................................................................
//
// URL: www.Mikro-Control.de
// mailto: stephan.busker@mikro-control.de
//________________________________________________________________________________________________________________________________________
 
 
//-------------------------------------- Hardware specific definitions --------------------------------------
#define PORTR_SPI PINB
#define PORTW_SPI PORTB //Port to which the sd-card is connected (SPI Port)
#define PORT_MISO PORTB6 //Port Pin that is connected to the DO of the MMC/SD-card
#define PORT_MOSI PORTB5 //Port Pin that is connected to DI of the MMC/SD-card
#define PORT_SCK PORTB7 //Port Pin that is connected the CLK of the MMC/SD-card
#define PORT_SS PORTB4 //Slave Select is not used in SPI Master Mode, but must be defined
#define PORT_CS PORTB4 //Port Pin that is connected to /CS of the MMC/SD-Karte
 
 
#ifdef USE_SDLOGGER
#define __SD_INTERFACE_INVERTED // the interface between the controller and the SD-card uses an inverting leveltranslator (transistorinverter)
#endif // and therefore the signals to or from the memorycard have to be inverted.
 
#ifdef USE_FOLLOWME // uses resitors, therefore its not inverted
//#define __SD_INTERFACE_INVERTED // the interface between the controller and the MMC/SD-card uses an inverting leveltranslator (transistorinverter)
#endif
 
#define DDR_SPI DDRB
#define DD_MISO DDB6 //Port Pin that is connected to the DO of the MMC/SD-card
#define DD_MOSI DDB5 //Port Pin that is connected to DI of the MMC/SD-card
#define DD_SCK DDB7 //Port Pin that is connected the CLK of the MMC/SD-card
#define DD_SS DDB4 //Slave Select is not used in SPI Master Mode, but must be defined
#define DD_CS DDB4 //Port Pin that is connected to /CS of the MMC/SD-Karte
 
// for compatibility reasons gcc3.x <-> gcc4.x
#ifndef SPCR
#define SPCR SPCR0
#endif
#ifndef SPIE
#define SPIE SPIE0
#endif
#ifndef SPE
#define SPE SPE0
#endif
#ifndef DORD
#define DORD DORD0
#endif
#ifndef MSTR
#define MSTR MSTR0
#endif
#ifndef CPOL
#define CPOL CPOL0
#endif
#ifndef CPHA
#define CPHA CPHA0
#endif
#ifndef SPR1
#define SPR1 SPR01
#endif
#ifndef SPR0
#define SPR0 SPR00
#endif
 
#ifndef SPDR
#define SPDR SPDR0
#endif
 
#ifndef SPSR
#define SPSR SPSR0
#endif
#ifndef SPIF
#define SPIF SPIF0
#endif
#ifndef WCOL
#define WCOL WCOL0
#endif
#ifndef SPI2X
#define SPI2X SPI2X0
#endif
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: SSC_Init(void);
//
40,44 → 86,40
 
void SSC_Init(void)
{
MMC_Direction_REG &=~(1<<SPI_DI); // Set the direction of the ssc-port
MMC_Direction_REG |= (1<<SPI_Clock); // _______ _______
MMC_Direction_REG |= (1<<SPI_DO); // CS \________________________/
MMC_Direction_REG |= (1<<MMC_Chip_Select); //
MMC_Direction_REG |= (1<<SPI_SS); // ___ ___ ___
// clk __________/ \___/ \___/ \_________
//
SSC_Disable(); // ___ ___
// data_________/ \___________/ \___________
// Set MOSI,SCK and CS as output
DDR_SPI |= (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_CS);
// set MISO as input
DDR_SPI &= ~(1<<DD_MISO);
 
// initialise ssc, clock = Idel low
// devide clock by 32
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<CPOL); // Enable SSC in mastermode, invert clockpolarity (idle high)
SPSR = SPSR|(1<<SPI2X);
}
SSC_Disable();
 
// 20MHz / 32 = 625 kHz
#ifdef __SD_INTERFACE_INVERTED
SPCR = (1<<SPE)|(1<<MSTR)|(0<<DORD)|(1<<CPOL)|(0<<CPHA)|(1<<SPR1)|(1<<SPR0); // Enable SSC in mastermode, inverted clockpolarity (idle high)
#else
SPCR = (1<<SPE)|(1<<MSTR)|(0<<DORD)|(0<<CPOL)|(0<<CPHA)|(1<<SPR1)|(1<<SPR0); // Enable SSC in mastermode, noninverted clockpolarity (idle low)
#endif
SPSR |= (1<<SPI2X);
 
// set port pin as input pullup for SD-Card switch
#ifdef USE_FOLLOWME
PORTB |= (1 << PORTB2);
DDRB &= ~(1 << DDB2);
#endif
 
#ifdef USE_SDLOGGER
PORTB |= (1 << PORTB3);
DDRB &= ~(1 << DDB3);
#endif
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: void SSC_ClearRxFifo(void);
//
// Description: Clears the fifo of the ssc if the controller used has a builtin fifo.
//
//
// Returnvalue: none
//________________________________________________________________________________________________________________________________________
void SSC_Deinit(void)
{
 
 
void SSC_ClearRxFifo(void)
{
// enter your code here to clear the rx-fifo of the ssc.
}
 
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: SSC_GetChar(void);
// Function: SSC_GetChar(void);
//
// Description: This function reads one byte from the SSC
//
85,26 → 127,31
// Returnvalue: the byte received.
//________________________________________________________________________________________________________________________________________
 
u8 SSC_GetChar (void)
uint8_t SSC_GetChar (void)
{
u8 Byte = 0;
uint8_t Byte = 0;
 
SPDR = 0x00; // read one byte of data from the SSC
while(!(SPSR & (1<<SPIF))){}; // wait until the data has been read.
#ifdef __SD_INTERFACE_INVERTED
SPDR = 0x00; // send dummy byte to initiate the reading
#else
SPDR = 0xFF; // send dummy byte to initiate the reading
#endif
while(!(SPSR & (1<<SPIF)))
{
// wait until the data has been read.
}
Byte = SPDR;
 
#ifdef __MMC_INTERFACE_INVERTED
return (~Byte);
#else
return (Byte); // the byte received
#ifdef __SD_INTERFACE_INVERTED
Byte = ~Byte;
#endif
 
 
return(Byte);
}
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: SSC_PutChar(u8 Byte);
// Function: SSC_PutChar(u8 Byte);
//
// Description: This function writes one byte to the SSC
//
112,22 → 159,23
// Returnvalue: none
//________________________________________________________________________________________________________________________________________
 
void SSC_PutChar (u8 Byte)
void SSC_PutChar (uint8_t Byte)
{
#ifdef __MMC_INTERFACE_INVERTED
 
#ifdef __SD_INTERFACE_INVERTED
SPDR = ~Byte; // send one byte of data to the SSC
#else
SPDR = Byte; // send one byte of data to the SSC
#endif
SPDR = ~Byte; // send one byte of data to the SSC
while(!(SPSR & (1<<SPIF))) // wait until data was send.
while(!(SPSR & (1<<SPIF)))
{
// wait until the data has been sent.
}
}
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: SSC_Disable(void);
// Function: SSC_Disable(void);
//
// Description: This function enables chipselect of the sdcard (active low)
//
137,10 → 185,10
 
void SSC_Disable(void)
{
#ifdef __MMC_INTERFACE_INVERTED
MMC_Write &= ~(1<<MMC_Chip_Select); // disable chipselect of the sdcard (active low).
#ifdef __SD_INTERFACE_INVERTED
PORTW_SPI &= ~(1<<PORT_CS); // disable chipselect of the sdcard (active low).
#else
MMC_Write |= (1<<MMC_Chip_Select); // enable chipselect of the sdcard (active low).
PORTW_SPI |= (1<<PORT_CS); // disable chipselect of the sdcard (active low).
#endif
}
 
148,7 → 196,7
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: SSC_Enable(void);
// Function: SSC_Enable(void);
//
// Description: This function disables chipselect of the sdcard (active low)
//
158,10 → 206,11
 
void SSC_Enable(void)
{
#ifdef __MMC_INTERFACE_INVERTED
MMC_Write |= (1<<MMC_Chip_Select); // enable chipselect of the sdcard (active low).
#ifdef __SD_INTERFACE_INVERTED
PORTW_SPI |= (1<<PORT_CS); // enable chipselect of the sdcard (active low).
#else
MMC_Write &= ~(1<<MMC_Chip_Select); // disable chipselect of the sdcard (active low).
PORTW_SPI &= ~(1<<PORT_CS); // enable chipselect of the sdcard (active low).
#endif
}
 
 
/FollowMe/ssc.h
1,42 → 1,20
#ifndef __SSC_H
#define __SSC_H
 
#include <inttypes.h>
 
//-------------------------------------- Hardware specific definitions --------------------------------------
 
#define MMC_Write PORTB //Port an der die MMC/SD-card angeschlossen ist (SPI Port)
#define MMC_Read PINB
#define MMC_Direction_REG DDRB
 
 
#ifdef USE_FOLLOWME
#define SD_SWITCH !(PINB & (1<<PINB2))
#endif
#ifdef USE_SDLOGGER
#define __MMC_INTERFACE_INVERTED // the interface between the controller and the MMC/SD-card uses an inverting leveltranslator (transistorinverter)
#endif // and therefore the signals to or from the memorycard have to be inverted.
 
#ifdef USE_FOLLOWME // uses resitors, therefore its not inverted
//#define __MMC_INTERFACE_INVERTED // the interface between the controller and the MMC/SD-card uses an inverting leveltranslator (transistorinverter)
#define SD_SWITCH !(PINB & (1<<PINB3))
#endif
 
#define SPI_DI 6 //Port Pin that is connected to the DO of the MMC/SD-card
#define SPI_DO 5 //Port Pin that is connected to DI of the MMC/SD-card
#define SPI_Clock 7 //Port Pin that is connected the CLK of the MMC/SD-card
#define SPI_SS 4 //Slave Select is not used in SPI Master Mode, but must be defined
#define MMC_Chip_Select 4 //Port Pin an dem Chip Select der MMC/SD-Karte angeschlossen ist
extern void SSC_Init(void);
extern uint8_t SSC_GetChar(void);
extern void SSC_PutChar(uint8_t);
extern void SSC_Enable(void);
extern void SSC_Disable(void);
extern void SSC_Deinit(void);
 
 
//________________________________________________________________________________________________________________________________________
//
// Functions needed for accessing the sdcard.
//
//________________________________________________________________________________________________________________________________________
 
extern void SSC_Init(void);
extern u8 SSC_GetChar (void);
extern void SSC_PutChar (u8);
extern void SSC_Enable(void);
extern void SSC_Disable(void);
extern void SSC_ClearRxFifo(void);
 
 
 
#endif
#endif //__SSC_H