SD card multiple read blocks giving error


Closed Thread
Results 1 to 6 of 6
  1. #1
    Join Date
    Sep 2009
    Location
    South Wales (UK)
    Posts
    62

    Default SD card multiple read blocks giving error

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

  2. #2
    Join Date
    Nov 2003
    Location
    Wellton, U.S.A.
    Posts
    5,924


    Did you find this post helpful? Yes | No

    Default Re: SD card multiple read blocks giving error

    Why not use SDFS like it is intended to be used ?
    Dave
    Always wear safety glasses while programming.

  3. #3
    Join Date
    Sep 2009
    Location
    South Wales (UK)
    Posts
    62


    Did you find this post helpful? Yes | No

    Default Re: SD card multiple read blocks giving error

    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

  4. #4
    Join Date
    Nov 2003
    Location
    Wellton, U.S.A.
    Posts
    5,924


    Did you find this post helpful? Yes | No

    Default Re: SD card multiple read blocks giving error

    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?
    Dave
    Always wear safety glasses while programming.

  5. #5
    Join Date
    Sep 2009
    Location
    South Wales (UK)
    Posts
    62


    Did you find this post helpful? Yes | No

    Default Re: SD card multiple read blocks giving error

    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...)

  6. #6
    Join Date
    Sep 2009
    Location
    South Wales (UK)
    Posts
    62


    Did you find this post helpful? Yes | No

    Default Re: SD card multiple read blocks giving error

    Quote Originally Posted by jimbostlawrence View Post
    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.

Members who have read this thread : 1

You do not have permission to view the list of names.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts