Compare commits

..

203 Commits

Author SHA1 Message Date
5c429ec894 Remove trailing whitespace 2024-03-24 14:13:56 +01:00
62ef147105 Incrment Cmake required version number 2024-03-24 14:11:33 +01:00
c6038969ca Fix style and code issues in bin2carray python script 2023-06-23 22:43:45 +02:00
0c8a0cd562 Fix watchdog tcode to write correct reload value 2023-06-09 00:12:41 +02:00
1300fe88a4 Shorten wtchdog trigger interval to 1.25 seconds nominal. This will ensure the internal watchdog triggers before the external one 2023-06-09 00:04:32 +02:00
df593e2ab2 Merge pull request 'misc-crc-monitor' (#55) from misc-crc-monitor into dev
Reviewed-on: #55
2023-05-23 19:07:21 +02:00
34ad930bd8 Fix mask for misc crc cfg monitor 2023-05-23 19:03:50 +02:00
1c1874abf1 Make safety flag ERR_FLAG_CFG_CRC_MISC trigger panic mode 2023-05-23 18:46:27 +02:00
fd2994f9b9 Add err flag cfg crc misc to flag list 2023-05-23 18:32:03 +02:00
b6befa70a2 Implement misc CRC monitor to supervise clocks and other system settings 2023-05-23 18:30:27 +02:00
dd6a7bef18 Merge pull request 'Pre-Release v0.5' (#54) from dev into master
Reviewed-on: #54
2023-01-03 16:37:53 +01:00
a005afaa13 Merge pull request 'Update FatFS in Firmware and Updater RAM Blob' (#53) from update-fatfs into dev
Reviewed-on: #53
2023-01-03 16:32:21 +01:00
cadd33d5a4 #48: Update FatFS in RAM code of updater 2023-01-03 15:08:57 +01:00
da132028b1 Issue #48: Update FatFS of main firmware to R0.15 2023-01-03 15:02:48 +01:00
2cd4847a57 Merge pull request 'version-rework' (#52) from version-rework into dev
Reviewed-on: #52
2023-01-01 21:23:32 +01:00
e335cb42ac Add comment to cmake build step 2023-01-01 21:16:36 +01:00
34c1c3db4e Rework UI to use newly created version handling 2023-01-01 21:12:19 +01:00
df70238b36 Remove git_ver define from updater 2023-01-01 21:12:00 +01:00
2c2e4c1484 Add compile date and time to version.c 2023-01-01 21:07:10 +01:00
767aa75c25 Make git a required build dependency 2023-01-01 21:04:03 +01:00
745e7db78f Add version c file that includes a generated file during build 2023-01-01 21:02:49 +01:00
9c0cbb107b Add script to generate header file containing version and commit hash 2023-01-01 20:45:57 +01:00
d48ccf1612 Fix #50: Enable core cycle counter 2023-01-01 20:18:39 +01:00
fd12faff75 Merge pull request 'Update develop. Ready for pre-release v0.4' (#49) from dev into master
Reviewed-on: #49
2022-12-31 20:39:51 +01:00
5ad1d574ff Fix #46: Fix update bug of GUI. Works now 2022-12-31 20:38:22 +01:00
f95ad1729e Fix buf on sd mounting handling 2022-12-31 20:29:22 +01:00
b18186423f Fix #46: Add SD status to GUI 2022-12-31 20:22:41 +01:00
ec2d3da4cb Add missing header file required for memset() 2022-12-31 20:22:08 +01:00
5e00441d99 Add separate source file handling the mounting of the SD card. This will give proper access to the GUI to check whether an SD is mounted 2022-12-31 20:18:34 +01:00
e91b33f379 Remove old CRC patcher 2022-12-31 19:56:33 +01:00
b621c66378 Update Flag Weights
* Fix #47: Update flash and data CRCs to trigger panic mode
* Update meas ADC CRC flag to stop PID
* Update safety ADC CRC flag to trigger panic mode
2022-12-31 19:53:45 +01:00
8ff402caaa Merge branch 'dev' of git.shimatta.de:mhu/reflow-oven-control-sw into dev 2022-12-31 19:43:41 +01:00
aade3288eb Update doxygen headers in config parser 2022-12-31 19:43:37 +01:00
049afbd66f Merge pull request 'Use patchelfcrc program for CRC patching.' (#45) from port-to-patchelfcrc into dev
Reviewed-on: #45
2022-12-31 19:42:54 +01:00
240b1ffc8f Update gitignore for use with vscode and clangd 2022-12-31 19:25:55 +01:00
f46044e5fc Remove mthumb-interwork from GCC command line. It is not neededfor CM4 cores 2022-12-31 19:24:27 +01:00
354c26ca67 Change Build step to use pathcelfcrc program instead of python script 2022-10-25 21:23:02 +02:00
6570d217c7 Separate flash CRC checker from safety controller and implement shell command to calculate CRCs 2022-09-22 21:16:41 +02:00
aeffb9df99 Update C file generator script 2022-09-22 21:16:07 +02:00
ad3de6e6b7 Improve HW version detect code. Funtionally equivalent 2022-08-09 00:23:55 +02:00
ab5fd6433e Rename python file to snake case 2022-08-09 00:23:23 +02:00
35542f56cb Add pylintrc and fix style problems in crc patcher 2022-08-09 00:21:57 +02:00
f9b9a3c685 Add compile error for configuration mistake 2022-07-30 16:45:26 +02:00
aaed95cc95 Restructure safety handle function. Now returns worst flag state set. Used to blink LED 2022-07-30 16:04:46 +02:00
6ac108e1b2 make LED blink if error that stop the PID are present 2022-07-30 15:53:04 +02:00
7a36b597be Add comment to function 2022-07-30 15:52:47 +02:00
00b8d1f48e Fix style issues in config-parser.c 2022-07-16 15:14:35 +02:00
8ac1d52240 Fix style issues in spi-eeprom.c/h 2022-07-16 15:09:41 +02:00
3e82cf69b4 Fix style in settings-sd-card.c 2022-07-16 15:07:33 +02:00
62b256fd18 Fix style in settings-sd-card.c 2022-07-16 15:07:01 +02:00
74111826a0 Fix style in settings-eeprom.c 2022-07-16 15:04:09 +02:00
69d7724c8f Fix style problems in settings.c 2022-07-16 14:46:44 +02:00
48f69d0fb5 Fix style issues in watchdog.c 2022-07-16 14:44:55 +02:00
8fd924829e Fix style problems in stack-check.c 2022-07-16 14:43:29 +02:00
ba8072c21d Fix style problems in safety-memory.c 2022-07-16 14:40:54 +02:00
5ddae7efee Fiy style issues 2022-07-16 13:01:38 +02:00
14ea4d22fe Fix style issues in STM peripheral drivers 2022-07-16 12:46:52 +02:00
d5780500f3 Update C-style checker 2022-07-16 12:38:37 +02:00
d4d654e8dd Add additional debug info to version command and add CPU cycle counter to cc instruction's output 2022-07-13 19:47:16 +02:00
8a62ed2ea7 Fix wrong short shell command for setting baudrate 2022-06-09 18:44:39 +02:00
7d43b4130c Add connector info to LCD GUI. So TX and RX of UART can be found without looking at the schematic. 2022-06-09 18:18:30 +02:00
835faf7e4e Merge pull request 'enhancement/39-digio-cmd-profile-language' (#44) from enhancement/39-digio-cmd-profile-language into dev
Reviewed-on: #44
2021-12-26 21:20:15 +01:00
2957a42cef Fix indetation in header file 2021-12-26 20:59:08 +01:00
1e45c8b5d7 Issue #39: Implement DIGIO profile commands 2021-12-26 20:54:04 +01:00
3bb4607798 digio: Make digio check if an port to set is an output port. 2021-12-26 20:40:28 +01:00
a8a622df25 Make temperture profile executer reset the DIGIO settings after profile execution/abort 2021-12-26 20:36:49 +01:00
45f91a7c5a Add commands for DIGIO channels to profile parser and add base construct to the profile interpreter 2021-12-26 20:27:20 +01:00
bf6a222c9d Merge branch 'feature/42-update-fatfs' of mhu/reflow-oven-control-sw into dev 2021-12-16 20:55:34 +01:00
ef534746f8 Update updater to newest fatfs and enable exfat support 2021-12-16 20:47:08 +01:00
8cd47aeed5 Add new FatFS implementation 2021-12-16 20:41:10 +01:00
1291b0fb6a Add FatFS license 2021-12-16 20:28:39 +01:00
b6a2790a59 cleanup code and write a little documentation 2021-11-28 23:40:43 +01:00
7bfa0732db Fix wrong register bit in flash writer. This actually didn't result in an error but it's better to fix it either way. 2021-11-28 23:11:40 +01:00
0dace23021 Bugfix: Fix null pointer access in temp profile parser 2021-11-27 19:24:51 +01:00
c78477296a Bugfix: Fix hardfault when update menu is opened and no hex file is located on disk 2021-11-27 18:47:17 +01:00
96e0931c9f Add a bunch of stuff: Add baudrate reconfig command to shell and move the uart to separate C file 2021-11-27 17:41:11 +01:00
6b9b7d78a0 Add v1.3.1 to supported hardware revisions 2021-10-24 21:59:44 +02:00
22bb227bc7 Add a few comments 2021-10-24 14:50:07 +02:00
78f24f7338 Add LCD output to shell function 'Emulate UI' 2021-10-24 14:47:52 +02:00
e3a552248d Make a wrong size of the flashcrc struct an error becuase it might lead to misaligned CRCs in the structure 2021-10-23 21:26:01 +02:00
288b19c4fc Comment functions 2021-10-23 21:18:32 +02:00
56872086fa Comment code 2021-10-23 21:14:24 +02:00
fe0e8136d4 Refactor temperature profile executer 2021-10-23 21:00:21 +02:00
73606bf7a0 Write documentation for the config parser 2021-10-23 20:54:37 +02:00
78501143cc Fix wrongly typed float literal 2021-10-23 20:54:20 +02:00
bb0ea908cb Merge branch 'brown-out-detection' into dev 2021-10-17 12:52:59 +02:00
61cb92fbe8 Add command for printing option bytes 2021-10-17 12:30:58 +02:00
eb41e5e210 Implement option byte writing and set brown out level 2021-10-16 23:39:23 +02:00
decb484d06 Start implementation of option byte manipulation 2021-10-16 00:44:39 +02:00
4009a2794d Add STM device resvision to MOTD. 2021-10-15 22:06:30 +02:00
d9c145ec81 Fix some coding issues and a possible race condition 2021-10-15 21:16:26 +02:00
6fde4cfd66 Improve doxygen comments in code. 2021-10-11 19:45:13 +02:00
c82ca7d8f0 Merge branch 'jenkins' into dev 2021-10-10 22:41:00 +02:00
2bc2c0c670 Add example jenkins file 2021-10-10 22:38:58 +02:00
aad9be9905 Add doxygen to CMake and update the config 2021-10-10 22:09:46 +02:00
6f2b6e0839 Fix code in updater.c 2021-10-10 21:04:40 +02:00
45145c1f36 Clean up systick.c 2021-10-10 21:02:39 +02:00
1722ba7e5d Clean up shell.c 2021-10-10 21:00:28 +02:00
7a44a383ff Fix style in file 2021-10-10 20:49:42 +02:00
7a2c77a83e Fix style problems in main-cycle-counter 2021-10-10 20:47:15 +02:00
c8e3bf5de2 Fix style problems in main.c 2021-10-10 20:45:59 +02:00
400c77f11c Update c style checker 2021-10-10 20:42:15 +02:00
7be6047e04 Fix style warnings 2021-10-10 20:40:40 +02:00
2ab7257fe6 Remove unneeded parameter from fuction 2021-10-09 22:59:35 +02:00
376d9c7aaf Merge branch 'dev' of git.shimatta.de:mhu/reflow-oven-control-sw into dev 2021-10-03 19:38:47 +02:00
2a6a98deac Merge branch 'feature/41-updater-sha256-check' into dev 2021-10-03 19:38:31 +02:00
20b460cd5a Fix #41: Updater SHA256 check implemented and tested 2021-10-03 19:38:01 +02:00
ae60c30919 Implement SHA256 update file checking 2021-10-03 19:27:41 +02:00
c6fcd3154f Remove unneeded variable 2021-10-03 18:51:14 +02:00
a7394ef170 Feature #41: Add SHA calculation to updater. Has yet to be checked against file. Code not tested 2021-09-24 22:43:47 +02:00
01abb3e085 Delete unnecessary code for testing CRCs 2021-09-21 10:14:25 +02:00
d63761d016 Add sha 256 library and adapt license sections in documentation 2021-08-24 22:19:12 +02:00
d468e52dea Merge branch 'feature/40-fir-filter' into dev 2021-08-24 21:51:20 +02:00
5a1deeb9ee Reformat code 2021-08-24 21:50:57 +02:00
809c86a618 Add shell command to change filter alpha 2021-08-24 21:50:36 +02:00
88a4bb97a5 Remove fior filter again... Not needed. 2021-08-24 21:49:23 +02:00
4a98d41623 Add sample data and jupyter notebook containing filter analysis 2021-08-24 21:48:04 +02:00
836c7af163 Merge branch 'dev' into feature/40-fir-filter 2021-08-19 21:47:11 +02:00
e3670434ca Add FIR filter code 2021-08-19 21:44:50 +02:00
a802b5c1b5 Add main cylcle counter and increase filter alpha for PT1000 to 0.01 2021-08-19 21:25:04 +02:00
ffb544e21d Merge branch 'issue/37-crc-flags-config-regs' into dev 2021-07-23 20:06:35 +02:00
e4ebf9ec3f Add CRC monitoring over ADC registers 2021-07-23 20:06:09 +02:00
6e89c0e098 Update error memory viewer to newest memory structure 2021-07-19 22:44:13 +02:00
fdb1c6e893 Fix memory checking. The stack is now completely copied to CCMRAM before testing the main memory. 2021-07-19 22:29:13 +02:00
e753504ae3 Check for python in RAM code and use find_package to determine the python interpreter 2021-07-17 15:25:25 +02:00
2fa12cda60 Throw error in case the python virtualenv cannot be found 2021-07-17 15:12:45 +02:00
17609a2491 Add automatic flash CRC patching to cmake 2021-07-16 21:57:30 +02:00
1e870972e3 Improve code and add a Flash CRC check 2021-07-16 21:17:59 +02:00
864c3fa0f2 Fix bug in handling of error memory NOP entries 2021-07-16 17:29:04 +02:00
9c872f6746 Improve documentation and beatify pieces of code 2021-07-15 19:50:14 +02:00
0bf587b8bb Add documentation in rst for PID 2021-07-15 00:21:14 +02:00
8a9bd0df6e Add documentation for reflow controller 2021-07-15 00:20:03 +02:00
baf6b67658 Fix #35: List with updae filename was freed before it was used. This is now fixed and working 2021-07-13 21:05:00 +02:00
41fbb83b46 Fix #34: Broken PID derivate term calculation. Sign error fixed 2021-07-13 20:32:12 +02:00
f4fcaf1e3a Start documentation of PID controller 2021-06-14 23:16:07 +02:00
67932bf465 Fix aligment problems in Linkerscript 2021-05-24 12:38:37 +02:00
632973cdac Update docu about calibration 2021-05-22 17:52:55 +02:00
9558d4bb45 Write hardware documentation 2021-05-22 17:36:09 +02:00
90c6165278 Move push button and rotary encoder files to UI folder 2021-05-22 17:05:56 +02:00
8c0cfa4993 Doxygen headers 2021-05-22 17:02:37 +02:00
5f91659d04 Doxygen headers 2021-05-22 16:46:26 +02:00
fdb3ceb3e9 Restructuring and comments 2021-05-22 16:40:08 +02:00
7e3d2d1d0b Expand documentation 2021-05-22 15:27:55 +02:00
ef2cd6acfe Change doxygen config 2021-05-22 15:26:39 +02:00
d9bd434dc6 Fix indent 2021-05-22 12:45:46 +02:00
4ed2203b35 Improve code style and comments 2021-05-22 12:44:43 +02:00
0b1ce8b614 Fix #32:
* Implement clear flags command for profile language.
2021-05-22 12:13:43 +02:00
bc5e4c14df Issue #5: Implement startup screen in case apanic happened and prevent the PID controller from starting when a watchdog reset has occured 2021-05-22 11:59:54 +02:00
43abca4c51 Merge branch 'memory-test' into dev 2021-05-22 11:41:45 +02:00
00c796c58f Merge branch 'memory-test' of mhu/reflow-oven-control-sw into dev 2021-05-22 11:41:22 +02:00
4d0f963585 Merge branch 'dev' into memory-test 2021-05-22 11:35:03 +02:00
708fdea058 Add static blocking write function to gui. This allows us to set a updating... status on the display when starting the updater. 2021-05-22 11:34:33 +02:00
ebb1383957 Write memory test for system RAM 2021-05-22 11:25:55 +02:00
3345004213 Merge branch 'dev' into memory-test 2021-05-22 00:23:18 +02:00
afadd539c8 Merge branch '28-update-notification' of mhu/reflow-oven-control-sw into dev 2021-05-22 00:17:01 +02:00
71315b7c92 Issue #28: Implement update successful notification. 2021-05-22 00:14:56 +02:00
410a5d4dd1 Change -Og to -O0 because it made a lot of problems when debugging 2021-05-22 00:13:07 +02:00
528db7a581 Fix error in CCM Ram test 2021-05-22 00:06:51 +02:00
384e127085 Add first draft of memory checking for CCM RAM 2021-05-20 23:55:32 +02:00
fe0bde5c32 Fix wrong string constant 2021-05-20 23:54:42 +02:00
2beaccbe32 Fix typo in comment 2021-05-20 23:54:21 +02:00
b6760ff426 Merge branch 'issue/24-update-could-fail' of mhu/reflow-oven-control-sw into dev 2021-05-16 20:41:56 +02:00
1b2dac21f2 Merge branch 'issue/25-add-update-to-gui' of mhu/reflow-oven-control-sw into dev 2021-05-16 20:40:39 +02:00
97f154d3b9 Add working reflow profile so it isn't lost by accident 2021-05-16 20:38:17 +02:00
ee5dda4a33 Issue #25: Add update menu to GUI 2021-05-16 20:34:09 +02:00
afb8e93b13 Rework function for finding temperature profiles to be able to search for any pattern 2021-05-16 19:57:08 +02:00
9bd0dd194b Issue #24: Fix bug in update code 2021-05-16 19:53:46 +02:00
6322c3728b Use singly linked list to store profile commands. 2021-05-15 21:58:00 +02:00
174bf4220e Remove unused function 2021-05-15 21:57:23 +02:00
566436201e Increase heap size 2021-05-15 21:56:33 +02:00
61e3b58992 Use singly linked list dfor temperature profile file list 2021-05-07 22:09:55 +02:00
01b445a0fb Update linked list library and include it into build 2021-04-10 22:35:30 +02:00
5437a323c3 Add linklist submodule 2021-04-10 22:29:18 +02:00
28e42d3306 Shell: Update: Print error if no update file name is specified 2021-04-10 22:28:30 +02:00
08606689b4 Update fatfs in main application 2021-04-10 20:35:33 +02:00
5776feee85 Merge branch 'dev' of git.shimatta.de:mhu/reflow-oven-control-sw into dev 2021-04-10 20:13:29 +02:00
6273c68821 Shell update command: Take file name as argument 2021-04-10 20:09:52 +02:00
3381840bba Modify git version generation in cmake 2021-04-10 20:09:15 +02:00
cf35ba735f Modify git version generation in cmake 2021-04-10 19:40:49 +02:00
3f31acfada Updater: Fix missing line break in uart output 2021-04-10 15:42:19 +02:00
77251cc1bc increase stack and heap sizes 2021-04-10 14:44:27 +02:00
f2972903d5 Use safer string copying in gui for file list 2021-04-10 14:37:51 +02:00
31b17dfd8d Updater: Clear shell at startup and print size of update 2021-04-10 14:37:05 +02:00
9f1a791be2 Remove custom option checker and use the one of the shellmatta instead 2021-04-10 14:10:17 +02:00
54416a6350 Edit Cmake file to use ENV variable to device if Uart is on debug header or not 2021-04-10 13:45:00 +02:00
9c94428144 Bugfix: button ready state not correctly detected when menu drops back 2021-04-10 13:24:15 +02:00
81155887de Bug: Fix missing variable in printf varargs for gui 2021-04-10 13:11:35 +02:00
8309cef5ec Updater: Fix updating code 2021-04-08 22:03:38 +02:00
1a76a69b6d Switch updater to -Os compilation 2021-04-08 21:50:42 +02:00
e50e3f0ace Add verify step to updater 2021-04-08 21:49:53 +02:00
5fb1612773 make updater reboot after successful update 2021-04-08 21:37:49 +02:00
72735915ee Clear code updated status flag upon startup 2021-04-08 21:35:19 +02:00
08ec458e8f Add update code to updater and use uart for status updates 2021-04-08 21:23:25 +02:00
d962110823 Updater: Use -O0 and write flash writer and fix hex parser 2021-04-07 23:14:45 +02:00
bfdc3d3246 Updater: Store update file name in safety memory before executing updater. Currently name is hardcoded. 2021-04-07 13:26:39 +02:00
dca839ce2e Merge branch 'dev' into updater 2021-04-07 13:19:53 +02:00
eea0826c7b updater: Add function to safety memory for storing the update file name 2021-04-07 13:19:16 +02:00
6e5627fde2 Updater: Add safety memory to updater 2021-04-06 20:55:41 +02:00
0f239dc39d Fix warning in temp profile parser 2021-04-06 20:53:18 +02:00
08eee66d30 Issue #28: Change GUI of profile executer 2021-04-06 19:46:31 +02:00
7c9d296e34 Merge branch 'dev' into feature/28-profile-parser 2021-04-06 19:45:37 +02:00
533656ca28 Add Cmake variable for Uart on debug header in release and use -Og for debugbuild instead of -O0 2021-04-06 19:25:25 +02:00
d146b10569 Issue #28: Inmprove GUI of profile executer 2021-04-06 19:23:45 +02:00
147 changed files with 13937 additions and 3830 deletions

3
.gitmodules vendored
View File

@ -10,3 +10,6 @@
path = stm-firmware/base64-lib path = stm-firmware/base64-lib
url = https://git.shimatta.de/mhu/base64-lib.git url = https://git.shimatta.de/mhu/base64-lib.git
branch = master 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
View 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.

21
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,21 @@
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building..'
}
}
stage('Test') {
steps {
echo 'Testing..'
}
}
stage('Deploy') {
steps {
echo 'Deploying....'
}
}
}
}

View File

@ -1,361 +1,10 @@
### GNU GENERAL PUBLIC LICENSE # License of the Relow Oven Control Firmware
Version 2, June 1991 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:
Copyright (C) 1989, 1991 Free Software Foundation, Inc. - Shellmatta Shell implementation by Stefan Strobel: Licensed under ``Mozilla Public License Version 2.0``
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - 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.
Everyone is permitted to copy and distribute verbatim copies - FatFs: Custom License (See source files of FatFS)
of this license document, but changing it is not allowed. - SHA256 Library <https://github.com/amosnier/sha-2> licensed under the ``Unilicense``
### 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.

@ -1 +1 @@
Subproject commit 3a58e3dd1c2ef6de78df89c8fdc7ba96b51cd4e0 Subproject commit aeb2707d80049094337742d0f62cd24dbef1c01d

3
doc/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"restructuredtext.confPath": "${workspaceFolder}/source"
}

3
doc/source/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"restructuredtext.confPath": "${workspaceFolder}"
}

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

View File

@ -9,6 +9,3 @@ Safety Controller
safety-adc safety-adc
.. doxygengroup:: safety-controller
:project: Reflow Controller Firmware

View 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

View File

@ -11,6 +11,8 @@ mechanisms and the behavior. For a detailed code documentation see the doxygen o
:maxdepth: 2 :maxdepth: 2
pt1000-processing pt1000-processing
pid-controller
safety/index safety/index
code/index code/index
hw-version-detect
peripherals

View File

@ -0,0 +1,44 @@
.. _peripherals:
Used Peripheral Modules
=======================
This section lists all the used peripheral modules of the ``STM32F407VxT6``.
Core Peripherals
----------------
- ``SysTick``: Generating a 100us tick for the LCD routine and 1ms base system tick.
- ``NVIC``: Interrupt controller
- ``FPU``: The Flaoting Point Unit is activated and used in this formware.
AHB Peripherals
---------------
- ``DMA2``
- ``Stream0``: DMA transfer of PT1000 measurement ADC to memory
- ``Stream4``: DMA transfer of Safety ADC measurement values
- ``Stream5``: Shell UART RX
- ``Stream7``: Shell UART TX
- ``RNG``: Random number generation for stack corruption / overflow checker.
- ``CRC``: CRC verfication of various data (Safety structures, EEPROM data, Safety RAM)
- ``Backup RAM``: Backup RAM storing errors and bootloader information beyond system resets. The memory is cleared by a power cycle!
ABP1 Peripherals
----------------
- ``IWDG``: Independent Watchdog
- ``TIM2``: PT1000 measurement ADC sample time generation timer. Genewrates the 1 KHz sample trigger to the ADC peripheral via the internal event routing system.
- ``TIM3``: PWM timer for oven relais output.
- ``TIM5``: Input capture for rotary encoder.
- ``TIM7``: Timer for loudspeaker tone generation.
APB2 Peripherals
----------------
- ``SPI1``: SPI for external SPI-EEPROM
- ``SDIO``: SD card interface
- ``USART1``: Shell UART
- ``ADC1``: Safety ADC for monitoring voltages
- ``ADC3``: PT1000 measurement ADC

View 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

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

View File

@ -120,19 +120,7 @@ are used to set the resistance calibration internally. For a guide on how to cal
The calibration is calculated the following way: The calibration is calculated the following way:
.. blockdiag:: .. drawio-image:: calibration.drawio
:desctable:
blockdiag {
orientation = portrait;
LF [label="LF", shape=beginpoint, description="Low Frequency PT1000 Value"];
SENS [label="Sens", description="Sensitivity Correction :math:`\sigma`"];
OFFSET [label="Offset", description="Offset Correction :math:`O`"];
OUT [shape=endpoint, description="Corrected Value"];
LF -> OFFSET -> SENS -> OUT
}
The final calibrated PT1000 resistance is calculated as: The final calibrated PT1000 resistance is calculated as:
@ -141,11 +129,11 @@ The final calibrated PT1000 resistance is calculated as:
The default values, if no calibration is loaded / executed, are: The default values, if no calibration is loaded / executed, are:
============== ========= ======== =====================
:math:`\sigma` :math:`O` Offset Sensitivity Deviation
============== ========= ======== =====================
0 0 0 0
============== ========= ======== =====================
Get Calibration Corrected Value Get Calibration Corrected Value
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -21,4 +21,5 @@ which are used to retain boot information across resets, for example to communic
flags flags
backup-ram backup-ram
error-handling error-handling
startup-tests
stack-checking stack-checking

View 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

View 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.

View File

@ -3,7 +3,7 @@
Hardware Hardware
======== ========
This guide on the reflow controller's hardware is based on the ``reflow-oven-control-pcb`` -- Version ``v1.2`` This guide on the reflow controller's hardware is based on the ``reflow-oven-control-pcb`` -- Version ``v1.3``
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2

View File

@ -1,7 +1,7 @@
.. _hardware_modifications: .. _hardware_modifications_v1_2:
Hardware Modifications Hardware Modifications for PCB v1.2
====================== ===================================
Analog Frontend Analog Frontend
--------------- ---------------
@ -13,3 +13,11 @@ Power Supply
------------ ------------
.. note:: .. 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. 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.

View File

@ -10,7 +10,8 @@ Quick Links
=========== ===========
* :ref:`genindex` * :ref:`genindex`
* :ref:`hardware_modifications` * :ref:`hardware_modifications_v1_2`
* :ref:`hardware_modifications_v1_3`
.. warning:: .. 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. 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.

View File

@ -9,8 +9,36 @@ 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`` - ``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`` - ``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_>`_ - ``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 ST License for Used Header Files
-------------------------------- --------------------------------

View 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

View File

@ -21,6 +21,7 @@ struct safety_memory_header {
uint32_t boot_status_offset; /**< @brief Offset of the safety_memory_boot_status struct (in 32 bit words)*/ 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_offset; /**< @brief Offset address of override entries */
uint32_t config_overrides_len; /**< @brief Length of override entries in words */ 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_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 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 */ uint32_t crc; /**< @brief CRC of the header */

View File

@ -1,12 +1,11 @@
#include <error-mem-viewer/crc.h> #include <error-mem-viewer/crc.h>
uint32_t do_crc(uint32_t init, uint32_t data) static uint32_t do_crc(uint32_t init, uint32_t data)
{ {
uint32_t crc = init; uint32_t crc = init;
uint32_t cnt; uint32_t cnt;
for(cnt=0; cnt < 32; cnt++) for (cnt=0; cnt < 32; cnt++) {
{
crc = ((int32_t)(crc ^ data))<0 ? (crc << 1) ^ 0x04C11DB7 : crc << 1; crc = ((int32_t)(crc ^ data))<0 ? (crc << 1) ^ 0x04C11DB7 : crc << 1;
data <<=1; data <<=1;
} }
@ -18,7 +17,7 @@ uint32_t calculate_stm_crc(uint32_t *data, size_t len)
{ {
uint32_t crc = ~0U; uint32_t crc = ~0U;
while(len--) { while (len--) {
crc = do_crc(crc, *data++); crc = do_crc(crc, *data++);
} }

View File

@ -214,16 +214,21 @@ static void show_error_memory(GtkTreeView *tree_view, const unsigned char *memor
valid = true; valid = true;
break; break;
case 4: 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; header.err_memory_offset = dat;
interpret = new_string_printf("Error memory offset addr: %u", dat); interpret = new_string_printf("Error memory offset addr: %u", dat);
valid = true; valid = true;
break; break;
case 5: case 6:
header.err_memory_end = dat; header.err_memory_end = dat;
interpret = new_string_printf("Error memory end ptr: %u", dat); interpret = new_string_printf("Error memory end ptr: %u", dat);
valid = true; valid = true;
break; break;
case 6: case 7:
header.crc = dat; header.crc = dat;
valid = check_err_mem_header(&header, &expected_value); valid = check_err_mem_header(&header, &expected_value);
if (valid) { if (valid) {
@ -235,7 +240,7 @@ static void show_error_memory(GtkTreeView *tree_view, const unsigned char *memor
} }
break; break;
} }
if (i <= 6) { if (i <= 7) {
state = ENTRY_STATE_INVALID; state = ENTRY_STATE_INVALID;
goto print; goto print;
} }

View File

@ -422,6 +422,13 @@
"print(calc_temp(2000))\n", "print(calc_temp(2000))\n",
"print(calc_temp(2000+adc_min_res))" "print(calc_temp(2000+adc_min_res))"
] ]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
} }
], ],
"metadata": { "metadata": {
@ -440,7 +447,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.9.1" "version": "3.9.6"
} }
}, },
"nbformat": 4, "nbformat": 4,

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -16,3 +16,10 @@ reflow-controller.includes
*.files *.files
*.user.* *.user.*
*.user *.user
# VSCODE and CLANGD sepcific excludes
.vscode/
build/
.cache/
compile_commands.json

View File

@ -1,7 +1,7 @@
set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_CROSSCOMPILING 1) set(CMAKE_CROSSCOMPILING 1)
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.18)
set(CMAKE_TOOLCHAIN_FILE "arm-none-eabi-gcc.cmake") set(CMAKE_TOOLCHAIN_FILE "arm-none-eabi-gcc.cmake")
@ -27,37 +27,63 @@ if(NOT WIN32)
set(BoldWhite "${Esc}[1;37m") set(BoldWhite "${Esc}[1;37m")
endif() endif()
execute_process(COMMAND bash -c "echo -n $(git describe --always --tags --dirty)" find_package(Git)
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} if (GIT_FOUND)
OUTPUT_VARIABLE GIT_DESCRIBE) 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)
message("${BoldRed}No git installation found. It is highly recommended using git to generate the version number")
message(FATAL_ERROR "Git is required")
endif (GIT_FOUND)
find_program(PATCHELFCRC patchelfcrc)
if (PATCHELFCRC)
message("patchelfcrc found: ${PATCHELFCRC}")
else(PATCHELFCRC)
message(FATAL_ERROR "${BoldRed}Patchelfcrc not found. Cannot patch CRC checksum into ELF file: patchelfcrc: command not found! See: https://git.shimatta.de/mhu/patchelfcrc${ColorReset}")
endif (PATCHELFCRC)
set(ELFFILE ${PROJECT_NAME}.elf) 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) 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(-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) add_compile_options(-mlittle-endian -mthumb -mcpu=cortex-m4 -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=\"?\" -DHSE_VALUE=8000000UL -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4)
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) add_subdirectory(updater/ram-code)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
message("${BoldGreen}Version: ${GIT_DESCRIBE}${ColorReset}")
IF(CMAKE_BUILD_TYPE STREQUAL "Debug") IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DDEBUGBUILD) add_definitions(-DDEBUGBUILD)
add_compile_options(-O0 -g) add_compile_options(-O0 -g)
add_link_options(-Wl,-Map=${MAPFILE})
ELSE() ELSE()
add_definitions(-DDEBUGBUILD) add_compile_options(-O3 -g)
add_compile_options(-O3 -g) add_link_options(-Wl,--gc-sections)
add_link_options(-Wl,--gc-sections)
ENDIF(CMAKE_BUILD_TYPE STREQUAL "Debug") ENDIF(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_subdirectory(base64-lib)
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("." MAIN_SOURCES)
aux_source_directory("config-parser" CFG_PARSER_SRCS) aux_source_directory("config-parser" CFG_PARSER_SRCS)
@ -71,16 +97,49 @@ aux_source_directory("settings" SETTINGS_SRCS)
aux_source_directory("safety" SAFETY_SRCS) aux_source_directory("safety" SAFETY_SRCS)
aux_source_directory("shellmatta/src" SHELLMATTA_SRCS) aux_source_directory("shellmatta/src" SHELLMATTA_SRCS)
aux_source_directory("updater" UPDATER_SRCS) aux_source_directory("updater" UPDATER_SRCS)
aux_source_directory("temp-profile" PROFILE_SRCS)
set(GEN_VERSION_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/include/generated-version")
add_custom_target(
generate-version-header
COMMAND mkdir -p ${GEN_VERSION_HEADER_PATH} && bash "${CMAKE_CURRENT_SOURCE_DIR}/create_version_header.sh" "${GEN_VERSION_HEADER_PATH}/version.h"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Generating version number using git"
)
add_executable(${ELFFILE} ${MAIN_SOURCES} ${CFG_PARSER_SRCS} ${UI_SRCS} add_executable(${ELFFILE} ${MAIN_SOURCES} ${CFG_PARSER_SRCS} ${UI_SRCS}
${FAT_SRCS} ${SDIO_SRCS} ${BOOT_SRCS} ${SETUP_SRCS} ${FAT_SRCS} ${SDIO_SRCS} ${BOOT_SRCS} ${SETUP_SRCS}
${STM_PERIPH_SRCS} ${SETTINGS_SRCS} ${SAFETY_SRCS} ${SHELLMATTA_SRCS} ${UPDATER_SRCS} ${STM_PERIPH_SRCS} ${SETTINGS_SRCS} ${SAFETY_SRCS}
${SHELLMATTA_SRCS} ${UPDATER_SRCS} ${PROFILE_SRCS}
) )
add_dependencies(${ELFFILE} updater-ram-code-header-blob) add_dependencies(${ELFFILE} updater-ram-code-header-blob generate-version-header)
target_include_directories(${ELFFILE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/shellmatta/api ${CMAKE_CURRENT_SOURCE_DIR}/config-parser/include) 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_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -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) target_link_libraries(${ELFFILE} base64-lib linklist-lib)
target_include_directories(${ELFFILE} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/updater/ram-code/include/") target_include_directories(${ELFFILE} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/updater/ram-code/include/" "${CMAKE_CURRENT_BINARY_DIR}/include/")
add_custom_command(
TARGET ${ELFFILE}
POST_BUILD
COMMAND ${PATCHELFCRC} --little-endian --verbose --granularity word --start-magic 0xa8be53f9 --end-magic 0xffa582ff -O .flashcrc -p crc-32-mpeg -S .text -S .data -S .ccmdata -S .vectors "${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
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"
)

View File

@ -82,6 +82,8 @@ static inline void adc_pt1000_disable_adc(void)
ADC_PT1000_PERIPH->CR2 &= ~ADC_CR2_ADON; ADC_PT1000_PERIPH->CR2 &= ~ADC_CR2_ADON;
DMA2_Stream0->CR = 0; DMA2_Stream0->CR = 0;
safety_controller_set_crc_monitor(ERR_CRC_MON_MEAS_ADC, SAFETY_CRC_MON_MEAS_ADC_PW);
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_OFF, MEAS_ADC_SAFETY_FLAG_KEY);
safety_controller_enable_timing_mon(ERR_TIMING_MEAS_ADC, false); 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->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC3EN));
@ -181,6 +183,8 @@ void adc_pt1000_setup_meas(void)
streaming_flag_ptr = NULL; streaming_flag_ptr = NULL;
adc_watchdog_counter = 0UL; adc_watchdog_counter = 0UL;
stream_buffer = NULL; 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) void adc_pt1000_set_moving_average_filter_param(float alpha)
@ -311,7 +315,8 @@ static inline __attribute__((optimize("O3"))) void adc_pt1000_filter(float adc_p
stable_sample_counter = 0; stable_sample_counter = 0;
alpha = ADC_PT1000_FILTER_WEIGHT_FAST; alpha = ADC_PT1000_FILTER_WEIGHT_FAST;
if (old_state != 1) { if (old_state != 1) {
safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE, MEAS_ADC_SAFETY_FLAG_KEY); safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE,
MEAS_ADC_SAFETY_FLAG_KEY);
old_state = 1; old_state = 1;
} }
} else { } else {
@ -319,7 +324,8 @@ static inline __attribute__((optimize("O3"))) void adc_pt1000_filter(float adc_p
if (old_state != 2) { if (old_state != 2) {
stable_sample_counter++; stable_sample_counter++;
if (stable_sample_counter >= ADC_PT1000_FILTER_STABLE_SAMPLE_COUNT) { 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); safety_controller_ack_flag_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE,
MEAS_ADC_SAFETY_FLAG_KEY);
old_state = 2; old_state = 2;
} }
} }

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

View 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_ */

View File

@ -19,6 +19,7 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include "startup-tests.h"
/* C++ library init */ /* C++ library init */
# if defined(__cplusplus) # if defined(__cplusplus)
@ -288,7 +289,7 @@ extern unsigned int __ld_eheap;
#define CPACR (*((volatile uint32_t *)0xE000ED88)) #define CPACR (*((volatile uint32_t *)0xE000ED88))
void Reset_Handler(void) { void __attribute__((noreturn)) Reset_Handler(void) {
/* Stack is already initialized by hardware */ /* Stack is already initialized by hardware */
/* The first thing we do here, is to initialize the FPU /* The first thing we do here, is to initialize the FPU
@ -297,6 +298,9 @@ void Reset_Handler(void) {
*/ */
CPACR |= (0xF << 20); CPACR |= (0xF << 20);
/**
* Prepare RAM etc for the System Init function. This ensures, the RAM tests execute at max speed.
*/
/* Copy .data section */ /* Copy .data section */
__init_section(&__ld_load_data, &__ld_sdata, &__ld_edata); __init_section(&__ld_load_data, &__ld_sdata, &__ld_edata);
@ -311,6 +315,74 @@ void Reset_Handler(void) {
/* Set clocks, waitstates, ART operation etc. */ /* Set clocks, waitstates, ART operation etc. */
SystemInit(); 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.
*/
__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 */ /* C++ init function */
#if defined(__cplusplus) #if defined(__cplusplus)

View File

@ -28,13 +28,27 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
/**
* @brief Config parser magic value used to check sanity of passed structs
*/
#define CONFIG_PARSER_MAGIC 0x464a6e2bUL #define CONFIG_PARSER_MAGIC 0x464a6e2bUL
/**
* @brief Config parser type casting macro
*/
#define CONFIG_PARSER(p) ((struct config_parser *)(p)) #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) \ * @brief Check if the supplied pointer is a valid @ref config_parser_handle_t
return CONFIG_PARSER_PARAM_ERR; \ *
} while (0) * If the pointer is invalid, the function using this macro will return with
* CONFIG_PARSER_PARAM_ERR
*/
#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, 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) char *working_buffer, size_t buff_size)
@ -56,9 +70,18 @@ config_parser_handle_t config_parser_open_file(struct config_parser *config_pars
return (config_parser_handle_t)config_parser; return (config_parser_handle_t)config_parser;
} }
/**
* @brief Token delimiters for the config parser.
*/
static const char * const token_delim = " \t"; static const char * const token_delim = " \t";
static int parse_value(struct config_parser_entry *entry, char *value_start_token) /**
* @brief Parse a value in the configuration
* @param entry Entry to parse the value in to
* @param value_start_token char pointer holding the value. Must be null-terminated
* @return 0 if successful
*/
static int parse_value(struct config_parser_entry *entry, char *value_start_token)
{ {
char *dot; char *dot;
char *endptr; char *endptr;
@ -76,19 +99,18 @@ static int parse_value(struct config_parser_entry *entry, char *value_start_tok
if (value_start_token[0] != '-') { if (value_start_token[0] != '-') {
/* Try parsing as ul */ /* Try parsing as ul */
/* Try parsing as int */
entry->value.uint_val = strtoul(value_start_token, &endptr, 0); entry->value.uint_val = strtoul(value_start_token, &endptr, 0);
if (endptr == value_start_token) { if (endptr == value_start_token)
return -1; return -1;
}
entry->type = CONFIG_PARSER_TYPE_UINT; entry->type = CONFIG_PARSER_TYPE_UINT;
goto exit; goto exit;
} else { } else {
/* Try parsing as int */ /* Try parsing as int */
entry->value.int_val = strtod(value_start_token, &endptr); entry->value.int_val = strtod(value_start_token, &endptr);
if (endptr == value_start_token) { if (endptr == value_start_token)
return -1; return -1;
}
entry->type = CONFIG_PARSER_TYPE_INT; entry->type = CONFIG_PARSER_TYPE_INT;
} }
@ -96,14 +118,16 @@ exit:
return 0; return 0;
} }
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_get_line(config_parser_handle_t handle, struct config_parser_entry *entry,
bool force_float)
{ {
struct config_parser *p; struct config_parser *p;
config_parser_check_handle(handle);
p = CONFIG_PARSER(handle);
char *token; char *token;
int token_round = 0; int token_round = 0;
config_parser_check_handle(handle);
p = CONFIG_PARSER(handle);
if (!entry) if (!entry)
return CONFIG_PARSER_PARAM_ERR; return CONFIG_PARSER_PARAM_ERR;
@ -117,8 +141,7 @@ enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, str
if (token[0] == '#') { if (token[0] == '#') {
if (token_round == 0) if (token_round == 0)
return CONFIG_PARSER_LINE_COMMENT; return CONFIG_PARSER_LINE_COMMENT;
else break;
break;
} }
switch (token_round) { switch (token_round) {
@ -126,9 +149,8 @@ enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, str
entry->name = token; entry->name = token;
break; break;
case 1: /* = Symbol */ case 1: /* = Symbol */
if (strcmp(token, "=")) { if (strcmp(token, "="))
return CONFIG_PARSER_LINE_MALFORM; return CONFIG_PARSER_LINE_MALFORM;
}
break; break;
case 2: /* VALUE */ case 2: /* VALUE */
if (parse_value(entry, token)) if (parse_value(entry, token))
@ -158,6 +180,7 @@ enum config_parser_ret config_parser_reset_to_start(config_parser_handle_t handl
{ {
FRESULT res; FRESULT res;
struct config_parser *p; struct config_parser *p;
config_parser_check_handle(handle); config_parser_check_handle(handle);
p = CONFIG_PARSER(handle); p = CONFIG_PARSER(handle);
@ -180,6 +203,7 @@ enum config_parser_ret config_parser_close_file(config_parser_handle_t handle)
{ {
struct config_parser *p; struct config_parser *p;
FRESULT res; FRESULT res;
config_parser_check_handle(handle); config_parser_check_handle(handle);
p = CONFIG_PARSER(handle); p = CONFIG_PARSER(handle);

View File

@ -33,44 +33,68 @@
#include <stdbool.h> #include <stdbool.h>
#include <fatfs/ff.h> #include <fatfs/ff.h>
/**
* @brief Confi parser instance struct
*/
struct config_parser { struct config_parser {
uint32_t magic; uint32_t magic; /**< @brief Magic value. Checked by each function to verify if the passed pointer is valid */
bool write; bool write; /**< @brief File opened in write / read mode */
FIL file; FIL file; /**< @brief FatFS file */
char *buffer; char *buffer; /**< @brief Working buffer */
size_t buff_size; size_t buff_size; /** @brief Size of the working buffer config_parser::buffer */
}; };
/**
* @brief handle type for the config parser. Never dereference this pointer directly!
*/
typedef void * config_parser_handle_t; typedef void * config_parser_handle_t;
/**
* @brief Differnet value types a config entry can hold
*/
enum config_parser_value_type { enum config_parser_value_type {
CONFIG_PARSER_TYPE_UINT = 0, CONFIG_PARSER_TYPE_UINT = 0,
CONFIG_PARSER_TYPE_INT, CONFIG_PARSER_TYPE_INT,
CONFIG_PARSER_TYPE_FLOAT, CONFIG_PARSER_TYPE_FLOAT,
}; };
/**
* @brief Error return code of config parser functions
*/
enum config_parser_ret { enum config_parser_ret {
CONFIG_PARSER_OK = 0, CONFIG_PARSER_OK = 0, /**< @brief Operation succeeded */
CONFIG_PARSER_PARAM_ERR, CONFIG_PARSER_PARAM_ERR, /**< @brief Function parameter error */
CONFIG_PARSER_GENERIC_ERR, CONFIG_PARSER_GENERIC_ERR, /**< @brief Generic unspecified error */
CONFIG_PARSER_IOERR, CONFIG_PARSER_IOERR, /**< @brief I/O Error while file handling */
CONFIG_PARSER_LINE_COMMENT, CONFIG_PARSER_LINE_COMMENT, /**< @brief The parser encountered a line starting with a comment. */
CONFIG_PARSER_LINE_TOO_LONG, CONFIG_PARSER_LINE_TOO_LONG, /**< @brief The read line is too long for the parser to process. */
CONFIG_PARSER_LINE_MALFORM, CONFIG_PARSER_LINE_MALFORM, /**< @brief Malfoirmed line. Line is neither a commenbt nor a key=value string */
CONFIG_PARSER_END_REACHED, CONFIG_PARSER_END_REACHED, /**< @brief The config parser has reached the end of the file */
CONFIG_PARSER_WRONG_MODE, CONFIG_PARSER_WRONG_MODE, /**< @brief Read or write requested on config parser instance that is opened in a different mode */
}; };
/**
* @brief Represents a configuration key-value-pair used by the config parser
*/
struct config_parser_entry { struct config_parser_entry {
const char *name; const char *name; /**< @brief Pointer to the name of the config entry (key) */
enum config_parser_value_type type; enum config_parser_value_type type; /**< @brief Type of the value held by this struct */
union { union {
uint32_t uint_val; uint32_t uint_val;
int32_t int_val; int32_t int_val;
float float_val; float float_val;
} value; } value; /**< @brief Value of the config entry. For correct processing, config_parser_entry::type has to be taken into account */
}; };
/**
* @brief Open a config file
* @param config_parser Struict holding the config parser isntance. Will be filled by this function
* @param write Open the config file for writing (true) or reading (false)
* @param file_name File name to open
* @param working_buffer A working buffer used by the config parser to process the file.
* @param buff_size Size of \p working_buffer. Must be large enough to hold a full line of the config file
* @return Config parser error
*/
config_parser_handle_t config_parser_open_file(struct config_parser *config_parser, bool write, const char *file_name, 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); char *working_buffer, size_t buff_size);
@ -83,13 +107,37 @@ config_parser_handle_t config_parser_open_file(struct config_parser *config_pars
* @return Config parser error * @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_get_line(config_parser_handle_t handle, struct config_parser_entry *entry, bool force_float);
/**
* @brief Reset the config parser instance to the beginning of the config file
* @param handle Config parser
* @return Config parser error
*/
enum config_parser_ret config_parser_reset_to_start(config_parser_handle_t handle); enum config_parser_ret config_parser_reset_to_start(config_parser_handle_t handle);
/**
* @brief Write a config entry to a config file
* @param handle Handle to the config parser. This must be opened in write mode.
* @param entry
* @return Config parser error
* @warning This function is currently not implemented and will return with a success!
*/
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_write_entry(config_parser_handle_t handle, const struct config_parser_entry *entry);
/**
* @brief Close a config parser handle
* @param handle Config parser
* @return Config parser error
*/
enum config_parser_ret config_parser_close_file(config_parser_handle_t handle); enum config_parser_ret config_parser_close_file(config_parser_handle_t handle);
/**
* @brief Check if the \p return_val is a abort condition to stop parsing a file.
*
* This function will return true if a disk error occured or the end of file is reached.
*
* @param return_val
* @return
*/
bool config_parser_ret_is_abort_condition(enum config_parser_ret return_val); bool config_parser_ret_is_abort_condition(enum config_parser_ret return_val);
#endif /* _CONFIG_PARSER_H_ */ #endif /* _CONFIG_PARSER_H_ */

View File

@ -6,7 +6,7 @@ import pathlib
license_header = """/* Reflow Oven Controller license_header = """/* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2022 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
@ -37,7 +37,7 @@ cpath = os.path.join(project_dir, sys.argv[1]+'.c')
hfile = sys.argv[1]+'.h' hfile = sys.argv[1]+'.h'
hpath = os.path.join(module_include_dir, hfile) hpath = os.path.join(module_include_dir, hfile)
h_define = '__'+hfile.replace('.', '_').replace('-', '_').replace('/', '_').upper()+'__' h_define = '_'+hfile.replace('.', '_').replace('-', '_').replace('/', '_').upper()+'_'
if os.path.exists(cpath) or os.path.exists(hpath): if os.path.exists(cpath) or os.path.exists(hpath):
print("File already exists! Abort!") print("File already exists! Abort!")

View File

@ -0,0 +1,15 @@
#!/bin/bash
if [[ -z $1 ]]; then
# Exit with error in case no output file is specified
exit -1
fi
firmware_version=`git describe --tags --always --dirty`
commit=`git rev-parse HEAD`
echo "#ifndef _VERSION_GENERATED_H_" > $1
echo "#define _VERSION_GENERATED_H_" >> $1
echo "#define GIT_VERSION_STRING \"$firmware_version\"" >> $1
echo "#define GIT_FULL_COMMIT \"$commit\"" >> $1
echo "#endif /* _VERSION_GENERATED_H_ */" >> $1

View File

@ -18,6 +18,11 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
/**
* @addtogroup digio
* @{
*/
#include <reflow-controller/digio.h> #include <reflow-controller/digio.h>
#include <stm32/stm32f4xx.h> #include <stm32/stm32f4xx.h>
#include <stm-periph/rcc-manager.h> #include <stm-periph/rcc-manager.h>
@ -47,17 +52,10 @@ static void digio_setup_pin_int(uint8_t bit_no, uint8_t in_out, uint8_t alt_func
} }
void digio_setup_default_all(void) void digio_init(void)
{ {
unsigned int i;
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(DIGIO_RCC_MASK)); rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(DIGIO_RCC_MASK));
digio_set_default_values();
for (i = 0; i < COUNT_OF(digio_pins); i++) {
digio_setup_pin_int(digio_pins[i], digio_default_io[i], digio_default_altfunc[i]);
if (digio_default_io[i] == 1)
digio_set(i, 0);
}
} }
void digio_setup_pin(uint8_t num, uint8_t in_out, uint8_t alt_func) void digio_setup_pin(uint8_t num, uint8_t in_out, uint8_t alt_func)
@ -69,12 +67,22 @@ void digio_setup_pin(uint8_t num, uint8_t in_out, uint8_t alt_func)
void digio_set(uint8_t num, int val) void digio_set(uint8_t num, int val)
{ {
uint8_t pin;
if (num >= COUNT_OF(digio_pins)) if (num >= COUNT_OF(digio_pins))
return; return;
pin = digio_pins[num];
/* Check if port is an output. If not, do noting. */
if ((DIGIO_PORT->MODER & (0x3<<pin)) != OUTPUT(pin)) {
return;
}
if (val) if (val)
DIGIO_PORT->ODR |= (1<<digio_pins[num]); DIGIO_PORT->ODR |= (1<<pin);
else else
DIGIO_PORT->ODR &= ~(1<<digio_pins[num]); DIGIO_PORT->ODR &= ~(1<<pin);
} }
int digio_get(uint8_t num) int digio_get(uint8_t num)
@ -119,7 +127,12 @@ int led_get(uint8_t num)
return ((LED_PORT->ODR & (1<<led_pins[num])) ? 1 : 0); return ((LED_PORT->ODR & (1<<led_pins[num])) ? 1 : 0);
} }
/**
* @brief Initialize the timer for the beeper to generate the output frequency
*
* TIM7 is used as the frequency generating timer. If @ref LOUDSPEAKER_MULTIFREQ
* is 0, the timer is unused and this function does nothing.
*/
static void loudspeaker_freq_timer_init(void) static void loudspeaker_freq_timer_init(void)
{ {
#if LOUDSPEAKER_MULTIFREQ #if LOUDSPEAKER_MULTIFREQ
@ -143,6 +156,13 @@ void loudspeaker_setup(void)
loudspeaker_set(0U); loudspeaker_set(0U);
} }
/**
* @brief Start the beeper
* @param val frequency value of the speaker in 'Timer relaod values'
* @note If @ref LOUDSPEAKER_MULTIFREQ isn't set,
* the speaker output will be set to high and no frequency is generated.
* The value of @p val is ignored in this case
*/
static void loudspeaker_start_beep(uint16_t val) static void loudspeaker_start_beep(uint16_t val)
{ {
#if LOUDSPEAKER_MULTIFREQ #if LOUDSPEAKER_MULTIFREQ
@ -155,6 +175,9 @@ static void loudspeaker_start_beep(uint16_t val)
#endif #endif
} }
/**
* @brief Stop the beeping of the loudspeaker
*/
static void loudspeaker_stop_beep(void) static void loudspeaker_stop_beep(void)
{ {
#if LOUDSPEAKER_MULTIFREQ #if LOUDSPEAKER_MULTIFREQ
@ -172,11 +195,10 @@ void loudspeaker_set(uint16_t val)
{ {
loudspeaker_val = val; loudspeaker_val = val;
if (!val) { if (!val)
loudspeaker_stop_beep(); loudspeaker_stop_beep();
} else { else
loudspeaker_start_beep(val); loudspeaker_start_beep(val);
}
} }
uint16_t loudspeaker_get(void) uint16_t loudspeaker_get(void)
@ -185,6 +207,12 @@ uint16_t loudspeaker_get(void)
} }
#if LOUDSPEAKER_MULTIFREQ #if LOUDSPEAKER_MULTIFREQ
/**
* @brief Timer7 IRQ Handler
*
* This IRQ Handler is used by the loudspeaker to synthesize the output frequency.
* If @ref LOUDSPEAKER_MULTIFREQ is 0, TIM7 and this interrupt will not be used.
*/
void TIM7_IRQHandler(void) void TIM7_IRQHandler(void)
{ {
TIM7->SR = 0UL; TIM7->SR = 0UL;
@ -192,3 +220,16 @@ void TIM7_IRQHandler(void)
LOUDSPEAKER_PORT->ODR ^= (1<<LOUDSPEAKER_PIN); LOUDSPEAKER_PORT->ODR ^= (1<<LOUDSPEAKER_PIN);
} }
#endif #endif
/** @} */
void digio_set_default_values()
{
unsigned int i;
for (i = 0; i < COUNT_OF(digio_pins); i++) {
digio_setup_pin_int(digio_pins[i], digio_default_io[i], digio_default_altfunc[i]);
if (digio_default_io[i] == 1)
digio_set(i, 0);
}
}

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

View File

@ -1,4 +1,4 @@
# Doxyfile 1.8.20 # Doxyfile 1.9.2
# This file describes the settings to be used by the documentation system # This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project. # doxygen (www.doxygen.org) for a project.
@ -93,14 +93,6 @@ ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English OUTPUT_LANGUAGE = English
# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all generated output in the proper direction.
# Possible values are: None, LTR, RTL and Context.
# The default value is: None.
OUTPUT_TEXT_DIRECTION = None
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class # descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this. # documentation (similar to Javadoc). Set to NO to disable this.
@ -258,16 +250,16 @@ TAB_SIZE = 8
# the documentation. An alias has the form: # the documentation. An alias has the form:
# name=value # name=value
# For example adding # For example adding
# "sideeffect=@par Side Effects:\n" # "sideeffect=@par Side Effects:^^"
# will allow you to put the command \sideeffect (or @sideeffect) in the # will allow you to put the command \sideeffect (or @sideeffect) in the
# documentation, which will result in a user-defined paragraph with heading # documentation, which will result in a user-defined paragraph with heading
# "Side Effects:". You can put \n's in the value part of an alias to insert # "Side Effects:". Note that you cannot put \n's in the value part of an alias
# newlines (in the resulting output). You can put ^^ in the value part of an # to insert newlines (in the resulting output). You can put ^^ in the value part
# alias to insert a newline as if a physical newline was in the original file. # of an alias to insert a newline as if a physical newline was in the original
# When you need a literal { or } or , in the value part of an alias you have to # file. When you need a literal { or } or , in the value part of an alias you
# escape them by means of a backslash (\), this can lead to conflicts with the # have to escape them by means of a backslash (\), this can lead to conflicts
# commands \{ and \} for these it is advised to use the version @{ and @} or use # with the commands \{ and \} for these it is advised to use the version @{ and
# a double escape (\\{ and \\}) # @} or use a double escape (\\{ and \\})
ALIASES = ALIASES =
@ -312,8 +304,8 @@ OPTIMIZE_OUTPUT_SLICE = NO
# extension. Doxygen has a built-in mapping, but you can override or extend it # extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and # using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, # language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, # Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
# tries to guess whether the code is fixed or free formatted code, this is the # tries to guess whether the code is fixed or free formatted code, this is the
# default for Fortran type files). For instance to make doxygen treat .inc files # default for Fortran type files). For instance to make doxygen treat .inc files
@ -323,7 +315,10 @@ OPTIMIZE_OUTPUT_SLICE = NO
# Note: For files without extension you can use no_extension as a placeholder. # Note: For files without extension you can use no_extension as a placeholder.
# #
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise # Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen. # the files are not read by doxygen. When specifying no_extension you should add
# * to the FILE_PATTERNS.
#
# Note see also the list of default file extension mappings.
EXTENSION_MAPPING = EXTENSION_MAPPING =
@ -463,12 +458,12 @@ LOOKUP_CACHE_SIZE = 0
# than 0 to get more control over the balance between CPU load and processing # than 0 to get more control over the balance between CPU load and processing
# speed. At this moment only the input processing can be done using multiple # speed. At this moment only the input processing can be done using multiple
# threads. Since this is still an experimental feature the default is set to 1, # threads. Since this is still an experimental feature the default is set to 1,
# which efficively disables parallel processing. Please report any issues you # which effectively disables parallel processing. Please report any issues you
# encounter. Generating dot graphs in parallel is controlled by the # encounter. Generating dot graphs in parallel is controlled by the
# DOT_NUM_THREADS setting. # DOT_NUM_THREADS setting.
# Minimum value: 0, maximum value: 32, default value: 1. # Minimum value: 0, maximum value: 32, default value: 1.
NUM_PROC_THREADS = 1 NUM_PROC_THREADS = 0
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Build related configuration options # Build related configuration options
@ -533,6 +528,13 @@ EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO EXTRACT_ANON_NSPACES = NO
# If this flag is set to YES, the name of an unnamed parameter in a declaration
# will be determined by the corresponding definition. By default unnamed
# parameters remain unnamed in the output.
# The default value is: YES.
RESOLVE_UNNAMED_PARAMS = YES
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
# undocumented members inside documented classes or files. If set to NO these # undocumented members inside documented classes or files. If set to NO these
# members will be included in the various overviews, but no documentation # members will be included in the various overviews, but no documentation
@ -570,11 +572,18 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # With the correct setting of option CASE_SENSE_NAMES doxygen will better be
# names in lower-case letters. If set to YES, upper-case letters are also # able to match the capabilities of the underlying filesystem. In case the
# allowed. This is useful if you have classes or files whose names only differ # filesystem is case sensitive (i.e. it supports files in the same directory
# in case and if your file system supports case sensitive file names. Windows # whose names only differ in casing), the option must be set to YES to properly
# (including Cygwin) and Mac users are advised to set this option to NO. # deal with such files in case they appear in the input. For filesystems that
# are not case sensitive the option should be be set to NO to properly deal with
# output files written for symbols that only differ in casing, such as for two
# classes, one named CLASS and the other named Class, and to also support
# references to files without having to specify the exact matching casing. On
# Windows (including Cygwin) and MacOS, users should typically set this option
# to NO, whereas on Linux or other Unix flavors it should typically be set to
# YES.
# The default value is: system dependent. # The default value is: system dependent.
CASE_SENSE_NAMES = NO CASE_SENSE_NAMES = NO
@ -593,6 +602,12 @@ HIDE_SCOPE_NAMES = YES
HIDE_COMPOUND_REFERENCE= NO HIDE_COMPOUND_REFERENCE= NO
# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
# will show which file needs to be included to use the class.
# The default value is: YES.
SHOW_HEADERFILE = YES
# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
# the files that are included by a file in the documentation of that file. # the files that are included by a file in the documentation of that file.
# The default value is: YES. # The default value is: YES.
@ -750,7 +765,8 @@ FILE_VERSION_FILTER =
# output files in an output format independent way. To create the layout file # output files in an output format independent way. To create the layout file
# that represents doxygen's defaults, run doxygen with the -l option. You can # that represents doxygen's defaults, run doxygen with the -l option. You can
# optionally specify a file name after the option, if omitted DoxygenLayout.xml # optionally specify a file name after the option, if omitted DoxygenLayout.xml
# will be used as the name of the layout file. # will be used as the name of the layout file. See also section "Changing the
# layout of pages" for information.
# #
# Note that if you run doxygen from a directory containing a file called # Note that if you run doxygen from a directory containing a file called
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
@ -796,24 +812,35 @@ WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES WARN_IF_UNDOCUMENTED = YES
# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
# potential errors in the documentation, such as not documenting some parameters # potential errors in the documentation, such as documenting some parameters in
# in a documented function, or documenting parameters that don't exist or using # a documented function twice, or documenting parameters that don't exist or
# markup commands wrongly. # using markup commands wrongly.
# The default value is: YES. # The default value is: YES.
WARN_IF_DOC_ERROR = YES WARN_IF_DOC_ERROR = YES
# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
# function parameter documentation. If set to NO, doxygen will accept that some
# parameters have no documentation without warning.
# The default value is: YES.
WARN_IF_INCOMPLETE_DOC = YES
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return # are documented, but have no documentation for their parameters or return
# value. If set to NO, doxygen will only warn about wrong or incomplete # value. If set to NO, doxygen will only warn about wrong parameter
# parameter documentation, but not about the absence of documentation. If # documentation, but not about the absence of documentation. If EXTRACT_ALL is
# EXTRACT_ALL is set to YES then this flag will automatically be disabled. # set to YES then this flag will automatically be disabled. See also
# WARN_IF_INCOMPLETE_DOC
# The default value is: NO. # The default value is: NO.
WARN_NO_PARAMDOC = NO WARN_NO_PARAMDOC = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered. # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
# at the end of the doxygen process doxygen will return with a non-zero status.
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
# The default value is: NO. # The default value is: NO.
WARN_AS_ERROR = NO WARN_AS_ERROR = NO
@ -849,8 +876,8 @@ INPUT = ../
# This tag can be used to specify the character encoding of the source files # This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv # libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of # documentation (see:
# possible encodings. # https://www.gnu.org/software/libiconv/) for the list of possible encodings.
# The default value is: UTF-8. # The default value is: UTF-8.
INPUT_ENCODING = UTF-8 INPUT_ENCODING = UTF-8
@ -863,12 +890,14 @@ INPUT_ENCODING = UTF-8
# need to set EXTENSION_MAPPING for the extension otherwise the files are not # need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen. # read by doxygen.
# #
# Note the list of default checked file patterns might differ from the list of
# default file extension mappings.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, # *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), # *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen # comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
# *.vhdl, *.ucf, *.qsf and *.ice. # *.vhdl, *.ucf, *.qsf and *.ice.
FILE_PATTERNS = *.c \ FILE_PATTERNS = *.c \
@ -934,8 +963,13 @@ RECURSIVE = YES
EXCLUDE = ../include/stm32 \ EXCLUDE = ../include/stm32 \
../include/arm_math.h \ ../include/arm_math.h \
../include/cmsis \ ../include/cmsis/ \
../shellmatta/test ../shellmatta/test/ \
../linklist-lib/test \
../base64-lib/test \
../shellmatta/doc/main.dox \
../updater/ram-code \
./
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded # directories that are symbolic links (a Unix file system feature) are excluded
@ -1143,13 +1177,6 @@ VERBATIM_HEADERS = YES
ALPHABETICAL_INDEX = YES ALPHABETICAL_INDEX = YES
# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
# which the alphabetical index list will be split.
# Minimum value: 1, maximum value: 20, default value: 5.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all classes will # In case all classes in a project start with a common prefix, all classes will
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
# can be used to specify a prefix (or a list of prefixes) that should be ignored # can be used to specify a prefix (or a list of prefixes) that should be ignored
@ -1249,7 +1276,7 @@ HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to # will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a colorwheel, see # this color. Hue is specified as an angle on a color-wheel, see
# https://en.wikipedia.org/wiki/Hue for more information. For instance the value # https://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
# purple, and 360 is red again. # purple, and 360 is red again.
@ -1259,7 +1286,7 @@ HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_HUE = 220
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
# in the HTML output. For a value of 0 the output will use grayscales only. A # in the HTML output. For a value of 0 the output will use gray-scales only. A
# value of 255 will produce the most vivid colors. # value of 255 will produce the most vivid colors.
# Minimum value: 0, maximum value: 255, default value: 100. # Minimum value: 0, maximum value: 255, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
@ -1320,10 +1347,11 @@ HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files will be # If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development # generated that can be used as input for Apple's Xcode 3 integrated development
# environment (see: https://developer.apple.com/xcode/), introduced with OSX # environment (see:
# 10.5 (Leopard). To create a documentation set, doxygen will generate a # https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
# Makefile in the HTML output directory. Running make will produce the docset in # create a documentation set, doxygen will generate a Makefile in the HTML
# that directory and running make install will install the docset in # output directory. Running make will produce the docset in that directory and
# running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
# genXcode/_index.html for more information. # genXcode/_index.html for more information.
@ -1365,8 +1393,12 @@ DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The # additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on # on Windows. In the beginning of 2021 Microsoft took the original page, with
# Windows. # a.o. the download links, offline the HTML help workshop was already many years
# in maintenance mode). You can download the HTML help workshop from the web
# archives at Installation executable (see:
# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
# #
# The HTML Help Workshop contains a compiler that can convert all HTML output # The HTML Help Workshop contains a compiler that can convert all HTML output
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
@ -1441,7 +1473,8 @@ QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace # Project output. For more information please see Qt Help Project / Namespace
# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project. # The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES. # This tag requires that the tag GENERATE_QHP is set to YES.
@ -1449,8 +1482,8 @@ QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual # Help Project output. For more information please see Qt Help Project / Virtual
# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- # Folders (see:
# folders). # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
# The default value is: doc. # The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES. # This tag requires that the tag GENERATE_QHP is set to YES.
@ -1458,16 +1491,16 @@ QHP_VIRTUAL_FOLDER = doc
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom # filter to add. For more information please see Qt Help Project / Custom
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # Filters (see:
# filters). # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES. # This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME = QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom # custom filter to add. For more information please see Qt Help Project / Custom
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # Filters (see:
# filters). # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES. # This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS = QHP_CUST_FILTER_ATTRS =
@ -1479,9 +1512,9 @@ QHP_CUST_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS =
# The QHG_LOCATION tag can be used to specify the location of Qt's # The QHG_LOCATION tag can be used to specify the location (absolute path
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
# generated .qhp file. # run qhelpgenerator on the generated .qhp file.
# This tag requires that the tag GENERATE_QHP is set to YES. # This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION = QHG_LOCATION =
@ -1524,16 +1557,28 @@ DISABLE_INDEX = NO
# to work a browser that supports JavaScript, DHTML, CSS and frames is required # to work a browser that supports JavaScript, DHTML, CSS and frames is required
# (i.e. any modern browser). Windows users are probably better off using the # (i.e. any modern browser). Windows users are probably better off using the
# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
# further fine-tune the look of the index. As an example, the default style # further fine tune the look of the index (see "Fine-tuning the output"). As an
# sheet generated by doxygen has an example that shows how to put an image at # example, the default style sheet generated by doxygen has an example that
# the root of the tree instead of the PROJECT_NAME. Since the tree basically has # shows how to put an image at the root of the tree instead of the PROJECT_NAME.
# the same information as the tab index, you could consider setting # Since the tree basically has the same information as the tab index, you could
# DISABLE_INDEX to YES when enabling this option. # consider setting DISABLE_INDEX to YES when enabling this option.
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = NO GENERATE_TREEVIEW = NO
# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
# area (value NO) or if it should extend to the full height of the window (value
# YES). Setting this to YES gives a layout similar to
# https://docs.readthedocs.io with more room for contents, but less room for the
# project logo, title, and description. If either GENERATOR_TREEVIEW or
# DISABLE_INDEX is set to NO, this option has no effect.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
FULL_SIDEBAR = NO
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation. # doxygen will group on one line in the generated HTML documentation.
# #
@ -1606,11 +1651,29 @@ FORMULA_MACROFILE =
USE_MATHJAX = YES USE_MATHJAX = YES
# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
# Note that the different versions of MathJax have different requirements with
# regards to the different settings, so it is possible that also other MathJax
# settings have to be changed when switching between the different MathJax
# versions.
# Possible values are: MathJax_2 and MathJax_3.
# The default value is: MathJax_2.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_VERSION = MathJax_2
# When MathJax is enabled you can set the default output format to be used for # When MathJax is enabled you can set the default output format to be used for
# the MathJax output. See the MathJax site (see: # the MathJax output. For more details about the output format see MathJax
# http://docs.mathjax.org/en/latest/output.html) for more details. # version 2 (see:
# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
# (see:
# http://docs.mathjax.org/en/latest/web/components/output.html).
# Possible values are: HTML-CSS (which is slower, but has the best # Possible values are: HTML-CSS (which is slower, but has the best
# compatibility), NativeMML (i.e. MathML) and SVG. # compatibility. This is the name for Mathjax version 2, for MathJax version 3
# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
# is the name for Mathjax version 3, for MathJax version 2 this will be
# translated into HTML-CSS) and SVG.
# The default value is: HTML-CSS. # The default value is: HTML-CSS.
# This tag requires that the tag USE_MATHJAX is set to YES. # This tag requires that the tag USE_MATHJAX is set to YES.
@ -1623,22 +1686,29 @@ MATHJAX_FORMAT = HTML-CSS
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
# Content Delivery Network so you can quickly see the result without installing # Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of # MathJax. However, it is strongly recommended to install a local copy of
# MathJax from https://www.mathjax.org before deployment. # MathJax from https://www.mathjax.org before deployment. The default value is:
# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. # - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
# This tag requires that the tag USE_MATHJAX is set to YES. # This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example # extension names that should be enabled during MathJax rendering. For example
# for MathJax version 2 (see
# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
# For example for MathJax version 3 (see
# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
# MATHJAX_EXTENSIONS = ams
# This tag requires that the tag USE_MATHJAX is set to YES. # This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_EXTENSIONS = MATHJAX_EXTENSIONS =
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
# of code that will be used on startup of the MathJax code. See the MathJax site # of code that will be used on startup of the MathJax code. See the MathJax site
# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # (see:
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
# example see the documentation. # example see the documentation.
# This tag requires that the tag USE_MATHJAX is set to YES. # This tag requires that the tag USE_MATHJAX is set to YES.
@ -1685,7 +1755,8 @@ SERVER_BASED_SEARCH = NO
# #
# Doxygen ships with an example indexer (doxyindexer) and search engine # Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library # (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: https://xapian.org/). # Xapian (see:
# https://xapian.org/).
# #
# See the section "External Indexing and Searching" for details. # See the section "External Indexing and Searching" for details.
# The default value is: NO. # The default value is: NO.
@ -1698,8 +1769,9 @@ EXTERNAL_SEARCH = NO
# #
# Doxygen ships with an example indexer (doxyindexer) and search engine # Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library # (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: https://xapian.org/). See the section "External Indexing and # Xapian (see:
# Searching" for details. # https://xapian.org/). See the section "External Indexing and Searching" for
# details.
# This tag requires that the tag SEARCHENGINE is set to YES. # This tag requires that the tag SEARCHENGINE is set to YES.
SEARCHENGINE_URL = SEARCHENGINE_URL =
@ -1737,7 +1809,7 @@ EXTRA_SEARCH_MAPPINGS =
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES. # The default value is: YES.
GENERATE_LATEX = NO GENERATE_LATEX = YES
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
@ -1808,29 +1880,31 @@ PAPER_TYPE = a4
EXTRA_PACKAGES = amsmath EXTRA_PACKAGES = amsmath
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the # The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
# generated LaTeX document. The header should contain everything until the first # the generated LaTeX document. The header should contain everything until the
# chapter. If it is left blank doxygen will generate a standard header. See # first chapter. If it is left blank doxygen will generate a standard header. It
# section "Doxygen usage" for information on how to let doxygen write the # is highly recommended to start with a default header using
# default header to a separate file. # doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
# and then modify the file new_header.tex. See also section "Doxygen usage" for
# information on how to generate the default header that doxygen normally uses.
# #
# Note: Only use a user-defined header if you know what you are doing! The # Note: Only use a user-defined header if you know what you are doing!
# following commands have a special meaning inside the header: $title, # Note: The header is subject to change so you typically have to regenerate the
# $datetime, $date, $doxygenversion, $projectname, $projectnumber, # default header when upgrading to a newer version of doxygen. The following
# $projectbrief, $projectlogo. Doxygen will replace $title with the empty # commands have a special meaning inside the header (and footer): For a
# string, for the replacement values of the other commands the user is referred # description of the possible markers and block names see the documentation.
# to HTML_HEADER.
# This tag requires that the tag GENERATE_LATEX is set to YES. # This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER = LATEX_HEADER =
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
# generated LaTeX document. The footer should contain everything after the last # the generated LaTeX document. The footer should contain everything after the
# chapter. If it is left blank doxygen will generate a standard footer. See # last chapter. If it is left blank doxygen will generate a standard footer. See
# LATEX_HEADER for more information on how to generate a default footer and what # LATEX_HEADER for more information on how to generate a default footer and what
# special commands can be used inside the footer. # special commands can be used inside the footer. See also section "Doxygen
# # usage" for information on how to generate the default footer that doxygen
# Note: Only use a user-defined footer if you know what you are doing! # normally uses. Note: Only use a user-defined footer if you know what you are
# doing!
# This tag requires that the tag GENERATE_LATEX is set to YES. # This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_FOOTER = LATEX_FOOTER =
@ -1875,8 +1949,7 @@ USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
# command to the generated LaTeX files. This will instruct LaTeX to keep running # command to the generated LaTeX files. This will instruct LaTeX to keep running
# if errors occur, instead of asking the user for help. This option is also used # if errors occur, instead of asking the user for help.
# when generating formulas in HTML.
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES. # This tag requires that the tag GENERATE_LATEX is set to YES.
@ -1889,16 +1962,6 @@ LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO LATEX_HIDE_INDICES = NO
# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
# code with syntax highlighting in the LaTeX output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_SOURCE_CODE = YES
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the # The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See # bibliography, e.g. plainnat, or ieeetr. See
# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
@ -1979,16 +2042,6 @@ RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE = RTF_EXTENSIONS_FILE =
# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
# with syntax highlighting in the RTF output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_SOURCE_CODE = NO
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the man page output # Configuration options related to the man page output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -2085,15 +2138,6 @@ GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook DOCBOOK_OUTPUT = docbook
# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
# program listings (including syntax highlighting and cross-referencing
# information) to the DOCBOOK output. Note that enabling this will significantly
# increase the size of the DOCBOOK output.
# The default value is: NO.
# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
DOCBOOK_PROGRAMLISTING = NO
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output # Configuration options for the AutoGen Definitions output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -2206,7 +2250,7 @@ INCLUDE_FILE_PATTERNS =
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED = __attribute__(x)= \ PREDEFINED = __attribute__(x)= \
IN_SECTION(x)= IN_SECTION(x)=
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The # tag can be used to specify a list of macro names that should be expanded. The
@ -2383,10 +2427,32 @@ UML_LOOK = NO
# but if the number exceeds 15, the total amount of fields shown is limited to # but if the number exceeds 15, the total amount of fields shown is limited to
# 10. # 10.
# Minimum value: 0, maximum value: 100, default value: 10. # Minimum value: 0, maximum value: 100, default value: 10.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag UML_LOOK is set to YES.
UML_LIMIT_NUM_FIELDS = 10 UML_LIMIT_NUM_FIELDS = 10
# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
# tag is set to YES, doxygen will add type and arguments for attributes and
# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
# will not generate fields with class member information in the UML graphs. The
# class diagrams will look similar to the default class diagrams but using UML
# notation for the relationships.
# Possible values are: NO, YES and NONE.
# The default value is: NO.
# This tag requires that the tag UML_LOOK is set to YES.
DOT_UML_DETAILS = NO
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
# to display on a single line. If the actual line length exceeds this threshold
# significantly it will wrapped across multiple lines. Some heuristics are apply
# to avoid ugly line breaks.
# Minimum value: 0, maximum value: 1000, default value: 17.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_WRAP_THRESHOLD = 17
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
# collaboration graphs will show the relations between templates and their # collaboration graphs will show the relations between templates and their
# instances. # instances.
@ -2576,9 +2642,11 @@ DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot # If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
# files that are used to generate the various graphs. # files that are used to generate the various graphs.
#
# Note: This setting is not only used for dot files but also for msc temporary
# files.
# The default value is: YES. # The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_CLEANUP = YES DOT_CLEANUP = YES

View File

@ -0,0 +1,24 @@
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.

View File

@ -1,5 +1,5 @@
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2019 */ /* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */ /* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */ /* attached to the FatFs via a glue function rather than modifying it. */
@ -12,14 +12,8 @@
#include "shimatta_sdio_driver/shimatta_sdio.h" #include "shimatta_sdio_driver/shimatta_sdio.h"
/* Definitions of physical drive number for each drive */ /* Definitions of physical drive number for each drive */
#define DEV_SD 0 /* Example: Map MMC/SD card to physical drive 0*/ #define DEV_SD 0
/*
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);
*/
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Get Drive Status */ /* Get Drive Status */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -116,4 +110,3 @@ DRESULT disk_ioctl (
return RES_PARERR; return RES_PARERR;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,170 +1,208 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Sample Code of OS Dependent Functions for FatFs */ /* A Sample Code of User Provided OS Dependent Functions for FatFs */
/* (C)ChaN, 2018 */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#include <fatfs/ff.h> #include <fatfs/ff.h>
#if FF_USE_LFN == 3 /* Dynamic memory allocation */ #if FF_USE_LFN == 3 /* Use dynamic memory allocation */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Allocate a memory block */ /* Allocate/Free a Memory Block */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#include <stdlib.h> /* with POSIX API */
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
UINT msize /* Number of bytes to allocate */ UINT msize /* Number of bytes to allocate */
) )
{ {
return malloc(msize); /* Allocate a new memory block with POSIX API */ return malloc((size_t)msize); /* Allocate a new memory block */
} }
/*------------------------------------------------------------------------*/
/* Free a memory block */
/*------------------------------------------------------------------------*/
void ff_memfree ( void ff_memfree (
void* mblock /* Pointer to the memory block to free (nothing to do if null) */ void* mblock /* Pointer to the memory block to free (no effect if null) */
) )
{ {
free(mblock); /* Free the memory block with POSIX API */ free(mblock); /* Free the memory block */
} }
#endif #endif
#if FF_FS_REENTRANT /* Mutal exclusion */ #if FF_FS_REENTRANT /* Mutal exclusion */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Create a Synchronization Object */ /* Definitions of Mutex */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* 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 */ #define OS_TYPE 0 /* 0:Win32, 1:uITRON4.0, 2:uC/OS-II, 3:FreeRTOS, 4:CMSIS-RTOS */
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ #if OS_TYPE == 0 /* Win32 */
BYTE vol, /* Corresponding volume (logical drive number) */ #include <windows.h>
FF_SYNC_t* sobj /* Pointer to return the created sync object */ static HANDLE Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */
)
{
/* Win32 */
*sobj = CreateMutex(NULL, FALSE, NULL);
return (int)(*sobj != INVALID_HANDLE_VALUE);
/* uITRON */ #elif OS_TYPE == 1 /* uITRON */
// T_CSEM csem = {TA_TPRI,1,1}; #include "itron.h"
// *sobj = acre_sem(&csem); #include "kernel.h"
// return (int)(*sobj > 0); static mtxid Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */
/* uC/OS-II */ #elif OS_TYPE == 2 /* uc/OS-II */
// OS_ERR err; #include "includes.h"
// *sobj = OSMutexCreate(0, &err); static OS_EVENT *Mutex[FF_VOLUMES + 1]; /* Table of mutex pinter */
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */ #elif OS_TYPE == 3 /* FreeRTOS */
// *sobj = xSemaphoreCreateMutex(); #include "FreeRTOS.h"
// return (int)(*sobj != NULL); #include "semphr.h"
static SemaphoreHandle_t Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */
/* CMSIS-RTOS */ #elif OS_TYPE == 4 /* CMSIS-RTOS */
// *sobj = osMutexCreate(&Mutex[vol]); #include "cmsis_os.h"
// return (int)(*sobj != NULL); static osMutexId Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */
}
/*------------------------------------------------------------------------*/
/* 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 #endif
/*------------------------------------------------------------------------*/
/* Create a Mutex */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount function to create a new mutex
/ or semaphore for the volume. When a 0 is returned, the f_mount function
/ fails with FR_INT_ERR.
*/
int ff_mutex_create ( /* Returns 1:Function succeeded or 0:Could not create the mutex */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
Mutex[vol] = CreateMutex(NULL, FALSE, NULL);
return (int)(Mutex[vol] != INVALID_HANDLE_VALUE);
#elif OS_TYPE == 1 /* uITRON */
T_CMTX cmtx = {TA_TPRI,1};
Mutex[vol] = acre_mtx(&cmtx);
return (int)(Mutex[vol] > 0);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
Mutex[vol] = OSMutexCreate(0, &err);
return (int)(err == OS_NO_ERR);
#elif OS_TYPE == 3 /* FreeRTOS */
Mutex[vol] = xSemaphoreCreateMutex();
return (int)(Mutex[vol] != NULL);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexDef(cmsis_os_mutex);
Mutex[vol] = osMutexCreate(osMutex(cmsis_os_mutex));
return (int)(Mutex[vol] != NULL);
#endif
}
/*------------------------------------------------------------------------*/
/* Delete a Mutex */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount function to delete a mutex or
/ semaphore of the volume created with ff_mutex_create function.
*/
void ff_mutex_delete ( /* Returns 1:Function succeeded or 0:Could not delete due to an error */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
CloseHandle(Mutex[vol]);
#elif OS_TYPE == 1 /* uITRON */
del_mtx(Mutex[vol]);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
OSMutexDel(Mutex[vol], OS_DEL_ALWAYS, &err);
#elif OS_TYPE == 3 /* FreeRTOS */
vSemaphoreDelete(Mutex[vol]);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexDelete(Mutex[vol]);
#endif
}
/*------------------------------------------------------------------------*/
/* Request a Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on enter file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_mutex_take ( /* Returns 1:Succeeded or 0:Timeout */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
return (int)(WaitForSingleObject(Mutex[vol], FF_FS_TIMEOUT) == WAIT_OBJECT_0);
#elif OS_TYPE == 1 /* uITRON */
return (int)(tloc_mtx(Mutex[vol], FF_FS_TIMEOUT) == E_OK);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
OSMutexPend(Mutex[vol], FF_FS_TIMEOUT, &err));
return (int)(err == OS_NO_ERR);
#elif OS_TYPE == 3 /* FreeRTOS */
return (int)(xSemaphoreTake(Mutex[vol], FF_FS_TIMEOUT) == pdTRUE);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
return (int)(osMutexWait(Mutex[vol], FF_FS_TIMEOUT) == osOK);
#endif
}
/*------------------------------------------------------------------------*/
/* Release a Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leave file functions to unlock the volume.
*/
void ff_mutex_give (
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
ReleaseMutex(Mutex[vol]);
#elif OS_TYPE == 1 /* uITRON */
unl_mtx(Mutex[vol]);
#elif OS_TYPE == 2 /* uC/OS-II */
OSMutexPost(Mutex[vol]);
#elif OS_TYPE == 3 /* FreeRTOS */
xSemaphoreGive(Mutex[vol]);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexRelease(Mutex[vol]);
#endif
}
#endif /* FF_FS_REENTRANT */

View File

@ -1,13 +1,13 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Unicode handling functions for FatFs R0.13+ */ /* Unicode Handling Functions for FatFs R0.13 and Later */
/*------------------------------------------------------------------------*/
/* This module will occupy a huge memory in the .rodata section when the */
/* FatFs is configured for LFN with DBCS. If the system has a Unicode */
/* library for the code conversion, this module should be modified to use */
/* it to avoid silly memory consumption. */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* This module will occupy a huge memory in the .const section when the /
/ FatFs is configured for LFN with DBCS. If the system has any Unicode /
/ utilitiy for the code conversion, this module should be modified to use /
/ that function to avoid silly memory consumption. /
/-------------------------------------------------------------------------*/
/* /*
/ Copyright (C) 2014, ChaN, all right reserved. / Copyright (C) 2022, ChaN, all right reserved.
/ /
/ FatFs module is an open source software. Redistribution and use of FatFs in / FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided / source and binary forms, with or without modification, are permitted provided
@ -25,7 +25,7 @@
#include <fatfs/ff.h> #include <fatfs/ff.h>
#if FF_USE_LFN /* This module will be blanked if non-LFN configuration */ #if FF_USE_LFN != 0 /* This module will be blanked if in non-LFN configuration */
#define MERGE2(a, b) a ## b #define MERGE2(a, b) a ## b
#define CVTBL(tbl, cp) MERGE2(tbl, cp) #define CVTBL(tbl, cp) MERGE2(tbl, cp)
@ -15214,8 +15214,8 @@ static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for static code page configuration */ /* OEM <==> Unicode Conversions for Static Code Page Configuration with */
/* SBCS fixed code page */ /* SBCS Fixed Code Page */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 #if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900
@ -15225,7 +15225,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
) )
{ {
WCHAR c = 0; WCHAR c = 0;
const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); const WCHAR* p = CVTBL(uc, FF_CODE_PAGE);
if (uni < 0x80) { /* ASCII? */ if (uni < 0x80) { /* ASCII? */
@ -15247,7 +15247,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
) )
{ {
WCHAR c = 0; WCHAR c = 0;
const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); const WCHAR* p = CVTBL(uc, FF_CODE_PAGE);
if (oem < 0x80) { /* ASCII? */ if (oem < 0x80) { /* ASCII? */
@ -15267,8 +15267,8 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for static code page configuration */ /* OEM <==> Unicode Conversions for Static Code Page Configuration with */
/* DBCS fixed code page */ /* DBCS Fixed Code Page */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if FF_CODE_PAGE >= 900 #if FF_CODE_PAGE >= 900
@ -15277,7 +15277,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0, uc; WCHAR c = 0, uc;
UINT i = 0, n, li, hi; UINT i = 0, n, li, hi;
@ -15313,7 +15313,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0; WCHAR c = 0;
UINT i = 0, n, li, hi; UINT i = 0, n, li, hi;
@ -15346,7 +15346,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for dynamic code page configuration */ /* OEM <==> Unicode Conversions for Dynamic Code Page Configuration */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 0
@ -15360,7 +15360,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0, uc; WCHAR c = 0, uc;
UINT i, n, li, hi; UINT i, n, li, hi;
@ -15412,7 +15412,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0; WCHAR c = 0;
UINT i, n, li, hi; UINT i, n, li, hi;
@ -15458,14 +15458,14 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Unicode up-case conversion */ /* Unicode Up-case Conversion */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
DWORD ff_wtoupper ( /* Returns up-converted code point */ DWORD ff_wtoupper ( /* Returns up-converted code point */
DWORD uni /* Unicode code point to be up-converted */ DWORD uni /* Unicode code point to be up-converted */
) )
{ {
const WORD *p; const WORD* p;
WORD uc, bc, nc, cmd; WORD uc, bc, nc, cmd;
static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */
/* Basic Latin */ /* Basic Latin */
@ -15590,4 +15590,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */
} }
#endif /* #if FF_USE_LFN */ #endif /* #if FF_USE_LFN != 0 */

View File

@ -1,18 +1,46 @@
/* 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 <reflow-controller/hw-version-detect.h>
#include <stm-periph/rcc-manager.h> #include <stm-periph/rcc-manager.h>
#include <stm32/stm32f4xx.h> #include <stm32/stm32f4xx.h>
#define HW_REV_DETECT_GPIO GPIOE #if HW_REV_DETECT_PIN_LOW > HW_REV_DETECT_PIN_HIGH
#define HW_REV_DETECT_RCC_FIELD RCC_AHB1ENR_GPIOEEN #error Configuration error for Hardware derection pins. Lowest position must be less than the highest pin position.
#define HW_REV_DETECT_PIN_LOW (8U) #endif
#define HW_REV_DETECT_PIN_HIGH (15U)
enum hw_revision get_pcb_hardware_version(void) enum hw_revision get_pcb_hardware_version(void)
{ {
uint8_t current_pin; uint8_t current_pin;
uint16_t port_bitmask = 0U; uint16_t port_bitmask = 0U; /* Use uint16_t because a port can have 16 IOs max. */
const uint16_t highest_bit_mask = (1 << (HW_REV_DETECT_PIN_HIGH - HW_REV_DETECT_PIN_LOW));
static enum hw_revision revision = HW_REV_NOT_DETECTED; static enum hw_revision revision = HW_REV_NOT_DETECTED;
/* If the revision has been previously detected,
* just return it and don't do the whole detection stuff
*/
if (revision != HW_REV_NOT_DETECTED) if (revision != HW_REV_NOT_DETECTED)
return revision; return revision;
@ -25,12 +53,15 @@ enum hw_revision get_pcb_hardware_version(void)
HW_REV_DETECT_GPIO->PUPDR |= PULLUP(current_pin); HW_REV_DETECT_GPIO->PUPDR |= PULLUP(current_pin);
} }
/* Loop again and read in the pin mask */ /* Loop again and read in the pin mask.
* Because we use GND-Shorts on the pins to detect the version, the pins are read inverted.
*/
for (current_pin = HW_REV_DETECT_PIN_LOW; current_pin <= HW_REV_DETECT_PIN_HIGH; current_pin++) { for (current_pin = HW_REV_DETECT_PIN_LOW; current_pin <= HW_REV_DETECT_PIN_HIGH; current_pin++) {
port_bitmask >>= 1; port_bitmask >>= 1;
port_bitmask |= (HW_REV_DETECT_GPIO->IDR & (1 << current_pin)) ? 0x0 : 0x80; port_bitmask |= (HW_REV_DETECT_GPIO->IDR & (1 << current_pin)) ? 0x0 : highest_bit_mask;
} }
/* Resolve the read in bitmask to a hardware version */
switch (port_bitmask) { switch (port_bitmask) {
case 0U: case 0U:
revision = HW_REV_V1_2; revision = HW_REV_V1_2;
@ -38,6 +69,9 @@ enum hw_revision get_pcb_hardware_version(void)
case 1U: case 1U:
revision = HW_REV_V1_3; revision = HW_REV_V1_3;
break; break;
case 2U:
revision = HW_REV_V1_3_1;
break;
default: default:
revision = HW_REV_ERROR; revision = HW_REV_ERROR;
} }
@ -46,3 +80,5 @@ enum hw_revision get_pcb_hardware_version(void)
return revision; return revision;
} }
/** @} */

View File

@ -1,8 +1,8 @@
/*----------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.14 / / FatFs - Generic FAT Filesystem module R0.15 /
/-----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ /
/ Copyright (C) 2019, ChaN, all right reserved. / Copyright (C) 2022, ChaN, all right reserved.
/ /
/ FatFs module is an open source software. Redistribution and use of FatFs in / FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided / source and binary forms, with or without modification, are permitted provided
@ -20,7 +20,7 @@
#ifndef FF_DEFINED #ifndef FF_DEFINED
#define FF_DEFINED 86606 /* Revision ID */ #define FF_DEFINED 80286 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -35,10 +35,14 @@ extern "C" {
/* Integer types used for FatFs API */ /* Integer types used for FatFs API */
#if defined(_WIN32) /* Main development platform */ #if defined(_WIN32) /* Windows VC++ (for development only) */
#define FF_INTDEF 2 #define FF_INTDEF 2
#include <windows.h> #include <windows.h>
typedef unsigned __int64 QWORD; typedef unsigned __int64 QWORD;
#include <float.h>
#define isnan(v) _isnan(v)
#define isinf(v) (!_finite(v))
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */ #elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
#define FF_INTDEF 2 #define FF_INTDEF 2
#include <stdint.h> #include <stdint.h>
@ -48,6 +52,7 @@ typedef uint16_t WORD; /* 16-bit unsigned integer */
typedef uint32_t DWORD; /* 32-bit unsigned integer */ typedef uint32_t DWORD; /* 32-bit unsigned integer */
typedef uint64_t QWORD; /* 64-bit unsigned integer */ typedef uint64_t QWORD; /* 64-bit unsigned integer */
typedef WORD WCHAR; /* UTF-16 character type */ typedef WORD WCHAR; /* UTF-16 character type */
#else /* Earlier than C99 */ #else /* Earlier than C99 */
#define FF_INTDEF 1 #define FF_INTDEF 1
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
@ -58,53 +63,6 @@ typedef WORD WCHAR; /* UTF-16 character type */
#endif #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 */ /* Type of file size and LBA variables */
#if FF_FS_EXFAT #if FF_FS_EXFAT
@ -127,14 +85,57 @@ typedef DWORD LBA_t;
/* Type of path name strings on FatFs API (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
/* 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
/* Filesystem object structure (FATFS) */ /* Filesystem object structure (FATFS) */
typedef struct { typedef struct {
BYTE fs_type; /* Filesystem type (0:not mounted) */ BYTE fs_type; /* Filesystem type (0:not mounted) */
BYTE pdrv; /* Associated physical drive */ BYTE pdrv; /* Volume hosting physical drive */
BYTE ldrv; /* Logical drive number (used only when FF_FS_REENTRANT) */
BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */ BYTE wflag; /* win[] status (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ BYTE fsi_flag; /* FSINFO status (b7:disabled, b0:dirty) */
WORD id; /* Volume mount ID */ WORD id; /* Volume mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
WORD csize; /* Cluster size [sectors] */ WORD csize; /* Cluster size [sectors] */
@ -147,9 +148,6 @@ typedef struct {
#if FF_FS_EXFAT #if FF_FS_EXFAT
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
#endif #endif
#if FF_FS_REENTRANT
FF_SYNC_t sobj; /* Identifier of sync object */
#endif
#if !FF_FS_READONLY #if !FF_FS_READONLY
DWORD last_clst; /* Last allocated cluster */ DWORD last_clst; /* Last allocated cluster */
DWORD free_clst; /* Number of free clusters */ DWORD free_clst; /* Number of free clusters */
@ -163,10 +161,10 @@ typedef struct {
#endif #endif
#endif #endif
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
DWORD fsize; /* Size of an FAT [sectors] */ DWORD fsize; /* Number of sectors per FAT */
LBA_t volbase; /* Volume base sector */ LBA_t volbase; /* Volume base sector */
LBA_t fatbase; /* FAT base sector */ LBA_t fatbase; /* FAT base sector */
LBA_t dirbase; /* Root directory base sector/cluster */ LBA_t dirbase; /* Root directory base sector (FAT12/16) or cluster (FAT32/exFAT) */
LBA_t database; /* Data base sector */ LBA_t database; /* Data base sector */
#if FF_FS_EXFAT #if FF_FS_EXFAT
LBA_t bitbase; /* Allocation bitmap base sector */ LBA_t bitbase; /* Allocation bitmap base sector */
@ -181,7 +179,7 @@ typedef struct {
typedef struct { typedef struct {
FATFS* fs; /* Pointer to the hosting volume of this object */ FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Hosting volume mount ID */ WORD id; /* Hosting volume's mount ID */
BYTE attr; /* Object attribute */ 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) */ 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) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
@ -250,7 +248,7 @@ typedef struct {
WORD ftime; /* Modified time */ WORD ftime; /* Modified time */
BYTE fattrib; /* File attribute */ BYTE fattrib; /* File attribute */
#if FF_USE_LFN #if FF_USE_LFN
TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ TCHAR altname[FF_SFN_BUF + 1];/* Alternative file name */
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
#else #else
TCHAR fname[12 + 1]; /* File name */ TCHAR fname[12 + 1]; /* File name */
@ -298,8 +296,10 @@ typedef enum {
/*--------------------------------------------------------------*/
/* FatFs Module Application Interface */
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ 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_close (FIL* fp); /* Close an open file object */
@ -336,6 +336,8 @@ 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 */ 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 */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
/* Some API fucntions are implemented as macro */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
#define f_error(fp) ((fp)->err) #define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr) #define f_tell(fp) ((fp)->fptr)
@ -345,46 +347,47 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil
#define f_rmdir(path) f_unlink(path) #define f_rmdir(path) f_unlink(path)
#define f_unmount(path) f_mount(0, path, 0) #define f_unmount(path) f_mount(0, path, 0)
#ifndef EOF
#define EOF (-1)
#endif
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
/* Additional user defined functions */ /* Additional Functions */
/*--------------------------------------------------------------*/
/* RTC function */ /* RTC function (provided by user) */
#if !FF_FS_READONLY && !FF_FS_NORTC #if !FF_FS_READONLY && !FF_FS_NORTC
DWORD get_fattime (void); DWORD get_fattime (void); /* Get current time */
#endif #endif
/* LFN support functions */
#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ /* LFN support functions (defined in ffunicode.c) */
#if FF_USE_LFN >= 1
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
#endif #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 /* O/S dependent functions (samples available in ffsystem.c) */
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 */ #if FF_USE_LFN == 3 /* Dynamic memory allocation */
void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ void* ff_memalloc (UINT msize); /* Allocate memory block */
int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ void ff_memfree (void* mblock); /* Free memory block */
#endif
#if FF_FS_REENTRANT /* Sync functions */
int ff_mutex_create (int vol); /* Create a sync object */
void ff_mutex_delete (int vol); /* Delete a sync object */
int ff_mutex_take (int vol); /* Lock sync object */
void ff_mutex_give (int vol); /* Unlock sync object */
#endif #endif
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
/* Flags and offset address */ /* Flags and Offset Address */
/*--------------------------------------------------------------*/
/* File access mode and open method flags (3rd argument of f_open) */ /* File access mode and open method flags (3rd argument of f_open) */
#define FA_READ 0x01 #define FA_READ 0x01

View File

@ -1,8 +1,8 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs Functional Configurations / Configurations of FatFs Module
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define FFCONF_DEF 86606 /* Revision ID */ #define FFCONF_DEF 80286 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Function Configurations / Function Configurations
@ -25,14 +25,6 @@
/ 3: f_lseek() function is removed in addition to 2. */ / 3: f_lseek() function is removed in addition to 2. */
#define FF_USE_STRFUNC 1
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
/
/ 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define FF_USE_FIND 1 #define FF_USE_FIND 1
/* This option switches filtered directory read functions, f_findfirst() and /* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
@ -64,6 +56,30 @@
/* This option switches f_forward() function. (0:Disable or 1:Enable) */ /* This option switches f_forward() function. (0:Disable or 1:Enable) */
#define FF_USE_STRFUNC 1
#define FF_PRINT_LLI 0
#define FF_PRINT_FLOAT 0
#define FF_STRF_ENCODE 0
/* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and
/ f_printf().
/
/ 0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion.
/
/ FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2
/ makes f_printf() support floating point argument. These features want C99 or later.
/ When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character
/ encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE
/ to be read/written via those functions.
/
/ 0: ANSI/OEM in current CP
/ 1: Unicode in UTF-16LE
/ 2: Unicode in UTF-16BE
/ 3: Unicode in UTF-8
*/
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations / Locale and Namespace Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
@ -137,19 +153,6 @@
/ on character encoding. When LFN is not enabled, these options have no effect. */ / on character encoding. When LFN is not enabled, these options have no effect. */
#define FF_STRF_ENCODE 3
/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),
/ f_putc(), f_puts and f_printf() convert the character encoding in it.
/ This option selects assumption of character encoding ON THE FILE to be
/ read/written via those functions.
/
/ 0: ANSI/OEM in current CP
/ 1: Unicode in UTF-16LE
/ 2: Unicode in UTF-16BE
/ 3: Unicode in UTF-8
*/
#define FF_FS_RPATH 2 #define FF_FS_RPATH 2
/* This option configures support for relative path. /* This option configures support for relative path.
/ /
@ -175,7 +178,7 @@
/ logical drives. Number of items must not be less than FF_VOLUMES. Valid / logical drives. Number of items must not be less than FF_VOLUMES. Valid
/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
/ not defined, a user defined volume string table needs to be defined as: / not defined, a user defined volume string table is needed as:
/ /
/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
*/ */
@ -187,14 +190,14 @@
/ number and only an FAT volume found on the physical drive will be mounted. / number and only an FAT volume found on the physical drive will be mounted.
/ When this function is enabled (1), each logical drive number can be bound to / When this function is enabled (1), each logical drive number can be bound to
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ funciton will be available. */ / function will be available. */
#define FF_MIN_SS 512 #define FF_MIN_SS 512
#define FF_MAX_SS 512 #define FF_MAX_SS 512
/* This set of options configures the range of sector size to be supported. (512, /* This set of options configures the range of sector size to be supported. (512,
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
/ harddisk. But a larger value may be required for on-board flash memory and some / harddisk, but a larger value may be required for on-board flash memory and some
/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured / type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
/ for variable sector size mode and disk_ioctl() function needs to implement / for variable sector size mode and disk_ioctl() function needs to implement
/ GET_SECTOR_SIZE command. */ / GET_SECTOR_SIZE command. */
@ -205,8 +208,8 @@
/ To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */ / To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */
#define FF_MIN_GPT 0x100000000 #define FF_MIN_GPT 0x10000000
/* Minimum number of sectors to switch GPT format to create partition in f_mkfs and /* Minimum number of sectors to switch GPT as partitioning format in f_mkfs and
/ f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */ / f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */
@ -228,7 +231,7 @@
/ buffer in the filesystem object (FATFS) is used for the file data transfer. */ / buffer in the filesystem object (FATFS) is used for the file data transfer. */
#define FF_FS_EXFAT 0 #define FF_FS_EXFAT 1
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) / To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */ / Note that enabling exFAT discards ANSI C (C89) compatibility. */
@ -237,10 +240,10 @@
#define FF_FS_NORTC 0 #define FF_FS_NORTC 0
#define FF_NORTC_MON 1 #define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1 #define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2019 #define FF_NORTC_YEAR 2022
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have /* The option FF_FS_NORTC switches timestamp feature. If the system does not have
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable / an RTC or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable the
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp / timestamp feature. Every object modified by FatFs will have a fixed timestamp
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
/ added to the project to read current time form real-time clock. FF_NORTC_MON, / added to the project to read current time form real-time clock. FF_NORTC_MON,
@ -250,7 +253,7 @@
#define FF_FS_NOFSINFO 0 #define FF_FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this /* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force / option, and f_getfree() function at the first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. / a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/ /
/ bit0=0: Use free cluster count in the FSINFO if available. / bit0=0: Use free cluster count in the FSINFO if available.
@ -272,26 +275,21 @@
/ lock control is independent of re-entrancy. */ / lock control is independent of re-entrancy. */
/* #include <somertos.h> // O/S definitions */
#define FF_FS_REENTRANT 0 #define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000 #define FF_FS_TIMEOUT 1000
#define FF_SYNC_t HANDLE
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different / module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access / and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this function. / to the same volume is under control of this featuer.
/ /
/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. / 0: Disable re-entrancy. FF_FS_TIMEOUT have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers, / 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() / ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give()
/ function, must be added to the project. Samples are available in / function, must be added to the project. Samples are available in ffsystem.c.
/ option/syscall.c.
/ /
/ The FF_FS_TIMEOUT defines timeout period in unit of time tick. / The FF_FS_TIMEOUT defines timeout period in unit of O/S time tick.
/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, */
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */

View File

@ -36,7 +36,7 @@
/** /**
* @brief Moving average filter coefficient for PT1000 measurement * @brief Moving average filter coefficient for PT1000 measurement
*/ */
#define ADC_PT1000_FILTER_WEIGHT 0.005f #define ADC_PT1000_FILTER_WEIGHT 0.01f
/** /**
* @brief Moving average filter weight used for fast regaulation. This is used when the measured resistance * @brief Moving average filter weight used for fast regaulation. This is used when the measured resistance

View File

@ -18,6 +18,11 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
/**
* @addtogroup digio
* @{
*/
#ifndef __DIGIO_H__ #ifndef __DIGIO_H__
#define __DIGIO_H__ #define __DIGIO_H__
@ -25,10 +30,22 @@
#include <stdint.h> #include <stdint.h>
#include <helper-macros/helper-macros.h> #include <helper-macros/helper-macros.h>
/**
* @brief Port the digital I/Os are located in
*/
#define DIGIO_PORT GPIOB #define DIGIO_PORT GPIOB
/**
* @brief Reset and clock control bit mask to enable clock of @ref DIGIO_PORT
*/
#define DIGIO_RCC_MASK RCC_AHB1ENR_GPIOBEN #define DIGIO_RCC_MASK RCC_AHB1ENR_GPIOBEN
/**
* @brief List of the pins used by the digio module
*/
#define DIGIO_PINS 4,5,6,7 #define DIGIO_PINS 4,5,6,7
#if defined(DEBUGBUILD) || defined(UART_ON_DEBUG_HEADER) #if defined(DEBUGBUILD) || defined(UART_ON_DEBUG_HEADER)
#define DIGIO_INOUT_DEFAULT 0,0,0,0 #define DIGIO_INOUT_DEFAULT 0,0,0,0
#define DIGIO_ALTFUNC_DEFAULT 0,0,0,0 #define DIGIO_ALTFUNC_DEFAULT 0,0,0,0
@ -37,33 +54,139 @@
#define DIGIO_ALTFUNC_DEFAULT 0,0,7,7 #define DIGIO_ALTFUNC_DEFAULT 0,0,7,7
#endif #endif
/**
* @brief The port, the loudspeaker is connected to
*/
#define BEEPER_PORT GPIOB #define BEEPER_PORT GPIOB
/**
* @brief The RCC mask for @ref BEEPER_PORT
*/
#define BEEPER_RCC_MASK RCC_AHB1ENR_GPIOBEN #define BEEPER_RCC_MASK RCC_AHB1ENR_GPIOBEN
/**
* @brief Enable all clocks and setup pins in default setting.
* @warning This function uses @ref rcc_manager_enable_clock to enable the clocks. Therefore, it must not be called
* multiple times.
* @note Calls @ref digio_set_default_values() internally.
*/
void digio_init(void);
void digio_setup_default_all(void); /**
* @brief Setup or restore the default DIGIO settings.
*
* This function can be called multiple times.
*/
void digio_set_default_values(void);
/**
* @brief Set up a DIGIO pin.
*
* Set up a digital IO pin config. For the index association see the @ref DIGIO_PINS table.
*
* @param num DIGIO number starting with 0
* @param in_out In: 0, Out 1, alternate function: 2
* @param alt_func Alternate function to set. Consult datasheet of STM32F407
*/
void digio_setup_pin(uint8_t num, uint8_t in_out, uint8_t alt_func); void digio_setup_pin(uint8_t num, uint8_t in_out, uint8_t alt_func);
/**
* @brief Set a digio output port
* @param num Digio channel number
* @param val Value: 0 or 1.
*/
void digio_set(uint8_t num, int val); void digio_set(uint8_t num, int val);
/**
* @brief Read the state of a digio channel
* @param num Channel number
* @return digital pin level.
*/
int digio_get(uint8_t num); int digio_get(uint8_t num);
/**
* @brief Port the LEDs are connected to
*/
#define LED_PORT GPIOB #define LED_PORT GPIOB
/**
* @brief RCC mask to enable clock for @ref LED_PORT
*/
#define LED_RCC_MASK RCC_AHB1ENR_GPIOBEN #define LED_RCC_MASK RCC_AHB1ENR_GPIOBEN
/**
* @brief Pin list on @ref LED_PORT that are connected to LEDs
*/
#define LED_PINS 2,3 #define LED_PINS 2,3
/**
* @brief Set up the LED Port
*/
void led_setup(void); void led_setup(void);
/**
* @brief Set the LED status
* @param num LED number
* @param val Value: 1 on, 0 off.
*/
void led_set(uint8_t num, int val); void led_set(uint8_t num, int val);
/**
* @brief Get the state of a LED
* @param num LED number
* @return Stateof the LED: 0 off, 1 on; -1 in case of an error
*/
int led_get(uint8_t num); int led_get(uint8_t num);
/**
* @brief Port to use for the loudpseaker
*/
#define LOUDSPEAKER_PORT GPIOB #define LOUDSPEAKER_PORT GPIOB
/**
* @brief RCC mask for @ref LOUDSPEAKER_PORT
*/
#define LOUDSPEAKER_RCC_MASK RCC_AHB1ENR_GPIOBEN #define LOUDSPEAKER_RCC_MASK RCC_AHB1ENR_GPIOBEN
/**
* @brief Pin on @ref LOUDSPEAKER_PORT the speaker is cnnected to
*/
#define LOUDSPEAKER_PIN 1 #define LOUDSPEAKER_PIN 1
/**
* @brief The loudpseaker requires a frequency signal instead of a simple on/off signal.
*/
#define LOUDSPEAKER_MULTIFREQ 1 #define LOUDSPEAKER_MULTIFREQ 1
/**
* @brief Defautl timer relaod for the frequency of the speaker. Only relevant if @ref LOUDSPEAKER_MULTIFREQ is 1.
*/
#define LOUDSPEAKER_MULTIFREQ_DEFAULT 9 #define LOUDSPEAKER_MULTIFREQ_DEFAULT 9
/**
* @brief Setup the loudspeaker
*/
void loudspeaker_setup(void); void loudspeaker_setup(void);
/**
* @brief Set the loudspeaker value
*
* Zero turns off the beeper. 1 is a special value
* and will set the @ref LOUDSPEAKER_MULTIFREQ_DEFAULT value.
*
* If @ref LOUDSPEAKER_MULTIFREQ is 0, then no actual frequency is produced.
* Instead any @p val unequal to zero turns the output pin high and 0 will turn it low.
*
* @param val Value.
*/
void loudspeaker_set(uint16_t val); void loudspeaker_set(uint16_t val);
/**
* @brief Get current value of the loadspeaker
* @return Value
*/
uint16_t loudspeaker_get(void); uint16_t loudspeaker_get(void);
#endif /* __DIGIO_H__ */ #endif /* __DIGIO_H__ */
/** @} */

View File

@ -1,8 +1,53 @@
/* 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
* @{
*/
#ifndef _HW_VERSION_DETECT_H_ #ifndef _HW_VERSION_DETECT_H_
#define _HW_VERSION_DETECT_H_ #define _HW_VERSION_DETECT_H_
#include <stdint.h> #include <stdint.h>
/**
* @brief GPIO Port used for hardware version detection
*/
#define HW_REV_DETECT_GPIO GPIOE
/**
* @brief RCC Clock register mask used to enable @ref HW_REV_DETECT_GPIO GPIO Port
*/
#define HW_REV_DETECT_RCC_FIELD RCC_AHB1ENR_GPIOEEN
/**
* @brief Lowest pin on @ref HW_REV_DETECT_GPIO GPIO Port that shall be used to read in the hardware version
*/
#define HW_REV_DETECT_PIN_LOW (8U)
/**
* @brief Highest pin on @ref HW_REV_DETECT_GPIO GPIO Port that shall be used to read in the hardware version
*/
#define HW_REV_DETECT_PIN_HIGH (15U)
/** /**
* @brief PCB/Hardware Revision Type * @brief PCB/Hardware Revision Type
*/ */
@ -11,6 +56,7 @@ enum hw_revision {
HW_REV_ERROR = 1, /**< @brief The hardware revision could not be detected due to an internal error */ HW_REV_ERROR = 1, /**< @brief The hardware revision could not be detected due to an internal error */
HW_REV_V1_2 = 120, /**< @brief Hardware Revision v1.2 */ HW_REV_V1_2 = 120, /**< @brief Hardware Revision v1.2 */
HW_REV_V1_3 = 130, /**< @brief Hardware Revision v1.3 */ HW_REV_V1_3 = 130, /**< @brief Hardware Revision v1.3 */
HW_REV_V1_3_1 = 131, /**< @brief Hardware revision v1.3.1 */
}; };
/** /**
@ -24,6 +70,7 @@ enum hw_revision {
* The function returns the HW revision as an enum hw_revision. * The function returns the HW revision as an enum hw_revision.
* For v1.2 the return value is 120 (HW_REV_V1_2). * For v1.2 the return value is 120 (HW_REV_V1_2).
* For v1.3 the return value is 130 (HW_REV_V1_3). * For v1.3 the return value is 130 (HW_REV_V1_3).
* For v1.3.1 the return value is 131 (HW_REV_V1_3_1).
* *
* Other return values are not defined yet. * Other return values are not defined yet.
* *
@ -32,3 +79,5 @@ enum hw_revision {
enum hw_revision get_pcb_hardware_version(void); enum hw_revision get_pcb_hardware_version(void);
#endif /* _HW_VERSION_DETECT_H_ */ #endif /* _HW_VERSION_DETECT_H_ */
/** @} */

View File

@ -0,0 +1,69 @@
/* 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/>.
*/
/**
* @defgroup main-cycle-counter Main Cycle Counter
* The main cycle counter is incremented after every loop run of the main loop in main.c
* @{
*/
#ifndef __MAIN_CYCLE_COUNTER_H__
#define __MAIN_CYCLE_COUNTER_H__
#include <stdint.h>
/**
* @brief Initialize the main cycle counter and reset to 0. This also enables the core cycle counter
* This function can be called multiple times.
*/
void main_and_core_cycle_counter_init(void);
/**
* @brief Reset the main cycle counter.
* @note This does not reset the core cycle counter
*/
void main_cycle_counter_reset(void);
/**
* @brief Increment the main cycle counter by 1
*/
void main_cycle_counter_inc(void);
/**
* @brief Get the current main cycle counter value
* @return Value
*/
uint64_t main_cycle_counter_get(void);
/**
* @brief Reset the core cycle counter to 0
*/
void core_cycle_counter_reset(void);
/**
* @brief Get the current value of the core cycle counter
*
* @return uint32_t Counter value
*/
uint32_t core_cycle_counter_get(void);
#endif /* __MAIN_CYCLE_COUNTER_H__ */
/** @} */

View File

@ -21,32 +21,93 @@
#ifndef __OVEN_DRIVER_H__ #ifndef __OVEN_DRIVER_H__
#define __OVEN_DRIVER_H__ #define __OVEN_DRIVER_H__
/**
* @defgroup oven-driver Oven SSR Driver and PID Controller
* @{
*/
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <reflow-controller/pid-controller.h> #include <reflow-controller/pid-controller.h>
enum oven_pid_status {OVEN_PID_DEACTIVATED, /**
OVEN_PID_RUNNING, * @brief Status of the PID controlling the oven
OVEN_PID_ABORTED}; */
enum oven_pid_status {
OVEN_PID_DEACTIVATED, /**< @brief The PID of the oven is deactivated. */
OVEN_PID_RUNNING, /**< @brief The PID of the oven is currently active and running. */
OVEN_PID_ABORTED, /**< @brief The PID of the oven has been aborted due to an error and is not running. */
};
/**
* @brief Initialize the oven driver.
*
* This will initialize the Timer for the PWM output to the SSR.
* If the hardware revision is >= v1.3 the SSR safety enable line will also be initialized.
*/
void oven_driver_init(void); void oven_driver_init(void);
/**
* @brief Set a power level on the oven control output
* @param power Power level between 0 to 100
* @note This will not actually set the output. For this, @ref oven_driver_apply_power_level() has to be called.
* It will be called in the main loop.
*/
void oven_driver_set_power(uint8_t power); void oven_driver_set_power(uint8_t power);
/**
* @brief Disable the oven driver.
*
* This shuts down the oven driver timer and the corresponding clocks.
*/
void oven_driver_disable(void); void oven_driver_disable(void);
/**
* @brief Initialize the PID controller for the oven output
* @param PID controller holding the settings
*/
void oven_pid_init(struct pid_controller *controller_to_copy); void oven_pid_init(struct pid_controller *controller_to_copy);
/**
* @brief Handle the PID controller.
* This must be called cyclically. When the sampling period has passed, the function will process the PT1000
* resistance and do a PID cycluilation for this sample.
* @note This function must be called with a frequency greater or equal to the PID's sampling frequency
*/
void oven_pid_handle(void); void oven_pid_handle(void);
/**
* @brief Stop the oven PID controller
*/
void oven_pid_stop(void); void oven_pid_stop(void);
/**
* @brief Abort the oven PID controller. This is the same as oven_pid_stop() but will set the abort flag.
* @note this function is called by the safety controller to disable the PID controller in case of an error.
*/
void oven_pid_abort(void); void oven_pid_abort(void);
/**
* @brief Set the target temperature of the PID controller.
* @param temp
*/
void oven_pid_set_target_temperature(float temp); void oven_pid_set_target_temperature(float temp);
/**
* @brief Output the power level currently configured to the SSR.
*
* This function is separated from oven_driver_set_power() because it is called in the main loop after the
* safety controller has run. This ensures, that if the safety controller decides to stop the PID no glitch makes it
* out to the SSR.
*/
void oven_driver_apply_power_level(void); void oven_driver_apply_power_level(void);
/**
* @brief Get the current status of the oven's PID controller
* @return
*/
enum oven_pid_status oven_pid_get_status(void); enum oven_pid_status oven_pid_get_status(void);
/** @} */
#endif /* __OVEN_DRIVER_H__ */ #endif /* __OVEN_DRIVER_H__ */

View File

@ -25,9 +25,11 @@
#endif #endif
/* UART_DIV is 45.5625 => 115200 @ 84 MHz */ /* UART_DIV is 45.5625 => 115200 @ 84 MHz */
#define SHELL_UART_DIV_FRACTION 9U /* Equals 9/16 = 0.5625 */ #define SHELL_UART_DEFAULT_DIV_FRACTION 9U /* Equals 9/16 = 0.5625 */
#define SHELL_UART_DIV_MANTISSA 45U /* Equals 45 */ #define SHELL_UART_DEFAULT_DIV_MANTISSA 45U /* Equals 45 */
#define SHELL_UART_BRR_REG_VALUE ((SHELL_UART_DIV_MANTISSA<<4) | SHELL_UART_DIV_FRACTION); #define SHELL_UART_DEFAULT_BRR_REG_VALUE ((SHELL_UART_DEFAULT_DIV_MANTISSA<<4) | SHELL_UART_DEFAULT_DIV_FRACTION);
#define SHELL_UART_PERIPHERAL_CLOCK (84000000UL)
#endif /* __SHELL_UART_CONFIG_H__ */ #endif /* __SHELL_UART_CONFIG_H__ */

View File

@ -18,35 +18,150 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @addtogroup pid-controller
* @{
*/
#ifndef __PID_CONTROLLER_H__ #ifndef __PID_CONTROLLER_H__
#define __PID_CONTROLLER_H__ #define __PID_CONTROLLER_H__
/**
* @brief Representation of a PID controller
*/
struct pid_controller { struct pid_controller {
/**
* @brief Derivate term @f$k_d@f$
*/
float k_deriv; float k_deriv;
/**
* @brief Integral term @f$k_i@f$
*/
float k_int; float k_int;
/**
* @brief Proportional term @f$k_p@f$
*/
float k_p; float k_p;
/**
* @brief Internally precalculated auxiliary value. @f$k_{i_t} = \frac{1}{2}k_{i} \cdot T_s@f$
*
* This value is caluclated during the @ref pid_init function to reduce calculations during the continous
* PID sampling.
*/
float k_int_t; float k_int_t;
/**
* @brief Internally precalculated auxiliary value. @f$k_{d_t} = 2\frac{k_{d}}{T_s + 2 k_{d\tau}}@f$
*
* This value is caluclated during the @ref pid_init function to reduce calculations during the continous
* PID sampling.
*/
float k_deriv_t; float k_deriv_t;
/**
* @brief Internally precalculated auxiliary value. @f$\overline{k_{d_t}} = \frac{2 k_{d\tau} - T_s}{ 2k_{d\tau} + T_s}@f$
*
* This value is caluclated during the @ref pid_init function to reduce calculations during the continous
* PID sampling.
*/
float k_inv_deriv_t; float k_inv_deriv_t;
/**
* @brief Saturation of output value
* @note This value is set to 100 (corresponding to 100%) for the temperature controller
*/
float output_sat_max; float output_sat_max;
/**
* @brief Minumum saturation of PID output value.
* @note This value is set to 0 for the temperature controller as the oven driver is not able to cool
*/
float output_sat_min; float output_sat_min;
/**
* @brief Maximum value @f$i_{max}@f$ the inegrator in the PID controller can reach.
*
* The output of the integral term of the PID controller is limited to @f$\pm i_{max}@f$
*
*/
float integral_max; float integral_max;
/**
* @brief Sampling period @f$T_s@f$ of the PID controller in seconds
*/
float sample_period; float sample_period;
/**
* @brief Output value of the PID controller
*/
volatile float control_output; volatile float control_output;
/**
* @brief Internal state variable holding the last input value.
*/
volatile float last_in; volatile float last_in;
/**
* @brief integral term's value
*/
volatile float integral; volatile float integral;
/**
* @brief derivate term's value
*/
volatile float derivate; volatile float derivate;
}; };
/**
* @brief Initialize a @ref pid_controller struct
* @param pid Struct to initilaize
* @param k_deriv Derivate term
* @param k_int integral term
* @param k_p Proportional term
* @param output_sat_min Minimum output saturation
* @param output_sat_max Maximum output saturation
* @param integral_max Maximum integral term
* @param kd_tau Time constant of derivate term low pass filter
* @param sample_period Sample time in seconds
*/
void pid_init(struct pid_controller *pid, float k_deriv, float k_int, float k_p, void pid_init(struct pid_controller *pid, float k_deriv, float k_int, float k_p,
float output_sat_min, float output_sat_max, float integral_max, float kd_tau, float sample_period); float output_sat_min, float output_sat_max, float integral_max, float kd_tau, float sample_period);
/**
* @brief Reset a PID controller.
*
* This sets all internal states to 0.
*
* @param pid Controller
*/
void pid_zero(struct pid_controller *pid); void pid_zero(struct pid_controller *pid);
/**
* @brief Execute a tiome step of the PID controller. This function must be periodically called in an pid_controller::sample_period interval
* @note This function does not check its calling interval. It must be ensured by the caller.
* @param pid Pid controller to execute
* @param deviation Input deviation
* @return Current controller output after the calculated time step
*/
float pid_sample(struct pid_controller *pid, float deviation); float pid_sample(struct pid_controller *pid, float deviation);
/**
* @brief Retrieve the controller's current output
* @param pid Pid controller
* @return Output
*/
float pid_get_control_output(const struct pid_controller *pid); float pid_get_control_output(const struct pid_controller *pid);
/**
* @brief Duplicate a PID controller
* @param dest destination controller
* @param src Source controller
* @return 0 if successful
*/
int pid_copy(struct pid_controller *dest, const struct pid_controller *src); int pid_copy(struct pid_controller *dest, const struct pid_controller *src);
#endif /* __PID_CONTROLLER_H__ */ #endif /* __PID_CONTROLLER_H__ */
/** @} */

View File

@ -1,6 +1,6 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2021 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2022 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
@ -18,35 +18,20 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef __TEMP_PROFILE_EXECUTER_H__ #ifndef _SAFETY_FLASH_CRC_STRUCT_H_
#define __TEMP_PROFILE_EXECUTER_H__ #define _SAFETY_FLASH_CRC_STRUCT_H_
#include <stdint.h> #include <stdint.h>
#include <reflow-controller/config-parser/temp-profile-parser.h>
#define MAX_PROFILE_LENGTH 50 struct flash_crcs {
uint32_t start_magic;
enum tpe_status { uint32_t crc_section_text;
TPE_OFF, uint32_t crc_section_data;
TPE_RUNNING, uint32_t crc_section_ccm_data;
TPE_ABORT, uint32_t crc_section_vectors;
uint32_t end_magic;
}; };
struct tpe_current_state { extern const struct flash_crcs crcs_in_flash;
enum tpe_status status;
float setpoint;
uint64_t start_timestamp;
uint32_t step;
uint32_t profile_steps;
enum pl_command_type current_command;
};
enum pl_ret_val temp_profile_executer_start(const char *filename); #endif /* _SAFETY_FLASH_CRC_STRUCT_H_ */
int temp_profile_executer_handle(void);
const struct tpe_current_state *temp_profile_executer_status(void);
int temp_profile_executer_stop(void);
#endif /* __TEMP_PROFILE_EXECUTER_H__ */

View File

@ -0,0 +1,56 @@
/* Reflow Oven Controller
*
* Copyright (C) 2022 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/>.
*/
#ifndef _SAFETY_FLASH_CRC_H_
#define _SAFETY_FLASH_CRC_H_
#include <stdint.h>
enum flash_crc_section {
FLASH_CRC_VECTOR = 0,
FLASH_CRC_TEXT,
FLASH_CRC_DATA,
FLASH_CRC_CCMDATA,
N_FLASH_CRC,
};
/**
* @brief Perform a CRC check of the flash memory and set appropriate flags
* @return negative if internal error occured. Otherwise (independent from CRC check result) 0.
* @note This function requires the safety controller (and CRC unit) to be set up before calling!
*/
int flash_crc_trigger_check(void);
/**
* @brief Calculate CRC over flash section
* @param sec Section to calculate CRC over
* @param[out] crc_result Calculated CRC
* @return negative if internal error occured. Otherwise (independent from CRC check result) 0.
*/
int flash_crc_calc_section(enum flash_crc_section sec, uint32_t *crc_result);
/**
* @brief Get expected CRC value of a section
* @param sec Section
* @return Expected CRC
*/
uint32_t flash_crc_get_expected_crc(enum flash_crc_section sec);
#endif /* _SAFETY_FLASH_CRC_H_ */

View File

@ -67,7 +67,7 @@ int safety_adc_poll_result(void);
* After that, it is safe to use the output values until a new conversion is triggered using #safety_adc_trigger_meas * After that, it is safe to use the output values until a new conversion is triggered using #safety_adc_trigger_meas
* *
* @warning This function return a constant buffer, that is directly written on by the DMA! Check #safety_adc_poll_result to prevent race conditions. * @warning This function return a constant buffer, that is directly written on by the DMA! Check #safety_adc_poll_result to prevent race conditions.
* @return Array of raw ADC readings with lenght of #SAFETY_ADC_NUM_OF_CHANNELS * @return Array of raw ADC readings with length of #SAFETY_ADC_NUM_OF_CHANNELS
*/ */
const uint16_t *safety_adc_get_values(void); const uint16_t *safety_adc_get_values(void);

View File

@ -27,6 +27,15 @@
#ifndef __SAFETY_CONFIG_H__ #ifndef __SAFETY_CONFIG_H__
#define __SAFETY_CONFIG_H__ #define __SAFETY_CONFIG_H__
/**
* @brief Weights of error flags.
*/
enum config_weight {
SAFETY_FLAG_CONFIG_WEIGHT_NONE = 0, /**< @brief This flag has no global error consequence, but might be respected by certain software modules. */
SAFETY_FLAG_CONFIG_WEIGHT_PID = 1, /**< @brief This flag will force a stop of the temperature PID controller */
SAFETY_FLAG_CONFIG_WEIGHT_PANIC = 2, /**< @brief This flag will trigger the panic mode */
};
/** /**
* @brief Enum type representing safety flags. * @brief Enum type representing safety flags.
* *
@ -56,6 +65,11 @@ enum safety_flag {
ERR_FLAG_SAFETY_TAB_CORRUPT = (1<<16), ERR_FLAG_SAFETY_TAB_CORRUPT = (1<<16),
ERR_FLAG_AMON_SUPPLY_VOLT = (1<<17), ERR_FLAG_AMON_SUPPLY_VOLT = (1<<17),
ERR_FLAG_OVERTEMP = (1<<18), ERR_FLAG_OVERTEMP = (1<<18),
ERR_FLAG_FLASH_CRC_CODE = (1<<19),
ERR_FLAG_FLASH_CRC_DATA = (1<<20),
ERR_FLAG_CFG_CRC_MEAS_ADC = (1<<21),
ERR_FLAG_CFG_CRC_SAFETY_ADC = (1<<22),
ERR_FLAG_CFG_CRC_MISC = (1<<23),
}; };
/** /**
@ -71,6 +85,13 @@ enum timing_monitor {
ERR_TIMING_MAIN_LOOP = (1<<3), ERR_TIMING_MAIN_LOOP = (1<<3),
}; };
enum crc_monitor {
ERR_CRC_MON_MEAS_ADC = 0,
ERR_CRC_MON_SAFETY_ADC,
ERR_CRC_MON_MISC,
N_ERR_CRC_MON
};
/** /**
* @brief Enum Type representing analog value monitors. * @brief Enum Type representing analog value monitors.
* *
@ -105,19 +126,21 @@ enum analog_value_monitor {
#define WATCHDOG_HALT_DEBUG (0) #define WATCHDOG_HALT_DEBUG (0)
#endif #endif
#define WATCHDOG_PRESCALER 16 /**
* @brief Watchdog clock prescaler value
*/
#define WATCHDOG_PRESCALER (16)
/**
* @brief Watchdog reload value
*/
#define WATCHDOG_RELOAD_VALUE (2500)
/** /**
* @brief Minimum number of bytes that have to be free on the stack. If this is not the case, an error is detected * @brief Minimum number of bytes that have to be free on the stack. If this is not the case, an error is detected
*/ */
#define SAFETY_MIN_STACK_FREE 0x100 #define SAFETY_MIN_STACK_FREE 0x100
#define PID_CONTROLLER_ERR_CAREMASK (ERR_FLAG_STACK | ERR_FLAG_AMON_UC_TEMP | ERR_FLAG_AMON_VREF | \
ERR_FLAG_TIMING_PID | ERR_FLAG_TIMING_MEAS_ADC | ERR_FLAG_MEAS_ADC_OFF | \
ERR_FLAG_MEAS_ADC_OVERFLOW)
#define HALTING_CAREMASK (ERR_FLAG_STACK | ERR_FLAG_AMON_UC_TEMP)
#define SAFETY_ADC_VREF_MVOLT (2500.0f) #define SAFETY_ADC_VREF_MVOLT (2500.0f)
#define SAFETY_ADC_VREF_TOL_MVOLT (100.0f) #define SAFETY_ADC_VREF_TOL_MVOLT (100.0f)
#define SAFETY_ADC_TEMP_LOW_LIM (0.0f) #define SAFETY_ADC_TEMP_LOW_LIM (0.0f)
@ -144,6 +167,25 @@ enum analog_value_monitor {
*/ */
#define SAFETY_CONTROLLER_ADC_DELAY_MS 250 #define SAFETY_CONTROLLER_ADC_DELAY_MS 250
/**
* @brief Password for resetting ERR_CRC_MON_MEAS_ADC
*/
#define SAFETY_CRC_MON_MEAS_ADC_PW 0xD96254A2
/**
* @brief Password for resetting ERR_CRC_MON_SAFETY_ADC
*/
#define SAFETY_CRC_MON_SAFETY_ADC_PW 0xA8DF2368
/**
* @brief Password for resetting ERR_CRC_MON_MISC
*
*/
#define SAFETY_CRC_MON_MISC_PW 0x9A62E96A
/**
* @brief Default persistence of safety flags. These values are loaded into the safety tables on startup.
*/
#define SAFETY_CONFIG_DEFAULT_PERSIST ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false), \ #define SAFETY_CONFIG_DEFAULT_PERSIST ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, false), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, false), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_UNSTABLE, false), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_UNSTABLE, false), \
@ -163,7 +205,14 @@ enum analog_value_monitor {
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT, true), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT, false), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT, false), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_OVERTEMP, false), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_OVERTEMP, false), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_FLASH_CRC_CODE, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_FLASH_CRC_DATA, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_MISC, true),
/**
* @brief Default config weights of safety flags. These values are loaded into the safety tables on startup.
*/
#define SAFETY_CONFIG_DEFAULT_WEIGHTS ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_OFF, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ #define SAFETY_CONFIG_DEFAULT_WEIGHTS ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_OFF, SAFETY_FLAG_CONFIG_WEIGHT_PID), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, SAFETY_FLAG_CONFIG_WEIGHT_PID), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_UNSTABLE, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_UNSTABLE, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
@ -175,9 +224,7 @@ enum analog_value_monitor {
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_STACK, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_STACK, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SYSTICK, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SYSTICK, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
/* Watchdog timeout is not handled periodically, but only on startup. ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_WTCHDG_FIRED, SAFETY_FLAG_CONFIG_WEIGHT_PID), \
* Therefore, it is not listed here */\
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_WTCHDG_FIRED, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_UNCAL, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_UNCAL, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_DEBUG, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_DEBUG, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_TIMING_MAIN_LOOP, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_TIMING_MAIN_LOOP, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
@ -185,5 +232,10 @@ enum analog_value_monitor {
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT, SAFETY_FLAG_CONFIG_WEIGHT_PID), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_OVERTEMP, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_OVERTEMP, SAFETY_FLAG_CONFIG_WEIGHT_PID), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_CODE, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_DATA, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC, SAFETY_FLAG_CONFIG_WEIGHT_PID), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_MISC, SAFETY_FLAG_CONFIG_WEIGHT_PANIC)
#endif /* __SAFETY_CONFIG_H__ */ #endif /* __SAFETY_CONFIG_H__ */

View File

@ -70,14 +70,14 @@ struct timing_monitor_info {
* You have to call safety_controller_handle * You have to call safety_controller_handle
* If this function fails, it will hang, because errors in the safety controller are not recoverable * If this function fails, it will hang, because errors in the safety controller are not recoverable
*/ */
void safety_controller_init(); void safety_controller_init(void);
/** /**
* @brief Handle the safety controller. * @brief Handle the safety controller.
* @note This function must be executed periodically in order to prevent the watchdog from resetting the firmware * @note This function must be executed periodically in order to prevent the watchdog from resetting the firmware
* @return 0 if successful * @returns Worst flag weigth that is currently set.
*/ */
int safety_controller_handle(); enum config_weight safety_controller_handle(void);
/** /**
* @brief Report one or multiple errors to the safety controller * @brief Report one or multiple errors to the safety controller
@ -170,13 +170,13 @@ bool safety_controller_get_flags_by_mask(enum safety_flag mask);
* @brief Get the count of error flags * @brief Get the count of error flags
* @return Error flag count * @return Error flag count
*/ */
uint32_t safety_controller_get_flag_count(); uint32_t safety_controller_get_flag_count(void);
/** /**
* @brief Get the count of analog monitors * @brief Get the count of analog monitors
* @return Analog monitor count * @return Analog monitor count
*/ */
uint32_t safety_controller_get_analog_monitor_count(); uint32_t safety_controller_get_analog_monitor_count(void);
/** /**
* @brief Get an error flag's name by its index. * @brief Get an error flag's name by its index.
@ -267,6 +267,14 @@ int safety_controller_set_overtemp_limit(float over_temperature);
*/ */
float safety_controller_get_overtemp_limit(void); float safety_controller_get_overtemp_limit(void);
/**
* @brief Recalculate the CRC of a given CRC Monitor. This has to be done once the supervised registers update
* @param mon Monitor to recalculate
* @param password Password
* @return 0 if successful
*/
int safety_controller_set_crc_monitor(enum crc_monitor mon, uint32_t password);
#endif /* __SAFETY_CONTROLLER_H__ */ #endif /* __SAFETY_CONTROLLER_H__ */
/** @} */ /** @} */

View File

@ -24,6 +24,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include <reflow-controller/safety/safety-config.h>
/** @addtogroup safety-memory /** @addtogroup safety-memory
* @{ * @{
@ -35,9 +36,14 @@
#define SAFETY_MEMORY_MAGIC 0x12AA5CB7 #define SAFETY_MEMORY_MAGIC 0x12AA5CB7
/** /**
* @brief Error memory NOP entry * @brief Error memory NOP entry word written to the memory
*/ */
#define SAFETY_MEMORY_NOP_ENTRY 0xC1AA1222 #define SAFETY_MEMORY_NOP_ENTRY_WORD 0xC1AA1222UL
/**
* @brief Low Byte (byte 0) of error memory entry
*/
#define SAFETY_MEMORY_ERROR_ENTRY_MARKER 0x51U
/** /**
* @brief Offset address for the safety_memory_header. * @brief Offset address for the safety_memory_header.
@ -47,6 +53,8 @@
#define SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT 32UL #define SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT 32UL
#define SAFETY_MEMORY_UPDATE_FILENAME_MAXSIZE 256U
/** /**
* @brief Safety memory header * @brief Safety memory header
*/ */
@ -55,6 +63,7 @@ struct safety_memory_header {
uint32_t boot_status_offset; /**< @brief Offset of the safety_memory_boot_status struct (in 32 bit words)*/ 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_offset; /**< @brief Offset address of override entries */
uint32_t config_overrides_len; /**< @brief Length of override entries in words */ 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_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 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 */ uint32_t crc; /**< @brief CRC of the header */
@ -123,15 +132,6 @@ enum config_override_entry_type {
SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE = 2, SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE = 2,
}; };
/**
* @brief Weights of error flags.
*/
enum config_weight {
SAFETY_FLAG_CONFIG_WEIGHT_NONE = 0, /**< @brief This flag has no global error consequence, but might be respected by certain software modules. */
SAFETY_FLAG_CONFIG_WEIGHT_PID = 1, /**< @brief This flag will force a stop of the temperature PID controller */
SAFETY_FLAG_CONFIG_WEIGHT_PANIC = 2, /**< @brief This flag will trigger the panic mode */
};
/** /**
* @brief representation of a config override memory entry * @brief representation of a config override memory entry
*/ */
@ -240,13 +240,35 @@ int safety_memory_insert_config_override(struct config_override *config_override
int safety_memory_get_config_override_count(uint32_t *count); int safety_memory_get_config_override_count(uint32_t *count);
/** /**
* @brief Get a config ovveide entry * @brief Get a config entry
* @param idx Index of the requested entry * @param idx Index of the requested entry
* @param[out] config_override READ override * @param[out] config_override READ override
* @return 0 if successful * @return 0 if successful
*/ */
int safety_memory_get_config_override(uint32_t idx, struct config_override *config_override); int safety_memory_get_config_override(uint32_t idx, struct config_override *config_override);
/**
* @brief Read the set update filename from the safety backup memory
*
* \p filename has to be large enough to hold the filename (255 chars) plus the '\0'-terminator.
*
* @param[out] filename Array to fill in file name. May be NULL to only read the length.
* @param[out] outlen String length of the filename. May be NULL to only read the file name.
* @note \p filename may be NULL. In this case this function can be used to read the currently set filename's length.
* @warning Function will fail if both parameters are NULL
* @return 0 if successful
*/
int safety_memory_get_update_filename(char *filename, size_t *outlen);
/**
* @brief Set the filename of the update file
* @param[in] filename Filename to set. Must be 255 chars at max (256 including null terminator)
* @return 0 if successful
*/
int safety_memory_set_update_filename(const char *filename);
#ifndef SAFETY_MEMORY_STRIPOUT_DUMP
/** /**
* @brief Get a base64 dump of the whole safety memory. * @brief Get a base64 dump of the whole safety memory.
* @param[out] buffer Buffer to write the base 64 dump into. * @param[out] buffer Buffer to write the base 64 dump into.
@ -256,6 +278,8 @@ int safety_memory_get_config_override(uint32_t idx, struct config_override *conf
*/ */
int safety_memory_dump_base64(char *buffer, size_t buffsize, size_t *used_size); int safety_memory_dump_base64(char *buffer, size_t buffsize, size_t *used_size);
#endif /* SAFETY_MEMORY_STRIPOUT_DUMP */
#endif /* __SAFETY_MEMORY_H__ */ #endif /* __SAFETY_MEMORY_H__ */
/** @} */ /** @} */

View File

@ -27,11 +27,19 @@
/** /**
* @brief Setup the watchdog for the safety controller * @brief Setup the watchdog for the safety controller
* @param Prescaler to use for the 32 KHz LSI clock *
* The watchdog timeout can be calculated with:
* \f[ t = \frac{(\mathrm{RELOAD_VAL} + 1)\cdot \mathrm{PRESCALER}}{32000 } s\f]
*
* Valid prescaler values are: 4, 8, 16, 32, 64, 128, 256.
* @param prescaler Prescaler to use for the 32 KHz LSI clock
* @param reload_value Reload value to reload the timer with when reset. 0 to 0xFFF
* @return 0 if successful * @return 0 if successful
* @return -1 if prescaler is wrong
* @return -2 if a reload value > 0xFFF is selected. 0xFFF will be used in this case
* @note Once the watchdog is enabled, it cannot be turned off! * @note Once the watchdog is enabled, it cannot be turned off!
*/ */
int watchdog_setup(uint8_t prescaler); int watchdog_setup(uint16_t prescaler, uint16_t reload_value);
/** /**
* @brief Reset watchdog counter * @brief Reset watchdog counter

View File

@ -0,0 +1,42 @@
/* Reflow Oven Controller
*
* Copyright (C) 2022 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.
*
* GDSII-Converter 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/>.
*/
#ifndef _SD_H_
#define _SD_H_
#include <stdbool.h>
#include <fatfs/ff.h>
/**
* @brief Mount the SD card if available and not already mounted
* @param fs Filesystem to mount to.
* @return true if mounted, false if an error occured or the SD is not inserted and cannot be mounted
*/
bool mount_sd_card_if_avail(FATFS *fs);
/**
* @brief Return whether an SD card is inserted and mounted
*
* @return true SD inserted and mounted
* @return false No SD inserted or not mounted
*/
bool sd_card_is_mounted(void);
#endif /* _SD_H_ */

View File

@ -24,6 +24,13 @@
#include <stdbool.h> #include <stdbool.h>
#include <reflow-controller/settings/settings.h> #include <reflow-controller/settings/settings.h>
/**
* @brief Save the calibration to the SD card
* @param sens_deviation Sensitivity deviation from nomila sensitivity (1)
* @param offset Offset
* @param active Calibration is active. If false, the calibration will be deleted from SD card
* @return 0 if successful
*/
int sd_card_settings_save_calibration(float sens_deviation, float offset, bool active); int sd_card_settings_save_calibration(float sens_deviation, float offset, bool active);
/** /**
@ -34,6 +41,13 @@ int sd_card_settings_save_calibration(float sens_deviation, float offset, bool a
*/ */
int sd_card_settings_try_load_calibration(float *sens_deviation, float *offset); int sd_card_settings_try_load_calibration(float *sens_deviation, float *offset);
/**
* @brief Load the PID parameters from @ref SETTINGS_PID_PARAMETER_FILE
* @param settings The PID settings
* @return Load result.
* @note This function is currently not used for the temperature profiles. They implement the PID parameters directy
* inside the profile
*/
enum settings_load_result sd_card_settings_load_pid_oven_parameters(struct oven_pid_settings *settings); enum settings_load_result sd_card_settings_load_pid_oven_parameters(struct oven_pid_settings *settings);
#endif /* __SETTINGS_SETTINGS_SD_CARD_H__ */ #endif /* __SETTINGS_SETTINGS_SD_CARD_H__ */

View File

@ -18,26 +18,31 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef __SETTINGS_SETTINGS_H__ #ifndef __SETTINGS_SETTINGS_H__
#define __SETTINGS_SETTINGS_H__ #define __SETTINGS_SETTINGS_H__
#include <stdbool.h> #include <stdbool.h>
/**
* @brief Settings for the PID controller that are stored in the config file
*/
struct oven_pid_settings { struct oven_pid_settings {
float kd; float kd; /**< @brief Derivate term */
float kp; float kp; /**< @brief Proportional term */
float ki; float ki; /**< @brief Integral term */
float kd_tau; float kd_tau; /**< @brief Time constant of the derivate term's low pass filter */
float t_sample; float t_sample; /**< @brief Sampling time in seconds. @warning The loading function expects the file to hold a ms value */
float max_integral; float max_integral; /**< @brief Maximum value of the intgral term */
}; };
/**
* @brief Results of a setting loading
*/
enum settings_load_result { enum settings_load_result {
SETT_LOAD_SUCCESS = 0, SETT_LOAD_SUCCESS = 0, /**< @brief Setting loaded successfully */
SETT_LOAD_FILE_NOT_FOUND, SETT_LOAD_FILE_NOT_FOUND, /**< @brief File not found. This is only used by Settings on the SD card */
SETT_LOAD_ERR, SETT_LOAD_ERR, /**< @brief Generic loading error */
SETT_LOAD_DISK_ERR SETT_LOAD_DISK_ERR, /**< @brief Disk access failure during loading */
}; };
#define SETTINGS_PID_PARAMETER_FILE "pid.conf" #define SETTINGS_PID_PARAMETER_FILE "pid.conf"
@ -50,14 +55,49 @@ enum settings_load_result {
*/ */
int settings_save_calibration(float sens_deviation, float offset, bool active); int settings_save_calibration(float sens_deviation, float offset, bool active);
/**
* @brief Load the calibration
*
* If an EEPROM is present, it is first tried to be retrieved from EEPROM.
* If there is no EEPROM or there is no valid data inside, it is tried to be loaded from SD card.
*
* @param sens_dev Sensiotivity deviation
* @param offset Offset
* @return 0 if successful and calibration valid
*/
int settings_load_calibration(float *sens_dev, float *offset); int settings_load_calibration(float *sens_dev, float *offset);
/**
* @brief Load PID overn parameters from file on SD card. This function is not implemented for EEPROM.
* @param settings settings
* @return Load result
*/
enum settings_load_result settings_load_pid_oven_parameters(struct oven_pid_settings *settings); enum settings_load_result settings_load_pid_oven_parameters(struct oven_pid_settings *settings);
/**
* @brief read the configured overtemperature limit
* @param[out] over_temp_limit Overtemperature limit in degrees Celsius
* @return Load result
*/
enum settings_load_result settings_load_overtemp_limit(float *over_temp_limit); enum settings_load_result settings_load_overtemp_limit(float *over_temp_limit);
/**
* @brief Save the overtemperature limit
* @param over_temp_limit Limit in degrees Celsius
* @param active Overtemperature limit active. If false: The config is delted and the controller uses its default limit
* @return 0 if successful
*/
int settings_save_overtemp_limit(float over_temp_limit, bool active); int settings_save_overtemp_limit(float over_temp_limit, bool active);
/**
* @brief Setup the settings module
*
* This function has to be called before performing any settings operations.
* It checks if an EEPTROM is connected and sets the appropriate settings storage in this case.
*
* EEPROM storage will only be available for HW versions > 1.3. Some functions require an EEPROM because the counterpart
* on the SD card is not defined. These functions will fail without an EEPROM.
*/
void settings_setup(void); void settings_setup(void);
#endif /* __SETTINGS_SETTINGS_H__ */ #endif /* __SETTINGS_SETTINGS_H__ */

View File

@ -24,19 +24,59 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
/**
* @brief Initialize the SPI for the eeprom.
* @return 0 if succesful
*/
int spi_eeprom_init(void);
int spi_eeprom_init(); /**
* @brief Uninitialize the SPI EEPROM
void spi_eeprom_deinit(); */
void spi_eeprom_deinit(void);
/**
* @brief Read from SPI EEPROM
* @param addr address to read from
* @param rx_buff buffer to write data to
* @param count Amount of bytes to read
* @return 0 if successful
*/
int spi_eeprom_read(uint32_t addr, uint8_t *rx_buff, uint32_t count); int spi_eeprom_read(uint32_t addr, uint8_t *rx_buff, uint32_t count);
/**
* @brief Check if the EEPROM is currently performing a write and therefore cannot serve other requests
* @return true: Write in Progress, false: No write active
*/
bool spi_eeprom_write_in_progress(void); bool spi_eeprom_write_in_progress(void);
/**
* @brief Write data to the EEPROM
* @param addr Address to write to
* @param data Data to write
* @param count Amount of bytes to write
* @return 0 if successful
* @note The page handling of the EEPROM is done internally. When using this function there is no need to worry about
* the 16 byte page boundaries of the EEPROM
*/
int spi_eeprom_write(uint32_t addr, const uint8_t *data, uint32_t count); int spi_eeprom_write(uint32_t addr, const uint8_t *data, uint32_t count);
/**
* @brief Read the status register of the EEPROM
* @return status register
*/
uint8_t spi_eeprom_read_status_reg(void); uint8_t spi_eeprom_read_status_reg(void);
/**
* @brief Check if an EEPROM is connected to the SPI.
*
* This is done by trying to set the write enable latch in the status register and reading it back.
* After it has been set, it is immediately reset.
*
* If it can't be read back, no EEPROM is connected
*
* @return true: EEPROM is connected, false: No (compatible) EEPROM found
*/
bool spi_eeprom_check_connected(void); bool spi_eeprom_check_connected(void);
#endif /* __SETTINGS_SPI_EEPROM_H__ */ #endif /* __SETTINGS_SPI_EEPROM_H__ */

View File

@ -69,10 +69,28 @@ void systick_setup(void);
*/ */
void systick_wait_ms(uint32_t ms); void systick_wait_ms(uint32_t ms);
uint64_t systick_get_global_tick(); /**
* @brief Get the gloabl millisecond tick. This can be used to implement all sorts of time based procedures / waits.
* @warning Use this with care in interrupts. It may lead to race conditions. It is generally safe for use in standard program flow though.
* @return Global millisecond tick.
*/
uint64_t systick_get_global_tick(void);
/**
* @brief Calculate the uptime from the current millisecond tick.
* @param[out] days Days. May be NULL.
* @param[out] hours Hours. May be NULL.
* @param[out] minutes Minutes. May be NULL.
* @param[out] seconds Seconds. May be NULL.
*/
void systick_get_uptime_from_tick(uint32_t *days, uint32_t *hours, uint32_t *minutes, uint32_t *seconds); void systick_get_uptime_from_tick(uint32_t *days, uint32_t *hours, uint32_t *minutes, uint32_t *seconds);
/**
* @brief Check if \p ticks (milliseconds) have passed since \p start_timestamp
* @param start_timestamp Start timestamp
* @param ticks tick count
* @return true: Time has passed
*/
bool systick_ticks_have_passed(uint64_t start_timestamp, uint64_t ticks); bool systick_ticks_have_passed(uint64_t start_timestamp, uint64_t ticks);
#endif /* __SYSTICK_H__ */ #endif /* __SYSTICK_H__ */

View File

@ -25,7 +25,8 @@
* @brief Convert PT1000 resistance to temperature in degrees celsius * @brief Convert PT1000 resistance to temperature in degrees celsius
* @param resistance PT1000 resistance value * @param resistance PT1000 resistance value
* @param[out] temp_out Temperature output * @param[out] temp_out Temperature output
* @return 0 if ok, -1 if value is below conversion range, 1 if value is above conversion range,-1000 in case of pointer error * @return 0 if ok, -1 if value is below conversion range, 1 if value is above conversion range,
* -1000 in case of pointer error
*/ */
int temp_converter_convert_resistance_to_temp(float resistance, float *temp_out); int temp_converter_convert_resistance_to_temp(float resistance, float *temp_out);
@ -36,6 +37,6 @@ int temp_converter_convert_resistance_to_temp(float resistance, float *temp_out)
* @return 0 if ok, -1 if tmeperature is below the lookup table, 1 if value is above the lookup table, -1000 in case of a pointer error, * @return 0 if ok, -1 if tmeperature is below the lookup table, 1 if value is above the lookup table, -1000 in case of a pointer error,
* -100 if an internal error occured. This should never happen, if the lookup table is correct * -100 if an internal error occured. This should never happen, if the lookup table is correct
*/ */
int temp_convertet_convert_temp_to_resistance(float temp, float *resistance_out); int temp_converter_convert_temp_to_resistance(float temp, float *resistance_out);
#endif /* __TEMP_CONVERTER_H__ */ #endif /* __TEMP_CONVERTER_H__ */

View File

@ -0,0 +1,94 @@
/* 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 temp-profile
* @{
*/
#ifndef __TEMP_PROFILE_EXECUTER_H__
#define __TEMP_PROFILE_EXECUTER_H__
#include <stdint.h>
#include <reflow-controller/temp-profile/temp-profile-parser.h>
/**
* @brief Maximum command count of a temperature profile the parser will handle
*/
#define MAX_PROFILE_LENGTH 64
/**
* @brief Status of the temperature profile execution
*/
enum tpe_status {
TPE_OFF, /**< @brief No profile execution */
TPE_RUNNING, /**< @brief Profile currently running */
TPE_ABORT, /**< @brief Profile execution aborted due to event / error */
};
/**
* @brief The execution state of the temperature profile
*/
struct tpe_exec_state {
enum tpe_status status; /**< @brief Execution status */
float setpoint; /**< @brief Temperature setpoint in degrees Celsius */
uint64_t start_timestamp; /**< @brief The millisicend tick timestamp, the profile execution was started */
uint32_t step; /**< @brief Current execution step. Starts at 0 */
uint32_t profile_steps; /**< @brief Number of steps (commands) in profile */
enum pl_command_type current_command; /**< @brief The currently executed command */
};
/**
* @brief Start a temperature profile execution from a file on SD card.
* @param filename Filename of the temperature profile
* @return Status. PL_RET_SUCCESS id profile was parsed and started successfully
*/
enum pl_ret_val temp_profile_executer_start(const char *filename);
/**
* @brief Handle the profile execution
*
* The function checks if since the last time it ran, 100 ms have passed. If yes,
* it proceeds with the command execution.
*
* @note This must be periodically called.
* @return 0 if successul, negative if profile not running or aborted or temperature set and PID not configured.
*/
int temp_profile_executer_handle(void);
/**
* @brief Get the curretn execution state of the temperature profile executer
* @warning The returned state structure is static and used internally. You must not modify it.
* @return Execution state
*/
const struct tpe_exec_state *temp_profile_executer_status(void);
/**
* @brief Stop the temperature profile execution.
*
* The profile execution is stopped and the beeper is deactivated.
*
* @return always 0. This function cannot fail.
*/
int temp_profile_executer_stop(void);
#endif /* __TEMP_PROFILE_EXECUTER_H__ */
/** @} */

View File

@ -0,0 +1,105 @@
/* 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/>.
*/
/**
* @defgroup temp-profile Temperature Profile Parser and Executer
* @{
*/
#ifndef __CONFIG_PARSER_TEMP_PROFILE_PARSER_H__
#define __CONFIG_PARSER_TEMP_PROFILE_PARSER_H__
#include <stdint.h>
#include <linklist-lib/singly-linked-list.h>
/**
* @brief Command types the temperature profile language supports
*/
enum pl_command_type {
PL_PID_CONF = 0, /**< @brief Configure the PID parameters and start PID controller */
PL_SET_TEMP, /**< @brief Set the target temperature of the PID controller */
PL_SET_RAMP, /**< @brief Perform a temperature ramp */
PL_WAIT_FOR_TEMP, /**< @brief Wait until a temperature is reached */
PL_WAIT_FOR_TIME, /**< @brief Wait for a specific amount of time */
PL_LOUDSPEAKER_SET, /**< @brief Set the loudspeaker/beeper */
PL_OFF, /**< @brief Disable the temperature output and shutdown the PID controller */
PL_CLEAR_FLAGS, /**< @brief Try clear all flags */
PL_DIGIO_CONF, /**< @brief Configure a DIGIO pin */
PL_DIGIO_SET, /**< @brief Set a DIGIO pin */
PL_DIGIO_WAIT, /**< @brief Wait until a DIGIO pin is set to the specified level */
_PL_NUM_CMDS, /**< @brief Sentinel to determine the total amount of commands */
};
/**
* @brief Profile language parser return value
*/
enum pl_ret_val {
PL_RET_SUCCESS = 0, /**< @brief Profile parsed successfully */
PL_RET_DISK_ERR, /**< @brief Disk I/O error */
PL_RET_PARAM_ERR, /**< @brief Function parameter error */
PL_RET_LIST_FULL, /**< @brief Command list is full. Temperature profile is longer than the specified maximum */
PL_RET_SCRIPT_ERR, /**< @brief Syntax error in temperature profile */
};
/**
* @brief Maximum parameter count of a command.
*/
#define PROFILE_LANG_MAX_NUM_ARGS (8)
/**
* @brief Structure representing a command in a temperature profile.
*/
struct pl_command {
enum pl_command_type cmd; /**< @brief Command */
float params[PROFILE_LANG_MAX_NUM_ARGS]; /**< @brief Parameters */
};
/**
* @brief Parse a temperature profile from file and generate the command list
*
* Commands are parsed into the list given by \p command_list. If \p max_len is reached,
* the function returns with @ref PL_RET_LIST_FULL
*
* In any case, the command list not cleared afterwards. The user has to clear the command list manually
* using @ref temp_profile_free_command_list.
*
* @param filename File to parse
* @param[in, out] command_list Command list to output @ref pl_command elements in.
* @param max_len maximum number of commands.
* @param cmds_parsed Number of parsed commands
* @return
*/
enum pl_ret_val temp_profile_parse_from_file(const char *filename,
SlList **command_list,
uint32_t max_len,
uint32_t *cmds_parsed);
/**
* @brief Fully free a comamnd list including hte stored command structures.
*
* \p list's destination is set to NULL to indicate the empty list.
*
* @param[in, out] list Pointer to list.
*/
void temp_profile_free_command_list(SlList **list);
#endif /* __CONFIG_PARSER_TEMP_PROFILE_PARSER_H__ */
/** @} */

View File

@ -21,12 +21,48 @@
#ifndef _GUI_H_ #ifndef _GUI_H_
#define _GUI_H_ #define _GUI_H_
#include <stdint.h>
#include <stddef.h>
/** /**
* @brief Handle the reflow controller's LCD Menu * @brief Handle the reflow controller's LCD Menu
* @return 0 if no delay is requested, 1 if delay is requested * @return 0 if no delay is requested, 1 if delay is requested
*/ */
int gui_handle(void); int gui_handle(void);
/**
* @brief Initialize the GUI (LCD, button, and rotary encoder)
*/
void gui_init(void); void gui_init(void);
/**
* @brief Set a overlay message displayed on top of the root menu
* @param heading Heading of the overlay message (1st line)
* @param text Text of the overlay (the two bottom lines, 2 times 16 chars)
*/
void gui_root_menu_message_set(const char *heading, const char *text);
/**
* @brief Directly write to the LCD
*
* This function writes directly to the LCD and doesn't use the handling FSM in the
* background. Therefore, the function will block until all data is written to the LCD.
*
* @param line line to write to. Starts at 0
* @param text Text to write to the line
*/
void gui_lcd_write_direct_blocking(uint8_t line, const char *text);
/**
* @brief Get the vertical size of the display
* @return Count of rows
*/
size_t gui_get_line_count(void);
/**
* @brief Return the const char disp[][21] array contianing all display rows
* @note This directly returns the working buffer pointer. Do not change it!
*/
const char (*gui_get_current_display_content(void))[21];
#endif /* _GUI_H_ */ #endif /* _GUI_H_ */

View File

@ -21,6 +21,8 @@
#ifndef __LCD_H__ #ifndef __LCD_H__
#define __LCD_H__ #define __LCD_H__
#include <stdint.h>
#define LCD_DPORT (GPIOD) #define LCD_DPORT (GPIOD)
#define LCD_RCC_MASK RCC_AHB1ENR_GPIODEN #define LCD_RCC_MASK RCC_AHB1ENR_GPIODEN
#define LCD_DATA_BIT_OFFSET (8) #define LCD_DATA_BIT_OFFSET (8)
@ -48,6 +50,8 @@ void lcd_init(void);
void lcd_string(const char *data); void lcd_string(const char *data);
void lcd_setcursor(uint8_t x, uint8_t y);
void lcd_home(void); void lcd_home(void);
enum lcd_fsm_ret lcd_fsm_write_buffer(const char (*display_buffer)[21]); enum lcd_fsm_ret lcd_fsm_write_buffer(const char (*display_buffer)[21]);

View File

@ -22,7 +22,7 @@
#define __MENU_H__ #define __MENU_H__
#include <stdint.h> #include <stdint.h>
#include <reflow-controller/button.h> #include <reflow-controller/ui/button.h>
#include <stdbool.h> #include <stdbool.h>
struct lcd_menu; struct lcd_menu;

View File

@ -18,40 +18,34 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef __CONFIG_PARSER_TEMP_PROFILE_PARSER_H__ #ifndef __SHELL_UART_H__
#define __CONFIG_PARSER_TEMP_PROFILE_PARSER_H__
#include <shellmatta.h>
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
enum pl_command_type { /**
PL_PID_CONF = 0, * @brief Configure the UART for the shellmatta shell.
PL_SET_TEMP, *
PL_SET_RAMP, * This will configure the UART for use with a DMA ring buffer.
PL_WAIT_FOR_TEMP, * @param uart
PL_WAIT_FOR_TIME, */
PL_LOUDSPEAKER_SET, void shell_uart_setup(void);
PL_OFF,
_PL_NUM_CMDS,
};
enum pl_ret_val { shellmatta_retCode_t shell_uart_write_callback(const char *data, uint32_t len);
PL_RET_SUCCESS = 0,
PL_RET_DISK_ERR,
PL_RET_PARAM_ERR,
PL_RET_LIST_FULL,
PL_RET_SCRIPT_ERR,
};
#define PROFILE_LANG_MAX_NUM_ARGS (8) int shell_uart_receive_data_with_dma(const char **data, size_t *len);
struct pl_command { /**
enum pl_command_type cmd; * @brief Configure a new connection speed.
float params[PROFILE_LANG_MAX_NUM_ARGS]; * @param new_baud Baudrate. E.g: 115200
}; * @return Error in permille (1/1000). A return value of 2 means a baudrate error of: 0.002 or 0.2%.
* Return value is negative in case of a hard error.
*/
int32_t shell_uart_reconfig_baud(uint32_t new_baud);
enum pl_ret_val temp_profile_parse_from_file(const char *filename, uint32_t shell_uart_get_current_baudrate(void);
struct pl_command *cmd_list,
uint32_t cmd_list_length,
uint32_t *cmds_parsed);
#endif /* __CONFIG_PARSER_TEMP_PROFILE_PARSER_H__ */ #define __SHELL_UART_H__
#endif /* __SHELL_UART_H__ */

View File

@ -25,7 +25,14 @@
/** /**
* @brief Start the RAM Code of the updater. This function will never return! * @brief Start the RAM Code of the updater. This function will never return!
*
* This function is called at startup when the controller detects, that an update should
* be performed.
*
* @note You prabably want to call @ref start_updater function to update.
*/ */
void __attribute__((noreturn)) start_updater(void); void __attribute__((noreturn)) start_updater_ram_code(void);
void __attribute__((noreturn)) updater_update_from_file(const char *filename);
#endif /* __UPDATER_UPDATER_H__ */ #endif /* __UPDATER_UPDATER_H__ */

View File

@ -0,0 +1,29 @@
/* Reflow Oven Controller
*
* Copyright (C) 2022 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/>.
*/
#ifndef _VERSION_H_
#define _VERSION_H_
extern const char *version_git_version_string;
extern const char *version_git_full_commit_string;
extern const char *version_compile_date;
extern const char *version_compile_time;
#endif /* _VERSION_H_ */

View File

@ -0,0 +1,45 @@
/* 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.
*
* GDSII-Converter 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/>.
*/
#ifndef _OPTION_BYTES_H_
#define _OPTION_BYTES_H_
#include <stdint.h>
struct option_bytes {
/* Word 1 */
uint32_t read_protection;// : 8;
uint32_t nrst_standby;// : 1;
uint32_t nrst_stop;// : 1;
uint32_t wdg_sw;// : 1;
uint32_t brown_out_level;// : 2;
/* Word 2 */
uint32_t nwrpi;// : 12;
};
/**
* @brief Read out the option bytes to structs
* @param opts
*/
void stm_option_bytes_read(struct option_bytes *opts);
int stm_option_bytes_program(const struct option_bytes *opts);
#endif /* _OPTION_BYTES_H_ */

View File

@ -33,7 +33,7 @@ enum random_number_error {
void random_number_gen_init(bool int_enable); void random_number_gen_init(bool int_enable);
void random_number_gen_deinit(); void random_number_gen_deinit(void);
void random_number_gen_reset(bool int_en); void random_number_gen_reset(bool int_en);

View File

@ -50,6 +50,8 @@ int uart_init(struct stm_uart *uart);
void uart_change_brr(struct stm_uart *uart, uint32_t brr); void uart_change_brr(struct stm_uart *uart, uint32_t brr);
uint32_t uart_get_brr(struct stm_uart *uart);
void uart_disable(struct stm_uart *uart); void uart_disable(struct stm_uart *uart);
void uart_send_char(struct stm_uart *uart, char c); void uart_send_char(struct stm_uart *uart, char c);

View File

@ -29,6 +29,10 @@
* @param mid mid word of ID * @param mid mid word of ID
* @param low low word of ID * @param low low word of ID
*/ */
void unique_id_get(uint32_t *high, uint32_t *mid, uint32_t *low); void stm_unique_id_get(uint32_t *high, uint32_t *mid, uint32_t *low);
void stm_dev_rev_id_get(uint32_t *device_id, uint32_t *revision_id);
void stm_cpuid_get(uint8_t *implementer, uint8_t *variant, uint16_t *part_no, uint8_t *rev);
#endif /* __UNIQUE_ID_H__ */ #endif /* __UNIQUE_ID_H__ */

@ -0,0 +1 @@
Subproject commit 18b3ab377ac30516f977e9831813ea37189d4028

View File

@ -0,0 +1,77 @@
/* 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 main-cycle-counter
* @{
*/
#include <reflow-controller/main-cycle-counter.h>
#include <helper-macros/helper-macros.h>
#include <stm32/stm32f4xx.h>
/**
* @brief Variable storing the main cycle counter.
* @note This variable should not be accessed directly.
* Use the main_cycle_counter_get() or main_cycle_counter_inc() functions.
*/
static uint64_t IN_SECTION(.ccm.bss) main_cycle_counter;
void main_and_core_cycle_counter_init(void)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
/* Enable the core cycle counter if available on current processor */
if (!(DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk)) {
/* Cycle counter is available. Enable */
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
/* Reset the counters to 0 */
main_cycle_counter_reset();
core_cycle_counter_reset();
}
void main_cycle_counter_reset(void)
{
main_cycle_counter = 0ULL;
}
void main_cycle_counter_inc(void)
{
main_cycle_counter++;
}
uint64_t main_cycle_counter_get(void)
{
return main_cycle_counter;
}
void core_cycle_counter_reset(void)
{
DWT->CYCCNT = 0UL;
}
uint32_t core_cycle_counter_get(void)
{
return DWT->CYCCNT;
}
/** @} */

View File

@ -23,6 +23,7 @@
* @brief Main file for firmware * @brief Main file for firmware
*/ */
#include "reflow-controller/safety/safety-config.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -31,23 +32,26 @@
#include <setup/system_stm32f4xx.h> #include <setup/system_stm32f4xx.h>
#include <reflow-controller/systick.h> #include <reflow-controller/systick.h>
#include <reflow-controller/adc-meas.h> #include <reflow-controller/adc-meas.h>
#include <reflow-controller/shell.h>
#include <reflow-controller/digio.h> #include <reflow-controller/digio.h>
#include "fatfs/shimatta_sdio_driver/shimatta_sdio.h"
#include <stm-periph/stm32-gpio-macros.h> #include <stm-periph/stm32-gpio-macros.h>
#include <stm-periph/rcc-manager.h> #include <stm-periph/rcc-manager.h>
#include <stm-periph/uart.h> #include <stm-periph/uart.h>
#include <reflow-controller/shell-uart-config.h> #include <reflow-controller/periph-config/shell-uart-config.h>
#include <reflow-controller/oven-driver.h> #include <reflow-controller/oven-driver.h>
#include <fatfs/ff.h> #include <fatfs/ff.h>
#include <reflow-controller/sd.h>
#include <reflow-controller/ui/gui.h> #include <reflow-controller/ui/gui.h>
#include <reflow-controller/ui/shell.h>
#include <reflow-controller/ui/shell-uart.h>
#include <reflow-controller/safety/safety-controller.h> #include <reflow-controller/safety/safety-controller.h>
#include <reflow-controller/settings/settings.h> #include <reflow-controller/settings/settings.h>
#include <reflow-controller/safety/safety-memory.h> #include <reflow-controller/safety/safety-memory.h>
#include <reflow-controller/safety/fault.h> #include <reflow-controller/safety/fault.h>
#include <reflow-controller/updater/updater.h> #include <reflow-controller/updater/updater.h>
#include <reflow-controller/temp-profile-executer.h> #include <reflow-controller/temp-profile/temp-profile-executer.h>
#include <reflow-controller/settings/spi-eeprom.h> #include <reflow-controller/settings/spi-eeprom.h>
#include <reflow-controller/main-cycle-counter.h>
#include <stm-periph/option-bytes.h>
static void setup_nvic_priorities(void) static void setup_nvic_priorities(void)
{ {
@ -66,13 +70,13 @@ static void setup_nvic_priorities(void)
FATFS fs; FATFS fs;
#define fs_ptr (&fs) #define fs_ptr (&fs)
/**
* @brief Configure UART GPIOs
* In case the application is build in debug mode, use the TX/RX Pins on the debug header
* else the Pins on the DIGIO header are configured in the digio module and this function does nothing.
*/
static inline void uart_gpio_config(void) static inline void uart_gpio_config(void)
{ {
/*
* In case the application is build in debug mode, use the TX/RX Pins on the debug header
* else the Pins on the DIGIO header are configured in the digio module
*/
#if defined(DEBUGBUILD) || defined(UART_ON_DEBUG_HEADER) #if defined(DEBUGBUILD) || defined(UART_ON_DEBUG_HEADER)
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(SHELL_UART_PORT_RCC_MASK)); rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(SHELL_UART_PORT_RCC_MASK));
SHELL_UART_PORT->MODER &= MODER_DELETE(SHELL_UART_TX_PIN) & MODER_DELETE(SHELL_UART_RX_PIN); SHELL_UART_PORT->MODER &= MODER_DELETE(SHELL_UART_TX_PIN) & MODER_DELETE(SHELL_UART_RX_PIN);
@ -85,68 +89,13 @@ static inline void uart_gpio_config(void)
#endif #endif
} }
/**
static char shell_uart_tx_buff[256]; * @brief Process the boot status structure in the safety (backup) RAM
static char shell_uart_rx_buff[48]; * Depending on the flags set there, this function will:
struct stm_uart shell_uart; * - Reboot into the ram code for reflashing
* - Display the PANIC message
static shellmatta_retCode_t write_shell_callback(const char *data, uint32_t len) * - Display if the flash has been successfully updated
{ */
uart_send_array_with_dma(&shell_uart, data, len);
return SHELLMATTA_OK;
}
static inline void setup_shell_uart(struct stm_uart *uart)
{
uart->rx = 1;
uart->tx = 1;
uart->brr_val = SHELL_UART_BRR_REG_VALUE;
uart->rcc_reg = &SHELL_UART_RCC_REG;
uart->rcc_bit_no = BITMASK_TO_BITNO(SHELL_UART_RCC_MASK);
uart->uart_dev = SHELL_UART_PERIPH;
uart->dma_rx_buff = shell_uart_rx_buff;
uart->dma_tx_buff = shell_uart_tx_buff;
uart->rx_buff_count = sizeof(shell_uart_rx_buff);
uart->tx_buff_count = sizeof(shell_uart_tx_buff);
uart->base_dma_num = 2;
uart->dma_rx_stream = SHELL_UART_RECEIVE_DMA_STREAM;
uart->dma_tx_stream = SHELL_UART_SEND_DMA_STREAM;
uart->dma_rx_trigger_channel = SHELL_UART_RX_DMA_TRIGGER;
uart->dma_tx_trigger_channel = SHELL_UART_TX_DMA_TRIGGER;
uart_init(uart);
NVIC_EnableIRQ(DMA2_Stream7_IRQn);
}
static bool mount_sd_card_if_avail(bool mounted)
{
FRESULT res;
static uint8_t IN_SECTION(.ccm.bss) inserted_counter = 0;
if (sdio_check_inserted() && mounted) {
memset(fs_ptr, 0, sizeof(FATFS));
sdio_stop_clk();
inserted_counter = 0;
return false;
}
if (!sdio_check_inserted() && inserted_counter < 255)
inserted_counter++;
if (!sdio_check_inserted() && !mounted && inserted_counter > 4) {
inserted_counter = 0;
res = f_mount(fs_ptr, "0:/", 1);
if (res == FR_OK) {
led_set(1, 1);
return true;
}
else
return false;
}
return mounted;
}
static inline void handle_boot_status(void) static inline void handle_boot_status(void)
{ {
struct safety_memory_boot_status status; struct safety_memory_boot_status status;
@ -155,6 +104,12 @@ static inline void handle_boot_status(void)
res = safety_memory_get_boot_status(&status); res = safety_memory_get_boot_status(&status);
if (res != 0) if (res != 0)
panic_mode(); panic_mode();
if (status.reset_from_panic) {
/* We've seen a panic */
gui_root_menu_message_set("!! PANIC !!", "Check error me- mory!");
}
if (status.reboot_to_bootloader) { if (status.reboot_to_bootloader) {
status.reboot_to_bootloader = 0UL; status.reboot_to_bootloader = 0UL;
safety_memory_set_boot_status(&status); safety_memory_set_boot_status(&status);
@ -162,39 +117,118 @@ static inline void handle_boot_status(void)
led_set(0, 1); led_set(0, 1);
led_set(1, 1); led_set(1, 1);
start_updater(); gui_lcd_write_direct_blocking(0, "Updating...");
start_updater_ram_code();
}
if (status.code_updated) {
status.code_updated = 0x0UL;
safety_memory_set_boot_status(&status);
/* Display notification on GUI */
gui_root_menu_message_set("Firmware updated", "[Press Key]");
} }
} }
/**
* @brief Read out the option bytes of the STM32 and program them to the desired values.
*
* - This function currently forces the brown out level to Level 3.
*/
static void check_and_program_opt_bytes(void)
{
struct option_bytes opts;
int err;
/** - Read option bytes */
stm_option_bytes_read(&opts);
if (opts.brown_out_level != 0) {
/* Set the brown out level to level 3 => highest brown out limit. */
opts.brown_out_level = 0;
/** - Program the option bytes if brown out level was not set correctly */
err = stm_option_bytes_program(&opts);
/** - If programming failes, enter panic mode */
if (err)
panic_mode();
/** - If programming is successful, reset the system to apply new settings */
NVIC_SystemReset();
}
}
/**
* @brief Setup the system.
*
* This function does all basic initializations of the MCU and its peripherals
*/
static inline void setup_system(void) static inline void setup_system(void)
{ {
float tmp; float tmp;
/** - Read the option bytes and if necessary program them to the desired values */
check_and_program_opt_bytes();
/** - Setup the NVIC priorities of the core peripherals using interrupts */
setup_nvic_priorities(); setup_nvic_priorities();
/* Init safety controller and safety memory */ /** - Init safety controller and safety memory */
safety_controller_init(); safety_controller_init();
/** - Setup the systick module generating the 100us tick fort the GUI and
* the 1ms tick for the global systick timestamp
*/
systick_setup(); systick_setup();
/** - Initialize the oven output driver outputting the wavepacket control signal for the SSR and */
oven_driver_init(); oven_driver_init();
digio_setup_default_all();
/** - Initialize all DIGIO Pins to their default state and pin functions */
digio_init();
/** - Set-up the LED outputs */
led_setup(); led_setup();
/** - Set-up the loudspeaker / beeper output */
loudspeaker_setup(); loudspeaker_setup();
/** - Initialize the GUI */
gui_init(); gui_init();
/** - Initialize the pins for the uart interface. */
uart_gpio_config(); uart_gpio_config();
/** - Set-up the settings module */
settings_setup(); settings_setup();
/* Load the overtemperature limit from eeprom if available. Otherwise the default value will be used */ /** - Load the overtemperature limit from eeprom if available. Otherwise the default value will be used */
if (settings_load_overtemp_limit(&tmp) == SETT_LOAD_SUCCESS) { if (settings_load_overtemp_limit(&tmp) == SETT_LOAD_SUCCESS)
safety_controller_set_overtemp_limit(tmp); safety_controller_set_overtemp_limit(tmp);
}
/** - Handle the boot status struct in the safety memory */
handle_boot_status(); handle_boot_status();
setup_shell_uart(&shell_uart); /** - Initialize the shell UART */
shell_uart_setup();
/** - Enable the ADC for PT1000 measurement */
adc_pt1000_setup_meas(); adc_pt1000_setup_meas();
/** - Enable the misc CRC config monitor to supervise clock, systick and flash settings */
(void)safety_controller_set_crc_monitor(ERR_CRC_MON_MISC, SAFETY_CRC_MON_MISC_PW);
} }
/**
* @brief Handle the input for the shell instance.
*
* This function will check if the RX ring buffer of the UART contains data.
* If so, it will prowvide it to the shellmatta shell.
*
* @param shell_handle Handle to the shellmatta instance
*/
static void handle_shell_uart_input(shellmatta_handle_t shell_handle) static void handle_shell_uart_input(shellmatta_handle_t shell_handle)
{ {
int uart_receive_status; int uart_receive_status;
@ -202,11 +236,15 @@ static void handle_shell_uart_input(shellmatta_handle_t shell_handle)
size_t uart_input_len; size_t uart_input_len;
/* Handle UART input for shell */ /* Handle UART input for shell */
uart_receive_status = uart_receive_data_with_dma(&shell_uart, &uart_input, &uart_input_len); uart_receive_status = shell_uart_receive_data_with_dma(&uart_input, &uart_input_len);
if (uart_receive_status >= 0) if (uart_receive_status >= 0)
shell_handle_input(shell_handle, uart_input, uart_input_len); shell_handle_input(shell_handle, uart_input, uart_input_len);
} }
/**
* @brief This is the main function containing the initilizations and the cyclic main loop
* @return Don't care. This function will never return. We're on an embedded device...
*/
int main(void) int main(void)
{ {
bool cal_active; bool cal_active;
@ -218,76 +256,99 @@ int main(void)
shellmatta_handle_t shell_handle; shellmatta_handle_t shell_handle;
int menu_wait_request; int menu_wait_request;
uint64_t quarter_sec_timestamp = 0ULL; uint64_t quarter_sec_timestamp = 0ULL;
static uint64_t IN_SECTION(.ccm.bss) main_loop_iter_count; enum config_weight worst_safety_flag = SAFETY_FLAG_CONFIG_WEIGHT_NONE;
/** - Setup all the peripherals and external componets like LCD, EEPROM etc. and the safety controller */
setup_system(); setup_system();
/* Try load the calibration. This will only succeed if there's an EEPROM */ /** - Try load the calibration. This will only succeed if there's an EEPROM */
status = settings_load_calibration(&sens, &offset); status = settings_load_calibration(&sens, &offset);
if (!status) { if (!status)
adc_pt1000_set_resistance_calibration(offset, sens, true); adc_pt1000_set_resistance_calibration(offset, sens, true);
}
shell_handle = shell_init(write_shell_callback); /** - Initialize the shellmatta shell */
shell_handle = shell_init(shell_uart_write_callback);
/** - Print motd to shell */
shell_print_motd(shell_handle); shell_print_motd(shell_handle);
/** - Set the main cycle counter to 0 and activate the core cycle counter if available */
main_and_core_cycle_counter_init();
/** - Do a loop over the following */
while (1) { while (1) {
/** - If 250 ms have passed since the last time this step was reached, we try to initialize the
* SD card. If the card has been mounted and there is no current resistance calibration,
* it is tried to load it from SD card.
*/
if (systick_ticks_have_passed(quarter_sec_timestamp, 250)) { if (systick_ticks_have_passed(quarter_sec_timestamp, 250)) {
led_set(1, 0); led_set(1u, 0);
sd_old = sd_card_mounted; sd_old = sd_card_mounted;
sd_card_mounted = mount_sd_card_if_avail(sd_card_mounted); sd_card_mounted = mount_sd_card_if_avail(fs_ptr);
if (sd_card_mounted && !sd_old) { if (sd_card_mounted && !sd_old) {
adc_pt1000_get_resistance_calibration(NULL, NULL, &cal_active); adc_pt1000_get_resistance_calibration(NULL, NULL, &cal_active);
if (!cal_active) { if (!cal_active) {
status = settings_load_calibration(&sens, &offset); status = settings_load_calibration(&sens, &offset);
if (!status) { if (!status)
adc_pt1000_set_resistance_calibration(offset, sens, true); adc_pt1000_set_resistance_calibration(offset, sens, true);
}
} }
} }
/* Check if any flags are present, that disable the PID controller. Blink
* LED 0 in this case
*/
if (worst_safety_flag >= SAFETY_FLAG_CONFIG_WEIGHT_PID)
led_set(0u, led_get(0u) ? 0 : 1);
else
led_set(0u, 0);
quarter_sec_timestamp = systick_get_global_tick(); quarter_sec_timestamp = systick_get_global_tick();
} }
/** - Handle the GUI */
menu_wait_request = gui_handle(); menu_wait_request = gui_handle();
/** - Handle the uart input for the shell */
handle_shell_uart_input(shell_handle); handle_shell_uart_input(shell_handle);
/* Execute current profile step, if a profile is active */ /** - Execute current profile step, if a profile is active */
temp_profile_executer_handle(); temp_profile_executer_handle();
safety_controller_handle(); /** - Handle the safety controller. This must be called! Otherwise a watchdog reset will occur */
if (oven_pid_get_status() == OVEN_PID_RUNNING) { worst_safety_flag = safety_controller_handle();
/** - If the Oven PID controller is running, we handle its sample function */
if (oven_pid_get_status() == OVEN_PID_RUNNING)
oven_pid_handle(); oven_pid_handle();
}
/** - Apply the power level of the oven driver */
oven_driver_apply_power_level(); oven_driver_apply_power_level();
/** - Report the main loop timing to the timing monitor to detect a slowed down main loop */
safety_controller_report_timing(ERR_TIMING_MAIN_LOOP); safety_controller_report_timing(ERR_TIMING_MAIN_LOOP);
/** - If the menu requests a directly following loop run, the main loop will continue.
* Otherwise it will wait for the next interrupt
*/
if (menu_wait_request) if (menu_wait_request)
__WFI(); __WFI();
else else
__NOP(); __NOP();
main_loop_iter_count++; /** - Increment the main cycle counter */
main_cycle_counter_inc();
} }
return 0; return 0;
} }
/**
* @brief Callback function for the SDIO driver to wait \p ms milliseconds
* @param ms
* @warning This function relies on the systick and must not be used in interrupt context.
*/
void sdio_wait_ms(uint32_t ms) void sdio_wait_ms(uint32_t ms)
{ {
systick_wait_ms(ms); systick_wait_ms(ms);
} }
/**
* @brief Handles the TX of UART1 (Shellmatta)
*/
void DMA2_Stream7_IRQHandler(void)
{
uint32_t hisr = DMA2->HISR & (0x3F << 22);
DMA2->HIFCR = hisr;
if (hisr & DMA_HISR_TCIF7)
uart_tx_dma_complete_int_callback(&shell_uart);
}

View File

@ -18,6 +18,11 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
/**
* @addtogroup oven-driver
* @{
*/
#include <reflow-controller/oven-driver.h> #include <reflow-controller/oven-driver.h>
#include <reflow-controller/periph-config/oven-driver-hwcfg.h> #include <reflow-controller/periph-config/oven-driver-hwcfg.h>
#include <stm-periph/rcc-manager.h> #include <stm-periph/rcc-manager.h>
@ -28,13 +33,42 @@
#include <reflow-controller/safety/safety-controller.h> #include <reflow-controller/safety/safety-controller.h>
#include <reflow-controller/hw-version-detect.h> #include <reflow-controller/hw-version-detect.h>
/**
* @brief PID controller instance of the oven driver
*/
static struct pid_controller IN_SECTION(.ccm.bss) oven_pid; static struct pid_controller IN_SECTION(.ccm.bss) oven_pid;
static bool oven_pid_running;
static bool oven_pid_aborted; /**
* @brief Oven PID is currently running
*/
static bool IN_SECTION(.ccm.bss) oven_pid_running;
/**
* @brief Oven PID has been aborted / abnormally stopped.
*/
static bool IN_SECTION(.ccm.bss) oven_pid_aborted;
/**
* @brief Power level [0..100] of the oven to be applied
*/
static uint8_t IN_SECTION(.ccm.bss) oven_driver_power_level; static uint8_t IN_SECTION(.ccm.bss) oven_driver_power_level;
/**
* @brief Current target temperature of the oven PID controller in degC
*/
static float IN_SECTION(.ccm.bss) target_temp; static float IN_SECTION(.ccm.bss) target_temp;
/**
* @brief The millisecond timestamp of the last run of the PID controller
*/
static uint64_t IN_SECTION(.ccm.bss) timestamp_last_run; static uint64_t IN_SECTION(.ccm.bss) timestamp_last_run;
/**
* @brief Enable or disable the safety enable line of the oven control relay.
* @param enable
* @note This function is only working for hardware revisions >= v1.3. Below,
* the safety enable is unavailable.
*/
static void ssr_safety_en(bool enable) static void ssr_safety_en(bool enable)
{ {
if (get_pcb_hardware_version() >= HW_REV_V1_3) { if (get_pcb_hardware_version() >= HW_REV_V1_3) {
@ -165,3 +199,5 @@ enum oven_pid_status oven_pid_get_status(void)
return ret; return ret;
} }
/** @} */

View File

@ -18,6 +18,10 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @addtogroup pid-controller
* @{
*/
#include <reflow-controller/pid-controller.h> #include <reflow-controller/pid-controller.h>
#include <string.h> #include <string.h>
@ -85,7 +89,8 @@ float pid_sample(struct pid_controller *pid, float deviation)
} }
/* Calculate derivative part */ /* Calculate derivative part */
pid->derivate = pid->k_deriv_t * (deviation - pid->last_in) - pid->k_inv_deriv_t * pid->derivate; pid->derivate = pid->k_deriv_t * (deviation - pid->last_in) +
pid->k_inv_deriv_t * pid->derivate;
output += pid->derivate; output += pid->derivate;
output += pid->integral; output += pid->integral;
@ -109,3 +114,5 @@ float pid_get_control_output(const struct pid_controller *pid)
return pid->control_output; return pid->control_output;
} }
/** @} */

View File

@ -24,10 +24,15 @@
#include <reflow-controller/safety/safety-memory.h> #include <reflow-controller/safety/safety-memory.h>
#include <helper-macros/helper-macros.h> #include <helper-macros/helper-macros.h>
/**
* @brief Handler for hard faults.
*
* This hard fault handler will turn of the oven output and go to panic mode.
* @note Depending on the fault condition some of the things done here could fail.
*/
void HardFault_Handler(void) void HardFault_Handler(void)
{ {
/* This is a non recoverable fault. Stop the oven */ /* This is a non recoverable fault. Stop the oven */
oven_driver_set_power(0); oven_driver_set_power(0);
oven_driver_apply_power_level(); oven_driver_apply_power_level();
@ -39,11 +44,26 @@ void HardFault_Handler(void)
} }
/* Overwrite default handler. Go to panic mode */ /* Overwrite default handler. Go to panic mode */
/**
* @brief Default interrupt handler. This will trigger a panic.
* @note This function should never be called during normal operation.
*/
void __int_default_handler(void) void __int_default_handler(void)
{ {
panic_mode(); panic_mode();
} }
/**
* @brief Put the device into panic mode.
*
* This function can be used when a irrecoverable error is encountered.
* The function will:
* - Disable the oven output
* - Set the panic flag in the safety memory
* - Hang and wait for the watchdog to trigger a system reset.
*
* The panic state will be entered after the reset due to the set panic flag in the safety memory
*/
void panic_mode(void) void panic_mode(void)
{ {
/* This variable is static, because I don't want it to be on the stack */ /* This variable is static, because I don't want it to be on the stack */
@ -58,5 +78,6 @@ void panic_mode(void)
} }
/* Let the watchdog do the rest */ /* Let the watchdog do the rest */
while (1); while (1)
;
} }

View File

@ -0,0 +1,31 @@
/* Reflow Oven Controller
*
* Copyright (C) 2022 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/safety/flash-crc-struct.h>
#include <helper-macros/helper-macros.h>
const struct flash_crcs IN_SECTION(.flashcrc) crcs_in_flash = {
.start_magic = 0xA8BE53F9UL,
.crc_section_ccm_data = 0UL,
.crc_section_text = 0UL,
.crc_section_data = 0UL,
.crc_section_vectors = 0UL,
.end_magic = 0xFFA582FFUL,
};

View File

@ -0,0 +1,152 @@
/* Reflow Oven Controller
*
* Copyright (C) 2022 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/safety/flash-crc.h>
#include <reflow-controller/safety/flash-crc-struct.h>
#include <reflow-controller/safety/safety-controller.h>
#include <stm-periph/crc-unit.h>
extern const uint32_t __ld_vectors_start;
extern const uint32_t __ld_vectors_end;
extern const uint32_t __ld_text_start;
extern const uint32_t __ld_text_end;
extern const uint32_t __ld_sdata_ccm;
extern const uint32_t __ld_edata_ccm;
extern const uint32_t __ld_load_ccm_data;
extern const uint32_t __ld_sdata;
extern const uint32_t __ld_edata;
extern const uint32_t __ld_load_data;
int flash_crc_trigger_check(void)
{
int ret = -1;
int res;
int any_err = 0;
uint32_t crc;
/* Perform CRC check over vector table */
res = flash_crc_calc_section(FLASH_CRC_VECTOR, &crc);
if (res || crc != flash_crc_get_expected_crc(FLASH_CRC_VECTOR))
safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE);
any_err |= res;
/* Perform CRC check over text section */
res = flash_crc_calc_section(FLASH_CRC_TEXT, &crc);
if (res || crc != flash_crc_get_expected_crc(FLASH_CRC_TEXT))
safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE);
any_err |= res;
/* Perform CRC check over data section */
res = flash_crc_calc_section(FLASH_CRC_DATA, &crc);
if (res || crc != flash_crc_get_expected_crc(FLASH_CRC_DATA))
safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA);
any_err |= res;
/* Perform CRC check over ccm data section */
res = flash_crc_calc_section(FLASH_CRC_CCMDATA, &crc);
if (res || crc != flash_crc_get_expected_crc(FLASH_CRC_CCMDATA))
safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA);
any_err |= res;
if (!any_err)
ret = 0;
return ret;
}
int flash_crc_calc_section(enum flash_crc_section sec, uint32_t *crc_result)
{
uint32_t len;
const uint32_t *startptr;
const uint32_t *endptr;
const uint32_t *load_addr = NULL;
if (!crc_result)
return -1002;
switch (sec) {
case FLASH_CRC_VECTOR:
startptr = &__ld_vectors_start;
endptr = &__ld_vectors_end;
break;
case FLASH_CRC_TEXT:
startptr = &__ld_text_start;
endptr = &__ld_text_end;
break;
case FLASH_CRC_DATA:
startptr = &__ld_sdata;
endptr = &__ld_edata;
load_addr = &__ld_load_data;
break;
case FLASH_CRC_CCMDATA:
startptr = &__ld_sdata_ccm;
endptr = &__ld_edata_ccm;
load_addr = &__ld_load_ccm_data;
break;
default:
return -1001;
}
len = (uint32_t)((void *)endptr - (void *)startptr);
if (!load_addr)
load_addr = startptr;
/* Not a multiple of 32bit words long. Cannot calculate CRC in this case! */
if (len % 4)
return -1;
/* Calculate word count */
len /= 4;
/* Reset CRC and calculate over data range */
crc_unit_reset();
crc_unit_input_array(load_addr, len);
*crc_result = crc_unit_get_crc();
return 0;
}
uint32_t flash_crc_get_expected_crc(enum flash_crc_section sec)
{
uint32_t crc;
switch (sec) {
case FLASH_CRC_VECTOR:
crc = crcs_in_flash.crc_section_vectors;
break;
case FLASH_CRC_TEXT:
crc = crcs_in_flash.crc_section_text;
break;
case FLASH_CRC_DATA:
crc = crcs_in_flash.crc_section_data;
break;
case FLASH_CRC_CCMDATA:
crc = crcs_in_flash.crc_section_ccm_data;
break;
default:
crc = 0xFFFFFFFFul;
break;
}
return crc;
}

View File

@ -1,22 +1,22 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * 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 * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @addtogroup safety-adc * @addtogroup safety-adc
@ -28,10 +28,25 @@
#include <helper-macros/helper-macros.h> #include <helper-macros/helper-macros.h>
#include <stm-periph/rcc-manager.h> #include <stm-periph/rcc-manager.h>
#include <reflow-controller/hw-version-detect.h> #include <reflow-controller/hw-version-detect.h>
#include <reflow-controller/safety/safety-controller.h>
static const uint8_t safety_adc_channels[SAFETY_ADC_NUM_OF_CHANNELS] = {SAFETY_ADC_CHANNELS}; static const uint8_t safety_adc_channels[SAFETY_ADC_NUM_OF_CHANNELS] = {SAFETY_ADC_CHANNELS};
static volatile uint8_t safety_adc_conversion_complete;
static volatile uint8_t safety_adc_triggered; /**
* @brief Safety ADC conversion complete. Set in interrupt.
*/
static volatile uint8_t IN_SECTION(.ccm.bss) safety_adc_conversion_complete;
/**
* @brief Safety ADC has been started. It will perform all specified conversions and
* set @ref safety_adc_conversion_complete afterwards
*/
static volatile uint8_t IN_SECTION(.ccm.bss) safety_adc_triggered;
/**
* @brief Safety ADC conversion storage. This is filled by DMA.
* @note Do not move this to CCM RAM as the DMA won't be able to access it.
*/
static volatile uint16_t safety_adc_conversions[SAFETY_ADC_NUM_OF_CHANNELS]; static volatile uint16_t safety_adc_conversions[SAFETY_ADC_NUM_OF_CHANNELS];
void safety_adc_init(void) void safety_adc_init(void)
@ -45,7 +60,8 @@ void safety_adc_init(void)
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN)); rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
if (hw_rev != HW_REV_V1_2) { if (hw_rev != HW_REV_V1_2) {
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT_RCC_MASK)); rcc_manager_enable_clock(&RCC->AHB1ENR,
BITMASK_TO_BITNO(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT_RCC_MASK));
SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT->MODER &= MODER_DELETE(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN); SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT->MODER &= MODER_DELETE(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN);
SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT->MODER |= ANALOG(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN); SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT->MODER |= ANALOG(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN);
} }
@ -57,7 +73,7 @@ void safety_adc_init(void)
SAFETY_ADC_ADC_PERIPHERAL->SMPR1 |= ADC_SMPR1_SMP17 | ADC_SMPR1_SMP16 | ADC_SMPR1_SMP15; SAFETY_ADC_ADC_PERIPHERAL->SMPR1 |= ADC_SMPR1_SMP17 | ADC_SMPR1_SMP16 | ADC_SMPR1_SMP15;
/* Standard sequence. Measure all channels in one sequence */ /* Standard sequence. Measure all channels in one sequence */
SAFETY_ADC_ADC_PERIPHERAL->SQR1 = (SAFETY_ADC_NUM_OF_CHANNELS - 1) << 20 ; SAFETY_ADC_ADC_PERIPHERAL->SQR1 = (SAFETY_ADC_NUM_OF_CHANNELS - 1) << 20;
SAFETY_ADC_ADC_PERIPHERAL->SQR2 = 0UL; SAFETY_ADC_ADC_PERIPHERAL->SQR2 = 0UL;
SAFETY_ADC_ADC_PERIPHERAL->SQR3 = 0UL; SAFETY_ADC_ADC_PERIPHERAL->SQR3 = 0UL;
@ -82,11 +98,14 @@ void safety_adc_init(void)
DMA2_Stream4->PAR = (uint32_t)&SAFETY_ADC_ADC_PERIPHERAL->DR; DMA2_Stream4->PAR = (uint32_t)&SAFETY_ADC_ADC_PERIPHERAL->DR;
DMA2_Stream4->M0AR = (uint32_t)safety_adc_conversions; DMA2_Stream4->M0AR = (uint32_t)safety_adc_conversions;
DMA2_Stream4->NDTR = SAFETY_ADC_NUM_OF_CHANNELS; DMA2_Stream4->NDTR = SAFETY_ADC_NUM_OF_CHANNELS;
DMA2_Stream4->CR = DMA_SxCR_PL_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC | DMA_SxCR_CIRC | DMA_SxCR_TCIE | DMA_SxCR_EN; DMA2_Stream4->CR = DMA_SxCR_PL_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC | DMA_SxCR_CIRC |
DMA_SxCR_TCIE | DMA_SxCR_EN;
NVIC_EnableIRQ(DMA2_Stream4_IRQn); NVIC_EnableIRQ(DMA2_Stream4_IRQn);
/* Enable ADC */ /* Enable ADC */
SAFETY_ADC_ADC_PERIPHERAL->CR1 |= ADC_CR1_SCAN;
SAFETY_ADC_ADC_PERIPHERAL->CR2 = ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS; SAFETY_ADC_ADC_PERIPHERAL->CR2 = ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
safety_controller_set_crc_monitor(ERR_CRC_MON_SAFETY_ADC, SAFETY_CRC_MON_SAFETY_ADC_PW);
} }
@ -95,9 +114,11 @@ void safety_adc_deinit(void)
SAFETY_ADC_ADC_PERIPHERAL->CR1 = 0UL; SAFETY_ADC_ADC_PERIPHERAL->CR1 = 0UL;
SAFETY_ADC_ADC_PERIPHERAL->CR2 = 0UL; SAFETY_ADC_ADC_PERIPHERAL->CR2 = 0UL;
SAFETY_ADC_ADC_PERIPHERAL->SMPR1 = 0UL; SAFETY_ADC_ADC_PERIPHERAL->SMPR1 = 0UL;
rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC2EN)); rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC2EN));
DMA2_Stream4->CR = 0; DMA2_Stream4->CR = 0;
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN)); rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
safety_controller_set_crc_monitor(ERR_CRC_MON_SAFETY_ADC, SAFETY_CRC_MON_SAFETY_ADC_PW);
} }
float safety_adc_convert_channel(enum safety_adc_meas_channel channel, uint16_t analog_value) float safety_adc_convert_channel(enum safety_adc_meas_channel channel, uint16_t analog_value)
@ -156,7 +177,7 @@ void safety_adc_trigger_meas(void)
safety_adc_triggered = 1; safety_adc_triggered = 1;
} }
void DMA2_Stream4_IRQHandler() void DMA2_Stream4_IRQHandler(void)
{ {
uint32_t hisr; uint32_t hisr;

View File

@ -1,28 +1,29 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * 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 * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @addtogroup safety-controller * @addtogroup safety-controller
* @{ * @{
*/ */
#include "stm32/stm32f407xx.h"
#include <reflow-controller/safety/safety-controller.h> #include <reflow-controller/safety/safety-controller.h>
#include <reflow-controller/safety/safety-config.h> #include <reflow-controller/safety/safety-config.h>
#include <reflow-controller/safety/watchdog.h> #include <reflow-controller/safety/watchdog.h>
@ -43,6 +44,8 @@
#include <stm-periph/rcc-manager.h> #include <stm-periph/rcc-manager.h>
#include <reflow-controller/temp-converter.h> #include <reflow-controller/temp-converter.h>
#include <reflow-controller/adc-meas.h> #include <reflow-controller/adc-meas.h>
#include <reflow-controller/safety/flash-crc.h>
#include <reflow-controller/periph-config/safety-adc-hwcfg.h>
/** /**
* @brief Macro that checks if a given @ref error_flag is persistent * @brief Macro that checks if a given @ref error_flag is persistent
@ -153,6 +156,34 @@ struct overtemp_config {
uint32_t crc; uint32_t crc;
}; };
struct crc_monitor_register {
const volatile void *reg_addr;
uint32_t mask;
uint8_t size;
};
#define CRC_MON_REGISTER_ENTRY(_addr, _mask, _size) {.reg_addr = &(_addr), .mask = (_mask), .size = (_size)}
/**
* @brief Sentinel Element for crc monitor register list
*
*/
#define CRC_MON_REGISTER_SENTINEL {.reg_addr = NULL, .mask = 0, .size = 0}
struct crc_mon {
/**
* @brief Array of registers to monitor. Terminated by NULL sentinel @ref CRC_MON_REGISTER_SENTINEL
*/
const struct crc_monitor_register *registers;
const enum crc_monitor monitor;
const uint32_t pw;
const enum safety_flag flag_to_set;
uint32_t expected_crc;
uint32_t expected_crc_inv;
uint32_t last_crc;
bool active;
};
/** /**
* @brief All safety error flags. * @brief All safety error flags.
*/ */
@ -176,11 +207,16 @@ static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = {
ERR_FLAG_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT), ERR_FLAG_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT),
ERR_FLAG_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT), ERR_FLAG_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT),
ERR_FLAG_ENTRY(ERR_FLAG_OVERTEMP), ERR_FLAG_ENTRY(ERR_FLAG_OVERTEMP),
ERR_FLAG_ENTRY(ERR_FLAG_FLASH_CRC_CODE),
ERR_FLAG_ENTRY(ERR_FLAG_FLASH_CRC_DATA),
ERR_FLAG_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC),
ERR_FLAG_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC),
ERR_FLAG_ENTRY(ERR_FLAG_CFG_CRC_MISC),
}; };
/** /**
* @brief All timing monitors * @brief All timing monitors
*/ */
static volatile struct timing_mon IN_SECTION(.ccm.data) timings[] = { static volatile struct timing_mon IN_SECTION(.ccm.data) timings[] = {
TIM_MON_ENTRY(ERR_TIMING_PID, 2, 5000, ERR_FLAG_TIMING_PID), TIM_MON_ENTRY(ERR_TIMING_PID, 2, 5000, ERR_FLAG_TIMING_PID),
TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 0, 50, ERR_FLAG_TIMING_MEAS_ADC), TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 0, 50, ERR_FLAG_TIMING_MEAS_ADC),
@ -248,6 +284,90 @@ static uint32_t IN_SECTION(.ccm.bss) flag_weight_crc;
*/ */
static struct overtemp_config IN_SECTION(.ccm.bss) safety_controller_overtemp_config; static struct overtemp_config IN_SECTION(.ccm.bss) safety_controller_overtemp_config;
static const struct crc_monitor_register meas_adc_crc_regs[] = {
CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->CR1, 0xFFFFFFFF, 4),
CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->CR2, ADC_CR2_ADON | ADC_CR2_CONT | ADC_CR2_ALIGN |
ADC_CR2_DMA | ADC_CR2_DDS | ADC_CR2_EOCS | ADC_CR2_EXTEN | ADC_CR2_EXTSEL, 4),
CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->SMPR1, 0xFFFFFFFF, 4),
CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->SMPR2, 0xFFFFFFFF, 4),
CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->HTR, ADC_HTR_HT, 4),
CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->LTR, ADC_LTR_LT, 4),
CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->SQR1, ADC_SQR1_L |
ADC_SQR1_SQ16 | ADC_SQR1_SQ15 | ADC_SQR1_SQ14 | ADC_SQR1_SQ13, 4),
CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->SQR2,
ADC_SQR2_SQ12 | ADC_SQR2_SQ11 | ADC_SQR2_SQ10 | ADC_SQR2_SQ9 |
ADC_SQR2_SQ8 | ADC_SQR2_SQ7, 4),
CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->SQR3, ADC_SQR3_SQ6 | ADC_SQR3_SQ5 | ADC_SQR3_SQ4 |
ADC_SQR3_SQ3 | ADC_SQR3_SQ2 | ADC_SQR3_SQ1, 4),
CRC_MON_REGISTER_SENTINEL
};
static const struct crc_monitor_register safety_adc_crc_regs[] = {
CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->CR1, 0xFFFFFFFF, 4),
CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->CR2, ADC_CR2_ADON | ADC_CR2_CONT | ADC_CR2_ALIGN |
ADC_CR2_DMA | ADC_CR2_DDS | ADC_CR2_EOCS | ADC_CR2_EXTEN | ADC_CR2_EXTSEL, 4),
CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->SMPR1, 0xFFFFFFFF, 4),
CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->SMPR2, 0xFFFFFFFF, 4),
CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->SQR1, ADC_SQR1_L |
ADC_SQR1_SQ16 | ADC_SQR1_SQ15 | ADC_SQR1_SQ14 | ADC_SQR1_SQ13, 4),
CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->SQR2,
ADC_SQR2_SQ12 | ADC_SQR2_SQ11 | ADC_SQR2_SQ10 | ADC_SQR2_SQ9 |
ADC_SQR2_SQ8 | ADC_SQR2_SQ7, 4),
CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->SQR3, ADC_SQR3_SQ6 | ADC_SQR3_SQ5 | ADC_SQR3_SQ4 |
ADC_SQR3_SQ3 | ADC_SQR3_SQ2 | ADC_SQR3_SQ1, 4),
CRC_MON_REGISTER_ENTRY(RCC->APB2ENR, SAFETY_ADC_ADC_RCC_MASK, 4),
CRC_MON_REGISTER_SENTINEL
};
static const struct crc_monitor_register misc_config_crc_regs[] = {
/* Check clock tree settings */
CRC_MON_REGISTER_ENTRY(RCC->CR, RCC_CR_PLLON | RCC_CR_HSEON | RCC_CR_PLLI2SON | RCC_CR_HSION, 4),
CRC_MON_REGISTER_ENTRY(RCC->CSR, RCC_CSR_LSION, 4),
CRC_MON_REGISTER_ENTRY(RCC->CFGR, RCC_CFGR_SWS | RCC_CFGR_HPRE | RCC_CFGR_PPRE1 | RCC_CFGR_PPRE2, 4),
CRC_MON_REGISTER_ENTRY(RCC->PLLCFGR, RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLQ | RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLP | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLM , 4),
/* Check Flash settings */
CRC_MON_REGISTER_ENTRY(FLASH->ACR, FLASH_ACR_LATENCY | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_PRFTEN, 4),
/* Check vector table offset */
CRC_MON_REGISTER_ENTRY(SCB->VTOR, 0xFFFFFFFF, 4),
/* Check system tick configuration */
CRC_MON_REGISTER_ENTRY(SysTick->CTRL, SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk, 4),
CRC_MON_REGISTER_ENTRY(SysTick->LOAD, 0xFFFFFFFF, 4),
CRC_MON_REGISTER_SENTINEL
};
static struct crc_mon IN_SECTION(.ccm.data) crc_monitors[] = {
{
.registers = meas_adc_crc_regs,
.monitor = ERR_CRC_MON_MEAS_ADC,
.pw = SAFETY_CRC_MON_MEAS_ADC_PW,
.flag_to_set = ERR_FLAG_CFG_CRC_MEAS_ADC,
.expected_crc = 0UL,
.expected_crc_inv = ~0UL,
.last_crc = 0UL,
.active = false,
},
{
.registers = safety_adc_crc_regs,
.monitor = ERR_CRC_MON_SAFETY_ADC,
.pw = SAFETY_CRC_MON_SAFETY_ADC_PW,
.flag_to_set = ERR_FLAG_CFG_CRC_SAFETY_ADC,
.expected_crc = 0UL,
.expected_crc_inv = ~0UL,
.last_crc = 0UL,
.active = false,
},
{
.registers = misc_config_crc_regs,
.monitor = ERR_CRC_MON_MISC,
.pw = SAFETY_CRC_MON_MISC_PW,
.flag_to_set = ERR_FLAG_CFG_CRC_MISC,
.expected_crc = 0UL,
.expected_crc_inv = ~0UL,
.last_crc = 0UL,
.active = false,
}
};
/** /**
* @brief Configure the overtemperature flag's settings * @brief Configure the overtemperature flag's settings
* @param over_temperature Temperature to set the limit to. * @param over_temperature Temperature to set the limit to.
@ -257,7 +377,7 @@ static void set_overtemp_config(float over_temperature)
int result; int result;
float resistance; float resistance;
result = temp_convertet_convert_temp_to_resistance(over_temperature, &resistance); result = temp_converter_convert_temp_to_resistance(over_temperature, &resistance);
/* An error in this function is really bad... */ /* An error in this function is really bad... */
if (result < -1) if (result < -1)
panic_mode(); panic_mode();
@ -266,16 +386,22 @@ static void set_overtemp_config(float over_temperature)
safety_controller_overtemp_config.crc_dummy_seed = 0xA4F5C7E6UL; safety_controller_overtemp_config.crc_dummy_seed = 0xA4F5C7E6UL;
safety_controller_overtemp_config.overtemp_deg_celsius = over_temperature; safety_controller_overtemp_config.overtemp_deg_celsius = over_temperature;
safety_controller_overtemp_config.overtemp_equiv_resistance = resistance; safety_controller_overtemp_config.overtemp_equiv_resistance = resistance;
crc_unit_input_array((const uint32_t *)&safety_controller_overtemp_config, wordsize_of(struct overtemp_config) - 1); crc_unit_input_array((const uint32_t *)&safety_controller_overtemp_config,
wordsize_of(struct overtemp_config) - 1);
safety_controller_overtemp_config.crc = crc_unit_get_crc(); safety_controller_overtemp_config.crc = crc_unit_get_crc();
} }
/**
* @brief Check the overtemperature config structure's CRC
* @return true if check failed. false if CRC check successful
*/
static bool over_temperature_config_check(void) static bool over_temperature_config_check(void)
{ {
if (safety_controller_overtemp_config.crc_dummy_seed != 0xA4F5C7E6UL) if (safety_controller_overtemp_config.crc_dummy_seed != 0xA4F5C7E6UL)
return true; return true;
crc_unit_reset(); crc_unit_reset();
crc_unit_input_array((const uint32_t *)&safety_controller_overtemp_config, wordsize_of(struct overtemp_config) - 1); crc_unit_input_array((const uint32_t *)&safety_controller_overtemp_config,
wordsize_of(struct overtemp_config) - 1);
if (crc_unit_get_crc() != safety_controller_overtemp_config.crc) if (crc_unit_get_crc() != safety_controller_overtemp_config.crc)
return true; return true;
@ -348,7 +474,7 @@ static int flag_weight_table_crc_check(void)
static int flag_persistence_table_crc_check(void) static int flag_persistence_table_crc_check(void)
{ {
crc_unit_reset(); crc_unit_reset();
crc_unit_input_array((uint32_t*)flag_persistencies, wordsize_of(flag_persistencies)); crc_unit_input_array((uint32_t *)flag_persistencies, wordsize_of(flag_persistencies));
if (crc_unit_get_crc() != flag_persistencies_crc) if (crc_unit_get_crc() != flag_persistencies_crc)
return -1; return -1;
@ -378,6 +504,61 @@ static volatile struct error_flag *find_error_flag(enum safety_flag flag)
return ret; return ret;
} }
static int crc_monitor_calculate_crc(const struct crc_monitor_register *registers, uint32_t *crc_out)
{
const struct crc_monitor_register *reg;
uint32_t i;
uint32_t reg_val;
if (!registers || !crc_out)
return -1000;
crc_unit_reset();
for (i = 0; registers[i].reg_addr != NULL; i++) {
reg = &registers[i];
switch (reg->size) {
case 1:
reg_val = *((volatile uint8_t *)reg->reg_addr);
break;
case 2:
reg_val = *((volatile uint16_t *)reg->reg_addr);
break;
case 4: /* FALLTHRU */
default:
reg_val = *((volatile uint32_t *)reg->reg_addr);
break;
}
reg_val &= reg->mask;
crc_unit_input(reg_val);
}
*crc_out = crc_unit_get_crc();
return 0;
}
static int safety_controller_check_crc_monitors(void)
{
uint32_t i;
struct crc_mon *mon;
uint32_t crc;
for (i = 0; i < COUNT_OF(crc_monitors); i++) {
mon = &crc_monitors[i];
if (!mon->active)
continue;
if (crc_monitor_calculate_crc(mon->registers, &crc))
return -1;
if (mon->expected_crc != crc || ~mon->expected_crc_inv != crc)
safety_controller_report_error(mon->flag_to_set);
mon->last_crc = crc;
}
return 0;
}
/** /**
* @brief This function copies the safety weigths from flash ro RAM and computes the CRC * @brief This function copies the safety weigths from flash ro RAM and computes the CRC
*/ */
@ -398,7 +579,7 @@ static void init_safety_flag_weight_table_from_default(void)
} }
crc_unit_reset(); crc_unit_reset();
crc_unit_input_array((uint32_t*)flag_weights, wordsize_of(flag_weights)); crc_unit_input_array((uint32_t *)flag_weights, wordsize_of(flag_weights));
flag_weight_crc = crc_unit_get_crc(); flag_weight_crc = crc_unit_get_crc();
} }
@ -458,16 +639,14 @@ static void apply_config_overrides(void)
case SAFETY_MEMORY_CONFIG_OVERRIDE_WEIGHT: case SAFETY_MEMORY_CONFIG_OVERRIDE_WEIGHT:
flag_enum = flag_no_to_flag_enum(override.entry.weight_override.flag); flag_enum = flag_no_to_flag_enum(override.entry.weight_override.flag);
flag = find_error_flag(flag_enum); flag = find_error_flag(flag_enum);
if (flag && flag->weight) { if (flag && flag->weight)
flag->weight->weight = override.entry.weight_override.weight; flag->weight->weight = override.entry.weight_override.weight;
}
break; break;
case SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE: case SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE:
flag_enum = flag_no_to_flag_enum(override.entry.persistence_override.flag); flag_enum = flag_no_to_flag_enum(override.entry.persistence_override.flag);
flag = find_error_flag(flag_enum); flag = find_error_flag(flag_enum);
if (flag && flag->persistence) { if (flag && flag->persistence)
flag->persistence->persistence = override.entry.persistence_override.persistence; flag->persistence->persistence = override.entry.persistence_override.persistence;
}
break; break;
default: default:
continue; continue;
@ -479,7 +658,7 @@ static void apply_config_overrides(void)
crc_unit_input_array((uint32_t *)flag_persistencies, wordsize_of(flag_persistencies)); crc_unit_input_array((uint32_t *)flag_persistencies, wordsize_of(flag_persistencies));
flag_persistencies_crc = crc_unit_get_crc(); flag_persistencies_crc = crc_unit_get_crc();
crc_unit_reset(); crc_unit_reset();
crc_unit_input_array((uint32_t*)flag_weights, wordsize_of(flag_weights)); crc_unit_input_array((uint32_t *)flag_weights, wordsize_of(flag_weights));
flag_weight_crc = crc_unit_get_crc(); flag_weight_crc = crc_unit_get_crc();
} }
@ -497,11 +676,10 @@ static bool error_flag_get_status(const volatile struct error_flag *flag)
if (!flag) if (!flag)
return true; return true;
if (flag->error_state == flag->error_state_inv) { if (flag->error_state == flag->error_state_inv)
return true; return true;
} else { else
return flag->error_state; return flag->error_state;
}
} }
/** /**
@ -543,7 +721,7 @@ static volatile struct timing_mon *find_timing_mon(enum timing_monitor mon)
/** /**
* @brief Check the active timing monitors and set the appropriate flags in case of an error. * @brief Check the active timing monitors and set the appropriate flags in case of an error.
*/ */
static void safety_controller_process_active_timing_mons() static void safety_controller_process_active_timing_mons(void)
{ {
uint32_t i; uint32_t i;
volatile struct timing_mon *current_mon; volatile struct timing_mon *current_mon;
@ -566,7 +744,8 @@ static void safety_controller_process_active_timing_mons()
* Process the analog and timing monitors and set the relevant flags in case of a monitor outside its limits. * Process the analog and timing monitors and set the relevant flags in case of a monitor outside its limits.
* Furthermore, the PT1000 resistance is checked for overtemperature * Furthermore, the PT1000 resistance is checked for overtemperature
* *
* The checking of the analog monitors will only be armed after a startup delay of 1000 ms to allow the values to stabilize. * The checking of the analog monitors will only be armed after a startup delay of 1000 ms to
* allow the values to stabilize.
*/ */
static void safety_controller_process_monitor_checks(void) static void safety_controller_process_monitor_checks(void)
{ {
@ -581,21 +760,20 @@ static void safety_controller_process_monitor_checks(void)
if (startup_completed) { if (startup_completed) {
analog_mon_count = safety_controller_get_analog_monitor_count(); analog_mon_count = safety_controller_get_analog_monitor_count();
for (idx = 0; idx < analog_mon_count; idx++) { for (idx = 0; idx < analog_mon_count; idx++)
if (safety_controller_get_analog_mon_by_index(idx, &amon_info)) { if (safety_controller_get_analog_mon_by_index(idx, &amon_info)) {
panic_mode(); panic_mode();
}
if (amon_info.status != ANALOG_MONITOR_OK) { if (amon_info.status != ANALOG_MONITOR_OK)
safety_controller_report_error(amon_info.associated_flag); safety_controller_report_error(amon_info.associated_flag);
}
} }
} }
adc_pt1000_get_current_resistance(&pt1000_val); adc_pt1000_get_current_resistance(&pt1000_val);
if (pt1000_val > safety_controller_overtemp_config.overtemp_equiv_resistance) { if (pt1000_val > safety_controller_overtemp_config.overtemp_equiv_resistance)
safety_controller_report_error(ERR_FLAG_OVERTEMP); safety_controller_report_error(ERR_FLAG_OVERTEMP);
}
(void)safety_controller_check_crc_monitors();
safety_controller_process_active_timing_mons(); safety_controller_process_active_timing_mons();
} }
@ -627,7 +805,7 @@ static int report_error(enum safety_flag flag, uint32_t key, bool prevent_error_
flags[i].error_state_inv = !flags[i].error_state; flags[i].error_state_inv = !flags[i].error_state;
flags[i].key = key; flags[i].key = key;
if ((check_flag_persistent(&flags[i]) && !old_state && !prevent_error_mem_enty) || if ((check_flag_persistent(&flags[i]) && !old_state && !prevent_error_mem_enty) ||
get_flag_weight(&flags[i]) == SAFETY_FLAG_CONFIG_WEIGHT_PANIC) { get_flag_weight(&flags[i]) == SAFETY_FLAG_CONFIG_WEIGHT_PANIC) {
err_mem_entry.counter = 1; err_mem_entry.counter = 1;
err_mem_entry.flag_num = flag_enum_to_flag_no(flags[i].flag); err_mem_entry.flag_num = flag_enum_to_flag_no(flags[i].flag);
@ -668,9 +846,8 @@ void safety_controller_report_timing(enum timing_monitor monitor)
tim = find_timing_mon(monitor); tim = find_timing_mon(monitor);
if (tim) { if (tim) {
if (tim->enabled) { if (tim->enabled) {
if (!systick_ticks_have_passed(tim->last, tim->min_delta) && tim->min_delta > 0U) { if (!systick_ticks_have_passed(tim->last, tim->min_delta) && tim->min_delta > 0U)
safety_controller_report_error(tim->associated_flag); safety_controller_report_error(tim->associated_flag);
}
} }
tim->calculated_delta = timestamp - tim->last; tim->calculated_delta = timestamp - tim->last;
@ -718,9 +895,8 @@ static int get_safety_flags_from_error_mem(enum safety_flag *flags)
for (idx = 0; idx < count; idx++) { for (idx = 0; idx < count; idx++) {
res = safety_memory_get_error_entry(idx, &entry); res = safety_memory_get_error_entry(idx, &entry);
if (entry.type == SAFETY_MEMORY_ERR_ENTRY_FLAG) { if (entry.type == SAFETY_MEMORY_ERR_ENTRY_FLAG)
return_flags |= flag_no_to_flag_enum(entry.flag_num); return_flags |= flag_no_to_flag_enum(entry.flag_num);
}
} }
*flags = return_flags; *flags = return_flags;
@ -732,11 +908,12 @@ static int get_safety_flags_from_error_mem(enum safety_flag *flags)
* *
* The external harware watchdog has to be periodically reset or it will reset hte controller. * The external harware watchdog has to be periodically reset or it will reset hte controller.
* Because debugging is not possible, when the watchdog is active, it is only activated, if the application is * Because debugging is not possible, when the watchdog is active, it is only activated, if the application is
* compiled in release mode. Any interruption of the main programm will then trigger the internal and/or the external watchdog. * compiled in release mode. Any interruption of the main programm will then trigger the internal and/or
* the external watchdog.
* *
* @note When enabled, execute the @ref external_watchdog_toggle function to reset the external watchdog. * @note When enabled, execute the @ref external_watchdog_toggle function to reset the external watchdog.
*/ */
static void safety_controller_init_external_watchdog() static void safety_controller_init_external_watchdog(void)
{ {
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(SAFETY_EXT_WATCHDOG_RCC_MASK)); rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(SAFETY_EXT_WATCHDOG_RCC_MASK));
SAFETY_EXT_WATCHDOG_PORT->MODER &= MODER_DELETE(SAFETY_EXT_WATCHDOG_PIN); SAFETY_EXT_WATCHDOG_PORT->MODER &= MODER_DELETE(SAFETY_EXT_WATCHDOG_PIN);
@ -747,7 +924,7 @@ static void safety_controller_init_external_watchdog()
__DSB(); __DSB();
} }
void safety_controller_init() void safety_controller_init(void)
{ {
enum safety_memory_state found_memory_state; enum safety_memory_state found_memory_state;
enum safety_flag flags_in_err_mem = ERR_FLAG_NO_FLAG; enum safety_flag flags_in_err_mem = ERR_FLAG_NO_FLAG;
@ -764,6 +941,7 @@ void safety_controller_init()
/* This is usually done by the safety memory already. But, since this module also uses the CRC... */ /* This is usually done by the safety memory already. But, since this module also uses the CRC... */
crc_unit_init(); crc_unit_init();
flash_crc_trigger_check();
stack_check_init_corruption_detect_area(); stack_check_init_corruption_detect_area();
hw_rev = get_pcb_hardware_version(); hw_rev = get_pcb_hardware_version();
@ -795,7 +973,7 @@ void safety_controller_init()
MEAS_ADC_SAFETY_FLAG_KEY); MEAS_ADC_SAFETY_FLAG_KEY);
safety_adc_init(); safety_adc_init();
watchdog_setup(WATCHDOG_PRESCALER); (void)watchdog_setup(WATCHDOG_PRESCALER, WATCHDOG_RELOAD_VALUE);
if (rcc_manager_get_reset_cause(false) & RCC_RESET_SOURCE_IWDG) if (rcc_manager_get_reset_cause(false) & RCC_RESET_SOURCE_IWDG)
safety_controller_report_error(ERR_FLAG_WTCHDG_FIRED); safety_controller_report_error(ERR_FLAG_WTCHDG_FIRED);
@ -814,7 +992,7 @@ void safety_controller_init()
* 1) Checking the remaining free space at the moment between stack pointer and top of heap. * 1) Checking the remaining free space at the moment between stack pointer and top of heap.
* 2) Checking The CRC of the corruption detect area between heap and stack * 2) Checking The CRC of the corruption detect area between heap and stack
*/ */
static void safety_controller_check_stack() static void safety_controller_check_stack(void)
{ {
int32_t free_stack; int32_t free_stack;
@ -822,18 +1000,17 @@ static void safety_controller_check_stack()
if (free_stack < SAFETY_MIN_STACK_FREE) if (free_stack < SAFETY_MIN_STACK_FREE)
safety_controller_report_error(ERR_FLAG_STACK); safety_controller_report_error(ERR_FLAG_STACK);
if (stack_check_corruption_detect_area()) { if (stack_check_corruption_detect_area())
safety_controller_report_error(ERR_FLAG_STACK); safety_controller_report_error(ERR_FLAG_STACK);
}
} }
/** /**
* @brief Handle the Safety ADC * @brief Handle the Safety ADC
* *
* This function handles the safety ADC. * This function handles the safety ADC.
* If the safety ADC ius not executing a measurment and the time since the last measurement has * If the safety ADC is not executing a measurment and the time since the last measurement has
* passed @ref SAFETY_CONTROLLER_ADC_DELAY_MS, the safety ADC is retriggered and will automatically perform a measurement * passed @ref SAFETY_CONTROLLER_ADC_DELAY_MS, the safety ADC is retriggered and will automatically perform a
* on all of its channels. * measurement on all of its channels.
* When called again, this function will retrieve the data from the safety ADC and converts it into the * When called again, this function will retrieve the data from the safety ADC and converts it into the
* appropriate analog values for the analog value monitors. * appropriate analog values for the analog value monitors.
* *
@ -842,7 +1019,7 @@ static void safety_controller_check_stack()
* *
* The channels, the ssafety ADC will convert is defined in its header file using the define @ref SAFETY_ADC_CHANNELS. * The channels, the ssafety ADC will convert is defined in its header file using the define @ref SAFETY_ADC_CHANNELS.
*/ */
static void safety_controller_handle_safety_adc() static void safety_controller_handle_safety_adc(void)
{ {
static uint64_t last_result_timestamp = 0; static uint64_t last_result_timestamp = 0;
const uint16_t *channels; const uint16_t *channels;
@ -913,9 +1090,8 @@ static void safety_controller_handle_memory_checks(void)
/* Check the safety memory */ /* Check the safety memory */
if (safety_memory_check()) { if (safety_memory_check()) {
(void)safety_memory_reinit(&found_state); (void)safety_memory_reinit(&found_state);
if (found_state != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (found_state != SAFETY_MEMORY_INIT_VALID_MEMORY)
safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT); safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT);
}
} }
/* If flag weight table is broken, reinit to default and set flag */ /* If flag weight table is broken, reinit to default and set flag */
@ -925,7 +1101,7 @@ static void safety_controller_handle_memory_checks(void)
} }
/* If persistence table is broken, reinit to default and set flag */ /* If persistence table is broken, reinit to default and set flag */
if(flag_persistence_table_crc_check()) { if (flag_persistence_table_crc_check()) {
safety_controller_report_error(ERR_FLAG_SAFETY_TAB_CORRUPT); safety_controller_report_error(ERR_FLAG_SAFETY_TAB_CORRUPT);
init_safety_flag_persistencies_from_default(); init_safety_flag_persistencies_from_default();
} }
@ -944,7 +1120,7 @@ static void safety_controller_handle_memory_checks(void)
* If the systick stays constant for more than 1000 calls of this function, * If the systick stays constant for more than 1000 calls of this function,
* the @ref ERR_FLAG_SYSTICK flag is set. * the @ref ERR_FLAG_SYSTICK flag is set.
*/ */
static void safety_controller_do_systick_checking() static void safety_controller_do_systick_checking(void)
{ {
static uint64_t last_systick; static uint64_t last_systick;
static uint32_t same_systick_cnt = 0UL; static uint32_t same_systick_cnt = 0UL;
@ -968,22 +1144,29 @@ static void safety_controller_do_systick_checking()
* is set, the appropriate action defined by the flag weight is executed. * is set, the appropriate action defined by the flag weight is executed.
* @note If no flag weigth is present for a given error flag, it is treated as the most critical category * @note If no flag weigth is present for a given error flag, it is treated as the most critical category
* (@ref SAFETY_FLAG_CONFIG_WEIGHT_PANIC) * (@ref SAFETY_FLAG_CONFIG_WEIGHT_PANIC)
*
* @returns Worst config weight set
*/ */
static void safety_controller_handle_weighted_flags() static enum config_weight safety_controller_handle_weighted_flags(void)
{ {
uint32_t flag_index; uint32_t flag_index;
volatile struct error_flag *current_flag; volatile struct error_flag *current_flag;
enum config_weight flag_weigth; enum config_weight flag_weigth;
enum config_weight worst = SAFETY_FLAG_CONFIG_WEIGHT_NONE;
for (flag_index = 0u; flag_index < COUNT_OF(flags); flag_index++) { for (flag_index = 0u; flag_index < COUNT_OF(flags); flag_index++) {
current_flag = &flags[flag_index]; current_flag = &flags[flag_index];
/* Continue if this flag is not set */ /* Continue if this flag is not set */
if (!error_flag_get_status(current_flag)) { if (!error_flag_get_status(current_flag))
continue; continue;
}
flag_weigth = get_flag_weight(current_flag); flag_weigth = get_flag_weight(current_flag);
/* Override the worst flag weigt set, if it is worse than the previous ones */
if (flag_weigth > worst)
worst = flag_weigth;
switch (flag_weigth) { switch (flag_weigth) {
case SAFETY_FLAG_CONFIG_WEIGHT_NONE: case SAFETY_FLAG_CONFIG_WEIGHT_NONE:
break; break;
@ -999,18 +1182,20 @@ static void safety_controller_handle_weighted_flags()
} }
} }
return worst;
} }
#ifndef DEBUGBUILD #ifndef DEBUGBUILD
static void external_watchdog_toggle() static void external_watchdog_toggle(void)
{ {
SAFETY_EXT_WATCHDOG_PORT->ODR ^= (1<<SAFETY_EXT_WATCHDOG_PIN); SAFETY_EXT_WATCHDOG_PORT->ODR ^= (1<<SAFETY_EXT_WATCHDOG_PIN);
} }
#endif #endif
int safety_controller_handle() enum config_weight safety_controller_handle(void)
{ {
int ret = 0; enum config_weight worst_weight_set;
#ifndef DEBUGBUILD #ifndef DEBUGBUILD
static uint32_t watchdog_counter = 0UL; static uint32_t watchdog_counter = 0UL;
#endif #endif
@ -1020,9 +1205,10 @@ int safety_controller_handle()
safety_controller_handle_memory_checks(); safety_controller_handle_memory_checks();
safety_controller_do_systick_checking(); safety_controller_do_systick_checking();
safety_controller_process_monitor_checks(); safety_controller_process_monitor_checks();
safety_controller_handle_weighted_flags(); worst_weight_set = safety_controller_handle_weighted_flags();
ret |= watchdog_ack(WATCHDOG_MAGIC_KEY); /* Ignore error here. Will trigger restart anyway */
(void)watchdog_ack(WATCHDOG_MAGIC_KEY);
#ifndef DEBUGBUILD #ifndef DEBUGBUILD
if (get_pcb_hardware_version() != HW_REV_V1_2) { if (get_pcb_hardware_version() != HW_REV_V1_2) {
@ -1033,7 +1219,8 @@ int safety_controller_handle()
} }
} }
#endif #endif
return (ret ? -1 : 0);
return worst_weight_set;
} }
int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable) int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable)
@ -1120,9 +1307,8 @@ int safety_controller_ack_flag_with_key(enum safety_flag flag, uint32_t key)
int ret = -1; int ret = -1;
volatile struct error_flag *found_flag; volatile struct error_flag *found_flag;
if (!is_power_of_two(flag)) { if (!is_power_of_two(flag))
return -1001; return -1001;
}
found_flag = find_error_flag(flag); found_flag = find_error_flag(flag);
if (found_flag) { if (found_flag) {
@ -1153,17 +1339,17 @@ bool safety_controller_get_flags_by_mask(enum safety_flag mask)
return ret; return ret;
} }
uint32_t safety_controller_get_flag_count() uint32_t safety_controller_get_flag_count(void)
{ {
return COUNT_OF(flags); return COUNT_OF(flags);
} }
uint32_t safety_controller_get_analog_monitor_count() uint32_t safety_controller_get_analog_monitor_count(void)
{ {
return COUNT_OF(analog_mons); return COUNT_OF(analog_mons);
} }
uint32_t safety_controller_get_timing_monitor_count() uint32_t safety_controller_get_timing_monitor_count(void)
{ {
return COUNT_OF(timings); return COUNT_OF(timings);
} }
@ -1270,9 +1456,8 @@ int safety_controller_get_timing_mon_by_index(uint32_t index, struct timing_moni
if (!info) if (!info)
return -1002; return -1002;
if (index >= COUNT_OF(timings)) { if (index >= COUNT_OF(timings))
return -1001; return -1001;
}
mon = &timings[index]; mon = &timings[index];
@ -1296,4 +1481,32 @@ float safety_controller_get_overtemp_limit(void)
return safety_controller_overtemp_config.overtemp_deg_celsius; return safety_controller_overtemp_config.overtemp_deg_celsius;
} }
int safety_controller_set_crc_monitor(enum crc_monitor mon, uint32_t password)
{
uint32_t i;
struct crc_mon *monitor;
uint32_t crc;
for (i = 0; i < COUNT_OF(crc_monitors); i++) {
monitor = &crc_monitors[i];
if (monitor->monitor != mon)
continue;
monitor->active = true;
if (password != monitor->pw)
return -1002;
crc = 0;
(void)crc_monitor_calculate_crc(monitor->registers, &crc);
monitor->expected_crc = crc;
monitor->expected_crc_inv = ~crc;
monitor->last_crc = crc;
return 0;
}
return -1001;
}
/** @} */ /** @} */

View File

@ -1,28 +1,32 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * 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 * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <reflow-controller/safety/safety-memory.h> #include <reflow-controller/safety/safety-memory.h>
#include <helper-macros/helper-macros.h> #include <helper-macros/helper-macros.h>
#include <stm-periph/crc-unit.h> #include <stm-periph/crc-unit.h>
#include <stm-periph/backup-ram.h> #include <stm-periph/backup-ram.h>
#include <string.h>
#ifndef SAFETY_MEMORY_STRIPOUT_DUMP
#include <base64-lib/base64-lib.h> #include <base64-lib/base64-lib.h>
#endif /* SAFETY_MEMORY_STRIPOUT_DUMP */
static int word_to_error_memory_entry(uint32_t entry_data, struct error_memory_entry *out) static int word_to_error_memory_entry(uint32_t entry_data, struct error_memory_entry *out)
{ {
@ -31,11 +35,11 @@ static int word_to_error_memory_entry(uint32_t entry_data, struct error_memory_e
if (!out) if (!out)
return -1002; return -1002;
if (entry_data == SAFETY_MEMORY_ERR_ENTRY_NOP) { if (entry_data == SAFETY_MEMORY_NOP_ENTRY_WORD) {
out->flag_num = 0U; out->flag_num = 0U;
out->type = SAFETY_MEMORY_ERR_ENTRY_NOP; out->type = SAFETY_MEMORY_ERR_ENTRY_NOP;
out->counter = 0U; out->counter = 0U;
} else if ((entry_data & 0xFFU) == 0x51U) { } else if ((entry_data & 0xFFU) == SAFETY_MEMORY_ERROR_ENTRY_MARKER) {
out->flag_num = (uint8_t)((entry_data >> 8U) & 0xFFU); out->flag_num = (uint8_t)((entry_data >> 8U) & 0xFFU);
out->type = SAFETY_MEMORY_ERR_ENTRY_FLAG; out->type = SAFETY_MEMORY_ERR_ENTRY_FLAG;
out->counter = (uint16_t)((entry_data >> 16U) & 0xFFFF); out->counter = (uint16_t)((entry_data >> 16U) & 0xFFFF);
@ -53,10 +57,10 @@ static uint32_t error_memory_entry_to_word(const struct error_memory_entry *entr
switch (entry->type) { switch (entry->type) {
case SAFETY_MEMORY_ERR_ENTRY_NOP: case SAFETY_MEMORY_ERR_ENTRY_NOP:
word = SAFETY_MEMORY_NOP_ENTRY; word = SAFETY_MEMORY_NOP_ENTRY_WORD;
break; break;
case SAFETY_MEMORY_ERR_ENTRY_FLAG: case SAFETY_MEMORY_ERR_ENTRY_FLAG:
word = 0x51UL | ((uint32_t)entry->flag_num << 8U) | word = (uint32_t)SAFETY_MEMORY_ERROR_ENTRY_MARKER | ((uint32_t)entry->flag_num << 8U) |
((uint32_t)entry->counter << 16U); ((uint32_t)entry->counter << 16U);
break; break;
} }
@ -95,13 +99,17 @@ static enum safety_memory_state safety_memory_get_header(struct safety_memory_he
res = 0; res = 0;
if (header->boot_status_offset < wordsize_of(struct safety_memory_header)) if (header->boot_status_offset < wordsize_of(struct safety_memory_header))
res++; res++;
if (header->config_overrides_offset < header->boot_status_offset + wordsize_of(struct safety_memory_boot_status)) if (header->config_overrides_offset < header->boot_status_offset +
wordsize_of(struct safety_memory_boot_status))
res++; res++;
if (header->config_overrides_len > SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT) if (header->config_overrides_len > SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT)
res++; res++;
if (header->err_memory_offset < header->config_overrides_offset + header->config_overrides_len) if (header->firmware_update_filename < header->config_overrides_offset + header->config_overrides_len)
res++; res++;
if (header->err_memory_end >= backup_ram_get_size_in_words() || header->err_memory_end < header->err_memory_offset) if (header->err_memory_offset < header->firmware_update_filename + (SAFETY_MEMORY_UPDATE_FILENAME_MAXSIZE / 4))
res++;
if (header->err_memory_end >= backup_ram_get_size_in_words() ||
header->err_memory_end < header->err_memory_offset)
res++; res++;
if (res) { if (res) {
@ -133,7 +141,8 @@ static void safety_memory_write_new_header(void)
header.boot_status_offset = wordsize_of(struct safety_memory_header); header.boot_status_offset = wordsize_of(struct safety_memory_header);
header.config_overrides_len = SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT; header.config_overrides_len = SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT;
header.config_overrides_offset = header.boot_status_offset + wordsize_of(struct safety_memory_boot_status); header.config_overrides_offset = header.boot_status_offset + wordsize_of(struct safety_memory_boot_status);
header.err_memory_offset = header.config_overrides_offset + SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT; header.firmware_update_filename = header.config_overrides_offset + SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT;
header.err_memory_offset = header.firmware_update_filename + (SAFETY_MEMORY_UPDATE_FILENAME_MAXSIZE / 4);
header.err_memory_end = header.err_memory_offset; header.err_memory_end = header.err_memory_offset;
header.magic = SAFETY_MEMORY_MAGIC; header.magic = SAFETY_MEMORY_MAGIC;
@ -141,7 +150,7 @@ static void safety_memory_write_new_header(void)
safety_memory_write_and_patch_header(&header); safety_memory_write_and_patch_header(&header);
} }
static int safety_memory_check_crc() static int safety_memory_check_crc(void)
{ {
struct safety_memory_header header; struct safety_memory_header header;
enum safety_memory_state state = safety_memory_get_header(&header); enum safety_memory_state state = safety_memory_get_header(&header);
@ -174,7 +183,7 @@ static int safety_memory_check_crc()
return 0; return 0;
} }
static int safety_memory_gen_crc() static int safety_memory_gen_crc(void)
{ {
struct safety_memory_header header; struct safety_memory_header header;
uint32_t word_addr; uint32_t word_addr;
@ -261,9 +270,8 @@ int safety_memory_get_boot_status(struct safety_memory_boot_status *status)
if (!status) if (!status)
return -1001; return -1001;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
if (safety_memory_check_crc()) if (safety_memory_check_crc())
return -2001; return -2001;
@ -282,9 +290,8 @@ int safety_memory_set_boot_status(const struct safety_memory_boot_status *status
if (!status) if (!status)
return -1001; return -1001;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
if (safety_memory_check_crc()) if (safety_memory_check_crc())
return -2001; return -2001;
@ -297,7 +304,7 @@ int safety_memory_set_boot_status(const struct safety_memory_boot_status *status
return 0; return 0;
} }
static int safety_memory_check_error_entries() static int safety_memory_check_error_entries(void)
{ {
struct safety_memory_header header; struct safety_memory_header header;
uint32_t addr; uint32_t addr;
@ -305,9 +312,8 @@ static int safety_memory_check_error_entries()
int ret = 0; int ret = 0;
int res; int res;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
for (addr = header.err_memory_offset; addr < header.err_memory_end; addr++) { for (addr = header.err_memory_offset; addr < header.err_memory_end; addr++) {
res = backup_ram_get_data(addr, &data, 1UL); res = backup_ram_get_data(addr, &data, 1UL);
@ -315,9 +321,9 @@ static int safety_memory_check_error_entries()
return -100; return -100;
/* Valid flag entry */ /* Valid flag entry */
if ((data & 0xFF) == 0x51) if ((data & 0xFF) == SAFETY_MEMORY_ERROR_ENTRY_MARKER)
continue; continue;
if (data == SAFETY_MEMORY_NOP_ENTRY) if (data == SAFETY_MEMORY_NOP_ENTRY_WORD)
continue; continue;
ret--; ret--;
@ -333,9 +339,8 @@ int safety_memory_get_error_entry_count(uint32_t *count)
if (!count) if (!count)
return -1001; return -1001;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
*count = header.err_memory_end - header.err_memory_offset; *count = header.err_memory_end - header.err_memory_offset;
@ -347,9 +352,8 @@ int safety_memory_check(void)
int res; int res;
res = safety_memory_check_crc(); res = safety_memory_check_crc();
if (!res) { if (!res)
res |= safety_memory_check_error_entries(); res |= safety_memory_check_error_entries();
}
return -!!res; return -!!res;
} }
@ -365,9 +369,8 @@ int safety_memory_get_error_entry(uint32_t idx, struct error_memory_entry *entry
if (!entry) if (!entry)
return -1001; return -1001;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
err_mem_count = header.err_memory_end - header.err_memory_offset; err_mem_count = header.err_memory_end - header.err_memory_offset;
if (idx < err_mem_count && err_mem_count > 0) { if (idx < err_mem_count && err_mem_count > 0) {
@ -403,9 +406,8 @@ int safety_memory_insert_error_entry(struct error_memory_entry *entry)
input_data = error_memory_entry_to_word(entry); input_data = error_memory_entry_to_word(entry);
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
if (entry->type == SAFETY_MEMORY_ERR_ENTRY_NOP) { if (entry->type == SAFETY_MEMORY_ERR_ENTRY_NOP) {
/* Append to end */ /* Append to end */
@ -503,9 +505,8 @@ int safety_memory_insert_config_override(struct config_override *config_override
int res; int res;
int ret = -3; int ret = -3;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
if (header.config_overrides_len == 0) if (header.config_overrides_len == 0)
return -1; return -1;
@ -543,9 +544,8 @@ int safety_memory_get_config_override_count(uint32_t *count)
*count = 0UL; *count = 0UL;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
if (header.config_overrides_len == 0) if (header.config_overrides_len == 0)
return 0; return 0;
@ -575,18 +575,15 @@ int safety_memory_get_config_override(uint32_t idx, struct config_override *conf
if (!config_override) if (!config_override)
return -1002; return -1002;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
if (idx >= header.config_overrides_len) { if (idx >= header.config_overrides_len)
return -1001; return -1001;
}
res = backup_ram_get_data(header.config_overrides_offset + idx, &data, 1UL); res = backup_ram_get_data(header.config_overrides_offset + idx, &data, 1UL);
if (res) { if (res)
return -1; return -1;
}
switch (data & 0xFF) { switch (data & 0xFF) {
case 0xA2: case 0xA2:
@ -608,6 +605,8 @@ int safety_memory_get_config_override(uint32_t idx, struct config_override *conf
return 0; return 0;
} }
#ifndef SAFETY_MEMORY_STRIPOUT_DUMP
int safety_memory_dump_base64(char *buffer, size_t buffsize, size_t *used_size) int safety_memory_dump_base64(char *buffer, size_t buffsize, size_t *used_size)
{ {
uint32_t safety_mem_size; uint32_t safety_mem_size;
@ -633,3 +632,66 @@ int safety_memory_dump_base64(char *buffer, size_t buffsize, size_t *used_size)
*used_size = output_size + 1u; *used_size = output_size + 1u;
return 0; return 0;
} }
#endif /* SAFETY_MEMORY_STRIPOUT_DUMP */
int safety_memory_get_update_filename(char *filename, size_t *outlen)
{
struct safety_memory_header header;
unsigned int i;
size_t len = 0u;
volatile char *ptr;
/* If filename and outlen are both NULL, we don't do anything */
if (!filename && !outlen)
return -1;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000;
/* Get the filename */
ptr = (volatile char *)backup_ram_get_base_ptr();
ptr += (unsigned int)(header.firmware_update_filename * 4);
for (i = 0; i < SAFETY_MEMORY_UPDATE_FILENAME_MAXSIZE; i++) {
if (filename)
filename[i] = *ptr;
if (*ptr)
len++;
else
break;
ptr++;
}
if (outlen)
*outlen = len;
return 0;
}
int safety_memory_set_update_filename(const char *filename)
{
int ret = 0;
size_t len;
unsigned int i;
struct safety_memory_header header;
volatile char *ram_ptr;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000;
if (!filename)
return -1001;
len = strnlen(filename, SAFETY_MEMORY_UPDATE_FILENAME_MAXSIZE - 1);
ram_ptr = backup_ram_get_base_ptr();
ram_ptr += header.firmware_update_filename * 4;
for (i = 0u; i < len; i++)
ram_ptr[i] = filename[i];
ram_ptr[i] = 0;
ret = safety_memory_gen_crc();
return ret;
}

View File

@ -1,22 +1,22 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * 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 * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <reflow-controller/safety/stack-check.h> #include <reflow-controller/safety/stack-check.h>
#include <stdint.h> #include <stdint.h>
@ -26,7 +26,7 @@
extern char __ld_top_of_stack; extern char __ld_top_of_stack;
extern char __ld_end_stack; extern char __ld_end_stack;
int32_t stack_check_get_usage() int32_t stack_check_get_usage(void)
{ {
uint32_t stack_top; uint32_t stack_top;
uint32_t stack_ptr; uint32_t stack_ptr;
@ -37,7 +37,7 @@ int32_t stack_check_get_usage()
return stack_top - stack_ptr; return stack_top - stack_ptr;
} }
int32_t stack_check_get_free() int32_t stack_check_get_free(void)
{ {
uint32_t upper_heap_boundary; uint32_t upper_heap_boundary;
uint32_t stack_ptr; uint32_t stack_ptr;
@ -102,9 +102,6 @@ int stack_check_corruption_detect_area(void)
&__ld_start_stack_corruption_detect_area; &__ld_start_stack_corruption_detect_area;
crc_unit_reset(); crc_unit_reset();
crc_unit_input_array(&__ld_start_stack_corruption_detect_area, area_size_in_words); crc_unit_input_array(&__ld_start_stack_corruption_detect_area, area_size_in_words);
if (crc_unit_get_crc() == 0UL) {
return 0; return crc_unit_get_crc() == 0UL ? 0 : -1;
} else {
return -1;
}
} }

View File

@ -1,22 +1,22 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * 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 * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @addtogroup watchdog * @addtogroup watchdog
@ -42,45 +42,63 @@
*/ */
#define STM32_WATCHDOG_REGISTER_ACCESS_KEY 0x5555 #define STM32_WATCHDOG_REGISTER_ACCESS_KEY 0x5555
int watchdog_setup(uint8_t prescaler) int watchdog_setup(uint16_t prescaler, uint16_t reload_value)
{ {
uint32_t prescaler_reg_val; uint32_t prescaler_reg_val;
int ret = 0;
/** - Activate the LSI oscillator */ /** - Activate the LSI oscillator */
RCC->CSR |= RCC_CSR_LSION; RCC->CSR |= RCC_CSR_LSION;
__DSB(); __DSB();
/** - Wait for the oscillator to be ready */ /** - Wait for the oscillator to be ready */
while (!(RCC->CSR & RCC_CSR_LSIRDY)); while (!(RCC->CSR & RCC_CSR_LSIRDY))
;
if (prescaler == 4U) if (prescaler == 4U) {
prescaler_reg_val = 0UL; prescaler_reg_val = 0UL;
else if (prescaler == 8U) } else if (prescaler == 8U) {
prescaler_reg_val = 1UL; prescaler_reg_val = 1UL;
else if (prescaler == 16U) } else if (prescaler == 16U) {
prescaler_reg_val = 2UL; prescaler_reg_val = 2UL;
else if (prescaler == 32U) } else if (prescaler == 32U) {
prescaler_reg_val = 3UL; prescaler_reg_val = 3UL;
else if (prescaler == 64U) } else if (prescaler == 64U) {
prescaler_reg_val = 4UL; prescaler_reg_val = 4UL;
else if (prescaler == 128U) } else if (prescaler == 128U) {
prescaler_reg_val = 5UL; prescaler_reg_val = 5UL;
else } else if (prescaler == 256U) {
prescaler_reg_val = 6UL; prescaler_reg_val = 6UL;
} else {
prescaler_reg_val = 6UL;
ret = -1;
}
/** - (De)activate the watchdog during debug access according to @ref WATCHDOG_HALT_DEBUG */
if (WATCHDOG_HALT_DEBUG)
DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_IWDG_STOP;
else
DBGMCU->APB1FZ &= ~DBGMCU_APB1_FZ_DBG_IWDG_STOP;
/** - Unlock registers */ /** - Unlock registers */
IWDG->KR = STM32_WATCHDOG_REGISTER_ACCESS_KEY; IWDG->KR = STM32_WATCHDOG_REGISTER_ACCESS_KEY;
/** - Wait until prescaler can be written */ /** - Wait until prescaler can be written */
while (IWDG->SR & IWDG_SR_PVU); while (IWDG->SR & IWDG_SR_PVU)
;
/** - Write prescaler value */ /** - Write prescaler value */
IWDG->PR = prescaler_reg_val; IWDG->PR = prescaler_reg_val;
/* - Wait until reload value can be written */ /* - Wait until reload value can be written */
while (IWDG->SR & IWDG_SR_RVU); while (IWDG->SR & IWDG_SR_RVU)
;
/** - Set reload value fixed to 0xFFF */ /** - Set reload value */
IWDG->RLR = 0xFFFU; if (reload_value > 0xFFFu) {
reload_value = 0xFFFFu;
ret = -2;
}
IWDG->RLR = reload_value;
/** - Write enable key */ /** - Write enable key */
IWDG->KR = STM32_WATCHDOG_ENABLE_KEY; IWDG->KR = STM32_WATCHDOG_ENABLE_KEY;
@ -88,7 +106,7 @@ int watchdog_setup(uint8_t prescaler)
/** - Do a first reset of the counter. This also locks the config regs */ /** - Do a first reset of the counter. This also locks the config regs */
watchdog_ack(WATCHDOG_MAGIC_KEY); watchdog_ack(WATCHDOG_MAGIC_KEY);
return 0; return ret;
} }
int watchdog_ack(uint32_t magic) int watchdog_ack(uint32_t magic)

65
stm-firmware/sd.c Normal file
View File

@ -0,0 +1,65 @@
/* Reflow Oven Controller
*
* Copyright (C) 2022 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.
*
* GDSII-Converter 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/sd.h>
#include "fatfs/ff.h"
#include "fatfs/shimatta_sdio_driver/shimatta_sdio.h"
#include <stdint.h>
#include <string.h>
#include <helper-macros/helper-macros.h>
#include <reflow-controller/digio.h>
static bool sd_card_mounted_state = false;
bool mount_sd_card_if_avail(FATFS *fs)
{
FRESULT res;
static uint8_t IN_SECTION(.ccm.bss) inserted_counter = 0;
if (sdio_check_inserted() && sd_card_mounted_state) {
memset(fs, 0, sizeof(FATFS));
sdio_stop_clk();
inserted_counter = 0;
sd_card_mounted_state = false;
goto ret;
}
if (!sdio_check_inserted() && inserted_counter < 255)
inserted_counter++;
if (!sdio_check_inserted() && !sd_card_mounted_state && inserted_counter > 4) {
inserted_counter = 0;
res = f_mount(fs, "0:/", 1);
if (res == FR_OK) {
led_set(1, 1);
sd_card_mounted_state = true;
} else {
sd_card_mounted_state = false;
}
}
ret:
return sd_card_mounted_state;
}
bool sd_card_is_mounted(void)
{
return sd_card_mounted_state;
}

Some files were not shown because too many files have changed in this diff Show More