Администрация форума не несёт ответственности за достоверность информации и оставляет за собой право редактировать или в особых случаях даже удалять посты без предупреждения. Спасибо за понимание.

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Программирование ATMEL в BASCOM. » Вопросы - ответы » Давайте прочитаем FAT без библиотек


Давайте прочитаем FAT без библиотек

Сообщений 1 страница 10 из 10

1

Давно меня берет зависть когда люди делают Wav плееры на Attinny2313, читают FAT и никаких трудностей при этом не испытывают.
Работа с FAT требует много ресурсов, но если нас интересует только чтение и если забить на фрагментацию то можно просто считывать данные с карточки и сразу пулять их в порт( как все и делают).

Вот что я смог понять про то как это сделать:

Данные с SD карты считываются блоками (секторами) по 512 байт. Т.е. нельзя обратиться к конкретной ячейке, а только к началу блока (сектора) и последовательно его считать. Блоки (сектора) организованы в кластеры, размер кластера задается при форматировании карты (если конечно вам предложат его указать) и прописан как и всё остальное в PBR.

НАЧИНАЕМ

Главная загрузочная запись MBR

Считываем первый байт. Если он равен EBh, то это PBR, если 0h то это MBR и надо искать адрес начала PBR.

Загрузочная запись разделов PBR

Адрес PBR находится в MBR в ячейках 1C6:1C9 (4 байта) (байты идут в обратном порядке, т.е. если вы видите 95 00 00 00 то значение будет 00 00 00 95h).
Переходим по этому адресу.

PBR самое основное место. Адрес PBR является точкой отсчета всех перемещений по SD карте.
Т.е. везде указывается смещение относительно PBR и если нужно получить конкретный адрес нужно к смещению прибавить адрес PBR

Считываем важную информацию из ячеек PBR

0Dh - количество секторов в кластере
0Eh,0Fh – количество зарезервированных секторов (фактически если к этому прибавить PBR то получим начало FAT)
16h,17h – количество секторов в FAT
10h – количество копий FAT (обычно 2)

Корневой катклог.
В нем хранится список файлов. На каждый файл формата 8.3 отводится 32 байта.
0h   -8 байт - имя
8h   -3 байта - расширение
0Bh -1 байт – атрибуты
16h -2 байта – время
18h -2 байта – дата
1Ah -2 байта – адрес первого кластера начала файла
1Ch -4 байта – размер файла

Чтобы найти корневой каталог надо умножить количество копий FAT (10h) на число секторов в нём (16h) и прибавить к полученному значению число зарезервированных секторов (0Eh).

Далее находим размер корневого каталога. По смещению 11h в PBR (2 байта) указано количество записей в корневом каталоге (размер каждой записи 32 байта).
Переводим количество записей в количество секторов: умножим количество записей на 32 и поделим на количество байт в секторе 512. Получаем размер корневого каталога в секторах.

Область данных. В ней начинается размещение данных.

Размещение области данных найдём  прибавляя, к вычисленному ранее адресу корневого каталога, его размер.
Чтобы найти в области данных файл нужно в корневом каталоге найти запись об этом файле, считать оттуда смещение начального кластера этого файла
прибавить к нему начало области данных и это и будет сам файл.

А теперь первые грабли, ну как грабли, об этом все знают но я попал.

Область данных начинается сразу со второго кластера

У меня получается так: из смещения указанном в записи файла в корневом каталоге надо вычесть 2

Например:
смещение 2 -2=0  => файл начинается в начале области данных
смещение 3 -2 =1 *64(64 размер кластера)*512(размер сектора)=32768+адрес начала области данных =>адрес начала файла

Проверяется так:
SD карта до 2ГБ, форматируем в FAT, записываем несколько текстовых файлов, открываем диск в редакторе WinHEX или HxD
И с калькулятором по каждому этапу.

Призываю интересующихся к участию!

Отредактировано Димон (2014-09-03 19:01:38)

+1

2

Прочитал флешку
Вывел список файлов
размер кода 4,6кб

Код:
'---------------------------------------------
'
'
'---------------------------------------------

'  mega8      SD\MMC
'  25 PC2-----1 CS
'  26 PC3-----2 MOSI
'           --3 Gnd
'           --4 +3.3v
'  27 PC4-----5 SCK
'           --6 Gnd
'  28 PC5-----7 MISO
'
'  15 PB1--4,7mF--Speeker--Gnd
'
'------------------------------------------
$regfile = "m8def.dat"
$crystal = 11059200                                         '
$hwstack = 16
$swstack = 64
$framesize = 32

$baud = 9600

Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Up , Compare B Pwm = Clear Down , Prescale = 1       ' шим модулятор PWM
Pwm1a = 255
Pwm1b = 255
'Constants
Const Msbl = 0
Const Msbh = 1
Const Dly = 2
Const Bits8 = 8
Const Bits16 = 16
Const Bits32 = 32

'Dim
Dim Adr_pbr As Dword
Dim Reserv_sec As Word
Dim Kol_sec_fat As Word
Dim Adr_root As Dword
Dim Kol_sec_klast As Byte
Dim Kol_zap_root As Word
Dim Razm_root As Word
Dim Adr_dat As Word
Dim Adr_file As Word

Dim Stp As Bit

Dim Dat As Byte
Dim Resp As Byte
Dim I As Word
Dim I1 As Byte
Dim Addr As Long
Dim Adres As Long
Dim Sub_adres As Word
Dim Sub_adres1 As Word
Dim Tanzim As Byte
Dim Ali As Byte
Dim Test As Long
Dim Copy As Long
Dim Shomare As Long
Dim Hassan As Byte
Dim Sd_dat(4) As Byte
Dim Res As Dword

Dim Str_dat As String * 4
Dim Str_ext As String * 3
'Aliases
Cs Alias Portc.2
Mosi Alias Portc.3
Clk Alias Portc.4
Miso Alias Pinc.5


'Declarations
Declare Sub Minit
Declare Sub Readmmc(byval Addr As Long )
Declare Sub Mread(byval Addr As Long )
'Configs
Config Portc.5 = Output
Config Portc.2 = Output
Config Portc.4 = Output
Config Pinc.3 = Input


Waitms 300
Config Spi = Soft , Din = Pinc.5 , Dout = Portc.3 , Ss = Portc.2 , Clock = Portc.4
 Enable Interrupts
 Enable Spi

 Spiinit

 Sd_dat(1) = 1
 Sd_dat(2) = 2
 Sd_dat(3) = 3
 Sd_dat(4) = 4


'******** MAIN PROGRAM *************

' Reset Portd.3
Main:
 'Initialize the MMCC
 Wait 2
  Print ""
  Print "Init MMC"
 Minit

  Print "ok"

 Wait 2
  Print "read"
'поиск адреса PBR
 Adres = 0
 sub_adres = 454                                               '&H1C6
 Call Readmmc(adres)
  Gosub Result4
   Print "Adr_pbr " ; Res
   Adr_pbr = Res
 'количество зарезервированных секторов
 Adres = Res * 512
 sub_adres = 14                                                '0Eh 0Fh
 Call Readmmc(adres)
  Gosub Result2
   Print "Reserv_sec " ; Res
   Reserv_sec = Res

 'количество секторов в кластере
 sub_adres = 13                                                '0Dh
 Call Readmmc(adres)
'  Gosub Result2
   Kol_sec_klast = Sd_dat(1)
 Print "Kol_sec_klast " ; Kol_sec_klast

 'количество секторов FAT
 sub_adres = 22                                                '16h 17h
 Call Readmmc(adres)
  Gosub Result2
   Print "Kol_sec_fat " ; Res
   Kol_sec_fat = Res

 'Размер Root количество записей
 sub_adres = 17                                                '11h
 Call Readmmc(adres)
  Gosub Result2
   Print "Kol_zap_root " ; Res
   Kol_zap_root = Res
  'адрес корневого каталога
  Adr_root = 2 * Kol_sec_fat
  Adr_root = Adr_root + Reserv_sec
  Adr_root = Adr_root + Adr_pbr
 Print "Adr_root  " ; Adr_root
  'размер корневого каталога
  Razm_root = Kol_zap_root * 32
  Razm_root = Razm_root / 512
 Print "Razm_root " ; Razm_root
  'адрес области данных
  Adr_dat = Adr_root + Razm_root
  'Adr_dat = Adr_dat + Adr_pbr
 Print "Adr_dat " ; Adr_dat


