1 ; -*- coding: utf-8 -*-
2 ; forthMSP430FR_SD_lowLvl.asm
4 ; Copyright (C) <2017> <J.M. THOORENS>
6 ; This program is free software: you can redistribute it and/or modify
7 ; it under the terms of the GNU General Public License as published by
8 ; the Free Software Foundation, either version 3 of the License, or
9 ; (at your option) any later version.
11 ; This program is distributed in the hope that it will be useful,
12 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ; GNU General Public License for more details.
16 ; You should have received a copy of the GNU General Public License
17 ; along with this program. If not, see <http://www.gnu.org/licenses/>.
19 ; =====================================================================
20 ; goal : accept 64 MB up to 64 GB SD_CARD
21 ; =====================================================================
22 ; thus FAT and RootClus logical sectors are word addressable.
24 ; FAT is a little endian structure.
25 ; CMD frame is sent as big endian.
27 ; we assume that SDSC Card (up to 2GB) is FAT16 with a byte addressing
28 ; and that SDHC Card (4GB up to 32GB) is FAT32 with a sector addressing (sector = 512 bytes)
30 ; ref. https://en.wikipedia.org/wiki/Extended_boot_record
31 ; ref. https://en.wikipedia.org/wiki/Partition_type
33 ; Formatage FA16 d'une SDSC Card 2GB
34 ; First sector of physical drive (sector 0) content :
35 ; ---------------------------------------------------
36 ; dec@| HEX@ = HEX decimal
37 ; 446 |0x1BE : partition table first record ==> logical drive 0
38 ; 446 |0x1CE : partition table 2th record ==> logical drive 1
39 ; 446 |0x1DE : partition table 3th record ==> logical drive 2
40 ; 446 |0x1EE : partition table 4th record ==> logical drive 3
42 ; partition record content :
43 ; ---------------------------------------------------
44 ; dec@|HEX@ = HEX decimal
45 ; 0 |0x00 = 0x00 : not bootable
46 ; 1 |0x01 = 02 0C 00 : Org Cylinder/Head/Sector offset (CHS-addressing) = not used
47 ; 4 |0x04 = 0x0E : type FAT16 using LBA addressing = 14 ==> FAT16
48 ; 5 |0x05 = ED 3F EE : End Cylinder/Head/Sector offset (CHS-addressing) = not used
49 ; 8 |0x08 = 00 20 00 00 : sector offset of logical drive = 8192
50 ; 12 |0x0C = 00 40 74 00 : sector size of logical drive = 7618560 sectors
52 ; 450 |0x04 = 0x0E : type FAT16 using LBA addressing = 14 ==> set FATtype = FAT16 with byte CMD addressing
53 ; 454 |0x1C6 = 89 00 : FirstSector (of logical drive 0) BS_FirstSector = 137
56 ; ref. https://www.compuphase.com/mbr_fat.htm#BOOTSECTOR
58 ; FirstSector of logical drive (sector 0) content :
59 ; -------------------------------------------------
60 ; dec@| HEX@ = HEX decimal
61 ; 11 | 0x0B = 00 02 : 512 bytes/sector BPB_BytsPerSec = 512
62 ; 13 | 0x0D = 40 : 64 sectors/cluster BPB_SecPerClus = 64
63 ; 14 | 0x0E = 01 00 : 2 reserved sectors BPB_RsvdSecCnt = 1
64 ; 16 | 0x10 = 02 : 2 FATs BPB_NumFATs = 2 (always 2)
65 ; 17 | 0x11 = 00 02 : 512 entries/directory BPB_RootEntCnt = 512
66 ; 19 | 0x13 = 00 00 : BPB_TotSec16 (if < 65535) BPB_TotSec16 = 0
67 ; 22 | 0x16 = EB 00 : 235 sectors/FAT (FAT16) BPB_FATSize = 235
68 ; 32 | 0x20 = 77 9F 3A 00 : 3841911 total sectors BPB_TotSec32 = 3841911
69 ; 54 | 0x36 = "FAT16" BS_FilSysType (not used)
71 ; all values below are evaluated in logical sectors
72 ; FAT1 = BPB_RsvdSecCnt = 1
73 ; FAT2 = BPB_RsvdSecCnt + BPB_FATSz32 = 1 + 235 = 236
74 ; OrgRootDirL = BPB_RsvdSecCnt + (BPB_FATSize * BPB_NumFATs) = 471
75 ; RootDirSize = BPB_RootEntCnt * 32 / BPB_BytsPerSec = 32 sectors
76 ; OrgDatas = OrgRootDir + RootDirSize = 503
77 ; OrgCluster = OrgRootDir - 2*BPB_SecPerClus = 375 (virtual value)
78 ; FirstSectorOfCluster(n) = OrgCluster + n*BPB_SecPerClus ==> cluster(3) = 705
80 ; ====================================================================================
82 ; Formatage FA32 d'une SDSC Card 8GB
83 ; First sector of physical drive (sector 0) content :
84 ; ---------------------------------------------------
85 ; dec@| HEX@ = HEX decimal
86 ; 446 |0x1BE : partition table first record ==> logical block 0
87 ; 446 |0x1CE : partition table 2th record ==> logical block 1
88 ; 446 |0x1DE : partition table 3th record ==> logical block 2
89 ; 446 |0x1EE : partition table 4th record ==> logical block 3
91 ; partition record content :
92 ; ---------------------------------------------------
93 ; dec@|HEX@ = HEX decimal
94 ; 0 |0x00 = 0x00 : not bootable
95 ; 1 |0x01 = 82 03 00 : Org CHS offset (Cylinder/Head/Sector) = not used
96 ; 4 |0x04 = 0x0C : type FAT32 using LBA addressing = 12 ==> set FATtype = FAT32 with sector CMD addressing
97 ; 5 |0x05 = 82 03 00 : End offset (Cylinder/Head/Sector offset) = not used
98 ; 8 |0x08 = 00 20 00 00 : sector offset of logical block = 8192
99 ; 12 |0x0C = 00 40 74 00 : sector size of logical block = 7618560
101 ; 454 |0x1C6 = 00 20 00 00 : FirstSector (of logical drive 0) BS_FirstSector = 8192
104 ; FirstSector of logical block (sector 0) content :
105 ; -------------------------------------------------
106 ; dec@| HEX@ = HEX decimal
107 ; 11 | 0x0B = 00 02 : 512 bytes/sector BPB_BytsPerSec = 512
108 ; 13 | 0x0D = 08 : 8 sectors/cluster BPB_SecPerClus = 8
109 ; 14 | 0x0E = 20 00 : 32 reserved sectors BPB_RsvdSecCnt = 32
110 ; 16 | 0x10 = 02 : 2 FATs BPB_NumFATs = 2 (always 2)
111 ; 17 | 0x11 = 00 00 : 0 BPB_RootEntCnt = 0 (always 0 for FAT32)
113 ; 32 | 0x20 = 00 C0 EC 00 : BPB_TotSec32 BPB_TotSec32 = 15515648
114 ; 36 | 0x24 = 30 3B 00 00 : BPB_FATSz32 BPB_FATSz32 = 15152
115 ; 40 | 0x28 = 00 00 : BPB_ExtFlags BPB_ExtFlags
116 ; 44 | 0x2C = 02 00 00 00 : BPB_RootClus BPB_RootClus = 2
117 ; 48 | 0x30 = 01 00 : BPB_FSInfo BPB_FSInfo = 1
118 ; 50 | 0x33 = 06 00 : BPB_BkBootSec BPB_BkBootSec = 6
119 ; 82 | 0x52 = "FAT32" : BS_FilSysType BS_FilSysType (not used)
122 ; all values below are evaluated in sectors
123 ; FAT1 = BS_FirstSector + BPB_RsvdSecCnt = 8192 + 32 = 8224
124 ; FAT2 = BS_FirstSector + BPB_RsvdSecCnt + BPB_FATSz32 = 8192 + 32 + 15152 = 23376
125 ; OrgRootDirL = BS_FirstSector + BPB_RsvdSecCnt + (BPB_FATSz32 * BPB_NumFATs) = 8192 + 32 + 15152*2 = 38528
126 ; OrgCluster = OrgRootDir - 2*BPB_SecPerClus = 38512
127 ; RootDirSize = BPB_RootEntCnt * 32 / BPB_BytsPerSec = 0
128 ; OrgDatas = OrgRootDir + RootDirSize = 38512
129 ; FirstSectorOfCluster(n) = OrgCluster + n*BPB_SecPerClus ==> cluster(6) = 38560
135 ; all sectors are computed as logical, then physically translated at last time by RW_Sector_CMD
137 ; in SPI mode CRC is not required, but CMD frame must be ended with a stop bit
138 ; ==================================;
139 RW_Sector_CMD ;WX <=== CMD17 or CMD24 (read or write Sector CMD)
140 ; ==================================;
141 BIC.B #SD_CS,&SD_CSOUT ; SD_CS low
142 BIT.B #SD_CD,&SD_CDIN ; memory card present ?
143 JZ ComputePhysicalSector ; yes
144 MOV #COLD,PC ; no: force COLD
145 ; ----------------------------------;
146 ComputePhysicalSector ;
147 ; ----------------------------------;
148 ADD &BS_FirstSectorL,W ;3
149 ADDC &BS_FirstSectorH,X ;3
150 ; ----------------------------------;
151 MOV #1,&SD_CMD_FRM ;3 $(01 00 xx xx xx CMD) (set stop bit)
152 CMP #2,&FATtype ;3 FAT32 ?
154 FAT16_CMD ; FAT16 : CMD17/24 byte address = Sector * BPB_BytsPerSec
155 ADD W,W ; shift left one SectorL
157 MOV W,&SD_CMD_FRM+2 ; $(01 00 ll LL xx CMD)
158 MOV.B X,&SD_CMD_FRM+4 ; $(01 00 ll LL hh CMD)
160 FAT32_CMD ; FAT32 : CMD17/24 sector address
161 MOV.B W,&SD_CMD_FRM+1 ;3 $(01 ll xx xx xx CMD)
163 MOV.B W,&SD_CMD_FRM+2 ;3 $(01 ll LL xx xx CMD)
164 MOV.B X,&SD_CMD_FRM+3 ;3 $(01 ll LL hh xx CMD)
166 MOV.B X,&SD_CMD_FRM+4 ;3 $(01 ll LL hh HH CMD)
167 ; ==================================;
168 SDbusyLoop ; <=== CMD41, CMD1, CMD16 (R1 expected response = 0 = ready)
169 ; ==================================;
171 CMP.B #-1,W ; FFh expected value <==> MISO = 1 = not busy
172 JNE SDbusyLoop ; loop back while yet busy
173 MOV #0,W ; W = expected R1 response = ready = 0, for CMD41, CMD1, CMD16, CMD17, CMD24
175 ; ==================================;
176 sendCommand ;X <=== CMD0, CMD8, CMD55 (W = R1 expected response = 1 = idle)
177 ; ==================================;
178 ; input : SD_CMD_FRM : {CRC,byte_l,byte_L,byte_h,byte_H,CMD}
179 ; W = expected return value
180 ; output W is unchanged, flag Z is positionned
181 ; reverts CMD bytes before send : $(CMD hh LL ll 00 CRC)
182 MOV #5,X ; X = SD_CMD_FRM index AND countdown
183 ; ----------------------------------;
184 Send_CMD_PUT ; performs little endian --> big endian conversion
185 ; ----------------------------------;
186 MOV.B SD_CMD_FRM(X),&SD_TXBUF ;5
187 CMP #0,&SD_BRW ;3 full speed ?
188 JZ FullSpeedSend ;2 yes
189 Send_CMD_Loop ; no: case of low speed during memCardInit
190 BIT #UCRXIFG,&SD_IFG ;3
192 CMP.B #0,&SD_RXBUF ;3 to clear UCRXIFG
194 ; NOP ;0 NOPx adjusted to avoid SD error
196 JHS Send_CMD_PUT ;2 U>= : don't skip SD_CMD_FRM(0) !
198 ; host must provide height clock cycles to complete operation
199 ; here X=255, so wait for CMD return expected value with PUT FFh 256 times
201 ; MOV #4,X ; to pass made in PRC SD_Card init
202 ; MOV #16,X ; to pass Transcend SD_Card init
203 ; MOV #32,X ; to pass Panasonic SD_Card init
204 ; MOV #64,X ; to pass SanDisk SD_Card init
205 ; MOV #1000,X ; max value
206 ; ----------------------------------;
207 Wait_Command_Response ; expect W = return value during X = 255 delay time
208 ; ----------------------------------;
210 JN SPI_WAIT_RET ;2 error on time out with SR(Z) = 0
211 MOV.B #-1,&SD_TXBUF ;3 PUT FFh
212 CMP #0,&SD_BRW ;3 full speed ?
213 JZ FullSpeedGET ;2 yes
214 cardResp_Getloop ; no: case of low speed during memCardInit
215 BIT #UCRXIFG,&SD_IFG ;3
216 JZ cardResp_Getloop ;2
218 ; NOP2 ;2 NOPx adjusted to avoid SD_error
219 CMP.B &SD_RXBUF,W ;3 return value = ExpectedValue ?
220 JNZ Wait_Command_Response ;2
221 SPI_WAIT_RET ; SR(Z) = 1 <==> Return value = expected value
222 RET ; expected value = W is unchanged
223 ; ----------------------------------;
226 ; SPI_GET and SPI_PUT are adjusted for SD_CLK = MCLK
227 ; PUT value must be a word or byte:byte because little endian to big endian conversion
229 ; ==================================;
231 ; ==================================; output : W = received byte, X = 0 always
233 ; ==================================;
234 SPI_X_GET ; PUT(FFh) X time
235 ; ==================================; output : W = last received byte, X = 0
237 ; ==================================;
238 SPI_PUT ; PUT(W) X time
239 ; ==================================; output : W = last received byte, X = 0
241 MOV.B W,&SD_TXBUF ;3 put W high byte then W low byte and so forth that performs little to big endian conversion
242 CMP #0,&SD_BRW ;3 full speed ?
244 SPI_PUTWAIT BIT #UCRXIFG,&SD_IFG ;3
246 CMP.B #0,&SD_RXBUF ;3 reset RX flag
248 ; NOP ;0 NOPx adjusted to avoid SD error
251 SPI_PUT_END MOV.B &SD_RXBUF,W ;3
253 ; ----------------------------------;
255 ; ==================================;
256 readFAT1SectorW ; read a FAT1 sector
257 ; ==================================;
259 ; ==================================;
260 readSectorW ; read a logical sector up to 65535 (case of FAT1,FAT2,RootDIR)
261 ; ==================================;
263 ; ==================================;
264 readSectorWX ; read a logical sector
265 ; ==================================;
266 BIS #1,S ; preset sd_read error
267 MOV.B #51h,&SD_CMD_FRM+5 ; CMD17 = READ_SINGLE_BLOCK
268 CALL #RW_Sector_CMD ; which performs logical sector to physical sector then little endian to big endian conversions
269 JNE SD_CARD_ERROR ; time out error if R1 <> 0
270 ; ----------------------------------;
271 WaitFEhResponse ; wait SD_Card response FEh
272 ; ----------------------------------;
274 CMP.B #-2,W ; FEh expected value
275 JNZ WaitFEhResponse ;
276 ; ----------------------------------;
277 ReadSectorLoop ; 16 cycles loop read byte, starts with X = 0
278 ; ----------------------------------;
279 MOV.B #-1,&SD_TXBUF ; 3 put FF
280 NOP3 ; 3 NOPx adjusted to avoid read SD_error
282 CMP #BytsPerSec,X ; 2
283 MOV.B &SD_RXBUF,BUFFER-1(X) ; 5
284 JNZ ReadSectorLoop ; 2
285 ; ----------------------------------;
286 ReadSkipCRC16 ; not used in SPI mode
287 ; ----------------------------------;
290 ; ----------------------------------;
292 ; ----------------------------------;
293 BIC #3,S ; reset read and write errors
294 BIS.B #SD_CS,&SD_CSOUT ; SD_CS = high
296 ; ----------------------------------;
298 .IFDEF SD_CARD_READ_WRITE
300 ; ==================================;
301 WriteSectorW ; write a logical sector up to 65535 (FAT1,FAT2,RootDIR)
302 ; ==================================;
304 ; ==================================;
305 WriteSectorWX ; write a logical sector
306 ; ==================================;
307 BIS #2,S ; preset sd_write error
308 MOV.B #058h,SD_CMD_FRM+5 ; CMD24 = WRITE_SINGLE_BLOCK
309 CALL #RW_Sector_CMD ; which performs logical sector to physical sector then little endian to big endian conversions
310 JNE SD_CARD_ERROR ; ReturnError = 2
311 MOV #0FFFEh,W ; PUT FFFEh as preamble requested for sector write
312 MOV #2,X ; to put 16 bits value
313 CALL #SPI_PUT ; which performs little endian to big endian conversion
314 ; ----------------------------------;
315 WriteSectorLoop ; 11 cycles loop write, starts with X = 0
316 ; ----------------------------------;
317 MOV.B BUFFER(X),&SD_TXBUF ; 5
318 NOP ; 1 NOPx adjusted to avoid write SD_error
320 CMP #BytsPerSec,X ; 2
321 JNZ WriteSectorLoop ; 2
322 ; ----------------------------------;
323 WriteSkipCRC16 ; not used in SPI mode
324 ; ----------------------------------;
325 MOV #3,X ; PUT 2 bytes to skip CRC16
326 CALL #SPI_X_GET ; + 1 byte to get data token in W
327 ; ----------------------------------;
329 ; ----------------------------------;
330 BIC.B #0E1h,W ; apply mask for Data response
331 CMP.B #4,W ; data accepted
332 JZ ReadWriteHappyEnd ;
333 ; ----------------------------------;
335 .ENDIF ; SD_CARD_READ_WRITE
339 ; 1 = CMD17 read error
340 ; 2 = CMD24 write error
341 ; 4 = CMD0 time out (GO_IDLE_STATE)
342 ; 8 = CMD1 time out (SEND_OP_COND), reserved for MMC_Card
343 ; 10 = ACMD41 time out (APP_SEND_OP_COND)
344 ; 20 = CMD16 time out (SET_BLOCKLEN)
345 ; 40 = not FAT16/FAT32 media, low byte = partition ID
347 ; low byte, if CMD R1 response : |0|7|6|5|4|3|2|1|
348 ; 1th bit = In Idle state
349 ; 2th bit = Erase reset
350 ; 3th bit = Illegal command
351 ; 4th bit = Command CRC error
352 ; 5th bit = erase sequence error
353 ; 6th bit = address error
354 ; 7th bit = parameter error
356 ; ----------------------------------;
357 SD_CARD_ERROR ; <=== SD_INIT errors 4,8,10,20,40
358 ; ----------------------------------;
359 BIS.B #SD_CS,&SD_CSOUT ; SD_CS = high
360 SWPB S ; High Level error in High byte
361 ADD &SD_RXBUF,S ; add SPI(GET) return value to high level error
364 .byte 11,"< SD Error!" ;
365 ; ----------------------------------;
366 SD_QABORTYES ; <=== OPEN/READ and WRITE errors
367 ; ----------------------------------;
372 MOV #10h,&BASE ; select hex
376 .word FBASE,STORE ; restore base
378 ; ----------------------------------;