Sie sind hier: Home » Datenlogger V2 » Programm V2 » SD Lib V2

  ' KokkeKat FAT-free SD library code for SDSC, SDHC, and SDXC - INCLUDE at the end of your code
' Written by Niclas Arndt, Stockholm, Sweden, 2011.05.06
' License terms apply, as stated in the application note

#if Sdinitdetail = 1                                        ' Minimum detail

   Sdinit:

      Sdstatus = 9                                          ' Minimum initialization detail unspecified error 2

      Set Sd_cs                                             ' Pull CS high

      Sdcommand = &HFF                                      ' Send at least 74 clock cycles with cs high
      For Sdtempb = 1 To 74
         Gosub Sdcommand1
      Next Sdtempb

      Reset Sd_cs

      Gosub Sdcommand1                                      ' Send 8 additional clock cycles with cs low

      Sdcommand = &H40                                      ' Send CMD0: &H40 &H00 &H00 &H00 &H00 &H95
      Gosub Sdcommand1
      Sdcommand = &H00
      Gosub Sdcommand1
      Gosub Sdcommand1
      Gosub Sdcommand1
      Gosub Sdcommand1
      Sdcommand = &H95
      Gosub Sdcommand1

      Gosub Sdresponseloop                                  ' Receive the single byte of response

      If Sdresponse(1) = &B00000001 Then                    ' CMD0 was successful

         Sdcommand = &HFF                                   ' Send 8 additional clock cycles with cs low
         Gosub Sdcommand1                                   ' The SanDisk Extreme III 4GB class 6 requires this

         Sdcommand = &H48                                   ' Send CMD8: &H48 &H00 &H00 &H01 &HAA &H87
         Gosub Sdcommand1
         Sdcommand = &H00                                   ' If the response to CMD8 is the same, we have a v2.0 compliant card
         Gosub Sdcommand1
         Gosub Sdcommand1
         Sdcommand = &H01                                   ' xxxx0001 specifies voltage range 2.7-3.6V
         Gosub Sdcommand1
         Sdcommand = &HAA                                   ' Check pattern 10101010 as recommended
         Gosub Sdcommand1
         Sdcommand = &H87
         Gosub Sdcommand1

         Gosub Sdresponseloop                               ' Receive the single byte of response
         If Sdresponse(1) <> 255 Then                       ' No timeout in CMD8

            If Sdresponse(1).2 = 1 Then
               Sdcardtype = 1                               ' R1 illegal command in this case means v1.x SD card
            Else
               Sdcardtype = 2                               ' v2+
               Gosub Sdresponse2_5                          ' Read the remaining 5 bytes (The first byte has already been checked and the last byte is only sent with CRC enabled)
               If Sdresponse(1) <> &B00000001 Or Sdresponse(2) <> &H00 Or Sdresponse(3) <> &H00 Or Sdresponse(4) <> &H01 Or Sdresponse(5) <> &HAA Then       ' Check if the CMD8 R7 response bytes 2-5 are identical to the command
                  Sdstatus = 8                              ' Minimum Initialization Detail Unspecified Error 1
               End If
            End If

            ' Sdstatus = 0 & Sdcardtype = 1 -> v1.x
            ' Sdstatus = 0 & Sdcardtype = 2 -> v2+

            If Sdstatus = 9 Then                            ' Correct response after CMD8

               Sdcommand = &HFF                             ' Send 8 additional clock cycles with cs low
               Gosub Sdcommand1                             ' The SanDisk Extreme III 4GB class 6 requires this

               Sdcommand = &H7A                             ' Send the first CMD58: &H7A &H00 &H00 &H00 &H00 &HFD
               Gosub Sdcommand1
               Sdcommand = &H00
               Gosub Sdcommand1
               Gosub Sdcommand1
               Gosub Sdcommand1
               Gosub Sdcommand1
               Sdcommand = &HFD
               Gosub Sdcommand1

               Gosub Sdresponseloop                         ' Receive the single byte of response
               If Sdresponse(1) <> 255 Then                 ' No timeout after CMD58

                  Gosub Sdresponse2_5                       ' Check OCR register response in bytes 2 & 3
                  If Sdresponse(1) = &B00000001 And Sdresponse(3) = 255 And Sdresponse(4).7 = 1 Then       ' There are 9 voltage ranges 2.7 - 3.6V. All must be supported according to spec. OCR bit 15-23 must be high.
                                                            ' The SD card is in a valid supply voltage
                     Sdtempw = 0
                     Do                                     ' Send <= 64k times CMD55+CMD41
                        Sdcommand = &HFF                    ' Send 8 additional clock cycles with cs low
                        Gosub Sdcommand1

                        Sdcommand = &H77                    ' Send CMD55 (required before all ACMD commands): &H77 &H00 &H00 &H00 &H00 &H65
                        Gosub Sdcommand1
                        Sdcommand = &H00
                        Gosub Sdcommand1
                        Gosub Sdcommand1
                        Gosub Sdcommand1
                        Gosub Sdcommand1
                        Sdcommand = &H65
                        Gosub Sdcommand1


                        Gosub Sdresponseloop                ' Receive the single byte of response
                        If Sdresponse(1) <> 255 Then        ' No timeout after CMD55

                           Set Sd_cs                        ' Set CS, clock out 8 bits and reset CS
                           Sdcommand = &HFF
                           Gosub Sdcommand1
                           Reset Sd_cs

                           Sdcommand = &H69                 ' Send CMD41: &H69 &H00 &H00 &H00 &H00 &HE5 ' SDSC compatible card (HDS = 0)
                           Gosub Sdcommand1                 ' Send CMD41: &H69 &H40 &H00 &H00 &H00 &H77 ' SDHC / SDXC compatible card (HDS = 1)
                           If Sdcardtype = 1 Then           ' SDSC compatible card (HDS = 0)
                              Sdcommand = &H00
                           Else                             ' SDHC / SDXC compatible card (HDS = 1)
                              Sdcommand = &H40
                           End If
                           Gosub Sdcommand1
                           Sdcommand = &H00
                           Gosub Sdcommand1
                           Gosub Sdcommand1
                           Gosub Sdcommand1
                           If Sdcardtype = 1 Then           ' SDSC compatible card (HDS = 0)
                              Sdcommand = &HE5
                           Else                             ' SDHC / SDXC compatible card (HDS = 1)
                              Sdcommand = &H77
                           End If
                           Gosub Sdcommand1

                           Gosub Sdresponseloop             ' Receive the single byte of response

                        End If

                        Incr Sdtempw

                     Loop Until Sdresponse(1) = 0 Or Sdtempw = &HFFFF       ' The sample cards' loop counts were 62 (Kingston 4GB C2), 56 (SanDisk Extreme III 4GB C6), 49 (SanDisk v2+ 1GB), 115 (Canon 32MB v1.x), and 558 (Transcend v2+ 64GB)

                     If Sdresponse(1) <> 255 Then           ' The SD card has accepted the host

                        Sdstatus = 0                        ' Initialization complete

                        If Sdcardtype = 2 Then              ' For v2+ cards, an additional CMD58 is required according to spec.
                                                                ' Some cards can respond the CCS info before ACMD41 (Kingston 4GB CL2),
                                                                ' but 3 of my 4 cards could only return the voltage bits in the previous response.

                           Sdcommand = &HFF                 ' Send 8 additional clock cycles with cs low
                           Gosub Sdcommand1

                           Sdcommand = &H7A                 ' Send second CMD58: &H7A &H00 &H00 &H00 &H00 &HFD
                           Gosub Sdcommand1
                           Sdcommand = &H00
                           Gosub Sdcommand1
                           Gosub Sdcommand1
                           Gosub Sdcommand1
                           Gosub Sdcommand1
                           Sdcommand = &HFD
                           Gosub Sdcommand1

                           Gosub Sdresponseloop             ' Receive the single byte of response
                           If Sdresponse(1) <> 255 Then     ' No timeout in CMD8

                              Gosub Sdresponse2_5           ' Check OCR register response in byte 2

                              If Sdresponse(1) = 0 And Sdresponse(2).7 <> 0 Then
                                 If Sdresponse(2).6 = 1 Then       ' Card capacity status CCS bit. If it is 1, then Sdcardtype = 2 (previously set)
                                    Sdcardtype = 3          ' 1 = v1.x SDSC, 2 = v2+ SDSC, 3 = v2+ SDHC/SDXC
                                 End If
                              End If
                           End If
                        End If
                     End If
                  End If
               End If
            End If
         End If
      End If                                                ' Close CMD8

      Set Sd_cs

      Sdcommand = &HFF                                      ' Clock SD to complete job
      Gosub Sdcommand1

      ' In SPI mode, speed is not guaranteed by specification, but the minimum supported 4-bit bus mode clock speed is 12,5 MHz.
      ' The maximum SPI speed for AVR 8-bit is 10MHz, so we set SPI to maximum speed, f osc / 2
      Spsr.0 = 1                                            ' Double speed (results in f osc / 2)
      Spcr.1 = 0                                            ' f osc / 4
      Spcr.0 = 0

      ' Spcr.1 = 0                                            ' f osc / 16
      ' Spcr.0 = 1

      ' Spcr.1 = 1                                            'f osc / 64
      ' Spcr.0 = 0

      ' Spcr.1 = 1                                            ' f osc / 128
      ' Spcr.0 = 1

   Return

#else                                                       ' Full detail

   Sdinit:

      Set Sd_cs                                             ' Pull CS high

      Sdcommand = &HFF                                      ' Send at least 74 clock cycles with cs high
      For Sdtempb = 1 To 74
         Gosub Sdcommand1
      Next Sdtempb

      Reset Sd_cs

      Gosub Sdcommand1                                      ' Send 8 additional clock cycles with cs low

      Sdcommand = &H40                                      ' Send CMD0: &H40 &H00 &H00 &H00 &H00 &H95
      Gosub Sdcommand1
      Sdcommand = &H00
      Gosub Sdcommand1
      Gosub Sdcommand1
      Gosub Sdcommand1
      Gosub Sdcommand1
      Sdcommand = &H95
      Gosub Sdcommand1

      Gosub Sdresponseloop                                  ' Receive the single byte of response

      If Sdresponse(1) = 255 Then
         Sdstatus = 1                                       ' Timeout in CMD0
      Else
         Gosub Sdcheckr1                                    ' Check R1 error codes
         If Sdstatus = 10 Then                              ' If Sdstatus = 0 and no timeout, the CMD0 was successful
            Sdstatus = 0                                    ' Remap status 10

            Sdcommand = &HFF                                ' Send 8 additional clock cycles with cs low
            Gosub Sdcommand1                                ' The SanDisk Extreme III 4GB class 6 requires this

            Sdcommand = &H48                                ' Send CMD8: &H48 &H00 &H00 &H01 &HAA &H87
            Gosub Sdcommand1
            Sdcommand = &H00                                ' If the response to CMD8 is the same, we have a v2.0 compliant card
            Gosub Sdcommand1
            Gosub Sdcommand1
            Sdcommand = &H01                                ' xxxx0001 specifies voltage range 2.7-3.6V
            Gosub Sdcommand1
            Sdcommand = &HAA                                ' Check pattern 10101010 as recommended
            Gosub Sdcommand1
            Sdcommand = &H87
            Gosub Sdcommand1

            Gosub Sdresponseloop                            ' Receive the single byte of response

            If Sdresponse(1) = 255 Then
               Sdstatus = 2                                 ' Timeout in CMD8
            Else
               Gosub Sdcheckr1                              ' Check R1 error codes
               If Sdstatus = 12 Then
                  Sdcardtype = 1                            ' v1.x
                  Sdstatus = 10                             ' This is not an error - it signifies that the card is v1.x
               Else
                  Sdcardtype = 2                            ' v2+
                  Gosub Sdresponse2_5                       ' Read the remaining 5 bytes (the last byte is only sent with CRC enabled)
                  If Sdresponse(2) <> &H00 Or Sdresponse(3) <> &H00 Or Sdresponse(5) <> &HAA Then       ' Check if the CMD8 R7 response bytes 2-5 are identical to the command
                     Sdstatus = 20                          ' The first byte has already been checked, the last byte (CRC) is not sent
                  Elseif Sdresponse(4) <> &H01 Then
                     Sdstatus = 19
                  End If
               End If

               ' Sdstatus = 0 & Sdcardtype = 1 -> v1.x
               ' Sdstatus = 0 & Sdcardtype = 2 -> v2+

               If Sdstatus = 10 Then
                  Sdstatus = 0                              ' Remap status

                  Sdcommand = &HFF                          ' Send 8 additional clock cycles with cs low
                  Gosub Sdcommand1                          ' The SanDisk Extreme III 4GB class 6 requires this

                  Sdcommand = &H7A                          ' Send the first CMD58: &H7A &H00 &H00 &H00 &H00 &HFD
                  Gosub Sdcommand1
                  Sdcommand = &H00
                  Gosub Sdcommand1
                  Gosub Sdcommand1
                  Gosub Sdcommand1
                  Gosub Sdcommand1
                  Sdcommand = &HFD
                  Gosub Sdcommand1

                  Gosub Sdresponseloop                      ' Receive the single byte of response

                  If Sdresponse(1) = 255 Then
                     Sdstatus = 3                           ' Timeout in first CMD58
                  Else
                     Gosub Sdcheckr1                        ' Check R1 error codes
                     If Sdstatus = 12 Then
                        If Sdcardtype = 1 Then              ' v1.x
                           Sdstatus = 17                    ' Remap error code to indicate that it is not an SD card
                        End If
                     Else
                        If Sdstatus = 10 Then
                           Sdstatus = 0                     ' Remap status
                           Gosub Sdresponse2_5
                           If Sdresponse(3) <> 255 Or Sdresponse(4).7 <> 1 Then       ' Check OCR register response in bytes 2 & 3
                              Sdstatus = 18                 ' There are 9 voltage ranges 2.7 - 3.6V. All must be supported according to spec. OCR bit 15-23 must be high.
                           End If

                           If Sdstatus = 0 Then             ' If sdstatus = 0, the SD card is in a valid supply voltage

                           Sdtempw = 0
                           Do
                              Sdcommand = &HFF              ' Send 8 additional clock cycles with cs low
                              Gosub Sdcommand1

                              Sdcommand = &H77              ' Send CMD55 (required before all ACMD commands): &H77 &H00 &H00 &H00 &H00 &H65
                              Gosub Sdcommand1
                              Sdcommand = &H00
                              Gosub Sdcommand1
                              Gosub Sdcommand1
                              Gosub Sdcommand1
                              Gosub Sdcommand1
                              Sdcommand = &H65
                              Gosub Sdcommand1

                              Gosub Sdresponseloop          ' Receive the single byte of response

                              If Sdresponse(1) <> 255 Then

                                 Set Sd_cs                  ' Set CS, clock out 8 bits and reset CS
                                 Sdcommand = &HFF
                                 Gosub Sdcommand1
                                 Reset Sd_cs

                                 Sdcommand = &H69           ' Send CMD41: &H69 &H00 &H00 &H00 &H00 &HE5 ' SDSC compatible card (HDS = 0)
                                 Gosub Sdcommand1           ' Send CMD41: &H69 &H40 &H00 &H00 &H00 &H77 ' SDHC / SDXC compatible card (HDS = 1)
                                 If Sdcardtype = 1 Then     ' SDSC compatible card (HDS = 0)
                                    Sdcommand = &H00
                                 Else                       ' SDHC / SDXC compatible card (HDS = 1)
                                    Sdcommand = &H40
                                 End If
                                 Gosub Sdcommand1
                                 Sdcommand = &H00
                                 Gosub Sdcommand1
                                 Gosub Sdcommand1
                                 Gosub Sdcommand1
                                 If Sdcardtype = 1 Then     ' SDSC compatible card (HDS = 0)
                                    Sdcommand = &HE5
                                 Else                       ' SDHC / SDXC compatible card (HDS = 1)
                                    Sdcommand = &H77
                                 End If
                                 Gosub Sdcommand1

                                 Gosub Sdresponseloop       ' Receive the single byte of response

                              End If

                              Incr Sdtempw
                           Loop Until Sdresponse(1) = 0 Or Sdtempw = &HFFFF       ' The sample cards' loop counts were 2 (Kingston 4GB C2), 17 (SanDisk Extreme III 4GB C6), 18 (SanDisk v2+ 1GB), and 672 (Canon 32MB v1.x)

                              If Sdresponse(1) = 255 Then
                                 Sdstatus = 4               ' Timeout in CMD41
                              Else
                                 Gosub Sdcheckr1

                                 If Sdstatus = 0 Then       ' If sdstatus = 0, the SD card has accepted the host

                                    If Sdcardtype = 2 Then  ' For v2+ cards, an additional CMD58 is required according to spec.
                                                             ' Some cards can respond the CCS info before ACMD41 (Kingston 4GB CL2),
                                                             ' but 3 of my 4 cards could only return the voltage bits in the previous response.

                                       Sdcommand = &HFF     ' Send 8 additional clock cycles with cs low
                                       Gosub Sdcommand1

                                       Sdcommand = &H7A     ' Send second CMD58: &H7A &H00 &H00 &H00 &H00 &HFD
                                       Gosub Sdcommand1
                                       Sdcommand = &H00
                                       Gosub Sdcommand1
                                       Gosub Sdcommand1
                                       Gosub Sdcommand1
                                       Gosub Sdcommand1
                                       Sdcommand = &HFD
                                       Gosub Sdcommand1

                                       Gosub Sdresponseloop ' Receive the single byte of response

                                       If Sdresponse(1) = 255 Then
                                          Sdstatus = 5      ' Timeout in second CMD58
                                       Else
                                          Gosub Sdcheckr1   ' Check R1 error codes
                                          If Sdstatus = 0 Then
                                             Gosub Sdresponse2_5
                                             If Sdresponse(2).7 = 0 Then       ' Check OCR register response in byte 2
                                                Sdstatus = 22       ' SD power up busy
                                             End If
                                             If Sdresponse(2).6 = 1 Then       ' Card capacity status CCS bit. If it is 1, then Sdcardtype = 2 (previously set)
                                                Sdcardtype = 3       ' 1 = v1.x SDSC, 2 = v2+ SDSC, 3 = v2+ SDHC/SDXC
                                             End If
                                          End If
                                       End If
                                    End If
                                 End If
                              End If
                           End If
                        End If
                     End If
                  End If
               End If
            End If
         End If                                             ' Close CMD8
      End If                                                ' Close CMD0

      Set Sd_cs

      Sdcommand = &HFF                                      ' Clock SD to complete job
      Gosub Sdcommand1

      ' In SPI mode, speed is not guaranteed by specification, but the minimum supported 4-bit bus mode clock speed is 12,5 MHz.
      ' The maximum SPI speed for AVR 8-bit is 10MHz, so we set SPI to maximum speed, f osc / 2
      Spsr.0 = 1                                            ' Double speed (results in f osc / 2)
      Spcr.1 = 0                                            ' f osc / 4
      Spcr.0 = 0

      ' Spcr.1 = 0                                            ' f osc / 16
      ' Spcr.0 = 1

      ' Spcr.1 = 1                                            'f osc / 64
      ' Spcr.0 = 0

      ' Spcr.1 = 1                                            ' f osc / 128
      ' Spcr.0 = 1

   Return

   '-------------------------------------------------------------------------------

   Sdcheckr1:
      If Sdresponse(1).1 = 1 Then
         Sdstatus = 11                                      ' R1 erase reset
      Elseif Sdresponse(1).2 = 1 Then
         Sdstatus = 12                                      ' R1 illegal command
      Elseif Sdresponse(1).3 = 1 Then
         Sdstatus = 13                                      ' R1 command CRC error
      Elseif Sdresponse(1).4 = 1 Then
         Sdstatus = 14                                      ' R1 erase sequence error
      Elseif Sdresponse(1).5 = 1 Then
         Sdstatus = 15                                      ' R1 address error
      Elseif Sdresponse(1).6 = 1 Then
         Sdstatus = 16                                      ' R1 parameter error
      Elseif Sdresponse(1).0 = 1 Then
         Sdstatus = 10                                      ' R1 idle (running initialization)
      End If
   Return