'читаем первый файл
 Adres = Adr_root
 Adres = Adres * 512
 Sub_adres1 = 0                                             '&H1C6
 sub_adres = 0                                                 '&H1C6
 Stp = 0



 Do
 Gosub Read_file_name

 Print Str_dat ; "." ; Str_ext ; " s " ; Adr_file
' adres=(adr_dat+(adr_file*kol_sec_klast))*512 формула получения адреса начала файла

 Loop Until Str_dat = "endd"



   Print "End of program"
Endloop:
Goto Endloop
End                                                         'end program
'***************************** END OF PROGRAM **********************************
Read_file_name:
M1:
  Call Readmmc(adres)
  If Sd_dat(1) = 0 Then
   Str_dat = "endd"
   Goto M2
  End If
  If Sd_dat(1) = 229 Then
  Sub_adres1 = Sub_adres1 + 32
  Sub_adres = Sub_adres1
   Goto M1
  End If



    Str_dat = Chr(sd_dat(1)) : Str_dat = Str_dat + Chr(sd_dat(2))
    Str_dat = Str_dat + Chr(sd_dat(3)) : Str_dat = Str_dat + Chr(sd_dat(4))

    Sub_adres = Sub_adres1 + 8                              '&H1C6
    Call Readmmc(adres)
    Str_ext = Chr(sd_dat(1)) : Str_ext = Str_ext + Chr(sd_dat(2))
    Str_ext = Str_ext + Chr(sd_dat(3))

    Sub_adres = Sub_adres1 + 26                             '&H1A 1B
    Call Readmmc(adres)
    Adr_file = Sd_dat(2)
    Shift Adr_file , Left , 8
    Adr_file = Adr_file + Sd_dat(1)                         'получаем начало файла (смещение в кластерах)



   Sub_adres1 = Sub_adres1 + 32
   Sub_adres = Sub_adres1
M2:
return
'======= SUB ROUTINES AND FUNCTIONS =======
Result4:
Res = 0
Res = Sd_dat(4)
Shift Res , Left , 8
Res = Res + Sd_dat(3)
Shift Res , Left , 8
Res = Res + Sd_dat(2)
Shift Res , Left , 8
Res = Res + Sd_dat(1)

Return

Result2:
Res = 0
Res = Sd_dat(2)
Shift Res , Left , 8
Res = Res + Sd_dat(1)

Return

Result1:
Res = 0
Res = Sd_dat(1)
Return


'*** Инициализация карты MMC ***
Sub Minit
 Set Cs
 Dat = &HFF                                                 ' отправляем FF
 For I = 1 To 10                                            '10 раз чтоб MMC получила тактовые импульсы для свойх нужд (не менее 8)
  Shiftout Mosi , Clk , Dat , Msbl                          '
 Next I

 Resp = 255
 Reset Cs

