News:

Let's find out together what makes a PIC Tick!

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!

Wimax

#15
Hello !

I need to save files on a FAT32 uSD together with time-stamp information i.e. day/month/year/hours/minutes/seconds.
Is it possible to modify the library to use names longer than the 8 characters for the name plus 3 for the extension format ?
Alternatively, is it possible to just enable the storage of the date and time attributes of the file at creation by manipulating the variables Global_bDay, Global_bMonth,Global_bYear, Global_bHours, Global_bMinutes, Global_bSeconds that are inside the library, but used as constants ?

'
' Global date and time variables for file creation
'
    Dim Global_bDay As Byte = 1
    Dim Global_bMonth As Byte = 1
    Dim Global_bYear As Byte = 1
    Dim Global_bHours As Byte = 0
    Dim Global_bMinutes As Byte = 0
    Dim Global_bSeconds As Byte = 0




trastikata

Quote from: Wimax on Aug 02, 2023, 05:12 AMAlternatively, is it possible to just enable the storage of the date and time attributes of the file at creation by manipulating the variables Global_bDay, Global_bMonth,Global_bYear, Global_bHours, Global_bMinutes, Global_bSeconds that are inside the library, but used as constants ?

Not sure what exactly you are asking.

You can give new values to those variables every time before you close the file, this will update the file "Last modified" attributes.

Wimax

#17
Hi Trastikata  ;) ,

I wanted to save files directly using the date and time digits with the addition of three characters for the file extension, but I reach 12 +3 characters and it does not work correctly.
I realised the existence of those variables by analysing the library, but having never used them I wondered if anyone had used them to store the date and time of creation of written files.
In this case, the name of the file would no longer be a big problem by being able to discriminate by time and date of creation.

****** SOLVED ******

I tried and it seems to work, the variables control the creation date of the files 😉

Nickma

Hi Trusticata. Hello Vimax. I already asked this question on the site 2 years ago.
I ask for help

Proton24 SD FAT File System problem.
I'm stumped with writing the attributes of the data file being created. I tried many options, but nothing works.

    Device = 24FJ64GA004
    Declare Xtal = 8
       PORTA = 0: PORTB = 0: PORTC = 0
       TRISA = 0: TRISB = 0: TRISC = 0
    $ define SD_CLK PORTB.13 'SPI CLK to SD card pin5 CLK pin
    $ define SD_SDO PORTB. 14 'SPI DO to SD card pin2 DI pin
    $ define SD_SDI PORTB. 12 'SPI DI to SD card pin7 DO pin
    $ define SD_CS PORTB. 15 'SPI CS to SD card pin1 CS pin
       Include "FileSys24.inc" 'Load the FAT file system
    Declare LCD_Type ALPHA
    Declare LCD_DTPin = PORTB.4
    Declare LCD_RSPin = PORTA.0
    Declare LCD_ENPin = PORTA.1
    Declare LCD_Interface = 4
    Declare LCD_Lines = 4
    Declare LCD_CommandUs = 2000
    Declare LCD_DataUs = 50
      Declare HRSOut1_Pin = PORTB.2
      Declare Hserial1_Baud = 9600 'Set baud rate to 9600
     Dim CR As $ 0D 'Carriage Return
    Dim LF As $ 0A 'Line Feed
    Dim i As Word
    Dim MyFileName As String * 11
      CLKDIV = 0 'CPU peripheral clock ratio set to 1: 1
      Write_OSCCONH (% 00000000) 'Internal OSC 8MHz
       
      PPS_Output (cOut_Pin_RP2, cOut_Fn_U1TX)
  PPS_Output (cOut_Pin_RP13, cOut_Fn_SCK1OUT) 'To SPI peripheral's CLK pin
  PPS_Output (cOut_Pin_RP13, cOut_Fn_SDO1) 'To SPI peripheral's SDO pin
  PPS_Input (cIn_Pin_RP12, cIn_Fn_SDI1) 'From SPI peripheral's SDI pin
  PPS_Input (cIn_Pin_RP15, cIn_Fn_SS1IN) 'SS1 Slave Select Input (SS1IN)
 
            Cls: DelayMS 1500
'************************************************ *************************
Main:
       MyFileName = "VL-101.DAT"
                  Cls
    If FAT_Init () = cErrOK Then 'Can we initialise the FAT?
        If File_Exists (MyFileName) = False Then 'Does the file already exist?
            File_Create (MyFileName) 'No. So create it
            File_Close () 'Then close it
        EndIf
         
        If File_Append (MyFileName) = cErrOK Then 'Can we append to an existing file?
            HRSOut "Writing \ r" 'Yes. So transmit a message
            Print At 2.4, "Writing"
                  GoSub Pause_1000
            File_Write "Integer Data \ r"
            For MyWord = 0 To 6 '\
                File_Write Dec MyWord, "," '| Write ASCII data to the file
            Next '/
            File_Write 13
              Global_bSeconds = 0
              Global_bMinutes = 15
              Global_bHours = 11
              Global_bDay = 12
              Global_bMonth = 11
              Global_bYear = 21
            File_Close () 'Close the file
            HRSOut "Finished Writing \ r"
            Print At 2,4, "Finished Writing"
                  GoSub Pause_1000
        Else
            HRSOut "Cannot append", MyFileName, 13
            Print At 2,4, "Cannot append"
                  GoSub Pause_1000
        EndIf
    Else 'Otherwise ...
        HRSOut "Cannot initialise SD \ r" 'Transmit an error response
        Print At 2,1, "Cannot initialise SD"
                  GoSub Pause_1000
    EndIf
 End
'************************************************ *************************
 Pause_10: For i = 1 To 10: DelayMS 1: Next i: Return
 Pause_1000: For i = 1 To 1000: DelayMS 1: Next i: Return
 Pause_1500: For i = 1 To 1500: DelayMS 1: Nexti: Return
'************************************************ *************************
'For internal 8MHz oscillator without PLL
'OSC pins are general purpose I / O
   Config Config1 = JTAGEN_OFF, GCP_OFF, BKBUG_OFF, COE_OFF, ICS_PGx1, FWDTEN_OFF, WINDIS_OFF, FWPSA_PR128, WDTPOST_PS256
   Config Config2 = IOL1WAY_OFF, COE_OFF, IESO_OFF, FNOSC_FRC, FCKSM_CSECME, OSCIOFNC_ON, POSCMOD_NONE

As a result, I get: VL-101.DAT 08/01/2021 12:15
moreover, if I change the value of the day or month, then nothing changes. Only the year is recorded correctly.

Wimax

Hi Nickma  ;) ,

I don't have the code right with me now, so I can't check, but I assign all the variables (Global_bSeconds etc.) just before calling all the SD related commands.
I tried with several files and I can see both the file names and the date/time attributes regularly recorded on the SD, moreover even the file content is ok.