Hi,

I'm having trouble with a PIC18LF45K22 and a 1GB SD card.

I've been looking at the SDFS file and tried to write directly to the SD card which has already been formatted FAT16. I've managed to have it initialise the card, set the block length etc and send out 512 bytes of data to a sector, it then reads that sector and displays the ASCII (sends data/response via RS232 to RealTerm).

2 issues:

1. When I write to the card, and it reads the same sector back, if I then place this card in my laptop and use a hexeditor, I cannot find the string ANYWHERE!!! But I know it's on the card as I've written to different sectors and stuff from previous hours remains!

2. If I issue a second readsector command (say for instance I wanted to read consecutive sectors, or even re-read the same sector) I get a non-zero SDC_response value and the routine fails!

I feel I've done pretty well here but my head is getting sore!

If I post the code here, is there any chance someone could have a look please?

Many thanks in advance

Jimbo

Code:
  
define OSC 16
DEFINE HSER_BAUD 19200
DEFINE HSER_CLROERR 1  ' Auto clear over-run errors
DEFINE HSER_RCSTA 90h
DEFINE HSER_TXSTA 20h
OSCCON = OSCCON | %01110000 ' set internal clock to 16 MHz incase of switchover
SDI         Var PORTC.4 ' SPI data in 
SDI_TRIS    Var TRISC.4 ' SPI data in direction 
SCL         Var PORTC.3 ' SPI clock 
SCL_TRIS    Var TRISC.3 ' SPI clock direction 
SD_CS       Var PORTA.5 ' SD card chip select 
SD_CS_TRIS  Var TRISA.5 ' SD card chip select direction 
SD_CD       Var PORTB.4 ' SD card detect 
SD_CD_TRIS  Var TRISB.4 ' SD card detect direction 
SDO         Var PORTC.5 ' SPI data out 
SDO_TRIS    Var TRISC.5 ' SPI data out direction
i2cSDA      VAR PORTD.1
i2cSCL      VAR PORTD.0
SSPEN  Var SSPCON1.5 ' SSP enable
WCOL  Var SSPCON1.7 ' SSP write collision
BF      Var SSPSTAT.0 ' SSP buffer full
SSPIF  Var PIR1.3  ' SSP interrupt flag
accx        var byte
accx2       var byte
accx_axis   var word
fail        var byte
read_loop        var byte
NODATA  Con 0
MOREDATA Con 1
MEDIA_SECTOR_SIZE Con 512
FAT_BUFFER_SIZE Con MEDIA_SECTOR_SIZE
' Indexes into command table
GO_IDLE_STATE Con 0
SEND_OP_COND Con 1
SET_BLOCKLEN Con 2
READ_SINGLE_BLOCK Con 3
WRITE_SINGLE_BLOCK Con 4
CRC_ON_OFF Con 5
sdcCardDataRejected Con 8
SDC_address Var Long
SDC_buffer Var Byte[MEDIA_SECTOR_SIZE]
SDC_cmd  Var Byte
SDC_CmdCode Var Byte
SDC_CRC  Var Byte
SDC_data_in Var Byte
SDC_data_out Var Byte
SDC_index Var Word
SDC_moredataexpected Var Byte
SDC_response Var Byte
SDC_sector_addr Var Long
SDC_status Var Byte
SDC_timeout Var Long
SDC_timeout1 Var Word

sdcValid Con 0
sdcCardInitCommFailure Con 1
sdcCardNotInitFailure Con 2
sdcCardInitTimeout Con 3
FAT_error Var Byte
FAT_error = 0
DATA_START_TOKEN Con $fe
DATA_ACCEPTED Con $05
SDC_FLOATING_BUS Con $ff
SDC_BAD_RESPONSE Con SDC_FLOATING_BUS
FALSE  Con 0
TRUE  Con 1
'SDC_UseHardSPI Var Byte
 
