News:

;) This forum is the property of Proton software developers

Main Menu

SD Card Fat16/Fat32

Started by pjdenyer, Jul 12, 2021, 12:58 PM

Previous topic - Next topic

pjdenyer

This is a modified version of Les's code. I had to modify the FileName string length to correct file name error. All the function work apart from going back a directory, I have put a fix in the bas program which allows you to go back to the Root directory by re-initialising the SD Card.

If anyone has any ideas!!

Wimax

#1
Hello,

I have a problem with the FileSys24 library and I can't detect vital signs using SD_File_System.bas.
I'm using a PIC24FJ64GA002 and the SPI bus is shared between the SD (1 GB FAT32), an external RAM and a DAC, each obviously driven by a dedicated CS line.
By picking up the signal with the logic state analyzer in parallel with the SD I verify the correct operation of both the RAM and the DAC, but when I try to use the SD I detect nothing.
I am using the file "SD_File_System.bas," and wanting to view directories and occupied and available space (pressing "1") I should see some traffic on the bus, I see only data on the serial communicator window (but no directory name), but I'm sure that data are wrong.
I have defined and rechecked the signals within the FileSys24.inc library a thousand times.
I don't understand where the problem could be!  :'(


Last update.
——————
——————
All wires re-routed, SD card changed and hours spent in debugging main code & library interaction...now it goes !

pjdenyer

Wilmax, was it just the wiring and type of sd card that caused the issue or were their any issues with the code I uploaded.

top204

Make sure you have a pull-up resistor on the SD card's DOUT line.

It has been a long time since I worked with SD cards, but I remember the DOUT pin is Open-Drain, so it needs a pull-up resistor of about 10K on it, to the 3V3 line. Otherwise, nothing will be seen by the microcontroller.

I tend to place pull-up resistors on all the SD card's lines, just in case. :-)

Wimax

Once the desperation has passed  ;D I re-routed and checked all wires, changed the SD card and now it works !
I have tried it with a 4 GB uSD and it works, same result with a 16 GB SD.
I still have problems with an old 1 GB SD that is not recognized, but it is correctly recognized by Windows if I insert it into an USB SD reader.

top204

If a card is not operating correctly, go into the code and change the setup speed interface so it is slower.

For some inexplicable reason, SD cards need to be set up with a very slow SPI interface, then it is speeded up for normal operations once the setup is accepted? I've never understood this methodology with them because if the SPI interface is capable of higher speeds, why can't it be setup with that speed? It seems to be a trait from the MMC cards that pre-dated the SD cards.

Some cards need very slow interfaces when setting up, so the SPI speed in the code I wrote was "best guess", and is very slow. But it may not be slow enough for all cards.

Wimax

Thank you Les! I will try!


top204

#7
To slow down the setup SPI interface speed, go into the SD_ReceiveByte and SD_SendByte procedures and change the DelayUs 4 commands, to a larger value for the delay.

Do it in increments of 1us until the SD card initialises.

To see if it is the SD not initialising or the FAT not initialising. Go into the FAT_Init() procedure, and place an HRsout command or a Print command between the code listing:

'
' Init SD/MMC
'
    If SD_InitSequence() = False Then
        Disk_tRWError = True
        Result = cErrNoResponse
        ExitProc
    EndIf

If the code gives a signal, via the Hrsout or Print, from between the If-Endif statements, and just before it exits the procedure prematurely, it is the SD card that is not initialising because the SD_InitSequence() procedure has returned a false result.

Or look for an error of cErrNoResponse coming from the FAT_Init() procedure in your main code that calls it.

Wimax

Hello Everybody !

I need to quickly transfer data acquired by the ADC, via interrupt, to a SPI RAM and I have to use the MCU's internal SPI module (for speed reasons), that works very well.
The problem arises when I write back the data to SD by reading them from the SPI RAM, in this case I just can't initialize the SD.
I have tried reading and writing to SPI via software and in this case the SD works, but writing to the SPI RAM via interrupt(@ the required speed) is too slow.
In the FileSys24.inc library (the version posted by pjdenyer ) it is possible to define the variable "SPI_Software 1" and in this case the bus is handled via software, including initializing the SD at slow speed.
By defining "SPI_Hardware 1" on the other hand, the hardware module is used, but I don't think reduced-speed initialization is performed. How can this problem be solved ? Is it possible to reprogram the SPI HW during execution or disable it by freeing the dedicated PINs ? Or is there any other way ? Every suggestion is valuable !



top204

#9
I don't fully understand your question Wimax.

You cannot write to the SD card with the FAT library from an interrupt, because all sorts of variables and SFRs will be effected and cause chaos in the program. The original "FileSys24.inc" file installed with the compiler uses a software SPI interface, so that it is generic and will run on all PIC24 and dsPIC33 devices, because Microchip keep changing how the peripherals work so one SPI interface on one devie will not work on another deive, even from the same family!

If using a hardware SPI peripheral for the interface, it can be slowed down by changing its clock speed via an SFR. But again, the SFR depends on the device used so the datasheet will need to be examined.

The original include file has the following procedures for SPI read and write:
'--------------------------------------------------------------------------------------------------------------------------
' Receive a byte from the card using a software SPI interface.
' Input     : None
' Return    : Returns the byte read from the SPI bus
' Notes     : None
'
Proc SD_ReceiveByte(), WREG0.Byte0
    WREG1 = 8                                   ' \ 8-bit SPI loop
    Repeat                                      ' /
        WREG0 = WREG0 << 1                      ' Shift the next bit into MSB
        Set SD_CLK                              ' Set CLK high
        If Disk_tSlowSPI = True Then
            DelayUS 4
        EndIf
        WREG0 = WREG0 | SD_SDI                  ' Capture the current bit on SPI DO
        Clear SD_CLK                            ' Pull CLK pin low
        Dec WREG1                               ' \
    Until SRbits_Z = 1                          ' / Do all 8-bits
EndProc

'--------------------------------------------------------------------------------------------------------------------------
' Send a byte to the card using a software SPI interface.
' Input     : pByte holds teh byte to write to the SPI bus
' Return    : None
' Notes     : None
'
Proc SD_SendByte(pByte As WREG0.Byte0)
    WREG1 = 8                                   ' \ 8-bit SPI loop
    Repeat                                      ' /
        SD_SDO = WREG0.7                        ' Put the current outgoing bit on SPI DOUT
        WREG0 = WREG0 << 1                      ' Shift the next bit into MSB
        Set SD_CLK                              ' Set CLK high
        If Disk_tSlowSPI = True Then
            DelayUS 4
        EndIf
        Clear SD_CLK                            ' Pull CLK pin low
        Dec WREG1                               ' \
    Until SRbits_Z = 1                          ' / Do all 8-bits
EndProc

But looking at them now, they can be made a bit more efficient and a bit faster to operate. :-)

