-
Notifications
You must be signed in to change notification settings - Fork 0
/
forthMSP430FR_SD_LowLvl.asm
262 lines (247 loc) · 12.2 KB
/
forthMSP430FR_SD_LowLvl.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
; -*- coding: utf-8 -*-
; forthMSP430FR_SD_lowLvl.asm
BytsPerSec .equ 512
; all sectors are computed as logical, then physically translated at last time by RW_Sector_CMD
; in SPI mode CRC is not required, but CMD frame must be ended with a stop bit
; ==================================;
RW_Sector_CMD ;WX <=== CMD17 or CMD24 (read or write Sector CMD)
; ==================================;
BIC.B #CS_SD,&SD_CSOUT ; set Chip Select low
; ----------------------------------;
;ComputePhysicalSector ; input = logical sector...
; ----------------------------------;
ADD &BS_FirstSectorL,W ;3
ADDC &BS_FirstSectorH,X ;3
; ----------------------------------; ...output = physical sector
;Compute CMD ;
; ----------------------------------;
MOV #1,&SD_CMD_FRM ;3 $(01 00 xx xx xx CMD) set stop bit in CMD frame
FAT32_CMD ; FAT32 : CMD17/24 sector address
MOV.B W,&SD_CMD_FRM+1 ;3 $(01 ll xx xx xx CMD)
SWPB W ;1
MOV.B W,&SD_CMD_FRM+2 ;3 $(01 ll LL xx xx CMD)
MOV.B X,&SD_CMD_FRM+3 ;3 $(01 ll LL hh xx CMD)
SWPB X ;1
MOV.B X,&SD_CMD_FRM+4 ;3 $(01 ll LL hh HH CMD)
; ==================================;
WaitIdleBeforeSendCMD ; <=== CMD41, CMD1, CMD16 (forthMSP430FR_SD_INIT.asm)
; ==================================;
CALL #SPI_GET ;
ADD.B #1,W ; expected value = FFh <==> MISO = 1 = SPI idle state
JNZ WaitIdleBeforeSendCMD ; loop back if <> FFh
; ==================================; W = 0 = expected R1 response = ready, for CMD41,CMD16, CMD17, CMD24
sendCommand ;
; ==================================;
; input : SD_CMD_FRM : {CRC,byte_l,byte_L,byte_h,byte_H,CMD}
; W = expected return value
; output W is unchanged, flag Z is positionned
; reverts CMD bytes before send : $(CMD hh LL ll 00 CRC)
MOV #5,X ; X = SD_CMD_FRM ptr AND countdown
; ----------------------------------;
Send_CMD_PUT ; performs little endian --> big endian conversion
; ----------------------------------;
MOV.B SD_CMD_FRM(X),&SD_TXBUF ;5
CMP #0,&SD_BRW ;3 full speed ?
JZ FullSpeedSend ;2 yes
Send_CMD_Loop ; case of low speed during memCardInit
BIT #RX_SD,&SD_IFG ;3
JZ Send_CMD_Loop ;2
CMP.B #0,&SD_RXBUF ;3 to clear UCRXIFG
FullSpeedSend ;
; NOP ;0 NOPx adjusted to avoid SD error
SUB.B #1,X ;1
JC Send_CMD_PUT ;2 U>= : don't skip SD_CMD_FRM(0) !
; host must provide height clock cycles to complete operation
; here X=255, so wait for CMD return expected value with PUT FFh 256 times
; MOV #4,X ; to pass made in PRC SD_Card init
; MOV #16,X ; to pass Transcend SD_Card init
; MOV #32,X ; to pass Panasonic SD_Card init
; MOV #64,X ; to pass SanDisk SD_Card init
; ----------------------------------;
Wait_Command_Response ; expect W = return value during X = 255 times
; ----------------------------------;
SUB #1,X ;1
JN SPI_WAIT_RET ;2 error on time out with flag Z = 0
MOV.B #-1,&SD_TXBUF ;3 PUT FFh
CMP #0,&SD_BRW ;3 full speed ?
JZ FullSpeedGET ;2 yes
cardResp_Getloop ; case of low speed during memCardInit (CMD0,CMD8,ACMD41,CMD16)
BIT #RX_SD,&SD_IFG ;3
JZ cardResp_Getloop ;2
FullSpeedGET ;
; NOP ; NOPx adjusted to avoid SD_error
CMP.B &SD_RXBUF,W ;3 return value = ExpectedValue ?
JNZ Wait_Command_Response ;2 16~ full speed loop
SPI_WAIT_RET ; flag Z = 1 <==> Returned value = expected value
MOV @RSP+,PC ; W = expected value, unchanged
; ----------------------------------;
; ----------------------------------;
sendCommandIdleRet ; <=== CMD0, CMD8, CMD55: W = 1 = R1 expected response = idle (forthMSP430FR_SD_INIT.asm)
; ----------------------------------;
MOV #1,W ; expected R1 response (first byte of SPI R7) = 01h : idle state
JMP sendCommand ;
; ----------------------------------;
; SPI_GET and SPI_PUT are adjusted for SD_CLK = MCLK
; PUT value must be a word or byte:byte because little endian to big endian conversion
; ==================================;
SPI_GET ; PUT(FFh) one time, output : W = received byte, X = 0
; ==================================;
MOV #1,X ;
; ==================================;
SPI_X_GET ; PUT(FFh) X times, output : W = last received byte, X = 0
; ==================================;
MOV #-1,W ;
; ==================================;
SPI_PUT ; PUT(W) X times, output : W = last received byte, X = 0
; ==================================;
SWPB W ;1
MOV.B W,&SD_TXBUF ;3 put W high byte then W low byte and so forth, that performs little to big endian conversion
CMP #0,&SD_BRW ;3 full speed ?
JZ FullSpeedPut ;2
SPI_PUTWAIT BIT #RX_SD,&SD_IFG ;3
JZ SPI_PUTWAIT ;2
CMP.B #0,&SD_RXBUF ;3 reset RX flag
FullSpeedPut
; NOP ; NOPx adjusted to avoid SD error
SUB #1,X ;1
JNZ SPI_PUT ;2 12~ loop
SPI_PUT_END MOV.B &SD_RXBUF,W ;3
MOV @RSP+,PC ;4
; ----------------------------------;
.IFDEF SD_CARD_READ_WRITE
ASMWORD "RD_SECT" ; ReaD SECTor W=lo, X=Hi
.ENDIF ; SD_CARD_READ_WRITE
; ==================================;
ReadSectorWX ; SWX read a logical sector
; ==================================;
BIS #1,S ; preset sd_read error
MOV.B #51h,&SD_CMD_FRM+5 ; CMD17 = READ_SINGLE_BLOCK
CALL #RW_Sector_CMD ; which performs logical sector to physical sector then little endian to big endian conversion
JNE SD_CARD_ERROR ; time out error if R1 <> 0
; ----------------------------------;
WaitFEhResponse ; wait for SD_Card response = FEh
; ----------------------------------;
CALL #SPI_GET ;
ADD.B #2,W ;1 W = 0 ?
JZ ReadSectorFirstByte ;2 yes, X = 0
JNZ WaitFEhResponse ;2
; ----------------------------------;
ReadSectorLoop ; get 512 bytes + CRC16 in SD_BUF
; ----------------------------------;
MOV.B &SD_RXBUF,SD_BUF-1(X) ; 5
ReadSectorFirstByte ; W=0
MOV.B #-1,&SD_TXBUF ; 3 put FF
NOP ; 1 NOPx adjusted to avoid read SD_error
ADD #1,X ; 1
CMP #BytsPerSec+3,X ; 2
JNZ ReadSectorLoop ; 2 14 cycles loop read byte
; ----------------------------------;
ReadWriteHappyEnd ; <==== WriteSector
; ----------------------------------;
BIC #3,S ; Clear read and write errors
BIS.B #CS_SD,&SD_CSOUT ; Chip Select high
MOV @RSP+,PC ; W = 0 SR(Z) = 1
; ----------------------------------;
.IFDEF SD_CARD_READ_WRITE
ASMWORD "WR_SECT" ; WRite SECTor W=lo, X=Hi
; ==================================;
WriteSectorWX ; write a logical sector
; ==================================;
BIS #2,S ; preset sd_write error
MOV.B #058h,SD_CMD_FRM+5 ; CMD24 = WRITE_SINGLE_BLOCK
CALL #RW_Sector_CMD ; which performs logical sector to physical sector then little endian to big endian conversions
JNE SD_CARD_ERROR ; ReturnError = 2
MOV #0FFFEh,W ; PUT FFFEh as preamble requested for sector write
MOV #2,X ; to put 16 bits value
CALL #SPI_PUT ; which performs little endian to big endian conversion
; ----------------------------------;
WriteSectorLoop ; 11 cycles loop write, starts with X = 0
; ----------------------------------;
MOV.B SD_BUF(X),&SD_TXBUF ; 5
NOP ; 1 NOPx adjusted to avoid write SD_error
ADD #1,X ; 1
CMP #BytsPerSec,X ; 2
JNZ WriteSectorLoop ; 2
; ----------------------------------;
;WriteSkipCRC16 ; CRC16 not used in SPI mode
; ----------------------------------;
MOV #3,X ; PUT 3 times to skip CRC16
CALL #SPI_X_GET ; and to get data token in W
; ----------------------------------;
;CheckWriteState ;
; ----------------------------------;
BIC.B #0E1h,W ; apply mask for Data response
SUB.B #4,W ; data accepted
JZ ReadWriteHappyEnd ;
; ----------------------------------;
.ENDIF ; SD_CARD_READ_WRITE
; ----------------------------------;
; SD ERRORS
; ----------------------------------;
; 0 = NO SD_CARD
; ----------------------------------;
;
; ----------------------------------;
; High byte = 0 : FILE level error
; ----------------------------------;
; low byte
; $1 = PathNameNotFound
; $2 = NoSuchFile
; $4 = alreadyOpen
; $8 = NomoreHandle
; $10 = InvalidPathname
; $20 = DiskFull
;
; ----------------------------------;
; High byte <> 0 : SD_CARD level error
; ----------------------------------;
; 1 = CMD17 read error
; 2 = CMD24 write error
; 4 = CMD0 time out (GO_IDLE_STATE)
; 8 = ACMD41 time out (APP_SEND_OP_COND)
; $10 = partition error, low byte = partition ID <> FAT32
;
; low byte, if CMD R1 response:
; bit0 = In Idle state
; bit1 = Erase reset
; bit2 = Illegal command
; bit3 = Command CRC error
; bit4 = erase sequence error
; bit5 = address error
; bit6 = parameter error
; low byte if Data Response Token
; Every data block written to the card will be acknowledged by a data response token.
; It is one byte long and has the following format:
; %xxxx_sss0 with bits(3-1) = Status
; The meaning of the status bits is defined as follows:
; '010' - Data accepted.
; '101' - Data rejected due to a CRC error.
; '110' - Data Rejected due to a Write Error
; ------------------------------;
SD_CARD_ERROR ; <=== SD_INIT errors 4,8,$10 from forthMSP430FR_SD_INIT.asm
; ------------------------------;
SWPB S ; High Level error in High byte
BIS &SD_RXBUF,S ; add SPI(GET) return value as low byte error
SD_CARD_INIT_ERROR ; <=== from forthMSP430FR_SD_INIT.asm
SD_CARD_FILE_ERROR ; <=== from forthMSP430FR_SD_LOAD.asm, forthMSP430FR_SD_RW.asm
NO_SD_CARD ; from forthMSP430FR_SD_LOAD(Open_File)
MOV S,TOS ;
CALL #ABORT_TERM+4 ;
CALL #INIT_FORTH ;
.IFDEF BOOTLOADER ;
.word NOBOOT ;
.ENDIF
.word ECHO ;
.word XSQUOTE ;
.byte 4,27,"[7m" ;
.word TYPE ;
.word XSQUOTE ;
.byte 10,"SD_ERROR $" ;
.word TYPE ;
.word LIT,10h ;
.word LIT,BASEADR,STORE;
.word UDOT ;
.word LIT,10 ;
.word LIT,BASEADR,STORE;
.word BRAN,SDABORT_END; to set normal video display then goto ABORT
; ------------------------------;