Print "Reset MMC"
 Cmd0:                                                      ' команда 0 сброс карты 40,00,00,00,00,95
  Dat = &H40                                                '40
    Shiftout Mosi , Clk , Dat , Msbl
  Addr = &H00000000
    Shiftout Mosi , Clk , Addr , Msbl
  Dat = &H95
    Shiftout Mosi , Clk , Dat , Msbl

  While Resp <> &H01                                        ' ждем отклик 01 если всё нормально (другие биты указывают на ошибку)
    Shiftin Miso , Clk , Resp , Msbl
        Print "Otklik " ; Resp
  Wend
 Print "Reset OK!"
 Set Cs
  Waitms 50
 Reset Cs

 Dat = &HFF
 Print "Return SPI"
 Cmd1:                                                      ' команда 1 перевод карты в режим spi 41,00,00,00,00,FF
 While Resp <> &H00                                         ' ждем отклик 00 если всё нормально в противном случае повторяем
  Set Cs
    Shiftout Mosi , Clk , Dat , Msbl
    Shiftin Miso , Clk , Resp , Msbl
  Reset Cs
  Dat = &H41                                                ' код команды 41
    Shiftout Mosi , Clk , Dat , Msbl                        ' 00000000
  Addr = 0
    Shiftout Mosi , Clk , Addr , Msbl                       ' FF вместо CRC
  Dat = &HFF
    Shiftout Mosi , Clk , Dat , Msbl                        ' пустой для тактов
    Shiftout Mosi , Clk , Dat , Msbl
    Shiftin Miso , Clk , Resp , Msbl                        ' принимаем отклик (01)
   Print "otklik SPI " ; Resp
 Wend

 Dat = &HFF
 Set Cs
 Print "Init OK!"
End Sub



'**** READ routine assumes ADDR uses Status subroutine *****
Sub Readmmc(byval Addr As Long)
' Addr = 0
Incr sub_adres
I1 = 5
 Set Cs
 Dat = &HFF
   Shiftout Mosi , Clk , Dat , Msbl
   Shiftin Miso , Clk , Resp , Msbl
 Reset Cs

 Dat = &H51                                                 'команда 51 читать блок 512 байт
   Shiftout Mosi , Clk , Dat , Msbl                         'адрес
   Shiftout Mosi , Clk , Addr , Msbl

 Dat = &HFF                                                 'FF вместо СRC
   Shiftout Mosi , Clk , Dat , Msbl
   Shiftin Miso , Clk , Resp , Msbl

 While Resp <> 0                                            ' пока карта думает, перед посылкой она даст 0 потом FE
   Shiftin Miso , Clk , Resp , Msbl
 Wend

 While Resp <> &HFE                                         ' посылка данных предваряется байтом FE перед
   Shiftin Miso , Clk , Resp , Msbl
 Wend

 For I = 1 To 512                                           ' принимаем блок 512 байт
    Shiftin Miso , Clk , Resp , Msbl


    If I = sub_adres Then I1 = 1
    If I1 = 1 Then
      Sd_dat(1) = Resp                                   
'      Incr sub_adres
 '     Print "Block # " ; Addr ; " " ; I ; " - " ; Hex(resp)
    End If

    If I1 = 2 Then
      Sd_dat(2) = Resp                                      

 '     Print "Block # " ; Addr ; " " ; I ; " - " ; Hex(resp)
    End If

    If I1 = 3 Then
      Sd_dat(3) = Resp                                      

 '     Print "Block # " ; Addr ; " " ; I ; " - " ; Hex(resp)
    End If
    If I1 = 4 Then
    Sd_dat(4) = Resp                                       
 '   Print "Block # " ; Addr ; " " ; I ; " - " ; Hex(resp)   '
'     Waitms 50                                              
    End If
'      Pwm1a = Resp
'      Pwm1b = Resp
     If I1 < 5 Then Incr I1
      Waitus 29
 Next I

 Shiftin Miso , Clk , Resp , Msbl                           ' пропускаем два байта CRC
 Shiftin Miso , Clk , Resp , Msbl
Set Cs

End Sub

Отредактировано Димон (2014-09-03 19:02:37)

+1

3

После оптимизации 3.6 кб

0

4

Весьма интересно!!!

0

5

Подчистил и прокомментировал

Находит на карточке файл с названием SET и выводит первые 4 символа из его содержимого

Пока получаю четыре символа из названия файла, три из расширения и абсолютный адрес начала самого файла.

Код:
'---------------------------------------------
' Чтение SDCard FAT16
'
'---------------------------------------------

