Compare commits

...

218 Commits

Author SHA1 Message Date
547abf0cf2
Switch fallthrough missing break usbdfu
usbdfu should be updated later...
2023-01-04 23:41:07 +01:00
06b21b6d82
Fixed bad libopencm3 linker file 2023-01-04 23:27:32 +01:00
dragonmux
ad1868f8d4 command: Cleaned up and refactored cmd_rtt
# Conflicts:
#	src/command.c
2022-08-11 19:56:31 -07:00
dragonmux
c712a54cbc rtt: Cleanup and fixes for the RTT over serial support as per #954 2022-08-11 19:45:58 -07:00
Koen De Vleeschauwer
a51d90ba2d rtt
# Conflicts:
#	src/gdb_main.c
2022-08-11 19:45:44 -07:00
Jason Kotzin
f67a4e421d merge fixes and selective optimizations 2022-08-11 19:28:10 -07:00
Jason Kotzin
8fc7a559b2 Merge commit '5cd430647ecfb6dab4a2ed858fb98567723de699' into stable 2022-08-11 19:15:01 -07:00
Jason Kotzin
c9a0be19cb Merge commit '5e3cadec20a5fa3ec6eef53f23520707d0db5380' into sam-update 2022-08-10 22:33:40 -07:00
Jason Kotzin
2ca08f8511 Merge commit '84311b38881ec4a0934686579fec1054feaf5394' into sam-update 2022-08-10 22:32:18 -07:00
Jason Kotzin
3ae3095499 Merge commit 'c4869a54733ae92099a7316954e34d1ab7b6097c' into sam-update 2022-08-10 22:31:16 -07:00
Jason Kotzin
2a792399ca Merge commit 'e535f53981da1fe80137504c761bc854ea8be356' into sam-update 2022-08-10 22:30:11 -07:00
Jason Kotzin
576f575871 Merge commit '7c120ecb582afb588cb391ab32614c4409a2671d' into sam-update 2022-08-10 22:28:35 -07:00
Jason Kotzin
e43b07172b Merge commit 'a3feae60aab1fb85fe44b33123e020a9d7c8e18c' into sam-update 2022-08-10 22:26:37 -07:00
Jason Kotzin
e0f1d29d41 compile fix 2022-08-10 22:26:10 -07:00
Jason Kotzin
2a00dd88ec Merge commit 'b59ca5142ad3a654dc173d598b826f5f453ae52b' into sam-update 2022-08-10 22:21:29 -07:00
Jason Kotzin
c121da06c8 Merge commit 'a0c77e216d268f2e1caa3442db02cf21f36fad91' into sam-update 2022-08-10 22:20:36 -07:00
Jason Kotzin
542c157955 Merge commit 'd9ef3ff14711457eaf0ea7152067c95b4bb45c03' into sam-update 2022-08-10 22:19:41 -07:00
Jason Kotzin
d4dd288426 Merge commit 'bba2bfdcf49695cb9b88482c7ed3db69db58b082' into sam-update 2022-08-10 22:18:39 -07:00
Jason Kotzin
b096e95488 Merge commit 'cedd9f9ac4fc02cc5ac152eb67024f714c6f95ab' into sam-update 2022-08-10 22:17:50 -07:00
Jason Kotzin
7bd7c3d0f5 Merge commit '8fb3b7b1a8d1cb2ac8b54204f452106939eb2ab7' into sam-update
# Conflicts:
#	src/target/adiv5_swdp.c
2022-08-10 22:17:33 -07:00
Jason Kotzin
82673b5e7b Merge commit '82c41cb739e3281e89319bd2fb9627d1a22c803b' into sam-update 2022-08-10 22:09:23 -07:00
Jason Kotzin
9542cd1cfb Merge commit '48c6db19635a804621c7e08e5e3c705aa50e5e9d' into sam-update 2022-08-10 22:08:46 -07:00
Jason Kotzin
328be18288 Merge commit 'd259d5c5110d5867031a9d9ceaaf3725ce242857' into sam-update 2022-08-10 22:07:38 -07:00
Jason Kotzin
03331b3fff Merge commit '4fe8fd8944ad49e40a46287e2286328af6871226' into sam-update 2022-08-10 22:06:28 -07:00
Jason Kotzin
ca1c0acb27 Merge commit '23534ab174ffadd63bbdb2e0626770753eff7c3b' into sam-update 2022-08-10 22:05:07 -07:00
Jason Kotzin
b4af0f5145 Merge commit '7d2afcff06f1ccd9fe583d562ddd81e04a17e166' into sam-update 2022-08-10 20:40:24 -07:00
Jason Kotzin
e174c5b503 Merge commit 'd594b42976e3b9640b64ef1cb2da3f74067930b8' into sam-update
# Conflicts:
#	README.md
#	src/platforms/common/cdcacm.c
#	src/target/adiv5_swdp.c
2022-08-10 20:39:54 -07:00
Jason Kotzin
c91322e38e fix stack compile warning 2022-08-10 20:37:14 -07:00
Jason Kotzin
85fc728293 Merge commit '59dc2255687436d7a21458615e4eb2e563ca64c1' into sam-update 2022-08-10 20:32:50 -07:00
Jason Kotzin
6727e74daf Merge commit '28623e6b275b90817894ddcbf915dbb8c6686433' into sam-update 2022-08-10 20:31:54 -07:00
Jason Kotzin
d7bf91d039 Merge commit '7ccbdd98c0bd18c2a672ed50aa1f96aff97dd4af' into sam-update 2022-08-10 20:31:11 -07:00
Jason Kotzin
878dc379b9 updates for merge 2022-08-10 20:30:57 -07:00
Jason Kotzin
4f97627b02 Merge commit '64f756d62791e16728e6c9d7877ce2ab620b9c1c' into sam-update 2022-08-10 20:25:30 -07:00
Jason Kotzin
56858650cb Merge commit '88cce08ce47b7b6f6f40b404fa79c6be687ab7e3' into sam-update 2022-08-10 20:24:43 -07:00
Jason Kotzin
dcbb1657b4 Merge commit 'da15cc3cb75cc2a9f604436402f6a81d42b27dce' into sam-update 2022-08-10 20:23:40 -07:00
Jason Kotzin
9dc79becc2 Merge commit '35687018eb634ea329609c86d9ed476bb79c0e91' into sam-update
# Conflicts:
#	src/platforms/common/cdcacm.c
#	src/target/adiv5_swdp.c
2022-08-10 20:19:55 -07:00
Jason Kotzin
9ec6693e4d Merge commit '2a0d608b07487300a63908baa62e73a51a11e811' into sam-update 2022-08-10 20:14:55 -07:00
Jason Kotzin
a2f6776bf8 Merge commit '8089e05a0018a040251ec5de145bccca0977bf78' into sam-update 2022-08-10 20:13:59 -07:00
Jason Kotzin
cb1ef7d616 Merge commit '1330288271bea7b6224bac5bc8e1438305eec44a' into sam-update 2022-08-10 20:09:58 -07:00
Jason Kotzin
def176b240 Merge commit '8da2dee0c41eead0c2b4f466fbc889ef413cf7e9' into sam-update 2022-08-10 20:08:13 -07:00
Jason Kotzin
d5a8717bb0 stack bug fix 2022-08-10 20:08:05 -07:00
Jason Kotzin
8acda14170 Merge commit '23f942ac8c7553f743128d9f96f0d2aa61fbc4bd' into sam-update 2022-08-10 20:07:25 -07:00
Jason Kotzin
c1e34792f4 Merge commit '04d1c9805b80b50b4f1cd33b08503b73e80c0ed3' into sam-update 2022-08-10 20:06:04 -07:00
Jason Kotzin
c5b6f066b8 Merge commit 'b6fbf86743509559fce4c56345e8fdc16df14a08' into sam-update 2022-08-10 19:55:26 -07:00
Jason Kotzin
f109bc2e98 Merge commit '61e237ec87c525876817e72fc82ce28b2a4951ae' into sam-update 2022-08-10 19:53:14 -07:00
Jason Kotzin
d36213b7d0 Merge commit 'be3bfc48a8be7cd4d84709e98c5def13259d49f6' into sam-update
# Conflicts:
#	README.md
2022-08-10 19:49:50 -07:00
Jason Kotzin
389bb03fc0 Merge commit 'db17f2caa8dcbf229670ba03b46be274656c6d72' into sam-update 2022-08-10 19:48:49 -07:00
Jason Kotzin
78837173a4 Merge commit 'e6a9a1a3665e83e25d5d4077a33aa5b0110646b8' into sam-update
# Conflicts:
#	.gitignore
2022-08-10 19:48:21 -07:00
Jason Kotzin
4328e8a4c1 Merge commit 'aa0d8f4b5de13f4fb7324a690a4bb7aa411e767f' into sam-update 2022-08-10 19:46:16 -07:00
Jason Kotzin
646fbcb21f fixes for upstream 2022-08-10 19:46:01 -07:00
Jason Kotzin
9da2d298c3 Merge commit '1ca9f234f7527396da91bfc1f98cb05c305c6472' into sam-update 2022-08-10 19:30:49 -07:00
Jason Kotzin
95a4ebf836 Merge commit '7365a44989c7c8561c583f75ff30f7277e712ff3' into sam-update 2022-08-10 19:30:16 -07:00
Jason Kotzin
3024cc1bfe minor update to libopencm3, only build samd to speed up merge 2022-08-10 19:28:12 -07:00
Jason Kotzin
7340b0065d Merge commit '93d4c659481c918b43c0068e69050ef1ad4ca91e' into sam-update 2022-08-10 19:08:37 -07:00
Jason Kotzin
dd01fe9ad3 upstream compile fixes 2022-08-10 19:08:35 -07:00
Jason Kotzin
336797363b Merge commit '98b4ec58bc566591943c9123dd4ca0c8dcfd521e' into sam-update
# Conflicts:
#	libopencm3
2022-08-10 19:08:25 -07:00
Jason Kotzin
046cc359ba Merge commit 'dd6aadc54d00cee92e14bf7538d3ece3d3ab298f' into sam-update 2022-08-10 18:37:14 -07:00
Jason Kotzin
9e02c5f0cd Merge commit 'cda83d308490738b54df0405cca3c0c048809664' into sam-update
# Conflicts:
#	src/Makefile
2022-08-10 18:36:23 -07:00
Jason Kotzin
c73329f7d4 Merge commit '59dc1b7eb4f3a0fda23d2c8624c3ecd26515fec8' into sam-update
# Conflicts:
#	src/platforms/common/cdcacm.c
2022-08-10 18:33:59 -07:00
Jason Kotzin
d90c207c50 adding cscope files to git ignore 2022-08-10 18:24:35 -07:00
Jason Kotzin
b87091a59b Merge commit 'dc8924a2bc0110287c1b289002efb52926daccb0' into sam-update
# Conflicts:
#	README.md
2022-08-10 18:24:25 -07:00
Jason Kotzin
f8aff4bf4b upstream fixes 2022-08-10 18:19:15 -07:00
Jason Kotzin
50b9a4ceb6 Merge commit '77231e8972fa22cb233354ba5aed694dff4a9e24' into sam-update 2022-08-10 17:40:26 -07:00
Jason Kotzin
93cf62d944 Merge commit '8289862b55e2a0dc658c3c7e2f6ab9878d0527fa' into sam-update
# Conflicts:
#	README.md
#	src/platforms/common/cdcacm.c
2022-08-10 17:40:24 -07:00
Jason Kotzin
09e45cea5b Merge commit 'a4cdd6b3103cdf6c1f8454fb81558ff98a8d912d' into sam-update 2022-08-10 17:36:48 -07:00
Jason Kotzin
65c95fb413 Merge commit 'f5e305e237aba0ab8bf2f42e75505ef468f47d82' into sam-update
# Conflicts:
#	README.md
2022-08-10 17:36:47 -07:00
Jason Kotzin
c643726c9d Merge commit 'da45281696b05089d694e6e9c7734968b9496865' into sam-update 2022-08-10 17:35:15 -07:00
Jason Kotzin
eda19bc28d Merge commit 'ef816e318391c64014554140be65a5cafc6c8be2' into sam-update
# Conflicts:
#	.gitignore
2022-08-10 17:34:55 -07:00
Jason Kotzin
9b145c8398 compatibility to upstream 2022-08-10 17:27:05 -07:00
Jason Kotzin
53c6821734 Merge commit '9969c984f3ca67f38677b061e2f91a1fb50cd310' into sam-update 2022-08-10 15:57:56 -07:00
Jason Kotzin
842a0b4193 compatibility with merge changes 2022-08-10 15:57:41 -07:00
Jason Kotzin
8a37449f8a Merge commit 'e34a27f72c9689850e97df74c499538d7f18518d' into sam-update
# Conflicts:
#	src/include/swdptap.h
#	src/platforms/common/swdptap.c
2022-08-10 15:57:29 -07:00
Jason Kotzin
21989d4142 Merge commit '1e10b96b03da71b1a101c108ca9511c8a613666e' into sam-update 2022-08-09 22:17:14 -07:00
Jason Kotzin
63449912e2 Merge commit 'f3790b90e5ecf44525dc05f05a4e72f74baea411' into sam-update 2022-08-09 22:11:55 -07:00
Jason Kotzin
1661396951 Merge commit '05adcd9bf5b36d099627aff6b73e463030ee417f' into sam-update 2022-08-09 22:06:01 -07:00
Jason Kotzin
fd6610bdae samd fix USB max packet size 2022-08-09 17:31:30 -07:00
Jason Kotzin
19e01abf70 Merge commit '16967b43288028dcdc2759bb2a25a53472571162' into sam-update 2022-08-09 17:25:16 -07:00
Jason Kotzin
a89b2ead47 Merge commit '541861e978ba88c80e7e2a0cbcd7ce55d574c97b' into sam-update
# Conflicts:
#	README.md
2022-08-09 17:23:48 -07:00
Jason Kotzin
81cfa0a380 Merge commit '1a83bc68920ad20ad044e9110c3599e3ac1f76c0' into sam-update
# Conflicts:
#	src/command.c
2022-08-09 17:22:19 -07:00
Jason Kotzin
41449370b4 Merge commit 'd63e870e82ecbd73af2d14e6794d2985cb9bd0ad' into sam-update 2022-08-09 17:13:06 -07:00
Jason Kotzin
73285885b3 Merge commit 'a0e42e229b99dad09f3c2eaf1455cbefc776cbe8' into sam-update 2022-08-09 17:11:21 -07:00
Jason Kotzin
b71213522a change spec to decrease code size 2022-08-08 21:14:10 -07:00
Jason Kotzin
c0c5255103 libopencm3 regression fix 2022-08-08 21:06:18 -07:00
Jason Kotzin
a2cdb32f14 Merge commit '2e185ba578cf996a9e6cd7b6a0321a2448064e52' into sam-update 2022-08-02 09:35:57 -07:00
Jason Kotzin
1930380e16 Merge commit '0b6f393d5b1ab03fc0dcd8b172261e7a52bdd3d8' into sam-update 2022-08-02 09:35:19 -07:00
Jason Kotzin
5509264a2b Merge commit 'ea779d13725f1c2c580c5c11c47267af09b6b007' into sam-update 2022-08-02 09:35:09 -07:00
Jason Kotzin
6f902bcfe7 optimization flag for jeff probe 2022-08-02 09:35:01 -07:00
Jason Kotzin
fdce017311 Merge commit 'f89542c79f6edb0d64e7dfa483501718113f45b5' into sam-update 2022-08-02 09:28:24 -07:00
Jason Kotzin
96a980b682 Merge commit '286b987822a685f6ff86f6522da3733a0c9d7757' into sam-update
# Conflicts:
#	src/command.c
2022-08-02 09:28:14 -07:00
Jason Kotzin
cedcd1a832 Merge commit '71b8a4e0818026fa25e9fa95b2cd3c0dd407b3a2' into sam-update 2022-08-02 09:21:00 -07:00
Jason Kotzin
1737788a92 Merge commit 'd1ee827b4df710a0f693f6df7808cb5d75b2530c' into sam-update 2022-08-02 09:20:50 -07:00
Jason Kotzin
f65793582d Merge commit '5704c2fb5a07bbe7982a368e6ab7762a6866988f' into sam-update
# Conflicts:
#	src/Makefile
2022-08-02 09:20:27 -07:00
Jason Kotzin
90a7ecaaf1 Merge commit 'e8bd066fe96f72c6998aea7c0d80d6de019b825d' into sam-update
# Conflicts:
#	README.md
2022-08-02 01:31:38 -07:00
Jason Kotzin
b6896898c2 Merge commit '82be49f05212d36733ab99c6f83ef93a7ff444d1' into sam-update 2022-08-02 01:31:04 -07:00
Jason Kotzin
81bb75bba6 Merge commit '443ced62d4e47d73da13746a836369d8421b4fe8' into sam-update
# Conflicts:
#	libopencm3
2022-08-02 01:23:28 -07:00
Jason Kotzin
6661871707 Merge commit 'fbf196378e5bbeffad02439fa974f6142a78d6a2' into sam-update 2022-08-01 21:46:52 -07:00
Jason Kotzin
885fdcc354 Merge commit '5107a29699904fb4e60907d1e9b2438592f6a3ff' into sam-update 2022-08-01 21:46:24 -07:00
Jason Kotzin
16261813ca Merge commit 'e29f2b4fb95601291afced3af3731385be343988' into sam-update
# Conflicts:
#	.gitignore
#	src/include/swdptap.h
#	src/target/swdptap_generic.c
2022-08-01 21:45:01 -07:00
Jason Kotzin
fcf5b74542 Merge commit '067956266c886d377231ffdd89e630e41aeb2783' into sam-update 2022-08-01 20:43:02 -07:00
Jason Kotzin
539fba02ac Merge commit '9e898cc4b8f3e1a5844a3693412a9977a65a0a63' into sam-update 2022-08-01 20:30:35 -07:00
Jason Kotzin
4a2a121e89 Merge commit 'dd3cb193f3a83e99b5a915e9942c295b9d9715d7' into sam-update 2022-08-01 20:30:04 -07:00
Jason Kotzin
16b827e4e4 Merge commit 'c44cb904b0d345753b40ac9649bb4c611855a5c4' into sam-update
# Conflicts:
#	src/target/adiv5.c
2022-08-01 20:29:58 -07:00
Jason Kotzin
a9197e67ea Merge commit '205fce20e5ade52b6331e315ccd0700293f51aac' into sam-update 2022-08-01 20:22:28 -07:00
Jason Kotzin
ab63700a80 Merge commit '9ed26645d332dbd1d725ccef64199ef13604686c' into sam-update 2022-08-01 20:22:07 -07:00
Jason Kotzin
0993a8ae28 Merge commit 'fd3af639b0f8eb816d4efc860f549e8c01454826' into sam-update 2022-08-01 20:21:48 -07:00
Jason Kotzin
a7c4a0c108 Merge commit 'bd530c8951f8393e8d799d25f233c77051b10561' into sam-update 2022-08-01 20:21:34 -07:00
Jason Kotzin
bb97e35f82 Merge commit '5aebef4f64d0fd4c19f794fb9725686c39a7e395' into sam-update 2022-08-01 20:21:13 -07:00
Jason Kotzin
cbed6c911f Merge commit 'df7458e35a67abb216d9816c59f218cad45f1c44' into sam-update 2022-08-01 20:20:38 -07:00
Jason Kotzin
272b461b3e Merge commit 'b4c680bb150b815df401c98c45f03ff45e5a231f' into sam-update 2022-08-01 20:18:49 -07:00
Jason Kotzin
a29d53cb31 Merge commit '600bc9f0294f07a5572511c98041710d80d95769' into sam-update 2022-08-01 20:18:03 -07:00
Jason Kotzin
4947f0f747 Merge commit '61e9607594586fe5018157f566b8b79a398444b7' into sam-update
# Conflicts:
#	src/Makefile
2022-08-01 20:17:24 -07:00
Jason Kotzin
a6f8944afe Merge commit '88ec55768389c6c4de69ecd6e101f6b136c25a8f' into sam-update 2022-08-01 20:10:32 -07:00
Jason Kotzin
33c0319263 Merge commit '2b4000b2b44ca629d18d96a803413c71ab7b8e52' into sam-update 2022-08-01 20:09:50 -07:00
Jason Kotzin
93cad1ca5a Merge commit 'cdb04a4214cfd1d94a7fe2fd1837b91ec099db28' into sam-update 2022-08-01 20:09:24 -07:00
Jason Kotzin
9a9fac2e83 Merge commit '02c1934c03eb86901634ed63e0cc9b13eb743fa8' into sam-update 2022-08-01 20:08:54 -07:00
Jason Kotzin
a285b2ac17 Merge commit '7032abd2b00d4548d41f7f1abbdf0837bc283def' into sam-update
# Conflicts:
#	src/Makefile
2022-08-01 20:08:51 -07:00
Jason Kotzin
4b4d0fcfcf Merge commit 'a65ce77466077b4259d99232d6f3c168b476ce79' into sam-update 2022-08-01 20:05:36 -07:00
Jason Kotzin
6b2b1aa4c3 Merge commit '525b90d4e5d07f431a1d0f4e5d2abf9e6c691e10' into sam-update 2022-08-01 20:04:51 -07:00
Jason Kotzin
fce7dd2957 Merge commit '7f947d724c552f896d5394f3ebbf6b47de9eb5a6' into sam-update 2022-08-01 20:04:01 -07:00
Jason Kotzin
6b2f0aeb63 Merge commit 'db544e9b671719e553bb6aec9e2e39294c3ee027' into sam-update 2022-08-01 20:03:40 -07:00
Jason Kotzin
4cae565ef3 Merge commit 'a988bba035824ddc97b2cf3aadc457dcd85aaad0' into sam-update 2022-08-01 20:02:30 -07:00
Jason Kotzin
d76fd844c9 Merge commit '05518094752e450708aced3397cb26146e8ce0d3' into sam-update 2022-08-01 19:59:54 -07:00
Jason Kotzin
27a099a94b Merge commit '46b681e050bbfb27acafab88a3b67bda292825ca' into sam-update 2022-08-01 19:58:15 -07:00
Jason Kotzin
9c33ce7979 Merge commit '7a7266a0f7e38a9359f84fe1fb34453e8b2b16ae' into sam-update
# Conflicts:
#	src/platforms/common/swdptap.c
2022-08-01 19:57:12 -07:00
Jason Kotzin
1612eacab2 Merge commit '5548d54626a658b65f1f963cd5af54ddaf93fbf7' into sam-update
# Conflicts:
#	src/platforms/common/swdptap.c
2022-08-01 19:56:08 -07:00
Jason Kotzin
f1f59d3c1d Merge commit '7e3fe352ad4aed89522d808d76dbe868a470412e' into sam-update
# Conflicts:
#	src/platforms/common/swdptap.c
2022-08-01 19:54:44 -07:00
Jason Kotzin
a42fc8904d Merge commit 'e54a826745ae298a4eb555f3d76dfcdd571211b9' into sam-update
# Conflicts:
#	src/platforms/common/swdptap.c
2022-08-01 19:52:55 -07:00
Jason Kotzin
f62c9db5af Merge commit 'd4d24c256c2c9a858ae6fc134ee34ba03cb65565' into sam-update 2022-08-01 19:21:49 -07:00
Jason Kotzin
1ba83f3283 Merge commit '17b817f37bca85c9b469470742ecdeedf02f7b3e' into sam-update 2022-08-01 19:21:27 -07:00
Jason Kotzin
c33a447210 Merge commit '9e365a58f77a9096b0203a5f012bb7bfb08fbc95' into sam-update 2022-08-01 19:21:10 -07:00
Jason Kotzin
81fafae68d Merge commit '44fc24e0e747293fa05b62ed7439501553829b0b' into sam-update 2022-08-01 19:20:52 -07:00
Jason Kotzin
447bdc50a0 Merge commit '66e357d51762f3bf93b549a5626554b2f8de4379' into sam-update
# Conflicts:
#	src/target/adiv5.c
2022-08-01 19:20:32 -07:00
Jason Kotzin
b91712214f Merge commit '1799ea3b7102ac1e2a86d78cdbde0f5b809b0be1' into sam-update 2022-08-01 19:03:03 -07:00
Jason Kotzin
5574a14aee Merge commit 'b7a59afc5920caf1e83cd470aee67f665d0e7197' into sam-update 2022-08-01 19:01:41 -07:00
Jason Kotzin
a82ab6a45d Merge commit '80f003ff4b6edc9d0d2b98b4ca65d610d86efc74' into sam-update 2022-08-01 19:01:18 -07:00
Jason Kotzin
40ea78d57b Merge commit '48d232807ee6096bfa839d91b1708252db0e1a59' into sam-update 2022-08-01 18:59:50 -07:00
Jason Kotzin
eab16ef39f Merge commit '0f2f1d74a2446275ee31ed582f1f4d98dff24d61' into sam-update 2022-08-01 18:57:07 -07:00
Jason Kotzin
da701aff6d Merge commit '455e0a74d2a77f2ae1f0acf53b778e41b890523e' into sam-update 2022-08-01 18:56:50 -07:00
Jason Kotzin
aece87bf3e Merge commit 'cfaa5ea9633fb8719da9455f6c04908810395abe' into sam-update 2022-08-01 18:54:48 -07:00
Jason Kotzin
2931169dd1 Merge commit '0c659f49cd03c7154bfb92c621df523aa8540f72' into sam-update 2022-08-01 18:52:34 -07:00
Jason Kotzin
95655b838e Merge commit '231d42d58172a2169d99c6e618192ac0d514d3b9' into sam-update 2022-08-01 18:50:19 -07:00
Jason Kotzin
1846795844 Merge commit '19e58a7205e2dfe849b5ac42e470ff489e4ab10d' into sam-update 2022-08-01 18:36:22 -07:00
Jason Kotzin
76c2f5e39c Merge commit 'eb46994bc95ba308f8eb96d42366abbdae7c5ab7' into sam-update 2022-08-01 18:35:43 -07:00
Jason Kotzin
51f2b79437 Merge commit '1ee1f441d581b6473526a4870f4c3aa201a18af6' into sam-update 2022-08-01 18:34:34 -07:00
Jason Kotzin
02eafe9883 Merge commit 'c7bc51d1919bce00c341b2b2e1e617adcf189be9' into sam-update 2022-08-01 18:33:40 -07:00
Jason Kotzin
05a42576c2 Merge commit 'a4bb2c6e3ea8404641325638a040e3295b7afe30' into sam-update 2022-08-01 18:33:13 -07:00
Jason Kotzin
39949eefe2 Merge commit 'fd467269eb82783c09a69763c46df4de2d494ef4' into sam-update 2022-08-01 18:32:42 -07:00
Jason Kotzin
d7afc92b5f Merge commit '539d9e14ec553c77b2c3387b4719d8f07401d6a7' into sam-update 2022-08-01 18:32:18 -07:00
Jason Kotzin
44b5eed7ca Merge commit '261be9864c8ce77c857a996784ac65ed3203b03a' into sam-update 2022-08-01 18:31:34 -07:00
Jason Kotzin
4346fb2405 Merge commit '98a4f8e31872d3f72e47aba8b01a167503144c1e' into sam-update 2022-08-01 18:31:06 -07:00
Jason Kotzin
9c95dfb712 adding adiv5 support 2022-08-01 17:45:49 -07:00
Jason Kotzin
f99fe59ce8 updating libopencm3 with samd i2c support 2022-08-01 17:45:30 -07:00
dragonmux
5cd430647e
gdb_main: Fixed a small DEBUG_GDB regression for vFlashErase and vFlashWrite debugging 2022-07-21 07:14:47 +01:00
dragonmux
fc55400aad
gdb_main: Implemented a notification to GDB that the "process" has exited when the user runs a new bus scan while attached to a target 2022-07-21 05:45:23 +01:00
dragonmux
d2370f780f
gdb_packet: Implement notification packets 2022-07-21 05:45:23 +01:00
dragonmux
f254e86511
gdb_main: Add some output in the scan commands to indicate when still attached that you aren't after the command, despite what GDB thinks 2022-07-21 05:45:22 +01:00
dragonmux
3cc6aa1236
gdb_main: Implemented qfThreadInfo and qsThreadInfo for GDB 11+ 2022-07-21 05:45:22 +01:00
dragonmux
65ac074410
gdb_main: Implemented vKill as it's required for GDB 11+ 2022-07-21 05:45:22 +01:00
dragonmux
c6d1bcb352
gdb_main: Cleaned up the naming in the 'g' and 'G' packet handlers 2022-07-21 05:45:22 +01:00
dragonmux
eb9d9893f8
hex_utils: Cleaned up and fixed the type confusion that was going on 2022-07-21 05:45:22 +01:00
dragonmux
8db1d30852
gdb_main: Reply to vAttach with TID 1 because GDB 11 and 12 are terminally broken otherwise 2022-07-21 05:45:21 +01:00
dragonmux
1f22c72634
gdb_main: Implemented support for qC queries 2022-07-21 05:45:21 +01:00
dragonmux
7322bb3ffa
gdb_main: More type confusion fixes and cleanup 2022-07-21 05:45:19 +01:00
dragonmux
17ba28c44b
gdb_main: Implemented H[m|M|g|G|c] packet support 2022-07-21 05:44:21 +01:00
dragonmux
47c84fac85
gdb_packet: Done a spring pass on the types situation and cleaned things up 2022-07-21 05:43:55 +01:00
Piotr Esden-Tempski
1cf1ba1ddb stm32f4: Fixes erase_mass command return error.
The final erase_mass command check is looking for the EOP (End of
OPeration) bit to be set. This bit is only set when the EOP interrupts
(EOPIE = 1) are enabled. We are not enabling those on the target so this
bit will never get set. As we are monitoring the BSY flag to make sure
the erase_mass operation is still ongoing and finished it is enough if
we just check the error flags.
2022-07-13 21:06:53 -07:00
dragonmux
34696c0fec
target: Make the buffers used to program a target's Flash better bounded in lifetime and memory usage 2022-07-13 22:28:33 -04:00
Piotr Esden-Tempski
a067e801d7
BMP V2.3: Fix outdated ADC reads.
We are using GD32F103 on the BMP V2.3 hardware. The GD32F103 has an
errata for the ADC where the end of conversion (EOC) bit is not reset
when reading the ADC result. This resulted in us not waiting for the new
value to be acquired and reading an old value instead. The solution for
that is resetting the EOC bit manually after reading the ADC result, so
that on the next acquisision we wait for the conversion to finish.

