$regfile = "m32DEF.dat"
$crystal = 11059200
$baud = 19200

'Нога отвечает за Вкл/Откл SD карты в SPI режиме
Config Portb.4 = Output : Chip_select Alias Portb.4

Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4

Dim Флаг As Bit
Dim ФлагПроверкиЗаписи As Bit
Dim ФлагДанныеЗаписаныВерно As Bit

Dim ПринятыйБайт As Byte
Dim Sd_command(6) As Byte
'Ответ максимум состоит из 10 байт
Dim Size_answer As Byte
Dim Sd_answer(10) As Byte
Dim Sd_data(512) As Byte

Dim Tmp_byt1 As Byte
Dim Tmp_byt2 As Byte
Dim Tmp_byt3 As Byte

Dim Count_wrd As Word

Dim Tmp_wrd1 As Word
Dim Tmp_wrd2 As Word

Dim Sd_address As Long

Print "Старт программы"

Begin:
Chip_select = 1 'Отключить SD карту
'Ответ максимум состоит из 1 байт
Size_answer = 1
ФлагПроверкиЗаписи = 0
Sd_address = &H0

Spiinit 'Инициализация SPI у меги

Gosub Init_sd 'Инициализация SPI у SD карты

  Do
  Gosub Clear_sd_buffer   'Очистить буфер для чтения/записи SD карты

  Sd_data(1) = 10
  Sd_data(2) = 20
  Sd_data(3) = 30
  Sd_data(4) = 40
  Sd_data(5) = 50
  Sd_data(6) = 60
  Sd_data(7) = 70
  Sd_data(8) = 80
  Sd_data(9) = 90
  Sd_data(10) = 100

  Gosub Write_sd_data  'Записать данные в SD карту

  Gosub Read_sd_data  'Прочитать данные из SD карты

  Sd_address = Sd_address + 512

  Loop Until Sd_address = 2048
End

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

Init_sd: 'Подпограмма инициализирует SPI у SD карты

Print "Инициализация SPI у SD карты"

'Переводим SD карту в SPI режим
ПринятыйБайт = Spimove(&Hff)
ПринятыйБайт = Spimove(&Hff)
ПринятыйБайт = Spimove(&Hff)
ПринятыйБайт = Spimove(&Hff)
ПринятыйБайт = Spimove(&Hff)
ПринятыйБайт = Spimove(&Hff)
ПринятыйБайт = Spimove(&Hff)
ПринятыйБайт = Spimove(&Hff)
ПринятыйБайт = Spimove(&Hff)
ПринятыйБайт = Spimove(&Hff)

Chip_select = 0 'Включить SD карту

Print "Ресет SD карты"
'Послать команду ресет SD карты
Sd_command(1) = &H40
Sd_command(2) = &H00
Sd_command(3) = &H00
Sd_command(4) = &H00
Sd_command(5) = &H00
Sd_command(6) = &H95
Gosub Send_sd_command

Print "Инициализация SD карты"
  Do 'Послать команду инициализации SD карты
  Sd_command(1) = &H41
  Sd_command(2) = &H00
  Sd_command(3) = &H00
  Sd_command(4) = &H00
  Sd_command(5) = &H00
  Sd_command(6) = &H55
  Gosub Send_sd_command
  Waitms 100
  Loop Until Sd_answer(1) = 0

Chip_select = 1 'Отключить SD карту

Print "Инициализация SPI у SD карты окончена"
Return

Send_sd_command: 'Подпограмма посылает команду SD карте

ПринятыйБайт = Spimove(&Hff)
ПринятыйБайт = Spimove(sd_command(1))
ПринятыйБайт = Spimove(sd_command(2))
ПринятыйБайт = Spimove(sd_command(3))
ПринятыйБайт = Spimove(sd_command(4))
ПринятыйБайт = Spimove(sd_command(5))
ПринятыйБайт = Spimove(sd_command(6))

Gosub Receive_sd_command 'Получить ответ от SD карты

ПринятыйБайт = Spimove(ПринятыйБайт)
Return

Receive_sd_command: 'Подпограмма получает ответ от SD карты

  Do
  ПринятыйБайт = Spimove(&Hff)
  Loop Until ПринятыйБайт <> &HFF

Tmp_byt1 = 0
  Do
  Incr Tmp_byt1
  Sd_answer(tmp_byt1) = ПринятыйБайт
  ПринятыйБайт = Spimove(&Hff)
  Loop Until ПринятыйБайт = &HFF Or Size_answer = Tmp_byt1

Print "Ответ SD карты"
For Tmp_byt2 = 1 To Tmp_byt1
  Print "Байт №" ; Tmp_byt2 ; " = " ; Sd_answer(tmp_byt2)
Next
Return

Clear_sd_buffer: 'Подпограмма очищяет буфер для чтения/записи SD карты

For Count_wrd = 1 To 512
  Sd_data(count_wrd) = 0
Next
Return