#endif

'-------------------------------------------------------------------------------

Sdcommand1:
   Spiout Sdcommand , 1
Return

'-------------------------------------------------------------------------------

Sdresponse1:
   Spiin Sdresponse(1) , 1
Return

'-------------------------------------------------------------------------------

Sdresponse2_5:
   Spiin Sdresponse(2) , 5
Return

'-------------------------------------------------------------------------------

Sdresponseloop:
   Sdtempb = 0
   Do
      Gosub Sdresponse1                                     ' Receive the single byte of response
      Incr Sdtempb
   Loop Until Sdresponse(1) <> 255 Or Sdtempb = 255
Return

'-------------------------------------------------------------------------------

Sdreadsector:                                               ' Read sector from SD

   If Sdcardtype <= 2 Then
      Shift Sdsectord , Left , 9                            ' Byte addressing for SDSC cards (shift left 9 = multiply by 512)
   End If

   Reset Sd_cs

   Sdcommand = &HFF                                         ' Clock SD
   Gosub Sdcommand1

   Sdcommand = &H51                                         ' Send CMD17
   Gosub Sdcommand1
   Sdcommand = Sdsectorb(4)
   Gosub Sdcommand1
   Sdcommand = Sdsectorb(3)
   Gosub Sdcommand1
   Sdcommand = Sdsectorb(2)
   Gosub Sdcommand1
   Sdcommand = Sdsectorb(1)
   Gosub Sdcommand1
   Sdcommand = &HFF
   Gosub Sdcommand1

   Sdexpectedresponse = &H00                                ' First response after CMD17
   Gosub Sdseekresponse

   If Sdcardtype <= 2 Then
      Shift Sdsectord , Right , 9                           ' Byte addressing for SDSC cards (shift right 9 = divide by 512)
   End If

   If Sdstatus = 0 Then
      Sdexpectedresponse = &HFE                             ' Start token after CMD17
      Gosub Sdseekresponse
      If Sdstatus = 0 Then

         ' 2 = write unbuffered
         ' 1 = write buffered
         ' 0 = not writing
         #if Sdwmode <> 1
            For Sdtempw = 1 To 512                          ' Read the data block into Sdbuffer
               Spiin Sdbuffer(sdtempw) , 1
            Next Sdtempw
         #endif

         #if Sdwmode = 1
            If Sdreaddestination = 0 Then
               For Sdtempw = 1 To 512                       ' Read the data block into Sdbuffer
                  Spiin Sdbuffer(sdtempw) , 1
               Next Sdtempw
            Else
               For Sdtempw = 1 To 512                       ' Read the data block into Sdfatbuffer
                  Spiin Sdfatbuffer(sdtempw) , 1
               Next Sdtempw
            End If
         #endif

         Gosub Sdresponse1                                  ' Read dummy CRC to conclude data block
         Gosub Sdresponse1
      End If
   End If

   Set Sd_cs

   Sdcommand = &HFF                                         ' Clock SD to complete job
   Gosub Sdcommand1

Return

'-------------------------------------------------------------------------------

Sdseekresponse:                                             ' Wait for Sdexpectedresponse from SD or timeout
   Sdtempw = 0
   Do
      Gosub Sdresponse1
      Incr Sdtempw
   Loop Until Sdresponse(1) = Sdexpectedresponse Or Sdtempw = &HFFFF

   If Sdresponse(1) <> Sdexpectedresponse Then
      Sdstatus = 7                                          ' Timeout
   End If
Return

'-------------------------------------------------------------------------------

#if Sdwmode > 0

   Sdwritesector:                                           ' Write sector to SD

      If Sdcardtype <= 2 Then
         Shift Sdsectord , Left , 9                         ' Byte addressing for SDSC cards (shift left 9 = multiply by 512)
      End If

      Reset Sd_cs

      Sdcommand = &HFF                                      ' Clock SD to prepare for new command
      Gosub Sdcommand1

      Sdcommand = &H58                                      ' Send CMD24
      Gosub Sdcommand1
      Sdcommand = Sdsectorb(4)
      Gosub Sdcommand1
      Sdcommand = Sdsectorb(3)
      Gosub Sdcommand1
      Sdcommand = Sdsectorb(2)
      Gosub Sdcommand1
      Sdcommand = Sdsectorb(1)
      Gosub Sdcommand1
      Sdcommand = &HFF
      Gosub Sdcommand1

      Sdexpectedresponse = &H00                             ' First response after CMD24
      Gosub Sdseekresponse

      If Sdcardtype <= 2 Then
         Shift Sdsectord , Right , 9                        ' Byte addressing for SDSC cards (shift right 9 = divide by 512)
      End If

      If Sdstatus = 0 Then
         Sdcommand = &HFE                                   ' Start block token after CMD24
         Gosub Sdcommand1

         ' 2 = write unbuffered
         ' 1 = write buffered
         ' 0 = not writing
         #if Sdwmode = 1
            If Sdwriteorigin = 0 Then                       ' Write the data block from Sdbuffer
               For Sdtempw = 1 To 512
                  Spiout Sdbuffer(sdtempw) , 1
               Next Sdtempw
            Else                                            ' Write the data block from Sdfatbuffer
               For Sdtempw = 1 To 512
                  Spiout Sdfatbuffer(sdtempw) , 1
               Next Sdtempw
            End If
         #else
            For Sdtempw = 1 To 512                          ' Write the data block from Sdbuffer
               Spiout Sdbuffer(sdtempw) , 1
            Next Sdtempw
'           Sdtempw = 1
'           Do
'              Spiout Sdbuffer(Sdtempw) , 128
'              Sdtempw = Sdtempw + 128                ' Max 255 bytes per turn
'           Loop Until Sdtempw = 513
         #endif

         Sdcommand = &HFF                                   ' Write dummy CRC to conclude data block
         Gosub Sdcommand1
         Gosub Sdcommand1

         Sdtempw = 0
         Do                                                 ' Wait for and receive data response token
            Gosub Sdresponse1
            Incr Sdtempw
         Loop Until Sdresponse(1) <> &HFF Or Sdtempw = 512

         Sdtempb = Sdresponse(1) And &H0F
         Select Case Sdtempb
            Case &H05 : Sdstatus = 0                        ' Data accepted
            Case &H0B : Sdstatus = 41                       ' Data rejected due to a CRC error
            Case &H0D : Sdstatus = 42                       ' Data rejected due to a Write Error
         End Select

         If Sdstatus = 0 Then                               ' Wait until card is no longer busy
            Sdexpectedresponse = &HFF
            Gosub Sdseekresponse
         End If

      End If

      Sdcommand = &HFF                                      ' Clock SD to complete job
      Gosub Sdcommand1

      Set Sd_cs

      Sdcommand = &HFF                                      ' Clock SD to complete job
      Gosub Sdcommand1

   Return

#endif


'-------------------------------------------------------------------------------

