;
.DSEG
SD_CARDTYPE: .BYTE 1 ;.0-SDv1; .1-SDv2; .2-SDv2HC; .4-MMC
; на данный момент имеет значение только это ^^^^^^^^^
;
FAT_CAL_FAT: .BYTE 1 ;тип обнаруженной FAT
FAT_MANYFAT: .BYTE 1 ;количество FAT-таблиц
FAT_BYTSSEC: .BYTE 1 ;количество секторов в кластере
FAT_ROOTCLS: .BYTE 4 ;КЛАСТЕР начала root директории
FAT_SEC_FAT: .BYTE 4 ;количество секторов одной FAT
FAT_RSVDSEC: .BYTE 2 ;размер резервной области
FAT_STARTRZ: .BYTE 4 ;начало диска/раздела
FAT_FRSTDAT: .BYTE 4 ;адрес первого сектора данных от BPB
FAT_SEC_DSC: .BYTE 4 ;количество секторов на диске/разделе
FAT_CLS_DSC: .BYTE 4 ;количество кластеров на диске/разделе
FAT_FATSTR0: .BYTE 4 ;начало первой FAT таблицы
FAT_FATSTR1: .BYTE 4 ;начало второй FAT таблицы
FAT_TEK_DIR: .BYTE 4 ;кластер текущей директории
FAT_KCLSDIR: .BYTE 1 ;кол-во кластеров директории
FAT_NUMSECK: .BYTE 1 ;счетчик секторов в кластере
FAT_TFILCLS: .BYTE 4 ;текущий кластер
FAT_MPHWOST: .BYTE 1 ;кол-во секторов в последнем кластере
FAT_KOL_CLS: .BYTE 4 ;кол-во кластеров файла минус 1
FAT_LASTSECFLAG:.BYTE 1
FAT_ERRHANDLER: .BYTE 2
FAT_LST0ZAP: .BYTE 4
.CSEG
;
CMD00: .DB $40,$00,$00,$00,$00,$95
CMD08: .DB $48,$00,$00,$01,$AA,$87
CMD16: .DB $50,$00,$00,$02,$00,$FF
;
;инициализация SD карточки
;out: XW == номер кластера root-директории
SD_FAT_INIT:
STSZ FAT_ERRHANDLER
LDI TEMP,SD_CS1
SER DATA
CALL FPGA_REG
LDI TEMP,32
RCALL SD_RD_DUMMY
LDI TEMP,SD_CS0
SER DATA
CALL FPGA_REG
SER COUNT
SDINIT1:LDIZ CMD00*2 ;CMD0 (go_idle_state)
RCALL SD_WR_PGM_6
DEC COUNT
BRNE SDINIT2
LDI DATA,1 ;нет карты
RJMP SD_ERROR
SDINIT2:CPI DATA,$01
BRNE SDINIT1
LDIZ CMD08*2 ;CMD8 (send_if_cond)
RCALL SD_WR_PGM_6
LDI WL,$00
SBRS DATA,2
LDI WL,$40
LDI TEMP,4
RCALL SD_RD_DUMMY
SDINIT3:LDI DATA,$40+55 ;CMD55
RCALL SD_WR_CMD
LDI TEMP,2
RCALL SD_RD_DUMMY
LDI DATA,$40+41 ;ACMD41 (sd_send_op_cond)
RCALL SD_EXCHANGE
MOV DATA,WL
RCALL SD_EXCHANGE
RCALL SD_WR_CMX4
TST DATA
BREQ SDINIT5
SBRS DATA,2
RJMP SDINIT3
SDINIT4:LDI DATA,$40+1 ;CMD1 (send_op_cond)
RCALL SD_WR_CMD
TST DATA
BRNE SDINIT4
RCALL SD_CRC_OFF
RCALL SD_SETBLKLEN
LDI TEMP,0B00010000
RJMP SDINIT9
SDINIT5:RCALL SD_CRC_OFF
RCALL SD_SETBLKLEN
LDI TEMP,0B00000001
TST WL
BREQ SDINIT9
LDI DATA,$40+58 ;CMD58 (read_ocr)
RCALL SD_WR_CMD
RCALL SD_RECEIVE
PUSH DATA
LDI TEMP,3+2
RCALL SD_RD_DUMMY
POP DATA
LDI TEMP,0B00000010
SBRC DATA,6
LDI TEMP,0B00000110
SDINIT9:STS SD_CARDTYPE,TEMP
;
; - - - - - - - - - - - - - - - - - - -
;поиск FAT, инициализация переменных
WC_FAT: LDIZ FAT_LST0ZAP
ST Z+,FF
ST Z+,FF
ST Z+,FF
ST Z,FF
LDIW 0
LDIX 0
RCALL LOADLST
RCALL FAT_CHKSIGN
BREQ WC_FAT1
SDERR3: LDI DATA,3 ;не найдена FAT
RJMP SD_ERROR
WC_FAT1:LDI ZL,$BE
LD DATA,Z
ANDI DATA,$7F
BRNE RDFAT05
LDI ZL,$C2
LD DATA,Z
CPI DATA,$01
BREQ RDFAT06
CPI DATA,$04
BREQ RDFAT06
CPI DATA,$06
BREQ RDFAT06
CPI DATA,$0B
BREQ RDFAT06
CPI DATA,$0C
BREQ RDFAT06
CPI DATA,$0E
BRNE RDFAT05
RDFAT06:LDI ZL,$C6
LD WL,Z+
LD WH,Z+
LD XL,Z+
LD XH,Z
RJMP RDFAT00
RDFAT05:LDIZ BUF4FAT
LDD BITS,Z+13 ;BPB_SecPerClus
LDI DATA,0
LDI TEMP,0
LDI COUNT,8
RDF051: ROR BITS
ADC DATA,NULL
DEC COUNT
BRNE RDF051
DEC DATA
BRNE RDF052
INC TEMP
RDF052: LDD DATA,Z+14 ;BPB_RsvdSecCnt
LDD R0,Z+15 ;BPB_RsvdSecCnt
OR DATA,R0
BREQ RDF053
INC TEMP
RDF053: LDD DATA,Z+19 ;BPB_TotSec16
LDD R0,Z+20 ;BPB_TotSec16
OR DATA,R0
BRNE RDF054
INC TEMP
RDF054: LDD DATA,Z+32 ;BPB_TotSec32
LDD R0,Z+33 ;BPB_TotSec32
OR DATA,R0
LDD R0,Z+34 ;BPB_TotSec32
OR DATA,R0
LDD R0,Z+35 ;BPB_TotSec32
OR DATA,R0
BRNE RDF055
INC TEMP
RDF055: LDD DATA,Z+21 ;BPB_Media
ANDI DATA,$F0
CPI DATA,$F0
BRNE RDF056
INC TEMP
RDF056: CPI TEMP,4
BREQ RDF057
RJMP SDERR3
;
RDF057: LDIW 0
LDIX 0
RDFAT00:STSW FAT_STARTRZ+0
STSX FAT_STARTRZ+2
RCALL LOADLST
RCALL FAT_CHKSIGN
BREQ RDF011
RJMP SDERR3
RDF011: LDIZ BUF4FAT
LDD DATA,Z+11 ;BPB_BytsPerSec
TST DATA
BRNE SDERR4
LDD DATA,Z+12 ;BPB_BytsPerSec
CPI DATA,$02
BREQ RDF012
SDERR4: LDI DATA,4 ;ошибка FAT (сектор не 512 байт)
RJMP SD_ERROR
RDF012: LDIX 0
LDD WL,Z+22 ;BPB_FATSz16
LDD WH,Z+23 ;BPB_FATSz16
MOV DATA,WH
OR DATA,WL
BRNE RDFAT01 ;если BPB_FATSz16==0 то берем BPB_FATSz32
LDD WL,Z+36 ;BPB_FATSz32
LDD WH,Z+37 ;BPB_FATSz32
LDD XL,Z+38 ;BPB_FATSz32
LDD XH,Z+39 ;BPB_FATSz32
RDFAT01:STSW FAT_SEC_FAT+0
STSX FAT_SEC_FAT+2 ;число секторов на FAT-таблицу
LDIX 0
LDD WL,Z+19 ;BPB_TotSec16
LDD WH,Z+20 ;BPB_TotSec16
MOV DATA,WH
OR DATA,WL
BRNE RDFAT02 ;если BPB_TotSec16==0 то берем из BPB_TotSec32
LDD WL,Z+32 ;BPB_TotSec32
LDD WH,Z+33 ;BPB_TotSec32
LDD XL,Z+34 ;BPB_TotSec32
LDD XH,Z+35 ;BPB_TotSec32
RDFAT02:STSW FAT_SEC_DSC+0
STSX FAT_SEC_DSC+2 ;к-во секторов на диске/разделе
;вычисляем rootdirsectors
LDD WL,Z+17 ;BPB_RootEntCnt
LDD WH,Z+18 ;BPB_RootEntCnt
LDIX 0
MOV DATA,WH
OR DATA,WL ;в FAT32 поле BPB_RootEntCnt всегда 0
BREQ RDFAT03 ;поэтому для FAT32 RootDirSectors всегда 0
LDI DATA,$10
RCALL BCDE_A
MOVW XL,WL
RDFAT03:PUSH XH ;RootDirSectors в X
PUSH XL
LDD DATA,Z+16 ;BPB_NumFATs
STS FAT_MANYFAT,DATA
LDSW FAT_SEC_FAT+0
LDSX FAT_SEC_FAT+2
DEC DATA
RDF031: LSL WL
ROL WH
ROL XL
ROL XH
DEC DATA
BRNE RDF031
POP TMP2
POP TMP3
;полный размер FAT-области в секторах
RCALL HLDEPBC ;прибавили RootDirSectors
LDD TMP2,Z+14 ;BPB_RsvdSecCnt
LDD TMP3,Z+15 ;BPB_RsvdSecCnt
STS FAT_RSVDSEC+0,TMP2
STS FAT_RSVDSEC+1,TMP3
RCALL HLDEPBC ;прибавили BPB_RsvdSecCnt
STSW FAT_FRSTDAT+0
STSX FAT_FRSTDAT+2 ;положили номер первого сектора данных
LDIZ FAT_SEC_DSC
RCALL BCDEHLM ;вычли из полного к-ва секторов раздела
LDIZ BUF4FAT
LDD DATA,Z+13 ;BPB_SecPerClus
CPI DATA,65
BRCS RDF032
RJMP SDERR4 ;ошибка FAT (кластер>32Kb, ограничения флешера)
RDF032: STS FAT_BYTSSEC,DATA
RCALL BCDE_A ;разделили на к-во секторов в кластере
STSW FAT_CLS_DSC+0
STSX FAT_CLS_DSC+2 ;положили кол-во кластеров на разделе
;microsoft-recommended FAT type determination (FAT12 <4085; FAT16 <65525; else FAT32)
LDI DATA,2
TST XH
BRNE RDFAT04
TST XL
BRNE RDFAT04
CPI WL,$F5
CPC WH,FF
BRCC RDFAT04
LDI DATA,1
LDI TEMP,$0F
CPI WL,$F5
CPC WH,TEMP
BRCC RDFAT04
LDI DATA,0
;alternative FAT type determination
; PUSHX
; PUSHW
; LSL WL
; ROL WH
; ROL XL
; ROL XH
; RCALL RASCHET
; LDI DATA,1
; POPW
; POPX
; BREQ RDFAT04
; LSL WL
; ROL WH
; ROL XL
; ROL XH
; LSL WL
; ROL WH
; ROL XL
; ROL XH
; RCALL RASCHET
; LDI DATA,2
; BREQ RDFAT04
; CLR DATA
RDFAT04:STS FAT_CAL_FAT,DATA
;для FAT12/16 вычисляем адрес первого сектора директории
;для FAT32 берем по смещемию +44
;на выходе XW == кластер rootdir
LDIW 0
LDIX 0
TST DATA
BREQ FSRROO2
DEC DATA
BREQ FSRROO2
LDD WL,Z+44
LDD WH,Z+45
LDD XL,Z+46
LDD XH,Z+47
FSRROO2:STSW FAT_ROOTCLS+0
STSX FAT_ROOTCLS+2 ;КЛАСТЕР root директории
STSW FAT_TEK_DIR+0
STSX FAT_TEK_DIR+2
LDSW FAT_RSVDSEC
LDIX 0
LDIZ FAT_STARTRZ
RCALL BCDEHLP
STSW FAT_FATSTR0+0
STSX FAT_FATSTR0+2
LDIZ FAT_SEC_FAT
RCALL BCDEHLP
STSW FAT_FATSTR1+0
STSX FAT_FATSTR1+2
LDSW FAT_ROOTCLS+0
LDSX FAT_ROOTCLS+2
;
;--------------------------------------
;
CALCKCLSDIR:
PUSHW
PUSHX
LDI TEMP,1
MOV R0,WL
OR R0,WH
OR R0,XL
OR R0,XH
BREQ LASTCLS
NEXTCLS:PUSH TEMP
RCALL RDFATZP
RCALL LST_CLS
POP TEMP
BRCC LASTCLS
INC TEMP
RJMP NEXTCLS
LASTCLS:STS FAT_KCLSDIR,TEMP
POPX
POPW
RET
;
;--------------------------------------
;
SD_CRC_OFF:
LDI DATA,$40+59 ;CMD59 (crc_on_off)
RCALL SD_WR_CMD
TST DATA
BRNE SD_CRC_OFF
RET
;
;--------------------------------------
;
SD_SETBLKLEN:
LDIZ CMD16*2 ;CMD16 (set_blocklen)
RCALL SD_WR_PGM_6
TST DATA
BRNE SD_SETBLKLEN
RET
;
;--------------------------------------
;out: sreg.Z SET==signature exist
; Z==BUF4FAT+$01FF
FAT_CHKSIGN:
LDIZ BUF4FAT+$01FE
LD DATA,Z+
CPI DATA,$55
LD DATA,Z
BRNE FAT_CHKSIG9
CPI DATA,$AA
FAT_CHKSIG9:
RET
;
;--------------------------------------
;чтение сектора данных
LOAD_DATA:
SBRS FLAGS1,3
RJMP LOAD_DAT1
PUSH FLAGS1
CBR FLAGS1,0B00001101
SBR FLAGS1,0B00000010
LDIZ MSG_TSD_READSECTOR*2
CALL PRINTSTRZ
MOV DATA,XH
CALL HEXBYTE
MOV DATA,XL
CALL HEXBYTE
MOV DATA,WH
CALL HEXBYTE
MOV DATA,WL
CALL HEXBYTE
POP FLAGS1
LOAD_DAT1:
LDIZ BUFSECT
RCALL SD_READ_SECTOR ;читать один сектор
BREQ SDERR2
; SBRS FLAGS1,3
RET
; LDIZ BUFSECT
; CALL UART_DUMP512
; RET
;
;--------------------------------------
SDERR2: LDI DATA,2 ;ошибка при чтении сектора
SD_ERROR:
LDSZ FAT_ERRHANDLER
IJMP
;
;--------------------------------------
;чтение сектора служ.инф. (FAT/DIR/...)
LOADLST:
LDIZ FAT_LST0ZAP
LD DATA,Z+
CP DATA,WL
BRNE LOADLST2
LD DATA,Z+
CP DATA,WH
BRNE LOADLST2
LD DATA,Z+
CP DATA,XL
BRNE LOADLST2
LD DATA,Z+
CP DATA,XH
BREQ LOADLST9
LOADLST2:
STSW FAT_LST0ZAP+0
STSX FAT_LST0ZAP+2
SBRS FLAGS1,3
RJMP LOADLST1
PUSH FLAGS1
CBR FLAGS1,0B00001101
SBR FLAGS1,0B00000010
LDIZ MSG_TSD_READSECTOR*2
CALL PRINTSTRZ
MOV DATA,XH
CALL HEXBYTE
MOV DATA,XL
CALL HEXBYTE
MOV DATA,WH
CALL HEXBYTE
MOV DATA,WL
CALL HEXBYTE
POP FLAGS1
LOADLST1:
LDIZ BUF4FAT
RCALL SD_READ_SECTOR ;читать один сектор
BREQ SDERR2
LDIZ BUF4FAT
SBRS FLAGS1,3
RET
CALL UART_DUMP512
LOADLST9:
LDIZ BUF4FAT
RET
;
;--------------------------------------
;чтение сектора dir по номеру описателя (W)
;на выходе: DATA=#ff (sreg.Z=0) выход за пределы dir
RDDIRSC:PUSHW
LDI TEMP,SD_CS0
SER DATA
CALL FPGA_REG
LDIX 0
LDI DATA,$10
RCALL BCDE_A
PUSH WL
LDS DATA,FAT_BYTSSEC
PUSH DATA
RCALL BCDE_A
LDS DATA,FAT_KCLSDIR
DEC DATA
CP DATA,WL
BRCC RDDIRS3
POP DATA
POP DATA
POPW
SER DATA
TST DATA
RET
RDDIRS3:LDSX FAT_TEK_DIR+2
MOV DATA,WL
TST DATA
LDSW FAT_TEK_DIR+0
BREQ RDDIRS1
RDDIRS2:PUSH DATA
RCALL RDFATZP
POP DATA
DEC DATA
BRNE RDDIRS2
RDDIRS1:RCALL REALSEC
POP R0
DEC R0
POP DATA
AND DATA,R0
ADD WL,DATA
ADC WH,NULL
ADC XL,NULL
ADC XH,NULL
RCALL LOADLST
POPW
CLR DATA
RET
;
;--------------------------------------
;out: sreg.C == CLR - EOCmark
;(chng: TEMP)
LST_CLS:LDI TEMP,$0F
LDS DATA,FAT_CAL_FAT
TST DATA
BRNE LST_CL1
CPI WL,$F7
CPC WH,TEMP
RET
LST_CL1:DEC DATA
BRNE LST_CL2
CPI WL,$F7
CPC WH,FF
RET
LST_CL2:CPI WL,$F7
CPC WH,FF
CPC XL,FF
CPC XH,TEMP
RET
;
;--------------------------------------
;
RDFATZP:
LDI TEMP,SD_CS0
SER DATA
CALL FPGA_REG
LDS DATA,FAT_CAL_FAT
TST DATA
BREQ RDFATS0 ;FAT12
DEC DATA
BREQ RDFATS1 ;FAT16
;FAT32
LSL WL
ROL WH
ROL XL
ROL XH
MOV DATA,WL
MOV WL,WH
MOV WH,XL
MOV XL,XH
CLR XH
RCALL RDFATS2
ADIW ZL,1
LD XL,Z+
LD XH,Z
ANDI XH,$0F ;
RET
;FAT16
RDFATS1:LDIX 0
MOV DATA,WL
MOV WL,WH
CLR WH
RDFATS2:PUSH DATA
PUSHX
LDIZ FAT_FATSTR0
RCALL BCDEHLP
RCALL LOADLST
POPX
POP DATA
ADD ZL,DATA
ADC ZH,NULL
ADD ZL,DATA
ADC ZH,NULL
LD WL,Z+
LD WH,Z
RET
;FAT12
RDFATS0:MOVW ZL,WL
LSL ZL
ROL ZH
ADD ZL,WL
ADC ZH,WH
LSR ZH
ROR ZL
MOV DATA,WL
MOV WL,ZH
CLR WH
CLR XL
CLR XH
LSR WL
PUSH DATA
PUSHZ
LDIZ FAT_FATSTR0
RCALL BCDEHLP
PUSHW
RCALL LOADLST
POPW
POPX
ANDI XH,$01
ADD ZL,XL
ADC ZH,XH
LD XL,Z+
CPI ZH,HIGH(BUF4FAT+512)
BRNE RDFATS4
PUSH XL
LDIX 0
ADIW WL,1
RCALL LOADLST
POP XL
RDFATS4:POP DATA
LD WH,Z
MOV WL,XL
LDIX 0
LSR DATA
BRCC RDFATS3
LSR WH
ROR WL
LSR WH
ROR WL
LSR WH
ROR WL
LSR WH
ROR WL
RDFATS3:ANDI WH,$0F
RET
;
;--------------------------------------
;вычисление реального сектора
;на входе XW==номер FAT
;на выходе XW==адрес сектора
REALSEC:MOV DATA,XH
OR DATA,XL
OR DATA,WH
OR DATA,WL
BRNE REALSE1
LDIZ FAT_FATSTR1
LDSW FAT_SEC_FAT+0
LDSX FAT_SEC_FAT+2
RJMP BCDEHLP
REALSE1:SBIW WL,2 ;номер кластера-2
SBC XL,NULL
SBC XH,NULL
LDS DATA,FAT_BYTSSEC
RJMP REALSE2
REALSE3:LSL WL
ROL WH
ROL XL
ROL XH
REALSE2:LSR DATA
BRCC REALSE3
;умножили на размер кластера
LDIZ FAT_STARTRZ
RCALL BCDEHLP ;прибавили смещение от начала диска
LDIZ FAT_FRSTDAT
RJMP BCDEHLP ;прибавили смещение от начала раздела
;
;--------------------------------------
;XW>>9 (деление на 512)
BCDE200:MOV WL,WH
MOV WH,XL
MOV XL,XH
LDI XH,0
LDI DATA,1
; - - - - - - - - - - - - - - - - - - -
;XWDATA>>до"переноса"
;если в DATA вкл.только один бит, то получается
;XW=XW/DATA
BCDE_A1:LSR XH
ROR XL
ROR WH
ROR WL
BCDE_A: ROR DATA
BRCC BCDE_A1
RET
;
;--------------------------------------
;XW=[Z]-XW
BCDEHLM:LD DATA,Z+
SUB DATA,WL
MOV WL,DATA
LD DATA,Z+
SBC DATA,WH
MOV WH,DATA
LD DATA,Z+
SBC DATA,XL
MOV XL,DATA
LD DATA,Z
SBC DATA,XH
MOV XH,DATA
RET
;
;--------------------------------------
;XW=XW+[Z]
BCDEHLP:LD DATA,Z+
ADD WL,DATA
LD DATA,Z+
ADC WH,DATA
LD DATA,Z+
ADC XL,DATA
LD DATA,Z
ADC XH,DATA
RET
;
;--------------------------------------
;XW=XW+TMP3TMP2
HLDEPBC:ADD WL,TMP2
ADC WH,TMP3
ADC XL,NULL
ADC XH,NULL
RET
;
;--------------------------------------
;
RASCHET:RCALL BCDE200
LDIZ FAT_SEC_FAT
RCALL BCDEHLM
MOV DATA,WL
ANDI DATA,$F0
OR DATA,WH
OR DATA,XL
OR DATA,XH
RET
;
;--------------------------------------
;чтение очередного сектора файла в BUFFER
;out: DATA == 0 - считан последний сектор файла
NEXTSEC:
LDI TEMP,SD_CS0
SER DATA
CALL FPGA_REG
LDIZ FAT_KOL_CLS
LD DATA,Z+
LD TEMP,Z+
OR DATA,TEMP
LD TEMP,Z+
OR DATA,TEMP
LD TEMP,Z+
OR DATA,TEMP
BREQ LSTCLSF
LDSW FAT_TFILCLS+0
LDSX FAT_TFILCLS+2
RCALL REALSEC
LDS DATA,FAT_NUMSECK
ADD WL,DATA
ADC WH,NULL
ADC XL,NULL
ADC XH,NULL
RCALL LOAD_DATA
LDSW FAT_TFILCLS+0
LDSX FAT_TFILCLS+2
LDS DATA,FAT_NUMSECK
INC DATA
STS FAT_NUMSECK,DATA
LDS TEMP,FAT_BYTSSEC
CP TEMP,DATA
BRNE NEXT_OK
STS FAT_NUMSECK,NULL
RCALL RDFATZP
STSW FAT_TFILCLS+0
STSX FAT_TFILCLS+2
LDIZ FAT_KOL_CLS
LD DATA,Z
SUBI DATA,1
ST Z+,DATA
LD DATA,Z
SBC DATA,NULL
ST Z+,DATA
LD DATA,Z
SBC DATA,NULL
ST Z+,DATA
LD DATA,Z
SBC DATA,NULL
ST Z+,DATA
NEXT_OK:SER DATA
RET
LSTCLSF:LDSW FAT_TFILCLS+0
LDSX FAT_TFILCLS+2
RCALL REALSEC
LDS DATA,FAT_NUMSECK
ADD WL,DATA
ADC WH,NULL
ADC XL,NULL
ADC XH,NULL
RCALL LOAD_DATA
LDS DATA,FAT_NUMSECK
INC DATA
STS FAT_NUMSECK,DATA
LDS TEMP,FAT_MPHWOST
SUB DATA,TEMP
RET
;
;--------------------------------------
;