Wimax

Hi Les,

perhaps I did not express myself well, I meant that in the program flow I have to save to SPI RAM samples acquired by the ADC operating in interrupt (blocks of 16 bytes at a time). Once the RAM is full, the interrupt is disabled.
I'm using now a 24FJ64GA002 that's not a Ferrari, but has enough RAM and Flash to perform some tests.
If I use the software routines to handle the read/write to SPI I am not fast enough and the ADC samples are not written to RAM properly.
If I activate the SPI HW module I can exploit the speed of the module and I can save all the samples to RAM without any problem. Later I try to save those samples to an SPI SD by running a number of cycles (I append N samples at a time to a file).
In the modified version of the FileSys24.inc library (the version posted by pjdenyer) there is provision to use the HW SPI modules via the variable "SPI_Hardware" set to 1, but in this case the SD does not work at all.
If I manage the reads/writes to SPI exclusively via software everything works, even the SD, but they are too slow to guarantee the initial data transfer from ADC to RAM in "real time."

Is it possible to change the SPI HW module settings several times during the course of the program if necessary, or once set do they stay that way until the next reset ?

Wimax

A piece of code where "SPI_Hardware" comes in.

'--------------------------------------------------------------------------------------------------------------------------
' Receive a byte from the card using a software SPI interface.
' Input     : None
' Return    : Returns the byte read from the SPI bus
' Notes     : None
'
Proc SD_ReceiveByte(), WREG0.Byte0