#if Sdfsactive = 1

   Sdinitfs:

      Sdsectord = 0                                         ' Read the boot sector
      Gosub Sdreadsector

      Print "--> Readsector i.O = Sdstatus: " ; Sdstatus

      If Sdstatus = 0 Then

         ' Locate the start of the BRB (Boot Record Block)
         If Sdbuffer(1) = &HEB And Sdbuffer(3) = &H90 Then  ' Sdsectord is already 0
         Elseif Sdbuffer(1) = &HE9 Then                     ' Sdsectord is already 0
         Else
            Sdsectorb(1) = Sdbuffer(&H1c7)                  ' Sector number of first partition
            Sdsectorb(2) = Sdbuffer(&H1c8)
            Sdsectorb(3) = Sdbuffer(&H1c9)
            Sdsectorb(4) = Sdbuffer(&H1ca)
            Gosub Sdreadsector                              ' Read the boot record
         End If

         #if Sdusewipe = 1
            Sdpartstart = Sdsectord
         #endif

         If Sdstatus = 0 Then

            ' Value Description
            ' 00h Unknown Or Nothing
            ' 01h 12-bit FAT
            ' 04h 16-bit FAT (Partition Smaller than 32MB)
            ' 05h Extended MS-DOS Partition
            ' 06h 16-bit FAT (Partition Larger than 32MB)
            ' 0Bh 32-bit FAT (Partition Up to 2048GB)
            ' 0Ch Same as 0BH, but uses LBA1 13h Extensions
            ' 0Eh Same as 06H, but uses LBA1 13h Extensions
            ' 0Fh Same as 05H, but uses LBA1 13h Extensions

            Select Case Sdbuffer(&H1c3)

   '             Print
   '             Print "Filesystem ist: " ; Sdbuffer(&H1c3)
                 Print

               Case &H0B To &H0C : Sdfattype = 4 : Print "FAT32"       ' FAT32
               Case &H04 : Sdfattype = 2 : print "FAT16"    ' FAT16
               Case &H06 : Sdfattype = 2 : print "FAT16"    ' FAT16
               Case &H0E : Sdfattype = 2 : Print "FAT16"    ' FAT16
               Case Else :                                  ' My Kingston CL2 4GB SD card suddenly would only report &H72, even after formatting
                  If Sdbuffer(55) = 70 And Sdbuffer(56) = 65 And Sdbuffer(57) = 84 And Sdbuffer(58) = 49 And Sdbuffer(59) = 54 Then
                     Sdfattype = 2 : Print "FAT16"          ' FAT16
                  Elseif Sdbuffer(83) = 70 And Sdbuffer(84) = 65 And Sdbuffer(85) = 84 And Sdbuffer(86) = 51 And Sdbuffer(87) = 50 Then
                     Sdfattype = 4 : Print "FAT32"          ' FAT32
                  Else
                     Sdstatus = 23 : Print "FAT unbekannt"  ' Not supported file system
                  End If
            End Select
            Print

            If Sdstatus = 0 Then

               If Sdbuffer(&H0c) = 0 And Sdbuffer(&H0d) = 2 Then       ' (&H0b-c) Bytes Per Sec

                  Sdsecspercluster = Sdbuffer(&H0e)         ' [$0d] Read Secs Per Cluster
                  If Sdsecspercluster > 64 Then
                     Sdstatus = 29                          '  Unsupported number of sectors per cluster
                  Else

                     ' Sdtempb represents Sdnumoffats
                     Sdtempb = Sdbuffer(&H11)               ' [$10] Read Num of FATs

                     If Sdfattype = 2 Then                  ' FAT16
                        ' Sdtempd represents Sdsecsperfatl
                        Sdtempdb(1) = Sdbuffer(&H17)        ' [$16] Read Secs Per FAT
                        Sdtempdb(2) = Sdbuffer(&H18)        ' [$17]
                        Sdtempdb(3) = 0
                        Sdtempdb(4) = 0

                        ' Sdtempw represents Sdmaxrootentriesw
                        Sdtempwb(1) = Sdbuffer(&H12)        ' [$11] Read maximum number of root entries (N/A for FAT32)
                        Sdtempwb(2) = Sdbuffer(&H13)        ' [$12]
                        Sdsecsinroot = Sdtempw * 32         ' Calculate Sectors in Root Dir
                        Sdsecsinroot = Sdsecsinroot / Sdbytespersecw

                     Else                                   ' FAT32

                        ' Sdfat32rootclusterb(1) = Sdbuffer(45)       ' Cluster number for the FAT32 root (normally 2 but could be higher (e.g. in case of bad cluster))
                        ' Sdfat32rootclusterb(2) = Sdbuffer(46)
                        ' Sdfat32rootclusterb(3) = Sdbuffer(47)
                        ' Sdfat32rootclusterb(4) = Sdbuffer(48)

                        Sdtempdb(1) = Sdbuffer(45)          ' Cluster number for the FAT32 root (normally 2 but could be higher (e.g. in case of bad cluster))
                        Sdtempdb(2) = Sdbuffer(46)
                        Sdtempdb(3) = Sdbuffer(47)
                        Sdtempdb(4) = Sdbuffer(48)

                        If Sdtempd = 2 Then

                           ' Sdtempd represents Sdsecsperfatl
                           Sdtempdb(1) = Sdbuffer(&H25)     ' [$24] Read Secs Per FAT
                           Sdtempdb(2) = Sdbuffer(&H26)     ' [$25]
                           Sdtempdb(3) = Sdbuffer(&H27)     ' [$26]
                           Sdtempdb(4) = Sdbuffer(&H28)     ' [$27]

                           Sdsecsinroot = 0

                           #if Sdusefsinfo = 1
                              Sdfat32fsinfolocationb(1) = Sdbuffer(49)       ' Sector number for the FAT32 fsinfo (normally 1)
                              Sdfat32fsinfolocationb(2) = Sdbuffer(50)
                              Sdfat32fsinfolocationw = Sdfat32fsinfolocationw + Sdsectord
                           #endif

                        Else

                           Sdstatus = 21                    ' Unsupported FAT32 root cluster number (not 2)

                        End If

                     End If

                     #if Sdusewipe = 1
                        ' First see if BPB_TotSec16 contains size:
                        Sdtotsecsb(1) = Sdbuffer(20)        ' Read total number of sectors in the entire partition
                        Sdtotsecsb(2) = Sdbuffer(21)
                        Sdtotsecsb(3) = 0
                        Sdtotsecsb(4) = 0

                        ' If not, look in BPB_TotSec32:
                        If Sdtotsecsd = 0 Then
                           Sdtotsecsb(1) = Sdbuffer(33)     ' Read total number of sectors in the entire partition
                           Sdtotsecsb(2) = Sdbuffer(34)
                           Sdtotsecsb(3) = Sdbuffer(35)
                           Sdtotsecsb(4) = Sdbuffer(36)
                        End If
                     #endif

                     ' Sdtempw represents Sdreservedsecsw
                     Sdtempwb(1) = Sdbuffer(&H0f)           ' [$0e] Read Num of Reserved Sectors
                     Sdtempwb(2) = Sdbuffer(&H10)           ' [$0f]

                     ' Sdsectord represents Sdbootrecordl
                     ' Sdtempw represents Sdreservedsecsw
                     Sdfat1location = Sdsectord + Sdtempw   ' Locate FAT1
                     Sdfat2location = Sdfat1location + Sdtempd       ' Locate FAT2 (Sdtempd represents Sdsecsperfatl)

                     ' Sdtempb represents Sdnumoffats
                     ' Sdtempd represents Sdsecsperfatl
                     Sdrootdirlocation = Sdtempb * Sdtempd  ' Locate FAT16 Root Dir (Sdrootdirlocation is only relevant for FAT<32 and as a basis for the start of the data area)
                     ' Sdrootdirlocation = Sdbootrecordl + Sdrootdirlocation
                     ' Sdrootdirlocation = Sdreservedsecsw + Sdrootdirlocation
                     Sdrootdirlocation = Sdfat1location + Sdrootdirlocation

                     Sddataareastart = Sdrootdirlocation + Sdsecsinroot       ' Locate start of data, starts with cluster 2 (where the FAT32 root directory is)

                  End If

               Else

                 Sdstatus = 35                              ' Unsupported sector size (not 512)

               End If

            End If

         End If

      End If

   Return

   '-------------------------------------------------------------------------------

   Sdlocatesector:

   ' Input variable:
   ' Sdclusterd = current cluster

   ' Output variable:
   ' Sdsectord  = the absolute sector number for this cluster

      Sdsectord = Sdclusterd - 2
      Sdsectord = Sdsectord * Sdsecspercluster
      Sdsectord = Sdsectord + Sddataareastart

   Return

   '-------------------------------------------------------------------------------

   Sdlocatenextcluster:

   ' Input variable:
   ' Sdclusterd = current cluster

   ' Output variable:
   ' Sdclusterd = next cluster

      Gosub Sdcalculatefat1sector

      Gosub Sdreadsector                                    ' Read the FAT sector
      If Sdstatus = 0 Then
         Sdbufferpos = Sdbufferpos - 1
         Sdtempw = 0
         Do
            Incr Sdtempw
            Incr Sdbufferpos
            Sdclusterb(sdtempw) = Sdbuffer(sdbufferpos)
         Loop Until Sdtempw = Sdfattype
      End If

   Return

   '-------------------------------------------------------------------------------

   Sdcalculatefat1sector:

   ' Input variable:
   ' Sdclusterd    = current cluster

   ' Output variables:
   ' Sdsectord     = absolute FAT1 sector number
   ' Sdbufferpos   = buffer pos in this sector

      Sdtempd = Sdclusterd * Sdfattype                      ' Offset in bytes from sdfat1location (Sdfattype = 2 for FAT16 and 4 for FAT32)
      Sdsectord = Sdtempd \ Sdbytespersecw                  ' Offset in sectors from sdfat1location
      Sdtempd = Sdtempd Mod Sdbytespersecw                  ' Byte position in the resulting sector (1 too low!)
      Sdbufferpos = Sdtempd + 1
      Sdsectord = Sdsectord + Sdfat1location                ' FAT sector for the current cluster

   Return

#endif


'===============================================================================


#if Sdrmode = 1 And Sdfsactive = 1

   Sdreadbyte:
   ' Used to read a single byte from the current file, as located by Gosub Sdfindentryindirectory or Gosub Sddirlist

   ' Before calling, make sure that Sdfilesized > 0, Sdstatus = 0, and Sdeof = 0

   ' Input variables:
   ' Sdclusterd     = current file cluster
   ' Sdsecincluster = sector number in this cluster, set to 0 before the very first call
   ' Sdbufferpos    = buffer pos in this sector
   ' Sdsectord      = absolute sector number

   ' Output variables:
   ' Sdbyterw       = the read byte
   ' Sdbytesread    = read byte counter
   ' Sdeof            1 = End Of File found, else 0
   ' Sdstatus

      If Sdsecincluster = 0 Then                            ' Very first call

         #if Sdusedirlist = 1
            Sdfilesizeb(1) = Sddirlistdirentry(29)          ' Read file size in bytes
            Sdfilesizeb(2) = Sddirlistdirentry(30)
            Sdfilesizeb(3) = Sddirlistdirentry(31)
            Sdfilesizeb(4) = Sddirlistdirentry(32)

            Sdclusterb(1) = Sddirlistdirentry(27)           ' Cluster number for the subdirectory we are about to enter
            Sdclusterb(2) = Sddirlistdirentry(28)
            Sdclusterb(3) = Sddirlistdirentry(21)
            Sdclusterb(4) = Sddirlistdirentry(22)
         #endif

         Gosub Sdlocatesector                               ' Read the first sector of the cluster where the file starts
         Gosub Sdreadsector
         If Sdstatus = 0 Then
            Sdsecincluster = 1                              ' Initialize pointers and byte counter
            Sdbufferpos = 1
            Sdbytesread = 0
            Sdeof = 0
         End If

      End If

      If Sdbufferpos > Sdbytespersecw Then                  ' Have we passed the end of the sector?
         Incr Sdsecincluster
         If Sdsecincluster > Sdsecspercluster Then          ' Have we passed the last sector of this cluster?
            Gosub Sdlocatenextcluster                       ' Locate next cluster
            Gosub Sdcheckclusterreference                   ' Check if it indicates EOC (in that case Sdstatus = 31)
            If Sdstatus = 0 Then                            ' EOF has not been reached
               Gosub Sdlocatesector                         ' Locate the sector start of the new cluster
               Gosub Sdreadsector
               Sdsecincluster = 1
            End If
         Else
            Incr Sdsectord
            Gosub Sdreadsector
         End If
         Sdbufferpos = 1
      End If

      If Sdstatus = 0 Then
         Sdbyterw = Sdbuffer(sdbufferpos)
         Incr Sdbufferpos
         Incr Sdbytesread
         If Sdbytesread >= Sdfilesized Then
            Sdeof = 1
         End If
      Else
         Sdeof = 1
      End If

   Return

#endif

'===============================================================================

#if Sdusefind = 1

   Sdfindentryindirectory:
   ' Used to find a file, subdirectory, volume ID, or available directory entry

   ' Input variables:
   ' Sdclusterd       = the cluster number for the directory in which you want to search (actual cluster or 0 for root directory)
   ' Sdsecincluster   = 1 if you are doing your first search, otherwise the actual Sdsecincluster
   ' Sdbufferpos      = 1 if you are doing your first search, otherwise the actual Sdbufferpos
   ' Sdentrynames     = the file or subdirectory name
   ' Sddirectorymode    0 = find file, 1 = find subdirectory, 2 = find volume ID, 3 = find available directory entry, 4 find parent directory
   ' If Sdrwmode = 2 Or Sdrwmode = 4
   '   Sdreaddestination  0 = Sdbuffer(), 1 = Sdfatbuffer()

   ' Output variables:
   ' Sdstatus:
   '   28 = An available directory space has been found
   '   31 = EOC End OF Cluster chain found (directory)
   '   32 = EOD End Of Directory marker found
   '   34 = The volume ID has been found
   '   47 = Parent directory pointer found
   '   48 = File or subdirectory found

   ' Sddirectorymode = 2:
   '   Sdclusterd           = Next cluster number (where file/subdirectory resides)
   '   Sdentrynames         = The volume ID

   ' Sddirectorymode <> 2:
   '   Sddirclusterd        = Cluster number for this directory entry
   '   Sddirsecincluster    = Chain start sector number of the current directory cluster, 1 to Sdsecincluster
   '   Sddirbufferpos       = Chain start directory buffer position, 1 to 512
   '   Sdclusterd           = Next cluster number (where file/subdirectory resides)

      ' 2 = write unbuffered
      ' 1 = write buffered
      ' 0 = not writing
      #if Sdwmode = 1
         Sdreaddestination = 0                              ' Only relevant for buffered writing
      #endif

      ' Special handling of root directory
      If Sdclusterd = 0 Then
         If Sdfattype = 2 Then                              ' FAT16 root directory
            Sdsectord = Sdrootdirlocation
            Sdsectorend = Sdsecsinroot
         Else
            Sdclusterd = Sdfat32rootclusterd                ' FAT32 root directory remapped to cluster 2
         End If
      End If

      ' If not in FAT16 root directory, locate the first directory sector
      If Sdclusterd > 0 Then
         Sdsectorend = Sdsecspercluster
         Gosub Sdlocatesector                               ' Calculate the first sector in Sdclusterd and place in Sdsectord
      End If

      Do
         Do                                                 ' Loop through this cluster
            Sdbufferpos = 1
            Gosub Sddirsectorloop
            If Sdstatus = 0 Then
               Incr Sdsectord
               Sdbufferpos = 1
               Incr Sdsecincluster
            End If

         ' Loop through this cluster until:
         ' file or subdirectory is found or
         ' empty directory entry has been found or
         ' we have scanned all sectors in the cluster without finding the entry
         Loop Until Sdstatus <> 0 Or Sdsecincluster > Sdsectorend

         If Sdstatus = 0 Then                               ' Entry hasn't been found and we have reached the end of the current directory cluster or FAT16 root directory
            If Sdclusterd = 0 Then
               Sdstatus = 46                                ' We have searched the entire FAT16 root directory but not found what we were looking for
            Else
               #if Sdwmode > 0
                  Sdpreviousclusterd = Sdclusterd           ' If we are writing, we here want to store the previous cluster number for cluster extension
               #endif
               Gosub Sdlocatenextcluster                    ' Look up the next cluster in the FAT
               Gosub Sdcheckclusterreference                ' Check if it indicates EOC (in that case Sdstatus = 31)
               If Sdstatus = 0 Then
                  Gosub Sdlocatesector                      ' Calculate the first sector in the next Sdclusterd and place in Sdsectord
                  Sdsecincluster = 1

                  #if Sdwmode > 0                           ' Store directory position if we are using write mode
               Else                                         ' We have reached the EOC marker, store this directory
                     Sddirclusterd = Sdpreviousclusterd     ' Store the directory cluster number in Sddirclusterd
                     Sddirsecincluster = Sdsecincluster     ' Chain start sector number of the current directory cluster, 1 to Sdsecincluster
                     Sddirbufferpos = Sdbufferpos           ' Chain start directory buffer position, 1 to 512
                  #endif

               End If
            End If
         End If

      Loop Until Sdstatus <> 0

   Return


   '-------------------------------------------------------------------------------

   Sddirsectorloop:
   ' Called from Sdfindentryindirectory

   ' Input variables:
   ' Sdsectord              = absolute directory sector number
   ' Sdbufferpos            = 1 if you are doing your first search, otherwise the actual Sdbufferpos
   ' Sddirectorymode
   '   0 = find file
   '   1 = find subdirectory
   '   2 = find volume ID
   '   3 = find available directory entry
   '   4 = find parent directory
   '   5 = return entire entry unless EOD (only if enabled by Sdusefindstoreentry = 1)

   ' Output variables:
   ' Sdstatus:
   '   28 = An available directory space has been found
   '   32 = EOD End Of Directory marker found
   '   34 = The volume ID has been found
   '   47 = Parent directory pointer found
   '   48 = File or subdirectory found

   ' Sddirectorymode = 2:
   '   Sdclusterd           = Next cluster number (where file/subdirectory resides)
   '   Sdentrynames         = The volume ID

   ' Sddirectorymode <> 2:
   '   Sddirclusterd        = Cluster number for this directory entry
   '   Sddirsecincluster    = Chain start sector number of the current directory cluster, 1 to Sdsecincluster
   '   Sddirbufferpos       = Chain start directory buffer position, 1 to 512
   '   Sdclusterd           = Next cluster number (where file/subdirectory resides)

      Gosub Sdreadsector                                    ' Read Sdsectord to buffer
      If Sdstatus = 0 Then
         Do
            If Sdbuffer(sdbufferpos) = &H00 Then
               Sdstatus = 32                                ' EOD End Of Directory marker found
            Else

            #if Sdusefind = 1 And Sdusefindstoreentry = 1
               If Sddirectorymode = 5 Then                  ' Store the entire directory entry in Sdfinddirentry()
                  Sdtempw = Sdbufferpos
                  For Sdtempb = 1 To 32
                     Sdfinddirentry(sdtempb) = Sdbuffer(sdtempw)
                     Incr Sdtempw
                  Next Sdtempb
               Else
            #endif

                  Sdtempw = Sdbufferpos + 11
                  Sdtempb = Sdbuffer(sdtempw) Or &B11110000
                  If Sdtempb <> &HFF Then                   ' Not Long FileName entry
                     Select Case Sddirectorymode
                        Case 0 To 1:                        ' Find file or find subdirectory
                           Sdtempb = 1
                           Sdtempw = Sdbufferpos
                           While Sdbuffer(sdtempw) = Sdentrynameb(sdtempb) And Sdtempb < 12
                              Incr Sdtempb
                              Incr Sdtempw
                           Wend
                           If Sdtempb = 12 Then
                              Sdstatus = 48                 ' File or subdirectory found
                           End If
                        Case 2:                             ' Find volume ID
                           If Sdbuffer(sdtempw).3 = 1 Then
                              Sdstatus = 34                 ' Volume ID found
                              Sdtempb = 1
                              Sdtempw = Sdbufferpos
                              While Sdtempb < 12
                                 Sdentrynameb(sdtempb) = Sdbuffer(sdtempw)
                                 Incr Sdtempb
                                 Incr Sdtempw
                              Wend
                           End If

                        #if Sdwmode > 0                     ' Find available directory entry is only relevant if we are using write mode
                           Case 3:
                              If Sdbuffer(sdbufferpos) = &HE5 Then
                                 Sdstatus = 28              ' Available (previously erased) directory entry found
                              End If
                        #endif

                        Case 4:                             ' Find parent directory cluster
                           Sdtempw = Sdbufferpos + 1
                           If Sdbuffer(sdbufferpos) = &H2E And Sdbuffer(sdtempw) = &H2E Then
                              Sdstatus = 47                 ' Parent directory pointer found
                           End If
                     End Select
                  End If
               End If
               If Sdstatus = 0 Then
                  Sdbufferpos = Sdbufferpos + 32            ' Matching entry not found - point to the next entry
               Else

                  If Sddirectorymode <> 2 Then              ' Point to the cluster where the file/subdirectory/parent directory/available directory entry resides

                     #if Sdwmode > 0                        ' Store directory position if we are using write mode
                        Sddirclusterd = Sdclusterd          ' Store the directory cluster number in Sddirclusterd
                        Sddirsecincluster = Sdsecincluster  ' Chain start sector number of the current directory cluster, 1 to Sdsecincluster
                        Sddirbufferpos = Sdbufferpos        ' Chain start directory buffer position, 1 to 512
                     #endif

                     Gosub Sdgetclusterandsize              ' Place cluster number in Sdclusterd and filesize in Sdfilesized

                  End If
               End If

            #if Sdusefind = 1 And Sdusefindstoreentry = 1
                End If
            #endif

         Loop Until Sdstatus <> 0 Or Sdbufferpos > Sdbytespersecw

      End If

   Return

   '-------------------------------------------------------------------------------

   Sdcheckclusterreference:                                 ' Check if it indicates EOC (>=&HFFF8 or >=&H0FFFFFF8)
      If Sdfattype = 2 Then                                 ' FAT16
         Sdclusterb(3) = 0
         Sdclusterb(4) = 0
         If Sdclusterd > &HFFF7 Then
            Sdstatus = 31                                   ' EOC End OF Cluster chain found
         End If
      Elseif Sdfattype = 4 Then                             ' FAT32
         Sdclusterb(4) = Sdclusterb(4) And &B00001111
         If Sdclusterd > &H0FFFFFF7 Then
            Sdstatus = 31                                   ' EOC End OF Cluster chain found
         End If
      End If
   Return

   '-------------------------------------------------------------------------------

   Sdgetclusterandsize:

      If Sdfattype = 4 Then                                 ' FAT32
         Sdtempw = Sdbufferpos + 20
         Sdclusterb(3) = Sdbuffer(sdtempw)                  ' 21 File/subdirectory cluster number
         Incr Sdtempw
         Sdclusterb(4) = Sdbuffer(sdtempw)                  ' 22
         Sdtempw = Sdtempw + 5
      Else                                                  ' FAT16
         Sdclusterb(3) = 0
         Sdclusterb(4) = 0
         Sdtempw = Sdbufferpos + 26
      End If

      Sdclusterb(1) = Sdbuffer(sdtempw)                     ' 27
      Incr Sdtempw
      Sdclusterb(2) = Sdbuffer(sdtempw)                     ' 28

      Incr Sdtempw
      Sdfilesizeb(1) = Sdbuffer(sdtempw)                    ' 29 File size in bytes
      Incr Sdtempw
      Sdfilesizeb(2) = Sdbuffer(sdtempw)                    ' 30
      Incr Sdtempw
      Sdfilesizeb(3) = Sdbuffer(sdtempw)                    ' 31
      Incr Sdtempw
      Sdfilesizeb(4) = Sdbuffer(sdtempw)                    ' 32

   Return