'Include "SDFS.PBP"
trisa = %00000000
trisd = %00000000
trisc = %00000000  
adcon0.0 = 0
ANSELA = 0
ANSELB = 0
ANSELC = 0
ANSELD = 0
ANSELE = 0 
ADCON1 = 15     ' All I/O pins digital
pause 1000
I2CWRITE i2cSDA,i2cSCL, $a6, $2d, [0]
pauseus 5
I2CWRITE i2cSDA,i2cSCL, $a6, $2d, [16]
pauseus 5
I2CWRITE i2cSDA,i2cSCL, $a6, $2d, [8]
pauseus 5
I2CWRITE i2cSDA,i2cSCL, $a6, $31, [8]
pause 1000 
i2cread i2cSDA,i2cSCL,$a7,50,[accx,accx2],error
accx_axis = accx+(accx2 &03)*256
hserout [$d,$a,#accx_axis,$d,$d]
fail = 0
'while (fail <5 & FAT_error != 0)
fail = fail+1
SD_CS = 1      ' SD card not selected.
SD_CS_TRIS = 0  ' Output SD card chip select.
SD_CD_TRIS = 1  ' Input card detect.
'SD_WE_TRIS = 1     ' Input write protect.
SDO = 1       ' Start SPI data out high.
SDO_TRIS = 0  ' Output SPI data out.
SDI_TRIS = 1  ' Input SPI data in.
SCL = 1       ' SPI clock idles high.
SCL_TRIS = 0  ' Output SPI clock.
pause 1
SSPSTAT = %00000000 ' Sample at middle of data output time, Mode 1, 1: Transmit on idle to active clock transition.
SSPCON1 = %00010010 ' SPI master mode, clock = Fosc/64, Mode 1, 1: Clock idle high.
SSPEN = 1      ' Enable hardware SPI port.
pause 1
For SDC_timeout1 = 1 To 10
    hserout [$d,$a,"sdc timeout: ",#SDC_timeout1]
    SDC_data_out = $ff  ' Data pin must be high.
    SDC_data_in = SSPBUF ' Clear the buffer.
    SSPIF = 0    ' Clear the interrupt flag.
    SSPBUF = SDC_data_out' Send the byte.
    If (WCOL) Then Return' Check for write collision.
    While !SSPIF   ' Wait for send to complete.
        Wend
    Next SDC_timeout1
pause 1
hserout [$d,$a,"Go idle"]
SDC_cmd = GO_IDLE_STATE
SDC_address = 0
gosub send_receive_SD_loop
SDC_data_out = $ff   ' Data pin must be high.
gosub write_byte
If (!SDC_moredataexpected) Then
 SD_CS = 1
 Endif
If (SDC_response = SDC_BAD_RESPONSE) Then
 SDC_status = sdcCardInitCommFailure
 Goto InitError
 Endif
If ((SDC_response & $F7) != $01) Then
 SDC_status = sdcCardNotInitFailure
 Goto InitError
 Endif
For SDC_timeout1 = $fff To 0 Step -1
    hserout [$d,$a,"Op cond"]
 SDC_cmd = SEND_OP_COND
 SDC_address = 0
    gosub send_receive_SD_loop
    ' Generate 8 clock cycles.
 SDC_data_out = $ff  ' Data pin must be high.
 SDC_data_in = SSPBUF  ' Clear the buffer.
 SSPIF = 0   ' Clear the interrupt flag.
 SSPBUF = SDC_data_out ' Send the byte.
 If (WCOL) Then Return  ' Check for write collision.
 While !SSPIF   ' Wait for send to complete.
    Wend 
 If (!SDC_moredataexpected) Then
  SD_CS = 1
  Endif
 If (SDC_response = $00) Then SDC_timeout1 = 0 ' Got a response, end the loop.
 Next SDC_timeout1
If (SDC_response != $00) Then
   SDC_status = sdcCardInitTimeout
   Goto InitError
   Endif
   
Pause 1
SSPSTAT = %00000000 ' Sample at middle of data output time, Mode 1, 1: Transmit on idle to active clock transition.
SSPCON1 = %00010000 ' SPI master mode, clock = Fosc/64, Mode 1, 1: Clock idle high.
SSPEN = 1
hserout [$d,$a,"CRC On/Off"]
SDC_cmd = CRC_ON_OFF
SDC_address = 0
gosub send_receive_SD_loop
SDC_data_out = $ff
gosub write_byte
If (!SDC_moredataexpected) Then
 SD_CS = 1
 Endif
hserout [$d,$a,"Set Block Length"]
SDC_cmd = SET_BLOCKLEN
SDC_address = MEDIA_SECTOR_SIZE
gosub send_receive_SD_loop
SDC_data_out = $ff
gosub write_byte
pause 1
'##############################################################
'SectorWrite:
hserout[$d,$a,"Sector write"]
        SDC_sector_addr = 200
  SDC_cmd = WRITE_SINGLE_BLOCK
  SDC_address = SDC_sector_addr << 9
  gosub send_receive_SD_loop
        If (SDC_response != 0) Then
            hserout[$d,$a,"Not accepted!",$d,$a]
            gosub stop_read
            else
            hserout[$d,$a,"Accepted!",$d,$a]
            endif
   SDC_data_out = DATA_START_TOKEN
   Gosub write_byte
   SDC_data_out = 72   'store 'HELLO'
   Gosub write_byte
   SDC_data_out = 69 
   Gosub write_byte
   SDC_data_out = 76
   Gosub write_byte
   SDC_data_out = 76 
   Gosub write_byte
   SDC_data_out = 79 
   Gosub write_byte
            For SDC_index = 0 To (MEDIA_SECTOR_SIZE - 6)
                hserout[$d,#SDC_index]
    SDC_data_out = $47
    Gosub write_byte
   Next SDC_index
   ' Send the CRC bytes.
   SDC_data_out = $ff
         gosub write_byte ' Just sends 16 1s.
         gosub write_byte
   SDC_data_in = SSPBUF ' Clear the buffer.
            SSPIF = 0  ' Clear the interrupt flag.
            SSPBUF = $ff  ' Shift out a dummy byte.
            While !SSPIF  ' Wait for receive byte.
          Wend
            SDC_data_in = SSPBUF ' Get the byte.
   If ((SDC_data_in & $0f) != DATA_ACCEPTED) Then
    SDC_status = sdcCardDataRejected
    hserout[$d,$a,"Rejected!"]
    gosub stop_read
   Else
                ' The card is writing data into the storage media.
    ' Wait for the card to return non-zero (not busy) or a timeout.
    For SDC_timeout = 0 To 10000
     SDC_data_in = SSPBUF ' Clear the buffer.
                    SSPIF = 0  ' Clear the interrupt flag.
                    SSPBUF = $ff  ' Shift out a dummy byte.
                    While !SSPIF  ' Wait for receive byte.
                        Wend
                    SDC_data_in = SSPBUF ' Get the byte.
     If (SDC_data_in != 0) Then
                        hserout[$d,$a,"Got a write response at ",#SDC_timeout]
                        SDC_timeout = 10000 ' Got a response, end the loop.
                        endif
        Next SDC_timeout
        hserout[$d,$a,"SDC data in = ",#SDC_data_in]
    If (SDC_data_in = 0) Then
                    hserout[$d,$a,"SDC Card timeout"]
                    gosub stop_read
                    endif
   Endif
   SDC_data_out = $ff  ' Data pin must be high.
         gosub write_byte
 SD_CS = 1
'##################################################################
pause 1
for read_loop = 10 to 12
hserout[$d,$a,"SDC sector address: ",#read_loop]
gosub SectorRead
next read_loop
End
error:
    HSEROUT["Error"]
    RETURN
    
InitError:
    HSEROUT [$d,$a,"Error unknown", $d, $a] 
    return
    
write_byte:    
 ' Write Byte SDC_data_out.
 SDC_data_in = SSPBUF ' Clear the buffer.
 SSPIF = 0   ' Clear the interrupt flag.
 SSPBUF = SDC_data_out ' Send the byte.
 If (WCOL) Then
        HSEROUT [$d,$a,"Error: collision", $d, $a]  
        Return  ' Check for write collision.
        endif
 While !SSPIF   ' Wait for send to complete.
    Wend
 return
 
write_SPI:
    SD_CS = 0
    Lookup SDC_cmd, [$40, $41, $50, $51, $58, $7b], SDC_CmdCode
    Lookup SDC_cmd, [$95, $f9, $ff, $ff, $ff, $25], SDC_CRC
    Lookup SDC_cmd, [NODATA, NODATA, NODATA, MOREDATA, MOREDATA, NODATA], SDC_moredataexpected
    SDC_data_out = SDC_CmdCode
    gosub write_byte
    SDC_data_out = SDC_address.Byte3 
    gosub write_byte
    SDC_data_out = SDC_address.Byte2 
    gosub write_byte
    SDC_data_out = SDC_address.Byte1 
    gosub write_byte
    SDC_data_out = SDC_address.Byte0 
    gosub write_byte
    SDC_data_out = SDC_CRC
    gosub write_byte
    return
send_receive_SD_loop:
    SD_CS = 0
    pause 1
    gosub write_SPI
    hserout [$d,$a,"Test card for response: ",$d,$a]
    For SDC_timeout = 8 To 0 Step -1
     ' Read Byte SDC_data_in from SPI bus.  Returns SDC_data_in.
     SDC_data_in = SSPBUF ' Clear the buffer.
     SSPIF = 0          ' Clear the interrupt flag.
     SSPBUF = $ff      ' Shift out a dummy byte.
     While !SSPIF      ' Wait for receive byte.
         Wend
        SDC_data_in = SSPBUF ' Get the byte.
        hserout ["Countdown timeout: ",#SDC_timeout,$d,$a]
        SDC_response = SDC_data_in
        If (SDC_response != SDC_FLOATING_BUS) Then 
            hserout ["Got a response at: ",#SDC_timeout]
            SDC_timeout = 0     ' Got a response, end the loop.
            endif
        Next SDC_timeout
        hserout[$d,$a,"SDC_response: ",#SDC_response]
    return
SectorRead:
    hserout[$d,$a,$a,"Entering SectorRead loop"]
    SDC_sector_addr = 200
 SDC_status = sdcValid      ' Set default error code.
 SDC_cmd = READ_SINGLE_BLOCK
 SDC_address = SDC_sector_addr << 9
 Gosub send_receive_SD_loop  ' Send Byte SDC_cmd to Long SDC_address, Returns Word SDC_response.
 hserout[$d,$a,"SectorRead error: ",bin SDC_response,8]
 If (SDC_response != 0) Then
  Gosub send_receive_SD_loop ' Try once more to send Byte SDC_cmd to Long SDC_address, Returns Word SDC_response.
  If (SDC_response != 0) Then
   hserout[$d,$a,"Not accepted!"]
   hserout[$d,$a,"SectorRead error: ",bin SDC_response,8]
   gosub stop_read   'stops the algorithm totally
            else
            hserout[$d,$a,"Accepted on 2nd attempt!",$d,$a]
            Endif
 Endif
 hserout[$d,$a,"Passed initial read command and address send",$d,$a]
 Pauseus 40 ' Timing delay- at least 8 clock cycles.
 For SDC_timeout = $2ff To 0 Step -1   
  SDC_data_in = SSPBUF ' Clear the buffer.
  SSPIF = 0          ' Clear the interrupt flag.
  SSPBUF = $ff       ' Shift out a dummy byte.
  While !SSPIF      ' Wait for receive byte.
  Wend
  SDC_data_in = SSPBUF ' Read Byte SDC_data_in from SPI bus.  Returns SDC_data_in.
  Pauseus 40             ' Timing delay- at least 8 clock cycles.
  If (SDC_data_in != SDC_FLOATING_BUS) Then SDC_timeout = 0 ' Got a response, end the loop.
        Next SDC_timeout
 If (SDC_data_in != DATA_START_TOKEN) Then
  hserout["Timeout!!!!"]
  gosub stop_read   'stops the algorithm totally
  else
  hserout["Data token received!",$d,$a]
  endif
 For SDC_index = 0 To (MEDIA_SECTOR_SIZE - 1)
  SDC_data_in = SSPBUF ' Clear the buffer.
  SSPIF = 0          ' Clear the interrupt flag.
  SSPBUF = $ff      ' Shift out a dummy byte.
  While !SSPIF      ' Wait for receive byte.
            Wend
  SDC_data_in = SSPBUF ' Read Byte SDC_data_in from SPI bus.  Returns SDC_data_in.
  hserout[SDC_data_in]
  Next SDC_index
 SDC_data_out = $ff          ' Data pin must be high.
    Gosub write_byte         ' Just sends 16 clocks.
    gosub write_byte
    SD_CS = 1           ' Return Byte SDC_status.
    pause 1
    return
stop_read:
    SSPEN = 0
    stop

Response is as follows...........

869 <----- [just an I2C sensor]
sdc timeout: 1
sdc timeout: 2
sdc timeout: 3
sdc timeout: 4
sdc timeout: 5
sdc timeout: 6
sdc timeout: 7
sdc timeout: 8
sdc timeout: 9
sdc timeout: 10
Go idle
Test card for response:
Countdown timeout: 8
Countdown timeout: 7
Got a response at: 7
SDC_response: 1
Op cond
Test card for response:
Countdown timeout: 8
Countdown timeout: 7
Got a response at: 7
SDC_response: 1
Op cond
Test card for response:
Countdown timeout: 8
Countdown timeout: 7
Got a response at: 7
SDC_response: 1
Op cond
Test card for response:
Countdown timeout: 8
Countdown timeout: 7
Got a response at: 7
SDC_response: 0
CRC On/Off
Test card for response:
Countdown timeout: 8
Countdown timeout: 7
Got a response at: 7
SDC_response: 0
Set Block Length
Test card for response:
Countdown timeout: 8
Countdown timeout: 7
Got a response at: 7
SDC_response: 0
Sector write
Test card for response:
Countdown timeout: 8
Countdown timeout: 7
Got a response at: 7
SDC_response: 0
Accepted!
506
Got a write response at 32
SDC data in = 3
SDC sector address: 10

Entering SectorRead loop
Test card for response:
Countdown timeout: 8
Countdown timeout: 7
Countdown timeout: 6
Got a response at: 6
SDC_response: 0
SectorRead error: 0
Passed initial read command and address send
Data token received!
HELLOGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
SDC sector address: 11

Entering SectorRead loop
Test card for response:
Countdown timeout: 8
Countdown timeout: 7
Got a response at: 7
SDC_response: 193
SectorRead error: 11000001
Test card for response:
Countdown timeout: 8
Countdown timeout: 7
Got a response at: 7
SDC_response: 240
Not accepted!
SectorRead error: 11110000
################################################## #######################