'  mega8      SD\MMC
'  25 PC2-----1 CS
'  26 PC3-----2 MOSI
'           --3 Gnd
'           --4 +3.3v
'  27 PC4-----5 SCK
'           --6 Gnd
'  28 PC5-----7 MISO
'
'  15 PB1--4,7mF--Speeker--Gnd
'
'------------------------------------------
$regfile = "m8def.dat"
$crystal = 11059200                                         '
$hwstack = 16
$swstack = 64
$framesize = 32

$baud = 9600

Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Up , Compare B Pwm = Clear Down , Prescale = 1       ' шим модулятор PWM
Pwm1a = 255
Pwm1b = 255
'Constants
Const Msbl = 0
Const Msbh = 1
Const Dly = 2
Const Bits8 = 8
Const Bits16 = 16
Const Bits32 = 32

'Dim
Dim Adr_pbr As Dword
Dim Reserv_sec As Word
Dim Kol_sec_fat As Word
Dim Adr_root As Dword
Dim Kol_sec_klast As Byte
Dim Kol_zap_root As Word
Dim Razm_root As Word
Dim Adr_dat As Word
Dim Adr_file As Word



Dim Dat As Byte
Dim Resp As Byte
Dim I As Word
Dim I1 As Byte
Dim Addr As Long
Dim Adres As Long
Dim Sub_adres As Word
Dim Sub_adres1 As Word
Dim Sd_dat1 As Byte
Dim Sd_dat2 As Byte
Dim Sd_dat3 As Byte
Dim Sd_dat4 As Byte
Dim Res As Dword

Dim Str_dat As String * 4
Dim Str_ext As String * 3
'Aliases
Cs Alias Portc.2
Mosi Alias Portc.3
Clk Alias Portc.4
Miso Alias Pinc.5

Config Portc.5 = Output
Config Portc.2 = Output
Config Portc.4 = Output
Config Pinc.3 = Input


Waitms 300
Config Spi = Soft , Din = Pinc.5 , Dout = Portc.3 , Ss = Portc.2 , Clock = Portc.4
 Enable Interrupts
 Enable Spi

 Spiinit

 Sd_dat1 = 1
 Sd_dat2 = 2
 Sd_dat3 = 3
 Sd_dat4 = 4


'******** MAIN PROGRAM *************


Main:

 Wait 2
  Print ""
  Print "Init MMC"
 Gosub Minit

  Print "ok"

 Wait 2
  Print "read"
'поиск адреса PBR
 Adres = 0                                                  'задаем адрес сектора (блок 512 байт)
 Sub_adres = 454                                            '&H1C6 задаем адрес внутри сектора чтоб считать следующие за ним 4 байта
 Gosub Readmmc                                              'вызываем процедуру считывания 4х байтов
  Gosub Result4                                             'переводим считанные 4 байла в четырехбайтнок число
   Print "Adr_pbr- " ; Res                                  'выводим результат
   Adr_pbr = Res
 'количество зарезервированных секторов
 Adres = Res * 512
 Sub_adres = 14                                             '0Eh 0Fh
 Gosub Readmmc
  Gosub Result2
   Print "Reserv_sec- " ; Res
   Reserv_sec = Res

 'количество секторов в кластере
 Sub_adres = 13                                             '0Dh
 Gosub Readmmc
'  Gosub Result2
   Kol_sec_klast = Sd_dat1
 Print "Kol_sec_klast- " ; Kol_sec_klast

 'количество секторов FAT
 Sub_adres = 22                                             '16h 17h
 Gosub Readmmc
  Gosub Result2
   Print "Kol_sec_fat- " ; Res
   Kol_sec_fat = Res

 'Размер Root количество записей
 Sub_adres = 17                                             '11h
 Gosub Readmmc
  Gosub Result2
   Print "Kol_zap_root- " ; Res
   Kol_zap_root = Res
  'адрес корневого каталога
  Adr_root = 2 * Kol_sec_fat
  Adr_root = Adr_root + Reserv_sec
  Adr_root = Adr_root + Adr_pbr
 Print "Adr_root- " ; Adr_root
  'размер корневого каталога
  Razm_root = Kol_zap_root * 32
  Razm_root = Razm_root / 512
 Print "Razm_root- " ; Razm_root
  'адрес области данных
  Adr_dat = Adr_root + Razm_root
  'Adr_dat = Adr_dat + Adr_pbr
 Print "Adr_dat- " ; Adr_dat