#endif

'===============================================================================

' 2 = write unbuffered
' 1 = write buffered
' 0 = not writing
#if Sdwmode > 0 And Sdfsactive = 1

   Sdcreatefileordir:
   ' Used as the first of three steps when creating a new file or the only step when creating a new subdirectory
   ' (Sdwritebyte and Sdclosefile are the subsequent two)

   ' Find free FAT entry, find free directory entry, and save the directory entry back to the SD card

   ' Input variables:
   ' Sdentrynames          = the 8.3 filename
   ' Sdcreatemode            0 = file, 1 = subdirectory
   ' Sdstartdirclusterd    = the directory cluster number (in which the file or subdirectory should be created). Set to 0 for root directory.
   ' Sdyear                = the year
   ' Sdmonth               = the month
   ' Sdday                 = the day
   ' Sdhours               = the hours
   ' Sdminutes             = the minutes
   ' Sdseconds             = the seconds
   ' Sdmseconds            = the milliseconds

   ' If Sdmaintainfsinfo = 1
   '   Sdfsinfofreeclustersd = the number of free clusters
   '   Sdfsinfonextfreeclusterd = the next unused cluster (typically not the first free re-usable cluster)

   ' Output variables:
   ' Sdpartitionfull       = 1 if the partition is full (no more free FAT entries)
   ' Sdfatsectornum        = the FAT sector number
   ' Sdfatbufferpos        = the position in this sector
   ' Sddirclusterd         = the directory cluster
   ' Sddirsecincluster     = the sector in this cluster
   ' Sddirbufferpos        = the position in this sector
   ' Sdwclusterd           = the cluster number we are writing to
   ' Sdwsecincluster       = the sector in this cluster (1)
   ' Sdwbufferpos          = the position in this sector (0) - please notice!
   ' Sdwfilesized          = the file size (0)

   ' If Sdmaintainfsinfo = 1
   '   Sdfsinfofreeclustersd = the number of free clusters
   '   Sdfsinfonextfreeclusterd = the next unused cluster (typically not the first free re-usable cluster)

      ' Find the first available directory entry in the specified directory (cluster) and store it in Sddirclusterd, Sddirsecincluster, and Sdirbufferpos
      Sdclusterd = Sdstartdirclusterd
      Sdsecincluster = 1
      Sdbufferpos = 1

      #if Sdusedirlist = 1
         Sddirlistarraycounter = 0
         Sddirlistdirection = 0
         Do
            Sdstatus = 0
            Gosub Sddirlist
         Loop Until Sdstatus = 28 Or Sdstatus = 32 Or Sddirlistendpoint = 1       ' Empty entry found or EOD marker found or EOD reached

         ' Store directory position for this directory entry
         Sddirclusterd = Sdclusterd                         ' Chain start directory cluster number
         Sddirsecincluster = Sdsecincluster                 ' Sector number in cluster
         Sddirbufferpos = Sdbufferpos                       ' Buffer position in sector

         If Sddirlistendpoint = 1 And Sddirclusterd <> 0 Then       ' EOD found and not in FAT16 root
      #else
         #if Sdusefind = 1
            Sddirectorymode = 3                             ' Find available directory entry
            Gosub Sdfindentryindirectory

            If Sdstatus = 31 Then                           ' EOC End OF Cluster chain found (directory) - we must first extend the cluster (if not FAT16 root)
         #endif
      #endif

         Sdstatus = 0

         ' Extend directory with additional cluster
         Sdsectord = Sdfat1location                         ' Find free FAT1 entry and store position in Sdfatsectornum, and Sdfatbufferpos plus Sdfatclusterd
         Sdbufferpos = 1
         Gosub Sdfindfreefat

         If Sdstatus = 0 Then
            Sdclusterd = Sddirclusterd                      ' Read the FAT entry for the directory cluster that we are about to extend
            Gosub Sdcalculatefat1sector
            Gosub Sdreadsector

            If Sdstatus = 0 Then                            ' Save the updated FAT sector holding the now extended directory cluster
               Sdtempw = Sdbufferpos
               Sdbuffer(sdtempw) = Sdfatclusterb(1)
               Incr Sdtempw
               Sdbuffer(sdtempw) = Sdfatclusterb(2)
               If Sdfattype = 4 Then
                  Incr Sdtempw
                  Sdbuffer(sdtempw) = Sdfatclusterb(3)
                  Incr Sdtempw
                  Sdbuffer(sdtempw) = Sdfatclusterb(4)
               End If
               #if Sdwmode = 1
                  Sdwriteorigin = 0
               #endif
               Gosub Sdwritesector
               If Sdstatus = 0 Then
                  Sdsectord = Sdfat1location - Sdsectord
                  Sdsectord = Sdsectord + Sdfat2location
                  Gosub Sdwritesector
                  If Sdstatus = 0 Then

                     Sdclusterd = &H0FFFFFFF                ' Save EOC marker to the FAT entry in Sdfatclusterd
                     Gosub Sdsavefatsec
                     If Sdstatus = 0 Then
                        Sdclusterd = Sdfatclusterd          ' Empty the extended directory cluster
                        Gosub Sdwclearcluster
                        If Sdstatus = 0 Then
                           Decr Sdsectord
                           Gosub Sdwritesector
                           If Sdstatus = 0 Then

                              #if Sdusefsinfo = 1
                                 Gosub Sdupdatefsinfo       ' Update the fsinfo variables
                              #endif

                              ' Store directory position for this directory entry
                              Sddirclusterd = Sdfatclusterd ' Directory cluster number
                              Sddirsecincluster = 1         ' Sector number in cluster
                              Sddirbufferpos = 1            ' Buffer position in sector
                              Gosub Sdlocatesector
                              Sdstatus = 32
                           End If
                        End If
                     End If
                  End If
               End If
            End If
         End If
      Else
         Sdfatsectornum = Sdfat1location
         Sdfatbufferpos = 1
      End If

      ' An available (previously erased) directory entry or EOD End Of Directory marker found
      ' Sddirclusterd, Sddirsecincluster, and Sddirbufferpos now point to this directory entry
      If Sdstatus = 28 Or Sdstatus = 32 Then                ' Free directory entry found
         Sdstatus = 0                                       ' Remap Sdstatus

         ' Find free FAT1 entry and store position in Sdfatsectornum, and Sdfatbufferpos plus Sdfatclusterd
         Sdsectord = Sdfatsectornum                         ' Continue looking in the same FAT sector
         Sdbufferpos = Sdfatbufferpos
         Gosub Sdfindfreefat
         If Sdstatus = 0 Then

            Gosub Sdlocatedirsector                         ' Point to the available directory entry again
            #if Sdwmode = 1
               Sdreaddestination = 0
            #endif
            Gosub Sdreadsector
            If Sdstatus = 0 Then

               #if Sdusefsinfo = 1
                  Gosub Sdupdatefsinfo                      ' Update the fsinfo variables
               #endif

               ' Store all information in this new directory entry, except file size, that will be updated at the end in a second read+write to this directory sector
               ' Sdentrynames set before calling Sdcreatefileordir
               Sdclusterd = Sdfatclusterd
               Sdwfilesized = 0
               Sdbufferpos = Sddirbufferpos

               Gosub Sdstoredirentry                        ' Sdcreatemode set before calling Sdcreatefileordir
               #if Sdwmode = 1
                  Sdwriteorigin = 0                         ' Write from Sdbuffer
               #endif

               Gosub Sdwritesector                          ' Write the updated directory sector back to the SD card

            End If

            If Sdcreatemode = 1 And Sdstatus = 0 Then       ' Create subdirectory ., .., (and EOD) entries in the new directory cluster

               Sdclusterd = Sdfatclusterd                   ' Calculate the absolute sector number for the free cluster and write the last (sdsecspercluster - 1) sectors
               Gosub Sdwclearcluster

               If Sdstatus = 0 Then

                  Sdentrynames = Space(11)                  ' First clean out Sdentrynames
                  Sdentrynameb(1) = &H2E                    ' Store the subdirectory's starting cluster number in the . directory entry
                  Sdclusterd = Sdfatclusterd
                  Sdwfilesized = 0
                  Sdbufferpos = 1
                  Gosub Sdstoredirentry

                  Sdentrynameb(2) = &H2E                    ' Store the parent directory's starting cluster number in the .. directory entry
                  Sdclusterd = Sdstartdirclusterd
                  Sdbufferpos = 33
                  Gosub Sdstoredirentry
                  Decr Sdsectord                            ' Finally write the first sector
                  Gosub Sdwritesector

                  If Sdstatus = 0 Then
                     Sdclusterd = &H0FFFFFFF                ' Save EOC marker to the FAT sector in Sdfatclusterd
                     Gosub Sdsavefatsec
                  End If
               End If
            End If
         End If
      End If
      Sdclosefile = 0

      If Sdstatus = 44 Then                                 ' End of FAT and no free entry found (partition full)
         Sdpartitionfull = 1                                ' The partition is full (no more free FAT entries)
         Sdstatus = 0
      End If

   Return

   '-------------------------------------------------------------------------------

   #if Sduseappend = 1

      Sdpreparetoappend:
      ' Used to append to a pre-existing file

      ' Input variables:
      ' Sdentrynames          = the 8.3 filename
      ' Sdyear                = the year
      ' Sdmonth               = the month
      ' Sdday                 = the day
      ' Sdhours               = the hours
      ' Sdminutes             = the minutes
      ' Sdseconds             = the seconds
      ' Sdstartdirclusterd    = the first cluster of this (sub-)directory
      ' Sdfsinfofreeclustersd = the number of free clusters
      ' Sdfsinfonextfreeclusterd = the next unused cluster (typically not the first free re-usable cluster)

      ' Output variables:
      ' Sdwclusterd           = the cluster number we are writing to
      ' Sdwsecincluster       = the sector in this cluster
      ' Sdwbufferpos          = the position in this sector
      ' Sdwfilesized          = the file size
      ' Sdfatsectornum        = the FAT sector number
      ' Sdfatbufferpos        = the position in this sector
      ' Sddirclusterd         = the directory cluster
      ' Sddirsecincluster     = the sector in this cluster
      ' Sddirbufferpos        = the position in this sector
      ' Sdfsinfofreeclustersd = the number of free clusters
      ' Sdfsinfonextfreeclusterd = the next unused cluster (typically not the first free re-usable cluster)

      ' Sddirclusterd, Sddirsecincluster, and Sddirbufferpos point to this directory entry
      ' Sdwclusterd,   Sdwsecincluster,   and Sdwbufferpos   point to the last byte of the file
      ' Sdfatclusterd, Sdfatsectornum,    and Sdfatbufferpos point to the last fat entry(cluster number)


         ' Find the file
         Sdclusterd = Sdstartdirclusterd
         Sdsecincluster = 1
         Sdbufferpos = 1

         #if Sdusedirlist = 1
            Sdappendfound = 0
            Sddirlistarraycounter = 0
            Sddirlistdirection = 0                          ' Loop through this directory forward
            Do
               Do
                  Sdstatus = 0
                  Gosub Sddirlist
               Loop Until Sdstatus = 26 Or Sdstatus = 32 Or Sddirlistendpoint = 1
               If Sdstatus = 26 Then                        ' Look for a file named Sdentrynames
                  Sdappendcontinue = 1
                  Sdtempb = 1
                  Do
                     If Sddirlistdirentry(sdtempb) <> Sdentrynameb(sdtempb) Then
                        Sdappendcontinue = 0
                     End If
                     Incr Sdtempb
                  Loop Until Sdappendcontinue = 0 Or Sdtempb = 12
                  If Sdappendcontinue = 1 Then
                     Sdappendfound = 1
                  End If
               End If
            Loop Until Sdappendfound = 1 Or Sdstatus = 32 Or Sddirlistendpoint = 1

            If Sdappendfound = 1 Then
               Sdstatus = 0

               Sddirclusterd = Sdclusterd                   ' Store this directory entry position
               Sddirsecincluster = Sdsecincluster
               Sddirbufferpos = Sdbufferpos

               Sdwfilesizeb(1) = Sddirlistdirentry(29)      ' Store original filesize in Sdwfilesized
               Sdwfilesizeb(2) = Sddirlistdirentry(30)
               Sdwfilesizeb(3) = Sddirlistdirentry(31)
               Sdwfilesizeb(4) = Sddirlistdirentry(32)

               Sdwclusterb(1) = Sddirlistdirentry(27)       ' Store the file's starting cluster number in the new directory entry
               Sdwclusterb(2) = Sddirlistdirentry(28)
               Sdwclusterb(3) = Sddirlistdirentry(21)
               Sdwclusterb(4) = Sddirlistdirentry(22)

               Sdclusterd = Sdwclusterd

        #else
        #if Sdusefind = 1

            Sddirectorymode = 0                             ' Find file
            Gosub Sdfindentryindirectory
            If Sdstatus = 48 Then                           ' File found
               Sdstatus = 0                                 ' Sddirclusterd, Sddirsecincluster, and Sddirbufferpos now point to this directory entry

               Gosub Sdgetclusterandsize                    ' Place file's starting cluster number in Sdwclusterd and original filesize in Sdwfilesized
               Sdwclusterd = Sdclusterd
               Sdwfilesized = Sdfilesized

        #endif
        #endif

            ' Loop through the FAT1 chain until EOC is found
            Do
               Sdfatclusterd = Sdclusterd                   ' Store the last known cluster number
               Gosub Sdlocatenextcluster                    ' Look up the next cluster number
               Gosub Sdcheckclusterreference                ' Check if it indicates EOC (in that case Sdstatus = 31)

            Loop Until Sdstatus <> 0

               If Sdstatus = 31 Then                        ' Unless bad cluster found (Assume the original file size is correct)

               Sdstatus = 0

               Sdwclusterd = Sdfatclusterd                  ' Store the file's last cluster number

               Sdtempd = Sdwfilesized Mod Sdbytespersecw

               'Sdwbufferposb(1) = Sdtempdb(1)            ' Buffer position in the last sector
               'Sdwbufferposb(2) = Sdtempdb(2)
               Sdwbufferpos = Sdtempd

               Sdtempd = Sdwfilesized \ Sdbytespersecw      ' Number of entire sectors
               Sdtempd = Sdtempd Mod Sdsecspercluster
               Sdwsecincluster = Sdtempdb(1) + 1            ' Sector number in the last cluster

               Sdclusterd = Sdwclusterd                     ' Calculate the FAT1 sector number and position for this cluster
               Gosub Sdcalculatefat1sector
               Sdfatsectornum = Sdsectord                   ' Store position
               Sdfatbufferpos = Sdbufferpos

               #if Sdwmode = 1
                  For Sdtempw = 1 To 512                    ' Copy this FAT sector data into Sdfat1buffer
                     Sdfatbuffer(sdtempw) = Sdbuffer(sdtempw)
                  Next Sdtempw
               #endif

               Gosub Sdlocatedirsector                      ' Update the directory sector with the new write and access DateTime
               #if Sdwmode = 1
                  Sdreaddestination = 0
               #endif
               Gosub Sdreadsector
               If Sdstatus = 0 Then

                  Gosub Sdpreparedatetime                   ' Calculate and store date and time in the directory entry
                  Sdtempw = Sddirbufferpos + 18
                  Gosub Sdstore19_26

                  #if Sdwmode = 1
                     Sdwriteorigin = 0
                  #endif
                  Gosub Sdwritesector

                  If Sdstatus = 0 Then                      ' Read the file's last sector into Sdbuffer()
                     Sdclusterd = Sdwclusterd
                     Gosub Sdlocatesector
                     Sdsectord = Sdsectord + Sdwsecincluster
                     Decr Sdsectord
                     Sdstatus = 0
                     Gosub Sdreadsector
                  End If
               End If

            End If

         End If

      Return

   #endif

   '-------------------------------------------------------------------------------

   Sdwritebyte:
   ' Used to write a byte to an open file
   ' Always make sure that Sdclosefile = 0 before writing

   ' Input variables:
   ' Sdclosefile       must be 0 - otherwise the file should be closed
   ' Sdwclusterd     = the cluster number we are writing to (initially set by Sdcreatefileordir or Sdappendfile - touch only when writing to > 1 file)
   ' Sdwsecincluster = the sector in this cluster           (initially set by Sdcreatefileordir or Sdappendfile - touch only when writing to > 1 file)
   ' Sdwbufferpos    = the position in this sector          (initially set by Sdcreatefileordir or Sdappendfile - touch only when writing to > 1 file)
   ' Sdwfilesized    = the file size                        (initially set by Sdcreatefileordir or Sdappendfile - touch only when writing to > 1 file)
   ' Sdfatsectornum  = the FAT sector number                (initially set by Sdcreatefileordir or Sdappendfile - touch only when writing to > 1 file)
   ' Sdfatbufferpos  = the position in this sector          (initially set by Sdcreatefileordir or Sdappendfile - touch only when writing to > 1 file)
   ' Sdbuffer()                                             (touch only when writing to > 1 file)
   ' Sdbyterw        = the data byte we are about to write

   ' Output variables:
   ' Sdwclusterd     = the cluster number we are writing to
   ' Sdwsecincluster = the sector in this cluster
   ' Sdwbufferpos    = the position in this sector
   ' Sdwfilesized    = the file size
   ' Sdfatsectornum  = the FAT sector number
   ' Sdfatbufferpos  = the position in this sector
   ' Sdbuffer()
   ' Sdpartitionfull = 1 if the partition is full (there are no more free FAT entries)
   ' Sdclosefile     = 1 if the file should be closed after the return from this gosub

   ' Returned statuses:
   ' Sdstatus =  0 Successful
   ' Sdstatus =  7 Timeout
   ' Sdstatus = 41 Data rejected due to a CRC error
   ' Sdstatus = 42 Data rejected due to a Write Error
   ' Sdstatus = 43 Free FAT entry found
   ' Sdstatus = 44 The partition is full - store FAT EOC marker

      Incr Sdwbufferpos                                     ' Start by pointing to the next byte
      If Sdwbufferpos > Sdbytespersecw Then                 ' After saving the last byte in a sector, save the sector to the SD card
         Sdclusterd = Sdwclusterd                           ' Calculate the absolute sector number for this sector
         Gosub Sdlocatesector
         Sdsectord = Sdsectord + Sdwsecincluster
         Decr Sdsectord
         #if Sdwmode = 1
            Sdwriteorigin = 0                               ' Save sector from Sdbuffer to SD card
         #endif
         Gosub Sdwritesector
         Sdsavedatasector = 0
         Incr Sdwsecincluster

         If Sdwsecincluster > Sdsecspercluster Then         ' After saving the last sector in the current cluster, look up the next cluster

            Sdsectord = Sdfatsectornum                      ' Point to the same FAT sector
            Sdbufferpos = Sdfatbufferpos + Sdfattype        ' Point to the next FAT position

            #if Sdwmode = 1
               If Sdbufferpos < Sdbytespersecw Then         ' Search for a free FAT entry in the current sector
                  Sdfatcontinue = 1
                  Do
                     Sdtempw = Sdbufferpos                  ' Look for &H0000 (FAT16) or &H00000000 (FAT32)
                     If Sdfatbuffer(sdtempw) = 0 Then       ' Byte 1
                        Incr Sdtempw
                        If Sdfatbuffer(sdtempw) = 0 Then    ' Byte 2
                           If Sdfattype = 2 Then            ' FAT16
                              Sdstatus = 43                 ' Free FAT entry found
                              Sdfatcontinue = 0
                           Else                             ' FAT32
                              Incr Sdtempw
                              If Sdfatbuffer(sdtempw) = 0 Then       ' Byte 3
                                 Incr Sdtempw
                                 Sdtempb = Sdfatbuffer(sdtempw) And &B00001111
                                 If Sdtempb = 0 Then        ' Byte 4
                                    Sdstatus = 43           ' Free FAT entry found
                                    Sdfatcontinue = 0
                                 End If
                              End If
                           End If
                        End If
                     End If
                     If Sdfatcontinue = 1 Then
                        Sdbufferpos = Sdbufferpos + Sdfattype
                     End If
                  Loop Until Sdfatcontinue = 0 Or Sdbufferpos > Sdbytespersecw

                  If Sdstatus = 43 Then                     ' New free FAT entry found in the same FAT sector
                     Gosub Sdcalculatefatentrycluster       ' Calculate cluster number
                     Sdtempw = Sdfatbufferpos
                     For Sdtempb = 1 To Sdfattype           ' Update this FAT entry with a pointer to the next cluster
                        Sdfatbuffer(sdtempw) = Sdclusterb(sdtempb)
                        Incr Sdtempw
                     Next Sdtempb
                     Sdwclusterd = Sdclusterd               ' Update the write cluster pointer
                     Sdwsecincluster = 1                    ' Reset write sector number (Sdwbufferpos is reset after return)
                     Sdfatbufferpos = Sdbufferpos           ' Update the FAT buffer pointer
                  End If
               End If

               If Sdstatus <> 43 Then                       ' If none is found in the current FAT sector, loop through the next sector(s)
                  Sdbufferpos = 1
                  Sdsectord = Sdfatsectornum + 1            ' Point to the next FAT sector
                  If Sdsectord < Sdfat2location Then
                     Do
                        Gosub Sdfindfreefatentry            ' Sdsectord and Sdbufferpos point to the next free FAT
                     Loop Until Sdstatus <> 0

                     If Sdstatus = 43 Then                  ' New free FAT entry found in another FAT sector
                        Sdstatus = 0
                        Sdtempd = Sdsectord                 ' Temporarily store the FAT sector number with the current empty entry
                        Gosub Sdcalculatefatentrycluster    ' Calculate cluster number into Sdclusterd
                        Gosub Sdsavefatsec                  ' Store Sdclusterd at Sdfatsectornum & Sdfatbufferpos and save Sdfatbuffer() back to the card
                        If Sdstatus = 0 Then
                           Sdwclusterd = Sdclusterd         ' Update the write cluster pointer
                           Sdwsecincluster = 1              ' Reset write sector number (Sdwbufferpos is reset after return)
                           Sdfatsectornum = Sdtempd         ' Step to the next FAT entry and position
                           Sdfatbufferpos = Sdbufferpos     ' Update the FAT buffer pointer
                           For Sdtempw = 1 To 512           ' Copy this FAT sector data into Sdfatbuffer
                              Sdfatbuffer(sdtempw) = Sdbuffer(sdtempw)
                           Next Sdtempw
                        End If

                        #if Sdusefsinfo = 1
                           Gosub Sdupdatefsinfo             ' Update the fsinfo variables
                        #endif

                        Sdstatus = 0
                     Else                                   ' End of FAT reached and no free FAT entry found (SDstatus = 44)
                        Sdsectord = Sdfatsectornum          ' Point back to the last FAT sector
                     End If
                  Else                                      ' End of FAT reached and no free FAT entry found (SDstatus = 44)
                     Sdsectord = Sdfatsectornum             ' Point back to the last FAT sector
                  End If
               Else
                  Sdstatus = 0
               End If

            #else                                           ' Unbuffered FAT
               If Sdsectord < Sdfat2location Then
                  Do
                     Gosub Sdfindfreefatentry
                  Loop Until Sdstatus <> 0
                  If Sdstatus = 43 Then                     ' New free FAT entry found in another FAT sector
                     Sdstatus = 0
                     Gosub Sdcalculatefatentrycluster       ' Calculate Sdclusterd number to store in Sdfatsectornum & Sdfatbufferpos
                     Sdtempd = Sdsectord                    ' Temporarily store FAT sector number with free position

                     Sdsectord = Sdfatsectornum             ' Read the sector containing the FAT entry about to be extended
                     Gosub Sdreadsector
                     If Sdstatus = 0 Then
                        Sdtempw = Sdfatbufferpos
                        For Sdtempb = 1 To Sdfattype        ' Update the previous FAT entry with a pointer to the next cluster
                           Sdbuffer(sdtempw) = Sdclusterb(sdtempb)
                           Incr Sdtempw
                        Next Sdtempb
                        Gosub Sdwritesector                 ' Write the now extended FAT chain sector back to the SD card
                        If Sdstatus = 0 Then
                           Sdwclusterd = Sdclusterd         ' Update the write cluster pointer
                           Sdwsecincluster = 1              ' Reset write sector number (Sdwbufferpos is reset after return)
                           Sdfatsectornum = Sdtempd         ' Update the FAT sector number
                           Sdfatbufferpos = Sdbufferpos     ' Update the FAT buffer pointer

                           #if Sdusefsinfo = 1
                              Gosub Sdupdatefsinfo          ' Update the fsinfo variables
                           #endif

                        End If
                     End If

                  Else                                      ' End of FAT reached and no free FAT entry found (SDstatus = 44)
                     Sdsectord = Sdfatsectornum             ' Point back to the last FAT sector
                  End If

               Else                                         ' End of FAT reached and no free FAT entry found (SDstatus = 44)
                  Sdsectord = Sdfatsectornum                ' Point back to the last FAT sector
               End If

            #endif

            If Sdstatus = 44 Then                           ' The partition is full - store FAT EOC marker
               Sdpartitionfull = 1                          ' The partition is full (there are no more free FAT entries)
               Sdclosefile = 1                              ' Close the file
               Sdstatus = 0                                 ' Remap Sdstatus
            End If

         End If
         Sdwbufferpos = 1                                   ' Reset byte counter
      End If

      If Sdclosefile = 0 Then
         Sdbuffer(sdwbufferpos) = Sdbyterw                  ' Store byte in sector buffer
         Incr Sdwfilesized                                  ' Increment the file size byte counter
         Sdsavedatasector = 1
      End If

   Return

   '-------------------------------------------------------------------------------

   Sdfinalizeafterwriting:
   ' Used to close the file after the final call to Sdwritebyte

   ' Input variables:
   ' Sdwclusterd       = the cluster number we are writing to    (set by Sdwritebyte - touch only when writing to > 1 file)
   ' Sdwsecincluster   = the sector in this cluster              (set by Sdwritebyte - touch only when writing to > 1 file)
   '' Sdwbufferpos     = the position in this sector              (set by Sdwritebyte - touch only when writing to > 1 file)
   ' Sdwfilesized      = the file size                           (set by Sdwritebyte - touch only when writing to > 1 file)
   ' Sdfatsectornum    = the FAT sector number                   (set by Sdwritebyte - touch only when writing to > 1 file)
   ' Sdfatbufferpos    = the position in this sector             (set by Sdwritebyte - touch only when writing to > 1 file)
   ' Sddirclusterd     = the directory cluster getting file size (set by Sdcreatefileordir or Sdappendfile - touch only when writing to > 1 file)
   ' Sddirsecincluster = the sector in this cluster              (set by Sdcreatefileordir or Sdappendfile - touch only when writing to > 1 file)
   ' Sddirbufferpos    = the position in this sector             (set by Sdcreatefileordir or Sdappendfile - touch only when writing to > 1 file)
   ' Sdbuffer()                                                  (touch only when writing to > 1 file)
   ' Sdfatbuffer()                                               (touch only when writing to > 1 file)
   ' Sdsavedatasector  = 1 if the data should be saved to the SD (set by Sdwritebyte - touch only when writing to > 1 file)

   ' Output variables:
   ' Sdclosefile = 0 if the file was closed successfully

   ' Returned statuses:
   ' Sdstatus =  0 Successful
   ' Sdstatus =  7 Timeout
   ' Sdstatus = 41 Data rejected due to a CRC error
   ' Sdstatus = 42 Data rejected due to a Write Error

      Sdclosefile = 1


      ' Save the current file content sector to the SD card (if we haven't just saved a full data sector to the SD card)
      If Sdsavedatasector = 1 Then                          ' Sdsavedatasector = 1 "inside" a data sector and 0 just after the sector has been saved by Sdwritebyte
         Sdclusterd = Sdwclusterd                           ' Calculate the absolute sector number for this sector
         Gosub Sdlocatesector
         Sdsectord = Sdsectord + Sdwsecincluster
         Decr Sdsectord

         #if Sdcleartail = 1
            Incr Sdwbufferpos
            For Sdtempw = Sdwbufferpos To Sdbytespersecw
               Sdbuffer(sdtempw) = 0
            Next Sdtempw
            Decr Sdwbufferpos
         #endif

         #if Sdwmode = 1
            Sdwriteorigin = 0
         #endif
         Gosub Sdwritesector
      End If

      Sdclusterd = &H0FFFFFFF                               ' Save EOC marker in the FAT sector
      Gosub Sdsavefatsec

      Sdstatus = 0
      ' Update the directory entry with file size and save it to the SD card
      Sdclusterd = Sddirclusterd                            ' Point to the directory entry again
      Sdsecincluster = Sddirsecincluster
      Sdbufferpos = Sddirbufferpos

      Gosub Sdlocatedirsector                               ' Point to the file's directory entry

      If Sddirclusterd > 0 Then                             ' Unless we are in the FAT16 root directory
         Sdsectord = Sdsectord + Sddirsecincluster
         Decr Sdsectord
      End If

      #if Sdwmode = 1
         Sdreaddestination = 0
      #endif
      Gosub Sdreadsector                                    ' Update the directory sector with the new write and access DateTime
      If Sdstatus = 0 Then
         Gosub Sdstore29_32                                 ' Enter file size into the directory entry
         #if Sdwmode = 1
            Sdwriteorigin = 0
         #endif

         Gosub Sdwritesector                                ' Write the directory entry back to the SD card
         Sdclosefile = 0                                    ' The file was close successfully
      End If

   Return

   '-------------------------------------------------------------------------------

   Sdstoredirentry:
   ' Used to store all information in a new directory entry, except file size, that will be updated at the end in a second read+write to this directory sector

   ' Input variables:
   ' Sdentrynames     = the name of the new file or subdirectory (or . .. in case of the leading subirectory entries)
   ' Sdcreatemode       0 = file, 1 = subdirectory
   ' Sdclusterd       = the cluster number where the new file or subdirectory starts
   ' Sdwfilesized     = the file size (0 for subdirectory or when creating a new file)
   ' Sdbufferpos      = the buffer position in the current sector of the current directory cluster
   ' Sdbuffer()       = the current directory sector
   ' Sdyear           = the year
   ' Sdmonth          = the month
   ' Sdday            = the day
   ' Sdhours          = the hours
   ' Sdminutes        = the minutes
   ' Sdseconds        = the seconds
   ' Sdmseconds       = the milliseconds

   ' Output variables:
   ' Sdbuffer()       = the current directory sector
   ' Sddatew          = the date in DateTime format (normally not used afterwards)
   ' Sdtimew          = the time in DateTime format (normally not used afterwards)

      Sdtempw = Sdbufferpos
      For Sdtempb = 1 To 11                                 ' Store the filename in the new directory entry
         Sdbuffer(sdtempw) = Sdentrynameb(sdtempb)
         Incr Sdtempw
      Next Sdtempb

      If Sdcreatemode = 0 Then                              ' Create file
         Sdbuffer(sdtempw) = &H20                           ' Set archive bit - has been changed since last backup
      Else                                                  ' Create subdirectory
         Sdbuffer(sdtempw) = &H10                           ' Set subdirectory bit
      End If

      Sdtempw = Sdtempw + 9
      Sdbuffer(sdtempw) = Sdclusterb(3)                     ' 21
      Incr Sdtempw
      Sdbuffer(sdtempw) = Sdclusterb(4)                     ' 22
      Sdtempw = Sdtempw + 5
      Sdbuffer(sdtempw) = Sdclusterb(1)                     ' 27 Store the file's starting cluster number in the new directory entry
      Incr Sdtempw
      Sdbuffer(sdtempw) = Sdclusterb(2)                     ' 28

      Gosub Sdstore29_32                                    ' Enter file size into the directory entry

      Gosub Sdpreparedatetime                               ' Calculate and store date and time in the new directory entry
      Sdtempw = Sdbufferpos + 12
      Sdbuffer(sdtempw) = 0                                 ' 13
      Incr Sdtempw
      Sdbuffer(sdtempw) = Sdseconds Mod 2                   ' 14
      Sdbuffer(sdtempw) = Sdbuffer(sdtempw) * 100           ' 14
      Sdbuffer(sdtempw) = Sdbuffer(sdtempw) + Sdmseconds    ' 14
      Incr Sdtempw
      Sdbuffer(sdtempw) = Sdtimeb(1)                        ' 15
      Incr Sdtempw
      Sdbuffer(sdtempw) = Sdtimeb(2)                        ' 16
      Incr Sdtempw
      Sdbuffer(sdtempw) = Sddateb(1)                        ' 17
      Incr Sdtempw
      Sdbuffer(sdtempw) = Sddateb(2)                        ' 18
      Incr Sdtempw
      Gosub Sdstore19_26

   Return

   '-------------------------------------------------------------------------------

   Sdstore19_26:
      Sdbuffer(sdtempw) = Sddateb(1)                        ' 19
      Incr Sdtempw
      Sdbuffer(sdtempw) = Sddateb(2)                        ' 20
      Sdtempw = Sdtempw + 3
      Sdbuffer(sdtempw) = Sdtimeb(1)                        ' 23
      Incr Sdtempw
      Sdbuffer(sdtempw) = Sdtimeb(2)                        ' 24
      Incr Sdtempw
      Sdbuffer(sdtempw) = Sddateb(1)                        ' 25
      Incr Sdtempw
      Sdbuffer(sdtempw) = Sddateb(2)                        ' 26
   Return

   '-------------------------------------------------------------------------------

   Sdstore29_32:
      Sdtempw = Sdbufferpos + 28                            ' Enter file size into the directory entry
      Sdbuffer(sdtempw) = Sdwfilesizeb(1)                   ' 29
      Incr Sdtempw
      Sdbuffer(sdtempw) = Sdwfilesizeb(2)                   ' 30
      Incr Sdtempw
      Sdbuffer(sdtempw) = Sdwfilesizeb(3)                   ' 31
      Incr Sdtempw
      Sdbuffer(sdtempw) = Sdwfilesizeb(4)                   ' 32
   Return

   '-------------------------------------------------------------------------------

   Sdfindfreefat:
   ' Used to search FAT1 for a free entry, starting from Sdsectord, and store a number of positions and the FAT1 sector

   ' Input variables:
   ' Sdsectord        = the FAT1 sector we are starting in (>= Sdfat1location, < Sdfat2location)
   ' Sdbufferpos      = 1 or the actual position

   ' Output variables:
   ' Sdfatsectornum   = the FAT1 sector in which we found a free entry
   ' Sdfatbufferpos   = the position in this sector
   ' Sdfatclusterd    = the cluster number corresponding to the above FAT1 position
   ' Sdwclusterd      = the cluster number corresponding to the above FAT1 position
   ' Sdwsecincluster  = 1
   ' Sdwbufferpos     = 0 (more practical starting point than 1)
   ' Sdwfilesized     = 0

   ' Returned statuses:
   '   0 = Successful
   '   7 = Timeout

      Sdpartitionfull = 0                                   ' Assume the partition is not full (there are free FAT entries)

      Gosub Sdfindfreefatentry

      If Sdstatus = 43 Then                                 ' Free FAT entry found
         Sdstatus = 0                                       ' Remap Sdstatus

         Sdfatsectornum = Sdsectord                         ' Store absolute sector position for this FAT entry
         Sdfatbufferpos = Sdbufferpos                       ' (This is where we are later going to write the pointer to the next entry)

         #if Sdwmode = 1                                    ' Buffered FAT sector writing
            For Sdtempw = 1 To 512                          ' Copy this FAT sector data into Sdfat1buffer
               Sdfatbuffer(sdtempw) = Sdbuffer(sdtempw)
            Next Sdtempw
         #endif

         Gosub Sdcalculatefatentrycluster                   ' Calculate cluster number for this FAT entry

         Sdfatclusterd = Sdclusterd                         ' Store this FAT entry's corresponding cluster number (not the pointer to the next entry)
         Sdwclusterd = Sdclusterd                           ' Set the initial write cluster pointer
         Sdwsecincluster = 1                                ' Set the initial write sector number
         Sdwbufferpos = 0                                   ' Set the initial write buffer position (0 is more practical than 1 in this case)
         Sdwfilesized = 0                                   ' Reset the file size counter
      End If

   Return

   '-------------------------------------------------------------------------------

   Sdfindfreefatentry:
   ' Used to search FAT1 for a free entry, starting from Sdsectord

   ' Input variables:
   ' Assign Sdsectord (>= Sdfat1location, < Sdfat2location)
   ' Assign Sdbufferpos = 1 or actual position

   ' Output variables:
   ' Sdsectord   = the FAT1 sector in which we found a free entry
   ' Sdbufferpos = the position in this sector

   ' Returned statuses:
   ''   0 = Successful
   '   7 = Timeout
   '  43 = Free FAT entry found
   '  44 = End of FAT and no free entry found

      Sdstatus = 0
      Sdfatcontinue = 1
      Do

         ' 2 = write unbuffered
         ' 1 = write buffered
         ' 0 = not writing
         #if Sdwmode = 1
            Sdreaddestination = 0
         #endif

         Gosub Sdreadsector

         If Sdstatus = 0 Then
            ' Look for &H0000 (FAT16) or &H00000000 (FAT32)
            Do
               Sdtempw = Sdbufferpos
               If Sdbuffer(sdtempw) = 0 Then                ' Byte 1
                  Incr Sdtempw
                  If Sdbuffer(sdtempw) = 0 Then             ' Byte 2
                     If Sdfattype = 2 Then                  ' FAT16
                        Sdstatus = 43                       ' Free FAT entry found
                        Sdfatcontinue = 0
                     Else                                   ' FAT32
                        Incr Sdtempw
                        If Sdbuffer(sdtempw) = 0 Then       ' Byte 3
                           Incr Sdtempw
                           Sdtempb = Sdbuffer(sdtempw) And &B00001111
                           If Sdtempb = 0 Then              ' Byte 4
                              Sdstatus = 43                 ' Free FAT entry found
                              Sdfatcontinue = 0
                           End If
                        End If
                     End If
                  End If
               End If

               If Sdstatus <> 43 Then
                  Sdbufferpos = Sdbufferpos + Sdfattype
               End If

            Loop Until Sdfatcontinue = 0 Or Sdbufferpos > Sdbytespersecw

            If Sdsectord = Sdfat2location Then
               Sdfatcontinue = 0
               If Sdstatus = 0 Then
                  Sdstatus = 44                             ' End of FAT and no free entry found
               End If
            Else
               If Sdstatus = 0 Then
                  Incr Sdsectord
                  Sdbufferpos = 1
               End If
            End If

         Else
            Sdfatcontinue = 0
         End If

      Loop Until Sdfatcontinue = 0

   Return

   '-------------------------------------------------------------------------------

   Sdwclearcluster:
   ' Used to write zeroes to sectors 2-Sdsecspercluster (which is then followed either by zeroes to sector 1 or the new directory entry or the . .. entries)

   ' Input variables:
   ' Sdclusterd = the cluster we are about to clear

   ' Output variables:
   ' Sdbuffer() contains 512*zero

   ' Returned statuses:
   ' Sdstatus =  0 Successful
   ' Sdstatus =  7 Timeout
   ' Sdstatus = 41 Data rejected due to a CRC error
   ' Sdstatus = 42 Data rejected due to a Write Error


      Gosub Sdlocatesector
      Sdsectord = Sdsectord + Sdsecspercluster              ' Now we are at the sector after the one we want...
      For Sdtempw = 1 To 512                                ' Keeping the directory nice and tidy
         Sdbuffer(sdtempw) = 0
      Next Sdtempw

      For Sdtempb2 = 2 To Sdsecspercluster
         Decr Sdsectord                                     ' ... and start by subtracting 1 in the loop to start at the last sector in the current cluster
         Gosub Sdwritesector
         If Sdstatus <> 0 Then
            Exit For
         End If
      Next Sdtempb2

   Return

   '----------------------------------------------------------------------------

   Sdsavefatsec:
   ' Used to store next cluster or EOC marker in Sd/fat/buffer() at Sdfatbufferpos and save it back to the SD card (FAT1 and FAT2)

   ' Input variable:
   ' Sdfatbufferpos = the FAT entry position
   ' Sdfatsectornum = the FAT sector number
   ' Sdclusterd     = the next cluster number or EOC marker

   ' Output variable:
   ' Sdbuffer()

   ' Returned statuses:
   ' Sdstatus =  0 Successful
   ' Sdstatus =  7 Timeout
   ' Sdstatus = 41 Data rejected due to a CRC error
   ' Sdstatus = 42 Data rejected due to a Write Error

      #if Sdwmode = 2                                       ' Unbuffered FAT sector
         Sdstatus = 0
         Sdsectord = Sdfatsectornum                         ' FAT1
         Gosub Sdreadsector
         If Sdstatus = 0 Then
            Sdtempw = Sdfatbufferpos
            For Sdtempb = 1 To Sdfattype
               Sdbuffer(sdtempw) = Sdclusterb(sdtempb)      ' (Lowest EOC byte can range from &HF8 to &HFF)
               Incr Sdtempw
            Next Sdtempb
            Sdsectord = Sdfatsectornum
            Gosub Sdwritesector
            If Sdstatus = 0 Then
               Sdsectord = Sdsectord - Sdfat1location
               Sdsectord = Sdsectord + Sdfat2location       ' FAT2
               Gosub Sdwritesector
            End If
         End If
      #else                                                 ' Buffered FAT sector
         Sdtempw = Sdfatbufferpos
         For Sdtempb = 1 To Sdfattype
            Sdfatbuffer(sdtempw) = Sdclusterb(sdtempb)      ' (Lowest EOC byte can range from &HF8 to &HFF)
            Incr Sdtempw
         Next Sdtempb
         Sdstatus = 0
         Sdsectord = Sdfatsectornum                         ' FAT1
         Sdwriteorigin = 1                                  ' Save from Sdfatbuffer
         Gosub Sdwritesector
         If Sdstatus = 0 Then
            Sdsectord = Sdsectord - Sdfat1location
            Sdsectord = Sdsectord + Sdfat2location          ' FAT2
            Gosub Sdwritesector
         End If
      #endif

   Return

