PDA

View Full Version : SD card multiple read blocks giving error



jimbostlawrence
- 20th October 2011, 15:39
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



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
################################################## #######################

mackrackit
- 20th October 2011, 16:15
Why not use SDFS like it is intended to be used ?

jimbostlawrence
- 20th October 2011, 17:05
Hi,

I'm trying to create a fast a system as possible and I'll be streaming bytes of data to the SD card (preformatted FAT16 with a maximum sized .txt file (completely empty with NULLs) on it such that when I write the bytes, they'll fill the space the .txt file occupies. Take the SD card out and into the laptop and hopefully, the .txt file will contain the data.

Cheers

Jimbo

mackrackit
- 20th October 2011, 17:12
I do not think you will be able to stream to a SD card in FAT format, FAT takes time.
I heard of a guy writing to a FRAM, then when the MCU had some down time the data would be transferred to the SD.
Have you tried SDFS the way it is? How much too slow was it?

jimbostlawrence
- 20th October 2011, 17:38
Hi Dave,

Not tested speed, but my aim is to get the absolute maximum speed by not actually using the FAT filing system but just writing bytes directly to the card. The FAT is already in existence in the card with the .txt file. I don't need to set file size changes to the .txt file etc as I'm just trying to fill the .txt file with the data. I'm trying to generate a setup that can read I2C data from multiple sensors and up to 200 Hz if possible and stream the data to the SD card (starting a new write_block at each 512 bytes...)

jimbostlawrence
- 20th October 2011, 18:27
Hi Dave,

Not tested speed, but my aim is to get the absolute maximum speed by not actually using the FAT filing system but just writing bytes directly to the card. The FAT is already in existence in the card with the .txt file. I don't need to set file size changes to the .txt file etc as I'm just trying to fill the .txt file with the data. I'm trying to generate a setup that can read I2C data from multiple sensors and up to 200 Hz if possible and stream the data to the SD card (starting a new write_block at each 512 bytes...)

It's main aim is to collect data over a period of days with no interuption so there is no 'down-time'. I read the forum posts you refer to regarding storing data elsewhere until enough was stored etc so it could then be transferred in one block. At the moment, I'm just trying to read from two successive blocks without error and curious as to why the SD card isn't responding. Am I supposed to send another command after the previous read command? Note that the above algorithm happily writes a block of 512 bytes to the card and then immediately reads it back, but when it tries to read the same block, or any other block, the SDC response flags from the SD card don't equal 'zero' (it tries twice in quick succession after an initial fail). I'm also confused as to where the 'HELLO' is on the card if it's not appearing in a hex editor lol.