├── Kconfig.projbuild ├── LICENSE ├── Makefile.projbuild ├── README.md ├── arduino └── ffat │ └── ffat.ino ├── component.mk ├── fatfsimage ├── fatfsimage.cpp └── private ├── driver └── sdmmc_host.h ├── esp_err.h ├── freertos ├── FreeRTOS.h └── semphr.h ├── sdmmc_cmd.h └── sdmmc_types.h /Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "FATFSIMAGE Configuration" 2 | 3 | config FATFSIMAGE_SRC 4 | string "Source directory" 5 | default "imagesrc" 6 | help 7 | Specifies the path(s) whose contents will be copied 8 | to the image file. 9 | 10 | config FATFSIMAGE_SIZE 11 | int "Disk image size in KB" 12 | default 1024 13 | help 14 | Specifies the desired disk image size in KB. Make 15 | sure your partition is the same size. 16 | 17 | config FATFSIMAGE_IMAGE 18 | string "Image name" 19 | default "fatfs.img" 20 | help 21 | Specifies the file name of the created disk image. 22 | 23 | config FATFSIMAGE_OFFSET 24 | hex "FATFS partition offset" 25 | default 0x2000000 26 | help 27 | Specifies the partition offset within the flash. This should 28 | be the same as the offset in your partition table. 29 | 30 | endmenu 31 | 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile.projbuild: -------------------------------------------------------------------------------- 1 | 2 | 3 | fat: $(BUILD_DIR_BASE)/fatfsimage/fatfsimage 4 | $< $(CONFIG_FATFSIMAGE_IMAGE) $(CONFIG_FATFSIMAGE_SIZE) $(CONFIG_FATFSIMAGE_SRC) 5 | 6 | fat-flash: $(BUILD_DIR_BASE)/fatfsimage/fatfsimage 7 | $(ESPTOOLPY_WRITE_FLASH) $(CONFIG_FATFSIMAGE_OFFSET) $(CONFIG_FATFSIMAGE_IMAGE) 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FATFS on ESP32 2 | 3 | This page is to help you setup a ffat image on your computer and upload it to your ESP32 4 | Blog post: http://marc.merlins.org/perso/arduino/post_2019-03-30_Using-FatFS-FFat-on-ESP32-Flash-With-Arduino.html 5 | If you're happy formatting FFAT and creating files directly from ESP32 code, you can look at those pages too: 6 | - https://www.dfrobot.com/blog-1179.html 7 | - https://techtutorialsx.com/2018/10/06/esp32-arduino-fat-file-system/ 8 | 9 | 10 | ## FatFS on ESP32 Howto: 11 | ESP32 allows you to use part of the flash to store a filesystem. Initially, it 12 | has been used for SPIFFS (a compressed read only filesystem). You can read more about it here: 13 | https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/spiffs.html 14 | 15 | Spiffs has issues though, on top of being read only of course, it's pretty bad at doing 16 | seeks across large files (it's slow), and another filesystem like Fat, works better. 17 | This is where FFat(Flash Fat) comes in. 18 | As of 2020 there is now also LittleFS. I have not used it, but I assume it's a better version 19 | of SPIFFS that doesn't take as much RAM as FatFS 20 | 21 | You can see how to use FatFS from this example: 22 | https://github.com/espressif/arduino-esp32/blob/master/libraries/FFat/examples/FFat_Test/FFat_Test.ino 23 | but it assumes that you are creating your files on the device you can begin(true) to format 24 | the filesystem. 25 | 26 | If you want to create the filesystem on your computer and send it to your ESP32 (in 27 | my case I have a big collection of Animated Gifs I want to serve), you follow these steps: 28 | 29 | 30 | ## This code is mostly obsolete Use arduino-esp32fs-plugin instead 31 | 32 | If you are on linux, you may still be happy with the instructions below, but after I wrote all this, 33 | a better solution came up: https://github.com/lorol/arduino-esp32fs-plugin 34 | I recommend you install this instead and then grab a mkfatfs binary (it's a bit of a pain to build) from: 35 | - https://github.com/labplus-cn/mkfatfs/releases/tag/v2.0.1 36 | - https://github.com/labplus-cn/mkfatfs/releases/tag/v1.0 37 | and grab esp32fs.jar from https://github.com/lorol/arduino-esp32fs-plugin/releases 38 | 39 | But if you'd like to create your FatFS image from a makefile and upload it via esptool, then my 40 | branch does this, read on. 41 | 42 | 43 | ### Create a FFAT partition on ESP32 44 | reformat your ESP32 to have a FatFS partition. You'll probably need this in your tree: 45 | https://github.com/espressif/arduino-esp32/pull/2623/files 46 | or you can simply git clone https://github.com/marcmerlin/arduino-esp32 which has the change you need 47 | 48 | You will need to pay attention to the last line for both the offset (which you copy as is 49 | in esptool) and the size, which you need to convert to decimal and divide by 1024 for KB: https://github.com/espressif/arduino-esp32/blob/170d204566bbee414f4059db99168974c69d166e/tools/partitions/noota_3gffat.csv 50 | ``` 51 | ffat, data, fat, 0x111000,0x2EF000, 52 | ``` 53 | actually the eeprom partition was removed in newer versions of esp32-arduino, so now it should be: 54 | ``` 55 | ffat, data, fat, 0x110000,0x2F0000 56 | ``` 57 | 58 | ### Create a FatFS image 59 | To create the fatfs image on linux (or you have to make the code here work and build for your OS). 60 | Thanks to lbernstone for building a binary: 61 | ``` 62 | # replace 3004 with the size of your partition. In the 1/3MB split, the fatfs partition is 63 | # 0x2EF000 = 3076096 . 3076096/1024 = 3004 64 | fatfsimage -l5 img.ffat 3004 datadir/ 65 | # with newer esp32-arduino, it's now 0x2F0000 = 3080192. 3080192/1024 = 3008 66 | fatfsimage -l5 img.ffat 3008 datadir/ 67 | ``` 68 | 69 | ### Upload the FatFS image to your ESP32 70 | To upload the image at the right offset (0x111000 for the 1/3MB split) 71 | ``` 72 | esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 write_flash 0x111000 img.ffat 73 | or with newer esp32-arduino: 74 | esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 write_flash 0x110000 img.ffat 75 | ``` 76 | 77 | ### FFat test code. 78 | upload and run the arduino/ffat code to verify the partition list and get a file listing. 79 | https://github.com/marcmerlin/esp32_fatfsimage/blob/master/arduino/ffat/ffat.ino 80 | ``` 81 | partition addr: 0x010000; size: 0x100000; label: app0 82 | partition addr: 0x009000; size: 0x005000; label: nvs 83 | partition addr: 0x00e000; size: 0x002000; label: otadata 84 | partition addr: 0x110000; size: 0x001000; label: eeprom 85 | partition addr: 0x111000; size: 0x2ef000; label: ffat 86 | 87 | Trying to mount ffat partition if present 88 | File system mounted 89 | Total space: 3018752 90 | Free space: 1429504 91 | Listing directory: /gifs64 92 | FILE: /gifs64/ani-bman-BW.gif SIZE: 4061 93 | FILE: /gifs64/087_net.gif SIZE: 46200 94 | (...) 95 | ``` 96 | 97 | ### Memory use 98 | The FFAT module uses 8KB plus 4KB per concurrent file that can be opened. By default, it allows 10 files to be opened, which means it uses 48KB. IF you want to reduce its memory use, you can tell it to only support one file, and you will save 36KB, leaving you with only 12KB used. 99 | ``` 100 | if (!FFat.begin(0, "", 1)) die("Fat FS mount failed. Not enough RAM?"); 101 | ``` 102 | 103 | 104 | Original project README listed below in case you need to (re)build fatfsimage 105 | 106 | ## fatfsimage 107 | A utility to create and populate FATFS image files on the host that can then 108 | be flashed to the ESP32. 109 | 110 | All you need to do is add it to your components directory and 111 | run "make menuconfig" to set the required parameters (look for 112 | FATFSIMAGE Configuration). Once done, "fatfsimage" will be built 113 | the next time you build your project. 114 | 115 | When ready, you can then do "make fat" to create the image or 116 | "make fat-flash" to flash it. 117 | 118 | The required settings are: 119 | 120 | #### Source directory 121 | This is the path to the directory containing any files or other directories 122 | you want to copy to the image. 123 | 124 | #### Disk image size in KB 125 | You specify the size of the disk image in KB. Make sure this matches the 126 | size of your partition. 127 | 128 | #### Image name 129 | The filename for the image file. 130 | 131 | #### FATFS Partition offset 132 | Specify the start of the partition. Make sure it matches the actual 133 | partition. 134 | 135 | ### Usage 136 | 137 | You may also run the utility manually if you like: 138 | 139 | ``` 140 | Usage: build/fatfsimage/fatfsimage [-h] [-l ] []... 141 | Create and load a FATFS disk image. 142 | 143 | -h, --help display this help and exit 144 | -l, --log= log level (0-5, 3 is default) 145 | image file name 146 | disk size in KB 147 | directories/files to load 148 | ``` 149 | -------------------------------------------------------------------------------- /arduino/ffat/ffat.ino: -------------------------------------------------------------------------------- 1 | /* Code gathered by Marc MERLIN from code found 2 | on gitter (license unknown) and in esp32-arduino's 3 | libraries/FFat/examples/FFat_Test/FFat_Test.ino */ 4 | 5 | #include 6 | #include "FFat.h" 7 | 8 | void partloop(esp_partition_type_t part_type) { 9 | esp_partition_iterator_t iterator = NULL; 10 | const esp_partition_t *next_partition = NULL; 11 | iterator = esp_partition_find(part_type, ESP_PARTITION_SUBTYPE_ANY, NULL); 12 | while (iterator) { 13 | next_partition = esp_partition_get(iterator); 14 | if (next_partition != NULL) { 15 | Serial.printf("partition addr: 0x%06x; size: 0x%06x; label: %s\n", next_partition->address, next_partition->size, next_partition->label); 16 | iterator = esp_partition_next(iterator); 17 | } 18 | } 19 | } 20 | 21 | void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ 22 | Serial.printf("Listing directory: %s\r\n", dirname); 23 | 24 | File root = fs.open(dirname); 25 | if(!root){ 26 | Serial.println("- failed to open directory"); 27 | return; 28 | } 29 | if(!root.isDirectory()){ 30 | Serial.println(" - not a directory"); 31 | return; 32 | } 33 | 34 | File file = root.openNextFile(); 35 | while(file){ 36 | if(file.isDirectory()){ 37 | Serial.print(" DIR : "); 38 | Serial.println(file.name()); 39 | if(levels){ 40 | listDir(fs, file.name(), levels -1); 41 | } 42 | } else { 43 | Serial.print(" FILE: "); 44 | Serial.print(file.name()); 45 | Serial.print("\tSIZE: "); 46 | Serial.println(file.size()); 47 | } 48 | file.close(); 49 | file = root.openNextFile(); 50 | } 51 | } 52 | 53 | void setup(){ 54 | Serial.begin(115200); 55 | Serial.setDebugOutput(true); 56 | 57 | Serial.println("Partition list:"); 58 | partloop(ESP_PARTITION_TYPE_APP); 59 | partloop(ESP_PARTITION_TYPE_DATA); 60 | 61 | Serial.println("\n\nTrying to mount ffat partition if present"); 62 | 63 | // Only allow one file to be open at a time instead of 10, saving 9x4 - 36KB of RAM 64 | if(!FFat.begin( 0, "", 1 )){ 65 | Serial.println("FFat Mount Failed"); 66 | return; 67 | } 68 | 69 | Serial.println("File system mounted"); 70 | Serial.printf("Total space: %10lu\n", FFat.totalBytes()); 71 | Serial.printf("Free space: %10lu\n\n", FFat.freeBytes()); 72 | listDir(FFat, "/", 5); 73 | } 74 | 75 | void loop(){} 76 | -------------------------------------------------------------------------------- /component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | 6 | COMPONENT_OWNBUILDTARGET := 1 7 | COMPONENT_PRIV_INCLUDEDIRS := private 8 | 9 | CC = gcc 10 | CXX = g++ 11 | 12 | CPPFLAGS = -D_XOPEN_SOURCE=500 \ 13 | -D_GNU_SOURCE \ 14 | -DLOG_LOCAL_LEVEL=10 \ 15 | -include stdlib.h 16 | 17 | CFLAGS = -O0 -g 18 | 19 | CXXFLAGS = $(CFLAGS) 20 | 21 | INCLUDES = $(COMPONENT_PATH)/private \ 22 | $(BUILD_DIR_BASE)/include \ 23 | ${IDF_PATH}/components/esp32/include \ 24 | ${IDF_PATH}/components/fatfs/src \ 25 | ${IDF_PATH}/components/log/include \ 26 | ${IDF_PATH}/components/nvs_flash/test_nvs_host \ 27 | ${IDF_PATH}/components/soc/esp32/include \ 28 | ${IDF_PATH}/components/spi_flash/include \ 29 | ${IDF_PATH}/components/wear_levelling/private_include \ 30 | ${IDF_PATH}/components/console/argtable3 31 | 32 | OBJS = $(COMPONENT_BUILD_DIR)/fatfsimage.o \ 33 | $(COMPONENT_BUILD_DIR)/WL_Flash.o \ 34 | $(COMPONENT_BUILD_DIR)/crc32.o \ 35 | $(COMPONENT_BUILD_DIR)/crc.o \ 36 | $(COMPONENT_BUILD_DIR)/argtable3.o \ 37 | $(COMPONENT_BUILD_DIR)/ff.o \ 38 | $(COMPONENT_BUILD_DIR)/ffsystem.o \ 39 | $(COMPONENT_BUILD_DIR)/ffunicode.o 40 | 41 | build: $(COMPONENT_BUILD_DIR)/fatfsimage 42 | 43 | $(COMPONENT_BUILD_DIR)/fatfsimage.o: $(COMPONENT_PATH)/fatfsimage.cpp 44 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(addprefix -I ,$(INCLUDES)) -c $< -o $@ 45 | 46 | $(COMPONENT_BUILD_DIR)/WL_Flash.o: ${IDF_PATH}/components/wear_levelling/WL_Flash.cpp 47 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(addprefix -I ,$(INCLUDES)) -c $< -o $@ 48 | 49 | $(COMPONENT_BUILD_DIR)/crc32.o: ${IDF_PATH}/components/wear_levelling/crc32.cpp 50 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(addprefix -I ,$(INCLUDES)) -c $< -o $@ 51 | 52 | $(COMPONENT_BUILD_DIR)/crc.o: ${IDF_PATH}/components/nvs_flash/test_nvs_host/crc.cpp 53 | $(CC) $(CFLAGS) $(CPPFLAGS) $(addprefix -I ,$(INCLUDES)) -c $< -o $@ 54 | 55 | $(COMPONENT_BUILD_DIR)/argtable3.o: ${IDF_PATH}/components/console/argtable3/argtable3.c 56 | $(CC) $(CFLAGS) $(CPPFLAGS) $(addprefix -I ,$(INCLUDES)) -c $< -o $@ 57 | 58 | $(COMPONENT_BUILD_DIR)/ff.o: ${IDF_PATH}/components/fatfs/src/ff.c 59 | $(CC) $(CFLAGS) $(CPPFLAGS) $(addprefix -I ,$(INCLUDES)) -c $< -o $@ 60 | 61 | $(COMPONENT_BUILD_DIR)/ffsystem.o: ${IDF_PATH}/components/fatfs/src/ffsystem.c 62 | $(CC) $(CFLAGS) $(CPPFLAGS) $(addprefix -I ,$(INCLUDES)) -c $< -o $@ 63 | 64 | $(COMPONENT_BUILD_DIR)/ffunicode.o: ${IDF_PATH}/components/fatfs/src/ffunicode.c 65 | $(CC) $(CFLAGS) $(CPPFLAGS) $(addprefix -I ,$(INCLUDES)) -c $< -o $@ 66 | 67 | $(COMPONENT_BUILD_DIR)/fatfsimage: $(OBJS) 68 | $(CXX) $(CFLAGS) $(CPPFLAGS) $(addprefix -I ,$(INCLUDES)) $(OBJS) -o $@ -lc 69 | # Create dummy archive to satisfy main app build 70 | echo "!" >$(COMPONENT_BUILD_DIR)/libfatfsimage.a 71 | 72 | .PHONY: build 73 | -------------------------------------------------------------------------------- /fatfsimage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcmerlin/esp32_fatfsimage/cfa48b886adbafc06c56db976545f78afe3426c4/fatfsimage -------------------------------------------------------------------------------- /fatfsimage.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2018 Leland Lucius 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "sdkconfig.h" 22 | 23 | #include "argtable3.h" 24 | #include "diskio.h" 25 | #include "esp_err.h" 26 | #include "esp_log.h" 27 | #include "esp_spi_flash.h" 28 | #include "ff.h" 29 | #include "WL_Flash.h" 30 | 31 | // Copied from "esp-idf/components/wear_leveling/wear_leveling.cpp" 32 | #ifndef MAX_WL_HANDLES 33 | #define MAX_WL_HANDLES 8 34 | #endif // MAX_WL_HANDLES 35 | 36 | #ifndef WL_DEFAULT_UPDATERATE 37 | #define WL_DEFAULT_UPDATERATE 16 38 | #endif //WL_DEFAULT_UPDATERATE 39 | 40 | #ifndef WL_DEFAULT_TEMP_BUFF_SIZE 41 | #define WL_DEFAULT_TEMP_BUFF_SIZE 32 42 | #endif //WL_DEFAULT_TEMP_BUFF_SIZE 43 | 44 | #ifndef WL_DEFAULT_WRITE_SIZE 45 | #define WL_DEFAULT_WRITE_SIZE 16 46 | #endif //WL_DEFAULT_WRITE_SIZE 47 | 48 | #ifndef WL_DEFAULT_START_ADDR 49 | #define WL_DEFAULT_START_ADDR 0 50 | #endif //WL_DEFAULT_START_ADDR 51 | 52 | #ifndef WL_CURRENT_VERSION 53 | #define WL_CURRENT_VERSION 1 54 | #endif //WL_CURRENT_VERSION 55 | 56 | static const char TAG[] = "FatFSImage"; 57 | static const char drv[] = "FatFSImage"; 58 | static WL_Flash flash; 59 | 60 | class FatFSImage : public Flash_Access 61 | { 62 | private: 63 | typedef struct 64 | { 65 | const char *srcbase; 66 | const char *dstbase; 67 | int srclen; 68 | int dstlen; 69 | char src[PATH_MAX]; 70 | char dst[PATH_MAX]; 71 | char buf[SPI_FLASH_SEC_SIZE]; 72 | } copy_state; 73 | 74 | public: 75 | FatFSImage(); 76 | virtual ~FatFSImage(); 77 | 78 | esp_err_t main(int argc, char *argv[]); 79 | esp_err_t parse(int argc, char *argv[]); 80 | esp_err_t init_wear_levelling(); 81 | esp_err_t create_image(); 82 | esp_err_t create_filesystem(); 83 | esp_err_t load_files(); 84 | esp_err_t copy(const char *src, const char *dst); 85 | esp_err_t copy_sub(copy_state *cs); 86 | 87 | // 88 | // Flash_Access implementaion 89 | // 90 | virtual size_t chip_size() final; 91 | virtual esp_err_t erase_sector(size_t sector) final; 92 | virtual esp_err_t erase_range(size_t start_address, size_t size) final; 93 | virtual esp_err_t write(size_t dest_addr, const void *src, size_t size) final; 94 | virtual esp_err_t read(size_t src_addr, void *dest, size_t size) final; 95 | virtual size_t sector_size() final; 96 | 97 | private: 98 | struct 99 | { 100 | struct arg_lit *help; 101 | struct arg_int *level; 102 | struct arg_file *image; 103 | struct arg_int *kb; 104 | struct arg_file *paths; 105 | struct arg_end *end; 106 | } 107 | args = 108 | { 109 | arg_litn("h", "help", 0, 1, "display this help and exit"), 110 | arg_intn("l", "log", "", 0, 1, "log level (0-5, 3 is default)"), 111 | arg_filen(NULL, NULL, "", 1, 1, "image file name"), 112 | arg_intn(NULL, NULL, "", 1, 1, "disk size in KB"), 113 | arg_filen(NULL, NULL, "", 1, 20, "directories/files to load"), 114 | arg_end(1), 115 | }; 116 | void **argtable = (void **) &args; // shame on me ;-) 117 | static const int argcount = sizeof(args) / sizeof(void *); 118 | 119 | FILE *image; 120 | FATFS *fs; 121 | uint32_t image_bytes = 0; 122 | uint32_t sector_bytes = 0; 123 | uint32_t sector_count = 0; 124 | uint32_t numdirs = 0; 125 | uint32_t numfiles = 0; 126 | }; 127 | 128 | FatFSImage::FatFSImage() 129 | { 130 | sector_bytes = SPI_FLASH_SEC_SIZE; 131 | image = NULL; 132 | fs = NULL; 133 | numdirs = 0; 134 | numfiles = 0; 135 | } 136 | 137 | FatFSImage::~FatFSImage() 138 | { 139 | } 140 | 141 | int FatFSImage::main(int argc, char *argv[]) 142 | { 143 | esp_err_t err = ESP_FAIL; 144 | 145 | if (parse(argc, argv) == ESP_OK) 146 | { 147 | if (create_image() == ESP_OK) 148 | { 149 | if (init_wear_levelling() == ESP_OK) 150 | { 151 | if (create_filesystem() == ESP_OK) 152 | { 153 | if (load_files() == ESP_OK) 154 | { 155 | FATFS *fs; 156 | DWORD nfree = 0; 157 | FRESULT res = f_getfree(drv, &nfree, &fs); 158 | printf("Filesystem created\n\n"); 159 | printf(" directories created: %d\n", numdirs); 160 | printf(" files copied: %d\n", numfiles); 161 | printf("\n"); 162 | 163 | printf(" flash sector size: %d\n", SPI_FLASH_SEC_SIZE); 164 | printf(" flash sectors: %d\n", image_bytes / SPI_FLASH_SEC_SIZE); 165 | printf("\n"); 166 | printf(" filesystem sector size: %d\n", fs->ssize); 167 | printf(" filesystem sectors: %d\n", image_bytes / fs->ssize); 168 | printf(" filesystem cluster size: %d\n", fs->csize * fs->ssize); 169 | printf(" filesystem total clusters: %d\n", fs->n_fatent - 2); 170 | printf(" filesystem free clusters: %d\n", nfree); 171 | 172 | err = ESP_OK; 173 | } 174 | 175 | f_unmount(drv); 176 | delete fs; 177 | } 178 | } 179 | 180 | fclose(image); 181 | } 182 | 183 | arg_freetable(argtable, argcount); 184 | } 185 | 186 | return err; 187 | } 188 | 189 | esp_err_t FatFSImage::parse(int argc, char *argv[]) 190 | { 191 | esp_err_t err; 192 | 193 | int err_cnt = arg_parse(argc, argv, argtable); 194 | 195 | if (args.help->count > 0) 196 | { 197 | printf("Usage: %s", argv[0]); 198 | arg_print_syntax(stdout, argtable, "\n"); 199 | 200 | printf("Create and load a FATFS disk image.\n\n"); 201 | arg_print_glossary(stdout, argtable, " %-25s %s\n"); 202 | 203 | err = ESP_FAIL; 204 | } 205 | else if (err_cnt > 0) 206 | { 207 | /* Display the error details contained in the arg_end struct.*/ 208 | arg_print_errors(stdout, args.end, argv[0]); 209 | 210 | printf("\nUsage: %s", argv[0]); 211 | arg_print_syntax(stdout, argtable, "\n"); 212 | 213 | err = ESP_FAIL; 214 | } 215 | else 216 | { 217 | image_bytes = args.kb->ival[0] * 1024; 218 | sector_count = image_bytes / sector_bytes; 219 | 220 | if (args.level->count > 0) 221 | { 222 | int level = args.level->ival[0]; 223 | if (level < ESP_LOG_NONE) 224 | { 225 | level = ESP_LOG_NONE; 226 | } 227 | else if (level > ESP_LOG_VERBOSE) 228 | { 229 | level = ESP_LOG_VERBOSE; 230 | } 231 | 232 | esp_log_level_set(TAG, (esp_log_level_t) level); 233 | } 234 | 235 | err = ESP_OK; 236 | } 237 | 238 | return err; 239 | } 240 | 241 | esp_err_t FatFSImage::create_image() 242 | { 243 | ESP_LOGD(TAG, "Creating '%s' with %d bytes", args.image->filename[0], image_bytes); 244 | 245 | image = fopen(args.image->filename[0], "w+"); 246 | if (image == NULL) 247 | { 248 | ESP_LOGE(TAG, "Open failed with %d for '%s'", errno, args.image->filename[0]); 249 | return ESP_FAIL; 250 | } 251 | 252 | char buf[SPI_FLASH_SEC_SIZE]; 253 | int bytes = image_bytes; 254 | 255 | memset(buf, 0xff, sizeof(buf)); 256 | 257 | for (int i = 0, len = 0; i < bytes; i += len) 258 | { 259 | len = bytes > sizeof(buf) ? sizeof(buf) : bytes; 260 | 261 | fwrite(buf, 1, len, image); 262 | if (ferror(image)) 263 | { 264 | ESP_LOGE(TAG, "Write failed with %d for '%s'", errno, args.image->filename); 265 | return ESP_FAIL; 266 | } 267 | } 268 | 269 | return ESP_OK; 270 | } 271 | 272 | esp_err_t FatFSImage::init_wear_levelling() 273 | { 274 | ESP_LOGD(TAG, "Initalizing wear levelling"); 275 | 276 | esp_err_t err = ESP_OK; 277 | 278 | wl_config_t cfg = 279 | { 280 | .start_addr = WL_DEFAULT_START_ADDR, 281 | .full_mem_size = image_bytes, 282 | .page_size = SPI_FLASH_SEC_SIZE, 283 | .sector_size = SPI_FLASH_SEC_SIZE, 284 | .updaterate = WL_DEFAULT_UPDATERATE, 285 | .wr_size = WL_DEFAULT_WRITE_SIZE, 286 | .version = WL_CURRENT_VERSION, 287 | .temp_buff_size = WL_DEFAULT_TEMP_BUFF_SIZE, 288 | .crc = 0 289 | }; 290 | 291 | err = flash.config(&cfg, this); 292 | if (err != ESP_OK) 293 | { 294 | ESP_LOGE(TAG, "Wear levelling configuration failed with %d", err); 295 | return err; 296 | } 297 | 298 | err = flash.init(); 299 | if (err != ESP_OK) 300 | { 301 | ESP_LOGE(TAG, "Wear levelling initialization failed with %d", err); 302 | return err; 303 | } 304 | 305 | return ESP_OK; 306 | } 307 | 308 | esp_err_t FatFSImage::create_filesystem() 309 | { 310 | ESP_LOGD(TAG, "Creating filesystem within image"); 311 | 312 | esp_err_t err; 313 | FRESULT res; 314 | 315 | res = f_mkfs(drv, FM_ANY | FM_SFD, 0, NULL, 0); 316 | if (res != FR_OK) 317 | { 318 | ESP_LOGE(TAG, "Filesystem creation failed with %d", res); 319 | return ESP_FAIL; 320 | } 321 | 322 | FATFS *f = new FATFS; 323 | if (f == nullptr) 324 | { 325 | ESP_LOGE(TAG, "Insufficent memory for FATFS"); 326 | return ESP_FAIL; 327 | } 328 | 329 | res = f_mount(f, drv, 0); 330 | if (res != FR_OK) 331 | { 332 | delete f; 333 | 334 | ESP_LOGE(TAG, "Mounting filesystem failed with %d", res); 335 | return ESP_FAIL; 336 | } 337 | 338 | fs = f; 339 | 340 | return ESP_OK; 341 | } 342 | 343 | esp_err_t FatFSImage::load_files() 344 | { 345 | ESP_LOGD(TAG, "Loading files"); 346 | 347 | for (int i = 0; i < args.paths->count; ++i) 348 | { 349 | copy(args.paths->filename[i], ""); 350 | } 351 | 352 | return ESP_OK; 353 | } 354 | 355 | int FatFSImage::copy(const char *src, const char *dst) 356 | { 357 | ESP_LOGD(TAG, "Processing '%s'", src); 358 | 359 | int err = 0; 360 | 361 | copy_state *cs = (copy_state *) malloc(sizeof(copy_state)); 362 | if (cs == NULL) 363 | { 364 | ESP_LOGE(TAG, "Unable to allocate memory"); 365 | return -1; 366 | } 367 | 368 | int len; 369 | for (len = 0; src[len] && len < sizeof(cs->src); len++) 370 | { 371 | cs->src[len] = src[len]; 372 | } 373 | 374 | if (len == sizeof(cs->src)) 375 | { 376 | ESP_LOGE(TAG, "Source name '%s' is too long", src); 377 | free(cs); 378 | return -1; 379 | } 380 | cs->src[len] = '\0'; 381 | cs->srclen = len; 382 | 383 | for (len = 0; dst[len] && len < sizeof(cs->dst); len++) 384 | { 385 | cs->dst[len] = dst[len]; 386 | } 387 | 388 | if (len == sizeof(cs->dst)) 389 | { 390 | ESP_LOGE(TAG, "Target name '%s' is too long", dst); 391 | free(cs); 392 | return -1; 393 | } 394 | cs->dst[len] = '\0'; 395 | cs->dstlen = len; 396 | 397 | cs->srcbase = src; 398 | cs->dstbase = dst; 399 | 400 | err = copy_sub(cs); 401 | 402 | free(cs); 403 | 404 | return err; 405 | } 406 | 407 | int FatFSImage::copy_sub(copy_state *cs) 408 | { 409 | FRESULT res = FR_OK; 410 | int err = 0; 411 | 412 | struct stat s; 413 | if (stat(cs->src, &s) == -1) 414 | { 415 | ESP_LOGE(TAG, "Unable to get file info for '%s'", cs->src); 416 | return -1; 417 | } 418 | 419 | if (S_ISDIR(s.st_mode)) 420 | { 421 | FILINFO fno; 422 | res = f_stat(cs->dst, &fno); 423 | if (res == FR_OK && !(fno.fattrib & AM_DIR)) 424 | { 425 | ESP_LOGE(TAG, "Attempt to copy directory '%s' to non-directorys '%s'", cs->src, cs->dst); 426 | return -1; 427 | } 428 | 429 | if (res == FR_NO_FILE) 430 | { 431 | ESP_LOGD(TAG, "Creating directory '%s'", cs->dst); 432 | err = f_mkdir(cs->dst); 433 | if (err == FR_OK) 434 | { 435 | numdirs++; 436 | } 437 | } 438 | 439 | if (err != FR_OK) 440 | { 441 | ESP_LOGE(TAG, "Unable to create directory '%s'", cs->dst); 442 | return -1; 443 | } 444 | 445 | DIR *dirp = opendir(cs->src); 446 | if (dirp != NULL) 447 | { 448 | while (1) 449 | { 450 | struct dirent *dp = readdir(dirp); 451 | if (dp == NULL) 452 | { 453 | break; 454 | } 455 | 456 | if (strcmp(dp->d_name, ".") == 0 || 457 | strcmp(dp->d_name, "..") == 0) 458 | { 459 | continue; 460 | } 461 | 462 | int srcorig = cs->srclen; 463 | int dstorig = cs->dstlen; 464 | 465 | cs->srclen += 1 + strlen(dp->d_name); 466 | cs->dstlen += 1 + strlen(dp->d_name); 467 | 468 | if (cs->srclen >= PATH_MAX) 469 | { 470 | ESP_LOGE(TAG, "Source name '%s/%s' is too long", cs->src, dp->d_name); 471 | err = -1; 472 | } 473 | else if (cs->dstlen >= PATH_MAX) 474 | { 475 | ESP_LOGE(TAG, "Target name '%s/%s' is too long", cs->dst, dp->d_name); 476 | err = -1; 477 | } 478 | else 479 | { 480 | cs->src[srcorig] = '/'; 481 | strcpy(&cs->src[srcorig + 1], dp->d_name); 482 | 483 | cs->dst[dstorig] = '/'; 484 | strcpy(&cs->dst[dstorig + 1], dp->d_name); 485 | 486 | err = copy_sub(cs); 487 | 488 | cs->src[srcorig] = '\0'; 489 | cs->dst[dstorig] = '\0'; 490 | } 491 | 492 | cs->srclen = srcorig; 493 | cs->dstlen = dstorig; 494 | } 495 | 496 | closedir(dirp); 497 | } 498 | } 499 | else if (!S_ISREG(s.st_mode)) 500 | { 501 | ESP_LOGE(TAG, "'%s' is not a normal file or directory", cs->src); 502 | err = -1; 503 | } 504 | else 505 | { 506 | FILINFO fno; 507 | 508 | res = f_stat(cs->dst, &fno); 509 | if (res == FR_OK && fno.fattrib & AM_DIR) 510 | { 511 | int dstorig = cs->dstlen; 512 | char *p = &cs->src[cs->srclen]; 513 | do 514 | { 515 | cs->dstlen++; 516 | } while (*--p != '/'); 517 | 518 | if (cs->dstlen >= PATH_MAX) 519 | { 520 | ESP_LOGE(TAG, "Target name '%s/%s' is too long", cs->dst, p + 1); 521 | err = -1; 522 | } 523 | else 524 | { 525 | cs->dst[dstorig] = '/'; 526 | strcpy(&cs->dst[dstorig + 1], p + 1); 527 | } 528 | } 529 | 530 | if (res != FR_NO_FILE) 531 | { 532 | ESP_LOGE(TAG, "Unable to create destination file '%s'", cs->dst); 533 | return -1; 534 | } 535 | 536 | ESP_LOGD(TAG, "Copying file '%s' to '%s'", cs->src, cs->dst); 537 | 538 | FILE *srcf = fopen(cs->src, "rb"); 539 | if (srcf == NULL) 540 | { 541 | ESP_LOGE(TAG, "Unable to open source '%s'", cs->src); 542 | return -1; 543 | } 544 | else 545 | { 546 | FIL dstf; 547 | 548 | res = f_open(&dstf, cs->dst, FA_WRITE | FA_CREATE_ALWAYS); 549 | if (res != FR_OK) 550 | { 551 | ESP_LOGE(TAG, "Unable to open target '%s'", cs->dst); 552 | err = -1; 553 | } 554 | else 555 | { 556 | err = 0; 557 | while (!feof(srcf) && !ferror(srcf) && f_error(&dstf) == FR_OK) 558 | { 559 | UINT bw; 560 | size_t read = fread(cs->buf, 1, sizeof(cs->buf), srcf); 561 | f_write(&dstf, cs->buf, read, &bw); 562 | } 563 | 564 | if (ferror(srcf)) 565 | { 566 | ESP_LOGE(TAG, "Read returned %d for source '%s'", errno, cs->src); 567 | err = -1; 568 | } 569 | else if (f_error(&dstf) != FR_OK) 570 | { 571 | ESP_LOGE(TAG, "Write returned %d for target '%s'", f_error(&dstf), cs->src); 572 | err = -1; 573 | } 574 | else 575 | { 576 | numfiles++; 577 | } 578 | 579 | f_close(&dstf); 580 | 581 | if (err == -1) 582 | { 583 | f_unlink(cs->dst); 584 | // ignore errors 585 | } 586 | } 587 | fclose(srcf); 588 | } 589 | } 590 | 591 | return err; 592 | } 593 | 594 | 595 | // ============================================================================ 596 | // Flash_Access implementation 597 | // ============================================================================ 598 | 599 | size_t FatFSImage::chip_size() 600 | { 601 | ESP_LOGV(TAG, "%s - %d", __func__, image_bytes); 602 | 603 | return image_bytes; 604 | } 605 | 606 | esp_err_t FatFSImage::erase_sector(size_t sector) 607 | { 608 | ESP_LOGV(TAG, "%s - sector=0x%08x", __func__, (uint32_t) sector); 609 | 610 | return erase_range(sector * sector_size(), sector_size()); 611 | } 612 | 613 | esp_err_t FatFSImage::erase_range(size_t start_address, size_t size) 614 | { 615 | ESP_LOGV(TAG, "%s - add=0x%08x size=%d", __func__, (uint32_t) start_address, size); 616 | 617 | if (fseek(image, start_address, SEEK_SET) == -1) 618 | { 619 | return RES_ERROR; 620 | } 621 | 622 | char buf[SPI_FLASH_SEC_SIZE]; 623 | int bytes = size; 624 | 625 | memset(buf, 0xff, sizeof(buf)); 626 | 627 | for (int i = 0, len = 0; i < bytes; i += len) 628 | { 629 | len = bytes > sizeof(buf) ? sizeof(buf) : bytes; 630 | 631 | fwrite(buf, 1, len, image); 632 | if (ferror(image)) 633 | { 634 | return ESP_FAIL; 635 | } 636 | } 637 | 638 | return ESP_OK; 639 | } 640 | 641 | esp_err_t FatFSImage::write(size_t addr, const void *src, size_t size) 642 | { 643 | ESP_LOGV(TAG, "%s - addr=0x%08x size=%d", __func__, (uint32_t) addr, size); 644 | 645 | if (fseek(image, addr, SEEK_SET) == -1) 646 | { 647 | return RES_ERROR; 648 | } 649 | 650 | size_t written = fwrite(src, 1, size, image); 651 | if (written == size) 652 | { 653 | return RES_OK; 654 | } 655 | 656 | return ESP_OK; 657 | } 658 | 659 | esp_err_t FatFSImage::read(size_t addr, void *dest, size_t size) 660 | { 661 | ESP_LOGV(TAG, "%s - addr=0x%08x size=%d", __func__, (uint32_t) addr, size); 662 | 663 | if (fseek(image, addr, SEEK_SET) == -1) 664 | { 665 | return RES_ERROR; 666 | } 667 | 668 | size_t read = fread(dest, 1, size, image); 669 | if (read == size) 670 | { 671 | return RES_OK; 672 | } 673 | 674 | return ESP_OK; 675 | } 676 | 677 | size_t FatFSImage::sector_size() 678 | { 679 | ESP_LOGV(TAG, "%s - %d", __func__, sector_bytes); 680 | 681 | return sector_bytes; 682 | } 683 | 684 | // ============================================================================ 685 | // The rest is plain old "C" code 686 | // ============================================================================ 687 | extern "C" 688 | { 689 | 690 | // ============================================================================ 691 | // FATFS diskio implementation 692 | // ============================================================================ 693 | 694 | #if FF_MULTI_PARTITION /* Multiple partition configuration */ 695 | PARTITION VolToPart[] = { 696 | {0, 0}, /* Logical drive 0 ==> Physical drive 0, auto detection */ 697 | {1, 0} /* Logical drive 1 ==> Physical drive 1, auto detection */ 698 | }; 699 | #endif 700 | 701 | DSTATUS disk_initialize(BYTE pdrv) 702 | { 703 | ESP_LOGV(TAG, "%s - pdrv=%d", __func__, pdrv); 704 | 705 | return 0; 706 | } 707 | 708 | DSTATUS disk_status(BYTE pdrv) 709 | { 710 | ESP_LOGV(TAG, "%s - pdrv=%d", __func__, pdrv); 711 | 712 | return 0; 713 | } 714 | 715 | DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count) 716 | { 717 | ESP_LOGV(TAG, "%s - pdrv=%d, sector=%ld, count=%d", __func__, pdrv, sector, count); 718 | 719 | size_t ss = flash.sector_size(); 720 | size_t addr = sector * ss; 721 | size_t len = count * ss; 722 | esp_err_t err; 723 | 724 | err = flash.read(addr, buff, len); 725 | if (err != ESP_OK) 726 | { 727 | return RES_ERROR; 728 | } 729 | 730 | return RES_OK; 731 | } 732 | 733 | DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count) 734 | { 735 | ESP_LOGV(TAG, "%s - pdrv=%d, sector=%ld, count=%d", __func__, pdrv, sector, count); 736 | 737 | size_t ss = flash.sector_size(); 738 | size_t addr = sector * ss; 739 | size_t len = count * ss; 740 | esp_err_t err; 741 | 742 | err = flash.erase_range(addr, len); 743 | if (err != ESP_OK) 744 | { 745 | return RES_ERROR; 746 | } 747 | 748 | err = flash.write(addr, buff, len); 749 | if (err != ESP_OK) 750 | { 751 | return RES_ERROR; 752 | } 753 | 754 | return RES_OK; 755 | } 756 | 757 | DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) 758 | { 759 | ESP_LOGV(TAG, "%s: cmd=%d", __func__, cmd); 760 | 761 | switch (cmd) 762 | { 763 | case CTRL_SYNC: 764 | return RES_OK; 765 | 766 | case GET_SECTOR_COUNT: 767 | *((DWORD *) buff) = flash.chip_size() / flash.sector_size(); 768 | return RES_OK; 769 | 770 | case GET_SECTOR_SIZE: 771 | *((WORD *) buff) = flash.sector_size(); 772 | return RES_OK; 773 | 774 | case GET_BLOCK_SIZE: 775 | return RES_ERROR; 776 | } 777 | 778 | return RES_ERROR; 779 | } 780 | 781 | DWORD get_fattime(void) 782 | { 783 | time_t t = time(NULL); 784 | struct tm tmr; 785 | localtime_r(&t, &tmr); 786 | int year = tmr.tm_year < 80 ? 0 : tmr.tm_year - 80; 787 | return ((DWORD)(year) << 25) 788 | | ((DWORD)(tmr.tm_mon + 1) << 21) 789 | | ((DWORD)tmr.tm_mday << 16) 790 | | (WORD)(tmr.tm_hour << 11) 791 | | (WORD)(tmr.tm_min << 5) 792 | | (WORD)(tmr.tm_sec >> 1); 793 | } 794 | 795 | // ============================================================================ 796 | // ESP logging replacements 797 | // ============================================================================ 798 | 799 | static esp_log_level_t esp_log_level = ESP_LOG_INFO; 800 | 801 | void esp_log_level_set(const char* tag, esp_log_level_t level) 802 | { 803 | esp_log_level = level; 804 | } 805 | 806 | uint32_t esp_log_timestamp() 807 | { 808 | return 0; 809 | } 810 | 811 | void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) 812 | { 813 | if (esp_log_level >= level) 814 | { 815 | if (tag == TAG || esp_log_level == ESP_LOG_VERBOSE) 816 | { 817 | va_list list; 818 | va_start(list, format); 819 | vprintf(format, list); 820 | va_end(list); 821 | } 822 | } 823 | } 824 | 825 | // ============================================================================ 826 | // Ye' old main 827 | // ============================================================================ 828 | 829 | int main(int argc, char *argv[]) 830 | { 831 | FatFSImage ffsi; 832 | 833 | return ffsi.main(argc, argv) == ESP_OK ? 0 : -1; 834 | } 835 | 836 | // ============================================================================ 837 | // End if "C" code 838 | // ============================================================================ 839 | }; 840 | 841 | -------------------------------------------------------------------------------- /private/driver/sdmmc_host.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include "esp_err.h" 20 | #include "sdmmc_types.h" 21 | #include "driver/gpio.h" 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | #define SDMMC_HOST_SLOT_0 0 ///< SDMMC slot 0 28 | #define SDMMC_HOST_SLOT_1 1 ///< SDMMC slot 1 29 | 30 | /** 31 | * @brief Default sdmmc_host_t structure initializer for SDMMC peripheral 32 | * 33 | * Uses SDMMC peripheral, with 4-bit mode enabled, and max frequency set to 20MHz 34 | */ 35 | #define SDMMC_HOST_DEFAULT() {\ 36 | .flags = SDMMC_HOST_FLAG_8BIT | \ 37 | SDMMC_HOST_FLAG_4BIT | \ 38 | SDMMC_HOST_FLAG_1BIT | \ 39 | SDMMC_HOST_FLAG_DDR, \ 40 | .slot = SDMMC_HOST_SLOT_1, \ 41 | .max_freq_khz = SDMMC_FREQ_DEFAULT, \ 42 | .io_voltage = 3.3f, \ 43 | .init = &sdmmc_host_init, \ 44 | .set_bus_width = &sdmmc_host_set_bus_width, \ 45 | .get_bus_width = &sdmmc_host_get_slot_width, \ 46 | .set_bus_ddr_mode = &sdmmc_host_set_bus_ddr_mode, \ 47 | .set_card_clk = &sdmmc_host_set_card_clk, \ 48 | .do_transaction = &sdmmc_host_do_transaction, \ 49 | .deinit = &sdmmc_host_deinit, \ 50 | .io_int_enable = sdmmc_host_io_int_enable, \ 51 | .io_int_wait = sdmmc_host_io_int_wait, \ 52 | .command_timeout_ms = 0, \ 53 | } 54 | 55 | /** 56 | * Extra configuration for SDMMC peripheral slot 57 | */ 58 | typedef struct { 59 | gpio_num_t gpio_cd; ///< GPIO number of card detect signal 60 | gpio_num_t gpio_wp; ///< GPIO number of write protect signal 61 | uint8_t width; ///< Bus width used by the slot (might be less than the max width supported) 62 | uint32_t flags; ///< Features used by this slot 63 | #define SDMMC_SLOT_FLAG_INTERNAL_PULLUP BIT(0) 64 | /**< Enable internal pullups on enabled pins. The internal pullups 65 | are insufficient however, please make sure external pullups are 66 | connected on the bus. This is for debug / example purpose only. 67 | */ 68 | } sdmmc_slot_config_t; 69 | 70 | #define SDMMC_SLOT_NO_CD ((gpio_num_t) -1) ///< indicates that card detect line is not used 71 | #define SDMMC_SLOT_NO_WP ((gpio_num_t) -1) ///< indicates that write protect line is not used 72 | #define SDMMC_SLOT_WIDTH_DEFAULT 0 ///< use the default width for the slot (8 for slot 0, 4 for slot 1) 73 | 74 | /** 75 | * Macro defining default configuration of SDMMC host slot 76 | */ 77 | #define SDMMC_SLOT_CONFIG_DEFAULT() {\ 78 | .gpio_cd = SDMMC_SLOT_NO_CD, \ 79 | .gpio_wp = SDMMC_SLOT_NO_WP, \ 80 | .width = SDMMC_SLOT_WIDTH_DEFAULT, \ 81 | .flags = 0, \ 82 | } 83 | 84 | /** 85 | * @brief Initialize SDMMC host peripheral 86 | * 87 | * @note This function is not thread safe 88 | * 89 | * @return 90 | * - ESP_OK on success 91 | * - ESP_ERR_INVALID_STATE if sdmmc_host_init was already called 92 | * - ESP_ERR_NO_MEM if memory can not be allocated 93 | */ 94 | esp_err_t sdmmc_host_init(); 95 | 96 | /** 97 | * @brief Initialize given slot of SDMMC peripheral 98 | * 99 | * On the ESP32, SDMMC peripheral has two slots: 100 | * - Slot 0: 8-bit wide, maps to HS1_* signals in PIN MUX 101 | * - Slot 1: 4-bit wide, maps to HS2_* signals in PIN MUX 102 | * 103 | * Card detect and write protect signals can be routed to 104 | * arbitrary GPIOs using GPIO matrix. 105 | * 106 | * @note This function is not thread safe 107 | * 108 | * @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1) 109 | * @param slot_config additional configuration for the slot 110 | * @return 111 | * - ESP_OK on success 112 | * - ESP_ERR_INVALID_STATE if host has not been initialized using sdmmc_host_init 113 | */ 114 | esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t* slot_config); 115 | 116 | /** 117 | * @brief Select bus width to be used for data transfer 118 | * 119 | * SD/MMC card must be initialized prior to this command, and a command to set 120 | * bus width has to be sent to the card (e.g. SD_APP_SET_BUS_WIDTH) 121 | * 122 | * @note This function is not thread safe 123 | * 124 | * @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1) 125 | * @param width bus width (1, 4, or 8 for slot 0; 1 or 4 for slot 1) 126 | * @return 127 | * - ESP_OK on success 128 | * - ESP_ERR_INVALID_ARG if slot number or width is not valid 129 | */ 130 | esp_err_t sdmmc_host_set_bus_width(int slot, size_t width); 131 | 132 | /** 133 | * @brief Get bus width configured in ``sdmmc_host_init_slot`` to be used for data transfer 134 | * 135 | * @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1) 136 | * @return configured bus width of the specified slot. 137 | */ 138 | size_t sdmmc_host_get_slot_width(int slot); 139 | 140 | /** 141 | * @brief Set card clock frequency 142 | * 143 | * Currently only integer fractions of 40MHz clock can be used. 144 | * For High Speed cards, 40MHz can be used. 145 | * For Default Speed cards, 20MHz can be used. 146 | * 147 | * @note This function is not thread safe 148 | * 149 | * @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1) 150 | * @param freq_khz card clock frequency, in kHz 151 | * @return 152 | * - ESP_OK on success 153 | * - other error codes may be returned in the future 154 | */ 155 | esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz); 156 | 157 | /** 158 | * @brief Enable or disable DDR mode of SD interface 159 | * @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1) 160 | * @param ddr_enabled enable or disable DDR mode 161 | * @return 162 | * - ESP_OK on success 163 | * - ESP_ERR_NOT_SUPPORTED if DDR mode is not supported on this slot 164 | */ 165 | esp_err_t sdmmc_host_set_bus_ddr_mode(int slot, bool ddr_enabled); 166 | 167 | /** 168 | * @brief Send command to the card and get response 169 | * 170 | * This function returns when command is sent and response is received, 171 | * or data is transferred, or timeout occurs. 172 | * 173 | * @note This function is not thread safe w.r.t. init/deinit functions, 174 | * and bus width/clock speed configuration functions. Multiple tasks 175 | * can call sdmmc_host_do_transaction as long as other sdmmc_host_* 176 | * functions are not called. 177 | * 178 | * @attention Data buffer passed in cmdinfo->data must be in DMA capable memory 179 | * 180 | * @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1) 181 | * @param cmdinfo pointer to structure describing command and data to transfer 182 | * @return 183 | * - ESP_OK on success 184 | * - ESP_ERR_TIMEOUT if response or data transfer has timed out 185 | * - ESP_ERR_INVALID_CRC if response or data transfer CRC check has failed 186 | * - ESP_ERR_INVALID_RESPONSE if the card has sent an invalid response 187 | * - ESP_ERR_INVALID_SIZE if the size of data transfer is not valid in SD protocol 188 | * - ESP_ERR_INVALID_ARG if the data buffer is not in DMA capable memory 189 | */ 190 | esp_err_t sdmmc_host_do_transaction(int slot, sdmmc_command_t* cmdinfo); 191 | 192 | /** 193 | * @brief Enable IO interrupts 194 | * 195 | * This function configures the host to accept SDIO interrupts. 196 | * 197 | * @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1) 198 | * @return returns ESP_OK, other errors possible in the future 199 | */ 200 | esp_err_t sdmmc_host_io_int_enable(int slot); 201 | 202 | /** 203 | * @brief Block until an SDIO interrupt is received, or timeout occurs 204 | * @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1) 205 | * @param timeout_ticks number of RTOS ticks to wait for the interrupt 206 | * @return 207 | * - ESP_OK on success (interrupt received) 208 | * - ESP_ERR_TIMEOUT if the interrupt did not occur within timeout_ticks 209 | */ 210 | esp_err_t sdmmc_host_io_int_wait(int slot, TickType_t timeout_ticks); 211 | 212 | /** 213 | * @brief Disable SDMMC host and release allocated resources 214 | * 215 | * @note This function is not thread safe 216 | * 217 | * @return 218 | * - ESP_OK on success 219 | * - ESP_ERR_INVALID_STATE if sdmmc_host_init function has not been called 220 | */ 221 | esp_err_t sdmmc_host_deinit(); 222 | 223 | /** 224 | * @brief Enable the pull-ups of sd pins. 225 | * 226 | * @note You should always place actual pullups on the lines instead of using 227 | * this function. Internal pullup resistance are high and not sufficient, may 228 | * cause instability in products. This is for debug or examples only. 229 | * 230 | * @param slot Slot to use, normally set it to 1. 231 | * @param width Bit width of your configuration, 1 or 4. 232 | * 233 | * @return 234 | * - ESP_OK: if success 235 | * - ESP_ERR_INVALID_ARG: if configured width larger than maximum the slot can 236 | * support 237 | */ 238 | esp_err_t sdmmc_host_pullup_en(int slot, int width); 239 | 240 | #ifdef __cplusplus 241 | } 242 | #endif 243 | -------------------------------------------------------------------------------- /private/esp_err.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #pragma once 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | typedef int32_t esp_err_t; 25 | 26 | /* Definitions for error constants. */ 27 | #define ESP_OK 0 /*!< esp_err_t value indicating success (no error) */ 28 | #define ESP_FAIL -1 /*!< Generic esp_err_t code indicating failure */ 29 | 30 | #define ESP_ERR_NO_MEM 0x101 /*!< Out of memory */ 31 | #define ESP_ERR_INVALID_ARG 0x102 /*!< Invalid argument */ 32 | #define ESP_ERR_INVALID_STATE 0x103 /*!< Invalid state */ 33 | #define ESP_ERR_INVALID_SIZE 0x104 /*!< Invalid size */ 34 | #define ESP_ERR_NOT_FOUND 0x105 /*!< Requested resource not found */ 35 | #define ESP_ERR_NOT_SUPPORTED 0x106 /*!< Operation or feature not supported */ 36 | #define ESP_ERR_TIMEOUT 0x107 /*!< Operation timed out */ 37 | #define ESP_ERR_INVALID_RESPONSE 0x108 /*!< Received response was invalid */ 38 | #define ESP_ERR_INVALID_CRC 0x109 /*!< CRC or checksum was invalid */ 39 | #define ESP_ERR_INVALID_VERSION 0x10A /*!< Version was invalid */ 40 | #define ESP_ERR_INVALID_MAC 0x10B /*!< MAC address was invalid */ 41 | 42 | #define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */ 43 | #define ESP_ERR_MESH_BASE 0x4000 /*!< Starting number of MESH error codes */ 44 | 45 | /** 46 | * @brief Returns string for esp_err_t error codes 47 | * 48 | * This function finds the error code in a pre-generated lookup-table and 49 | * returns its string representation. 50 | * 51 | * The function is generated by the Python script 52 | * tools/gen_esp_err_to_name.py which should be run each time an esp_err_t 53 | * error is modified, created or removed from the IDF project. 54 | * 55 | * @param code esp_err_t error code 56 | * @return string error message 57 | */ 58 | const char *esp_err_to_name(esp_err_t code); 59 | 60 | /** 61 | * @brief Returns string for esp_err_t and system error codes 62 | * 63 | * This function finds the error code in a pre-generated lookup-table of 64 | * esp_err_t errors and returns its string representation. If the error code 65 | * is not found then it is attempted to be found among system errors. 66 | * 67 | * The function is generated by the Python script 68 | * tools/gen_esp_err_to_name.py which should be run each time an esp_err_t 69 | * error is modified, created or removed from the IDF project. 70 | * 71 | * @param code esp_err_t error code 72 | * @param[out] buf buffer where the error message should be written 73 | * @param buflen Size of buffer buf. At most buflen bytes are written into the buf buffer (including the terminating null byte). 74 | * @return buf containing the string error message 75 | */ 76 | const char *esp_err_to_name_r(esp_err_t code, char *buf, size_t buflen); 77 | 78 | /** @cond */ 79 | void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression) __attribute__((noreturn)); 80 | 81 | /** @cond */ 82 | void _esp_error_check_failed_without_abort(esp_err_t rc, const char *file, int line, const char *function, const char *expression); 83 | 84 | #ifndef __ASSERT_FUNC 85 | /* This won't happen on IDF, which defines __ASSERT_FUNC in assert.h, but it does happen when building on the host which 86 | uses /usr/include/assert.h or equivalent. 87 | */ 88 | #ifdef __ASSERT_FUNCTION 89 | #define __ASSERT_FUNC __ASSERT_FUNCTION /* used in glibc assert.h */ 90 | #else 91 | #define __ASSERT_FUNC "??" 92 | #endif 93 | #endif 94 | /** @endcond */ 95 | 96 | /** 97 | * Macro which can be used to check the error code, 98 | * and terminate the program in case the code is not ESP_OK. 99 | * Prints the error code, error location, and the failed statement to serial output. 100 | * 101 | * Disabled if assertions are disabled. 102 | */ 103 | #ifdef NDEBUG 104 | #define ESP_ERROR_CHECK(x) do { \ 105 | esp_err_t __err_rc = (x); \ 106 | (void) sizeof(__err_rc); \ 107 | } while(0) 108 | #elif defined(CONFIG_OPTIMIZATION_ASSERTIONS_SILENT) 109 | #define ESP_ERROR_CHECK(x) do { \ 110 | esp_err_t __err_rc = (x); \ 111 | if (__err_rc != ESP_OK) { \ 112 | abort(); \ 113 | } \ 114 | } while(0) 115 | #else 116 | #define ESP_ERROR_CHECK(x) do { \ 117 | esp_err_t __err_rc = (x); \ 118 | if (__err_rc != ESP_OK) { \ 119 | _esp_error_check_failed(__err_rc, __FILE__, __LINE__, \ 120 | __ASSERT_FUNC, #x); \ 121 | } \ 122 | } while(0) 123 | #endif 124 | 125 | /** 126 | * Macro which can be used to check the error code. Prints the error code, error location, and the failed statement to 127 | * serial output. 128 | * In comparison with ESP_ERROR_CHECK(), this prints the same error message but isn't terminating the program. 129 | */ 130 | #ifdef NDEBUG 131 | #define ESP_ERROR_CHECK_WITHOUT_ABORT(x) ({ \ 132 | esp_err_t __err_rc = (x); \ 133 | __err_rc; \ 134 | }) 135 | #else 136 | #define ESP_ERROR_CHECK_WITHOUT_ABORT(x) ({ \ 137 | esp_err_t __err_rc = (x); \ 138 | if (__err_rc != ESP_OK) { \ 139 | _esp_error_check_failed_without_abort(__err_rc, __FILE__, __LINE__, \ 140 | __ASSERT_FUNC, #x); \ 141 | } \ 142 | __err_rc; \ 143 | }) 144 | #endif //NDEBUG 145 | 146 | #ifdef __cplusplus 147 | } 148 | #endif 149 | -------------------------------------------------------------------------------- /private/freertos/FreeRTOS.h: -------------------------------------------------------------------------------- 1 | /* 2 | FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd. 3 | All rights reserved 4 | 5 | VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. 6 | 7 | This file is part of the FreeRTOS distribution. 8 | 9 | FreeRTOS is free software; you can redistribute it and/or modify it under 10 | the terms of the GNU General Public License (version 2) as published by the 11 | Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. 12 | 13 | *************************************************************************** 14 | >>! NOTE: The modification to the GPL is included to allow you to !<< 15 | >>! distribute a combined work that includes FreeRTOS without being !<< 16 | >>! obliged to provide the source code for proprietary components !<< 17 | >>! outside of the FreeRTOS kernel. !<< 18 | *************************************************************************** 19 | 20 | FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY 21 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 22 | FOR A PARTICULAR PURPOSE. Full license text is available on the following 23 | link: http://www.freertos.org/a00114.html 24 | 25 | *************************************************************************** 26 | * * 27 | * FreeRTOS provides completely free yet professionally developed, * 28 | * robust, strictly quality controlled, supported, and cross * 29 | * platform software that is more than just the market leader, it * 30 | * is the industry's de facto standard. * 31 | * * 32 | * Help yourself get started quickly while simultaneously helping * 33 | * to support the FreeRTOS project by purchasing a FreeRTOS * 34 | * tutorial book, reference manual, or both: * 35 | * http://www.FreeRTOS.org/Documentation * 36 | * * 37 | *************************************************************************** 38 | 39 | http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading 40 | the FAQ page "My application does not run, what could be wrong?". Have you 41 | defined configASSERT()? 42 | 43 | http://www.FreeRTOS.org/support - In return for receiving this top quality 44 | embedded software for free we request you assist our global community by 45 | participating in the support forum. 46 | 47 | http://www.FreeRTOS.org/training - Investing in training allows your team to 48 | be as productive as possible as early as possible. Now you can receive 49 | FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers 50 | Ltd, and the world's leading authority on the world's leading RTOS. 51 | 52 | http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, 53 | including FreeRTOS+Trace - an indispensable productivity tool, a DOS 54 | compatible FAT file system, and our tiny thread aware UDP/IP stack. 55 | 56 | http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. 57 | Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. 58 | 59 | http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High 60 | Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS 61 | licenses offer ticketed support, indemnification and commercial middleware. 62 | 63 | http://www.SafeRTOS.com - High Integrity Systems also provide a safety 64 | engineered and independently SIL3 certified version for use in safety and 65 | mission critical applications that require provable dependability. 66 | 67 | 1 tab == 4 spaces! 68 | */ 69 | 70 | #ifndef INC_FREERTOS_H 71 | #define INC_FREERTOS_H 72 | 73 | /* 74 | * Include the generic headers required for the FreeRTOS port being used. 75 | */ 76 | #include 77 | #include "sys/reent.h" 78 | 79 | /* 80 | * If stdint.h cannot be located then: 81 | * + If using GCC ensure the -nostdint options is *not* being used. 82 | * + Ensure the project's include path includes the directory in which your 83 | * compiler stores stdint.h. 84 | * + Set any compiler options necessary for it to support C99, as technically 85 | * stdint.h is only mandatory with C99 (FreeRTOS does not require C99 in any 86 | * other way). 87 | * + The FreeRTOS download includes a simple stdint.h definition that can be 88 | * used in cases where none is provided by the compiler. The files only 89 | * contains the typedefs required to build FreeRTOS. Read the instructions 90 | * in FreeRTOS/source/stdint.readme for more information. 91 | */ 92 | #include /* READ COMMENT ABOVE. */ 93 | 94 | #ifdef __cplusplus 95 | extern "C" { 96 | #endif 97 | 98 | /* Application specific configuration options. */ 99 | #include "FreeRTOSConfig.h" 100 | 101 | /* Basic FreeRTOS definitions. */ 102 | #include "projdefs.h" 103 | 104 | /* Definitions specific to the port being used. */ 105 | #include "portable.h" 106 | 107 | /* 108 | * Check all the required application specific macros have been defined. 109 | * These macros are application specific and (as downloaded) are defined 110 | * within FreeRTOSConfig.h. 111 | */ 112 | 113 | #ifndef configMINIMAL_STACK_SIZE 114 | #error Missing definition: configMINIMAL_STACK_SIZE must be defined in FreeRTOSConfig.h. configMINIMAL_STACK_SIZE defines the size (in words) of the stack allocated to the idle task. Refer to the demo project provided for your port for a suitable value. 115 | #endif 116 | 117 | #ifndef configMAX_PRIORITIES 118 | #error Missing definition: configMAX_PRIORITIES must be defined in FreeRTOSConfig.h. See the Configuration section of the FreeRTOS API documentation for details. 119 | #endif 120 | 121 | #ifndef configUSE_PREEMPTION 122 | #error Missing definition: configUSE_PREEMPTION must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. 123 | #endif 124 | 125 | #ifndef configUSE_IDLE_HOOK 126 | #error Missing definition: configUSE_IDLE_HOOK must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. 127 | #endif 128 | 129 | #ifndef configUSE_TICK_HOOK 130 | #error Missing definition: configUSE_TICK_HOOK must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. 131 | #endif 132 | 133 | #ifndef configUSE_CO_ROUTINES 134 | #error Missing definition: configUSE_CO_ROUTINES must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. 135 | #endif 136 | 137 | #ifndef INCLUDE_vTaskPrioritySet 138 | #error Missing definition: INCLUDE_vTaskPrioritySet must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. 139 | #endif 140 | 141 | #ifndef INCLUDE_uxTaskPriorityGet 142 | #error Missing definition: INCLUDE_uxTaskPriorityGet must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. 143 | #endif 144 | 145 | #ifndef INCLUDE_vTaskDelete 146 | #error Missing definition: INCLUDE_vTaskDelete must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. 147 | #endif 148 | 149 | #ifndef INCLUDE_vTaskSuspend 150 | #error Missing definition: INCLUDE_vTaskSuspend must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. 151 | #endif 152 | 153 | #ifndef INCLUDE_vTaskDelayUntil 154 | #error Missing definition: INCLUDE_vTaskDelayUntil must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. 155 | #endif 156 | 157 | #ifndef INCLUDE_vTaskDelay 158 | #error Missing definition: INCLUDE_vTaskDelay must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. 159 | #endif 160 | 161 | #ifndef configUSE_16_BIT_TICKS 162 | #error Missing definition: configUSE_16_BIT_TICKS must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. 163 | #endif 164 | 165 | #if configUSE_CO_ROUTINES != 0 166 | #ifndef configMAX_CO_ROUTINE_PRIORITIES 167 | #error configMAX_CO_ROUTINE_PRIORITIES must be greater than or equal to 1. 168 | #endif 169 | #endif 170 | 171 | #ifndef configMAX_PRIORITIES 172 | #error configMAX_PRIORITIES must be defined to be greater than or equal to 1. 173 | #endif 174 | 175 | #ifndef INCLUDE_xTaskGetIdleTaskHandle 176 | #define INCLUDE_xTaskGetIdleTaskHandle 0 177 | #endif 178 | 179 | #ifndef INCLUDE_xTimerGetTimerDaemonTaskHandle 180 | #define INCLUDE_xTimerGetTimerDaemonTaskHandle 0 181 | #endif 182 | 183 | #ifndef INCLUDE_xQueueGetMutexHolder 184 | #define INCLUDE_xQueueGetMutexHolder 0 185 | #endif 186 | 187 | #ifndef INCLUDE_xSemaphoreGetMutexHolder 188 | #define INCLUDE_xSemaphoreGetMutexHolder INCLUDE_xQueueGetMutexHolder 189 | #endif 190 | 191 | #ifndef INCLUDE_pcTaskGetTaskName 192 | #define INCLUDE_pcTaskGetTaskName 1 193 | #endif 194 | 195 | #ifndef configUSE_APPLICATION_TASK_TAG 196 | #define configUSE_APPLICATION_TASK_TAG 0 197 | #endif 198 | 199 | #ifndef INCLUDE_uxTaskGetStackHighWaterMark 200 | #define INCLUDE_uxTaskGetStackHighWaterMark 0 201 | #endif 202 | 203 | #ifndef INCLUDE_pxTaskGetStackStart 204 | #define INCLUDE_pxTaskGetStackStart 0 205 | #endif 206 | 207 | #ifndef INCLUDE_eTaskGetState 208 | #define INCLUDE_eTaskGetState 0 209 | #endif 210 | 211 | #ifndef configUSE_RECURSIVE_MUTEXES 212 | #define configUSE_RECURSIVE_MUTEXES 0 213 | #endif 214 | 215 | #ifndef configUSE_MUTEXES 216 | #define configUSE_MUTEXES 0 217 | #endif 218 | 219 | #ifndef configUSE_TIMERS 220 | #define configUSE_TIMERS 0 221 | #endif 222 | 223 | #ifndef configUSE_COUNTING_SEMAPHORES 224 | #define configUSE_COUNTING_SEMAPHORES 0 225 | #endif 226 | 227 | #ifndef configUSE_ALTERNATIVE_API 228 | #define configUSE_ALTERNATIVE_API 0 229 | #endif 230 | 231 | #ifndef portCRITICAL_NESTING_IN_TCB 232 | #define portCRITICAL_NESTING_IN_TCB 0 233 | #endif 234 | 235 | #ifndef configMAX_TASK_NAME_LEN 236 | #define configMAX_TASK_NAME_LEN 16 237 | #endif 238 | 239 | #ifndef configIDLE_SHOULD_YIELD 240 | #define configIDLE_SHOULD_YIELD 1 241 | #endif 242 | 243 | #if configMAX_TASK_NAME_LEN < 1 244 | #error configMAX_TASK_NAME_LEN must be set to a minimum of 1 in FreeRTOSConfig.h 245 | #endif 246 | 247 | #ifndef INCLUDE_xTaskResumeFromISR 248 | #define INCLUDE_xTaskResumeFromISR 1 249 | #endif 250 | 251 | #ifndef INCLUDE_xEventGroupSetBitFromISR 252 | #define INCLUDE_xEventGroupSetBitFromISR 0 253 | #endif 254 | 255 | #ifndef INCLUDE_xTimerPendFunctionCall 256 | #define INCLUDE_xTimerPendFunctionCall 0 257 | #endif 258 | 259 | #ifndef configASSERT 260 | #define configASSERT( x ) 261 | #define configASSERT_DEFINED 0 262 | #else 263 | #define configASSERT_DEFINED 1 264 | #endif 265 | 266 | /* The timers module relies on xTaskGetSchedulerState(). */ 267 | #if configUSE_TIMERS == 1 268 | 269 | #ifndef configTIMER_TASK_PRIORITY 270 | #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_PRIORITY must also be defined. 271 | #endif /* configTIMER_TASK_PRIORITY */ 272 | 273 | #ifndef configTIMER_QUEUE_LENGTH 274 | #error If configUSE_TIMERS is set to 1 then configTIMER_QUEUE_LENGTH must also be defined. 275 | #endif /* configTIMER_QUEUE_LENGTH */ 276 | 277 | #ifndef configTIMER_TASK_STACK_DEPTH 278 | #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_STACK_DEPTH must also be defined. 279 | #endif /* configTIMER_TASK_STACK_DEPTH */ 280 | 281 | #endif /* configUSE_TIMERS */ 282 | 283 | #ifndef INCLUDE_xTaskGetSchedulerState 284 | #define INCLUDE_xTaskGetSchedulerState 0 285 | #endif 286 | 287 | #ifndef INCLUDE_xTaskGetCurrentTaskHandle 288 | #define INCLUDE_xTaskGetCurrentTaskHandle 0 289 | #endif 290 | 291 | 292 | #ifndef portSET_INTERRUPT_MASK_FROM_ISR 293 | #define portSET_INTERRUPT_MASK_FROM_ISR() 0 294 | #endif 295 | 296 | #ifndef portCLEAR_INTERRUPT_MASK_FROM_ISR 297 | #define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) ( void ) uxSavedStatusValue 298 | #endif 299 | 300 | #ifndef portCLEAN_UP_TCB 301 | #define portCLEAN_UP_TCB( pxTCB ) ( void ) pxTCB 302 | #endif 303 | 304 | #ifndef portPRE_TASK_DELETE_HOOK 305 | #define portPRE_TASK_DELETE_HOOK( pvTaskToDelete, pxYieldPending ) 306 | #endif 307 | 308 | #ifndef portSETUP_TCB 309 | #define portSETUP_TCB( pxTCB ) ( void ) pxTCB 310 | #endif 311 | 312 | #ifndef configQUEUE_REGISTRY_SIZE 313 | #define configQUEUE_REGISTRY_SIZE 0U 314 | #endif 315 | 316 | #if ( configQUEUE_REGISTRY_SIZE < 1 ) 317 | #define vQueueAddToRegistry( xQueue, pcName ) 318 | #define vQueueUnregisterQueue( xQueue ) 319 | #endif 320 | 321 | #ifndef portPOINTER_SIZE_TYPE 322 | #define portPOINTER_SIZE_TYPE uint32_t 323 | #endif 324 | 325 | /* Remove any unused trace macros. */ 326 | #ifndef traceSTART 327 | /* Used to perform any necessary initialisation - for example, open a file 328 | into which trace is to be written. */ 329 | #define traceSTART() 330 | #endif 331 | 332 | #ifndef traceEND 333 | /* Use to close a trace, for example close a file into which trace has been 334 | written. */ 335 | #define traceEND() 336 | #endif 337 | 338 | #ifndef traceTASK_SWITCHED_IN 339 | /* Called after a task has been selected to run. pxCurrentTCB holds a pointer 340 | to the task control block of the selected task. */ 341 | #define traceTASK_SWITCHED_IN() 342 | #endif 343 | 344 | #ifndef traceINCREASE_TICK_COUNT 345 | /* Called before stepping the tick count after waking from tickless idle 346 | sleep. */ 347 | #define traceINCREASE_TICK_COUNT( x ) 348 | #endif 349 | 350 | #ifndef traceLOW_POWER_IDLE_BEGIN 351 | /* Called immediately before entering tickless idle. */ 352 | #define traceLOW_POWER_IDLE_BEGIN() 353 | #endif 354 | 355 | #ifndef traceLOW_POWER_IDLE_END 356 | /* Called when returning to the Idle task after a tickless idle. */ 357 | #define traceLOW_POWER_IDLE_END() 358 | #endif 359 | 360 | #ifndef traceTASK_SWITCHED_OUT 361 | /* Called before a task has been selected to run. pxCurrentTCB holds a pointer 362 | to the task control block of the task being switched out. */ 363 | #define traceTASK_SWITCHED_OUT() 364 | #endif 365 | 366 | #ifndef traceTASK_PRIORITY_INHERIT 367 | /* Called when a task attempts to take a mutex that is already held by a 368 | lower priority task. pxTCBOfMutexHolder is a pointer to the TCB of the task 369 | that holds the mutex. uxInheritedPriority is the priority the mutex holder 370 | will inherit (the priority of the task that is attempting to obtain the 371 | muted. */ 372 | #define traceTASK_PRIORITY_INHERIT( pxTCBOfMutexHolder, uxInheritedPriority ) 373 | #endif 374 | 375 | #ifndef traceTASK_PRIORITY_DISINHERIT 376 | /* Called when a task releases a mutex, the holding of which had resulted in 377 | the task inheriting the priority of a higher priority task. 378 | pxTCBOfMutexHolder is a pointer to the TCB of the task that is releasing the 379 | mutex. uxOriginalPriority is the task's configured (base) priority. */ 380 | #define traceTASK_PRIORITY_DISINHERIT( pxTCBOfMutexHolder, uxOriginalPriority ) 381 | #endif 382 | 383 | #ifndef traceBLOCKING_ON_QUEUE_RECEIVE 384 | /* Task is about to block because it cannot read from a 385 | queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore 386 | upon which the read was attempted. pxCurrentTCB points to the TCB of the 387 | task that attempted the read. */ 388 | #define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ) 389 | #endif 390 | 391 | #ifndef traceBLOCKING_ON_QUEUE_SEND 392 | /* Task is about to block because it cannot write to a 393 | queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore 394 | upon which the write was attempted. pxCurrentTCB points to the TCB of the 395 | task that attempted the write. */ 396 | #define traceBLOCKING_ON_QUEUE_SEND( pxQueue ) 397 | #endif 398 | 399 | #ifndef configCHECK_FOR_STACK_OVERFLOW 400 | #define configCHECK_FOR_STACK_OVERFLOW 0 401 | #endif 402 | 403 | /* The following event macros are embedded in the kernel API calls. */ 404 | 405 | #ifndef traceMOVED_TASK_TO_READY_STATE 406 | #define traceMOVED_TASK_TO_READY_STATE( pxTCB ) 407 | #endif 408 | 409 | #ifndef traceREADDED_TASK_TO_READY_STATE 410 | #define traceREADDED_TASK_TO_READY_STATE( pxTCB ) traceMOVED_TASK_TO_READY_STATE( pxTCB ) 411 | #endif 412 | 413 | #ifndef traceMOVED_TASK_TO_DELAYED_LIST 414 | #define traceMOVED_TASK_TO_DELAYED_LIST() 415 | #endif 416 | 417 | #ifndef traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST 418 | #define traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST() 419 | #endif 420 | 421 | #ifndef traceMOVED_TASK_TO_SUSPENDED_LIST 422 | #define traceMOVED_TASK_TO_SUSPENDED_LIST( pxTCB ) 423 | #endif 424 | 425 | #ifndef traceQUEUE_CREATE 426 | #define traceQUEUE_CREATE( pxNewQueue ) 427 | #endif 428 | 429 | #ifndef traceQUEUE_CREATE_FAILED 430 | #define traceQUEUE_CREATE_FAILED( ucQueueType ) 431 | #endif 432 | 433 | #ifndef traceCREATE_MUTEX 434 | #define traceCREATE_MUTEX( pxNewQueue ) 435 | #endif 436 | 437 | #ifndef traceCREATE_MUTEX_FAILED 438 | #define traceCREATE_MUTEX_FAILED() 439 | #endif 440 | 441 | #ifndef traceGIVE_MUTEX_RECURSIVE 442 | #define traceGIVE_MUTEX_RECURSIVE( pxMutex ) 443 | #endif 444 | 445 | #ifndef traceGIVE_MUTEX_RECURSIVE_FAILED 446 | #define traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ) 447 | #endif 448 | 449 | #ifndef traceTAKE_MUTEX_RECURSIVE 450 | #define traceTAKE_MUTEX_RECURSIVE( pxMutex ) 451 | #endif 452 | 453 | #ifndef traceTAKE_MUTEX_RECURSIVE_FAILED 454 | #define traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex ) 455 | #endif 456 | 457 | #ifndef traceCREATE_COUNTING_SEMAPHORE 458 | #define traceCREATE_COUNTING_SEMAPHORE() 459 | #endif 460 | 461 | #ifndef traceCREATE_COUNTING_SEMAPHORE_FAILED 462 | #define traceCREATE_COUNTING_SEMAPHORE_FAILED() 463 | #endif 464 | 465 | #ifndef traceQUEUE_SEND 466 | #define traceQUEUE_SEND( pxQueue ) 467 | #endif 468 | 469 | #ifndef traceQUEUE_SEND_FAILED 470 | #define traceQUEUE_SEND_FAILED( pxQueue ) 471 | #endif 472 | 473 | #ifndef traceQUEUE_RECEIVE 474 | #define traceQUEUE_RECEIVE( pxQueue ) 475 | #endif 476 | 477 | #ifndef traceQUEUE_PEEK 478 | #define traceQUEUE_PEEK( pxQueue ) 479 | #endif 480 | 481 | #ifndef traceQUEUE_PEEK_FROM_ISR 482 | #define traceQUEUE_PEEK_FROM_ISR( pxQueue ) 483 | #endif 484 | 485 | #ifndef traceQUEUE_RECEIVE_FAILED 486 | #define traceQUEUE_RECEIVE_FAILED( pxQueue ) 487 | #endif 488 | 489 | #ifndef traceQUEUE_SEND_FROM_ISR 490 | #define traceQUEUE_SEND_FROM_ISR( pxQueue ) 491 | #endif 492 | 493 | #ifndef traceQUEUE_SEND_FROM_ISR_FAILED 494 | #define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) 495 | #endif 496 | 497 | #ifndef traceQUEUE_RECEIVE_FROM_ISR 498 | #define traceQUEUE_RECEIVE_FROM_ISR( pxQueue ) 499 | #endif 500 | 501 | #ifndef traceQUEUE_RECEIVE_FROM_ISR_FAILED 502 | #define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ) 503 | #endif 504 | 505 | #ifndef traceQUEUE_PEEK_FROM_ISR_FAILED 506 | #define traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue ) 507 | #endif 508 | 509 | #ifndef traceQUEUE_DELETE 510 | #define traceQUEUE_DELETE( pxQueue ) 511 | #endif 512 | 513 | #ifndef traceTASK_CREATE 514 | #define traceTASK_CREATE( pxNewTCB ) 515 | #endif 516 | 517 | #ifndef traceTASK_CREATE_FAILED 518 | #define traceTASK_CREATE_FAILED() 519 | #endif 520 | 521 | #ifndef traceTASK_DELETE 522 | #define traceTASK_DELETE( pxTaskToDelete ) 523 | #endif 524 | 525 | #ifndef traceTASK_DELAY_UNTIL 526 | #define traceTASK_DELAY_UNTIL() 527 | #endif 528 | 529 | #ifndef traceTASK_DELAY 530 | #define traceTASK_DELAY() 531 | #endif 532 | 533 | #ifndef traceTASK_PRIORITY_SET 534 | #define traceTASK_PRIORITY_SET( pxTask, uxNewPriority ) 535 | #endif 536 | 537 | #ifndef traceTASK_SUSPEND 538 | #define traceTASK_SUSPEND( pxTaskToSuspend ) 539 | #endif 540 | 541 | #ifndef traceTASK_RESUME 542 | #define traceTASK_RESUME( pxTaskToResume ) 543 | #endif 544 | 545 | #ifndef traceTASK_RESUME_FROM_ISR 546 | #define traceTASK_RESUME_FROM_ISR( pxTaskToResume ) 547 | #endif 548 | 549 | #ifndef traceTASK_INCREMENT_TICK 550 | #define traceTASK_INCREMENT_TICK( xTickCount ) 551 | #endif 552 | 553 | #ifndef traceTIMER_CREATE 554 | #define traceTIMER_CREATE( pxNewTimer ) 555 | #endif 556 | 557 | #ifndef traceTIMER_CREATE_FAILED 558 | #define traceTIMER_CREATE_FAILED() 559 | #endif 560 | 561 | #ifndef traceTIMER_COMMAND_SEND 562 | #define traceTIMER_COMMAND_SEND( xTimer, xMessageID, xMessageValueValue, xReturn ) 563 | #endif 564 | 565 | #ifndef traceTIMER_EXPIRED 566 | #define traceTIMER_EXPIRED( pxTimer ) 567 | #endif 568 | 569 | #ifndef traceTIMER_COMMAND_RECEIVED 570 | #define traceTIMER_COMMAND_RECEIVED( pxTimer, xMessageID, xMessageValue ) 571 | #endif 572 | 573 | #ifndef traceMALLOC 574 | #define traceMALLOC( pvAddress, uiSize ) 575 | #endif 576 | 577 | #ifndef traceFREE 578 | #define traceFREE( pvAddress, uiSize ) 579 | #endif 580 | 581 | #ifndef traceEVENT_GROUP_CREATE 582 | #define traceEVENT_GROUP_CREATE( xEventGroup ) 583 | #endif 584 | 585 | #ifndef traceEVENT_GROUP_CREATE_FAILED 586 | #define traceEVENT_GROUP_CREATE_FAILED() 587 | #endif 588 | 589 | #ifndef traceEVENT_GROUP_SYNC_BLOCK 590 | #define traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor ) 591 | #endif 592 | 593 | #ifndef traceEVENT_GROUP_SYNC_END 594 | #define traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred ) ( void ) xTimeoutOccurred 595 | #endif 596 | 597 | #ifndef traceEVENT_GROUP_WAIT_BITS_BLOCK 598 | #define traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor ) 599 | #endif 600 | 601 | #ifndef traceEVENT_GROUP_WAIT_BITS_END 602 | #define traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred ) ( void ) xTimeoutOccurred 603 | #endif 604 | 605 | #ifndef traceEVENT_GROUP_CLEAR_BITS 606 | #define traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear ) 607 | #endif 608 | 609 | #ifndef traceEVENT_GROUP_CLEAR_BITS_FROM_ISR 610 | #define traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear ) 611 | #endif 612 | 613 | #ifndef traceEVENT_GROUP_SET_BITS 614 | #define traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet ) 615 | #endif 616 | 617 | #ifndef traceEVENT_GROUP_SET_BITS_FROM_ISR 618 | #define traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet ) 619 | #endif 620 | 621 | #ifndef traceEVENT_GROUP_DELETE 622 | #define traceEVENT_GROUP_DELETE( xEventGroup ) 623 | #endif 624 | 625 | #ifndef tracePEND_FUNC_CALL 626 | #define tracePEND_FUNC_CALL(xFunctionToPend, pvParameter1, ulParameter2, ret) 627 | #endif 628 | 629 | #ifndef tracePEND_FUNC_CALL_FROM_ISR 630 | #define tracePEND_FUNC_CALL_FROM_ISR(xFunctionToPend, pvParameter1, ulParameter2, ret) 631 | #endif 632 | 633 | #ifndef traceQUEUE_REGISTRY_ADD 634 | #define traceQUEUE_REGISTRY_ADD(xQueue, pcQueueName) 635 | #endif 636 | 637 | #ifndef traceTASK_NOTIFY_GIVE_FROM_ISR 638 | #define traceTASK_NOTIFY_GIVE_FROM_ISR() 639 | #endif 640 | 641 | #ifndef traceISR_EXIT_TO_SCHEDULER 642 | #define traceISR_EXIT_TO_SCHEDULER() 643 | #endif 644 | 645 | #ifndef traceISR_EXIT 646 | #define traceISR_EXIT() 647 | #endif 648 | 649 | #ifndef traceISR_ENTER 650 | #define traceISR_ENTER(_n_) 651 | #endif 652 | 653 | #ifndef configGENERATE_RUN_TIME_STATS 654 | #define configGENERATE_RUN_TIME_STATS 0 655 | #endif 656 | 657 | #if ( configGENERATE_RUN_TIME_STATS == 1 ) 658 | 659 | #ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS 660 | #error If configGENERATE_RUN_TIME_STATS is defined then portCONFIGURE_TIMER_FOR_RUN_TIME_STATS must also be defined. portCONFIGURE_TIMER_FOR_RUN_TIME_STATS should call a port layer function to setup a peripheral timer/counter that can then be used as the run time counter time base. 661 | #endif /* portCONFIGURE_TIMER_FOR_RUN_TIME_STATS */ 662 | 663 | #ifndef portGET_RUN_TIME_COUNTER_VALUE 664 | #ifndef portALT_GET_RUN_TIME_COUNTER_VALUE 665 | #error If configGENERATE_RUN_TIME_STATS is defined then either portGET_RUN_TIME_COUNTER_VALUE or portALT_GET_RUN_TIME_COUNTER_VALUE must also be defined. See the examples provided and the FreeRTOS web site for more information. 666 | #endif /* portALT_GET_RUN_TIME_COUNTER_VALUE */ 667 | #endif /* portGET_RUN_TIME_COUNTER_VALUE */ 668 | 669 | #endif /* configGENERATE_RUN_TIME_STATS */ 670 | 671 | #ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS 672 | #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() 673 | #endif 674 | 675 | #ifndef configUSE_MALLOC_FAILED_HOOK 676 | #define configUSE_MALLOC_FAILED_HOOK 0 677 | #endif 678 | 679 | #ifndef portPRIVILEGE_BIT 680 | #define portPRIVILEGE_BIT ( ( UBaseType_t ) 0x00 ) 681 | #endif 682 | 683 | #ifndef portYIELD_WITHIN_API 684 | #define portYIELD_WITHIN_API portYIELD 685 | #endif 686 | 687 | #ifndef pvPortMallocAligned 688 | #define pvPortMallocAligned( x, puxStackBuffer ) ( ( ( puxStackBuffer ) == NULL ) ? ( pvPortMalloc( ( x ) ) ) : ( puxStackBuffer ) ) 689 | #endif 690 | 691 | #ifndef vPortFreeAligned 692 | #define vPortFreeAligned( pvBlockToFree ) vPortFree( pvBlockToFree ) 693 | #endif 694 | 695 | #ifndef portSUPPRESS_TICKS_AND_SLEEP 696 | #define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) 697 | #endif 698 | 699 | #ifndef configEXPECTED_IDLE_TIME_BEFORE_SLEEP 700 | #define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2 701 | #endif 702 | 703 | #if configEXPECTED_IDLE_TIME_BEFORE_SLEEP < 2 704 | #error configEXPECTED_IDLE_TIME_BEFORE_SLEEP must not be less than 2 705 | #endif 706 | 707 | #ifndef configUSE_TICKLESS_IDLE 708 | #define configUSE_TICKLESS_IDLE 0 709 | #endif 710 | 711 | #ifndef configPRE_SLEEP_PROCESSING 712 | #define configPRE_SLEEP_PROCESSING( x ) 713 | #endif 714 | 715 | #ifndef configPOST_SLEEP_PROCESSING 716 | #define configPOST_SLEEP_PROCESSING( x ) 717 | #endif 718 | 719 | #ifndef configUSE_QUEUE_SETS 720 | #define configUSE_QUEUE_SETS 0 721 | #endif 722 | 723 | #ifndef portTASK_USES_FLOATING_POINT 724 | #define portTASK_USES_FLOATING_POINT() 725 | #endif 726 | 727 | #ifndef configUSE_TIME_SLICING 728 | #define configUSE_TIME_SLICING 1 729 | #endif 730 | 731 | #ifndef configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 732 | #define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 733 | #endif 734 | 735 | #ifndef configUSE_NEWLIB_REENTRANT 736 | #define configUSE_NEWLIB_REENTRANT 0 737 | #endif 738 | 739 | #ifndef configUSE_STATS_FORMATTING_FUNCTIONS 740 | #define configUSE_STATS_FORMATTING_FUNCTIONS 0 741 | #endif 742 | 743 | #ifndef configTASKLIST_INCLUDE_COREID 744 | #define configTASKLIST_INCLUDE_COREID 0 745 | #endif 746 | 747 | #ifndef portASSERT_IF_INTERRUPT_PRIORITY_INVALID 748 | #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() 749 | #endif 750 | 751 | #ifndef configUSE_TRACE_FACILITY 752 | #define configUSE_TRACE_FACILITY 0 753 | #endif 754 | 755 | #ifndef mtCOVERAGE_TEST_MARKER 756 | #define mtCOVERAGE_TEST_MARKER() 757 | #endif 758 | 759 | #ifndef portASSERT_IF_IN_ISR 760 | #define portASSERT_IF_IN_ISR() 761 | #endif 762 | 763 | #ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION 764 | #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 765 | #endif 766 | 767 | #ifndef configAPPLICATION_ALLOCATED_HEAP 768 | #define configAPPLICATION_ALLOCATED_HEAP 0 769 | #endif 770 | 771 | #ifndef configUSE_TASK_NOTIFICATIONS 772 | #define configUSE_TASK_NOTIFICATIONS 1 773 | #endif 774 | 775 | #ifndef portTICK_TYPE_IS_ATOMIC 776 | #define portTICK_TYPE_IS_ATOMIC 0 777 | #endif 778 | 779 | #ifndef configSUPPORT_STATIC_ALLOCATION 780 | /* Defaults to 0 for backward compatibility. */ 781 | #define configSUPPORT_STATIC_ALLOCATION 0 782 | #endif 783 | 784 | #ifndef configSUPPORT_DYNAMIC_ALLOCATION 785 | /* Defaults to 1 for backward compatibility. */ 786 | #define configSUPPORT_DYNAMIC_ALLOCATION 1 787 | #endif 788 | 789 | #if( ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) ) 790 | #error configSUPPORT_STATIC_ALLOCATION and configSUPPORT_DYNAMIC_ALLOCATION cannot both be 0, but can both be 1. 791 | #endif 792 | 793 | #if( portTICK_TYPE_IS_ATOMIC == 0 ) 794 | /* Either variables of tick type cannot be read atomically, or 795 | portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when 796 | the tick count is returned to the standard critical section macros. */ 797 | #define portTICK_TYPE_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux) 798 | #define portTICK_TYPE_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux) 799 | #define portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR() 800 | #define portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( ( x ) ) 801 | #else 802 | /* The tick type can be read atomically, so critical sections used when the 803 | tick count is returned can be defined away. */ 804 | #define portTICK_TYPE_ENTER_CRITICAL() 805 | #define portTICK_TYPE_EXIT_CRITICAL() 806 | #define portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR() 0 807 | #define portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( x ) ( void ) x 808 | #endif 809 | 810 | /* Definitions to allow backward compatibility with FreeRTOS versions prior to 811 | V8 if desired. */ 812 | #ifndef configENABLE_BACKWARD_COMPATIBILITY 813 | #define configENABLE_BACKWARD_COMPATIBILITY 1 814 | #endif 815 | 816 | #if configENABLE_BACKWARD_COMPATIBILITY == 1 817 | #define eTaskStateGet eTaskGetState 818 | #define portTickType TickType_t 819 | #define xTaskHandle TaskHandle_t 820 | #define xQueueHandle QueueHandle_t 821 | #define xSemaphoreHandle SemaphoreHandle_t 822 | #define xQueueSetHandle QueueSetHandle_t 823 | #define xQueueSetMemberHandle QueueSetMemberHandle_t 824 | #define xTimeOutType TimeOut_t 825 | #define xMemoryRegion MemoryRegion_t 826 | #define xTaskParameters TaskParameters_t 827 | #define xTaskStatusType TaskStatus_t 828 | #define xTimerHandle TimerHandle_t 829 | #define xCoRoutineHandle CoRoutineHandle_t 830 | #define pdTASK_HOOK_CODE TaskHookFunction_t 831 | #define portTICK_RATE_MS portTICK_PERIOD_MS 832 | 833 | /* Backward compatibility within the scheduler code only - these definitions 834 | are not really required but are included for completeness. */ 835 | #define tmrTIMER_CALLBACK TimerCallbackFunction_t 836 | #define pdTASK_CODE TaskFunction_t 837 | #define xListItem ListItem_t 838 | #define xList List_t 839 | #endif /* configENABLE_BACKWARD_COMPATIBILITY */ 840 | 841 | #ifndef configESP32_PER_TASK_DATA 842 | #define configESP32_PER_TASK_DATA 1 843 | #endif 844 | 845 | /* 846 | * In line with software engineering best practice, FreeRTOS implements a strict 847 | * data hiding policy, so the real structures used by FreeRTOS to maintain the 848 | * state of tasks, queues, semaphores, etc. are not accessible to the application 849 | * code. However, if the application writer wants to statically allocate such 850 | * an object then the size of the object needs to be know. Dummy structures 851 | * that are guaranteed to have the same size and alignment requirements of the 852 | * real objects are used for this purpose. The dummy list and list item 853 | * structures below are used for inclusion in such a dummy structure. 854 | */ 855 | struct xSTATIC_LIST_ITEM 856 | { 857 | TickType_t xDummy1; 858 | void *pvDummy2[ 4 ]; 859 | }; 860 | typedef struct xSTATIC_LIST_ITEM StaticListItem_t; 861 | 862 | /* See the comments above the struct xSTATIC_LIST_ITEM definition. */ 863 | struct xSTATIC_MINI_LIST_ITEM 864 | { 865 | TickType_t xDummy1; 866 | void *pvDummy2[ 2 ]; 867 | }; 868 | typedef struct xSTATIC_MINI_LIST_ITEM StaticMiniListItem_t; 869 | 870 | /* See the comments above the struct xSTATIC_LIST_ITEM definition. */ 871 | typedef struct xSTATIC_LIST 872 | { 873 | UBaseType_t uxDummy1; 874 | void *pvDummy2; 875 | StaticMiniListItem_t xDummy3; 876 | } StaticList_t; 877 | 878 | /* 879 | * In line with software engineering best practice, especially when supplying a 880 | * library that is likely to change in future versions, FreeRTOS implements a 881 | * strict data hiding policy. This means the Task structure used internally by 882 | * FreeRTOS is not accessible to application code. However, if the application 883 | * writer wants to statically allocate the memory required to create a task then 884 | * the size of the task object needs to be know. The StaticTask_t structure 885 | * below is provided for this purpose. Its sizes and alignment requirements are 886 | * guaranteed to match those of the genuine structure, no matter which 887 | * architecture is being used, and no matter how the values in FreeRTOSConfig.h 888 | * are set. Its contents are somewhat obfuscated in the hope users will 889 | * recognise that it would be unwise to make direct use of the structure members. 890 | */ 891 | typedef struct xSTATIC_TCB 892 | { 893 | void *pxDummy1; 894 | #if ( portUSING_MPU_WRAPPERS == 1 ) 895 | xMPU_SETTINGS xDummy2; 896 | #endif 897 | StaticListItem_t xDummy3[ 2 ]; 898 | UBaseType_t uxDummy5; 899 | void *pxDummy6; 900 | uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ]; 901 | UBaseType_t uxDummyCoreId; 902 | #if ( portSTACK_GROWTH > 0 || configENABLE_TASK_SNAPSHOT == 1 ) 903 | void *pxDummy8; 904 | #endif 905 | #if ( portCRITICAL_NESTING_IN_TCB == 1 ) 906 | UBaseType_t uxDummy9; 907 | uint32_t OldInterruptState; 908 | #endif 909 | #if ( configUSE_TRACE_FACILITY == 1 ) 910 | UBaseType_t uxDummy10[ 2 ]; 911 | #endif 912 | #if ( configUSE_MUTEXES == 1 ) 913 | UBaseType_t uxDummy12[ 2 ]; 914 | #endif 915 | #if ( configUSE_APPLICATION_TASK_TAG == 1 ) 916 | void *pxDummy14; 917 | #endif 918 | #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) 919 | void *pvDummy15[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; 920 | #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) 921 | void *pvDummyLocalStorageCallBack[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; 922 | #endif 923 | #endif 924 | #if ( configGENERATE_RUN_TIME_STATS == 1 ) 925 | uint32_t ulDummy16; 926 | #endif 927 | #if ( configUSE_NEWLIB_REENTRANT == 1 ) 928 | struct _reent xDummy17; 929 | #endif 930 | #if ( configUSE_TASK_NOTIFICATIONS == 1 ) 931 | uint32_t ulDummy18; 932 | uint32_t ucDummy19; 933 | #endif 934 | #if( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) \ 935 | || ( portUSING_MPU_WRAPPERS == 1 ) ) 936 | uint8_t uxDummy20; 937 | #endif 938 | 939 | } StaticTask_t; 940 | 941 | /* 942 | * In line with software engineering best practice, especially when supplying a 943 | * library that is likely to change in future versions, FreeRTOS implements a 944 | * strict data hiding policy. This means the Queue structure used internally by 945 | * FreeRTOS is not accessible to application code. However, if the application 946 | * writer wants to statically allocate the memory required to create a queue 947 | * then the size of the queue object needs to be know. The StaticQueue_t 948 | * structure below is provided for this purpose. Its sizes and alignment 949 | * requirements are guaranteed to match those of the genuine structure, no 950 | * matter which architecture is being used, and no matter how the values in 951 | * FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in the hope 952 | * users will recognise that it would be unwise to make direct use of the 953 | * structure members. 954 | */ 955 | typedef struct xSTATIC_QUEUE 956 | { 957 | void *pvDummy1[ 3 ]; 958 | 959 | union 960 | { 961 | void *pvDummy2; 962 | UBaseType_t uxDummy2; 963 | } u; 964 | 965 | StaticList_t xDummy3[ 2 ]; 966 | UBaseType_t uxDummy4[ 3 ]; 967 | 968 | #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) 969 | uint8_t ucDummy6; 970 | #endif 971 | 972 | #if ( configUSE_QUEUE_SETS == 1 ) 973 | void *pvDummy7; 974 | #endif 975 | 976 | #if ( configUSE_TRACE_FACILITY == 1 ) 977 | UBaseType_t uxDummy8; 978 | uint8_t ucDummy9; 979 | #endif 980 | 981 | portMUX_TYPE muxDummy; //Mutex required due to SMP 982 | 983 | } StaticQueue_t; 984 | typedef StaticQueue_t StaticSemaphore_t; 985 | 986 | /* 987 | * In line with software engineering best practice, especially when supplying a 988 | * library that is likely to change in future versions, FreeRTOS implements a 989 | * strict data hiding policy. This means the event group structure used 990 | * internally by FreeRTOS is not accessible to application code. However, if 991 | * the application writer wants to statically allocate the memory required to 992 | * create an event group then the size of the event group object needs to be 993 | * know. The StaticEventGroup_t structure below is provided for this purpose. 994 | * Its sizes and alignment requirements are guaranteed to match those of the 995 | * genuine structure, no matter which architecture is being used, and no matter 996 | * how the values in FreeRTOSConfig.h are set. Its contents are somewhat 997 | * obfuscated in the hope users will recognise that it would be unwise to make 998 | * direct use of the structure members. 999 | */ 1000 | typedef struct xSTATIC_EVENT_GROUP 1001 | { 1002 | TickType_t xDummy1; 1003 | StaticList_t xDummy2; 1004 | 1005 | #if( configUSE_TRACE_FACILITY == 1 ) 1006 | UBaseType_t uxDummy3; 1007 | #endif 1008 | 1009 | #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) 1010 | uint8_t ucDummy4; 1011 | #endif 1012 | 1013 | portMUX_TYPE muxDummy; //Mutex required due to SMP 1014 | 1015 | } StaticEventGroup_t; 1016 | 1017 | /* 1018 | * In line with software engineering best practice, especially when supplying a 1019 | * library that is likely to change in future versions, FreeRTOS implements a 1020 | * strict data hiding policy. This means the software timer structure used 1021 | * internally by FreeRTOS is not accessible to application code. However, if 1022 | * the application writer wants to statically allocate the memory required to 1023 | * create a software timer then the size of the queue object needs to be know. 1024 | * The StaticTimer_t structure below is provided for this purpose. Its sizes 1025 | * and alignment requirements are guaranteed to match those of the genuine 1026 | * structure, no matter which architecture is being used, and no matter how the 1027 | * values in FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in 1028 | * the hope users will recognise that it would be unwise to make direct use of 1029 | * the structure members. 1030 | */ 1031 | typedef struct xSTATIC_TIMER 1032 | { 1033 | void *pvDummy1; 1034 | StaticListItem_t xDummy2; 1035 | TickType_t xDummy3; 1036 | UBaseType_t uxDummy4; 1037 | void *pvDummy5[ 2 ]; 1038 | #if( configUSE_TRACE_FACILITY == 1 ) 1039 | UBaseType_t uxDummy6; 1040 | #endif 1041 | 1042 | #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) 1043 | uint8_t ucDummy7; 1044 | #endif 1045 | 1046 | } StaticTimer_t; 1047 | 1048 | #ifdef __cplusplus 1049 | } 1050 | #endif 1051 | 1052 | #endif /* INC_FREERTOS_H */ 1053 | 1054 | -------------------------------------------------------------------------------- /private/freertos/semphr.h: -------------------------------------------------------------------------------- 1 | /* 2 | FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd. 3 | All rights reserved 4 | 5 | VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. 6 | 7 | This file is part of the FreeRTOS distribution. 8 | 9 | FreeRTOS is free software; you can redistribute it and/or modify it under 10 | the terms of the GNU General Public License (version 2) as published by the 11 | Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. 12 | 13 | *************************************************************************** 14 | >>! NOTE: The modification to the GPL is included to allow you to !<< 15 | >>! distribute a combined work that includes FreeRTOS without being !<< 16 | >>! obliged to provide the source code for proprietary components !<< 17 | >>! outside of the FreeRTOS kernel. !<< 18 | *************************************************************************** 19 | 20 | FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY 21 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 22 | FOR A PARTICULAR PURPOSE. Full license text is available on the following 23 | link: http://www.freertos.org/a00114.html 24 | 25 | *************************************************************************** 26 | * * 27 | * FreeRTOS provides completely free yet professionally developed, * 28 | * robust, strictly quality controlled, supported, and cross * 29 | * platform software that is more than just the market leader, it * 30 | * is the industry's de facto standard. * 31 | * * 32 | * Help yourself get started quickly while simultaneously helping * 33 | * to support the FreeRTOS project by purchasing a FreeRTOS * 34 | * tutorial book, reference manual, or both: * 35 | * http://www.FreeRTOS.org/Documentation * 36 | * * 37 | *************************************************************************** 38 | 39 | http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading 40 | the FAQ page "My application does not run, what could be wrong?". Have you 41 | defined configASSERT()? 42 | 43 | http://www.FreeRTOS.org/support - In return for receiving this top quality 44 | embedded software for free we request you assist our global community by 45 | participating in the support forum. 46 | 47 | http://www.FreeRTOS.org/training - Investing in training allows your team to 48 | be as productive as possible as early as possible. Now you can receive 49 | FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers 50 | Ltd, and the world's leading authority on the world's leading RTOS. 51 | 52 | http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, 53 | including FreeRTOS+Trace - an indispensable productivity tool, a DOS 54 | compatible FAT file system, and our tiny thread aware UDP/IP stack. 55 | 56 | http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. 57 | Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. 58 | 59 | http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High 60 | Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS 61 | licenses offer ticketed support, indemnification and commercial middleware. 62 | 63 | http://www.SafeRTOS.com - High Integrity Systems also provide a safety 64 | engineered and independently SIL3 certified version for use in safety and 65 | mission critical applications that require provable dependability. 66 | 67 | 1 tab == 4 spaces! 68 | */ 69 | 70 | #ifndef SEMAPHORE_H 71 | #define SEMAPHORE_H 72 | 73 | #ifndef INC_FREERTOS_H 74 | #error "include FreeRTOS.h" must appear in source files before "include semphr.h" 75 | #endif 76 | 77 | #include "queue.h" 78 | 79 | typedef QueueHandle_t SemaphoreHandle_t; 80 | 81 | #define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( uint8_t ) 1U ) 82 | #define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( uint8_t ) 0U ) 83 | #define semGIVE_BLOCK_TIME ( ( TickType_t ) 0U ) 84 | 85 | /** @cond */ 86 | /** 87 | * This old vSemaphoreCreateBinary() macro is now deprecated in favour of the 88 | * xSemaphoreCreateBinary() function. Note that binary semaphores created using 89 | * the vSemaphoreCreateBinary() macro are created in a state such that the 90 | * first call to 'take' the semaphore would pass, whereas binary semaphores 91 | * created using xSemaphoreCreateBinary() are created in a state such that the 92 | * the semaphore must first be 'given' before it can be 'taken'. 93 | * 94 | * Macro that implements a semaphore by using the existing queue mechanism. 95 | * The queue length is 1 as this is a binary semaphore. The data size is 0 96 | * as we don't want to actually store any data - we just want to know if the 97 | * queue is empty or full. 98 | * 99 | * This type of semaphore can be used for pure synchronisation between tasks or 100 | * between an interrupt and a task. The semaphore need not be given back once 101 | * obtained, so one task/interrupt can continuously 'give' the semaphore while 102 | * another continuously 'takes' the semaphore. For this reason this type of 103 | * semaphore does not use a priority inheritance mechanism. For an alternative 104 | * that does use priority inheritance see xSemaphoreCreateMutex(). 105 | * 106 | * @param xSemaphore Handle to the created semaphore. Should be of type SemaphoreHandle_t. 107 | * 108 | * Example usage: 109 | * @code{c} 110 | * SemaphoreHandle_t xSemaphore = NULL; 111 | * 112 | * void vATask( void * pvParameters ) 113 | * { 114 | * // Semaphore cannot be used before a call to vSemaphoreCreateBinary (). 115 | * // This is a macro so pass the variable in directly. 116 | * vSemaphoreCreateBinary( xSemaphore ); 117 | * 118 | * if( xSemaphore != NULL ) 119 | * { 120 | * // The semaphore was created successfully. 121 | * // The semaphore can now be used. 122 | * } 123 | * } 124 | * @endcode 125 | * \ingroup Semaphores 126 | */ 127 | #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) 128 | #define vSemaphoreCreateBinary( xSemaphore ) \ 129 | { \ 130 | ( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \ 131 | if( ( xSemaphore ) != NULL ) \ 132 | { \ 133 | ( void ) xSemaphoreGive( ( xSemaphore ) ); \ 134 | } \ 135 | } 136 | #endif 137 | /** @endcond */ 138 | 139 | /** 140 | * Creates a new binary semaphore instance, and returns a handle by which the 141 | * new semaphore can be referenced. 142 | * 143 | * In many usage scenarios it is faster and more memory efficient to use a 144 | * direct to task notification in place of a binary semaphore! 145 | * http://www.freertos.org/RTOS-task-notifications.html 146 | * 147 | * Internally, within the FreeRTOS implementation, binary semaphores use a block 148 | * of memory, in which the semaphore structure is stored. If a binary semaphore 149 | * is created using xSemaphoreCreateBinary() then the required memory is 150 | * automatically dynamically allocated inside the xSemaphoreCreateBinary() 151 | * function. (see http://www.freertos.org/a00111.html). If a binary semaphore 152 | * is created using xSemaphoreCreateBinaryStatic() then the application writer 153 | * must provide the memory. xSemaphoreCreateBinaryStatic() therefore allows a 154 | * binary semaphore to be created without using any dynamic memory allocation. 155 | * 156 | * The old vSemaphoreCreateBinary() macro is now deprecated in favour of this 157 | * xSemaphoreCreateBinary() function. Note that binary semaphores created using 158 | * the vSemaphoreCreateBinary() macro are created in a state such that the 159 | * first call to 'take' the semaphore would pass, whereas binary semaphores 160 | * created using xSemaphoreCreateBinary() are created in a state such that the 161 | * the semaphore must first be 'given' before it can be 'taken'. 162 | * 163 | * Function that creates a semaphore by using the existing queue mechanism. 164 | * The queue length is 1 as this is a binary semaphore. The data size is 0 165 | * as nothing is actually stored - all that is important is whether the queue is 166 | * empty or full (the binary semaphore is available or not). 167 | * 168 | * This type of semaphore can be used for pure synchronisation between tasks or 169 | * between an interrupt and a task. The semaphore need not be given back once 170 | * obtained, so one task/interrupt can continuously 'give' the semaphore while 171 | * another continuously 'takes' the semaphore. For this reason this type of 172 | * semaphore does not use a priority inheritance mechanism. For an alternative 173 | * that does use priority inheritance see xSemaphoreCreateMutex(). 174 | * 175 | * @return Handle to the created semaphore. 176 | * 177 | * Example usage: 178 | * @code{c} 179 | * SemaphoreHandle_t xSemaphore = NULL; 180 | * 181 | * void vATask( void * pvParameters ) 182 | * { 183 | * // Semaphore cannot be used before a call to vSemaphoreCreateBinary (). 184 | * // This is a macro so pass the variable in directly. 185 | * xSemaphore = xSemaphoreCreateBinary(); 186 | * 187 | * if( xSemaphore != NULL ) 188 | * { 189 | * // The semaphore was created successfully. 190 | * // The semaphore can now be used. 191 | * } 192 | * } 193 | * @endcode 194 | * \ingroup Semaphores 195 | */ 196 | #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) 197 | #define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ) 198 | #endif 199 | 200 | /** 201 | * Creates a new binary semaphore instance, and returns a handle by which the 202 | * new semaphore can be referenced. 203 | * 204 | * NOTE: In many usage scenarios it is faster and more memory efficient to use a 205 | * direct to task notification in place of a binary semaphore! 206 | * http://www.freertos.org/RTOS-task-notifications.html 207 | * 208 | * Internally, within the FreeRTOS implementation, binary semaphores use a block 209 | * of memory, in which the semaphore structure is stored. If a binary semaphore 210 | * is created using xSemaphoreCreateBinary() then the required memory is 211 | * automatically dynamically allocated inside the xSemaphoreCreateBinary() 212 | * function. (see http://www.freertos.org/a00111.html). If a binary semaphore 213 | * is created using xSemaphoreCreateBinaryStatic() then the application writer 214 | * must provide the memory. xSemaphoreCreateBinaryStatic() therefore allows a 215 | * binary semaphore to be created without using any dynamic memory allocation. 216 | * 217 | * This type of semaphore can be used for pure synchronisation between tasks or 218 | * between an interrupt and a task. The semaphore need not be given back once 219 | * obtained, so one task/interrupt can continuously 'give' the semaphore while 220 | * another continuously 'takes' the semaphore. For this reason this type of 221 | * semaphore does not use a priority inheritance mechanism. For an alternative 222 | * that does use priority inheritance see xSemaphoreCreateMutex(). 223 | * 224 | * @param pxStaticSemaphore Must point to a variable of type StaticSemaphore_t, 225 | * which will then be used to hold the semaphore's data structure, removing the 226 | * need for the memory to be allocated dynamically. 227 | * 228 | * @return If the semaphore is created then a handle to the created semaphore is 229 | * returned. If pxSemaphoreBuffer is NULL then NULL is returned. 230 | * 231 | * Example usage: 232 | * @code{c} 233 | * SemaphoreHandle_t xSemaphore = NULL; 234 | * StaticSemaphore_t xSemaphoreBuffer; 235 | * 236 | * void vATask( void * pvParameters ) 237 | * { 238 | * // Semaphore cannot be used before a call to xSemaphoreCreateBinary(). 239 | * // The semaphore's data structures will be placed in the xSemaphoreBuffer 240 | * // variable, the address of which is passed into the function. The 241 | * // function's parameter is not NULL, so the function will not attempt any 242 | * // dynamic memory allocation, and therefore the function will not return 243 | * // return NULL. 244 | * xSemaphore = xSemaphoreCreateBinary( &xSemaphoreBuffer ); 245 | * 246 | * // Rest of task code goes here. 247 | * } 248 | * @endcode 249 | * \ingroup Semaphores 250 | */ 251 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 252 | #define xSemaphoreCreateBinaryStatic( pxStaticSemaphore ) xQueueGenericCreateStatic( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticSemaphore, queueQUEUE_TYPE_BINARY_SEMAPHORE ) 253 | #endif /* configSUPPORT_STATIC_ALLOCATION */ 254 | 255 | /** 256 | * Macro to obtain a semaphore. The semaphore must have previously been 257 | * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or 258 | * xSemaphoreCreateCounting(). 259 | * 260 | * @param xSemaphore A handle to the semaphore being taken - obtained when 261 | * the semaphore was created. 262 | * 263 | * @param xBlockTime The time in ticks to wait for the semaphore to become 264 | * available. The macro portTICK_PERIOD_MS can be used to convert this to a 265 | * real time. A block time of zero can be used to poll the semaphore. A block 266 | * time of portMAX_DELAY can be used to block indefinitely (provided 267 | * INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h). 268 | * 269 | * @return pdTRUE if the semaphore was obtained. pdFALSE 270 | * if xBlockTime expired without the semaphore becoming available. 271 | * 272 | * Example usage: 273 | * @code{c} 274 | * SemaphoreHandle_t xSemaphore = NULL; 275 | * 276 | * // A task that creates a semaphore. 277 | * void vATask( void * pvParameters ) 278 | * { 279 | * // Create the semaphore to guard a shared resource. 280 | * vSemaphoreCreateBinary( xSemaphore ); 281 | * } 282 | * 283 | * // A task that uses the semaphore. 284 | * void vAnotherTask( void * pvParameters ) 285 | * { 286 | * // ... Do other things. 287 | * 288 | * if( xSemaphore != NULL ) 289 | * { 290 | * // See if we can obtain the semaphore. If the semaphore is not available 291 | * // wait 10 ticks to see if it becomes free. 292 | * if( xSemaphoreTake( xSemaphore, ( TickType_t ) 10 ) == pdTRUE ) 293 | * { 294 | * // We were able to obtain the semaphore and can now access the 295 | * // shared resource. 296 | * 297 | * // ... 298 | * 299 | * // We have finished accessing the shared resource. Release the 300 | * // semaphore. 301 | * xSemaphoreGive( xSemaphore ); 302 | * } 303 | * else 304 | * { 305 | * // We could not obtain the semaphore and can therefore not access 306 | * // the shared resource safely. 307 | * } 308 | * } 309 | * } 310 | * @endcode 311 | * \ingroup Semaphores 312 | */ 313 | #define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE ) 314 | 315 | /** 316 | * Macro to recursively obtain, or 'take', a mutex type semaphore. 317 | * The mutex must have previously been created using a call to 318 | * xSemaphoreCreateRecursiveMutex(); 319 | * 320 | * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this 321 | * macro to be available. 322 | * 323 | * This macro must not be used on mutexes created using xSemaphoreCreateMutex(). 324 | * 325 | * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex 326 | * doesn't become available again until the owner has called 327 | * xSemaphoreGiveRecursive() for each successful 'take' request. For example, 328 | * if a task successfully 'takes' the same mutex 5 times then the mutex will 329 | * not be available to any other task until it has also 'given' the mutex back 330 | * exactly five times. 331 | * 332 | * @param xMutex A handle to the mutex being obtained. This is the 333 | * handle returned by xSemaphoreCreateRecursiveMutex(); 334 | * 335 | * @param xBlockTime The time in ticks to wait for the semaphore to become 336 | * available. The macro portTICK_PERIOD_MS can be used to convert this to a 337 | * real time. A block time of zero can be used to poll the semaphore. If 338 | * the task already owns the semaphore then xSemaphoreTakeRecursive() will 339 | * return immediately no matter what the value of xBlockTime. 340 | * 341 | * @return pdTRUE if the semaphore was obtained. pdFALSE if xBlockTime 342 | * expired without the semaphore becoming available. 343 | * 344 | * Example usage: 345 | * @code{c} 346 | * SemaphoreHandle_t xMutex = NULL; 347 | * 348 | * // A task that creates a mutex. 349 | * void vATask( void * pvParameters ) 350 | * { 351 | * // Create the mutex to guard a shared resource. 352 | * xMutex = xSemaphoreCreateRecursiveMutex(); 353 | * } 354 | * 355 | * // A task that uses the mutex. 356 | * void vAnotherTask( void * pvParameters ) 357 | * { 358 | * // ... Do other things. 359 | * 360 | * if( xMutex != NULL ) 361 | * { 362 | * // See if we can obtain the mutex. If the mutex is not available 363 | * // wait 10 ticks to see if it becomes free. 364 | * if( xSemaphoreTakeRecursive( xSemaphore, ( TickType_t ) 10 ) == pdTRUE ) 365 | * { 366 | * // We were able to obtain the mutex and can now access the 367 | * // shared resource. 368 | * 369 | * // ... 370 | * // For some reason due to the nature of the code further calls to 371 | * // xSemaphoreTakeRecursive() are made on the same mutex. In real 372 | * // code these would not be just sequential calls as this would make 373 | * // no sense. Instead the calls are likely to be buried inside 374 | * // a more complex call structure. 375 | * xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ); 376 | * xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ); 377 | * 378 | * // The mutex has now been 'taken' three times, so will not be 379 | * // available to another task until it has also been given back 380 | * // three times. Again it is unlikely that real code would have 381 | * // these calls sequentially, but instead buried in a more complex 382 | * // call structure. This is just for illustrative purposes. 383 | * xSemaphoreGiveRecursive( xMutex ); 384 | * xSemaphoreGiveRecursive( xMutex ); 385 | * xSemaphoreGiveRecursive( xMutex ); 386 | * 387 | * // Now the mutex can be taken by other tasks. 388 | * } 389 | * else 390 | * { 391 | * // We could not obtain the mutex and can therefore not access 392 | * // the shared resource safely. 393 | * } 394 | * } 395 | * } 396 | * @endcode 397 | * \ingroup Semaphores 398 | */ 399 | #define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) ) 400 | 401 | /** @cond */ 402 | /* 403 | * xSemaphoreAltTake() is an alternative version of xSemaphoreTake(). 404 | * 405 | * The source code that implements the alternative (Alt) API is much 406 | * simpler because it executes everything from within a critical section. 407 | * This is the approach taken by many other RTOSes, but FreeRTOS.org has the 408 | * preferred fully featured API too. The fully featured API has more 409 | * complex code that takes longer to execute, but makes much less use of 410 | * critical sections. Therefore the alternative API sacrifices interrupt 411 | * responsiveness to gain execution speed, whereas the fully featured API 412 | * sacrifices execution speed to ensure better interrupt responsiveness. 413 | */ 414 | #define xSemaphoreAltTake( xSemaphore, xBlockTime ) xQueueAltGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE ) 415 | /** @endcond */ 416 | 417 | /** 418 | * Macro to release a semaphore. The semaphore must have previously been 419 | * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or 420 | * xSemaphoreCreateCounting(). and obtained using sSemaphoreTake(). 421 | * 422 | * This macro must not be used from an ISR. See xSemaphoreGiveFromISR () for 423 | * an alternative which can be used from an ISR. 424 | * 425 | * This macro must also not be used on semaphores created using 426 | * xSemaphoreCreateRecursiveMutex(). 427 | * 428 | * @param xSemaphore A handle to the semaphore being released. This is the 429 | * handle returned when the semaphore was created. 430 | * 431 | * @return pdTRUE if the semaphore was released. pdFALSE if an error occurred. 432 | * Semaphores are implemented using queues. An error can occur if there is 433 | * no space on the queue to post a message - indicating that the 434 | * semaphore was not first obtained correctly. 435 | * 436 | * Example usage: 437 | * @code{c} 438 | * SemaphoreHandle_t xSemaphore = NULL; 439 | * 440 | * void vATask( void * pvParameters ) 441 | * { 442 | * // Create the semaphore to guard a shared resource. 443 | * vSemaphoreCreateBinary( xSemaphore ); 444 | * 445 | * if( xSemaphore != NULL ) 446 | * { 447 | * if( xSemaphoreGive( xSemaphore ) != pdTRUE ) 448 | * { 449 | * // We would expect this call to fail because we cannot give 450 | * // a semaphore without first "taking" it! 451 | * } 452 | * 453 | * // Obtain the semaphore - don't block if the semaphore is not 454 | * // immediately available. 455 | * if( xSemaphoreTake( xSemaphore, ( TickType_t ) 0 ) ) 456 | * { 457 | * // We now have the semaphore and can access the shared resource. 458 | * 459 | * // ... 460 | * 461 | * // We have finished accessing the shared resource so can free the 462 | * // semaphore. 463 | * if( xSemaphoreGive( xSemaphore ) != pdTRUE ) 464 | * { 465 | * // We would not expect this call to fail because we must have 466 | * // obtained the semaphore to get here. 467 | * } 468 | * } 469 | * } 470 | * } 471 | * @endcode 472 | * \ingroup Semaphores 473 | */ 474 | #define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK ) 475 | 476 | /** 477 | * Macro to recursively release, or 'give', a mutex type semaphore. 478 | * The mutex must have previously been created using a call to 479 | * xSemaphoreCreateRecursiveMutex(); 480 | * 481 | * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this 482 | * macro to be available. 483 | * 484 | * This macro must not be used on mutexes created using xSemaphoreCreateMutex(). 485 | * 486 | * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex 487 | * doesn't become available again until the owner has called 488 | * xSemaphoreGiveRecursive() for each successful 'take' request. For example, 489 | * if a task successfully 'takes' the same mutex 5 times then the mutex will 490 | * not be available to any other task until it has also 'given' the mutex back 491 | * exactly five times. 492 | * 493 | * @param xMutex A handle to the mutex being released, or 'given'. This is the 494 | * handle returned by xSemaphoreCreateMutex(); 495 | * 496 | * @return pdTRUE if the semaphore was given. 497 | * 498 | * Example usage: 499 | * @code{c} 500 | * SemaphoreHandle_t xMutex = NULL; 501 | * 502 | * // A task that creates a mutex. 503 | * void vATask( void * pvParameters ) 504 | * { 505 | * // Create the mutex to guard a shared resource. 506 | * xMutex = xSemaphoreCreateRecursiveMutex(); 507 | * } 508 | * 509 | * // A task that uses the mutex. 510 | * void vAnotherTask( void * pvParameters ) 511 | * { 512 | * // ... Do other things. 513 | * 514 | * if( xMutex != NULL ) 515 | * { 516 | * // See if we can obtain the mutex. If the mutex is not available 517 | * // wait 10 ticks to see if it becomes free. 518 | * if( xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ) == pdTRUE ) 519 | * { 520 | * // We were able to obtain the mutex and can now access the 521 | * // shared resource. 522 | * 523 | * // ... 524 | * // For some reason due to the nature of the code further calls to 525 | * // xSemaphoreTakeRecursive() are made on the same mutex. In real 526 | * // code these would not be just sequential calls as this would make 527 | * // no sense. Instead the calls are likely to be buried inside 528 | * // a more complex call structure. 529 | * xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ); 530 | * xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ); 531 | * 532 | * // The mutex has now been 'taken' three times, so will not be 533 | * // available to another task until it has also been given back 534 | * // three times. Again it is unlikely that real code would have 535 | * // these calls sequentially, it would be more likely that the calls 536 | * // to xSemaphoreGiveRecursive() would be called as a call stack 537 | * // unwound. This is just for demonstrative purposes. 538 | * xSemaphoreGiveRecursive( xMutex ); 539 | * xSemaphoreGiveRecursive( xMutex ); 540 | * xSemaphoreGiveRecursive( xMutex ); 541 | * 542 | * // Now the mutex can be taken by other tasks. 543 | * } 544 | * else 545 | * { 546 | * // We could not obtain the mutex and can therefore not access 547 | * // the shared resource safely. 548 | * } 549 | * } 550 | * } 551 | * @endcode 552 | * \ingroup Semaphores 553 | */ 554 | #define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) ) 555 | 556 | /** @cond */ 557 | /* 558 | * xSemaphoreAltGive() is an alternative version of xSemaphoreGive(). 559 | * 560 | * The source code that implements the alternative (Alt) API is much 561 | * simpler because it executes everything from within a critical section. 562 | * This is the approach taken by many other RTOSes, but FreeRTOS.org has the 563 | * preferred fully featured API too. The fully featured API has more 564 | * complex code that takes longer to execute, but makes much less use of 565 | * critical sections. Therefore the alternative API sacrifices interrupt 566 | * responsiveness to gain execution speed, whereas the fully featured API 567 | * sacrifices execution speed to ensure better interrupt responsiveness. 568 | */ 569 | #define xSemaphoreAltGive( xSemaphore ) xQueueAltGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK ) 570 | 571 | /** @endcond */ 572 | 573 | /** 574 | * Macro to release a semaphore. The semaphore must have previously been 575 | * created with a call to vSemaphoreCreateBinary() or xSemaphoreCreateCounting(). 576 | * 577 | * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) 578 | * must not be used with this macro. 579 | * 580 | * This macro can be used from an ISR. 581 | * 582 | * @param xSemaphore A handle to the semaphore being released. This is the 583 | * handle returned when the semaphore was created. 584 | * 585 | * @param[out] pxHigherPriorityTaskWoken xSemaphoreGiveFromISR() will set 586 | * *pxHigherPriorityTaskWoken to pdTRUE if giving the semaphore caused a task 587 | * to unblock, and the unblocked task has a priority higher than the currently 588 | * running task. If xSemaphoreGiveFromISR() sets this value to pdTRUE then 589 | * a context switch should be requested before the interrupt is exited. 590 | * 591 | * @return pdTRUE if the semaphore was successfully given, otherwise errQUEUE_FULL. 592 | * 593 | * Example usage: 594 | * @code{c} 595 | * \#define LONG_TIME 0xffff 596 | * \#define TICKS_TO_WAIT 10 597 | * SemaphoreHandle_t xSemaphore = NULL; 598 | * 599 | * // Repetitive task. 600 | * void vATask( void * pvParameters ) 601 | * { 602 | * for( ;; ) 603 | * { 604 | * // We want this task to run every 10 ticks of a timer. The semaphore 605 | * // was created before this task was started. 606 | * 607 | * // Block waiting for the semaphore to become available. 608 | * if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE ) 609 | * { 610 | * // It is time to execute. 611 | * 612 | * // ... 613 | * 614 | * // We have finished our task. Return to the top of the loop where 615 | * // we will block on the semaphore until it is time to execute 616 | * // again. Note when using the semaphore for synchronisation with an 617 | * // ISR in this manner there is no need to 'give' the semaphore back. 618 | * } 619 | * } 620 | * } 621 | * 622 | * // Timer ISR 623 | * void vTimerISR( void * pvParameters ) 624 | * { 625 | * static uint8_t ucLocalTickCount = 0; 626 | * static BaseType_t xHigherPriorityTaskWoken; 627 | * 628 | * // A timer tick has occurred. 629 | * 630 | * // ... Do other time functions. 631 | * 632 | * // Is it time for vATask () to run? 633 | * xHigherPriorityTaskWoken = pdFALSE; 634 | * ucLocalTickCount++; 635 | * if( ucLocalTickCount >= TICKS_TO_WAIT ) 636 | * { 637 | * // Unblock the task by releasing the semaphore. 638 | * xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken ); 639 | * 640 | * // Reset the count so we release the semaphore again in 10 ticks time. 641 | * ucLocalTickCount = 0; 642 | * } 643 | * 644 | * if( xHigherPriorityTaskWoken != pdFALSE ) 645 | * { 646 | * // We can force a context switch here. Context switching from an 647 | * // ISR uses port specific syntax. Check the demo task for your port 648 | * // to find the syntax required. 649 | * } 650 | * } 651 | * @endcode 652 | * \ingroup Semaphores 653 | */ 654 | #define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) ) 655 | 656 | /** 657 | * Macro to take a semaphore from an ISR. The semaphore must have 658 | * previously been created with a call to vSemaphoreCreateBinary() or 659 | * xSemaphoreCreateCounting(). 660 | * 661 | * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) 662 | * must not be used with this macro. 663 | * 664 | * This macro can be used from an ISR, however taking a semaphore from an ISR 665 | * is not a common operation. It is likely to only be useful when taking a 666 | * counting semaphore when an interrupt is obtaining an object from a resource 667 | * pool (when the semaphore count indicates the number of resources available). 668 | * 669 | * @param xSemaphore A handle to the semaphore being taken. This is the 670 | * handle returned when the semaphore was created. 671 | * 672 | * @param[out] pxHigherPriorityTaskWoken xSemaphoreTakeFromISR() will set 673 | * *pxHigherPriorityTaskWoken to pdTRUE if taking the semaphore caused a task 674 | * to unblock, and the unblocked task has a priority higher than the currently 675 | * running task. If xSemaphoreTakeFromISR() sets this value to pdTRUE then 676 | * a context switch should be requested before the interrupt is exited. 677 | * 678 | * @return pdTRUE if the semaphore was successfully taken, otherwise 679 | * pdFALSE 680 | */ 681 | #define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ) ) 682 | 683 | /** 684 | * Macro that implements a mutex semaphore by using the existing queue 685 | * mechanism. 686 | * 687 | * Internally, within the FreeRTOS implementation, mutex semaphores use a block 688 | * of memory, in which the mutex structure is stored. If a mutex is created 689 | * using xSemaphoreCreateMutex() then the required memory is automatically 690 | * dynamically allocated inside the xSemaphoreCreateMutex() function. (see 691 | * http://www.freertos.org/a00111.html). If a mutex is created using 692 | * xSemaphoreCreateMutexStatic() then the application writer must provided the 693 | * memory. xSemaphoreCreateMutexStatic() therefore allows a mutex to be created 694 | * without using any dynamic memory allocation. 695 | * 696 | * Mutexes created using this function can be accessed using the xSemaphoreTake() 697 | * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and 698 | * xSemaphoreGiveRecursive() macros must not be used. 699 | * 700 | * This type of semaphore uses a priority inheritance mechanism so a task 701 | * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the 702 | * semaphore it is no longer required. 703 | * 704 | * Mutex type semaphores cannot be used from within interrupt service routines. 705 | * 706 | * See vSemaphoreCreateBinary() for an alternative implementation that can be 707 | * used for pure synchronisation (where one task or interrupt always 'gives' the 708 | * semaphore and another always 'takes' the semaphore) and from within interrupt 709 | * service routines. 710 | * 711 | * @return If the mutex was successfully created then a handle to the created 712 | * semaphore is returned. If there was not enough heap to allocate the mutex 713 | * data structures then NULL is returned. 714 | * 715 | * Example usage: 716 | * @code{c} 717 | * SemaphoreHandle_t xSemaphore; 718 | * 719 | * void vATask( void * pvParameters ) 720 | * { 721 | * // Semaphore cannot be used before a call to xSemaphoreCreateMutex(). 722 | * // This is a macro so pass the variable in directly. 723 | * xSemaphore = xSemaphoreCreateMutex(); 724 | * 725 | * if( xSemaphore != NULL ) 726 | * { 727 | * // The semaphore was created successfully. 728 | * // The semaphore can now be used. 729 | * } 730 | * } 731 | * @endcode 732 | * \ingroup Semaphores 733 | */ 734 | #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) 735 | #define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX ) 736 | #endif 737 | 738 | /** 739 | * Creates a new mutex type semaphore instance, and returns a handle by which 740 | * the new mutex can be referenced. 741 | * 742 | * Internally, within the FreeRTOS implementation, mutex semaphores use a block 743 | * of memory, in which the mutex structure is stored. If a mutex is created 744 | * using xSemaphoreCreateMutex() then the required memory is automatically 745 | * dynamically allocated inside the xSemaphoreCreateMutex() function. (see 746 | * http://www.freertos.org/a00111.html). If a mutex is created using 747 | * xSemaphoreCreateMutexStatic() then the application writer must provided the 748 | * memory. xSemaphoreCreateMutexStatic() therefore allows a mutex to be created 749 | * without using any dynamic memory allocation. 750 | * 751 | * Mutexes created using this function can be accessed using the xSemaphoreTake() 752 | * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and 753 | * xSemaphoreGiveRecursive() macros must not be used. 754 | * 755 | * This type of semaphore uses a priority inheritance mechanism so a task 756 | * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the 757 | * semaphore it is no longer required. 758 | * 759 | * Mutex type semaphores cannot be used from within interrupt service routines. 760 | * 761 | * See xSemaphoreCreateBinary() for an alternative implementation that can be 762 | * used for pure synchronisation (where one task or interrupt always 'gives' the 763 | * semaphore and another always 'takes' the semaphore) and from within interrupt 764 | * service routines. 765 | * 766 | * @param pxMutexBuffer Must point to a variable of type StaticSemaphore_t, 767 | * which will be used to hold the mutex's data structure, removing the need for 768 | * the memory to be allocated dynamically. 769 | * 770 | * @return If the mutex was successfully created then a handle to the created 771 | * mutex is returned. If pxMutexBuffer was NULL then NULL is returned. 772 | * 773 | * Example usage: 774 | * @code 775 | * SemaphoreHandle_t xSemaphore; 776 | * StaticSemaphore_t xMutexBuffer; 777 | * 778 | * void vATask( void * pvParameters ) 779 | * { 780 | * // A mutex cannot be used before it has been created. xMutexBuffer is 781 | * // into xSemaphoreCreateMutexStatic() so no dynamic memory allocation is 782 | * // attempted. 783 | * xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer ); 784 | * 785 | * // As no dynamic memory allocation was performed, xSemaphore cannot be NULL, 786 | * // so there is no need to check it. 787 | * } 788 | * @endcode 789 | * \ingroup Semaphores 790 | */ 791 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 792 | #define xSemaphoreCreateMutexStatic( pxMutexBuffer ) xQueueCreateMutexStatic( queueQUEUE_TYPE_MUTEX, ( pxMutexBuffer ) ) 793 | #endif /* configSUPPORT_STATIC_ALLOCATION */ 794 | 795 | 796 | /** 797 | * Creates a new recursive mutex type semaphore instance, and returns a handle 798 | * by which the new recursive mutex can be referenced. 799 | * 800 | * Internally, within the FreeRTOS implementation, recursive mutexs use a block 801 | * of memory, in which the mutex structure is stored. If a recursive mutex is 802 | * created using xSemaphoreCreateRecursiveMutex() then the required memory is 803 | * automatically dynamically allocated inside the 804 | * xSemaphoreCreateRecursiveMutex() function. (see 805 | * http://www.freertos.org/a00111.html). If a recursive mutex is created using 806 | * xSemaphoreCreateRecursiveMutexStatic() then the application writer must 807 | * provide the memory that will get used by the mutex. 808 | * xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to 809 | * be created without using any dynamic memory allocation. 810 | * 811 | * Mutexes created using this macro can be accessed using the 812 | * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The 813 | * xSemaphoreTake() and xSemaphoreGive() macros must not be used. 814 | * 815 | * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex 816 | * doesn't become available again until the owner has called 817 | * xSemaphoreGiveRecursive() for each successful 'take' request. For example, 818 | * if a task successfully 'takes' the same mutex 5 times then the mutex will 819 | * not be available to any other task until it has also 'given' the mutex back 820 | * exactly five times. 821 | * 822 | * This type of semaphore uses a priority inheritance mechanism so a task 823 | * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the 824 | * semaphore it is no longer required. 825 | * 826 | * Mutex type semaphores cannot be used from within interrupt service routines. 827 | * 828 | * See vSemaphoreCreateBinary() for an alternative implementation that can be 829 | * used for pure synchronisation (where one task or interrupt always 'gives' the 830 | * semaphore and another always 'takes' the semaphore) and from within interrupt 831 | * service routines. 832 | * 833 | * @return xSemaphore Handle to the created mutex semaphore. Should be of type 834 | * SemaphoreHandle_t. 835 | * 836 | * Example usage: 837 | * @code{c} 838 | * SemaphoreHandle_t xSemaphore; 839 | * 840 | * void vATask( void * pvParameters ) 841 | * { 842 | * // Semaphore cannot be used before a call to xSemaphoreCreateMutex(). 843 | * // This is a macro so pass the variable in directly. 844 | * xSemaphore = xSemaphoreCreateRecursiveMutex(); 845 | * 846 | * if( xSemaphore != NULL ) 847 | * { 848 | * // The semaphore was created successfully. 849 | * // The semaphore can now be used. 850 | * } 851 | * } 852 | * @endcode 853 | * \ingroup Semaphores 854 | */ 855 | #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) ) 856 | #define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX ) 857 | #endif 858 | 859 | /** 860 | * Creates a new recursive mutex type semaphore instance, and returns a handle 861 | * by which the new recursive mutex can be referenced. 862 | * 863 | * Internally, within the FreeRTOS implementation, recursive mutexs use a block 864 | * of memory, in which the mutex structure is stored. If a recursive mutex is 865 | * created using xSemaphoreCreateRecursiveMutex() then the required memory is 866 | * automatically dynamically allocated inside the 867 | * xSemaphoreCreateRecursiveMutex() function. (see 868 | * http://www.freertos.org/a00111.html). If a recursive mutex is created using 869 | * xSemaphoreCreateRecursiveMutexStatic() then the application writer must 870 | * provide the memory that will get used by the mutex. 871 | * xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to 872 | * be created without using any dynamic memory allocation. 873 | * 874 | * Mutexes created using this macro can be accessed using the 875 | * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The 876 | * xSemaphoreTake() and xSemaphoreGive() macros must not be used. 877 | * 878 | * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex 879 | * doesn't become available again until the owner has called 880 | * xSemaphoreGiveRecursive() for each successful 'take' request. For example, 881 | * if a task successfully 'takes' the same mutex 5 times then the mutex will 882 | * not be available to any other task until it has also 'given' the mutex back 883 | * exactly five times. 884 | * 885 | * This type of semaphore uses a priority inheritance mechanism so a task 886 | * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the 887 | * semaphore it is no longer required. 888 | * 889 | * Mutex type semaphores cannot be used from within interrupt service routines. 890 | * 891 | * See xSemaphoreCreateBinary() for an alternative implementation that can be 892 | * used for pure synchronisation (where one task or interrupt always 'gives' the 893 | * semaphore and another always 'takes' the semaphore) and from within interrupt 894 | * service routines. 895 | * 896 | * @param pxStaticSemaphore Must point to a variable of type StaticSemaphore_t, 897 | * which will then be used to hold the recursive mutex's data structure, 898 | * removing the need for the memory to be allocated dynamically. 899 | * 900 | * @return If the recursive mutex was successfully created then a handle to the 901 | * created recursive mutex is returned. If pxMutexBuffer was NULL then NULL is 902 | * returned. 903 | * 904 | * Example usage: 905 | * @code 906 | * SemaphoreHandle_t xSemaphore; 907 | * StaticSemaphore_t xMutexBuffer; 908 | * 909 | * void vATask( void * pvParameters ) 910 | * { 911 | * // A recursive semaphore cannot be used before it is created. Here a 912 | * // recursive mutex is created using xSemaphoreCreateRecursiveMutexStatic(). 913 | * // The address of xMutexBuffer is passed into the function, and will hold 914 | * // the mutexes data structures - so no dynamic memory allocation will be 915 | * // attempted. 916 | * xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xMutexBuffer ); 917 | * 918 | * // As no dynamic memory allocation was performed, xSemaphore cannot be NULL, 919 | * // so there is no need to check it. 920 | * } 921 | * @endcode 922 | * \ingroup Semaphores 923 | */ 924 | #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) ) 925 | #define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutexStatic( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore ) 926 | #endif /* configSUPPORT_STATIC_ALLOCATION */ 927 | 928 | /** 929 | * Creates a new counting semaphore instance, and returns a handle by which the 930 | * new counting semaphore can be referenced. 931 | * 932 | * In many usage scenarios it is faster and more memory efficient to use a 933 | * direct to task notification in place of a counting semaphore! 934 | * http://www.freertos.org/RTOS-task-notifications.html 935 | * 936 | * Internally, within the FreeRTOS implementation, counting semaphores use a 937 | * block of memory, in which the counting semaphore structure is stored. If a 938 | * counting semaphore is created using xSemaphoreCreateCounting() then the 939 | * required memory is automatically dynamically allocated inside the 940 | * xSemaphoreCreateCounting() function. (see 941 | * http://www.freertos.org/a00111.html). If a counting semaphore is created 942 | * using xSemaphoreCreateCountingStatic() then the application writer can 943 | * instead optionally provide the memory that will get used by the counting 944 | * semaphore. xSemaphoreCreateCountingStatic() therefore allows a counting 945 | * semaphore to be created without using any dynamic memory allocation. 946 | * 947 | * Counting semaphores are typically used for two things: 948 | * 949 | * 1) Counting events. 950 | * 951 | * In this usage scenario an event handler will 'give' a semaphore each time 952 | * an event occurs (incrementing the semaphore count value), and a handler 953 | * task will 'take' a semaphore each time it processes an event 954 | * (decrementing the semaphore count value). The count value is therefore 955 | * the difference between the number of events that have occurred and the 956 | * number that have been processed. In this case it is desirable for the 957 | * initial count value to be zero. 958 | * 959 | * 2) Resource management. 960 | * 961 | * In this usage scenario the count value indicates the number of resources 962 | * available. To obtain control of a resource a task must first obtain a 963 | * semaphore - decrementing the semaphore count value. When the count value 964 | * reaches zero there are no free resources. When a task finishes with the 965 | * resource it 'gives' the semaphore back - incrementing the semaphore count 966 | * value. In this case it is desirable for the initial count value to be 967 | * equal to the maximum count value, indicating that all resources are free. 968 | * 969 | * @param uxMaxCount The maximum count value that can be reached. When the 970 | * semaphore reaches this value it can no longer be 'given'. 971 | * 972 | * @param uxInitialCount The count value assigned to the semaphore when it is 973 | * created. 974 | * 975 | * @return Handle to the created semaphore. Null if the semaphore could not be 976 | * created. 977 | * 978 | * Example usage: 979 | * @code{c} 980 | * SemaphoreHandle_t xSemaphore; 981 | * 982 | * void vATask( void * pvParameters ) 983 | * { 984 | * SemaphoreHandle_t xSemaphore = NULL; 985 | * 986 | * // Semaphore cannot be used before a call to xSemaphoreCreateCounting(). 987 | * // The max value to which the semaphore can count should be 10, and the 988 | * // initial value assigned to the count should be 0. 989 | * xSemaphore = xSemaphoreCreateCounting( 10, 0 ); 990 | * 991 | * if( xSemaphore != NULL ) 992 | * { 993 | * // The semaphore was created successfully. 994 | * // The semaphore can now be used. 995 | * } 996 | * } 997 | * @endcode 998 | * \ingroup Semaphores 999 | */ 1000 | #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) 1001 | #define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) ) 1002 | #endif 1003 | 1004 | /** 1005 | * Creates a new counting semaphore instance, and returns a handle by which the 1006 | * new counting semaphore can be referenced. 1007 | * 1008 | * In many usage scenarios it is faster and more memory efficient to use a 1009 | * direct to task notification in place of a counting semaphore! 1010 | * http://www.freertos.org/RTOS-task-notifications.html 1011 | * 1012 | * Internally, within the FreeRTOS implementation, counting semaphores use a 1013 | * block of memory, in which the counting semaphore structure is stored. If a 1014 | * counting semaphore is created using xSemaphoreCreateCounting() then the 1015 | * required memory is automatically dynamically allocated inside the 1016 | * xSemaphoreCreateCounting() function. (see 1017 | * http://www.freertos.org/a00111.html). If a counting semaphore is created 1018 | * using xSemaphoreCreateCountingStatic() then the application writer must 1019 | * provide the memory. xSemaphoreCreateCountingStatic() therefore allows a 1020 | * counting semaphore to be created without using any dynamic memory allocation. 1021 | * 1022 | * Counting semaphores are typically used for two things: 1023 | * 1024 | * 1) Counting events. 1025 | * 1026 | * In this usage scenario an event handler will 'give' a semaphore each time 1027 | * an event occurs (incrementing the semaphore count value), and a handler 1028 | * task will 'take' a semaphore each time it processes an event 1029 | * (decrementing the semaphore count value). The count value is therefore 1030 | * the difference between the number of events that have occurred and the 1031 | * number that have been processed. In this case it is desirable for the 1032 | * initial count value to be zero. 1033 | * 1034 | * 2) Resource management. 1035 | * 1036 | * In this usage scenario the count value indicates the number of resources 1037 | * available. To obtain control of a resource a task must first obtain a 1038 | * semaphore - decrementing the semaphore count value. When the count value 1039 | * reaches zero there are no free resources. When a task finishes with the 1040 | * resource it 'gives' the semaphore back - incrementing the semaphore count 1041 | * value. In this case it is desirable for the initial count value to be 1042 | * equal to the maximum count value, indicating that all resources are free. 1043 | * 1044 | * @param uxMaxCount The maximum count value that can be reached. When the 1045 | * semaphore reaches this value it can no longer be 'given'. 1046 | * 1047 | * @param uxInitialCount The count value assigned to the semaphore when it is 1048 | * created. 1049 | * 1050 | * @param pxSemaphoreBuffer Must point to a variable of type StaticSemaphore_t, 1051 | * which will then be used to hold the semaphore's data structure, removing the 1052 | * need for the memory to be allocated dynamically. 1053 | * 1054 | * @return If the counting semaphore was successfully created then a handle to 1055 | * the created counting semaphore is returned. If pxSemaphoreBuffer was NULL 1056 | * then NULL is returned. 1057 | * 1058 | * Example usage: 1059 | * @code{c} 1060 | * SemaphoreHandle_t xSemaphore; 1061 | * StaticSemaphore_t xSemaphoreBuffer; 1062 | * 1063 | * void vATask( void * pvParameters ) 1064 | * { 1065 | * SemaphoreHandle_t xSemaphore = NULL; 1066 | * 1067 | * // Counting semaphore cannot be used before they have been created. Create 1068 | * // a counting semaphore using xSemaphoreCreateCountingStatic(). The max 1069 | * // value to which the semaphore can count is 10, and the initial value 1070 | * // assigned to the count will be 0. The address of xSemaphoreBuffer is 1071 | * // passed in and will be used to hold the semaphore structure, so no dynamic 1072 | * // memory allocation will be used. 1073 | * xSemaphore = xSemaphoreCreateCounting( 10, 0, &xSemaphoreBuffer ); 1074 | * 1075 | * // No memory allocation was attempted so xSemaphore cannot be NULL, so there 1076 | * // is no need to check its value. 1077 | * } 1078 | * @endcode 1079 | * \ingroup Semaphores 1080 | */ 1081 | #if( configSUPPORT_STATIC_ALLOCATION == 1 ) 1082 | #define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxSemaphoreBuffer ) xQueueCreateCountingSemaphoreStatic( ( uxMaxCount ), ( uxInitialCount ), ( pxSemaphoreBuffer ) ) 1083 | #endif /* configSUPPORT_STATIC_ALLOCATION */ 1084 | 1085 | /** 1086 | * Delete a semaphore. This function must be used with care. For example, 1087 | * do not delete a mutex type semaphore if the mutex is held by a task. 1088 | * 1089 | * @param xSemaphore A handle to the semaphore to be deleted. 1090 | * 1091 | * \ingroup Semaphores 1092 | */ 1093 | #define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) ) 1094 | 1095 | /** 1096 | * If xMutex is indeed a mutex type semaphore, return the current mutex holder. 1097 | * If xMutex is not a mutex type semaphore, or the mutex is available (not held 1098 | * by a task), return NULL. 1099 | * 1100 | * Note: This is a good way of determining if the calling task is the mutex 1101 | * holder, but not a good way of determining the identity of the mutex holder as 1102 | * the holder may change between the function exiting and the returned value 1103 | * being tested. 1104 | */ 1105 | #define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) ) 1106 | 1107 | /** 1108 | * If the semaphore is a counting semaphore then uxSemaphoreGetCount() returns 1109 | * its current count value. If the semaphore is a binary semaphore then 1110 | * uxSemaphoreGetCount() returns 1 if the semaphore is available, and 0 if the 1111 | * semaphore is not available. 1112 | * 1113 | */ 1114 | #define uxSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) ) 1115 | 1116 | #endif /* SEMAPHORE_H */ 1117 | 1118 | 1119 | -------------------------------------------------------------------------------- /private/sdmmc_cmd.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include 18 | #include "esp_err.h" 19 | #include "driver/sdmmc_types.h" 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | /** 26 | * Probe and initialize SD/MMC card using given host 27 | * 28 | * @note Only SD cards (SDSC and SDHC/SDXC) are supported now. 29 | * Support for MMC/eMMC cards will be added later. 30 | * 31 | * @param host pointer to structure defining host controller 32 | * @param out_card pointer to structure which will receive information 33 | * about the card when the function completes 34 | * @return 35 | * - ESP_OK on success 36 | * - One of the error codes from SDMMC host controller 37 | */ 38 | esp_err_t sdmmc_card_init(const sdmmc_host_t* host, 39 | sdmmc_card_t* out_card); 40 | 41 | /** 42 | * @brief Print information about the card to a stream 43 | * @param stream stream obtained using fopen or fdopen 44 | * @param card card information structure initialized using sdmmc_card_init 45 | */ 46 | void sdmmc_card_print_info(FILE* stream, const sdmmc_card_t* card); 47 | 48 | /** 49 | * Write given number of sectors to SD/MMC card 50 | * 51 | * @param card pointer to card information structure previously initialized 52 | * using sdmmc_card_init 53 | * @param src pointer to data buffer to read data from; data size must be 54 | * equal to sector_count * card->csd.sector_size 55 | * @param start_sector sector where to start writing 56 | * @param sector_count number of sectors to write 57 | * @return 58 | * - ESP_OK on success 59 | * - One of the error codes from SDMMC host controller 60 | */ 61 | esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src, 62 | size_t start_sector, size_t sector_count); 63 | 64 | /** 65 | * Write given number of sectors to SD/MMC card 66 | * 67 | * @param card pointer to card information structure previously initialized 68 | * using sdmmc_card_init 69 | * @param dst pointer to data buffer to write into; buffer size must be 70 | * at least sector_count * card->csd.sector_size 71 | * @param start_sector sector where to start reading 72 | * @param sector_count number of sectors to read 73 | * @return 74 | * - ESP_OK on success 75 | * - One of the error codes from SDMMC host controller 76 | */ 77 | esp_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst, 78 | size_t start_sector, size_t sector_count); 79 | 80 | /** 81 | * Read one byte from an SDIO card using IO_RW_DIRECT (CMD52) 82 | * 83 | * @param card pointer to card information structure previously initialized 84 | * using sdmmc_card_init 85 | * @param function IO function number 86 | * @param reg byte address within IO function 87 | * @param[out] out_byte output, receives the value read from the card 88 | * @return 89 | * - ESP_OK on success 90 | * - One of the error codes from SDMMC host controller 91 | */ 92 | esp_err_t sdmmc_io_read_byte(sdmmc_card_t* card, uint32_t function, 93 | uint32_t reg, uint8_t *out_byte); 94 | 95 | /** 96 | * Write one byte to an SDIO card using IO_RW_DIRECT (CMD52) 97 | * 98 | * @param card pointer to card information structure previously initialized 99 | * using sdmmc_card_init 100 | * @param function IO function number 101 | * @param reg byte address within IO function 102 | * @param in_byte value to be written 103 | * @param[out] out_byte if not NULL, receives new byte value read 104 | * from the card (read-after-write). 105 | * @return 106 | * - ESP_OK on success 107 | * - One of the error codes from SDMMC host controller 108 | */ 109 | esp_err_t sdmmc_io_write_byte(sdmmc_card_t* card, uint32_t function, 110 | uint32_t reg, uint8_t in_byte, uint8_t* out_byte); 111 | 112 | /** 113 | * Read multiple bytes from an SDIO card using IO_RW_EXTENDED (CMD53) 114 | * 115 | * This function performs read operation using CMD53 in byte mode. 116 | * For block mode, see sdmmc_io_read_blocks. 117 | * 118 | * @param card pointer to card information structure previously initialized 119 | * using sdmmc_card_init 120 | * @param function IO function number 121 | * @param addr byte address within IO function where reading starts 122 | * @param dst buffer which receives the data read from card 123 | * @param size number of bytes to read 124 | * @return 125 | * - ESP_OK on success 126 | * - ESP_ERR_INVALID_SIZE if size exceeds 512 bytes 127 | * - One of the error codes from SDMMC host controller 128 | */ 129 | esp_err_t sdmmc_io_read_bytes(sdmmc_card_t* card, uint32_t function, 130 | uint32_t addr, void* dst, size_t size); 131 | 132 | /** 133 | * Write multiple bytes to an SDIO card using IO_RW_EXTENDED (CMD53) 134 | * 135 | * This function performs write operation using CMD53 in byte mode. 136 | * For block mode, see sdmmc_io_write_blocks. 137 | * 138 | * @param card pointer to card information structure previously initialized 139 | * using sdmmc_card_init 140 | * @param function IO function number 141 | * @param addr byte address within IO function where writing starts 142 | * @param src data to be written 143 | * @param size number of bytes to write 144 | * @return 145 | * - ESP_OK on success 146 | * - ESP_ERR_INVALID_SIZE if size exceeds 512 bytes 147 | * - One of the error codes from SDMMC host controller 148 | */ 149 | esp_err_t sdmmc_io_write_bytes(sdmmc_card_t* card, uint32_t function, 150 | uint32_t addr, const void* src, size_t size); 151 | 152 | /** 153 | * Read blocks of data from an SDIO card using IO_RW_EXTENDED (CMD53) 154 | * 155 | * This function performs read operation using CMD53 in block mode. 156 | * For byte mode, see sdmmc_io_read_bytes. 157 | * 158 | * @param card pointer to card information structure previously initialized 159 | * using sdmmc_card_init 160 | * @param function IO function number 161 | * @param addr byte address within IO function where writing starts 162 | * @param dst buffer which receives the data read from card 163 | * @param size number of bytes to read, must be divisible by the card block 164 | * size. 165 | * @return 166 | * - ESP_OK on success 167 | * - ESP_ERR_INVALID_SIZE if size is not divisible by 512 bytes 168 | * - One of the error codes from SDMMC host controller 169 | */ 170 | esp_err_t sdmmc_io_read_blocks(sdmmc_card_t* card, uint32_t function, 171 | uint32_t addr, void* dst, size_t size); 172 | 173 | /** 174 | * Write blocks of data to an SDIO card using IO_RW_EXTENDED (CMD53) 175 | * 176 | * This function performs write operation using CMD53 in block mode. 177 | * For byte mode, see sdmmc_io_write_bytes. 178 | * 179 | * @param card pointer to card information structure previously initialized 180 | * using sdmmc_card_init 181 | * @param function IO function number 182 | * @param addr byte address within IO function where writing starts 183 | * @param src data to be written 184 | * @param size number of bytes to read, must be divisible by the card block 185 | * size. 186 | * @return 187 | * - ESP_OK on success 188 | * - ESP_ERR_INVALID_SIZE if size is not divisible by 512 bytes 189 | * - One of the error codes from SDMMC host controller 190 | */ 191 | esp_err_t sdmmc_io_write_blocks(sdmmc_card_t* card, uint32_t function, 192 | uint32_t addr, const void* src, size_t size); 193 | 194 | /** 195 | * Enable SDIO interrupt in the SDMMC host 196 | * 197 | * @param card pointer to card information structure previously initialized 198 | * using sdmmc_card_init 199 | * @return 200 | * - ESP_OK on success 201 | * - ESP_ERR_NOT_SUPPORTED if the host controller does not support 202 | * IO interrupts 203 | */ 204 | esp_err_t sdmmc_io_enable_int(sdmmc_card_t* card); 205 | 206 | /** 207 | * Block until an SDIO interrupt is received 208 | * 209 | * Slave uses D1 line to signal interrupt condition to the host. 210 | * This function can be used to wait for the interrupt. 211 | * 212 | * @param card pointer to card information structure previously initialized 213 | * using sdmmc_card_init 214 | * @param timeout_ticks time to wait for the interrupt, in RTOS ticks 215 | * @return 216 | * - ESP_OK if the interrupt is received 217 | * - ESP_ERR_NOT_SUPPORTED if the host controller does not support 218 | * IO interrupts 219 | * - ESP_ERR_TIMEOUT if the interrupt does not happen in timeout_ticks 220 | */ 221 | esp_err_t sdmmc_io_wait_int(sdmmc_card_t* card, TickType_t timeout_ticks); 222 | 223 | #ifdef __cplusplus 224 | } 225 | #endif 226 | -------------------------------------------------------------------------------- /private/sdmmc_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006 Uwe Stuehler 3 | * Adaptations to ESP-IDF Copyright (c) 2016 Espressif Systems (Shanghai) PTE LTD 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #ifndef _SDMMC_TYPES_H_ 19 | #define _SDMMC_TYPES_H_ 20 | 21 | #include 22 | #include 23 | #include "esp_err.h" 24 | #include "freertos/FreeRTOS.h" 25 | 26 | /** 27 | * Decoded values from SD card Card Specific Data register 28 | */ 29 | typedef struct { 30 | int csd_ver; /*!< CSD structure format */ 31 | int mmc_ver; /*!< MMC version (for CID format) */ 32 | int capacity; /*!< total number of sectors */ 33 | int sector_size; /*!< sector size in bytes */ 34 | int read_block_len; /*!< block length for reads */ 35 | int card_command_class; /*!< Card Command Class for SD */ 36 | int tr_speed; /*!< Max transfer speed */ 37 | } sdmmc_csd_t; 38 | 39 | /** 40 | * Decoded values from SD card Card IDentification register 41 | */ 42 | typedef struct { 43 | int mfg_id; /*!< manufacturer identification number */ 44 | int oem_id; /*!< OEM/product identification number */ 45 | char name[8]; /*!< product name (MMC v1 has the longest) */ 46 | int revision; /*!< product revision */ 47 | int serial; /*!< product serial number */ 48 | int date; /*!< manufacturing date */ 49 | } sdmmc_cid_t; 50 | 51 | /** 52 | * Decoded values from SD Configuration Register 53 | */ 54 | typedef struct { 55 | int sd_spec; /*!< SD Physical layer specification version, reported by card */ 56 | int bus_width; /*!< bus widths supported by card: BIT(0) — 1-bit bus, BIT(2) — 4-bit bus */ 57 | } sdmmc_scr_t; 58 | 59 | /** 60 | * Decoded values of Extended Card Specific Data 61 | */ 62 | typedef struct { 63 | uint8_t power_class; /*!< Power class used by the card */ 64 | } sdmmc_ext_csd_t; 65 | 66 | /** 67 | * SD/MMC command response buffer 68 | */ 69 | typedef uint32_t sdmmc_response_t[4]; 70 | 71 | /** 72 | * SD SWITCH_FUNC response buffer 73 | */ 74 | typedef struct { 75 | uint32_t data[512 / 8 / sizeof(uint32_t)]; /*!< response data */ 76 | } sdmmc_switch_func_rsp_t; 77 | 78 | /** 79 | * SD/MMC command information 80 | */ 81 | typedef struct { 82 | uint32_t opcode; /*!< SD or MMC command index */ 83 | uint32_t arg; /*!< SD/MMC command argument */ 84 | sdmmc_response_t response; /*!< response buffer */ 85 | void* data; /*!< buffer to send or read into */ 86 | size_t datalen; /*!< length of data buffer */ 87 | size_t blklen; /*!< block length */ 88 | int flags; /*!< see below */ 89 | /** @cond */ 90 | #define SCF_ITSDONE 0x0001 /*!< command is complete */ 91 | #define SCF_CMD(flags) ((flags) & 0x00f0) 92 | #define SCF_CMD_AC 0x0000 93 | #define SCF_CMD_ADTC 0x0010 94 | #define SCF_CMD_BC 0x0020 95 | #define SCF_CMD_BCR 0x0030 96 | #define SCF_CMD_READ 0x0040 /*!< read command (data expected) */ 97 | #define SCF_RSP_BSY 0x0100 98 | #define SCF_RSP_136 0x0200 99 | #define SCF_RSP_CRC 0x0400 100 | #define SCF_RSP_IDX 0x0800 101 | #define SCF_RSP_PRESENT 0x1000 102 | /* response types */ 103 | #define SCF_RSP_R0 0 /*!< none */ 104 | #define SCF_RSP_R1 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) 105 | #define SCF_RSP_R1B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY) 106 | #define SCF_RSP_R2 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_136) 107 | #define SCF_RSP_R3 (SCF_RSP_PRESENT) 108 | #define SCF_RSP_R4 (SCF_RSP_PRESENT) 109 | #define SCF_RSP_R5 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) 110 | #define SCF_RSP_R5B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY) 111 | #define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) 112 | #define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) 113 | /* special flags */ 114 | #define SCF_WAIT_BUSY 0x2000 /*!< Wait for completion of card busy signal before returning */ 115 | /** @endcond */ 116 | esp_err_t error; /*!< error returned from transfer */ 117 | int timeout_ms; /*!< response timeout, in milliseconds */ 118 | } sdmmc_command_t; 119 | 120 | /** 121 | * SD/MMC Host description 122 | * 123 | * This structure defines properties of SD/MMC host and functions 124 | * of SD/MMC host which can be used by upper layers. 125 | */ 126 | typedef struct { 127 | uint32_t flags; /*!< flags defining host properties */ 128 | #define SDMMC_HOST_FLAG_1BIT BIT(0) /*!< host supports 1-line SD and MMC protocol */ 129 | #define SDMMC_HOST_FLAG_4BIT BIT(1) /*!< host supports 4-line SD and MMC protocol */ 130 | #define SDMMC_HOST_FLAG_8BIT BIT(2) /*!< host supports 8-line MMC protocol */ 131 | #define SDMMC_HOST_FLAG_SPI BIT(3) /*!< host supports SPI protocol */ 132 | #define SDMMC_HOST_FLAG_DDR BIT(4) /*!< host supports DDR mode for SD/MMC */ 133 | int slot; /*!< slot number, to be passed to host functions */ 134 | int max_freq_khz; /*!< max frequency supported by the host */ 135 | #define SDMMC_FREQ_DEFAULT 20000 /*!< SD/MMC Default speed (limited by clock divider) */ 136 | #define SDMMC_FREQ_HIGHSPEED 40000 /*!< SD High speed (limited by clock divider) */ 137 | #define SDMMC_FREQ_PROBING 400 /*!< SD/MMC probing speed */ 138 | #define SDMMC_FREQ_52M 52000 /*!< MMC 52MHz speed */ 139 | #define SDMMC_FREQ_26M 26000 /*!< MMC 26MHz speed */ 140 | float io_voltage; /*!< I/O voltage used by the controller (voltage switching is not supported) */ 141 | esp_err_t (*init)(void); /*!< Host function to initialize the driver */ 142 | esp_err_t (*set_bus_width)(int slot, size_t width); /*!< host function to set bus width */ 143 | size_t (*get_bus_width)(int slot); /*!< host function to get bus width */ 144 | esp_err_t (*set_bus_ddr_mode)(int slot, bool ddr_enable); /*!< host function to set DDR mode */ 145 | esp_err_t (*set_card_clk)(int slot, uint32_t freq_khz); /*!< host function to set card clock frequency */ 146 | esp_err_t (*do_transaction)(int slot, sdmmc_command_t* cmdinfo); /*!< host function to do a transaction */ 147 | esp_err_t (*deinit)(void); /*!< host function to deinitialize the driver */ 148 | esp_err_t (*io_int_enable)(int slot); /*!< Host function to enable SDIO interrupt line */ 149 | esp_err_t (*io_int_wait)(int slot, TickType_t timeout_ticks); /*!< Host function to wait for SDIO interrupt line to be active */ 150 | int command_timeout_ms; /*!< timeout, in milliseconds, of a single command. Set to 0 to use the default value. */ 151 | } sdmmc_host_t; 152 | 153 | /** 154 | * SD/MMC card information structure 155 | */ 156 | typedef struct { 157 | sdmmc_host_t host; /*!< Host with which the card is associated */ 158 | uint32_t ocr; /*!< OCR (Operation Conditions Register) value */ 159 | sdmmc_cid_t cid; /*!< decoded CID (Card IDentification) register value */ 160 | sdmmc_csd_t csd; /*!< decoded CSD (Card-Specific Data) register value */ 161 | sdmmc_scr_t scr; /*!< decoded SCR (SD card Configuration Register) value */ 162 | sdmmc_ext_csd_t ext_csd; /*!< decoded EXT_CSD (Extended Card Specific Data) register value */ 163 | uint16_t rca; /*!< RCA (Relative Card Address) */ 164 | uint16_t max_freq_khz; /*!< Maximum frequency, in kHz, supported by the card */ 165 | uint32_t is_mem : 1; /*!< Bit indicates if the card is a memory card */ 166 | uint32_t is_sdio : 1; /*!< Bit indicates if the card is an IO card */ 167 | uint32_t is_mmc : 1; /*!< Bit indicates if the card is MMC */ 168 | uint32_t num_io_functions : 3; /*!< If is_sdio is 1, contains the number of IO functions on the card */ 169 | uint32_t log_bus_width : 2; /*!< log2(bus width supported by card) */ 170 | uint32_t is_ddr : 1; /*!< Card supports DDR mode */ 171 | uint32_t reserved : 23; /*!< Reserved for future expansion */ 172 | } sdmmc_card_t; 173 | 174 | 175 | #endif // _SDMMC_TYPES_H_ 176 | --------------------------------------------------------------------------------