Subversion Repositories NaviCtrl

Rev

Rev 516 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*#######################################################################################*/
/* !!! THIS IS NOT FREE SOFTWARE !!!                                                     */
/*#######################################################################################*/
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + www.MikroKopter.com
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Software Nutzungsbedingungen (english version: see below)
// + der Fa. HiSystems GmbH, Flachsmeerstrasse 2, 26802 Moormerland - nachfolgend Lizenzgeber genannt -
// + Der Lizenzgeber räumt dem Kunden ein nicht-ausschließliches, zeitlich und räumlich* unbeschränktes Recht ein, die im den
// + Mikrocontroller verwendete Firmware für die Hardware Flight-Ctrl, Navi-Ctrl, BL-Ctrl, MK3Mag & PC-Programm MikroKopter-Tool
// + - nachfolgend Software genannt - nur für private Zwecke zu nutzen.
// + Der Einsatz dieser Software ist nur auf oder mit Produkten des Lizenzgebers zulässig.
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Die vom Lizenzgeber gelieferte Software ist urheberrechtlich geschützt. Alle Rechte an der Software sowie an sonstigen im
// + Rahmen der Vertragsanbahnung und Vertragsdurchführung überlassenen Unterlagen stehen im Verhältnis der Vertragspartner ausschließlich dem Lizenzgeber zu.
// + Die in der Software enthaltenen Copyright-Vermerke, Markenzeichen, andere Rechtsvorbehalte, Seriennummern sowie
// + sonstige der Programmidentifikation dienenden Merkmale dürfen vom Kunden nicht verändert oder unkenntlich gemacht werden.
// + Der Kunde trifft angemessene Vorkehrungen für den sicheren Einsatz der Software. Er wird die Software gründlich auf deren
// + Verwendbarkeit zu dem von ihm beabsichtigten Zweck testen, bevor er diese operativ einsetzt.
// + Die Haftung des Lizenzgebers wird - soweit gesetzlich zulässig - begrenzt in Höhe des typischen und vorhersehbaren
// + Schadens. Die gesetzliche Haftung bei Personenschäden und nach dem Produkthaftungsgesetz bleibt unberührt. Dem Lizenzgeber steht jedoch der Einwand
// + des Mitverschuldens offen.
// + Der Kunde trifft angemessene Vorkehrungen für den Fall, dass die Software ganz oder teilweise nicht ordnungsgemäß arbeitet.
// + Er wird die Software gründlich auf deren Verwendbarkeit zu dem von ihm beabsichtigten Zweck testen, bevor er diese operativ einsetzt.
// + Der Kunde wird er seine Daten vor Einsatz der Software nach dem Stand der Technik sichern.
// + Der Kunde ist darüber unterrichtet, dass der Lizenzgeber seine Daten im zur Vertragsdurchführung erforderlichen Umfang
// + und auf Grundlage der Datenschutzvorschriften erhebt, speichert, verarbeitet und, sofern notwendig, an Dritte übermittelt.
// + *) Die räumliche Nutzung bezieht sich nur auf den Einsatzort, nicht auf die Reichweite der programmierten Software.
// + #### ENDE DER NUTZUNGSBEDINGUNGEN ####'
// +  Hinweis: Informationen über erweiterte Nutzungsrechte (wie z.B. Nutzung für nicht-private Zwecke) sind auf Anfrage per Email an info(@)hisystems.de verfügbar.
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Software LICENSING TERMS
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + of HiSystems GmbH, Flachsmeerstrasse 2, 26802 Moormerland, Germany - the Licensor -
// + The Licensor grants the customer a non-exclusive license to use the microcontroller firmware of the Flight-Ctrl, Navi-Ctrl, BL-Ctrl, and MK3Mag hardware
// + (the Software) exclusively for private purposes. The License is unrestricted with respect to time and territory*.
// + The Software may only be used with the Licensor's products.
// + The Software provided by the Licensor is protected by copyright. With respect to the relationship between the parties to this
// + agreement, all rights pertaining to the Software and other documents provided during the preparation and execution of this
// + agreement shall be the property of the Licensor.
// + The information contained in the Software copyright notices, trademarks, other legal reservations, serial numbers and other
// + features that can be used to identify the program may not be altered or defaced by the customer.
// + The customer shall be responsible for taking reasonable precautions
// + for the safe use of the Software. The customer shall test the Software thoroughly regarding its suitability for the
// + intended purpose before implementing it for actual operation. The Licensor's liability shall be limited to the extent of typical and
// + foreseeable damage to the extent permitted by law, notwithstanding statutory liability for bodily injury and product
// + liability. However, the Licensor shall be entitled to the defense of contributory negligence.
// + The customer will take adequate precautions in the case, that the software is not working properly. The customer will test
// + the software for his purpose before any operational usage. The customer will backup his data before using the software.
// + The customer understands that the Licensor collects, stores and processes, and, where required, forwards, customer data
// + to third parties to the extent necessary for executing the agreement, subject to applicable data protection and privacy regulations.
// + *) The territory aspect only refers to the place where the Software is used, not its programmed range.
// + #### END OF LICENSING TERMS ####
// + Note: For information on license extensions (e.g. commercial use), please contact us at info(@)hisystems.de.
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#include <stdio.h>
#include <string.h>
#include "91x_lib.h"
#include "uart1.h"
#include "sdc.h"
#include "ssc.h"
#include "timer1.h"
#include "main.h"
#include "crc16.h"



