diff --git a/docs/llfs.md b/docs/llfs.md index eac7c21..2fa6986 100644 --- a/docs/llfs.md +++ b/docs/llfs.md @@ -1,17 +1,52 @@ # LLFS (Linked List File System) ## Introduction -The llfs filesystem can be generated using the mkllfss utility. -It is a simple filesystem that uses a linked list to store files. -The filesystem is stored in a single c file (`llfs_data.c`), which can be compiled and read by the llfs library. -The llfs filesystem is a flat filesystem, meaning that it does not support directories. +The llfs filesystem can be generated using the [mkllfs](mkllfs.md) utility. +The resulting C file encapsulates the filesystem data within a linked list which can be used by the llfs library. + +As a flat filesystem, llfs lacks support for directories. +Using the llfs API, information about the files in the filesystem can be retrieved, +and the files can be read using direct memory access. +Alternatively, the POSIX file functions can be used. +But this is more resource intensive, as data must be copied before using it. + +It's essential to note that the llfs filesystem operates in a read-only mode, +restricting operations solely to read functions. + +## Table of contents + - [Introduction](#introduction) + - [Table of contents](#table-of-contents) + - [Initialization](#initialization) + - [Usage of the llfs API](#usage-of-the-llfs-api) + - [The `llfs_file_t` struct](#the-llfs_file_t-struct) + - [Getting a list of files](#getting-a-list-of-files) + - [Iterator function (not recommended)](#iterator-function-not-recommended) + - [Reading a file](#reading-a-file) + - [Getting the number of files](#getting-the-number-of-files) + - [Using the POSIX file functions](#using-the-posix-file-functions) + +## Initialization +Before using the llfs API, or the file related POSIX (fopen, fgetc, ...) functions, the filesystem must be initialized by calling `llfs_init()`. ## Usage of the llfs API +### The `llfs_file_t` struct +The `llfs_file_t` struct contains information about a file in the filesystem. +```c +typedef struct { + const uint8_t* data; // Pointer to the file data (len bytes) + const char* name; // Null-terminated string with the filename + size_t len; // Length of the file data +} llfs_file_t; +``` +The data pointer points to the data of the file in the filesystem, and can be used to read the file. + ### Getting a list of files ```c #include "llfs.h" void main(void) { + llfs_init(); + // Allocate space for 10 files llfs_file_t file_list[10]; @@ -33,13 +68,50 @@ Result: [Info] (2031) [main]: File: file1.txt, size: 77 ``` +It is also possible to use a file extension filter (e.g. `*.bmp`, `*.txt`, `*.py`). +```c + // ... + size_t file_count = llfs_file_list(file_list, 10, "*.bmp"); + // ... +``` +This will only return files with the `.bmp` extension. +```` +[Info] (2009) [main]: File: image.bmp, size: 9270 +[Info] (2019) [main]: File: image2.bmp, size: 7738 +```` + +#### Iterator function (not recommended) +It is also possible to iterate through the files without allocating an array. +When the memory pointer is `NULL`, the iterator will start at the beginning of the file list. +Each call to `llfs_next_file()` will return the next file in the list, +if a filter is specified files that don't match the filter will be skipped. +```c +#include "llfs.h" + +void main(void) { + llfs_init(); + + // Get the file list + void* mem = NULL; // Pointer for internal use by the llfs library + llfs_file_t* file; + while ((file = llfs_next_file(&mem, ".bmp")) != NULL) { + LOG_INFO(TAG, "File: %s", file->name); + } +} +``` +While this method doesn't require allocating memory for the file list, +it is slower than the previous method due to the overhead calling the function for each file. +Additionally, the required memory for the filelist is very small, so it's recommended to use the first method. + ### Reading a file ```c #include "llfs.h" void main(void) { + llfs_init(); + // Get a file by name - llfs_file_t *file = llfs_file_open("filename with a space.txt"); + llfs_file_t* file = llfs_file_open("filename with a space.txt"); if (file != NULL) { // Print the file name, size and data @@ -55,3 +127,37 @@ Result: [Info] (2040) [main]: File found: filename with a space.txt, size: 61 [Info] (2047) [main]: File data: This is a file with a space in it's filename. ``` + +### Getting the number of files +```c +#include "llfs.h" + +void main(void) { + llfs_init(); + + // Get the number of files + size_t file_count = llfs_file_count(); + + // Print the number of files + LOG_INFO(TAG, "File count: %d", file_count); +} +``` + +## Using the POSIX file functions +The llfs library also supports the POSIX file functions. +As the file system is read-only, write functions are not implemented. +There is also a limit on the number of files that can be open concurrently, +this is set by the `POSIX_MAX_FILES` macro in `llfs.c`. +The default value is 10, but there are already 3 files in use (stdin, stdout, stderr), +so the maximum number of files that can be open is 7. + +The following functions are tested and working, but other functions might also work: + - `fopen` + - `fclose` + - `fgetc` + - `fread` + - `fseek` + - `ftell` + - `rewind` + - `fstat` + - `fileno` diff --git a/project/Core/Inc/llfs.h b/project/Core/Inc/llfs.h index 7fff04a..780a73b 100644 --- a/project/Core/Inc/llfs.h +++ b/project/Core/Inc/llfs.h @@ -2,6 +2,7 @@ * @file llfs.h * @brief Linked List Filesystem header (llfs) * @author Lorenz C. + * @version 0.1.1 */ #ifndef LLFS_H @@ -30,20 +31,25 @@ struct llfs_data_file { const struct llfs_data_file* next; }; +/** + * @brief Initialize the llfs filesystem + * @note This function should be called before any other llfs function or POSIX file operation (e.g. fopen, fread, ...) + * @return 0 on success + */ +int8_t llfs_init(void); + /** * @brief Get a list of files in the filesystem * Get a list of all the files in the filesystem. * - * Use the filter to filter out files with a filename that do not match the filter. (e.g. "*.txt" or "*.png|*.jpg") (not - * implemented yet) Multiple filters can be used by separating them with a pipe (|). + * Use the filter to filter out files with a filename that do not match the file extension filter. * * The following members of the llfs_file_t struct are set: name, len and data. @ref llfs_file_t * - * @todo Implement file filter * * @param[out] file_list A pointer to an array of llfs_file_t to store the files in @ref llfs_file_t * @param[in] max_files The maximum number of files to return (size of file_list) - * @param[in] filter A string with file extensions to filter out. (e.g. "*.txt" or "*.png|*.jpg") + * @param[in] filter A string with the file extensions to filter out. (e.g. "*.txt" or "*.png") * @return The number of files returned */ size_t llfs_file_list(llfs_file_t* file_list, size_t max_files, char* filter); @@ -58,4 +64,23 @@ size_t llfs_file_list(llfs_file_t* file_list, size_t max_files, char* filter); */ llfs_file_t* llfs_file_open(const char* name); +/** + * @brief Iterate over all files in the filesystem + * For each call (with the same mem pointer) the next file in the filesystem is returned. + * The first call should be with mem = NULL. + * If a filter is specified, only files with a filename that matches the filter are returned. + * + * @param[in, out] mem A pointer to a void* that is used internally to keep track of the current file + * @param[in] filter A string with file extension to filter out. (e.g. "*.txt" or "*.png") + * @return The next file in the filesystem or NULL if there are no more files @ref llfs_file_t + */ +llfs_file_t* llfs_next_file(void** mem, char* filter); + +/** + * @brief Get the number of files in the filesystem + * + * @return The number of files in the filesystem + */ +size_t llfs_file_count(void); + #endif // LLFS_H diff --git a/project/Core/Src/llfs.c b/project/Core/Src/llfs.c index b139d99..62588de 100644 --- a/project/Core/Src/llfs.c +++ b/project/Core/Src/llfs.c @@ -2,34 +2,82 @@ * @file llfs.c * @brief Linked List Filesystem implementation (llfs) * @author Lorenz C. - * @todo Implement file extension filter + * @version 0.1.1 */ +#include +#include +#include #include #define LOGGER_LEVEL_WARN #include "llfs.h" #include "log.h" +/** + * @brief The maximum number of files that can be opened concurrently using the POSIX API + */ +#define POSIX_MAX_FILES 10 + extern struct llfs_data_file* llfs_root; const char* TAG = "llfs"; +size_t file_count = 0; +FILE* file_table[POSIX_MAX_FILES]; + +static int new_file_table_entry(void); +static int free_file_table_entry(int file_id); +static FILE* file_id_to_stream(int file_id); +static uint8_t file_ext_cmp(const char* filename, const char* ext); + +int8_t llfs_init(void) { + LOG_DEBUG(TAG, "Initializing llfs"); + + // Initialize the file table + for (int i = 0; i < POSIX_MAX_FILES; i++) { + file_table[i] = NULL; + } + + // Add stdin, stdout and stderr to the file table + file_table[STDIN_FILENO] = stdin; + file_table[STDOUT_FILENO] = stdout; + file_table[STDERR_FILENO] = stderr; + + return 0; +} -// TODO: Implement file extension filter size_t llfs_file_list(llfs_file_t* file_list, size_t max_files, char* filter) { - size_t file_count = 0; - const struct llfs_data_file* file = llfs_root; + size_t count = 0; // Number of files found + const struct llfs_data_file* file = llfs_root; // Pointer to the current file - LOG_DEBUG(TAG, "Getting file list with filter: %s", filter); + if (filter != NULL) { + LOG_DEBUG(TAG, "Filtering files with filter: %s", filter); + if (filter[0] == '*') { + filter++; + } + } + + // Iterate over all files in the filesystem while (file != NULL && file_count < max_files) { - file_list[file_count].data = file->data; - file_list[file_count].name = file->name; - file_list[file_count].len = file->len; - file_count++; + // Filter out files with a filename that does not match the filter + if (filter != NULL) { + if (!file_ext_cmp(file->name, filter)) { + file = file->next; + continue; + } + } + + // Add the file to the file list + file_list[count].data = file->data; + file_list[count].name = file->name; + file_list[count].len = file->len; + + // Move to the next file + count++; file = file->next; } - LOG_DEBUG(TAG, "Files found: %d", file_count); - return file_count; + LOG_DEBUG(TAG, "Files found: %d", count); + return count; } llfs_file_t* llfs_file_open(const char* name) { @@ -48,3 +96,341 @@ llfs_file_t* llfs_file_open(const char* name) { LOG_DEBUG(TAG, "File not found: %s", name); return NULL; } + +llfs_file_t* llfs_next_file(void** mem, char* filter) { + struct llfs_data_file* prev_file = (struct llfs_data_file*)*mem; + uint8_t filter_ok = 0; + + if (prev_file == NULL) { + prev_file = llfs_root; + } else { + prev_file = (struct llfs_data_file*)prev_file->next; + } + + // If a filter is specified, only return files that match the filter + if (filter != NULL) { + LOG_DEBUG(TAG, "Filtering files with filter: %s", filter); + + // Remove the '*' from the filter + if (filter[0] == '*') { + filter++; + } + + while (prev_file != NULL) { + if (file_ext_cmp(prev_file->name, filter)) { + filter_ok = 1; + break; + } + prev_file = (struct llfs_data_file*)prev_file->next; + } + } + + *mem = (void*)prev_file; + return (llfs_file_t*)prev_file; +} + +size_t llfs_file_count(void) { + if (file_count == 0) { + const struct llfs_data_file* file = llfs_root; + while (file != NULL) { + file_count++; + file = file->next; + } + } + return file_count; +} + +/** + * @brief Newlib open implementation + * + * @param path + * @param flags + * @param mode + * @return + */ +int _open(char* path, int flags, int mode) { + int file_id; + FILE* stream; + errno = 0; + llfs_file_t* llfs_file; + + // Add a new entry to the file table + file_id = new_file_table_entry(); + if (file_id < 0) { + LOG_WARN(TAG, "Failed to add new file table entry. %s", strerror(errno)); + return -1; + } + + // Get the stream associated with the file id + stream = file_id_to_stream(file_id); + if (stream == NULL) { + LOG_WARN(TAG, "Failed to get file table entry. %s", strerror(errno)); + free_file_table_entry(file_id); + return -1; + } + + // Get the file from the llfs filesystem + llfs_file = llfs_file_open(path); + if (llfs_file == NULL) { + LOG_DEBUG(TAG, "Failed to open file: %s", path); + free_file_table_entry(file_id); + return -1; + } + + // Initialize the stream + stream->_cookie = (void*)llfs_file; + stream->_offset = 0; + stream->_flags = __SRD; + + return file_id; +} + +/** + * @brief Newlib close implementation + * + * @param file_id + * @return + */ +int _close(int file_id) { + FILE* stream; + + // Get the stream associated with the file id + stream = file_id_to_stream(file_id); + if (stream == NULL) { + LOG_WARN(TAG, "Failed to get file table entry. %s", strerror(errno)); + return -1; + } + + // Remove the entry from the file table + if (free_file_table_entry(file_id) < 0) { + LOG_WARN(TAG, "Failed to remove file table entry. %s", strerror(errno)); + return -1; + } + + return 0; +} + +/** + * @brief Newlib read implementation + * + * @param file_id + * @param ptr + * @param len + * @return + */ +int _read(int file_id, char* ptr, int len) { + FILE* stream; + llfs_file_t* llfs_file; + size_t bytes_read; + + // Read from stdin, stdout and stderr is not supported + if (file_id == STDIN_FILENO || file_id == STDOUT_FILENO || file_id == STDERR_FILENO) { + LOG_DEBUG(TAG, "Trying to read from stdin, stdout or stderr: %d", file_id); + return -1; + } + + // Get the stream associated with the file id + stream = file_id_to_stream(file_id); + if (stream == NULL) { + LOG_WARN(TAG, "Failed to get file table entry. %s", strerror(errno)); + return -1; + } + + // Get the file from the llfs filesystem associated with the stream + llfs_file = (llfs_file_t*)stream->_cookie; + if (llfs_file == NULL) { + LOG_WARN(TAG, "Failed to get llfs file associated with stream: %d", file_id); + return -1; + } + + // Calculate the number of bytes to read (limited by the file size) + bytes_read = llfs_file->len - stream->_offset; + if (bytes_read > len) { + bytes_read = len; + } else if (bytes_read == 0) { // End of file + stream->_flags |= __SEOF; + return 0; + } + + // Copy the data over to the dst buffer + memcpy(ptr, llfs_file->data + stream->_offset, bytes_read); + + stream->_offset += (off_t)bytes_read; + return (int)bytes_read; +} + +/** + * @brief Newlib isatty implementation + * + * @param file + * @return 1 if the file is stdin, stdout or stderr, 0 otherwise + */ +int isatty(int file) { + if (file == STDIN_FILENO || file == STDOUT_FILENO || file == STDERR_FILENO) { + return 1; + } + + return 0; +} + +/** + * @brief Newlib lseek implementation + * + * @param file + * @param ptr + * @param dir + * @return + */ +int _lseek(int file, int ptr, int dir) { + FILE* stream; + + if (file == STDIN_FILENO || file == STDOUT_FILENO || file == STDERR_FILENO) { + LOG_DEBUG(TAG, "Trying to seek stdin, stdout or stderr: %d", file); + return -1; + } + + stream = file_id_to_stream(file); + if (stream == NULL) { + LOG_WARN(TAG, "Failed to get file table entry. %s", strerror(errno)); + return -1; + } + + switch (dir) { + case SEEK_SET: + stream->_offset = ptr; + break; + case SEEK_CUR: + stream->_offset += ptr; + break; + case SEEK_END: + stream->_offset = (off_t)((llfs_file_t*)stream->_cookie)->len + ptr; + break; + default: + LOG_WARN(TAG, "Invalid seek direction: %d", dir); + return -1; + } + + return 0; +} + +/** + * @brief Newlib fstat implementation + * + * @param[in] file + * @param[out] st + * @return + */ +int _fstat(int file, struct stat* st) { + FILE* stream; + llfs_file_t *llfs_file; + + // Check if the file is stdin, stdout or stderr + if (file == STDIN_FILENO || file == STDOUT_FILENO || file == STDERR_FILENO) { + st->st_mode = S_IFCHR; // Character special file + return 0; + } + + // Get the stream associated with the file id + stream = file_id_to_stream(file); + if (stream == NULL) { + LOG_WARN(TAG, "Failed to get file table entry. %s", strerror(errno)); + return -1; + } + + // Get the file from the llfs filesystem associated with the stream + llfs_file = (llfs_file_t*)stream->_cookie; + if (llfs_file == NULL) { + LOG_WARN(TAG, "Failed to get llfs file associated with stream: %d", file); + return -1; + } + + st->st_mode = S_IFREG; // Regular file + st->st_size = (off_t)llfs_file->len; + return 0; +} + +/** + * @brief Create a new entry in the file table + * + * @return The file id or -1 if an error occurred. See errno for more information. + */ +static int new_file_table_entry(void) { + FILE* stream; + + // Try to find an empty entry in the file table + for (int i = 0; i < POSIX_MAX_FILES; i++) { + if (file_table[i] == NULL) { + stream = (FILE*)malloc(sizeof(FILE)); + if (stream == NULL) { + errno = ENOMEM; // Out of memory + return -1; + } + file_table[i] = stream; + return i; + } + } + + // No empty entry found + errno = ENFILE; // Too many open files + return -1; +} + +/** + * @brief Remove an entry from the file table + * + * @param[in] file_id The file id to remove + * @return 0 if successful, -1 if an error occurred. See errno for more information. + */ +static int free_file_table_entry(int file_id) { + // Check if the file id is valid + if (file_id < 0 || file_id >= POSIX_MAX_FILES) { + errno = EBADF; // Bad file number + return -1; + } + + // Remove the entry from the file table + free(file_table[file_id]); + file_table[file_id] = NULL; + + return 0; +} + +/** + * @brief Get the stream associated with a file id + * + * @param[in] file_id The file id to get the stream for + * @return The stream or NULL if an error occurred. See errno for more information. + */ +static FILE* file_id_to_stream(int file_id) { + if (file_id < 0 || file_id >= POSIX_MAX_FILES) { + errno = EBADF; // Bad file number + return NULL; + } + return file_table[file_id]; +} + + + +/** + * @brief Check if a filename ends with a given extension + * + * @param[in] filename The filename to check + * @param[in] ext The extension to check for + * @return 1 if the filename ends with the extension, 0 otherwise + */ +static uint8_t file_ext_cmp(const char* const filename, const char* const ext) { + uint8_t ext_len = strlen(ext); + uint8_t filename_len = strlen(filename); + + if (filename_len < ext_len) { + return 0; + } + + // Compare backwards + for (uint8_t i = 0; i < ext_len; i++) { + if (filename[filename_len - i] != ext[ext_len - i]) { + return 0; + } + } + return 1; +} diff --git a/project/Core/Src/main.c b/project/Core/Src/main.c index 0875149..6af0c87 100644 --- a/project/Core/Src/main.c +++ b/project/Core/Src/main.c @@ -1,507 +1,656 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file : main.c - * @brief : Main program body - ****************************************************************************** - * @attention - * - * Copyright (c) 2023 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ -/* USER CODE END Header */ -/* Includes ------------------------------------------------------------------*/ -#include "main.h" -#include "lwip.h" - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ -#define LOGGER_LEVEL_ALL -#include "log.h" - -#include "lcd_api.h" -/* USER CODE END Includes */ - -/* Private typedef -----------------------------------------------------------*/ -/* USER CODE BEGIN PTD */ - -/* USER CODE END PTD */ - -/* Private define ------------------------------------------------------------*/ -/* USER CODE BEGIN PD */ -static const char *TAG = "main"; -/* USER CODE END PD */ - -/* Private macro -------------------------------------------------------------*/ -/* USER CODE BEGIN PM */ - -/* USER CODE END PM */ - -/* Private variables ---------------------------------------------------------*/ - -DMA2D_HandleTypeDef hdma2d; - -LTDC_HandleTypeDef hltdc; - -QSPI_HandleTypeDef hqspi; - -UART_HandleTypeDef huart1; - -SDRAM_HandleTypeDef hsdram1; - -/* USER CODE BEGIN PV */ - -/* USER CODE END PV */ - -/* Private function prototypes -----------------------------------------------*/ -void SystemClock_Config(void); -static void MX_GPIO_Init(void); -static void MX_LTDC_Init(void); -static void MX_USART1_UART_Init(void); -static void MX_DMA2D_Init(void); -static void MX_FMC_Init(void); -static void MX_QUADSPI_Init(void); -/* USER CODE BEGIN PFP */ - -/* USER CODE END PFP */ - -/* Private user code ---------------------------------------------------------*/ -/* USER CODE BEGIN 0 */ - -/* 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_LTDC_Init(); - MX_USART1_UART_Init(); - MX_DMA2D_Init(); - MX_FMC_Init(); - MX_LWIP_Init(); - MX_QUADSPI_Init(); - /* USER CODE BEGIN 2 */ - lcd_init(true); - /* USER CODE END 2 */ - /* Infinite loop */ - /* USER CODE BEGIN WHILE */ - while (1) - { - /* USER CODE END WHILE */ - - /* USER CODE BEGIN 3 */ - MX_LWIP_Process(); - } - /* USER CODE END 3 */ -} - -/** - * @brief System Clock Configuration - * @retval None - */ -void SystemClock_Config(void) -{ - RCC_OscInitTypeDef RCC_OscInitStruct = {0}; - RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; - - /** Configure LSE Drive Capability - */ - HAL_PWR_EnableBkUpAccess(); - - /** Configure the main internal regulator output voltage - */ - __HAL_RCC_PWR_CLK_ENABLE(); - __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); - - /** Initializes the RCC Oscillators according to the specified parameters - * in the RCC_OscInitTypeDef structure. - */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; - RCC_OscInitStruct.HSEState = RCC_HSE_ON; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; - RCC_OscInitStruct.PLL.PLLM = 25; - RCC_OscInitStruct.PLL.PLLN = 400; - RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; - RCC_OscInitStruct.PLL.PLLQ = 2; - if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) - { - Error_Handler(); - } - - /** Activate the Over-Drive mode - */ - if (HAL_PWREx_EnableOverDrive() != 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_DIV4; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; - - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6) != HAL_OK) - { - Error_Handler(); - } -} - -/** - * @brief DMA2D Initialization Function - * @param None - * @retval None - */ -static void MX_DMA2D_Init(void) -{ - - /* USER CODE BEGIN DMA2D_Init 0 */ - - /* USER CODE END DMA2D_Init 0 */ - - /* USER CODE BEGIN DMA2D_Init 1 */ - - /* USER CODE END DMA2D_Init 1 */ - hdma2d.Instance = DMA2D; - hdma2d.Init.Mode = DMA2D_M2M; - hdma2d.Init.ColorMode = DMA2D_OUTPUT_ARGB8888; - hdma2d.Init.OutputOffset = 0; - hdma2d.LayerCfg[1].InputOffset = 0; - hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888; - hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA; - hdma2d.LayerCfg[1].InputAlpha = 0; - if (HAL_DMA2D_Init(&hdma2d) != HAL_OK) - { - Error_Handler(); - } - if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) != HAL_OK) - { - Error_Handler(); - } - /* USER CODE BEGIN DMA2D_Init 2 */ - - /* USER CODE END DMA2D_Init 2 */ - -} - -/** - * @brief LTDC Initialization Function - * @param None - * @retval None - */ -static void MX_LTDC_Init(void) -{ - - /* USER CODE BEGIN LTDC_Init 0 */ - - /* USER CODE END LTDC_Init 0 */ - - LTDC_LayerCfgTypeDef pLayerCfg = {0}; - LTDC_LayerCfgTypeDef pLayerCfg1 = {0}; - - /* USER CODE BEGIN LTDC_Init 1 */ - - /* USER CODE END LTDC_Init 1 */ - hltdc.Instance = LTDC; - hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL; - hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL; - hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL; - hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC; - hltdc.Init.HorizontalSync = 40; - hltdc.Init.VerticalSync = 9; - hltdc.Init.AccumulatedHBP = 53; - hltdc.Init.AccumulatedVBP = 11; - hltdc.Init.AccumulatedActiveW = 533; - hltdc.Init.AccumulatedActiveH = 283; - hltdc.Init.TotalWidth = 565; - hltdc.Init.TotalHeigh = 285; - hltdc.Init.Backcolor.Blue = 0; - hltdc.Init.Backcolor.Green = 255; - hltdc.Init.Backcolor.Red = 0; - if (HAL_LTDC_Init(&hltdc) != HAL_OK) - { - Error_Handler(); - } - pLayerCfg.WindowX0 = 0; - pLayerCfg.WindowX1 = 480; - pLayerCfg.WindowY0 = 0; - pLayerCfg.WindowY1 = 272; - pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB1555; - pLayerCfg.Alpha = 255; - pLayerCfg.Alpha0 = 0; - pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; - pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; - pLayerCfg.FBStartAdress = 0; - pLayerCfg.ImageWidth = 480; - pLayerCfg.ImageHeight = 272; - pLayerCfg.Backcolor.Blue = 0; - pLayerCfg.Backcolor.Green = 0; - pLayerCfg.Backcolor.Red = 0; - if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK) - { - Error_Handler(); - } - pLayerCfg1.WindowX0 = 0; - pLayerCfg1.WindowX1 = 480; - pLayerCfg1.WindowY0 = 0; - pLayerCfg1.WindowY1 = 272; - pLayerCfg1.PixelFormat = LTDC_PIXEL_FORMAT_ARGB1555; - pLayerCfg1.Alpha = 255; - pLayerCfg1.Alpha0 = 0; - pLayerCfg1.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; - pLayerCfg1.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; - pLayerCfg1.FBStartAdress = 0; - pLayerCfg1.ImageWidth = 480; - pLayerCfg1.ImageHeight = 272; - pLayerCfg1.Backcolor.Blue = 0; - pLayerCfg1.Backcolor.Green = 0; - pLayerCfg1.Backcolor.Red = 0; - if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg1, 1) != HAL_OK) - { - Error_Handler(); - } - /* USER CODE BEGIN LTDC_Init 2 */ - - /* USER CODE END LTDC_Init 2 */ - -} - -/** - * @brief QUADSPI Initialization Function - * @param None - * @retval None - */ -static void MX_QUADSPI_Init(void) -{ - - /* USER CODE BEGIN QUADSPI_Init 0 */ - - /* USER CODE END QUADSPI_Init 0 */ - - /* USER CODE BEGIN QUADSPI_Init 1 */ - - /* USER CODE END QUADSPI_Init 1 */ - /* QUADSPI parameter configuration*/ - hqspi.Instance = QUADSPI; - hqspi.Init.ClockPrescaler = 1; - hqspi.Init.FifoThreshold = 4; - hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; - hqspi.Init.FlashSize = 16; - hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE; - hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0; - hqspi.Init.FlashID = QSPI_FLASH_ID_1; - hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE; - if (HAL_QSPI_Init(&hqspi) != HAL_OK) - { - Error_Handler(); - } - /* USER CODE BEGIN QUADSPI_Init 2 */ - - /* USER CODE END QUADSPI_Init 2 */ - -} - -/** - * @brief USART1 Initialization Function - * @param None - * @retval None - */ -static void MX_USART1_UART_Init(void) -{ - - /* USER CODE BEGIN USART1_Init 0 */ - - /* USER CODE END USART1_Init 0 */ - - /* USER CODE BEGIN USART1_Init 1 */ - - /* USER CODE END USART1_Init 1 */ - huart1.Instance = USART1; - huart1.Init.BaudRate = 115200; - huart1.Init.WordLength = UART_WORDLENGTH_8B; - huart1.Init.StopBits = UART_STOPBITS_1; - huart1.Init.Parity = UART_PARITY_NONE; - huart1.Init.Mode = UART_MODE_TX_RX; - huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; - huart1.Init.OverSampling = UART_OVERSAMPLING_16; - huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; - huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; - if (HAL_UART_Init(&huart1) != HAL_OK) - { - Error_Handler(); - } - /* USER CODE BEGIN USART1_Init 2 */ - - /* USER CODE END USART1_Init 2 */ - -} - -/* FMC initialization function */ -static void MX_FMC_Init(void) -{ - - /* USER CODE BEGIN FMC_Init 0 */ - - /* USER CODE END FMC_Init 0 */ - - FMC_SDRAM_TimingTypeDef SdramTiming = {0}; - - /* USER CODE BEGIN FMC_Init 1 */ - - /* USER CODE END FMC_Init 1 */ - - /** Perform the SDRAM1 memory initialization sequence - */ - hsdram1.Instance = FMC_SDRAM_DEVICE; - /* hsdram1.Init */ - hsdram1.Init.SDBank = FMC_SDRAM_BANK1; - hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8; - hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; - hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16; - hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; - hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_1; - hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; - hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_DISABLE; - hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE; - hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; - /* SdramTiming */ - SdramTiming.LoadToActiveDelay = 16; - SdramTiming.ExitSelfRefreshDelay = 16; - SdramTiming.SelfRefreshTime = 16; - SdramTiming.RowCycleDelay = 16; - SdramTiming.WriteRecoveryTime = 16; - SdramTiming.RPDelay = 16; - SdramTiming.RCDDelay = 16; - - if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK) - { - Error_Handler( ); - } - - /* USER CODE BEGIN FMC_Init 2 */ - - /* USER CODE END FMC_Init 2 */ -} - -/** - * @brief GPIO Initialization Function - * @param None - * @retval None - */ -static void MX_GPIO_Init(void) -{ - GPIO_InitTypeDef GPIO_InitStruct = {0}; -/* USER CODE BEGIN MX_GPIO_Init_1 */ -/* USER CODE END MX_GPIO_Init_1 */ - - /* GPIO Ports Clock Enable */ - __HAL_RCC_GPIOE_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOJ_CLK_ENABLE(); - __HAL_RCC_GPIOD_CLK_ENABLE(); - __HAL_RCC_GPIOK_CLK_ENABLE(); - __HAL_RCC_GPIOF_CLK_ENABLE(); - __HAL_RCC_GPIOI_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOH_CLK_ENABLE(); - - /*Configure GPIO pin Output Level */ - HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_Port, LCD_BL_CTRL_Pin, GPIO_PIN_RESET); - - /*Configure GPIO pin Output Level */ - HAL_GPIO_WritePin(GPIOI, LED_Pin|LCD_DISP_Pin, GPIO_PIN_RESET); - - /*Configure GPIO pin : LCD_BL_CTRL_Pin */ - GPIO_InitStruct.Pin = LCD_BL_CTRL_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - HAL_GPIO_Init(LCD_BL_CTRL_GPIO_Port, &GPIO_InitStruct); - - /*Configure GPIO pins : LED_Pin LCD_DISP_Pin */ - GPIO_InitStruct.Pin = LED_Pin|LCD_DISP_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - HAL_GPIO_Init(GPIOI, &GPIO_InitStruct); - - /*Configure GPIO pin : BUTTON_Pin */ - GPIO_InitStruct.Pin = BUTTON_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(BUTTON_GPIO_Port, &GPIO_InitStruct); - -/* USER CODE BEGIN MX_GPIO_Init_2 */ -/* USER CODE END MX_GPIO_Init_2 */ -} - -/* 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 */ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.c + * @brief : Main program body + ****************************************************************************** + * @attention + * + * Copyright (c) 2023 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +#include "lwip.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ +#define LOGGER_LEVEL_ALL +#include "log.h" +#include "llfs.h" +#include "../../Drivers/BSP/STM32746G-Discovery/stm32746g_discovery_lcd.h" +#include "lcd_api.h" + +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN PTD */ + +/* USER CODE END PTD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ +static const char *TAG = "main"; +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ + +DMA2D_HandleTypeDef hdma2d; + +LTDC_HandleTypeDef hltdc; + +QSPI_HandleTypeDef hqspi; + +UART_HandleTypeDef huart1; + +SDRAM_HandleTypeDef hsdram1; + +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +void SystemClock_Config(void); +static void MX_GPIO_Init(void); +static void MX_LTDC_Init(void); +static void MX_USART1_UART_Init(void); +static void MX_DMA2D_Init(void); +static void MX_FMC_Init(void); +static void MX_QUADSPI_Init(void); +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* Private user code ---------------------------------------------------------*/ +/* USER CODE BEGIN 0 */ + +/* 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_LTDC_Init(); + MX_USART1_UART_Init(); + MX_DMA2D_Init(); + MX_FMC_Init(); + MX_LWIP_Init(); + MX_QUADSPI_Init(); + /* USER CODE BEGIN 2 */ + lcd_init(true); + + llfs_init(); + + + FILE *f = fopen("test.txt", "rw"); + if (f == NULL) { + LOG_INFO(TAG, "File not found test.txt"); + return 1; + } else { + LOG_INFO(TAG, "File found test.txt"); + } + + // Test POSIX file operations + // fgetc + int c; + printf("Printing file:\n"); + while ((c = fgetc(f)) != EOF) { + printf("%c", c); + } + LOG_INFO(TAG, "File printed"); + + // fseek + fseek(f, 0, SEEK_SET); + LOG_INFO(TAG, "File seeked to start"); + + // ftell + long pos = ftell(f); + LOG_INFO(TAG, "File position: %d", pos); + + // fread + char buf[100]; + size_t bytes_read = fread(buf, 1, 100, f); + LOG_INFO(TAG, "Read %d bytes from file", bytes_read); + printf("Read from file:\n"); + for (int i = 0; i < bytes_read; i++) { + printf("%c", buf[i]); + } + + // Rewind the file + LOG_INFO(TAG, "Before File rewinded, pos: %d", ftell(f)); + rewind(f); + LOG_INFO(TAG, "File rewinded, pos: %d", ftell(f)); + + // Get the file size fstat + struct stat st; + fstat(fileno(f), &st); + LOG_INFO(TAG, "File size: %d", st.st_size); + + + // Get a list of all files with the .bmp extension + llfs_file_t file_list[10]; + size_t num_files = llfs_file_list(file_list, 10, "*.bmp"); + LOG_INFO(TAG, "Found %d files with the .bmp extension", num_files); + for (int i = 0; i < num_files; i++) { + LOG_INFO(TAG, "File %d: %s", i, file_list[i].name); + } + + // Get a list of files with .txt or .html + num_files = llfs_file_list(file_list, 10, "*.txt"); + LOG_INFO(TAG, "Found %d files with the .txt or .html extension", num_files); + for (int i = 0; i < num_files; i++) { + LOG_INFO(TAG, "File %d: %s", i, file_list[i].name); + } + + // Loop over all files using the iterator + LOG_INFO(TAG, "Looping over all files, using the iterator"); + void *mem = NULL; + llfs_file_t *file; + while ((file = llfs_next_file(&mem, NULL)) != NULL) { + LOG_INFO(TAG, "File: %s", file->name); + } + + // Loop over all files with the .bmp extension using the iterator + LOG_INFO(TAG, "Looping over all files with the .bmp extension, using the iterator"); + mem = NULL; + while ((file = llfs_next_file(&mem, "*.bmp")) != NULL) { + LOG_INFO(TAG, "File: %s", file->name); + } + + // Get the number of files in the filesystem + size_t num_files_in_fs = llfs_file_count(); + LOG_INFO(TAG, "Number of files in the filesystem: %d", num_files_in_fs); + + + fclose(f); + + // Try opening multiple files + LOG_INFO(TAG, "Opening an closing multiple files"); + FILE * f1 = fopen("test.txt", "rw"); + if (f1 == NULL) { + LOG_INFO(TAG, "File not found f1"); + return 1; + } else { + LOG_INFO(TAG, "File found f1"); + } + // Get the fileno + int fd = fileno(f1); + LOG_INFO(TAG, "File descriptor f1: %d", fd); + + FILE * f2 = fopen("test.txt", "rw"); + if (f2 == NULL) { + LOG_INFO(TAG, "File not found f2"); + return 1; + } else { + LOG_INFO(TAG, "File found f2"); + } + // Get the fileno + fd = fileno(f2); + LOG_INFO(TAG, "File descriptorf2: %d", fd); + + LOG_INFO(TAG, "Closing f1"); + fclose(f1); + + FILE * f3 = fopen("test.txt", "rw"); + if (f3 == NULL) { + LOG_INFO(TAG, "File not found f3"); + return 1; + } else { + LOG_INFO(TAG, "File found f3"); + } + // Get the fileno + fd = fileno(f3); + LOG_INFO(TAG, "File descriptor f3: %d", fd); + + LOG_INFO(TAG, "Closing f2"); + fclose(f2); + + LOG_INFO(TAG, "Closing f3"); + fclose(f3); + + // Try opening a file multiple times, until it fails + int i = 0; + LOG_INFO(TAG, "Opening a file multiple times, until it fails"); + while (1) { + f = fopen("test.txt", "rw"); + LOG_INFO(TAG, "File descriptor: %d", fileno(f)); + if (f == NULL) { + LOG_INFO(TAG, "File not found test.txt"); + break; + } else { + LOG_INFO(TAG, "File found test.txt"); + } + i++; + } + LOG_INFO(TAG, "File opened %d times", i); + + + /* USER CODE END 2 */ + /* Infinite loop */ + /* USER CODE BEGIN WHILE */ + while (1) + { + /* USER CODE END WHILE */ + + /* USER CODE BEGIN 3 */ + MX_LWIP_Process(); + } + /* USER CODE END 3 */ +} + +/** + * @brief System Clock Configuration + * @retval None + */ +void SystemClock_Config(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + + /** Configure LSE Drive Capability + */ + HAL_PWR_EnableBkUpAccess(); + + /** Configure the main internal regulator output voltage + */ + __HAL_RCC_PWR_CLK_ENABLE(); + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLM = 25; + RCC_OscInitStruct.PLL.PLLN = 400; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; + RCC_OscInitStruct.PLL.PLLQ = 2; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) + { + Error_Handler(); + } + + /** Activate the Over-Drive mode + */ + if (HAL_PWREx_EnableOverDrive() != 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_DIV4; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6) != HAL_OK) + { + Error_Handler(); + } +} + +/** + * @brief DMA2D Initialization Function + * @param None + * @retval None + */ +static void MX_DMA2D_Init(void) +{ + + /* USER CODE BEGIN DMA2D_Init 0 */ + + /* USER CODE END DMA2D_Init 0 */ + + /* USER CODE BEGIN DMA2D_Init 1 */ + + /* USER CODE END DMA2D_Init 1 */ + hdma2d.Instance = DMA2D; + hdma2d.Init.Mode = DMA2D_M2M; + hdma2d.Init.ColorMode = DMA2D_OUTPUT_ARGB8888; + hdma2d.Init.OutputOffset = 0; + hdma2d.LayerCfg[1].InputOffset = 0; + hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888; + hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA; + hdma2d.LayerCfg[1].InputAlpha = 0; + if (HAL_DMA2D_Init(&hdma2d) != HAL_OK) + { + Error_Handler(); + } + if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN DMA2D_Init 2 */ + + /* USER CODE END DMA2D_Init 2 */ + +} + +/** + * @brief LTDC Initialization Function + * @param None + * @retval None + */ +static void MX_LTDC_Init(void) +{ + + /* USER CODE BEGIN LTDC_Init 0 */ + + /* USER CODE END LTDC_Init 0 */ + + LTDC_LayerCfgTypeDef pLayerCfg = {0}; + LTDC_LayerCfgTypeDef pLayerCfg1 = {0}; + + /* USER CODE BEGIN LTDC_Init 1 */ + + /* USER CODE END LTDC_Init 1 */ + hltdc.Instance = LTDC; + hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL; + hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL; + hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL; + hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC; + hltdc.Init.HorizontalSync = 40; + hltdc.Init.VerticalSync = 9; + hltdc.Init.AccumulatedHBP = 53; + hltdc.Init.AccumulatedVBP = 11; + hltdc.Init.AccumulatedActiveW = 533; + hltdc.Init.AccumulatedActiveH = 283; + hltdc.Init.TotalWidth = 565; + hltdc.Init.TotalHeigh = 285; + hltdc.Init.Backcolor.Blue = 0; + hltdc.Init.Backcolor.Green = 255; + hltdc.Init.Backcolor.Red = 0; + if (HAL_LTDC_Init(&hltdc) != HAL_OK) + { + Error_Handler(); + } + pLayerCfg.WindowX0 = 0; + pLayerCfg.WindowX1 = 480; + pLayerCfg.WindowY0 = 0; + pLayerCfg.WindowY1 = 272; + pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB1555; + pLayerCfg.Alpha = 255; + pLayerCfg.Alpha0 = 0; + pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; + pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; + pLayerCfg.FBStartAdress = 0; + pLayerCfg.ImageWidth = 480; + pLayerCfg.ImageHeight = 272; + pLayerCfg.Backcolor.Blue = 0; + pLayerCfg.Backcolor.Green = 0; + pLayerCfg.Backcolor.Red = 0; + if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK) + { + Error_Handler(); + } + pLayerCfg1.WindowX0 = 0; + pLayerCfg1.WindowX1 = 480; + pLayerCfg1.WindowY0 = 0; + pLayerCfg1.WindowY1 = 272; + pLayerCfg1.PixelFormat = LTDC_PIXEL_FORMAT_ARGB1555; + pLayerCfg1.Alpha = 255; + pLayerCfg1.Alpha0 = 0; + pLayerCfg1.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; + pLayerCfg1.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; + pLayerCfg1.FBStartAdress = 0; + pLayerCfg1.ImageWidth = 480; + pLayerCfg1.ImageHeight = 272; + pLayerCfg1.Backcolor.Blue = 0; + pLayerCfg1.Backcolor.Green = 0; + pLayerCfg1.Backcolor.Red = 0; + if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg1, 1) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN LTDC_Init 2 */ + + /* USER CODE END LTDC_Init 2 */ + +} + +/** + * @brief QUADSPI Initialization Function + * @param None + * @retval None + */ +static void MX_QUADSPI_Init(void) +{ + + /* USER CODE BEGIN QUADSPI_Init 0 */ + + /* USER CODE END QUADSPI_Init 0 */ + + /* USER CODE BEGIN QUADSPI_Init 1 */ + + /* USER CODE END QUADSPI_Init 1 */ + /* QUADSPI parameter configuration*/ + hqspi.Instance = QUADSPI; + hqspi.Init.ClockPrescaler = 1; + hqspi.Init.FifoThreshold = 4; + hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; + hqspi.Init.FlashSize = 16; + hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE; + hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0; + hqspi.Init.FlashID = QSPI_FLASH_ID_1; + hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE; + if (HAL_QSPI_Init(&hqspi) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN QUADSPI_Init 2 */ + + /* USER CODE END QUADSPI_Init 2 */ + +} + +/** + * @brief USART1 Initialization Function + * @param None + * @retval None + */ +static void MX_USART1_UART_Init(void) +{ + + /* USER CODE BEGIN USART1_Init 0 */ + + /* USER CODE END USART1_Init 0 */ + + /* USER CODE BEGIN USART1_Init 1 */ + + /* USER CODE END USART1_Init 1 */ + huart1.Instance = USART1; + huart1.Init.BaudRate = 115200; + huart1.Init.WordLength = UART_WORDLENGTH_8B; + huart1.Init.StopBits = UART_STOPBITS_1; + huart1.Init.Parity = UART_PARITY_NONE; + huart1.Init.Mode = UART_MODE_TX_RX; + huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart1.Init.OverSampling = UART_OVERSAMPLING_16; + huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; + huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; + if (HAL_UART_Init(&huart1) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN USART1_Init 2 */ + + /* USER CODE END USART1_Init 2 */ + +} + +/* FMC initialization function */ +static void MX_FMC_Init(void) +{ + + /* USER CODE BEGIN FMC_Init 0 */ + + /* USER CODE END FMC_Init 0 */ + + FMC_SDRAM_TimingTypeDef SdramTiming = {0}; + + /* USER CODE BEGIN FMC_Init 1 */ + + /* USER CODE END FMC_Init 1 */ + + /** Perform the SDRAM1 memory initialization sequence + */ + hsdram1.Instance = FMC_SDRAM_DEVICE; + /* hsdram1.Init */ + hsdram1.Init.SDBank = FMC_SDRAM_BANK1; + hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8; + hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; + hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16; + hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; + hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_1; + hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; + hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_DISABLE; + hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE; + hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; + /* SdramTiming */ + SdramTiming.LoadToActiveDelay = 16; + SdramTiming.ExitSelfRefreshDelay = 16; + SdramTiming.SelfRefreshTime = 16; + SdramTiming.RowCycleDelay = 16; + SdramTiming.WriteRecoveryTime = 16; + SdramTiming.RPDelay = 16; + SdramTiming.RCDDelay = 16; + + if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK) + { + Error_Handler( ); + } + + /* USER CODE BEGIN FMC_Init 2 */ + + /* USER CODE END FMC_Init 2 */ +} + +/** + * @brief GPIO Initialization Function + * @param None + * @retval None + */ +static void MX_GPIO_Init(void) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; +/* USER CODE BEGIN MX_GPIO_Init_1 */ +/* USER CODE END MX_GPIO_Init_1 */ + + /* GPIO Ports Clock Enable */ + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOJ_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOK_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_Port, LCD_BL_CTRL_Pin, GPIO_PIN_RESET); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(GPIOI, LED_Pin|LCD_DISP_Pin, GPIO_PIN_RESET); + + /*Configure GPIO pin : LCD_BL_CTRL_Pin */ + GPIO_InitStruct.Pin = LCD_BL_CTRL_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(LCD_BL_CTRL_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pins : LED_Pin LCD_DISP_Pin */ + GPIO_InitStruct.Pin = LED_Pin|LCD_DISP_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(GPIOI, &GPIO_InitStruct); + + /*Configure GPIO pin : BUTTON_Pin */ + GPIO_InitStruct.Pin = BUTTON_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(BUTTON_GPIO_Port, &GPIO_InitStruct); + +/* USER CODE BEGIN MX_GPIO_Init_2 */ +/* USER CODE END MX_GPIO_Init_2 */ +} + +/* 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 */ diff --git a/project/Core/Src/syscalls.c b/project/Core/Src/syscalls.c index d190edf..ede9e3a 100644 --- a/project/Core/Src/syscalls.c +++ b/project/Core/Src/syscalls.c @@ -89,14 +89,14 @@ __attribute__((weak)) int _write(int file, char *ptr, int len) return len; } -int _close(int file) +__attribute__((weak)) int _close(int file) { (void)file; return -1; } -int _fstat(int file, struct stat *st) +__attribute__((weak)) int _fstat(int file, struct stat *st) { (void)file; st->st_mode = S_IFCHR; @@ -109,7 +109,7 @@ int _isatty(int file) return 1; } -int _lseek(int file, int ptr, int dir) +__attribute__((weak)) int _lseek(int file, int ptr, int dir) { (void)file; (void)ptr; @@ -117,7 +117,7 @@ int _lseek(int file, int ptr, int dir) return 0; } -int _open(char *path, int flags, ...) +__attribute__((weak)) int _open(char *path, int flags, ...) { (void)path; (void)flags; @@ -145,7 +145,7 @@ int _times(struct tms *buf) return -1; } -int _stat(char *file, struct stat *st) +__attribute__((weak)) int _stat(char *file, struct stat *st) { (void)file; st->st_mode = S_IFCHR;