'задаем адрес первого файла в корневом каталоге первый файл
 Adres = Adr_root
 Adres = Adres * 512
 Sub_adres1 = 0
 Sub_adres = 0
Main_loop:
 Gosub Read_file_name                                       'читаем 4символа из имени файла, 3 символа расширения, смещение начального кластера
 If Str_dat = "SET " Then Goto M_2                          'ищем файл с названием SET, буквы заглавные дополненные пробелами до 4х символов
 If Str_dat = "endd" Then                                   'мой вариант поиска конца файлов
  Print "file not found"
  Goto Endloop
 End If
' adres=(adr_dat+(adr_file*kol_sec_klast-2))*512 формула получения адреса начала файла
Goto Main_loop

M_2:
 Print "File Name- " ; Str_dat ; "." ; Str_ext ; " ,klaster- " ; Adr_file       'выводим имя файла расширение и смещение кластера
 Adr_file = Adr_file - 2                                    'высчитываем абсолютный адрес начала файла
 Adres = Adr_file * Kol_sec_klast
 Adres = Adres + Adr_dat
 Adres = Adres * 512
 Sub_adres = 0
 Print "Adres file- " ; Adres                               'выводим адрес
 Gosub Readmmc                                              'считываем 4 первые символа из тела файла
 Print "Data file- " ; Chr(sd_dat1) ; Chr(sd_dat2) ; Chr(sd_dat3) ; Chr(sd_dat4)       'выводим содержимое файла

Print "End of program"
Endloop:
Goto Endloop
End                                                         'end program
'***************************** END OF PROGRAM **********************************
'чтение имени файла
Read_file_name:
M1:
  Gosub Readmmc
  If Sd_dat1 = 0 Then                                       ' если пришел 0 то это конец списка файлов
   Str_dat = "endd"
   Goto M2
  End If
  If Sd_dat1 = 229 Then                                     'если в имени файла пкрвый символ E5h то файл был удален
  Sub_adres1 = Sub_adres1 + 32                              'переходим к другому файлу
  Sub_adres = Sub_adres1
   Goto M1
  End If



    Str_dat = Chr(sd_dat1) : Str_dat = Str_dat + Chr(sd_dat2)
    Str_dat = Str_dat + Chr(sd_dat3) : Str_dat = Str_dat + Chr(sd_dat4)       'набираем в строку 4е символа - название файла

    Sub_adres = Sub_adres1 + 8                              '&H1C6 переход на расширение файла
    Gosub Readmmc
    Str_ext = Chr(sd_dat1) : Str_ext = Str_ext + Chr(sd_dat2)
    Str_ext = Str_ext + Chr(sd_dat3)                        'набираем в строку расширение файла

    Sub_adres = Sub_adres1 + 26                             '&H1A 1B переход на информацию о начале файла
    Gosub Readmmc
    Adr_file = Sd_dat2
    Shift Adr_file , Left , 8
    Adr_file = Adr_file + Sd_dat1                           'получаем начало файла (смещение в кластерах)



   Sub_adres1 = Sub_adres1 + 32
   Sub_adres = Sub_adres1
M2:
Return
'======= SUB ROUTINES AND FUNCTIONS =======
Result4:                                                    'собираем четырехбайтное число
Res = 0
Res = Sd_dat4
Shift Res , Left , 8
Res = Res + Sd_dat3
Shift Res , Left , 8
Res = Res + Sd_dat2
Shift Res , Left , 8
Res = Res + Sd_dat1

Return

Result2:                                                    'собираем двухбайтное число
Res = 0
Res = Sd_dat2
Shift Res , Left , 8
Res = Res + Sd_dat1