This patch also increases the sampling time as the GD32 have lower ADC
impedance than the STM32 and this should help us read a more accuarate
target voltage.
2022-07-13 20:54:14 -04:00
dragonmux
d01acd8030
kinetis: Clean up how kl_gen_flash_done builds the command buffers to send to ensure the security byte is OK 2022-07-11 20:17:53 -04:00
dragonmux
0dffd2ffd2
kinetis: Fixed the flash write command generation for K64 devices 2022-07-11 20:17:52 -04:00
dragonmux
0f1006bf08
kinetis: Try to be safer about our FCCOB writes so the Flash controller's less likely to get mad 2022-07-11 20:17:52 -04:00
Rafael Silva
f69ed07ba7
kinetis: macro organization and clearer function naming
Signed-off-by: Rafael Silva <perigoso@riseup.net>
2022-07-09 19:12:05 -04:00
dragonmux
9591649ec6
kinetis: Run clang-format on the code 2022-07-09 19:10:40 -04:00
dragonmux
e9abd83412
kinetis: Refactored out some common code from kinetis_probe for the S32K14 lineup 2022-07-09 19:10:39 -04:00
dragonmux
4de54fbee6
kinetis: General formatting and readability cleanup 2022-07-09 19:10:39 -04:00
dragonmux
77a83f4ffc
ch32f1: Fixed another broken debug print that made assumptions about %x and %d that are wrong 2022-06-26 17:34:22 -04:00
dragonmux
d613d29839
cortexm: Added additional debug information for part probing 2022-06-26 17:34:22 -04:00
dragonmux
c7c5f68a84
ch32f1: Re-ordered a couple of the operation in ch32f1_probe so it plays nicer with the STM32 parts 2022-06-26 17:34:22 -04:00
dragonmux
d9f4d069e6
ch32f1: Further formatting and layout cleanup 2022-06-26 17:34:22 -04:00
dragonmux
eb8bb01c57
ch32f1: Fixed the probe routine distrubing state for other parts wrt t->idcode
The CH32F1 routine now reads the IDCode into a local.
If the part number matches and appears to be the chip (based on Flash locking), it only then writes the IDCode into `t->idcode`, which is at the point we can only `return true` from the probe routine anyway.
2022-06-26 17:34:22 -04:00
dragonmux
7e91c401d3
ch32f1: formatting cleanup to bring things closer to inline with the rest of the codebase 2022-06-26 17:34:09 -04:00
Maciej Musiał
54790f032e
cortexm: fixed an issue with watchpoint handling and a register sanity check 2022-06-26 17:32:19 -04:00
dragonmux
08956eb4fb
gdb_main: Fix a formatting bug that breaks, among other things, breakpoints 2022-06-26 17:31:13 -04:00
Mikaela Szekely
289d963ba5 Complete the version string migration from 5e3cade, fixing HOSTED_BMP_ONLY 2022-06-03 14:45:16 -07:00
Jason Kotzin
a6f9701368 Adding schematic, use adobe, has a 3D step built in 2021-08-15 22:22:09 -07:00
Jason Kotzin
237d6b89f6 Updating Readme 2021-08-15 22:18:41 -07:00
Jason Kotzin
2b89a07dae samd: adding bootprotect and unlock commands 2021-08-15 21:50:54 -07:00
Jason Kotzin
a01642e480 samd: create a copy that’s named with the version 2019-05-31 00:33:57 -07:00
Jason Kotzin
6b9b502354 tag correctly if we are on a branch 2019-05-31 00:07:20 -07:00
Jason Kotzin
8606b78b9e updating gitignore file 2019-05-18 14:55:31 -07:00
Ryan
cd325dfe52 samd: convert_tdio requires enable/disable 2019-05-16 13:18:05 -07:00
Ryan
c1b3d0c629 samd: bug fix on uart newlines 2019-04-10 17:38:16 -07:00
Jason Kotzin
94238fd95b samd: ability to printout entire serial number 2019-03-29 16:34:12 -07:00
Ryan
5c835bc0f6 samd: srst_get_val now actually works 2019-02-22 18:21:13 -08:00
Ryan
100fc2e7d4 samd: added command to toggle srst pin when not used 2019-02-11 16:15:03 -08:00
Jason Kotzin
880e977fb6 samd: custom serial string for easy opening on mac 2019-02-09 13:48:04 -08:00
Ryan
3a9b0eee7a samd: added tpwr support 2019-02-04 18:19:28 -08:00
Jason Kotzin
6baf90ac4c samd: adding dfu bootloader, compile support, and combined image 2018-12-20 13:35:45 -08:00
Ryan
77064754ad samd: fixed first-scan failure 2018-10-17 15:08:08 -07:00
Ryan
92ed79e68e samd: button code updated for libopencm3 2018-10-04 14:24:18 -07:00
Ryan
b91a975d56 samd: button must hold for 5 seconds now 2018-10-03 16:04:32 -07:00
Ryan
84b6818982 samd: convert_tdio command cleaned up 2018-09-28 14:54:31 -07:00
Ryan
4aee9fe2a3 samd: enter_bootldr command, bootldr button 2018-09-28 14:37:33 -07:00
Ryan
4847e0d1e6 samd: uart ports updated for bm-sam hw 2018-09-05 15:52:04 -07:00
Ryan
a599b989cf samd: TDI/O conversion, usart line coding 2018-09-05 12:10:43 -07:00
Ryan
50658a5c0a samd: small fixes to uart 2018-08-27 16:22:48 -07:00
Ryan
f828fc1ac1 samd voltage detection and line coding 2018-08-07 14:32:00 -07:00
Jason Kotzin
bd71ca2a3c Minor updates to help with speed, temporarily disabling uart 2018-08-01 19:10:01 -07:00
Ryan
2d38c9614e fixed typo in jeff/platform.h 2018-08-01 16:22:03 -07:00
Jason Kotzin
7ce265f2cf Adding queue.h file and fixing some compile errors 2018-08-01 14:26:31 -07:00
Jason Kotzin
638299534b samd: updates for jeff probe pcb 2018-07-13 23:48:52 -07:00
Jason Kotzin
919a005b65 debug flags only if we are debugging, speeds up firmware slightly 2018-07-12 19:19:39 -07:00
Jason Kotzin
58865ca5ec samd: uart support 2018-07-12 18:54:13 -07:00
Jason Kotzin
d62d82bb2f M0 SWDIO 2x performance improvements 2018-07-10 16:18:05 -07:00
Jason Kotzin
f1ecd66283 Initial support for samd hardware and jeff ‘probe’ 2018-07-10 15:42:44 -07:00
Jason Kotzin
fd2cb4b8d2 Updating submodule to use flirc samd branch 2018-07-10 14:01:03 -07:00
Jason Kotzin
1cc3e05c11 Force USB connect 2018-07-10 13:36:00 -07:00
Jason Kotzin
d5b6d4ab12 Allow support for older chip architectures 2018-07-10 13:35:45 -07:00
43 changed files with 3727 additions and 715 deletions

5
.gitignore vendored
View File

@ -16,7 +16,10 @@ tags
*.b#*
blackmagic_upgrade
*.exe
.DS_Store
*.elf
.vscode
cscope.out
cscope.files
.gdb_history
src/artifacts/
src/artifacts/

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "libopencm3"]
path = libopencm3
url = https://github.com/libopencm3/libopencm3.git
url = https://github.com/flirc/libopencm3.git

View File

