Compare commits
704 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc0e016a6d | ||
|
|
f5c0148665 | ||
|
|
3d78a99758 | ||
|
|
03e97c2d95 | ||
|
|
eaacb928fc | ||
|
|
75ba375b8a | ||
|
|
cbd06f1433 | ||
|
|
1c59a0d30a | ||
|
|
d222ec1024 | ||
|
|
674f584190 | ||
|
|
77fea562c4 | ||
|
|
e0f275cddf | ||
|
|
07a69df62f | ||
|
|
f8750b142f | ||
|
|
3033b03789 | ||
|
|
3506d1e994 | ||
|
|
3c4d14bfa9 | ||
|
|
db97f36631 | ||
|
|
d03cf2b83f | ||
|
|
744c6d114e | ||
|
|
3b9b4e4d6f | ||
|
|
78ba7064a7 | ||
|
|
cc7c99a4a4 | ||
|
|
d3eb148cfa | ||
|
|
00d541b767 | ||
|
|
ecf2596469 | ||
|
|
6a2eaeae40 | ||
|
|
ce7cc798dc | ||
|
|
0ec7eda11b | ||
|
|
fb0f344346 | ||
|
|
afac81c161 | ||
|
|
5c982c90f3 | ||
|
|
381304aa6f | ||
|
|
ce9523fb90 | ||
|
|
06420b0ddf | ||
|
|
c2e1c53356 | ||
|
|
eaeb831107 | ||
|
|
459695e9d7 | ||
|
|
ece1f71c64 | ||
|
|
776d8f9f79 | ||
|
|
61ee63f358 | ||
|
|
6f65ba9214 | ||
|
|
ba837c2641 | ||
|
|
1518032606 | ||
|
|
6469cce2bc | ||
|
|
4c40b50fb5 | ||
|
|
a0f0911a95 | ||
|
|
f658819862 | ||
|
|
8d5a9143bb | ||
|
|
8f8951b4c1 | ||
|
|
6e5bcc69bc | ||
|
|
8d04d3d8fd | ||
|
|
f37fc775e5 | ||
|
|
ead99cf647 | ||
|
|
3982b5030e | ||
|
|
d9fe4b6944 | ||
|
|
387cab27bd | ||
|
|
6dcc44ce2d | ||
|
|
3b4088c23f | ||
|
|
5a85c1667a | ||
|
|
16d2ec3a90 | ||
|
|
4d60567bc6 | ||
|
|
73a1c9d249 | ||
|
|
d851882278 | ||
|
|
3ccecc568d | ||
|
|
cee200e509 | ||
|
|
f1b315e04f | ||
|
|
94bcd9735a | ||
|
|
f662445766 | ||
|
|
008be18f41 | ||
|
|
13812aa1c9 | ||
|
|
2089f19670 | ||
|
|
593741919f | ||
|
|
9d0fcca8a9 | ||
|
|
857eb01bfa | ||
|
|
a100f174f9 | ||
|
|
5dfe4e1eb9 | ||
|
|
b9586bad18 | ||
|
|
f1c2f789b6 | ||
|
|
123719bf92 | ||
|
|
14810d7e80 | ||
|
|
52156d2c41 | ||
|
|
2a6a9eb52f | ||
|
|
bf85c61b48 | ||
|
|
dba488f30a | ||
|
|
d618affd63 | ||
|
|
121c747cc8 | ||
|
|
91b9634198 | ||
|
|
7d17002b33 | ||
|
|
477b3941a6 | ||
|
|
36dd7e7609 | ||
|
|
167a65d826 | ||
|
|
c9cd8cea66 | ||
|
|
dfdcbece53 | ||
|
|
5b62f15c6d | ||
|
|
09e32d1b84 | ||
|
|
68fc6abf74 | ||
|
|
ff56c0fb74 | ||
|
|
36de6118c1 | ||
|
|
7083a33ecd | ||
|
|
7b7f57e01c | ||
|
|
8d0ef49e8f | ||
|
|
7a81bfc4a4 | ||
|
|
0d13834293 | ||
|
|
ac53806e04 | ||
|
|
026b9c336c | ||
|
|
60c77fff06 | ||
|
|
588ecbe868 | ||
|
|
e05c635489 | ||
|
|
f5cc355044 | ||
|
|
78f4c25a14 | ||
|
|
002dc0dfaf | ||
|
|
68d6788413 | ||
|
|
c7c551369f | ||
|
|
0c2919b534 | ||
|
|
d8c75fc608 | ||
|
|
a42cb4fecf | ||
|
|
68ba3d5106 | ||
|
|
80dc1dfcc1 | ||
|
|
931811ab59 | ||
|
|
9d75c3b0ca | ||
|
|
6ab8567d51 | ||
|
|
c727ed3592 | ||
|
|
c72ca983ba | ||
|
|
ec7990796a | ||
|
|
268834e4ae | ||
|
|
b80c488d36 | ||
|
|
f25cb33367 | ||
|
|
4b5f3bec4b | ||
|
|
1f4c6443ef | ||
|
|
0adea120cd | ||
|
|
71bb7acb8e | ||
|
|
4b5109c1b9 | ||
|
|
085817d332 | ||
|
|
f8bd8b97be | ||
|
|
f3da473285 | ||
|
|
f0f4ab7abe | ||
|
|
d8225642fa | ||
|
|
8ebba6d27a | ||
|
|
1051a52755 | ||
|
|
5583b050a0 | ||
|
|
a38082016d | ||
|
|
156e9b7556 | ||
|
|
5e6acf7dbc | ||
|
|
58811b5c44 | ||
|
|
86a762b2b7 | ||
|
|
f886212b44 | ||
|
|
2c272f99a3 | ||
|
|
a9982beacf | ||
|
|
e9d2ec7c41 | ||
|
|
78982ebb51 | ||
|
|
6a63c27542 | ||
|
|
62f77f6bc5 | ||
|
|
88a10fb31c | ||
|
|
e12527b895 | ||
|
|
114c8c5b6d | ||
|
|
d50f4e23e0 | ||
|
|
dca0fc91ea | ||
|
|
981c53682f | ||
|
|
143b7cccf4 | ||
|
|
8ce042bf04 | ||
|
|
85a1e1118f | ||
|
|
51baeb3c2c | ||
|
|
959a20888c | ||
|
|
7bf0ec2fe7 | ||
|
|
c6231a16e3 | ||
|
|
a619aacfc6 | ||
|
|
d469db84ee | ||
|
|
4655a6bfef | ||
|
|
61325c0a14 | ||
|
|
7faa5fe233 | ||
|
|
19090bdd5b | ||
|
|
4a6254fac3 | ||
|
|
649d26e093 | ||
|
|
2ee42997e4 | ||
|
|
17a3e25036 | ||
|
|
c4b8d3ea8b | ||
|
|
118fd21cb8 | ||
|
|
969485c754 | ||
|
|
519e81d0fa | ||
|
|
12ca45a264 | ||
|
|
3ac60b31a2 | ||
|
|
c105ff1c51 | ||
|
|
ae9bc93ccc | ||
|
|
afc665d7c8 | ||
|
|
2d173f51b1 | ||
|
|
b32ba3727b | ||
|
|
5793271308 | ||
|
|
09140a51d5 | ||
|
|
cf662b842b | ||
|
|
0ac518040b | ||
|
|
067fac05a8 | ||
|
|
c7d0358c41 | ||
|
|
c957e4ba86 | ||
|
|
c8dca0a56c | ||
|
|
da3569c490 | ||
|
|
e8356afa26 | ||
|
|
c1bd628ce5 | ||
|
|
849096d5f3 | ||
|
|
e681369a1a | ||
|
|
faa29c8062 | ||
|
|
44f2a2a952 | ||
|
|
292453d306 | ||
|
|
1ae78d08e9 | ||
|
|
1c3cbe9456 | ||
|
|
88f4c38dca | ||
|
|
b7b368a1ed | ||
|
|
d2fafbdd9e | ||
|
|
d981973096 | ||
|
|
b310501970 | ||
|
|
e92ce565dd | ||
|
|
da4f2c5ea0 | ||
|
|
bd48c3a083 | ||
|
|
ba58e0446d | ||
|
|
c03b4921c3 | ||
|
|
c60e4aceed | ||
|
|
156de2e4c2 | ||
|
|
959509496a | ||
|
|
8419e152bb | ||
|
|
1bc3e0a678 | ||
|
|
d093200966 | ||
|
|
72dc21fb1a | ||
|
|
24b8f4ebc1 | ||
|
|
136dccbcdf | ||
|
|
d0e6a0928b | ||
|
|
46846d4297 | ||
|
|
01ee9e16c5 | ||
|
|
38411fd2e7 | ||
|
|
b8094de129 | ||
|
|
73207a12ba | ||
|
|
3af87e1c42 | ||
|
|
d2547ce6b0 | ||
|
|
7e3d7e071f | ||
|
|
d4bed025ed | ||
|
|
a82e949c00 | ||
|
|
ca9756413f | ||
|
|
b9940f0e0d | ||
|
|
f91a49c65d | ||
|
|
4b8ad3fc03 | ||
|
|
e8aabbb40b | ||
|
|
02a5fa2c79 | ||
|
|
944c121a00 | ||
|
|
c9b6662138 | ||
|
|
b85755c0ff | ||
|
|
b6f24e78ac | ||
|
|
fc24aa041b | ||
|
|
c9b44b5bb6 | ||
|
|
2255176228 | ||
|
|
ccaa25eaa5 | ||
|
|
969ee4c8f9 | ||
|
|
c35278e217 | ||
|
|
039d3f0523 | ||
|
|
d56f8407a5 | ||
|
|
142b92b883 | ||
|
|
c292006421 | ||
|
|
5c4cc0d646 | ||
|
|
a361b92184 | ||
|
|
37572bc217 | ||
|
|
233adfe660 | ||
|
|
450c14b286 | ||
|
|
33dfc386c9 | ||
|
|
f331936969 | ||
|
|
8f1d0c2a7c | ||
|
|
02549c9299 | ||
|
|
98f2adbcb5 | ||
|
|
c9d21574d8 | ||
|
|
253517096e | ||
|
|
0fa35254c6 | ||
|
|
fc9fb7473c | ||
|
|
31ca2331d2 | ||
|
|
b5062a07d1 | ||
|
|
4112007314 | ||
|
|
a3162b17d9 | ||
|
|
e177d4f70d | ||
|
|
631b0e6c37 | ||
|
|
a7f339ad1c | ||
|
|
c1c0b2dd38 | ||
|
|
d7a1111955 | ||
|
|
d73340474b | ||
|
|
4f7237de44 | ||
|
|
4096745a58 | ||
|
|
a97e074022 | ||
|
|
917c6aa94a | ||
|
|
05bd6fda7e | ||
|
|
7c78de989d | ||
|
|
35a6d9ba87 | ||
|
|
c63754fc32 | ||
|
|
ccb93068fe | ||
|
|
a6fe355801 | ||
|
|
fe11c3e348 | ||
|
|
56d4422d31 | ||
|
|
e507848a8f | ||
|
|
70599667cb | ||
|
|
1878da228d | ||
|
|
37865d69a2 | ||
|
|
83eba902a3 | ||
|
|
ec805aee2e | ||
|
|
167b18b58f | ||
|
|
4b1a530330 | ||
|
|
19ffaa9ff0 | ||
|
|
0f5167a407 | ||
|
|
563ab5caa5 | ||
|
|
db5b5f121c | ||
|
|
1f417a8441 | ||
|
|
b74b09ea7a | ||
|
|
2cce67ad84 | ||
|
|
2cb935c300 | ||
|
|
b9623c1128 | ||
|
|
7a386cff7d | ||
|
|
839725e3c5 | ||
|
|
8920479f85 | ||
|
|
4c25eae9b4 | ||
|
|
a3a45b5037 | ||
|
|
dc645d76b4 | ||
|
|
daff83ee9a | ||
|
|
9f9e3e61d6 | ||
|
|
1592395036 | ||
|
|
8491b1f86a | ||
|
|
a7b4d70cc6 | ||
|
|
fa193e9618 | ||
|
|
050008f3c8 | ||
|
|
70e53cb080 | ||
|
|
7b03b04c78 | ||
|
|
7a7b98cc31 | ||
|
|
15d5837322 | ||
|
|
f9ebb8b23e | ||
|
|
77b94451de | ||
|
|
ca6245e974 | ||
|
|
1cdddeec30 | ||
|
|
657c908f88 | ||
|
|
d7a0e22d59 | ||
|
|
33b809714f | ||
|
|
b915a2ad7d | ||
|
|
85ed5cef7f | ||
|
|
df42b0d1ac | ||
|
|
98add22891 | ||
|
|
1d81bf5596 | ||
|
|
e4153a536f | ||
|
|
79f31238b0 | ||
|
|
8c712d959d | ||
|
|
c4b1a79db2 | ||
|
|
47f12f107d | ||
|
|
bfad970e4d | ||
|
|
49bdc6fbd1 | ||
|
|
57f279677f | ||
|
|
fff73c7735 | ||
|
|
e44678ceba | ||
|
|
85c0e9c574 | ||
|
|
0c3ec7f9a5 | ||
|
|
74e15b2eb5 | ||
|
|
565861f680 | ||
|
|
7c991399ac | ||
|
|
384c853a39 | ||
|
|
c0380d0280 | ||
|
|
a1c61563a0 | ||
|
|
aa0f1aaeb2 | ||
|
|
03ddd64b93 | ||
|
|
7fc9ba7d3a | ||
|
|
63b6bab5c3 | ||
|
|
eb4eeb6f73 | ||
|
|
6988507998 | ||
|
|
65be6d5146 | ||
|
|
6d05dd07f5 | ||
|
|
7436ec093a | ||
|
|
2b735daae5 | ||
|
|
f8b0c884b0 | ||
|
|
18f4d343f5 | ||
|
|
31e78c90e2 | ||
|
|
3238256b79 | ||
|
|
59b71d5d05 | ||
|
|
4dfa6c6ee4 | ||
|
|
60e488eb17 | ||
|
|
14340ac4df | ||
|
|
efbfc2b1ab | ||
|
|
d4f09bc20d | ||
|
|
d67f962a38 | ||
|
|
6de85d02ae | ||
|
|
f28eb902df | ||
|
|
9702d522a4 | ||
|
|
4f710b0470 | ||
|
|
5f29787dc7 | ||
|
|
1fbb36fa87 | ||
|
|
3cafcc2bc7 | ||
|
|
8d92c898ee | ||
|
|
9bf73cd72d | ||
|
|
f97cf5c3b6 | ||
|
|
5ff2d5aee6 | ||
|
|
1f474742eb | ||
|
|
0041a0079d | ||
|
|
9bb8b0c622 | ||
|
|
df6d3107f2 | ||
|
|
cbdc54843d | ||
|
|
d2027cb4a9 | ||
|
|
e60779bfe1 | ||
|
|
f66b1ac450 | ||
|
|
ff6a96665a | ||
|
|
4388a294a4 | ||
|
|
d21b9280f0 | ||
|
|
92649332ce | ||
|
|
be91c1229f | ||
|
|
168cb95bd5 | ||
|
|
1d796a4e24 | ||
|
|
8e6d5efdac | ||
|
|
0f2478b62f | ||
|
|
e5d7e593ec | ||
|
|
69b927bfe9 | ||
|
|
944d176856 | ||
|
|
cdd5a772e8 | ||
|
|
0a3c23bcf6 | ||
|
|
cb286ede9d | ||
|
|
16e3dbb18c | ||
|
|
a38437f378 | ||
|
|
8d6ecd9af8 | ||
|
|
342a7096ea | ||
|
|
60a4bda9d4 | ||
|
|
d5fc594317 | ||
|
|
64407dc5d2 | ||
|
|
b0329465ec | ||
|
|
0f70b420f2 | ||
|
|
21c4dea0e6 | ||
|
|
bcaf818c0e | ||
|
|
37bac916e7 | ||
|
|
affdbbf9ca | ||
|
|
4fcf0ff2ac | ||
|
|
c19af4fb2b | ||
|
|
f53897758d | ||
|
|
54002c4391 | ||
|
|
6a53eaefc0 | ||
|
|
4bc114336c | ||
|
|
47f1d377f5 | ||
|
|
566699f68a | ||
|
|
29ba92a551 | ||
|
|
38e9484f9f | ||
|
|
fec12030a9 | ||
|
|
bdfdf7ef55 | ||
|
|
9f65ae72c3 | ||
|
|
3434ea540c | ||
|
|
29131c873a | ||
|
|
ab1eb70d1c | ||
|
|
71256f9456 | ||
|
|
6179839215 | ||
|
|
0ca96e543c | ||
|
|
acb0b8f599 | ||
|
|
20d0936fa2 | ||
|
|
c24b7a7ef9 | ||
|
|
074495a13a | ||
|
|
e14d86d8b8 | ||
|
|
528c29c01c | ||
|
|
1bb7a22115 | ||
|
|
19ed67331d | ||
|
|
667b72870f | ||
|
|
4194ebf9df | ||
|
|
5beceaae5c | ||
|
|
9c1bf1387c | ||
|
|
fc6a31eac8 | ||
|
|
064e8bdd84 | ||
|
|
262ccbcf30 | ||
|
|
7567885115 | ||
|
|
ed715ec437 | ||
|
|
9a44a20a9d | ||
|
|
f335045273 | ||
|
|
4ea091339e | ||
|
|
8378b7345b | ||
|
|
4a71c7a2bd | ||
|
|
b2885a53cb | ||
|
|
46b6b4037d | ||
|
|
93d3a6e1d1 | ||
|
|
eebaeeff96 | ||
|
|
3a7a77d49e | ||
|
|
c87c090264 | ||
|
|
b26922978a | ||
|
|
5a5bd2596a | ||
|
|
38ca051381 | ||
|
|
91056809dd | ||
|
|
f75430e95f | ||
|
|
8e797e6830 | ||
|
|
73c4be3fd3 | ||
|
|
c552ba06b4 | ||
|
|
6bd5f4e44e | ||
|
|
6138d18f4b | ||
|
|
d028f42e99 | ||
|
|
860fc3e91d | ||
|
|
2e03d84755 | ||
|
|
f2b406fc5e | ||
|
|
f46bc0ef04 | ||
|
|
800d53db6a | ||
|
|
a9444d3399 | ||
|
|
4a16053c00 | ||
|
|
d0c61f0f76 | ||
|
|
451ffd567d | ||
|
|
f3a49604f1 | ||
|
|
3576dd6e87 | ||
|
|
3b668c9baf | ||
|
|
618fe0e6fb | ||
|
|
872b08601a | ||
|
|
fe95ea221b | ||
|
|
4e8674d5df | ||
|
|
9894348e12 | ||
|
|
189ac86b06 | ||
|
|
6f3bbafbbd | ||
|
|
3a478adeaa | ||
|
|
29aa6ef6c7 | ||
|
|
219796ef4e | ||
|
|
4f087c331c | ||
|
|
18456f71f8 | ||
|
|
1d841eeb87 | ||
|
|
19d1f83d97 | ||
|
|
6efadf44d0 | ||
|
|
e4c4a4628b | ||
|
|
a217c0f394 | ||
|
|
1dbd11446c | ||
|
|
74fa8a3907 | ||
|
|
cad1e0b985 | ||
|
|
b099851a8b | ||
|
|
f25ead109c | ||
|
|
edd7dfe1c8 | ||
|
|
89f5452ddb | ||
|
|
a6de1db94d | ||
|
|
ed9d7e4fae | ||
|
|
e169f70bfb | ||
|
|
35428f2e04 | ||
|
|
0718a1bd1f | ||
|
|
83f7d702e7 | ||
|
|
12d4888321 | ||
|
|
4565a73e91 | ||
|
|
9c932ad514 | ||
|
|
5458f3cbd2 | ||
|
|
611e1d239b | ||
|
|
d2abbd8f5d | ||
|
|
00b40b720f | ||
|
|
71b4923208 | ||
|
|
c49d3fdb17 | ||
|
|
fcaf359e89 | ||
|
|
9a31c068c4 | ||
|
|
babc9e7a1e | ||
|
|
d2ecc9d80c | ||
|
|
fbd7cc243b | ||
|
|
a6055ce069 | ||
|
|
35719e665c | ||
|
|
bc80ed4e88 | ||
|
|
5ebe8ce025 | ||
|
|
17dcb42752 | ||
|
|
2f97b2d7c2 | ||
|
|
57244de37d | ||
|
|
3806ed882a | ||
|
|
ce7e7c4048 | ||
|
|
524e0290bc | ||
|
|
dbdf1e137e | ||
|
|
6ebb1a68cb | ||
|
|
7e7e607e3f | ||
|
|
4eb21a71ae | ||
|
|
4f07ee4d92 | ||
|
|
b14db404b5 | ||
|
|
7cb71df02c | ||
|
|
55fc11ff02 | ||
|
|
0d43d269ed | ||
|
|
a0829c63de | ||
|
|
535c7b99b4 | ||
|
|
5d805ba550 | ||
|
|
bafe796eeb | ||
|
|
ceb60ffcc6 | ||
|
|
72c4f353e6 | ||
|
|
4d6830a373 | ||
|
|
f547cab710 | ||
|
|
7835f50722 | ||
|
|
d161d66741 | ||
|
|
9755182adf | ||
|
|
a5637bb9d4 | ||
|
|
1e1364c3d4 | ||
|
|
7cf914537b | ||
|
|
ab1972d1cf | ||
|
|
e0aa067cc9 | ||
|
|
4f30dce64f | ||
|
|
2b5b899d35 | ||
|
|
781cf608d7 | ||
|
|
9e1059afb4 | ||
|
|
7ef8c0442a | ||
|
|
6ab269ceb7 | ||
|
|
fd7cb99f47 | ||
|
|
5a1ec817d4 | ||
|
|
9ad8153d33 | ||
|
|
941427554a | ||
|
|
7554c7f694 | ||
|
|
79da35d023 | ||
|
|
1dee1ba64e | ||
|
|
afecf7ce36 | ||
|
|
5e6127869a | ||
|
|
3b5b895a10 | ||
|
|
345fc41482 | ||
|
|
93dd310add | ||
|
|
a201385008 | ||
|
|
9d7aa1e155 | ||
|
|
6285cc6f66 | ||
|
|
8e165fecc0 | ||
|
|
7c8addc5c5 | ||
|
|
5419c456ac | ||
|
|
2b7ab290b8 | ||
|
|
508a934d62 | ||
|
|
8025921fc8 | ||
|
|
ff6fef927a | ||
|
|
77d486f8d2 | ||
|
|
233a90ce8b | ||
|
|
41ef0bd98c | ||
|
|
f58d93c0bf | ||
|
|
8f331f08d2 | ||
|
|
f0cefebff7 | ||
|
|
2904a0bbac | ||
|
|
6a96e83ea9 | ||
|
|
306db9a851 | ||
|
|
93bd19a8c2 | ||
|
|
98ce7dc465 | ||
|
|
9edf60ffc6 | ||
|
|
884cee27eb | ||
|
|
0f87493487 | ||
|
|
8be8cb7a91 | ||
|
|
977aabe038 | ||
|
|
da7d8dbcac | ||
|
|
3809e4c055 | ||
|
|
7f8a94ff48 | ||
|
|
ee56b14faa | ||
|
|
ab54fcd443 | ||
|
|
9fa0a62c8a | ||
|
|
9faa0fbd25 | ||
|
|
3167e8ddbe | ||
|
|
b53da365a1 | ||
|
|
275b386856 | ||
|
|
e9505697fb | ||
|
|
47f303317b | ||
|
|
0685802cb8 | ||
|
|
c8ff439722 | ||
|
|
a7b81dc05c | ||
|
|
0824d32319 | ||
|
|
9ff5600421 | ||
|
|
94272ed072 | ||
|
|
7b2f6f89f0 | ||
|
|
06dbc40f53 | ||
|
|
1bbcb51066 | ||
|
|
33a48d926c | ||
|
|
c5f50e73c2 | ||
|
|
7276c7085a | ||
|
|
e52113a319 | ||
|
|
11ecac626d | ||
|
|
5a24ab06d8 | ||
|
|
654546e338 | ||
|
|
170389ef14 | ||
|
|
a17229a4c1 | ||
|
|
92f81d51f4 | ||
|
|
e9c03f2e4a | ||
|
|
dc37a07a8e | ||
|
|
c847606311 | ||
|
|
589017a3d6 | ||
|
|
d3c27c514f | ||
|
|
777a0b817b | ||
|
|
4988ba9a71 | ||
|
|
3fa7da804d | ||
|
|
af99ab1645 | ||
|
|
4a527a46ce | ||
|
|
5829aa8bd7 | ||
|
|
9bb1ae079f | ||
|
|
e0a9a1b800 | ||
|
|
861f5a5387 | ||
|
|
20ae4e5d98 | ||
|
|
b3e8b430e5 | ||
|
|
ae8d57e650 | ||
|
|
b0b2e9c4aa | ||
|
|
409904c61c | ||
|
|
afb1839b6b | ||
|
|
cc62a3dbf3 | ||
|
|
31c04261c1 | ||
|
|
6220cdda92 | ||
|
|
da305e6b61 | ||
|
|
343de9c454 | ||
|
|
e59951c8ae | ||
|
|
ea5f825a91 | ||
|
|
b3e4ff7ef0 | ||
|
|
b0524947e5 | ||
|
|
fa85094cbb | ||
|
|
9dd101c26f | ||
|
|
4fcf5a31f5 | ||
|
|
c20f993747 | ||
|
|
71947d6bea | ||
|
|
220a1e4197 | ||
|
|
4dd3478fc1 | ||
|
|
8e1c0941b0 | ||
|
|
62f96f0911 | ||
|
|
73f3b0636a | ||
|
|
9f8817a47e | ||
|
|
9971f999b3 | ||
|
|
ff789058df | ||
|
|
bd07cd1193 | ||
|
|
a6de2184ba | ||
|
|
bb3b881e21 | ||
|
|
e4859d2e9a | ||
|
|
91e7807af6 | ||
|
|
38f1d78e1b | ||
|
|
b52b65624b | ||
|
|
2a17d9457a | ||
|
|
7531d0c678 | ||
|
|
3eafc83458 | ||
|
|
4326a3adce | ||
|
|
ed103822f5 | ||
|
|
d68cb264c4 | ||
|
|
45ba03efa3 | ||
|
|
f582a36e4d |
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
out
|
||||
*.so
|
||||
*.pyc
|
||||
.config
|
||||
.config.old
|
||||
674
COPYING
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
118
Makefile
Normal file
@@ -0,0 +1,118 @@
|
||||
# Klipper build system
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
# Output directory
|
||||
OUT=out/
|
||||
|
||||
# Kconfig includes
|
||||
export HOSTCC := $(CC)
|
||||
export CONFIG_SHELL := sh
|
||||
export KCONFIG_AUTOHEADER := autoconf.h
|
||||
export KCONFIG_CONFIG := $(CURDIR)/.config
|
||||
-include $(KCONFIG_CONFIG)
|
||||
|
||||
# Common command definitions
|
||||
CC=$(CROSS_PREFIX)gcc
|
||||
AS=$(CROSS_PREFIX)as
|
||||
LD=$(CROSS_PREFIX)ld
|
||||
OBJCOPY=$(CROSS_PREFIX)objcopy
|
||||
OBJDUMP=$(CROSS_PREFIX)objdump
|
||||
STRIP=$(CROSS_PREFIX)strip
|
||||
CPP=cpp
|
||||
PYTHON=python2
|
||||
|
||||
# Source files
|
||||
src-y =
|
||||
dirs-y = src
|
||||
|
||||
# Default compiler flags
|
||||
cc-option=$(shell if test -z "`$(1) $(2) -S -o /dev/null -xc /dev/null 2>&1`" \
|
||||
; then echo "$(2)"; else echo "$(3)"; fi ;)
|
||||
|
||||
CFLAGS := -I$(OUT) -Isrc -I$(OUT)board-generic/ -O2 -MD -g \
|
||||
-Wall -Wold-style-definition $(call cc-option,$(CC),-Wtype-limits,) \
|
||||
-ffunction-sections -fdata-sections
|
||||
CFLAGS += -flto -fwhole-program -fno-use-linker-plugin
|
||||
|
||||
CFLAGS_klipper.elf = $(CFLAGS) -Wl,--gc-sections
|
||||
|
||||
CPPFLAGS = -I$(OUT) -P -MD -MT $@
|
||||
|
||||
# Default targets
|
||||
target-y := $(OUT)klipper.elf
|
||||
|
||||
all:
|
||||
|
||||
# Run with "make V=1" to see the actual compile commands
|
||||
ifdef V
|
||||
Q=
|
||||
else
|
||||
Q=@
|
||||
MAKEFLAGS += --no-print-directory
|
||||
endif
|
||||
|
||||
# Include board specific makefile
|
||||
include src/Makefile
|
||||
-include src/$(patsubst "%",%,$(CONFIG_BOARD_DIRECTORY))/Makefile
|
||||
|
||||
################ Common build rules
|
||||
|
||||
$(OUT)%.o: %.c $(OUT)autoconf.h $(OUT)board-link
|
||||
@echo " Compiling $@"
|
||||
$(Q)$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
################ Main build rules
|
||||
|
||||
$(OUT)board-link: $(KCONFIG_CONFIG)
|
||||
@echo " Creating symbolic link $(OUT)board"
|
||||
$(Q)mkdir -p $(addprefix $(OUT), $(dirs-y))
|
||||
$(Q)touch $@
|
||||
$(Q)ln -Tsf $(PWD)/src/$(CONFIG_BOARD_DIRECTORY) $(OUT)board
|
||||
$(Q)mkdir -p $(OUT)board-generic
|
||||
$(Q)ln -Tsf $(PWD)/src/generic $(OUT)board-generic/board
|
||||
|
||||
$(OUT)%.o.ctr: $(OUT)%.o
|
||||
$(Q)$(OBJCOPY) -j '.compile_time_request' -O binary $^ $@
|
||||
|
||||
$(OUT)compile_time_request.o: $(patsubst %.c, $(OUT)src/%.o.ctr,$(src-y)) ./scripts/buildcommands.py
|
||||
@echo " Building $@"
|
||||
$(Q)cat $(patsubst %.c, $(OUT)src/%.o.ctr,$(src-y)) > $(OUT)klipper.compile_time_request
|
||||
$(Q)$(PYTHON) ./scripts/buildcommands.py -d $(OUT)klipper.dict $(OUT)klipper.compile_time_request $(OUT)compile_time_request.c
|
||||
$(Q)$(CC) $(CFLAGS) -c $(OUT)compile_time_request.c -o $@
|
||||
|
||||
$(OUT)klipper.elf: $(patsubst %.c, $(OUT)src/%.o,$(src-y)) $(OUT)compile_time_request.o
|
||||
@echo " Linking $@"
|
||||
$(Q)$(CC) $(CFLAGS_klipper.elf) $^ -o $@
|
||||
|
||||
################ Kconfig rules
|
||||
|
||||
define do-kconfig
|
||||
$(Q)mkdir -p $(OUT)/scripts/kconfig/lxdialog
|
||||
$(Q)mkdir -p $(OUT)/include/config
|
||||
$(Q)$(MAKE) -C $(OUT) -f $(CURDIR)/scripts/kconfig/Makefile srctree=$(CURDIR) src=scripts/kconfig obj=scripts/kconfig Q=$(Q) Kconfig=$(CURDIR)/src/Kconfig $1
|
||||
endef
|
||||
|
||||
$(OUT)autoconf.h : $(KCONFIG_CONFIG) ; $(call do-kconfig, silentoldconfig)
|
||||
$(KCONFIG_CONFIG): src/Kconfig ; $(call do-kconfig, olddefconfig)
|
||||
%onfig: ; $(call do-kconfig, $@)
|
||||
help: ; $(call do-kconfig, $@)
|
||||
|
||||
|
||||
################ Generic rules
|
||||
|
||||
# Make definitions
|
||||
.PHONY : all clean distclean FORCE
|
||||
.DELETE_ON_ERROR:
|
||||
|
||||
all: $(target-y)
|
||||
|
||||
clean:
|
||||
$(Q)rm -rf $(OUT)
|
||||
|
||||
distclean: clean
|
||||
$(Q)rm -f .config .config.old
|
||||
|
||||
-include $(OUT)*.d $(patsubst %,$(OUT)%/*.d,$(dirs-y))
|
||||
29
README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
Welcome to the Klipper project!
|
||||
|
||||
This project implements a 3d-printer firmware. There are two parts to
|
||||
this firmware - code that runs on a micro-controller and code that
|
||||
runs on a host machine. The host software does the work to build a
|
||||
schedule of events, while the micro-controller software does the work
|
||||
to execute the provided schedule at the specified times.
|
||||
|
||||
See the [features](docs/Features.md) document to find out why you
|
||||
should use Klipper. To begin using Klipper start by
|
||||
[installing](docs/Installation.md) it.
|
||||
|
||||
There is also [developer documentation](docs/Overview.md) available.
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
Klipper 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.
|
||||
|
||||
Klipper 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 Klipper. If not, see <http://www.gnu.org/licenses/>.
|
||||
78
config/avrsim.cfg
Normal file
@@ -0,0 +1,78 @@
|
||||
# Support for internal testing with the "simulavr" program. To use
|
||||
# this config, compile the firmware for an AVR atmega644p, disable the
|
||||
# AVR watchdog timer, set the MCU frequency to 20000000, and set the
|
||||
# serial baud rate to 250000.
|
||||
|
||||
[stepper_x]
|
||||
# Pins: PA5, PA4, PA1
|
||||
step_pin: ar29
|
||||
dir_pin: ar28
|
||||
enable_pin: ar25
|
||||
step_distance: .0225
|
||||
endstop_pin: ^ar0
|
||||
position_min: -0.25
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
|
||||
[stepper_y]
|
||||
# Pins: PA3, PA2
|
||||
step_pin: ar27
|
||||
dir_pin: ar26
|
||||
enable_pin: ar25
|
||||
step_distance: .0225
|
||||
endstop_pin: ^ar1
|
||||
position_min: -0.25
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
|
||||
[stepper_z]
|
||||
# Pins: PC7, PC6
|
||||
step_pin: ar23
|
||||
dir_pin: ar22
|
||||
enable_pin: ar25
|
||||
step_distance: .005
|
||||
endstop_pin: ^ar2
|
||||
position_min: 0.1
|
||||
position_endstop: 0.5
|
||||
position_max: 200
|
||||
|
||||
[extruder]
|
||||
# Pins: PC3, PC2
|
||||
step_pin: ar19
|
||||
dir_pin: ar18
|
||||
enable_pin: ar25
|
||||
step_distance: .004242
|
||||
nozzle_diameter: 0.500
|
||||
filament_diameter: 3.500
|
||||
heater_pin: ar4
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: analog1
|
||||
control: pid
|
||||
pid_Kp: 22.2
|
||||
pid_Ki: 1.08
|
||||
pid_Kd: 114
|
||||
min_temp: 0
|
||||
min_extrude_temp: 0
|
||||
max_temp: 210
|
||||
|
||||
[heater_bed]
|
||||
heater_pin: ar3
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: analog0
|
||||
control: watermark
|
||||
min_temp: 0
|
||||
max_temp: 110
|
||||
|
||||
[fan]
|
||||
pin: ar14
|
||||
|
||||
[mcu]
|
||||
serial: /tmp/pseudoserial
|
||||
pin_map: arduino
|
||||
|
||||
[printer]
|
||||
kinematics: cartesian
|
||||
max_velocity: 500
|
||||
max_accel: 3000
|
||||
max_z_velocity: 250
|
||||
max_z_accel: 30
|
||||
81
config/example-corexy.cfg
Normal file
@@ -0,0 +1,81 @@
|
||||
# This file serves as documentation for config parameters of corexy
|
||||
# style printers. One may copy and edit this file to configure a new
|
||||
# corexy printer. Only parameters unique to corexy printers are
|
||||
# described here - see the "example.cfg" file for description of
|
||||
# common config parameters.
|
||||
|
||||
# DO NOT COPY THIS FILE WITHOUT CAREFULLY READING AND UPDATING IT
|
||||
# FIRST. Incorrectly configured parameters may cause damage.
|
||||
|
||||
# The stepper_x section is used to describe the X axis as well as the
|
||||
# stepper controlling the X+Y movement.
|
||||
[stepper_x]
|
||||
step_pin: ar54
|
||||
dir_pin: ar55
|
||||
enable_pin: !ar38
|
||||
step_distance: .01
|
||||
endstop_pin: ^ar3
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
homing_speed: 50
|
||||
|
||||
# The stepper_y section is used to describe the Y axis as well as the
|
||||
# stepper controlling the X-Y movement.
|
||||
[stepper_y]
|
||||
step_pin: ar60
|
||||
dir_pin: ar61
|
||||
enable_pin: !ar56
|
||||
step_distance: .01
|
||||
endstop_pin: ^ar14
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
homing_speed: 50
|
||||
|
||||
[stepper_z]
|
||||
step_pin: ar46
|
||||
dir_pin: ar48
|
||||
enable_pin: !ar62
|
||||
step_distance: .01
|
||||
endstop_pin: ^ar18
|
||||
position_endstop: 0.5
|
||||
position_max: 200
|
||||
|
||||
[extruder]
|
||||
step_pin: ar26
|
||||
dir_pin: ar28
|
||||
enable_pin: !ar24
|
||||
step_distance: .0022
|
||||
nozzle_diameter: 0.400
|
||||
filament_diameter: 1.750
|
||||
heater_pin: ar10
|
||||
sensor_type: ATC Semitec 104GT-2
|
||||
sensor_pin: analog13
|
||||
control: pid
|
||||
pid_Kp: 22.2
|
||||
pid_Ki: 1.08
|
||||
pid_Kd: 114
|
||||
min_temp: 0
|
||||
max_temp: 250
|
||||
|
||||
[heater_bed]
|
||||
heater_pin: ar8
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: analog14
|
||||
control: watermark
|
||||
min_temp: 0
|
||||
max_temp: 130
|
||||
|
||||
[fan]
|
||||
pin: ar9
|
||||
|
||||
[mcu]
|
||||
serial: /dev/ttyACM0
|
||||
pin_map: arduino
|
||||
|
||||
[printer]
|
||||
kinematics: corexy
|
||||
# This option must be "corexy" for corexy printers.
|
||||
max_velocity: 300
|
||||
max_accel: 3000
|
||||
max_z_velocity: 25
|
||||
max_z_accel: 30
|
||||
101
config/example-delta.cfg
Normal file
@@ -0,0 +1,101 @@
|
||||
# This file serves as documentation for config parameters of delta
|
||||
# style printers. One may copy and edit this file to configure a new
|
||||
# delta printer. Only parameters unique to delta printers are
|
||||
# described here - see the "example.cfg" file for description of
|
||||
# common config parameters.
|
||||
|
||||
# DO NOT COPY THIS FILE WITHOUT CAREFULLY READING AND UPDATING IT
|
||||
# FIRST. Incorrectly configured parameters may cause damage.
|
||||
|
||||
# The stepper_a section describes the stepper controlling the front
|
||||
# left tower (at 210 degrees). This section also controls the homing
|
||||
# parameters (homing_speed, homing_retract_dist) for all towers.
|
||||
[stepper_a]
|
||||
step_pin: ar54
|
||||
dir_pin: ar55
|
||||
enable_pin: !ar38
|
||||
step_distance: .01
|
||||
endstop_pin: ^ar2
|
||||
position_endstop: 297.05
|
||||
#angle:
|
||||
# This option specifies the angle (in degrees) that the tower is
|
||||
# at. The default is 210 for stepper_a, 330 for stepper_b, and 90
|
||||
# for stepper_c.
|
||||
homing_speed: 50
|
||||
|
||||
# The stepper_b section describes the stepper controlling the front
|
||||
# right tower (at 330 degrees).
|
||||
[stepper_b]
|
||||
step_pin: ar60
|
||||
dir_pin: ar61
|
||||
enable_pin: !ar56
|
||||
step_distance: .01
|
||||
endstop_pin: ^ar15
|
||||
position_endstop: 297.05
|
||||
|
||||
# The stepper_c section describes the stepper controlling the rear
|
||||
# tower (at 90 degrees).
|
||||
[stepper_c]
|
||||
step_pin: ar46
|
||||
dir_pin: ar48
|
||||
enable_pin: !ar62
|
||||
step_distance: .01
|
||||
endstop_pin: ^ar19
|
||||
position_endstop: 297.05
|
||||
|
||||
[extruder]
|
||||
step_pin: ar26
|
||||
dir_pin: ar28
|
||||
enable_pin: !ar24
|
||||
step_distance: .0022
|
||||
nozzle_diameter: 0.400
|
||||
filament_diameter: 1.750
|
||||
heater_pin: ar10
|
||||
sensor_type: ATC Semitec 104GT-2
|
||||
sensor_pin: analog13
|
||||
control: pid
|
||||
pid_Kp: 22.2
|
||||
pid_Ki: 1.08
|
||||
pid_Kd: 114
|
||||
min_temp: 0
|
||||
max_temp: 250
|
||||
|
||||
[heater_bed]
|
||||
heater_pin: ar8
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: analog14
|
||||
control: watermark
|
||||
min_temp: 0
|
||||
max_temp: 130
|
||||
|
||||
# Print cooling fan (omit section if fan not present).
|
||||
#[fan]
|
||||
#pin: ar9
|
||||
|
||||
[mcu]
|
||||
serial: /dev/ttyACM0
|
||||
pin_map: arduino
|
||||
|
||||
[printer]
|
||||
kinematics: delta
|
||||
# This option must be "delta" for linear delta printers.
|
||||
max_velocity: 300
|
||||
# Maximum velocity (in mm/s) of the toolhead relative to the
|
||||
# print. This parameter must be specified.
|
||||
max_accel: 3000
|
||||
# Maximum acceleration (in mm/s^2) of the toolhead relative to the
|
||||
# print. This parameter must be specified.
|
||||
max_z_velocity: 150
|
||||
# For delta printers this limits the maximum velocity (in mm/s) of
|
||||
# moves with z axis movement. This setting can be used to reduce the
|
||||
# maximum speed of up/down moves (which require a higher step rate
|
||||
# than other moves on a delta printer). The default is to use
|
||||
# max_velocity for max_z_velocity.
|
||||
delta_arm_length: 333.0
|
||||
# Length (in mm) of the diagonal rods that connect the linear axes
|
||||
# to the print head. This parameter must be provided.
|
||||
delta_radius: 174.75
|
||||
# Radius (in mm) of the horizontal circle formed by the three linear
|
||||
# axis towers. This parameter may also be calculated as:
|
||||
# delta_radius = smooth_rod_offset - effector_offset - carriage_offset
|
||||
# This parameter must be provided.
|
||||
153
config/example-extras.cfg
Normal file
@@ -0,0 +1,153 @@
|
||||
# This file serves as documentation for config parameters of
|
||||
# additional devices that may be configured on a printer. The snippets
|
||||
# in this file may be copied into the main printer.cfg file. See the
|
||||
# "example.cfg" file for description of common config parameters.
|
||||
|
||||
|
||||
# In a multi-extruder printer add an additional extruder section for
|
||||
# each additional extruder. The additional extruder sections should be
|
||||
# named "extruder1", "extruder2", "extruder3", and so on. See the
|
||||
# "extruder" section in example.cfg for a description of available
|
||||
# parameters.
|
||||
#[extruder1]
|
||||
#step_pin: ar36
|
||||
#dir_pin: ar34
|
||||
#...
|
||||
#deactivate_gcode:
|
||||
# A list of G-Code commands (one per line) to execute on a G-Code
|
||||
# tool change command (eg, "T1") that deactivates this extruder and
|
||||
# activates some other extruder. It only makes sense to define this
|
||||
# section on multi-extruder printers. The default is to not run any
|
||||
# special G-Code commands on deactivation.
|
||||
#activate_gcode:
|
||||
# A list of G-Code commands (one per line) to execute on a G-Code
|
||||
# tool change command (eg, "T0") that activates this extruder. It
|
||||
# only makes sense to define this section on multi-extruder
|
||||
# printers. The default is to not run any special G-Code commands on
|
||||
# activation.
|
||||
|
||||
|
||||
# Heater cooling fans (one may define any number of sections with a
|
||||
# "heater_fan" prefix). A "heater fan" is a fan that will be enabled
|
||||
# whenever its associated heater is active. In the event of an MCU
|
||||
# software error the heater_fan will be set to its max_power.
|
||||
#[heater_fan my_nozzle_fan]
|
||||
# See the "fan" section for fan configuration parameters.
|
||||
#pin: ar4
|
||||
# The remaining variables are specific to heater_fan.
|
||||
#heater: extruder
|
||||
# Name of the config section defining the heater that this fan is
|
||||
# associated with. The default is "extruder".
|
||||
#heater_temp: 50.0
|
||||
# A temperature (in Celsius) that the heater must drop below before
|
||||
# the fan is disabled. The default is 50 Celsius.
|
||||
#fan_speed:
|
||||
# The fan speed (expressed as a value from 0.0 to 1.0) that the fan
|
||||
# will be set to when its associated heater is enabled. The default
|
||||
# is max_power.
|
||||
|
||||
|
||||
# Additional micro-controllers (one may define any number of sections
|
||||
# with an "mcu" prefix). Additional micro-controllers introduce
|
||||
# additional pins that may be configured as heaters, steppers, fans,
|
||||
# etc.. For example, if an "[mcu extra_mcu]" section is introduced,
|
||||
# then pins such as "extra_mcu:ar9" may then be used elsewhere in the
|
||||
# config (where "ar9" is a hardware pin name or alias name on the
|
||||
# given mcu).
|
||||
#[mcu my_extra_mcu]
|
||||
# See the "mcu" section in example.cfg for configuration parameters.
|
||||
|
||||
|
||||
# Servos (one may define any number of sections with a "servo"
|
||||
# prefix). The servos may be controlled using the SET_SERVO g-code
|
||||
# command. For example: SET_SERVO SERVO=my_servo ANGLE=180
|
||||
#[servo my_servo]
|
||||
#pin: ar7
|
||||
# PWM output pin controlling the servo. This parameter must be
|
||||
# provided.
|
||||
#maximum_servo_angle: 180
|
||||
# The maximum angle (in degrees) that this servo can be set to. The
|
||||
# default is 180 degrees.
|
||||
#minimum_pulse_width: 0.001
|
||||
# The minimum pulse width time (in seconds). This should correspond
|
||||
# with an angle of 0 degrees. The default is 0.001 seconds.
|
||||
#maximum_pulse_width: 0.002
|
||||
# The maximum pulse width time (in seconds). This should correspond
|
||||
# with an angle of maximum_servo_angle. The default is 0.002
|
||||
# seconds.
|
||||
|
||||
|
||||
# Statically configured digital output pins (one may define any number
|
||||
# of sections with a "static_digital_output" prefix). Pins configured
|
||||
# here will be setup as a GPIO output during MCU configuration.
|
||||
#[static_digital_output my_output_pins]
|
||||
#pins:
|
||||
# A comma separated list of pins to be set as GPIO output pins. The
|
||||
# pin will be set to a high level unless the pin name is prefaced
|
||||
# with "!". This parameter must be provided.
|
||||
|
||||
|
||||
# Statically configured PWM output pins (one may define any number of
|
||||
# sections with a "static_pwm_output" prefix). Pins configured here
|
||||
# will be setup as PWM outputs during MCU configuration.
|
||||
#[static_pwm_output my_output_pwm]
|
||||
#pin:
|
||||
# The pin to configure as PWM output. This parameter must be
|
||||
# provided.
|
||||
#value:
|
||||
# The value to statically set the PWM output to. This is typically
|
||||
# set to a number between 0.0 and 1.0 with 1.0 being full on and 0.0
|
||||
# being full off. However, the range may be changed with the 'scale'
|
||||
# parameter (see below). This parameter must be provided.
|
||||
#hard_pwm:
|
||||
# Set this value to force hardware PWM instead of software PWM. Set
|
||||
# to 1 to force a hardware PWM at the fastest rate; set to a higher
|
||||
# number to force hardware PWM with the given cycle time in clock
|
||||
# ticks. The default is to use software PWM.
|
||||
#cycle_time: 0.100
|
||||
# The amount of time (in seconds) per PWM cycle when using software
|
||||
# based PWM. The default is 0.100 seconds.
|
||||
#scale:
|
||||
# This parameter can be used to alter how the 'value' parameter is
|
||||
# interpreted. If provided, then the 'value' parameter should be
|
||||
# between 0.0 and 'scale'. This may be useful when configuring a PWM
|
||||
# pin that controls a stepper voltage reference. The 'scale' can be
|
||||
# set to the equivalent stepper amperage if the PWM were fully
|
||||
# enabled, and then the 'value' parameter can be specified using the
|
||||
# desired amperage for the stepper. The default is to not scale the
|
||||
# 'value' parameter.
|
||||
|
||||
|
||||
# Statically configured AD5206 digipots connected via SPI bus (one may
|
||||
# define any number of sections with an "ad5206" prefix).
|
||||
#[ad5206 my_digipot]
|
||||
#enable_pin:
|
||||
# The pin corresponding to the AD5206 chip select line. This pin
|
||||
# will be set to low at the start of SPI messages and raised to high
|
||||
# after the message completes. This parameter must be provided.
|
||||
#channel_1:
|
||||
#channel_2:
|
||||
#channel_3:
|
||||
#channel_4:
|
||||
#channel_5:
|
||||
#channel_6:
|
||||
# The value to statically set the given AD5206 channel to. This is
|
||||
# typically set to a number between 0.0 and 1.0 with 1.0 being the
|
||||
# highest resistance and 0.0 being the lowest resistance. However,
|
||||
# the range may be changed with the 'scale' parameter (see
|
||||
# below). If a channel is not specified then it is left
|
||||
# unconfigured.
|
||||
#scale:
|
||||
# This parameter can be used to alter how the 'channel_x' parameters
|
||||
# are interpreted. If provided, then the 'channel_x' parameters
|
||||
# should be between 0.0 and 'scale'. This may be useful when the
|
||||
# AD5206 is used to set stepper voltage references. The 'scale' can
|
||||
# be set to the equivalent stepper amperage if the AD5206 were at
|
||||
# its highest resistance, and then the 'channel_x' parameters can be
|
||||
# specified using the desired amperage value for the stepper. The
|
||||
# default is to not scale the 'channel_x' parameters.
|
||||
|
||||
|
||||
# Replicape support - see the generic-replicape.cfg file for further
|
||||
# details.
|
||||
#[replicape]
|
||||
300
config/example.cfg
Normal file
@@ -0,0 +1,300 @@
|
||||
# This file serves as documentation for config parameters. One may
|
||||
# copy and edit this file to configure a new cartesian style
|
||||
# printer. For delta style printers, see the "example-delta.cfg"
|
||||
# file. For corexy/h-bot style printers, see the "example-corexy.cfg"
|
||||
# file. Only common config sections are described here - see the
|
||||
# "example-extras.cfg" file for configuring less common devices.
|
||||
|
||||
# DO NOT COPY THIS FILE WITHOUT CAREFULLY READING AND UPDATING IT
|
||||
# FIRST. Incorrectly configured parameters may cause damage.
|
||||
|
||||
# A note on pin names: pins may be configured with a hardware name
|
||||
# (such as "PA4") or with an Arduino alias name (such as "ar29" or
|
||||
# "analog3"). In order to use Arduino names, the pin_map variable in
|
||||
# the mcu section must be present and have a value of "arduino".
|
||||
# Pin names may be preceded by an '!' to indicate that a reverse
|
||||
# polarity should be used (eg, trigger on low instead of high). Input
|
||||
# pins may be preceded by a '^' to indicate that a hardware pull-up
|
||||
# resistor should be enabled for the pin.
|
||||
|
||||
|
||||
# The stepper_x section is used to describe the stepper controlling
|
||||
# the X axis in a cartesian robot.
|
||||
[stepper_x]
|
||||
step_pin: ar54
|
||||
# Step GPIO pin (triggered high). This parameter must be provided.
|
||||
dir_pin: ar55
|
||||
# Direction GPIO pin (high indicates positive direction). This
|
||||
# parameter must be provided.
|
||||
enable_pin: !ar38
|
||||
# Enable pin (default is enable high; use ! to indicate enable
|
||||
# low). If this parameter is not provided then the stepper motor
|
||||
# driver must always be enabled.
|
||||
step_distance: .0225
|
||||
# Distance in mm that each step causes the axis to travel. This
|
||||
# parameter must be provided.
|
||||
endstop_pin: ^ar3
|
||||
# Endstop switch detection pin. This parameter must be provided for
|
||||
# the X, Y, and Z steppers on cartesian style printers.
|
||||
#position_min: 0
|
||||
# Minimum valid distance (in mm) the user may command the stepper to
|
||||
# move to. The default is 0mm.
|
||||
position_endstop: 0
|
||||
# Location of the endstop (in mm). This parameter must be provided
|
||||
# for the X, Y, and Z steppers on cartesian style printers.
|
||||
position_max: 200
|
||||
# Maximum valid distance (in mm) the user may command the stepper to
|
||||
# move to. This parameter must be provided for the X, Y, and Z
|
||||
# steppers on cartesian style printers.
|
||||
#homing_speed: 5.0
|
||||
# Maximum velocity (in mm/s) of the stepper when homing. The default
|
||||
# is 5mm/s.
|
||||
#homing_retract_dist: 5.0
|
||||
# Distance to backoff (in mm) before homing a second time during
|
||||
# homing. The default is 5mm.
|
||||
#homing_positive_dir:
|
||||
# If true, homing will cause the stepper to move in a positive
|
||||
# direction (away from zero); if false, home towards zero. The
|
||||
# default is true if position_endstop is near position_max and false
|
||||
# if near position_min.
|
||||
#homing_stepper_phases: 0
|
||||
# One may optionally set this to the number of phases of the stepper
|
||||
# motor driver (which is the number of micro-steps multiplied by
|
||||
# four). When set, the phase of the stepper driver will be used
|
||||
# during homing to improve the accuracy of the endstop switch.
|
||||
#homing_endstop_accuracy: 0.200
|
||||
# Sets the expected accuracy (in mm) of the endstop. This represents
|
||||
# the maximum error distance the endstop may trigger (eg, if an
|
||||
# endstop may occasionally trigger 100um early or up to 100um late
|
||||
# then set this to 0.200 for 200um). This setting is used with
|
||||
# homing_stepper_phases and is only useful if that parameter is also
|
||||
# configured.
|
||||
#homing_endstop_phase: 0
|
||||
# This specifies the phase of the stepper motor driver to expect
|
||||
# when hitting the endstop. This setting is only meaningful if
|
||||
# homing_stepper_phases is also set. Only set this value if one is
|
||||
# sure the stepper motor driver is reset every time the mcu is
|
||||
# reset. If this is not set, but homing_stepper_phases is set, then
|
||||
# the stepper phase will be detected on the first home and that
|
||||
# phase will be used on all subsequent homes.
|
||||
|
||||
# The stepper_y section is used to describe the stepper controlling
|
||||
# the Y axis in a cartesian robot. It has the same settings as the
|
||||
# stepper_x section.
|
||||
[stepper_y]
|
||||
step_pin: ar60
|
||||
dir_pin: !ar61
|
||||
enable_pin: !ar56
|
||||
step_distance: .0225
|
||||
endstop_pin: ^ar14
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
|
||||
# The stepper_z section is used to describe the stepper controlling
|
||||
# the Z axis in a cartesian robot. It has the same settings as the
|
||||
# stepper_x section.
|
||||
[stepper_z]
|
||||
step_pin: ar46
|
||||
dir_pin: ar48
|
||||
enable_pin: !ar62
|
||||
step_distance: .005
|
||||
endstop_pin: ^ar18
|
||||
position_endstop: 0.5
|
||||
position_max: 200
|
||||
|
||||
# The extruder section is used to describe both the stepper
|
||||
# controlling the printer extruder and the heater parameters for the
|
||||
# nozzle. The stepper configuration has the same settings as the
|
||||
# stepper_x section and the heater configuration has the same settings
|
||||
# as the heater_bed section (described below).
|
||||
[extruder]
|
||||
step_pin: ar26
|
||||
dir_pin: ar28
|
||||
enable_pin: !ar24
|
||||
step_distance: .004242
|
||||
nozzle_diameter: 0.500
|
||||
# Diameter of the nozzle orifice (in mm). This parameter must be
|
||||
# provided.
|
||||
filament_diameter: 3.500
|
||||
# Diameter of the raw filament (in mm) as it enters the
|
||||
# extruder. This parameter must be provided.
|
||||
#max_extrude_cross_section:
|
||||
# Maximum area of the cross section of an extrusion line (in
|
||||
# mm^2). This setting prevents excessive amounts of extrusion during
|
||||
# relatively small XY moves. If a move requests an extrusion rate
|
||||
# that would exceed this value it will cause an error to be
|
||||
# returned. The default is: 4.0 * nozzle_diameter^2
|
||||
#max_extrude_only_distance: 50.0
|
||||
# Maximum length (in mm of raw filament) that an extrude only move
|
||||
# may be. If an extrude only move requests a distance greater than
|
||||
# this value it will cause an error to be returned. The default is
|
||||
# 50mm.
|
||||
#max_extrude_only_velocity:
|
||||
# Maximum velocity (in mm/s) of the extruder motor for extrude only
|
||||
# moves. If this is not specified then it is calculated to match the
|
||||
# limit an XY printing move with a max_extrude_cross_section
|
||||
# extrusion would have.
|
||||
#max_extrude_only_accel:
|
||||
# Maximum acceleration (in mm/s^2) of the extruder motor for extrude
|
||||
# only moves. If this is not specified then it is calculated to
|
||||
# match the limit an XY printing move with a
|
||||
# max_extrude_cross_section extrusion would have.
|
||||
#pressure_advance: 0.0
|
||||
# The amount of raw filament to push into the extruder during
|
||||
# extruder acceleration. An equal amount of filament is retracted
|
||||
# during deceleration. It is measured in millimeters per
|
||||
# millimeter/second. The default is 0, which disables pressure
|
||||
# advance.
|
||||
#pressure_advance_lookahead_time: 0.010
|
||||
# A time (in seconds) to "look ahead" at future extrusion moves when
|
||||
# calculating pressure advance. This is used to reduce the
|
||||
# application of pressure advance during cornering moves that would
|
||||
# otherwise cause retraction followed immediately by pressure
|
||||
# buildup. This setting only applies if pressure_advance is
|
||||
# non-zero. The default is 0.010 (10 milliseconds).
|
||||
#
|
||||
# The remaining variables describe the extruder heater.
|
||||
heater_pin: ar10
|
||||
# PWM output pin controlling the heater. This parameter must be
|
||||
# provided.
|
||||
#max_power: 1.0
|
||||
# The maximum power (expressed as a value from 0.0 to 1.0) that the
|
||||
# heater_pin may be set to. The value 1.0 allows the pin to be set
|
||||
# fully enabled for extended periods, while a value of 0.5 would
|
||||
# allow the pin to be enabled for no more than half the time. This
|
||||
# setting may be used to limit the total power output (over extended
|
||||
# periods) to the heater. The default is 1.0.
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
# Type of sensor - this may be "EPCOS 100K B57560G104F", "ATC
|
||||
# Semitec 104GT-2", "NTC 100K beta 3950", or "AD595". This parameter
|
||||
# must be provided.
|
||||
sensor_pin: analog13
|
||||
# Analog input pin connected to the sensor. This parameter must be
|
||||
# provided.
|
||||
#pullup_resistor: 4700
|
||||
# The resistance (in ohms) of the pullup attached to the
|
||||
# thermistor. This parameter is only valid when the sensor is a
|
||||
# thermistor. The default is 4700 ohms.
|
||||
#adc_voltage: 5.0
|
||||
# The ADC comparison voltage. This parameter is only valid when the
|
||||
# sensor is an AD595. The default is 5 volts.
|
||||
control: pid
|
||||
# Control algorithm (either pid or watermark). This parameter must
|
||||
# be provided.
|
||||
pid_Kp: 22.2
|
||||
# Kp is the "proportional" constant for the pid. This parameter must
|
||||
# be provided for PID heaters.
|
||||
pid_Ki: 1.08
|
||||
# Ki is the "integral" constant for the pid. This parameter must be
|
||||
# provided for PID heaters.
|
||||
pid_Kd: 114
|
||||
# Kd is the "derivative" constant for the pid. This parameter must
|
||||
# be provided for PID heaters.
|
||||
#pid_deriv_time: 2.0
|
||||
# A time value (in seconds) over which the derivative in the pid
|
||||
# will be smoothed to reduce the impact of measurement noise. The
|
||||
# default is 2 seconds.
|
||||
#pid_integral_max:
|
||||
# The maximum "windup" the integral term may accumulate. The default
|
||||
# is to use the same value as max_power.
|
||||
#min_extrude_temp: 170
|
||||
# The minimum temperature (in Celsius) at which extruder move
|
||||
# commands may be issued. The default is 170 Celsius.
|
||||
min_temp: 0
|
||||
# Minimum temperature in Celsius (mcu will shutdown if not
|
||||
# met). This parameter must be provided.
|
||||
max_temp: 210
|
||||
# Maximum temperature (mcu will shutdown if temperature is above
|
||||
# this value). This parameter must be provided.
|
||||
|
||||
# The heater_bed section describes a heated bed (if present - omit
|
||||
# section if not present).
|
||||
[heater_bed]
|
||||
heater_pin: ar8
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: analog14
|
||||
control: watermark
|
||||
#max_delta: 2.0
|
||||
# On 'watermark' controlled heaters this is the number of degrees in
|
||||
# Celsius above the target temperature before disabling the heater
|
||||
# as well as the number of degrees below the target before
|
||||
# re-enabling the heater. The default is 2 degrees Celsius.
|
||||
min_temp: 0
|
||||
max_temp: 110
|
||||
|
||||
# Print cooling fan (omit section if fan not present).
|
||||
[fan]
|
||||
pin: ar9
|
||||
# PWM output pin controlling the fan. This parameter must be
|
||||
# provided.
|
||||
#max_power: 1.0
|
||||
# The maximum power (expressed as a value from 0.0 to 1.0) that the
|
||||
# pin may be set to. The value 1.0 allows the pin to be set fully
|
||||
# enabled for extended periods, while a value of 0.5 would allow the
|
||||
# pin to be enabled for no more than half the time. This setting may
|
||||
# be used to limit the total power output (over extended periods) to
|
||||
# the fan. The default is 1.0.
|
||||
#hard_pwm: 0
|
||||
# Set this value to force hardware PWM instead of software PWM. Set
|
||||
# to 1 to force a hardware PWM at the fastest rate; set to a higher
|
||||
# number to force hardware PWM with the given cycle time in clock
|
||||
# ticks. The default is 0 which enables software PWM with a cycle
|
||||
# time of 10ms.
|
||||
#kick_start_time: 0.100
|
||||
# Time (in seconds) to run the fan at full speed when first enabling
|
||||
# it (helps get the fan spinning). The default is 0.100 seconds.
|
||||
|
||||
# Micro-controller information.
|
||||
[mcu]
|
||||
serial: /dev/ttyACM0
|
||||
# The serial port to connect to the MCU. The default is /dev/ttyS0
|
||||
#baud: 250000
|
||||
# The baud rate to use. The default is 250000.
|
||||
pin_map: arduino
|
||||
# This option may be used to enable Arduino pin name aliases. The
|
||||
# default is to not enable the aliases.
|
||||
#restart_method: arduino
|
||||
# This controls the mechanism the host will use to reset the
|
||||
# micro-controller. The choices are 'arduino', 'rpi_usb', and
|
||||
# 'command'. The 'arduino' method (toggle DTR) is common on Arduino
|
||||
# boards and clones. The 'rpi_usb' method is useful on Raspberry Pi
|
||||
# boards with micro-controllers powered over USB - it briefly
|
||||
# disables power to all USB ports to accomplish a micro-controller
|
||||
# reset. The 'command' method involves sending a Klipper command to
|
||||
# the micro-controller so that it can reset itself. The default is
|
||||
# 'arduino'.
|
||||
|
||||
# The printer section controls high level printer settings.
|
||||
[printer]
|
||||
kinematics: cartesian
|
||||
# This option must be "cartesian" for cartesian printers.
|
||||
max_velocity: 500
|
||||
# Maximum velocity (in mm/s) of the toolhead (relative to the
|
||||
# print). This parameter must be specified.
|
||||
max_accel: 3000
|
||||
# Maximum acceleration (in mm/s^2) of the toolhead (relative to the
|
||||
# print). This parameter must be specified.
|
||||
#max_accel_to_decel:
|
||||
# A pseudo acceleration (in mm/s^2) controlling how fast the
|
||||
# toolhead may go from acceleration to deceleration. It is used to
|
||||
# reduce the top speed of short zig-zag moves (and thus reduce
|
||||
# printer vibration from these moves). The default is half of
|
||||
# max_accel.
|
||||
max_z_velocity: 25
|
||||
# For cartesian printers this sets the maximum velocity (in mm/s) of
|
||||
# movement along the z axis. This setting can be used to restrict
|
||||
# the maximum speed of the z stepper motor on cartesian
|
||||
# printers. The default is to use max_velocity for max_z_velocity.
|
||||
max_z_accel: 30
|
||||
# For cartesian printers this sets the maximum acceleration (in
|
||||
# mm/s^2) of movement along the z axis. It limits the acceleration
|
||||
# of the z stepper motor on cartesian printers. The default is to
|
||||
# use max_accel for max_z_accel.
|
||||
#motor_off_time: 600
|
||||
# Time (in seconds) of idle time before the printer will try to
|
||||
# disable active motors. The default is 600 seconds.
|
||||
#junction_deviation: 0.02
|
||||
# Distance (in mm) used to control the internal approximated
|
||||
# centripetal velocity cornering algorithm. A larger number will
|
||||
# permit higher "cornering speeds" at the junction of two moves. The
|
||||
# default is 0.02mm.
|
||||
79
config/generic-cramps.cfg
Normal file
@@ -0,0 +1,79 @@
|
||||
# This file contains an example configuration for a Beaglebone PRU
|
||||
# micro-controller attached to a CRAMPS board.
|
||||
|
||||
# THIS FILE HAS NOT BEEN TESTED - PROCEED WITH CAUTION!
|
||||
|
||||
# NOTE: Klipper does not alter the input/output state of the
|
||||
# Beaglebone pins and it does not control their pull-up resistors. In
|
||||
# order to set the pin state one must use a "device tree overlay" or
|
||||
# use the config-pin program.
|
||||
|
||||
# See the example.cfg file for a description of available parameters.
|
||||
|
||||
[stepper_x]
|
||||
step_pin: P8_13
|
||||
dir_pin: P8_12
|
||||
enable_pin: !P9_14
|
||||
step_distance: .0125
|
||||
endstop_pin: ^P8_8
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
homing_speed: 50
|
||||
|
||||
[stepper_y]
|
||||
step_pin: P8_15
|
||||
dir_pin: P8_14
|
||||
enable_pin: !P9_14
|
||||
step_distance: .0125
|
||||
endstop_pin: ^P8_10
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
homing_speed: 50
|
||||
|
||||
[stepper_z]
|
||||
step_pin: P8_19
|
||||
dir_pin: P8_18
|
||||
enable_pin: !P9_14
|
||||
step_distance: 0.00025
|
||||
endstop_pin: ^P9_13
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
|
||||
[extruder]
|
||||
step_pin: P9_16
|
||||
dir_pin: P9_12
|
||||
enable_pin: !P9_14
|
||||
step_distance: .002
|
||||
nozzle_diameter: 0.400
|
||||
filament_diameter: 1.750
|
||||
heater_pin: P9_15
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: P9_36
|
||||
control: pid
|
||||
pid_Kp: 22.2
|
||||
pid_Ki: 1.08
|
||||
pid_Kd: 114
|
||||
min_temp: 0
|
||||
max_temp: 250
|
||||
|
||||
[heater_bed]
|
||||
heater_pin: P8_11
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: P9_33
|
||||
control: watermark
|
||||
min_temp: 0
|
||||
max_temp: 130
|
||||
|
||||
[fan]
|
||||
pin: P9_41
|
||||
|
||||
[mcu]
|
||||
serial: /dev/rpmsg_pru30
|
||||
pin_map: beaglebone
|
||||
|
||||
[printer]
|
||||
kinematics: cartesian
|
||||
max_velocity: 300
|
||||
max_accel: 3000
|
||||
max_z_velocity: 5
|
||||
max_z_accel: 100
|
||||
76
config/generic-melzi.cfg
Normal file
@@ -0,0 +1,76 @@
|
||||
# This file contains common pin mappings for Melzi v2.0 boards. To use
|
||||
# this config, the firmware should be compiled for the AVR
|
||||
# atmega1284p.
|
||||
|
||||
# Note that the "make flash" command does not work with Melzi
|
||||
# boards. The boards are typically flashed with this command:
|
||||
# avrdude -p atmega1284p -c avrisp -P /dev/ttyUSB0 -U flash:w:out/klipper.elf.hex
|
||||
|
||||
# See the example.cfg file for a description of available parameters.
|
||||
|
||||
[stepper_x]
|
||||
step_pin: PD7
|
||||
dir_pin: PC5
|
||||
enable_pin: !PD6
|
||||
step_distance: .0125
|
||||
endstop_pin: ^!PC2
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
homing_speed: 50
|
||||
|
||||
[stepper_y]
|
||||
step_pin: PC6
|
||||
dir_pin: PC7
|
||||
enable_pin: !PD6
|
||||
step_distance: .0125
|
||||
endstop_pin: ^!PC3
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
homing_speed: 50
|
||||
|
||||
[stepper_z]
|
||||
step_pin: PB3
|
||||
dir_pin: !PB2
|
||||
enable_pin: !PA5
|
||||
step_distance: 0.00025
|
||||
endstop_pin: ^!PC4
|
||||
position_endstop: 0.5
|
||||
position_max: 200
|
||||
|
||||
[extruder]
|
||||
step_pin: PB1
|
||||
dir_pin: PB0
|
||||
enable_pin: !PD6
|
||||
step_distance: .002
|
||||
nozzle_diameter: 0.400
|
||||
filament_diameter: 1.750
|
||||
heater_pin: PD5
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: PA7
|
||||
control: pid
|
||||
pid_Kp: 22.2
|
||||
pid_Ki: 1.08
|
||||
pid_Kd: 114
|
||||
min_temp: 0
|
||||
max_temp: 250
|
||||
|
||||
[heater_bed]
|
||||
heater_pin: PD2
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: PA6
|
||||
control: watermark
|
||||
min_temp: 0
|
||||
max_temp: 130
|
||||
|
||||
[fan]
|
||||
pin: PB4
|
||||
|
||||
[mcu]
|
||||
serial: /dev/ttyUSB0
|
||||
|
||||
[printer]
|
||||
kinematics: cartesian
|
||||
max_velocity: 300
|
||||
max_accel: 3000
|
||||
max_z_velocity: 5
|
||||
max_z_accel: 100
|
||||
109
config/generic-rambo.cfg
Normal file
@@ -0,0 +1,109 @@
|
||||
# This file contains common pin mappings for RAMBo boards. To use this
|
||||
# config, the firmware should be compiled for the AVR atmega2560.
|
||||
|
||||
# See the example.cfg file for a description of available parameters.
|
||||
|
||||
[stepper_x]
|
||||
step_pin: PC0
|
||||
dir_pin: PL1
|
||||
enable_pin: !PA7
|
||||
step_distance: .0125
|
||||
endstop_pin: ^PB6
|
||||
#endstop_pin: ^PA2
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
homing_speed: 50
|
||||
|
||||
[stepper_y]
|
||||
step_pin: PC1
|
||||
dir_pin: !PL0
|
||||
enable_pin: !PA6
|
||||
step_distance: .0125
|
||||
endstop_pin: ^PB5
|
||||
#endstop_pin: ^PA1
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
homing_speed: 50
|
||||
|
||||
[stepper_z]
|
||||
step_pin: PC2
|
||||
dir_pin: PL2
|
||||
enable_pin: !PA5
|
||||
step_distance: 0.00025
|
||||
endstop_pin: ^PB4
|
||||
#endstop_pin: ^PC7
|
||||
position_endstop: 0.5
|
||||
position_max: 200
|
||||
|
||||
[extruder]
|
||||
step_pin: PC3
|
||||
dir_pin: PL6
|
||||
enable_pin: !PA4
|
||||
step_distance: .002
|
||||
nozzle_diameter: 0.400
|
||||
filament_diameter: 1.750
|
||||
heater_pin: PH6
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: PF0
|
||||
control: pid
|
||||
pid_Kp: 22.2
|
||||
pid_Ki: 1.08
|
||||
pid_Kd: 114
|
||||
min_temp: 0
|
||||
max_temp: 250
|
||||
|
||||
#[extruder1]
|
||||
#step_pin: PC4
|
||||
#dir_pin: PL7
|
||||
#enable_pin: !PA3
|
||||
#heater_pin: PH4
|
||||
#sensor_pin: PF1
|
||||
#...
|
||||
|
||||
[heater_bed]
|
||||
heater_pin: PE5
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: PF2
|
||||
control: watermark
|
||||
min_temp: 0
|
||||
max_temp: 130
|
||||
|
||||
[fan]
|
||||
pin: PH5
|
||||
|
||||
#[heater_fan nozzle_cooling_fan]
|
||||
#pin: PH3
|
||||
|
||||
[mcu]
|
||||
serial: /dev/ttyACM0
|
||||
|
||||
[printer]
|
||||
kinematics: cartesian
|
||||
max_velocity: 300
|
||||
max_accel: 3000
|
||||
max_z_velocity: 5
|
||||
max_z_accel: 100
|
||||
|
||||
[ad5206 stepper_digipot]
|
||||
enable_pin: PD7
|
||||
# Scale the config so that the channel value can be specified in amps.
|
||||
# (For Rambo v1.0d boards, use 1.56 instead.)
|
||||
scale: 2.08
|
||||
# Channel 1 is E0, 2 is E1, 3 is unused, 4 is Z, 5 is X, 6 is Y
|
||||
channel_1: 1.34
|
||||
channel_2: 1.0
|
||||
channel_4: 1.1
|
||||
channel_5: 1.1
|
||||
channel_6: 1.1
|
||||
|
||||
# Enable 16 micro-steps on steppers X, Y, Z, E0, E1
|
||||
[static_digital_output stepper_config]
|
||||
pins:
|
||||
PG1, PG0,
|
||||
PK7, PG2,
|
||||
PK6, PK5,
|
||||
PK3, PK4,
|
||||
PK2, PK1
|
||||
|
||||
[static_digital_output yellow_led]
|
||||
pins: !PB7
|
||||
84
config/generic-ramps.cfg
Normal file
@@ -0,0 +1,84 @@
|
||||
# This file contains common pin mappings for RAMPS (v1.3 and later)
|
||||
# boards. RAMPS boards typically use a firmware compiled for the AVR
|
||||
# atmega2560 (though other AVR chips are also possible).
|
||||
|
||||
# See the example.cfg file for a description of available parameters.
|
||||
|
||||
[stepper_x]
|
||||
step_pin: ar54
|
||||
dir_pin: ar55
|
||||
enable_pin: !ar38
|
||||
step_distance: .0125
|
||||
endstop_pin: ^ar3
|
||||
#endstop_pin: ^ar2
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
homing_speed: 50
|
||||
|
||||
[stepper_y]
|
||||
step_pin: ar60
|
||||
dir_pin: !ar61
|
||||
enable_pin: !ar56
|
||||
step_distance: .0125
|
||||
endstop_pin: ^ar14
|
||||
#endstop_pin: ^ar15
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
homing_speed: 50
|
||||
|
||||
[stepper_z]
|
||||
step_pin: ar46
|
||||
dir_pin: ar48
|
||||
enable_pin: !ar62
|
||||
step_distance: 0.00025
|
||||
endstop_pin: ^ar18
|
||||
#endstop_pin: ^ar19
|
||||
position_endstop: 0.5
|
||||
position_max: 200
|
||||
|
||||
[extruder]
|
||||
step_pin: ar26
|
||||
dir_pin: ar28
|
||||
enable_pin: !ar24
|
||||
step_distance: .002
|
||||
nozzle_diameter: 0.400
|
||||
filament_diameter: 1.750
|
||||
heater_pin: ar10
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: analog13
|
||||
control: pid
|
||||
pid_Kp: 22.2
|
||||
pid_Ki: 1.08
|
||||
pid_Kd: 114
|
||||
min_temp: 0
|
||||
max_temp: 250
|
||||
|
||||
#[extruder1]
|
||||
#step_pin: ar36
|
||||
#dir_pin: ar34
|
||||
#enable_pin: !ar30
|
||||
#heater_pin: ar9
|
||||
#sensor_pin: analog15
|
||||
#...
|
||||
|
||||
[heater_bed]
|
||||
heater_pin: ar8
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: analog14
|
||||
control: watermark
|
||||
min_temp: 0
|
||||
max_temp: 130
|
||||
|
||||
[fan]
|
||||
pin: ar9
|
||||
|
||||
[mcu]
|
||||
serial: /dev/ttyACM0
|
||||
pin_map: arduino
|
||||
|
||||
[printer]
|
||||
kinematics: cartesian
|
||||
max_velocity: 300
|
||||
max_accel: 3000
|
||||
max_z_velocity: 5
|
||||
max_z_accel: 100
|
||||
124
config/generic-replicape.cfg
Normal file
@@ -0,0 +1,124 @@
|
||||
# This file contains an example configuration for the Replicape rev B3
|
||||
# board. To use this config, one must compile and install the
|
||||
# micro-controller code for the "Beaglebone PRU", and then compile and
|
||||
# install the micro-controller code a second time for a "Linux
|
||||
# process".
|
||||
|
||||
# NOTE: Klipper does not alter the input/output state of the
|
||||
# Beaglebone pins and it does not control their pull-up resistors.
|
||||
# Typically the correct settings are automatically applied when the
|
||||
# Beaglebone detects the Replicape board, but if changes are needed
|
||||
# they must be specified in a "device tree overlay" or via the
|
||||
# config-pin program.
|
||||
|
||||
# See the example.cfg file for a description of available parameters.
|
||||
|
||||
[stepper_x]
|
||||
step_pin: P8_17
|
||||
dir_pin: P8_26
|
||||
enable_pin: replicape:stepper_x_enable
|
||||
step_distance: .0125
|
||||
endstop_pin: ^P9_25
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
homing_speed: 50
|
||||
|
||||
[stepper_y]
|
||||
step_pin: P8_12
|
||||
dir_pin: P8_19
|
||||
enable_pin: replicape:stepper_y_enable
|
||||
step_distance: .0125
|
||||
endstop_pin: ^P9_23
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
homing_speed: 50
|
||||
|
||||
[stepper_z]
|
||||
step_pin: P8_13
|
||||
dir_pin: P8_14
|
||||
enable_pin: replicape:stepper_z_enable
|
||||
step_distance: 0.00025
|
||||
endstop_pin: ^P9_13
|
||||
position_endstop: 0
|
||||
position_max: 200
|
||||
|
||||
[extruder]
|
||||
step_pin: P9_12
|
||||
dir_pin: P8_15
|
||||
enable_pin: replicape:stepper_e_enable
|
||||
step_distance: .002
|
||||
nozzle_diameter: 0.400
|
||||
filament_diameter: 1.750
|
||||
heater_pin: replicape:power_e
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: host:analog4
|
||||
control: pid
|
||||
pid_Kp: 22.2
|
||||
pid_Ki: 1.08
|
||||
pid_Kd: 114
|
||||
min_temp: 0
|
||||
max_temp: 250
|
||||
|
||||
[heater_bed]
|
||||
heater_pin: replicape:power_hotbed
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: host:analog6
|
||||
control: watermark
|
||||
min_temp: 0
|
||||
max_temp: 130
|
||||
|
||||
[fan]
|
||||
pin: replicape:power_fan0
|
||||
|
||||
[mcu]
|
||||
serial: /dev/rpmsg_pru30
|
||||
pin_map: beaglebone
|
||||
|
||||
[printer]
|
||||
kinematics: cartesian
|
||||
max_velocity: 300
|
||||
max_accel: 3000
|
||||
max_z_velocity: 25
|
||||
max_z_accel: 30
|
||||
|
||||
[mcu host]
|
||||
serial: /tmp/klipper_host_mcu
|
||||
|
||||
# The "replicape" config section adds "replicape:stepper_x_enable"
|
||||
# virtual stepper enable pins (for steppers x, y, z, e, and h) and
|
||||
# "replicape:power_x" PWM output pins (for hotbed, e, h, fan0, fan1,
|
||||
# fan2, and fan3) that may then be used elsewhere in the config file.
|
||||
[replicape]
|
||||
revision: B3
|
||||
# The replicape hardware revision. Currently only revision "B3" is
|
||||
# supported. This parameter must be provided.
|
||||
#enable_pin: !P9_41
|
||||
# The replicape global enable pin. The default is !P9_41.
|
||||
host_mcu: host
|
||||
# The name of the mcu config section that communicates with the
|
||||
# Klipper "linux process" mcu instance. This parameter must be
|
||||
# provided.
|
||||
stepper_x_microstep_mode: spread16
|
||||
# This parameter controls the CFG1 and CFG2 pins of the given
|
||||
# stepper motor driver. Available options are: disable, 1, 2,
|
||||
# spread2, 4, 16, spread4, spread16, stealth4, and stealth16. The
|
||||
# default is disable.
|
||||
stepper_x_current: 0.5
|
||||
# The configured maximum current (in Amps) of the stepper motor
|
||||
# driver. This parameter must be provided if the stepper is not in a
|
||||
# disable mode.
|
||||
#stepper_x_chopper_off_time_high: False
|
||||
# This parameter controls the CFG0 pin of the stepper motor driver
|
||||
# (True sets CFG0 high, False sets it low). The default is False.
|
||||
#stepper_x_chopper_hysteresis_high: False
|
||||
# This parameter controls the CFG4 pin of the stepper motor driver
|
||||
# (True sets CFG4 high, False sets it low). The default is False.
|
||||
#stepper_x_chopper_blank_time_high: True
|
||||
# This parameter controls the CFG5 pin of the stepper motor driver
|
||||
# (True sets CFG5 high, False sets it low). The default is True.
|
||||
stepper_y_microstep_mode: spread16
|
||||
stepper_y_current: 0.5
|
||||
stepper_z_microstep_mode: spread16
|
||||
stepper_z_current: 0.5
|
||||
stepper_e_microstep_mode: 16
|
||||
stepper_e_current: 0.5
|
||||
107
config/makergear-m2-2012.cfg
Normal file
@@ -0,0 +1,107 @@
|
||||
# Support for Makergear M2 printers circa 2012 that have the RAMBo
|
||||
# v1.0d electronics along with the V3A extruder. The electronics use
|
||||
# Allegro A4984 stepper drivers with 1/8th micro-stepping. To use
|
||||
# this config, the firmware should be compiled for the AVR atmega2560.
|
||||
|
||||
[stepper_x]
|
||||
step_pin: PC0
|
||||
dir_pin: !PL1
|
||||
enable_pin: !PA7
|
||||
step_distance: .0225
|
||||
endstop_pin: ^!PB6
|
||||
position_endstop: 0.0
|
||||
position_max: 200
|
||||
homing_speed: 50
|
||||
homing_stepper_phases: 32
|
||||
homing_endstop_accuracy: .200
|
||||
|
||||
[stepper_y]
|
||||
step_pin: PC1
|
||||
dir_pin: PL0
|
||||
enable_pin: !PA6
|
||||
step_distance: .0225
|
||||
endstop_pin: ^!PB5
|
||||
position_endstop: 0.0
|
||||
position_max: 250
|
||||
homing_speed: 50
|
||||
homing_stepper_phases: 32
|
||||
homing_endstop_accuracy: .200
|
||||
|
||||
[stepper_z]
|
||||
step_pin: PC2
|
||||
dir_pin: !PL2
|
||||
enable_pin: !PA5
|
||||
step_distance: .005
|
||||
endstop_pin: ^!PB4
|
||||
position_min: 0.1
|
||||
position_endstop: 0.7
|
||||
position_max: 200
|
||||
homing_retract_dist: 2.0
|
||||
homing_stepper_phases: 32
|
||||
homing_endstop_accuracy: .070
|
||||
|
||||
[extruder]
|
||||
step_pin: PC3
|
||||
dir_pin: PL6
|
||||
enable_pin: !PA4
|
||||
step_distance: .004242
|
||||
nozzle_diameter: 0.350
|
||||
filament_diameter: 1.750
|
||||
pressure_advance: 0.07
|
||||
heater_pin: PH6
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: PF0
|
||||
control: pid
|
||||
pid_Kp: 7.0
|
||||
pid_Ki: 0.1
|
||||
pid_Kd: 12
|
||||
min_temp: 0
|
||||
max_temp: 210
|
||||
|
||||
[heater_bed]
|
||||
heater_pin: PE5
|
||||
sensor_type: EPCOS 100K B57560G104F
|
||||
sensor_pin: PF2
|
||||
control: watermark
|
||||
min_temp: 0
|
||||
max_temp: 100
|
||||
|
||||
[fan]
|
||||
pin: PH5
|
||||
|
||||
[heater_fan nozzle_fan]
|
||||
pin: PH3
|
||||
max_power: 0.61
|
||||
hard_pwm: 1
|
||||
|
||||
[mcu]
|
||||
serial: /dev/ttyACM0
|
||||
|
||||
[printer]
|
||||
kinematics: cartesian
|
||||
max_velocity: 500
|
||||
max_accel: 3000
|
||||
max_z_velocity: 25
|
||||
max_z_accel: 30
|
||||
|
||||
[ad5206 stepper_digipot]
|
||||
enable_pin: PD7
|
||||
# Scale the config so that the channel value can be specified in amps
|
||||
scale: 1.56
|
||||
# Channel 1 is E0, 2 is E1, 3 is unused, 4 is Z, 5 is X, 6 is Y
|
||||
channel_1: 1.0
|
||||
channel_2: 0.75
|
||||
channel_4: 0.82
|
||||
channel_5: 0.82
|
||||
channel_6: 0.82
|
||||
|
||||
# Enable 8 micro-steps on steppers X, Y, Z, E0
|
||||
[static_digital_output stepper_config]
|
||||
pins:
|
||||
PG1, PG0,
|
||||
PK7, PG2,
|
||||
PK6, PK5,
|
||||
PK3, PK4
|
||||
|
||||
[static_digital_output yellow_led]
|
||||
pins: !PB7
|
||||
277
docs/Code_Overview.md
Normal file
@@ -0,0 +1,277 @@
|
||||
This document describes the overall code layout and major code flow of
|
||||
Klipper.
|
||||
|
||||
Directory Layout
|
||||
================
|
||||
|
||||
The **src/** directory contains the C source for the micro-controller
|
||||
code. The **src/avr/** directory contains specific code for Atmel
|
||||
ATmega micro-controllers. The **src/sam3x8e/** directory contains code
|
||||
specific to the Arduino Due style ARM micro-controllers. The
|
||||
**src/pru/** directory contains code specific to the Beaglebone's
|
||||
on-board PRU micro-controller. The **src/simulator/** contains code
|
||||
stubs that allow the micro-controller to be test compiled on other
|
||||
architectures. The **src/generic/** directory contains helper code
|
||||
that may be useful across different host architectures. The build
|
||||
arranges for includes of "board/somefile.h" to first look in the
|
||||
current architecture directory (eg, src/avr/somefile.h) and then in
|
||||
the generic directory (eg, src/generic/somefile.h).
|
||||
|
||||
The **klippy/** directory contains the C and Python source for the
|
||||
host part of the software.
|
||||
|
||||
The **lib/** directory contains external 3rd-party library code that
|
||||
is necessary to build some targets.
|
||||
|
||||
The **config/** directory contains example printer configuration
|
||||
files.
|
||||
|
||||
The **scripts/** directory contains build-time scripts useful for
|
||||
compiling the micro-controller code.
|
||||
|
||||
During compilation, the build may create an **out/** directory. This
|
||||
contains temporary build time objects. The final micro-controller
|
||||
object that is built is **out/klipper.elf.hex** on AVR and
|
||||
**out/klipper.bin** on ARM.
|
||||
|
||||
Micro-controller code flow
|
||||
==========================
|
||||
|
||||
Execution of the micro-controller code starts in architecture specific
|
||||
code (eg, **src/avr/main.c**) which ultimately calls sched_main()
|
||||
located in **src/sched.c**. The sched_main() code starts by running
|
||||
all functions that have been tagged with the DECL_INIT() macro. It
|
||||
then goes on to repeatedly run all functions tagged with the
|
||||
DECL_TASK() macro.
|
||||
|
||||
One of the main task functions is command_dispatch() located in
|
||||
**src/command.c**. This function is called from the board specific
|
||||
input/output code (eg, **src/avr/serial.c**) and it runs the command
|
||||
functions associated with the commands found in the input
|
||||
stream. Command functions are declared using the DECL_COMMAND() macro
|
||||
(see the [protocol](Protocol.md) document for more information).
|
||||
|
||||
Task, init, and command functions always run with interrupts enabled
|
||||
(however, they can temporarily disable interrupts if needed). These
|
||||
functions should never pause, delay, or do any work that lasts more
|
||||
than a few micro-seconds. These functions schedule work at specific
|
||||
times by scheduling timers.
|
||||
|
||||
Timer functions are scheduled by calling sched_add_timer() (located in
|
||||
**src/sched.c**). The scheduler code will arrange for the given
|
||||
function to be called at the requested clock time. Timer interrupts
|
||||
are initially handled in an architecture specific interrupt handler
|
||||
(eg, **src/avr/timer.c**) which calls sched_timer_dispatch() located
|
||||
in **src/sched.c**. The timer interrupt leads to execution of schedule
|
||||
timer functions. Timer functions always run with interrupts
|
||||
disabled. The timer functions should always complete within a few
|
||||
micro-seconds. At completion of the timer event, the function may
|
||||
choose to reschedule itself.
|
||||
|
||||
In the event an error is detected the code can invoke shutdown() (a
|
||||
macro which calls sched_shutdown() located in **src/sched.c**).
|
||||
Invoking shutdown() causes all functions tagged with the
|
||||
DECL_SHUTDOWN() macro to be run. Shutdown functions always run with
|
||||
interrupts disabled.
|
||||
|
||||
Much of the functionality of the micro-controller involves working
|
||||
with General-Purpose Input/Output pins (GPIO). In order to abstract
|
||||
the low-level architecture specific code from the high-level task
|
||||
code, all GPIO events are implemented in architectures specific
|
||||
wrappers (eg, **src/avr/gpio.c**). The code is compiled with gcc's
|
||||
"-flto -fwhole-program" optimization which does an excellent job of
|
||||
inlining functions across compilation units, so most of these tiny
|
||||
gpio functions are inlined into their callers, and there is no
|
||||
run-time cost to using them.
|
||||
|
||||
Klippy code overview
|
||||
====================
|
||||
|
||||
The host code (Klippy) is intended to run on a low-cost computer (such
|
||||
as a Raspberry Pi) paired with the micro-controller. The code is
|
||||
primarily written in Python, however it does use CFFI to implement
|
||||
some functionality in C code.
|
||||
|
||||
Initial execution starts in **klippy/klippy.py**. This reads the
|
||||
command-line arguments, opens the printer config file, instantiates
|
||||
the main printer objects, and starts the serial connection. The main
|
||||
execution of G-code commands is in the process_commands() method in
|
||||
**klippy/gcode.py**. This code translates the G-code commands into
|
||||
printer object calls, which frequently translate the actions to
|
||||
commands to be executed on the micro-controller (as declared via the
|
||||
DECL_COMMAND macro in the micro-controller code).
|
||||
|
||||
There are four threads in the Klippy host code. The main thread
|
||||
handles incoming gcode commands. A second thread (which resides
|
||||
entirely in the **klippy/serialqueue.c** C code) handles low-level IO
|
||||
with the serial port. The third thread is used to process response
|
||||
messages from the micro-controller in the Python code (see
|
||||
**klippy/serialhdl.py**). The fourth thread writes debug messages to
|
||||
the log (see **klippy/queuelogger.py**) so that the other threads
|
||||
never block on log writes.
|
||||
|
||||
Code flow of a move command
|
||||
===========================
|
||||
|
||||
A typical printer movement starts when a "G1" command is sent to the
|
||||
Klippy host and it completes when the corresponding step pulses are
|
||||
produced on the micro-controller. This section outlines the code flow
|
||||
of a typical move command. The [kinematics](Kinematics.md) document
|
||||
provides further information on the mechanics of moves.
|
||||
|
||||
* Processing for a move command starts in gcode.py. The goal of
|
||||
gcode.py is to translate G-code into internal calls. Changes in
|
||||
origin (eg, G92), changes in relative vs absolute positions (eg,
|
||||
G90), and unit changes (eg, F6000=100mm/s) are handled here. The
|
||||
code path for a move is: `process_data() -> process_commands() ->
|
||||
cmd_G1()`. Ultimately the ToolHead class is invoked to execute the
|
||||
actual request: `cmd_G1() -> ToolHead.move()`
|
||||
|
||||
* The ToolHead class (in toolhead.py) handles "look-ahead" and tracks
|
||||
the timing of printing actions. The codepath for a move is:
|
||||
`ToolHead.move() -> MoveQueue.add_move() -> MoveQueue.flush() ->
|
||||
Move.set_junction() -> Move.move()`.
|
||||
* ToolHead.move() creates a Move() object with the parameters of the
|
||||
move (in cartesian space and in units of seconds and millimeters).
|
||||
* MoveQueue.add_move() places the move object on the "look-ahead"
|
||||
queue.
|
||||
* MoveQueue.flush() determines the start and end velocities of each
|
||||
move.
|
||||
* Move.set_junction() implements the "trapezoid generator" on a
|
||||
move. The "trapezoid generator" breaks every move into three parts:
|
||||
a constant acceleration phase, followed by a constant velocity
|
||||
phase, followed by a constant deceleration phase. Every move
|
||||
contains these three phases in this order, but some phases may be of
|
||||
zero duration.
|
||||
* When Move.move() is called, everything about the move is known -
|
||||
its start location, its end location, its acceleration, its
|
||||
start/crusing/end velocity, and distance traveled during
|
||||
acceleration/cruising/deceleration. All the information is stored in
|
||||
the Move() class and is in cartesian space in units of millimeters
|
||||
and seconds.
|
||||
|
||||
The move is then handed off to the kinematics classes: `Move.move()
|
||||
-> kin.move()`
|
||||
|
||||
* The goal of the kinematics classes is to translate the movement in
|
||||
cartesian space to movement on each stepper. The kinematics classes
|
||||
are in cartesian.py, corexy.py, delta.py, and extruder.py. The
|
||||
kinematic class is given a chance to audit the move
|
||||
(`ToolHead.move() -> kin.check_move()`) before it goes on the
|
||||
look-ahead queue, but once the move arrives in *kin*.move() the
|
||||
kinematic class is required to handle the move as specified. The
|
||||
kinematic classes translate the three parts of each move
|
||||
(acceleration, constant "cruising" velocity, and deceleration) to
|
||||
the associated movement on each stepper. Note that the extruder is
|
||||
handled in its own kinematic class. Since the Move() class specifies
|
||||
the exact movement time and since step pulses are sent to the
|
||||
micro-controller with specific timing, stepper movements produced by
|
||||
the extruder class will be in sync with head movement even though
|
||||
the code is kept separate.
|
||||
|
||||
* For efficiency reasons, the stepper pulse times are generated in C
|
||||
code. The code flow is: `kin.move() -> MCU_Stepper.step_const() ->
|
||||
stepcompress_push_const()`, or for delta kinematics:
|
||||
`DeltaKinematics.move() -> MCU_Stepper.step_delta() ->
|
||||
stepcompress_push_delta()`. The MCU_Stepper code just performs unit
|
||||
and axis transformation (millimeters to step distances), and calls
|
||||
the C code. The C code calculates the stepper step times for each
|
||||
movement and fills an array (struct stepcompress.queue) with the
|
||||
corresponding micro-controller clock counter times for every
|
||||
step. Here the "micro-controller clock counter" value directly
|
||||
corresponds to the micro-controller's hardware counter - it is
|
||||
relative to when the micro-controller was last powered up.
|
||||
|
||||
* The next major step is to compress the steps: `stepcompress_flush()
|
||||
-> compress_bisect_add()` (in stepcompress.c). This code generates
|
||||
and encodes a series of micro-controller "queue_step" commands that
|
||||
correspond to the list of stepper step times built in the previous
|
||||
stage. These "queue_step" commands are then queued, prioritized, and
|
||||
sent to the micro-controller (via stepcompress.c:steppersync and
|
||||
serialqueue.c:serialqueue).
|
||||
|
||||
* Processing of the queue_step commands on the micro-controller starts
|
||||
in command.c which parses the command and calls
|
||||
`command_queue_step()`. The command_queue_step() code (in stepper.c)
|
||||
just appends the parameters of each queue_step command to a per
|
||||
stepper queue. Under normal operation the queue_step command is
|
||||
parsed and queued at least 100ms before the time of its first
|
||||
step. Finally, the generation of stepper events is done in
|
||||
`stepper_event()`. It's called from the hardware timer interrupt at
|
||||
the scheduled time of the first step. The stepper_event() code
|
||||
generates a step pulse and then reschedules itself to run at the
|
||||
time of the next step pulse for the given queue_step parameters. The
|
||||
parameters for each queue_step command are "interval", "count", and
|
||||
"add". At a high-level, stepper_event() runs the following, 'count'
|
||||
times: `do_step(); next_wake_time = last_wake_time + interval;
|
||||
interval += add;`
|
||||
|
||||
The above may seem like a lot of complexity to execute a
|
||||
movement. However, the only really interesting parts are in the
|
||||
ToolHead and kinematic classes. It's this part of the code which
|
||||
specifies the movements and their timings. The remaining parts of the
|
||||
processing is mostly just communication and plumbing.
|
||||
|
||||
Time
|
||||
====
|
||||
|
||||
Fundamental to the operation of Klipper is the handling of clocks,
|
||||
times, and timestamps. Klipper executes actions on the printer by
|
||||
scheduling events to occur in the near future. For example, to turn on
|
||||
a fan, the code might schedule a change to a GPIO pin in a 100ms. It
|
||||
is rare for the code to attempt to take an instantaneous action. Thus,
|
||||
the handling of time within Klipper is critical to correct operation.
|
||||
|
||||
There are three types of times tracked internally in the Klipper host
|
||||
software:
|
||||
* System time. The system time uses the system's monotonic clock - it
|
||||
is a floating point number stored as seconds and it is (generally)
|
||||
relative to when the host computer was last started. System times
|
||||
have limited use in the software - they are primarily used when
|
||||
interacting with the operating system. Within the host code, system
|
||||
times are frequently stored in variables named *eventtime* or
|
||||
*curtime*.
|
||||
* Print time. The print time is synchronized to the main
|
||||
micro-controller clock (the micro-controller defined in the "[mcu]"
|
||||
config section). It is a floating point number stored as seconds and
|
||||
is relative to when the main mcu was last restarted. It is possible
|
||||
to convert from a "print time" to the main micro-controller's
|
||||
hardware clock by multiplying the print time by the mcu's statically
|
||||
configured frequency rate. The high-level host code uses print times
|
||||
to calculates almost all physical actions (eg, head movement, heater
|
||||
changes, etc.). Within the host code, print times are generally
|
||||
stored in variables named *print_time* or *move_time*.
|
||||
* MCU clock. This is the hardware clock counter on each
|
||||
micro-controller. It is stored as an integer and its update rate is
|
||||
relative to the frequency of the given micro-controller. The host
|
||||
software translates its internal times to clocks before transmission
|
||||
to the mcu. The mcu code only ever tracks time in clock
|
||||
ticks. Within the host code, clock values are tracked as 64bit
|
||||
integers, while the mcu code uses 32bit integers. Within the host
|
||||
code, clocks are generally stored in variables with names containing
|
||||
*clock* or *ticks*.
|
||||
|
||||
Conversion between the different time formats is primarily implemented
|
||||
in the **klippy/clocksync.py** code.
|
||||
|
||||
Some things to be aware of when reviewing the code:
|
||||
* 32bit and 64bit clocks: To reduce bandwidth and to improve
|
||||
micro-controller efficiency, clocks on the micro-controller are
|
||||
tracked as 32bit integers. When comparing two clocks in the mcu
|
||||
code, the `timer_is_before()` function must always be used to ensure
|
||||
integer rollovers are handled properly. The host software converts
|
||||
32bit clocks to 64bit clocks by appending the high-order bits from
|
||||
the last mcu timestamp it has received - no message from the mcu is
|
||||
ever more than 2^31 clock ticks in the future or past so this
|
||||
conversion is never ambiguous. The host converts from 64bit clocks
|
||||
to 32bit clocks by simply truncating the high-order bits. To ensure
|
||||
there is no ambiguity in this conversion, the
|
||||
**klippy/serialqueue.c** code will buffer messages until they are
|
||||
within 2^31 clock ticks of their target time.
|
||||
* Multiple micro-controllers: The host software supports using
|
||||
multiple micro-controllers on a single printer. In this case, the
|
||||
"MCU clock" of each micro-controller is tracked separately. The
|
||||
clocksync.py code handles clock drift between micro-controllers by
|
||||
modifying the way it converts from "print time" to "MCU clock". On
|
||||
secondary mcus, the mcu frequency that is used in this conversion is
|
||||
regularly updated to account for measured drift.
|
||||
47
docs/Contact.md
Normal file
@@ -0,0 +1,47 @@
|
||||
This page provides information on how to contact the Klipper
|
||||
developers.
|
||||
|
||||
Bug reporting
|
||||
=============
|
||||
|
||||
Bug reports are submitted through github issues. All bug reports must
|
||||
include the full /tmp/klippy.log log file from the session that
|
||||
produced the error. To acquire this log file, ssh into the computer
|
||||
running the klipper host software, and run:
|
||||
|
||||
```
|
||||
gzip -k /tmp/klippy.log
|
||||
```
|
||||
|
||||
Then scp the resulting `/tmp/klippy.log.gz` file from the host machine
|
||||
to your desktop. (If your desktop does not have scp installed, there
|
||||
are a number of free scp programs available - just do a web search for
|
||||
`windows scp` to find one.) Open a new issue at
|
||||
https://github.com/KevinOConnor/klipper/issues , attach the
|
||||
`klippy.log.gz` file to that issue, and provide a description of the
|
||||
problem.
|
||||
|
||||
Mailing list
|
||||
============
|
||||
|
||||
There is a mailing list for general discussions on Klipper. In order
|
||||
to send am email to the list, one must first subscribe:
|
||||
https://www.freelists.org/list/klipper . Once subscribed, emails may
|
||||
be sent to `klipper@freelists.org`.
|
||||
|
||||
Archives of the mailing list are available at:
|
||||
https://www.freelists.org/archive/klipper/
|
||||
|
||||
IRC
|
||||
===
|
||||
|
||||
One may join the #klipper channel on freenode.net (
|
||||
irc://chat.freenode.net:6667 ).
|
||||
|
||||
To communicate in this IRC channel one will need an IRC
|
||||
client. Configure it to connect to chat.freenode.net on port 6667 and
|
||||
join the #klipper channel (`/join #klipper`).
|
||||
|
||||
If asking a question on IRC, be sure to ask the question and then stay
|
||||
connected to the channel to receive responses. Due to timezone
|
||||
differences, it may take several hours before receiving a response.
|
||||
150
docs/Debugging.md
Normal file
@@ -0,0 +1,150 @@
|
||||
The Klippy host code has some tools to help in debugging.
|
||||
|
||||
Translating gcode files to micro-controller commands
|
||||
====================================================
|
||||
|
||||
The Klippy host code can run in a batch mode to produce the low-level
|
||||
micro-controller commands associated with a gcode file. Inspecting
|
||||
these low-level commands is useful when trying to understand the
|
||||
actions of the low-level hardware. It can also be useful to compare
|
||||
the difference in micro-controller commands after a code change.
|
||||
|
||||
To run Klippy in this batch mode, there is a one time step necessary
|
||||
to generate the micro-controller "data dictionary". This is done by
|
||||
compiling the micro-controller code to obtain the **out/klipper.dict**
|
||||
file:
|
||||
|
||||
```
|
||||
make menuconfig
|
||||
make
|
||||
```
|
||||
|
||||
Once the above is done it is possible to run Klipper in batch mode
|
||||
(see [installation](Installation.md) for the steps necessary to build
|
||||
the python virtual environment and a printer.cfg file):
|
||||
|
||||
```
|
||||
~/klippy-env/bin/python ./klippy/klippy.py ~/printer.cfg -i test.gcode -o test.serial -v -d out/klipper.dict
|
||||
```
|
||||
|
||||
The above will produce a file **test.serial** with the binary serial
|
||||
output. This output can be translated to readable text with:
|
||||
|
||||
```
|
||||
~/klippy-env/bin/python ./klippy/parsedump.py out/klipper.dict test.serial > test.txt
|
||||
```
|
||||
|
||||
The resulting file **test.txt** contains a human readable list of
|
||||
micro-controller commands.
|
||||
|
||||
The batch mode disables certain response / request commands in order
|
||||
to function. As a result, there will be some differences between
|
||||
actual commands and the above output. The generated data is useful for
|
||||
testing and inspection; it is not useful for sending to a real
|
||||
micro-controller.
|
||||
|
||||
Testing with simulavr
|
||||
=====================
|
||||
|
||||
The [simulavr](http://www.nongnu.org/simulavr/) tool enables one to
|
||||
simulate an Atmel ATmega micro-controller. This section describes how
|
||||
one can run test gcode files through simulavr. It is recommended to
|
||||
run this on a desktop class machine (not a Raspberry Pi) as it does
|
||||
require significant cpu to run efficiently.
|
||||
|
||||
To use simulavr, download the simulavr package and compile with python
|
||||
support:
|
||||
|
||||
```
|
||||
git clone git://git.savannah.nongnu.org/simulavr.git
|
||||
cd simulavr
|
||||
./bootstrap
|
||||
./configure --enable-python
|
||||
make
|
||||
```
|
||||
|
||||
Note that the build system may need to have some packages (such as
|
||||
swig) installed in order to build the python module. Make sure the
|
||||
file **src/python/_pysimulavr.so** is present after the above
|
||||
compilation.
|
||||
|
||||
To compile Klipper for use in simulavr, run:
|
||||
|
||||
```
|
||||
cd /patch/to/klipper
|
||||
make menuconfig
|
||||
```
|
||||
|
||||
and compile the micro-controller software for an AVR atmega644p, set
|
||||
the MCU frequency to 20Mhz, and select SIMULAVR software emulation
|
||||
support. Then one can compile Klipper (run `make`) and then start the
|
||||
simulation with:
|
||||
|
||||
```
|
||||
PYTHONPATH=/path/to/simulavr/src/python/ ./scripts/avrsim.py -m atmega644 -s 20000000 -b 250000 out/klipper.elf
|
||||
```
|
||||
|
||||
Then, with simulavr running in another window, one can run the
|
||||
following to read gcode from a file (eg, "test.gcode"), process it
|
||||
with Klippy, and send it to Klipper running in simulavr (see
|
||||
[installation](Installation.md) for the steps necessary to build the
|
||||
python virtual environment):
|
||||
|
||||
```
|
||||
~/klippy-env/bin/python ./klippy/klippy.py config/avrsim.cfg -i test.gcode -v
|
||||
```
|
||||
|
||||
Using simulavr with gtkwave
|
||||
---------------------------
|
||||
|
||||
One useful feature of simulavr is its ability to create signal wave
|
||||
generation files with the exact timing of events. To do this, follow
|
||||
the directions above, but run avrsim.py with a command-line like the
|
||||
following:
|
||||
|
||||
```
|
||||
PYTHONPATH=/path/to/simulavr/src/python/ ./scripts/avrsim.py -m atmega644 -s 20000000 -b 250000 out/klipper.elf -t PORTA.PORT,PORTC.PORT
|
||||
```
|
||||
|
||||
The above would create a file **avrsim.vcd** with information on each
|
||||
change to the GPIOs on PORTA and PORTB. This could then be viewed
|
||||
using gtkwave with:
|
||||
|
||||
```
|
||||
gtkwave avrsim.vcd
|
||||
```
|
||||
|
||||
Manually sending commands to the micro-controller
|
||||
-------------------------------------------------
|
||||
|
||||
Normally, Klippy would be used to translate gcode commands to Klipper
|
||||
commands. However, it's also possible to manually send Klipper
|
||||
commands (functions marked with the DECL_COMMAND() macro in the
|
||||
Klipper source code). To do so, run:
|
||||
|
||||
```
|
||||
~/klippy-env/bin/python ./klippy/console.py /tmp/pseudoserial 250000
|
||||
```
|
||||
|
||||
Generating load graphs
|
||||
======================
|
||||
|
||||
The Klippy log file (/tmp/klippy.log) stores statistics on bandwidth,
|
||||
micro-controller load, and host buffer load. It can be useful to graph
|
||||
these statistics after a print.
|
||||
|
||||
To generate a graph, a one time step is necessary to install the
|
||||
"matplotlib" package:
|
||||
|
||||
```
|
||||
sudo apt-get update
|
||||
sudo apt-get install python-matplotlib
|
||||
```
|
||||
|
||||
Then graphs can be produced with:
|
||||
|
||||
```
|
||||
~/klipper/scripts/graphstats.py /tmp/klippy.log loadgraph.png
|
||||
```
|
||||
|
||||
One can then view the resulting **loadgraph.png** file.
|
||||
102
docs/Features.md
Normal file
@@ -0,0 +1,102 @@
|
||||
Klipper has several compelling features:
|
||||
|
||||
* High precision stepper movement. Klipper utilizes an application
|
||||
processor (such as a low-cost Raspberry Pi) when calculating printer
|
||||
movements. The application processor determines when to step each
|
||||
stepper motor, it compresses those events, transmits them to the
|
||||
micro-controller, and then the micro-controller executes each event
|
||||
at the requested time. Each stepper event is scheduled with a
|
||||
precision of 25 micro-seconds or better. The software does not use
|
||||
kinematic estimations (such as the Bresenham algorithm) - instead it
|
||||
calculates precise step times based on the physics of acceleration
|
||||
and the physics of the machine kinematics. More precise stepper
|
||||
movement translates to quieter and more stable printer operation.
|
||||
|
||||
* Best in class performance. Klipper is able to achieve high stepping
|
||||
rates on both new and old micro-controllers. Even an old 8bit AVR
|
||||
micro-controller can obtain rates over 175K steps per second. On
|
||||
more recent micro-controllers, rates over 500K steps per second are
|
||||
possible. Higher stepper rates enable higher print velocities. The
|
||||
stepper event timing remains precise even at high speeds which
|
||||
improves overall stability.
|
||||
|
||||
* Configuration via simple config file. There's no need to reflash the
|
||||
micro-controller to change a setting. All of Klipper's configuration
|
||||
is stored in a standard config file which can be easily edited. This
|
||||
makes it easier to setup and maintain the hardware.
|
||||
|
||||
* Portable code. Klipper works on both ARM and AVR
|
||||
micro-controllers. Existing "reprap" style printers can run Klipper
|
||||
without hardware modification - just add a Raspberry Pi. Klipper's
|
||||
internal code layout makes it easier to support other
|
||||
micro-controller architectures as well.
|
||||
|
||||
* Simpler code. Klipper uses a very high level language (Python) for
|
||||
most code. The kinematics algorithms, the G-code parsing, the
|
||||
heating and thermistor algorithms, etc. are all written in
|
||||
Python. This makes it easier to develop new functionality.
|
||||
|
||||
* Advanced features:
|
||||
* Klipper implements the "pressure advance" algorithm for
|
||||
extruders. When properly tuned, pressure advance reduces extruder
|
||||
ooze.
|
||||
* Klipper supports printers with multiple micro-controllers. For
|
||||
example, one micro-controller could be used to control an
|
||||
extruder, while another could control the printer's heaters, while
|
||||
a third controls the rest of the printer. The Klipper host
|
||||
software implements clock synchronization to account for clock
|
||||
drift between micro-controllers. No special code is needed to
|
||||
enable multiple micro-controllers - it just requires a few extra
|
||||
lines in the config file.
|
||||
* Klipper also implements a novel "stepper phase endstop" algorithm
|
||||
that can dramatically improve the accuracy of typical endstop
|
||||
switches. When properly tuned it can improve a print's first layer
|
||||
bed adhesion.
|
||||
* Support for limiting the top speed of short "zigzag" moves to
|
||||
reduce printer vibration and noise. See the
|
||||
[kinematics](Kinematics.md) document for more information.
|
||||
|
||||
To get started with Klipper, read the [installation](Installation.md)
|
||||
guide.
|
||||
|
||||
Common features supported by Klipper
|
||||
====================================
|
||||
|
||||
Klipper supports many standard 3d printer features:
|
||||
|
||||
* Works with Octoprint. This allows the printer to be controlled using
|
||||
a regular web-browser. The same Raspberry Pi that runs Klipper can
|
||||
also run Octoprint.
|
||||
|
||||
* Standard G-Code support. Common g-code commands that are produced by
|
||||
typical "slicers" are supported. One may continue to use Slic3r,
|
||||
Cura, etc. with Klipper.
|
||||
|
||||
* Constant speed acceleration support. All printer moves will
|
||||
gradually accelerate from standstill to cruising speed and then
|
||||
decelerate back to a standstill.
|
||||
|
||||
* "Look-ahead" support. The incoming stream of G-Code movement
|
||||
commands are queued and analyzed - the acceleration between
|
||||
movements in a similar direction will be optimized to reduce print
|
||||
stalls and improve overall print time.
|
||||
|
||||
* Support for cartesian, delta, and corexy style printers.
|
||||
|
||||
Step Benchmarks
|
||||
===============
|
||||
|
||||
Below are the results of stepper performance tests. The numbers shown
|
||||
represent total number of steps per second on the micro-controller.
|
||||
|
||||
| Micro-controller | Fastest step rate | 3 steppers active |
|
||||
| ----------------- | ----------------- | ----------------- |
|
||||
| 20Mhz AVR | 189K | 125K |
|
||||
| 16Mhz AVR | 151K | 100K |
|
||||
| Arduino Due (ARM) | 382K | 337K |
|
||||
| Beaglebone PRU | 689K | 689K |
|
||||
|
||||
On AVR platforms, the highest achievable step rate is with just one
|
||||
stepper stepping. On the Due, the highest step rate is with two
|
||||
simultaneous steppers stepping. On the PRU, the highest step rate is
|
||||
with three simultaneous steppers.
|
||||
128
docs/Installation.md
Normal file
@@ -0,0 +1,128 @@
|
||||
These instructions assume the software will run on a Raspberry Pi
|
||||
computer in conjunction with OctoPrint. (See the
|
||||
[Beaglebone specific instructions](beaglebone.md) if using a
|
||||
Beaglebone.) It is recommended that a Raspberry Pi 2 or Raspberry Pi 3
|
||||
computer be used as the host machine.
|
||||
|
||||
It should be possible to run the Klipper host software on any computer
|
||||
running a recent Linux distribution, but doing so will require Linux
|
||||
admin knowledge to translate these installation instructions to the
|
||||
particulars of that machine.
|
||||
|
||||
Klipper currently supports Atmel ATmega based micro-controllers,
|
||||
Arduino Due (Atmel SAM3x8e ARM micro-controller), and
|
||||
[Beaglebone PRU](beaglebone.md) based printers.
|
||||
|
||||
Prepping an OS image
|
||||
====================
|
||||
|
||||
Start by installing [OctoPi](https://github.com/guysoft/OctoPi) on the
|
||||
Raspberry Pi computer. Use OctoPi v0.14.0 or later - see the
|
||||
[octopi releases](https://github.com/guysoft/OctoPi/releases) for
|
||||
release information. One should verify that OctoPi boots and that the
|
||||
OctoPrint web server works. After connecting to the OctoPrint web
|
||||
page, follow the prompt to upgrade OctoPrint to v1.3.5 or later.
|
||||
|
||||
After installing OctoPi and upgrading OctoPrint, ssh into the target
|
||||
machine (ssh pi@octopi -- password is "raspberry") and run the
|
||||
following commands:
|
||||
|
||||
```
|
||||
git clone https://github.com/KevinOConnor/klipper
|
||||
./klipper/scripts/install-octopi.sh
|
||||
```
|
||||
|
||||
The above will download Klipper, install some system dependencies,
|
||||
setup Klipper to run at system startup, and start the Klipper host
|
||||
software. It will require an internet connection and it may take a few
|
||||
minutes to complete.
|
||||
|
||||
Building and flashing the micro-controller
|
||||
==========================================
|
||||
|
||||
To compile the micro-controller code, start by configuring it:
|
||||
|
||||
```
|
||||
cd ~/klipper/
|
||||
make menuconfig
|
||||
```
|
||||
|
||||
Select the appropriate micro-controller and serial baud rate. Once
|
||||
configured, run:
|
||||
|
||||
```
|
||||
make
|
||||
```
|
||||
|
||||
Finally, for common micro-controllers, the code can be flashed with:
|
||||
|
||||
```
|
||||
sudo service klipper stop
|
||||
make flash FLASH_DEVICE=/dev/ttyACM0
|
||||
sudo service klipper start
|
||||
```
|
||||
|
||||
Configuring Klipper
|
||||
===================
|
||||
|
||||
The Klipper configuration is stored in a text file on the Raspberry
|
||||
Pi. Take a look at the example config files in the
|
||||
[config directory](../config/). The
|
||||
[example.cfg](../config/example.cfg) file contains documentation on
|
||||
command parameters and it can also be used as an initial config file
|
||||
template. However, for most printers, one of the other config files
|
||||
may be a more concise starting point. The next step is to copy and
|
||||
edit one of these config files - for example:
|
||||
|
||||
```
|
||||
cp ~/klipper/config/example.cfg ~/printer.cfg
|
||||
nano ~/printer.cfg
|
||||
```
|
||||
|
||||
Make sure to review and update each setting that is appropriate for
|
||||
the hardware.
|
||||
|
||||
Configuring OctoPrint to use Klipper
|
||||
====================================
|
||||
|
||||
The OctoPrint web server needs to be configured to communicate with
|
||||
the Klipper host software. Using a web browser, login to the OctoPrint
|
||||
web page, and navigate to the Settings tab. Then configure the
|
||||
following items:
|
||||
|
||||
Under "Serial Connection" in "Additional serial ports" add
|
||||
"/tmp/printer". Then click "Save".
|
||||
|
||||
Enter the Settings tab again and under "Serial Connection" change the
|
||||
"Serial Port" setting to "/tmp/printer". Unselect the "Not only cancel
|
||||
ongoing prints but also disconnect..." checkbox. Click "Save".
|
||||
|
||||
From the main page, under the "Connection" section (at the top left of
|
||||
the page) make sure the "Serial Port" is set to "/tmp/printer" and
|
||||
click "Connect". (If "/tmp/printer" is not an available selection then
|
||||
try reloading the page.)
|
||||
|
||||
Once connected, navigate to the "Terminal" tab and type "status"
|
||||
(without the quotes) into the command entry box and click "Send". The
|
||||
terminal window will likely report there is an error opening the
|
||||
config file - issue a "restart" command in the OctoPrint terminal to
|
||||
load the config. A "status" command will report the printer is ready
|
||||
if the Klipper config file is successfully read and the
|
||||
micro-controller is successfully found and configured. It is not
|
||||
unusual to have configuration errors during the initial setup - update
|
||||
the printer config file and issue "restart" until "status" reports the
|
||||
printer is ready.
|
||||
|
||||
Klipper reports error messages via the OctoPrint terminal tab. The
|
||||
"status" command can be used to re-report error messages. The default
|
||||
Klipper startup script also places a log in **/tmp/klippy.log** which
|
||||
provides more detailed information.
|
||||
|
||||
In addition to common g-code commands, Klipper supports a few extended
|
||||
commands - "status" and "restart" are examples of these commands. Use
|
||||
the "help" command to get a list of other extended commands.
|
||||
|
||||
Contacting the developers
|
||||
=========================
|
||||
|
||||
See the [contact page](Contact.md) to ask questions or report a bug.
|
||||
298
docs/Kinematics.md
Normal file
@@ -0,0 +1,298 @@
|
||||
This document provides an overview of how Klipper implements robot
|
||||
motion (its [kinematics](https://en.wikipedia.org/wiki/Kinematics)).
|
||||
The contents may be of interest to both developers interested in
|
||||
working on the Klipper software as well as users interested in better
|
||||
understanding the mechanics of their machines.
|
||||
|
||||
Acceleration
|
||||
============
|
||||
|
||||
Klipper implements a constant acceleration scheme whenever the print
|
||||
head changes velocity - the velocity is gradually changed to the new
|
||||
speed instead of suddenly jerking to it. Klipper always enforces
|
||||
acceleration between the tool head and the print. The filament leaving
|
||||
the extruder can be quite fragile - rapid jerks and/or extruder flow
|
||||
changes lead to poor quality and poor bed adhesion. Even when not
|
||||
extruding, if the print head is at the same level as the print then
|
||||
rapid jerking of the head can cause disruption of recently deposited
|
||||
filament. Limiting speed changes of the print head (relative to the
|
||||
print) reduces risks of disrupting the print.
|
||||
|
||||
It is also important to limit acceleration so that the stepper motors
|
||||
do not skip or put excessive stress on the machine. Klipper limits the
|
||||
torque on each stepper by virtue of limiting the acceleration of the
|
||||
print head. Enforcing acceleration at the print head naturally also
|
||||
limits the torque of the steppers that move the print head (the
|
||||
inverse is not always true).
|
||||
|
||||
Klipper implements constant acceleration. The key formula for constant
|
||||
acceleration is:
|
||||
```
|
||||
velocity(time) = start_velocity + accel*time
|
||||
```
|
||||
|
||||
Trapezoid generator
|
||||
===================
|
||||
|
||||
Klipper uses a traditional "trapezoid generator" to model the motion
|
||||
of each move - each move has a start speed, it accelerates to a
|
||||
cruising speed at constant acceleration, it cruises at a constant
|
||||
speed, and then decelerates to the end speed using constant
|
||||
acceleration.
|
||||
|
||||

|
||||
|
||||
It's called a "trapezoid generator" because a velocity diagram of the
|
||||
move looks like a trapezoid.
|
||||
|
||||
The cruising speed is always greater than or equal to both the start
|
||||
speed and the end speed. The acceleration phase may be of zero
|
||||
duration (if the start speed is equal to the cruising speed), the
|
||||
cruising phase may be of zero duration (if the move immediately starts
|
||||
decelerating after acceleration), and/or the deceleration phase may be
|
||||
of zero duration (if the end speed is equal to the cruising speed).
|
||||
|
||||

|
||||
|
||||
Look-ahead
|
||||
==========
|
||||
|
||||
The "look-ahead" system is used to determine cornering speeds between
|
||||
moves.
|
||||
|
||||
Consider the following two moves contained on an XY plane:
|
||||
|
||||

|
||||
|
||||
In the above situation it is possible to fully decelerate after the
|
||||
first move and then fully accelerate at the start of the next move,
|
||||
but that is not ideal as all that acceleration and deceleration would
|
||||
greatly increase the print time and the frequent changes in extruder
|
||||
flow would result in poor print quality.
|
||||
|
||||
To solve this, the "look-ahead" mechanism queues multiple incoming
|
||||
moves and analyzes the angles between moves to determine a reasonable
|
||||
speed that can be obtained during the "junction" between two moves. If
|
||||
the next move is nearly in the same direction then the head need only
|
||||
slow down a little (if at all).
|
||||
|
||||

|
||||
|
||||
However, if the next move forms an acute angle (the head is going to
|
||||
travel in nearly a reverse direction on the next move) then only a
|
||||
small junction speed is permitted.
|
||||
|
||||

|
||||
|
||||
The junction speeds are determined using "approximated centripetal
|
||||
acceleration". Best
|
||||
[described by the author](https://onehossshay.wordpress.com/2011/09/24/improving_grbl_cornering_algorithm/).
|
||||
|
||||
Klipper implements look-ahead between moves that have similar extruder
|
||||
flow rates. Other moves are relatively rare and implementing
|
||||
look-ahead between them is unnecessary.
|
||||
|
||||
Key formula for look-ahead:
|
||||
```
|
||||
end_velocity^2 = start_velocity^2 + 2*accel*move_distance
|
||||
```
|
||||
|
||||
Smoothed look-ahead
|
||||
-------------------
|
||||
|
||||
Klipper also implements a mechanism for smoothing out the motions of
|
||||
short "zigzag" moves. Consider the following moves:
|
||||
|
||||

|
||||
|
||||
In the above, the frequent changes from acceleration to deceleration
|
||||
can cause the machine to vibrate which causes stress on the machine
|
||||
and increases the noise. To reduce this, Klipper tracks both regular
|
||||
move acceleration as well as a virtual "acceleration to deceleration"
|
||||
rate. Using this system, the top speed of these short "zigzag" moves
|
||||
are limited to smooth out the printer motion:
|
||||
|
||||

|
||||
|
||||
Specifically, the code calculates what the velocity of each move would
|
||||
be if it were limited to this virtual "acceleration to deceleration"
|
||||
rate (half the normal acceleration rate by default). In the above
|
||||
picture the dashed gray lines represent this virtual acceleration rate
|
||||
for the first move. If a move can not reach its full cruising speed
|
||||
using this virtual acceleration rate then its top speed is reduced to
|
||||
the maximum speed it could obtain at this virtual acceleration
|
||||
rate. For most moves the limit will be at or above the move's existing
|
||||
limits and no change in behavior is induced. For short zigzag moves,
|
||||
however, this limit reduces the top speed. Note that it does not
|
||||
change the actual acceleration within the move - the move continues to
|
||||
use the normal acceleration scheme up to its adjusted top-speed.
|
||||
|
||||
Generating steps
|
||||
================
|
||||
|
||||
Once the look-ahead process completes, the print head movement for the
|
||||
given move is fully known (time, start position, end position,
|
||||
velocity at each point) and it is possible to generate the step times
|
||||
for the move. This process is done within "kinematic classes" in the
|
||||
Klipper code. Outside of these kinematic classes, everything is
|
||||
tracked in millimeters, seconds, and in cartesian coordinate space.
|
||||
It's the task of the kinematic classes to convert from this generic
|
||||
coordinate system to the hardware specifics of the particular printer.
|
||||
|
||||
In general, the code determines each step time by first calculating
|
||||
where along the line of movement the head would be if a step is
|
||||
taken. It then calculates what time the head should be at that
|
||||
position. Determining the time along the line of movement can be done
|
||||
using the formulas for constant acceleration and constant velocity:
|
||||
|
||||
```
|
||||
time = sqrt(2*distance/accel + (start_velocity/accel)^2) - start_velocity/accel
|
||||
time = distance/cruise_velocity
|
||||
```
|
||||
|
||||
Cartesian Robots
|
||||
----------------
|
||||
|
||||
Generating steps for cartesian printers is the simplest case. The
|
||||
movement on each axis is directly related to the movement in cartesian
|
||||
space.
|
||||
|
||||
Delta Robots
|
||||
------------
|
||||
|
||||
To generate step times on Delta printers it is necessary to correlate
|
||||
the movement in cartesian space with the movement on each stepper
|
||||
tower.
|
||||
|
||||
To simplify the math, for each stepper tower, the code calculates the
|
||||
location of a "virtual tower" that is along the line of movement.
|
||||
This virtual tower is chosen at the point where the line of movement
|
||||
(extended infinitely in both directions) would be closest to the
|
||||
actual tower.
|
||||
|
||||

|
||||
|
||||
It is then possible to calculate where the head will be along the line
|
||||
of movement after each step is taken on the virtual tower.
|
||||
|
||||

|
||||
|
||||
The key formula is Pythagoras's theorem:
|
||||
```
|
||||
distance_to_tower^2 = arm_length^2 - tower_height^2
|
||||
```
|
||||
|
||||
One complexity is that if the print head passes the virtual tower
|
||||
location then the stepper direction must be reversed. In this case
|
||||
forward steps will be taken at the start of the move and reverse steps
|
||||
will be taken at the end of the move.
|
||||
|
||||
### Delta movements beyond simple XY plane ###
|
||||
|
||||
Movement calculation is more complicated if a single move contains
|
||||
both XY movement and Z movement. These moves are rare, but they must
|
||||
still be handled correctly. A virtual tower along the line of movement
|
||||
is still calculated, but in this case the tower is not at a 90 degree
|
||||
angle relative to the line of movement:
|
||||
|
||||

|
||||
|
||||
The code continues to calculate step times using the same general
|
||||
scheme as delta moves within an XY plane, but the slope of the tower
|
||||
must also be used in the calculations.
|
||||
|
||||
Should the move contain only Z movement (ie, no XY movement at all)
|
||||
then the same math is used - just in this case the tower is parallel
|
||||
to the line of movement.
|
||||
|
||||
### Stepper motor acceleration limits ###
|
||||
|
||||
With delta kinematics it is possible for a move that is accelerating
|
||||
in cartesian space to require an acceleration on a particular stepper
|
||||
motor greater than the move's acceleration. This can occur when a
|
||||
stepper arm is more horizontal than vertical and the line of movement
|
||||
passes near that stepper's tower. Although these moves could require a
|
||||
stepper motor acceleration greater than the printer's maximum
|
||||
configured move acceleration, the effective mass moved by that stepper
|
||||
would be smaller. Thus the higher stepper acceleration does not result
|
||||
in significantly higher stepper torque and it is therefore considered
|
||||
harmless.
|
||||
|
||||
However, to avoid extreme cases, Klipper enforces a maximum ceiling on
|
||||
stepper acceleration of three times the printer's configured maximum
|
||||
move acceleration. (Similarly, the maximum velocity of the stepper is
|
||||
limited to three times the maximum move velocity.) In order to enforce
|
||||
this limit, moves at the extreme edge of the build envelope (where a
|
||||
stepper arm may be nearly horizontal) will have a lower maximum
|
||||
acceleration and velocity.
|
||||
|
||||
Extruder kinematics
|
||||
-------------------
|
||||
|
||||
Klipper implements extruder motion in its own kinematic class. Since
|
||||
the timing and speed of each print head movement is fully known for
|
||||
each move, it's possible to calculate the step times for the extruder
|
||||
independently from the step time calculations of the print head
|
||||
movement.
|
||||
|
||||
Basic extruder movement is simple to calculate. The step time
|
||||
generation uses the same constant acceleration and constant velocity
|
||||
formulas that cartesian robots use.
|
||||
|
||||
### Pressure advance ###
|
||||
|
||||
Experimentation has shown that it's possible to improve the modeling
|
||||
of the extruder beyond the basic extruder formula. In the ideal case,
|
||||
as an extrusion move progresses, the same volume of filament should be
|
||||
deposited at each point along the move and there should be no volume
|
||||
extruded after the move. Unfortunately, it's common to find that the
|
||||
basic extrusion formulas cause too little filament to exit the
|
||||
extruder at the start of extrusion moves and for excess filament to
|
||||
extrude after extrusion ends. This is often referred to as "ooze".
|
||||
|
||||

|
||||
|
||||
The "pressure advance" system attempts to account for this by using a
|
||||
different model for the extruder. Instead of naively believing that
|
||||
each mm^3 of filament fed into the extruder will result in that amount
|
||||
of mm^3 immediately exiting the extruder, it uses a model based on
|
||||
pressure. Pressure increases when filament is pushed into the extruder
|
||||
(as in [Hooke's law](https://en.wikipedia.org/wiki/Hooke%27s_law)) and
|
||||
the pressure necessary to extrude is dominated by the flow rate
|
||||
through the nozzle orifice (as in
|
||||
[Poiseuille's law](https://en.wikipedia.org/wiki/Poiseuille_law)). The
|
||||
key idea is that the relationship between filament, pressure, and flow
|
||||
rate can be modeled using a linear coefficient:
|
||||
```
|
||||
extra_filament = pressure_advance_coefficient * extruder_velocity
|
||||
```
|
||||
|
||||
See the [pressure advance](Pressure_Advance.md) document for
|
||||
information on how to find this pressure advance coefficient.
|
||||
|
||||
Once configured, Klipper will push in an additional amount of filament
|
||||
during acceleration. The higher the desired filament flow rate, the
|
||||
more filament must be pushed in during acceleration to account for
|
||||
pressure. During head deceleration the extra filament is retracted
|
||||
(the extruder will have a negative velocity).
|
||||
|
||||

|
||||
|
||||
One may notice that the pressure advance algorithm can cause the
|
||||
extruder motor to make sudden velocity changes. This is tolerated
|
||||
based on the idea that the majority of the inertia in the system is in
|
||||
changing the extruder pressure. As long as the extruder pressure does
|
||||
not change rapidly the sudden changes in extruder motor velocity are
|
||||
tolerated.
|
||||
|
||||
One area where sudden velocity changes become problematic is during
|
||||
small changes in head speed due to cornering.
|
||||
|
||||

|
||||
|
||||
To prevent this, the Klipper pressure advance code utilizes the move
|
||||
look-ahead queue to detect intermittent speed changes. During a
|
||||
deceleration event the code finds the maximum upcoming head speed
|
||||
within a configurable time window. The pressure is then only adjusted
|
||||
to this found maximum. This can greatly reduce (or even completely
|
||||
eliminate) pressure changes during cornering.
|
||||
285
docs/MCU_Commands.md
Normal file
@@ -0,0 +1,285 @@
|
||||
This document provides information on the low-level micro-controller
|
||||
commands that are sent from the Klipper "host" software and processed
|
||||
by the Klipper micro-controller software. This document is not an
|
||||
authoritative reference for these commands, nor is it an exclusive
|
||||
list of all available commands.
|
||||
|
||||
This document may be useful for developers interested in understanding
|
||||
the low-level micro-controller commands.
|
||||
|
||||
See the [protocol](Protocol.md) document for more information on the
|
||||
format of commands and their transmission. The commands here are
|
||||
described using their "printf" style syntax - for those unfamiliar
|
||||
with that format, just note that where a '%...' sequence is seen it
|
||||
should be replaced with an actual integer. For example, a description
|
||||
with "count=%c" could be replaced with the text "count=10".
|
||||
|
||||
Startup Commands
|
||||
================
|
||||
|
||||
It may be necessary to take certain one-time actions to configure the
|
||||
micro-controller and its peripherals. This section lists common
|
||||
commands available for that purpose. Unlike most micro-controller
|
||||
commands, these commands run as soon as they are received and they do
|
||||
not require any particular setup.
|
||||
|
||||
Several of these commands will take a "pin=%u" parameter. The
|
||||
low-level micro-controller software uses integer encodings of the
|
||||
hardware pin numbers, but to make things more readable the host will
|
||||
translate human readable pin names (eg, "PA3") to their equivalent
|
||||
integer encodings. By convention, any parameter named "pin" or that
|
||||
has a "_pin" suffix will use pin name translation by the
|
||||
host.
|
||||
|
||||
Common startup commands:
|
||||
|
||||
* `set_digital_out pin=%u value=%c` : This command immediately
|
||||
configures the given pin as a digital out GPIO and it sets it to
|
||||
either a low level (value=0) or a high level (value=1). This command
|
||||
may be useful for configuring the initial value of LEDs and for
|
||||
configuring the initial value of stepper driver micro-stepping pins.
|
||||
|
||||
* `set_pwm_out pin=%u cycle_ticks=%u value=%hu` : This command will
|
||||
immediately configure the given pin to use hardware based
|
||||
pulse-width-modulation (PWM) with the given number of
|
||||
cycle_ticks. The "cycle_ticks" is the number of MCU clock ticks each
|
||||
power on and power off cycle should last. A cycle_ticks value of 1
|
||||
can be used to request the fastest possible cycle time. The "value"
|
||||
parameter is between 0 and 255 with 0 indicating a full off state
|
||||
and 255 indicating a full on state. This command may be useful for
|
||||
enabling CPU and nozzle cooling fans.
|
||||
|
||||
* `send_spi_message pin=%u msg=%*s` : This command can be used to
|
||||
transmit messages to a serial-peripheral-interface (SPI) component
|
||||
connected to the micro-controller. It has been used to configure the
|
||||
startup settings of AD5206 digipots. The 'pin' parameter specifies
|
||||
the chip select line to use during the transmission. The 'msg'
|
||||
indicates the binary message to transmit to the given chip.
|
||||
|
||||
Low-level micro-controller configuration
|
||||
========================================
|
||||
|
||||
Most commands in the micro-controller require an initial setup before
|
||||
they can be successfully invoked. This section provides an overview of
|
||||
the configuration process. This section and the following sections are
|
||||
likely only of interest to developers interested in the internal
|
||||
details of Klipper.
|
||||
|
||||
When the host first connects to the micro-controller it always starts
|
||||
by obtaining a data dictionary (see [protocol](Protocol.md) for more
|
||||
information). After the data dictionary is obtained the host will
|
||||
check if the micro-controller is in a "configured" state and configure
|
||||
it if not. Configuration involves the following phases:
|
||||
|
||||
* `get_config` : The host starts by checking if the micro-controller
|
||||
is already configured. The micro-controller responds to this command
|
||||
with a "config" response message. The micro-controller software
|
||||
always starts in an unconfigured state at power-on. It remains in
|
||||
this state until the host completes the configuration processes (by
|
||||
issuing a finalize_config command). If the micro-controller is
|
||||
already configured from a previous session (and is configured with
|
||||
the desired settings) then no further action is needed by the host
|
||||
and the configuration process ends successfully.
|
||||
|
||||
* `allocate_oids count=%c` : This command is issued to inform the
|
||||
micro-controller of the maximum number of object-ids (oid) that the
|
||||
host requires. It is only valid to issue this command once. An oid
|
||||
is an integer identifier allocated to each stepper, each endstop,
|
||||
and each schedulable gpio pin. The host determines in advance the
|
||||
number of oids it will require to operate the hardware and passes
|
||||
this to the micro-controller so that it may allocate sufficient
|
||||
memory to store a mapping from oid to internal object.
|
||||
|
||||
* `config_XXX oid=%c ...` : By convention any command starting with
|
||||
the "config_" prefix creates a new micro-controller object and
|
||||
assigns the given oid to it. For example, the config_digital_out
|
||||
command will configure the specified pin as a digital output GPIO
|
||||
and create an internal object that the host can use to schedule
|
||||
changes to the given GPIO. The oid parameter passed into the config
|
||||
command is selected by the host and must be between zero and the
|
||||
maximum count supplied in the allocate_oids command. The config
|
||||
commands may only be run when the micro-controller is not in a
|
||||
configured state (ie, prior to the host sending finalize_config) and
|
||||
after the allocate_oids command has been sent.
|
||||
|
||||
* `finalize_config crc=%u` : The finalize_config command transitions
|
||||
the micro-controller from an unconfigured state to a configured
|
||||
state. The crc parameter passed to the micro-controller is stored
|
||||
and provided back to the host in "config" response messages. By
|
||||
convention, the host takes a 32bit CRC of the configuration it will
|
||||
request and at the start of subsequent communication sessions it
|
||||
checks that the CRC stored in the micro-controller exactly matches
|
||||
its desired CRC. If the CRC does not match then the host knows the
|
||||
micro-controller has not been configured in the state desired by the
|
||||
host.
|
||||
|
||||
Common micro-controller objects
|
||||
-------------------------------
|
||||
|
||||
This section lists some commonly used config commands.
|
||||
|
||||
* `config_digital_out oid=%c pin=%u value=%c default_value=%c
|
||||
max_duration=%u` : This command creates an internal micro-controller
|
||||
object for the given GPIO 'pin'. The pin will be configured in
|
||||
digital output mode and set to an initial value as specified by
|
||||
'value' (0 for low, 1 for high). Creating a digital_out object
|
||||
allows the host to schedule GPIO updates for the given pin at
|
||||
specified times (see the schedule_digital_out command described
|
||||
below). Should the micro-controller software go into shutdown mode
|
||||
then all configured digital_out objects will be set to
|
||||
'default_value'. The 'max_duration' parameter is used to implement a
|
||||
safety check - if it is non-zero then it is the maximum number of
|
||||
clock ticks that the host may set the given GPIO to a non-default
|
||||
value without further updates. For example, if the default_value is
|
||||
zero and the max_duration is 16000 then if the host sets the gpio to
|
||||
a value of one then it must schedule another update to the gpio pin
|
||||
(to either zero or one) within 16000 clock ticks. This safety
|
||||
feature can be used with heater pins to ensure the host does not
|
||||
enable the heater and then go off-line.
|
||||
|
||||
* `config_pwm_out oid=%c pin=%u cycle_ticks=%u value=%hu
|
||||
default_value=%hu max_duration=%u` : This command creates an
|
||||
internal object for hardware based PWM pins that the host may
|
||||
schedule updates for. Its usage is analogous to config_digital_out -
|
||||
see the description of the 'set_pwm_out' and 'config_digital_out'
|
||||
commands for parameter description.
|
||||
|
||||
* `config_soft_pwm_out oid=%c pin=%u cycle_ticks=%u value=%c
|
||||
default_value=%c max_duration=%u` : This command creates an internal
|
||||
micro-controller object for software implemented PWM. Unlike
|
||||
hardware pwm pins, a software pwm object does not require any
|
||||
special hardware support (other than the ability to configure the
|
||||
pin as a digital output GPIO). Because the output switching is
|
||||
implemented in the micro-controller software, it is recommended that
|
||||
the cycle_ticks parameter correspond to a time of 10ms or
|
||||
greater. See the description of the 'set_pwm_out' and
|
||||
'config_digital_out' commands for parameter description.
|
||||
|
||||
* `config_analog_in oid=%c pin=%u` : This command is used to configure
|
||||
a pin in analog input sampling mode. Once configured, the pin can be
|
||||
sampled at regular interval using the query_analog_in command (see
|
||||
below).
|
||||
|
||||
* `config_stepper oid=%c step_pin=%c dir_pin=%c min_stop_interval=%u
|
||||
invert_step=%c` : This command creates an internal stepper
|
||||
object. The 'step_pin' and 'dir_pin' parameters specify the step and
|
||||
direction pins respectively; this command will configure them in
|
||||
digital output mode. The 'invert_step' parameter specifies whether a
|
||||
step occurs on a rising edge (invert_step=0) or falling edge
|
||||
(invert_step=1). The 'min_stop_interval' implements a safety
|
||||
feature - it is checked when the micro-controller finishes all moves
|
||||
for a stepper - if it is non-zero it specifies the minimum number of
|
||||
clock ticks since the last step. It is used as a check on the
|
||||
maximum stepper velocity that a stepper may have before stopping.
|
||||
|
||||
* `config_end_stop oid=%c pin=%c pull_up=%c stepper_count=%c` : This
|
||||
command creates an internal "endstop" object. It is used to specify
|
||||
the endstop pins and to enable "homing" operations (see the
|
||||
end_stop_home command below). The command will configure the
|
||||
specified pin in digital input mode. The 'pull_up' parameter
|
||||
determines whether hardware provided pullup resistors for the pin
|
||||
(if available) will be enabled. The 'stepper_count' parameter
|
||||
specifies the maximum number of steppers that this endstop may need
|
||||
to halt during a homing operation (see end_stop_home below).
|
||||
|
||||
Common commands
|
||||
===============
|
||||
|
||||
This section lists some commonly used run-time commands. It is likely
|
||||
only of interest to developers looking to gain insight into Klipper.
|
||||
|
||||
* `schedule_digital_out oid=%c clock=%u value=%c` : This command will
|
||||
schedule a change to a digital output GPIO pin at the given clock
|
||||
time. To use this command a 'config_digital_out' command with the
|
||||
same 'oid' parameter must have been issued during micro-controller
|
||||
configuration.
|
||||
|
||||
* `schedule_pwm_out oid=%c clock=%u value=%hu` : Schedules a change to
|
||||
a hardware PWM output pin. See the 'schedule_digital_out' and
|
||||
'config_pwm_out' commands for more info.
|
||||
|
||||
* `schedule_soft_pwm_out oid=%c clock=%u value=%hu` : Schedules a
|
||||
change to a software PWM output pin. See the 'schedule_digital_out'
|
||||
and 'config_soft_pwm_out' commands for more info.
|
||||
|
||||
* `query_analog_in oid=%c clock=%u sample_ticks=%u sample_count=%c
|
||||
rest_ticks=%u min_value=%hu max_value=%hu` : This command sets up a
|
||||
recurring schedule of analog input samples. To use this command a
|
||||
'config_analog_in' command with the same 'oid' parameter must have
|
||||
been issued during micro-controller configuration. The samples will
|
||||
start as of 'clock' time, it will report on the obtained value every
|
||||
'rest_ticks' clock ticks, it will over-sample 'sample_count' number
|
||||
of times, and it will pause 'sample_ticks' number of clock ticks
|
||||
between over-sample samples. The 'min_value' and 'max_value'
|
||||
parameters implement a safety feature - the micro-controller
|
||||
software will verify the sampled value (after any oversampling) is
|
||||
always between the supplied range. This is intended for use with
|
||||
pins attached to thermistors controlling heaters - it can be used to
|
||||
check that a heater is within a temperature range.
|
||||
|
||||
* `get_status` : This command causes the micro-controller to generate
|
||||
a "status" response message. The host sends this command once a
|
||||
second to obtain the value of the micro-controller clock and to
|
||||
estimate the drift between host and micro-controller clocks. It
|
||||
enables the host to accurately estimate the micro-controller clock.
|
||||
|
||||
Stepper commands
|
||||
----------------
|
||||
|
||||
* `queue_step oid=%c interval=%u count=%hu add=%hi` : This command
|
||||
schedules 'count' number of steps for the given stepper, with
|
||||
'interval' number of clock ticks between each step. The first step
|
||||
will be 'interval' number of clock ticks since the last scheduled
|
||||
step for the given stepper. If 'add' is non-zero then the interval
|
||||
will be adjusted by 'add' amount after each step. This command
|
||||
appends the given interval/count/add sequence to a per-stepper
|
||||
queue. There may be hundreds of these sequences queued during normal
|
||||
operation. New sequence are appended to the end of the queue and as
|
||||
each sequence completes its 'count' number of steps it is popped
|
||||
from the front of the queue. This system allows the micro-controller
|
||||
to queue potentially hundreds of thousands of steps - all with
|
||||
reliable and predictable schedule times.
|
||||
|
||||
* `set_next_step_dir oid=%c dir=%c` : This command specifies the value
|
||||
of the dir_pin that the next queue_step command will use.
|
||||
|
||||
* `reset_step_clock oid=%c clock=%u` : Normally, step timing is
|
||||
relative to the last step for a given stepper. This command resets
|
||||
the clock so that the next step is relative to the supplied 'clock'
|
||||
time. The host usually only sends this command at the start of a
|
||||
print.
|
||||
|
||||
* `stepper_get_position oid=%c` : This command causes the
|
||||
micro-controller to generate a "stepper_position" response message
|
||||
with the stepper's current position. The position is the total
|
||||
number of steps generated with dir=1 minus the total number of steps
|
||||
generated with dir=0.
|
||||
|
||||
* `end_stop_home oid=%c clock=%u sample_ticks=%u sample_count=%c
|
||||
rest_ticks=%u pin_value=%c` : This command is used during stepper
|
||||
"homing" operations. To use this command a 'config_end_stop' command
|
||||
with the same 'oid' parameter must have been issued during
|
||||
micro-controller configuration. When this command is invoked, the
|
||||
micro-controller will sample the endstop pin every 'rest_ticks'
|
||||
clock ticks and check if it has a value equal to 'pin_value'. If the
|
||||
value matches (and it continues to match for 'sample_count'
|
||||
additional samples spread 'sample_ticks' apart) then the movement
|
||||
queue for the associated stepper will be cleared and the stepper
|
||||
will come to an immediate halt. The host uses this command to
|
||||
implement homing - the host instructs the endstop to sample for the
|
||||
endstop trigger and then it issues a series of queue_step commands
|
||||
to move a stepper towards the endstop. Once the stepper hits the
|
||||
endstop, the trigger will be detected, the movement halted, and the
|
||||
host notified.
|
||||
|
||||
### Move queue
|
||||
|
||||
Each queue_step command utilizes an entry in the micro-controller
|
||||
"move queue". This queue is allocated when it receives the
|
||||
"finalize_config" command, and it reports the number of available
|
||||
queue entries in "config" response messages.
|
||||
|
||||
It is the responsibility of the host to ensure that there is available
|
||||
space in the queue before sending a queue_step command. The host does
|
||||
this by calculating when each queue_step command completes and
|
||||
scheduling new queue_step commands accordingly.
|
||||
38
docs/Overview.md
Normal file
@@ -0,0 +1,38 @@
|
||||
Welcome to the Klipper documentation. There are two parts to Klipper -
|
||||
code that runs on a micro-controller and code that runs on a "host"
|
||||
machine. The host code is intended to run on a low-cost
|
||||
general-purpose machine such as a Raspberry Pi, while the
|
||||
micro-controller code is intended to run on commodity micro-controller
|
||||
chips. Read [features](Features.md) for reasons to use Klipper. See
|
||||
[installation](Installation.md) to get started with Klipper.
|
||||
|
||||
The Klipper configuration is stored in a simple text file on the host
|
||||
machine. The [config/example.cfg](../config/example.cfg) file serves
|
||||
as a reference for the config file. The
|
||||
[Pressure Advance](Pressure_Advance.md) document contains information
|
||||
on tuning the pressure advance config.
|
||||
|
||||
The [kinematics](Kinematics.md) document provides some technical
|
||||
details on how Klipper implements motion.
|
||||
|
||||
The history of Klipper releases is available at
|
||||
[releases](Releases.md). See [contact](Contact.md) for information on
|
||||
bug reporting and general communication with the developers.
|
||||
|
||||
Developer Documentation
|
||||
=======================
|
||||
|
||||
There are also several documents available for developers interested
|
||||
in understanding how Klipper works. Start with the
|
||||
[code overview](Code_Overview.md) document - it provides information
|
||||
on the structure and layout of the Klipper code.
|
||||
|
||||
See [protocol](Protocol.md) for information on the low-level messaging
|
||||
protocol between host and micro-controller. See also
|
||||
[MCU commands](MCU_Commands.md) for a description of low-level
|
||||
commands implemented in the micro-controller software.
|
||||
|
||||
See [debugging](Debugging.md) for information on how to test and debug
|
||||
Klipper.
|
||||
|
||||
See [todo](Todo.md) for information on possible future code features.
|
||||
94
docs/Pressure_Advance.md
Normal file
@@ -0,0 +1,94 @@
|
||||
This document provides information on tuning the "pressure advance"
|
||||
configuration variables for a particular nozzle and filament. The
|
||||
pressure advance feature can be helpful in reducing ooze. For more
|
||||
information on how pressure advance is implemented see the
|
||||
[kinematics](Kinematics.md) document.
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
|
||||
In order to tune the pressure advance setting the printer must be
|
||||
configured and operational. The tuning test involves printing objects
|
||||
and inspecting the differences between objects. In particular, the
|
||||
extruder
|
||||
[E steps](http://reprap.org/wiki/Triffid_Hunter%27s_Calibration_Guide#E_steps)
|
||||
and
|
||||
[nozzle temperature](http://reprap.org/wiki/Triffid_Hunter%27s_Calibration_Guide#Nozzle_Temperature)
|
||||
should be tuned prior to tuning pressure advance.
|
||||
|
||||
Tuning pressure advance
|
||||
=======================
|
||||
|
||||
Pressure advance does two useful things - it reduces ooze during
|
||||
non-extrude moves and it reduces blobbing during cornering. This guide
|
||||
uses the second feature (reducing blobbing during cornering) as a
|
||||
mechanism for measuring and tuning the pressure advance configuration.
|
||||
|
||||
Start by changing the extruder section of the config file so that
|
||||
pressure_advance is set to 0.0. (Make sure to issue a RESTART command
|
||||
after each update to the config file so that the new configuration
|
||||
takes effect.) Then print at least 10 layers of a large hollow square
|
||||
at high speed (eg, 100mm/s). See
|
||||
[docs/prints/square.stl](prints/square.stl) file for an STL file that
|
||||
one may use. While the object is printing, make a note of which
|
||||
direction the head is moving during external perimeters. What many
|
||||
people see here is blobbing occurring at the corners - extra filament
|
||||
at the corner in the direction the head travels followed by a possible
|
||||
lack of filament on the side immediately after that corner:
|
||||
|
||||

|
||||
|
||||
This blobbing is the result of pressure in the extruder being released
|
||||
as a blob when the head slows down to corner.
|
||||
|
||||
The next step is to set pressure_advance_lookahead_time to 0.0, slowly
|
||||
increase pressure_advance (eg, start with 0.05), and reprint the test
|
||||
object. (Be sure to issue RESTART between each config change.) The
|
||||
goal is to attempt to eliminate the blobbing during cornering. (With
|
||||
pressure advance, the extruder will retract when the head slows down,
|
||||
thus countering the pressure buildup and ideally eliminate the
|
||||
blobbing.)
|
||||
|
||||
If a test run is done with a pressure_advance setting that is too
|
||||
high, one typically sees a dimple in the corner followed by possible
|
||||
blobbing after the corner (too much filament is retracted during slow
|
||||
down and then too much filament is extruded during the following speed
|
||||
up after cornering):
|
||||
|
||||

|
||||
|
||||
The goal is to find the smallest pressure_advance value that results
|
||||
in good quality corners:
|
||||
|
||||

|
||||
|
||||
Typical pressure_advance values are between 0.05 and 0.20 (the high
|
||||
end usually only with bowden extruders).
|
||||
|
||||
It is not unusual for one corner of the test print to be consistently
|
||||
different than the other three corners. This typically occurs when the
|
||||
slicer arranges to always change Z height at that corner. If this
|
||||
occurs, then ignore that corner and tune pressure_advance using the
|
||||
other three corners.
|
||||
|
||||
Once a good pressure_advance value is found, return
|
||||
pressure_advance_lookahead_time to its default (0.010). This parameter
|
||||
controls how far in advance to check if a head slow-down is
|
||||
immediately followed by a speed-up - it reduces pointless pressure
|
||||
changes in the head. It's possible to tune this - higher values will
|
||||
decrease the number of pressure changes in the nozzle at the expense
|
||||
of permitting more blobbing during cornering. (Tuning this value is
|
||||
unlikely to impact ooze.) The default of 10ms should work well on most
|
||||
printers.
|
||||
|
||||
Although this tuning exercise directly improves the quality of
|
||||
corners, it's worth remembering that a good pressure advance
|
||||
configuration can reduce ooze throughout the print.
|
||||
|
||||
Finally, once pressure_advance is tuned in Klipper, it may still be
|
||||
useful to configure a small retract value in the slicer (eg, 0.75mm)
|
||||
and to utilize the slicer's "wipe on retract option" if available.
|
||||
These slicer settings may help counteract ooze caused by filament
|
||||
cohesion (filament pulled out of the nozzle due to the stickiness of
|
||||
the plastic). It is recommended to disable the slicer's "z-lift on
|
||||
retract" option.
|
||||
343
docs/Protocol.md
Normal file
@@ -0,0 +1,343 @@
|
||||
The Klipper messaging protocol is used for low-level communication
|
||||
between the Klipper host software and the Klipper micro-controller
|
||||
software. At a high level the protocol can be thought of as a series
|
||||
of command and response strings that are compressed, transmitted, and
|
||||
then processed at the receiving side. An example series of commands in
|
||||
uncompressed human-readable format might look like:
|
||||
|
||||
```
|
||||
set_digital_out pin=86 value=1
|
||||
set_digital_out pin=85 value=1
|
||||
schedule_digital_out oid=8 clock=4000000 value=0
|
||||
queue_step oid=7 interval=7458 count=10 add=331
|
||||
queue_step oid=7 interval=11717 count=4 add=1281
|
||||
```
|
||||
|
||||
See the [mcu commands](MCU_Commands.md) document for information on
|
||||
available commands. See the [debugging](Debugging.md) document for
|
||||
information on how to translate a G-Code file into its corresponding
|
||||
human-readable micro-controller commands.
|
||||
|
||||
This page provides a high-level description of the Klipper messaging
|
||||
protocol itself. It describes how messages are declared, encoded in
|
||||
binary format (the "compression" scheme), and transmitted.
|
||||
|
||||
The goal of the protocol is to enable an error-free communication
|
||||
channel between the host and micro-controller that is low-latency,
|
||||
low-bandwidth, and low-complexity for the micro-controller.
|
||||
|
||||
Micro-controller Interface
|
||||
==========================
|
||||
|
||||
The Klipper transmission protocol can be thought of as a
|
||||
[RPC](https://en.wikipedia.org/wiki/Remote_procedure_call) mechanism
|
||||
between micro-controller and host. The micro-controller software
|
||||
declares the commands that the host may invoke along with the response
|
||||
messages that it can generate. The host uses that information to
|
||||
command the micro-controller to perform actions and to interpret the
|
||||
results.
|
||||
|
||||
Declaring commands
|
||||
------------------
|
||||
|
||||
The micro-controller software declares a "command" by using the
|
||||
DECL_COMMAND() macro in the C code. For example:
|
||||
|
||||
```
|
||||
DECL_COMMAND(command_set_digital_out, "set_digital_out pin=%u value=%c");
|
||||
```
|
||||
|
||||
The above declares a command named "set_digital_out". This allows the
|
||||
host to "invoke" this command which would cause the
|
||||
command_set_digital_out() C function to be executed in the
|
||||
micro-controller. The above also indicates that the command takes two
|
||||
integer parameters. When the command_set_digital_out() C code is
|
||||
executed, it will be passed an array containing these two integers -
|
||||
the first corresponding to the 'pin' and the second corresponding to
|
||||
the 'value'.
|
||||
|
||||
In general, the parameters are described with printf() style syntax
|
||||
(eg, "%u"). The formatting directly corresponds to the human-readable
|
||||
view of commands (eg, "set_digital_out pin=86 value=1"). In the above
|
||||
example, "value=" is a parameter name and "%c" indicates the parameter
|
||||
is an integer. Internally, the parameter name is only used as
|
||||
documentation. In this example, the "%c" is also used as documentation
|
||||
to indicate the expected integer is 1 byte in size (the declared
|
||||
integer size does not impact the parsing or encoding).
|
||||
|
||||
The micro-controller build will collect all commands declared with
|
||||
DECL_COMMAND(), determine their parameters, and arrange for them to be
|
||||
callable.
|
||||
|
||||
Declaring responses
|
||||
-------------------
|
||||
|
||||
To send information from the micro-controller to the host a "response"
|
||||
is generated. These are both declared and transmitted using the
|
||||
sendf() C macro. For example:
|
||||
|
||||
```
|
||||
sendf("status clock=%u status=%c", sched_read_time(), sched_is_shutdown());
|
||||
```
|
||||
|
||||
The above transmits a "status" response message that contains two
|
||||
integer parameters ("clock" and "status"). The micro-controller build
|
||||
automatically finds all sendf() calls and generates encoders for
|
||||
them. The first parameter of the sendf() function describes the
|
||||
response and it is in the same format as command declarations.
|
||||
|
||||
The host can arrange to register a callback function for each
|
||||
response. So, in effect, commands allow the host to invoke C functions
|
||||
in the micro-controller and responses allow the micro-controller
|
||||
software to invoke code in the host.
|
||||
|
||||
The sendf() macro should only be invoked from command or task
|
||||
handlers, and it should not be invoked from interrupts or timers. The
|
||||
code does not need to issue a sendf() in response to a received
|
||||
command, it is not limited in the number of times sendf() may be
|
||||
invoked, and it may invoke sendf() at any time from a task handler.
|
||||
|
||||
### Output responses
|
||||
|
||||
To simplify debugging, there is also has an output() C function. For
|
||||
example:
|
||||
|
||||
```
|
||||
output("The value of %u is %s with size %u.", x, buf, buf_len);
|
||||
```
|
||||
|
||||
The output() function is similar in usage to printf() - it is intended
|
||||
to generate and format arbitrary messages for human consumption.
|
||||
|
||||
Declaring constants
|
||||
-------------------
|
||||
|
||||
Constants can also be exported. For example, the following:
|
||||
|
||||
```
|
||||
DECL_CONSTANT(SERIAL_BAUD, 250000);
|
||||
```
|
||||
|
||||
would export a constant named "SERIAL_BAUD" with a value of 250000
|
||||
from the micro-controller to the host.
|
||||
|
||||
Low-level message encoding
|
||||
==========================
|
||||
|
||||
To accomplish the above RPC mechanism, each command and response is
|
||||
encoded into a binary format for transmission. This section describes
|
||||
the transmission system.
|
||||
|
||||
Message Blocks
|
||||
--------------
|
||||
|
||||
All data sent from host to micro-controller and vice-versa are
|
||||
contained in "message blocks". A message block has a two byte header
|
||||
and a three byte trailer. The format of a message block is:
|
||||
|
||||
```
|
||||
<1 byte length><1 byte sequence><n-byte content><2 byte crc><1 byte sync>
|
||||
```
|
||||
|
||||
The length byte contains the number of bytes in the message block
|
||||
including the header and trailer bytes (thus the minimum message
|
||||
length is 5 bytes). The maximum message block length is currently 64
|
||||
bytes. The sequence byte contains a 4 bit sequence number in the
|
||||
low-order bits and the high-order bits always contain 0x10 (the
|
||||
high-order bits are reserved for future use). The content bytes
|
||||
contain arbitrary data and its format is described in the following
|
||||
section. The crc bytes contain a 16bit CCITT
|
||||
[CRC](https://en.wikipedia.org/wiki/Cyclic_redundancy_check) of the
|
||||
message block including the header bytes but excluding the trailer
|
||||
bytes. The sync byte is 0x7e.
|
||||
|
||||
The format of the message block is inspired by
|
||||
[HDLC](https://en.wikipedia.org/wiki/High-Level_Data_Link_Control)
|
||||
message frames. Like in HDLC, the message block may optionally contain
|
||||
an additional sync character at the start of the block. Unlike in
|
||||
HDLC, a sync character is not exclusive to the framing and may be
|
||||
present in the message block content.
|
||||
|
||||
Message Block Contents
|
||||
----------------------
|
||||
|
||||
Each message block sent from host to micro-controller contains a
|
||||
series of zero or more message commands in its contents. Each command
|
||||
starts with a [Variable Length Quantity](#variable-length-quantities)
|
||||
(VLQ) encoded integer command-id followed by zero or more VLQ
|
||||
parameters for the given command.
|
||||
|
||||
As an example, the following four commands might be placed in a single
|
||||
message block:
|
||||
|
||||
```
|
||||
set_digital_out pin=86 value=1
|
||||
set_digital_out pin=85 value=0
|
||||
get_config
|
||||
get_status
|
||||
```
|
||||
|
||||
and encoded into the following eight VLQ integers:
|
||||
|
||||
```
|
||||
<id_set_digital_out><86><1><id_set_digital_out><85><0><id_get_config><id_get_status>
|
||||
```
|
||||
|
||||
In order to encode and parse the message contents, both the host and
|
||||
micro-controller must agree on the command ids and the number of
|
||||
parameters each command has. So, in the above example, both the host
|
||||
and micro-controller would know that "id_set_digital_out" is always
|
||||
followed by two parameters, and "id_get_config" and "id_get_status"
|
||||
have zero parameters. The host and micro-controller share a "data
|
||||
dictionary" that maps the command descriptions (eg, "set_digital_out
|
||||
pin=%u value=%c") to their integer command-ids. When processing the
|
||||
data, the parser will know to expect a specific number of VLQ encoded
|
||||
parameters following a given command id.
|
||||
|
||||
The message contents for blocks sent from micro-controller to host
|
||||
follow the same format. The identifiers in these messages are
|
||||
"response ids", but they serve the same purpose and follow the same
|
||||
encoding rules. In practice, message blocks sent from the
|
||||
micro-controller to the host never contain more than one response in
|
||||
the message block contents.
|
||||
|
||||
### Variable Length Quantities
|
||||
|
||||
See the [wikipedia article](https://en.wikipedia.org/wiki/Variable-length_quantity)
|
||||
for more information on the general format of VLQ encoded
|
||||
integers. Klipper uses an encoding scheme that supports both positive
|
||||
and negative integers. Integers close to zero use less bytes to encode
|
||||
and positive integers typically encode using less bytes than negative
|
||||
integers. The following table shows the number of bytes each integer
|
||||
takes to encode:
|
||||
|
||||
| Integer | Encoded size |
|
||||
|---------------------------|--------------|
|
||||
| -32 .. 95 | 1 |
|
||||
| -4096 .. 12287 | 2 |
|
||||
| -524288 .. 1572863 | 3 |
|
||||
| -67108864 .. 201326591 | 4 |
|
||||
| -2147483648 .. 4294967295 | 5 |
|
||||
|
||||
### Variable length strings
|
||||
|
||||
As an exception to the above encoding rules, if a parameter to a
|
||||
command or response is a dynamic string then the parameter is not
|
||||
encoded as a simple VLQ integer. Instead it is encoded by transmitting
|
||||
the length as a VLQ encoded integer followed by the contents itself:
|
||||
|
||||
```
|
||||
<VLQ encoded length><n-byte contents>
|
||||
```
|
||||
|
||||
The command descriptions found in the data dictionary allow both the
|
||||
host and micro-controller to know which command parameters use simple
|
||||
VLQ encoding and which parameters use string encoding.
|
||||
|
||||
Data Dictionary
|
||||
===============
|
||||
|
||||
In order for meaningful communications to be established between
|
||||
micro-controller and host, both sides must agree on a "data
|
||||
dictionary". This data dictionary contains the integer identifiers for
|
||||
commands and responses along with their descriptions.
|
||||
|
||||
The micro-controller build uses the contents of DECL_COMMAND() and
|
||||
sendf() macros to generate the data dictionary. The build
|
||||
automatically assigns unique identifiers to each command and
|
||||
response. This system allows both the host and micro-controller code
|
||||
to seamlessly use descriptive human-readable names while still using
|
||||
minimal bandwidth.
|
||||
|
||||
The host queries the data dictionary when it first connects to the
|
||||
micro-controller. Once the host downloads the data dictionary from the
|
||||
micro-controller, it uses that data dictionary to encode all commands
|
||||
and to parse all responses from the micro-controller. The host must
|
||||
therefore handle a dynamic data dictionary. However, to keep the
|
||||
micro-controller software simple, the micro-controller always uses its
|
||||
static (compiled in) data dictionary.
|
||||
|
||||
The data dictionary is queried by sending "identify" commands to the
|
||||
micro-controller. The micro-controller will respond to each identify
|
||||
command with an "identify_response" message. Since these two commands
|
||||
are needed prior to obtaining the data dictionary, their integer ids
|
||||
and parameter types are hard-coded in both the micro-controller and
|
||||
the host. The "identify_response" response id is 0, the "identify"
|
||||
command id is 1. Other than having hard-coded ids the identify command
|
||||
and its response are declared and transmitted the same way as other
|
||||
commands and responses. No other command or response is hard-coded.
|
||||
|
||||
The format of the transmitted data dictionary itself is a zlib
|
||||
compressed JSON string. The micro-controller build process generates
|
||||
the string, compresses it, and stores it in the text section of the
|
||||
micro-controller flash. The data dictionary can be much larger than
|
||||
the maximum message block size - the host downloads it by sending
|
||||
multiple identify commands requesting progressive chunks of the data
|
||||
dictionary. Once all chunks are obtained the host will assemble the
|
||||
chunks, uncompress the data, and parse the contents.
|
||||
|
||||
In addition to information on the communication protocol, the data
|
||||
dictionary also contains the software version, constants (as defined
|
||||
by DECL_CONSTANT), and static strings.
|
||||
|
||||
Static Strings
|
||||
--------------
|
||||
|
||||
To reduce bandwidth the data dictionary also contains a set of static
|
||||
strings known to the micro-controller. This is useful when sending
|
||||
messages from micro-controller to host. For example, if the
|
||||
micro-controller were to run:
|
||||
|
||||
```
|
||||
shutdown("Unable to handle command");
|
||||
```
|
||||
|
||||
The error message would be encoded and sent using a single VLQ. The
|
||||
host uses the data dictionary to resolve VLQ encoded static string ids
|
||||
to their associated human-readable strings.
|
||||
|
||||
Message flow
|
||||
============
|
||||
|
||||
Message commands sent from host to micro-controller are intended to be
|
||||
error-free. The micro-controller will check the CRC and sequence
|
||||
numbers in each message block to ensure the commands are accurate and
|
||||
in-order. The micro-controller always processes message blocks
|
||||
in-order - should it receive a block out-of-order it will discard it
|
||||
and any other out-of-order blocks until it receives blocks with the
|
||||
correct sequencing.
|
||||
|
||||
The low-level host code implements an automatic retransmission system
|
||||
for lost and corrupt message blocks sent to the micro-controller. To
|
||||
facilitate this, the micro-controller transmits an "ack message block"
|
||||
after each successfully received message block. The host schedules a
|
||||
timeout after sending each block and it will retransmit should the
|
||||
timeout expire without receiving a corresponding "ack". In addition,
|
||||
if the micro-controller detects a corrupt or out-of-order block it may
|
||||
transmit a "nak message block" to facilitate fast retransmission.
|
||||
|
||||
An "ack" is a message block with empty content (ie, a 5 byte message
|
||||
block) and a sequence number greater than the last received host
|
||||
sequence number. A "nak" is a message block with empty content and a
|
||||
sequence number less than the last received host sequence number.
|
||||
|
||||
The protocol facilitates a "window" transmission system so that the
|
||||
host can have many outstanding message blocks in-flight at a
|
||||
time. (This is in addition to the many commands that may be present in
|
||||
a given message block.) This allows maximum bandwidth utilization even
|
||||
in the event of transmission latency. The timeout, retransmit,
|
||||
windowing, and ack mechanism are inspired by similar mechanisms in
|
||||
[TCP](https://en.wikipedia.org/wiki/Transmission_Control_Protocol).
|
||||
|
||||
In the other direction, message blocks sent from micro-controller to
|
||||
host are designed to be error-free, but they do not have assured
|
||||
transmission. (Responses should not be corrupt, but they may go
|
||||
missing.) This is done to keep the implementation in the
|
||||
micro-controller simple. There is no automatic retransmission system
|
||||
for responses - the high-level code is expected to be capable of
|
||||
handling an occasional missing response (usually by re-requesting the
|
||||
content or setting up a recurring schedule of response
|
||||
transmission). The sequence number field in message blocks sent to the
|
||||
host is always one greater than the last received sequence number of
|
||||
message blocks received from the host. It is not used to track
|
||||
sequences of response message blocks.
|
||||
2
docs/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Welcome to the Klipper documentation. The
|
||||
[overview document](Overview.md) is a good starting point.
|
||||
78
docs/Releases.md
Normal file
@@ -0,0 +1,78 @@
|
||||
History of Klipper releases. Please see
|
||||
[installation](Installation.md) for information on installing Klipper.
|
||||
|
||||
Klipper 0.5.0
|
||||
=============
|
||||
|
||||
Available on 20171025. Major changes in this release:
|
||||
|
||||
* Support for printers with multiple extruders.
|
||||
* Initial support for running on the Beaglebone PRU. Initial support
|
||||
for the Replicape board.
|
||||
* Initial support for running the micro-controller code in a real-time
|
||||
Linux process.
|
||||
* Support for multiple micro-controllers. (For example, one could
|
||||
control an extruder with one micro-controller and the rest of the
|
||||
printer with another.) Software clock synchronization is implemented
|
||||
to coordinate actions between micro-controllers.
|
||||
* Stepper performance improvements (20Mhz AVRs up to 189K steps per
|
||||
second).
|
||||
* Support for controlling servos and support for defining nozzle
|
||||
cooling fans.
|
||||
* Several bug fixes and code cleanups
|
||||
|
||||
Klipper 0.4.0
|
||||
=============
|
||||
|
||||
Available on 20170503. Major changes in this release:
|
||||
|
||||
* Improved installation on Raspberry Pi machines. Most of the install
|
||||
is now scripted.
|
||||
* Support for corexy kinematics
|
||||
* Documentation updates: New Kinematics document, new Pressure Advance
|
||||
tuning guide, new example config files, and more
|
||||
* Stepper performance improvements (20Mhz AVRs over 175K steps per
|
||||
second, Arduino Due over 460K)
|
||||
* Support for automatic micro-controller resets. Support for resets
|
||||
via toggling USB power on Raspberry Pi.
|
||||
* The pressure advance algorithm now works with look-ahead to reduce
|
||||
pressure changes during cornering.
|
||||
* Support for limiting the top speed of short zigzag moves
|
||||
* Support for AD595 sensors
|
||||
* Several bug fixes and code cleanups
|
||||
|
||||
Klipper 0.3.0
|
||||
=============
|
||||
|
||||
Available on 20161223. Major changes in this release:
|
||||
|
||||
* Improved documentation
|
||||
* Support for robots with delta kinematics
|
||||
* Support for Arduino Due micro-controller (ARM cortex-M3)
|
||||
* Support for USB based AVR micro-controllers
|
||||
* Support for "pressure advance" algorithm - it reduces ooze during
|
||||
prints.
|
||||
* New "stepper phased based endstop" feature - enables higher
|
||||
precision on endstop homing.
|
||||
* Support for "extended g-code" commands such as "help", "restart",
|
||||
and "status".
|
||||
* Support for reloading the Klipper config and restarting the host
|
||||
software by issuing a "restart" command from the terminal.
|
||||
* Stepper performance improvements (20Mhz AVRs up to 158K steps per
|
||||
second).
|
||||
* Improved error reporting. Most errors now shown via the terminal
|
||||
along with help on how to resolve.
|
||||
* Several bug fixes and code cleanups
|
||||
|
||||
Klipper 0.2.0
|
||||
=============
|
||||
|
||||
Initial release of Klipper. Available on 20160525. Major features
|
||||
available in the initial release include:
|
||||
|
||||
* Basic support for cartesian printers (steppers, extruder, heated
|
||||
bed, cooling fan).
|
||||
* Support for common g-code commands. Support for interfacing with
|
||||
OctoPrint.
|
||||
* Acceleration and lookahead handling
|
||||
* Support for AVR micro-controllers via standard serial ports
|
||||
92
docs/Todo.md
Normal file
@@ -0,0 +1,92 @@
|
||||
There are several features still to be implemented in Klipper. In no
|
||||
particular order:
|
||||
|
||||
Host user interaction
|
||||
=====================
|
||||
|
||||
* See if there is a better way to report errors. Octoprint sometimes
|
||||
doesn't highlight an error (one has to look in the terminal tab to
|
||||
find the error) and errors written to the log can be non-obvious to
|
||||
a user.
|
||||
|
||||
* Improve gcode interface:
|
||||
|
||||
* Provide a better way to handle print nozzle z offsets. The M206
|
||||
command is cryptic to use and it is too easy to set the value
|
||||
incorrectly or to forget to set it.
|
||||
|
||||
* Provide a way to temporarily disable endstop checks so that a user
|
||||
can issue commands that potentially move the head past
|
||||
position_min/position_max.
|
||||
|
||||
* Improve logging:
|
||||
|
||||
* Possibly collate and report the statistics messages in the log in a
|
||||
more friendly way.
|
||||
|
||||
* Possibly support a mechanism for the host to limit maximum velocity
|
||||
so that the mcu is never requested to step at a higher rate than it
|
||||
can support.
|
||||
|
||||
Safety features
|
||||
===============
|
||||
|
||||
* Support loading a valid step range into the micro-controller
|
||||
software after homing. This would provide a sanity check in the
|
||||
micro-controller that would reduce the risk of the host commanding a
|
||||
stepper motor past its valid step range. To maintain high
|
||||
efficiency, the micro-controller would only need to check
|
||||
periodically (eg, every 100ms) that the stepper is in range.
|
||||
|
||||
* Possibly support periodically querying the endstop switches and use
|
||||
multiple step ranges depending on the switch state. This would
|
||||
enable runtime endstop detection. (However, it's unclear if runtime
|
||||
endstop detection is a good idea because of spurious signals caused
|
||||
by electrical noise.)
|
||||
|
||||
* Support validating that heaters are heating at expected rates. This
|
||||
can be useful to detect a sensor failure (eg, thermistor short) that
|
||||
could otherwise cause the PID to command excessive heating.
|
||||
|
||||
Testing features
|
||||
================
|
||||
|
||||
* Complete the host based simulator. It's possible to compile the
|
||||
micro-controller for a "host simulator", but that simulator doesn't
|
||||
do anything currently. It would be useful to expand the code to
|
||||
support more error checks, kinematic simulations, and improved
|
||||
logging.
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
* Add documentation describing how to perform bed-leveling accurately
|
||||
in Klipper. Improve description of stepper phase based bed leveling.
|
||||
|
||||
Hardware features
|
||||
=================
|
||||
|
||||
* Port to additional micro-controller architectures:
|
||||
* Smoothieboard / NXP LPC1769 (ARM cortex-M3)
|
||||
|
||||
* Support for additional kinematics: scara, etc.
|
||||
|
||||
* Support shared motor enable GPIO lines.
|
||||
|
||||
* Support for bed-level probes.
|
||||
|
||||
* Possible support for touch panels attached to the micro-controller.
|
||||
(In general, it would be preferable to attach touch panels to the
|
||||
host system and have octoprint interact with the panel directly, but
|
||||
it would also be useful to handle panels already hardwired to the
|
||||
micro-controller.)
|
||||
|
||||
Misc features
|
||||
=============
|
||||
|
||||
* Possibly support a "feed forward PID" that takes into account the
|
||||
amount of plastic being extruded. If the extrude rate changes
|
||||
significantly during a print it can cause heating bumps that the PID
|
||||
overcompensates for. The temperature change due to the extrusion
|
||||
rate could be modeled to eliminate these bumps and make the
|
||||
extrusion temperature more consistent.
|
||||
94
docs/beaglebone.md
Normal file
@@ -0,0 +1,94 @@
|
||||
This document describes the process of running Klipper on a Beaglebone
|
||||
PRU.
|
||||
|
||||
Building an OS image
|
||||
====================
|
||||
|
||||
Start by installing the
|
||||
[latest Jessie IoT](https://beagleboard.org/latest-images) image
|
||||
(2017-03-19 or later). One may run the image from either a micro-SD
|
||||
card or from builtin eMMC. If using the eMMC, install it to eMMC now
|
||||
by following the instructions from the above link.
|
||||
|
||||
Then ssh into the beaglebone machine (ssh debian@beaglebone --
|
||||
password is "temppwd") and install Klipper by running the following
|
||||
commands:
|
||||
```
|
||||
git clone https://github.com/KevinOConnor/klipper
|
||||
./klipper/scripts/install-beaglebone.sh
|
||||
```
|
||||
|
||||
Install Octoprint
|
||||
=================
|
||||
|
||||
One may then install Octoprint:
|
||||
```
|
||||
git clone https://github.com/foosel/OctoPrint.git
|
||||
cd OctoPrint/
|
||||
virtualenv venv
|
||||
./venv/bin/python setup.py install
|
||||
```
|
||||
|
||||
And setup OctoPrint to start at bootup:
|
||||
```
|
||||
sudo cp ~/OctoPrint/scripts/octoprint.init /etc/init.d/octoprint
|
||||
sudo chmod +x /etc/init.d/octoprint
|
||||
sudo cp ~/OctoPrint/scripts/octoprint.default /etc/default/octoprint
|
||||
sudo update-rc.d octoprint defaults
|
||||
```
|
||||
|
||||
It is necessary to modify OctoPrint's **/etc/default/octoprint**
|
||||
configuration file. One must change the OCTOPRINT_USER user to
|
||||
"debian", change NICELEVEL to 0, uncomment the BASEDIR, CONFIGFILE,
|
||||
and DAEMON settings and change the references from "/home/pi/" to
|
||||
"/home/debian/":
|
||||
```
|
||||
sudo nano /etc/default/octoprint
|
||||
```
|
||||
|
||||
Then start the Octoprint service:
|
||||
```
|
||||
sudo systemctl start octoprint
|
||||
```
|
||||
|
||||
Make sure the octoprint web server is accessible - it should be at:
|
||||
[http://beaglebone:5000/](http://beaglebone:5000/)
|
||||
|
||||
|
||||
Building the micro-controller code
|
||||
==================================
|
||||
|
||||
To compile the Klipper micro-controller code, start by configuring it
|
||||
for the "Beaglebone PRU":
|
||||
```
|
||||
cd ~/klipper/
|
||||
make menuconfig
|
||||
```
|
||||
|
||||
To build and install the new micro-controller code, run:
|
||||
```
|
||||
sudo service klipper stop
|
||||
make flash
|
||||
sudo service klipper start
|
||||
```
|
||||
|
||||
For the Replicape, it is also necessary to compile and install the
|
||||
micro-controller code for a Linux host process. Run "make menuconfig"
|
||||
a second time and configure it for a "Linux process":
|
||||
```
|
||||
make menuconfig
|
||||
```
|
||||
|
||||
Then install this micro-controller code as well:
|
||||
```
|
||||
sudo service klipper stop
|
||||
make flash
|
||||
sudo service klipper start
|
||||
```
|
||||
|
||||
Remaining configuration
|
||||
=======================
|
||||
|
||||
Complete the installation by configuring Klipper and Octoprint
|
||||
following the instructions in
|
||||
[the main installation document](Installation.md#configuring-klipper).
|
||||
BIN
docs/img/corner-blob.jpg
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
docs/img/corner-dimple.jpg
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
docs/img/corner-good.jpg
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
184
docs/img/corner.svg
Normal file
@@ -0,0 +1,184 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="54.904114mm"
|
||||
height="6.0860338mm"
|
||||
viewBox="0 0 194.54213 21.564687"
|
||||
id="svg3506"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="corner.svg">
|
||||
<defs
|
||||
id="defs3508">
|
||||
<marker
|
||||
inkscape:stockid="DiamondL"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="DiamondL"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4399"
|
||||
d="M 0,-7.0710768 -7.0710894,0 0,7.0710589 7.0710462,0 0,-7.0710768 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="scale(0.8,0.8)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Lend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow2Lend"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4341"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker4596"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4598"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4329"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend-1"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4329-1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2.49"
|
||||
inkscape:cx="95.030833"
|
||||
inkscape:cy="-0.17370789"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showborder="false"
|
||||
inkscape:window-width="1068"
|
||||
inkscape:window-height="478"
|
||||
inkscape:window-x="378"
|
||||
inkscape:window-y="113"
|
||||
inkscape:window-maximized="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid6021"
|
||||
spacingx="9.9999997"
|
||||
spacingy="10.000001"
|
||||
originx="0.89299989"
|
||||
originy="-30.954583" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata3511">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-253.40821,-436.43703)">
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend)"
|
||||
d="m 345.38554,440.31401 96.88541,12.96764"
|
||||
id="path3514"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend-1)"
|
||||
d="m 253.63788,454.62572 89.78715,-13.91164"
|
||||
id="path3514-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="189.09824"
|
||||
y="482.48389"
|
||||
id="text12656-9"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(0.98759291,-0.15703579,0.15703579,0.98759291,0,0)"
|
||||
inkscape:transform-center-x="1.3563414"
|
||||
inkscape:transform-center-y="-5.7099754"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5552"
|
||||
x="189.09824"
|
||||
y="482.48389">move 1</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="427.95532"
|
||||
y="379.5321"
|
||||
id="text12656-9-8"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(0.98949457,0.14457001,-0.14457001,0.98949457,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5554"
|
||||
x="427.95532"
|
||||
y="379.5321">move 2</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.7 KiB |
BIN
docs/img/corner.svg.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
273
docs/img/delta-tower.svg
Normal file
@@ -0,0 +1,273 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="97.22496mm"
|
||||
height="32.550285mm"
|
||||
viewBox="0 0 344.49789 115.33566"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="delta-tower.svg">
|
||||
<defs
|
||||
id="defs4">
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker6618"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Mend">
|
||||
<path
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
id="path6620"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="marker6500"
|
||||
style="overflow:visible;"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path6502"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1;fill:#4b4b4b;fill-opacity:1"
|
||||
transform="scale(0.4) rotate(180) translate(10,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible;"
|
||||
id="marker6082"
|
||||
refX="0.0"
|
||||
refY="0.0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
transform="scale(0.4) rotate(180) translate(10,0)"
|
||||
style="fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1;fill:#4b4b4b;fill-opacity:1"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
id="path6084" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible;"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
id="path5747"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1;fill:#4b4b4b;fill-opacity:1"
|
||||
transform="scale(0.4) rotate(180) translate(10,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Mstart"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path5744"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1;fill:#4b4b4b;fill-opacity:1"
|
||||
transform="scale(0.4) translate(10,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend-1"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4329-1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker6082-9"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
id="path6084-2" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.75"
|
||||
inkscape:cx="172.24895"
|
||||
inkscape:cy="45.708959"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="928"
|
||||
inkscape:window-height="628"
|
||||
inkscape:window-x="162"
|
||||
inkscape:window-y="50"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showborder="false"
|
||||
inkscape:snap-global="false"
|
||||
showguides="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3436" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-135.22429,-249.96955)">
|
||||
<ellipse
|
||||
style="fill:#4d4d4d;stroke:#4b4b4b;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:2, 1, 0.5, 1;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path4255"
|
||||
cx="353.79568"
|
||||
cy="327.87662"
|
||||
rx="4.2857141"
|
||||
ry="4.8571429" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000006;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend)"
|
||||
d="M 181.50998,381.87664 359.22427,275.01949"
|
||||
id="path5510"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="371.22427"
|
||||
y="354.44806"
|
||||
id="text6058"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6060"
|
||||
x="371.22427"
|
||||
y="354.44806">stepper</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="371.22427"
|
||||
y="366.94806"
|
||||
id="tspan9337">tower</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="166.65283"
|
||||
y="304.16235"
|
||||
id="text6062"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6064"
|
||||
x="166.65283"
|
||||
y="304.16235">line of movement</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:10.0000006px;line-height:125%;font-family:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;-inkscape-font-specification:'DejaVu Sans, Normal';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;"
|
||||
x="252.93855"
|
||||
y="384.16235"
|
||||
id="text6066"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6068"
|
||||
x="252.93855"
|
||||
y="384.16235">move</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000006;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#marker6618)"
|
||||
d="m 382.65284,344.73378 c -0.19273,-13.52091 -9.87887,-14.83602 -20.57143,-14.85715"
|
||||
id="path6070"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker6500)"
|
||||
d="m 254.65284,374.44806 c 3.39239,-12.86009 -2.06023,-20.09154 -15.42857,-22.28571"
|
||||
id="path6072"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6082)"
|
||||
d="m 257.50997,296.16234 c 31.05376,-3.13332 32.38959,-1.23784 42.28572,10.28572"
|
||||
id="path6074"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend-1)"
|
||||
d="m 219.61431,358.80126 57.78715,-34.48307"
|
||||
id="path3514-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:0.50000003;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="m 351.22427,323.59092 -20.57143,-32"
|
||||
id="path3358"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="244.36713"
|
||||
y="257.30521"
|
||||
id="text4460"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4462"
|
||||
x="244.36713"
|
||||
y="257.30521">virtual tower</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="244.36713"
|
||||
y="269.80521"
|
||||
id="tspan5867">location</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6082-9)"
|
||||
d="m 310.90661,257.14111 c 21.29088,8.40268 18.35244,16.28958 20.57143,29.7143"
|
||||
id="path6074-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
BIN
docs/img/delta-tower.svg.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
208
docs/img/lookahead-slow.svg
Normal file
@@ -0,0 +1,208 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="97.22496mm"
|
||||
height="32.550285mm"
|
||||
viewBox="0 0 344.49789 115.33566"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="lookahead-slow.svg"
|
||||
inkscape:export-filename="/home/kevin/src/reprap/firmware/klipper/docs/img/lookahead-slow.svg.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs4">
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend-1"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4329-1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path4329"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.15"
|
||||
inkscape:cx="3.4198125"
|
||||
inkscape:cy="101.26451"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1091"
|
||||
inkscape:window-height="588"
|
||||
inkscape:window-x="149"
|
||||
inkscape:window-y="422"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showborder="false"
|
||||
inkscape:snap-global="false"
|
||||
showguides="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3436" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-135.22429,-249.96955)">
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||
id="path3347"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="434.04257"
|
||||
y="365.1282"
|
||||
id="text3349"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3351"
|
||||
x="434.04257"
|
||||
y="365.1282">time</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-313.86618"
|
||||
y="140.27856"
|
||||
id="text3353"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3355"
|
||||
x="-313.86618"
|
||||
y="140.27856">velocity</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 -5.31915,8.51063"
|
||||
id="path3359"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.62366331px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 179.63013,351.45141 16.05677,-60.94328 43.25999,0 16.53759,47.11348"
|
||||
id="path3361"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.7558428px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 254.72406,337.27551 22.65101,-77.77178 43.89917,0 24.69858,91.73948"
|
||||
id="path3361-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="195.45749"
|
||||
y="286.52051"
|
||||
id="text12656-9"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan7078"
|
||||
x="195.45749"
|
||||
y="286.52051">move A</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="280.5639"
|
||||
y="254.60564"
|
||||
id="text12656-9-3"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan7080"
|
||||
x="280.5639"
|
||||
y="254.60564">move B</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend)"
|
||||
d="m 74.333855,283.02668 -147.83244,52.19984"
|
||||
id="path3514"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend-1)"
|
||||
d="m -79.633985,251.6122 154.13499,31.81455"
|
||||
id="path3514-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="36.7374"
|
||||
y="252.31848"
|
||||
id="text12656-9-1"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(0.96753827,0.25272454,-0.25272454,0.96753827,0,0)"
|
||||
inkscape:transform-center-x="-0.91382951"
|
||||
inkscape:transform-center-y="-4.9145266"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan7074"
|
||||
x="36.7374"
|
||||
y="252.31848">move A</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-126.26086"
|
||||
y="304.35226"
|
||||
id="text12656-9-8"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(0.93839918,-0.34555314,0.34555314,0.93839918,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan7076"
|
||||
x="-126.26086"
|
||||
y="304.35226">move B</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.2 KiB |
BIN
docs/img/lookahead-slow.svg.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
136
docs/img/lookahead.svg
Normal file
@@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="97.22496mm"
|
||||
height="32.550285mm"
|
||||
viewBox="0 0 344.49789 115.33566"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="lookahead.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.94"
|
||||
inkscape:cx="116.54041"
|
||||
inkscape:cy="45.708959"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1091"
|
||||
inkscape:window-height="588"
|
||||
inkscape:window-x="149"
|
||||
inkscape:window-y="422"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showborder="false"
|
||||
inkscape:snap-global="false"
|
||||
showguides="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3436" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-135.22429,-249.96955)">
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||
id="path3347"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="434.04257"
|
||||
y="365.1282"
|
||||
id="text3349"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3351"
|
||||
x="434.04257"
|
||||
y="365.1282">time</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-313.86618"
|
||||
y="140.27856"
|
||||
id="text3353"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3355"
|
||||
x="-313.86618"
|
||||
y="140.27856">velocity</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 -5.31915,8.51063"
|
||||
id="path3359"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.62366331px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 179.63013,351.45141 16.05677,-60.94328 61.3451,0 4.83546,8.81561"
|
||||
id="path3361"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.7558428px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 261.70791,300.17937 13.5395,-40.67564 59.85662,0 24.69858,91.73948"
|
||||
id="path3361-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="200.77664"
|
||||
y="286.52051"
|
||||
id="text12656-9"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5532"
|
||||
x="200.77664"
|
||||
y="286.52051">move 1</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="280.5639"
|
||||
y="255.66946"
|
||||
id="text12656-9-3"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5534"
|
||||
x="280.5639"
|
||||
y="255.66946">move 2</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.8 KiB |
BIN
docs/img/lookahead.svg.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
207
docs/img/ooze.svg
Normal file
@@ -0,0 +1,207 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="98.140816mm"
|
||||
height="63.537022mm"
|
||||
viewBox="0 0 347.74305 225.13119"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="ooze.svg"
|
||||
inkscape:export-filename="/home/kevin/src/reprap/firmware/klipper/docs/img/ooze.svg.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.94"
|
||||
inkscape:cx="199.68782"
|
||||
inkscape:cy="58.510649"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1091"
|
||||
inkscape:window-height="588"
|
||||
inkscape:window-x="266"
|
||||
inkscape:window-y="106"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showborder="false"
|
||||
inkscape:snap-global="false"
|
||||
showguides="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3436"
|
||||
originx="-1.5695746e-05"
|
||||
originy="109.79552" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-135.22431,-249.96955)">
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||
id="path3347"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-346.84067"
|
||||
y="139.75046"
|
||||
id="text3353"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12733"
|
||||
x="-346.84067"
|
||||
y="139.75046">head velocity</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 -5.31915,8.51063"
|
||||
id="path3359"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 179.63013,351.45141 16.05677,-60.94328 120.91957,-1.06383 16.53759,62.00711"
|
||||
id="path3361"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.78742969px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 332.99641,351.24986 16.72764,-63.00287 133.24331,0"
|
||||
id="path3361-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="200.11789"
|
||||
y="284.45413"
|
||||
id="text12656"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12658"
|
||||
x="200.11789"
|
||||
y="284.45413">extrude move</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="356.50089"
|
||||
y="283.39032"
|
||||
id="text12660"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12662"
|
||||
x="356.50089"
|
||||
y="283.39032">non-extrude move</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 152.72419,471.73218 1.06383,102.12766 327.12768,-0.53192 -7.97872,5.85107"
|
||||
id="path3347-0"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="436.76678"
|
||||
y="586.62585"
|
||||
id="text3349-3"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3351-4"
|
||||
x="436.76678"
|
||||
y="586.62585">time</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-551.11292"
|
||||
y="125.37186"
|
||||
id="text3353-0"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4197"
|
||||
x="-551.11292"
|
||||
y="125.37186">actual</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4199"
|
||||
x="-551.11292"
|
||||
y="140.99686">filament</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 152.72419,471.73218 -5.31915,8.51063"
|
||||
id="path3359-9"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 182.35432,572.94905 c 17.46262,-43.80215 52.67413,-56.54375 92.65253,-60.94329 l 48.57915,-1.06383 c 24.916,55.4715 110.00504,59.23318 151.64398,62.00712"
|
||||
id="path3361-1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150.87843,360.66993 1.06383,102.12766 327.12768,-0.53192 -7.97872,5.85107"
|
||||
id="path3347-8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-444.27307"
|
||||
y="124.17301"
|
||||
id="text3353-6"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4193"
|
||||
x="-444.27307"
|
||||
y="124.17301">desired</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4195"
|
||||
x="-444.27307"
|
||||
y="139.79802">filament</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150.87843,360.66993 -5.31915,8.51063"
|
||||
id="path3359-8"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 180.50856,461.8868 16.05678,-60.94329 120.91958,-1.06383 16.53759,62.00712"
|
||||
id="path3361-4"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.8 KiB |
BIN
docs/img/ooze.svg.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
207
docs/img/pressure-advance.svg
Normal file
@@ -0,0 +1,207 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="102.61139mm"
|
||||
height="99.266594mm"
|
||||
viewBox="0 0 363.58366 351.73204"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="pressure-advance.svg"
|
||||
inkscape:export-filename="/home/kevin/src/reprap/firmware/klipper/docs/img/pressure-advance.svg.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.97968464"
|
||||
inkscape:cx="147.06528"
|
||||
inkscape:cy="169.55487"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1091"
|
||||
inkscape:window-height="588"
|
||||
inkscape:window-x="419"
|
||||
inkscape:window-y="273"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showborder="false"
|
||||
inkscape:snap-global="false"
|
||||
showguides="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3436"
|
||||
originx="17.089787"
|
||||
originy="126.61899" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-118.13451,-140.19216)">
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150.47693,249.82417 0.58688,123.9666 m 0,-21.42857 327.12765,-0.53192 -7.97871,5.85107"
|
||||
id="path3347"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-334.86746"
|
||||
y="122.91875"
|
||||
id="text3353"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12816"
|
||||
x="-334.86746"
|
||||
y="122.91875">extruder</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12818"
|
||||
x="-334.86746"
|
||||
y="138.54375">velocity</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 -5.31915,8.51063"
|
||||
id="path3359"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 316.60647,311.78473 16.53759,62.00711 m -154.57776,-52.12767 16.05677,-60.94328 1.06383,29.78724 m 0,0 120.91957,-1.06383 0,22.34043"
|
||||
id="path3361"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 148.75077,140.45716 1.06383,102.12766 327.12769,-0.53192 -7.97872,5.85107"
|
||||
id="path3347-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-237.05733"
|
||||
y="140.25932"
|
||||
id="text3353-2"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12733-6"
|
||||
x="-237.05733"
|
||||
y="140.25932">head velocity</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 148.75077,140.45716 -5.31915,8.51063"
|
||||
id="path3359-7"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 178.3809,241.67403 16.05679,-60.94329 120.91958,-1.06383 16.53759,62.00712"
|
||||
id="path3361-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.78742969px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 331.74721,241.47248 16.72764,-63.00288 133.24332,0"
|
||||
id="path3361-7-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="198.86868"
|
||||
y="174.67674"
|
||||
id="text12656-9"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12658-8"
|
||||
x="198.86868"
|
||||
y="174.67674">extrude move</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="355.25165"
|
||||
y="173.61293"
|
||||
id="text12660-7"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12662-2"
|
||||
x="355.25165"
|
||||
y="173.61293">non-extrude move</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 151.94226,384.0742 1.06383,102.12766 327.12769,-0.53192 -7.97872,5.85107"
|
||||
id="path3347-2"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-467.65732"
|
||||
y="122.73453"
|
||||
id="text3353-1"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12868"
|
||||
x="-467.65732"
|
||||
y="122.73453">extruder</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12870"
|
||||
x="-467.65732"
|
||||
y="138.35953">pressure</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 151.94226,384.0742 -5.31915,8.51063"
|
||||
id="path3359-5"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 181.57239,485.29107 16.05679,-60.94329 120.91958,-1.06383 16.53759,62.00712"
|
||||
id="path3361-9"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="438.03586"
|
||||
y="499.53384"
|
||||
id="text3349"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3351"
|
||||
x="438.03586"
|
||||
y="499.53384">time</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.8 KiB |
BIN
docs/img/pressure-advance.svg.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
180
docs/img/pressure-cornering.svg
Normal file
@@ -0,0 +1,180 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="102.04809mm"
|
||||
height="61.494076mm"
|
||||
viewBox="0 0 361.58771 217.8924"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="pressure-cornering.svg"
|
||||
inkscape:export-filename="/home/kevin/src/reprap/firmware/klipper/docs/img/pressure-cornering.svg.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.98"
|
||||
inkscape:cx="110.74341"
|
||||
inkscape:cy="35.715236"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1091"
|
||||
inkscape:window-height="588"
|
||||
inkscape:window-x="656"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showborder="false"
|
||||
inkscape:snap-global="false"
|
||||
showguides="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3436"
|
||||
originx="17.089805"
|
||||
originy="-7.2206491" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-118.13449,-140.19216)">
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||
id="path3347"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-334.86746"
|
||||
y="122.91875"
|
||||
id="text3353"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12816"
|
||||
x="-334.86746"
|
||||
y="122.91875">extruder</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12818"
|
||||
x="-334.86746"
|
||||
y="138.54375">velocity</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 -5.31915,8.51063"
|
||||
id="path3359"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 178.5663,321.66417 16.05677,-60.94328 1.06383,29.78724 m 0,0 117.21969,-0.77616 5.99519,7.3871 5.9952,-6.89861 131.50541,-0.77616"
|
||||
id="path3361"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 148.75077,140.45716 1.06383,102.12766 327.12769,-0.53192 -7.97872,5.85107"
|
||||
id="path3347-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-237.05733"
|
||||
y="140.25932"
|
||||
id="text3353-2"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12733-6"
|
||||
x="-237.05733"
|
||||
y="140.25932">head velocity</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 148.75077,140.45716 -5.31915,8.51063"
|
||||
id="path3359-7"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 178.3809,241.67403 16.05679,-60.94329 120.91958,-1.06383 4.29269,10.98671"
|
||||
id="path3361-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 319.50231,193.5133 4.48274,-15.0437 133.24332,0"
|
||||
id="path3361-7-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="198.86868"
|
||||
y="174.67674"
|
||||
id="text12656-9"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12891"
|
||||
x="198.86868"
|
||||
y="174.67674">first extrude</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="355.25165"
|
||||
y="173.61293"
|
||||
id="text12660-7"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12893"
|
||||
x="355.25165"
|
||||
y="173.61293">second extrude</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4, 2, 1, 2;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 314.05288,288.86296 0,17.34694 5.10204,17.34694 -1.02041,-48.97959 7.14286,-17.34694 0,31.63265"
|
||||
id="path12895"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="435.80841"
|
||||
y="366.8262"
|
||||
id="text3349"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3351"
|
||||
x="435.80841"
|
||||
y="366.8262">time</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.4 KiB |
BIN
docs/img/pressure-cornering.svg.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
132
docs/img/smoothed.svg
Normal file
@@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="97.22496mm"
|
||||
height="32.550285mm"
|
||||
viewBox="0 0 344.49789 115.33566"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="smoothed.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.75"
|
||||
inkscape:cx="167.32577"
|
||||
inkscape:cy="45.708959"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="840"
|
||||
inkscape:window-height="628"
|
||||
inkscape:window-x="162"
|
||||
inkscape:window-y="50"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showborder="false"
|
||||
inkscape:snap-global="false"
|
||||
showguides="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3436" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-135.22429,-249.96955)">
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||
id="path3347"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="434.04257"
|
||||
y="365.1282"
|
||||
id="text3349"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3351"
|
||||
x="434.04257"
|
||||
y="365.1282">time</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-313.86618"
|
||||
y="140.27856"
|
||||
id="text3353"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3355"
|
||||
x="-313.86618"
|
||||
y="140.27856">velocity</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 -5.31915,8.51063"
|
||||
id="path3359"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 165.50998,351.59092 15.42857,-35.42857 35.71428,0 11.71429,36.57143"
|
||||
id="path3362"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.07142997px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 227.83578,352.85633 15.76217,-47.37239 22.00135,0 5.58242,17.6933"
|
||||
id="path3362-3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.21482575px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 271.35434,323.73296 11.15454,-30.54076 19.27119,-0.11152 8.73883,29.51288"
|
||||
id="path3362-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.01949775px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 311.26144,322.49329 11.63197,-21.06975 15.33656,0 13.51652,50.22357"
|
||||
id="path3362-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:2.00000012, 1.00000006, 0.50000003, 1.00000006;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 165.50999,351.59092 33.14285,-34.28571 29.14286,34.28571"
|
||||
id="path3426"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
BIN
docs/img/smoothed.svg.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
102
docs/img/trapezoid.svg
Normal file
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="97.22496mm"
|
||||
height="32.550285mm"
|
||||
viewBox="0 0 344.49789 115.33566"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="trapezoid.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.94"
|
||||
inkscape:cx="294.7319"
|
||||
inkscape:cy="45.708959"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1091"
|
||||
inkscape:window-height="588"
|
||||
inkscape:window-x="113"
|
||||
inkscape:window-y="31"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showborder="false" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-135.22429,-249.96955)">
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||
id="path3347"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="434.04257"
|
||||
y="365.1282"
|
||||
id="text3349"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3351"
|
||||
x="434.04257"
|
||||
y="365.1282">time</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-313.86618"
|
||||
y="140.27856"
|
||||
id="text3353"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3355"
|
||||
x="-313.86618"
|
||||
y="140.27856">velocity</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 -5.31915,8.51063"
|
||||
id="path3359"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 179.78723,351.29837 41.48937,-60.63829 158.51063,0 37.23405,60.63829"
|
||||
id="path3361"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
BIN
docs/img/trapezoid.svg.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
182
docs/img/trapezoids.svg
Normal file
@@ -0,0 +1,182 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="97.22496mm"
|
||||
height="32.550285mm"
|
||||
viewBox="0 0 344.49789 115.33566"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="trapezoids.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2.67"
|
||||
inkscape:cx="164.48301"
|
||||
inkscape:cy="76.011989"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1091"
|
||||
inkscape:window-height="588"
|
||||
inkscape:window-x="113"
|
||||
inkscape:window-y="31"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showborder="false"
|
||||
inkscape:snap-global="false"
|
||||
showguides="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3436" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-135.22429,-249.96955)">
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||
id="path3347"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="434.04257"
|
||||
y="365.1282"
|
||||
id="text3349"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3351"
|
||||
x="434.04257"
|
||||
y="365.1282">time</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-313.86618"
|
||||
y="140.27856"
|
||||
id="text3353"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3355"
|
||||
x="-313.86618"
|
||||
y="140.27856">velocity</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 -5.31915,8.51063"
|
||||
id="path3359"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.62366331px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 179.63013,351.45141 16.05677,-60.94328 61.3451,0 6.96312,32.21987"
|
||||
id="path3361"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.7558428px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 263.83557,321.45597 11.41184,-61.95224 59.85662,0 9.80496,29.88826"
|
||||
id="path3361-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.7558428px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 344.93248,289.80297 59.85663,0 15.12411,61.95225"
|
||||
id="path3361-7-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 263.86975,321.69491 0.37453,30.52957"
|
||||
id="path3412"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 345.25947,289.31929 0.14909,62.46104"
|
||||
id="path3414"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 222.45831,289.77329 -0.0598,62.07666"
|
||||
id="path3416"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:20.00000119px;line-height:125%;font-family:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;-inkscape-font-specification:'DejaVu Sans, Normal';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;"
|
||||
x="193.73491"
|
||||
y="338.70944"
|
||||
id="text3418"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3420"
|
||||
x="193.73491"
|
||||
y="338.70944">1</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20.00000191px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="236.28812"
|
||||
y="338.70947"
|
||||
id="text3422"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3434"
|
||||
x="236.28812"
|
||||
y="338.70947">2</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20.00000191px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="294.79874"
|
||||
y="335.51794"
|
||||
id="text3426"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3428"
|
||||
x="294.79874"
|
||||
y="335.51794">3</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:20.00000119px;line-height:125%;font-family:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;-inkscape-font-specification:'DejaVu Sans, Normal';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;"
|
||||
x="367.13916"
|
||||
y="337.6456"
|
||||
id="text3430"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3432"
|
||||
x="367.13916"
|
||||
y="337.6456">4</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.3 KiB |
BIN
docs/img/trapezoids.svg.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
241
docs/img/virtual-tower.svg
Normal file
@@ -0,0 +1,241 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64.619751mm"
|
||||
height="27.45583mm"
|
||||
viewBox="0 0 228.96762 97.284438"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="virtual-tower.svg">
|
||||
<defs
|
||||
id="defs4">
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker6618"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Mend">
|
||||
<path
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
id="path6620"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker6500"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path6502"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
id="path5747"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mstart"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mstart"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path5744"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(0.4,0,0,0.4,4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend-1"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4329-1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker6082"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
id="path6084" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.75"
|
||||
inkscape:cx="169.7719"
|
||||
inkscape:cy="-4.0565054"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="922"
|
||||
inkscape:window-height="628"
|
||||
inkscape:window-x="162"
|
||||
inkscape:window-y="50"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showborder="false"
|
||||
inkscape:snap-global="false"
|
||||
showguides="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3436"
|
||||
originx="-14.085234"
|
||||
originy="-95.286988" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-149.30952,-172.73378)">
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend)"
|
||||
d="m 176.36712,256.16235 200.00001,-0.57143"
|
||||
id="path5510"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-254.01012"
|
||||
y="369.20834"
|
||||
id="text6058"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01833576,-0.99983189,0.99983189,-0.01833576,0,0)"
|
||||
inkscape:transform-center-x="-8.0000002"
|
||||
inkscape:transform-center-y="12.571429"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan10365"
|
||||
x="-254.01012"
|
||||
y="369.20834">virtual tower</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="148.36713"
|
||||
y="269.87662"
|
||||
id="text6062"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6064"
|
||||
x="148.36713"
|
||||
y="269.87662">line of movement</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="237.50998"
|
||||
y="251.01949"
|
||||
id="text6066"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6068"
|
||||
x="237.50998"
|
||||
y="251.01949">move</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:7.00000048;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 358.08141,255.01949 0,-82.28571"
|
||||
id="path10351"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 220.36713,255.01949 357.50998,173.30521"
|
||||
id="path10373"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="200.36713"
|
||||
y="187.59093"
|
||||
id="text10375"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan10377"
|
||||
x="200.36713"
|
||||
y="187.59093">virtual arm</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6082)"
|
||||
d="m 261.76375,182.85539 c 22.73118,-0.70136 26.45506,3.7437 40.00001,18.28573"
|
||||
id="path6074"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend-1)"
|
||||
d="m 219.61431,255.37268 70.93001,0.37408"
|
||||
id="path3514-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.5 KiB |
BIN
docs/img/virtual-tower.svg.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
241
docs/img/xy+z-tower.svg
Normal file
@@ -0,0 +1,241 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64.619751mm"
|
||||
height="27.45583mm"
|
||||
viewBox="0 0 228.96762 97.284438"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="xy+z-tower.svg">
|
||||
<defs
|
||||
id="defs4">
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker6618"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Mend">
|
||||
<path
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
id="path6620"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker6500"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path6502"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
id="path5747"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mstart"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mstart"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path5744"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(0.4,0,0,0.4,4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend-1"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4329-1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="marker6082"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||
id="path6084" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.75"
|
||||
inkscape:cx="169.7719"
|
||||
inkscape:cy="-4.0565054"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="922"
|
||||
inkscape:window-height="628"
|
||||
inkscape:window-x="162"
|
||||
inkscape:window-y="50"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showborder="false"
|
||||
inkscape:snap-global="false"
|
||||
showguides="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3436"
|
||||
originx="-14.085234"
|
||||
originy="-95.286988" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-149.30952,-172.73378)">
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend)"
|
||||
d="m 176.36712,256.16235 200.00001,-0.57143"
|
||||
id="path5510"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-119.27526"
|
||||
y="434.37329"
|
||||
id="text6058"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(0.32454206,-0.94587127,0.94587127,0.32454206,0,0)"
|
||||
inkscape:transform-center-x="-3.9400734"
|
||||
inkscape:transform-center-y="14.789029"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan10365"
|
||||
x="-119.27526"
|
||||
y="434.37329">virtual tower</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="148.36713"
|
||||
y="269.87662"
|
||||
id="text6062"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6064"
|
||||
x="148.36713"
|
||||
y="269.87662">line of movement</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="237.50998"
|
||||
y="251.01949"
|
||||
id="text6066"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6068"
|
||||
x="237.50998"
|
||||
y="251.01949">move</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:7.00000048;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 354.70239,255.76769 28.12779,-77.32895"
|
||||
id="path10351"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 220.36713,255.01949 380.93855,178.44807"
|
||||
id="path10373"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="200.36713"
|
||||
y="187.59093"
|
||||
id="text10375"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan10377"
|
||||
x="200.36713"
|
||||
y="187.59093">virtual arm</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6082)"
|
||||
d="m 261.76375,182.85539 c 22.73118,-0.70136 26.45506,3.7437 40.00001,18.28573"
|
||||
id="path6074"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend-1)"
|
||||
d="m 219.61431,255.37268 70.93001,0.37408"
|
||||
id="path3514-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.5 KiB |
BIN
docs/img/xy+z-tower.svg.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
126
docs/img/zigzag.svg
Normal file
@@ -0,0 +1,126 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="97.22496mm"
|
||||
height="32.550285mm"
|
||||
viewBox="0 0 344.49789 115.33566"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="zigzag.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.75"
|
||||
inkscape:cx="167.32577"
|
||||
inkscape:cy="45.708959"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="840"
|
||||
inkscape:window-height="628"
|
||||
inkscape:window-x="160"
|
||||
inkscape:window-y="35"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showborder="false"
|
||||
inkscape:snap-global="false"
|
||||
showguides="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3436" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-135.22429,-249.96955)">
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||
id="path3347"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="434.04257"
|
||||
y="365.1282"
|
||||
id="text3349"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3351"
|
||||
x="434.04257"
|
||||
y="365.1282">time</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-313.86618"
|
||||
y="140.27856"
|
||||
id="text3353"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3355"
|
||||
x="-313.86618"
|
||||
y="140.27856">velocity</tspan></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 150,250.23455 -5.31915,8.51063"
|
||||
id="path3359"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 165.50998,351.59092 24.57143,-73.14286 23.42857,73.14286"
|
||||
id="path3362"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 214.08032,352.31321 24.57144,-73.14287 13.14286,43.42858"
|
||||
id="path3362-3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.09757805px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 252.42963,323.78006 17.64919,-60.34771 14.22362,59.20485"
|
||||
id="path3362-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 284.36604,322.59892 14.85715,-44.00001 3.71429,0 16.85715,73.14287"
|
||||
id="path3362-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
BIN
docs/img/zigzag.svg.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
16
docs/prints/square.scad
Normal file
@@ -0,0 +1,16 @@
|
||||
// Test square
|
||||
//
|
||||
// Generate STL using OpenSCAD:
|
||||
// openscad square.scad -o square.stl
|
||||
|
||||
square_width = 5;
|
||||
square_size = 60;
|
||||
square_height = 5;
|
||||
|
||||
difference() {
|
||||
cube([square_size, square_size, square_height]);
|
||||
translate([square_width, square_width, -1])
|
||||
cube([square_size-2*square_width, square_size-2*square_width, square_height+2]);
|
||||
translate([-.5, square_size/2 - 4, -1])
|
||||
cube([1, 2, square_height+2]);
|
||||
}
|
||||
338
docs/prints/square.stl
Normal file
@@ -0,0 +1,338 @@
|
||||
solid OpenSCAD_Model
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex 0 0 0
|
||||
vertex 0 26 5
|
||||
vertex 0 26 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 -0 0
|
||||
outer loop
|
||||
vertex 0 26 5
|
||||
vertex 0 0 0
|
||||
vertex 0 0 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex 0 28 0
|
||||
vertex 0 60 5
|
||||
vertex 0 60 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 -0 0
|
||||
outer loop
|
||||
vertex 0 60 5
|
||||
vertex 0 28 0
|
||||
vertex 0 28 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 60 60 5
|
||||
vertex 55 55 5
|
||||
vertex 60 0 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 60 60 5
|
||||
vertex 5 55 5
|
||||
vertex 55 55 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 5 55 5
|
||||
vertex 0.5 28 5
|
||||
vertex 5 5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex 0 60 5
|
||||
vertex 5 55 5
|
||||
vertex 60 60 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 0 28 5
|
||||
vertex 5 55 5
|
||||
vertex 0 60 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 5 55 5
|
||||
vertex 0 28 5
|
||||
vertex 0.5 28 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex 55 5 5
|
||||
vertex 60 0 5
|
||||
vertex 55 55 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex 5 5 5
|
||||
vertex 60 0 5
|
||||
vertex 55 5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex 0.5 26 5
|
||||
vertex 5 5 5
|
||||
vertex 0.5 28 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -0 0 1
|
||||
outer loop
|
||||
vertex 0 26 5
|
||||
vertex 5 5 5
|
||||
vertex 0.5 26 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 5 5 5
|
||||
vertex 0 0 5
|
||||
vertex 60 0 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 1
|
||||
outer loop
|
||||
vertex 0 0 5
|
||||
vertex 5 5 5
|
||||
vertex 0 26 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 -0 0
|
||||
outer loop
|
||||
vertex 60 0 5
|
||||
vertex 60 60 0
|
||||
vertex 60 60 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 60 60 0
|
||||
vertex 60 0 5
|
||||
vertex 60 0 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 -0
|
||||
outer loop
|
||||
vertex 60 60 0
|
||||
vertex 0 60 5
|
||||
vertex 60 60 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex 0 60 5
|
||||
vertex 60 60 0
|
||||
vertex 0 60 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex 60 0 0
|
||||
vertex 55 5 0
|
||||
vertex 60 60 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex 60 0 0
|
||||
vertex 5 5 0
|
||||
vertex 55 5 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex 0.5 28 0
|
||||
vertex 5 5 0
|
||||
vertex 0.5 26 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex 0 0 0
|
||||
vertex 5 5 0
|
||||
vertex 60 0 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex 0 26 0
|
||||
vertex 5 5 0
|
||||
vertex 0 0 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex 5 5 0
|
||||
vertex 0 26 0
|
||||
vertex 0.5 26 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex 55 55 0
|
||||
vertex 60 60 0
|
||||
vertex 55 5 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex 5 55 0
|
||||
vertex 60 60 0
|
||||
vertex 55 55 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex 5 5 0
|
||||
vertex 0.5 28 0
|
||||
vertex 5 55 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex 0 28 0
|
||||
vertex 5 55 0
|
||||
vertex 0.5 28 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex 5 55 0
|
||||
vertex 0 60 0
|
||||
vertex 60 60 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 0 -1
|
||||
outer loop
|
||||
vertex 0 60 0
|
||||
vertex 5 55 0
|
||||
vertex 0 28 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex 0 0 0
|
||||
vertex 60 0 5
|
||||
vertex 0 0 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 -0
|
||||
outer loop
|
||||
vertex 60 0 5
|
||||
vertex 0 0 0
|
||||
vertex 60 0 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 -0 0
|
||||
outer loop
|
||||
vertex 5 5 5
|
||||
vertex 5 55 0
|
||||
vertex 5 55 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 1 0 0
|
||||
outer loop
|
||||
vertex 5 55 0
|
||||
vertex 5 5 5
|
||||
vertex 5 5 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex 55 5 0
|
||||
vertex 55 55 5
|
||||
vertex 55 55 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 -0 0
|
||||
outer loop
|
||||
vertex 55 55 5
|
||||
vertex 55 5 0
|
||||
vertex 55 5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex 5 55 0
|
||||
vertex 55 55 5
|
||||
vertex 5 55 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 -0
|
||||
outer loop
|
||||
vertex 55 55 5
|
||||
vertex 5 55 0
|
||||
vertex 55 55 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 -0
|
||||
outer loop
|
||||
vertex 55 5 0
|
||||
vertex 5 5 5
|
||||
vertex 55 5 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex 5 5 5
|
||||
vertex 55 5 0
|
||||
vertex 5 5 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 0 0
|
||||
outer loop
|
||||
vertex 0.5 26 0
|
||||
vertex 0.5 28 5
|
||||
vertex 0.5 28 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal -1 -0 0
|
||||
outer loop
|
||||
vertex 0.5 28 5
|
||||
vertex 0.5 26 0
|
||||
vertex 0.5 26 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 0
|
||||
outer loop
|
||||
vertex 0 28 0
|
||||
vertex 0.5 28 5
|
||||
vertex 0 28 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 -1 -0
|
||||
outer loop
|
||||
vertex 0.5 28 5
|
||||
vertex 0 28 0
|
||||
vertex 0.5 28 0
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 -0
|
||||
outer loop
|
||||
vertex 0.5 26 0
|
||||
vertex 0 26 5
|
||||
vertex 0.5 26 5
|
||||
endloop
|
||||
endfacet
|
||||
facet normal 0 1 0
|
||||
outer loop
|
||||
vertex 0 26 5
|
||||
vertex 0.5 26 0
|
||||
vertex 0 26 0
|
||||
endloop
|
||||
endfacet
|
||||
endsolid OpenSCAD_Model
|
||||
135
klippy/cartesian.py
Normal file
@@ -0,0 +1,135 @@
|
||||
# Code for handling the kinematics of cartesian robots
|
||||
#
|
||||
# Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import logging
|
||||
import stepper, homing
|
||||
|
||||
StepList = (0, 1, 2)
|
||||
|
||||
class CartKinematics:
|
||||
def __init__(self, toolhead, printer, config):
|
||||
self.steppers = [stepper.PrinterHomingStepper(
|
||||
printer, config.getsection('stepper_' + n), n)
|
||||
for n in ['x', 'y', 'z']]
|
||||
max_velocity, max_accel = toolhead.get_max_velocity()
|
||||
self.max_z_velocity = config.getfloat(
|
||||
'max_z_velocity', max_velocity, above=0., maxval=max_velocity)
|
||||
self.max_z_accel = config.getfloat(
|
||||
'max_z_accel', max_accel, above=0., maxval=max_accel)
|
||||
self.need_motor_enable = True
|
||||
self.limits = [(1.0, -1.0)] * 3
|
||||
# Setup stepper max halt velocity
|
||||
max_halt_velocity = toolhead.get_max_axis_halt()
|
||||
self.steppers[0].set_max_jerk(max_halt_velocity, max_accel)
|
||||
self.steppers[1].set_max_jerk(max_halt_velocity, max_accel)
|
||||
self.steppers[2].set_max_jerk(
|
||||
min(max_halt_velocity, self.max_z_velocity), max_accel)
|
||||
def set_position(self, newpos):
|
||||
for i in StepList:
|
||||
self.steppers[i].mcu_stepper.set_position(newpos[i])
|
||||
def home(self, homing_state):
|
||||
# Each axis is homed independently and in order
|
||||
for axis in homing_state.get_axes():
|
||||
s = self.steppers[axis]
|
||||
self.limits[axis] = (s.position_min, s.position_max)
|
||||
# Determine moves
|
||||
if s.homing_positive_dir:
|
||||
pos = s.position_endstop - 1.5*(
|
||||
s.position_endstop - s.position_min)
|
||||
rpos = s.position_endstop - s.homing_retract_dist
|
||||
r2pos = rpos - s.homing_retract_dist
|
||||
else:
|
||||
pos = s.position_endstop + 1.5*(
|
||||
s.position_max - s.position_endstop)
|
||||
rpos = s.position_endstop + s.homing_retract_dist
|
||||
r2pos = rpos + s.homing_retract_dist
|
||||
# Initial homing
|
||||
homing_speed = s.get_homing_speed()
|
||||
homepos = [None, None, None, None]
|
||||
homepos[axis] = s.position_endstop
|
||||
coord = [None, None, None, None]
|
||||
coord[axis] = pos
|
||||
homing_state.home(list(coord), homepos, [s], homing_speed)
|
||||
# Retract
|
||||
coord[axis] = rpos
|
||||
homing_state.retract(list(coord), homing_speed)
|
||||
# Home again
|
||||
coord[axis] = r2pos
|
||||
homing_state.home(
|
||||
list(coord), homepos, [s], homing_speed/2.0, second_home=True)
|
||||
# Set final homed position
|
||||
coord[axis] = s.position_endstop + s.get_homed_offset()
|
||||
homing_state.set_homed_position(coord)
|
||||
def query_endstops(self, print_time, query_flags):
|
||||
return homing.query_endstops(print_time, query_flags, self.steppers)
|
||||
def motor_off(self, print_time):
|
||||
self.limits = [(1.0, -1.0)] * 3
|
||||
for stepper in self.steppers:
|
||||
stepper.motor_enable(print_time, 0)
|
||||
self.need_motor_enable = True
|
||||
def _check_motor_enable(self, print_time, move):
|
||||
need_motor_enable = False
|
||||
for i in StepList:
|
||||
if move.axes_d[i]:
|
||||
self.steppers[i].motor_enable(print_time, 1)
|
||||
need_motor_enable |= self.steppers[i].need_motor_enable
|
||||
self.need_motor_enable = need_motor_enable
|
||||
def _check_endstops(self, move):
|
||||
end_pos = move.end_pos
|
||||
for i in StepList:
|
||||
if (move.axes_d[i]
|
||||
and (end_pos[i] < self.limits[i][0]
|
||||
or end_pos[i] > self.limits[i][1])):
|
||||
if self.limits[i][0] > self.limits[i][1]:
|
||||
raise homing.EndstopMoveError(
|
||||
end_pos, "Must home axis first")
|
||||
raise homing.EndstopMoveError(end_pos)
|
||||
def check_move(self, move):
|
||||
limits = self.limits
|
||||
xpos, ypos = move.end_pos[:2]
|
||||
if (xpos < limits[0][0] or xpos > limits[0][1]
|
||||
or ypos < limits[1][0] or ypos > limits[1][1]):
|
||||
self._check_endstops(move)
|
||||
if not move.axes_d[2]:
|
||||
# Normal XY move - use defaults
|
||||
return
|
||||
# Move with Z - update velocity and accel for slower Z axis
|
||||
self._check_endstops(move)
|
||||
z_ratio = move.move_d / abs(move.axes_d[2])
|
||||
move.limit_speed(
|
||||
self.max_z_velocity * z_ratio, self.max_z_accel * z_ratio)
|
||||
def move(self, print_time, move):
|
||||
if self.need_motor_enable:
|
||||
self._check_motor_enable(print_time, move)
|
||||
for i in StepList:
|
||||
axis_d = move.axes_d[i]
|
||||
if not axis_d:
|
||||
continue
|
||||
mcu_stepper = self.steppers[i].mcu_stepper
|
||||
move_time = print_time
|
||||
start_pos = move.start_pos[i]
|
||||
axis_r = abs(axis_d) / move.move_d
|
||||
accel = move.accel * axis_r
|
||||
cruise_v = move.cruise_v * axis_r
|
||||
|
||||
# Acceleration steps
|
||||
if move.accel_r:
|
||||
accel_d = move.accel_r * axis_d
|
||||
mcu_stepper.step_const(
|
||||
move_time, start_pos, accel_d, move.start_v * axis_r, accel)
|
||||
start_pos += accel_d
|
||||
move_time += move.accel_t
|
||||
# Cruising steps
|
||||
if move.cruise_r:
|
||||
cruise_d = move.cruise_r * axis_d
|
||||
mcu_stepper.step_const(
|
||||
move_time, start_pos, cruise_d, cruise_v, 0.)
|
||||
start_pos += cruise_d
|
||||
move_time += move.cruise_t
|
||||
# Deceleration steps
|
||||
if move.decel_r:
|
||||
decel_d = move.decel_r * axis_d
|
||||
mcu_stepper.step_const(
|
||||
move_time, start_pos, decel_d, cruise_v, -accel)
|
||||
137
klippy/chelper.py
Normal file
@@ -0,0 +1,137 @@
|
||||
# Wrapper around C helper code
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import os, logging
|
||||
import cffi
|
||||
|
||||
|
||||
######################################################################
|
||||
# c_helper.so compiling
|
||||
######################################################################
|
||||
|
||||
COMPILE_CMD = "gcc -Wall -g -O2 -shared -fPIC -o %s %s"
|
||||
SOURCE_FILES = ['stepcompress.c', 'serialqueue.c', 'pyhelper.c']
|
||||
DEST_LIB = "c_helper.so"
|
||||
OTHER_FILES = ['list.h', 'serialqueue.h', 'pyhelper.h']
|
||||
|
||||
defs_stepcompress = """
|
||||
struct stepcompress *stepcompress_alloc(uint32_t max_error
|
||||
, uint32_t queue_step_msgid, uint32_t set_next_step_dir_msgid
|
||||
, uint32_t invert_sdir, uint32_t oid);
|
||||
void stepcompress_free(struct stepcompress *sc);
|
||||
int stepcompress_reset(struct stepcompress *sc, uint64_t last_step_clock);
|
||||
int stepcompress_set_homing(struct stepcompress *sc, uint64_t homing_clock);
|
||||
int stepcompress_queue_msg(struct stepcompress *sc, uint32_t *data, int len);
|
||||
|
||||
int32_t stepcompress_push(struct stepcompress *sc, double step_clock
|
||||
, int32_t sdir);
|
||||
int32_t stepcompress_push_const(struct stepcompress *sc, double clock_offset
|
||||
, double step_offset, double steps, double start_sv, double accel);
|
||||
int32_t stepcompress_push_delta(struct stepcompress *sc
|
||||
, double clock_offset, double move_sd, double start_sv, double accel
|
||||
, double height, double startxy_sd, double arm_d, double movez_r);
|
||||
|
||||
struct steppersync *steppersync_alloc(struct serialqueue *sq
|
||||
, struct stepcompress **sc_list, int sc_num, int move_num);
|
||||
void steppersync_free(struct steppersync *ss);
|
||||
void steppersync_set_time(struct steppersync *ss
|
||||
, double time_offset, double mcu_freq);
|
||||
int steppersync_flush(struct steppersync *ss, uint64_t move_clock);
|
||||
"""
|
||||
|
||||
defs_serialqueue = """
|
||||
#define MESSAGE_MAX 64
|
||||
struct pull_queue_message {
|
||||
uint8_t msg[MESSAGE_MAX];
|
||||
int len;
|
||||
double sent_time, receive_time;
|
||||
};
|
||||
|
||||
struct serialqueue *serialqueue_alloc(int serial_fd, int write_only);
|
||||
void serialqueue_exit(struct serialqueue *sq);
|
||||
void serialqueue_free(struct serialqueue *sq);
|
||||
struct command_queue *serialqueue_alloc_commandqueue(void);
|
||||
void serialqueue_free_commandqueue(struct command_queue *cq);
|
||||
void serialqueue_send(struct serialqueue *sq, struct command_queue *cq
|
||||
, uint8_t *msg, int len, uint64_t min_clock, uint64_t req_clock);
|
||||
void serialqueue_encode_and_send(struct serialqueue *sq
|
||||
, struct command_queue *cq, uint32_t *data, int len
|
||||
, uint64_t min_clock, uint64_t req_clock);
|
||||
void serialqueue_pull(struct serialqueue *sq, struct pull_queue_message *pqm);
|
||||
void serialqueue_set_baud_adjust(struct serialqueue *sq, double baud_adjust);
|
||||
void serialqueue_set_clock_est(struct serialqueue *sq, double est_freq
|
||||
, double last_clock_time, uint64_t last_clock);
|
||||
void serialqueue_get_stats(struct serialqueue *sq, char *buf, int len);
|
||||
int serialqueue_extract_old(struct serialqueue *sq, int sentq
|
||||
, struct pull_queue_message *q, int max);
|
||||
"""
|
||||
|
||||
defs_pyhelper = """
|
||||
void set_python_logging_callback(void (*func)(const char *));
|
||||
double get_monotonic(void);
|
||||
"""
|
||||
|
||||
# Return the list of file modification times
|
||||
def get_mtimes(srcdir, filelist):
|
||||
out = []
|
||||
for filename in filelist:
|
||||
pathname = os.path.join(srcdir, filename)
|
||||
try:
|
||||
t = os.path.getmtime(pathname)
|
||||
except os.error:
|
||||
continue
|
||||
out.append(t)
|
||||
return out
|
||||
|
||||
# Check if the code needs to be compiled
|
||||
def check_build_code(srcdir, target, sources, cmd, other_files=[]):
|
||||
src_times = get_mtimes(srcdir, sources + other_files)
|
||||
obj_times = get_mtimes(srcdir, [target])
|
||||
if not obj_times or max(src_times) > min(obj_times):
|
||||
logging.info("Building C code module %s", target)
|
||||
srcfiles = [os.path.join(srcdir, fname) for fname in sources]
|
||||
destlib = os.path.join(srcdir, target)
|
||||
os.system(cmd % (destlib, ' '.join(srcfiles)))
|
||||
|
||||
FFI_main = None
|
||||
FFI_lib = None
|
||||
pyhelper_logging_callback = None
|
||||
|
||||
# Return the Foreign Function Interface api to the caller
|
||||
def get_ffi():
|
||||
global FFI_main, FFI_lib, pyhelper_logging_callback
|
||||
if FFI_lib is None:
|
||||
srcdir = os.path.dirname(os.path.realpath(__file__))
|
||||
check_build_code(srcdir, DEST_LIB, SOURCE_FILES, COMPILE_CMD
|
||||
, OTHER_FILES)
|
||||
FFI_main = cffi.FFI()
|
||||
FFI_main.cdef(defs_stepcompress)
|
||||
FFI_main.cdef(defs_serialqueue)
|
||||
FFI_main.cdef(defs_pyhelper)
|
||||
FFI_lib = FFI_main.dlopen(os.path.join(srcdir, DEST_LIB))
|
||||
# Setup error logging
|
||||
def logging_callback(msg):
|
||||
logging.error(FFI_main.string(msg))
|
||||
pyhelper_logging_callback = FFI_main.callback(
|
||||
"void(const char *)", logging_callback)
|
||||
FFI_lib.set_python_logging_callback(pyhelper_logging_callback)
|
||||
return FFI_main, FFI_lib
|
||||
|
||||
|
||||
######################################################################
|
||||
# hub-ctrl hub power controller
|
||||
######################################################################
|
||||
|
||||
HC_COMPILE_CMD = "gcc -Wall -g -O2 -o %s %s -lusb"
|
||||
HC_SOURCE_FILES = ['hub-ctrl.c']
|
||||
HC_SOURCE_DIR = '../lib/hub-ctrl'
|
||||
HC_TARGET = "hub-ctrl"
|
||||
HC_CMD = "sudo %s/hub-ctrl -h 0 -P 2 -p %d"
|
||||
|
||||
def run_hub_ctrl(enable_power):
|
||||
srcdir = os.path.dirname(os.path.realpath(__file__))
|
||||
hubdir = os.path.join(srcdir, HC_SOURCE_DIR)
|
||||
check_build_code(hubdir, HC_TARGET, HC_SOURCE_FILES, HC_COMPILE_CMD)
|
||||
os.system(HC_CMD % (hubdir, enable_power))
|
||||
296
klippy/chipmisc.py
Normal file
@@ -0,0 +1,296 @@
|
||||
# Code to configure miscellaneous chips
|
||||
#
|
||||
# Copyright (C) 2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import pins, mcu
|
||||
|
||||
|
||||
######################################################################
|
||||
# Statically configured output pins
|
||||
######################################################################
|
||||
|
||||
class PrinterStaticDigitalOut:
|
||||
def __init__(self, printer, config):
|
||||
pin_list = [pin.strip() for pin in config.get('pins').split(',')]
|
||||
for pin_desc in pin_list:
|
||||
mcu_pin = pins.setup_pin(printer, 'digital_out', pin_desc)
|
||||
mcu_pin.setup_static()
|
||||
|
||||
class PrinterStaticPWM:
|
||||
def __init__(self, printer, config):
|
||||
mcu_pwm = pins.setup_pin(printer, 'pwm', config.get('pin'))
|
||||
mcu_pwm.setup_max_duration(0.)
|
||||
hard_pwm = config.getint('hard_pwm', None, minval=1)
|
||||
if hard_pwm is None:
|
||||
mcu_pwm.setup_cycle_time(config.getfloat(
|
||||
'cycle_time', 0.100, above=0.))
|
||||
else:
|
||||
mcu_pwm.setup_hard_pwm(hard_pwm)
|
||||
scale = config.getfloat('scale', 1., above=0.)
|
||||
value = config.getfloat('value', minval=0., maxval=scale)
|
||||
mcu_pwm.setup_static_pwm(value / scale)
|
||||
|
||||
|
||||
######################################################################
|
||||
# Servos
|
||||
######################################################################
|
||||
|
||||
SERVO_MIN_TIME = 0.100
|
||||
SERVO_SIGNAL_PERIOD = 0.020
|
||||
|
||||
class PrinterServo:
|
||||
def __init__(self, printer, config):
|
||||
self.mcu_servo = pins.setup_pin(printer, 'pwm', config.get('pin'))
|
||||
self.mcu_servo.setup_max_duration(0.)
|
||||
self.mcu_servo.setup_cycle_time(SERVO_SIGNAL_PERIOD)
|
||||
self.min_width = config.getfloat(
|
||||
'minimum_pulse_width', .001, above=0., below=SERVO_SIGNAL_PERIOD)
|
||||
self.max_width = config.getfloat(
|
||||
'maximum_pulse_width', .002
|
||||
, above=self.min_width, below=SERVO_SIGNAL_PERIOD)
|
||||
self.max_angle = config.getfloat('maximum_servo_angle', 180.)
|
||||
self.angle_to_width = (self.max_width - self.min_width) / self.max_angle
|
||||
self.width_to_value = 1. / SERVO_SIGNAL_PERIOD
|
||||
self.last_value = self.last_value_time = 0.
|
||||
def set_pwm(self, print_time, value):
|
||||
if value == self.last_value:
|
||||
return
|
||||
print_time = max(self.last_value_time + SERVO_MIN_TIME, print_time)
|
||||
self.mcu_servo.set_pwm(print_time, value)
|
||||
self.last_value = value
|
||||
self.last_value_time = print_time
|
||||
# External commands
|
||||
def set_angle(self, print_time, angle):
|
||||
angle = max(0., min(self.max_angle, angle))
|
||||
width = self.min_width + angle * self.angle_to_width
|
||||
self.set_pwm(print_time, width * self.width_to_value)
|
||||
def set_pulse_width(self, print_time, width):
|
||||
width = max(self.min_width, min(self.max_width, width))
|
||||
self.set_pwm(print_time, width * self.width_to_value)
|
||||
|
||||
def get_printer_servo(printer, name):
|
||||
return printer.objects.get('servo ' + name)
|
||||
|
||||
|
||||
######################################################################
|
||||
# AD5206 digipot
|
||||
######################################################################
|
||||
|
||||
class ad5206:
|
||||
def __init__(self, printer, config):
|
||||
enable_pin_params = pins.get_printer_pins(printer).parse_pin_desc(
|
||||
config.get('enable_pin'))
|
||||
self.mcu = enable_pin_params['chip']
|
||||
self.pin = enable_pin_params['pin']
|
||||
self.mcu.add_config_object(self)
|
||||
scale = config.getfloat('scale', 1., above=0.)
|
||||
self.channels = [None] * 6
|
||||
for i in range(len(self.channels)):
|
||||
val = config.getfloat('channel_%d' % (i+1,), None,
|
||||
minval=0., maxval=scale)
|
||||
if val is not None:
|
||||
self.channels[i] = int(val * 256. / scale + .5)
|
||||
def build_config(self):
|
||||
for i, val in enumerate(self.channels):
|
||||
if val is not None:
|
||||
self.mcu.add_config_cmd(
|
||||
"send_spi_message pin=%s msg=%02x%02x" % (self.pin, i, val))
|
||||
|
||||
|
||||
######################################################################
|
||||
# Replicape board
|
||||
######################################################################
|
||||
|
||||
REPLICAPE_MAX_CURRENT = 3.84
|
||||
REPLICAPE_SHIFT_REGISTER_BUS = 1
|
||||
REPLICAPE_SHIFT_REGISTER_DEVICE = 1
|
||||
REPLICAPE_PCA9685_BUS = 2
|
||||
REPLICAPE_PCA9685_ADDRESS = 0x70
|
||||
REPLICAPE_PCA9685_CYCLE_TIME = .001
|
||||
|
||||
class pca9685_pwm:
|
||||
def __init__(self, replicape, channel, pin_params):
|
||||
self._replicape = replicape
|
||||
self._channel = channel
|
||||
if pin_params['type'] not in ['digital_out', 'pwm']:
|
||||
raise pins.error("Pin type not supported on replicape")
|
||||
self._mcu = replicape.host_mcu
|
||||
self._mcu.add_config_object(self)
|
||||
self._bus = REPLICAPE_PCA9685_BUS
|
||||
self._address = REPLICAPE_PCA9685_ADDRESS
|
||||
self._cycle_time = REPLICAPE_PCA9685_CYCLE_TIME
|
||||
self._max_duration = 2.
|
||||
self._oid = None
|
||||
self._invert = pin_params['invert']
|
||||
self._shutdown_value = float(self._invert)
|
||||
self._last_clock = 0
|
||||
self._pwm_max = 0.
|
||||
self._cmd_queue = self._mcu.alloc_command_queue()
|
||||
self._set_cmd = None
|
||||
self._static_value = None
|
||||
def get_mcu(self):
|
||||
return self._mcu
|
||||
def setup_max_duration(self, max_duration):
|
||||
self._max_duration = max_duration
|
||||
def setup_cycle_time(self, cycle_time):
|
||||
pass
|
||||
def setup_hard_pwm(self, hard_cycle_ticks):
|
||||
if hard_cycle_ticks:
|
||||
raise pins.error("pca9685 does not support hard_pwm parameter")
|
||||
def setup_static_pwm(self, value):
|
||||
if self._invert:
|
||||
value = 1. - value
|
||||
self._static_value = max(0., min(1., value))
|
||||
def setup_shutdown_value(self, value):
|
||||
if self._invert:
|
||||
value = 1. - value
|
||||
self._shutdown_value = max(0., min(1., value))
|
||||
if self._shutdown_value:
|
||||
self._replicape.note_enable_on_shutdown()
|
||||
def build_config(self):
|
||||
self._pwm_max = self._mcu.get_constant_float("PCA9685_MAX")
|
||||
cycle_ticks = self._mcu.seconds_to_clock(self._cycle_time)
|
||||
if self._static_value is not None:
|
||||
value = int(self._static_value * self._pwm_max + 0.5)
|
||||
self._mcu.add_config_cmd(
|
||||
"set_pca9685_out bus=%d addr=%d channel=%d"
|
||||
" cycle_ticks=%d value=%d" % (
|
||||
self._bus, self._address, self._channel,
|
||||
cycle_ticks, value))
|
||||
return
|
||||
self._oid = self._mcu.create_oid()
|
||||
self._mcu.add_config_cmd(
|
||||
"config_pca9685 oid=%d bus=%d addr=%d channel=%d cycle_ticks=%d"
|
||||
" value=%d default_value=%d max_duration=%d" % (
|
||||
self._oid, self._bus, self._address, self._channel, cycle_ticks,
|
||||
self._invert * self._pwm_max,
|
||||
self._shutdown_value * self._pwm_max,
|
||||
self._mcu.seconds_to_clock(self._max_duration)))
|
||||
self._set_cmd = self._mcu.lookup_command(
|
||||
"schedule_pca9685_out oid=%c clock=%u value=%hu")
|
||||
def set_pwm(self, print_time, value):
|
||||
clock = self._mcu.print_time_to_clock(print_time)
|
||||
if self._invert:
|
||||
value = 1. - value
|
||||
value = int(max(0., min(1., value)) * self._pwm_max + 0.5)
|
||||
self._replicape.note_enable(print_time, self._channel, not not value)
|
||||
msg = self._set_cmd.encode(self._oid, clock, value)
|
||||
self._mcu.send(msg, minclock=self._last_clock, reqclock=clock
|
||||
, cq=self._cmd_queue)
|
||||
self._last_clock = clock
|
||||
def set_digital(self, print_time, value):
|
||||
if value:
|
||||
self.set_pwm(print_time, 1.)
|
||||
else:
|
||||
self.set_pwm(print_time, 0.)
|
||||
|
||||
class ReplicapeDACEnable:
|
||||
def __init__(self, replicape, channel, pin_params):
|
||||
if pin_params['type'] != 'digital_out':
|
||||
raise pins.error("Replicape virtual enable pin must be digital_out")
|
||||
if pin_params['invert']:
|
||||
raise pins.error("Replicape virtual enable pin can not be inverted")
|
||||
self.mcu = replicape.host_mcu
|
||||
self.value = replicape.stepper_dacs[channel]
|
||||
self.pwm = pca9685_pwm(replicape, channel, pin_params)
|
||||
self.last = 0
|
||||
def get_mcu(self):
|
||||
return self.mcu
|
||||
def setup_max_duration(self, max_duration):
|
||||
self.pwm.setup_max_duration(max_duration)
|
||||
def set_digital(self, print_time, value):
|
||||
if value:
|
||||
self.pwm.set_pwm(print_time, self.value)
|
||||
else:
|
||||
self.pwm.set_pwm(print_time, 0.)
|
||||
self.last = value
|
||||
def get_last_setting(self):
|
||||
return self.last
|
||||
|
||||
ReplicapeStepConfig = {
|
||||
'disable': None,
|
||||
'1': (1<<7)|(1<<5), '2': (1<<7)|(1<<5)|(1<<6), 'spread2': (1<<5),
|
||||
'4': (1<<7)|(1<<5)|(1<<4), '16': (1<<7)|(1<<5)|(1<<6)|(1<<4),
|
||||
'spread4': (1<<5)|(1<<4), 'spread16': (1<<7), 'stealth4': (1<<7)|(1<<6),
|
||||
'stealth16': 0
|
||||
}
|
||||
|
||||
class Replicape:
|
||||
def __init__(self, printer, config):
|
||||
pins.get_printer_pins(printer).register_chip('replicape', self)
|
||||
revisions = {'B3': 'B3'}
|
||||
config.getchoice('revision', revisions)
|
||||
self.host_mcu = mcu.get_printer_mcu(printer, config.get('host_mcu'))
|
||||
# Setup enable pin
|
||||
self.mcu_enable = pins.setup_pin(
|
||||
printer, 'digital_out', config.get('enable_pin', '!P9_41'))
|
||||
self.mcu_enable.setup_max_duration(0.)
|
||||
self.enabled_channels = {}
|
||||
# Setup power pins
|
||||
self.pins = {
|
||||
"power_e": (pca9685_pwm, 5), "power_h": (pca9685_pwm, 3),
|
||||
"power_hotbed": (pca9685_pwm, 4),
|
||||
"power_fan0": (pca9685_pwm, 7), "power_fan1": (pca9685_pwm, 8),
|
||||
"power_fan2": (pca9685_pwm, 9), "power_fan3": (pca9685_pwm, 10) }
|
||||
# Setup stepper config
|
||||
self.stepper_dacs = {}
|
||||
shift_registers = [1] * 5
|
||||
for port, name in enumerate('xyzeh'):
|
||||
prefix = 'stepper_%s_' % (name,)
|
||||
sc = config.getchoice(
|
||||
prefix + 'microstep_mode', ReplicapeStepConfig, 'disable')
|
||||
if sc is None:
|
||||
continue
|
||||
if config.getboolean(prefix + 'chopper_off_time_high', False):
|
||||
sc |= 1<<3
|
||||
if config.getboolean(prefix + 'chopper_hysteresis_high', False):
|
||||
sc |= 1<<2
|
||||
if config.getboolean(prefix + 'chopper_blank_time_high', True):
|
||||
sc |= 1<<1
|
||||
shift_registers[port] = sc
|
||||
channel = port + 11
|
||||
cur = config.getfloat(
|
||||
prefix + 'current', above=0., maxval=REPLICAPE_MAX_CURRENT)
|
||||
self.stepper_dacs[channel] = cur / REPLICAPE_MAX_CURRENT
|
||||
self.pins[prefix + 'enable'] = (ReplicapeDACEnable, channel)
|
||||
shift_registers.reverse()
|
||||
self.host_mcu.add_config_cmd("send_spi bus=%d dev=%d msg=%s" % (
|
||||
REPLICAPE_SHIFT_REGISTER_BUS, REPLICAPE_SHIFT_REGISTER_DEVICE,
|
||||
"".join(["%02x" % (x,) for x in shift_registers])))
|
||||
def note_enable_on_shutdown(self):
|
||||
self.mcu_enable.setup_shutdown_value(1)
|
||||
def note_enable(self, print_time, channel, is_enable):
|
||||
if is_enable:
|
||||
is_off = not self.enabled_channels
|
||||
self.enabled_channels[channel] = 1
|
||||
if is_off:
|
||||
self.mcu_enable.set_digital(print_time, 1)
|
||||
elif channel in self.enabled_channels:
|
||||
del self.enabled_channels[channel]
|
||||
if not self.enabled_channels:
|
||||
self.mcu_enable.set_digital(print_time, 0)
|
||||
def setup_pin(self, pin_params):
|
||||
pin = pin_params['pin']
|
||||
if pin not in self.pins:
|
||||
raise pins.error("Unknown replicape pin %s" % (pin,))
|
||||
pclass, channel = self.pins[pin]
|
||||
return pclass(self, channel, pin_params)
|
||||
|
||||
|
||||
######################################################################
|
||||
# Setup
|
||||
######################################################################
|
||||
|
||||
def add_printer_objects(printer, config):
|
||||
if config.has_section('replicape'):
|
||||
printer.add_object('replicape', Replicape(
|
||||
printer, config.getsection('replicape')))
|
||||
for s in config.get_prefix_sections('static_digital_output '):
|
||||
printer.add_object(s.section, PrinterStaticDigitalOut(printer, s))
|
||||
for s in config.get_prefix_sections('static_pwm_output '):
|
||||
printer.add_object(s.section, PrinterStaticPWM(printer, s))
|
||||
for s in config.get_prefix_sections('servo '):
|
||||
printer.add_object(s.section, PrinterServo(printer, s))
|
||||
for s in config.get_prefix_sections('ad5206 '):
|
||||
printer.add_object(s.section, ad5206(printer, s))
|
||||
212
klippy/clocksync.py
Normal file
@@ -0,0 +1,212 @@
|
||||
# Micro-controller clock synchronization
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import logging, threading, math
|
||||
|
||||
COMM_TIMEOUT = 3.5
|
||||
RTT_AGE = .000010 / (60. * 60.)
|
||||
DECAY = 1. / (2. * 60.)
|
||||
TRANSMIT_EXTRA = .001
|
||||
|
||||
class ClockSync:
|
||||
def __init__(self, reactor):
|
||||
self.reactor = reactor
|
||||
self.serial = None
|
||||
self.status_timer = self.reactor.register_timer(self._status_event)
|
||||
self.status_cmd = None
|
||||
self.mcu_freq = 1.
|
||||
self.last_clock = 0
|
||||
self.clock_est = (0., 0., 0.)
|
||||
# Minimum round-trip-time tracking
|
||||
self.min_half_rtt = 999999999.9
|
||||
self.min_rtt_time = 0.
|
||||
# Linear regression of mcu clock and system sent_time
|
||||
self.time_avg = self.time_variance = 0.
|
||||
self.clock_avg = self.clock_covariance = 0.
|
||||
self.prediction_variance = 0.
|
||||
self.last_prediction_time = 0.
|
||||
def connect(self, serial):
|
||||
self.serial = serial
|
||||
msgparser = serial.msgparser
|
||||
self.mcu_freq = msgparser.get_constant_float('CLOCK_FREQ')
|
||||
# Load initial clock and frequency
|
||||
uptime_msg = msgparser.create_command('get_uptime')
|
||||
params = serial.send_with_response(uptime_msg, 'uptime')
|
||||
self.last_clock = (params['high'] << 32) | params['clock']
|
||||
self.clock_avg = self.last_clock
|
||||
self.time_avg = params['#sent_time']
|
||||
self.clock_est = (self.time_avg, self.clock_avg, self.mcu_freq)
|
||||
self.prediction_variance = (.001 * self.mcu_freq)**2
|
||||
# Enable periodic get_status timer
|
||||
self.status_cmd = msgparser.create_command('get_status')
|
||||
for i in range(8):
|
||||
params = serial.send_with_response(self.status_cmd, 'status')
|
||||
self._handle_status(params)
|
||||
self.reactor.pause(0.100)
|
||||
serial.register_callback(self._handle_status, 'status')
|
||||
self.reactor.update_timer(self.status_timer, self.reactor.NOW)
|
||||
def connect_file(self, serial, pace=False):
|
||||
self.serial = serial
|
||||
self.mcu_freq = serial.msgparser.get_constant_float('CLOCK_FREQ')
|
||||
self.clock_est = (0., 0., self.mcu_freq)
|
||||
freq = 1000000000000.
|
||||
if pace:
|
||||
freq = self.mcu_freq
|
||||
serial.set_clock_est(freq, self.reactor.monotonic(), 0)
|
||||
# MCU clock querying (status callback invoked from background thread)
|
||||
def _status_event(self, eventtime):
|
||||
self.serial.send(self.status_cmd)
|
||||
return eventtime + 1.0
|
||||
def _handle_status(self, params):
|
||||
# Extend clock to 64bit
|
||||
last_clock = self.last_clock
|
||||
clock = (last_clock & ~0xffffffff) | params['clock']
|
||||
if clock < last_clock:
|
||||
clock += 0x100000000
|
||||
self.last_clock = clock
|
||||
# Check if this is the best round-trip-time seen so far
|
||||
sent_time = params['#sent_time']
|
||||
if not sent_time:
|
||||
return
|
||||
receive_time = params['#receive_time']
|
||||
half_rtt = .5 * (receive_time - sent_time)
|
||||
aged_rtt = (sent_time - self.min_rtt_time) * RTT_AGE
|
||||
if half_rtt < self.min_half_rtt + aged_rtt:
|
||||
self.min_half_rtt = half_rtt
|
||||
self.min_rtt_time = sent_time
|
||||
logging.debug("new minimum rtt %.3f: hrtt=%.6f freq=%d",
|
||||
sent_time, half_rtt, self.clock_est[2])
|
||||
# Filter out samples that are extreme outliers
|
||||
exp_clock = ((sent_time - self.time_avg) * self.clock_est[2]
|
||||
+ self.clock_avg)
|
||||
clock_diff2 = (clock - exp_clock)**2
|
||||
if (clock_diff2 > 25. * self.prediction_variance
|
||||
and clock_diff2 > (.000500 * self.mcu_freq)**2):
|
||||
if clock > exp_clock and sent_time < self.last_prediction_time + 10.:
|
||||
logging.debug("Ignoring clock sample %.3f:"
|
||||
" freq=%d diff=%d stddev=%.3f",
|
||||
sent_time, self.clock_est[2], clock - exp_clock,
|
||||
math.sqrt(self.prediction_variance))
|
||||
return
|
||||
logging.info("Resetting prediction variance %.3f:"
|
||||
" freq=%d diff=%d stddev=%.3f",
|
||||
sent_time, self.clock_est[2], clock - exp_clock,
|
||||
math.sqrt(self.prediction_variance))
|
||||
self.prediction_variance = (.001 * self.mcu_freq)**2
|
||||
else:
|
||||
self.last_prediction_time = sent_time
|
||||
self.prediction_variance = (
|
||||
(1. - DECAY) * (self.prediction_variance + clock_diff2 * DECAY))
|
||||
# Add clock and sent_time to linear regression
|
||||
diff_sent_time = sent_time - self.time_avg
|
||||
self.time_avg += DECAY * diff_sent_time
|
||||
self.time_variance = (1. - DECAY) * (
|
||||
self.time_variance + diff_sent_time**2 * DECAY)
|
||||
diff_clock = clock - self.clock_avg
|
||||
self.clock_avg += DECAY * diff_clock
|
||||
self.clock_covariance = (1. - DECAY) * (
|
||||
self.clock_covariance + diff_sent_time * diff_clock * DECAY)
|
||||
# Update prediction from linear regression
|
||||
new_freq = self.clock_covariance / self.time_variance
|
||||
pred_stddev = math.sqrt(self.prediction_variance)
|
||||
self.serial.set_clock_est(new_freq, self.time_avg + TRANSMIT_EXTRA,
|
||||
int(self.clock_avg - 3. * pred_stddev))
|
||||
self.clock_est = (self.time_avg - self.min_half_rtt,
|
||||
self.clock_avg, new_freq)
|
||||
#logging.debug("regr %.3f: freq=%.3f d=%d(%.3f)",
|
||||
# sent_time, new_freq, clock - exp_clock, pred_stddev)
|
||||
# clock frequency conversions
|
||||
def print_time_to_clock(self, print_time):
|
||||
return int(print_time * self.mcu_freq)
|
||||
def clock_to_print_time(self, clock):
|
||||
return clock / self.mcu_freq
|
||||
def get_adjusted_freq(self):
|
||||
return self.mcu_freq
|
||||
# system time conversions
|
||||
def get_clock(self, eventtime):
|
||||
sample_time, clock, freq = self.clock_est
|
||||
return int(clock + (eventtime - sample_time) * freq)
|
||||
def estimated_print_time(self, eventtime):
|
||||
return self.clock_to_print_time(self.get_clock(eventtime))
|
||||
# misc commands
|
||||
def clock32_to_clock64(self, clock32):
|
||||
last_clock = self.last_clock
|
||||
clock_diff = (last_clock - clock32) & 0xffffffff
|
||||
if clock_diff & 0x80000000:
|
||||
return last_clock + 0x100000000 - clock_diff
|
||||
return last_clock - clock_diff
|
||||
def is_active(self, eventtime):
|
||||
print_time = self.estimated_print_time(eventtime)
|
||||
last_clock_print_time = self.clock_to_print_time(self.last_clock)
|
||||
return print_time < last_clock_print_time + COMM_TIMEOUT
|
||||
def dump_debug(self):
|
||||
sample_time, clock, freq = self.clock_est
|
||||
return ("clocksync state: mcu_freq=%d last_clock=%d"
|
||||
" clock_est=(%.3f %d %.3f) min_half_rtt=%.6f min_rtt_time=%.3f"
|
||||
" time_avg=%.3f(%.3f) clock_avg=%.3f(%.3f)"
|
||||
" pred_variance=%.3f" % (
|
||||
self.mcu_freq, self.last_clock, sample_time, clock, freq,
|
||||
self.min_half_rtt, self.min_rtt_time,
|
||||
self.time_avg, self.time_variance,
|
||||
self.clock_avg, self.clock_covariance,
|
||||
self.prediction_variance))
|
||||
def stats(self, eventtime):
|
||||
sample_time, clock, freq = self.clock_est
|
||||
return "freq=%d" % (freq,)
|
||||
def calibrate_clock(self, print_time, eventtime):
|
||||
return (0., self.mcu_freq)
|
||||
|
||||
# Clock syncing code for secondary MCUs (whose clocks are sync'ed to a
|
||||
# primary MCU)
|
||||
class SecondarySync(ClockSync):
|
||||
def __init__(self, reactor, main_sync):
|
||||
ClockSync.__init__(self, reactor)
|
||||
self.main_sync = main_sync
|
||||
self.clock_adj = (0., 1.)
|
||||
def connect(self, serial):
|
||||
ClockSync.connect(self, serial)
|
||||
self.clock_adj = (0., self.mcu_freq)
|
||||
curtime = self.reactor.monotonic()
|
||||
main_print_time = self.main_sync.estimated_print_time(curtime)
|
||||
local_print_time = self.estimated_print_time(curtime)
|
||||
self.clock_adj = (main_print_time - local_print_time, self.mcu_freq)
|
||||
self.calibrate_clock(0., curtime)
|
||||
def connect_file(self, serial, pace=False):
|
||||
ClockSync.connect_file(self, serial, pace)
|
||||
self.clock_adj = (0., self.mcu_freq)
|
||||
# clock frequency conversions
|
||||
def print_time_to_clock(self, print_time):
|
||||
adjusted_offset, adjusted_freq = self.clock_adj
|
||||
return int((print_time - adjusted_offset) * adjusted_freq)
|
||||
def clock_to_print_time(self, clock):
|
||||
adjusted_offset, adjusted_freq = self.clock_adj
|
||||
return clock / adjusted_freq + adjusted_offset
|
||||
def get_adjusted_freq(self):
|
||||
adjusted_offset, adjusted_freq = self.clock_adj
|
||||
return adjusted_freq
|
||||
# misc commands
|
||||
def dump_debug(self):
|
||||
adjusted_offset, adjusted_freq = self.clock_adj
|
||||
return "%s clock_adj=(%.3f %.3f)" % (
|
||||
ClockSync.dump_debug(self), adjusted_offset, adjusted_freq)
|
||||
def stats(self, eventtime):
|
||||
adjusted_offset, adjusted_freq = self.clock_adj
|
||||
return "%s adj=%d" % (ClockSync.stats(self, eventtime), adjusted_freq)
|
||||
def calibrate_clock(self, print_time, eventtime):
|
||||
ser_time, ser_clock, ser_freq = self.main_sync.clock_est
|
||||
main_mcu_freq = self.main_sync.mcu_freq
|
||||
|
||||
main_clock = (eventtime - ser_time) * ser_freq + ser_clock
|
||||
print_time = max(print_time, main_clock / main_mcu_freq)
|
||||
main_sync_clock = (print_time + 4.) * main_mcu_freq
|
||||
sync_time = ser_time + (main_sync_clock - ser_clock) / ser_freq
|
||||
|
||||
print_clock = self.print_time_to_clock(print_time)
|
||||
sync_clock = self.get_clock(sync_time)
|
||||
adjusted_freq = .25 * (sync_clock - print_clock)
|
||||
adjusted_offset = print_time - print_clock / adjusted_freq
|
||||
|
||||
self.clock_adj = (adjusted_offset, adjusted_freq)
|
||||
return self.clock_adj
|
||||
208
klippy/console.py
Executable file
@@ -0,0 +1,208 @@
|
||||
#!/usr/bin/env python2
|
||||
# Script to implement a test console with firmware over serial port
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import sys, optparse, os, re, logging
|
||||
import reactor, serialhdl, pins, util, msgproto, clocksync
|
||||
|
||||
help_txt = """
|
||||
This is a debugging console for the Klipper micro-controller.
|
||||
In addition to mcu commands, the following artificial commands are
|
||||
available:
|
||||
PINS : Load pin name aliases (eg, "PINS arduino")
|
||||
DELAY : Send a command at a clock time (eg, "DELAY 9999 get_uptime")
|
||||
FLOOD : Send a command many times (eg, "FLOOD 22 .01 get_uptime")
|
||||
SUPPRESS : Suppress a response message (eg, "SUPPRESS stats")
|
||||
SET : Create a local variable (eg, "SET myvar 123.4")
|
||||
STATS : Report serial statistics
|
||||
LIST : List available mcu commands, local commands, and local variables
|
||||
HELP : Show this text
|
||||
All commands also support evaluation by enclosing an expression in { }.
|
||||
For example, "reset_step_clock oid=4 clock={clock + freq}". In addition
|
||||
to user defined variables (via the SET command) the following builtin
|
||||
variables may be used in expressions:
|
||||
clock : The current mcu clock time (as estimated by the host)
|
||||
freq : The mcu clock frequency
|
||||
"""
|
||||
|
||||
re_eval = re.compile(r'\{(?P<eval>[^}]*)\}')
|
||||
|
||||
class KeyboardReader:
|
||||
def __init__(self, ser, reactor):
|
||||
self.ser = ser
|
||||
self.reactor = reactor
|
||||
self.clocksync = clocksync.ClockSync(self.reactor)
|
||||
self.fd = sys.stdin.fileno()
|
||||
util.set_nonblock(self.fd)
|
||||
self.mcu_freq = 0
|
||||
self.pins = None
|
||||
self.data = ""
|
||||
reactor.register_fd(self.fd, self.process_kbd)
|
||||
self.connect_timer = reactor.register_timer(self.connect, reactor.NOW)
|
||||
self.local_commands = {
|
||||
"PINS": self.command_PINS, "SET": self.command_SET,
|
||||
"DELAY": self.command_DELAY, "FLOOD": self.command_FLOOD,
|
||||
"SUPPRESS": self.command_SUPPRESS, "STATS": self.command_STATS,
|
||||
"LIST": self.command_LIST, "HELP": self.command_HELP,
|
||||
}
|
||||
self.eval_globals = {}
|
||||
def connect(self, eventtime):
|
||||
self.output(help_txt)
|
||||
self.output("="*20 + " attempting to connect " + "="*20)
|
||||
self.ser.connect()
|
||||
self.clocksync.connect(self.ser)
|
||||
self.ser.handle_default = self.handle_default
|
||||
self.mcu_freq = self.ser.msgparser.get_constant_float('CLOCK_FREQ')
|
||||
mcu = self.ser.msgparser.get_constant('MCU')
|
||||
self.pins = pins.get_pin_map(mcu)
|
||||
self.reactor.unregister_timer(self.connect_timer)
|
||||
self.output("="*20 + " connected " + "="*20)
|
||||
return self.reactor.NEVER
|
||||
def output(self, msg):
|
||||
sys.stdout.write("%s\n" % (msg,))
|
||||
sys.stdout.flush()
|
||||
def handle_default(self, params):
|
||||
self.output(self.ser.msgparser.format_params(params))
|
||||
def handle_suppress(self, params):
|
||||
pass
|
||||
def update_evals(self, eventtime):
|
||||
self.eval_globals['freq'] = self.mcu_freq
|
||||
self.eval_globals['clock'] = self.clocksync.get_clock(eventtime)
|
||||
def command_PINS(self, parts):
|
||||
mcu = self.ser.msgparser.get_constant('MCU')
|
||||
self.pins = pins.get_pin_map(mcu, parts[1])
|
||||
def command_SET(self, parts):
|
||||
val = parts[2]
|
||||
try:
|
||||
val = float(val)
|
||||
except ValueError:
|
||||
pass
|
||||
self.eval_globals[parts[1]] = val
|
||||
def command_DELAY(self, parts):
|
||||
try:
|
||||
val = int(parts[1])
|
||||
except ValueError as e:
|
||||
self.output("Error: %s" % (str(e),))
|
||||
return
|
||||
try:
|
||||
msg = self.ser.msgparser.create_command(' '.join(parts[2:]))
|
||||
except msgproto.error as e:
|
||||
self.output("Error: %s" % (str(e),))
|
||||
return
|
||||
self.ser.send(msg, minclock=val)
|
||||
def command_FLOOD(self, parts):
|
||||
try:
|
||||
count = int(parts[1])
|
||||
delay = float(parts[2])
|
||||
except ValueError as e:
|
||||
self.output("Error: %s" % (str(e),))
|
||||
return
|
||||
try:
|
||||
msg = self.ser.msgparser.create_command(' '.join(parts[3:]))
|
||||
except msgproto.error as e:
|
||||
self.output("Error: %s" % (str(e),))
|
||||
return
|
||||
delay_clock = int(delay * self.mcu_freq)
|
||||
msg_clock = int(self.clocksync.get_clock(self.reactor.monotonic())
|
||||
+ self.mcu_freq * .200)
|
||||
for i in range(count):
|
||||
next_clock = msg_clock + delay_clock
|
||||
self.ser.send(msg, minclock=msg_clock, reqclock=next_clock)
|
||||
msg_clock = next_clock
|
||||
def command_SUPPRESS(self, parts):
|
||||
oid = None
|
||||
try:
|
||||
name = parts[1]
|
||||
if len(parts) > 2:
|
||||
oid = int(parts[2])
|
||||
except ValueError as e:
|
||||
self.output("Error: %s" % (str(e),))
|
||||
return
|
||||
self.ser.register_callback(self.handle_suppress, name, oid)
|
||||
def command_STATS(self, parts):
|
||||
curtime = self.reactor.monotonic()
|
||||
self.output(' '.join([self.ser.stats(curtime),
|
||||
self.clocksync.stats(curtime)]))
|
||||
def command_LIST(self, parts):
|
||||
self.update_evals(self.reactor.monotonic())
|
||||
mp = self.ser.msgparser
|
||||
out = "Available mcu commands:"
|
||||
out += "\n ".join([""] + sorted([
|
||||
mp.messages_by_id[i].msgformat for i in mp.command_ids]))
|
||||
out += "\nAvailable artificial commands:"
|
||||
out += "\n ".join([""] + [n for n in sorted(self.local_commands)])
|
||||
out += "\nAvailable local variables:"
|
||||
out += "\n ".join([""] + ["%s: %s" % (k, v)
|
||||
for k, v in sorted(self.eval_globals.items())])
|
||||
self.output(out)
|
||||
def command_HELP(self, parts):
|
||||
self.output(help_txt)
|
||||
def translate(self, line, eventtime):
|
||||
evalparts = re_eval.split(line)
|
||||
if len(evalparts) > 1:
|
||||
self.update_evals(eventtime)
|
||||
try:
|
||||
for i in range(1, len(evalparts), 2):
|
||||
e = eval(evalparts[i], dict(self.eval_globals))
|
||||
if type(e) == type(0.):
|
||||
e = int(e)
|
||||
evalparts[i] = str(e)
|
||||
except:
|
||||
self.output("Unable to evaluate: %s" % (line,))
|
||||
return None
|
||||
line = ''.join(evalparts)
|
||||
self.output("Eval: %s" % (line,))
|
||||
if self.pins is not None:
|
||||
try:
|
||||
line = pins.update_command(line, self.pins).strip()
|
||||
except:
|
||||
self.output("Unable to map pin: %s" % (line,))
|
||||
return None
|
||||
if line:
|
||||
parts = line.split()
|
||||
if parts[0] in self.local_commands:
|
||||
self.local_commands[parts[0]](parts)
|
||||
return None
|
||||
try:
|
||||
msg = self.ser.msgparser.create_command(line)
|
||||
except msgproto.error as e:
|
||||
self.output("Error: %s" % (str(e),))
|
||||
return None
|
||||
return msg
|
||||
def process_kbd(self, eventtime):
|
||||
self.data += os.read(self.fd, 4096)
|
||||
|
||||
kbdlines = self.data.split('\n')
|
||||
for line in kbdlines[:-1]:
|
||||
line = line.strip()
|
||||
cpos = line.find('#')
|
||||
if cpos >= 0:
|
||||
line = line[:cpos]
|
||||
if not line:
|
||||
continue
|
||||
msg = self.translate(line.strip(), eventtime)
|
||||
if msg is None:
|
||||
continue
|
||||
self.ser.send(msg)
|
||||
self.data = kbdlines[-1]
|
||||
|
||||
def main():
|
||||
usage = "%prog [options] <serialdevice> <baud>"
|
||||
opts = optparse.OptionParser(usage)
|
||||
options, args = opts.parse_args()
|
||||
serialport, baud = args
|
||||
baud = int(baud)
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
r = reactor.Reactor()
|
||||
ser = serialhdl.SerialReader(r, serialport, baud)
|
||||
kbd = KeyboardReader(ser, r)
|
||||
try:
|
||||
r.run()
|
||||
except KeyboardInterrupt:
|
||||
sys.stdout.write("\n")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
150
klippy/corexy.py
Normal file
@@ -0,0 +1,150 @@
|
||||
# Code for handling the kinematics of corexy robots
|
||||
#
|
||||
# Copyright (C) 2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import logging, math
|
||||
import stepper, homing
|
||||
|
||||
StepList = (0, 1, 2)
|
||||
|
||||
class CoreXYKinematics:
|
||||
def __init__(self, toolhead, printer, config):
|
||||
self.steppers = [stepper.PrinterHomingStepper(
|
||||
printer, config.getsection('stepper_' + n), n)
|
||||
for n in ['x', 'y', 'z']]
|
||||
self.steppers[0].mcu_endstop.add_stepper(self.steppers[1].mcu_stepper)
|
||||
self.steppers[1].mcu_endstop.add_stepper(self.steppers[0].mcu_stepper)
|
||||
max_velocity, max_accel = toolhead.get_max_velocity()
|
||||
self.max_z_velocity = config.getfloat(
|
||||
'max_z_velocity', max_velocity, above=0., maxval=max_velocity)
|
||||
self.max_z_accel = config.getfloat(
|
||||
'max_z_accel', max_accel, above=0., maxval=max_accel)
|
||||
self.need_motor_enable = True
|
||||
self.limits = [(1.0, -1.0)] * 3
|
||||
# Setup stepper max halt velocity
|
||||
max_halt_velocity = toolhead.get_max_axis_halt()
|
||||
max_xy_halt_velocity = max_halt_velocity * math.sqrt(2.)
|
||||
self.steppers[0].set_max_jerk(max_xy_halt_velocity, max_accel)
|
||||
self.steppers[1].set_max_jerk(max_xy_halt_velocity, max_accel)
|
||||
self.steppers[2].set_max_jerk(
|
||||
min(max_halt_velocity, self.max_z_velocity), self.max_z_accel)
|
||||
def set_position(self, newpos):
|
||||
pos = (newpos[0] + newpos[1], newpos[0] - newpos[1], newpos[2])
|
||||
for i in StepList:
|
||||
self.steppers[i].mcu_stepper.set_position(pos[i])
|
||||
def home(self, homing_state):
|
||||
# Each axis is homed independently and in order
|
||||
for axis in homing_state.get_axes():
|
||||
s = self.steppers[axis]
|
||||
self.limits[axis] = (s.position_min, s.position_max)
|
||||
# Determine moves
|
||||
if s.homing_positive_dir:
|
||||
pos = s.position_endstop - 1.5*(
|
||||
s.position_endstop - s.position_min)
|
||||
rpos = s.position_endstop - s.homing_retract_dist
|
||||
r2pos = rpos - s.homing_retract_dist
|
||||
else:
|
||||
pos = s.position_endstop + 1.5*(
|
||||
s.position_max - s.position_endstop)
|
||||
rpos = s.position_endstop + s.homing_retract_dist
|
||||
r2pos = rpos + s.homing_retract_dist
|
||||
# Initial homing
|
||||
homing_speed = s.get_homing_speed()
|
||||
homepos = [None, None, None, None]
|
||||
homepos[axis] = s.position_endstop
|
||||
coord = [None, None, None, None]
|
||||
coord[axis] = pos
|
||||
homing_state.home(list(coord), homepos, [s], homing_speed)
|
||||
# Retract
|
||||
coord[axis] = rpos
|
||||
homing_state.retract(list(coord), homing_speed)
|
||||
# Home again
|
||||
coord[axis] = r2pos
|
||||
homing_state.home(
|
||||
list(coord), homepos, [s], homing_speed/2.0, second_home=True)
|
||||
if axis == 2:
|
||||
# Support endstop phase detection on Z axis
|
||||
coord[axis] = s.position_endstop + s.get_homed_offset()
|
||||
homing_state.set_homed_position(coord)
|
||||
def query_endstops(self, print_time, query_flags):
|
||||
return homing.query_endstops(print_time, query_flags, self.steppers)
|
||||
def motor_off(self, print_time):
|
||||
self.limits = [(1.0, -1.0)] * 3
|
||||
for stepper in self.steppers:
|
||||
stepper.motor_enable(print_time, 0)
|
||||
self.need_motor_enable = True
|
||||
def _check_motor_enable(self, print_time, move):
|
||||
if move.axes_d[0] or move.axes_d[1]:
|
||||
self.steppers[0].motor_enable(print_time, 1)
|
||||
self.steppers[1].motor_enable(print_time, 1)
|
||||
if move.axes_d[2]:
|
||||
self.steppers[2].motor_enable(print_time, 1)
|
||||
need_motor_enable = False
|
||||
for i in StepList:
|
||||
need_motor_enable |= self.steppers[i].need_motor_enable
|
||||
self.need_motor_enable = need_motor_enable
|
||||
def _check_endstops(self, move):
|
||||
end_pos = move.end_pos
|
||||
for i in StepList:
|
||||
if (move.axes_d[i]
|
||||
and (end_pos[i] < self.limits[i][0]
|
||||
or end_pos[i] > self.limits[i][1])):
|
||||
if self.limits[i][0] > self.limits[i][1]:
|
||||
raise homing.EndstopMoveError(
|
||||
end_pos, "Must home axis first")
|
||||
raise homing.EndstopMoveError(end_pos)
|
||||
def check_move(self, move):
|
||||
limits = self.limits
|
||||
xpos, ypos = move.end_pos[:2]
|
||||
if (xpos < limits[0][0] or xpos > limits[0][1]
|
||||
or ypos < limits[1][0] or ypos > limits[1][1]):
|
||||
self._check_endstops(move)
|
||||
if not move.axes_d[2]:
|
||||
# Normal XY move - use defaults
|
||||
return
|
||||
# Move with Z - update velocity and accel for slower Z axis
|
||||
self._check_endstops(move)
|
||||
z_ratio = move.move_d / abs(move.axes_d[2])
|
||||
move.limit_speed(
|
||||
self.max_z_velocity * z_ratio, self.max_z_accel * z_ratio)
|
||||
def move(self, print_time, move):
|
||||
if self.need_motor_enable:
|
||||
self._check_motor_enable(print_time, move)
|
||||
sxp = move.start_pos[0]
|
||||
syp = move.start_pos[1]
|
||||
move_start_pos = (sxp + syp, sxp - syp, move.start_pos[2])
|
||||
exp = move.end_pos[0]
|
||||
eyp = move.end_pos[1]
|
||||
axes_d = ((exp + eyp) - move_start_pos[0],
|
||||
(exp - eyp) - move_start_pos[1], move.axes_d[2])
|
||||
for i in StepList:
|
||||
axis_d = axes_d[i]
|
||||
if not axis_d:
|
||||
continue
|
||||
mcu_stepper = self.steppers[i].mcu_stepper
|
||||
move_time = print_time
|
||||
start_pos = move_start_pos[i]
|
||||
axis_r = abs(axis_d) / move.move_d
|
||||
accel = move.accel * axis_r
|
||||
cruise_v = move.cruise_v * axis_r
|
||||
|
||||
# Acceleration steps
|
||||
if move.accel_r:
|
||||
accel_d = move.accel_r * axis_d
|
||||
mcu_stepper.step_const(
|
||||
move_time, start_pos, accel_d, move.start_v * axis_r, accel)
|
||||
start_pos += accel_d
|
||||
move_time += move.accel_t
|
||||
# Cruising steps
|
||||
if move.cruise_r:
|
||||
cruise_d = move.cruise_r * axis_d
|
||||
mcu_stepper.step_const(
|
||||
move_time, start_pos, cruise_d, cruise_v, 0.)
|
||||
start_pos += cruise_d
|
||||
move_time += move.cruise_t
|
||||
# Deceleration steps
|
||||
if move.decel_r:
|
||||
decel_d = move.decel_r * axis_d
|
||||
mcu_stepper.step_const(
|
||||
move_time, start_pos, decel_d, cruise_v, -accel)
|
||||
245
klippy/delta.py
Normal file
@@ -0,0 +1,245 @@
|
||||
# Code for handling the kinematics of linear delta robots
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import math, logging
|
||||
import stepper, homing
|
||||
|
||||
StepList = (0, 1, 2)
|
||||
|
||||
# Slow moves once the ratio of tower to XY movement exceeds SLOW_RATIO
|
||||
SLOW_RATIO = 3.
|
||||
|
||||
class DeltaKinematics:
|
||||
def __init__(self, toolhead, printer, config):
|
||||
self.steppers = [stepper.PrinterHomingStepper(
|
||||
printer, config.getsection('stepper_' + n), n)
|
||||
for n in ['a', 'b', 'c']]
|
||||
self.need_motor_enable = self.need_home = True
|
||||
radius = config.getfloat('delta_radius', above=0.)
|
||||
arm_length = config.getfloat('delta_arm_length', above=radius)
|
||||
self.arm_length2 = arm_length**2
|
||||
self.limit_xy2 = -1.
|
||||
tower_height_at_zeros = math.sqrt(self.arm_length2 - radius**2)
|
||||
self.max_z = min([s.position_endstop for s in self.steppers])
|
||||
self.limit_z = self.max_z - (arm_length - tower_height_at_zeros)
|
||||
logging.info(
|
||||
"Delta max build height %.2fmm (radius tapered above %.2fmm)" % (
|
||||
self.max_z, self.limit_z))
|
||||
# Setup stepper max halt velocity
|
||||
self.max_velocity, self.max_accel = toolhead.get_max_velocity()
|
||||
self.max_z_velocity = config.getfloat(
|
||||
'max_z_velocity', self.max_velocity,
|
||||
above=0., maxval=self.max_velocity)
|
||||
max_halt_velocity = toolhead.get_max_axis_halt()
|
||||
for s in self.steppers:
|
||||
s.set_max_jerk(max_halt_velocity, self.max_accel)
|
||||
# Determine tower locations in cartesian space
|
||||
angles = [config.getsection('stepper_a').getfloat('angle', 210.),
|
||||
config.getsection('stepper_b').getfloat('angle', 330.),
|
||||
config.getsection('stepper_c').getfloat('angle', 90.)]
|
||||
self.towers = [(math.cos(math.radians(angle)) * radius,
|
||||
math.sin(math.radians(angle)) * radius)
|
||||
for angle in angles]
|
||||
# Find the point where an XY move could result in excessive
|
||||
# tower movement
|
||||
half_min_step_dist = min([s.step_dist for s in self.steppers]) * .5
|
||||
def ratio_to_dist(ratio):
|
||||
return (ratio * math.sqrt(self.arm_length2 / (ratio**2 + 1.)
|
||||
- half_min_step_dist**2)
|
||||
+ half_min_step_dist)
|
||||
self.slow_xy2 = (ratio_to_dist(SLOW_RATIO) - radius)**2
|
||||
self.very_slow_xy2 = (ratio_to_dist(2. * SLOW_RATIO) - radius)**2
|
||||
self.max_xy2 = min(radius, arm_length - radius,
|
||||
ratio_to_dist(4. * SLOW_RATIO) - radius)**2
|
||||
logging.info(
|
||||
"Delta max build radius %.2fmm (moves slowed past %.2fmm and %.2fmm)"
|
||||
% (math.sqrt(self.max_xy2), math.sqrt(self.slow_xy2),
|
||||
math.sqrt(self.very_slow_xy2)))
|
||||
self.set_position([0., 0., 0.])
|
||||
def _cartesian_to_actuator(self, coord):
|
||||
return [math.sqrt(self.arm_length2
|
||||
- (self.towers[i][0] - coord[0])**2
|
||||
- (self.towers[i][1] - coord[1])**2) + coord[2]
|
||||
for i in StepList]
|
||||
def _actuator_to_cartesian(self, pos):
|
||||
# Based on code from Smoothieware
|
||||
tower1 = list(self.towers[0]) + [pos[0]]
|
||||
tower2 = list(self.towers[1]) + [pos[1]]
|
||||
tower3 = list(self.towers[2]) + [pos[2]]
|
||||
|
||||
s12 = matrix_sub(tower1, tower2)
|
||||
s23 = matrix_sub(tower2, tower3)
|
||||
s13 = matrix_sub(tower1, tower3)
|
||||
|
||||
normal = matrix_cross(s12, s23)
|
||||
|
||||
magsq_s12 = matrix_magsq(s12)
|
||||
magsq_s23 = matrix_magsq(s23)
|
||||
magsq_s13 = matrix_magsq(s13)
|
||||
|
||||
inv_nmag_sq = 1.0 / matrix_magsq(normal)
|
||||
q = 0.5 * inv_nmag_sq
|
||||
|
||||
a = q * magsq_s23 * matrix_dot(s12, s13)
|
||||
b = -q * magsq_s13 * matrix_dot(s12, s23) # negate because we use s12 instead of s21
|
||||
c = q * magsq_s12 * matrix_dot(s13, s23)
|
||||
|
||||
circumcenter = [tower1[0] * a + tower2[0] * b + tower3[0] * c,
|
||||
tower1[1] * a + tower2[1] * b + tower3[1] * c,
|
||||
tower1[2] * a + tower2[2] * b + tower3[2] * c]
|
||||
|
||||
r_sq = 0.5 * q * magsq_s12 * magsq_s23 * magsq_s13
|
||||
dist = math.sqrt(inv_nmag_sq * (self.arm_length2 - r_sq))
|
||||
|
||||
return matrix_sub(circumcenter, matrix_mul(normal, dist))
|
||||
def set_position(self, newpos):
|
||||
pos = self._cartesian_to_actuator(newpos)
|
||||
for i in StepList:
|
||||
self.steppers[i].mcu_stepper.set_position(pos[i])
|
||||
self.limit_xy2 = -1.
|
||||
def home(self, homing_state):
|
||||
# All axes are homed simultaneously
|
||||
homing_state.set_axes([0, 1, 2])
|
||||
s = self.steppers[0] # Assume homing speed same for all steppers
|
||||
self.need_home = False
|
||||
# Initial homing
|
||||
homing_speed = s.get_homing_speed()
|
||||
homepos = [0., 0., self.max_z, None]
|
||||
coord = list(homepos)
|
||||
coord[2] = -1.5 * math.sqrt(self.arm_length2-self.max_xy2)
|
||||
homing_state.home(list(coord), homepos, self.steppers, homing_speed)
|
||||
# Retract
|
||||
coord[2] = homepos[2] - s.homing_retract_dist
|
||||
homing_state.retract(list(coord), homing_speed)
|
||||
# Home again
|
||||
coord[2] -= s.homing_retract_dist
|
||||
homing_state.home(list(coord), homepos, self.steppers
|
||||
, homing_speed/2.0, second_home=True)
|
||||
# Set final homed position
|
||||
spos = self._cartesian_to_actuator(homepos)
|
||||
spos = [spos[i] + self.steppers[i].position_endstop - self.max_z
|
||||
+ self.steppers[i].get_homed_offset()
|
||||
for i in StepList]
|
||||
homing_state.set_homed_position(self._actuator_to_cartesian(spos))
|
||||
def query_endstops(self, print_time, query_flags):
|
||||
return homing.query_endstops(print_time, query_flags, self.steppers)
|
||||
def motor_off(self, print_time):
|
||||
self.limit_xy2 = -1.
|
||||
for stepper in self.steppers:
|
||||
stepper.motor_enable(print_time, 0)
|
||||
self.need_motor_enable = self.need_home = True
|
||||
def _check_motor_enable(self, print_time):
|
||||
for i in StepList:
|
||||
self.steppers[i].motor_enable(print_time, 1)
|
||||
self.need_motor_enable = False
|
||||
def check_move(self, move):
|
||||
end_pos = move.end_pos
|
||||
xy2 = end_pos[0]**2 + end_pos[1]**2
|
||||
if xy2 <= self.limit_xy2 and not move.axes_d[2]:
|
||||
# Normal XY move
|
||||
return
|
||||
if self.need_home:
|
||||
raise homing.EndstopMoveError(end_pos, "Must home first")
|
||||
limit_xy2 = self.max_xy2
|
||||
if end_pos[2] > self.limit_z:
|
||||
limit_xy2 = min(limit_xy2, (self.max_z - end_pos[2])**2)
|
||||
if xy2 > limit_xy2 or end_pos[2] < 0. or end_pos[2] > self.max_z:
|
||||
raise homing.EndstopMoveError(end_pos)
|
||||
if move.axes_d[2]:
|
||||
move.limit_speed(self.max_z_velocity, move.accel)
|
||||
limit_xy2 = -1.
|
||||
# Limit the speed/accel of this move if is is at the extreme
|
||||
# end of the build envelope
|
||||
extreme_xy2 = max(xy2, move.start_pos[0]**2 + move.start_pos[1]**2)
|
||||
if extreme_xy2 > self.slow_xy2:
|
||||
r = 0.5
|
||||
if extreme_xy2 > self.very_slow_xy2:
|
||||
r = 0.25
|
||||
max_velocity = self.max_velocity
|
||||
if move.axes_d[2]:
|
||||
max_velocity = self.max_z_velocity
|
||||
move.limit_speed(max_velocity * r, self.max_accel * r)
|
||||
limit_xy2 = -1.
|
||||
self.limit_xy2 = min(limit_xy2, self.slow_xy2)
|
||||
def move(self, print_time, move):
|
||||
if self.need_motor_enable:
|
||||
self._check_motor_enable(print_time)
|
||||
axes_d = move.axes_d
|
||||
move_d = move.move_d
|
||||
movexy_r = 1.
|
||||
movez_r = 0.
|
||||
inv_movexy_d = 1. / move_d
|
||||
if not axes_d[0] and not axes_d[1]:
|
||||
# Z only move
|
||||
movez_r = axes_d[2] * inv_movexy_d
|
||||
movexy_r = inv_movexy_d = 0.
|
||||
elif axes_d[2]:
|
||||
# XY+Z move
|
||||
movexy_d = math.sqrt(axes_d[0]**2 + axes_d[1]**2)
|
||||
movexy_r = movexy_d * inv_movexy_d
|
||||
movez_r = axes_d[2] * inv_movexy_d
|
||||
inv_movexy_d = 1. / movexy_d
|
||||
|
||||
origx, origy, origz = move.start_pos[:3]
|
||||
|
||||
accel = move.accel
|
||||
cruise_v = move.cruise_v
|
||||
accel_d = move.accel_r * move_d
|
||||
cruise_d = move.cruise_r * move_d
|
||||
decel_d = move.decel_r * move_d
|
||||
|
||||
for i in StepList:
|
||||
# Calculate a virtual tower along the line of movement at
|
||||
# the point closest to this stepper's tower.
|
||||
towerx_d = self.towers[i][0] - origx
|
||||
towery_d = self.towers[i][1] - origy
|
||||
vt_startxy_d = (towerx_d*axes_d[0] + towery_d*axes_d[1])*inv_movexy_d
|
||||
tangentxy_d2 = towerx_d**2 + towery_d**2 - vt_startxy_d**2
|
||||
vt_arm_d = math.sqrt(self.arm_length2 - tangentxy_d2)
|
||||
vt_startz = origz
|
||||
|
||||
# Generate steps
|
||||
mcu_stepper = self.steppers[i].mcu_stepper
|
||||
move_time = print_time
|
||||
if accel_d:
|
||||
mcu_stepper.step_delta(
|
||||
move_time, accel_d, move.start_v, accel,
|
||||
vt_startz, vt_startxy_d, vt_arm_d, movez_r)
|
||||
vt_startz += accel_d * movez_r
|
||||
vt_startxy_d -= accel_d * movexy_r
|
||||
move_time += move.accel_t
|
||||
if cruise_d:
|
||||
mcu_stepper.step_delta(
|
||||
move_time, cruise_d, cruise_v, 0.,
|
||||
vt_startz, vt_startxy_d, vt_arm_d, movez_r)
|
||||
vt_startz += cruise_d * movez_r
|
||||
vt_startxy_d -= cruise_d * movexy_r
|
||||
move_time += move.cruise_t
|
||||
if decel_d:
|
||||
mcu_stepper.step_delta(
|
||||
move_time, decel_d, cruise_v, -accel,
|
||||
vt_startz, vt_startxy_d, vt_arm_d, movez_r)
|
||||
|
||||
|
||||
######################################################################
|
||||
# Matrix helper functions for 3x1 matrices
|
||||
######################################################################
|
||||
|
||||
def matrix_cross(m1, m2):
|
||||
return [m1[1] * m2[2] - m1[2] * m2[1],
|
||||
m1[2] * m2[0] - m1[0] * m2[2],
|
||||
m1[0] * m2[1] - m1[1] * m2[0]]
|
||||
|
||||
def matrix_dot(m1, m2):
|
||||
return m1[0] * m2[0] + m1[1] * m2[1] + m1[2] * m2[2]
|
||||
|
||||
def matrix_magsq(m1):
|
||||
return m1[0]**2 + m1[1]**2 + m1[2]**2
|
||||
|
||||
def matrix_sub(m1, m2):
|
||||
return [m1[0] - m2[0], m1[1] - m2[1], m1[2] - m2[2]]
|
||||
|
||||
def matrix_mul(m1, s):
|
||||
return [m1[0]*s, m1[1]*s, m1[2]*s]
|
||||
260
klippy/extruder.py
Normal file
@@ -0,0 +1,260 @@
|
||||
# Code for handling printer nozzle extruders
|
||||
#
|
||||
# Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import math, logging
|
||||
import stepper, heater, homing
|
||||
|
||||
EXTRUDE_DIFF_IGNORE = 1.02
|
||||
|
||||
class PrinterExtruder:
|
||||
def __init__(self, printer, config):
|
||||
self.config = config
|
||||
self.heater = heater.PrinterHeater(printer, config)
|
||||
self.stepper = stepper.PrinterStepper(printer, config, 'extruder')
|
||||
self.nozzle_diameter = config.getfloat('nozzle_diameter', above=0.)
|
||||
filament_diameter = config.getfloat(
|
||||
'filament_diameter', minval=self.nozzle_diameter)
|
||||
self.filament_area = math.pi * (filament_diameter * .5)**2
|
||||
max_cross_section = config.getfloat(
|
||||
'max_extrude_cross_section', 4. * self.nozzle_diameter**2
|
||||
, above=0.)
|
||||
self.max_extrude_ratio = max_cross_section / self.filament_area
|
||||
toolhead = printer.objects['toolhead']
|
||||
max_velocity, max_accel = toolhead.get_max_velocity()
|
||||
self.max_e_velocity = self.config.getfloat(
|
||||
'max_extrude_only_velocity', max_velocity * self.max_extrude_ratio
|
||||
, above=0.)
|
||||
self.max_e_accel = self.config.getfloat(
|
||||
'max_extrude_only_accel', max_accel * self.max_extrude_ratio
|
||||
, above=0.)
|
||||
self.stepper.set_max_jerk(9999999.9, 9999999.9)
|
||||
self.max_e_dist = config.getfloat(
|
||||
'max_extrude_only_distance', 50., minval=0.)
|
||||
self.activate_gcode = config.get('activate_gcode', '')
|
||||
self.deactivate_gcode = config.get('deactivate_gcode', '')
|
||||
self.pressure_advance = config.getfloat(
|
||||
'pressure_advance', 0., minval=0.)
|
||||
self.pressure_advance_lookahead_time = 0.
|
||||
if self.pressure_advance:
|
||||
self.pressure_advance_lookahead_time = config.getfloat(
|
||||
'pressure_advance_lookahead_time', 0.010, minval=0.)
|
||||
self.need_motor_enable = True
|
||||
self.extrude_pos = 0.
|
||||
def get_heater(self):
|
||||
return self.heater
|
||||
def set_active(self, print_time, is_active):
|
||||
return self.extrude_pos
|
||||
def get_activate_gcode(self, is_active):
|
||||
if is_active:
|
||||
return self.activate_gcode
|
||||
return self.deactivate_gcode
|
||||
def motor_off(self, print_time):
|
||||
self.stepper.motor_enable(print_time, 0)
|
||||
self.need_motor_enable = True
|
||||
def check_move(self, move):
|
||||
move.extrude_r = move.axes_d[3] / move.move_d
|
||||
move.extrude_max_corner_v = 0.
|
||||
if not self.heater.can_extrude:
|
||||
raise homing.EndstopError(
|
||||
"Extrude below minimum temp\n"
|
||||
"See the 'min_extrude_temp' config option for details")
|
||||
if not move.is_kinematic_move or move.extrude_r < 0.:
|
||||
# Extrude only move (or retraction move) - limit accel and velocity
|
||||
if abs(move.axes_d[3]) > self.max_e_dist:
|
||||
raise homing.EndstopError(
|
||||
"Extrude only move too long (%.3fmm vs %.3fmm)\n"
|
||||
"See the 'max_extrude_only_distance' config"
|
||||
" option for details" % (move.axes_d[3], self.max_e_dist))
|
||||
inv_extrude_r = 1. / abs(move.extrude_r)
|
||||
move.limit_speed(self.max_e_velocity * inv_extrude_r
|
||||
, self.max_e_accel * inv_extrude_r)
|
||||
elif (move.extrude_r > self.max_extrude_ratio
|
||||
and move.axes_d[3] > self.nozzle_diameter*self.max_extrude_ratio):
|
||||
area = move.axes_d[3] * self.filament_area / move.move_d
|
||||
logging.debug("Overextrude: %s vs %s (area=%.3f dist=%.3f)",
|
||||
move.extrude_r, self.max_extrude_ratio,
|
||||
area, move.move_d)
|
||||
raise homing.EndstopError(
|
||||
"Move exceeds maximum extrusion (%.3fmm^2 vs %.3fmm^2)\n"
|
||||
"See the 'max_extrude_cross_section' config option for details"
|
||||
% (area, self.max_extrude_ratio * self.filament_area))
|
||||
def calc_junction(self, prev_move, move):
|
||||
extrude = move.axes_d[3]
|
||||
prev_extrude = prev_move.axes_d[3]
|
||||
if extrude or prev_extrude:
|
||||
if not extrude or not prev_extrude:
|
||||
# Extrude move to non-extrude move - disable lookahead
|
||||
return 0.
|
||||
if ((move.extrude_r > prev_move.extrude_r * EXTRUDE_DIFF_IGNORE
|
||||
or prev_move.extrude_r > move.extrude_r * EXTRUDE_DIFF_IGNORE)
|
||||
and abs(move.move_d * prev_move.extrude_r - extrude) >= .001):
|
||||
# Extrude ratio between moves is too different
|
||||
return 0.
|
||||
move.extrude_r = prev_move.extrude_r
|
||||
return move.max_cruise_v2
|
||||
def lookahead(self, moves, flush_count, lazy):
|
||||
lookahead_t = self.pressure_advance_lookahead_time
|
||||
if not lookahead_t:
|
||||
return flush_count
|
||||
# Calculate max_corner_v - the speed the head will accelerate
|
||||
# to after cornering.
|
||||
for i in range(flush_count):
|
||||
move = moves[i]
|
||||
if not move.decel_t:
|
||||
continue
|
||||
cruise_v = move.cruise_v
|
||||
max_corner_v = 0.
|
||||
sum_t = lookahead_t
|
||||
for j in range(i+1, flush_count):
|
||||
fmove = moves[j]
|
||||
if not fmove.max_start_v2:
|
||||
break
|
||||
if fmove.cruise_v > max_corner_v:
|
||||
if (not max_corner_v
|
||||
and not fmove.accel_t and not fmove.cruise_t):
|
||||
# Start timing after any full decel moves
|
||||
continue
|
||||
if sum_t >= fmove.accel_t:
|
||||
max_corner_v = fmove.cruise_v
|
||||
else:
|
||||
max_corner_v = max(
|
||||
max_corner_v, fmove.start_v + fmove.accel * sum_t)
|
||||
if max_corner_v >= cruise_v:
|
||||
break
|
||||
sum_t -= fmove.accel_t + fmove.cruise_t + fmove.decel_t
|
||||
if sum_t <= 0.:
|
||||
break
|
||||
else:
|
||||
if lazy:
|
||||
return i
|
||||
move.extrude_max_corner_v = max_corner_v
|
||||
return flush_count
|
||||
def move(self, print_time, move):
|
||||
if self.need_motor_enable:
|
||||
self.stepper.motor_enable(print_time, 1)
|
||||
self.need_motor_enable = False
|
||||
axis_d = move.axes_d[3]
|
||||
axis_r = abs(axis_d) / move.move_d
|
||||
accel = move.accel * axis_r
|
||||
start_v = move.start_v * axis_r
|
||||
cruise_v = move.cruise_v * axis_r
|
||||
end_v = move.end_v * axis_r
|
||||
accel_t, cruise_t, decel_t = move.accel_t, move.cruise_t, move.decel_t
|
||||
accel_d = move.accel_r * axis_d
|
||||
cruise_d = move.cruise_r * axis_d
|
||||
decel_d = move.decel_r * axis_d
|
||||
|
||||
retract_t = retract_d = retract_v = 0.
|
||||
decel_v = cruise_v
|
||||
|
||||
# Update for pressure advance
|
||||
start_pos = self.extrude_pos
|
||||
if (axis_d >= 0. and (move.axes_d[0] or move.axes_d[1])
|
||||
and self.pressure_advance):
|
||||
# Increase accel_d and start_v when accelerating
|
||||
pressure_advance = self.pressure_advance * move.extrude_r
|
||||
prev_pressure_d = start_pos - move.start_pos[3]
|
||||
if accel_d:
|
||||
npd = move.cruise_v * pressure_advance
|
||||
extra_accel_d = npd - prev_pressure_d
|
||||
if extra_accel_d > 0.:
|
||||
accel_d += extra_accel_d
|
||||
start_v += extra_accel_d / accel_t
|
||||
prev_pressure_d += extra_accel_d
|
||||
# Update decel and retract parameters when decelerating
|
||||
emcv = move.extrude_max_corner_v
|
||||
if decel_d and emcv < move.cruise_v:
|
||||
npd = max(emcv, move.end_v) * pressure_advance
|
||||
extra_decel_d = prev_pressure_d - npd
|
||||
if extra_decel_d > 0.:
|
||||
extra_decel_v = extra_decel_d / decel_t
|
||||
decel_v -= extra_decel_v
|
||||
end_v -= extra_decel_v
|
||||
if decel_v <= 0.:
|
||||
# The entire decel phase is replaced with retraction
|
||||
retract_t = decel_t
|
||||
retract_d = -(end_v + decel_v) * 0.5 * decel_t
|
||||
retract_v = -decel_v
|
||||
decel_t = decel_d = 0.
|
||||
elif end_v < 0.:
|
||||
# Split decel phase into decel and retraction
|
||||
retract_t = -end_v / accel
|
||||
retract_d = -end_v * 0.5 * retract_t
|
||||
decel_t -= retract_t
|
||||
decel_d = decel_v * 0.5 * decel_t
|
||||
else:
|
||||
# There is still only a decel phase (no retraction)
|
||||
decel_d -= extra_decel_d
|
||||
|
||||
# Prepare for steps
|
||||
mcu_stepper = self.stepper.mcu_stepper
|
||||
move_time = print_time
|
||||
|
||||
# Acceleration steps
|
||||
if accel_d:
|
||||
mcu_stepper.step_const(move_time, start_pos, accel_d, start_v, accel)
|
||||
start_pos += accel_d
|
||||
move_time += accel_t
|
||||
# Cruising steps
|
||||
if cruise_d:
|
||||
mcu_stepper.step_const(move_time, start_pos, cruise_d, cruise_v, 0.)
|
||||
start_pos += cruise_d
|
||||
move_time += cruise_t
|
||||
# Deceleration steps
|
||||
if decel_d:
|
||||
mcu_stepper.step_const(
|
||||
move_time, start_pos, decel_d, decel_v, -accel)
|
||||
start_pos += decel_d
|
||||
move_time += decel_t
|
||||
# Retraction steps
|
||||
if retract_d:
|
||||
mcu_stepper.step_const(
|
||||
move_time, start_pos, -retract_d, retract_v, accel)
|
||||
start_pos -= retract_d
|
||||
self.extrude_pos = start_pos
|
||||
|
||||
# Dummy extruder class used when a printer has no extruder at all
|
||||
class DummyExtruder:
|
||||
def set_active(self, print_time, is_active):
|
||||
return 0.
|
||||
def motor_off(self, move_time):
|
||||
pass
|
||||
def check_move(self, move):
|
||||
raise homing.EndstopMoveError(
|
||||
move.end_pos, "Extrude when no extruder present")
|
||||
def calc_junction(self, prev_move, move):
|
||||
return move.max_cruise_v2
|
||||
def lookahead(self, moves, flush_count, lazy):
|
||||
return flush_count
|
||||
|
||||
def add_printer_objects(printer, config):
|
||||
for i in range(99):
|
||||
section = 'extruder%d' % (i,)
|
||||
if not config.has_section(section):
|
||||
if not i and config.has_section('extruder'):
|
||||
printer.add_object('extruder0', PrinterExtruder(
|
||||
printer, config.getsection('extruder')))
|
||||
continue
|
||||
break
|
||||
printer.add_object(section, PrinterExtruder(
|
||||
printer, config.getsection(section)))
|
||||
|
||||
def get_printer_extruders(printer):
|
||||
out = []
|
||||
for i in range(99):
|
||||
extruder = printer.objects.get('extruder%d' % (i,))
|
||||
if extruder is None:
|
||||
break
|
||||
out.append(extruder)
|
||||
return out
|
||||
|
||||
def get_printer_heater(printer, name):
|
||||
if name == 'heater_bed' and name in printer.objects:
|
||||
return printer.objects[name]
|
||||
if name == 'extruder':
|
||||
name = 'extruder0'
|
||||
if name.startswith('extruder') and name in printer.objects:
|
||||
return printer.objects[name].get_heater()
|
||||
raise printer.config_error("Unknown heater '%s'" % (name,))
|
||||
63
klippy/fan.py
Normal file
@@ -0,0 +1,63 @@
|
||||
# Printer fan support
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import extruder, pins
|
||||
|
||||
FAN_MIN_TIME = 0.1
|
||||
PWM_CYCLE_TIME = 0.010
|
||||
|
||||
class PrinterFan:
|
||||
def __init__(self, printer, config):
|
||||
self.last_fan_value = 0.
|
||||
self.last_fan_time = 0.
|
||||
self.max_power = config.getfloat('max_power', 1., above=0., maxval=1.)
|
||||
self.kick_start_time = config.getfloat('kick_start_time', 0.1, minval=0.)
|
||||
self.mcu_fan = pins.setup_pin(printer, 'pwm', config.get('pin'))
|
||||
self.mcu_fan.setup_max_duration(0.)
|
||||
self.mcu_fan.setup_cycle_time(PWM_CYCLE_TIME)
|
||||
self.mcu_fan.setup_hard_pwm(config.getint('hard_pwm', 0))
|
||||
def set_speed(self, print_time, value):
|
||||
value = max(0., min(self.max_power, value))
|
||||
if value == self.last_fan_value:
|
||||
return
|
||||
print_time = max(self.last_fan_time + FAN_MIN_TIME, print_time)
|
||||
if (value and value < self.max_power
|
||||
and not self.last_fan_value and self.kick_start_time):
|
||||
# Run fan at full speed for specified kick_start_time
|
||||
self.mcu_fan.set_pwm(print_time, self.max_power)
|
||||
print_time += self.kick_start_time
|
||||
self.mcu_fan.set_pwm(print_time, value)
|
||||
self.last_fan_time = print_time
|
||||
self.last_fan_value = value
|
||||
|
||||
class PrinterHeaterFan:
|
||||
def __init__(self, printer, config):
|
||||
self.fan = PrinterFan(printer, config)
|
||||
self.mcu = printer.objects['mcu']
|
||||
heater = config.get("heater", "extruder0")
|
||||
self.heater = extruder.get_printer_heater(printer, heater)
|
||||
self.heater_temp = config.getfloat("heater_temp", 50.0)
|
||||
max_power = self.fan.max_power
|
||||
self.fan_speed = config.getfloat(
|
||||
"fan_speed", max_power, minval=0., maxval=max_power)
|
||||
self.fan.mcu_fan.setup_shutdown_value(max_power)
|
||||
printer.reactor.register_timer(self.callback, printer.reactor.NOW)
|
||||
def callback(self, eventtime):
|
||||
current_temp, target_temp = self.heater.get_temp(eventtime)
|
||||
if not current_temp and not target_temp and not self.fan.last_fan_time:
|
||||
# Printer still starting
|
||||
return eventtime + 1.
|
||||
power = 0.
|
||||
if target_temp or current_temp > self.heater_temp:
|
||||
power = self.fan_speed
|
||||
print_time = self.mcu.estimated_print_time(eventtime) + FAN_MIN_TIME
|
||||
self.fan.set_speed(print_time, power)
|
||||
return eventtime + 1.
|
||||
|
||||
def add_printer_objects(printer, config):
|
||||
if config.has_section('fan'):
|
||||
printer.add_object('fan', PrinterFan(printer, config.getsection('fan')))
|
||||
for s in config.get_prefix_sections('heater_fan '):
|
||||
printer.add_object(s.section, PrinterHeaterFan(printer, s))
|
||||
523
klippy/gcode.py
Normal file
@@ -0,0 +1,523 @@
|
||||
# Parse gcode commands
|
||||
#
|
||||
# Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import os, re, logging, collections
|
||||
import homing, extruder, chipmisc
|
||||
|
||||
# Parse out incoming GCode and find and translate head movements
|
||||
class GCodeParser:
|
||||
RETRY_TIME = 0.100
|
||||
def __init__(self, printer, fd):
|
||||
self.printer = printer
|
||||
self.fd = fd
|
||||
# Input handling
|
||||
self.reactor = printer.reactor
|
||||
self.is_processing_data = False
|
||||
self.is_fileinput = not not printer.get_start_args().get("debuginput")
|
||||
self.fd_handle = None
|
||||
if not self.is_fileinput:
|
||||
self.fd_handle = self.reactor.register_fd(self.fd, self.process_data)
|
||||
self.partial_input = ""
|
||||
self.bytes_read = 0
|
||||
self.input_log = collections.deque([], 50)
|
||||
# Command handling
|
||||
self.is_printer_ready = False
|
||||
self.gcode_handlers = {}
|
||||
self.build_handlers()
|
||||
self.need_ack = False
|
||||
self.toolhead = self.fan = self.extruder = None
|
||||
self.heaters = []
|
||||
self.speed = 25.0
|
||||
self.absolutecoord = self.absoluteextrude = True
|
||||
self.base_position = [0.0, 0.0, 0.0, 0.0]
|
||||
self.last_position = [0.0, 0.0, 0.0, 0.0]
|
||||
self.homing_add = [0.0, 0.0, 0.0, 0.0]
|
||||
self.axis2pos = {'X': 0, 'Y': 1, 'Z': 2, 'E': 3}
|
||||
def build_handlers(self):
|
||||
handlers = self.all_handlers
|
||||
if not self.is_printer_ready:
|
||||
handlers = [h for h in handlers
|
||||
if getattr(self, 'cmd_'+h+'_when_not_ready', False)]
|
||||
gcode_handlers = { h: getattr(self, 'cmd_'+h) for h in handlers }
|
||||
for h, f in list(gcode_handlers.items()):
|
||||
aliases = getattr(self, 'cmd_'+h+'_aliases', [])
|
||||
gcode_handlers.update({ a: f for a in aliases })
|
||||
self.gcode_handlers = gcode_handlers
|
||||
def stats(self, eventtime):
|
||||
return "gcodein=%d" % (self.bytes_read,)
|
||||
def connect(self):
|
||||
self.is_printer_ready = True
|
||||
self.build_handlers()
|
||||
# Lookup printer components
|
||||
self.toolhead = self.printer.objects.get('toolhead')
|
||||
extruders = extruder.get_printer_extruders(self.printer)
|
||||
if extruders:
|
||||
self.extruder = extruders[0]
|
||||
self.toolhead.set_extruder(self.extruder)
|
||||
self.heaters = [ e.get_heater() for e in extruders ]
|
||||
self.heaters.append(self.printer.objects.get('heater_bed'))
|
||||
self.fan = self.printer.objects.get('fan')
|
||||
if self.is_fileinput and self.fd_handle is None:
|
||||
self.fd_handle = self.reactor.register_fd(self.fd, self.process_data)
|
||||
def do_shutdown(self):
|
||||
if not self.is_printer_ready:
|
||||
return
|
||||
self.is_printer_ready = False
|
||||
self.build_handlers()
|
||||
self.dump_debug()
|
||||
if self.is_fileinput:
|
||||
self.printer.request_exit()
|
||||
def motor_heater_off(self):
|
||||
if self.toolhead is None:
|
||||
return
|
||||
self.toolhead.motor_off()
|
||||
print_time = self.toolhead.get_last_move_time()
|
||||
for heater in self.heaters:
|
||||
if heater is not None:
|
||||
heater.set_temp(print_time, 0.)
|
||||
if self.fan is not None:
|
||||
self.fan.set_speed(print_time, 0.)
|
||||
def dump_debug(self):
|
||||
out = []
|
||||
out.append("Dumping gcode input %d blocks" % (
|
||||
len(self.input_log),))
|
||||
for eventtime, data in self.input_log:
|
||||
out.append("Read %f: %s" % (eventtime, repr(data)))
|
||||
logging.info("\n".join(out))
|
||||
# Parse input into commands
|
||||
args_r = re.compile('([A-Z_]+|[A-Z*])')
|
||||
def process_commands(self, commands, need_ack=True):
|
||||
prev_need_ack = self.need_ack
|
||||
for line in commands:
|
||||
# Ignore comments and leading/trailing spaces
|
||||
line = origline = line.strip()
|
||||
cpos = line.find(';')
|
||||
if cpos >= 0:
|
||||
line = line[:cpos]
|
||||
# Break command into parts
|
||||
parts = self.args_r.split(line.upper())[1:]
|
||||
params = { parts[i]: parts[i+1].strip()
|
||||
for i in range(0, len(parts), 2) }
|
||||
params['#original'] = origline
|
||||
if parts and parts[0] == 'N':
|
||||
# Skip line number at start of command
|
||||
del parts[:2]
|
||||
if not parts:
|
||||
self.cmd_default(params)
|
||||
continue
|
||||
params['#command'] = cmd = parts[0] + parts[1].strip()
|
||||
# Invoke handler for command
|
||||
self.need_ack = need_ack
|
||||
handler = self.gcode_handlers.get(cmd, self.cmd_default)
|
||||
try:
|
||||
handler(params)
|
||||
except error as e:
|
||||
self.respond_error(str(e))
|
||||
except:
|
||||
msg = 'Internal error on command:"%s"' % (cmd,)
|
||||
logging.exception(msg)
|
||||
self.printer.invoke_shutdown(msg)
|
||||
self.respond_error(msg)
|
||||
self.ack()
|
||||
self.need_ack = prev_need_ack
|
||||
def process_data(self, eventtime):
|
||||
data = os.read(self.fd, 4096)
|
||||
self.input_log.append((eventtime, data))
|
||||
self.bytes_read += len(data)
|
||||
lines = data.split('\n')
|
||||
lines[0] = self.partial_input + lines[0]
|
||||
self.partial_input = lines.pop()
|
||||
if self.is_processing_data:
|
||||
if not self.is_fileinput and not lines:
|
||||
return
|
||||
self.reactor.unregister_fd(self.fd_handle)
|
||||
self.fd_handle = None
|
||||
if not self.is_fileinput and lines[0].strip().upper() == 'M112':
|
||||
self.cmd_M112({})
|
||||
while self.is_processing_data:
|
||||
eventtime = self.reactor.pause(eventtime + 0.100)
|
||||
self.fd_handle = self.reactor.register_fd(self.fd, self.process_data)
|
||||
self.is_processing_data = True
|
||||
self.process_commands(lines)
|
||||
if not data and self.is_fileinput:
|
||||
self.motor_heater_off()
|
||||
if self.toolhead is not None:
|
||||
self.toolhead.wait_moves()
|
||||
self.printer.request_exit()
|
||||
self.is_processing_data = False
|
||||
# Response handling
|
||||
def ack(self, msg=None):
|
||||
if not self.need_ack or self.is_fileinput:
|
||||
return
|
||||
if msg:
|
||||
os.write(self.fd, "ok %s\n" % (msg,))
|
||||
else:
|
||||
os.write(self.fd, "ok\n")
|
||||
self.need_ack = False
|
||||
def respond(self, msg):
|
||||
if self.is_fileinput:
|
||||
return
|
||||
os.write(self.fd, msg+"\n")
|
||||
def respond_info(self, msg):
|
||||
logging.debug(msg)
|
||||
lines = [l.strip() for l in msg.strip().split('\n')]
|
||||
self.respond("// " + "\n// ".join(lines))
|
||||
def respond_error(self, msg):
|
||||
logging.warning(msg)
|
||||
lines = msg.strip().split('\n')
|
||||
if len(lines) > 1:
|
||||
self.respond_info("\n".join(lines[:-1]))
|
||||
self.respond('!! %s' % (lines[-1].strip(),))
|
||||
# Parameter parsing helpers
|
||||
def get_int(self, name, params, default=None):
|
||||
if name in params:
|
||||
try:
|
||||
return int(params[name])
|
||||
except ValueError:
|
||||
raise error("Error on '%s': unable to parse %s" % (
|
||||
params['#original'], params[name]))
|
||||
if default is not None:
|
||||
return default
|
||||
raise error("Error on '%s': missing %s" % (params['#original'], name))
|
||||
def get_float(self, name, params, default=None):
|
||||
if name in params:
|
||||
try:
|
||||
return float(params[name])
|
||||
except ValueError:
|
||||
raise error("Error on '%s': unable to parse %s" % (
|
||||
params['#original'], params[name]))
|
||||
if default is not None:
|
||||
return default
|
||||
raise error("Error on '%s': missing %s" % (params['#original'], name))
|
||||
extended_r = re.compile(
|
||||
r'^\s*(?:N[0-9]+\s*)?'
|
||||
r'(?P<cmd>[a-zA-Z_][a-zA-Z_]+)(?:\s+|$)'
|
||||
r'(?P<args>[^#*;]*?)'
|
||||
r'\s*(?:[#*;].*)?$')
|
||||
def get_extended_params(self, params):
|
||||
m = self.extended_r.match(params['#original'])
|
||||
if m is None:
|
||||
# Not an "extended" command
|
||||
return params
|
||||
eargs = m.group('args')
|
||||
try:
|
||||
eparams = [earg.split('=', 1) for earg in eargs.split()]
|
||||
eparams = { k.upper(): v for k, v in eparams }
|
||||
eparams.update({k: params[k] for k in params if k.startswith('#')})
|
||||
return eparams
|
||||
except ValueError as e:
|
||||
raise error("Malformed command '%s'" % (params['#original'],))
|
||||
# Temperature wrappers
|
||||
def get_temp(self, eventtime):
|
||||
# Tn:XXX /YYY B:XXX /YYY
|
||||
out = []
|
||||
for i, heater in enumerate(self.heaters):
|
||||
if heater is not None:
|
||||
cur, target = heater.get_temp(eventtime)
|
||||
name = "B"
|
||||
if i < len(self.heaters) - 1:
|
||||
name = "T%d" % (i,)
|
||||
out.append("%s:%.1f /%.1f" % (name, cur, target))
|
||||
if not out:
|
||||
return "T:0"
|
||||
return " ".join(out)
|
||||
def bg_temp(self, heater):
|
||||
if self.is_fileinput:
|
||||
return
|
||||
eventtime = self.reactor.monotonic()
|
||||
while self.is_printer_ready and heater.check_busy(eventtime):
|
||||
print_time = self.toolhead.get_last_move_time()
|
||||
self.respond(self.get_temp(eventtime))
|
||||
eventtime = self.reactor.pause(eventtime + 1.)
|
||||
def set_temp(self, params, is_bed=False, wait=False):
|
||||
temp = self.get_float('S', params, 0.)
|
||||
heater = None
|
||||
if is_bed:
|
||||
heater = self.heaters[-1]
|
||||
elif 'T' in params:
|
||||
heater_index = self.get_int('T', params)
|
||||
if heater_index >= 0 and heater_index < len(self.heaters) - 1:
|
||||
heater = self.heaters[heater_index]
|
||||
elif self.extruder is not None:
|
||||
heater = self.extruder.get_heater()
|
||||
if heater is None:
|
||||
if temp > 0.:
|
||||
self.respond_error("Heater not configured")
|
||||
return
|
||||
print_time = self.toolhead.get_last_move_time()
|
||||
try:
|
||||
heater.set_temp(print_time, temp)
|
||||
except heater.error as e:
|
||||
self.respond_error(str(e))
|
||||
return
|
||||
if wait:
|
||||
self.bg_temp(heater)
|
||||
def set_fan_speed(self, speed):
|
||||
if self.fan is None:
|
||||
if speed and not self.is_fileinput:
|
||||
self.respond_info("Fan not configured")
|
||||
return
|
||||
print_time = self.toolhead.get_last_move_time()
|
||||
self.fan.set_speed(print_time, speed)
|
||||
# Individual command handlers
|
||||
def cmd_default(self, params):
|
||||
if not self.is_printer_ready:
|
||||
self.respond_error(self.printer.get_state_message())
|
||||
return
|
||||
cmd = params.get('#command')
|
||||
if not cmd:
|
||||
logging.debug(params['#original'])
|
||||
return
|
||||
if cmd[0] == 'T' and len(cmd) > 1 and cmd[1].isdigit():
|
||||
# Tn command has to be handled specially
|
||||
self.cmd_Tn(params)
|
||||
return
|
||||
self.respond_info('Unknown command:"%s"' % (cmd,))
|
||||
def cmd_Tn(self, params):
|
||||
# Select Tool
|
||||
index = self.get_int('T', params)
|
||||
extruders = extruder.get_printer_extruders(self.printer)
|
||||
if self.extruder is None or index < 0 or index >= len(extruders):
|
||||
self.respond_error("Extruder %d not configured" % (index,))
|
||||
return
|
||||
e = extruders[index]
|
||||
if self.extruder is e:
|
||||
return
|
||||
deactivate_gcode = self.extruder.get_activate_gcode(False)
|
||||
self.process_commands(deactivate_gcode.split('\n'), need_ack=False)
|
||||
try:
|
||||
self.toolhead.set_extruder(e)
|
||||
except homing.EndstopError as e:
|
||||
self.respond_error(str(e))
|
||||
return
|
||||
self.extruder = e
|
||||
self.last_position = self.toolhead.get_position()
|
||||
activate_gcode = self.extruder.get_activate_gcode(True)
|
||||
self.process_commands(activate_gcode.split('\n'), need_ack=False)
|
||||
all_handlers = [
|
||||
'G1', 'G4', 'G20', 'G28', 'G90', 'G91', 'G92',
|
||||
'M82', 'M83', 'M18', 'M105', 'M104', 'M109', 'M112', 'M114', 'M115',
|
||||
'M140', 'M190', 'M106', 'M107', 'M206', 'M400',
|
||||
'IGNORE', 'QUERY_ENDSTOPS', 'PID_TUNE', 'SET_SERVO',
|
||||
'RESTART', 'FIRMWARE_RESTART', 'ECHO', 'STATUS', 'HELP']
|
||||
cmd_G1_aliases = ['G0']
|
||||
def cmd_G1(self, params):
|
||||
# Move
|
||||
try:
|
||||
for a, p in self.axis2pos.items():
|
||||
if a in params:
|
||||
v = float(params[a])
|
||||
if (not self.absolutecoord
|
||||
or (p>2 and not self.absoluteextrude)):
|
||||
# value relative to position of last move
|
||||
self.last_position[p] += v
|
||||
else:
|
||||
# value relative to base coordinate position
|
||||
self.last_position[p] = v + self.base_position[p]
|
||||
if 'F' in params:
|
||||
speed = float(params['F']) / 60.
|
||||
if speed <= 0.:
|
||||
raise ValueError()
|
||||
self.speed = speed
|
||||
except ValueError as e:
|
||||
self.last_position = self.toolhead.get_position()
|
||||
raise error("Unable to parse move '%s'" % (params['#original'],))
|
||||
try:
|
||||
self.toolhead.move(self.last_position, self.speed)
|
||||
except homing.EndstopError as e:
|
||||
self.respond_error(str(e))
|
||||
self.last_position = self.toolhead.get_position()
|
||||
def cmd_G4(self, params):
|
||||
# Dwell
|
||||
if 'S' in params:
|
||||
delay = self.get_float('S', params)
|
||||
else:
|
||||
delay = self.get_float('P', params, 0.) / 1000.
|
||||
self.toolhead.dwell(delay)
|
||||
def cmd_G20(self, params):
|
||||
# Set units to inches
|
||||
self.respond_error('Machine does not support G20 (inches) command')
|
||||
def cmd_G28(self, params):
|
||||
# Move to origin
|
||||
axes = []
|
||||
for axis in 'XYZ':
|
||||
if axis in params:
|
||||
axes.append(self.axis2pos[axis])
|
||||
if not axes:
|
||||
axes = [0, 1, 2]
|
||||
homing_state = homing.Homing(self.toolhead, axes)
|
||||
if self.is_fileinput:
|
||||
homing_state.set_no_verify_retract()
|
||||
try:
|
||||
self.toolhead.home(homing_state)
|
||||
except homing.EndstopError as e:
|
||||
self.toolhead.motor_off()
|
||||
self.respond_error(str(e))
|
||||
return
|
||||
newpos = self.toolhead.get_position()
|
||||
for axis in homing_state.get_axes():
|
||||
self.last_position[axis] = newpos[axis]
|
||||
self.base_position[axis] = -self.homing_add[axis]
|
||||
def cmd_G90(self, params):
|
||||
# Use absolute coordinates
|
||||
self.absolutecoord = True
|
||||
def cmd_G91(self, params):
|
||||
# Use relative coordinates
|
||||
self.absolutecoord = False
|
||||
def cmd_G92(self, params):
|
||||
# Set position
|
||||
offsets = { p: self.get_float(a, params)
|
||||
for a, p in self.axis2pos.items() if a in params }
|
||||
for p, offset in offsets.items():
|
||||
self.base_position[p] = self.last_position[p] - offset
|
||||
if not offsets:
|
||||
self.base_position = list(self.last_position)
|
||||
def cmd_M82(self, params):
|
||||
# Use absolute distances for extrusion
|
||||
self.absoluteextrude = True
|
||||
def cmd_M83(self, params):
|
||||
# Use relative distances for extrusion
|
||||
self.absoluteextrude = False
|
||||
cmd_M18_aliases = ["M84"]
|
||||
def cmd_M18(self, params):
|
||||
# Turn off motors
|
||||
self.toolhead.motor_off()
|
||||
cmd_M105_when_not_ready = True
|
||||
def cmd_M105(self, params):
|
||||
# Get Extruder Temperature
|
||||
self.ack(self.get_temp(self.reactor.monotonic()))
|
||||
def cmd_M104(self, params):
|
||||
# Set Extruder Temperature
|
||||
self.set_temp(params)
|
||||
def cmd_M109(self, params):
|
||||
# Set Extruder Temperature and Wait
|
||||
self.set_temp(params, wait=True)
|
||||
def cmd_M112(self, params):
|
||||
# Emergency Stop
|
||||
self.printer.invoke_shutdown("Shutdown due to M112 command")
|
||||
cmd_M114_when_not_ready = True
|
||||
def cmd_M114(self, params):
|
||||
# Get Current Position
|
||||
if self.toolhead is None:
|
||||
self.cmd_default(params)
|
||||
return
|
||||
raw_pos = self.toolhead.query_endstops("get_mcu_position")
|
||||
self.respond("X:%.3f Y:%.3f Z:%.3f E:%.3f Count %s" % (
|
||||
self.last_position[0], self.last_position[1],
|
||||
self.last_position[2], self.last_position[3],
|
||||
" ".join(["%s:%d" % (n.upper(), p) for n, p in raw_pos])))
|
||||
cmd_M115_when_not_ready = True
|
||||
def cmd_M115(self, params):
|
||||
# Get Firmware Version and Capabilities
|
||||
software_version = self.printer.get_start_args().get('software_version')
|
||||
kw = {"FIRMWARE_NAME": "Klipper", "FIRMWARE_VERSION": software_version}
|
||||
self.ack(" ".join(["%s:%s" % (k, v) for k, v in kw.items()]))
|
||||
def cmd_M140(self, params):
|
||||
# Set Bed Temperature
|
||||
self.set_temp(params, is_bed=True)
|
||||
def cmd_M190(self, params):
|
||||
# Set Bed Temperature and Wait
|
||||
self.set_temp(params, is_bed=True, wait=True)
|
||||
def cmd_M106(self, params):
|
||||
# Set fan speed
|
||||
self.set_fan_speed(self.get_float('S', params, 255.) / 255.)
|
||||
def cmd_M107(self, params):
|
||||
# Turn fan off
|
||||
self.set_fan_speed(0.)
|
||||
def cmd_M206(self, params):
|
||||
# Set home offset
|
||||
offsets = { p: self.get_float(a, params)
|
||||
for a, p in self.axis2pos.items() if a in params }
|
||||
for p, offset in offsets.items():
|
||||
self.base_position[p] += self.homing_add[p] - offset
|
||||
self.homing_add[p] = offset
|
||||
def cmd_M400(self, params):
|
||||
# Wait for current moves to finish
|
||||
self.toolhead.wait_moves()
|
||||
cmd_IGNORE_when_not_ready = True
|
||||
cmd_IGNORE_aliases = ["G21", "M110", "M21"]
|
||||
def cmd_IGNORE(self, params):
|
||||
# Commands that are just silently accepted
|
||||
pass
|
||||
cmd_QUERY_ENDSTOPS_help = "Report on the status of each endstop"
|
||||
cmd_QUERY_ENDSTOPS_aliases = ["M119"]
|
||||
def cmd_QUERY_ENDSTOPS(self, params):
|
||||
# Get Endstop Status
|
||||
if self.is_fileinput:
|
||||
return
|
||||
try:
|
||||
res = self.toolhead.query_endstops()
|
||||
except homing.EndstopError as e:
|
||||
self.respond_error(str(e))
|
||||
return
|
||||
self.respond(" ".join(["%s:%s" % (name, ["open", "TRIGGERED"][not not t])
|
||||
for name, t in res]))
|
||||
cmd_PID_TUNE_help = "Run PID Tuning"
|
||||
cmd_PID_TUNE_aliases = ["M303"]
|
||||
def cmd_PID_TUNE(self, params):
|
||||
# Run PID tuning
|
||||
heater_index = self.get_int('E', params, 0)
|
||||
if (heater_index < -1 or heater_index >= len(self.heaters) - 1
|
||||
or self.heaters[heater_index] is None):
|
||||
self.respond_error("Heater not configured")
|
||||
heater = self.heaters[heater_index]
|
||||
temp = self.get_float('S', params)
|
||||
heater.start_auto_tune(temp)
|
||||
self.bg_temp(heater)
|
||||
cmd_SET_SERVO_help = "Set servo angle"
|
||||
def cmd_SET_SERVO(self, params):
|
||||
params = self.get_extended_params(params)
|
||||
name = params.get('SERVO')
|
||||
if name is None:
|
||||
raise error("Error on '%s': missing SERVO" % (params['#original'],))
|
||||
s = chipmisc.get_printer_servo(self.printer, name)
|
||||
if s is None:
|
||||
raise error("Servo not configured")
|
||||
print_time = self.toolhead.get_last_move_time()
|
||||
if 'WIDTH' in params:
|
||||
s.set_pulse_width(print_time, self.get_float('WIDTH', params))
|
||||
return
|
||||
s.set_angle(print_time, self.get_float('ANGLE', params))
|
||||
def prep_restart(self):
|
||||
if self.is_printer_ready:
|
||||
self.respond_info("Preparing to restart...")
|
||||
self.motor_heater_off()
|
||||
self.toolhead.dwell(0.500)
|
||||
self.toolhead.wait_moves()
|
||||
cmd_RESTART_when_not_ready = True
|
||||
cmd_RESTART_help = "Reload config file and restart host software"
|
||||
def cmd_RESTART(self, params):
|
||||
self.prep_restart()
|
||||
self.printer.request_exit('restart')
|
||||
cmd_FIRMWARE_RESTART_when_not_ready = True
|
||||
cmd_FIRMWARE_RESTART_help = "Restart firmware, host, and reload config"
|
||||
def cmd_FIRMWARE_RESTART(self, params):
|
||||
self.prep_restart()
|
||||
self.printer.request_exit('firmware_restart')
|
||||
cmd_ECHO_when_not_ready = True
|
||||
def cmd_ECHO(self, params):
|
||||
self.respond_info(params['#original'])
|
||||
cmd_STATUS_when_not_ready = True
|
||||
cmd_STATUS_help = "Report the printer status"
|
||||
def cmd_STATUS(self, params):
|
||||
msg = self.printer.get_state_message()
|
||||
if self.is_printer_ready:
|
||||
self.respond_info(msg)
|
||||
else:
|
||||
self.respond_error(msg)
|
||||
cmd_HELP_when_not_ready = True
|
||||
def cmd_HELP(self, params):
|
||||
cmdhelp = []
|
||||
if not self.is_printer_ready:
|
||||
cmdhelp.append("Printer is not ready - not all commands available.")
|
||||
cmdhelp.append("Available extended commands:")
|
||||
for cmd in sorted(self.gcode_handlers):
|
||||
desc = getattr(self, 'cmd_'+cmd+'_help', None)
|
||||
if desc is not None:
|
||||
cmdhelp.append("%-10s: %s" % (cmd, desc))
|
||||
self.respond_info("\n".join(cmdhelp))
|
||||
|
||||
class error(Exception):
|
||||
pass
|
||||
367
klippy/heater.py
Normal file
@@ -0,0 +1,367 @@
|
||||
# Printer heater support
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import math, logging, threading
|
||||
import pins
|
||||
|
||||
|
||||
######################################################################
|
||||
# Sensors
|
||||
######################################################################
|
||||
|
||||
KELVIN_TO_CELCIUS = -273.15
|
||||
|
||||
# Thermistor calibrated with three temp measurements
|
||||
class Thermistor:
|
||||
def __init__(self, config, params):
|
||||
self.pullup = config.getfloat('pullup_resistor', 4700., above=0.)
|
||||
# Calculate Steinhart-Hart coefficents from temp measurements
|
||||
inv_t1 = 1. / (params['t1'] - KELVIN_TO_CELCIUS)
|
||||
inv_t2 = 1. / (params['t2'] - KELVIN_TO_CELCIUS)
|
||||
inv_t3 = 1. / (params['t3'] - KELVIN_TO_CELCIUS)
|
||||
ln_r1 = math.log(params['r1'])
|
||||
ln_r2 = math.log(params['r2'])
|
||||
ln_r3 = math.log(params['r3'])
|
||||
ln3_r1, ln3_r2, ln3_r3 = ln_r1**3, ln_r2**3, ln_r3**3
|
||||
|
||||
inv_t12, inv_t13 = inv_t1 - inv_t2, inv_t1 - inv_t3
|
||||
ln_r12, ln_r13 = ln_r1 - ln_r2, ln_r1 - ln_r3
|
||||
ln3_r12, ln3_r13 = ln3_r1 - ln3_r2, ln3_r1 - ln3_r3
|
||||
|
||||
self.c3 = ((inv_t12 - inv_t13 * ln_r12 / ln_r13)
|
||||
/ (ln3_r12 - ln3_r13 * ln_r12 / ln_r13))
|
||||
self.c2 = (inv_t12 - self.c3 * ln3_r12) / ln_r12
|
||||
self.c1 = inv_t1 - self.c2 * ln_r1 - self.c3 * ln3_r1
|
||||
def calc_temp(self, adc):
|
||||
r = self.pullup * adc / (1.0 - adc)
|
||||
ln_r = math.log(r)
|
||||
inv_t = self.c1 + self.c2 * ln_r + self.c3 * ln_r**3
|
||||
return 1.0/inv_t + KELVIN_TO_CELCIUS
|
||||
def calc_adc(self, temp):
|
||||
inv_t = 1. / (temp - KELVIN_TO_CELCIUS)
|
||||
if self.c3:
|
||||
y = (self.c1 - inv_t) / (2. * self.c3)
|
||||
x = math.sqrt((self.c2 / (3. * self.c3))**3 + y**2)
|
||||
ln_r = math.pow(x - y, 1./3.) - math.pow(x + y, 1./3.)
|
||||
else:
|
||||
ln_r = (inv_t - self.c1) / self.c2
|
||||
r = math.exp(ln_r)
|
||||
return r / (self.pullup + r)
|
||||
|
||||
# Thermistor calibrated from one temp measurement and its beta
|
||||
class ThermistorBeta(Thermistor):
|
||||
def __init__(self, config, params):
|
||||
self.pullup = config.getfloat('pullup_resistor', 4700., above=0.)
|
||||
# Calculate Steinhart-Hart coefficents from beta
|
||||
inv_t1 = 1. / (params['t1'] - KELVIN_TO_CELCIUS)
|
||||
ln_r1 = math.log(params['r1'])
|
||||
self.c3 = 0.
|
||||
self.c2 = 1. / params['beta']
|
||||
self.c1 = inv_t1 - self.c2 * ln_r1
|
||||
|
||||
# Linear style conversion chips calibrated with two temp measurements
|
||||
class Linear:
|
||||
def __init__(self, config, params):
|
||||
adc_voltage = config.getfloat('adc_voltage', 5., above=0.)
|
||||
slope = (params['t2'] - params['t1']) / (params['v2'] - params['v1'])
|
||||
self.gain = adc_voltage * slope
|
||||
self.offset = params['t1'] - params['v1'] * slope
|
||||
def calc_temp(self, adc):
|
||||
return adc * self.gain + self.offset
|
||||
def calc_adc(self, temp):
|
||||
return (temp - self.offset) / self.gain
|
||||
|
||||
# Available sensors
|
||||
Sensors = {
|
||||
"EPCOS 100K B57560G104F": {
|
||||
'class': Thermistor, 't1': 25., 'r1': 100000.,
|
||||
't2': 150., 'r2': 1641.9, 't3': 250., 'r3': 226.15 },
|
||||
"ATC Semitec 104GT-2": {
|
||||
'class': Thermistor, 't1': 20., 'r1': 126800.,
|
||||
't2': 150., 'r2': 1360., 't3': 300., 'r3': 80.65 },
|
||||
"NTC 100K beta 3950": {
|
||||
'class': ThermistorBeta, 't1': 25., 'r1': 100000., 'beta': 3950. },
|
||||
"AD595": { 'class': Linear, 't1': 25., 'v1': .25, 't2': 300., 'v2': 3.022 },
|
||||
}
|
||||
|
||||
|
||||
######################################################################
|
||||
# Heater
|
||||
######################################################################
|
||||
|
||||
SAMPLE_TIME = 0.001
|
||||
SAMPLE_COUNT = 8
|
||||
REPORT_TIME = 0.300
|
||||
PWM_CYCLE_TIME = 0.100
|
||||
MAX_HEAT_TIME = 5.0
|
||||
AMBIENT_TEMP = 25.
|
||||
PID_PARAM_BASE = 255.
|
||||
|
||||
class error(Exception):
|
||||
pass
|
||||
|
||||
class PrinterHeater:
|
||||
error = error
|
||||
def __init__(self, printer, config):
|
||||
self.name = config.section
|
||||
sensor_params = config.getchoice('sensor_type', Sensors)
|
||||
self.sensor = sensor_params['class'](config, sensor_params)
|
||||
self.min_temp = config.getfloat('min_temp', minval=0.)
|
||||
self.max_temp = config.getfloat('max_temp', above=self.min_temp)
|
||||
self.min_extrude_temp = config.getfloat(
|
||||
'min_extrude_temp', 170., minval=self.min_temp, maxval=self.max_temp)
|
||||
self.max_power = config.getfloat('max_power', 1., above=0., maxval=1.)
|
||||
self.lock = threading.Lock()
|
||||
self.last_temp = 0.
|
||||
self.last_temp_time = 0.
|
||||
self.target_temp = 0.
|
||||
algos = {'watermark': ControlBangBang, 'pid': ControlPID}
|
||||
algo = config.getchoice('control', algos)
|
||||
heater_pin = config.get('heater_pin')
|
||||
if algo is ControlBangBang and self.max_power == 1.:
|
||||
self.mcu_pwm = pins.setup_pin(printer, 'digital_out', heater_pin)
|
||||
else:
|
||||
self.mcu_pwm = pins.setup_pin(printer, 'pwm', heater_pin)
|
||||
self.mcu_pwm.setup_cycle_time(PWM_CYCLE_TIME)
|
||||
self.mcu_pwm.setup_max_duration(MAX_HEAT_TIME)
|
||||
self.mcu_adc = pins.setup_pin(printer, 'adc', config.get('sensor_pin'))
|
||||
adc_range = [self.sensor.calc_adc(self.min_temp),
|
||||
self.sensor.calc_adc(self.max_temp)]
|
||||
self.mcu_adc.setup_minmax(SAMPLE_TIME, SAMPLE_COUNT,
|
||||
minval=min(adc_range), maxval=max(adc_range))
|
||||
self.mcu_adc.setup_adc_callback(REPORT_TIME, self.adc_callback)
|
||||
is_fileoutput = self.mcu_adc.get_mcu().is_fileoutput()
|
||||
self.can_extrude = self.min_extrude_temp <= 0. or is_fileoutput
|
||||
self.control = algo(self, config)
|
||||
# pwm caching
|
||||
self.next_pwm_time = 0.
|
||||
self.last_pwm_value = 0
|
||||
def set_pwm(self, read_time, value):
|
||||
if self.target_temp <= 0.:
|
||||
value = 0.
|
||||
if ((read_time < self.next_pwm_time or not self.last_pwm_value)
|
||||
and abs(value - self.last_pwm_value) < 0.05):
|
||||
# No significant change in value - can suppress update
|
||||
return
|
||||
pwm_time = read_time + REPORT_TIME + SAMPLE_TIME*SAMPLE_COUNT
|
||||
self.next_pwm_time = pwm_time + 0.75 * MAX_HEAT_TIME
|
||||
self.last_pwm_value = value
|
||||
logging.debug("%s: pwm=%.3f@%.3f (from %.3f@%.3f [%.3f])",
|
||||
self.name, value, pwm_time,
|
||||
self.last_temp, self.last_temp_time, self.target_temp)
|
||||
self.mcu_pwm.set_pwm(pwm_time, value)
|
||||
def adc_callback(self, read_time, read_value):
|
||||
temp = self.sensor.calc_temp(read_value)
|
||||
with self.lock:
|
||||
self.last_temp = temp
|
||||
self.last_temp_time = read_time
|
||||
self.can_extrude = (temp >= self.min_extrude_temp)
|
||||
self.control.adc_callback(read_time, temp)
|
||||
#logging.debug("temp: %.3f %f = %f", read_time, read_value, temp)
|
||||
# External commands
|
||||
def set_temp(self, print_time, degrees):
|
||||
if degrees and (degrees < self.min_temp or degrees > self.max_temp):
|
||||
raise error("Requested temperature (%.1f) out of range (%.1f:%.1f)"
|
||||
% (degrees, self.min_temp, self.max_temp))
|
||||
with self.lock:
|
||||
self.target_temp = degrees
|
||||
def get_temp(self, eventtime):
|
||||
print_time = self.mcu_adc.get_mcu().estimated_print_time(eventtime) - 5.
|
||||
with self.lock:
|
||||
if self.last_temp_time < print_time:
|
||||
return 0., self.target_temp
|
||||
return self.last_temp, self.target_temp
|
||||
def check_busy(self, eventtime):
|
||||
with self.lock:
|
||||
return self.control.check_busy(eventtime)
|
||||
def start_auto_tune(self, degrees):
|
||||
if degrees and (degrees < self.min_temp or degrees > self.max_temp):
|
||||
raise error("Requested temperature (%.1f) out of range (%.1f:%.1f)"
|
||||
% (degrees, self.min_temp, self.max_temp))
|
||||
with self.lock:
|
||||
self.control = ControlAutoTune(self, self.control)
|
||||
self.target_temp = degrees
|
||||
def finish_auto_tune(self, old_control):
|
||||
self.control = old_control
|
||||
self.target_temp = 0
|
||||
|
||||
|
||||
######################################################################
|
||||
# Bang-bang control algo
|
||||
######################################################################
|
||||
|
||||
class ControlBangBang:
|
||||
def __init__(self, heater, config):
|
||||
self.heater = heater
|
||||
self.max_delta = config.getfloat('max_delta', 2.0, above=0.)
|
||||
self.heating = False
|
||||
def adc_callback(self, read_time, temp):
|
||||
if self.heating and temp >= self.heater.target_temp+self.max_delta:
|
||||
self.heating = False
|
||||
elif not self.heating and temp <= self.heater.target_temp-self.max_delta:
|
||||
self.heating = True
|
||||
if self.heating:
|
||||
self.heater.set_pwm(read_time, self.heater.max_power)
|
||||
else:
|
||||
self.heater.set_pwm(read_time, 0.)
|
||||
def check_busy(self, eventtime):
|
||||
return self.heater.last_temp < self.heater.target_temp-self.max_delta
|
||||
|
||||
|
||||
######################################################################
|
||||
# Proportional Integral Derivative (PID) control algo
|
||||
######################################################################
|
||||
|
||||
class ControlPID:
|
||||
def __init__(self, heater, config):
|
||||
self.heater = heater
|
||||
self.Kp = config.getfloat('pid_Kp') / PID_PARAM_BASE
|
||||
self.Ki = config.getfloat('pid_Ki') / PID_PARAM_BASE
|
||||
self.Kd = config.getfloat('pid_Kd') / PID_PARAM_BASE
|
||||
self.min_deriv_time = config.getfloat('pid_deriv_time', 2., above=0.)
|
||||
imax = config.getfloat('pid_integral_max', heater.max_power, minval=0.)
|
||||
self.temp_integ_max = imax / self.Ki
|
||||
self.prev_temp = AMBIENT_TEMP
|
||||
self.prev_temp_time = 0.
|
||||
self.prev_temp_deriv = 0.
|
||||
self.prev_temp_integ = 0.
|
||||
def adc_callback(self, read_time, temp):
|
||||
time_diff = read_time - self.prev_temp_time
|
||||
# Calculate change of temperature
|
||||
temp_diff = temp - self.prev_temp
|
||||
if time_diff >= self.min_deriv_time:
|
||||
temp_deriv = temp_diff / time_diff
|
||||
else:
|
||||
temp_deriv = (self.prev_temp_deriv * (self.min_deriv_time-time_diff)
|
||||
+ temp_diff) / self.min_deriv_time
|
||||
# Calculate accumulated temperature "error"
|
||||
temp_err = self.heater.target_temp - temp
|
||||
temp_integ = self.prev_temp_integ + temp_err * time_diff
|
||||
temp_integ = max(0., min(self.temp_integ_max, temp_integ))
|
||||
# Calculate output
|
||||
co = self.Kp*temp_err + self.Ki*temp_integ - self.Kd*temp_deriv
|
||||
#logging.debug("pid: %f@%.3f -> diff=%f deriv=%f err=%f integ=%f co=%d",
|
||||
# temp, read_time, temp_diff, temp_deriv, temp_err, temp_integ, co)
|
||||
bounded_co = max(0., min(self.heater.max_power, co))
|
||||
self.heater.set_pwm(read_time, bounded_co)
|
||||
# Store state for next measurement
|
||||
self.prev_temp = temp
|
||||
self.prev_temp_time = read_time
|
||||
self.prev_temp_deriv = temp_deriv
|
||||
if co == bounded_co:
|
||||
self.prev_temp_integ = temp_integ
|
||||
def check_busy(self, eventtime):
|
||||
temp_diff = self.heater.target_temp - self.heater.last_temp
|
||||
return abs(temp_diff) > 1. or abs(self.prev_temp_deriv) > 0.1
|
||||
|
||||
|
||||
######################################################################
|
||||
# Ziegler-Nichols PID autotuning
|
||||
######################################################################
|
||||
|
||||
TUNE_PID_DELTA = 5.0
|
||||
|
||||
class ControlAutoTune:
|
||||
def __init__(self, heater, old_control):
|
||||
self.heater = heater
|
||||
self.old_control = old_control
|
||||
self.heating = False
|
||||
self.peaks = []
|
||||
self.peak = 0.
|
||||
self.peak_time = 0.
|
||||
def adc_callback(self, read_time, temp):
|
||||
if self.heating and temp >= self.heater.target_temp:
|
||||
self.heating = False
|
||||
self.check_peaks()
|
||||
elif (not self.heating
|
||||
and temp <= self.heater.target_temp - TUNE_PID_DELTA):
|
||||
self.heating = True
|
||||
self.check_peaks()
|
||||
if self.heating:
|
||||
self.heater.set_pwm(read_time, self.heater.max_power)
|
||||
if temp < self.peak:
|
||||
self.peak = temp
|
||||
self.peak_time = read_time
|
||||
else:
|
||||
self.heater.set_pwm(read_time, 0.)
|
||||
if temp > self.peak:
|
||||
self.peak = temp
|
||||
self.peak_time = read_time
|
||||
def check_peaks(self):
|
||||
self.peaks.append((self.peak, self.peak_time))
|
||||
if self.heating:
|
||||
self.peak = 9999999.
|
||||
else:
|
||||
self.peak = -9999999.
|
||||
if len(self.peaks) < 4:
|
||||
return
|
||||
temp_diff = self.peaks[-1][0] - self.peaks[-2][0]
|
||||
time_diff = self.peaks[-1][1] - self.peaks[-3][1]
|
||||
max_power = self.heater.max_power
|
||||
Ku = 4. * (2. * max_power) / (abs(temp_diff) * math.pi)
|
||||
Tu = time_diff
|
||||
|
||||
Kp = 0.6 * Ku
|
||||
Ti = 0.5 * Tu
|
||||
Td = 0.125 * Tu
|
||||
Ki = Kp / Ti
|
||||
Kd = Kp * Td
|
||||
logging.info("Autotune: raw=%f/%f Ku=%f Tu=%f Kp=%f Ki=%f Kd=%f",
|
||||
temp_diff, max_power, Ku, Tu, Kp * PID_PARAM_BASE,
|
||||
Ki * PID_PARAM_BASE, Kd * PID_PARAM_BASE)
|
||||
def check_busy(self, eventtime):
|
||||
if self.heating or len(self.peaks) < 12:
|
||||
return True
|
||||
self.heater.finish_auto_tune(self.old_control)
|
||||
return False
|
||||
|
||||
|
||||
######################################################################
|
||||
# Tuning information test
|
||||
######################################################################
|
||||
|
||||
class ControlBumpTest:
|
||||
def __init__(self, heater, old_control):
|
||||
self.heater = heater
|
||||
self.old_control = old_control
|
||||
self.temp_samples = {}
|
||||
self.pwm_samples = {}
|
||||
self.state = 0
|
||||
def set_pwm(self, read_time, value):
|
||||
self.pwm_samples[read_time + 2*REPORT_TIME] = value
|
||||
self.heater.set_pwm(read_time, value)
|
||||
def adc_callback(self, read_time, temp):
|
||||
self.temp_samples[read_time] = temp
|
||||
if not self.state:
|
||||
self.set_pwm(read_time, 0.)
|
||||
if len(self.temp_samples) >= 20:
|
||||
self.state += 1
|
||||
elif self.state == 1:
|
||||
if temp < self.heater.target_temp:
|
||||
self.set_pwm(read_time, self.heater.max_power)
|
||||
return
|
||||
self.set_pwm(read_time, 0.)
|
||||
self.state += 1
|
||||
elif self.state == 2:
|
||||
self.set_pwm(read_time, 0.)
|
||||
if temp <= (self.heater.target_temp + AMBIENT_TEMP) / 2.:
|
||||
self.dump_stats()
|
||||
self.state += 1
|
||||
def dump_stats(self):
|
||||
out = ["%.3f %.1f %d" % (time, temp, self.pwm_samples.get(time, -1.))
|
||||
for time, temp in sorted(self.temp_samples.items())]
|
||||
f = open("/tmp/heattest.txt", "wb")
|
||||
f.write('\n'.join(out))
|
||||
f.close()
|
||||
def check_busy(self, eventtime):
|
||||
if self.state < 3:
|
||||
return True
|
||||
self.heater.finish_auto_tune(self.old_control)
|
||||
return False
|
||||
|
||||
def add_printer_objects(printer, config):
|
||||
if config.has_section('heater_bed'):
|
||||
printer.add_object('heater_bed', PrinterHeater(
|
||||
printer, config.getsection('heater_bed')))
|
||||
83
klippy/homing.py
Normal file
@@ -0,0 +1,83 @@
|
||||
# Code for state tracking during homing operations
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import logging
|
||||
|
||||
HOMING_DELAY = 0.250
|
||||
ENDSTOP_SAMPLE_TIME = .000015
|
||||
ENDSTOP_SAMPLE_COUNT = 4
|
||||
|
||||
class Homing:
|
||||
def __init__(self, toolhead, changed_axes):
|
||||
self.toolhead = toolhead
|
||||
self.changed_axes = changed_axes
|
||||
self.verify_retract = True
|
||||
def set_no_verify_retract(self):
|
||||
self.verify_retract = False
|
||||
def set_axes(self, axes):
|
||||
self.changed_axes = axes
|
||||
def get_axes(self):
|
||||
return self.changed_axes
|
||||
def _fill_coord(self, coord):
|
||||
# Fill in any None entries in 'coord' with current toolhead position
|
||||
thcoord = list(self.toolhead.get_position())
|
||||
for i in range(len(coord)):
|
||||
if coord[i] is not None:
|
||||
thcoord[i] = coord[i]
|
||||
return thcoord
|
||||
def retract(self, newpos, speed):
|
||||
self.toolhead.move(self._fill_coord(newpos), speed)
|
||||
def home(self, forcepos, movepos, steppers, speed, second_home=False):
|
||||
# Alter kinematics class to think printer is at forcepos
|
||||
self.toolhead.set_position(self._fill_coord(forcepos))
|
||||
# Start homing and issue move
|
||||
if not second_home:
|
||||
self.toolhead.dwell(HOMING_DELAY)
|
||||
print_time = self.toolhead.get_last_move_time()
|
||||
endstops = []
|
||||
for s in steppers:
|
||||
s.mcu_endstop.home_start(print_time, ENDSTOP_SAMPLE_TIME,
|
||||
ENDSTOP_SAMPLE_COUNT, s.step_dist / speed)
|
||||
endstops.append((s, s.mcu_stepper.get_mcu_position()))
|
||||
self.toolhead.move(self._fill_coord(movepos), speed)
|
||||
move_end_print_time = self.toolhead.get_last_move_time()
|
||||
self.toolhead.reset_print_time(print_time)
|
||||
for s, last_pos in endstops:
|
||||
s.mcu_endstop.home_finalize(move_end_print_time)
|
||||
# Wait for endstops to trigger
|
||||
for s, last_pos in endstops:
|
||||
try:
|
||||
s.mcu_endstop.home_wait()
|
||||
except s.mcu_endstop.error as e:
|
||||
raise EndstopError("Failed to home stepper %s: %s" % (
|
||||
s.name, str(e)))
|
||||
post_home_pos = s.mcu_stepper.get_mcu_position()
|
||||
if second_home and self.verify_retract and last_pos == post_home_pos:
|
||||
raise EndstopError("Endstop %s still triggered after retract" % (
|
||||
s.name,))
|
||||
def set_homed_position(self, pos):
|
||||
self.toolhead.set_position(self._fill_coord(pos))
|
||||
|
||||
def query_endstops(print_time, query_flags, steppers):
|
||||
if query_flags == "get_mcu_position":
|
||||
# Only the commanded position is requested
|
||||
return [(s.name.upper(), s.mcu_stepper.get_mcu_position())
|
||||
for s in steppers]
|
||||
for s in steppers:
|
||||
s.mcu_endstop.query_endstop(print_time)
|
||||
out = []
|
||||
for s in steppers:
|
||||
try:
|
||||
out.append((s.name, s.mcu_endstop.query_endstop_wait()))
|
||||
except s.mcu_endstop.error as e:
|
||||
raise EndstopError(str(e))
|
||||
return out
|
||||
|
||||
class EndstopError(Exception):
|
||||
pass
|
||||
|
||||
def EndstopMoveError(pos, msg="Move out of range"):
|
||||
return EndstopError("%s: %.3f %.3f %.3f [%.3f]" % (
|
||||
msg, pos[0], pos[1], pos[2], pos[3]))
|
||||
341
klippy/klippy.py
Normal file
@@ -0,0 +1,341 @@
|
||||
#!/usr/bin/env python2
|
||||
# Main code for host side printer firmware
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import sys, optparse, ConfigParser, logging, time, threading
|
||||
import util, reactor, queuelogger, msgproto, gcode
|
||||
import pins, mcu, chipmisc, toolhead, extruder, heater, fan
|
||||
|
||||
message_ready = "Printer is ready"
|
||||
|
||||
message_startup = """
|
||||
The klippy host software is attempting to connect. Please
|
||||
retry in a few moments.
|
||||
Printer is not ready
|
||||
"""
|
||||
|
||||
message_restart = """
|
||||
Once the underlying issue is corrected, use the "RESTART"
|
||||
command to reload the config and restart the host software.
|
||||
Printer is halted
|
||||
"""
|
||||
|
||||
message_protocol_error = """
|
||||
This type of error is frequently caused by running an older
|
||||
version of the firmware on the micro-controller (fix by
|
||||
recompiling and flashing the firmware).
|
||||
Once the underlying issue is corrected, use the "RESTART"
|
||||
command to reload the config and restart the host software.
|
||||
Protocol error connecting to printer
|
||||
"""
|
||||
|
||||
message_mcu_connect_error = """
|
||||
Once the underlying issue is corrected, use the
|
||||
"FIRMWARE_RESTART" command to reset the firmware, reload the
|
||||
config, and restart the host software.
|
||||
Error configuring printer
|
||||
"""
|
||||
|
||||
message_shutdown = """
|
||||
Once the underlying issue is corrected, use the
|
||||
"FIRMWARE_RESTART" command to reset the firmware, reload the
|
||||
config, and restart the host software.
|
||||
Printer is shutdown
|
||||
"""
|
||||
|
||||
class ConfigWrapper:
|
||||
error = ConfigParser.Error
|
||||
class sentinel:
|
||||
pass
|
||||
def __init__(self, printer, section):
|
||||
self.printer = printer
|
||||
self.section = section
|
||||
def get_wrapper(self, parser, option, default
|
||||
, minval=None, maxval=None, above=None, below=None):
|
||||
if (default is not self.sentinel
|
||||
and not self.printer.fileconfig.has_option(self.section, option)):
|
||||
return default
|
||||
self.printer.all_config_options[
|
||||
(self.section.lower(), option.lower())] = 1
|
||||
try:
|
||||
v = parser(self.section, option)
|
||||
except self.error as e:
|
||||
raise
|
||||
except:
|
||||
raise self.error("Unable to parse option '%s' in section '%s'" % (
|
||||
option, self.section))
|
||||
if minval is not None and v < minval:
|
||||
raise self.error(
|
||||
"Option '%s' in section '%s' must have minimum of %s" % (
|
||||
option, self.section, minval))
|
||||
if maxval is not None and v > maxval:
|
||||
raise self.error(
|
||||
"Option '%s' in section '%s' must have maximum of %s" % (
|
||||
option, self.section, maxval))
|
||||
if above is not None and v <= above:
|
||||
raise self.error(
|
||||
"Option '%s' in section '%s' must be above %s" % (
|
||||
option, self.section, above))
|
||||
if below is not None and v >= below:
|
||||
raise self.error(
|
||||
"Option '%s' in section '%s' must be below %s" % (
|
||||
option, self.section, below))
|
||||
return v
|
||||
def get(self, option, default=sentinel):
|
||||
return self.get_wrapper(self.printer.fileconfig.get, option, default)
|
||||
def getint(self, option, default=sentinel, minval=None, maxval=None):
|
||||
return self.get_wrapper(
|
||||
self.printer.fileconfig.getint, option, default, minval, maxval)
|
||||
def getfloat(self, option, default=sentinel
|
||||
, minval=None, maxval=None, above=None, below=None):
|
||||
return self.get_wrapper(
|
||||
self.printer.fileconfig.getfloat, option, default
|
||||
, minval, maxval, above, below)
|
||||
def getboolean(self, option, default=sentinel):
|
||||
return self.get_wrapper(
|
||||
self.printer.fileconfig.getboolean, option, default)
|
||||
def getchoice(self, option, choices, default=sentinel):
|
||||
c = self.get(option, default)
|
||||
if c not in choices:
|
||||
raise self.error(
|
||||
"Option '%s' in section '%s' is not a valid choice" % (
|
||||
option, self.section))
|
||||
return choices[c]
|
||||
def getsection(self, section):
|
||||
return ConfigWrapper(self.printer, section)
|
||||
def has_section(self, section):
|
||||
return self.printer.fileconfig.has_section(section)
|
||||
def get_prefix_sections(self, prefix):
|
||||
return [self.getsection(s) for s in self.printer.fileconfig.sections()
|
||||
if s.startswith(prefix)]
|
||||
|
||||
class ConfigLogger():
|
||||
def __init__(self, cfg, bglogger):
|
||||
self.lines = ["===== Config file ====="]
|
||||
cfg.write(self)
|
||||
self.lines.append("=======================")
|
||||
data = "\n".join(self.lines)
|
||||
logging.info(data)
|
||||
bglogger.set_rollover_info("config", data)
|
||||
def write(self, data):
|
||||
self.lines.append(data.strip())
|
||||
|
||||
class Printer:
|
||||
config_error = ConfigParser.Error
|
||||
def __init__(self, input_fd, bglogger, start_args):
|
||||
self.bglogger = bglogger
|
||||
self.start_args = start_args
|
||||
if bglogger is not None:
|
||||
bglogger.set_rollover_info("config", None)
|
||||
self.reactor = reactor.Reactor()
|
||||
self.objects = {}
|
||||
self.gcode = gcode.GCodeParser(self, input_fd)
|
||||
self.stats_timer = self.reactor.register_timer(self._stats)
|
||||
self.connect_timer = self.reactor.register_timer(
|
||||
self._connect, self.reactor.NOW)
|
||||
self.all_config_options = {}
|
||||
self.state_message = message_startup
|
||||
self.is_shutdown = False
|
||||
self.async_shutdown_msg = ""
|
||||
self.run_result = None
|
||||
self.fileconfig = None
|
||||
self.mcus = []
|
||||
def get_start_args(self):
|
||||
return self.start_args
|
||||
def _stats(self, eventtime, force_output=False):
|
||||
toolhead = self.objects.get('toolhead')
|
||||
if toolhead is None:
|
||||
return eventtime + 1.
|
||||
is_active = toolhead.check_active(eventtime)
|
||||
if not is_active and not force_output:
|
||||
return eventtime + 1.
|
||||
out = []
|
||||
out.append(self.gcode.stats(eventtime))
|
||||
out.append(toolhead.stats(eventtime))
|
||||
for m in self.mcus:
|
||||
out.append(m.stats(eventtime))
|
||||
logging.info("Stats %.1f: %s", eventtime, ' '.join(out))
|
||||
return eventtime + 1.
|
||||
def add_object(self, name, obj):
|
||||
self.objects[name] = obj
|
||||
def _load_config(self):
|
||||
self.fileconfig = ConfigParser.RawConfigParser()
|
||||
config_file = self.start_args['config_file']
|
||||
res = self.fileconfig.read(config_file)
|
||||
if not res:
|
||||
raise self.config_error("Unable to open config file %s" % (
|
||||
config_file,))
|
||||
if self.bglogger is not None:
|
||||
ConfigLogger(self.fileconfig, self.bglogger)
|
||||
# Create printer components
|
||||
config = ConfigWrapper(self, 'printer')
|
||||
for m in [pins, mcu, chipmisc, toolhead, extruder, heater, fan]:
|
||||
m.add_printer_objects(self, config)
|
||||
self.mcus = mcu.get_printer_mcus(self)
|
||||
# Validate that there are no undefined parameters in the config file
|
||||
valid_sections = { s: 1 for s, o in self.all_config_options }
|
||||
for section in self.fileconfig.sections():
|
||||
section = section.lower()
|
||||
if section not in valid_sections:
|
||||
raise self.config_error("Unknown config file section '%s'" % (
|
||||
section,))
|
||||
for option in self.fileconfig.options(section):
|
||||
option = option.lower()
|
||||
if (section, option) not in self.all_config_options:
|
||||
raise self.config_error(
|
||||
"Unknown option '%s' in section '%s'" % (
|
||||
option, section))
|
||||
def _connect(self, eventtime):
|
||||
self.reactor.unregister_timer(self.connect_timer)
|
||||
try:
|
||||
self._load_config()
|
||||
for m in self.mcus:
|
||||
m.connect()
|
||||
self.gcode.connect()
|
||||
self.state_message = message_ready
|
||||
if self.start_args.get('debugoutput') is None:
|
||||
self.reactor.update_timer(self.stats_timer, self.reactor.NOW)
|
||||
except (self.config_error, pins.error) as e:
|
||||
logging.exception("Config error")
|
||||
self.state_message = "%s%s" % (str(e), message_restart)
|
||||
except msgproto.error as e:
|
||||
logging.exception("Protocol error")
|
||||
self.state_message = "%s%s" % (str(e), message_protocol_error)
|
||||
except mcu.error as e:
|
||||
logging.exception("MCU error during connect")
|
||||
self.state_message = "%s%s" % (str(e), message_mcu_connect_error)
|
||||
except:
|
||||
logging.exception("Unhandled exception during connect")
|
||||
self.state_message = "Internal error during connect.%s" % (
|
||||
message_restart,)
|
||||
return self.reactor.NEVER
|
||||
def run(self):
|
||||
systime = time.time()
|
||||
monotime = self.reactor.monotonic()
|
||||
logging.info("Start printer at %s (%.1f %.1f)",
|
||||
time.asctime(time.localtime(systime)), systime, monotime)
|
||||
while 1:
|
||||
# Enter main reactor loop
|
||||
try:
|
||||
self.reactor.run()
|
||||
except:
|
||||
logging.exception("Unhandled exception during run")
|
||||
return "exit"
|
||||
# Check restart flags
|
||||
run_result = self.run_result
|
||||
try:
|
||||
if run_result == 'shutdown':
|
||||
self.invoke_shutdown(self.async_shutdown_msg, True)
|
||||
continue
|
||||
self._stats(self.reactor.monotonic(), force_output=True)
|
||||
for m in self.mcus:
|
||||
if run_result == 'firmware_restart':
|
||||
m.microcontroller_restart()
|
||||
m.disconnect()
|
||||
except:
|
||||
logging.exception("Unhandled exception during post run")
|
||||
return run_result
|
||||
def get_state_message(self):
|
||||
return self.state_message
|
||||
def invoke_shutdown(self, msg, is_mcu_shutdown=False):
|
||||
if self.is_shutdown:
|
||||
return
|
||||
self.is_shutdown = True
|
||||
if is_mcu_shutdown:
|
||||
self.state_message = "%s%s" % (msg, message_shutdown)
|
||||
else:
|
||||
self.state_message = "%s%s" % (msg, message_restart)
|
||||
for m in self.mcus:
|
||||
m.do_shutdown()
|
||||
self.gcode.do_shutdown()
|
||||
toolhead = self.objects.get('toolhead')
|
||||
if toolhead is not None:
|
||||
toolhead.do_shutdown()
|
||||
def invoke_async_shutdown(self, msg):
|
||||
self.async_shutdown_msg = msg
|
||||
self.request_exit("shutdown")
|
||||
def request_exit(self, result="exit"):
|
||||
self.run_result = result
|
||||
self.reactor.end()
|
||||
|
||||
|
||||
######################################################################
|
||||
# Startup
|
||||
######################################################################
|
||||
|
||||
def arg_dictionary(option, opt_str, value, parser):
|
||||
key, fname = "dictionary", value
|
||||
if '=' in value:
|
||||
mcu_name, fname = value.split('=', 1)
|
||||
key = "dictionary_" + mcu_name
|
||||
if parser.values.dictionary is None:
|
||||
parser.values.dictionary = {}
|
||||
parser.values.dictionary[key] = fname
|
||||
|
||||
def main():
|
||||
usage = "%prog [options] <config file>"
|
||||
opts = optparse.OptionParser(usage)
|
||||
opts.add_option("-i", "--debuginput", dest="debuginput",
|
||||
help="read commands from file instead of from tty port")
|
||||
opts.add_option("-I", "--input-tty", dest="inputtty", default='/tmp/printer',
|
||||
help="input tty name (default is /tmp/printer)")
|
||||
opts.add_option("-l", "--logfile", dest="logfile",
|
||||
help="write log to file instead of stderr")
|
||||
opts.add_option("-v", action="store_true", dest="verbose",
|
||||
help="enable debug messages")
|
||||
opts.add_option("-o", "--debugoutput", dest="debugoutput",
|
||||
help="write output to file instead of to serial port")
|
||||
opts.add_option("-d", "--dictionary", dest="dictionary", type="string",
|
||||
action="callback", callback=arg_dictionary,
|
||||
help="file to read for mcu protocol dictionary")
|
||||
options, args = opts.parse_args()
|
||||
if len(args) != 1:
|
||||
opts.error("Incorrect number of arguments")
|
||||
start_args = {'config_file': args[0], 'start_reason': 'startup'}
|
||||
|
||||
input_fd = bglogger = None
|
||||
|
||||
debuglevel = logging.INFO
|
||||
if options.verbose:
|
||||
debuglevel = logging.DEBUG
|
||||
if options.debuginput:
|
||||
start_args['debuginput'] = options.debuginput
|
||||
debuginput = open(options.debuginput, 'rb')
|
||||
input_fd = debuginput.fileno()
|
||||
else:
|
||||
input_fd = util.create_pty(options.inputtty)
|
||||
if options.debugoutput:
|
||||
start_args['debugoutput'] = options.debugoutput
|
||||
start_args.update(options.dictionary)
|
||||
if options.logfile:
|
||||
bglogger = queuelogger.setup_bg_logging(options.logfile, debuglevel)
|
||||
else:
|
||||
logging.basicConfig(level=debuglevel)
|
||||
logging.info("Starting Klippy...")
|
||||
start_args['software_version'] = util.get_git_version()
|
||||
if bglogger is not None:
|
||||
lines = ["Args: %s" % (sys.argv,),
|
||||
"Git version: %s" % (repr(start_args['software_version']),),
|
||||
"CPU: %s" % (util.get_cpu_info(),),
|
||||
"Python: %s" % (repr(sys.version),)]
|
||||
lines = "\n".join(lines)
|
||||
logging.info(lines)
|
||||
bglogger.set_rollover_info('versions', lines)
|
||||
|
||||
# Start Printer() class
|
||||
while 1:
|
||||
printer = Printer(input_fd, bglogger, start_args)
|
||||
res = printer.run()
|
||||
if res == 'exit':
|
||||
break
|
||||
time.sleep(1.)
|
||||
logging.info("Restarting printer")
|
||||
start_args['start_reason'] = res
|
||||
|
||||
if bglogger is not None:
|
||||
bglogger.stop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
108
klippy/list.h
Normal file
@@ -0,0 +1,108 @@
|
||||
#ifndef __LIST_H
|
||||
#define __LIST_H
|
||||
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* list - Double linked lists
|
||||
****************************************************************/
|
||||
|
||||
struct list_node {
|
||||
struct list_node *next, *prev;
|
||||
};
|
||||
|
||||
struct list_head {
|
||||
struct list_node root;
|
||||
};
|
||||
|
||||
static inline void
|
||||
list_init(struct list_head *h)
|
||||
{
|
||||
h->root.prev = h->root.next = &h->root;
|
||||
}
|
||||
|
||||
static inline int
|
||||
list_empty(const struct list_head *h)
|
||||
{
|
||||
return h->root.next == &h->root;
|
||||
}
|
||||
|
||||
static inline void
|
||||
list_del(struct list_node *n)
|
||||
{
|
||||
struct list_node *prev = n->prev;
|
||||
struct list_node *next = n->next;
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
static inline void
|
||||
__list_add(struct list_node *n, struct list_node *prev, struct list_node *next)
|
||||
{
|
||||
next->prev = n;
|
||||
n->next = next;
|
||||
n->prev = prev;
|
||||
prev->next = n;
|
||||
}
|
||||
|
||||
static inline void
|
||||
list_add_after(struct list_node *n, struct list_node *prev)
|
||||
{
|
||||
__list_add(n, prev, prev->next);
|
||||
}
|
||||
|
||||
static inline void
|
||||
list_add_before(struct list_node *n, struct list_node *next)
|
||||
{
|
||||
__list_add(n, next->prev, next);
|
||||
}
|
||||
|
||||
static inline void
|
||||
list_add_head(struct list_node *n, struct list_head *h)
|
||||
{
|
||||
list_add_after(n, &h->root);
|
||||
}
|
||||
|
||||
static inline void
|
||||
list_add_tail(struct list_node *n, struct list_head *h)
|
||||
{
|
||||
list_add_before(n, &h->root);
|
||||
}
|
||||
|
||||
static inline void
|
||||
list_join_tail(struct list_head *add, struct list_head *h)
|
||||
{
|
||||
if (!list_empty(add)) {
|
||||
struct list_node *prev = h->root.prev;
|
||||
struct list_node *next = &h->root;
|
||||
struct list_node *first = add->root.next;
|
||||
struct list_node *last = add->root.prev;
|
||||
first->prev = prev;
|
||||
prev->next = first;
|
||||
last->next = next;
|
||||
next->prev = last;
|
||||
}
|
||||
}
|
||||
|
||||
#define list_next_entry(pos, member) \
|
||||
container_of((pos)->member.next, typeof(*pos), member)
|
||||
|
||||
#define list_first_entry(head, type, member) \
|
||||
container_of((head)->root.next, type, member)
|
||||
|
||||
#define list_for_each_entry(pos, head, member) \
|
||||
for (pos = list_first_entry((head), typeof(*pos), member) \
|
||||
; &pos->member != &(head)->root \
|
||||
; pos = list_next_entry(pos, member))
|
||||
|
||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = list_first_entry((head), typeof(*pos), member) \
|
||||
, n = list_next_entry(pos, member) \
|
||||
; &pos->member != &(head)->root \
|
||||
; pos = n, n = list_next_entry(n, member))
|
||||
|
||||
|
||||
#endif // list.h
|
||||
790
klippy/mcu.py
Normal file
@@ -0,0 +1,790 @@
|
||||
# Interface to Klipper micro-controller code
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import sys, os, zlib, logging, math
|
||||
import serialhdl, pins, chelper, clocksync
|
||||
|
||||
class error(Exception):
|
||||
pass
|
||||
|
||||
STEPCOMPRESS_ERROR_RET = -989898989
|
||||
|
||||
class MCU_stepper:
|
||||
def __init__(self, mcu, pin_params):
|
||||
self._mcu = mcu
|
||||
self._oid = self._mcu.create_oid()
|
||||
self._step_pin = pin_params['pin']
|
||||
self._invert_step = pin_params['invert']
|
||||
self._dir_pin = self._invert_dir = None
|
||||
self._commanded_pos = 0
|
||||
self._step_dist = self._inv_step_dist = 1.
|
||||
self._mcu_position_offset = 0
|
||||
self._min_stop_interval = 0.
|
||||
self._reset_cmd = self._get_position_cmd = None
|
||||
self._ffi_lib = self._stepqueue = None
|
||||
def get_mcu(self):
|
||||
return self._mcu
|
||||
def setup_dir_pin(self, pin_params):
|
||||
if pin_params['chip'] is not self._mcu:
|
||||
raise pins.error("Stepper dir pin must be on same mcu as step pin")
|
||||
self._dir_pin = pin_params['pin']
|
||||
self._invert_dir = pin_params['invert']
|
||||
def setup_min_stop_interval(self, min_stop_interval):
|
||||
self._min_stop_interval = min_stop_interval
|
||||
def setup_step_distance(self, step_dist):
|
||||
self._step_dist = step_dist
|
||||
self._inv_step_dist = 1. / step_dist
|
||||
def build_config(self):
|
||||
max_error = self._mcu.get_max_stepper_error()
|
||||
min_stop_interval = max(0., self._min_stop_interval - max_error)
|
||||
self._mcu.add_config_cmd(
|
||||
"config_stepper oid=%d step_pin=%s dir_pin=%s"
|
||||
" min_stop_interval=%d invert_step=%d" % (
|
||||
self._oid, self._step_pin, self._dir_pin,
|
||||
self._mcu.seconds_to_clock(min_stop_interval),
|
||||
self._invert_step))
|
||||
step_cmd = self._mcu.lookup_command(
|
||||
"queue_step oid=%c interval=%u count=%hu add=%hi")
|
||||
dir_cmd = self._mcu.lookup_command(
|
||||
"set_next_step_dir oid=%c dir=%c")
|
||||
self._reset_cmd = self._mcu.lookup_command(
|
||||
"reset_step_clock oid=%c clock=%u")
|
||||
self._get_position_cmd = self._mcu.lookup_command(
|
||||
"stepper_get_position oid=%c")
|
||||
ffi_main, self._ffi_lib = chelper.get_ffi()
|
||||
self._stepqueue = ffi_main.gc(self._ffi_lib.stepcompress_alloc(
|
||||
self._mcu.seconds_to_clock(max_error), step_cmd.msgid, dir_cmd.msgid,
|
||||
self._invert_dir, self._oid),
|
||||
self._ffi_lib.stepcompress_free)
|
||||
self._mcu.register_stepqueue(self._stepqueue)
|
||||
def get_oid(self):
|
||||
return self._oid
|
||||
def set_position(self, pos):
|
||||
if pos >= 0.:
|
||||
steppos = int(pos * self._inv_step_dist + 0.5)
|
||||
else:
|
||||
steppos = int(pos * self._inv_step_dist - 0.5)
|
||||
self._mcu_position_offset += self._commanded_pos - steppos
|
||||
self._commanded_pos = steppos
|
||||
def get_commanded_position(self):
|
||||
return self._commanded_pos * self._step_dist
|
||||
def get_mcu_position(self):
|
||||
return self._commanded_pos + self._mcu_position_offset
|
||||
def note_homing_start(self, homing_clock):
|
||||
ret = self._ffi_lib.stepcompress_set_homing(
|
||||
self._stepqueue, homing_clock)
|
||||
if ret:
|
||||
raise error("Internal error in stepcompress")
|
||||
def note_homing_finalized(self):
|
||||
ret = self._ffi_lib.stepcompress_set_homing(self._stepqueue, 0)
|
||||
if ret:
|
||||
raise error("Internal error in stepcompress")
|
||||
ret = self._ffi_lib.stepcompress_reset(self._stepqueue, 0)
|
||||
if ret:
|
||||
raise error("Internal error in stepcompress")
|
||||
def note_homing_triggered(self):
|
||||
cmd = self._get_position_cmd.encode(self._oid)
|
||||
params = self._mcu.send_with_response(cmd, 'stepper_position', self._oid)
|
||||
pos = params['pos']
|
||||
if self._invert_dir:
|
||||
pos = -pos
|
||||
self._mcu_position_offset = pos - self._commanded_pos
|
||||
def reset_step_clock(self, print_time):
|
||||
clock = self._mcu.print_time_to_clock(print_time)
|
||||
ret = self._ffi_lib.stepcompress_reset(self._stepqueue, clock)
|
||||
if ret:
|
||||
raise error("Internal error in stepcompress")
|
||||
data = (self._reset_cmd.msgid, self._oid, clock & 0xffffffff)
|
||||
ret = self._ffi_lib.stepcompress_queue_msg(
|
||||
self._stepqueue, data, len(data))
|
||||
if ret:
|
||||
raise error("Internal error in stepcompress")
|
||||
def step(self, print_time, sdir):
|
||||
count = self._ffi_lib.stepcompress_push(
|
||||
self._stepqueue, print_time, sdir)
|
||||
if count == STEPCOMPRESS_ERROR_RET:
|
||||
raise error("Internal error in stepcompress")
|
||||
self._commanded_pos += count
|
||||
def step_const(self, print_time, start_pos, dist, start_v, accel):
|
||||
inv_step_dist = self._inv_step_dist
|
||||
step_offset = self._commanded_pos - start_pos * inv_step_dist
|
||||
count = self._ffi_lib.stepcompress_push_const(
|
||||
self._stepqueue, print_time, step_offset, dist * inv_step_dist,
|
||||
start_v * inv_step_dist, accel * inv_step_dist)
|
||||
if count == STEPCOMPRESS_ERROR_RET:
|
||||
raise error("Internal error in stepcompress")
|
||||
self._commanded_pos += count
|
||||
def step_delta(self, print_time, dist, start_v, accel
|
||||
, height_base, startxy_d, arm_d, movez_r):
|
||||
inv_step_dist = self._inv_step_dist
|
||||
height = self._commanded_pos - height_base * inv_step_dist
|
||||
count = self._ffi_lib.stepcompress_push_delta(
|
||||
self._stepqueue, print_time, dist * inv_step_dist,
|
||||
start_v * inv_step_dist, accel * inv_step_dist,
|
||||
height, startxy_d * inv_step_dist, arm_d * inv_step_dist, movez_r)
|
||||
if count == STEPCOMPRESS_ERROR_RET:
|
||||
raise error("Internal error in stepcompress")
|
||||
self._commanded_pos += count
|
||||
|
||||
class MCU_endstop:
|
||||
error = error
|
||||
RETRY_QUERY = 1.000
|
||||
def __init__(self, mcu, pin_params):
|
||||
self._mcu = mcu
|
||||
self._steppers = []
|
||||
self._pin = pin_params['pin']
|
||||
self._pullup = pin_params['pullup']
|
||||
self._invert = pin_params['invert']
|
||||
self._cmd_queue = mcu.alloc_command_queue()
|
||||
self._oid = self._home_cmd = self._query_cmd = None
|
||||
self._homing = False
|
||||
self._min_query_time = self._next_query_time = self._home_timeout = 0.
|
||||
self._last_state = {}
|
||||
def get_mcu(self):
|
||||
return self._mcu
|
||||
def add_stepper(self, stepper):
|
||||
self._steppers.append(stepper)
|
||||
def build_config(self):
|
||||
self._oid = self._mcu.create_oid()
|
||||
self._mcu.add_config_cmd(
|
||||
"config_end_stop oid=%d pin=%s pull_up=%d stepper_count=%d" % (
|
||||
self._oid, self._pin, self._pullup, len(self._steppers)))
|
||||
for i, s in enumerate(self._steppers):
|
||||
self._mcu.add_config_cmd(
|
||||
"end_stop_set_stepper oid=%d pos=%d stepper_oid=%d" % (
|
||||
self._oid, i, s.get_oid()), is_init=True)
|
||||
self._home_cmd = self._mcu.lookup_command(
|
||||
"end_stop_home oid=%c clock=%u sample_ticks=%u sample_count=%c"
|
||||
" rest_ticks=%u pin_value=%c")
|
||||
self._query_cmd = self._mcu.lookup_command("end_stop_query oid=%c")
|
||||
self._mcu.register_msg(self._handle_end_stop_state, "end_stop_state"
|
||||
, self._oid)
|
||||
def home_start(self, print_time, sample_time, sample_count, rest_time):
|
||||
clock = self._mcu.print_time_to_clock(print_time)
|
||||
rest_ticks = int(rest_time * self._mcu.get_adjusted_freq())
|
||||
self._homing = True
|
||||
self._min_query_time = self._mcu.monotonic()
|
||||
self._next_query_time = print_time + self.RETRY_QUERY
|
||||
msg = self._home_cmd.encode(
|
||||
self._oid, clock, self._mcu.seconds_to_clock(sample_time),
|
||||
sample_count, rest_ticks, 1 ^ self._invert)
|
||||
self._mcu.send(msg, reqclock=clock, cq=self._cmd_queue)
|
||||
for s in self._steppers:
|
||||
s.note_homing_start(clock)
|
||||
def home_finalize(self, print_time):
|
||||
for s in self._steppers:
|
||||
s.note_homing_finalized()
|
||||
self._home_timeout = print_time
|
||||
def home_wait(self):
|
||||
eventtime = self._mcu.monotonic()
|
||||
while self._check_busy(eventtime):
|
||||
eventtime = self._mcu.pause(eventtime + 0.1)
|
||||
def _handle_end_stop_state(self, params):
|
||||
logging.debug("end_stop_state %s", params)
|
||||
self._last_state = params
|
||||
def _check_busy(self, eventtime):
|
||||
# Check if need to send an end_stop_query command
|
||||
if self._mcu.is_fileoutput():
|
||||
return False
|
||||
print_time = self._mcu.estimated_print_time(eventtime)
|
||||
last_sent_time = self._last_state.get('#sent_time', -1.)
|
||||
if last_sent_time >= self._min_query_time:
|
||||
if not self._homing:
|
||||
return False
|
||||
if not self._last_state.get('homing', 0):
|
||||
for s in self._steppers:
|
||||
s.note_homing_triggered()
|
||||
self._homing = False
|
||||
return False
|
||||
if print_time > self._home_timeout:
|
||||
# Timeout - disable endstop checking
|
||||
msg = self._home_cmd.encode(self._oid, 0, 0, 0, 0, 0)
|
||||
self._mcu.send(msg, reqclock=0, cq=self._cmd_queue)
|
||||
raise error("Timeout during endstop homing")
|
||||
if self._mcu.is_shutdown():
|
||||
raise error("MCU is shutdown")
|
||||
if print_time >= self._next_query_time:
|
||||
self._next_query_time = print_time + self.RETRY_QUERY
|
||||
msg = self._query_cmd.encode(self._oid)
|
||||
self._mcu.send(msg, cq=self._cmd_queue)
|
||||
return True
|
||||
def query_endstop(self, print_time):
|
||||
self._homing = False
|
||||
self._next_query_time = print_time
|
||||
self._min_query_time = self._mcu.monotonic()
|
||||
def query_endstop_wait(self):
|
||||
eventtime = self._mcu.monotonic()
|
||||
while self._check_busy(eventtime):
|
||||
eventtime = self._mcu.pause(eventtime + 0.1)
|
||||
return self._last_state.get('pin', self._invert) ^ self._invert
|
||||
|
||||
class MCU_digital_out:
|
||||
def __init__(self, mcu, pin_params):
|
||||
self._mcu = mcu
|
||||
self._oid = None
|
||||
self._static_value = None
|
||||
self._pin = pin_params['pin']
|
||||
self._invert = self._shutdown_value = pin_params['invert']
|
||||
self._max_duration = 2.
|
||||
self._last_clock = 0
|
||||
self._last_value = None
|
||||
self._cmd_queue = mcu.alloc_command_queue()
|
||||
self._set_cmd = None
|
||||
def get_mcu(self):
|
||||
return self._mcu
|
||||
def setup_max_duration(self, max_duration):
|
||||
self._max_duration = max_duration
|
||||
def setup_static(self):
|
||||
self._static_value = not self._invert
|
||||
def setup_shutdown_value(self, value):
|
||||
self._shutdown_value = (not not value) ^ self._invert
|
||||
def build_config(self):
|
||||
if self._static_value is not None:
|
||||
self._mcu.add_config_cmd("set_digital_out pin=%s value=%d" % (
|
||||
self._pin, self._static_value))
|
||||
return
|
||||
self._oid = self._mcu.create_oid()
|
||||
self._mcu.add_config_cmd(
|
||||
"config_digital_out oid=%d pin=%s value=%d default_value=%d"
|
||||
" max_duration=%d" % (
|
||||
self._oid, self._pin, self._invert, self._shutdown_value,
|
||||
self._mcu.seconds_to_clock(self._max_duration)))
|
||||
self._set_cmd = self._mcu.lookup_command(
|
||||
"schedule_digital_out oid=%c clock=%u value=%c")
|
||||
def set_digital(self, print_time, value):
|
||||
clock = self._mcu.print_time_to_clock(print_time)
|
||||
msg = self._set_cmd.encode(
|
||||
self._oid, clock, (not not value) ^ self._invert)
|
||||
self._mcu.send(msg, minclock=self._last_clock, reqclock=clock
|
||||
, cq=self._cmd_queue)
|
||||
self._last_clock = clock
|
||||
self._last_value = value
|
||||
def get_last_setting(self):
|
||||
return self._last_value
|
||||
def set_pwm(self, print_time, value):
|
||||
self.set_digital(print_time, value >= 0.5)
|
||||
|
||||
class MCU_pwm:
|
||||
def __init__(self, mcu, pin_params):
|
||||
self._mcu = mcu
|
||||
self._hard_pwm = False
|
||||
self._cycle_time = 0.100
|
||||
self._max_duration = 2.
|
||||
self._oid = None
|
||||
self._static_value = None
|
||||
self._pin = pin_params['pin']
|
||||
self._invert = pin_params['invert']
|
||||
self._shutdown_value = float(self._invert)
|
||||
self._last_clock = 0
|
||||
self._pwm_max = 0.
|
||||
self._cmd_queue = mcu.alloc_command_queue()
|
||||
self._set_cmd = None
|
||||
def get_mcu(self):
|
||||
return self._mcu
|
||||
def setup_max_duration(self, max_duration):
|
||||
self._max_duration = max_duration
|
||||
def setup_cycle_time(self, cycle_time):
|
||||
self._cycle_time = cycle_time
|
||||
self._hard_pwm = False
|
||||
def setup_hard_pwm(self, hard_cycle_ticks):
|
||||
if not hard_cycle_ticks:
|
||||
return
|
||||
self._cycle_time = hard_cycle_ticks
|
||||
self._hard_pwm = True
|
||||
def setup_static_pwm(self, value):
|
||||
if self._invert:
|
||||
value = 1. - value
|
||||
self._static_value = max(0., min(1., value))
|
||||
def setup_shutdown_value(self, value):
|
||||
if self._invert:
|
||||
value = 1. - value
|
||||
self._shutdown_value = max(0., min(1., value))
|
||||
def build_config(self):
|
||||
if self._hard_pwm:
|
||||
self._pwm_max = self._mcu.get_constant_float("PWM_MAX")
|
||||
if self._static_value is not None:
|
||||
value = int(self._static_value * self._pwm_max + 0.5)
|
||||
self._mcu.add_config_cmd(
|
||||
"set_pwm_out pin=%s cycle_ticks=%d value=%d" % (
|
||||
self._pin, self._cycle_time, value))
|
||||
return
|
||||
self._oid = self._mcu.create_oid()
|
||||
self._mcu.add_config_cmd(
|
||||
"config_pwm_out oid=%d pin=%s cycle_ticks=%d value=%d"
|
||||
" default_value=%d max_duration=%d" % (
|
||||
self._oid, self._pin, self._cycle_time,
|
||||
self._invert * self._pwm_max,
|
||||
self._shutdown_value * self._pwm_max,
|
||||
self._mcu.seconds_to_clock(self._max_duration)))
|
||||
self._set_cmd = self._mcu.lookup_command(
|
||||
"schedule_pwm_out oid=%c clock=%u value=%hu")
|
||||
else:
|
||||
self._pwm_max = self._mcu.get_constant_float("SOFT_PWM_MAX")
|
||||
if self._static_value is not None:
|
||||
if self._static_value not in [0., 1.]:
|
||||
raise pins.error(
|
||||
"static value must be 0.0 or 1.0 on soft pwm")
|
||||
self._mcu.add_config_cmd("set_digital_out pin=%s value=%d" % (
|
||||
self._pin, self._static_value >= 0.5))
|
||||
return
|
||||
if self._shutdown_value not in [0., 1.]:
|
||||
raise pins.error(
|
||||
"shutdown value must be 0.0 or 1.0 on soft pwm")
|
||||
self._oid = self._mcu.create_oid()
|
||||
self._mcu.add_config_cmd(
|
||||
"config_soft_pwm_out oid=%d pin=%s cycle_ticks=%d value=%d"
|
||||
" default_value=%d max_duration=%d" % (
|
||||
self._oid, self._pin,
|
||||
self._mcu.seconds_to_clock(self._cycle_time),
|
||||
self._invert, self._shutdown_value >= 0.5,
|
||||
self._mcu.seconds_to_clock(self._max_duration)))
|
||||
self._set_cmd = self._mcu.lookup_command(
|
||||
"schedule_soft_pwm_out oid=%c clock=%u value=%hu")
|
||||
def set_pwm(self, print_time, value):
|
||||
clock = self._mcu.print_time_to_clock(print_time)
|
||||
if self._invert:
|
||||
value = 1. - value
|
||||
value = int(max(0., min(1., value)) * self._pwm_max + 0.5)
|
||||
msg = self._set_cmd.encode(self._oid, clock, value)
|
||||
self._mcu.send(msg, minclock=self._last_clock, reqclock=clock
|
||||
, cq=self._cmd_queue)
|
||||
self._last_clock = clock
|
||||
|
||||
class MCU_adc:
|
||||
def __init__(self, mcu, pin_params):
|
||||
self._mcu = mcu
|
||||
self._pin = pin_params['pin']
|
||||
self._min_sample = self._max_sample = 0.
|
||||
self._sample_time = self._report_time = 0.
|
||||
self._sample_count = 0
|
||||
self._report_clock = 0
|
||||
self._oid = self._callback = None
|
||||
self._inv_max_adc = 0.
|
||||
self._cmd_queue = mcu.alloc_command_queue()
|
||||
def get_mcu(self):
|
||||
return self._mcu
|
||||
def setup_minmax(self, sample_time, sample_count, minval=0., maxval=1.):
|
||||
self._sample_time = sample_time
|
||||
self._sample_count = sample_count
|
||||
self._min_sample = minval
|
||||
self._max_sample = maxval
|
||||
def setup_adc_callback(self, report_time, callback):
|
||||
self._report_time = report_time
|
||||
self._callback = callback
|
||||
def build_config(self):
|
||||
if not self._sample_count:
|
||||
return
|
||||
self._oid = self._mcu.create_oid()
|
||||
self._mcu.add_config_cmd("config_analog_in oid=%d pin=%s" % (
|
||||
self._oid, self._pin))
|
||||
clock = self._mcu.get_query_slot(self._oid)
|
||||
sample_ticks = self._mcu.seconds_to_clock(self._sample_time)
|
||||
mcu_adc_max = self._mcu.get_constant_float("ADC_MAX")
|
||||
max_adc = self._sample_count * mcu_adc_max
|
||||
self._inv_max_adc = 1.0 / max_adc
|
||||
self._report_clock = self._mcu.seconds_to_clock(self._report_time)
|
||||
min_sample = max(0, min(0xffff, int(self._min_sample * max_adc)))
|
||||
max_sample = max(0, min(0xffff, int(
|
||||
math.ceil(self._max_sample * max_adc))))
|
||||
self._mcu.add_config_cmd(
|
||||
"query_analog_in oid=%d clock=%d sample_ticks=%d sample_count=%d"
|
||||
" rest_ticks=%d min_value=%d max_value=%d" % (
|
||||
self._oid, clock, sample_ticks, self._sample_count,
|
||||
self._report_clock, min_sample, max_sample), is_init=True)
|
||||
self._mcu.register_msg(self._handle_analog_in_state, "analog_in_state"
|
||||
, self._oid)
|
||||
def _handle_analog_in_state(self, params):
|
||||
last_value = params['value'] * self._inv_max_adc
|
||||
next_clock = self._mcu.clock32_to_clock64(params['next_clock'])
|
||||
last_read_clock = next_clock - self._report_clock
|
||||
last_read_time = self._mcu.clock_to_print_time(last_read_clock)
|
||||
if self._callback is not None:
|
||||
self._callback(last_read_time, last_value)
|
||||
|
||||
class MCU:
|
||||
error = error
|
||||
def __init__(self, printer, config, clocksync):
|
||||
self._printer = printer
|
||||
self._clocksync = clocksync
|
||||
self._name = config.section
|
||||
if self._name.startswith('mcu '):
|
||||
self._name = self._name[4:]
|
||||
# Serial port
|
||||
self._serialport = config.get('serial', '/dev/ttyS0')
|
||||
baud = 0
|
||||
if not (self._serialport.startswith("/dev/rpmsg_")
|
||||
or self._serialport.startswith("/tmp/klipper_host_")):
|
||||
baud = config.getint('baud', 250000, minval=2400)
|
||||
self._serial = serialhdl.SerialReader(
|
||||
printer.reactor, self._serialport, baud)
|
||||
# Restarts
|
||||
self._restart_method = 'command'
|
||||
if baud:
|
||||
rmethods = {m: m for m in ['arduino', 'command', 'rpi_usb']}
|
||||
self._restart_method = config.getchoice(
|
||||
'restart_method', rmethods, 'arduino')
|
||||
self._reset_cmd = self._config_reset_cmd = None
|
||||
self._emergency_stop_cmd = None
|
||||
self._is_shutdown = False
|
||||
self._shutdown_msg = ""
|
||||
if printer.bglogger is not None:
|
||||
printer.bglogger.set_rollover_info(self._name, None)
|
||||
# Config building
|
||||
pins.get_printer_pins(printer).register_chip(self._name, self)
|
||||
self._oid_count = 0
|
||||
self._config_objects = []
|
||||
self._init_cmds = []
|
||||
self._config_cmds = []
|
||||
self._config_crc = None
|
||||
self._pin_map = config.get('pin_map', None)
|
||||
self._custom = config.get('custom', '')
|
||||
self._mcu_freq = 0.
|
||||
# Move command queuing
|
||||
ffi_main, self._ffi_lib = chelper.get_ffi()
|
||||
self._max_stepper_error = config.getfloat(
|
||||
'max_stepper_error', 0.000025, minval=0.)
|
||||
self._stepqueues = []
|
||||
self._steppersync = None
|
||||
# Stats
|
||||
self._stats_sumsq_base = 0.
|
||||
self._mcu_tick_avg = 0.
|
||||
self._mcu_tick_stddev = 0.
|
||||
self._mcu_tick_awake = 0.
|
||||
# Serial callbacks
|
||||
def handle_mcu_stats(self, params):
|
||||
count = params['count']
|
||||
tick_sum = params['sum']
|
||||
c = 1.0 / (count * self._mcu_freq)
|
||||
self._mcu_tick_avg = tick_sum * c
|
||||
tick_sumsq = params['sumsq'] * self._stats_sumsq_base
|
||||
self._mcu_tick_stddev = c * math.sqrt(count*tick_sumsq - tick_sum**2)
|
||||
self._mcu_tick_awake = tick_sum / self._mcu_freq
|
||||
def handle_shutdown(self, params):
|
||||
if self._is_shutdown:
|
||||
return
|
||||
self._is_shutdown = True
|
||||
self._shutdown_msg = msg = params['#msg']
|
||||
logging.info("MCU '%s' %s: %s\n%s\n%s", self._name, params['#name'],
|
||||
self._shutdown_msg, self._clocksync.dump_debug(),
|
||||
self._serial.dump_debug())
|
||||
prefix = "MCU '%s' shutdown: " % (self._name,)
|
||||
if params['#name'] == 'is_shutdown':
|
||||
prefix = "Previous MCU '%s' shutdown: " % (self._name,)
|
||||
self._printer.invoke_async_shutdown(prefix + msg + error_help(msg))
|
||||
# Connection phase
|
||||
def _check_restart(self, reason):
|
||||
start_reason = self._printer.get_start_args().get("start_reason")
|
||||
if start_reason == 'firmware_restart':
|
||||
return
|
||||
logging.info("Attempting automated MCU '%s' restart: %s",
|
||||
self._name, reason)
|
||||
self._printer.request_exit('firmware_restart')
|
||||
self._printer.reactor.pause(self._printer.reactor.monotonic() + 2.000)
|
||||
raise error("Attempt MCU '%s' restart failed" % (self._name,))
|
||||
def _connect_file(self, pace=False):
|
||||
# In a debugging mode. Open debug output file and read data dictionary
|
||||
start_args = self._printer.get_start_args()
|
||||
if self._name == 'mcu':
|
||||
out_fname = start_args.get('debugoutput')
|
||||
dict_fname = start_args.get('dictionary')
|
||||
else:
|
||||
out_fname = start_args.get('debugoutput') + "-" + self._name
|
||||
dict_fname = start_args.get('dictionary_' + self._name)
|
||||
outfile = open(out_fname, 'wb')
|
||||
dfile = open(dict_fname, 'rb')
|
||||
dict_data = dfile.read()
|
||||
dfile.close()
|
||||
self._serial.connect_file(outfile, dict_data)
|
||||
self._clocksync.connect_file(self._serial, pace)
|
||||
# Handle pacing
|
||||
if not pace:
|
||||
def dummy_estimated_print_time(eventtime):
|
||||
return 0.
|
||||
self.estimated_print_time = dummy_estimated_print_time
|
||||
def _add_custom(self):
|
||||
for line in self._custom.split('\n'):
|
||||
line = line.strip()
|
||||
cpos = line.find('#')
|
||||
if cpos >= 0:
|
||||
line = line[:cpos].strip()
|
||||
if not line:
|
||||
continue
|
||||
self.add_config_cmd(line)
|
||||
def _build_config(self):
|
||||
# Build config commands
|
||||
for co in self._config_objects:
|
||||
co.build_config()
|
||||
self._add_custom()
|
||||
self._config_cmds.insert(0, "allocate_oids count=%d" % (
|
||||
self._oid_count,))
|
||||
|
||||
# Resolve pin names
|
||||
mcu = self._serial.msgparser.get_constant('MCU')
|
||||
pnames = pins.get_pin_map(mcu, self._pin_map)
|
||||
updated_cmds = []
|
||||
for cmd in self._config_cmds:
|
||||
try:
|
||||
updated_cmds.append(pins.update_command(cmd, pnames))
|
||||
except:
|
||||
raise pins.error("Unable to translate pin name: %s" % (cmd,))
|
||||
self._config_cmds = updated_cmds
|
||||
|
||||
# Calculate config CRC
|
||||
self._config_crc = zlib.crc32('\n'.join(self._config_cmds)) & 0xffffffff
|
||||
self.add_config_cmd("finalize_config crc=%d" % (self._config_crc,))
|
||||
def _send_config(self):
|
||||
msg = self.create_command("get_config")
|
||||
if self.is_fileoutput():
|
||||
config_params = {
|
||||
'is_config': 0, 'move_count': 500, 'crc': self._config_crc}
|
||||
else:
|
||||
config_params = self.send_with_response(msg, 'config')
|
||||
if not config_params['is_config']:
|
||||
if self._restart_method == 'rpi_usb':
|
||||
# Only configure mcu after usb power reset
|
||||
self._check_restart("full reset before config")
|
||||
# Send config commands
|
||||
logging.info("Sending MCU '%s' printer configuration...",
|
||||
self._name)
|
||||
for c in self._config_cmds:
|
||||
self.send(self.create_command(c))
|
||||
if not self.is_fileoutput():
|
||||
config_params = self.send_with_response(msg, 'config')
|
||||
if not config_params['is_config']:
|
||||
if self._is_shutdown:
|
||||
raise error("MCU '%s' error during config: %s" % (
|
||||
self._name, self._shutdown_msg))
|
||||
raise error("Unable to configure MCU '%s'" % (self._name,))
|
||||
else:
|
||||
start_reason = self._printer.get_start_args().get("start_reason")
|
||||
if start_reason == 'firmware_restart':
|
||||
raise error("Failed automated reset of MCU '%s'" % (self._name,))
|
||||
if self._config_crc != config_params['crc']:
|
||||
self._check_restart("CRC mismatch")
|
||||
raise error("MCU '%s' CRC does not match config" % (self._name,))
|
||||
move_count = config_params['move_count']
|
||||
logging.info("Configured MCU '%s' (%d moves)", self._name, move_count)
|
||||
if self._printer.bglogger is not None:
|
||||
msgparser = self._serial.msgparser
|
||||
info = [
|
||||
"Configured MCU '%s' (%d moves)" % (self._name, move_count),
|
||||
"Loaded MCU '%s' %d commands (%s)" % (
|
||||
self._name, len(msgparser.messages_by_id),
|
||||
msgparser.version),
|
||||
"MCU '%s' config: %s" % (self._name, " ".join(
|
||||
["%s=%s" % (k, v) for k, v in msgparser.config.items()]))]
|
||||
self._printer.bglogger.set_rollover_info(self._name, "\n".join(info))
|
||||
self._steppersync = self._ffi_lib.steppersync_alloc(
|
||||
self._serial.serialqueue, self._stepqueues, len(self._stepqueues),
|
||||
move_count)
|
||||
self._ffi_lib.steppersync_set_time(self._steppersync, 0., self._mcu_freq)
|
||||
for c in self._init_cmds:
|
||||
self.send(self.create_command(c))
|
||||
def connect(self):
|
||||
if self.is_fileoutput():
|
||||
self._connect_file()
|
||||
else:
|
||||
if (self._restart_method == 'rpi_usb'
|
||||
and not os.path.exists(self._serialport)):
|
||||
# Try toggling usb power
|
||||
self._check_restart("enable power")
|
||||
self._serial.connect()
|
||||
self._clocksync.connect(self._serial)
|
||||
self._mcu_freq = self.get_constant_float('CLOCK_FREQ')
|
||||
self._stats_sumsq_base = self.get_constant_float('STATS_SUMSQ_BASE')
|
||||
self._emergency_stop_cmd = self.lookup_command("emergency_stop")
|
||||
self._reset_cmd = self.try_lookup_command("reset")
|
||||
self._config_reset_cmd = self.try_lookup_command("config_reset")
|
||||
self.register_msg(self.handle_shutdown, 'shutdown')
|
||||
self.register_msg(self.handle_shutdown, 'is_shutdown')
|
||||
self.register_msg(self.handle_mcu_stats, 'stats')
|
||||
self._build_config()
|
||||
self._send_config()
|
||||
# Config creation helpers
|
||||
def setup_pin(self, pin_params):
|
||||
pcs = {'stepper': MCU_stepper, 'endstop': MCU_endstop,
|
||||
'digital_out': MCU_digital_out, 'pwm': MCU_pwm, 'adc': MCU_adc}
|
||||
pin_type = pin_params['type']
|
||||
if pin_type not in pcs:
|
||||
raise pins.error("pin type %s not supported on mcu" % (pin_type,))
|
||||
co = pcs[pin_type](self, pin_params)
|
||||
self.add_config_object(co)
|
||||
return co
|
||||
def create_oid(self):
|
||||
self._oid_count += 1
|
||||
return self._oid_count - 1
|
||||
def add_config_object(self, co):
|
||||
self._config_objects.append(co)
|
||||
def add_config_cmd(self, cmd, is_init=False):
|
||||
if is_init:
|
||||
self._init_cmds.append(cmd)
|
||||
else:
|
||||
self._config_cmds.append(cmd)
|
||||
def get_query_slot(self, oid):
|
||||
slot = self.seconds_to_clock(oid * .01)
|
||||
t = int(self.estimated_print_time(self.monotonic()) + 1.5)
|
||||
return self.print_time_to_clock(t) + slot
|
||||
def register_stepqueue(self, stepqueue):
|
||||
self._stepqueues.append(stepqueue)
|
||||
def seconds_to_clock(self, time):
|
||||
return int(time * self._mcu_freq)
|
||||
def get_max_stepper_error(self):
|
||||
return self._max_stepper_error
|
||||
# Wrapper functions
|
||||
def send(self, cmd, minclock=0, reqclock=0, cq=None):
|
||||
self._serial.send(cmd, minclock, reqclock, cq=cq)
|
||||
def send_with_response(self, cmd, name, oid=None):
|
||||
return self._serial.send_with_response(cmd, name, oid)
|
||||
def register_msg(self, cb, msg, oid=None):
|
||||
self._serial.register_callback(cb, msg, oid)
|
||||
def alloc_command_queue(self):
|
||||
return self._serial.alloc_command_queue()
|
||||
def create_command(self, msg):
|
||||
return self._serial.msgparser.create_command(msg)
|
||||
def lookup_command(self, msgformat):
|
||||
return self._serial.msgparser.lookup_command(msgformat)
|
||||
def try_lookup_command(self, msgformat):
|
||||
try:
|
||||
return self._serial.msgparser.lookup_command(msgformat)
|
||||
except self._serial.msgparser.error as e:
|
||||
return None
|
||||
def get_constant_float(self, name):
|
||||
return self._serial.msgparser.get_constant_float(name)
|
||||
def print_time_to_clock(self, print_time):
|
||||
return self._clocksync.print_time_to_clock(print_time)
|
||||
def clock_to_print_time(self, clock):
|
||||
return self._clocksync.clock_to_print_time(clock)
|
||||
def estimated_print_time(self, eventtime):
|
||||
return self._clocksync.estimated_print_time(eventtime)
|
||||
def get_adjusted_freq(self):
|
||||
return self._clocksync.get_adjusted_freq()
|
||||
def clock32_to_clock64(self, clock32):
|
||||
return self._clocksync.clock32_to_clock64(clock32)
|
||||
def pause(self, waketime):
|
||||
return self._printer.reactor.pause(waketime)
|
||||
def monotonic(self):
|
||||
return self._printer.reactor.monotonic()
|
||||
# Restarts
|
||||
def _restart_arduino(self):
|
||||
logging.info("Attempting MCU '%s' reset", self._name)
|
||||
self.disconnect()
|
||||
serialhdl.arduino_reset(self._serialport, self._printer.reactor)
|
||||
def _restart_via_command(self):
|
||||
reactor = self._printer.reactor
|
||||
if ((self._reset_cmd is None and self._config_reset_cmd is None)
|
||||
or not self._clocksync.is_active(reactor.monotonic())):
|
||||
logging.info("Unable to issue reset command on MCU '%s'", self._name)
|
||||
return
|
||||
if self._reset_cmd is None:
|
||||
# Attempt reset via config_reset command
|
||||
logging.info("Attempting MCU '%s' config_reset command", self._name)
|
||||
self._is_shutdown = True
|
||||
self.do_shutdown(force=True)
|
||||
reactor.pause(reactor.monotonic() + 0.015)
|
||||
self.send(self._config_reset_cmd.encode())
|
||||
else:
|
||||
# Attempt reset via reset command
|
||||
logging.info("Attempting MCU '%s' reset command", self._name)
|
||||
self.send(self._reset_cmd.encode())
|
||||
reactor.pause(reactor.monotonic() + 0.015)
|
||||
self.disconnect()
|
||||
def _restart_rpi_usb(self):
|
||||
logging.info("Attempting MCU '%s' reset via rpi usb power", self._name)
|
||||
self.disconnect()
|
||||
chelper.run_hub_ctrl(0)
|
||||
self._printer.reactor.pause(self._printer.reactor.monotonic() + 2.)
|
||||
chelper.run_hub_ctrl(1)
|
||||
def microcontroller_restart(self):
|
||||
if self._restart_method == 'rpi_usb':
|
||||
self._restart_rpi_usb()
|
||||
elif self._restart_method == 'command':
|
||||
self._restart_via_command()
|
||||
else:
|
||||
self._restart_arduino()
|
||||
# Misc external commands
|
||||
def is_fileoutput(self):
|
||||
return self._printer.get_start_args().get('debugoutput') is not None
|
||||
def is_shutdown(self):
|
||||
return self._is_shutdown
|
||||
def flush_moves(self, print_time):
|
||||
if self._steppersync is None:
|
||||
return
|
||||
clock = self.print_time_to_clock(print_time)
|
||||
if clock < 0:
|
||||
return
|
||||
ret = self._ffi_lib.steppersync_flush(self._steppersync, clock)
|
||||
if ret:
|
||||
raise error("Internal error in MCU '%s' stepcompress" % (
|
||||
self._name,))
|
||||
def check_active(self, print_time, eventtime):
|
||||
if self._steppersync is None:
|
||||
return
|
||||
offset, freq = self._clocksync.calibrate_clock(print_time, eventtime)
|
||||
self._ffi_lib.steppersync_set_time(self._steppersync, offset, freq)
|
||||
if self._clocksync.is_active(eventtime) or self.is_fileoutput():
|
||||
return
|
||||
logging.info("Timeout with MCU '%s' (eventtime=%f)",
|
||||
self._name, eventtime)
|
||||
self._printer.invoke_shutdown("Lost communication with MCU '%s'" % (
|
||||
self._name,))
|
||||
def stats(self, eventtime):
|
||||
msg = "%s: mcu_awake=%.03f mcu_task_avg=%.06f mcu_task_stddev=%.06f" % (
|
||||
self._name, self._mcu_tick_awake, self._mcu_tick_avg,
|
||||
self._mcu_tick_stddev)
|
||||
return ' '.join([msg, self._serial.stats(eventtime),
|
||||
self._clocksync.stats(eventtime)])
|
||||
def do_shutdown(self, force=False):
|
||||
if self._emergency_stop_cmd is None or (self._is_shutdown and not force):
|
||||
return
|
||||
self.send(self._emergency_stop_cmd.encode())
|
||||
def disconnect(self):
|
||||
self._serial.disconnect()
|
||||
if self._steppersync is not None:
|
||||
self._ffi_lib.steppersync_free(self._steppersync)
|
||||
self._steppersync = None
|
||||
def __del__(self):
|
||||
self.disconnect()
|
||||
|
||||
Common_MCU_errors = {
|
||||
("Timer too close", "No next step", "Missed scheduling of next "): """
|
||||
This is generally indicative of an intermittent
|
||||
communication failure between micro-controller and host.""",
|
||||
("ADC out of range",): """
|
||||
This generally occurs when a heater temperature exceeds
|
||||
its configured min_temp or max_temp.""",
|
||||
("Rescheduled timer in the past", "Stepper too far in past"): """
|
||||
This generally occurs when the micro-controller has been
|
||||
requested to step at a rate higher than it is capable of
|
||||
obtaining.""",
|
||||
("Command request",): """
|
||||
This generally occurs in response to an M112 G-Code command
|
||||
or in response to an internal error in the host software.""",
|
||||
}
|
||||
|
||||
def error_help(msg):
|
||||
for prefixes, help_msg in Common_MCU_errors.items():
|
||||
for prefix in prefixes:
|
||||
if msg.startswith(prefix):
|
||||
return help_msg
|
||||
return ""
|
||||
|
||||
def add_printer_objects(printer, config):
|
||||
mainsync = clocksync.ClockSync(printer.reactor)
|
||||
printer.add_object('mcu', MCU(printer, config.getsection('mcu'), mainsync))
|
||||
for s in config.get_prefix_sections('mcu '):
|
||||
printer.add_object(s.section, MCU(
|
||||
printer, s, clocksync.SecondarySync(printer.reactor, mainsync)))
|
||||
|
||||
def get_printer_mcus(printer):
|
||||
return [printer.objects[n] for n in sorted(printer.objects)
|
||||
if n.startswith('mcu')]
|
||||
|
||||
def get_printer_mcu(printer, name):
|
||||
mcu_name = name
|
||||
if name != 'mcu':
|
||||
mcu_name = 'mcu ' + name
|
||||
if mcu_name not in printer.objects:
|
||||
raise printer.config_error("Unknown MCU %s" % (name,))
|
||||
return printer.objects[mcu_name]
|
||||
337
klippy/msgproto.py
Normal file
@@ -0,0 +1,337 @@
|
||||
# Protocol definitions for firmware communication
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import json, zlib, logging
|
||||
|
||||
DefaultMessages = {
|
||||
0: "identify_response offset=%u data=%.*s",
|
||||
1: "identify offset=%u count=%c",
|
||||
}
|
||||
|
||||
MESSAGE_MIN = 5
|
||||
MESSAGE_MAX = 64
|
||||
MESSAGE_HEADER_SIZE = 2
|
||||
MESSAGE_TRAILER_SIZE = 3
|
||||
MESSAGE_POS_LEN = 0
|
||||
MESSAGE_POS_SEQ = 1
|
||||
MESSAGE_TRAILER_CRC = 3
|
||||
MESSAGE_TRAILER_SYNC = 1
|
||||
MESSAGE_PAYLOAD_MAX = MESSAGE_MAX - MESSAGE_MIN
|
||||
MESSAGE_SEQ_MASK = 0x0f
|
||||
MESSAGE_DEST = 0x10
|
||||
MESSAGE_SYNC = '\x7E'
|
||||
|
||||
class error(Exception):
|
||||
pass
|
||||
|
||||
def crc16_ccitt(buf):
|
||||
crc = 0xffff
|
||||
for data in buf:
|
||||
data = ord(data)
|
||||
data ^= crc & 0xff
|
||||
data ^= (data & 0x0f) << 4
|
||||
crc = ((data << 8) | (crc >> 8)) ^ (data >> 4) ^ (data << 3)
|
||||
crc = chr(crc >> 8) + chr(crc & 0xff)
|
||||
return crc
|
||||
|
||||
class PT_uint32:
|
||||
is_int = 1
|
||||
max_length = 5
|
||||
signed = 0
|
||||
def encode(self, out, v):
|
||||
if v >= 0xc000000 or v < -0x4000000: out.append((v>>28) & 0x7f | 0x80)
|
||||
if v >= 0x180000 or v < -0x80000: out.append((v>>21) & 0x7f | 0x80)
|
||||
if v >= 0x3000 or v < -0x1000: out.append((v>>14) & 0x7f | 0x80)
|
||||
if v >= 0x60 or v < -0x20: out.append((v>>7) & 0x7f | 0x80)
|
||||
out.append(v & 0x7f)
|
||||
def parse(self, s, pos):
|
||||
c = s[pos]
|
||||
pos += 1
|
||||
v = c & 0x7f
|
||||
if (c & 0x60) == 0x60:
|
||||
v |= -0x20
|
||||
while c & 0x80:
|
||||
c = s[pos]
|
||||
pos += 1
|
||||
v = (v<<7) | (c & 0x7f)
|
||||
if not self.signed:
|
||||
v = int(v & 0xffffffff)
|
||||
return v, pos
|
||||
|
||||
class PT_int32(PT_uint32):
|
||||
signed = 1
|
||||
class PT_uint16(PT_uint32):
|
||||
max_length = 3
|
||||
class PT_int16(PT_int32):
|
||||
signed = 1
|
||||
max_length = 3
|
||||
class PT_byte(PT_uint32):
|
||||
max_length = 2
|
||||
|
||||
class PT_string:
|
||||
is_int = 0
|
||||
max_length = 64
|
||||
def encode(self, out, v):
|
||||
out.append(len(v))
|
||||
out.extend(bytearray(v))
|
||||
def parse(self, s, pos):
|
||||
l = s[pos]
|
||||
return str(bytearray(s[pos+1:pos+l+1])), pos+l+1
|
||||
class PT_progmem_buffer(PT_string):
|
||||
pass
|
||||
class PT_buffer(PT_string):
|
||||
pass
|
||||
|
||||
MessageTypes = {
|
||||
'%u': PT_uint32(), '%i': PT_int32(),
|
||||
'%hu': PT_uint16(), '%hi': PT_int16(),
|
||||
'%c': PT_byte(),
|
||||
'%s': PT_string(), '%.*s': PT_progmem_buffer(), '%*s': PT_buffer(),
|
||||
}
|
||||
|
||||
# Update the message format to be compatible with python's % operator
|
||||
def convert_msg_format(msgformat):
|
||||
mf = msgformat.replace('%c', '%u')
|
||||
mf = mf.replace('%.*s', '%s').replace('%*s', '%s')
|
||||
return mf
|
||||
|
||||
class MessageFormat:
|
||||
def __init__(self, msgid, msgformat):
|
||||
self.msgid = msgid
|
||||
self.msgformat = msgformat
|
||||
self.debugformat = convert_msg_format(msgformat)
|
||||
parts = msgformat.split()
|
||||
self.name = parts[0]
|
||||
argparts = [arg.split('=') for arg in parts[1:]]
|
||||
self.param_types = [MessageTypes[fmt] for name, fmt in argparts]
|
||||
self.param_names = [(name, MessageTypes[fmt]) for name, fmt in argparts]
|
||||
self.name_to_type = dict(self.param_names)
|
||||
def encode(self, *params):
|
||||
out = []
|
||||
out.append(self.msgid)
|
||||
for i, t in enumerate(self.param_types):
|
||||
t.encode(out, params[i])
|
||||
return out
|
||||
def encode_by_name(self, **params):
|
||||
out = []
|
||||
out.append(self.msgid)
|
||||
for name, t in self.param_names:
|
||||
t.encode(out, params[name])
|
||||
return out
|
||||
def parse(self, s, pos):
|
||||
pos += 1
|
||||
out = {}
|
||||
for name, t in self.param_names:
|
||||
v, pos = t.parse(s, pos)
|
||||
out[name] = v
|
||||
return out, pos
|
||||
def format_params(self, params):
|
||||
out = []
|
||||
for name, t in self.param_names:
|
||||
v = params[name]
|
||||
if not t.is_int:
|
||||
v = repr(v)
|
||||
out.append(v)
|
||||
return self.debugformat % tuple(out)
|
||||
|
||||
class OutputFormat:
|
||||
name = '#output'
|
||||
def __init__(self, msgid, msgformat):
|
||||
self.msgid = msgid
|
||||
self.msgformat = msgformat
|
||||
self.debugformat = convert_msg_format(msgformat)
|
||||
self.param_types = []
|
||||
args = msgformat
|
||||
while 1:
|
||||
pos = args.find('%')
|
||||
if pos < 0:
|
||||
break
|
||||
if pos+1 >= len(args) or args[pos+1] != '%':
|
||||
for i in range(4):
|
||||
t = MessageTypes.get(args[pos:pos+1+i])
|
||||
if t is not None:
|
||||
self.param_types.append(t)
|
||||
break
|
||||
else:
|
||||
raise error("Invalid output format for '%s'" % (msg,))
|
||||
args = args[pos+1:]
|
||||
def parse(self, s, pos):
|
||||
pos += 1
|
||||
out = []
|
||||
for t in self.param_types:
|
||||
v, pos = t.parse(s, pos)
|
||||
if not t.is_int:
|
||||
v = repr(v)
|
||||
out.append(v)
|
||||
outmsg = self.debugformat % tuple(out)
|
||||
return {'#msg': outmsg}, pos
|
||||
def format_params(self, params):
|
||||
return "#output %s" % (params['#msg'],)
|
||||
|
||||
class UnknownFormat:
|
||||
name = '#unknown'
|
||||
def parse(self, s, pos):
|
||||
msgid = s[pos]
|
||||
msg = str(bytearray(s))
|
||||
return {'#msgid': msgid, '#msg': msg}, len(s)-MESSAGE_TRAILER_SIZE
|
||||
def format_params(self, params):
|
||||
return "#unknown %s" % (repr(params['#msg']),)
|
||||
|
||||
class MessageParser:
|
||||
error = error
|
||||
def __init__(self):
|
||||
self.unknown = UnknownFormat()
|
||||
self.command_ids = []
|
||||
self.messages_by_id = {}
|
||||
self.messages_by_name = {}
|
||||
self.static_strings = {}
|
||||
self.config = {}
|
||||
self.version = ""
|
||||
self.raw_identify_data = ""
|
||||
self._init_messages(DefaultMessages, DefaultMessages.keys())
|
||||
def check_packet(self, s):
|
||||
if len(s) < MESSAGE_MIN:
|
||||
return 0
|
||||
msglen = ord(s[MESSAGE_POS_LEN])
|
||||
if msglen < MESSAGE_MIN or msglen > MESSAGE_MAX:
|
||||
return -1
|
||||
msgseq = ord(s[MESSAGE_POS_SEQ])
|
||||
if (msgseq & ~MESSAGE_SEQ_MASK) != MESSAGE_DEST:
|
||||
return -1
|
||||
if len(s) < msglen:
|
||||
# Need more data
|
||||
return 0
|
||||
if s[msglen-MESSAGE_TRAILER_SYNC] != MESSAGE_SYNC:
|
||||
return -1
|
||||
msgcrc = s[msglen-MESSAGE_TRAILER_CRC:msglen-MESSAGE_TRAILER_CRC+2]
|
||||
crc = crc16_ccitt(s[:msglen-MESSAGE_TRAILER_SIZE])
|
||||
if crc != msgcrc:
|
||||
#logging.debug("got crc %s vs %s", repr(crc), repr(msgcrc))
|
||||
return -1
|
||||
return msglen
|
||||
def dump(self, s):
|
||||
msgseq = s[MESSAGE_POS_SEQ]
|
||||
out = ["seq: %02x" % (msgseq,)]
|
||||
pos = MESSAGE_HEADER_SIZE
|
||||
while 1:
|
||||
msgid = s[pos]
|
||||
mid = self.messages_by_id.get(msgid, self.unknown)
|
||||
params, pos = mid.parse(s, pos)
|
||||
out.append(mid.format_params(params))
|
||||
if pos >= len(s)-MESSAGE_TRAILER_SIZE:
|
||||
break
|
||||
return out
|
||||
def format_params(self, params):
|
||||
name = params.get('#name')
|
||||
mid = self.messages_by_name.get(name)
|
||||
if mid is not None:
|
||||
return mid.format_params(params)
|
||||
msg = params.get('#msg')
|
||||
if msg is not None:
|
||||
return "%s %s" % (name, msg)
|
||||
return str(params)
|
||||
def parse(self, s):
|
||||
msgid = s[MESSAGE_HEADER_SIZE]
|
||||
mid = self.messages_by_id.get(msgid, self.unknown)
|
||||
params, pos = mid.parse(s, MESSAGE_HEADER_SIZE)
|
||||
if pos != len(s)-MESSAGE_TRAILER_SIZE:
|
||||
raise error("Extra data at end of message")
|
||||
params['#name'] = mid.name
|
||||
static_string_id = params.get('static_string_id')
|
||||
if static_string_id is not None:
|
||||
params['#msg'] = self.static_strings.get(static_string_id, "?")
|
||||
return params
|
||||
def encode(self, seq, cmd):
|
||||
msglen = MESSAGE_MIN + len(cmd)
|
||||
seq = (seq & MESSAGE_SEQ_MASK) | MESSAGE_DEST
|
||||
out = [chr(msglen), chr(seq), cmd]
|
||||
out.append(crc16_ccitt(''.join(out)))
|
||||
out.append(MESSAGE_SYNC)
|
||||
return ''.join(out)
|
||||
def _parse_buffer(self, value):
|
||||
tval = int(value, 16)
|
||||
out = []
|
||||
for i in range(len(value) // 2):
|
||||
out.append(tval & 0xff)
|
||||
tval >>= 8
|
||||
out.reverse()
|
||||
return ''.join([chr(i) for i in out])
|
||||
def lookup_command(self, msgformat):
|
||||
parts = msgformat.strip().split()
|
||||
msgname = parts[0]
|
||||
mp = self.messages_by_name.get(msgname)
|
||||
if mp is None:
|
||||
raise error("Unknown command: %s" % (msgname,))
|
||||
if msgformat != mp.msgformat:
|
||||
raise error("Command format mismatch: %s vs %s" % (
|
||||
msgformat, mp.msgformat))
|
||||
return mp
|
||||
def create_command(self, msg):
|
||||
parts = msg.strip().split()
|
||||
if not parts:
|
||||
return ""
|
||||
msgname = parts[0]
|
||||
mp = self.messages_by_name.get(msgname)
|
||||
if mp is None:
|
||||
raise error("Unknown command: %s" % (msgname,))
|
||||
try:
|
||||
argparts = dict(arg.split('=', 1) for arg in parts[1:])
|
||||
for name, value in argparts.items():
|
||||
t = mp.name_to_type[name]
|
||||
if t.is_int:
|
||||
tval = int(value, 0)
|
||||
else:
|
||||
tval = self._parse_buffer(value)
|
||||
argparts[name] = tval
|
||||
except:
|
||||
#traceback.print_exc()
|
||||
raise error("Unable to extract params from: %s" % (msgname,))
|
||||
try:
|
||||
cmd = mp.encode_by_name(**argparts)
|
||||
except:
|
||||
#traceback.print_exc()
|
||||
raise error("Unable to encode: %s" % (msgname,))
|
||||
return cmd
|
||||
def _init_messages(self, messages, parsers):
|
||||
for msgid, msgformat in messages.items():
|
||||
msgid = int(msgid)
|
||||
if msgid not in parsers:
|
||||
self.messages_by_id[msgid] = OutputFormat(msgid, msgformat)
|
||||
continue
|
||||
msg = MessageFormat(msgid, msgformat)
|
||||
self.messages_by_id[msgid] = msg
|
||||
self.messages_by_name[msg.name] = msg
|
||||
def process_identify(self, data, decompress=True):
|
||||
try:
|
||||
if decompress:
|
||||
data = zlib.decompress(data)
|
||||
self.raw_identify_data = data
|
||||
data = json.loads(data)
|
||||
messages = data.get('messages')
|
||||
commands = data.get('commands')
|
||||
self.command_ids = commands
|
||||
responses = data.get('responses')
|
||||
self._init_messages(messages, commands+responses)
|
||||
static_strings = data.get('static_strings', {})
|
||||
self.static_strings = { int(k): v for k, v in static_strings.items() }
|
||||
self.config.update(data.get('config', {}))
|
||||
self.version = data.get('version', '')
|
||||
except error as e:
|
||||
raise
|
||||
except Exception as e:
|
||||
logging.exception("process_identify error")
|
||||
raise error("Error during identify: %s" % (str(e),))
|
||||
def get_constant(self, name):
|
||||
try:
|
||||
return self.config[name]
|
||||
except KeyError:
|
||||
raise error("Firmware constant '%s' not found" % (name,))
|
||||
def get_constant_float(self, name):
|
||||
try:
|
||||
return float(self.config[name])
|
||||
except ValueError:
|
||||
raise error("Firmware constant '%s' not a float" % (name,))
|
||||
except KeyError:
|
||||
raise error("Firmware constant '%s' not found" % (name,))
|
||||
45
klippy/parsedump.py
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python2
|
||||
# Script to parse a serial port data dump
|
||||
#
|
||||
# Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import os, sys, logging
|
||||
import msgproto
|
||||
|
||||
def read_dictionary(filename):
|
||||
dfile = open(filename, 'rb')
|
||||
dictionary = dfile.read()
|
||||
dfile.close()
|
||||
return dictionary
|
||||
|
||||
def main():
|
||||
dict_filename, data_filename = sys.argv[1:]
|
||||
|
||||
dictionary = read_dictionary(dict_filename)
|
||||
|
||||
mp = msgproto.MessageParser()
|
||||
mp.process_identify(dictionary, decompress=False)
|
||||
|
||||
f = open(data_filename, 'rb')
|
||||
fd = f.fileno()
|
||||
data = ""
|
||||
while 1:
|
||||
newdata = os.read(fd, 4096)
|
||||
if not newdata:
|
||||
break
|
||||
data += newdata
|
||||
while 1:
|
||||
l = mp.check_packet(data)
|
||||
if l == 0:
|
||||
break
|
||||
if l < 0:
|
||||
logging.error("Invalid data")
|
||||
data = data[-l:]
|
||||
continue
|
||||
msgs = mp.dump(bytearray(data[:l]))
|
||||
sys.stdout.write('\n'.join(msgs[1:]) + '\n')
|
||||
data = data[l:]
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
216
klippy/pins.py
Normal file
@@ -0,0 +1,216 @@
|
||||
# Pin name to pin number definitions
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import re
|
||||
|
||||
|
||||
######################################################################
|
||||
# Hardware pin names
|
||||
######################################################################
|
||||
|
||||
def port_pins(port_count, bit_count=8):
|
||||
pins = {}
|
||||
for port in range(port_count):
|
||||
portchr = chr(65 + port)
|
||||
if portchr == 'I':
|
||||
continue
|
||||
for portbit in range(bit_count):
|
||||
pins['P%c%d' % (portchr, portbit)] = port * bit_count + portbit
|
||||
return pins
|
||||
|
||||
def named_pins(fmt, port_count, bit_count=32):
|
||||
return { fmt % (port, portbit) : port * bit_count + portbit
|
||||
for port in range(port_count)
|
||||
for portbit in range(bit_count) }
|
||||
|
||||
def beaglebone_pins():
|
||||
gpios = named_pins("gpio%d_%d", 4)
|
||||
gpios.update({"AIN%d" % i: i+4*32 for i in range(8)})
|
||||
return gpios
|
||||
|
||||
MCU_PINS = {
|
||||
"atmega168": port_pins(4), "atmega328": port_pins(4),
|
||||
"atmega644p": port_pins(4), "atmega1284p": port_pins(4),
|
||||
"at90usb1286": port_pins(6),
|
||||
"atmega1280": port_pins(12), "atmega2560": port_pins(12),
|
||||
"sam3x8e": port_pins(4, 32),
|
||||
"pru": beaglebone_pins(),
|
||||
"linux": {"analog%d" % i: i for i in range(8)}, # XXX
|
||||
}
|
||||
|
||||
|
||||
######################################################################
|
||||
# Arduino mappings
|
||||
######################################################################
|
||||
|
||||
Arduino_standard = [
|
||||
"PD0", "PD1", "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", "PB0", "PB1",
|
||||
"PB2", "PB3", "PB4", "PB5", "PC0", "PC1", "PC2", "PC3", "PC4", "PC5",
|
||||
]
|
||||
Arduino_analog_standard = [
|
||||
"PC0", "PC1", "PC2", "PC3", "PC4", "PC5", "PE0", "PE1",
|
||||
]
|
||||
|
||||
Arduino_mega = [
|
||||
"PE0", "PE1", "PE4", "PE5", "PG5", "PE3", "PH3", "PH4", "PH5", "PH6",
|
||||
"PB4", "PB5", "PB6", "PB7", "PJ1", "PJ0", "PH1", "PH0", "PD3", "PD2",
|
||||
"PD1", "PD0", "PA0", "PA1", "PA2", "PA3", "PA4", "PA5", "PA6", "PA7",
|
||||
"PC7", "PC6", "PC5", "PC4", "PC3", "PC2", "PC1", "PC0", "PD7", "PG2",
|
||||
"PG1", "PG0", "PL7", "PL6", "PL5", "PL4", "PL3", "PL2", "PL1", "PL0",
|
||||
"PB3", "PB2", "PB1", "PB0", "PF0", "PF1", "PF2", "PF3", "PF4", "PF5",
|
||||
"PF6", "PF7", "PK0", "PK1", "PK2", "PK3", "PK4", "PK5", "PK6", "PK7",
|
||||
]
|
||||
Arduino_analog_mega = [
|
||||
"PF0", "PF1", "PF2", "PF3", "PF4", "PF5",
|
||||
"PF6", "PF7", "PK0", "PK1", "PK2", "PK3", "PK4", "PK5", "PK6", "PK7",
|
||||
]
|
||||
|
||||
Sanguino = [
|
||||
"PB0", "PB1", "PB2", "PB3", "PB4", "PB5", "PB6", "PB7", "PD0", "PD1",
|
||||
"PD2", "PD3", "PD4", "PD5", "PD6", "PD7", "PC0", "PC1", "PC2", "PC3",
|
||||
"PC4", "PC5", "PC6", "PC7", "PA0", "PA1", "PA2", "PA3", "PA4", "PA5",
|
||||
"PA6", "PA7"
|
||||
]
|
||||
Sanguino_analog = [
|
||||
"PA0", "PA1", "PA2", "PA3", "PA4", "PA5", "PA6", "PA7"
|
||||
]
|
||||
|
||||
Arduino_Due = [
|
||||
"PA8", "PA9", "PB25", "PC28", "PA29", "PC25", "PC24", "PC23", "PC22", "PC21",
|
||||
"PA28", "PD7", "PD8", "PB27", "PD4", "PD5", "PA13", "PA12", "PA11", "PA10",
|
||||
"PB12", "PB13", "PB26", "PA14", "PA15", "PD0", "PD1", "PD2", "PD3", "PD6",
|
||||
"PD9", "PA7", "PD10", "PC1", "PC2", "PC3", "PC4", "PC5", "PC6", "PC7",
|
||||
"PC8", "PC9", "PA19", "PA20", "PC19", "PC18", "PC17", "PC16", "PC15", "PC14",
|
||||
"PC13", "PC12", "PB21", "PB14", "PA16", "PA24", "PA23", "PA22", "PA6", "PA4",
|
||||
"PA3", "PA2", "PB17", "PB18", "PB19", "PB20", "PB15", "PB16", "PA1", "PA0",
|
||||
"PA17", "PA18", "PC30", "PA21", "PA25", "PA26", "PA27", "PA28", "PB23"
|
||||
]
|
||||
Arduino_Due_analog = [
|
||||
"PA16", "PA24", "PA23", "PA22", "PA6", "PA4", "PA3", "PA2", "PB17", "PB18",
|
||||
"PB19", "PB20"
|
||||
]
|
||||
|
||||
|
||||
Arduino_from_mcu = {
|
||||
"atmega168": (Arduino_standard, Arduino_analog_standard),
|
||||
"atmega644p": (Sanguino, Sanguino_analog),
|
||||
"atmega1280": (Arduino_mega, Arduino_analog_mega),
|
||||
"atmega2560": (Arduino_mega, Arduino_analog_mega),
|
||||
"sam3x8e": (Arduino_Due, Arduino_Due_analog),
|
||||
}
|
||||
|
||||
def update_map_arduino(pins, mcu):
|
||||
dpins, apins = Arduino_from_mcu.get(mcu, ([], []))
|
||||
for i in range(len(dpins)):
|
||||
pins['ar' + str(i)] = pins[dpins[i]]
|
||||
for i in range(len(apins)):
|
||||
pins['analog%d' % (i,)] = pins[apins[i]]
|
||||
|
||||
|
||||
######################################################################
|
||||
# Beaglebone mappings
|
||||
######################################################################
|
||||
|
||||
beagleboneblack_mappings = {
|
||||
'P8_3': 'gpio1_6', 'P8_4': 'gpio1_7', 'P8_5': 'gpio1_2',
|
||||
'P8_6': 'gpio1_3', 'P8_7': 'gpio2_2', 'P8_8': 'gpio2_3',
|
||||
'P8_9': 'gpio2_5', 'P8_10': 'gpio2_4', 'P8_11': 'gpio1_13',
|
||||
'P8_12': 'gpio1_12', 'P8_13': 'gpio0_23', 'P8_14': 'gpio0_26',
|
||||
'P8_15': 'gpio1_15', 'P8_16': 'gpio1_14', 'P8_17': 'gpio0_27',
|
||||
'P8_18': 'gpio2_1', 'P8_19': 'gpio0_22', 'P8_20': 'gpio1_31',
|
||||
'P8_21': 'gpio1_30', 'P8_22': 'gpio1_5', 'P8_23': 'gpio1_4',
|
||||
'P8_24': 'gpio1_1', 'P8_25': 'gpio1_0', 'P8_26': 'gpio1_29',
|
||||
'P8_27': 'gpio2_22', 'P8_28': 'gpio2_24', 'P8_29': 'gpio2_23',
|
||||
'P8_30': 'gpio2_25', 'P8_31': 'gpio0_10', 'P8_32': 'gpio0_11',
|
||||
'P8_33': 'gpio0_9', 'P8_34': 'gpio2_17', 'P8_35': 'gpio0_8',
|
||||
'P8_36': 'gpio2_16', 'P8_37': 'gpio2_14', 'P8_38': 'gpio2_15',
|
||||
'P8_39': 'gpio2_12', 'P8_40': 'gpio2_13', 'P8_41': 'gpio2_10',
|
||||
'P8_42': 'gpio2_11', 'P8_43': 'gpio2_8', 'P8_44': 'gpio2_9',
|
||||
'P8_45': 'gpio2_6', 'P8_46': 'gpio2_7', 'P9_11': 'gpio0_30',
|
||||
'P9_12': 'gpio1_28', 'P9_13': 'gpio0_31', 'P9_14': 'gpio1_18',
|
||||
'P9_15': 'gpio1_16', 'P9_16': 'gpio1_19', 'P9_17': 'gpio0_5',
|
||||
'P9_18': 'gpio0_4', 'P9_19': 'gpio0_13', 'P9_20': 'gpio0_12',
|
||||
'P9_21': 'gpio0_3', 'P9_22': 'gpio0_2', 'P9_23': 'gpio1_17',
|
||||
'P9_24': 'gpio0_15', 'P9_25': 'gpio3_21', 'P9_26': 'gpio0_14',
|
||||
'P9_27': 'gpio3_19', 'P9_28': 'gpio3_17', 'P9_29': 'gpio3_15',
|
||||
'P9_30': 'gpio3_16', 'P9_31': 'gpio3_14', 'P9_41': 'gpio0_20',
|
||||
'P9_42': 'gpio3_20', 'P9_43': 'gpio0_7', 'P9_44': 'gpio3_18',
|
||||
|
||||
'P9_33': 'AIN4', 'P9_35': 'AIN6', 'P9_36': 'AIN5', 'P9_37': 'AIN2',
|
||||
'P9_38': 'AIN3', 'P9_39': 'AIN0', 'P9_40': 'AIN1',
|
||||
}
|
||||
|
||||
def update_map_beaglebone(pins, mcu):
|
||||
for pin, gpio in beagleboneblack_mappings.items():
|
||||
pins[pin] = pins[gpio]
|
||||
|
||||
|
||||
######################################################################
|
||||
# Command translation
|
||||
######################################################################
|
||||
|
||||
# Obtains the pin mappings
|
||||
def get_pin_map(mcu, mapping_name=None):
|
||||
pins = dict(MCU_PINS.get(mcu, {}))
|
||||
if mapping_name == 'arduino':
|
||||
update_map_arduino(pins, mcu)
|
||||
elif mapping_name == 'beaglebone':
|
||||
update_map_beaglebone(pins, mcu)
|
||||
return pins
|
||||
|
||||
# Translate pin names in a firmware command
|
||||
re_pin = re.compile(r'(?P<prefix>[ _]pin=)(?P<name>[^ ]*)')
|
||||
def update_command(cmd, pmap):
|
||||
def pin_fixup(m):
|
||||
return m.group('prefix') + str(pmap[m.group('name')])
|
||||
return re_pin.sub(pin_fixup, cmd)
|
||||
|
||||
|
||||
######################################################################
|
||||
# Pin to chip mapping
|
||||
######################################################################
|
||||
|
||||
class error(Exception):
|
||||
pass
|
||||
|
||||
class PrinterPins:
|
||||
error = error
|
||||
def __init__(self):
|
||||
self.chips = {}
|
||||
def parse_pin_desc(self, pin_desc, can_invert=False, can_pullup=False):
|
||||
pullup = invert = 0
|
||||
if can_pullup and pin_desc.startswith('^'):
|
||||
pullup = 1
|
||||
pin_desc = pin_desc[1:].strip()
|
||||
if can_invert and pin_desc.startswith('!'):
|
||||
invert = 1
|
||||
pin_desc = pin_desc[1:].strip()
|
||||
if ':' not in pin_desc:
|
||||
chip_name, pin = 'mcu', pin_desc
|
||||
else:
|
||||
chip_name, pin = [s.strip() for s in pin_desc.split(':', 1)]
|
||||
if chip_name not in self.chips:
|
||||
raise error("Unknown pin chip name '%s'" % (chip_name,))
|
||||
return {'chip': self.chips[chip_name], 'pin': pin,
|
||||
'invert': invert, 'pullup': pullup}
|
||||
def register_chip(self, chip_name, chip):
|
||||
chip_name = chip_name.strip()
|
||||
if chip_name in self.chips:
|
||||
raise error("Duplicate chip name '%s'" % (chip_name,))
|
||||
self.chips[chip_name] = chip
|
||||
|
||||
def add_printer_objects(printer, config):
|
||||
printer.add_object('pins', PrinterPins())
|
||||
|
||||
def get_printer_pins(printer):
|
||||
return printer.objects['pins']
|
||||
|
||||
def setup_pin(printer, pin_type, pin_desc):
|
||||
ppins = get_printer_pins(printer)
|
||||
can_invert = pin_type in ['stepper', 'endstop', 'digital_out', 'pwm']
|
||||
can_pullup = pin_type == 'endstop'
|
||||
pin_params = ppins.parse_pin_desc(pin_desc, can_invert, can_pullup)
|
||||
pin_params['type'] = pin_type
|
||||
return pin_params['chip'].setup_pin(pin_params)
|
||||
93
klippy/pyhelper.c
Normal file
@@ -0,0 +1,93 @@
|
||||
// Helper functions for C / Python interface
|
||||
//
|
||||
// Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include <errno.h> // errno
|
||||
#include <stdarg.h> // va_start
|
||||
#include <stdint.h> // uint8_t
|
||||
#include <stdio.h> // fprintf
|
||||
#include <string.h> // strerror
|
||||
#include <time.h> // struct timespec
|
||||
#include "pyhelper.h" // get_monotonic
|
||||
|
||||
// Return the monotonic system time as a double
|
||||
double
|
||||
get_monotonic(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
if (ret) {
|
||||
report_errno("clock_gettime", ret);
|
||||
return 0.;
|
||||
}
|
||||
return (double)ts.tv_sec + (double)ts.tv_nsec * .000000001;
|
||||
}
|
||||
|
||||
// Fill a 'struct timespec' with a system time stored in a double
|
||||
struct timespec
|
||||
fill_time(double time)
|
||||
{
|
||||
time_t t = time;
|
||||
return (struct timespec) {t, (time - t)*1000000000. };
|
||||
}
|
||||
|
||||
static void
|
||||
default_logger(const char *msg)
|
||||
{
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
}
|
||||
|
||||
static void (*python_logging_callback)(const char *msg) = default_logger;
|
||||
|
||||
void
|
||||
set_python_logging_callback(void (*func)(const char *))
|
||||
{
|
||||
python_logging_callback = func;
|
||||
}
|
||||
|
||||
// Log an error message
|
||||
void
|
||||
errorf(const char *fmt, ...)
|
||||
{
|
||||
char buf[512];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
python_logging_callback(buf);
|
||||
}
|
||||
|
||||
// Report 'errno' in a message written to stderr
|
||||
void
|
||||
report_errno(char *where, int rc)
|
||||
{
|
||||
int e = errno;
|
||||
errorf("Got error %d in %s: (%d)%s", rc, where, e, strerror(e));
|
||||
}
|
||||
|
||||
// Return a hex character for a given number
|
||||
#define GETHEX(x) ((x) < 10 ? '0' + (x) : 'a' + (x) - 10)
|
||||
|
||||
// Translate a binary string into an ASCII string with escape sequences
|
||||
char *
|
||||
dump_string(char *outbuf, int outbuf_size, char *inbuf, int inbuf_size)
|
||||
{
|
||||
char *outend = &outbuf[outbuf_size-5], *o = outbuf;
|
||||
uint8_t *inend = (void*)&inbuf[inbuf_size], *p = (void*)inbuf;
|
||||
while (p < inend && o < outend) {
|
||||
uint8_t c = *p++;
|
||||
if (c > 31 && c < 127 && c != '\\') {
|
||||
*o++ = c;
|
||||
continue;
|
||||
}
|
||||
*o++ = '\\';
|
||||
*o++ = 'x';
|
||||
*o++ = GETHEX(c >> 4);
|
||||
*o++ = GETHEX(c & 0x0f);
|
||||
}
|
||||
*o = '\0';
|
||||
return outbuf;
|
||||
}
|
||||
14
klippy/pyhelper.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef PYHELPER_H
|
||||
#define PYHELPER_H
|
||||
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
double get_monotonic(void);
|
||||
struct timespec fill_time(double time);
|
||||
void set_python_logging_callback(void (*func)(const char *));
|
||||
void errorf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
void report_errno(char *where, int rc);
|
||||
char *dump_string(char *outbuf, int outbuf_size, char *inbuf, int inbuf_size);
|
||||
|
||||
#endif // pyhelper.h
|
||||
60
klippy/queuelogger.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# Code to implement asynchronous logging from a background thread
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import logging, logging.handlers, threading, Queue, time
|
||||
|
||||
# Class to forward all messages through a queue to a background thread
|
||||
class QueueHandler(logging.Handler):
|
||||
def __init__(self, queue):
|
||||
logging.Handler.__init__(self)
|
||||
self.queue = queue
|
||||
def emit(self, record):
|
||||
try:
|
||||
self.format(record)
|
||||
record.msg = record.message
|
||||
record.args = None
|
||||
record.exc_info = None
|
||||
self.queue.put_nowait(record)
|
||||
except Exception:
|
||||
self.handleError(record)
|
||||
|
||||
# Class to poll a queue in a background thread and log each message
|
||||
class QueueListener(logging.handlers.TimedRotatingFileHandler):
|
||||
def __init__(self, filename):
|
||||
logging.handlers.TimedRotatingFileHandler.__init__(
|
||||
self, filename, when='midnight', backupCount=5)
|
||||
self.bg_queue = Queue.Queue()
|
||||
self.bg_thread = threading.Thread(target=self._bg_thread)
|
||||
self.bg_thread.start()
|
||||
self.rollover_info = {}
|
||||
def _bg_thread(self):
|
||||
while 1:
|
||||
record = self.bg_queue.get(True)
|
||||
if record is None:
|
||||
break
|
||||
self.handle(record)
|
||||
def stop(self):
|
||||
self.bg_queue.put_nowait(None)
|
||||
self.bg_thread.join()
|
||||
def set_rollover_info(self, name, info):
|
||||
self.rollover_info[name] = info
|
||||
def doRollover(self):
|
||||
logging.handlers.TimedRotatingFileHandler.doRollover(self)
|
||||
lines = [self.rollover_info[name]
|
||||
for name in sorted(self.rollover_info)
|
||||
if self.rollover_info[name]]
|
||||
lines.append(
|
||||
"=============== Log rollover at %s ===============" % (
|
||||
time.asctime(),))
|
||||
self.emit(logging.makeLogRecord(
|
||||
{'msg': "\n".join(lines), 'level': logging.INFO}))
|
||||
|
||||
def setup_bg_logging(filename, debuglevel):
|
||||
ql = QueueListener(filename)
|
||||
qh = QueueHandler(ql.bg_queue)
|
||||
root = logging.getLogger()
|
||||
root.addHandler(qh)
|
||||
root.setLevel(debuglevel)
|
||||
return ql
|
||||
201
klippy/reactor.py
Normal file
@@ -0,0 +1,201 @@
|
||||
# File descriptor and timer event helper
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import select, math, time
|
||||
import greenlet
|
||||
import chelper
|
||||
|
||||
class ReactorTimer:
|
||||
def __init__(self, callback, waketime):
|
||||
self.callback = callback
|
||||
self.waketime = waketime
|
||||
|
||||
class ReactorFileHandler:
|
||||
def __init__(self, fd, callback):
|
||||
self.fd = fd
|
||||
self.callback = callback
|
||||
def fileno(self):
|
||||
return self.fd
|
||||
|
||||
class ReactorGreenlet(greenlet.greenlet):
|
||||
def __init__(self, run):
|
||||
greenlet.greenlet.__init__(self, run=run)
|
||||
self.timer = None
|
||||
|
||||
class SelectReactor:
|
||||
NOW = 0.
|
||||
NEVER = 9999999999999999.
|
||||
def __init__(self):
|
||||
self._fds = []
|
||||
self._timers = []
|
||||
self._next_timer = self.NEVER
|
||||
self._process = False
|
||||
self._g_dispatch = None
|
||||
self._greenlets = []
|
||||
self.monotonic = chelper.get_ffi()[1].get_monotonic
|
||||
# Timers
|
||||
def _note_time(self, t):
|
||||
nexttime = t.waketime
|
||||
if nexttime < self._next_timer:
|
||||
self._next_timer = nexttime
|
||||
def update_timer(self, t, nexttime):
|
||||
t.waketime = nexttime
|
||||
self._note_time(t)
|
||||
def register_timer(self, callback, waketime = NEVER):
|
||||
handler = ReactorTimer(callback, waketime)
|
||||
timers = list(self._timers)
|
||||
timers.append(handler)
|
||||
self._timers = timers
|
||||
self._note_time(handler)
|
||||
return handler
|
||||
def unregister_timer(self, handler):
|
||||
timers = list(self._timers)
|
||||
timers.pop(timers.index(handler))
|
||||
self._timers = timers
|
||||
def _check_timers(self, eventtime):
|
||||
if eventtime < self._next_timer:
|
||||
return min(1., max(.001, self._next_timer - eventtime))
|
||||
self._next_timer = self.NEVER
|
||||
g_dispatch = self._g_dispatch
|
||||
for t in self._timers:
|
||||
if eventtime >= t.waketime:
|
||||
t.waketime = self.NEVER
|
||||
t.waketime = t.callback(eventtime)
|
||||
if g_dispatch is not self._g_dispatch:
|
||||
self._end_greenlet(g_dispatch)
|
||||
return 0.
|
||||
self._note_time(t)
|
||||
if eventtime >= self._next_timer:
|
||||
return 0.
|
||||
return min(1., max(.001, self._next_timer - self.monotonic()))
|
||||
# Greenlets
|
||||
def _sys_pause(self, waketime):
|
||||
# Pause using system sleep for when reactor not running
|
||||
delay = waketime - self.monotonic()
|
||||
if delay > 0.:
|
||||
time.sleep(delay)
|
||||
return self.monotonic()
|
||||
def pause(self, waketime):
|
||||
g = greenlet.getcurrent()
|
||||
if g is not self._g_dispatch:
|
||||
if self._g_dispatch is None:
|
||||
return self._sys_pause(waketime)
|
||||
return self._g_dispatch.switch(waketime)
|
||||
if self._greenlets:
|
||||
g_next = self._greenlets.pop()
|
||||
else:
|
||||
g_next = ReactorGreenlet(run=self._dispatch_loop)
|
||||
g_next.parent = g.parent
|
||||
g.timer = self.register_timer(g.switch, waketime)
|
||||
return g_next.switch()
|
||||
def _end_greenlet(self, g_old):
|
||||
self._greenlets.append(g_old)
|
||||
self.unregister_timer(g_old.timer)
|
||||
g_old.timer = None
|
||||
self._g_dispatch.switch(self.NEVER)
|
||||
self._g_dispatch = g_old
|
||||
# File descriptors
|
||||
def register_fd(self, fd, callback):
|
||||
handler = ReactorFileHandler(fd, callback)
|
||||
self._fds.append(handler)
|
||||
return handler
|
||||
def unregister_fd(self, handler):
|
||||
self._fds.pop(self._fds.index(handler))
|
||||
# Main loop
|
||||
def _dispatch_loop(self):
|
||||
self._g_dispatch = g_dispatch = greenlet.getcurrent()
|
||||
eventtime = self.monotonic()
|
||||
while self._process:
|
||||
timeout = self._check_timers(eventtime)
|
||||
res = select.select(self._fds, [], [], timeout)
|
||||
eventtime = self.monotonic()
|
||||
for fd in res[0]:
|
||||
fd.callback(eventtime)
|
||||
if g_dispatch is not self._g_dispatch:
|
||||
self._end_greenlet(g_dispatch)
|
||||
eventtime = self.monotonic()
|
||||
break
|
||||
self._g_dispatch = None
|
||||
def run(self):
|
||||
self._process = True
|
||||
g_next = ReactorGreenlet(run=self._dispatch_loop)
|
||||
g_next.switch()
|
||||
def end(self):
|
||||
self._process = False
|
||||
|
||||
class PollReactor(SelectReactor):
|
||||
def __init__(self):
|
||||
SelectReactor.__init__(self)
|
||||
self._poll = select.poll()
|
||||
self._fds = {}
|
||||
# File descriptors
|
||||
def register_fd(self, fd, callback):
|
||||
handler = ReactorFileHandler(fd, callback)
|
||||
fds = self._fds.copy()
|
||||
fds[fd] = callback
|
||||
self._fds = fds
|
||||
self._poll.register(handler, select.POLLIN | select.POLLHUP)
|
||||
return handler
|
||||
def unregister_fd(self, handler):
|
||||
self._poll.unregister(handler)
|
||||
fds = self._fds.copy()
|
||||
del fds[handler.fd]
|
||||
self._fds = fds
|
||||
# Main loop
|
||||
def _dispatch_loop(self):
|
||||
self._g_dispatch = g_dispatch = greenlet.getcurrent()
|
||||
eventtime = self.monotonic()
|
||||
while self._process:
|
||||
timeout = self._check_timers(eventtime)
|
||||
res = self._poll.poll(int(math.ceil(timeout * 1000.)))
|
||||
eventtime = self.monotonic()
|
||||
for fd, event in res:
|
||||
self._fds[fd](eventtime)
|
||||
if g_dispatch is not self._g_dispatch:
|
||||
self._end_greenlet(g_dispatch)
|
||||
eventtime = self.monotonic()
|
||||
break
|
||||
self._g_dispatch = None
|
||||
|
||||
class EPollReactor(SelectReactor):
|
||||
def __init__(self):
|
||||
SelectReactor.__init__(self)
|
||||
self._epoll = select.epoll()
|
||||
self._fds = {}
|
||||
# File descriptors
|
||||
def register_fd(self, fd, callback):
|
||||
handler = ReactorFileHandler(fd, callback)
|
||||
fds = self._fds.copy()
|
||||
fds[fd] = callback
|
||||
self._fds = fds
|
||||
self._epoll.register(fd, select.EPOLLIN | select.EPOLLHUP)
|
||||
return handler
|
||||
def unregister_fd(self, handler):
|
||||
self._epoll.unregister(handler.fd)
|
||||
fds = self._fds.copy()
|
||||
del fds[handler.fd]
|
||||
self._fds = fds
|
||||
# Main loop
|
||||
def _dispatch_loop(self):
|
||||
self._g_dispatch = g_dispatch = greenlet.getcurrent()
|
||||
eventtime = self.monotonic()
|
||||
while self._process:
|
||||
timeout = self._check_timers(eventtime)
|
||||
res = self._epoll.poll(timeout)
|
||||
eventtime = self.monotonic()
|
||||
for fd, event in res:
|
||||
self._fds[fd](eventtime)
|
||||
if g_dispatch is not self._g_dispatch:
|
||||
self._end_greenlet(g_dispatch)
|
||||
eventtime = self.monotonic()
|
||||
break
|
||||
self._g_dispatch = None
|
||||
|
||||
# Use the poll based reactor if it is available
|
||||
try:
|
||||
select.poll
|
||||
Reactor = PollReactor
|
||||
except:
|
||||
Reactor = SelectReactor
|
||||
284
klippy/serialhdl.py
Normal file
@@ -0,0 +1,284 @@
|
||||
# Serial port management for firmware communication
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import logging, threading
|
||||
import serial
|
||||
|
||||
import msgproto, chelper, util
|
||||
|
||||
class error(Exception):
|
||||
pass
|
||||
|
||||
class SerialReader:
|
||||
BITS_PER_BYTE = 10.
|
||||
def __init__(self, reactor, serialport, baud):
|
||||
self.reactor = reactor
|
||||
self.serialport = serialport
|
||||
self.baud = baud
|
||||
# Serial port
|
||||
self.ser = None
|
||||
self.msgparser = msgproto.MessageParser()
|
||||
# C interface
|
||||
self.ffi_main, self.ffi_lib = chelper.get_ffi()
|
||||
self.serialqueue = None
|
||||
self.default_cmd_queue = self.alloc_command_queue()
|
||||
self.stats_buf = self.ffi_main.new('char[4096]')
|
||||
# Threading
|
||||
self.lock = threading.Lock()
|
||||
self.background_thread = None
|
||||
# Message handlers
|
||||
handlers = {
|
||||
'#unknown': self.handle_unknown, '#output': self.handle_output,
|
||||
'shutdown': self.handle_output, 'is_shutdown': self.handle_output
|
||||
}
|
||||
self.handlers = { (k, None): v for k, v in handlers.items() }
|
||||
def _bg_thread(self):
|
||||
response = self.ffi_main.new('struct pull_queue_message *')
|
||||
while 1:
|
||||
self.ffi_lib.serialqueue_pull(self.serialqueue, response)
|
||||
count = response.len
|
||||
if count <= 0:
|
||||
break
|
||||
params = self.msgparser.parse(response.msg[0:count])
|
||||
params['#sent_time'] = response.sent_time
|
||||
params['#receive_time'] = response.receive_time
|
||||
hdl = (params['#name'], params.get('oid'))
|
||||
with self.lock:
|
||||
hdl = self.handlers.get(hdl, self.handle_default)
|
||||
try:
|
||||
hdl(params)
|
||||
except:
|
||||
logging.exception("Exception in serial callback")
|
||||
def connect(self):
|
||||
# Initial connection
|
||||
logging.info("Starting serial connect")
|
||||
while 1:
|
||||
starttime = self.reactor.monotonic()
|
||||
try:
|
||||
if self.baud:
|
||||
self.ser = serial.Serial(
|
||||
self.serialport, self.baud, timeout=0)
|
||||
else:
|
||||
self.ser = open(self.serialport, 'rb+')
|
||||
except (OSError, IOError, serial.SerialException) as e:
|
||||
logging.warn("Unable to open port: %s", e)
|
||||
self.reactor.pause(starttime + 5.)
|
||||
continue
|
||||
if self.baud:
|
||||
stk500v2_leave(self.ser, self.reactor)
|
||||
self.serialqueue = self.ffi_lib.serialqueue_alloc(
|
||||
self.ser.fileno(), 0)
|
||||
self.background_thread = threading.Thread(target=self._bg_thread)
|
||||
self.background_thread.start()
|
||||
# Obtain and load the data dictionary from the firmware
|
||||
sbs = SerialBootStrap(self)
|
||||
identify_data = sbs.get_identify_data(starttime + 5.)
|
||||
if identify_data is None:
|
||||
logging.warn("Timeout on serial connect")
|
||||
self.disconnect()
|
||||
continue
|
||||
break
|
||||
msgparser = msgproto.MessageParser()
|
||||
msgparser.process_identify(identify_data)
|
||||
self.msgparser = msgparser
|
||||
self.register_callback(self.handle_unknown, '#unknown')
|
||||
logging.info("Loaded %d commands (%s)",
|
||||
len(msgparser.messages_by_id), msgparser.version)
|
||||
logging.info("MCU config: %s", " ".join(
|
||||
["%s=%s" % (k, v) for k, v in msgparser.config.items()]))
|
||||
# Setup baud adjust
|
||||
mcu_baud = float(msgparser.config.get('SERIAL_BAUD', 0.))
|
||||
if mcu_baud:
|
||||
baud_adjust = self.BITS_PER_BYTE / mcu_baud
|
||||
self.ffi_lib.serialqueue_set_baud_adjust(
|
||||
self.serialqueue, baud_adjust)
|
||||
def connect_file(self, debugoutput, dictionary, pace=False):
|
||||
self.ser = debugoutput
|
||||
self.msgparser.process_identify(dictionary, decompress=False)
|
||||
self.serialqueue = self.ffi_lib.serialqueue_alloc(self.ser.fileno(), 1)
|
||||
def set_clock_est(self, freq, last_time, last_clock):
|
||||
self.ffi_lib.serialqueue_set_clock_est(
|
||||
self.serialqueue, freq, last_time, last_clock)
|
||||
def disconnect(self):
|
||||
if self.serialqueue is not None:
|
||||
self.ffi_lib.serialqueue_exit(self.serialqueue)
|
||||
if self.background_thread is not None:
|
||||
self.background_thread.join()
|
||||
self.ffi_lib.serialqueue_free(self.serialqueue)
|
||||
self.background_thread = self.serialqueue = None
|
||||
if self.ser is not None:
|
||||
self.ser.close()
|
||||
self.ser = None
|
||||
def stats(self, eventtime):
|
||||
if self.serialqueue is None:
|
||||
return ""
|
||||
self.ffi_lib.serialqueue_get_stats(
|
||||
self.serialqueue, self.stats_buf, len(self.stats_buf))
|
||||
return self.ffi_main.string(self.stats_buf)
|
||||
# Serial response callbacks
|
||||
def register_callback(self, callback, name, oid=None):
|
||||
with self.lock:
|
||||
self.handlers[name, oid] = callback
|
||||
def unregister_callback(self, name, oid=None):
|
||||
with self.lock:
|
||||
del self.handlers[name, oid]
|
||||
# Command sending
|
||||
def send(self, cmd, minclock=0, reqclock=0, cq=None):
|
||||
if cq is None:
|
||||
cq = self.default_cmd_queue
|
||||
self.ffi_lib.serialqueue_send(
|
||||
self.serialqueue, cq, cmd, len(cmd), minclock, reqclock)
|
||||
def encode_and_send(self, data, minclock, reqclock, cq):
|
||||
self.ffi_lib.serialqueue_encode_and_send(
|
||||
self.serialqueue, cq, data, len(data), minclock, reqclock)
|
||||
def send_with_response(self, cmd, name, oid=None):
|
||||
src = SerialRetryCommand(self, cmd, name, oid)
|
||||
return src.get_response()
|
||||
def alloc_command_queue(self):
|
||||
return self.ffi_main.gc(self.ffi_lib.serialqueue_alloc_commandqueue(),
|
||||
self.ffi_lib.serialqueue_free_commandqueue)
|
||||
# Dumping debug lists
|
||||
def dump_debug(self):
|
||||
out = []
|
||||
out.append("Dumping serial stats: %s" % (
|
||||
self.stats(self.reactor.monotonic()),))
|
||||
sdata = self.ffi_main.new('struct pull_queue_message[1024]')
|
||||
rdata = self.ffi_main.new('struct pull_queue_message[1024]')
|
||||
scount = self.ffi_lib.serialqueue_extract_old(
|
||||
self.serialqueue, 1, sdata, len(sdata))
|
||||
rcount = self.ffi_lib.serialqueue_extract_old(
|
||||
self.serialqueue, 0, rdata, len(rdata))
|
||||
out.append("Dumping send queue %d messages" % (scount,))
|
||||
for i in range(scount):
|
||||
msg = sdata[i]
|
||||
cmds = self.msgparser.dump(msg.msg[0:msg.len])
|
||||
out.append("Sent %d %f %f %d: %s" % (
|
||||
i, msg.receive_time, msg.sent_time, msg.len, ', '.join(cmds)))
|
||||
out.append("Dumping receive queue %d messages" % (rcount,))
|
||||
for i in range(rcount):
|
||||
msg = rdata[i]
|
||||
cmds = self.msgparser.dump(msg.msg[0:msg.len])
|
||||
out.append("Receive: %d %f %f %d: %s" % (
|
||||
i, msg.receive_time, msg.sent_time, msg.len, ', '.join(cmds)))
|
||||
return '\n'.join(out)
|
||||
# Default message handlers
|
||||
def handle_unknown(self, params):
|
||||
logging.warn("Unknown message type %d: %s",
|
||||
params['#msgid'], repr(params['#msg']))
|
||||
def handle_output(self, params):
|
||||
logging.info("%s: %s", params['#name'], params['#msg'])
|
||||
def handle_default(self, params):
|
||||
logging.warn("got %s", params)
|
||||
def __del__(self):
|
||||
self.disconnect()
|
||||
|
||||
# Class to retry sending of a query command until a given response is received
|
||||
class SerialRetryCommand:
|
||||
TIMEOUT_TIME = 5.0
|
||||
RETRY_TIME = 0.500
|
||||
def __init__(self, serial, cmd, name, oid=None):
|
||||
self.serial = serial
|
||||
self.cmd = cmd
|
||||
self.name = name
|
||||
self.oid = oid
|
||||
self.response = None
|
||||
self.min_query_time = self.serial.reactor.monotonic()
|
||||
self.serial.register_callback(self.handle_callback, self.name, self.oid)
|
||||
self.send_timer = self.serial.reactor.register_timer(
|
||||
self.send_event, self.serial.reactor.NOW)
|
||||
def unregister(self):
|
||||
self.serial.unregister_callback(self.name, self.oid)
|
||||
self.serial.reactor.unregister_timer(self.send_timer)
|
||||
def send_event(self, eventtime):
|
||||
if self.response is not None:
|
||||
return self.serial.reactor.NEVER
|
||||
self.serial.send(self.cmd)
|
||||
return eventtime + self.RETRY_TIME
|
||||
def handle_callback(self, params):
|
||||
last_sent_time = params['#sent_time']
|
||||
if last_sent_time >= self.min_query_time:
|
||||
self.response = params
|
||||
def get_response(self):
|
||||
eventtime = self.serial.reactor.monotonic()
|
||||
while self.response is None:
|
||||
eventtime = self.serial.reactor.pause(eventtime + 0.05)
|
||||
if eventtime > self.min_query_time + self.TIMEOUT_TIME:
|
||||
self.unregister()
|
||||
raise error("Timeout on wait for '%s' response" % (self.name,))
|
||||
self.unregister()
|
||||
return self.response
|
||||
|
||||
# Code to start communication and download message type dictionary
|
||||
class SerialBootStrap:
|
||||
RETRY_TIME = 0.500
|
||||
def __init__(self, serial):
|
||||
self.serial = serial
|
||||
self.identify_data = ""
|
||||
self.identify_cmd = self.serial.msgparser.lookup_command(
|
||||
"identify offset=%u count=%c")
|
||||
self.is_done = False
|
||||
self.serial.register_callback(self.handle_identify, 'identify_response')
|
||||
self.serial.register_callback(self.handle_unknown, '#unknown')
|
||||
self.send_timer = self.serial.reactor.register_timer(
|
||||
self.send_event, self.serial.reactor.NOW)
|
||||
def get_identify_data(self, timeout):
|
||||
eventtime = self.serial.reactor.monotonic()
|
||||
while not self.is_done and eventtime <= timeout:
|
||||
eventtime = self.serial.reactor.pause(eventtime + 0.05)
|
||||
self.serial.unregister_callback('identify_response')
|
||||
self.serial.reactor.unregister_timer(self.send_timer)
|
||||
if not self.is_done:
|
||||
return None
|
||||
return self.identify_data
|
||||
def handle_identify(self, params):
|
||||
if self.is_done or params['offset'] != len(self.identify_data):
|
||||
return
|
||||
msgdata = params['data']
|
||||
if not msgdata:
|
||||
self.is_done = True
|
||||
return
|
||||
self.identify_data += msgdata
|
||||
imsg = self.identify_cmd.encode(len(self.identify_data), 40)
|
||||
self.serial.send(imsg)
|
||||
def send_event(self, eventtime):
|
||||
if self.is_done:
|
||||
return self.serial.reactor.NEVER
|
||||
imsg = self.identify_cmd.encode(len(self.identify_data), 40)
|
||||
self.serial.send(imsg)
|
||||
return eventtime + self.RETRY_TIME
|
||||
def handle_unknown(self, params):
|
||||
logging.debug("Unknown message %d (len %d) while identifying",
|
||||
params['#msgid'], len(params['#msg']))
|
||||
|
||||
# Attempt to place an AVR stk500v2 style programmer into normal mode
|
||||
def stk500v2_leave(ser, reactor):
|
||||
logging.debug("Starting stk500v2 leave programmer sequence")
|
||||
util.clear_hupcl(ser.fileno())
|
||||
origbaud = ser.baudrate
|
||||
# Request a dummy speed first as this seems to help reset the port
|
||||
ser.baudrate = 2400
|
||||
ser.read(1)
|
||||
# Send stk500v2 leave programmer sequence
|
||||
ser.baudrate = 115200
|
||||
reactor.pause(reactor.monotonic() + 0.100)
|
||||
ser.read(4096)
|
||||
ser.write('\x1b\x01\x00\x01\x0e\x11\x04')
|
||||
reactor.pause(reactor.monotonic() + 0.050)
|
||||
res = ser.read(4096)
|
||||
logging.debug("Got %s from stk500v2", repr(res))
|
||||
ser.baudrate = origbaud
|
||||
|
||||
# Attempt an arduino style reset on a serial port
|
||||
def arduino_reset(serialport, reactor):
|
||||
# First try opening the port at a different baud
|
||||
ser = serial.Serial(serialport, 2400, timeout=0)
|
||||
ser.read(1)
|
||||
reactor.pause(reactor.monotonic() + 0.100)
|
||||
# Then toggle DTR
|
||||
ser.dtr = True
|
||||
reactor.pause(reactor.monotonic() + 0.100)
|
||||
ser.dtr = False
|
||||
reactor.pause(reactor.monotonic() + 0.100)
|
||||
ser.close()
|
||||
1084
klippy/serialqueue.c
Normal file
68
klippy/serialqueue.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#ifndef SERIALQUEUE_H
|
||||
#define SERIALQUEUE_H
|
||||
|
||||
#include "list.h" // struct list_head
|
||||
|
||||
#define MAX_CLOCK 0x7fffffffffffffff
|
||||
|
||||
#define MESSAGE_MIN 5
|
||||
#define MESSAGE_MAX 64
|
||||
#define MESSAGE_HEADER_SIZE 2
|
||||
#define MESSAGE_TRAILER_SIZE 3
|
||||
#define MESSAGE_POS_LEN 0
|
||||
#define MESSAGE_POS_SEQ 1
|
||||
#define MESSAGE_TRAILER_CRC 3
|
||||
#define MESSAGE_TRAILER_SYNC 1
|
||||
#define MESSAGE_PAYLOAD_MAX (MESSAGE_MAX - MESSAGE_MIN)
|
||||
#define MESSAGE_SEQ_MASK 0x0f
|
||||
#define MESSAGE_DEST 0x10
|
||||
#define MESSAGE_SYNC 0x7E
|
||||
|
||||
struct queue_message {
|
||||
int len;
|
||||
uint8_t msg[MESSAGE_MAX];
|
||||
union {
|
||||
// Filled when on a command queue
|
||||
struct {
|
||||
uint64_t min_clock, req_clock;
|
||||
};
|
||||
// Filled when in sent/receive queues
|
||||
struct {
|
||||
double sent_time, receive_time;
|
||||
};
|
||||
};
|
||||
struct list_node node;
|
||||
};
|
||||
|
||||
struct queue_message *message_alloc_and_encode(uint32_t *data, int len);
|
||||
void message_queue_free(struct list_head *root);
|
||||
|
||||
struct pull_queue_message {
|
||||
uint8_t msg[MESSAGE_MAX];
|
||||
int len;
|
||||
double sent_time, receive_time;
|
||||
};
|
||||
|
||||
struct serialqueue;
|
||||
struct serialqueue *serialqueue_alloc(int serial_fd, int write_only);
|
||||
void serialqueue_exit(struct serialqueue *sq);
|
||||
void serialqueue_free(struct serialqueue *sq);
|
||||
struct command_queue *serialqueue_alloc_commandqueue(void);
|
||||
void serialqueue_free_commandqueue(struct command_queue *cq);
|
||||
void serialqueue_send_batch(struct serialqueue *sq, struct command_queue *cq
|
||||
, struct list_head *msgs);
|
||||
void serialqueue_send(struct serialqueue *sq, struct command_queue *cq
|
||||
, uint8_t *msg, int len
|
||||
, uint64_t min_clock, uint64_t req_clock);
|
||||
void serialqueue_encode_and_send(struct serialqueue *sq, struct command_queue *cq
|
||||
, uint32_t *data, int len
|
||||
, uint64_t min_clock, uint64_t req_clock);
|
||||
void serialqueue_pull(struct serialqueue *sq, struct pull_queue_message *pqm);
|
||||
void serialqueue_set_baud_adjust(struct serialqueue *sq, double baud_adjust);
|
||||
void serialqueue_set_clock_est(struct serialqueue *sq, double est_freq
|
||||
, double last_clock_time, uint64_t last_clock);
|
||||
void serialqueue_get_stats(struct serialqueue *sq, char *buf, int len);
|
||||
int serialqueue_extract_old(struct serialqueue *sq, int sentq
|
||||
, struct pull_queue_message *q, int max);
|
||||
|
||||
#endif // serialqueue.h
|
||||
847
klippy/stepcompress.c
Normal file
@@ -0,0 +1,847 @@
|
||||
// Stepper pulse schedule compression
|
||||
//
|
||||
// Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
//
|
||||
// The goal of this code is to take a series of scheduled stepper
|
||||
// pulse times and compress them into a handful of commands that can
|
||||
// be efficiently transmitted and executed on a microcontroller (mcu).
|
||||
// The mcu accepts step pulse commands that take interval, count, and
|
||||
// add parameters such that 'count' pulses occur, with each step event
|
||||
// calculating the next step event time using:
|
||||
// next_wake_time = last_wake_time + interval; interval += add
|
||||
// This code is writtin in C (instead of python) for processing
|
||||
// efficiency - the repetitive integer math is vastly faster in C.
|
||||
|
||||
#include <math.h> // sqrt
|
||||
#include <stddef.h> // offsetof
|
||||
#include <stdint.h> // uint32_t
|
||||
#include <stdio.h> // fprintf
|
||||
#include <stdlib.h> // malloc
|
||||
#include <string.h> // memset
|
||||
#include "pyhelper.h" // errorf
|
||||
#include "serialqueue.h" // struct queue_message
|
||||
|
||||
#define CHECK_LINES 1
|
||||
#define QUEUE_START_SIZE 1024
|
||||
|
||||
struct stepcompress {
|
||||
// Buffer management
|
||||
uint32_t *queue, *queue_end, *queue_pos, *queue_next;
|
||||
// Internal tracking
|
||||
uint32_t max_error;
|
||||
double mcu_time_offset, mcu_freq;
|
||||
// Message generation
|
||||
uint64_t last_step_clock, homing_clock;
|
||||
struct list_head msg_queue;
|
||||
uint32_t queue_step_msgid, set_next_step_dir_msgid, oid;
|
||||
int sdir, invert_sdir;
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Step compression
|
||||
****************************************************************/
|
||||
|
||||
#define DIV_UP(n,d) (((n) + (d) - 1) / (d))
|
||||
|
||||
static inline int32_t
|
||||
idiv_up(int32_t n, int32_t d)
|
||||
{
|
||||
return (n>=0) ? DIV_UP(n,d) : (n/d);
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
idiv_down(int32_t n, int32_t d)
|
||||
{
|
||||
return (n>=0) ? (n/d) : (n - d + 1) / d;
|
||||
}
|
||||
|
||||
struct points {
|
||||
int32_t minp, maxp;
|
||||
};
|
||||
|
||||
// Given a requested step time, return the minimum and maximum
|
||||
// acceptable times
|
||||
static inline struct points
|
||||
minmax_point(struct stepcompress *sc, uint32_t *pos)
|
||||
{
|
||||
uint32_t lsc = sc->last_step_clock, point = *pos - lsc;
|
||||
uint32_t prevpoint = pos > sc->queue_pos ? *(pos-1) - lsc : 0;
|
||||
uint32_t max_error = (point - prevpoint) / 2;
|
||||
if (max_error > sc->max_error)
|
||||
max_error = sc->max_error;
|
||||
return (struct points){ point - max_error, point };
|
||||
}
|
||||
|
||||
// The maximum add delta between two valid quadratic sequences of the
|
||||
// form "add*count*(count-1)/2 + interval*count" is "(6 + 4*sqrt(2)) *
|
||||
// maxerror / (count*count)". The "6 + 4*sqrt(2)" is 11.65685, but
|
||||
// using 11 works well in practice.
|
||||
#define QUADRATIC_DEV 11
|
||||
|
||||
struct step_move {
|
||||
uint32_t interval;
|
||||
uint16_t count;
|
||||
int16_t add;
|
||||
};
|
||||
|
||||
// Find a 'step_move' that covers a series of step times
|
||||
static struct step_move
|
||||
compress_bisect_add(struct stepcompress *sc)
|
||||
{
|
||||
uint32_t *qlast = sc->queue_next;
|
||||
if (qlast > sc->queue_pos + 65535)
|
||||
qlast = sc->queue_pos + 65535;
|
||||
struct points point = minmax_point(sc, sc->queue_pos);
|
||||
int32_t outer_mininterval = point.minp, outer_maxinterval = point.maxp;
|
||||
int32_t add = 0, minadd = -0x8000, maxadd = 0x7fff;
|
||||
int32_t bestinterval = 0, bestcount = 1, bestadd = 1, bestreach = INT32_MIN;
|
||||
int32_t zerointerval = 0, zerocount = 0;
|
||||
|
||||
for (;;) {
|
||||
// Find longest valid sequence with the given 'add'
|
||||
struct points nextpoint;
|
||||
int32_t nextmininterval = outer_mininterval;
|
||||
int32_t nextmaxinterval = outer_maxinterval, interval = nextmaxinterval;
|
||||
int32_t nextcount = 1;
|
||||
for (;;) {
|
||||
nextcount++;
|
||||
if (&sc->queue_pos[nextcount-1] >= qlast) {
|
||||
int32_t count = nextcount - 1;
|
||||
return (struct step_move){ interval, count, add };
|
||||
}
|
||||
nextpoint = minmax_point(sc, sc->queue_pos + nextcount - 1);
|
||||
int32_t nextaddfactor = nextcount*(nextcount-1)/2;
|
||||
int32_t c = add*nextaddfactor;
|
||||
if (nextmininterval*nextcount < nextpoint.minp - c)
|
||||
nextmininterval = DIV_UP(nextpoint.minp - c, nextcount);
|
||||
if (nextmaxinterval*nextcount > nextpoint.maxp - c)
|
||||
nextmaxinterval = (nextpoint.maxp - c) / nextcount;
|
||||
if (nextmininterval > nextmaxinterval)
|
||||
break;
|
||||
interval = nextmaxinterval;
|
||||
}
|
||||
|
||||
// Check if this is the best sequence found so far
|
||||
int32_t count = nextcount - 1, addfactor = count*(count-1)/2;
|
||||
int32_t reach = add*addfactor + interval*count;
|
||||
if (reach > bestreach
|
||||
|| (reach == bestreach && interval > bestinterval)) {
|
||||
bestinterval = interval;
|
||||
bestcount = count;
|
||||
bestadd = add;
|
||||
bestreach = reach;
|
||||
if (!add) {
|
||||
zerointerval = interval;
|
||||
zerocount = count;
|
||||
}
|
||||
if (count > 0x200)
|
||||
// No 'add' will improve sequence; avoid integer overflow
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if a greater or lesser add could extend the sequence
|
||||
int32_t nextaddfactor = nextcount*(nextcount-1)/2;
|
||||
int32_t nextreach = add*nextaddfactor + interval*nextcount;
|
||||
if (nextreach < nextpoint.minp) {
|
||||
minadd = add + 1;
|
||||
outer_maxinterval = nextmaxinterval;
|
||||
} else {
|
||||
maxadd = add - 1;
|
||||
outer_mininterval = nextmininterval;
|
||||
}
|
||||
|
||||
// The maximum valid deviation between two quadratic sequences
|
||||
// can be calculated and used to further limit the add range.
|
||||
if (count > 1) {
|
||||
int32_t errdelta = sc->max_error*QUADRATIC_DEV / (count*count);
|
||||
if (minadd < add - errdelta)
|
||||
minadd = add - errdelta;
|
||||
if (maxadd > add + errdelta)
|
||||
maxadd = add + errdelta;
|
||||
}
|
||||
|
||||
// See if next point would further limit the add range
|
||||
int32_t c = outer_maxinterval * nextcount;
|
||||
if (minadd*nextaddfactor < nextpoint.minp - c)
|
||||
minadd = idiv_up(nextpoint.minp - c, nextaddfactor);
|
||||
c = outer_mininterval * nextcount;
|
||||
if (maxadd*nextaddfactor > nextpoint.maxp - c)
|
||||
maxadd = idiv_down(nextpoint.maxp - c, nextaddfactor);
|
||||
|
||||
// Bisect valid add range and try again with new 'add'
|
||||
if (minadd > maxadd)
|
||||
break;
|
||||
add = maxadd - (maxadd - minadd) / 4;
|
||||
}
|
||||
if (zerocount + zerocount/16 >= bestcount)
|
||||
// Prefer add=0 if it's similar to the best found sequence
|
||||
return (struct step_move){ zerointerval, zerocount, 0 };
|
||||
return (struct step_move){ bestinterval, bestcount, bestadd };
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Step compress checking
|
||||
****************************************************************/
|
||||
|
||||
#define ERROR_RET -989898989
|
||||
|
||||
// Verify that a given 'step_move' matches the actual step times
|
||||
static int
|
||||
check_line(struct stepcompress *sc, struct step_move move)
|
||||
{
|
||||
if (!CHECK_LINES)
|
||||
return 0;
|
||||
if (!move.count || (!move.interval && !move.add && move.count > 1)
|
||||
|| move.interval >= 0x80000000) {
|
||||
errorf("stepcompress o=%d i=%d c=%d a=%d: Invalid sequence"
|
||||
, sc->oid, move.interval, move.count, move.add);
|
||||
return ERROR_RET;
|
||||
}
|
||||
uint32_t interval = move.interval, p = 0;
|
||||
uint16_t i;
|
||||
for (i=0; i<move.count; i++) {
|
||||
struct points point = minmax_point(sc, sc->queue_pos + i);
|
||||
p += interval;
|
||||
if (p < point.minp || p > point.maxp) {
|
||||
errorf("stepcompress o=%d i=%d c=%d a=%d: Point %d: %d not in %d:%d"
|
||||
, sc->oid, move.interval, move.count, move.add
|
||||
, i+1, p, point.minp, point.maxp);
|
||||
return ERROR_RET;
|
||||
}
|
||||
if (interval >= 0x80000000) {
|
||||
errorf("stepcompress o=%d i=%d c=%d a=%d:"
|
||||
" Point %d: interval overflow %d"
|
||||
, sc->oid, move.interval, move.count, move.add
|
||||
, i+1, interval);
|
||||
return ERROR_RET;
|
||||
}
|
||||
interval += move.add;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Step compress interface
|
||||
****************************************************************/
|
||||
|
||||
// Allocate a new 'stepcompress' object
|
||||
struct stepcompress *
|
||||
stepcompress_alloc(uint32_t max_error, uint32_t queue_step_msgid
|
||||
, uint32_t set_next_step_dir_msgid, uint32_t invert_sdir
|
||||
, uint32_t oid)
|
||||
{
|
||||
struct stepcompress *sc = malloc(sizeof(*sc));
|
||||
memset(sc, 0, sizeof(*sc));
|
||||
sc->max_error = max_error;
|
||||
list_init(&sc->msg_queue);
|
||||
sc->queue_step_msgid = queue_step_msgid;
|
||||
sc->set_next_step_dir_msgid = set_next_step_dir_msgid;
|
||||
sc->oid = oid;
|
||||
sc->sdir = -1;
|
||||
sc->invert_sdir = !!invert_sdir;
|
||||
return sc;
|
||||
}
|
||||
|
||||
// Free memory associated with a 'stepcompress' object
|
||||
void
|
||||
stepcompress_free(struct stepcompress *sc)
|
||||
{
|
||||
if (!sc)
|
||||
return;
|
||||
free(sc->queue);
|
||||
message_queue_free(&sc->msg_queue);
|
||||
free(sc);
|
||||
}
|
||||
|
||||
// Convert previously scheduled steps into commands for the mcu
|
||||
static int
|
||||
stepcompress_flush(struct stepcompress *sc, uint64_t move_clock)
|
||||
{
|
||||
if (sc->queue_pos >= sc->queue_next)
|
||||
return 0;
|
||||
while (sc->last_step_clock < move_clock) {
|
||||
struct step_move move = compress_bisect_add(sc);
|
||||
int ret = check_line(sc, move);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
uint32_t msg[5] = {
|
||||
sc->queue_step_msgid, sc->oid, move.interval, move.count, move.add
|
||||
};
|
||||
struct queue_message *qm = message_alloc_and_encode(msg, 5);
|
||||
qm->min_clock = qm->req_clock = sc->last_step_clock;
|
||||
int32_t addfactor = move.count*(move.count-1)/2;
|
||||
uint32_t ticks = move.add*addfactor + move.interval*move.count;
|
||||
sc->last_step_clock += ticks;
|
||||
if (sc->homing_clock)
|
||||
// When homing, all steps should be sent prior to homing_clock
|
||||
qm->min_clock = qm->req_clock = sc->homing_clock;
|
||||
list_add_tail(&qm->node, &sc->msg_queue);
|
||||
|
||||
if (sc->queue_pos + move.count >= sc->queue_next) {
|
||||
sc->queue_pos = sc->queue_next = sc->queue;
|
||||
break;
|
||||
}
|
||||
sc->queue_pos += move.count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Generate a queue_step for a step far in the future from the last step
|
||||
static int
|
||||
stepcompress_flush_far(struct stepcompress *sc, uint64_t abs_step_clock)
|
||||
{
|
||||
uint32_t msg[5] = {
|
||||
sc->queue_step_msgid, sc->oid, abs_step_clock - sc->last_step_clock, 1, 0
|
||||
};
|
||||
struct queue_message *qm = message_alloc_and_encode(msg, 5);
|
||||
qm->min_clock = sc->last_step_clock;
|
||||
sc->last_step_clock = qm->req_clock = abs_step_clock;
|
||||
if (sc->homing_clock)
|
||||
// When homing, all steps should be sent prior to homing_clock
|
||||
qm->min_clock = qm->req_clock = sc->homing_clock;
|
||||
list_add_tail(&qm->node, &sc->msg_queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Send the set_next_step_dir command
|
||||
static int
|
||||
set_next_step_dir(struct stepcompress *sc, int sdir)
|
||||
{
|
||||
if (sc->sdir == sdir)
|
||||
return 0;
|
||||
sc->sdir = sdir;
|
||||
int ret = stepcompress_flush(sc, UINT64_MAX);
|
||||
if (ret)
|
||||
return ret;
|
||||
uint32_t msg[3] = {
|
||||
sc->set_next_step_dir_msgid, sc->oid, sdir ^ sc->invert_sdir
|
||||
};
|
||||
struct queue_message *qm = message_alloc_and_encode(msg, 3);
|
||||
qm->req_clock = sc->homing_clock ?: sc->last_step_clock;
|
||||
list_add_tail(&qm->node, &sc->msg_queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reset the internal state of the stepcompress object
|
||||
int
|
||||
stepcompress_reset(struct stepcompress *sc, uint64_t last_step_clock)
|
||||
{
|
||||
int ret = stepcompress_flush(sc, UINT64_MAX);
|
||||
if (ret)
|
||||
return ret;
|
||||
sc->last_step_clock = last_step_clock;
|
||||
sc->sdir = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Indicate the stepper is in homing mode (or done homing if zero)
|
||||
int
|
||||
stepcompress_set_homing(struct stepcompress *sc, uint64_t homing_clock)
|
||||
{
|
||||
int ret = stepcompress_flush(sc, UINT64_MAX);
|
||||
if (ret)
|
||||
return ret;
|
||||
sc->homing_clock = homing_clock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Queue an mcu command to go out in order with stepper commands
|
||||
int
|
||||
stepcompress_queue_msg(struct stepcompress *sc, uint32_t *data, int len)
|
||||
{
|
||||
int ret = stepcompress_flush(sc, UINT64_MAX);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
struct queue_message *qm = message_alloc_and_encode(data, len);
|
||||
qm->req_clock = sc->homing_clock ?: sc->last_step_clock;
|
||||
list_add_tail(&qm->node, &sc->msg_queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set the conversion rate of 'print_time' to mcu clock
|
||||
static void
|
||||
stepcompress_set_time(struct stepcompress *sc
|
||||
, double time_offset, double mcu_freq)
|
||||
{
|
||||
sc->mcu_time_offset = time_offset;
|
||||
sc->mcu_freq = mcu_freq;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Queue management
|
||||
****************************************************************/
|
||||
|
||||
struct queue_append {
|
||||
struct stepcompress *sc;
|
||||
uint32_t *qnext, *qend, last_step_clock_32;
|
||||
double clock_offset;
|
||||
};
|
||||
|
||||
// Maximium clock delta between messages in the queue
|
||||
#define CLOCK_DIFF_MAX (3<<28)
|
||||
|
||||
// Create a cursor for inserting clock times into the queue
|
||||
static inline struct queue_append
|
||||
queue_append_start(struct stepcompress *sc, double print_time, double adjust)
|
||||
{
|
||||
double print_clock = (print_time - sc->mcu_time_offset) * sc->mcu_freq;
|
||||
return (struct queue_append) {
|
||||
.sc = sc, .qnext = sc->queue_next, .qend = sc->queue_end,
|
||||
.last_step_clock_32 = sc->last_step_clock,
|
||||
.clock_offset = (print_clock - (double)sc->last_step_clock) + adjust };
|
||||
}
|
||||
|
||||
// Finalize a cursor created with queue_append_start()
|
||||
static inline void
|
||||
queue_append_finish(struct queue_append qa)
|
||||
{
|
||||
qa.sc->queue_next = qa.qnext;
|
||||
}
|
||||
|
||||
// Slow path for queue_append()
|
||||
static int
|
||||
queue_append_slow(struct stepcompress *sc, double rel_sc)
|
||||
{
|
||||
uint64_t abs_step_clock = (uint64_t)rel_sc + sc->last_step_clock;
|
||||
if (abs_step_clock >= sc->last_step_clock + CLOCK_DIFF_MAX) {
|
||||
// Avoid integer overflow on steps far in the future
|
||||
int ret = stepcompress_flush(sc, abs_step_clock - CLOCK_DIFF_MAX + 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (abs_step_clock >= sc->last_step_clock + CLOCK_DIFF_MAX)
|
||||
return stepcompress_flush_far(sc, abs_step_clock);
|
||||
}
|
||||
|
||||
if (sc->queue_next - sc->queue_pos > 65535 + 2000) {
|
||||
// No point in keeping more than 64K steps in memory
|
||||
int ret = stepcompress_flush(sc, *(sc->queue_next - 65535));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int in_use = sc->queue_next - sc->queue_pos;
|
||||
if (sc->queue_pos > sc->queue) {
|
||||
// Shuffle the internal queue to avoid having to allocate more ram
|
||||
memmove(sc->queue, sc->queue_pos, in_use * sizeof(*sc->queue));
|
||||
} else {
|
||||
// Expand the internal queue of step times
|
||||
int alloc = sc->queue_end - sc->queue;
|
||||
if (!alloc)
|
||||
alloc = QUEUE_START_SIZE;
|
||||
while (in_use >= alloc)
|
||||
alloc *= 2;
|
||||
sc->queue = realloc(sc->queue, alloc * sizeof(*sc->queue));
|
||||
sc->queue_end = sc->queue + alloc;
|
||||
}
|
||||
sc->queue_pos = sc->queue;
|
||||
sc->queue_next = sc->queue + in_use;
|
||||
*sc->queue_next++ = abs_step_clock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add a clock time to the queue (flushing the queue if needed)
|
||||
static inline int
|
||||
queue_append(struct queue_append *qa, double step_clock)
|
||||
{
|
||||
double rel_sc = step_clock + qa->clock_offset;
|
||||
if (likely(!(qa->qnext >= qa->qend || rel_sc >= (double)CLOCK_DIFF_MAX))) {
|
||||
*qa->qnext++ = qa->last_step_clock_32 + (uint32_t)rel_sc;
|
||||
return 0;
|
||||
}
|
||||
// Call queue_append_slow() to handle queue expansion and integer overflow
|
||||
struct stepcompress *sc = qa->sc;
|
||||
uint64_t old_last_step_clock = sc->last_step_clock;
|
||||
sc->queue_next = qa->qnext;
|
||||
int ret = queue_append_slow(sc, rel_sc);
|
||||
if (ret)
|
||||
return ret;
|
||||
qa->qnext = sc->queue_next;
|
||||
qa->qend = sc->queue_end;
|
||||
qa->last_step_clock_32 = sc->last_step_clock;
|
||||
qa->clock_offset -= sc->last_step_clock - old_last_step_clock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Motion to step conversions
|
||||
****************************************************************/
|
||||
|
||||
// Common suffixes: _sd is step distance (a unit length the same
|
||||
// distance the stepper moves on each step), _sv is step velocity (in
|
||||
// units of step distance per time), _sd2 is step distance squared, _r
|
||||
// is ratio (scalar usually between 0.0 and 1.0). Times are in
|
||||
// seconds and acceleration is in units of step distance per second
|
||||
// squared.
|
||||
|
||||
// Wrapper around sqrt() to handle small negative numbers
|
||||
static double
|
||||
_safe_sqrt(double v)
|
||||
{
|
||||
// Due to floating point truncation, it's possible to get a small
|
||||
// negative number - treat it as zero.
|
||||
if (v < -0.001)
|
||||
errorf("safe_sqrt of %.9f", v);
|
||||
return 0.;
|
||||
}
|
||||
static inline double safe_sqrt(double v) {
|
||||
return likely(v >= 0.) ? sqrt(v) : _safe_sqrt(v);
|
||||
}
|
||||
|
||||
// Schedule a step event at the specified step_clock time
|
||||
int32_t
|
||||
stepcompress_push(struct stepcompress *sc, double print_time, int32_t sdir)
|
||||
{
|
||||
int ret = set_next_step_dir(sc, !!sdir);
|
||||
if (ret)
|
||||
return ret;
|
||||
struct queue_append qa = queue_append_start(sc, print_time, 0.5);
|
||||
ret = queue_append(&qa, 0.);
|
||||
if (ret)
|
||||
return ret;
|
||||
queue_append_finish(qa);
|
||||
return sdir ? 1 : -1;
|
||||
}
|
||||
|
||||
// Schedule 'steps' number of steps at constant acceleration. If
|
||||
// acceleration is zero (ie, constant velocity) it uses the formula:
|
||||
// step_time = print_time + step_num/start_sv
|
||||
// Otherwise it uses the formula:
|
||||
// step_time = (print_time + sqrt(2*step_num/accel + (start_sv/accel)**2)
|
||||
// - start_sv/accel)
|
||||
int32_t
|
||||
stepcompress_push_const(
|
||||
struct stepcompress *sc, double print_time
|
||||
, double step_offset, double steps, double start_sv, double accel)
|
||||
{
|
||||
// Calculate number of steps to take
|
||||
int sdir = 1;
|
||||
if (steps < 0) {
|
||||
sdir = 0;
|
||||
steps = -steps;
|
||||
step_offset = -step_offset;
|
||||
}
|
||||
int count = steps + .5 - step_offset;
|
||||
if (count <= 0 || count > 10000000) {
|
||||
if (count && steps) {
|
||||
errorf("push_const invalid count %d %f %f %f %f %f"
|
||||
, sc->oid, print_time, step_offset, steps
|
||||
, start_sv, accel);
|
||||
return ERROR_RET;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int ret = set_next_step_dir(sc, sdir);
|
||||
if (ret)
|
||||
return ret;
|
||||
int res = sdir ? count : -count;
|
||||
|
||||
// Calculate each step time
|
||||
if (!accel) {
|
||||
// Move at constant velocity (zero acceleration)
|
||||
struct queue_append qa = queue_append_start(sc, print_time, .5);
|
||||
double inv_cruise_sv = sc->mcu_freq / start_sv;
|
||||
double pos = (step_offset + .5) * inv_cruise_sv;
|
||||
while (count--) {
|
||||
ret = queue_append(&qa, pos);
|
||||
if (ret)
|
||||
return ret;
|
||||
pos += inv_cruise_sv;
|
||||
}
|
||||
queue_append_finish(qa);
|
||||
} else {
|
||||
// Move with constant acceleration
|
||||
double inv_accel = 1. / accel;
|
||||
double accel_time = start_sv * inv_accel * sc->mcu_freq;
|
||||
struct queue_append qa = queue_append_start(
|
||||
sc, print_time, 0.5 - accel_time);
|
||||
double accel_multiplier = 2. * inv_accel * sc->mcu_freq * sc->mcu_freq;
|
||||
double pos = (step_offset + .5)*accel_multiplier + accel_time*accel_time;
|
||||
while (count--) {
|
||||
double v = safe_sqrt(pos);
|
||||
int ret = queue_append(&qa, accel_multiplier >= 0. ? v : -v);
|
||||
if (ret)
|
||||
return ret;
|
||||
pos += accel_multiplier;
|
||||
}
|
||||
queue_append_finish(qa);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Schedule steps using delta kinematics
|
||||
static int32_t
|
||||
_stepcompress_push_delta(
|
||||
struct stepcompress *sc, int sdir
|
||||
, double print_time, double move_sd, double start_sv, double accel
|
||||
, double height, double startxy_sd, double arm_sd, double movez_r)
|
||||
{
|
||||
// Calculate number of steps to take
|
||||
double movexy_r = movez_r ? sqrt(1. - movez_r*movez_r) : 1.;
|
||||
double arm_sd2 = arm_sd * arm_sd;
|
||||
double endxy_sd = startxy_sd - movexy_r*move_sd;
|
||||
double end_height = safe_sqrt(arm_sd2 - endxy_sd*endxy_sd);
|
||||
int count = (end_height + movez_r*move_sd - height) * (sdir ? 1. : -1.) + .5;
|
||||
if (count <= 0 || count > 10000000) {
|
||||
if (count) {
|
||||
errorf("push_delta invalid count %d %d %f %f %f %f %f %f %f %f"
|
||||
, sc->oid, count, print_time, move_sd, start_sv, accel
|
||||
, height, startxy_sd, arm_sd, movez_r);
|
||||
return ERROR_RET;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int ret = set_next_step_dir(sc, sdir);
|
||||
if (ret)
|
||||
return ret;
|
||||
int res = sdir ? count : -count;
|
||||
|
||||
// Calculate each step time
|
||||
height += (sdir ? .5 : -.5);
|
||||
if (!accel) {
|
||||
// Move at constant velocity (zero acceleration)
|
||||
struct queue_append qa = queue_append_start(sc, print_time, .5);
|
||||
double inv_cruise_sv = sc->mcu_freq / start_sv;
|
||||
if (!movez_r) {
|
||||
// Optimized case for common XY only moves (no Z movement)
|
||||
while (count--) {
|
||||
double v = safe_sqrt(arm_sd2 - height*height);
|
||||
double pos = startxy_sd + (sdir ? -v : v);
|
||||
int ret = queue_append(&qa, pos * inv_cruise_sv);
|
||||
if (ret)
|
||||
return ret;
|
||||
height += (sdir ? 1. : -1.);
|
||||
}
|
||||
} else if (!movexy_r) {
|
||||
// Optimized case for Z only moves
|
||||
double pos = ((sdir ? height-end_height : end_height-height)
|
||||
* inv_cruise_sv);
|
||||
while (count--) {
|
||||
int ret = queue_append(&qa, pos);
|
||||
if (ret)
|
||||
return ret;
|
||||
pos += inv_cruise_sv;
|
||||
}
|
||||
} else {
|
||||
// General case (handles XY+Z moves)
|
||||
double start_pos = movexy_r*startxy_sd, zoffset = movez_r*startxy_sd;
|
||||
while (count--) {
|
||||
double relheight = movexy_r*height - zoffset;
|
||||
double v = safe_sqrt(arm_sd2 - relheight*relheight);
|
||||
double pos = start_pos + movez_r*height + (sdir ? -v : v);
|
||||
int ret = queue_append(&qa, pos * inv_cruise_sv);
|
||||
if (ret)
|
||||
return ret;
|
||||
height += (sdir ? 1. : -1.);
|
||||
}
|
||||
}
|
||||
queue_append_finish(qa);
|
||||
} else {
|
||||
// Move with constant acceleration
|
||||
double start_pos = movexy_r*startxy_sd, zoffset = movez_r*startxy_sd;
|
||||
double inv_accel = 1. / accel;
|
||||
start_pos += 0.5 * start_sv*start_sv * inv_accel;
|
||||
struct queue_append qa = queue_append_start(
|
||||
sc, print_time, 0.5 - start_sv * inv_accel * sc->mcu_freq);
|
||||
double accel_multiplier = 2. * inv_accel * sc->mcu_freq * sc->mcu_freq;
|
||||
while (count--) {
|
||||
double relheight = movexy_r*height - zoffset;
|
||||
double v = safe_sqrt(arm_sd2 - relheight*relheight);
|
||||
double pos = start_pos + movez_r*height + (sdir ? -v : v);
|
||||
v = safe_sqrt(pos * accel_multiplier);
|
||||
int ret = queue_append(&qa, accel_multiplier >= 0. ? v : -v);
|
||||
if (ret)
|
||||
return ret;
|
||||
height += (sdir ? 1. : -1.);
|
||||
}
|
||||
queue_append_finish(qa);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t
|
||||
stepcompress_push_delta(
|
||||
struct stepcompress *sc, double print_time, double move_sd
|
||||
, double start_sv, double accel
|
||||
, double height, double startxy_sd, double arm_sd, double movez_r)
|
||||
{
|
||||
double reversexy_sd = startxy_sd + arm_sd*movez_r;
|
||||
if (reversexy_sd <= 0.)
|
||||
// All steps are in down direction
|
||||
return _stepcompress_push_delta(
|
||||
sc, 0, print_time, move_sd, start_sv, accel
|
||||
, height, startxy_sd, arm_sd, movez_r);
|
||||
double movexy_r = movez_r ? sqrt(1. - movez_r*movez_r) : 1.;
|
||||
if (reversexy_sd >= move_sd * movexy_r)
|
||||
// All steps are in up direction
|
||||
return _stepcompress_push_delta(
|
||||
sc, 1, print_time, move_sd, start_sv, accel
|
||||
, height, startxy_sd, arm_sd, movez_r);
|
||||
// Steps in both up and down direction
|
||||
int res1 = _stepcompress_push_delta(
|
||||
sc, 1, print_time, reversexy_sd / movexy_r, start_sv, accel
|
||||
, height, startxy_sd, arm_sd, movez_r);
|
||||
if (res1 == ERROR_RET)
|
||||
return res1;
|
||||
int res2 = _stepcompress_push_delta(
|
||||
sc, 0, print_time, move_sd, start_sv, accel
|
||||
, height + res1, startxy_sd, arm_sd, movez_r);
|
||||
if (res2 == ERROR_RET)
|
||||
return res2;
|
||||
return res1 + res2;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Step compress synchronization
|
||||
****************************************************************/
|
||||
|
||||
// The steppersync object is used to synchronize the output of mcu
|
||||
// step commands. The mcu can only queue a limited number of step
|
||||
// commands - this code tracks when items on the mcu step queue become
|
||||
// free so that new commands can be transmitted. It also ensures the
|
||||
// mcu step queue is ordered between steppers so that no stepper
|
||||
// starves the other steppers of space in the mcu step queue.
|
||||
|
||||
struct steppersync {
|
||||
// Serial port
|
||||
struct serialqueue *sq;
|
||||
struct command_queue *cq;
|
||||
// Storage for associated stepcompress objects
|
||||
struct stepcompress **sc_list;
|
||||
int sc_num;
|
||||
// Storage for list of pending move clocks
|
||||
uint64_t *move_clocks;
|
||||
int num_move_clocks;
|
||||
};
|
||||
|
||||
// Allocate a new 'steppersync' object
|
||||
struct steppersync *
|
||||
steppersync_alloc(struct serialqueue *sq, struct stepcompress **sc_list
|
||||
, int sc_num, int move_num)
|
||||
{
|
||||
struct steppersync *ss = malloc(sizeof(*ss));
|
||||
memset(ss, 0, sizeof(*ss));
|
||||
ss->sq = sq;
|
||||
ss->cq = serialqueue_alloc_commandqueue();
|
||||
|
||||
ss->sc_list = malloc(sizeof(*sc_list)*sc_num);
|
||||
memcpy(ss->sc_list, sc_list, sizeof(*sc_list)*sc_num);
|
||||
ss->sc_num = sc_num;
|
||||
|
||||
ss->move_clocks = malloc(sizeof(*ss->move_clocks)*move_num);
|
||||
memset(ss->move_clocks, 0, sizeof(*ss->move_clocks)*move_num);
|
||||
ss->num_move_clocks = move_num;
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
// Free memory associated with a 'steppersync' object
|
||||
void
|
||||
steppersync_free(struct steppersync *ss)
|
||||
{
|
||||
if (!ss)
|
||||
return;
|
||||
free(ss->sc_list);
|
||||
free(ss->move_clocks);
|
||||
serialqueue_free_commandqueue(ss->cq);
|
||||
free(ss);
|
||||
}
|
||||
|
||||
// Set the conversion rate of 'print_time' to mcu clock
|
||||
void
|
||||
steppersync_set_time(struct steppersync *ss, double time_offset, double mcu_freq)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<ss->sc_num; i++) {
|
||||
struct stepcompress *sc = ss->sc_list[i];
|
||||
stepcompress_set_time(sc, time_offset, mcu_freq);
|
||||
}
|
||||
}
|
||||
|
||||
// Implement a binary heap algorithm to track when the next available
|
||||
// 'struct move' in the mcu will be available
|
||||
static void
|
||||
heap_replace(struct steppersync *ss, uint64_t req_clock)
|
||||
{
|
||||
uint64_t *mc = ss->move_clocks;
|
||||
int nmc = ss->num_move_clocks, pos = 0;
|
||||
for (;;) {
|
||||
int child1_pos = 2*pos+1, child2_pos = 2*pos+2;
|
||||
uint64_t child2_clock = child2_pos < nmc ? mc[child2_pos] : UINT64_MAX;
|
||||
uint64_t child1_clock = child1_pos < nmc ? mc[child1_pos] : UINT64_MAX;
|
||||
if (req_clock <= child1_clock && req_clock <= child2_clock) {
|
||||
mc[pos] = req_clock;
|
||||
break;
|
||||
}
|
||||
if (child1_clock < child2_clock) {
|
||||
mc[pos] = child1_clock;
|
||||
pos = child1_pos;
|
||||
} else {
|
||||
mc[pos] = child2_clock;
|
||||
pos = child2_pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find and transmit any scheduled steps prior to the given 'move_clock'
|
||||
int
|
||||
steppersync_flush(struct steppersync *ss, uint64_t move_clock)
|
||||
{
|
||||
// Flush each stepcompress to the specified move_clock
|
||||
int i;
|
||||
for (i=0; i<ss->sc_num; i++) {
|
||||
int ret = stepcompress_flush(ss->sc_list[i], move_clock);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Order commands by the reqclock of each pending command
|
||||
struct list_head msgs;
|
||||
list_init(&msgs);
|
||||
for (;;) {
|
||||
// Find message with lowest reqclock
|
||||
uint64_t req_clock = MAX_CLOCK;
|
||||
struct queue_message *qm = NULL;
|
||||
for (i=0; i<ss->sc_num; i++) {
|
||||
struct stepcompress *sc = ss->sc_list[i];
|
||||
if (!list_empty(&sc->msg_queue)) {
|
||||
struct queue_message *m = list_first_entry(
|
||||
&sc->msg_queue, struct queue_message, node);
|
||||
if (m->req_clock < req_clock) {
|
||||
qm = m;
|
||||
req_clock = m->req_clock;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!qm || (qm->min_clock && req_clock > move_clock))
|
||||
break;
|
||||
|
||||
uint64_t next_avail = ss->move_clocks[0];
|
||||
if (qm->min_clock)
|
||||
// The qm->min_clock field is overloaded to indicate that
|
||||
// the command uses the 'move queue' and to store the time
|
||||
// that move queue item becomes available.
|
||||
heap_replace(ss, qm->min_clock);
|
||||
// Reset the min_clock to its normal meaning (minimum transmit time)
|
||||
qm->min_clock = next_avail;
|
||||
|
||||
// Batch this command
|
||||
list_del(&qm->node);
|
||||
list_add_tail(&qm->node, &msgs);
|
||||
}
|
||||
|
||||
// Transmit commands
|
||||
if (!list_empty(&msgs))
|
||||
serialqueue_send_batch(ss->sq, ss->cq, &msgs);
|
||||
return 0;
|
||||
}
|
||||
135
klippy/stepper.py
Normal file
@@ -0,0 +1,135 @@
|
||||
# Printer stepper support
|
||||
#
|
||||
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import math, logging
|
||||
import homing, pins
|
||||
|
||||
class PrinterStepper:
|
||||
def __init__(self, printer, config, name):
|
||||
self.name = name
|
||||
|
||||
self.step_dist = config.getfloat('step_distance', above=0.)
|
||||
self.inv_step_dist = 1. / self.step_dist
|
||||
self.min_stop_interval = 0.
|
||||
self.mcu_stepper = pins.setup_pin(
|
||||
printer, 'stepper', config.get('step_pin'))
|
||||
dir_pin_params = pins.get_printer_pins(printer).parse_pin_desc(
|
||||
config.get('dir_pin'), can_invert=True)
|
||||
self.mcu_stepper.setup_dir_pin(dir_pin_params)
|
||||
self.mcu_stepper.setup_step_distance(self.step_dist)
|
||||
|
||||
enable_pin = config.get('enable_pin', None)
|
||||
self.mcu_enable = None
|
||||
if enable_pin is not None:
|
||||
self.mcu_enable = pins.setup_pin(printer, 'digital_out', enable_pin)
|
||||
self.mcu_enable.setup_max_duration(0.)
|
||||
self.need_motor_enable = True
|
||||
def _dist_to_time(self, dist, start_velocity, accel):
|
||||
# Calculate the time it takes to travel a distance with constant accel
|
||||
time_offset = start_velocity / accel
|
||||
return math.sqrt(2. * dist / accel + time_offset**2) - time_offset
|
||||
def set_max_jerk(self, max_halt_velocity, max_accel):
|
||||
# Calculate the firmware's maximum halt interval time
|
||||
last_step_time = self._dist_to_time(
|
||||
self.step_dist, max_halt_velocity, max_accel)
|
||||
second_last_step_time = self._dist_to_time(
|
||||
2. * self.step_dist, max_halt_velocity, max_accel)
|
||||
min_stop_interval = second_last_step_time - last_step_time
|
||||
self.mcu_stepper.setup_min_stop_interval(min_stop_interval)
|
||||
def motor_enable(self, print_time, enable=0):
|
||||
if enable and self.need_motor_enable:
|
||||
self.mcu_stepper.reset_step_clock(print_time)
|
||||
if (self.mcu_enable is not None
|
||||
and self.mcu_enable.get_last_setting() != enable):
|
||||
self.mcu_enable.set_digital(print_time, enable)
|
||||
self.need_motor_enable = not enable
|
||||
|
||||
class PrinterHomingStepper(PrinterStepper):
|
||||
def __init__(self, printer, config, name):
|
||||
PrinterStepper.__init__(self, printer, config, name)
|
||||
|
||||
self.mcu_endstop = pins.setup_pin(
|
||||
printer, 'endstop', config.get('endstop_pin'))
|
||||
self.mcu_endstop.add_stepper(self.mcu_stepper)
|
||||
self.position_min = config.getfloat('position_min', 0.)
|
||||
self.position_max = config.getfloat(
|
||||
'position_max', 0., above=self.position_min)
|
||||
self.position_endstop = config.getfloat('position_endstop')
|
||||
|
||||
self.homing_speed = config.getfloat('homing_speed', 5.0, above=0.)
|
||||
self.homing_positive_dir = config.getboolean('homing_positive_dir', None)
|
||||
if self.homing_positive_dir is None:
|
||||
axis_len = self.position_max - self.position_min
|
||||
if self.position_endstop <= self.position_min + axis_len / 4.:
|
||||
self.homing_positive_dir = False
|
||||
elif self.position_endstop >= self.position_max - axis_len / 4.:
|
||||
self.homing_positive_dir = True
|
||||
else:
|
||||
raise config.error(
|
||||
"Unable to infer homing_positive_dir in section '%s'" % (
|
||||
config.section,))
|
||||
self.homing_retract_dist = config.getfloat(
|
||||
'homing_retract_dist', 5., above=0.)
|
||||
self.homing_stepper_phases = config.getint(
|
||||
'homing_stepper_phases', None, minval=0)
|
||||
endstop_accuracy = config.getfloat(
|
||||
'homing_endstop_accuracy', None, above=0.)
|
||||
self.homing_endstop_accuracy = self.homing_endstop_phase = None
|
||||
if self.homing_stepper_phases:
|
||||
self.homing_endstop_phase = config.getint(
|
||||
'homing_endstop_phase', None, minval=0
|
||||
, maxval=self.homing_stepper_phases-1)
|
||||
if self.homing_endstop_phase is not None:
|
||||
# Adjust the endstop position so 0.0 is always at a full step
|
||||
micro_steps = self.homing_stepper_phases // 4
|
||||
phase_offset = (
|
||||
((self.homing_endstop_phase + micro_steps // 2) % micro_steps)
|
||||
- micro_steps // 2) * self.step_dist
|
||||
full_step = micro_steps * self.step_dist
|
||||
es_pos = (int(self.position_endstop / full_step + .5) * full_step
|
||||
+ phase_offset)
|
||||
if es_pos != self.position_endstop:
|
||||
logging.info("Changing %s endstop position to %.3f"
|
||||
" (from %.3f)", self.name, es_pos,
|
||||
self.position_endstop)
|
||||
self.position_endstop = es_pos
|
||||
if endstop_accuracy is None:
|
||||
self.homing_endstop_accuracy = self.homing_stepper_phases//2 - 1
|
||||
elif self.homing_endstop_phase is not None:
|
||||
self.homing_endstop_accuracy = int(math.ceil(
|
||||
endstop_accuracy * self.inv_step_dist / 2.))
|
||||
else:
|
||||
self.homing_endstop_accuracy = int(math.ceil(
|
||||
endstop_accuracy * self.inv_step_dist))
|
||||
if self.homing_endstop_accuracy >= self.homing_stepper_phases // 2:
|
||||
logging.info("Endstop for %s is not accurate enough for stepper"
|
||||
" phase adjustment", name)
|
||||
self.homing_stepper_phases = None
|
||||
if self.mcu_endstop.get_mcu().is_fileoutput():
|
||||
self.homing_endstop_accuracy = self.homing_stepper_phases
|
||||
def get_homing_speed(self):
|
||||
# Round the configured homing speed so that it is an even
|
||||
# number of ticks per step.
|
||||
adjusted_freq = self.mcu_stepper.get_mcu().get_adjusted_freq()
|
||||
dist_ticks = adjusted_freq * self.step_dist
|
||||
ticks_per_step = round(dist_ticks / self.homing_speed)
|
||||
return dist_ticks / ticks_per_step
|
||||
def get_homed_offset(self):
|
||||
if not self.homing_stepper_phases or self.need_motor_enable:
|
||||
return 0
|
||||
pos = self.mcu_stepper.get_mcu_position()
|
||||
pos %= self.homing_stepper_phases
|
||||
if self.homing_endstop_phase is None:
|
||||
logging.info("Setting %s endstop phase to %d", self.name, pos)
|
||||
self.homing_endstop_phase = pos
|
||||
return 0
|
||||
delta = (pos - self.homing_endstop_phase) % self.homing_stepper_phases
|
||||
if delta >= self.homing_stepper_phases - self.homing_endstop_accuracy:
|
||||
delta -= self.homing_stepper_phases
|
||||
elif delta > self.homing_endstop_accuracy:
|
||||
raise homing.EndstopError(
|
||||
"Endstop %s incorrect phase (got %d vs %d)" % (
|
||||
self.name, pos, self.homing_endstop_phase))
|
||||
return delta * self.step_dist
|
||||
390
klippy/toolhead.py
Normal file
@@ -0,0 +1,390 @@
|
||||
# Code for coordinating events on the printer toolhead
|
||||
#
|
||||
# Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import math, logging
|
||||
import mcu, homing, cartesian, corexy, delta, extruder
|
||||
|
||||
# Common suffixes: _d is distance (in mm), _v is velocity (in
|
||||
# mm/second), _v2 is velocity squared (mm^2/s^2), _t is time (in
|
||||
# seconds), _r is ratio (scalar between 0.0 and 1.0)
|
||||
|
||||
# Class to track each move request
|
||||
class Move:
|
||||
def __init__(self, toolhead, start_pos, end_pos, speed):
|
||||
self.toolhead = toolhead
|
||||
self.start_pos = tuple(start_pos)
|
||||
self.end_pos = tuple(end_pos)
|
||||
self.accel = toolhead.max_accel
|
||||
self.is_kinematic_move = True
|
||||
self.axes_d = axes_d = [end_pos[i] - start_pos[i] for i in (0, 1, 2, 3)]
|
||||
self.move_d = move_d = math.sqrt(sum([d*d for d in axes_d[:3]]))
|
||||
if not move_d:
|
||||
# Extrude only move
|
||||
self.move_d = move_d = abs(axes_d[3])
|
||||
self.is_kinematic_move = False
|
||||
self.min_move_t = move_d / speed
|
||||
# Junction speeds are tracked in velocity squared. The
|
||||
# delta_v2 is the maximum amount of this squared-velocity that
|
||||
# can change in this move.
|
||||
self.max_start_v2 = 0.
|
||||
self.max_cruise_v2 = speed**2
|
||||
self.delta_v2 = 2.0 * move_d * self.accel
|
||||
self.max_smoothed_v2 = 0.
|
||||
self.smooth_delta_v2 = 2.0 * move_d * toolhead.max_accel_to_decel
|
||||
def limit_speed(self, speed, accel):
|
||||
speed2 = speed**2
|
||||
if speed2 < self.max_cruise_v2:
|
||||
self.max_cruise_v2 = speed2
|
||||
self.min_move_t = self.move_d / speed
|
||||
self.accel = min(self.accel, accel)
|
||||
self.delta_v2 = 2.0 * self.move_d * self.accel
|
||||
self.smooth_delta_v2 = min(self.smooth_delta_v2, self.delta_v2)
|
||||
def calc_junction(self, prev_move):
|
||||
if not self.is_kinematic_move or not prev_move.is_kinematic_move:
|
||||
return
|
||||
# Allow extruder to calculate its maximum junction
|
||||
extruder_v2 = self.toolhead.extruder.calc_junction(prev_move, self)
|
||||
# Find max velocity using approximated centripetal velocity as
|
||||
# described at:
|
||||
# https://onehossshay.wordpress.com/2011/09/24/improving_grbl_cornering_algorithm/
|
||||
axes_d = self.axes_d
|
||||
prev_axes_d = prev_move.axes_d
|
||||
junction_cos_theta = -((axes_d[0] * prev_axes_d[0]
|
||||
+ axes_d[1] * prev_axes_d[1]
|
||||
+ axes_d[2] * prev_axes_d[2])
|
||||
/ (self.move_d * prev_move.move_d))
|
||||
if junction_cos_theta > 0.999999:
|
||||
return
|
||||
junction_cos_theta = max(junction_cos_theta, -0.999999)
|
||||
sin_theta_d2 = math.sqrt(0.5*(1.0-junction_cos_theta))
|
||||
R = self.toolhead.junction_deviation * sin_theta_d2 / (1. - sin_theta_d2)
|
||||
self.max_start_v2 = min(
|
||||
R * self.accel, R * prev_move.accel, extruder_v2
|
||||
, self.max_cruise_v2, prev_move.max_cruise_v2
|
||||
, prev_move.max_start_v2 + prev_move.delta_v2)
|
||||
self.max_smoothed_v2 = min(
|
||||
self.max_start_v2
|
||||
, prev_move.max_smoothed_v2 + prev_move.smooth_delta_v2)
|
||||
def set_junction(self, start_v2, cruise_v2, end_v2):
|
||||
# Determine accel, cruise, and decel portions of the move distance
|
||||
inv_delta_v2 = 1. / self.delta_v2
|
||||
self.accel_r = accel_r = (cruise_v2 - start_v2) * inv_delta_v2
|
||||
self.decel_r = decel_r = (cruise_v2 - end_v2) * inv_delta_v2
|
||||
self.cruise_r = cruise_r = 1. - accel_r - decel_r
|
||||
# Determine move velocities
|
||||
self.start_v = start_v = math.sqrt(start_v2)
|
||||
self.cruise_v = cruise_v = math.sqrt(cruise_v2)
|
||||
self.end_v = end_v = math.sqrt(end_v2)
|
||||
# Determine time spent in each portion of move (time is the
|
||||
# distance divided by average velocity)
|
||||
self.accel_t = accel_r * self.move_d / ((start_v + cruise_v) * 0.5)
|
||||
self.cruise_t = cruise_r * self.move_d / cruise_v
|
||||
self.decel_t = decel_r * self.move_d / ((end_v + cruise_v) * 0.5)
|
||||
def move(self):
|
||||
# Generate step times for the move
|
||||
next_move_time = self.toolhead.get_next_move_time()
|
||||
if self.is_kinematic_move:
|
||||
self.toolhead.kin.move(next_move_time, self)
|
||||
if self.axes_d[3]:
|
||||
self.toolhead.extruder.move(next_move_time, self)
|
||||
self.toolhead.update_move_time(
|
||||
self.accel_t + self.cruise_t + self.decel_t)
|
||||
|
||||
LOOKAHEAD_FLUSH_TIME = 0.250
|
||||
|
||||
# Class to track a list of pending move requests and to facilitate
|
||||
# "look-ahead" across moves to reduce acceleration between moves.
|
||||
class MoveQueue:
|
||||
def __init__(self):
|
||||
self.extruder_lookahead = None
|
||||
self.queue = []
|
||||
self.leftover = 0
|
||||
self.junction_flush = LOOKAHEAD_FLUSH_TIME
|
||||
def reset(self):
|
||||
del self.queue[:]
|
||||
self.leftover = 0
|
||||
self.junction_flush = LOOKAHEAD_FLUSH_TIME
|
||||
def set_flush_time(self, flush_time):
|
||||
self.junction_flush = flush_time
|
||||
def set_extruder(self, extruder):
|
||||
self.extruder_lookahead = extruder.lookahead
|
||||
def flush(self, lazy=False):
|
||||
self.junction_flush = LOOKAHEAD_FLUSH_TIME
|
||||
update_flush_count = lazy
|
||||
queue = self.queue
|
||||
flush_count = len(queue)
|
||||
# Traverse queue from last to first move and determine maximum
|
||||
# junction speed assuming the robot comes to a complete stop
|
||||
# after the last move.
|
||||
delayed = []
|
||||
next_end_v2 = next_smoothed_v2 = peak_cruise_v2 = 0.
|
||||
for i in range(flush_count-1, self.leftover-1, -1):
|
||||
move = queue[i]
|
||||
reachable_start_v2 = next_end_v2 + move.delta_v2
|
||||
start_v2 = min(move.max_start_v2, reachable_start_v2)
|
||||
reachable_smoothed_v2 = next_smoothed_v2 + move.smooth_delta_v2
|
||||
smoothed_v2 = min(move.max_smoothed_v2, reachable_smoothed_v2)
|
||||
if smoothed_v2 < reachable_smoothed_v2:
|
||||
# It's possible for this move to accelerate
|
||||
if (smoothed_v2 + move.smooth_delta_v2 > next_smoothed_v2
|
||||
or delayed):
|
||||
# This move can decelerate or this is a full accel
|
||||
# move after a full decel move
|
||||
if update_flush_count and peak_cruise_v2:
|
||||
flush_count = i
|
||||
update_flush_count = False
|
||||
peak_cruise_v2 = min(move.max_cruise_v2, (
|
||||
smoothed_v2 + reachable_smoothed_v2) * .5)
|
||||
if delayed:
|
||||
# Propagate peak_cruise_v2 to any delayed moves
|
||||
if not update_flush_count and i < flush_count:
|
||||
for m, ms_v2, me_v2 in delayed:
|
||||
mc_v2 = min(peak_cruise_v2, ms_v2)
|
||||
m.set_junction(min(ms_v2, mc_v2), mc_v2
|
||||
, min(me_v2, mc_v2))
|
||||
del delayed[:]
|
||||
if not update_flush_count and i < flush_count:
|
||||
cruise_v2 = min((start_v2 + reachable_start_v2) * .5
|
||||
, move.max_cruise_v2, peak_cruise_v2)
|
||||
move.set_junction(min(start_v2, cruise_v2), cruise_v2
|
||||
, min(next_end_v2, cruise_v2))
|
||||
else:
|
||||
# Delay calculating this move until peak_cruise_v2 is known
|
||||
delayed.append((move, start_v2, next_end_v2))
|
||||
next_end_v2 = start_v2
|
||||
next_smoothed_v2 = smoothed_v2
|
||||
if update_flush_count:
|
||||
return
|
||||
# Allow extruder to do its lookahead
|
||||
move_count = self.extruder_lookahead(queue, flush_count, lazy)
|
||||
# Generate step times for all moves ready to be flushed
|
||||
for move in queue[:move_count]:
|
||||
move.move()
|
||||
# Remove processed moves from the queue
|
||||
self.leftover = flush_count - move_count
|
||||
del queue[:move_count]
|
||||
def add_move(self, move):
|
||||
self.queue.append(move)
|
||||
if len(self.queue) == 1:
|
||||
return
|
||||
move.calc_junction(self.queue[-2])
|
||||
self.junction_flush -= move.min_move_t
|
||||
if self.junction_flush <= 0.:
|
||||
# There are enough queued moves to return to zero velocity
|
||||
# from the first move's maximum possible velocity, so at
|
||||
# least one move can be flushed.
|
||||
self.flush(lazy=True)
|
||||
|
||||
STALL_TIME = 0.100
|
||||
|
||||
# Main code to track events (and their timing) on the printer toolhead
|
||||
class ToolHead:
|
||||
def __init__(self, printer, config):
|
||||
self.printer = printer
|
||||
self.reactor = printer.reactor
|
||||
self.all_mcus = mcu.get_printer_mcus(printer)
|
||||
self.mcu = self.all_mcus[0]
|
||||
self.max_velocity = config.getfloat('max_velocity', above=0.)
|
||||
self.max_accel = config.getfloat('max_accel', above=0.)
|
||||
self.max_accel_to_decel = config.getfloat(
|
||||
'max_accel_to_decel', self.max_accel * 0.5
|
||||
, above=0., maxval=self.max_accel)
|
||||
self.junction_deviation = config.getfloat(
|
||||
'junction_deviation', 0.02, above=0.)
|
||||
self.move_queue = MoveQueue()
|
||||
self.commanded_pos = [0., 0., 0., 0.]
|
||||
# Print time tracking
|
||||
self.buffer_time_low = config.getfloat(
|
||||
'buffer_time_low', 1.000, above=0.)
|
||||
self.buffer_time_high = config.getfloat(
|
||||
'buffer_time_high', 2.000, above=self.buffer_time_low)
|
||||
self.buffer_time_start = config.getfloat(
|
||||
'buffer_time_start', 0.250, above=0.)
|
||||
self.move_flush_time = config.getfloat(
|
||||
'move_flush_time', 0.050, above=0.)
|
||||
self.print_time = 0.
|
||||
self.need_check_stall = -1.
|
||||
self.print_stall = 0
|
||||
self.sync_print_time = True
|
||||
self.last_flush_from_idle = False
|
||||
self.flush_timer = self.reactor.register_timer(self._flush_handler)
|
||||
self.move_queue.set_flush_time(self.buffer_time_high)
|
||||
# Motor off tracking
|
||||
self.need_motor_off = False
|
||||
self.motor_off_time = config.getfloat('motor_off_time', 600., above=0.)
|
||||
self.motor_off_timer = self.reactor.register_timer(
|
||||
self._motor_off_handler, self.reactor.NOW)
|
||||
# Create kinematics class
|
||||
self.extruder = extruder.DummyExtruder()
|
||||
self.move_queue.set_extruder(self.extruder)
|
||||
kintypes = {'cartesian': cartesian.CartKinematics,
|
||||
'corexy': corexy.CoreXYKinematics,
|
||||
'delta': delta.DeltaKinematics}
|
||||
self.kin = config.getchoice('kinematics', kintypes)(
|
||||
self, printer, config)
|
||||
# Print time tracking
|
||||
def update_move_time(self, movetime):
|
||||
self.print_time += movetime
|
||||
flush_to_time = self.print_time - self.move_flush_time
|
||||
for m in self.all_mcus:
|
||||
m.flush_moves(flush_to_time)
|
||||
def get_next_move_time(self):
|
||||
if not self.sync_print_time:
|
||||
return self.print_time
|
||||
self.sync_print_time = False
|
||||
est_print_time = self.mcu.estimated_print_time(self.reactor.monotonic())
|
||||
if self.last_flush_from_idle and self.print_time > est_print_time:
|
||||
self.print_stall += 1
|
||||
self.last_flush_from_idle = False
|
||||
self.need_motor_off = True
|
||||
self.print_time = max(
|
||||
self.print_time, est_print_time + self.buffer_time_start)
|
||||
self.reactor.update_timer(self.flush_timer, self.reactor.NOW)
|
||||
return self.print_time
|
||||
def _flush_lookahead(self, must_sync=False):
|
||||
sync_print_time = self.sync_print_time
|
||||
self.move_queue.flush()
|
||||
self.last_flush_from_idle = False
|
||||
if sync_print_time or must_sync:
|
||||
self.sync_print_time = True
|
||||
self.move_queue.set_flush_time(self.buffer_time_high)
|
||||
self.need_check_stall = -1.
|
||||
self.reactor.update_timer(self.flush_timer, self.reactor.NEVER)
|
||||
for m in self.all_mcus:
|
||||
m.flush_moves(self.print_time)
|
||||
def get_last_move_time(self):
|
||||
self._flush_lookahead()
|
||||
return self.get_next_move_time()
|
||||
def reset_print_time(self, min_print_time=0.):
|
||||
self._flush_lookahead(must_sync=True)
|
||||
self.print_time = max(min_print_time, self.mcu.estimated_print_time(
|
||||
self.reactor.monotonic()))
|
||||
def _check_stall(self):
|
||||
eventtime = self.reactor.monotonic()
|
||||
if self.sync_print_time:
|
||||
# Building initial queue - make sure to flush on idle input
|
||||
self.reactor.update_timer(self.flush_timer, eventtime + 0.100)
|
||||
return
|
||||
# Check if there are lots of queued moves and stall if so
|
||||
while 1:
|
||||
est_print_time = self.mcu.estimated_print_time(eventtime)
|
||||
buffer_time = self.print_time - est_print_time
|
||||
stall_time = buffer_time - self.buffer_time_high
|
||||
if stall_time <= 0.:
|
||||
break
|
||||
if self.mcu.is_fileoutput():
|
||||
self.need_check_stall = self.reactor.NEVER
|
||||
return
|
||||
eventtime = self.reactor.pause(eventtime + min(1., stall_time))
|
||||
self.need_check_stall = est_print_time + self.buffer_time_high + 0.100
|
||||
def _flush_handler(self, eventtime):
|
||||
try:
|
||||
print_time = self.print_time
|
||||
buffer_time = print_time - self.mcu.estimated_print_time(eventtime)
|
||||
if buffer_time > self.buffer_time_low:
|
||||
# Running normally - reschedule check
|
||||
return eventtime + buffer_time - self.buffer_time_low
|
||||
# Under ran low buffer mark - flush lookahead queue
|
||||
self._flush_lookahead(must_sync=True)
|
||||
if print_time != self.print_time:
|
||||
self.last_flush_from_idle = True
|
||||
except:
|
||||
logging.exception("Exception in flush_handler")
|
||||
self.printer.invoke_shutdown("Exception in flush_handler")
|
||||
return self.reactor.NEVER
|
||||
# Motor off timer
|
||||
def _motor_off_handler(self, eventtime):
|
||||
if not self.need_motor_off or not self.sync_print_time:
|
||||
return eventtime + self.motor_off_time
|
||||
elapsed_time = self.mcu.estimated_print_time(eventtime) - self.print_time
|
||||
if elapsed_time < self.motor_off_time:
|
||||
return eventtime + self.motor_off_time - elapsed_time
|
||||
try:
|
||||
self.motor_off()
|
||||
except:
|
||||
logging.exception("Exception in motor_off_handler")
|
||||
self.printer.invoke_shutdown("Exception in motor_off_handler")
|
||||
return eventtime + self.motor_off_time
|
||||
# Movement commands
|
||||
def get_position(self):
|
||||
return list(self.commanded_pos)
|
||||
def set_position(self, newpos):
|
||||
self._flush_lookahead()
|
||||
self.commanded_pos[:] = newpos
|
||||
self.kin.set_position(newpos)
|
||||
def move(self, newpos, speed):
|
||||
speed = min(speed, self.max_velocity)
|
||||
move = Move(self, self.commanded_pos, newpos, speed)
|
||||
if not move.move_d:
|
||||
return
|
||||
if move.is_kinematic_move:
|
||||
self.kin.check_move(move)
|
||||
if move.axes_d[3]:
|
||||
self.extruder.check_move(move)
|
||||
self.commanded_pos[:] = newpos
|
||||
self.move_queue.add_move(move)
|
||||
if self.print_time > self.need_check_stall:
|
||||
self._check_stall()
|
||||
def home(self, homing_state):
|
||||
self.kin.home(homing_state)
|
||||
def dwell(self, delay):
|
||||
self.get_last_move_time()
|
||||
self.update_move_time(delay)
|
||||
self._check_stall()
|
||||
def motor_off(self):
|
||||
self.dwell(STALL_TIME)
|
||||
last_move_time = self.get_last_move_time()
|
||||
self.kin.motor_off(last_move_time)
|
||||
self.extruder.motor_off(last_move_time)
|
||||
self.dwell(STALL_TIME)
|
||||
self.need_motor_off = False
|
||||
logging.debug('; Max time of %f', last_move_time)
|
||||
def wait_moves(self):
|
||||
self._flush_lookahead()
|
||||
if self.mcu.is_fileoutput():
|
||||
return
|
||||
eventtime = self.reactor.monotonic()
|
||||
while (not self.sync_print_time
|
||||
or self.print_time >= self.mcu.estimated_print_time(eventtime)):
|
||||
eventtime = self.reactor.pause(eventtime + 0.100)
|
||||
def query_endstops(self, query_flags=""):
|
||||
last_move_time = self.get_last_move_time()
|
||||
return self.kin.query_endstops(last_move_time, query_flags)
|
||||
def set_extruder(self, extruder):
|
||||
last_move_time = self.get_last_move_time()
|
||||
self.extruder.set_active(last_move_time, False)
|
||||
extrude_pos = extruder.set_active(last_move_time, True)
|
||||
self.extruder = extruder
|
||||
self.move_queue.set_extruder(extruder)
|
||||
self.commanded_pos[3] = extrude_pos
|
||||
# Misc commands
|
||||
def check_active(self, eventtime):
|
||||
for m in self.all_mcus:
|
||||
m.check_active(self.print_time, eventtime)
|
||||
if not self.sync_print_time:
|
||||
return True
|
||||
return self.print_time + 60. > self.mcu.estimated_print_time(eventtime)
|
||||
def stats(self, eventtime):
|
||||
est_print_time = self.mcu.estimated_print_time(eventtime)
|
||||
buffer_time = max(0., self.print_time - est_print_time)
|
||||
return "print_time=%.3f buffer_time=%.3f print_stall=%d" % (
|
||||
self.print_time, buffer_time, self.print_stall)
|
||||
def do_shutdown(self):
|
||||
try:
|
||||
self.move_queue.reset()
|
||||
self.reset_print_time()
|
||||
except:
|
||||
logging.exception("Exception in do_shutdown")
|
||||
def get_max_velocity(self):
|
||||
return self.max_velocity, self.max_accel
|
||||
def get_max_axis_halt(self):
|
||||
# Determine the maximum velocity a cartesian axis could halt
|
||||
# at due to the junction_deviation setting. The 8.0 was
|
||||
# determined experimentally.
|
||||
return min(self.max_velocity,
|
||||
math.sqrt(8. * self.junction_deviation * self.max_accel))
|
||||
|
||||
def add_printer_objects(printer, config):
|
||||
printer.add_object('toolhead', ToolHead(printer, config))
|
||||
69
klippy/util.py
Normal file
@@ -0,0 +1,69 @@
|
||||
# Low level unix utility functions
|
||||
#
|
||||
# Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import sys, os, pty, fcntl, termios, signal, logging
|
||||
import subprocess, traceback, shlex
|
||||
|
||||
# Return the SIGINT interrupt handler back to the OS default
|
||||
def fix_sigint():
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
fix_sigint()
|
||||
|
||||
# Set a file-descriptor as non-blocking
|
||||
def set_nonblock(fd):
|
||||
fcntl.fcntl(fd, fcntl.F_SETFL
|
||||
, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
|
||||
|
||||
# Clear HUPCL flag
|
||||
def clear_hupcl(fd):
|
||||
attrs = termios.tcgetattr(fd)
|
||||
attrs[2] = attrs[2] & ~termios.HUPCL
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, attrs)
|
||||
|
||||
# Support for creating a pseudo-tty for emulating a serial port
|
||||
def create_pty(ptyname):
|
||||
mfd, sfd = pty.openpty()
|
||||
try:
|
||||
os.unlink(ptyname)
|
||||
except os.error:
|
||||
pass
|
||||
os.symlink(os.ttyname(sfd), ptyname)
|
||||
fcntl.fcntl(mfd, fcntl.F_SETFL
|
||||
, fcntl.fcntl(mfd, fcntl.F_GETFL) | os.O_NONBLOCK)
|
||||
old = termios.tcgetattr(mfd)
|
||||
old[3] = old[3] & ~termios.ECHO
|
||||
termios.tcsetattr(mfd, termios.TCSADRAIN, old)
|
||||
return mfd
|
||||
|
||||
def get_cpu_info():
|
||||
try:
|
||||
f = open('/proc/cpuinfo', 'rb')
|
||||
data = f.read()
|
||||
f.close()
|
||||
except OSError:
|
||||
logging.debug("Exception on read /proc/cpuinfo: %s",
|
||||
traceback.format_exc())
|
||||
return "?"
|
||||
lines = [l.split(':', 1) for l in data.split('\n')]
|
||||
lines = [(l[0].strip(), l[1].strip()) for l in lines if len(l) == 2]
|
||||
core_count = [k for k, v in lines].count("processor")
|
||||
model_name = dict(lines).get("model name", "?")
|
||||
return "%d core %s" % (core_count, model_name)
|
||||
|
||||
def get_git_version():
|
||||
# Obtain version info from "git" program
|
||||
gitdir = os.path.join(sys.path[0], '..')
|
||||
if not os.path.exists(gitdir):
|
||||
logging.debug("No '.git' file/directory found")
|
||||
return "?"
|
||||
prog = "git -C %s describe --tags --long --dirty" % (gitdir,)
|
||||
try:
|
||||
process = subprocess.Popen(shlex.split(prog), stdout=subprocess.PIPE)
|
||||
output = process.communicate()[0]
|
||||
retcode = process.poll()
|
||||
except OSError:
|
||||
logging.debug("Exception on run: %s", traceback.format_exc())
|
||||
return "?"
|
||||
return output.strip()
|
||||
24
lib/README
Normal file
@@ -0,0 +1,24 @@
|
||||
This directory contains external library code.
|
||||
|
||||
The pjrc_usb_serial directory contains code from:
|
||||
http://www.pjrc.com/teensy/usb_serial.html
|
||||
version 1.7 (extracted on 20160605). It has been modified to compile
|
||||
on recent versions of gcc, to support asynchronous notification of
|
||||
incoming data, and to not use SOF interrupts. See usb_serial.patch for
|
||||
the modifications.
|
||||
|
||||
The cmsis-sam3x8e directory contains code from the Arduino project:
|
||||
https://www.arduino.cc/
|
||||
version 1.5.1 (extracted on 20160608). It has been modified to compile
|
||||
with gcc's LTO feature. See cmsis-sam3x8e.patch for the modifications.
|
||||
|
||||
The hub-ctrl directory contains code from:
|
||||
https://github.com/codazoda/hub-ctrl.c/
|
||||
revision 42095e522859059e8a5f4ec05c1e3def01a870a9.
|
||||
|
||||
The pru_rpmsg directory contains code from:
|
||||
https://github.com/dinuxbg/pru-gcc-examples
|
||||
revision 425a42d82006cf0aa24be27b483d2f6a41607489. The code is taken
|
||||
from the repo's hc-sr04-range-sensor directory. It has been modified
|
||||
so that the IEP definitions compile correctly. See pru_rpmsg.patch for
|
||||
the modifications.
|
||||
1244
lib/cmsis-sam3x8e/cmsis-include/core_cm3.h
Normal file
609
lib/cmsis-sam3x8e/cmsis-include/core_cmFunc.h
Normal file
@@ -0,0 +1,609 @@
|
||||
/**************************************************************************//**
|
||||
* @file core_cmFunc.h
|
||||
* @brief CMSIS Cortex-M Core Function Access Header File
|
||||
* @version V2.10
|
||||
* @date 26. July 2011
|
||||
*
|
||||
* @note
|
||||
* Copyright (C) 2009-2011 ARM Limited. All rights reserved.
|
||||
*
|
||||
* @par
|
||||
* ARM Limited (ARM) is supplying this software for use with Cortex-M
|
||||
* processor based microcontrollers. This file can be freely distributed
|
||||
* within development tools that are supporting such ARM based processors.
|
||||
*
|
||||
* @par
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
|
||||
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __CORE_CMFUNC_H
|
||||
#define __CORE_CMFUNC_H
|
||||
|
||||
|
||||
/* ########################### Core Function Access ########################### */
|
||||
/** \ingroup CMSIS_Core_FunctionInterface
|
||||
\defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions
|
||||
@{
|
||||
*/
|
||||
|
||||
#if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/
|
||||
/* ARM armcc specific functions */
|
||||
|
||||
#if (__ARMCC_VERSION < 400677)
|
||||
#error "Please use ARM Compiler Toolchain V4.0.677 or later!"
|
||||
#endif
|
||||
|
||||
/* intrinsic void __enable_irq(); */
|
||||
/* intrinsic void __disable_irq(); */
|
||||
|
||||
/** \brief Get Control Register
|
||||
|
||||
This function returns the content of the Control Register.
|
||||
|
||||
\return Control Register value
|
||||
*/
|
||||
static __INLINE uint32_t __get_CONTROL(void)
|
||||
{
|
||||
register uint32_t __regControl __ASM("control");
|
||||
return(__regControl);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Control Register
|
||||
|
||||
This function writes the given value to the Control Register.
|
||||
|
||||
\param [in] control Control Register value to set
|
||||
*/
|
||||
static __INLINE void __set_CONTROL(uint32_t control)
|
||||
{
|
||||
register uint32_t __regControl __ASM("control");
|
||||
__regControl = control;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get ISPR Register
|
||||
|
||||
This function returns the content of the ISPR Register.
|
||||
|
||||
\return ISPR Register value
|
||||
*/
|
||||
static __INLINE uint32_t __get_IPSR(void)
|
||||
{
|
||||
register uint32_t __regIPSR __ASM("ipsr");
|
||||
return(__regIPSR);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get APSR Register
|
||||
|
||||
This function returns the content of the APSR Register.
|
||||
|
||||
\return APSR Register value
|
||||
*/
|
||||
static __INLINE uint32_t __get_APSR(void)
|
||||
{
|
||||
register uint32_t __regAPSR __ASM("apsr");
|
||||
return(__regAPSR);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get xPSR Register
|
||||
|
||||
This function returns the content of the xPSR Register.
|
||||
|
||||
\return xPSR Register value
|
||||
*/
|
||||
static __INLINE uint32_t __get_xPSR(void)
|
||||
{
|
||||
register uint32_t __regXPSR __ASM("xpsr");
|
||||
return(__regXPSR);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Process Stack Pointer
|
||||
|
||||
This function returns the current value of the Process Stack Pointer (PSP).
|
||||
|
||||
\return PSP Register value
|
||||
*/
|
||||
static __INLINE uint32_t __get_PSP(void)
|
||||
{
|
||||
register uint32_t __regProcessStackPointer __ASM("psp");
|
||||
return(__regProcessStackPointer);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Process Stack Pointer
|
||||
|
||||
This function assigns the given value to the Process Stack Pointer (PSP).
|
||||
|
||||
\param [in] topOfProcStack Process Stack Pointer value to set
|
||||
*/
|
||||
static __INLINE void __set_PSP(uint32_t topOfProcStack)
|
||||
{
|
||||
register uint32_t __regProcessStackPointer __ASM("psp");
|
||||
__regProcessStackPointer = topOfProcStack;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Main Stack Pointer
|
||||
|
||||
This function returns the current value of the Main Stack Pointer (MSP).
|
||||
|
||||
\return MSP Register value
|
||||
*/
|
||||
static __INLINE uint32_t __get_MSP(void)
|
||||
{
|
||||
register uint32_t __regMainStackPointer __ASM("msp");
|
||||
return(__regMainStackPointer);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Main Stack Pointer
|
||||
|
||||
This function assigns the given value to the Main Stack Pointer (MSP).
|
||||
|
||||
\param [in] topOfMainStack Main Stack Pointer value to set
|
||||
*/
|
||||
static __INLINE void __set_MSP(uint32_t topOfMainStack)
|
||||
{
|
||||
register uint32_t __regMainStackPointer __ASM("msp");
|
||||
__regMainStackPointer = topOfMainStack;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Priority Mask
|
||||
|
||||
This function returns the current state of the priority mask bit from the Priority Mask Register.
|
||||
|
||||
\return Priority Mask value
|
||||
*/
|
||||
static __INLINE uint32_t __get_PRIMASK(void)
|
||||
{
|
||||
register uint32_t __regPriMask __ASM("primask");
|
||||
return(__regPriMask);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Priority Mask
|
||||
|
||||
This function assigns the given value to the Priority Mask Register.
|
||||
|
||||
\param [in] priMask Priority Mask
|
||||
*/
|
||||
static __INLINE void __set_PRIMASK(uint32_t priMask)
|
||||
{
|
||||
register uint32_t __regPriMask __ASM("primask");
|
||||
__regPriMask = (priMask);
|
||||
}
|
||||
|
||||
|
||||
#if (__CORTEX_M >= 0x03)
|
||||
|
||||
/** \brief Enable FIQ
|
||||
|
||||
This function enables FIQ interrupts by clearing the F-bit in the CPSR.
|
||||
Can only be executed in Privileged modes.
|
||||
*/
|
||||
#define __enable_fault_irq __enable_fiq
|
||||
|
||||
|
||||
/** \brief Disable FIQ
|
||||
|
||||
This function disables FIQ interrupts by setting the F-bit in the CPSR.
|
||||
Can only be executed in Privileged modes.
|
||||
*/
|
||||
#define __disable_fault_irq __disable_fiq
|
||||
|
||||
|
||||
/** \brief Get Base Priority
|
||||
|
||||
This function returns the current value of the Base Priority register.
|
||||
|
||||
\return Base Priority register value
|
||||
*/
|
||||
static __INLINE uint32_t __get_BASEPRI(void)
|
||||
{
|
||||
register uint32_t __regBasePri __ASM("basepri");
|
||||
return(__regBasePri);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Base Priority
|
||||
|
||||
This function assigns the given value to the Base Priority register.
|
||||
|
||||
\param [in] basePri Base Priority value to set
|
||||
*/
|
||||
static __INLINE void __set_BASEPRI(uint32_t basePri)
|
||||
{
|
||||
register uint32_t __regBasePri __ASM("basepri");
|
||||
__regBasePri = (basePri & 0xff);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Fault Mask
|
||||
|
||||
This function returns the current value of the Fault Mask register.
|
||||
|
||||
\return Fault Mask register value
|
||||
*/
|
||||
static __INLINE uint32_t __get_FAULTMASK(void)
|
||||
{
|
||||
register uint32_t __regFaultMask __ASM("faultmask");
|
||||
return(__regFaultMask);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Fault Mask
|
||||
|
||||
This function assigns the given value to the Fault Mask register.
|
||||
|
||||
\param [in] faultMask Fault Mask value to set
|
||||
*/
|
||||
static __INLINE void __set_FAULTMASK(uint32_t faultMask)
|
||||
{
|
||||
register uint32_t __regFaultMask __ASM("faultmask");
|
||||
__regFaultMask = (faultMask & (uint32_t)1);
|
||||
}
|
||||
|
||||
#endif /* (__CORTEX_M >= 0x03) */
|
||||
|
||||
|
||||
#if (__CORTEX_M == 0x04)
|
||||
|
||||
/** \brief Get FPSCR
|
||||
|
||||
This function returns the current value of the Floating Point Status/Control register.
|
||||
|
||||
\return Floating Point Status/Control register value
|
||||
*/
|
||||
static __INLINE uint32_t __get_FPSCR(void)
|
||||
{
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
register uint32_t __regfpscr __ASM("fpscr");
|
||||
return(__regfpscr);
|
||||
#else
|
||||
return(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set FPSCR
|
||||
|
||||
This function assigns the given value to the Floating Point Status/Control register.
|
||||
|
||||
\param [in] fpscr Floating Point Status/Control value to set
|
||||
*/
|
||||
static __INLINE void __set_FPSCR(uint32_t fpscr)
|
||||
{
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
register uint32_t __regfpscr __ASM("fpscr");
|
||||
__regfpscr = (fpscr);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* (__CORTEX_M == 0x04) */
|
||||
|
||||
|
||||
#elif defined ( __ICCARM__ ) /*------------------ ICC Compiler -------------------*/
|
||||
/* IAR iccarm specific functions */
|
||||
|
||||
#include <cmsis_iar.h>
|
||||
|
||||
#elif defined ( __GNUC__ ) /*------------------ GNU Compiler ---------------------*/
|
||||
/* GNU gcc specific functions */
|
||||
|
||||
/** \brief Enable IRQ Interrupts
|
||||
|
||||
This function enables IRQ interrupts by clearing the I-bit in the CPSR.
|
||||
Can only be executed in Privileged modes.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __enable_irq(void)
|
||||
{
|
||||
__ASM volatile ("cpsie i");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Disable IRQ Interrupts
|
||||
|
||||
This function disables IRQ interrupts by setting the I-bit in the CPSR.
|
||||
Can only be executed in Privileged modes.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __disable_irq(void)
|
||||
{
|
||||
__ASM volatile ("cpsid i");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Control Register
|
||||
|
||||
This function returns the content of the Control Register.
|
||||
|
||||
\return Control Register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_CONTROL(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, control" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Control Register
|
||||
|
||||
This function writes the given value to the Control Register.
|
||||
|
||||
\param [in] control Control Register value to set
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __set_CONTROL(uint32_t control)
|
||||
{
|
||||
__ASM volatile ("MSR control, %0" : : "r" (control) );
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get ISPR Register
|
||||
|
||||
This function returns the content of the ISPR Register.
|
||||
|
||||
\return ISPR Register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_IPSR(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, ipsr" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get APSR Register
|
||||
|
||||
This function returns the content of the APSR Register.
|
||||
|
||||
\return APSR Register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_APSR(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, apsr" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get xPSR Register
|
||||
|
||||
This function returns the content of the xPSR Register.
|
||||
|
||||
\return xPSR Register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_xPSR(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, xpsr" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Process Stack Pointer
|
||||
|
||||
This function returns the current value of the Process Stack Pointer (PSP).
|
||||
|
||||
\return PSP Register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_PSP(void)
|
||||
{
|
||||
register uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, psp\n" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Process Stack Pointer
|
||||
|
||||
This function assigns the given value to the Process Stack Pointer (PSP).
|
||||
|
||||
\param [in] topOfProcStack Process Stack Pointer value to set
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __set_PSP(uint32_t topOfProcStack)
|
||||
{
|
||||
__ASM volatile ("MSR psp, %0\n" : : "r" (topOfProcStack) );
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Main Stack Pointer
|
||||
|
||||
This function returns the current value of the Main Stack Pointer (MSP).
|
||||
|
||||
\return MSP Register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_MSP(void)
|
||||
{
|
||||
register uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, msp\n" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Main Stack Pointer
|
||||
|
||||
This function assigns the given value to the Main Stack Pointer (MSP).
|
||||
|
||||
\param [in] topOfMainStack Main Stack Pointer value to set
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __set_MSP(uint32_t topOfMainStack)
|
||||
{
|
||||
__ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) );
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Priority Mask
|
||||
|
||||
This function returns the current state of the priority mask bit from the Priority Mask Register.
|
||||
|
||||
\return Priority Mask value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_PRIMASK(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, primask" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Priority Mask
|
||||
|
||||
This function assigns the given value to the Priority Mask Register.
|
||||
|
||||
\param [in] priMask Priority Mask
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __set_PRIMASK(uint32_t priMask)
|
||||
{
|
||||
__ASM volatile ("MSR primask, %0" : : "r" (priMask) );
|
||||
}
|
||||
|
||||
|
||||
#if (__CORTEX_M >= 0x03)
|
||||
|
||||
/** \brief Enable FIQ
|
||||
|
||||
This function enables FIQ interrupts by clearing the F-bit in the CPSR.
|
||||
Can only be executed in Privileged modes.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __enable_fault_irq(void)
|
||||
{
|
||||
__ASM volatile ("cpsie f");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Disable FIQ
|
||||
|
||||
This function disables FIQ interrupts by setting the F-bit in the CPSR.
|
||||
Can only be executed in Privileged modes.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __disable_fault_irq(void)
|
||||
{
|
||||
__ASM volatile ("cpsid f");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Base Priority
|
||||
|
||||
This function returns the current value of the Base Priority register.
|
||||
|
||||
\return Base Priority register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_BASEPRI(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, basepri_max" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Base Priority
|
||||
|
||||
This function assigns the given value to the Base Priority register.
|
||||
|
||||
\param [in] basePri Base Priority value to set
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __set_BASEPRI(uint32_t value)
|
||||
{
|
||||
__ASM volatile ("MSR basepri, %0" : : "r" (value) );
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Fault Mask
|
||||
|
||||
This function returns the current value of the Fault Mask register.
|
||||
|
||||
\return Fault Mask register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_FAULTMASK(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, faultmask" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Fault Mask
|
||||
|
||||
This function assigns the given value to the Fault Mask register.
|
||||
|
||||
\param [in] faultMask Fault Mask value to set
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __set_FAULTMASK(uint32_t faultMask)
|
||||
{
|
||||
__ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) );
|
||||
}
|
||||
|
||||
#endif /* (__CORTEX_M >= 0x03) */
|
||||
|
||||
|
||||
#if (__CORTEX_M == 0x04)
|
||||
|
||||
/** \brief Get FPSCR
|
||||
|
||||
This function returns the current value of the Floating Point Status/Control register.
|
||||
|
||||
\return Floating Point Status/Control register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_FPSCR(void)
|
||||
{
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("VMRS %0, fpscr" : "=r" (result) );
|
||||
return(result);
|
||||
#else
|
||||
return(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set FPSCR
|
||||
|
||||
This function assigns the given value to the Floating Point Status/Control register.
|
||||
|
||||
\param [in] fpscr Floating Point Status/Control value to set
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __set_FPSCR(uint32_t fpscr)
|
||||
{
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
__ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) );
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* (__CORTEX_M == 0x04) */
|
||||
|
||||
|
||||
#elif defined ( __TASKING__ ) /*------------------ TASKING Compiler --------------*/
|
||||
/* TASKING carm specific functions */
|
||||
|
||||
/*
|
||||
* The CMSIS functions have been implemented as intrinsics in the compiler.
|
||||
* Please use "carm -?i" to get an up to date list of all instrinsics,
|
||||
* Including the CMSIS ones.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
/*@} end of CMSIS_Core_RegAccFunctions */
|
||||
|
||||
|
||||
#endif /* __CORE_CMFUNC_H */
|
||||
585
lib/cmsis-sam3x8e/cmsis-include/core_cmInstr.h
Normal file
@@ -0,0 +1,585 @@
|
||||
/**************************************************************************//**
|
||||
* @file core_cmInstr.h
|
||||
* @brief CMSIS Cortex-M Core Instruction Access Header File
|
||||
* @version V2.10
|
||||
* @date 19. July 2011
|
||||
*
|
||||
* @note
|
||||
* Copyright (C) 2009-2011 ARM Limited. All rights reserved.
|
||||
*
|
||||
* @par
|
||||
* ARM Limited (ARM) is supplying this software for use with Cortex-M
|
||||
* processor based microcontrollers. This file can be freely distributed
|
||||
* within development tools that are supporting such ARM based processors.
|
||||
*
|
||||
* @par
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
|
||||
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __CORE_CMINSTR_H
|
||||
#define __CORE_CMINSTR_H
|
||||
|
||||
|
||||
/* ########################## Core Instruction Access ######################### */
|
||||
/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface
|
||||
Access to dedicated instructions
|
||||
@{
|
||||
*/
|
||||
|
||||
#if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/
|
||||
/* ARM armcc specific functions */
|
||||
|
||||
#if (__ARMCC_VERSION < 400677)
|
||||
#error "Please use ARM Compiler Toolchain V4.0.677 or later!"
|
||||
#endif
|
||||
|
||||
|
||||
/** \brief No Operation
|
||||
|
||||
No Operation does nothing. This instruction can be used for code alignment purposes.
|
||||
*/
|
||||
#define __NOP __nop
|
||||
|
||||
|
||||
/** \brief Wait For Interrupt
|
||||
|
||||
Wait For Interrupt is a hint instruction that suspends execution
|
||||
until one of a number of events occurs.
|
||||
*/
|
||||
#define __WFI __wfi
|
||||
|
||||
|
||||
/** \brief Wait For Event
|
||||
|
||||
Wait For Event is a hint instruction that permits the processor to enter
|
||||
a low-power state until one of a number of events occurs.
|
||||
*/
|
||||
#define __WFE __wfe
|
||||
|
||||
|
||||
/** \brief Send Event
|
||||
|
||||
Send Event is a hint instruction. It causes an event to be signaled to the CPU.
|
||||
*/
|
||||
#define __SEV __sev
|
||||
|
||||
|
||||
/** \brief Instruction Synchronization Barrier
|
||||
|
||||
Instruction Synchronization Barrier flushes the pipeline in the processor,
|
||||
so that all instructions following the ISB are fetched from cache or
|
||||
memory, after the instruction has been completed.
|
||||
*/
|
||||
#define __ISB() __isb(0xF)
|
||||
|
||||
|
||||
/** \brief Data Synchronization Barrier
|
||||
|
||||
This function acts as a special kind of Data Memory Barrier.
|
||||
It completes when all explicit memory accesses before this instruction complete.
|
||||
*/
|
||||
#define __DSB() __dsb(0xF)
|
||||
|
||||
|
||||
/** \brief Data Memory Barrier
|
||||
|
||||
This function ensures the apparent order of the explicit memory operations before
|
||||
and after the instruction, without ensuring their completion.
|
||||
*/
|
||||
#define __DMB() __dmb(0xF)
|
||||
|
||||
|
||||
/** \brief Reverse byte order (32 bit)
|
||||
|
||||
This function reverses the byte order in integer value.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
#define __REV __rev
|
||||
|
||||
|
||||
/** \brief Reverse byte order (16 bit)
|
||||
|
||||
This function reverses the byte order in two unsigned short values.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
static __INLINE __ASM uint32_t __REV16(uint32_t value)
|
||||
{
|
||||
rev16 r0, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
/** \brief Reverse byte order in signed short value
|
||||
|
||||
This function reverses the byte order in a signed short value with sign extension to integer.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
static __INLINE __ASM int32_t __REVSH(int32_t value)
|
||||
{
|
||||
revsh r0, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
#if (__CORTEX_M >= 0x03)
|
||||
|
||||
/** \brief Reverse bit order of value
|
||||
|
||||
This function reverses the bit order of the given value.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
#define __RBIT __rbit
|
||||
|
||||
|
||||
/** \brief LDR Exclusive (8 bit)
|
||||
|
||||
This function performs a exclusive LDR command for 8 bit value.
|
||||
|
||||
\param [in] ptr Pointer to data
|
||||
\return value of type uint8_t at (*ptr)
|
||||
*/
|
||||
#define __LDREXB(ptr) ((uint8_t ) __ldrex(ptr))
|
||||
|
||||
|
||||
/** \brief LDR Exclusive (16 bit)
|
||||
|
||||
This function performs a exclusive LDR command for 16 bit values.
|
||||
|
||||
\param [in] ptr Pointer to data
|
||||
\return value of type uint16_t at (*ptr)
|
||||
*/
|
||||
#define __LDREXH(ptr) ((uint16_t) __ldrex(ptr))
|
||||
|
||||
|
||||
/** \brief LDR Exclusive (32 bit)
|
||||
|
||||
This function performs a exclusive LDR command for 32 bit values.
|
||||
|
||||
\param [in] ptr Pointer to data
|
||||
\return value of type uint32_t at (*ptr)
|
||||
*/
|
||||
#define __LDREXW(ptr) ((uint32_t ) __ldrex(ptr))
|
||||
|
||||
|
||||
/** \brief STR Exclusive (8 bit)
|
||||
|
||||
This function performs a exclusive STR command for 8 bit values.
|
||||
|
||||
\param [in] value Value to store
|
||||
\param [in] ptr Pointer to location
|
||||
\return 0 Function succeeded
|
||||
\return 1 Function failed
|
||||
*/
|
||||
#define __STREXB(value, ptr) __strex(value, ptr)
|
||||
|
||||
|
||||
/** \brief STR Exclusive (16 bit)
|
||||
|
||||
This function performs a exclusive STR command for 16 bit values.
|
||||
|
||||
\param [in] value Value to store
|
||||
\param [in] ptr Pointer to location
|
||||
\return 0 Function succeeded
|
||||
\return 1 Function failed
|
||||
*/
|
||||
#define __STREXH(value, ptr) __strex(value, ptr)
|
||||
|
||||
|
||||
/** \brief STR Exclusive (32 bit)
|
||||
|
||||
This function performs a exclusive STR command for 32 bit values.
|
||||
|
||||
\param [in] value Value to store
|
||||
\param [in] ptr Pointer to location
|
||||
\return 0 Function succeeded
|
||||
\return 1 Function failed
|
||||
*/
|
||||
#define __STREXW(value, ptr) __strex(value, ptr)
|
||||
|
||||
|
||||
/** \brief Remove the exclusive lock
|
||||
|
||||
This function removes the exclusive lock which is created by LDREX.
|
||||
|
||||
*/
|
||||
#define __CLREX __clrex
|
||||
|
||||
|
||||
/** \brief Signed Saturate
|
||||
|
||||
This function saturates a signed value.
|
||||
|
||||
\param [in] value Value to be saturated
|
||||
\param [in] sat Bit position to saturate to (1..32)
|
||||
\return Saturated value
|
||||
*/
|
||||
#define __SSAT __ssat
|
||||
|
||||
|
||||
/** \brief Unsigned Saturate
|
||||
|
||||
This function saturates an unsigned value.
|
||||
|
||||
\param [in] value Value to be saturated
|
||||
\param [in] sat Bit position to saturate to (0..31)
|
||||
\return Saturated value
|
||||
*/
|
||||
#define __USAT __usat
|
||||
|
||||
|
||||
/** \brief Count leading zeros
|
||||
|
||||
This function counts the number of leading zeros of a data value.
|
||||
|
||||
\param [in] value Value to count the leading zeros
|
||||
\return number of leading zeros in value
|
||||
*/
|
||||
#define __CLZ __clz
|
||||
|
||||
#endif /* (__CORTEX_M >= 0x03) */
|
||||
|
||||
|
||||
|
||||
#elif defined ( __ICCARM__ ) /*------------------ ICC Compiler -------------------*/
|
||||
/* IAR iccarm specific functions */
|
||||
|
||||
#include <cmsis_iar.h>
|
||||
|
||||
|
||||
#elif defined ( __GNUC__ ) /*------------------ GNU Compiler ---------------------*/
|
||||
/* GNU gcc specific functions */
|
||||
|
||||
/** \brief No Operation
|
||||
|
||||
No Operation does nothing. This instruction can be used for code alignment purposes.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __NOP(void)
|
||||
{
|
||||
__ASM volatile ("nop");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Wait For Interrupt
|
||||
|
||||
Wait For Interrupt is a hint instruction that suspends execution
|
||||
until one of a number of events occurs.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __WFI(void)
|
||||
{
|
||||
__ASM volatile ("wfi");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Wait For Event
|
||||
|
||||
Wait For Event is a hint instruction that permits the processor to enter
|
||||
a low-power state until one of a number of events occurs.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __WFE(void)
|
||||
{
|
||||
__ASM volatile ("wfe");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Send Event
|
||||
|
||||
Send Event is a hint instruction. It causes an event to be signaled to the CPU.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __SEV(void)
|
||||
{
|
||||
__ASM volatile ("sev");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Instruction Synchronization Barrier
|
||||
|
||||
Instruction Synchronization Barrier flushes the pipeline in the processor,
|
||||
so that all instructions following the ISB are fetched from cache or
|
||||
memory, after the instruction has been completed.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __ISB(void)
|
||||
{
|
||||
__ASM volatile ("isb");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Data Synchronization Barrier
|
||||
|
||||
This function acts as a special kind of Data Memory Barrier.
|
||||
It completes when all explicit memory accesses before this instruction complete.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __DSB(void)
|
||||
{
|
||||
__ASM volatile ("dsb");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Data Memory Barrier
|
||||
|
||||
This function ensures the apparent order of the explicit memory operations before
|
||||
and after the instruction, without ensuring their completion.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __DMB(void)
|
||||
{
|
||||
__ASM volatile ("dmb");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Reverse byte order (32 bit)
|
||||
|
||||
This function reverses the byte order in integer value.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __REV(uint32_t value)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("rev %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Reverse byte order (16 bit)
|
||||
|
||||
This function reverses the byte order in two unsigned short values.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __REV16(uint32_t value)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("rev16 %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Reverse byte order in signed short value
|
||||
|
||||
This function reverses the byte order in a signed short value with sign extension to integer.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE int32_t __REVSH(int32_t value)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("revsh %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
#if (__CORTEX_M >= 0x03)
|
||||
|
||||
/** \brief Reverse bit order of value
|
||||
|
||||
This function reverses the bit order of the given value.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __RBIT(uint32_t value)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief LDR Exclusive (8 bit)
|
||||
|
||||
This function performs a exclusive LDR command for 8 bit value.
|
||||
|
||||
\param [in] ptr Pointer to data
|
||||
\return value of type uint8_t at (*ptr)
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint8_t __LDREXB(volatile uint8_t *addr)
|
||||
{
|
||||
uint8_t result;
|
||||
|
||||
__ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief LDR Exclusive (16 bit)
|
||||
|
||||
This function performs a exclusive LDR command for 16 bit values.
|
||||
|
||||
\param [in] ptr Pointer to data
|
||||
\return value of type uint16_t at (*ptr)
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint16_t __LDREXH(volatile uint16_t *addr)
|
||||
{
|
||||
uint16_t result;
|
||||
|
||||
__ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief LDR Exclusive (32 bit)
|
||||
|
||||
This function performs a exclusive LDR command for 32 bit values.
|
||||
|
||||
\param [in] ptr Pointer to data
|
||||
\return value of type uint32_t at (*ptr)
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __LDREXW(volatile uint32_t *addr)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("ldrex %0, [%1]" : "=r" (result) : "r" (addr) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief STR Exclusive (8 bit)
|
||||
|
||||
This function performs a exclusive STR command for 8 bit values.
|
||||
|
||||
\param [in] value Value to store
|
||||
\param [in] ptr Pointer to location
|
||||
\return 0 Function succeeded
|
||||
\return 1 Function failed
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("strexb %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief STR Exclusive (16 bit)
|
||||
|
||||
This function performs a exclusive STR command for 16 bit values.
|
||||
|
||||
\param [in] value Value to store
|
||||
\param [in] ptr Pointer to location
|
||||
\return 0 Function succeeded
|
||||
\return 1 Function failed
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief STR Exclusive (32 bit)
|
||||
|
||||
This function performs a exclusive STR command for 32 bit values.
|
||||
|
||||
\param [in] value Value to store
|
||||
\param [in] ptr Pointer to location
|
||||
\return 0 Function succeeded
|
||||
\return 1 Function failed
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("strex %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Remove the exclusive lock
|
||||
|
||||
This function removes the exclusive lock which is created by LDREX.
|
||||
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE void __CLREX(void)
|
||||
{
|
||||
__ASM volatile ("clrex");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Signed Saturate
|
||||
|
||||
This function saturates a signed value.
|
||||
|
||||
\param [in] value Value to be saturated
|
||||
\param [in] sat Bit position to saturate to (1..32)
|
||||
\return Saturated value
|
||||
*/
|
||||
#define __SSAT(ARG1,ARG2) \
|
||||
({ \
|
||||
uint32_t __RES, __ARG1 = (ARG1); \
|
||||
__ASM ("ssat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \
|
||||
__RES; \
|
||||
})
|
||||
|
||||
|
||||
/** \brief Unsigned Saturate
|
||||
|
||||
This function saturates an unsigned value.
|
||||
|
||||
\param [in] value Value to be saturated
|
||||
\param [in] sat Bit position to saturate to (0..31)
|
||||
\return Saturated value
|
||||
*/
|
||||
#define __USAT(ARG1,ARG2) \
|
||||
({ \
|
||||
uint32_t __RES, __ARG1 = (ARG1); \
|
||||
__ASM ("usat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \
|
||||
__RES; \
|
||||
})
|
||||
|
||||
|
||||
/** \brief Count leading zeros
|
||||
|
||||
This function counts the number of leading zeros of a data value.
|
||||
|
||||
\param [in] value Value to count the leading zeros
|
||||
\return number of leading zeros in value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) static __INLINE uint8_t __CLZ(uint32_t value)
|
||||
{
|
||||
uint8_t result;
|
||||
|
||||
__ASM volatile ("clz %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
#endif /* (__CORTEX_M >= 0x03) */
|
||||
|
||||
|
||||
|
||||
|
||||
#elif defined ( __TASKING__ ) /*------------------ TASKING Compiler --------------*/
|
||||
/* TASKING carm specific functions */
|
||||
|
||||
/*
|
||||
* The CMSIS functions have been implemented as intrinsics in the compiler.
|
||||
* Please use "carm -?i" to get an up to date list of all intrinsics,
|
||||
* Including the CMSIS ones.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
/*@}*/ /* end of group CMSIS_Core_InstructionInterface */
|
||||
|
||||
#endif /* __CORE_CMINSTR_H */
|
||||
11
lib/cmsis-sam3x8e/cmsis-sam3x8e.patch
Normal file
@@ -0,0 +1,11 @@
|
||||
--- source/gcc/startup_sam3xa.c.orig 2016-06-14 14:20:43.166209461 -0400
|
||||
+++ source/gcc/startup_sam3xa.c 2016-06-14 14:00:57.497137169 -0400
|
||||
@@ -129,7 +129,7 @@
|
||||
void CAN1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
|
||||
|
||||
/* Exception Table */
|
||||
-__attribute__ ((section(".vectors")))
|
||||
+__attribute__ ((section(".vectors"))) __attribute__((externally_visible))
|
||||
const DeviceVectors exception_table = {
|
||||
|
||||
/* Configure Initial Stack Pointer, using linker-generated symbols */
|
||||
504
lib/cmsis-sam3x8e/include/component/component_adc.h
Normal file
@@ -0,0 +1,504 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* SAM Software Package License
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2012, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following condition is met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _SAM3XA_ADC_COMPONENT_
|
||||
#define _SAM3XA_ADC_COMPONENT_
|
||||
|
||||
/* ============================================================================= */
|
||||
/** SOFTWARE API DEFINITION FOR Analog-to-digital Converter */
|
||||
/* ============================================================================= */
|
||||
/** \addtogroup SAM3XA_ADC Analog-to-digital Converter */
|
||||
/*@{*/
|
||||
|
||||
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
|
||||
/** \brief Adc hardware registers */
|
||||
typedef struct {
|
||||
WoReg ADC_CR; /**< \brief (Adc Offset: 0x00) Control Register */
|
||||
RwReg ADC_MR; /**< \brief (Adc Offset: 0x04) Mode Register */
|
||||
RwReg ADC_SEQR1; /**< \brief (Adc Offset: 0x08) Channel Sequence Register 1 */
|
||||
RwReg ADC_SEQR2; /**< \brief (Adc Offset: 0x0C) Channel Sequence Register 2 */
|
||||
WoReg ADC_CHER; /**< \brief (Adc Offset: 0x10) Channel Enable Register */
|
||||
WoReg ADC_CHDR; /**< \brief (Adc Offset: 0x14) Channel Disable Register */
|
||||
RoReg ADC_CHSR; /**< \brief (Adc Offset: 0x18) Channel Status Register */
|
||||
RoReg Reserved1[1];
|
||||
RoReg ADC_LCDR; /**< \brief (Adc Offset: 0x20) Last Converted Data Register */
|
||||
WoReg ADC_IER; /**< \brief (Adc Offset: 0x24) Interrupt Enable Register */
|
||||
WoReg ADC_IDR; /**< \brief (Adc Offset: 0x28) Interrupt Disable Register */
|
||||
RoReg ADC_IMR; /**< \brief (Adc Offset: 0x2C) Interrupt Mask Register */
|
||||
RoReg ADC_ISR; /**< \brief (Adc Offset: 0x30) Interrupt Status Register */
|
||||
RoReg Reserved2[2];
|
||||
RoReg ADC_OVER; /**< \brief (Adc Offset: 0x3C) Overrun Status Register */
|
||||
RwReg ADC_EMR; /**< \brief (Adc Offset: 0x40) Extended Mode Register */
|
||||
RwReg ADC_CWR; /**< \brief (Adc Offset: 0x44) Compare Window Register */
|
||||
RwReg ADC_CGR; /**< \brief (Adc Offset: 0x48) Channel Gain Register */
|
||||
RwReg ADC_COR; /**< \brief (Adc Offset: 0x4C) Channel Offset Register */
|
||||
RoReg ADC_CDR[16]; /**< \brief (Adc Offset: 0x50) Channel Data Register */
|
||||
RoReg Reserved3[1];
|
||||
RwReg ADC_ACR; /**< \brief (Adc Offset: 0x94) Analog Control Register */
|
||||
RoReg Reserved4[19];
|
||||
RwReg ADC_WPMR; /**< \brief (Adc Offset: 0xE4) Write Protect Mode Register */
|
||||
RoReg ADC_WPSR; /**< \brief (Adc Offset: 0xE8) Write Protect Status Register */
|
||||
RoReg Reserved5[5];
|
||||
RwReg ADC_RPR; /**< \brief (Adc Offset: 0x100) Receive Pointer Register */
|
||||
RwReg ADC_RCR; /**< \brief (Adc Offset: 0x104) Receive Counter Register */
|
||||
RoReg Reserved6[2];
|
||||
RwReg ADC_RNPR; /**< \brief (Adc Offset: 0x110) Receive Next Pointer Register */
|
||||
RwReg ADC_RNCR; /**< \brief (Adc Offset: 0x114) Receive Next Counter Register */
|
||||
RoReg Reserved7[2];
|
||||
WoReg ADC_PTCR; /**< \brief (Adc Offset: 0x120) Transfer Control Register */
|
||||
RoReg ADC_PTSR; /**< \brief (Adc Offset: 0x124) Transfer Status Register */
|
||||
} Adc;
|
||||
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
|
||||
/* -------- ADC_CR : (ADC Offset: 0x00) Control Register -------- */
|
||||
#define ADC_CR_SWRST (0x1u << 0) /**< \brief (ADC_CR) Software Reset */
|
||||
#define ADC_CR_START (0x1u << 1) /**< \brief (ADC_CR) Start Conversion */
|
||||
/* -------- ADC_MR : (ADC Offset: 0x04) Mode Register -------- */
|
||||
#define ADC_MR_TRGEN (0x1u << 0) /**< \brief (ADC_MR) Trigger Enable */
|
||||
#define ADC_MR_TRGEN_DIS (0x0u << 0) /**< \brief (ADC_MR) Hardware triggers are disabled. Starting a conversion is only possible by software. */
|
||||
#define ADC_MR_TRGEN_EN (0x1u << 0) /**< \brief (ADC_MR) Hardware trigger selected by TRGSEL field is enabled. */
|
||||
#define ADC_MR_TRGSEL_Pos 1
|
||||
#define ADC_MR_TRGSEL_Msk (0x7u << ADC_MR_TRGSEL_Pos) /**< \brief (ADC_MR) Trigger Selection */
|
||||
#define ADC_MR_TRGSEL_ADC_TRIG0 (0x0u << 1) /**< \brief (ADC_MR) External : ADCTRG */
|
||||
#define ADC_MR_TRGSEL_ADC_TRIG1 (0x1u << 1) /**< \brief (ADC_MR) TIOA Output of the Timer Counter Channel 0 */
|
||||
#define ADC_MR_TRGSEL_ADC_TRIG2 (0x2u << 1) /**< \brief (ADC_MR) TIOA Output of the Timer Counter Channel 1 */
|
||||
#define ADC_MR_TRGSEL_ADC_TRIG3 (0x3u << 1) /**< \brief (ADC_MR) TIOA Output of the Timer Counter Channel 2 */
|
||||
#define ADC_MR_TRGSEL_ADC_TRIG4 (0x4u << 1) /**< \brief (ADC_MR) PWM Event Line 0 */
|
||||
#define ADC_MR_TRGSEL_ADC_TRIG5 (0x5u << 1) /**< \brief (ADC_MR) PWM Event Line 0 */
|
||||
#define ADC_MR_LOWRES (0x1u << 4) /**< \brief (ADC_MR) Resolution */
|
||||
#define ADC_MR_LOWRES_BITS_12 (0x0u << 4) /**< \brief (ADC_MR) 12-bit resolution */
|
||||
#define ADC_MR_LOWRES_BITS_10 (0x1u << 4) /**< \brief (ADC_MR) 10-bit resolution */
|
||||
#define ADC_MR_SLEEP (0x1u << 5) /**< \brief (ADC_MR) Sleep Mode */
|
||||
#define ADC_MR_SLEEP_NORMAL (0x0u << 5) /**< \brief (ADC_MR) Normal Mode: The ADC Core and reference voltage circuitry are kept ON between conversions */
|
||||
#define ADC_MR_SLEEP_SLEEP (0x1u << 5) /**< \brief (ADC_MR) Sleep Mode: The ADC Core and reference voltage circuitry are OFF between conversions */
|
||||
#define ADC_MR_FWUP (0x1u << 6) /**< \brief (ADC_MR) Fast Wake Up */
|
||||
#define ADC_MR_FWUP_OFF (0x0u << 6) /**< \brief (ADC_MR) Normal Sleep Mode: The sleep mode is defined by the SLEEP bit */
|
||||
#define ADC_MR_FWUP_ON (0x1u << 6) /**< \brief (ADC_MR) Fast Wake Up Sleep Mode: The Voltage reference is ON between conversions and ADC Core is OFF */
|
||||
#define ADC_MR_FREERUN (0x1u << 7) /**< \brief (ADC_MR) Free Run Mode */
|
||||
#define ADC_MR_FREERUN_OFF (0x0u << 7) /**< \brief (ADC_MR) Normal Mode */
|
||||
#define ADC_MR_FREERUN_ON (0x1u << 7) /**< \brief (ADC_MR) Free Run Mode: Never wait for any trigger. */
|
||||
#define ADC_MR_PRESCAL_Pos 8
|
||||
#define ADC_MR_PRESCAL_Msk (0xffu << ADC_MR_PRESCAL_Pos) /**< \brief (ADC_MR) Prescaler Rate Selection */
|
||||
#define ADC_MR_PRESCAL(value) ((ADC_MR_PRESCAL_Msk & ((value) << ADC_MR_PRESCAL_Pos)))
|
||||
#define ADC_MR_STARTUP_Pos 16
|
||||
#define ADC_MR_STARTUP_Msk (0xfu << ADC_MR_STARTUP_Pos) /**< \brief (ADC_MR) Start Up Time */
|
||||
#define ADC_MR_STARTUP_SUT0 (0x0u << 16) /**< \brief (ADC_MR) 0 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT8 (0x1u << 16) /**< \brief (ADC_MR) 8 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT16 (0x2u << 16) /**< \brief (ADC_MR) 16 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT24 (0x3u << 16) /**< \brief (ADC_MR) 24 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT64 (0x4u << 16) /**< \brief (ADC_MR) 64 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT80 (0x5u << 16) /**< \brief (ADC_MR) 80 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT96 (0x6u << 16) /**< \brief (ADC_MR) 96 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT112 (0x7u << 16) /**< \brief (ADC_MR) 112 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT512 (0x8u << 16) /**< \brief (ADC_MR) 512 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT576 (0x9u << 16) /**< \brief (ADC_MR) 576 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT640 (0xAu << 16) /**< \brief (ADC_MR) 640 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT704 (0xBu << 16) /**< \brief (ADC_MR) 704 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT768 (0xCu << 16) /**< \brief (ADC_MR) 768 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT832 (0xDu << 16) /**< \brief (ADC_MR) 832 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT896 (0xEu << 16) /**< \brief (ADC_MR) 896 periods of ADCClock */
|
||||
#define ADC_MR_STARTUP_SUT960 (0xFu << 16) /**< \brief (ADC_MR) 960 periods of ADCClock */
|
||||
#define ADC_MR_SETTLING_Pos 20
|
||||
#define ADC_MR_SETTLING_Msk (0x3u << ADC_MR_SETTLING_Pos) /**< \brief (ADC_MR) Analog Settling Time */
|
||||
#define ADC_MR_SETTLING_AST3 (0x0u << 20) /**< \brief (ADC_MR) 3 periods of ADCClock */
|
||||
#define ADC_MR_SETTLING_AST5 (0x1u << 20) /**< \brief (ADC_MR) 5 periods of ADCClock */
|
||||
#define ADC_MR_SETTLING_AST9 (0x2u << 20) /**< \brief (ADC_MR) 9 periods of ADCClock */
|
||||
#define ADC_MR_SETTLING_AST17 (0x3u << 20) /**< \brief (ADC_MR) 17 periods of ADCClock */
|
||||
#define ADC_MR_ANACH (0x1u << 23) /**< \brief (ADC_MR) Analog Change */
|
||||
#define ADC_MR_ANACH_NONE (0x0u << 23) /**< \brief (ADC_MR) No analog change on channel switching: DIFF0, GAIN0 and OFF0 are used for all channels */
|
||||
#define ADC_MR_ANACH_ALLOWED (0x1u << 23) /**< \brief (ADC_MR) Allows different analog settings for each channel. See ADC_CGR and ADC_COR Registers */
|
||||
#define ADC_MR_TRACKTIM_Pos 24
|
||||
#define ADC_MR_TRACKTIM_Msk (0xfu << ADC_MR_TRACKTIM_Pos) /**< \brief (ADC_MR) Tracking Time */
|
||||
#define ADC_MR_TRACKTIM(value) ((ADC_MR_TRACKTIM_Msk & ((value) << ADC_MR_TRACKTIM_Pos)))
|
||||
#define ADC_MR_TRANSFER_Pos 28
|
||||
#define ADC_MR_TRANSFER_Msk (0x3u << ADC_MR_TRANSFER_Pos) /**< \brief (ADC_MR) Transfer Period */
|
||||
#define ADC_MR_TRANSFER(value) ((ADC_MR_TRANSFER_Msk & ((value) << ADC_MR_TRANSFER_Pos)))
|
||||
#define ADC_MR_USEQ (0x1u << 31) /**< \brief (ADC_MR) Use Sequence Enable */
|
||||
#define ADC_MR_USEQ_NUM_ORDER (0x0u << 31) /**< \brief (ADC_MR) Normal Mode: The controller converts channels in a simple numeric order. */
|
||||
#define ADC_MR_USEQ_REG_ORDER (0x1u << 31) /**< \brief (ADC_MR) User Sequence Mode: The sequence respects what is defined in ADC_SEQR1 and ADC_SEQR2 registers. */
|
||||
/* -------- ADC_SEQR1 : (ADC Offset: 0x08) Channel Sequence Register 1 -------- */
|
||||
#define ADC_SEQR1_USCH1_Pos 0
|
||||
#define ADC_SEQR1_USCH1_Msk (0xfu << ADC_SEQR1_USCH1_Pos) /**< \brief (ADC_SEQR1) User Sequence Number 1 */
|
||||
#define ADC_SEQR1_USCH1(value) ((ADC_SEQR1_USCH1_Msk & ((value) << ADC_SEQR1_USCH1_Pos)))
|
||||
#define ADC_SEQR1_USCH2_Pos 4
|
||||
#define ADC_SEQR1_USCH2_Msk (0xfu << ADC_SEQR1_USCH2_Pos) /**< \brief (ADC_SEQR1) User Sequence Number 2 */
|
||||
#define ADC_SEQR1_USCH2(value) ((ADC_SEQR1_USCH2_Msk & ((value) << ADC_SEQR1_USCH2_Pos)))
|
||||
#define ADC_SEQR1_USCH3_Pos 8
|
||||
#define ADC_SEQR1_USCH3_Msk (0xfu << ADC_SEQR1_USCH3_Pos) /**< \brief (ADC_SEQR1) User Sequence Number 3 */
|
||||
#define ADC_SEQR1_USCH3(value) ((ADC_SEQR1_USCH3_Msk & ((value) << ADC_SEQR1_USCH3_Pos)))
|
||||
#define ADC_SEQR1_USCH4_Pos 12
|
||||
#define ADC_SEQR1_USCH4_Msk (0xfu << ADC_SEQR1_USCH4_Pos) /**< \brief (ADC_SEQR1) User Sequence Number 4 */
|
||||
#define ADC_SEQR1_USCH4(value) ((ADC_SEQR1_USCH4_Msk & ((value) << ADC_SEQR1_USCH4_Pos)))
|
||||
#define ADC_SEQR1_USCH5_Pos 16
|
||||
#define ADC_SEQR1_USCH5_Msk (0xfu << ADC_SEQR1_USCH5_Pos) /**< \brief (ADC_SEQR1) User Sequence Number 5 */
|
||||
#define ADC_SEQR1_USCH5(value) ((ADC_SEQR1_USCH5_Msk & ((value) << ADC_SEQR1_USCH5_Pos)))
|
||||
#define ADC_SEQR1_USCH6_Pos 20
|
||||
#define ADC_SEQR1_USCH6_Msk (0xfu << ADC_SEQR1_USCH6_Pos) /**< \brief (ADC_SEQR1) User Sequence Number 6 */
|
||||
#define ADC_SEQR1_USCH6(value) ((ADC_SEQR1_USCH6_Msk & ((value) << ADC_SEQR1_USCH6_Pos)))
|
||||
#define ADC_SEQR1_USCH7_Pos 24
|
||||
#define ADC_SEQR1_USCH7_Msk (0xfu << ADC_SEQR1_USCH7_Pos) /**< \brief (ADC_SEQR1) User Sequence Number 7 */
|
||||
#define ADC_SEQR1_USCH7(value) ((ADC_SEQR1_USCH7_Msk & ((value) << ADC_SEQR1_USCH7_Pos)))
|
||||
#define ADC_SEQR1_USCH8_Pos 28
|
||||
#define ADC_SEQR1_USCH8_Msk (0xfu << ADC_SEQR1_USCH8_Pos) /**< \brief (ADC_SEQR1) User Sequence Number 8 */
|
||||
#define ADC_SEQR1_USCH8(value) ((ADC_SEQR1_USCH8_Msk & ((value) << ADC_SEQR1_USCH8_Pos)))
|
||||
/* -------- ADC_SEQR2 : (ADC Offset: 0x0C) Channel Sequence Register 2 -------- */
|
||||
#define ADC_SEQR2_USCH9_Pos 0
|
||||
#define ADC_SEQR2_USCH9_Msk (0xfu << ADC_SEQR2_USCH9_Pos) /**< \brief (ADC_SEQR2) User Sequence Number 9 */
|
||||
#define ADC_SEQR2_USCH9(value) ((ADC_SEQR2_USCH9_Msk & ((value) << ADC_SEQR2_USCH9_Pos)))
|
||||
#define ADC_SEQR2_USCH10_Pos 4
|
||||
#define ADC_SEQR2_USCH10_Msk (0xfu << ADC_SEQR2_USCH10_Pos) /**< \brief (ADC_SEQR2) User Sequence Number 10 */
|
||||
#define ADC_SEQR2_USCH10(value) ((ADC_SEQR2_USCH10_Msk & ((value) << ADC_SEQR2_USCH10_Pos)))
|
||||
#define ADC_SEQR2_USCH11_Pos 8
|
||||
#define ADC_SEQR2_USCH11_Msk (0xfu << ADC_SEQR2_USCH11_Pos) /**< \brief (ADC_SEQR2) User Sequence Number 11 */
|
||||
#define ADC_SEQR2_USCH11(value) ((ADC_SEQR2_USCH11_Msk & ((value) << ADC_SEQR2_USCH11_Pos)))
|
||||
#define ADC_SEQR2_USCH12_Pos 12
|
||||
#define ADC_SEQR2_USCH12_Msk (0xfu << ADC_SEQR2_USCH12_Pos) /**< \brief (ADC_SEQR2) User Sequence Number 12 */
|
||||
#define ADC_SEQR2_USCH12(value) ((ADC_SEQR2_USCH12_Msk & ((value) << ADC_SEQR2_USCH12_Pos)))
|
||||
#define ADC_SEQR2_USCH13_Pos 16
|
||||
#define ADC_SEQR2_USCH13_Msk (0xfu << ADC_SEQR2_USCH13_Pos) /**< \brief (ADC_SEQR2) User Sequence Number 13 */
|
||||
#define ADC_SEQR2_USCH13(value) ((ADC_SEQR2_USCH13_Msk & ((value) << ADC_SEQR2_USCH13_Pos)))
|
||||
#define ADC_SEQR2_USCH14_Pos 20
|
||||
#define ADC_SEQR2_USCH14_Msk (0xfu << ADC_SEQR2_USCH14_Pos) /**< \brief (ADC_SEQR2) User Sequence Number 14 */
|
||||
#define ADC_SEQR2_USCH14(value) ((ADC_SEQR2_USCH14_Msk & ((value) << ADC_SEQR2_USCH14_Pos)))
|
||||
#define ADC_SEQR2_USCH15_Pos 24
|
||||
#define ADC_SEQR2_USCH15_Msk (0xfu << ADC_SEQR2_USCH15_Pos) /**< \brief (ADC_SEQR2) User Sequence Number 15 */
|
||||
#define ADC_SEQR2_USCH15(value) ((ADC_SEQR2_USCH15_Msk & ((value) << ADC_SEQR2_USCH15_Pos)))
|
||||
#define ADC_SEQR2_USCH16_Pos 28
|
||||
#define ADC_SEQR2_USCH16_Msk (0xfu << ADC_SEQR2_USCH16_Pos) /**< \brief (ADC_SEQR2) User Sequence Number 16 */
|
||||
#define ADC_SEQR2_USCH16(value) ((ADC_SEQR2_USCH16_Msk & ((value) << ADC_SEQR2_USCH16_Pos)))
|
||||
/* -------- ADC_CHER : (ADC Offset: 0x10) Channel Enable Register -------- */
|
||||
#define ADC_CHER_CH0 (0x1u << 0) /**< \brief (ADC_CHER) Channel 0 Enable */
|
||||
#define ADC_CHER_CH1 (0x1u << 1) /**< \brief (ADC_CHER) Channel 1 Enable */
|
||||
#define ADC_CHER_CH2 (0x1u << 2) /**< \brief (ADC_CHER) Channel 2 Enable */
|
||||
#define ADC_CHER_CH3 (0x1u << 3) /**< \brief (ADC_CHER) Channel 3 Enable */
|
||||
#define ADC_CHER_CH4 (0x1u << 4) /**< \brief (ADC_CHER) Channel 4 Enable */
|
||||
#define ADC_CHER_CH5 (0x1u << 5) /**< \brief (ADC_CHER) Channel 5 Enable */
|
||||
#define ADC_CHER_CH6 (0x1u << 6) /**< \brief (ADC_CHER) Channel 6 Enable */
|
||||
#define ADC_CHER_CH7 (0x1u << 7) /**< \brief (ADC_CHER) Channel 7 Enable */
|
||||
#define ADC_CHER_CH8 (0x1u << 8) /**< \brief (ADC_CHER) Channel 8 Enable */
|
||||
#define ADC_CHER_CH9 (0x1u << 9) /**< \brief (ADC_CHER) Channel 9 Enable */
|
||||
#define ADC_CHER_CH10 (0x1u << 10) /**< \brief (ADC_CHER) Channel 10 Enable */
|
||||
#define ADC_CHER_CH11 (0x1u << 11) /**< \brief (ADC_CHER) Channel 11 Enable */
|
||||
#define ADC_CHER_CH12 (0x1u << 12) /**< \brief (ADC_CHER) Channel 12 Enable */
|
||||
#define ADC_CHER_CH13 (0x1u << 13) /**< \brief (ADC_CHER) Channel 13 Enable */
|
||||
#define ADC_CHER_CH14 (0x1u << 14) /**< \brief (ADC_CHER) Channel 14 Enable */
|
||||
#define ADC_CHER_CH15 (0x1u << 15) /**< \brief (ADC_CHER) Channel 15 Enable */
|
||||
/* -------- ADC_CHDR : (ADC Offset: 0x14) Channel Disable Register -------- */
|
||||
#define ADC_CHDR_CH0 (0x1u << 0) /**< \brief (ADC_CHDR) Channel 0 Disable */
|
||||
#define ADC_CHDR_CH1 (0x1u << 1) /**< \brief (ADC_CHDR) Channel 1 Disable */
|
||||
#define ADC_CHDR_CH2 (0x1u << 2) /**< \brief (ADC_CHDR) Channel 2 Disable */
|
||||
#define ADC_CHDR_CH3 (0x1u << 3) /**< \brief (ADC_CHDR) Channel 3 Disable */
|
||||
#define ADC_CHDR_CH4 (0x1u << 4) /**< \brief (ADC_CHDR) Channel 4 Disable */
|
||||
#define ADC_CHDR_CH5 (0x1u << 5) /**< \brief (ADC_CHDR) Channel 5 Disable */
|
||||
#define ADC_CHDR_CH6 (0x1u << 6) /**< \brief (ADC_CHDR) Channel 6 Disable */
|
||||
#define ADC_CHDR_CH7 (0x1u << 7) /**< \brief (ADC_CHDR) Channel 7 Disable */
|
||||
#define ADC_CHDR_CH8 (0x1u << 8) /**< \brief (ADC_CHDR) Channel 8 Disable */
|
||||
#define ADC_CHDR_CH9 (0x1u << 9) /**< \brief (ADC_CHDR) Channel 9 Disable */
|
||||
#define ADC_CHDR_CH10 (0x1u << 10) /**< \brief (ADC_CHDR) Channel 10 Disable */
|
||||
#define ADC_CHDR_CH11 (0x1u << 11) /**< \brief (ADC_CHDR) Channel 11 Disable */
|
||||
#define ADC_CHDR_CH12 (0x1u << 12) /**< \brief (ADC_CHDR) Channel 12 Disable */
|
||||
#define ADC_CHDR_CH13 (0x1u << 13) /**< \brief (ADC_CHDR) Channel 13 Disable */
|
||||
#define ADC_CHDR_CH14 (0x1u << 14) /**< \brief (ADC_CHDR) Channel 14 Disable */
|
||||
#define ADC_CHDR_CH15 (0x1u << 15) /**< \brief (ADC_CHDR) Channel 15 Disable */
|
||||
/* -------- ADC_CHSR : (ADC Offset: 0x18) Channel Status Register -------- */
|
||||
#define ADC_CHSR_CH0 (0x1u << 0) /**< \brief (ADC_CHSR) Channel 0 Status */
|
||||
#define ADC_CHSR_CH1 (0x1u << 1) /**< \brief (ADC_CHSR) Channel 1 Status */
|
||||
#define ADC_CHSR_CH2 (0x1u << 2) /**< \brief (ADC_CHSR) Channel 2 Status */
|
||||
#define ADC_CHSR_CH3 (0x1u << 3) /**< \brief (ADC_CHSR) Channel 3 Status */
|
||||
#define ADC_CHSR_CH4 (0x1u << 4) /**< \brief (ADC_CHSR) Channel 4 Status */
|
||||
#define ADC_CHSR_CH5 (0x1u << 5) /**< \brief (ADC_CHSR) Channel 5 Status */
|
||||
#define ADC_CHSR_CH6 (0x1u << 6) /**< \brief (ADC_CHSR) Channel 6 Status */
|
||||
#define ADC_CHSR_CH7 (0x1u << 7) /**< \brief (ADC_CHSR) Channel 7 Status */
|
||||
#define ADC_CHSR_CH8 (0x1u << 8) /**< \brief (ADC_CHSR) Channel 8 Status */
|
||||
#define ADC_CHSR_CH9 (0x1u << 9) /**< \brief (ADC_CHSR) Channel 9 Status */
|
||||
#define ADC_CHSR_CH10 (0x1u << 10) /**< \brief (ADC_CHSR) Channel 10 Status */
|
||||
#define ADC_CHSR_CH11 (0x1u << 11) /**< \brief (ADC_CHSR) Channel 11 Status */
|
||||
#define ADC_CHSR_CH12 (0x1u << 12) /**< \brief (ADC_CHSR) Channel 12 Status */
|
||||
#define ADC_CHSR_CH13 (0x1u << 13) /**< \brief (ADC_CHSR) Channel 13 Status */
|
||||
#define ADC_CHSR_CH14 (0x1u << 14) /**< \brief (ADC_CHSR) Channel 14 Status */
|
||||
#define ADC_CHSR_CH15 (0x1u << 15) /**< \brief (ADC_CHSR) Channel 15 Status */
|
||||
/* -------- ADC_LCDR : (ADC Offset: 0x20) Last Converted Data Register -------- */
|
||||
#define ADC_LCDR_LDATA_Pos 0
|
||||
#define ADC_LCDR_LDATA_Msk (0xfffu << ADC_LCDR_LDATA_Pos) /**< \brief (ADC_LCDR) Last Data Converted */
|
||||
#define ADC_LCDR_CHNB_Pos 12
|
||||
#define ADC_LCDR_CHNB_Msk (0xfu << ADC_LCDR_CHNB_Pos) /**< \brief (ADC_LCDR) Channel Number */
|
||||
/* -------- ADC_IER : (ADC Offset: 0x24) Interrupt Enable Register -------- */
|
||||
#define ADC_IER_EOC0 (0x1u << 0) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 0 */
|
||||
#define ADC_IER_EOC1 (0x1u << 1) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 1 */
|
||||
#define ADC_IER_EOC2 (0x1u << 2) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 2 */
|
||||
#define ADC_IER_EOC3 (0x1u << 3) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 3 */
|
||||
#define ADC_IER_EOC4 (0x1u << 4) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 4 */
|
||||
#define ADC_IER_EOC5 (0x1u << 5) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 5 */
|
||||
#define ADC_IER_EOC6 (0x1u << 6) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 6 */
|
||||
#define ADC_IER_EOC7 (0x1u << 7) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 7 */
|
||||
#define ADC_IER_EOC8 (0x1u << 8) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 8 */
|
||||
#define ADC_IER_EOC9 (0x1u << 9) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 9 */
|
||||
#define ADC_IER_EOC10 (0x1u << 10) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 10 */
|
||||
#define ADC_IER_EOC11 (0x1u << 11) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 11 */
|
||||
#define ADC_IER_EOC12 (0x1u << 12) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 12 */
|
||||
#define ADC_IER_EOC13 (0x1u << 13) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 13 */
|
||||
#define ADC_IER_EOC14 (0x1u << 14) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 14 */
|
||||
#define ADC_IER_EOC15 (0x1u << 15) /**< \brief (ADC_IER) End of Conversion Interrupt Enable 15 */
|
||||
#define ADC_IER_DRDY (0x1u << 24) /**< \brief (ADC_IER) Data Ready Interrupt Enable */
|
||||
#define ADC_IER_GOVRE (0x1u << 25) /**< \brief (ADC_IER) General Overrun Error Interrupt Enable */
|
||||
#define ADC_IER_COMPE (0x1u << 26) /**< \brief (ADC_IER) Comparison Event Interrupt Enable */
|
||||
#define ADC_IER_ENDRX (0x1u << 27) /**< \brief (ADC_IER) End of Receive Buffer Interrupt Enable */
|
||||
#define ADC_IER_RXBUFF (0x1u << 28) /**< \brief (ADC_IER) Receive Buffer Full Interrupt Enable */
|
||||
/* -------- ADC_IDR : (ADC Offset: 0x28) Interrupt Disable Register -------- */
|
||||
#define ADC_IDR_EOC0 (0x1u << 0) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 0 */
|
||||
#define ADC_IDR_EOC1 (0x1u << 1) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 1 */
|
||||
#define ADC_IDR_EOC2 (0x1u << 2) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 2 */
|
||||
#define ADC_IDR_EOC3 (0x1u << 3) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 3 */
|
||||
#define ADC_IDR_EOC4 (0x1u << 4) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 4 */
|
||||
#define ADC_IDR_EOC5 (0x1u << 5) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 5 */
|
||||
#define ADC_IDR_EOC6 (0x1u << 6) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 6 */
|
||||
#define ADC_IDR_EOC7 (0x1u << 7) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 7 */
|
||||
#define ADC_IDR_EOC8 (0x1u << 8) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 8 */
|
||||
#define ADC_IDR_EOC9 (0x1u << 9) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 9 */
|
||||
#define ADC_IDR_EOC10 (0x1u << 10) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 10 */
|
||||
#define ADC_IDR_EOC11 (0x1u << 11) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 11 */
|
||||
#define ADC_IDR_EOC12 (0x1u << 12) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 12 */
|
||||
#define ADC_IDR_EOC13 (0x1u << 13) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 13 */
|
||||
#define ADC_IDR_EOC14 (0x1u << 14) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 14 */
|
||||
#define ADC_IDR_EOC15 (0x1u << 15) /**< \brief (ADC_IDR) End of Conversion Interrupt Disable 15 */
|
||||
#define ADC_IDR_DRDY (0x1u << 24) /**< \brief (ADC_IDR) Data Ready Interrupt Disable */
|
||||
#define ADC_IDR_GOVRE (0x1u << 25) /**< \brief (ADC_IDR) General Overrun Error Interrupt Disable */
|
||||
#define ADC_IDR_COMPE (0x1u << 26) /**< \brief (ADC_IDR) Comparison Event Interrupt Disable */
|
||||
#define ADC_IDR_ENDRX (0x1u << 27) /**< \brief (ADC_IDR) End of Receive Buffer Interrupt Disable */
|
||||
#define ADC_IDR_RXBUFF (0x1u << 28) /**< \brief (ADC_IDR) Receive Buffer Full Interrupt Disable */
|
||||
/* -------- ADC_IMR : (ADC Offset: 0x2C) Interrupt Mask Register -------- */
|
||||
#define ADC_IMR_EOC0 (0x1u << 0) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 0 */
|
||||
#define ADC_IMR_EOC1 (0x1u << 1) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 1 */
|
||||
#define ADC_IMR_EOC2 (0x1u << 2) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 2 */
|
||||
#define ADC_IMR_EOC3 (0x1u << 3) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 3 */
|
||||
#define ADC_IMR_EOC4 (0x1u << 4) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 4 */
|
||||
#define ADC_IMR_EOC5 (0x1u << 5) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 5 */
|
||||
#define ADC_IMR_EOC6 (0x1u << 6) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 6 */
|
||||
#define ADC_IMR_EOC7 (0x1u << 7) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 7 */
|
||||
#define ADC_IMR_EOC8 (0x1u << 8) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 8 */
|
||||
#define ADC_IMR_EOC9 (0x1u << 9) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 9 */
|
||||
#define ADC_IMR_EOC10 (0x1u << 10) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 10 */
|
||||
#define ADC_IMR_EOC11 (0x1u << 11) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 11 */
|
||||
#define ADC_IMR_EOC12 (0x1u << 12) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 12 */
|
||||
#define ADC_IMR_EOC13 (0x1u << 13) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 13 */
|
||||
#define ADC_IMR_EOC14 (0x1u << 14) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 14 */
|
||||
#define ADC_IMR_EOC15 (0x1u << 15) /**< \brief (ADC_IMR) End of Conversion Interrupt Mask 15 */
|
||||
#define ADC_IMR_DRDY (0x1u << 24) /**< \brief (ADC_IMR) Data Ready Interrupt Mask */
|
||||
#define ADC_IMR_GOVRE (0x1u << 25) /**< \brief (ADC_IMR) General Overrun Error Interrupt Mask */
|
||||
#define ADC_IMR_COMPE (0x1u << 26) /**< \brief (ADC_IMR) Comparison Event Interrupt Mask */
|
||||
#define ADC_IMR_ENDRX (0x1u << 27) /**< \brief (ADC_IMR) End of Receive Buffer Interrupt Mask */
|
||||
#define ADC_IMR_RXBUFF (0x1u << 28) /**< \brief (ADC_IMR) Receive Buffer Full Interrupt Mask */
|
||||
/* -------- ADC_ISR : (ADC Offset: 0x30) Interrupt Status Register -------- */
|
||||
#define ADC_ISR_EOC0 (0x1u << 0) /**< \brief (ADC_ISR) End of Conversion 0 */
|
||||
#define ADC_ISR_EOC1 (0x1u << 1) /**< \brief (ADC_ISR) End of Conversion 1 */
|
||||
#define ADC_ISR_EOC2 (0x1u << 2) /**< \brief (ADC_ISR) End of Conversion 2 */
|
||||
#define ADC_ISR_EOC3 (0x1u << 3) /**< \brief (ADC_ISR) End of Conversion 3 */
|
||||
#define ADC_ISR_EOC4 (0x1u << 4) /**< \brief (ADC_ISR) End of Conversion 4 */
|
||||
#define ADC_ISR_EOC5 (0x1u << 5) /**< \brief (ADC_ISR) End of Conversion 5 */
|
||||
#define ADC_ISR_EOC6 (0x1u << 6) /**< \brief (ADC_ISR) End of Conversion 6 */
|
||||
#define ADC_ISR_EOC7 (0x1u << 7) /**< \brief (ADC_ISR) End of Conversion 7 */
|
||||
#define ADC_ISR_EOC8 (0x1u << 8) /**< \brief (ADC_ISR) End of Conversion 8 */
|
||||
#define ADC_ISR_EOC9 (0x1u << 9) /**< \brief (ADC_ISR) End of Conversion 9 */
|
||||
#define ADC_ISR_EOC10 (0x1u << 10) /**< \brief (ADC_ISR) End of Conversion 10 */
|
||||
#define ADC_ISR_EOC11 (0x1u << 11) /**< \brief (ADC_ISR) End of Conversion 11 */
|
||||
#define ADC_ISR_EOC12 (0x1u << 12) /**< \brief (ADC_ISR) End of Conversion 12 */
|
||||
#define ADC_ISR_EOC13 (0x1u << 13) /**< \brief (ADC_ISR) End of Conversion 13 */
|
||||
#define ADC_ISR_EOC14 (0x1u << 14) /**< \brief (ADC_ISR) End of Conversion 14 */
|
||||
#define ADC_ISR_EOC15 (0x1u << 15) /**< \brief (ADC_ISR) End of Conversion 15 */
|
||||
#define ADC_ISR_DRDY (0x1u << 24) /**< \brief (ADC_ISR) Data Ready */
|
||||
#define ADC_ISR_GOVRE (0x1u << 25) /**< \brief (ADC_ISR) General Overrun Error */
|
||||
#define ADC_ISR_COMPE (0x1u << 26) /**< \brief (ADC_ISR) Comparison Error */
|
||||
#define ADC_ISR_ENDRX (0x1u << 27) /**< \brief (ADC_ISR) End of RX Buffer */
|
||||
#define ADC_ISR_RXBUFF (0x1u << 28) /**< \brief (ADC_ISR) RX Buffer Full */
|
||||
/* -------- ADC_OVER : (ADC Offset: 0x3C) Overrun Status Register -------- */
|
||||
#define ADC_OVER_OVRE0 (0x1u << 0) /**< \brief (ADC_OVER) Overrun Error 0 */
|
||||
#define ADC_OVER_OVRE1 (0x1u << 1) /**< \brief (ADC_OVER) Overrun Error 1 */
|
||||
#define ADC_OVER_OVRE2 (0x1u << 2) /**< \brief (ADC_OVER) Overrun Error 2 */
|
||||
#define ADC_OVER_OVRE3 (0x1u << 3) /**< \brief (ADC_OVER) Overrun Error 3 */
|
||||
#define ADC_OVER_OVRE4 (0x1u << 4) /**< \brief (ADC_OVER) Overrun Error 4 */
|
||||
#define ADC_OVER_OVRE5 (0x1u << 5) /**< \brief (ADC_OVER) Overrun Error 5 */
|
||||
#define ADC_OVER_OVRE6 (0x1u << 6) /**< \brief (ADC_OVER) Overrun Error 6 */
|
||||
#define ADC_OVER_OVRE7 (0x1u << 7) /**< \brief (ADC_OVER) Overrun Error 7 */
|
||||
#define ADC_OVER_OVRE8 (0x1u << 8) /**< \brief (ADC_OVER) Overrun Error 8 */
|
||||
#define ADC_OVER_OVRE9 (0x1u << 9) /**< \brief (ADC_OVER) Overrun Error 9 */
|
||||
#define ADC_OVER_OVRE10 (0x1u << 10) /**< \brief (ADC_OVER) Overrun Error 10 */
|
||||
#define ADC_OVER_OVRE11 (0x1u << 11) /**< \brief (ADC_OVER) Overrun Error 11 */
|
||||
#define ADC_OVER_OVRE12 (0x1u << 12) /**< \brief (ADC_OVER) Overrun Error 12 */
|
||||
#define ADC_OVER_OVRE13 (0x1u << 13) /**< \brief (ADC_OVER) Overrun Error 13 */
|
||||
#define ADC_OVER_OVRE14 (0x1u << 14) /**< \brief (ADC_OVER) Overrun Error 14 */
|
||||
#define ADC_OVER_OVRE15 (0x1u << 15) /**< \brief (ADC_OVER) Overrun Error 15 */
|
||||
/* -------- ADC_EMR : (ADC Offset: 0x40) Extended Mode Register -------- */
|
||||
#define ADC_EMR_CMPMODE_Pos 0
|
||||
#define ADC_EMR_CMPMODE_Msk (0x3u << ADC_EMR_CMPMODE_Pos) /**< \brief (ADC_EMR) Comparison Mode */
|
||||
#define ADC_EMR_CMPMODE_LOW (0x0u << 0) /**< \brief (ADC_EMR) Generates an event when the converted data is lower than the low threshold of the window. */
|
||||
#define ADC_EMR_CMPMODE_HIGH (0x1u << 0) /**< \brief (ADC_EMR) Generates an event when the converted data is higher than the high threshold of the window. */
|
||||
#define ADC_EMR_CMPMODE_IN (0x2u << 0) /**< \brief (ADC_EMR) Generates an event when the converted data is in the comparison window. */
|
||||
#define ADC_EMR_CMPMODE_OUT (0x3u << 0) /**< \brief (ADC_EMR) Generates an event when the converted data is out of the comparison window. */
|
||||
#define ADC_EMR_CMPSEL_Pos 4
|
||||
#define ADC_EMR_CMPSEL_Msk (0xfu << ADC_EMR_CMPSEL_Pos) /**< \brief (ADC_EMR) Comparison Selected Channel */
|
||||
#define ADC_EMR_CMPSEL(value) ((ADC_EMR_CMPSEL_Msk & ((value) << ADC_EMR_CMPSEL_Pos)))
|
||||
#define ADC_EMR_CMPALL (0x1u << 9) /**< \brief (ADC_EMR) Compare All Channels */
|
||||
#define ADC_EMR_CMPFILTER_Pos 12
|
||||
#define ADC_EMR_CMPFILTER_Msk (0x3u << ADC_EMR_CMPFILTER_Pos) /**< \brief (ADC_EMR) Compare Event Filtering */
|
||||
#define ADC_EMR_CMPFILTER(value) ((ADC_EMR_CMPFILTER_Msk & ((value) << ADC_EMR_CMPFILTER_Pos)))
|
||||
#define ADC_EMR_TAG (0x1u << 24) /**< \brief (ADC_EMR) TAG of ADC_LDCR register */
|
||||
/* -------- ADC_CWR : (ADC Offset: 0x44) Compare Window Register -------- */
|
||||
#define ADC_CWR_LOWTHRES_Pos 0
|
||||
#define ADC_CWR_LOWTHRES_Msk (0xfffu << ADC_CWR_LOWTHRES_Pos) /**< \brief (ADC_CWR) Low Threshold */
|
||||
#define ADC_CWR_LOWTHRES(value) ((ADC_CWR_LOWTHRES_Msk & ((value) << ADC_CWR_LOWTHRES_Pos)))
|
||||
#define ADC_CWR_HIGHTHRES_Pos 16
|
||||
#define ADC_CWR_HIGHTHRES_Msk (0xfffu << ADC_CWR_HIGHTHRES_Pos) /**< \brief (ADC_CWR) High Threshold */
|
||||
#define ADC_CWR_HIGHTHRES(value) ((ADC_CWR_HIGHTHRES_Msk & ((value) << ADC_CWR_HIGHTHRES_Pos)))
|
||||
/* -------- ADC_CGR : (ADC Offset: 0x48) Channel Gain Register -------- */
|
||||
#define ADC_CGR_GAIN0_Pos 0
|
||||
#define ADC_CGR_GAIN0_Msk (0x3u << ADC_CGR_GAIN0_Pos) /**< \brief (ADC_CGR) Gain for channel 0 */
|
||||
#define ADC_CGR_GAIN0(value) ((ADC_CGR_GAIN0_Msk & ((value) << ADC_CGR_GAIN0_Pos)))
|
||||
#define ADC_CGR_GAIN1_Pos 2
|
||||
#define ADC_CGR_GAIN1_Msk (0x3u << ADC_CGR_GAIN1_Pos) /**< \brief (ADC_CGR) Gain for channel 1 */
|
||||
#define ADC_CGR_GAIN1(value) ((ADC_CGR_GAIN1_Msk & ((value) << ADC_CGR_GAIN1_Pos)))
|
||||
#define ADC_CGR_GAIN2_Pos 4
|
||||
#define ADC_CGR_GAIN2_Msk (0x3u << ADC_CGR_GAIN2_Pos) /**< \brief (ADC_CGR) Gain for channel 2 */
|
||||
#define ADC_CGR_GAIN2(value) ((ADC_CGR_GAIN2_Msk & ((value) << ADC_CGR_GAIN2_Pos)))
|
||||
#define ADC_CGR_GAIN3_Pos 6
|
||||
#define ADC_CGR_GAIN3_Msk (0x3u << ADC_CGR_GAIN3_Pos) /**< \brief (ADC_CGR) Gain for channel 3 */
|
||||
#define ADC_CGR_GAIN3(value) ((ADC_CGR_GAIN3_Msk & ((value) << ADC_CGR_GAIN3_Pos)))
|
||||
#define ADC_CGR_GAIN4_Pos 8
|
||||
#define ADC_CGR_GAIN4_Msk (0x3u << ADC_CGR_GAIN4_Pos) /**< \brief (ADC_CGR) Gain for channel 4 */
|
||||
#define ADC_CGR_GAIN4(value) ((ADC_CGR_GAIN4_Msk & ((value) << ADC_CGR_GAIN4_Pos)))
|
||||
#define ADC_CGR_GAIN5_Pos 10
|
||||
#define ADC_CGR_GAIN5_Msk (0x3u << ADC_CGR_GAIN5_Pos) /**< \brief (ADC_CGR) Gain for channel 5 */
|
||||
#define ADC_CGR_GAIN5(value) ((ADC_CGR_GAIN5_Msk & ((value) << ADC_CGR_GAIN5_Pos)))
|
||||
#define ADC_CGR_GAIN6_Pos 12
|
||||
#define ADC_CGR_GAIN6_Msk (0x3u << ADC_CGR_GAIN6_Pos) /**< \brief (ADC_CGR) Gain for channel 6 */
|
||||
#define ADC_CGR_GAIN6(value) ((ADC_CGR_GAIN6_Msk & ((value) << ADC_CGR_GAIN6_Pos)))
|
||||
#define ADC_CGR_GAIN7_Pos 14
|
||||
#define ADC_CGR_GAIN7_Msk (0x3u << ADC_CGR_GAIN7_Pos) /**< \brief (ADC_CGR) Gain for channel 7 */
|
||||
#define ADC_CGR_GAIN7(value) ((ADC_CGR_GAIN7_Msk & ((value) << ADC_CGR_GAIN7_Pos)))
|
||||
#define ADC_CGR_GAIN8_Pos 16
|
||||
#define ADC_CGR_GAIN8_Msk (0x3u << ADC_CGR_GAIN8_Pos) /**< \brief (ADC_CGR) Gain for channel 8 */
|
||||
#define ADC_CGR_GAIN8(value) ((ADC_CGR_GAIN8_Msk & ((value) << ADC_CGR_GAIN8_Pos)))
|
||||
#define ADC_CGR_GAIN9_Pos 18
|
||||
#define ADC_CGR_GAIN9_Msk (0x3u << ADC_CGR_GAIN9_Pos) /**< \brief (ADC_CGR) Gain for channel 9 */
|
||||
#define ADC_CGR_GAIN9(value) ((ADC_CGR_GAIN9_Msk & ((value) << ADC_CGR_GAIN9_Pos)))
|
||||
#define ADC_CGR_GAIN10_Pos 20
|
||||
#define ADC_CGR_GAIN10_Msk (0x3u << ADC_CGR_GAIN10_Pos) /**< \brief (ADC_CGR) Gain for channel 10 */
|
||||
#define ADC_CGR_GAIN10(value) ((ADC_CGR_GAIN10_Msk & ((value) << ADC_CGR_GAIN10_Pos)))
|
||||
#define ADC_CGR_GAIN11_Pos 22
|
||||
#define ADC_CGR_GAIN11_Msk (0x3u << ADC_CGR_GAIN11_Pos) /**< \brief (ADC_CGR) Gain for channel 11 */
|
||||
#define ADC_CGR_GAIN11(value) ((ADC_CGR_GAIN11_Msk & ((value) << ADC_CGR_GAIN11_Pos)))
|
||||
#define ADC_CGR_GAIN12_Pos 24
|
||||
#define ADC_CGR_GAIN12_Msk (0x3u << ADC_CGR_GAIN12_Pos) /**< \brief (ADC_CGR) Gain for channel 12 */
|
||||
#define ADC_CGR_GAIN12(value) ((ADC_CGR_GAIN12_Msk & ((value) << ADC_CGR_GAIN12_Pos)))
|
||||
#define ADC_CGR_GAIN13_Pos 26
|
||||
#define ADC_CGR_GAIN13_Msk (0x3u << ADC_CGR_GAIN13_Pos) /**< \brief (ADC_CGR) Gain for channel 13 */
|
||||
#define ADC_CGR_GAIN13(value) ((ADC_CGR_GAIN13_Msk & ((value) << ADC_CGR_GAIN13_Pos)))
|
||||
#define ADC_CGR_GAIN14_Pos 28
|
||||
#define ADC_CGR_GAIN14_Msk (0x3u << ADC_CGR_GAIN14_Pos) /**< \brief (ADC_CGR) Gain for channel 14 */
|
||||
#define ADC_CGR_GAIN14(value) ((ADC_CGR_GAIN14_Msk & ((value) << ADC_CGR_GAIN14_Pos)))
|
||||
#define ADC_CGR_GAIN15_Pos 30
|
||||
#define ADC_CGR_GAIN15_Msk (0x3u << ADC_CGR_GAIN15_Pos) /**< \brief (ADC_CGR) Gain for channel 15 */
|
||||
#define ADC_CGR_GAIN15(value) ((ADC_CGR_GAIN15_Msk & ((value) << ADC_CGR_GAIN15_Pos)))
|
||||
/* -------- ADC_COR : (ADC Offset: 0x4C) Channel Offset Register -------- */
|
||||
#define ADC_COR_OFF0 (0x1u << 0) /**< \brief (ADC_COR) Offset for channel 0 */
|
||||
#define ADC_COR_OFF1 (0x1u << 1) /**< \brief (ADC_COR) Offset for channel 1 */
|
||||
#define ADC_COR_OFF2 (0x1u << 2) /**< \brief (ADC_COR) Offset for channel 2 */
|
||||
#define ADC_COR_OFF3 (0x1u << 3) /**< \brief (ADC_COR) Offset for channel 3 */
|
||||
#define ADC_COR_OFF4 (0x1u << 4) /**< \brief (ADC_COR) Offset for channel 4 */
|
||||
#define ADC_COR_OFF5 (0x1u << 5) /**< \brief (ADC_COR) Offset for channel 5 */
|
||||
#define ADC_COR_OFF6 (0x1u << 6) /**< \brief (ADC_COR) Offset for channel 6 */
|
||||
#define ADC_COR_OFF7 (0x1u << 7) /**< \brief (ADC_COR) Offset for channel 7 */
|
||||
#define ADC_COR_OFF8 (0x1u << 8) /**< \brief (ADC_COR) Offset for channel 8 */
|
||||
#define ADC_COR_OFF9 (0x1u << 9) /**< \brief (ADC_COR) Offset for channel 9 */
|
||||
#define ADC_COR_OFF10 (0x1u << 10) /**< \brief (ADC_COR) Offset for channel 10 */
|
||||
#define ADC_COR_OFF11 (0x1u << 11) /**< \brief (ADC_COR) Offset for channel 11 */
|
||||
#define ADC_COR_OFF12 (0x1u << 12) /**< \brief (ADC_COR) Offset for channel 12 */
|
||||
#define ADC_COR_OFF13 (0x1u << 13) /**< \brief (ADC_COR) Offset for channel 13 */
|
||||
#define ADC_COR_OFF14 (0x1u << 14) /**< \brief (ADC_COR) Offset for channel 14 */
|
||||
#define ADC_COR_OFF15 (0x1u << 15) /**< \brief (ADC_COR) Offset for channel 15 */
|
||||
#define ADC_COR_DIFF0 (0x1u << 16) /**< \brief (ADC_COR) Differential inputs for channel 0 */
|
||||
#define ADC_COR_DIFF1 (0x1u << 17) /**< \brief (ADC_COR) Differential inputs for channel 1 */
|
||||
#define ADC_COR_DIFF2 (0x1u << 18) /**< \brief (ADC_COR) Differential inputs for channel 2 */
|
||||
#define ADC_COR_DIFF3 (0x1u << 19) /**< \brief (ADC_COR) Differential inputs for channel 3 */
|
||||
#define ADC_COR_DIFF4 (0x1u << 20) /**< \brief (ADC_COR) Differential inputs for channel 4 */
|
||||
#define ADC_COR_DIFF5 (0x1u << 21) /**< \brief (ADC_COR) Differential inputs for channel 5 */
|
||||
#define ADC_COR_DIFF6 (0x1u << 22) /**< \brief (ADC_COR) Differential inputs for channel 6 */
|
||||
#define ADC_COR_DIFF7 (0x1u << 23) /**< \brief (ADC_COR) Differential inputs for channel 7 */
|
||||
#define ADC_COR_DIFF8 (0x1u << 24) /**< \brief (ADC_COR) Differential inputs for channel 8 */
|
||||
#define ADC_COR_DIFF9 (0x1u << 25) /**< \brief (ADC_COR) Differential inputs for channel 9 */
|
||||
#define ADC_COR_DIFF10 (0x1u << 26) /**< \brief (ADC_COR) Differential inputs for channel 10 */
|
||||
#define ADC_COR_DIFF11 (0x1u << 27) /**< \brief (ADC_COR) Differential inputs for channel 11 */
|
||||
#define ADC_COR_DIFF12 (0x1u << 28) /**< \brief (ADC_COR) Differential inputs for channel 12 */
|
||||
#define ADC_COR_DIFF13 (0x1u << 29) /**< \brief (ADC_COR) Differential inputs for channel 13 */
|
||||
#define ADC_COR_DIFF14 (0x1u << 30) /**< \brief (ADC_COR) Differential inputs for channel 14 */
|
||||
#define ADC_COR_DIFF15 (0x1u << 31) /**< \brief (ADC_COR) Differential inputs for channel 15 */
|
||||
/* -------- ADC_CDR[16] : (ADC Offset: 0x50) Channel Data Register -------- */
|
||||
#define ADC_CDR_DATA_Pos 0
|
||||
#define ADC_CDR_DATA_Msk (0xfffu << ADC_CDR_DATA_Pos) /**< \brief (ADC_CDR[16]) Converted Data */
|
||||
/* -------- ADC_ACR : (ADC Offset: 0x94) Analog Control Register -------- */
|
||||
#define ADC_ACR_TSON (0x1u << 4) /**< \brief (ADC_ACR) Temperature Sensor On */
|
||||
#define ADC_ACR_IBCTL_Pos 8
|
||||
#define ADC_ACR_IBCTL_Msk (0x3u << ADC_ACR_IBCTL_Pos) /**< \brief (ADC_ACR) ADC Bias Current Control */
|
||||
#define ADC_ACR_IBCTL(value) ((ADC_ACR_IBCTL_Msk & ((value) << ADC_ACR_IBCTL_Pos)))
|
||||
/* -------- ADC_WPMR : (ADC Offset: 0xE4) Write Protect Mode Register -------- */
|
||||
#define ADC_WPMR_WPEN (0x1u << 0) /**< \brief (ADC_WPMR) Write Protect Enable */
|
||||
#define ADC_WPMR_WPKEY_Pos 8
|
||||
#define ADC_WPMR_WPKEY_Msk (0xffffffu << ADC_WPMR_WPKEY_Pos) /**< \brief (ADC_WPMR) Write Protect KEY */
|
||||
#define ADC_WPMR_WPKEY(value) ((ADC_WPMR_WPKEY_Msk & ((value) << ADC_WPMR_WPKEY_Pos)))
|
||||
/* -------- ADC_WPSR : (ADC Offset: 0xE8) Write Protect Status Register -------- */
|
||||
#define ADC_WPSR_WPVS (0x1u << 0) /**< \brief (ADC_WPSR) Write Protect Violation Status */
|
||||
#define ADC_WPSR_WPVSRC_Pos 8
|
||||
#define ADC_WPSR_WPVSRC_Msk (0xffffu << ADC_WPSR_WPVSRC_Pos) /**< \brief (ADC_WPSR) Write Protect Violation Source */
|
||||
/* -------- ADC_RPR : (ADC Offset: 0x100) Receive Pointer Register -------- */
|
||||
#define ADC_RPR_RXPTR_Pos 0
|
||||
#define ADC_RPR_RXPTR_Msk (0xffffffffu << ADC_RPR_RXPTR_Pos) /**< \brief (ADC_RPR) Receive Pointer Register */
|
||||
#define ADC_RPR_RXPTR(value) ((ADC_RPR_RXPTR_Msk & ((value) << ADC_RPR_RXPTR_Pos)))
|
||||
/* -------- ADC_RCR : (ADC Offset: 0x104) Receive Counter Register -------- */
|
||||
#define ADC_RCR_RXCTR_Pos 0
|
||||
#define ADC_RCR_RXCTR_Msk (0xffffu << ADC_RCR_RXCTR_Pos) /**< \brief (ADC_RCR) Receive Counter Register */
|
||||
#define ADC_RCR_RXCTR(value) ((ADC_RCR_RXCTR_Msk & ((value) << ADC_RCR_RXCTR_Pos)))
|
||||
/* -------- ADC_RNPR : (ADC Offset: 0x110) Receive Next Pointer Register -------- */
|
||||
#define ADC_RNPR_RXNPTR_Pos 0
|
||||
#define ADC_RNPR_RXNPTR_Msk (0xffffffffu << ADC_RNPR_RXNPTR_Pos) /**< \brief (ADC_RNPR) Receive Next Pointer */
|
||||
#define ADC_RNPR_RXNPTR(value) ((ADC_RNPR_RXNPTR_Msk & ((value) << ADC_RNPR_RXNPTR_Pos)))
|
||||
/* -------- ADC_RNCR : (ADC Offset: 0x114) Receive Next Counter Register -------- */
|
||||
#define ADC_RNCR_RXNCTR_Pos 0
|
||||
#define ADC_RNCR_RXNCTR_Msk (0xffffu << ADC_RNCR_RXNCTR_Pos) /**< \brief (ADC_RNCR) Receive Next Counter */
|
||||
#define ADC_RNCR_RXNCTR(value) ((ADC_RNCR_RXNCTR_Msk & ((value) << ADC_RNCR_RXNCTR_Pos)))
|
||||
/* -------- ADC_PTCR : (ADC Offset: 0x120) Transfer Control Register -------- */
|
||||
#define ADC_PTCR_RXTEN (0x1u << 0) /**< \brief (ADC_PTCR) Receiver Transfer Enable */
|
||||
#define ADC_PTCR_RXTDIS (0x1u << 1) /**< \brief (ADC_PTCR) Receiver Transfer Disable */
|
||||
#define ADC_PTCR_TXTEN (0x1u << 8) /**< \brief (ADC_PTCR) Transmitter Transfer Enable */
|
||||
#define ADC_PTCR_TXTDIS (0x1u << 9) /**< \brief (ADC_PTCR) Transmitter Transfer Disable */
|
||||
/* -------- ADC_PTSR : (ADC Offset: 0x124) Transfer Status Register -------- */
|
||||
#define ADC_PTSR_RXTEN (0x1u << 0) /**< \brief (ADC_PTSR) Receiver Transfer Enable */
|
||||
#define ADC_PTSR_TXTEN (0x1u << 8) /**< \brief (ADC_PTSR) Transmitter Transfer Enable */
|
||||
|
||||
/*@}*/
|
||||
|
||||
|
||||
#endif /* _SAM3XA_ADC_COMPONENT_ */
|
||||
298
lib/cmsis-sam3x8e/include/component/component_can.h
Normal file
@@ -0,0 +1,298 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* SAM Software Package License
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2012, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following condition is met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _SAM3XA_CAN_COMPONENT_
|
||||
#define _SAM3XA_CAN_COMPONENT_
|
||||
|
||||
/* ============================================================================= */
|
||||
/** SOFTWARE API DEFINITION FOR Controller Area Network */
|
||||
/* ============================================================================= */
|
||||
/** \addtogroup SAM3XA_CAN Controller Area Network */
|
||||
/*@{*/
|
||||
|
||||
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
|
||||
/** \brief CanMb hardware registers */
|
||||
typedef struct {
|
||||
RwReg CAN_MMR; /**< \brief (CanMb Offset: 0x0) Mailbox Mode Register */
|
||||
RwReg CAN_MAM; /**< \brief (CanMb Offset: 0x4) Mailbox Acceptance Mask Register */
|
||||
RwReg CAN_MID; /**< \brief (CanMb Offset: 0x8) Mailbox ID Register */
|
||||
RwReg CAN_MFID; /**< \brief (CanMb Offset: 0xC) Mailbox Family ID Register */
|
||||
RwReg CAN_MSR; /**< \brief (CanMb Offset: 0x10) Mailbox Status Register */
|
||||
RwReg CAN_MDL; /**< \brief (CanMb Offset: 0x14) Mailbox Data Low Register */
|
||||
RwReg CAN_MDH; /**< \brief (CanMb Offset: 0x18) Mailbox Data High Register */
|
||||
RwReg CAN_MCR; /**< \brief (CanMb Offset: 0x1C) Mailbox Control Register */
|
||||
} CanMb;
|
||||
/** \brief Can hardware registers */
|
||||
#define CANMB_NUMBER 8
|
||||
typedef struct {
|
||||
RwReg CAN_MR; /**< \brief (Can Offset: 0x0000) Mode Register */
|
||||
WoReg CAN_IER; /**< \brief (Can Offset: 0x0004) Interrupt Enable Register */
|
||||
WoReg CAN_IDR; /**< \brief (Can Offset: 0x0008) Interrupt Disable Register */
|
||||
RoReg CAN_IMR; /**< \brief (Can Offset: 0x000C) Interrupt Mask Register */
|
||||
RoReg CAN_SR; /**< \brief (Can Offset: 0x0010) Status Register */
|
||||
RwReg CAN_BR; /**< \brief (Can Offset: 0x0014) Baudrate Register */
|
||||
RoReg CAN_TIM; /**< \brief (Can Offset: 0x0018) Timer Register */
|
||||
RoReg CAN_TIMESTP; /**< \brief (Can Offset: 0x001C) Timestamp Register */
|
||||
RoReg CAN_ECR; /**< \brief (Can Offset: 0x0020) Error Counter Register */
|
||||
WoReg CAN_TCR; /**< \brief (Can Offset: 0x0024) Transfer Command Register */
|
||||
WoReg CAN_ACR; /**< \brief (Can Offset: 0x0028) Abort Command Register */
|
||||
RoReg Reserved1[46];
|
||||
RwReg CAN_WPMR; /**< \brief (Can Offset: 0x00E4) Write Protect Mode Register */
|
||||
RoReg CAN_WPSR; /**< \brief (Can Offset: 0x00E8) Write Protect Status Register */
|
||||
RoReg Reserved2[69];
|
||||
CanMb CAN_MB[CANMB_NUMBER]; /**< \brief (Can Offset: 0x200) MB = 0 .. 7 */
|
||||
} Can;
|
||||
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
|
||||
/* -------- CAN_MR : (CAN Offset: 0x0000) Mode Register -------- */
|
||||
#define CAN_MR_CANEN (0x1u << 0) /**< \brief (CAN_MR) CAN Controller Enable */
|
||||
#define CAN_MR_LPM (0x1u << 1) /**< \brief (CAN_MR) Disable/Enable Low Power Mode */
|
||||
#define CAN_MR_ABM (0x1u << 2) /**< \brief (CAN_MR) Disable/Enable Autobaud/Listen mode */
|
||||
#define CAN_MR_OVL (0x1u << 3) /**< \brief (CAN_MR) Disable/Enable Overload Frame */
|
||||
#define CAN_MR_TEOF (0x1u << 4) /**< \brief (CAN_MR) Timestamp messages at each end of Frame */
|
||||
#define CAN_MR_TTM (0x1u << 5) /**< \brief (CAN_MR) Disable/Enable Time Triggered Mode */
|
||||
#define CAN_MR_TIMFRZ (0x1u << 6) /**< \brief (CAN_MR) Enable Timer Freeze */
|
||||
#define CAN_MR_DRPT (0x1u << 7) /**< \brief (CAN_MR) Disable Repeat */
|
||||
#define CAN_MR_RXSYNC_Pos 24
|
||||
#define CAN_MR_RXSYNC_Msk (0x7u << CAN_MR_RXSYNC_Pos) /**< \brief (CAN_MR) Reception Synchronization Stage (not readable) */
|
||||
#define CAN_MR_RXSYNC_DOUBLE_PP (0x0u << 24) /**< \brief (CAN_MR) Rx Signal with Double Synchro Stages (2 Positive Edges) */
|
||||
#define CAN_MR_RXSYNC_DOUBLE_PN (0x1u << 24) /**< \brief (CAN_MR) Rx Signal with Double Synchro Stages (One Positive Edge and One Negative Edge) */
|
||||
#define CAN_MR_RXSYNC_SINGLE_P (0x2u << 24) /**< \brief (CAN_MR) Rx Signal with Single Synchro Stage (Positive Edge) */
|
||||
#define CAN_MR_RXSYNC_NONE (0x3u << 24) /**< \brief (CAN_MR) Rx Signal with No Synchro Stage */
|
||||
/* -------- CAN_IER : (CAN Offset: 0x0004) Interrupt Enable Register -------- */
|
||||
#define CAN_IER_MB0 (0x1u << 0) /**< \brief (CAN_IER) Mailbox 0 Interrupt Enable */
|
||||
#define CAN_IER_MB1 (0x1u << 1) /**< \brief (CAN_IER) Mailbox 1 Interrupt Enable */
|
||||
#define CAN_IER_MB2 (0x1u << 2) /**< \brief (CAN_IER) Mailbox 2 Interrupt Enable */
|
||||
#define CAN_IER_MB3 (0x1u << 3) /**< \brief (CAN_IER) Mailbox 3 Interrupt Enable */
|
||||
#define CAN_IER_MB4 (0x1u << 4) /**< \brief (CAN_IER) Mailbox 4 Interrupt Enable */
|
||||
#define CAN_IER_MB5 (0x1u << 5) /**< \brief (CAN_IER) Mailbox 5 Interrupt Enable */
|
||||
#define CAN_IER_MB6 (0x1u << 6) /**< \brief (CAN_IER) Mailbox 6 Interrupt Enable */
|
||||
#define CAN_IER_MB7 (0x1u << 7) /**< \brief (CAN_IER) Mailbox 7 Interrupt Enable */
|
||||
#define CAN_IER_ERRA (0x1u << 16) /**< \brief (CAN_IER) Error Active Mode Interrupt Enable */
|
||||
#define CAN_IER_WARN (0x1u << 17) /**< \brief (CAN_IER) Warning Limit Interrupt Enable */
|
||||
#define CAN_IER_ERRP (0x1u << 18) /**< \brief (CAN_IER) Error Passive Mode Interrupt Enable */
|
||||
#define CAN_IER_BOFF (0x1u << 19) /**< \brief (CAN_IER) Bus Off Mode Interrupt Enable */
|
||||
#define CAN_IER_SLEEP (0x1u << 20) /**< \brief (CAN_IER) Sleep Interrupt Enable */
|
||||
#define CAN_IER_WAKEUP (0x1u << 21) /**< \brief (CAN_IER) Wakeup Interrupt Enable */
|
||||
#define CAN_IER_TOVF (0x1u << 22) /**< \brief (CAN_IER) Timer Overflow Interrupt Enable */
|
||||
#define CAN_IER_TSTP (0x1u << 23) /**< \brief (CAN_IER) TimeStamp Interrupt Enable */
|
||||
#define CAN_IER_CERR (0x1u << 24) /**< \brief (CAN_IER) CRC Error Interrupt Enable */
|
||||
#define CAN_IER_SERR (0x1u << 25) /**< \brief (CAN_IER) Stuffing Error Interrupt Enable */
|
||||
#define CAN_IER_AERR (0x1u << 26) /**< \brief (CAN_IER) Acknowledgment Error Interrupt Enable */
|
||||
#define CAN_IER_FERR (0x1u << 27) /**< \brief (CAN_IER) Form Error Interrupt Enable */
|
||||
#define CAN_IER_BERR (0x1u << 28) /**< \brief (CAN_IER) Bit Error Interrupt Enable */
|
||||
/* -------- CAN_IDR : (CAN Offset: 0x0008) Interrupt Disable Register -------- */
|
||||
#define CAN_IDR_MB0 (0x1u << 0) /**< \brief (CAN_IDR) Mailbox 0 Interrupt Disable */
|
||||
#define CAN_IDR_MB1 (0x1u << 1) /**< \brief (CAN_IDR) Mailbox 1 Interrupt Disable */
|
||||
#define CAN_IDR_MB2 (0x1u << 2) /**< \brief (CAN_IDR) Mailbox 2 Interrupt Disable */
|
||||
#define CAN_IDR_MB3 (0x1u << 3) /**< \brief (CAN_IDR) Mailbox 3 Interrupt Disable */
|
||||
#define CAN_IDR_MB4 (0x1u << 4) /**< \brief (CAN_IDR) Mailbox 4 Interrupt Disable */
|
||||
#define CAN_IDR_MB5 (0x1u << 5) /**< \brief (CAN_IDR) Mailbox 5 Interrupt Disable */
|
||||
#define CAN_IDR_MB6 (0x1u << 6) /**< \brief (CAN_IDR) Mailbox 6 Interrupt Disable */
|
||||
#define CAN_IDR_MB7 (0x1u << 7) /**< \brief (CAN_IDR) Mailbox 7 Interrupt Disable */
|
||||
#define CAN_IDR_ERRA (0x1u << 16) /**< \brief (CAN_IDR) Error Active Mode Interrupt Disable */
|
||||
#define CAN_IDR_WARN (0x1u << 17) /**< \brief (CAN_IDR) Warning Limit Interrupt Disable */
|
||||
#define CAN_IDR_ERRP (0x1u << 18) /**< \brief (CAN_IDR) Error Passive Mode Interrupt Disable */
|
||||
#define CAN_IDR_BOFF (0x1u << 19) /**< \brief (CAN_IDR) Bus Off Mode Interrupt Disable */
|
||||
#define CAN_IDR_SLEEP (0x1u << 20) /**< \brief (CAN_IDR) Sleep Interrupt Disable */
|
||||
#define CAN_IDR_WAKEUP (0x1u << 21) /**< \brief (CAN_IDR) Wakeup Interrupt Disable */
|
||||
#define CAN_IDR_TOVF (0x1u << 22) /**< \brief (CAN_IDR) Timer Overflow Interrupt */
|
||||
#define CAN_IDR_TSTP (0x1u << 23) /**< \brief (CAN_IDR) TimeStamp Interrupt Disable */
|
||||
#define CAN_IDR_CERR (0x1u << 24) /**< \brief (CAN_IDR) CRC Error Interrupt Disable */
|
||||
#define CAN_IDR_SERR (0x1u << 25) /**< \brief (CAN_IDR) Stuffing Error Interrupt Disable */
|
||||
#define CAN_IDR_AERR (0x1u << 26) /**< \brief (CAN_IDR) Acknowledgment Error Interrupt Disable */
|
||||
#define CAN_IDR_FERR (0x1u << 27) /**< \brief (CAN_IDR) Form Error Interrupt Disable */
|
||||
#define CAN_IDR_BERR (0x1u << 28) /**< \brief (CAN_IDR) Bit Error Interrupt Disable */
|
||||
/* -------- CAN_IMR : (CAN Offset: 0x000C) Interrupt Mask Register -------- */
|
||||
#define CAN_IMR_MB0 (0x1u << 0) /**< \brief (CAN_IMR) Mailbox 0 Interrupt Mask */
|
||||
#define CAN_IMR_MB1 (0x1u << 1) /**< \brief (CAN_IMR) Mailbox 1 Interrupt Mask */
|
||||
#define CAN_IMR_MB2 (0x1u << 2) /**< \brief (CAN_IMR) Mailbox 2 Interrupt Mask */
|
||||
#define CAN_IMR_MB3 (0x1u << 3) /**< \brief (CAN_IMR) Mailbox 3 Interrupt Mask */
|
||||
#define CAN_IMR_MB4 (0x1u << 4) /**< \brief (CAN_IMR) Mailbox 4 Interrupt Mask */
|
||||
#define CAN_IMR_MB5 (0x1u << 5) /**< \brief (CAN_IMR) Mailbox 5 Interrupt Mask */
|
||||
#define CAN_IMR_MB6 (0x1u << 6) /**< \brief (CAN_IMR) Mailbox 6 Interrupt Mask */
|
||||
#define CAN_IMR_MB7 (0x1u << 7) /**< \brief (CAN_IMR) Mailbox 7 Interrupt Mask */
|
||||
#define CAN_IMR_ERRA (0x1u << 16) /**< \brief (CAN_IMR) Error Active Mode Interrupt Mask */
|
||||
#define CAN_IMR_WARN (0x1u << 17) /**< \brief (CAN_IMR) Warning Limit Interrupt Mask */
|
||||
#define CAN_IMR_ERRP (0x1u << 18) /**< \brief (CAN_IMR) Error Passive Mode Interrupt Mask */
|
||||
#define CAN_IMR_BOFF (0x1u << 19) /**< \brief (CAN_IMR) Bus Off Mode Interrupt Mask */
|
||||
#define CAN_IMR_SLEEP (0x1u << 20) /**< \brief (CAN_IMR) Sleep Interrupt Mask */
|
||||
#define CAN_IMR_WAKEUP (0x1u << 21) /**< \brief (CAN_IMR) Wakeup Interrupt Mask */
|
||||
#define CAN_IMR_TOVF (0x1u << 22) /**< \brief (CAN_IMR) Timer Overflow Interrupt Mask */
|
||||
#define CAN_IMR_TSTP (0x1u << 23) /**< \brief (CAN_IMR) Timestamp Interrupt Mask */
|
||||
#define CAN_IMR_CERR (0x1u << 24) /**< \brief (CAN_IMR) CRC Error Interrupt Mask */
|
||||
#define CAN_IMR_SERR (0x1u << 25) /**< \brief (CAN_IMR) Stuffing Error Interrupt Mask */
|
||||
#define CAN_IMR_AERR (0x1u << 26) /**< \brief (CAN_IMR) Acknowledgment Error Interrupt Mask */
|
||||
#define CAN_IMR_FERR (0x1u << 27) /**< \brief (CAN_IMR) Form Error Interrupt Mask */
|
||||
#define CAN_IMR_BERR (0x1u << 28) /**< \brief (CAN_IMR) Bit Error Interrupt Mask */
|
||||
/* -------- CAN_SR : (CAN Offset: 0x0010) Status Register -------- */
|
||||
#define CAN_SR_MB0 (0x1u << 0) /**< \brief (CAN_SR) Mailbox 0 Event */
|
||||
#define CAN_SR_MB1 (0x1u << 1) /**< \brief (CAN_SR) Mailbox 1 Event */
|
||||
#define CAN_SR_MB2 (0x1u << 2) /**< \brief (CAN_SR) Mailbox 2 Event */
|
||||
#define CAN_SR_MB3 (0x1u << 3) /**< \brief (CAN_SR) Mailbox 3 Event */
|
||||
#define CAN_SR_MB4 (0x1u << 4) /**< \brief (CAN_SR) Mailbox 4 Event */
|
||||
#define CAN_SR_MB5 (0x1u << 5) /**< \brief (CAN_SR) Mailbox 5 Event */
|
||||
#define CAN_SR_MB6 (0x1u << 6) /**< \brief (CAN_SR) Mailbox 6 Event */
|
||||
#define CAN_SR_MB7 (0x1u << 7) /**< \brief (CAN_SR) Mailbox 7 Event */
|
||||
#define CAN_SR_ERRA (0x1u << 16) /**< \brief (CAN_SR) Error Active Mode */
|
||||
#define CAN_SR_WARN (0x1u << 17) /**< \brief (CAN_SR) Warning Limit */
|
||||
#define CAN_SR_ERRP (0x1u << 18) /**< \brief (CAN_SR) Error Passive Mode */
|
||||
#define CAN_SR_BOFF (0x1u << 19) /**< \brief (CAN_SR) Bus Off Mode */
|
||||
#define CAN_SR_SLEEP (0x1u << 20) /**< \brief (CAN_SR) CAN controller in Low power Mode */
|
||||
#define CAN_SR_WAKEUP (0x1u << 21) /**< \brief (CAN_SR) CAN controller is not in Low power Mode */
|
||||
#define CAN_SR_TOVF (0x1u << 22) /**< \brief (CAN_SR) Timer Overflow */
|
||||
#define CAN_SR_TSTP (0x1u << 23) /**< \brief (CAN_SR) */
|
||||
#define CAN_SR_CERR (0x1u << 24) /**< \brief (CAN_SR) Mailbox CRC Error */
|
||||
#define CAN_SR_SERR (0x1u << 25) /**< \brief (CAN_SR) Mailbox Stuffing Error */
|
||||
#define CAN_SR_AERR (0x1u << 26) /**< \brief (CAN_SR) Acknowledgment Error */
|
||||
#define CAN_SR_FERR (0x1u << 27) /**< \brief (CAN_SR) Form Error */
|
||||
#define CAN_SR_BERR (0x1u << 28) /**< \brief (CAN_SR) Bit Error */
|
||||
#define CAN_SR_RBSY (0x1u << 29) /**< \brief (CAN_SR) Receiver busy */
|
||||
#define CAN_SR_TBSY (0x1u << 30) /**< \brief (CAN_SR) Transmitter busy */
|
||||
#define CAN_SR_OVLSY (0x1u << 31) /**< \brief (CAN_SR) Overload busy */
|
||||
/* -------- CAN_BR : (CAN Offset: 0x0014) Baudrate Register -------- */
|
||||
#define CAN_BR_PHASE2_Pos 0
|
||||
#define CAN_BR_PHASE2_Msk (0x7u << CAN_BR_PHASE2_Pos) /**< \brief (CAN_BR) Phase 2 segment */
|
||||
#define CAN_BR_PHASE2(value) ((CAN_BR_PHASE2_Msk & ((value) << CAN_BR_PHASE2_Pos)))
|
||||
#define CAN_BR_PHASE1_Pos 4
|
||||
#define CAN_BR_PHASE1_Msk (0x7u << CAN_BR_PHASE1_Pos) /**< \brief (CAN_BR) Phase 1 segment */
|
||||
#define CAN_BR_PHASE1(value) ((CAN_BR_PHASE1_Msk & ((value) << CAN_BR_PHASE1_Pos)))
|
||||
#define CAN_BR_PROPAG_Pos 8
|
||||
#define CAN_BR_PROPAG_Msk (0x7u << CAN_BR_PROPAG_Pos) /**< \brief (CAN_BR) Programming time segment */
|
||||
#define CAN_BR_PROPAG(value) ((CAN_BR_PROPAG_Msk & ((value) << CAN_BR_PROPAG_Pos)))
|
||||
#define CAN_BR_SJW_Pos 12
|
||||
#define CAN_BR_SJW_Msk (0x3u << CAN_BR_SJW_Pos) /**< \brief (CAN_BR) Re-synchronization jump width */
|
||||
#define CAN_BR_SJW(value) ((CAN_BR_SJW_Msk & ((value) << CAN_BR_SJW_Pos)))
|
||||
#define CAN_BR_BRP_Pos 16
|
||||
#define CAN_BR_BRP_Msk (0x7fu << CAN_BR_BRP_Pos) /**< \brief (CAN_BR) Baudrate Prescaler. */
|
||||
#define CAN_BR_BRP(value) ((CAN_BR_BRP_Msk & ((value) << CAN_BR_BRP_Pos)))
|
||||
#define CAN_BR_SMP (0x1u << 24) /**< \brief (CAN_BR) Sampling Mode */
|
||||
#define CAN_BR_SMP_ONCE (0x0u << 24) /**< \brief (CAN_BR) The incoming bit stream is sampled once at sample point. */
|
||||
#define CAN_BR_SMP_THREE (0x1u << 24) /**< \brief (CAN_BR) The incoming bit stream is sampled three times with a period of a MCK clock period, centered on sample point. */
|
||||
/* -------- CAN_TIM : (CAN Offset: 0x0018) Timer Register -------- */
|
||||
#define CAN_TIM_TIMER_Pos 0
|
||||
#define CAN_TIM_TIMER_Msk (0xffffu << CAN_TIM_TIMER_Pos) /**< \brief (CAN_TIM) Timer */
|
||||
/* -------- CAN_TIMESTP : (CAN Offset: 0x001C) Timestamp Register -------- */
|
||||
#define CAN_TIMESTP_MTIMESTAMP_Pos 0
|
||||
#define CAN_TIMESTP_MTIMESTAMP_Msk (0xffffu << CAN_TIMESTP_MTIMESTAMP_Pos) /**< \brief (CAN_TIMESTP) Timestamp */
|
||||
/* -------- CAN_ECR : (CAN Offset: 0x0020) Error Counter Register -------- */
|
||||
#define CAN_ECR_REC_Pos 0
|
||||
#define CAN_ECR_REC_Msk (0xffu << CAN_ECR_REC_Pos) /**< \brief (CAN_ECR) Receive Error Counter */
|
||||
#define CAN_ECR_TEC_Pos 16
|
||||
#define CAN_ECR_TEC_Msk (0xffu << CAN_ECR_TEC_Pos) /**< \brief (CAN_ECR) Transmit Error Counter */
|
||||
/* -------- CAN_TCR : (CAN Offset: 0x0024) Transfer Command Register -------- */
|
||||
#define CAN_TCR_MB0 (0x1u << 0) /**< \brief (CAN_TCR) Transfer Request for Mailbox 0 */
|
||||
#define CAN_TCR_MB1 (0x1u << 1) /**< \brief (CAN_TCR) Transfer Request for Mailbox 1 */
|
||||
#define CAN_TCR_MB2 (0x1u << 2) /**< \brief (CAN_TCR) Transfer Request for Mailbox 2 */
|
||||
#define CAN_TCR_MB3 (0x1u << 3) /**< \brief (CAN_TCR) Transfer Request for Mailbox 3 */
|
||||
#define CAN_TCR_MB4 (0x1u << 4) /**< \brief (CAN_TCR) Transfer Request for Mailbox 4 */
|
||||
#define CAN_TCR_MB5 (0x1u << 5) /**< \brief (CAN_TCR) Transfer Request for Mailbox 5 */
|
||||
#define CAN_TCR_MB6 (0x1u << 6) /**< \brief (CAN_TCR) Transfer Request for Mailbox 6 */
|
||||
#define CAN_TCR_MB7 (0x1u << 7) /**< \brief (CAN_TCR) Transfer Request for Mailbox 7 */
|
||||
#define CAN_TCR_TIMRST (0x1u << 31) /**< \brief (CAN_TCR) Timer Reset */
|
||||
/* -------- CAN_ACR : (CAN Offset: 0x0028) Abort Command Register -------- */
|
||||
#define CAN_ACR_MB0 (0x1u << 0) /**< \brief (CAN_ACR) Abort Request for Mailbox 0 */
|
||||
#define CAN_ACR_MB1 (0x1u << 1) /**< \brief (CAN_ACR) Abort Request for Mailbox 1 */
|
||||
#define CAN_ACR_MB2 (0x1u << 2) /**< \brief (CAN_ACR) Abort Request for Mailbox 2 */
|
||||
#define CAN_ACR_MB3 (0x1u << 3) /**< \brief (CAN_ACR) Abort Request for Mailbox 3 */
|
||||
#define CAN_ACR_MB4 (0x1u << 4) /**< \brief (CAN_ACR) Abort Request for Mailbox 4 */
|
||||
#define CAN_ACR_MB5 (0x1u << 5) /**< \brief (CAN_ACR) Abort Request for Mailbox 5 */
|
||||
#define CAN_ACR_MB6 (0x1u << 6) /**< \brief (CAN_ACR) Abort Request for Mailbox 6 */
|
||||
#define CAN_ACR_MB7 (0x1u << 7) /**< \brief (CAN_ACR) Abort Request for Mailbox 7 */
|
||||
/* -------- CAN_WPMR : (CAN Offset: 0x00E4) Write Protect Mode Register -------- */
|
||||
#define CAN_WPMR_WPEN (0x1u << 0) /**< \brief (CAN_WPMR) Write Protection Enable */
|
||||
#define CAN_WPMR_WPKEY_Pos 8
|
||||
#define CAN_WPMR_WPKEY_Msk (0xffffffu << CAN_WPMR_WPKEY_Pos) /**< \brief (CAN_WPMR) SPI Write Protection Key Password */
|
||||
#define CAN_WPMR_WPKEY(value) ((CAN_WPMR_WPKEY_Msk & ((value) << CAN_WPMR_WPKEY_Pos)))
|
||||
/* -------- CAN_WPSR : (CAN Offset: 0x00E8) Write Protect Status Register -------- */
|
||||
#define CAN_WPSR_WPVS (0x1u << 0) /**< \brief (CAN_WPSR) Write Protection Violation Status */
|
||||
#define CAN_WPSR_WPVSRC_Pos 8
|
||||
#define CAN_WPSR_WPVSRC_Msk (0xffu << CAN_WPSR_WPVSRC_Pos) /**< \brief (CAN_WPSR) Write Protection Violation Source */
|
||||
/* -------- CAN_MMR : (CAN Offset: N/A) Mailbox Mode Register -------- */
|
||||
#define CAN_MMR_MTIMEMARK_Pos 0
|
||||
#define CAN_MMR_MTIMEMARK_Msk (0xffffu << CAN_MMR_MTIMEMARK_Pos) /**< \brief (CAN_MMR) Mailbox Timemark */
|
||||
#define CAN_MMR_MTIMEMARK(value) ((CAN_MMR_MTIMEMARK_Msk & ((value) << CAN_MMR_MTIMEMARK_Pos)))
|
||||
#define CAN_MMR_PRIOR_Pos 16
|
||||
#define CAN_MMR_PRIOR_Msk (0xfu << CAN_MMR_PRIOR_Pos) /**< \brief (CAN_MMR) Mailbox Priority */
|
||||
#define CAN_MMR_PRIOR(value) ((CAN_MMR_PRIOR_Msk & ((value) << CAN_MMR_PRIOR_Pos)))
|
||||
#define CAN_MMR_MOT_Pos 24
|
||||
#define CAN_MMR_MOT_Msk (0x7u << CAN_MMR_MOT_Pos) /**< \brief (CAN_MMR) Mailbox Object Type */
|
||||
#define CAN_MMR_MOT_MB_DISABLED (0x0u << 24) /**< \brief (CAN_MMR) Mailbox is disabled. This prevents receiving or transmitting any messages with this mailbox. */
|
||||
#define CAN_MMR_MOT_MB_RX (0x1u << 24) /**< \brief (CAN_MMR) Reception Mailbox. Mailbox is configured for reception. If a message is received while the mailbox data register is full, it is discarded. */
|
||||
#define CAN_MMR_MOT_MB_RX_OVERWRITE (0x2u << 24) /**< \brief (CAN_MMR) Reception mailbox with overwrite. Mailbox is configured for reception. If a message is received while the mailbox is full, it overwrites the previous message. */
|
||||
#define CAN_MMR_MOT_MB_TX (0x3u << 24) /**< \brief (CAN_MMR) Transmit mailbox. Mailbox is configured for transmission. */
|
||||
#define CAN_MMR_MOT_MB_CONSUMER (0x4u << 24) /**< \brief (CAN_MMR) Consumer Mailbox. Mailbox is configured in reception but behaves as a Transmit Mailbox, i.e., it sends a remote frame and waits for an answer. */
|
||||
#define CAN_MMR_MOT_MB_PRODUCER (0x5u << 24) /**< \brief (CAN_MMR) Producer Mailbox. Mailbox is configured in transmission but also behaves like a reception mailbox, i.e., it waits to receive a Remote Frame before sending its contents. */
|
||||
/* -------- CAN_MAM : (CAN Offset: N/A) Mailbox Acceptance Mask Register -------- */
|
||||
#define CAN_MAM_MIDvB_Pos 0
|
||||
#define CAN_MAM_MIDvB_Msk (0x3ffffu << CAN_MAM_MIDvB_Pos) /**< \brief (CAN_MAM) Complementary bits for identifier in extended frame mode */
|
||||
#define CAN_MAM_MIDvB(value) ((CAN_MAM_MIDvB_Msk & ((value) << CAN_MAM_MIDvB_Pos)))
|
||||
#define CAN_MAM_MIDvA_Pos 18
|
||||
#define CAN_MAM_MIDvA_Msk (0x7ffu << CAN_MAM_MIDvA_Pos) /**< \brief (CAN_MAM) Identifier for standard frame mode */
|
||||
#define CAN_MAM_MIDvA(value) ((CAN_MAM_MIDvA_Msk & ((value) << CAN_MAM_MIDvA_Pos)))
|
||||
#define CAN_MAM_MIDE (0x1u << 29) /**< \brief (CAN_MAM) Identifier Version */
|
||||
/* -------- CAN_MID : (CAN Offset: N/A) Mailbox ID Register -------- */
|
||||
#define CAN_MID_MIDvB_Pos 0
|
||||
#define CAN_MID_MIDvB_Msk (0x3ffffu << CAN_MID_MIDvB_Pos) /**< \brief (CAN_MID) Complementary bits for identifier in extended frame mode */
|
||||
#define CAN_MID_MIDvB(value) ((CAN_MID_MIDvB_Msk & ((value) << CAN_MID_MIDvB_Pos)))
|
||||
#define CAN_MID_MIDvA_Pos 18
|
||||
#define CAN_MID_MIDvA_Msk (0x7ffu << CAN_MID_MIDvA_Pos) /**< \brief (CAN_MID) Identifier for standard frame mode */
|
||||
#define CAN_MID_MIDvA(value) ((CAN_MID_MIDvA_Msk & ((value) << CAN_MID_MIDvA_Pos)))
|
||||
#define CAN_MID_MIDE (0x1u << 29) /**< \brief (CAN_MID) Identifier Version */
|
||||
/* -------- CAN_MFID : (CAN Offset: N/A) Mailbox Family ID Register -------- */
|
||||
#define CAN_MFID_MFID_Pos 0
|
||||
#define CAN_MFID_MFID_Msk (0x1fffffffu << CAN_MFID_MFID_Pos) /**< \brief (CAN_MFID) Family ID */
|
||||
/* -------- CAN_MSR : (CAN Offset: N/A) Mailbox Status Register -------- */
|
||||
#define CAN_MSR_MTIMESTAMP_Pos 0
|
||||
#define CAN_MSR_MTIMESTAMP_Msk (0xffffu << CAN_MSR_MTIMESTAMP_Pos) /**< \brief (CAN_MSR) Timer value */
|
||||
#define CAN_MSR_MDLC_Pos 16
|
||||
#define CAN_MSR_MDLC_Msk (0xfu << CAN_MSR_MDLC_Pos) /**< \brief (CAN_MSR) Mailbox Data Length Code */
|
||||
#define CAN_MSR_MRTR (0x1u << 20) /**< \brief (CAN_MSR) Mailbox Remote Transmission Request */
|
||||
#define CAN_MSR_MABT (0x1u << 22) /**< \brief (CAN_MSR) Mailbox Message Abort */
|
||||
#define CAN_MSR_MRDY (0x1u << 23) /**< \brief (CAN_MSR) Mailbox Ready */
|
||||
#define CAN_MSR_MMI (0x1u << 24) /**< \brief (CAN_MSR) Mailbox Message Ignored */
|
||||
/* -------- CAN_MDL : (CAN Offset: N/A) Mailbox Data Low Register -------- */
|
||||
#define CAN_MDL_MDL_Pos 0
|
||||
#define CAN_MDL_MDL_Msk (0xffffffffu << CAN_MDL_MDL_Pos) /**< \brief (CAN_MDL) Message Data Low Value */
|
||||
#define CAN_MDL_MDL(value) ((CAN_MDL_MDL_Msk & ((value) << CAN_MDL_MDL_Pos)))
|
||||
/* -------- CAN_MDH : (CAN Offset: N/A) Mailbox Data High Register -------- */
|
||||
#define CAN_MDH_MDH_Pos 0
|
||||
#define CAN_MDH_MDH_Msk (0xffffffffu << CAN_MDH_MDH_Pos) /**< \brief (CAN_MDH) Message Data High Value */
|
||||
#define CAN_MDH_MDH(value) ((CAN_MDH_MDH_Msk & ((value) << CAN_MDH_MDH_Pos)))
|
||||
/* -------- CAN_MCR : (CAN Offset: N/A) Mailbox Control Register -------- */
|
||||
#define CAN_MCR_MDLC_Pos 16
|
||||
#define CAN_MCR_MDLC_Msk (0xfu << CAN_MCR_MDLC_Pos) /**< \brief (CAN_MCR) Mailbox Data Length Code */
|
||||
#define CAN_MCR_MDLC(value) ((CAN_MCR_MDLC_Msk & ((value) << CAN_MCR_MDLC_Pos)))
|
||||
#define CAN_MCR_MRTR (0x1u << 20) /**< \brief (CAN_MCR) Mailbox Remote Transmission Request */
|
||||
#define CAN_MCR_MACR (0x1u << 22) /**< \brief (CAN_MCR) Abort Request for Mailbox x */
|
||||
#define CAN_MCR_MTCR (0x1u << 23) /**< \brief (CAN_MCR) Mailbox Transfer Command */
|
||||
|
||||
/*@}*/
|
||||
|
||||
|
||||
#endif /* _SAM3XA_CAN_COMPONENT_ */
|
||||
159
lib/cmsis-sam3x8e/include/component/component_chipid.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* SAM Software Package License
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2012, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following condition is met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _SAM3XA_CHIPID_COMPONENT_
|
||||
#define _SAM3XA_CHIPID_COMPONENT_
|
||||
|
||||
/* ============================================================================= */
|
||||
/** SOFTWARE API DEFINITION FOR Chip Identifier */
|
||||
/* ============================================================================= */
|
||||
/** \addtogroup SAM3XA_CHIPID Chip Identifier */
|
||||
/*@{*/
|
||||
|
||||
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
|
||||
/** \brief Chipid hardware registers */
|
||||
typedef struct {
|
||||
RoReg CHIPID_CIDR; /**< \brief (Chipid Offset: 0x0) Chip ID Register */
|
||||
RoReg CHIPID_EXID; /**< \brief (Chipid Offset: 0x4) Chip ID Extension Register */
|
||||
} Chipid;
|
||||
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
|
||||
/* -------- CHIPID_CIDR : (CHIPID Offset: 0x0) Chip ID Register -------- */
|
||||
#define CHIPID_CIDR_VERSION_Pos 0
|
||||
#define CHIPID_CIDR_VERSION_Msk (0x1fu << CHIPID_CIDR_VERSION_Pos) /**< \brief (CHIPID_CIDR) Version of the Device */
|
||||
#define CHIPID_CIDR_EPROC_Pos 5
|
||||
#define CHIPID_CIDR_EPROC_Msk (0x7u << CHIPID_CIDR_EPROC_Pos) /**< \brief (CHIPID_CIDR) Embedded Processor */
|
||||
#define CHIPID_CIDR_EPROC_ARM946ES (0x1u << 5) /**< \brief (CHIPID_CIDR) ARM946ES */
|
||||
#define CHIPID_CIDR_EPROC_ARM7TDMI (0x2u << 5) /**< \brief (CHIPID_CIDR) ARM7TDMI */
|
||||
#define CHIPID_CIDR_EPROC_CM3 (0x3u << 5) /**< \brief (CHIPID_CIDR) Cortex-M3 */
|
||||
#define CHIPID_CIDR_EPROC_ARM920T (0x4u << 5) /**< \brief (CHIPID_CIDR) ARM920T */
|
||||
#define CHIPID_CIDR_EPROC_ARM926EJS (0x5u << 5) /**< \brief (CHIPID_CIDR) ARM926EJS */
|
||||
#define CHIPID_CIDR_EPROC_CA5 (0x6u << 5) /**< \brief (CHIPID_CIDR) Cortex-A5 */
|
||||
#define CHIPID_CIDR_EPROC_CM4 (0x7u << 5) /**< \brief (CHIPID_CIDR) Cortex-M4 */
|
||||
#define CHIPID_CIDR_NVPSIZ_Pos 8
|
||||
#define CHIPID_CIDR_NVPSIZ_Msk (0xfu << CHIPID_CIDR_NVPSIZ_Pos) /**< \brief (CHIPID_CIDR) Nonvolatile Program Memory Size */
|
||||
#define CHIPID_CIDR_NVPSIZ_NONE (0x0u << 8) /**< \brief (CHIPID_CIDR) None */
|
||||
#define CHIPID_CIDR_NVPSIZ_8K (0x1u << 8) /**< \brief (CHIPID_CIDR) 8K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ_16K (0x2u << 8) /**< \brief (CHIPID_CIDR) 16K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ_32K (0x3u << 8) /**< \brief (CHIPID_CIDR) 32K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ_64K (0x5u << 8) /**< \brief (CHIPID_CIDR) 64K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ_128K (0x7u << 8) /**< \brief (CHIPID_CIDR) 128K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ_256K (0x9u << 8) /**< \brief (CHIPID_CIDR) 256K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ_512K (0xAu << 8) /**< \brief (CHIPID_CIDR) 512K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ_1024K (0xCu << 8) /**< \brief (CHIPID_CIDR) 1024K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ_2048K (0xEu << 8) /**< \brief (CHIPID_CIDR) 2048K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ2_Pos 12
|
||||
#define CHIPID_CIDR_NVPSIZ2_Msk (0xfu << CHIPID_CIDR_NVPSIZ2_Pos) /**< \brief (CHIPID_CIDR) Second Nonvolatile Program Memory Size */
|
||||
#define CHIPID_CIDR_NVPSIZ2_NONE (0x0u << 12) /**< \brief (CHIPID_CIDR) None */
|
||||
#define CHIPID_CIDR_NVPSIZ2_8K (0x1u << 12) /**< \brief (CHIPID_CIDR) 8K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ2_16K (0x2u << 12) /**< \brief (CHIPID_CIDR) 16K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ2_32K (0x3u << 12) /**< \brief (CHIPID_CIDR) 32K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ2_64K (0x5u << 12) /**< \brief (CHIPID_CIDR) 64K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ2_128K (0x7u << 12) /**< \brief (CHIPID_CIDR) 128K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ2_256K (0x9u << 12) /**< \brief (CHIPID_CIDR) 256K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ2_512K (0xAu << 12) /**< \brief (CHIPID_CIDR) 512K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ2_1024K (0xCu << 12) /**< \brief (CHIPID_CIDR) 1024K bytes */
|
||||
#define CHIPID_CIDR_NVPSIZ2_2048K (0xEu << 12) /**< \brief (CHIPID_CIDR) 2048K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_Pos 16
|
||||
#define CHIPID_CIDR_SRAMSIZ_Msk (0xfu << CHIPID_CIDR_SRAMSIZ_Pos) /**< \brief (CHIPID_CIDR) Internal SRAM Size */
|
||||
#define CHIPID_CIDR_SRAMSIZ_48K (0x0u << 16) /**< \brief (CHIPID_CIDR) 48K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_1K (0x1u << 16) /**< \brief (CHIPID_CIDR) 1K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_2K (0x2u << 16) /**< \brief (CHIPID_CIDR) 2K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_6K (0x3u << 16) /**< \brief (CHIPID_CIDR) 6K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_24K (0x4u << 16) /**< \brief (CHIPID_CIDR) 24K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_4K (0x5u << 16) /**< \brief (CHIPID_CIDR) 4K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_80K (0x6u << 16) /**< \brief (CHIPID_CIDR) 80K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_160K (0x7u << 16) /**< \brief (CHIPID_CIDR) 160K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_8K (0x8u << 16) /**< \brief (CHIPID_CIDR) 8K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_16K (0x9u << 16) /**< \brief (CHIPID_CIDR) 16K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_32K (0xAu << 16) /**< \brief (CHIPID_CIDR) 32K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_64K (0xBu << 16) /**< \brief (CHIPID_CIDR) 64K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_128K (0xCu << 16) /**< \brief (CHIPID_CIDR) 128K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_256K (0xDu << 16) /**< \brief (CHIPID_CIDR) 256K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_96K (0xEu << 16) /**< \brief (CHIPID_CIDR) 96K bytes */
|
||||
#define CHIPID_CIDR_SRAMSIZ_512K (0xFu << 16) /**< \brief (CHIPID_CIDR) 512K bytes */
|
||||
#define CHIPID_CIDR_ARCH_Pos 20
|
||||
#define CHIPID_CIDR_ARCH_Msk (0xffu << CHIPID_CIDR_ARCH_Pos) /**< \brief (CHIPID_CIDR) Architecture Identifier */
|
||||
#define CHIPID_CIDR_ARCH_AT91SAM9xx (0x19u << 20) /**< \brief (CHIPID_CIDR) AT91SAM9xx Series */
|
||||
#define CHIPID_CIDR_ARCH_AT91SAM9XExx (0x29u << 20) /**< \brief (CHIPID_CIDR) AT91SAM9XExx Series */
|
||||
#define CHIPID_CIDR_ARCH_AT91x34 (0x34u << 20) /**< \brief (CHIPID_CIDR) AT91x34 Series */
|
||||
#define CHIPID_CIDR_ARCH_CAP7 (0x37u << 20) /**< \brief (CHIPID_CIDR) CAP7 Series */
|
||||
#define CHIPID_CIDR_ARCH_CAP9 (0x39u << 20) /**< \brief (CHIPID_CIDR) CAP9 Series */
|
||||
#define CHIPID_CIDR_ARCH_CAP11 (0x3Bu << 20) /**< \brief (CHIPID_CIDR) CAP11 Series */
|
||||
#define CHIPID_CIDR_ARCH_AT91x40 (0x40u << 20) /**< \brief (CHIPID_CIDR) AT91x40 Series */
|
||||
#define CHIPID_CIDR_ARCH_AT91x42 (0x42u << 20) /**< \brief (CHIPID_CIDR) AT91x42 Series */
|
||||
#define CHIPID_CIDR_ARCH_AT91x55 (0x55u << 20) /**< \brief (CHIPID_CIDR) AT91x55 Series */
|
||||
#define CHIPID_CIDR_ARCH_AT91SAM7Axx (0x60u << 20) /**< \brief (CHIPID_CIDR) AT91SAM7Axx Series */
|
||||
#define CHIPID_CIDR_ARCH_AT91SAM7AQxx (0x61u << 20) /**< \brief (CHIPID_CIDR) AT91SAM7AQxx Series */
|
||||
#define CHIPID_CIDR_ARCH_AT91x63 (0x63u << 20) /**< \brief (CHIPID_CIDR) AT91x63 Series */
|
||||
#define CHIPID_CIDR_ARCH_AT91SAM7Sxx (0x70u << 20) /**< \brief (CHIPID_CIDR) AT91SAM7Sxx Series */
|
||||
#define CHIPID_CIDR_ARCH_AT91SAM7XCxx (0x71u << 20) /**< \brief (CHIPID_CIDR) AT91SAM7XCxx Series */
|
||||
#define CHIPID_CIDR_ARCH_AT91SAM7SExx (0x72u << 20) /**< \brief (CHIPID_CIDR) AT91SAM7SExx Series */
|
||||
#define CHIPID_CIDR_ARCH_AT91SAM7Lxx (0x73u << 20) /**< \brief (CHIPID_CIDR) AT91SAM7Lxx Series */
|
||||
#define CHIPID_CIDR_ARCH_AT91SAM7Xxx (0x75u << 20) /**< \brief (CHIPID_CIDR) AT91SAM7Xxx Series */
|
||||
#define CHIPID_CIDR_ARCH_AT91SAM7SLxx (0x76u << 20) /**< \brief (CHIPID_CIDR) AT91SAM7SLxx Series */
|
||||
#define CHIPID_CIDR_ARCH_SAM3UxC (0x80u << 20) /**< \brief (CHIPID_CIDR) SAM3UxC Series (100-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM3UxE (0x81u << 20) /**< \brief (CHIPID_CIDR) SAM3UxE Series (144-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM3AxC (0x83u << 20) /**< \brief (CHIPID_CIDR) SAM3AxC Series (100-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM4AxC (0x83u << 20) /**< \brief (CHIPID_CIDR) SAM4AxC Series (100-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM3XxC (0x84u << 20) /**< \brief (CHIPID_CIDR) SAM3XxC Series (100-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM4XxC (0x84u << 20) /**< \brief (CHIPID_CIDR) SAM4XxC Series (100-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM3XxE (0x85u << 20) /**< \brief (CHIPID_CIDR) SAM3XxE Series (144-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM4XxE (0x85u << 20) /**< \brief (CHIPID_CIDR) SAM4XxE Series (144-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM3XxG (0x86u << 20) /**< \brief (CHIPID_CIDR) SAM3XxG Series (208/217-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM4XxG (0x86u << 20) /**< \brief (CHIPID_CIDR) SAM4XxG Series (208/217-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM3SxA (0x88u << 20) /**< \brief (CHIPID_CIDR) SAM3SxASeries (48-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM4SxA (0x88u << 20) /**< \brief (CHIPID_CIDR) SAM4SxA Series (48-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM3SxB (0x89u << 20) /**< \brief (CHIPID_CIDR) SAM3SxB Series (64-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM4SxB (0x89u << 20) /**< \brief (CHIPID_CIDR) SAM4SxB Series (64-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM3SxC (0x8Au << 20) /**< \brief (CHIPID_CIDR) SAM3SxC Series (100-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM4SxC (0x8Au << 20) /**< \brief (CHIPID_CIDR) SAM4SxC Series (100-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_AT91x92 (0x92u << 20) /**< \brief (CHIPID_CIDR) AT91x92 Series */
|
||||
#define CHIPID_CIDR_ARCH_SAM3NxA (0x93u << 20) /**< \brief (CHIPID_CIDR) SAM3NxA Series (48-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM3NxB (0x94u << 20) /**< \brief (CHIPID_CIDR) SAM3NxB Series (64-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM3NxC (0x95u << 20) /**< \brief (CHIPID_CIDR) SAM3NxC Series (100-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM3SDxB (0x99u << 20) /**< \brief (CHIPID_CIDR) SAM3SDxB Series (64-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM3SDxC (0x9Au << 20) /**< \brief (CHIPID_CIDR) SAM3SDxC Series (100-pin version) */
|
||||
#define CHIPID_CIDR_ARCH_SAM5A (0xA5u << 20) /**< \brief (CHIPID_CIDR) SAM5A */
|
||||
#define CHIPID_CIDR_ARCH_AT75Cxx (0xF0u << 20) /**< \brief (CHIPID_CIDR) AT75Cxx Series */
|
||||
#define CHIPID_CIDR_NVPTYP_Pos 28
|
||||
#define CHIPID_CIDR_NVPTYP_Msk (0x7u << CHIPID_CIDR_NVPTYP_Pos) /**< \brief (CHIPID_CIDR) Nonvolatile Program Memory Type */
|
||||
#define CHIPID_CIDR_NVPTYP_ROM (0x0u << 28) /**< \brief (CHIPID_CIDR) ROM */
|
||||
#define CHIPID_CIDR_NVPTYP_ROMLESS (0x1u << 28) /**< \brief (CHIPID_CIDR) ROMless or on-chip Flash */
|
||||
#define CHIPID_CIDR_NVPTYP_FLASH (0x2u << 28) /**< \brief (CHIPID_CIDR) Embedded Flash Memory */
|
||||
#define CHIPID_CIDR_NVPTYP_ROM_FLASH (0x3u << 28) /**< \brief (CHIPID_CIDR) ROM and Embedded Flash MemoryNVPSIZ is ROM size NVPSIZ2 is Flash size */
|
||||
#define CHIPID_CIDR_NVPTYP_SRAM (0x4u << 28) /**< \brief (CHIPID_CIDR) SRAM emulating ROM */
|
||||
#define CHIPID_CIDR_EXT (0x1u << 31) /**< \brief (CHIPID_CIDR) Extension Flag */
|
||||
/* -------- CHIPID_EXID : (CHIPID Offset: 0x4) Chip ID Extension Register -------- */
|
||||
#define CHIPID_EXID_EXID_Pos 0
|
||||
#define CHIPID_EXID_EXID_Msk (0xffffffffu << CHIPID_EXID_EXID_Pos) /**< \brief (CHIPID_EXID) Chip ID Extension */
|
||||
|
||||
/*@}*/
|
||||
|
||||
|
||||
#endif /* _SAM3XA_CHIPID_COMPONENT_ */
|
||||
210
lib/cmsis-sam3x8e/include/component/component_dacc.h
Normal file
@@ -0,0 +1,210 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* SAM Software Package License
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2012, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following condition is met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _SAM3XA_DACC_COMPONENT_
|
||||
#define _SAM3XA_DACC_COMPONENT_
|
||||
|
||||
/* ============================================================================= */
|
||||
/** SOFTWARE API DEFINITION FOR Digital-to-Analog Converter Controller */
|
||||
/* ============================================================================= */
|
||||
/** \addtogroup SAM3XA_DACC Digital-to-Analog Converter Controller */
|
||||
/*@{*/
|
||||
|
||||
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
|
||||
/** \brief Dacc hardware registers */
|
||||
typedef struct {
|
||||
WoReg DACC_CR; /**< \brief (Dacc Offset: 0x00) Control Register */
|
||||
RwReg DACC_MR; /**< \brief (Dacc Offset: 0x04) Mode Register */
|
||||
RoReg Reserved1[2];
|
||||
WoReg DACC_CHER; /**< \brief (Dacc Offset: 0x10) Channel Enable Register */
|
||||
WoReg DACC_CHDR; /**< \brief (Dacc Offset: 0x14) Channel Disable Register */
|
||||
RoReg DACC_CHSR; /**< \brief (Dacc Offset: 0x18) Channel Status Register */
|
||||
RoReg Reserved2[1];
|
||||
WoReg DACC_CDR; /**< \brief (Dacc Offset: 0x20) Conversion Data Register */
|
||||
WoReg DACC_IER; /**< \brief (Dacc Offset: 0x24) Interrupt Enable Register */
|
||||
WoReg DACC_IDR; /**< \brief (Dacc Offset: 0x28) Interrupt Disable Register */
|
||||
RoReg DACC_IMR; /**< \brief (Dacc Offset: 0x2C) Interrupt Mask Register */
|
||||
RoReg DACC_ISR; /**< \brief (Dacc Offset: 0x30) Interrupt Status Register */
|
||||
RoReg Reserved3[24];
|
||||
RwReg DACC_ACR; /**< \brief (Dacc Offset: 0x94) Analog Current Register */
|
||||
RoReg Reserved4[19];
|
||||
RwReg DACC_WPMR; /**< \brief (Dacc Offset: 0xE4) Write Protect Mode register */
|
||||
RoReg DACC_WPSR; /**< \brief (Dacc Offset: 0xE8) Write Protect Status register */
|
||||
RoReg Reserved5[7];
|
||||
RwReg DACC_TPR; /**< \brief (Dacc Offset: 0x108) Transmit Pointer Register */
|
||||
RwReg DACC_TCR; /**< \brief (Dacc Offset: 0x10C) Transmit Counter Register */
|
||||
RoReg Reserved6[2];
|
||||
RwReg DACC_TNPR; /**< \brief (Dacc Offset: 0x118) Transmit Next Pointer Register */
|
||||
RwReg DACC_TNCR; /**< \brief (Dacc Offset: 0x11C) Transmit Next Counter Register */
|
||||
WoReg DACC_PTCR; /**< \brief (Dacc Offset: 0x120) Transfer Control Register */
|
||||
RoReg DACC_PTSR; /**< \brief (Dacc Offset: 0x124) Transfer Status Register */
|
||||
} Dacc;
|
||||
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
|
||||
/* -------- DACC_CR : (DACC Offset: 0x00) Control Register -------- */
|
||||
#define DACC_CR_SWRST (0x1u << 0) /**< \brief (DACC_CR) Software Reset */
|
||||
/* -------- DACC_MR : (DACC Offset: 0x04) Mode Register -------- */
|
||||
#define DACC_MR_TRGEN (0x1u << 0) /**< \brief (DACC_MR) Trigger Enable */
|
||||
#define DACC_MR_TRGEN_DIS (0x0u << 0) /**< \brief (DACC_MR) External trigger mode disabled. DACC in free running mode. */
|
||||
#define DACC_MR_TRGEN_EN (0x1u << 0) /**< \brief (DACC_MR) External trigger mode enabled. */
|
||||
#define DACC_MR_TRGSEL_Pos 1
|
||||
#define DACC_MR_TRGSEL_Msk (0x7u << DACC_MR_TRGSEL_Pos) /**< \brief (DACC_MR) Trigger Selection */
|
||||
#define DACC_MR_TRGSEL(value) ((DACC_MR_TRGSEL_Msk & ((value) << DACC_MR_TRGSEL_Pos)))
|
||||
#define DACC_MR_WORD (0x1u << 4) /**< \brief (DACC_MR) Word Transfer */
|
||||
#define DACC_MR_WORD_HALF (0x0u << 4) /**< \brief (DACC_MR) Half-Word transfer */
|
||||
#define DACC_MR_WORD_WORD (0x1u << 4) /**< \brief (DACC_MR) Word Transfer */
|
||||
#define DACC_MR_SLEEP (0x1u << 5) /**< \brief (DACC_MR) Sleep Mode */
|
||||
#define DACC_MR_FASTWKUP (0x1u << 6) /**< \brief (DACC_MR) Fast Wake up Mode */
|
||||
#define DACC_MR_REFRESH_Pos 8
|
||||
#define DACC_MR_REFRESH_Msk (0xffu << DACC_MR_REFRESH_Pos) /**< \brief (DACC_MR) Refresh Period */
|
||||
#define DACC_MR_REFRESH(value) ((DACC_MR_REFRESH_Msk & ((value) << DACC_MR_REFRESH_Pos)))
|
||||
#define DACC_MR_USER_SEL_Pos 16
|
||||
#define DACC_MR_USER_SEL_Msk (0x3u << DACC_MR_USER_SEL_Pos) /**< \brief (DACC_MR) User Channel Selection */
|
||||
#define DACC_MR_USER_SEL_CHANNEL0 (0x0u << 16) /**< \brief (DACC_MR) Channel 0 */
|
||||
#define DACC_MR_USER_SEL_CHANNEL1 (0x1u << 16) /**< \brief (DACC_MR) Channel 1 */
|
||||
#define DACC_MR_TAG (0x1u << 20) /**< \brief (DACC_MR) Tag Selection Mode */
|
||||
#define DACC_MR_TAG_DIS (0x0u << 20) /**< \brief (DACC_MR) Tag selection mode disabled. Using USER_SEL to select the channel for the conversion. */
|
||||
#define DACC_MR_TAG_EN (0x1u << 20) /**< \brief (DACC_MR) Tag selection mode enabled */
|
||||
#define DACC_MR_MAXS (0x1u << 21) /**< \brief (DACC_MR) Max Speed Mode */
|
||||
#define DACC_MR_MAXS_NORMAL (0x0u << 21) /**< \brief (DACC_MR) Normal Mode */
|
||||
#define DACC_MR_MAXS_MAXIMUM (0x1u << 21) /**< \brief (DACC_MR) Max Speed Mode enabled */
|
||||
#define DACC_MR_STARTUP_Pos 24
|
||||
#define DACC_MR_STARTUP_Msk (0x3fu << DACC_MR_STARTUP_Pos) /**< \brief (DACC_MR) Startup Time Selection */
|
||||
#define DACC_MR_STARTUP_0 (0x0u << 24) /**< \brief (DACC_MR) 0 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_8 (0x1u << 24) /**< \brief (DACC_MR) 8 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_16 (0x2u << 24) /**< \brief (DACC_MR) 16 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_24 (0x3u << 24) /**< \brief (DACC_MR) 24 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_64 (0x4u << 24) /**< \brief (DACC_MR) 64 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_80 (0x5u << 24) /**< \brief (DACC_MR) 80 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_96 (0x6u << 24) /**< \brief (DACC_MR) 96 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_112 (0x7u << 24) /**< \brief (DACC_MR) 112 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_512 (0x8u << 24) /**< \brief (DACC_MR) 512 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_576 (0x9u << 24) /**< \brief (DACC_MR) 576 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_640 (0xAu << 24) /**< \brief (DACC_MR) 640 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_704 (0xBu << 24) /**< \brief (DACC_MR) 704 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_768 (0xCu << 24) /**< \brief (DACC_MR) 768 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_832 (0xDu << 24) /**< \brief (DACC_MR) 832 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_896 (0xEu << 24) /**< \brief (DACC_MR) 896 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_960 (0xFu << 24) /**< \brief (DACC_MR) 960 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1024 (0x10u << 24) /**< \brief (DACC_MR) 1024 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1088 (0x11u << 24) /**< \brief (DACC_MR) 1088 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1152 (0x12u << 24) /**< \brief (DACC_MR) 1152 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1216 (0x13u << 24) /**< \brief (DACC_MR) 1216 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1280 (0x14u << 24) /**< \brief (DACC_MR) 1280 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1344 (0x15u << 24) /**< \brief (DACC_MR) 1344 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1408 (0x16u << 24) /**< \brief (DACC_MR) 1408 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1472 (0x17u << 24) /**< \brief (DACC_MR) 1472 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1536 (0x18u << 24) /**< \brief (DACC_MR) 1536 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1600 (0x19u << 24) /**< \brief (DACC_MR) 1600 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1664 (0x1Au << 24) /**< \brief (DACC_MR) 1664 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1728 (0x1Bu << 24) /**< \brief (DACC_MR) 1728 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1792 (0x1Cu << 24) /**< \brief (DACC_MR) 1792 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1856 (0x1Du << 24) /**< \brief (DACC_MR) 1856 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1920 (0x1Eu << 24) /**< \brief (DACC_MR) 1920 periods of DACClock */
|
||||
#define DACC_MR_STARTUP_1984 (0x1Fu << 24) /**< \brief (DACC_MR) 1984 periods of DACClock */
|
||||
/* -------- DACC_CHER : (DACC Offset: 0x10) Channel Enable Register -------- */
|
||||
#define DACC_CHER_CH0 (0x1u << 0) /**< \brief (DACC_CHER) Channel 0 Enable */
|
||||
#define DACC_CHER_CH1 (0x1u << 1) /**< \brief (DACC_CHER) Channel 1 Enable */
|
||||
/* -------- DACC_CHDR : (DACC Offset: 0x14) Channel Disable Register -------- */
|
||||
#define DACC_CHDR_CH0 (0x1u << 0) /**< \brief (DACC_CHDR) Channel 0 Disable */
|
||||
#define DACC_CHDR_CH1 (0x1u << 1) /**< \brief (DACC_CHDR) Channel 1 Disable */
|
||||
/* -------- DACC_CHSR : (DACC Offset: 0x18) Channel Status Register -------- */
|
||||
#define DACC_CHSR_CH0 (0x1u << 0) /**< \brief (DACC_CHSR) Channel 0 Status */
|
||||
#define DACC_CHSR_CH1 (0x1u << 1) /**< \brief (DACC_CHSR) Channel 1 Status */
|
||||
/* -------- DACC_CDR : (DACC Offset: 0x20) Conversion Data Register -------- */
|
||||
#define DACC_CDR_DATA_Pos 0
|
||||
#define DACC_CDR_DATA_Msk (0xffffffffu << DACC_CDR_DATA_Pos) /**< \brief (DACC_CDR) Data to Convert */
|
||||
#define DACC_CDR_DATA(value) ((DACC_CDR_DATA_Msk & ((value) << DACC_CDR_DATA_Pos)))
|
||||
/* -------- DACC_IER : (DACC Offset: 0x24) Interrupt Enable Register -------- */
|
||||
#define DACC_IER_TXRDY (0x1u << 0) /**< \brief (DACC_IER) Transmit Ready Interrupt Enable */
|
||||
#define DACC_IER_EOC (0x1u << 1) /**< \brief (DACC_IER) End of Conversion Interrupt Enable */
|
||||
#define DACC_IER_ENDTX (0x1u << 2) /**< \brief (DACC_IER) End of Transmit Buffer Interrupt Enable */
|
||||
#define DACC_IER_TXBUFE (0x1u << 3) /**< \brief (DACC_IER) Transmit Buffer Empty Interrupt Enable */
|
||||
/* -------- DACC_IDR : (DACC Offset: 0x28) Interrupt Disable Register -------- */
|
||||
#define DACC_IDR_TXRDY (0x1u << 0) /**< \brief (DACC_IDR) Transmit Ready Interrupt Disable. */
|
||||
#define DACC_IDR_EOC (0x1u << 1) /**< \brief (DACC_IDR) End of Conversion Interrupt Disable */
|
||||
#define DACC_IDR_ENDTX (0x1u << 2) /**< \brief (DACC_IDR) End of Transmit Buffer Interrupt Disable */
|
||||
#define DACC_IDR_TXBUFE (0x1u << 3) /**< \brief (DACC_IDR) Transmit Buffer Empty Interrupt Disable */
|
||||
/* -------- DACC_IMR : (DACC Offset: 0x2C) Interrupt Mask Register -------- */
|
||||
#define DACC_IMR_TXRDY (0x1u << 0) /**< \brief (DACC_IMR) Transmit Ready Interrupt Mask */
|
||||
#define DACC_IMR_EOC (0x1u << 1) /**< \brief (DACC_IMR) End of Conversion Interrupt Mask */
|
||||
#define DACC_IMR_ENDTX (0x1u << 2) /**< \brief (DACC_IMR) End of Transmit Buffer Interrupt Mask */
|
||||
#define DACC_IMR_TXBUFE (0x1u << 3) /**< \brief (DACC_IMR) Transmit Buffer Empty Interrupt Mask */
|
||||
/* -------- DACC_ISR : (DACC Offset: 0x30) Interrupt Status Register -------- */
|
||||
#define DACC_ISR_TXRDY (0x1u << 0) /**< \brief (DACC_ISR) Transmit Ready Interrupt Flag */
|
||||
#define DACC_ISR_EOC (0x1u << 1) /**< \brief (DACC_ISR) End of Conversion Interrupt Flag */
|
||||
#define DACC_ISR_ENDTX (0x1u << 2) /**< \brief (DACC_ISR) End of DMA Interrupt Flag */
|
||||
#define DACC_ISR_TXBUFE (0x1u << 3) /**< \brief (DACC_ISR) Transmit Buffer Empty */
|
||||
/* -------- DACC_ACR : (DACC Offset: 0x94) Analog Current Register -------- */
|
||||
#define DACC_ACR_IBCTLCH0_Pos 0
|
||||
#define DACC_ACR_IBCTLCH0_Msk (0x3u << DACC_ACR_IBCTLCH0_Pos) /**< \brief (DACC_ACR) Analog Output Current Control */
|
||||
#define DACC_ACR_IBCTLCH0(value) ((DACC_ACR_IBCTLCH0_Msk & ((value) << DACC_ACR_IBCTLCH0_Pos)))
|
||||
#define DACC_ACR_IBCTLCH1_Pos 2
|
||||
#define DACC_ACR_IBCTLCH1_Msk (0x3u << DACC_ACR_IBCTLCH1_Pos) /**< \brief (DACC_ACR) Analog Output Current Control */
|
||||
#define DACC_ACR_IBCTLCH1(value) ((DACC_ACR_IBCTLCH1_Msk & ((value) << DACC_ACR_IBCTLCH1_Pos)))
|
||||
#define DACC_ACR_IBCTLDACCORE_Pos 8
|
||||
#define DACC_ACR_IBCTLDACCORE_Msk (0x3u << DACC_ACR_IBCTLDACCORE_Pos) /**< \brief (DACC_ACR) Bias Current Control for DAC Core */
|
||||
#define DACC_ACR_IBCTLDACCORE(value) ((DACC_ACR_IBCTLDACCORE_Msk & ((value) << DACC_ACR_IBCTLDACCORE_Pos)))
|
||||
/* -------- DACC_WPMR : (DACC Offset: 0xE4) Write Protect Mode register -------- */
|
||||
#define DACC_WPMR_WPEN (0x1u << 0) /**< \brief (DACC_WPMR) Write Protect Enable */
|
||||
#define DACC_WPMR_WPKEY_Pos 8
|
||||
#define DACC_WPMR_WPKEY_Msk (0xffffffu << DACC_WPMR_WPKEY_Pos) /**< \brief (DACC_WPMR) Write Protect KEY */
|
||||
#define DACC_WPMR_WPKEY(value) ((DACC_WPMR_WPKEY_Msk & ((value) << DACC_WPMR_WPKEY_Pos)))
|
||||
/* -------- DACC_WPSR : (DACC Offset: 0xE8) Write Protect Status register -------- */
|
||||
#define DACC_WPSR_WPROTERR (0x1u << 0) /**< \brief (DACC_WPSR) Write protection error */
|
||||
#define DACC_WPSR_WPROTADDR_Pos 8
|
||||
#define DACC_WPSR_WPROTADDR_Msk (0xffu << DACC_WPSR_WPROTADDR_Pos) /**< \brief (DACC_WPSR) Write protection error address */
|
||||
/* -------- DACC_TPR : (DACC Offset: 0x108) Transmit Pointer Register -------- */
|
||||
#define DACC_TPR_TXPTR_Pos 0
|
||||
#define DACC_TPR_TXPTR_Msk (0xffffffffu << DACC_TPR_TXPTR_Pos) /**< \brief (DACC_TPR) Transmit Counter Register */
|
||||
#define DACC_TPR_TXPTR(value) ((DACC_TPR_TXPTR_Msk & ((value) << DACC_TPR_TXPTR_Pos)))
|
||||
/* -------- DACC_TCR : (DACC Offset: 0x10C) Transmit Counter Register -------- */
|
||||
#define DACC_TCR_TXCTR_Pos 0
|
||||
#define DACC_TCR_TXCTR_Msk (0xffffu << DACC_TCR_TXCTR_Pos) /**< \brief (DACC_TCR) Transmit Counter Register */
|
||||
#define DACC_TCR_TXCTR(value) ((DACC_TCR_TXCTR_Msk & ((value) << DACC_TCR_TXCTR_Pos)))
|
||||
/* -------- DACC_TNPR : (DACC Offset: 0x118) Transmit Next Pointer Register -------- */
|
||||
#define DACC_TNPR_TXNPTR_Pos 0
|
||||
#define DACC_TNPR_TXNPTR_Msk (0xffffffffu << DACC_TNPR_TXNPTR_Pos) /**< \brief (DACC_TNPR) Transmit Next Pointer */
|
||||
#define DACC_TNPR_TXNPTR(value) ((DACC_TNPR_TXNPTR_Msk & ((value) << DACC_TNPR_TXNPTR_Pos)))
|
||||
/* -------- DACC_TNCR : (DACC Offset: 0x11C) Transmit Next Counter Register -------- */
|
||||
#define DACC_TNCR_TXNCTR_Pos 0
|
||||
#define DACC_TNCR_TXNCTR_Msk (0xffffu << DACC_TNCR_TXNCTR_Pos) /**< \brief (DACC_TNCR) Transmit Counter Next */
|
||||
#define DACC_TNCR_TXNCTR(value) ((DACC_TNCR_TXNCTR_Msk & ((value) << DACC_TNCR_TXNCTR_Pos)))
|
||||
/* -------- DACC_PTCR : (DACC Offset: 0x120) Transfer Control Register -------- */
|
||||
#define DACC_PTCR_RXTEN (0x1u << 0) /**< \brief (DACC_PTCR) Receiver Transfer Enable */
|
||||
#define DACC_PTCR_RXTDIS (0x1u << 1) /**< \brief (DACC_PTCR) Receiver Transfer Disable */
|
||||
#define DACC_PTCR_TXTEN (0x1u << 8) /**< \brief (DACC_PTCR) Transmitter Transfer Enable */
|
||||
#define DACC_PTCR_TXTDIS (0x1u << 9) /**< \brief (DACC_PTCR) Transmitter Transfer Disable */
|
||||
/* -------- DACC_PTSR : (DACC Offset: 0x124) Transfer Status Register -------- */
|
||||
#define DACC_PTSR_RXTEN (0x1u << 0) /**< \brief (DACC_PTSR) Receiver Transfer Enable */
|
||||
#define DACC_PTSR_TXTEN (0x1u << 8) /**< \brief (DACC_PTSR) Transmitter Transfer Enable */
|
||||
|
||||
/*@}*/
|
||||
|
||||
|
||||
#endif /* _SAM3XA_DACC_COMPONENT_ */
|
||||
367
lib/cmsis-sam3x8e/include/component/component_dmac.h
Normal file
@@ -0,0 +1,367 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* SAM Software Package License
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2012, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following condition is met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _SAM3XA_DMAC_COMPONENT_
|
||||
#define _SAM3XA_DMAC_COMPONENT_
|
||||
|
||||
/* ============================================================================= */
|
||||
/** SOFTWARE API DEFINITION FOR DMA Controller */
|
||||
/* ============================================================================= */
|
||||
/** \addtogroup SAM3XA_DMAC DMA Controller */
|
||||
/*@{*/
|
||||
|
||||
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
|
||||
/** \brief DmacCh_num hardware registers */
|
||||
typedef struct {
|
||||
RwReg DMAC_SADDR; /**< \brief (DmacCh_num Offset: 0x0) DMAC Channel Source Address Register */
|
||||
RwReg DMAC_DADDR; /**< \brief (DmacCh_num Offset: 0x4) DMAC Channel Destination Address Register */
|
||||
RwReg DMAC_DSCR; /**< \brief (DmacCh_num Offset: 0x8) DMAC Channel Descriptor Address Register */
|
||||
RwReg DMAC_CTRLA; /**< \brief (DmacCh_num Offset: 0xC) DMAC Channel Control A Register */
|
||||
RwReg DMAC_CTRLB; /**< \brief (DmacCh_num Offset: 0x10) DMAC Channel Control B Register */
|
||||
RwReg DMAC_CFG; /**< \brief (DmacCh_num Offset: 0x14) DMAC Channel Configuration Register */
|
||||
RoReg Reserved1[4];
|
||||
} DmacCh_num;
|
||||
/** \brief Dmac hardware registers */
|
||||
#define DMACCH_NUM_NUMBER 6
|
||||
typedef struct {
|
||||
RwReg DMAC_GCFG; /**< \brief (Dmac Offset: 0x000) DMAC Global Configuration Register */
|
||||
RwReg DMAC_EN; /**< \brief (Dmac Offset: 0x004) DMAC Enable Register */
|
||||
RwReg DMAC_SREQ; /**< \brief (Dmac Offset: 0x008) DMAC Software Single Request Register */
|
||||
RwReg DMAC_CREQ; /**< \brief (Dmac Offset: 0x00C) DMAC Software Chunk Transfer Request Register */
|
||||
RwReg DMAC_LAST; /**< \brief (Dmac Offset: 0x010) DMAC Software Last Transfer Flag Register */
|
||||
RoReg Reserved1[1];
|
||||
WoReg DMAC_EBCIER; /**< \brief (Dmac Offset: 0x018) DMAC Error, Chained Buffer Transfer Completed Interrupt and Buffer Transfer Completed Interrupt Enable register. */
|
||||
WoReg DMAC_EBCIDR; /**< \brief (Dmac Offset: 0x01C) DMAC Error, Chained Buffer Transfer Completed Interrupt and Buffer Transfer Completed Interrupt Disable register. */
|
||||
RoReg DMAC_EBCIMR; /**< \brief (Dmac Offset: 0x020) DMAC Error, Chained Buffer Transfer Completed Interrupt and Buffer transfer completed Mask Register. */
|
||||
RoReg DMAC_EBCISR; /**< \brief (Dmac Offset: 0x024) DMAC Error, Chained Buffer Transfer Completed Interrupt and Buffer transfer completed Status Register. */
|
||||
WoReg DMAC_CHER; /**< \brief (Dmac Offset: 0x028) DMAC Channel Handler Enable Register */
|
||||
WoReg DMAC_CHDR; /**< \brief (Dmac Offset: 0x02C) DMAC Channel Handler Disable Register */
|
||||
RoReg DMAC_CHSR; /**< \brief (Dmac Offset: 0x030) DMAC Channel Handler Status Register */
|
||||
RoReg Reserved2[2];
|
||||
DmacCh_num DMAC_CH_NUM[DMACCH_NUM_NUMBER]; /**< \brief (Dmac Offset: 0x3C) ch_num = 0 .. 5 */
|
||||
RoReg Reserved3[46];
|
||||
RwReg DMAC_WPMR; /**< \brief (Dmac Offset: 0x1E4) DMAC Write Protect Mode Register */
|
||||
RoReg DMAC_WPSR; /**< \brief (Dmac Offset: 0x1E8) DMAC Write Protect Status Register */
|
||||
} Dmac;
|
||||
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
|
||||
/* -------- DMAC_GCFG : (DMAC Offset: 0x000) DMAC Global Configuration Register -------- */
|
||||
#define DMAC_GCFG_ARB_CFG (0x1u << 4) /**< \brief (DMAC_GCFG) Arbiter Configuration */
|
||||
#define DMAC_GCFG_ARB_CFG_FIXED (0x0u << 4) /**< \brief (DMAC_GCFG) Fixed priority arbiter. */
|
||||
#define DMAC_GCFG_ARB_CFG_ROUND_ROBIN (0x1u << 4) /**< \brief (DMAC_GCFG) Modified round robin arbiter. */
|
||||
/* -------- DMAC_EN : (DMAC Offset: 0x004) DMAC Enable Register -------- */
|
||||
#define DMAC_EN_ENABLE (0x1u << 0) /**< \brief (DMAC_EN) */
|
||||
/* -------- DMAC_SREQ : (DMAC Offset: 0x008) DMAC Software Single Request Register -------- */
|
||||
#define DMAC_SREQ_SSREQ0 (0x1u << 0) /**< \brief (DMAC_SREQ) Source Request */
|
||||
#define DMAC_SREQ_DSREQ0 (0x1u << 1) /**< \brief (DMAC_SREQ) Destination Request */
|
||||
#define DMAC_SREQ_SSREQ1 (0x1u << 2) /**< \brief (DMAC_SREQ) Source Request */
|
||||
#define DMAC_SREQ_DSREQ1 (0x1u << 3) /**< \brief (DMAC_SREQ) Destination Request */
|
||||
#define DMAC_SREQ_SSREQ2 (0x1u << 4) /**< \brief (DMAC_SREQ) Source Request */
|
||||
#define DMAC_SREQ_DSREQ2 (0x1u << 5) /**< \brief (DMAC_SREQ) Destination Request */
|
||||
#define DMAC_SREQ_SSREQ3 (0x1u << 6) /**< \brief (DMAC_SREQ) Source Request */
|
||||
#define DMAC_SREQ_DSREQ3 (0x1u << 7) /**< \brief (DMAC_SREQ) Destination Request */
|
||||
#define DMAC_SREQ_SSREQ4 (0x1u << 8) /**< \brief (DMAC_SREQ) Source Request */
|
||||
#define DMAC_SREQ_DSREQ4 (0x1u << 9) /**< \brief (DMAC_SREQ) Destination Request */
|
||||
#define DMAC_SREQ_SSREQ5 (0x1u << 10) /**< \brief (DMAC_SREQ) Source Request */
|
||||
#define DMAC_SREQ_DSREQ5 (0x1u << 11) /**< \brief (DMAC_SREQ) Destination Request */
|
||||
/* -------- DMAC_CREQ : (DMAC Offset: 0x00C) DMAC Software Chunk Transfer Request Register -------- */
|
||||
#define DMAC_CREQ_SCREQ0 (0x1u << 0) /**< \brief (DMAC_CREQ) Source Chunk Request */
|
||||
#define DMAC_CREQ_DCREQ0 (0x1u << 1) /**< \brief (DMAC_CREQ) Destination Chunk Request */
|
||||
#define DMAC_CREQ_SCREQ1 (0x1u << 2) /**< \brief (DMAC_CREQ) Source Chunk Request */
|
||||
#define DMAC_CREQ_DCREQ1 (0x1u << 3) /**< \brief (DMAC_CREQ) Destination Chunk Request */
|
||||
#define DMAC_CREQ_SCREQ2 (0x1u << 4) /**< \brief (DMAC_CREQ) Source Chunk Request */
|
||||
#define DMAC_CREQ_DCREQ2 (0x1u << 5) /**< \brief (DMAC_CREQ) Destination Chunk Request */
|
||||
#define DMAC_CREQ_SCREQ3 (0x1u << 6) /**< \brief (DMAC_CREQ) Source Chunk Request */
|
||||
#define DMAC_CREQ_DCREQ3 (0x1u << 7) /**< \brief (DMAC_CREQ) Destination Chunk Request */
|
||||
#define DMAC_CREQ_SCREQ4 (0x1u << 8) /**< \brief (DMAC_CREQ) Source Chunk Request */
|
||||
#define DMAC_CREQ_DCREQ4 (0x1u << 9) /**< \brief (DMAC_CREQ) Destination Chunk Request */
|
||||
#define DMAC_CREQ_SCREQ5 (0x1u << 10) /**< \brief (DMAC_CREQ) Source Chunk Request */
|
||||
#define DMAC_CREQ_DCREQ5 (0x1u << 11) /**< \brief (DMAC_CREQ) Destination Chunk Request */
|
||||
/* -------- DMAC_LAST : (DMAC Offset: 0x010) DMAC Software Last Transfer Flag Register -------- */
|
||||
#define DMAC_LAST_SLAST0 (0x1u << 0) /**< \brief (DMAC_LAST) Source Last */
|
||||
#define DMAC_LAST_DLAST0 (0x1u << 1) /**< \brief (DMAC_LAST) Destination Last */
|
||||
#define DMAC_LAST_SLAST1 (0x1u << 2) /**< \brief (DMAC_LAST) Source Last */
|
||||
#define DMAC_LAST_DLAST1 (0x1u << 3) /**< \brief (DMAC_LAST) Destination Last */
|
||||
#define DMAC_LAST_SLAST2 (0x1u << 4) /**< \brief (DMAC_LAST) Source Last */
|
||||
#define DMAC_LAST_DLAST2 (0x1u << 5) /**< \brief (DMAC_LAST) Destination Last */
|
||||
#define DMAC_LAST_SLAST3 (0x1u << 6) /**< \brief (DMAC_LAST) Source Last */
|
||||
#define DMAC_LAST_DLAST3 (0x1u << 7) /**< \brief (DMAC_LAST) Destination Last */
|
||||
#define DMAC_LAST_SLAST4 (0x1u << 8) /**< \brief (DMAC_LAST) Source Last */
|
||||
#define DMAC_LAST_DLAST4 (0x1u << 9) /**< \brief (DMAC_LAST) Destination Last */
|
||||
#define DMAC_LAST_SLAST5 (0x1u << 10) /**< \brief (DMAC_LAST) Source Last */
|
||||
#define DMAC_LAST_DLAST5 (0x1u << 11) /**< \brief (DMAC_LAST) Destination Last */
|
||||
/* -------- DMAC_EBCIER : (DMAC Offset: 0x018) DMAC Error, Chained Buffer Transfer Completed Interrupt and Buffer Transfer Completed Interrupt Enable register. -------- */
|
||||
#define DMAC_EBCIER_BTC0 (0x1u << 0) /**< \brief (DMAC_EBCIER) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIER_BTC1 (0x1u << 1) /**< \brief (DMAC_EBCIER) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIER_BTC2 (0x1u << 2) /**< \brief (DMAC_EBCIER) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIER_BTC3 (0x1u << 3) /**< \brief (DMAC_EBCIER) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIER_BTC4 (0x1u << 4) /**< \brief (DMAC_EBCIER) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIER_BTC5 (0x1u << 5) /**< \brief (DMAC_EBCIER) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIER_CBTC0 (0x1u << 8) /**< \brief (DMAC_EBCIER) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIER_CBTC1 (0x1u << 9) /**< \brief (DMAC_EBCIER) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIER_CBTC2 (0x1u << 10) /**< \brief (DMAC_EBCIER) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIER_CBTC3 (0x1u << 11) /**< \brief (DMAC_EBCIER) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIER_CBTC4 (0x1u << 12) /**< \brief (DMAC_EBCIER) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIER_CBTC5 (0x1u << 13) /**< \brief (DMAC_EBCIER) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIER_ERR0 (0x1u << 16) /**< \brief (DMAC_EBCIER) Access Error [5:0] */
|
||||
#define DMAC_EBCIER_ERR1 (0x1u << 17) /**< \brief (DMAC_EBCIER) Access Error [5:0] */
|
||||
#define DMAC_EBCIER_ERR2 (0x1u << 18) /**< \brief (DMAC_EBCIER) Access Error [5:0] */
|
||||
#define DMAC_EBCIER_ERR3 (0x1u << 19) /**< \brief (DMAC_EBCIER) Access Error [5:0] */
|
||||
#define DMAC_EBCIER_ERR4 (0x1u << 20) /**< \brief (DMAC_EBCIER) Access Error [5:0] */
|
||||
#define DMAC_EBCIER_ERR5 (0x1u << 21) /**< \brief (DMAC_EBCIER) Access Error [5:0] */
|
||||
/* -------- DMAC_EBCIDR : (DMAC Offset: 0x01C) DMAC Error, Chained Buffer Transfer Completed Interrupt and Buffer Transfer Completed Interrupt Disable register. -------- */
|
||||
#define DMAC_EBCIDR_BTC0 (0x1u << 0) /**< \brief (DMAC_EBCIDR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIDR_BTC1 (0x1u << 1) /**< \brief (DMAC_EBCIDR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIDR_BTC2 (0x1u << 2) /**< \brief (DMAC_EBCIDR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIDR_BTC3 (0x1u << 3) /**< \brief (DMAC_EBCIDR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIDR_BTC4 (0x1u << 4) /**< \brief (DMAC_EBCIDR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIDR_BTC5 (0x1u << 5) /**< \brief (DMAC_EBCIDR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIDR_CBTC0 (0x1u << 8) /**< \brief (DMAC_EBCIDR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIDR_CBTC1 (0x1u << 9) /**< \brief (DMAC_EBCIDR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIDR_CBTC2 (0x1u << 10) /**< \brief (DMAC_EBCIDR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIDR_CBTC3 (0x1u << 11) /**< \brief (DMAC_EBCIDR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIDR_CBTC4 (0x1u << 12) /**< \brief (DMAC_EBCIDR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIDR_CBTC5 (0x1u << 13) /**< \brief (DMAC_EBCIDR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIDR_ERR0 (0x1u << 16) /**< \brief (DMAC_EBCIDR) Access Error [5:0] */
|
||||
#define DMAC_EBCIDR_ERR1 (0x1u << 17) /**< \brief (DMAC_EBCIDR) Access Error [5:0] */
|
||||
#define DMAC_EBCIDR_ERR2 (0x1u << 18) /**< \brief (DMAC_EBCIDR) Access Error [5:0] */
|
||||
#define DMAC_EBCIDR_ERR3 (0x1u << 19) /**< \brief (DMAC_EBCIDR) Access Error [5:0] */
|
||||
#define DMAC_EBCIDR_ERR4 (0x1u << 20) /**< \brief (DMAC_EBCIDR) Access Error [5:0] */
|
||||
#define DMAC_EBCIDR_ERR5 (0x1u << 21) /**< \brief (DMAC_EBCIDR) Access Error [5:0] */
|
||||
/* -------- DMAC_EBCIMR : (DMAC Offset: 0x020) DMAC Error, Chained Buffer Transfer Completed Interrupt and Buffer transfer completed Mask Register. -------- */
|
||||
#define DMAC_EBCIMR_BTC0 (0x1u << 0) /**< \brief (DMAC_EBCIMR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIMR_BTC1 (0x1u << 1) /**< \brief (DMAC_EBCIMR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIMR_BTC2 (0x1u << 2) /**< \brief (DMAC_EBCIMR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIMR_BTC3 (0x1u << 3) /**< \brief (DMAC_EBCIMR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIMR_BTC4 (0x1u << 4) /**< \brief (DMAC_EBCIMR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIMR_BTC5 (0x1u << 5) /**< \brief (DMAC_EBCIMR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIMR_CBTC0 (0x1u << 8) /**< \brief (DMAC_EBCIMR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIMR_CBTC1 (0x1u << 9) /**< \brief (DMAC_EBCIMR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIMR_CBTC2 (0x1u << 10) /**< \brief (DMAC_EBCIMR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIMR_CBTC3 (0x1u << 11) /**< \brief (DMAC_EBCIMR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIMR_CBTC4 (0x1u << 12) /**< \brief (DMAC_EBCIMR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIMR_CBTC5 (0x1u << 13) /**< \brief (DMAC_EBCIMR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCIMR_ERR0 (0x1u << 16) /**< \brief (DMAC_EBCIMR) Access Error [5:0] */
|
||||
#define DMAC_EBCIMR_ERR1 (0x1u << 17) /**< \brief (DMAC_EBCIMR) Access Error [5:0] */
|
||||
#define DMAC_EBCIMR_ERR2 (0x1u << 18) /**< \brief (DMAC_EBCIMR) Access Error [5:0] */
|
||||
#define DMAC_EBCIMR_ERR3 (0x1u << 19) /**< \brief (DMAC_EBCIMR) Access Error [5:0] */
|
||||
#define DMAC_EBCIMR_ERR4 (0x1u << 20) /**< \brief (DMAC_EBCIMR) Access Error [5:0] */
|
||||
#define DMAC_EBCIMR_ERR5 (0x1u << 21) /**< \brief (DMAC_EBCIMR) Access Error [5:0] */
|
||||
/* -------- DMAC_EBCISR : (DMAC Offset: 0x024) DMAC Error, Chained Buffer Transfer Completed Interrupt and Buffer transfer completed Status Register. -------- */
|
||||
#define DMAC_EBCISR_BTC0 (0x1u << 0) /**< \brief (DMAC_EBCISR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCISR_BTC1 (0x1u << 1) /**< \brief (DMAC_EBCISR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCISR_BTC2 (0x1u << 2) /**< \brief (DMAC_EBCISR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCISR_BTC3 (0x1u << 3) /**< \brief (DMAC_EBCISR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCISR_BTC4 (0x1u << 4) /**< \brief (DMAC_EBCISR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCISR_BTC5 (0x1u << 5) /**< \brief (DMAC_EBCISR) Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCISR_CBTC0 (0x1u << 8) /**< \brief (DMAC_EBCISR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCISR_CBTC1 (0x1u << 9) /**< \brief (DMAC_EBCISR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCISR_CBTC2 (0x1u << 10) /**< \brief (DMAC_EBCISR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCISR_CBTC3 (0x1u << 11) /**< \brief (DMAC_EBCISR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCISR_CBTC4 (0x1u << 12) /**< \brief (DMAC_EBCISR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCISR_CBTC5 (0x1u << 13) /**< \brief (DMAC_EBCISR) Chained Buffer Transfer Completed [5:0] */
|
||||
#define DMAC_EBCISR_ERR0 (0x1u << 16) /**< \brief (DMAC_EBCISR) Access Error [5:0] */
|
||||
#define DMAC_EBCISR_ERR1 (0x1u << 17) /**< \brief (DMAC_EBCISR) Access Error [5:0] */
|
||||
#define DMAC_EBCISR_ERR2 (0x1u << 18) /**< \brief (DMAC_EBCISR) Access Error [5:0] */
|
||||
#define DMAC_EBCISR_ERR3 (0x1u << 19) /**< \brief (DMAC_EBCISR) Access Error [5:0] */
|
||||
#define DMAC_EBCISR_ERR4 (0x1u << 20) /**< \brief (DMAC_EBCISR) Access Error [5:0] */
|
||||
#define DMAC_EBCISR_ERR5 (0x1u << 21) /**< \brief (DMAC_EBCISR) Access Error [5:0] */
|
||||
/* -------- DMAC_CHER : (DMAC Offset: 0x028) DMAC Channel Handler Enable Register -------- */
|
||||
#define DMAC_CHER_ENA0 (0x1u << 0) /**< \brief (DMAC_CHER) Enable [5:0] */
|
||||
#define DMAC_CHER_ENA1 (0x1u << 1) /**< \brief (DMAC_CHER) Enable [5:0] */
|
||||
#define DMAC_CHER_ENA2 (0x1u << 2) /**< \brief (DMAC_CHER) Enable [5:0] */
|
||||
#define DMAC_CHER_ENA3 (0x1u << 3) /**< \brief (DMAC_CHER) Enable [5:0] */
|
||||
#define DMAC_CHER_ENA4 (0x1u << 4) /**< \brief (DMAC_CHER) Enable [5:0] */
|
||||
#define DMAC_CHER_ENA5 (0x1u << 5) /**< \brief (DMAC_CHER) Enable [5:0] */
|
||||
#define DMAC_CHER_SUSP0 (0x1u << 8) /**< \brief (DMAC_CHER) Suspend [5:0] */
|
||||
#define DMAC_CHER_SUSP1 (0x1u << 9) /**< \brief (DMAC_CHER) Suspend [5:0] */
|
||||
#define DMAC_CHER_SUSP2 (0x1u << 10) /**< \brief (DMAC_CHER) Suspend [5:0] */
|
||||
#define DMAC_CHER_SUSP3 (0x1u << 11) /**< \brief (DMAC_CHER) Suspend [5:0] */
|
||||
#define DMAC_CHER_SUSP4 (0x1u << 12) /**< \brief (DMAC_CHER) Suspend [5:0] */
|
||||
#define DMAC_CHER_SUSP5 (0x1u << 13) /**< \brief (DMAC_CHER) Suspend [5:0] */
|
||||
#define DMAC_CHER_KEEP0 (0x1u << 24) /**< \brief (DMAC_CHER) Keep on [5:0] */
|
||||
#define DMAC_CHER_KEEP1 (0x1u << 25) /**< \brief (DMAC_CHER) Keep on [5:0] */
|
||||
#define DMAC_CHER_KEEP2 (0x1u << 26) /**< \brief (DMAC_CHER) Keep on [5:0] */
|
||||
#define DMAC_CHER_KEEP3 (0x1u << 27) /**< \brief (DMAC_CHER) Keep on [5:0] */
|
||||
#define DMAC_CHER_KEEP4 (0x1u << 28) /**< \brief (DMAC_CHER) Keep on [5:0] */
|
||||
#define DMAC_CHER_KEEP5 (0x1u << 29) /**< \brief (DMAC_CHER) Keep on [5:0] */
|
||||
/* -------- DMAC_CHDR : (DMAC Offset: 0x02C) DMAC Channel Handler Disable Register -------- */
|
||||
#define DMAC_CHDR_DIS0 (0x1u << 0) /**< \brief (DMAC_CHDR) Disable [5:0] */
|
||||
#define DMAC_CHDR_DIS1 (0x1u << 1) /**< \brief (DMAC_CHDR) Disable [5:0] */
|
||||
#define DMAC_CHDR_DIS2 (0x1u << 2) /**< \brief (DMAC_CHDR) Disable [5:0] */
|
||||
#define DMAC_CHDR_DIS3 (0x1u << 3) /**< \brief (DMAC_CHDR) Disable [5:0] */
|
||||
#define DMAC_CHDR_DIS4 (0x1u << 4) /**< \brief (DMAC_CHDR) Disable [5:0] */
|
||||
#define DMAC_CHDR_DIS5 (0x1u << 5) /**< \brief (DMAC_CHDR) Disable [5:0] */
|
||||
#define DMAC_CHDR_RES0 (0x1u << 8) /**< \brief (DMAC_CHDR) Resume [5:0] */
|
||||
#define DMAC_CHDR_RES1 (0x1u << 9) /**< \brief (DMAC_CHDR) Resume [5:0] */
|
||||
#define DMAC_CHDR_RES2 (0x1u << 10) /**< \brief (DMAC_CHDR) Resume [5:0] */
|
||||
#define DMAC_CHDR_RES3 (0x1u << 11) /**< \brief (DMAC_CHDR) Resume [5:0] */
|
||||
#define DMAC_CHDR_RES4 (0x1u << 12) /**< \brief (DMAC_CHDR) Resume [5:0] */
|
||||
#define DMAC_CHDR_RES5 (0x1u << 13) /**< \brief (DMAC_CHDR) Resume [5:0] */
|
||||
/* -------- DMAC_CHSR : (DMAC Offset: 0x030) DMAC Channel Handler Status Register -------- */
|
||||
#define DMAC_CHSR_ENA0 (0x1u << 0) /**< \brief (DMAC_CHSR) Enable [5:0] */
|
||||
#define DMAC_CHSR_ENA1 (0x1u << 1) /**< \brief (DMAC_CHSR) Enable [5:0] */
|
||||
#define DMAC_CHSR_ENA2 (0x1u << 2) /**< \brief (DMAC_CHSR) Enable [5:0] */
|
||||
#define DMAC_CHSR_ENA3 (0x1u << 3) /**< \brief (DMAC_CHSR) Enable [5:0] */
|
||||
#define DMAC_CHSR_ENA4 (0x1u << 4) /**< \brief (DMAC_CHSR) Enable [5:0] */
|
||||
#define DMAC_CHSR_ENA5 (0x1u << 5) /**< \brief (DMAC_CHSR) Enable [5:0] */
|
||||
#define DMAC_CHSR_SUSP0 (0x1u << 8) /**< \brief (DMAC_CHSR) Suspend [5:0] */
|
||||
#define DMAC_CHSR_SUSP1 (0x1u << 9) /**< \brief (DMAC_CHSR) Suspend [5:0] */
|
||||
#define DMAC_CHSR_SUSP2 (0x1u << 10) /**< \brief (DMAC_CHSR) Suspend [5:0] */
|
||||
#define DMAC_CHSR_SUSP3 (0x1u << 11) /**< \brief (DMAC_CHSR) Suspend [5:0] */
|
||||
#define DMAC_CHSR_SUSP4 (0x1u << 12) /**< \brief (DMAC_CHSR) Suspend [5:0] */
|
||||
#define DMAC_CHSR_SUSP5 (0x1u << 13) /**< \brief (DMAC_CHSR) Suspend [5:0] */
|
||||
#define DMAC_CHSR_EMPT0 (0x1u << 16) /**< \brief (DMAC_CHSR) Empty [5:0] */
|
||||
#define DMAC_CHSR_EMPT1 (0x1u << 17) /**< \brief (DMAC_CHSR) Empty [5:0] */
|
||||
#define DMAC_CHSR_EMPT2 (0x1u << 18) /**< \brief (DMAC_CHSR) Empty [5:0] */
|
||||
#define DMAC_CHSR_EMPT3 (0x1u << 19) /**< \brief (DMAC_CHSR) Empty [5:0] */
|
||||
#define DMAC_CHSR_EMPT4 (0x1u << 20) /**< \brief (DMAC_CHSR) Empty [5:0] */
|
||||
#define DMAC_CHSR_EMPT5 (0x1u << 21) /**< \brief (DMAC_CHSR) Empty [5:0] */
|
||||
#define DMAC_CHSR_STAL0 (0x1u << 24) /**< \brief (DMAC_CHSR) Stalled [5:0] */
|
||||
#define DMAC_CHSR_STAL1 (0x1u << 25) /**< \brief (DMAC_CHSR) Stalled [5:0] */
|
||||
#define DMAC_CHSR_STAL2 (0x1u << 26) /**< \brief (DMAC_CHSR) Stalled [5:0] */
|
||||
#define DMAC_CHSR_STAL3 (0x1u << 27) /**< \brief (DMAC_CHSR) Stalled [5:0] */
|
||||
#define DMAC_CHSR_STAL4 (0x1u << 28) /**< \brief (DMAC_CHSR) Stalled [5:0] */
|
||||
#define DMAC_CHSR_STAL5 (0x1u << 29) /**< \brief (DMAC_CHSR) Stalled [5:0] */
|
||||
/* -------- DMAC_SADDR : (DMAC Offset: N/A) DMAC Channel Source Address Register -------- */
|
||||
#define DMAC_SADDR_SADDR_Pos 0
|
||||
#define DMAC_SADDR_SADDR_Msk (0xffffffffu << DMAC_SADDR_SADDR_Pos) /**< \brief (DMAC_SADDR) Channel x Source Address */
|
||||
#define DMAC_SADDR_SADDR(value) ((DMAC_SADDR_SADDR_Msk & ((value) << DMAC_SADDR_SADDR_Pos)))
|
||||
/* -------- DMAC_DADDR : (DMAC Offset: N/A) DMAC Channel Destination Address Register -------- */
|
||||
#define DMAC_DADDR_DADDR_Pos 0
|
||||
#define DMAC_DADDR_DADDR_Msk (0xffffffffu << DMAC_DADDR_DADDR_Pos) /**< \brief (DMAC_DADDR) Channel x Destination Address */
|
||||
#define DMAC_DADDR_DADDR(value) ((DMAC_DADDR_DADDR_Msk & ((value) << DMAC_DADDR_DADDR_Pos)))
|
||||
/* -------- DMAC_DSCR : (DMAC Offset: N/A) DMAC Channel Descriptor Address Register -------- */
|
||||
#define DMAC_DSCR_DSCR_Pos 2
|
||||
#define DMAC_DSCR_DSCR_Msk (0x3fffffffu << DMAC_DSCR_DSCR_Pos) /**< \brief (DMAC_DSCR) Buffer Transfer Descriptor Address */
|
||||
#define DMAC_DSCR_DSCR(value) ((DMAC_DSCR_DSCR_Msk & ((value) << DMAC_DSCR_DSCR_Pos)))
|
||||
/* -------- DMAC_CTRLA : (DMAC Offset: N/A) DMAC Channel Control A Register -------- */
|
||||
#define DMAC_CTRLA_BTSIZE_Pos 0
|
||||
#define DMAC_CTRLA_BTSIZE_Msk (0xffffu << DMAC_CTRLA_BTSIZE_Pos) /**< \brief (DMAC_CTRLA) Buffer Transfer Size */
|
||||
#define DMAC_CTRLA_BTSIZE(value) ((DMAC_CTRLA_BTSIZE_Msk & ((value) << DMAC_CTRLA_BTSIZE_Pos)))
|
||||
#define DMAC_CTRLA_SCSIZE_Pos 16
|
||||
#define DMAC_CTRLA_SCSIZE_Msk (0x7u << DMAC_CTRLA_SCSIZE_Pos) /**< \brief (DMAC_CTRLA) Source Chunk Transfer Size. */
|
||||
#define DMAC_CTRLA_SCSIZE_CHK_1 (0x0u << 16) /**< \brief (DMAC_CTRLA) 1 data transferred */
|
||||
#define DMAC_CTRLA_SCSIZE_CHK_4 (0x1u << 16) /**< \brief (DMAC_CTRLA) 4 data transferred */
|
||||
#define DMAC_CTRLA_SCSIZE_CHK_8 (0x2u << 16) /**< \brief (DMAC_CTRLA) 8 data transferred */
|
||||
#define DMAC_CTRLA_SCSIZE_CHK_16 (0x3u << 16) /**< \brief (DMAC_CTRLA) 16 data transferred */
|
||||
#define DMAC_CTRLA_SCSIZE_CHK_32 (0x4u << 16) /**< \brief (DMAC_CTRLA) 32 data transferred */
|
||||
#define DMAC_CTRLA_SCSIZE_CHK_64 (0x5u << 16) /**< \brief (DMAC_CTRLA) 64 data transferred */
|
||||
#define DMAC_CTRLA_SCSIZE_CHK_128 (0x6u << 16) /**< \brief (DMAC_CTRLA) 128 data transferred */
|
||||
#define DMAC_CTRLA_SCSIZE_CHK_256 (0x7u << 16) /**< \brief (DMAC_CTRLA) 256 data transferred */
|
||||
#define DMAC_CTRLA_DCSIZE_Pos 20
|
||||
#define DMAC_CTRLA_DCSIZE_Msk (0x7u << DMAC_CTRLA_DCSIZE_Pos) /**< \brief (DMAC_CTRLA) Destination Chunk Transfer Size */
|
||||
#define DMAC_CTRLA_DCSIZE_CHK_1 (0x0u << 20) /**< \brief (DMAC_CTRLA) 1 data transferred */
|
||||
#define DMAC_CTRLA_DCSIZE_CHK_4 (0x1u << 20) /**< \brief (DMAC_CTRLA) 4 data transferred */
|
||||
#define DMAC_CTRLA_DCSIZE_CHK_8 (0x2u << 20) /**< \brief (DMAC_CTRLA) 8 data transferred */
|
||||
#define DMAC_CTRLA_DCSIZE_CHK_16 (0x3u << 20) /**< \brief (DMAC_CTRLA) 16 data transferred */
|
||||
#define DMAC_CTRLA_DCSIZE_CHK_32 (0x4u << 20) /**< \brief (DMAC_CTRLA) 32 data transferred */
|
||||
#define DMAC_CTRLA_DCSIZE_CHK_64 (0x5u << 20) /**< \brief (DMAC_CTRLA) 64 data transferred */
|
||||
#define DMAC_CTRLA_DCSIZE_CHK_128 (0x6u << 20) /**< \brief (DMAC_CTRLA) 128 data transferred */
|
||||
#define DMAC_CTRLA_DCSIZE_CHK_256 (0x7u << 20) /**< \brief (DMAC_CTRLA) 256 data transferred */
|
||||
#define DMAC_CTRLA_SRC_WIDTH_Pos 24
|
||||
#define DMAC_CTRLA_SRC_WIDTH_Msk (0x3u << DMAC_CTRLA_SRC_WIDTH_Pos) /**< \brief (DMAC_CTRLA) Transfer Width for the Source */
|
||||
#define DMAC_CTRLA_SRC_WIDTH_BYTE (0x0u << 24) /**< \brief (DMAC_CTRLA) the transfer size is set to 8-bit width */
|
||||
#define DMAC_CTRLA_SRC_WIDTH_HALF_WORD (0x1u << 24) /**< \brief (DMAC_CTRLA) the transfer size is set to 16-bit width */
|
||||
#define DMAC_CTRLA_SRC_WIDTH_WORD (0x2u << 24) /**< \brief (DMAC_CTRLA) the transfer size is set to 32-bit width */
|
||||
#define DMAC_CTRLA_DST_WIDTH_Pos 28
|
||||
#define DMAC_CTRLA_DST_WIDTH_Msk (0x3u << DMAC_CTRLA_DST_WIDTH_Pos) /**< \brief (DMAC_CTRLA) Transfer Width for the Destination */
|
||||
#define DMAC_CTRLA_DST_WIDTH_BYTE (0x0u << 28) /**< \brief (DMAC_CTRLA) the transfer size is set to 8-bit width */
|
||||
#define DMAC_CTRLA_DST_WIDTH_HALF_WORD (0x1u << 28) /**< \brief (DMAC_CTRLA) the transfer size is set to 16-bit width */
|
||||
#define DMAC_CTRLA_DST_WIDTH_WORD (0x2u << 28) /**< \brief (DMAC_CTRLA) the transfer size is set to 32-bit width */
|
||||
#define DMAC_CTRLA_DONE (0x1u << 31) /**< \brief (DMAC_CTRLA) */
|
||||
/* -------- DMAC_CTRLB : (DMAC Offset: N/A) DMAC Channel Control B Register -------- */
|
||||
#define DMAC_CTRLB_SRC_DSCR (0x1u << 16) /**< \brief (DMAC_CTRLB) Source Address Descriptor */
|
||||
#define DMAC_CTRLB_SRC_DSCR_FETCH_FROM_MEM (0x0u << 16) /**< \brief (DMAC_CTRLB) Source address is updated when the descriptor is fetched from the memory. */
|
||||
#define DMAC_CTRLB_SRC_DSCR_FETCH_DISABLE (0x1u << 16) /**< \brief (DMAC_CTRLB) Buffer Descriptor Fetch operation is disabled for the source. */
|
||||
#define DMAC_CTRLB_DST_DSCR (0x1u << 20) /**< \brief (DMAC_CTRLB) Destination Address Descriptor */
|
||||
#define DMAC_CTRLB_DST_DSCR_FETCH_FROM_MEM (0x0u << 20) /**< \brief (DMAC_CTRLB) Destination address is updated when the descriptor is fetched from the memory. */
|
||||
#define DMAC_CTRLB_DST_DSCR_FETCH_DISABLE (0x1u << 20) /**< \brief (DMAC_CTRLB) Buffer Descriptor Fetch operation is disabled for the destination. */
|
||||
#define DMAC_CTRLB_FC_Pos 21
|
||||
#define DMAC_CTRLB_FC_Msk (0x7u << DMAC_CTRLB_FC_Pos) /**< \brief (DMAC_CTRLB) Flow Control */
|
||||
#define DMAC_CTRLB_FC_MEM2MEM_DMA_FC (0x0u << 21) /**< \brief (DMAC_CTRLB) Memory-to-Memory Transfer DMAC is flow controller */
|
||||
#define DMAC_CTRLB_FC_MEM2PER_DMA_FC (0x1u << 21) /**< \brief (DMAC_CTRLB) Memory-to-Peripheral Transfer DMAC is flow controller */
|
||||
#define DMAC_CTRLB_FC_PER2MEM_DMA_FC (0x2u << 21) /**< \brief (DMAC_CTRLB) Peripheral-to-Memory Transfer DMAC is flow controller */
|
||||
#define DMAC_CTRLB_FC_PER2PER_DMA_FC (0x3u << 21) /**< \brief (DMAC_CTRLB) Peripheral-to-Peripheral Transfer DMAC is flow controller */
|
||||
#define DMAC_CTRLB_SRC_INCR_Pos 24
|
||||
#define DMAC_CTRLB_SRC_INCR_Msk (0x3u << DMAC_CTRLB_SRC_INCR_Pos) /**< \brief (DMAC_CTRLB) Incrementing, Decrementing or Fixed Address for the Source */
|
||||
#define DMAC_CTRLB_SRC_INCR_INCREMENTING (0x0u << 24) /**< \brief (DMAC_CTRLB) The source address is incremented */
|
||||
#define DMAC_CTRLB_SRC_INCR_DECREMENTING (0x1u << 24) /**< \brief (DMAC_CTRLB) The source address is decremented */
|
||||
#define DMAC_CTRLB_SRC_INCR_FIXED (0x2u << 24) /**< \brief (DMAC_CTRLB) The source address remains unchanged */
|
||||
#define DMAC_CTRLB_DST_INCR_Pos 28
|
||||
#define DMAC_CTRLB_DST_INCR_Msk (0x3u << DMAC_CTRLB_DST_INCR_Pos) /**< \brief (DMAC_CTRLB) Incrementing, Decrementing or Fixed Address for the Destination */
|
||||
#define DMAC_CTRLB_DST_INCR_INCREMENTING (0x0u << 28) /**< \brief (DMAC_CTRLB) The destination address is incremented */
|
||||
#define DMAC_CTRLB_DST_INCR_DECREMENTING (0x1u << 28) /**< \brief (DMAC_CTRLB) The destination address is decremented */
|
||||
#define DMAC_CTRLB_DST_INCR_FIXED (0x2u << 28) /**< \brief (DMAC_CTRLB) The destination address remains unchanged */
|
||||
#define DMAC_CTRLB_IEN (0x1u << 30) /**< \brief (DMAC_CTRLB) */
|
||||
/* -------- DMAC_CFG : (DMAC Offset: N/A) DMAC Channel Configuration Register -------- */
|
||||
#define DMAC_CFG_SRC_PER_Pos 0
|
||||
#define DMAC_CFG_SRC_PER_Msk (0xfu << DMAC_CFG_SRC_PER_Pos) /**< \brief (DMAC_CFG) Source with Peripheral identifier */
|
||||
#define DMAC_CFG_SRC_PER(value) ((DMAC_CFG_SRC_PER_Msk & ((value) << DMAC_CFG_SRC_PER_Pos)))
|
||||
#define DMAC_CFG_DST_PER_Pos 4
|
||||
#define DMAC_CFG_DST_PER_Msk (0xfu << DMAC_CFG_DST_PER_Pos) /**< \brief (DMAC_CFG) Destination with Peripheral identifier */
|
||||
#define DMAC_CFG_DST_PER(value) ((DMAC_CFG_DST_PER_Msk & ((value) << DMAC_CFG_DST_PER_Pos)))
|
||||
#define DMAC_CFG_SRC_H2SEL (0x1u << 9) /**< \brief (DMAC_CFG) Software or Hardware Selection for the Source */
|
||||
#define DMAC_CFG_SRC_H2SEL_SW (0x0u << 9) /**< \brief (DMAC_CFG) Software handshaking interface is used to trigger a transfer request. */
|
||||
#define DMAC_CFG_SRC_H2SEL_HW (0x1u << 9) /**< \brief (DMAC_CFG) Hardware handshaking interface is used to trigger a transfer request. */
|
||||
#define DMAC_CFG_DST_H2SEL (0x1u << 13) /**< \brief (DMAC_CFG) Software or Hardware Selection for the Destination */
|
||||
#define DMAC_CFG_DST_H2SEL_SW (0x0u << 13) /**< \brief (DMAC_CFG) Software handshaking interface is used to trigger a transfer request. */
|
||||
#define DMAC_CFG_DST_H2SEL_HW (0x1u << 13) /**< \brief (DMAC_CFG) Hardware handshaking interface is used to trigger a transfer request. */
|
||||
#define DMAC_CFG_SOD (0x1u << 16) /**< \brief (DMAC_CFG) Stop On Done */
|
||||
#define DMAC_CFG_SOD_DISABLE (0x0u << 16) /**< \brief (DMAC_CFG) STOP ON DONE disabled, the descriptor fetch operation ignores DONE Field of CTRLA register. */
|
||||
#define DMAC_CFG_SOD_ENABLE (0x1u << 16) /**< \brief (DMAC_CFG) STOP ON DONE activated, the DMAC module is automatically disabled if DONE FIELD is set to 1. */
|
||||
#define DMAC_CFG_LOCK_IF (0x1u << 20) /**< \brief (DMAC_CFG) Interface Lock */
|
||||
#define DMAC_CFG_LOCK_IF_DISABLE (0x0u << 20) /**< \brief (DMAC_CFG) Interface Lock capability is disabled */
|
||||
#define DMAC_CFG_LOCK_IF_ENABLE (0x1u << 20) /**< \brief (DMAC_CFG) Interface Lock capability is enabled */
|
||||
#define DMAC_CFG_LOCK_B (0x1u << 21) /**< \brief (DMAC_CFG) Bus Lock */
|
||||
#define DMAC_CFG_LOCK_B_DISABLE (0x0u << 21) /**< \brief (DMAC_CFG) AHB Bus Locking capability is disabled. */
|
||||
#define DMAC_CFG_LOCK_IF_L (0x1u << 22) /**< \brief (DMAC_CFG) Master Interface Arbiter Lock */
|
||||
#define DMAC_CFG_LOCK_IF_L_CHUNK (0x0u << 22) /**< \brief (DMAC_CFG) The Master Interface Arbiter is locked by the channel x for a chunk transfer. */
|
||||
#define DMAC_CFG_LOCK_IF_L_BUFFER (0x1u << 22) /**< \brief (DMAC_CFG) The Master Interface Arbiter is locked by the channel x for a buffer transfer. */
|
||||
#define DMAC_CFG_AHB_PROT_Pos 24
|
||||
#define DMAC_CFG_AHB_PROT_Msk (0x7u << DMAC_CFG_AHB_PROT_Pos) /**< \brief (DMAC_CFG) AHB Protection */
|
||||
#define DMAC_CFG_AHB_PROT(value) ((DMAC_CFG_AHB_PROT_Msk & ((value) << DMAC_CFG_AHB_PROT_Pos)))
|
||||
#define DMAC_CFG_FIFOCFG_Pos 28
|
||||
#define DMAC_CFG_FIFOCFG_Msk (0x3u << DMAC_CFG_FIFOCFG_Pos) /**< \brief (DMAC_CFG) FIFO Configuration */
|
||||
#define DMAC_CFG_FIFOCFG_ALAP_CFG (0x0u << 28) /**< \brief (DMAC_CFG) The largest defined length AHB burst is performed on the destination AHB interface. */
|
||||
#define DMAC_CFG_FIFOCFG_HALF_CFG (0x1u << 28) /**< \brief (DMAC_CFG) When half FIFO size is available/filled, a source/destination request is serviced. */
|
||||
#define DMAC_CFG_FIFOCFG_ASAP_CFG (0x2u << 28) /**< \brief (DMAC_CFG) When there is enough space/data available to perform a single AHB access, then the request is serviced. */
|
||||
/* -------- DMAC_WPMR : (DMAC Offset: 0x1E4) DMAC Write Protect Mode Register -------- */
|
||||
#define DMAC_WPMR_WPEN (0x1u << 0) /**< \brief (DMAC_WPMR) Write Protect Enable */
|
||||
#define DMAC_WPMR_WPKEY_Pos 8
|
||||
#define DMAC_WPMR_WPKEY_Msk (0xffffffu << DMAC_WPMR_WPKEY_Pos) /**< \brief (DMAC_WPMR) Write Protect KEY */
|
||||
#define DMAC_WPMR_WPKEY(value) ((DMAC_WPMR_WPKEY_Msk & ((value) << DMAC_WPMR_WPKEY_Pos)))
|
||||
/* -------- DMAC_WPSR : (DMAC Offset: 0x1E8) DMAC Write Protect Status Register -------- */
|
||||
#define DMAC_WPSR_WPVS (0x1u << 0) /**< \brief (DMAC_WPSR) Write Protect Violation Status */
|
||||
#define DMAC_WPSR_WPVSRC_Pos 8
|
||||
#define DMAC_WPSR_WPVSRC_Msk (0xffffu << DMAC_WPSR_WPVSRC_Pos) /**< \brief (DMAC_WPSR) Write Protect Violation Source */
|
||||
|
||||
/*@}*/
|
||||
|
||||
|
||||
#endif /* _SAM3XA_DMAC_COMPONENT_ */
|
||||
76
lib/cmsis-sam3x8e/include/component/component_efc.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* SAM Software Package License
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2012, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following condition is met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _SAM3XA_EFC_COMPONENT_
|
||||
#define _SAM3XA_EFC_COMPONENT_
|
||||
|
||||
/* ============================================================================= */
|
||||
/** SOFTWARE API DEFINITION FOR Embedded Flash Controller */
|
||||
/* ============================================================================= */
|
||||
/** \addtogroup SAM3XA_EFC Embedded Flash Controller */
|
||||
/*@{*/
|
||||
|
||||
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
|
||||
/** \brief Efc hardware registers */
|
||||
typedef struct {
|
||||
RwReg EEFC_FMR; /**< \brief (Efc Offset: 0x00) EEFC Flash Mode Register */
|
||||
WoReg EEFC_FCR; /**< \brief (Efc Offset: 0x04) EEFC Flash Command Register */
|
||||
RoReg EEFC_FSR; /**< \brief (Efc Offset: 0x08) EEFC Flash Status Register */
|
||||
RoReg EEFC_FRR; /**< \brief (Efc Offset: 0x0C) EEFC Flash Result Register */
|
||||
} Efc;
|
||||
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
|
||||
/* -------- EEFC_FMR : (EFC Offset: 0x00) EEFC Flash Mode Register -------- */
|
||||
#define EEFC_FMR_FRDY (0x1u << 0) /**< \brief (EEFC_FMR) Ready Interrupt Enable */
|
||||
#define EEFC_FMR_FWS_Pos 8
|
||||
#define EEFC_FMR_FWS_Msk (0xfu << EEFC_FMR_FWS_Pos) /**< \brief (EEFC_FMR) Flash Wait State */
|
||||
#define EEFC_FMR_FWS(value) ((EEFC_FMR_FWS_Msk & ((value) << EEFC_FMR_FWS_Pos)))
|
||||
#define EEFC_FMR_SCOD (0x1u << 16) /**< \brief (EEFC_FMR) Sequential Code Optimization Disable */
|
||||
#define EEFC_FMR_FAM (0x1u << 24) /**< \brief (EEFC_FMR) Flash Access Mode */
|
||||
/* -------- EEFC_FCR : (EFC Offset: 0x04) EEFC Flash Command Register -------- */
|
||||
#define EEFC_FCR_FCMD_Pos 0
|
||||
#define EEFC_FCR_FCMD_Msk (0xffu << EEFC_FCR_FCMD_Pos) /**< \brief (EEFC_FCR) Flash Command */
|
||||
#define EEFC_FCR_FCMD(value) ((EEFC_FCR_FCMD_Msk & ((value) << EEFC_FCR_FCMD_Pos)))
|
||||
#define EEFC_FCR_FARG_Pos 8
|
||||
#define EEFC_FCR_FARG_Msk (0xffffu << EEFC_FCR_FARG_Pos) /**< \brief (EEFC_FCR) Flash Command Argument */
|
||||
#define EEFC_FCR_FARG(value) ((EEFC_FCR_FARG_Msk & ((value) << EEFC_FCR_FARG_Pos)))
|
||||
#define EEFC_FCR_FKEY_Pos 24
|
||||
#define EEFC_FCR_FKEY_Msk (0xffu << EEFC_FCR_FKEY_Pos) /**< \brief (EEFC_FCR) Flash Writing Protection Key */
|
||||
#define EEFC_FCR_FKEY(value) ((EEFC_FCR_FKEY_Msk & ((value) << EEFC_FCR_FKEY_Pos)))
|
||||
/* -------- EEFC_FSR : (EFC Offset: 0x08) EEFC Flash Status Register -------- */
|
||||
#define EEFC_FSR_FRDY (0x1u << 0) /**< \brief (EEFC_FSR) Flash Ready Status */
|
||||
#define EEFC_FSR_FCMDE (0x1u << 1) /**< \brief (EEFC_FSR) Flash Command Error Status */
|
||||
#define EEFC_FSR_FLOCKE (0x1u << 2) /**< \brief (EEFC_FSR) Flash Lock Error Status */
|
||||
/* -------- EEFC_FRR : (EFC Offset: 0x0C) EEFC Flash Result Register -------- */
|
||||
#define EEFC_FRR_FVALUE_Pos 0
|
||||
#define EEFC_FRR_FVALUE_Msk (0xffffffffu << EEFC_FRR_FVALUE_Pos) /**< \brief (EEFC_FRR) Flash Result Value */
|
||||
|
||||
/*@}*/
|
||||
|
||||
|
||||
#endif /* _SAM3XA_EFC_COMPONENT_ */
|
||||