#endif


#if Sdwmode > 0 And Sdfsactive = 1

   Sdcalculatefatentrycluster:
   ' Used to calculate the cluster number for the FAT entry specified by Sdsectord and Sdbufferpos

   ' Input variables:
   ' Sdsectord   = the current FAT sector
   ' Sdbufferpos = the position within it

   ' Output variable:
   ' Sdclusterd holds the cluster number

      ' Calculate cluster number for this FAT entry
      Sdclusterd = Sdsectord - Sdfat1location
      Sdclusterd = Sdclusterd * Sdbytespersecw
      Sdclusterd = Sdclusterd + Sdbufferpos
      Decr Sdclusterd
      Sdclusterd = Sdclusterd / Sdfattype
      ' Incr Sdclusterd                      ' The first FAT entry refers to cluster 0

   Return

   '-------------------------------------------------------------------------------

   Sdlocatedirsector:

      If Sddirclusterd = 0 And Sdfattype = 2 Then
         Sdsectord = Sdrootdirlocation + Sddirsecincluster
         Decr Sdsectord
      Else
         Sdclusterd = Sddirclusterd
         Gosub Sdlocatesector
      End If

   Return

#endif

#if Sdwmode > 0
   #if Sdfsactive = 1 Or Sdusewipe = 1

      Sdpreparedatetime:
      ' Used to calculate date and time in the format used in directory entries

      ' Input variables:
      ' Sdyear
      ' Sdmonth
      ' Sdday
      ' Sdhours
      ' Sdminutes
      ' Sdseconds

      ' Output variables:
      ' Sddatew holds the date
      ' Sdtimew holds the time

      ' Internally used variables:
      ' Sdtempb

      ' Date and Time Formats
      ' Many FAT file systems do not support Date/Time other than DIR_WrtTime and DIR_WrtDate.
      ' For this reason, DIR_CrtTimeMil, DIR_CrtTime, DIR_CrtDate, and DIR_LstAccDate are actually optional fields.
      ' DIR_WrtTime and DIR_WrtDate must be supported, however.
      ' If the other date and time fields are not supported, they should be set to 0 on file create and ignored on other file operations.

      ' Date Format. A FAT directory entry date stamp is a 16-bit field that is basically a date relative to the MS-DOS epoch of 01/01/1980.
      ' Here is the format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the 16-bit word):

      ' Bits 0-4: Day of month, valid value range 1-31 inclusive.
      ' Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
      ' Bits 9-15: Count of years from 1980, valid value range 0-127 inclusive (1980-2107).

      ' Time Format. A FAT directory entry time stamp is a 16-bit field that has a granularity of 2 seconds.
      ' Here is the format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the 16-bit word).

      ' Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
      ' Bits 5-10: Minutes, valid value range 0-59 inclusive.
      ' Bits 11-15: Hours, valid value range 0-23 inclusive.

      ' The valid time range is from Midnight 00:00:00 to 23:59:58.

         Sddatew = 0
         Sddateb(2) = Sdyear - 1980
         Sddateb(1) = Sdmonth
         Shift Sddateb(1) , Left , 4
         Shift Sddatew , Left , 1
         Sddateb(1) = Sddateb(1) Or Sdday

         Sdtimew = 0
         Sdtimeb(2) = Sdhours
         Sdtimeb(1) = Sdminutes
         Shift Sdtimeb(1) , Left , 2
         Shift Sdtimew , Left , 3
         Sdtempb = Sdseconds / 2
         Sdtimeb(1) = Sdtimeb(1) Or Sdtempb

      Return

   #endif