@ -17,13 +17,23 @@ ifndef NO_LIBOPENCM3
git submodule init ;\
git submodule update ;\
fi
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib/stm32/f1 lib/stm32/f4 lib/lm4f
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib/sam/d
endif
$(Q)$(MAKE) $(MFLAGS) -C src
all_platforms:
$(Q)$(MAKE) $(MFLAGS) -C src $@
clean:
ifndef NO_LIBOPENCM3
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 $@
endif
$(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
View File

@ -1,113 +1,54 @@
Black Magic Probe
=================
[![Discord](https://img.shields.io/discord/613131135903596547?logo=discord)](https://discord.gg/P7FYThy)
Firmware for the Black Magic Debug Probe.
The Black Magic Probe is a modern, in-application debugging tool for
embedded microprocessors. It allows you see what is going on 'inside' an
application running on an embedded microprocessor while it executes. It is
able to control and examine the state of the target microprocessor using a
JTAG or Serial Wire Debugging (SWD) port and on-chip debug logic provided
by the microprocessor. The probe connects to a host computer using a
standard USB interface. The user is able to control exactly what happens
using the GNU source level debugging software, GDB.
Serial Wire Output (SWO) allows the target to write tracing and logging to the host
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/blackmagic-debug/blackmagic/wiki/Serial-Wire-Output).
Resources
=========
* [Documentation](https://github.com/blackmagic-debug/blackmagic/wiki)
* [Binary builds](http://builds.blacksphere.co.nz/blackmagic)
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.<br>
Building hosted for BMP firmware probes only with "make PROBE_HOST HOSTED_BMP_ONLY=1" does not require libusb, libftdi and evt. libhidapi development headers and libraries for running.<br>
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.<br>
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
Jeff Probe
==========
You can also build blackmagic as a PC hosted application
"make PROBE_HOST=hosted"
This is a fork of the [original Black Magic Probe](https://github.com/blacksphere/blackmagic).
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.
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.
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
...
One urguably better funncton is the ability to do DEBUG and Serial communication
over a single JTAG cable when paired with a device that uses single wire JTAG.
Normally, the serial header can be used on a target for the serial port, and
shows up as the second serial device on the system, however, we can dynamically
change the pins to use the ones on the JTAG cable with the following command:
``` bash
$ mon convert_tdio enable
```
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.
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
Binaries from the latest automated build can be found on the release page.

271
UsingRTT.md Normal file
View 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)

View File

@ -1,6 +1,7 @@
# Black Magic Probe
# there are two connections, one for GDB and one for UART debugging
# 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 UART Port", SYMLINK+="ttyBmpTarg"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="1d50", ATTR{idProduct}=="6017", MODE="0666"

@ -1 +1 @@
Subproject commit 8435287300e5ca9af9f889c529e7b1fa019c42fb
Subproject commit 63573143ef7e1b037d1f0c5baedc5264e12562b8

BIN
schematic/bm-sam-a04.pdf Normal file

Binary file not shown.

View File

@ -9,7 +9,7 @@ Q := @
endif
CFLAGS += -Wall -Wextra -Werror -Wno-char-subscripts \
-std=gnu99 -g3 -MD -I./target \
-std=gnu99 -MD -I./target \
-I. -Iinclude -I$(PLATFORM_DIR)
ifeq ($(ENABLE_DEBUG), 1)
@ -65,11 +65,6 @@ SRC = \
include $(PLATFORM_DIR)/Makefile.inc
ifneq ($(PC_HOSTED),1)
# Output memory usage information
LDFLAGS += -Wl,--print-memory-usage
endif
OPT_FLAGS ?= -Os
CFLAGS += $(OPT_FLAGS)
LDFLAGS += $(OPT_FLAGS)
@ -95,8 +90,28 @@ VPATH += platforms/common
CFLAGS += -Iplatforms/common
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)))
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)
@echo " LD $@"
$(Q)$(CC) -o $@ $(OBJ) $(LDFLAGS)
@ -112,14 +127,14 @@ $(TARGET): include/version.h $(OBJ)
ifndef PC_HOSTED
%.bin: %.elf
@echo " OBJCOPY $@"
$(Q)$(OBJCOPY) -O binary $^ $@
$(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) -O binary $^ $@
%.hex: %.elf
@echo " OBJCOPY $@"
$(Q)$(OBJCOPY) -O ihex $^ $@
endif
.PHONY: clean host_clean all_platforms FORCE
.PHONY: clean host_clean all_platforms clang-format FORCE
clean: host_clean
$(Q)echo " CLEAN"
@ -127,16 +142,27 @@ clean: host_clean
-$(Q)$(RM) platforms/*/*.o platforms/*/*.d mapfile include/version.h
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 ;\
mkdir -p artifacts/$(shell git describe --always --dirty --tags) ;\
echo "<html><body><ul>" > artifacts/index.html ;\
$(MAKE) clean ;\
for i in platforms/*/Makefile.inc ; do \
export DIRNAME=`dirname $$i` ;\
export PROBE_HOST=`basename $$DIRNAME` ;\
export CFLAGS=-Werror ;\
echo "Building for hardware platform: $$PROBE_HOST" ;\
$(MAKE) clean ;\
$(MAKE);\
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 \
mv blackmagic.bin artifacts/blackmagic-$$PROBE_HOST.bin ;\
echo "<li><a href='blackmagic-$$PROBE_HOST.bin'>$$PROBE_HOST</a></li>"\
@ -147,13 +173,31 @@ all_platforms:
echo "<li><a href='blackmagic_dfu-$$PROBE_HOST.bin'>$$PROBE_HOST DFU</a></li>"\
>> artifacts/index.html ;\
fi ;\
$(MAKE) clean ;\
done ;\
echo "</ul></body></html>" >> artifacts/index.html ;\
cp artifacts/*.bin artifacts/$(shell git describe --always --dirty --tags)
cp artifacts/blackmagic* artifacts/$(shell git describe --always --dirty --tags)
command.c: include/version.h
GIT_VERSION := $(shell git describe --always --dirty --tags)
VERSION_HEADER := \#define FIRMWARE_VERSION "$(GIT_VERSION)"
include/version.h: FORCE
$(Q)echo " GIT include/version.h"
$(Q)echo "#define FIRMWARE_VERSION \"$(shell git describe --always --dirty --tags)\"" > $@
@# If git isn't found then GIT_VERSION will be an empty string.
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

View File

@ -34,11 +34,18 @@
#include "version.h"
#include "serialno.h"
#ifdef ENABLE_RTT
#include "rtt.h"
#endif
#ifdef PLATFORM_HAS_TRACESWO
# include "traceswo.h"
#endif
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_jtag_scan(target *t, int argc, char **argv);
@ -56,12 +63,25 @@ static bool cmd_target_power(target *t, int argc, const char **argv);
static bool cmd_traceswo(target *t, int argc, const char **argv);
#endif
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)
static bool cmd_debug_bmp(target *t, int argc, const char **argv);
#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[] = {
{"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"},
{"jtag_scan", (cmd_handler)cmd_jtag_scan, "Scan JTAG chain for devices" },
{"swdp_scan", (cmd_handler)cmd_swdp_scan, "Scan SW-DP for devices" },
@ -74,6 +94,9 @@ const struct command_s cmd_list[] = {
#ifdef PLATFORM_HAS_POWER_SWITCH
{"tpwr", (cmd_handler)cmd_target_power, "Supplies power to the target: (enable|disable)"},
#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
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, NRZ mode: (baudrate) (decode channel ...)" },
@ -84,6 +107,13 @@ const struct command_s cmd_list[] = {
{"heapinfo", (cmd_handler)cmd_heapinfo, "Set semihosting heapinfo" },
#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)"},
#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
{NULL, NULL, NULL}
};
@ -410,6 +440,82 @@ static bool cmd_target_power(target *t, int argc, const char **argv)
}
#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
static bool cmd_traceswo(target *t, int argc, const char **argv)
{
@ -487,6 +593,66 @@ static bool cmd_debug_bmp(target *t, int argc, const char **argv)
return true;
}
#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)
{
if (t == NULL) gdb_out("not attached\n");

View File

@ -130,4 +130,3 @@ int hostio_system(struct target_controller *tc,
gdb_putpacket_f("Fsystem,%08X/%X", cmd, cmd_len);
return gdb_main_loop(tc, true);
}

View File

@ -35,6 +35,9 @@
#include "command.h"
#include "crc32.h"
#include "morse.h"
#ifdef ENABLE_RTT
#include "rtt.h"
#endif
enum gdb_signal {
GDB_SIGINT = 2,
@ -43,7 +46,7 @@ enum gdb_signal {
GDB_SIGLOST = 29,
};
#define BUF_SIZE 1024
#define BUF_SIZE 1024U
#define ERROR_IF_NO_TARGET() \
if(!cur_target) { gdb_putpacketz("EFF"); break; }
@ -51,23 +54,29 @@ enum gdb_signal {
typedef struct
{
const char *cmd_prefix;
void (*func)(const char *packet, int len);
void (*func)(const char *packet, size_t len);
} cmd_executer;
static char pbuf[BUF_SIZE + 1];
static char pbuf[BUF_SIZE + 1U];
static target *cur_target;
static target *last_target;
static bool gdb_needs_detach_notify = false;
static void handle_q_packet(char *packet, int len);
static void handle_v_packet(char *packet, int len);
static void handle_z_packet(char *packet, int len);
static void handle_q_packet(char *packet, size_t len);
static void handle_v_packet(char *packet, size_t 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)
{
(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;
gdb_needs_detach_notify = true;
}
if (last_target == t)
last_target = NULL;
@ -100,22 +109,20 @@ static struct target_controller gdb_controller = {
int gdb_main_loop(struct target_controller *tc, bool in_syscall)
{
int size;
bool single_step = false;
/* GDB protocol main loop */
while(1) {
while (1) {
SET_IDLE_STATE(1);
size = gdb_getpacket(pbuf, BUF_SIZE);
size_t size = gdb_getpacket(pbuf, BUF_SIZE);
SET_IDLE_STATE(0);
switch(pbuf[0]) {
switch (pbuf[0]) {
/* Implementation of these is mandatory! */
case 'g': { /* 'g': Read general registers */
ERROR_IF_NO_TARGET();
uint8_t arm_regs[target_regs_size(cur_target)];
target_regs_read(cur_target, arm_regs);
gdb_putpacket(hexify(pbuf, arm_regs, sizeof(arm_regs)),
sizeof(arm_regs) * 2);
uint8_t gp_regs[target_regs_size(cur_target)];
target_regs_read(cur_target, gp_regs);
gdb_putpacket(hexify(pbuf, gp_regs, sizeof(gp_regs)), sizeof(gp_regs) * 2U);
break;
}
case 'm': { /* 'm addr,len': Read len bytes from addr */
@ -132,19 +139,20 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
if (target_mem_read(cur_target, mem, addr, len))
gdb_putpacketz("E01");
else
gdb_putpacket(hexify(pbuf, mem, len), len * 2);
gdb_putpacket(hexify(pbuf, mem, len), len * 2U);
break;
}
case 'G': { /* 'G XX': Write general registers */
ERROR_IF_NO_TARGET();
uint8_t arm_regs[target_regs_size(cur_target)];
unhexify(arm_regs, &pbuf[1], sizeof(arm_regs));
target_regs_write(cur_target, arm_regs);
uint8_t gp_regs[target_regs_size(cur_target)];
unhexify(gp_regs, &pbuf[1], sizeof(gp_regs));
target_regs_write(cur_target, gp_regs);
gdb_putpacketz("OK");
break;
}
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;
ERROR_IF_NO_TARGET();
sscanf(pbuf, "M%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &hex);
@ -162,11 +170,24 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
gdb_putpacketz("OK");
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] */
single_step = true;
/* fall through */
case 'c': /* 'c [addr]': Continue [at addr] */
if(!cur_target) {
if (!cur_target) {
gdb_putpacketz("X1D");
break;
}
@ -181,7 +202,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
target_addr watch;
enum target_halt_reason reason;
if(!cur_target) {
if (!cur_target) {
/* Report "target exited" if no target */
gdb_putpacketz("W00");
break;
@ -189,10 +210,13 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
/* Wait for target halt */
while(!(reason = target_halt_poll(cur_target, &watch))) {
unsigned char c = gdb_if_getchar_to(0);
if((c == '\x03') || (c == '\x04')) {
char c = (char)gdb_if_getchar_to(0);
if(c == '\x03' || c == '\x04') {
target_halt_request(cur_target);
}
#ifdef ENABLE_RTT
if (rtt_enabled) poll_rtt(cur_target);
#endif
}
SET_RUN_STATE(0);
@ -274,12 +298,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
break;
case 'k': /* Kill the target */
if(cur_target) {
target_reset(cur_target);
target_detach(cur_target);
last_target = cur_target;
cur_target = NULL;
}
handle_kill_target();
break;
case 'r': /* Reset the target system */
@ -317,7 +336,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
handle_q_packet(pbuf, size);
break;
case 'v': /* General query packet */
case 'v': /* Verbose command packet */
handle_v_packet(pbuf, size);
break;
@ -335,12 +354,12 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
}
}
static bool exec_command(char *packet, int len, const cmd_executer *exec)
static bool exec_command(char *packet, const size_t length, const cmd_executer *exec)
{
while (exec->cmd_prefix) {
const int l = strlen(exec->cmd_prefix);
if (!strncmp(packet, exec->cmd_prefix, l)) {
exec->func(packet + l, len - l);
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;
@ -348,19 +367,16 @@ static bool exec_command(char *packet, int len, const cmd_executer *exec)
return false;
}
static void exec_q_rcmd(const char *packet,int len)
static void exec_q_rcmd(const char *packet, const size_t length)
{
char *data;
int datalen;
/* calculate size and allocate buffer for command */
datalen = len / 2;
data = alloca(datalen + 1);
const size_t datalen = length / 2U;
char *data = alloca(datalen + 1);
/* dehexify command */
unhexify(data, packet, datalen);
data[datalen] = 0; /* add terminating null */
int c = command_process(cur_target, data);
const int c = command_process(cur_target, data);
if (c < 0)
gdb_putpacketz("");
else if (c == 0)
@ -370,41 +386,41 @@ static void exec_q_rcmd(const char *packet,int len)
2 * strlen("Failed\n"));
}
static void
handle_q_string_reply(const char *str, const char *param)
static void handle_q_string_reply(const char *reply, const char *param)
{
unsigned long addr, len;
const size_t str_len = strlen(str);
const size_t reply_length = strlen(reply);
uint32_t addr = 0;
uint32_t len = 0;
if (sscanf(param, "%08lx,%08lx", &addr, &len) != 2) {
if (sscanf(param, "%08" PRIx32 ",%08" PRIx32, &addr, &len) != 2) {
gdb_putpacketz("E01");
return;
}
else if (addr > str_len) {
if (addr > reply_length) {
gdb_putpacketz("E01");
return;
}
else if (addr == str_len) {
if (addr == reply_length) {
gdb_putpacketz("l");
return;
}
unsigned long output_len = str_len - addr;
size_t output_len = reply_length - addr;
if (output_len > len)
output_len = len;
gdb_putpacket2("m", 1, str + addr, output_len);
gdb_putpacket2("m", 1U, reply + addr, output_len);
}
static void exec_q_supported(const char *packet, int len)
static void exec_q_supported(const char *packet, const size_t length)
{
(void)packet;
(void)len;
(void)length;
gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE);
}
static void exec_q_memory_map(const char *packet, int len)
static void exec_q_memory_map(const char *packet, const size_t length)
{
(void)packet;
(void)len;
(void)length;
/* Read target XML memory map */
if ((!cur_target) && last_target) {
/* Attach to last target if detached. */
@ -420,9 +436,9 @@ static void exec_q_memory_map(const char *packet, int len)
handle_q_string_reply(buf, packet);
}
static void exec_q_feature_read(const char *packet, int len)
static void exec_q_feature_read(const char *packet, const size_t length)
{
(void)len;
(void)length;
/* Read target description */
if ((!cur_target) && last_target) {
/* Attach to last target if detached. */
@ -435,24 +451,51 @@ static void exec_q_feature_read(const char *packet, int len)
handle_q_string_reply(target_tdesc(cur_target), packet);
}
static void exec_q_crc(const char *packet, int len)
static void exec_q_crc(const char *packet, const size_t length)
{
(void)len;
uint32_t addr, alen;
if (sscanf(packet, "%" PRIx32 ",%" PRIx32, &addr, &alen) == 2) {
(void)length;
uint32_t addr;
uint32_t addr_length;
if (sscanf(packet, "%" PRIx32 ",%" PRIx32, &addr, &addr_length) == 2) {
if (!cur_target) {
gdb_putpacketz("E01");
return;
}
uint32_t crc;
int res = generic_crc32(cur_target, &crc, addr, alen);
if (res)
if (generic_crc32(cur_target, &crc, addr, addr_length))
gdb_putpacketz("E03");
else
gdb_putpacket_f("C%lx", crc);
}
}
/*
* 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)
{
(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},
@ -460,34 +503,60 @@ static const cmd_executer q_commands[]=
{"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_q_packet(char *packet, int len)
static void handle_kill_target(void)
{
if (exec_command(packet, len, q_commands))
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, int plen)
static void handle_v_packet(char *packet, const size_t plen)
{
unsigned long addr, len;
uint32_t addr = 0;
uint32_t len = 0;
int bin;
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 */
cur_target = target_attach_n(addr, &gdb_controller);
if(cur_target) {
morse(NULL, false);
gdb_putpacketz("T05");
/*
* 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");
} 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)) {
/* Parse command line for get_cmdline semihosting call */
char cmdline[83];
@ -518,6 +587,10 @@ handle_v_packet(char *packet, int plen)
}
break;
}
#ifdef ENABLE_RTT
/* force searching rtt control block */
rtt_found = false;
#endif
/* Run target program. For us (embedded) this means reset. */
if (cur_target) {
target_set_cmdline(cur_target, cmdline);
@ -539,9 +612,9 @@ handle_v_packet(char *packet, int plen)
} 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 */
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;
@ -560,11 +633,11 @@ handle_v_packet(char *packet, int plen)
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 */
len = plen - bin;
DEBUG_GDB("Flash Write %08lX %08lX\n", addr, len);
if (cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0)
const uint32_t count = plen - bin;
DEBUG_GDB("Flash Write %08" PRIX32 " %08" PRIX32 "\n", addr, count);
if (cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, count) == 0)
gdb_putpacketz("OK");
else {
flash_mode = 0;
@ -576,24 +649,30 @@ handle_v_packet(char *packet, int plen)
gdb_putpacketz(target_flash_done(cur_target) ? "EFF" : "OK");
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 {
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
gdb_putpacket("", 0);
}
}
static void
handle_z_packet(char *packet, int plen)
static void handle_z_packet(char *packet, const size_t plen)
{
(void)plen;
uint8_t set = (packet[0] == 'Z') ? 1 : 0;
int type, len;
uint32_t type;
uint32_t len;
uint32_t addr;
int ret;
sscanf(packet, "%*[zZ]%" PRIu32 ",%08" PRIx32 ",%" PRIu32, &type, &addr, &len);
sscanf(packet, "%*[zZ]%d,%08" PRIX32 ",%d", &type, &addr, &len);
if(set)
int ret = 0;
if (packet[0] == 'Z')
ret = target_breakwatch_set(cur_target, type, addr, len);
else
ret = target_breakwatch_clear(cur_target, type, addr, len);

View File

@ -30,12 +30,11 @@
#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;
char recv_csum[3];
int i;
size_t offset = 0;
while (1) {
/* Wait for packet start */
@ -44,7 +43,8 @@ int gdb_getpacket(char *packet, int size)
* start ('$') or a BMP remote packet start ('!').
*/
do {
packet[0] = gdb_if_getchar();
/* Smells like bad code */
packet[0] = (char)gdb_if_getchar();
if (packet[0] == 0x04)
return 1;
} while ((packet[0] != '$') && (packet[0] != REMOTE_SOM));
@ -52,18 +52,19 @@ int gdb_getpacket(char *packet, int size)
if (packet[0] == REMOTE_SOM) {
/* This is probably a remote control packet
* - get and handle it */
i = 0;
offset = 0;
bool gettingRemotePacket = true;
while (gettingRemotePacket) {
c = gdb_if_getchar();
/* Smells like bad code */
const char c = (char)gdb_if_getchar();
switch (c) {
case REMOTE_SOM: /* Oh dear, packet restarts */
i = 0;
offset = 0;
break;
case REMOTE_EOM: /* Complete packet for processing */
packet[i] = 0;
remotePacketProcess(i, packet);
packet[offset] = 0;
remotePacketProcess(offset, packet);
gettingRemotePacket = false;
break;
@ -73,8 +74,8 @@ int gdb_getpacket(char *packet, int size)
break;
default:
if (i < size) {
packet[i++] = c;
if (offset < size) {
packet[offset++] = c;
} else {
/* Who knows what is going on...return to normality */
gettingRemotePacket = false;
@ -92,30 +93,32 @@ int gdb_getpacket(char *packet, int size)
#endif
} while (packet[0] != '$');
i = 0;
offset = 0;
csum = 0;
char c;
/* Capture packet data into buffer */
while ((c = gdb_if_getchar()) != '#') {
while ((c = (char)gdb_if_getchar()) != '#') {
if (i == size) /* Oh shit */
/* If we run out of buffer space, exit early */
if (offset == size)
break;
if (c == '$') { /* Restart capture */
i = 0;
offset = 0;
csum = 0;
continue;
}
if (c == '}') { /* escaped char */
c = gdb_if_getchar();
csum += c + '}';
packet[i++] = c ^ 0x20;
packet[offset++] = c ^ 0x20;
continue;
}
csum += c;
packet[i++] = c;
packet[offset++] = c;
}
recv_csum[0] = gdb_if_getchar();
recv_csum[1] = gdb_if_getchar();
recv_csum[0] = (char)gdb_if_getchar();
recv_csum[1] = (char)gdb_if_getchar();
recv_csum[2] = 0;
/* return packet if checksum matches */
@ -126,20 +129,20 @@ int gdb_getpacket(char *packet, int size)
gdb_if_putchar('-', 1); /* send nack */
}
gdb_if_putchar('+', 1); /* send ack */
packet[i] = 0;
packet[offset] = 0;
#if PC_HOSTED == 1
DEBUG_GDB_WIRE("%s : ", __func__);
for(int j = 0; j < i; j++) {
c = packet[j];
if ((c >= 32) && (c < 127))
for (size_t j = 0; j < offset; j++) {
const char c = packet[j];
if (c >= ' ' && c < 0x7F)
DEBUG_GDB_WIRE("%c", c);
else
DEBUG_GDB_WIRE("\\x%02X", c);
}
DEBUG_GDB_WIRE("\n");
#endif
return i;
return offset;
}
static void gdb_next_char(char c, unsigned char *csum)
@ -161,21 +164,19 @@ static void gdb_next_char(char c, unsigned char *csum)
}
}
void gdb_putpacket2(const char *packet1, int size1, const char *packet2, int size2)
void gdb_putpacket2(const char *packet1, size_t size1, const char *packet2, size_t size2)
{
int i;
unsigned char csum;
char xmit_csum[3];
int tries = 0;
size_t tries = 0;
do {
DEBUG_GDB_WIRE("%s : ", __func__);
csum = 0;
DEBUG_GDB_WIRE("%s: ", __func__);
unsigned char csum = 0;
gdb_if_putchar('$', 0);
for (i = 0; i < size1; ++i)
for (size_t i = 0; i < size1; ++i)
gdb_next_char(packet1[i], &csum);
for (i = 0; i < size2; ++i)
for (size_t i = 0; i < size2; ++i)
gdb_next_char(packet2[i], &csum);
gdb_if_putchar('#', 0);
@ -183,28 +184,42 @@ void gdb_putpacket2(const char *packet1, int size1, const char *packet2, int siz
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));
} while (gdb_if_getchar_to(2000) != '+' && tries++ < 3);
}
void gdb_putpacket(const char *packet, int size)
void gdb_putpacket(const char *packet, size_t size)
{
int i;
unsigned char csum;
char xmit_csum[3];
int tries = 0;
size_t tries = 0;
do {
DEBUG_GDB_WIRE("%s : ", __func__);
csum = 0;
DEBUG_GDB_WIRE("%s: ", __func__);
unsigned char csum = 0;
gdb_if_putchar('$', 0);
for (i = 0; i < size; ++i)
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));
} 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, ...)

View File

@ -26,16 +26,16 @@
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;
const uint8_t *b = buf;
char *dst = hex;
const uint8_t *const src = buf;
while (size--) {
*tmp++ = hexdigits[*b >> 4];
*tmp++ = hexdigits[*b++ & 0xF];
for (size_t idx = 0; idx < size; ++idx) {
*dst++ = hexdigits[src[idx] >> 4];
*dst++ = hexdigits[src[idx] & 0xF];
}
*tmp++ = 0;
*dst++ = 0;
return hex;
}
@ -43,20 +43,18 @@ char * hexify(char *hex, const void *buf, size_t size)
static uint8_t unhex_digit(char hex)
{
uint8_t tmp = hex - '0';
if(tmp > 9)
if (tmp > 9)
tmp -= 'A' - '0' - 10;
if(tmp > 16)
if (tmp > 16)
tmp -= 'a' - 'A';
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;
while (size--) {
*b = unhex_digit(*hex++) << 4;
*b++ |= unhex_digit(*hex++);
uint8_t *const dst = buf;
for (size_t idx = 0; idx < size; ++idx, hex += 2) {
dst[idx] = (unhex_digit(hex[0]) << 4) | unhex_digit(hex[1]);
}
return buf;
}

View File

@ -21,18 +21,19 @@
#ifndef __GDB_PACKET_H
#define __GDB_PACKET_H
#include <stddef.h>
#include <stdarg.h>
int gdb_getpacket(char *packet, int size);
void gdb_putpacket(const char *packet, int size);
void gdb_putpacket2(const char *packet1, int size1, const char *packet2, int size2);
size_t gdb_getpacket(char *packet, size_t 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))
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_voutf(const char *fmt, va_list);
void gdb_outf(const char *fmt, ...);
#endif

85
src/include/queue.h Normal file
View 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
View 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
View 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

View File

@ -78,7 +78,7 @@ static const struct usb_device_descriptor dev_desc = {
.bDeviceClass = 0xEF, /* Miscellaneous Device */
.bDeviceSubClass = 2, /* Common Class */
.bDeviceProtocol = 1, /* Interface Association */
#ifdef LM4F
#if defined(SAMD21E17) || defined(LM4F)
.bMaxPacketSize0 = 64, /*Fixed for icdi*/
#else
.bMaxPacketSize0 = 32,
@ -435,6 +435,8 @@ static void dfu_detach_complete(usbd_device *dev, struct usb_setup_data *req)
/* Reset core to enter bootloader */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
scb_reset_core();
#else
scb_reset_system();
#endif
}
@ -524,7 +526,7 @@ static void cdcacm_set_config(usbd_device *dev, uint16_t wValue)
configured = wValue;
/* GDB interface */
#if defined(STM32F4) || defined(LM4F)
#if defined(STM32F4) || defined(LM4F) || defined(SAMD)
usbd_ep_setup(dev, CDCACM_GDB_ENDPOINT, USB_ENDPOINT_ATTR_BULK,
CDCACM_PACKET_SIZE, gdb_usb_out_cb);
#else
@ -580,6 +582,7 @@ void cdcacm_init(void)
nvic_set_priority(USB_IRQ, IRQ_PRI_USB);
nvic_enable_irq(USB_IRQ);
usbd_disconnect(usbdev, false);
}
void USB_ISR(void)

View File

@ -233,7 +233,9 @@ int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
struct dirent *dp;
int i = 0;
while ((dp = readdir(dir)) != NULL) {
if ((strstr(dp->d_name, BMP_IDSTRING)) &&
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];
@ -266,7 +268,9 @@ int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
dir = opendir(DEVICE_BY_ID);
i = 0;
while ((dp = readdir(dir)) != NULL) {
if ((strstr(dp->d_name, BMP_IDSTRING)) &&
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];

View File

@ -30,6 +30,10 @@
#include "gdb_if.h"
#include <signal.h>
#ifdef ENABLE_RTT
#include "rtt_if.h"
#endif
#include "bmp_remote.h"
#include "bmp_hosted.h"
#include "stlinkv2.h"
@ -58,6 +62,9 @@ static void exit_function(void)
default:
break;
}
#ifdef ENABLE_RTT
rtt_if_exit();
#endif
fflush(stdout);
}
@ -110,6 +117,9 @@ void platform_init(int argc, char **argv)
exit(cl_execute(&cl_opts));
else {
gdb_if_init();
#ifdef ENABLE_RTT
rtt_if_init();
#endif
return;
}
}

View 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

View 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

View 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;
}

View 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
View 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);
}

View File

@ -285,7 +285,7 @@ static void adc_init(void)
adc_set_single_conversion_mode(ADC1);
adc_disable_external_trigger_regular(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);
@ -316,6 +316,8 @@ uint32_t platform_target_voltage_sense(void)
while (!adc_eoc(ADC1));
uint32_t val = adc_read_regular(ADC1); /* 0-4095 */
/* Clear EOC bit. The GD32F103 does not automatically reset it on ADC read. */
ADC_SR(ADC1) &= ~ADC_SR_EOC;
return (val * 99) / 8191;
}

103
src/platforms/samd/gdb_if.c Normal file
View File

@ -0,0 +1,103 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
*
* 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/>.
*/
/* This file implements a transparent channel over which the GDB Remote
* Serial Debugging protocol is implemented. This implementation for STM32
* uses the USB CDC-ACM device bulk endpoints to implement the channel.
*/
#include "general.h"
#include "gdb_if.h"
#include "cdcacm.h"
#include <libopencm3/usb/usbd.h>
static volatile uint32_t head_out, tail_out;
static volatile uint32_t count_in;
static volatile uint8_t buffer_out[16*CDCACM_PACKET_SIZE];
static volatile uint8_t buffer_in[CDCACM_PACKET_SIZE];
void gdb_if_putchar(unsigned char c, int flush)
{
buffer_in[count_in++] = c;
if(flush || (count_in == CDCACM_PACKET_SIZE)) {
/* Refuse to send if USB isn't configured, and
* don't bother if nobody's listening */
if((cdcacm_get_config() != 1) || !cdcacm_get_dtr()) {
count_in = 0;
return;
}
while(usbd_ep_write_packet(usbdev, CDCACM_GDB_ENDPOINT,
(uint8_t *)buffer_in, count_in) <= 0);
count_in = 0;
}
}
void gdb_usb_out_cb(usbd_device *dev, uint8_t ep)
{
(void)ep;
static uint8_t buf[CDCACM_PACKET_SIZE];
usbd_ep_nak_set(dev, CDCACM_GDB_ENDPOINT, 1);
uint32_t count = usbd_ep_read_packet(dev, CDCACM_GDB_ENDPOINT,
(uint8_t *)buf, CDCACM_PACKET_SIZE);
uint32_t idx;
for (idx=0; idx<count; idx++) {
buffer_out[head_out++ % sizeof(buffer_out)] = buf[idx];
}
usbd_ep_nak_set(dev, CDCACM_GDB_ENDPOINT, 0);
}
unsigned char gdb_if_getchar(void)
{
while(tail_out == head_out) {
/* Detach if port closed */
if(!cdcacm_get_dtr())
return 0x04;
while(cdcacm_get_config() != 1);
}
return buffer_out[tail_out++ % sizeof(buffer_out)];
}
unsigned char gdb_if_getchar_to(int timeout)
{
platform_timeout t;
platform_timeout_set(&t, timeout);
if(head_out == tail_out) do {
/* Detach if port closed */
if(!cdcacm_get_dtr())
return 0x04;
while(cdcacm_get_config() != 1);
} while(!platform_timeout_is_expired(&t) && head_out == tail_out);
if(head_out != tail_out)
return gdb_if_getchar();
return -1;
}

134
src/platforms/samd/rtt_if.c Normal file
View File

@ -0,0 +1,134 @@
/*
* 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 "platform.h"
#include <assert.h>
#include "cdcacm.h"
#include "rtt.h"
#include "rtt_if.h"
/*********************************************************************
*
* rtt terminal i/o
*
**********************************************************************
*/
/* usb uart receive buffer */
static char recv_buf[RTT_DOWN_BUF_SIZE];
static uint32_t recv_head = 0;
static uint32_t recv_tail = 0;
/* data from host to target: number of free bytes in usb receive buffer */
inline static uint32_t recv_bytes_free()
{
if (recv_tail <= recv_head)
return sizeof(recv_buf) - recv_head + recv_tail - 1;
else
return recv_tail - recv_head - 1;
}
/* data from host to target: true if not enough free buffer space and we need to close flow control */
inline static bool recv_set_nak()
{
assert(sizeof(recv_buf) > 2 * CDCACM_PACKET_SIZE);
return recv_bytes_free() < 2 * CDCACM_PACKET_SIZE;
}
/* usbuart_usb_out_cb is called when usb uart has received new data for target.
this routine has to be fast */
void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
{
(void)dev;
(void)ep;
char usb_buf[CDCACM_PACKET_SIZE];
/* close flow control while processing packet */
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 1);
const uint16_t len = usbd_ep_read_packet(usbdev, CDCACM_UART_ENDPOINT, usb_buf, CDCACM_PACKET_SIZE);
/* skip flag: drop packet if not enough free buffer space */
if (rtt_flag_skip && len > recv_bytes_free()) {
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0);
return;
}
/* copy data to recv_buf */
for (int i = 0; i < len; i++) {
uint32_t next_recv_head = (recv_head + 1) % sizeof(recv_buf);
if (next_recv_head == recv_tail)
break; /* overflow */
recv_buf[recv_head] = usb_buf[i];
recv_head = next_recv_head;
}
/* block flag: flow control closed if not enough free buffer space */
if (!(rtt_flag_block && recv_set_nak()))
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0);
return;
}
/* rtt host to target: read one character */
int32_t rtt_getchar()
{
int retval;
if (recv_head == recv_tail)
return -1;
retval = recv_buf[recv_tail];
recv_tail = (recv_tail + 1) % sizeof(recv_buf);
/* open flow control if enough free buffer space */
if (!recv_set_nak())
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0);
return retval;
}
/* rtt host to target: true if no characters available for reading */
bool rtt_nodata()
{
return recv_head == recv_tail;
}
/* rtt target to host: write string */
uint32_t rtt_write(const char *buf, uint32_t len)
{
if (len != 0 && usbdev && cdcacm_get_config() && cdcacm_get_dtr()) {
for (uint32_t p = 0; p < len; p += CDCACM_PACKET_SIZE) {
uint32_t plen = MIN(CDCACM_PACKET_SIZE, len - p);
while(usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, buf + p, plen) <= 0);
}
/* flush 64-byte packet on full-speed */
if (CDCACM_PACKET_SIZE == 64 && (len % CDCACM_PACKET_SIZE) == 0)
while(usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, NULL, 0) <= 0);
}
return len;
}

