Compare commits
642 Commits
Author | SHA1 | Date | |
---|---|---|---|
547abf0cf2 | |||
06b21b6d82 | |||
|
ad1868f8d4 | ||
|
c712a54cbc | ||
|
a51d90ba2d | ||
|
f67a4e421d | ||
|
8fc7a559b2 | ||
|
c9a0be19cb | ||
|
2ca08f8511 | ||
|
3ae3095499 | ||
|
2a792399ca | ||
|
576f575871 | ||
|
e43b07172b | ||
|
e0f1d29d41 | ||
|
2a00dd88ec | ||
|
c121da06c8 | ||
|
542c157955 | ||
|
d4dd288426 | ||
|
b096e95488 | ||
|
7bd7c3d0f5 | ||
|
82673b5e7b | ||
|
9542cd1cfb | ||
|
328be18288 | ||
|
03331b3fff | ||
|
ca1c0acb27 | ||
|
b4af0f5145 | ||
|
e174c5b503 | ||
|
c91322e38e | ||
|
85fc728293 | ||
|
6727e74daf | ||
|
d7bf91d039 | ||
|
878dc379b9 | ||
|
4f97627b02 | ||
|
56858650cb | ||
|
dcbb1657b4 | ||
|
9dc79becc2 | ||
|
9ec6693e4d | ||
|
a2f6776bf8 | ||
|
cb1ef7d616 | ||
|
def176b240 | ||
|
d5a8717bb0 | ||
|
8acda14170 | ||
|
c1e34792f4 | ||
|
c5b6f066b8 | ||
|
f109bc2e98 | ||
|
d36213b7d0 | ||
|
389bb03fc0 | ||
|
78837173a4 | ||
|
4328e8a4c1 | ||
|
646fbcb21f | ||
|
9da2d298c3 | ||
|
95a4ebf836 | ||
|
3024cc1bfe | ||
|
7340b0065d | ||
|
dd01fe9ad3 | ||
|
336797363b | ||
|
046cc359ba | ||
|
9e02c5f0cd | ||
|
c73329f7d4 | ||
|
d90c207c50 | ||
|
b87091a59b | ||
|
f8aff4bf4b | ||
|
50b9a4ceb6 | ||
|
93cf62d944 | ||
|
09e45cea5b | ||
|
65c95fb413 | ||
|
c643726c9d | ||
|
eda19bc28d | ||
|
9b145c8398 | ||
|
53c6821734 | ||
|
842a0b4193 | ||
|
8a37449f8a | ||
|
21989d4142 | ||
|
63449912e2 | ||
|
1661396951 | ||
|
fd6610bdae | ||
|
19e01abf70 | ||
|
a89b2ead47 | ||
|
81cfa0a380 | ||
|
41449370b4 | ||
|
73285885b3 | ||
|
b71213522a | ||
|
c0c5255103 | ||
|
a2cdb32f14 | ||
|
1930380e16 | ||
|
5509264a2b | ||
|
6f902bcfe7 | ||
|
fdce017311 | ||
|
96a980b682 | ||
|
cedcd1a832 | ||
|
1737788a92 | ||
|
f65793582d | ||
|
90a7ecaaf1 | ||
|
b6896898c2 | ||
|
81bb75bba6 | ||
|
6661871707 | ||
|
885fdcc354 | ||
|
16261813ca | ||
|
fcf5b74542 | ||
|
539fba02ac | ||
|
4a2a121e89 | ||
|
16b827e4e4 | ||
|
a9197e67ea | ||
|
ab63700a80 | ||
|
0993a8ae28 | ||
|
a7c4a0c108 | ||
|
bb97e35f82 | ||
|
cbed6c911f | ||
|
272b461b3e | ||
|
a29d53cb31 | ||
|
4947f0f747 | ||
|
a6f8944afe | ||
|
33c0319263 | ||
|
93cad1ca5a | ||
|
9a9fac2e83 | ||
|
a285b2ac17 | ||
|
4b4d0fcfcf | ||
|
6b2b1aa4c3 | ||
|
fce7dd2957 | ||
|
6b2f0aeb63 | ||
|
4cae565ef3 | ||
|
d76fd844c9 | ||
|
27a099a94b | ||
|
9c33ce7979 | ||
|
1612eacab2 | ||
|
f1f59d3c1d | ||
|
a42fc8904d | ||
|
f62c9db5af | ||
|
1ba83f3283 | ||
|
c33a447210 | ||
|
81fafae68d | ||
|
447bdc50a0 | ||
|
b91712214f | ||
|
5574a14aee | ||
|
a82ab6a45d | ||
|
40ea78d57b | ||
|
eab16ef39f | ||
|
da701aff6d | ||
|
aece87bf3e | ||
|
2931169dd1 | ||
|
95655b838e | ||
|
1846795844 | ||
|
76c2f5e39c | ||
|
51f2b79437 | ||
|
02eafe9883 | ||
|
05a42576c2 | ||
|
39949eefe2 | ||
|
d7afc92b5f | ||
|
44b5eed7ca | ||
|
4346fb2405 | ||
|
9c95dfb712 | ||
|
f99fe59ce8 | ||
|
5cd430647e | ||
|
fc55400aad | ||
|
d2370f780f | ||
|
f254e86511 | ||
|
3cc6aa1236 | ||
|
65ac074410 | ||
|
c6d1bcb352 | ||
|
eb9d9893f8 | ||
|
8db1d30852 | ||
|
1f22c72634 | ||
|
7322bb3ffa | ||
|
17ba28c44b | ||
|
47c84fac85 | ||
|
1cf1ba1ddb | ||
|
34696c0fec | ||
|
a067e801d7 | ||
|
d01acd8030 | ||
|
0dffd2ffd2 | ||
|
0f1006bf08 | ||
|
f69ed07ba7 | ||
|
9591649ec6 | ||
|
e9abd83412 | ||
|
4de54fbee6 | ||
|
77a83f4ffc | ||
|
d613d29839 | ||
|
c7c5f68a84 | ||
|
d9f4d069e6 | ||
|
eb8bb01c57 | ||
|
7e91c401d3 | ||
|
54790f032e | ||
|
08956eb4fb | ||
|
289d963ba5 | ||
|
5e3cadec20 | ||
|
84311b3888 | ||
|
9b5b6fab5b | ||
|
e4d692bf7a | ||
|
434a23b478 | ||
|
0ee03080c3 | ||
|
754d65ad54 | ||
|
29dc94c3d6 | ||
|
c4869a5473 | ||
|
a27661cd0b | ||
|
ba8ed132a8 | ||
|
4287f1ba0e | ||
|
94e9281404 | ||
|
c7eba0a439 | ||
|
c5dbf851f6 | ||
|
6c700f7b6c | ||
|
6b465d6a77 | ||
|
e535f53981 | ||
|
7c120ecb58 | ||
|
a3feae60aa | ||
|
844ca65a8f | ||
|
04eb33e039 | ||
|
fb216a2a98 | ||
|
17dca6f791 | ||
|
e12939582c | ||
|
9b23265dde | ||
|
733cf12663 | ||
|
83e3d9c135 | ||
|
90d15e6633 | ||
|
17d7dca9ae | ||
|
be83c2861e | ||
|
e424859ecb | ||
|
804a1a4f43 | ||
|
eed1cc81ff | ||
|
b59ca5142a | ||
|
a0c77e216d | ||
|
d9ef3ff147 | ||
|
bba2bfdcf4 | ||
|
cedd9f9ac4 | ||
|
8fb3b7b1a8 | ||
|
82c41cb739 | ||
|
9007c40954 | ||
|
8b52bbd9a9 | ||
|
b82ee6bc90 | ||
|
48c6db1963 | ||
|
e82d4f2eda | ||
|
bcba3ee4a9 | ||
|
06f24d3269 | ||
|
bb761e4b38 | ||
|
2d63021344 | ||
|
e7982d594e | ||
|
655014ac9c | ||
|
9ffa923bc1 | ||
|
d259d5c511 | ||
|
488df7e6f7 | ||
|
e0619ca7d5 | ||
|
4b92415442 | ||
|
501fd09228 | ||
|
0d97871893 | ||
|
4fe8fd8944 | ||
|
23534ab174 | ||
|
7d2afcff06 | ||
|
e271c16f6c | ||
|
361dc9c234 | ||
|
024152b03e | ||
|
c30e165c1c | ||
|
54f577a970 | ||
|
02d9a1d3cf | ||
|
3bb8c2bf19 | ||
|
d1c9d94174 | ||
|
75e786da11 | ||
|
27c143a3a3 | ||
|
4045406ed8 | ||
|
c1a12edbe9 | ||
|
91a63fe0e6 | ||
|
2dd3c7bae2 | ||
|
de834264ab | ||
|
f8f2ab2016 | ||
|
eafc634eba | ||
|
d9cce4d5e8 | ||
|
ca9d8cd0ae | ||
|
ed156076a2 | ||
|
6a9b2b8224 | ||
|
266fe17461 | ||
|
e3804183f7 | ||
|
b1ed55a18f | ||
|
d594b42976 | ||
|
d6440d716c | ||
|
5c07d6170f | ||
|
946ccab778 | ||
|
ad6c1eb11b | ||
|
8def28dee9 | ||
|
c832cb04e7 | ||
|
d00607f71a | ||
|
8039e2b26a | ||
|
f43101fd9f | ||
|
fcb2a609fc | ||
|
728e955193 | ||
|
3f28e728e9 | ||
|
98e3858f7c | ||
|
bb4151377f | ||
|
d4cd81fa36 | ||
|
73b4612ec7 | ||
|
5cb501049a | ||
|
efa889156f | ||
|
b4ac52d1f5 | ||
|
71b67beb98 | ||
|
92d6056711 | ||
|
73624826b6 | ||
|
59dc225568 | ||
|
1d0e45bdbb | ||
|
8970160f1d | ||
|
2bc2db1140 | ||
|
a4caec29b9 | ||
|
181466549b | ||
|
07b4e5726e | ||
|
88e44d1c12 | ||
|
a1d4649795 | ||
|
4f36c1ddf8 | ||
|
f9d343af3e | ||
|
d4ae308f9f | ||
|
166eb3ee3e | ||
|
b343ebe06f | ||
|
d144f9d54b | ||
|
761e0230d4 | ||
|
39fbffd3d2 | ||
|
c13778139f | ||
|
b7e7aa3f9a | ||
|
485105221e | ||
|
397fbd5749 | ||
|
7b1eb6e6e3 | ||
|
80064c18a9 | ||
|
8845a22226 | ||
|
c4b6b42dcf | ||
|
5dafc0828c | ||
|
e7e1bfdb53 | ||
|
99a5fdb6f8 | ||
|
f4117aa1b4 | ||
|
f28f05952f | ||
|
7307f086c6 | ||
|
e1a928beb1 | ||
|
28623e6b27 | ||
|
e2d3161442 | ||
|
59282b6f66 | ||
|
7274f55ff4 | ||
|
3f54fba986 | ||
|
7ccbdd98c0 | ||
|
f69f29a660 | ||
|
b076d5cea1 | ||
|
554e34517e | ||
|
9e98cfa220 | ||
|
64f756d627 | ||
|
88cce08ce4 | ||
|
da15cc3cb7 | ||
|
356325f563 | ||
|
a93e57e112 | ||
|
79066c950f | ||
|
9de69bb3ab | ||
|
9ebc44bcea | ||
|
db1f13db25 | ||
|
a9854e9b37 | ||
|
01583560cd | ||
|
f66caa0d29 | ||
|
95288bcf75 | ||
|
e58b7d623b | ||
|
ff79108f66 | ||
|
a76a559656 | ||
|
dd28fa5743 | ||
|
a297c8c8ad | ||
|
698cfeb1f4 | ||
|
35687018eb | ||
|
a6f9701368 | ||
|
237d6b89f6 | ||
|
2b89a07dae | ||
|
863a41daac | ||
|
49122b50b6 | ||
|
2fcd4a878a | ||
|
6308506276 | ||
|
6dff2a9f31 | ||
|
f7670fcd44 | ||
|
3df692ecb2 | ||
|
5c8e277663 | ||
|
2d4a503135 | ||
|
e1a1865de9 | ||
|
8084a75634 | ||
|
36836d0746 | ||
|
cfdf55855e | ||
|
1845d71f00 | ||
|
0d78331149 | ||
|
c7bc4b6a5d | ||
|
5eb43a1ddb | ||
|
be534a9c5e | ||
|
72bd825a60 | ||
|
6d6a67b44b | ||
|
0c63903071 | ||
|
b887a8d355 | ||
|
41719c5559 | ||
|
3cfd8226ba | ||
|
a0dbb2a787 | ||
|
ea4b232996 | ||
|
5ea01030e2 | ||
|
d987a8dd8c | ||
|
4b8c4990dc | ||
|
711a87f7ba | ||
|
53f022d29b | ||
|
04eab8e1f8 | ||
|
2a0d608b07 | ||
|
1b49823f64 | ||
|
de83dbb7e2 | ||
|
c0437e7b25 | ||
|
891633322a | ||
|
f7b4697280 | ||
|
42ebcac329 | ||
|
21a702dc1e | ||
|
6454d0bc96 | ||
|
df575eb090 | ||
|
7f1a560288 | ||
|
90534b3cf6 | ||
|
87acd99fe4 | ||
|
cb4cff2c71 | ||
|
c3fd198f0d | ||
|
36ad6efc6f | ||
|
f0dd8c9517 | ||
|
517d5b5b31 | ||
|
0ab10fee0b | ||
|
ff30259354 | ||
|
e453740aca | ||
|
67c9003522 | ||
|
f880734050 | ||
|
e4421799ba | ||
|
8e438b9e5f | ||
|
cfbe9f1c94 | ||
|
8089e05a00 | ||
|
f121350fc9 | ||
|
494524dd85 | ||
|
4f52a7b235 | ||
|
c4874fdf44 | ||
|
f9414d5826 | ||
|
923edc7f7e | ||
|
96bec7e3fb | ||
|
877a6e694c | ||
|
da2fb7f210 | ||
|
1f67bab475 | ||
|
f87dff8d83 | ||
|
ac7c1057cc | ||
|
cddf02f174 | ||
|
1330288271 | ||
|
8c8aa980cf | ||
|
f98b7274b4 | ||
|
a83700d1cf | ||
|
8da2dee0c4 | ||
|
1b26ff560d | ||
|
52bffa70cf | ||
|
2b0e255c40 | ||
|
61efe26348 | ||
|
fa5e69e3be | ||
|
ea92c8b8c8 | ||
|
23f942ac8c | ||
|
04d1c9805b | ||
|
b6fbf86743 | ||
|
61e237ec87 | ||
|
d6ade4d94e | ||
|
5abb288c7a | ||
|
fa561c8d66 | ||
|
be3bfc48a8 | ||
|
65f08cd46d | ||
|
b1ac4187b9 | ||
|
637d76b585 | ||
|
5288eef617 | ||
|
beaccf2714 | ||
|
21b80949ff | ||
|
f55ad67b1b | ||
|
806787529f | ||
|
cf5b4afb38 | ||
|
d6b24c00c8 | ||
|
99f9557cc0 | ||
|
c85c946ce3 | ||
|
9ec7d05d8d | ||
|
2d293ec755 | ||
|
299da8627c | ||
|
a6a8606edb | ||
|
db17f2caa8 | ||
|
739941dc5f | ||
|
2982888b66 | ||
|
f85c54be97 | ||
|
6d6cfd6c98 | ||
|
fb8492a7e5 | ||
|
58f153e12b | ||
|
a025c9a7bd | ||
|
f89b07d892 | ||
|
e6a9a1a366 | ||
|
7859a2aabd | ||
|
cfb784d428 | ||
|
3aa6f16964 | ||
|
43770736f1 | ||
|
560a046a22 | ||
|
aeae9f7cde | ||
|
0df44e205b | ||
|
d70fa8c7f6 | ||
|
c776e7a9a6 | ||
|
8e2f6937d5 | ||
|
165560edd8 | ||
|
4eb336277c | ||
|
3b8502c2e5 | ||
|
d4dc3b2717 | ||
|
42f590ce0b | ||
|
09c000eca8 | ||
|
c49c895f39 | ||
|
2b06f045c4 | ||
|
5f76169b95 | ||
|
98c92a6d18 | ||
|
272a45df12 | ||
|
aa0d8f4b5d | ||
|
020600aa56 | ||
|
1ca9f234f7 | ||
|
7365a44989 | ||
|
6dbb5ff7ee | ||
|
fdc654cfb3 | ||
|
de26ba6f73 | ||
|
28a966a3e6 | ||
|
13e8a262e4 | ||
|
f796b774bd | ||
|
518529a772 | ||
|
14498decd9 | ||
|
93d4c65948 | ||
|
3cec441833 | ||
|
b5172cf6df | ||
|
01f8628aed | ||
|
170fe0c368 | ||
|
4c5ce0b16a | ||
|
0f1fe9e438 | ||
|
bd5f4c6ed5 | ||
|
0870b778c0 | ||
|
32db38ecf2 | ||
|
41788f923b | ||
|
98b4ec58bc | ||
|
633c6a2e81 | ||
|
dd6aadc54d | ||
|
e65ee7124b | ||
|
0a7bfd5923 | ||
|
17dfec3572 | ||
|
5c7e0eedb0 | ||
|
07c3699225 | ||
|
e318f884bf | ||
|
c9a419e44b | ||
|
e3fd12ebc6 | ||
|
575c25e570 | ||
|
48a79ff9da | ||
|
752bc26536 | ||
|
acec489647 | ||
|
9e1b7fdac0 | ||
|
8903026c14 | ||
|
f45c56af83 | ||
|
3b6432912d | ||
|
7df314e265 | ||
|
e1329499de | ||
|
77025d4b6b | ||
|
cda83d3084 | ||
|
bf548e92c0 | ||
|
9ac5adfcef | ||
|
139e5d7e22 | ||
|
d78d7838d3 | ||
|
636bcee355 | ||
|
653d486ee2 | ||
|
03a7b06eb8 | ||
|
824a1d8abc | ||
|
27ef4569ca | ||
|
e68dd25813 | ||
|
9d55128ab8 | ||
|
f71e18948a | ||
|
e6823f39de | ||
|
80154c5c7a | ||
|
3ee31473c6 | ||
|
62d9f60f03 | ||
|
26a23dd1cb | ||
|
19e1fddba2 | ||
|
35bcb4f7c6 | ||
|
e9c02296f2 | ||
|
f18be6ef7a | ||
|
2c33cde63f | ||
|
d75f3124b9 | ||
|
99142d1c0e | ||
|
59dc1b7eb4 | ||
|
1f7a716710 | ||
|
976c763747 | ||
|
18673d9a56 | ||
|
0995fe1288 | ||
|
f76a7c4e92 | ||
|
f15b1d7763 | ||
|
73e6b540b2 | ||
|
c161521c26 | ||
|
776861c6a0 | ||
|
cdd07544d5 | ||
|
80ddafc2f8 | ||
|
3270138ec2 | ||
|
77c4f9d702 | ||
|
9cd3193a89 | ||
|
0ffb4f7b18 | ||
|
5bc743d221 | ||
|
1d707efa47 | ||
|
8b929c12c9 | ||
|
3d92b82678 | ||
|
6e2a074064 | ||
|
0f5fb6b9a0 | ||
|
752d14ca3e | ||
|
ba26adce53 | ||
|
7ccf0d3e03 | ||
|
87b546777a | ||
|
4108b649c2 | ||
|
817c62d7fd | ||
|
877b4be8ee | ||
|
91d1ef8bf6 | ||
|
44bfb62715 | ||
|
c456fc7f61 | ||
|
159196c2ad | ||
|
9bb2807706 | ||
|
a254bc6308 | ||
|
ceaee2a11e | ||
|
dc8924a2bc | ||
|
9bba3165fb | ||
|
4d18496a6f | ||
|
014abf6cc9 | ||
|
be40d2b851 | ||
|
747336e927 | ||
|
38bc5bbf82 | ||
|
2fdd94adeb | ||
|
0ae65cc10f | ||
|
a01642e480 | ||
|
6b9b502354 | ||
|
8606b78b9e | ||
|
cd325dfe52 | ||
|
c1b3d0c629 | ||
|
94238fd95b | ||
|
5c835bc0f6 | ||
|
100fc2e7d4 | ||
|
880e977fb6 | ||
|
3a9b0eee7a | ||
|
6baf90ac4c | ||
|
77064754ad | ||
|
92ed79e68e | ||
|
b91a975d56 | ||
|
84b6818982 | ||
|
4aee9fe2a3 | ||
|
4847e0d1e6 | ||
|
a599b989cf | ||
|
50658a5c0a | ||
|
f828fc1ac1 | ||
|
bd71ca2a3c | ||
|
2d38c9614e | ||
|
7ce265f2cf | ||
|
638299534b | ||
|
919a005b65 | ||
|
58865ca5ec | ||
|
d62d82bb2f | ||
|
f1ecd66283 | ||
|
fd2cb4b8d2 | ||
|
1cc3e05c11 | ||
|
d5b6d4ab12 |
40
.gitattributes
vendored
Normal file
40
.gitattributes
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Text for humans
|
||||||
|
LICENSE text eol=lf
|
||||||
|
HACKING text eol=lf
|
||||||
|
COPYING text eol=lf
|
||||||
|
UsingSWO text eol=lf
|
||||||
|
README.* text eol=lf
|
||||||
|
|
||||||
|
# Source code
|
||||||
|
Makefile text eol=lf
|
||||||
|
*.mk text eol=lf
|
||||||
|
*.mak text eol=lf
|
||||||
|
*.inc text eol=lf
|
||||||
|
*.py text eol=lf
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.c text eol=lf
|
||||||
|
*.S text eol=lf
|
||||||
|
*.s text eol=lf
|
||||||
|
*.h text eol=lf
|
||||||
|
*.ld text eol=lf
|
||||||
|
*.yml text eol=lf
|
||||||
|
*.rules text eol=lf
|
||||||
|
|
||||||
|
# Git control files
|
||||||
|
.gitattributes eol=lf
|
||||||
|
.gitignore eol=lf
|
||||||
|
.gitmodules eol=lf
|
||||||
|
|
||||||
|
# Windows source code uses CRLF
|
||||||
|
*.vcxproj text eol=crlf
|
||||||
|
*.props text eol=crlf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.ps1 text eol=crlf
|
||||||
|
*.inf text eol=crlf
|
||||||
|
|
||||||
|
# Other binary files
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.bin binary
|
||||||
|
*.elf binary
|
||||||
|
*.bin binary
|
2
.github/FUNDING.yml
vendored
Normal file
2
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
github: [esden, dragonmux]
|
||||||
|
patreon: 1bitsquared
|
36
.github/workflows/build-and-upload.yml
vendored
Normal file
36
.github/workflows/build-and-upload.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
name: build and upload
|
||||||
|
|
||||||
|
# Controls when the workflow will run
|
||||||
|
on:
|
||||||
|
# Triggers the workflow on push or pull request events but only for the main branch
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||||
|
jobs:
|
||||||
|
# This workflow contains a single job called "build"
|
||||||
|
build:
|
||||||
|
# The type of runner that the job will run on
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
|
steps:
|
||||||
|
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# Use embedded toolchain
|
||||||
|
- uses: numworks/setup-arm-toolchain@2020-q4
|
||||||
|
|
||||||
|
# Runs a single command using the runners shell
|
||||||
|
- name: Build
|
||||||
|
run: make
|
||||||
|
|
||||||
|
- name: Archive firmware build artifacts as a zip
|
||||||
|
uses: actions/upload-artifact@v2.2.4
|
||||||
|
with:
|
||||||
|
name: blackmagic-firmware.zip
|
||||||
|
path: src/blackmagic*
|
||||||
|
if-no-files-found: error
|
38
.github/workflows/build-pr.yml
vendored
Normal file
38
.github/workflows/build-pr.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
name: build PR
|
||||||
|
|
||||||
|
# Controls when the workflow will run
|
||||||
|
on:
|
||||||
|
# Triggers the workflow on push or pull request events but only for the main branch
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||||
|
jobs:
|
||||||
|
# This workflow contains a single job called "build"
|
||||||
|
build:
|
||||||
|
# The type of runner that the job will run on
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
|
steps:
|
||||||
|
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# Use embedded toolchain
|
||||||
|
- uses: numworks/setup-arm-toolchain@2020-q4
|
||||||
|
|
||||||
|
# Run some of the most common build types
|
||||||
|
- name: Build native fw
|
||||||
|
run: make
|
||||||
|
|
||||||
|
- name: Clean
|
||||||
|
run: make clean
|
||||||
|
|
||||||
|
- name: Install BMP PC hosted dependencies
|
||||||
|
run: sudo apt-get -y install libftdi1-dev libhidapi-dev
|
||||||
|
|
||||||
|
- name: Build PC hosted binary
|
||||||
|
run: make PROBE_HOST=hosted
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -16,5 +16,10 @@ tags
|
|||||||
*.b#*
|
*.b#*
|
||||||
blackmagic_upgrade
|
blackmagic_upgrade
|
||||||
*.exe
|
*.exe
|
||||||
|
.DS_Store
|
||||||
*.elf
|
*.elf
|
||||||
.vscode
|
.vscode
|
||||||
|
cscope.out
|
||||||
|
cscope.files
|
||||||
|
.gdb_history
|
||||||
|
src/artifacts/
|
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,3 +1,3 @@
|
|||||||
[submodule "libopencm3"]
|
[submodule "libopencm3"]
|
||||||
path = libopencm3
|
path = libopencm3
|
||||||
url = https://github.com/libopencm3/libopencm3.git
|
url = https://github.com/flirc/libopencm3.git
|
||||||
|
35
.travis.yml
35
.travis.yml
@ -1,42 +1,11 @@
|
|||||||
dist: trusty
|
dist: bionic
|
||||||
sudo: required
|
sudo: required
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa
|
- sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa
|
||||||
- sudo apt-get update -qq
|
- sudo apt-get update -qq
|
||||||
- pip install --user intelhex
|
- pip install --user intelhex
|
||||||
- gpg --recv-keys 3CEA9B8868BC3852618EB5B4707F91A424F006F5
|
- sudo apt-get install -y build-essential libboost-all-dev gcc-arm-embedded libusb-1.0-0-dev libhidapi-dev libftdi1 libftdi1-dev
|
||||||
- wget http://www.intra2net.com/en/developer/libftdi/download/libftdi1-1.2.tar.bz2
|
|
||||||
- wget http://www.intra2net.com/en/developer/libftdi/download/libftdi1-1.2.tar.bz2.sig
|
|
||||||
- gpg --trust-model always --verify libftdi1-1.2.tar.bz2.sig
|
|
||||||
- tar -xjf libftdi1-1.2.tar.bz2
|
|
||||||
- sudo apt-get install -y build-essential libboost-all-dev gcc-arm-embedded libusb-1.0-0-dev libhidapi-dev
|
|
||||||
|
|
||||||
install:
|
|
||||||
- cd libftdi1-1.2
|
|
||||||
- if [ "$TRAVIS_OS_NAME" = "linux" ];
|
|
||||||
then
|
|
||||||
sudo apt-get update -qq;
|
|
||||||
if [ "$ARCH" = "x86_64" ];
|
|
||||||
then
|
|
||||||
sudo apt-get install -qq libusb-1.0-0-dev;
|
|
||||||
elif [ "$ARCH" = "i386" ];
|
|
||||||
then
|
|
||||||
sudo apt-get install -qq gcc-multilib libusb-1.0-0-dev:i386 pkg-config:i386;
|
|
||||||
export CFLAGS="-m32";
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
- if [ "$TRAVIS_OS_NAME" = "osx" ];
|
|
||||||
then
|
|
||||||
brew update;
|
|
||||||
brew install libusb;
|
|
||||||
fi
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- cmake ../
|
|
||||||
- make
|
|
||||||
- sudo make install
|
|
||||||
- cd ../../
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- make -C libopencm3 lib
|
- make -C libopencm3 lib
|
||||||
|
2
HACKING
2
HACKING
@ -1 +1 @@
|
|||||||
See https://github.com/blacksphere/blackmagic/wiki/Hacking
|
See https://github.com/blackmagic-debug/blackmagic/wiki/Hacking
|
||||||
|
20
Makefile
20
Makefile
@ -5,14 +5,6 @@ endif
|
|||||||
|
|
||||||
PC_HOSTED =
|
PC_HOSTED =
|
||||||
NO_LIBOPENCM3 =
|
NO_LIBOPENCM3 =
|
||||||
ifeq ($(PROBE_HOST), libftdi)
|
|
||||||
PC_HOSTED = true
|
|
||||||
NO_LIBOPENCM3 = true
|
|
||||||
endif
|
|
||||||
ifeq ($(PROBE_HOST), pc-stlinkv2)
|
|
||||||
PC_HOSTED = true
|
|
||||||
NO_LIBOPENCM3 = true
|
|
||||||
endif
|
|
||||||
ifeq ($(PROBE_HOST), hosted)
|
ifeq ($(PROBE_HOST), hosted)
|
||||||
PC_HOSTED = true
|
PC_HOSTED = true
|
||||||
NO_LIBOPENCM3 = true
|
NO_LIBOPENCM3 = true
|
||||||
@ -25,13 +17,23 @@ ifndef NO_LIBOPENCM3
|
|||||||
git submodule init ;\
|
git submodule init ;\
|
||||||
git submodule update ;\
|
git submodule update ;\
|
||||||
fi
|
fi
|
||||||
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib
|
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib/sam/d
|
||||||
endif
|
endif
|
||||||
$(Q)$(MAKE) $(MFLAGS) -C src
|
$(Q)$(MAKE) $(MFLAGS) -C src
|
||||||
|
|
||||||
|
all_platforms:
|
||||||
|
$(Q)$(MAKE) $(MFLAGS) -C src $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
ifndef NO_LIBOPENCM3
|
ifndef NO_LIBOPENCM3
|
||||||
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 $@
|
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 $@
|
||||||
endif
|
endif
|
||||||
$(Q)$(MAKE) $(MFLAGS) -C src $@
|
$(Q)$(MAKE) $(MFLAGS) -C src $@
|
||||||
|
|
||||||
|
clang-tidy:
|
||||||
|
$(Q)scripts/run-clang-tidy.py -s "$(PWD)"
|
||||||
|
|
||||||
|
clang-format:
|
||||||
|
$(Q)$(MAKE) $(MFLAGS) -C src $@
|
||||||
|
|
||||||
|
.PHONY: clean all_platforms clang-tidy clang-format
|
||||||
|
153
README.md
153
README.md
@ -1,111 +1,54 @@
|
|||||||
Black Magic Probe
|
Jeff Probe
|
||||||
=================
|
==========
|
||||||
|
|
||||||
[](https://travis-ci.org/blacksphere/blackmagic)
|
This is a fork of the [original Black Magic Probe](https://github.com/blacksphere/blackmagic).
|
||||||
[](https://discord.gg/P7FYThy)
|
|
||||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=N84QYNAM2JJQG)
|
|
||||||
[](https://www.kickstarter.com/projects/esden/1bitsy-and-black-magic-probe-demystifying-arm-prog)
|
|
||||||
|
|
||||||
Firmware for the Black Magic Debug Probe.
|
The original is arguably better, faster and wider supported. However, this
|
||||||
|
project was a way to offer an affordable version and I'll rely on community
|
||||||
|
support and pull requests.
|
||||||
|
|
||||||
The Black Magic Probe is a modern, in-application debugging tool for
|
One urguably better funncton is the ability to do DEBUG and Serial communication
|
||||||
embedded microprocessors. It allows you see what is going on 'inside' an
|
over a single JTAG cable when paired with a device that uses single wire JTAG.
|
||||||
application running on an embedded microprocessor while it executes. It is
|
|
||||||
able to control and examine the state of the target microprocessor using a
|
Normally, the serial header can be used on a target for the serial port, and
|
||||||
JTAG or Serial Wire Debugging (SWD) port and on-chip debug logic provided
|
shows up as the second serial device on the system, however, we can dynamically
|
||||||
by the microprocessor. The probe connects to a host computer using a
|
change the pins to use the ones on the JTAG cable with the following command:
|
||||||
standard USB interface. The user is able to control exactly what happens
|
|
||||||
using the GNU source level debugging software, GDB.
|
``` bash
|
||||||
Serial Wire Output (SWO) allows the target to write tracing and logging to the host
|
$ mon convert_tdio enable
|
||||||
without using usb or serial port. Decoding SWO in the probe itself
|
```
|
||||||
makes [SWO viewing as simple as connecting to a serial port](https://github.com/blacksphere/blackmagic/wiki/Serial-Wire-Output).
|
|
||||||
|
Compilation
|
||||||
|
---
|
||||||
|
|
||||||
|
Newer toolchains can cause issues. I usually work 4_9-2014q4-20141203 found [here.](https://launchpad.net/gcc-arm-embedded/4.9/4.9-2014-q4-major/+download/gcc-arm-none-eabi-4_9-2014q4-20141203-mac.tar.bz2)
|
||||||
|
|
||||||
|
the versionfollowing version
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ make clean
|
||||||
|
$ make PROBE_HOST=jeff CUSTOM_SER=1
|
||||||
|
$ dfu-util --device ,1d50:6017 -s 0x00002000:leave -D src/blackmagic.bin
|
||||||
|
```
|
||||||
|
|
||||||
|
CUSTOM OPTIONS
|
||||||
|
---
|
||||||
|
|
||||||
|
On mac, our device shows up with a serial number /dev/tty.cuJEFF123HDC
|
||||||
|
|
||||||
|
This can be annoy if we want to autocnnect with a gith script. We can override
|
||||||
|
the use of a serial number by doing a custom compliation such that our device
|
||||||
|
shows up with the following: /dev/cu.usbmodemJEFF1 and /dev/cu.usbmodemJEFF3
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ make PROBE_HOST=jeff CUSTOM_SER=1
|
||||||
|
```
|
||||||
|
|
||||||
|
More
|
||||||
|
---
|
||||||
|
|
||||||
|
More helpful information can be found on the black magic probe [readme](https://github.com/blacksphere/blackmagic/blob/master/README.md#black-magic-probe), which is relevant.
|
||||||
|
|
||||||
See online documentation at https://github.com/blacksphere/blackmagic/wiki
|
See online documentation at https://github.com/blacksphere/blackmagic/wiki
|
||||||
|
|
||||||
Binaries from the latest automated build are at http://builds.blacksphere.co.nz/blackmagic
|
Binaries from the latest automated build can be found on the release page.
|
||||||
|
|
||||||
Toolchain specific remarks
|
|
||||||
==========================
|
|
||||||
Most firmware building is done with the most recent suite from https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm.
|
|
||||||
If you have a toolchain from other sources and find problems, check if it is a failure of your toolchain and if not open an issue or better provide a pull request with a fix.
|
|
||||||
|
|
||||||
OS specific remarks for BMP-Hosted
|
|
||||||
==================================
|
|
||||||
Most hosted building is done on and for Linux. BMP-hosted for windows can also be build with Mingw on Linux.
|
|
||||||
On BSD/Macos, using dev/tty.usbmodemXXX should work but unresolved discussions indicate a hanging open() call on the second invocation. If that happens, try with cu.usbmodemXXX.
|
|
||||||
|
|
||||||
Reporting problems
|
|
||||||
==================
|
|
||||||
Before reporting issues, check against the latest git version. If possible, test against another target /and/or debug probe. Consider broken USB cables and connectors. Try to reproduce with bmp-hosted with at least debug bit 1 set (blackmagic -v 1 ...), as debug messages will be dumped to the starting console. When reporting issues, be as specific as possible!
|
|
||||||
|
|
||||||
Sample Session
|
|
||||||
=============
|
|
||||||
```console
|
|
||||||
> arm-none-eabi-gdb gpio.elf
|
|
||||||
...<GDB Copyright message>
|
|
||||||
(gdb) tar ext /dev/ttyACM0
|
|
||||||
Remote debugging using /dev/ttyACM0
|
|
||||||
(gdb) mon s
|
|
||||||
Target voltage: 2.94V
|
|
||||||
Available Targets:
|
|
||||||
No. Att Driver
|
|
||||||
1 STM32F40x M3/M4
|
|
||||||
(gdb) att 1
|
|
||||||
Attaching to program: /devel/en_apps/gpio/f4_discovery/gpio.elf, Remote target
|
|
||||||
0x08002298 in UsartIOCtl ()
|
|
||||||
(gdb) load
|
|
||||||
Loading section .text, size 0x5868 lma 0x8000000
|
|
||||||
Loading section .data, size 0x9e0 lma 0x8005868
|
|
||||||
Loading section .rodata, size 0x254 lma 0x8006248
|
|
||||||
Start address 0x800007c, load size 25756
|
|
||||||
Transfer rate: 31 KB/sec, 919 bytes/write.
|
|
||||||
(gdb) b main
|
|
||||||
Breakpoint 1 at 0x80000e8: file /devel/en_apps/gpio/f4_discovery/../gpio.c, line 70.
|
|
||||||
(gdb) r
|
|
||||||
Starting program: /devel/en_apps/gpio/f4_discovery/gpio.elf
|
|
||||||
Note: automatically using hardware breakpoints for read-only addresses.
|
|
||||||
|
|
||||||
Breakpoint 1, main () at /devel/en_apps/gpio/f4_discovery/../gpio.c:70
|
|
||||||
70 {
|
|
||||||
```
|
|
||||||
|
|
||||||
BLACKMAGIC
|
|
||||||
==========
|
|
||||||
|
|
||||||
You can also build blackmagic as a PC hosted application
|
|
||||||
"make PROBE_HOST=hosted"
|
|
||||||
|
|
||||||
This builds the same GDB server, that is running on the Black Magic Probe.
|
|
||||||
While connection to the Black Magic Probe GDB server is via serial line,
|
|
||||||
connection to the PC-Hosted GDB server is via TCP port 2000 for the first
|
|
||||||
GDB server and higher for more invokations. Use "tar(get) ext(ented) :2000"
|
|
||||||
to connect.
|
|
||||||
PC-hosted BMP GDB server can talk to
|
|
||||||
- Black Magic Probe firmware probes via the USB-serial port
|
|
||||||
- ST-LinkV2 and V3 with recent firmware
|
|
||||||
- CMSIS-DAP compatible probes
|
|
||||||
- JLINK probes
|
|
||||||
- FTDI MPSSE based probe.
|
|
||||||
|
|
||||||
When connected to a single BMP supported probe, starting "blackmagic" w/o any
|
|
||||||
arguments starts the server. When several BMP supported probes are connected,
|
|
||||||
their types, position and serial number is displayed and the program exits.
|
|
||||||
Add "-P (position)" to the next invocation to select one.
|
|
||||||
For the setup from the sample session above:
|
|
||||||
In another terminal:
|
|
||||||
```console
|
|
||||||
> blackmagic
|
|
||||||
Using 1d50:6018 E2E489E7 Black Sphere Technologies Black Magic Probe (STLINK), (Firmware v1.6.1-477-g70bb131-dirty)
|
|
||||||
Remote is Black Magic Probe (STLINK), (Firmware v1.6.1-477-g70bb131-dirty) v1.6.1-477-g70bb131-dirty
|
|
||||||
Listening on TCP: 2000
|
|
||||||
And in the GDB terminal:
|
|
||||||
(gdb) target ext :2000
|
|
||||||
Remote debugging using :2000
|
|
||||||
(gdb) mon s
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
PC hosted BMP also allows to flash, read and verify a binary file, by default
|
|
||||||
starting at lowest flash address. The "-t" argument displays information about the
|
|
||||||
connected target. Use "-h " to get a list of supported options.
|
|
||||||
|
|
||||||
|
271
UsingRTT.md
Normal file
271
UsingRTT.md
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
# Using RTT
|
||||||
|
|
||||||
|
When debugging arm processors, there are three ways for the target to print debug messages on the host: Semihosting, Serial Wire Output SWO, and Real-Time Transfer RTT.
|
||||||
|
|
||||||
|
[Black Magic Probe](https://github.com/blacksphere/blackmagic) (BMP) is an open source debugger probe that already implements Semihosting and Single Wire Output. This patch adds Real-Time Transfer RTT output to usb serial port.
|
||||||
|
|
||||||
|
- RTT is implemented, not as a user program, but as a serial port device. To read RTT output, use a terminal emulator and connect to the serial port.
|
||||||
|
|
||||||
|
- A novel way to detect RTT automatically, fast and convenient.
|
||||||
|
|
||||||
|
## Use
|
||||||
|
This example uses linux as operating system. For Windows and MacOS see the *Operating Systems* section.
|
||||||
|
|
||||||
|
In one window open a terminal emulator (minicom, putty) and connect to the usb uart:
|
||||||
|
```
|
||||||
|
$ minicom -c on -D /dev/ttyBmpTarg
|
||||||
|
```
|
||||||
|
|
||||||
|
In another window open a debugger:
|
||||||
|
```
|
||||||
|
$ gdb
|
||||||
|
(gdb) target extended-remote /dev/ttyBmpGdb
|
||||||
|
(gdb) monitor swdp_scan
|
||||||
|
(gdb) attach 1
|
||||||
|
(gdb) monitor rtt
|
||||||
|
(gdb) run
|
||||||
|
^C
|
||||||
|
(gdb) monitor rtt status
|
||||||
|
rtt: on found: yes ident: off halt: off channels: auto 0 1 3
|
||||||
|
max poll ms: 256 min poll ms: 8 max errs: 10
|
||||||
|
```
|
||||||
|
|
||||||
|
The terminal emulator displays RTT output from the target,
|
||||||
|
and characters typed in the terminal emulator are sent via RTT to the target.
|
||||||
|
|
||||||
|
|
||||||
|
## gdb commands
|
||||||
|
|
||||||
|
The following new gdb commands are available:
|
||||||
|
|
||||||
|
- ``monitor rtt``
|
||||||
|
|
||||||
|
switch rtt on
|
||||||
|
|
||||||
|
- ``monitor rtt enable``
|
||||||
|
|
||||||
|
switch rtt on
|
||||||
|
|
||||||
|
- ``monitor rtt disable``
|
||||||
|
|
||||||
|
switch rtt off
|
||||||
|
|
||||||
|
- ``monitor rtt poll `` max_poll_ms min_poll_ms max_errs
|
||||||
|
|
||||||
|
sets maximum time between polls, minimum time between polls, and the maximum number of errors before RTT disconnects from the target. Times in milliseconds. It is best if max_poll_ms/min_poll_ms is a power of two. As an example, if you wish to check for RTT output between once per second to eight times per second: ``monitor rtt poll 1000 125 10``.
|
||||||
|
|
||||||
|
- ``monitor rtt status``
|
||||||
|
|
||||||
|
show status.
|
||||||
|
|
||||||
|
rtt|found|state
|
||||||
|
---|---|---
|
||||||
|
rtt: off|found: no|rtt inactive
|
||||||
|
rtt: on|found: no|searching for rtt control block
|
||||||
|
rtt: on|found: yes|rtt active
|
||||||
|
rtt: off|found: yes|corrupt rtt control block, or target memory access error
|
||||||
|
|
||||||
|
A status of `rtt: on found: no` indicates bmp is still searching for the rtt control block in target ram, but has not found anything yet. A status of `rtt: on found: yes` indicates the control block has been found and rtt is active.
|
||||||
|
|
||||||
|
- ``monitor rtt channel``
|
||||||
|
|
||||||
|
enables the first two output channels, and the first input channel. (default)
|
||||||
|
|
||||||
|
- ``monitor rtt channel number...``
|
||||||
|
|
||||||
|
enables the given RTT channel numbers. Channels are numbers from 0 to 15, inclusive. Eg. ``monitor rtt channel 0 1 4`` to enable channels 0, 1, and 4.
|
||||||
|
|
||||||
|
- ``monitor rtt ident string``
|
||||||
|
|
||||||
|
sets RTT ident to *string*. If *string* contains a space, replace the space with an underscore _. Setting ident string is optional, RTT works fine without.
|
||||||
|
|
||||||
|
- ``monitor rtt ident``
|
||||||
|
|
||||||
|
clears ident string. (default)
|
||||||
|
|
||||||
|
- ``monitor rtt cblock``
|
||||||
|
|
||||||
|
shows rtt control block data, and which channels are enabled. This is an example control block:
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) mon rtt cb
|
||||||
|
cbaddr: 0x200000a0
|
||||||
|
ch ena cfg i/o buf@ size head@ tail@ flg
|
||||||
|
0 y y out 0x20000148 1024 0x200000c4 0x200000c8 2
|
||||||
|
1 y n out 0x00000000 0 0x200000dc 0x200000e0 0
|
||||||
|
2 n n out 0x00000000 0 0x200000f4 0x200000f8 0
|
||||||
|
3 y y in 0x20000548 16 0x2000010c 0x20000110 0
|
||||||
|
4 n n in 0x00000000 0 0x20000124 0x20000128 0
|
||||||
|
5 n n in 0x00000000 0 0x2000013c 0x20000140 0
|
||||||
|
6 n n in 0x00000000 0 0x00000000 0x00000000 0
|
||||||
|
7 n n in 0x00000000 0 0x00000000 0x00000000 0
|
||||||
|
8 n n in 0x00000000 0 0x00000000 0x00000000 0
|
||||||
|
9 n n in 0x00000000 0 0x00000000 0x00000000 0
|
||||||
|
10 n n in 0x00000000 0 0x00000000 0x00000000 0
|
||||||
|
11 n n in 0x00000000 0 0x00000000 0x00000000 0
|
||||||
|
12 n n in 0x00000000 0 0x00000000 0x00000000 0
|
||||||
|
13 n n in 0x00000000 0 0x00000000 0x00000000 0
|
||||||
|
14 n n in 0x00000000 0 0x00000000 0x00000000 0
|
||||||
|
15 n n in 0x00000000 0 0x00000000 0x00000000 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Channels are listed, one channel per line. The columns are: channel, enabled, configured, input/output, buffer address, buffer size, address of head pointer, address of tail pointer, flag. Each channel is a circular buffer with head and tail pointer.
|
||||||
|
|
||||||
|
Note the columns `ena` for enabled, `cfg` for configured.
|
||||||
|
|
||||||
|
Configured channels have a non-zero buffer address and non-zero size. Configured channels are marked yes `y` in the column `cfg` . What channels are configured depends upon target software.
|
||||||
|
|
||||||
|
Channels the user wants to see are marked yes `y` in the column enabled `ena`. The user can change which channels are shown with the `monitor rtt channel` command.
|
||||||
|
|
||||||
|
Output channels are displayed, and Input channels receive keyboard input, if they are marked yes in both *enabled* and *configured*.
|
||||||
|
|
||||||
|
The control block is cached for speed. In an interrupted program, `monitor rtt` will force a reload of the control block when the program continues.
|
||||||
|
|
||||||
|
## Identifier string
|
||||||
|
It is possible to set an RTT identifier string.
|
||||||
|
As an example, if the RTT identifier is "IDENT STR":
|
||||||
|
```
|
||||||
|
$ gdb
|
||||||
|
(gdb) target extended-remote /dev/ttyBmpGdb
|
||||||
|
(gdb) monitor swdp_scan
|
||||||
|
(gdb) attach 1
|
||||||
|
(gdb) monitor rtt ident IDENT_STR
|
||||||
|
(gdb) monitor rtt
|
||||||
|
(gdb) run
|
||||||
|
^C
|
||||||
|
(gdb) monitor rtt status
|
||||||
|
rtt: on found: yes ident: "IDENT STR" halt: off channels: auto 0 1 3
|
||||||
|
max poll ms: 256 min poll ms: 8 max errs: 10
|
||||||
|
```
|
||||||
|
Note replacing space with underscore _ in *monitor rtt ident*.
|
||||||
|
|
||||||
|
Setting an identifier string is optional. RTT gives the same output at the same speed, with or without specifying identifier string.
|
||||||
|
|
||||||
|
## Operating systems
|
||||||
|
|
||||||
|
[Configuration](https://github.com/blacksphere/blackmagic/wiki/Getting-Started) instructions for windows, linux and macos.
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
After configuration, Black Magic Probe shows up in Windows as two _USB Serial (CDC)_ ports.
|
||||||
|
|
||||||
|
Connect arm-none-eabi-gdb, the gnu debugger for arm processors, to the lower numbered of the two COM ports. Connect an ansi terminal emulator to the higher numbered of the two COM ports.
|
||||||
|
|
||||||
|
Sample gdb session:
|
||||||
|
```
|
||||||
|
(gdb) target extended-remote COM3
|
||||||
|
(gdb) monitor swdp_scan
|
||||||
|
(gdb) attach 1
|
||||||
|
(gdb) monitor rtt
|
||||||
|
(gdb) run
|
||||||
|
```
|
||||||
|
|
||||||
|
For COM port COM10 and higher, add the prefix `\\.\`, e.g.
|
||||||
|
```
|
||||||
|
target extended-remote \\.\COM10
|
||||||
|
```
|
||||||
|
|
||||||
|
Target RTT output will appear in the terminal, and what you type in the terminal will be sent to the RTT input of the target.
|
||||||
|
|
||||||
|
### linux
|
||||||
|
On linux, install [udev rules](https://github.com/blacksphere/blackmagic/blob/master/driver/99-blackmagic.rules). Disconnect and re-connect the BMP. Check the device shows up in /dev/ :
|
||||||
|
```
|
||||||
|
$ ls -l /dev/ttyBmp*
|
||||||
|
lrwxrwxrwx 1 root root 7 Dec 13 07:29 /dev/ttyBmpGdb -> ttyACM0
|
||||||
|
lrwxrwxrwx 1 root root 7 Dec 13 07:29 /dev/ttyBmpTarg -> ttyACM2
|
||||||
|
```
|
||||||
|
Connect terminal emulator to /dev/ttyBmpTarg and gdb to /dev/ttyBmpGdb .
|
||||||
|
|
||||||
|
In one window:
|
||||||
|
```
|
||||||
|
minicom -c on -D /dev/ttyBmpTarg
|
||||||
|
```
|
||||||
|
In another window :
|
||||||
|
```
|
||||||
|
gdb
|
||||||
|
(gdb) target extended-remote /dev/ttyBmpGdb
|
||||||
|
(gdb) monitor swdp_scan
|
||||||
|
(gdb) attach 1
|
||||||
|
(gdb) monitor rtt
|
||||||
|
(gdb) run
|
||||||
|
```
|
||||||
|
|
||||||
|
### MacOS
|
||||||
|
|
||||||
|
On MacOS the tty devices have different names than on linux. On connecting blackmagic to the computer 4 devices are created, 2 'tty' and 2 'cu' devices. Gdb connects to the first cu device (e.g.: `target extended-remote /dev/cu.usbmodemDDCEC9EC1`), while RTT is connected to the second tty device (`minicom -c on -D /dev/tty.usbmodemDDCEC9EC3`). In full:
|
||||||
|
|
||||||
|
In one Terminal window, connect a terminal emulator to /dev/tty.usbmodemDDCEC9EC3 :
|
||||||
|
|
||||||
|
```
|
||||||
|
minicom -c on -D /dev/tty.usbmodemDDCEC9EC3
|
||||||
|
```
|
||||||
|
In another Terminal window, connect gdb to /dev/cu.usbmodemDDCEC9EC1 :
|
||||||
|
```
|
||||||
|
gdb
|
||||||
|
(gdb) target extended-remote /dev/cu.usbmodemDDCEC9EC1
|
||||||
|
(gdb) monitor swdp_scan
|
||||||
|
(gdb) attach 1
|
||||||
|
(gdb) monitor rtt
|
||||||
|
(gdb) run
|
||||||
|
```
|
||||||
|
RTT input/output is in the window running _minicom_.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Design goal was smallest, simplest implementation that has good practical use.
|
||||||
|
|
||||||
|
- RTT code size is 3.5 kbyte - the whole debugger 110 kbyte.
|
||||||
|
|
||||||
|
- Because RTT is implemented as a serial port device, there is no need to write and maintain software for different host operating systems. A serial port works everywhere - linux, windows and mac. You can even use an Android mobile phone as RTT terminal.
|
||||||
|
|
||||||
|
- Because polling occurs between debugger probe and target, the load on the host is small. There is no constant usb traffic, there are no real-time requirements on the host.
|
||||||
|
|
||||||
|
- RTT polling frequency is adaptive and goes up and down with RTT activity. Use *monitor rtt poll* to balance response speed and target load for your use.
|
||||||
|
|
||||||
|
- Detects RTT automatically, very convenient.
|
||||||
|
|
||||||
|
- When using RTT as a terminal, sending data from host to target, you may need to change local echo, carriage return and/or line feed settings in your terminal emulator.
|
||||||
|
|
||||||
|
- Architectures such as risc-v may not allow the debugger access to target memory while the target is running. As a workaround, on these architectures RTT briefly halts the target during polling. If the target is halted during polling, `monitor rtt status` shows `halt: on`.
|
||||||
|
|
||||||
|
- Measured RTT speed.
|
||||||
|
|
||||||
|
| debugger | char/s |
|
||||||
|
| ------------------------- | ------ |
|
||||||
|
| bmp stm32f723 stlinkv3 | 49811 |
|
||||||
|
| bmp stm32f411 black pill | 50073 |
|
||||||
|
| bmp stm32f103 blue pill | 50142 |
|
||||||
|
|
||||||
|
This is the speed at which characters can be sent from target to debugger probe, in reasonable circumstances. Test target is an stm32f103 blue pill running an [Arduino sketch](https://github.com/koendv/Arduino-RTTStream/blob/main/examples/SpeedTest/SpeedTest.ino). Default *monitor rtt poll* settings on debugger. Default RTT buffer size in target and debugger. Overhead for printf() calls included.
|
||||||
|
|
||||||
|
## Compiling firmware
|
||||||
|
To compile with RTT support, add *ENABLE_RTT=1*.
|
||||||
|
|
||||||
|
Eg. for STM32F103 blue pill:
|
||||||
|
```
|
||||||
|
make clean
|
||||||
|
make PROBE_HOST=stlink ENABLE_RTT=1
|
||||||
|
```
|
||||||
|
or for the STM32F411 *[Black Pill](https://www.aliexpress.com/item/1005001456186625.html)*:
|
||||||
|
```
|
||||||
|
make clean
|
||||||
|
make PROBE_HOST=f4discovery BLACKPILL=1 ENABLE_RTT=1
|
||||||
|
```
|
||||||
|
Setting an ident string is optional. But if you wish, you can set the default RTT ident at compile time.
|
||||||
|
For STM32F103 *Blue Pill*:
|
||||||
|
```
|
||||||
|
make clean
|
||||||
|
make PROBE_HOST=stlink ENABLE_RTT=1 "RTT_IDENT=IDENT\ STR"
|
||||||
|
```
|
||||||
|
or for STM32F411 *Black Pill*:
|
||||||
|
```
|
||||||
|
make clean
|
||||||
|
make PROBE_HOST=f4discovery BLACKPILL=1 ENABLE_RTT=1 "RTT_IDENT=IDENT\ STR"
|
||||||
|
```
|
||||||
|
Note the backslash \\ before the space.
|
||||||
|
|
||||||
|
## Links
|
||||||
|
- [OpenOCD](https://openocd.org/doc/html/General-Commands.html#Real-Time-Transfer-_0028RTT_0029)
|
||||||
|
- [probe-rs](https://probe.rs/) and [rtt-target](https://github.com/mvirkkunen/rtt-target) for the _rust_ programming language.
|
||||||
|
- [RTT Stream](https://github.com/koendv/Arduino-RTTStream) for Arduino on arm processors
|
||||||
|
- [\[WIP\] RTT support - PR from katyo](https://github.com/blacksphere/blackmagic/pull/833)
|
28
UsingSWO
28
UsingSWO
@ -14,24 +14,28 @@ monitor traceswo 115200
|
|||||||
|
|
||||||
We are constrained on maximum input speed by both the capabilities of the
|
We are constrained on maximum input speed by both the capabilities of the
|
||||||
BMP STM32F103 USART and the ability to get the packets back out over the USB
|
BMP STM32F103 USART and the ability to get the packets back out over the USB
|
||||||
link. The UART baudrate is set by b=(72x10^6)/(16*d)...so for d=1 that means
|
link. The UART baudrate is set by b=(72x10^6)/d...with d >= 16 or
|
||||||
a maximum speed of 4.5Mbps. For continious streaming that turns out to be
|
a maximum speed of 4.5Mbps UART1 and 2.25 Mbps on UART2.
|
||||||
_too_ fast for the USB link, so the next available option is the 2.25Mbps
|
For continious streaming that turns out to be_too_ fast for the USB
|
||||||
that we use. ....you can safely use the 4.5Mbps setting if your debug data
|
link, so the next available option is the 2.25Mbps that we use. ....
|
||||||
|
You can safely use the 4.5Mbps setting if your debug data
|
||||||
is bursty, or if you're using a different CPU to the STM32F103 as your BMP
|
is bursty, or if you're using a different CPU to the STM32F103 as your BMP
|
||||||
host, but you potentially run the risk of losing packets if you have long
|
host, but you potentially run the risk of losing packets if you have long
|
||||||
runs of sending which the usb cannot flush in time (there's a 12K buffer, so
|
runs of sending which the usb cannot flush in time (there's a 12K buffer, so
|
||||||
the it is a pretty long run before it becomes a problem).
|
the it is a pretty long run before it becomes a problem).
|
||||||
|
|
||||||
Note that the baudrate equation means there are only certain speeds
|
Note that the baudrate equation means there are only certain speeds
|
||||||
available. The highest half dozen are;
|
available. The highest:
|
||||||
SWO uses USART1(stlink) USART2(swlink)
|
BRR USART1(stlink) USART2(swlink)
|
||||||
1 4.50 Mbps 2.25 Mbps
|
16 4.50 Mbps 2.25 Mbps
|
||||||
2 2.25 Mbps 1.125 Mbps
|
17 4.235 Mbps 2.118 Mbps
|
||||||
3 1.50 Mbps 0.75 Mbps
|
18 4.000 Mbps 2.0 Mbps
|
||||||
4 1.125 Mbps 0.5635 Mbps
|
19 3.789 Mbps 1.895 Mbps
|
||||||
5 0.900 Mbps 0.45 Mbps
|
20 3.600 Mbps 1.8 Mbps
|
||||||
6 0.750 Mbps 0.375 Mbps
|
...
|
||||||
|
24 3.0 Mbps 1.5 Mbps
|
||||||
|
...
|
||||||
|
36 2.0 Mbps 1.0 Mbps
|
||||||
|
|
||||||
...the USART will cope with some timing slip, but it's advisible to stay as
|
...the USART will cope with some timing slip, but it's advisible to stay as
|
||||||
close to these values as you can. As the speed comes down the spread between
|
close to these values as you can. As the speed comes down the spread between
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Black Magic Probe
|
# Black Magic Probe
|
||||||
# there are two connections, one for GDB and one for UART debugging
|
# there are two connections, one for GDB and one for UART debugging
|
||||||
# copy this to /etc/udev/rules.d/99-blackmagic.rules
|
# copy this to /etc/udev/rules.d/99-blackmagic.rules
|
||||||
|
# and run /usr/sbin/udevadm control --reload-rules
|
||||||
SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic GDB Server", SYMLINK+="ttyBmpGdb"
|
SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic GDB Server", SYMLINK+="ttyBmpGdb"
|
||||||
SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic UART Port", SYMLINK+="ttyBmpTarg"
|
SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic UART Port", SYMLINK+="ttyBmpTarg"
|
||||||
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="1d50", ATTR{idProduct}=="6017", MODE="0666"
|
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="1d50", ATTR{idProduct}=="6017", MODE="0666"
|
||||||
|
@ -13,17 +13,17 @@
|
|||||||
Signature="$Windows NT$"
|
Signature="$Windows NT$"
|
||||||
Class=Ports
|
Class=Ports
|
||||||
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
|
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
|
||||||
Provider=%BLACKSPHERE%
|
Provider=%BLACKMAGIC%
|
||||||
DriverVer=28/12/2011,0.0.1.1
|
DriverVer=28/12/2011,0.0.1.1
|
||||||
|
|
||||||
[Manufacturer]
|
[Manufacturer]
|
||||||
%VendorName%=DeviceList, NTamd64
|
%VendorName%=DeviceList, NTamd64
|
||||||
|
|
||||||
[Strings]
|
[Strings]
|
||||||
VendorName = "Black Sphere Technologies"
|
VendorName = "Black Magic Debug"
|
||||||
BLACKMAGICGDB = "Black Magic GDB Server"
|
BLACKMAGICGDB = "Black Magic GDB Server"
|
||||||
BLACKMAGICUART = "Black Magic UART Port"
|
BLACKMAGICUART = "Black Magic UART Port"
|
||||||
BLACKSPHERE_DISPLAY_NAME = "Black Magic Probe Driver"
|
BLACKMAGIC_DISPLAY_NAME = "Black Magic Probe Driver"
|
||||||
|
|
||||||
[DeviceList]
|
[DeviceList]
|
||||||
%BLACKMAGICGDB%=DriverInstall, USB\VID_1d50&PID_6018&Rev_0100&MI_00
|
%BLACKMAGICGDB%=DriverInstall, USB\VID_1d50&PID_6018&Rev_0100&MI_00
|
||||||
@ -55,7 +55,7 @@ HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
|
|||||||
AddService = usbser,0x0002,DriverService.nt
|
AddService = usbser,0x0002,DriverService.nt
|
||||||
|
|
||||||
[DriverService.nt]
|
[DriverService.nt]
|
||||||
DisplayName = %BLACKSPHERE_DISPLAY_NAME%
|
DisplayName = %BLACKMAGIC_DISPLAY_NAME%
|
||||||
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
|
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
|
||||||
StartType = 3 ; SERVICE_DEMAND_START
|
StartType = 3 ; SERVICE_DEMAND_START
|
||||||
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
|
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
|
||||||
@ -80,7 +80,7 @@ HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
|
|||||||
AddService = usbser,0x0002,DriverService.NTamd64
|
AddService = usbser,0x0002,DriverService.NTamd64
|
||||||
|
|
||||||
[DriverService.NTamd64]
|
[DriverService.NTamd64]
|
||||||
DisplayName = %BLACKSPHERE_DISPLAY_NAME%
|
DisplayName = %BLACKMAGIC_DISPLAY_NAME%
|
||||||
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
|
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
|
||||||
StartType = 3 ; SERVICE_DEMAND_START
|
StartType = 3 ; SERVICE_DEMAND_START
|
||||||
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
|
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
DeviceName = "Black Magic Firmware Upgrade"
|
DeviceName = "Black Magic Firmware Upgrade"
|
||||||
DeviceNameDFU = "Black Magic Probe (Upgrade)"
|
DeviceNameDFU = "Black Magic Probe (Upgrade)"
|
||||||
DeviceNameTPA = "Black Magic Trace Capture"
|
DeviceNameTPA = "Black Magic Trace Capture"
|
||||||
VendorName = "Black Sphere Technologies"
|
VendorName = "Black Magic Debug"
|
||||||
SourceName = "Black Magic Firmware Upgrade Install Disk"
|
SourceName = "Black Magic Firmware Upgrade Install Disk"
|
||||||
DeviceID = "VID_1d50&PID_6018&Rev_0100&MI_04"
|
DeviceID = "VID_1d50&PID_6018&Rev_0100&MI_04"
|
||||||
DeviceIDDFU= "VID_1d50&PID_6017&Rev_0100"
|
DeviceIDDFU= "VID_1d50&PID_6017&Rev_0100"
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 89074d6a13ed7febba04d3c421ce7bf2b7972156
|
Subproject commit 63573143ef7e1b037d1f0c5baedc5264e12562b8
|
BIN
schematic/bm-sam-a04.pdf
Normal file
BIN
schematic/bm-sam-a04.pdf
Normal file
Binary file not shown.
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
#
|
#
|
||||||
# bootprog.py: STM32 SystemMemory Production Programmer -- version 1.1
|
# bootprog.py: STM32 SystemMemory Production Programmer -- version 1.1
|
||||||
# Copyright (C) 2011 Black Sphere Technologies
|
# Copyright (C) 2011 Black Sphere Technologies
|
||||||
@ -23,107 +23,105 @@ from time import sleep
|
|||||||
|
|
||||||
class stm32_boot:
|
class stm32_boot:
|
||||||
def __init__(self, port, baud=115200):
|
def __init__(self, port, baud=115200):
|
||||||
self.serial = serial.Serial(port, baud, 8, 'E', 1,
|
self.serial = serial.Serial(port, baud, 8, 'E', 1,
|
||||||
timeout=1)
|
timeout=1)
|
||||||
|
|
||||||
# Turn on target device in SystemMemory boot mode
|
# Turn on target device in SystemMemory boot mode
|
||||||
self.serial.setDTR(1)
|
self.serial.setDTR(1)
|
||||||
sleep(0.1);
|
sleep(0.1)
|
||||||
|
|
||||||
self._sync()
|
self._sync()
|
||||||
|
|
||||||
def _sync(self):
|
def _sync(self):
|
||||||
# Send sync byte
|
# Send sync byte
|
||||||
#print "sending sync byte"
|
#print("sending sync byte")
|
||||||
self.serial.write("\x7F")
|
self.serial.write(b"\x7f")
|
||||||
self._checkack()
|
self._checkack()
|
||||||
|
|
||||||
def _sendcmd(self, cmd):
|
def _sendcmd(self, cmd):
|
||||||
if type(cmd) == int:
|
cmd = ord(cmd)
|
||||||
cmd = chr(cmd)
|
cmd = bytes((cmd, cmd ^ 0xff))
|
||||||
cmd += chr(ord(cmd) ^ 0xff)
|
#print("sendcmd:", repr(cmd))
|
||||||
#print "sendcmd:", repr(cmd)
|
|
||||||
self.serial.write(cmd)
|
self.serial.write(cmd)
|
||||||
|
|
||||||
def _send(self, data):
|
def _send(self, data):
|
||||||
csum = 0
|
csum = 0
|
||||||
for c in data: csum ^= ord(c)
|
for c in data: csum ^= c
|
||||||
data = data + chr(csum)
|
data = data + bytes((csum,))
|
||||||
#print "sending:", repr(data)
|
#print("sending:", repr(data))
|
||||||
self.serial.write(data)
|
self.serial.write(data)
|
||||||
|
|
||||||
def _checkack(self):
|
def _checkack(self):
|
||||||
ACK = "\x79"
|
ACK = b"\x79"
|
||||||
b = self.serial.read(1)
|
b = self.serial.read(1)
|
||||||
if b != ACK: raise Exception("Invalid ack: %r" % b)
|
if b != ACK: raise Exception("Invalid ack: %r" % b)
|
||||||
#print "got ack!"
|
#print("got ack!")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
self._sendcmd("\x00")
|
self._sendcmd(b"\x00")
|
||||||
self._checkack()
|
self._checkack()
|
||||||
num = ord(self.serial.read(1))
|
num = self.serial.read(1)[0]
|
||||||
data = self.serial.read(num+1)
|
data = self.serial.read(num+1)
|
||||||
self._checkack()
|
self._checkack()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def eraseall(self):
|
def eraseall(self):
|
||||||
# Send erase cmd
|
# Send erase cmd
|
||||||
self._sendcmd("\x43")
|
self._sendcmd(b"\x43")
|
||||||
self._checkack()
|
self._checkack()
|
||||||
# Global erase
|
# Global erase
|
||||||
self._sendcmd("\xff")
|
self._sendcmd(b"\xff")
|
||||||
self._checkack()
|
self._checkack()
|
||||||
|
|
||||||
def read(self, addr, len):
|
def read(self, addr, len):
|
||||||
# Send read cmd
|
# Send read cmd
|
||||||
self._sendcmd("\x11")
|
self._sendcmd(b"\x11")
|
||||||
self._checkack()
|
self._checkack()
|
||||||
# Send address
|
# Send address
|
||||||
self._send(struct.pack(">L", addr))
|
self._send(struct.pack(">L", addr))
|
||||||
self._checkack()
|
self._checkack()
|
||||||
# Send length
|
# Send length
|
||||||
self._sendcmd(chr(len-1))
|
self._sendcmd(bytes((len-1,)))
|
||||||
self._checkack()
|
self._checkack()
|
||||||
return self.serial.read(len)
|
return self.serial.read(len)
|
||||||
|
|
||||||
def write(self, addr, data):
|
def write(self, addr, data):
|
||||||
# Send write cmd
|
# Send write cmd
|
||||||
self._sendcmd("\x31")
|
self._sendcmd(b"\x31")
|
||||||
self._checkack()
|
self._checkack()
|
||||||
# Send address
|
# Send address
|
||||||
self._send(struct.pack(">L", addr))
|
self._send(struct.pack(">L", addr))
|
||||||
self._checkack()
|
self._checkack()
|
||||||
# Send data
|
# Send data
|
||||||
self._send(chr(len(data)-1) + data)
|
self._send(bytes((len(data)-1,)) + data)
|
||||||
self._checkack()
|
self._checkack()
|
||||||
|
|
||||||
|
|
||||||
def write_protect(self, sectors):
|
def write_protect(self, sectors):
|
||||||
# Send WP cmd
|
# Send WP cmd
|
||||||
self._sendcmd("\x63")
|
self._sendcmd(b"\x63")
|
||||||
self._checkack()
|
self._checkack()
|
||||||
# Send sector list
|
# Send sector list
|
||||||
self._send(chr(len(sectors)-1) + "".join(chr(i) for i in sectors))
|
self._send(bytes((len(sectors)-1,)) + bytes(sectors))
|
||||||
self._checkack()
|
self._checkack()
|
||||||
# Resync after system reset
|
# Resync after system reset
|
||||||
self._sync()
|
self._sync()
|
||||||
|
|
||||||
def write_unprotect(self):
|
def write_unprotect(self):
|
||||||
self._sendcmd("\x73")
|
self._sendcmd(b"\x73")
|
||||||
self._checkack()
|
self._checkack()
|
||||||
self._checkack()
|
self._checkack()
|
||||||
self._sync()
|
self._sync()
|
||||||
|
|
||||||
def read_protect(self):
|
def read_protect(self):
|
||||||
self._sendcmd("\x82")
|
self._sendcmd(b"\x82")
|
||||||
self._checkack()
|
self._checkack()
|
||||||
self._checkack()
|
self._checkack()
|
||||||
self._sync()
|
self._sync()
|
||||||
|
|
||||||
def read_unprotect(self):
|
def read_unprotect(self):
|
||||||
self._sendcmd("\x92")
|
self._sendcmd(b"\x92")
|
||||||
self._checkack()
|
self._checkack()
|
||||||
self._checkack()
|
self._checkack()
|
||||||
self._sync()
|
self._sync()
|
||||||
@ -133,12 +131,12 @@ if __name__ == "__main__":
|
|||||||
from sys import stdout, argv, platform
|
from sys import stdout, argv, platform
|
||||||
from getopt import getopt
|
from getopt import getopt
|
||||||
|
|
||||||
if platform == "linux2":
|
if platform == "linux":
|
||||||
print "\x1b\x5b\x48\x1b\x5b\x32\x4a" # clear terminal screen
|
print("\x1b\x5b\x48\x1b\x5b\x32\x4a") # clear terminal screen
|
||||||
print "STM32 SystemMemory Production Programmer -- version 1.1"
|
print("STM32 SystemMemory Production Programmer -- version 1.1")
|
||||||
print "Copyright (C) 2011 Black Sphere Technologies"
|
print("Copyright (C) 2011 Black Sphere Technologies")
|
||||||
print "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>"
|
print("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>")
|
||||||
print
|
print()
|
||||||
|
|
||||||
dev = "COM1" if platform == "win32" else "/dev/ttyUSB0"
|
dev = "COM1" if platform == "win32" else "/dev/ttyUSB0"
|
||||||
baud = 115200
|
baud = 115200
|
||||||
@ -152,38 +150,38 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
progfile = args[0]
|
progfile = args[0]
|
||||||
except:
|
except:
|
||||||
print "Usage %s [-d <dev>] [-b <baudrate>] [-a <address>] <filename>" % argv[0]
|
print("Usage %s [-d <dev>] [-b <baudrate>] [-a <address>] <filename>" % argv[0])
|
||||||
print "\t-d : Use target on interface <dev> (default: %s)" % dev
|
print("\t-d : Use target on interface <dev> (default: %s)" % dev)
|
||||||
print "\t-b : Set device baudrate (default: %d)" % baud
|
print("\t-b : Set device baudrate (default: %d)" % baud)
|
||||||
print "\t-a : Set programming address (default: 0x%X)" % addr
|
print("\t-a : Set programming address (default: 0x%X)" % addr)
|
||||||
print
|
print()
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
prog = open(progfile, "rb").read()
|
prog = open(progfile, "rb").read()
|
||||||
boot = stm32_boot(dev, baud)
|
boot = stm32_boot(dev, baud)
|
||||||
|
|
||||||
cmds = boot.get()
|
cmds = boot.get()
|
||||||
print "Target bootloader version: %d.%d\n" % (ord(cmds[0]) >> 4, ord(cmds[0]) % 0xf)
|
print("Target bootloader version: %d.%d\n" % (cmds[0] >> 4, cmds[0] % 0xf))
|
||||||
|
|
||||||
print "Removing device protection..."
|
print("Removing device protection...")
|
||||||
boot.read_unprotect()
|
boot.read_unprotect()
|
||||||
boot.write_unprotect()
|
boot.write_unprotect()
|
||||||
print "Erasing target device..."
|
print("Erasing target device...")
|
||||||
boot.eraseall()
|
boot.eraseall()
|
||||||
addr = 0x8000000
|
addr = 0x8000000
|
||||||
while prog:
|
while prog:
|
||||||
print ("Programming address 0x%08X..0x%08X...\r" % (addr, addr + min(len(prog), 255))),
|
print("Programming address 0x%08X..0x%08X...\r" % (addr, addr + min(len(prog), 255)), end=' ')
|
||||||
stdout.flush();
|
stdout.flush()
|
||||||
boot.write(addr, prog[:256])
|
boot.write(addr, prog[:256])
|
||||||
addr += 256
|
addr += 256
|
||||||
prog = prog[256:]
|
prog = prog[256:]
|
||||||
|
|
||||||
print
|
print
|
||||||
print "Enabling device protection..."
|
print("Enabling device protection...")
|
||||||
boot.write_protect(range(0,2))
|
boot.write_protect(range(0,2))
|
||||||
#boot.read_protect()
|
#boot.read_protect()
|
||||||
|
|
||||||
print "All operations completed."
|
print("All operations completed.")
|
||||||
print
|
print
|
||||||
|
|
||||||
|
|
||||||
|
53
scripts/dfu-convert.py
Normal file → Executable file
53
scripts/dfu-convert.py
Normal file → Executable file
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/python2
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# Written by Antonio Galea - 2010/11/18
|
# Written by Antonio Galea - 2010/11/18
|
||||||
# Distributed under Gnu LGPL 3.0
|
# Distributed under Gnu LGPL 3.0
|
||||||
@ -16,57 +16,64 @@ def consume(fmt,data,names):
|
|||||||
n = struct.calcsize(fmt)
|
n = struct.calcsize(fmt)
|
||||||
return named(struct.unpack(fmt,data[:n]),names),data[n:]
|
return named(struct.unpack(fmt,data[:n]),names),data[n:]
|
||||||
def cstring(string):
|
def cstring(string):
|
||||||
return string.split('\0',1)[0]
|
return string.split(b'\0',1)[0]
|
||||||
def compute_crc(data):
|
def compute_crc(data):
|
||||||
return 0xFFFFFFFF & -zlib.crc32(data) -1
|
return 0xFFFFFFFF & -zlib.crc32(data) -1
|
||||||
|
|
||||||
def parse(file,dump_images=False):
|
def parse(file,dump_images=False):
|
||||||
print 'File: "%s"' % file
|
print('File: "%s"' % file)
|
||||||
data = open(file,'rb').read()
|
data = open(file,'rb').read()
|
||||||
crc = compute_crc(data[:-4])
|
crc = compute_crc(data[:-4])
|
||||||
prefix, data = consume('<5sBIB',data,'signature version size targets')
|
prefix, data = consume('<5sBIB',data,'signature version size targets')
|
||||||
print '%(signature)s v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix
|
print('%(signature)r v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix)
|
||||||
for t in range(prefix['targets']):
|
for t in range(prefix['targets']):
|
||||||
tprefix, data = consume('<6sBI255s2I',data,'signature altsetting named name size elements')
|
tprefix, data = consume('<6sBI255s2I',data,'signature altsetting named name size elements')
|
||||||
tprefix['num'] = t
|
tprefix['num'] = t
|
||||||
if tprefix['named']:
|
if tprefix['named']:
|
||||||
tprefix['name'] = cstring(tprefix['name'])
|
tprefix['name'] = cstring(tprefix['name'])
|
||||||
else:
|
else:
|
||||||
tprefix['name'] = ''
|
tprefix['name'] = b''
|
||||||
print '%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d' % tprefix
|
print('%(signature)r %(num)d, alt setting: %(altsetting)r, name: %(name)r, size: %(size)d, elements: %(elements)d' % tprefix)
|
||||||
tsize = tprefix['size']
|
tsize = tprefix['size']
|
||||||
target, data = data[:tsize], data[tsize:]
|
target, data = data[:tsize], data[tsize:]
|
||||||
for e in range(tprefix['elements']):
|
for e in range(tprefix['elements']):
|
||||||
eprefix, target = consume('<2I',target,'address size')
|
eprefix, target = consume('<2I',target,'address size')
|
||||||
eprefix['num'] = e
|
eprefix['num'] = e
|
||||||
print ' %(num)d, address: 0x%(address)08x, size: %(size)d' % eprefix
|
print(' %(num)d, address: 0x%(address)08x, size: %(size)d' % eprefix)
|
||||||
esize = eprefix['size']
|
esize = eprefix['size']
|
||||||
image, target = target[:esize], target[esize:]
|
image, target = target[:esize], target[esize:]
|
||||||
if dump_images:
|
if dump_images:
|
||||||
out = '%s.target%d.image%d.bin' % (file,t,e)
|
out = '%s.target%d.image%d.bin' % (file,t,e)
|
||||||
open(out,'wb').write(image)
|
open(out,'wb').write(image)
|
||||||
print ' DUMPED IMAGE TO "%s"' % out
|
print(' DUMPED IMAGE TO "%s"' % out)
|
||||||
if len(target):
|
if len(target):
|
||||||
print "target %d: PARSE ERROR" % t
|
print("target %d: PARSE ERROR" % t)
|
||||||
suffix = named(struct.unpack('<4H3sBI',data[:16]),'device product vendor dfu ufd len crc')
|
suffix = named(struct.unpack('<4H3sBI',data[:16]),'device product vendor dfu ufd len crc')
|
||||||
print 'usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % suffix
|
print('usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)r, %(len)d, 0x%(crc)08x' % suffix)
|
||||||
if crc != suffix['crc']:
|
if crc != suffix['crc']:
|
||||||
print "CRC ERROR: computed crc32 is 0x%08x" % crc
|
print("CRC ERROR: computed crc32 is 0x%08x" % crc)
|
||||||
data = data[16:]
|
data = data[16:]
|
||||||
if data:
|
if data:
|
||||||
print "PARSE ERROR"
|
print("PARSE ERROR")
|
||||||
|
|
||||||
def build(file,targets,device=DEFAULT_DEVICE):
|
def build(file,targets,device=DEFAULT_DEVICE):
|
||||||
data = ''
|
data = b''
|
||||||
for t,target in enumerate(targets):
|
for t,target in enumerate(targets):
|
||||||
tdata = ''
|
tdata = b''
|
||||||
for image in target:
|
for image in target:
|
||||||
tdata += struct.pack('<2I',image['address'],len(image['data']))+image['data']
|
tdata += struct.pack('<2I',image['address'],len(image['data']))+image['data']
|
||||||
tdata = struct.pack('<6sBI255s2I','Target',0,1,'ST...',len(tdata),len(target)) + tdata
|
|
||||||
|
trgt = b'Target'
|
||||||
|
st = b'ST...'
|
||||||
|
tdata = struct.pack('<6sBI255s2I',trgt,0,1,st,len(tdata),len(target)) + tdata
|
||||||
data += tdata
|
data += tdata
|
||||||
data = struct.pack('<5sBIB','DfuSe',1,len(data)+11,len(targets)) + data
|
|
||||||
|
dfu_se = b'DfuSe'
|
||||||
|
ufd = b'UFD'
|
||||||
|
data = struct.pack('<5sBIB',dfu_se,1,len(data)+11,len(targets)) + data
|
||||||
|
|
||||||
v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1))
|
v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1))
|
||||||
data += struct.pack('<4H3sB',0,d,v,0x011a,'UFD',16)
|
data += struct.pack('<4H3sB',0,d,v,0x011a,ufd,16)
|
||||||
crc = compute_crc(data)
|
crc = compute_crc(data)
|
||||||
data += struct.pack('<I',crc)
|
data += struct.pack('<I',crc)
|
||||||
open(file,'wb').write(data)
|
open(file,'wb').write(data)
|
||||||
@ -96,15 +103,15 @@ if __name__=="__main__":
|
|||||||
try:
|
try:
|
||||||
address,binfile = arg.split(':',1)
|
address,binfile = arg.split(':',1)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print "Address:file couple '%s' invalid." % arg
|
print("Address:file couple '%s' invalid." % arg)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
try:
|
try:
|
||||||
address = int(address,0) & 0xFFFFFFFF
|
address = int(address,0) & 0xFFFFFFFF
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print "Address %s invalid." % address
|
print("Address %s invalid." % address)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if not os.path.isfile(binfile):
|
if not os.path.isfile(binfile):
|
||||||
print "Unreadable file '%s'." % binfile
|
print("Unreadable file '%s'." % binfile)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
target.append({ 'address': address, 'data': open(binfile,'rb').read() })
|
target.append({ 'address': address, 'data': open(binfile,'rb').read() })
|
||||||
|
|
||||||
@ -116,7 +123,7 @@ if __name__=="__main__":
|
|||||||
try:
|
try:
|
||||||
address = address & 0xFFFFFFFF
|
address = address & 0xFFFFFFFF
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print "Address %s invalid." % address
|
print("Address %s invalid." % address)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
target.append({ 'address': address, 'data': data })
|
target.append({ 'address': address, 'data': data })
|
||||||
|
|
||||||
@ -127,13 +134,13 @@ if __name__=="__main__":
|
|||||||
try:
|
try:
|
||||||
v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1))
|
v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1))
|
||||||
except:
|
except:
|
||||||
print "Invalid device '%s'." % device
|
print("Invalid device '%s'." % device)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
build(outfile,[target],device)
|
build(outfile,[target],device)
|
||||||
elif len(args)==1:
|
elif len(args)==1:
|
||||||
infile = args[0]
|
infile = args[0]
|
||||||
if not os.path.isfile(infile):
|
if not os.path.isfile(infile):
|
||||||
print "Unreadable file '%s'." % infile
|
print("Unreadable file '%s'." % infile)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
parse(infile, dump_images=options.dump_images)
|
parse(infile, dump_images=options.dump_images)
|
||||||
else:
|
else:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
#
|
#
|
||||||
# dfu.py: Access USB DFU class devices
|
# dfu.py: Access USB DFU class devices
|
||||||
# Copyright (C) 2009 Black Sphere Technologies
|
# Copyright (C) 2009 Black Sphere Technologies
|
||||||
@ -62,7 +62,7 @@ DFU_STATUS_ERROR_POR = 0x0d
|
|||||||
DFU_STATUS_ERROR_UNKNOWN = 0x0e
|
DFU_STATUS_ERROR_UNKNOWN = 0x0e
|
||||||
DFU_STATUS_ERROR_STALLEDPKT = 0x0f
|
DFU_STATUS_ERROR_STALLEDPKT = 0x0f
|
||||||
|
|
||||||
class dfu_status(object):
|
class dfu_status:
|
||||||
def __init__(self, buf):
|
def __init__(self, buf):
|
||||||
self.bStatus = buf[0]
|
self.bStatus = buf[0]
|
||||||
self.bwPollTimeout = buf[1] + (buf[2]<<8) + (buf[3]<<16)
|
self.bwPollTimeout = buf[1] + (buf[2]<<8) + (buf[3]<<16)
|
||||||
@ -70,7 +70,7 @@ class dfu_status(object):
|
|||||||
self.iString = buf[5]
|
self.iString = buf[5]
|
||||||
|
|
||||||
|
|
||||||
class dfu_device(object):
|
class dfu_device:
|
||||||
def __init__(self, dev, conf, iface):
|
def __init__(self, dev, conf, iface):
|
||||||
self.dev = dev
|
self.dev = dev
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
|
263
scripts/gdb.py
263
scripts/gdb.py
@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
#
|
#
|
||||||
# gdb.py: Python module for low level GDB protocol implementation
|
# gdb.py: Python module for low level GDB protocol implementation
|
||||||
# Copyright (C) 2009 Black Sphere Technologies
|
# Copyright (C) 2009 Black Sphere Technologies
|
||||||
# Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
# Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -24,24 +24,18 @@ import struct
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
def hexify(s):
|
def hexify(s):
|
||||||
"""Convert a binary string into hex representation"""
|
"""Convert a bytes object into hex bytes representation"""
|
||||||
ret = ''
|
return s.hex().encode()
|
||||||
for c in s:
|
|
||||||
ret += "%02X" % ord(c)
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def unhexify(s):
|
def unhexify(s):
|
||||||
"""Convert a hex string into binary representation"""
|
"""Convert a hex-encoded bytes into bytes object"""
|
||||||
ret = ''
|
return bytes.fromhex(s.decode())
|
||||||
for i in range(0, len(s), 2):
|
|
||||||
ret += chr(int(s[i:i+2], 16))
|
|
||||||
return ret
|
|
||||||
|
|
||||||
class FakeSocket:
|
class FakeSocket:
|
||||||
"""Emulate socket functions send and recv on a file object"""
|
"""Emulate socket functions send and recv on a file object"""
|
||||||
def __init__(self, file):
|
def __init__(self, file):
|
||||||
self.file = file
|
self.file = file
|
||||||
|
|
||||||
def send(self, data):
|
def send(self, data):
|
||||||
self.file.write(data)
|
self.file.write(data)
|
||||||
|
|
||||||
@ -52,148 +46,186 @@ class Target:
|
|||||||
def __init__(self, sock):
|
def __init__(self, sock):
|
||||||
if "send" in dir(sock):
|
if "send" in dir(sock):
|
||||||
self.sock = sock
|
self.sock = sock
|
||||||
else:
|
else:
|
||||||
self.sock = FakeSocket(sock)
|
self.sock = FakeSocket(sock)
|
||||||
|
|
||||||
|
self.PacketSize=0x100 # default
|
||||||
|
|
||||||
def getpacket(self):
|
def getpacket(self):
|
||||||
"""Return the first correctly received packet from GDB target"""
|
"""Return the first correctly received packet from GDB target"""
|
||||||
while True:
|
while True:
|
||||||
while self.sock.recv(1) != '$': pass
|
while self.sock.recv(1) != b'$':
|
||||||
|
pass
|
||||||
|
|
||||||
csum = 0
|
csum = 0
|
||||||
packet = ''
|
packet = [] # list-of-small-int
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
c = self.sock.recv(1)
|
c, = self.sock.recv(1)
|
||||||
if c == '#': break
|
if c == ord('#'):
|
||||||
|
break
|
||||||
|
|
||||||
if c == '$':
|
if c == ord('$'):
|
||||||
packet = ''
|
packet = []
|
||||||
csum = 0
|
csum = 0
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if c == '}':
|
if c == ord('}'):
|
||||||
c = self.sock.recv(1)
|
c, = self.sock.recv(1)
|
||||||
csum += ord(c) + ord('}')
|
csum += c + ord('}')
|
||||||
packet += chr(ord(c) ^ 0x20)
|
packet.append(c ^ 0x20)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
packet += c
|
packet.append(c)
|
||||||
csum += ord(c)
|
csum += c
|
||||||
|
|
||||||
if (csum & 0xFF) == int(self.sock.recv(2),16): break
|
if (csum & 0xFF) == int(self.sock.recv(2),16):
|
||||||
|
break
|
||||||
|
|
||||||
self.sock.send('-')
|
self.sock.send(b'-')
|
||||||
|
|
||||||
self.sock.send('+')
|
|
||||||
return packet
|
|
||||||
|
|
||||||
|
self.sock.send(b'+')
|
||||||
|
return bytes(packet)
|
||||||
|
|
||||||
def putpacket(self, packet):
|
def putpacket(self, packet):
|
||||||
"""Send packet to GDB target and wait for acknowledge"""
|
"""Send packet to GDB target and wait for acknowledge
|
||||||
|
packet is bytes or string"""
|
||||||
|
|
||||||
|
if type(packet) == str:
|
||||||
|
packet = packet.encode()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
self.sock.send('$')
|
out = []
|
||||||
csum = 0
|
|
||||||
for c in packet:
|
for c in packet:
|
||||||
if (c == '$') or (c == '#') or (c == '}'):
|
if (c in b'$#}'):
|
||||||
self.sock.send('}')
|
out.append(ord('}'))
|
||||||
self.sock.send(chr(ord(c) ^ 0x20))
|
out.append(c ^ 0x20)
|
||||||
csum += (ord(c) ^ 0x20) + ord('}')
|
|
||||||
else:
|
else:
|
||||||
self.sock.send(c)
|
out.append(c)
|
||||||
csum += ord(c)
|
|
||||||
self.sock.send('#')
|
csum = sum(out)
|
||||||
self.sock.send("%02X" % (csum & 0xFF))
|
outb = b'$'+bytes(out)+b'#%02X' % (csum & 0xff)
|
||||||
if self.sock.recv(1) == '+': break
|
|
||||||
|
self.sock.send(outb)
|
||||||
|
if self.sock.recv(1) == b'+':
|
||||||
|
break
|
||||||
|
|
||||||
def monitor(self, cmd):
|
def monitor(self, cmd):
|
||||||
"""Send gdb "monitor" command to target"""
|
"""Send gdb "monitor" command to target"""
|
||||||
|
if type(cmd) == str:
|
||||||
|
cmd = cmd.encode()
|
||||||
|
|
||||||
ret = []
|
ret = []
|
||||||
self.putpacket("qRcmd," + hexify(cmd))
|
self.putpacket(b"qRcmd," + hexify(cmd))
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
s = self.getpacket()
|
s = self.getpacket()
|
||||||
if s == '': return None
|
|
||||||
if s == 'OK': return ret
|
if s == b'':
|
||||||
if s.startswith('O'): ret.append(unhexify(s[1:]))
|
return None
|
||||||
|
if s == b'OK':
|
||||||
|
return ret
|
||||||
|
if s.startswith(b'O'):
|
||||||
|
ret.append(unhexify(s[1:]))
|
||||||
else:
|
else:
|
||||||
raise Exception('Invalid GDB stub response')
|
raise Exception('Invalid GDB stub response %r'%s.decode())
|
||||||
|
|
||||||
def attach(self, pid):
|
def attach(self, pid):
|
||||||
"""Attach to target process (gdb "attach" command)"""
|
"""Attach to target process (gdb "attach" command)"""
|
||||||
self.putpacket("vAttach;%08X" % pid)
|
self.putpacket(b"vAttach;%08X" % pid)
|
||||||
reply = self.getpacket()
|
reply = self.getpacket()
|
||||||
if (len(reply) == 0) or (reply[0] == 'E'):
|
if (reply == b'') or (reply[:1] == b'E'):
|
||||||
raise Exception('Failed to attach to remote pid %d' % pid)
|
raise Exception('Failed to attach to remote pid %d' % pid)
|
||||||
|
|
||||||
def detach(self):
|
def detach(self):
|
||||||
"""Detach from target process (gdb "detach" command)"""
|
"""Detach from target process (gdb "detach" command)"""
|
||||||
self.putpacket("D")
|
self.putpacket(b"D")
|
||||||
if self.getpacket() != 'OK':
|
if self.getpacket() != b'OK':
|
||||||
raise Exception("Failed to detach from remote process")
|
raise Exception("Failed to detach from remote process")
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
"""Reset the target system"""
|
"""Reset the target system"""
|
||||||
self.putpacket("r")
|
self.putpacket(b"r")
|
||||||
|
|
||||||
def read_mem(self, addr, length):
|
def read_mem(self, addr, length):
|
||||||
"""Read length bytes from target at address addr"""
|
"""Read length bytes from target at address addr"""
|
||||||
self.putpacket("m%08X,%08X" % (addr, length))
|
ret = b''
|
||||||
reply = self.getpacket()
|
while length:
|
||||||
if (len(reply) == 0) or (reply[0] == 'E'):
|
# print("Read")
|
||||||
raise Exception('Error reading memory at 0x%08X' % addr)
|
packlen = min(length,self.PacketSize//2)
|
||||||
try:
|
self.putpacket(b"m%08X,%08X" % (addr, packlen))
|
||||||
data = unhexify(reply)
|
reply = self.getpacket()
|
||||||
except Excpetion:
|
if (reply == b'') or (reply[:1] == b'E'):
|
||||||
raise Exception('Invalid response to memory read packet: %r' % reply)
|
raise Exception('Error reading memory at 0x%08X' % addr)
|
||||||
return data
|
try:
|
||||||
|
data = unhexify(reply)
|
||||||
|
except Exception:
|
||||||
|
raise Exception('Invalid response to memory read packet: %r' % reply)
|
||||||
|
ret += data
|
||||||
|
length -= packlen
|
||||||
|
addr += packlen
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
def write_mem(self, addr, data):
|
def write_mem(self, addr, data):
|
||||||
"""Write data to target at address addr"""
|
"""Write data to target at address addr"""
|
||||||
self.putpacket("X%08X,%08X:%s" % (addr, len(data), data))
|
data = bytes(data)
|
||||||
if self.getpacket() != 'OK':
|
|
||||||
raise Exception('Error writing to memory at 0x%08X' % addr)
|
while data:
|
||||||
|
d = data[:self.PacketSize-44]
|
||||||
|
data = data[len(d):]
|
||||||
|
#print("Writing %d bytes at 0x%X" % (len(d), addr))
|
||||||
|
pack = b"X%08X,%08X:%s" % (addr, len(d), d)
|
||||||
|
self.putpacket(pack)
|
||||||
|
|
||||||
|
if self.getpacket() != b'OK':
|
||||||
|
raise Exception('Error writing to memory at 0x%08X' % addr)
|
||||||
|
addr += len(d)
|
||||||
|
|
||||||
def read_regs(self):
|
def read_regs(self):
|
||||||
"""Read target core registers"""
|
"""Read target core registers"""
|
||||||
self.putpacket("g")
|
self.putpacket(b"g")
|
||||||
reply = self.getpacket()
|
reply = self.getpacket()
|
||||||
if (len(reply) == 0) or (reply[0] == 'E'):
|
if (reply == b'') or (reply[:1] == b'E'):
|
||||||
raise Exception('Error reading memory at 0x%08X' % addr)
|
raise Exception('Error reading target core registers')
|
||||||
try:
|
try:
|
||||||
data = unhexify(reply)
|
data = unhexify(reply)
|
||||||
except Excpetion:
|
except Exception:
|
||||||
raise Exception('Invalid response to memory read packet: %r' % reply)
|
raise Exception('Invalid response to registers read packet: %r' % reply)
|
||||||
return struct.unpack("=20L", data)
|
ret = array.array('I',data)
|
||||||
|
return ret
|
||||||
|
|
||||||
def write_regs(self, *regs):
|
def write_regs(self, *regs):
|
||||||
"""Write target core registers"""
|
"""Write target core registers"""
|
||||||
data = struct.pack("=%dL" % len(regs), *regs)
|
data = struct.pack("=%dL" % len(regs), *regs)
|
||||||
self.putpacket("G" + hexify(data))
|
self.putpacket(b"G" + hexify(data))
|
||||||
if self.getpacket() != 'OK':
|
if self.getpacket() != b'OK':
|
||||||
raise Exception('Error writing to target core registers')
|
raise Exception('Error writing to target core registers')
|
||||||
|
|
||||||
def memmap_read(self):
|
def memmap_read(self):
|
||||||
"""Read the XML memory map from target"""
|
"""Read the XML memory map from target"""
|
||||||
offset = 0
|
offset = 0
|
||||||
ret = ''
|
ret = b''
|
||||||
while True:
|
while True:
|
||||||
self.putpacket("qXfer:memory-map:read::%08X,%08X" % (offset, 512))
|
self.putpacket(b"qXfer:memory-map:read::%08X,%08X" % (offset, 512))
|
||||||
reply = self.getpacket()
|
reply = self.getpacket()
|
||||||
if (reply[0] == 'm') or (reply[0] == 'l'):
|
if (reply[0] in b'ml'):
|
||||||
offset += len(reply) - 1
|
offset += len(reply) - 1
|
||||||
ret += reply[1:]
|
ret += reply[1:]
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid GDB stub response")
|
raise Exception('Invalid GDB stub response %r'%reply)
|
||||||
|
|
||||||
|
if reply[:1] == b'l':
|
||||||
|
return ret
|
||||||
|
|
||||||
if reply[0] == 'l': return ret
|
|
||||||
|
|
||||||
def resume(self):
|
def resume(self):
|
||||||
"""Resume target execution"""
|
"""Resume target execution"""
|
||||||
self.putpacket("c")
|
self.putpacket(b'c')
|
||||||
|
|
||||||
def interrupt(self):
|
def interrupt(self):
|
||||||
"""Interrupt target execution"""
|
"""Interrupt target execution"""
|
||||||
self.sock.send("\x03")
|
self.sock.send(b'\x03')
|
||||||
|
|
||||||
def run_stub(self, stub, address, *args):
|
def run_stub(self, stub, address, *args):
|
||||||
"""Execute a binary stub at address, passing args in core registers."""
|
"""Execute a binary stub at address, passing args in core registers."""
|
||||||
@ -205,11 +237,19 @@ class Target:
|
|||||||
regs[15] = address
|
regs[15] = address
|
||||||
self.write_regs(*regs)
|
self.write_regs(*regs)
|
||||||
self.resume()
|
self.resume()
|
||||||
reply = self.getpacket()
|
reply = None
|
||||||
while not reply:
|
while not reply:
|
||||||
reply = self.getpacket()
|
reply = self.getpacket()
|
||||||
if not reply.startswith("T05"):
|
if not reply.startswith(b"T05"):
|
||||||
raise Exception("Invalid stop response: %r" % reply)
|
message = "Invalid stop response: %r" % reply
|
||||||
|
try:
|
||||||
|
message += {'T02':' (SIGINT)',
|
||||||
|
'T05':' (SIGTRAP)',
|
||||||
|
'T0B':' (SIGSEGV)',
|
||||||
|
'T1D':' (SIGLOST)'}[reply]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
raise Exception(message)
|
||||||
|
|
||||||
class FlashMemory:
|
class FlashMemory:
|
||||||
def __init__(self, target, offset, length, blocksize):
|
def __init__(self, target, offset, length, blocksize):
|
||||||
@ -217,27 +257,30 @@ class Target:
|
|||||||
self.offset = offset
|
self.offset = offset
|
||||||
self.length = length
|
self.length = length
|
||||||
self.blocksize = blocksize
|
self.blocksize = blocksize
|
||||||
self.blocks = list(None for i in range(length / blocksize))
|
self.blocks = list(None for i in range(length // blocksize))
|
||||||
|
|
||||||
def prog(self, offset, data):
|
def prog(self, offset, data):
|
||||||
assert ((offset >= self.offset) and
|
assert type(data)==bytes
|
||||||
|
|
||||||
|
assert ((offset >= self.offset) and
|
||||||
(offset + len(data) <= self.offset + self.length))
|
(offset + len(data) <= self.offset + self.length))
|
||||||
|
|
||||||
while data:
|
while data:
|
||||||
index = (offset - self.offset) / self.blocksize
|
index = (offset - self.offset) // self.blocksize
|
||||||
bloffset = (offset - self.offset) % self.blocksize
|
bloffset = (offset - self.offset) % self.blocksize
|
||||||
bldata = data[:self.blocksize-bloffset]
|
bldata = data[:self.blocksize-bloffset]
|
||||||
data = data[len(bldata):]; offset += len(bldata)
|
data = data[len(bldata):]; offset += len(bldata)
|
||||||
if self.blocks[index] is None: # Initialize a clear block
|
if self.blocks[index] is None: # Initialize a clear block
|
||||||
self.blocks[index] = "".join(chr(0xff) for i in range(self.blocksize))
|
self.blocks[index] = bytes(0xff for i in range(self.blocksize))
|
||||||
self.blocks[index] = (self.blocks[index][:bloffset] + bldata +
|
self.blocks[index] = (self.blocks[index][:bloffset] + bldata +
|
||||||
self.blocks[index][bloffset+len(bldata):])
|
self.blocks[index][bloffset+len(bldata):])
|
||||||
|
|
||||||
def commit(self, progress_cb=None):
|
def commit(self, progress_cb=None):
|
||||||
totalblocks = 0
|
totalblocks = 0
|
||||||
for b in self.blocks:
|
for b in self.blocks:
|
||||||
if b is not None: totalblocks += 1
|
if b is not None:
|
||||||
|
totalblocks += 1
|
||||||
|
|
||||||
block = 0
|
block = 0
|
||||||
for i in range(len(self.blocks)):
|
for i in range(len(self.blocks)):
|
||||||
block += 1
|
block += 1
|
||||||
@ -247,35 +290,37 @@ class Target:
|
|||||||
# Erase the block
|
# Erase the block
|
||||||
data = self.blocks[i]
|
data = self.blocks[i]
|
||||||
addr = self.offset + self.blocksize * i
|
addr = self.offset + self.blocksize * i
|
||||||
if data is None: continue
|
if data is None:
|
||||||
#print "Erasing flash at 0x%X" % (self.offset + self.blocksize*i)
|
continue
|
||||||
self.target.putpacket("vFlashErase:%08X,%08X" %
|
#print("Erasing flash at 0x%X" % (self.offset + self.blocksize*i))
|
||||||
|
self.target.putpacket(b"vFlashErase:%08X,%08X" %
|
||||||
(self.offset + self.blocksize*i, self.blocksize))
|
(self.offset + self.blocksize*i, self.blocksize))
|
||||||
if self.target.getpacket() != 'OK':
|
if self.target.getpacket() != b'OK':
|
||||||
raise Exception("Failed to erase flash")
|
raise Exception("Failed to erase flash")
|
||||||
|
|
||||||
while data:
|
while data:
|
||||||
d = data[0:980]
|
d = data[0:980]
|
||||||
data = data[len(d):]
|
data = data[len(d):]
|
||||||
#print "Writing %d bytes at 0x%X" % (len(d), addr)
|
#print("Writing %d bytes at 0x%X" % (len(d), addr))
|
||||||
self.target.putpacket("vFlashWrite:%08X:%s" % (addr, d))
|
self.target.putpacket(b"vFlashWrite:%08X:%s" % (addr, d))
|
||||||
addr += len(d)
|
addr += len(d)
|
||||||
if self.target.getpacket() != 'OK':
|
if self.target.getpacket() != b'OK':
|
||||||
raise Exception("Failed to write flash")
|
raise Exception("Failed to write flash")
|
||||||
|
|
||||||
self.target.putpacket("vFlashDone")
|
self.target.putpacket(b"vFlashDone")
|
||||||
if self.target.getpacket() != 'OK':
|
if self.target.getpacket() != b'OK':
|
||||||
raise Exception("Failed to commit")
|
raise Exception("Failed to commit")
|
||||||
|
|
||||||
self.blocks = list(None for i in range(self.length / self.blocksize))
|
self.blocks = list(None for i in range(self.length // self.blocksize))
|
||||||
|
|
||||||
|
|
||||||
def flash_probe(self):
|
def flash_probe(self):
|
||||||
self.mem = []
|
self.mem = []
|
||||||
xmldom = parseString(self.memmap_read())
|
xmldom = parseString(self.memmap_read())
|
||||||
|
|
||||||
for memrange in xmldom.getElementsByTagName("memory"):
|
for memrange in xmldom.getElementsByTagName("memory"):
|
||||||
if memrange.getAttribute("type") != "flash": continue
|
if memrange.getAttribute("type") != "flash":
|
||||||
|
continue
|
||||||
offset = eval(memrange.getAttribute("start"))
|
offset = eval(memrange.getAttribute("start"))
|
||||||
length = eval(memrange.getAttribute("length"))
|
length = eval(memrange.getAttribute("length"))
|
||||||
for property in memrange.getElementsByTagName("property"):
|
for property in memrange.getElementsByTagName("property"):
|
||||||
@ -297,5 +342,3 @@ class Target:
|
|||||||
def flash_commit(self, progress_cb=None):
|
def flash_commit(self, progress_cb=None):
|
||||||
for m in self.mem:
|
for m in self.mem:
|
||||||
m.commit(progress_cb)
|
m.commit(progress_cb)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,60 +1,56 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
"""Pulls nRF51 IDs from openocd's nrf51.c in a form suitable for
|
"""Pulls nRF51 IDs from openocd's nrf51.c in a form suitable for
|
||||||
pasting into blackmagic's nrf51.c
|
pasting into blackmagic's nrf51.c
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import subprocess,re
|
import subprocess
|
||||||
|
import re
|
||||||
|
import io
|
||||||
|
|
||||||
cmd = 'git archive --remote=git://git.code.sf.net/p/openocd/code HEAD src/flash/nor/nrf51.c | tar -xO'
|
cmd = 'git archive --remote=git://git.code.sf.net/p/openocd/code HEAD src/flash/nor/nrf5.c | tar -xO'
|
||||||
|
|
||||||
class Spec():
|
class Spec():
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "0x%04X: /* %s %s %s */"%(self.hwid,self.comment, self.variant,self.build_code)
|
return "0x%04X: /* %s %s %s */"%(self.hwid,self.comment, self.variant,self.build_code)
|
||||||
|
|
||||||
fd = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE).stdout
|
proc = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
|
||||||
|
|
||||||
specdict={}
|
specdict = {}
|
||||||
specs=[]
|
specs = []
|
||||||
spec=Spec()
|
spec = Spec()
|
||||||
for line in fd.read().split('\n'):
|
for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"):
|
||||||
m=re.search('/\*(.*)\*/',line)
|
m = re.search(r'/\*(.*)\*/',line)
|
||||||
if m:
|
if m:
|
||||||
lastcomment=m.group(1)
|
lastcomment=m.group(1)
|
||||||
|
|
||||||
m=re.search('.hwid.*=\s*(0x[0-9A-F]*),',line)
|
m = re.search(r'NRF51_DEVICE_DEF\((0x[0-9A-F]*),\s*"(.*)",\s*"(.*)",\s*"(.*)",\s*([0-9]*)\s*\),', line)
|
||||||
if m:
|
if m:
|
||||||
spec.hwid=int(m.group(1),base=0)
|
spec.hwid = int(m.group(1), base=0)
|
||||||
m=re.search('.variant.*=\s*"(.*)",',line)
|
spec.variant = m.group(3)
|
||||||
if m:
|
spec.build_code = m.group(4)
|
||||||
spec.variant=m.group(1)
|
spec.flash_size_kb = int(m.group(5), base=0)
|
||||||
m=re.search('.build_code.*=\s*"(.*)",',line)
|
ram, flash = {'AA':(16,256),
|
||||||
if m:
|
'AB':(16,128),
|
||||||
spec.build_code=m.group(1)
|
'AC':(32,256)}[spec.variant[-2:]]
|
||||||
m=re.search('.flash_size_kb.*=\s*([0-9]*),',line)
|
assert flash == spec.flash_size_kb
|
||||||
if m:
|
|
||||||
spec.flash_size_kb=int(m.group(1),base=0)
|
|
||||||
ram,flash = {'AA':(16,256),
|
|
||||||
'AB':(16,128),
|
|
||||||
'AC':(32,256)}[spec.variant[-2:]]
|
|
||||||
assert flash==spec.flash_size_kb
|
|
||||||
spec.ram_size_kb = ram
|
spec.ram_size_kb = ram
|
||||||
nicecomment =lastcomment.strip().replace('IC ','').replace('Devices ','').replace('.','')
|
nicecomment = lastcomment.strip().replace('IC ','').replace('Devices ','').replace('.','')
|
||||||
spec.comment=nicecomment
|
spec.comment = nicecomment
|
||||||
|
|
||||||
specdict.setdefault((ram,flash),[]).append(spec)
|
specdict.setdefault((ram,flash),[]).append(spec)
|
||||||
specs.append(spec)
|
specs.append(spec)
|
||||||
spec=Spec()
|
spec=Spec()
|
||||||
|
|
||||||
for (ram,flash),specs in specdict.iteritems():
|
for (ram,flash),specs in specdict.items():
|
||||||
specs.sort(key=lambda x:x.hwid)
|
specs.sort(key=lambda x:x.hwid)
|
||||||
for spec in specs:
|
for spec in specs:
|
||||||
print "\tcase",spec
|
print("\tcase",spec)
|
||||||
print '\t\tt->driver = "Nordic nRF51";'
|
print('\t\tt->driver = "Nordic nRF51";')
|
||||||
print '\t\ttarget_add_ram(t, 0x20000000, 0x%X);'%(1024*ram)
|
print('\t\ttarget_add_ram(t, 0x20000000, 0x%X);'%(1024*ram))
|
||||||
print '\t\tnrf51_add_flash(t, 0x00000000, 0x%X, NRF51_PAGE_SIZE);'%(1024*flash)
|
print('\t\tnrf51_add_flash(t, 0x00000000, 0x%X, NRF51_PAGE_SIZE);'%(1024*flash))
|
||||||
print '\t\tnrf51_add_flash(t, NRF51_UICR, 0x100, 0x100);'
|
print('\t\tnrf51_add_flash(t, NRF51_UICR, 0x100, 0x100);')
|
||||||
print '\t\ttarget_add_commands(t, nrf51_cmd_list, "nRF51");'
|
print('\t\ttarget_add_commands(t, nrf51_cmd_list, "nRF51");')
|
||||||
print '\t\treturn true;'
|
print('\t\treturn true;')
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# hexprog.py: Python application to flash a target with an Intel hex file
|
# hexprog.py: Python application to flash a target with an Intel hex file
|
||||||
# Copyright (C) 2011 Black Sphere Technologies
|
# Copyright (C) 2011 Black Sphere Technologies
|
||||||
# Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
# Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -18,7 +18,6 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import gdb
|
import gdb
|
||||||
import struct
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
# Microcode sequence to erase option bytes
|
# Microcode sequence to erase option bytes
|
||||||
@ -31,15 +30,16 @@ def flash_write_hex(target, hexfile, progress_cb=None):
|
|||||||
f = open(hexfile)
|
f = open(hexfile)
|
||||||
addrhi = 0
|
addrhi = 0
|
||||||
for line in f:
|
for line in f:
|
||||||
if line[0] != ':': raise Exception("Error in hex file")
|
if line[0] != ':':
|
||||||
|
raise Exception("Error in hex file")
|
||||||
reclen = int(line[1:3], 16)
|
reclen = int(line[1:3], 16)
|
||||||
addrlo = int(line[3:7], 16)
|
addrlo = int(line[3:7], 16)
|
||||||
rectype = int(line[7:9], 16);
|
rectype = int(line[7:9], 16)
|
||||||
if sum(ord(x) for x in gdb.unhexify(line[1:11+reclen*2])) & 0xff != 0:
|
if sum(x for x in bytes.fromhex(line[1:11+reclen*2])) & 0xff != 0:
|
||||||
raise Exception("Checksum error in hex file")
|
raise Exception("Checksum error in hex file")
|
||||||
if rectype == 0: # Data record
|
if rectype == 0: # Data record
|
||||||
addr = (addrhi << 16) + addrlo
|
addr = (addrhi << 16) + addrlo
|
||||||
data = gdb.unhexify(line[9:9+reclen*2])
|
data = bytes.fromhex(line[9:9+reclen*2])
|
||||||
target.flash_write_prepare(addr, data)
|
target.flash_write_prepare(addr, data)
|
||||||
pass
|
pass
|
||||||
elif rectype == 4: # High address record
|
elif rectype == 4: # High address record
|
||||||
@ -48,27 +48,27 @@ def flash_write_hex(target, hexfile, progress_cb=None):
|
|||||||
elif rectype == 5: # Entry record
|
elif rectype == 5: # Entry record
|
||||||
pass
|
pass
|
||||||
elif rectype == 1: # End of file record
|
elif rectype == 1: # End of file record
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid record in hex file")
|
raise Exception("Invalid record in hex file")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
target.flash_commit(progress_cb)
|
target.flash_commit(progress_cb)
|
||||||
except:
|
except:
|
||||||
print "Flash write failed! Is device protected?\n"
|
print("Flash write failed! Is device protected?\n")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from serial import Serial, SerialException
|
from serial import Serial, SerialException
|
||||||
from sys import argv, platform, stdout
|
from sys import argv, platform, stdout
|
||||||
from getopt import getopt
|
from getopt import getopt
|
||||||
|
|
||||||
if platform == "linux2":
|
if platform == "linux":
|
||||||
print ("\x1b\x5b\x48\x1b\x5b\x32\x4a") # clear terminal screen
|
print("\x1b\x5b\x48\x1b\x5b\x32\x4a") # clear terminal screen
|
||||||
print("Black Magic Probe -- Target Production Programming Tool -- version 1.0")
|
print("Black Magic Probe -- Target Production Programming Tool -- version 1.0")
|
||||||
print "Copyright (C) 2011 Black Sphere Technologies"
|
print("Copyright (C) 2011 Black Sphere Technologies")
|
||||||
print "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>"
|
print("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
dev = "COM1" if platform == "win32" else "/dev/ttyACM0"
|
dev = "COM1" if platform == "win32" else "/dev/ttyACM0"
|
||||||
@ -80,13 +80,20 @@ if __name__ == "__main__":
|
|||||||
try:
|
try:
|
||||||
opts, args = getopt(argv[1:], "sd:b:t:rR")
|
opts, args = getopt(argv[1:], "sd:b:t:rR")
|
||||||
for opt in opts:
|
for opt in opts:
|
||||||
if opt[0] == "-s": scan = "swdp_scan"
|
if opt[0] == "-s":
|
||||||
elif opt[0] == "-b": baud = int(opt[1])
|
scan = "swdp_scan"
|
||||||
elif opt[0] == "-d": dev = opt[1]
|
elif opt[0] == "-b":
|
||||||
elif opt[0] == "-t": targetno = int(opt[1])
|
baud = int(opt[1])
|
||||||
elif opt[0] == "-r": unprot = True
|
elif opt[0] == "-d":
|
||||||
elif opt[0] == "-R": prot = True
|
dev = opt[1]
|
||||||
else: raise Exception()
|
elif opt[0] == "-t":
|
||||||
|
targetno = int(opt[1])
|
||||||
|
elif opt[0] == "-r":
|
||||||
|
unprot = True
|
||||||
|
elif opt[0] == "-R":
|
||||||
|
prot = True
|
||||||
|
else:
|
||||||
|
raise Exception()
|
||||||
|
|
||||||
hexfile = args[0]
|
hexfile = args[0]
|
||||||
except:
|
except:
|
||||||
@ -101,39 +108,44 @@ if __name__ == "__main__":
|
|||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
s = Serial(dev, baud, timeout=3)
|
s = Serial(dev) #, baud, timeout=0.1)
|
||||||
s.setDTR(1)
|
#s.setDTR(1)
|
||||||
while s.read(1024):
|
#s.flushInput()
|
||||||
pass
|
|
||||||
|
#while s.read(1024):
|
||||||
|
# pass
|
||||||
|
|
||||||
target = gdb.Target(s)
|
target = gdb.Target(s)
|
||||||
|
|
||||||
except SerialException, e:
|
except SerialException as e:
|
||||||
print("FATAL: Failed to open serial device!\n%s\n" % e[0])
|
print("FATAL: Failed to open serial device!\n%s\n" % e[0])
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = target.monitor("version")
|
r = target.monitor("version")
|
||||||
for s in r: print s,
|
for s in r:
|
||||||
except SerialException, e:
|
print(s.decode(), end=' ')
|
||||||
|
except SerialException as e:
|
||||||
print("FATAL: Serial communication failure!\n%s\n" % e[0])
|
print("FATAL: Serial communication failure!\n%s\n" % e[0])
|
||||||
exit(-1)
|
exit(-1)
|
||||||
except: pass
|
#except: pass
|
||||||
|
|
||||||
print "Target device scan:"
|
print("Target device scan:")
|
||||||
targetlist = None
|
targetlist = None
|
||||||
r = target.monitor(scan)
|
r = target.monitor(scan)
|
||||||
for s in r:
|
for s in r:
|
||||||
print s,
|
print(s.decode(), end=' ')
|
||||||
print
|
print()
|
||||||
|
|
||||||
r = target.monitor("targets")
|
r = target.monitor("targets")
|
||||||
for s in r:
|
for s in r:
|
||||||
if s.startswith("No. Att Driver"): targetlist = []
|
if s.startswith(b"No. Att Driver"):
|
||||||
|
targetlist = []
|
||||||
try:
|
try:
|
||||||
if type(targetlist) is list:
|
if type(targetlist) is list:
|
||||||
targetlist.append(int(s[:2]))
|
targetlist.append(int(s[:2]))
|
||||||
except: pass
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
#if not targetlist:
|
#if not targetlist:
|
||||||
# print("FATAL: No usable targets found!\n")
|
# print("FATAL: No usable targets found!\n")
|
||||||
@ -161,7 +173,7 @@ if __name__ == "__main__":
|
|||||||
print("FLASH memory -- Offset: 0x%X BlockSize:0x%X\n" % (m.offset, m.blocksize))
|
print("FLASH memory -- Offset: 0x%X BlockSize:0x%X\n" % (m.offset, m.blocksize))
|
||||||
|
|
||||||
def progress(percent):
|
def progress(percent):
|
||||||
print ("Progress: %d%%\r" % percent),
|
print("Progress: %d%%\r" % percent, end=' ')
|
||||||
stdout.flush()
|
stdout.flush()
|
||||||
|
|
||||||
print("Programming target")
|
print("Programming target")
|
||||||
@ -179,4 +191,3 @@ if __name__ == "__main__":
|
|||||||
target.detach()
|
target.detach()
|
||||||
|
|
||||||
print("\nAll operations complete!\n")
|
print("\nAll operations complete!\n")
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
#
|
#
|
||||||
# stm32_mem.py: STM32 memory access using USB DFU class
|
# stm32_mem.py: STM32 memory access using USB DFU class
|
||||||
# Copyright (C) 2011 Black Sphere Technologies
|
# Copyright (C) 2011 Black Sphere Technologies
|
||||||
# Copyright (C) 2017 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
# Copyright (C) 2017, 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
# Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
# Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
@ -18,14 +18,12 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
from time import sleep
|
from time import sleep
|
||||||
import struct
|
import struct
|
||||||
import os
|
import os
|
||||||
from sys import stdout, argv
|
from sys import stdout
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import usb
|
|
||||||
import dfu
|
import dfu
|
||||||
|
|
||||||
CMD_GETCOMMANDS = 0x00
|
CMD_GETCOMMANDS = 0x00
|
||||||
@ -72,7 +70,7 @@ def stm32_read(dev):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
def stm32_manifest(dev):
|
def stm32_manifest(dev):
|
||||||
dev.download(0, "")
|
dev.download(0, b"")
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
status = dev.get_status()
|
status = dev.get_status()
|
||||||
@ -87,7 +85,7 @@ def stm32_scan(args, test):
|
|||||||
bmp_devs = []
|
bmp_devs = []
|
||||||
bmp = 0
|
bmp = 0
|
||||||
if not devs:
|
if not devs:
|
||||||
if test == True:
|
if test:
|
||||||
return
|
return
|
||||||
|
|
||||||
print("No DFU devices found!")
|
print("No DFU devices found!")
|
||||||
@ -108,37 +106,37 @@ def stm32_scan(args, test):
|
|||||||
bmp_devs.append(dev)
|
bmp_devs.append(dev)
|
||||||
|
|
||||||
if bmp == 0:
|
if bmp == 0:
|
||||||
if test == True:
|
if test:
|
||||||
return
|
return
|
||||||
|
|
||||||
print("No compatible device found\n")
|
print("No compatible device found\n")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
if bmp > 1 and not args.serial_target:
|
if bmp > 1 and not args.serial_target:
|
||||||
if test == True:
|
if test:
|
||||||
return
|
return
|
||||||
|
|
||||||
print("Found multiple devices:\n")
|
print("Found multiple devices:\n")
|
||||||
for dev in bmp_devs:
|
for dev in bmp_devs:
|
||||||
dfudev = dfu.dfu_device(*dev)
|
dfudev = dfu.dfu_device(*dev)
|
||||||
man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30)
|
man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30).decode('utf8')
|
||||||
product = dfudev.handle.getString(dfudev.dev.iProduct, 96)
|
product = dfudev.handle.getString(dfudev.dev.iProduct, 96).decode('utf8')
|
||||||
serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30)
|
serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30).decode('utf8')
|
||||||
print("Device ID:\t %04x:%04x" % (dfudev.dev.idVendor, dfudev.dev.idProduct))
|
print("Device ID:\t %04x:%04x" % (dfudev.dev.idVendor, dfudev.dev.idProduct))
|
||||||
print("Manufacturer:\t %s" % man)
|
print("Manufacturer:\t %s" % man)
|
||||||
print("Product:\t %s" % product)
|
print("Product:\t %s" % product)
|
||||||
print("Serial:\t\t %s\n" % serial_no)
|
print("Serial:\t\t %s\n" % serial_no)
|
||||||
|
|
||||||
print("Select device with serial number!")
|
print("Select device with serial number!")
|
||||||
exit (-1)
|
exit(-1)
|
||||||
|
|
||||||
for dev in bmp_devs:
|
for dev in bmp_devs:
|
||||||
dfudev = dfu.dfu_device(*dev)
|
dfudev = dfu.dfu_device(*dev)
|
||||||
man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30)
|
man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30).decode('utf8')
|
||||||
product = dfudev.handle.getString(dfudev.dev.iProduct, 96)
|
product = dfudev.handle.getString(dfudev.dev.iProduct, 96).decode('utf8')
|
||||||
serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30)
|
serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30).decode('utf8')
|
||||||
if args.serial_target:
|
if args.serial_target:
|
||||||
if man == "Black Sphere Technologies" and serial_no == args.serial_target:
|
if man == "Black Sphere Technologies" and serial_no == args.serial_target:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
if man == "Black Sphere Technologies":
|
if man == "Black Sphere Technologies":
|
||||||
@ -150,7 +148,7 @@ def stm32_scan(args, test):
|
|||||||
print("Serial:\t\t %s" % serial_no)
|
print("Serial:\t\t %s" % serial_no)
|
||||||
|
|
||||||
if args.serial_target and serial_no != args.serial_target:
|
if args.serial_target and serial_no != args.serial_target:
|
||||||
print("Serial number doesn't match!\n")
|
print("Serial number doesn't match %s vs %s!\n" % (serial_no, args.serial_target))
|
||||||
exit(-2)
|
exit(-2)
|
||||||
|
|
||||||
return dfudev
|
return dfudev
|
||||||
@ -172,7 +170,7 @@ if __name__ == "__main__":
|
|||||||
try:
|
try:
|
||||||
state = dfudev.get_state()
|
state = dfudev.get_state()
|
||||||
except:
|
except:
|
||||||
if args.manifest : exit(0)
|
if args.manifest: exit(0)
|
||||||
print("Failed to read device state! Assuming APP_IDLE")
|
print("Failed to read device state! Assuming APP_IDLE")
|
||||||
state = dfu.STATE_APP_IDLE
|
state = dfu.STATE_APP_IDLE
|
||||||
if state == dfu.STATE_APP_IDLE:
|
if state == dfu.STATE_APP_IDLE:
|
||||||
@ -183,15 +181,15 @@ if __name__ == "__main__":
|
|||||||
dfudev.release()
|
dfudev.release()
|
||||||
print("Invoking DFU Device")
|
print("Invoking DFU Device")
|
||||||
timeout = 0
|
timeout = 0
|
||||||
while True :
|
while True:
|
||||||
sleep(0.5)
|
sleep(1)
|
||||||
timeout = timeout + 0.5
|
timeout = timeout + 0.5
|
||||||
dfudev = stm32_scan(args, True)
|
dfudev = stm32_scan(args, True)
|
||||||
if dfudev: break
|
if dfudev: break
|
||||||
if timeout > 5 :
|
if timeout > 5:
|
||||||
print("Error: DFU device did not appear")
|
print("Error: DFU device did not appear")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
if args.manifest :
|
if args.manifest:
|
||||||
stm32_manifest(dfudev)
|
stm32_manifest(dfudev)
|
||||||
print("Invoking Application Device")
|
print("Invoking Application Device")
|
||||||
exit(0)
|
exit(0)
|
||||||
@ -203,17 +201,17 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
bin = file.read()
|
bin = file.read()
|
||||||
|
|
||||||
product = dfudev.handle.getString(dfudev.dev.iProduct, 64)
|
product = dfudev.handle.getString(dfudev.dev.iProduct, 64).decode('utf8')
|
||||||
if args.address :
|
if args.address:
|
||||||
start = int(args.address, 0)
|
start = int(args.address, 0)
|
||||||
else :
|
else:
|
||||||
if b"F4" in product:
|
if "F4" in product or "STLINK-V3" in product:
|
||||||
start = 0x8004000
|
start = 0x8004000
|
||||||
else:
|
else:
|
||||||
start = 0x8002000
|
start = 0x8002000
|
||||||
addr = start
|
addr = start
|
||||||
while bin:
|
while bin:
|
||||||
print ("Programming memory at 0x%08X" % addr, end="\r")
|
print("Programming memory at 0x%08X" % addr, end="\r")
|
||||||
stdout.flush()
|
stdout.flush()
|
||||||
try:
|
try:
|
||||||
# STM DFU bootloader erases always.
|
# STM DFU bootloader erases always.
|
||||||
@ -236,7 +234,7 @@ if __name__ == "__main__":
|
|||||||
bin = file.read()
|
bin = file.read()
|
||||||
len = len(bin)
|
len = len(bin)
|
||||||
addr = start
|
addr = start
|
||||||
print("-")
|
print("\n-")
|
||||||
while bin:
|
while bin:
|
||||||
try:
|
try:
|
||||||
stm32_set_address(dfudev, addr)
|
stm32_set_address(dfudev, addr)
|
||||||
@ -244,19 +242,19 @@ if __name__ == "__main__":
|
|||||||
except:
|
except:
|
||||||
# Abort silent if bootloader does not support upload
|
# Abort silent if bootloader does not support upload
|
||||||
break
|
break
|
||||||
print ("Verifying memory at 0x%08X" % addr, end="\r")
|
print("Verifying memory at 0x%08X" % addr, end="\r")
|
||||||
stdout.flush()
|
stdout.flush()
|
||||||
if len > 1024 :
|
if len > 1024:
|
||||||
size = 1024
|
size = 1024
|
||||||
else :
|
else:
|
||||||
size = len
|
size = len
|
||||||
if bin[:size] != bytearray(data[:size]) :
|
if bin[:size] != bytearray(data[:size]):
|
||||||
print ("\nMitmatch in block at 0x%08X" % addr)
|
print("\nMismatch in block at 0x%08X" % addr)
|
||||||
break;
|
break
|
||||||
bin = bin[1024:]
|
bin = bin[1024:]
|
||||||
addr += 1024
|
addr += 1024
|
||||||
len -= 1024
|
len -= 1024
|
||||||
if len <= 0 :
|
if len <= 0:
|
||||||
print("\nVerified!")
|
print("\nVerified!")
|
||||||
stm32_manifest(dfudev)
|
stm32_manifest(dfudev)
|
||||||
|
|
||||||
|
74
src/Makefile
74
src/Makefile
@ -9,7 +9,7 @@ Q := @
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS += -Wall -Wextra -Werror -Wno-char-subscripts \
|
CFLAGS += -Wall -Wextra -Werror -Wno-char-subscripts \
|
||||||
-std=gnu99 -g3 -MD -I./target \
|
-std=gnu99 -MD -I./target \
|
||||||
-I. -Iinclude -I$(PLATFORM_DIR)
|
-I. -Iinclude -I$(PLATFORM_DIR)
|
||||||
|
|
||||||
ifeq ($(ENABLE_DEBUG), 1)
|
ifeq ($(ENABLE_DEBUG), 1)
|
||||||
@ -39,6 +39,7 @@ SRC = \
|
|||||||
lpc17xx.c \
|
lpc17xx.c \
|
||||||
lpc15xx.c \
|
lpc15xx.c \
|
||||||
lpc43xx.c \
|
lpc43xx.c \
|
||||||
|
lpc546xx.c \
|
||||||
kinetis.c \
|
kinetis.c \
|
||||||
main.c \
|
main.c \
|
||||||
morse.c \
|
morse.c \
|
||||||
@ -47,20 +48,24 @@ SRC = \
|
|||||||
nxpke04.c \
|
nxpke04.c \
|
||||||
platform.c \
|
platform.c \
|
||||||
remote.c \
|
remote.c \
|
||||||
|
rp.c \
|
||||||
sam3x.c \
|
sam3x.c \
|
||||||
sam4l.c \
|
sam4l.c \
|
||||||
samd.c \
|
samd.c \
|
||||||
samx5x.c \
|
samx5x.c \
|
||||||
stm32f1.c \
|
stm32f1.c \
|
||||||
|
ch32f1.c \
|
||||||
stm32f4.c \
|
stm32f4.c \
|
||||||
stm32h7.c \
|
stm32h7.c \
|
||||||
stm32l0.c \
|
stm32l0.c \
|
||||||
stm32l4.c \
|
stm32l4.c \
|
||||||
|
stm32g0.c \
|
||||||
target.c \
|
target.c \
|
||||||
|
|
||||||
|
|
||||||
include $(PLATFORM_DIR)/Makefile.inc
|
include $(PLATFORM_DIR)/Makefile.inc
|
||||||
|
|
||||||
OPT_FLAGS ?= -Og
|
OPT_FLAGS ?= -Os
|
||||||
CFLAGS += $(OPT_FLAGS)
|
CFLAGS += $(OPT_FLAGS)
|
||||||
LDFLAGS += $(OPT_FLAGS)
|
LDFLAGS += $(OPT_FLAGS)
|
||||||
|
|
||||||
@ -85,8 +90,28 @@ VPATH += platforms/common
|
|||||||
CFLAGS += -Iplatforms/common
|
CFLAGS += -Iplatforms/common
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ENABLE_RTT), 1)
|
||||||
|
CFLAGS += -DENABLE_RTT
|
||||||
|
SRC += rtt.c rtt_if.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef RTT_IDENT
|
||||||
|
CFLAGS += -DRTT_IDENT=$(RTT_IDENT)
|
||||||
|
endif
|
||||||
|
|
||||||
OBJ = $(patsubst %.S,%.o,$(patsubst %.c,%.o,$(SRC)))
|
OBJ = $(patsubst %.S,%.o,$(patsubst %.c,%.o,$(SRC)))
|
||||||
|
|
||||||
|
OPTIMIZE := swdptap.o jtagtap.o \
|
||||||
|
adiv5_jtagdp.o adiv5_swdp.o adiv5.o \
|
||||||
|
cortexa.o cortexm.o \
|
||||||
|
gdb_if.o gdb_main.o gdb_hostio.o gdb_packet.o \
|
||||||
|
jtag_devs.o jtag_scan.o \
|
||||||
|
crc32.o main.o \
|
||||||
|
cdcacm.o jeff.o timing.o traceswo.o usbuart.o \
|
||||||
|
|
||||||
|
$(OPTIMIZE):: CFLAGS := $(filter-out -Os, $(CFLAGS))
|
||||||
|
$(OPTIMIZE):: CFLAGS += -O3
|
||||||
|
|
||||||
$(TARGET): include/version.h $(OBJ)
|
$(TARGET): include/version.h $(OBJ)
|
||||||
@echo " LD $@"
|
@echo " LD $@"
|
||||||
$(Q)$(CC) -o $@ $(OBJ) $(LDFLAGS)
|
$(Q)$(CC) -o $@ $(OBJ) $(LDFLAGS)
|
||||||
@ -102,14 +127,14 @@ $(TARGET): include/version.h $(OBJ)
|
|||||||
ifndef PC_HOSTED
|
ifndef PC_HOSTED
|
||||||
%.bin: %.elf
|
%.bin: %.elf
|
||||||
@echo " OBJCOPY $@"
|
@echo " OBJCOPY $@"
|
||||||
$(Q)$(OBJCOPY) -O binary $^ $@
|
$(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) -O binary $^ $@
|
||||||
|
|
||||||
%.hex: %.elf
|
%.hex: %.elf
|
||||||
@echo " OBJCOPY $@"
|
@echo " OBJCOPY $@"
|
||||||
$(Q)$(OBJCOPY) -O ihex $^ $@
|
$(Q)$(OBJCOPY) -O ihex $^ $@
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: clean host_clean all_platforms FORCE
|
.PHONY: clean host_clean all_platforms clang-format FORCE
|
||||||
|
|
||||||
clean: host_clean
|
clean: host_clean
|
||||||
$(Q)echo " CLEAN"
|
$(Q)echo " CLEAN"
|
||||||
@ -117,16 +142,27 @@ clean: host_clean
|
|||||||
-$(Q)$(RM) platforms/*/*.o platforms/*/*.d mapfile include/version.h
|
-$(Q)$(RM) platforms/*/*.o platforms/*/*.d mapfile include/version.h
|
||||||
|
|
||||||
all_platforms:
|
all_platforms:
|
||||||
|
$(Q)if [ ! -f ../libopencm3/Makefile ]; then \
|
||||||
|
echo "Initialising git submodules..." ;\
|
||||||
|
git submodule init ;\
|
||||||
|
git submodule update ;\
|
||||||
|
fi
|
||||||
|
$(Q)$(MAKE) $(MFLAGS) -C ../libopencm3 lib/stm32/f1 lib/stm32/f4 lib/lm4f
|
||||||
$(Q)set -e ;\
|
$(Q)set -e ;\
|
||||||
mkdir -p artifacts/$(shell git describe --always) ;\
|
mkdir -p artifacts/$(shell git describe --always --dirty --tags) ;\
|
||||||
echo "<html><body><ul>" > artifacts/index.html ;\
|
echo "<html><body><ul>" > artifacts/index.html ;\
|
||||||
|
$(MAKE) clean ;\
|
||||||
for i in platforms/*/Makefile.inc ; do \
|
for i in platforms/*/Makefile.inc ; do \
|
||||||
export DIRNAME=`dirname $$i` ;\
|
export DIRNAME=`dirname $$i` ;\
|
||||||
export PROBE_HOST=`basename $$DIRNAME` ;\
|
export PROBE_HOST=`basename $$DIRNAME` ;\
|
||||||
export CFLAGS=-Werror ;\
|
export CFLAGS=-Werror ;\
|
||||||
echo "Building for hardware platform: $$PROBE_HOST" ;\
|
echo "Building for hardware platform: $$PROBE_HOST" ;\
|
||||||
$(MAKE) $(MAKEFLAGS) clean ;\
|
$(MAKE);\
|
||||||
$(MAKE) $(MAKEFLAGS);\
|
if [ -f blackmagic ]; then \
|
||||||
|
mv blackmagic artifacts/blackmagic-$$PROBE_HOST ;\
|
||||||
|
echo "<li><a href='blackmagic-$$PROBE_HOST'>$$PROBE_HOST</a></li>"\
|
||||||
|
>> artifacts/index.html ;\
|
||||||
|
fi ;\
|
||||||
if [ -f blackmagic.bin ]; then \
|
if [ -f blackmagic.bin ]; then \
|
||||||
mv blackmagic.bin artifacts/blackmagic-$$PROBE_HOST.bin ;\
|
mv blackmagic.bin artifacts/blackmagic-$$PROBE_HOST.bin ;\
|
||||||
echo "<li><a href='blackmagic-$$PROBE_HOST.bin'>$$PROBE_HOST</a></li>"\
|
echo "<li><a href='blackmagic-$$PROBE_HOST.bin'>$$PROBE_HOST</a></li>"\
|
||||||
@ -137,13 +173,31 @@ all_platforms:
|
|||||||
echo "<li><a href='blackmagic_dfu-$$PROBE_HOST.bin'>$$PROBE_HOST DFU</a></li>"\
|
echo "<li><a href='blackmagic_dfu-$$PROBE_HOST.bin'>$$PROBE_HOST DFU</a></li>"\
|
||||||
>> artifacts/index.html ;\
|
>> artifacts/index.html ;\
|
||||||
fi ;\
|
fi ;\
|
||||||
|
$(MAKE) clean ;\
|
||||||
done ;\
|
done ;\
|
||||||
echo "</ul></body></html>" >> artifacts/index.html ;\
|
echo "</ul></body></html>" >> artifacts/index.html ;\
|
||||||
cp artifacts/*.bin artifacts/$(shell git describe --always)
|
cp artifacts/blackmagic* artifacts/$(shell git describe --always --dirty --tags)
|
||||||
|
|
||||||
command.c: include/version.h
|
command.c: include/version.h
|
||||||
|
|
||||||
|
GIT_VERSION := $(shell git describe --always --dirty --tags)
|
||||||
|
VERSION_HEADER := \#define FIRMWARE_VERSION "$(GIT_VERSION)"
|
||||||
|
|
||||||
include/version.h: FORCE
|
include/version.h: FORCE
|
||||||
$(Q)echo " GIT include/version.h"
|
@# If git isn't found then GIT_VERSION will be an empty string.
|
||||||
$(Q)echo "#define FIRMWARE_VERSION \"$(shell git describe --always --dirty)\"" > $@
|
ifeq ($(GIT_VERSION),)
|
||||||
|
@echo Git not found, assuming up to date include/version.h
|
||||||
|
else
|
||||||
|
@# Note that when we echo the version to the header file, echo writes a final newline
|
||||||
|
@# to the file. This is fine and probably makes the file more human-readable, but
|
||||||
|
@# also means we have to account for that newline in this comparison.
|
||||||
|
$(Q)if [ ! -f $@ ] || [ "$$(cat $@)" != "$$(echo '$(VERSION_HEADER)\n')" ]; then \
|
||||||
|
echo " GEN $@"; \
|
||||||
|
echo '$(VERSION_HEADER)' > $@; \
|
||||||
|
fi
|
||||||
|
endif
|
||||||
|
|
||||||
|
clang-format:
|
||||||
|
$(Q)clang-format -i *.c */*.c */*/*.c *.h */*.h */*/*.h
|
||||||
|
|
||||||
-include *.d
|
-include *.d
|
||||||
|
273
src/command.c
273
src/command.c
@ -3,6 +3,8 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
||||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||||
|
* Copyright (C) 2021 Uwe Bonnes
|
||||||
|
* (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -27,28 +29,28 @@
|
|||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "gdb_packet.h"
|
#include "gdb_packet.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
|
#include "target_internal.h"
|
||||||
#include "morse.h"
|
#include "morse.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "serialno.h"
|
#include "serialno.h"
|
||||||
|
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
#include "rtt.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef PLATFORM_HAS_TRACESWO
|
#ifdef PLATFORM_HAS_TRACESWO
|
||||||
# include "traceswo.h"
|
# include "traceswo.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef bool (*cmd_handler)(target *t, int argc, const char **argv);
|
|
||||||
|
|
||||||
struct command_s {
|
|
||||||
const char *cmd;
|
|
||||||
cmd_handler handler;
|
|
||||||
|
|
||||||
const char *help;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool cmd_version(target *t, int argc, char **argv);
|
static bool cmd_version(target *t, int argc, char **argv);
|
||||||
|
#ifdef PLATFORM_HAS_PRINTSERIAL
|
||||||
|
static bool cmd_serial(target *t, int argc, char **argv);
|
||||||
|
#endif
|
||||||
static bool cmd_help(target *t, int argc, char **argv);
|
static bool cmd_help(target *t, int argc, char **argv);
|
||||||
|
|
||||||
static bool cmd_jtag_scan(target *t, int argc, char **argv);
|
static bool cmd_jtag_scan(target *t, int argc, char **argv);
|
||||||
static bool cmd_swdp_scan(target *t, int argc, char **argv);
|
static bool cmd_swdp_scan(target *t, int argc, char **argv);
|
||||||
|
static bool cmd_frequency(target *t, int argc, char **argv);
|
||||||
static bool cmd_targets(target *t, int argc, char **argv);
|
static bool cmd_targets(target *t, int argc, char **argv);
|
||||||
static bool cmd_morse(target *t, int argc, char **argv);
|
static bool cmd_morse(target *t, int argc, char **argv);
|
||||||
static bool cmd_halt_timeout(target *t, int argc, const char **argv);
|
static bool cmd_halt_timeout(target *t, int argc, const char **argv);
|
||||||
@ -61,15 +63,29 @@ static bool cmd_target_power(target *t, int argc, const char **argv);
|
|||||||
static bool cmd_traceswo(target *t, int argc, const char **argv);
|
static bool cmd_traceswo(target *t, int argc, const char **argv);
|
||||||
#endif
|
#endif
|
||||||
static bool cmd_heapinfo(target *t, int argc, const char **argv);
|
static bool cmd_heapinfo(target *t, int argc, const char **argv);
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
static bool cmd_rtt(target *t, int argc, const char **argv);
|
||||||
|
#endif
|
||||||
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
|
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
|
||||||
static bool cmd_debug_bmp(target *t, int argc, const char **argv);
|
static bool cmd_debug_bmp(target *t, int argc, const char **argv);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
|
||||||
|
static bool cmd_convert_tdio(target *t, int argc, const char **argv);
|
||||||
|
static bool cmd_set_srst(target *t, int argc, const char **argv);
|
||||||
|
#endif
|
||||||
|
#ifdef PLATFORM_HAS_BOOTLOADER
|
||||||
|
static bool cmd_enter_bootldr(target *t, int argc, const char **argv);
|
||||||
|
#endif
|
||||||
|
|
||||||
const struct command_s cmd_list[] = {
|
const struct command_s cmd_list[] = {
|
||||||
{"version", (cmd_handler)cmd_version, "Display firmware version info"},
|
{"version", (cmd_handler)cmd_version, "Display firmware version info"},
|
||||||
|
#ifdef PLATFORM_HAS_PRINTSERIAL
|
||||||
|
{"serial", (cmd_handler)cmd_serial, "Display firmware serial number"},
|
||||||
|
#endif
|
||||||
{"help", (cmd_handler)cmd_help, "Display help for monitor commands"},
|
{"help", (cmd_handler)cmd_help, "Display help for monitor commands"},
|
||||||
{"jtag_scan", (cmd_handler)cmd_jtag_scan, "Scan JTAG chain for devices" },
|
{"jtag_scan", (cmd_handler)cmd_jtag_scan, "Scan JTAG chain for devices" },
|
||||||
{"swdp_scan", (cmd_handler)cmd_swdp_scan, "Scan SW-DP for devices" },
|
{"swdp_scan", (cmd_handler)cmd_swdp_scan, "Scan SW-DP for devices" },
|
||||||
|
{"frequency", (cmd_handler)cmd_frequency, "set minimum high and low times" },
|
||||||
{"targets", (cmd_handler)cmd_targets, "Display list of available targets" },
|
{"targets", (cmd_handler)cmd_targets, "Display list of available targets" },
|
||||||
{"morse", (cmd_handler)cmd_morse, "Display morse error message" },
|
{"morse", (cmd_handler)cmd_morse, "Display morse error message" },
|
||||||
{"halt_timeout", (cmd_handler)cmd_halt_timeout, "Timeout (ms) to wait until Cortex-M is halted: (Default 2000)" },
|
{"halt_timeout", (cmd_handler)cmd_halt_timeout, "Timeout (ms) to wait until Cortex-M is halted: (Default 2000)" },
|
||||||
@ -78,6 +94,9 @@ const struct command_s cmd_list[] = {
|
|||||||
#ifdef PLATFORM_HAS_POWER_SWITCH
|
#ifdef PLATFORM_HAS_POWER_SWITCH
|
||||||
{"tpwr", (cmd_handler)cmd_target_power, "Supplies power to the target: (enable|disable)"},
|
{"tpwr", (cmd_handler)cmd_target_power, "Supplies power to the target: (enable|disable)"},
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
{"rtt", (cmd_handler)cmd_rtt, "enable|disable|status|channel 0..15|ident (str)|cblock|poll maxms minms maxerr" },
|
||||||
|
#endif
|
||||||
#ifdef PLATFORM_HAS_TRACESWO
|
#ifdef PLATFORM_HAS_TRACESWO
|
||||||
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2
|
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2
|
||||||
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, NRZ mode: (baudrate) (decode channel ...)" },
|
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, NRZ mode: (baudrate) (decode channel ...)" },
|
||||||
@ -88,6 +107,13 @@ const struct command_s cmd_list[] = {
|
|||||||
{"heapinfo", (cmd_handler)cmd_heapinfo, "Set semihosting heapinfo" },
|
{"heapinfo", (cmd_handler)cmd_heapinfo, "Set semihosting heapinfo" },
|
||||||
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
|
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
|
||||||
{"debug_bmp", (cmd_handler)cmd_debug_bmp, "Output BMP \"debug\" strings to the second vcom: (enable|disable)"},
|
{"debug_bmp", (cmd_handler)cmd_debug_bmp, "Output BMP \"debug\" strings to the second vcom: (enable|disable)"},
|
||||||
|
#endif
|
||||||
|
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
|
||||||
|
{"convert_tdio", (cmd_handler)cmd_convert_tdio,"Switch TDI/O pins to UART TX/RX functions"},
|
||||||
|
{"set_srst", (cmd_handler)cmd_set_srst,"Set output state of SRST pin (enable|disable)"},
|
||||||
|
#endif
|
||||||
|
#ifdef PLATFORM_HAS_BOOTLOADER
|
||||||
|
{"enter_bootldr", (cmd_handler)cmd_enter_bootldr,"Force BMP into bootloader mode"},
|
||||||
#endif
|
#endif
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
@ -96,7 +122,7 @@ bool connect_assert_srst;
|
|||||||
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
|
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
|
||||||
bool debug_bmp;
|
bool debug_bmp;
|
||||||
#endif
|
#endif
|
||||||
long cortexm_wait_timeout = 2000; /* Timeout to wait for Cortex to react on halt command. */
|
unsigned cortexm_wait_timeout = 2000; /* Timeout to wait for Cortex to react on halt command. */
|
||||||
|
|
||||||
int command_process(target *t, char *cmd)
|
int command_process(target *t, char *cmd)
|
||||||
{
|
{
|
||||||
@ -131,20 +157,24 @@ int command_process(target *t, char *cmd)
|
|||||||
return target_command(t, argc, argv);
|
return target_command(t, argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BOARD_IDENT "Black Magic Probe" PLATFORM_IDENT FIRMWARE_VERSION
|
||||||
|
|
||||||
bool cmd_version(target *t, int argc, char **argv)
|
bool cmd_version(target *t, int argc, char **argv)
|
||||||
{
|
{
|
||||||
(void)t;
|
(void)t;
|
||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
#if PC_HOSTED == 1
|
#if PC_HOSTED == 1
|
||||||
gdb_outf("Black Magic Probe, PC-Hosted for " PLATFORM_IDENT()
|
char ident[256];
|
||||||
", Version " FIRMWARE_VERSION "\n");
|
gdb_ident(ident, sizeof(ident));
|
||||||
|
DEBUG_WARN("%s\n", ident);
|
||||||
#else
|
#else
|
||||||
gdb_outf("Black Magic Probe (Firmware " FIRMWARE_VERSION ") (Hardware Version %d)\n", platform_hwversion());
|
gdb_out(BOARD_IDENT);
|
||||||
#endif
|
gdb_outf(", Hardware Version %d\n", platform_hwversion());
|
||||||
gdb_out("Copyright (C) 2015 Black Sphere Technologies Ltd.\n");
|
gdb_out("Copyright (C) 2022 Black Magic Debug Project\n");
|
||||||
gdb_out("License GPLv3+: GNU GPL version 3 or later "
|
gdb_out("License GPLv3+: GNU GPL version 3 or later "
|
||||||
"<http://gnu.org/licenses/gpl.html>\n\n");
|
"<http://gnu.org/licenses/gpl.html>\n\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -155,10 +185,11 @@ bool cmd_help(target *t, int argc, char **argv)
|
|||||||
(void)argv;
|
(void)argv;
|
||||||
const struct command_s *c;
|
const struct command_s *c;
|
||||||
|
|
||||||
gdb_out("General commands:\n");
|
if (!t || t->tc->destroy_callback) {
|
||||||
for(c = cmd_list; c->cmd; c++)
|
gdb_out("General commands:\n");
|
||||||
gdb_outf("\t%s -- %s\n", c->cmd, c->help);
|
for(c = cmd_list; c->cmd; c++)
|
||||||
|
gdb_outf("\t%s -- %s\n", c->cmd, c->help);
|
||||||
|
}
|
||||||
if (!t)
|
if (!t)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -216,8 +247,9 @@ static bool cmd_jtag_scan(target *t, int argc, char **argv)
|
|||||||
bool cmd_swdp_scan(target *t, int argc, char **argv)
|
bool cmd_swdp_scan(target *t, int argc, char **argv)
|
||||||
{
|
{
|
||||||
(void)t;
|
(void)t;
|
||||||
(void)argc;
|
volatile uint32_t targetid = 0;
|
||||||
(void)argv;
|
if (argc > 1)
|
||||||
|
targetid = strtol(argv[1], NULL, 0);
|
||||||
if (platform_target_voltage())
|
if (platform_target_voltage())
|
||||||
gdb_outf("Target voltage: %s\n", platform_target_voltage());
|
gdb_outf("Target voltage: %s\n", platform_target_voltage());
|
||||||
|
|
||||||
@ -228,9 +260,9 @@ bool cmd_swdp_scan(target *t, int argc, char **argv)
|
|||||||
volatile struct exception e;
|
volatile struct exception e;
|
||||||
TRY_CATCH (e, EXCEPTION_ALL) {
|
TRY_CATCH (e, EXCEPTION_ALL) {
|
||||||
#if PC_HOSTED == 1
|
#if PC_HOSTED == 1
|
||||||
devs = platform_adiv5_swdp_scan();
|
devs = platform_adiv5_swdp_scan(targetid);
|
||||||
#else
|
#else
|
||||||
devs = adiv5_swdp_scan();
|
devs = adiv5_swdp_scan(targetid);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
@ -254,12 +286,46 @@ bool cmd_swdp_scan(target *t, int argc, char **argv)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cmd_frequency(target *t, int argc, char **argv)
|
||||||
|
{
|
||||||
|
(void)t;
|
||||||
|
if (argc == 2) {
|
||||||
|
char *p;
|
||||||
|
uint32_t frequency = strtol(argv[1], &p, 10);
|
||||||
|
switch(*p) {
|
||||||
|
case 'k':
|
||||||
|
frequency *= 1000;
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
frequency *= 1000*1000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
platform_max_frequency_set(frequency);
|
||||||
|
}
|
||||||
|
uint32_t freq = platform_max_frequency_get();
|
||||||
|
if (freq == FREQ_FIXED)
|
||||||
|
gdb_outf("SWJ freq fixed\n");
|
||||||
|
else
|
||||||
|
gdb_outf("Max SWJ freq %08" PRIx32 "\n", freq);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static void display_target(int i, target *t, void *context)
|
static void display_target(int i, target *t, void *context)
|
||||||
{
|
{
|
||||||
(void)context;
|
(void)context;
|
||||||
gdb_outf("%2d %c %s %s\n", i, target_attached(t)?'*':' ',
|
if (!strcmp(target_driver_name(t), "ARM Cortex-M")) {
|
||||||
target_driver_name(t),
|
gdb_outf("***%2d%sUnknown %s Designer %3x Partno %3x %s\n",
|
||||||
(target_core_name(t)) ? target_core_name(t): "");
|
i, target_attached(t)?" * ":" ",
|
||||||
|
target_driver_name(t),
|
||||||
|
target_designer(t),
|
||||||
|
target_idcode(t),
|
||||||
|
(target_core_name(t)) ? target_core_name(t): "");
|
||||||
|
} else {
|
||||||
|
gdb_outf("%2d %c %s %s\n", i, target_attached(t)?'*':' ',
|
||||||
|
target_driver_name(t),
|
||||||
|
(target_core_name(t)) ? target_core_name(t): "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cmd_targets(target *t, int argc, char **argv)
|
bool cmd_targets(target *t, int argc, char **argv)
|
||||||
@ -282,8 +348,10 @@ bool cmd_morse(target *t, int argc, char **argv)
|
|||||||
(void)t;
|
(void)t;
|
||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
if(morse_msg)
|
if(morse_msg) {
|
||||||
gdb_outf("%s\n", morse_msg);
|
gdb_outf("%s\n", morse_msg);
|
||||||
|
DEBUG_WARN("%s\n", morse_msg);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,8 +423,15 @@ static bool cmd_target_power(target *t, int argc, const char **argv)
|
|||||||
} else if (argc == 2) {
|
} else if (argc == 2) {
|
||||||
bool want_enable = false;
|
bool want_enable = false;
|
||||||
if (parse_enable_or_disable(argv[1], &want_enable)) {
|
if (parse_enable_or_disable(argv[1], &want_enable)) {
|
||||||
platform_target_set_power(want_enable);
|
if (want_enable
|
||||||
gdb_outf("%s target power\n", want_enable ? "Enabling" : "Disabling");
|
&& !platform_target_get_power()
|
||||||
|
&& platform_target_voltage_sense() > POWER_CONFLICT_THRESHOLD) {
|
||||||
|
/* want to enable target power, but VREF > 0.5V sensed -> cancel */
|
||||||
|
gdb_outf("Target already powered (%s)\n", platform_target_voltage());
|
||||||
|
} else {
|
||||||
|
platform_target_set_power(want_enable);
|
||||||
|
gdb_outf("%s target power\n", want_enable ? "Enabling" : "Disabling");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gdb_outf("Unrecognized command format\n");
|
gdb_outf("Unrecognized command format\n");
|
||||||
@ -365,10 +440,86 @@ static bool cmd_target_power(target *t, int argc, const char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
static const char *on_or_off(const bool value)
|
||||||
|
{
|
||||||
|
return value ? "on" : "off";
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cmd_rtt(target *t, int argc, const char **argv)
|
||||||
|
{
|
||||||
|
(void)t;
|
||||||
|
const size_t command_len = strlen(argv[1]);
|
||||||
|
if (argc == 1 || (argc == 2 && !strncmp(argv[1], "enabled", command_len))) {
|
||||||
|
rtt_enabled = true;
|
||||||
|
rtt_found = false;
|
||||||
|
} else if ((argc == 2) && !strncmp(argv[1], "disabled", command_len)) {
|
||||||
|
rtt_enabled = false;
|
||||||
|
rtt_found = false;
|
||||||
|
} else if ((argc == 2) && !strncmp(argv[1], "status", command_len)) {
|
||||||
|
gdb_outf("rtt: %s found: %s ident: \"%s\"", on_or_off(rtt_enabled), rtt_found ? "yes" : "no",
|
||||||
|
rtt_ident[0] == '\0' ? "off" : rtt_ident);
|
||||||
|
gdb_outf(" halt: %s", on_or_off(target_no_background_memory_access(t)));
|
||||||
|
gdb_out(" channels: ");
|
||||||
|
if (rtt_auto_channel)
|
||||||
|
gdb_out("auto ");
|
||||||
|
for (size_t i = 0; i < MAX_RTT_CHAN; i++) {
|
||||||
|
if (rtt_channel[i].is_enabled)
|
||||||
|
gdb_outf("%d ", i);
|
||||||
|
}
|
||||||
|
gdb_outf(
|
||||||
|
"\nmax poll ms: %u min poll ms: %u max errs: %u\n", rtt_max_poll_ms, rtt_min_poll_ms, rtt_max_poll_errs);
|
||||||
|
} else if (argc >= 2 && !strncmp(argv[1], "channel", command_len)) {
|
||||||
|
/* mon rtt channel switches to auto rtt channel selection
|
||||||
|
mon rtt channel number... selects channels given */
|
||||||
|
for (size_t i = 0; i < MAX_RTT_CHAN; i++)
|
||||||
|
rtt_channel[i].is_enabled = false;
|
||||||
|
|
||||||
|
if (argc == 2)
|
||||||
|
rtt_auto_channel = true;
|
||||||
|
else {
|
||||||
|
rtt_auto_channel = false;
|
||||||
|
for (size_t i = 2; i < (size_t)argc; ++i) {
|
||||||
|
const uint32_t channel = strtoul(argv[i], NULL, 0);
|
||||||
|
if (channel < MAX_RTT_CHAN)
|
||||||
|
rtt_channel[channel].is_enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (argc == 2 && !strncmp(argv[1], "ident", command_len))
|
||||||
|
rtt_ident[0] = '\0';
|
||||||
|
else if (argc == 2 && !strncmp(argv[1], "poll", command_len))
|
||||||
|
gdb_outf("%u %u %u\n", rtt_max_poll_ms, rtt_min_poll_ms, rtt_max_poll_errs);
|
||||||
|
else if (argc == 2 && !strncmp(argv[1], "cblock", command_len)) {
|
||||||
|
gdb_outf("cbaddr: 0x%x\n", rtt_cbaddr);
|
||||||
|
gdb_out("ch ena cfg i/o buf@ size head@ tail@ flg\n");
|
||||||
|
for (size_t i = 0; i < MAX_RTT_CHAN; ++i) {
|
||||||
|
gdb_outf("%2zu %c %c %s 0x%08x %5d 0x%08x 0x%08x %d\n", i, rtt_channel[i].is_enabled ? 'y' : 'n',
|
||||||
|
rtt_channel[i].is_configured ? 'y' : 'n', rtt_channel[i].is_output ? "out" : "in ",
|
||||||
|
rtt_channel[i].buf_addr, rtt_channel[i].buf_size, rtt_channel[i].head_addr, rtt_channel[i].tail_addr,
|
||||||
|
rtt_channel[i].flag);
|
||||||
|
}
|
||||||
|
} else if (argc == 3 && !strncmp(argv[1], "ident", command_len)) {
|
||||||
|
strncpy(rtt_ident, argv[2], sizeof(rtt_ident));
|
||||||
|
rtt_ident[sizeof(rtt_ident) - 1] = '\0';
|
||||||
|
for (size_t i = 0; i < sizeof(rtt_ident); i++) {
|
||||||
|
if (rtt_ident[i] == '_')
|
||||||
|
rtt_ident[i] = ' ';
|
||||||
|
}
|
||||||
|
} else if (argc == 5 && !strncmp(argv[1], "poll", command_len)) {
|
||||||
|
/* set polling params */
|
||||||
|
rtt_max_poll_ms = strtoul(argv[2], NULL, 0);
|
||||||
|
rtt_min_poll_ms = strtoul(argv[3], NULL, 0);
|
||||||
|
rtt_max_poll_errs = strtoul(argv[4], NULL, 0);
|
||||||
|
} else
|
||||||
|
gdb_out("what?\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef PLATFORM_HAS_TRACESWO
|
#ifdef PLATFORM_HAS_TRACESWO
|
||||||
static bool cmd_traceswo(target *t, int argc, const char **argv)
|
static bool cmd_traceswo(target *t, int argc, const char **argv)
|
||||||
{
|
{
|
||||||
char serial_no[13];
|
char serial_no[DFU_SERIAL_LENGTH];
|
||||||
(void)t;
|
(void)t;
|
||||||
#if TRACESWO_PROTOCOL == 2
|
#if TRACESWO_PROTOCOL == 2
|
||||||
uint32_t baudrate = SWO_DEFAULT_BAUD;
|
uint32_t baudrate = SWO_DEFAULT_BAUD;
|
||||||
@ -414,7 +565,7 @@ static bool cmd_traceswo(target *t, int argc, const char **argv)
|
|||||||
#else
|
#else
|
||||||
traceswo_init(swo_channelmask);
|
traceswo_init(swo_channelmask);
|
||||||
#endif
|
#endif
|
||||||
serial_no_read(serial_no, sizeof(serial_no));
|
serial_no_read(serial_no);
|
||||||
gdb_outf("%s:%02X:%02X\n", serial_no, 5, 0x85);
|
gdb_outf("%s:%02X:%02X\n", serial_no, 5, 0x85);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -442,6 +593,66 @@ static bool cmd_debug_bmp(target *t, int argc, const char **argv)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
|
||||||
|
static bool cmd_convert_tdio(target *t, int argc, const char **argv)
|
||||||
|
{
|
||||||
|
(void)t;
|
||||||
|
|
||||||
|
uint8_t val;
|
||||||
|
if (argc > 1) {
|
||||||
|
val = (!strcmp(argv[1], "enable")) ? true : false;
|
||||||
|
usbuart_convert_tdio(val);
|
||||||
|
} else {
|
||||||
|
gdb_outf("Convert_tdio: %s\n",(usbuart_convert_tdio_enabled()) ?
|
||||||
|
"enabled" : "disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cmd_set_srst(target *t, int argc, const char **argv)
|
||||||
|
{
|
||||||
|
(void) t;
|
||||||
|
|
||||||
|
uint8_t val;
|
||||||
|
if (argc > 1) {
|
||||||
|
val = (!strcmp(argv[1], "enable")) ? true : false;
|
||||||
|
platform_srst_set_val(val);
|
||||||
|
} else {
|
||||||
|
gdb_outf("SRST: %s\n",(platform_srst_get_val()) ?
|
||||||
|
"enabled" : "disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PLATFORM_HAS_BOOTLOADER
|
||||||
|
static bool cmd_enter_bootldr(target *t, int argc, const char **argv)
|
||||||
|
{
|
||||||
|
(void) t;
|
||||||
|
(void) argc;
|
||||||
|
(void) argv;
|
||||||
|
|
||||||
|
scb_reset_system();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PLATFORM_HAS_PRINTSERIAL
|
||||||
|
bool cmd_serial(target *t, int argc, char **argv)
|
||||||
|
{
|
||||||
|
(void) t;
|
||||||
|
(void) argc;
|
||||||
|
(void) argv;
|
||||||
|
|
||||||
|
print_serial();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static bool cmd_heapinfo(target *t, int argc, const char **argv)
|
static bool cmd_heapinfo(target *t, int argc, const char **argv)
|
||||||
{
|
{
|
||||||
if (t == NULL) gdb_out("not attached\n");
|
if (t == NULL) gdb_out("not attached\n");
|
||||||
|
53
src/crc32.c
53
src/crc32.c
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
|
#include "gdb_if.h"
|
||||||
|
|
||||||
#if !defined(STM32F0) && !defined(STM32F1) && !defined(STM32F2) && \
|
#if !defined(STM32F0) && !defined(STM32F1) && !defined(STM32F2) && \
|
||||||
!defined(STM32F3) && !defined(STM32F4) && !defined(STM32F7) && \
|
!defined(STM32F3) && !defined(STM32F4) && !defined(STM32F7) && \
|
||||||
@ -97,14 +98,33 @@ static uint32_t crc32_calc(uint32_t crc, uint8_t data)
|
|||||||
return (crc << 8) ^ crc32_table[((crc >> 24) ^ data) & 255];
|
return (crc << 8) ^ crc32_table[((crc >> 24) ^ data) & 255];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t generic_crc32(target *t, uint32_t base, size_t len)
|
int generic_crc32(target *t, uint32_t *crc_res, uint32_t base, size_t len)
|
||||||
{
|
{
|
||||||
uint32_t crc = -1;
|
uint32_t crc = -1;
|
||||||
|
#if PC_HOSTED == 1
|
||||||
|
/* Reading a 2 MByte on a H743 takes about 80 s@128, 28s @ 1k,
|
||||||
|
* 22 s @ 4k and 21 s @ 64k
|
||||||
|
*/
|
||||||
|
uint8_t bytes[0x1000];
|
||||||
|
#else
|
||||||
uint8_t bytes[128];
|
uint8_t bytes[128];
|
||||||
|
#endif
|
||||||
|
#if defined(ENABLE_DEBUG)
|
||||||
|
uint32_t start_time = platform_time_ms();
|
||||||
|
#endif
|
||||||
|
uint32_t last_time = platform_time_ms();
|
||||||
while (len) {
|
while (len) {
|
||||||
|
uint32_t actual_time = platform_time_ms();
|
||||||
|
if ( actual_time > last_time + 1000) {
|
||||||
|
last_time = actual_time;
|
||||||
|
gdb_if_putchar(0, true);
|
||||||
|
}
|
||||||
size_t read_len = MIN(sizeof(bytes), len);
|
size_t read_len = MIN(sizeof(bytes), len);
|
||||||
target_mem_read(t, bytes, base, read_len);
|
if (target_mem_read(t, bytes, base, read_len)) {
|
||||||
|
DEBUG_WARN("generic_crc32 error around address 0x%08" PRIx32 "\n",
|
||||||
|
base);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < read_len; i++)
|
for (unsigned i = 0; i < read_len; i++)
|
||||||
crc = crc32_calc(crc, bytes[i]);
|
crc = crc32_calc(crc, bytes[i]);
|
||||||
@ -112,20 +132,32 @@ uint32_t generic_crc32(target *t, uint32_t base, size_t len)
|
|||||||
base += read_len;
|
base += read_len;
|
||||||
len -= read_len;
|
len -= read_len;
|
||||||
}
|
}
|
||||||
return crc;
|
DEBUG_WARN("%" PRIu32 " ms\n", platform_time_ms() - start_time);
|
||||||
|
*crc_res = crc;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#include <libopencm3/stm32/crc.h>
|
#include <libopencm3/stm32/crc.h>
|
||||||
uint32_t generic_crc32(target *t, uint32_t base, size_t len)
|
int generic_crc32(target *t, uint32_t *crc_res, uint32_t base, size_t len)
|
||||||
{
|
{
|
||||||
uint8_t bytes[128];
|
uint8_t bytes[128];
|
||||||
uint32_t crc;
|
uint32_t crc;
|
||||||
|
|
||||||
CRC_CR |= CRC_CR_RESET;
|
CRC_CR |= CRC_CR_RESET;
|
||||||
|
|
||||||
|
uint32_t last_time = platform_time_ms();
|
||||||
while (len > 3) {
|
while (len > 3) {
|
||||||
|
uint32_t actual_time = platform_time_ms();
|
||||||
|
if ( actual_time > last_time + 1000) {
|
||||||
|
last_time = actual_time;
|
||||||
|
gdb_if_putchar(0, true);
|
||||||
|
}
|
||||||
size_t read_len = MIN(sizeof(bytes), len) & ~3;
|
size_t read_len = MIN(sizeof(bytes), len) & ~3;
|
||||||
target_mem_read(t, bytes, base, read_len);
|
if (target_mem_read(t, bytes, base, read_len)) {
|
||||||
|
DEBUG_WARN("generic_crc32 error around address 0x%08" PRIx32 "\n",
|
||||||
|
base);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < read_len; i += 4)
|
for (unsigned i = 0; i < read_len; i += 4)
|
||||||
CRC_DR = __builtin_bswap32(*(uint32_t*)(bytes+i));
|
CRC_DR = __builtin_bswap32(*(uint32_t*)(bytes+i));
|
||||||
@ -136,7 +168,11 @@ uint32_t generic_crc32(target *t, uint32_t base, size_t len)
|
|||||||
|
|
||||||
crc = CRC_DR;
|
crc = CRC_DR;
|
||||||
|
|
||||||
target_mem_read(t, bytes, base, len);
|
if (target_mem_read(t, bytes, base, len)) {
|
||||||
|
DEBUG_WARN("generic_crc32 error around address 0x%08" PRIx32 "\n",
|
||||||
|
base);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
uint8_t *data = bytes;
|
uint8_t *data = bytes;
|
||||||
while (len--) {
|
while (len--) {
|
||||||
crc ^= *data++ << 24;
|
crc ^= *data++ << 24;
|
||||||
@ -147,7 +183,8 @@ uint32_t generic_crc32(target *t, uint32_t base, size_t len)
|
|||||||
crc <<= 1;
|
crc <<= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return crc;
|
*crc_res = crc;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@ struct exception *innermost_exception;
|
|||||||
void raise_exception(uint32_t type, const char *msg)
|
void raise_exception(uint32_t type, const char *msg)
|
||||||
{
|
{
|
||||||
struct exception *e;
|
struct exception *e;
|
||||||
DEBUG_WARN("Exception: %s\n", msg);
|
|
||||||
for (e = innermost_exception; e; e = e->outer) {
|
for (e = innermost_exception; e; e = e->outer) {
|
||||||
if (e->mask & type) {
|
if (e->mask & type) {
|
||||||
e->type = type;
|
e->type = type;
|
||||||
@ -35,6 +34,7 @@ void raise_exception(uint32_t type, const char *msg)
|
|||||||
longjmp(e->jmpbuf, type);
|
longjmp(e->jmpbuf, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DEBUG_WARN("Unhandled exception: %s\n", msg);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,4 +130,3 @@ int hostio_system(struct target_controller *tc,
|
|||||||
gdb_putpacket_f("Fsystem,%08X/%X", cmd, cmd_len);
|
gdb_putpacket_f("Fsystem,%08X/%X", cmd, cmd_len);
|
||||||
return gdb_main_loop(tc, true);
|
return gdb_main_loop(tc, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
491
src/gdb_main.c
491
src/gdb_main.c
@ -35,6 +35,9 @@
|
|||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "crc32.h"
|
#include "crc32.h"
|
||||||
#include "morse.h"
|
#include "morse.h"
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
#include "rtt.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
enum gdb_signal {
|
enum gdb_signal {
|
||||||
GDB_SIGINT = 2,
|
GDB_SIGINT = 2,
|
||||||
@ -43,25 +46,37 @@ enum gdb_signal {
|
|||||||
GDB_SIGLOST = 29,
|
GDB_SIGLOST = 29,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BUF_SIZE 1024
|
#define BUF_SIZE 1024U
|
||||||
|
|
||||||
#define ERROR_IF_NO_TARGET() \
|
#define ERROR_IF_NO_TARGET() \
|
||||||
if(!cur_target) { gdb_putpacketz("EFF"); break; }
|
if(!cur_target) { gdb_putpacketz("EFF"); break; }
|
||||||
|
|
||||||
static char pbuf[BUF_SIZE+1];
|
typedef struct
|
||||||
|
{
|
||||||
|
const char *cmd_prefix;
|
||||||
|
void (*func)(const char *packet, size_t len);
|
||||||
|
} cmd_executer;
|
||||||
|
|
||||||
|
static char pbuf[BUF_SIZE + 1U];
|
||||||
|
|
||||||
static target *cur_target;
|
static target *cur_target;
|
||||||
static target *last_target;
|
static target *last_target;
|
||||||
|
static bool gdb_needs_detach_notify = false;
|
||||||
|
|
||||||
static void handle_q_packet(char *packet, int len);
|
static void handle_q_packet(char *packet, size_t len);
|
||||||
static void handle_v_packet(char *packet, int len);
|
static void handle_v_packet(char *packet, size_t len);
|
||||||
static void handle_z_packet(char *packet, int len);
|
static void handle_z_packet(char *packet, size_t len);
|
||||||
|
static void handle_kill_target(void);
|
||||||
|
|
||||||
static void gdb_target_destroy_callback(struct target_controller *tc, target *t)
|
static void gdb_target_destroy_callback(struct target_controller *tc, target *t)
|
||||||
{
|
{
|
||||||
(void)tc;
|
(void)tc;
|
||||||
if (cur_target == t)
|
if (cur_target == t) {
|
||||||
|
gdb_put_notificationz("%Stop:W00");
|
||||||
|
gdb_out("You are now detached from the previous target.\n");
|
||||||
cur_target = NULL;
|
cur_target = NULL;
|
||||||
|
gdb_needs_detach_notify = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (last_target == t)
|
if (last_target == t)
|
||||||
last_target = NULL;
|
last_target = NULL;
|
||||||
@ -94,24 +109,22 @@ static struct target_controller gdb_controller = {
|
|||||||
|
|
||||||
int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
||||||
{
|
{
|
||||||
int size;
|
|
||||||
bool single_step = false;
|
bool single_step = false;
|
||||||
|
|
||||||
/* GDB protocol main loop */
|
/* GDB protocol main loop */
|
||||||
while(1) {
|
while (1) {
|
||||||
SET_IDLE_STATE(1);
|
SET_IDLE_STATE(1);
|
||||||
size = gdb_getpacket(pbuf, BUF_SIZE);
|
size_t size = gdb_getpacket(pbuf, BUF_SIZE);
|
||||||
SET_IDLE_STATE(0);
|
SET_IDLE_STATE(0);
|
||||||
switch(pbuf[0]) {
|
switch (pbuf[0]) {
|
||||||
/* Implementation of these is mandatory! */
|
/* Implementation of these is mandatory! */
|
||||||
case 'g': { /* 'g': Read general registers */
|
case 'g': { /* 'g': Read general registers */
|
||||||
ERROR_IF_NO_TARGET();
|
ERROR_IF_NO_TARGET();
|
||||||
uint8_t arm_regs[target_regs_size(cur_target)];
|
uint8_t gp_regs[target_regs_size(cur_target)];
|
||||||
target_regs_read(cur_target, arm_regs);
|
target_regs_read(cur_target, gp_regs);
|
||||||
gdb_putpacket(hexify(pbuf, arm_regs, sizeof(arm_regs)),
|
gdb_putpacket(hexify(pbuf, gp_regs, sizeof(gp_regs)), sizeof(gp_regs) * 2U);
|
||||||
sizeof(arm_regs) * 2);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'm': { /* 'm addr,len': Read len bytes from addr */
|
case 'm': { /* 'm addr,len': Read len bytes from addr */
|
||||||
uint32_t addr, len;
|
uint32_t addr, len;
|
||||||
ERROR_IF_NO_TARGET();
|
ERROR_IF_NO_TARGET();
|
||||||
@ -126,19 +139,20 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
if (target_mem_read(cur_target, mem, addr, len))
|
if (target_mem_read(cur_target, mem, addr, len))
|
||||||
gdb_putpacketz("E01");
|
gdb_putpacketz("E01");
|
||||||
else
|
else
|
||||||
gdb_putpacket(hexify(pbuf, mem, len), len*2);
|
gdb_putpacket(hexify(pbuf, mem, len), len * 2U);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'G': { /* 'G XX': Write general registers */
|
case 'G': { /* 'G XX': Write general registers */
|
||||||
ERROR_IF_NO_TARGET();
|
ERROR_IF_NO_TARGET();
|
||||||
uint8_t arm_regs[target_regs_size(cur_target)];
|
uint8_t gp_regs[target_regs_size(cur_target)];
|
||||||
unhexify(arm_regs, &pbuf[1], sizeof(arm_regs));
|
unhexify(gp_regs, &pbuf[1], sizeof(gp_regs));
|
||||||
target_regs_write(cur_target, arm_regs);
|
target_regs_write(cur_target, gp_regs);
|
||||||
gdb_putpacketz("OK");
|
gdb_putpacketz("OK");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'M': { /* 'M addr,len:XX': Write len bytes to addr */
|
case 'M': { /* 'M addr,len:XX': Write len bytes to addr */
|
||||||
uint32_t addr, len;
|
uint32_t addr = 0;
|
||||||
|
uint32_t len = 0;
|
||||||
int hex;
|
int hex;
|
||||||
ERROR_IF_NO_TARGET();
|
ERROR_IF_NO_TARGET();
|
||||||
sscanf(pbuf, "M%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &hex);
|
sscanf(pbuf, "M%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &hex);
|
||||||
@ -155,12 +169,25 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
else
|
else
|
||||||
gdb_putpacketz("OK");
|
gdb_putpacketz("OK");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* '[m|M|g|G|c][thread-id]' : Set the thread ID for the given subsequent operation
|
||||||
|
* (we don't actually care which as we only care about the TID for whether to send OK or an error)
|
||||||
|
*/
|
||||||
|
case 'H': {
|
||||||
|
char operation = 0;
|
||||||
|
uint32_t thread_id = 0;
|
||||||
|
sscanf(pbuf, "H%c%" SCNx32, &operation, &thread_id);
|
||||||
|
if (thread_id <= 1)
|
||||||
|
gdb_putpacketz("OK");
|
||||||
|
else
|
||||||
|
gdb_putpacketz("E01");
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 's': /* 's [addr]': Single step [start at addr] */
|
case 's': /* 's [addr]': Single step [start at addr] */
|
||||||
single_step = true;
|
single_step = true;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 'c': /* 'c [addr]': Continue [at addr] */
|
case 'c': /* 'c [addr]': Continue [at addr] */
|
||||||
if(!cur_target) {
|
if (!cur_target) {
|
||||||
gdb_putpacketz("X1D");
|
gdb_putpacketz("X1D");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -175,7 +202,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
target_addr watch;
|
target_addr watch;
|
||||||
enum target_halt_reason reason;
|
enum target_halt_reason reason;
|
||||||
|
|
||||||
if(!cur_target) {
|
if (!cur_target) {
|
||||||
/* Report "target exited" if no target */
|
/* Report "target exited" if no target */
|
||||||
gdb_putpacketz("W00");
|
gdb_putpacketz("W00");
|
||||||
break;
|
break;
|
||||||
@ -183,10 +210,13 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
|
|
||||||
/* Wait for target halt */
|
/* Wait for target halt */
|
||||||
while(!(reason = target_halt_poll(cur_target, &watch))) {
|
while(!(reason = target_halt_poll(cur_target, &watch))) {
|
||||||
unsigned char c = gdb_if_getchar_to(0);
|
char c = (char)gdb_if_getchar_to(0);
|
||||||
if((c == '\x03') || (c == '\x04')) {
|
if(c == '\x03' || c == '\x04') {
|
||||||
target_halt_request(cur_target);
|
target_halt_request(cur_target);
|
||||||
}
|
}
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
if (rtt_enabled) poll_rtt(cur_target);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
SET_RUN_STATE(0);
|
SET_RUN_STATE(0);
|
||||||
|
|
||||||
@ -209,7 +239,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
gdb_putpacket_f("T%02X", GDB_SIGTRAP);
|
gdb_putpacket_f("T%02X", GDB_SIGTRAP);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Optional GDB packet support */
|
/* Optional GDB packet support */
|
||||||
case 'p': { /* Read single register */
|
case 'p': { /* Read single register */
|
||||||
@ -218,32 +248,31 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
sscanf(pbuf, "p%" SCNx32, ®);
|
sscanf(pbuf, "p%" SCNx32, ®);
|
||||||
uint8_t val[8];
|
uint8_t val[8];
|
||||||
size_t s = target_reg_read(cur_target, reg, val, sizeof(val));
|
size_t s = target_reg_read(cur_target, reg, val, sizeof(val));
|
||||||
if (s > 0) {
|
if (s > 0)
|
||||||
gdb_putpacket(hexify(pbuf, val, s), s * 2);
|
gdb_putpacket(hexify(pbuf, val, s), s * 2);
|
||||||
} else {
|
else
|
||||||
gdb_putpacketz("EFF");
|
gdb_putpacketz("EFF");
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'P': { /* Write single register */
|
case 'P': { /* Write single register */
|
||||||
ERROR_IF_NO_TARGET();
|
ERROR_IF_NO_TARGET();
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
int n;
|
int n;
|
||||||
sscanf(pbuf, "P%" SCNx32 "=%n", ®, &n);
|
sscanf(pbuf, "P%" SCNx32 "=%n", ®, &n);
|
||||||
uint8_t val[strlen(&pbuf[n])/2];
|
// TODO: FIXME, VLAs considered harmful.
|
||||||
|
uint8_t val[strlen(&pbuf[n]) / 2];
|
||||||
unhexify(val, pbuf + n, sizeof(val));
|
unhexify(val, pbuf + n, sizeof(val));
|
||||||
if (target_reg_write(cur_target, reg, val, sizeof(val)) > 0) {
|
if (target_reg_write(cur_target, reg, val, sizeof(val)) > 0)
|
||||||
gdb_putpacketz("OK");
|
gdb_putpacketz("OK");
|
||||||
} else {
|
else
|
||||||
gdb_putpacketz("EFF");
|
gdb_putpacketz("EFF");
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'F': /* Semihosting call finished */
|
case 'F': /* Semihosting call finished */
|
||||||
if (in_syscall) {
|
if (in_syscall)
|
||||||
return hostio_reply(tc, pbuf, size);
|
return hostio_reply(tc, pbuf, size);
|
||||||
} else {
|
else {
|
||||||
DEBUG_GDB("*** F packet when not in syscall! '%s'\n", pbuf);
|
DEBUG_GDB("*** F packet when not in syscall! '%s'\n", pbuf);
|
||||||
gdb_putpacketz("");
|
gdb_putpacketz("");
|
||||||
}
|
}
|
||||||
@ -269,12 +298,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'k': /* Kill the target */
|
case 'k': /* Kill the target */
|
||||||
if(cur_target) {
|
handle_kill_target();
|
||||||
target_reset(cur_target);
|
|
||||||
target_detach(cur_target);
|
|
||||||
last_target = cur_target;
|
|
||||||
cur_target = NULL;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r': /* Reset the target system */
|
case 'r': /* Reset the target system */
|
||||||
@ -284,6 +308,8 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
else if(last_target) {
|
else if(last_target) {
|
||||||
cur_target = target_attach(last_target,
|
cur_target = target_attach(last_target,
|
||||||
&gdb_controller);
|
&gdb_controller);
|
||||||
|
if(cur_target)
|
||||||
|
morse(NULL, false);
|
||||||
target_reset(cur_target);
|
target_reset(cur_target);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -299,18 +325,18 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
}
|
}
|
||||||
DEBUG_GDB("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n",
|
DEBUG_GDB("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n",
|
||||||
addr, len);
|
addr, len);
|
||||||
if (target_mem_write(cur_target, addr, pbuf+bin, len))
|
if (target_mem_write(cur_target, addr, pbuf + bin, len))
|
||||||
gdb_putpacketz("E01");
|
gdb_putpacketz("E01");
|
||||||
else
|
else
|
||||||
gdb_putpacketz("OK");
|
gdb_putpacketz("OK");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'q': /* General query packet */
|
case 'q': /* General query packet */
|
||||||
handle_q_packet(pbuf, size);
|
handle_q_packet(pbuf, size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'v': /* General query packet */
|
case 'v': /* Verbose command packet */
|
||||||
handle_v_packet(pbuf, size);
|
handle_v_packet(pbuf, size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -328,182 +354,292 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static bool exec_command(char *packet, const size_t length, const cmd_executer *exec)
|
||||||
handle_q_string_reply(const char *str, const char *param)
|
|
||||||
{
|
{
|
||||||
unsigned long addr, len;
|
while (exec->cmd_prefix) {
|
||||||
|
const size_t prefix_length = strlen(exec->cmd_prefix);
|
||||||
|
if (!strncmp(packet, exec->cmd_prefix, prefix_length)) {
|
||||||
|
exec->func(packet + prefix_length, length - prefix_length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
++exec;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (sscanf(param, "%08lx,%08lx", &addr, &len) != 2) {
|
static void exec_q_rcmd(const char *packet, const size_t length)
|
||||||
|
{
|
||||||
|
/* calculate size and allocate buffer for command */
|
||||||
|
const size_t datalen = length / 2U;
|
||||||
|
char *data = alloca(datalen + 1);
|
||||||
|
/* dehexify command */
|
||||||
|
unhexify(data, packet, datalen);
|
||||||
|
data[datalen] = 0; /* add terminating null */
|
||||||
|
|
||||||
|
const int c = command_process(cur_target, data);
|
||||||
|
if (c < 0)
|
||||||
|
gdb_putpacketz("");
|
||||||
|
else if (c == 0)
|
||||||
|
gdb_putpacketz("OK");
|
||||||
|
else
|
||||||
|
gdb_putpacket(hexify(pbuf, "Failed\n", strlen("Failed\n")),
|
||||||
|
2 * strlen("Failed\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_q_string_reply(const char *reply, const char *param)
|
||||||
|
{
|
||||||
|
const size_t reply_length = strlen(reply);
|
||||||
|
uint32_t addr = 0;
|
||||||
|
uint32_t len = 0;
|
||||||
|
|
||||||
|
if (sscanf(param, "%08" PRIx32 ",%08" PRIx32, &addr, &len) != 2) {
|
||||||
gdb_putpacketz("E01");
|
gdb_putpacketz("E01");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (addr < strlen (str)) {
|
if (addr > reply_length) {
|
||||||
char reply[len+2];
|
|
||||||
reply[0] = 'm';
|
|
||||||
strncpy (reply + 1, &str[addr], len);
|
|
||||||
if(len > strlen(&str[addr]))
|
|
||||||
len = strlen(&str[addr]);
|
|
||||||
gdb_putpacket(reply, len + 1);
|
|
||||||
} else if (addr == strlen (str)) {
|
|
||||||
gdb_putpacketz("l");
|
|
||||||
} else
|
|
||||||
gdb_putpacketz("E01");
|
gdb_putpacketz("E01");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (addr == reply_length) {
|
||||||
|
gdb_putpacketz("l");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t output_len = reply_length - addr;
|
||||||
|
if (output_len > len)
|
||||||
|
output_len = len;
|
||||||
|
gdb_putpacket2("m", 1U, reply + addr, output_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void exec_q_supported(const char *packet, const size_t length)
|
||||||
handle_q_packet(char *packet, int len)
|
|
||||||
{
|
{
|
||||||
uint32_t addr, alen;
|
(void)packet;
|
||||||
|
(void)length;
|
||||||
|
gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
if(!strncmp(packet, "qRcmd,", 6)) {
|
static void exec_q_memory_map(const char *packet, const size_t length)
|
||||||
char *data;
|
{
|
||||||
int datalen;
|
(void)packet;
|
||||||
|
(void)length;
|
||||||
|
/* Read target XML memory map */
|
||||||
|
if ((!cur_target) && last_target) {
|
||||||
|
/* Attach to last target if detached. */
|
||||||
|
cur_target = target_attach(last_target,
|
||||||
|
&gdb_controller);
|
||||||
|
}
|
||||||
|
if (!cur_target) {
|
||||||
|
gdb_putpacketz("E01");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char buf[1024];
|
||||||
|
target_mem_map(cur_target, buf, sizeof(buf)); /* Fixme: Check size!*/
|
||||||
|
handle_q_string_reply(buf, packet);
|
||||||
|
}
|
||||||
|
|
||||||
/* calculate size and allocate buffer for command */
|
static void exec_q_feature_read(const char *packet, const size_t length)
|
||||||
datalen = (len - 6) / 2;
|
{
|
||||||
data = alloca(datalen+1);
|
(void)length;
|
||||||
/* dehexify command */
|
/* Read target description */
|
||||||
unhexify(data, packet+6, datalen);
|
if ((!cur_target) && last_target) {
|
||||||
data[datalen] = 0; /* add terminating null */
|
/* Attach to last target if detached. */
|
||||||
|
cur_target = target_attach(last_target, &gdb_controller);
|
||||||
|
}
|
||||||
|
if (!cur_target) {
|
||||||
|
gdb_putpacketz("E01");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handle_q_string_reply(target_tdesc(cur_target), packet);
|
||||||
|
}
|
||||||
|
|
||||||
int c = command_process(cur_target, data);
|
static void exec_q_crc(const char *packet, const size_t length)
|
||||||
if(c < 0)
|
{
|
||||||
gdb_putpacketz("");
|
(void)length;
|
||||||
else if(c == 0)
|
uint32_t addr;
|
||||||
gdb_putpacketz("OK");
|
uint32_t addr_length;
|
||||||
|
if (sscanf(packet, "%" PRIx32 ",%" PRIx32, &addr, &addr_length) == 2) {
|
||||||
|
if (!cur_target) {
|
||||||
|
gdb_putpacketz("E01");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t crc;
|
||||||
|
if (generic_crc32(cur_target, &crc, addr, addr_length))
|
||||||
|
gdb_putpacketz("E03");
|
||||||
else
|
else
|
||||||
gdb_putpacketz("E");
|
gdb_putpacket_f("C%lx", crc);
|
||||||
|
|
||||||
} else if (!strncmp (packet, "qSupported", 10)) {
|
|
||||||
/* Query supported protocol features */
|
|
||||||
gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE);
|
|
||||||
|
|
||||||
} else if (strncmp (packet, "qXfer:memory-map:read::", 23) == 0) {
|
|
||||||
/* Read target XML memory map */
|
|
||||||
if((!cur_target) && last_target) {
|
|
||||||
/* Attach to last target if detached. */
|
|
||||||
cur_target = target_attach(last_target,
|
|
||||||
&gdb_controller);
|
|
||||||
}
|
|
||||||
if (!cur_target) {
|
|
||||||
gdb_putpacketz("E01");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
char buf[1024];
|
|
||||||
target_mem_map(cur_target, buf, sizeof(buf)); /* Fixme: Check size!*/
|
|
||||||
handle_q_string_reply(buf, packet + 23);
|
|
||||||
|
|
||||||
} else if (strncmp (packet, "qXfer:features:read:target.xml:", 31) == 0) {
|
|
||||||
/* Read target description */
|
|
||||||
if((!cur_target) && last_target) {
|
|
||||||
/* Attach to last target if detached. */
|
|
||||||
cur_target = target_attach(last_target,
|
|
||||||
&gdb_controller);
|
|
||||||
}
|
|
||||||
if (!cur_target) {
|
|
||||||
gdb_putpacketz("E01");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
handle_q_string_reply(target_tdesc(cur_target), packet + 31);
|
|
||||||
} else if (sscanf(packet, "qCRC:%" PRIx32 ",%" PRIx32, &addr, &alen) == 2) {
|
|
||||||
if(!cur_target) {
|
|
||||||
gdb_putpacketz("E01");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gdb_putpacket_f("C%lx", generic_crc32(cur_target, addr, alen));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
|
|
||||||
gdb_putpacket("", 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/*
|
||||||
handle_v_packet(char *packet, int plen)
|
* qC queries are for the current thread. We don't support threads but GDB 11 and 12 require this,
|
||||||
|
* so we always answer that the current thread is thread 1.
|
||||||
|
*/
|
||||||
|
static void exec_q_c(const char *packet, const size_t length)
|
||||||
{
|
{
|
||||||
unsigned long addr, len;
|
(void)packet;
|
||||||
|
(void)length;
|
||||||
|
gdb_putpacketz("QC1");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* qfThreadInfo queries are required in GDB 11 and 12 as these GDBs require the server to support
|
||||||
|
* threading even when there's only the possiblity for one thread to exist. In this instance,
|
||||||
|
* we have to tell GDB that there is a single active thread so it doesn't think the "thread" died.
|
||||||
|
* qsThreadInfo will always follow qfThreadInfo when we reply as we have to specify 'l' at the
|
||||||
|
* end to terminate the list.. GDB doesn't like this not happening.
|
||||||
|
*/
|
||||||
|
static void exec_q_thread_info(const char *packet, const size_t length)
|
||||||
|
{
|
||||||
|
(void)length;
|
||||||
|
if (packet[-11] == 'f')
|
||||||
|
gdb_putpacketz("m1");
|
||||||
|
else
|
||||||
|
gdb_putpacketz("l");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const cmd_executer q_commands[]=
|
||||||
|
{
|
||||||
|
{"qRcmd,", exec_q_rcmd},
|
||||||
|
{"qSupported", exec_q_supported},
|
||||||
|
{"qXfer:memory-map:read::", exec_q_memory_map},
|
||||||
|
{"qXfer:features:read:target.xml:",exec_q_feature_read},
|
||||||
|
{"qCRC:", exec_q_crc},
|
||||||
|
{"qC", exec_q_c},
|
||||||
|
{"qfThreadInfo", exec_q_thread_info},
|
||||||
|
{"qsThreadInfo", exec_q_thread_info},
|
||||||
|
{NULL, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void handle_kill_target(void)
|
||||||
|
{
|
||||||
|
if (cur_target) {
|
||||||
|
target_reset(cur_target);
|
||||||
|
target_detach(cur_target);
|
||||||
|
last_target = cur_target;
|
||||||
|
cur_target = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_q_packet(char *packet, const size_t length)
|
||||||
|
{
|
||||||
|
if (exec_command(packet, length, q_commands))
|
||||||
|
return;
|
||||||
|
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
|
||||||
|
gdb_putpacket("", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_v_packet(char *packet, const size_t plen)
|
||||||
|
{
|
||||||
|
uint32_t addr = 0;
|
||||||
|
uint32_t len = 0;
|
||||||
int bin;
|
int bin;
|
||||||
static uint8_t flash_mode = 0;
|
static uint8_t flash_mode = 0;
|
||||||
|
|
||||||
if (sscanf(packet, "vAttach;%08lx", &addr) == 1) {
|
if (sscanf(packet, "vAttach;%08" PRIx32, &addr) == 1) {
|
||||||
/* Attach to remote target processor */
|
/* Attach to remote target processor */
|
||||||
cur_target = target_attach_n(addr, &gdb_controller);
|
cur_target = target_attach_n(addr, &gdb_controller);
|
||||||
if(cur_target)
|
if(cur_target) {
|
||||||
gdb_putpacketz("T05");
|
morse(NULL, false);
|
||||||
else
|
/*
|
||||||
|
* We don't actually support threads, but GDB 11 and 12 can't work without
|
||||||
|
* us saying we attached to thread 1.. see the following for the low-down of this:
|
||||||
|
* https://sourceware.org/bugzilla/show_bug.cgi?id=28405
|
||||||
|
* https://sourceware.org/bugzilla/show_bug.cgi?id=28874
|
||||||
|
* https://sourceware.org/pipermail/gdb-patches/2021-December/184171.html
|
||||||
|
* https://sourceware.org/pipermail/gdb-patches/2022-April/188058.html
|
||||||
|
* https://sourceware.org/pipermail/gdb-patches/2022-July/190869.html
|
||||||
|
*/
|
||||||
|
gdb_putpacketz("T05thread:1;");
|
||||||
|
} else
|
||||||
gdb_putpacketz("E01");
|
gdb_putpacketz("E01");
|
||||||
|
|
||||||
|
} else if (!strncmp(packet, "vKill;", 6)) {
|
||||||
|
/* Kill the target - we don't actually care about the PID that follows "vKill;" */
|
||||||
|
handle_kill_target();
|
||||||
|
gdb_putpacketz("OK");
|
||||||
|
|
||||||
} else if (!strncmp(packet, "vRun", 4)) {
|
} else if (!strncmp(packet, "vRun", 4)) {
|
||||||
/* Parse command line for get_cmdline semihosting call */
|
/* Parse command line for get_cmdline semihosting call */
|
||||||
char cmdline[83];
|
char cmdline[83];
|
||||||
char *pbuf = cmdline;
|
char *pcmdline = cmdline;
|
||||||
char *tok = packet + 4;
|
char *tok = packet + 4;
|
||||||
if (*tok == ';') tok++;
|
if (*tok == ';')
|
||||||
*cmdline='\0';
|
++tok;
|
||||||
|
cmdline[0] = '\0';
|
||||||
while(*tok != '\0') {
|
while(*tok != '\0') {
|
||||||
if(strlen(cmdline)+3 >= sizeof(cmdline)) break;
|
if (strlen(cmdline) + 3 >= sizeof(cmdline))
|
||||||
|
break;
|
||||||
if (*tok == ';') {
|
if (*tok == ';') {
|
||||||
*pbuf++=' ';
|
*pcmdline++ = ' ';
|
||||||
*pbuf='\0';
|
pcmdline[0] = '\0';
|
||||||
tok++;
|
tok++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isxdigit(*tok) && isxdigit(*(tok+1))) {
|
if (isxdigit(tok[0]) && isxdigit(tok[1])) {
|
||||||
unhexify(pbuf, tok, 2);
|
unhexify(pcmdline, tok, 2);
|
||||||
if ((*pbuf == ' ') || (*pbuf == '\\')) {
|
if ((*pcmdline == ' ') || (*pcmdline == '\\')) {
|
||||||
*(pbuf+1)=*pbuf;
|
pcmdline[1] = *pcmdline;
|
||||||
*pbuf++='\\';
|
*pcmdline++ = '\\';
|
||||||
}
|
}
|
||||||
pbuf++;
|
pcmdline++;
|
||||||
tok+=2;
|
tok += 2;
|
||||||
*pbuf='\0';
|
pcmdline[0] = '\0';
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
/* force searching rtt control block */
|
||||||
|
rtt_found = false;
|
||||||
|
#endif
|
||||||
/* Run target program. For us (embedded) this means reset. */
|
/* Run target program. For us (embedded) this means reset. */
|
||||||
if(cur_target) {
|
if (cur_target) {
|
||||||
target_set_cmdline(cur_target, cmdline);
|
target_set_cmdline(cur_target, cmdline);
|
||||||
target_reset(cur_target);
|
target_reset(cur_target);
|
||||||
gdb_putpacketz("T05");
|
gdb_putpacketz("T05");
|
||||||
} else if(last_target) {
|
} else if (last_target) {
|
||||||
cur_target = target_attach(last_target,
|
cur_target = target_attach(last_target,
|
||||||
&gdb_controller);
|
&gdb_controller);
|
||||||
|
|
||||||
/* If we were able to attach to the target again */
|
/* If we were able to attach to the target again */
|
||||||
if (cur_target) {
|
if (cur_target) {
|
||||||
target_set_cmdline(cur_target, cmdline);
|
target_set_cmdline(cur_target, cmdline);
|
||||||
target_reset(cur_target);
|
target_reset(cur_target);
|
||||||
gdb_putpacketz("T05");
|
morse(NULL, false);
|
||||||
} else gdb_putpacketz("E01");
|
gdb_putpacketz("T05");
|
||||||
|
} else
|
||||||
|
gdb_putpacketz("E01");
|
||||||
|
|
||||||
} else gdb_putpacketz("E01");
|
} else
|
||||||
|
gdb_putpacketz("E01");
|
||||||
|
|
||||||
} else if (sscanf(packet, "vFlashErase:%08lx,%08lx", &addr, &len) == 2) {
|
} else if (sscanf(packet, "vFlashErase:%08" PRIx32 ",%08" PRIx32, &addr, &len) == 2) {
|
||||||
/* Erase Flash Memory */
|
/* Erase Flash Memory */
|
||||||
DEBUG_GDB("Flash Erase %08lX %08lX\n", addr, len);
|
DEBUG_GDB("Flash Erase %08" PRIX32 " %08" PRIX32 "\n", addr, len);
|
||||||
if(!cur_target) { gdb_putpacketz("EFF"); return; }
|
if (!cur_target) {
|
||||||
|
gdb_putpacketz("EFF");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(!flash_mode) {
|
if (!flash_mode) {
|
||||||
/* Reset target if first flash command! */
|
/* Reset target if first flash command! */
|
||||||
/* This saves us if we're interrupted in IRQ context */
|
/* This saves us if we're interrupted in IRQ context */
|
||||||
target_reset(cur_target);
|
target_reset(cur_target);
|
||||||
flash_mode = 1;
|
flash_mode = 1;
|
||||||
}
|
}
|
||||||
if(target_flash_erase(cur_target, addr, len) == 0) {
|
if (target_flash_erase(cur_target, addr, len) == 0)
|
||||||
gdb_putpacketz("OK");
|
gdb_putpacketz("OK");
|
||||||
} else {
|
else {
|
||||||
flash_mode = 0;
|
flash_mode = 0;
|
||||||
gdb_putpacketz("EFF");
|
gdb_putpacketz("EFF");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (sscanf(packet, "vFlashWrite:%08lx:%n", &addr, &bin) == 1) {
|
} else if (sscanf(packet, "vFlashWrite:%08" PRIx32 ":%n", &addr, &bin) == 1) {
|
||||||
/* Write Flash Memory */
|
/* Write Flash Memory */
|
||||||
len = plen - bin;
|
const uint32_t count = plen - bin;
|
||||||
DEBUG_GDB("Flash Write %08lX %08lX\n", addr, len);
|
DEBUG_GDB("Flash Write %08" PRIX32 " %08" PRIX32 "\n", addr, count);
|
||||||
if(cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0) {
|
if (cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, count) == 0)
|
||||||
gdb_putpacketz("OK");
|
gdb_putpacketz("OK");
|
||||||
} else {
|
else {
|
||||||
flash_mode = 0;
|
flash_mode = 0;
|
||||||
gdb_putpacketz("EFF");
|
gdb_putpacketz("EFF");
|
||||||
}
|
}
|
||||||
@ -513,39 +649,40 @@ handle_v_packet(char *packet, int plen)
|
|||||||
gdb_putpacketz(target_flash_done(cur_target) ? "EFF" : "OK");
|
gdb_putpacketz(target_flash_done(cur_target) ? "EFF" : "OK");
|
||||||
flash_mode = 0;
|
flash_mode = 0;
|
||||||
|
|
||||||
|
} else if (!strcmp(packet, "vStopped")) {
|
||||||
|
if (gdb_needs_detach_notify) {
|
||||||
|
gdb_putpacketz("W00");
|
||||||
|
gdb_needs_detach_notify = false;
|
||||||
|
} else
|
||||||
|
gdb_putpacketz("OK");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
|
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
|
||||||
gdb_putpacket("", 0);
|
gdb_putpacket("", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void handle_z_packet(char *packet, const size_t plen)
|
||||||
handle_z_packet(char *packet, int plen)
|
|
||||||
{
|
{
|
||||||
(void)plen;
|
(void)plen;
|
||||||
|
|
||||||
uint8_t set = (packet[0] == 'Z') ? 1 : 0;
|
uint32_t type;
|
||||||
int type, len;
|
uint32_t len;
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
int ret;
|
sscanf(packet, "%*[zZ]%" PRIu32 ",%08" PRIx32 ",%" PRIu32, &type, &addr, &len);
|
||||||
|
|
||||||
/* I have no idea why this doesn't work. Seems to work
|
int ret = 0;
|
||||||
* with real sscanf() though... */
|
if (packet[0] == 'Z')
|
||||||
//sscanf(packet, "%*[zZ]%hhd,%08lX,%hhd", &type, &addr, &len);
|
|
||||||
type = packet[1] - '0';
|
|
||||||
sscanf(packet + 2, ",%" PRIx32 ",%d", &addr, &len);
|
|
||||||
if(set)
|
|
||||||
ret = target_breakwatch_set(cur_target, type, addr, len);
|
ret = target_breakwatch_set(cur_target, type, addr, len);
|
||||||
else
|
else
|
||||||
ret = target_breakwatch_clear(cur_target, type, addr, len);
|
ret = target_breakwatch_clear(cur_target, type, addr, len);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0)
|
||||||
gdb_putpacketz("E01");
|
gdb_putpacketz("E01");
|
||||||
} else if (ret > 0) {
|
else if (ret > 0)
|
||||||
gdb_putpacketz("");
|
gdb_putpacketz("");
|
||||||
} else {
|
else
|
||||||
gdb_putpacketz("OK");
|
gdb_putpacketz("OK");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdb_main(void)
|
void gdb_main(void)
|
||||||
|
187
src/gdb_packet.c
187
src/gdb_packet.c
@ -30,143 +30,196 @@
|
|||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
int gdb_getpacket(char *packet, int size)
|
size_t gdb_getpacket(char *packet, size_t size)
|
||||||
{
|
{
|
||||||
unsigned char c;
|
|
||||||
unsigned char csum;
|
unsigned char csum;
|
||||||
char recv_csum[3];
|
char recv_csum[3];
|
||||||
int i;
|
size_t offset = 0;
|
||||||
|
|
||||||
while(1) {
|
while (1) {
|
||||||
/* Wait for packet start */
|
/* Wait for packet start */
|
||||||
do {
|
do {
|
||||||
/* Spin waiting for a start of packet character - either a gdb
|
/* Spin waiting for a start of packet character - either a gdb
|
||||||
* start ('$') or a BMP remote packet start ('!').
|
* start ('$') or a BMP remote packet start ('!').
|
||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
packet[0] = gdb_if_getchar();
|
/* Smells like bad code */
|
||||||
if (packet[0]==0x04) return 1;
|
packet[0] = (char)gdb_if_getchar();
|
||||||
|
if (packet[0] == 0x04)
|
||||||
|
return 1;
|
||||||
} while ((packet[0] != '$') && (packet[0] != REMOTE_SOM));
|
} while ((packet[0] != '$') && (packet[0] != REMOTE_SOM));
|
||||||
#if PC_HOSTED == 0
|
#if PC_HOSTED == 0
|
||||||
if (packet[0]==REMOTE_SOM) {
|
if (packet[0] == REMOTE_SOM) {
|
||||||
/* This is probably a remote control packet
|
/* This is probably a remote control packet
|
||||||
* - get and handle it */
|
* - get and handle it */
|
||||||
i=0;
|
offset = 0;
|
||||||
bool gettingRemotePacket=true;
|
bool gettingRemotePacket = true;
|
||||||
while (gettingRemotePacket) {
|
while (gettingRemotePacket) {
|
||||||
c=gdb_if_getchar();
|
/* Smells like bad code */
|
||||||
|
const char c = (char)gdb_if_getchar();
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case REMOTE_SOM: /* Oh dear, packet restarts */
|
case REMOTE_SOM: /* Oh dear, packet restarts */
|
||||||
i=0;
|
offset = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case REMOTE_EOM: /* Complete packet for processing */
|
case REMOTE_EOM: /* Complete packet for processing */
|
||||||
packet[i]=0;
|
packet[offset] = 0;
|
||||||
remotePacketProcess(i,packet);
|
remotePacketProcess(offset, packet);
|
||||||
gettingRemotePacket=false;
|
gettingRemotePacket = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '$': /* A 'real' gdb packet, best stop squatting now */
|
case '$': /* A 'real' gdb packet, best stop squatting now */
|
||||||
packet[0]='$';
|
packet[0] = '$';
|
||||||
gettingRemotePacket=false;
|
gettingRemotePacket = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (i<size) {
|
if (offset < size) {
|
||||||
packet[i++]=c;
|
packet[offset++] = c;
|
||||||
} else {
|
} else {
|
||||||
/* Who knows what is going on...return to normality */
|
/* Who knows what is going on...return to normality */
|
||||||
gettingRemotePacket=false;
|
gettingRemotePacket = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Reset the packet buffer start character to zero, because function
|
||||||
|
* 'remotePacketProcess()' above overwrites this buffer, and
|
||||||
|
* an arbitrary character may have been placed there. If this is a '$'
|
||||||
|
* character, this will cause this loop to be terminated, which is wrong.
|
||||||
|
*/
|
||||||
|
packet[0] = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} while (packet[0] != '$');
|
} while (packet[0] != '$');
|
||||||
|
|
||||||
i = 0; csum = 0;
|
offset = 0;
|
||||||
|
csum = 0;
|
||||||
|
char c;
|
||||||
/* Capture packet data into buffer */
|
/* Capture packet data into buffer */
|
||||||
while((c = gdb_if_getchar()) != '#') {
|
while ((c = (char)gdb_if_getchar()) != '#') {
|
||||||
|
|
||||||
if(i == size) break; /* Oh shit */
|
/* If we run out of buffer space, exit early */
|
||||||
|
if (offset == size)
|
||||||
|
break;
|
||||||
|
|
||||||
if(c == '$') { /* Restart capture */
|
if (c == '$') { /* Restart capture */
|
||||||
i = 0;
|
offset = 0;
|
||||||
csum = 0;
|
csum = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(c == '}') { /* escaped char */
|
if (c == '}') { /* escaped char */
|
||||||
c = gdb_if_getchar();
|
c = gdb_if_getchar();
|
||||||
csum += c + '}';
|
csum += c + '}';
|
||||||
packet[i++] = c ^ 0x20;
|
packet[offset++] = c ^ 0x20;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
csum += c;
|
csum += c;
|
||||||
packet[i++] = c;
|
packet[offset++] = c;
|
||||||
}
|
}
|
||||||
recv_csum[0] = gdb_if_getchar();
|
recv_csum[0] = (char)gdb_if_getchar();
|
||||||
recv_csum[1] = gdb_if_getchar();
|
recv_csum[1] = (char)gdb_if_getchar();
|
||||||
recv_csum[2] = 0;
|
recv_csum[2] = 0;
|
||||||
|
|
||||||
/* return packet if checksum matches */
|
/* return packet if checksum matches */
|
||||||
if(csum == strtol(recv_csum, NULL, 16)) break;
|
if (csum == strtol(recv_csum, NULL, 16))
|
||||||
|
break;
|
||||||
|
|
||||||
/* get here if checksum fails */
|
/* get here if checksum fails */
|
||||||
gdb_if_putchar('-', 1); /* send nack */
|
gdb_if_putchar('-', 1); /* send nack */
|
||||||
}
|
}
|
||||||
gdb_if_putchar('+', 1); /* send ack */
|
gdb_if_putchar('+', 1); /* send ack */
|
||||||
packet[i] = 0;
|
packet[offset] = 0;
|
||||||
|
|
||||||
#if PC_HOSTED == 1
|
#if PC_HOSTED == 1
|
||||||
DEBUG_GDB_WIRE("%s : ", __func__);
|
DEBUG_GDB_WIRE("%s : ", __func__);
|
||||||
for(int j = 0; j < i; j++) {
|
for (size_t j = 0; j < offset; j++) {
|
||||||
c = packet[j];
|
const char c = packet[j];
|
||||||
if ((c >= 32) && (c < 127))
|
if (c >= ' ' && c < 0x7F)
|
||||||
DEBUG_GDB_WIRE("%c", c);
|
DEBUG_GDB_WIRE("%c", c);
|
||||||
else
|
else
|
||||||
DEBUG_GDB_WIRE("\\x%02X", c);
|
DEBUG_GDB_WIRE("\\x%02X", c);
|
||||||
}
|
}
|
||||||
DEBUG_GDB_WIRE("\n");
|
DEBUG_GDB_WIRE("\n");
|
||||||
#endif
|
#endif
|
||||||
return i;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdb_putpacket(const char *packet, int size)
|
static void gdb_next_char(char c, unsigned char *csum)
|
||||||
|
{
|
||||||
|
#if PC_HOSTED == 1
|
||||||
|
if ((c >= 32) && (c < 127))
|
||||||
|
DEBUG_GDB_WIRE("%c", c);
|
||||||
|
else
|
||||||
|
DEBUG_GDB_WIRE("\\x%02X", c);
|
||||||
|
#endif
|
||||||
|
if ((c == '$') || (c == '#') || (c == '}') || (c == '*')) {
|
||||||
|
gdb_if_putchar('}', 0);
|
||||||
|
gdb_if_putchar(c ^ 0x20, 0);
|
||||||
|
*csum += '}' + (c ^ 0x20);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gdb_if_putchar(c, 0);
|
||||||
|
*csum += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_putpacket2(const char *packet1, size_t size1, const char *packet2, size_t size2)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
unsigned char csum;
|
|
||||||
unsigned char c;
|
|
||||||
char xmit_csum[3];
|
char xmit_csum[3];
|
||||||
int tries = 0;
|
size_t tries = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
DEBUG_GDB_WIRE("%s : ", __func__);
|
DEBUG_GDB_WIRE("%s: ", __func__);
|
||||||
csum = 0;
|
unsigned char csum = 0;
|
||||||
gdb_if_putchar('$', 0);
|
gdb_if_putchar('$', 0);
|
||||||
for(i = 0; i < size; i++) {
|
|
||||||
c = packet[i];
|
for (size_t i = 0; i < size1; ++i)
|
||||||
#if PC_HOSTED == 1
|
gdb_next_char(packet1[i], &csum);
|
||||||
if ((c >= 32) && (c < 127))
|
for (size_t i = 0; i < size2; ++i)
|
||||||
DEBUG_GDB_WIRE("%c", c);
|
gdb_next_char(packet2[i], &csum);
|
||||||
else
|
|
||||||
DEBUG_GDB_WIRE("\\x%02X", c);
|
|
||||||
#endif
|
|
||||||
if((c == '$') || (c == '#') || (c == '}')) {
|
|
||||||
gdb_if_putchar('}', 0);
|
|
||||||
gdb_if_putchar(c ^ 0x20, 0);
|
|
||||||
csum += '}' + (c ^ 0x20);
|
|
||||||
} else {
|
|
||||||
gdb_if_putchar(c, 0);
|
|
||||||
csum += c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gdb_if_putchar('#', 0);
|
gdb_if_putchar('#', 0);
|
||||||
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
|
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
|
||||||
gdb_if_putchar(xmit_csum[0], 0);
|
gdb_if_putchar(xmit_csum[0], 0);
|
||||||
gdb_if_putchar(xmit_csum[1], 1);
|
gdb_if_putchar(xmit_csum[1], 1);
|
||||||
DEBUG_GDB_WIRE("\n");
|
DEBUG_GDB_WIRE("\n");
|
||||||
} while((gdb_if_getchar_to(2000) != '+') && (tries++ < 3));
|
} while (gdb_if_getchar_to(2000) != '+' && tries++ < 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_putpacket(const char *packet, size_t size)
|
||||||
|
{
|
||||||
|
char xmit_csum[3];
|
||||||
|
size_t tries = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
DEBUG_GDB_WIRE("%s: ", __func__);
|
||||||
|
unsigned char csum = 0;
|
||||||
|
gdb_if_putchar('$', 0);
|
||||||
|
for (size_t i = 0; i < size; ++i)
|
||||||
|
gdb_next_char(packet[i], &csum);
|
||||||
|
gdb_if_putchar('#', 0);
|
||||||
|
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
|
||||||
|
gdb_if_putchar(xmit_csum[0], 0);
|
||||||
|
gdb_if_putchar(xmit_csum[1], 1);
|
||||||
|
DEBUG_GDB_WIRE("\n");
|
||||||
|
} while (gdb_if_getchar_to(2000) != '+' && tries++ < 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_put_notification(const char *const packet, const size_t size)
|
||||||
|
{
|
||||||
|
char xmit_csum[3];
|
||||||
|
|
||||||
|
DEBUG_GDB_WIRE("%s: ", __func__);
|
||||||
|
uint8_t csum = 0;
|
||||||
|
gdb_if_putchar('%', 0);
|
||||||
|
for (size_t i = 0; i < size; ++i)
|
||||||
|
gdb_next_char(packet[i], &csum);
|
||||||
|
gdb_if_putchar('#', 0);
|
||||||
|
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
|
||||||
|
gdb_if_putchar(xmit_csum[0], 0);
|
||||||
|
gdb_if_putchar(xmit_csum[1], 1);
|
||||||
|
DEBUG_GDB_WIRE("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdb_putpacket_f(const char *fmt, ...)
|
void gdb_putpacket_f(const char *fmt, ...)
|
||||||
@ -184,13 +237,13 @@ void gdb_putpacket_f(const char *fmt, ...)
|
|||||||
|
|
||||||
void gdb_out(const char *buf)
|
void gdb_out(const char *buf)
|
||||||
{
|
{
|
||||||
char *hexdata;
|
int l = strlen(buf);
|
||||||
int i;
|
char *hexdata = calloc(1, 2 * l + 1);
|
||||||
|
if (!hexdata)
|
||||||
hexdata = alloca((i = strlen(buf)*2 + 1) + 1);
|
return;
|
||||||
hexdata[0] = 'O';
|
hexify(hexdata, buf, l);
|
||||||
hexify(hexdata+1, buf, strlen(buf));
|
gdb_putpacket2("O", 1, hexdata, 2 * l);
|
||||||
gdb_putpacket(hexdata, i);
|
free(hexdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdb_voutf(const char *fmt, va_list ap)
|
void gdb_voutf(const char *fmt, va_list ap)
|
||||||
|
@ -26,16 +26,16 @@
|
|||||||
|
|
||||||
static const char hexdigits[] = "0123456789abcdef";
|
static const char hexdigits[] = "0123456789abcdef";
|
||||||
|
|
||||||
char * hexify(char *hex, const void *buf, size_t size)
|
char *hexify(char *hex, const void *buf, const size_t size)
|
||||||
{
|
{
|
||||||
char *tmp = hex;
|
char *dst = hex;
|
||||||
const uint8_t *b = buf;
|
const uint8_t *const src = buf;
|
||||||
|
|
||||||
while (size--) {
|
for (size_t idx = 0; idx < size; ++idx) {
|
||||||
*tmp++ = hexdigits[*b >> 4];
|
*dst++ = hexdigits[src[idx] >> 4];
|
||||||
*tmp++ = hexdigits[*b++ & 0xF];
|
*dst++ = hexdigits[src[idx] & 0xF];
|
||||||
}
|
}
|
||||||
*tmp++ = 0;
|
*dst++ = 0;
|
||||||
|
|
||||||
return hex;
|
return hex;
|
||||||
}
|
}
|
||||||
@ -43,20 +43,18 @@ char * hexify(char *hex, const void *buf, size_t size)
|
|||||||
static uint8_t unhex_digit(char hex)
|
static uint8_t unhex_digit(char hex)
|
||||||
{
|
{
|
||||||
uint8_t tmp = hex - '0';
|
uint8_t tmp = hex - '0';
|
||||||
if(tmp > 9)
|
if (tmp > 9)
|
||||||
tmp -= 'A' - '0' - 10;
|
tmp -= 'A' - '0' - 10;
|
||||||
if(tmp > 16)
|
if (tmp > 16)
|
||||||
tmp -= 'a' - 'A';
|
tmp -= 'a' - 'A';
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * unhexify(void *buf, const char *hex, size_t size)
|
char *unhexify(void *buf, const char *hex, const size_t size)
|
||||||
{
|
{
|
||||||
uint8_t *b = buf;
|
uint8_t *const dst = buf;
|
||||||
while (size--) {
|
for (size_t idx = 0; idx < size; ++idx, hex += 2) {
|
||||||
*b = unhex_digit(*hex++) << 4;
|
dst[idx] = (unhex_digit(hex[0]) << 4) | unhex_digit(hex[1]);
|
||||||
*b++ |= unhex_digit(*hex++);
|
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,6 @@
|
|||||||
#ifndef __CRC32_H
|
#ifndef __CRC32_H
|
||||||
#define __CRC32_H
|
#define __CRC32_H
|
||||||
|
|
||||||
uint32_t generic_crc32(target *t, uint32_t base, int len);
|
int generic_crc32(target *t, uint32_t *crc, uint32_t base, int len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -29,6 +29,8 @@ void gdb_usb_out_cb(usbd_device *dev, uint8_t ep);
|
|||||||
int gdb_if_init(void);
|
int gdb_if_init(void);
|
||||||
unsigned char gdb_if_getchar(void);
|
unsigned char gdb_if_getchar(void);
|
||||||
unsigned char gdb_if_getchar_to(int timeout);
|
unsigned char gdb_if_getchar_to(int timeout);
|
||||||
|
|
||||||
|
/* sending gdb_if_putchar(0, true) seems to work as keep alive */
|
||||||
void gdb_if_putchar(unsigned char c, int flush);
|
void gdb_if_putchar(unsigned char c, int flush);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,17 +21,19 @@
|
|||||||
#ifndef __GDB_PACKET_H
|
#ifndef __GDB_PACKET_H
|
||||||
#define __GDB_PACKET_H
|
#define __GDB_PACKET_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
int gdb_getpacket(char *packet, int size);
|
size_t gdb_getpacket(char *packet, size_t size);
|
||||||
void gdb_putpacket(const char *packet, int size);
|
void gdb_putpacket(const char *packet, size_t size);
|
||||||
|
void gdb_putpacket2(const char *packet1, size_t size1, const char *packet2, size_t size2);
|
||||||
#define gdb_putpacketz(packet) gdb_putpacket((packet), strlen(packet))
|
#define gdb_putpacketz(packet) gdb_putpacket((packet), strlen(packet))
|
||||||
void gdb_putpacket_f(const char *packet, ...);
|
void gdb_putpacket_f(const char *packet, ...);
|
||||||
|
void gdb_put_notification(const char *packet, size_t size);
|
||||||
|
#define gdb_put_notificationz(packet) gdb_put_notification((packet), strlen(packet))
|
||||||
|
|
||||||
void gdb_out(const char *buf);
|
void gdb_out(const char *buf);
|
||||||
void gdb_voutf(const char *fmt, va_list);
|
void gdb_voutf(const char *fmt, va_list);
|
||||||
void gdb_outf(const char *fmt, ...);
|
void gdb_outf(const char *fmt, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,7 +21,9 @@
|
|||||||
#ifndef __GENERAL_H
|
#ifndef __GENERAL_H
|
||||||
#define __GENERAL_H
|
#define __GENERAL_H
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
#if !defined(_GNU_SOURCE)
|
||||||
|
# define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
#if !defined(__USE_MINGW_ANSI_STDIO)
|
#if !defined(__USE_MINGW_ANSI_STDIO)
|
||||||
# define __USE_MINGW_ANSI_STDIO 1
|
# define __USE_MINGW_ANSI_STDIO 1
|
||||||
#endif
|
#endif
|
||||||
@ -37,6 +39,8 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "platform_support.h"
|
#include "platform_support.h"
|
||||||
|
|
||||||
|
extern uint32_t delay_cnt;
|
||||||
|
|
||||||
enum BMP_DEBUG {
|
enum BMP_DEBUG {
|
||||||
BMP_DEBUG_NONE = 0,
|
BMP_DEBUG_NONE = 0,
|
||||||
BMP_DEBUG_INFO = 1,
|
BMP_DEBUG_INFO = 1,
|
||||||
@ -48,23 +52,28 @@ enum BMP_DEBUG {
|
|||||||
BMP_DEBUG_STDOUT = 0x8000,
|
BMP_DEBUG_STDOUT = 0x8000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define FREQ_FIXED 0xffffffff
|
||||||
|
|
||||||
#if PC_HOSTED == 0
|
#if PC_HOSTED == 0
|
||||||
/* For BMP debug output on a firmware BMP platform, using
|
/* For BMP debug output on a firmware BMP platform, using
|
||||||
* BMP PC-Hosted is the preferred way. Printing DEBUG_WARN
|
* BMP PC-Hosted is the preferred way. Printing DEBUG_WARN
|
||||||
* and DEBUG_INFO is kept for comptibiluty.
|
* and DEBUG_INFO is kept for comptibiluty.
|
||||||
*/
|
*/
|
||||||
# if defined(ENABLE_DEBUG)
|
# if !defined(PLATFORM_PRINTF)
|
||||||
# define DEBUG_WARN printf
|
# define PLATFORM_PRINTF printf
|
||||||
# define DEBUG_INFO printf
|
|
||||||
# else
|
|
||||||
# define DEBUG_WARN(...)
|
|
||||||
# define DEBUG_INFO(...)
|
|
||||||
# endif
|
# endif
|
||||||
# define DEBUG_GDB(...)
|
# if defined(ENABLE_DEBUG)
|
||||||
# define DEBUG_TARGET(...)
|
# define DEBUG_WARN PLATFORM_PRINTF
|
||||||
# define DEBUG_PROBE(...)
|
# define DEBUG_INFO PLATFORM_PRINTF
|
||||||
# define DEBUG_WIRE(...)
|
# else
|
||||||
# define DEBUG_GDB_WIRE(...)
|
# define DEBUG_WARN(...) do {} while(0)
|
||||||
|
# define DEBUG_INFO(...) do {} while(0)
|
||||||
|
# endif
|
||||||
|
# define DEBUG_GDB(...) do {} while(0)
|
||||||
|
# define DEBUG_TARGET(...) do {} while(0)
|
||||||
|
# define DEBUG_PROBE(...) do {} while(0)
|
||||||
|
# define DEBUG_WIRE(...) do {} while(0)
|
||||||
|
# define DEBUG_GDB_WIRE(...) do {} while(0)
|
||||||
#else
|
#else
|
||||||
# include <stdarg.h>
|
# include <stdarg.h>
|
||||||
extern int cl_debuglevel;
|
extern int cl_debuglevel;
|
||||||
@ -155,5 +164,11 @@ static inline void DEBUG_WIRE(const char *format, ...)
|
|||||||
#undef MAX
|
#undef MAX
|
||||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||||
|
|
||||||
|
#if !defined(SYSTICKHZ)
|
||||||
|
# define SYSTICKHZ 100
|
||||||
|
#endif
|
||||||
|
#define SYSTICKMS (1000 / SYSTICKHZ)
|
||||||
|
#define MORSECNT ((SYSTICKHZ / 10) - 1)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -37,7 +37,9 @@ void platform_timeout_set(platform_timeout *t, uint32_t ms);
|
|||||||
bool platform_timeout_is_expired(platform_timeout *t);
|
bool platform_timeout_is_expired(platform_timeout *t);
|
||||||
void platform_delay(uint32_t ms);
|
void platform_delay(uint32_t ms);
|
||||||
|
|
||||||
|
#define POWER_CONFLICT_THRESHOLD 5 /* in 0.1V, so 5 stands for 0.5V */
|
||||||
extern bool connect_assert_srst;
|
extern bool connect_assert_srst;
|
||||||
|
uint32_t platform_target_voltage_sense(void);
|
||||||
const char *platform_target_voltage(void);
|
const char *platform_target_voltage(void);
|
||||||
int platform_hwversion(void);
|
int platform_hwversion(void);
|
||||||
void platform_srst_set_val(bool assert);
|
void platform_srst_set_val(bool assert);
|
||||||
@ -45,6 +47,8 @@ bool platform_srst_get_val(void);
|
|||||||
bool platform_target_get_power(void);
|
bool platform_target_get_power(void);
|
||||||
void platform_target_set_power(bool power);
|
void platform_target_set_power(bool power);
|
||||||
void platform_request_boot(void);
|
void platform_request_boot(void);
|
||||||
|
void platform_max_frequency_set(uint32_t frequency);
|
||||||
|
uint32_t platform_max_frequency_get(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
85
src/include/queue.h
Normal file
85
src/include/queue.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Robert C. Curtis. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ROBERT C. CURTIS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ROBERT C. CURTIS OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGE.
|
||||||
|
*
|
||||||
|
* The views and conclusions contained in the software and documentation
|
||||||
|
* are those of the authors and should not be interpreted as representing
|
||||||
|
* official policies, either expressed or implied, of Robert C. Curtis.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file util/queue.h
|
||||||
|
* Static queue primitives.
|
||||||
|
*
|
||||||
|
* This file contains a set of static queue primitives that are common among
|
||||||
|
* all of the low level queue implementations. The primitives are inline
|
||||||
|
* functions, and will be optimal if size is a constant power of 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef I__QUEUE_H__
|
||||||
|
#define I__QUEUE_H__
|
||||||
|
|
||||||
|
/** Increment a queue index.
|
||||||
|
* @param[in] idx Queue index
|
||||||
|
* @param[in] size Queue size
|
||||||
|
* @returns The new queue index value
|
||||||
|
*/
|
||||||
|
static inline size_t qinc(size_t idx, size_t size)
|
||||||
|
{
|
||||||
|
return ((idx + 1) % size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Decrement a queue index.
|
||||||
|
* @param[in] idx Queue index
|
||||||
|
* @param[in] size Queue size
|
||||||
|
* @returns The new queue index value
|
||||||
|
*/
|
||||||
|
static inline size_t qdec(size_t idx, size_t size)
|
||||||
|
{
|
||||||
|
return ((idx - 1) % size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tests if a queue is full.
|
||||||
|
* @param[in] head Head index
|
||||||
|
* @param[in] tail Tail index
|
||||||
|
* @param[in] size Queue size
|
||||||
|
*/
|
||||||
|
static inline int qfull(size_t head, size_t tail, size_t size)
|
||||||
|
{
|
||||||
|
size_t next_head = qinc(head, size);
|
||||||
|
return (next_head == tail);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tests if a queue is empty.
|
||||||
|
* @param[in] head Head index
|
||||||
|
* @param[in] tail Tail index
|
||||||
|
*/
|
||||||
|
static inline int qempty(size_t head, size_t tail)
|
||||||
|
{
|
||||||
|
return (head == tail);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* I__QUEUE_H__ */
|
34
src/include/rtt.h
Normal file
34
src/include/rtt.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#ifndef RTT_H
|
||||||
|
#define RTT_H
|
||||||
|
#include <target.h>
|
||||||
|
|
||||||
|
#define MAX_RTT_CHAN 16
|
||||||
|
|
||||||
|
extern char rtt_ident[16]; // string
|
||||||
|
extern bool rtt_enabled; // rtt on/off
|
||||||
|
extern bool rtt_found; // control block found
|
||||||
|
extern uint32_t rtt_cbaddr; // control block address
|
||||||
|
extern uint32_t rtt_min_poll_ms; // min time between polls (ms)
|
||||||
|
extern uint32_t rtt_max_poll_ms; // max time between polls (ms)
|
||||||
|
extern uint32_t rtt_max_poll_errs; // max number of errors before disconnect
|
||||||
|
extern bool rtt_auto_channel; // manual or auto channel selection
|
||||||
|
extern bool rtt_flag_skip; // skip if host-to-target fifo full
|
||||||
|
extern bool rtt_flag_block; // block if host-to-target fifo full
|
||||||
|
|
||||||
|
struct rtt_channel_struct {
|
||||||
|
bool is_enabled; // does user want to see this channel?
|
||||||
|
bool is_configured; // is channel configured in control block?
|
||||||
|
bool is_output;
|
||||||
|
uint32_t buf_addr;
|
||||||
|
uint32_t buf_size;
|
||||||
|
uint32_t head_addr;
|
||||||
|
uint32_t tail_addr;
|
||||||
|
uint32_t flag;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct rtt_channel_struct rtt_channel[MAX_RTT_CHAN];
|
||||||
|
|
||||||
|
// true if target memory access does not work when target running
|
||||||
|
extern bool target_no_background_memory_access(target *cur_target);
|
||||||
|
extern void poll_rtt(target *cur_target);
|
||||||
|
#endif
|
36
src/include/rtt_if.h
Normal file
36
src/include/rtt_if.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef RTT_IF_H
|
||||||
|
#define RTT_IF_H
|
||||||
|
/* rtt i/o to terminal */
|
||||||
|
|
||||||
|
/* default buffer sizes, 8 bytes added to up buffer for alignment and padding */
|
||||||
|
/* override RTT_UP_BUF_SIZE and RTT_DOWN_BUF_SIZE in platform.h if needed */
|
||||||
|
|
||||||
|
#if !defined(RTT_UP_BUF_SIZE) || !defined(RTT_DOWN_BUF_SIZE)
|
||||||
|
#if (PC_HOSTED == 1)
|
||||||
|
#define RTT_UP_BUF_SIZE (4096 + 8)
|
||||||
|
#define RTT_DOWN_BUF_SIZE (512)
|
||||||
|
#elif defined(STM32F7)
|
||||||
|
#define RTT_UP_BUF_SIZE (4096 + 8)
|
||||||
|
#define RTT_DOWN_BUF_SIZE (2048)
|
||||||
|
#elif defined(STM32F4)
|
||||||
|
#define RTT_UP_BUF_SIZE (2048 + 8)
|
||||||
|
#define RTT_DOWN_BUF_SIZE (256)
|
||||||
|
#else /* stm32f103 */
|
||||||
|
#define RTT_UP_BUF_SIZE (1024 + 8)
|
||||||
|
#define RTT_DOWN_BUF_SIZE (256)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* hosted initialisation */
|
||||||
|
extern int rtt_if_init(void);
|
||||||
|
/* hosted teardown */
|
||||||
|
extern int rtt_if_exit(void);
|
||||||
|
|
||||||
|
/* target to host: write len bytes from the buffer starting at buf. return number bytes written */
|
||||||
|
extern uint32_t rtt_write(const char *buf, uint32_t len);
|
||||||
|
/* host to target: read one character, non-blocking. return character, -1 if no character */
|
||||||
|
extern int32_t rtt_getchar();
|
||||||
|
/* host to target: true if no characters available for reading */
|
||||||
|
extern bool rtt_nodata();
|
||||||
|
|
||||||
|
#endif
|
@ -20,7 +20,7 @@
|
|||||||
#ifndef __SERIALNO_H
|
#ifndef __SERIALNO_H
|
||||||
#define __SERIALNO_H
|
#define __SERIALNO_H
|
||||||
|
|
||||||
char *serial_no_read(char *s, int max);
|
char *serial_no_read(char *s);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -35,13 +35,13 @@ typedef uint32_t target_addr;
|
|||||||
struct target_controller;
|
struct target_controller;
|
||||||
|
|
||||||
#if PC_HOSTED == 1
|
#if PC_HOSTED == 1
|
||||||
int platform_adiv5_swdp_scan(void);
|
int platform_adiv5_swdp_scan(uint32_t targetid);
|
||||||
int platform_jtag_scan(const uint8_t *lrlens);
|
int platform_jtag_scan(const uint8_t *lrlens);
|
||||||
#endif
|
#endif
|
||||||
int adiv5_swdp_scan(void);
|
int adiv5_swdp_scan(uint32_t targetid);
|
||||||
int jtag_scan(const uint8_t *lrlens);
|
int jtag_scan(const uint8_t *lrlens);
|
||||||
|
|
||||||
bool target_foreach(void (*cb)(int i, target *t, void *context), void *context);
|
int target_foreach(void (*cb)(int i, target *t, void *context), void *context);
|
||||||
void target_list_free(void);
|
void target_list_free(void);
|
||||||
|
|
||||||
/* Attach/detach functions */
|
/* Attach/detach functions */
|
||||||
@ -51,6 +51,8 @@ void target_detach(target *t);
|
|||||||
bool target_attached(target *t);
|
bool target_attached(target *t);
|
||||||
const char *target_driver_name(target *t);
|
const char *target_driver_name(target *t);
|
||||||
const char *target_core_name(target *t);
|
const char *target_core_name(target *t);
|
||||||
|
unsigned int target_designer(target *t);
|
||||||
|
unsigned int target_idcode(target *t);
|
||||||
|
|
||||||
/* Memory access functions */
|
/* Memory access functions */
|
||||||
bool target_mem_map(target *t, char *buf, size_t len);
|
bool target_mem_map(target *t, char *buf, size_t len);
|
||||||
|
@ -24,6 +24,7 @@ struct platform_timeout {
|
|||||||
uint32_t time;
|
uint32_t time;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern int32_t swj_delay_cnt;
|
||||||
uint32_t platform_time_ms(void);
|
uint32_t platform_time_ms(void);
|
||||||
|
|
||||||
#endif /* __TIMING_H */
|
#endif /* __TIMING_H */
|
||||||
|
@ -64,7 +64,7 @@ void morse(const char *msg, char repeat)
|
|||||||
DEBUG_WARN("%s\n", msg);
|
DEBUG_WARN("%s\n", msg);
|
||||||
(void) repeat;
|
(void) repeat;
|
||||||
#else
|
#else
|
||||||
morse_msg = morse_ptr = msg;
|
morse_msg = morse_ptr = msg;
|
||||||
morse_repeat = repeat;
|
morse_repeat = repeat;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,18 @@
|
|||||||
* field firmware upgrade.
|
* field firmware upgrade.
|
||||||
*
|
*
|
||||||
* The device's unique id is used as the USB serial number string.
|
* The device's unique id is used as the USB serial number string.
|
||||||
|
*
|
||||||
|
* Endpoint Usage
|
||||||
|
*
|
||||||
|
* 0 Control Endpoint
|
||||||
|
* IN 1 GDB CDC DATA
|
||||||
|
* OUT 1 GDB CDC DATA
|
||||||
|
* IN 2 GDB CDC CTR
|
||||||
|
* IN 3 UART CDC DATA
|
||||||
|
* OUT 3 UART CDC DATA
|
||||||
|
* OUT 4 UART CDC CTRL
|
||||||
|
* In 5 Trace Capture
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
@ -34,15 +46,23 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "usbuart.h"
|
#include "usbuart.h"
|
||||||
#include "serialno.h"
|
#include "serialno.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
#include <libopencm3/cm3/nvic.h>
|
#include <libopencm3/cm3/nvic.h>
|
||||||
#include <libopencm3/usb/usbd.h>
|
#include <libopencm3/usb/usbd.h>
|
||||||
#include <libopencm3/usb/cdc.h>
|
#include <libopencm3/usb/cdc.h>
|
||||||
#include <libopencm3/cm3/scb.h>
|
#include <libopencm3/cm3/scb.h>
|
||||||
#include <libopencm3/usb/dfu.h>
|
#include <libopencm3/usb/dfu.h>
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#define DFU_IF_NO 4
|
#define GDB_IF_NO 0
|
||||||
|
#define UART_IF_NO 2
|
||||||
|
#define DFU_IF_NO 4
|
||||||
|
#if defined(PLATFORM_HAS_TRACESWO)
|
||||||
|
# define TRACE_IF_NO 5
|
||||||
|
# define TOTAL_INTERFACES 6
|
||||||
|
#else
|
||||||
|
# define TOTAL_INTERFACES 5
|
||||||
|
#endif
|
||||||
|
|
||||||
usbd_device * usbdev;
|
usbd_device * usbdev;
|
||||||
|
|
||||||
@ -51,14 +71,18 @@ static int cdcacm_gdb_dtr = 1;
|
|||||||
|
|
||||||
static void cdcacm_set_modem_state(usbd_device *dev, int iface, bool dsr, bool dcd);
|
static void cdcacm_set_modem_state(usbd_device *dev, int iface, bool dsr, bool dcd);
|
||||||
|
|
||||||
static const struct usb_device_descriptor dev = {
|
static const struct usb_device_descriptor dev_desc = {
|
||||||
.bLength = USB_DT_DEVICE_SIZE,
|
.bLength = USB_DT_DEVICE_SIZE,
|
||||||
.bDescriptorType = USB_DT_DEVICE,
|
.bDescriptorType = USB_DT_DEVICE,
|
||||||
.bcdUSB = 0x0200,
|
.bcdUSB = 0x0200,
|
||||||
.bDeviceClass = 0xEF, /* Miscellaneous Device */
|
.bDeviceClass = 0xEF, /* Miscellaneous Device */
|
||||||
.bDeviceSubClass = 2, /* Common Class */
|
.bDeviceSubClass = 2, /* Common Class */
|
||||||
.bDeviceProtocol = 1, /* Interface Association */
|
.bDeviceProtocol = 1, /* Interface Association */
|
||||||
|
#if defined(SAMD21E17) || defined(LM4F)
|
||||||
|
.bMaxPacketSize0 = 64, /*Fixed for icdi*/
|
||||||
|
#else
|
||||||
.bMaxPacketSize0 = 32,
|
.bMaxPacketSize0 = 32,
|
||||||
|
#endif
|
||||||
.idVendor = 0x1D50,
|
.idVendor = 0x1D50,
|
||||||
.idProduct = 0x6018,
|
.idProduct = 0x6018,
|
||||||
.bcdDevice = 0x0100,
|
.bcdDevice = 0x0100,
|
||||||
@ -74,7 +98,7 @@ static const struct usb_device_descriptor dev = {
|
|||||||
static const struct usb_endpoint_descriptor gdb_comm_endp[] = {{
|
static const struct usb_endpoint_descriptor gdb_comm_endp[] = {{
|
||||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||||
.bDescriptorType = USB_DT_ENDPOINT,
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
.bEndpointAddress = 0x82,
|
.bEndpointAddress = (CDCACM_GDB_ENDPOINT + 1) | USB_REQ_TYPE_IN,
|
||||||
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
|
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
|
||||||
.wMaxPacketSize = 16,
|
.wMaxPacketSize = 16,
|
||||||
.bInterval = 255,
|
.bInterval = 255,
|
||||||
@ -83,14 +107,14 @@ static const struct usb_endpoint_descriptor gdb_comm_endp[] = {{
|
|||||||
static const struct usb_endpoint_descriptor gdb_data_endp[] = {{
|
static const struct usb_endpoint_descriptor gdb_data_endp[] = {{
|
||||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||||
.bDescriptorType = USB_DT_ENDPOINT,
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
.bEndpointAddress = 0x01,
|
.bEndpointAddress = CDCACM_GDB_ENDPOINT,
|
||||||
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
||||||
.wMaxPacketSize = CDCACM_PACKET_SIZE,
|
.wMaxPacketSize = CDCACM_PACKET_SIZE,
|
||||||
.bInterval = 1,
|
.bInterval = 1,
|
||||||
}, {
|
}, {
|
||||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||||
.bDescriptorType = USB_DT_ENDPOINT,
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
.bEndpointAddress = 0x81,
|
.bEndpointAddress = CDCACM_GDB_ENDPOINT | USB_REQ_TYPE_IN,
|
||||||
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
||||||
.wMaxPacketSize = CDCACM_PACKET_SIZE,
|
.wMaxPacketSize = CDCACM_PACKET_SIZE,
|
||||||
.bInterval = 1,
|
.bInterval = 1,
|
||||||
@ -114,7 +138,7 @@ static const struct {
|
|||||||
.bDescriptorType = CS_INTERFACE,
|
.bDescriptorType = CS_INTERFACE,
|
||||||
.bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
|
.bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
|
||||||
.bmCapabilities = 0,
|
.bmCapabilities = 0,
|
||||||
.bDataInterface = 1,
|
.bDataInterface = GDB_IF_NO + 1,
|
||||||
},
|
},
|
||||||
.acm = {
|
.acm = {
|
||||||
.bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
|
.bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
|
||||||
@ -126,8 +150,8 @@ static const struct {
|
|||||||
.bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
|
.bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
|
||||||
.bDescriptorType = CS_INTERFACE,
|
.bDescriptorType = CS_INTERFACE,
|
||||||
.bDescriptorSubtype = USB_CDC_TYPE_UNION,
|
.bDescriptorSubtype = USB_CDC_TYPE_UNION,
|
||||||
.bControlInterface = 0,
|
.bControlInterface = GDB_IF_NO,
|
||||||
.bSubordinateInterface0 = 1,
|
.bSubordinateInterface0 = GDB_IF_NO + 1,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -139,7 +163,7 @@ static const struct usb_interface_descriptor gdb_comm_iface[] = {{
|
|||||||
.bNumEndpoints = 1,
|
.bNumEndpoints = 1,
|
||||||
.bInterfaceClass = USB_CLASS_CDC,
|
.bInterfaceClass = USB_CLASS_CDC,
|
||||||
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
||||||
.bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
|
.bInterfaceProtocol = USB_CDC_PROTOCOL_NONE,
|
||||||
.iInterface = 4,
|
.iInterface = 4,
|
||||||
|
|
||||||
.endpoint = gdb_comm_endp,
|
.endpoint = gdb_comm_endp,
|
||||||
@ -151,7 +175,7 @@ static const struct usb_interface_descriptor gdb_comm_iface[] = {{
|
|||||||
static const struct usb_interface_descriptor gdb_data_iface[] = {{
|
static const struct usb_interface_descriptor gdb_data_iface[] = {{
|
||||||
.bLength = USB_DT_INTERFACE_SIZE,
|
.bLength = USB_DT_INTERFACE_SIZE,
|
||||||
.bDescriptorType = USB_DT_INTERFACE,
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
.bInterfaceNumber = 1,
|
.bInterfaceNumber = GDB_IF_NO + 1,
|
||||||
.bAlternateSetting = 0,
|
.bAlternateSetting = 0,
|
||||||
.bNumEndpoints = 2,
|
.bNumEndpoints = 2,
|
||||||
.bInterfaceClass = USB_CLASS_DATA,
|
.bInterfaceClass = USB_CLASS_DATA,
|
||||||
@ -165,19 +189,19 @@ static const struct usb_interface_descriptor gdb_data_iface[] = {{
|
|||||||
static const struct usb_iface_assoc_descriptor gdb_assoc = {
|
static const struct usb_iface_assoc_descriptor gdb_assoc = {
|
||||||
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
|
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
|
||||||
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
||||||
.bFirstInterface = 0,
|
.bFirstInterface = GDB_IF_NO,
|
||||||
.bInterfaceCount = 2,
|
.bInterfaceCount = 2,
|
||||||
.bFunctionClass = USB_CLASS_CDC,
|
.bFunctionClass = USB_CLASS_CDC,
|
||||||
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
||||||
.bFunctionProtocol = USB_CDC_PROTOCOL_AT,
|
.bFunctionProtocol = USB_CDC_PROTOCOL_NONE,
|
||||||
.iFunction = 0,
|
.iFunction = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Serial ACM interface */
|
/* Serial ACM interface */
|
||||||
static const struct usb_endpoint_descriptor uart_comm_endp[] = {{
|
static const struct usb_endpoint_descriptor uart_comm_endp[] = {{
|
||||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||||
.bDescriptorType = USB_DT_ENDPOINT,
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
.bEndpointAddress = 0x84,
|
.bEndpointAddress = (CDCACM_UART_ENDPOINT + 1) | USB_REQ_TYPE_IN,
|
||||||
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
|
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
|
||||||
.wMaxPacketSize = 16,
|
.wMaxPacketSize = 16,
|
||||||
.bInterval = 255,
|
.bInterval = 255,
|
||||||
@ -186,14 +210,14 @@ static const struct usb_endpoint_descriptor uart_comm_endp[] = {{
|
|||||||
static const struct usb_endpoint_descriptor uart_data_endp[] = {{
|
static const struct usb_endpoint_descriptor uart_data_endp[] = {{
|
||||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||||
.bDescriptorType = USB_DT_ENDPOINT,
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
.bEndpointAddress = 0x03,
|
.bEndpointAddress = CDCACM_UART_ENDPOINT,
|
||||||
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
||||||
.wMaxPacketSize = CDCACM_PACKET_SIZE / 2,
|
.wMaxPacketSize = CDCACM_PACKET_SIZE / 2,
|
||||||
.bInterval = 1,
|
.bInterval = 1,
|
||||||
}, {
|
}, {
|
||||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||||
.bDescriptorType = USB_DT_ENDPOINT,
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
.bEndpointAddress = 0x83,
|
.bEndpointAddress = CDCACM_UART_ENDPOINT | USB_REQ_TYPE_IN,
|
||||||
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
||||||
.wMaxPacketSize = CDCACM_PACKET_SIZE,
|
.wMaxPacketSize = CDCACM_PACKET_SIZE,
|
||||||
.bInterval = 1,
|
.bInterval = 1,
|
||||||
@ -217,7 +241,7 @@ static const struct {
|
|||||||
.bDescriptorType = CS_INTERFACE,
|
.bDescriptorType = CS_INTERFACE,
|
||||||
.bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
|
.bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
|
||||||
.bmCapabilities = 0,
|
.bmCapabilities = 0,
|
||||||
.bDataInterface = 3,
|
.bDataInterface = UART_IF_NO + 1,
|
||||||
},
|
},
|
||||||
.acm = {
|
.acm = {
|
||||||
.bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
|
.bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
|
||||||
@ -229,20 +253,20 @@ static const struct {
|
|||||||
.bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
|
.bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
|
||||||
.bDescriptorType = CS_INTERFACE,
|
.bDescriptorType = CS_INTERFACE,
|
||||||
.bDescriptorSubtype = USB_CDC_TYPE_UNION,
|
.bDescriptorSubtype = USB_CDC_TYPE_UNION,
|
||||||
.bControlInterface = 2,
|
.bControlInterface = UART_IF_NO,
|
||||||
.bSubordinateInterface0 = 3,
|
.bSubordinateInterface0 = UART_IF_NO + 1,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct usb_interface_descriptor uart_comm_iface[] = {{
|
static const struct usb_interface_descriptor uart_comm_iface[] = {{
|
||||||
.bLength = USB_DT_INTERFACE_SIZE,
|
.bLength = USB_DT_INTERFACE_SIZE,
|
||||||
.bDescriptorType = USB_DT_INTERFACE,
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
.bInterfaceNumber = 2,
|
.bInterfaceNumber = UART_IF_NO,
|
||||||
.bAlternateSetting = 0,
|
.bAlternateSetting = 0,
|
||||||
.bNumEndpoints = 1,
|
.bNumEndpoints = 1,
|
||||||
.bInterfaceClass = USB_CLASS_CDC,
|
.bInterfaceClass = USB_CLASS_CDC,
|
||||||
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
||||||
.bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
|
.bInterfaceProtocol = USB_CDC_PROTOCOL_NONE,
|
||||||
.iInterface = 5,
|
.iInterface = 5,
|
||||||
|
|
||||||
.endpoint = uart_comm_endp,
|
.endpoint = uart_comm_endp,
|
||||||
@ -254,7 +278,7 @@ static const struct usb_interface_descriptor uart_comm_iface[] = {{
|
|||||||
static const struct usb_interface_descriptor uart_data_iface[] = {{
|
static const struct usb_interface_descriptor uart_data_iface[] = {{
|
||||||
.bLength = USB_DT_INTERFACE_SIZE,
|
.bLength = USB_DT_INTERFACE_SIZE,
|
||||||
.bDescriptorType = USB_DT_INTERFACE,
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
.bInterfaceNumber = 3,
|
.bInterfaceNumber = UART_IF_NO + 1,
|
||||||
.bAlternateSetting = 0,
|
.bAlternateSetting = 0,
|
||||||
.bNumEndpoints = 2,
|
.bNumEndpoints = 2,
|
||||||
.bInterfaceClass = USB_CLASS_DATA,
|
.bInterfaceClass = USB_CLASS_DATA,
|
||||||
@ -268,12 +292,12 @@ static const struct usb_interface_descriptor uart_data_iface[] = {{
|
|||||||
static const struct usb_iface_assoc_descriptor uart_assoc = {
|
static const struct usb_iface_assoc_descriptor uart_assoc = {
|
||||||
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
|
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
|
||||||
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
||||||
.bFirstInterface = 2,
|
.bFirstInterface = UART_IF_NO,
|
||||||
.bInterfaceCount = 2,
|
.bInterfaceCount = 2,
|
||||||
.bFunctionClass = USB_CLASS_CDC,
|
.bFunctionClass = USB_CLASS_CDC,
|
||||||
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
||||||
.bFunctionProtocol = USB_CDC_PROTOCOL_AT,
|
.bFunctionProtocol = USB_CDC_PROTOCOL_NONE,
|
||||||
.iFunction = 0,
|
.iFunction = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct usb_dfu_descriptor dfu_function = {
|
const struct usb_dfu_descriptor dfu_function = {
|
||||||
@ -303,7 +327,7 @@ const struct usb_interface_descriptor dfu_iface = {
|
|||||||
static const struct usb_iface_assoc_descriptor dfu_assoc = {
|
static const struct usb_iface_assoc_descriptor dfu_assoc = {
|
||||||
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
|
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
|
||||||
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
||||||
.bFirstInterface = 4,
|
.bFirstInterface = DFU_IF_NO,
|
||||||
.bInterfaceCount = 1,
|
.bInterfaceCount = 1,
|
||||||
.bFunctionClass = 0xFE,
|
.bFunctionClass = 0xFE,
|
||||||
.bFunctionSubClass = 1,
|
.bFunctionSubClass = 1,
|
||||||
@ -315,7 +339,7 @@ static const struct usb_iface_assoc_descriptor dfu_assoc = {
|
|||||||
static const struct usb_endpoint_descriptor trace_endp[] = {{
|
static const struct usb_endpoint_descriptor trace_endp[] = {{
|
||||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||||
.bDescriptorType = USB_DT_ENDPOINT,
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
.bEndpointAddress = 0x85,
|
.bEndpointAddress = TRACE_ENDPOINT | USB_REQ_TYPE_IN,
|
||||||
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
||||||
.wMaxPacketSize = 64,
|
.wMaxPacketSize = 64,
|
||||||
.bInterval = 0,
|
.bInterval = 0,
|
||||||
@ -324,7 +348,7 @@ static const struct usb_endpoint_descriptor trace_endp[] = {{
|
|||||||
const struct usb_interface_descriptor trace_iface = {
|
const struct usb_interface_descriptor trace_iface = {
|
||||||
.bLength = USB_DT_INTERFACE_SIZE,
|
.bLength = USB_DT_INTERFACE_SIZE,
|
||||||
.bDescriptorType = USB_DT_INTERFACE,
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
.bInterfaceNumber = 5,
|
.bInterfaceNumber = TRACE_IF_NO,
|
||||||
.bAlternateSetting = 0,
|
.bAlternateSetting = 0,
|
||||||
.bNumEndpoints = 1,
|
.bNumEndpoints = 1,
|
||||||
.bInterfaceClass = 0xFF,
|
.bInterfaceClass = 0xFF,
|
||||||
@ -338,7 +362,7 @@ const struct usb_interface_descriptor trace_iface = {
|
|||||||
static const struct usb_iface_assoc_descriptor trace_assoc = {
|
static const struct usb_iface_assoc_descriptor trace_assoc = {
|
||||||
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
|
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
|
||||||
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
||||||
.bFirstInterface = 5,
|
.bFirstInterface = TRACE_IF_NO,
|
||||||
.bInterfaceCount = 1,
|
.bInterfaceCount = 1,
|
||||||
.bFunctionClass = 0xFF,
|
.bFunctionClass = 0xFF,
|
||||||
.bFunctionSubClass = 0xFF,
|
.bFunctionSubClass = 0xFF,
|
||||||
@ -377,11 +401,7 @@ static const struct usb_config_descriptor config = {
|
|||||||
.bLength = USB_DT_CONFIGURATION_SIZE,
|
.bLength = USB_DT_CONFIGURATION_SIZE,
|
||||||
.bDescriptorType = USB_DT_CONFIGURATION,
|
.bDescriptorType = USB_DT_CONFIGURATION,
|
||||||
.wTotalLength = 0,
|
.wTotalLength = 0,
|
||||||
#if defined(PLATFORM_HAS_TRACESWO)
|
.bNumInterfaces = TOTAL_INTERFACES,
|
||||||
.bNumInterfaces = 6,
|
|
||||||
#else
|
|
||||||
.bNumInterfaces = 5,
|
|
||||||
#endif
|
|
||||||
.bConfigurationValue = 1,
|
.bConfigurationValue = 1,
|
||||||
.iConfiguration = 0,
|
.iConfiguration = 0,
|
||||||
.bmAttributes = 0x80,
|
.bmAttributes = 0x80,
|
||||||
@ -389,20 +409,17 @@ static const struct usb_config_descriptor config = {
|
|||||||
|
|
||||||
.interface = ifaces,
|
.interface = ifaces,
|
||||||
};
|
};
|
||||||
|
static char serial_no[DFU_SERIAL_LENGTH];
|
||||||
|
|
||||||
#if defined(STM32L0) || defined(STM32F3) || defined(STM32F4)
|
#define BOARD_IDENT "Black Magic Probe " PLATFORM_IDENT FIRMWARE_VERSION
|
||||||
static char serial_no[13];
|
|
||||||
#else
|
|
||||||
static char serial_no[9];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const char *usb_strings[] = {
|
static const char *usb_strings[] = {
|
||||||
"Black Sphere Technologies",
|
"Black Magic Debug",
|
||||||
BOARD_IDENT,
|
BOARD_IDENT,
|
||||||
serial_no,
|
serial_no,
|
||||||
"Black Magic GDB Server",
|
"Black Magic GDB Server",
|
||||||
"Black Magic UART Port",
|
"Black Magic UART Port",
|
||||||
DFU_IDENT,
|
"Black Magic DFU",
|
||||||
#if defined(PLATFORM_HAS_TRACESWO)
|
#if defined(PLATFORM_HAS_TRACESWO)
|
||||||
"Black Magic Trace Capture",
|
"Black Magic Trace Capture",
|
||||||
#endif
|
#endif
|
||||||
@ -416,7 +433,11 @@ static void dfu_detach_complete(usbd_device *dev, struct usb_setup_data *req)
|
|||||||
platform_request_boot();
|
platform_request_boot();
|
||||||
|
|
||||||
/* Reset core to enter bootloader */
|
/* Reset core to enter bootloader */
|
||||||
|
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||||
scb_reset_core();
|
scb_reset_core();
|
||||||
|
#else
|
||||||
|
scb_reset_system();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum usbd_request_return_codes cdcacm_control_request(usbd_device *dev,
|
static enum usbd_request_return_codes cdcacm_control_request(usbd_device *dev,
|
||||||
@ -432,7 +453,7 @@ static enum usbd_request_return_codes cdcacm_control_request(usbd_device *dev,
|
|||||||
case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
|
case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
|
||||||
cdcacm_set_modem_state(dev, req->wIndex, true, true);
|
cdcacm_set_modem_state(dev, req->wIndex, true, true);
|
||||||
/* Ignore if not for GDB interface */
|
/* Ignore if not for GDB interface */
|
||||||
if(req->wIndex != 0)
|
if(req->wIndex != GDB_IF_NO)
|
||||||
return USBD_REQ_HANDLED;
|
return USBD_REQ_HANDLED;
|
||||||
|
|
||||||
cdcacm_gdb_dtr = req->wValue & 1;
|
cdcacm_gdb_dtr = req->wValue & 1;
|
||||||
@ -443,10 +464,10 @@ static enum usbd_request_return_codes cdcacm_control_request(usbd_device *dev,
|
|||||||
return USBD_REQ_NOTSUPP;
|
return USBD_REQ_NOTSUPP;
|
||||||
|
|
||||||
switch(req->wIndex) {
|
switch(req->wIndex) {
|
||||||
case 2:
|
case UART_IF_NO:
|
||||||
usbuart_set_line_coding((struct usb_cdc_line_coding*)*buf);
|
usbuart_set_line_coding((struct usb_cdc_line_coding*)*buf);
|
||||||
return USBD_REQ_HANDLED;
|
return USBD_REQ_HANDLED;
|
||||||
case 0:
|
case GDB_IF_NO:
|
||||||
return USBD_REQ_HANDLED; /* Ignore on GDB Port */
|
return USBD_REQ_HANDLED; /* Ignore on GDB Port */
|
||||||
default:
|
default:
|
||||||
return USBD_REQ_NOTSUPP;
|
return USBD_REQ_NOTSUPP;
|
||||||
@ -496,6 +517,7 @@ static void cdcacm_set_modem_state(usbd_device *dev, int iface, bool dsr, bool d
|
|||||||
notif->wLength = 2;
|
notif->wLength = 2;
|
||||||
buf[8] = (dsr ? 2 : 0) | (dcd ? 1 : 0);
|
buf[8] = (dsr ? 2 : 0) | (dcd ? 1 : 0);
|
||||||
buf[9] = 0;
|
buf[9] = 0;
|
||||||
|
/* FIXME: Remove magic numbers */
|
||||||
usbd_ep_write_packet(dev, 0x82 + iface, buf, 10);
|
usbd_ep_write_packet(dev, 0x82 + iface, buf, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,27 +526,30 @@ static void cdcacm_set_config(usbd_device *dev, uint16_t wValue)
|
|||||||
configured = wValue;
|
configured = wValue;
|
||||||
|
|
||||||
/* GDB interface */
|
/* GDB interface */
|
||||||
#if defined(STM32F4) || defined(LM4F)
|
#if defined(STM32F4) || defined(LM4F) || defined(SAMD)
|
||||||
usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK,
|
usbd_ep_setup(dev, CDCACM_GDB_ENDPOINT, USB_ENDPOINT_ATTR_BULK,
|
||||||
CDCACM_PACKET_SIZE, gdb_usb_out_cb);
|
CDCACM_PACKET_SIZE, gdb_usb_out_cb);
|
||||||
#else
|
#else
|
||||||
usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK,
|
usbd_ep_setup(dev, CDCACM_GDB_ENDPOINT, USB_ENDPOINT_ATTR_BULK,
|
||||||
CDCACM_PACKET_SIZE, NULL);
|
CDCACM_PACKET_SIZE, NULL);
|
||||||
#endif
|
#endif
|
||||||
usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_BULK,
|
usbd_ep_setup(dev, CDCACM_GDB_ENDPOINT | USB_REQ_TYPE_IN,
|
||||||
CDCACM_PACKET_SIZE, NULL);
|
USB_ENDPOINT_ATTR_BULK, CDCACM_PACKET_SIZE, NULL);
|
||||||
usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
|
usbd_ep_setup(dev, (CDCACM_GDB_ENDPOINT + 1) | USB_REQ_TYPE_IN,
|
||||||
|
USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
|
||||||
|
|
||||||
/* Serial interface */
|
/* Serial interface */
|
||||||
usbd_ep_setup(dev, 0x03, USB_ENDPOINT_ATTR_BULK,
|
usbd_ep_setup(dev, CDCACM_UART_ENDPOINT, USB_ENDPOINT_ATTR_BULK,
|
||||||
CDCACM_PACKET_SIZE / 2, usbuart_usb_out_cb);
|
CDCACM_PACKET_SIZE / 2, usbuart_usb_out_cb);
|
||||||
usbd_ep_setup(dev, 0x83, USB_ENDPOINT_ATTR_BULK,
|
usbd_ep_setup(dev, CDCACM_UART_ENDPOINT | USB_REQ_TYPE_IN,
|
||||||
|
USB_ENDPOINT_ATTR_BULK,
|
||||||
CDCACM_PACKET_SIZE, usbuart_usb_in_cb);
|
CDCACM_PACKET_SIZE, usbuart_usb_in_cb);
|
||||||
usbd_ep_setup(dev, 0x84, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
|
usbd_ep_setup(dev, (CDCACM_UART_ENDPOINT + 1) | USB_REQ_TYPE_IN,
|
||||||
|
USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
|
||||||
|
|
||||||
#if defined(PLATFORM_HAS_TRACESWO)
|
#if defined(PLATFORM_HAS_TRACESWO)
|
||||||
/* Trace interface */
|
/* Trace interface */
|
||||||
usbd_ep_setup(dev, 0x85, USB_ENDPOINT_ATTR_BULK,
|
usbd_ep_setup(dev, TRACE_ENDPOINT | USB_REQ_TYPE_IN, USB_ENDPOINT_ATTR_BULK,
|
||||||
64, trace_buf_drain);
|
64, trace_buf_drain);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -536,8 +561,8 @@ static void cdcacm_set_config(usbd_device *dev, uint16_t wValue)
|
|||||||
/* Notify the host that DCD is asserted.
|
/* Notify the host that DCD is asserted.
|
||||||
* Allows the use of /dev/tty* devices on *BSD/MacOS
|
* Allows the use of /dev/tty* devices on *BSD/MacOS
|
||||||
*/
|
*/
|
||||||
cdcacm_set_modem_state(dev, 0, true, true);
|
cdcacm_set_modem_state(dev, GDB_IF_NO, true, true);
|
||||||
cdcacm_set_modem_state(dev, 2, true, true);
|
cdcacm_set_modem_state(dev, UART_IF_NO, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need a special large control buffer for this device: */
|
/* We need a special large control buffer for this device: */
|
||||||
@ -547,9 +572,9 @@ void cdcacm_init(void)
|
|||||||
{
|
{
|
||||||
void exti15_10_isr(void);
|
void exti15_10_isr(void);
|
||||||
|
|
||||||
serial_no_read(serial_no, sizeof(serial_no));
|
serial_no_read(serial_no);
|
||||||
|
|
||||||
usbdev = usbd_init(&USB_DRIVER, &dev, &config, usb_strings,
|
usbdev = usbd_init(&USB_DRIVER, &dev_desc, &config, usb_strings,
|
||||||
sizeof(usb_strings)/sizeof(char *),
|
sizeof(usb_strings)/sizeof(char *),
|
||||||
usbd_control_buffer, sizeof(usbd_control_buffer));
|
usbd_control_buffer, sizeof(usbd_control_buffer));
|
||||||
|
|
||||||
@ -557,6 +582,7 @@ void cdcacm_init(void)
|
|||||||
|
|
||||||
nvic_set_priority(USB_IRQ, IRQ_PRI_USB);
|
nvic_set_priority(USB_IRQ, IRQ_PRI_USB);
|
||||||
nvic_enable_irq(USB_IRQ);
|
nvic_enable_irq(USB_IRQ);
|
||||||
|
usbd_disconnect(usbdev, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void USB_ISR(void)
|
void USB_ISR(void)
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#define CDCACM_GDB_ENDPOINT 1
|
#define CDCACM_GDB_ENDPOINT 1
|
||||||
#define CDCACM_UART_ENDPOINT 3
|
#define CDCACM_UART_ENDPOINT 3
|
||||||
|
#define TRACE_ENDPOINT 5
|
||||||
|
|
||||||
extern usbd_device *usbdev;
|
extern usbd_device *usbdev;
|
||||||
|
|
||||||
|
@ -70,12 +70,15 @@ static void jtagtap_reset(void)
|
|||||||
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
||||||
{
|
{
|
||||||
uint16_t ret;
|
uint16_t ret;
|
||||||
|
register volatile int32_t cnt;
|
||||||
|
|
||||||
gpio_set_val(TMS_PORT, TMS_PIN, dTMS);
|
gpio_set_val(TMS_PORT, TMS_PIN, dTMS);
|
||||||
gpio_set_val(TDI_PORT, TDI_PIN, dTDI);
|
gpio_set_val(TDI_PORT, TDI_PIN, dTDI);
|
||||||
gpio_set(TCK_PORT, TCK_PIN);
|
gpio_set(TCK_PORT, TCK_PIN);
|
||||||
|
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
|
||||||
ret = gpio_get(TDO_PORT, TDO_PIN);
|
ret = gpio_get(TDO_PORT, TDO_PIN);
|
||||||
gpio_clear(TCK_PORT, TCK_PIN);
|
gpio_clear(TCK_PORT, TCK_PIN);
|
||||||
|
for(cnt = swd_delay_cnt - 2; cnt > 0; cnt--);
|
||||||
|
|
||||||
//DEBUG("jtagtap_next(TMS = %d, TDI = %d) = %d\n", dTMS, dTDI, ret);
|
//DEBUG("jtagtap_next(TMS = %d, TDI = %d) = %d\n", dTMS, dTDI, ret);
|
||||||
|
|
||||||
@ -86,13 +89,27 @@ static void jtagtap_tms_seq(uint32_t MS, int ticks)
|
|||||||
{
|
{
|
||||||
gpio_set_val(TDI_PORT, TDI_PIN, 1);
|
gpio_set_val(TDI_PORT, TDI_PIN, 1);
|
||||||
int data = MS & 1;
|
int data = MS & 1;
|
||||||
while(ticks) {
|
register volatile int32_t cnt;
|
||||||
gpio_set_val(TMS_PORT, TMS_PIN, data);
|
if (swd_delay_cnt) {
|
||||||
gpio_set(TCK_PORT, TCK_PIN);
|
while(ticks) {
|
||||||
MS >>= 1;
|
gpio_set_val(TMS_PORT, TMS_PIN, data);
|
||||||
data = MS & 1;
|
gpio_set(TCK_PORT, TCK_PIN);
|
||||||
ticks--;
|
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
|
||||||
gpio_clear(TCK_PORT, TCK_PIN);
|
MS >>= 1;
|
||||||
|
data = MS & 1;
|
||||||
|
ticks--;
|
||||||
|
gpio_clear(TCK_PORT, TCK_PIN);
|
||||||
|
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while(ticks) {
|
||||||
|
gpio_set_val(TMS_PORT, TMS_PIN, data);
|
||||||
|
gpio_set(TCK_PORT, TCK_PIN);
|
||||||
|
MS >>= 1;
|
||||||
|
data = MS & 1;
|
||||||
|
ticks--;
|
||||||
|
gpio_clear(TCK_PORT, TCK_PIN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,42 +119,81 @@ static void jtagtap_tdi_tdo_seq(
|
|||||||
uint8_t index = 1;
|
uint8_t index = 1;
|
||||||
gpio_set_val(TMS_PORT, TMS_PIN, 0);
|
gpio_set_val(TMS_PORT, TMS_PIN, 0);
|
||||||
uint8_t res = 0;
|
uint8_t res = 0;
|
||||||
while(ticks > 1) {
|
register volatile int32_t cnt;
|
||||||
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
|
if (swd_delay_cnt) {
|
||||||
gpio_set(TCK_PORT, TCK_PIN);
|
while(ticks > 1) {
|
||||||
if (gpio_get(TDO_PORT, TDO_PIN)) {
|
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
|
||||||
res |= index;
|
gpio_set(TCK_PORT, TCK_PIN);
|
||||||
|
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
|
||||||
|
if (gpio_get(TDO_PORT, TDO_PIN)) {
|
||||||
|
res |= index;
|
||||||
|
}
|
||||||
|
if(!(index <<= 1)) {
|
||||||
|
*DO = res;
|
||||||
|
res = 0;
|
||||||
|
index = 1;
|
||||||
|
DI++; DO++;
|
||||||
|
}
|
||||||
|
ticks--;
|
||||||
|
gpio_clear(TCK_PORT, TCK_PIN);
|
||||||
|
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
|
||||||
}
|
}
|
||||||
if(!(index <<= 1)) {
|
} else {
|
||||||
*DO = res;
|
while(ticks > 1) {
|
||||||
res = 0;
|
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
|
||||||
index = 1;
|
gpio_set(TCK_PORT, TCK_PIN);
|
||||||
DI++; DO++;
|
if (gpio_get(TDO_PORT, TDO_PIN)) {
|
||||||
|
res |= index;
|
||||||
|
}
|
||||||
|
if(!(index <<= 1)) {
|
||||||
|
*DO = res;
|
||||||
|
res = 0;
|
||||||
|
index = 1;
|
||||||
|
DI++; DO++;
|
||||||
|
}
|
||||||
|
ticks--;
|
||||||
|
gpio_clear(TCK_PORT, TCK_PIN);
|
||||||
}
|
}
|
||||||
ticks--;
|
|
||||||
gpio_clear(TCK_PORT, TCK_PIN);
|
|
||||||
}
|
}
|
||||||
gpio_set_val(TMS_PORT, TMS_PIN, final_tms);
|
gpio_set_val(TMS_PORT, TMS_PIN, final_tms);
|
||||||
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
|
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
|
||||||
gpio_set(TCK_PORT, TCK_PIN);
|
gpio_set(TCK_PORT, TCK_PIN);
|
||||||
|
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
|
||||||
if (gpio_get(TDO_PORT, TDO_PIN)) {
|
if (gpio_get(TDO_PORT, TDO_PIN)) {
|
||||||
res |= index;
|
res |= index;
|
||||||
}
|
}
|
||||||
*DO = res;
|
*DO = res;
|
||||||
gpio_clear(TCK_PORT, TCK_PIN);
|
gpio_clear(TCK_PORT, TCK_PIN);
|
||||||
|
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks)
|
static void jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||||
{
|
{
|
||||||
uint8_t index = 1;
|
uint8_t index = 1;
|
||||||
while(ticks--) {
|
register volatile int32_t cnt;
|
||||||
gpio_set_val(TMS_PORT, TMS_PIN, ticks? 0 : final_tms);
|
if (swd_delay_cnt) {
|
||||||
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
|
while(ticks--) {
|
||||||
gpio_set(TCK_PORT, TCK_PIN);
|
gpio_set_val(TMS_PORT, TMS_PIN, ticks? 0 : final_tms);
|
||||||
if(!(index <<= 1)) {
|
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
|
||||||
index = 1;
|
gpio_set(TCK_PORT, TCK_PIN);
|
||||||
DI++;
|
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
|
||||||
|
if(!(index <<= 1)) {
|
||||||
|
index = 1;
|
||||||
|
DI++;
|
||||||
|
}
|
||||||
|
gpio_clear(TCK_PORT, TCK_PIN);
|
||||||
|
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while(ticks--) {
|
||||||
|
gpio_set_val(TMS_PORT, TMS_PIN, ticks? 0 : final_tms);
|
||||||
|
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
|
||||||
|
gpio_set(TCK_PORT, TCK_PIN);
|
||||||
|
if(!(index <<= 1)) {
|
||||||
|
index = 1;
|
||||||
|
DI++;
|
||||||
|
}
|
||||||
|
gpio_clear(TCK_PORT, TCK_PIN);
|
||||||
}
|
}
|
||||||
gpio_clear(TCK_PORT, TCK_PIN);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,8 @@
|
|||||||
/* This file implements the SW-DP interface. */
|
/* This file implements the SW-DP interface. */
|
||||||
|
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "swdptap.h"
|
#include "timing.h"
|
||||||
|
#include "adiv5.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SWDIO_STATUS_FLOAT = 0,
|
SWDIO_STATUS_FLOAT = 0,
|
||||||
@ -39,6 +40,7 @@ static void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
|||||||
static void swdptap_turnaround(int dir)
|
static void swdptap_turnaround(int dir)
|
||||||
{
|
{
|
||||||
static int olddir = SWDIO_STATUS_FLOAT;
|
static int olddir = SWDIO_STATUS_FLOAT;
|
||||||
|
register volatile int32_t cnt;
|
||||||
|
|
||||||
/* Don't turnaround if direction not changing */
|
/* Don't turnaround if direction not changing */
|
||||||
if(dir == olddir) return;
|
if(dir == olddir) return;
|
||||||
@ -51,10 +53,9 @@ static void swdptap_turnaround(int dir)
|
|||||||
if(dir == SWDIO_STATUS_FLOAT)
|
if(dir == SWDIO_STATUS_FLOAT)
|
||||||
SWDIO_MODE_FLOAT();
|
SWDIO_MODE_FLOAT();
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
for(cnt = swd_delay_cnt; --cnt > 0;);
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
|
||||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||||
|
for(cnt = swd_delay_cnt; --cnt > 0;);
|
||||||
if(dir == SWDIO_STATUS_DRIVE)
|
if(dir == SWDIO_STATUS_DRIVE)
|
||||||
SWDIO_MODE_DRIVE();
|
SWDIO_MODE_DRIVE();
|
||||||
}
|
}
|
||||||
@ -64,21 +65,30 @@ static uint32_t swdptap_seq_in(int ticks)
|
|||||||
uint32_t index = 1;
|
uint32_t index = 1;
|
||||||
uint32_t ret = 0;
|
uint32_t ret = 0;
|
||||||
int len = ticks;
|
int len = ticks;
|
||||||
|
register volatile int32_t cnt;
|
||||||
|
|
||||||
swdptap_turnaround(SWDIO_STATUS_FLOAT);
|
swdptap_turnaround(SWDIO_STATUS_FLOAT);
|
||||||
while (len--) {
|
if (swd_delay_cnt) {
|
||||||
int res;
|
while (len--) {
|
||||||
res = gpio_get(SWDIO_PORT, SWDIO_PIN);
|
int res;
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
res = gpio_get(SWDIO_PORT, SWDIO_PIN);
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
for(cnt = swd_delay_cnt; --cnt > 0;);
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
ret |= (res) ? index : 0;
|
||||||
if (res)
|
index <<= 1;
|
||||||
ret |= index;
|
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||||
index <<= 1;
|
for(cnt = swd_delay_cnt; --cnt > 0;);
|
||||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
}
|
||||||
|
} else {
|
||||||
|
volatile int res;
|
||||||
|
while (len--) {
|
||||||
|
res = gpio_get(SWDIO_PORT, SWDIO_PIN);
|
||||||
|
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||||
|
ret |= (res) ? index : 0;
|
||||||
|
index <<= 1;
|
||||||
|
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_SWD_BITS
|
#ifdef DEBUG_SWD_BITS
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
DEBUG("%d", (ret & (1 << i)) ? 1 : 0);
|
DEBUG("%d", (ret & (1 << i)) ? 1 : 0);
|
||||||
@ -92,31 +102,42 @@ static bool swdptap_seq_in_parity(uint32_t *ret, int ticks)
|
|||||||
uint32_t res = 0;
|
uint32_t res = 0;
|
||||||
bool bit;
|
bool bit;
|
||||||
int len = ticks;
|
int len = ticks;
|
||||||
|
register volatile int32_t cnt;
|
||||||
|
|
||||||
swdptap_turnaround(SWDIO_STATUS_FLOAT);
|
swdptap_turnaround(SWDIO_STATUS_FLOAT);
|
||||||
while (len--) {
|
if (swd_delay_cnt) {
|
||||||
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
|
while (len--) {
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
for(cnt = swd_delay_cnt; --cnt > 0;);
|
||||||
if (bit)
|
res |= (bit) ? index : 0;
|
||||||
res |= index;
|
index <<= 1;
|
||||||
index <<= 1;
|
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
for(cnt = swd_delay_cnt; --cnt > 0;);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (len--) {
|
||||||
|
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
|
||||||
|
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||||
|
res |= (bit) ? index : 0;
|
||||||
|
index <<= 1;
|
||||||
|
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int parity = __builtin_popcount(res);
|
int parity = __builtin_popcount(res);
|
||||||
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
|
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||||
if (bit)
|
for(cnt = swd_delay_cnt; --cnt > 0;);
|
||||||
parity++;
|
parity += (bit) ? 1 : 0;
|
||||||
else
|
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
|
||||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||||
|
for(cnt = swd_delay_cnt; --cnt > 0;);
|
||||||
#ifdef DEBUG_SWD_BITS
|
#ifdef DEBUG_SWD_BITS
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
DEBUG("%d", (res & (1 << i)) ? 1 : 0);
|
DEBUG("%d", (res & (1 << i)) ? 1 : 0);
|
||||||
#endif
|
#endif
|
||||||
*ret = res;
|
*ret = res;
|
||||||
|
/* Terminate the read cycle now */
|
||||||
|
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
||||||
return (parity & 1);
|
return (parity & 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,14 +147,25 @@ static void swdptap_seq_out(uint32_t MS, int ticks)
|
|||||||
for (int i = 0; i < ticks; i++)
|
for (int i = 0; i < ticks; i++)
|
||||||
DEBUG("%d", (MS & (1 << i)) ? 1 : 0);
|
DEBUG("%d", (MS & (1 << i)) ? 1 : 0);
|
||||||
#endif
|
#endif
|
||||||
|
register volatile int32_t cnt;
|
||||||
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
||||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
|
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
|
||||||
while (ticks--) {
|
if (swd_delay_cnt) {
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
while (ticks--) {
|
||||||
MS >>= 1;
|
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
|
for(cnt = swd_delay_cnt; --cnt > 0;);
|
||||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
MS >>= 1;
|
||||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
|
||||||
|
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||||
|
for(cnt = swd_delay_cnt; --cnt > 0;);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (ticks--) {
|
||||||
|
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||||
|
MS >>= 1;
|
||||||
|
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
|
||||||
|
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,30 +176,40 @@ static void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
|||||||
for (int i = 0; i < ticks; i++)
|
for (int i = 0; i < ticks; i++)
|
||||||
DEBUG("%d", (MS & (1 << i)) ? 1 : 0);
|
DEBUG("%d", (MS & (1 << i)) ? 1 : 0);
|
||||||
#endif
|
#endif
|
||||||
|
register volatile int32_t cnt;
|
||||||
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
||||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
|
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
|
||||||
MS >>= 1;
|
MS >>= 1;
|
||||||
while (ticks--) {
|
if (swd_delay_cnt) {
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
while (ticks--) {
|
||||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
|
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||||
MS >>= 1;
|
for(cnt = swd_delay_cnt; --cnt > 0;);
|
||||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
|
||||||
|
MS >>= 1;
|
||||||
|
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||||
|
for(cnt = swd_delay_cnt; --cnt > 0;);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (ticks--) {
|
||||||
|
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||||
|
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
|
||||||
|
MS >>= 1;
|
||||||
|
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, parity & 1);
|
gpio_set_val(SWDIO_PORT, SWDIO_PIN, parity & 1);
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
for(cnt = swd_delay_cnt; --cnt > 0;);
|
||||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
|
||||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||||
|
for(cnt = swd_delay_cnt; --cnt > 0;);
|
||||||
}
|
}
|
||||||
|
|
||||||
swd_proc_t swd_proc;
|
int swdptap_init(ADIv5_DP_t *dp)
|
||||||
|
|
||||||
int swdptap_init(void)
|
|
||||||
{
|
{
|
||||||
swd_proc.swdptap_seq_in = swdptap_seq_in;
|
dp->seq_in = swdptap_seq_in;
|
||||||
swd_proc.swdptap_seq_in_parity = swdptap_seq_in_parity;
|
dp->seq_in_parity = swdptap_seq_in_parity;
|
||||||
swd_proc.swdptap_seq_out = swdptap_seq_out;
|
dp->seq_out = swdptap_seq_out;
|
||||||
swd_proc.swdptap_seq_out_parity = swdptap_seq_out_parity;
|
dp->seq_out_parity = swdptap_seq_out_parity;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,35 @@
|
|||||||
CROSS_COMPILE ?= arm-none-eabi-
|
CROSS_COMPILE ?= arm-none-eabi-
|
||||||
|
BMP_BOOTLOADER ?=
|
||||||
CC = $(CROSS_COMPILE)gcc
|
CC = $(CROSS_COMPILE)gcc
|
||||||
OBJCOPY = $(CROSS_COMPILE)objcopy
|
OBJCOPY = $(CROSS_COMPILE)objcopy
|
||||||
|
|
||||||
CFLAGS += -Istm32/include -mcpu=cortex-m4 -mthumb \
|
CFLAGS += -Istm32/include -mcpu=cortex-m4 -mthumb \
|
||||||
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \
|
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \
|
||||||
-DSTM32F4 -DF4DISCOVERY -I../libopencm3/include \
|
-DSTM32F4 -I../libopencm3/include \
|
||||||
-Iplatforms/stm32
|
-Iplatforms/stm32
|
||||||
|
|
||||||
LDFLAGS = -lopencm3_stm32f4 \
|
ifeq ($(BLACKPILL), 1)
|
||||||
-Wl,-T,platforms/stm32/f4discovery.ld -nostartfiles -lc -lnosys \
|
LINKER_SCRIPT=platforms/stm32/blackpillv2.ld
|
||||||
|
CFLAGS += -DBLACKPILL=1
|
||||||
|
else
|
||||||
|
LINKER_SCRIPT=platforms/stm32/f4discovery.ld
|
||||||
|
endif
|
||||||
|
|
||||||
|
LDFLAGS_BOOT = -lopencm3_stm32f4 \
|
||||||
|
-Wl,-T,$(LINKER_SCRIPT) -nostartfiles -lc -lnosys \
|
||||||
-Wl,-Map=mapfile -mthumb -mcpu=cortex-m4 -Wl,-gc-sections \
|
-Wl,-Map=mapfile -mthumb -mcpu=cortex-m4 -Wl,-gc-sections \
|
||||||
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \
|
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \
|
||||||
-L../libopencm3/lib
|
-L../libopencm3/lib
|
||||||
|
|
||||||
|
ifeq ($(BMP_BOOTLOADER), 1)
|
||||||
|
$(info Load address 0x08004000 for BMPBootloader)
|
||||||
|
LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8004000
|
||||||
|
CFLAGS += -DDFU_SERIAL_LENGTH=9
|
||||||
|
else
|
||||||
|
LDFLAGS += $(LDFLAGS_BOOT)
|
||||||
|
CFLAGS += -DDFU_SERIAL_LENGTH=13
|
||||||
|
endif
|
||||||
|
|
||||||
VPATH += platforms/stm32
|
VPATH += platforms/stm32
|
||||||
|
|
||||||
SRC += cdcacm.c \
|
SRC += cdcacm.c \
|
||||||
@ -23,7 +40,18 @@ SRC += cdcacm.c \
|
|||||||
timing.c \
|
timing.c \
|
||||||
timing_stm32.c \
|
timing_stm32.c \
|
||||||
|
|
||||||
|
ifneq ($(BMP_BOOTLOADER), 1)
|
||||||
all: blackmagic.bin
|
all: blackmagic.bin
|
||||||
|
else
|
||||||
|
all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
|
||||||
|
blackmagic_dfu: usbdfu.o dfucore.o dfu_f4.o serialno.o
|
||||||
|
$(CC) $^ -o $@ $(LDFLAGS_BOOT)
|
||||||
|
|
||||||
|
blackmagic_dfu.bin: blackmagic_dfu
|
||||||
|
$(OBJCOPY) -O binary $^ $@
|
||||||
|
|
||||||
|
blackmagic_dfu.hex: blackmagic_dfu
|
||||||
|
$(OBJCOPY) -O ihex $^ $@
|
||||||
|
endif
|
||||||
host_clean:
|
host_clean:
|
||||||
-$(Q)$(RM) blackmagic.bin
|
-$(Q)$(RM) blackmagic.bin
|
||||||
|
@ -11,3 +11,55 @@ PC6: TDO/TRACESWO<br>
|
|||||||
|
|
||||||
PC1: TRST<br>
|
PC1: TRST<br>
|
||||||
PC8: SRST<br>
|
PC8: SRST<br>
|
||||||
|
|
||||||
|
# Alternate build for stm32f401 stm32f411 MiniF4 aka BlackPillV2 boards.
|
||||||
|
|
||||||
|
https://github.com/WeActTC/MiniSTM32F4x1
|
||||||
|
|
||||||
|
## Connections:
|
||||||
|
|
||||||
|
* JTAG/SWD
|
||||||
|
* PA1: TDI
|
||||||
|
* PA13: TMS/SWDIO
|
||||||
|
* PA14: TCK/SWCLK
|
||||||
|
* PB3: TDO/TRACESWO
|
||||||
|
* PB5: TRST
|
||||||
|
* PB4: SRST
|
||||||
|
|
||||||
|
* USB USART
|
||||||
|
* PB6: USART1 TX (usbuart_xxx)
|
||||||
|
* PB7: USART1 RX (usbuart_xxx)
|
||||||
|
|
||||||
|
* +3V3.
|
||||||
|
* PB8 - turn on IRLML5103 transistor
|
||||||
|
|
||||||
|
How to Build
|
||||||
|
========================================
|
||||||
|
```
|
||||||
|
cd blackmagic
|
||||||
|
make clean
|
||||||
|
make PROBE_HOST=f4discovery BLACKPILL=1
|
||||||
|
```
|
||||||
|
|
||||||
|
How to Flash with dfu
|
||||||
|
========================================
|
||||||
|
* After build:
|
||||||
|
* 1) `apt install dfu-util`
|
||||||
|
* 2) Force the F4 into system bootloader mode by jumpering "BOOT0" to "3V3" and "PB2/BOOT1" to "GND" and reset (RESET button). System bootloader should appear.
|
||||||
|
* 3) `dfu-util -a 0 --dfuse-address 0x08000000 -D blackmagic.bin`
|
||||||
|
|
||||||
|
To exit from dfu mode press a "key" and "reset", release reset. BMP firmware should appear
|
||||||
|
|
||||||
|
|
||||||
|
10 pin male from pins
|
||||||
|
========================================
|
||||||
|
|
||||||
|
| PB3/TDO | PB7/RX | PB6/TX | X | PA1/TDI |
|
||||||
|
| -------- | ----------- | ---------- | ---------- | ------- |
|
||||||
|
| PB4/SRST | +3V3/PB8 SW | PA13/SWDIO | PA14/SWCLK | GND |
|
||||||
|
|
||||||
|
SWJ frequency setting
|
||||||
|
====================================
|
||||||
|
https://github.com/blackmagic-debug/blackmagic/pull/783#issue-529197718
|
||||||
|
|
||||||
|
`mon freq 900k` helps at most
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
#include "usbuart.h"
|
#include "usbuart.h"
|
||||||
#include "morse.h"
|
#include "morse.h"
|
||||||
|
|
||||||
#include <libopencm3/stm32/f4/rcc.h>
|
#include <libopencm3/stm32/rcc.h>
|
||||||
#include <libopencm3/cm3/scb.h>
|
#include <libopencm3/cm3/scb.h>
|
||||||
#include <libopencm3/cm3/nvic.h>
|
#include <libopencm3/cm3/nvic.h>
|
||||||
#include <libopencm3/stm32/exti.h>
|
#include <libopencm3/stm32/exti.h>
|
||||||
@ -37,20 +37,32 @@
|
|||||||
#include <libopencm3/cm3/systick.h>
|
#include <libopencm3/cm3/systick.h>
|
||||||
#include <libopencm3/cm3/cortex.h>
|
#include <libopencm3/cm3/cortex.h>
|
||||||
|
|
||||||
|
#ifdef BLACKPILL
|
||||||
|
#include <libopencm3/usb/dwc/otg_fs.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
jmp_buf fatal_error_jmpbuf;
|
jmp_buf fatal_error_jmpbuf;
|
||||||
extern char _ebss[];
|
extern char _ebss[];
|
||||||
|
|
||||||
void platform_init(void)
|
void platform_init(void)
|
||||||
{
|
{
|
||||||
volatile uint32_t *magic = (uint32_t *)_ebss;
|
volatile uint32_t *magic = (uint32_t *)_ebss;
|
||||||
/* Check the USER button*/
|
/* Enable GPIO peripherals */
|
||||||
rcc_periph_clock_enable(RCC_GPIOA);
|
rcc_periph_clock_enable(RCC_GPIOA);
|
||||||
|
rcc_periph_clock_enable(RCC_GPIOC);
|
||||||
|
#ifdef BLACKPILL
|
||||||
|
rcc_periph_clock_enable(RCC_GPIOB);
|
||||||
|
#else
|
||||||
|
rcc_periph_clock_enable(RCC_GPIOD);
|
||||||
|
#endif
|
||||||
|
/* Check the USER button*/
|
||||||
if (gpio_get(GPIOA, GPIO0) ||
|
if (gpio_get(GPIOA, GPIO0) ||
|
||||||
((magic[0] == BOOTMAGIC0) && (magic[1] == BOOTMAGIC1))) {
|
((magic[0] == BOOTMAGIC0) && (magic[1] == BOOTMAGIC1)))
|
||||||
|
{
|
||||||
magic[0] = 0;
|
magic[0] = 0;
|
||||||
magic[1] = 0;
|
magic[1] = 0;
|
||||||
/* Assert blue LED as indicator we are in the bootloader */
|
/* Assert blue LED as indicator we are in the bootloader */
|
||||||
rcc_periph_clock_enable(RCC_GPIOD);
|
|
||||||
gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT,
|
gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT,
|
||||||
GPIO_PUPD_NONE, LED_BOOTLOADER);
|
GPIO_PUPD_NONE, LED_BOOTLOADER);
|
||||||
gpio_set(LED_PORT, LED_BOOTLOADER);
|
gpio_set(LED_PORT, LED_BOOTLOADER);
|
||||||
@ -58,41 +70,65 @@ void platform_init(void)
|
|||||||
As we just come out of reset, no other deinit is needed!*/
|
As we just come out of reset, no other deinit is needed!*/
|
||||||
rcc_periph_clock_enable(RCC_SYSCFG);
|
rcc_periph_clock_enable(RCC_SYSCFG);
|
||||||
SYSCFG_MEMRM &= ~3;
|
SYSCFG_MEMRM &= ~3;
|
||||||
SYSCFG_MEMRM |= 1;
|
SYSCFG_MEMRM |= 1;
|
||||||
scb_reset_core();
|
scb_reset_core();
|
||||||
}
|
}
|
||||||
|
#ifdef BLACKPILL
|
||||||
|
rcc_clock_setup_pll(&rcc_hse_25mhz_3v3[RCC_CLOCK_3V3_84MHZ]);
|
||||||
|
#else
|
||||||
rcc_clock_setup_pll(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]);
|
rcc_clock_setup_pll(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Enable peripherals */
|
/* Enable peripherals */
|
||||||
rcc_periph_clock_enable(RCC_OTGFS);
|
rcc_periph_clock_enable(RCC_OTGFS);
|
||||||
rcc_periph_clock_enable(RCC_GPIOC);
|
|
||||||
rcc_periph_clock_enable(RCC_GPIOD);
|
|
||||||
rcc_periph_clock_enable(RCC_CRC);
|
rcc_periph_clock_enable(RCC_CRC);
|
||||||
|
|
||||||
/* Set up USB Pins and alternate function*/
|
/* Set up USB Pins and alternate function*/
|
||||||
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12);
|
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9 | GPIO11 | GPIO12);
|
||||||
gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12);
|
gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO10 | GPIO11 | GPIO12);
|
||||||
|
|
||||||
GPIOC_OSPEEDR &=~0xF30;
|
#ifdef BLACKPILL
|
||||||
|
GPIOA_OSPEEDR &= 0x3C00000C;
|
||||||
|
GPIOA_OSPEEDR |= 0x28000008;
|
||||||
|
#else
|
||||||
|
GPIOC_OSPEEDR &= ~0xF30;
|
||||||
GPIOC_OSPEEDR |= 0xA20;
|
GPIOC_OSPEEDR |= 0xA20;
|
||||||
gpio_mode_setup(JTAG_PORT, GPIO_MODE_OUTPUT,
|
#endif
|
||||||
GPIO_PUPD_NONE,
|
|
||||||
TCK_PIN | TDI_PIN);
|
|
||||||
gpio_mode_setup(JTAG_PORT, GPIO_MODE_INPUT,
|
|
||||||
GPIO_PUPD_NONE, TMS_PIN);
|
|
||||||
|
|
||||||
|
gpio_mode_setup(JTAG_PORT, GPIO_MODE_OUTPUT,
|
||||||
|
GPIO_PUPD_NONE,
|
||||||
|
TCK_PIN | TDI_PIN);
|
||||||
|
gpio_mode_setup(JTAG_PORT, GPIO_MODE_INPUT,
|
||||||
|
GPIO_PUPD_NONE, TMS_PIN);
|
||||||
|
gpio_set_output_options(JTAG_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ,
|
||||||
|
TCK_PIN | TDI_PIN | TMS_PIN);
|
||||||
gpio_mode_setup(TDO_PORT, GPIO_MODE_INPUT,
|
gpio_mode_setup(TDO_PORT, GPIO_MODE_INPUT,
|
||||||
GPIO_PUPD_NONE,
|
GPIO_PUPD_NONE,
|
||||||
TDO_PIN);
|
TDO_PIN);
|
||||||
|
gpio_set_output_options(TDO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ,
|
||||||
|
TDO_PIN | TMS_PIN);
|
||||||
|
|
||||||
gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT,
|
gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT,
|
||||||
GPIO_PUPD_NONE,
|
GPIO_PUPD_NONE,
|
||||||
LED_UART | LED_IDLE_RUN | LED_ERROR | LED_BOOTLOADER);
|
LED_IDLE_RUN | LED_ERROR | LED_BOOTLOADER);
|
||||||
|
|
||||||
|
gpio_mode_setup(LED_PORT_UART, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_UART);
|
||||||
|
|
||||||
|
#ifdef PLATFORM_HAS_POWER_SWITCH
|
||||||
|
gpio_set(PWR_BR_PORT, PWR_BR_PIN);
|
||||||
|
gpio_mode_setup(PWR_BR_PORT, GPIO_MODE_OUTPUT,
|
||||||
|
GPIO_PUPD_NONE,
|
||||||
|
PWR_BR_PIN);
|
||||||
|
#endif
|
||||||
|
|
||||||
platform_timing_init();
|
platform_timing_init();
|
||||||
usbuart_init();
|
usbuart_init();
|
||||||
cdcacm_init();
|
cdcacm_init();
|
||||||
|
#ifdef BLACKPILL
|
||||||
|
// https://github.com/libopencm3/libopencm3/pull/1256#issuecomment-779424001
|
||||||
|
OTG_FS_GCCFG |= OTG_GCCFG_NOVBUSSENS | OTG_GCCFG_PWRDWN;
|
||||||
|
OTG_FS_GCCFG &= ~(OTG_GCCFG_VBUSBSEN | OTG_GCCFG_VBUSASEN);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void platform_srst_set_val(bool assert) { (void)assert; }
|
void platform_srst_set_val(bool assert) { (void)assert; }
|
||||||
@ -105,8 +141,20 @@ const char *platform_target_voltage(void)
|
|||||||
|
|
||||||
void platform_request_boot(void)
|
void platform_request_boot(void)
|
||||||
{
|
{
|
||||||
uint32_t *magic = (uint32_t *) &_ebss;
|
uint32_t *magic = (uint32_t *)&_ebss;
|
||||||
magic[0] = BOOTMAGIC0;
|
magic[0] = BOOTMAGIC0;
|
||||||
magic[1] = BOOTMAGIC1;
|
magic[1] = BOOTMAGIC1;
|
||||||
scb_reset_system();
|
scb_reset_system();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef PLATFORM_HAS_POWER_SWITCH
|
||||||
|
bool platform_target_get_power(void)
|
||||||
|
{
|
||||||
|
return !gpio_get(PWR_BR_PORT, PWR_BR_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void platform_target_set_power(bool power)
|
||||||
|
{
|
||||||
|
gpio_set_val(PWR_BR_PORT, PWR_BR_PIN, !power);
|
||||||
|
}
|
||||||
|
#endif
|
@ -27,13 +27,80 @@
|
|||||||
#include "gpio.h"
|
#include "gpio.h"
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
#include "timing_stm32.h"
|
#include "timing_stm32.h"
|
||||||
#include "version.h"
|
|
||||||
|
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
|
||||||
#define PLATFORM_HAS_TRACESWO
|
#define PLATFORM_HAS_TRACESWO
|
||||||
#define BOARD_IDENT "Black Magic Probe (F4Discovery), (Firmware " FIRMWARE_VERSION ")"
|
#ifdef BLACKPILL
|
||||||
#define DFU_IDENT "Black Magic Firmware Upgrade (F4Discovery)"
|
#define PLATFORM_IDENT "(F4Discovery/BlackPillV2) "
|
||||||
|
/* Important pin mappings for STM32 implementation:
|
||||||
|
* JTAG/SWD
|
||||||
|
* PA1: TDI<br>
|
||||||
|
* PA13: TMS/SWDIO<br>
|
||||||
|
* PA14: TCK/SWCLK<br>
|
||||||
|
* PB3: TDO/TRACESWO<br>
|
||||||
|
* PB5: TRST<br>
|
||||||
|
* PB4: SRST<br>
|
||||||
|
* USB USART
|
||||||
|
* PB6: USART1 TX
|
||||||
|
* PB7: USART1 RX
|
||||||
|
* +3V3
|
||||||
|
* PB8 - turn on IRLML5103 transistor
|
||||||
|
* Force DFU mode button: PA0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Hardware definitions... */
|
||||||
|
#define JTAG_PORT GPIOA
|
||||||
|
#define TDI_PORT JTAG_PORT
|
||||||
|
#define TMS_PORT JTAG_PORT
|
||||||
|
#define TCK_PORT JTAG_PORT
|
||||||
|
#define TDO_PORT GPIOB
|
||||||
|
#define TDI_PIN GPIO1
|
||||||
|
#define TMS_PIN GPIO13
|
||||||
|
#define TCK_PIN GPIO14
|
||||||
|
#define TDO_PIN GPIO3
|
||||||
|
|
||||||
|
#define SWDIO_PORT JTAG_PORT
|
||||||
|
#define SWCLK_PORT JTAG_PORT
|
||||||
|
#define SWDIO_PIN TMS_PIN
|
||||||
|
#define SWCLK_PIN TCK_PIN
|
||||||
|
|
||||||
|
#define TRST_PORT GPIOB
|
||||||
|
#define TRST_PIN GPIO5
|
||||||
|
#define SRST_PORT GPIOB
|
||||||
|
#define SRST_PIN GPIO4
|
||||||
|
|
||||||
|
#define PWR_BR_PORT GPIOB
|
||||||
|
#define PWR_BR_PIN GPIO8
|
||||||
|
|
||||||
|
#define LED_PORT GPIOC
|
||||||
|
#define LED_PORT_UART GPIOA
|
||||||
|
#define LED_UART GPIO1
|
||||||
|
#define LED_IDLE_RUN GPIO15
|
||||||
|
#define LED_ERROR GPIO14
|
||||||
|
#define LED_BOOTLOADER GPIO13
|
||||||
|
|
||||||
|
#define USBUSART USART1
|
||||||
|
#define USBUSART_CR1 USART1_CR1
|
||||||
|
#define USBUSART_DR USART1_DR
|
||||||
|
#define USBUSART_IRQ NVIC_USART1_IRQ
|
||||||
|
#define USBUSART_CLK RCC_USART1
|
||||||
|
#define USBUSART_PORT GPIOB
|
||||||
|
#define USBUSART_TX_PIN GPIO6
|
||||||
|
#define USBUSART_RX_PIN GPIO7
|
||||||
|
#define USBUSART_ISR(x) usart1_isr(x)
|
||||||
|
#define USBUSART_DMA_BUS DMA2
|
||||||
|
#define USBUSART_DMA_CLK RCC_DMA2
|
||||||
|
#define USBUSART_DMA_TX_CHAN DMA_STREAM7
|
||||||
|
#define USBUSART_DMA_TX_IRQ NVIC_DMA2_STREAM7_IRQ
|
||||||
|
#define USBUSART_DMA_TX_ISR(x) dma2_stream7_isr(x)
|
||||||
|
#define USBUSART_DMA_RX_CHAN DMA_STREAM5
|
||||||
|
#define USBUSART_DMA_RX_IRQ NVIC_DMA2_STREAM5_IRQ
|
||||||
|
#define USBUSART_DMA_RX_ISR(x) dma2_stream5_isr(x)
|
||||||
|
/* For STM32F4 DMA trigger source must be specified */
|
||||||
|
#define USBUSART_DMA_TRG DMA_SxCR_CHSEL_4
|
||||||
|
#else
|
||||||
|
#define PLATFORM_IDENT "(F4Discovery) "
|
||||||
|
|
||||||
/* Important pin mappings for STM32 implementation:
|
/* Important pin mappings for STM32 implementation:
|
||||||
*
|
*
|
||||||
@ -80,6 +147,28 @@
|
|||||||
#define LED_IDLE_RUN GPIO13
|
#define LED_IDLE_RUN GPIO13
|
||||||
#define LED_ERROR GPIO14
|
#define LED_ERROR GPIO14
|
||||||
#define LED_BOOTLOADER GPIO15
|
#define LED_BOOTLOADER GPIO15
|
||||||
|
|
||||||
|
#define USBUSART USART3
|
||||||
|
#define USBUSART_CR1 USART3_CR1
|
||||||
|
#define USBUSART_DR USART3_DR
|
||||||
|
#define USBUSART_IRQ NVIC_USART3_IRQ
|
||||||
|
#define USBUSART_CLK RCC_USART3
|
||||||
|
#define USBUSART_PORT GPIOD
|
||||||
|
#define USBUSART_TX_PIN GPIO8
|
||||||
|
#define USBUSART_RX_PIN GPIO9
|
||||||
|
#define USBUSART_ISR(x) usart3_isr(x)
|
||||||
|
#define USBUSART_DMA_BUS DMA1
|
||||||
|
#define USBUSART_DMA_CLK RCC_DMA1
|
||||||
|
#define USBUSART_DMA_TX_CHAN DMA_STREAM3
|
||||||
|
#define USBUSART_DMA_TX_IRQ NVIC_DMA1_STREAM3_IRQ
|
||||||
|
#define USBUSART_DMA_TX_ISR(x) dma1_stream3_isr(x)
|
||||||
|
#define USBUSART_DMA_RX_CHAN DMA_STREAM1
|
||||||
|
#define USBUSART_DMA_RX_IRQ NVIC_DMA1_STREAM1_IRQ
|
||||||
|
#define USBUSART_DMA_RX_ISR(x) dma1_stream1_isr(x)
|
||||||
|
/* For STM32F4 DMA trigger source must be specified */
|
||||||
|
#define USBUSART_DMA_TRG DMA_SxCR_CHSEL_4
|
||||||
|
#endif
|
||||||
|
|
||||||
#define BOOTMAGIC0 0xb007da7a
|
#define BOOTMAGIC0 0xb007da7a
|
||||||
#define BOOTMAGIC1 0xbaadfeed
|
#define BOOTMAGIC1 0xbaadfeed
|
||||||
|
|
||||||
@ -93,47 +182,35 @@
|
|||||||
#define SWDIO_MODE_DRIVE() \
|
#define SWDIO_MODE_DRIVE() \
|
||||||
gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, \
|
gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, \
|
||||||
GPIO_PUPD_NONE, SWDIO_PIN);
|
GPIO_PUPD_NONE, SWDIO_PIN);
|
||||||
|
#define UART_PIN_SETUP() do { \
|
||||||
|
gpio_mode_setup(USBUSART_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
|
||||||
|
USBUSART_TX_PIN); \
|
||||||
|
gpio_set_output_options(USBUSART_PORT, GPIO_OTYPE_PP, \
|
||||||
|
GPIO_OSPEED_100MHZ, USBUSART_TX_PIN); \
|
||||||
|
gpio_set_af(USBUSART_PORT, GPIO_AF7, USBUSART_TX_PIN); \
|
||||||
|
gpio_mode_setup(USBUSART_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, \
|
||||||
|
USBUSART_RX_PIN); \
|
||||||
|
gpio_set_output_options(USBUSART_PORT, GPIO_OTYPE_OD, \
|
||||||
|
GPIO_OSPEED_100MHZ, USBUSART_RX_PIN); \
|
||||||
|
gpio_set_af(USBUSART_PORT, GPIO_AF7, USBUSART_RX_PIN); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#define USB_DRIVER stm32f107_usb_driver
|
#define USB_DRIVER stm32f107_usb_driver
|
||||||
#define USB_IRQ NVIC_OTG_FS_IRQ
|
#define USB_IRQ NVIC_OTG_FS_IRQ
|
||||||
#define USB_ISR otg_fs_isr
|
#define USB_ISR(x) otg_fs_isr(x)
|
||||||
/* Interrupt priorities. Low numbers are high priority.
|
/* Interrupt priorities. Low numbers are high priority.
|
||||||
* For now USART1 preempts USB which may spin while buffer is drained.
|
|
||||||
* TIM3 is used for traceswo capture and must be highest priority.
|
* TIM3 is used for traceswo capture and must be highest priority.
|
||||||
*/
|
*/
|
||||||
#define IRQ_PRI_USB (2 << 4)
|
#define IRQ_PRI_USB (1 << 4)
|
||||||
#define IRQ_PRI_USBUSART (1 << 4)
|
#define IRQ_PRI_USBUSART (2 << 4)
|
||||||
#define IRQ_PRI_USBUSART_TIM (3 << 4)
|
#define IRQ_PRI_USBUSART_DMA (2 << 4)
|
||||||
#define IRQ_PRI_TRACE (0 << 4)
|
#define IRQ_PRI_TRACE (0 << 4)
|
||||||
|
|
||||||
#define USBUSART USART3
|
|
||||||
#define USBUSART_CR1 USART3_CR1
|
|
||||||
#define USBUSART_IRQ NVIC_USART3_IRQ
|
|
||||||
#define USBUSART_CLK RCC_USART3
|
|
||||||
#define USBUSART_TX_PORT GPIOD
|
|
||||||
#define USBUSART_TX_PIN GPIO8
|
|
||||||
#define USBUSART_RX_PORT GPIOD
|
|
||||||
#define USBUSART_RX_PIN GPIO9
|
|
||||||
#define USBUSART_ISR usart3_isr
|
|
||||||
#define USBUSART_TIM TIM4
|
|
||||||
#define USBUSART_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM4)
|
|
||||||
#define USBUSART_TIM_IRQ NVIC_TIM4_IRQ
|
|
||||||
#define USBUSART_TIM_ISR tim4_isr
|
|
||||||
|
|
||||||
#define UART_PIN_SETUP() do { \
|
|
||||||
gpio_mode_setup(USBUSART_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
|
|
||||||
USBUSART_TX_PIN); \
|
|
||||||
gpio_mode_setup(USBUSART_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
|
|
||||||
USBUSART_RX_PIN); \
|
|
||||||
gpio_set_af(USBUSART_TX_PORT, GPIO_AF7, USBUSART_TX_PIN); \
|
|
||||||
gpio_set_af(USBUSART_RX_PORT, GPIO_AF7, USBUSART_RX_PIN); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define TRACE_TIM TIM3
|
#define TRACE_TIM TIM3
|
||||||
#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3)
|
#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3)
|
||||||
#define TRACE_IRQ NVIC_TIM3_IRQ
|
#define TRACE_IRQ NVIC_TIM3_IRQ
|
||||||
#define TRACE_ISR tim3_isr
|
#define TRACE_ISR(x) tim3_isr(x)
|
||||||
|
|
||||||
#define gpio_set_val(port, pin, val) do { \
|
#define gpio_set_val(port, pin, val) do { \
|
||||||
if(val) \
|
if(val) \
|
||||||
|
@ -27,59 +27,47 @@
|
|||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
uint32_t app_address = 0x08000000;
|
uint32_t app_address = 0x08004000;
|
||||||
static uint16_t led_upgrade;
|
extern char _ebss[];
|
||||||
static uint32_t led2_state = 0;
|
|
||||||
extern uint32_t _stack;
|
|
||||||
static uint32_t rev;
|
|
||||||
|
|
||||||
void dfu_detach(void)
|
void dfu_detach(void)
|
||||||
{
|
{
|
||||||
platform_request_boot();
|
scb_reset_system();
|
||||||
scb_reset_core();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
rev = detect_rev();
|
volatile uint32_t *magic = (uint32_t *)_ebss;
|
||||||
rcc_clock_setup_in_hse_8mhz_out_72mhz();
|
rcc_periph_clock_enable(RCC_GPIOA);
|
||||||
if (rev == 0)
|
if (gpio_get(GPIOA, GPIO0) ||
|
||||||
led_upgrade = GPIO8;
|
((magic[0] == BOOTMAGIC0) && (magic[1] == BOOTMAGIC1))) {
|
||||||
else
|
magic[0] = 0;
|
||||||
led_upgrade = GPIO9;
|
magic[1] = 0;
|
||||||
|
} else {
|
||||||
|
dfu_jump_app_if_valid();
|
||||||
|
}
|
||||||
|
rcc_clock_setup_pll(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]);
|
||||||
|
|
||||||
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
|
/* Assert blue LED as indicator we are in the bootloader */
|
||||||
systick_set_reload(900000);
|
rcc_periph_clock_enable(RCC_GPIOD);
|
||||||
|
gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT,
|
||||||
|
GPIO_PUPD_NONE, LED_BOOTLOADER);
|
||||||
|
gpio_set(LED_PORT, LED_BOOTLOADER);
|
||||||
|
|
||||||
dfu_protect(UPD_MODE);
|
/* Enable peripherals */
|
||||||
|
rcc_periph_clock_enable(RCC_OTGFS);
|
||||||
|
|
||||||
systick_interrupt_enable();
|
/* Set up USB Pins and alternate function*/
|
||||||
systick_counter_enable();
|
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12);
|
||||||
|
gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12);
|
||||||
if (rev > 1) /* Reconnect USB */
|
|
||||||
gpio_set(GPIOA, GPIO15);
|
|
||||||
dfu_init(&st_usbfs_v1_usb_driver, UPD_MODE);
|
|
||||||
|
|
||||||
|
dfu_protect(false);
|
||||||
|
dfu_init(&USB_DRIVER);
|
||||||
dfu_main();
|
dfu_main();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dfu_event(void)
|
void dfu_event(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_tick_handler(void)
|
|
||||||
{
|
|
||||||
if (rev == 0) {
|
|
||||||
gpio_toggle(GPIOA, led_upgrade);
|
|
||||||
} else {
|
|
||||||
if (led2_state & 1) {
|
|
||||||
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
|
|
||||||
GPIO_CNF_OUTPUT_PUSHPULL, led_upgrade);
|
|
||||||
gpio_set(GPIOA, led_upgrade);
|
|
||||||
} else {
|
|
||||||
gpio_set_mode(GPIOA, GPIO_MODE_INPUT,
|
|
||||||
GPIO_CNF_INPUT_ANALOG, led_upgrade);
|
|
||||||
}
|
|
||||||
led2_state++;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +1,39 @@
|
|||||||
|
CC ?= gcc
|
||||||
SYS = $(shell $(CC) -dumpmachine)
|
SYS = $(shell $(CC) -dumpmachine)
|
||||||
CFLAGS += -DENABLE_DEBUG -DPLATFORM_HAS_DEBUG
|
CFLAGS += -DENABLE_DEBUG -DPLATFORM_HAS_DEBUG
|
||||||
CFLAGS +=-I ./target -I./platforms/pc
|
CFLAGS +=-I ./target -I./platforms/pc
|
||||||
|
|
||||||
|
# Define HOSTED_BMP_ONLY to '0' in order to build the hosted blackmagic
|
||||||
|
# executable with support for other probes beside BMP. Default HOSTED_BMP_ONLY
|
||||||
|
# == 1 on Windows makes linking against the libftdi and libusb libraries
|
||||||
|
# unnecessary.
|
||||||
|
# This can be useful to minimize external dependencies, and make building on
|
||||||
|
# windows systems easier and is default now.
|
||||||
|
ifneq (, $(findstring linux, $(SYS)))
|
||||||
|
HOSTED_BMP_ONLY ?= 0
|
||||||
|
else
|
||||||
|
HOSTED_BMP_ONLY ?= 1
|
||||||
|
endif
|
||||||
|
CFLAGS += -DHOSTED_BMP_ONLY=$(HOSTED_BMP_ONLY)
|
||||||
|
|
||||||
ifneq (, $(findstring linux, $(SYS)))
|
ifneq (, $(findstring linux, $(SYS)))
|
||||||
SRC += serial_unix.c
|
SRC += serial_unix.c
|
||||||
|
HIDAPILIB = hidapi-hidraw
|
||||||
ifeq ($(ASAN), 1)
|
ifeq ($(ASAN), 1)
|
||||||
CFLAGS += -fsanitize=address
|
CFLAGS += -fsanitize=address -Wno-format-truncation
|
||||||
LDFLAGS += -lasan
|
LDFLAGS += -lasan
|
||||||
endif
|
endif
|
||||||
else ifneq (, $(findstring mingw, $(SYS)))
|
else ifneq (, $(findstring mingw, $(SYS)))
|
||||||
|
# Build for windows versions Vista, and above, where the
|
||||||
|
# 'SetupDiGetDevicePropertyW()' function is available
|
||||||
|
CFLAGS += -D_WIN32_WINNT=0x600
|
||||||
SRC += serial_win.c
|
SRC += serial_win.c
|
||||||
LDFLAGS += -lws2_32
|
LDFLAGS += -lws2_32
|
||||||
LDFLAGS += -lsetupapi
|
LDFLAGS += -lsetupapi
|
||||||
else ifneq (, $(findstring cygwin, $(SYS)))
|
else ifneq (, $(findstring cygwin, $(SYS)))
|
||||||
|
# Build for windows versions Vista, and above, where the
|
||||||
|
# 'SetupDiGetDevicePropertyW()' function is available
|
||||||
|
CFLAGS += -D_WIN32_WINNT=0x600
|
||||||
SRC += serial_win.c
|
SRC += serial_win.c
|
||||||
LDFLAGS += -lws2_32
|
LDFLAGS += -lws2_32
|
||||||
LDFLAGS += -lsetupapi
|
LDFLAGS += -lsetupapi
|
||||||
@ -22,29 +43,43 @@ SRC += serial_unix.c
|
|||||||
LDFLAGS += -lhidapi
|
LDFLAGS += -lhidapi
|
||||||
LDFLAGS += -framework CoreFoundation
|
LDFLAGS += -framework CoreFoundation
|
||||||
CFLAGS += -Ihidapi/hidapi
|
CFLAGS += -Ihidapi/hidapi
|
||||||
|
HIDAPILIB = hidapi
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LDFLAGS += -lusb-1.0
|
ifneq ($(HOSTED_BMP_ONLY), 1)
|
||||||
CFLAGS += $(shell pkg-config --cflags libftdi1)
|
$(shell pkg-config --exists libftdi1)
|
||||||
LDFLAGS += $(shell pkg-config --libs libftdi1)
|
ifneq ($(.SHELLSTATUS), 0)
|
||||||
CFLAGS += -Wno-missing-field-initializers
|
$(error Please install libftdi1 dependency or set HOSTED_BMP_ONLY to 1)
|
||||||
|
endif
|
||||||
|
LDFLAGS += -lusb-1.0
|
||||||
|
CFLAGS += $(shell pkg-config --cflags libftdi1)
|
||||||
|
LDFLAGS += $(shell pkg-config --libs libftdi1)
|
||||||
|
CFLAGS += -Wno-missing-field-initializers
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq (, $(findstring mingw, $(SYS)))
|
ifneq ($(HOSTED_BMP_ONLY), 1)
|
||||||
SRC += cmsis_dap.c dap.c hid.c
|
|
||||||
CFLAGS += -DCMSIS_DAP
|
CFLAGS += -DCMSIS_DAP
|
||||||
else
|
SRC += cmsis_dap.c dap.c
|
||||||
ifeq ($(shell pkg-config --exists hidapi-libusb && echo 0), 0)
|
ifneq (, $(findstring mingw, $(SYS)))
|
||||||
CFLAGS += $(shell pkg-config --cflags hidapi-libusb)
|
SRC += hid.c
|
||||||
LDFLAGS += $(shell pkg-config --libs hidapi-libusb)
|
else
|
||||||
CFLAGS += -DCMSIS_DAP
|
$(shell pkg-config --exists $(HIDAPILIB))
|
||||||
SRC += cmsis_dap.c dap.c
|
ifneq ($(.SHELLSTATUS), 0)
|
||||||
|
$(error Please install $(HIDAPILIB) dependency or set HOSTED_BMP_ONLY to 1)
|
||||||
|
endif
|
||||||
|
CFLAGS += $(shell pkg-config --cflags $(HIDAPILIB))
|
||||||
|
LDFLAGS += $(shell pkg-config --libs $(HIDAPILIB))
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
VPATH += platforms/pc
|
VPATH += platforms/pc
|
||||||
SRC += timing.c cl_utils.c utils.c libusb_utils.c
|
SRC += timing.c cl_utils.c utils.c
|
||||||
SRC += stlinkv2.c
|
|
||||||
SRC += bmp_remote.c remote_swdptap.c remote_jtagtap.c
|
SRC += bmp_remote.c remote_swdptap.c remote_jtagtap.c
|
||||||
|
ifneq ($(HOSTED_BMP_ONLY), 1)
|
||||||
|
SRC += bmp_libusb.c stlinkv2.c
|
||||||
SRC += ftdi_bmp.c libftdi_swdptap.c libftdi_jtagtap.c
|
SRC += ftdi_bmp.c libftdi_swdptap.c libftdi_jtagtap.c
|
||||||
SRC += jlink.c jlink_adiv5_swdp.c jlink_jtagtap.c
|
SRC += jlink.c jlink_adiv5_swdp.c jlink_jtagtap.c
|
||||||
|
else
|
||||||
|
SRC += bmp_serial.c
|
||||||
|
endif
|
||||||
PC_HOSTED = 1
|
PC_HOSTED = 1
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# PC-Hosted BMP
|
# PC-Hosted BMP
|
||||||
Compile in src with "make PROBE_HOST=hosted"
|
Compile in src with "make PROBE_HOST=hosted". This needs minimal external
|
||||||
|
support. "make PROBE_HOST=hosted HOSTED_BMP_ONLY=0" will compile support for FTDI,
|
||||||
|
STLink, CMSIS-DAP and JLINK probes, but requires external libraries.
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
PC-hosted BMP run on the PC and compiles as "blackmagic". When started,
|
PC-hosted BMP run on the PC and compiles as "blackmagic". When started,
|
||||||
@ -8,7 +10,7 @@ if either only one probe is attached to the PC or enough information is
|
|||||||
given on the command line to select one of several probes.
|
given on the command line to select one of several probes.
|
||||||
|
|
||||||
When started without any other argument beside the probe selection, a
|
When started without any other argument beside the probe selection, a
|
||||||
GDB server is started as port 2000 and up. Connect to the server as you would
|
GDB server is started on port 2000 and up. Connect to the server as you would
|
||||||
connect to the BMP with the CDCACM GDB serial server. GDB functionality
|
connect to the BMP with the CDCACM GDB serial server. GDB functionality
|
||||||
is the same, monitor option may vary.
|
is the same, monitor option may vary.
|
||||||
|
|
||||||
@ -36,23 +38,51 @@ blackmagic -V <file>.bin
|
|||||||
```
|
```
|
||||||
### Show more options
|
### Show more options
|
||||||
```
|
```
|
||||||
blackmagic -h"
|
blackmagic -h
|
||||||
```
|
```
|
||||||
## Used libraries:
|
### Show available monitor commands
|
||||||
|
```
|
||||||
|
blackmagic -M help
|
||||||
|
```
|
||||||
|
### Show available monitor commands on second target
|
||||||
|
```
|
||||||
|
blackmagic -n 2 -M help
|
||||||
|
```
|
||||||
|
### Monitor commands with multiple arguments, e.g.Stm32F1:
|
||||||
|
```
|
||||||
|
blackmagic -M "option help"
|
||||||
|
```
|
||||||
|
## Used shared libraries:
|
||||||
### libusb
|
### libusb
|
||||||
### libftdi, for FTDI support
|
### libftdi, for FTDI support
|
||||||
|
|
||||||
|
## Other used libraries:
|
||||||
### hidapi-libusb, for CMSIS-DAP support
|
### hidapi-libusb, for CMSIS-DAP support
|
||||||
|
|
||||||
## Compiling on windows
|
## Compiling on windows
|
||||||
|
|
||||||
You can crosscompile blackmagic for windows with mingw or on windows
|
You can crosscompile blackmagic for windows with mingw or on windows
|
||||||
with cygwin. For compilation, headers for libftdi1 and libusb-1.0 are
|
with cygwin. For suppport of other probes beside BMP, headers for libftdi1 and
|
||||||
needed. For running, libftdi1.dll and libusb-1.0.dll are needed and
|
libusb-1.0 are needed. For running, libftdi1.dll and libusb-1.0.dll are needed
|
||||||
the executable must be able to find them. Mingw on cygwin does not provide
|
and the executable must be able to find them. Mingw on cygwin does not provide
|
||||||
a libftdi package yet.
|
a libftdi package yet.
|
||||||
|
|
||||||
To prepare libusb access to the ftdi device, run zadig https://zadig.akeo.ie/.
|
PC-hosted BMP for windows can also be built with [MSYS2](https://www.msys2.org/),
|
||||||
Choose WinUSB(libusb-1.0) for the BMP Ftdi device.
|
in windows. Make sure to use the `mingw64` shell from msys2, otherwise,
|
||||||
|
you may get compilation errors. You will need to install the libusb
|
||||||
|
and libftdi libraries, and have the correct mingw compiler.
|
||||||
|
You can use these commands to install dependencies, and build PC-hosted BMP
|
||||||
|
from a mingw64 shell, from within the `src` directory:
|
||||||
|
```
|
||||||
|
pacman -S mingw-w64-x86_64-libusb --needed
|
||||||
|
pacman -S mingw-w64-x86_64-libftdi --needed
|
||||||
|
pacman -S mingw-w64-x86_64-gcc --needed
|
||||||
|
PROBE_HOST=hosted make
|
||||||
|
```
|
||||||
|
|
||||||
|
For suppport of other probes beside BMP, libusb access is needed. To prepare
|
||||||
|
libusb access to the ftdi/stlink/jlink/cmsis-dap devices, run zadig
|
||||||
|
https://zadig.akeo.ie/. Choose WinUSB(libusb-1.0).
|
||||||
|
|
||||||
Running cygwin/blackmagic in a cygwin console, the program does not react
|
Running cygwin/blackmagic in a cygwin console, the program does not react
|
||||||
on ^C. In another console, run "ps ax" to find the WINPID of the process
|
on ^C. In another console, run "ps ax" to find the WINPID of the process
|
||||||
@ -64,6 +94,7 @@ REMOTE_BMP is a "normal" BMP usb connected
|
|||||||
| Debugger | Speed | Remarks
|
| Debugger | Speed | Remarks
|
||||||
| ------------ | ----- | ------
|
| ------------ | ----- | ------
|
||||||
| REMOTE_BMP | +++ | Requires recent firmware for decent speed
|
| REMOTE_BMP | +++ | Requires recent firmware for decent speed
|
||||||
|
Probes below only when compiled with HOSTED_BMP_ONLY=0
|
||||||
| ST-Link V3 | ++++ | Requires recent firmware, Only STM32 devices supported!
|
| ST-Link V3 | ++++ | Requires recent firmware, Only STM32 devices supported!
|
||||||
| ST-Link V2 | +++ | Requires recent firmware, No CDCACM uart! Cortex only!
|
| ST-Link V2 | +++ | Requires recent firmware, No CDCACM uart! Cortex only!
|
||||||
| ST-Link V2/1 | +++ | Requires recent firmware, Cortex only!
|
| ST-Link V2/1 | +++ | Requires recent firmware, Cortex only!
|
||||||
@ -140,7 +171,7 @@ cables already listed and propose other cable. A link to the schematics
|
|||||||
is welcome.
|
is welcome.
|
||||||
|
|
||||||
## Feedback
|
## Feedback
|
||||||
### Issues and Pull request on https://github.com/blacksphere/blackmagic/
|
### Issues and Pull request on https://github.com/blackmagic-debug/blackmagic/
|
||||||
### Discussions on Discord.
|
### Discussions on Discord.
|
||||||
You can find the Discord link here: https://1bitsquared.com/pages/chat
|
You can find the Discord link here: https://1bitsquared.com/pages/chat
|
||||||
### Blackmagic mailing list http://sourceforge.net/mail/?group_id=407419
|
### Blackmagic mailing list http://sourceforge.net/mail/?group_id=407419
|
||||||
|
52
src/platforms/hosted/bmp_hosted.h
Normal file
52
src/platforms/hosted/bmp_hosted.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#if !defined(__BMP_LIBUSB_H)
|
||||||
|
#define __BMP_LIBUSB_H
|
||||||
|
|
||||||
|
#include "cl_utils.h"
|
||||||
|
|
||||||
|
#if HOSTED_BMP_ONLY != 1
|
||||||
|
# include <libusb-1.0/libusb.h>
|
||||||
|
struct trans_ctx {
|
||||||
|
#define TRANS_FLAGS_IS_DONE (1 << 0)
|
||||||
|
#define TRANS_FLAGS_HAS_ERROR (1 << 1)
|
||||||
|
volatile unsigned long flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct usb_link_s {
|
||||||
|
libusb_context *ul_libusb_ctx;
|
||||||
|
libusb_device_handle *ul_libusb_device_handle;
|
||||||
|
unsigned char ep_tx;
|
||||||
|
unsigned char ep_rx;
|
||||||
|
struct libusb_transfer* req_trans;
|
||||||
|
struct libusb_transfer* rep_trans;
|
||||||
|
void *priv;
|
||||||
|
} usb_link_t;
|
||||||
|
|
||||||
|
int send_recv(usb_link_t *link, uint8_t *txbuf, size_t txsize,
|
||||||
|
uint8_t *rxbuf, size_t rxsize);
|
||||||
|
#endif
|
||||||
|
typedef struct bmp_info_s {
|
||||||
|
bmp_type_t bmp_type;
|
||||||
|
char dev;
|
||||||
|
char serial[64];
|
||||||
|
char manufacturer[512];
|
||||||
|
char product[256];
|
||||||
|
char version[256];
|
||||||
|
bool is_jtag;
|
||||||
|
#if HOSTED_BMP_ONLY != 1
|
||||||
|
libusb_context *libusb_ctx;
|
||||||
|
struct ftdi_context *ftdic;
|
||||||
|
usb_link_t *usb_link;
|
||||||
|
unsigned int vid;
|
||||||
|
unsigned int pid;
|
||||||
|
uint8_t interface_num;
|
||||||
|
uint8_t in_ep;
|
||||||
|
uint8_t out_ep;
|
||||||
|
#endif
|
||||||
|
} bmp_info_t;
|
||||||
|
|
||||||
|
extern bmp_info_t info;
|
||||||
|
void bmp_ident(bmp_info_t *info);
|
||||||
|
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info);
|
||||||
|
void libusb_exit_function(bmp_info_t *info);
|
||||||
|
|
||||||
|
#endif
|
473
src/platforms/hosted/bmp_libusb.c
Normal file
473
src/platforms/hosted/bmp_libusb.c
Normal file
@ -0,0 +1,473 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Black Magic Debug project.
|
||||||
|
*
|
||||||
|
* Copyright(C) 2020 - 2022 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Find all known usb connected debuggers */
|
||||||
|
#include "general.h"
|
||||||
|
#include "libusb-1.0/libusb.h"
|
||||||
|
#include "cl_utils.h"
|
||||||
|
#include "ftdi_bmp.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
#define NO_SERIAL_NUMBER "<no serial number>"
|
||||||
|
|
||||||
|
void bmp_ident(bmp_info_t *info)
|
||||||
|
{
|
||||||
|
DEBUG_INFO("BMP hosted %s\n for ST-Link V2/3, CMSIS_DAP, JLINK and "
|
||||||
|
"LIBFTDI/MPSSE\n", FIRMWARE_VERSION);
|
||||||
|
if (info && info->vid && info->pid)
|
||||||
|
DEBUG_INFO("Using %04x:%04x %s %s\n %s\n", info->vid, info->pid,
|
||||||
|
(info->serial[0]) ? info->serial : NO_SERIAL_NUMBER,
|
||||||
|
info->manufacturer,
|
||||||
|
info->product);
|
||||||
|
}
|
||||||
|
|
||||||
|
void libusb_exit_function(bmp_info_t *info)
|
||||||
|
{
|
||||||
|
if (!info->usb_link)
|
||||||
|
return;
|
||||||
|
libusb_free_transfer(info->usb_link->req_trans);
|
||||||
|
libusb_free_transfer(info->usb_link->rep_trans);
|
||||||
|
if (info->usb_link->ul_libusb_device_handle) {
|
||||||
|
libusb_release_interface (
|
||||||
|
info->usb_link->ul_libusb_device_handle, 0);
|
||||||
|
libusb_close(info->usb_link->ul_libusb_device_handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bmp_type_t find_cmsis_dap_interface(libusb_device *dev,bmp_info_t *info) {
|
||||||
|
bmp_type_t type = BMP_TYPE_NONE;
|
||||||
|
|
||||||
|
struct libusb_config_descriptor *conf;
|
||||||
|
char interface_string[128];
|
||||||
|
|
||||||
|
int res = libusb_get_active_config_descriptor(dev, &conf);
|
||||||
|
if (res < 0) {
|
||||||
|
DEBUG_WARN( "WARN: libusb_get_active_config_descriptor() failed: %s",
|
||||||
|
libusb_strerror(res));
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_device_handle *handle;
|
||||||
|
res = libusb_open(dev, &handle);
|
||||||
|
if (res != LIBUSB_SUCCESS) {
|
||||||
|
DEBUG_INFO("INFO: libusb_open() failed: %s\n",
|
||||||
|
libusb_strerror(res));
|
||||||
|
libusb_free_config_descriptor(conf);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < conf->bNumInterfaces; i++) {
|
||||||
|
const struct libusb_interface_descriptor *interface = &conf->interface[i].altsetting[0];
|
||||||
|
|
||||||
|
if (!interface->iInterface) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = libusb_get_string_descriptor_ascii(
|
||||||
|
handle, interface->iInterface, (uint8_t*)interface_string,
|
||||||
|
sizeof(interface_string));
|
||||||
|
if (res < 0) {
|
||||||
|
DEBUG_WARN( "WARN: libusb_get_string_descriptor_ascii() failed: %s\n",
|
||||||
|
libusb_strerror(res));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strstr(interface_string, "CMSIS")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
type = BMP_TYPE_CMSIS_DAP;
|
||||||
|
|
||||||
|
if (interface->bInterfaceClass == 0xff && interface->bNumEndpoints == 2) {
|
||||||
|
info->interface_num = interface->bInterfaceNumber;
|
||||||
|
|
||||||
|
for (int j = 0; j < interface->bNumEndpoints; j++) {
|
||||||
|
uint8_t n = interface->endpoint[j].bEndpointAddress;
|
||||||
|
|
||||||
|
if (n & 0x80) {
|
||||||
|
info->in_ep = n;
|
||||||
|
} else {
|
||||||
|
info->out_ep = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* V2 is preferred, return early. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
libusb_free_config_descriptor(conf);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
||||||
|
{
|
||||||
|
libusb_device **devs;
|
||||||
|
int res = libusb_init(&info->libusb_ctx);
|
||||||
|
if (res) {
|
||||||
|
DEBUG_WARN( "Fatal: Failed to get USB context: %s\n",
|
||||||
|
libusb_strerror(res));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if (cl_opts->opt_cable) {
|
||||||
|
if (!strcmp(cl_opts->opt_cable, "list") ||
|
||||||
|
!strcmp(cl_opts->opt_cable, "l")) {
|
||||||
|
cable_desc_t *cable = cable_desc;
|
||||||
|
DEBUG_WARN("Available cables:\n");
|
||||||
|
for (; cable->name; ++cable) {
|
||||||
|
DEBUG_WARN("\t%s\n", cable->name);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
info->bmp_type = BMP_TYPE_LIBFTDI;
|
||||||
|
}
|
||||||
|
int n_devs = libusb_get_device_list(info->libusb_ctx, &devs);
|
||||||
|
if (n_devs < 0) {
|
||||||
|
DEBUG_WARN( "WARN:libusb_get_device_list() failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
bool report = false;
|
||||||
|
int found_debuggers;
|
||||||
|
struct libusb_device_descriptor desc;
|
||||||
|
char serial[64];
|
||||||
|
char manufacturer[128];
|
||||||
|
char product[128];
|
||||||
|
bool access_problems = false;
|
||||||
|
char *active_cable = NULL;
|
||||||
|
bool ftdi_unknown = false;
|
||||||
|
rescan:
|
||||||
|
found_debuggers = 0;
|
||||||
|
serial[0] = 0;
|
||||||
|
manufacturer[0] = 0;
|
||||||
|
product[0] = 0;
|
||||||
|
access_problems = false;
|
||||||
|
active_cable = NULL;
|
||||||
|
ftdi_unknown = false;
|
||||||
|
for (size_t i = 0; devs[i]; ++i) {
|
||||||
|
bmp_type_t type = BMP_TYPE_NONE;
|
||||||
|
libusb_device *dev = devs[i];
|
||||||
|
int res = libusb_get_device_descriptor(dev, &desc);
|
||||||
|
if (res < 0) {
|
||||||
|
DEBUG_WARN( "WARN: libusb_get_device_descriptor() failed: %s",
|
||||||
|
libusb_strerror(res));
|
||||||
|
libusb_free_device_list(devs, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Exclude hubs from testing. Probably more classes could be excluded here!*/
|
||||||
|
switch (desc.bDeviceClass) {
|
||||||
|
case LIBUSB_CLASS_HUB:
|
||||||
|
case LIBUSB_CLASS_WIRELESS:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
libusb_device_handle *handle = NULL;
|
||||||
|
res = libusb_open(dev, &handle);
|
||||||
|
if (res != LIBUSB_SUCCESS) {
|
||||||
|
if (!access_problems) {
|
||||||
|
DEBUG_INFO("INFO: Open USB %04x:%04x class %2x failed\n",
|
||||||
|
desc.idVendor, desc.idProduct, desc.bDeviceClass);
|
||||||
|
access_problems = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* If the device even has a serial number string, fetch it */
|
||||||
|
if (desc.iSerialNumber) {
|
||||||
|
res = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber,
|
||||||
|
(uint8_t *)serial, sizeof(serial));
|
||||||
|
/* If the call fails and it's not because the device gave us STALL, continue to the next one */
|
||||||
|
if (res < 0 && res != LIBUSB_ERROR_PIPE) {
|
||||||
|
libusb_close(handle);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Device has no serial and that's ok. */
|
||||||
|
else if (res <= 0)
|
||||||
|
serial[0] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
serial[0] = '\0';
|
||||||
|
if (cl_opts->opt_serial && !strstr(serial, cl_opts->opt_serial)) {
|
||||||
|
libusb_close(handle);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Attempt to get the manufacturer string */
|
||||||
|
if (desc.iManufacturer) {
|
||||||
|
res = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer,
|
||||||
|
(uint8_t *)manufacturer, sizeof(manufacturer));
|
||||||
|
/* If the call fails and it's not because the device gave us STALL, continue to the next one */
|
||||||
|
if (res < 0 && res != LIBUSB_ERROR_PIPE) {
|
||||||
|
DEBUG_WARN("WARN: libusb_get_string_descriptor_ascii() call to fetch manufacturer string failed: %s\n",
|
||||||
|
libusb_strerror(res));
|
||||||
|
libusb_close(handle);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Device has no manufacturer string and that's ok. */
|
||||||
|
else if (res <= 0)
|
||||||
|
manufacturer[0] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
manufacturer[0] = '\0';
|
||||||
|
/* Attempt to get the product string */
|
||||||
|
if (desc.iProduct) {
|
||||||
|
res = libusb_get_string_descriptor_ascii(handle, desc.iProduct,
|
||||||
|
(uint8_t *)product, sizeof(product));
|
||||||
|
/* If the call fails and it's not because the device gave us STALL, continue to the next one */
|
||||||
|
if (res < 0 && res != LIBUSB_ERROR_PIPE) {
|
||||||
|
DEBUG_WARN("WARN: libusb_get_string_descriptor_ascii() call to fetch product string failed: %s\n",
|
||||||
|
libusb_strerror(res));
|
||||||
|
libusb_close(handle);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Device has no product string and that's ok. */
|
||||||
|
else if (res <= 0)
|
||||||
|
product[0] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
product[0] = '\0';
|
||||||
|
libusb_close(handle);
|
||||||
|
if (cl_opts->opt_ident_string) {
|
||||||
|
char *match_manu = NULL;
|
||||||
|
char *match_product = NULL;
|
||||||
|
match_manu = strstr(manufacturer, cl_opts->opt_ident_string);
|
||||||
|
match_product = strstr(product, cl_opts->opt_ident_string);
|
||||||
|
if (!match_manu && !match_product)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Either serial and/or ident_string match or are not given.
|
||||||
|
* Check type.*/
|
||||||
|
if (desc.idVendor == VENDOR_ID_BMP) {
|
||||||
|
if (desc.idProduct == PRODUCT_ID_BMP)
|
||||||
|
type = BMP_TYPE_BMP;
|
||||||
|
else {
|
||||||
|
if (desc.idProduct == PRODUCT_ID_BMP_BL)
|
||||||
|
DEBUG_WARN("BMP in bootloader mode found. Restart or reflash!\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (type == BMP_TYPE_NONE &&
|
||||||
|
(type = find_cmsis_dap_interface(dev, info)) != BMP_TYPE_NONE) {
|
||||||
|
/* find_cmsis_dap_interface has set valid type*/
|
||||||
|
} else if (strstr(manufacturer, "CMSIS") || strstr(product, "CMSIS"))
|
||||||
|
type = BMP_TYPE_CMSIS_DAP;
|
||||||
|
else if (desc.idVendor == VENDOR_ID_STLINK) {
|
||||||
|
if (desc.idProduct == PRODUCT_ID_STLINKV2 ||
|
||||||
|
desc.idProduct == PRODUCT_ID_STLINKV21 ||
|
||||||
|
desc.idProduct == PRODUCT_ID_STLINKV21_MSD ||
|
||||||
|
desc.idProduct == PRODUCT_ID_STLINKV3_NO_MSD ||
|
||||||
|
desc.idProduct == PRODUCT_ID_STLINKV3_BL ||
|
||||||
|
desc.idProduct == PRODUCT_ID_STLINKV3 ||
|
||||||
|
desc.idProduct == PRODUCT_ID_STLINKV3E)
|
||||||
|
type = BMP_TYPE_STLINKV2;
|
||||||
|
else {
|
||||||
|
if (desc.idProduct == PRODUCT_ID_STLINKV1)
|
||||||
|
DEBUG_WARN( "INFO: STLINKV1 not supported\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (desc.idVendor == VENDOR_ID_SEGGER)
|
||||||
|
type = BMP_TYPE_JLINK;
|
||||||
|
else {
|
||||||
|
cable_desc_t *cable = cable_desc;
|
||||||
|
for (; cable->name; ++cable) {
|
||||||
|
bool found = false;
|
||||||
|
if (cable->vendor != desc.idVendor || cable->product != desc.idProduct)
|
||||||
|
continue; /* VID/PID do not match*/
|
||||||
|
if (cl_opts->opt_cable) {
|
||||||
|
if (strncmp(cable->name, cl_opts->opt_cable, strlen(cable->name)))
|
||||||
|
continue; /* cable names do not match*/
|
||||||
|
else
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (cable->description) {
|
||||||
|
if (strncmp(cable->description, product, strlen(cable->description)))
|
||||||
|
continue; /* discriptions do not match*/
|
||||||
|
else
|
||||||
|
found = true;
|
||||||
|
} else { /* VID/PID fits, but no cl_opts->opt_cable and no description*/
|
||||||
|
if (cable->vendor == 0x0403 && /* FTDI*/
|
||||||
|
(cable->product == 0x6010 || /* FT2232C/D/H*/
|
||||||
|
cable->product == 0x6011 || /* FT4232H Quad HS USB-UART/FIFO IC */
|
||||||
|
cable->product == 0x6014)) { /* FT232H Single HS USB-UART/FIFO IC */
|
||||||
|
ftdi_unknown = true;
|
||||||
|
continue; /* Cable name is needed */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
active_cable = cable->name;
|
||||||
|
type = BMP_TYPE_LIBFTDI;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!cable->name)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (report) {
|
||||||
|
DEBUG_WARN("%2d: %s, %s, %s\n", found_debuggers + 1,
|
||||||
|
serial[0] ? serial : NO_SERIAL_NUMBER,
|
||||||
|
manufacturer,product);
|
||||||
|
}
|
||||||
|
info->vid = desc.idVendor;
|
||||||
|
info->pid = desc.idProduct;
|
||||||
|
info->bmp_type = type;
|
||||||
|
strncpy(info->serial, serial, sizeof(info->serial));
|
||||||
|
strncpy(info->product, product, sizeof(info->product));
|
||||||
|
strncpy(info->manufacturer, manufacturer, sizeof(info->manufacturer));
|
||||||
|
if (cl_opts->opt_position &&
|
||||||
|
cl_opts->opt_position == found_debuggers + 1) {
|
||||||
|
found_debuggers = 1;
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
++found_debuggers;
|
||||||
|
}
|
||||||
|
if (found_debuggers == 0 && ftdi_unknown)
|
||||||
|
DEBUG_WARN("Generic FTDI MPSSE VID/PID found. Please specify exact type with \"-c <cable>\" !\n");
|
||||||
|
if (found_debuggers == 1 && !cl_opts->opt_cable && info->bmp_type == BMP_TYPE_LIBFTDI)
|
||||||
|
cl_opts->opt_cable = active_cable;
|
||||||
|
if (!found_debuggers && cl_opts->opt_list_only)
|
||||||
|
DEBUG_WARN("No usable debugger found\n");
|
||||||
|
if (found_debuggers > 1 ||
|
||||||
|
(found_debuggers == 1 && cl_opts->opt_list_only)) {
|
||||||
|
if (!report) {
|
||||||
|
if (found_debuggers > 1)
|
||||||
|
DEBUG_WARN("%d debuggers found!\nSelect with -P <pos> "
|
||||||
|
"or -s <(partial)serial no.>\n",
|
||||||
|
found_debuggers);
|
||||||
|
report = true;
|
||||||
|
goto rescan;
|
||||||
|
} else {
|
||||||
|
if (found_debuggers > 0)
|
||||||
|
access_problems = false;
|
||||||
|
found_debuggers = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found_debuggers && access_problems)
|
||||||
|
DEBUG_WARN(
|
||||||
|
"No debugger found. Please check access rights to USB devices!\n");
|
||||||
|
libusb_free_device_list(devs, 1);
|
||||||
|
return found_debuggers == 1 ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LIBUSB_CALL on_trans_done(struct libusb_transfer *trans)
|
||||||
|
{
|
||||||
|
struct trans_ctx * const ctx = trans->user_data;
|
||||||
|
|
||||||
|
if (trans->status != LIBUSB_TRANSFER_COMPLETED)
|
||||||
|
{
|
||||||
|
DEBUG_WARN("on_trans_done: ");
|
||||||
|
if (trans->status == LIBUSB_TRANSFER_TIMED_OUT)
|
||||||
|
DEBUG_WARN(" Timeout\n");
|
||||||
|
else if (trans->status == LIBUSB_TRANSFER_CANCELLED)
|
||||||
|
DEBUG_WARN(" cancelled\n");
|
||||||
|
else if (trans->status == LIBUSB_TRANSFER_NO_DEVICE)
|
||||||
|
DEBUG_WARN(" no device\n");
|
||||||
|
else
|
||||||
|
DEBUG_WARN(" unknown\n");
|
||||||
|
ctx->flags |= TRANS_FLAGS_HAS_ERROR;
|
||||||
|
}
|
||||||
|
ctx->flags |= TRANS_FLAGS_IS_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int submit_wait(usb_link_t *link, struct libusb_transfer *trans) {
|
||||||
|
struct trans_ctx trans_ctx;
|
||||||
|
enum libusb_error error;
|
||||||
|
|
||||||
|
trans_ctx.flags = 0;
|
||||||
|
|
||||||
|
/* brief intrusion inside the libusb interface */
|
||||||
|
trans->callback = on_trans_done;
|
||||||
|
trans->user_data = &trans_ctx;
|
||||||
|
|
||||||
|
if ((error = libusb_submit_transfer(trans))) {
|
||||||
|
DEBUG_WARN("libusb_submit_transfer(%d): %s\n", error,
|
||||||
|
libusb_strerror(error));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t start_time = platform_time_ms();
|
||||||
|
while (trans_ctx.flags == 0) {
|
||||||
|
struct timeval timeout;
|
||||||
|
timeout.tv_sec = 1;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
if (libusb_handle_events_timeout(link->ul_libusb_ctx, &timeout)) {
|
||||||
|
DEBUG_WARN("libusb_handle_events()\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
uint32_t now = platform_time_ms();
|
||||||
|
if (now - start_time > 1000) {
|
||||||
|
libusb_cancel_transfer(trans);
|
||||||
|
DEBUG_WARN("libusb_handle_events() timeout\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (trans_ctx.flags & TRANS_FLAGS_HAS_ERROR) {
|
||||||
|
DEBUG_WARN("libusb_handle_events() | has_error\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* One USB transaction */
|
||||||
|
int send_recv(usb_link_t *link,
|
||||||
|
uint8_t *txbuf, size_t txsize,
|
||||||
|
uint8_t *rxbuf, size_t rxsize)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
if (txsize) {
|
||||||
|
libusb_fill_bulk_transfer(link->req_trans,
|
||||||
|
link->ul_libusb_device_handle,
|
||||||
|
link->ep_tx | LIBUSB_ENDPOINT_OUT,
|
||||||
|
txbuf, txsize,
|
||||||
|
NULL, NULL, 0);
|
||||||
|
size_t i = 0;
|
||||||
|
DEBUG_WIRE(" Send (%3zu): ", txsize);
|
||||||
|
for (; i < txsize; ++i) {
|
||||||
|
DEBUG_WIRE("%02x", txbuf[i]);
|
||||||
|
if ((i & 7U) == 7U)
|
||||||
|
DEBUG_WIRE(".");
|
||||||
|
if ((i & 31U) == 31U)
|
||||||
|
DEBUG_WIRE("\n ");
|
||||||
|
}
|
||||||
|
if (!(i & 31U))
|
||||||
|
DEBUG_WIRE("\n");
|
||||||
|
if (submit_wait(link, link->req_trans)) {
|
||||||
|
libusb_clear_halt(link->ul_libusb_device_handle, link->ep_tx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* send_only */
|
||||||
|
if (rxsize != 0) {
|
||||||
|
/* read the response */
|
||||||
|
libusb_fill_bulk_transfer(link->rep_trans, link->ul_libusb_device_handle,
|
||||||
|
link->ep_rx | LIBUSB_ENDPOINT_IN,
|
||||||
|
rxbuf, rxsize, NULL, NULL, 0);
|
||||||
|
|
||||||
|
if (submit_wait(link, link->rep_trans)) {
|
||||||
|
DEBUG_WARN("clear 1\n");
|
||||||
|
libusb_clear_halt(link->ul_libusb_device_handle, link->ep_rx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
res = link->rep_trans->actual_length;
|
||||||
|
if (res > 0) {
|
||||||
|
const size_t rxlen = (size_t)res;
|
||||||
|
DEBUG_WIRE(" Rec (%zu/%zu)", rxsize, rxlen);
|
||||||
|
for (size_t i = 0; i < rxlen && i < 32 ; ++i) {
|
||||||
|
if (i && ((i & 7U) == 0U))
|
||||||
|
DEBUG_WIRE(".");
|
||||||
|
DEBUG_WIRE("%02x", rxbuf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DEBUG_WIRE("\n");
|
||||||
|
return res;
|
||||||
|
}
|
@ -22,7 +22,6 @@
|
|||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "gdb_if.h"
|
#include "gdb_if.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "platform.h"
|
|
||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "bmp_remote.h"
|
#include "bmp_remote.h"
|
||||||
@ -33,25 +32,23 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "adiv5.h"
|
#include "adiv5.h"
|
||||||
|
|
||||||
int remote_init(bool verbose)
|
int remote_init(void)
|
||||||
{
|
{
|
||||||
char construct[REMOTE_MAX_MSG_SIZE];
|
char construct[REMOTE_MAX_MSG_SIZE];
|
||||||
int c = snprintf(construct, REMOTE_MAX_MSG_SIZE, "%s", REMOTE_START_STR);
|
int c = snprintf(construct, REMOTE_MAX_MSG_SIZE, "%s", REMOTE_START_STR);
|
||||||
platform_buffer_write((uint8_t *)construct, c);
|
platform_buffer_write((uint8_t *)construct, c);
|
||||||
c = platform_buffer_read((uint8_t *)construct, REMOTE_MAX_MSG_SIZE);
|
c = platform_buffer_read((uint8_t *)construct, REMOTE_MAX_MSG_SIZE);
|
||||||
|
|
||||||
if ((!c) || (construct[0] == REMOTE_RESP_ERR)) {
|
if ((c < 1) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||||
DEBUG_WARN("Remote Start failed, error %s\n",
|
DEBUG_WARN("Remote Start failed, error %s\n",
|
||||||
c ? (char *)&(construct[1]) : "unknown");
|
c ? (char *)&(construct[1]) : "unknown");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (verbose)
|
DEBUG_PROBE("Remote is %s\n", &construct[1]);
|
||||||
DEBUG_WARN("Remote is %s\n", &construct[1]);
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool remote_target_get_power(void)
|
bool remote_target_get_power(void)
|
||||||
@ -65,7 +62,7 @@ bool remote_target_get_power(void)
|
|||||||
|
|
||||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||||
|
|
||||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||||
DEBUG_WARN(" platform_target_get_power failed, error %s\n",
|
DEBUG_WARN(" platform_target_get_power failed, error %s\n",
|
||||||
s ? (char *)&(construct[1]) : "unknown");
|
s ? (char *)&(construct[1]) : "unknown");
|
||||||
exit (-1);
|
exit (-1);
|
||||||
@ -74,7 +71,7 @@ bool remote_target_get_power(void)
|
|||||||
return (construct[1] == '1');
|
return (construct[1] == '1');
|
||||||
}
|
}
|
||||||
|
|
||||||
void remote_target_set_power(bool power)
|
bool remote_target_set_power(bool power)
|
||||||
{
|
{
|
||||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||||
int s;
|
int s;
|
||||||
@ -85,11 +82,12 @@ void remote_target_set_power(bool power)
|
|||||||
|
|
||||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||||
|
|
||||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||||
DEBUG_WARN("platform_target_set_power failed, error %s\n",
|
DEBUG_WARN("platform_target_set_power failed, error %s\n",
|
||||||
s ? (char *)&(construct[1]) : "unknown");
|
s ? (char *)&(construct[1]) : "unknown");
|
||||||
exit(-1);
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remote_srst_set_val(bool assert)
|
void remote_srst_set_val(bool assert)
|
||||||
@ -103,7 +101,7 @@ void remote_srst_set_val(bool assert)
|
|||||||
|
|
||||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||||
|
|
||||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||||
DEBUG_WARN("platform_srst_set_val failed, error %s\n",
|
DEBUG_WARN("platform_srst_set_val failed, error %s\n",
|
||||||
s ? (char *)&(construct[1]) : "unknown");
|
s ? (char *)&(construct[1]) : "unknown");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@ -121,7 +119,7 @@ bool remote_srst_get_val(void)
|
|||||||
|
|
||||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||||
|
|
||||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||||
DEBUG_WARN("platform_srst_set_val failed, error %s\n",
|
DEBUG_WARN("platform_srst_set_val failed, error %s\n",
|
||||||
s ? (char *)&(construct[1]) : "unknown");
|
s ? (char *)&(construct[1]) : "unknown");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@ -129,6 +127,40 @@ bool remote_srst_get_val(void)
|
|||||||
return (construct[1] == '1');
|
return (construct[1] == '1');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void remote_max_frequency_set(uint32_t freq)
|
||||||
|
{
|
||||||
|
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||||
|
int s;
|
||||||
|
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, REMOTE_FREQ_SET_STR,
|
||||||
|
freq);
|
||||||
|
platform_buffer_write(construct, s);
|
||||||
|
|
||||||
|
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||||
|
|
||||||
|
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||||
|
DEBUG_WARN("Update Firmware to allow to set max SWJ frequency\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t remote_max_frequency_get(void)
|
||||||
|
{
|
||||||
|
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||||
|
int s;
|
||||||
|
|
||||||
|
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,"%s",
|
||||||
|
REMOTE_FREQ_GET_STR);
|
||||||
|
platform_buffer_write(construct, s);
|
||||||
|
|
||||||
|
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||||
|
|
||||||
|
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR))
|
||||||
|
return FREQ_FIXED;
|
||||||
|
|
||||||
|
uint32_t freq[1];
|
||||||
|
unhexify(freq, (const char*)&construct[1], 4);
|
||||||
|
return freq[0];
|
||||||
|
}
|
||||||
|
|
||||||
const char *remote_target_voltage(void)
|
const char *remote_target_voltage(void)
|
||||||
{
|
{
|
||||||
static uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
static uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||||
@ -140,7 +172,7 @@ const char *remote_target_voltage(void)
|
|||||||
|
|
||||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||||
|
|
||||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||||
DEBUG_WARN("platform_target_voltage failed, error %s\n",
|
DEBUG_WARN("platform_target_voltage failed, error %s\n",
|
||||||
s ? (char *)&(construct[1]) : "unknown");
|
s ? (char *)&(construct[1]) : "unknown");
|
||||||
exit(- 1);
|
exit(- 1);
|
||||||
@ -153,10 +185,10 @@ static uint32_t remote_adiv5_dp_read(ADIv5_DP_t *dp, uint16_t addr)
|
|||||||
(void)dp;
|
(void)dp;
|
||||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||||
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, REMOTE_DP_READ_STR,
|
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, REMOTE_DP_READ_STR,
|
||||||
addr);
|
dp->dp_jd_index, addr);
|
||||||
platform_buffer_write(construct, s);
|
platform_buffer_write(construct, s);
|
||||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||||
DEBUG_WARN("%s error %d\n", __func__, s);
|
DEBUG_WARN("%s error %d\n", __func__, s);
|
||||||
}
|
}
|
||||||
uint32_t dest[1];
|
uint32_t dest[1];
|
||||||
@ -171,10 +203,10 @@ static uint32_t remote_adiv5_low_access(
|
|||||||
(void)dp;
|
(void)dp;
|
||||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||||
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,
|
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,
|
||||||
REMOTE_LOW_ACCESS_STR, RnW, addr, value);
|
REMOTE_LOW_ACCESS_STR, dp->dp_jd_index, RnW, addr, value);
|
||||||
platform_buffer_write(construct, s);
|
platform_buffer_write(construct, s);
|
||||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||||
DEBUG_WARN("%s error %d\n", __func__, s);
|
DEBUG_WARN("%s error %d\n", __func__, s);
|
||||||
}
|
}
|
||||||
uint32_t dest[1];
|
uint32_t dest[1];
|
||||||
@ -186,10 +218,10 @@ static uint32_t remote_adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr)
|
|||||||
{
|
{
|
||||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||||
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,REMOTE_AP_READ_STR,
|
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,REMOTE_AP_READ_STR,
|
||||||
ap->apsel, addr);
|
ap->dp->dp_jd_index, ap->apsel, addr);
|
||||||
platform_buffer_write(construct, s);
|
platform_buffer_write(construct, s);
|
||||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||||
DEBUG_WARN("%s error %d\n", __func__, s);
|
DEBUG_WARN("%s error %d\n", __func__, s);
|
||||||
}
|
}
|
||||||
uint32_t dest[1];
|
uint32_t dest[1];
|
||||||
@ -201,10 +233,10 @@ static void remote_adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value)
|
|||||||
{
|
{
|
||||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||||
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,REMOTE_AP_WRITE_STR,
|
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,REMOTE_AP_WRITE_STR,
|
||||||
ap->apsel, addr, value);
|
ap->dp->dp_jd_index, ap->apsel, addr, value);
|
||||||
platform_buffer_write(construct, s);
|
platform_buffer_write(construct, s);
|
||||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||||
DEBUG_WARN("%s error %d\n", __func__, s);
|
DEBUG_WARN("%s error %d\n", __func__, s);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -267,7 +299,7 @@ static void remote_ap_mem_read(
|
|||||||
if (count > batchsize)
|
if (count > batchsize)
|
||||||
count = batchsize;
|
count = batchsize;
|
||||||
s = snprintf(construct, REMOTE_MAX_MSG_SIZE,
|
s = snprintf(construct, REMOTE_MAX_MSG_SIZE,
|
||||||
REMOTE_AP_MEM_READ_STR, ap->apsel, ap->csw, src, count);
|
REMOTE_AP_MEM_READ_STR, ap->dp->dp_jd_index, ap->apsel, ap->csw, src, count);
|
||||||
platform_buffer_write((uint8_t*)construct, s);
|
platform_buffer_write((uint8_t*)construct, s);
|
||||||
s = platform_buffer_read((uint8_t*)construct, REMOTE_MAX_MSG_SIZE);
|
s = platform_buffer_read((uint8_t*)construct, REMOTE_MAX_MSG_SIZE);
|
||||||
if ((s > 0) && (construct[0] == REMOTE_RESP_OK)) {
|
if ((s > 0) && (construct[0] == REMOTE_RESP_OK)) {
|
||||||
@ -307,7 +339,7 @@ static void remote_ap_mem_write_sized(
|
|||||||
count = batchsize;
|
count = batchsize;
|
||||||
int s = snprintf(construct, REMOTE_MAX_MSG_SIZE,
|
int s = snprintf(construct, REMOTE_MAX_MSG_SIZE,
|
||||||
REMOTE_AP_MEM_WRITE_SIZED_STR,
|
REMOTE_AP_MEM_WRITE_SIZED_STR,
|
||||||
ap->apsel, ap->csw, align, dest, count);
|
ap->dp->dp_jd_index, ap->apsel, ap->csw, align, dest, count);
|
||||||
char *p = construct + s;
|
char *p = construct + s;
|
||||||
hexify(p, src, count);
|
hexify(p, src, count);
|
||||||
p += 2 * count;
|
p += 2 * count;
|
||||||
@ -340,7 +372,8 @@ void remote_adiv5_dp_defaults(ADIv5_DP_t *dp)
|
|||||||
REMOTE_HL_CHECK_STR);
|
REMOTE_HL_CHECK_STR);
|
||||||
platform_buffer_write(construct, s);
|
platform_buffer_write(construct, s);
|
||||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR) ||
|
||||||
|
((construct[1] - '0') < REMOTE_HL_VERSION)) {
|
||||||
DEBUG_WARN(
|
DEBUG_WARN(
|
||||||
"Please update BMP firmware for substantial speed increase!\n");
|
"Please update BMP firmware for substantial speed increase!\n");
|
||||||
return;
|
return;
|
||||||
@ -352,3 +385,20 @@ void remote_adiv5_dp_defaults(ADIv5_DP_t *dp)
|
|||||||
dp->mem_read = remote_ap_mem_read;
|
dp->mem_read = remote_ap_mem_read;
|
||||||
dp->mem_write_sized = remote_ap_mem_write_sized;
|
dp->mem_write_sized = remote_ap_mem_write_sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void remote_add_jtag_dev(int i, const jtag_dev_t *jtag_dev)
|
||||||
|
{
|
||||||
|
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||||
|
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,
|
||||||
|
REMOTE_JTAG_ADD_DEV_STR,
|
||||||
|
i,
|
||||||
|
jtag_dev->dr_prescan,
|
||||||
|
jtag_dev->dr_postscan,
|
||||||
|
jtag_dev->ir_len,
|
||||||
|
jtag_dev->ir_prescan,
|
||||||
|
jtag_dev->ir_postscan,
|
||||||
|
jtag_dev->current_ir);
|
||||||
|
platform_buffer_write(construct, s);
|
||||||
|
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||||
|
/* No check for error here. Done in remote_adiv5_dp_defaults!*/
|
||||||
|
}
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
#if !defined(__BMP_REMOTE_H_)
|
#if !defined(__BMP_REMOTE_H_)
|
||||||
#define __BMP_REMOTE_H_
|
#define __BMP_REMOTE_H_
|
||||||
#include "swdptap.h"
|
|
||||||
#include "jtagtap.h"
|
#include "jtagtap.h"
|
||||||
#include "adiv5.h"
|
#include "adiv5.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
@ -29,15 +28,18 @@
|
|||||||
int platform_buffer_write(const uint8_t *data, int size);
|
int platform_buffer_write(const uint8_t *data, int size);
|
||||||
int platform_buffer_read(uint8_t *data, int size);
|
int platform_buffer_read(uint8_t *data, int size);
|
||||||
|
|
||||||
int remote_init(bool verbose);
|
int remote_init(void);
|
||||||
int remote_swdptap_init(swd_proc_t *swd_proc);
|
int remote_swdptap_init(ADIv5_DP_t *dp);
|
||||||
int remote_jtagtap_init(jtag_proc_t *jtag_proc);
|
int remote_jtagtap_init(jtag_proc_t *jtag_proc);
|
||||||
bool remote_target_get_power(void);
|
bool remote_target_get_power(void);
|
||||||
const char *remote_target_voltage(void);
|
const char *remote_target_voltage(void);
|
||||||
void remote_target_set_power(bool power);
|
bool remote_target_set_power(bool power);
|
||||||
void remote_srst_set_val(bool assert);
|
void remote_srst_set_val(bool assert);
|
||||||
bool remote_srst_get_val(void);
|
bool remote_srst_get_val(void);
|
||||||
|
void remote_max_frequency_set(uint32_t freq);
|
||||||
|
uint32_t remote_max_frequency_get(void);
|
||||||
const char *platform_target_voltage(void);
|
const char *platform_target_voltage(void);
|
||||||
void remote_adiv5_dp_defaults(ADIv5_DP_t *dp);
|
void remote_adiv5_dp_defaults(ADIv5_DP_t *dp);
|
||||||
|
void remote_add_jtag_dev(int i, const jtag_dev_t *jtag_dev);
|
||||||
#define __BMP_REMOTE_H_
|
#define __BMP_REMOTE_H_
|
||||||
#endif
|
#endif
|
||||||
|
296
src/platforms/hosted/bmp_serial.c
Normal file
296
src/platforms/hosted/bmp_serial.c
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Black Magic Debug project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Find all known serial connected debuggers */
|
||||||
|
|
||||||
|
#include "general.h"
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "bmp_hosted.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
void bmp_ident(bmp_info_t *info)
|
||||||
|
{
|
||||||
|
if (!info)
|
||||||
|
return;
|
||||||
|
DEBUG_INFO("BMP hosted (BMP Only) %s\n", FIRMWARE_VERSION);
|
||||||
|
DEBUG_INFO("Using:\n %s %s %s\n", info->manufacturer, info->version, info->serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
void libusb_exit_function(bmp_info_t *info) {(void)info;};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
||||||
|
{
|
||||||
|
DEBUG_WARN("Please implement find_debuggers for MACOS!\n");
|
||||||
|
(void)cl_opts;
|
||||||
|
(void)info;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#elif defined(__WIN32__) || defined(__CYGWIN__)
|
||||||
|
|
||||||
|
|
||||||
|
/* This source has been used as an example:
|
||||||
|
* https://stackoverflow.com/questions/3438366/setupdigetdeviceproperty-usage-example */
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <setupapi.h>
|
||||||
|
#include <cfgmgr32.h> // for MAX_DEVICE_ID_LEN, CM_Get_Parent and CM_Get_Device_ID
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* include DEVPKEY_Device_BusReportedDeviceDesc from WinDDK\7600.16385.1\inc\api\devpropdef.h */
|
||||||
|
#ifdef DEFINE_DEVPROPKEY
|
||||||
|
#undef DEFINE_DEVPROPKEY
|
||||||
|
#endif
|
||||||
|
#define DEFINE_DEVPROPKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) const DEVPROPKEY DECLSPEC_SELECTANY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid }
|
||||||
|
|
||||||
|
/* include DEVPKEY_Device_BusReportedDeviceDesc from WinDDK\7600.16385.1\inc\api\devpkey.h */
|
||||||
|
DEFINE_DEVPROPKEY(DEVPKEY_Device_BusReportedDeviceDesc, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 4); // DEVPROP_TYPE_STRING
|
||||||
|
|
||||||
|
/* List all USB devices with some additional information.
|
||||||
|
* Unfortunately, this code is quite ugly. */
|
||||||
|
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
DWORD dwSize;
|
||||||
|
DEVPROPTYPE ulPropertyType;
|
||||||
|
CONFIGRET status;
|
||||||
|
HDEVINFO hDevInfo;
|
||||||
|
SP_DEVINFO_DATA DeviceInfoData;
|
||||||
|
TCHAR szDeviceInstanceID [MAX_DEVICE_ID_LEN];
|
||||||
|
WCHAR busReportedDeviceSesc[4096];
|
||||||
|
int probes_found = 0;
|
||||||
|
bool is_printing_probes_info = cl_opts->opt_list_only != 0;
|
||||||
|
|
||||||
|
info->bmp_type = BMP_TYPE_BMP;
|
||||||
|
|
||||||
|
hDevInfo = SetupDiGetClassDevs (0, "USB", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
|
||||||
|
if (hDevInfo == INVALID_HANDLE_VALUE)
|
||||||
|
return -1;
|
||||||
|
print_probes_info:
|
||||||
|
for (i = 0; ; i++) {
|
||||||
|
char serial_number[sizeof info->serial];
|
||||||
|
DeviceInfoData.cbSize = sizeof (DeviceInfoData);
|
||||||
|
if (!SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData))
|
||||||
|
break;
|
||||||
|
|
||||||
|
status = CM_Get_Device_ID(DeviceInfoData.DevInst, szDeviceInstanceID , MAX_PATH, 0);
|
||||||
|
if (status != CR_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!sscanf(szDeviceInstanceID, "USB\\VID_1D50&PID_6018\\%s", serial_number))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc,
|
||||||
|
&ulPropertyType, (BYTE*)busReportedDeviceSesc, sizeof busReportedDeviceSesc, &dwSize, 0))
|
||||||
|
{
|
||||||
|
probes_found ++;
|
||||||
|
if (is_printing_probes_info)
|
||||||
|
{
|
||||||
|
DEBUG_WARN("%2d: %s, %ls\n", probes_found,
|
||||||
|
serial_number, busReportedDeviceSesc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool probe_identified = true;
|
||||||
|
if ((cl_opts->opt_serial && strstr(serial_number, cl_opts->opt_serial)) ||
|
||||||
|
(cl_opts->opt_position && cl_opts->opt_position == probes_found) ||
|
||||||
|
/* Special case for the very first probe found. */
|
||||||
|
(probe_identified = false, probes_found == 1)) {
|
||||||
|
|
||||||
|
strncpy(info->serial, serial_number, sizeof info->serial);
|
||||||
|
strncpy(info->manufacturer, "BMP", sizeof info->manufacturer);
|
||||||
|
snprintf(info->product, sizeof info->product, "%ls", busReportedDeviceSesc);
|
||||||
|
/* Don't bother to parse the version string. It is a part of the
|
||||||
|
* product description string. It seems that at the moment it
|
||||||
|
* is only being used to print a version string in response
|
||||||
|
* to the 'monitor version' command, so it doesn't really matter
|
||||||
|
* if the version string is printed as a part of the product string,
|
||||||
|
* or as a separate string, the result is pretty much the same. */
|
||||||
|
info->version[0] = 0;
|
||||||
|
if (probe_identified)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_printing_probes_info)
|
||||||
|
return 1;
|
||||||
|
if (probes_found == 1)
|
||||||
|
/* Exactly one probe found. Its information has already been filled
|
||||||
|
* in the detection loop, so use this probe. */
|
||||||
|
return 0;
|
||||||
|
if (probes_found < 1) {
|
||||||
|
DEBUG_WARN("No BMP probe found\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Otherwise, if this line is reached, then more than one probe has been found,
|
||||||
|
* and no probe was identified as selected by the user.
|
||||||
|
* Restart the identification loop, this time printing the probe information,
|
||||||
|
* and then return. */
|
||||||
|
DEBUG_WARN("%d debuggers found!\nSelect with -P <pos>, or "
|
||||||
|
"-s <(partial)serial no.>\n",
|
||||||
|
probes_found);
|
||||||
|
probes_found = 0;
|
||||||
|
is_printing_probes_info = true;
|
||||||
|
goto print_probes_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
/* Old ID: Black_Sphere_Technologies_Black_Magic_Probe_BFE4D6EC-if00
|
||||||
|
* Recent: Black_Sphere_Technologies_Black_Magic_Probe_v1.7.1-212-g212292ab_7BAE7AB8-if00
|
||||||
|
* usb-Black_Sphere_Technologies_Black_Magic_Probe__SWLINK__v1.7.1-155-gf55ad67b-dirty_DECB8811-if00
|
||||||
|
*/
|
||||||
|
#define BMP_IDSTRING_BLACKSPHERE "usb-Black_Sphere_Technologies_Black_Magic_Probe"
|
||||||
|
#define BMP_IDSTRING_BLACKMAGIC "usb-Black_Magic_Debug_Black_Magic_Probe"
|
||||||
|
#define BMP_IDSTRING_1BITSQUARED "usb-1BitSquared_Black_Magic_Probe"
|
||||||
|
#define DEVICE_BY_ID "/dev/serial/by-id/"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract type, version and serial from /dev/serial/by_id
|
||||||
|
* Return 0 on success
|
||||||
|
*
|
||||||
|
* Old versions have different strings. Try to cope!
|
||||||
|
*/
|
||||||
|
static int scan_linux_id(char *name, char *type, char *version, char *serial)
|
||||||
|
{
|
||||||
|
name += strlen(BMP_IDSTRING_BLACKSPHERE) + 1;
|
||||||
|
while (*name == '_')
|
||||||
|
name++;
|
||||||
|
if (!*name) {
|
||||||
|
DEBUG_WARN("Unexpected end\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
char *p = name;
|
||||||
|
char *delims[4] = {0,0,0,0};
|
||||||
|
int underscores = 0;
|
||||||
|
while (*p) {
|
||||||
|
if (*p == '_') {
|
||||||
|
while (p[1] == '_')
|
||||||
|
p++; /* remove multiple underscores */
|
||||||
|
if (underscores > 2)
|
||||||
|
return -1;
|
||||||
|
delims[underscores] = p;
|
||||||
|
underscores ++;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
if (underscores == 0) { /* Old BMP native */
|
||||||
|
int res;
|
||||||
|
res = sscanf(name, "%8s-if00", serial);
|
||||||
|
if (res != 1)
|
||||||
|
return -1;
|
||||||
|
strcpy(type, "Native");
|
||||||
|
strcpy(version, "Unknown");
|
||||||
|
} else if (underscores == 2) {
|
||||||
|
strncpy(type, name, delims[0] - name - 1);
|
||||||
|
strncpy(version, delims[0] + 1, delims[1] - delims[0] - 1);
|
||||||
|
int res = sscanf(delims[1] + 1, "%8s-if00", serial);
|
||||||
|
if (!res)
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
int res = sscanf(delims[0] + 1, "%8s-if00", serial);
|
||||||
|
if (!res)
|
||||||
|
return -1;
|
||||||
|
if (name[0] == 'v') {
|
||||||
|
strcpy(type, "Unknown");
|
||||||
|
strncpy(version, name, delims[0] - name - 1);
|
||||||
|
} else {
|
||||||
|
strncpy(type, name, delims[0] - name);
|
||||||
|
strcpy(type, "Unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
||||||
|
{
|
||||||
|
if (cl_opts->opt_device)
|
||||||
|
return 1;
|
||||||
|
info->bmp_type = BMP_TYPE_BMP;
|
||||||
|
DIR *dir = opendir(DEVICE_BY_ID);
|
||||||
|
if (!dir) /* No serial device connected!*/
|
||||||
|
return 0;
|
||||||
|
int found_bmps = 0;
|
||||||
|
struct dirent *dp;
|
||||||
|
int i = 0;
|
||||||
|
while ((dp = readdir(dir)) != NULL) {
|
||||||
|
if ((strstr(dp->d_name, BMP_IDSTRING_BLACKMAGIC) ||
|
||||||
|
strstr(dp->d_name, BMP_IDSTRING_BLACKSPHERE) ||
|
||||||
|
strstr(dp->d_name, BMP_IDSTRING_1BITSQUARED)) &&
|
||||||
|
(strstr(dp->d_name, "-if00"))) {
|
||||||
|
i++;
|
||||||
|
char type[256], version[256], serial[256];
|
||||||
|
if (scan_linux_id(dp->d_name, type, version, serial)) {
|
||||||
|
DEBUG_WARN("Unexpected device name found \"%s\"\n",
|
||||||
|
dp->d_name);
|
||||||
|
}
|
||||||
|
if ((cl_opts->opt_serial && strstr(serial, cl_opts->opt_serial)) ||
|
||||||
|
(cl_opts->opt_position && cl_opts->opt_position == i)) {
|
||||||
|
/* With serial number given and partial match, we are done!*/
|
||||||
|
strncpy(info->serial, serial, sizeof(info->serial));
|
||||||
|
int res = snprintf(info->manufacturer, sizeof(info->manufacturer), "Black Magic Probe (%s)", type);
|
||||||
|
if (res)
|
||||||
|
DEBUG_WARN("Overflow\n");
|
||||||
|
strncpy(info->version, version, sizeof(info->version));
|
||||||
|
found_bmps = 1;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
found_bmps++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
if (found_bmps < 1) {
|
||||||
|
DEBUG_WARN("No BMP probe found\n");
|
||||||
|
return -1;
|
||||||
|
} else if ((found_bmps > 1) || cl_opts->opt_list_only) {
|
||||||
|
DEBUG_WARN("Available Probes:\n");
|
||||||
|
}
|
||||||
|
dir = opendir(DEVICE_BY_ID);
|
||||||
|
i = 0;
|
||||||
|
while ((dp = readdir(dir)) != NULL) {
|
||||||
|
if ((strstr(dp->d_name, BMP_IDSTRING_BLACKMAGIC) ||
|
||||||
|
strstr(dp->d_name, BMP_IDSTRING_BLACKSPHERE) ||
|
||||||
|
strstr(dp->d_name, BMP_IDSTRING_1BITSQUARED)) &&
|
||||||
|
(strstr(dp->d_name, "-if00"))) {
|
||||||
|
i++;
|
||||||
|
char type[256], version[256], serial[256];
|
||||||
|
if (scan_linux_id(dp->d_name, type, version, serial)) {
|
||||||
|
DEBUG_WARN("Unexpected device name found \"%s\"\n",
|
||||||
|
dp->d_name);
|
||||||
|
} else if ((found_bmps == 1) && (!cl_opts->opt_list_only)) {
|
||||||
|
strncpy(info->serial, serial, sizeof(info->serial));
|
||||||
|
found_bmps = 1;
|
||||||
|
strncpy(info->serial, serial, sizeof(info->serial));
|
||||||
|
snprintf(info->manufacturer, sizeof(info->manufacturer), "Black Magic Probe (%s)", type);
|
||||||
|
strncpy(info->version, version, sizeof(info->version));
|
||||||
|
break;
|
||||||
|
} else if (found_bmps > 0) {
|
||||||
|
DEBUG_WARN("%2d: %s, Black Magic Debug, Black Magic "
|
||||||
|
"Probe (%s), %s\n", i, serial, type, version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
return (found_bmps == 1 && !cl_opts->opt_list_only) ? 0 : 1;
|
||||||
|
}
|
||||||
|
#endif
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2019-20 Uwe Bonnes <bon@elektron,ikp.physik.tu-darmstadt.de>
|
* Copyright (C) 2019-2021 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -34,6 +34,7 @@
|
|||||||
#include <hidapi.h>
|
#include <hidapi.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#include "bmp_hosted.h"
|
||||||
#include "dap.h"
|
#include "dap.h"
|
||||||
#include "cmsis_dap.h"
|
#include "cmsis_dap.h"
|
||||||
|
|
||||||
@ -44,48 +45,101 @@
|
|||||||
uint8_t dap_caps;
|
uint8_t dap_caps;
|
||||||
uint8_t mode;
|
uint8_t mode;
|
||||||
|
|
||||||
|
typedef enum cmsis_type_s {
|
||||||
|
CMSIS_TYPE_NONE = 0,
|
||||||
|
CMSIS_TYPE_HID,
|
||||||
|
CMSIS_TYPE_BULK
|
||||||
|
} cmsis_type_t;
|
||||||
/*- Variables ---------------------------------------------------------------*/
|
/*- Variables ---------------------------------------------------------------*/
|
||||||
|
static cmsis_type_t type;
|
||||||
|
static libusb_device_handle *usb_handle = NULL;
|
||||||
|
static uint8_t in_ep;
|
||||||
|
static uint8_t out_ep;
|
||||||
static hid_device *handle = NULL;
|
static hid_device *handle = NULL;
|
||||||
static uint8_t hid_buffer[1024 + 1];
|
static uint8_t buffer[1024 + 1];
|
||||||
static int report_size = 512 + 1; // TODO: read actual report size
|
static int report_size = 64 + 1; // TODO: read actual report size
|
||||||
|
static bool has_swd_sequence = false;
|
||||||
|
|
||||||
/* LPC845 Breakout Board Rev. 0 report invalid response with > 65 bytes */
|
/* LPC845 Breakout Board Rev. 0 report invalid response with > 65 bytes */
|
||||||
int dap_init(bmp_info_t *info)
|
int dap_init(bmp_info_t *info)
|
||||||
{
|
{
|
||||||
printf("dap_init\n");
|
type = (info->in_ep && info->out_ep) ? CMSIS_TYPE_BULK : CMSIS_TYPE_HID;
|
||||||
if (hid_init())
|
int size;
|
||||||
return -1;
|
|
||||||
int size = strlen(info->serial);
|
if (type == CMSIS_TYPE_HID) {
|
||||||
wchar_t serial[size + 1], *wc = serial;
|
DEBUG_INFO("Using hid transfer\n");
|
||||||
for (int i = 0; i < size; i++)
|
if (hid_init())
|
||||||
*wc++ = info->serial[i];
|
return -1;
|
||||||
*wc = 0;
|
size = strlen(info->serial);
|
||||||
/* Blacklist devices that do not wirk with 513 byte report length
|
wchar_t serial[64] = {0}, *wc = serial;
|
||||||
* FIXME: Find a solution to decipher from the device.
|
for (int i = 0; i < size; i++)
|
||||||
*/
|
*wc++ = info->serial[i];
|
||||||
if ((info->vid == 0x1fc9) && (info->pid == 0x0132)) {
|
*wc = 0;
|
||||||
DEBUG_WARN("Blacklist\n");
|
/* Blacklist devices that do not work with 513 byte report length
|
||||||
report_size = 64 + 1;
|
* FIXME: Find a solution to decipher from the device.
|
||||||
|
*/
|
||||||
|
if ((info->vid == 0x1fc9) && (info->pid == 0x0132)) {
|
||||||
|
DEBUG_WARN("Blacklist\n");
|
||||||
|
report_size = 64 + 1;
|
||||||
|
}
|
||||||
|
handle = hid_open(info->vid, info->pid, (serial[0]) ? serial : NULL);
|
||||||
|
if (!handle) {
|
||||||
|
DEBUG_WARN("hid_open failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (type == CMSIS_TYPE_BULK) {
|
||||||
|
DEBUG_INFO("Using bulk transfer\n");
|
||||||
|
usb_handle = libusb_open_device_with_vid_pid(info->libusb_ctx, info->vid, info->pid);
|
||||||
|
if (!usb_handle) {
|
||||||
|
DEBUG_WARN("WARN: libusb_open_device_with_vid_pid() failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (libusb_claim_interface(usb_handle, info->interface_num) < 0) {
|
||||||
|
DEBUG_WARN("WARN: libusb_claim_interface() failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
in_ep = info->in_ep;
|
||||||
|
out_ep = info->out_ep;
|
||||||
}
|
}
|
||||||
handle = hid_open(info->vid, info->pid, serial);
|
|
||||||
if (!handle)
|
|
||||||
return -1;
|
|
||||||
dap_disconnect();
|
dap_disconnect();
|
||||||
size = dap_info(DAP_INFO_CAPABILITIES, hid_buffer, sizeof(hid_buffer));
|
size = dap_info(DAP_INFO_FW_VER, buffer, sizeof(buffer));
|
||||||
dap_caps = hid_buffer[0];
|
if (size) {
|
||||||
DEBUG_INFO(" Cap (0x%2x): %s%s%s", hid_buffer[0],
|
DEBUG_INFO("Ver %s, ", buffer);
|
||||||
(hid_buffer[0] & 1)? "SWD" : "",
|
int major = -1, minor = -1, sub = -1;
|
||||||
((hid_buffer[0] & 3) == 3) ? "/" : "",
|
if (sscanf((const char *)buffer, "%d.%d.%d",
|
||||||
(hid_buffer[0] & 2)? "JTAG" : "");
|
&major, &minor, &sub)) {
|
||||||
if (hid_buffer[0] & 4)
|
if (sub == -1) {
|
||||||
|
if (minor >= 10) {
|
||||||
|
minor /= 10;
|
||||||
|
sub = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
has_swd_sequence = ((major > 1 ) || ((major > 0 ) && (minor > 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size = dap_info(DAP_INFO_CAPABILITIES, buffer, sizeof(buffer));
|
||||||
|
dap_caps = buffer[0];
|
||||||
|
DEBUG_INFO("Cap (0x%2x): %s%s%s", dap_caps,
|
||||||
|
(dap_caps & 1)? "SWD" : "",
|
||||||
|
((dap_caps & 3) == 3) ? "/" : "",
|
||||||
|
(dap_caps & 2)? "JTAG" : "");
|
||||||
|
if (dap_caps & 4)
|
||||||
DEBUG_INFO(", SWO_UART");
|
DEBUG_INFO(", SWO_UART");
|
||||||
if (hid_buffer[0] & 8)
|
if (dap_caps & 8)
|
||||||
DEBUG_INFO(", SWO_MANCHESTER");
|
DEBUG_INFO(", SWO_MANCHESTER");
|
||||||
if (hid_buffer[0] & 0x10)
|
if (dap_caps & 0x10)
|
||||||
DEBUG_INFO(", Atomic Cmds");
|
DEBUG_INFO(", Atomic Cmds");
|
||||||
|
if (has_swd_sequence)
|
||||||
|
DEBUG_INFO(", DAP_SWD_Sequence");
|
||||||
DEBUG_INFO("\n");
|
DEBUG_INFO("\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dap_srst_set_val(bool assert)
|
||||||
|
{
|
||||||
|
dap_reset_pin(!assert);
|
||||||
|
}
|
||||||
|
|
||||||
static void dap_dp_abort(ADIv5_DP_t *dp, uint32_t abort)
|
static void dap_dp_abort(ADIv5_DP_t *dp, uint32_t abort)
|
||||||
{
|
{
|
||||||
/* DP Write to Reg 0.*/
|
/* DP Write to Reg 0.*/
|
||||||
@ -94,6 +148,7 @@ static void dap_dp_abort(ADIv5_DP_t *dp, uint32_t abort)
|
|||||||
|
|
||||||
static uint32_t dap_dp_error(ADIv5_DP_t *dp)
|
static uint32_t dap_dp_error(ADIv5_DP_t *dp)
|
||||||
{
|
{
|
||||||
|
/* Not used for SWD debugging, so no TARGETID switch needed!*/
|
||||||
uint32_t ctrlstat = dap_read_reg(dp, ADIV5_DP_CTRLSTAT);
|
uint32_t ctrlstat = dap_read_reg(dp, ADIV5_DP_CTRLSTAT);
|
||||||
uint32_t err = ctrlstat &
|
uint32_t err = ctrlstat &
|
||||||
(ADIV5_DP_CTRLSTAT_STICKYORUN | ADIV5_DP_CTRLSTAT_STICKYCMP |
|
(ADIV5_DP_CTRLSTAT_STICKYORUN | ADIV5_DP_CTRLSTAT_STICKYCMP |
|
||||||
@ -129,23 +184,23 @@ static uint32_t dap_dp_low_access(struct ADIv5_DP_s *dp, uint8_t RnW,
|
|||||||
|
|
||||||
static uint32_t dap_dp_read_reg(ADIv5_DP_t *dp, uint16_t addr)
|
static uint32_t dap_dp_read_reg(ADIv5_DP_t *dp, uint16_t addr)
|
||||||
{
|
{
|
||||||
uint32_t res;
|
uint32_t res = dap_dp_low_access(dp, ADIV5_LOW_READ, addr, 0);
|
||||||
if (addr & ADIV5_APnDP) {
|
|
||||||
dap_dp_low_access(dp, ADIV5_LOW_READ, addr, 0);
|
|
||||||
res = dap_dp_low_access(dp, ADIV5_LOW_READ,
|
|
||||||
ADIV5_DP_RDBUFF, 0);
|
|
||||||
} else {
|
|
||||||
res = dap_dp_low_access(dp, ADIV5_LOW_READ, addr, 0);
|
|
||||||
}
|
|
||||||
DEBUG_PROBE("dp_read %04x %08" PRIx32 "\n", addr, res);
|
DEBUG_PROBE("dp_read %04x %08" PRIx32 "\n", addr, res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dap_exit_function(void)
|
void dap_exit_function(void)
|
||||||
{
|
{
|
||||||
if (handle) {
|
if (type == CMSIS_TYPE_HID) {
|
||||||
dap_disconnect();
|
if (handle) {
|
||||||
hid_close(handle);
|
dap_disconnect();
|
||||||
|
hid_close(handle);
|
||||||
|
}
|
||||||
|
} else if (type == CMSIS_TYPE_BULK) {
|
||||||
|
if (usb_handle) {
|
||||||
|
dap_disconnect();
|
||||||
|
libusb_close(usb_handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,40 +213,56 @@ int dbg_dap_cmd(uint8_t *data, int size, int rsize)
|
|||||||
|
|
||||||
{
|
{
|
||||||
char cmd = data[0];
|
char cmd = data[0];
|
||||||
int res;
|
int res = -1;
|
||||||
|
|
||||||
memset(hid_buffer, 0xff, report_size + 1);
|
memset(buffer, 0xff, report_size + 1);
|
||||||
|
|
||||||
hid_buffer[0] = 0x00; // Report ID??
|
buffer[0] = 0x00; // Report ID??
|
||||||
memcpy(&hid_buffer[1], data, rsize);
|
memcpy(&buffer[1], data, rsize);
|
||||||
|
|
||||||
DEBUG_WIRE("cmd : ");
|
DEBUG_WIRE("cmd : ");
|
||||||
for(int i = 0; (i < 16) && (i < rsize + 1); i++)
|
for(int i = 0; (i < 32) && (i < rsize + 1); i++)
|
||||||
DEBUG_WIRE("%02x.", hid_buffer[i]);
|
DEBUG_WIRE("%02x.", buffer[i]);
|
||||||
DEBUG_WIRE("\n");
|
DEBUG_WIRE("\n");
|
||||||
res = hid_write(handle, hid_buffer, rsize + 1);
|
if (type == CMSIS_TYPE_HID) {
|
||||||
if (res < 0) {
|
res = hid_write(handle, buffer, 65);
|
||||||
DEBUG_WARN( "Error: %ls\n", hid_error(handle));
|
if (res < 0) {
|
||||||
exit(-1);
|
DEBUG_WARN( "Error: %ls\n", hid_error(handle));
|
||||||
}
|
exit(-1);
|
||||||
if (size) {
|
}
|
||||||
res = hid_read(handle, hid_buffer, report_size + 1);
|
res = hid_read_timeout(handle, buffer, 65, 1000);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
DEBUG_WARN( "debugger read(): %ls\n", hid_error(handle));
|
DEBUG_WARN( "debugger read(): %ls\n", hid_error(handle));
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
} else if (res == 0) {
|
||||||
|
DEBUG_WARN( "timeout\n");
|
||||||
|
exit(-1);
|
||||||
}
|
}
|
||||||
if (size && hid_buffer[0] != cmd) {
|
} else if (type == CMSIS_TYPE_BULK) {
|
||||||
DEBUG_WARN("cmd %02x invalid response received %02x\n",
|
int transferred = 0;
|
||||||
cmd, hid_buffer[0]);
|
|
||||||
}
|
|
||||||
res--;
|
|
||||||
memcpy(data, &hid_buffer[1], (size < res) ? size : res);
|
|
||||||
DEBUG_WIRE("cmd res:");
|
|
||||||
for(int i = 0; (i < 16) && (i < size + 4); i++)
|
|
||||||
DEBUG_WIRE("%02x.", hid_buffer[i]);
|
|
||||||
DEBUG_WIRE("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
res = libusb_bulk_transfer(usb_handle, out_ep, data, rsize, &transferred, 500);
|
||||||
|
if (res < 0) {
|
||||||
|
DEBUG_WARN("OUT error: %d\n", res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
res = libusb_bulk_transfer(usb_handle, in_ep, buffer, report_size, &transferred, 500);
|
||||||
|
if (res < 0) {
|
||||||
|
DEBUG_WARN("IN error: %d\n", res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
res = transferred;
|
||||||
|
}
|
||||||
|
DEBUG_WIRE("cmd res:");
|
||||||
|
for(int i = 0; (i < 16) && (i < size + 1); i++)
|
||||||
|
DEBUG_WIRE("%02x.", buffer[i]);
|
||||||
|
DEBUG_WIRE("\n");
|
||||||
|
if (buffer[0] != cmd) {
|
||||||
|
DEBUG_WARN("cmd %02x not implemented\n", cmd);
|
||||||
|
buffer[1] = 0xff /*DAP_ERROR*/;
|
||||||
|
}
|
||||||
|
if (size)
|
||||||
|
memcpy(data, &buffer[1], (size < res) ? size : res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
#define ALIGNOF(x) (((x) & 3) == 0 ? ALIGN_WORD : \
|
#define ALIGNOF(x) (((x) & 3) == 0 ? ALIGN_WORD : \
|
||||||
@ -208,7 +279,7 @@ static void dap_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
|
|||||||
return dap_read_single(ap, dest, src, align);
|
return dap_read_single(ap, dest, src, align);
|
||||||
/* One word transfer for every byte/halfword/word
|
/* One word transfer for every byte/halfword/word
|
||||||
* Total number of bytes in transfer*/
|
* Total number of bytes in transfer*/
|
||||||
unsigned int max_size = (dbg_get_report_size() - 5) >> (2 - align);
|
unsigned int max_size = ((dbg_get_report_size() - 6) >> (2 - align)) & ~3;
|
||||||
while (len) {
|
while (len) {
|
||||||
dap_ap_mem_access_setup(ap, src, align);
|
dap_ap_mem_access_setup(ap, src, align);
|
||||||
/* Calculate length until next access setup is needed */
|
/* Calculate length until next access setup is needed */
|
||||||
@ -245,7 +316,7 @@ static void dap_mem_write_sized(
|
|||||||
dest, len, align, *(uint32_t *)src);
|
dest, len, align, *(uint32_t *)src);
|
||||||
if (((unsigned)(1 << align)) == len)
|
if (((unsigned)(1 << align)) == len)
|
||||||
return dap_write_single(ap, dest, src, align);
|
return dap_write_single(ap, dest, src, align);
|
||||||
unsigned int max_size = (dbg_get_report_size() - 5) >> (2 - align);
|
unsigned int max_size = ((dbg_get_report_size() - 6) >> (2 - align) & ~3);
|
||||||
while (len) {
|
while (len) {
|
||||||
dap_ap_mem_access_setup(ap, dest, align);
|
dap_ap_mem_access_setup(ap, dest, align);
|
||||||
unsigned int blocksize = (dest | 0x3ff) - dest + 1;
|
unsigned int blocksize = (dest | 0x3ff) - dest + 1;
|
||||||
@ -271,27 +342,6 @@ static void dap_mem_write_sized(
|
|||||||
DEBUG_WIRE("memwrite done\n");
|
DEBUG_WIRE("memwrite done\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int dap_enter_debug_swd(ADIv5_DP_t *dp)
|
|
||||||
{
|
|
||||||
target_list_free();
|
|
||||||
if (!(dap_caps & DAP_CAP_SWD))
|
|
||||||
return -1;
|
|
||||||
mode = DAP_CAP_SWD;
|
|
||||||
dap_swj_clock(2000000);
|
|
||||||
dap_transfer_configure(2, 128, 128);
|
|
||||||
dap_swd_configure(0);
|
|
||||||
dap_connect(false);
|
|
||||||
dap_led(0, 1);
|
|
||||||
dap_reset_link(false);
|
|
||||||
|
|
||||||
dp->idcode = dap_read_idcode(dp);
|
|
||||||
dp->dp_read = dap_dp_read_reg;
|
|
||||||
dp->error = dap_dp_error;
|
|
||||||
dp->low_access = dap_dp_low_access;
|
|
||||||
dp->abort = dap_dp_abort; /* DP Write to Reg 0.*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp)
|
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp)
|
||||||
{
|
{
|
||||||
if ((mode == DAP_CAP_JTAG) && dap_jtag_configure())
|
if ((mode == DAP_CAP_JTAG) && dap_jtag_configure())
|
||||||
@ -320,7 +370,7 @@ static void cmsis_dap_jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms,
|
|||||||
const uint8_t *DI, int ticks)
|
const uint8_t *DI, int ticks)
|
||||||
{
|
{
|
||||||
dap_jtagtap_tdi_tdo_seq(DO, (final_tms), NULL, DI, ticks);
|
dap_jtagtap_tdi_tdo_seq(DO, (final_tms), NULL, DI, ticks);
|
||||||
DEBUG_PROBE("jtagtap_tdi_tdo_seq %d, %02x-> %02x\n", ticks, DI[0], DO[0]);
|
DEBUG_PROBE("jtagtap_tdi_tdo_seq %d, %02x-> %02x\n", ticks, DI[0], (DO)? DO[0] : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cmsis_dap_jtagtap_tdi_seq(const uint8_t final_tms,
|
static void cmsis_dap_jtagtap_tdi_seq(const uint8_t final_tms,
|
||||||
@ -346,13 +396,12 @@ int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc)
|
|||||||
mode = DAP_CAP_JTAG;
|
mode = DAP_CAP_JTAG;
|
||||||
dap_disconnect();
|
dap_disconnect();
|
||||||
dap_connect(true);
|
dap_connect(true);
|
||||||
dap_swj_clock(2000000);
|
dap_reset_link(true);
|
||||||
jtag_proc->jtagtap_reset = cmsis_dap_jtagtap_reset;
|
jtag_proc->jtagtap_reset = cmsis_dap_jtagtap_reset;
|
||||||
jtag_proc->jtagtap_next = cmsis_dap_jtagtap_next;
|
jtag_proc->jtagtap_next = cmsis_dap_jtagtap_next;
|
||||||
jtag_proc->jtagtap_tms_seq = cmsis_dap_jtagtap_tms_seq;
|
jtag_proc->jtagtap_tms_seq = cmsis_dap_jtagtap_tms_seq;
|
||||||
jtag_proc->jtagtap_tdi_tdo_seq = cmsis_dap_jtagtap_tdi_tdo_seq;
|
jtag_proc->jtagtap_tdi_tdo_seq = cmsis_dap_jtagtap_tdi_tdo_seq;
|
||||||
jtag_proc->jtagtap_tdi_seq = cmsis_dap_jtagtap_tdi_seq;
|
jtag_proc->jtagtap_tdi_seq = cmsis_dap_jtagtap_tdi_seq;
|
||||||
dap_reset_link(true);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,3 +414,57 @@ int dap_jtag_dp_init(ADIv5_DP_t *dp)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SWD_SEQUENCE_IN 0x80
|
||||||
|
#define DAP_SWD_SEQUENCE 0x1d
|
||||||
|
static bool dap_dp_low_write(ADIv5_DP_t *dp, uint16_t addr, const uint32_t data)
|
||||||
|
{
|
||||||
|
DEBUG_PROBE("dap_dp_low_write %08" PRIx32 "\n", data);
|
||||||
|
(void)dp;
|
||||||
|
unsigned int paket_request = make_packet_request(ADIV5_LOW_WRITE, addr);
|
||||||
|
uint8_t buf[32] = {
|
||||||
|
DAP_SWD_SEQUENCE,
|
||||||
|
5,
|
||||||
|
8,
|
||||||
|
paket_request,
|
||||||
|
4 + SWD_SEQUENCE_IN, /* one turn-around + read 3 bit ACK */
|
||||||
|
1, /* one bit turn around to drive SWDIO */
|
||||||
|
0,
|
||||||
|
32, /* write 32 bit data */
|
||||||
|
(data >> 0) & 0xff,
|
||||||
|
(data >> 8) & 0xff,
|
||||||
|
(data >> 16) & 0xff,
|
||||||
|
(data >> 24) & 0xff,
|
||||||
|
1, /* write parity biT */
|
||||||
|
__builtin_parity(data)
|
||||||
|
};
|
||||||
|
dbg_dap_cmd(buf, sizeof(buf), 14);
|
||||||
|
if (buf[0])
|
||||||
|
DEBUG_WARN("dap_dp_low_write failed\n");
|
||||||
|
uint32_t ack = (buf[1] >> 1) & 7;
|
||||||
|
return (ack != SWDP_ACK_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dap_swdptap_init(ADIv5_DP_t *dp)
|
||||||
|
{
|
||||||
|
if (!(dap_caps & DAP_CAP_SWD))
|
||||||
|
return 1;
|
||||||
|
mode = DAP_CAP_SWD;
|
||||||
|
dap_transfer_configure(2, 128, 128);
|
||||||
|
dap_swd_configure(0);
|
||||||
|
dap_connect(false);
|
||||||
|
dap_led(0, 1);
|
||||||
|
dap_reset_link(false);
|
||||||
|
if ((has_swd_sequence) && dap_sequence_test()) {
|
||||||
|
/* DAP_SWD_SEQUENCE does not do auto turnaround, use own!*/
|
||||||
|
dp->dp_low_write = dap_dp_low_write;
|
||||||
|
} else {
|
||||||
|
dp->dp_low_write = NULL;
|
||||||
|
}
|
||||||
|
dp->seq_out = dap_swdptap_seq_out;
|
||||||
|
dp->dp_read = dap_dp_read_reg;
|
||||||
|
/* For error() use the TARGETID switching firmware_swdp_error */
|
||||||
|
dp->low_access = dap_dp_low_access;
|
||||||
|
dp->abort = dap_dp_abort;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2019 Uwe Bonnes
|
* Copyright (C) 2019 - 2021 Uwe Bonnes(bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -24,11 +24,14 @@
|
|||||||
|
|
||||||
#if defined(CMSIS_DAP)
|
#if defined(CMSIS_DAP)
|
||||||
int dap_init(bmp_info_t *info);
|
int dap_init(bmp_info_t *info);
|
||||||
int dap_enter_debug_swd(ADIv5_DP_t *dp);
|
|
||||||
void dap_exit_function(void);
|
void dap_exit_function(void);
|
||||||
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp);
|
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp);
|
||||||
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc);
|
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc);
|
||||||
|
int dap_swdptap_init(ADIv5_DP_t *dp);
|
||||||
int dap_jtag_dp_init(ADIv5_DP_t *dp);
|
int dap_jtag_dp_init(ADIv5_DP_t *dp);
|
||||||
|
uint32_t dap_swj_clock(uint32_t clock);
|
||||||
|
void dap_swd_configure(uint8_t cfg);
|
||||||
|
void dap_srst_set_val(bool assert);
|
||||||
#else
|
#else
|
||||||
int dap_init(bmp_info_t *info)
|
int dap_init(bmp_info_t *info)
|
||||||
{
|
{
|
||||||
@ -36,19 +39,17 @@ int dap_init(bmp_info_t *info)
|
|||||||
(void)info;
|
(void)info;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int dap_enter_debug_swd(ADIv5_DP_t *dp) {(void)dp; return -1;}
|
# pragma GCC diagnostic push
|
||||||
void dap_exit_function(void) {return;};
|
# pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||||
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp) {(void)dp; return; }
|
uint32_t dap_swj_clock(uint32_t clock) {return 0;}
|
||||||
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc)
|
void dap_exit_function(void) {};
|
||||||
{
|
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp) {};
|
||||||
(void)jtag_proc;
|
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc) {return -1;}
|
||||||
return -1;
|
int dap_swdptap_init(ADIv5_DP_t *dp) {return -1;}
|
||||||
}
|
int dap_jtag_dp_init(ADIv5_DP_t *dp) {return -1;}
|
||||||
int dap_jtag_dp_init(ADIv5_DP_t *dp)
|
void dap_swd_configure(uint8_t cfg) {};
|
||||||
{
|
void dap_srst_set_val(bool assert) {};
|
||||||
(void)dp;
|
# pragma GCC diagnostic pop
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -27,12 +27,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Modified for Blackmagic Probe
|
/* Modified for Blackmagic Probe
|
||||||
* Copyright (c) 2020 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de
|
* Copyright (c) 2020-21 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*- Includes ----------------------------------------------------------------*/
|
/*- Includes ----------------------------------------------------------------*/
|
||||||
#include <general.h>
|
#include <general.h>
|
||||||
#include <stdlib.h>
|
#include "exception.h"
|
||||||
#include "dap.h"
|
#include "dap.h"
|
||||||
#include "jtag_scan.h"
|
#include "jtag_scan.h"
|
||||||
|
|
||||||
@ -57,6 +57,7 @@ enum
|
|||||||
ID_DAP_JTAG_SEQUENCE = 0x14,
|
ID_DAP_JTAG_SEQUENCE = 0x14,
|
||||||
ID_DAP_JTAG_CONFIGURE = 0x15,
|
ID_DAP_JTAG_CONFIGURE = 0x15,
|
||||||
ID_DAP_JTAG_IDCODE = 0x16,
|
ID_DAP_JTAG_IDCODE = 0x16,
|
||||||
|
ID_DAP_SWD_SEQUENCE = 0x1D,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@ -197,24 +198,33 @@ void dap_connect(bool jtag)
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void dap_disconnect(void)
|
void dap_disconnect(void)
|
||||||
{
|
{
|
||||||
uint8_t buf[1];
|
uint8_t buf[65];
|
||||||
|
|
||||||
buf[0] = ID_DAP_DISCONNECT;
|
buf[0] = ID_DAP_DISCONNECT;
|
||||||
dbg_dap_cmd(buf, sizeof(buf), 1);
|
dbg_dap_cmd(buf, sizeof(buf), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
static uint32_t swj_clock;
|
||||||
void dap_swj_clock(uint32_t clock)
|
/* Set/Get JTAG/SWD clock frequency
|
||||||
|
*
|
||||||
|
* With clock == 0, return last set value.
|
||||||
|
*/
|
||||||
|
uint32_t dap_swj_clock(uint32_t clock)
|
||||||
{
|
{
|
||||||
|
if (clock == 0)
|
||||||
|
return swj_clock;
|
||||||
uint8_t buf[5];
|
uint8_t buf[5];
|
||||||
|
|
||||||
buf[0] = ID_DAP_SWJ_CLOCK;
|
buf[0] = ID_DAP_SWJ_CLOCK;
|
||||||
buf[1] = clock & 0xff;
|
buf[1] = clock & 0xff;
|
||||||
buf[2] = (clock >> 8) & 0xff;
|
buf[2] = (clock >> 8) & 0xff;
|
||||||
buf[3] = (clock >> 16) & 0xff;
|
buf[3] = (clock >> 16) & 0xff;
|
||||||
buf[4] = (clock >> 24) & 0xff;
|
buf[4] = (clock >> 24) & 0xff;
|
||||||
dbg_dap_cmd(buf, sizeof(buf), 5);
|
dbg_dap_cmd(buf, sizeof(buf), 5);
|
||||||
|
if (buf[0])
|
||||||
|
DEBUG_WARN("dap_swj_clock failed\n");
|
||||||
|
else
|
||||||
|
swj_clock = clock;
|
||||||
|
return swj_clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -268,9 +278,9 @@ void dap_reset_pin(int state)
|
|||||||
buf[1] = state ? DAP_SWJ_nRESET : 0; // Value
|
buf[1] = state ? DAP_SWJ_nRESET : 0; // Value
|
||||||
buf[2] = DAP_SWJ_nRESET; // Select
|
buf[2] = DAP_SWJ_nRESET; // Select
|
||||||
buf[3] = 0; // Wait
|
buf[3] = 0; // Wait
|
||||||
buf[4] = 0;
|
buf[4] = 0; // Wait
|
||||||
buf[5] = 0;
|
buf[5] = 0; // Wait
|
||||||
buf[6] = 0;
|
buf[6] = 0; // Wait
|
||||||
dbg_dap_cmd(buf, sizeof(buf), 7);
|
dbg_dap_cmd(buf, sizeof(buf), 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,20 +324,22 @@ static void dap_line_reset(void)
|
|||||||
|
|
||||||
static uint32_t wait_word(uint8_t *buf, int size, int len, uint8_t *dp_fault)
|
static uint32_t wait_word(uint8_t *buf, int size, int len, uint8_t *dp_fault)
|
||||||
{
|
{
|
||||||
|
uint8_t cmd_copy[len];
|
||||||
|
memcpy(cmd_copy, buf, len);
|
||||||
do {
|
do {
|
||||||
|
memcpy(buf, cmd_copy, len);
|
||||||
dbg_dap_cmd(buf, size, len);
|
dbg_dap_cmd(buf, size, len);
|
||||||
if (buf[1] < DAP_TRANSFER_WAIT)
|
if (buf[1] < DAP_TRANSFER_WAIT)
|
||||||
break;
|
break;
|
||||||
} while (buf[1] == DAP_TRANSFER_WAIT);
|
} while (buf[1] == DAP_TRANSFER_WAIT);
|
||||||
|
|
||||||
if (buf[1] > DAP_TRANSFER_WAIT) {
|
if(buf[1] == SWDP_ACK_FAULT) {
|
||||||
// DEBUG_WARN("dap_read_reg fault\n");
|
|
||||||
*dp_fault = 1;
|
*dp_fault = 1;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
if (buf[1] == DAP_TRANSFER_ERROR) {
|
|
||||||
DEBUG_WARN("dap_read_reg, protocoll error\n");
|
if(buf[1] != SWDP_ACK_OK)
|
||||||
dap_line_reset();
|
raise_exception(EXCEPTION_ERROR, "SWDP invalid ACK");
|
||||||
}
|
|
||||||
uint32_t res =
|
uint32_t res =
|
||||||
((uint32_t)buf[5] << 24) | ((uint32_t)buf[4] << 16) |
|
((uint32_t)buf[5] << 24) | ((uint32_t)buf[4] << 16) |
|
||||||
((uint32_t)buf[3] << 8) | (uint32_t)buf[2];
|
((uint32_t)buf[3] << 8) | (uint32_t)buf[2];
|
||||||
@ -339,8 +351,7 @@ uint32_t dap_read_reg(ADIv5_DP_t *dp, uint8_t reg)
|
|||||||
{
|
{
|
||||||
uint8_t buf[8];
|
uint8_t buf[8];
|
||||||
uint8_t dap_index = 0;
|
uint8_t dap_index = 0;
|
||||||
if (dp->dev)
|
dap_index = dp->dp_jd_index;
|
||||||
dap_index = dp->dev->dev;
|
|
||||||
buf[0] = ID_DAP_TRANSFER;
|
buf[0] = ID_DAP_TRANSFER;
|
||||||
buf[1] = dap_index;
|
buf[1] = dap_index;
|
||||||
buf[2] = 0x01; // Request size
|
buf[2] = 0x01; // Request size
|
||||||
@ -358,8 +369,7 @@ void dap_write_reg(ADIv5_DP_t *dp, uint8_t reg, uint32_t data)
|
|||||||
|
|
||||||
buf[0] = ID_DAP_TRANSFER;
|
buf[0] = ID_DAP_TRANSFER;
|
||||||
uint8_t dap_index = 0;
|
uint8_t dap_index = 0;
|
||||||
if (dp->dev)
|
dap_index = dp->dp_jd_index;
|
||||||
dap_index = dp->dev->dev;
|
|
||||||
buf[1] = dap_index;
|
buf[1] = dap_index;
|
||||||
buf[2] = 0x01; // Request size
|
buf[2] = 0x01; // Request size
|
||||||
buf[3] = reg & ~DAP_TRANSFER_RnW;;
|
buf[3] = reg & ~DAP_TRANSFER_RnW;;
|
||||||
@ -367,7 +377,10 @@ void dap_write_reg(ADIv5_DP_t *dp, uint8_t reg, uint32_t data)
|
|||||||
buf[5] = (data >> 8) & 0xff;
|
buf[5] = (data >> 8) & 0xff;
|
||||||
buf[6] = (data >> 16) & 0xff;
|
buf[6] = (data >> 16) & 0xff;
|
||||||
buf[7] = (data >> 24) & 0xff;
|
buf[7] = (data >> 24) & 0xff;
|
||||||
|
uint8_t cmd_copy[8];
|
||||||
|
memcpy(cmd_copy, buf, 8);
|
||||||
do {
|
do {
|
||||||
|
memcpy(buf, cmd_copy, 8);
|
||||||
dbg_dap_cmd(buf, sizeof(buf), 8);
|
dbg_dap_cmd(buf, sizeof(buf), 8);
|
||||||
if (buf[1] < DAP_TRANSFER_WAIT)
|
if (buf[1] < DAP_TRANSFER_WAIT)
|
||||||
break;
|
break;
|
||||||
@ -390,17 +403,16 @@ unsigned int dap_read_block(ADIv5_AP_t *ap, void *dest, uint32_t src,
|
|||||||
uint8_t buf[1024];
|
uint8_t buf[1024];
|
||||||
unsigned int sz = len >> align;
|
unsigned int sz = len >> align;
|
||||||
uint8_t dap_index = 0;
|
uint8_t dap_index = 0;
|
||||||
if (ap->dp->dev)
|
dap_index = ap->dp->dp_jd_index;
|
||||||
dap_index = ap->dp->dev->dev;
|
|
||||||
buf[0] = ID_DAP_TRANSFER_BLOCK;
|
buf[0] = ID_DAP_TRANSFER_BLOCK;
|
||||||
buf[1] = dap_index;
|
buf[1] = dap_index;
|
||||||
buf[2] = sz & 0xff;
|
buf[2] = sz & 0xff;
|
||||||
buf[3] = (sz >> 8) & 0xff;
|
buf[3] = (sz >> 8) & 0xff;
|
||||||
buf[4] = SWD_AP_DRW | DAP_TRANSFER_RnW;
|
buf[4] = SWD_AP_DRW | DAP_TRANSFER_RnW;
|
||||||
dbg_dap_cmd(buf, 1023, 5 + 1);
|
dbg_dap_cmd(buf, 1023, 5);
|
||||||
unsigned int transferred = buf[0] + (buf[1] << 8);
|
unsigned int transferred = buf[0] + (buf[1] << 8);
|
||||||
if (buf[2] >= DAP_TRANSFER_FAULT) {
|
if (buf[2] >= DAP_TRANSFER_FAULT) {
|
||||||
DEBUG_WARN("dap_read_block @ %08 "PRIx32 " fault -> line reset\n", src);
|
DEBUG_WARN("dap_read_block @ %08" PRIx32 " fault -> line reset\n", src);
|
||||||
dap_line_reset();
|
dap_line_reset();
|
||||||
}
|
}
|
||||||
if (sz != transferred) {
|
if (sz != transferred) {
|
||||||
@ -413,7 +425,6 @@ unsigned int dap_read_block(ADIv5_AP_t *ap, void *dest, uint32_t src,
|
|||||||
dest = extract(dest, src, *p, align);
|
dest = extract(dest, src, *p, align);
|
||||||
p++;
|
p++;
|
||||||
src += (1 << align);
|
src += (1 << align);
|
||||||
dest += (1 << align);
|
|
||||||
sz--;
|
sz--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -426,8 +437,7 @@ unsigned int dap_write_block(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
|||||||
uint8_t buf[1024];
|
uint8_t buf[1024];
|
||||||
unsigned int sz = len >> align;
|
unsigned int sz = len >> align;
|
||||||
uint8_t dap_index = 0;
|
uint8_t dap_index = 0;
|
||||||
if (ap->dp->dev)
|
dap_index = ap->dp->dp_jd_index;
|
||||||
dap_index = ap->dp->dev->dev;
|
|
||||||
buf[0] = ID_DAP_TRANSFER_BLOCK;
|
buf[0] = ID_DAP_TRANSFER_BLOCK;
|
||||||
buf[1] = dap_index;
|
buf[1] = dap_index;
|
||||||
buf[2] = sz & 0xff;
|
buf[2] = sz & 0xff;
|
||||||
@ -527,8 +537,7 @@ static uint8_t *mem_access_setup(ADIv5_AP_t *ap, uint8_t *p,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
uint8_t dap_index = 0;
|
uint8_t dap_index = 0;
|
||||||
if (ap->dp->dev)
|
dap_index = ap->dp->dp_jd_index;
|
||||||
dap_index = ap->dp->dev->dev;
|
|
||||||
*p++ = ID_DAP_TRANSFER;
|
*p++ = ID_DAP_TRANSFER;
|
||||||
*p++ = dap_index;
|
*p++ = dap_index;
|
||||||
*p++ = 3; /* Nr transfers */
|
*p++ = 3; /* Nr transfers */
|
||||||
@ -559,12 +568,11 @@ void dap_ap_mem_access_setup(ADIv5_AP_t *ap, uint32_t addr, enum align align)
|
|||||||
|
|
||||||
uint32_t dap_ap_read(ADIv5_AP_t *ap, uint16_t addr)
|
uint32_t dap_ap_read(ADIv5_AP_t *ap, uint16_t addr)
|
||||||
{
|
{
|
||||||
DEBUG_PROBE("dap_ap_read_start\n");
|
DEBUG_PROBE("dap_ap_read_start addr %x\n", addr);
|
||||||
uint8_t buf[63], *p = buf;
|
uint8_t buf[63], *p = buf;
|
||||||
buf[0] = ID_DAP_TRANSFER;
|
buf[0] = ID_DAP_TRANSFER;
|
||||||
uint8_t dap_index = 0;
|
uint8_t dap_index = 0;
|
||||||
if (ap->dp->dev)
|
dap_index = ap->dp->dp_jd_index;
|
||||||
dap_index = ap->dp->dev->dev;
|
|
||||||
*p++ = ID_DAP_TRANSFER;
|
*p++ = ID_DAP_TRANSFER;
|
||||||
*p++ = dap_index;
|
*p++ = dap_index;
|
||||||
*p++ = 2; /* Nr transfers */
|
*p++ = 2; /* Nr transfers */
|
||||||
@ -576,6 +584,9 @@ uint32_t dap_ap_read(ADIv5_AP_t *ap, uint16_t addr)
|
|||||||
*p++ = (addr & 0x0c) | DAP_TRANSFER_RnW |
|
*p++ = (addr & 0x0c) | DAP_TRANSFER_RnW |
|
||||||
((addr & 0x100) ? DAP_TRANSFER_APnDP : 0);
|
((addr & 0x100) ? DAP_TRANSFER_APnDP : 0);
|
||||||
uint32_t res = wait_word(buf, 63, p - buf, &ap->dp->fault);
|
uint32_t res = wait_word(buf, 63, p - buf, &ap->dp->fault);
|
||||||
|
if ((buf[0] != 2) || (buf[1] != 1)) {
|
||||||
|
DEBUG_WARN("dap_ap_read error %x\n", buf[1]);
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -584,8 +595,7 @@ void dap_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value)
|
|||||||
DEBUG_PROBE("dap_ap_write addr %04x value %08x\n", addr, value);
|
DEBUG_PROBE("dap_ap_write addr %04x value %08x\n", addr, value);
|
||||||
uint8_t buf[63], *p = buf;
|
uint8_t buf[63], *p = buf;
|
||||||
uint8_t dap_index = 0;
|
uint8_t dap_index = 0;
|
||||||
if (ap->dp->dev)
|
dap_index = ap->dp->dp_jd_index;
|
||||||
dap_index = ap->dp->dev->dev;
|
|
||||||
*p++ = ID_DAP_TRANSFER;
|
*p++ = ID_DAP_TRANSFER;
|
||||||
*p++ = dap_index;
|
*p++ = dap_index;
|
||||||
*p++ = 2; /* Nr transfers */
|
*p++ = 2; /* Nr transfers */
|
||||||
@ -600,6 +610,9 @@ void dap_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value)
|
|||||||
*p++ = (value >> 16) & 0xff;
|
*p++ = (value >> 16) & 0xff;
|
||||||
*p++ = (value >> 24) & 0xff;
|
*p++ = (value >> 24) & 0xff;
|
||||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||||
|
if ((buf[0] != 2) || (buf[1] != 1)) {
|
||||||
|
DEBUG_WARN("dap_ap_write error %x\n", buf[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dap_read_single(ADIv5_AP_t *ap, void *dest, uint32_t src, enum align align)
|
void dap_read_single(ADIv5_AP_t *ap, void *dest, uint32_t src, enum align align)
|
||||||
@ -607,7 +620,8 @@ void dap_read_single(ADIv5_AP_t *ap, void *dest, uint32_t src, enum align align)
|
|||||||
uint8_t buf[63];
|
uint8_t buf[63];
|
||||||
uint8_t *p = mem_access_setup(ap, buf, src, align);
|
uint8_t *p = mem_access_setup(ap, buf, src, align);
|
||||||
*p++ = SWD_AP_DRW | DAP_TRANSFER_RnW;
|
*p++ = SWD_AP_DRW | DAP_TRANSFER_RnW;
|
||||||
buf[2] = 4;
|
*p++ = SWD_DP_R_RDBUFF | DAP_TRANSFER_RnW;
|
||||||
|
buf[2] = 5;
|
||||||
uint32_t tmp = wait_word(buf, 63, p - buf, &ap->dp->fault);
|
uint32_t tmp = wait_word(buf, 63, p - buf, &ap->dp->fault);
|
||||||
dest = extract(dest, src, tmp, align);
|
dest = extract(dest, src, tmp, align);
|
||||||
}
|
}
|
||||||
@ -643,15 +657,16 @@ void dap_write_single(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
|||||||
void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
||||||
const uint8_t *DI, int ticks)
|
const uint8_t *DI, int ticks)
|
||||||
{
|
{
|
||||||
|
DEBUG_PROBE("dap_jtagtap_tdi_tdo_seq %s %d ticks\n",
|
||||||
|
(final_tms) ? "final" : "", ticks);
|
||||||
uint8_t buf[64];
|
uint8_t buf[64];
|
||||||
|
const uint8_t *din = DI;
|
||||||
|
uint8_t *dout = DO;
|
||||||
if (!TMS) {
|
if (!TMS) {
|
||||||
int last_byte = 0;
|
int last_byte = last_byte = (ticks - 1) >> 3;
|
||||||
int last_bit = 0;
|
int last_bit = (ticks - 1) & 7;
|
||||||
if (final_tms) {
|
if (final_tms)
|
||||||
last_byte = ticks >> 3;
|
|
||||||
last_bit = ticks & 7;
|
|
||||||
ticks --;
|
ticks --;
|
||||||
}
|
|
||||||
while (ticks) {
|
while (ticks) {
|
||||||
int transfers = ticks;
|
int transfers = ticks;
|
||||||
if (transfers > 64)
|
if (transfers > 64)
|
||||||
@ -659,11 +674,12 @@ void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
|||||||
uint8_t *p = buf;
|
uint8_t *p = buf;
|
||||||
*p++ = ID_DAP_JTAG_SEQUENCE;
|
*p++ = ID_DAP_JTAG_SEQUENCE;
|
||||||
*p++ = 1;
|
*p++ = 1;
|
||||||
*p++ = transfers | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0);
|
*p++ = ((transfers == 64) ? 0 : transfers) |
|
||||||
|
((DO) ? DAP_JTAG_TDO_CAPTURE : 0);
|
||||||
int n_di_bytes = (transfers + 7) >> 3;
|
int n_di_bytes = (transfers + 7) >> 3;
|
||||||
if (DI) {
|
if (din) {
|
||||||
p = memcpy(p, DI, n_di_bytes);
|
p = memcpy(p, din, n_di_bytes);
|
||||||
DI += n_di_bytes;
|
din += n_di_bytes;
|
||||||
} else {
|
} else {
|
||||||
p = memset(p, 0xff, n_di_bytes);
|
p = memset(p, 0xff, n_di_bytes);
|
||||||
}
|
}
|
||||||
@ -671,9 +687,9 @@ void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
|||||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||||
if (buf[0] != DAP_OK)
|
if (buf[0] != DAP_OK)
|
||||||
DEBUG_WARN("dap_jtagtap_tdi_tdo_seq failed %02x\n", buf[0]);
|
DEBUG_WARN("dap_jtagtap_tdi_tdo_seq failed %02x\n", buf[0]);
|
||||||
if (DO) {
|
if (dout) {
|
||||||
memcpy(DO, &buf[1], (transfers + 7) >> 3);
|
memcpy(dout, &buf[1], (transfers + 7) >> 3);
|
||||||
DO += (transfers + 7) >> 3;
|
dout += (transfers + 7) >> 3;
|
||||||
}
|
}
|
||||||
ticks -= transfers;
|
ticks -= transfers;
|
||||||
}
|
}
|
||||||
@ -681,8 +697,8 @@ void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
|||||||
uint8_t *p = buf;
|
uint8_t *p = buf;
|
||||||
*p++ = ID_DAP_JTAG_SEQUENCE;
|
*p++ = ID_DAP_JTAG_SEQUENCE;
|
||||||
*p++ = 1;
|
*p++ = 1;
|
||||||
*p++ = 1 | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0) | DAP_JTAG_TMS;
|
*p++ = 1 | ((dout) ? DAP_JTAG_TDO_CAPTURE : 0) | DAP_JTAG_TMS;
|
||||||
if (DI) {
|
if (din) {
|
||||||
*p++ = ((DI[last_byte] & (1 << last_bit)) ? 1 : 0);
|
*p++ = ((DI[last_byte] & (1 << last_bit)) ? 1 : 0);
|
||||||
} else {
|
} else {
|
||||||
*p++ = 0;
|
*p++ = 0;
|
||||||
@ -690,7 +706,7 @@ void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
|||||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||||
if (buf[0] == DAP_ERROR)
|
if (buf[0] == DAP_ERROR)
|
||||||
DEBUG_WARN("dap_jtagtap_tdi_tdo_seq failed %02x\n", buf[0]);
|
DEBUG_WARN("dap_jtagtap_tdi_tdo_seq failed %02x\n", buf[0]);
|
||||||
if (DO) {
|
if (dout) {
|
||||||
if (buf[1] & 1)
|
if (buf[1] & 1)
|
||||||
DO[last_byte] |= (1 << last_bit);
|
DO[last_byte] |= (1 << last_bit);
|
||||||
else
|
else
|
||||||
@ -708,11 +724,11 @@ void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
|||||||
*p++ = transfers;
|
*p++ = transfers;
|
||||||
for (int i = 0; i < transfers; i++) {
|
for (int i = 0; i < transfers; i++) {
|
||||||
*p++ = 1 | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0) |
|
*p++ = 1 | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0) |
|
||||||
((TMS[i >> 8] & (1 << (i & 7))) ? DAP_JTAG_TMS : 0);
|
((TMS[i >> 3] & (1 << (i & 7))) ? DAP_JTAG_TMS : 0);
|
||||||
if (DI)
|
if (DI)
|
||||||
*p++ = (DI[i >> 8] & (1 << (i & 7))) ? 1 : 0;
|
*p++ = (DI[i >> 3] & (1 << (i & 7))) ? 1 : 0;
|
||||||
else
|
else
|
||||||
*p++ = 0x55;
|
*p++ = 1;
|
||||||
}
|
}
|
||||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||||
if (buf[0] == DAP_ERROR)
|
if (buf[0] == DAP_ERROR)
|
||||||
@ -720,9 +736,9 @@ void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
|||||||
if (DO) {
|
if (DO) {
|
||||||
for (int i = 0; i < transfers; i++) {
|
for (int i = 0; i < transfers; i++) {
|
||||||
if (buf[i + 1])
|
if (buf[i + 1])
|
||||||
DO[i >> 8] |= (1 << (i & 7));
|
DO[i >> 3] |= (1 << (i & 7));
|
||||||
else
|
else
|
||||||
DO[i >> 8] &= ~(1 << (i & 7));
|
DO[i >> 3] &= ~(1 << (i & 7));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ticks -= transfers;
|
ticks -= transfers;
|
||||||
@ -748,3 +764,86 @@ int dap_jtag_configure(void)
|
|||||||
DEBUG_WARN("dap_jtag_configure Failed %02x\n", buf[0]);
|
DEBUG_WARN("dap_jtag_configure Failed %02x\n", buf[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dap_swdptap_seq_out(uint32_t MS, int ticks)
|
||||||
|
{
|
||||||
|
uint8_t buf[64] = {
|
||||||
|
ID_DAP_SWJ_SEQUENCE,
|
||||||
|
ticks,
|
||||||
|
(MS >> 0) & 0xff,
|
||||||
|
(MS >> 8) & 0xff,
|
||||||
|
(MS >> 16) & 0xff,
|
||||||
|
(MS >> 24) & 0xff
|
||||||
|
};
|
||||||
|
dbg_dap_cmd(buf, 64, 2 + ((ticks +7) >> 3));
|
||||||
|
if (buf[0])
|
||||||
|
DEBUG_WARN("dap_swdptap_seq_out error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void dap_swdptap_seq_out_parity(uint32_t MS, int ticks)
|
||||||
|
{
|
||||||
|
uint8_t buf[] = {
|
||||||
|
ID_DAP_SWJ_SEQUENCE,
|
||||||
|
ticks + 1,
|
||||||
|
(MS >> 0) & 0xff,
|
||||||
|
(MS >> 8) & 0xff,
|
||||||
|
(MS >> 16) & 0xff,
|
||||||
|
(MS >> 24) & 0xff,
|
||||||
|
__builtin_parity(MS) & 1
|
||||||
|
};
|
||||||
|
dbg_dap_cmd(buf, 1, sizeof(buf));
|
||||||
|
if (buf[0])
|
||||||
|
DEBUG_WARN("dap_swdptap_seq_out error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dap_sequence_test(void)
|
||||||
|
{
|
||||||
|
uint8_t buf[4] = {
|
||||||
|
ID_DAP_SWD_SEQUENCE,
|
||||||
|
0x1,
|
||||||
|
0x81, /* Read one bit */
|
||||||
|
0 /* one idle cycle */
|
||||||
|
};
|
||||||
|
dbg_dap_cmd(buf, sizeof(buf), 3);
|
||||||
|
return (buf[0] == DAP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SWD_SEQUENCE_IN 0x80
|
||||||
|
uint32_t dap_swdptap_seq_in(int ticks)
|
||||||
|
{
|
||||||
|
uint8_t buf[5] = {
|
||||||
|
ID_DAP_SWD_SEQUENCE,
|
||||||
|
1,
|
||||||
|
ticks + SWD_SEQUENCE_IN
|
||||||
|
};
|
||||||
|
dbg_dap_cmd(buf, 2 + ((ticks + 7) >> 3), 3);
|
||||||
|
uint32_t res = 0;
|
||||||
|
int len = (ticks + 7) >> 3;
|
||||||
|
while (len--) {
|
||||||
|
res <<= 8;
|
||||||
|
res += buf[len + 1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dap_swdptap_seq_in_parity(uint32_t *ret, int ticks)
|
||||||
|
{
|
||||||
|
(void)ticks;
|
||||||
|
uint8_t buf[8] = {
|
||||||
|
ID_DAP_SWD_SEQUENCE,
|
||||||
|
1,
|
||||||
|
33 + SWD_SEQUENCE_IN,
|
||||||
|
};
|
||||||
|
dbg_dap_cmd(buf, 7, 4);
|
||||||
|
uint32_t res = 0;
|
||||||
|
int len = 4;
|
||||||
|
while (len--) {
|
||||||
|
res <<= 8;
|
||||||
|
res += buf[len + 1];
|
||||||
|
}
|
||||||
|
*ret = res;
|
||||||
|
unsigned int parity = __builtin_parity(res) & 1;
|
||||||
|
parity ^= (buf[5] % 1);
|
||||||
|
DEBUG_WARN("Res %08" PRIx32" %d\n", *ret, parity & 1);
|
||||||
|
return (!(parity & 1));
|
||||||
|
}
|
||||||
|
@ -65,11 +65,11 @@ enum
|
|||||||
void dap_led(int index, int state);
|
void dap_led(int index, int state);
|
||||||
void dap_connect(bool jtag);
|
void dap_connect(bool jtag);
|
||||||
void dap_disconnect(void);
|
void dap_disconnect(void);
|
||||||
void dap_swj_clock(uint32_t clock);
|
|
||||||
void dap_transfer_configure(uint8_t idle, uint16_t count, uint16_t retry);
|
void dap_transfer_configure(uint8_t idle, uint16_t count, uint16_t retry);
|
||||||
void dap_swd_configure(uint8_t cfg);
|
void dap_swd_configure(uint8_t cfg);
|
||||||
int dap_info(int info, uint8_t *data, int size);
|
int dap_info(int info, uint8_t *data, int size);
|
||||||
void dap_reset_target(void);
|
void dap_reset_target(void);
|
||||||
|
void dap_srst_set_val(bool assert);
|
||||||
void dap_trst_reset(void);
|
void dap_trst_reset(void);
|
||||||
void dap_reset_target_hw(int state);
|
void dap_reset_target_hw(int state);
|
||||||
void dap_reset_pin(int state);
|
void dap_reset_pin(int state);
|
||||||
@ -91,4 +91,7 @@ int dbg_dap_cmd(uint8_t *data, int size, int rsize);
|
|||||||
void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
||||||
const uint8_t *DI, int ticks);
|
const uint8_t *DI, int ticks);
|
||||||
int dap_jtag_configure(void);
|
int dap_jtag_configure(void);
|
||||||
|
void dap_swdptap_seq_out(uint32_t MS, int ticks);
|
||||||
|
void dap_swdptap_seq_out_parity(uint32_t MS, int ticks);
|
||||||
|
bool dap_sequence_test(void);
|
||||||
#endif // _DAP_H_
|
#endif // _DAP_H_
|
||||||
|
@ -20,8 +20,6 @@
|
|||||||
*/
|
*/
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "gdb_if.h"
|
#include "gdb_if.h"
|
||||||
#include "version.h"
|
|
||||||
#include "platform.h"
|
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -29,6 +27,7 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include "ftdi_bmp.h"
|
#include "ftdi_bmp.h"
|
||||||
|
#include <ftdi.h>
|
||||||
|
|
||||||
struct ftdi_context *ftdic;
|
struct ftdi_context *ftdic;
|
||||||
|
|
||||||
@ -124,8 +123,8 @@ cable_desc_t cable_desc[] = {
|
|||||||
.init.ddr_low = PIN4,
|
.init.ddr_low = PIN4,
|
||||||
.init.data_high = PIN4 | PIN3 | PIN2,
|
.init.data_high = PIN4 | PIN3 | PIN2,
|
||||||
.init.ddr_high = PIN4 | PIN3 | PIN2 | PIN1 | PIN0,
|
.init.ddr_high = PIN4 | PIN3 | PIN2 | PIN1 | PIN0,
|
||||||
.assert_srst.data_high = ~PIN2,
|
.assert_srst.data_high = ~PIN3,
|
||||||
.deassert_srst.data_high = PIN2,
|
.deassert_srst.data_high = PIN3,
|
||||||
.srst_get_port_cmd = GET_BITS_LOW,
|
.srst_get_port_cmd = GET_BITS_LOW,
|
||||||
.srst_get_pin = PIN6,
|
.srst_get_pin = PIN6,
|
||||||
.description = "FTDIJTAG",
|
.description = "FTDIJTAG",
|
||||||
@ -270,7 +269,7 @@ int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
|||||||
int err;
|
int err;
|
||||||
cable_desc_t *cable = &cable_desc[0];
|
cable_desc_t *cable = &cable_desc[0];
|
||||||
for(; cable->name; cable++) {
|
for(; cable->name; cable++) {
|
||||||
if (strcmp(cable->name, cl_opts->opt_cable) == 0)
|
if (strncmp(cable->name, cl_opts->opt_cable, strlen(cable->name)) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,7 +281,7 @@ int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
|||||||
active_cable = cable;
|
active_cable = cable;
|
||||||
memcpy(&active_state, &active_cable->init, sizeof(data_desc_t));
|
memcpy(&active_state, &active_cable->init, sizeof(data_desc_t));
|
||||||
/* If swd_(read|write) is not given for the selected cable and
|
/* If swd_(read|write) is not given for the selected cable and
|
||||||
the 'r' command line argument is give, assume resistor SWD
|
the 'e' command line argument is give, assume resistor SWD
|
||||||
connection.*/
|
connection.*/
|
||||||
if (cl_opts->external_resistor_swd &&
|
if (cl_opts->external_resistor_swd &&
|
||||||
(active_cable->mpsse_swd_read.set_data_low == 0) &&
|
(active_cable->mpsse_swd_read.set_data_low == 0) &&
|
||||||
@ -341,23 +340,27 @@ int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
|||||||
goto error_2;
|
goto error_2;
|
||||||
}
|
}
|
||||||
assert(ftdic != NULL);
|
assert(ftdic != NULL);
|
||||||
err = ftdi_usb_purge_buffers(ftdic);
|
#ifdef _Ftdi_Pragma
|
||||||
|
err = ftdi_tcioflush(ftdic);
|
||||||
|
#else
|
||||||
|
err = ftdi_usb_purge_buffers(ftdic);
|
||||||
|
#endif
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
fprintf(stderr, "ftdi_usb_purge_buffer: %d: %s\n",
|
DEBUG_WARN("ftdi_tcioflush(ftdi_usb_purge_buffer): %d: %s\n",
|
||||||
err, ftdi_get_error_string(ftdic));
|
err, ftdi_get_error_string(ftdic));
|
||||||
goto error_2;
|
goto error_2;
|
||||||
}
|
}
|
||||||
/* Reset MPSSE controller. */
|
/* Reset MPSSE controller. */
|
||||||
err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET);
|
err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
|
DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
|
||||||
err, ftdi_get_error_string(ftdic));
|
err, ftdi_get_error_string(ftdic));
|
||||||
goto error_2;
|
goto error_2;
|
||||||
}
|
}
|
||||||
/* Enable MPSSE controller. Pin directions are set later.*/
|
/* Enable MPSSE controller. Pin directions are set later.*/
|
||||||
err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE);
|
err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
|
DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
|
||||||
err, ftdi_get_error_string(ftdic));
|
err, ftdi_get_error_string(ftdic));
|
||||||
goto error_2;
|
goto error_2;
|
||||||
}
|
}
|
||||||
@ -372,6 +375,18 @@ int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
|||||||
}
|
}
|
||||||
int index = 0;
|
int index = 0;
|
||||||
ftdi_init[index++]= LOOPBACK_END; /* FT2232D gets upset otherwise*/
|
ftdi_init[index++]= LOOPBACK_END; /* FT2232D gets upset otherwise*/
|
||||||
|
switch(ftdic->type) {
|
||||||
|
case TYPE_2232H:
|
||||||
|
case TYPE_4232H:
|
||||||
|
case TYPE_232H:
|
||||||
|
ftdi_init[index++] = DIS_DIV_5;
|
||||||
|
break;
|
||||||
|
case TYPE_2232C:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DEBUG_WARN("FTDI Chip has no MPSSE\n");
|
||||||
|
goto error_2;
|
||||||
|
}
|
||||||
ftdi_init[index++]= TCK_DIVISOR;
|
ftdi_init[index++]= TCK_DIVISOR;
|
||||||
/* Use CLK/2 for about 50 % SWDCLK duty cycle on FT2232c.*/
|
/* Use CLK/2 for about 50 % SWDCLK duty cycle on FT2232c.*/
|
||||||
ftdi_init[index++]= 1;
|
ftdi_init[index++]= 1;
|
||||||
@ -406,11 +421,11 @@ static void libftdi_set_data(data_desc_t* data)
|
|||||||
if ((data->data_low) || (data->ddr_low)) {
|
if ((data->data_low) || (data->ddr_low)) {
|
||||||
if (data->data_low > 0)
|
if (data->data_low > 0)
|
||||||
active_state.data_low |= (data->data_low & 0xff);
|
active_state.data_low |= (data->data_low & 0xff);
|
||||||
else
|
else if (data->data_low < 0)
|
||||||
active_state.data_low &= (data->data_low & 0xff);
|
active_state.data_low &= (data->data_low & 0xff);
|
||||||
if (data->ddr_low > 0)
|
if (data->ddr_low > 0)
|
||||||
active_state.ddr_low |= (data->ddr_low & 0xff);
|
active_state.ddr_low |= (data->ddr_low & 0xff);
|
||||||
else
|
else if (data->ddr_low < 0)
|
||||||
active_state.ddr_low &= (data->ddr_low & 0xff);
|
active_state.ddr_low &= (data->ddr_low & 0xff);
|
||||||
cmd[index++] = SET_BITS_LOW;
|
cmd[index++] = SET_BITS_LOW;
|
||||||
cmd[index++] = active_state.data_low;
|
cmd[index++] = active_state.data_low;
|
||||||
@ -419,11 +434,11 @@ static void libftdi_set_data(data_desc_t* data)
|
|||||||
if ((data->data_high) || (data->ddr_high)) {
|
if ((data->data_high) || (data->ddr_high)) {
|
||||||
if (data->data_high > 0)
|
if (data->data_high > 0)
|
||||||
active_state.data_high |= (data->data_high & 0xff);
|
active_state.data_high |= (data->data_high & 0xff);
|
||||||
else
|
else if (data->data_high < 0)
|
||||||
active_state.data_high &= (data->data_high & 0xff);
|
active_state.data_high &= (data->data_high & 0xff);
|
||||||
if (data->ddr_high > 0)
|
if (data->ddr_high > 0)
|
||||||
active_state.ddr_high |= (data->ddr_high & 0xff);
|
active_state.ddr_high |= (data->ddr_high & 0xff);
|
||||||
else
|
else if (data->ddr_high < 0)
|
||||||
active_state.ddr_high &= (data->ddr_high & 0xff);
|
active_state.ddr_high &= (data->ddr_high & 0xff);
|
||||||
cmd[index++] = SET_BITS_HIGH;
|
cmd[index++] = SET_BITS_HIGH;
|
||||||
cmd[index++] = active_state.data_high;
|
cmd[index++] = active_state.data_high;
|
||||||
@ -537,7 +552,8 @@ void libftdi_jtagtap_tdi_tdo_seq(
|
|||||||
if(!ticks) return;
|
if(!ticks) return;
|
||||||
if (!DI && !DO) return;
|
if (!DI && !DO) return;
|
||||||
|
|
||||||
// printf("ticks: %d\n", ticks);
|
DEBUG_WIRE("libftdi_jtagtap_tdi_tdo_seq %s ticks: %d\n",
|
||||||
|
(DI && DO) ? "read/write" : ((DI) ? "write" : "read"), ticks);
|
||||||
if(final_tms) ticks--;
|
if(final_tms) ticks--;
|
||||||
rticks = ticks & 7;
|
rticks = ticks & 7;
|
||||||
ticks >>= 3;
|
ticks >>= 3;
|
||||||
@ -567,7 +583,7 @@ void libftdi_jtagtap_tdi_tdo_seq(
|
|||||||
MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG;
|
MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG;
|
||||||
data[index++] = 0;
|
data[index++] = 0;
|
||||||
if (DI)
|
if (DI)
|
||||||
data[index++] = (DI[ticks]) >> rticks?0x81 : 0x01;
|
data[index++] = (DI[ticks] & (1 << rticks)) ? 0x81 : 0x01;
|
||||||
}
|
}
|
||||||
if (index)
|
if (index)
|
||||||
libftdi_buffer_write(data, index);
|
libftdi_buffer_write(data, index);
|
||||||
@ -578,7 +594,6 @@ void libftdi_jtagtap_tdi_tdo_seq(
|
|||||||
if(final_tms) rsize--;
|
if(final_tms) rsize--;
|
||||||
|
|
||||||
while(rsize--) {
|
while(rsize--) {
|
||||||
/*if(rsize) printf("%02X ", tmp[index]);*/
|
|
||||||
*DO++ = tmp[index++];
|
*DO++ = tmp[index++];
|
||||||
}
|
}
|
||||||
if (rticks == 0)
|
if (rticks == 0)
|
||||||
@ -591,7 +606,6 @@ void libftdi_jtagtap_tdi_tdo_seq(
|
|||||||
if(rticks) {
|
if(rticks) {
|
||||||
*DO >>= (8-rticks);
|
*DO >>= (8-rticks);
|
||||||
}
|
}
|
||||||
/*printf("%02X\n", *DO);*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,3 +628,34 @@ const char *libftdi_target_voltage(void)
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint16_t divisor;
|
||||||
|
void libftdi_max_frequency_set(uint32_t freq)
|
||||||
|
{
|
||||||
|
uint32_t clock;
|
||||||
|
if (ftdic->type == TYPE_2232C)
|
||||||
|
clock = 12 * 1000 * 1000;
|
||||||
|
else
|
||||||
|
/* Undivided clock set during startup*/
|
||||||
|
clock = 60 * 1000 * 1000;
|
||||||
|
uint32_t div = (clock + 2 * freq - 1)/ freq;
|
||||||
|
if ((div < 4) && (ftdic->type = TYPE_2232C))
|
||||||
|
div = 4; /* Avoid bad unsymetrict FT2232C clock at 6 MHz*/
|
||||||
|
divisor = div / 2 - 1;
|
||||||
|
uint8_t buf[3];
|
||||||
|
buf[0] = TCK_DIVISOR;
|
||||||
|
buf[1] = divisor & 0xff;
|
||||||
|
buf[2] = (divisor >> 8) & 0xff;
|
||||||
|
libftdi_buffer_write(buf, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t libftdi_max_frequency_get(void)
|
||||||
|
{
|
||||||
|
uint32_t clock;
|
||||||
|
if (ftdic->type == TYPE_2232C)
|
||||||
|
clock = 12 * 1000 * 1000;
|
||||||
|
else
|
||||||
|
/* Undivided clock set during startup*/
|
||||||
|
clock = 60 * 1000 * 1000;
|
||||||
|
return clock/ ( 2 *(divisor + 1));
|
||||||
|
}
|
||||||
|
@ -23,9 +23,10 @@
|
|||||||
#define __FTDI_BMP_H
|
#define __FTDI_BMP_H
|
||||||
|
|
||||||
#include "cl_utils.h"
|
#include "cl_utils.h"
|
||||||
#include "swdptap.h"
|
|
||||||
#include "jtagtap.h"
|
#include "jtagtap.h"
|
||||||
|
|
||||||
|
#include "bmp_hosted.h"
|
||||||
|
|
||||||
typedef struct data_desc_s {
|
typedef struct data_desc_s {
|
||||||
int16_t data_low;
|
int16_t data_low;
|
||||||
int16_t ddr_low;
|
int16_t ddr_low;
|
||||||
@ -98,14 +99,33 @@ typedef struct cable_desc_s {
|
|||||||
char * name;
|
char * name;
|
||||||
}cable_desc_t;
|
}cable_desc_t;
|
||||||
|
|
||||||
|
#if HOSTED_BMP_ONLY == 1
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||||
|
int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info) {return -1;};
|
||||||
|
int libftdi_swdptap_init(ADIv5_DP_t *dp) {return -1;};
|
||||||
|
int libftdi_jtagtap_init(jtag_proc_t *jtag_proc) {return 0;};
|
||||||
|
void libftdi_buffer_flush(void) {};
|
||||||
|
int libftdi_buffer_write(const uint8_t *data, int size) {return size;};
|
||||||
|
int libftdi_buffer_read(uint8_t *data, int size) {return size;};
|
||||||
|
const char *libftdi_target_voltage(void) {return "ERROR";};
|
||||||
|
void libftdi_jtagtap_tdi_tdo_seq(
|
||||||
|
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks) {};
|
||||||
|
bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd) {return false;};
|
||||||
|
void libftdi_max_frequency_set(uint32_t freq) {};
|
||||||
|
uint32_t libftdi_max_frequency_get(void) {return 0;};
|
||||||
|
void libftdi_srst_set_val(bool assert){};
|
||||||
|
bool libftdi_srst_get_val(void) { return false;};
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#else
|
||||||
|
#include <ftdi.h>
|
||||||
extern cable_desc_t cable_desc[];
|
extern cable_desc_t cable_desc[];
|
||||||
extern cable_desc_t *active_cable;
|
extern cable_desc_t *active_cable;
|
||||||
extern struct ftdi_context *ftdic;
|
extern struct ftdi_context *ftdic;
|
||||||
extern data_desc_t active_state;
|
extern data_desc_t active_state;
|
||||||
|
|
||||||
int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info);
|
int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info);
|
||||||
|
int libftdi_swdptap_init(ADIv5_DP_t *dp);
|
||||||
int libftdi_swdptap_init(swd_proc_t *swd_proc);
|
|
||||||
int libftdi_jtagtap_init(jtag_proc_t *jtag_proc);
|
int libftdi_jtagtap_init(jtag_proc_t *jtag_proc);
|
||||||
void libftdi_buffer_flush(void);
|
void libftdi_buffer_flush(void);
|
||||||
int libftdi_buffer_write(const uint8_t *data, int size);
|
int libftdi_buffer_write(const uint8_t *data, int size);
|
||||||
@ -114,6 +134,11 @@ const char *libftdi_target_voltage(void);
|
|||||||
void libftdi_jtagtap_tdi_tdo_seq(
|
void libftdi_jtagtap_tdi_tdo_seq(
|
||||||
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks);
|
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks);
|
||||||
bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd);
|
bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd);
|
||||||
|
void libftdi_max_frequency_set(uint32_t freq);
|
||||||
|
uint32_t libftdi_max_frequency_get(void);
|
||||||
|
void libftdi_srst_set_val(bool assert);
|
||||||
|
bool libftdi_srst_get_val(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MPSSE_SK 1
|
#define MPSSE_SK 1
|
||||||
#define PIN0 1
|
#define PIN0 1
|
||||||
|
@ -38,15 +38,21 @@
|
|||||||
/* Only two devices PIDS tested so long */
|
/* Only two devices PIDS tested so long */
|
||||||
#define USB_VID_SEGGER_0101 0x0101
|
#define USB_VID_SEGGER_0101 0x0101
|
||||||
#define USB_VID_SEGGER_0105 0x0105
|
#define USB_VID_SEGGER_0105 0x0105
|
||||||
|
#define USB_VID_SEGGER_1020 0x1020
|
||||||
|
|
||||||
|
static uint32_t emu_caps;
|
||||||
|
static uint32_t emu_speed_kHz;
|
||||||
|
static uint16_t emu_min_divisor;
|
||||||
|
static uint16_t emu_current_divisor;
|
||||||
|
|
||||||
static void jlink_print_caps(bmp_info_t *info)
|
static void jlink_print_caps(bmp_info_t *info)
|
||||||
{
|
{
|
||||||
uint8_t cmd[1] = {CMD_GET_CAPS};
|
uint8_t cmd[1] = {CMD_GET_CAPS};
|
||||||
uint8_t res[4];
|
uint8_t res[4];
|
||||||
send_recv(info->usb_link, cmd, 1, res, sizeof(res));
|
send_recv(info->usb_link, cmd, 1, res, sizeof(res));
|
||||||
uint32_t caps = res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24);
|
emu_caps = res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24);
|
||||||
DEBUG_INFO("Caps %" PRIx32 "\n", caps);
|
DEBUG_INFO("Caps %" PRIx32 "\n", emu_caps);
|
||||||
if (caps & JLINK_CAP_GET_HW_VERSION) {
|
if (emu_caps & JLINK_CAP_GET_HW_VERSION) {
|
||||||
uint8_t cmd[1] = {CMD_GET_HW_VERSION};
|
uint8_t cmd[1] = {CMD_GET_HW_VERSION};
|
||||||
send_recv(info->usb_link, cmd, 1, NULL, 0);
|
send_recv(info->usb_link, cmd, 1, NULL, 0);
|
||||||
send_recv(info->usb_link, NULL, 0, res, sizeof(res));
|
send_recv(info->usb_link, NULL, 0, res, sizeof(res));
|
||||||
@ -56,13 +62,15 @@ static void jlink_print_caps(bmp_info_t *info)
|
|||||||
}
|
}
|
||||||
static void jlink_print_speed(bmp_info_t *info)
|
static void jlink_print_speed(bmp_info_t *info)
|
||||||
{
|
{
|
||||||
uint8_t cmd[1] = {CMD_GET_SPEED};
|
uint8_t cmd[1] = {CMD_GET_SPEEDS};
|
||||||
uint8_t res[6];
|
uint8_t res[6];
|
||||||
send_recv(info->usb_link, cmd, 1, res, sizeof(res));
|
send_recv(info->usb_link, cmd, 1, res, sizeof(res));
|
||||||
uint32_t speed = res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24);
|
emu_speed_kHz = (res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24)) /
|
||||||
double freq_mhz = speed / 1000000.0;
|
1000;
|
||||||
uint16_t divisor = res[4] | (res[5] << 8);
|
emu_min_divisor = res[4] | (res[5] << 8);
|
||||||
DEBUG_INFO("Emulator speed %3.1f MHz, Mindiv %d\n", freq_mhz, divisor);
|
DEBUG_INFO("Emulator speed %d kHz, Mindiv %d%s\n", emu_speed_kHz,
|
||||||
|
emu_min_divisor,
|
||||||
|
(emu_caps & JLINK_CAP_GET_SPEEDS) ? "" : ", fixed");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void jlink_print_version(bmp_info_t *info)
|
static void jlink_print_version(bmp_info_t *info)
|
||||||
@ -90,15 +98,15 @@ static void jlink_print_interfaces(bmp_info_t *info)
|
|||||||
DEBUG_INFO(", %s available\n",
|
DEBUG_INFO(", %s available\n",
|
||||||
(other_interface == JLINK_IF_SWD) ? "SWD": "JTAG");
|
(other_interface == JLINK_IF_SWD) ? "SWD": "JTAG");
|
||||||
else
|
else
|
||||||
DEBUG_WARN(", %s not available\n",
|
DEBUG_INFO(", %s not available\n",
|
||||||
((res[0] + 1) == JLINK_IF_SWD) ? "JTAG": "SWD");
|
((res[0] + 1) == JLINK_IF_SWD) ? "JTAG": "SWD");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void jlink_info(bmp_info_t *info)
|
static void jlink_info(bmp_info_t *info)
|
||||||
{
|
{
|
||||||
jlink_print_version(info);
|
jlink_print_version(info);
|
||||||
jlink_print_speed(info);
|
|
||||||
jlink_print_caps(info);
|
jlink_print_caps(info);
|
||||||
|
jlink_print_speed(info);
|
||||||
jlink_print_interfaces(info);
|
jlink_print_interfaces(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +183,8 @@ int jlink_init(bmp_info_t *info)
|
|||||||
if (desc.idVendor != USB_PID_SEGGER)
|
if (desc.idVendor != USB_PID_SEGGER)
|
||||||
continue;
|
continue;
|
||||||
if ((desc.idProduct != USB_VID_SEGGER_0101) &&
|
if ((desc.idProduct != USB_VID_SEGGER_0101) &&
|
||||||
(desc.idProduct != USB_VID_SEGGER_0105))
|
(desc.idProduct != USB_VID_SEGGER_0105) &&
|
||||||
|
(desc.idProduct != USB_VID_SEGGER_1020))
|
||||||
continue;
|
continue;
|
||||||
int res = libusb_open(dev, &jl->ul_libusb_device_handle);
|
int res = libusb_open(dev, &jl->ul_libusb_device_handle);
|
||||||
if (res != LIBUSB_SUCCESS)
|
if (res != LIBUSB_SUCCESS)
|
||||||
@ -212,7 +221,7 @@ int jlink_init(bmp_info_t *info)
|
|||||||
const char *jlink_target_voltage(bmp_info_t *info)
|
const char *jlink_target_voltage(bmp_info_t *info)
|
||||||
{
|
{
|
||||||
uint8_t cmd[1] = {CMD_GET_HW_STATUS};
|
uint8_t cmd[1] = {CMD_GET_HW_STATUS};
|
||||||
uint8_t res[8];
|
uint8_t res[8];
|
||||||
send_recv(info->usb_link, cmd, 1, res, sizeof(res));
|
send_recv(info->usb_link, cmd, 1, res, sizeof(res));
|
||||||
uint16_t mVolt = res[0] | (res[1] << 8);
|
uint16_t mVolt = res[0] | (res[1] << 8);
|
||||||
static char ret[7];
|
static char ret[7];
|
||||||
@ -236,3 +245,27 @@ bool jlink_srst_get_val(bmp_info_t *info) {
|
|||||||
send_recv(info->usb_link, cmd, 1, res, sizeof(res));
|
send_recv(info->usb_link, cmd, 1, res, sizeof(res));
|
||||||
return !(res[6]);
|
return !(res[6]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void jlink_max_frequency_set(bmp_info_t *info, uint32_t freq)
|
||||||
|
{
|
||||||
|
if (!(emu_caps & JLINK_CAP_GET_SPEEDS))
|
||||||
|
return;
|
||||||
|
if (!info->is_jtag)
|
||||||
|
return;
|
||||||
|
uint16_t freq_kHz = freq /1000;
|
||||||
|
uint16_t divisor = (emu_speed_kHz + freq_kHz - 1) / freq_kHz;
|
||||||
|
if (divisor < emu_min_divisor)
|
||||||
|
divisor = emu_min_divisor;
|
||||||
|
emu_current_divisor = divisor;
|
||||||
|
uint16_t speed_kHz = emu_speed_kHz / divisor;
|
||||||
|
uint8_t cmd[3] = {CMD_SET_SPEED, speed_kHz & 0xff, speed_kHz >> 8};
|
||||||
|
DEBUG_WARN("Set Speed %d\n", speed_kHz);
|
||||||
|
send_recv(info->usb_link, cmd, 3, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t jlink_max_frequency_get(bmp_info_t *info)
|
||||||
|
{
|
||||||
|
if ((emu_caps & JLINK_CAP_GET_SPEEDS) && (info->is_jtag))
|
||||||
|
return (emu_speed_kHz * 1000L)/ emu_current_divisor;
|
||||||
|
return FREQ_FIXED;
|
||||||
|
}
|
||||||
|
@ -19,12 +19,14 @@
|
|||||||
#if !defined(__JLINK_H_)
|
#if !defined(__JLINK_H_)
|
||||||
#define __JLINK_H_
|
#define __JLINK_H_
|
||||||
|
|
||||||
|
#include "bmp_hosted.h"
|
||||||
#include "jtagtap.h"
|
#include "jtagtap.h"
|
||||||
|
|
||||||
/** @cond PRIVATE */
|
/** @cond PRIVATE */
|
||||||
#define CMD_GET_VERSION 0x01
|
#define CMD_GET_VERSION 0x01
|
||||||
|
#define CMD_SET_SPEED 0x05
|
||||||
#define CMD_GET_HW_STATUS 0x07
|
#define CMD_GET_HW_STATUS 0x07
|
||||||
#define CMD_GET_SPEED 0xc0
|
#define CMD_GET_SPEEDS 0xc0
|
||||||
#define CMD_GET_SELECT_IF 0xc7
|
#define CMD_GET_SELECT_IF 0xc7
|
||||||
#define CMD_HW_JTAG3 0xcf
|
#define CMD_HW_JTAG3 0xcf
|
||||||
#define CMD_HW_RESET0 0xdc
|
#define CMD_HW_RESET0 0xdc
|
||||||
@ -36,13 +38,63 @@
|
|||||||
#define JLINK_IF_GET_ACTIVE 0xfe
|
#define JLINK_IF_GET_ACTIVE 0xfe
|
||||||
#define JLINK_IF_GET_AVAILABLE 0xff
|
#define JLINK_IF_GET_AVAILABLE 0xff
|
||||||
|
|
||||||
#define JLINK_CAP_GET_HW_VERSION 2
|
#define JLINK_CAP_GET_SPEEDS (1 << 9)
|
||||||
|
#define JLINK_CAP_GET_HW_VERSION (1 << 1)
|
||||||
#define JLINK_IF_JTAG 1
|
#define JLINK_IF_JTAG 1
|
||||||
#define JLINK_IF_SWD 2
|
#define JLINK_IF_SWD 2
|
||||||
|
|
||||||
#define SELECT_IF_JTAG 0
|
#define SELECT_IF_JTAG 0
|
||||||
#define SELECT_IF_SWD 1
|
#define SELECT_IF_SWD 1
|
||||||
|
|
||||||
|
#if HOSTED_BMP_ONLY == 1
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||||
|
int jlink_init(bmp_info_t *info) {return -1;};
|
||||||
|
int jlink_swdp_scan(bmp_info_t *info) {return 0;};
|
||||||
|
int jlink_jtagtap_init(bmp_info_t *info, jtag_proc_t *jtag_proc) {return 0;};
|
||||||
|
const char *jlink_target_voltage(bmp_info_t *info) {return "ERROR";};
|
||||||
|
void jlink_srst_set_val(bmp_info_t *info, bool assert) {};
|
||||||
|
bool jlink_srst_get_val(bmp_info_t *info) {return true;};
|
||||||
|
void jlink_max_frequency_set(bmp_info_t *info, uint32_t freq) {};
|
||||||
|
uint32_t jlink_max_frequency_get(bmp_info_t *info) {return 0;};
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#else
|
||||||
|
/** Device capabilities. (from openocd*/
|
||||||
|
enum jaylink_device_capability {
|
||||||
|
/** Device supports retrieval of the hardware version. */
|
||||||
|
JAYLINK_DEV_CAP_GET_HW_VERSION = 1,
|
||||||
|
/** Device supports adaptive clocking. */
|
||||||
|
JAYLINK_DEV_CAP_ADAPTIVE_CLOCKING = 3,
|
||||||
|
/** Device supports reading configuration data. */
|
||||||
|
JAYLINK_DEV_CAP_READ_CONFIG = 4,
|
||||||
|
/** Device supports writing configuration data. */
|
||||||
|
JAYLINK_DEV_CAP_WRITE_CONFIG = 5,
|
||||||
|
/** Device supports retrieval of target interface speeds. */
|
||||||
|
JAYLINK_DEV_CAP_GET_SPEEDS = 9,
|
||||||
|
/** Device supports retrieval of free memory size. */
|
||||||
|
JAYLINK_DEV_CAP_GET_FREE_MEMORY = 11,
|
||||||
|
/** Device supports retrieval of hardware information. */
|
||||||
|
JAYLINK_DEV_CAP_GET_HW_INFO = 12,
|
||||||
|
/** Device supports the setting of the target power supply. */
|
||||||
|
JAYLINK_DEV_CAP_SET_TARGET_POWER = 13,
|
||||||
|
/** Device supports target interface selection. */
|
||||||
|
JAYLINK_DEV_CAP_SELECT_TIF = 17,
|
||||||
|
/** Device supports retrieval of counter values. */
|
||||||
|
JAYLINK_DEV_CAP_GET_COUNTERS = 19,
|
||||||
|
/** Device supports capturing of SWO trace data. */
|
||||||
|
JAYLINK_DEV_CAP_SWO = 23,
|
||||||
|
/** Device supports file I/O operations. */
|
||||||
|
JAYLINK_DEV_CAP_FILE_IO = 26,
|
||||||
|
/** Device supports registration of connections. */
|
||||||
|
JAYLINK_DEV_CAP_REGISTER = 27,
|
||||||
|
/** Device supports retrieval of extended capabilities. */
|
||||||
|
JAYLINK_DEV_CAP_GET_EXT_CAPS = 31,
|
||||||
|
/** Device supports EMUCOM. */
|
||||||
|
JAYLINK_DEV_CAP_EMUCOM = 33,
|
||||||
|
/** Device supports ethernet connectivity. */
|
||||||
|
JAYLINK_DEV_CAP_ETHERNET = 38
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
int jlink_init(bmp_info_t *info);
|
int jlink_init(bmp_info_t *info);
|
||||||
int jlink_swdp_scan(bmp_info_t *info);
|
int jlink_swdp_scan(bmp_info_t *info);
|
||||||
@ -50,4 +102,7 @@ int jlink_jtagtap_init(bmp_info_t *info, jtag_proc_t *jtag_proc);
|
|||||||
const char *jlink_target_voltage(bmp_info_t *info);
|
const char *jlink_target_voltage(bmp_info_t *info);
|
||||||
void jlink_srst_set_val(bmp_info_t *info, bool assert);
|
void jlink_srst_set_val(bmp_info_t *info, bool assert);
|
||||||
bool jlink_srst_get_val(bmp_info_t *info);
|
bool jlink_srst_get_val(bmp_info_t *info);
|
||||||
|
void jlink_max_frequency_set(bmp_info_t *info, uint32_t freq);
|
||||||
|
uint32_t jlink_max_frequency_get(bmp_info_t *info);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
||||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||||
* Copyright (C) 2019 - 2020 Uwe Bonnes
|
* Copyright (C) 2019 - 2021 Uwe Bonnes
|
||||||
* (bon@elektron.ikp.physik.tu-darmstadt.de)
|
* (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -103,7 +103,7 @@ static int line_reset(bmp_info_t *info)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int swdptap_init(bmp_info_t *info)
|
static int jlink_swdptap_init(bmp_info_t *info)
|
||||||
{
|
{
|
||||||
uint8_t cmd[2] = {CMD_GET_SELECT_IF, JLINK_IF_GET_AVAILABLE};
|
uint8_t cmd[2] = {CMD_GET_SELECT_IF, JLINK_IF_GET_AVAILABLE};
|
||||||
uint8_t res[4];
|
uint8_t res[4];
|
||||||
@ -113,20 +113,14 @@ static int swdptap_init(bmp_info_t *info)
|
|||||||
cmd[1] = SELECT_IF_SWD;
|
cmd[1] = SELECT_IF_SWD;
|
||||||
send_recv(info->usb_link, cmd, 2, res, sizeof(res));
|
send_recv(info->usb_link, cmd, 2, res, sizeof(res));
|
||||||
platform_delay(10);
|
platform_delay(10);
|
||||||
/* Set speed 256 kHz*/
|
/* SWD speed is fixed. Do not set it here*/
|
||||||
unsigned int speed = 2000;
|
|
||||||
uint8_t jtag_speed[3] = {5, speed & 0xff, speed >> 8};
|
|
||||||
send_recv(info->usb_link, jtag_speed, 3, NULL, 0);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int jlink_swdp_scan(bmp_info_t *info)
|
int jlink_swdp_scan(bmp_info_t *info)
|
||||||
{
|
{
|
||||||
swdptap_init(info);
|
jlink_swdptap_init(info);
|
||||||
target_list_free();
|
target_list_free();
|
||||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
|
||||||
if (!dp) /* calloc failed: heap exhaustion */
|
|
||||||
return 0;
|
|
||||||
uint8_t cmd[44];
|
uint8_t cmd[44];
|
||||||
cmd[0] = CMD_HW_JTAG3;
|
cmd[0] = CMD_HW_JTAG3;
|
||||||
cmd[1] = 0;
|
cmd[1] = 0;
|
||||||
@ -178,7 +172,18 @@ int jlink_swdp_scan(bmp_info_t *info)
|
|||||||
DEBUG_WARN( "Line reset failed\n");
|
DEBUG_WARN( "Line reset failed\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
dp->idcode = jlink_adiv5_swdp_low_access(dp, 1, ADIV5_DP_IDCODE, 0);
|
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
||||||
|
if (!dp) /* calloc failed: heap exhaustion */
|
||||||
|
return 0;
|
||||||
|
volatile struct exception e;
|
||||||
|
TRY_CATCH (e, EXCEPTION_ALL) {
|
||||||
|
dp->idcode = jlink_adiv5_swdp_low_access(dp, 1, ADIV5_DP_IDCODE, 0);
|
||||||
|
}
|
||||||
|
if (e.type) {
|
||||||
|
DEBUG_WARN("DP not responding for IDCODE! Reset stuck low?\n");
|
||||||
|
free(dp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
dp->dp_read = jlink_adiv5_swdp_read;
|
dp->dp_read = jlink_adiv5_swdp_read;
|
||||||
dp->error = jlink_adiv5_swdp_error;
|
dp->error = jlink_adiv5_swdp_error;
|
||||||
dp->low_access = jlink_adiv5_swdp_low_access;
|
dp->low_access = jlink_adiv5_swdp_low_access;
|
||||||
@ -247,20 +252,26 @@ static uint32_t jlink_adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
|||||||
uint8_t res[8];
|
uint8_t res[8];
|
||||||
cmd[0] = CMD_HW_JTAG3;
|
cmd[0] = CMD_HW_JTAG3;
|
||||||
cmd[1] = 0;
|
cmd[1] = 0;
|
||||||
cmd[2] = 13;
|
/* It seems, JLINK samples read data at end of previous clock.
|
||||||
|
* So target data read must start at the 12'th clock, while
|
||||||
|
* write starts as expected at the 14'th clock (8 cmd, 3 response,
|
||||||
|
* 2 turn around.
|
||||||
|
*/
|
||||||
|
cmd[2] = (RnW) ? 11 : 13;
|
||||||
cmd[3] = 0;
|
cmd[3] = 0;
|
||||||
cmd[4] = 0xff;
|
cmd[4] = 0xff; /* 8 bits command OUT */
|
||||||
cmd[5] = 0xe3;
|
cmd[5] = 0xf0; /* one IN bit to turn around to read, read 2
|
||||||
cmd[6] = request << 2;
|
(read) or 3 (write) IN bits for response and
|
||||||
cmd[7] = request >> 6;
|
and one OUT bit to turn around to write on write*/
|
||||||
|
cmd[6] = request;
|
||||||
|
cmd[7] = 0x00;
|
||||||
platform_timeout_set(&timeout, 2000);
|
platform_timeout_set(&timeout, 2000);
|
||||||
do {
|
do {
|
||||||
send_recv(info.usb_link, cmd, 8, res, 2);
|
send_recv(info.usb_link, cmd, 8, res, 2);
|
||||||
send_recv(info.usb_link, NULL, 0, res, 1);
|
send_recv(info.usb_link, NULL, 0, res + 2 , 1);
|
||||||
if (res[0] != 0)
|
if (res[2] != 0)
|
||||||
raise_exception(EXCEPTION_ERROR, "Low access setup failed");
|
raise_exception(EXCEPTION_ERROR, "Low access setup failed");
|
||||||
ack = res[1] >> 2;
|
ack = res[1] & 7;
|
||||||
ack &= 7;
|
|
||||||
} while (ack == SWDP_ACK_WAIT && !platform_timeout_is_expired(&timeout));
|
} while (ack == SWDP_ACK_WAIT && !platform_timeout_is_expired(&timeout));
|
||||||
if (ack == SWDP_ACK_WAIT)
|
if (ack == SWDP_ACK_WAIT)
|
||||||
raise_exception(EXCEPTION_TIMEOUT, "SWDP ACK timeout");
|
raise_exception(EXCEPTION_TIMEOUT, "SWDP ACK timeout");
|
||||||
@ -274,17 +285,15 @@ static uint32_t jlink_adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
|||||||
|
|
||||||
if(ack != SWDP_ACK_OK) {
|
if(ack != SWDP_ACK_OK) {
|
||||||
if (cl_debuglevel & BMP_DEBUG_TARGET)
|
if (cl_debuglevel & BMP_DEBUG_TARGET)
|
||||||
DEBUG_WARN( "Protocol\n");
|
DEBUG_WARN( "Protocol %d\n", ack);
|
||||||
line_reset(&info);
|
line_reset(&info);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
cmd[3] = 0;
|
/* Always append 8 idle cycle (SWDIO = 0)!*/
|
||||||
/* Always prepend an idle cycle (SWDIO = 0)!*/
|
|
||||||
if(RnW) {
|
if(RnW) {
|
||||||
memset(cmd + 4, 0, 10);
|
memset(cmd + 4, 0, 10);
|
||||||
cmd[2] = 34;
|
cmd[2] = 33 + 2; /* 2 idle cycles */
|
||||||
cmd[8] = 0xfe;
|
cmd[8] = 0xfe;
|
||||||
cmd[13] = 0;
|
|
||||||
send_recv(info.usb_link, cmd, 14, res, 5);
|
send_recv(info.usb_link, cmd, 14, res, 5);
|
||||||
send_recv(info.usb_link, NULL, 0, res + 5, 1);
|
send_recv(info.usb_link, NULL, 0, res + 5, 1);
|
||||||
if (res[5] != 0)
|
if (res[5] != 0)
|
||||||
@ -292,19 +301,19 @@ static uint32_t jlink_adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
|||||||
response = res[0] | res[1] << 8 | res[2] << 16 | res[3] << 24;
|
response = res[0] | res[1] << 8 | res[2] << 16 | res[3] << 24;
|
||||||
int parity = res[4] & 1;
|
int parity = res[4] & 1;
|
||||||
int bit_count = __builtin_popcount (response) + parity;
|
int bit_count = __builtin_popcount (response) + parity;
|
||||||
if (bit_count & 1) /* Give up on parity error */
|
if (bit_count & 1) /* Give up on parity error */
|
||||||
raise_exception(EXCEPTION_ERROR, "SWDP Parity error");
|
raise_exception(EXCEPTION_ERROR, "SWDP Parity error");
|
||||||
} else {
|
} else {
|
||||||
cmd[2] = 35;
|
cmd[2] = 33 + 8; /* 8 idle cycle to move data through SW-DP */
|
||||||
memset(cmd + 4, 0xff, 5);
|
memset(cmd + 4, 0xff, 6);
|
||||||
cmd[ 9] = ((value << 2) & 0xfc);
|
cmd[10] = ((value >> 0) & 0xff);
|
||||||
cmd[10] = ((value >> 6) & 0xff);
|
cmd[11] = ((value >> 8) & 0xff);
|
||||||
cmd[11] = ((value >> 14) & 0xff);
|
cmd[12] = ((value >> 16) & 0xff);
|
||||||
cmd[12] = ((value >> 22) & 0xff);
|
cmd[13] = ((value >> 24) & 0xff);
|
||||||
cmd[13] = ((value >> 30) & 0x03);
|
|
||||||
int bit_count = __builtin_popcount(value);
|
int bit_count = __builtin_popcount(value);
|
||||||
cmd[13] |= ((bit_count & 1) ? 4 : 0);
|
cmd[14] = bit_count & 1;
|
||||||
send_recv(info.usb_link, cmd, 14, res, 5);
|
cmd[15] = 0;
|
||||||
|
send_recv(info.usb_link, cmd, 16, res, 6);
|
||||||
send_recv(info.usb_link, NULL, 0, res, 1);
|
send_recv(info.usb_link, NULL, 0, res, 1);
|
||||||
if (res[0] != 0)
|
if (res[0] != 0)
|
||||||
raise_exception(EXCEPTION_ERROR, "Low access write failed");
|
raise_exception(EXCEPTION_ERROR, "Low access write failed");
|
||||||
|
@ -21,13 +21,10 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "general.h"
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "general.h"
|
|
||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
|
|
||||||
#include "jlink.h"
|
#include "jlink.h"
|
||||||
|
@ -22,15 +22,13 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ftdi.h>
|
||||||
#include "ftdi_bmp.h"
|
#include "ftdi_bmp.h"
|
||||||
|
|
||||||
|
|
||||||
extern cable_desc_t *active_cable;
|
extern cable_desc_t *active_cable;
|
||||||
extern struct ftdi_context *ftdic;
|
extern struct ftdi_context *ftdic;
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
* Copyright(C) 2018 - 2021 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -22,10 +21,10 @@
|
|||||||
* Speed is sensible.
|
* Speed is sensible.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "general.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "general.h"
|
#include <ftdi.h>
|
||||||
#include "ftdi_bmp.h"
|
#include "ftdi_bmp.h"
|
||||||
|
|
||||||
enum swdio_status{
|
enum swdio_status{
|
||||||
@ -166,7 +165,7 @@ bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int libftdi_swdptap_init(swd_proc_t *swd_proc)
|
int libftdi_swdptap_init(ADIv5_DP_t *dp)
|
||||||
{
|
{
|
||||||
if (!libftdi_swd_possible(&do_mpsse, &direct_bb_swd)) {
|
if (!libftdi_swd_possible(&do_mpsse, &direct_bb_swd)) {
|
||||||
DEBUG_WARN("SWD not possible or missing item in cable description.\n");
|
DEBUG_WARN("SWD not possible or missing item in cable description.\n");
|
||||||
@ -206,11 +205,14 @@ int libftdi_swdptap_init(swd_proc_t *swd_proc)
|
|||||||
libftdi_buffer_flush();
|
libftdi_buffer_flush();
|
||||||
olddir = SWDIO_STATUS_FLOAT;
|
olddir = SWDIO_STATUS_FLOAT;
|
||||||
|
|
||||||
swd_proc->swdptap_seq_in = swdptap_seq_in;
|
dp->seq_in = swdptap_seq_in;
|
||||||
swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity;
|
dp->seq_in_parity = swdptap_seq_in_parity;
|
||||||
swd_proc->swdptap_seq_out = swdptap_seq_out;
|
dp->seq_out = swdptap_seq_out;
|
||||||
swd_proc->swdptap_seq_out_parity = swdptap_seq_out_parity;
|
dp->seq_out_parity = swdptap_seq_out_parity;
|
||||||
|
dp->dp_read = firmware_swdp_read;
|
||||||
|
dp->error = firmware_swdp_error;
|
||||||
|
dp->low_access = firmware_swdp_low_access;
|
||||||
|
dp->abort = firmware_swdp_abort;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,7 +305,10 @@ static uint32_t swdptap_seq_in(int ticks)
|
|||||||
if (do_mpsse) {
|
if (do_mpsse) {
|
||||||
uint8_t DO[4];
|
uint8_t DO[4];
|
||||||
libftdi_jtagtap_tdi_tdo_seq(DO, 0, NULL, ticks);
|
libftdi_jtagtap_tdi_tdo_seq(DO, 0, NULL, ticks);
|
||||||
for (int i = 0; i < (ticks >> 3) + (ticks & 7)? 1: 0; i++) {
|
int bytes = ticks >> 3;
|
||||||
|
if (ticks & 7)
|
||||||
|
bytes++;
|
||||||
|
for (int i = 0; i < bytes; i++) {
|
||||||
result |= DO[i] << (8 * i);
|
result |= DO[i] << (8 * i);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -361,9 +366,19 @@ static void swdptap_seq_out(uint32_t MS, int ticks)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ARM Debug Interface Architecture Specification ADIv5.0 to ADIv5.2
|
||||||
|
* tells to clock the data through SW-DP to either :
|
||||||
|
* - immediate start a new transaction
|
||||||
|
* - continue to drive idle cycles
|
||||||
|
* - or clock at least 8 idle cycles
|
||||||
|
*
|
||||||
|
* Implement last option to favour correctness over
|
||||||
|
* slight speed decrease
|
||||||
|
*/
|
||||||
static void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
static void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
||||||
{
|
{
|
||||||
int parity = __builtin_parity(MS & ((1LL << ticks) - 1)) & 1;
|
(void) ticks;
|
||||||
|
int parity = __builtin_parity(MS) & 1;
|
||||||
unsigned int index = 0;
|
unsigned int index = 0;
|
||||||
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
||||||
if (do_mpsse) {
|
if (do_mpsse) {
|
||||||
@ -373,26 +388,26 @@ static void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
|||||||
DI[2] = (MS >> 16) & 0xff;
|
DI[2] = (MS >> 16) & 0xff;
|
||||||
DI[3] = (MS >> 24) & 0xff;
|
DI[3] = (MS >> 24) & 0xff;
|
||||||
DI[4] = parity;
|
DI[4] = parity;
|
||||||
libftdi_jtagtap_tdi_tdo_seq(NULL, 0, DI, ticks + 1);
|
DI[5] = 0;
|
||||||
|
libftdi_jtagtap_tdi_tdo_seq(NULL, 0, DI, 32 + 1 + 8);
|
||||||
} else {
|
} else {
|
||||||
uint8_t cmd[32];
|
uint8_t cmd[32];
|
||||||
int steps = ticks;
|
int steps = ticks;
|
||||||
while (steps) {
|
while (steps) {
|
||||||
cmd[index++] = MPSSE_TMS_SHIFT;
|
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||||
|
cmd[index++] = 6;
|
||||||
if (steps >= 7) {
|
if (steps >= 7) {
|
||||||
cmd[index++] = 6;
|
|
||||||
cmd[index++] = MS & 0x7f;
|
cmd[index++] = MS & 0x7f;
|
||||||
MS >>= 7;
|
MS >>= 7;
|
||||||
steps -= 7;
|
steps -= 7;
|
||||||
} else {
|
} else {
|
||||||
cmd[index++] = steps - 1;
|
cmd[index++] = (MS & 0x7f) | (parity << 4);
|
||||||
cmd[index++] = MS & 0x7f;
|
|
||||||
steps = 0;
|
steps = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmd[index++] = MPSSE_TMS_SHIFT;
|
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||||
|
cmd[index++] = 4;
|
||||||
cmd[index++] = 0;
|
cmd[index++] = 0;
|
||||||
cmd[index++] = parity;
|
|
||||||
libftdi_buffer_write(cmd, index);
|
libftdi_buffer_write(cmd, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
* Copyright (C) 2020- 2021 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -21,7 +21,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "swdptap.h"
|
|
||||||
#include "jtagtap.h"
|
#include "jtagtap.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "target_internal.h"
|
#include "target_internal.h"
|
||||||
@ -31,40 +30,31 @@
|
|||||||
#include "gdb_if.h"
|
#include "gdb_if.h"
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
#include "rtt_if.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "bmp_remote.h"
|
#include "bmp_remote.h"
|
||||||
|
#include "bmp_hosted.h"
|
||||||
#include "stlinkv2.h"
|
#include "stlinkv2.h"
|
||||||
#include "ftdi_bmp.h"
|
#include "ftdi_bmp.h"
|
||||||
#include "jlink.h"
|
#include "jlink.h"
|
||||||
#include "cmsis_dap.h"
|
#include "cmsis_dap.h"
|
||||||
|
#include "cl_utils.h"
|
||||||
#define VENDOR_ID_STLINK 0x0483
|
|
||||||
#define PRODUCT_ID_STLINK_MASK 0xffe0
|
|
||||||
#define PRODUCT_ID_STLINK_GROUP 0x3740
|
|
||||||
#define PRODUCT_ID_STLINKV1 0x3744
|
|
||||||
#define PRODUCT_ID_STLINKV2 0x3748
|
|
||||||
#define PRODUCT_ID_STLINKV21 0x374b
|
|
||||||
#define PRODUCT_ID_STLINKV21_MSD 0x3752
|
|
||||||
#define PRODUCT_ID_STLINKV3 0x374f
|
|
||||||
#define PRODUCT_ID_STLINKV3E 0x374e
|
|
||||||
|
|
||||||
#define VENDOR_ID_SEGGER 0x1366
|
|
||||||
|
|
||||||
bmp_info_t info;
|
bmp_info_t info;
|
||||||
|
|
||||||
swd_proc_t swd_proc;
|
|
||||||
jtag_proc_t jtag_proc;
|
jtag_proc_t jtag_proc;
|
||||||
|
|
||||||
|
void gdb_ident(char *p, int count)
|
||||||
|
{
|
||||||
|
snprintf(p, count, "%s (%s), %s", info.manufacturer, info.product,
|
||||||
|
info.version);
|
||||||
|
}
|
||||||
|
|
||||||
static void exit_function(void)
|
static void exit_function(void)
|
||||||
{
|
{
|
||||||
if(info.usb_link) {
|
libusb_exit_function(&info);
|
||||||
libusb_free_transfer(info.usb_link->req_trans);
|
|
||||||
libusb_free_transfer(info.usb_link->rep_trans);
|
|
||||||
if (info.usb_link->ul_libusb_device_handle) {
|
|
||||||
libusb_release_interface (
|
|
||||||
info.usb_link->ul_libusb_device_handle, 0);
|
|
||||||
libusb_close(info.usb_link->ul_libusb_device_handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (info.bmp_type) {
|
switch (info.bmp_type) {
|
||||||
case BMP_TYPE_CMSIS_DAP:
|
case BMP_TYPE_CMSIS_DAP:
|
||||||
dap_exit_function();
|
dap_exit_function();
|
||||||
@ -72,6 +62,9 @@ static void exit_function(void)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
rtt_if_exit();
|
||||||
|
#endif
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,232 +75,31 @@ static void sigterm_handler(int sig)
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info)
|
static BMP_CL_OPTIONS_t cl_opts;
|
||||||
{
|
|
||||||
libusb_device **devs;
|
|
||||||
int n_devs = libusb_get_device_list(info->libusb_ctx, &devs);
|
|
||||||
if (n_devs < 0) {
|
|
||||||
DEBUG_WARN( "WARN:libusb_get_device_list() failed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
bool report = false;
|
|
||||||
int found_debuggers;
|
|
||||||
struct libusb_device_descriptor desc;
|
|
||||||
char serial[64];
|
|
||||||
char manufacturer[128];
|
|
||||||
char product[128];
|
|
||||||
bmp_type_t type = BMP_TYPE_NONE;
|
|
||||||
bool access_problems = false;
|
|
||||||
char *active_cable = NULL;
|
|
||||||
bool ftdi_unknown = false;
|
|
||||||
rescan:
|
|
||||||
found_debuggers = 0;
|
|
||||||
for (int i = 0; devs[i]; i++) {
|
|
||||||
libusb_device *dev = devs[i];
|
|
||||||
int res = libusb_get_device_descriptor(dev, &desc);
|
|
||||||
if (res < 0) {
|
|
||||||
DEBUG_WARN( "WARN: libusb_get_device_descriptor() failed: %s",
|
|
||||||
libusb_strerror(res));
|
|
||||||
libusb_free_device_list(devs, 1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
libusb_device_handle *handle;
|
|
||||||
res = libusb_open(dev, &handle);
|
|
||||||
if (res != LIBUSB_SUCCESS) {
|
|
||||||
if (!access_problems) {
|
|
||||||
DEBUG_INFO("INFO: Open USB %04x:%04x failed\n",
|
|
||||||
desc.idVendor, desc.idProduct);
|
|
||||||
access_problems = true;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
res = libusb_get_string_descriptor_ascii(
|
|
||||||
handle, desc.iSerialNumber, (uint8_t*)serial,
|
|
||||||
sizeof(serial));
|
|
||||||
if (res <= 0) {
|
|
||||||
/* This can fail for many devices. Continue silent!*/
|
|
||||||
libusb_close(handle);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (cl_opts->opt_serial && !strstr(serial, cl_opts->opt_serial)) {
|
|
||||||
libusb_close(handle);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
res = libusb_get_string_descriptor_ascii(
|
|
||||||
handle, desc.iManufacturer, (uint8_t*)manufacturer,
|
|
||||||
sizeof(manufacturer));
|
|
||||||
if (res > 0) {
|
|
||||||
res = libusb_get_string_descriptor_ascii(
|
|
||||||
handle, desc.iProduct, (uint8_t*)product,
|
|
||||||
sizeof(product));
|
|
||||||
if (res <= 0) {
|
|
||||||
DEBUG_WARN( "WARN:"
|
|
||||||
"libusb_get_string_descriptor_ascii "
|
|
||||||
"for ident_string failed: %s\n",
|
|
||||||
libusb_strerror(res));
|
|
||||||
libusb_close(handle);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
libusb_close(handle);
|
|
||||||
if (cl_opts->opt_ident_string) {
|
|
||||||
char *match_manu = NULL;
|
|
||||||
char *match_product = NULL;
|
|
||||||
match_manu = strstr(manufacturer, cl_opts->opt_ident_string);
|
|
||||||
match_product = strstr(product, cl_opts->opt_ident_string);
|
|
||||||
if (!match_manu && !match_product) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Either serial and/or ident_string match or are not given.
|
|
||||||
* Check type.*/
|
|
||||||
if ((desc.idVendor == VENDOR_ID_BMP) &&
|
|
||||||
(desc.idProduct == PRODUCT_ID_BMP)) {
|
|
||||||
type = BMP_TYPE_BMP;
|
|
||||||
} else if ((strstr(manufacturer, "CMSIS")) || (strstr(product, "CMSIS"))) {
|
|
||||||
type = BMP_TYPE_CMSIS_DAP;
|
|
||||||
} else if (desc.idVendor == VENDOR_ID_STLINK) {
|
|
||||||
if ((desc.idProduct == PRODUCT_ID_STLINKV2) ||
|
|
||||||
(desc.idProduct == PRODUCT_ID_STLINKV21) ||
|
|
||||||
(desc.idProduct == PRODUCT_ID_STLINKV21_MSD) ||
|
|
||||||
(desc.idProduct == PRODUCT_ID_STLINKV3) ||
|
|
||||||
(desc.idProduct == PRODUCT_ID_STLINKV3E)) {
|
|
||||||
type = BMP_TYPE_STLINKV2;
|
|
||||||
} else {
|
|
||||||
if (desc.idProduct == PRODUCT_ID_STLINKV1)
|
|
||||||
DEBUG_WARN( "INFO: STLINKV1 not supported\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else if (desc.idVendor == VENDOR_ID_SEGGER) {
|
|
||||||
type = BMP_TYPE_JLINK;
|
|
||||||
} else {
|
|
||||||
cable_desc_t *cable = &cable_desc[0];
|
|
||||||
for (; cable->name; cable++) {
|
|
||||||
bool found = false;
|
|
||||||
if ((cable->vendor != desc.idVendor) || (cable->product != desc.idProduct))
|
|
||||||
continue; /* VID/PID do not match*/
|
|
||||||
if (cl_opts->opt_cable) {
|
|
||||||
if (strcmp(cable->name, cl_opts->opt_cable))
|
|
||||||
continue; /* cable names do not match*/
|
|
||||||
else
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
if (cable->description) {
|
|
||||||
if (strcmp(cable->description, product))
|
|
||||||
continue; /* discriptions do not match*/
|
|
||||||
else
|
|
||||||
found = true;
|
|
||||||
} else { /* VID/PID fits, but no cl_opts->opt_cable and no description*/
|
|
||||||
if ((cable->vendor == 0x0403) && /* FTDI*/
|
|
||||||
((cable->product == 0x6010) || /* FT2232C/D/H*/
|
|
||||||
(cable->product == 0x6011) || /* FT4232H Quad HS USB-UART/FIFO IC */
|
|
||||||
(cable->product == 0x6014))) { /* FT232H Single HS USB-UART/FIFO IC */
|
|
||||||
ftdi_unknown = true;
|
|
||||||
continue; /* Cable name is needed */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found) {
|
|
||||||
active_cable = cable->name;
|
|
||||||
type = BMP_TYPE_LIBFTDI;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!cable->name)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (report) {
|
|
||||||
DEBUG_WARN("%2d: %s, %s, %s\n", found_debuggers + 1,
|
|
||||||
serial,
|
|
||||||
manufacturer,product);
|
|
||||||
}
|
|
||||||
info->vid = desc.idVendor;
|
|
||||||
info->pid = desc.idProduct;
|
|
||||||
info->bmp_type = type;
|
|
||||||
strncpy(info->serial, serial, sizeof(info->serial));
|
|
||||||
strncpy(info->product, product, sizeof(info->product));
|
|
||||||
strncpy(info->manufacturer, manufacturer, sizeof(info->manufacturer));
|
|
||||||
if (cl_opts->opt_position &&
|
|
||||||
(cl_opts->opt_position == (found_debuggers + 1))) {
|
|
||||||
found_debuggers = 1;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
found_debuggers++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((found_debuggers == 0) && ftdi_unknown)
|
|
||||||
DEBUG_WARN("Generic FTDI MPSSE VID/PID found. Please specify exact type with \"-c <cable>\" !\n");
|
|
||||||
if ((found_debuggers == 1) && !cl_opts->opt_cable && (type == BMP_TYPE_LIBFTDI))
|
|
||||||
cl_opts->opt_cable = active_cable;
|
|
||||||
if (!found_debuggers && cl_opts->opt_list_only)
|
|
||||||
DEBUG_WARN("No usable debugger found\n");
|
|
||||||
if ((found_debuggers > 1) ||
|
|
||||||
((found_debuggers == 1) && (cl_opts->opt_list_only))) {
|
|
||||||
if (!report) {
|
|
||||||
if (found_debuggers > 1)
|
|
||||||
DEBUG_WARN("%d debuggers found!\nSelect with -P <pos>, "
|
|
||||||
"-s <(partial)serial no.> "
|
|
||||||
"and/or -S <(partial)description>\n",
|
|
||||||
found_debuggers);
|
|
||||||
report = true;
|
|
||||||
goto rescan;
|
|
||||||
} else {
|
|
||||||
if (found_debuggers > 0)
|
|
||||||
access_problems = false;
|
|
||||||
found_debuggers = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found_debuggers && access_problems)
|
|
||||||
DEBUG_WARN(
|
|
||||||
"No debugger found. Please check access rights to USB devices!\n");
|
|
||||||
libusb_free_device_list(devs, 1);
|
|
||||||
return (found_debuggers == 1) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void platform_init(int argc, char **argv)
|
void platform_init(int argc, char **argv)
|
||||||
{
|
{
|
||||||
BMP_CL_OPTIONS_t cl_opts = {0};
|
|
||||||
cl_opts.opt_idstring = "Blackmagic PC-Hosted";
|
|
||||||
cl_init(&cl_opts, argc, argv);
|
cl_init(&cl_opts, argc, argv);
|
||||||
atexit(exit_function);
|
atexit(exit_function);
|
||||||
signal(SIGTERM, sigterm_handler);
|
signal(SIGTERM, sigterm_handler);
|
||||||
signal(SIGINT, sigterm_handler);
|
signal(SIGINT, sigterm_handler);
|
||||||
int res = libusb_init(&info.libusb_ctx);
|
if (cl_opts.opt_device)
|
||||||
if (res) {
|
|
||||||
DEBUG_WARN( "Fatal: Failed to get USB context: %s\n",
|
|
||||||
libusb_strerror(res));
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
if (cl_opts.opt_device) {
|
|
||||||
info.bmp_type = BMP_TYPE_BMP;
|
info.bmp_type = BMP_TYPE_BMP;
|
||||||
} else if (cl_opts.opt_cable) {
|
else if (find_debuggers(&cl_opts, &info))
|
||||||
if ((!strcmp(cl_opts.opt_cable, "list")) ||
|
|
||||||
(!strcmp(cl_opts.opt_cable, "l"))) {
|
|
||||||
cable_desc_t *cable = &cable_desc[0];
|
|
||||||
DEBUG_WARN("Available cables:\n");
|
|
||||||
for (; cable->name; cable++) {
|
|
||||||
DEBUG_WARN("\t%s\n", cable->name);
|
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
info.bmp_type = BMP_TYPE_LIBFTDI;
|
|
||||||
} else if (find_debuggers(&cl_opts, &info)) {
|
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
bmp_ident(&info);
|
||||||
DEBUG_WARN("Using %04x:%04x %s %s %s\n", info.vid, info.pid, info.serial,
|
|
||||||
info.manufacturer,
|
|
||||||
info.product);
|
|
||||||
switch (info.bmp_type) {
|
switch (info.bmp_type) {
|
||||||
case BMP_TYPE_BMP:
|
case BMP_TYPE_BMP:
|
||||||
if (serial_open(&cl_opts, info.serial))
|
if (serial_open(&cl_opts, info.serial))
|
||||||
exit(-1);
|
exit(-1);
|
||||||
remote_init(true);
|
remote_init();
|
||||||
break;
|
break;
|
||||||
case BMP_TYPE_STLINKV2:
|
case BMP_TYPE_STLINKV2:
|
||||||
if (stlink_init( &info))
|
if (stlink_init(&info))
|
||||||
exit(-1);
|
exit(-1);
|
||||||
break;
|
break;
|
||||||
case BMP_TYPE_CMSIS_DAP:
|
case BMP_TYPE_CMSIS_DAP:
|
||||||
if (dap_init( &info))
|
if (dap_init(&info))
|
||||||
exit(-1);
|
exit(-1);
|
||||||
break;
|
break;
|
||||||
case BMP_TYPE_LIBFTDI:
|
case BMP_TYPE_LIBFTDI:
|
||||||
@ -321,45 +113,38 @@ void platform_init(int argc, char **argv)
|
|||||||
default:
|
default:
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
int ret = -1;
|
if (cl_opts.opt_mode != BMP_MODE_DEBUG)
|
||||||
if (cl_opts.opt_mode != BMP_MODE_DEBUG) {
|
exit(cl_execute(&cl_opts));
|
||||||
ret = cl_execute(&cl_opts);
|
else {
|
||||||
} else {
|
|
||||||
gdb_if_init();
|
gdb_if_init();
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
rtt_if_init();
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
exit(ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int platform_adiv5_swdp_scan(void)
|
int platform_adiv5_swdp_scan(uint32_t targetid)
|
||||||
{
|
{
|
||||||
|
info.is_jtag = false;
|
||||||
|
platform_max_frequency_set(cl_opts.opt_max_swj_frequency);
|
||||||
switch (info.bmp_type) {
|
switch (info.bmp_type) {
|
||||||
case BMP_TYPE_BMP:
|
case BMP_TYPE_BMP:
|
||||||
case BMP_TYPE_LIBFTDI:
|
case BMP_TYPE_LIBFTDI:
|
||||||
return adiv5_swdp_scan();
|
case BMP_TYPE_CMSIS_DAP:
|
||||||
|
return adiv5_swdp_scan(targetid);
|
||||||
break;
|
break;
|
||||||
case BMP_TYPE_STLINKV2:
|
case BMP_TYPE_STLINKV2:
|
||||||
{
|
{
|
||||||
target_list_free();
|
target_list_free();
|
||||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
||||||
if (!stlink_enter_debug_swd(&info, dp)) {
|
if (stlink_enter_debug_swd(&info, dp)) {
|
||||||
|
free(dp);
|
||||||
|
} else {
|
||||||
adiv5_dp_init(dp);
|
adiv5_dp_init(dp);
|
||||||
if (target_list)
|
if (target_list)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
free(dp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BMP_TYPE_CMSIS_DAP:
|
|
||||||
{
|
|
||||||
target_list_free();
|
|
||||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
|
||||||
if (!dap_enter_debug_swd(dp)) {
|
|
||||||
adiv5_dp_init(dp);
|
|
||||||
if (target_list)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
free(dp);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BMP_TYPE_JLINK:
|
case BMP_TYPE_JLINK:
|
||||||
@ -370,25 +155,34 @@ int platform_adiv5_swdp_scan(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int platform_swdptap_init(void)
|
int swdptap_init(ADIv5_DP_t *dp)
|
||||||
{
|
{
|
||||||
switch (info.bmp_type) {
|
switch (info.bmp_type) {
|
||||||
case BMP_TYPE_BMP:
|
case BMP_TYPE_BMP:
|
||||||
return remote_swdptap_init(&swd_proc);
|
return remote_swdptap_init(dp);
|
||||||
case BMP_TYPE_STLINKV2:
|
|
||||||
case BMP_TYPE_CMSIS_DAP:
|
case BMP_TYPE_CMSIS_DAP:
|
||||||
|
return dap_swdptap_init(dp);
|
||||||
|
case BMP_TYPE_STLINKV2:
|
||||||
case BMP_TYPE_JLINK:
|
case BMP_TYPE_JLINK:
|
||||||
return 0;
|
return 0;
|
||||||
case BMP_TYPE_LIBFTDI:
|
case BMP_TYPE_LIBFTDI:
|
||||||
return libftdi_swdptap_init(&swd_proc);
|
return libftdi_swdptap_init(dp);
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void platform_add_jtag_dev(int i, const jtag_dev_t *jtag_dev)
|
||||||
|
{
|
||||||
|
if (info.bmp_type == BMP_TYPE_BMP)
|
||||||
|
remote_add_jtag_dev(i, jtag_dev);
|
||||||
|
}
|
||||||
|
|
||||||
int platform_jtag_scan(const uint8_t *lrlens)
|
int platform_jtag_scan(const uint8_t *lrlens)
|
||||||
{
|
{
|
||||||
|
info.is_jtag = true;
|
||||||
|
platform_max_frequency_set(cl_opts.opt_max_swj_frequency);
|
||||||
switch (info.bmp_type) {
|
switch (info.bmp_type) {
|
||||||
case BMP_TYPE_BMP:
|
case BMP_TYPE_BMP:
|
||||||
case BMP_TYPE_LIBFTDI:
|
case BMP_TYPE_LIBFTDI:
|
||||||
@ -424,8 +218,13 @@ int platform_jtagtap_init(void)
|
|||||||
|
|
||||||
void platform_adiv5_dp_defaults(ADIv5_DP_t *dp)
|
void platform_adiv5_dp_defaults(ADIv5_DP_t *dp)
|
||||||
{
|
{
|
||||||
|
dp->dp_bmp_type = info.bmp_type;
|
||||||
switch (info.bmp_type) {
|
switch (info.bmp_type) {
|
||||||
case BMP_TYPE_BMP:
|
case BMP_TYPE_BMP:
|
||||||
|
if (cl_opts.opt_no_hl) {
|
||||||
|
DEBUG_WARN("Not using HL commands\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
return remote_adiv5_dp_defaults(dp);
|
return remote_adiv5_dp_defaults(dp);
|
||||||
case BMP_TYPE_STLINKV2:
|
case BMP_TYPE_STLINKV2:
|
||||||
return stlink_adiv5_dp_defaults(dp);
|
return stlink_adiv5_dp_defaults(dp);
|
||||||
@ -498,6 +297,10 @@ void platform_srst_set_val(bool assert)
|
|||||||
return remote_srst_set_val(assert);
|
return remote_srst_set_val(assert);
|
||||||
case BMP_TYPE_JLINK:
|
case BMP_TYPE_JLINK:
|
||||||
return jlink_srst_set_val(&info, assert);
|
return jlink_srst_set_val(&info, assert);
|
||||||
|
case BMP_TYPE_LIBFTDI:
|
||||||
|
return libftdi_srst_set_val(assert);
|
||||||
|
case BMP_TYPE_CMSIS_DAP:
|
||||||
|
return dap_srst_set_val(assert);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -512,12 +315,83 @@ bool platform_srst_get_val(void)
|
|||||||
return stlink_srst_get_val();
|
return stlink_srst_get_val();
|
||||||
case BMP_TYPE_JLINK:
|
case BMP_TYPE_JLINK:
|
||||||
return jlink_srst_get_val(&info);
|
return jlink_srst_get_val(&info);
|
||||||
|
case BMP_TYPE_LIBFTDI:
|
||||||
|
return libftdi_srst_get_val();
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void platform_max_frequency_set(uint32_t freq)
|
||||||
|
{
|
||||||
|
if (!freq)
|
||||||
|
return;
|
||||||
|
switch (info.bmp_type) {
|
||||||
|
case BMP_TYPE_BMP:
|
||||||
|
remote_max_frequency_set(freq);
|
||||||
|
break;
|
||||||
|
case BMP_TYPE_CMSIS_DAP:
|
||||||
|
dap_swj_clock(freq);
|
||||||
|
break;
|
||||||
|
case BMP_TYPE_LIBFTDI:
|
||||||
|
libftdi_max_frequency_set(freq);
|
||||||
|
break;
|
||||||
|
case BMP_TYPE_STLINKV2:
|
||||||
|
stlink_max_frequency_set(&info, freq);
|
||||||
|
break;
|
||||||
|
case BMP_TYPE_JLINK:
|
||||||
|
jlink_max_frequency_set(&info, freq);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DEBUG_WARN("Setting max SWJ frequency not yet implemented\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uint32_t max_freq = platform_max_frequency_get();
|
||||||
|
if (max_freq == FREQ_FIXED)
|
||||||
|
DEBUG_INFO("Device has fixed frequency for %s\n",
|
||||||
|
(info.is_jtag) ? "JTAG" : "SWD" );
|
||||||
|
else
|
||||||
|
DEBUG_INFO("Speed set to %7.4f MHz for %s\n",
|
||||||
|
platform_max_frequency_get() / 1000000.0,
|
||||||
|
(info.is_jtag) ? "JTAG" : "SWD" );
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t platform_max_frequency_get(void)
|
||||||
|
{
|
||||||
|
switch (info.bmp_type) {
|
||||||
|
case BMP_TYPE_BMP:
|
||||||
|
return remote_max_frequency_get();
|
||||||
|
case BMP_TYPE_CMSIS_DAP:
|
||||||
|
return dap_swj_clock(0);
|
||||||
|
break;
|
||||||
|
case BMP_TYPE_LIBFTDI:
|
||||||
|
return libftdi_max_frequency_get();
|
||||||
|
case BMP_TYPE_STLINKV2:
|
||||||
|
return stlink_max_frequency_get(&info);
|
||||||
|
case BMP_TYPE_JLINK:
|
||||||
|
return jlink_max_frequency_get(&info);
|
||||||
|
default:
|
||||||
|
DEBUG_WARN("Reading max SWJ frequency not yet implemented\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void platform_target_set_power(bool power)
|
||||||
|
{
|
||||||
|
switch (info.bmp_type) {
|
||||||
|
case BMP_TYPE_BMP:
|
||||||
|
if (remote_target_set_power(power))
|
||||||
|
DEBUG_INFO("Powering up device!\n");
|
||||||
|
else
|
||||||
|
DEBUG_WARN("Powering up device unimplemented or failed\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void platform_buffer_flush(void)
|
void platform_buffer_flush(void)
|
||||||
{
|
{
|
||||||
switch (info.bmp_type) {
|
switch (info.bmp_type) {
|
||||||
|
@ -1,22 +1,35 @@
|
|||||||
#ifndef __PLATFORM_H
|
#ifndef __PLATFORM_H
|
||||||
#define __PLATFORM_H
|
#define __PLATFORM_H
|
||||||
|
|
||||||
#include <libusb-1.0/libusb.h>
|
|
||||||
#include "libusb_utils.h"
|
|
||||||
#include <libftdi1/ftdi.h>
|
|
||||||
|
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
|
|
||||||
char *platform_ident(void);
|
char *platform_ident(void);
|
||||||
void platform_buffer_flush(void);
|
void platform_buffer_flush(void);
|
||||||
|
|
||||||
#define PLATFORM_IDENT() "NONE"
|
#define PLATFORM_IDENT "(PC-Hosted) "
|
||||||
#define SET_IDLE_STATE(x)
|
#define SET_IDLE_STATE(x)
|
||||||
#define SET_RUN_STATE(x)
|
#define SET_RUN_STATE(x)
|
||||||
|
|
||||||
|
#define SYSTICKHZ 1000
|
||||||
|
|
||||||
#define VENDOR_ID_BMP 0x1d50
|
#define VENDOR_ID_BMP 0x1d50
|
||||||
|
#define PRODUCT_ID_BMP_BL 0x6017
|
||||||
#define PRODUCT_ID_BMP 0x6018
|
#define PRODUCT_ID_BMP 0x6018
|
||||||
|
|
||||||
|
#define VENDOR_ID_STLINK 0x0483
|
||||||
|
#define PRODUCT_ID_STLINK_MASK 0xffe0
|
||||||
|
#define PRODUCT_ID_STLINK_GROUP 0x3740
|
||||||
|
#define PRODUCT_ID_STLINKV1 0x3744
|
||||||
|
#define PRODUCT_ID_STLINKV2 0x3748
|
||||||
|
#define PRODUCT_ID_STLINKV21 0x374b
|
||||||
|
#define PRODUCT_ID_STLINKV21_MSD 0x3752
|
||||||
|
#define PRODUCT_ID_STLINKV3_NO_MSD 0x3754
|
||||||
|
#define PRODUCT_ID_STLINKV3_BL 0x374d
|
||||||
|
#define PRODUCT_ID_STLINKV3 0x374f
|
||||||
|
#define PRODUCT_ID_STLINKV3E 0x374e
|
||||||
|
|
||||||
|
#define VENDOR_ID_SEGGER 0x1366
|
||||||
|
|
||||||
typedef enum bmp_type_s {
|
typedef enum bmp_type_s {
|
||||||
BMP_TYPE_NONE = 0,
|
BMP_TYPE_NONE = 0,
|
||||||
BMP_TYPE_BMP,
|
BMP_TYPE_BMP,
|
||||||
@ -26,19 +39,5 @@ typedef enum bmp_type_s {
|
|||||||
BMP_TYPE_JLINK
|
BMP_TYPE_JLINK
|
||||||
} bmp_type_t;
|
} bmp_type_t;
|
||||||
|
|
||||||
typedef struct bmp_info_s {
|
void gdb_ident(char *p, int count);
|
||||||
bmp_type_t bmp_type;
|
|
||||||
libusb_context *libusb_ctx;
|
|
||||||
struct ftdi_context *ftdic;
|
|
||||||
usb_link_t *usb_link;
|
|
||||||
unsigned int vid;
|
|
||||||
unsigned int pid;
|
|
||||||
char dev;
|
|
||||||
char serial[64];
|
|
||||||
char manufacturer[128];
|
|
||||||
char product[128];
|
|
||||||
} bmp_info_t;
|
|
||||||
|
|
||||||
extern bmp_info_t info;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,13 +26,11 @@
|
|||||||
* Should share interface with swdptap.c or at least clean up...
|
* Should share interface with swdptap.c or at least clean up...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "general.h"
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "general.h"
|
|
||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
#include "jtagtap.h"
|
#include "jtagtap.h"
|
||||||
#include "bmp_remote.h"
|
#include "bmp_remote.h"
|
||||||
@ -106,35 +104,58 @@ static void jtagtap_tms_seq(uint32_t MS, int ticks)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* At least up to v1.7.1-233, remote handles only up to 32 ticks in one
|
||||||
|
* call. Break up large calls.
|
||||||
|
*
|
||||||
|
* FIXME: Provide and test faster call and keep fallback
|
||||||
|
* for old firmware
|
||||||
|
*/
|
||||||
static void jtagtap_tdi_tdo_seq(
|
static void jtagtap_tdi_tdo_seq(
|
||||||
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
|
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||||
{
|
{
|
||||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
uint64_t DIl=*(uint64_t *)DI;
|
if(!ticks || (!DI && !DO))
|
||||||
|
return;
|
||||||
|
while (ticks) {
|
||||||
|
int chunk;
|
||||||
|
if (ticks < 65)
|
||||||
|
chunk = ticks;
|
||||||
|
else {
|
||||||
|
chunk = 64;
|
||||||
|
}
|
||||||
|
ticks -= chunk;
|
||||||
|
uint64_t di = 0;
|
||||||
|
int bytes = (chunk + 7) >> 3;
|
||||||
|
int i = 0;
|
||||||
|
if (DI) {
|
||||||
|
for (; i < bytes; i++) {
|
||||||
|
di |= *DI << (i * 8);
|
||||||
|
DI++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* PRIx64 differs with system. Use it explicit in the format string*/
|
||||||
|
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,
|
||||||
|
"!J%c%02x%" PRIx64 "%c",
|
||||||
|
(!ticks && final_tms) ?
|
||||||
|
REMOTE_TDITDO_TMS : REMOTE_TDITDO_NOTMS,
|
||||||
|
chunk, di, REMOTE_EOM);
|
||||||
|
platform_buffer_write(construct,s);
|
||||||
|
|
||||||
if(!ticks || !DI) return;
|
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||||
|
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||||
/* Reduce the length of DI according to the bits we're transmitting */
|
DEBUG_WARN("jtagtap_tms_seq failed, error %s\n",
|
||||||
DIl &= (1LL << (ticks + 1))-1;
|
s ? (char *)&(construct[1]) : "unknown");
|
||||||
|
exit(-1);
|
||||||
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,
|
}
|
||||||
REMOTE_JTAG_TDIDO_STR,
|
if (DO) {
|
||||||
final_tms ? REMOTE_TDITDO_TMS : REMOTE_TDITDO_NOTMS,
|
uint64_t res = remotehston(-1, (char *)&construct[1]);
|
||||||
ticks, DIl);
|
for (i = bytes; i > 0; i--) {
|
||||||
platform_buffer_write(construct,s);
|
*DO++ = res & 0xff;
|
||||||
|
res >>= 8;
|
||||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
}
|
||||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
}
|
||||||
DEBUG_WARN("jtagtap_tms_seq failed, error %s\n",
|
|
||||||
s ? (char *)&(construct[1]) : "unknown");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DO) {
|
|
||||||
uint64_t DOl = remotehston(-1, (char *)&construct[1]);
|
|
||||||
*(uint64_t *)DO = DOl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||||
* Modified by Dave Marples <dave@marples.net>
|
* Modified by Dave Marples <dave@marples.net>
|
||||||
* Modification (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
* Modified 2020 - 2021 by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -35,7 +35,7 @@ static uint32_t swdptap_seq_in(int ticks);
|
|||||||
static void swdptap_seq_out(uint32_t MS, int ticks);
|
static void swdptap_seq_out(uint32_t MS, int ticks);
|
||||||
static void swdptap_seq_out_parity(uint32_t MS, int ticks);
|
static void swdptap_seq_out_parity(uint32_t MS, int ticks);
|
||||||
|
|
||||||
int remote_swdptap_init(swd_proc_t *swd_proc)
|
int remote_swdptap_init(ADIv5_DP_t *dp)
|
||||||
{
|
{
|
||||||
DEBUG_WIRE("remote_swdptap_init\n");
|
DEBUG_WIRE("remote_swdptap_init\n");
|
||||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||||
@ -50,11 +50,14 @@ int remote_swdptap_init(swd_proc_t *swd_proc)
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
swd_proc->swdptap_seq_in = swdptap_seq_in;
|
dp->seq_in = swdptap_seq_in;
|
||||||
swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity;
|
dp->seq_in_parity = swdptap_seq_in_parity;
|
||||||
swd_proc->swdptap_seq_out = swdptap_seq_out;
|
dp->seq_out = swdptap_seq_out;
|
||||||
swd_proc->swdptap_seq_out_parity = swdptap_seq_out_parity;
|
dp->seq_out_parity = swdptap_seq_out_parity;
|
||||||
|
dp->dp_read = firmware_swdp_read;
|
||||||
|
dp->error = firmware_swdp_error;
|
||||||
|
dp->low_access = firmware_swdp_low_access;
|
||||||
|
dp->abort = firmware_swdp_abort;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
127
src/platforms/hosted/rtt_if.c
Normal file
127
src/platforms/hosted/rtt_if.c
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Black Magic Debug project.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Koen De Vleeschauwer
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <general.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <rtt_if.h>
|
||||||
|
|
||||||
|
/* maybe rewrite this as tcp server */
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
#include <termios.h>
|
||||||
|
|
||||||
|
/* linux */
|
||||||
|
static struct termios saved_ttystate;
|
||||||
|
static bool tty_saved = false;
|
||||||
|
|
||||||
|
/* set up and tear down */
|
||||||
|
|
||||||
|
int rtt_if_init()
|
||||||
|
{
|
||||||
|
struct termios ttystate;
|
||||||
|
tcgetattr(STDIN_FILENO, &saved_ttystate);
|
||||||
|
tty_saved = true;
|
||||||
|
tcgetattr(STDIN_FILENO, &ttystate);
|
||||||
|
ttystate.c_lflag &= ~ICANON;
|
||||||
|
ttystate.c_lflag &= ~ECHO;
|
||||||
|
ttystate.c_cc[VMIN] = 1;
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
|
||||||
|
int flags = fcntl(0, F_GETFL, 0);
|
||||||
|
fcntl(0, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtt_if_exit()
|
||||||
|
{
|
||||||
|
if (tty_saved)
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &saved_ttystate);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write buffer to terminal */
|
||||||
|
|
||||||
|
uint32_t rtt_write(const char *buf, uint32_t len)
|
||||||
|
{
|
||||||
|
write(1, buf, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read character from terminal */
|
||||||
|
|
||||||
|
int32_t rtt_getchar()
|
||||||
|
{
|
||||||
|
char ch;
|
||||||
|
int len;
|
||||||
|
len = read(0, &ch, 1);
|
||||||
|
if (len == 1) return ch;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* true if no characters available */
|
||||||
|
|
||||||
|
bool rtt_nodata()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* windows, output only */
|
||||||
|
|
||||||
|
int rtt_if_init()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtt_if_exit()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write buffer to terminal */
|
||||||
|
|
||||||
|
uint32_t rtt_write(const char *buf, uint32_t len)
|
||||||
|
{
|
||||||
|
write(1, buf, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read character from terminal */
|
||||||
|
|
||||||
|
int32_t rtt_getchar()
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* true if no characters available */
|
||||||
|
|
||||||
|
bool rtt_nodata()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -27,10 +27,12 @@
|
|||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "gdb_if.h"
|
#include "gdb_if.h"
|
||||||
#include "adiv5.h"
|
#include "adiv5.h"
|
||||||
|
#include "bmp_hosted.h"
|
||||||
#include "stlinkv2.h"
|
#include "stlinkv2.h"
|
||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
#include "jtag_devs.h"
|
#include "jtag_devs.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
|
#include "cortexm.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -40,16 +42,6 @@
|
|||||||
|
|
||||||
#include "cl_utils.h"
|
#include "cl_utils.h"
|
||||||
|
|
||||||
#define VENDOR_ID_STLINK 0x483
|
|
||||||
#define PRODUCT_ID_STLINK_MASK 0xffe0
|
|
||||||
#define PRODUCT_ID_STLINK_GROUP 0x3740
|
|
||||||
#define PRODUCT_ID_STLINKV1 0x3744
|
|
||||||
#define PRODUCT_ID_STLINKV2 0x3748
|
|
||||||
#define PRODUCT_ID_STLINKV21 0x374b
|
|
||||||
#define PRODUCT_ID_STLINKV21_MSD 0x3752
|
|
||||||
#define PRODUCT_ID_STLINKV3 0x374f
|
|
||||||
#define PRODUCT_ID_STLINKV3E 0x374e
|
|
||||||
|
|
||||||
#define STLINK_SWIM_ERR_OK 0x00
|
#define STLINK_SWIM_ERR_OK 0x00
|
||||||
#define STLINK_SWIM_BUSY 0x01
|
#define STLINK_SWIM_BUSY 0x01
|
||||||
#define STLINK_DEBUG_ERR_OK 0x80
|
#define STLINK_DEBUG_ERR_OK 0x80
|
||||||
@ -198,7 +190,6 @@ typedef struct {
|
|||||||
libusb_context* libusb_ctx;
|
libusb_context* libusb_ctx;
|
||||||
uint16_t vid;
|
uint16_t vid;
|
||||||
uint16_t pid;
|
uint16_t pid;
|
||||||
uint8_t transport_mode;
|
|
||||||
bool srst;
|
bool srst;
|
||||||
uint8_t dap_select;
|
uint8_t dap_select;
|
||||||
uint8_t ep_tx;
|
uint8_t ep_tx;
|
||||||
@ -348,7 +339,8 @@ static int stlink_send_recv_retry(uint8_t *txbuf, size_t txsize,
|
|||||||
if (res == STLINK_ERROR_OK)
|
if (res == STLINK_ERROR_OK)
|
||||||
return res;
|
return res;
|
||||||
uint32_t now = platform_time_ms();
|
uint32_t now = platform_time_ms();
|
||||||
if (((now - start) > 1000) || (res != STLINK_ERROR_WAIT)) {
|
if (((now - start) > cortexm_wait_timeout) ||
|
||||||
|
(res != STLINK_ERROR_WAIT)) {
|
||||||
DEBUG_WARN("write_retry failed. ");
|
DEBUG_WARN("write_retry failed. ");
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -397,6 +389,9 @@ static int write_retry(uint8_t *cmdbuf, size_t cmdsize,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Version data is at 0x080103f8 with STLINKV3 bootloader flashed with
|
||||||
|
* STLinkUpgrade_v3[3|5].jar
|
||||||
|
*/
|
||||||
static void stlink_version(bmp_info_t *info)
|
static void stlink_version(bmp_info_t *info)
|
||||||
{
|
{
|
||||||
if (Stlink.ver_hw == 30) {
|
if (Stlink.ver_hw == 30) {
|
||||||
@ -434,7 +429,8 @@ static void stlink_version(bmp_info_t *info)
|
|||||||
Stlink.ver_swim = (version >> 0) & 0x3f;
|
Stlink.ver_swim = (version >> 0) & 0x3f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEBUG_INFO("V%dJ%d",Stlink.ver_stlink, Stlink.ver_jtag);
|
DEBUG_INFO("STLink firmware version: V%dJ%d",Stlink.ver_stlink,
|
||||||
|
Stlink.ver_jtag);
|
||||||
if (Stlink.ver_hw == 30) {
|
if (Stlink.ver_hw == 30) {
|
||||||
DEBUG_INFO("M%dB%dS%d", Stlink.ver_mass, Stlink.ver_bridge, Stlink.ver_swim);
|
DEBUG_INFO("M%dB%dS%d", Stlink.ver_mass, Stlink.ver_bridge, Stlink.ver_swim);
|
||||||
} else if (Stlink.ver_hw == 20) {
|
} else if (Stlink.ver_hw == 20) {
|
||||||
@ -514,23 +510,39 @@ int stlink_init(bmp_info_t *info)
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
while ((dev = devs[i++]) != NULL) {
|
while ((dev = devs[i++]) != NULL) {
|
||||||
struct libusb_device_descriptor desc;
|
struct libusb_device_descriptor desc;
|
||||||
int r = libusb_get_device_descriptor(dev, &desc);
|
int result = libusb_get_device_descriptor(dev, &desc);
|
||||||
if (r < 0) {
|
if (result != LIBUSB_SUCCESS) {
|
||||||
DEBUG_WARN("libusb_get_device_descriptor failed %s",
|
DEBUG_WARN("libusb_get_device_descriptor failed %s",
|
||||||
libusb_strerror(r));
|
libusb_strerror(result));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ((desc.idVendor != info->vid) ||
|
if (desc.idVendor != info->vid ||
|
||||||
(desc.idProduct != info->pid) ||
|
desc.idProduct != info->pid) {
|
||||||
(libusb_open(dev, &sl->ul_libusb_device_handle)
|
continue;
|
||||||
!= LIBUSB_SUCCESS)) {
|
}
|
||||||
|
if ((result = libusb_open(dev, &sl->ul_libusb_device_handle)) != LIBUSB_SUCCESS)
|
||||||
|
{
|
||||||
|
DEBUG_WARN("Failed to open STLink device %04x:%04x - %s\n",
|
||||||
|
desc.idVendor, desc.idProduct, libusb_strerror(result));
|
||||||
|
DEBUG_WARN("Are you sure the permissions on the device are set correctly?\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
char serial[64];
|
char serial[64];
|
||||||
r = libusb_get_string_descriptor_ascii(
|
if (desc.iSerialNumber) {
|
||||||
sl->ul_libusb_device_handle, desc.iSerialNumber,
|
int result = libusb_get_string_descriptor_ascii(sl->ul_libusb_device_handle,
|
||||||
(uint8_t*)serial,sizeof(serial));
|
desc.iSerialNumber, (uint8_t *)serial, sizeof(serial));
|
||||||
if (r <= 0 || !strstr(serial, info->serial)) {
|
/* If the call fails and it's not because the device gave us STALL, continue to the next one */
|
||||||
|
if (result < 0 && result != LIBUSB_ERROR_PIPE) {
|
||||||
|
libusb_close(sl->ul_libusb_device_handle);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (result <= 0)
|
||||||
|
serial[0] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
serial[0] = '\0';
|
||||||
|
/* Likewise, if the serial number returned doesn't match the one in info, go to next */
|
||||||
|
if (!strstr(serial, info->serial)) {
|
||||||
libusb_close(sl->ul_libusb_device_handle);
|
libusb_close(sl->ul_libusb_device_handle);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -539,21 +551,31 @@ int stlink_init(bmp_info_t *info)
|
|||||||
}
|
}
|
||||||
libusb_free_device_list(devs, 1);
|
libusb_free_device_list(devs, 1);
|
||||||
if (!found)
|
if (!found)
|
||||||
|
return 1;
|
||||||
|
if (info->vid != VENDOR_ID_STLINK)
|
||||||
return 0;
|
return 0;
|
||||||
if (info->pid == PRODUCT_ID_STLINKV2) {
|
switch (info->pid) {
|
||||||
|
case PRODUCT_ID_STLINKV2:
|
||||||
Stlink.ver_hw = 20;
|
Stlink.ver_hw = 20;
|
||||||
info->usb_link->ep_tx = 2;
|
info->usb_link->ep_tx = 2;
|
||||||
Stlink.ep_tx = 2;
|
Stlink.ep_tx = 2;
|
||||||
} else if ((info->pid == PRODUCT_ID_STLINKV21)||
|
break;
|
||||||
(info->pid == PRODUCT_ID_STLINKV21_MSD)) {
|
case PRODUCT_ID_STLINKV21 :
|
||||||
|
case PRODUCT_ID_STLINKV21_MSD:
|
||||||
Stlink.ver_hw = 21;
|
Stlink.ver_hw = 21;
|
||||||
info->usb_link->ep_tx = 1;
|
info->usb_link->ep_tx = 1;
|
||||||
Stlink.ep_tx = 1;
|
Stlink.ep_tx = 1;
|
||||||
} else if ((info->pid == PRODUCT_ID_STLINKV3) ||
|
break;
|
||||||
(info->pid == PRODUCT_ID_STLINKV3E)) {
|
case PRODUCT_ID_STLINKV3_BL:
|
||||||
|
case PRODUCT_ID_STLINKV3:
|
||||||
|
case PRODUCT_ID_STLINKV3E:
|
||||||
|
case PRODUCT_ID_STLINKV3_NO_MSD:
|
||||||
Stlink.ver_hw = 30;
|
Stlink.ver_hw = 30;
|
||||||
info->usb_link->ep_tx = 1;
|
info->usb_link->ep_tx = 1;
|
||||||
Stlink.ep_tx = 1;
|
Stlink.ep_tx = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DEBUG_INFO("Unhandled STM32 device\n");
|
||||||
}
|
}
|
||||||
info->usb_link->ep_rx = 1;
|
info->usb_link->ep_rx = 1;
|
||||||
int config;
|
int config;
|
||||||
@ -625,44 +647,6 @@ bool stlink_srst_get_val(void)
|
|||||||
return Stlink.srst;
|
return Stlink.srst;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool stlink_set_freq_divisor(bmp_info_t *info, uint16_t divisor)
|
|
||||||
{
|
|
||||||
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
|
||||||
STLINK_DEBUG_APIV2_SWD_SET_FREQ,
|
|
||||||
divisor & 0xff, divisor >> 8};
|
|
||||||
uint8_t data[2];
|
|
||||||
send_recv(info->usb_link, cmd, 16, data, 2);
|
|
||||||
if (stlink_usb_error_check(data, false))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool stlink3_set_freq_divisor(bmp_info_t *info, uint16_t divisor)
|
|
||||||
{
|
|
||||||
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
|
||||||
STLINK_APIV3_GET_COM_FREQ,
|
|
||||||
Stlink.transport_mode};
|
|
||||||
uint8_t data[52];
|
|
||||||
send_recv(info->usb_link, cmd, 16, data, 52);
|
|
||||||
stlink_usb_error_check(data, true);
|
|
||||||
int size = data[8];
|
|
||||||
if (divisor > size)
|
|
||||||
divisor = size;
|
|
||||||
uint8_t *p = data + 12 + divisor * sizeof(uint32_t);
|
|
||||||
uint32_t freq = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
|
|
||||||
DEBUG_INFO("Selected %" PRId32 " khz\n", freq);
|
|
||||||
cmd[1] = STLINK_APIV3_SET_COM_FREQ;
|
|
||||||
cmd[2] = Stlink.transport_mode;
|
|
||||||
cmd[3] = 0;
|
|
||||||
p = data + 12 + divisor * sizeof(uint32_t);
|
|
||||||
cmd[4] = p[0];
|
|
||||||
cmd[5] = p[1];
|
|
||||||
cmd[6] = p[2];
|
|
||||||
cmd[7] = p[3];
|
|
||||||
send_recv(info->usb_link, cmd, 16, data, 8);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int stlink_hwversion(void)
|
int stlink_hwversion(void)
|
||||||
{
|
{
|
||||||
return Stlink.ver_stlink;
|
return Stlink.ver_stlink;
|
||||||
@ -671,16 +655,10 @@ int stlink_hwversion(void)
|
|||||||
static int stlink_enter_debug_jtag(bmp_info_t *info)
|
static int stlink_enter_debug_jtag(bmp_info_t *info)
|
||||||
{
|
{
|
||||||
stlink_leave_state(info);
|
stlink_leave_state(info);
|
||||||
Stlink.transport_mode = STLINK_MODE_JTAG;
|
|
||||||
if (Stlink.ver_stlink == 3)
|
|
||||||
stlink3_set_freq_divisor(info, 4);
|
|
||||||
else
|
|
||||||
stlink_set_freq_divisor(info, 1);
|
|
||||||
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
||||||
STLINK_DEBUG_APIV2_ENTER,
|
STLINK_DEBUG_APIV2_ENTER,
|
||||||
STLINK_DEBUG_ENTER_JTAG_NO_RESET};
|
STLINK_DEBUG_ENTER_JTAG_NO_RESET};
|
||||||
uint8_t data[2];
|
uint8_t data[2];
|
||||||
DEBUG_INFO("Enter JTAG\n");
|
|
||||||
send_recv(info->usb_link, cmd, 16, data, 2);
|
send_recv(info->usb_link, cmd, 16, data, 2);
|
||||||
return stlink_usb_error_check(data, true);
|
return stlink_usb_error_check(data, true);
|
||||||
}
|
}
|
||||||
@ -802,9 +780,10 @@ uint32_t stlink_dp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
|||||||
int res;
|
int res;
|
||||||
if (RnW) {
|
if (RnW) {
|
||||||
res = stlink_read_dp_register(
|
res = stlink_read_dp_register(
|
||||||
STLINK_DEBUG_PORT_ACCESS, addr, &response);
|
(addr < 0x100) ? STLINK_DEBUG_PORT_ACCESS : 0, addr, &response);
|
||||||
} else {
|
} else {
|
||||||
res = stlink_write_dp_register(STLINK_DEBUG_PORT_ACCESS, addr, value);
|
res = stlink_write_dp_register(
|
||||||
|
(addr < 0x100) ? STLINK_DEBUG_PORT_ACCESS : 0, addr, value);
|
||||||
}
|
}
|
||||||
if (res == STLINK_ERROR_WAIT)
|
if (res == STLINK_ERROR_WAIT)
|
||||||
raise_exception(EXCEPTION_TIMEOUT, "DP ACK timeout");
|
raise_exception(EXCEPTION_TIMEOUT, "DP ACK timeout");
|
||||||
@ -829,8 +808,8 @@ static bool stlink_ap_setup(int ap)
|
|||||||
ap,
|
ap,
|
||||||
};
|
};
|
||||||
uint8_t data[2];
|
uint8_t data[2];
|
||||||
send_recv(info.usb_link, cmd, 16, data, 2);
|
|
||||||
DEBUG_PROBE("Open AP %d\n", ap);
|
DEBUG_PROBE("Open AP %d\n", ap);
|
||||||
|
stlink_send_recv_retry(cmd, 16, data, 2);
|
||||||
int res = stlink_usb_error_check(data, true);
|
int res = stlink_usb_error_check(data, true);
|
||||||
if (res) {
|
if (res) {
|
||||||
if (Stlink.ver_hw == 30) {
|
if (Stlink.ver_hw == 30) {
|
||||||
@ -1041,13 +1020,13 @@ int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens)
|
|||||||
jtag_dev_count = stlink_read_idcodes(info, idcodes);
|
jtag_dev_count = stlink_read_idcodes(info, idcodes);
|
||||||
/* Check for known devices and handle accordingly */
|
/* Check for known devices and handle accordingly */
|
||||||
for(int i = 0; i < jtag_dev_count; i++)
|
for(int i = 0; i < jtag_dev_count; i++)
|
||||||
jtag_devs[i].idcode = idcodes[i];
|
jtag_devs[i].jd_idcode = idcodes[i];
|
||||||
for(int i = 0; i < jtag_dev_count; i++)
|
for(int i = 0; i < jtag_dev_count; i++)
|
||||||
for(int j = 0; dev_descr[j].idcode; j++)
|
for(int j = 0; dev_descr[j].idcode; j++)
|
||||||
if((jtag_devs[i].idcode & dev_descr[j].idmask) ==
|
if((jtag_devs[i].jd_idcode & dev_descr[j].idmask) ==
|
||||||
dev_descr[j].idcode) {
|
dev_descr[j].idcode) {
|
||||||
if(dev_descr[j].handler)
|
if(dev_descr[j].handler)
|
||||||
dev_descr[j].handler(&jtag_devs[i]);
|
dev_descr[j].handler(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1081,19 +1060,13 @@ void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp)
|
|||||||
int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp)
|
int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp)
|
||||||
{
|
{
|
||||||
stlink_leave_state(info);
|
stlink_leave_state(info);
|
||||||
Stlink.transport_mode = STLINK_MODE_SWD;
|
|
||||||
if (Stlink.ver_stlink == 3)
|
|
||||||
stlink3_set_freq_divisor(info, 2);
|
|
||||||
else
|
|
||||||
stlink_set_freq_divisor(info, 1);
|
|
||||||
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
||||||
STLINK_DEBUG_APIV2_ENTER,
|
STLINK_DEBUG_APIV2_ENTER,
|
||||||
STLINK_DEBUG_ENTER_SWD_NO_RESET};
|
STLINK_DEBUG_ENTER_SWD_NO_RESET};
|
||||||
uint8_t data[2];
|
uint8_t data[2];
|
||||||
DEBUG_INFO("Enter SWD\n");
|
|
||||||
stlink_send_recv_retry(cmd, 16, data, 2);
|
stlink_send_recv_retry(cmd, 16, data, 2);
|
||||||
if (stlink_usb_error_check(data, true))
|
if (stlink_usb_error_check(data, true))
|
||||||
return -1;
|
exit( -1);
|
||||||
dp->idcode = stlink_read_coreid();
|
dp->idcode = stlink_read_coreid();
|
||||||
dp->dp_read = stlink_dp_read;
|
dp->dp_read = stlink_dp_read;
|
||||||
dp->error = stlink_dp_error;
|
dp->error = stlink_dp_error;
|
||||||
@ -1101,5 +1074,117 @@ int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp)
|
|||||||
dp->abort = stlink_dp_abort;
|
dp->abort = stlink_dp_abort;
|
||||||
|
|
||||||
stlink_dp_error(dp);
|
stlink_dp_error(dp);
|
||||||
|
if ((dp->idcode & ADIV5_DP_VERSION_MASK) == ADIV5_DPv2) {
|
||||||
|
adiv5_dp_write(dp, ADIV5_DP_SELECT, 2);
|
||||||
|
dp->targetid = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT);
|
||||||
|
adiv5_dp_write(dp, ADIV5_DP_SELECT, 0);
|
||||||
|
DEBUG_INFO("TARGETID 0x%08" PRIx32 "\n", dp->targetid);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define V2_USED_SWD_CYCLES 20
|
||||||
|
#define V2_CYCLES_PER_CNT 20
|
||||||
|
#define V2_CLOCK_RATE (72*1000*1000)
|
||||||
|
/* Above values reproduce the known values for V2
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int divs[] = {0, 1,2,3,7,15,31,40,79,158,265,798};
|
||||||
|
for (int i = 0; i < (sizeof(divs) /sizeof(divs[0])); i++) {
|
||||||
|
float ret = 72.0 * 1000 * 1000 / (20 + 20 * divs[i]);
|
||||||
|
printf("%3d: %6.4f MHz\n", divs[i], ret/ 1000000);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int divisor;
|
||||||
|
static unsigned int v3_freq[2];
|
||||||
|
void stlink_max_frequency_set(bmp_info_t *info, uint32_t freq)
|
||||||
|
{
|
||||||
|
if (Stlink.ver_hw == 30) {
|
||||||
|
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
||||||
|
STLINK_APIV3_GET_COM_FREQ,
|
||||||
|
info->is_jtag ? STLINK_MODE_JTAG : STLINK_MODE_SWD};
|
||||||
|
uint8_t data[52];
|
||||||
|
send_recv(info->usb_link, cmd, 16, data, 52);
|
||||||
|
stlink_usb_error_check(data, true);
|
||||||
|
volatile uint8_t *p = data + 12;
|
||||||
|
int i;
|
||||||
|
unsigned int last_freq = 0;
|
||||||
|
DEBUG_INFO("Available speed settings: ");
|
||||||
|
for (i = 0; i < STLINK_V3_MAX_FREQ_NB; i++) {
|
||||||
|
unsigned int new_freq = *p++;
|
||||||
|
new_freq |= *p++ << 8;
|
||||||
|
new_freq |= *p++ << 16;
|
||||||
|
new_freq |= *p++ << 24;
|
||||||
|
if (!new_freq)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
last_freq = new_freq;
|
||||||
|
DEBUG_INFO("%s%d", (i)? "/": "", last_freq);
|
||||||
|
if ((freq / 1000) >= last_freq)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DEBUG_INFO(" kHz for %s\n", (info->is_jtag) ? "JTAG" : "SWD");
|
||||||
|
cmd[1] = STLINK_APIV3_SET_COM_FREQ;
|
||||||
|
cmd[3] = 0;
|
||||||
|
cmd[4] = (last_freq >> 0) & 0xff;
|
||||||
|
cmd[5] = (last_freq >> 8) & 0xff;
|
||||||
|
cmd[6] = (last_freq >> 16) & 0xff;
|
||||||
|
cmd[7] = (last_freq >> 24) & 0xff;
|
||||||
|
send_recv(info->usb_link, cmd, 16, data, 8);
|
||||||
|
stlink_usb_error_check(data, true);
|
||||||
|
v3_freq[(info->is_jtag) ? 1 : 0] = last_freq * 1000;
|
||||||
|
} else {
|
||||||
|
uint8_t cmd[16];
|
||||||
|
cmd[0] = STLINK_DEBUG_COMMAND;
|
||||||
|
if (info->is_jtag) {
|
||||||
|
cmd[1] = STLINK_DEBUG_APIV2_JTAG_SET_FREQ;
|
||||||
|
/* V2_CLOCK_RATE / (4, 8, 16, ... 256)*/
|
||||||
|
int div = (V2_CLOCK_RATE + (2 * freq) - 1) / (2 * freq);
|
||||||
|
if (div & (div -1)) {/* Round up */
|
||||||
|
int clz = __builtin_clz(div);
|
||||||
|
divisor = 1 << (32 - clz);
|
||||||
|
} else
|
||||||
|
divisor = div;
|
||||||
|
if (divisor < 4)
|
||||||
|
divisor = 4;
|
||||||
|
else if (divisor > 256)
|
||||||
|
divisor = 256;
|
||||||
|
} else {
|
||||||
|
cmd[1] = STLINK_DEBUG_APIV2_SWD_SET_FREQ;
|
||||||
|
divisor = V2_CLOCK_RATE + freq - 1;
|
||||||
|
divisor /= freq;
|
||||||
|
divisor -= V2_USED_SWD_CYCLES;
|
||||||
|
if (divisor < 0)
|
||||||
|
divisor = 0;
|
||||||
|
divisor /= V2_CYCLES_PER_CNT;
|
||||||
|
}
|
||||||
|
DEBUG_WARN("Divisor for %6.4f MHz is %" PRIu32 "\n",
|
||||||
|
freq/1000000.0, divisor);
|
||||||
|
cmd[2] = divisor & 0xff;
|
||||||
|
cmd[3] = (divisor >> 8) & 0xff;
|
||||||
|
uint8_t data[2];
|
||||||
|
send_recv(info->usb_link, cmd, 16, data, 2);
|
||||||
|
if (stlink_usb_error_check(data, false))
|
||||||
|
DEBUG_WARN("Set frequency failed!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t stlink_max_frequency_get(bmp_info_t *info)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
if (Stlink.ver_hw == 30) {
|
||||||
|
ret = v3_freq[(info->is_jtag) ? STLINK_MODE_JTAG : STLINK_MODE_SWD];
|
||||||
|
} else {
|
||||||
|
ret = V2_CLOCK_RATE;
|
||||||
|
if (info->is_jtag)
|
||||||
|
ret /= (2 * divisor);
|
||||||
|
else
|
||||||
|
ret /= (V2_USED_SWD_CYCLES + (V2_CYCLES_PER_CNT * divisor));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -24,16 +24,34 @@
|
|||||||
|
|
||||||
#define STLINK_DEBUG_PORT_ACCESS 0xffff
|
#define STLINK_DEBUG_PORT_ACCESS 0xffff
|
||||||
|
|
||||||
|
#if HOSTED_BMP_ONLY == 1
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||||
|
int stlink_init(bmp_info_t *info) {return -1;};
|
||||||
|
int stlink_hwversion(void) {return -1;};
|
||||||
|
const char *stlink_target_voltage(bmp_info_t *info) {return "ERROR";};
|
||||||
|
void stlink_srst_set_val(bmp_info_t *info, bool assert) {};
|
||||||
|
bool stlink_srst_get_val(void) {return true;};
|
||||||
|
int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp) {return -1;};
|
||||||
|
void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp) {};
|
||||||
|
int stlink_jtag_dp_init(ADIv5_DP_t *dp) {return false;};
|
||||||
|
int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens) {return 0;};
|
||||||
|
void stlink_exit_function(bmp_info_t *info) {};
|
||||||
|
void stlink_max_frequency_set(bmp_info_t *info, uint32_t freq) {};
|
||||||
|
uint32_t stlink_max_frequency_get(bmp_info_t *info) {return 0;};
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#else
|
||||||
int stlink_init(bmp_info_t *info);
|
int stlink_init(bmp_info_t *info);
|
||||||
int stlink_hwversion(void);
|
int stlink_hwversion(void);
|
||||||
const char *stlink_target_voltage(bmp_info_t *info);
|
const char *stlink_target_voltage(bmp_info_t *info);
|
||||||
void stlink_srst_set_val(bmp_info_t *info, bool assert);
|
void stlink_srst_set_val(bmp_info_t *info, bool assert);
|
||||||
bool stlink_srst_get_val(void);
|
bool stlink_srst_get_val(void);
|
||||||
int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp);
|
int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp);
|
||||||
|
|
||||||
const char *stlink_target_voltage(bmp_info_t *info);
|
|
||||||
void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp);
|
void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp);
|
||||||
int stlink_jtag_dp_init(ADIv5_DP_t *dp);
|
int stlink_jtag_dp_init(ADIv5_DP_t *dp);
|
||||||
int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens);
|
int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens);
|
||||||
void stlink_exit_function(bmp_info_t *info);
|
void stlink_exit_function(bmp_info_t *info);
|
||||||
|
void stlink_max_frequency_set(bmp_info_t *info, uint32_t freq);
|
||||||
|
uint32_t stlink_max_frequency_get(bmp_info_t *info);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,8 +4,8 @@ OBJCOPY = $(CROSS_COMPILE)objcopy
|
|||||||
|
|
||||||
CFLAGS += -Istm32/include -mcpu=cortex-m4 -mthumb \
|
CFLAGS += -Istm32/include -mcpu=cortex-m4 -mthumb \
|
||||||
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \
|
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \
|
||||||
-DSTM32F4 -DHYDRABUS -I../libopencm3/include \
|
-DSTM32F4 -I../libopencm3/include \
|
||||||
-Iplatforms/stm32
|
-Iplatforms/stm32 -DDFU_SERIAL_LENGTH=9
|
||||||
|
|
||||||
LDFLAGS = -lopencm3_stm32f4 \
|
LDFLAGS = -lopencm3_stm32f4 \
|
||||||
-Wl,-T,platforms/stm32/f4discovery.ld -nostartfiles -lc -lnosys \
|
-Wl,-T,platforms/stm32/f4discovery.ld -nostartfiles -lc -lnosys \
|
||||||
@ -27,7 +27,7 @@ all: blackmagic.bin blackmagic.hex
|
|||||||
|
|
||||||
blackmagic.dfu: blackmagic.hex
|
blackmagic.dfu: blackmagic.hex
|
||||||
@echo Creating $@
|
@echo Creating $@
|
||||||
@python ../scripts/dfu-convert.py -i $< $@
|
@python3 ../scripts/dfu-convert.py -i $< $@
|
||||||
|
|
||||||
host_clean:
|
host_clean:
|
||||||
-$(Q)$(RM) blackmagic.bin blackmagic.hex blackmagic.dfu
|
-$(Q)$(RM) blackmagic.bin blackmagic.hex blackmagic.dfu
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
#include "usbuart.h"
|
#include "usbuart.h"
|
||||||
#include "morse.h"
|
#include "morse.h"
|
||||||
|
|
||||||
#include <libopencm3/stm32/f4/rcc.h>
|
#include <libopencm3/stm32/rcc.h>
|
||||||
#include <libopencm3/cm3/scb.h>
|
#include <libopencm3/cm3/scb.h>
|
||||||
#include <libopencm3/cm3/nvic.h>
|
#include <libopencm3/cm3/nvic.h>
|
||||||
#include <libopencm3/stm32/exti.h>
|
#include <libopencm3/stm32/exti.h>
|
||||||
|
@ -28,14 +28,11 @@
|
|||||||
#include "gpio.h"
|
#include "gpio.h"
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
#include "timing_stm32.h"
|
#include "timing_stm32.h"
|
||||||
#include "version.h"
|
|
||||||
|
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
|
||||||
#define PLATFORM_HAS_TRACESWO
|
#define PLATFORM_HAS_TRACESWO
|
||||||
#define BOARD_IDENT "Black Magic Probe (HydraBus), (Firmware " FIRMWARE_VERSION ")"
|
#define PLATFORM_IDENT " (HydraBus))"
|
||||||
#define BOARD_IDENT_DFU "Black Magic (Upgrade) for HydraBus, (Firmware " FIRMWARE_VERSION ")"
|
|
||||||
#define DFU_IDENT "Black Magic Firmware Upgrade (HydraBus)"
|
|
||||||
|
|
||||||
/* Important pin mappings for STM32 implementation:
|
/* Important pin mappings for STM32 implementation:
|
||||||
*
|
*
|
||||||
@ -93,47 +90,54 @@
|
|||||||
#define SWDIO_MODE_DRIVE() \
|
#define SWDIO_MODE_DRIVE() \
|
||||||
gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, \
|
gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, \
|
||||||
GPIO_PUPD_NONE, SWDIO_PIN);
|
GPIO_PUPD_NONE, SWDIO_PIN);
|
||||||
|
#define UART_PIN_SETUP() do { \
|
||||||
|
gpio_mode_setup(USBUSART_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
|
||||||
|
USBUSART_TX_PIN); \
|
||||||
|
gpio_set_output_options(USBUSART_PORT, GPIO_OTYPE_PP, \
|
||||||
|
GPIO_OSPEED_100MHZ, USBUSART_TX_PIN); \
|
||||||
|
gpio_set_af(USBUSART_PORT, GPIO_AF7, USBUSART_TX_PIN); \
|
||||||
|
gpio_mode_setup(USBUSART_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, \
|
||||||
|
USBUSART_RX_PIN); \
|
||||||
|
gpio_set_output_options(USBUSART_PORT, GPIO_OTYPE_OD, \
|
||||||
|
GPIO_OSPEED_100MHZ, USBUSART_RX_PIN); \
|
||||||
|
gpio_set_af(USBUSART_PORT, GPIO_AF7, USBUSART_RX_PIN); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#define USB_DRIVER stm32f107_usb_driver
|
#define USB_DRIVER stm32f107_usb_driver
|
||||||
#define USB_IRQ NVIC_OTG_FS_IRQ
|
#define USB_IRQ NVIC_OTG_FS_IRQ
|
||||||
#define USB_ISR otg_fs_isr
|
#define USB_ISR(x) otg_fs_isr(x)
|
||||||
/* Interrupt priorities. Low numbers are high priority.
|
/* Interrupt priorities. Low numbers are high priority.
|
||||||
* For now USART1 preempts USB which may spin while buffer is drained.
|
|
||||||
* TIM3 is used for traceswo capture and must be highest priority.
|
* TIM3 is used for traceswo capture and must be highest priority.
|
||||||
*/
|
*/
|
||||||
#define IRQ_PRI_USB (2 << 4)
|
#define IRQ_PRI_USB (1 << 4)
|
||||||
#define IRQ_PRI_USBUSART (1 << 4)
|
#define IRQ_PRI_USBUSART (2 << 4)
|
||||||
#define IRQ_PRI_USBUSART_TIM (3 << 4)
|
#define IRQ_PRI_USBUSART_DMA (2 << 4)
|
||||||
#define IRQ_PRI_TRACE (0 << 4)
|
#define IRQ_PRI_TRACE (0 << 4)
|
||||||
|
|
||||||
#define USBUSART USART1
|
#define USBUSART USART1
|
||||||
#define USBUSART_CR1 USART1_CR1
|
#define USBUSART_CR1 USART1_CR1
|
||||||
|
#define USBUSART_DR USART1_DR
|
||||||
#define USBUSART_IRQ NVIC_USART1_IRQ
|
#define USBUSART_IRQ NVIC_USART1_IRQ
|
||||||
#define USBUSART_CLK RCC_USART1
|
#define USBUSART_CLK RCC_USART1
|
||||||
#define USBUSART_TX_PORT GPIOA
|
#define USBUSART_PORT GPIOA
|
||||||
#define USBUSART_TX_PIN GPIO9
|
#define USBUSART_TX_PIN GPIO9
|
||||||
#define USBUSART_RX_PORT GPIOA
|
#define USBUSART_RX_PIN GPIO10
|
||||||
#define USBUSART_RX_PIN GPIO10
|
#define USBUSART_ISR(x) usart1_isr(x)
|
||||||
#define USBUSART_ISR usart1_isr
|
#define USBUSART_DMA_BUS DMA2
|
||||||
#define USBUSART_TIM TIM4
|
#define USBUSART_DMA_CLK RCC_DMA2
|
||||||
#define USBUSART_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM4)
|
#define USBUSART_DMA_TX_CHAN DMA_STREAM7
|
||||||
#define USBUSART_TIM_IRQ NVIC_TIM4_IRQ
|
#define USBUSART_DMA_TX_IRQ NVIC_DMA2_STREAM7_IRQ
|
||||||
#define USBUSART_TIM_ISR tim4_isr
|
#define USBUSART_DMA_TX_ISR(x) dma2_stream7_isr(x)
|
||||||
|
#define USBUSART_DMA_RX_CHAN DMA_STREAM5
|
||||||
#define UART_PIN_SETUP() do { \
|
#define USBUSART_DMA_RX_IRQ NVIC_DMA2_STREAM5_IRQ
|
||||||
gpio_mode_setup(USBUSART_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
|
#define USBUSART_DMA_RX_ISR(x) dma2_stream5_isr(x)
|
||||||
USBUSART_TX_PIN); \
|
/* For STM32F4 DMA trigger source must be specified */
|
||||||
gpio_mode_setup(USBUSART_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
|
#define USBUSART_DMA_TRG DMA_SxCR_CHSEL_4
|
||||||
USBUSART_RX_PIN); \
|
|
||||||
gpio_set_af(USBUSART_TX_PORT, GPIO_AF7, USBUSART_TX_PIN); \
|
|
||||||
gpio_set_af(USBUSART_RX_PORT, GPIO_AF7, USBUSART_RX_PIN); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define TRACE_TIM TIM3
|
#define TRACE_TIM TIM3
|
||||||
#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3)
|
#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3)
|
||||||
#define TRACE_IRQ NVIC_TIM3_IRQ
|
#define TRACE_IRQ NVIC_TIM3_IRQ
|
||||||
#define TRACE_ISR tim3_isr
|
#define TRACE_ISR(x) tim3_isr(x)
|
||||||
|
|
||||||
#define gpio_set_val(port, pin, val) do { \
|
#define gpio_set_val(port, pin, val) do { \
|
||||||
if(val) \
|
if(val) \
|
||||||
@ -185,4 +189,3 @@ static inline int platform_hwversion(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
61
src/platforms/jeff/Makefile.inc
Normal file
61
src/platforms/jeff/Makefile.inc
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
CROSS_COMPILE ?= arm-none-eabi-
|
||||||
|
CC = $(CROSS_COMPILE)gcc
|
||||||
|
OBJCOPY = $(CROSS_COMPILE)objcopy
|
||||||
|
|
||||||
|
OPT_FLAGS := -Os
|
||||||
|
|
||||||
|
ifeq ($(ENABLE_DEBUG), 1)
|
||||||
|
CFLAGS += -DDEBUG_ME
|
||||||
|
CFLAGS += -DENABLE_DEBUG
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CUSTOM_SER), 1)
|
||||||
|
CFLAGS += -DCUSTOM_SER
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONSOLE_NO_AUTO_CRLF), 1)
|
||||||
|
CFLAGS += -DCONSOLE_NO_AUTO_CRLF
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ENABLE_DEBUG), 1)
|
||||||
|
CFLAGS += -g3 -ggdb
|
||||||
|
endif
|
||||||
|
|
||||||
|
CFLAGS += -mthumb -mcpu=cortex-m0plus -DDFU_SERIAL_LENGTH=9 \
|
||||||
|
-DSAMD -DSAMD21E17 -DBLACKMAGIC -I../libopencm3/include \
|
||||||
|
-Iplatforms/samd -msoft-float -ffunction-sections -fdata-sections -MD
|
||||||
|
|
||||||
|
LINKER_SCRIPT="platforms/samd/samd.ld"
|
||||||
|
LDFLAGS = -mthumb -mcpu=cortex-m0plus -msoft-float -nostartfiles -lc \
|
||||||
|
$(CPU_FLAGS) -T$(LINKER_SCRIPT) -Wl,--gc-sections \
|
||||||
|
-L../libopencm3/lib -lopencm3_samd -lnosys -lm -lgcc
|
||||||
|
|
||||||
|
ifeq ($(ENABLE_DEBUG), 1)
|
||||||
|
LDFLAGS += --specs=rdimon.specs
|
||||||
|
else
|
||||||
|
LDFLAGS += --specs=nano.specs
|
||||||
|
endif
|
||||||
|
|
||||||
|
VPATH += platforms/samd
|
||||||
|
|
||||||
|
SRC += cdcacm.c \
|
||||||
|
timing.c \
|
||||||
|
traceswo.o \
|
||||||
|
usbuart.c \
|
||||||
|
|
||||||
|
all: blackmagic_full.bin blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
|
||||||
|
|
||||||
|
blackmagic_dfu.bin : OBJCOPY_FLAGS := --pad-to 0x00002000 --gap-fill 0xFF -j .text -j .data
|
||||||
|
blackmagic_dfu.bin : LINKER_SCRIPT := "platforms/samd/samd_boot.ld"
|
||||||
|
|
||||||
|
blackmagic_dfu.elf: usbdfu.o
|
||||||
|
@echo " LD $@"
|
||||||
|
$(Q)$(CC) $^ -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
blackmagic_full.bin: blackmagic_dfu.bin blackmagic.bin
|
||||||
|
@echo " CAT $@"
|
||||||
|
$(Q)cp blackmagic.bin jeff-$(shell git describe --tags --always --dirty).bin
|
||||||
|
$(Q)cat $^ > $@
|
||||||
|
|
||||||
|
host_clean:
|
||||||
|
$(Q)$(RM) -f blackmagic.bin blackmagic_full.bin blackmagic_dfu blackmagic_dfu.bin blackmagic_dfu.hex jeff*.bin
|
346
src/platforms/jeff/platform.c
Normal file
346
src/platforms/jeff/platform.c
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Black Magic Debug project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Flirc Inc.
|
||||||
|
* Written by Jason Kotzin <jasonkotzin@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "general.h"
|
||||||
|
#include "gdb_if.h"
|
||||||
|
#include "cdcacm.h"
|
||||||
|
#include "usbuart.h"
|
||||||
|
#include "gdb_packet.h"
|
||||||
|
|
||||||
|
#include <libopencm3/sam/d/nvic.h>
|
||||||
|
#include <libopencm3/sam/d/port.h>
|
||||||
|
#include <libopencm3/sam/d/gclk.h>
|
||||||
|
#include <libopencm3/sam/d/pm.h>
|
||||||
|
#include <libopencm3/sam/d/uart.h>
|
||||||
|
#include <libopencm3/sam/d/adc.h>
|
||||||
|
|
||||||
|
#include <libopencm3/cm3/systick.h>
|
||||||
|
#include <libopencm3/cm3/scb.h>
|
||||||
|
|
||||||
|
#include <libopencm3/sam/d/tc.h>
|
||||||
|
#include <libopencm3/sam/d/eic.h>
|
||||||
|
|
||||||
|
static struct gclk_hw clock = {
|
||||||
|
.gclk0 = SRC_DFLL48M,
|
||||||
|
.gclk1 = SRC_OSC8M,
|
||||||
|
.gclk1_div = 30, /* divide clock for ADC */
|
||||||
|
.gclk2 = SRC_OSC8M,
|
||||||
|
.gclk2_div = 100, /* divide clock for TC */
|
||||||
|
.gclk3 = SRC_DFLL48M,
|
||||||
|
.gclk4 = SRC_DFLL48M,
|
||||||
|
.gclk5 = SRC_DFLL48M,
|
||||||
|
.gclk6 = SRC_DFLL48M,
|
||||||
|
.gclk7 = SRC_DFLL48M,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void trace_tick(void);
|
||||||
|
|
||||||
|
uint8_t running_status;
|
||||||
|
static volatile uint32_t time_ms;
|
||||||
|
|
||||||
|
uint8_t button_pressed;
|
||||||
|
|
||||||
|
uint8_t tpwr_enabled;
|
||||||
|
|
||||||
|
void sys_tick_handler(void)
|
||||||
|
{
|
||||||
|
if(running_status)
|
||||||
|
gpio_toggle(LED_PORT, LED_IDLE_RUN);
|
||||||
|
|
||||||
|
time_ms += 10;
|
||||||
|
|
||||||
|
uart_pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t platform_time_ms(void)
|
||||||
|
{
|
||||||
|
return time_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_setup(void)
|
||||||
|
{
|
||||||
|
/* Enable USB */
|
||||||
|
INSERTBF(PM_APBBMASK_USB, 1, PM->apbbmask);
|
||||||
|
|
||||||
|
/* enable clocking to usb */
|
||||||
|
set_periph_clk(GCLK0, GCLK_ID_USB);
|
||||||
|
periph_clk_en(GCLK_ID_USB, 1);
|
||||||
|
|
||||||
|
gpio_config_special(PORTA, GPIO24, SOC_GPIO_PERIPH_G);
|
||||||
|
gpio_config_special(PORTA, GPIO25, SOC_GPIO_PERIPH_G);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t timing_init(void)
|
||||||
|
{
|
||||||
|
uint32_t cal = 0;
|
||||||
|
|
||||||
|
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
|
||||||
|
systick_set_reload(4800); /* Interrupt us at 10 Hz */
|
||||||
|
systick_interrupt_enable();
|
||||||
|
|
||||||
|
systick_counter_enable();
|
||||||
|
return cal;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adc_init(void)
|
||||||
|
{
|
||||||
|
gpio_config_special(ADC_PORT, ADC_POS_PIN, SOC_GPIO_PERIPH_B); /* +input */
|
||||||
|
gpio_config_special(ADC_PORT, ADC_REF_PIN, SOC_GPIO_PERIPH_B); /* reference */
|
||||||
|
|
||||||
|
set_periph_clk(GCLK1, GCLK_ID_ADC);
|
||||||
|
periph_clk_en(GCLK_ID_ADC, 1);
|
||||||
|
|
||||||
|
adc_enable(ADC_REFCTRL_VREFA,0,ADC_INPUTCTRL_GND,ADC_MUXPOS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void counter_init(void)
|
||||||
|
{
|
||||||
|
/* enable bus and clock */
|
||||||
|
INSERTBF(PM_APBCMASK_TC3, 1, PM->apbcmask);
|
||||||
|
|
||||||
|
set_periph_clk(GCLK2, GCLK_ID_TC3);
|
||||||
|
periph_clk_en(GCLK_ID_TC3, 1);
|
||||||
|
|
||||||
|
/* reset */
|
||||||
|
tc_reset(3);
|
||||||
|
|
||||||
|
/* set CTRLA.PRESCALER and CTRLA.PRESYNC */
|
||||||
|
tc_config_ctrla(3,1,(7<<8));
|
||||||
|
|
||||||
|
/* set CC0 (approx. 5 seconds delay) */
|
||||||
|
tc_set_cc(3,0,1000);
|
||||||
|
|
||||||
|
/* enable MC0 interrupt */
|
||||||
|
tc_enable_interrupt(3,(1<<4));
|
||||||
|
nvic_enable_irq(NVIC_TC3_IRQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void button_init(void)
|
||||||
|
{
|
||||||
|
gpio_config_special(BUTTON_PORT, BUTTON_PIN, SOC_GPIO_PERIPH_A);
|
||||||
|
|
||||||
|
/* enable bus and clock */
|
||||||
|
INSERTBF(PM_APBAMASK_EIC, 1, PM->apbamask);
|
||||||
|
|
||||||
|
set_periph_clk(GCLK0, GCLK_ID_EIC);
|
||||||
|
periph_clk_en(GCLK_ID_EIC, 1);
|
||||||
|
|
||||||
|
/* configure r/f edge, enable filtering */
|
||||||
|
eic_set_config(15, 1, EIC_FALL);
|
||||||
|
|
||||||
|
/* enable the IEC */
|
||||||
|
eic_enable(1);
|
||||||
|
|
||||||
|
/* enable interrupts */
|
||||||
|
eic_enable_interrupt((1<<15));
|
||||||
|
nvic_enable_irq(NVIC_EIC_IRQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
void platform_init(void)
|
||||||
|
{
|
||||||
|
gclk_init(&clock);
|
||||||
|
|
||||||
|
usb_setup();
|
||||||
|
|
||||||
|
gpio_config_output(LED_PORT, LED_IDLE_RUN, 0);
|
||||||
|
gpio_config_output(TMS_PORT, TMS_PIN, 0);
|
||||||
|
gpio_config_output(TCK_PORT, TCK_PIN, 0);
|
||||||
|
gpio_config_output(TDI_PORT, TDI_PIN, 0);
|
||||||
|
|
||||||
|
gpio_config_output(TMS_PORT, TMS_DIR_PIN, 0);
|
||||||
|
gpio_set(TMS_PORT, TMS_DIR_PIN);
|
||||||
|
|
||||||
|
/* enable both input and output with pullup disabled by default */
|
||||||
|
PORT_DIRSET(SWDIO_PORT) = SWDIO_PIN;
|
||||||
|
PORT_PINCFG(SWDIO_PORT, SWDIO_PIN_NUM) |= GPIO_PINCFG_INEN | GPIO_PINCFG_PULLEN;
|
||||||
|
gpio_clear(SWDIO_PORT, SWDIO_PIN);
|
||||||
|
|
||||||
|
/* configure swclk_pin as output */
|
||||||
|
gpio_config_output(SWCLK_PORT, SWCLK_PIN, 0);
|
||||||
|
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||||
|
|
||||||
|
gpio_config_input(TDO_PORT, TDO_PIN, 0);
|
||||||
|
gpio_config_output(SRST_PORT, SRST_PIN, GPIO_OUT_FLAG_DEFAULT_HIGH);
|
||||||
|
gpio_clear(SRST_PORT, SRST_PIN);
|
||||||
|
|
||||||
|
/* setup uart led, disable by default*/
|
||||||
|
gpio_config_output(LED_PORT_UART, LED_UART, 0);//GPIO_OUT_FLAG_DEFAULT_HIGH);
|
||||||
|
gpio_clear(LED_PORT_UART, LED_UART);
|
||||||
|
|
||||||
|
/* set up TPWR */
|
||||||
|
gpio_set(PWR_BR_PORT, PWR_BR_PIN);
|
||||||
|
gpio_config_output(PWR_BR_PORT, PWR_BR_PIN, GPIO_OUT_FLAG_DEFAULT_HIGH);
|
||||||
|
|
||||||
|
timing_init();
|
||||||
|
usbuart_init();
|
||||||
|
cdcacm_init();
|
||||||
|
adc_init();
|
||||||
|
counter_init();
|
||||||
|
button_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t srst_state;
|
||||||
|
void platform_srst_set_val(bool assert)
|
||||||
|
{
|
||||||
|
volatile int i;
|
||||||
|
if (!assert) {
|
||||||
|
gpio_clear(SRST_PORT, SRST_PIN);
|
||||||
|
for(i = 0; i < 10000; i++) asm("nop");
|
||||||
|
srst_state = 0;
|
||||||
|
} else {
|
||||||
|
gpio_set(SRST_PORT, SRST_PIN);
|
||||||
|
srst_state = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool platform_srst_get_val(void)
|
||||||
|
{
|
||||||
|
//return gpio_get(SRST_PORT, SRST_PIN) != 0;
|
||||||
|
return srst_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool platform_target_get_power(void)
|
||||||
|
{
|
||||||
|
//return !gpio_get(PWR_BR_PORT, PWR_BR_PIN);
|
||||||
|
return tpwr_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void platform_target_set_power(bool power)
|
||||||
|
{
|
||||||
|
gpio_set_val(PWR_BR_PORT, PWR_BR_PIN, !power);
|
||||||
|
tpwr_enabled = power;
|
||||||
|
}
|
||||||
|
|
||||||
|
void platform_delay(uint32_t ms)
|
||||||
|
{
|
||||||
|
platform_timeout timeout;
|
||||||
|
platform_timeout_set(&timeout, ms);
|
||||||
|
while (!platform_timeout_is_expired(&timeout));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t platform_target_voltage_sense(void)
|
||||||
|
{
|
||||||
|
uint32_t val;
|
||||||
|
adc_start();
|
||||||
|
|
||||||
|
while (!(1&(ADC->intflag)));
|
||||||
|
val = ((485*adc_result())>>12); /* 330 without divider, 485 with it */
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *platform_target_voltage(void)
|
||||||
|
{
|
||||||
|
uint32_t voltage;
|
||||||
|
static char out[] = "0.0V";
|
||||||
|
|
||||||
|
adc_start();
|
||||||
|
|
||||||
|
voltage = platform_target_voltage_sense();
|
||||||
|
|
||||||
|
out[0] = '0' + (char)(voltage/100);
|
||||||
|
out[2] = '0' + (char)((voltage/10) % 10);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *serial_no_read(char *s)
|
||||||
|
{
|
||||||
|
#ifdef CUSTOM_SER
|
||||||
|
s[0] = 'J';
|
||||||
|
s[1] = 'E';
|
||||||
|
s[2] = 'F';
|
||||||
|
s[3] = 'F';
|
||||||
|
return s;
|
||||||
|
#else
|
||||||
|
int i;
|
||||||
|
|
||||||
|
volatile uint32_t unique_id = *(volatile uint32_t *)0x0080A00C +
|
||||||
|
*(volatile uint32_t *)0x0080A040 +
|
||||||
|
*(volatile uint32_t *)0x0080A044 +
|
||||||
|
*(volatile uint32_t *)0x0080A048;
|
||||||
|
|
||||||
|
/* Fetch serial number from chip's unique ID */
|
||||||
|
for(i = 0; i < 8; i++) {
|
||||||
|
s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < 8; i++)
|
||||||
|
if(s[i] > '9')
|
||||||
|
s[i] += 'A' - '9' - 1;
|
||||||
|
s[8] = 0;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_serial(void)
|
||||||
|
{
|
||||||
|
gdb_outf("0x%08X%08X%08X%08X\n", *(volatile uint32_t *)0x0080A048,
|
||||||
|
*(volatile uint32_t *)0x0080A044,
|
||||||
|
*(volatile uint32_t *)0x0080A040,
|
||||||
|
*(volatile uint32_t *)0x0080A00C);
|
||||||
|
}
|
||||||
|
|
||||||
|
void platform_request_boot(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void eic_isr(void)
|
||||||
|
{
|
||||||
|
if (!button_pressed){
|
||||||
|
/* set to rising-edge detection */
|
||||||
|
eic_set_config(15, 1, EIC_RISE);
|
||||||
|
|
||||||
|
/* enable counter */
|
||||||
|
tc_enable(3,1);
|
||||||
|
|
||||||
|
button_pressed = 1;
|
||||||
|
} else {
|
||||||
|
/* set to falling-edge detection */
|
||||||
|
eic_set_config(15, 1, EIC_FALL);
|
||||||
|
|
||||||
|
/* disable and reset counter */
|
||||||
|
tc_enable(3,0);
|
||||||
|
|
||||||
|
button_pressed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clear the interrupt */
|
||||||
|
eic_clr_interrupt((1<<15));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tc3_isr(void)
|
||||||
|
{
|
||||||
|
if (tc_interrupt_flag(3) & 16)
|
||||||
|
scb_reset_system();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t swd_delay_cnt = 0;
|
||||||
|
|
||||||
|
void platform_max_frequency_set(uint32_t freq)
|
||||||
|
{
|
||||||
|
(void)freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t platform_max_frequency_get(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
227
src/platforms/jeff/platform.h
Normal file
227
src/platforms/jeff/platform.h
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Black Magic Debug project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Flirc Inc.
|
||||||
|
* Written by Jason Kotzin <jasonkotzin@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PLATFORM_H
|
||||||
|
#define __PLATFORM_H
|
||||||
|
|
||||||
|
#include <libopencm3/sam/d/port.h>
|
||||||
|
#include <libopencm3/usb/usbd.h>
|
||||||
|
#include <libopencm3/cm3/scb.h>
|
||||||
|
#include <libopencm3/sam/d/nvmctrl.h>
|
||||||
|
|
||||||
|
#include "timing.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
//#define PLATFORM_HAS_DEBUG
|
||||||
|
//#define USBUART_DEBUG
|
||||||
|
#define PLATFORM_HAS_UART_WHEN_SWDP
|
||||||
|
#define PLATFORM_HAS_POWER_SWITCH
|
||||||
|
#define PLATFORM_HAS_BOOTLOADER
|
||||||
|
#define PLATFORM_HAS_PRINTSERIAL
|
||||||
|
|
||||||
|
//#define BOARD_IDENT "Black Magic Probe (SAMD), (Firmware " FIRMWARE_VERSION ")"
|
||||||
|
#define BOARD_IDENT_DFU "Black Magic (Upgrade) for Launchpad, (Firmware " FIRMWARE_VERSION ")"
|
||||||
|
//#define DFU_IDENT "Black Magic Firmware Upgrade (SAMD)"
|
||||||
|
#define DFU_IFACE_STRING "hid"
|
||||||
|
|
||||||
|
#define BOARD_IDENT_UPD "Black Magic (DFU Upgrade), SAMD21, (Firmware " FIRMWARE_VERSION ")"
|
||||||
|
#define UPD_IFACE_STRING "@Internal Flash /0x00000000/1*008Ka,15*8Kg"
|
||||||
|
|
||||||
|
#define PLATFORM_IDENT " "
|
||||||
|
|
||||||
|
extern uint8_t running_status;
|
||||||
|
extern uint32_t swd_delay_cnt;
|
||||||
|
|
||||||
|
#ifdef DEBUG_ME
|
||||||
|
|
||||||
|
#define LED_PORT PORTA
|
||||||
|
#define LED_IDLE_RUN GPIO11
|
||||||
|
#define LED_ERROR GPIO10
|
||||||
|
|
||||||
|
#define TMS_PORT PORTA
|
||||||
|
#define TMS_PIN GPIO1
|
||||||
|
#define TMS_DIR_PIN GPIO5
|
||||||
|
|
||||||
|
#define TCK_PORT PORTA
|
||||||
|
#define TCK_PIN GPIO2
|
||||||
|
|
||||||
|
#define TDI_PORT PORTA
|
||||||
|
#define TDI_PIN GPIO16
|
||||||
|
|
||||||
|
#define TDO_PORT PORTA
|
||||||
|
#define TDO_PIN GPIO19
|
||||||
|
|
||||||
|
#define SWO_PORT PORTA
|
||||||
|
#define SWO_PIN GPIO6
|
||||||
|
|
||||||
|
#define SWDIO_PORT PORTA
|
||||||
|
#define SWDIO_PIN TMS_PIN
|
||||||
|
#define SWDIO_PIN_NUM 1
|
||||||
|
|
||||||
|
#define SWCLK_PORT PORTA
|
||||||
|
#define SWCLK_PIN TCK_PIN
|
||||||
|
|
||||||
|
#define SRST_PORT PORTA
|
||||||
|
#define SRST_PIN GPIO7
|
||||||
|
|
||||||
|
#define LED_PORT_UART PORTA
|
||||||
|
#define LED_UART GPIO12
|
||||||
|
|
||||||
|
#define UART_TX_PIN GPIO8
|
||||||
|
#define UART_RX_PIN GPIO9
|
||||||
|
#define UART_PERIPH SOC_GPIO_PERIPH_C
|
||||||
|
#define UART_PERIPH_2 SOC_GPIO_PERIPH_C
|
||||||
|
|
||||||
|
#define ADC_PORT PORTA
|
||||||
|
#define ADC_REF_PIN GPIO3
|
||||||
|
#define ADC_POS_PIN GPIO4
|
||||||
|
#define ADC_MUXPOS 4
|
||||||
|
|
||||||
|
#define BUTTON_PORT PORTA
|
||||||
|
#define BUTTON_PIN GPIO27
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Hardware definitions... */
|
||||||
|
#define JTAG_PORT PORTA
|
||||||
|
#define TDI_PORT JTAG_PORT
|
||||||
|
#define TMS_DIR_PORT JTAG_PORT
|
||||||
|
#define TMS_PORT JTAG_PORT
|
||||||
|
#define TCK_PORT JTAG_PORT
|
||||||
|
#define TDO_PORT JTAG_PORT
|
||||||
|
#define TMS_DIR_PIN GPIO15
|
||||||
|
#define TMS_PIN GPIO0
|
||||||
|
#define TCK_PIN GPIO6
|
||||||
|
#define TDI_PIN GPIO16
|
||||||
|
#define TDO_PIN GPIO19
|
||||||
|
|
||||||
|
#define SWDIO_DIR_PORT JTAG_PORT
|
||||||
|
#define SWDIO_PORT JTAG_PORT
|
||||||
|
#define SWCLK_PORT JTAG_PORT
|
||||||
|
#define SWDIO_DIR_PIN TMS_DIR_PIN
|
||||||
|
#define SWDIO_PIN TMS_PIN
|
||||||
|
#define SWDIO_PIN_NUM 0
|
||||||
|
#define SWCLK_PIN TCK_PIN
|
||||||
|
|
||||||
|
#define TRST_PORT PORTA
|
||||||
|
#define TRST_PIN GPIO27
|
||||||
|
#define PWR_BR_PORT PORTA
|
||||||
|
#define PWR_BR_PIN GPIO28
|
||||||
|
#define SRST_PORT PORTA
|
||||||
|
#define SRST_PIN GPIO8
|
||||||
|
#define SRST_SENSE_PORT GPIOA
|
||||||
|
#define SRST_SENSE_PIN GPIO9
|
||||||
|
#define TRGT_SENSE GPIO2
|
||||||
|
|
||||||
|
#define LED_PORT PORTA
|
||||||
|
#define LED_PORT_UART PORTA
|
||||||
|
#define LED_0 GPIO10
|
||||||
|
#define LED_1 GPIO11
|
||||||
|
#define LED_2 GPIO14
|
||||||
|
//#define LED_2 GPIO13
|
||||||
|
#define LED_UART LED_1 /* Orange */
|
||||||
|
#define LED_IDLE_RUN LED_0 /* Yellow */
|
||||||
|
#define LED_ERROR LED_2 /* Red */
|
||||||
|
|
||||||
|
#define UART_TX_PIN GPIO4
|
||||||
|
#define UART_RX_PIN GPIO7
|
||||||
|
#define UART_PERIPH SOC_GPIO_PERIPH_D
|
||||||
|
#define UART_PERIPH_2 SOC_GPIO_PERIPH_C
|
||||||
|
|
||||||
|
#define SWO_PORT JTAG_PORT
|
||||||
|
#define SWO_PIN SWD_PIN
|
||||||
|
|
||||||
|
#define ADC_PORT PORTA
|
||||||
|
#define ADC_REF_PIN GPIO3
|
||||||
|
#define ADC_POS_PIN GPIO2
|
||||||
|
#define ADC_MUXPOS 0
|
||||||
|
|
||||||
|
#define BUTTON_PORT PORTA
|
||||||
|
#define BUTTON_PIN GPIO27
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TMS_SET_MODE() { \
|
||||||
|
gpio_config_output(TMS_PORT, TMS_PIN, 0); \
|
||||||
|
gpio_set(TMS_PORT, TMS_DIR_PIN); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SWDIO_MODE_FLOAT() do { \
|
||||||
|
PORT_DIRCLR(SWDIO_PORT) = SWDIO_PIN; \
|
||||||
|
gpio_set(SWDIO_PORT, SWDIO_PIN); \
|
||||||
|
gpio_clear(TMS_PORT, TMS_DIR_PIN); \
|
||||||
|
} while(0)
|
||||||
|
#define SWDIO_MODE_DRIVE() do { \
|
||||||
|
PORT_DIRSET(SWDIO_PORT) = SWDIO_PIN; \
|
||||||
|
gpio_set(TMS_PORT, TMS_DIR_PIN); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/* extern usbd_driver samd21_usb_driver; */
|
||||||
|
#define USB_DRIVER samd21_usb_driver
|
||||||
|
#define USB_IRQ NVIC_USB_IRQ
|
||||||
|
#define USB_ISR usb_isr
|
||||||
|
|
||||||
|
#define IRQ_PRI_USB (2 << 4)
|
||||||
|
|
||||||
|
#define INLINE_GPIO
|
||||||
|
|
||||||
|
#define gpio_set_val(port, pin, val) do { \
|
||||||
|
if(val) \
|
||||||
|
_gpio_set((port), (pin)); \
|
||||||
|
else \
|
||||||
|
_gpio_clear((port), (pin)); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#ifdef INLINE_GPIO
|
||||||
|
static inline void _gpio_set(uint32_t gpioport, uint32_t gpios)
|
||||||
|
{
|
||||||
|
PORT_OUTSET(gpioport) = gpios;
|
||||||
|
}
|
||||||
|
#define gpio_set _gpio_set
|
||||||
|
|
||||||
|
static inline void _gpio_clear(uint32_t gpioport, uint32_t gpios)
|
||||||
|
{
|
||||||
|
PORT_OUTCLR(gpioport) = gpios;
|
||||||
|
}
|
||||||
|
#define gpio_clear _gpio_clear
|
||||||
|
|
||||||
|
static inline uint16_t _gpio_get(uint32_t gpioport, uint32_t gpios)
|
||||||
|
{
|
||||||
|
return (uint32_t)PORT_IN(gpioport) & gpios;
|
||||||
|
}
|
||||||
|
#define gpio_get _gpio_get
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEBUG(...)
|
||||||
|
|
||||||
|
#define SET_RUN_STATE(state) {running_status = (state);}
|
||||||
|
#define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, LED_IDLE_RUN, state);}
|
||||||
|
#define SET_ERROR_STATE(state) {gpio_set_val(LED_PORT, LED_ERROR, state);}
|
||||||
|
|
||||||
|
static inline int platform_hwversion(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_pop(void);
|
||||||
|
int usbuart_convert_tdio(uint32_t arg);
|
||||||
|
int usbuart_convert_tdio_enabled(void);
|
||||||
|
void print_serial(void);
|
||||||
|
#endif
|
351
src/platforms/jeff/usbdfu.c
Normal file
351
src/platforms/jeff/usbdfu.c
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the libopencm3 project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
|
||||||
|
*
|
||||||
|
* This library is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <libopencm3/sam/d/gclk.h>
|
||||||
|
#include <libopencm3/sam/d/port.h>
|
||||||
|
#include <libopencm3/sam/d/nvmctrl.h>
|
||||||
|
#include <libopencm3/cm3/scb.h>
|
||||||
|
#include <libopencm3/usb/usbd.h>
|
||||||
|
#include <libopencm3/usb/dfu.h>
|
||||||
|
|
||||||
|
#include <libopencm3/sam/d/nvic.h>
|
||||||
|
#include <libopencm3/sam/d/pm.h>
|
||||||
|
#include <libopencm3/sam/d/bitfield.h>
|
||||||
|
#include <libopencm3/sam/d/usb.h>
|
||||||
|
|
||||||
|
//#define APP_ADDRESS 0x08002000
|
||||||
|
//#define APP_ADDRESS 0x00002000
|
||||||
|
#define APP_ADDRESS 0x00002000
|
||||||
|
//#define APP_ADDRESS 0x00004000
|
||||||
|
|
||||||
|
/* Commands sent with wBlockNum == 0 as per ST implementation. */
|
||||||
|
#define CMD_SETADDR 0x21
|
||||||
|
#define CMD_ERASE 0x41
|
||||||
|
|
||||||
|
#define BUTTON_PORT PORTA
|
||||||
|
#define BUTTON_PIN GPIO27
|
||||||
|
|
||||||
|
#define BUF_SIZE 4096
|
||||||
|
|
||||||
|
static struct gclk_hw clock = {
|
||||||
|
.gclk0 = SRC_DFLL48M,
|
||||||
|
.gclk1 = SRC_OSC8M,
|
||||||
|
/* clock 1 has 8 divider, clock should be over 1khz for 1ms timer */
|
||||||
|
.gclk1_div = 100,
|
||||||
|
.gclk2 = SRC_DFLL48M,
|
||||||
|
.gclk3 = SRC_DFLL48M,
|
||||||
|
.gclk3_div = 1,
|
||||||
|
.gclk4 = SRC_OSC8M,
|
||||||
|
.gclk4_div = 1,
|
||||||
|
.gclk5 = SRC_DFLL48M,
|
||||||
|
.gclk6 = SRC_DFLL48M,
|
||||||
|
.gclk7 = SRC_DFLL48M,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* We need a special large control buffer for this device: */
|
||||||
|
uint8_t usbd_control_buffer[BUF_SIZE];
|
||||||
|
|
||||||
|
static enum dfu_state usbdfu_state = STATE_DFU_IDLE;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
uint8_t buf[sizeof(usbd_control_buffer)];
|
||||||
|
uint16_t len;
|
||||||
|
uint32_t addr;
|
||||||
|
uint16_t blocknum;
|
||||||
|
} prog;
|
||||||
|
|
||||||
|
const struct usb_device_descriptor dev = {
|
||||||
|
.bLength = USB_DT_DEVICE_SIZE,
|
||||||
|
.bDescriptorType = USB_DT_DEVICE,
|
||||||
|
.bcdUSB = 0x0200,
|
||||||
|
.bDeviceClass = 0,
|
||||||
|
.bDeviceSubClass = 0,
|
||||||
|
.bDeviceProtocol = 0,
|
||||||
|
.bMaxPacketSize0 = 64,
|
||||||
|
.idVendor = 0x1D50,
|
||||||
|
.idProduct = 0x6017,
|
||||||
|
.bcdDevice = 0x0200,
|
||||||
|
.iManufacturer = 1,
|
||||||
|
.iProduct = 2,
|
||||||
|
.iSerialNumber = 3,
|
||||||
|
.bNumConfigurations = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct usb_dfu_descriptor dfu_function = {
|
||||||
|
.bLength = sizeof(struct usb_dfu_descriptor),
|
||||||
|
.bDescriptorType = DFU_FUNCTIONAL,
|
||||||
|
.bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
|
||||||
|
.wDetachTimeout = 255,
|
||||||
|
.wTransferSize = BUF_SIZE,
|
||||||
|
.bcdDFUVersion = 0x011A,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct usb_interface_descriptor iface = {
|
||||||
|
.bLength = USB_DT_INTERFACE_SIZE,
|
||||||
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
|
.bInterfaceNumber = 0,
|
||||||
|
.bAlternateSetting = 0,
|
||||||
|
.bNumEndpoints = 0,
|
||||||
|
.bInterfaceClass = 0xFE, /* Device Firmware Upgrade */
|
||||||
|
.bInterfaceSubClass = 1,
|
||||||
|
.bInterfaceProtocol = 2,
|
||||||
|
|
||||||
|
/* The ST Microelectronics DfuSe application needs this string.
|
||||||
|
* The format isn't documented... */
|
||||||
|
.iInterface = 4,
|
||||||
|
|
||||||
|
.extra = &dfu_function,
|
||||||
|
.extralen = sizeof(dfu_function),
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct usb_interface ifaces[] = {{
|
||||||
|
.num_altsetting = 1,
|
||||||
|
.altsetting = &iface,
|
||||||
|
}};
|
||||||
|
|
||||||
|
const struct usb_config_descriptor config = {
|
||||||
|
.bLength = USB_DT_CONFIGURATION_SIZE,
|
||||||
|
.bDescriptorType = USB_DT_CONFIGURATION,
|
||||||
|
.wTotalLength = 0,
|
||||||
|
.bNumInterfaces = 1,
|
||||||
|
.bConfigurationValue = 1,
|
||||||
|
.iConfiguration = 0,
|
||||||
|
.bmAttributes = 0xC0,
|
||||||
|
.bMaxPower = 0x32,
|
||||||
|
|
||||||
|
.interface = ifaces,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *usb_strings[] = {
|
||||||
|
"Black Sphere Technologies",
|
||||||
|
"DFU Demo",
|
||||||
|
"DEMO",
|
||||||
|
/* This string is used by ST Microelectronics' DfuSe utility. */
|
||||||
|
//"@Internal Flash /0x08000000/8*001Ka,56*001Kg",
|
||||||
|
"@Internal Flash /0x00000000/1*008Ka,15*008Kg",
|
||||||
|
//"@Internal Flash /0x00000000/1*0016Ka,15*0016Kg",
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t usbdfu_getstatus(uint32_t *bwPollTimeout)
|
||||||
|
{
|
||||||
|
switch (usbdfu_state) {
|
||||||
|
case STATE_DFU_DNLOAD_SYNC:
|
||||||
|
usbdfu_state = STATE_DFU_DNBUSY;
|
||||||
|
*bwPollTimeout = 100;
|
||||||
|
return DFU_STATUS_OK;
|
||||||
|
case STATE_DFU_MANIFEST_SYNC:
|
||||||
|
/* Device will reset when read is complete. */
|
||||||
|
usbdfu_state = STATE_DFU_MANIFEST;
|
||||||
|
return DFU_STATUS_OK;
|
||||||
|
default:
|
||||||
|
return DFU_STATUS_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usbdfu_getstatus_complete(usbd_device *usbd_dev, struct usb_setup_data *req)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
(void)req;
|
||||||
|
(void)usbd_dev;
|
||||||
|
|
||||||
|
switch (usbdfu_state) {
|
||||||
|
case STATE_DFU_DNBUSY:
|
||||||
|
//flash_unlock();
|
||||||
|
if (prog.blocknum == 0) {
|
||||||
|
switch (prog.buf[0]) {
|
||||||
|
case CMD_ERASE:
|
||||||
|
{
|
||||||
|
uint32_t *dat = (uint32_t *)(prog.buf + 1);
|
||||||
|
nvmctrl_erase_row(*dat); //flash_erase_page(*dat);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CMD_SETADDR:
|
||||||
|
{
|
||||||
|
uint32_t *dat = (uint32_t *)(prog.buf + 1);
|
||||||
|
prog.addr = *dat;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//uint32_t baseaddr = prog.addr + ((prog.blocknum - 2) *
|
||||||
|
// dfu_function.wTransferSize);
|
||||||
|
uint32_t baseaddr = prog.addr;
|
||||||
|
//for (i = 0; i < prog.len; i += 2) {
|
||||||
|
//uint16_t *dat = (uint16_t *)(prog.buf + i);
|
||||||
|
//flash_program_half_word(baseaddr + i,
|
||||||
|
// *dat);
|
||||||
|
for (i = 0; i < BUF_SIZE; i += 256){
|
||||||
|
nvmctrl_erase_row(baseaddr+i);
|
||||||
|
nvmctrl_write_row(baseaddr+i, prog.buf+i);
|
||||||
|
}
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
//flash_lock();
|
||||||
|
|
||||||
|
/* Jump straight to dfuDNLOAD-IDLE, skipping dfuDNLOAD-SYNC. */
|
||||||
|
usbdfu_state = STATE_DFU_DNLOAD_IDLE;
|
||||||
|
return;
|
||||||
|
case STATE_DFU_MANIFEST:
|
||||||
|
/* reset USB */
|
||||||
|
INSERTBF(USB_CTRLA_SWRST, 1, USB->ctrla);
|
||||||
|
/* jump to app */
|
||||||
|
if ((*(volatile uint32_t *)APP_ADDRESS & 0x2FFE0000) == 0x20000000) {
|
||||||
|
|
||||||
|
/* Set vector table base address. */
|
||||||
|
//SCB_VTOR = APP_ADDRESS & 0xFFFF;
|
||||||
|
SCB_VTOR = APP_ADDRESS;
|
||||||
|
/* Initialise master stack pointer. */
|
||||||
|
asm volatile("msr msp, %0"::"g"
|
||||||
|
(*(volatile uint32_t *)APP_ADDRESS));
|
||||||
|
/* Jump to application. */
|
||||||
|
(*(void (**)())(APP_ADDRESS + 4))();
|
||||||
|
}
|
||||||
|
|
||||||
|
//scb_reset_system();
|
||||||
|
return; /* Will never return. */
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum usbd_request_return_codes usbdfu_control_request(usbd_device *dev,
|
||||||
|
struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
|
||||||
|
void (**complete)(usbd_device *dev, struct usb_setup_data *req))
|
||||||
|
{
|
||||||
|
(void)dev;
|
||||||
|
|
||||||
|
if ((req->bmRequestType & 0x7F) != 0x21)
|
||||||
|
return 0; /* Only accept class request. */
|
||||||
|
|
||||||
|
switch (req->bRequest) {
|
||||||
|
case DFU_DNLOAD:
|
||||||
|
if ((len == NULL) || (*len == 0)) {
|
||||||
|
usbdfu_state = STATE_DFU_MANIFEST_SYNC;
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
/* Copy download data for use on GET_STATUS. */
|
||||||
|
prog.blocknum = req->wValue;
|
||||||
|
prog.len = *len;
|
||||||
|
memcpy(prog.buf, *buf, *len);
|
||||||
|
usbdfu_state = STATE_DFU_DNLOAD_SYNC;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
case DFU_CLRSTATUS:
|
||||||
|
/* Clear error and return to dfuIDLE. */
|
||||||
|
if (usbdfu_state == STATE_DFU_ERROR)
|
||||||
|
usbdfu_state = STATE_DFU_IDLE;
|
||||||
|
return 1;
|
||||||
|
case DFU_ABORT:
|
||||||
|
/* Abort returns to dfuIDLE state. */
|
||||||
|
usbdfu_state = STATE_DFU_IDLE;
|
||||||
|
return 1;
|
||||||
|
case DFU_UPLOAD:
|
||||||
|
/* Upload not supported for now. */
|
||||||
|
return 0;
|
||||||
|
case DFU_GETSTATUS: {
|
||||||
|
uint32_t bwPollTimeout = 0; /* 24-bit integer in DFU class spec */
|
||||||
|
(*buf)[0] = usbdfu_getstatus(&bwPollTimeout);
|
||||||
|
(*buf)[1] = bwPollTimeout & 0xFF;
|
||||||
|
(*buf)[2] = (bwPollTimeout >> 8) & 0xFF;
|
||||||
|
(*buf)[3] = (bwPollTimeout >> 16) & 0xFF;
|
||||||
|
(*buf)[4] = usbdfu_state;
|
||||||
|
(*buf)[5] = 0; /* iString not used here */
|
||||||
|
*len = 6;
|
||||||
|
*complete = usbdfu_getstatus_complete;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
case DFU_GETSTATE:
|
||||||
|
/* Return state with no state transision. */
|
||||||
|
*buf[0] = usbdfu_state;
|
||||||
|
*len = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usbdfu_set_config(usbd_device *usbd_dev, uint16_t wValue)
|
||||||
|
{
|
||||||
|
(void)wValue;
|
||||||
|
|
||||||
|
usbd_register_control_callback(
|
||||||
|
usbd_dev,
|
||||||
|
USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
|
||||||
|
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
|
||||||
|
usbdfu_control_request);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_setup(void)
|
||||||
|
{
|
||||||
|
/* Enable USB */
|
||||||
|
INSERTBF(PM_APBBMASK_USB, 1, PM->apbbmask);
|
||||||
|
|
||||||
|
/* enable clocking to usb */
|
||||||
|
set_periph_clk(GCLK0, GCLK_ID_USB);
|
||||||
|
periph_clk_en(GCLK_ID_USB, 1);
|
||||||
|
|
||||||
|
gpio_config_special(PORTA, GPIO24, SOC_GPIO_PERIPH_G);
|
||||||
|
gpio_config_special(PORTA, GPIO25, SOC_GPIO_PERIPH_G);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
usbd_device *usbd_dev;
|
||||||
|
|
||||||
|
gclk_init(&clock);
|
||||||
|
//rcc_periph_clock_enable(RCC_GPIOA);
|
||||||
|
//gpio_config_input(BUTTON_PORT,BUTTON_PIN,GPIO_IN_FLAG_PULLUP);
|
||||||
|
gpio_config_input(BUTTON_PORT,BUTTON_PIN,0);
|
||||||
|
|
||||||
|
nvmctrl_init(0,0);
|
||||||
|
|
||||||
|
usb_setup();
|
||||||
|
|
||||||
|
if (PM->rcause != (1<<6))
|
||||||
|
if (gpio_get(BUTTON_PORT, BUTTON_PIN)) {
|
||||||
|
//if (gpio_get(PORTA, GPIO27)) {
|
||||||
|
/* Boot the application if it's valid. */
|
||||||
|
if ((*(volatile uint32_t *)APP_ADDRESS & 0x2FFE0000) == 0x20000000) {
|
||||||
|
|
||||||
|
/* Set vector table base address. */
|
||||||
|
//SCB_VTOR = APP_ADDRESS & 0xFFFF;
|
||||||
|
SCB_VTOR = APP_ADDRESS;
|
||||||
|
/* Initialise master stack pointer. */
|
||||||
|
asm volatile("msr msp, %0"::"g"
|
||||||
|
(*(volatile uint32_t *)APP_ADDRESS));
|
||||||
|
/* Jump to application. */
|
||||||
|
(*(void (**)())(APP_ADDRESS + 4))();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usbd_dev = usbd_init(&samd21_usb_driver, &dev, &config, usb_strings, 4, usbd_control_buffer, sizeof(usbd_control_buffer));
|
||||||
|
usbd_register_set_config_callback(usbd_dev, usbdfu_set_config);
|
||||||
|
|
||||||
|
//nvic_enable_irq(NVIC_USB_IRQ);
|
||||||
|
|
||||||
|
/* Connect USB cable */
|
||||||
|
usbd_disconnect(usbd_dev, false);
|
||||||
|
|
||||||
|
//gpio_clear(GPIOC, GPIO11);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
usbd_poll(usbd_dev);
|
||||||
|
}
|
@ -7,6 +7,7 @@ INCLUDES = -I../libopencm3/include
|
|||||||
|
|
||||||
CPU_FLAGS = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard
|
CPU_FLAGS = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard
|
||||||
CFLAGS += $(INCLUDES) $(CPU_FLAGS) -DSERIAL_NO=$(SERIAL_NO) -DTARGET_IS_BLIZZARD_RB1 -DLM4F -DPART_TM4C123GH6PM
|
CFLAGS += $(INCLUDES) $(CPU_FLAGS) -DSERIAL_NO=$(SERIAL_NO) -DTARGET_IS_BLIZZARD_RB1 -DLM4F -DPART_TM4C123GH6PM
|
||||||
|
CFLAGS += -DDFU_SERIAL_LENGTH=9
|
||||||
|
|
||||||
LINKER_SCRIPT="platforms/tm4c/tm4c.ld"
|
LINKER_SCRIPT="platforms/tm4c/tm4c.ld"
|
||||||
LDFLAGS = -nostartfiles -lc $(CPU_FLAGS) -nodefaultlibs -T$(LINKER_SCRIPT) -Wl,--gc-sections \
|
LDFLAGS = -nostartfiles -lc $(CPU_FLAGS) -nodefaultlibs -T$(LINKER_SCRIPT) -Wl,--gc-sections \
|
||||||
|
@ -25,9 +25,6 @@
|
|||||||
#include <libopencm3/cm3/systick.h>
|
#include <libopencm3/cm3/systick.h>
|
||||||
#include <libopencm3/lm4f/usb.h>
|
#include <libopencm3/lm4f/usb.h>
|
||||||
|
|
||||||
#define SYSTICKHZ 100
|
|
||||||
#define SYSTICKMS (1000 / SYSTICKHZ)
|
|
||||||
|
|
||||||
#define PLL_DIV_80MHZ 5
|
#define PLL_DIV_80MHZ 5
|
||||||
#define PLL_DIV_25MHZ 16
|
#define PLL_DIV_25MHZ 16
|
||||||
|
|
||||||
@ -37,6 +34,8 @@ volatile platform_timeout * volatile head_timeout;
|
|||||||
uint8_t running_status;
|
uint8_t running_status;
|
||||||
static volatile uint32_t time_ms;
|
static volatile uint32_t time_ms;
|
||||||
|
|
||||||
|
uint32_t swd_delay_cnt = 0;
|
||||||
|
|
||||||
void sys_tick_handler(void)
|
void sys_tick_handler(void)
|
||||||
{
|
{
|
||||||
trace_tick();
|
trace_tick();
|
||||||
@ -118,7 +117,7 @@ const char *platform_target_voltage(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *serial_no_read(char *s, int max)
|
char *serial_no_read(char *s)
|
||||||
{
|
{
|
||||||
/* FIXME: Store a unique serial number somewhere and retreive here */
|
/* FIXME: Store a unique serial number somewhere and retreive here */
|
||||||
uint32_t unique_id = SERIAL_NO;
|
uint32_t unique_id = SERIAL_NO;
|
||||||
@ -128,10 +127,10 @@ char *serial_no_read(char *s, int max)
|
|||||||
for(i = 0; i < 8; i++) {
|
for(i = 0; i < 8; i++) {
|
||||||
s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
|
s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
|
||||||
}
|
}
|
||||||
for(i = 0; i < max - 1; i++)
|
for(i = 0; i < DFU_SERIAL_LENGTH - 1; i++)
|
||||||
if(s[i] > '9')
|
if(s[i] > '9')
|
||||||
s[i] += 'A' - '9' - 1;
|
s[i] += 'A' - '9' - 1;
|
||||||
s[max] = 0;
|
s[DFU_SERIAL_LENGTH - 1] = 0;
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@ -140,3 +139,12 @@ void platform_request_boot(void)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void platform_max_frequency_set(uint32_t freq)
|
||||||
|
{
|
||||||
|
(void)freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t platform_max_frequency_get(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -21,14 +21,11 @@
|
|||||||
#include <libopencm3/usb/usbd.h>
|
#include <libopencm3/usb/usbd.h>
|
||||||
|
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
#include "version.h"
|
|
||||||
|
|
||||||
#define BOARD_IDENT "Black Magic Probe (Launchpad ICDI), (Firmware " FIRMWARE_VERSION ")"
|
#define PLATFORM_IDENT "(Launchpad ICDI) "
|
||||||
#define BOARD_IDENT_DFU "Black Magic (Upgrade) for Launchpad, (Firmware " FIRMWARE_VERSION ")"
|
|
||||||
#define DFU_IDENT "Black Magic Firmware Upgrade (Launchpad)"
|
|
||||||
#define DFU_IFACE_STRING "lolwut"
|
|
||||||
|
|
||||||
extern uint8_t running_status;
|
extern uint8_t running_status;
|
||||||
|
extern uint32_t swd_delay_cnt;
|
||||||
|
|
||||||
#define TMS_PORT GPIOA_BASE
|
#define TMS_PORT GPIOA_BASE
|
||||||
#define TMS_PIN GPIO3
|
#define TMS_PIN GPIO3
|
||||||
|
@ -4,7 +4,7 @@ OBJCOPY = $(CROSS_COMPILE)objcopy
|
|||||||
|
|
||||||
CFLAGS += -Istm32/include -mcpu=cortex-m3 -mthumb \
|
CFLAGS += -Istm32/include -mcpu=cortex-m3 -mthumb \
|
||||||
-DSTM32F1 -DBLACKMAGIC -I../libopencm3/include \
|
-DSTM32F1 -DBLACKMAGIC -I../libopencm3/include \
|
||||||
-Iplatforms/stm32
|
-Iplatforms/stm32 -DDFU_SERIAL_LENGTH=9
|
||||||
|
|
||||||
LDFLAGS_BOOT := $(LDFLAGS) --specs=nano.specs -lopencm3_stm32f1 \
|
LDFLAGS_BOOT := $(LDFLAGS) --specs=nano.specs -lopencm3_stm32f1 \
|
||||||
-Wl,-T,platforms/stm32/blackmagic.ld -nostartfiles -lc \
|
-Wl,-T,platforms/stm32/blackmagic.ld -nostartfiles -lc \
|
||||||
@ -30,7 +30,7 @@ SRC += cdcacm.c \
|
|||||||
|
|
||||||
all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
|
all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
|
||||||
|
|
||||||
blackmagic_dfu.elf: usbdfu.o dfucore.o dfu_f1.o
|
blackmagic_dfu.elf: usbdfu.o dfucore.o dfu_f1.o serialno.o
|
||||||
@echo " LD $@"
|
@echo " LD $@"
|
||||||
$(Q)$(CC) $^ -o $@ $(LDFLAGS_BOOT)
|
$(Q)$(CC) $^ -o $@ $(LDFLAGS_BOOT)
|
||||||
|
|
||||||
|
@ -27,23 +27,50 @@
|
|||||||
#include "usbuart.h"
|
#include "usbuart.h"
|
||||||
#include "morse.h"
|
#include "morse.h"
|
||||||
|
|
||||||
#include <libopencm3/stm32/f1/rcc.h>
|
#include <libopencm3/stm32/rcc.h>
|
||||||
#include <libopencm3/cm3/scb.h>
|
#include <libopencm3/cm3/scb.h>
|
||||||
#include <libopencm3/cm3/scs.h>
|
#include <libopencm3/cm3/scs.h>
|
||||||
#include <libopencm3/cm3/nvic.h>
|
#include <libopencm3/cm3/nvic.h>
|
||||||
#include <libopencm3/stm32/exti.h>
|
#include <libopencm3/stm32/exti.h>
|
||||||
#include <libopencm3/stm32/usart.h>
|
#include <libopencm3/stm32/usart.h>
|
||||||
#include <libopencm3/usb/usbd.h>
|
#include <libopencm3/usb/usbd.h>
|
||||||
#include <libopencm3/stm32/f1/adc.h>
|
#include <libopencm3/stm32/adc.h>
|
||||||
|
#include <libopencm3/stm32/flash.h>
|
||||||
|
|
||||||
static void adc_init(void);
|
static void adc_init(void);
|
||||||
static void setup_vbus_irq(void);
|
static void setup_vbus_irq(void);
|
||||||
|
|
||||||
|
/* Starting with hardware version 4 we are storing the hardware version in the
|
||||||
|
* flash option user Data1 byte.
|
||||||
|
* The hardware version 4 was the transition version that had it's hardware
|
||||||
|
* pins strapped to 3 but contains version 4 in the Data1 byte.
|
||||||
|
* The hardware 4 is backward compatible with V3 but provides the new jumper
|
||||||
|
* connecting STRACE target pin to the UART1 pin.
|
||||||
|
* Hardware version 5 does not have the physically strapped version encoding
|
||||||
|
* any more and the hardware version has to be read out of the option bytes.
|
||||||
|
* This means that older firmware versions that don't do the detection won't
|
||||||
|
* work on the newer hardware.
|
||||||
|
*/
|
||||||
|
#define BMP_HWVERSION_BYTE FLASH_OPTION_BYTE_2
|
||||||
|
|
||||||
/* Pins PB[7:5] are used to detect hardware revision.
|
/* Pins PB[7:5] are used to detect hardware revision.
|
||||||
* 000 - Original production build.
|
* User option byte Data1 is used starting with hardware revision 4.
|
||||||
* 001 - Mini production build.
|
* Pin - OByte - Rev - Description
|
||||||
* 010 - Mini V2.0e and later.
|
* 000 - 0xFFFF - 0 - Original production build.
|
||||||
* 011 - Mini V2.1e and later.
|
* 001 - 0xFFFF - 1 - Mini production build.
|
||||||
|
* 010 - 0xFFFF - 2 - Mini V2.0e and later.
|
||||||
|
* 011 - 0xFFFF - 3 - Mini V2.1a and later.
|
||||||
|
* 011 - 0xFB04 - 4 - Mini V2.1d and later.
|
||||||
|
* xxx - 0xFB05 - 5 - Mini V2.2a and later.
|
||||||
|
* xxx - 0xFB06 - 6 - Mini V2.3a and later.
|
||||||
|
*
|
||||||
|
* This function will return -2 if the version number does not make sense.
|
||||||
|
* This can happen when the Data1 byte contains "garbage". For example a
|
||||||
|
* hardware revision that is <4 or the high byte is not the binary inverse of
|
||||||
|
* the lower byte.
|
||||||
|
* Note: The high byte of the Data1 option byte should always be the binary
|
||||||
|
* inverse of the lower byte unless the byte is not set, then all bits in both
|
||||||
|
* high and low byte are 0xFF.
|
||||||
*/
|
*/
|
||||||
int platform_hwversion(void)
|
int platform_hwversion(void)
|
||||||
{
|
{
|
||||||
@ -51,7 +78,26 @@ int platform_hwversion(void)
|
|||||||
uint16_t hwversion_pins = GPIO7 | GPIO6 | GPIO5;
|
uint16_t hwversion_pins = GPIO7 | GPIO6 | GPIO5;
|
||||||
uint16_t unused_pins = hwversion_pins ^ 0xFFFF;
|
uint16_t unused_pins = hwversion_pins ^ 0xFFFF;
|
||||||
|
|
||||||
/* Only check for version if this is the first time. */
|
/* Check if the hwversion is set in the user option byte. */
|
||||||
|
if (hwversion == -1) {
|
||||||
|
if ((BMP_HWVERSION_BYTE != 0xFFFF) &&
|
||||||
|
(BMP_HWVERSION_BYTE != 0x00FF)) {
|
||||||
|
/* Check if the data is valid.
|
||||||
|
* When valid it should only have values 4 and higher.
|
||||||
|
*/
|
||||||
|
if (((BMP_HWVERSION_BYTE >> 8) !=
|
||||||
|
(~BMP_HWVERSION_BYTE & 0xFF)) ||
|
||||||
|
((BMP_HWVERSION_BYTE & 0xFF) < 4)) {
|
||||||
|
return -2;
|
||||||
|
} else {
|
||||||
|
hwversion = BMP_HWVERSION_BYTE & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the hwversion is not set in option bytes check
|
||||||
|
* the hw pin strapping.
|
||||||
|
*/
|
||||||
if (hwversion == -1) {
|
if (hwversion == -1) {
|
||||||
/* Configure the hardware version pins as input pull-up/down */
|
/* Configure the hardware version pins as input pull-up/down */
|
||||||
gpio_set_mode(GPIOB, GPIO_MODE_INPUT,
|
gpio_set_mode(GPIOB, GPIO_MODE_INPUT,
|
||||||
@ -97,7 +143,7 @@ void platform_init(void)
|
|||||||
initialise_monitor_handles();
|
initialise_monitor_handles();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rcc_clock_setup_in_hse_8mhz_out_72mhz();
|
rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]);
|
||||||
|
|
||||||
/* Enable peripherals */
|
/* Enable peripherals */
|
||||||
rcc_periph_clock_enable(RCC_USB);
|
rcc_periph_clock_enable(RCC_USB);
|
||||||
@ -131,10 +177,6 @@ void platform_init(void)
|
|||||||
GPIO_CNF_OUTPUT_PUSHPULL,
|
GPIO_CNF_OUTPUT_PUSHPULL,
|
||||||
LED_UART | LED_IDLE_RUN | LED_ERROR);
|
LED_UART | LED_IDLE_RUN | LED_ERROR);
|
||||||
|
|
||||||
/* FIXME: This pin in intended to be input, but the TXS0108 fails
|
|
||||||
* to release the device from reset if this floats. */
|
|
||||||
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
|
|
||||||
GPIO_CNF_OUTPUT_PUSHPULL, GPIO7);
|
|
||||||
/* Enable SRST output. Original uses a NPN to pull down, so setting the
|
/* Enable SRST output. Original uses a NPN to pull down, so setting the
|
||||||
* output HIGH asserts. Mini is directly connected so use open drain output
|
* output HIGH asserts. Mini is directly connected so use open drain output
|
||||||
* and set LOW to assert.
|
* and set LOW to assert.
|
||||||
@ -146,7 +188,17 @@ void platform_init(void)
|
|||||||
? GPIO_CNF_OUTPUT_PUSHPULL
|
? GPIO_CNF_OUTPUT_PUSHPULL
|
||||||
: GPIO_CNF_OUTPUT_OPENDRAIN),
|
: GPIO_CNF_OUTPUT_OPENDRAIN),
|
||||||
SRST_PIN);
|
SRST_PIN);
|
||||||
|
/* FIXME: Gareth, Esden, what versions need this fix? */
|
||||||
|
if (platform_hwversion() < 3) {
|
||||||
|
/* FIXME: This pin in intended to be input, but the TXS0108 fails
|
||||||
|
* to release the device from reset if this floats. */
|
||||||
|
gpio_set_mode(SRST_SENSE_PORT, GPIO_MODE_OUTPUT_2_MHZ,
|
||||||
|
GPIO_CNF_OUTPUT_PUSHPULL, SRST_SENSE_PIN);
|
||||||
|
} else {
|
||||||
|
gpio_set(SRST_SENSE_PORT, SRST_SENSE_PIN);
|
||||||
|
gpio_set_mode(SRST_SENSE_PORT, GPIO_MODE_INPUT,
|
||||||
|
GPIO_CNF_INPUT_PULL_UPDOWN, SRST_SENSE_PIN);
|
||||||
|
}
|
||||||
/* Enable internal pull-up on PWR_BR so that we don't drive
|
/* Enable internal pull-up on PWR_BR so that we don't drive
|
||||||
TPWR locally or inadvertently supply power to the target. */
|
TPWR locally or inadvertently supply power to the target. */
|
||||||
if (platform_hwversion () == 1) {
|
if (platform_hwversion () == 1) {
|
||||||
@ -233,7 +285,7 @@ static void adc_init(void)
|
|||||||
adc_set_single_conversion_mode(ADC1);
|
adc_set_single_conversion_mode(ADC1);
|
||||||
adc_disable_external_trigger_regular(ADC1);
|
adc_disable_external_trigger_regular(ADC1);
|
||||||
adc_set_right_aligned(ADC1);
|
adc_set_right_aligned(ADC1);
|
||||||
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28DOT5CYC);
|
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_239DOT5CYC);
|
||||||
|
|
||||||
adc_power_on(ADC1);
|
adc_power_on(ADC1);
|
||||||
|
|
||||||
@ -245,12 +297,16 @@ static void adc_init(void)
|
|||||||
adc_calibrate(ADC1);
|
adc_calibrate(ADC1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *platform_target_voltage(void)
|
uint32_t platform_target_voltage_sense(void)
|
||||||
{
|
{
|
||||||
|
/* returns the voltage in volt scaled by 10 (so 33 means 3.3V), except
|
||||||
|
* for hardware version 1
|
||||||
|
* this function is only needed for implementations that allow the
|
||||||
|
* target to be powered from the debug probe
|
||||||
|
*/
|
||||||
if (platform_hwversion() == 0)
|
if (platform_hwversion() == 0)
|
||||||
return gpio_get(GPIOB, GPIO0) ? "OK" : "ABSENT!";
|
return 0;
|
||||||
|
|
||||||
static char ret[] = "0.0V";
|
|
||||||
const uint8_t channel = 8;
|
const uint8_t channel = 8;
|
||||||
adc_set_regular_sequence(ADC1, 1, (uint8_t*)&channel);
|
adc_set_regular_sequence(ADC1, 1, (uint8_t*)&channel);
|
||||||
|
|
||||||
@ -259,9 +315,21 @@ const char *platform_target_voltage(void)
|
|||||||
/* Wait for end of conversion. */
|
/* Wait for end of conversion. */
|
||||||
while (!adc_eoc(ADC1));
|
while (!adc_eoc(ADC1));
|
||||||
|
|
||||||
uint32_t val = adc_read_regular(ADC1) * 99; /* 0-4095 */
|
uint32_t val = adc_read_regular(ADC1); /* 0-4095 */
|
||||||
ret[0] = '0' + val / 81910;
|
/* Clear EOC bit. The GD32F103 does not automatically reset it on ADC read. */
|
||||||
ret[2] = '0' + (val / 8191) % 10;
|
ADC_SR(ADC1) &= ~ADC_SR_EOC;
|
||||||
|
return (val * 99) / 8191;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *platform_target_voltage(void)
|
||||||
|
{
|
||||||
|
if (platform_hwversion() == 0)
|
||||||
|
return gpio_get(GPIOB, GPIO0) ? "OK" : "ABSENT!";
|
||||||
|
|
||||||
|
static char ret[] = "0.0V";
|
||||||
|
uint32_t val = platform_target_voltage_sense();
|
||||||
|
ret[0] = '0' + val / 10;
|
||||||
|
ret[2] = '0' + val % 10;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -279,7 +347,18 @@ void platform_request_boot(void)
|
|||||||
|
|
||||||
void exti15_10_isr(void)
|
void exti15_10_isr(void)
|
||||||
{
|
{
|
||||||
if (gpio_get(USB_VBUS_PORT, USB_VBUS_PIN)) {
|
uint32_t usb_vbus_port;
|
||||||
|
uint16_t usb_vbus_pin;
|
||||||
|
|
||||||
|
if (platform_hwversion() < 5) {
|
||||||
|
usb_vbus_port = USB_VBUS_PORT;
|
||||||
|
usb_vbus_pin = USB_VBUS_PIN;
|
||||||
|
} else {
|
||||||
|
usb_vbus_port = USB_VBUS5_PORT;
|
||||||
|
usb_vbus_pin = USB_VBUS5_PIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpio_get(usb_vbus_port, usb_vbus_pin)) {
|
||||||
/* Drive pull-up high if VBUS connected */
|
/* Drive pull-up high if VBUS connected */
|
||||||
gpio_set_mode(USB_PU_PORT, GPIO_MODE_OUTPUT_10_MHZ,
|
gpio_set_mode(USB_PU_PORT, GPIO_MODE_OUTPUT_10_MHZ,
|
||||||
GPIO_CNF_OUTPUT_PUSHPULL, USB_PU_PIN);
|
GPIO_CNF_OUTPUT_PUSHPULL, USB_PU_PIN);
|
||||||
@ -289,24 +368,35 @@ void exti15_10_isr(void)
|
|||||||
GPIO_CNF_INPUT_FLOAT, USB_PU_PIN);
|
GPIO_CNF_INPUT_FLOAT, USB_PU_PIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
exti_reset_request(USB_VBUS_PIN);
|
exti_reset_request(usb_vbus_pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_vbus_irq(void)
|
static void setup_vbus_irq(void)
|
||||||
{
|
{
|
||||||
|
uint32_t usb_vbus_port;
|
||||||
|
uint16_t usb_vbus_pin;
|
||||||
|
|
||||||
|
if (platform_hwversion() < 5) {
|
||||||
|
usb_vbus_port = USB_VBUS_PORT;
|
||||||
|
usb_vbus_pin = USB_VBUS_PIN;
|
||||||
|
} else {
|
||||||
|
usb_vbus_port = USB_VBUS5_PORT;
|
||||||
|
usb_vbus_pin = USB_VBUS5_PIN;
|
||||||
|
}
|
||||||
|
|
||||||
nvic_set_priority(USB_VBUS_IRQ, IRQ_PRI_USB_VBUS);
|
nvic_set_priority(USB_VBUS_IRQ, IRQ_PRI_USB_VBUS);
|
||||||
nvic_enable_irq(USB_VBUS_IRQ);
|
nvic_enable_irq(USB_VBUS_IRQ);
|
||||||
|
|
||||||
gpio_set(USB_VBUS_PORT, USB_VBUS_PIN);
|
gpio_set(usb_vbus_port, usb_vbus_pin);
|
||||||
gpio_set(USB_PU_PORT, USB_PU_PIN);
|
gpio_set(USB_PU_PORT, USB_PU_PIN);
|
||||||
|
|
||||||
gpio_set_mode(USB_VBUS_PORT, GPIO_MODE_INPUT,
|
gpio_set_mode(usb_vbus_port, GPIO_MODE_INPUT,
|
||||||
GPIO_CNF_INPUT_PULL_UPDOWN, USB_VBUS_PIN);
|
GPIO_CNF_INPUT_PULL_UPDOWN, usb_vbus_pin);
|
||||||
|
|
||||||
/* Configure EXTI for USB VBUS monitor */
|
/* Configure EXTI for USB VBUS monitor */
|
||||||
exti_select_source(USB_VBUS_PIN, USB_VBUS_PORT);
|
exti_select_source(usb_vbus_pin, usb_vbus_port);
|
||||||
exti_set_trigger(USB_VBUS_PIN, EXTI_TRIGGER_BOTH);
|
exti_set_trigger(usb_vbus_pin, EXTI_TRIGGER_BOTH);
|
||||||
exti_enable_request(USB_VBUS_PIN);
|
exti_enable_request(usb_vbus_pin);
|
||||||
|
|
||||||
exti15_10_isr();
|
exti15_10_isr();
|
||||||
}
|
}
|
||||||
|
@ -38,33 +38,69 @@ extern bool debug_bmp;
|
|||||||
int usbuart_debug_write(const char *buf, size_t len);
|
int usbuart_debug_write(const char *buf, size_t len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BOARD_IDENT "Black Magic Probe"
|
#define PLATFORM_IDENT " "
|
||||||
#define BOARD_IDENT_DFU "Black Magic Probe (Upgrade)"
|
|
||||||
#define BOARD_IDENT_UPD "Black Magic Probe (DFU Upgrade)"
|
|
||||||
#define DFU_IDENT "Black Magic Firmware Upgrade"
|
|
||||||
#define UPD_IFACE_STRING "@Internal Flash /0x08000000/8*001Kg"
|
#define UPD_IFACE_STRING "@Internal Flash /0x08000000/8*001Kg"
|
||||||
|
|
||||||
|
/* Hardware version switcher helper
|
||||||
|
* when the hardware version is smaller than ver
|
||||||
|
* it outputs opt1, otherwise opt2 */
|
||||||
|
#define HW_SWITCH(ver, opt1, opt2) \
|
||||||
|
((platform_hwversion() < (ver))?(opt1):(opt2))
|
||||||
|
|
||||||
/* Important pin mappings for STM32 implementation:
|
/* Important pin mappings for STM32 implementation:
|
||||||
*
|
*
|
||||||
* LED0 = PB2 (Yellow LED : Running)
|
* LED0 = PB2 (Yellow LED : Running)
|
||||||
* LED1 = PB10 (Yellow LED : Idle)
|
* LED1 = PB10 (Orange LED : Idle)
|
||||||
* LED2 = PB11 (Red LED : Error)
|
* LED2 = PB11 (Red LED : Error)
|
||||||
*
|
*
|
||||||
* TPWR = PB0 (input) -- analogue on mini design ADC1, ch8
|
* TPWR = PB0 (input) -- analogue on mini design ADC1, CH8
|
||||||
* nTRST = PB1 (output) [blackmagic]
|
* nTRST = PB1 (output) [blackmagic]
|
||||||
* PWR_BR = PB1 (output) [blackmagic_mini] -- supply power to the target, active low
|
* PWR_BR = PB1 (output) [blackmagic_mini] -- supply power to the target, active low
|
||||||
* TMS_DIR = PA1 (output) [blackmagic_mini v2.1] -- choose direction of the TCK pin, input low, output high
|
* TMS_DIR = PA1 (output) [blackmagic_mini v2.1] -- choose direction of the TCK pin, input low, output high
|
||||||
* SRST_OUT = PA2 (output)
|
* SRST_OUT = PA2 (output) -- Hardware 5 and older
|
||||||
* TDI = PA3 (output)
|
* = PA9 (output) -- Hardware 6 and newer
|
||||||
* TMS = PA4 (input/output for SWDIO)
|
* TDI = PA3 (output) -- Hardware 5 and older
|
||||||
* TCK = PA5 (output SWCLK)
|
* = PA7 (output) -- Hardware 6 and newer
|
||||||
* TDO = PA6 (input)
|
* TMS = PA4 (input/output for SWDIO)
|
||||||
* nSRST = PA7 (input)
|
* TCK = PA5 (output SWCLK)
|
||||||
|
* TDO = PA6 (input)
|
||||||
|
* TRACESWO = PB7 (input) -- To allow trace decoding using USART1
|
||||||
|
* Hardware 4 has a normally open jumper between TDO and TRACESWO
|
||||||
|
* Hardware 5 has hardwired connection between TDO and TRACESWO
|
||||||
|
* = PA10 (input) -- Hardware 6 and newer
|
||||||
|
* nSRST = PA7 (input) -- Hardware 5 and older
|
||||||
|
* = PC13 (input) -- Hardware 6 and newer
|
||||||
*
|
*
|
||||||
* USB cable pull-up: PA8
|
* USB_PU = PA8 (output)
|
||||||
* USB VBUS detect: PB13 -- New on mini design.
|
* USB_VBUS = PB13 (input) -- New on mini design.
|
||||||
* Enable pull up for compatibility.
|
* Enable pull up for compatibility.
|
||||||
* Force DFU mode button: PB12
|
* Hardware 4 and older. (we needed the pin for SPI on 5)
|
||||||
|
* = PA15 (input) -- Hardware 5 and newer.
|
||||||
|
* BTN1 = PB12 (input) -- Force DFU bootloader when pressed during powerup.
|
||||||
|
*
|
||||||
|
* UART_TX = PA9 (output) -- USART1 Hardware 5 and older
|
||||||
|
* = PA2 (output) -- USART2 Hardware 6 and newer
|
||||||
|
* UART_RX = PA10 (input) -- USART1 Hardware 5 and older
|
||||||
|
* = PA3 (input) -- USART2 Hardware 6 and newer
|
||||||
|
*
|
||||||
|
* On Board OTG Flash: -- Optional on Hardware 5 and newer, since Hardware 6 can be on the main board
|
||||||
|
* FLASH_CS = PB5 (output)
|
||||||
|
* SCLK = PB13 (output)
|
||||||
|
* COPI = PB15 (output)
|
||||||
|
* CIPO = PB14 (input)
|
||||||
|
*
|
||||||
|
* AUX Interface: -- Hardware 5 and newer
|
||||||
|
* SCLK = PB13 (output)
|
||||||
|
* COPI = PB15 (output)
|
||||||
|
* CIPO = PB14 (input)
|
||||||
|
* FLASH_CS = PB5 (output) -- Only Hardware 5
|
||||||
|
* SD_CS = PB6 (output) -- Hardware 6 and newer
|
||||||
|
* DISPLAY_CS = PB6 (output) -- OnlyHardware 5
|
||||||
|
* = PB7 (output) -- Hardware 6 and newer
|
||||||
|
* DISPLAY_DC = PB8 (output)
|
||||||
|
* BTN1 = PB12 (input) -- Shared with the DFU bootloader button
|
||||||
|
* BTN2 = PB9 (input)
|
||||||
|
* VBAT = PA0 (input) -- Battery voltage sense ADC2, CH0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Hardware definitions... */
|
/* Hardware definitions... */
|
||||||
@ -74,7 +110,7 @@ int usbuart_debug_write(const char *buf, size_t len);
|
|||||||
#define TMS_PORT JTAG_PORT
|
#define TMS_PORT JTAG_PORT
|
||||||
#define TCK_PORT JTAG_PORT
|
#define TCK_PORT JTAG_PORT
|
||||||
#define TDO_PORT JTAG_PORT
|
#define TDO_PORT JTAG_PORT
|
||||||
#define TDI_PIN GPIO3
|
#define TDI_PIN HW_SWITCH(6, GPIO3, GPIO7)
|
||||||
#define TMS_DIR_PIN GPIO1
|
#define TMS_DIR_PIN GPIO1
|
||||||
#define TMS_PIN GPIO4
|
#define TMS_PIN GPIO4
|
||||||
#define TCK_PIN GPIO5
|
#define TCK_PIN GPIO5
|
||||||
@ -92,17 +128,23 @@ int usbuart_debug_write(const char *buf, size_t len);
|
|||||||
#define PWR_BR_PORT GPIOB
|
#define PWR_BR_PORT GPIOB
|
||||||
#define PWR_BR_PIN GPIO1
|
#define PWR_BR_PIN GPIO1
|
||||||
#define SRST_PORT GPIOA
|
#define SRST_PORT GPIOA
|
||||||
#define SRST_PIN GPIO2
|
#define SRST_PIN HW_SWITCH(6, GPIO2, GPIO9)
|
||||||
#define SRST_SENSE_PORT GPIOA
|
#define SRST_SENSE_PORT GPIOA
|
||||||
#define SRST_SENSE_PIN GPIO7
|
#define SRST_SENSE_PIN HW_SWITCH(6, GPIO7, GPIO13)
|
||||||
|
|
||||||
#define USB_PU_PORT GPIOA
|
#define USB_PU_PORT GPIOA
|
||||||
#define USB_PU_PIN GPIO8
|
#define USB_PU_PIN GPIO8
|
||||||
|
|
||||||
|
/* For HW Rev 4 and older */
|
||||||
#define USB_VBUS_PORT GPIOB
|
#define USB_VBUS_PORT GPIOB
|
||||||
#define USB_VBUS_PIN GPIO13
|
#define USB_VBUS_PIN GPIO13
|
||||||
|
/* IRQ stays the same for all hw revisions. */
|
||||||
#define USB_VBUS_IRQ NVIC_EXTI15_10_IRQ
|
#define USB_VBUS_IRQ NVIC_EXTI15_10_IRQ
|
||||||
|
|
||||||
|
/* For HW Rev 5 and newer */
|
||||||
|
#define USB_VBUS5_PORT GPIOA
|
||||||
|
#define USB_VBUS5_PIN GPIO15
|
||||||
|
|
||||||
#define LED_PORT GPIOB
|
#define LED_PORT GPIOB
|
||||||
#define LED_PORT_UART GPIOB
|
#define LED_PORT_UART GPIOB
|
||||||
#define LED_0 GPIO2
|
#define LED_0 GPIO2
|
||||||
@ -112,6 +154,37 @@ int usbuart_debug_write(const char *buf, size_t len);
|
|||||||
#define LED_IDLE_RUN LED_1
|
#define LED_IDLE_RUN LED_1
|
||||||
#define LED_ERROR LED_2
|
#define LED_ERROR LED_2
|
||||||
|
|
||||||
|
/* OTG Flash HW Rev 5 and newer */
|
||||||
|
#define OTG_PORT GPIOB
|
||||||
|
#define OTG_CS GPIO5
|
||||||
|
#define OTG_SCLK GPIO13
|
||||||
|
#define OTG_COPI GPIO15
|
||||||
|
#define OTG_CIPO GPIO14
|
||||||
|
|
||||||
|
/* AUX Port HW Rev 5 and newer */
|
||||||
|
#define AUX_PORT GPIOB
|
||||||
|
#define AUX_SCLK_PORT AUX_PORT
|
||||||
|
#define AUX_COPI_PORT AUX_PORT
|
||||||
|
#define AUX_CIPO_PORT AUX_PORT
|
||||||
|
#define AUX_FCS_PORT AUX_PORT
|
||||||
|
#define AUX_SDCS_PORT AUX_PORT
|
||||||
|
#define AUX_DCS_PORT AUX_PORT
|
||||||
|
#define AUX_DDC_PORT AUX_PORT
|
||||||
|
#define AUX_BTN1_PORT AUX_PORT
|
||||||
|
#define AUX_BTN2_PORT AUX_PORT
|
||||||
|
#define AUX_VBAT_PORT GPIOA
|
||||||
|
#define AUX_SCLK GPIO13
|
||||||
|
#define AUX_COPI GPIO15
|
||||||
|
#define AUX_CIPO GPIO14
|
||||||
|
#define AUX_FCS GPIO5
|
||||||
|
#define AUX_SDCS GPIO6
|
||||||
|
#define AUX_DCS GPIO6
|
||||||
|
#define AUX_DCS6 GPIO7
|
||||||
|
#define AUX_DDC GPIO8
|
||||||
|
#define AUX_BTN1 GPIO12
|
||||||
|
#define AUX_BTN2 GPIO9
|
||||||
|
#define AUX_VBAT GPIO0
|
||||||
|
|
||||||
# define SWD_CR GPIO_CRL(SWDIO_PORT)
|
# define SWD_CR GPIO_CRL(SWDIO_PORT)
|
||||||
# define SWD_CR_MULT (1 << (4 << 2))
|
# define SWD_CR_MULT (1 << (4 << 2))
|
||||||
|
|
||||||
@ -135,39 +208,63 @@ int usbuart_debug_write(const char *buf, size_t len);
|
|||||||
SWD_CR = cr; \
|
SWD_CR = cr; \
|
||||||
} while(0)
|
} while(0)
|
||||||
#define UART_PIN_SETUP() do { \
|
#define UART_PIN_SETUP() do { \
|
||||||
gpio_set_mode(USBUSART_PORT, GPIO_MODE_OUTPUT_2_MHZ, \
|
gpio_set_mode(USBUSART_PORT, GPIO_MODE_OUTPUT_50_MHZ, \
|
||||||
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, USBUSART_TX_PIN); \
|
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, USBUSART_TX_PIN); \
|
||||||
|
gpio_set_mode(USBUSART_PORT, GPIO_MODE_INPUT, \
|
||||||
|
GPIO_CNF_INPUT_PULL_UPDOWN, USBUSART_RX_PIN); \
|
||||||
|
gpio_set(USBUSART_PORT, USBUSART_RX_PIN); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#define USB_DRIVER st_usbfs_v1_usb_driver
|
#define USB_DRIVER st_usbfs_v1_usb_driver
|
||||||
#define USB_IRQ NVIC_USB_LP_CAN_RX0_IRQ
|
#define USB_IRQ NVIC_USB_LP_CAN_RX0_IRQ
|
||||||
#define USB_ISR usb_lp_can_rx0_isr
|
#define USB_ISR(x) usb_lp_can_rx0_isr(x)
|
||||||
/* Interrupt priorities. Low numbers are high priority.
|
/* Interrupt priorities. Low numbers are high priority.
|
||||||
* For now USART1 preempts USB which may spin while buffer is drained.
|
|
||||||
* TIM3 is used for traceswo capture and must be highest priority.
|
* TIM3 is used for traceswo capture and must be highest priority.
|
||||||
*/
|
*/
|
||||||
#define IRQ_PRI_USB (2 << 4)
|
#define IRQ_PRI_USB (1 << 4)
|
||||||
#define IRQ_PRI_USBUSART (1 << 4)
|
#define IRQ_PRI_USBUSART (2 << 4)
|
||||||
#define IRQ_PRI_USBUSART_TIM (3 << 4)
|
#define IRQ_PRI_USBUSART_DMA (2 << 4)
|
||||||
#define IRQ_PRI_USB_VBUS (14 << 4)
|
#define IRQ_PRI_USB_VBUS (14 << 4)
|
||||||
#define IRQ_PRI_TRACE (0 << 4)
|
#define IRQ_PRI_TRACE (0 << 4)
|
||||||
|
|
||||||
#define USBUSART USART1
|
#define USBUSART HW_SWITCH(6, USBUSART1, USBUSART2)
|
||||||
#define USBUSART_CR1 USART1_CR1
|
#define USBUSART_IRQ HW_SWITCH(6, NVIC_USART1_IRQ, NVIC_USART2_IRQ)
|
||||||
#define USBUSART_IRQ NVIC_USART1_IRQ
|
#define USBUSART_CLK HW_SWITCH(6, RCC_USART1, RCC_USART2)
|
||||||
#define USBUSART_CLK RCC_USART1
|
|
||||||
#define USBUSART_PORT GPIOA
|
#define USBUSART_PORT GPIOA
|
||||||
#define USBUSART_TX_PIN GPIO9
|
#define USBUSART_TX_PIN HW_SWITCH(6, GPIO9, GPIO2)
|
||||||
#define USBUSART_ISR usart1_isr
|
#define USBUSART_RX_PIN HW_SWITCH(6, GPIO10, GPIO3)
|
||||||
#define USBUSART_TIM TIM4
|
|
||||||
#define USBUSART_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM4)
|
#define USBUSART_DMA_BUS DMA1
|
||||||
#define USBUSART_TIM_IRQ NVIC_TIM4_IRQ
|
#define USBUSART_DMA_CLK RCC_DMA1
|
||||||
#define USBUSART_TIM_ISR tim4_isr
|
#define USBUSART_DMA_TX_CHAN HW_SWITCH(6, USBUSART1_DMA_TX_CHAN, USBUSART2_DMA_TX_CHAN)
|
||||||
|
#define USBUSART_DMA_RX_CHAN HW_SWITCH(6, USBUSART1_DMA_RX_CHAN, USBUSART2_DMA_RX_CHAN)
|
||||||
|
#define USBUSART_DMA_TX_IRQ HW_SWITCH(6, USBUSART1_DMA_TX_IRQ, USBUSART2_DMA_TX_IRQ)
|
||||||
|
#define USBUSART_DMA_RX_IRQ HW_SWITCH(6, USBUSART1_DMA_RX_IRQ, USBUSART2_DMA_RX_IRQ)
|
||||||
|
|
||||||
|
#define USBUSART1 USART1
|
||||||
|
#define USBUSART1_IRQ NVIC_USART1_IRQ
|
||||||
|
#define USBUSART1_ISR(x) usart1_isr(x)
|
||||||
|
#define USBUSART1_DMA_TX_CHAN DMA_CHANNEL4
|
||||||
|
#define USBUSART1_DMA_TX_IRQ NVIC_DMA1_CHANNEL4_IRQ
|
||||||
|
#define USBUSART1_DMA_TX_ISR(x) dma1_channel4_isr(x)
|
||||||
|
#define USBUSART1_DMA_RX_CHAN DMA_CHANNEL5
|
||||||
|
#define USBUSART1_DMA_RX_IRQ NVIC_DMA1_CHANNEL5_IRQ
|
||||||
|
#define USBUSART1_DMA_RX_ISR(x) dma1_channel5_isr(x)
|
||||||
|
|
||||||
|
#define USBUSART2 USART2
|
||||||
|
#define USBUSART2_IRQ NVIC_USART2_IRQ
|
||||||
|
#define USBUSART2_ISR(x) usart2_isr(x)
|
||||||
|
#define USBUSART2_DMA_TX_CHAN DMA_CHANNEL7
|
||||||
|
#define USBUSART2_DMA_TX_IRQ NVIC_DMA1_CHANNEL7_IRQ
|
||||||
|
#define USBUSART2_DMA_TX_ISR(x) dma1_channel7_isr(x)
|
||||||
|
#define USBUSART2_DMA_RX_CHAN DMA_CHANNEL6
|
||||||
|
#define USBUSART2_DMA_RX_IRQ NVIC_DMA1_CHANNEL6_IRQ
|
||||||
|
#define USBUSART2_DMA_RX_ISR(x) dma1_channel6_isr(x)
|
||||||
|
|
||||||
#define TRACE_TIM TIM3
|
#define TRACE_TIM TIM3
|
||||||
#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3)
|
#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3)
|
||||||
#define TRACE_IRQ NVIC_TIM3_IRQ
|
#define TRACE_IRQ NVIC_TIM3_IRQ
|
||||||
#define TRACE_ISR tim3_isr
|
#define TRACE_ISR(x) tim3_isr(x)
|
||||||
|
|
||||||
#define SET_RUN_STATE(state) {running_status = (state);}
|
#define SET_RUN_STATE(state) {running_status = (state);}
|
||||||
#define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, LED_IDLE_RUN, state);}
|
#define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, LED_IDLE_RUN, state);}
|
||||||
|
@ -42,9 +42,9 @@ int main(void)
|
|||||||
if(gpio_get(GPIOB, GPIO12))
|
if(gpio_get(GPIOB, GPIO12))
|
||||||
dfu_jump_app_if_valid();
|
dfu_jump_app_if_valid();
|
||||||
|
|
||||||
dfu_protect(DFU_MODE);
|
dfu_protect(false);
|
||||||
|
|
||||||
rcc_clock_setup_in_hse_8mhz_out_72mhz();
|
rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]);
|
||||||
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
|
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
|
||||||
systick_set_reload(900000);
|
systick_set_reload(900000);
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ int main(void)
|
|||||||
gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ,
|
gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ,
|
||||||
GPIO_CNF_OUTPUT_PUSHPULL, LED_0 | LED_1 | LED_2);
|
GPIO_CNF_OUTPUT_PUSHPULL, LED_0 | LED_1 | LED_2);
|
||||||
|
|
||||||
dfu_init(&st_usbfs_v1_usb_driver, DFU_MODE);
|
dfu_init(&st_usbfs_v1_usb_driver);
|
||||||
|
|
||||||
/* Configure the USB pull up pin. */
|
/* Configure the USB pull up pin. */
|
||||||
gpio_set(GPIOA, GPIO8);
|
gpio_set(GPIOA, GPIO8);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2019 - 2020 Uwe Bonnes
|
* Copyright (C) 2019 - 2021 Uwe Bonnes
|
||||||
* (bon@elektron.ikp.physik.tu-darmstadt.de)
|
* (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -24,15 +24,17 @@
|
|||||||
|
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include "version.h"
|
||||||
#include "target.h"
|
|
||||||
#include "target_internal.h"
|
#include "target_internal.h"
|
||||||
|
#include "cortexm.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
#include "cl_utils.h"
|
#include "cl_utils.h"
|
||||||
|
#include "bmp_hosted.h"
|
||||||
|
|
||||||
#ifndef O_BINARY
|
#ifndef O_BINARY
|
||||||
#define O_BINARY 0
|
#define O_BINARY 0
|
||||||
@ -43,6 +45,18 @@
|
|||||||
# include <sys/mman.h>
|
# include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void cl_target_printf(struct target_controller *tc,
|
||||||
|
const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
(void)tc;
|
||||||
|
|
||||||
|
vprintf(fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct target_controller cl_controller = {
|
||||||
|
.printf = cl_target_printf,
|
||||||
|
};
|
||||||
|
|
||||||
struct mmap_data {
|
struct mmap_data {
|
||||||
void *data;
|
void *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
@ -113,17 +127,21 @@ static void bmp_munmap(struct mmap_data *map)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cl_help(char **argv, BMP_CL_OPTIONS_t *opt)
|
static void cl_help(char **argv)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("%s for: \n", opt->opt_idstring);
|
bmp_ident(NULL);
|
||||||
DEBUG_WARN("\tBMP Firmware, ST-Link V2/3, CMSIS_DAP, JLINK and "
|
|
||||||
"LIBFTDI/MPSSE\n\n");
|
|
||||||
DEBUG_WARN("Usage: %s [options]\n", argv[0]);
|
DEBUG_WARN("Usage: %s [options]\n", argv[0]);
|
||||||
DEBUG_WARN("\t-h\t\t: This help.\n");
|
DEBUG_WARN("\t-h\t\t: This help.\n");
|
||||||
DEBUG_WARN("\t-v[bitmask]\t: Increasing verbosity. Bitmask:\n");
|
DEBUG_WARN("\t-v[bitmask]\t: Increasing verbosity. Bitmask:\n");
|
||||||
DEBUG_WARN("\t\t\t 1 = INFO, 2 = GDB, 4 = TARGET, 8 = PROBE, 16 = WIRE\n");
|
DEBUG_WARN("\t\t\t 1 = INFO, 2 = GDB, 4 = TARGET, 8 = PROBE, 16 = WIRE\n");
|
||||||
|
DEBUG_WARN("\t-l\t\t: List available probes\n");
|
||||||
DEBUG_WARN("Probe selection arguments:\n");
|
DEBUG_WARN("Probe selection arguments:\n");
|
||||||
DEBUG_WARN("\t-d \"path\"\t: Use serial device at \"path\"\n");
|
DEBUG_WARN("\t-d \"path\"\t: Use serial BMP device at <path>");
|
||||||
|
#if HOSTED_BMP_ONLY == 1 && defined(__APPLE__)
|
||||||
|
DEBUG_WARN("\n");
|
||||||
|
#else
|
||||||
|
DEBUG_WARN(". Deprecated!\n");
|
||||||
|
#endif
|
||||||
DEBUG_WARN("\t-P <pos>\t: Use debugger found at position <pos>\n");
|
DEBUG_WARN("\t-P <pos>\t: Use debugger found at position <pos>\n");
|
||||||
DEBUG_WARN("\t-n <num>\t: Use target device found at position <num>\n");
|
DEBUG_WARN("\t-n <num>\t: Use target device found at position <num>\n");
|
||||||
DEBUG_WARN("\t-s \"serial\"\t: Use dongle with (partial) "
|
DEBUG_WARN("\t-s \"serial\"\t: Use dongle with (partial) "
|
||||||
@ -133,16 +151,25 @@ static void cl_help(char **argv, BMP_CL_OPTIONS_t *opt)
|
|||||||
DEBUG_WARN("Run mode related options:\n");
|
DEBUG_WARN("Run mode related options:\n");
|
||||||
DEBUG_WARN("\tDefault mode is to start the debug server at :2000\n");
|
DEBUG_WARN("\tDefault mode is to start the debug server at :2000\n");
|
||||||
DEBUG_WARN("\t-j\t\t: Use JTAG. SWD is default.\n");
|
DEBUG_WARN("\t-j\t\t: Use JTAG. SWD is default.\n");
|
||||||
DEBUG_WARN("\t-C\t\t: Connect under reset\n");
|
DEBUG_WARN("\t-f\t\t: Set minimum high and low times of SWJ waveform.\n");
|
||||||
|
DEBUG_WARN("\t-C\t\t: Connect under hardware reset\n");
|
||||||
DEBUG_WARN("\t-t\t\t: Scan SWD or JTAG and display information about \n"
|
DEBUG_WARN("\t-t\t\t: Scan SWD or JTAG and display information about \n"
|
||||||
"\t\t\t connected devices\n");
|
"\t\t\t connected devices\n");
|
||||||
|
DEBUG_WARN("\t-T\t\t: Continuous read/write-back some value to allow\n"
|
||||||
|
"\t\t\t timing insection of SWJ. Abort with ^C\n");
|
||||||
DEBUG_WARN("\t-e\t\t: Assume \"resistor SWD connection\" on FTDI: TDI\n"
|
DEBUG_WARN("\t-e\t\t: Assume \"resistor SWD connection\" on FTDI: TDI\n"
|
||||||
"\t\t\t connected to TMS, TDO to TDI with eventual resistor\n");
|
"\t\t\t connected to TMS, TDO to TDI with eventual resistor\n");
|
||||||
DEBUG_WARN("\t-E\t\t: Erase flash until flash end or for given size\n");
|
DEBUG_WARN("\t-E\t\t: Erase flash until flash end or for given size\n");
|
||||||
DEBUG_WARN("\t-V\t\t: Verify flash against binary file\n");
|
DEBUG_WARN("\t-w\t\t: Write binary file to target flash (default).\n");
|
||||||
|
DEBUG_WARN("\t-V\t\t: Verify flash against binary file. Can be combined\n"
|
||||||
|
"\t\t\t with -w to verify right after programming.\n");
|
||||||
DEBUG_WARN("\t-r\t\t: Read flash and write to binary file\n");
|
DEBUG_WARN("\t-r\t\t: Read flash and write to binary file\n");
|
||||||
DEBUG_WARN("\t-p\t\t: Supplies power to the target (where applicable)\n");
|
DEBUG_WARN("\t-p\t\t: Supplies power to the target (where applicable)\n");
|
||||||
DEBUG_WARN("\t-R\t\t: Reset device\n");
|
DEBUG_WARN("\t-R[h]\t\t: Reset device. Default via SWJ or by hardware(h)\n");
|
||||||
|
DEBUG_WARN("\t-H\t\t: Do not use high level commands (BMP-Remote)\n");
|
||||||
|
DEBUG_WARN("\t-m <target>\t: Use (target)id for SWD multi-drop.\n");
|
||||||
|
DEBUG_WARN("\t-M <string>\t: Run target specific monitor commands. Quote multi\n");
|
||||||
|
DEBUG_WARN("\t\t\t word strings. Run \"-M help\" for help.\n");
|
||||||
DEBUG_WARN("Flash operation modifiers options:\n");
|
DEBUG_WARN("Flash operation modifiers options:\n");
|
||||||
DEBUG_WARN("\tDefault action with given file is to write to flash\n");
|
DEBUG_WARN("\tDefault action with given file is to write to flash\n");
|
||||||
DEBUG_WARN("\t-a <addr>\t: Start flash operation at flash address <addr>\n"
|
DEBUG_WARN("\t-a <addr>\t: Start flash operation at flash address <addr>\n"
|
||||||
@ -156,15 +183,21 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
opt->opt_target_dev = 1;
|
opt->opt_target_dev = 1;
|
||||||
opt->opt_flash_size = 16 * 1024 *1024;
|
opt->opt_flash_size = 0xffffffff;
|
||||||
while((c = getopt(argc, argv, "eEhv:d:s:I:c:CnltVta:S:jpP:rR")) != -1) {
|
opt->opt_flash_start = 0xffffffff;
|
||||||
|
opt->opt_max_swj_frequency = 4000000;
|
||||||
|
while((c = getopt(argc, argv, "eEhHv:d:f:s:I:c:Cln:m:M:wVtTa:S:jpP:rR::")) != -1) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'c':
|
case 'c':
|
||||||
if (optarg)
|
if (optarg)
|
||||||
opt->opt_cable = optarg;
|
opt->opt_cable = optarg;
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
cl_help(argv, opt);
|
cl_debuglevel = 3;
|
||||||
|
cl_help(argv);
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
opt->opt_no_hl = true;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
if (optarg)
|
if (optarg)
|
||||||
@ -187,6 +220,21 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||||||
if (optarg)
|
if (optarg)
|
||||||
opt->opt_device = optarg;
|
opt->opt_device = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
if (optarg) {
|
||||||
|
char *p;
|
||||||
|
uint32_t frequency = strtol(optarg, &p, 10);
|
||||||
|
switch(*p) {
|
||||||
|
case 'k':
|
||||||
|
frequency *= 1000;
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
frequency *= 1000*1000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
opt->opt_max_swj_frequency = frequency;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
if (optarg)
|
if (optarg)
|
||||||
opt->opt_serial = optarg;
|
opt->opt_serial = optarg;
|
||||||
@ -202,14 +250,29 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||||||
opt->opt_mode = BMP_MODE_TEST;
|
opt->opt_mode = BMP_MODE_TEST;
|
||||||
cl_debuglevel |= BMP_DEBUG_INFO | BMP_DEBUG_STDOUT;
|
cl_debuglevel |= BMP_DEBUG_INFO | BMP_DEBUG_STDOUT;
|
||||||
break;
|
break;
|
||||||
|
case 'T':
|
||||||
|
opt->opt_mode = BMP_MODE_SWJ_TEST;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
if (opt->opt_mode == BMP_MODE_FLASH_VERIFY)
|
||||||
|
opt->opt_mode = BMP_MODE_FLASH_WRITE_VERIFY;
|
||||||
|
else
|
||||||
|
opt->opt_mode = BMP_MODE_FLASH_WRITE;
|
||||||
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
opt->opt_mode = BMP_MODE_FLASH_VERIFY;
|
if (opt->opt_mode == BMP_MODE_FLASH_WRITE)
|
||||||
|
opt->opt_mode = BMP_MODE_FLASH_WRITE_VERIFY;
|
||||||
|
else
|
||||||
|
opt->opt_mode = BMP_MODE_FLASH_VERIFY;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
opt->opt_mode = BMP_MODE_FLASH_READ;
|
opt->opt_mode = BMP_MODE_FLASH_READ;
|
||||||
break;
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
opt->opt_mode = BMP_MODE_RESET;
|
if ((optarg) && (tolower(optarg[0]) == 'h'))
|
||||||
|
opt->opt_mode = BMP_MODE_RESET_HW;
|
||||||
|
else
|
||||||
|
opt->opt_mode = BMP_MODE_RESET;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
opt->opt_tpwr = true;
|
opt->opt_tpwr = true;
|
||||||
@ -222,6 +285,14 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||||||
if (optarg)
|
if (optarg)
|
||||||
opt->opt_target_dev = strtol(optarg, NULL, 0);
|
opt->opt_target_dev = strtol(optarg, NULL, 0);
|
||||||
break;
|
break;
|
||||||
|
case 'm':
|
||||||
|
if (optarg)
|
||||||
|
opt->opt_targetid = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
if (optarg)
|
||||||
|
opt->opt_monitor = optarg;
|
||||||
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
if (optarg)
|
if (optarg)
|
||||||
opt->opt_position = atoi(optarg);
|
opt->opt_position = atoi(optarg);
|
||||||
@ -249,10 +320,16 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||||||
if (opt->opt_mode == BMP_MODE_DEBUG)
|
if (opt->opt_mode == BMP_MODE_DEBUG)
|
||||||
opt->opt_mode = BMP_MODE_FLASH_WRITE;
|
opt->opt_mode = BMP_MODE_FLASH_WRITE;
|
||||||
opt->opt_flash_file = argv[optind];
|
opt->opt_flash_file = argv[optind];
|
||||||
|
} else if ((opt->opt_mode == BMP_MODE_DEBUG) &&
|
||||||
|
(opt->opt_monitor)) {
|
||||||
|
opt->opt_mode = BMP_MODE_MONITOR; // To avoid DEBUG mode
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checks */
|
/* Checks */
|
||||||
if ((opt->opt_flash_file) && ((opt->opt_mode == BMP_MODE_TEST ) ||
|
if ((opt->opt_flash_file) && ((opt->opt_mode == BMP_MODE_TEST ) ||
|
||||||
(opt->opt_mode == BMP_MODE_RESET))) {
|
(opt->opt_mode == BMP_MODE_SWJ_TEST) ||
|
||||||
|
(opt->opt_mode == BMP_MODE_RESET) ||
|
||||||
|
(opt->opt_mode == BMP_MODE_RESET_HW))) {
|
||||||
DEBUG_WARN("Ignoring filename in reset/test mode\n");
|
DEBUG_WARN("Ignoring filename in reset/test mode\n");
|
||||||
opt->opt_flash_file = NULL;
|
opt->opt_flash_file = NULL;
|
||||||
}
|
}
|
||||||
@ -261,104 +338,131 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||||||
static void display_target(int i, target *t, void *context)
|
static void display_target(int i, target *t, void *context)
|
||||||
{
|
{
|
||||||
(void)context;
|
(void)context;
|
||||||
DEBUG_INFO("*** %2d %c %s %s\n", i, target_attached(t)?'*':' ',
|
if (!strcmp(target_driver_name(t), "ARM Cortex-M")) {
|
||||||
target_driver_name(t),
|
DEBUG_INFO("***%2d%sUnknown %s Designer %3x Partno %3x %s\n",
|
||||||
(target_core_name(t)) ? target_core_name(t): "");
|
i, target_attached(t)?" * ":" ",
|
||||||
|
target_driver_name(t),
|
||||||
|
target_designer(t),
|
||||||
|
target_idcode(t),
|
||||||
|
(target_core_name(t)) ? target_core_name(t): "");
|
||||||
|
} else {
|
||||||
|
DEBUG_INFO("*** %2d %c %s %s\n", i, target_attached(t)?'*':' ',
|
||||||
|
target_driver_name(t),
|
||||||
|
(target_core_name(t)) ? target_core_name(t): "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int cl_execute(BMP_CL_OPTIONS_t *opt)
|
int cl_execute(BMP_CL_OPTIONS_t *opt)
|
||||||
{
|
{
|
||||||
int res = -1;
|
int res = 0;
|
||||||
int num_targets;
|
int num_targets;
|
||||||
#if defined(PLATFORM_HAS_POWER_SWITCH)
|
|
||||||
if (opt->opt_tpwr) {
|
if (opt->opt_tpwr) {
|
||||||
DEBUG_INFO("Powering up device");
|
|
||||||
platform_target_set_power(true);
|
platform_target_set_power(true);
|
||||||
platform_delay(500);
|
platform_delay(500);
|
||||||
}
|
}
|
||||||
#endif
|
if (opt->opt_mode == BMP_MODE_RESET_HW) {
|
||||||
|
platform_srst_set_val(true);
|
||||||
|
platform_delay(1);
|
||||||
|
platform_srst_set_val(false);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
if (opt->opt_connect_under_reset)
|
if (opt->opt_connect_under_reset)
|
||||||
DEBUG_INFO("Connecting under reset\n");
|
DEBUG_INFO("Connecting under reset\n");
|
||||||
connect_assert_srst = opt->opt_connect_under_reset;
|
connect_assert_srst = opt->opt_connect_under_reset;
|
||||||
platform_srst_set_val(opt->opt_connect_under_reset);
|
platform_srst_set_val(opt->opt_connect_under_reset);
|
||||||
if (opt->opt_mode == BMP_MODE_TEST)
|
if (opt->opt_mode == BMP_MODE_TEST)
|
||||||
DEBUG_INFO("Running in Test Mode\n");
|
DEBUG_INFO("Running in Test Mode\n");
|
||||||
if (platform_target_voltage())
|
DEBUG_INFO("Target voltage: %s Volt\n", platform_target_voltage());
|
||||||
DEBUG_INFO("Target voltage: %s Volt\n", platform_target_voltage());
|
|
||||||
if (opt->opt_usejtag) {
|
if (opt->opt_usejtag) {
|
||||||
num_targets = platform_jtag_scan(NULL);
|
num_targets = platform_jtag_scan(NULL);
|
||||||
} else {
|
} else {
|
||||||
num_targets = platform_adiv5_swdp_scan();
|
num_targets = platform_adiv5_swdp_scan(opt->opt_targetid);
|
||||||
|
if (!num_targets) {
|
||||||
|
DEBUG_INFO("Scan SWD failed, trying JTAG!\n");
|
||||||
|
num_targets = platform_jtag_scan(NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!num_targets) {
|
if (!num_targets) {
|
||||||
DEBUG_WARN("No target found\n");
|
DEBUG_WARN("No target found\n");
|
||||||
return res;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
target_foreach(display_target, NULL);
|
num_targets = target_foreach(display_target, &num_targets);
|
||||||
}
|
}
|
||||||
if (opt->opt_target_dev > num_targets) {
|
if (opt->opt_target_dev > num_targets) {
|
||||||
DEBUG_WARN("Given target nummer %d not available\n",
|
DEBUG_WARN("Given target number %d not available max %d\n",
|
||||||
opt->opt_target_dev);
|
opt->opt_target_dev, num_targets);
|
||||||
return res;
|
return -1;
|
||||||
}
|
}
|
||||||
target *t = target_attach_n(opt->opt_target_dev, NULL);
|
target *t = target_attach_n(opt->opt_target_dev, &cl_controller);
|
||||||
|
|
||||||
if (!t) {
|
if (!t) {
|
||||||
DEBUG_WARN("Can not attach to target %d\n", opt->opt_target_dev);
|
DEBUG_WARN("Can not attach to target %d\n", opt->opt_target_dev);
|
||||||
|
res = -1;
|
||||||
goto target_detach;
|
goto target_detach;
|
||||||
}
|
}
|
||||||
|
/* List each defined RAM */
|
||||||
|
int n_ram = 0;
|
||||||
|
for (struct target_ram *r = t->ram; r; r = r->next)
|
||||||
|
n_ram++;
|
||||||
|
for (int n = n_ram; n >= 0; n --) {
|
||||||
|
struct target_ram *r = t->ram;
|
||||||
|
for (int i = 1; r; r = r->next, i++)
|
||||||
|
if (i == n)
|
||||||
|
DEBUG_INFO("RAM Start: 0x%08" PRIx32 " length = 0x%" PRIx32 "\n",
|
||||||
|
r->start, (uint32_t)r->length);
|
||||||
|
}
|
||||||
/* Always scan memory map to find lowest flash */
|
/* Always scan memory map to find lowest flash */
|
||||||
char memory_map [1024], *p = memory_map;
|
/* List each defined Flash */
|
||||||
uint32_t flash_start = 0xffffffff;
|
uint32_t lowest_flash_start = 0xffffffff;
|
||||||
if (target_mem_map(t, memory_map, sizeof(memory_map))) {
|
uint32_t lowest_flash_size = 0;
|
||||||
while (*p && (*p == '<')) {
|
int n_flash = 0;
|
||||||
unsigned int start, size;
|
for (struct target_flash *f = t->flash; f; f = f->next)
|
||||||
char *res;
|
n_flash++;
|
||||||
int match;
|
for (int n = n_flash; n >= 0; n --) {
|
||||||
match = strncmp(p, "<memory-map>", strlen("<memory-map>"));
|
struct target_flash *f = t->flash;
|
||||||
if (!match) {
|
for (int i = 1; f; f = f->next, i++)
|
||||||
p += strlen("<memory-map>");
|
if (i == n) {
|
||||||
continue;
|
DEBUG_INFO("Flash Start: 0x%08" PRIx32 " length = 0x%" PRIx32
|
||||||
}
|
" blocksize 0x%" PRIx32 "\n",
|
||||||
match = strncmp(p, "<memory type=\"flash\" ", strlen("<memory type=\"flash\" "));
|
f->start, (uint32_t)f->length, (uint32_t)f->blocksize);
|
||||||
if (!match) {
|
if (f->start < lowest_flash_start) {
|
||||||
unsigned int blocksize;
|
lowest_flash_start = f->start;
|
||||||
if (sscanf(p, "<memory type=\"flash\" start=\"%x\" length=\"%x\">"
|
lowest_flash_size = f->length;
|
||||||
"<property name=\"blocksize\">%x</property></memory>",
|
|
||||||
&start, &size, &blocksize)) {
|
|
||||||
if (opt->opt_mode == BMP_MODE_TEST)
|
|
||||||
DEBUG_INFO("Flash Start: 0x%08x, length %#9x, "
|
|
||||||
"blocksize %#8x\n", start, size, blocksize);
|
|
||||||
if (start < flash_start)
|
|
||||||
flash_start = start;
|
|
||||||
}
|
}
|
||||||
res = strstr(p, "</memory>");
|
|
||||||
p = res + strlen("</memory>");
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
match = strncmp(p, "<memory type=\"ram\" ", strlen("<memory type=\"ram\" "));
|
}
|
||||||
if (!match) {
|
if (opt->opt_flash_start == 0xffffffff)
|
||||||
if (sscanf(p, "<memory type=\"ram\" start=\"%x\" length=\"%x\"/",
|
opt->opt_flash_start = lowest_flash_start;
|
||||||
&start, &size))
|
if ((opt->opt_flash_size == 0xffffffff) &&
|
||||||
if (opt->opt_mode == BMP_MODE_TEST)
|
(opt->opt_mode != BMP_MODE_FLASH_WRITE) &&
|
||||||
DEBUG_INFO("Ram Start: 0x%08x, length %#9x\n",
|
(opt->opt_mode != BMP_MODE_FLASH_VERIFY) &&
|
||||||
start, size);
|
(opt->opt_mode != BMP_MODE_FLASH_WRITE_VERIFY))
|
||||||
res = strstr(p, "/>");
|
opt->opt_flash_size = lowest_flash_size;
|
||||||
p = res + strlen("/>");
|
if (opt->opt_mode == BMP_MODE_SWJ_TEST) {
|
||||||
continue;
|
switch (t->core[0]) {
|
||||||
|
case 'M':
|
||||||
|
DEBUG_WARN("Continuous read/write-back DEMCR. Abort with ^C\n");
|
||||||
|
while(1) {
|
||||||
|
uint32_t demcr;
|
||||||
|
target_mem_read(t, &demcr, CORTEXM_DEMCR, 4);
|
||||||
|
target_mem_write32(t, CORTEXM_DEMCR, demcr);
|
||||||
|
platform_delay(1); /* To allow trigger*/
|
||||||
}
|
}
|
||||||
break;
|
default:
|
||||||
|
DEBUG_WARN("No test for this core type yet\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (opt->opt_flash_start < flash_start)
|
if ((opt->opt_mode == BMP_MODE_TEST) ||
|
||||||
opt->opt_flash_start = flash_start;
|
(opt->opt_mode == BMP_MODE_SWJ_TEST))
|
||||||
if (opt->opt_mode == BMP_MODE_TEST)
|
|
||||||
goto target_detach;
|
goto target_detach;
|
||||||
int read_file = -1;
|
int read_file = -1;
|
||||||
if ((opt->opt_mode == BMP_MODE_FLASH_WRITE) ||
|
if ((opt->opt_mode == BMP_MODE_FLASH_WRITE) ||
|
||||||
(opt->opt_mode == BMP_MODE_FLASH_VERIFY)) {
|
(opt->opt_mode == BMP_MODE_FLASH_VERIFY) ||
|
||||||
|
(opt->opt_mode == BMP_MODE_FLASH_WRITE_VERIFY)) {
|
||||||
int mmap_res = bmp_mmap(opt->opt_flash_file, &map);
|
int mmap_res = bmp_mmap(opt->opt_flash_file, &map);
|
||||||
if (mmap_res) {
|
if (mmap_res) {
|
||||||
DEBUG_WARN("Can not map file: %s. Aborting!\n", strerror(errno));
|
DEBUG_WARN("Can not map file: %s. Aborting!\n", strerror(errno));
|
||||||
|
res = -1;
|
||||||
goto target_detach;
|
goto target_detach;
|
||||||
}
|
}
|
||||||
} else if (opt->opt_mode == BMP_MODE_FLASH_READ) {
|
} else if (opt->opt_mode == BMP_MODE_FLASH_READ) {
|
||||||
@ -368,12 +472,18 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||||||
if (read_file == -1) {
|
if (read_file == -1) {
|
||||||
DEBUG_WARN("Error opening flashfile %s for read: %s\n",
|
DEBUG_WARN("Error opening flashfile %s for read: %s\n",
|
||||||
opt->opt_flash_file, strerror(errno));
|
opt->opt_flash_file, strerror(errno));
|
||||||
return res;
|
res = -1;
|
||||||
|
goto target_detach;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (opt->opt_flash_size < map.size)
|
if (opt->opt_flash_size < map.size)
|
||||||
/* restrict to size given on command line */
|
/* restrict to size given on command line */
|
||||||
map.size = opt->opt_flash_size;
|
map.size = opt->opt_flash_size;
|
||||||
|
if (opt->opt_monitor) {
|
||||||
|
res = command_process(t, opt->opt_monitor);
|
||||||
|
if (res)
|
||||||
|
DEBUG_WARN("Command \"%s\" failed\n", opt->opt_monitor);
|
||||||
|
}
|
||||||
if (opt->opt_mode == BMP_MODE_RESET) {
|
if (opt->opt_mode == BMP_MODE_RESET) {
|
||||||
target_reset(t);
|
target_reset(t);
|
||||||
} else if (opt->opt_mode == BMP_MODE_FLASH_ERASE) {
|
} else if (opt->opt_mode == BMP_MODE_FLASH_ERASE) {
|
||||||
@ -382,18 +492,21 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||||||
unsigned int erased = target_flash_erase(t, opt->opt_flash_start,
|
unsigned int erased = target_flash_erase(t, opt->opt_flash_start,
|
||||||
opt->opt_flash_size);
|
opt->opt_flash_size);
|
||||||
if (erased) {
|
if (erased) {
|
||||||
DEBUG_WARN("Erased failed!\n");
|
DEBUG_WARN("Erasure failed!\n");
|
||||||
|
res = -1;
|
||||||
goto free_map;
|
goto free_map;
|
||||||
}
|
}
|
||||||
target_reset(t);
|
target_reset(t);
|
||||||
} else if (opt->opt_mode == BMP_MODE_FLASH_WRITE) {
|
} else if ((opt->opt_mode == BMP_MODE_FLASH_WRITE) ||
|
||||||
|
(opt->opt_mode == BMP_MODE_FLASH_WRITE_VERIFY)) {
|
||||||
DEBUG_INFO("Erase %zu bytes at 0x%08" PRIx32 "\n", map.size,
|
DEBUG_INFO("Erase %zu bytes at 0x%08" PRIx32 "\n", map.size,
|
||||||
opt->opt_flash_start);
|
opt->opt_flash_start);
|
||||||
uint32_t start_time = platform_time_ms();
|
uint32_t start_time = platform_time_ms();
|
||||||
unsigned int erased = target_flash_erase(t, opt->opt_flash_start,
|
unsigned int erased = target_flash_erase(t, opt->opt_flash_start,
|
||||||
map.size);
|
map.size);
|
||||||
if (erased) {
|
if (erased) {
|
||||||
DEBUG_WARN("Erased failed!\n");
|
DEBUG_WARN("Erasure failed!\n");
|
||||||
|
res = -1;
|
||||||
goto free_map;
|
goto free_map;
|
||||||
} else {
|
} else {
|
||||||
DEBUG_INFO("Flashing %zu bytes at 0x%08" PRIx32 "\n",
|
DEBUG_INFO("Flashing %zu bytes at 0x%08" PRIx32 "\n",
|
||||||
@ -401,25 +514,34 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||||||
unsigned int flashed = target_flash_write(t, opt->opt_flash_start,
|
unsigned int flashed = target_flash_write(t, opt->opt_flash_start,
|
||||||
map.data, map.size);
|
map.data, map.size);
|
||||||
/* Buffered write cares for padding*/
|
/* Buffered write cares for padding*/
|
||||||
|
if (!flashed)
|
||||||
|
flashed = target_flash_done(t);
|
||||||
if (flashed) {
|
if (flashed) {
|
||||||
DEBUG_WARN("Flashing failed!\n");
|
DEBUG_WARN("Flashing failed!\n");
|
||||||
|
res = -1;
|
||||||
|
goto free_map;
|
||||||
} else {
|
} else {
|
||||||
DEBUG_INFO("Success!\n");
|
DEBUG_INFO("Success!\n");
|
||||||
res = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
target_flash_done(t);
|
|
||||||
target_reset(t);
|
|
||||||
uint32_t end_time = platform_time_ms();
|
uint32_t end_time = platform_time_ms();
|
||||||
DEBUG_WARN("Flash Write succeeded for %d bytes, %8.3f kiB/s\n",
|
DEBUG_WARN("Flash Write succeeded for %d bytes, %8.3f kiB/s\n",
|
||||||
(int)map.size, (((map.size * 1.0)/(end_time - start_time))));
|
(int)map.size, (((map.size * 1.0)/(end_time - start_time))));
|
||||||
} else {
|
if (opt->opt_mode != BMP_MODE_FLASH_WRITE_VERIFY) {
|
||||||
#define WORKSIZE 1024
|
target_reset(t);
|
||||||
|
goto free_map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((opt->opt_mode == BMP_MODE_FLASH_READ) ||
|
||||||
|
(opt->opt_mode == BMP_MODE_FLASH_VERIFY) ||
|
||||||
|
(opt->opt_mode == BMP_MODE_FLASH_WRITE_VERIFY)) {
|
||||||
|
#define WORKSIZE 0x1000
|
||||||
uint8_t *data = alloca(WORKSIZE);
|
uint8_t *data = alloca(WORKSIZE);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
DEBUG_WARN("Can not malloc memory for flash read/verify "
|
DEBUG_WARN("Can not malloc memory for flash read/verify "
|
||||||
"operation\n");
|
"operation\n");
|
||||||
return res;
|
res = -1;
|
||||||
|
goto free_map;
|
||||||
}
|
}
|
||||||
if (opt->opt_mode == BMP_MODE_FLASH_READ)
|
if (opt->opt_mode == BMP_MODE_FLASH_READ)
|
||||||
DEBUG_INFO("Reading flash from 0x%08" PRIx32 " for %zu"
|
DEBUG_INFO("Reading flash from 0x%08" PRIx32 " for %zu"
|
||||||
@ -447,12 +569,14 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||||||
} else {
|
} else {
|
||||||
bytes_read += worksize;
|
bytes_read += worksize;
|
||||||
}
|
}
|
||||||
if (opt->opt_mode == BMP_MODE_FLASH_VERIFY) {
|
if ((opt->opt_mode == BMP_MODE_FLASH_VERIFY) ||
|
||||||
|
(opt->opt_mode == BMP_MODE_FLASH_WRITE_VERIFY)) {
|
||||||
int difference = memcmp(data, flash, worksize);
|
int difference = memcmp(data, flash, worksize);
|
||||||
if (difference){
|
if (difference){
|
||||||
DEBUG_WARN("Verify failed at flash region 0x%08"
|
DEBUG_WARN("Verify failed at flash region 0x%08"
|
||||||
PRIx32 "\n", flash_src);
|
PRIx32 "\n", flash_src);
|
||||||
return -1;
|
res = -1;
|
||||||
|
goto free_map;
|
||||||
}
|
}
|
||||||
flash += worksize;
|
flash += worksize;
|
||||||
} else if (read_file != -1) {
|
} else if (read_file != -1) {
|
||||||
@ -460,19 +584,21 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||||||
if (written < worksize) {
|
if (written < worksize) {
|
||||||
DEBUG_WARN("Read failed at flash region 0x%08" PRIx32 "\n",
|
DEBUG_WARN("Read failed at flash region 0x%08" PRIx32 "\n",
|
||||||
flash_src);
|
flash_src);
|
||||||
return -1;
|
res = -1;
|
||||||
|
goto free_map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flash_src += worksize;
|
flash_src += worksize;
|
||||||
size -= worksize;
|
size -= worksize;
|
||||||
if (size <= 0)
|
|
||||||
res = 0;
|
|
||||||
}
|
}
|
||||||
uint32_t end_time = platform_time_ms();
|
uint32_t end_time = platform_time_ms();
|
||||||
if (read_file != -1)
|
if (read_file != -1)
|
||||||
close(read_file);
|
close(read_file);
|
||||||
DEBUG_WARN("Read/Verify succeeded for %d bytes, %8.3f kiB/s\n",
|
DEBUG_WARN("Read/Verify succeeded for %d bytes, %8.3f kiB/s\n",
|
||||||
bytes_read, (((bytes_read * 1.0)/(end_time - start_time))));
|
bytes_read,
|
||||||
|
(((bytes_read * 1.0)/(end_time - start_time))));
|
||||||
|
if (opt->opt_mode == BMP_MODE_FLASH_WRITE_VERIFY)
|
||||||
|
target_reset(t);
|
||||||
}
|
}
|
||||||
free_map:
|
free_map:
|
||||||
if (map.size)
|
if (map.size)
|
||||||
@ -480,5 +606,6 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||||||
target_detach:
|
target_detach:
|
||||||
if (t)
|
if (t)
|
||||||
target_detach(t);
|
target_detach(t);
|
||||||
|
target_list_free();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2019 - 2020 Uwe Bonnes
|
* Copyright (C) 2019 - 2021 Uwe Bonnes
|
||||||
* Written by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
* Written by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -24,16 +24,20 @@
|
|||||||
#if !defined(__CL_UTILS_H)
|
#if !defined(__CL_UTILS_H)
|
||||||
#define __CL_UTILS_H
|
#define __CL_UTILS_H
|
||||||
|
|
||||||
#define RESP_TIMEOUT (100)
|
#include "cortexm.h"
|
||||||
|
|
||||||
enum bmp_cl_mode {
|
enum bmp_cl_mode {
|
||||||
BMP_MODE_DEBUG,
|
BMP_MODE_DEBUG,
|
||||||
BMP_MODE_TEST,
|
BMP_MODE_TEST,
|
||||||
BMP_MODE_RESET,
|
BMP_MODE_RESET,
|
||||||
|
BMP_MODE_RESET_HW,
|
||||||
BMP_MODE_FLASH_ERASE,
|
BMP_MODE_FLASH_ERASE,
|
||||||
BMP_MODE_FLASH_WRITE,
|
BMP_MODE_FLASH_WRITE,
|
||||||
|
BMP_MODE_FLASH_WRITE_VERIFY,
|
||||||
BMP_MODE_FLASH_READ,
|
BMP_MODE_FLASH_READ,
|
||||||
BMP_MODE_FLASH_VERIFY
|
BMP_MODE_FLASH_VERIFY,
|
||||||
|
BMP_MODE_SWJ_TEST,
|
||||||
|
BMP_MODE_MONITOR,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct BMP_CL_OPTIONS_s {
|
typedef struct BMP_CL_OPTIONS_s {
|
||||||
@ -43,17 +47,20 @@ typedef struct BMP_CL_OPTIONS_s {
|
|||||||
bool opt_list_only;
|
bool opt_list_only;
|
||||||
bool opt_connect_under_reset;
|
bool opt_connect_under_reset;
|
||||||
bool external_resistor_swd;
|
bool external_resistor_swd;
|
||||||
|
bool opt_no_hl;
|
||||||
char *opt_flash_file;
|
char *opt_flash_file;
|
||||||
char *opt_device;
|
char *opt_device;
|
||||||
char *opt_serial;
|
char *opt_serial;
|
||||||
|
uint32_t opt_targetid;
|
||||||
char *opt_ident_string;
|
char *opt_ident_string;
|
||||||
int opt_position;
|
int opt_position;
|
||||||
char *opt_cable;
|
char *opt_cable;
|
||||||
|
char *opt_monitor;
|
||||||
int opt_debuglevel;
|
int opt_debuglevel;
|
||||||
int opt_target_dev;
|
int opt_target_dev;
|
||||||
uint32_t opt_flash_start;
|
uint32_t opt_flash_start;
|
||||||
|
uint32_t opt_max_swj_frequency;
|
||||||
size_t opt_flash_size;
|
size_t opt_flash_size;
|
||||||
char *opt_idstring;
|
|
||||||
}BMP_CL_OPTIONS_t;
|
}BMP_CL_OPTIONS_t;
|
||||||
|
|
||||||
void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv);
|
void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv);
|
||||||
|
@ -36,13 +36,11 @@
|
|||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "general.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "general.h"
|
|
||||||
#include "gdb_if.h"
|
#include "gdb_if.h"
|
||||||
|
|
||||||
static int gdb_if_serv, gdb_if_conn;
|
static int gdb_if_serv, gdb_if_conn;
|
||||||
@ -51,8 +49,13 @@ static int gdb_if_serv, gdb_if_conn;
|
|||||||
int gdb_if_init(void)
|
int gdb_if_init(void)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
int iResult;
|
||||||
WSADATA wsaData;
|
WSADATA wsaData;
|
||||||
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||||
|
if (iResult != NO_ERROR) {
|
||||||
|
DEBUG_WARN("WSAStartup failed with error: %ld\n", iResult);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
int opt;
|
int opt;
|
||||||
@ -67,23 +70,47 @@ int gdb_if_init(void)
|
|||||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
|
||||||
gdb_if_serv = socket(PF_INET, SOCK_STREAM, 0);
|
gdb_if_serv = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
if (gdb_if_serv == -1)
|
if (gdb_if_serv == -1) {
|
||||||
|
DEBUG_WARN("PF_INET %d\n",gdb_if_serv);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
opt = 1;
|
opt = 1;
|
||||||
if (setsockopt(gdb_if_serv, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(opt)) == -1) {
|
if (setsockopt(gdb_if_serv, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(opt)) == -1) {
|
||||||
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
DEBUG_WARN("error setsockopt SOL_SOCKET : %d error: %d\n", gdb_if_serv,
|
||||||
|
WSAGetLastError());
|
||||||
|
#else
|
||||||
|
DEBUG_WARN("error setsockopt SOL_SOCKET : %d error: %d\n", gdb_if_serv,
|
||||||
|
strerror(errno));
|
||||||
|
#endif
|
||||||
close(gdb_if_serv);
|
close(gdb_if_serv);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (setsockopt(gdb_if_serv, IPPROTO_TCP, TCP_NODELAY, (void*)&opt, sizeof(opt)) == -1) {
|
if (setsockopt(gdb_if_serv, IPPROTO_TCP, TCP_NODELAY, (void*)&opt, sizeof(opt)) == -1) {
|
||||||
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
DEBUG_WARN("error setsockopt IPPROTO_TCP : %d error: %d\n", gdb_if_serv,
|
||||||
|
WSAGetLastError());
|
||||||
|
#else
|
||||||
|
DEBUG_WARN("error setsockopt IPPROTO_TCP : %d error: %d\n", gdb_if_serv,
|
||||||
|
strerror(errno));
|
||||||
|
#endif
|
||||||
close(gdb_if_serv);
|
close(gdb_if_serv);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (bind(gdb_if_serv, (void*)&addr, sizeof(addr)) == -1) {
|
if (bind(gdb_if_serv, (void*)&addr, sizeof(addr)) == -1) {
|
||||||
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
DEBUG_WARN("error when binding socket: %d error: %d\n", gdb_if_serv,
|
||||||
|
WSAGetLastError());
|
||||||
|
#else
|
||||||
|
DEBUG_WARN("error when binding socket: %d error: %d\n", gdb_if_serv,
|
||||||
|
strerror(errno));
|
||||||
|
#endif
|
||||||
close(gdb_if_serv);
|
close(gdb_if_serv);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (listen(gdb_if_serv, 1) == -1) {
|
if (listen(gdb_if_serv, 1) == -1) {
|
||||||
|
DEBUG_WARN("listen closed %d\n",gdb_if_serv);
|
||||||
close(gdb_if_serv);
|
close(gdb_if_serv);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -100,6 +127,7 @@ unsigned char gdb_if_getchar(void)
|
|||||||
unsigned char ret;
|
unsigned char ret;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
int iResult;
|
||||||
unsigned long opt;
|
unsigned long opt;
|
||||||
#else
|
#else
|
||||||
int flags;
|
int flags;
|
||||||
@ -108,7 +136,10 @@ unsigned char gdb_if_getchar(void)
|
|||||||
if(gdb_if_conn <= 0) {
|
if(gdb_if_conn <= 0) {
|
||||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
opt = 1;
|
opt = 1;
|
||||||
ioctlsocket(gdb_if_serv, FIONBIO, &opt);
|
iResult = ioctlsocket(gdb_if_serv, FIONBIO, &opt);
|
||||||
|
if (iResult != NO_ERROR) {
|
||||||
|
DEBUG_WARN("ioctlsocket failed with error: %ld\n", iResult);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
flags = fcntl(gdb_if_serv, F_GETFL);
|
flags = fcntl(gdb_if_serv, F_GETFL);
|
||||||
fcntl(gdb_if_serv, F_SETFL, flags | O_NONBLOCK);
|
fcntl(gdb_if_serv, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
@ -61,9 +61,7 @@ extern "C" {
|
|||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <general.h>
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include "hidapi.h"
|
#include "hidapi.h"
|
||||||
|
|
||||||
|
@ -1,138 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Black Magic Debug project.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#include "general.h"
|
|
||||||
#include "cl_utils.h"
|
|
||||||
|
|
||||||
static void LIBUSB_CALL on_trans_done(struct libusb_transfer *trans)
|
|
||||||
{
|
|
||||||
struct trans_ctx * const ctx = trans->user_data;
|
|
||||||
|
|
||||||
if (trans->status != LIBUSB_TRANSFER_COMPLETED)
|
|
||||||
{
|
|
||||||
DEBUG_WARN("on_trans_done: ");
|
|
||||||
if(trans->status == LIBUSB_TRANSFER_TIMED_OUT) {
|
|
||||||
DEBUG_WARN(" Timeout\n");
|
|
||||||
} else if (trans->status == LIBUSB_TRANSFER_CANCELLED) {
|
|
||||||
DEBUG_WARN(" cancelled\n");
|
|
||||||
} else if (trans->status == LIBUSB_TRANSFER_NO_DEVICE) {
|
|
||||||
DEBUG_WARN(" no device\n");
|
|
||||||
} else {
|
|
||||||
DEBUG_WARN(" unknown\n");
|
|
||||||
}
|
|
||||||
ctx->flags |= TRANS_FLAGS_HAS_ERROR;
|
|
||||||
}
|
|
||||||
ctx->flags |= TRANS_FLAGS_IS_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int submit_wait(usb_link_t *link, struct libusb_transfer *trans) {
|
|
||||||
struct trans_ctx trans_ctx;
|
|
||||||
enum libusb_error error;
|
|
||||||
|
|
||||||
trans_ctx.flags = 0;
|
|
||||||
|
|
||||||
/* brief intrusion inside the libusb interface */
|
|
||||||
trans->callback = on_trans_done;
|
|
||||||
trans->user_data = &trans_ctx;
|
|
||||||
|
|
||||||
if ((error = libusb_submit_transfer(trans))) {
|
|
||||||
DEBUG_WARN("libusb_submit_transfer(%d): %s\n", error,
|
|
||||||
libusb_strerror(error));
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t start_time = platform_time_ms();
|
|
||||||
while (trans_ctx.flags == 0) {
|
|
||||||
struct timeval timeout;
|
|
||||||
timeout.tv_sec = 1;
|
|
||||||
timeout.tv_usec = 0;
|
|
||||||
if (libusb_handle_events_timeout(link->ul_libusb_ctx, &timeout)) {
|
|
||||||
DEBUG_WARN("libusb_handle_events()\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
uint32_t now = platform_time_ms();
|
|
||||||
if (now - start_time > 1000) {
|
|
||||||
libusb_cancel_transfer(trans);
|
|
||||||
DEBUG_WARN("libusb_handle_events() timeout\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (trans_ctx.flags & TRANS_FLAGS_HAS_ERROR) {
|
|
||||||
DEBUG_WARN("libusb_handle_events() | has_error\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* One USB transaction */
|
|
||||||
int send_recv(usb_link_t *link,
|
|
||||||
uint8_t *txbuf, size_t txsize,
|
|
||||||
uint8_t *rxbuf, size_t rxsize)
|
|
||||||
{
|
|
||||||
int res = 0;
|
|
||||||
if( txsize) {
|
|
||||||
int txlen = txsize;
|
|
||||||
libusb_fill_bulk_transfer(link->req_trans,
|
|
||||||
link->ul_libusb_device_handle,
|
|
||||||
link->ep_tx | LIBUSB_ENDPOINT_OUT,
|
|
||||||
txbuf, txlen,
|
|
||||||
NULL, NULL, 0);
|
|
||||||
int i = 0;
|
|
||||||
DEBUG_WIRE(" Send (%3d): ", txlen);
|
|
||||||
for (; i < txlen; i++) {
|
|
||||||
DEBUG_WIRE("%02x", txbuf[i]);
|
|
||||||
if ((i & 7) == 7)
|
|
||||||
DEBUG_WIRE(".");
|
|
||||||
if ((i & 31) == 31)
|
|
||||||
DEBUG_WIRE("\n ");
|
|
||||||
}
|
|
||||||
if (!(i & 31))
|
|
||||||
DEBUG_WIRE("\n");
|
|
||||||
if (submit_wait(link, link->req_trans)) {
|
|
||||||
libusb_clear_halt(link->ul_libusb_device_handle, link->ep_tx);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* send_only */
|
|
||||||
if (rxsize != 0) {
|
|
||||||
/* read the response */
|
|
||||||
libusb_fill_bulk_transfer(link->rep_trans, link->ul_libusb_device_handle,
|
|
||||||
link->ep_rx | LIBUSB_ENDPOINT_IN,
|
|
||||||
rxbuf, rxsize, NULL, NULL, 0);
|
|
||||||
|
|
||||||
if (submit_wait(link, link->rep_trans)) {
|
|
||||||
DEBUG_WARN("clear 1\n");
|
|
||||||
libusb_clear_halt(link->ul_libusb_device_handle, link->ep_rx);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
res = link->rep_trans->actual_length;
|
|
||||||
if (res >0) {
|
|
||||||
int i;
|
|
||||||
uint8_t *p = rxbuf;
|
|
||||||
DEBUG_WIRE(" Rec (%zu/%d)", rxsize, res);
|
|
||||||
for (i = 0; i < res && i < 32 ; i++) {
|
|
||||||
if ( i && ((i & 7) == 0))
|
|
||||||
DEBUG_WIRE(".");
|
|
||||||
DEBUG_WIRE("%02x", p[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DEBUG_WIRE("\n");
|
|
||||||
return res;
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user