#endif

'===============================================================================

#if Sdusefsinfo = 1

   Sdreadfsinfo:
   ' Used to read the fsinfo variables

   ' Input variable
   ' None

   ' Output variables:
   ' Sdfsinfofreeclustersd holds the number of free clusters
   ' Sdfsinfonextfreeclusterd points to the next unused cluster (typically not the first free re-usable cluster)

   ' Returned statuses:
   ' Sdstatus = 0 Successful
   ' Sdstatus = 7 Timeout

      If Sdfattype = 4 Then
         Sdsectord = Sdfat32fsinfolocationw

         ' 2 = write unbuffered
         ' 1 = write buffered
         ' 0 = not writing
         #if Sdwmode = 1
            Sdreaddestination = 0
         #endif

         Gosub Sdreadsector
         If Sdstatus = 0 Then
            Sdfsinfofreeclustersb(1) = Sdbuffer(489)
            Sdfsinfofreeclustersb(2) = Sdbuffer(490)
            Sdfsinfofreeclustersb(3) = Sdbuffer(491)
            Sdfsinfofreeclustersb(4) = Sdbuffer(492)

            Sdfsinfonextfreeclusterb(1) = Sdbuffer(493)
            Sdfsinfonextfreeclusterb(2) = Sdbuffer(494)
            Sdfsinfonextfreeclusterb(3) = Sdbuffer(495)
            Sdfsinfonextfreeclusterb(4) = Sdbuffer(496)
         End If
      End If
   Return

   '-------------------------------------------------------------------------------

   Sdwritefsinfo:
   ' Used to write the fsinfo variables back to the SD card (after being updated)

   ' Input variables:
   ' Sdfsinfofreeclustersd holds the number of free clusters
   ' Sdfsinfonextfreeclusterd points to the next unused cluster (typically not the first free re-usable cluster)

   ' Output variable
   ' None

   ' Returned statuses:
   ' Sdstatus =  0 Successful
   ' Sdstatus =  7 Timeout
   ' Sdstatus = 41 Data rejected due to a CRC error
   ' Sdstatus = 42 Data rejected due to a Write Error

      If Sdfattype = 4 Then
         Sdsectord = Sdfat32fsinfolocationw

         ' 2 = write unbuffered
         ' 1 = write buffered
         ' 0 = not writing
         #if Sdwmode = 1
            Sdreaddestination = 0
         #endif

         Gosub Sdreadsector
         If Sdstatus = 0 Then
            Sdbuffer(489) = Sdfsinfofreeclustersb(1)
            Sdbuffer(490) = Sdfsinfofreeclustersb(2)
            Sdbuffer(491) = Sdfsinfofreeclustersb(3)
            Sdbuffer(492) = Sdfsinfofreeclustersb(4)

            Sdbuffer(493) = Sdfsinfonextfreeclusterb(1)
            Sdbuffer(494) = Sdfsinfonextfreeclusterb(2)
            Sdbuffer(495) = Sdfsinfonextfreeclusterb(3)
            Sdbuffer(496) = Sdfsinfonextfreeclusterb(4)

            ' 2 = write unbuffered
            ' 1 = write buffered
            ' 0 = not writing
            #if Sdwmode = 1
               Sdwriteorigin = 0
            #endif

            Gosub Sdwritesector
         End If
      End If
   Return

   '-------------------------------------------------------------------------------

   Sdupdatefsinfo:
   ' Used when an additional cluster is being put into use

   ' Input variables:
   ' Sdfatclusterd = the cluster we have just started using
   ' Sdfsinfofreeclustersd holds the previous number of free clusters
   ' Sdfsinfonextfreeclusterd points to the previous unused cluster (typically not the first free re-usable cluster)

   ' Output variables:
   ' Sdfsinfofreeclustersd holds the updated number of free clusters
   ' Sdfsinfonextfreeclusterd points to the next unused cluster (typically not the first free re-usable cluster)

      If Sdfattype = 4 Then
         If Sdfatclusterd >= Sdfsinfonextfreeclusterd Then
            Sdfsinfonextfreeclusterd = Sdfatclusterd + 1
         End If
         Decr Sdfsinfofreeclustersd
      End If
   Return