View File

@ -0,0 +1,28 @@
/*
* This file is part of the libopenstm32 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
*
* 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/>.
*/
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x00002000, LENGTH = 120K /* 128k - 8k for bootloader */
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
}
/* Include the common ld script from libopenstm32. */
INCLUDE cortex-m-generic.ld

View File

@ -0,0 +1,28 @@
/*
* This file is part of the libopenstm32 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
*
* 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/>.
*/
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x00000000, LENGTH = 128K /* 128k - 8k for bootloader */
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
}
/* Include the common ld script from libopenstm32. */
INCLUDE cortex-m-generic.ld

View File

@ -0,0 +1,57 @@
/*
* 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/>.
*/
/* This file implements capture of the TRACESWO output.
*
* ARM DDI 0403D - ARMv7M Architecture Reference Manual
* ARM DDI 0337I - Cortex-M3 Technical Reference Manual
* ARM DDI 0314H - CoreSight Components Technical Reference Manual
*/
#include "general.h"
#include "cdcacm.h"
void traceswo_init(void)
{
}
void traceswo_baud(unsigned int baud)
{
baud++;
}
void trace_buf_push(void)
{
}
void trace_buf_drain(usbd_device *dev, uint8_t ep)
{
ep ++;
if (dev == NULL)
return;
}
void trace_tick(void)
{
}
void TRACEUART_ISR(void)
{
}

View File

@ -0,0 +1,251 @@
/*
* 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 "cdcacm.h"
#include <libopencm3/sam/d/bitfield.h>
#include <libopencm3/sam/d/gclk.h>
#include <libopencm3/sam/d/pm.h>
#include <libopencm3/sam/d/port.h>
#include <libopencm3/sam/d/nvic.h>
#include <libopencm3/sam/d/uart.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/scs.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/cdc.h>
#include "queue.h"
#define Q_SIZE 1024
/* Active USART number */
static uint8_t USART_NUM = 0;
/* Current Baud Rate setting */
static uint32_t current_baud = 115200;
usbd_device * usbdev;
/* input and output ring buffer */
struct {
char buf[Q_SIZE];
volatile size_t head, tail;
} rx, tx;
#ifndef ENABLE_RTT
/* non blocking putc function */
static void usart_putc(char c)
{
#ifdef CONSOLE_NO_AUTO_CRLF
if (c == '\n')
usart_putc('\r');
#endif
if (qfull(tx.head, tx.tail, Q_SIZE))
return;
cm_disable_interrupts();
tx.buf[tx.head] = c;
tx.head = qinc(tx.head, Q_SIZE);
cm_enable_interrupts();
/* kick the transmitter to restart interrupts */
usart_enable_tx_interrupt(USART_NUM);
}
#endif
void usbuart_init(void)
{
/* enable gpios */
gpio_config_special(PORTA, UART_TX_PIN, UART_PERIPH); /* tx pin */
gpio_config_special(PORTA, UART_RX_PIN, UART_PERIPH); /* rx pin */
/* enable clocking to sercom0 */
set_periph_clk(GCLK0, GCLK_ID_SERCOM0_CORE);
periph_clk_en(GCLK_ID_SERCOM0_CORE, 1);
//usart_enable(USART_NUM, current_baud);
usart_setup(USART_NUM, current_baud);
#ifndef DEBUG_ME
usart_set_pads(USART_NUM, 3, 0); /* bm-sam uses different pads */
#endif
usart_enable(USART_NUM, 0); /* baud==0 so setup is skipped */
usart_enable_rx_interrupt(USART_NUM);
usart_enable_tx_interrupt(USART_NUM);
}
static uint8_t convert_tdio_enabled;
int usbuart_convert_tdio(uint32_t arg)
{
(void) arg;
convert_tdio_enabled = arg;
if (!convert_tdio_enabled) {
usart_disable(1);
USART_NUM = 0;
usbuart_init();
return current_baud;
}
gpio_config_special(PORTA, TDI_PIN, UART_PERIPH_2); /* TX */
gpio_config_special(PORTA, TDO_PIN, UART_PERIPH_2); /* RX */
/* disable USART0 (we will be using USART1 now) */
usart_disable(0);
USART_NUM = 1;
/* Select and Enable system clock */
set_periph_clk(GCLK0, GCLK_ID_SERCOM1_CORE);
periph_clk_en(GCLK_ID_SERCOM1_CORE, 1);
usart_setup(1, current_baud);
usart_set_pads(1, 3, 0); /* uses different pads than the default */
usart_enable(1, 0); /* baud==0 so setup is skipped */
usart_enable_rx_interrupt(1);
usart_enable_tx_interrupt(1);
return current_baud;
}
int usbuart_convert_tdio_enabled(void)
{
return convert_tdio_enabled;
}
void usbuart_set_line_coding(struct usb_cdc_line_coding *coding)
{
uint8_t sbmode = (coding->bCharFormat == 2) ? 1 : 0;
uint8_t parity = (coding->bParityType == 1) ? 0 : 1;
uint8_t form = (coding->bParityType) ? 1 : 0;
uint8_t chsize = (form) ? coding->bDataBits + 1 : coding->bDataBits;
usart_disable(USART_NUM);
/* set baud rate */
usart_set_baudrate(USART_NUM, coding->dwDTERate);
/* set data size, stop mode, and parity */
usart_set_chsize(USART_NUM, chsize);
usart_set_sbmode(USART_NUM, sbmode);
usart_set_parity(USART_NUM, parity, form);
usart_enable(USART_NUM, 0);
current_baud = coding->dwDTERate;
}
#ifndef ENABLE_RTT
void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
{
(void)ep;
char buf[CDCACM_PACKET_SIZE];
int len = usbd_ep_read_packet(dev, CDCACM_UART_ENDPOINT,
buf, CDCACM_PACKET_SIZE);
gpio_set(LED_PORT_UART, LED_UART);
for(int i = 0; i < len; i++) {
usart_putc(buf[i]);
}
gpio_clear(LED_PORT_UART, LED_UART);
}
#endif
/* run by our systick timer */
void uart_pop(void)
{
if (cdcacm_get_config() != 1) {
return;
}
if (!qempty(rx.head, rx.tail)) {
if (usbd_ep_write_packet(usbdev, 0x83, &rx.buf[rx.tail], 1) == 0) {
return;
}
rx.tail = qinc(rx.tail, Q_SIZE);
}
}
void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep)
{
(void) dev;
(void) ep;
}
/************************** UART Interrupt Handlers *************************/
static void uart_rx_irq(void)
{
char c = UART(USART_NUM)->data;
/* bug?, need to re-enable rx complete interrupt */
INSERTBF(UART_INTENSET_RXC, 1, UART(USART_NUM)->intenset);
if (!qfull(rx.head, rx.tail, Q_SIZE)) {
rx.buf[rx.head] = c;
rx.head = qinc(rx.head, Q_SIZE);
}
}
static void uart_tx_irq(void)
{
if (!qempty(tx.head, tx.tail)) {
usart_send(USART_NUM, tx.buf[tx.tail]);
tx.tail = qinc(tx.tail, Q_SIZE);
} else {
usart_disable_tx_interrupt(USART_NUM);
}
}
void sercom0_isr(void)
{
/* Turn on LED */
gpio_set(LED_PORT_UART, LED_UART);
if (GETBF(UART_INTFLAG_RXC, UART(USART_NUM)->intflag))
uart_rx_irq();
if (GETBF(UART_INTFLAG_DRE, UART(USART_NUM)->intflag))
uart_tx_irq();
}
void sercom1_isr(void)
{
/* Turn on LED */
gpio_set(LED_PORT_UART, LED_UART);
if (GETBF(UART_INTFLAG_RXC, UART(USART_NUM)->intflag))
uart_rx_irq();
if (GETBF(UART_INTFLAG_DRE, UART(USART_NUM)->intflag))
uart_tx_irq();
}

