Compare commits
604 Commits
26f8e7ae99
...
jenkins
| Author | SHA1 | Date | |
|---|---|---|---|
| 4efa5ae797 | |||
| 5e90cd39fa | |||
| 015028bde2 | |||
| 4e6e5db2c3 | |||
| a2bcd37800 | |||
| ed936cf9f9 | |||
| e595e398d4 | |||
| 86446e1b22 | |||
| b26233d5e3 | |||
| 0ab13edced | |||
| 2bc2c0c670 | |||
| aad9be9905 | |||
| 6f2b6e0839 | |||
| 45145c1f36 | |||
| 1722ba7e5d | |||
| 7a44a383ff | |||
| 7a2c77a83e | |||
| c8e3bf5de2 | |||
| 400c77f11c | |||
| 7be6047e04 | |||
| 2ab7257fe6 | |||
| 376d9c7aaf | |||
| 2a6a98deac | |||
| 20b460cd5a | |||
| ae60c30919 | |||
| c6fcd3154f | |||
| a7394ef170 | |||
| 01abb3e085 | |||
| d63761d016 | |||
| d468e52dea | |||
| 5a1deeb9ee | |||
| 809c86a618 | |||
| 88a4bb97a5 | |||
| 4a98d41623 | |||
| 836c7af163 | |||
| e3670434ca | |||
| a802b5c1b5 | |||
| ffb544e21d | |||
| e4ebf9ec3f | |||
| 6e89c0e098 | |||
| fdb1c6e893 | |||
| e753504ae3 | |||
| 2fa12cda60 | |||
| 17609a2491 | |||
| 1e870972e3 | |||
| 864c3fa0f2 | |||
| 9c872f6746 | |||
| 0bf587b8bb | |||
| 8a9bd0df6e | |||
| baf6b67658 | |||
| 41fbb83b46 | |||
| f4fcaf1e3a | |||
| 67932bf465 | |||
| 632973cdac | |||
| 9558d4bb45 | |||
| 90c6165278 | |||
| 8c0cfa4993 | |||
| 5f91659d04 | |||
| fdb3ceb3e9 | |||
| 7e3d2d1d0b | |||
| ef2cd6acfe | |||
| d9bd434dc6 | |||
| 4ed2203b35 | |||
| 0b1ce8b614 | |||
| bc5e4c14df | |||
| 43abca4c51 | |||
| 00c796c58f | |||
| 4d0f963585 | |||
| 708fdea058 | |||
| ebb1383957 | |||
| 3345004213 | |||
| afadd539c8 | |||
| 71315b7c92 | |||
| 410a5d4dd1 | |||
| 528db7a581 | |||
| 384e127085 | |||
| fe0bde5c32 | |||
| 2beaccbe32 | |||
| b6760ff426 | |||
| 1b2dac21f2 | |||
| 97f154d3b9 | |||
| ee5dda4a33 | |||
| afb8e93b13 | |||
| 9bd0dd194b | |||
| 6322c3728b | |||
| 174bf4220e | |||
| 566436201e | |||
| 61e3b58992 | |||
| 01b445a0fb | |||
| 5437a323c3 | |||
| 28e42d3306 | |||
| 08606689b4 | |||
| 5776feee85 | |||
| 6273c68821 | |||
| 3381840bba | |||
| cf35ba735f | |||
| 3f31acfada | |||
| 77251cc1bc | |||
| f2972903d5 | |||
| 31b17dfd8d | |||
| 9f1a791be2 | |||
| 54416a6350 | |||
| 9c94428144 | |||
| 81155887de | |||
| 8309cef5ec | |||
| 1a76a69b6d | |||
| e50e3f0ace | |||
| 5fb1612773 | |||
| 72735915ee | |||
| 08ec458e8f | |||
| d962110823 | |||
| bfdc3d3246 | |||
| dca839ce2e | |||
| eea0826c7b | |||
| 6e5627fde2 | |||
| 0f239dc39d | |||
| 08eee66d30 | |||
| 7c9d296e34 | |||
| 533656ca28 | |||
| d146b10569 | |||
| 8576bf4231 | |||
| 6ebd74cb31 | |||
| 46125ba752 | |||
| 6c9f90c986 | |||
| 74defd5384 | |||
| 5deac33949 | |||
| 666353e3b7 | |||
| df40ab1be7 | |||
| 4c3574c2e2 | |||
| 289f49204d | |||
| 4bc98e6baf | |||
| e50ce0d541 | |||
| 78b63c853f | |||
| a25b249d77 | |||
| e815442617 | |||
| 60104df30e | |||
| 5ab911b4b6 | |||
| 9c37e083a0 | |||
| 08427cc589 | |||
| 62d745bd3a | |||
| ba6e0880b4 | |||
| ec2c23c9f7 | |||
| 6a71416d2a | |||
| 1ecd5edd93 | |||
| 1b4eba1871 | |||
| 13e7cbfd81 | |||
| 857838f293 | |||
| ae97a69d26 | |||
| 001f2be176 | |||
| 1797dac60b | |||
| e3e4a6d926 | |||
| dca696cd6a | |||
| 93ff4959a2 | |||
| b1a7af28a2 | |||
| b560a91673 | |||
| 64a97fa048 | |||
| d1b8e91674 | |||
| 0fc35db53d | |||
| 8a764f599b | |||
| b9dfe35652 | |||
| 694a78982a | |||
| 59ff842f56 | |||
| 7c5b60ec6b | |||
| e614eaa23b | |||
| 50ad31d58a | |||
| 64bb06882f | |||
| 0b01be9840 | |||
| ba9247be69 | |||
| e7aa714976 | |||
| 125b41de44 | |||
| 4c1797aa24 | |||
| 20a65fd7f9 | |||
| 67b079fe33 | |||
| a5c9350835 | |||
| cc545bfc69 | |||
| f6fb541924 | |||
| 86a0b2087e | |||
| 55f35a5009 | |||
| 870c228e37 | |||
| 2fcc5d6a9f | |||
| 52272938b7 | |||
| 58c72fb2bc | |||
| 99d96fb426 | |||
| 24651fa74d | |||
| 56b5ddc209 | |||
| 94726e1466 | |||
| d6356de1b6 | |||
| 69ff13a991 | |||
| bbfcd429fe | |||
| 3a07347f48 | |||
| 0e233a257c | |||
| 95bd606dd8 | |||
| 6e3f90d38e | |||
| 82cab98f59 | |||
| 2d29857c2f | |||
| bea8e2df74 | |||
| 7c6205d20a | |||
| 0e114d1344 | |||
| 2c3c1c9861 | |||
| 75f9c58c54 | |||
| 44c861a245 | |||
| c01b7a9825 | |||
| 87c372d871 | |||
| 3125e34922 | |||
| fed18f1c24 | |||
| caabde39d2 | |||
| 1167358c5a | |||
| 444fded972 | |||
| 963b1e106c | |||
| 0d861b1aed | |||
| 9226f43cad | |||
| 2ff2d963c8 | |||
| d353183826 | |||
| a3e652ddb8 | |||
| c67298118e | |||
| abb333cfe7 | |||
| 5a41e7815f | |||
| 8a8004e187 | |||
| b1271cee43 | |||
| daaf848e0c | |||
| ef8e6231ff | |||
| cd35f9e694 | |||
| 91d9db6a4e | |||
| 898feac168 | |||
| 0b1d872ed0 | |||
| 687c72bde7 | |||
| b6d4a2e35e | |||
| a474111f36 | |||
| ed4c18f2be | |||
| f4d6f5a1ae | |||
| 32da2a5fa6 | |||
| ec66814184 | |||
| 37c68809d1 | |||
| 67d59928c9 | |||
| 37bc397e9a | |||
| d176389711 | |||
| e60da5b23f | |||
| 8603f84142 | |||
| d51c73d694 | |||
| 8f6462bcc9 | |||
| c02d988350 | |||
| 11b84afca0 | |||
| a858223c35 | |||
| f2405e23b4 | |||
| 2e640fa7fa | |||
| 1a3889b72d | |||
| a7e376deab | |||
| bb39c4b6e0 | |||
| 7b1ae3bdc6 | |||
| e37001e3c4 | |||
| 09ea84beaf | |||
| dc9fc2f814 | |||
| 32c8e2e937 | |||
| 88360fe307 | |||
| 57308e18e3 | |||
| 731cb4fec3 | |||
| 8ff276e30d | |||
| 1166477a6c | |||
| 7aa0b62012 | |||
| 10596cdbf0 | |||
| fc6fb1aee0 | |||
| 1eeaf3d892 | |||
| a3778fcb6e | |||
| 86f153bf69 | |||
| 3ca5e41602 | |||
| dcec366b0a | |||
| 14b7bdbf19 | |||
| af9845cbba | |||
| 034ecaa60f | |||
| ae91affc30 | |||
| 5fd2db319d | |||
| eec15df271 | |||
| 84c747c81c | |||
| b869ed9c45 | |||
| 42f6d0270d | |||
| e8f59b6dc6 | |||
| d91a1b1da0 | |||
| 004be4ea5c | |||
| a838bf3af8 | |||
| 1c1d1c4c97 | |||
| e0f61af709 | |||
| b619fc5600 | |||
| 2f6590416d | |||
| a877ef5f28 | |||
| af555aba21 | |||
| dd0ee47d86 | |||
| 452abfdd5c | |||
| ba41c0911d | |||
| cbbd97e1bd | |||
| ab8228f712 | |||
| 20e2a2b84b | |||
| 039a35522e | |||
| 72668472a0 | |||
| 569d42bbe9 | |||
| c7ebe441c7 | |||
| 403786e0c6 | |||
| 192bcf01f6 | |||
| 9880c701b1 | |||
| 910037a562 | |||
| 6232e2f330 | |||
| 7ea0e73869 | |||
| c4fe006efa | |||
| b2b1702670 | |||
| 1f8a6347e9 | |||
| d0cf95db49 | |||
| 331b049868 | |||
| e50602611c | |||
| 95382d9ab8 | |||
| e96a710576 | |||
| 2673112a9c | |||
| b8b8e19206 | |||
| 325fb24ed8 | |||
| ea26f56545 | |||
| 77c88c69cd | |||
| e85a85d9c3 | |||
| 3df0631ffc | |||
| 7434554319 | |||
| c9a5a2c2ff | |||
| 04008a07c0 | |||
| 928dbfb9f3 | |||
| 0f0afcf359 | |||
| 5d437f3a9f | |||
| cb3b42aece | |||
| a12648ff7a | |||
| d3c4e1bffc | |||
| 45c0625864 | |||
| 03e1ccf97e | |||
| 0fd738f37e | |||
| 3dfe59482e | |||
| 9024402a3b | |||
| f32d1afde5 | |||
| 0da6925119 | |||
| 914abd8562 | |||
| 80edd09528 | |||
| ab4499a284 | |||
| cc6e922d1b | |||
| 149c5715c6 | |||
| 627da0def5 | |||
| 324e6d506d | |||
| dcd1fa9605 | |||
| 3cc49fb764 | |||
| 13ac487ddb | |||
| ec117e0627 | |||
| 95de84fa85 | |||
| 432d30cc34 | |||
| 0395cd19d4 | |||
| 04994bff51 | |||
| 45564a7789 | |||
| fa20304df8 | |||
| 86ba94a3f3 | |||
| 60e990632b | |||
| 64ef7b4a3c | |||
| 637ac77a09 | |||
| 6c980721b2 | |||
| 107c676084 | |||
| 34b6af3627 | |||
| 277b28d7f5 | |||
| bdfaa67070 | |||
| 4e9b28ce15 | |||
| 543127b187 | |||
| 6c92048de5 | |||
| 227562cf3c | |||
| 58937b46f6 | |||
| e06c9f7ddc | |||
| a5402d3f04 | |||
| d04d8ebf9d | |||
| 42ca1a01b5 | |||
| 68883735ec | |||
| 15d255778c | |||
| 2f39b5eb69 | |||
| d1d2d514bd | |||
| 4a441a9c44 | |||
| fa3c980207 | |||
| 3c6200e08c | |||
| e7d150e8f5 | |||
| c5667c6895 | |||
| b7ccd8542e | |||
| 1ad68a2c43 | |||
| 4ab91ace5f | |||
| 97c32b0443 | |||
| a68b9176cb | |||
| cb3c989683 | |||
| f6f01b0510 | |||
| d6815f8285 | |||
| 62ea995c2d | |||
| e8e3d71bbe | |||
| 75d4af84c4 | |||
| 6cde956c31 | |||
| bedf231550 | |||
| a112cd80bf | |||
| fdf3f2c7d6 | |||
| 21ad2ace4a | |||
| 464c247e32 | |||
| 6c4b698fd7 | |||
| 6498aaf8b8 | |||
| b65d94b0e8 | |||
| 97fc04399e | |||
| da96daa767 | |||
| a9e300bf5b | |||
| 4f3016649d | |||
| a04e894518 | |||
| 9136dc196c | |||
| 5eb51f08b6 | |||
| 06a75559f0 | |||
| 248707055e | |||
| 67a32cdc20 | |||
| 8a365ab5e0 | |||
| 7cd05e1582 | |||
| 0e97d57883 | |||
| cced874460 | |||
| 49927a25cf | |||
| a7c91cee0e | |||
| acbde24c2f | |||
| 47d8df052a | |||
| 3705cc09d1 | |||
| ecd8d2537d | |||
| 56439a3b13 | |||
| 137e846cf2 | |||
| 78417e0c8c | |||
| 62a3e06baa | |||
| 485b887b54 | |||
| fe75b93ec7 | |||
| ab157bfb5a | |||
| f0bf10d91d | |||
| cbd28f9a12 | |||
| a33154b2d0 | |||
| 828b47f3be | |||
| 7b426c93c9 | |||
| 20fd7b41e6 | |||
| f60545f664 | |||
| 679d4534cb | |||
| 372be53471 | |||
| 0cdc7448e4 | |||
| 43b4fd1e77 | |||
| d178910594 | |||
| 6f4363e021 | |||
| 0fca4c6c20 | |||
| 7595e6ced8 | |||
| 2547c134f2 | |||
| a6dc4f9b46 | |||
| e627cb67a5 | |||
| d6e489bb61 | |||
| 3b2d8c14c3 | |||
| 9f0d81cc76 | |||
| b9c1968dc4 | |||
| 7553cfa310 | |||
| af04da6eca | |||
| 949d16cd03 | |||
| 917497e7e4 | |||
| 7db5f02067 | |||
| 3c3715effa | |||
| a016681d08 | |||
| 5fc4220ecf | |||
| 70730fd0f0 | |||
| c63986e271 | |||
| 9615fdb39d | |||
| fc2372f754 | |||
| 92c0c5cd8c | |||
| 25bb341fa4 | |||
| 0d44d25ec9 | |||
| 6b4029f8c2 | |||
| 76f5a4e9be | |||
| f493b823b3 | |||
| d508402aa8 | |||
| 6477950eea | |||
| 5819a0736c | |||
| f956968cb4 | |||
| 1751db31c5 | |||
| e659c6d097 | |||
| 355e81ba44 | |||
| c18acba48b | |||
| e97092042b | |||
| dc8beefb63 | |||
| b9b899b4f6 | |||
| 6c013d5aa3 | |||
| 2614cea431 | |||
| b9857745b1 | |||
| 13bdd6b8eb | |||
| 0b83125ab5 | |||
| 8d6c81441d | |||
| 5fcb5305f8 | |||
| d6d8973800 | |||
| 99ae5f9bc1 | |||
| 4f05c084d9 | |||
| 8f2418eb7c | |||
| a25d3bc8c9 | |||
| 8a0572d698 | |||
| 2187c1a712 | |||
| 60602008d4 | |||
| 04389b1df6 | |||
| 90da880386 | |||
| bd82f55966 | |||
| 3d48bfb6a6 | |||
| ea3d0121cc | |||
| e2c2be6e30 | |||
| df82f14206 | |||
| e237776810 | |||
| 88062dc8e4 | |||
| 67899c8f02 | |||
| cfaffc7d50 | |||
| fe51c80248 | |||
| e7106b54c4 | |||
| 119aa1b0ff | |||
| 415979e211 | |||
| d91463c458 | |||
| 122a16ad4e | |||
| 3834bd404c | |||
| eb3b0eb459 | |||
| 9761204b08 | |||
| 4df68880f0 | |||
| 6e07a363f4 | |||
| cf3818040c | |||
| 2d3b61550b | |||
| 85fe0f6749 | |||
| 5ae31a1705 | |||
| ffe195d7b2 | |||
| b9a38549dc | |||
| 8df0a6c774 | |||
| 7fca0fc31d | |||
| 8125fc4ffb | |||
| d0fa0cf39c | |||
| c419ca7bcb | |||
| 5017bf7003 | |||
| 985c29b281 | |||
| d85381e30e | |||
| 83978e8188 | |||
| 4e4dc8e16e | |||
| 66d6a76e1a | |||
| 455c3dae68 | |||
| 310922161a | |||
| f119433814 | |||
| c745f865bd | |||
| cbd3e56503 | |||
| 1e35af770f | |||
| 18bb0ae1af | |||
| dcf10d39c7 | |||
| 0ef58a7d0d | |||
| f583d03785 | |||
| 8281bcaca3 | |||
| f7998f4c57 | |||
| 1acce563c1 | |||
| bf985a9ca4 | |||
| cd23e93825 | |||
| cd892e1d5c | |||
| f2c596a670 | |||
| d5c459d136 | |||
| 9b90af8405 | |||
| 9311d0b515 | |||
| 0bc341c0aa | |||
| a338831d69 | |||
| 4487f854cd | |||
| a39fe09de4 | |||
| 31769fd42d | |||
| 0ddaef01c8 | |||
| 71e2073a76 | |||
| c923fb3e12 | |||
| 49835d9213 | |||
| 1ef7713351 | |||
| 26b8ad852e | |||
| f09877921a | |||
| 5012b726cd | |||
| 4bc85d474f | |||
| 5948ac2897 | |||
| 55b664b58f | |||
| fcbd1ae05e | |||
| 6700b0ea81 | |||
| 6965882435 | |||
| c35c80ce24 | |||
| 8ffc5c11e0 | |||
| 37e2c78b0b | |||
| e85a26d90b | |||
| c3ff199a09 | |||
| 6832afa087 | |||
| be65301986 | |||
| 30aa1149a3 | |||
| 68fc473372 | |||
| b5d4bf5528 | |||
| 532262f670 | |||
| 85ecc3064a | |||
| f8076920fe | |||
| 9629c08da2 | |||
| a35f66f2cd | |||
| 6fa071e1d1 | |||
| 47daf495bd | |||
| 7ade829a70 | |||
| 1d62bc22b8 | |||
| 6ed7a4886d | |||
| 3781ecb669 | |||
| 4c5b3add1d | |||
| c3be39b4e5 | |||
| 43473efcdd | |||
| 7df97831be | |||
| 92526e71b2 | |||
| b13b3b4377 | |||
| c568b95cf2 | |||
| c565dab3ad | |||
| 5a00950589 | |||
| b497537a78 | |||
| 723afd9f56 | |||
| ebb95b902c | |||
| 40093322c3 | |||
| 0da3ebed6f | |||
| c6dd4e735c | |||
| 13c528163d |
12
.gitmodules
vendored
12
.gitmodules
vendored
@@ -1,3 +1,15 @@
|
||||
[submodule "stm-firmware/shellmatta"]
|
||||
path = stm-firmware/shellmatta
|
||||
url = https://git.shimatta.de/mhu/shellmatta
|
||||
[submodule "c-style-checker"]
|
||||
path = c-style-checker
|
||||
url = https://git.shimatta.de/mhu/c-style-checker.git
|
||||
branch = master
|
||||
|
||||
[submodule "stm-firmware/base64-lib"]
|
||||
path = stm-firmware/base64-lib
|
||||
url = https://git.shimatta.de/mhu/base64-lib.git
|
||||
branch = master
|
||||
[submodule "stm-firmware/linklist-lib"]
|
||||
path = stm-firmware/linklist-lib
|
||||
url = https://git.shimatta.de/mhu/linklist-lib.git
|
||||
|
||||
361
GPLv2.md
Normal file
361
GPLv2.md
Normal file
@@ -0,0 +1,361 @@
|
||||
### GNU GENERAL PUBLIC LICENSE
|
||||
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
### Preamble
|
||||
|
||||
The licenses for most software are designed to take away your freedom
|
||||
to share and change it. By contrast, the GNU General Public License is
|
||||
intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) 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
|
||||
this service 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 make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. 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.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on,
|
||||
we want its recipients to know that what they have is not the
|
||||
original, so that any problems introduced by others will not reflect
|
||||
on the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at
|
||||
all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
**0.** This License applies to any program or other work which
|
||||
contains a notice placed by the copyright holder saying it may be
|
||||
distributed under the terms of this General Public License. The
|
||||
"Program", below, refers to any such program or work, and a "work
|
||||
based on the Program" means either the Program or any derivative work
|
||||
under copyright law: that is to say, a work containing the Program or
|
||||
a portion of it, either verbatim or with modifications and/or
|
||||
translated into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".) Each licensee
|
||||
is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the Program
|
||||
(independent of having been made by running the Program). Whether that
|
||||
is true depends on what the Program does.
|
||||
|
||||
**1.** You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
**2.** You may modify your copy or copies of the Program or any
|
||||
portion of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
|
||||
**a)** You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
|
||||
**b)** You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any part
|
||||
thereof, to be licensed as a whole at no charge to all third parties
|
||||
under the terms of this License.
|
||||
|
||||
|
||||
**c)** If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such interactive
|
||||
use in the most ordinary way, to print or display an announcement
|
||||
including an appropriate copyright notice and a notice that there is
|
||||
no warranty (or else, saying that you provide a warranty) and that
|
||||
users may redistribute the program under these conditions, and telling
|
||||
the user how to view a copy of this License. (Exception: if the
|
||||
Program itself is interactive but does not normally print such an
|
||||
announcement, your work based on the Program is not required to print
|
||||
an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
**3.** You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
|
||||
**a)** Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections 1
|
||||
and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
|
||||
**b)** Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your cost of
|
||||
physically performing source distribution, a complete machine-readable
|
||||
copy of the corresponding source code, to be distributed under the
|
||||
terms of Sections 1 and 2 above on a medium customarily used for
|
||||
software interchange; or,
|
||||
|
||||
|
||||
**c)** Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is allowed
|
||||
only for noncommercial distribution and only if you received the
|
||||
program in object code or executable form with such an offer, in
|
||||
accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
**4.** You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt otherwise
|
||||
to copy, modify, sublicense or distribute the Program is void, and
|
||||
will automatically terminate your rights under this License. However,
|
||||
parties who have received copies, or rights, from you under this
|
||||
License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
**5.** You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
**6.** Each time you redistribute the Program (or any work based on
|
||||
the Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
**7.** If, as a consequence of a court judgment or allegation of
|
||||
patent infringement or for any other reason (not limited to patent
|
||||
issues), 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 distribute so as to satisfy simultaneously your
|
||||
obligations under this License and any other pertinent obligations,
|
||||
then as a consequence you may not distribute the Program at all. For
|
||||
example, if a patent license would not permit royalty-free
|
||||
redistribution of the Program by all those who receive copies directly
|
||||
or indirectly through you, then the only way you could satisfy both it
|
||||
and this License would be to refrain entirely from distribution of the
|
||||
Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
**8.** If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
**9.** The Free Software Foundation may publish revised and/or new
|
||||
versions of the 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 a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Program does not specify a
|
||||
version number of this License, you may choose any version ever
|
||||
published by the Free Software Foundation.
|
||||
|
||||
**10.** If you wish to incorporate parts of the Program into other
|
||||
free programs whose distribution conditions are different, write to
|
||||
the author to ask for permission. For software which is copyrighted by
|
||||
the Free Software Foundation, write to the Free Software Foundation;
|
||||
we sometimes make exceptions for this. Our decision will be guided by
|
||||
the two goals of preserving the free status of all derivatives of our
|
||||
free software and of promoting the sharing and reuse of software
|
||||
generally.
|
||||
|
||||
**NO WARRANTY**
|
||||
|
||||
**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||
|
||||
**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE 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.
|
||||
|
||||
### 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
|
||||
convey 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 an idea of what it does.
|
||||
Copyright (C) yyyy 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 2
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper
|
||||
mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision 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, the
|
||||
commands you use may be called something other than \`show w' and
|
||||
\`show c'; they could even be mouse-clicks or menu items--whatever
|
||||
suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or
|
||||
your school, if any, to sign a "copyright disclaimer" for the program,
|
||||
if necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright
|
||||
interest in the program `Gnomovision'
|
||||
(which makes passes at compilers) written
|
||||
by James Hacker.
|
||||
|
||||
signature of Ty Coon, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This 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](https://www.gnu.org/licenses/lgpl.html) instead of this
|
||||
License.
|
||||
35
Jenkinsfile
vendored
Normal file
35
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
stages {
|
||||
stage('Configure') {
|
||||
steps {
|
||||
echo 'Configuring Cmake...'
|
||||
sh '''
|
||||
mkdir "build" &&
|
||||
cd "build" &&
|
||||
cmake "../stm-firmware"
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh '''
|
||||
cd "build" &&
|
||||
make
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
echo 'Testing..'
|
||||
}
|
||||
}
|
||||
stage('Deploy') {
|
||||
when { tag "*" }
|
||||
steps {
|
||||
echo 'Deploying tag...'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
LICENSE.md
Normal file
10
LICENSE.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# License of the Relow Oven Control Firmware
|
||||
|
||||
This software is licsensed according to the GPLv2. See GPLv2.md for details.
|
||||
However, this software includes various third party libraries for which different licenses apply:
|
||||
|
||||
- Shellmatta Shell implementation by Stefan Strobel: Licensed under ``Mozilla Public License Version 2.0``
|
||||
- CMSIS by ARM Limited <https://github.com/ARM-software/CMSIS_5>, licensed under ``Apache License Version 2.0, January 2004``
|
||||
- STM Header Files etc. by ST Microelectronics icensed under a custom license. See the sphinx documentation (section License) for details.
|
||||
- FatFs: Custom License (See source files of FatFS)
|
||||
- SHA256 Library <https://github.com/amosnier/sha-2> licensed under the ``Unilicense``
|
||||
1
c-style-checker
Submodule
1
c-style-checker
Submodule
Submodule c-style-checker added at cb937262aa
2
doc/.gitignore
vendored
Normal file
2
doc/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
build/*
|
||||
venv
|
||||
3
doc/.vscode/settings.json
vendored
Normal file
3
doc/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"restructuredtext.confPath": "${workspaceFolder}/source"
|
||||
}
|
||||
22
doc/Makefile
Normal file
22
doc/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
livehtml:
|
||||
sphinx-autobuild -b html $(SPHINXOPTS) $(SOURCEDIR) $(BUILDDIR)/html
|
||||
@@ -1,3 +1,3 @@
|
||||
*
|
||||
*.*
|
||||
*/*
|
||||
!.gitignore
|
||||
21
doc/make-with-virtualenv.sh
Executable file
21
doc/make-with-virtualenv.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
cd "$DIR"
|
||||
|
||||
if [[ ! -d "venv" ]]; then
|
||||
virtualenv venv
|
||||
source ./venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
else
|
||||
source ./venv/bin/activate
|
||||
fi
|
||||
|
||||
make SPHINXBUILD='venv/bin/python venv/bin/sphinx-build' $@
|
||||
35
doc/make.bat
Normal file
35
doc/make.bat
Normal file
@@ -0,0 +1,35 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
||||
32
doc/requirements.txt
Normal file
32
doc/requirements.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
alabaster==0.7.12
|
||||
Babel==2.9.0
|
||||
blockdiag==2.0.1
|
||||
breathe==4.24.1
|
||||
certifi==2020.11.8
|
||||
chardet==3.0.4
|
||||
docutils==0.16
|
||||
funcparserlib==0.3.6
|
||||
idna==2.10
|
||||
imagesize==1.2.0
|
||||
Jinja2==2.11.2
|
||||
MarkupSafe==1.1.1
|
||||
packaging==20.7
|
||||
Pillow==8.0.1
|
||||
Pygments==2.7.2
|
||||
pyparsing==2.4.7
|
||||
pytz==2020.4
|
||||
requests==2.25.0
|
||||
six==1.15.0
|
||||
snowballstemmer==2.0.0
|
||||
Sphinx==3.3.1
|
||||
sphinx-rtd-theme==0.5.0
|
||||
sphinxcontrib-applehelp==1.0.2
|
||||
sphinxcontrib-blockdiag==2.0.0
|
||||
sphinxcontrib-devhelp==1.0.2
|
||||
sphinxcontrib-drawio==0.0.12
|
||||
sphinxcontrib-htmlhelp==1.0.3
|
||||
sphinxcontrib-jsmath==1.0.1
|
||||
sphinxcontrib-qthelp==1.0.3
|
||||
sphinxcontrib-serializinghtml==1.1.4
|
||||
urllib3==1.26.2
|
||||
webcolors==1.11.1
|
||||
2
doc/source/.gitignore
vendored
Normal file
2
doc/source/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.drawio/*
|
||||
.drawio
|
||||
3
doc/source/.vscode/settings.json
vendored
Normal file
3
doc/source/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"restructuredtext.confPath": "${workspaceFolder}"
|
||||
}
|
||||
2536
doc/source/Doxyfile.in
Normal file
2536
doc/source/Doxyfile.in
Normal file
File diff suppressed because it is too large
Load Diff
3432
doc/source/_static/ibom.html
Normal file
3432
doc/source/_static/ibom.html
Normal file
File diff suppressed because one or more lines are too long
86
doc/source/conf.py
Normal file
86
doc/source/conf.py
Normal file
@@ -0,0 +1,86 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
import os, subprocess
|
||||
import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
import re
|
||||
|
||||
project = 'Shimatta Reflow Controller'
|
||||
copyright = '2020, Mario Hüttel'
|
||||
author = 'Mario Hüttel'
|
||||
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = re.sub('^v', '', os.popen('git describe --always --tags --dirty').read().strip())
|
||||
# The short X.Y version.
|
||||
version = release
|
||||
|
||||
try:
|
||||
os.mkdir('../build/_doxygen')
|
||||
except FileExistsError:
|
||||
pass
|
||||
|
||||
subprocess.call('doxygen Doxyfile.in', shell=True)
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx_rtd_theme',
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.todo',
|
||||
'sphinxcontrib.blockdiag',
|
||||
'sphinxcontrib.drawio',
|
||||
'breathe'
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = []
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
breathe_projects = {
|
||||
"Reflow Controller Firmware": "../build/_doxygen/xml/"
|
||||
}
|
||||
|
||||
breathe_domain_by_extension = { "h" : "c",
|
||||
"c" : "c" }
|
||||
breathe_default_project = "Reflow Controller Firmware"
|
||||
breathe_default_members = ('members', 'undoc-members')
|
||||
|
||||
blockdiag_html_image_format = 'SVG'
|
||||
breathe_show_define_initializer = True
|
||||
blockdiag_latex_image_format = 'PDF'
|
||||
|
||||
todo_include_todos = True
|
||||
1
doc/source/firmware/calibration.drawio
Normal file
1
doc/source/firmware/calibration.drawio
Normal file
@@ -0,0 +1 @@
|
||||
<mxfile host="Electron" modified="2021-05-22T15:48:58.897Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/14.1.8 Chrome/87.0.4280.88 Electron/11.1.1 Safari/537.36" etag="60nNVEjkDLNBMWFG8AC7" version="14.1.8" type="device"><diagram id="3R1YF1CA5z1RRVBQNkpO" name="Page-1">7VlLc9o6FP41LGFkCduwbCBtF+1cbtOZpkthy7Z6ZURk8eqvr2TLLwSBFIgnmZtFxjqSjh7n+85D9NAk3X4SeJl85SFhPQjCbQ9NexB6vq/+a8GuEKCRVwhiQcNC5NSCB/qbGCEw0hUNSdYaKDlnki7bwoAvFiSQLRkWgm/awyLO2qsucUwswUOAmS39QUOZFNIR9Gv5Z0LjpFzZ8cZFT4rLweYkWYJDvmmI0H0PTQTnsvhKtxPC9N2V91LM+3ikt9qYIAt5zgRvNpa/npLHmH16+jdwvo+m7rzvmr3JXXlgEqrzmyYXMuExX2B2X0vvBF8tQqK1AtWqx3zhfKmEjhL+IlLujDHxSnIlSmTKTK/asNg9mvl546duDNyyOd02O6c70yr2qjd49ApKiGARE/nMuceVARRwCU+JWkfNE4RhSddt/dhAKK7GVVNnnKqVITBor1BrwO74oK2i2JeZ1bTVnqJ9PZ7b1pPxlQiIpUd9NI5Ti3IkvAAVhqJrzFbmKr7hjRLMvjsAgPyeMppJvAjIQfx8wXPlBVo2x4zGC/UdKFMRoQRrIiRVPPtgOlIahgW8lO7feJ7r01Zf6lPm53bveu60woFWQLa9A07ATK6p10TIcRrYcDDa+2DgAH/cMknfLHkhYhwwGLug8YcOrlIq5FGUkZuY3OnGE2ypfGx8N/yAatVuQDdKL/C33iNvzYig6qo0Al/oUgrKnXIpZ7geZ3ih72mZ/qV2HlvU7kGPqf3ezdVHLPM7KQQRz5FaI8J7WvGyo5/lNv2gBiC03NadtZZKkdpooautX4kba+6DjzEV4jXINgmV5GGJ88vfqCRjz7FkyyLuR3SroXgXUcYmnHGRK0KhS0bhUMkzKfh/pNEzgnPkec/5EwsGR10ELPlTeuyhcT2bOmlwjShp5AsuuJGdHce+0vfF5ytStwy3p7kLb5M3oHa8h8Pz8oarOX9geYWJCthzgaVCAwT/1GGnCag2XE7wdI+WURTBIDhEy9Cbe+6VaOnv3atrs9KBB2jp3YyW6O3Rsmbiz2YC/wq0hGfS8tJs/jKTQos8fdv5SkHxImZnBDTBpdo11zlxfwxs5hBHhTT/EHPGno/wtQIabAe0qiRpUAcdYM6+57raNUP4ZpijGjfMMy/OHw/HIA+cqDlvHIMgej4GVbXnt3dWe8IjOUVdfCIXOC3bXKn4RM7gcFH7CuXm0LK2Zc3SSrlFZzyjxivOuZQ81Q6wfFHTpgpxllRMtyzeQMO+8aV2BVrXUq+bbmP9jjkgTBlT6HEDPFeeFgdykK70uyOjucZOygw03CNp12UGfINlRnf5jHdmPuP4nSY09vNf0xOb1wJRlu4PZKGpuaZSb3FK1rRIX958tYBg59XCqBN2/SVTbv3A5vjn0qfTF7Zym/8/sd029lXlR2exD9hX+h5+PDtNxLOfuruNY/Zbt52tXBKVXqkSHx95HDxRiaOX414169+ji1S//lEf3f8B</diagram></mxfile>
|
||||
8
doc/source/firmware/code/dmas.rst
Normal file
8
doc/source/firmware/code/dmas.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
.. _api_dmas:
|
||||
|
||||
Peripheral DMA Library Code
|
||||
====================================
|
||||
|
||||
.. doxygengroup:: dma-ring-buffer
|
||||
:project: Reflow Controller Firmware
|
||||
|
||||
11
doc/source/firmware/code/index.rst
Normal file
11
doc/source/firmware/code/index.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
.. _api:
|
||||
|
||||
Important Code APIs
|
||||
===================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:glob:
|
||||
|
||||
*
|
||||
safety/safety-controller
|
||||
8
doc/source/firmware/code/main.rst
Normal file
8
doc/source/firmware/code/main.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
.. _api_main:
|
||||
|
||||
Reflow Controller Firmware Main File
|
||||
====================================
|
||||
|
||||
.. doxygenfile:: main.c
|
||||
:project: Reflow Controller Firmware
|
||||
|
||||
8
doc/source/firmware/code/safety/safety-adc.rst
Normal file
8
doc/source/firmware/code/safety/safety-adc.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
.. _dox_safety_adc:
|
||||
|
||||
Safety ADC
|
||||
====================================
|
||||
|
||||
.. doxygengroup:: safety-adc
|
||||
:project: Reflow Controller Firmware
|
||||
|
||||
11
doc/source/firmware/code/safety/safety-controller.rst
Normal file
11
doc/source/firmware/code/safety/safety-controller.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
.. _dox_safety_controller:
|
||||
|
||||
Safety Controller
|
||||
====================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
safety-adc
|
||||
|
||||
|
||||
31
doc/source/firmware/hw-version-detect.rst
Normal file
31
doc/source/firmware/hw-version-detect.rst
Normal file
@@ -0,0 +1,31 @@
|
||||
.. _hw_version_detect:
|
||||
|
||||
Automatic Hardware Version detection
|
||||
====================================
|
||||
|
||||
Functional Description
|
||||
----------------------
|
||||
|
||||
In order to automatically select the available hardware features, the firmware checks the PCB's version
|
||||
using vertain pins on the microcontroller.
|
||||
|
||||
The hardware revision is represented by the enum type :c:enum:`hw_revision`. A call to :c:func:`get_pcb_hardware_version` retrieves the revision.
|
||||
When the function is called for the first time, it activates pull-up resistors on pin numbers :c:macro:`HW_REV_DETECT_PIN_LOW` to :c:macro:`HW_REV_DETECT_PIN_HIGH`
|
||||
on port :c:macro:`HW_REV_DETECT_GPIO` and reads in the binary number.
|
||||
|
||||
The revision is set by externally connecting the pins to ground. The bit pattern read from the port is inverted and then checked internally to derive the hardware version.
|
||||
After the version is read for the first time, it is stored internally and subsequent calls to :c:func:`get_pcb_hardware_version` only retrieve the internally stored value to reduce the overhead of the function.
|
||||
|
||||
Hardware Version Dependent Features
|
||||
-----------------------------------
|
||||
|
||||
- The settings module searches for an external EEPROM on the SPI interface to store some settings, like the calibration. This is enabled for all versions higher or equal to ``v1.3``.
|
||||
- The safety controller enables the acknowledging of the external watchdog for all versions higher or equal to ``v1.3``.
|
||||
- The oven driver has a separate safety enable for the solid state relay which it enables on all versions higher or equal to ``v1.3``.
|
||||
|
||||
|
||||
API Documentation
|
||||
-----------------
|
||||
|
||||
.. doxygengroup:: hw-version-detect
|
||||
:project: Reflow Controller Firmware
|
||||
18
doc/source/firmware/index.rst
Normal file
18
doc/source/firmware/index.rst
Normal file
@@ -0,0 +1,18 @@
|
||||
.. _firmware:
|
||||
|
||||
Reflow Controller Firmware
|
||||
==========================
|
||||
|
||||
This chapter describes the reflow controller's firmware.
|
||||
This is in most cases not intended to be a code documentation but an overview over the functional
|
||||
mechanisms and the behavior. For a detailed code documentation see the doxygen output.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
pt1000-processing
|
||||
pid-controller
|
||||
safety/index
|
||||
code/index
|
||||
hw-version-detect
|
||||
|
||||
78
doc/source/firmware/pid-controller.rst
Normal file
78
doc/source/firmware/pid-controller.rst
Normal file
@@ -0,0 +1,78 @@
|
||||
.. _pid_controller:
|
||||
|
||||
PID Controller
|
||||
==============
|
||||
|
||||
The PID controller is the main element of the oven. It controls the output of the solid state relais in order to achieve the desired temperature.
|
||||
|
||||
The PID controller is implemented in the ``pid-controller.c`` file. See the :ref:`pid_code_api` for details.
|
||||
|
||||
Functional Description
|
||||
----------------------
|
||||
|
||||
The following figure shows the PID controller's structure.
|
||||
|
||||
.. drawio-image:: pid.drawio
|
||||
|
||||
The controller is composed of 3 paths. The proportional, the derivate, and the integrator path.
|
||||
Compared to a textbook PID controller, this version contains a few additional features.
|
||||
|
||||
The integrator has a configurable maximum limit of :c:var:`pid_controller.integral_max`. Once this value is reached (plus or minus), the integrator freezes.
|
||||
The integrator is also frozen in case the output value is in saturation. This serves as an anti-windup protection.
|
||||
|
||||
The output value saturates at configurable high and low limits (:c:var:`pid_controller.output_sat_max` and :c:var:`pid_controller.output_sat_min`). The controller instance used for the
|
||||
reflow oven's solid state relais output is saturated by software to a limit of 0 to 100.
|
||||
|
||||
In addition to the above features, the derivate term contains an additional first order low pass filter in order to prevent coupling of high frequency noise amplified by the derivate term.
|
||||
The low pass filter is charcterized by its time constant :math:`k_{d\tau}`.
|
||||
|
||||
Time Continuous Transfer Function
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The time continous transfer function of the PID controller is
|
||||
|
||||
.. math:: H_c(s) = \frac{Y_c(s)}{X_c(s)} = k_p + \frac{k_i}{s} + \frac{k_ds}{1+sk_{d\tau}}
|
||||
|
||||
|
||||
Time Discrete Transfer Function
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The time descrete transfer function which is implemented in the code is derived by converting the time continuous transfer function
|
||||
with the bilinear transformation:
|
||||
|
||||
.. math:: s = \frac{2}{T_s}\cdot \frac{z-1}{z+1}
|
||||
|
||||
The frequency warping of the bilinear transform can be considered negligible because the PID controller is targetted for low frequency temperature signal data with a maximum far below the nyquist freqency.
|
||||
In this area, the mapping of the continuous frequencies to the time descrete can be considered linear.
|
||||
|
||||
The time discrete transfer function after inserting the bilinear transform is:
|
||||
|
||||
.. math:: H_d(z) = H_c(s)\bigg|_{s=\frac{2}{T_s}\cdot \frac{z-1}{z+1}} = k_p + \frac{k_i T_s (z+1)}{2(z-1)} + \frac{\frac{2}{T_s}k_d(z-1)}{\left(1+\frac{2k_{d\tau}}{T_s}\right)z+\left(1-\frac{2k_{d\tau}}{T_s}\right)}.
|
||||
|
||||
Converted to an implementable form:
|
||||
|
||||
.. math:: H_d(z) = k_p + \frac{k_iT_s(1+ z^{-1})}{2(1-z^{-1})} + \frac{\frac{2}{T_s}k_d(1-z^{-1})}{(1+2k_{d\tau}T_s^{-1})+(1-2k_{d\tau}T_s^{-1})z^{-1}}
|
||||
|
||||
This function can be splitted in the three individual parts of the PID controller:
|
||||
|
||||
.. math:: H_{d1}(z) = k_p
|
||||
.. math:: H_{d2}(z) = \frac{k_iT_s(1+ z^{-1})}{2(1-z^{-1})}
|
||||
.. math:: H_{d3}(z) = \frac{\frac{2}{T_s}k_d(1-z^{-1})}{(1+2k_{d\tau}T_s^{-1})+(1-2k_{d\tau}T_s^{-1})z^{-1}}
|
||||
|
||||
The individual time domain difference equations :math:`y_i[n] = \mathcal{Z}^{-1}\left\lbrace H_{di} * X(z)\right\rbrace` that are implemented in software are:
|
||||
|
||||
.. math:: y_1[n] = k_p x[n]
|
||||
.. math:: y_2[n] = \underbrace{\frac{k_iT_s}{2}}_{k_{i_t}} \left( x[n] + x[n-1]\right) + y_2[n-1]
|
||||
.. math:: y_3[n] = \underbrace{\frac{2k_{d}}{2k_{d\tau} + T_s}}_{k_{d_t}}\left( x[n] - x[n-1] \right) + \underbrace{\frac{2k_{d\tau} - T_s}{2k_{d\tau} + T_s}}_{\overline{k_{d_t}}} y_3[n-1]
|
||||
|
||||
The final output value is the sum of all three terms:
|
||||
|
||||
.. math:: y[n] = \sum_{i=1}^{3} y_i[n]
|
||||
|
||||
.. _pid_code_api:
|
||||
|
||||
PID Controller Code API
|
||||
-----------------------
|
||||
|
||||
.. doxygengroup:: pid-controller
|
||||
:project: Reflow Controller Firmware
|
||||
1
doc/source/firmware/pid.drawio
Normal file
1
doc/source/firmware/pid.drawio
Normal file
@@ -0,0 +1 @@
|
||||
<mxfile host="Electron" modified="2021-06-14T21:01:35.428Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/14.1.8 Chrome/87.0.4280.88 Electron/11.1.1 Safari/537.36" etag="ORruDkFRflEPSgIrI-Cx" version="14.1.8" type="device"><diagram name="Page-1" id="b520641d-4fe3-3701-9064-5fc419738815">3Vttb6M4EP41+dgIMObl4/bl7lba1VXqSbt3XyonOMRXiDnjtGR//dnYQHhLySaEdFFV2ePx2Hjm8YzHZAbu4ux3hpL1VxrgaGYZQTYD9zPL8j1T/JeEnSJA6CtCyEigSGZFeCI/sCYamrolAU5rjJzSiJOkTlzSzQYveY2GGKNvdbYVjeqjJijELcLTEkVt6jcS8LWmmoZRNfyBSbjWQ3tQNyzQ8iVkdLvR480ssMof1RyjUpYipGsU0DdFykWAhxm4Y5RyVYqzOxzJpS2WTY3zW09rOW+GN3xIBy/JHl5eQ/vrX8//QJh8C+iPpxutq5TvivXAgVgeXaWMr2lINyh6qKi3+TtjKdUQtYrnC6WJIJqC+C/mfKd1jbacCtKax5FuxRnh3/fKf0tRc6hr95mWnFd2RWXD2e57xSirf++3Vd3yWq3fI2YkxhwzTVQvLd+0dy0LpdEtW+IDC1iYLGIh5of4zFLlAkmYiumwnejIcIQ4ea1PBGmbDku+susjJWKKlqHh50BLrEfeSePPstyCUohRk9M9KwsRhb2pVKTcbo6wISlyAiMqDaJmDpV19BjEcN2/r9NRVFrujIVCHWOQOtuC7HcEKeNuCfrEGNrtsSWSIT0wYbd7nN55NfjNOr8oqBmc1Ui1Gl5RtMXFfu1EQru3C1EIZeHzhuOQIU5Z0SRGKltLdlZRbPH38kxUoQWCysSlvb6tCcdPCcp3kzfhSuvmvCJRdEcjyvK+IIDYC2xBTzmjL3ivxbMWwHFKQ37FjOPssCm3TVR3ALChCe1CjLeaJ1S09b4TbFjSvlXXtpej1QQ+ikM6ow8Bo+wjtt+AJfTnHnRN21L//Ys6CfA+/u6Fl35Vb3wU/oJfBn/W9PgzPgr++gLCMjaYKCCEVxcQ+talA8JpNvHpA0I4TkBo1HcJAH7xgBBcIiCEHQ5J+ZOkx59wRtAmzI31Kp2JU8c96HAm3iV9ifO+y39kNBFQJxLo3U6/qQOc8fpao4iEG1FeimWS+/mtXESyRNEn3RCTIFA7DE7JD7TIRUngazMWcuHtDN5LWWJTSdX+MqEa62CwDdhSo9+hRmssNYI2Eq41JBCVMVM9I3ns93blkb212XU0bii8wNQXtMDRo8CIhKxoWlDOaSwhUSQ35ZoHKF2Xum/hc0/JTahyaRxSViLHjbNQZpznOMJLsfcKvjlaCOyhJZ+n2zhGchLPOYqnAitsgFVE9C2wwg6wwtHi92nA+pOh1+jJWWtg4HYytE9TmtUbi8zc22AG7zjaztz7nrjkWsAZ0ZAsn0PEcSrKbwlK02eBSiV4Eni2UiDAHQRP2xlL0+608Dzu7uScSHSGInFSIPaHrCua++xKcc5/W1o03Kig8ZNgMK0kqxqLOPYryki8jUUVxRJFm0WaHMhpCcQnsZysxH+Msj3slzGymlBPmHxS6gthb7Xsgqaz9PBiNQ403WGHldEcpzVJ4uuMCANDkxTjZJubO+3A1MLZ0ssDglghhiTpgOM7ShP1pcGKZFK7TYQY+XMeHFjNCBK2gWBd9LjXsXDXA4TzJ9csf+7bP2W7bVmwLUuQnEY0MfZNS/uq5fMm2cp5BviV5KemThXn8eN4yZVesOgve3TnWWna+8o/YKq90Lox5o4NzZo+dO1Eo7kBcG47RvXUBzHmvufvPZ5dH4CuVikeRff2JOCd+vp0nLS7Z7Rc2hyYBrBtz3Kh54BBqD42d+56x+XO3+EfJ3duX1FK0Bp8TWhNdfgBg+8ERzHklokMyy8ebbnNWx8bHrbcBj88bOjAdQ+wj2Tn7fPgn1uufGmK+JZpZ2qsMA7k96C/hl9V8O71q2Jr9626Mm7O41c9Z97cVsfzlaB9A1gq92lPuec8Wl8k69W6UADtI4XZdaZoxr1nO1PYkxyuT/yqxJ3MXXgD3cXJgc9pB0WvHz8x2ah814fLSzmNr2+9NnbcDujYo0HHbC3i9UNnMuT4HwM5/gHkFJniD48c054aOu1ESLnMitZc5It+XXKGJW+F3B3Xz11Z9J9IHopq9VMlFYJVPwcDD/8D</diagram></mxfile>
|
||||
168
doc/source/firmware/pt1000-processing.rst
Normal file
168
doc/source/firmware/pt1000-processing.rst
Normal file
@@ -0,0 +1,168 @@
|
||||
.. _pt1000_processing:
|
||||
|
||||
PT1000 Temperature Value Processing
|
||||
===================================
|
||||
|
||||
The PT1000 temperature sensor is the sensing element used for determining the Reflow Oven Temperature.
|
||||
|
||||
The PT1000 value processing is enabled by default and not intended to be turned off.
|
||||
|
||||
PT1000 Value Sampling
|
||||
---------------------
|
||||
|
||||
The following block diagram shows the processing chain of the temperature signal.
|
||||
|
||||
.. drawio-image:: pt1000.drawio
|
||||
|
||||
ADC
|
||||
~~~
|
||||
|
||||
The internal ADC of the STM32F407 controller is used to sample the analog signal from the :ref:`hw_analog_fe`. The ADC is triggered by the hardware Timer *TIM2* each millisecond, which results in a sampling frequency of
|
||||
1 kHz. The ADC module provides an analog value `watchdog <Watchdog_>`_, which is used to detect wirebreaks and other hardware errors that result in a wrong resistance measurement.
|
||||
|
||||
The sample frequency is controlled by
|
||||
|
||||
.. doxygendefine:: ADC_PT1000_SAMPLE_CNT_DELAY
|
||||
|
||||
whereas the ADC Peripheral module is defined by
|
||||
|
||||
.. doxygendefine:: ADC_PT1000_PERIPH
|
||||
|
||||
Prefilter
|
||||
~~~~~~~~~
|
||||
|
||||
The analog value prefilter is used to filter outliers. It is triggered after a certain amount ``n`` of values have been sampled by the `ADC`_.
|
||||
The filter then removes the two most extreme values and computes the average of the remaining ``n - 2`` values. By default ``n`` is configured to:
|
||||
|
||||
.. doxygendefine:: ADC_PT1000_DMA_AVG_SAMPLES
|
||||
|
||||
Therefore, by default, the resulting datastream has a sampling rate of 1/6 kHz. This depends on the :c:macro:`ADC_PT1000_SAMPLE_CNT_DELAY` and ``n``
|
||||
|
||||
|
||||
.. _firmware_meas_adc_watchdog:
|
||||
|
||||
Watchdog
|
||||
~~~~~~~~
|
||||
|
||||
The analog watchdog supervises the measured value of the `ADC`_. It is configured by the following defines:
|
||||
|
||||
.. doxygendefine:: ADC_PT1000_LOWER_WATCHDOG
|
||||
|
||||
.. doxygendefine:: ADC_PT1000_UPPER_WATCHDOG
|
||||
|
||||
.. doxygendefine:: ADC_PT1000_WATCHDOG_SAMPLE_COUNT
|
||||
|
||||
The watchdog will set the :ref:`safety_flags_adc_watchdog` error flag.
|
||||
|
||||
ADC Value to Ohm
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
This block converts the analog value to an Ohm resistance value.
|
||||
The formula is:
|
||||
|
||||
.. math::
|
||||
R(V) = \frac{V}{4096} \cdot 2500~\Omega
|
||||
|
||||
The equation is implemented in
|
||||
|
||||
.. doxygendefine:: ADC_TO_RES
|
||||
|
||||
and applied during the `Exponential Moving Average Filter`_.
|
||||
|
||||
.. _firmware_meas_adc_filter:
|
||||
|
||||
Exponential Moving Average Filter
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The external moving average filter filters the measured resistance value. It's equation is:
|
||||
|
||||
.. math::
|
||||
y[n] = (1-\alpha) y[n-1] + \alpha x[n]
|
||||
|
||||
The filter constant *alpha* defaults to the define
|
||||
|
||||
.. doxygendefine:: ADC_PT1000_FILTER_WEIGHT
|
||||
|
||||
and can be changed in code using
|
||||
|
||||
.. doxygenfunction:: adc_pt1000_set_moving_average_filter_param
|
||||
|
||||
The moving average filter is considered unstable, if the input to output difference is greater than
|
||||
|
||||
.. doxygendefine:: ADC_PT1000_FILTER_UNSTABLE_DIFF
|
||||
|
||||
In this case, the :ref:`safety_flags_adc_unstable` flag will be set until the filter output converges within the range for at least
|
||||
|
||||
.. doxygendefine:: ADC_PT1000_FILTER_STABLE_SAMPLE_COUNT
|
||||
|
||||
samples.
|
||||
If the input value keeps changing or oscillating, the error flag will be permanently set.
|
||||
|
||||
The moving average filter's output signal is the Low Frequency (LF) PT1000 resistance signal used for internal PT1000 measurements.
|
||||
|
||||
Reading and Converting the PT1000 Value
|
||||
---------------------------------------
|
||||
|
||||
Calibration
|
||||
~~~~~~~~~~~
|
||||
|
||||
The functions
|
||||
|
||||
.. doxygenfunction:: adc_pt1000_set_resistance_calibration
|
||||
:outline:
|
||||
|
||||
and
|
||||
|
||||
.. doxygenfunction:: adc_pt1000_get_resistance_calibration
|
||||
:outline:
|
||||
|
||||
are used to set the resistance calibration internally. For a guide on how to calibrate the deivce, see the corresponding :ref:`usage_calibration` usage page.
|
||||
|
||||
The calibration is calculated the following way:
|
||||
|
||||
.. drawio-image:: calibration.drawio
|
||||
|
||||
The final calibrated PT1000 resistance is calculated as:
|
||||
|
||||
.. math::
|
||||
R_{PT1000_{corr}} = (R_{PT1000_{LF}} - O) \cdot (1 + \sigma)
|
||||
|
||||
The default values, if no calibration is loaded / executed, are:
|
||||
|
||||
======== =====================
|
||||
Offset Sensitivity Deviation
|
||||
======== =====================
|
||||
0 0
|
||||
======== =====================
|
||||
|
||||
Get Calibration Corrected Value
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The PT1000 value is available through the following function.
|
||||
If a calibration is set, it is applied.
|
||||
|
||||
.. doxygenfunction:: adc_pt1000_get_current_resistance
|
||||
|
||||
Converting the Value
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The valid range for conversion is between
|
||||
|
||||
.. doxygendefine:: TEMP_CONVERSION_MIN_RES
|
||||
:outline:
|
||||
|
||||
and
|
||||
|
||||
.. doxygendefine:: TEMP_CONVERSION_MAX_RES
|
||||
:outline:
|
||||
|
||||
By default, the valid range is:
|
||||
|
||||
.. math::
|
||||
1000~\Omega \le R_{PT1000} \le 2200~\Omega
|
||||
|
||||
.. doxygenfunction:: temp_converter_convert_resistance_to_temp
|
||||
|
||||
The cvonversion function is based on a lookup table with linear interpolation between the data points.
|
||||
The lookuptable is stored as a header file and can, if necessary, be recreated using the ``create-temp-lookup-table.py`` script.
|
||||
|
||||
1
doc/source/firmware/pt1000.drawio
Normal file
1
doc/source/firmware/pt1000.drawio
Normal file
@@ -0,0 +1 @@
|
||||
<mxfile host="Electron" modified="2021-01-26T21:12:06.071Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/14.1.8 Chrome/87.0.4280.88 Electron/11.1.1 Safari/537.36" etag="PrKjQ8DyGBUrBwv3aoCi" version="14.1.8" type="device"><diagram name="Page-1" id="099fd60b-425b-db50-ffb0-6b813814b670">7Vxbd6M4Ev41Pmf3IT7cL49ObHfmTHqS7cx07+yLj4xlWx2MHJAvya9fCQQGJGPHBl/S0w9pKGQJqr66qKqgpd/N1l9CMJ9+xSPotzRltG7p3ZamuY5K/zLCW0JQLUtPKJMQjThtQ3hG75ATFU5doBGMCgMJxj5B8yLRw0EAPVKggTDEq+KwMfaLq87BBAqEZw/4IvUHGpFpQnVMZUO/h2gyTVdWFX5lCLyXSYgXAV+vpenj+F9yeQbSufj4aApGeJUj6b2WfhdiTJKj2foO+oy3KduS3/W3XM3uO4QB2ecH8N5wZ2TQ/+PnqoPhj3Xn0fp5o2r85shbyhA4ovzhpzgkUzzBAfB7G+pt/NCQTavQs82YB4znlKhS4k9IyBsXNlgQTElTMvP5VbhG5L/85+z4b3bcNvlZd5271H3LnTzBEM0ggSGnRSTEL/AO+ziM7113tKFuWWx0QMK3bAl2kluDnW4Wic/SVcbI93PzjUzojAxKF5nN+R/hRehxzv3UX5V38HU98L4twG/6+rszgTdcGwgIJ5BUSMJOxjHu5xbgovwCMX3u8I0OCKEPCFoW0Qu4EkyycdlPnzCit6wpXGF1i8Mx1dcU6OkUyY3yX23gRA9yt7EhxSD7CODsawbcobCKz/ZH7/lQqFp1w7AAoAq0VN32EvgLvlKnS2eyfPoMt8OQHk1IxpccpJYwJIja+AcwhP4TjhBBOKCXhpgQPGO8T40xE8QIRNMMXcBHEzbUozxmosrDKJ22w8cQBj8215ytO1tPmItsQ5/6qZCNa4MhFTLwSHsEvBjHBPA7iddFIR2ZnK9gxJ6EzjBCdOWueKkECqhSWNgyGLmWrQMrN1nuWtfsOd1KKLFnhOtK2fOrmlk0JS5X7dXGjdp8xDTnQQ2rIbCo5uWYFkc/xri03RrMCwxGHRYf0dMABzCh9BHjqczV7YGnw82PIZof6bjLsj6pMbwEQKnWIYCqRkCt3uyXgJM8pnJKIZW9X0hFZQPecsPmbEC0fRlXHrn19xxuKyWFSNY/NLqTa4xzTo1RCxpzhAFWf1Hzq1+U+TWE4K+LxmNIH58+rKZ0ZnMfjREMxXjwC0ABHRH/SEkTDZccHtK4cMBmGPtofp8ChB5/5zPXCJb94ztVLVoQ2xTiuywZkg/wXKUhQJgCIATJxjYUhr0lZKa0KJZzSzui44A/SLQ1anuLkAlnkGrveYSslbyEIsjYkIjYakrE1f6DG9KLSQec0oafKJYxaKhpaI5p879qAR4ZPurPFlU99LVqfAgjFBEcRu0lCBEY+nCQkmJzn08ABAzHYo7gPJa/ZPhFo2BJjELmDGq3Cu5uGOTCLc8HUYS8ouy2cmWnQuWe2pQ8dUo7Ni/rtm1Lyf0zi4pXYm1iLgS9++i0zSV/5duDq642HG27ry39Iaqd1tYogJT7d/rn4eli42ofT5A3mABCwywfr+bUHgyoIU0mPo9FdXfmSk1NNC515EqleX79WhRxWylke/FkLzWVFz/2VNPat8lbbLdSwsyJK3WC9j8DuuVmW+8/qV2km23lX3SM8nL//m8BTTmpF9R8NUVUKecglsOK6m29It5fIXWjyFxNjHEynS1oZA0xjpTdZ801H5s5+3gpM8u13ShtRc0oyQ0Yrn5Iyu1wzZckyKTjNPc0qm+XInC1HP/VlFK2DUO6Tl1J4qGrWl9ty/vr5vX19jnovg6Wy5uzdgAcnSP2h3EAk8YkeSjnMsV/t3JZ5CPKKHsbwxIia1MDqQT1RkBv2UXQ66f1d2K6ubee44AyEVExCznmr3iJggnLQ1MosB4zTeknIeZniIpP44Qt3bqoqFg1zmKaDizDNtQ/VNWdtrt/6GwlpKrbzvcPUclgprbfY5qm/ADEm44Y6epD2BS++RhWlr0vZ33q0x+xX6v37ZvA2dRG0RnRPIJFbdjJ63nOY/IZck60LIrxeKx5nkwUI2tomTWJwilt1WTbCd0RJZHSapeEVh1kxVHMRcZXpzRq9Tc7busPKe81m4nmjXIjilVvNC/PJKmfDmlnaR6vROhOv5vGyk1D2TQP25jWlpQSK4JPIRz/E3h/MHRw3csKvCUVPkPh2UVBrvQhSVEkgrjKMpqh0SgxPzBC76wSywXNbSqd17xtmV02F7U4UWJ8KguHH+C2vjP5L6unllWrvuBA2cLtvvVJOG5YOzkua01vjuOS1qXPxfFyxvLsHHcEjt/36XkXEED/a7F90eUI4CI2LVm9I79/1E4qNNENPPwjtGqhSTr2Tis0vbqWfCEbgCt4ca8ysN+5A+C5nwtJvOknzz/k64l2qYHfcM8s5t37N7Nu8W2psVjFBrDUTe/oK/toJkJYpvpVlfJwp3q4WSoUWW4Jr02kOUTX1A/ha5uS7qbQe5HCPd54NuePRLhV6qLgZLKPKvBVWvkPE8icD9UtzdRLJePk7Ni8gt5WiltStW0UJ8HjcQSPTSpIy5lXVfW5vKqxzEU1Vzb+sCkqv+FQ/kzGjvHp4zVrXcQdeVqfumlpFpixDBN/1V15nM4EwBbhGJdNnotlkxz0zpJyMktJkKxbPBe4OpK4tbGGK10s+GfFwU1RUOn7QKwNfv59hl1K9GqmI4hLWlxsbp8h5lB+zeKiKSqOrLbYnOKIOfj4qxysLTRpiflVdaYUxuqSrbnakMr8rvXu4X/Cx5fftYe38Y8/jf8tHUkLb+ePzsPjlwr3oX7YfZymgb7UP6/tm6uq401FKW81gbddNEGEtYopbGZNecZjsqLPXCu3T1Qfss0LY7fYWfK4IPMFC9zS7CBjerlLrxeGlD+JRYpqFcSJTIrQE3lCQUiDeIlNiY3/X0GU7CNT88+j1mAYzTNeXJs7kGyZBXFWuIPSTkLyHmVjqVqp7ESbdTUR1FGScJTia8w3JwyhpIK46s+knCrZcMLW83KIfaO5bce1TFO1NUPVbVcpNerV1+ay/SmrX3i+lOaWzSfuoE/98OHwOErDs6/OpgI0xI+V6Jqo4eV3DGrTcDFd/FuQhCtpYueZukvkI8KeokvVK/kQwFndZA2CMJ1i5Ch1ek11AsgDFjG3FueelNad1ro1O/ToLvkUy/Uzf/f+U/bBngNYT083Xy5OrN7m89B67/8=</diagram></mxfile>
|
||||
112
doc/source/firmware/safety/backup-ram.rst
Normal file
112
doc/source/firmware/safety/backup-ram.rst
Normal file
@@ -0,0 +1,112 @@
|
||||
.. _backup_ram:
|
||||
|
||||
Safety Backup RAM
|
||||
=================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The STM controller's backup RAM is used to store different kinds of information that shall be preserved if the controller resets.
|
||||
The hardware setup is missing a separate powersupply for the controller's backup domain. Therefore, the backup RAM is cleared, when the power is cut.
|
||||
|
||||
The backup RAM is used to store permanent error flags (See :ref:`safety_flags`). This ensures the flags that trigger hard faults / the panic mode, can be identified, although the wathcoog resets the controller. The only way to clear them is by cutting the power.
|
||||
Because cutting the power is a way to clear the backup RAM, no separate method for clearing the error entries in the backup RAM is defined.
|
||||
|
||||
The backup RAM contents are protected by a `CRC Checksum`_.
|
||||
|
||||
The backup RAM is initialized and checked after boot. If the controller starts from a powered down state,
|
||||
the backup RAM is empty. This is detected by an invalid `Header`_ at the beginning of the backup RAM. If this is the case, the safety ocntoller
|
||||
will create a valid backup RAM image with a `Header`_, empty `Boot Status Flag Entries`_, empty `Config Overrides`_, an empty `Error Memory`_, and a valid `CRC Checksum`_.
|
||||
|
||||
If the Header is valid during boot (verified by plausible values and correct magic numbers), the backup RAM is CRC checked and the error memory is
|
||||
checked for valid entries.
|
||||
In case of a CRC error or invalid entries in the error memory, the Backup RAM is wiped and reinitialized. On top of that, the error flag :ref:`safety_flags_safety_mem_corrupt` is set.
|
||||
|
||||
.. note:: It may be possible that future versions of the hardware include a backup RAM battery / Goldcap. In this case, a way to clear the error memory will be implemented,
|
||||
because it will no longer be possible to clear the error memory by cutting the power.
|
||||
On top of that, the backup memory will also contain the calibration data.
|
||||
|
||||
.. note:: The firmware will not use the ``NOP`` entries of the error memory by default, but they will be respected by the validity checker.
|
||||
|
||||
Partitioning and Entries
|
||||
------------------------
|
||||
|
||||
The backup RAM consists of multiple sections. The memory section are listed below.
|
||||
|
||||
Header
|
||||
~~~~~~
|
||||
|
||||
The backup memory header is located at offset address:
|
||||
|
||||
.. doxygendefine:: SAFETY_MEMORY_HEADER_ADDRESS
|
||||
|
||||
The header is defined by the following structure:
|
||||
|
||||
.. doxygenstruct:: safety_memory_header
|
||||
|
||||
The validity of the header is checked, if the magic and inverse amgic fields contain the correct values, and if the offset address pointers
|
||||
have values that are located inside the error memory and are not ``0`` or the same value.
|
||||
|
||||
The safety memory header magic is:
|
||||
|
||||
.. doxygendefine:: SAFETY_MEMORY_MAGIC
|
||||
|
||||
|
||||
.. _backup_ram_boot_flags:
|
||||
|
||||
Boot Status Flag Entries
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The boot status flag entries are use to store system states over resets.
|
||||
The flags are stored in memory using the follwoing structure:
|
||||
|
||||
.. doxygenstruct:: safety_memory_boot_status
|
||||
|
||||
Flags are evaluated active, if the corresponding word is unequal to ``0``.
|
||||
|
||||
Config Overrides
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Config overrides are used to override persistance and flag weights dynamically. The safety controller will parse the entries on
|
||||
startup.
|
||||
|
||||
======================= ============ ================= ===================== =====================================
|
||||
Entry Byte 1 (LSB) Byte 2 Byte 3 Byte 4 (MSB)
|
||||
======================= ============ ================= ===================== =====================================
|
||||
Weight override ``0xA2`` ``Weight`` ``Flag Number`` reserved don't care (written as 0xAA)
|
||||
Persistance override ``0x8E`` ``Persistance`` ``Flag Number`` reserved don't care (written as 0xBB)
|
||||
======================= ============ ================= ===================== =====================================
|
||||
|
||||
All words, not matching the table above are ignored and do not cause an error. By default the firmware fills this memory area with zeroes.
|
||||
|
||||
Error Memory
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The error memory contains error entries in form of 32 bit words. The entries are coded as stated below.
|
||||
|
||||
``Error Flag`` entries are used to restore error flags after boot. In theory, all flags can be set using this entry type.
|
||||
However, only persistent flags are stored in the error memory by the firmware.
|
||||
|
||||
``NOP`` entries have no meaning. They are used as a filler. When adding a new error memory entry, the error memory is scanned until the first ``NOP`` entry is found.
|
||||
It is replaced with a valid entry. If the error memory contains a word, that is not defined below, it is considered invalid and will trigger the RAM checker on boot.
|
||||
``NOP`` entries can be used to preallocate the error memory in advance. if the end of the error memory is reached, it is expanded by 1 word to first
|
||||
the new error entry, until the backup RAM is full. After this, no further errors are stored.
|
||||
|
||||
If the same persistent error is triggered mutliple times, the ``COUNTER`` in the error entry is incremented.
|
||||
|
||||
======================= ============ ================= ===================== =====================================
|
||||
Entry Byte 1 (LSB) Byte 2 Byte 3 Byte 4 (MSB)
|
||||
======================= ============ ================= ===================== =====================================
|
||||
Error Flag ``0x51`` ``Flag Number`` ``COUNTER 7:0`` ``COUNTER 15:8``
|
||||
NOP Entry ``0x22`` ``0x12`` ``0xAA`` ``0xC1``
|
||||
======================= ============ ================= ===================== =====================================
|
||||
|
||||
CRC Checksum
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The CRC checksum is located after the error memory. The checksum is calculated by the internal peripheral module of the STM32F4 controller.
|
||||
Therefore, the CRC calculation is fixed.
|
||||
|
||||
The polynomial is ``0x4C11DB7`` (Ethernet CRC32):
|
||||
|
||||
.. math:: P_{CRC}(x) = x^{32}+x^{26}+x^{23}+x^{22}+x^{16}+x^{12}+x^{11}+x^{10}+x^{8}+x^{7}+x^{5}+x^{4}+x^{2}+x+1
|
||||
20
doc/source/firmware/safety/error-handling.rst
Normal file
20
doc/source/firmware/safety/error-handling.rst
Normal file
@@ -0,0 +1,20 @@
|
||||
.. _safety_handling:
|
||||
|
||||
Error Handling
|
||||
==============
|
||||
|
||||
.. _safety_panic:
|
||||
|
||||
Panic Mode
|
||||
----------
|
||||
|
||||
|
||||
.. _safety_error_mem:
|
||||
|
||||
Error memory
|
||||
------------
|
||||
|
||||
Permanent errors are stored in the backup RAM of the STM. This ensures, that errors can be read even after a full system reset has occured.
|
||||
|
||||
.. seealso:: :ref:`backup_ram`
|
||||
|
||||
150
doc/source/firmware/safety/flags.rst
Normal file
150
doc/source/firmware/safety/flags.rst
Normal file
@@ -0,0 +1,150 @@
|
||||
.. _safety_flags:
|
||||
|
||||
Safety Flags
|
||||
============
|
||||
|
||||
The safety flags are represented in software by the following enums
|
||||
|
||||
.. doxygenenum:: safety_flag
|
||||
|
||||
The safety flags can be temporarily or permanent. Some temporary flags are reset automatically, once the error condition disappears. Others have to be explicitly cleared.
|
||||
The safety weights (if a flag stops the PID controller, or triggers the panic mode) are configured by default as described below. However, it will be possible to override these weights by
|
||||
setting config entries in the safety memory.
|
||||
|
||||
.. todo:: Change docu of config entires in memory
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
.. _safety_flags_adc_overflow:
|
||||
|
||||
ERR_FLAG_MEAS_ADC_OVERFLOW
|
||||
--------------------------
|
||||
|
||||
``ERR_FLAG_MEAS_ADC_OVERFLOW`` is triggered in case of an overflow in the signal path of the measurement ADC. This should never happen unless there is a bug in the software.
|
||||
|
||||
========== ============= ============= ===========
|
||||
persistent self-clearing Stops PID Panic Mode
|
||||
========== ============= ============= ===========
|
||||
yes no yes no
|
||||
========== ============= ============= ===========
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
.. _safety_flags_adc_off:
|
||||
|
||||
ERR_FLAG_MEAS_ADC_OFF
|
||||
---------------------
|
||||
|
||||
``ERR_FLAG_MEAS_ADC_OFF`` signals that the measurement ADC for the PT1000 sensor is deactivated. This flag is automatically cleared by the firmware
|
||||
once the ADC is started.
|
||||
|
||||
========== ============= ============= ===========
|
||||
persistent self-clearing Stops PID Panic Mode
|
||||
========== ============= ============= ===========
|
||||
no yes yes no
|
||||
========== ============= ============= ===========
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
.. _safety_flags_adc_watchdog:
|
||||
|
||||
ERR_FLAG_MEAS_ADC_WATCHDOG
|
||||
--------------------------
|
||||
|
||||
``ERR_FLAG_MEAS_ADC_WATCHDOG`` is used as a wire break detection mechanism. This flag is set when the PT1000 measurement ADC detects an invalid resistance measurement.
|
||||
|
||||
.. seealso:: :ref:`ADC Watchdog<firmware_meas_adc_watchdog>`
|
||||
|
||||
========== ============= ============= ===========
|
||||
persistent self-clearing Stops PID Panic Mode
|
||||
========== ============= ============= ===========
|
||||
no no yes no
|
||||
========== ============= ============= ===========
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
.. _safety_flags_adc_unstable:
|
||||
|
||||
ERR_FLAG_MEAS_ADC_UNSTABLE
|
||||
--------------------------
|
||||
|
||||
``ERR_FLAG_MEAS_ADC_UNSTABLE`` is set if the Moving Average Filter of the PT1000 ADC detects a bigger deviation between input and filtered output value.
|
||||
The flag is automatically cleared by the controller as soon as the unstable condition is not met anymore. For this, the filter input to filter output difference has to stay below a certain threshold for a defined amount of samples.
|
||||
|
||||
.. seealso:: :ref:`firmware_meas_adc_filter`
|
||||
|
||||
========== ============= ============= ===========
|
||||
persistent self-clearing Stops PID Panic Mode
|
||||
========== ============= ============= ===========
|
||||
no yes no no
|
||||
========== ============= ============= ===========
|
||||
|
||||
|
||||
.. _safety_flags_safety_mem_corrupt:
|
||||
|
||||
ERR_FLAG_SAFETY_MEM_CORRUPT
|
||||
---------------------------
|
||||
|
||||
``ERR_FLAG_SAFETY_MEM_CORRUPT`` is set during the initialization of the controller, in case a corrupted safety memory is encountered.
|
||||
In this case the error memory is reinitialized and the flag is set in the error memory. Afer a reboot it will stay asserted until the
|
||||
safety backup memory is cleared.
|
||||
|
||||
.. seealso:: :ref:`backup_ram`
|
||||
|
||||
========== ============= ============= ===========
|
||||
persistent self-clearing Stops PID Panic Mode
|
||||
========== ============= ============= ===========
|
||||
yes no yes no
|
||||
========== ============= ============= ===========
|
||||
|
||||
|
||||
.. _safety_flags_stack:
|
||||
|
||||
ERR_FLAG_STACK
|
||||
---------------------------
|
||||
|
||||
``ERR_FLAG_STACK`` Shutdown of the controller, in case a corrupted safety memory is encountered.
|
||||
This error is not recoverable and will trigger the panic mode.
|
||||
|
||||
.. seealso:: :ref:`safety_stack_checking`
|
||||
|
||||
========== ============= ============= ===========
|
||||
persistent self-clearing Stops PID Panic Mode
|
||||
========== ============= ============= ===========
|
||||
yes no yes yes
|
||||
========== ============= ============= ===========
|
||||
|
||||
.. _safety_flags_timing_pid:
|
||||
|
||||
ERR_FLAG_TIMING_PID
|
||||
---------------------------
|
||||
|
||||
``ERR_FLAG_TIMING_PID`` is set if the timing monitor of the PID controller detects a violation in the sample frequency.
|
||||
The flag is recoverable and only shuts down the PID and therefore the oven control output.
|
||||
|
||||
.. seealso:: Timing Monitor
|
||||
|
||||
========== ============= ============= ===========
|
||||
persistent self-clearing Stops PID Panic Mode
|
||||
========== ============= ============= ===========
|
||||
no no yes no
|
||||
========== ============= ============= ===========
|
||||
|
||||
.. _safety_flags_overtemp:
|
||||
|
||||
ERR_FLAG_OVERTEMP
|
||||
---------------------------
|
||||
|
||||
``ERR_FLAG_OVERTEMP`` is set if the :ref:`pt1000_processing` detects an overtemperature.
|
||||
The default limit is set to:
|
||||
|
||||
.. doxygendefine:: SAFETY_DEFAULT_OVERTEMP_LIMIT_DEGC
|
||||
|
||||
However, it is possible to configure the limit and permanenty store it in the EEPROM since hardware version v1.3.
|
||||
|
||||
|
||||
========== ============= ============= ===========
|
||||
persistent self-clearing Stops PID Panic Mode
|
||||
========== ============= ============= ===========
|
||||
no no yes no
|
||||
========== ============= ============= ===========
|
||||
25
doc/source/firmware/safety/index.rst
Normal file
25
doc/source/firmware/safety/index.rst
Normal file
@@ -0,0 +1,25 @@
|
||||
.. _firmware_safety:
|
||||
|
||||
Safety Controller
|
||||
=================
|
||||
|
||||
The safety controller is the software component that monitors the overall condition of the reflow controller,
|
||||
and stops the output driver in case of an error.
|
||||
|
||||
Severe error flags, like a drifting reference voltage, stop the PID controller and force the output to zero.
|
||||
The controller stays in a usable state. After the errors have been cleared, normal operation may continue.
|
||||
|
||||
On the other hand, fatal errors like an over-temperature error, or memory problem, lead to the activation of the :ref:`safety_panic`,
|
||||
which forces the output zero, but does not allow any further interaction.
|
||||
|
||||
On top of this, a :ref:`backup_ram` is implemented. It stores permantent errors, which are reset at a restart. On top of that, it stores the :ref:`backup_ram_boot_flags`,
|
||||
which are used to retain boot information across resets, for example to communicate with the firmware updater etc. The RAM also contains entries, that allow overrides of flag weights and persistance.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
flags
|
||||
backup-ram
|
||||
error-handling
|
||||
startup-tests
|
||||
stack-checking
|
||||
39
doc/source/firmware/safety/stack-checking.rst
Normal file
39
doc/source/firmware/safety/stack-checking.rst
Normal file
@@ -0,0 +1,39 @@
|
||||
.. _safety_stack_checking:
|
||||
|
||||
Safety Stack Checking
|
||||
=====================
|
||||
|
||||
To ensure correct operation of the controller, the stack is continuously monitored. For this, the :ref:`firmware_safety` checks the stack in each run.
|
||||
These checks include:
|
||||
|
||||
1. Checking of used stack space and limit to end of stack
|
||||
2. Checking a protection area between heap and stack for memory corruption
|
||||
|
||||
Any detected error will set the :ref:`safety_flags_stack` error flag.
|
||||
|
||||
Stack Pointer Checking
|
||||
----------------------
|
||||
|
||||
The stack pointer is checked using :c:func:`stack_check_get_free`. The returned value for the remaining stack space is checked against
|
||||
|
||||
.. doxygendefine:: SAFETY_MIN_STACK_FREE
|
||||
|
||||
.. doxygenfunction:: stack_check_get_free
|
||||
|
||||
|
||||
Stack and Heap Corruption Checking
|
||||
----------------------------------
|
||||
|
||||
A section of memory is located between the stack and the heap. It is defined inside the linker script. It's size is configured by the linker script parameter ``__stack_corruption_area_size``, which is set to ``128`` by default.
|
||||
This section is filled at the initializazion of the safety controller by a call to
|
||||
|
||||
.. doxygenfunction:: stack_check_init_corruption_detect_area
|
||||
|
||||
On each run of the safety controller's handling function (:c:func:`safety_controller_handle`) the following function is called:
|
||||
|
||||
.. doxygenfunction:: stack_check_corruption_detect_area
|
||||
|
||||
|
||||
This function checks the memory area for write modifications, and therefore detects, if the stack or heap have grown outside their boundaries. This canary approach does, however, not guarantee a full protection against heap or stack overflows.
|
||||
|
||||
|
||||
23
doc/source/firmware/safety/startup-tests.rst
Normal file
23
doc/source/firmware/safety/startup-tests.rst
Normal file
@@ -0,0 +1,23 @@
|
||||
.. _safety_startup_tests:
|
||||
|
||||
Startup Tests
|
||||
=============
|
||||
|
||||
The following tests will be performed after each reset / power cycle of the controller.
|
||||
|
||||
Internal Memory Test
|
||||
--------------------
|
||||
Directly after startup and after setting up the system clocks, the controller performs memory checks on the internal SRAM and the core coupled memory.
|
||||
|
||||
RAM checking is performed by testing the following sequences:
|
||||
|
||||
- Alternating 0x55AA55AA / 0xAA55AA55 pattern
|
||||
- Alternating 0xAA55AA55 / 0x55AA55AA pattern
|
||||
- 0xFFFFFFFF constant value
|
||||
- 0x00000000 constant value
|
||||
|
||||
The following functions implement the RAM checking:
|
||||
|
||||
.. doxygenfunction:: startup_test_perform_ccm_ram_check
|
||||
|
||||
.. doxygenfunction:: startup_test_perform_system_ram_check
|
||||
8
doc/source/hardware/controller-bom.rst
Normal file
8
doc/source/hardware/controller-bom.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
.. _hw_bom:
|
||||
|
||||
Interactive BoM of Controller Board
|
||||
===================================
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<iframe src="../_static/ibom.html" width="100%" height="1500"></iframe>
|
||||
16443
doc/source/hardware/frontend-schematic_v1.2.svg
Normal file
16443
doc/source/hardware/frontend-schematic_v1.2.svg
Normal file
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 284 KiB |
10
doc/source/hardware/frontend.rst
Normal file
10
doc/source/hardware/frontend.rst
Normal file
@@ -0,0 +1,10 @@
|
||||
.. _hw_analog_fe:
|
||||
|
||||
Analog Frontend
|
||||
===============
|
||||
|
||||
Schematic
|
||||
---------
|
||||
|
||||
.. image:: frontend-schematic_v1.2.svg
|
||||
:target: /_images/frontend-schematic_v1.2.svg
|
||||
27
doc/source/hardware/hardware-watchdog.rst
Normal file
27
doc/source/hardware/hardware-watchdog.rst
Normal file
@@ -0,0 +1,27 @@
|
||||
.. _hw_watchdog:
|
||||
|
||||
Hardware Watchdog
|
||||
=================
|
||||
|
||||
the PCB (> v1.3) is equipped with an external power supply monitor and hardware watchdog IC ``STM6822S``.
|
||||
The watchdog is periodically reset by the firmware.
|
||||
|
||||
.. note:: The external watchdog is only activated in Release mode. When building the application in Debug mode, it is deactivated because setting breakpoints or other events that distrb the program flow would trigger a the external watchdog and force a software reset.
|
||||
|
||||
|
||||
During startup of the power supply, it keeps the controller in reset until the power supply is stable.
|
||||
The following picture shows the 3.3 Volt supply rail on channel 2 and the low active reset signal of the STM32F407 on channel 1.
|
||||
|
||||
.. image:: hw_watchdog_delay.png
|
||||
:alt: Image not found
|
||||
|
||||
The total startup delay is larger than 200 ms.
|
||||
|
||||
The follwoing figure shows the startup of the voltage rgulator and the reset signal.
|
||||
|
||||
.. image:: hw_watchdog_startup.png
|
||||
:alt: Image not found
|
||||
|
||||
The power supply is gradually ramped up over approximately 500 us. The external watchdog does not work fpr voltages below 0.9 Volt. Therefore the reset signal rises simultaneously.
|
||||
Once the supply voltage exceeds 0.9 Volts, the reset signal is pulled low. This ensures that the controller is not able to start until the > 200 ms startup time have passed.
|
||||
|
||||
BIN
doc/source/hardware/hw_watchdog_delay.png
Normal file
BIN
doc/source/hardware/hw_watchdog_delay.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
doc/source/hardware/hw_watchdog_startup.png
Normal file
BIN
doc/source/hardware/hw_watchdog_startup.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
20
doc/source/hardware/index.rst
Normal file
20
doc/source/hardware/index.rst
Normal file
@@ -0,0 +1,20 @@
|
||||
.. _hw:
|
||||
|
||||
Hardware
|
||||
========
|
||||
|
||||
This guide on the reflow controller's hardware is based on the ``reflow-oven-control-pcb`` -- Version ``v1.3``
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:glob:
|
||||
|
||||
*
|
||||
|
||||
Links
|
||||
-----
|
||||
|
||||
- `Reflow Oven Control PCB v1.2 schematic <https://git.shimatta.de/attachments/788fde4e-a560-445b-87ea-de1d67f6846a>`__
|
||||
- `Git Repository for Controller PCB <https://git.shimatta.de/pcb/reflow-oven-control-pcb>`__
|
||||
|
||||
|
||||
23
doc/source/hardware/modifications.rst
Normal file
23
doc/source/hardware/modifications.rst
Normal file
@@ -0,0 +1,23 @@
|
||||
.. _hardware_modifications_v1_2:
|
||||
|
||||
Hardware Modifications for PCB v1.2
|
||||
===================================
|
||||
|
||||
Analog Frontend
|
||||
---------------
|
||||
|
||||
.. note::
|
||||
Solder a ``100 nF`` capacitor parallel to ``R315`` in order to implement a low pass characteristic of the difference amplifier in the :ref:`analog frontend<hw_analog_fe>`. This massively increases EMI performance which prevents the :ref:`ADC Watchdog<firmware_meas_adc_watchdog>` from triggering.
|
||||
|
||||
Power Supply
|
||||
------------
|
||||
.. note::
|
||||
Replace transformer ``BV-EI-303-2010`` with ``BV-EI-303-2050``, which has the same footprint but a little more power and does not heat that much.
|
||||
|
||||
.. _hardware_modifications_v1_3:
|
||||
|
||||
Hardware Modifications for PCB v1.3
|
||||
===================================
|
||||
|
||||
.. note::
|
||||
solder jumpers to bridge GND and Earth together must be soldered for the SD card slot to work properly. The card detect's switch terminal is on Earth potential.
|
||||
27
doc/source/index.rst
Normal file
27
doc/source/index.rst
Normal file
@@ -0,0 +1,27 @@
|
||||
.. Shimatta Reflow Controller documentation master file, created by
|
||||
sphinx-quickstart on Thu Jul 30 22:56:09 2020.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to Shimatta Reflow Controller's documentation!
|
||||
======================================================
|
||||
|
||||
Quick Links
|
||||
===========
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`hardware_modifications_v1_2`
|
||||
* :ref:`hardware_modifications_v1_3`
|
||||
|
||||
.. warning::
|
||||
Although the Shimatta Reflow Controller provides a bunch of safety mechanisms that -- in theory -- prevent your house from burning down, NEVER leave the oven controller running unattended. This project is published 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.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents
|
||||
|
||||
self
|
||||
usage/index
|
||||
hardware/index
|
||||
firmware/index
|
||||
license
|
||||
427
doc/source/license.rst
Normal file
427
doc/source/license.rst
Normal file
@@ -0,0 +1,427 @@
|
||||
.. _license:
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
The firmware of the reflow controller and its hardware are distributed under the GPLv2 license (see below).
|
||||
The firmware includes following third-party software libraries:
|
||||
|
||||
- ``shellmatta`` by ``Stefan Strobel`` <https://git.shimatta.net/shimatta/shellmatta>, licensed under ``Mozilla Public License Version 2.0``
|
||||
- ``CMSIS`` by ``ARM Limited`` <https://github.com/ARM-software/CMSIS_5>, licensed under ``Apache License Version 2.0, January 2004``
|
||||
- ``STM Header files and startup code`` by ``ST Microelectronics``, licensed under a `custom license <ST License for Used Header Files_>`_
|
||||
- ``SHA-256 Library`` by ``Alain Mosnier`` <https://github.com/amosnier/sha-2>, licensed under ``Zero Clause BSD License`` or the ``Unlicense``
|
||||
- ``FatFS`` Library by ``ChaN`` licensed under a `custom license <FatFS License_>`_
|
||||
|
||||
|
||||
FatFS License
|
||||
-------------
|
||||
|
||||
FatFs has being developped as a personal project of the author, ChaN. It is free from the code anyone else wrote at current release. Following code block shows a copy of the FatFs license document that heading the source files.::
|
||||
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT Filesystem Module Rx.xx /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 20xx, ChaN, all right reserved.
|
||||
/
|
||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||
/ source and binary forms, with or without modification, are permitted provided
|
||||
/ that the following condition is met:
|
||||
/
|
||||
/ 1. Redistributions of source code must retain the above copyright notice,
|
||||
/ this condition and the following disclaimer.
|
||||
/
|
||||
/ This software is provided by the copyright holder and contributors "AS IS"
|
||||
/ and any warranties related to this software are DISCLAIMED.
|
||||
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
||||
/ by use of this software.
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
Therefore FatFs license is one of the BSD-style licenses, but there is a significant feature. FatFs is mainly intended for embedded systems. In order to extend the usability for commercial products, the redistributions of FatFs in binary form, such as embedded code, binary library and any forms without source code, do not need to include about FatFs in the documentations. This is equivalent to the 1-clause BSD license. Of course FatFs is compatible with the most of open source software licenses include GNU GPL. When you redistribute the FatFs source code with changes or create a fork, the license can also be changed to GNU GPL, BSD-style license or any open source software license that not conflict with FatFs license.
|
||||
|
||||
ST License for Used Header Files
|
||||
--------------------------------
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
--------------------------
|
||||
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
~~~~~~~~
|
||||
|
||||
The licenses for most software are designed to take away your freedom
|
||||
to share and change it. By contrast, the GNU General Public License is
|
||||
intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) 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
|
||||
this service 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 make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. 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.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on,
|
||||
we want its recipients to know that what they have is not the
|
||||
original, so that any problems introduced by others will not reflect
|
||||
on the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at
|
||||
all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**0.** This License applies to any program or other work which
|
||||
contains a notice placed by the copyright holder saying it may be
|
||||
distributed under the terms of this General Public License. The
|
||||
"Program", below, refers to any such program or work, and a "work
|
||||
based on the Program" means either the Program or any derivative work
|
||||
under copyright law: that is to say, a work containing the Program or
|
||||
a portion of it, either verbatim or with modifications and/or
|
||||
translated into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".) Each licensee
|
||||
is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the Program
|
||||
(independent of having been made by running the Program). Whether that
|
||||
is true depends on what the Program does.
|
||||
|
||||
**1.** You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
**2.** You may modify your copy or copies of the Program or any
|
||||
portion of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
|
||||
**a)** You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
|
||||
**b)** You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any part
|
||||
thereof, to be licensed as a whole at no charge to all third parties
|
||||
under the terms of this License.
|
||||
|
||||
|
||||
**c)** If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such interactive
|
||||
use in the most ordinary way, to print or display an announcement
|
||||
including an appropriate copyright notice and a notice that there is
|
||||
no warranty (or else, saying that you provide a warranty) and that
|
||||
users may redistribute the program under these conditions, and telling
|
||||
the user how to view a copy of this License. (Exception: if the
|
||||
Program itself is interactive but does not normally print such an
|
||||
announcement, your work based on the Program is not required to print
|
||||
an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
**3.** You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
|
||||
**a)** Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections 1
|
||||
and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
|
||||
**b)** Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your cost of
|
||||
physically performing source distribution, a complete machine-readable
|
||||
copy of the corresponding source code, to be distributed under the
|
||||
terms of Sections 1 and 2 above on a medium customarily used for
|
||||
software interchange; or,
|
||||
|
||||
|
||||
**c)** Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is allowed
|
||||
only for noncommercial distribution and only if you received the
|
||||
program in object code or executable form with such an offer, in
|
||||
accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
**4.** You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt otherwise
|
||||
to copy, modify, sublicense or distribute the Program is void, and
|
||||
will automatically terminate your rights under this License. However,
|
||||
parties who have received copies, or rights, from you under this
|
||||
License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
**5.** You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
**6.** Each time you redistribute the Program (or any work based on
|
||||
the Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
**7.** If, as a consequence of a court judgment or allegation of
|
||||
patent infringement or for any other reason (not limited to patent
|
||||
issues), 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 distribute so as to satisfy simultaneously your
|
||||
obligations under this License and any other pertinent obligations,
|
||||
then as a consequence you may not distribute the Program at all. For
|
||||
example, if a patent license would not permit royalty-free
|
||||
redistribution of the Program by all those who receive copies directly
|
||||
or indirectly through you, then the only way you could satisfy both it
|
||||
and this License would be to refrain entirely from distribution of the
|
||||
Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
**8.** If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
**9.** The Free Software Foundation may publish revised and/or new
|
||||
versions of the 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 a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Program does not specify a
|
||||
version number of this License, you may choose any version ever
|
||||
published by the Free Software Foundation.
|
||||
|
||||
**10.** If you wish to incorporate parts of the Program into other
|
||||
free programs whose distribution conditions are different, write to
|
||||
the author to ask for permission. For software which is copyrighted by
|
||||
the Free Software Foundation, write to the Free Software Foundation;
|
||||
we sometimes make exceptions for this. Our decision will be guided by
|
||||
the two goals of preserving the free status of all derivatives of our
|
||||
free software and of promoting the sharing and reuse of software
|
||||
generally.
|
||||
|
||||
**NO WARRANTY**
|
||||
|
||||
**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||
|
||||
**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE 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.
|
||||
|
||||
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
|
||||
convey 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 an idea of what it does.
|
||||
Copyright (C) yyyy 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 2
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper
|
||||
mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision 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, the
|
||||
commands you use may be called something other than \`show w' and
|
||||
\`show c'; they could even be mouse-clicks or menu items--whatever
|
||||
suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or
|
||||
your school, if any, to sign a "copyright disclaimer" for the program,
|
||||
if necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright
|
||||
interest in the program ``Gnomovision``
|
||||
(which makes passes at compilers) written
|
||||
by James Hacker.
|
||||
|
||||
signature of Ty Coon, 1 April 1989
|
||||
Ty Coon, President of Vice``
|
||||
|
||||
This 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](<https://www.gnu.org/licenses/lgpl.html>) instead of this
|
||||
License.
|
||||
15
doc/source/reflow-profiles/reflow-245.tpr
Normal file
15
doc/source/reflow-profiles/reflow-245.tpr
Normal file
@@ -0,0 +1,15 @@
|
||||
# This is a comment
|
||||
pid_conf 10 0.3 5 60 2.5 0.5
|
||||
temp_set 50
|
||||
wait_temp 45
|
||||
temp_set 45
|
||||
temp_ramp 150 120
|
||||
temp_ramp 190 90
|
||||
pid_conf 9 0.5 6 60 2.5 0.5
|
||||
temp_set 250
|
||||
wait_temp 245
|
||||
temp_off
|
||||
beep 1
|
||||
wait_time 1
|
||||
beep 0
|
||||
|
||||
17
doc/source/usage/calibration.rst
Normal file
17
doc/source/usage/calibration.rst
Normal file
@@ -0,0 +1,17 @@
|
||||
.. _usage_calibration:
|
||||
|
||||
Calibration
|
||||
===========
|
||||
|
||||
In order to provide higher measurement accuracy, the PT1000 measurement can be calibrated. The calibration only calibrates the internal :ref:`hw_analog_fe` and not the PT1000 Sensor element itself.
|
||||
The Sensor element must be conform with the standard PT1000 norms.
|
||||
|
||||
Tests have shown, that a calibration is most likely not necessary, because the resolution of the 12 bit analog measurement is far worse than the reistance reading error produced by the :ref:`hw_analog_fe`.
|
||||
Calibration might only be necessary if no precission reistors in the frontend hardware are used.
|
||||
|
||||
Calibration can be performed the following ways:
|
||||
|
||||
Command Line Calibration
|
||||
------------------------
|
||||
|
||||
Use the :ref:`command_line` to invoke the :ref:`shell_command_calibrate` command.
|
||||
88
doc/source/usage/command-line.rst
Normal file
88
doc/source/usage/command-line.rst
Normal file
@@ -0,0 +1,88 @@
|
||||
.. _command_line:
|
||||
|
||||
Command Line Interface
|
||||
======================
|
||||
|
||||
This section describes the command line interface located on the UART interface.
|
||||
The command line interface is implemented using a "shellmatta" shell module <https://git.shimatta.net/shimatta/shellmatta>
|
||||
|
||||
Hardware Settings
|
||||
-----------------
|
||||
|
||||
General Settings
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The UART is configured for the following settings:
|
||||
|
||||
- 115200 Baud
|
||||
- 1 Stopbit
|
||||
- No parity
|
||||
- 8 data bits
|
||||
|
||||
|
||||
Setup in Debug Build
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If the Reflow controller is build in **debug** mode, the UART is located on the internal spring contact connector, which is also used for the SWD interface.
|
||||
|
||||
Setup in Release Build
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In case of a **release** build, the UART is externally accessible on the DIGIO Header. The voltage level is 3.3 Volt LVCMOS. The inputs are ESD protected. Overvoltage is interally clamped and may dammage the clamping diodes!
|
||||
|
||||
- DIGIO2: Reflow Controller's TX
|
||||
- DIGIO3: Reflow Controller's RX
|
||||
|
||||
|
||||
Shell Commands
|
||||
--------------
|
||||
|
||||
The following shell commands are available.
|
||||
|
||||
- `safety-flags <safety-flags_>`_ (alias: flags)
|
||||
- `calibrate`_ (alias: cal)
|
||||
|
||||
safety-flags
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The ``safety-flags`` (``flags``) command displays the status of all safety flags and analog monitors. See: :ref:`safety_flags`
|
||||
|
||||
|
||||
.. _shell_command_calibrate:
|
||||
|
||||
calibrate
|
||||
~~~~~~~~~
|
||||
|
||||
The ``calibrate`` (``cal``) command is used to calibrate the :ref:`hw_analog_fe`, in order to ensure correct resistance measurement.
|
||||
Calibration is most likely not necessary! See the :ref:`usage_calibration` page.
|
||||
|
||||
The command will guide you through the calibration process and will ask for two reference resistors with ``1000 Ohm`` and ``2000 Ohm`` values.
|
||||
Calibration can be aborted using ``CTRL + C``.
|
||||
|
||||
|
||||
.. _shell_command_hang:
|
||||
|
||||
hang
|
||||
~~~~
|
||||
|
||||
The ``hang`` command hangs the main-loop in an infinite loop. This function tests, whether the controller is correctly rescued by the watchdog.
|
||||
|
||||
|
||||
.. _shell_command_ui_emulate:
|
||||
|
||||
ui-emulate
|
||||
~~~~~~~~~~
|
||||
|
||||
The ``ui-emulate`` command emulates the rotary encoder and button from the shell. The following keys are available:
|
||||
|
||||
========== ================================
|
||||
Key Emulation
|
||||
========== ================================
|
||||
``CTRL+C`` Exit the command
|
||||
``ENTER`` Button press: short released
|
||||
``s`` Rotary Encoder: anti-clockwise
|
||||
``w`` Rotary Encoder: clockwise
|
||||
``l`` Button press: long
|
||||
``k`` Button press: short
|
||||
``r`` Button press: long released
|
||||
========== ================================
|
||||
12
doc/source/usage/index.rst
Normal file
12
doc/source/usage/index.rst
Normal file
@@ -0,0 +1,12 @@
|
||||
.. _usage:
|
||||
|
||||
Reflow Controller Usage Guide
|
||||
=============================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
command-line
|
||||
calibration
|
||||
|
||||
|
||||
3
error-mem-viewer/.gitignore
vendored
Normal file
3
error-mem-viewer/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*.ui~
|
||||
*.user
|
||||
*.user*
|
||||
26
error-mem-viewer/CMakeLists.txt
Normal file
26
error-mem-viewer/CMakeLists.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
project(error-mem-viewer)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
pkg_search_module(GLIB REQUIRED glib-2.0)
|
||||
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
|
||||
pkg_check_modules(GTK_MOD REQUIRED gmodule-2.0)
|
||||
|
||||
aux_source_directory("src" SRCES)
|
||||
include_directories("include" ${GLIB_INCLUDE_DIRS} ${GTK3_INCLUDE_DIRS} ${GTK_MOD_INCLUDE_DIRS})
|
||||
|
||||
add_subdirectory(resources)
|
||||
|
||||
set(SOURCE_GENERATED
|
||||
${CMAKE_CURRENT_BINARY_DIR}/resources/resources.c
|
||||
)
|
||||
SET_SOURCE_FILES_PROPERTIES(${SOURCE_GENERATED} PROPERTIES GENERATED 1)
|
||||
|
||||
add_compile_options(-Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter)
|
||||
|
||||
link_directories(${GLIB_LINK_DIRS} ${GTK3_LINK_DIRS} ${GTK_MOD_LINK_DIRS})
|
||||
add_definitions(${GLIB2_CFLAGS_OTHER} ${GTK_MOD_CFLAGS_OTHER})
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SRCES} ${SOURCE_GENERATED})
|
||||
target_link_libraries(${PROJECT_NAME} ${GLIB_LDFLAGS} ${GTK3_LDFLAGS} ${GTK_MOD_LDFLAGS})
|
||||
add_dependencies(${PROJECT_NAME} glib-resources)
|
||||
10
error-mem-viewer/include/error-mem-viewer/crc.h
Normal file
10
error-mem-viewer/include/error-mem-viewer/crc.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef _CRC_H_
|
||||
#define _CRC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
uint32_t calculate_stm_crc(uint32_t *data, size_t len);
|
||||
|
||||
|
||||
#endif /* _CRC_H_ */
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef _ERR_MEM_VIEWER_ADDRESS_CELL_RENDERER_H_
|
||||
#define _ERR_MEM_VIEWER_ADDRESS_CELL_RENDERER_H_
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_DECLARE_FINAL_TYPE(ErrMemViewHexCellRenderer, err_mem_view_hex_cell_renderer, ERR_MEM_VIEW, HEX_CELL_RENDERER, GtkCellRendererText)
|
||||
#define ERR_MEM_VIEW_TYPE_HEX_CELL_RENDERER (err_mem_view_address_cell_renderer_get_type())
|
||||
|
||||
GtkCellRenderer *err_mem_view_hex_cell_renderer_new();
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _ERR_MEM_VIEWER_ADDRESS_CELL_RENDERER_H_ */
|
||||
@@ -0,0 +1,58 @@
|
||||
#ifndef _SAFETY_MEM_TYPES_H_
|
||||
#define _SAFETY_MEM_TYPES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Magic number to signal a valid safety memory header.
|
||||
*/
|
||||
#define SAFETY_MEMORY_MAGIC 0x12AA5CB7
|
||||
|
||||
/**
|
||||
* @brief Error memory NOP entry
|
||||
*/
|
||||
#define SAFETY_MEMORY_NOP_ENTRY 0xC1AA1222
|
||||
|
||||
/**
|
||||
* @brief Safety memory header
|
||||
*/
|
||||
struct safety_memory_header {
|
||||
uint32_t magic; /**< @brief Magic. Set to @ref SAFETY_MEMORY_MAGIC */
|
||||
uint32_t boot_status_offset; /**< @brief Offset of the safety_memory_boot_status struct (in 32 bit words)*/
|
||||
uint32_t config_overrides_offset; /**< @brief Offset address of override entries */
|
||||
uint32_t config_overrides_len; /**< @brief Length of override entries in words */
|
||||
uint32_t firmware_update_filename; /**< @brief Filename of the firmware update. This string is at maximum 256 bytes long including the 0 terminator */
|
||||
uint32_t err_memory_offset; /**< @brief Offset of the error memory */
|
||||
uint32_t err_memory_end; /**< @brief End of the error memory. This points to the word after the error memory, containing the CRC of the whole backup RAM. */
|
||||
uint32_t crc; /**< @brief CRC of the header */
|
||||
};
|
||||
|
||||
struct safety_memory_boot_status {
|
||||
/**
|
||||
* @brief Reboot into the bootloader
|
||||
*
|
||||
* When this flag is set, the controller will load the bootloader to
|
||||
* memory and execute it.
|
||||
*/
|
||||
uint32_t reboot_to_bootloader;
|
||||
|
||||
/**
|
||||
* @brief Bootloader has updated the code
|
||||
*
|
||||
* This flag is set, if the firmware ahs been updated successfully
|
||||
*/
|
||||
uint32_t code_updated;
|
||||
|
||||
/**
|
||||
* @brief reset_from_panic
|
||||
*
|
||||
* This flag is set, when entering the panic mode.
|
||||
* Because the panic mode is reset by a watchdog reset,
|
||||
* this flag is needed, in order to ensure, that the panic is handled correcly after
|
||||
* the watchdog reset.
|
||||
*/
|
||||
uint32_t reset_from_panic;
|
||||
};
|
||||
|
||||
|
||||
#endif /* _SAFETY_MEM_TYPES_H_ */
|
||||
9
error-mem-viewer/resources/CMakeLists.txt
Normal file
9
error-mem-viewer/resources/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
add_custom_target(glib-resources DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/resources.c")
|
||||
add_custom_command(DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/*.ui"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/resources.xml"
|
||||
OUTPUT
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/resources.c"
|
||||
COMMAND
|
||||
glib-compile-resources --target="${CMAKE_CURRENT_BINARY_DIR}/resources.c" --sourcedir="${CMAKE_CURRENT_SOURCE_DIR}" --generate-source "${CMAKE_CURRENT_SOURCE_DIR}/resources.xml"
|
||||
)
|
||||
120
error-mem-viewer/resources/main-window.ui
Normal file
120
error-mem-viewer/resources/main-window.ui
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.38.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.24"/>
|
||||
<object class="GtkWindow" id="main-window">
|
||||
<property name="name">main-window</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkInfoBar" id="info-bar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="message-type">warning</property>
|
||||
<property name="show-close-button">True</property>
|
||||
<property name="revealed">False</property>
|
||||
<signal name="response" handler="info_bar_close_cb" swapped="no"/>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkButtonBox">
|
||||
<property name="can-focus">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<property name="layout-style">end</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child internal-child="content_area">
|
||||
<object class="GtkBox">
|
||||
<property name="can-focus">False</property>
|
||||
<property name="spacing">16</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="error-mem-tree-view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection"/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header-bar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="title" translatable="yes">Error Memory Viewer</property>
|
||||
<property name="subtitle" translatable="yes">Reflow Controller Error Memory Viewer</property>
|
||||
<property name="show-close-button">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="open-button">
|
||||
<property name="label">gtk-open</property>
|
||||
<property name="name">open-button</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="use-stock">True</property>
|
||||
<property name="always-show-image">True</property>
|
||||
<signal name="clicked" handler="open_button_clicked_cb" swapped="no"/>
|
||||
<style>
|
||||
<class name="suggested-action"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
6
error-mem-viewer/resources/resources.xml
Normal file
6
error-mem-viewer/resources/resources.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/gui">
|
||||
<file compressed="true" alias="main">main-window.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
25
error-mem-viewer/src/crc.c
Normal file
25
error-mem-viewer/src/crc.c
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <error-mem-viewer/crc.h>
|
||||
|
||||
static uint32_t do_crc(uint32_t init, uint32_t data)
|
||||
{
|
||||
uint32_t crc = init;
|
||||
uint32_t cnt;
|
||||
|
||||
for (cnt=0; cnt < 32; cnt++) {
|
||||
crc = ((int32_t)(crc ^ data))<0 ? (crc << 1) ^ 0x04C11DB7 : crc << 1;
|
||||
data <<=1;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t calculate_stm_crc(uint32_t *data, size_t len)
|
||||
{
|
||||
uint32_t crc = ~0U;
|
||||
|
||||
while (len--) {
|
||||
crc = do_crc(crc, *data++);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
81
error-mem-viewer/src/err-mem-viewer-hex-cell-renderer.c
Normal file
81
error-mem-viewer/src/err-mem-viewer-hex-cell-renderer.c
Normal file
@@ -0,0 +1,81 @@
|
||||
#include <error-mem-viewer/err-mem-viewer-hex-cell-renderer.h>
|
||||
#include <string.h>
|
||||
|
||||
struct _ErrMemViewHexCellRenderer {
|
||||
GtkCellRendererText base;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_HEXNUM = 1,
|
||||
PROP_COUNT
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(ErrMemViewHexCellRenderer, err_mem_view_address_cell_renderer, GTK_TYPE_CELL_RENDERER_TEXT)
|
||||
|
||||
static void err_mem_view_address_cell_renderer_init(ErrMemViewHexCellRenderer *self)
|
||||
{
|
||||
(void)self;
|
||||
}
|
||||
|
||||
static void convert_gvalue_uint_to_string(const GValue *in, GValue *out)
|
||||
{
|
||||
uint32_t val;
|
||||
char text[32];
|
||||
|
||||
if (!in || !out)
|
||||
return;
|
||||
|
||||
g_value_init(out, G_TYPE_STRING);
|
||||
|
||||
val = g_value_get_uint(in);
|
||||
snprintf(text, sizeof(text), "0x%08X", val);
|
||||
g_value_set_string(out, text);
|
||||
}
|
||||
|
||||
static void err_mem_view_address_cell_renderer_set_property(GObject *obj, guint param_id, const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
GValue val = G_VALUE_INIT;
|
||||
|
||||
switch (param_id) {
|
||||
case PROP_HEXNUM:
|
||||
convert_gvalue_uint_to_string(value, &val);
|
||||
g_object_set_property(obj, "text", &val);
|
||||
g_value_unset(&val);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void err_mem_view_address_cell_renderer_get_property(GObject *object,
|
||||
guint param_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
(void)value;
|
||||
|
||||
switch (param_id) {
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GParamSpec *properties[PROP_COUNT];
|
||||
|
||||
void err_mem_view_address_cell_renderer_class_init(ErrMemViewHexCellRendererClass *klass)
|
||||
{
|
||||
GObjectClass *oclass = G_OBJECT_CLASS(klass);
|
||||
|
||||
oclass->set_property = err_mem_view_address_cell_renderer_set_property;
|
||||
oclass->get_property = err_mem_view_address_cell_renderer_get_property;
|
||||
|
||||
properties[PROP_HEXNUM] = g_param_spec_uint("hex-num", "hex-num", "Hex number to display", 0U, UINT_MAX, 0U, G_PARAM_WRITABLE);
|
||||
g_object_class_install_properties(oclass, PROP_COUNT, properties);
|
||||
}
|
||||
|
||||
GtkCellRenderer *err_mem_view_hex_cell_renderer_new()
|
||||
{
|
||||
return GTK_CELL_RENDERER(g_object_new(ERR_MEM_VIEW_TYPE_HEX_CELL_RENDERER, NULL));
|
||||
}
|
||||
542
error-mem-viewer/src/main.c
Normal file
542
error-mem-viewer/src/main.c
Normal file
@@ -0,0 +1,542 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <error-mem-viewer/err-mem-viewer-hex-cell-renderer.h>
|
||||
#include <error-mem-viewer/safety-memory-types.h>
|
||||
#include <error-mem-viewer/crc.h>
|
||||
|
||||
enum memory_view_columns {
|
||||
MEM_VIEW_COL_ADDRESS = 0,
|
||||
MEM_VIEW_COL_DATA,
|
||||
MEM_VIEW_COL_INTERPRETATION,
|
||||
MEM_VIEW_COLOR,
|
||||
MEM_VIEW_COLUMN_COUNT
|
||||
};
|
||||
|
||||
struct application_data {
|
||||
GtkWidget *borrowed_main_window;
|
||||
GtkTreeView *borrowed_tree_view;
|
||||
GtkHeaderBar *borrowed_header_bar;
|
||||
GtkInfoBar *borrowed_info_bar;
|
||||
const char *error_memory_data;
|
||||
size_t file_size;
|
||||
};
|
||||
|
||||
enum entry_state {
|
||||
ENTRY_STATE_VALID = 0,
|
||||
ENTRY_STATE_INVALID,
|
||||
ENTRY_STATE_NOT_PARSED,
|
||||
ENTRY_STATE_BLOCK
|
||||
};
|
||||
|
||||
static void append_data(GtkTreeStore *store, GtkTreeIter *parent, GtkTreeIter *iter, GString *interpretation, enum entry_state state, uint32_t addr, uint32_t val)
|
||||
{
|
||||
const GdkRGBA invalid_color = {
|
||||
.red = 1.0,
|
||||
.alpha = 1.0,
|
||||
.green = 0.0,
|
||||
.blue = 0.0,
|
||||
};
|
||||
|
||||
const GdkRGBA valid_color = {
|
||||
.red = 0.0,
|
||||
.alpha = 1.0,
|
||||
.green = 1.0,
|
||||
.blue = 0.0,
|
||||
};
|
||||
|
||||
const GdkRGBA warn_color = {
|
||||
.red = 1.0,
|
||||
.alpha = 1.0,
|
||||
.green = 1.0,
|
||||
.blue = 0.0,
|
||||
};
|
||||
|
||||
const GdkRGBA block_color = {
|
||||
.red = 1.0,
|
||||
.alpha = 1.0,
|
||||
.green = 0.3,
|
||||
.blue = 0.5,
|
||||
};
|
||||
|
||||
const GdkRGBA *col;
|
||||
|
||||
switch (state) {
|
||||
case ENTRY_STATE_VALID:
|
||||
col = &valid_color;
|
||||
break;
|
||||
case ENTRY_STATE_NOT_PARSED:
|
||||
col = &warn_color;
|
||||
break;
|
||||
case ENTRY_STATE_BLOCK:
|
||||
col = &block_color;
|
||||
break;
|
||||
case ENTRY_STATE_INVALID:
|
||||
default:
|
||||
col = &invalid_color;
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_tree_store_append(store, iter, parent);
|
||||
gtk_tree_store_set(store, iter, MEM_VIEW_COL_ADDRESS, addr, MEM_VIEW_COLOR, col, MEM_VIEW_COL_INTERPRETATION, (interpretation ? interpretation->str : ""), MEM_VIEW_COL_DATA, val, -1);
|
||||
if (interpretation)
|
||||
g_string_free(interpretation, TRUE);
|
||||
}
|
||||
|
||||
static void info_bar_show_message(GtkInfoBar *info_bar, GtkMessageType type, const char *format, ...)
|
||||
{
|
||||
GString *string;
|
||||
va_list args;
|
||||
GtkWidget *content;
|
||||
GList *children, *iter;
|
||||
GtkWidget *label;
|
||||
|
||||
va_start(args, format);
|
||||
string = g_string_new(NULL);
|
||||
|
||||
g_string_vprintf(string, format, args);
|
||||
va_end(args);
|
||||
|
||||
content = gtk_info_bar_get_content_area(info_bar);
|
||||
children = gtk_container_get_children(GTK_CONTAINER(content));
|
||||
for (iter = children; iter; iter = g_list_next(iter))
|
||||
gtk_widget_destroy(GTK_WIDGET(iter->data));
|
||||
g_list_free(children);
|
||||
|
||||
label = gtk_label_new(string->str);
|
||||
gtk_container_add(GTK_CONTAINER(content), label);
|
||||
gtk_widget_show(label);
|
||||
gtk_info_bar_set_message_type(info_bar, type);
|
||||
gtk_widget_show(GTK_WIDGET(info_bar));
|
||||
gtk_info_bar_set_revealed(info_bar, TRUE);
|
||||
|
||||
g_string_free(string, TRUE);
|
||||
}
|
||||
|
||||
static bool check_err_mem_header(struct safety_memory_header *header, uint32_t *expected)
|
||||
{
|
||||
uint32_t crc;
|
||||
|
||||
crc = calculate_stm_crc((uint32_t *)header, sizeof(*header) / sizeof(uint32_t) - 1);
|
||||
if (expected)
|
||||
*expected = crc;
|
||||
if (crc == header->crc)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static GString *new_string_printf(const char *fmt, ...)
|
||||
{
|
||||
GString *string;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
string = g_string_new(NULL);
|
||||
g_string_vprintf(string, fmt, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
static void show_error_memory(GtkTreeView *tree_view, const unsigned char *memory, size_t len)
|
||||
{
|
||||
GtkTreeStore *store;
|
||||
GtkTreeIter iter;
|
||||
GtkTreeIter iter2;
|
||||
GtkTreeIter *parent_iter, *child_iter;
|
||||
enum entry_state state;
|
||||
GString *interpret;
|
||||
bool valid;
|
||||
bool analyze_further = true;
|
||||
struct safety_memory_header header;
|
||||
unsigned int i;
|
||||
uint32_t dat, expected_value;
|
||||
|
||||
store = GTK_TREE_STORE(gtk_tree_view_get_model(tree_view));
|
||||
gtk_tree_store_clear(store);
|
||||
|
||||
for (i = 0; i < len / 4; i++) {
|
||||
valid = false;
|
||||
interpret = NULL;
|
||||
dat = memory[i*4];
|
||||
dat |= ((uint32_t)memory[i*4+1]) << 8;
|
||||
dat |= ((uint32_t)memory[i*4+2]) << 16;
|
||||
dat |= ((uint32_t)memory[i*4+3]) << 24;
|
||||
|
||||
state = ENTRY_STATE_NOT_PARSED;
|
||||
|
||||
if (!analyze_further) {
|
||||
interpret = g_string_new("Not analyzed due to previous error");
|
||||
state = ENTRY_STATE_NOT_PARSED;
|
||||
parent_iter = NULL;
|
||||
child_iter = &iter;
|
||||
goto print;
|
||||
}
|
||||
/* Parse header */
|
||||
switch (i) {
|
||||
case 0: /* Magic */
|
||||
parent_iter = NULL;
|
||||
child_iter = &iter;
|
||||
append_data(store, parent_iter, child_iter, new_string_printf("Header"), ENTRY_STATE_BLOCK, i * 4, dat);
|
||||
parent_iter = child_iter;
|
||||
child_iter = &iter2;
|
||||
if (dat == SAFETY_MEMORY_MAGIC) {
|
||||
valid = true;
|
||||
interpret = g_string_new("Valid Header Magic");
|
||||
} else {
|
||||
interpret = g_string_new("Invalid Header Magic");
|
||||
analyze_further = false;
|
||||
}
|
||||
header.magic = dat;
|
||||
break;
|
||||
case 1:
|
||||
header.boot_status_offset = dat;
|
||||
|
||||
valid = true;
|
||||
interpret = new_string_printf("Boot status offset addr: %u", dat);
|
||||
break;
|
||||
case 2:
|
||||
header.config_overrides_offset = dat;
|
||||
interpret = new_string_printf("Config override offset addr: %u", dat);
|
||||
valid = true;
|
||||
break;
|
||||
case 3:
|
||||
header.config_overrides_len = dat;
|
||||
interpret = new_string_printf("Config override length: %u", dat);
|
||||
valid = true;
|
||||
break;
|
||||
case 4:
|
||||
header.firmware_update_filename = dat;
|
||||
interpret = new_string_printf("Offset of FW update filename: %u", dat);
|
||||
valid = true;
|
||||
break;
|
||||
case 5:
|
||||
header.err_memory_offset = dat;
|
||||
interpret = new_string_printf("Error memory offset addr: %u", dat);
|
||||
valid = true;
|
||||
break;
|
||||
case 6:
|
||||
header.err_memory_end = dat;
|
||||
interpret = new_string_printf("Error memory end ptr: %u", dat);
|
||||
valid = true;
|
||||
break;
|
||||
case 7:
|
||||
header.crc = dat;
|
||||
valid = check_err_mem_header(&header, &expected_value);
|
||||
if (valid) {
|
||||
interpret = new_string_printf("Header CRC: 0x%08X", dat);
|
||||
} else {
|
||||
|
||||
interpret = new_string_printf("Invalid CRC: 0x%08X | Expected: 0x%08X", dat, expected_value);
|
||||
analyze_further = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (i <= 7) {
|
||||
state = ENTRY_STATE_INVALID;
|
||||
goto print;
|
||||
}
|
||||
|
||||
/* Check if we're in the boot status structure */
|
||||
if (i >= header.boot_status_offset && i < header.boot_status_offset + sizeof(struct safety_memory_boot_status) / 4) {
|
||||
if (i == header.boot_status_offset) {
|
||||
/* First entry of boot status struct */
|
||||
parent_iter = NULL;
|
||||
child_iter = &iter;
|
||||
interpret = new_string_printf("Boot Status Struct");
|
||||
append_data(store, parent_iter, child_iter, interpret, ENTRY_STATE_BLOCK, i * 4, dat);
|
||||
parent_iter = &iter;
|
||||
child_iter = &iter2;
|
||||
interpret = NULL;
|
||||
}
|
||||
switch (i - header.boot_status_offset) {
|
||||
case 0:
|
||||
interpret = new_string_printf("%s into bootloader", (dat ? "Boot" : "Do not boot"));
|
||||
valid = true;
|
||||
break;
|
||||
case 1:
|
||||
interpret = new_string_printf("Code %s been updated", (dat ? "has" : "hasn't"));
|
||||
valid = true;
|
||||
break;
|
||||
case 2:
|
||||
interpret = new_string_printf("Panic %s", (dat ? "occured" : "did not occur"));
|
||||
valid = true;
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
interpret = new_string_printf("Value undefined!");
|
||||
break;
|
||||
}
|
||||
state = ENTRY_STATE_INVALID;
|
||||
goto print;
|
||||
}
|
||||
|
||||
if (i >= header.config_overrides_offset && i < (header.config_overrides_offset + header.config_overrides_len)) {
|
||||
if (i == header.config_overrides_offset) {
|
||||
parent_iter = NULL;
|
||||
child_iter = &iter;
|
||||
append_data(store, parent_iter, child_iter,
|
||||
new_string_printf("Config Overrides"),
|
||||
ENTRY_STATE_BLOCK, i * 4, dat);
|
||||
parent_iter = child_iter;
|
||||
child_iter = &iter2;
|
||||
}
|
||||
|
||||
interpret = new_string_printf("Config Overrides not yet implemented");
|
||||
valid = true;
|
||||
state = ENTRY_STATE_INVALID;
|
||||
goto print;
|
||||
}
|
||||
|
||||
if (i >= header.err_memory_offset && i < header.err_memory_end) {
|
||||
if (i == header.err_memory_offset) {
|
||||
parent_iter = NULL;
|
||||
child_iter = &iter;
|
||||
append_data(store, parent_iter, child_iter,
|
||||
new_string_printf("Error Memory (length: %d)", header.err_memory_end - header.err_memory_offset),
|
||||
ENTRY_STATE_BLOCK, i * 4, dat);
|
||||
parent_iter = child_iter;
|
||||
child_iter = &iter2;
|
||||
}
|
||||
|
||||
switch (dat) {
|
||||
case SAFETY_MEMORY_NOP_ENTRY:
|
||||
valid = true;
|
||||
interpret = new_string_printf("Error Memory NOP");
|
||||
break;
|
||||
default:
|
||||
if ((dat & 0xFFU) == 0x51U) {
|
||||
valid = true;
|
||||
interpret = new_string_printf("Err memory Entry");
|
||||
} else
|
||||
interpret = new_string_printf("Invalid error memory entry");
|
||||
break;
|
||||
}
|
||||
state = ENTRY_STATE_INVALID;
|
||||
goto print;
|
||||
}
|
||||
|
||||
if (i == header.err_memory_end) {
|
||||
expected_value = calculate_stm_crc((uint32_t *)memory, header.err_memory_end);
|
||||
if (expected_value == dat) {
|
||||
interpret = new_string_printf("Valid Memory CRC");
|
||||
valid = true;
|
||||
} else {
|
||||
interpret = new_string_printf("Invalid CRC. Expected: 0x%08X", expected_value);
|
||||
}
|
||||
state = ENTRY_STATE_INVALID;
|
||||
parent_iter = NULL;
|
||||
child_iter = &iter;
|
||||
goto print;
|
||||
}
|
||||
|
||||
parent_iter = NULL;
|
||||
child_iter = &iter;
|
||||
print:
|
||||
if (state != ENTRY_STATE_NOT_PARSED) {
|
||||
state = (valid ? ENTRY_STATE_VALID : ENTRY_STATE_INVALID);
|
||||
}
|
||||
append_data(store, parent_iter, child_iter, interpret, state, i * 4, dat);
|
||||
}
|
||||
|
||||
|
||||
if (!store)
|
||||
return;
|
||||
}
|
||||
|
||||
void setup_tree_view(GtkTreeView *tree_view)
|
||||
{
|
||||
GtkTreeStore *tree_store;
|
||||
GtkCellRenderer *string_renderer;
|
||||
GtkCellRenderer *hex_renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
|
||||
g_return_if_fail(GTK_IS_TREE_VIEW(tree_view));
|
||||
|
||||
tree_store = gtk_tree_store_new(MEM_VIEW_COLUMN_COUNT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, GDK_TYPE_RGBA);
|
||||
gtk_tree_view_set_model(tree_view, GTK_TREE_MODEL(tree_store));
|
||||
|
||||
string_renderer = gtk_cell_renderer_text_new();
|
||||
hex_renderer = err_mem_view_hex_cell_renderer_new();
|
||||
|
||||
column = gtk_tree_view_column_new_with_attributes("Address", hex_renderer, "hex-num", MEM_VIEW_COL_ADDRESS, "foreground-rgba", MEM_VIEW_COLOR, NULL);
|
||||
gtk_tree_view_append_column(tree_view, column);
|
||||
column = gtk_tree_view_column_new_with_attributes("Data", hex_renderer, "hex-num", MEM_VIEW_COL_DATA, "foreground-rgba", MEM_VIEW_COLOR, NULL);
|
||||
gtk_tree_view_append_column(tree_view, column);
|
||||
column = gtk_tree_view_column_new_with_attributes("Interpretation", string_renderer, "text", MEM_VIEW_COL_INTERPRETATION, "foreground-rgba", MEM_VIEW_COLOR, NULL);
|
||||
gtk_tree_view_append_column(tree_view, column);
|
||||
}
|
||||
|
||||
static ptrdiff_t get_file_size(const char *filename)
|
||||
{
|
||||
struct stat file_stat;
|
||||
int res;
|
||||
ptrdiff_t size;
|
||||
|
||||
res = stat(filename, &file_stat);
|
||||
|
||||
if (res)
|
||||
size = -1UL;
|
||||
else
|
||||
size = (ptrdiff_t)file_stat.st_size;
|
||||
|
||||
return size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loads a file to memory and decodes it using base64
|
||||
* @param name Filename
|
||||
* @param detected_size detected Size of the ouput generated
|
||||
* @return Buffer of decoded data with size \p detected_size, NULL in case of an error.
|
||||
* @note Return buffer is allocated on heap. Use free() to free the memory.
|
||||
*/
|
||||
static char *load_file_to_memory(const char *name, size_t *detected_size)
|
||||
{
|
||||
ptrdiff_t size;
|
||||
FILE *f;
|
||||
char *ret = NULL;
|
||||
size_t read_bytes;
|
||||
gsize decoded_size;
|
||||
|
||||
size = get_file_size(name);
|
||||
if (size <= 0)
|
||||
goto exit;
|
||||
|
||||
f = fopen(name, "rb");
|
||||
ret = (char *)malloc(size + 1);
|
||||
if (!ret)
|
||||
goto exit_close_file;
|
||||
|
||||
read_bytes = fread(ret, 1UL, (size_t)size, f);
|
||||
if (read_bytes != (size_t)size) {
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
goto exit_close_file;
|
||||
}
|
||||
|
||||
ret[size] = '\0';
|
||||
|
||||
g_base64_decode_inplace(ret, &decoded_size);
|
||||
if (decoded_size == 0) {
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
goto exit_close_file;
|
||||
}
|
||||
|
||||
if (detected_size)
|
||||
*detected_size = (size_t)decoded_size;
|
||||
exit_close_file:
|
||||
fclose(f);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT
|
||||
void info_bar_close_cb(GtkInfoBar *info_bar, gpointer user_data)
|
||||
{
|
||||
(void)user_data;
|
||||
|
||||
gtk_info_bar_set_revealed(info_bar, FALSE);
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT
|
||||
void open_button_clicked_cb(GtkButton *button, gpointer *user_data)
|
||||
{
|
||||
struct application_data *data = (struct application_data *)user_data;
|
||||
(void)button;
|
||||
GtkDialog *dialog;
|
||||
gint res;
|
||||
gchar *filename;
|
||||
|
||||
|
||||
dialog = GTK_DIALOG(gtk_file_chooser_dialog_new("Open File", GTK_WINDOW(data->borrowed_main_window),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
"Cancel", GTK_RESPONSE_CANCEL,
|
||||
"Open", GTK_RESPONSE_ACCEPT,
|
||||
NULL));
|
||||
res = gtk_dialog_run(dialog);
|
||||
if (res == GTK_RESPONSE_ACCEPT) {
|
||||
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
if (data->error_memory_data)
|
||||
free((void *)data->error_memory_data);
|
||||
data->error_memory_data = load_file_to_memory(filename, &data->file_size);
|
||||
if (!data->error_memory_data) {
|
||||
g_warning("File could not be loaded");
|
||||
g_free(filename);
|
||||
goto ret_destroy_dialog;
|
||||
}
|
||||
|
||||
gtk_header_bar_set_subtitle(data->borrowed_header_bar, filename);
|
||||
g_free(filename);
|
||||
} else {
|
||||
goto ret_destroy_dialog;
|
||||
}
|
||||
|
||||
if (data->file_size % 4 || data->file_size == 0) {
|
||||
free((void *)data->error_memory_data);
|
||||
data->error_memory_data = NULL;
|
||||
info_bar_show_message(data->borrowed_info_bar, GTK_MESSAGE_WARNING,
|
||||
"Data must be base64 encoded and must contain full 32 bit words of data.");
|
||||
goto ret_destroy_dialog;
|
||||
}
|
||||
|
||||
show_error_memory(data->borrowed_tree_view, (const unsigned char *)data->error_memory_data, data->file_size);
|
||||
|
||||
ret_destroy_dialog:
|
||||
gtk_widget_destroy(GTK_WIDGET(dialog));
|
||||
}
|
||||
|
||||
static void app_activated(GApplication *app, gpointer user_data)
|
||||
{
|
||||
struct application_data *data = (struct application_data *)user_data;
|
||||
GtkBuilder *builder;
|
||||
GtkWindow *main_window;
|
||||
|
||||
builder = gtk_builder_new_from_resource("/gui/main");
|
||||
main_window = GTK_WINDOW(gtk_builder_get_object(builder, "main-window"));
|
||||
data->borrowed_main_window = GTK_WIDGET(main_window);
|
||||
data->error_memory_data = NULL;
|
||||
data->borrowed_tree_view = GTK_TREE_VIEW(gtk_builder_get_object(builder, "error-mem-tree-view"));
|
||||
data->borrowed_header_bar = GTK_HEADER_BAR(gtk_builder_get_object(builder, "header-bar"));
|
||||
data->borrowed_info_bar = GTK_INFO_BAR(gtk_builder_get_object(builder, "info-bar"));
|
||||
|
||||
setup_tree_view(data->borrowed_tree_view);
|
||||
|
||||
gtk_builder_connect_signals(builder, data);
|
||||
g_object_unref(builder);
|
||||
gtk_application_add_window(GTK_APPLICATION(app), main_window);
|
||||
gtk_widget_show(GTK_WIDGET(main_window));
|
||||
}
|
||||
|
||||
static int start_gui(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
GtkApplication *g_app;
|
||||
static struct application_data data;
|
||||
|
||||
/* Create a new G application which will start a completely new process for each call to the program (NON_UNIQUE) instead
|
||||
* of creating an additional window in the same process
|
||||
*/
|
||||
g_app = gtk_application_new("de.shimatta.reflow.error-mem-viewer", G_APPLICATION_NON_UNIQUE);
|
||||
g_signal_connect(g_app, "activate", G_CALLBACK(app_activated), &data);
|
||||
ret = g_application_run(G_APPLICATION(g_app), argc, argv);
|
||||
g_object_unref(g_app);
|
||||
if (data.error_memory_data)
|
||||
free((void *)data.error_memory_data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return start_gui(argc, argv);
|
||||
}
|
||||
26627
measurement-data/1000OhmSampling-v1.2.csv
Normal file
26627
measurement-data/1000OhmSampling-v1.2.csv
Normal file
File diff suppressed because it is too large
Load Diff
5626
measurement-data/1000OhmSampling-v1.3.csv
Normal file
5626
measurement-data/1000OhmSampling-v1.3.csv
Normal file
File diff suppressed because it is too large
Load Diff
@@ -351,7 +351,8 @@
|
||||
" (kilo_ohm_sampling1_ht, 'Day 1 Sampling -- Stable circuit -- HT'),\n",
|
||||
" (kilo_ohm_sampling2, 'Day 2 Sampling -- Stable circuit'),\n",
|
||||
" (pd.read_csv(r'1000OhmSamplingFixedStableCircuitDay3.csv'), 'Day 3 Sampling -- Stable Circuit (improved)'),\n",
|
||||
" (pd.read_csv(r'1000OhmSamplingFixedStableCircuitDay4.csv'), 'Day 4 Sampling -- Stable Circuit (improved)')\n",
|
||||
" (pd.read_csv(r'1000OhmSamplingFixedStableCircuitDay4.csv'), 'Day 4 Sampling -- Stable Circuit (improved)'),\n",
|
||||
" (pd.read_csv(r'1000OhmSampling-v1.2.csv'), 'Day 1 Sampling v1.2')\n",
|
||||
" ]\n"
|
||||
]
|
||||
},
|
||||
@@ -389,9 +390,45 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(calc_temp(1000.6)-calc_temp(1000.4))\n",
|
||||
"print(1/4096*2500)"
|
||||
"fig, axes = plt.subplots(nrows=1, ncols=2, sharex='col', figsize=(28, 8))\n",
|
||||
"v12_df = pd.read_csv(r'hw-v12-1000Ohm.csv') \n",
|
||||
"plot_histogram(axes[0], v12_df['pt1000_res_raw_lf'], 21, 'HW v1.2 1k Ohm Sampling', '1k Resistance')\n",
|
||||
"plot_histogram(axes[1], v12_df['adc_pt1000_raw_reading_hf'], 21, 'HW v1.2 1k Ohm Sampling', '1k Resistance HF RAW')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"fig, axes = plt.subplots(nrows=1, ncols=2, sharex='col', figsize=(28, 8))\n",
|
||||
"v13_df = pd.read_csv(r'1000OhmSampling-v1.3.csv') \n",
|
||||
"plot_histogram(axes[0], v13_df['pt1000_res_raw_lf'], 21, 'HW v1.3 1k Ohm Sampling', '1k Resistance')\n",
|
||||
"plot_histogram(axes[1], v13_df['adc_pt1000_raw_reading_hf'], 21, 'HW v1.3 1k Ohm Sampling', '1k Resistance')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(calc_temp(1000.6)-calc_temp(1000.4))\n",
|
||||
"\n",
|
||||
"adc_min_res = 1/4095*2500\n",
|
||||
"print('Min res: ', adc_min_res)\n",
|
||||
"\n",
|
||||
"print(calc_temp(2000))\n",
|
||||
"print(calc_temp(2000+adc_min_res))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
@@ -410,7 +447,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.1"
|
||||
"version": "3.9.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
475
measurement-data/FilterAnalysis.ipynb
Normal file
475
measurement-data/FilterAnalysis.ipynb
Normal file
@@ -0,0 +1,475 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7c270395",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"from scipy import signal\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import pandas as pd\n",
|
||||
"from scipy.fft import fft, fftfreq"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b09956cf",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "348b4663",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Filter comparison"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "eef8fc32",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"alpha = 0.01\n",
|
||||
"mavg_b = [alpha]\n",
|
||||
"mavg_a = [1, -(1-alpha)]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "06cc8d91",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Sinc filter\n",
|
||||
"b_sinc = [\n",
|
||||
" 0.013166773445594984,\n",
|
||||
" 0.015510026576574206,\n",
|
||||
" 0.017943762856303655,\n",
|
||||
" 0.020436419999452039,\n",
|
||||
" 0.022953654956480787,\n",
|
||||
" 0.025459023223972144,\n",
|
||||
" 0.027914730737546672,\n",
|
||||
" 0.030282439536854874,\n",
|
||||
" 0.032524106530629059,\n",
|
||||
" 0.034602833419516990,\n",
|
||||
" 0.036483705201686277,\n",
|
||||
" 0.038134594717421900,\n",
|
||||
" 0.039526911389630152,\n",
|
||||
" 0.040636273671486346,\n",
|
||||
" 0.041443086683647982,\n",
|
||||
" 0.041933009054862178,\n",
|
||||
" 0.042097295996679322,\n",
|
||||
" 0.041933009054862178,\n",
|
||||
" 0.041443086683647982,\n",
|
||||
" 0.040636273671486346,\n",
|
||||
" 0.039526911389630152,\n",
|
||||
" 0.038134594717421900,\n",
|
||||
" 0.036483705201686277,\n",
|
||||
" 0.034602833419516990,\n",
|
||||
" 0.032524106530629059,\n",
|
||||
" 0.030282439536854874,\n",
|
||||
" 0.027914730737546672,\n",
|
||||
" 0.025459023223972144,\n",
|
||||
" 0.022953654956480787,\n",
|
||||
" 0.020436419999452039,\n",
|
||||
" 0.017943762856303655,\n",
|
||||
" 0.015510026576574206,\n",
|
||||
" 0.013166773445594984,\n",
|
||||
"]\n",
|
||||
"b_sinc = [\n",
|
||||
" -0.000005301919181359,\n",
|
||||
" -0.000020372384569462,\n",
|
||||
" -0.000043393375246200,\n",
|
||||
" -0.000071643508460196,\n",
|
||||
" -0.000101272447699964,\n",
|
||||
" -0.000127045709202358,\n",
|
||||
" -0.000142084479366378,\n",
|
||||
" -0.000137630058679112,\n",
|
||||
" -0.000102865422361326,\n",
|
||||
" -0.000024826753571648,\n",
|
||||
" 0.000111564545505229,\n",
|
||||
" 0.000323323938002668,\n",
|
||||
" 0.000629062120588115,\n",
|
||||
" 0.001048471626315150,\n",
|
||||
" 0.001601644955843253,\n",
|
||||
" 0.002308239744151386,\n",
|
||||
" 0.003186518744650963,\n",
|
||||
" 0.004252303894058680,\n",
|
||||
" 0.005517893567100900,\n",
|
||||
" 0.006990999568786174,\n",
|
||||
" 0.008673764799041549,\n",
|
||||
" 0.010561923390649710,\n",
|
||||
" 0.012644162210467481,\n",
|
||||
" 0.014901735907231652,\n",
|
||||
" 0.017308377414832196,\n",
|
||||
" 0.019830532444994709,\n",
|
||||
" 0.022427930710902887,\n",
|
||||
" 0.025054489273884574,\n",
|
||||
" 0.027659525485854094,\n",
|
||||
" 0.030189239563895277,\n",
|
||||
" 0.032588410933658420,\n",
|
||||
" 0.034802239101869442,\n",
|
||||
" 0.036778249821351520,\n",
|
||||
" 0.038468181363671021,\n",
|
||||
" 0.039829764251821352,\n",
|
||||
" 0.040828311002284692,\n",
|
||||
" 0.041438040179150003,\n",
|
||||
" 0.041643070995549647,\n",
|
||||
" 0.041438040179150003,\n",
|
||||
" 0.040828311002284692,\n",
|
||||
" 0.039829764251821366,\n",
|
||||
" 0.038468181363671021,\n",
|
||||
" 0.036778249821351520,\n",
|
||||
" 0.034802239101869456,\n",
|
||||
" 0.032588410933658420,\n",
|
||||
" 0.030189239563895291,\n",
|
||||
" 0.027659525485854094,\n",
|
||||
" 0.025054489273884584,\n",
|
||||
" 0.022427930710902898,\n",
|
||||
" 0.019830532444994709,\n",
|
||||
" 0.017308377414832207,\n",
|
||||
" 0.014901735907231647,\n",
|
||||
" 0.012644162210467488,\n",
|
||||
" 0.010561923390649715,\n",
|
||||
" 0.008673764799041547,\n",
|
||||
" 0.006990999568786178,\n",
|
||||
" 0.005517893567100902,\n",
|
||||
" 0.004252303894058680,\n",
|
||||
" 0.003186518744650965,\n",
|
||||
" 0.002308239744151388,\n",
|
||||
" 0.001601644955843254,\n",
|
||||
" 0.001048471626315152,\n",
|
||||
" 0.000629062120588114,\n",
|
||||
" 0.000323323938002668,\n",
|
||||
" 0.000111564545505229,\n",
|
||||
" -0.000024826753571648,\n",
|
||||
" -0.000102865422361327,\n",
|
||||
" -0.000137630058679112,\n",
|
||||
" -0.000142084479366378,\n",
|
||||
" -0.000127045709202359,\n",
|
||||
" -0.000101272447699963,\n",
|
||||
" -0.000071643508460196,\n",
|
||||
" -0.000043393375246200,\n",
|
||||
" -0.000020372384569461,\n",
|
||||
" -0.000005301919181359,\n",
|
||||
"]\n",
|
||||
"b_sinc = np.around([k * 56536 for k in b_sinc])/65536\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def combined_sinc_mavg(alpha = 0.4):\n",
|
||||
" b1 = [alpha]\n",
|
||||
" b2 = b_sinc\n",
|
||||
" a1 = [1, -(1-alpha)]\n",
|
||||
" a2 = [1]\n",
|
||||
" \n",
|
||||
" b = np.convolve(b1, b2)\n",
|
||||
" a = np.convolve(a1, a2)\n",
|
||||
" return b,a\n",
|
||||
"\n",
|
||||
"def iir_notch(freq, r, fsa):\n",
|
||||
" b = [1, -2*np.cos(freq/fsa*2*np.pi), 1]\n",
|
||||
" a = [1, -2*r*np.cos(freq/fsa*2*np.pi), r*r]\n",
|
||||
" return b,a"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "299fc59e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0af3fa7b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def plot_transfer_func(b, a, fsa = 1):\n",
|
||||
" omega, vals = signal.freqz(b, a, worN = 1024)\n",
|
||||
" plt.plot(omega/(2*np.pi)*fsa, abs(vals))\n",
|
||||
" \n",
|
||||
"sample_rate = 1e3/6\n",
|
||||
"plt.figure(figsize=(16,8))\n",
|
||||
"plt.yscale('log')\n",
|
||||
"plot_transfer_func(mavg_b, mavg_a, sample_rate)\n",
|
||||
"plt.ylabel('|H(w)| [dB]')\n",
|
||||
"plt.xlabel('Frequency [Hz]')\n",
|
||||
"\n",
|
||||
"plot_transfer_func(b_sinc, [1], sample_rate)\n",
|
||||
"\n",
|
||||
"# Combined filter\n",
|
||||
"b,a = combined_sinc_mavg(alpha = 1)\n",
|
||||
"b_notch, a_notch = iir_notch(50, 0.875, sample_rate)\n",
|
||||
"b = np.convolve(b, b_notch)\n",
|
||||
"a = np.convolve(a, a_notch)\n",
|
||||
"plot_transfer_func(b,a, sample_rate)\n",
|
||||
"plt.grid()\n",
|
||||
"\n",
|
||||
"plt.legend(['MAVG a = 0.01', 'SINC', 'SINC+MAVG'])\n",
|
||||
"plt.xlim(0, 70)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c9b87b82",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Notch filters (Not used for implementation)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c360b127",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"plt.figure(figsize=(16,8))\n",
|
||||
"plt.yscale('log')\n",
|
||||
"a = [1]\n",
|
||||
"b = [1, -2*np.cos(50/sample_rate*2*np.pi), 1]\n",
|
||||
"plot_transfer_func(b,a, sample_rate)\n",
|
||||
"\n",
|
||||
"b = [1, -2*np.cos(60/sample_rate*2*np.pi), 1]\n",
|
||||
"plot_transfer_func(b,a, sample_rate)\n",
|
||||
"\n",
|
||||
"r = 0.875\n",
|
||||
"b,a = iir_notch(50, r, sample_rate)\n",
|
||||
"plot_transfer_func(b,a, sample_rate)\n",
|
||||
"\n",
|
||||
"b,a = iir_notch(60, r, sample_rate)\n",
|
||||
"plot_transfer_func(b,a, sample_rate)\n",
|
||||
"plt.xlim(40,70)\n",
|
||||
"plt.legend(['FIR 50 Hz Notch', 'FIR 60 Hz', 'IIR 50Hz', 'IIR 60Hz'])\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "891bf909",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Singal testing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "29277520",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"N = 30000\n",
|
||||
"time = np.linspace(0, 1/sample_rate*N, N, endpoint=False)\n",
|
||||
"sig = 10*signal.sawtooth(2*np.pi*0.2*time)+10 #+ 0.5 * np.sin(2*np.pi*50*time)+0.8 * np.sin(2*np.pi*80*time)\n",
|
||||
"\n",
|
||||
"plt.figure(figsize=(16,8))\n",
|
||||
"\n",
|
||||
"spur_len = 3\n",
|
||||
"\n",
|
||||
"sig[1000:1000+spur_len] = sig[1000]+5\n",
|
||||
"sig[2000:2000+spur_len] = sig[2000]-6\n",
|
||||
"sig[3000:3000+spur_len] = sig[3000]+2\n",
|
||||
"sig[4000:4000+spur_len] = sig[4000]+8\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"plt.plot(time, sig)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Apply the combined filter:\n",
|
||||
"b,a = combined_sinc_mavg(alpha = 1)\n",
|
||||
"\n",
|
||||
"bn,an = iir_notch(50, 0.875, sample_rate)\n",
|
||||
"a = np.convolve(a, an)\n",
|
||||
"b = np.convolve(b, bn)\n",
|
||||
"\n",
|
||||
"#b,a = mavg_b, mavg_a\n",
|
||||
"\n",
|
||||
"w,h = signal.freqz(b,a)\n",
|
||||
"gain_corr = round(1/abs(h[0])*65536)/65536\n",
|
||||
"\n",
|
||||
"sig_f = signal.lfilter(b, a, sig) * gain_corr\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print('Gain correction:', gain_corr)\n",
|
||||
"\n",
|
||||
"plt.plot(time, sig_f)\n",
|
||||
"plt.xlim(5,10)\n",
|
||||
"plt.show()\n",
|
||||
"\n",
|
||||
"plt.figure(figsize=(16,8))\n",
|
||||
"plt.plot(time, abs(sig-sig_f))\n",
|
||||
"plt.xlim(5,10)\n",
|
||||
"plt.ylim(0,2)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "13758640",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\n",
|
||||
"window = signal.windows.hamming(N)\n",
|
||||
"\n",
|
||||
"h_sig = fft(sig*window)\n",
|
||||
"f_sig = fftfreq(N, 1/sample_rate)[:N//2]\n",
|
||||
"\n",
|
||||
"h_sig_f = fft(sig_f*window)\n",
|
||||
"f_sig_f = fftfreq(N, 1/sample_rate)[:N//2]\n",
|
||||
"\n",
|
||||
"plt.figure(figsize=(16,10))\n",
|
||||
"plt.yscale('log')\n",
|
||||
"plt.plot(f_sig, 2.0/N*abs(h_sig[0:N//2]))\n",
|
||||
"plt.plot(f_sig_f, 2.0/N*abs(h_sig_f[0:N//2]))\n",
|
||||
"plt.show();"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f4b81600",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# PT1000 HF Filtering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a87370ee",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"raw_data = pd.read_csv(r'pt1000_hf_2kOhm_v1.3.dat')\n",
|
||||
"raw_data = pd.read_csv(r'pt1000_hf_changing.dat')\n",
|
||||
"time = np.linspace(0, 2000*6e-3, 2000, endpoint=False)\n",
|
||||
"\n",
|
||||
"plt.figure(figsize=(22,12))\n",
|
||||
"plt.plot(time, raw_data['hf_value']*2500/4096)\n",
|
||||
"\n",
|
||||
"alpha = 0.005\n",
|
||||
"\n",
|
||||
"mavg_b = [alpha]\n",
|
||||
"mavg_a = [1, -(1-alpha)]\n",
|
||||
"\n",
|
||||
"zi = signal.lfilter_zi(mavg_b, mavg_a)\n",
|
||||
"filtered, _ = signal.lfilter(mavg_b, mavg_a, raw_data['hf_value'], zi=zi*raw_data['hf_value'][0])\n",
|
||||
"plt.plot(time, filtered*2500/4096)\n",
|
||||
"filtered_avg_low = filtered\n",
|
||||
"\n",
|
||||
"alpha = 0.01\n",
|
||||
"mavg_b = [alpha]\n",
|
||||
"mavg_a = [1, -(1-alpha)]\n",
|
||||
"\n",
|
||||
"zi = signal.lfilter_zi(mavg_b, mavg_a)\n",
|
||||
"filtered, _ = signal.lfilter(mavg_b, mavg_a, raw_data['hf_value'], zi=zi*raw_data['hf_value'][0])\n",
|
||||
"plt.plot(time, filtered*2500/4096)\n",
|
||||
"filtered_avg = filtered\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Apply the combined filter:\n",
|
||||
"b,a = combined_sinc_mavg(alpha = 0.08)\n",
|
||||
"\n",
|
||||
"bn,an = iir_notch(4, 0.75, sample_rate)\n",
|
||||
"a = np.convolve(a, an)\n",
|
||||
"b = np.convolve(b, bn)\n",
|
||||
"\n",
|
||||
"zi = signal.lfilter_zi(b, a)\n",
|
||||
"filtered, _ = signal.lfilter(b, a, raw_data['hf_value'], zi=zi*raw_data['hf_value'][0])\n",
|
||||
"\n",
|
||||
"w,h = signal.freqz(b,a)\n",
|
||||
"gain_corr = round(1/abs(h[0])*65536)/65536\n",
|
||||
"\n",
|
||||
"plt.plot(time, filtered*gain_corr*2500/4096)\n",
|
||||
"plt.savefig('expl.pdf', format='pdf', dpi=1200)\n",
|
||||
"plt.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3eae0e71",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Spectrum"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8d082b99",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"window =signal.windows.hamming(len(raw_data['hf_value']))\n",
|
||||
"raw_fft = fft(np.array(raw_data['hf_value'].to_list())*window)\n",
|
||||
"f_raw = fftfreq(len(raw_data), 1/sample_rate)[:len(raw_data)//2]\n",
|
||||
"plt.figure(figsize=(16,10));\n",
|
||||
"plt.yscale('log')\n",
|
||||
"plt.plot(f_raw, abs(raw_fft[:len(raw_data)//2]))\n",
|
||||
"\n",
|
||||
"avg_fft = fft(np.array(filtered_avg)*window)\n",
|
||||
"plt.plot(f_raw, abs(avg_fft[:len(raw_data)//2]))\n",
|
||||
"\n",
|
||||
"avg_fft = fft(np.array(filtered_avg_low)*window)\n",
|
||||
"plt.plot(f_raw, abs(avg_fft[:len(raw_data)//2]))\n",
|
||||
"\n",
|
||||
"sinc_fft = fft(np.array(filtered)*window)\n",
|
||||
"plt.plot(f_raw, abs(sinc_fft[:len(raw_data)//2]))\n",
|
||||
"plt.xscale('log')\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e09d63f9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(np.std(filtered_avg_low/4096*2500))\n",
|
||||
"print(np.std(filtered_avg/4096*2500))\n",
|
||||
"print(np.std(filtered/4096*2500))\n",
|
||||
"\n",
|
||||
"print('Min',min(filtered_avg/4096*2500), 'Max', max(filtered_avg)/4096*2500)\n",
|
||||
"print('Min',min(filtered)/4096*2500*gain_corr, 'Max', max(filtered)/4096*2500*gain_corr)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
5396
measurement-data/hw-v12-1000Ohm.csv
Normal file
5396
measurement-data/hw-v12-1000Ohm.csv
Normal file
File diff suppressed because it is too large
Load Diff
2001
measurement-data/pt1000_hf_2kOhm_v1.3.dat
Normal file
2001
measurement-data/pt1000_hf_2kOhm_v1.3.dat
Normal file
File diff suppressed because it is too large
Load Diff
2001
measurement-data/pt1000_hf_changing.dat
Normal file
2001
measurement-data/pt1000_hf_changing.dat
Normal file
File diff suppressed because it is too large
Load Diff
8
stm-firmware/.gitignore
vendored
8
stm-firmware/.gitignore
vendored
@@ -8,3 +8,11 @@ reflow-controller.cxxflags
|
||||
reflow-controller.files
|
||||
reflow-controller.includes
|
||||
*.creator.user
|
||||
*.cflags
|
||||
*.creator
|
||||
*.cxxflags
|
||||
*.includes
|
||||
*.config
|
||||
*.files
|
||||
*.user.*
|
||||
*.user
|
||||
|
||||
150
stm-firmware/CMakeLists.txt
Normal file
150
stm-firmware/CMakeLists.txt
Normal file
@@ -0,0 +1,150 @@
|
||||
set(CMAKE_SYSTEM_NAME Generic)
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
set(CMAKE_CROSSCOMPILING 1)
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
set(CMAKE_TOOLCHAIN_FILE "arm-none-eabi-gcc.cmake")
|
||||
|
||||
project(reflow-controller)
|
||||
|
||||
if(NOT WIN32)
|
||||
string(ASCII 27 Esc)
|
||||
set(ColorReset "${Esc}[m")
|
||||
set(ColorBold "${Esc}[1m")
|
||||
set(Red "${Esc}[31m")
|
||||
set(Green "${Esc}[32m")
|
||||
set(Yellow "${Esc}[33m")
|
||||
set(Blue "${Esc}[34m")
|
||||
set(Magenta "${Esc}[35m")
|
||||
set(Cyan "${Esc}[36m")
|
||||
set(White "${Esc}[37m")
|
||||
set(BoldRed "${Esc}[1;31m")
|
||||
set(BoldGreen "${Esc}[1;32m")
|
||||
set(BoldYellow "${Esc}[1;33m")
|
||||
set(BoldBlue "${Esc}[1;34m")
|
||||
set(BoldMagenta "${Esc}[1;35m")
|
||||
set(BoldCyan "${Esc}[1;36m")
|
||||
set(BoldWhite "${Esc}[1;37m")
|
||||
endif()
|
||||
|
||||
find_package(Git)
|
||||
if (GIT_FOUND)
|
||||
message("Git found")
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} describe --always --tags --dirty
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_DESCRIBE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
message("${BoldGreen}Git based version number: ${GIT_DESCRIBE}${ColorReset}")
|
||||
else (GIT_FOUND)
|
||||
set(GIT_DESCRIBE "v0.0.0-unknown")
|
||||
message("${BoldRed}No git installation found. It is highly recommended using git to generate the version number")
|
||||
message("Version is set to: ${GIT_DESCRIBE}${ColorReset}")
|
||||
endif (GIT_FOUND)
|
||||
|
||||
find_program(VIRTUALENV virtualenv)
|
||||
if (VIRTUALENV)
|
||||
message("Python virtual environment found")
|
||||
execute_process(
|
||||
COMMAND ${VIRTUALENV} venv
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
OUTPUT_QUIET
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
)
|
||||
set(VENV_BIN "${CMAKE_CURRENT_BINARY_DIR}/venv/bin")
|
||||
execute_process(
|
||||
COMMAND ./pip install -r "${CMAKE_CURRENT_SOURCE_DIR}/crc-patcher/requirements.txt"
|
||||
WORKING_DIRECTORY ${VENV_BIN}
|
||||
OUTPUT_QUIET
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
)
|
||||
message("${BoldGreen}python virtual environment set up!${ColorReset}")
|
||||
else(VIRTUALENV)
|
||||
message(FATAL_ERROR "${BoldRed}Python virtual environment not set up: virtualenv: command not found!${ColorReset}")
|
||||
endif (VIRTUALENV)
|
||||
|
||||
|
||||
set(ELFFILE ${PROJECT_NAME}.elf)
|
||||
set(HEXFILE ${PROJECT_NAME}.hex)
|
||||
set(MAPFILE ${PROJECT_NAME}.map)
|
||||
set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/stm32f407vet6_flash.ld)
|
||||
|
||||
add_compile_options(-Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter)
|
||||
add_compile_options(-mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -Wimplicit-fallthrough=3 -Wsign-compare)
|
||||
|
||||
|
||||
set(GIT_DESCRIBE "${GIT_DESCRIBE}")
|
||||
add_definitions(-DBASE64_LOOKUP_TABLE_SECTION=\".ccm.bss\" -DSHELLMATTA_HELP_ALIAS=\"?\" -DGIT_VER=${GIT_DESCRIBE} -DHSE_VALUE=8000000UL -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4)
|
||||
|
||||
add_subdirectory(doxygen)
|
||||
add_subdirectory(updater/ram-code)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
|
||||
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_definitions(-DDEBUGBUILD)
|
||||
add_compile_options(-O0 -g)
|
||||
add_link_options(-Wl,-Map=${MAPFILE})
|
||||
ELSE()
|
||||
add_compile_options(-O3 -g)
|
||||
add_link_options(-Wl,--gc-sections)
|
||||
ENDIF(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
|
||||
|
||||
if (UART_ON_DEBUG_HEADER)
|
||||
add_definitions(-DUART_ON_DEBUG_HEADER)
|
||||
message("${BoldRed}UART forced to debug header${ColorReset}")
|
||||
endif (UART_ON_DEBUG_HEADER)
|
||||
|
||||
add_subdirectory(base64-lib)
|
||||
add_subdirectory(linklist-lib)
|
||||
|
||||
aux_source_directory("." MAIN_SOURCES)
|
||||
aux_source_directory("config-parser" CFG_PARSER_SRCS)
|
||||
aux_source_directory("ui" UI_SRCS)
|
||||
aux_source_directory("fatfs" FAT_SRCS)
|
||||
aux_source_directory("fatfs/shimatta_sdio_driver" SDIO_SRCS)
|
||||
aux_source_directory("boot" BOOT_SRCS)
|
||||
aux_source_directory("setup" SETUP_SRCS)
|
||||
aux_source_directory("stm-periph" STM_PERIPH_SRCS)
|
||||
aux_source_directory("settings" SETTINGS_SRCS)
|
||||
aux_source_directory("safety" SAFETY_SRCS)
|
||||
aux_source_directory("shellmatta/src" SHELLMATTA_SRCS)
|
||||
aux_source_directory("updater" UPDATER_SRCS)
|
||||
aux_source_directory("temp-profile" PROFILE_SRCS)
|
||||
|
||||
add_executable(${ELFFILE} ${MAIN_SOURCES} ${CFG_PARSER_SRCS} ${UI_SRCS}
|
||||
${FAT_SRCS} ${SDIO_SRCS} ${BOOT_SRCS} ${SETUP_SRCS}
|
||||
${STM_PERIPH_SRCS} ${SETTINGS_SRCS} ${SAFETY_SRCS}
|
||||
${SHELLMATTA_SRCS} ${UPDATER_SRCS} ${PROFILE_SRCS}
|
||||
)
|
||||
|
||||
add_dependencies(${ELFFILE} updater-ram-code-header-blob)
|
||||
|
||||
target_include_directories(${ELFFILE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/shellmatta/api ${CMAKE_CURRENT_SOURCE_DIR}/config-parser/include)
|
||||
target_link_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles -T${LINKER_SCRIPT} -Wl,--print-memory-usage)
|
||||
target_link_libraries(${ELFFILE} base64-lib linklist-lib)
|
||||
target_include_directories(${ELFFILE} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/updater/ram-code/include/")
|
||||
|
||||
add_custom_command(
|
||||
TARGET ${ELFFILE}
|
||||
POST_BUILD
|
||||
COMMAND ./python "${CMAKE_CURRENT_SOURCE_DIR}/crc-patcher/crc-patch-elf.py" "${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}"
|
||||
WORKING_DIRECTORY ${VENV_BIN}
|
||||
COMMENT "Running Flash CRC Patcher"
|
||||
)
|
||||
|
||||
set(HEX_PATH "${CMAKE_CURRENT_BINARY_DIR}/${HEXFILE}")
|
||||
add_custom_target(update-image ALL DEPENDS ${HEX_PATH} "${HEX_PATH}.sha")
|
||||
add_custom_command(
|
||||
DEPENDS ${ELFFILE}
|
||||
OUTPUT ${HEX_PATH}
|
||||
COMMAND ${CMAKE_OBJCOPY} -O ihex ${ELFFILE} ${HEX_PATH}
|
||||
)
|
||||
add_custom_command(
|
||||
DEPENDS ${HEX_PATH}
|
||||
OUTPUT "${HEX_PATH}.sha"
|
||||
COMMAND sha256sum "${HEX_PATH}" | cut -d " " -f 1 > "${HEX_PATH}.sha"
|
||||
)
|
||||
@@ -1,112 +0,0 @@
|
||||
################################Shimatta Makefile####################################
|
||||
#CPU: STM32F407VET6
|
||||
#Compiler: arm-none-eabi
|
||||
#####################################################################################
|
||||
#Add Files and Folders below#########################################################
|
||||
CFILES = main.c syscalls.c setup/system_stm32f4xx.c systick.c
|
||||
ASFILES = boot/startup_stm32f4xx.S
|
||||
INCLUDEPATH = -Icmsis -Iinclude
|
||||
|
||||
OBJDIR = obj
|
||||
target = reflow-controller
|
||||
LIBRARYPATH = -L. -Lmathlib
|
||||
LIBRARIES = -larm_cortexM4lf_math
|
||||
|
||||
DEFINES = -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4 -DHSE_VALUE=8000000UL
|
||||
mapfile = memory-mapping
|
||||
|
||||
GIT_VER := $(shell git describe --always --dirty --tags)
|
||||
DEFINES += -DGIT_VER=$(GIT_VER)
|
||||
|
||||
ifneq ($(VERBOSE),true)
|
||||
QUIET=@
|
||||
else
|
||||
QUIET=
|
||||
endif
|
||||
|
||||
##Custom Files###
|
||||
CFILES += adc-meas.c
|
||||
|
||||
# Shellmatta
|
||||
CFILES += shellmatta/src/shellmatta.c shellmatta/src/shellmatta_autocomplete.c shellmatta/src/shellmatta_escape.c shellmatta/src/shellmatta_history.c shellmatta/src/shellmatta_utils.c shell.c
|
||||
INCLUDEPATH += -Ishellmatta/api
|
||||
# DEFINES += -DSHELLMATTA_STRIP_PRINTF
|
||||
|
||||
# RCC Manager
|
||||
CFILES += stm-periph/clock-enable-manager.c
|
||||
|
||||
CFILES += stm-periph/uart.c stm-periph/dma-ring-buffer.c
|
||||
|
||||
CFILES += digio.c
|
||||
|
||||
DEFINES += -DDEBUGBUILD
|
||||
#TODO
|
||||
|
||||
###################################################################################
|
||||
CC=arm-none-eabi-gcc
|
||||
OBJCOPY=arm-none-eabi-objcopy
|
||||
OBJDUMP=arm-none-eabi-objdump
|
||||
SIZE=arm-none-eabi-size
|
||||
|
||||
LFLAGS = -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
|
||||
LFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles
|
||||
LFLAGS += -Tstm32f407vet6_flash.ld -Wl,-Map=$(mapfile).map
|
||||
|
||||
CFLAGS = -c -fmessage-length=0 -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
|
||||
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -O0 -g
|
||||
CFLAGS += -Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter
|
||||
####################################################################################
|
||||
|
||||
OBJ = $(CFILES:%.c=$(OBJDIR)/%.c.o)
|
||||
ASOBJ += $(ASFILES:%.S=$(OBJDIR)/%.S.o)
|
||||
|
||||
default: $(target).elf
|
||||
|
||||
%.bin: %.elf
|
||||
$(QUIET)$(OBJCOPY) -O binary $^ $@
|
||||
%.hex: %.elf
|
||||
$(QUIET)$(OBJCOPY) -O ihex $^ $@
|
||||
|
||||
|
||||
#Linking
|
||||
$(target).elf: $(OBJ) $(ASOBJ)
|
||||
@echo [LD] $@
|
||||
$(QUIET)$(CC) $(LFLAGS) $(LIBRARYPATH) -o $@ $^ $(LIBRARIES)
|
||||
$(QUIET)$(SIZE) $@
|
||||
|
||||
#Compiling
|
||||
$(OBJ):
|
||||
@echo [CC] $@
|
||||
$(eval OUTPATH=$(dir $@))
|
||||
@mkdir -p $(OUTPATH)
|
||||
$(QUIET)$(CC) $(CFLAGS) -MMD -MT $@ $(INCLUDEPATH) $(DEFINES) -o $@ $(@:$(OBJDIR)/%.c.o=%.c)
|
||||
$(ASOBJ):
|
||||
@echo [AS] $@
|
||||
$(eval OUTPATH=$(dir $@))
|
||||
@mkdir -p $(OUTPATH)
|
||||
$(QUIET)$(CC) $(CFLAGS) -MMD -MT $@ $(INCLUDEPATH) $(DEFINES) -o $@ $(@:$(OBJDIR)/%.S.o=%.S)
|
||||
|
||||
|
||||
.PHONY: qtproject clean mrproper objcopy disassemble
|
||||
|
||||
disassemble: $(target).elf
|
||||
$(QUIET)$(OBJDUMP) -D -s $< > $(target).lss
|
||||
|
||||
objcopy: $(target).bin $(target).hex
|
||||
|
||||
mrproper: clean
|
||||
rm -f $(target).pro
|
||||
|
||||
clean:
|
||||
rm -f $(target).elf $(target).bin $(target).hex $(OBJ) $(ASOBJ) $(mapfile).map $(CFILES:%.c=$(OBJDIR)/%.c.d) $(ASFILES:%.S=$(OBJDIR)/%.S.d)
|
||||
qtproject:
|
||||
echo -e "TEMPLATE = app\nCONFIG -= console app_bundle qt" > $(target).pro
|
||||
echo -e "SOURCES += $(CFILES) $(ASFILES)" >> $(target).pro
|
||||
echo -ne "INCLUDEPATH += " >> $(target).pro
|
||||
echo "$(INCLUDEPATH)" | sed "s!-I!./!g" >> $(target).pro
|
||||
echo -ne "HEADERS += " >> $(target).pro
|
||||
find -name "*.h" | tr "\\n" " " >> $(target).pro
|
||||
echo -ne "\nDEFINES += " >> $(target).pro
|
||||
echo "$(DEFINES)" | sed "s/-D//g" >> $(target).pro
|
||||
|
||||
-include $(CFILES:%.c=$(OBJDIR)/%.c.d) $(ASFILES:%.S=$(OBJDIR)/%.S.d)
|
||||
@@ -1,37 +1,70 @@
|
||||
/* Reflow Oven Controller
|
||||
*
|
||||
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
||||
*
|
||||
* This file is part of the Reflow Oven Controller Project.
|
||||
*
|
||||
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* The Reflow Oven Control Firmware 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 the reflow oven controller project.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file adc-meas.c
|
||||
* @brief Implementation of the PT1000 measurement ADC and filtering functions
|
||||
*/
|
||||
|
||||
#include <reflow-controller/adc-meas.h>
|
||||
#include <stm32/stm32f4xx.h>
|
||||
#include <cmsis/core_cm4.h>
|
||||
#include <stm-periph/stm32-gpio-macros.h>
|
||||
#include <stdlib.h>
|
||||
#include <stm-periph/clock-enable-manager.h>
|
||||
#include <helper-macros/helper-macros.h>
|
||||
#include <stm-periph/rcc-manager.h>
|
||||
#include <reflow-controller/safety/safety-controller.h>
|
||||
|
||||
static float pt1000_offset;
|
||||
static float pt1000_sens_dev;
|
||||
static bool calibration_active;
|
||||
static float filter_alpha;
|
||||
static volatile float pt1000_res_raw_lf;
|
||||
static volatile bool filter_ready;
|
||||
static volatile enum adc_pt1000_error pt1000_error;
|
||||
static volatile uint8_t * volatile streaming_flag_ptr = NULL;
|
||||
static uint32_t filter_startup_cnt;
|
||||
static volatile float adc_pt1000_raw_reading_hf;
|
||||
static volatile bool pt1000_measurement_active = false;
|
||||
static float IN_SECTION(.ccm.bss) pt1000_offset;
|
||||
static float IN_SECTION(.ccm.bss) pt1000_sens_dev;
|
||||
static bool IN_SECTION(.ccm.bss) calibration_active;
|
||||
static float IN_SECTION(.ccm.bss) filter_alpha;
|
||||
|
||||
/**
|
||||
* @brief Filtered PT1000 resistance value.
|
||||
* @note This value is not yet calibrated.
|
||||
* Use @ref adc_pt1000_get_current_resistance to get this value with calibration.
|
||||
*/
|
||||
static volatile float IN_SECTION(.ccm.bss) pt1000_res_raw_lf;
|
||||
|
||||
static volatile int * volatile streaming_flag_ptr;
|
||||
static volatile float IN_SECTION(.ccm.bss) adc_pt1000_raw_reading_hf;
|
||||
static volatile uint16_t dma_sample_buffer[ADC_PT1000_DMA_AVG_SAMPLES];
|
||||
static volatile uint32_t IN_SECTION(.ccm.bss) adc_watchdog_counter;
|
||||
|
||||
#define ADC_TO_RES(adc) ((float)(adc) / 4096.0f * 2500.0f)
|
||||
volatile float * volatile stream_buffer;
|
||||
volatile uint32_t stream_count;
|
||||
volatile uint32_t stream_pos;
|
||||
|
||||
static inline void adc_pt1000_stop_sample_frequency_timer()
|
||||
static inline void adc_pt1000_stop_sample_frequency_timer(void)
|
||||
{
|
||||
TIM2->CR1 &= ~TIM_CR1_CEN;
|
||||
rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB1ENR_TIM2EN));
|
||||
}
|
||||
|
||||
static inline void adc_pt1000_setup_sample_frequency_timer()
|
||||
static inline void adc_pt1000_setup_sample_frequency_timer(void)
|
||||
{
|
||||
rcc_manager_enable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB1ENR_TIM2EN));
|
||||
|
||||
/* Divide 42 MHz peripheral clock by 42 */
|
||||
TIM2->PSC = (42UL-1UL);
|
||||
/* Divide 2*42 MHz peripheral clock by 42 */
|
||||
TIM2->PSC = (84UL-1UL);
|
||||
|
||||
/* Reload value */
|
||||
TIM2->ARR = ADC_PT1000_SAMPLE_CNT_DELAY;
|
||||
@@ -44,14 +77,16 @@ static inline void adc_pt1000_setup_sample_frequency_timer()
|
||||
|
||||
}
|
||||
|
||||
static inline void adc_pt1000_disable_adc()
|
||||
static inline void adc_pt1000_disable_adc(void)
|
||||
{
|
||||
ADC1->CR2 &= ~ADC_CR2_ADON;
|
||||
ADC_PT1000_PERIPH->CR2 &= ~ADC_CR2_ADON;
|
||||
DMA2_Stream0->CR = 0;
|
||||
|
||||
pt1000_measurement_active = false;
|
||||
safety_controller_set_crc_monitor(ERR_CRC_MON_MEAS_ADC, SAFETY_CRC_MON_MEAS_ADC_PW);
|
||||
|
||||
rcc_manager_disable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC1EN));
|
||||
safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_OFF, MEAS_ADC_SAFETY_FLAG_KEY);
|
||||
safety_controller_enable_timing_mon(ERR_TIMING_MEAS_ADC, false);
|
||||
rcc_manager_disable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC3EN));
|
||||
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(ADC_PT1000_PORT_RCC_MASK));
|
||||
}
|
||||
|
||||
@@ -66,7 +101,7 @@ static inline void adc_pt1000_disable_adc()
|
||||
* After that, the moving average filter is fed with the values.
|
||||
*
|
||||
*/
|
||||
static inline void adc_pt1000_enable_dma_stream()
|
||||
static inline void adc_pt1000_enable_dma_stream(void)
|
||||
{
|
||||
/* Enable peripheral clock for DMA2 */
|
||||
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
|
||||
@@ -75,7 +110,7 @@ static inline void adc_pt1000_enable_dma_stream()
|
||||
DMA2_Stream0->M0AR = (uint32_t)dma_sample_buffer;
|
||||
|
||||
/* Source is the ADC data register */
|
||||
DMA2_Stream0->PAR = (uint32_t)&ADC1->DR;
|
||||
DMA2_Stream0->PAR = (uint32_t)&ADC_PT1000_PERIPH->DR;
|
||||
|
||||
/* Transfer size is ADC_PT1000_DMA_AVG_SAMPLES */
|
||||
DMA2_Stream0->NDTR = ADC_PT1000_DMA_AVG_SAMPLES;
|
||||
@@ -88,10 +123,10 @@ static inline void adc_pt1000_enable_dma_stream()
|
||||
* Todo: Maybe use twice as big of a buffer and also use half-fill interrupt in order to prevent overruns
|
||||
*/
|
||||
DMA2_Stream0->CR = DMA_SxCR_PL_1 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC |
|
||||
DMA_SxCR_CIRC | DMA_SxCR_TCIE | DMA_SxCR_EN;
|
||||
DMA_SxCR_CIRC | DMA_SxCR_TCIE | DMA_SxCR_TEIE | DMA_SxCR_EN | ((ADC_PT1000_CHANNEL & 0x7)<<25);
|
||||
}
|
||||
|
||||
static inline void adc_pt1000_disable_dma_stream()
|
||||
static inline void adc_pt1000_disable_dma_stream(void)
|
||||
{
|
||||
/* Disable the stream */
|
||||
DMA2_Stream0->CR = 0;
|
||||
@@ -103,34 +138,35 @@ static inline void adc_pt1000_disable_dma_stream()
|
||||
NVIC_DisableIRQ(DMA2_Stream0_IRQn);
|
||||
}
|
||||
|
||||
void adc_pt1000_setup_meas()
|
||||
void adc_pt1000_setup_meas(void)
|
||||
{
|
||||
rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC1EN));
|
||||
rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC3EN));
|
||||
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(ADC_PT1000_PORT_RCC_MASK));
|
||||
|
||||
ADC_PT1000_PORT->MODER |= ANALOG(ADC_PT1000_PIN);
|
||||
|
||||
/* Set S&H time for PT1000 ADC channel */
|
||||
#if ADC_PT1000_CHANNEL < 10
|
||||
ADC1->SMPR2 |= (7U << (3*ADC_PT1000_CHANNEL));
|
||||
ADC_PT1000_PERIPH->SMPR2 |= (7U << (3*ADC_PT1000_CHANNEL));
|
||||
#else
|
||||
ADC1->SMPR1 |= (7U << (3*(ADC_PT1000_CHANNEL-10)));
|
||||
ADC_PT1000_PERIPH->SMPR1 |= (7U << (3*(ADC_PT1000_CHANNEL-10)));
|
||||
#endif
|
||||
|
||||
ADC->CCR |= (0x2<<16);
|
||||
ADC->CCR |= (0x3<<16);
|
||||
|
||||
/* Set watchdog limits */
|
||||
ADC1->HTR = ADC_PT1000_UPPER_WATCHDOG;
|
||||
ADC1->LTR = ADC_PT1000_LOWER_WATCHDOG;
|
||||
ADC_PT1000_PERIPH->HTR = ADC_PT1000_UPPER_WATCHDOG;
|
||||
ADC_PT1000_PERIPH->LTR = ADC_PT1000_LOWER_WATCHDOG;
|
||||
|
||||
/* Set length of sequence to 1 */
|
||||
ADC1->SQR1 = (0UL<<20);
|
||||
ADC_PT1000_PERIPH->SQR1 = (0UL<<20);
|
||||
|
||||
/* Set channel as 1st element in sequence */
|
||||
ADC1->SQR3 = (ADC_PT1000_CHANNEL<<0);
|
||||
ADC_PT1000_PERIPH->SQR3 = (ADC_PT1000_CHANNEL<<0);
|
||||
|
||||
ADC1->CR1 = ADC_CR1_OVRIE | ADC_CR1_AWDEN | ADC_CR1_AWDIE;
|
||||
ADC1->CR2 = ADC_CR2_EXTEN_0 | ADC_CR2_EXTSEL_2 | ADC_CR2_EXTSEL_1 | ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
|
||||
ADC_PT1000_PERIPH->CR1 = ADC_CR1_OVRIE | ADC_CR1_AWDEN | ADC_CR1_AWDIE;
|
||||
ADC_PT1000_PERIPH->CR2 = ADC_CR2_EXTEN_0 | ADC_CR2_EXTSEL_2 | ADC_CR2_EXTSEL_1 |
|
||||
ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
|
||||
|
||||
adc_pt1000_set_moving_average_filter_param(ADC_PT1000_FILTER_WEIGHT);
|
||||
adc_pt1000_set_resistance_calibration(0, 0, false);
|
||||
@@ -142,14 +178,19 @@ void adc_pt1000_setup_meas()
|
||||
|
||||
adc_pt1000_setup_sample_frequency_timer();
|
||||
|
||||
pt1000_measurement_active = true;
|
||||
safety_controller_ack_flag_with_key(ERR_FLAG_MEAS_ADC_OFF, MEAS_ADC_SAFETY_FLAG_KEY);
|
||||
|
||||
streaming_flag_ptr = NULL;
|
||||
adc_watchdog_counter = 0UL;
|
||||
stream_buffer = NULL;
|
||||
|
||||
safety_controller_set_crc_monitor(ERR_CRC_MON_MEAS_ADC, SAFETY_CRC_MON_MEAS_ADC_PW);
|
||||
}
|
||||
|
||||
void adc_pt1000_set_moving_average_filter_param(float alpha)
|
||||
{
|
||||
filter_alpha = alpha;
|
||||
filter_ready = false;
|
||||
filter_startup_cnt = ADC_FILTER_STARTUP_CYCLES;
|
||||
safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE, MEAS_ADC_SAFETY_FLAG_KEY);
|
||||
}
|
||||
|
||||
void adc_pt1000_set_resistance_calibration(float offset, float sensitivity_deviation, bool active)
|
||||
@@ -157,22 +198,27 @@ void adc_pt1000_set_resistance_calibration(float offset, float sensitivity_devia
|
||||
pt1000_offset = offset;
|
||||
pt1000_sens_dev = sensitivity_deviation;
|
||||
calibration_active = active;
|
||||
|
||||
if (!calibration_active)
|
||||
safety_controller_report_error_with_key(ERR_FLAG_UNCAL, MEAS_ADC_SAFETY_FLAG_KEY);
|
||||
else
|
||||
safety_controller_ack_flag_with_key(ERR_FLAG_UNCAL, MEAS_ADC_SAFETY_FLAG_KEY);
|
||||
}
|
||||
|
||||
void adc_pt1000_get_resistance_calibration(float *offset, float *sensitivity_deviation, bool *active)
|
||||
{
|
||||
if (!offset || !sensitivity_deviation || !active)
|
||||
return;
|
||||
|
||||
*offset = pt1000_offset;
|
||||
*sensitivity_deviation = pt1000_sens_dev;
|
||||
*active = calibration_active;
|
||||
if (offset)
|
||||
*offset = pt1000_offset;
|
||||
if (sensitivity_deviation)
|
||||
*sensitivity_deviation = pt1000_sens_dev;
|
||||
if (active)
|
||||
*active = calibration_active;
|
||||
}
|
||||
|
||||
static inline float adc_pt1000_apply_calibration(float raw_resistance)
|
||||
{
|
||||
if (calibration_active)
|
||||
return pt1000_res_raw_lf * (1.0f + pt1000_sens_dev) + pt1000_offset;
|
||||
return (raw_resistance - pt1000_offset) * (1.0f + pt1000_sens_dev);
|
||||
else
|
||||
return raw_resistance;
|
||||
|
||||
@@ -181,18 +227,23 @@ static inline float adc_pt1000_apply_calibration(float raw_resistance)
|
||||
int adc_pt1000_get_current_resistance(float *resistance)
|
||||
{
|
||||
int ret_val = 0;
|
||||
bool flag = true;
|
||||
|
||||
|
||||
if (!resistance)
|
||||
return -1001;
|
||||
|
||||
*resistance = adc_pt1000_apply_calibration(pt1000_res_raw_lf);
|
||||
|
||||
if (adc_pt1000_check_error()) {
|
||||
if (safety_controller_get_flags_by_mask(ERR_FLAG_MEAS_ADC_OFF | ERR_FLAG_MEAS_ADC_OVERFLOW |
|
||||
ERR_FLAG_MEAS_ADC_WATCHDOG | ERR_FLAG_TIMING_MEAS_ADC)) {
|
||||
ret_val = -100;
|
||||
goto return_value;
|
||||
}
|
||||
|
||||
if (!filter_ready) {
|
||||
(void)safety_controller_get_flag(ERR_FLAG_MEAS_ADC_UNSTABLE, &flag, false);
|
||||
|
||||
if (flag) {
|
||||
ret_val = 2;
|
||||
goto return_value;
|
||||
}
|
||||
@@ -201,36 +252,50 @@ return_value:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/*
|
||||
int adc_pt1000_stream_raw_value_to_memory(float *adc_array, uint32_t length, volatile uint8_t *flag_to_set)
|
||||
int adc_pt1000_stream_raw_value_to_memory(volatile float *adc_array, uint32_t length, volatile int *flag_to_set)
|
||||
{
|
||||
return -1;
|
||||
int ret = 0;
|
||||
|
||||
if (!flag_to_set)
|
||||
return -1;
|
||||
|
||||
stream_buffer = adc_array;
|
||||
stream_count = length;
|
||||
stream_pos = 0U;
|
||||
|
||||
if (adc_array) {
|
||||
*flag_to_set = 0;
|
||||
streaming_flag_ptr = flag_to_set;
|
||||
} else {
|
||||
ret = -2;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void adc_pt1000_convert_raw_value_array_to_resistance(float *resistance_dest, float *raw_source, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
}
|
||||
*/
|
||||
if (!resistance_dest)
|
||||
resistance_dest = raw_source;
|
||||
|
||||
enum adc_pt1000_error adc_pt1000_check_error()
|
||||
{
|
||||
return pt1000_error;
|
||||
if (!raw_source || !count)
|
||||
return;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
resistance_dest[i] = ADC_TO_RES(raw_source[i]);
|
||||
}
|
||||
|
||||
void adc_pt1000_clear_error()
|
||||
{
|
||||
pt1000_error = ADC_PT1000_NO_ERR;
|
||||
}
|
||||
|
||||
void adc_pt1000_disable()
|
||||
void adc_pt1000_disable(void)
|
||||
{
|
||||
adc_pt1000_disable_adc();
|
||||
adc_pt1000_stop_sample_frequency_timer();
|
||||
adc_pt1000_disable_dma_stream();
|
||||
|
||||
filter_ready = false;
|
||||
pt1000_res_raw_lf = 0.0f;
|
||||
safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_OFF, MEAS_ADC_SAFETY_FLAG_KEY);
|
||||
safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE, MEAS_ADC_SAFETY_FLAG_KEY);
|
||||
|
||||
if (streaming_flag_ptr) {
|
||||
*streaming_flag_ptr = -3;
|
||||
@@ -240,13 +305,39 @@ void adc_pt1000_disable()
|
||||
|
||||
static inline __attribute__((optimize("O3"))) void adc_pt1000_filter(float adc_prefiltered_value)
|
||||
{
|
||||
if (!filter_ready && --filter_startup_cnt <= 0)
|
||||
filter_ready = true;
|
||||
float alpha;
|
||||
float res;
|
||||
static uint8_t old_state = 0;
|
||||
static uint32_t stable_sample_counter = 0;
|
||||
|
||||
pt1000_res_raw_lf = (1.0f-filter_alpha) * pt1000_res_raw_lf + filter_alpha * ADC_TO_RES(adc_prefiltered_value);
|
||||
res = ADC_TO_RES(adc_prefiltered_value);
|
||||
if (ABS(res - pt1000_res_raw_lf) >= ADC_PT1000_FILTER_UNSTABLE_DIFF) {
|
||||
stable_sample_counter = 0;
|
||||
alpha = ADC_PT1000_FILTER_WEIGHT_FAST;
|
||||
if (old_state != 1) {
|
||||
safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE,
|
||||
MEAS_ADC_SAFETY_FLAG_KEY);
|
||||
old_state = 1;
|
||||
}
|
||||
} else {
|
||||
alpha = filter_alpha;
|
||||
if (old_state != 2) {
|
||||
stable_sample_counter++;
|
||||
if (stable_sample_counter >= ADC_PT1000_FILTER_STABLE_SAMPLE_COUNT) {
|
||||
safety_controller_ack_flag_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE,
|
||||
MEAS_ADC_SAFETY_FLAG_KEY);
|
||||
old_state = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pt1000_res_raw_lf = (1.0f - alpha) * pt1000_res_raw_lf +
|
||||
alpha * res;
|
||||
|
||||
safety_controller_report_timing(ERR_TIMING_MEAS_ADC);
|
||||
}
|
||||
|
||||
static inline __attribute__((optimize("O3"))) float adc_pt1000_dma_avg_pre_filter()
|
||||
static inline __attribute__((optimize("O3"))) float adc_pt1000_dma_avg_pre_filter(void)
|
||||
{
|
||||
unsigned int i;
|
||||
uint32_t sum = 0;
|
||||
@@ -276,45 +367,62 @@ void ADC_IRQHandler(void)
|
||||
{
|
||||
uint32_t adc1_sr;
|
||||
|
||||
adc1_sr = ADC1->SR;
|
||||
adc1_sr = ADC_PT1000_PERIPH->SR;
|
||||
|
||||
if (adc1_sr & ADC_SR_OVR) {
|
||||
ADC1->SR &= ~ADC_SR_OVR;
|
||||
pt1000_error |= ADC_PT1000_OVERFLOW;
|
||||
ADC_PT1000_PERIPH->SR &= ~ADC_SR_OVR;
|
||||
safety_controller_report_error(ERR_FLAG_MEAS_ADC_OVERFLOW);
|
||||
/* Disable ADC in case of overrrun*/
|
||||
adc_pt1000_disable();
|
||||
if (streaming_flag_ptr) {
|
||||
*streaming_flag_ptr = -1;
|
||||
streaming_flag_ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (adc1_sr & ADC_SR_AWD) {
|
||||
ADC1->SR &= ~ADC_SR_AWD;
|
||||
pt1000_error |= ADC_PT1000_WATCHDOG_ERROR;
|
||||
ADC_PT1000_PERIPH->SR &= ~ADC_SR_AWD;
|
||||
adc_watchdog_counter++;
|
||||
if (adc_watchdog_counter >= ADC_PT1000_WATCHDOG_SAMPLE_COUNT)
|
||||
safety_controller_report_error(ERR_FLAG_MEAS_ADC_WATCHDOG);
|
||||
}
|
||||
}
|
||||
|
||||
void DMA2_Stream0_IRQHandler()
|
||||
static void append_stream_buffer(float val)
|
||||
{
|
||||
if (!stream_buffer || !streaming_flag_ptr)
|
||||
return;
|
||||
|
||||
if (stream_pos < stream_count)
|
||||
stream_buffer[stream_pos++] = val;
|
||||
|
||||
if (stream_pos >= stream_count) {
|
||||
*streaming_flag_ptr = 1;
|
||||
streaming_flag_ptr = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DMA2_Stream0_IRQHandler(void)
|
||||
{
|
||||
uint32_t lisr;
|
||||
float adc_val;
|
||||
|
||||
lisr = DMA2->LISR;
|
||||
lisr = DMA2->LISR & (0x3F);
|
||||
DMA2->LIFCR = lisr;
|
||||
|
||||
if (lisr & DMA_LISR_TCIF0) {
|
||||
/* Samples Transfered */
|
||||
/* Samples transferred */
|
||||
adc_val = adc_pt1000_dma_avg_pre_filter();
|
||||
adc_pt1000_raw_reading_hf = adc_val;
|
||||
|
||||
if (streaming_flag_ptr)
|
||||
append_stream_buffer(adc_val);
|
||||
|
||||
if (adc_watchdog_counter > 0UL)
|
||||
adc_watchdog_counter--;
|
||||
|
||||
/* Call moving average filter */
|
||||
adc_pt1000_filter(adc_val);
|
||||
}
|
||||
|
||||
if (lisr & DMA_LISR_TEIF0) {
|
||||
/* Wait for watchdog to kick in */
|
||||
while(1);
|
||||
}
|
||||
if (lisr & DMA_LISR_TEIF0)
|
||||
adc_pt1000_disable();
|
||||
|
||||
}
|
||||
|
||||
28
stm-firmware/arm-none-eabi-gcc.cmake
Normal file
28
stm-firmware/arm-none-eabi-gcc.cmake
Normal file
@@ -0,0 +1,28 @@
|
||||
if(MINGW OR CYGWIN OR WIN32)
|
||||
set(UTIL_SEARCH_CMD where)
|
||||
elseif(UNIX OR APPLE)
|
||||
set(UTIL_SEARCH_CMD which)
|
||||
endif()
|
||||
|
||||
set(TOOLCHAIN_PREFIX arm-none-eabi-)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${UTIL_SEARCH_CMD} ${TOOLCHAIN_PREFIX}gcc
|
||||
OUTPUT_VARIABLE BINUTILS_PATH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
get_filename_component(ARM_TOOLCHAIN_DIR ${BINUTILS_PATH} DIRECTORY)
|
||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||
|
||||
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc)
|
||||
set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
|
||||
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++)
|
||||
|
||||
set(CMAKE_OBJCOPY ${ARM_TOOLCHAIN_DIR}/${TOOLCHAIN_PREFIX}objcopy CACHE INTERNAL "objcopy tool")
|
||||
set(CMAKE_SIZE_UTIL ${ARM_TOOLCHAIN_DIR}/${TOOLCHAIN_PREFIX}size CACHE INTERNAL "size tool")
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH ${BINUTILS_PATH})
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
1
stm-firmware/base64-lib
Submodule
1
stm-firmware/base64-lib
Submodule
Submodule stm-firmware/base64-lib added at 251e90abf3
126
stm-firmware/boot/startup-tests.c
Normal file
126
stm-firmware/boot/startup-tests.c
Normal file
@@ -0,0 +1,126 @@
|
||||
#include "startup-tests.h"
|
||||
|
||||
uint32_t startup_test_perform_ccm_ram_check(void)
|
||||
{
|
||||
const void *ccmram_base = (void *)0x10000000UL;
|
||||
const uint32_t ccmram_size = 64U * 1024UL;
|
||||
volatile uint32_t *word_ptr;
|
||||
uint32_t target_val;
|
||||
uint32_t idx;
|
||||
uint32_t ret = 0UL;
|
||||
|
||||
|
||||
/* Perform inversion test with 0x55 and 0xAA, Part 1 */
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) {
|
||||
word_ptr[idx] = idx & 1 ? 0x55AA55AAUL : 0xAA55AA55UL;
|
||||
}
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) {
|
||||
target_val = idx & 1 ? 0x55AA55AAUL : 0xAA55AA55UL;
|
||||
if (target_val != word_ptr[idx]) {
|
||||
ret = (uint32_t)&word_ptr[idx];
|
||||
goto exit_ret_address;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform inversion test with 0x55 and 0xAA, Part 2 */
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) {
|
||||
word_ptr[idx] = idx & 1 ? 0xAA55AA55UL : 0x55AA55AAUL;
|
||||
}
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) {
|
||||
target_val = idx & 1 ? 0xAA55AA55UL : 0x55AA55AAUL;
|
||||
if (target_val != word_ptr[idx]) {
|
||||
ret = (uint32_t)&word_ptr[idx];
|
||||
goto exit_ret_address;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform static test with 0xFF */
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) {
|
||||
word_ptr[idx] = 0xFFFFFFFFUL;
|
||||
}
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) {
|
||||
target_val = 0xFFFFFFFFUL;
|
||||
if (target_val != word_ptr[idx]) {
|
||||
ret = (uint32_t)&word_ptr[idx];
|
||||
goto exit_ret_address;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform static test with 0x00 */
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) {
|
||||
word_ptr[idx] = 0x0UL;
|
||||
}
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) {
|
||||
target_val = 0x0UL;
|
||||
if (target_val != word_ptr[idx]) {
|
||||
ret = (uint32_t)&word_ptr[idx];
|
||||
goto exit_ret_address;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
exit_ret_address:
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t startup_test_perform_system_ram_check()
|
||||
{
|
||||
const void *ram_base = (void *)0x20000000UL;
|
||||
const uint32_t ram_size = 128U * 1024UL;
|
||||
volatile uint32_t *word_ptr;
|
||||
uint32_t target_val;
|
||||
uint32_t idx;
|
||||
uint32_t ret = 0UL;
|
||||
|
||||
|
||||
/* Perform inversion test with 0x55 and 0xAA, Part 1 */
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) {
|
||||
word_ptr[idx] = idx & 1 ? 0x55AA55AAUL : 0xAA55AA55UL;
|
||||
}
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) {
|
||||
target_val = idx & 1 ? 0x55AA55AAUL : 0xAA55AA55UL;
|
||||
if (target_val != word_ptr[idx]) {
|
||||
ret = (uint32_t)&word_ptr[idx];
|
||||
goto exit_ret_address;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform inversion test with 0x55 and 0xAA, Part 2 */
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) {
|
||||
word_ptr[idx] = idx & 1 ? 0xAA55AA55UL : 0x55AA55AAUL;
|
||||
}
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) {
|
||||
target_val = idx & 1 ? 0xAA55AA55UL : 0x55AA55AAUL;
|
||||
if (target_val != word_ptr[idx]) {
|
||||
ret = (uint32_t)&word_ptr[idx];
|
||||
goto exit_ret_address;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform static test with 0xFF */
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) {
|
||||
word_ptr[idx] = 0xFFFFFFFFUL;
|
||||
}
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) {
|
||||
target_val = 0xFFFFFFFFUL;
|
||||
if (target_val != word_ptr[idx]) {
|
||||
ret = (uint32_t)&word_ptr[idx];
|
||||
goto exit_ret_address;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform static test with 0x00 */
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) {
|
||||
word_ptr[idx] = 0x0UL;
|
||||
}
|
||||
for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) {
|
||||
target_val = 0x0UL;
|
||||
if (target_val != word_ptr[idx]) {
|
||||
ret = (uint32_t)&word_ptr[idx];
|
||||
goto exit_ret_address;
|
||||
}
|
||||
}
|
||||
|
||||
exit_ret_address:
|
||||
return ret;
|
||||
}
|
||||
25
stm-firmware/boot/startup-tests.h
Normal file
25
stm-firmware/boot/startup-tests.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef _STARTUP_TESTS_H_
|
||||
#define _STARTUP_TESTS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Do a RAM check of the CCM RAM.
|
||||
*
|
||||
* Loop over the whole CCM memory area and check it.
|
||||
*
|
||||
* @return 0 if successful. Else the defect address is returned.
|
||||
* @warning This will completely corrupt this memory!
|
||||
* You have to ensure to set it to sane values afterwards!
|
||||
*/
|
||||
uint32_t startup_test_perform_ccm_ram_check(void);
|
||||
|
||||
/**
|
||||
* @brief Do a RAM check of the stnadard SRAM regions
|
||||
* @return 0 if successful. If an error is found, the faulty address is returned
|
||||
* @warning This completely destroys all content in the memory!
|
||||
* @warning Ensure that the stack pointer is moved to a different memory reagion (CCM RAM)!
|
||||
*/
|
||||
uint32_t startup_test_perform_system_ram_check(void);
|
||||
|
||||
#endif /* _STARTUP_TESTS_H_ */
|
||||
402
stm-firmware/boot/startup_stm32f407vx.c
Normal file
402
stm-firmware/boot/startup_stm32f407vx.c
Normal file
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* STM32F4 Startup Code for STM32F407 devices
|
||||
* Copyright (C) 2017 Mario Hüttel <mario.huettel@gmx.net>
|
||||
*
|
||||
* This file is part of 'STM32F4 code template'.
|
||||
*
|
||||
* It 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, version 2 of the License.
|
||||
*
|
||||
* This code 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 template. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "startup-tests.h"
|
||||
|
||||
/* C++ library init */
|
||||
# if defined(__cplusplus)
|
||||
extern "C" {
|
||||
extern void __libc_init_array(void);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Defines for weak default handlers */
|
||||
#define WEAK __attribute__((weak))
|
||||
#define ALIAS(func) __attribute__ ((weak, alias (#func)))
|
||||
|
||||
/* Define for section mapping */
|
||||
#define SECTION(sec) __attribute__((section(sec)))
|
||||
|
||||
/* Handler prototypes */
|
||||
#if defined(_cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Interrupt Defualt handler */
|
||||
WEAK void __int_default_handler(void);
|
||||
|
||||
/* Core Interrupts */
|
||||
void Reset_Handler(void);
|
||||
void NMI_Handler(void) ALIAS(__int_default_handler);
|
||||
void HardFault_Handler(void) ALIAS(__int_default_handler);
|
||||
void MemManage_Handler(void) ALIAS(__int_default_handler);
|
||||
void BusFault_Handler(void) ALIAS(__int_default_handler);
|
||||
void UsageFault_Handler(void) ALIAS(__int_default_handler);
|
||||
void SVC_Handler(void) ALIAS(__int_default_handler);
|
||||
void DebugMon_Handler(void) ALIAS(__int_default_handler);
|
||||
void PendSV_Handler(void) ALIAS(__int_default_handler);
|
||||
void SysTick_Handler(void) ALIAS(__int_default_handler);
|
||||
|
||||
/* Peripheral Interrupts (by default mapped onto Default Handler) */
|
||||
void WWDG_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void PVD_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TAMP_STAMP_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void RTC_WKUP_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void FLASH_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void RCC_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void EXTI0_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void EXTI1_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void EXTI2_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void EXTI3_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void EXTI4_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA1_Stream0_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA1_Stream1_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA1_Stream2_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA1_Stream3_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA1_Stream4_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA1_Stream5_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA1_Stream6_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void ADC_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void CAN1_TX_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void CAN1_RX0_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void CAN1_RX1_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void CAN1_SCE_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void EXTI9_5_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TIM1_BRK_TIM9_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TIM1_UP_TIM10_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TIM1_TRG_COM_TIM11_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TIM1_CC_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TIM2_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TIM3_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TIM4_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void I2C1_EV_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void I2C1_ER_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void I2C2_EV_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void I2C2_ER_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void SPI1_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void SPI2_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void USART1_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void USART2_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void USART3_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void EXTI15_10_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void RTC_Alarm_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void OTG_FS_WKUP_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TIM8_BRK_TIM12_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TIM8_UP_TIM13_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TIM8_TRG_COM_TIM14_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TIM8_CC_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA1_Stream7_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void FSMC_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void SDIO_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TIM5_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void SPI3_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void UART4_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void UART5_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TIM6_DAC_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void TIM7_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA2_Stream0_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA2_Stream1_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA2_Stream2_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA2_Stream3_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA2_Stream4_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void ETH_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void ETH_WKUP_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void CAN2_TX_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void CAN2_RX0_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void CAN2_RX1_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void CAN2_SCE_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void OTG_FS_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA2_Stream5_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA2_Stream6_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DMA2_Stream7_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void USART6_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void I2C3_EV_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void I2C3_ER_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void OTG_HS_EP1_OUT_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void OTG_HS_EP1_IN_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void OTG_HS_WKUP_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void OTG_HS_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void DCMI_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void CRYP_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void HASH_RNG_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
void FPU_IRQHandler(void) ALIAS(__int_default_handler);
|
||||
|
||||
extern int main(void);
|
||||
extern void SystemInit(void);
|
||||
|
||||
extern void __ld_top_of_stack(void);
|
||||
#if defined(_cplusplus)
|
||||
extern "C" }
|
||||
#endif
|
||||
|
||||
void (* const vector_table[])(void) SECTION(".vectors") = {
|
||||
&__ld_top_of_stack,
|
||||
/* Core Interrupts */
|
||||
Reset_Handler,
|
||||
NMI_Handler,
|
||||
HardFault_Handler,
|
||||
MemManage_Handler,
|
||||
BusFault_Handler,
|
||||
UsageFault_Handler,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
SVC_Handler,
|
||||
DebugMon_Handler,
|
||||
0,
|
||||
PendSV_Handler,
|
||||
SysTick_Handler,
|
||||
/* Peripheral Interrupts */
|
||||
WWDG_IRQHandler,
|
||||
PVD_IRQHandler,
|
||||
TAMP_STAMP_IRQHandler,
|
||||
RTC_WKUP_IRQHandler,
|
||||
FLASH_IRQHandler,
|
||||
RCC_IRQHandler,
|
||||
EXTI0_IRQHandler,
|
||||
EXTI1_IRQHandler,
|
||||
EXTI2_IRQHandler,
|
||||
EXTI3_IRQHandler,
|
||||
EXTI4_IRQHandler,
|
||||
DMA1_Stream0_IRQHandler,
|
||||
DMA1_Stream1_IRQHandler,
|
||||
DMA1_Stream2_IRQHandler,
|
||||
DMA1_Stream3_IRQHandler,
|
||||
DMA1_Stream4_IRQHandler,
|
||||
DMA1_Stream5_IRQHandler,
|
||||
DMA1_Stream6_IRQHandler,
|
||||
ADC_IRQHandler,
|
||||
CAN1_TX_IRQHandler,
|
||||
CAN1_RX0_IRQHandler,
|
||||
CAN1_RX1_IRQHandler,
|
||||
CAN1_SCE_IRQHandler,
|
||||
EXTI9_5_IRQHandler,
|
||||
TIM1_BRK_TIM9_IRQHandler,
|
||||
TIM1_UP_TIM10_IRQHandler,
|
||||
TIM1_TRG_COM_TIM11_IRQHandler,
|
||||
TIM1_CC_IRQHandler,
|
||||
TIM2_IRQHandler,
|
||||
TIM3_IRQHandler,
|
||||
TIM4_IRQHandler,
|
||||
I2C1_EV_IRQHandler,
|
||||
I2C1_ER_IRQHandler,
|
||||
I2C2_EV_IRQHandler,
|
||||
I2C2_ER_IRQHandler,
|
||||
SPI1_IRQHandler,
|
||||
SPI2_IRQHandler,
|
||||
USART1_IRQHandler,
|
||||
USART2_IRQHandler,
|
||||
USART3_IRQHandler,
|
||||
EXTI15_10_IRQHandler,
|
||||
RTC_Alarm_IRQHandler,
|
||||
OTG_FS_WKUP_IRQHandler,
|
||||
TIM8_BRK_TIM12_IRQHandler,
|
||||
TIM8_UP_TIM13_IRQHandler,
|
||||
TIM8_TRG_COM_TIM14_IRQHandler,
|
||||
TIM8_CC_IRQHandler,
|
||||
DMA1_Stream7_IRQHandler,
|
||||
FSMC_IRQHandler,
|
||||
SDIO_IRQHandler,
|
||||
TIM5_IRQHandler,
|
||||
SPI3_IRQHandler,
|
||||
UART4_IRQHandler,
|
||||
UART5_IRQHandler,
|
||||
TIM6_DAC_IRQHandler,
|
||||
TIM7_IRQHandler,
|
||||
DMA2_Stream0_IRQHandler,
|
||||
DMA2_Stream1_IRQHandler,
|
||||
DMA2_Stream2_IRQHandler,
|
||||
DMA2_Stream3_IRQHandler,
|
||||
DMA2_Stream4_IRQHandler,
|
||||
ETH_IRQHandler,
|
||||
ETH_WKUP_IRQHandler,
|
||||
CAN2_TX_IRQHandler,
|
||||
CAN2_RX0_IRQHandler,
|
||||
CAN2_RX1_IRQHandler,
|
||||
CAN2_SCE_IRQHandler,
|
||||
OTG_FS_IRQHandler,
|
||||
DMA2_Stream5_IRQHandler,
|
||||
DMA2_Stream6_IRQHandler,
|
||||
DMA2_Stream7_IRQHandler,
|
||||
USART6_IRQHandler,
|
||||
I2C3_EV_IRQHandler,
|
||||
I2C3_ER_IRQHandler,
|
||||
OTG_HS_EP1_OUT_IRQHandler,
|
||||
OTG_HS_EP1_IN_IRQHandler,
|
||||
OTG_HS_WKUP_IRQHandler,
|
||||
OTG_HS_IRQHandler,
|
||||
DCMI_IRQHandler,
|
||||
CRYP_IRQHandler,
|
||||
HASH_RNG_IRQHandler,
|
||||
FPU_IRQHandler
|
||||
};
|
||||
|
||||
static void __init_section(unsigned int *src_start, unsigned int *dest_start, unsigned int *dest_end) {
|
||||
unsigned int *get, *put;
|
||||
|
||||
put = dest_start;
|
||||
get = src_start;
|
||||
|
||||
while ((unsigned int)put < (unsigned int)dest_end) {
|
||||
*(put++) = *(get++);
|
||||
}
|
||||
}
|
||||
|
||||
static void __fill_zero(unsigned int *start, unsigned int *end) {
|
||||
while ((unsigned int) start < (unsigned int)end) {
|
||||
*(start++) = 0x00000000;
|
||||
}
|
||||
}
|
||||
|
||||
extern unsigned int __ld_load_data;
|
||||
extern unsigned int __ld_sdata_ccm;
|
||||
extern unsigned int __ld_edata_ccm;
|
||||
extern unsigned int __ld_load_ccm_data;
|
||||
extern unsigned int __ld_sdata_ccm;
|
||||
extern unsigned int __ld_edata_ccm;
|
||||
extern unsigned int __ld_sbss_ccm;
|
||||
extern unsigned int __ld_ebss_ccm;
|
||||
extern unsigned int __ld_sdata;
|
||||
extern unsigned int __ld_edata;
|
||||
extern unsigned int __ld_sbss;
|
||||
extern unsigned int __ld_ebss;
|
||||
extern unsigned int __ld_sheap;
|
||||
extern unsigned int __ld_eheap;
|
||||
|
||||
#ifdef CPACR
|
||||
#undef CPACR
|
||||
#endif
|
||||
|
||||
#define CPACR (*((volatile uint32_t *)0xE000ED88))
|
||||
|
||||
void __attribute__((noreturn)) Reset_Handler(void) {
|
||||
/* Stack is already initialized by hardware */
|
||||
|
||||
/* The first thing we do here, is to initialize the FPU
|
||||
* When this code is compiled optimized with hardfpu abi,
|
||||
* GCC tends to generate FPU instructions for data copying
|
||||
*/
|
||||
CPACR |= (0xF << 20);
|
||||
|
||||
/**
|
||||
* Prepare RAM etc for the System Init function. This ensures, the RAM tests execute at max speed.
|
||||
*/
|
||||
|
||||
/* Copy .data section */
|
||||
__init_section(&__ld_load_data, &__ld_sdata, &__ld_edata);
|
||||
/* Fill bss with zero */
|
||||
__fill_zero(&__ld_sbss, &__ld_ebss);
|
||||
/* Fill Heap with zero */
|
||||
__fill_zero(&__ld_sheap, &__ld_eheap);
|
||||
/* Fill static CCM memory with zeroes */
|
||||
__fill_zero(&__ld_sbss_ccm, &__ld_ebss_ccm);
|
||||
/* Init CCM RAM data section */
|
||||
__init_section(&__ld_load_ccm_data, &__ld_sdata_ccm, &__ld_edata_ccm);
|
||||
|
||||
/* Set clocks, waitstates, ART operation etc. */
|
||||
SystemInit();
|
||||
|
||||
if (startup_test_perform_ccm_ram_check()) {
|
||||
/* Hang forever in case of an error. We cannot handle this (yet?) */
|
||||
while (1);
|
||||
}
|
||||
|
||||
/* Move the stack and the stack pointer to CCMRAM
|
||||
* This allows us to perform a RAM test on the main RAM.
|
||||
*/
|
||||
/* R2 holds the amount of bytes / words on the stack. */
|
||||
__asm__ __volatile__ (
|
||||
"mov r2, sp\n" /* Move stack pointer to register 2 */
|
||||
"sub r2, %[stacktop], r2\n" /* Subtract stackpointer from top of ram => byte usage */
|
||||
"mov r3, sp\n" /* Init r3 with first word address to copy (stack pointer) */
|
||||
"sub r4, %[ccmtop], r2\n" /* Init r4 with first address to copy to! This will be the new stack pointer! */
|
||||
"mov r5, r4\n" /* R5 will be the new stackpointer after we are finished copying */
|
||||
"copyloop:\n"
|
||||
"cmp r3, %[stacktop]\n" /* Check if we still have word to copy. If not => finish */
|
||||
"beq finish\n"
|
||||
"ldr.w r6, [r3, #0]\n" /* Load word from [r3] and store into [r4] */
|
||||
"str.w r6, [r4, #0]\n"
|
||||
"add r3, #4\n" /* Increment pointers */
|
||||
"add r4, #4\n"
|
||||
"b copyloop\n" /* go back to loop head */
|
||||
"finish:\n"
|
||||
"mov sp, r5\n" /* Set the new stack pointer to the beginning of the copied area */
|
||||
:
|
||||
: [stacktop]"r"(&__ld_top_of_stack), [ccmtop]"r"(0x10000000UL + (64U * 1024UL))
|
||||
: "memory", "r2", "r3", "r4", "r5", "r6");
|
||||
|
||||
if (startup_test_perform_system_ram_check()) {
|
||||
while (1);
|
||||
}
|
||||
|
||||
/* Move the stack back to system ram */
|
||||
__asm__ __volatile__ (
|
||||
"mov r2, sp\n" /* Move stack pointer to register 2 */
|
||||
"sub r2, %[ccmtop], r2\n" /* Subtract stackpointer from top of ccmram => byte usage */
|
||||
"mov r3, sp\n" /* Init r3 with first word address to copy (stack pointer) */
|
||||
"sub r4, %[stacktop], r2\n" /* Init r4 with first address to copy to! This will be the new stack pointer! */
|
||||
"mov r5, r4\n" /* R5 will be the new stackpointer after we are finished copying */
|
||||
"copyloop_2:\n"
|
||||
"cmp r3, %[ccmtop]\n" /* Check if we still have word to copy. If not => finish */
|
||||
"beq finish_2\n"
|
||||
"ldr.w r6, [r3, #0]\n" /* Load word from [r3] and store into [r4] */
|
||||
"str.w r6, [r4, #0]\n"
|
||||
"add r3, #4\n" /* Increment pointers */
|
||||
"add r4, #4\n"
|
||||
"b copyloop_2\n" /* go back to loop head */
|
||||
"finish_2:\n"
|
||||
"mov sp, r5\n" /* Set the new stack pointer to the beginning of the copied area */
|
||||
:
|
||||
: [stacktop]"r"(&__ld_top_of_stack), [ccmtop]"r"(0x10000000UL + (64U * 1024UL))
|
||||
: "memory", "r2", "r3", "r4", "r5", "r6");
|
||||
|
||||
/**
|
||||
* RAM tests destroyed our values. So we have to copy them again...
|
||||
*/
|
||||
|
||||
/* Copy .data section */
|
||||
__init_section(&__ld_load_data, &__ld_sdata, &__ld_edata);
|
||||
/* Fill bss with zero */
|
||||
__fill_zero(&__ld_sbss, &__ld_ebss);
|
||||
/* Fill Heap with zero */
|
||||
__fill_zero(&__ld_sheap, &__ld_eheap);
|
||||
/* Fill static CCM memory with zeroes */
|
||||
__fill_zero(&__ld_sbss_ccm, &__ld_ebss_ccm);
|
||||
/* Init CCM RAM data section */
|
||||
__init_section(&__ld_load_ccm_data, &__ld_sdata_ccm, &__ld_edata_ccm);
|
||||
|
||||
/* C++ init function */
|
||||
#if defined(__cplusplus)
|
||||
__libc_init_array();
|
||||
#endif
|
||||
/* Call main */
|
||||
main();
|
||||
|
||||
/* Catch return from main() */
|
||||
while(1);
|
||||
}
|
||||
|
||||
WEAK void __int_default_handler(void)
|
||||
{
|
||||
while(1);
|
||||
}
|
||||
@@ -1,513 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file startup_stm32f4xx.s
|
||||
* @author MCD Application Team
|
||||
* @version V1.0.0
|
||||
* @date 30-September-2011
|
||||
* @brief STM32F4xx Devices vector table for Atollic TrueSTUDIO toolchain.
|
||||
* This module performs:
|
||||
* - Set the initial SP
|
||||
* - Set the initial PC == Reset_Handler,
|
||||
* - Set the vector table entries with the exceptions ISR address
|
||||
* - Configure the clock system and the external SRAM mounted on
|
||||
* STM324xG-EVAL board to be used as data memory (optional,
|
||||
* to be enabled by user)
|
||||
* - Branches to main in the C library (which eventually
|
||||
* calls main()).
|
||||
* After Reset the Cortex-M4 processor is in Thread mode,
|
||||
* priority is Privileged, and the Stack is set to Main.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m3
|
||||
.fpu softvfp
|
||||
.thumb
|
||||
|
||||
.global g_pfnVectors
|
||||
.global Default_Handler
|
||||
|
||||
/* start address for the initialization values of the .data section.
|
||||
defined in linker script */
|
||||
.word _sidata
|
||||
/* start address for the .data section. defined in linker script */
|
||||
.word _sdata
|
||||
/* end address for the .data section. defined in linker script */
|
||||
.word _edata
|
||||
/* start address for the .bss section. defined in linker script */
|
||||
.word _sbss
|
||||
/* end address for the .bss section. defined in linker script */
|
||||
.word _ebss
|
||||
/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
|
||||
|
||||
/**
|
||||
* @brief This is the code that gets called when the processor first
|
||||
* starts execution following a reset event. Only the absolutely
|
||||
* necessary set is performed, after which the application
|
||||
* supplied main() routine is called.
|
||||
* @param None
|
||||
* @retval : None
|
||||
*/
|
||||
|
||||
.section .text.Reset_Handler
|
||||
.weak Reset_Handler
|
||||
.type Reset_Handler, %function
|
||||
Reset_Handler:
|
||||
|
||||
/* Copy the data segment initializers from flash to SRAM */
|
||||
movs r1, #0
|
||||
b LoopCopyDataInit
|
||||
|
||||
CopyDataInit:
|
||||
ldr r3, =_sidata
|
||||
ldr r3, [r3, r1]
|
||||
str r3, [r0, r1]
|
||||
adds r1, r1, #4
|
||||
|
||||
LoopCopyDataInit:
|
||||
ldr r0, =_sdata
|
||||
ldr r3, =_edata
|
||||
adds r2, r0, r1
|
||||
cmp r2, r3
|
||||
bcc CopyDataInit
|
||||
ldr r2, =_sbss
|
||||
b LoopFillZerobss
|
||||
/* Zero fill the bss segment. */
|
||||
FillZerobss:
|
||||
movs r3, #0
|
||||
str r3, [r2], #4
|
||||
|
||||
LoopFillZerobss:
|
||||
ldr r3, = _ebss
|
||||
cmp r2, r3
|
||||
bcc FillZerobss
|
||||
|
||||
/* Call the clock system intitialization function.*/
|
||||
bl SystemInit
|
||||
/* Call static constructors */
|
||||
//bl __libc_init_array
|
||||
/* Call the application's entry point.*/
|
||||
|
||||
bl main
|
||||
bx lr
|
||||
.size Reset_Handler, .-Reset_Handler
|
||||
|
||||
/**
|
||||
* @brief This is the code that gets called when the processor receives an
|
||||
* unexpected interrupt. This simply enters an infinite loop, preserving
|
||||
* the system state for examination by a debugger.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.section .text.Default_Handler,"ax",%progbits
|
||||
Default_Handler:
|
||||
Infinite_Loop:
|
||||
b Infinite_Loop
|
||||
.size Default_Handler, .-Default_Handler
|
||||
/******************************************************************************
|
||||
*
|
||||
* The minimal vector table for a Cortex M3. Note that the proper constructs
|
||||
* must be placed on this to ensure that it ends up at physical address
|
||||
* 0x0000.0000.
|
||||
*
|
||||
*******************************************************************************/
|
||||
.section .isr_vector,"a",%progbits
|
||||
.type g_pfnVectors, %object
|
||||
.size g_pfnVectors, .-g_pfnVectors
|
||||
|
||||
|
||||
g_pfnVectors:
|
||||
.word _estack
|
||||
.word Reset_Handler
|
||||
.word NMI_Handler
|
||||
.word HardFault_Handler
|
||||
.word MemManage_Handler
|
||||
.word BusFault_Handler
|
||||
.word UsageFault_Handler
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word SVC_Handler
|
||||
.word DebugMon_Handler
|
||||
.word 0
|
||||
.word PendSV_Handler
|
||||
.word SysTick_Handler
|
||||
|
||||
/* External Interrupts */
|
||||
.word WWDG_IRQHandler /* Window WatchDog */
|
||||
.word PVD_IRQHandler /* PVD through EXTI Line detection */
|
||||
.word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
|
||||
.word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
|
||||
.word FLASH_IRQHandler /* FLASH */
|
||||
.word RCC_IRQHandler /* RCC */
|
||||
.word EXTI0_IRQHandler /* EXTI Line0 */
|
||||
.word EXTI1_IRQHandler /* EXTI Line1 */
|
||||
.word EXTI2_IRQHandler /* EXTI Line2 */
|
||||
.word EXTI3_IRQHandler /* EXTI Line3 */
|
||||
.word EXTI4_IRQHandler /* EXTI Line4 */
|
||||
.word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
|
||||
.word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */
|
||||
.word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */
|
||||
.word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */
|
||||
.word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */
|
||||
.word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */
|
||||
.word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */
|
||||
.word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */
|
||||
.word CAN1_TX_IRQHandler /* CAN1 TX */
|
||||
.word CAN1_RX0_IRQHandler /* CAN1 RX0 */
|
||||
.word CAN1_RX1_IRQHandler /* CAN1 RX1 */
|
||||
.word CAN1_SCE_IRQHandler /* CAN1 SCE */
|
||||
.word EXTI9_5_IRQHandler /* External Line[9:5]s */
|
||||
.word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */
|
||||
.word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */
|
||||
.word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */
|
||||
.word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
|
||||
.word TIM2_IRQHandler /* TIM2 */
|
||||
.word TIM3_IRQHandler /* TIM3 */
|
||||
.word TIM4_IRQHandler /* TIM4 */
|
||||
.word I2C1_EV_IRQHandler /* I2C1 Event */
|
||||
.word I2C1_ER_IRQHandler /* I2C1 Error */
|
||||
.word I2C2_EV_IRQHandler /* I2C2 Event */
|
||||
.word I2C2_ER_IRQHandler /* I2C2 Error */
|
||||
.word SPI1_IRQHandler /* SPI1 */
|
||||
.word SPI2_IRQHandler /* SPI2 */
|
||||
.word USART1_IRQHandler /* USART1 */
|
||||
.word USART2_IRQHandler /* USART2 */
|
||||
.word USART3_IRQHandler /* USART3 */
|
||||
.word EXTI15_10_IRQHandler /* External Line[15:10]s */
|
||||
.word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
|
||||
.word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */
|
||||
.word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */
|
||||
.word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */
|
||||
.word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */
|
||||
.word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
|
||||
.word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */
|
||||
.word FSMC_IRQHandler /* FSMC */
|
||||
.word SDIO_IRQHandler /* SDIO */
|
||||
.word TIM5_IRQHandler /* TIM5 */
|
||||
.word SPI3_IRQHandler /* SPI3 */
|
||||
.word UART4_IRQHandler /* UART4 */
|
||||
.word UART5_IRQHandler /* UART5 */
|
||||
.word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
|
||||
.word TIM7_IRQHandler /* TIM7 */
|
||||
.word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */
|
||||
.word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */
|
||||
.word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */
|
||||
.word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */
|
||||
.word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */
|
||||
.word ETH_IRQHandler /* Ethernet */
|
||||
.word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */
|
||||
.word CAN2_TX_IRQHandler /* CAN2 TX */
|
||||
.word CAN2_RX0_IRQHandler /* CAN2 RX0 */
|
||||
.word CAN2_RX1_IRQHandler /* CAN2 RX1 */
|
||||
.word CAN2_SCE_IRQHandler /* CAN2 SCE */
|
||||
.word OTG_FS_IRQHandler /* USB OTG FS */
|
||||
.word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */
|
||||
.word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */
|
||||
.word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */
|
||||
.word USART6_IRQHandler /* USART6 */
|
||||
.word I2C3_EV_IRQHandler /* I2C3 event */
|
||||
.word I2C3_ER_IRQHandler /* I2C3 error */
|
||||
.word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */
|
||||
.word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */
|
||||
.word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */
|
||||
.word OTG_HS_IRQHandler /* USB OTG HS */
|
||||
.word DCMI_IRQHandler /* DCMI */
|
||||
.word CRYP_IRQHandler /* CRYP crypto */
|
||||
.word HASH_RNG_IRQHandler /* Hash and Rng */
|
||||
.word FPU_IRQHandler /* FPU */
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Provide weak aliases for each Exception handler to the Default_Handler.
|
||||
* As they are weak aliases, any function with the same name will override
|
||||
* this definition.
|
||||
*
|
||||
*******************************************************************************/
|
||||
.weak NMI_Handler
|
||||
.thumb_set NMI_Handler,Default_Handler
|
||||
|
||||
.weak HardFault_Handler
|
||||
.thumb_set HardFault_Handler,Default_Handler
|
||||
|
||||
.weak MemManage_Handler
|
||||
.thumb_set MemManage_Handler,Default_Handler
|
||||
|
||||
.weak BusFault_Handler
|
||||
.thumb_set BusFault_Handler,Default_Handler
|
||||
|
||||
.weak UsageFault_Handler
|
||||
.thumb_set UsageFault_Handler,Default_Handler
|
||||
|
||||
.weak SVC_Handler
|
||||
.thumb_set SVC_Handler,Default_Handler
|
||||
|
||||
.weak DebugMon_Handler
|
||||
.thumb_set DebugMon_Handler,Default_Handler
|
||||
|
||||
.weak PendSV_Handler
|
||||
.thumb_set PendSV_Handler,Default_Handler
|
||||
|
||||
.weak SysTick_Handler
|
||||
.thumb_set SysTick_Handler,Default_Handler
|
||||
|
||||
.weak WWDG_IRQHandler
|
||||
.thumb_set WWDG_IRQHandler,Default_Handler
|
||||
|
||||
.weak PVD_IRQHandler
|
||||
.thumb_set PVD_IRQHandler,Default_Handler
|
||||
|
||||
.weak TAMP_STAMP_IRQHandler
|
||||
.thumb_set TAMP_STAMP_IRQHandler,Default_Handler
|
||||
|
||||
.weak RTC_WKUP_IRQHandler
|
||||
.thumb_set RTC_WKUP_IRQHandler,Default_Handler
|
||||
|
||||
.weak FLASH_IRQHandler
|
||||
.thumb_set FLASH_IRQHandler,Default_Handler
|
||||
|
||||
.weak RCC_IRQHandler
|
||||
.thumb_set RCC_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI0_IRQHandler
|
||||
.thumb_set EXTI0_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI1_IRQHandler
|
||||
.thumb_set EXTI1_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI2_IRQHandler
|
||||
.thumb_set EXTI2_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI3_IRQHandler
|
||||
.thumb_set EXTI3_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI4_IRQHandler
|
||||
.thumb_set EXTI4_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream0_IRQHandler
|
||||
.thumb_set DMA1_Stream0_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream1_IRQHandler
|
||||
.thumb_set DMA1_Stream1_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream2_IRQHandler
|
||||
.thumb_set DMA1_Stream2_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream3_IRQHandler
|
||||
.thumb_set DMA1_Stream3_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream4_IRQHandler
|
||||
.thumb_set DMA1_Stream4_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream5_IRQHandler
|
||||
.thumb_set DMA1_Stream5_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream6_IRQHandler
|
||||
.thumb_set DMA1_Stream6_IRQHandler,Default_Handler
|
||||
|
||||
.weak ADC_IRQHandler
|
||||
.thumb_set ADC_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN1_TX_IRQHandler
|
||||
.thumb_set CAN1_TX_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN1_RX0_IRQHandler
|
||||
.thumb_set CAN1_RX0_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN1_RX1_IRQHandler
|
||||
.thumb_set CAN1_RX1_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN1_SCE_IRQHandler
|
||||
.thumb_set CAN1_SCE_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI9_5_IRQHandler
|
||||
.thumb_set EXTI9_5_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM1_BRK_TIM9_IRQHandler
|
||||
.thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM1_UP_TIM10_IRQHandler
|
||||
.thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM1_TRG_COM_TIM11_IRQHandler
|
||||
.thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM1_CC_IRQHandler
|
||||
.thumb_set TIM1_CC_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM2_IRQHandler
|
||||
.thumb_set TIM2_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM3_IRQHandler
|
||||
.thumb_set TIM3_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM4_IRQHandler
|
||||
.thumb_set TIM4_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C1_EV_IRQHandler
|
||||
.thumb_set I2C1_EV_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C1_ER_IRQHandler
|
||||
.thumb_set I2C1_ER_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C2_EV_IRQHandler
|
||||
.thumb_set I2C2_EV_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C2_ER_IRQHandler
|
||||
.thumb_set I2C2_ER_IRQHandler,Default_Handler
|
||||
|
||||
.weak SPI1_IRQHandler
|
||||
.thumb_set SPI1_IRQHandler,Default_Handler
|
||||
|
||||
.weak SPI2_IRQHandler
|
||||
.thumb_set SPI2_IRQHandler,Default_Handler
|
||||
|
||||
.weak USART1_IRQHandler
|
||||
.thumb_set USART1_IRQHandler,Default_Handler
|
||||
|
||||
.weak USART2_IRQHandler
|
||||
.thumb_set USART2_IRQHandler,Default_Handler
|
||||
|
||||
.weak USART3_IRQHandler
|
||||
.thumb_set USART3_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI15_10_IRQHandler
|
||||
.thumb_set EXTI15_10_IRQHandler,Default_Handler
|
||||
|
||||
.weak RTC_Alarm_IRQHandler
|
||||
.thumb_set RTC_Alarm_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_FS_WKUP_IRQHandler
|
||||
.thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM8_BRK_TIM12_IRQHandler
|
||||
.thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM8_UP_TIM13_IRQHandler
|
||||
.thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM8_TRG_COM_TIM14_IRQHandler
|
||||
.thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM8_CC_IRQHandler
|
||||
.thumb_set TIM8_CC_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream7_IRQHandler
|
||||
.thumb_set DMA1_Stream7_IRQHandler,Default_Handler
|
||||
|
||||
.weak FSMC_IRQHandler
|
||||
.thumb_set FSMC_IRQHandler,Default_Handler
|
||||
|
||||
.weak SDIO_IRQHandler
|
||||
.thumb_set SDIO_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM5_IRQHandler
|
||||
.thumb_set TIM5_IRQHandler,Default_Handler
|
||||
|
||||
.weak SPI3_IRQHandler
|
||||
.thumb_set SPI3_IRQHandler,Default_Handler
|
||||
|
||||
.weak UART4_IRQHandler
|
||||
.thumb_set UART4_IRQHandler,Default_Handler
|
||||
|
||||
.weak UART5_IRQHandler
|
||||
.thumb_set UART5_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM6_DAC_IRQHandler
|
||||
.thumb_set TIM6_DAC_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM7_IRQHandler
|
||||
.thumb_set TIM7_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream0_IRQHandler
|
||||
.thumb_set DMA2_Stream0_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream1_IRQHandler
|
||||
.thumb_set DMA2_Stream1_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream2_IRQHandler
|
||||
.thumb_set DMA2_Stream2_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream3_IRQHandler
|
||||
.thumb_set DMA2_Stream3_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream4_IRQHandler
|
||||
.thumb_set DMA2_Stream4_IRQHandler,Default_Handler
|
||||
|
||||
.weak ETH_IRQHandler
|
||||
.thumb_set ETH_IRQHandler,Default_Handler
|
||||
|
||||
.weak ETH_WKUP_IRQHandler
|
||||
.thumb_set ETH_WKUP_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN2_TX_IRQHandler
|
||||
.thumb_set CAN2_TX_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN2_RX0_IRQHandler
|
||||
.thumb_set CAN2_RX0_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN2_RX1_IRQHandler
|
||||
.thumb_set CAN2_RX1_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN2_SCE_IRQHandler
|
||||
.thumb_set CAN2_SCE_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_FS_IRQHandler
|
||||
.thumb_set OTG_FS_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream5_IRQHandler
|
||||
.thumb_set DMA2_Stream5_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream6_IRQHandler
|
||||
.thumb_set DMA2_Stream6_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream7_IRQHandler
|
||||
.thumb_set DMA2_Stream7_IRQHandler,Default_Handler
|
||||
|
||||
.weak USART6_IRQHandler
|
||||
.thumb_set USART6_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C3_EV_IRQHandler
|
||||
.thumb_set I2C3_EV_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C3_ER_IRQHandler
|
||||
.thumb_set I2C3_ER_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_HS_EP1_OUT_IRQHandler
|
||||
.thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_HS_EP1_IN_IRQHandler
|
||||
.thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_HS_WKUP_IRQHandler
|
||||
.thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_HS_IRQHandler
|
||||
.thumb_set OTG_HS_IRQHandler,Default_Handler
|
||||
|
||||
.weak DCMI_IRQHandler
|
||||
.thumb_set DCMI_IRQHandler,Default_Handler
|
||||
|
||||
.weak CRYP_IRQHandler
|
||||
.thumb_set CRYP_IRQHandler,Default_Handler
|
||||
|
||||
.weak HASH_RNG_IRQHandler
|
||||
.thumb_set HASH_RNG_IRQHandler,Default_Handler
|
||||
|
||||
.weak FPU_IRQHandler
|
||||
.thumb_set FPU_IRQHandler,Default_Handler
|
||||
|
||||
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
||||
329
stm-firmware/calibration.c
Normal file
329
stm-firmware/calibration.c
Normal file
@@ -0,0 +1,329 @@
|
||||
/* Reflow Oven Controller
|
||||
*
|
||||
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
||||
*
|
||||
* This file is part of the Reflow Oven Controller Project.
|
||||
*
|
||||
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* The Reflow Oven Control Firmware 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 the reflow oven controller project.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <reflow-controller/calibration.h>
|
||||
#include <reflow-controller/adc-meas.h>
|
||||
#include <stm-periph/uart.h>
|
||||
#include <helper-macros/helper-macros.h>
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
#include <reflow-controller/safety/safety-controller.h>
|
||||
|
||||
enum calibration_shell_state {CAL_START = 0, CAL_WAIT_RES1, CAL_MEAS_RES1, CAL_WAIT_RES2, CAL_MEAS_RES2};
|
||||
|
||||
void calibration_calculate(float low_measured, float low_setpoint, float high_measured, float high_setpoint,
|
||||
float *sens_deviation, float *offset)
|
||||
{
|
||||
if (!sens_deviation || !offset)
|
||||
return;
|
||||
|
||||
float delta_y;
|
||||
float delta_x;
|
||||
float sens_corr_mult;
|
||||
|
||||
delta_y = high_measured - low_measured;
|
||||
delta_x = high_setpoint - low_setpoint;
|
||||
|
||||
sens_corr_mult = delta_x / delta_y;
|
||||
*sens_deviation = sens_corr_mult - 1.0f;
|
||||
|
||||
*offset = (high_setpoint * low_measured - low_setpoint * high_measured) / (high_setpoint - low_setpoint);
|
||||
}
|
||||
|
||||
float *calibration_acquire_data_start(uint32_t count, volatile int *flag)
|
||||
{
|
||||
int status;
|
||||
float *stream_mem;
|
||||
|
||||
if (!count)
|
||||
return NULL;
|
||||
|
||||
stream_mem = (float *)calloc(count, sizeof(float));
|
||||
if (!stream_mem)
|
||||
return stream_mem;
|
||||
|
||||
*flag = 0;
|
||||
status = adc_pt1000_stream_raw_value_to_memory(stream_mem, count, flag);
|
||||
if (status)
|
||||
goto free_mem;
|
||||
|
||||
|
||||
return stream_mem;
|
||||
free_mem:
|
||||
free(stream_mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static float calculate_mean(float *values, uint32_t count)
|
||||
{
|
||||
uint32_t loop_cnt = (count + 7) / 8;
|
||||
uint32_t remainder = count % 8;
|
||||
float sum = 0;
|
||||
|
||||
switch (remainder) {
|
||||
case 0: do { sum += *values++; /* FALLTHRU */
|
||||
case 7: sum += *values++; /* FALLTHRU */
|
||||
case 6: sum += *values++; /* FALLTHRU */
|
||||
case 5: sum += *values++; /* FALLTHRU */
|
||||
case 4: sum += *values++; /* FALLTHRU */
|
||||
case 3: sum += *values++; /* FALLTHRU */
|
||||
case 2: sum += *values++; /* FALLTHRU */
|
||||
case 1: sum += *values++;
|
||||
} while (--loop_cnt > 0);
|
||||
}
|
||||
|
||||
return sum / (float)count;
|
||||
}
|
||||
|
||||
static float calculate_standard_deviation(float *values, uint32_t count, float mean)
|
||||
{
|
||||
uint32_t loop_cnt = (count + 7) / 8;
|
||||
uint32_t remainder = count % 8;
|
||||
float sum = 0;
|
||||
float res;
|
||||
|
||||
switch (remainder) {
|
||||
case 0: do {
|
||||
sum += (*values - mean) * (*values - mean);
|
||||
values++;
|
||||
/* FALLTHRU */
|
||||
case 7: sum += (*values - mean) * (*values - mean);
|
||||
values++;
|
||||
/* FALLTHRU */
|
||||
case 6: sum += (*values - mean) * (*values - mean);
|
||||
values++;
|
||||
/* FALLTHRU */
|
||||
case 5: sum += (*values - mean) * (*values - mean);
|
||||
values++;
|
||||
/* FALLTHRU */
|
||||
case 4: sum += (*values - mean) * (*values - mean);
|
||||
values++;
|
||||
/* FALLTHRU */
|
||||
case 3: sum += (*values - mean) * (*values - mean);
|
||||
values++;
|
||||
/* FALLTHRU */
|
||||
case 2: sum += (*values - mean) * (*values - mean);
|
||||
values++;
|
||||
/* FALLTHRU */
|
||||
case 1: sum += (*values - mean) * (*values - mean);
|
||||
values++;
|
||||
/* FALLTHRU */
|
||||
} while (--loop_cnt > 0);
|
||||
}
|
||||
|
||||
sum /= (float)count;
|
||||
/* Compute the square root using the FPU.
|
||||
* The constraint 't' tells GCC to use a floating point register
|
||||
*/
|
||||
__asm__ __volatile__("vsqrt.f32 %0, %1" : "=t"(res) : "t"(sum));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int calibration_poll_data_acquisition(float *mem_array, uint32_t count, volatile int *flag, float *mu, float *std_dev)
|
||||
{
|
||||
int ret_val = 0;
|
||||
|
||||
if (!flag || !mem_array || !mu || !std_dev)
|
||||
return -1000;
|
||||
|
||||
if (*flag == 0) {
|
||||
/* Continue polling */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (*flag != 1) {
|
||||
/* Error */
|
||||
ret_val = -1;
|
||||
goto ret_free_mem;
|
||||
}
|
||||
|
||||
/* Convert the stream memory to Ohm readings */
|
||||
adc_pt1000_convert_raw_value_array_to_resistance(NULL, mem_array, count);
|
||||
|
||||
/* Do not compute std-deviation. Too imprecise */
|
||||
*mu = calculate_mean(mem_array, count);
|
||||
*std_dev = calculate_standard_deviation(mem_array, count, *mu);
|
||||
|
||||
ret_free_mem:
|
||||
free(mem_array);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
shellmatta_retCode_t calibration_sequence_shell_cmd(shellmatta_handle_t shell, const char *arg, uint32_t len)
|
||||
{
|
||||
(void)arg;
|
||||
(void)len;
|
||||
bool error_occured;
|
||||
const enum safety_flag meas_adc_err_mask = ERR_FLAG_MEAS_ADC_OFF | ERR_FLAG_MEAS_ADC_WATCHDOG;
|
||||
|
||||
/* This stores the current state of the calibration process */
|
||||
static enum calibration_shell_state cal_state = CAL_START;
|
||||
shellmatta_retCode_t ret_val = SHELLMATTA_BUSY;
|
||||
uint32_t i;
|
||||
int res;
|
||||
|
||||
static float mu = 0.0f, mu2 = 0.0f, dev = 0.0f, dev2 = 0.0f;
|
||||
float sens_dev, offset;
|
||||
static float *data_buffer = NULL;
|
||||
static volatile int flag;
|
||||
char *stdin_data;
|
||||
uint32_t stdin_len;
|
||||
bool cal_active;
|
||||
|
||||
switch (cal_state) {
|
||||
case CAL_START:
|
||||
/* Clear errors of PT1000 reading */
|
||||
safety_controller_ack_flag(ERR_FLAG_MEAS_ADC_WATCHDOG);
|
||||
safety_controller_ack_flag(ERR_FLAG_OVERTEMP);
|
||||
adc_pt1000_get_resistance_calibration(&offset, &sens_dev, &cal_active);
|
||||
if (cal_active) {
|
||||
shellmatta_printf(shell, "Already calibrated.\r\n\tOffset: %f\r\n\tSens: %f\r\n", offset, sens_dev);
|
||||
shellmatta_printf(shell, "Press CTRL-C to abort new calibration.\r\n");
|
||||
}
|
||||
shellmatta_printf(shell, "Starting calibration: Insert 1000 Ohm calibration resistor and press ENTER\r\n");
|
||||
cal_state = CAL_WAIT_RES1;
|
||||
ret_val = SHELLMATTA_CONTINUE;
|
||||
break;
|
||||
case CAL_WAIT_RES1:
|
||||
cal_state = CAL_WAIT_RES1;
|
||||
ret_val = SHELLMATTA_CONTINUE;
|
||||
shellmatta_read(shell, &stdin_data, &stdin_len);
|
||||
if (stdin_len > 0) {
|
||||
for (i = 0; i < stdin_len; i++) {
|
||||
if (stdin_data[i] == '\r') {
|
||||
cal_state = CAL_MEAS_RES1;
|
||||
ret_val = SHELLMATTA_BUSY;
|
||||
shellmatta_printf(shell, "Measurement...\r\n");
|
||||
safety_controller_ack_flag(ERR_FLAG_MEAS_ADC_WATCHDOG);
|
||||
safety_controller_ack_flag(ERR_FLAG_OVERTEMP);
|
||||
data_buffer = calibration_acquire_data_start(512UL, &flag);
|
||||
break;
|
||||
} else if (stdin_data[i] == '\x03') {
|
||||
cal_state = CAL_START;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case CAL_MEAS_RES1:
|
||||
if (!data_buffer) {
|
||||
shellmatta_printf(shell, "Data acquisition failed!\r\n");
|
||||
ret_val = SHELLMATTA_OK;
|
||||
cal_state = CAL_START;
|
||||
break;
|
||||
}
|
||||
|
||||
res = calibration_poll_data_acquisition(data_buffer, 512UL, &flag, &mu, &dev);
|
||||
/* Stay in this state until the measurements are finished */
|
||||
if (res == 1) {
|
||||
ret_val = SHELLMATTA_BUSY;
|
||||
cal_state = CAL_MEAS_RES1;
|
||||
} else if (res == 0) {
|
||||
shellmatta_printf(shell, "R=%.2f, Std-Dev: %.2f\r\n", mu, dev);
|
||||
error_occured = safety_controller_get_flags_by_mask(meas_adc_err_mask);
|
||||
if (error_occured) {
|
||||
shellmatta_printf(shell, "Error in resistance measurement");
|
||||
ret_val = SHELLMATTA_OK;
|
||||
cal_state = CAL_START;
|
||||
} else {
|
||||
ret_val = SHELLMATTA_CONTINUE;
|
||||
shellmatta_printf(shell, "Insert 2000 Ohm calibration resistor and press ENTER\r\n");
|
||||
cal_state = CAL_WAIT_RES2;
|
||||
}
|
||||
} else {
|
||||
shellmatta_printf(shell, "Error in resistance measurement");
|
||||
ret_val = SHELLMATTA_OK;
|
||||
cal_state = CAL_START;
|
||||
}
|
||||
break;
|
||||
case CAL_WAIT_RES2:
|
||||
cal_state = CAL_WAIT_RES2;
|
||||
ret_val = SHELLMATTA_CONTINUE;
|
||||
shellmatta_read(shell, &stdin_data, &stdin_len);
|
||||
if (stdin_len > 0) {
|
||||
for (i = 0; i < stdin_len; i++) {
|
||||
if (stdin_data[i] == '\r') {
|
||||
cal_state = CAL_MEAS_RES2;
|
||||
ret_val = SHELLMATTA_BUSY;
|
||||
shellmatta_printf(shell, "Measurement...\r\n");
|
||||
safety_controller_ack_flag(ERR_FLAG_MEAS_ADC_WATCHDOG);
|
||||
safety_controller_ack_flag(ERR_FLAG_OVERTEMP);
|
||||
data_buffer = calibration_acquire_data_start(512UL, &flag);
|
||||
break;
|
||||
} else if (stdin_data[i] == '\x03') {
|
||||
cal_state = CAL_START;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case CAL_MEAS_RES2:
|
||||
if (!data_buffer) {
|
||||
shellmatta_printf(shell, "Data acquisition failed!\r\n");
|
||||
ret_val = SHELLMATTA_OK;
|
||||
cal_state = CAL_START;
|
||||
break;
|
||||
}
|
||||
|
||||
res = calibration_poll_data_acquisition(data_buffer, 512UL, &flag, &mu2, &dev2);
|
||||
/* Stay in this state until the measurements are finished */
|
||||
if (res == 1) {
|
||||
ret_val = SHELLMATTA_BUSY;
|
||||
cal_state = CAL_MEAS_RES2;
|
||||
} else if (res == 0) {
|
||||
shellmatta_printf(shell, "R=%.2f, Std-Dev: %.2f\r\n", mu2, dev2);
|
||||
error_occured = safety_controller_get_flags_by_mask(meas_adc_err_mask);
|
||||
if (error_occured) {
|
||||
shellmatta_printf(shell, "Error in resistance measurement");
|
||||
ret_val = SHELLMATTA_OK;
|
||||
cal_state = CAL_START;
|
||||
} else {
|
||||
ret_val = SHELLMATTA_OK;
|
||||
cal_state = CAL_START;
|
||||
|
||||
if (dev > CALIBRATION_MAX_NOISE_OHM ||
|
||||
dev2 > CALIBRATION_MAX_NOISE_OHM) {
|
||||
shellmatta_printf(shell, "Calibration failed! Too much noise. Check your hardware.\r\n");
|
||||
break;
|
||||
}
|
||||
shellmatta_printf(shell, "Calibartion finished successfully!\r\n");
|
||||
/* Calculate calibration */
|
||||
calibration_calculate(mu, 1000.0f, mu2, 2000.0f, &sens_dev, &offset);
|
||||
|
||||
shellmatta_printf(shell, "\r\n\tSENS_DEVIATION: %.4f\r\n\tOFFSET_CORR: %.2f\r\n", sens_dev, offset);
|
||||
adc_pt1000_set_resistance_calibration(offset, sens_dev, true);
|
||||
}
|
||||
} else {
|
||||
shellmatta_printf(shell, "Error in resistance measurement");
|
||||
ret_val = SHELLMATTA_OK;
|
||||
cal_state = CAL_START;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
shellmatta_printf(shell, "Undefined state reached in calibration. Aborting\r\n");
|
||||
cal_state = CAL_START;
|
||||
ret_val = SHELLMATTA_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
202
stm-firmware/config-parser/config-parser.c
Normal file
202
stm-firmware/config-parser/config-parser.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/* Reflow Oven Controller
|
||||
*
|
||||
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
||||
*
|
||||
* This file is part of the Reflow Oven Controller Project.
|
||||
*
|
||||
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* The Reflow Oven Control Firmware 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 the reflow oven controller project.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup config-parser
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <config-parser/config-parser.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define CONFIG_PARSER_MAGIC 0x464a6e2bUL
|
||||
#define CONFIG_PARSER(p) ((struct config_parser *)(p))
|
||||
|
||||
#define config_parser_check_handle(handle) do { if (!(handle) || \
|
||||
((struct config_parser *)(handle))->magic != CONFIG_PARSER_MAGIC) \
|
||||
return CONFIG_PARSER_PARAM_ERR; \
|
||||
} while (0)
|
||||
|
||||
config_parser_handle_t config_parser_open_file(struct config_parser *config_parser, bool write, const char *file_name,
|
||||
char *working_buffer, size_t buff_size)
|
||||
{
|
||||
FRESULT res;
|
||||
|
||||
if (!config_parser || !file_name || !working_buffer)
|
||||
return NULL;
|
||||
|
||||
config_parser->magic = CONFIG_PARSER_MAGIC;
|
||||
config_parser->write = write;
|
||||
config_parser->buffer = working_buffer;
|
||||
config_parser->buff_size = buff_size;
|
||||
|
||||
res = f_open(&config_parser->file, file_name, (write ? FA_CREATE_ALWAYS | FA_WRITE : FA_READ));
|
||||
if (res != FR_OK)
|
||||
return NULL;
|
||||
|
||||
return (config_parser_handle_t)config_parser;
|
||||
}
|
||||
|
||||
static const char * const token_delim = " \t";
|
||||
|
||||
static int parse_value(struct config_parser_entry *entry, char *value_start_token)
|
||||
{
|
||||
char *dot;
|
||||
char *endptr;
|
||||
|
||||
/* Check if token is a float number */
|
||||
dot = strstr(value_start_token, ".");
|
||||
if (dot) {
|
||||
/* Try parsing as float */
|
||||
entry->value.float_val = strtof(value_start_token, &endptr);
|
||||
if (endptr == value_start_token)
|
||||
return -1;
|
||||
entry->type = CONFIG_PARSER_TYPE_FLOAT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (value_start_token[0] != '-') {
|
||||
/* Try parsing as ul */
|
||||
/* Try parsing as int */
|
||||
entry->value.uint_val = strtoul(value_start_token, &endptr, 0);
|
||||
if (endptr == value_start_token) {
|
||||
return -1;
|
||||
}
|
||||
entry->type = CONFIG_PARSER_TYPE_UINT;
|
||||
goto exit;
|
||||
} else {
|
||||
/* Try parsing as int */
|
||||
entry->value.int_val = strtod(value_start_token, &endptr);
|
||||
if (endptr == value_start_token) {
|
||||
return -1;
|
||||
}
|
||||
entry->type = CONFIG_PARSER_TYPE_INT;
|
||||
}
|
||||
|
||||
exit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, struct config_parser_entry *entry, bool force_float)
|
||||
{
|
||||
struct config_parser *p;
|
||||
config_parser_check_handle(handle);
|
||||
p = CONFIG_PARSER(handle);
|
||||
char *token;
|
||||
int token_round = 0;
|
||||
|
||||
if (!entry)
|
||||
return CONFIG_PARSER_PARAM_ERR;
|
||||
|
||||
p->buffer[0] = '\0';
|
||||
if (f_gets(p->buffer, (int)p->buff_size, &p->file) == NULL)
|
||||
return CONFIG_PARSER_IOERR;
|
||||
|
||||
token = strtok(p->buffer, token_delim);
|
||||
while (token != NULL) {
|
||||
/* Check for comment */
|
||||
if (token[0] == '#') {
|
||||
if (token_round == 0)
|
||||
return CONFIG_PARSER_LINE_COMMENT;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
switch (token_round) {
|
||||
case 0: /* KEY */
|
||||
entry->name = token;
|
||||
break;
|
||||
case 1: /* = Symbol */
|
||||
if (strcmp(token, "=")) {
|
||||
return CONFIG_PARSER_LINE_MALFORM;
|
||||
}
|
||||
break;
|
||||
case 2: /* VALUE */
|
||||
if (parse_value(entry, token))
|
||||
return CONFIG_PARSER_LINE_MALFORM;
|
||||
break;
|
||||
default:
|
||||
return CONFIG_PARSER_LINE_MALFORM;
|
||||
}
|
||||
|
||||
token_round++;
|
||||
token = strtok(NULL, token_delim);
|
||||
}
|
||||
|
||||
if (force_float) {
|
||||
if (entry->type == CONFIG_PARSER_TYPE_INT)
|
||||
entry->value.float_val = (float)entry->value.int_val;
|
||||
if (entry->type == CONFIG_PARSER_TYPE_UINT)
|
||||
entry->value.float_val = (float)entry->value.uint_val;
|
||||
|
||||
entry->type = CONFIG_PARSER_TYPE_FLOAT;
|
||||
}
|
||||
|
||||
return CONFIG_PARSER_OK;
|
||||
}
|
||||
|
||||
enum config_parser_ret config_parser_reset_to_start(config_parser_handle_t handle)
|
||||
{
|
||||
FRESULT res;
|
||||
struct config_parser *p;
|
||||
config_parser_check_handle(handle);
|
||||
p = CONFIG_PARSER(handle);
|
||||
|
||||
res = f_rewind(&p->file);
|
||||
if (res != FR_OK)
|
||||
return CONFIG_PARSER_IOERR;
|
||||
|
||||
return CONFIG_PARSER_OK;
|
||||
}
|
||||
|
||||
enum config_parser_ret config_parser_write_entry(config_parser_handle_t handle, const struct config_parser_entry *entry)
|
||||
{
|
||||
(void)entry;
|
||||
config_parser_check_handle(handle);
|
||||
|
||||
return CONFIG_PARSER_OK;
|
||||
}
|
||||
|
||||
enum config_parser_ret config_parser_close_file(config_parser_handle_t handle)
|
||||
{
|
||||
struct config_parser *p;
|
||||
FRESULT res;
|
||||
config_parser_check_handle(handle);
|
||||
p = CONFIG_PARSER(handle);
|
||||
|
||||
res = f_close(&p->file);
|
||||
|
||||
return (res == FR_OK ? CONFIG_PARSER_OK : CONFIG_PARSER_IOERR);
|
||||
}
|
||||
|
||||
bool config_parser_ret_is_abort_condition(enum config_parser_ret return_val)
|
||||
{
|
||||
if (return_val == CONFIG_PARSER_END_REACHED ||
|
||||
return_val == CONFIG_PARSER_GENERIC_ERR ||
|
||||
return_val == CONFIG_PARSER_IOERR ||
|
||||
return_val == CONFIG_PARSER_PARAM_ERR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,97 @@
|
||||
/* Reflow Oven Controller
|
||||
*
|
||||
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
||||
*
|
||||
* This file is part of the Reflow Oven Controller Project.
|
||||
*
|
||||
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* The Reflow Oven Control Firmware 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 the reflow oven controller project.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file config-parser.h
|
||||
* @brief Header file for the key-value pair config parser
|
||||
* @addtogroup config-parser
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CONFIG_PARSER_H_
|
||||
#define _CONFIG_PARSER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <fatfs/ff.h>
|
||||
|
||||
struct config_parser {
|
||||
uint32_t magic;
|
||||
bool write;
|
||||
FIL file;
|
||||
char *buffer;
|
||||
size_t buff_size;
|
||||
};
|
||||
|
||||
typedef void * config_parser_handle_t;
|
||||
|
||||
enum config_parser_value_type {
|
||||
CONFIG_PARSER_TYPE_UINT = 0,
|
||||
CONFIG_PARSER_TYPE_INT,
|
||||
CONFIG_PARSER_TYPE_FLOAT,
|
||||
};
|
||||
|
||||
enum config_parser_ret {
|
||||
CONFIG_PARSER_OK = 0,
|
||||
CONFIG_PARSER_PARAM_ERR,
|
||||
CONFIG_PARSER_GENERIC_ERR,
|
||||
CONFIG_PARSER_IOERR,
|
||||
CONFIG_PARSER_LINE_COMMENT,
|
||||
CONFIG_PARSER_LINE_TOO_LONG,
|
||||
CONFIG_PARSER_LINE_MALFORM,
|
||||
CONFIG_PARSER_END_REACHED,
|
||||
CONFIG_PARSER_WRONG_MODE,
|
||||
};
|
||||
|
||||
struct config_parser_entry {
|
||||
const char *name;
|
||||
enum config_parser_value_type type;
|
||||
union {
|
||||
uint32_t uint_val;
|
||||
int32_t int_val;
|
||||
float float_val;
|
||||
} value;
|
||||
};
|
||||
|
||||
config_parser_handle_t config_parser_open_file(struct config_parser *config_parser, bool write, const char *file_name,
|
||||
char *working_buffer, size_t buff_size);
|
||||
|
||||
/**
|
||||
* @brief Parse the current line in the config file.
|
||||
* @param handle Config parser handle
|
||||
* @param[out] entry Entry read from config file.
|
||||
* @warning \p entry is only valid as long as no other function was called on the same \p handle. If necessary, the values
|
||||
* have to be copied
|
||||
* @return Config parser error
|
||||
*/
|
||||
enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, struct config_parser_entry *entry, bool force_float);
|
||||
|
||||
enum config_parser_ret config_parser_reset_to_start(config_parser_handle_t handle);
|
||||
|
||||
enum config_parser_ret config_parser_write_entry(config_parser_handle_t handle, const struct config_parser_entry *entry);
|
||||
|
||||
enum config_parser_ret config_parser_close_file(config_parser_handle_t handle);
|
||||
|
||||
bool config_parser_ret_is_abort_condition(enum config_parser_ret return_val);
|
||||
|
||||
#endif /* _CONFIG_PARSER_H_ */
|
||||
|
||||
/** @} */
|
||||
113
stm-firmware/crc-patcher/crc-patch-elf.py
Executable file
113
stm-firmware/crc-patcher/crc-patch-elf.py
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/bin/python
|
||||
|
||||
"""
|
||||
This script patches the CRC checksums into an existing ELF file.
|
||||
|
||||
For this, it searches the follwoing sections:
|
||||
1) .text
|
||||
2) .data
|
||||
3) .ccmdata
|
||||
4) .vectors
|
||||
|
||||
All sections MUST be a multiple of 4 bytes long because the CRC calculation relies on whole 32 bit words.
|
||||
The sections are excrated and the CRC is calculated for each section.
|
||||
|
||||
In the section .flashcrc, the script expects a single struct with the prototype:
|
||||
struct flash_crcs {
|
||||
uint32_t start_magic;
|
||||
uint32_t crc_section_text;
|
||||
uint32_t crc_section_data;
|
||||
uint32_t crc_section_ccm_data;
|
||||
uint32_t crc_section_vectors;
|
||||
uint32_t end_magic;
|
||||
};
|
||||
|
||||
It checks, if the start magic and end magic are set to the appropriate values and then patches in the CRC values of the sections.
|
||||
The magic values checked for are: 0xA8BE53F9 and 0xFFA582FF
|
||||
"""
|
||||
from elftools.elf.elffile import ELFFile
|
||||
from elftools.elf.segments import Segment
|
||||
import elftools.elf.constants as elf_const
|
||||
import sys
|
||||
import crcmod
|
||||
import crcmod.predefined
|
||||
import struct
|
||||
|
||||
crc_calc = crcmod.predefined.mkCrcFun('crc-32-mpeg')
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage:", sys.argv[0], ' <elf file>')
|
||||
sys.exit(-1)
|
||||
|
||||
filename=sys.argv[1]
|
||||
|
||||
def section_calculate_crc(section):
|
||||
data = bytearray(section.data())
|
||||
be_data = bytearray([0 for k in range(0, len(data))])
|
||||
# Rearrange data, because the STM controller sees it as 32 bit little endian words
|
||||
for i in range(0, int(len(data)/4)):
|
||||
be_data[i*4+0] = data[i*4+3]
|
||||
be_data[i*4+1] = data[i*4+2]
|
||||
be_data[i*4+2] = data[i*4+1]
|
||||
be_data[i*4+3] = data[i*4+0]
|
||||
|
||||
return crc_calc(be_data)
|
||||
|
||||
with open(filename, 'r+b') as f:
|
||||
elf = ELFFile(f)
|
||||
sections = {}
|
||||
sections['.text'] = elf.get_section_by_name('.text')
|
||||
sections['.data'] = elf.get_section_by_name('.data')
|
||||
sections['.ccmdata'] = elf.get_section_by_name('.ccmdata')
|
||||
sections['.vectors'] = elf.get_section_by_name('.vectors')
|
||||
|
||||
for key, sec in sections.items():
|
||||
if sec is None:
|
||||
print("Error! Section", key, "not found in ELF file!")
|
||||
sys.exit(-1)
|
||||
print('Found section', key, 'Size:',
|
||||
sec.data_size, 'Type:', sec['sh_type'])
|
||||
if sec['sh_type'] != 'SHT_PROGBITS':
|
||||
print('Error! Section must be of type SHT_PROGBITS')
|
||||
sys.exit(-1)
|
||||
if (sec.data_size % 4 != 0):
|
||||
print("Section", key, "has wrong size. Must be a multiple of 4 bytes!")
|
||||
sys.exit(-1)
|
||||
|
||||
text_crc = section_calculate_crc(sections['.text'])
|
||||
print('CRC of .text section:', hex(text_crc))
|
||||
data_crc = section_calculate_crc(sections['.data'])
|
||||
print('CRC of .data section:', hex(data_crc))
|
||||
ccmdata_crc = section_calculate_crc(sections['.ccmdata'])
|
||||
print('CRC of .ccmdata section:', hex(ccmdata_crc))
|
||||
vextors_crc = section_calculate_crc(sections['.vectors'])
|
||||
print('CRC of .vectors section:', hex(vextors_crc))
|
||||
|
||||
# Check the flashcrc section
|
||||
flashcrc_sec = elf.get_section_by_name('.flashcrc')
|
||||
if flashcrc_sec is None:
|
||||
print('Section for flash CRC missing!')
|
||||
sys.exit(-1)
|
||||
if flashcrc_sec.data_size != 6*4:
|
||||
print("Warning!!! .flashcrc section has wrong size:",flashcrc_sec.data_size)
|
||||
|
||||
crc_sec_data = bytearray(flashcrc_sec.data())
|
||||
magic1 = struct.unpack('<I'*1, bytes(crc_sec_data[0:4]))[0]
|
||||
magic2 = struct.unpack('<I'*1, bytes(crc_sec_data[-4:]))[0]
|
||||
print("CRC section magic values:", hex(magic1), hex(magic2))
|
||||
if magic1 != 0xA8BE53F9 or magic2 != 0xFFA582FF:
|
||||
print("Wrong magics in CRC section. Data misalignment?")
|
||||
sys.exit(-2)
|
||||
|
||||
crc_sec_offset = flashcrc_sec['sh_offset']
|
||||
print('CRC section ELF file offset:', hex(crc_sec_offset))
|
||||
|
||||
crc_sec_data[4:8] = struct.pack('<I',text_crc)
|
||||
crc_sec_data[8:12] = struct.pack('<I',data_crc)
|
||||
crc_sec_data[12:16] = struct.pack('<I',ccmdata_crc)
|
||||
crc_sec_data[16:20] = struct.pack('<I',vextors_crc)
|
||||
f.seek(crc_sec_offset)
|
||||
f.write(crc_sec_data)
|
||||
print('CRCs patched successfully')
|
||||
|
||||
|
||||
2
stm-firmware/crc-patcher/requirements.txt
Normal file
2
stm-firmware/crc-patcher/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
crcmod==1.7
|
||||
pyelftools==0.27
|
||||
65
stm-firmware/create-c-file-with-header.py
Executable file
65
stm-firmware/create-c-file-with-header.py
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import pathlib
|
||||
|
||||
license_header = """/* Reflow Oven Controller
|
||||
*
|
||||
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
||||
*
|
||||
* This file is part of the Reflow Oven Controller Project.
|
||||
*
|
||||
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* The Reflow Oven Control Firmware 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 the reflow oven controller project.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
"""
|
||||
|
||||
project_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
include_prefix = 'reflow-controller'
|
||||
module_include_dir = os.path.join(project_dir, os.path.join('include', include_prefix))
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print('Supply module name')
|
||||
sys.exit()
|
||||
|
||||
cpath = os.path.join(project_dir, sys.argv[1]+'.c')
|
||||
hfile = sys.argv[1]+'.h'
|
||||
hpath = os.path.join(module_include_dir, hfile)
|
||||
|
||||
h_define = '__'+hfile.replace('.', '_').replace('-', '_').replace('/', '_').upper()+'__'
|
||||
|
||||
if os.path.exists(cpath) or os.path.exists(hpath):
|
||||
print("File already exists! Abort!")
|
||||
sys.exit()
|
||||
|
||||
print('Creating C file: %s' % (cpath))
|
||||
cfile_folder = os.path.dirname(cpath)
|
||||
pathlib.Path(cfile_folder).mkdir(parents=True, exist_ok=True)
|
||||
with open(cpath, 'x') as f:
|
||||
f.write(license_header)
|
||||
f.write('\n')
|
||||
f.write('#include <%s>' % (os.path.join(include_prefix, hfile)))
|
||||
|
||||
print('Creating H file: %s' % (hpath))
|
||||
hfile_folder = os.path.dirname(hpath)
|
||||
pathlib.Path(hfile_folder).mkdir(parents=True, exist_ok=True)
|
||||
with open(hpath, 'x') as f:
|
||||
f.write(license_header)
|
||||
f.write('\n')
|
||||
f.write('#ifndef %s\n' % h_define)
|
||||
f.write('#define %s\n' % h_define)
|
||||
f.write('\n')
|
||||
f.write('#endif /* %s */\n' % h_define)
|
||||
|
||||
|
||||
74
stm-firmware/create-temp-lookup-table.py
Executable file
74
stm-firmware/create-temp-lookup-table.py
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import numpy as np
|
||||
|
||||
license_header = """/* Reflow Oven Controller
|
||||
*
|
||||
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
||||
*
|
||||
* This file is part of the Reflow Oven Controller Project.
|
||||
*
|
||||
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* The Reflow Oven Control Firmware 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 the reflow oven controller project.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
"""
|
||||
|
||||
hfile="temp-converter-data.h"
|
||||
|
||||
project_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
include_prefix = 'reflow-controller'
|
||||
module_include_dir = os.path.join(project_dir, os.path.join('include', include_prefix))
|
||||
include_file = os.path.join(module_include_dir, hfile)
|
||||
|
||||
h_define = '__'+hfile.replace('.', '_').replace('-', '_').upper()+'__'
|
||||
|
||||
min_res = 1000
|
||||
max_res = 2200
|
||||
res_step = 20
|
||||
|
||||
R_zero = 1000.0
|
||||
A = 3.9083E-3
|
||||
B = -5.7750E-7
|
||||
|
||||
def calc_temp(resistance):
|
||||
temp = (-R_zero * A + np.sqrt(R_zero*R_zero * A * A - 4* R_zero * B * (R_zero - resistance)))/(2*R_zero*B)
|
||||
return temp
|
||||
|
||||
if ((max_res-min_res) % res_step) != 0:
|
||||
print('Resistance range must be a multiple of res_step!')
|
||||
sys.exit(-1)
|
||||
|
||||
print('Calculating temperature table for %f Ohm to %f Ohm in %f Ohm steps' % (min_res, max_res, res_step))
|
||||
|
||||
temp_array = ''
|
||||
|
||||
for res in range(min_res, max_res+res_step, res_step):
|
||||
temp = calc_temp(res)
|
||||
temp_array = temp_array+ ',%.2ff' % temp
|
||||
|
||||
temp_array = temp_array[1:]
|
||||
|
||||
with open(include_file, 'x') as f:
|
||||
f.write(license_header)
|
||||
f.write('\n')
|
||||
f.write('#ifndef %s\n' % h_define)
|
||||
f.write('#define %s\n\n' % h_define)
|
||||
f.write('#define TEMP_CONVERSION_ARRAY_DATA %s\n' % temp_array)
|
||||
f.write('#define TEMP_CONVERSION_MIN_RES %d\n' % min_res)
|
||||
f.write('#define TEMP_CONVERSION_MAX_RES %d\n' % max_res)
|
||||
f.write('#define TEMP_CONVERSION_RES_STEP %d\n' % res_step)
|
||||
f.write('\n')
|
||||
f.write('#endif /* %s */\n' % h_define)
|
||||
@@ -1,12 +1,33 @@
|
||||
/* Reflow Oven Controller
|
||||
*
|
||||
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
||||
*
|
||||
* This file is part of the Reflow Oven Controller Project.
|
||||
*
|
||||
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* The Reflow Oven Control Firmware 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 the reflow oven controller project.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <reflow-controller/digio.h>
|
||||
#include <stm32/stm32f4xx.h>
|
||||
#include <stm-periph/clock-enable-manager.h>
|
||||
#include <stm-periph/rcc-manager.h>
|
||||
#include <stm-periph/stm32-gpio-macros.h>
|
||||
#include <helper-macros/helper-macros.h>
|
||||
|
||||
static const uint8_t digio_pins[] = {DIGIO_PINS};
|
||||
static const uint8_t digio_default_io[] = {DIGIO_INOUT_DEFAULT};
|
||||
static const uint8_t digio_default_altfunc[] = {DIGIO_ALTFUNC_DEFAULT};
|
||||
static uint16_t loudspeaker_val;
|
||||
|
||||
static void digio_setup_pin_int(uint8_t bit_no, uint8_t in_out, uint8_t alt_func)
|
||||
{
|
||||
@@ -26,7 +47,7 @@ static void digio_setup_pin_int(uint8_t bit_no, uint8_t in_out, uint8_t alt_func
|
||||
|
||||
}
|
||||
|
||||
void digio_setup_default_all()
|
||||
void digio_setup_default_all(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@@ -69,7 +90,7 @@ int digio_get(uint8_t num)
|
||||
|
||||
static const uint8_t led_pins[] = {LED_PINS};
|
||||
|
||||
void led_setup()
|
||||
void led_setup(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@@ -98,23 +119,75 @@ int led_get(uint8_t num)
|
||||
return ((LED_PORT->ODR & (1<<led_pins[num])) ? 1 : 0);
|
||||
}
|
||||
|
||||
void loudspeaker_setup()
|
||||
|
||||
static void loudspeaker_freq_timer_init(void)
|
||||
{
|
||||
#if LOUDSPEAKER_MULTIFREQ
|
||||
rcc_manager_enable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB1ENR_TIM7EN));
|
||||
TIM7->CR1 = 0UL;
|
||||
TIM7->CR2 = 0UL;
|
||||
TIM7->PSC = 1000;
|
||||
TIM7->DIER = TIM_DIER_UIE;
|
||||
NVIC_EnableIRQ(TIM7_IRQn);
|
||||
#endif
|
||||
}
|
||||
|
||||
void loudspeaker_setup(void)
|
||||
{
|
||||
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(LOUDSPEAKER_RCC_MASK));
|
||||
|
||||
LOUDSPEAKER_PORT->MODER &= MODER_DELETE(LOUDSPEAKER_PIN);
|
||||
LOUDSPEAKER_PORT->MODER |= OUTPUT(LOUDSPEAKER_PIN);
|
||||
|
||||
loudspeaker_set(0);
|
||||
loudspeaker_freq_timer_init();
|
||||
loudspeaker_set(0U);
|
||||
}
|
||||
void loudspeaker_set(int val)
|
||||
|
||||
static void loudspeaker_start_beep(uint16_t val)
|
||||
{
|
||||
if (val)
|
||||
LOUDSPEAKER_PORT->ODR |= (1<<LOUDSPEAKER_PIN);
|
||||
#if LOUDSPEAKER_MULTIFREQ
|
||||
TIM7->ARR = (val == 1 ? LOUDSPEAKER_MULTIFREQ_DEFAULT : val);
|
||||
TIM7->CNT = 0UL;
|
||||
TIM7->CR1 |= TIM_CR1_CEN;
|
||||
#else
|
||||
(void)val;
|
||||
LOUDSPEAKER_PORT->ODR |= (1<<LOUDSPEAKER_PIN);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void loudspeaker_stop_beep(void)
|
||||
{
|
||||
#if LOUDSPEAKER_MULTIFREQ
|
||||
TIM7->CR1 &= ~TIM_CR1_CEN;
|
||||
__DSB();
|
||||
TIM7->SR = 0UL;
|
||||
__DSB();
|
||||
LOUDSPEAKER_PORT->ODR &= ~(1<<LOUDSPEAKER_PIN);
|
||||
#else
|
||||
LOUDSPEAKER_PORT->ODR &= ~(1<<LOUDSPEAKER_PIN);
|
||||
#endif
|
||||
}
|
||||
|
||||
void loudspeaker_set(uint16_t val)
|
||||
{
|
||||
loudspeaker_val = val;
|
||||
|
||||
if (!val)
|
||||
loudspeaker_stop_beep();
|
||||
else
|
||||
LOUDSPEAKER_PORT->ODR &= ~(1<<LOUDSPEAKER_PIN);
|
||||
loudspeaker_start_beep(val);
|
||||
}
|
||||
int loudspeaker_get()
|
||||
|
||||
uint16_t loudspeaker_get(void)
|
||||
{
|
||||
return ((LOUDSPEAKER_PORT->ODR & (1<<LOUDSPEAKER_PIN)) ? 1 : 0);
|
||||
return loudspeaker_val;
|
||||
}
|
||||
|
||||
#if LOUDSPEAKER_MULTIFREQ
|
||||
void TIM7_IRQHandler(void)
|
||||
{
|
||||
TIM7->SR = 0UL;
|
||||
__DSB();
|
||||
LOUDSPEAKER_PORT->ODR ^= (1<<LOUDSPEAKER_PIN);
|
||||
}
|
||||
#endif
|
||||
|
||||
40
stm-firmware/doxygen/CMakeLists.txt
Normal file
40
stm-firmware/doxygen/CMakeLists.txt
Normal file
@@ -0,0 +1,40 @@
|
||||
find_package(Doxygen)
|
||||
|
||||
if(NOT WIN32)
|
||||
string(ASCII 27 Esc)
|
||||
set(ColorReset "${Esc}[m")
|
||||
set(ColorBold "${Esc}[1m")
|
||||
set(Red "${Esc}[31m")
|
||||
set(Green "${Esc}[32m")
|
||||
set(Yellow "${Esc}[33m")
|
||||
set(Blue "${Esc}[34m")
|
||||
set(Magenta "${Esc}[35m")
|
||||
set(Cyan "${Esc}[36m")
|
||||
set(White "${Esc}[37m")
|
||||
set(BoldRed "${Esc}[1;31m")
|
||||
set(BoldGreen "${Esc}[1;32m")
|
||||
set(BoldYellow "${Esc}[1;33m")
|
||||
set(BoldBlue "${Esc}[1;34m")
|
||||
set(BoldMagenta "${Esc}[1;35m")
|
||||
set(BoldCyan "${Esc}[1;36m")
|
||||
set(BoldWhite "${Esc}[1;37m")
|
||||
endif()
|
||||
|
||||
if (DOXYGEN_FOUND)
|
||||
add_custom_target(documentation DEPENDS doxygen doxygen-pdf)
|
||||
|
||||
add_custom_target(doxygen
|
||||
COMMAND ./build-doxygen.sh "${PROJECT_BINARY_DIR}"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Generating documentation with Doxygen")
|
||||
|
||||
add_custom_target(
|
||||
doxygen-pdf
|
||||
COMMAND make
|
||||
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/latex"
|
||||
DEPENDS doxygen
|
||||
)
|
||||
else (DOXYGEN_FOUND)
|
||||
message("${BoldMagenta}Doxygen needs to be installed to generate the doxygen documentation${ColorReset}")
|
||||
message("${BoldMagenta}doxygen, documentation, doxygen-latex targets will not be available${ColorReset}")
|
||||
endif (DOXYGEN_FOUND)
|
||||
2651
stm-firmware/doxygen/Doxyconfig
Normal file
2651
stm-firmware/doxygen/Doxyconfig
Normal file
File diff suppressed because it is too large
Load Diff
27
stm-firmware/doxygen/build-doxygen.sh
Executable file
27
stm-firmware/doxygen/build-doxygen.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"
|
||||
cd "$DIR"
|
||||
|
||||
export PROJECT_NUMBER=`git describe --always --tags --dirty`
|
||||
|
||||
configfile="Doxyconfig"
|
||||
|
||||
if [[ -z "$1" ]]; then
|
||||
export OUTPUT_DIRECTORY="./output"
|
||||
else
|
||||
export OUTPUT_DIRECTORY="$1"
|
||||
fi
|
||||
|
||||
if [[ -n "$2" ]]; then
|
||||
configfile="$2"
|
||||
fi
|
||||
|
||||
|
||||
doxygen "$configfile"
|
||||
3
stm-firmware/doxygen/output/.gitignore
vendored
Normal file
3
stm-firmware/doxygen/output/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*
|
||||
*/
|
||||
!.gitignore
|
||||
112
stm-firmware/fatfs/diskio.c
Normal file
112
stm-firmware/fatfs/diskio.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* If a working storage control module is available, it should be */
|
||||
/* attached to the FatFs via a glue function rather than modifying it. */
|
||||
/* This is an example of glue functions to attach various exsisting */
|
||||
/* storage control modules to the FatFs module with a defined API. */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#include <fatfs/ff.h> /* Obtains integer types */
|
||||
#include <fatfs/diskio.h> /* Declarations of disk functions */
|
||||
#include "shimatta_sdio_driver/shimatta_sdio.h"
|
||||
|
||||
/* Definitions of physical drive number for each drive */
|
||||
#define DEV_SD 0
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Drive Status */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_status (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
|
||||
switch (pdrv) {
|
||||
case DEV_SD:
|
||||
return sdio_status();
|
||||
}
|
||||
return STA_NOINIT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Inidialize a Drive */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_initialize (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
switch (pdrv) {
|
||||
case DEV_SD:
|
||||
return sdio_initialize();
|
||||
}
|
||||
return STA_NOINIT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Read Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_read (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
BYTE *buff, /* Data buffer to store read data */
|
||||
LBA_t sector, /* Start sector in LBA */
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
switch (pdrv) {
|
||||
case DEV_SD:
|
||||
return sdio_disk_read(buff, sector, count);
|
||||
}
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Write Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#if FF_FS_READONLY == 0
|
||||
|
||||
DRESULT disk_write (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
const BYTE *buff, /* Data to be written */
|
||||
LBA_t sector, /* Start sector in LBA */
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
switch (pdrv) {
|
||||
case DEV_SD:
|
||||
return sdio_disk_write(buff, sector, count);
|
||||
}
|
||||
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Miscellaneous Functions */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_ioctl (
|
||||
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||
BYTE cmd, /* Control code */
|
||||
void *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
{
|
||||
switch (pdrv) {
|
||||
case DEV_SD:
|
||||
return sdio_disk_ioctl(cmd, buff);
|
||||
}
|
||||
|
||||
return RES_PARERR;
|
||||
}
|
||||
6874
stm-firmware/fatfs/ff.c
Normal file
6874
stm-firmware/fatfs/ff.c
Normal file
File diff suppressed because it is too large
Load Diff
170
stm-firmware/fatfs/ffsystem.c
Normal file
170
stm-firmware/fatfs/ffsystem.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Sample Code of OS Dependent Functions for FatFs */
|
||||
/* (C)ChaN, 2018 */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include <fatfs/ff.h>
|
||||
|
||||
|
||||
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Allocate a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
|
||||
UINT msize /* Number of bytes to allocate */
|
||||
)
|
||||
{
|
||||
return malloc(msize); /* Allocate a new memory block with POSIX API */
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Free a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void ff_memfree (
|
||||
void* mblock /* Pointer to the memory block to free (nothing to do if null) */
|
||||
)
|
||||
{
|
||||
free(mblock); /* Free the memory block with POSIX API */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if FF_FS_REENTRANT /* Mutal exclusion */
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Create a Synchronization Object */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount() function to create a new
|
||||
/ synchronization object for the volume, such as semaphore and mutex.
|
||||
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
//const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */
|
||||
|
||||
|
||||
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */
|
||||
BYTE vol, /* Corresponding volume (logical drive number) */
|
||||
FF_SYNC_t* sobj /* Pointer to return the created sync object */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
*sobj = CreateMutex(NULL, FALSE, NULL);
|
||||
return (int)(*sobj != INVALID_HANDLE_VALUE);
|
||||
|
||||
/* uITRON */
|
||||
// T_CSEM csem = {TA_TPRI,1,1};
|
||||
// *sobj = acre_sem(&csem);
|
||||
// return (int)(*sobj > 0);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OS_ERR err;
|
||||
// *sobj = OSMutexCreate(0, &err);
|
||||
// return (int)(err == OS_NO_ERR);
|
||||
|
||||
/* FreeRTOS */
|
||||
// *sobj = xSemaphoreCreateMutex();
|
||||
// return (int)(*sobj != NULL);
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// *sobj = osMutexCreate(&Mutex[vol]);
|
||||
// return (int)(*sobj != NULL);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Delete a Synchronization Object */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount() function to delete a synchronization
|
||||
/ object that created with ff_cre_syncobj() function. When a 0 is returned,
|
||||
/ the f_mount() function fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */
|
||||
FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
return (int)CloseHandle(sobj);
|
||||
|
||||
/* uITRON */
|
||||
// return (int)(del_sem(sobj) == E_OK);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OS_ERR err;
|
||||
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err);
|
||||
// return (int)(err == OS_NO_ERR);
|
||||
|
||||
/* FreeRTOS */
|
||||
// vSemaphoreDelete(sobj);
|
||||
// return 1;
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// return (int)(osMutexDelete(sobj) == osOK);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Request Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on entering file functions to lock the volume.
|
||||
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
|
||||
*/
|
||||
|
||||
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
|
||||
FF_SYNC_t sobj /* Sync object to wait */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0);
|
||||
|
||||
/* uITRON */
|
||||
// return (int)(wai_sem(sobj) == E_OK);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OS_ERR err;
|
||||
// OSMutexPend(sobj, FF_FS_TIMEOUT, &err));
|
||||
// return (int)(err == OS_NO_ERR);
|
||||
|
||||
/* FreeRTOS */
|
||||
// return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Release Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on leaving file functions to unlock the volume.
|
||||
*/
|
||||
|
||||
void ff_rel_grant (
|
||||
FF_SYNC_t sobj /* Sync object to be signaled */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
ReleaseMutex(sobj);
|
||||
|
||||
/* uITRON */
|
||||
// sig_sem(sobj);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OSMutexPost(sobj);
|
||||
|
||||
/* FreeRTOS */
|
||||
// xSemaphoreGive(sobj);
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// osMutexRelease(sobj);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
15593
stm-firmware/fatfs/ffunicode.c
Normal file
15593
stm-firmware/fatfs/ffunicode.c
Normal file
File diff suppressed because it is too large
Load Diff
800
stm-firmware/fatfs/shimatta_sdio_driver/shimatta_sdio.c
Normal file
800
stm-firmware/fatfs/shimatta_sdio_driver/shimatta_sdio.c
Normal file
@@ -0,0 +1,800 @@
|
||||
#include "shimatta_sdio.h"
|
||||
#include "shimatta_sdio_config.h"
|
||||
#include <cmsis/core_cm4.h>
|
||||
#include <stm32/stm32f4xx.h>
|
||||
|
||||
extern void sdio_wait_ms(unsigned int i);
|
||||
|
||||
#define SETAF(PORT,PIN,AF) PORT->AFR[(PIN < 8 ? 0 : 1)] |= AF << ((PIN < 8 ? PIN : (PIN - 8)) * 4)
|
||||
|
||||
#define READCTRL ((BLOCKSIZE << 4) | SDIO_DCTRL_DMAEN)
|
||||
#define DMAP2M (DMA_SxCR_CHSEL_2 | DMA_SxCR_PBURST_0 | DMA_SxCR_MBURST_0 | DMA_SxCR_MSIZE_1 | DMA_SxCR_PSIZE_1 | DMA_SxCR_MINC | DMA_SxCR_PFCTRL)
|
||||
#define DMAM2P (DMA_SxCR_CHSEL_2 | DMA_SxCR_PBURST_0 | DMA_SxCR_MBURST_0 | DMA_SxCR_MSIZE_1 | DMA_SxCR_PSIZE_1 | DMA_SxCR_MINC | DMA_SxCR_PFCTRL | DMA_SxCR_DIR_0)
|
||||
#define SHORT_ANS 1
|
||||
#define LONG_ANS 3
|
||||
#define NO_ANS 0
|
||||
|
||||
#define CCRCFAIL 1
|
||||
#define CTIMEOUT 2
|
||||
#define CNOTEXPETED 3
|
||||
|
||||
/* OCR Register Masks */
|
||||
#define OCS_CCS (1<<30)
|
||||
#define OCS_BUSY (1<<31)
|
||||
|
||||
enum acmd41_ret {ACMD41_RESP_INIT = 0, ACMD41_RESP_ERR, ACMD41_RESP_SDSC, ACMD41_RESP_SDXC};
|
||||
enum cmd8_ret {CMD8_RESP_TIMEOUT = 0, CMD8_VOLTAGE_ACCEPTED, CMD8_VOLTAGE_DENIED};
|
||||
typedef uint8_t CID_t;
|
||||
|
||||
static struct sd_info card_info; // = {.type = CARD_NONE};
|
||||
|
||||
/**
|
||||
* @brief checkNotInserted
|
||||
* @return return 0 if card is inserted, else 1
|
||||
*/
|
||||
int sdio_check_inserted() {
|
||||
#if SDIO_ENABLE_INS
|
||||
return ((INS_PORT->IDR & (1<<INS_PIN)) == (INS_ACTIVE_LEVEL<<INS_PIN) ? 0 : 1);
|
||||
#else
|
||||
return 0; // Assume Card is inserted
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief checkWriteProtection
|
||||
* @return 0 if card is writable.
|
||||
*/
|
||||
static int sdio_check_write_protection() {
|
||||
#if SDIO_ENABLE_WRITEPROT
|
||||
return ((WRITEPROT_PORT->IDR & (1<<WRITEPROT_PIN)) == (WRITEPROT_ACTIVE_LEVEL<<WRITEPROT_PIN) ? 1 : 0);
|
||||
#else
|
||||
return 0; // Assume Card is not write protected
|
||||
#endif
|
||||
}
|
||||
|
||||
static void sdio_wait_cmd_sent()
|
||||
{
|
||||
while (!(SDIO->STA & SDIO_STA_CMDSENT));
|
||||
SDIO->ICR |= SDIO_ICR_CMDSENTC;
|
||||
}
|
||||
|
||||
static int sdio_send_cmd(uint8_t cmd, uint32_t arg, uint8_t expected_ans){
|
||||
/* Clear Flags */
|
||||
SDIO->ICR = SDIO_ICR_CCRCFAILC | SDIO_ICR_CMDRENDC | SDIO_ICR_CTIMEOUTC | SDIO_ICR_CMDSENTC;
|
||||
/* Send command */
|
||||
SDIO->ARG = arg;
|
||||
SDIO->CMD = (cmd & SDIO_CMD_CMDINDEX) | SDIO_CMD_CPSMEN | ((expected_ans << 6) & SDIO_CMD_WAITRESP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdio_get_response(uint8_t expected_command, uint8_t type_of_answer, uint32_t *response_buffer) {
|
||||
uint32_t sdio_status;
|
||||
|
||||
/* Wait until command isn't active anymore */
|
||||
while (SDIO->STA & SDIO_STA_CMDACT);
|
||||
|
||||
/* Wait for error or success */
|
||||
while (1) {
|
||||
sdio_status = SDIO->STA;
|
||||
|
||||
/* Check if a valid response was received */
|
||||
if (sdio_status & SDIO_STA_CMDREND)
|
||||
break;
|
||||
|
||||
if ((sdio_status & SDIO_STA_CMDSENT) && (type_of_answer == NO_ANS))
|
||||
break; // No response required
|
||||
|
||||
/* Exclude ACMD41 and CMD2 from valid CRC check */
|
||||
if ((sdio_status & SDIO_STA_CCRCFAIL)) {
|
||||
if(expected_command == 0xff) {
|
||||
break;
|
||||
} else {
|
||||
return -CCRCFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (sdio_status & SDIO_STA_CTIMEOUT)
|
||||
return -CTIMEOUT;
|
||||
}
|
||||
|
||||
/* Valid Respone Received */
|
||||
if (((SDIO->RESPCMD & SDIO_RESPCMD_RESPCMD) != expected_command) && (expected_command != 0xff))
|
||||
return -CNOTEXPETED; //Not the expected respose
|
||||
|
||||
/* If case of a correct Response */
|
||||
*(response_buffer++) = SDIO->RESP1;
|
||||
|
||||
/* Long response */
|
||||
if (type_of_answer == LONG_ANS) {
|
||||
*(response_buffer++) = SDIO->RESP2;
|
||||
*(response_buffer++) = SDIO->RESP3;
|
||||
*(response_buffer++) = SDIO->RESP4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Switch the card to application mode. It now accepts ACMDXX commands
|
||||
* @return 0 if successfuls
|
||||
*/
|
||||
static int sdio_switch_appmode_cmd55()
|
||||
{
|
||||
int retry = 0x20;
|
||||
union sdio_status_conv converter;
|
||||
uint32_t response;
|
||||
do {
|
||||
/* Execute Command and check for valid response */
|
||||
sdio_send_cmd(55, (card_info.rca<<16)&0xFFFF0000, SHORT_ANS);
|
||||
|
||||
if (!sdio_get_response(55, SHORT_ANS, &response))
|
||||
{
|
||||
/* Response valid. Check if Card has accepted switch to application command mode */
|
||||
converter.value = response;
|
||||
if (converter.statusstruct.APP_CMD == 1)
|
||||
return 0;
|
||||
}
|
||||
} while (--retry > 0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
enum acmd41_ret sdio_init_card_acmd41(uint8_t HCS)
|
||||
{
|
||||
uint32_t response;
|
||||
int retry = 0x20;
|
||||
if (sdio_switch_appmode_cmd55())
|
||||
return ACMD41_RESP_ERR;
|
||||
|
||||
do {
|
||||
sdio_send_cmd(41, (HCS ? (1<<30) : 0) | (1<<28) | (1<<20) |(1<<21)|(1<<22) |(1<<23)|(1<<19), SHORT_ANS);
|
||||
if (!sdio_get_response(0xFF, SHORT_ANS, &response)) {
|
||||
if (response & OCS_BUSY) {
|
||||
/* Card is ready... Who knows why this bit is called busy */
|
||||
if (response & OCS_CCS) {
|
||||
return ACMD41_RESP_SDXC;
|
||||
} else {
|
||||
return ACMD41_RESP_SDSC;
|
||||
}
|
||||
} else {
|
||||
return ACMD41_RESP_INIT;
|
||||
}
|
||||
}
|
||||
} while (--retry > 0);
|
||||
|
||||
return ACMD41_RESP_ERR;
|
||||
}
|
||||
|
||||
static int sdio_send_csd_cmd9(uint16_t rca, uint32_t *response_buffer) {
|
||||
int timeout = 0x20;
|
||||
int res;
|
||||
|
||||
do {
|
||||
sdio_send_cmd(9, (rca<<16)&0xFFFF0000, LONG_ANS);
|
||||
res = sdio_get_response(0xFF, LONG_ANS, response_buffer);
|
||||
if (!res)
|
||||
break;
|
||||
} while (--timeout > 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send data buffer to SD card
|
||||
* @param dlen Data length. Must be a multiple of 4 bytes
|
||||
* @param blklen Log2 of block length (9 in case of 512 byte block)
|
||||
* @param buff Buffer to send
|
||||
*/
|
||||
static int sdio_write_buffer(uint32_t dlen, uint32_t log_blklen, const unsigned char *buff)
|
||||
{
|
||||
uint32_t count;
|
||||
int byte_count;
|
||||
int byte_max;
|
||||
uint32_t fifo;
|
||||
uint32_t status_reg;
|
||||
|
||||
SDIO->DLEN = dlen;
|
||||
|
||||
/* Init Transfer */
|
||||
SDIO->ICR = SDIO_ICR_CCRCFAILC | SDIO_ICR_DCRCFAILC | SDIO_ICR_CTIMEOUTC | SDIO_ICR_DTIMEOUTC |
|
||||
SDIO_ICR_TXUNDERRC | SDIO_ICR_RXOVERRC | SDIO_ICR_CMDRENDC | SDIO_ICR_CMDSENTC | SDIO_ICR_DATAENDC |
|
||||
SDIO_ICR_STBITERRC | SDIO_ICR_DBCKENDC | SDIO_ICR_SDIOITC | SDIO_ICR_CEATAENDC;
|
||||
SDIO->DCTRL = (log_blklen<<4) | SDIO_DCTRL_DTEN;
|
||||
|
||||
for (count = 0; count < dlen; count += 4) {
|
||||
fifo = 0;
|
||||
|
||||
if ((dlen - count) < 4)
|
||||
byte_max = dlen - count;
|
||||
else
|
||||
byte_max = 4;
|
||||
|
||||
for (byte_count = 0; byte_count < byte_max; byte_count++) {
|
||||
fifo >>= 8;
|
||||
fifo |= (((uint32_t)*(buff++)) << 24) & 0xFF000000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Wait as long as FIFO is full */
|
||||
while (SDIO->STA & SDIO_STA_TXFIFOF);
|
||||
|
||||
/* Write data to FIFO */
|
||||
SDIO->FIFO = fifo;
|
||||
}
|
||||
|
||||
/* Wait for TX to complete */
|
||||
while (SDIO->STA & SDIO_STA_TXACT);
|
||||
|
||||
status_reg = SDIO->STA;
|
||||
if (status_reg & (SDIO_STA_DTIMEOUT | SDIO_STA_TXUNDERR | SDIO_STA_DCRCFAIL)) {
|
||||
SDIO->DCTRL = 0UL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdio_send_write_block_cmd24(uint32_t addr)
|
||||
{
|
||||
uint32_t response;
|
||||
|
||||
sdio_send_cmd(24, addr, SHORT_ANS);
|
||||
|
||||
return sdio_get_response(24, SHORT_ANS, &response);
|
||||
}
|
||||
|
||||
static int sdio_check_status_register_cmd13(uint16_t rca, uint32_t *status)
|
||||
{
|
||||
int timeout = 0x20;
|
||||
uint32_t response;
|
||||
int res;
|
||||
|
||||
*status = 0UL;
|
||||
|
||||
do {
|
||||
sdio_send_cmd(13, (rca<<16)&0xFFFF0000, SHORT_ANS);
|
||||
if (!(res = sdio_get_response(13, SHORT_ANS, &response))) {
|
||||
*status = response;
|
||||
break;
|
||||
}
|
||||
} while (--timeout > 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int sdio_send_bus_width_acmd6(uint8_t bus_width)
|
||||
{
|
||||
uint32_t response;
|
||||
int retry = 0x20;
|
||||
int ret;
|
||||
|
||||
if (sdio_switch_appmode_cmd55()) return -1;
|
||||
do {
|
||||
sdio_send_cmd(0x6, (bus_width == 4 ? 0x2 : 0x0), SHORT_ANS);
|
||||
ret = sdio_get_response(0x6, SHORT_ANS, &response);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
} while (--retry > 0);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int sdio_get_sector_count(uint16_t rca, uint32_t *sector_count)
|
||||
{
|
||||
uint32_t csd[4];
|
||||
int res;
|
||||
uint32_t size, mult, read_len, csd_rev;
|
||||
|
||||
if ((res = sdio_send_csd_cmd9(rca, csd))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
csd_rev = ((csd[0] >> 30) & (0x3));
|
||||
|
||||
if (csd_rev == 0) {
|
||||
/* SD v1 Card */
|
||||
size = ((csd[1] & 0x3FF) <<2) | (((csd[2]) & ((1<<31) | (1<<30)))>>30);
|
||||
mult = ((csd[2] & ((1<<17)|(1<<16)|(1<<15)))>>15);
|
||||
read_len = (1<<((csd[1] & ((1<<19)|(1<<18)|(1<<17)|(1<<16)))>>16));
|
||||
*sector_count = (((size +1)*(1<<(mult+2))*read_len) >> BLOCKSIZE);
|
||||
} else if (csd_rev == 1) {
|
||||
/* SD v2 Card */
|
||||
size = (((csd[1] & 0x3F)<<16) | ((csd[2] & 0xFFFF0000) >> 16));
|
||||
*sector_count = (size << (19-BLOCKSIZE));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Switch the SDIo prescaler
|
||||
* @param Prescaler value
|
||||
*/
|
||||
static void sdio_switch_prescaler(uint8_t clkdiv)
|
||||
{
|
||||
uint32_t reg;
|
||||
reg = SDIO->CLKCR;
|
||||
/* Clear prescaler */
|
||||
reg &= ~SDIO_CLKCR_CLKDIV;
|
||||
/* Set bits */
|
||||
reg |= (SDIO_CLKCR_CLKDIV & clkdiv);
|
||||
SDIO->CLKCR = reg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief initDetectandProtectionPins
|
||||
*/
|
||||
static void sdio_init_detect_pins()
|
||||
{
|
||||
#if SDIO_ENABLE_WRITEPROT==1
|
||||
WRITEPROT_PORT->PUPDR |= ((WRITEPROT_PULLUP ? 1 : 0)<<WRITEPROT_PIN*2);
|
||||
#endif /* SDIO_ENABLE_WRITEPROT */
|
||||
#if SDIO_ENABLE_INS==1
|
||||
INS_PORT->PUPDR |= ((INS_PULLUP? 1 : 0)<<INS_PIN*2);
|
||||
#endif /* SDIO_ENABLE_INS */
|
||||
__DSB();
|
||||
}
|
||||
|
||||
static void sdio_init_hw()
|
||||
{
|
||||
//Init Clocks
|
||||
RCC->AHB1ENR |= PORTCLKMASK | RCC_AHB1ENR_DMA2EN;
|
||||
RCC->APB2ENR |= RCC_APB2ENR_SDIOEN;
|
||||
//Init Alternate Functions
|
||||
CLKPORT->MODER |= (2<<CLKPIN*2);
|
||||
D0PORT->MODER |= (2<<D0PIN*2);
|
||||
D0PORT->PUPDR |= (1<<D0PIN*2);
|
||||
CMDPORT->MODER |= (2<<CMDPIN*2);
|
||||
CMDPORT->PUPDR |= (1<<CMDPIN*2);
|
||||
#if BUSWIDTH==4
|
||||
D1PORT->MODER |= (2<<D1PIN*2);
|
||||
D1PORT->PUPDR |= (1<<D1PIN*2);
|
||||
D2PORT->MODER |= (2<<D2PIN*2);
|
||||
D2PORT->PUPDR |= (1<<D2PIN*2);
|
||||
D3PORT->MODER |= (2<<D3PIN*2);
|
||||
D3PORT->PUPDR |= (1<<D3PIN*2);
|
||||
#endif
|
||||
//CLKPORT->AFR[(CLKPIN < 8 ? 0 : 1)] |= ALTFUNC << ((CLKPIN < 8 ? CLKPIN : (CLKPIN - 8)) * 4);
|
||||
SETAF(CLKPORT, CLKPIN, ALTFUNC);
|
||||
SETAF(CMDPORT, CMDPIN, ALTFUNC);
|
||||
SETAF(D0PORT, D0PIN, ALTFUNC);
|
||||
#if BUSWIDTH==4
|
||||
SETAF(D1PORT, D1PIN, ALTFUNC);
|
||||
SETAF(D2PORT, D2PIN, ALTFUNC);
|
||||
SETAF(D3PORT, D3PIN, ALTFUNC);
|
||||
#endif
|
||||
|
||||
|
||||
//Init Module
|
||||
|
||||
//Set CLK Control Register
|
||||
SDIO->CLKCR = (HW_FLOW<<14) | ((BUSWIDTH == 4 ? 1 : 0)<<11) | SDIO_CLKCR_CLKEN |
|
||||
(INITCLK & SDIO_CLKCR_CLKDIV);
|
||||
|
||||
//Set Data Timeout
|
||||
SDIO->DTIMER = DTIMEOUT;
|
||||
|
||||
//Set Data Parameters
|
||||
//SDIO->DCTRL = (BLOCKSIZE << 4) | SDIO_DCTRL_DMAEN;
|
||||
//Set Power Register: Power up Card CLK
|
||||
SDIO->POWER = SDIO_POWER_PWRCTRL_0 | SDIO_POWER_PWRCTRL_1;
|
||||
|
||||
}
|
||||
|
||||
static int sdio_send_read_block_cmd17(uint32_t addr)
|
||||
{
|
||||
uint32_t response;
|
||||
|
||||
sdio_send_cmd(17, addr, SHORT_ANS);
|
||||
return sdio_get_response(17, SHORT_ANS, &response);
|
||||
}
|
||||
|
||||
static int sdio_send_all_send_cid_cmd2()
|
||||
{
|
||||
uint32_t response[4];
|
||||
int ret;
|
||||
int retry = 0x20;
|
||||
|
||||
do {
|
||||
sdio_send_cmd(2, 0, LONG_ANS);
|
||||
if (!(ret = sdio_get_response(0xFF, LONG_ANS, response)))
|
||||
return 0;
|
||||
} while (retry-- > 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sdio_send_relative_address_cmd3(uint16_t* rca)
|
||||
{
|
||||
uint32_t response;
|
||||
int retry = 0x20;
|
||||
|
||||
do {
|
||||
sdio_send_cmd(3, 0, SHORT_ANS);
|
||||
if (!sdio_get_response(3, SHORT_ANS, &response)) {
|
||||
// TODO: Do some *optional* checking
|
||||
*rca = ((response & 0xFFFF0000) >> 16);
|
||||
return 0;
|
||||
}
|
||||
} while (retry-- > 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int sdio_send_go_idle_cmd0() {
|
||||
sdio_send_cmd(0, 0x0, NO_ANS);
|
||||
sdio_wait_cmd_sent();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdio_send_stop_transmission_cmd12()
|
||||
{
|
||||
int res;
|
||||
uint32_t response;
|
||||
|
||||
sdio_send_cmd(12, 0, SHORT_ANS);
|
||||
res = sdio_get_response(12, SHORT_ANS, &response);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int sdio_send_write_multiple_blocks_cmd25(uint32_t address)
|
||||
{
|
||||
int res;
|
||||
uint32_t response;
|
||||
|
||||
sdio_send_cmd(25, address, SHORT_ANS);
|
||||
res = sdio_get_response(25, SHORT_ANS, &response);
|
||||
return res;
|
||||
}
|
||||
|
||||
static enum cmd8_ret sdio_send_iface_condition_cmd8()
|
||||
{
|
||||
uint32_t response;
|
||||
int res = 0;
|
||||
int retry = 0x20;
|
||||
|
||||
do {
|
||||
sdio_send_cmd(8, 0x1CC, SHORT_ANS); // 3.3V supply requesR
|
||||
res = sdio_get_response(8, SHORT_ANS, &response);
|
||||
if (res == 0) {
|
||||
if (response & 0x100)
|
||||
return CMD8_VOLTAGE_ACCEPTED;
|
||||
else
|
||||
return CMD8_VOLTAGE_DENIED;
|
||||
}
|
||||
} while (retry-- > 0);
|
||||
|
||||
return CMD8_RESP_TIMEOUT;
|
||||
}
|
||||
|
||||
static int sdio_send_block_length_cmd16(uint32_t blocklen) {
|
||||
int timeout = 0x20;
|
||||
int res;
|
||||
uint32_t response;
|
||||
|
||||
do {
|
||||
sdio_send_cmd(16, blocklen, SHORT_ANS);
|
||||
if (!(res = sdio_get_response(16, SHORT_ANS, &response))) {
|
||||
return 0;
|
||||
}
|
||||
}while(--timeout > 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int sdio_send_select_card_cmd7(uint16_t rca) {
|
||||
int timeout = 0x20;
|
||||
uint32_t response;
|
||||
union sdio_status_conv status;
|
||||
int res;
|
||||
|
||||
/* Send CMD7. Selects card */
|
||||
do {
|
||||
sdio_send_cmd(7, (rca<<16)&0xFFFF0000, SHORT_ANS);
|
||||
if (!(res = sdio_get_response(7, SHORT_ANS, &response))) {
|
||||
break;
|
||||
}
|
||||
} while(--timeout > 0);
|
||||
|
||||
/* Check, if card in in TRANS state */
|
||||
if (sdio_check_status_register_cmd13(rca, &status.value)) {
|
||||
res = -1;
|
||||
goto ret_val;
|
||||
}
|
||||
if (status.statusstruct.CURRENT_STATE != CURRENT_STATE_TRAN)
|
||||
res = -2;
|
||||
|
||||
ret_val:
|
||||
return res;
|
||||
}
|
||||
|
||||
DSTATUS sdio_status()
|
||||
{
|
||||
DSTATUS returnval = 0;
|
||||
|
||||
if (sdio_check_inserted())
|
||||
returnval |= STA_NODISK;
|
||||
|
||||
if (card_info.type == CARD_NONE)
|
||||
returnval |= STA_NOINIT;
|
||||
|
||||
if (sdio_check_write_protection())
|
||||
returnval |= STA_PROTECT;
|
||||
|
||||
return returnval;
|
||||
}
|
||||
|
||||
DRESULT sdio_disk_ioctl(BYTE cmd, void* buff){
|
||||
DRESULT res = RES_OK;
|
||||
|
||||
switch(cmd) {
|
||||
case GET_BLOCK_SIZE:
|
||||
*((DWORD*)buff) = (DWORD)0x01;
|
||||
break;
|
||||
case GET_SECTOR_SIZE:
|
||||
*((WORD*)buff) = (WORD)(1<<BLOCKSIZE);
|
||||
break;
|
||||
case GET_SECTOR_COUNT:
|
||||
if (card_info.type != CARD_NONE) {
|
||||
*((DWORD*)buff) = (DWORD)card_info.sector_count;
|
||||
} else {
|
||||
res = RES_ERROR;
|
||||
}
|
||||
break;
|
||||
case CTRL_SYNC:
|
||||
res = RES_OK;
|
||||
break;
|
||||
default:
|
||||
res = RES_PARERR;
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
DWORD __attribute__((weak)) get_fattime()
|
||||
{
|
||||
return (1<<16) | (1<<24); // return Jan. 1st 1980 00:00:00
|
||||
}
|
||||
|
||||
DSTATUS sdio_initialize(){
|
||||
int timeout = 0x3000;
|
||||
enum cmd8_ret res8;
|
||||
enum acmd41_ret resa41;
|
||||
uint8_t hcs_flag = 0;
|
||||
card_info.rca = 0;
|
||||
card_info.type = CARD_NONE;
|
||||
enum sdio_card_type detected_card = CARD_NONE;
|
||||
|
||||
sdio_init_hw();
|
||||
sdio_wait_ms(2);
|
||||
sdio_init_detect_pins();
|
||||
if (sdio_check_inserted()) {
|
||||
return STA_NOINIT | STA_NODISK;
|
||||
}
|
||||
|
||||
sdio_send_go_idle_cmd0();
|
||||
|
||||
sdio_wait_ms(2);
|
||||
|
||||
res8 = sdio_send_iface_condition_cmd8();
|
||||
switch (res8) {
|
||||
case CMD8_VOLTAGE_ACCEPTED: // SDV2 Card
|
||||
hcs_flag = 1;
|
||||
break;
|
||||
case CMD8_VOLTAGE_DENIED: // should not happen
|
||||
return STA_NOINIT;
|
||||
break;
|
||||
case CMD8_RESP_TIMEOUT: // SDV1 Card
|
||||
hcs_flag=0;
|
||||
break;
|
||||
default:
|
||||
return STA_NOINIT;
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
//SDIO_wait_ms(2);
|
||||
resa41 = sdio_init_card_acmd41(hcs_flag);
|
||||
} while ((resa41 == ACMD41_RESP_INIT) && (--timeout > 0));
|
||||
|
||||
switch (resa41) {
|
||||
case ACMD41_RESP_SDSC:
|
||||
detected_card = (hcs_flag ? SD_V2_SC : SD_V1);
|
||||
break;
|
||||
case ACMD41_RESP_SDXC:
|
||||
detected_card = SD_V2_HC;
|
||||
break;
|
||||
default:
|
||||
return STA_NOINIT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sdio_send_all_send_cid_cmd2())
|
||||
return STA_NOINIT;
|
||||
|
||||
if (sdio_send_relative_address_cmd3(&card_info.rca))
|
||||
return STA_NOINIT;
|
||||
if (sdio_get_sector_count(card_info.rca, &card_info.sector_count))
|
||||
return STA_NOINIT;
|
||||
if (sdio_send_select_card_cmd7(card_info.rca))
|
||||
return STA_NOINIT;
|
||||
|
||||
if (sdio_send_block_length_cmd16((uint32_t)(1<<BLOCKSIZE)))
|
||||
return STA_NOINIT;
|
||||
|
||||
if (sdio_send_bus_width_acmd6(BUSWIDTH))
|
||||
return STA_NOINIT;
|
||||
|
||||
sdio_switch_prescaler(WORKCLK);
|
||||
|
||||
card_info.type = detected_card;
|
||||
|
||||
if (sdio_check_write_protection()) {
|
||||
return STA_PROTECT;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sdio_stop_clk()
|
||||
{
|
||||
SDIO->POWER = 0UL;
|
||||
}
|
||||
|
||||
DRESULT sdio_disk_read(BYTE *buff, DWORD sector, UINT count){
|
||||
uint32_t addr;
|
||||
uint32_t sdio_status;
|
||||
uint32_t fifo;
|
||||
uint32_t counter;
|
||||
int err;
|
||||
union sdio_status_conv status;
|
||||
|
||||
|
||||
do {
|
||||
err = sdio_check_status_register_cmd13(card_info.rca, &status.value);
|
||||
if (err)
|
||||
return RES_ERROR;
|
||||
} while (status.statusstruct.CURRENT_STATE != CURRENT_STATE_TRAN);
|
||||
|
||||
addr = (card_info.type == SD_V2_HC ? (sector) : (sector*512));
|
||||
for (; count > 0; count--) {
|
||||
|
||||
/* configure read DMA */
|
||||
// DMA2->LIFCR = 0xffffffff;
|
||||
// DMA2->HIFCR = 0xffffffff;
|
||||
// DMASTREAM->NDTR = 0;
|
||||
// DMASTREAM->FCR = DMA_SxFCR_FTH_0 | DMA_SxFCR_FTH_1 | DMA_SxFCR_DMDIS;
|
||||
// DMASTREAM->M0AR = (uint32_t)(buff);
|
||||
// DMASTREAM->PAR = (uint32_t)&(SDIO->FIFO);
|
||||
// DMASTREAM->CR = DMAP2M | DMA_SxCR_PL_1 | DMA_SxCR_PL_1;
|
||||
// DMASTREAM->CR |= DMA_SxCR_EN;
|
||||
|
||||
SDIO->DLEN = (1 << BLOCKSIZE);
|
||||
|
||||
SDIO->ICR = SDIO_ICR_CCRCFAILC | SDIO_ICR_DCRCFAILC | SDIO_ICR_CTIMEOUTC | SDIO_ICR_DTIMEOUTC |
|
||||
SDIO_ICR_TXUNDERRC | SDIO_ICR_RXOVERRC | SDIO_ICR_CMDRENDC | SDIO_ICR_CMDSENTC | SDIO_ICR_DATAENDC |
|
||||
SDIO_ICR_STBITERRC | SDIO_ICR_DBCKENDC | SDIO_ICR_SDIOITC | SDIO_ICR_CEATAENDC;
|
||||
SDIO->DCTRL = (BLOCKSIZE<<4) | SDIO_DCTRL_DTDIR | /*SDIO_DCTRL_DMAEN |*/ SDIO_DCTRL_DTEN;
|
||||
|
||||
/* Init Transfer */
|
||||
err = sdio_send_read_block_cmd17(addr);
|
||||
if (err) {
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
counter = 0;
|
||||
while (counter < (1<<(BLOCKSIZE-2)) || !(SDIO->STA & (SDIO_STA_DBCKEND | SDIO_STA_DATAEND))) {
|
||||
/* TODO: Handle errors */
|
||||
if (SDIO->STA & (SDIO_STA_DCRCFAIL | SDIO_STA_DTIMEOUT | SDIO_STA_STBITERR))
|
||||
{
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
if (SDIO->STA & SDIO_STA_RXDAVL) {
|
||||
counter++;
|
||||
fifo = SDIO->FIFO;
|
||||
*(buff++) = (BYTE)(fifo & 0xFF);
|
||||
fifo >>= 8;
|
||||
*(buff++) = (BYTE)(fifo & 0xFF);
|
||||
fifo >>= 8;
|
||||
*(buff++) = (BYTE)(fifo & 0xFF);
|
||||
fifo >>= 8;
|
||||
*(buff++) = (BYTE)(fifo & 0xFF);
|
||||
}
|
||||
|
||||
}
|
||||
if (SDIO->STA & SDIO_STA_DCRCFAIL) return RES_ERROR;
|
||||
|
||||
//while(DMASTREAM->CR & DMA_SxCR_EN);
|
||||
while(1) {
|
||||
__DSB();
|
||||
__DMB();
|
||||
sdio_status = SDIO->STA;
|
||||
if (sdio_status & SDIO_STA_DCRCFAIL) {
|
||||
return RES_ERROR;
|
||||
}
|
||||
if (sdio_status & SDIO_STA_DTIMEOUT) {
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
if (sdio_status & SDIO_STA_DATAEND) {
|
||||
|
||||
if (!(sdio_status & SDIO_STA_RXACT)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (card_info.type == SD_V2_HC) {
|
||||
addr++;
|
||||
} else {
|
||||
addr += (1<<BLOCKSIZE);
|
||||
}
|
||||
}
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SDIO_disk_write
|
||||
* @param buff
|
||||
* @param sector
|
||||
* @param count
|
||||
* @warning Not yet implemented
|
||||
* @return
|
||||
*/
|
||||
DRESULT sdio_disk_write(const BYTE *buff, DWORD sector, UINT count)
|
||||
{
|
||||
uint32_t addr;
|
||||
union sdio_status_conv status;
|
||||
uint32_t buff_offset = 0;
|
||||
int ret;
|
||||
UINT count_backup = count;
|
||||
uint32_t retry_counter = 512;
|
||||
|
||||
if (sdio_check_write_protection())
|
||||
return RES_WRPRT;
|
||||
|
||||
addr = (card_info.type == SD_V2_HC ? (sector) : (sector * 512));
|
||||
|
||||
ret = sdio_check_status_register_cmd13(card_info.rca, &status.value);
|
||||
if (ret)
|
||||
return RES_ERROR;
|
||||
|
||||
if (status.statusstruct.CURRENT_STATE == CURRENT_STATE_STBY) {
|
||||
if (sdio_send_select_card_cmd7(card_info.rca))
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
ret = sdio_check_status_register_cmd13(card_info.rca, &status.value);
|
||||
if (ret)
|
||||
return RES_ERROR;
|
||||
|
||||
if (status.statusstruct.CURRENT_STATE == CURRENT_STATE_TRAN)
|
||||
break;
|
||||
|
||||
if (--retry_counter == 0)
|
||||
return RES_ERROR;
|
||||
|
||||
sdio_wait_ms(1);
|
||||
}
|
||||
|
||||
if (count > 1)
|
||||
ret = sdio_send_write_multiple_blocks_cmd25(addr);
|
||||
else if (count == 1)
|
||||
ret = sdio_send_write_block_cmd24(addr);
|
||||
else
|
||||
ret = RES_PARERR;
|
||||
if (ret)
|
||||
return RES_ERROR;
|
||||
|
||||
ret = 0;
|
||||
ret = sdio_write_buffer((count * 512UL), 9, &buff[buff_offset]);
|
||||
|
||||
if (count_backup > 1)
|
||||
(void)sdio_send_stop_transmission_cmd12();
|
||||
|
||||
return (ret ? RES_ERROR : RES_OK);
|
||||
}
|
||||
79
stm-firmware/fatfs/shimatta_sdio_driver/shimatta_sdio.h
Normal file
79
stm-firmware/fatfs/shimatta_sdio_driver/shimatta_sdio.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* shimatta_sdio-driver.h
|
||||
*
|
||||
* Created on: Apr 26, 2015
|
||||
* Mario Hüttel
|
||||
*/
|
||||
|
||||
#ifndef FATFS_SHIMATTA_SDIO_DRIVER_SHIMATTA_SDIO_DRIVER_H_
|
||||
#define FATFS_SHIMATTA_SDIO_DRIVER_SHIMATTA_SDIO_DRIVER_H_
|
||||
|
||||
#include <fatfs/diskio.h>
|
||||
#include <fatfs/ff.h>
|
||||
#include <stdint.h>
|
||||
|
||||
DSTATUS sdio_status();
|
||||
DSTATUS sdio_initialize();
|
||||
|
||||
DRESULT sdio_disk_read(BYTE *buff, DWORD sector, UINT count);
|
||||
DRESULT sdio_disk_write(const BYTE *buff, DWORD sector, UINT count);
|
||||
DRESULT sdio_disk_ioctl(BYTE cmd, void* buff);
|
||||
DWORD get_fattime();
|
||||
|
||||
int sdio_check_inserted();
|
||||
void sdio_stop_clk();
|
||||
|
||||
//Defines for Card Status in struct _CardStatus
|
||||
#define CURRENT_STATE_IDLE 0
|
||||
#define CURRENT_STATE_READY 1
|
||||
#define CURRENT_STATE_IDENT 2
|
||||
#define CURRENT_STATE_STBY 3
|
||||
#define CURRENT_STATE_TRAN 4
|
||||
#define CURRENT_STATE_DATA 5
|
||||
#define CURRENT_STATE_RCV 6
|
||||
#define CURRENT_STATE_PRG 7
|
||||
#define CURRENT_STATE_DIS 8
|
||||
|
||||
struct sd_card_status {
|
||||
uint32_t reserved : 3;
|
||||
uint32_t AKE_SEQ_ERROR : 1;
|
||||
uint32_t reserved_2 : 1;
|
||||
uint32_t APP_CMD : 1;
|
||||
uint32_t reserved_3 : 2;
|
||||
uint32_t READY_FOR_DATA : 1;
|
||||
uint32_t CURRENT_STATE : 4;
|
||||
uint32_t ERASE_RESET : 1;
|
||||
uint32_t CARD_ECC_DIABLED : 1;
|
||||
uint32_t WP_ERASE_SKIP : 1;
|
||||
uint32_t CSD_OVERWRITE : 1;
|
||||
uint32_t reserved17 : 1;
|
||||
uint32_t reserved18 : 1;
|
||||
uint32_t ERROR : 1;
|
||||
uint32_t CC_ERROR : 1;
|
||||
uint32_t CARD_ECC_FAILED : 1;
|
||||
uint32_t ILLEGAL_COMMAND : 1;
|
||||
uint32_t COM_CRC_ERROR : 1;
|
||||
uint32_t LOCK_UNLOCK_FAILED : 1;
|
||||
uint32_t CARD_IS_LOCKED : 1;
|
||||
uint32_t WP_VIOLATION : 1;
|
||||
uint32_t ERASE_PARAM : 1;
|
||||
uint32_t ERASE_SEQ_ERROR : 1;
|
||||
uint32_t BLOCK_LEN_ERROR : 1;
|
||||
uint32_t ADDRESS_ERROR : 1;
|
||||
uint32_t OUT_OF_RANGE : 1;
|
||||
};
|
||||
|
||||
enum sdio_card_type {CARD_NONE = 0, MMC, SD_V1, SD_V2_SC, SD_V2_HC};
|
||||
// MMC not supported
|
||||
struct sd_info {
|
||||
uint16_t rca;
|
||||
enum sdio_card_type type;
|
||||
uint32_t sector_count;
|
||||
};
|
||||
|
||||
union sdio_status_conv {
|
||||
struct sd_card_status statusstruct;
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
#endif /* FATFS_SHIMATTA_SDIO_DRIVER_SHIMATTA_SDIO_DRIVER_H_ */
|
||||
@@ -0,0 +1,65 @@
|
||||
#ifndef FATFS_SHIMATTA_SDIO_DRIVER_SHIMATTA_SDIO_CONFIG_H_
|
||||
#define FATFS_SHIMATTA_SDIO_DRIVER_SHIMATTA_SDIO_CONFIG_H_
|
||||
|
||||
#include <stm32/stm32f4xx.h>
|
||||
|
||||
#define SDIO_CLOCK_FREQ 42000000UL
|
||||
|
||||
//General Definitions
|
||||
//Blocksize: 512 = 2^9 => 9
|
||||
#define BLOCKSIZE 9 //9
|
||||
//Hardware Flow: Prevents over- and underruns.
|
||||
#define HW_FLOW 0 //0
|
||||
//1 bit: !=4
|
||||
//4 bit: 4
|
||||
#define BUSWIDTH 4 //4
|
||||
//Initial Transfer CLK (ca. 400kHz)
|
||||
#define INITCLK 140UL //120
|
||||
//Working CLK (Maximum)
|
||||
#define WORKCLK 30UL //0
|
||||
//Data Timeout in CLK Cycles
|
||||
|
||||
#define DATA_TIMEOUT_MS 250UL // 250
|
||||
|
||||
#define DTIMEOUT (((SDIO_CLOCK_FREQ / (WORKCLK+2))) * DATA_TIMEOUT_MS / 1000UL)
|
||||
//DMA Stream used for TX and RX DMA2 Stream 3 or 6 possible
|
||||
// Currently not used due to possible misalignment of the data buffer.
|
||||
//#define DMASTREAM DMA2_Stream6
|
||||
|
||||
|
||||
/* Port Definitions */
|
||||
|
||||
#define PORTCLKMASK (RCC_AHB1ENR_GPIODEN | RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIOAEN)
|
||||
|
||||
#define ALTFUNC 12
|
||||
|
||||
#define CLKPORT GPIOC
|
||||
#define D0PORT GPIOC
|
||||
#define D1PORT GPIOC
|
||||
#define D2PORT GPIOC
|
||||
#define D3PORT GPIOC
|
||||
#define CMDPORT GPIOD
|
||||
|
||||
#define CLKPIN 12
|
||||
#define D0PIN 8
|
||||
#define D1PIN 9
|
||||
#define D2PIN 10
|
||||
#define D3PIN 11
|
||||
#define CMDPIN 2
|
||||
|
||||
// Write Protection
|
||||
#define SDIO_ENABLE_WRITEPROT 0
|
||||
#define WRITEPROT_PORT GPIOD // Add this port to port clock mask!
|
||||
#define WRITEPROT_PIN 0
|
||||
#define WRITEPROT_PULLUP 0
|
||||
#define WRITEPROT_ACTIVE_LEVEL 0
|
||||
|
||||
// Card inserted pin
|
||||
#define SDIO_ENABLE_INS 1
|
||||
#define INS_PORT GPIOA // Add this port to port clock mask!
|
||||
#define INS_PIN 8
|
||||
#define INS_PULLUP 1
|
||||
#define INS_ACTIVE_LEVEL 0
|
||||
|
||||
|
||||
#endif /* FATFS_SHIMATTA_SDIO_DRIVER_SHIMATTA_SDIO_CONFIG_H_ */
|
||||
70
stm-firmware/hw-version-detect.c
Normal file
70
stm-firmware/hw-version-detect.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/* Reflow Oven Controller
|
||||
*
|
||||
* Copyright (C) 2021 Mario Hüttel <mario.huettel@gmx.net>
|
||||
*
|
||||
* This file is part of the Reflow Oven Controller Project.
|
||||
*
|
||||
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* The Reflow Oven Control Firmware 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 the reflow oven controller project.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup hw-version-detect
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <reflow-controller/hw-version-detect.h>
|
||||
#include <stm-periph/rcc-manager.h>
|
||||
#include <stm32/stm32f4xx.h>
|
||||
|
||||
enum hw_revision get_pcb_hardware_version(void)
|
||||
{
|
||||
uint8_t current_pin;
|
||||
uint16_t port_bitmask = 0U;
|
||||
static enum hw_revision revision = HW_REV_NOT_DETECTED;
|
||||
|
||||
if (revision != HW_REV_NOT_DETECTED)
|
||||
return revision;
|
||||
|
||||
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(HW_REV_DETECT_RCC_FIELD));
|
||||
|
||||
/* Setup the pins as input with pull up */
|
||||
for (current_pin = HW_REV_DETECT_PIN_LOW; current_pin <= HW_REV_DETECT_PIN_HIGH; current_pin++) {
|
||||
HW_REV_DETECT_GPIO->MODER &= MODER_DELETE(current_pin);
|
||||
HW_REV_DETECT_GPIO->PUPDR &= PUPDR_DELETE(current_pin);
|
||||
HW_REV_DETECT_GPIO->PUPDR |= PULLUP(current_pin);
|
||||
}
|
||||
|
||||
/* Loop again and read in the pin mask */
|
||||
for (current_pin = HW_REV_DETECT_PIN_LOW; current_pin <= HW_REV_DETECT_PIN_HIGH; current_pin++) {
|
||||
port_bitmask >>= 1;
|
||||
port_bitmask |= (HW_REV_DETECT_GPIO->IDR & (1 << current_pin)) ? 0x0 : 0x80;
|
||||
}
|
||||
|
||||
switch (port_bitmask) {
|
||||
case 0U:
|
||||
revision = HW_REV_V1_2;
|
||||
break;
|
||||
case 1U:
|
||||
revision = HW_REV_V1_3;
|
||||
break;
|
||||
default:
|
||||
revision = HW_REV_ERROR;
|
||||
}
|
||||
|
||||
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(HW_REV_DETECT_RCC_FIELD));
|
||||
|
||||
return revision;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
File diff suppressed because it is too large
Load Diff
79
stm-firmware/include/fatfs/diskio.h
Normal file
79
stm-firmware/include/fatfs/diskio.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*-----------------------------------------------------------------------/
|
||||
/ Low level disk interface modlue include file (C)ChaN, 2019 /
|
||||
/-----------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _DISKIO_DEFINED
|
||||
#define _DISKIO_DEFINED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <fatfs/ff.h>
|
||||
|
||||
/* Status of Disk Functions */
|
||||
typedef BYTE DSTATUS;
|
||||
|
||||
/* Results of Disk Functions */
|
||||
typedef enum {
|
||||
RES_OK = 0, /* 0: Successful */
|
||||
RES_ERROR, /* 1: R/W Error */
|
||||
RES_WRPRT, /* 2: Write Protected */
|
||||
RES_NOTRDY, /* 3: Not Ready */
|
||||
RES_PARERR /* 4: Invalid Parameter */
|
||||
} DRESULT;
|
||||
|
||||
|
||||
/*---------------------------------------*/
|
||||
/* Prototypes for disk control functions */
|
||||
|
||||
|
||||
DSTATUS disk_initialize (BYTE pdrv);
|
||||
DSTATUS disk_status (BYTE pdrv);
|
||||
DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
|
||||
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
|
||||
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||
|
||||
|
||||
/* Disk Status Bits (DSTATUS) */
|
||||
|
||||
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||||
#define STA_NODISK 0x02 /* No medium in the drive */
|
||||
#define STA_PROTECT 0x04 /* Write protected */
|
||||
|
||||
|
||||
/* Command code for disk_ioctrl fucntion */
|
||||
|
||||
/* Generic command (Used by FatFs) */
|
||||
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
|
||||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
|
||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
|
||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
|
||||
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
|
||||
|
||||
/* Generic command (Not used by FatFs) */
|
||||
#define CTRL_POWER 5 /* Get/Set power status */
|
||||
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
|
||||
#define CTRL_EJECT 7 /* Eject media */
|
||||
#define CTRL_FORMAT 8 /* Create physical format on the media */
|
||||
|
||||
/* MMC/SDC specific ioctl command */
|
||||
#define MMC_GET_TYPE 10 /* Get card type */
|
||||
#define MMC_GET_CSD 11 /* Get CSD */
|
||||
#define MMC_GET_CID 12 /* Get CID */
|
||||
#define MMC_GET_OCR 13 /* Get OCR */
|
||||
#define MMC_GET_SDSTAT 14 /* Get SD status */
|
||||
#define ISDIO_READ 55 /* Read data form SD iSDIO register */
|
||||
#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
|
||||
#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
|
||||
|
||||
/* ATA/CF specific ioctl command */
|
||||
#define ATA_GET_REV 20 /* Get F/W revision */
|
||||
#define ATA_GET_MODEL 21 /* Get model name */
|
||||
#define ATA_GET_SN 22 /* Get serial number */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
422
stm-firmware/include/fatfs/ff.h
Normal file
422
stm-firmware/include/fatfs/ff.h
Normal file
@@ -0,0 +1,422 @@
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT Filesystem module R0.14a /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2020, ChaN, all right reserved.
|
||||
/
|
||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||
/ source and binary forms, with or without modification, are permitted provided
|
||||
/ that the following condition is met:
|
||||
|
||||
/ 1. Redistributions of source code must retain the above copyright notice,
|
||||
/ this condition and the following disclaimer.
|
||||
/
|
||||
/ This software is provided by the copyright holder and contributors "AS IS"
|
||||
/ and any warranties related to this software are DISCLAIMED.
|
||||
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
||||
/ by use of this software.
|
||||
/
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef FF_DEFINED
|
||||
#define FF_DEFINED 80196 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ffconf.h" /* FatFs configuration options */
|
||||
|
||||
#if FF_DEFINED != FFCONF_DEF
|
||||
#error Wrong configuration file (ffconf.h).
|
||||
#endif
|
||||
|
||||
|
||||
/* Integer types used for FatFs API */
|
||||
|
||||
#if defined(_WIN32) /* Main development platform */
|
||||
#define FF_INTDEF 2
|
||||
#include <windows.h>
|
||||
typedef unsigned __int64 QWORD;
|
||||
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
|
||||
#define FF_INTDEF 2
|
||||
#include <stdint.h>
|
||||
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
|
||||
typedef unsigned char BYTE; /* char must be 8-bit */
|
||||
typedef uint16_t WORD; /* 16-bit unsigned integer */
|
||||
typedef uint32_t DWORD; /* 32-bit unsigned integer */
|
||||
typedef uint64_t QWORD; /* 64-bit unsigned integer */
|
||||
typedef WORD WCHAR; /* UTF-16 character type */
|
||||
#else /* Earlier than C99 */
|
||||
#define FF_INTDEF 1
|
||||
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
|
||||
typedef unsigned char BYTE; /* char must be 8-bit */
|
||||
typedef unsigned short WORD; /* 16-bit unsigned integer */
|
||||
typedef unsigned long DWORD; /* 32-bit unsigned integer */
|
||||
typedef WORD WCHAR; /* UTF-16 character type */
|
||||
#endif
|
||||
|
||||
|
||||
/* Definitions of volume management */
|
||||
|
||||
#if FF_MULTI_PARTITION /* Multiple partition configuration */
|
||||
typedef struct {
|
||||
BYTE pd; /* Physical drive number */
|
||||
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
|
||||
} PARTITION;
|
||||
extern PARTITION VolToPart[]; /* Volume - Partition mapping table */
|
||||
#endif
|
||||
|
||||
#if FF_STR_VOLUME_ID
|
||||
#ifndef FF_VOLUME_STRS
|
||||
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Type of path name strings on FatFs API */
|
||||
|
||||
#ifndef _INC_TCHAR
|
||||
#define _INC_TCHAR
|
||||
|
||||
#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */
|
||||
typedef WCHAR TCHAR;
|
||||
#define _T(x) L ## x
|
||||
#define _TEXT(x) L ## x
|
||||
#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */
|
||||
typedef char TCHAR;
|
||||
#define _T(x) u8 ## x
|
||||
#define _TEXT(x) u8 ## x
|
||||
#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */
|
||||
typedef DWORD TCHAR;
|
||||
#define _T(x) U ## x
|
||||
#define _TEXT(x) U ## x
|
||||
#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3)
|
||||
#error Wrong FF_LFN_UNICODE setting
|
||||
#else /* ANSI/OEM code in SBCS/DBCS */
|
||||
typedef char TCHAR;
|
||||
#define _T(x) x
|
||||
#define _TEXT(x) x
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Type of file size and LBA variables */
|
||||
|
||||
#if FF_FS_EXFAT
|
||||
#if FF_INTDEF != 2
|
||||
#error exFAT feature wants C99 or later
|
||||
#endif
|
||||
typedef QWORD FSIZE_t;
|
||||
#if FF_LBA64
|
||||
typedef QWORD LBA_t;
|
||||
#else
|
||||
typedef DWORD LBA_t;
|
||||
#endif
|
||||
#else
|
||||
#if FF_LBA64
|
||||
#error exFAT needs to be enabled when enable 64-bit LBA
|
||||
#endif
|
||||
typedef DWORD FSIZE_t;
|
||||
typedef DWORD LBA_t;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Filesystem object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fs_type; /* Filesystem type (0:not mounted) */
|
||||
BYTE pdrv; /* Associated physical drive */
|
||||
BYTE n_fats; /* Number of FATs (1 or 2) */
|
||||
BYTE wflag; /* win[] flag (b0:dirty) */
|
||||
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
|
||||
WORD id; /* Volume mount ID */
|
||||
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
|
||||
WORD csize; /* Cluster size [sectors] */
|
||||
#if FF_MAX_SS != FF_MIN_SS
|
||||
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
||||
#endif
|
||||
#if FF_USE_LFN
|
||||
WCHAR* lfnbuf; /* LFN working buffer */
|
||||
#endif
|
||||
#if FF_FS_EXFAT
|
||||
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
|
||||
#endif
|
||||
#if FF_FS_REENTRANT
|
||||
FF_SYNC_t sobj; /* Identifier of sync object */
|
||||
#endif
|
||||
#if !FF_FS_READONLY
|
||||
DWORD last_clst; /* Last allocated cluster */
|
||||
DWORD free_clst; /* Number of free clusters */
|
||||
#endif
|
||||
#if FF_FS_RPATH
|
||||
DWORD cdir; /* Current directory start cluster (0:root) */
|
||||
#if FF_FS_EXFAT
|
||||
DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
|
||||
DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
|
||||
DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
|
||||
#endif
|
||||
#endif
|
||||
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
|
||||
DWORD fsize; /* Size of an FAT [sectors] */
|
||||
LBA_t volbase; /* Volume base sector */
|
||||
LBA_t fatbase; /* FAT base sector */
|
||||
LBA_t dirbase; /* Root directory base sector/cluster */
|
||||
LBA_t database; /* Data base sector */
|
||||
#if FF_FS_EXFAT
|
||||
LBA_t bitbase; /* Allocation bitmap base sector */
|
||||
#endif
|
||||
LBA_t winsect; /* Current sector appearing in the win[] */
|
||||
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
|
||||
|
||||
/* Object ID and allocation information (FFOBJID) */
|
||||
|
||||
typedef struct {
|
||||
FATFS* fs; /* Pointer to the hosting volume of this object */
|
||||
WORD id; /* Hosting volume mount ID */
|
||||
BYTE attr; /* Object attribute */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
|
||||
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
|
||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||
#if FF_FS_EXFAT
|
||||
DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */
|
||||
DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */
|
||||
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
|
||||
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
|
||||
DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */
|
||||
#endif
|
||||
#if FF_FS_LOCK
|
||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||
#endif
|
||||
} FFOBJID;
|
||||
|
||||
|
||||
|
||||
/* File object structure (FIL) */
|
||||
|
||||
typedef struct {
|
||||
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||
BYTE flag; /* File status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
||||
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
|
||||
LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */
|
||||
#if !FF_FS_READONLY
|
||||
LBA_t dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
|
||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
|
||||
#endif
|
||||
#if FF_USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||
#endif
|
||||
#if !FF_FS_TINY
|
||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
} FIL;
|
||||
|
||||
|
||||
|
||||
/* Directory object structure (DIR) */
|
||||
|
||||
typedef struct {
|
||||
FFOBJID obj; /* Object identifier */
|
||||
DWORD dptr; /* Current read/write offset */
|
||||
DWORD clust; /* Current cluster */
|
||||
LBA_t sect; /* Current sector (0:Read operation has terminated) */
|
||||
BYTE* dir; /* Pointer to the directory item in the win[] */
|
||||
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
|
||||
#if FF_USE_LFN
|
||||
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
||||
#endif
|
||||
#if FF_USE_FIND
|
||||
const TCHAR* pat; /* Pointer to the name matching pattern */
|
||||
#endif
|
||||
} DIR;
|
||||
|
||||
|
||||
|
||||
/* File information structure (FILINFO) */
|
||||
|
||||
typedef struct {
|
||||
FSIZE_t fsize; /* File size */
|
||||
WORD fdate; /* Modified date */
|
||||
WORD ftime; /* Modified time */
|
||||
BYTE fattrib; /* File attribute */
|
||||
#if FF_USE_LFN
|
||||
TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */
|
||||
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
|
||||
#else
|
||||
TCHAR fname[12 + 1]; /* File name */
|
||||
#endif
|
||||
} FILINFO;
|
||||
|
||||
|
||||
|
||||
/* Format parameter structure (MKFS_PARM) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */
|
||||
BYTE n_fat; /* Number of FATs */
|
||||
UINT align; /* Data area alignment (sector) */
|
||||
UINT n_root; /* Number of root directory entries */
|
||||
DWORD au_size; /* Cluster size (byte) */
|
||||
} MKFS_PARM;
|
||||
|
||||
|
||||
|
||||
/* File function return code (FRESULT) */
|
||||
|
||||
typedef enum {
|
||||
FR_OK = 0, /* (0) Succeeded */
|
||||
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
|
||||
FR_INT_ERR, /* (2) Assertion failed */
|
||||
FR_NOT_READY, /* (3) The physical drive cannot work */
|
||||
FR_NO_FILE, /* (4) Could not find the file */
|
||||
FR_NO_PATH, /* (5) Could not find the path */
|
||||
FR_INVALID_NAME, /* (6) The path name format is invalid */
|
||||
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
|
||||
FR_EXIST, /* (8) Access denied due to prohibited access */
|
||||
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
|
||||
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
|
||||
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
||||
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
||||
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
||||
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
|
||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
|
||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||
} FRESULT;
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* FatFs module application interface */
|
||||
|
||||
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
||||
FRESULT f_close (FIL* fp); /* Close an open file object */
|
||||
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
|
||||
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
|
||||
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
|
||||
FRESULT f_truncate (FIL* fp); /* Truncate the file */
|
||||
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
|
||||
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
||||
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
||||
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
||||
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
|
||||
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
|
||||
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
|
||||
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
||||
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
||||
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
||||
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
|
||||
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
|
||||
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
||||
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
||||
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
||||
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
|
||||
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
|
||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||
FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */
|
||||
FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */
|
||||
FRESULT f_setcp (WORD cp); /* Set current code page */
|
||||
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
||||
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
||||
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
||||
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
|
||||
|
||||
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
|
||||
#define f_error(fp) ((fp)->err)
|
||||
#define f_tell(fp) ((fp)->fptr)
|
||||
#define f_size(fp) ((fp)->obj.objsize)
|
||||
#define f_rewind(fp) f_lseek((fp), 0)
|
||||
#define f_rewinddir(dp) f_readdir((dp), 0)
|
||||
#define f_rmdir(path) f_unlink(path)
|
||||
#define f_unmount(path) f_mount(0, path, 0)
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Additional user defined functions */
|
||||
|
||||
/* RTC function */
|
||||
#if !FF_FS_READONLY && !FF_FS_NORTC
|
||||
DWORD get_fattime (void);
|
||||
#endif
|
||||
|
||||
/* LFN support functions */
|
||||
#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */
|
||||
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
|
||||
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
|
||||
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
|
||||
#endif
|
||||
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
||||
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
||||
void ff_memfree (void* mblock); /* Free memory block */
|
||||
#endif
|
||||
|
||||
/* Sync functions */
|
||||
#if FF_FS_REENTRANT
|
||||
int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */
|
||||
int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */
|
||||
void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */
|
||||
int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Flags and offset address */
|
||||
|
||||
|
||||
/* File access mode and open method flags (3rd argument of f_open) */
|
||||
#define FA_READ 0x01
|
||||
#define FA_WRITE 0x02
|
||||
#define FA_OPEN_EXISTING 0x00
|
||||
#define FA_CREATE_NEW 0x04
|
||||
#define FA_CREATE_ALWAYS 0x08
|
||||
#define FA_OPEN_ALWAYS 0x10
|
||||
#define FA_OPEN_APPEND 0x30
|
||||
|
||||
/* Fast seek controls (2nd argument of f_lseek) */
|
||||
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
|
||||
|
||||
/* Format options (2nd argument of f_mkfs) */
|
||||
#define FM_FAT 0x01
|
||||
#define FM_FAT32 0x02
|
||||
#define FM_EXFAT 0x04
|
||||
#define FM_ANY 0x07
|
||||
#define FM_SFD 0x08
|
||||
|
||||
/* Filesystem type (FATFS.fs_type) */
|
||||
#define FS_FAT12 1
|
||||
#define FS_FAT16 2
|
||||
#define FS_FAT32 3
|
||||
#define FS_EXFAT 4
|
||||
|
||||
/* File attribute bits for directory entry (FILINFO.fattrib) */
|
||||
#define AM_RDO 0x01 /* Read only */
|
||||
#define AM_HID 0x02 /* Hidden */
|
||||
#define AM_SYS 0x04 /* System */
|
||||
#define AM_DIR 0x10 /* Directory */
|
||||
#define AM_ARC 0x20 /* Archive */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FF_DEFINED */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user