| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- /* USER CODE BEGIN Header */
- /* USER CODE END Header */
- /* Includes ------------------------------------------------------------------*/
- #include "main.h"
- #include "gpio.h"
- #include "spi.h"
- #include "spif.h"
- #include "usart.h"
- /* Private includes ----------------------------------------------------------*/
- /* USER CODE BEGIN Includes */
- #include "lfs.h"
- #include <stdio.h>
- /* USER CODE END Includes */
- /* Private typedef -----------------------------------------------------------*/
- /* USER CODE BEGIN PTD */
- /* USER CODE END PTD */
- /* Private define ------------------------------------------------------------*/
- /* USER CODE BEGIN PD */
- /* USER CODE END PD */
- /* Private macro -------------------------------------------------------------*/
- /* USER CODE BEGIN PM */
- /* USER CODE END PM */
- /* Private variables ---------------------------------------------------------*/
- /* USER CODE BEGIN PV */
- uint8_t test_write[256];
- uint8_t test_read[256];
- SPIF_HandleTypeDef spif_handle;
- // Прототипы функций
- int littlefs_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off,
- void *buffer, lfs_size_t size);
- int littlefs_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off,
- const void *buffer, lfs_size_t size);
- int littlefs_erase(const struct lfs_config *c, lfs_block_t block);
- int littlefs_sync(const struct lfs_config *c);
- // Конфигурация LittleFS
- struct lfs_config littlefs_config = {
- // ... function pointers ...
- .read = littlefs_read,
- .prog = littlefs_prog,
- .erase = littlefs_erase,
- .sync = littlefs_sync,
- // CONFIGURATION
- .read_size = 1, // Winbond allows byte-level reads. 1 is more efficient for
- // small files.
- .prog_size = 256, // Winbond Page Size
- .block_size = 4096, // 4KB Sector Size (Must match SPIF_SECTOR_SIZE)
- .block_count = 4096, // 128Mbit / 4096 bytes = 4096 blocks
- .cache_size = 256, // One page cache
- .lookahead_size =
- 128, // CHANGE THIS: 8 is too small for 4096 blocks. Use 128 or 256.
- .block_cycles = 500, // CHANGE THIS: 100 is too low, causes excessive wear
- // leveling overhead.
- };
- lfs_t littlefs;
- /**
- * @brief Инициализация LittleFS с использованием SPIF
- * @param handle Указатель на инициализированную структуру SPIF_HandleTypeDef
- */
- int spif_littlefs_init(SPIF_HandleTypeDef *spif_handle) {
- if (spif_handle == NULL || spif_handle->Inited == 0) {
- return -1;
- }
- // Update config based on chip probe
- littlefs_config.block_count = spif_handle->SectorCnt;
- // Ensure block_size matches the physical erase size (usually 4096 for
- // Winbond)
- littlefs_config.block_size = SPIF_SECTOR_SIZE;
- // 1. Try to mount
- int err = lfs_mount(&littlefs, &littlefs_config);
- // 2. If mount fails, format and try again
- if (err) {
- printf("LittleFS: First boot or corruption detected. Formatting...\r\n");
- err = lfs_format(&littlefs, &littlefs_config);
- if (err) {
- printf("LittleFS: Format Failed! Error: %d\r\n", err);
- return err;
- }
- err = lfs_mount(&littlefs, &littlefs_config);
- if (err) {
- printf("LittleFS: Mount Failed after format! Error: %d\r\n", err);
- return err;
- }
- }
- printf("LittleFS: Mounted Successfully. Size: %lu Bytes\r\n",
- littlefs_config.block_count * littlefs_config.block_size);
- return LFS_ERR_OK;
- }
- int littlefs_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off,
- void *buffer, lfs_size_t size) {
- printf("LittleFS Read b = 0x%04lx o = 0x%04lx s = 0x%04lx", block, off, size);
- // Вычисляем абсолютный адрес: (Номер блока * Размер блока) + Смещение
- uint32_t address = (block * littlefs_config.block_size) + off;
- // SPIF_ReadAddress возвращает true при успехе, false при ошибке
- if (SPIF_ReadAddress(&spif_handle, address, (uint8_t *)buffer, size) ==
- true) {
- return LFS_ERR_OK; // 0
- }
- return LFS_ERR_IO; // Отрицательное значение ошибки
- }
- int littlefs_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off,
- const void *buffer, lfs_size_t size) {
- printf("LittleFS Prog b = 0x%04lx o = 0x%04lx s = 0x%04lx", block, off, size);
- uint32_t address = (block * littlefs_config.block_size) + off;
- // SPIF_WriteAddress сама обрабатывает запись страниц
- if (SPIF_WriteAddress(&spif_handle, address, (uint8_t *)buffer, size) ==
- true) {
- return LFS_ERR_OK;
- }
- return LFS_ERR_IO;
- }
- int littlefs_erase(const struct lfs_config *c, lfs_block_t block) {
- printf("LittleFS Erase b = 0x%04lx", block);
- // SPIF_EraseSector принимает номер сектора, который равен номеру блока LFS
- // (при условии, что block_size == SPIF_SECTOR_SIZE)
- if (SPIF_EraseSector(&spif_handle, block) == true) {
- return LFS_ERR_OK;
- }
- return LFS_ERR_IO;
- }
- int littlefs_sync(const struct lfs_config *c) {
- printf("LittleFS Sync");
- // SPIF библиотека блокирующая, дополнительная синхронизация обычно не
- // требуется, если не используется кэширование записи на уровне драйвера.
- return LFS_ERR_OK;
- }
- void lfs_test_write_read(void) {
- lfs_file_t file;
- int err;
- const char *filename = "boot_count.txt";
- uint32_t boot_count = 0;
- printf("\r\n--- Starting File Test ---\r\n");
- // 1. Open file for reading and writing. Create if it doesn't exist.
- err = lfs_file_open(&littlefs, &file, filename, LFS_O_RDWR | LFS_O_CREAT);
- if (err) {
- printf("Error opening file: %d\r\n", err);
- return;
- }
- // 2. Read current content (if file existed)
- // We try to read sizeof(uint32_t). If file is empty, it returns 0 bytes.
- lfs_ssize_t read_size =
- lfs_file_read(&littlefs, &file, &boot_count, sizeof(boot_count));
- if (read_size < 0) {
- printf("Error reading file: %ld\r\n", read_size);
- lfs_file_close(&littlefs, &file);
- return;
- } else if (read_size == 0) {
- printf("File was empty (First run)\r\n");
- boot_count = 0;
- } else {
- printf("Previous boot count: %lu\r\n", boot_count);
- }
- // 3. Increment count
- boot_count++;
- // 4. Rewind file to the beginning to overwrite the old value
- err = lfs_file_rewind(&littlefs, &file);
- if (err) {
- printf("Error rewinding: %d\r\n", err);
- lfs_file_close(&littlefs, &file);
- return;
- }
- // 5. Write new value
- err = lfs_file_write(&littlefs, &file, &boot_count, sizeof(boot_count));
- if (err < 0) {
- printf("Error writing: %d\r\n", err);
- lfs_file_close(&littlefs, &file);
- return;
- }
- // 6. Close the file (CRITICAL: This flushes data to the chip)
- err = lfs_file_close(&littlefs, &file);
- if (err) {
- printf("Error closing: %d\r\n", err);
- return;
- }
- printf("Updated boot count to: %lu\r\n", boot_count);
- printf("--- Test Finished ---\r\n");
- }
- /* USER CODE END PV */
- /* Private function prototypes -----------------------------------------------*/
- void SystemClock_Config(void);
- /* USER CODE BEGIN PFP */
- /* USER CODE END PFP */
- /* Private user code ---------------------------------------------------------*/
- /* USER CODE BEGIN 0 */
- int _write(int fd, char *ptr, int len) {
- HAL_StatusTypeDef hstatus;
- if (fd == 1 || fd == 2) {
- hstatus = HAL_UART_Transmit(&huart2, (uint8_t *)ptr, len, HAL_MAX_DELAY);
- if (hstatus == HAL_OK)
- return len;
- else
- return -1;
- }
- return -1;
- }
- void dump_hex(char *header, uint32_t start, uint8_t *buf, uint32_t len) {
- uint32_t i = 0;
- printf("%s\n", header);
- for (i = 0; i < len; ++i) {
- if (i % 16 == 0) {
- printf("0x%08lx: ", start);
- }
- printf("%02x ", buf[i]);
- if ((i + 1) % 16 == 0) {
- printf("\n");
- }
- ++start;
- }
- }
- // int __io_putchar(int ch) {
- // // Write character to ITM ch.0
- // ITM_SendChar(ch);
- // return (ch);
- // }
- /* USER CODE END 0 */
- /**
- * @brief The application entry point.
- * @retval int
- */
- int main(void) {
- /* USER CODE BEGIN 1 */
- /* USER CODE END 1 */
- /* MCU Configuration--------------------------------------------------------*/
- /* Reset of all peripherals, Initializes the Flash interface and the Systick.
- */
- HAL_Init();
- /* USER CODE BEGIN Init */
- /* USER CODE END Init */
- /* Configure the system clock */
- SystemClock_Config();
- /* USER CODE BEGIN SysInit */
- /* USER CODE END SysInit */
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_USART2_UART_Init();
- MX_SPI2_Init();
- /* USER CODE BEGIN 2 */
- HAL_Delay(10);
- if (SPIF_Init(&spif_handle, &hspi2, GPIOB, GPIO_PIN_6)) {
- // Initialize and Mount
- if (spif_littlefs_init(&spif_handle) == LFS_ERR_OK) {
- // Run the test
- lfs_test_write_read();
- } else {
- printf("Mount failed!\n");
- }
- } else {
- printf("SPIF Init failed!\n");
- }
- /* USER CODE END 2 */
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1) {
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }
- /**
- * @brief System Clock Configuration
- * @retval None
- */
- void SystemClock_Config(void) {
- RCC_OscInitTypeDef RCC_OscInitStruct = {0};
- RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
- /** Initializes the RCC Oscillators according to the specified parameters
- * in the RCC_OscInitTypeDef structure.
- */
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
- RCC_OscInitStruct.HSIState = RCC_HSI_ON;
- RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
- RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
- if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
- Error_Handler();
- }
- /** Initializes the CPU, AHB and APB buses clocks
- */
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
- RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
- RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
- RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
- if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
- Error_Handler();
- }
- }
- /* USER CODE BEGIN 4 */
- /* USER CODE END 4 */
- /**
- * @brief This function is executed in case of error occurrence.
- * @retval None
- */
- void Error_Handler(void) {
- /* USER CODE BEGIN Error_Handler_Debug */
- /* User can add his own implementation to report the HAL error return state */
- __disable_irq();
- while (1) {
- }
- /* USER CODE END Error_Handler_Debug */
- }
- #ifdef USE_FULL_ASSERT
- /**
- * @brief Reports the name of the source file and the source line number
- * where the assert_param error has occurred.
- * @param file: pointer to the source file name
- * @param line: assert_param error line source number
- * @retval None
- */
- void assert_failed(uint8_t *file, uint32_t line) {
- /* USER CODE BEGIN 6 */
- /* User can add his own implementation to report the file name and line
- number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file,
- line) */
- /* USER CODE END 6 */
- }
- #endif /* USE_FULL_ASSERT */
|