-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathswd-bb.fs
229 lines (182 loc) · 4.46 KB
/
swd-bb.fs
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
\ SWD-BB
\ bitbang swd protocol for NRF52
\ (C) Copyright 2018 by juju2013@github
\ under BSD 2-Clause License, see LICENSE
\ This implement ( a subset of ) the ARM Cortex's SWD protocol
\ using big-banging on a stm32f103 ( bluepill ) board.
\ The final word Factory is used to do a mass_erase on a nRF52832 chip
\ Requires some files from jeelabs' embello libraries
\ https://github.com/jeelabs/embello :
\ clock.fs
\ hexdump.fs
\ io.fs
\ pins64.fs
compiletoram
\ --- PIN definitions
PB13 constant DAT \ DATA pin
PB14 constant CLK \ CLOCK pin
PB15 constant RST \ RESET pin (for DEBUG only, not part of SWD protocol)
PB9 constant DBG \ DEBUG pin (for DEBUG only, not part of SWD protocol)
0 constant AP
1 constant DAP
500 constant sw.delay \ adjust this for fewer/faster or more/slower protocole speed
\ SWD request constants
0 constant DP-DAP
6 bit constant DP-AP
0 constant DP-WRITE
5 bit constant DP-READ
\ Global parity calculation
0 variable parity
: parity? ( -- c ) \ return 0 or 1
parity @ 1 and
;
: >parity ( u -- ) \ Add 1 bit to parity
0 bit and parity @ + parity !
;
: c>parity ( u -- ) \ Add 1 byte to parity
0 parity !
8 0 do dup i bit and if 1 >parity then loop
drop parity?
;
: .revadr ( addr -- rdda ) \ inverse address bits in swd request
dup %01 = if %10 else
dup %10 = if %01 else
dup
then then
swap drop
;
: dpreq ( DAP/AP READ/XRITE Addr -- u ) \ caculate dp request value
.revadr 3 lshift swap + swap + dup c>parity 2 lshift + 7 bit + 1+
;
: sw.half ( -- ) \ half-cycle timing delay for SW
sw.DELAY 0 do loop inline
;
: tic
sw.half CLK ios! inline
\ begin CLK io@ until inline \ clock stretching to finish
;
: tac CLK ioc! sw.half inline
;
: b>sw ( f -- ) \ send one SWD bit
0<> DAT io! tic sw.half tac
;
: sw>b ( -- f ) \ receive one swd bit
tic sw.half tac DAT io@ \ latch at failling edge
;
: idle 0 b>sw ;
: >sw ( c -- ) \ send a byte to swd (MSB)
RST iox! RST iox!
DAT ios!
0 7 do dup i bit and b>sw -1 +loop
drop
;
: trn sw.half tic sw.half tac ; \ turnover
: epilog ( -- ) \ finishing transaction
OMODE-pp DAT IO-MODE!
8 0 do idle loop
;
: sw? ( f -- ) \ print sw response status
dup %100 and if ." FAULT"
else dup %010 and if ." WAIT"
else dup %001 and if ." OK"
else dup ." ???" dup binary . decimal
then then then
drop
;
: ack? ( -- u ) \ read ack response
DBG iox!
IMODE-FLOAT DAT IO-MODE!
DBG iox!
0 3 0 do sw>b if i bit or then loop \ ack/nak
;
: 32sw> ( -- u ) \ read 32 bit LSB data
0 parity !
0 32 0 do sw>b dup >parity if i bit or then loop \ result
sw>b drop \ ignore parity error
;
: sw.get ( reg -- ack val ) \ read SW register
>sw ack?
dup %001 = if
32sw>
else
$DEADBEEF
then
epilog
;
: >sw32 ( u -- ) \ write 32 bit LSB data
0 parity !
32 0 do dup i bit and if 1 else 0 then dup >parity b>sw loop
parity? b>sw
epilog drop
;
: sw.set ( val reg -- ack ) \ write value to register
>sw ack? dup %001 = if
trn trn OMODE-pp DAT IO-MODE!
swap dup ." sw.set " hex. ." " DBG iox! >sw32
then
epilog
;
\ Mimics some JLINK commands
: dap.get ( reg -- val flag )
DP-READ DP-DAP rot dpreq sw.get
;
: ap.get ( reg -- val flag )
DP-READ DP-AP rot dpreq sw.get
;
: dap.set ( val reg -- flag )
DP-DAP DP-WRITE rot dpreq sw.set
;
: ap.set ( val reg -- flag )
DP-AP DP-WRITE rot dpreq sw.set
;
: sw.reset DAT ios! 50 0 do tic sw.half tac loop idle idle ;
: swd-init
OMODE-FAST DAT io-mode!
OMODE-FAST CLK io-mode!
OMODE-FAST DBG io-mode!
OMODE-pp DAT IO-MODE!
OMODE-pp CLK IO-MODE!
OMODE-pp RST IO-MODE!
OMODE-pp DBG IO-MODE!
72Mhz
1000 systick-hz
sw.reset $79 >sw $E7 >sw sw.reset
8 0 do idle loop
10 ms
DP-DAP DP-READ 0 dpreq sw.get hex. sw?
cr
;
: init
swd-init 10 ms
RST iox!
cr
." CTL/STAT=" %01 dap.get hex. sw?
10 ms cr
;
\ do a mass_erase, clear the protection bits and ALL flash/ram contents
: Factory
RST iox!
." write DP 1 $50000000="
$50000000 1 dap.set sw? cr
." write DP 2 $01000000="
$01000000 2 dap.set sw? cr
." write AP 1 $00000001="
$00000001 1 ap.set sw? cr
100 ms
." CTRL-AP="
2 dap.get hex. sw? cr
." CTRL-AP2="
2 dap.get hex. sw? cr
." write AP 0 0$01"
1 0 ap.set sw? cr
." write AP 0 0$00"
0 0 ap.set sw? cr
." write AP 1 0$00"
0 1 ap.set sw? cr
." APPROTECT="
3 ap.get hex. sw? cr
." APPROTECT2="
3 ap.get hex. sw? cr
;
\ to do a mass_erase, un comment next line
\ init Factory