View File

@ -0,0 +1,134 @@
/*
* 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 "platform.h"
#include <assert.h>
#include "cdcacm.h"
#include "rtt.h"
#include "rtt_if.h"
/*********************************************************************
*
* rtt terminal i/o
*
**********************************************************************
*/
/* usb uart receive buffer */
static char recv_buf[RTT_DOWN_BUF_SIZE];
static uint32_t recv_head = 0;
static uint32_t recv_tail = 0;
/* data from host to target: number of free bytes in usb receive buffer */
inline static uint32_t recv_bytes_free()
{
if (recv_tail <= recv_head)
return sizeof(recv_buf) - recv_head + recv_tail - 1;
else
return recv_tail - recv_head - 1;
}
/* data from host to target: true if not enough free buffer space and we need to close flow control */
inline static bool recv_set_nak()
{
assert(sizeof(recv_buf) > 2 * CDCACM_PACKET_SIZE);
return recv_bytes_free() < 2 * CDCACM_PACKET_SIZE;
}
/* usbuart_usb_out_cb is called when usb uart has received new data for target.
this routine has to be fast */
void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
{
(void)dev;
(void)ep;
char usb_buf[CDCACM_PACKET_SIZE];
/* close flow control while processing packet */
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 1);
const uint16_t len = usbd_ep_read_packet(usbdev, CDCACM_UART_ENDPOINT, usb_buf, CDCACM_PACKET_SIZE);
/* skip flag: drop packet if not enough free buffer space */
if (rtt_flag_skip && len > recv_bytes_free()) {
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0);
return;
}
/* copy data to recv_buf */
for (int i = 0; i < len; i++) {
uint32_t next_recv_head = (recv_head + 1) % sizeof(recv_buf);
if (next_recv_head == recv_tail)
break; /* overflow */
recv_buf[recv_head] = usb_buf[i];
recv_head = next_recv_head;
}
/* block flag: flow control closed if not enough free buffer space */
if (!(rtt_flag_block && recv_set_nak()))
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0);
return;
}
/* rtt host to target: read one character */
int32_t rtt_getchar()
{
int retval;
if (recv_head == recv_tail)
return -1;
retval = recv_buf[recv_tail];
recv_tail = (recv_tail + 1) % sizeof(recv_buf);
/* open flow control if enough free buffer space */
if (!recv_set_nak())
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0);
return retval;
}
/* rtt host to target: true if no characters available for reading */
bool rtt_nodata()
{
return recv_head == recv_tail;
}
/* rtt target to host: write string */
uint32_t rtt_write(const char *buf, uint32_t len)
{
if (len != 0 && usbdev && cdcacm_get_config() && cdcacm_get_dtr()) {
for (uint32_t p = 0; p < len; p += CDCACM_PACKET_SIZE) {
uint32_t plen = MIN(CDCACM_PACKET_SIZE, len - p);
while(usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, buf + p, plen) <= 0);
}
/* flush 64-byte packet on full-speed */
if (CDCACM_PACKET_SIZE == 64 && (len % CDCACM_PACKET_SIZE) == 0)
while(usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, NULL, 0) <= 0);
}
return len;
}

View File

@ -259,6 +259,7 @@ static void usbuart_change_dma_tx_buf(void)
buf_tx_act_idx ^= 1;
}
#ifndef ENABLE_RTT
void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
{
(void)ep;
@ -301,6 +302,7 @@ void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
if (TX_BUF_SIZE - buf_tx_act_sz >= CDCACM_PACKET_SIZE)
usbd_ep_nak_set(dev, CDCACM_UART_ENDPOINT, 0);
}
#endif
#ifdef USBUART_DEBUG
int usbuart_debug_write(const char *buf, size_t len)

View File