#endif


#if Sdusedirlist = 1

   Sddirlist:                                               ' Currently assumes we never fill the SD card completely !!!
   ' Used to scroll forward and backward through the current directory
   ' Call this routine in a loop in which you check for certain Sdstatus values
   ' Reset Sdstatus to 0 before the next step in the loop

   ' In the very first call to a new directory, assign real or dummy Sdclusterd. If you are listing the root, set it to dummy value 0 to also support FAT16 root dir.
   ' In the very first call to a new directory, assign Sddirlistarraycounter = 0
   ' Always assign Sddirlistdirection, 0 = forward, 1 = backward

   ' Routine-specific Sdstatuses:
   ' 26 = A file entry has been found
   ' 27 = A directory entry has been found
   ' 28 = An available directory space has been found
   ' 32 = EOD End Of Directory marker found
   ' 33 = Subdirectory . or .. entry found
   ' 34 = A volume ID has been found
   ' 36 = Long file name found

   ' Since the first directory entry can't have both status and start of directory status, this bit indicates that we have returned to the starting point
   ' Sddirliststartpoint = 1                  ' The directory backward listing has reached the starting point
   ' Sddirlistendpoint = 1                    ' The directory forward listing has reached the end point
   ' Sddirlistoutside = 1                     ' We have scrolled outside of Sddirlistarray() array


      ' Special handling of root directory
      If Sdclusterd = 0 Then
         If Sdfattype = 2 Then                              ' FAT16 root directory
            Sdsectorend = Sdsecsinroot
         Else
            Sdclusterd = Sdfat32rootclusterd                ' FAT32 root directory remapped to (normally) cluster 2
         End If
      End If

      ' If not in FAT16 root directory, locate the first directory sector
      If Sdclusterd > 0 Then
         Sdsectorend = Sdsecspercluster
      End If

      If Sddirlistarraycounter = 0 Then                     ' Very first call
         Sddirliststartpoint = 1                            ' Prevent going backward from the starting point
         Sddirlistendpoint = 0
         Sddirlistarraycounter = 1
         Sddirlistarraypointer = 1
         Sddirlistoutside = 0
         Sdbufferpos = 1
         Sdsecincluster = 1
         Sddirlistarray(1) = Sdclusterd

         If Sdclusterd = 0 Then
            Sdsectord = Sdrootdirlocation
         Else
            Gosub Sdlocatesector
         End If
         Gosub Sdreadsector
      Else                                                  ' All subsequent calls
         If Sddirlistdirection = 0 Then                     ' Forward
            Sddirliststartpoint = 0
            Sdbufferpos = Sdbufferpos + 32
            If Sdbufferpos > Sdbytespersecw Then
               Sdbufferpos = 1
               Incr Sdsecincluster
               If Sdsecincluster > Sdsectorend Then
                  If Sdclusterd > 0 Then
                     Sdsecincluster = 1
                     If Sddirlistarraypointer >= Sddirlistarraycounter Then       ' We are pointing to or after the last stored cluster
                        If Sddirlistarraypointer >= Sddirlistarraysize Then       ' We are pointing to or after the last entry in Sddirlistarray() array - continue outside of it
                           Sddirlistoutside = 1             ' We Have Scrolled Outside Of Sddirlistarray() Array
                           Sddirlistnextclusterd = Sdclusterd       ' Store the soon-to-be-previous cluster som we can go back to it if EOD reached later
                           Gosub Sdlocatenextcluster        ' Read next cluster
                           Gosub Sdcheckclusterreference    ' Check if it indicates EOC (in that case Sdstatus = 31)
                           If Sdstatus = 0 And Sddirlistendpoint = 0 Then
                              Incr Sddirlistarraypointer
                              Gosub Sdlocatesector
                              Gosub Sdreadsector
                              Sdbufferpos = 1
                           Else                             ' In case of EOD marker found, point to the last valid directory entry
                              Sdclusterd = Sddirlistnextclusterd
                              Gosub Sdlocatesector
                              Sdsectord = Sdsectord + Sdsecspercluster
                              Decr Sdsectord
                              Sdbufferpos = Sdbytespersecw - 31
                              Sdsecincluster = Sdsecspercluster
                              Gosub Sdreadsector
                           End If
                        Else                                ' We are still before the end of the array
                           Gosub Sdlocatenextcluster        ' Read and append next cluster to the cluster array
                           Gosub Sdcheckclusterreference    ' Check if it indicates EOC (in that case Sdstatus = 31)
                           If Sdstatus = 0 And Sddirlistendpoint = 0 Then
                              Incr Sddirlistarraycounter
                              Incr Sddirlistarraypointer
                              Sddirlistarray(sddirlistarraypointer) = Sdclusterd
                              Gosub Sdlocatesector
                              Gosub Sdreadsector
                              Sdbufferpos = 1
                           Else                             ' In case of EOD marker found, point to the last valid directory entry
                              Sdclusterd = Sddirlistarray(sddirlistarraypointer)
                              Gosub Sdlocatesector
                              Sdsectord = Sdsectord + Sdsecspercluster
                              Decr Sdsectord
                              Sdbufferpos = Sdbytespersecw - 31
                              Sdsecincluster = Sdsecspercluster
                              Gosub Sdreadsector
                           End If
                        End If
                     Else                                   ' Point to the next cluster in the array
                        Incr Sddirlistarraypointer
                        Sdclusterd = Sddirlistarray(sddirlistarraypointer)
                        Incr Sdsectord
                        Gosub Sdreadsector
                     End If
                  Else                                      ' End of the FAT16 root
                     Sddirlistendpoint = 1
                     Decr Sdsecincluster                    ' Point back to the last entry
                     Sdbufferpos = Sdbytespersecw - 31
                  End If
               Else
                  Incr Sdsectord
                  Gosub Sdreadsector
               End If
            End If
         Else                                               ' Backward
            If Sddirliststartpoint = 0 Then                 ' Only allow backward if we are not at the starting point
               Sddirlistendpoint = 0                        ' We are no longer at the end of the directory
               If Sdbufferpos > 32 Then
                  Sdbufferpos = Sdbufferpos - 32
                  Sddirliststartpoint = 0
               Else
                  Sdbufferpos = Sdbytespersecw - 31
                  If Sdsecincluster > 1 Then
                     Decr Sdsecincluster
                     Decr Sdsectord
                     Gosub Sdreadsector
                  Else
                     Sdsecincluster = Sdsecspercluster
                     If Sddirlistoutside = 1 Then           ' We are outside of Sddirlistarray() array
                        Sddirlistcurrclusterd = Sdclusterd  ' Locate the cluster before the current cluster
                        Sdclusterd = Sddirlistarray(sddirlistarraysize)
                        Do
                           Sddirlistnextclusterd = Sdclusterd
                           Gosub Sdlocatenextcluster
                           Gosub Sdcheckclusterreference    ' Check if it indicates EOC (in that case Sdstatus = 31)
                        Loop Until Sdstatus <> 0 Or Sdclusterd = Sddirlistcurrclusterd
                        If Sdstatus = 0 Then
                           Decr Sddirlistarraypointer
                           If Sddirlistarraypointer <= Sddirlistarraysize Then
                              Sddirlistoutside = 0
                           End If
                           Sdclusterd = Sddirlistnextclusterd
                           Gosub Sdlocatesector
                           Sdsectord = Sdsectord + Sdsecspercluster
                           Decr Sdsectord
                           Gosub Sdreadsector
                        End If
                     Elseif Sddirlistarraypointer > 1 Then
                        Decr Sddirlistarraypointer
                        Sdclusterd = Sddirlistarray(sddirlistarraypointer)
                        Gosub Sdlocatesector
                        Sdsectord = Sdsectord + Sdsecspercluster
                        Decr Sdsectord
                        Gosub Sdreadsector
                     End If
                  End If
               End If
               If Sdclusterd = Sddirlistarray(1) And Sdsecincluster = 1 And Sdbufferpos = 1 Then
                  Sddirliststartpoint = 1                   ' Back at the starting point
               End If
            End If
         End If
      End If


      ' Check this directory entry
      If Sdstatus = 0 Then
         If Sdbuffer(sdbufferpos) = &H00 Then               ' End of directory marker
            Sdstatus = 32                                   ' EOD End Of Directory marker found
         Elseif Sdbuffer(sdbufferpos) = &HE5 Then           ' Empty directory entry - previous file was deleted
            Sdstatus = 28                                   ' An available directory space has been found
         Elseif Sdbuffer(sdbufferpos) = &H2E Then           ' One of first two entries in a subdirectory, . contains the current cluster, .. points to parent directory
            Sdstatus = 33                                   ' Subdirectory . or .. entry found
         Else
            Sdtempw = Sdbufferpos + 11                      ' Check attribute byte
            Sdtempb = Sdbuffer(sdtempw) Or &B11110000
            If Sdtempb = &HFF Then
               Sdstatus = 36                                ' Long file name found
            Elseif Sdbuffer(sdtempw).4 = 1 Then
               Sdstatus = 27                                ' Subdirectory found
            Elseif Sdbuffer(sdtempw).3 = 1 Then
               Sdstatus = 34                                ' Volume ID found
            Else
               Sdstatus = 26                                ' File found
            End If
         End If

         ' Store the current directory entry in Sddirlistdirentry
         Sdtempw = Sdbufferpos                              ' Make a copy of this directory entry byte by byte
         Sdtempb = 1
         For Sdtempb = 1 To 32
            Sddirlistdirentry(sdtempb) = Sdbuffer(sdtempw)
            Incr Sdtempw
         Next Sdtempb

         If Sddirlistdirentry(1) = &H05 Then                ' Substitute for 0xE5 in the Japanese KANJI character set
            Sddirlistdirentry(1) = &HE5
         End If

      End If

   Return

   '-------------------------------------------------------------------------------

   Sdcheckclusterreference:                                 ' Check if it indicates EOC (>=&HFFF8 or >=&H0FFFFFF8)
      If Sdfattype = 2 Then                                 ' FAT16
         Sdclusterb(3) = 0
         Sdclusterb(4) = 0
         If Sdclusterd > &HFFF7 Then                        ' EOC End OF Cluster chain found
            Sddirlistendpoint = 1
            #if Sduseappend = 1
               Sdstatus = 31
            #endif
         End If
      Elseif Sdfattype = 4 Then                             ' FAT32
         Sdclusterb(4) = Sdclusterb(4) And &B00001111
         If Sdclusterd > &H0FFFFFF7 Then                    ' EOC End OF Cluster chain found
            Sddirlistendpoint = 1
            #if Sduseappend = 1
               Sdstatus = 31
            #endif
         End If
      End If
   Return