$ifdef SPI_Hardware
    WREG0.Byte0 = SPI1_Read()                   ' Use Hardware SPI
$endif
$ifdef SPI_Software
    WREG1 = 8                                   ' \ 8-bit SPI loop
    Repeat                                      ' /
        WREG0 = WREG0 << 1                      ' Shift the next bit into MSB
        Set SD_CLK                              ' Set CLK high
        If Disk_tSlowSPI = True Then
            DelayUS 4
        EndIf
        WREG0 = WREG0 | SD_SDI                  ' Capture the current bit on SPI DO
        Clear SD_CLK                            ' Pull CLK pin low
        Dec WREG1                               ' \
    Until SRbits_Z = 1                          ' / Do all 8-bits
$endif
EndProc

'--------------------------------------------------------------------------------------------------------------------------
' Send a byte to the card using a software SPI interface.
' Input     : pByte holds teh byte to write to the SPI bus
' Return    : None
' Notes     : None
'
Proc SD_SendByte(pByte As WREG0.Byte0)

$ifdef SPI_Hardware
    SPI1_Write(pByte)                           ' Use Hardware SPI
$endif
$ifdef SPI_Software
    WREG1 = 8                                   ' \ 8-bit SPI loop
    Repeat                                      ' /
        SD_SDO = WREG0.7                        ' Put the current outgoing bit on SPI DOUT
        WREG0 = WREG0 << 1                      ' Shift the next bit into MSB
        Set SD_CLK                              ' Set CLK high
        If Disk_tSlowSPI = True Then
            DelayUS 4
        EndIf
        Clear SD_CLK                            ' Pull CLK pin low
        Dec WREG1                               ' \
    Until SRbits_Z = 1                          ' / Do all 8-bits
$endif
EndProc

Wimax

I think I found the bug, probably due to all the various trials in the past.
Needless to say, I tried slowing down the clock to Commodore 64 values, but it still did not work.
Comparing the signals on the bus in the case of fully software and fully hardware SPI management, both the clock pulse train (80 cycles) and the attempts made by the MCU to identify the SD were always visible.
The read phase gave different results thats is a correct sequence with a full sw managament of SPI and nothing with an hw management.
I discovered a "little" difference in my "SPI_24.inc" due to the dummy initial data on the bus:
 Proc Read_SPI1(), WREG0.Byte0
    SPI1BUF = $0000
    While SPI1STATbits_SPITBF = 1 : Wend 
    While SPI1STATbits_SPIRBF = 0 : Wend
    Result =  SPI1BUF
EndProc


instead of:

 Proc Read_SPI1(), WREG0.Byte0
    SPI1BUF = $00FF
    While SPI1STATbits_SPITBF = 1 : Wend 
    While SPI1STATbits_SPIRBF = 0 : Wend
    Result =  SPI1BUF
EndProc


Now all seems to go well, I hope it is not a time-variant phenomenon  ;D

pjdenyer

I have just checked the RAR file I uploaded and the SPI.inc file is correct as in the Read_SPI1 procedure is setting SPIBUF = $00FF

I have tested the software this weekend and it works with an Adata 512Mb, Sandisk 1Gb and Veho 2Gb SD cards.

Wimax

Yes ! I changed the value some time ago by doing some tests with the logic state analyser and it remained zero.
It works flawlessly now!