Return

Result1:
Res = 0
Res = Sd_dat1
Return


'*** Инициализация карты MMC ***
Minit:
 Set Cs
 Dat = &HFF                                                 ' отправляем FF
 For I = 1 To 10                                            '10 раз чтоб MMC получила тактовые импульсы для свойх нужд (не менее 8)
  Shiftout Mosi , Clk , Dat , Msbl                          '
 Next I

 Resp = 255
 Reset Cs

Print "Reset MMC"
 Cmd0:                                                      ' команда 0 сброс карты 40,00,00,00,00,95
  Dat = &H40                                                '40
    Shiftout Mosi , Clk , Dat , Msbl
  Addr = &H00000000
    Shiftout Mosi , Clk , Addr , Msbl
  Dat = &H95
    Shiftout Mosi , Clk , Dat , Msbl

  While Resp <> &H01                                        ' ждем отклик 01 если всё нормально (другие биты указывают на ошибку)
    Shiftin Miso , Clk , Resp , Msbl
        Print "Otklik " ; Resp
  Wend
 Print "Reset OK!"
 Set Cs
  Waitms 50
 Reset Cs

 Dat = &HFF
 Print "Return SPI"
 Cmd1:                                                      ' команда 1 перевод карты в режим spi 41,00,00,00,00,FF
 While Resp <> &H00                                         ' ждем отклик 00 если всё нормально в противном случае повторяем
  Set Cs
    Shiftout Mosi , Clk , Dat , Msbl
    Shiftin Miso , Clk , Resp , Msbl
  Reset Cs
  Dat = &H41                                                ' код команды 41
    Shiftout Mosi , Clk , Dat , Msbl                        ' 00000000
  Addr = 0
    Shiftout Mosi , Clk , Addr , Msbl                       ' FF вместо CRC
  Dat = &HFF
    Shiftout Mosi , Clk , Dat , Msbl                        ' пустой для тактов
    Shiftout Mosi , Clk , Dat , Msbl
    Shiftin Miso , Clk , Resp , Msbl                        ' принимаем отклик (01)
   Print "otklik SPI " ; Resp
 Wend

 Dat = &HFF
 Set Cs
 Print "Init OK!"
Return



'**** READ routine assumes ADDR uses Status subroutine *****
Readmmc:
' Addr = 0
Incr Sub_adres                                              'задает адрес внутри выбранного сектора
I1 = 5
 Set Cs
 Dat = &HFF
   Shiftout Mosi , Clk , Dat , Msbl
   Shiftin Miso , Clk , Resp , Msbl
 Reset Cs

 Dat = &H51                                                 'команда 51 читать блок 512 байт
   Shiftout Mosi , Clk , Dat , Msbl                         'адрес
   Shiftout Mosi , Clk , Adres , Msbl

 Dat = &HFF                                                 'FF вместо СRC
   Shiftout Mosi , Clk , Dat , Msbl
   Shiftin Miso , Clk , Resp , Msbl

 While Resp <> 0                                            ' пока карта думает, перед посылкой она даст 0 потом FE
   Shiftin Miso , Clk , Resp , Msbl
 Wend

 While Resp <> &HFE                                         ' посылка данных предваряется байтом FE перед
   Shiftin Miso , Clk , Resp , Msbl
 Wend

 For I = 1 To 512                                           ' принимаем блок 512 байт
    Shiftin Miso , Clk , Resp , Msbl

'читаем 4 байта с SD
    If I = Sub_adres Then I1 = 1
    If I1 = 1 Then
      Sd_dat1 = Resp                                        '
'      Incr sub_adres
 '     print "Block # " ; Adres ; " " ; I ; " - " ; Hex(resp)
    End If

    If I1 = 2 Then
      Sd_dat2 = Resp                                        '

 '     print "Block # " ; Adres ; " " ; I ; " - " ; Hex(resp)
    End If

    If I1 = 3 Then
      Sd_dat3 = Resp                                        '

 '     print "Block # " ; Adres ; " " ; I ; " - " ; Hex(resp)
    End If
    If I1 = 4 Then
    Sd_dat4 = Resp                                          '
 '   print "Block # " ; Adres ; " " ; I ; " - " ; Hex(resp)   '
