1 ; -*- coding: utf-8 -*-
2 ; forthMSP430FR_SD_INIT.asm
5 ; ===========================================================
6 ; ABOUT INIT SD_CARD AND HOW TO SELECT FAT16/FAT32 FORMAT
7 ; ===========================================================
8 ; FAT16/FAT32 selection is made via the ID of partition in EBP
9 ; because SD must be always FAT16 and SDHC must be always FAT32
10 ; this is automatically done when we format the SD_Card !
13 ; =====================================================================
14 ; goal : accept 64 MB up to 64 GB SD_CARD
15 ; =====================================================================
16 ; thus FAT and RootClus logical sectors are word addressable.
18 ; FAT is a little endian structure.
19 ; CMD frame is sent as big endian.
21 ; we assume that SDSC Card (up to 2GB) is FAT16 with a byte addressing
22 ; and that SDHC Card (4GB up to 64GB) is FAT32 with a sector addressing (sector = 512 bytes)
23 ; for SDHC Card = 64 GB, cluster = 64 sectors ==> max clusters = 20 0000h ==> FAT size = 16384 sectors
24 ; ==> FAT1 and FAT2 can be addressed with a single word.
26 ; ref. https://en.wikipedia.org/wiki/Extended_boot_record
27 ; ref. https://en.wikipedia.org/wiki/Partition_type
29 ; Formatage FA16 d'une SDSC Card 2GB
30 ; First sector of physical drive (sector 0) content :
31 ; ---------------------------------------------------
33 ; 446 |0x1BE : partition table first record ==> logical drive 0
34 ; 462 |0x1CE : partition table 2th record ==> logical drive 1
35 ; 478 |0x1DE : partition table 3th record ==> logical drive 2
36 ; 494 |0x1EE : partition table 4th record ==> logical drive 3
38 ; partition of first record content :
39 ; ---------------------------------------------------
40 ; 450 |0x1C2 = 0x0E : type FAT16 using LBA addressing
41 ; 454 |0x1C6 = 89 00 00 00 : FirstSector (of logical drive 0) BS_FirstSector = 137
44 ; Partition type Description
47 ; 4 FAT16 for partitions <= 32 MiB
48 ; 5 extended partition
49 ; 6 FAT16 for partitions > 32 MiB
50 ; 11 FAT32 for partitions <= 2 GiB
51 ; 12 Same as type 11 (FAT32), but using LBA addressing, which removes size constraints
52 ; 14 Same as type 6 (FAT16), but using LBA addressing
53 ; 15 Same as type 5, but using LBA addressing
54 ; ref. https://www.compuphase.com/mbr_fat.htm#BOOTSECTOR
56 ; FirstSector of logical drive (sector 0) content :
57 ; -------------------------------------------------
58 ; dec@| HEX@ = HEX decimal
59 ; 11 | 0x0B = 00 02 : 512 bytes/sector BPB_BytsPerSec = 512
60 ; 13 | 0x0D = 40 : 64 sectors/cluster BPB_SecPerClus = 64
61 ; 14 | 0x0E = 01 00 : 2 reserved sectors BPB_RsvdSecCnt = 1
62 ; 16 | 0x10 = 02 : 2 FATs BPB_NumFATs = 2 (always 2)
63 ; 17 | 0x11 = 00 02 : 512 entries/directory BPB_RootEntCnt = 512
64 ; 19 | 0x13 = 00 00 : BPB_TotSec16 (if < 65535) BPB_TotSec16 = 0
65 ; 22 | 0x16 = EB 00 : 235 sectors/FAT (FAT16) BPB_FATSize = 235
66 ; 32 | 0x20 = 77 9F 3A 00 : 3841911 total sectors BPB_TotSec32 = 3841911
67 ; 54 | 0x36 = "FAT16" BS_FilSysType (not used)
69 ; all values below are evaluated in logical sectors
70 ; FAT1 = BPB_RsvdSecCnt = 1
71 ; FAT2 = BPB_RsvdSecCnt + BPB_FATSz32 = 1 + 235 = 236
72 ; OrgRootDirL = BPB_RsvdSecCnt + (BPB_FATSize * BPB_NumFATs) = 471
73 ; RootDirSize = BPB_RootEntCnt * 32 / BPB_BytsPerSec = 32 sectors
74 ; OrgDatas = OrgRootDir + RootDirSize = 503
75 ; OrgCluster = OrgRootDir - 2*BPB_SecPerClus = 375 (virtual value)
76 ; FirstSectorOfCluster(n) = OrgCluster + n*BPB_SecPerClus ==> cluster(3) = 705
78 ; ====================================================================================
80 ; Formatage FA32 d'une SDSC Card 8GB
81 ; First sector of physical drive (sector 0) content :
82 ; ---------------------------------------------------
84 ; 446 |0x1BE : partition table first record ==> logical drive 0
85 ; 462 |0x1CE : partition table 2th record ==> logical drive 1
86 ; 478 |0x1DE : partition table 3th record ==> logical drive 2
87 ; 494 |0x1EE : partition table 4th record ==> logical drive 3
89 ; partition record content :
90 ; ---------------------------------------------------
91 ; 450 |0x1C2 = 0x0C : type FAT32 using LBA addressing
92 ; 454 |0x1C6 = 00 20 00 00 : FirstSector (of logical drive 0) = BS_FirstSector = 8192
95 ; FirstSector of logical block (sector 0) content :
96 ; -------------------------------------------------
97 ; dec@| HEX@ = HEX decimal
98 ; 11 | 0x0B = 00 02 : 512 bytes/sector BPB_BytsPerSec = 512
99 ; 13 | 0x0D = 08 : 8 sectors/cluster BPB_SecPerClus = 8
100 ; 14 | 0x0E = 20 00 : 32 reserved sectors BPB_RsvdSecCnt = 32
101 ; 16 | 0x10 = 02 : 2 FATs BPB_NumFATs = 2 (always 2)
102 ; 17 | 0x11 = 00 00 : 0 BPB_RootEntCnt = 0 (always 0 for FAT32)
104 ; 32 | 0x20 = 00 C0 EC 00 : BPB_TotSec32 BPB_TotSec32 = 15515648
105 ; 36 | 0x24 = 30 3B 00 00 : BPB_FATSz32 BPB_FATSz32 = 15152
106 ; 40 | 0x28 = 00 00 : BPB_ExtFlags BPB_ExtFlags
107 ; 44 | 0x2C = 02 00 00 00 : BPB_RootClus BPB_RootClus = 2
108 ; 48 | 0x30 = 01 00 : BPB_FSInfo BPB_FSInfo = 1
109 ; 50 | 0x33 = 06 00 : BPB_BkBootSec BPB_BkBootSec = 6
110 ; 82 | 0x52 = "FAT32" : BS_FilSysType BS_FilSysType (not used)
113 ; all values below are evaluated in logical sectors
114 ; FAT1 = BPB_RsvdSecCnt = 32
115 ; FAT2 = BPB_RsvdSecCnt + BPB_FATSz32 = 32 + 15152 = 15184
116 ; OrgRootDirL = BPB_RsvdSecCnt + BPB_FATSz32 * BPB_NumFATs = 32 + 15152*2 = 30336
117 ; OrgCluster = OrgRootDir - 2*BPB_SecPerClus = 30320
118 ; RootDirSize = BPB_RootEntCnt * 32 / BPB_BytsPerSec = 0
119 ; OrgDatas = OrgRootDir + RootDirSize = 30336
120 ; FirstSectorOfCluster(n) = OrgCluster + n*BPB_SecPerClus ==> cluster(6) = 30368
124 ; ===========================================================
125 ; Init hardware SD_Card, called by WARM
126 ; ===========================================================
127 ;-----------------------------------;
128 INI_HARD_SD CALL @PC+ ; link to previous INI_HARD_APP
129 I_H_S_PFA .word INIT_TERM ; which activates all previous I/O settings and set TOS = RSTIV_MEM.
130 ;-----------------------------------;
131 CMP #0,TOS ; RSTIV_MEM = WARM ?
132 JZ INI_SD_END ; no init if RSTIV_MEM = WARM
133 ;-----------------------------------;
134 BIT.B #CD_SD,&SD_CDIN ; SD_memory in SD_Card module ?
136 ;-----------------------------------;
137 MOV #0A981h,&SD_CTLW0 ; UCxxCTL1 = CKPH, MSB, MST, SPI_3, SMCLK + UCSWRST
138 MOV #FREQUENCY*3,&SD_BRW; UCxxBRW init SPI CLK = 333 kHz ( < 400 kHz) for SD_Card initialisation
139 BIS.B #CS_SD,&SD_CSDIR ; SD Chip Select as output high
140 BIS #BUS_SD,&SD_SEL ; Configure pins as SIMO, SOMI & SCK (PxDIR.y are controlled by eUSCI module)
141 BIC #1,&SD_CTLW0 ; release eUSCI from reset
142 ;-----------------------------------;
143 .IF RAM_LEN < 2048 ; case of MSP430FR57xx : SD datas are in FRAM not initialized by RESET.
144 MOV #SD_LEN,X ; clear all SD datas
145 ClearSDdata SUB #2,X ; 1
149 ;-----------------------------------;
151 ; ----------------------------------;
152 MOV #8,X ; send 8*8 = 64 clk on SPI
154 BIC.B #CS_SD,&SD_CSOUT ; preset Chip Select output low to switch in SPI one wire mode
155 ; ----------------------------------;
156 INIT_CMD0 ; after PUC, all SD variables area is 0 filled
157 ; ----------------------------------;
158 MOV #4,S ; preset error 4R1 for CMD0
159 MOV #95h,&SD_CMD_FRM ; $(95 00 00 00 00 00)
160 MOV #4000h,&SD_CMD_FRM+4 ; $(95 00 00 00 00 40) = CMD0
161 ; ----------------------------------;
162 SEND_CMD0 ; GO_IDLE_STATE, expected SPI_R1 response = 1 = idle state
163 ; ----------------------------------;
164 CALL #sendCommandIdleRet ;X send command, see forthMSP430FR_SD_lowLvl.asm
165 JZ INIT_CMD8 ; if idle state
167 MOV #SD_CARD_ERROR,PC ; ReturnError = $04R1, case of defectuous card (or insufficient SD_POWER_ON clk)
168 ; ----------------------------------; see forthMSP430FR_SD_lowLvl.asm
169 INIT_CMD8 ; mandatory if SD_Card >= V2.x [11:8]supply voltage(VHS)
170 ; ----------------------------------;
171 CALL #SPI_GET ; (needed to pass SanDisk ultra 8GB "HC I")
172 CMP.B #-1,W ; FFh expected value <==> MISO = high level
173 JNE INIT_CMD8 ; loop back while yet busy
174 MOV #0AA87h,&SD_CMD_FRM ; $(87 AA ...) (CRC:CHECK PATTERN)
175 MOV #1,&SD_CMD_FRM+2 ; $(87 AA 01 00 ...) (CRC:CHECK PATTERN:VHS set as 2.7to3.6V:0)
176 MOV #4800h,&SD_CMD_FRM+4 ; $(87 AA 01 00 00 48)
177 ; ----------------------------------;
178 SEND_CMD8 ; SEND_IF_COND; expected R1 response (first byte of SPI R7) = 01h : idle state
179 ; ----------------------------------;
180 CALL #sendCommandIdleRet ;X time out occurs with SD_Card V1.x (and all MMC_card)
181 ; ----------------------------------;
182 MOV #4,X ; skip end of SD_Card V2.x type R7 response (4 bytes), because useless
184 ; ----------------------------------;
185 INIT_ACMD41 ; no more CRC needed from here
186 ; ----------------------------------;
187 MOV #1,&SD_CMD_FRM ; $(01 00 ... set stop bit
188 MOV #0,&SD_CMD_FRM+2 ; $(01 00 00 00 ...
189 ; MOV.B #16,Y ; init 16 * ACMD41 repeats (power on fails with SanDisk ultra 8GB "HC I" and Transcend 2GB)
190 ; MOV.B #32,Y ; init 32 * ACMD41 repeats ==> ~400ms time out
191 MOV.B #-1,Y ; init 255 * ACMD41 repeats ==> ~3 s time out
192 MOV #8,S ; preset error 8R1 for ACMD41
193 ; ----------------------------------;
194 SEND_ACMD41 ; send CMD55+CMD41
195 ; ----------------------------------;
197 MOV #7700h,&SD_CMD_FRM+4 ; $(01 00 00 00 00 77)
198 SEND_CMD55 ; CMD55 = APP_CMD; expected SPI_R1 response = 1 : idle
199 CALL #sendCommandIdleRet ;X
200 SEND_CMD41 ; CMD41 = APP OPERATING CONDITION
201 MOV #6940h,&SD_CMD_FRM+4 ; $(01 00 00 00 40 69) (30th bit = HCS = High Capacity Support request)
202 CALL #WaitIdleBeforeSendCMD ; wait until idle (needed to pass SanDisk ultra 8GB "HC I") then send Command CMD41
203 JZ SetBLockLength ; if SD_Card ready (R1=0)
204 SUB.B #1,Y ; else decr time out delay
205 JNZ INIT_CMD55 ; then loop back while count of repeat not reached
206 JMP SD_INIT_ERROR ; ReturnError on time out : unusable card (or insufficient Vdd SD)
207 ; ----------------------------------;
208 setBLockLength ; set block = 512 bytes (buffer size), usefull only for FAT16 SD Cards
209 ; ----------------------------------;
210 ADD S,S ; preset error $10 for CMD16
211 SEND_CMD16 ; CMD16 = SET_BLOCKLEN
212 MOV #02h,&SD_CMD_FRM+2 ; $(01 00 02 00 ...)
213 MOV #5000h,&SD_CMD_FRM+4 ; $(01 00 02 00 00 50)
214 CALL #WaitIdleBeforeSendCMD ; wait until idle then send CMD16
215 JNZ SD_INIT_ERROR ; if W = R1 <> 0, ReturnError = $20R1 ; send command ko
216 ; ----------------------------------; W = R1 = 0
217 SwitchSPIhighSpeed ; end of SD init ==> SD_CLK = SMCLK
218 ; ----------------------------------;
219 BIS #1,&SD_CTLW0 ; UC Software reset
220 MOV #0,&SD_BRW ; UCxxBRW = 0 ==> SPI_CLK = MCLK
221 BIC #1,&SD_CTLW0 ; release from reset
222 ; ----------------------------------;
223 Read_EBP_FirstSector ; W=0, BS_FirstSectorHL=0
224 ; ----------------------------------;
226 CALL #readSectorWX ; read physical first sector
228 MOV 454(Y),&BS_FirstSectorL ; so, sectors become logical
229 MOV 456(Y),&BS_FirstSectorH ;
230 MOV.B 450(Y),W ; W = partition ID
231 ; ----------------------------------;
233 ; ----------------------------------;
234 MOV #1,&FATtype ; preset FAT16
236 SUB.B #6,W ; ID=06h Partition FAT16 > 32MB using CHS & LBA ?
237 JZ Read_MBR_FirstSector ; W = 0
239 SUB.B #8,W ; ID=0Eh Partition FAT16 using LBA ?
240 JZ Read_MBR_FirstSector ; W = 0
241 ; ----------------------------------;
242 MOV #2,&FATtype ; set FAT32
244 ADD.B #2,W ; ID=0Ch Partition FAT32 using LBA ?
245 JZ Read_MBR_FirstSector ; W = 0
247 ADD.B #1,W ; ID=0Bh Partition FAT32 using CHS & LBA ?
248 JZ Read_MBR_FirstSector ; W = 0
249 ADD.B #4,W ; ID=07h assigned to FAT 32 by MiniTools Partition Wizard....
250 JZ Read_MBR_FirstSector ; W = 0
253 MOV #SD_CARD_ID_ERROR,PC ; S = ReturnError = $20xx with xx = partition ID
254 ; ----------------------------------; see: https://en.wikipedia.org/wiki/Partition_type
255 Read_MBR_FirstSector ; read first logical sector
256 ; ----------------------------------; W = 0
258 CALL #readSectorWX ; ...with the good CMD17 bytes/sectors frame ! (good switch FAT16/FAT32)
259 ; ----------------------------------;
260 FATxx_SetFileSystem ;
261 ; ----------------------------------;
262 MOV.B 13(Y),&SecPerClus ;
263 MOV 14(Y),X ;3 X = BPB_RsvdSecCnt
264 MOV X,&OrgFAT1 ;3 set OrgFAT1
265 MOV 22(Y),W ; W = BPB_FATsize
266 CMP #0,W ; BPB_FATsize <> 0 ?
267 JNZ Set_FATsize ; yes
268 MOV 36(Y),W ; W = BPB_FATSz32
270 MOV W,&FATSize ; limited to 16384 sectors....
272 MOV X,&OrgFAT2 ; X = OrgFAT1 + FATsize = OrgFAT2
273 ADD W,X ; X = OrgFAT2 + FATsize = FAT16 OrgRootDir | FAT32 OrgDatas
274 CMP #2,&FATtype ; FAT32?
275 JZ FATxx_SetFileSystemNext ; yes
276 FAT16_SetRootCluster ;
277 MOV X,&OrgRootDIR ; only FAT16 use, is a sector used by ComputeClusFrstSect
278 ADD #32,X ; OrgRootDir + RootDirSize = OrgDatas
279 FATxx_SetFileSystemNext ;
280 SUB &SecPerClus,X ; OrgDatas - SecPerClus*2 = OrgClusters
281 SUB &SecPerClus,X ; no borrow expected
282 MOV X,&OrgClusters ; X = virtual cluster 0 address (clusters 0 and 1 don't exist)
283 MOV &FATtype,&DIRClusterL ; init DIRcluster as RootDIR
286 ;-----------------------------------;
288 ; ===========================================================
289 ; Init SD_Card software, called by ?ABORT|RST
290 ; ===========================================================
291 ;-----------------------------------;
292 INI_SOFT_SD ; called by INI_FORTH common part of ?ABORT|RST
293 ;-----------------------------------;
294 CALL @PC+ ; link to previous INI_FORTH_APP
295 RSAB_SD_PFA .word RET_ADR ; which does nothing
296 ;-----------------------------------;
297 MOV #HandlesLen,X ; clear all handles
298 ClearHandle SUB #2,X ; 1
299 MOV #0,FirstHandle(X) ; 3
303 ;-----------------------------------;