-
-
Notifications
You must be signed in to change notification settings - Fork 14
/
openocd-on-raspberry-pi-better-with-swd-on-spi.html
1306 lines (1181 loc) · 86.2 KB
/
openocd-on-raspberry-pi-better-with-swd-on-spi.html
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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" type="text/css" href="/_static/css/banner-styles.css?v=bsmaklHF" />
<link rel="stylesheet" type="text/css" href="/_static/css/iconochive.css?v=qtvMKcIJ" />
<link rel="canonical" href="https://lupyuen.org/articles/openocd-on-raspberry-pi-better-with-swd-on-spi.html" />
<!-- End Wayback Rewrite JS Include -->
<title data-rh="true">OpenOCD on Raspberry Pi: Better with SWD on SPI | by Lup Yuen Lee 李立源 | Medium</title>
<meta data-rh="true" charset="utf-8" />
<meta data-rh="true" name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />
<meta data-rh="true" name="theme-color" content="#000000" />
<meta data-rh="true" property="og:type" content="article" />
<meta data-rh="true" property="article:published_time" content="2020-12-11T12:54:05.157Z" />
<meta data-rh="true" name="title"
content="OpenOCD on Raspberry Pi: Better with SWD on SPI | by Lup Yuen Lee 李立源 | Medium" />
<meta data-rh="true" property="og:title" content="OpenOCD on Raspberry Pi: Better with SWD on SPI" />
<meta data-rh="true" property="twitter:title" content="OpenOCD on Raspberry Pi: Better with SWD on SPI" />
<meta data-rh="true" name="description"
content="The setup that we see above… Debugging nRF52 with a Raspberry Pi running VSCode and OpenOCD… Was impossible just a week ago! OpenOCD connects to nRF52 for flashing and debugging by running Arm’s SWD…" />
<meta data-rh="true" property="og:description" content="Sneaky tricks to align stray bits into proper bytes" />
<meta data-rh="true" property="twitter:description" content="Sneaky tricks to align stray bits into proper bytes" />
<meta data-rh="true" name="twitter:card" content="summary_large_image" />
<meta data-rh="true" name="twitter:creator" content="@MisterTechBlog" />
<meta data-rh="true" name="author" content="Lup Yuen Lee 李立源" />
<meta data-rh="true" name="robots" content="index,follow,max-image-preview:large" />
<meta data-rh="true" name="referrer" content="unsafe-url" />
<meta data-rh="true" name="twitter:label1" value="Reading time" />
<meta data-rh="true" name="twitter:data1" value="14 min read" />
<meta property="og:image"
content="https://lupyuen.github.io/images/legacy/d1.jpeg">
<!-- Begin scripts/rustdoc-header.html: Header for Custom Markdown files processed by rustdoc, like chip8.md -->
<link rel="alternate" type="application/rss+xml" title="RSS Feed for lupyuen" href="/rss.xml" />
<link rel="stylesheet" type="text/css" href="../normalize.css">
<link rel="stylesheet" type="text/css" href="../rustdoc.css" id="mainThemeStyle">
<link rel="stylesheet" type="text/css" href="../light.css" id="themeStyle">
<link rel="stylesheet" type="text/css" href="../prism.css">
<script src="../storage.js"></script><noscript>
<link rel="stylesheet" href="../noscript.css"></noscript>
<link rel="shortcut icon" href="../favicon.ico">
<style type="text/css">
#crate-search {
background-image: url("../down-arrow.svg");
}
a {
color: #77d;
}
</style>
<!-- End scripts/rustdoc-header.html -->
</head>
<body>
<div id="root">
<div class="a b c">
<div class="d e f g h i j k"></div>
<div class="s">
<article>
<section class="fa fb fc fd w fe bp s"></section><span class="s"></span>
<div>
<div class="ff ep fg fh fi fj"></div>
<section class="dh fk fl dc fm">
<div class="fn w">
<p><img src="https://lupyuen.github.io/images/legacy/d1.jpeg" /></p>
<p><em>Debugging nRF52 with a Raspberry Pi 4 running
VSCode and OpenOCD with SWD over SPI at 31 MHz</em></p>
</div>
<div class="n p">
<div class="aj ak al am an gi ap w">
<div class="">
<h1 id="2f47"
class="gj df gk av cu gl gm gn go gp gq gr gs gt gu gv gw gx gy gz ha hb hc hd he hf hg">OpenOCD
on Raspberry Pi: Better with SWD on SPI</h1>
<div class="cr">
<div class="n ce hh hi hj">
<div class="o n">
<div><a rel="noopener"
href="https://lupyuen.github.io">
<div class="ah hk hl">
<div class="bb n ar o p ff hm hn ho hp hq fj"></div>
</div>
</a></div>
<div class="dt w n co">
<div class="n">
<div style="flex:1"><span class="av b aw ax hg"><a class="" rel="noopener"
href="https://lupyuen.github.io">
<h4 class="av b aw ax ay">Lup Yuen Lee 李立源</h4>
</a></span></div>
</div><span class="av b aw ax bt"><a class="" rel="noopener"
href="https://lupyuen.github.io">
<h4 class="av b aw ax bt"><span class="hs"></span>Jan 17, 2020<span
class="ht">·</span>14 min read</h4>
</a></span>
</div>
</div>
<div class="n cn hu hv hw hx hy hz ia ib">
<div class="n o">
<div class="ic s">
<div class="bq" aria-hidden="false"></div>
</div>
<div class="id s">
<div class="ie"><span><a
href="https://lupyuen.github.io/articles/openocd-on-raspberry-pi-better-with-swd-on-spi"
class="dn do bu bv bw bx by bz ca bg dp dq cb dr ds" rel="noopener"></a></span></div>
</div>
<div class="if s as"></div>
</div>
</div>
</div>
</div>
</div>
<p id="03ff" class="ig ih gk ii b ij ik il im in io ip iq ir is it iu iv iw ix iy iz dh hg"><em
class="ja">Sneaky tricks to align stray bits into proper bytes</em></p>
<p id="8f9a"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">The setup
that we see above… Debugging nRF52 with a Raspberry Pi running <a
href="https://code.headmelted.com/" class="dn jg"
rel="noopener nofollow">VSCode</a> and <a
href="http://openocd.org/doc/html/About.html#What-is-OpenOCD_003f"
class="dn jg" rel="noopener nofollow">OpenOCD</a>… <em class="ja">Was impossible just a week
ago!</em></p>
<p id="7df9"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">OpenOCD
connects to nRF52 for flashing and debugging by running <a
href="https://github.com/MarkDing/swd_programing_sram"
class="dn jg" rel="noopener nofollow">Arm’s SWD protocol</a> over GPIO <a
href="https://en.wikipedia.org/wiki/Bit_banging"
class="dn jg" rel="noopener nofollow">Bit Banging</a>. OpenOCD was sending data to nRF52 <strong
class="ii cu">one bit at a time</strong>… Works fine when OpenOCD is the only task running, <em
class="ja">not when it’s sharing the CPU with VSCode and other interactive tasks!</em></p>
<p id="fb26"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">That’s
because multitasking skews the precise timing that’s needed by OpenOCD to send each bit correctly.
</p>
<p id="f9c9"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Inst<span
id="rmm">e</span>ad of sending data over GPIO one bit at a time, <em class="ja">what if we could
blast out the data over </em><a
href="https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md"
class="dn jg" rel="noopener nofollow"><em class="ja">Raspberry Pi’s SPI interface</em></a><em
class="ja">?</em></p>
<p id="72df"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><strong
class="ii cu">SPI (</strong><a
href="https://en.wikipedia.org/wiki/Serial_Peripheral_Interface"
class="dn jg" rel="noopener nofollow"><strong class="ii cu">Serial Peripheral
Interface</strong></a><strong class="ii cu">)</strong> is implemented as a <a
href="https://github.com/raspberrypi/linux/blob/rpi-3.12.y/drivers/spi/spi-bcm2708.c"
class="dn jg" rel="noopener nofollow">kernel mode driver</a> with interrupts, so it runs with
<strong class="ii cu">high CPU priority</strong>. Raspberry Pi’s <a
href="https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835/BCM2835-ARM-Peripherals.pdf"
class="dn jg" rel="noopener nofollow">Broadcom microcontroller</a> supports Bidirectional SPI (31
MHz) with <strong class="ii cu">precise clocking and buffering</strong>. <em class="ja">Why not use
SPI for SWD?</em></p>
<p id="d4a6"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">This
article explains how we did that… By overcoming some interesting bitwise challenges. The SWD
protocol enables OpenOCD to flash and debug firmware, by reading and writing the debugging registers
on our Arm CPU. We’ll study the SWD Register Read/Write operations in a while…</p>
</div>
</div>
</section>
<div class="n p cr jh ji jj" role="separator"><span class="jk hr bq jl jm jn"></span><span
class="jk hr bq jl jm jn"></span><span class="jk hr bq jl jm"></span></div>
<section class="dh fk fl dc fm">
<div class="n p">
<div class="aj ak al am an gi ap w">
<h1 id="6277"
class="jo jp gk av jq jr js ik jt ju jv in jw jx jy jz ka kb kc kd ke kf kg kh ki kj hg">Build and
Test OpenOCD with SPI</h1>
<p id="a6b7"
class="ig ih gk ii b ij kk ik il im kl in io ip km iq ir is kn it iu iv ko iw ix iz dh hg"><strong
class="ii cu">UPDATE: There’s an easier way to build </strong><code
class="fy kp kq kr ks b"><strong class="ii cu">openocd-spi</strong></code><strong class="ii cu">
and use it to flash firmware… </strong><a
href="https://github.com/lupyuen/pinetime-updater"
class="dn jg" rel="noopener nofollow"><strong class="ii cu">Check out </strong></a><code
class="fy kp kq kr ks b"><a href="https://github.com/lupyuen/pinetime-updater" class="dn jg" rel="noopener nofollow"><strong class="ii cu">pinetime-updater</strong></a></code>
</p>
<p id="0f26"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">The SPI
version of OpenOCD is here…</p>
<p><a href="https://github.com/lupyuen/openocd-spi">https://github.com/lupyuen/openocd-spi</a></p>
<p id="6b24"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">To build
and test on Raspberry Pi Zero, 1, 2, 3 or 4…</p>
<p id="a357"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">1️⃣
Connect PineTime / nRF52 to the SPI port on Raspberry Pi…</p>
<p><script src="https://gist.github.com/lupyuen/6913bcd5ff5a5d67698f8bac0d84599b.js"></script></p>
<p><img src="https://lupyuen.github.io/images/legacy/d2.png" /></p>
<p><em>Connecting Raspberry Pi to PineTime / nRF52.
Based on <a href="https://pinout.xyz/" class="dn jg"
rel="noopener nofollow">https://pinout.xyz/</a></em></p>
</div>
</div>
<div class="fn">
<div class="n p">
<div class="mb mc md me mf mg am mh an mi ap w">
<p><img src="https://lupyuen.github.io/images/legacy/d3.jpeg" /></p>
<p><em>Connecting Raspberry Pi to PineTime / nRF52</em></p>
</div>
</div>
</div>
<div class="n p">
<div class="aj ak al am an gi ap w">
<p id="bdc9"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">2️⃣
Enable the SPI interface on Raspberry Pi…</p>
<pre
class="lt lu lv lw lx mn mo mp"><span id="f7f6" class="hg mq jp gk ks b di mr ms s mt">sudo raspi-config</span></pre>
<p id="ad7b"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Select
<code class="fy kp kq kr ks b">Interfacing Options → SPI → Yes</code></p>
<p id="8871"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">3️⃣
Download and build the modified OpenOCD…</p>
<pre
class="lt lu lv lw lx mn mo mp"><span id="b44b" class="hg mq jp gk ks b di mr ms s mt">cd ~<br/>git clone <a href="https://github.com/lupyuen/openocd-spi" class="dn jg" rel="noopener nofollow">https://github.com/lupyuen/openocd-spi</a><br/>cd openocd-spi<br/>./bootstrap<br/>./configure --enable-sysfsgpio --enable-bcm2835spi --enable-cmsis-dap<br/>make</span></pre>
<p id="8eda"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">The
modified OpenOCD executable is now at <code class="fy kp kq kr ks b">openocd-spi/src/openocd</code>
</p>
<p id="dbee"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">If you
see this error…</p>
<pre
class="lt lu lv lw lx mn mo mp"><span id="053f" class="hg mq jp gk ks b di mr ms s mt">Cloning into 'openocd-spi/jimtcl'...<br/>fatal: unable to access '<a href="http://repo.or.cz/r/jimtcl.git/'" class="dn jg" rel="noopener nofollow">http://repo.or.cz/r/jimtcl.git/'</a>: Recv failure: Connection reset by peer<br/>fatal: clone of '<a href="http://repo.or.cz/r/jimtcl.git'" class="dn jg" rel="noopener nofollow">http://repo.or.cz/r/jimtcl.git'</a> into submodule path '/private/tmp/aa/openocd-spi/jimtcl' failed</span></pre>
<p id="8ba3"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">It means
that the sub-repository for one of the dependencies <code class="fy kp kq kr ks b">jimtcl</code> is
temporarily down. You may download the pre-built <code class="fy kp kq kr ks b">openocd-spi</code>
binaries <a
href="https://github.com/lupyuen/pinetime-rust-mynewt/releases/download/openocd-spi2/openocd-spi.7z"
class="dn jg" rel="noopener nofollow">from this link</a>.</p>
<p id="5c77"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">4️⃣ If
you’re using <code class="fy kp kq kr ks b">pinetime-rust-mynewt</code> downloaded <a class="dn jg"
rel="noopener"
href="https://lupyuen.github.io/articles/build-and-flash-rust-mynewt-firmware-for-pinetime-smart-watch">from
this article</a>…</p>
<p id="e40b"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Edit the
OpenOCD scripts located at <code
class="fy kp kq kr ks b">pinetime-rust-mynewt/scripts/nrf52-pi</code>…</p>
<p id="a482"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><code
class="fy kp kq kr ks b">flash-app.sh, flash-boot.sh, flash-unprotect.sh</code></p>
<p id="52a7"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Change
the <code class="fy kp kq kr ks b">openocd</code> folder to <code
class="fy kp kq kr ks b">openocd-spi</code> like this…</p>
<pre
class="lt lu lv lw lx mn mo mp"><span id="e986" class="hg mq jp gk ks b di mr ms s mt">$HOME/<strong class="ks cu">openocd-spi</strong>/src/openocd \<br/> -s $HOME/<strong class="ks cu">openocd-spi</strong>/tcl \<br/> -f scripts/nrf52-pi/swd-pi.ocd \<br/> -f scripts/nrf52/flash-app.ocd</span></pre>
<p id="51fd"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Run these
scripts to unprotect the flash ROM, flash the bootloader and flash the application via SPI…</p>
<pre
class="lt lu lv lw lx mn mo mp"><span id="f816" class="hg mq jp gk ks b di mr ms s mt">cd ~/pinetime-rust-mynewt<br/>scripts/nrf52-pi/flash-unprotect.sh<br/>scripts/nrf52-pi/flash-boot.sh<br/>scripts/nrf52-pi/flash-app.sh</span></pre>
<p id="f06f"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">More
details may be found the article <em class="ja">“</em><a class="dn jg" rel="noopener"
href="https://lupyuen.github.io/articles/build-and-flash-rust-mynewt-firmware-for-pinetime-smart-watch"><em
class="ja">Build and Flash Rust+Mynewt Firmware for PineTime Smart Watch</em></a><em
class="ja">”</em> under the section <em class="ja">“Remove PineTime Flash Protection”</em></p>
<p id="002d"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">5️⃣ If
you prefer to write your own OpenOCD scripts (instead of using <code
class="fy kp kq kr ks b">pinetime-rust-mynewt</code>)…</p>
<p id="1d6f"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Here’s a
sample OpenOCD script and shell script that you may adapt for flashing…</p>
<p id="48f5"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">OpenOCD
Script: <code
class="fy kp kq kr ks b"><a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/scripts/nrf52/flash-boot.ocd" class="dn jg" rel="noopener nofollow">flash-boot.ocd</a></code>
and <code
class="fy kp kq kr ks b"><a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/scripts/nrf52-pi/swd-pi.ocd" class="dn jg" rel="noopener nofollow">swd-pi.ocd</a></code>
</p>
<p id="dad4"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Shell
Script:</p>
<pre
class="lt lu lv lw lx mn mo mp"><span id="c828" class="hg mq jp gk ks b di mr ms s mt">$HOME/<strong class="ks cu">openocd-spi</strong>/src/openocd \<br/> -s $HOME/<strong class="ks cu">openocd-spi</strong>/tcl \<br/> -f swd-pi.ocd \<br/> -f flash-boot.ocd</span></pre>
<p id="3d1e"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Unlike
GPIO, the SPI interface doesn’t require <code class="fy kp kq kr ks b">sudo</code> access.</p>
<p id="3b47"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Make sure
that you select <code class="fy kp kq kr ks b">bcm2835spi</code> as the OpenOCD interface (in <code
class="fy kp kq kr ks b"><a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/scripts/nrf52-pi/swd-pi.ocd" class="dn jg" rel="noopener nofollow">swd-pi.ocd</a></code>).
</p>
<pre
class="lt lu lv lw lx mn mo mp"><span id="ac0e" class="hg mq jp gk ks b di mr ms s mt"># Select the Broadcom SPI interface for Raspberry Pi (SWD transport)<br/>interface bcm2835spi </span><span id="273b" class="hg mq jp gk ks b di mu mv mw mx my ms s mt"># Set the SPI speed in kHz<br/>bcm2835spi_speed 31200 # 31.2 MHz</span></pre>
<p id="6deb"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><code
class="fy kp kq kr ks b">bcm2835spi</code> accepts one parameter <code
class="fy kp kq kr ks b">bcm2835spi_speed</code>, the SPI speed in kHz. <code
class="fy kp kq kr ks b">bcm2835spi_speed</code> defaults to <code
class="fy kp kq kr ks b">31200</code> (31.2 MHz). <a
href="https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md"
class="dn jg" rel="noopener nofollow"><em class="ja">Check this for the list of supported SPI
speeds</em></a></p>
<p id="5bc7"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Run the
above scripts to flash your device.</p>
<p id="e09b"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">6️⃣ You
should see this message if you’re using the 31 MHz SPI version of OpenOCD (instead of the old GPIO
version)…</p>
<pre
class="lt lu lv lw lx mn mo mp"><span id="547e" class="hg mq jp gk ks b di mr ms s mt">Info : BCM2835 SPI SWD driver<br/>Info : SWD only mode enabled<br/>Info : clock speed 31200 kHz</span></pre>
<p id="87d9"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">7️⃣ If
the flashing over SPI is successful, you should see…</p>
<pre
class="lt lu lv lw lx mn mo mp"><span id="b9ee" class="hg mq jp gk ks b di mr ms s mt">** Programming Started **<br/>Info : nRF52832-QFAA(build code: E1) 512kB Flash, 64kB RAM<br/>Warn : Adding extra erase range, 0x0003da78 .. 0x0003dfff<br/>** Programming Finished **<br/>** Verify Started **<br/>** Verified OK **</span></pre>
</div>
</div>
<div class="fn w">
<p><img src="https://lupyuen.github.io/images/legacy/d4.jpeg" /></p>
<p><em>Here’s a tip: Colour the Raspberry Pi pins with
a marker (one side only) so that we remember which pin to connect</em></p>
</div>
<div class="n p">
<div class="aj ak al am an gi ap w">
<blockquote class="na nb nc">
<p id="aee9"
class="ig ih ja ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><em
class="gk">💎 </em>The Bidirectional SPI we’re using on Raspberry Pi is slightly different from
the <a
href="https://en.wikipedia.org/wiki/Serial_Peripheral_Interface"
class="dn jg" rel="noopener nofollow">normal SPI interface</a>… Normal SPI runs on 3 data pins:
SCLK (Clock), MOSI (Host → Target), MISO (Target → Host). The <a
href="https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835/BCM2835-ARM-Peripherals.pdf"
class="dn jg" rel="noopener nofollow">Broadcom microcontroller on Pi</a> supports <a
href="https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md"
class="dn jg" rel="noopener nofollow">SPI with 2 data pins</a>, by merging the MOSI and MISO
pins. Hence it’s called “Bidirectional SPI”. It’s pin-compatible with SWD, which also uses 2 data
pins.</p>
<p id="fccb"
class="ig ih ja ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Will
SWD over SPI work on other microcontrollers besides Broadcom? Possibly not… I wasn’t able to find
a similar Bidirectional SPI mode for Rockchip RK3328, for instance. Bidirectional SPI mode is
sometimes named MOMI or SISO mode.</p>
</blockquote>
</div>
</div>
</section>
<div class="n p cr jh ji jj" role="separator"><span class="jk hr bq jl jm jn"></span><span
class="jk hr bq jl jm jn"></span><span class="jk hr bq jl jm"></span></div>
<section class="dh fk fl dc fm">
<div class="n p">
<div class="aj ak al am an gi ap w">
<h1 id="d19a"
class="jo jp gk av jq jr js ik jt ju jv in jw jx jy jz ka kb kc kd ke kf kg kh ki kj hg">SWD Read
Operation</h1>
<p id="ccae"
class="ig ih gk ii b ij kk ik il im kl in io ip km iq ir is kn it iu iv ko iw ix iz dh hg">OpenOCD
flashes and debugs firmware by reading and writing the debugging registers on our Arm CPU. Let’s
look at the reading of registers…</p>
<p id="b69d"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">For
Raspberry Pi to read an SWD Register on nRF52, we perform an SWD Read Operation like this (Raspberry
Pi is the host, PineTime/nRF52 is the target)…</p>
</div>
</div>
<div class="fn w">
<p><img src="https://lupyuen.github.io/images/legacy/d5.png" /></p>
<p><em>SWD Read Operation with 2 undefined trailing
bits. From <a
href="https://docs.google.com/spreadsheets/d/12oXe1MTTEZVIbdmFXsOgOXVFHCQnYVvIw6fRpIQZybg/edit#gid=0"
class="dn jg"
rel="noopener nofollow">https://docs.google.com/spreadsheets/d/12oXe1MTTEZVIbdmFXsOgOXVFHCQnYVvIw6fRpIQZybg/edit#gid=0</a>
</em></p>
</div>
<div class="n p">
<div class="aj ak al am an gi ap w">
<p id="0038"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Here we
are reading the <strong class="ii cu">IDCODE (Identification Code) Register</strong>, which
identifies the Arm Debug Interface (<code class="fy kp kq kr ks b">0x2ba01477</code> for nRF52).
IDCODE is Register #0 (in Read Mode), so we set <code class="fy kp kq kr ks b">A2</code> and <code
class="fy kp kq kr ks b">A3</code> (bits 2 and 3 of the register number) to <code
class="fy kp kq kr ks b">0</code>.</p>
<p id="1f2d"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><strong
class="ii cu"><em class="ja">Pi → nRF52: 8 bits…</em></strong></p>
<p><img src="https://lupyuen.github.io/images/legacy/d6.png" /></p>
<p><em>From Pi to nRF52</em></p>
<p id="57c4"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Pi sends
<code class="fy kp kq kr ks b">0xA5</code> (least significant bit first) to nRF52. That’s followed
by <code class="fy kp kq kr ks b">Trn</code>, the Turnaround Bit. This bit gives 1 clock cycle of
breathing space whenever we flip the transmission from Pi to nRF52 and back. The value of <code
class="fy kp kq kr ks b">Trn</code> doesn’t matter.</p>
<p id="f84f"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><strong
class="ii cu"><em class="ja">nRF52 → Pi: 38 bits (including turnaround)…</em></strong></p>
</div>
</div>
<div class="fn w">
<p><img src="https://lupyuen.github.io/images/legacy/d7.png" /></p>
<p><em>From nRF52 to Pi</em></p>
</div>
<div class="n p">
<div class="aj ak al am an gi ap w">
<p id="2fed"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">nRF52
responds with the Acknowledgement <code class="fy kp kq kr ks b">100</code> (which means OK).
Followed by 32 bits of data (the value of Register IDCODE), a Parity bit, and another Turnaround
Bit.</p>
<p id="b426"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Now let’s
see whether Raspberry Pi’s SPI interface will allow us to send and receive this kind of data.</p>
<p id="ecb9"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><strong
class="ii cu"><em class="ja">Missing: 2 bits…</em></strong></p>
<p><img src="https://lupyuen.github.io/images/legacy/d8.png" /></p>
<p><em>From nRF52 to Pi and back</em></p>
<p id="4545"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Count the
bits for the entire SWD Read Operation (look at the red blocks)… It has 46 bits, which is <em
class="ja">2 bits short of 6 whole bytes</em>.</p>
<p id="730b"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Also the
<em class="ja">last byte is split across Pi and nRF52</em>… nRF52 sends 5 bits, then Turnaround,
then Pi is supposed to send 2 bits from the next read/write operation!</p>
<p id="c399"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Since
Raspberry Pi’s SPI interface can only send and receive whole bytes (not bits)… <em class="ja">We
have a problem with the last 2 stray bits!</em></p>
<p id="55f6"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">nRF52
gets utterly confused after the SWD Read Operation. Only way to fix this? <strong
class="ii cu">Reset the SWD connection and resynchronise by resending the JTAG-To-SWD
Sequence.</strong></p>
<p><script src="https://gist.github.com/lupyuen/b8612a2a9f861da7750f9baca66d94bc.js"></script></p>
<p><em>Sending the JTAG-To-SWD Sequence to reset SWD
connection. From <a
href="https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/swd.h"
class="dn jg"
rel="noopener nofollow">https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/swd.h</a>
</em></p>
<p id="05bd"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Yes our
SWD flashing may slow down when we reset the SWD connection after every SWD Read Operation… But we
are now running the SWD connection over SPI at a speedy <strong class="ii cu">31 MHz</strong>! This
compensates for the reset transmission, so the overall SWD flashing is still fast.</p>
<p><script src="https://gist.github.com/lupyuen/70a0e939bb1b7a985e5b8eedbb34baee.js"></script></p>
<p><em>After every SWD Read Operation, send the
JTAG-To-SWD Sequence to reset SWD connection. From <a
href="https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/drivers/bcm2835spi.c"
class="dn jg"
rel="noopener nofollow">https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/drivers/bcm2835spi.c</a>
</em></p>
</div>
</div>
</section>
<div class="n p cr jh ji jj" role="separator"><span class="jk hr bq jl jm jn"></span><span
class="jk hr bq jl jm jn"></span><span class="jk hr bq jl jm"></span></div>
<section class="dh fk fl dc fm">
<div class="n p">
<div class="aj ak al am an gi ap w">
<h1 id="30e6"
class="jo jp gk av jq jr js ik jt ju jv in jw jx jy jz ka kb kc kd ke kf kg kh ki kj hg">Throwaway
SWD Read Operation</h1>
<p id="fb58"
class="ig ih gk ii b ij kk ik il im kl in io ip km iq ir is kn it iu iv ko iw ix iz dh hg">For SWD
to work over SPI, we need to reset the SWD connection after every SWD Read Operation… Just send the
JTAG-To-SWD Sequence! But there’s a catch: <em class="ja">We MUST read IDCODE after sending the
JTAG-To-SWD Sequence…</em></p>
<p><img src="https://lupyuen.github.io/images/legacy/d9.png" /></p>
<p><em>Resetting the SWD connection. From ARM® Debug
Interface v5 Architecture Specification <a
href="https://github.com/MarkDing/swd_programing_sram/blob/master/Ref/ARM_debug.pdf"
class="dn jg"
rel="noopener nofollow">https://github.com/MarkDing/swd_programing_sram/blob/master/Ref/ARM_debug.pdf</a>
</em></p>
<p id="d77e"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><em
class="ja">See the problem here? </em>We need to reset after reading a register… <em
class="ja">And yet we need to read a register (IDCODE) after resetting!</em></p>
<p id="c12a"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><em
class="ja">The snake eats its own tail! </em>To break the snake, we use a sneaky way to read
IDCODE after resetting, the Throwaway Way…</p>
</div>
</div>
<div class="fn w">
<p><img src="https://lupyuen.github.io/images/legacy/d10.png" /></p>
<p><em>Read IDCODE Operation: Normal operation (above)
and Throwaway operation (below). From <a
href="https://docs.google.com/spreadsheets/d/12oXe1MTTEZVIbdmFXsOgOXVFHCQnYVvIw6fRpIQZybg/edit#gid=0"
class="dn jg"
rel="noopener nofollow">https://docs.google.com/spreadsheets/d/12oXe1MTTEZVIbdmFXsOgOXVFHCQnYVvIw6fRpIQZybg/edit#gid=0</a>
</em></p>
</div>
<div class="n p">
<div class="aj ak al am an gi ap w">
<p id="a7ab"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Notice
that we <em class="ja">slide the entire Read IDCODE Operation two bits to the right</em>… Inserting
two null bits in front.</p>
<p id="2cc8"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><em
class="ja">Will nRF52 accept the two null leading bits sent by Pi?</em> Yes because all SWD
Read/Write Operations must start with <code class="fy kp kq kr ks b">1</code>. So it’s always OK for
Pi to send null bits before and after every SWD Read/Write Operation.</p>
<p id="b4b0"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">For a
normal SWD Read Operation (that’s not byte-aligned and hence problematic)…</p>
<p id="2d5b"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><strong
class="ii cu"><em class="ja">Pi → nRF52</em></strong>: 8 bits (<code
class="fy kp kq kr ks b">A5</code>), followed by…<br /><strong class="ii cu"><em class="ja">nRF52
→ Pi</em></strong>: 38 bits (Data + Parity + Turnaround)</p>
<p id="b205"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><strong
class="ii cu">Total 46 bits</strong>, not byte-aligned, no good. For our special Throwaway version
with two prepadded null bits…</p>
<p id="449e"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><strong
class="ii cu"><em class="ja">Pi → nRF52</em></strong>: 48 bits (<code
class="fy kp kq kr ks b">94 02 00 00 00 00</code>), followed by…<br /><strong class="ii cu"><em
class="ja">nRF52 → Pi</em></strong>: 0 bits</p>
<p id="5182"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><strong
class="ii cu">Total 48 bits</strong>, byte-aligned, all good! So the next SWD Read or Write
Operation may be sent, perfectly aligned to the byte. (If the next operation is SWD Read, we’ll have
to read the register, reset and read IDCODE again)</p>
<p id="3133"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><em
class="ja">But it sounds like Pi is yakking away over the entire SWD Read Operation, not really
listening to nRF52 (and getting the value of IDCODE)?</em></p>
<p id="0362"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">That’s
perfectly fine… We don’t really care about the value of IDCODE anyway. We are only reading IDCODE
because Arm said so.</p>
<p id="758a"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Thus in
the SPI implementation of SWD, we see this special Throwaway Read IDCODE (<code
class="fy kp kq kr ks b">94 02 00 00 00 00</code>) that’s sent after every SWD connection reset in
<code
class="fy kp kq kr ks b"><a href="https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/drivers/spi.c" class="dn jg" rel="noopener nofollow">spi_transmit_resync</a>()</code>.
To give sufficient clock cycles for nRF52 to do its job, we insert a null byte before and after the
Throwaway Read IDCODE: <code
class="fy kp kq kr ks b"><strong class="ii cu">00</strong> 94 02 00 00 00 00 <strong class="ii cu">00</strong></code>
</p>
<p><script src="https://gist.github.com/lupyuen/0d45e70d60bcd303a12392f13eebf80b.js"></script></p>
<p><em>Reset SWD Connection with Throwaway Read
IDCODE. From <a
href="https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/drivers/bcm2835spi.c"
class="dn jg"
rel="noopener nofollow">https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/drivers/bcm2835spi.c</a>
</em></p>
<p id="7acf"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><em
class="ja">What’s the SWD Write ABORT Operation?</em> We’ll learn in a while…</p>
</div>
</div>
</section>
<div class="n p cr jh ji jj" role="separator"><span class="jk hr bq jl jm jn"></span><span
class="jk hr bq jl jm jn"></span><span class="jk hr bq jl jm"></span></div>
<section class="dh fk fl dc fm">
<div class="n p">
<div class="aj ak al am an gi ap w">
<h1 id="81ad"
class="jo jp gk av jq jr js ik jt ju jv in jw jx jy jz ka kb kc kd ke kf kg kh ki kj hg">SWD Write
Operation</h1>
<p id="7a4a"
class="ig ih gk ii b ij kk ik il im kl in io ip km iq ir is kn it iu iv ko iw ix iz dh hg">For
Raspberry Pi to write an SWD Register on nRF52, we perform an SWD Write Operation like this
(Raspberry Pi is the host, PineTime/nRF52 is the target)…</p>
</div>
</div>
<div class="fn w">
<p><img src="https://lupyuen.github.io/images/legacy/d11.png" /></p>
<p><em>SWD Write Operation padded with 2 null bits.
From <a
href="https://docs.google.com/spreadsheets/d/12oXe1MTTEZVIbdmFXsOgOXVFHCQnYVvIw6fRpIQZybg/edit#gid=0"
class="dn jg"
rel="noopener nofollow">https://docs.google.com/spreadsheets/d/12oXe1MTTEZVIbdmFXsOgOXVFHCQnYVvIw6fRpIQZybg/edit#gid=0</a>
</em></p></em></p>
</div>
<div class="n p">
<div class="aj ak al am an gi ap w">
<p id="31fa"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Here we
are writing the value <code class="fy kp kq kr ks b">0x1E</code> to the <strong class="ii cu">ABORT
Register</strong>. Whenever a SWD protocol error occurs during transmission (e.g. misaligned
bits), we need to clear the error by writing to the ABORT Register.</p>
<p id="91be"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">ABORT is
Register #0 (in Write Mode), so we set <code class="fy kp kq kr ks b">A2</code> and <code
class="fy kp kq kr ks b">A3</code> (bits 2 and 3 of the register number) to <code
class="fy kp kq kr ks b">0</code>.</p>
<p id="cb3f"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><strong
class="ii cu"><em class="ja">Pi → nRF52: 8 bits…</em></strong></p>
<p><img src="https://lupyuen.github.io/images/legacy/d12.png" /></p>
<p><em>From Pi to nRF52</em></p>
<p id="78a0"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Pi sends
<code class="fy kp kq kr ks b">0x81</code> (least significant bit first) to nRF52. That’s followed
by <code class="fy kp kq kr ks b">Trn</code>, the Turnaround Bit.</p>
<p id="9139"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><strong
class="ii cu"><em class="ja">nRF52 → Pi: 5 bits (including turnaround)…</em></strong></p>
<p><img src="https://lupyuen.github.io/images/legacy/d13.png" /></p>
<p><em>From nRF52 to Pi</em></p>
<p id="59cf"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">nRF52
responds with the Acknowledgement <code class="fy kp kq kr ks b">100</code> (which means OK). and
another Turnaround Bit.</p>
<p id="a1fd"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><strong
class="ii cu"><em class="ja">Pi → nRF52: 33 bits…</em></strong></p>
</div>
</div>
<div class="fn w">
<p><img src="https://lupyuen.github.io/images/legacy/d14.png" /></p>
<p><em>From Pi to nRF52</em></p>
</div>
<div class="n p">
<div class="aj ak al am an gi ap w">
<p id="c3aa"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Pi sends
32 bits of data (the value to be written to Register ABORT) and a Parity bit.</p>
<p id="b3c1"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><strong
class="ii cu"><em class="ja">Pi → nRF52: 2 bits (padding for byte alignment)…</em></strong></p>
<p><img src="https://lupyuen.github.io/images/legacy/d15.png" /></p>
<p><em>From Pi to nRF52</em></p>
<p id="ea2d"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">For our
SPI implementation, Pi sends an extra 2 null bits to make the entire operation byte-aligned: 6 whole
SPI bytes. <em class="ja">(Remember: It’s OK to insert extra null bits before and after SWD
Read/Write Operations)</em></p>
<p id="c4c9"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">No
misaligned bits for SWD Write Operations… <em class="ja">Phew!</em></p>
</div>
</div>
</section>
<div class="n p cr jh ji jj" role="separator"><span class="jk hr bq jl jm jn"></span><span
class="jk hr bq jl jm jn"></span><span class="jk hr bq jl jm"></span></div>
<section class="dh fk fl dc fm">
<div class="n p">
<div class="aj ak al am an gi ap w">
<h1 id="a93c"
class="jo jp gk av jq jr js ik jt ju jv in jw jx jy jz ka kb kc kd ke kf kg kh ki kj hg">A
Convenient Write Lie</h1>
<p id="5a2c"
class="ig ih gk ii b ij kk ik il im kl in io ip km iq ir is kn it iu iv ko iw ix iz dh hg"><em
class="ja">Will SWD Write Operations work over SPI?</em> SWD Write Operations are always
byte-aligned, because we padded 2 null bits. But we have a funny Turnaround situation in the second
byte of the SWD Write Operation…</p>
<p><img src="https://lupyuen.github.io/images/legacy/d16.png" /></p>
<p><em>From Pi to nRF52 and back</em></p>
<p id="69ee"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><em
class="ja">There are Two Turnarounds in the same byte!</em></p>
<p id="d467"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><strong
class="ii cu"><em class="ja">nRF52 → Pi:</em></strong> 3 Acknowledgement Bits + 2 Turnaround Bits,
followed by…<em class="ja"><br /></em><strong class="ii cu"><em class="ja">Pi →
nRF52:</em></strong><em class="ja"> </em>3 Data Bits</p>
<p id="72be"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">We can’t
flip the direction of transmission within a single SPI byte transfer. <em class="ja">So this fails
for SPI!</em> Thankfully we have another sneaky solution for this problematic second byte…</p>
<p id="4c36"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><strong
class="ii cu"><em class="ja">nRF52 → Pi:</em></strong> 0 bits, followed by…<em
class="ja"><br /></em><strong class="ii cu"><em class="ja">Pi → nRF52:</em></strong><em
class="ja"> </em>3 Acknowledgement Bits + 2 Turnaround Bits + 3 Data Bits</p>
<p id="155a"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><em
class="ja">Look familiar?</em> This is the same trick as the Throwaway SWD Read Operation… <em
class="ja">We now throw away the 3 Acknowledgement Bits sent by nRF52 to Pi!</em></p>
<p id="bde1"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Instead
of Pi receiving the 3 Acknowledgement Bits from nRF52, <em class="ja">Pi now sends 3 bits to
nRF52</em>. Doesn’t matter whether they are <code class="fy kp kq kr ks b">0</code> or <code
class="fy kp kq kr ks b">1</code>, as long as it takes 3 clock cycles.</p>
<p id="2c7d"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">But that
means we won’t know whether the Write Acknowledgement is OK (<code
class="fy kp kq kr ks b">100</code>)!</p>
<p id="a5f4"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><em
class="ja">Think about it… Is this Write Acknowledgement really useful?</em> It happens <em
class="ja">before</em> the data is written! Most of the time it’s used to indicate that the
Register ID (in <code class="fy kp kq kr ks b">A2</code> and <code
class="fy kp kq kr ks b">A3</code>) is valid.</p>
<p id="101c"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Thus we
take a calculated risk and assume that the <strong class="ii cu">SWD Write Acknowledgement is always
OK</strong>. Our SPI code always lies and returns <code class="fy kp kq kr ks b">100</code> to
OpenOCD.</p>
<p><script src="https://gist.github.com/lupyuen/82adeeecf84f6b62d90d9536c3043105.js"></script></p>
<p><em>Our SPI code always returns OK to OpenOCD for
SWD Write Acknowledgement. From <a
href="https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/drivers/bcm2835spi.c"
class="dn jg"
rel="noopener nofollow">https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/drivers/bcm2835spi.c</a>
</em></p>
<p id="eb0b"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><em
class="ja">Will this cause problems when flashing the ROM of nRF52? Since we’re not checking the
SWD Write Acknowledgement?</em></p>
<p id="749e"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Here’s
how we mitigate the risk of write failures: <strong class="ii cu">We always read and verify the ROM
contents after flashing</strong>, like in <a
href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/scripts/nrf52/flash-app.ocd"
class="dn jg" rel="noopener nofollow">this OpenOCD script</a>…</p>
<pre
class="lt lu lv lw lx mn mo mp"><span id="dd35" class="hg mq jp gk ks b di mr ms s mt">program bin/targets/nrf52_my_sensor/app/apps/my_sensor_app/my_sensor_app.img verify 0x00008000</span></pre>
<p id="1afa"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">When we
throw away the SWD Write Acknowledgement, we eliminate all Turnarounds. Our SWD Write Operation
becomes really simple… <em class="ja">Just send 8 whole bytes from Pi to nRF52!</em></p>
<p id="11ed"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><em
class="ja">Perfect for implementing SWD over SPI!</em></p>
<p id="ff0e"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Hence to
write value <code class="fy kp kq kr ks b">0x1E</code> to the ABORT Register, Pi only needs to blast
out 6 bytes over SPI to nRF52: <code class="fy kp kq kr ks b">81 d3 03 00 00 00</code></p>
<p><script src="https://gist.github.com/lupyuen/3fd90b6f7f060e49bd629eccee1958d7.js"></script></p>
<p><em>Sending 8 whole bytes from Pi to nRF52 for an
SPI Write Operation. From <a
href="https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/drivers/bcm2835spi.c"
class="dn jg"
rel="noopener nofollow">https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/drivers/bcm2835spi.c</a>
</em></p>
</div>
</div>
</section>
<div class="n p cr jh ji jj" role="separator"><span class="jk hr bq jl jm jn"></span><span
class="jk hr bq jl jm jn"></span><span class="jk hr bq jl jm"></span></div>
<section class="dh fk fl dc fm">
<div class="n p">
<div class="aj ak al am an gi ap w">
<h1 id="81eb"
class="jo jp gk av jq jr js ik jt ju jv in jw jx jy jz ka kb kc kd ke kf kg kh ki kj hg">Clear the
Sticky Error Bits</h1>
<p id="6561"
class="ig ih gk ii b ij kk ik il im kl in io ip km iq ir is kn it iu iv ko iw ix iz dh hg">We added
debug logs to the existing OpenOCD code in <code
class="fy kp kq kr ks b"><a href="https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/drivers/bitbang.c#L414-L464" class="dn jg" rel="noopener nofollow">bitbang.c</a></code>
to compare the old GPIO and new SPI implementations of the SWD protocol.</p>
<p id="b1f6"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Remember
we said earlier that every SWD Read Operation will be followed by an SWD connection reset that
transmits two byte sequences to nRF52…</p>
<ol class="">
<li id="3467"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz nw nx ny hg">
JTAG-To-SWD Sequence</li>
<li id="01a6"
class="ig ih gk ii b ij nz ik il im oa in io ip ob iq ir is oc it iu iv od iw ix iz nw nx ny hg">
Read IDCODE Sequence, prepadded with two null bits</li>
</ol>
<p id="3f64"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Here’s
what happens when we run OpenOCD with that setup…</p>
<p><img src="https://lupyuen.github.io/images/legacy/d17.png" /></p>
<p><em>Comparing the logs from SWD over GPIO (left)
with SWD over SPI (right). From <a
href="https://docs.google.com/spreadsheets/d/12oXe1MTTEZVIbdmFXsOgOXVFHCQnYVvIw6fRpIQZybg/edit#gid=900511571"
class="dn jg"
rel="noopener nofollow">https://docs.google.com/spreadsheets/d/12oXe1MTTEZVIbdmFXsOgOXVFHCQnYVvIw6fRpIQZybg/edit#gid=900511571</a>
</em></p>
<p id="27f8"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Both the
GPIO and SPI versions of OpenOCD are reading and writing to the same nRF52 registers: IDCODE, SELECT
AP, CTRL/STAT. But the value of the Control/Status Register (CTRL/STAT) is different for SPI: <code
class="fy kp kq kr ks b">f0000003</code>.</p>
<p id="6270"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">What’s
<code class="fy kp kq kr ks b">f0000003</code>? Let’s key that <a
href="https://docs.google.com/spreadsheets/d/12oXe1MTTEZVIbdmFXsOgOXVFHCQnYVvIw6fRpIQZybg/edit#gid=2077834467"
class="dn jg" rel="noopener nofollow">into this spreadsheet</a> to decode the Control/Status
value…</p>
</div>
</div>
<div class="fn w">
<p><img src="https://lupyuen.github.io/images/legacy/d18.png" /></p>
<p><em>Control/Status Register Decoder: <a
href="https://docs.google.com/spreadsheets/d/12oXe1MTTEZVIbdmFXsOgOXVFHCQnYVvIw6fRpIQZybg/edit#gid=2077834467"
class="dn jg"
rel="noopener nofollow">https://docs.google.com/spreadsheets/d/12oXe1MTTEZVIbdmFXsOgOXVFHCQnYVvIw6fRpIQZybg/edit#gid=2077834467</a>
</em></p>
</div>
<div class="n p">
<div class="aj ak al am an gi ap w">
<p id="a209"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><em
class="ja">What’s the difference between the GPIO and SPI values for the Control/Status
Register?</em> SPI is experiencing the <strong class="ii cu">STICKYORUN</strong> error…</p>
<p><img src="https://lupyuen.github.io/images/legacy/d19.png" /></p>
<p><em>STICKYORUN flag in the Control/Status
Register. From ARM® Debug Interface v5 Architecture Specification <a
href="https://github.com/MarkDing/swd_programing_sram/blob/master/Ref/ARM_debug.pdf"
class="dn jg"
rel="noopener nofollow">https://github.com/MarkDing/swd_programing_sram/blob/master/Ref/ARM_debug.pdf</a>
</em></p>
<p id="528b"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">This
means that nRF52 has <strong class="ii cu">detected some overrun garbage on the SWD
connection</strong>… <em class="ja">Must be due to our misaligned SWD Read Operations!</em></p>
<p id="8474"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">This is a
“Sticky” error… It sticks there forever until we do something to clear the error status. <strong
class="ii cu">If we don’t clear the Sticky error status, all SWD operations will fail.</strong>
</p>
<p><img src="https://lupyuen.github.io/images/legacy/d20.png" /></p>
<p><em>ABORT Register. From ARM® Debug Interface v5
Architecture Specification <a
href="https://github.com/MarkDing/swd_programing_sram/blob/master/Ref/ARM_debug.pdf"
class="dn jg"
rel="noopener nofollow">https://github.com/MarkDing/swd_programing_sram/blob/master/Ref/ARM_debug.pdf</a>
</em></p>
<p id="264e"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">The
solution: We write value <code class="fy kp kq kr ks b">0x1E</code> to the ABORT Register. That’s
binary <code class="fy kp kq kr ks b">11110</code>, which means that we are clearing <em
class="ja">all</em> the errors: Overrun Error, Write Data Error, Sticky Error, Sticky Compare
Error.</p>
<p id="b043"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">In the
previous section we have learnt how to write value <code class="fy kp kq kr ks b">0x1E</code> to the
ABORT Register: By blasting out over SPI <code class="fy kp kq kr ks b">81 d3 03 00 00 00</code></p>
<p id="8206"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><em
class="ja">When shall we write to the ABORT Register to clear the errors?</em></p>
<p id="1b5f"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Remember
that Pi has become extremely negligent to nRF52… <em class="ja">Pi has thrown away so much feedback
and acknowledgement from nRF52!</em> We don’t know exactly when nRF52 is having issues. But since…
</p>
<ol class="">
<li id="0b29"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz nw nx ny hg">
The errors are caused by the misaligned SWD Read Operation</li>
<li id="0da2"
class="ig ih gk ii b ij nz ik il im oa in io ip ob iq ir is oc it iu iv od iw ix iz nw nx ny hg">
And we always reset the SWD connection after every SWD Read Operation (except the Throwaway Read
IDCODE)…</li>
</ol>
<p id="f7cb"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">Let’s
write to the ABORT Register and <strong class="ii cu">clear the errors at every SWD connection
reset</strong>.</p>
<p><script src="https://gist.github.com/lupyuen/4977b46c0c7dfdc6c8d22cf6cbfd6f6c.js"></script></p>
<p><em>Clearing the errors at every SWD connect
reset by writing to ABORT. From <a
href="https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/drivers/bcm2835spi.c"
class="dn jg"
rel="noopener nofollow">https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/drivers/bcm2835spi.c</a>
</em></p>
<p id="6702"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg"><em
class="ja">With this fix, SWD over SPI works perfectly!</em></p>
</div>
</div>
</section>
<div class="n p cr jh ji jj" role="separator"><span class="jk hr bq jl jm jn"></span><span
class="jk hr bq jl jm jn"></span><span class="jk hr bq jl jm"></span></div>
<section class="dh fk fl dc fm">
<div class="n p">
<div class="aj ak al am an gi ap w">
<h1 id="6258"
class="jo jp gk av jq jr js ik jt ju jv in jw jx jy jz ka kb kc kd ke kf kg kh ki kj hg">Inject SPI
into OpenOCD Bit Bang</h1>
<p id="2886"
class="ig ih gk ii b ij kk ik il im kl in io ip km iq ir is kn it iu iv ko iw ix iz dh hg">We have
SWD Read and Write Operations working fine over SPI, and we have forcibly fixed all the SWD errors
indirectly caused by SPI. Now let’s inject this SPI code into the OpenOCD code.</p>
<p id="8ac8"
class="ig ih gk ii b ij jb ik il im jc in io ip jd iq ir is je it iu iv jf iw ix iz dh hg">OpenOCD
calls <code class="fy kp kq kr ks b">bitbang_exchange()</code> in <code
class="fy kp kq kr ks b"><a href="https://github.com/lupyuen/openocd-spi/blob/master/src/jtag/drivers/bitbang.c#L414-L464" class="dn jg" rel="noopener nofollow">bitbang.c</a></code>
whenever it needs to transmit or receive a chunk of bits in a fixed direction. OpenOCD calls <code
class="fy kp kq kr ks b">bitbang_exchange()</code> two times for every SWD Read, three times for
every SWD Write…</p>
</div>
</div>
<div class="fn">
<div class="n p">
<div class="mb mc md me mf mg am mh an mi ap w">
<p><img src="https://lupyuen.github.io/images/legacy/d21.png" /></p>
<p><em><code
class="fy kp kq kr ks b">SWD Read: bitbang_exchange()</code> called for two chunks of bits.
From <a