'     Waitms 50                                              '
    End If
'      Pwm1a = Resp
'      Pwm1b = Resp
     If I1 < 5 Then Incr I1
      Waitus 29
 Next I

 Shiftin Miso , Clk , Resp , Msbl                           ' пропускаем два байта CRC
 Shiftin Miso , Clk , Resp , Msbl
Set Cs
Return

+2

6

Тема весьма интересная. То же в своё время разбирался.
В итоге налетел на баскомовском форуме (забугорном) на готовые библиотеки и понял, что есть два пути: юзать их (не изобретая велосипед) или уйти к примитивам.
Весь FAT из-за своей основы весьма массивной, по хорошему требует кучу ОЗУ и худо-бедно можно конечно что-то организовать, но всё равно полностью не получится.
Там столько нюансов и система весьма гибкая, что проще использовать свою файловую систему (это второй вариант). Можно взять готовую, на подобии TR-DOS или ещё проще (если нужна совместимость с PC), создаем один жирный файл с своими аттрибутами/признаками (можно на весь объём носителя/раздела или часть) и потом по этим признакам с ним работаем. Такой вариант весьма успешно используют люди в инете. Понятное дело, что требуется доп. ПО для работы с своими данными, за-то полная поддержка функционала.
Кстати говоря есть ряд готовых аппаратно-программных решений от FTDI и 4D Systems.

+1

7

Для полного чтения FAT есть AVR-DOS  и изобретать ничего не надо. Но даже на Atmega16 она не работает.

0

8

RDW написал(а):

есть ряд готовых аппаратно-программных решений от FTDI и 4D Systems.

fat 16

0

9

Александр Д. написал(а):

fat 16

FTDI на ванкулуме2 у меня спокойно читала и писала USB флешки 32ГБ, т.ч. FAT32, но на макс объём не гонял.

Отредактировано RDW (2014-09-07 21:56:24)

0

10

Димон, Вы в своём коде конфигурируете софтовый spi при этом не используете, почему? Вот я инициализацию подправил, код существенно уменьшился

Код:
Sub Minit
'Do
 Set Cs
 D(1) = &HFF : D(2) = &HFF : D(3) = &HFF : D(4) = &HFF : D(5) = &HFF : D(6) = &HFF : D(7) = &HFF : D(8) = &HFF       ' отправляем FF
  Spiout D(1) , 8
 Reset Cs
Print "Reset MMC"

 Cmd0:                                                      ' команда 0 сброс карты 40,00,00,00,00,95
  D(1) = &H40                                               '40
  D(2) = 0
  D(3) = 0
  D(4) = 0
  D(5) = 0
  D(6) = &H95
  D(7) = 0
    Spiout D(1) , 7

  While Resp <> &H01                                        ' ждем отклик 01 если всё нормально (другие биты указывают на ошибку)
   Spiin Resp , 1
        Print "Otklik " ; Resp
  Wend

 Print "Reset OK!"
 Print "Return SPI"

 Cmd1:
 D(1) = &H41                                                ' команда 1 перевод карты в режим spi 41,00,00,00,00,FF
 While Resp <> &H00                                         ' ждем отклик 00 если всё нормально в противном случае повторяем
  Spiout D(1) , 7                                           ' принимаем отклик (01)
 Spiin Resp , 1
        Print "Otklik " ; Resp
  Wend
 Set Cs
 Print "Init OK!"
End Sub

И второй вопрос - решил проверить как считывает. Считал первый сектор с карты, а он не совпадает . Потом разобрался, что реально начинает считывать с 249 сектора, хотя addr = 0. В чём может быть причина? Карта микросд на 1Гб.

0


Вы здесь » Программирование ATMEL в BASCOM. » Вопросы - ответы » Давайте прочитаем FAT без библиотек