//________________________________________________________________________________________________________________________________________
// Module name:                 sdc.c
// Compiler used:               avr-gcc 3.4.5
// Last Modifikation:   08.06.2008
// Version:                             1.07
// Authors:                             Stephan Busker, Gregor Stobrawa        
// Description:                 Source files for connecting to an sd-card using the SSC
//
//........................................................................................................................................
// Functions:                   SD_Result_t     SDC_init(void);
//                                              u8                      SDC_PutCommand (u8 *cmd);
//                                              SD_Result_t     SDC_PutSector(u32 addr,u8 *Buffer);
//                                              SD_Result_t     SDC_GetSector(u32 addr,u8 *Buffer);
//
////........................................................................................................................................
// 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);
//                                              extern void     SSC_ClearRxFifo();
//........................................................................................................................................
//
// URL:                                 www.Mikro-Control.de
// mailto:                              stephan.busker@mikro-control.de
//________________________________________________________________________________________________________________________________________



#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

volatile SDCardInfo_t SDCardInfo;
u8 SDCardWriteRetryCounterMax;


//________________________________________________________________________________________________________________________________________
// Function:    CRC7(u8* cmd, u32 len);
//
// Description: This function calculated the CRC7 checksum used in the last byte of a spi command frame.
//                             
//
// Returnvalue: the function returns the crc7 including bit 0 set to 1
//________________________________________________________________________________________________________________________________________

u8 CRC7(u8 * cmd, u32 len)
{
        u8 i, a;
        u8 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);
}

u8 SDC_WaitForBusy(u32 timeout)
{
        u8 rsp = 0;
        u32 timestamp = 0;

        SSC_ClearRxFifo();
        SSC_Enable();                           // enable chipselect.  SSC_Disable
        timestamp = SetDelay(timeout);
        do     
        {
                rsp = SSC_GetChar();
                if(CheckDelay(timestamp))  break;
        }while(rsp != 0xFF);            // wait while card is busy (data out low)
        return(rsp);
}



//________________________________________________________________________________________________________________________________________
// Function:    SDC_SendCMDR1(u8 CmdNo, u32 arg);
//
// 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_SendCMDR1(u8 CmdNo, u32 arg)
{
        u8 r1;
        u16 timeout = 0;
        u16 a;
        u8 cmd[6];

        SSC_ClearRxFifo();      // clear the rx fifo
        SSC_Enable();           // enable chipselect.
        SDC_WaitForBusy(600);   // wait 500ms until card is busy
        SSC_ClearRxFifo();      // clear the rx fifo
        SSC_GetChar();      // dummy to sync

        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
        for (a = 0;a < 6; a++) // send the command sequence to the sdcard (6 bytes)
        {      
                SSC_PutChar(cmd[a]);
        }
        SSC_ClearRxFifo();      // clear the rx fifo to discard the bytes received during the transmission of the 6 command bytes

        do                                     
        {
                r1 = SSC_GetChar();       // get byte from sd-card
                if (timeout++ >500) break;
        }while(r1 == 0xFF); // wait for the response byte from sd-card.
        return(r1);
}


