main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /* USER CODE BEGIN Header */
  2. /* USER CODE END Header */
  3. /* Includes ------------------------------------------------------------------*/
  4. #include "main.h"
  5. #include "gpio.h"
  6. #include "spi.h"
  7. #include "spif.h"
  8. #include "usart.h"
  9. /* Private includes ----------------------------------------------------------*/
  10. /* USER CODE BEGIN Includes */
  11. #include "lfs.h"
  12. #include <stdio.h>
  13. /* USER CODE END Includes */
  14. /* Private typedef -----------------------------------------------------------*/
  15. /* USER CODE BEGIN PTD */
  16. /* USER CODE END PTD */
  17. /* Private define ------------------------------------------------------------*/
  18. /* USER CODE BEGIN PD */
  19. /* USER CODE END PD */
  20. /* Private macro -------------------------------------------------------------*/
  21. /* USER CODE BEGIN PM */
  22. /* USER CODE END PM */
  23. /* Private variables ---------------------------------------------------------*/
  24. /* USER CODE BEGIN PV */
  25. uint8_t test_write[256];
  26. uint8_t test_read[256];
  27. SPIF_HandleTypeDef spif_handle;
  28. // Прототипы функций
  29. int littlefs_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off,
  30. void *buffer, lfs_size_t size);
  31. int littlefs_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off,
  32. const void *buffer, lfs_size_t size);
  33. int littlefs_erase(const struct lfs_config *c, lfs_block_t block);
  34. int littlefs_sync(const struct lfs_config *c);
  35. // Конфигурация LittleFS
  36. struct lfs_config littlefs_config = {
  37. // ... function pointers ...
  38. .read = littlefs_read,
  39. .prog = littlefs_prog,
  40. .erase = littlefs_erase,
  41. .sync = littlefs_sync,
  42. // CONFIGURATION
  43. .read_size = 1, // Winbond allows byte-level reads. 1 is more efficient for
  44. // small files.
  45. .prog_size = 256, // Winbond Page Size
  46. .block_size = 4096, // 4KB Sector Size (Must match SPIF_SECTOR_SIZE)
  47. .block_count = 4096, // 128Mbit / 4096 bytes = 4096 blocks
  48. .cache_size = 256, // One page cache
  49. .lookahead_size =
  50. 128, // CHANGE THIS: 8 is too small for 4096 blocks. Use 128 or 256.
  51. .block_cycles = 500, // CHANGE THIS: 100 is too low, causes excessive wear
  52. // leveling overhead.
  53. };
  54. lfs_t littlefs;
  55. /**
  56. * @brief Инициализация LittleFS с использованием SPIF
  57. * @param handle Указатель на инициализированную структуру SPIF_HandleTypeDef
  58. */
  59. int spif_littlefs_init(SPIF_HandleTypeDef *spif_handle) {
  60. if (spif_handle == NULL || spif_handle->Inited == 0) {
  61. return -1;
  62. }
  63. // Update config based on chip probe
  64. littlefs_config.block_count = spif_handle->SectorCnt;
  65. // Ensure block_size matches the physical erase size (usually 4096 for
  66. // Winbond)
  67. littlefs_config.block_size = SPIF_SECTOR_SIZE;
  68. // 1. Try to mount
  69. int err = lfs_mount(&littlefs, &littlefs_config);
  70. // 2. If mount fails, format and try again
  71. if (err) {
  72. printf("LittleFS: First boot or corruption detected. Formatting...\r\n");
  73. err = lfs_format(&littlefs, &littlefs_config);
  74. if (err) {
  75. printf("LittleFS: Format Failed! Error: %d\r\n", err);
  76. return err;
  77. }
  78. err = lfs_mount(&littlefs, &littlefs_config);
  79. if (err) {
  80. printf("LittleFS: Mount Failed after format! Error: %d\r\n", err);
  81. return err;
  82. }
  83. }
  84. printf("LittleFS: Mounted Successfully. Size: %lu Bytes\r\n",
  85. littlefs_config.block_count * littlefs_config.block_size);
  86. return LFS_ERR_OK;
  87. }
  88. int littlefs_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off,
  89. void *buffer, lfs_size_t size) {
  90. printf("LittleFS Read b = 0x%04lx o = 0x%04lx s = 0x%04lx", block, off, size);
  91. // Вычисляем абсолютный адрес: (Номер блока * Размер блока) + Смещение
  92. uint32_t address = (block * littlefs_config.block_size) + off;
  93. // SPIF_ReadAddress возвращает true при успехе, false при ошибке
  94. if (SPIF_ReadAddress(&spif_handle, address, (uint8_t *)buffer, size) ==
  95. true) {
  96. return LFS_ERR_OK; // 0
  97. }
  98. return LFS_ERR_IO; // Отрицательное значение ошибки
  99. }
  100. int littlefs_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off,
  101. const void *buffer, lfs_size_t size) {
  102. printf("LittleFS Prog b = 0x%04lx o = 0x%04lx s = 0x%04lx", block, off, size);
  103. uint32_t address = (block * littlefs_config.block_size) + off;
  104. // SPIF_WriteAddress сама обрабатывает запись страниц
  105. if (SPIF_WriteAddress(&spif_handle, address, (uint8_t *)buffer, size) ==
  106. true) {
  107. return LFS_ERR_OK;
  108. }
  109. return LFS_ERR_IO;
  110. }
  111. int littlefs_erase(const struct lfs_config *c, lfs_block_t block) {
  112. printf("LittleFS Erase b = 0x%04lx", block);
  113. // SPIF_EraseSector принимает номер сектора, который равен номеру блока LFS
  114. // (при условии, что block_size == SPIF_SECTOR_SIZE)
  115. if (SPIF_EraseSector(&spif_handle, block) == true) {
  116. return LFS_ERR_OK;
  117. }
  118. return LFS_ERR_IO;
  119. }
  120. int littlefs_sync(const struct lfs_config *c) {
  121. printf("LittleFS Sync");
  122. // SPIF библиотека блокирующая, дополнительная синхронизация обычно не
  123. // требуется, если не используется кэширование записи на уровне драйвера.
  124. return LFS_ERR_OK;
  125. }
  126. void lfs_test_write_read(void) {
  127. lfs_file_t file;
  128. int err;
  129. const char *filename = "boot_count.txt";
  130. uint32_t boot_count = 0;
  131. printf("\r\n--- Starting File Test ---\r\n");
  132. // 1. Open file for reading and writing. Create if it doesn't exist.
  133. err = lfs_file_open(&littlefs, &file, filename, LFS_O_RDWR | LFS_O_CREAT);
  134. if (err) {
  135. printf("Error opening file: %d\r\n", err);
  136. return;
  137. }
  138. // 2. Read current content (if file existed)
  139. // We try to read sizeof(uint32_t). If file is empty, it returns 0 bytes.
  140. lfs_ssize_t read_size =
  141. lfs_file_read(&littlefs, &file, &boot_count, sizeof(boot_count));
  142. if (read_size < 0) {
  143. printf("Error reading file: %ld\r\n", read_size);
  144. lfs_file_close(&littlefs, &file);
  145. return;
  146. } else if (read_size == 0) {
  147. printf("File was empty (First run)\r\n");
  148. boot_count = 0;
  149. } else {
  150. printf("Previous boot count: %lu\r\n", boot_count);
  151. }
  152. // 3. Increment count
  153. boot_count++;
  154. // 4. Rewind file to the beginning to overwrite the old value
  155. err = lfs_file_rewind(&littlefs, &file);
  156. if (err) {
  157. printf("Error rewinding: %d\r\n", err);
  158. lfs_file_close(&littlefs, &file);
  159. return;
  160. }
  161. // 5. Write new value
  162. err = lfs_file_write(&littlefs, &file, &boot_count, sizeof(boot_count));
  163. if (err < 0) {
  164. printf("Error writing: %d\r\n", err);
  165. lfs_file_close(&littlefs, &file);
  166. return;
  167. }
  168. // 6. Close the file (CRITICAL: This flushes data to the chip)
  169. err = lfs_file_close(&littlefs, &file);
  170. if (err) {
  171. printf("Error closing: %d\r\n", err);
  172. return;
  173. }
  174. printf("Updated boot count to: %lu\r\n", boot_count);
  175. printf("--- Test Finished ---\r\n");
  176. }
  177. /* USER CODE END PV */
  178. /* Private function prototypes -----------------------------------------------*/
  179. void SystemClock_Config(void);
  180. /* USER CODE BEGIN PFP */
  181. /* USER CODE END PFP */
  182. /* Private user code ---------------------------------------------------------*/
  183. /* USER CODE BEGIN 0 */
  184. int _write(int fd, char *ptr, int len) {
  185. HAL_StatusTypeDef hstatus;
  186. if (fd == 1 || fd == 2) {
  187. hstatus = HAL_UART_Transmit(&huart2, (uint8_t *)ptr, len, HAL_MAX_DELAY);
  188. if (hstatus == HAL_OK)
  189. return len;
  190. else
  191. return -1;
  192. }
  193. return -1;
  194. }
  195. void dump_hex(char *header, uint32_t start, uint8_t *buf, uint32_t len) {
  196. uint32_t i = 0;
  197. printf("%s\n", header);
  198. for (i = 0; i < len; ++i) {
  199. if (i % 16 == 0) {
  200. printf("0x%08lx: ", start);
  201. }
  202. printf("%02x ", buf[i]);
  203. if ((i + 1) % 16 == 0) {
  204. printf("\n");
  205. }
  206. ++start;
  207. }
  208. }
  209. // int __io_putchar(int ch) {
  210. // // Write character to ITM ch.0
  211. // ITM_SendChar(ch);
  212. // return (ch);
  213. // }
  214. /* USER CODE END 0 */
  215. /**
  216. * @brief The application entry point.
  217. * @retval int
  218. */
  219. int main(void) {
  220. /* USER CODE BEGIN 1 */
  221. /* USER CODE END 1 */
  222. /* MCU Configuration--------------------------------------------------------*/
  223. /* Reset of all peripherals, Initializes the Flash interface and the Systick.
  224. */
  225. HAL_Init();
  226. /* USER CODE BEGIN Init */
  227. /* USER CODE END Init */
  228. /* Configure the system clock */
  229. SystemClock_Config();
  230. /* USER CODE BEGIN SysInit */
  231. /* USER CODE END SysInit */
  232. /* Initialize all configured peripherals */
  233. MX_GPIO_Init();
  234. MX_USART2_UART_Init();
  235. MX_SPI2_Init();
  236. /* USER CODE BEGIN 2 */
  237. HAL_Delay(10);
  238. if (SPIF_Init(&spif_handle, &hspi2, GPIOB, GPIO_PIN_6)) {
  239. // Initialize and Mount
  240. if (spif_littlefs_init(&spif_handle) == LFS_ERR_OK) {
  241. // Run the test
  242. lfs_test_write_read();
  243. } else {
  244. printf("Mount failed!\n");
  245. }
  246. } else {
  247. printf("SPIF Init failed!\n");
  248. }
  249. /* USER CODE END 2 */
  250. /* Infinite loop */
  251. /* USER CODE BEGIN WHILE */
  252. while (1) {
  253. /* USER CODE END WHILE */
  254. /* USER CODE BEGIN 3 */
  255. }
  256. /* USER CODE END 3 */
  257. }
  258. /**
  259. * @brief System Clock Configuration
  260. * @retval None
  261. */
  262. void SystemClock_Config(void) {
  263. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  264. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  265. /** Initializes the RCC Oscillators according to the specified parameters
  266. * in the RCC_OscInitTypeDef structure.
  267. */
  268. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  269. RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  270. RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  271. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  272. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  273. RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
  274. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
  275. Error_Handler();
  276. }
  277. /** Initializes the CPU, AHB and APB buses clocks
  278. */
  279. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
  280. RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  281. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  282. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  283. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  284. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  285. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
  286. Error_Handler();
  287. }
  288. }
  289. /* USER CODE BEGIN 4 */
  290. /* USER CODE END 4 */
  291. /**
  292. * @brief This function is executed in case of error occurrence.
  293. * @retval None
  294. */
  295. void Error_Handler(void) {
  296. /* USER CODE BEGIN Error_Handler_Debug */
  297. /* User can add his own implementation to report the HAL error return state */
  298. __disable_irq();
  299. while (1) {
  300. }
  301. /* USER CODE END Error_Handler_Debug */
  302. }
  303. #ifdef USE_FULL_ASSERT
  304. /**
  305. * @brief Reports the name of the source file and the source line number
  306. * where the assert_param error has occurred.
  307. * @param file: pointer to the source file name
  308. * @param line: assert_param error line source number
  309. * @retval None
  310. */
  311. void assert_failed(uint8_t *file, uint32_t line) {
  312. /* USER CODE BEGIN 6 */
  313. /* User can add his own implementation to report the file name and line
  314. number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file,
  315. line) */
  316. /* USER CODE END 6 */
  317. }
  318. #endif /* USE_FULL_ASSERT */