Write_sd_data: 'Подпограмма записывает данные в SD карту по адресу Sd_address размером 512 байт
'данные берёт из Sd_data(512)

  Do
  Tmp_byt3 = 0
    Do
    Флаг = 0
    Chip_select = 0     'Включить SD карту

    Print "Запись"

    Print "Записать блок данных (512 байт) по адресу " ; Hex(sd_address)

      Do
      Incr Tmp_byt3
      Print "Попытка записать данные №" ; Tmp_byt3
      Sd_command(1) = &H58  'Послать команду записать блок данных по адресу (sd_address) в SD карту

      Tmp_wrd1 = Highw(sd_address)
      Tmp_wrd2 = Sd_address

      Sd_command(2) = High(tmp_wrd1)
      Sd_command(3) = Low(tmp_wrd1)
      Sd_command(4) = High(tmp_wrd2)
      Sd_command(5) = Low(tmp_wrd2)
      Sd_command(6) = &H55
      Gosub Send_sd_command
      Loop Until Sd_answer(1) = 0 Or Tmp_byt3 = 5

    If Sd_answer(1) <> 0 Then
      Флаг = 1       'Команда на запись не прошла
      Print "Пришёл неверный ответ от команды записи"
    Else
      Print "Послать данные"
      ПринятыйБайт = Spimove(&Hff)      'Послать данные
      ПринятыйБайт = Spimove(&Hfe)      'Послать стартовые байты
      'Послать данные
      For Count_wrd = 1 To 512
        ПринятыйБайт = Spimove(sd_data(count_wrd))
      Next
      'Послать CRC16
      ПринятыйБайт = &H55
      ПринятыйБайт = Spimove(ПринятыйБайт)
      ПринятыйБайт = &H55
      ПринятыйБайт = Spimove(ПринятыйБайт)

      Gosub Receive_sd_command      'Получить ответ от SD карты

      If Sd_answer(1) <> 229 Then
        Sd_answer(1) = 1         'Данные не записались
        If Tmp_byt3 = 5 Then
          Флаг = 1
          Print "Пришёл неверный ответ после записи данных"
        End If
      Else
        ПринятыйБайт = Spimove(&Hff)

        Chip_select = 1        'Отключить Sd карту

        ПринятыйБайт = Spimove(&Hff)

        Chip_select = 0        'Включить SD карту

        ПринятыйБайт = Spimove(&Hff)

        Print "Данные успешно записаны"
        Sd_answer(1) = 0
      End If
    End If

    Chip_select = 1     'Отключить Sd карту
    Waitms 10     'Время, которое неоюходимо, для записи данных в SD карту

    If Флаг = 1 Then
      Tmp_byt3 = 0      'Произошла ошибка при записи команды или данных
      Gosub Init_sd      'Инициализация SPI у SD карты
    End If
    Loop Until Флаг = 0 And Sd_answer(1) = 0
  ФлагПроверкиЗаписи = 1  'Проверить правильно ли записали
  Gosub Read_sd_data  'Прочитать данные из SD карты

  If ФлагДанныеЗаписаныВерно = 1 Then
    Print "Верификация прошла успешно"
  Else
    Print "Верификация не прошла"
  End If
  Loop Until ФлагДанныеЗаписаныВерно = 1
Return

Read_sd_data:
'Подпограмма читает данные из SD карты по адресу Sd_address размером 512 байт
'данные записывает в Sd_data(512)
ФлагДанныеЗаписаныВерно = 1

  Do
  Флаг = 0
  Chip_select = 0  'Включить SD карту

  If ФлагПроверкиЗаписи = 1 Then
    Print "Верификация"
  Else
    Print "Чтение"
  End If

  Print "Установить размер блока чтения данных - 512"
  'Послать команду установить размер блока 512 в SD карту
  Sd_command(1) = &H50
  Sd_command(2) = &H00
  Sd_command(3) = &H00
  Sd_command(4) = &H02
  Sd_command(5) = &H00
  Sd_command(6) = &H55
  Gosub Send_sd_command

  Print "Прочитать блок данных по адресу " ; Hex(sd_address)
  'Послать команду прочитать блок данных по адресу (sd_address) в SD карту

  Tmp_byt3 = 0
    Do
    Incr Tmp_byt3
    Print "Попытка прочитать данные №" ; Tmp_byt3
    Sd_command(1) = &H51

    Tmp_wrd1 = Highw(sd_address)
    Tmp_wrd2 = Sd_address

    Sd_command(2) = High(tmp_wrd1)
    Sd_command(3) = Low(tmp_wrd1)
    Sd_command(4) = High(tmp_wrd2)
    Sd_command(5) = Low(tmp_wrd2)
    Sd_command(6) = &H55
    Gosub Send_sd_command
    Loop Until Sd_answer(1) = 0 Or Tmp_byt3 = 5

  If Sd_answer(1) <> 0 Then
    Флаг = 1     'Команда на чтение не прошла
    Print "Пришёл неверный ответ от команды чтения"
  Else
    'Получение данных
    'Поймать стартовый байт
      Do
      ПринятыйБайт = Spimove(&Hff)
      Loop Until ПринятыйБайт = &HFE
    For Count_wrd = 1 To 512     'Получить 512 байт данных
      If ФлагПроверкиЗаписи = 1 Then
        ПринятыйБайт = Spimove(&Hff)        'Читаем и сравниваем с Sd_data(512)
        If ПринятыйБайт <> Sd_data(count_wrd) Then
          ФлагДанныеЗаписаныВерно = 0
        End If
      Else
        Sd_data(count_wrd) = Spimove(&Hff)        'Читаем и записываем в Sd_data(512)
      End If
    Next
    'Получить КС
    ПринятыйБайт = Spimove(&Hff)
    ПринятыйБайт = Spimove(&Hff)

    Print "Данные успешно считаны"
  End If

  Chip_select = 1   'Отключить Sd карту'

  If Флаг = 1 Then
    'Произошла ошибка при записи команды или данных

    Gosub Init_sd    'Инициализация SPI у SD карты
  End If
  Loop Until Флаг = 0
ФлагПроверкиЗаписи = 0
Return