@ -99,6 +99,7 @@ void usbuart_set_line_coding(struct usb_cdc_line_coding *coding)
}
}
#ifndef ENABLE_RTT
void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
{
(void)ep;
@ -110,7 +111,7 @@ void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
for(int i = 0; i < len; i++)
uart_send_blocking(USBUART, buf[i]);
}
#endif
void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep)
{

456
src/rtt.c Normal file
View File

@ -0,0 +1,456 @@
/*
* 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 "platform.h"
#include "gdb_packet.h"
#include "target.h"
#include "target/target_internal.h"
#include "rtt.h"
#include "rtt_if.h"
bool rtt_enabled = false;
bool rtt_found = false;
static bool rtt_halt = false; // true if rtt needs to halt target to access memory
uint32_t rtt_cbaddr = 0;
bool rtt_auto_channel = true;
struct rtt_channel_struct rtt_channel[MAX_RTT_CHAN];
uint32_t rtt_min_poll_ms = 8; /* 8 ms */
uint32_t rtt_max_poll_ms = 256; /* 0.256 s */
uint32_t rtt_max_poll_errs = 10;
static uint32_t poll_ms;
static uint32_t poll_errs;
static uint32_t last_poll_ms;
/* flags for data from host to target */
bool rtt_flag_skip = false;
bool rtt_flag_block = false;
typedef enum rtt_retval {
RTT_OK,
RTT_IDLE,
RTT_ERR
} rtt_retval;
#ifdef RTT_IDENT
#define Q(x) #x
#define QUOTE(x) Q(x)
char rtt_ident[16] = QUOTE(RTT_IDENT);
#else
char rtt_ident[16] = {0};
#endif
/* usb uart transmit buffer */
static char xmit_buf[RTT_UP_BUF_SIZE];
/*********************************************************************
*
* rtt control block
*
**********************************************************************
*/
uint32_t fastsrch(target *cur_target)
{
const uint32_t m = 16;
const uint64_t q = 0x797a9691; /* prime */
const uint64_t rm = 0x73b07d01;
const uint64_t p = 0x444110cd;
const uint32_t stride = 128;
uint64_t t = 0;
uint8_t srch_buf[m+stride];
for (struct target_ram *r = cur_target->ram; r; r = r->next) {
const uint32_t ram_start = r->start;
const uint32_t ram_end = r->start + r->length;
t = 0;
memset(srch_buf, 0, sizeof(srch_buf));
for (uint32_t addr = ram_start; addr < ram_end; addr += stride) {
uint32_t buf_siz = MIN(stride, ram_end - addr);
memcpy(srch_buf, srch_buf + stride, m);
if (target_mem_read(cur_target, srch_buf + m, addr, buf_siz)) {
gdb_outf("rtt: read fail at 0x%" PRIx32 "\r\n", addr);
return 0;
}
for (uint32_t i = 0; i < buf_siz; i++) {
t = (t + q - rm * srch_buf[i] % q) % q;
t = ((t << 8) + srch_buf[i + m]) % q;
if (p == t) {
uint32_t offset = i - m + 1;
return addr + offset;
}
}
}
}
/* no match */
return 0;
}
uint32_t memsrch(target *cur_target)
{
char *srch_str = rtt_ident;
uint32_t srch_str_len = strlen(srch_str);
uint8_t srch_buf[128];
if (srch_str_len == 0 || srch_str_len > sizeof(srch_buf) / 2)
return 0;
if (rtt_cbaddr && !target_mem_read(cur_target, srch_buf, rtt_cbaddr, srch_str_len)
&& strncmp((const char *)(srch_buf), srch_str, srch_str_len) == 0)
/* still at same place */
return rtt_cbaddr;
for (struct target_ram *r = cur_target->ram; r; r = r->next) {
uint32_t ram_end = r->start + r->length;
for (uint32_t addr = r->start; addr < ram_end; addr += sizeof(srch_buf) - srch_str_len - 1) {
uint32_t buf_siz = MIN(ram_end - addr, sizeof(srch_buf));
if (target_mem_read(cur_target, srch_buf, addr, buf_siz)) {
gdb_outf("rtt: read fail at 0x%" PRIx32 "\r\n", addr);
continue;
}
for (uint32_t offset = 0; offset + srch_str_len + 1 < buf_siz; offset++) {
if (strncmp((const char *)(srch_buf + offset), srch_str, srch_str_len) == 0) {
uint32_t cb_addr = addr + offset;
return cb_addr;
}
}
}
}
return 0;
}
static void find_rtt(target *cur_target)
{
rtt_found = false;
poll_ms = rtt_max_poll_ms;
poll_errs = 0;
last_poll_ms = 0;
if (!cur_target || !rtt_enabled)
return;
if (rtt_ident[0] == 0)
rtt_cbaddr = fastsrch(cur_target);
else
rtt_cbaddr = memsrch(cur_target);
DEBUG_INFO("rtt: match at 0x%" PRIx32 "\r\n", rtt_cbaddr);
if (rtt_cbaddr) {
uint32_t num_buf[2];
int32_t num_up_buf;
int32_t num_down_buf;
if (target_mem_read(cur_target, num_buf, rtt_cbaddr + 16, sizeof(num_buf)))
return;
num_up_buf = num_buf[0];
num_down_buf = num_buf[1];
if (num_up_buf > 255 || num_down_buf > 255) {
gdb_out("rtt: bad cblock\r\n");
rtt_enabled = false;
return;
} else if (num_up_buf == 0 && num_down_buf == 0)
gdb_out("rtt: empty cblock\r\n");
for (int32_t i = 0; i < MAX_RTT_CHAN; i++) {
uint32_t buf_desc[6];
rtt_channel[i].is_configured = false;
rtt_channel[i].is_output = false;
rtt_channel[i].buf_addr = 0;
rtt_channel[i].buf_size = 0;
rtt_channel[i].head_addr = 0;
rtt_channel[i].tail_addr = 0;
rtt_channel[i].flag = 0;
if (i >= num_up_buf + num_down_buf)
continue;
if (target_mem_read(cur_target, buf_desc, rtt_cbaddr + 24 + i * 24, sizeof(buf_desc)))
return;
rtt_channel[i].is_output = i < num_up_buf;
rtt_channel[i].buf_addr = buf_desc[1];
rtt_channel[i].buf_size = buf_desc[2];
rtt_channel[i].head_addr = rtt_cbaddr + 24 + i * 24 + 12;
rtt_channel[i].tail_addr = rtt_cbaddr + 24 + i * 24 + 16;
rtt_channel[i].flag = buf_desc[5];
rtt_channel[i].is_configured = (rtt_channel[i].buf_addr != 0) && (rtt_channel[i].buf_size != 0);
}
/* auto channel: enable output channels 0 and 1 and first input channel */
if (rtt_auto_channel) {
for (uint32_t i = 0; i < MAX_RTT_CHAN; i++)
rtt_channel[i].is_enabled = false;
rtt_channel[0].is_enabled = num_up_buf > 0;
rtt_channel[1].is_enabled = num_up_buf > 1;
if ((num_up_buf < MAX_RTT_CHAN) && (num_down_buf > 0))
rtt_channel[num_up_buf].is_enabled = true;
}
/* get flags for data from host to target */
rtt_flag_skip = false;
rtt_flag_block = false;
for (uint32_t i = 0; i < MAX_RTT_CHAN; i++)
if (rtt_channel[i].is_enabled && rtt_channel[i].is_configured && !rtt_channel[i].is_output) {
rtt_flag_skip = rtt_channel[i].flag == 0;
rtt_flag_block = rtt_channel[i].flag == 2;
break;
}
rtt_found = true;
DEBUG_INFO("rtt found\n");
}
return;
}
/*********************************************************************
*
* rtt from host to target
*
**********************************************************************
*/
/* poll if host has new data for target */
static rtt_retval read_rtt(target *cur_target, uint32_t i)
{
uint32_t head_tail[2];
uint32_t buf_head;
uint32_t buf_tail;
uint32_t next_head;
int ch;
/* copy data from recv_buf to target rtt 'down' buffer */
if (rtt_nodata())
return RTT_IDLE;
if (cur_target == NULL || rtt_channel[i].is_output || rtt_channel[i].buf_addr == 0 || rtt_channel[i].buf_size == 0)
return RTT_IDLE;
/* read down buffer head and tail from target */
if (target_mem_read(cur_target, head_tail, rtt_channel[i].head_addr, sizeof(head_tail)))
return RTT_ERR;
buf_head = head_tail[0];
buf_tail = head_tail[1];
if (buf_head >= rtt_channel[i].buf_size || buf_tail >= rtt_channel[i].buf_size)
return RTT_ERR;
/* write recv_buf to target rtt 'down' buf */
while ((next_head = ((buf_head + 1) % rtt_channel[i].buf_size)) != buf_tail && (ch = rtt_getchar()) != -1) {
if (target_mem_write(cur_target, rtt_channel[i].buf_addr + buf_head, &ch, 1))
return RTT_ERR;
/* advance pointers */
buf_head = next_head;
}
/* update head of target 'down' buffer */
if (target_mem_write(cur_target, rtt_channel[i].head_addr, &buf_head, sizeof(buf_head)))
return RTT_ERR;
return RTT_OK;
}
/*********************************************************************
*
* rtt from target to host
*
**********************************************************************
*/
/* target_mem_read, word aligned for speed.
note: dest has to be len + 8 bytes, to allow for alignment and padding.
*/
int target_aligned_mem_read(target *t, void *dest, target_addr src, size_t len)
{
uint32_t src0 = src;
uint32_t len0 = len;
uint32_t offset = src & 0x3;
src0 -= offset;
len0 += offset;
if ((len0 & 0x3) != 0)
len0 = (len0 + 4) & ~0x3;
if (src0 == src && len0 == len)
return target_mem_read(t, dest, src, len);
else {
uint32_t retval = target_mem_read(t, dest, src0, len0);
memmove(dest, dest + offset, len);
return retval;
}
}
/* poll if target has new data for host */
static rtt_retval print_rtt(target *cur_target, uint32_t i)
{
uint32_t head;
uint32_t tail;
if (!cur_target || !rtt_channel[i].is_output || rtt_channel[i].buf_addr == 0 || rtt_channel[i].head_addr == 0)
return RTT_IDLE;
uint32_t head_tail[2];
if (target_mem_read(cur_target, head_tail, rtt_channel[i].head_addr, sizeof(head_tail)))
return RTT_ERR;
head = head_tail[0];
tail = head_tail[1];
if (head >= rtt_channel[i].buf_size || tail >= rtt_channel[i].buf_size)
return RTT_ERR;
else if (head == tail)
return RTT_IDLE;
uint32_t bytes_free = sizeof(xmit_buf) - 8; /* need 8 bytes for alignment and padding */
uint32_t bytes_read = 0;
if (tail > head) {
uint32_t len = rtt_channel[i].buf_size - tail;
if (len > bytes_free)
len = bytes_free;
if (target_aligned_mem_read(cur_target, xmit_buf + bytes_read, rtt_channel[i].buf_addr + tail, len))
return RTT_ERR;
bytes_free -= len;
bytes_read += len;
tail = (tail + len) % rtt_channel[i].buf_size;
}
if (head > tail && bytes_free > 0) {
uint32_t len = head - tail;
if (len > bytes_free)
len = bytes_free;
if (target_aligned_mem_read(cur_target, xmit_buf + bytes_read, rtt_channel[i].buf_addr + tail, len))
return RTT_ERR;
bytes_read += len;
tail = (tail + len) % rtt_channel[i].buf_size;
}
/* update tail on target */
if (target_mem_write(cur_target, rtt_channel[i].tail_addr, &tail, sizeof(tail)))
return RTT_ERR;
/* write buffer to usb */
rtt_write(xmit_buf, bytes_read);
return RTT_OK;
}
/*********************************************************************
*
* target background memory access
*
**********************************************************************
*/
/* target_no_background_memory_access() is true if the target needs to be halted during jtag memory access
target_no_background_memory_access() is false if the target allows jtag memory access while running */
bool target_no_background_memory_access(target *cur_target)
{
/* if error message is 'rtt: read fail at' add target to expression below.
As a first approximation, assume all arm processors allow memory access while running, and no riscv does. */
bool riscv_core = cur_target && target_core_name(cur_target) && strstr(target_core_name(cur_target), "RVDBG");
return riscv_core;
}
/*********************************************************************
*
* rtt top level
*
**********************************************************************
*/
void poll_rtt(target *cur_target)
{
/* rtt off */
if (!cur_target || !rtt_enabled)
return;
/* target present and rtt enabled */
uint32_t now = platform_time_ms();
bool rtt_err = false;
bool rtt_busy = false;
if (last_poll_ms + poll_ms <= now || now < last_poll_ms) {
target_addr watch;
enum target_halt_reason reason;
bool resume_target = false;
if (!rtt_found)
/* check if target needs to be halted during memory access */
rtt_halt = target_no_background_memory_access(cur_target);
if (rtt_halt && target_halt_poll(cur_target, &watch) == TARGET_HALT_RUNNING) {
/* briefly halt target during target memory access */
target_halt_request(cur_target);
while((reason = target_halt_poll(cur_target, &watch)) == TARGET_HALT_RUNNING)
continue;
resume_target = reason == TARGET_HALT_REQUEST;
}
if (!rtt_found)
/* find rtt control block in target memory */
find_rtt(cur_target);
/* do rtt i/o if control block found */
if (rtt_found) {
for (uint32_t i = 0; i < MAX_RTT_CHAN; i++) {
rtt_retval v;
if (rtt_channel[i].is_enabled && rtt_channel[i].is_configured) {
if (rtt_channel[i].is_output)
v = print_rtt(cur_target, i);
else
v = read_rtt(cur_target, i);
if (v == RTT_OK) rtt_busy = true;
else if (v == RTT_ERR) rtt_err = true;
}
}
}
/* continue target if halted */
if (resume_target)
target_halt_resume(cur_target, false);
/* update last poll time */
last_poll_ms = now;
/* rtt polling frequency goes up and down with rtt activity */
if (rtt_busy && !rtt_err)
poll_ms /= 2;
else
poll_ms *= 2;
if (poll_ms > rtt_max_poll_ms)
poll_ms = rtt_max_poll_ms;
else if (poll_ms < rtt_min_poll_ms)
poll_ms = rtt_min_poll_ms;
if (rtt_err) {
gdb_out("rtt: err\r\n");
poll_errs++;
if (rtt_max_poll_errs != 0 && poll_errs > rtt_max_poll_errs) {
gdb_out("\r\nrtt lost\r\n");
rtt_enabled = false;
}
}
}
return;
}

View File

@ -68,7 +68,7 @@ bool firmware_dp_low_write(ADIv5_DP_t *dp, uint16_t addr, const uint32_t data)
int adiv5_swdp_scan(uint32_t targetid)
{
volatile struct exception e;
target_list_free();
static bool scan_multidrop = true;
ADIv5_DP_t idp = {
.dp_low_write = firmware_dp_low_write,
.error = firmware_swdp_error,
@ -77,6 +77,7 @@ int adiv5_swdp_scan(uint32_t targetid)
.abort = firmware_swdp_abort,
};
ADIv5_DP_t *initial_dp = &idp;
target_list_free();
if (swdptap_init(initial_dp))
return -1;
/* DORMANT-> SWD sequence*/
@ -93,7 +94,6 @@ int adiv5_swdp_scan(uint32_t targetid)
initial_dp->seq_out(0x1a0, 12);
uint32_t idcode = 0;
volatile uint32_t target_id = 0;
bool scan_multidrop = true;
if (!targetid || !initial_dp->dp_low_write) {
/* No targetID given on the command line or probe can not
* handle multi-drop. Try to read ID */

View File

@ -18,12 +18,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* This file implements CH32F1xx target specific functions.
/* This file implements CH32F1xx target specific functions.
The ch32 flash is rather slow so this code is using the so called fast mode (ch32 specific).
128 bytes are copied to a write buffer, then the write buffer is committed to flash
/!\ There is some sort of bus stall/bus arbitration going on that does NOT work when
programmed through SWD/jtag
The workaround is to wait a few cycles before filling the write buffer. This is performed by reading the flash a few times
The workaround is to wait a few cycles before filling the write buffer. This is performed by reading the flash a few times
*/
@ -32,29 +32,20 @@
#include "target_internal.h"
#include "cortexm.h"
#if PC_HOSTED == 1
#define DEBUG_CH DEBUG_INFO
#define ERROR_CH DEBUG_WARN
#else
#define DEBUG_CH(...) {} //DEBUG_WARN //(...) {}
#define ERROR_CH DEBUG_WARN //DEBUG_WARN
#endif
extern const struct command_s stm32f1_cmd_list[]; // Reuse stm32f1 stuff
static int ch32f1_flash_erase(struct target_flash *f,
target_addr addr, size_t len);
static int ch32f1_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
static int ch32f1_flash_erase(struct target_flash *f,
target_addr addr, size_t len);
static int ch32f1_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
// these are common with stm32f1/gd32f1/...
#define FPEC_BASE 0x40022000
#define FLASH_ACR (FPEC_BASE+0x00)
#define FLASH_KEYR (FPEC_BASE+0x04)
#define FLASH_SR (FPEC_BASE+0x0C)
#define FLASH_CR (FPEC_BASE+0x10)
#define FLASH_AR (FPEC_BASE+0x14)
#define FLASH_ACR (FPEC_BASE + 0x00)
#define FLASH_KEYR (FPEC_BASE + 0x04)
#define FLASH_SR (FPEC_BASE + 0x0C)
#define FLASH_CR (FPEC_BASE + 0x10)
#define FLASH_AR (FPEC_BASE + 0x14)
#define FLASH_CR_LOCK (1 << 7)
#define FLASH_CR_STRT (1 << 6)
#define FLASH_SR_BSY (1 << 0)
@ -66,19 +57,16 @@ extern const struct command_s stm32f1_cmd_list[]; // Reuse stm32f1 stuff
#define FLASHSIZE 0x1FFFF7E0
// these are specific to ch32f1
#define FLASH_MAGIC (FPEC_BASE+0x34)
#define FLASH_MODEKEYR_CH32 (FPEC_BASE+0x24) // Fast mode for CH32F10x
#define FLASH_CR_FLOCK_CH32 (1<<15) // fast unlock
#define FLASH_CR_FTPG_CH32 (1<<16) // fast page program
#define FLASH_CR_FTER_CH32 (1<<17) // fast page erase
#define FLASH_CR_BUF_LOAD_CH32 (1<<18) // Buffer load
#define FLASH_CR_BUF_RESET_CH32 (1<<19) // Buffer reset
#define FLASH_SR_EOP (1<<5) // End of programming
#define FLASH_MAGIC (FPEC_BASE + 0x34)
#define FLASH_MODEKEYR_CH32 (FPEC_BASE + 0x24) // Fast mode for CH32F10x
#define FLASH_CR_FLOCK_CH32 (1 << 15) // fast unlock
#define FLASH_CR_FTPG_CH32 (1 << 16) // fast page program
#define FLASH_CR_FTER_CH32 (1 << 17) // fast page erase
#define FLASH_CR_BUF_LOAD_CH32 (1 << 18) // Buffer load
#define FLASH_CR_BUF_RESET_CH32 (1 << 19) // Buffer reset
#define FLASH_SR_EOP (1 << 5) // End of programming
#define FLASH_BEGIN_ADDRESS_CH32 0x8000000
/**
\fn ch32f1_add_flash
\brief "fast" flash driver for CH32F10x chips
@ -101,38 +89,41 @@ static void ch32f1_add_flash(target *t, uint32_t addr, size_t length, size_t era
target_add_flash(t, f);
}
#define WAIT_BUSY() do { \
sr = target_mem_read32(t, FLASH_SR); \
if(target_check_error(t)) { \
ERROR_CH("ch32f1 flash write: comm error\n"); \
return -1; \
} \
} while (sr & FLASH_SR_BSY);
#define WAIT_BUSY() do { \
sr = target_mem_read32(t, FLASH_SR); \
if (target_check_error(t)) { \
DEBUG_WARN("ch32f1 flash write: comm error\n"); \
return -1; \
} \
} while (sr & FLASH_SR_BSY);
#define WAIT_EOP() do { \
sr = target_mem_read32(t, FLASH_SR); \
if(target_check_error(t)) { \
ERROR_CH("ch32f1 flash write: comm error\n"); \
return -1; \
} \
} while (!(sr & FLASH_SR_EOP));
#define WAIT_EOP() do { \
sr = target_mem_read32(t, FLASH_SR); \
if (target_check_error(t)) { \
DEBUG_WARN("ch32f1 flash write: comm error\n"); \
return -1; \
} \
} while (!(sr & FLASH_SR_EOP));
#define CLEAR_EOP() target_mem_write32(t, FLASH_SR,FLASH_SR_EOP)
#define CLEAR_EOP() target_mem_write32(t, FLASH_SR,FLASH_SR_EOP)
#define SET_CR(bit) { ct = target_mem_read32(t, FLASH_CR); \
ct|=(bit); \
target_mem_write32(t, FLASH_CR, ct);}
#define SET_CR(bit) do { \
const uint32_t cr = target_mem_read32(t, FLASH_CR) | (bit); \
target_mem_write32(t, FLASH_CR, cr); \
} while(0)
#define CLEAR_CR(bit) {ct = target_mem_read32(t, FLASH_CR); \
ct&=~(bit); \
target_mem_write32(t, FLASH_CR, ct);}
#define CLEAR_CR(bit) do { \
const uint32_t cr = target_mem_read32(t, FLASH_CR) & (~(bit)); \
target_mem_write32(t, FLASH_CR, cr); \
} while(0)
// Which one is the right value ?
#define MAGIC_WORD 0x100
// #define MAGIC_WORD 0x1000
#define MAGIC(adr) { magic=target_mem_read32(t,(adr) ^ MAGIC_WORD); \
target_mem_write32(t, FLASH_MAGIC , magic); }
#define MAGIC(addr) do { \
magic = target_mem_read32(t, (addr) ^ MAGIC_WORD); \
target_mem_write32(t, FLASH_MAGIC , magic); \
} while(0)
/**
\fn ch32f1_flash_unlock
@ -140,24 +131,24 @@ static void ch32f1_add_flash(target *t, uint32_t addr, size_t length, size_t era
*/
static int ch32f1_flash_unlock(target *t)
{
DEBUG_CH("CH32: flash unlock \n");
DEBUG_INFO("CH32: flash unlock \n");
target_mem_write32(t, FLASH_KEYR , KEY1);
target_mem_write32(t, FLASH_KEYR , KEY2);
target_mem_write32(t, FLASH_KEYR, KEY1);
target_mem_write32(t, FLASH_KEYR, KEY2);
// fast mode
target_mem_write32(t, FLASH_MODEKEYR_CH32 , KEY1);
target_mem_write32(t, FLASH_MODEKEYR_CH32 , KEY2);
target_mem_write32(t, FLASH_MODEKEYR_CH32, KEY1);
target_mem_write32(t, FLASH_MODEKEYR_CH32, KEY2);
uint32_t cr = target_mem_read32(t, FLASH_CR);
if (cr & FLASH_CR_FLOCK_CH32){
ERROR_CH("Fast unlock failed, cr: 0x%08" PRIx32 "\n", cr);
if (cr & FLASH_CR_FLOCK_CH32) {
DEBUG_WARN("Fast unlock failed, cr: 0x%08" PRIx32 "\n", cr);
return -1;
}
return 0;
}
static int ch32f1_flash_lock(target *t)
{
volatile uint32_t ct;
DEBUG_CH("CH32: flash lock \n");
DEBUG_INFO("CH32: flash lock \n");
SET_CR(FLASH_CR_LOCK);
return 0;
}
@ -166,56 +157,55 @@ static int ch32f1_flash_lock(target *t)
\brief identify the ch32f1 chip
Actually grab all cortex m3 with designer = arm not caught earlier...
*/
bool ch32f1_probe(target *t)
{
t->idcode = target_mem_read32(t, DBGMCU_IDCODE) & 0xfff;
if ((t->cpuid & CPUID_PARTNO_MASK) != CORTEX_M3)
return false;
if(t->idcode !=0x410) { // only ch32f103
const uint32_t idcode = target_mem_read32(t, DBGMCU_IDCODE) & 0x00000fffU;
if (idcode != 0x410) // only ch32f103
return false;
}
// try to flock
ch32f1_flash_lock(t);
// if this fails it is not a CH32 chip
if(ch32f1_flash_unlock(t)) {
if (ch32f1_flash_unlock(t))
return false;
}
t->idcode = idcode;
uint32_t signature = target_mem_read32(t, FLASHSIZE);
uint32_t flashSize = signature & 0xFFFF;
target_add_ram(t, 0x20000000, 0x5000);
ch32f1_add_flash(t, FLASH_BEGIN_ADDRESS_CH32, flashSize*1024, 128);
ch32f1_add_flash(t, FLASH_BEGIN_ADDRESS_CH32, flashSize * 1024, 128);
target_add_commands(t, stm32f1_cmd_list, "STM32 LD/MD/VL-LD/VL-MD");
t->driver = "CH32F1 medium density (stm32f1 clone)";
return true;
}
/**
\fn ch32f1_flash_erase
\brief fast erase of CH32
*/
int ch32f1_flash_erase (struct target_flash *f, target_addr addr, size_t len)
int ch32f1_flash_erase(struct target_flash *f, target_addr addr, size_t len)
{
volatile uint32_t ct, sr, magic;
volatile uint32_t sr, magic;
target *t = f->t;
DEBUG_CH("CH32: flash erase \n");
DEBUG_INFO("CH32: flash erase \n");
if (ch32f1_flash_unlock(t)) {
ERROR_CH("CH32: Unlock failed\n");
DEBUG_WARN("CH32: Unlock failed\n");
return -1;
}
// Fast Erase 128 bytes pages (ch32 mode)
while(len) {
while (len) {
SET_CR(FLASH_CR_FTER_CH32);// CH32 PAGE_ER
/* write address to FMA */
target_mem_write32(t, FLASH_AR , addr);
target_mem_write32(t, FLASH_AR, addr);
/* Flash page erase start instruction */
SET_CR( FLASH_CR_STRT );
SET_CR(FLASH_CR_STRT);
WAIT_EOP();
CLEAR_EOP();
CLEAR_CR( FLASH_CR_STRT );
CLEAR_CR(FLASH_CR_STRT);
// Magic
MAGIC(addr);
if (len > 128)
@ -226,8 +216,8 @@ int ch32f1_flash_erase (struct target_flash *f, target_addr addr, size_t len)
}
sr = target_mem_read32(t, FLASH_SR);
ch32f1_flash_lock(t);
if ((sr & SR_ERROR_MASK)) {
ERROR_CH("ch32f1 flash erase error 0x%" PRIx32 "\n", sr);
if (sr & SR_ERROR_MASK) {
DEBUG_WARN("ch32f1 flash erase error 0x%" PRIx32 "\n", sr);
return -1;
}
return 0;
@ -241,39 +231,38 @@ int ch32f1_flash_erase (struct target_flash *f, target_addr addr, size_t len)
NB: Just reading fff is not enough as it could be a transient previous operation value
*/
static bool ch32f1_wait_flash_ready(target *t,uint32_t adr)
static bool ch32f1_wait_flash_ready(target *t, uint32_t addr)
{
uint32_t ff;
for(int i = 0; i < 32; i++) {
ff = target_mem_read32(t,adr);
}
if(ff != 0xffffffffUL) {
ERROR_CH("ch32f1 Not erased properly at %x or flash access issue\n",adr);
return false;
}
return true;
uint32_t ff = 0;
for (size_t i = 0; i < 32; i++)
ff = target_mem_read32(t, addr);
if (ff != 0xffffffffUL) {
DEBUG_WARN("ch32f1 Not erased properly at %" PRIx32 " or flash access issue\n", addr);
return false;
}
return true;
}
/**
\fn ch32f1_flash_write
\brief fast flash for ch32. Load 128 bytes chunk and then flash them
*/
static int ch32f1_upload(target *t, uint32_t dest, const void *src, uint32_t offset)
static int ch32f1_upload(target *t, uint32_t dest, const void *src, uint32_t offset)
{
volatile uint32_t ct, sr, magic;
volatile uint32_t sr, magic;
const uint32_t *ss = (const uint32_t *)(src+offset);
uint32_t dd = dest+offset;
uint32_t dd = dest + offset;
SET_CR(FLASH_CR_FTPG_CH32);
target_mem_write32(t, dd+0,ss[0]);
target_mem_write32(t, dd+4,ss[1]);
target_mem_write32(t, dd+8,ss[2]);
target_mem_write32(t, dd+12,ss[3]);
target_mem_write32(t, dd + 0, ss[0]);
target_mem_write32(t, dd + 4, ss[1]);
target_mem_write32(t, dd + 8, ss[2]);
target_mem_write32(t, dd + 12, ss[3]);
SET_CR(FLASH_CR_BUF_LOAD_CH32); /* BUF LOAD */
WAIT_EOP();
CLEAR_EOP();
CLEAR_CR(FLASH_CR_FTPG_CH32);
MAGIC((dest+offset));
MAGIC(dest + offset);
return 0;
}
/**
@ -282,12 +271,12 @@ static int ch32f1_upload(target *t, uint32_t dest, const void *src, uint32_t of
*/
int ch32f1_buffer_clear(target *t)
{
volatile uint32_t ct,sr;
SET_CR(FLASH_CR_FTPG_CH32); // Fast page program 4-
SET_CR(FLASH_CR_BUF_RESET_CH32); // BUF_RESET 5-
WAIT_BUSY(); // 6-
CLEAR_CR(FLASH_CR_FTPG_CH32); // Fast page program 4-
return 0;
volatile uint32_t sr;
SET_CR(FLASH_CR_FTPG_CH32); // Fast page program 4-
SET_CR(FLASH_CR_BUF_RESET_CH32); // BUF_RESET 5-
WAIT_BUSY(); // 6-
CLEAR_CR(FLASH_CR_FTPG_CH32); // Fast page program 4-
return 0;
}
//#define CH32_VERIFY
@ -295,21 +284,21 @@ int ch32f1_buffer_clear(target *t)
*/
static int ch32f1_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len)
target_addr dest, const void *src, size_t len)
{
volatile uint32_t ct, sr, magic;
volatile uint32_t sr, magic;
target *t = f->t;
size_t length = len;
#ifdef CH32_VERIFY
target_addr orgDest=dest;
const void *orgSrc=src;
target_addr org_dest = dest;
const void *org_src = src;
#endif
DEBUG_CH("CH32: flash write 0x%x ,size=%d\n",dest,len);
DEBUG_INFO("CH32: flash write 0x%" PRIx32 " ,size=%zu\n", dest, len);
while(length > 0)
while (length > 0)
{
if(ch32f1_flash_unlock(t)) {
ERROR_CH("ch32f1 cannot fast unlock\n");
if (ch32f1_flash_unlock(t)) {
DEBUG_WARN("ch32f1 cannot fast unlock\n");
return -1;
}
WAIT_BUSY();
@ -317,12 +306,12 @@ static int ch32f1_flash_write(struct target_flash *f,
// Buffer reset...
ch32f1_buffer_clear(t);
// Load 128 bytes to buffer
if(!ch32f1_wait_flash_ready(t,dest)) {
if (!ch32f1_wait_flash_ready(t,dest))
return -1;
}
for(int i = 0; i < 8; i++) {
if(ch32f1_upload(t,dest,src, 16*i)) {
ERROR_CH("Cannot upload to buffer\n");
for (size_t i = 0; i < 8; i++) {
if (ch32f1_upload(t, dest, src, i * 16U)) {
DEBUG_WARN("Cannot upload to buffer\n");
return -1;
}
}
@ -334,11 +323,11 @@ static int ch32f1_flash_write(struct target_flash *f,
CLEAR_EOP();
CLEAR_CR(FLASH_CR_FTPG_CH32);
MAGIC((dest));
MAGIC(dest);
// next
if(length > 128)
length -=128;
if (length > 128)
length -=128;
else
length = 0;
dest += 128;
@ -346,24 +335,23 @@ static int ch32f1_flash_write(struct target_flash *f,
sr = target_mem_read32(t, FLASH_SR); // 13
ch32f1_flash_lock(t);
if ((sr & SR_ERROR_MASK) ) {
ERROR_CH("ch32f1 flash write error 0x%" PRIx32 "\n", sr);
if (sr & SR_ERROR_MASK) {
DEBUG_WARN("ch32f1 flash write error 0x%" PRIx32 "\n", sr);
return -1;
}
}
#ifdef CH32_VERIFY
DEBUG_CH("Verifying\n");
size_t i = 0;
for(i = 0; i < len; i+= 4)
DEBUG_INFO("Verifying\n");
for (size_t i = 0; i < len; i += 4)
{
uint32_t mem=target_mem_read32(t, orgDest+i);
uint32_t mem2=*(uint32_t *)(orgSrc+i);
if(mem!=mem2)
const uint32_t expected = *(uint32_t *)(org_src + i);
const uint32_t actual = target_mem_read32(t, org_dest + i);
if (expected != actual)
{
ERROR_CH(">>>>write mistmatch at address 0x%x\n",orgDest+i);
ERROR_CH(">>>>expected 0x%x\n",mem2);
ERROR_CH(">>>>flash 0x%x\n",mem);
DEBUG_WARN(">>>>write mistmatch at address 0x%x\n", org_dest + i);
DEBUG_WARN(">>>>expected: 0x%x\n", expected);
DEBUG_WARN(">>>> actual: 0x%x\n", actual);
return -1;
}
}
@ -371,4 +359,3 @@ static int ch32f1_flash_write(struct target_flash *f,
return 0;
}
// EOF

View File

@ -378,8 +378,25 @@ bool cortexm_probe(ADIv5_AP_t *ap)
} else {
target_check_error(t);
}
#if PC_HOSTED
#define STRINGIFY(x) #x
#define PROBE(x) \
do { if ((x)(t)) {return true;} else target_check_error(t); } while (0)
do { \
DEBUG_INFO("Calling " STRINGIFY(x) "\n"); \
if ((x)(t)) \
return true; \
else \
target_check_error(t); \
} while (0)
#else
#define PROBE(x) \
do { \
if ((x)(t)) \
return true; \
else \
target_check_error(t); \
} while (0)
#endif
switch (ap->ap_designer) {
case AP_DESIGNER_FREESCALE:
@ -502,7 +519,7 @@ bool cortexm_attach(target *t)
priv->flash_patch_revision = (r >> 28);
priv->hw_watchpoint_max = CORTEXM_MAX_WATCHPOINTS;
r = target_mem_read32(t, CORTEXM_DWT_CTRL);
if ((r >> 28) > priv->hw_watchpoint_max)
if ((r >> 28) < priv->hw_watchpoint_max)
priv->hw_watchpoint_max = r >> 28;
/* Clear any stale breakpoints */
@ -675,7 +692,7 @@ static int dcrsr_regnum(target *t, unsigned reg)
return regnum_cortex_m[reg];
} else if ((t->target_options & TOPT_FLAVOUR_V7MF) &&
(reg < (sizeof(regnum_cortex_m) +
sizeof(regnum_cortex_mf) / 4))) {
sizeof(regnum_cortex_mf)) / 4)) {
return regnum_cortex_mf[reg - sizeof(regnum_cortex_m)/4];
} else {
return -1;

View File

@ -37,77 +37,96 @@
#include "general.h"
#include "target.h"
#include "target_internal.h"
#include "adiv5.h"
#define SIM_SDID 0x40048024
#define SIM_FCFG1 0x4004804C
#define KINETIS_MDM_IDR_K22F 0x1c0000
#define KINETIS_MDM_IDR_KZ03 0x1c0020
#define FTFA_BASE 0x40020000
#define FTFA_FSTAT (FTFA_BASE + 0x00)
#define FTFA_FCNFG (FTFA_BASE + 0x01)
#define FTFA_FSEC (FTFA_BASE + 0x02)
#define FTFA_FOPT (FTFA_BASE + 0x03)
#define FTFA_FCCOB_0 (FTFA_BASE + 0x04)
#define FTFA_FCCOB_1 (FTFA_BASE + 0x08)
#define FTFA_FCCOB_2 (FTFA_BASE + 0x0C)
#define MDM_STATUS ADIV5_AP_REG(0x00)
#define MDM_CONTROL ADIV5_AP_REG(0x04)
#define FTFA_FSTAT_CCIF (1 << 7)
#define FTFA_FSTAT_RDCOLERR (1 << 6)
#define FTFA_FSTAT_ACCERR (1 << 5)
#define FTFA_FSTAT_FPVIOL (1 << 4)
#define FTFA_FSTAT_MGSTAT0 (1 << 0)
#define MDM_STATUS_MASS_ERASE_ACK (1 << 0)
#define MDM_STATUS_FLASH_READY (1 << 1)
#define MDM_STATUS_MASS_ERASE_ENABLED (1 << 5)
#define MDM_STATUS_BACK_KEY_ENABLED (1 << 6)
#define FTFA_CMD_CHECK_ERASE 0x01
#define FTFA_CMD_PROGRAM_CHECK 0x02
#define FTFA_CMD_READ_RESOURCE 0x03
#define FTFA_CMD_PROGRAM_LONGWORD 0x06
#define MDM_CONTROL_MASS_ERASE (1 << 0)
#define MDM_CONTROL_SYS_RESET (1 << 3)
#define SIM_SDID 0x40048024
#define SIM_FCFG1 0x4004804C
#define FLASH_SECURITY_BYTE_ADDRESS 0x40C
#define FLASH_SECURITY_BYTE_UNSECURED 0xFE
#define FTFx_BASE 0x40020000
#define FTFx_FSTAT (FTFx_BASE + 0x00)
#define FTFx_FCNFG (FTFx_BASE + 0x01)
#define FTFx_FSEC (FTFx_BASE + 0x02)
#define FTFx_FOPT (FTFx_BASE + 0x03)
#define FTFx_FCCOB0 (FTFx_BASE + 0x04)
#define FTFx_FCCOB4 (FTFx_BASE + 0x08)
#define FTFx_FCCOB8 (FTFx_BASE + 0x0C)
#define FTFx_FSTAT_CCIF (1 << 7)
#define FTFx_FSTAT_RDCOLERR (1 << 6)
#define FTFx_FSTAT_ACCERR (1 << 5)
#define FTFx_FSTAT_FPVIOL (1 << 4)
#define FTFx_FSTAT_MGSTAT0 (1 << 0)
#define FTFx_FSEC_KEYEN_MSK (0b11 << 6)
#define FTFx_FSEC_KEYEN (0b10 << 6)
#define FTFx_CMD_CHECK_ERASE 0x01
#define FTFx_CMD_PROGRAM_CHECK 0x02
#define FTFx_CMD_READ_RESOURCE 0x03
#define FTFx_CMD_PROGRAM_LONGWORD 0x06
/* Part of the FTFE module for K64 */
#define FTFE_CMD_PROGRAM_PHRASE 0x07
#define FTFA_CMD_ERASE_SECTOR 0x09
#define FTFA_CMD_CHECK_ERASE_ALL 0x40
#define FTFA_CMD_READ_ONCE 0x41
#define FTFA_CMD_PROGRAM_ONCE 0x43
#define FTFA_CMD_ERASE_ALL 0x44
#define FTFA_CMD_BACKDOOR_ACCESS 0x45
#define FTFx_CMD_PROGRAM_PHRASE 0x07
#define FTFx_CMD_ERASE_SECTOR 0x09
#define FTFx_CMD_CHECK_ERASE_ALL 0x40
#define FTFx_CMD_READ_ONCE 0x41
#define FTFx_CMD_PROGRAM_ONCE 0x43
#define FTFx_CMD_ERASE_ALL 0x44
#define FTFx_CMD_BACKDOOR_ACCESS 0x45
#define KL_WRITE_LEN 4
/* 8 byte phrases need to be written to the k64 flash */
#define K64_WRITE_LEN 8
static bool kinetis_cmd_unsafe(target *t, int argc, char *argv[]);
static bool kinetis_cmd_unsafe(target *t, int argc, char **argv);
const struct command_s kinetis_cmd_list[] = {
{"unsafe", (cmd_handler)kinetis_cmd_unsafe, "Allow programming security byte (enable|disable)"},
{NULL, NULL, NULL}
{NULL, NULL, NULL},
};
static bool kinetis_cmd_unsafe(target *t, int argc, char *argv[])
static bool kinetis_cmd_unsafe(target *t, int argc, char **argv)
{
if (argc == 1) {
tc_printf(t, "Allow programming security byte: %s\n",
t->unsafe_enabled ? "enabled" : "disabled");
tc_printf(t, "Allow programming security byte: %s\n", t->unsafe_enabled ? "enabled" : "disabled");
} else {
parse_enable_or_disable(argv[1], &t->unsafe_enabled);
}
return true;
}
static int kl_gen_flash_erase(struct target_flash *f, target_addr addr, size_t len);
static int kl_gen_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
static int kl_gen_flash_done(struct target_flash *f);
static int kinetis_flash_cmd_erase(struct target_flash *f, target_addr addr, size_t len);
static int kinetis_flash_cmd_write(struct target_flash *f, target_addr dest, const void *src, size_t len);
static int kinetis_flash_done(struct target_flash *f);
struct kinetis_flash {
struct target_flash f;
uint8_t write_len;
};
static void kl_gen_add_flash(target *t, uint32_t addr, size_t length,
size_t erasesize, size_t write_len)
static void kinetis_add_flash(
target *const t, const uint32_t addr, const size_t length, const size_t erasesize, const size_t write_len)
{
struct kinetis_flash *kf = calloc(1, sizeof(*kf));
struct target_flash *f;
if (!kf) { /* calloc failed: heap exhaustion */
if (!kf) { /* calloc failed: heap exhaustion */
DEBUG_WARN("calloc: failed in %s\n", __func__);
return;
}
@ -116,15 +135,26 @@ static void kl_gen_add_flash(target *t, uint32_t addr, size_t length,
f->start = addr;
f->length = length;
f->blocksize = erasesize;
f->erase = kl_gen_flash_erase;
f->write = kl_gen_flash_write;
f->done = kl_gen_flash_done;
f->erase = kinetis_flash_cmd_erase;
f->write = kinetis_flash_cmd_write;
f->done = kinetis_flash_done;
f->erased = 0xff;
kf->write_len = write_len;
target_add_flash(t, f);
}
bool kinetis_probe(target *t)
static void kl_s32k14_setup(
target *const t, const uint32_t sram_l, const uint32_t sram_h, const size_t flash_size, const size_t flexmem_size)
{
t->driver = "S32K14x";
target_add_ram(t, sram_l, 0x20000000 - sram_l);
target_add_ram(t, 0x20000000, sram_h);
kinetis_add_flash(t, 0x00000000, flash_size, 0x1000, K64_WRITE_LEN); /* P-Flash, 4 KB Sectors */
kinetis_add_flash(t, 0x10000000, flexmem_size, 0x1000, K64_WRITE_LEN); /* FlexNVM, 4 KB Sectors */
}
bool kinetis_probe(target *const t)
{
uint32_t sdid = target_mem_read32(t, SIM_SDID);
uint32_t fcfg1 = target_mem_read32(t, SIM_FCFG1);
@ -132,52 +162,52 @@ bool kinetis_probe(target *t)
switch (sdid >> 20) {
case 0x161:
/* sram memory size */
switch((sdid >> 16) & 0x0f) {
case 0x03:/* 4 KB */
target_add_ram(t, 0x1ffffc00, 0x0400);
target_add_ram(t, 0x20000000, 0x0C00);
break;
case 0x04:/* 8 KB */
target_add_ram(t, 0x1ffff800, 0x0800);
target_add_ram(t, 0x20000000, 0x1800);
break;
case 0x05:/* 16 KB */
target_add_ram(t, 0x1ffff000, 0x1000);
target_add_ram(t, 0x20000000, 0x3000);
break;
case 0x06:/* 32 KB */
target_add_ram(t, 0x1fffe000, 0x2000);
target_add_ram(t, 0x20000000, 0x6000);
break;
default:
return false;
break;
switch ((sdid >> 16) & 0x0f) {
case 0x03: /* 4 KB */
target_add_ram(t, 0x1ffffc00, 0x0400);
target_add_ram(t, 0x20000000, 0x0C00);
break;
case 0x04: /* 8 KB */
target_add_ram(t, 0x1ffff800, 0x0800);
target_add_ram(t, 0x20000000, 0x1800);
break;
case 0x05: /* 16 KB */
target_add_ram(t, 0x1ffff000, 0x1000);
target_add_ram(t, 0x20000000, 0x3000);
break;
case 0x06: /* 32 KB */
target_add_ram(t, 0x1fffe000, 0x2000);
target_add_ram(t, 0x20000000, 0x6000);
break;
default:
return false;
break;
}
/* flash memory size */
switch((fcfg1 >> 24) & 0x0f) {
case 0x03: /* 32 KB */
t->driver = "KL16Z32Vxxx";
kl_gen_add_flash(t, 0x00000000, 0x08000, 0x400, KL_WRITE_LEN);
break;
switch ((fcfg1 >> 24) & 0x0f) {
case 0x03: /* 32 KB */
t->driver = "KL16Z32Vxxx";
kinetis_add_flash(t, 0x00000000, 0x08000, 0x400, KL_WRITE_LEN);
break;
case 0x05: /* 64 KB */
t->driver = "KL16Z64Vxxx";
kl_gen_add_flash(t, 0x00000000, 0x10000, 0x400, KL_WRITE_LEN);
break;
case 0x05: /* 64 KB */
t->driver = "KL16Z64Vxxx";
kinetis_add_flash(t, 0x00000000, 0x10000, 0x400, KL_WRITE_LEN);
break;
case 0x07: /* 128 KB */
t->driver = "KL16Z128Vxxx";
kl_gen_add_flash(t, 0x00000000, 0x20000, 0x400, KL_WRITE_LEN);
break;
case 0x07: /* 128 KB */
t->driver = "KL16Z128Vxxx";
kinetis_add_flash(t, 0x00000000, 0x20000, 0x400, KL_WRITE_LEN);
break;
case 0x09: /* 256 KB */
t->driver = "KL16Z256Vxxx";
kl_gen_add_flash(t, 0x00000000, 0x40000, 0x400, KL_WRITE_LEN);
break;
default:
return false;
break;
case 0x09: /* 256 KB */
t->driver = "KL16Z256Vxxx";
kinetis_add_flash(t, 0x00000000, 0x40000, 0x400, KL_WRITE_LEN);
break;
default:
return false;
break;
}
break;
@ -186,68 +216,68 @@ bool kinetis_probe(target *t)
t->driver = "KL25";
target_add_ram(t, 0x1ffff000, 0x1000);
target_add_ram(t, 0x20000000, 0x3000);
kl_gen_add_flash(t, 0x00000000, 0x20000, 0x400, KL_WRITE_LEN);
kinetis_add_flash(t, 0x00000000, 0x20000, 0x400, KL_WRITE_LEN);
break;
case 0x231:
t->driver = "KL27x128"; // MKL27 >=128kb
target_add_ram(t, 0x1fffe000, 0x2000);
target_add_ram(t, 0x20000000, 0x6000);
kl_gen_add_flash(t, 0x00000000, 0x40000, 0x400, KL_WRITE_LEN);
kinetis_add_flash(t, 0x00000000, 0x40000, 0x400, KL_WRITE_LEN);
break;
case 0x271:
switch((sdid >> 16) & 0x0f) {
case 4:
t->driver = "KL27x32";
target_add_ram(t, 0x1ffff800, 0x0800);
target_add_ram(t, 0x20000000, 0x1800);
kl_gen_add_flash(t, 0x00000000, 0x8000, 0x400, KL_WRITE_LEN);
break;
case 5:
t->driver = "KL27x64";
target_add_ram(t, 0x1ffff000, 0x1000);
target_add_ram(t, 0x20000000, 0x3000);
kl_gen_add_flash(t, 0x00000000, 0x10000, 0x400, KL_WRITE_LEN);
break;
default:
return false;
switch ((sdid >> 16) & 0x0f) {
case 4:
t->driver = "KL27x32";
target_add_ram(t, 0x1ffff800, 0x0800);
target_add_ram(t, 0x20000000, 0x1800);
kinetis_add_flash(t, 0x00000000, 0x8000, 0x400, KL_WRITE_LEN);
break;
case 5:
t->driver = "KL27x64";
target_add_ram(t, 0x1ffff000, 0x1000);
target_add_ram(t, 0x20000000, 0x3000);
kinetis_add_flash(t, 0x00000000, 0x10000, 0x400, KL_WRITE_LEN);
break;
default:
return false;
}
break;
case 0x021: /* KL02 family */
switch((sdid >> 16) & 0x0f) {
case 3:
t->driver = "KL02x32";
target_add_ram(t, 0x1FFFFC00, 0x400);
target_add_ram(t, 0x20000000, 0xc00);
kl_gen_add_flash(t, 0x00000000, 0x7FFF, 0x400, KL_WRITE_LEN);
break;
case 2:
t->driver = "KL02x16";
target_add_ram(t, 0x1FFFFE00, 0x200);
target_add_ram(t, 0x20000000, 0x600);
kl_gen_add_flash(t, 0x00000000, 0x3FFF, 0x400, KL_WRITE_LEN);
break;
case 1:
t->driver = "KL02x8";
target_add_ram(t, 0x1FFFFF00, 0x100);
target_add_ram(t, 0x20000000, 0x300);
kl_gen_add_flash(t, 0x00000000, 0x1FFF, 0x400, KL_WRITE_LEN);
break;
default:
return false;
switch ((sdid >> 16) & 0x0f) {
case 3:
t->driver = "KL02x32";
target_add_ram(t, 0x1FFFFC00, 0x400);
target_add_ram(t, 0x20000000, 0xc00);
kinetis_add_flash(t, 0x00000000, 0x7FFF, 0x400, KL_WRITE_LEN);
break;
case 2:
t->driver = "KL02x16";
target_add_ram(t, 0x1FFFFE00, 0x200);
target_add_ram(t, 0x20000000, 0x600);
kinetis_add_flash(t, 0x00000000, 0x3FFF, 0x400, KL_WRITE_LEN);
break;
case 1:
t->driver = "KL02x8";
target_add_ram(t, 0x1FFFFF00, 0x100);
target_add_ram(t, 0x20000000, 0x300);
kinetis_add_flash(t, 0x00000000, 0x1FFF, 0x400, KL_WRITE_LEN);
break;
default:
return false;
}
break;
case 0x031: /* KL03 family */
t->driver = "KL03";
target_add_ram(t, 0x1ffffe00, 0x200);
target_add_ram(t, 0x20000000, 0x600);
kl_gen_add_flash(t, 0, 0x8000, 0x400, KL_WRITE_LEN);
kinetis_add_flash(t, 0, 0x8000, 0x400, KL_WRITE_LEN);
break;
case 0x220: /* K22F family */
t->driver = "K22F";
target_add_ram(t, 0x1c000000, 0x4000000);
target_add_ram(t, 0x20000000, 0x100000);
kl_gen_add_flash(t, 0, 0x40000, 0x800, KL_WRITE_LEN);
kl_gen_add_flash(t, 0x40000, 0x40000, 0x800, KL_WRITE_LEN);
kinetis_add_flash(t, 0, 0x40000, 0x800, KL_WRITE_LEN);
kinetis_add_flash(t, 0x40000, 0x40000, 0x800, KL_WRITE_LEN);
break;
case 0x620: /* K64F family. */
/* This should be 0x640, but according to the errata sheet
@ -255,115 +285,107 @@ bool kinetis_probe(target *t)
* subfamily nibble as 2
*/
t->driver = "K64";
target_add_ram(t, 0x1FFF0000, 0x10000);
target_add_ram(t, 0x20000000, 0x30000);
kl_gen_add_flash(t, 0, 0x80000, 0x1000, K64_WRITE_LEN);
kl_gen_add_flash(t, 0x80000, 0x80000, 0x1000, K64_WRITE_LEN);
target_add_ram(t, 0x1FFF0000, 0x10000);
target_add_ram(t, 0x20000000, 0x30000);
kinetis_add_flash(t, 0, 0x80000, 0x1000, K64_WRITE_LEN);
kinetis_add_flash(t, 0x80000, 0x80000, 0x1000, K64_WRITE_LEN);
break;
case 0x000: /* Older K-series */
switch(sdid & 0xff0) {
case 0x000: /* K10 Family, DIEID=0x0 */
case 0x080: /* K10 Family, DIEID=0x1 */
case 0x100: /* K10 Family, DIEID=0x2 */
case 0x180: /* K10 Family, DIEID=0x3 */
case 0x220: /* K11 Family, DIEID=0x4 */
return false;
case 0x200: /* K12 Family, DIEID=0x4 */
switch((fcfg1 >> 24) & 0x0f) {
/* K12 Sub-Family Reference Manual, K12P80M50SF4RM, Rev. 4, February 2013 */
case 0x7:
t->driver = "MK12DX128Vxx5";
target_add_ram(t, 0x1fffc000, 0x00004000); /* SRAM_L, 16 KB */
target_add_ram(t, 0x20000000, 0x00004000); /* SRAM_H, 16 KB */
kl_gen_add_flash(t, 0x00000000, 0x00020000, 0x800, KL_WRITE_LEN); /* P-Flash, 128 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x10000000, 0x00010000, 0x800, KL_WRITE_LEN); /* FlexNVM, 64 KB, 2 KB Sectors */
break;
case 0x9:
t->driver = "MK12DX256Vxx5";
target_add_ram(t, 0x1fffc000, 0x00004000); /* SRAM_L, 16 KB */
target_add_ram(t, 0x20000000, 0x00004000); /* SRAM_H, 16 KB */
kl_gen_add_flash(t, 0x00000000, 0x00040000, 0x800, KL_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x10000000, 0x00010000, 0x800, KL_WRITE_LEN); /* FlexNVM, 64 KB, 2 KB Sectors */
break;
case 0xb:
t->driver = "MK12DN512Vxx5";
target_add_ram(t, 0x1fff8000, 0x00008000); /* SRAM_L, 32 KB */
target_add_ram(t, 0x20000000, 0x00008000); /* SRAM_H, 32 KB */
kl_gen_add_flash(t, 0x00000000, 0x00040000, 0x800, KL_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x00040000, 0x00040000, 0x800, KL_WRITE_LEN); /* FlexNVM, 256 KB, 2 KB Sectors */
break;
default:
return false;
}
switch (sdid & 0xff0) {
case 0x000: /* K10 Family, DIEID=0x0 */
case 0x080: /* K10 Family, DIEID=0x1 */
case 0x100: /* K10 Family, DIEID=0x2 */
case 0x180: /* K10 Family, DIEID=0x3 */
case 0x220: /* K11 Family, DIEID=0x4 */
return false;
case 0x200: /* K12 Family, DIEID=0x4 */
switch ((fcfg1 >> 24) & 0x0f) {
/* K12 Sub-Family Reference Manual, K12P80M50SF4RM, Rev. 4, February 2013 */
case 0x7:
t->driver = "MK12DX128Vxx5";
target_add_ram(t, 0x1fffc000, 0x00004000); /* SRAM_L, 16 KB */
target_add_ram(t, 0x20000000, 0x00004000); /* SRAM_H, 16 KB */
kinetis_add_flash(t, 0x00000000, 0x00020000, 0x800, KL_WRITE_LEN); /* P-Flash, 128 KB, 2 KB Sectors */
kinetis_add_flash(t, 0x10000000, 0x00010000, 0x800, KL_WRITE_LEN); /* FlexNVM, 64 KB, 2 KB Sectors */
break;
case 0x9:
t->driver = "MK12DX256Vxx5";
target_add_ram(t, 0x1fffc000, 0x00004000); /* SRAM_L, 16 KB */
target_add_ram(t, 0x20000000, 0x00004000); /* SRAM_H, 16 KB */
kinetis_add_flash(t, 0x00000000, 0x00040000, 0x800, KL_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kinetis_add_flash(t, 0x10000000, 0x00010000, 0x800, KL_WRITE_LEN); /* FlexNVM, 64 KB, 2 KB Sectors */
break;
case 0xb:
t->driver = "MK12DN512Vxx5";
target_add_ram(t, 0x1fff8000, 0x00008000); /* SRAM_L, 32 KB */
target_add_ram(t, 0x20000000, 0x00008000); /* SRAM_H, 32 KB */
kinetis_add_flash(t, 0x00000000, 0x00040000, 0x800, KL_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kinetis_add_flash(t, 0x00040000, 0x00040000, 0x800, KL_WRITE_LEN); /* FlexNVM, 256 KB, 2 KB Sectors */
break;
case 0x010: /* K20 Family, DIEID=0x0 */
case 0x090: /* K20 Family, DIEID=0x1 */
case 0x110: /* K20 Family, DIEID=0x2 */
case 0x190: /* K20 Family, DIEID=0x3 */
case 0x230: /* K21 Family, DIEID=0x4 */
case 0x330: /* K21 Family, DIEID=0x6 */
case 0x210: /* K22 Family, DIEID=0x4 */
case 0x310: /* K22 Family, DIEID=0x6 */
case 0x0a0: /* K30 Family, DIEID=0x1 */
case 0x120: /* K30 Family, DIEID=0x2 */
case 0x0b0: /* K40 Family, DIEID=0x1 */
case 0x130: /* K40 Family, DIEID=0x2 */
case 0x0e0: /* K50 Family, DIEID=0x1 */
case 0x0f0: /* K51 Family, DIEID=0x1 */
case 0x170: /* K53 Family, DIEID=0x2 */
case 0x140: /* K60 Family, DIEID=0x2 */
case 0x1c0: /* K60 Family, DIEID=0x3 */
case 0x1d0: /* K70 Family, DIEID=0x3 */
default:
return false;
}
break;
case 0x010: /* K20 Family, DIEID=0x0 */
case 0x090: /* K20 Family, DIEID=0x1 */
case 0x110: /* K20 Family, DIEID=0x2 */
case 0x190: /* K20 Family, DIEID=0x3 */
case 0x230: /* K21 Family, DIEID=0x4 */
case 0x330: /* K21 Family, DIEID=0x6 */
case 0x210: /* K22 Family, DIEID=0x4 */
case 0x310: /* K22 Family, DIEID=0x6 */
case 0x0a0: /* K30 Family, DIEID=0x1 */
case 0x120: /* K30 Family, DIEID=0x2 */
case 0x0b0: /* K40 Family, DIEID=0x1 */
case 0x130: /* K40 Family, DIEID=0x2 */
case 0x0e0: /* K50 Family, DIEID=0x1 */
case 0x0f0: /* K51 Family, DIEID=0x1 */
case 0x170: /* K53 Family, DIEID=0x2 */
case 0x140: /* K60 Family, DIEID=0x2 */
case 0x1c0: /* K60 Family, DIEID=0x3 */
case 0x1d0: /* K70 Family, DIEID=0x3 */
default:
return false;
}
break;
case 0x118: /* S32K118 */
t->driver = "S32K118";
target_add_ram(t, 0x1ffffc00, 0x00000400); /* SRAM_L, 1 KB */
target_add_ram(t, 0x20000000, 0x00005800); /* SRAM_H, 22 KB */
kl_gen_add_flash(t, 0x00000000, 0x00040000, 0x800, K64_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x10000000, 0x00008000, 0x800, K64_WRITE_LEN); /* FlexNVM, 32 KB, 2 KB Sectors */
target_add_ram(t, 0x1ffffc00, 0x00000400); /* SRAM_L, 1 KB */
target_add_ram(t, 0x20000000, 0x00005800); /* SRAM_H, 22 KB */
kinetis_add_flash(t, 0x00000000, 0x00040000, 0x800, K64_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kinetis_add_flash(t, 0x10000000, 0x00008000, 0x800, K64_WRITE_LEN); /* FlexNVM, 32 KB, 2 KB Sectors */
break;
/* gen1 s32k14x */
case 0x142: /* S32K142 */
case 0x143: /* S32K142W */
/* SRAM_L = 16KiB */
/* SRAM_H = 12KiB */
/* Flash = 256 KiB */
/* FlexNVM = 64 KiB */
kl_s32k14_setup(t, 0x1FFFC000, 0x03000, 0x00040000, 0x10000);
break;
case 0x144: /* S32K144 */
case 0x145: /* S32K144W */
/* SRAM_L = 32KiB */
/* SRAM_H = 28KiB */
/* Flash = 512 KiB */
/* FlexNVM = 64 KiB */
kl_s32k14_setup(t, 0x1FFF8000, 0x07000, 0x00080000, 0x10000);
break;
case 0x146: /* S32K146 */
/* SRAM_L = 64KiB */
/* SRAM_H = 60KiB */
/* Flash = 1024 KiB */
/* FlexNVM = 64 KiB */
kl_s32k14_setup(t, 0x1fff0000, 0x0f000, 0x00100000, 0x10000);
break;
/* gen1 s32k14x */
{
uint32_t sram_l, sram_h;
uint32_t flash, flexmem;
case 0x142: /* s32k142 */
case 0x143: /* s32k142w */
sram_l = 0x1FFFC000; /* SRAM_L, 16k */
sram_h = 0x03000; /* SRAM_H, 12k */
flash = 0x00040000; /* flash 256 KB */
flexmem = 0x10000; /* FlexNVM 64 KB */
goto do_common_s32k14x;
case 0x144: /* s32k144 */
case 0x145: /* s32k144w */
sram_l = 0x1FFF8000; /* SRAM_L, 32k */
sram_h = 0x07000; /* SRAM_H, 28k */
flash = 0x00080000; /* flash 512 KB */
flexmem = 0x10000; /* FlexNVM 64 KB */
goto do_common_s32k14x;
case 0x146: /* s32k146 */
sram_l = 0x1fff0000; /* SRAM_L, 64k */
sram_h = 0x0f000; /* SRAM_H, 60k */
flash = 0x00100000; /* flash 1024 KB */
flexmem = 0x10000; /* FlexNVM 64 KB */
goto do_common_s32k14x;
case 0x148: /* S32K148 */
sram_l = 0x1ffe0000; /* SRAM_L, 128 KB */
sram_h = 0x1f000; /* SRAM_H, 124 KB */
flash = 0x00180000; /* flash 1536 KB */
flexmem = 0x80000; /* FlexNVM 512 KB */
goto do_common_s32k14x;
do_common_s32k14x:
t->driver = "S32K14x";
target_add_ram(t, sram_l, 0x20000000 - sram_l);
target_add_ram(t, 0x20000000, sram_h);
kl_gen_add_flash(t, 0x00000000, flash, 0x1000, K64_WRITE_LEN); /* P-Flash, 4 KB Sectors */
kl_gen_add_flash(t, 0x10000000, flexmem, 0x1000, K64_WRITE_LEN); /* FlexNVM, 4 KB Sectors */
/* SRAM_L = 128 KiB */
/* SRAM_H = 124 KiB */
/* Flash = 1536 KiB */
/* FlexNVM = 512 KiB */
kl_s32k14_setup(t, 0x1ffe0000, 0x1f000, 0x00180000, 0x80000);
break;
}
default:
return false;
}
@ -372,47 +394,48 @@ do_common_s32k14x:
return true;
}
static bool
kl_gen_command(target *t, uint8_t cmd, uint32_t addr, const uint32_t *data, int n_items)
static bool kinetis_fccob_cmd(target *t, uint8_t cmd, uint32_t addr, const uint32_t *data, int n_items)
{
uint8_t fstat;
/* clear errors unconditionally, so we can start a new operation */
target_mem_write8(t,FTFA_FSTAT,(FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL));
target_mem_write8(t, FTFx_FSTAT, (FTFx_FSTAT_ACCERR | FTFx_FSTAT_FPVIOL));
/* Wait for CCIF to be high */
do {
fstat = target_mem_read8(t, FTFA_FSTAT);
} while (!(fstat & FTFA_FSTAT_CCIF));
fstat = target_mem_read8(t, FTFx_FSTAT);
} while (!(fstat & FTFx_FSTAT_CCIF));
/* Write command to FCCOB */
addr &= 0xffffff;
addr |= (uint32_t)cmd << 24;
target_mem_write32(t, FTFA_FCCOB_0, addr);
if (data) {
target_mem_write32(t, FTFA_FCCOB_1, data[0]);
addr &= 0x00ffffffU;
addr |= cmd << 24U;
target_mem_write32(t, FTFx_FCCOB0, addr);
if (data && n_items) {
target_mem_write32(t, FTFx_FCCOB4, data[0]);
if (n_items > 1)
target_mem_write32(t, FTFA_FCCOB_2, data[1]);
target_mem_write32(t, FTFx_FCCOB8, data[1]);
else
target_mem_write32(t, FTFx_FCCOB8, 0);
}
/* Enable execution by clearing CCIF */
target_mem_write8(t, FTFA_FSTAT, FTFA_FSTAT_CCIF);
target_mem_write8(t, FTFx_FSTAT, FTFx_FSTAT_CCIF);
/* Wait for execution to complete */
do {
fstat = target_mem_read8(t, FTFA_FSTAT);
fstat = target_mem_read8(t, FTFx_FSTAT);
/* Check ACCERR and FPVIOL are zero in FSTAT */
if (fstat & (FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL))
if (fstat & (FTFx_FSTAT_ACCERR | FTFx_FSTAT_FPVIOL))
return false;
} while (!(fstat & FTFA_FSTAT_CCIF));
} while (!(fstat & FTFx_FSTAT_CCIF));
return true;
}
static int kl_gen_flash_erase(struct target_flash *f, target_addr addr, size_t len)
static int kinetis_flash_cmd_erase(struct target_flash *const f, target_addr addr, size_t len)
{
while (len) {
if (kl_gen_command(f->t, FTFA_CMD_ERASE_SECTOR, addr, NULL, 0)) {
if (kinetis_fccob_cmd(f->t, FTFx_CMD_ERASE_SECTOR, addr, NULL, 0)) {
/* Different targets have different flash erase sizes */
if (len > f->blocksize)
len -= f->blocksize;
@ -426,72 +449,60 @@ static int kl_gen_flash_erase(struct target_flash *f, target_addr addr, size_t l
return 0;
}
#define FLASH_SECURITY_BYTE_ADDRESS 0x40C
#define FLASH_SECURITY_BYTE_UNSECURED 0xFE
static int kl_gen_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len)
static int kinetis_flash_cmd_write(struct target_flash *f, target_addr dest, const void *src, size_t len)
{
struct kinetis_flash *kf = (struct kinetis_flash *)f;
struct kinetis_flash *const kf = (struct kinetis_flash *)f;
/* Ensure we don't write something horrible over the security byte */
if (!f->t->unsafe_enabled &&
(dest <= FLASH_SECURITY_BYTE_ADDRESS) &&
((dest + len) > FLASH_SECURITY_BYTE_ADDRESS)) {
((uint8_t*)src)[FLASH_SECURITY_BYTE_ADDRESS - dest] =
FLASH_SECURITY_BYTE_UNSECURED;
if (!f->t->unsafe_enabled && dest <= FLASH_SECURITY_BYTE_ADDRESS && dest + len > FLASH_SECURITY_BYTE_ADDRESS) {
((uint8_t *)src)[FLASH_SECURITY_BYTE_ADDRESS - dest] = FLASH_SECURITY_BYTE_UNSECURED;
}
/* Determine write command based on the alignment. */
uint8_t write_cmd;
if (kf->write_len == K64_WRITE_LEN) {
write_cmd = FTFE_CMD_PROGRAM_PHRASE;
} else {
write_cmd = FTFA_CMD_PROGRAM_LONGWORD;
}
if (kf->write_len == K64_WRITE_LEN)
write_cmd = FTFx_CMD_PROGRAM_PHRASE;
else
write_cmd = FTFx_CMD_PROGRAM_LONGWORD;
while (len) {
if (kl_gen_command(f->t, write_cmd, dest, src, 1)) {
if (kinetis_fccob_cmd(f->t, write_cmd, dest, src, kf->write_len >> 2U)) {
if (len > kf->write_len)
len -= kf->write_len;
else
len = 0;
dest += kf->write_len;
src += kf->write_len;
} else {
} else
return 1;
}
}
return 0;
}
static int kl_gen_flash_done(struct target_flash *f)
static int kinetis_flash_done(struct target_flash *const f)
{
struct kinetis_flash *kf = (struct kinetis_flash *)f;
struct kinetis_flash *const kf = (struct kinetis_flash *)f;
if (f->t->unsafe_enabled)
return 0;
if (target_mem_read8(f->t, FLASH_SECURITY_BYTE_ADDRESS) ==
FLASH_SECURITY_BYTE_UNSECURED)
if (target_mem_read8(f->t, FLASH_SECURITY_BYTE_ADDRESS) == FLASH_SECURITY_BYTE_UNSECURED)
return 0;
/* Load the security byte based on the alignment (determine 8 byte phrases
* vs 4 byte phrases).
*/
if (kf->write_len == 8) {
uint32_t vals[2];
vals[0] = target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS-4);
vals[1] = target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS);
vals[1] = (vals[1] & 0xffffff00) | FLASH_SECURITY_BYTE_UNSECURED;
kl_gen_command(f->t, FTFE_CMD_PROGRAM_PHRASE,
FLASH_SECURITY_BYTE_ADDRESS - 4, vals, 2);
if (kf->write_len == K64_WRITE_LEN) {
uint32_t vals[2] = {
target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS - 4),
target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS)
};
vals[1] = (vals[1] & 0xffffff00U) | FLASH_SECURITY_BYTE_UNSECURED;
kinetis_fccob_cmd(f->t, FTFx_CMD_PROGRAM_PHRASE, FLASH_SECURITY_BYTE_ADDRESS - 4, vals, 2);
} else {
uint32_t vals[1];
vals[0] = target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS);
vals[0] = (vals[0] & 0xffffff00) | FLASH_SECURITY_BYTE_UNSECURED;
kl_gen_command(f->t, FTFA_CMD_PROGRAM_LONGWORD,
FLASH_SECURITY_BYTE_ADDRESS, vals, 1);
uint32_t val = target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS);
val = (val & 0xffffff00U) | FLASH_SECURITY_BYTE_UNSECURED;
kinetis_fccob_cmd(f->t, FTFx_CMD_PROGRAM_LONGWORD, FLASH_SECURITY_BYTE_ADDRESS, &val, 1);
}
return 0;
@ -504,10 +515,6 @@ static int kl_gen_flash_done(struct target_flash *f)
* a backdoor AP is provided which may allow a mass erase to recover the
* device. This provides a fake target to allow a monitor command interface
*/
#include "adiv5.h"
#define KINETIS_MDM_IDR_K22F 0x1c0000
#define KINETIS_MDM_IDR_KZ03 0x1c0020
static bool kinetis_mdm_cmd_erase_mass(target *t, int argc, const char **argv);
static bool kinetis_mdm_cmd_ke04_mode(target *t, int argc, const char **argv);
@ -515,18 +522,19 @@ static bool kinetis_mdm_cmd_ke04_mode(target *t, int argc, const char **argv);
const struct command_s kinetis_mdm_cmd_list[] = {
{"erase_mass", (cmd_handler)kinetis_mdm_cmd_erase_mass, "Erase entire flash memory"},
{"ke04_mode", (cmd_handler)kinetis_mdm_cmd_ke04_mode, "Allow erase for KE04"},
{NULL, NULL, NULL}
{NULL, NULL, NULL},
};
enum target_halt_reason mdm_halt_poll(target *t, target_addr *watch)
enum target_halt_reason mdm_halt_poll(target *t, const target_addr *const watch)
{
(void)t; (void)watch;
(void)t;
(void)watch;
return TARGET_HALT_REQUEST;
}
void kinetis_mdm_probe(ADIv5_AP_t *ap)
{
switch(ap->idr) {
switch (ap->idr) {
case KINETIS_MDM_IDR_KZ03: /* Also valid for KE04, no way to check! */
case KINETIS_MDM_IDR_K22F:
break;
@ -541,23 +549,13 @@ void kinetis_mdm_probe(ADIv5_AP_t *ap)
adiv5_ap_ref(ap);
t->priv = ap;
t->priv_free = (void*)adiv5_ap_unref;
t->priv_free = (void *)adiv5_ap_unref;
t->driver = "Kinetis Recovery (MDM-AP)";
t->regs_size = 4;
target_add_commands(t, kinetis_mdm_cmd_list, t->driver);
}
#define MDM_STATUS ADIV5_AP_REG(0x00)
#define MDM_CONTROL ADIV5_AP_REG(0x04)
#define MDM_STATUS_MASS_ERASE_ACK (1 << 0)
#define MDM_STATUS_FLASH_READY (1 << 1)
#define MDM_STATUS_MASS_ERASE_ENABLED (1 << 5)
#define MDM_CONTROL_MASS_ERASE (1 << 0)
#define MDM_CONTROL_SYS_RESET (1 << 3)
/* This is needed as a separate command, as there's no way to *
* tell a KE04 from other kinetis in kinetis_mdm_probe() */
static bool kinetis_mdm_cmd_ke04_mode(target *t, int argc, const char **argv)
@ -569,6 +567,7 @@ static bool kinetis_mdm_cmd_ke04_mode(target *t, int argc, const char **argv)
tc_printf(t, "Mass erase for KE04 now allowed\n");
return true;
}
static bool kinetis_mdm_cmd_erase_mass(target *t, int argc, const char **argv)
{
(void)argc;
@ -576,13 +575,12 @@ static bool kinetis_mdm_cmd_erase_mass(target *t, int argc, const char **argv)
ADIv5_AP_t *ap = t->priv;
/* Keep the MCU in reset as stated in KL25PxxM48SF0RM */
if(t->ke04_mode)
if (t->ke04_mode)
adiv5_ap_write(ap, MDM_CONTROL, MDM_CONTROL_SYS_RESET);
uint32_t status, control;
status = adiv5_ap_read(ap, MDM_STATUS);
control = adiv5_ap_read(ap, MDM_CONTROL);
tc_printf(t, "Requesting mass erase (status = 0x%"PRIx32")\n", status);
uint32_t status = adiv5_ap_read(ap, MDM_STATUS);
uint32_t control = adiv5_ap_read(ap, MDM_CONTROL);
tc_printf(t, "Requesting mass erase (status = 0x%" PRIx32 ")\n", status);
/* This flag does not exist on KE04 */
if (!(status & MDM_STATUS_MASS_ERASE_ENABLED) && !t->ke04_mode) {

View File

@ -56,7 +56,7 @@ static int stm32f4_flash_erase(struct target_flash *f, target_addr addr,
static int stm32f4_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
/* Flash Program ad Erase Controller Register Map */
/* Flash Program and Erase Controller Register Map */
#define FPEC_BASE 0x40023C00
#define FLASH_ACR (FPEC_BASE+0x00)
#define FLASH_KEYR (FPEC_BASE+0x04)
@ -503,11 +503,8 @@ static bool stm32f4_cmd_erase_mass(target *t, int argc, const char **argv)
tc_printf(t, "\n");
/* Check for error */
uint32_t sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP))
return false;
return true;
const uint32_t result = target_mem_read32(t, FLASH_SR);
return !(result & SR_ERROR_MASK);
}
/* Dev | DOC |Rev|ID |OPTCR |OPTCR |OPTCR1 |OPTCR1 | OPTCR2

View File

@ -271,6 +271,11 @@ int target_flash_write(target *t,
dest += tmplen;
src += tmplen;
len -= tmplen;
/* If the current chunk of Flash is now full from this operation
* then finish operations on the Flash chunk and free the internal buffer.
*/
if (dest == f->start + f->length)
ret |= target_flash_done_buffered(f);
}
return ret;
}