INTEGRATION 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. * QUICK AND DIRTY INTEGRATION EXAMPLE
  2. So, assume you're running a Cortex-M3 board with a 2 MB SPI flash on it. The
  3. SPI flash has 64kB blocks. Your project is built using gnumake, and now you
  4. want to try things out.
  5. First, you simply copy the files in src/ to your own source folder. Exclude
  6. all files in test folder. Then you point out these files in your make script
  7. for compilation.
  8. Also copy the spiffs_config.h over from the src/default/ folder.
  9. Try building. This fails, nagging about inclusions and u32_t and whatnot. Open
  10. the spiffs_config.h and delete the bad inclusions. Also, add following
  11. typedefs:
  12. typedef signed int s32_t;
  13. typedef unsigned int u32_t;
  14. typedef signed short s16_t;
  15. typedef unsigned short u16_t;
  16. typedef signed char s8_t;
  17. typedef unsigned char u8_t;
  18. Now it should build. Over to the mounting business. Assume you already
  19. implemented the read, write and erase functions to your SPI flash:
  20. void my_spi_read(int addr, int size, char *buf)
  21. void my_spi_write(int addr, int size, char *buf)
  22. void my_spi_erase(int addr, int size)
  23. In your main.c or similar, include the spiffs.h and do that spiffs struct:
  24. #include <spiffs.h>
  25. static spiffs fs;
  26. Also, toss up some of the needed buffers:
  27. #define LOG_PAGE_SIZE 256
  28. static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
  29. static u8_t spiffs_fds[32*4];
  30. static u8_t spiffs_cache_buf[(LOG_PAGE_SIZE+32)*4];
  31. Now, write the my_spiffs_mount function:
  32. void my_spiffs_mount() {
  33. spiffs_config cfg;
  34. cfg.phys_size = 2*1024*1024; // use all spi flash
  35. cfg.phys_addr = 0; // start spiffs at start of spi flash
  36. cfg.phys_erase_block = 65536; // according to datasheet
  37. cfg.log_block_size = 65536; // let us not complicate things
  38. cfg.log_page_size = LOG_PAGE_SIZE; // as we said
  39. cfg.hal_read_f = my_spi_read;
  40. cfg.hal_write_f = my_spi_write;
  41. cfg.hal_erase_f = my_spi_erase;
  42. int res = SPIFFS_mount(&fs,
  43. &cfg,
  44. spiffs_work_buf,
  45. spiffs_fds,
  46. sizeof(spiffs_fds),
  47. spiffs_cache_buf,
  48. sizeof(spiffs_cache_buf),
  49. 0);
  50. printf("mount res: %i\n", res);
  51. }
  52. Now, build warns about the my_spi_read, write and erase functions. Wrong
  53. signatures, so go wrap them:
  54. static s32_t my_spiffs_read(u32_t addr, u32_t size, u8_t *dst) {
  55. my_spi_read(addr, size, dst);
  56. return SPIFFS_OK;
  57. }
  58. static s32_t my_spiffs_write(u32_t addr, u32_t size, u8_t *src) {
  59. my_spi_write(addr, size, dst);
  60. return SPIFFS_OK;
  61. }
  62. static s32_t my_spiffs_erase(u32_t addr, u32_t size) {
  63. my_spi_erase(addr, size);
  64. return SPIFFS_OK;
  65. }
  66. Redirect the config in my_spiffs_mount to the wrappers instead:
  67. cfg.hal_read_f = my_spiffs_read;
  68. cfg.hal_write_f = my_spiffs_write;
  69. cfg.hal_erase_f = my_spiffs_erase;
  70. Ok, now you should be able to build and run. However, you get this output:
  71. mount res: -1
  72. but you wanted
  73. mount res: 0
  74. This is probably due to you having experimented with your SPI flash, so it
  75. contains rubbish from spiffs's point of view. Do a mass erase and run again.
  76. If all is ok now, you're good to go. Try creating a file and read it back:
  77. static void test_spiffs() {
  78. char buf[12];
  79. // Surely, I've mounted spiffs before entering here
  80. spiffs_file fd = SPIFFS_open(&fs, "my_file", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);
  81. if (SPIFFS_write(&fs, fd, (u8_t *)"Hello world", 12) < 0) printf("errno %i\n", SPIFFS_errno(&fs));
  82. SPIFFS_close(&fs, fd);
  83. fd = SPIFFS_open(&fs, "my_file", SPIFFS_RDWR, 0);
  84. if (SPIFFS_read(&fs, fd, (u8_t *)buf, 12) < 0) printf("errno %i\n", SPIFFS_errno(&fs));
  85. SPIFFS_close(&fs, fd);
  86. printf("--> %s <--\n", buf);
  87. }
  88. Compile, run, cross fingers hard, and you'll get the output:
  89. --> Hello world <--
  90. Got errors? Check spiffs.h for error definitions to get a clue what went voodoo.
  91. * THINGS TO CHECK
  92. When you alter the spiffs_config values, make sure you also check the typedefs
  93. in spiffs_config.h:
  94. - spiffs_block_ix
  95. - spiffs_page_ix
  96. - spiffs_obj_id
  97. - spiffs_span_ix
  98. The sizes of these typedefs must not underflow, else spiffs might end up in
  99. eternal loops. Each typedef is commented what check for.
  100. Also, if you alter the code or just want to verify your configuration, you can
  101. run
  102. > make test
  103. in the spiffs folder. This will run all testcases using the configuration in
  104. default/spiffs_config.h and test/params_test.h. The tests are written for linux
  105. but should run under cygwin also.
  106. * INTEGRATING SPIFFS
  107. In order to integrate spiffs to your embedded target, you will basically need:
  108. - A SPI flash device which your processor can communicate with
  109. - An implementation for reading, writing and erasing the flash
  110. - Memory (flash or ram) for the code
  111. - Memory (ram) for the stack
  112. Other stuff may be needed, threaded systems might need mutexes and so on.
  113. ** Logical structure
  114. First and foremost, one must decide how to divide up the SPI flash for spiffs.
  115. Having the datasheet for the actual SPI flash in hand will help. Spiffs can be
  116. defined to use all or only parts of the SPI flash.
  117. If following seems arcane, read the "HOW TO CONFIG" chapter first.
  118. - Decide the logical size of blocks. This must be a multiple of the biggest
  119. physical SPI flash block size. To go safe, use the physical block size -
  120. which in many cases is 65536 bytes.
  121. - Decide the logical size of pages. This must be a 2nd logarithm part of the
  122. logical block size. To go safe, use 256 bytes to start with.
  123. - Decide how much of the SPI flash memory to be used for spiffs. This must be
  124. on logical block boundary. If unsafe, use 1 megabyte to start with.
  125. - Decide where on the SPI flash memory the spiffs area should start. This must
  126. be on physical block/sector boundary. If unsafe, use address 0.
  127. ** SPI flash API
  128. The target must provide three functions to spiffs:
  129. - s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst)
  130. - s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src)
  131. - s32_t (*spiffs_erase)(u32_t addr, u32_t size)
  132. These functions define the only communication between the SPI flash and the
  133. spiffs stack.
  134. On success these must return 0 (or SPIFFS_OK). Anything else will be considered
  135. an error.
  136. The size for read and write requests will never exceed the logical page size,
  137. but it may be less.
  138. The address and size on erase requests will always be on physical block size
  139. boundaries.
  140. ** Mount specification
  141. In spiffs.h, there is a SPIFFS_mount function defined, used to mount spiffs on
  142. the SPI flash.
  143. s32_t SPIFFS_mount(
  144. spiffs *fs,
  145. spiffs_config *config,
  146. u8_t *work,
  147. u8_t *fd_space,
  148. u32_t fd_space_size,
  149. void *cache,
  150. u32_t cache_size,
  151. spiffs_check_callback check_cb_f)
  152. - fs Points to a spiffs struct. This may be totally uninitialized.
  153. - config Points to a spiffs_config struct. This struct must be
  154. initialized when mounting. See below.
  155. - work A ram memory buffer being double the size of the logical page
  156. size. This buffer is used excessively by the spiffs stack. If
  157. logical page size is 256, this buffer must be 512 bytes.
  158. - fd_space A ram memory buffer used for file descriptors.
  159. - fd_space_size The size of the file descriptor buffer. A file descriptor
  160. normally is around 32 bytes depending on the build config -
  161. the bigger the buffer, the more file descriptors are
  162. available.
  163. - cache A ram memory buffer used for cache. Ignored if cache is
  164. disabled in build config.
  165. - cache_size The size of the cache buffer. Ignored if cache is disabled in
  166. build config. One cache page will be slightly larger than the
  167. logical page size. The more ram, the more cache pages, the
  168. quicker the system.
  169. - check_cb_f Callback function for monitoring spiffs consistency checks and
  170. mending operations. May be null.
  171. The config struct must be initialized prior to mounting. One must always
  172. define the SPI flash access functions:
  173. spiffs_config.hal_read_f - pointing to the function reading the SPI flash
  174. spiffs_config.hal_write_f - pointing to the function writing the SPI flash
  175. spiffs_config.hal_erase_f - pointing to the function erasing the SPI flash
  176. Depending on the build config - if SPIFFS_SINGLETON is set to zero - following
  177. parameters must be defined:
  178. spiffs_config.phys_size - the physical number of bytes accounted for
  179. spiffs on the SPI flash
  180. spiffs_config.phys_addr - the physical starting address on the SPI flash
  181. spiffs_config.phys_erase_block - the physical size of the largest block/sector
  182. on the SPI flash found within the spiffs
  183. usage address space
  184. spiffs_config.log_block_size - the logical size of a spiffs block
  185. spiffs_config.log_page_size - the logical size of a spiffs page
  186. If SPIFFS_SINGLETON is set to one, above parameters must be set ny defines in
  187. the config header file, spiffs_config.h.
  188. ** Build config
  189. makefile: The files needed to be compiled to your target resides in files.mk to
  190. be included in your makefile, either by cut and paste or by inclusion.
  191. Types: spiffs uses the types u8_t, s8_t, u16_t, s16_t, u32_t, s32_t; these must
  192. be typedeffed.
  193. spiffs_config.h: you also need to define a spiffs_config.h header. Example of
  194. this is found in the default/ directory.
  195. ** RAM
  196. Spiffs needs ram. It needs a working buffer being double the size of the
  197. logical page size. It also needs at least one file descriptor. If cache is
  198. enabled (highly recommended), it will also need a bunch of cache pages.
  199. Say you have a logical page size of 256 bytes. You want to be able to have four
  200. files open simultaneously, and you can give spiffs four cache pages. This
  201. roughly sums up to:
  202. 256*2 (work buffer) +
  203. 32*4 (file descriptors) +
  204. (256+32)*4 (cache pages) + 40 (cache metadata)
  205. i.e. 1832 bytes.
  206. This is apart from call stack usage.
  207. To get the exact amount of bytes needed on your specific target, enable
  208. SPIFFS_BUFFER_HELP in spiffs_config.h, rebuild and call:
  209. SPIFFS_buffer_bytes_for_filedescs
  210. SPIFFS_buffer_bytes_for_cache
  211. Having these figures you can disable SPIFFS_BUFFER_HELP again to save flash.
  212. * HOW TO CONFIG
  213. TODO