//________________________________________________________________________________________________________________________________________
// Function:    SDC_SendACMDR1(u8 CmdNo, u32 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
//________________________________________________________________________________________________________________________________________
u8 SDC_SendACMDR1(u8 CmdNo, u32 arg)
{
        u8 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(u8 * cmd ,u8 *Buffer, u32 len);
//
// Description: This function sneds cmd an reads a datablock of len from the sd-card
//                             
//
// Returnvalue: SD_Result_t
//________________________________________________________________________________________________________________________________________

SD_Result_t SDC_GetData(u8 CmdNo, u32 addr, u8 *Buffer, u32 len)
{
        u8 rsp;        
        u16 a, crc16;
        u32 timeout;
        SD_Result_t result = SD_ERROR_UNKNOWN;

        // send the command    
        rsp = SDC_SendCMDR1(CmdNo, addr);
        if (rsp != R1_NO_ERR)
        {
                result = SD_ERROR_BAD_RESPONSE;
                goto end;
        }
        SSC_ClearRxFifo();
        timeout = SetDelay(500);
        do
        {
                rsp = SSC_GetChar();
                if( ( (rsp & 0xF0) == 0x00 ) || CheckDelay(timeout) ) // data error token or timeout
                {
                        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();
        }
        // 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:
        SSC_Disable();   // disable CS
        if(result != SD_SUCCESS)
        {
                sprintf(text,"Error %02X reading data from sd card (R1=%02X).\r\n", result, rsp);
                UART1_PutString(text);
        }
        return(result);
}


//________________________________________________________________________________________________________________________________________
// 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(u8 * pCID)
{
        u8 pn[6];
        u16 temp1, temp2;

        sprintf(text, "\r\n Manufacturer ID: %i\r\n", pCID[0]);
        UART1_PutString(text);
        memcpy(pn, &pCID[1], 2);
        pn[2] = '\0'; // terminate string
        sprintf(text, " Application ID: %s\r\n",pn);
        UART1_PutString(text);
        memcpy(pn, &pCID[3], 5);
        pn[5] = '\0'; // terminate string
        sprintf(text, " Product Name: %s\r\n",pn);
        UART1_PutString(text);
        sprintf(text, " Product Rev.: %i.%i\r\n",pCID[8]>>4, pCID[8]&0xF);
        UART1_PutString(text);
        UART1_PutString(" Serial No.: ");
        for(temp1 = 0; temp1<4; temp1++)
        {
                sprintf(text,"%02X", pCID[9+temp1]);
                UART1_PutString(text);
        }
        UART1_PutString("\r\n");
        temp1 = pCID[14] & 0x0F;    // month
        temp2 = ((pCID[14]>>4)|(pCID[13]<<4)) + 2000; // year
        sprintf(text, " Manufac. Date: %i/%i\r\n\r\n",temp1, temp2);
        UART1_PutString(text);
}

//________________________________________________________________________________________________________________________________________
// Funtion:     SDC_GetCID(u8 * 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(u8 * pCID)
{
        return SDC_GetData(CMD_SEND_CID, 0UL, pCID, 16);
}

//________________________________________________________________________________________________________________________________________
// Funtion:     SDC_GetCSD(u8 * 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(u8 * pCSD)
{
        return SDC_GetData(CMD_SEND_CSD, 0UL, pCSD, 16);
}

//________________________________________________________________________________________________________________________________________
// Funtion:     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.
//________________________________________________________________________________________________________________________________________

SD_Result_t SDC_Init(unsigned char print)
{
        u32 timeout = 0;
        u16 speed;
        u8 rsp[6]; // SD-SPI response buffer
        SD_Result_t result = SD_ERROR_UNKNOWN;
        if(SPI_Speed < 500) SPI_Speed = 500; // nur zur Sicherheit
        speed = SPI_Speed; // weil das bei SSC_Init() auf 400 gesetzt werden würde

        //SDCardWriteRetryCounterMax = 0;
               
        if(SD_SWITCH) // init only if the SD-Switch is indicating a card in the slot
        {
                if(print)               UART1_PutString("\r\n SSC init...");
                SSC_Init();
                if(print)               UART1_PutString("ok");

                if(print)               UART1_PutString("\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
                SSC_ClearRxFifo();      // clear the rx fifo
       
                for (timeout = 0; timeout < 15; timeout++)      // 15*8 = 120 cycles
                {
                        SSC_PutChar(0xFF);
                }
       
                // switch to idle state
                while(SDC_SendCMDR1(CMD_GO_IDLE_STATE, 0UL) != R1_IDLE_STATE)                                          
                {
                        if (timeout++ > 20)
                        {
                                UART1_PutString("reset timeout");
                                result = SD_ERROR_RESET;
                                goto end;                                                                              
                        }
                }
            // enable crc feature
/*              if(SDC_SendCMDR1(CMD_CRC_ON_OFF, 1UL) != R1_IDLE_STATE)
                {
                                sprintf(text,"Bad cmd59 R1=%02X.", rsp[0]);
                                UART1_PutString(text);
                                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)
                {
                        sprintf(text,"Bad cmd8 R1=%02X.", rsp[0]);
                        UART1_PutString(text);
                        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)
                   {
                                UART1_PutString("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
                   {
                               
                                UART1_PutString("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)
                {
                        sprintf(text,"Bad cmd58 R1 %02x.", rsp[0]);
                        UART1_PutString(text);
                        result = SD_ERROR_BAD_RESPONSE;
                        goto end;
                }
                if(rsp[0] & R1_ILLEGAL_CMD)
                {
                        UART1_PutString("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();
                }
                //      NavicCtrl uses 3.3 V,  therefore check for bit 20 & 21
                if((rsp[2] & 0x30) != 0x30)
                {
                        // supply voltage is not supported by sd-card
                        UART1_PutString("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)
                        {
                                sprintf(text,"Bad Acmd41 R1=%02X.", rsp[0]);
                                UART1_PutString(text);
                                result = SD_ERROR_BAD_RESPONSE;
                                goto end;
                        }
                        if(CheckDelay(timeout))
                        {
                            UART1_PutString("Init timeout.");
                                result = SD_ERROR_INITIALIZE;
                                goto end;
                        }
                } while(rsp[0] & R1_IDLE_STATE); // loop until idle state
               
                if(rsp[0] != R1_NO_ERR)
                {
                        UART1_PutString("Init error.");
                        result = SD_ERROR_INITIALIZE;
                        goto end;      
                }
                /* set block size to 512 bytes */
        if(SDC_SendCMDR1(CMD_SET_BLOCKLEN, 512UL) != R1_NO_ERR)
        {
                UART1_PutString("Error setting block length to 512.");
                        result = SD_ERROR_SET_BLOCKLEN;
                        goto end;
        }
               
                SSC_Disable(); // set SD_CS high                                                                         
                // here is the right place to inrease the SPI baud rate to maximum             

        SSC_Speed(speed);
                if(print) { sprintf(text,"\r\n Setting SPI speed to %d ", SPI_Speed);UART1_PutString(text); }
               
        SSC_Enable(); // set SD_CS high

               // read CID register
               result = SDC_GetCID((u8 *)&SDCardInfo.CID);
               if(result != SD_SUCCESS)
               {
                       
                                if(print) UART1_PutString(" failed - Set interface to low speed...");
                       SSC_Disable(); // set SD_CS high                                                                          
                       // here is the right place to inrease the SPI baud rate to maximum                
                       SPI_Speed = 1000;
                                           SSC_Speed(SPI_Speed);
                       SSC_Enable(); // set SD_CS high
                       result = SDC_GetCID((u8 *)&SDCardInfo.CID);
               }
       
               if(result != SD_SUCCESS)
               {
                       UART1_PutString("Error reading CID.\r\n");
                       goto end;
               }

       
                // read CSD register
                result = SDC_GetCSD((u8 *)&SDCardInfo.CSD);
                if(result != SD_SUCCESS)
                {
                        UART1_PutString("Error reading CSD.");
                        goto end;
                }
       
                if(print) UART1_PutString("ok\r\n");
       
                u8 c_size_mult, read_bl_len;
                u32 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 = ((u32)(SDCardInfo.CSD[6] & 0x03))<<10; //CSD[06] -> [79:72]
                        c_size |= ((u32)SDCardInfo.CSD[7])<<2;                  //CSD[07] -> [71:64]
                        c_size |= (u32)(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 = (u32)(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 = ((u32)(SDCardInfo.CSD[7] & 0x3F))<<16; //CSD[07] -> [71:64]
                        c_size |= ((u32)SDCardInfo.CSD[8])<<8;                  //CSD[08] -> [63:56]
                        c_size |= (u32)SDCardInfo.CSD[9];                               //CSD[09] -> [55:48];
                        SDCardInfo.Capacity = (c_size + 1)* 512L * 1024L;
                        break;
       
                default: //unknown CSD Version
                        SDCardInfo.Capacity = 0;
                        break; 
                }
       
                if(print) switch(SDCardInfo.Version)
                {
                        case VER_1X:
                                UART1_PutString(" SD-CARD V1.x");
                                break;
                        case VER_20:
                                UART1_PutString(" SD-CARD V2.0 or later");
                        default:
                                break;
                }
                if(print)
                {
                 u16 mb_size = (u16)(SDCardInfo.Capacity/(1024L*1024L));
                 sprintf(text, "\r\n Capacity = %i MB", mb_size);
                 UART1_PutString(text);
                }
       
                if(print) SDC_PrintCID((u8 *)&SDCardInfo.CID);
                SDCardInfo.Valid = 1;
                // jump point for error condition before
                end:
                //SSC_Disable();
                ;
        }
        else
        {
                SSC_Deinit();
                SDCardInfo.Valid = 0;
                result = SD_ERROR_NOCARD;
                UART1_PutString("No Card in Slot.");
        }
        return(result);
}


//________________________________________________________________________________________________________________________________________
// Funtion:     SDC_Deinit(void);
//
// Description: This function deinitialises the SDCard interface.
//                             
//
// Returnvalue: the function returns 0 if the deinitialisation was successfull otherwise the function returns an errorcode.
//________________________________________________________________________________________________________________________________________

SD_Result_t SDC_Deinit(void)
{
        UART1_PutString("\r\n SDC deinit...");
        // SSC_Deinit();

        SDCardInfo.Valid = 0;
        SDCardInfo.Capacity = 0;
        SDCardInfo.Version = VER_UNKNOWN;

        UART1_PutString("ok");
        return(SD_SUCCESS);
}


//________________________________________________________________________________________________________________________________________
// Funtion:     SDC_PutSector(void);
//
// Description: This function writes one sector of data to the SSC
//                             
//
// Returnvalue: SD_Result_t
//________________________________________________________________________________________________________________________________________

SD_Result_t SDC_PutSector(u32 addr, const u8 *Buffer)
{
    u8 retryCounter = 0;
    u8 rsp;
        u16 a, crc16;
        u16 timeout = 0;
        SD_Result_t result;

        addr = addr << 9; // convert sectoradress to byteadress
 
  while(retryCounter < 10)
  {    
    result = SD_ERROR_UNKNOWN;

        rsp = SDC_SendCMDR1(CMD_WRITE_SINGLE_BLOCK, addr);
        if (rsp != R1_NO_ERR)
        {
                result = SD_ERROR_BAD_RESPONSE;
                goto end;
        }
        SSC_ClearRxFifo();             
        for (a=0;a<20;a++)                                      // at least one byte
        {
                SSC_GetChar();
        }
        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((u8)(crc16>>8));            // write high byte first
        SSC_PutChar((u8)(0x00FF&crc16));        // lowbyte last
        SSC_ClearRxFifo();
        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:
        //SSC_Disable();   // disable CS
        if(result != SD_SUCCESS)
        {

//              sprintf(text,"\r\nError %02X writing data to sd card (R=%02X)", result, rsp);
//              UART1_PutString(text);
                retryCounter++;

                if(SPI_Speed > 1000)
                {
                        SPI_Speed -= 200;  
//                      sprintf(text," new Speed = %d", SPI_Speed);
//                      UART1_PutString(text);
                }
                SDC_Init(0);
        }
        else
        {
//       if(retryCounter == 1) UART1_PutString(" Problem solved\r\n");  
         break;      // Success -> end retry loop
        }

  }
        if (retryCounter > SDCardWriteRetryCounterMax)
        { SDCardWriteRetryCounterMax = retryCounter;
//        DebugOut.Analog[] = SDCardWriteRetryCounterMax;
        }
 
        return(result);
}


//________________________________________________________________________________________________________________________________________
// Funtion:     SDC_GetSector(u32 addr,u8 *Buffer);
//
// Description: This function reads one sector of data from the SSC
//                             
//
// Returnvalue: SD_Result_t
//________________________________________________________________________________________________________________________________________

SD_Result_t SDC_GetSector(u32 addr,u8 *Buffer)
{
        addr = addr << 9; // convert sectoradress to byteadress
        return SDC_GetData(CMD_READ_SINGLE_BLOCK, addr, Buffer, 512);
}