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/>.
23 ; all sectors are computed as logical, then physically translated at last time by RW_Sector_CMD
25 sendCommandIdleRet ; <=== CMD0, CMD8, CMD55: W = 1 = R1 expected response = idle (forthMSP430FR_SD_INIT.asm)
26 MOV #1,W ; expected R1 response (first byte of SPI R7) = 01h : idle state
29 ; in SPI mode CRC is not required, but CMD frame must be ended with a stop bit
30 ; ==================================;
31 RW_Sector_CMD ;WX <=== CMD17 or CMD24 (read or write Sector CMD)
32 ; ==================================;
33 BIC.B #SD_CS,&SD_CSOUT ; set SD_CS low
34 BIT.B #SD_CD,&SD_CDIN ; test CD: memory card present ?
35 JZ ComputePhysicalSector ; yes
36 MOV #COLD,PC ; no: force COLD
37 ; ----------------------------------;
38 ComputePhysicalSector ;
39 ; ----------------------------------; input = logical sector...
40 ADD &BS_FirstSectorL,W ;3
41 ADDC &BS_FirstSectorH,X ;3
42 ; ----------------------------------; ...output = physical sector
44 ; ----------------------------------;
45 MOV #1,&SD_CMD_FRM ;3 $(01 00 xx xx xx CMD) set stop bit in CMD frame
46 CMP #2,&FATtype ;3 FAT32 ?
48 FAT16_CMD ; FAT16 : CMD17/24 byte address = Sector * BPB_BytsPerSec
49 ADD W,W ;1 shift left one Sector
51 MOV W,&SD_CMD_FRM+2 ;3 $(01 00 ll LL xx CMD)
52 MOV.B X,&SD_CMD_FRM+4 ;3 $(01 00 ll LL hh CMD)
53 JMP WaitIdleBeforeSendCMD ;
54 FAT32_CMD ; FAT32 : CMD17/24 sector address
55 MOV.B W,&SD_CMD_FRM+1 ;3 $(01 ll xx xx xx CMD)
57 MOV.B W,&SD_CMD_FRM+2 ;3 $(01 ll LL xx xx CMD)
58 MOV.B X,&SD_CMD_FRM+3 ;3 $(01 ll LL hh xx CMD)
60 MOV.B X,&SD_CMD_FRM+4 ;3 $(01 ll LL hh HH CMD)
61 ; ==================================;
62 WaitIdleBeforeSendCMD ; <=== CMD41, CMD1, CMD16 (forthMSP430FR_SD_INIT.asm)
63 ; ==================================;
65 ADD.B #1,W ; expected value = FFh <==> MISO = 1 = not busy = idle state
66 JNE WaitIdleBeforeSendCMD ; loop back if <> FFh
67 ; ==================================; W = 0 = expected R1 response = ready, for CMD41,CMD16, CMD17, CMD24
69 ; ==================================;
70 ; input : SD_CMD_FRM : {CRC,byte_l,byte_L,byte_h,byte_H,CMD}
71 ; W = expected return value
72 ; output W is unchanged, flag Z is positionned
73 ; reverts CMD bytes before send : $(CMD hh LL ll 00 CRC)
74 MOV #5,X ; X = SD_CMD_FRM ptr AND countdown
75 ; ----------------------------------;
76 Send_CMD_PUT ; performs little endian --> big endian conversion
77 ; ----------------------------------;
78 MOV.B SD_CMD_FRM(X),&SD_TXBUF ;5
79 CMP #0,&SD_BRW ;3 full speed ?
80 JZ FullSpeedSend ;2 yes
82 BIT #UCRXIFG,&SD_IFG ;3 no: case of low speed during memCardInit
84 CMP.B #0,&SD_RXBUF ;3 to clear UCRXIFG
86 ; NOP ;0 NOPx adjusted to avoid SD error
88 JHS Send_CMD_PUT ;2 U>= : don't skip SD_CMD_FRM(0) !
90 ; host must provide height clock cycles to complete operation
91 ; here X=255, so wait for CMD return expected value with PUT FFh 256 times
93 ; MOV #4,X ; to pass made in PRC SD_Card init
94 ; MOV #16,X ; to pass Transcend SD_Card init
95 ; MOV #32,X ; to pass Panasonic SD_Card init
96 ; MOV #64,X ; to pass SanDisk SD_Card init
97 ; ----------------------------------;
98 Wait_Command_Response ; expect W = return value during X = 255 times
99 ; ----------------------------------;
101 JN SPI_WAIT_RET ;2 error on time out with flag Z = 0
102 MOV.B #-1,&SD_TXBUF ;3 PUT FFh
103 CMP #0,&SD_BRW ;3 full speed ?
104 JZ FullSpeedGET ;2 yes
105 cardResp_Getloop ; no: case of low speed during memCardInit (CMD0,CMD8,ACMD41,CMD16)
106 BIT #UCRXIFG,&SD_IFG ;3
107 JZ cardResp_Getloop ;2
109 ; NOP ; NOPx adjusted to avoid SD_error
110 CMP.B &SD_RXBUF,W ;3 return value = ExpectedValue ?
111 JNZ Wait_Command_Response ;2 16~ full speed loop
112 SPI_WAIT_RET ; flag Z = 1 <==> Returned value = expected value
113 RET ; W = expected value, unchanged
114 ; ----------------------------------;
117 ; SPI_GET and SPI_PUT are adjusted for SD_CLK = MCLK
118 ; PUT value must be a word or byte:byte because little endian to big endian conversion
120 ; ==================================;
121 SPI_GET ; PUT(FFh), output : W = received byte, X = 0
122 ; ==================================;
124 ; ==================================;
125 SPI_X_GET ; PUT(FFh) X times, output : W = last received byte, X = 0
126 ; ==================================;
127 MOV #-1,W ;1 W = FFFFh
128 ; ==================================;
129 SPI_PUT ; PUT(W) X time, output : W = last received byte, X = 0
130 ; ==================================;
132 MOV.B W,&SD_TXBUF ;3 put W high byte then W low byte and so forth, that performs little to big endian conversion
133 CMP #0,&SD_BRW ;3 full speed ?
135 SPI_PUTWAIT BIT #UCRXIFG,&SD_IFG ;3
137 CMP.B #0,&SD_RXBUF ;3 reset RX flag
139 ; NOP ; NOPx adjusted to avoid SD error
141 JNZ SPI_PUT ;2 12~ loop
142 SPI_PUT_END MOV.B &SD_RXBUF,W ;3
144 ; ----------------------------------;
146 ; ==================================;
147 readFAT1SectorW ; read a FAT1 sector
148 ; ==================================;
150 ; ==================================;
151 readSectorW ; read a logical sector < 65536
152 ; ==================================;
154 ; ==================================;
155 readSectorWX ; read a logical sector
156 ; ==================================;
157 BIS #1,S ; preset sd_read error
158 MOV.B #51h,&SD_CMD_FRM+5 ; CMD17 = READ_SINGLE_BLOCK
159 CALL #RW_Sector_CMD ; which performs logical sector to physical sector then little endian to big endian conversion
160 JNE SD_CARD_ERROR ; time out error if R1 <> 0
161 ; ----------------------------------;
162 WaitFEhResponse ; wait SD_Card response FEh
163 ; ----------------------------------;
165 ADD.B #2,W ;1 FEh expected value
166 JZ ReadSectorfirst ; 2
167 JNZ WaitFEhResponse ;
168 ; ----------------------------------;
169 ReadSectorLoop ; get 512+1 bytes, write 512 bytes in SD_BUF
170 ; ----------------------------------;
171 MOV.B &SD_RXBUF,SD_BUF-1(X) ; 5
173 MOV.B #-1,&SD_TXBUF ; 3 put FF
174 NOP ; 1 NOPx adjusted to avoid read SD_error
176 CMP #BytsPerSec+1,X ; 2
177 JNZ ReadSectorLoop ; 2 14 cycles loop read byte
178 ; ----------------------------------;
179 MOV.B #-1,&SD_TXBUF ; 3 put only one FF because first CRC byte is already received...
180 ; ----------------------------------;
181 ReadWriteHappyEnd ; <==== WriteSector
182 ; ----------------------------------;
183 BIC #3,S ; reset read and write errors
184 BIS.B #SD_CS,&SD_CSOUT ; SD_CS = high
186 ; ----------------------------------;
188 .IFDEF SD_CARD_READ_WRITE
190 ; ==================================;
191 WriteSectorW ; write a logical sector up to 65535 (FAT1,FAT2)
192 ; ==================================;
194 ; ==================================;
195 WriteSectorWX ; write a logical sector
196 ; ==================================;
197 BIS #2,S ; preset sd_write error
198 MOV.B #058h,SD_CMD_FRM+5 ; CMD24 = WRITE_SINGLE_BLOCK
199 CALL #RW_Sector_CMD ; which performs logical sector to physical sector then little endian to big endian conversions
200 JNE SD_CARD_ERROR ; ReturnError = 2
201 MOV #0FFFEh,W ; PUT FFFEh as preamble requested for sector write
202 MOV #2,X ; to put 16 bits value
203 CALL #SPI_PUT ; which performs little endian to big endian conversion
204 ; ----------------------------------;
205 WriteSectorLoop ; 11 cycles loop write, starts with X = 0
206 ; ----------------------------------;
207 MOV.B SD_BUF(X),&SD_TXBUF ; 5
208 NOP ; 1 NOPx adjusted to avoid write SD_error
210 CMP #BytsPerSec,X ; 2
211 JNZ WriteSectorLoop ; 2
212 ; ----------------------------------;
213 WriteSkipCRC16 ; CRC not used in SPI mode
214 ; ----------------------------------;
215 MOV #3,X ; PUT 2 bytes to skip CRC16
216 CALL #SPI_X_GET ; + 1 byte to get data token in W
217 ; ----------------------------------;
219 ; ----------------------------------;
220 BIC.B #0E1h,W ; apply mask for Data response
221 CMP.B #4,W ; data accepted
222 JZ ReadWriteHappyEnd ;
223 ; ----------------------------------;
225 .ENDIF ; SD_CARD_READ_WRITE
229 ; 1 = CMD17 read error
230 ; 2 = CMD24 write error
231 ; 4 = CMD0 time out (GO_IDLE_STATE)
232 ; 8 = ACMD41 time out (APP_SEND_OP_COND)
233 ; 10 = CMD16 time out (SET_BLOCKLEN)
234 ; 20 = not FAT16/FAT32 media, low byte = partition ID
236 ; low byte, if CMD R1 response : |0|7|6|5|4|3|2|1|
237 ; 1th bit = In Idle state
238 ; 2th bit = Erase reset
239 ; 3th bit = Illegal command
240 ; 4th bit = Command CRC error
241 ; 5th bit = erase sequence error
242 ; 6th bit = address error
243 ; 7th bit = parameter error
245 ; Data Response Token
246 ; Every data block written to the card will be acknowledged by a data response token.
247 ; It is one byte long and has the following format:
250 ;The meaning of the status bits is defined as follows:
251 ;'010' - Data accepted.
252 ;'101' - Data rejected due to a CRC error.
253 ;'110' - Data Rejected due to a Write Error
255 ; ----------------------------------;
256 SD_CARD_ERROR ; <=== SD_INIT errors 4,8,$10
257 ; ----------------------------------;
258 SWPB S ; High Level error in High byte
259 ADD &SD_RXBUF,S ; add SPI(GET) return value as low byte error
260 SD_CARD_ID_ERROR ; <=== SD_INIT error $20 from forthMSP430FR_SD_LowLvl.asm
261 BIS.B #SD_CS,&SD_CSOUT ; SD_CS = high
264 .byte 11,"< SD Error!" ;
265 ; ----------------------------------;
266 SD_QABORTYES ; <=== OPEN file errors from forthMSP430FR_SD_LOAD.asm
267 ; ----------------------------------;
269 SUB #2,PSP ; to avoid stack underflow crash
270 MOV #10h,&BASE ; select hex
274 .word QABORTYES ; no return...
275 ; ----------------------------------;