#endif


#if Sduselfn = 1

   Sdlookforlfn:

   ' Call after Sddirlist has returned with Sdstatus = 26 (file) or 27 (subdirectory)

      For Sdtempb = 1 To 32                                 ' Copy the directory entry
         Sdlfndirentry(sdtempb) = Sddirlistdirentry(sdtempb)
      Next Sdtempb

      Sddirlistdirection = 1                                ' Read the previous directory entry
      Sdlfncontinue = 1
      Sdlfnfound = 0
      Sdtempb4 = 1                                          ' Expected starting point for the long filename ordinal

      Do
         If Sddirliststartpoint = 0 Then                    ' 0 = the directory backward listing has NOT reached the starting point
            Sdstatus = 0
            Gosub Sddirlist
            If Sdstatus = 36 Then
               Sdtempb = Sddirlistdirentry(1) And &B00011111
               If Sdtempb = Sdtempb4 Then                   ' Expected ordinal number found
                  If Sdtempb = 1 Then
                     Gosub Sdcalculatelfnchecksum
                  End If
                  If Sdlfnchecksum = Sddirlistdirentry(14) Then       ' Matching checksum found
                     Sdtempb = Sdtempb4 - 1                 ' Calculate the starting point in the string for these 13 characters
                     Sdtempb = Sdtempb * 13
                     Sdtempb2 = 0
                     Do
                        Sdtempb2 = Sdtempb2 + 2
                        Incr Sdtempb
                        If Sdtempb2 = 12 Then
                           Sdtempb2 = 15
                        Elseif Sdtempb2 = 27 Then
                           Sdtempb2 = 29
                        End If
                        If Sddirlistdirentry(sdtempb2) > 0 And Sddirlistdirentry(sdtempb2) < 255 Then       ' Don't append NULL &H0000 and padding &HFFFF at the end of the name
                           Sdlfnb(sdtempb) = Sddirlistdirentry(sdtempb2)       ' Append the characters from this directory entry
                        End If
                     Loop Until Sdtempb2 = 31
                     Incr Sdtempb4
                     If Sddirlistdirentry(1).6 = 1 Then     ' Stop bit found
                        Sdlfnfound = 1                      ' We have read a complete long filename
                        Sdlfncontinue = 0
                     End If
                  Else
                     Sdlfncontinue = 0                      ' Checksum is not matching
                  End If
               Else
                  Sdlfncontinue = 0                         ' Expected ordinal number not found
               End If
            Else
               Sdlfncontinue = 0                            ' Record is not a long filename entry
            End If
         Else
            Sdlfncontinue = 0                               ' Current record is the very first directory entry
         End If
      Loop Until Sdlfncontinue = 0

   Return

   '-------------------------------------------------------------------------------

   Sdcalculatelfnchecksum:
      Sdlfnchecksum = Sdlfndirentry(1)
      For Sdtempb = 2 To 11
         Sdtempb2 = Sdlfnchecksum
         Shift Sdtempb2 , Right , 1
         Sdtempb3 = Sdlfnchecksum And &B00000001
         Shift Sdtempb3 , Left , 7
         Sdlfnchecksum = Sdlfndirentry(sdtempb) + Sdtempb2
         Sdlfnchecksum = Sdlfnchecksum + Sdtempb3
     Next Sdtempb
   Return

   '-------------------------------------------------------------------------------

   #if Sduselfncompare = 1
      Sdcomparefilenames:
         Sdlfnfound = 0
         Sdlfncontinue = 1
         Sdtempb = 0
         Do
            Incr Sdtempb
            If Sdlfnb(sdtempb) <> 0 Then                    ' End marker
               If Sdlfnb(sdtempb) <> Sdlfn2b(sdtempb) Then
                  Sdlfncontinue = 0
               End If
            Else
               Sdlfncontinue = 0
               If Sdtempb > 1 Then
                  Sdlfnfound = 1
               End If
            End If
         Loop Until Sdlfncontinue = 0 Or Sdtempb = 255
      Return
   #endif

#endif

'-------------------------------------------------------------------------------

#if Sdusewipe = 1

   Sdwipe:
   ' Used to clean out and reset FAT1, FAT2, root directory, and fsinfo sector.
   ' This is NOT a real formatting!

   ' Input variables
   ' Sdentrynames with all 11 characters including space characters
   ' Sdyear
   ' Sdmonth
   ' Sdday
   ' Sdhours
   ' Sdminutes
   ' Sdseconds

      For Sdtempw = 1 To 512
         Sdbuffer(sdtempw) = 0
      Next Sdtempw

      #if Sdwmode = 1
         Sdwriteorigin = 0
      #endif

      If Sderaseall = 1 Then                                ' Erase everything from the beginning of FAT1 to the last sector in this partition
         Sdtempd = Sdtotsecsd + Sdpartstart
      Else
         Sdtempd = Sddataareastart + Sdsecspercluster       ' Erase everything from the beginning of FAT1 to the end of cluster 2
      End If

      Sdstatus = 0

      Sdsectord = Sdfat1location
      While Sdsectord < Sdtempd
         Gosub Sdwritesector
         Incr Sdsectord
      Wend

      Sdstatus = 0

      ' Then write FAT pointers to dummy clusters 0 and 1 (and 2 if FAT32)
      Sdbuffer(1) = &HF8
      Sdbuffer(2) = &HFF
      Sdbuffer(3) = &HFF

      If Sdfattype = 2 Then                                 ' FAT16 F8FF FFFF
         Sdbuffer(4) = &HFF
      Else
         Sdbuffer(4) = &H0F                                 ' FAT32 F8FFFF0F FFFFFFFF FFFFFF0F
         For Sdtempb = 5 To 11
            Sdbuffer(sdtempb) = &HFF
         Next Sdtempb
         Sdbuffer(12) = &H0F
      End If

      Sdsectord = Sdfat1location
      Gosub Sdwritesector
      Sdsectord = Sdfat2location
      Gosub Sdwritesector

      ' Then store the new volume ID in the root directory
      ' 1-11  = Name
      ' 12    = &H08
      ' 23-26 = timestamp
      For Sdtempb = 1 To 11
         Sdbuffer(sdtempb) = Sdentrynameb(sdtempb)
      Next Sdtempb
      Sdbuffer(12) = &H08

      Gosub Sdpreparedatetime

      Sdbuffer(23) = Sdtimeb(1)
      Sdbuffer(24) = Sdtimeb(2)
      Sdbuffer(25) = Sddateb(1)
      Sdbuffer(26) = Sddateb(2)

      If Sdfattype = 2 Then
         Sdsectord = Sdrootdirlocation
      Else
         Sdsectord = Sddataareastart
      End If

      Gosub Sdwritesector

      ' Finally update fsinfo sector
      #if Sdusefsinfo = 1

         If Sdfattype = 4 Then

            Gosub Sdreadfsinfo

            Sdfsinfofreeclustersd = Sdtotsecsd - Sddataareastart
            Incr Sdfsinfofreeclustersd
            Sdfsinfofreeclustersd = Sdfsinfofreeclustersd / Sdsecspercluster
            Decr Sdfsinfofreeclustersd                      ' The first cluster (2) is used by the FAT32 root directory

            Sdfsinfonextfreeclusterd = 3

            Sdbuffer(489) = Sdfsinfofreeclustersb(1)
            Sdbuffer(490) = Sdfsinfofreeclustersb(2)
            Sdbuffer(491) = Sdfsinfofreeclustersb(3)
            Sdbuffer(492) = Sdfsinfofreeclustersb(4)

            Sdbuffer(493) = Sdfsinfonextfreeclusterb(1)
            Sdbuffer(494) = Sdfsinfonextfreeclusterb(2)
            Sdbuffer(495) = Sdfsinfonextfreeclusterb(3)
            Sdbuffer(496) = Sdfsinfonextfreeclusterb(4)

            Gosub Sdwritefsinfo

         End If

      #endif


   Return

#endif

'-------------------------------------------------------------------------------

#if Sdusesizeinfo = 1

   Sdreceivebuffer18:
      Spiin Sdbuffer(1) , 18
   Return

   '-------------------------------------------------------------------------------

   Sdrequestcid:

      Sdcommand = &HFF                                      ' Clock SD to complete job
      Gosub Sdcommand1
      ' Gosub Sdcommand1

      Reset Sd_cs

      ' Sdcommand = &HFF                                    ' Clock SD to complete job
      Gosub Sdcommand1
      ' Gosub Sdcommand1

      Sdcommand = &H4A                                      ' Send CMD10
      Gosub Sdcommand1
      Sdcommand = &H00
      Gosub Sdcommand1
      Gosub Sdcommand1
      Gosub Sdcommand1
      Gosub Sdcommand1
      Sdcommand = &H1D
      Gosub Sdcommand1

      Sdexpectedresponse = &H00                             ' First response after CMD9
      Gosub Sdseekresponse
      If Sdstatus = 0 Then
         Sdexpectedresponse = &HFE                          ' Start token after CMD9
         Gosub Sdseekresponse
         If Sdstatus = 0 Then
            Gosub Sdreceivebuffer18
         End If
      End If

      Reset Sd_cs

      Sdcommand = &HFF                                      ' Clock SD to complete job
      Gosub Sdcommand1
      'Gosub Sdcommand1

   Return

   '-------------------------------------------------------------------------------

   Sdrequestcsd:

   ' 16 bytes, MSB first

      Sdcommand = &HFF                                      ' Clock SD to complete job
      Gosub Sdcommand1
      'Gosub Sdcommand1

      Reset Sd_cs

      ' Sdcommand = &HFF                                   ' Clock SD to complete job
      Gosub Sdcommand1
      ' Gosub Sdcommand1

      Sdcommand = &H49                                      ' Send CMD9
      Gosub Sdcommand1
      Sdcommand = &H00
      Gosub Sdcommand1
      Gosub Sdcommand1
      Gosub Sdcommand1
      Gosub Sdcommand1
      Sdcommand = &HAF
      Gosub Sdcommand1

      Sdexpectedresponse = &H00                             ' First response after CMD9
      Gosub Sdseekresponse
      If Sdstatus = 0 Then
         Sdexpectedresponse = &HFE                          ' Start token after CMD9
         Gosub Sdseekresponse
         If Sdstatus = 0 Then
            Gosub Sdreceivebuffer18
         End If
      End If

      Reset Sd_cs

      Sdcommand = &HFF                                      ' Clock SD to complete job
      Gosub Sdcommand1
      'Gosub Sdcommand1

   Return

   '-------------------------------------------------------------------------------

   Sdcalculatesize:                                         ' Can be called after Sdrequestcsd

   ' v2+
   ' Bits 127-126 = 01 (byte 1.6 = 1, 1.7 = 0)
   ' C_SIZE 22 bits 69-48 (bytes 8&B00111111,9,10)
   ' Size = C_SIZE * 2^19

   ' v1.x:
   ' Bits 127-126 = 00
   ' C_SIZE 12 bits 73-62 (bytes 7&B00000011, 8, 9&B11000000)
   ' C_SIZE_MULT 3 bits 49-47 (bytes 10&B00000011, 11&B10000000)
   ' READ_BL_LEN 4 bits 84-80 (byte 6&B00001111)
   ' Size = (C_SIZE+1) * 2^(C_SIZE_MULT+2) * 2^READ_BL_LEN

      If Sdbuffer(1).6 = 1 And Sdbuffer(1).7 = 0 Then
         Sdcsize = &B00111111 And Sdbuffer(8)               ' v2+
         Sdcsize = Sdbuffer(8)
         Shift Sdcsize , Left , 8
         Sdcsize = Sdcsize + Sdbuffer(9)
         Shift Sdcsize , Left , 8
         Sdcsize = Sdcsize + Sdbuffer(10)
         Incr Sdcsize
         Shift Sdcsize , Right , 1                          ' Size in MB (1k = 1024)
      Else
         Sdcsize = &B00000011 And Sdbuffer(7)               ' v1.x      ok
         Shift Sdcsize , Left , 8
         Sdcsize = Sdcsize + Sdbuffer(8)
         Shift Sdcsize , Left , 8
         Sdcsize = Sdcsize + Sdbuffer(9)
         Shift Sdcsize , Right , 6

         Sdcsizemult = Sdbuffer(10) And &B00000011
         Shift Sdcsizemult , Left , 1
         If Sdbuffer(11).7 = 1 Then
            Incr Sdcsizemult
         End If

         Sdreadbllen = Sdbuffer(6) And &B00001111

         Incr Sdcsize
         Shift Sdcsize , Left , Sdcsizemult
         Shift Sdcsize , Left , Sdreadbllen
         Shift Sdcsize , Right , 18                         ' Size in MB (1k = 1024)
         ' Size = (C_SIZE+1) * 2^(C_SIZE_MULT+2) * 2^READ_BL_LEN
      End If

   Return

   '-------------------------------------------------------------------------------

   Sdrequeststatus:

      Sdcommand = &HFF                                      ' Clock SD to complete job
      Gosub Sdcommand1
      ' Gosub Sdcommand1

      Reset Sd_cs

      ' Sdcommand = &HFF                                      ' Clock SD to complete job
      Gosub Sdcommand1
      ' Gosub Sdcommand1

      Sdcommand = &H4D                                      ' Send CMD13
      Gosub Sdcommand1
      Sdcommand = &H00
      Gosub Sdcommand1
      Gosub Sdcommand1
      Gosub Sdcommand1
      Gosub Sdcommand1
      Sdcommand = &H0D
      Gosub Sdcommand1

      Sdtempb = 0
      Do
         Gosub Sdresponse1
         Incr Sdtempb
      Loop Until Sdresponse(1) <> 255 Or Sdtempb = 255

      If Sdresponse(1) = 255 Then
         Sdstatus = 6                                       ' Timeout in CMD13
      Else
         Gosub Sdresponse2_5
      End If

      Reset Sd_cs

      Sdcommand = &HFF                                      ' Clock SD to complete job
      Gosub Sdcommand1
      'Gosub Sdcommand1

   Return

#endif

'-------------------------------------------------------------------------------

#if Sdusecrc7 = 1

   Sdcheckresponsecrc7:                                     ' Receives the SD response and checks the CRC
      Sdcrc7byte = Sdcrc7(sdresponse(1))
      If Sdresponse(6) <> Sdcrc7byte Then
         Sdstatus = 129
      End If
   Return

   '-------------------------------------------------------------------------------

   Function Sdcrc7(byval Sdarray As Byte) As Byte           ' Calculates CRC7 for the 5 first bytes of Sdarray

      Local Sdm As Byte                                     ' Array byte loop
      Local Sdk As Byte                                     ' Byte bit loop
      Local Sdx As Byte                                     ' Current array byte value (could be skipped and work only with Sdarray(m))
      Local Sdcrc7sum As Byte                               ' The CRC7 being calculated
      Local Sdcalcstep As Byte                              ' Intermediate step necessary for BASCOM

      Sdcrc7sum = 0

      For Sdm = 1 To 5                                      ' Loop through the 5 first array bytes
         Sdx = Sdarray(sdm)

         For Sdk = 0 To 7                                   ' Loop through the byte bitwise

            Shift Sdcrc7sum , Left , 1                      ' Shift CRC left
            Sdcalcstep = Sdx Xor Sdcrc7sum

            If Sdcalcstep.7 = 1 Then                        ' Do XOR if MSB = 1
               Sdcrc7sum = Sdcrc7sum Xor &H9
            End If

            Shift Sdx , Left , 1                            ' Shift current array byte value left

         Next Sdk

         Sdcrc7sum = Sdcrc7sum And &H7F

      Next Sdm

      Shift Sdcrc7sum , Left , 1                            ' Shift left and add 1
      Sdcrc7sum = Sdcrc7sum + 1
      Sdcrc7 = Sdcrc7sum

   End Function

#endif

'===============================================================================