diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 886a204..7bc9b27 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,6 +34,7 @@ jobs: run: | make -s stm32f103 make -s stm32g0b1 + make -s stm32h753xx make -s ubuntu test_params_generator: diff --git a/Makefile b/Makefile index c65c388..0444c1d 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,11 @@ stm32g0b1: clean -DCMAKE_TOOLCHAIN_FILE=${ROOT_DIR}/tests/platform_specific/cmake/arm-none-eabi-toolchain.cmake cmake --build build/tests/platform_specific/stm32g0b1 +stm32h753xx: clean + cmake -S tests/platform_specific/stm32h753xx -B build/tests/platform_specific/stm32h753xx \ + -DCMAKE_TOOLCHAIN_FILE=${ROOT_DIR}/tests/platform_specific/cmake/arm-none-eabi-toolchain.cmake + cmake --build build/tests/platform_specific/stm32h753xx + UBUNTU_BUILD_DIR=${ROOT_DIR}/build/tests/platform_specific/ubuntu UBUNTU_CMAKE_DIR=${ROOT_DIR}/tests/platform_specific/ubuntu ubuntu: clean diff --git a/README.md b/README.md index a67f43f..2743713 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ Look at [libparams/storage.h](libparams/storage.h) to get full API and [src/stor ROM driver simply allows you to write and read sequence of bytes. Mainly, it consist of 3 operations. -1. Initialization. It is necessary to call `romInit()` to configure the driver. Storage driver do it automatically. +1. Initialization. It is necessary to call `romInit()` with flash driver ops to configure the driver. Storage driver do it automatically. 2. Read operation. You just need to call `romRead` with corresponded arguments. @@ -174,9 +174,15 @@ The initialization of the application can be as shown below: ```c++ #include "params.h" +#include "flash_driver.h" +#include "platform_flash_driver.h" void application_example() { - paramsInit(IntParamsIndexes::INTEGER_PARAMS_AMOUNT, StrParamsIndexes::STRING_PARAMS_AMOUNT, -1, 1); + paramsInit(stm32h753xxInternalFlashGetOps(), + IntParamsIndexes::INTEGER_PARAMS_AMOUNT, + StrParamsIndexes::STRING_PARAMS_AMOUNT, + -1, + 1); paramsLoad(); } ``` diff --git a/include/libparams/flash_driver.h b/include/libparams/flash_driver.h index 6364f68..73058d6 100644 --- a/include/libparams/flash_driver.h +++ b/include/libparams/flash_driver.h @@ -18,40 +18,18 @@ extern "C" { #endif +typedef struct { + void (*init)(void); + int8_t (*unlock)(void); + int8_t (*lock)(void); + int8_t (*erase)(uint32_t start_page_idx, uint32_t num_of_pages); + int32_t (*write)(const uint8_t* data, size_t offset, size_t bytes_to_write); + size_t (*read)(uint8_t* data, size_t offset, size_t bytes_to_read); + uint16_t (*get_number_of_pages)(void); + uint32_t (*get_page_size)(void); + size_t start_addr; +} FlashDriverOps; -/** - * @brief Do nothing at the moment, but reserved for future possible updates - */ -void flashInit(); - -/** - * @param start_page_idx starts from 0 up to maximum number of pages - * @param num_of_pages last page should not be above flashGetNumberOfPages() - * @return 0 if success, otherwise < 0 - */ -int8_t flashErase(uint32_t start_page_idx, uint32_t num_of_pages); - -/** - * @brief Before writing you must call flashUnlock(), after writing you must call flashLock() - * Write chunk of data like memcpy - * @return number of written bytes if success, otherwise < 0 - */ -int8_t flashUnlock(); -int32_t flashWrite(const uint8_t* data, size_t offset, size_t bytes_to_write); -int8_t flashLock(); - -/** - * @brief Read chunk of data like memcpy - * @return bytes_to_read if success, otherwise 0 - */ -size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read); - - -/** - * @return Info about the flash memory - */ -uint16_t flashGetNumberOfPages(); -uint32_t flashGetPageSize(); #ifdef __cplusplus } diff --git a/include/libparams/rom.h b/include/libparams/rom.h index fc25522..892de31 100644 --- a/include/libparams/rom.h +++ b/include/libparams/rom.h @@ -12,6 +12,7 @@ #include #include #include +#include "flash_driver.h" #ifdef __cplusplus extern "C" { @@ -23,6 +24,7 @@ extern "C" { * Use romInit() to create an instance. */ typedef struct { + const FlashDriverOps* flash; size_t addr; size_t first_page_idx; size_t total_size; @@ -41,9 +43,9 @@ typedef struct { * On Ubuntu platform, it is safe to use -1 even if it has a single page (equal to idx=0). * @param pages_num The amount of allocated pages. At least 1 page is required. * @return ROM driver instance. It will have inited=true on success and inited=false on failure. - * @note Example of a single latest page allocation: romInit(-1, 1) + * @note Example of a single latest page allocation: romInit(stm32h753xxInternalFlashGetOps(), -1, 1) */ -RomDriverInstance romInit(int32_t first_page_idx, size_t pages_amount); +RomDriverInstance romInit(const FlashDriverOps* flash, int32_t first_page_idx, size_t pages_amount); /** * @brief Return the number of bytes read (may be less than requested_size). diff --git a/include/libparams/storage.h b/include/libparams/storage.h index d4254f3..26f1abd 100644 --- a/include/libparams/storage.h +++ b/include/libparams/storage.h @@ -74,6 +74,7 @@ typedef uint16_t ParamIndex_t; /** * @brief Initialize the parameters. Call this on startup. + * @param flash Flash driver operations used as parameter storage. * @param int_num The amount of integers parameters * @param str_num The amount of string parameters * @param first_page_idx Index of the first page. Negative values are counted from the end. @@ -81,7 +82,9 @@ typedef uint16_t ParamIndex_t; * @param pages_num The amount of allocated pages. At least 1 page is required. * @return LIBPARAMS_OK on success, otherwise < 0. */ -int8_t paramsInit(ParamIndex_t int_num, ParamIndex_t str_num, +int8_t paramsInit(const FlashDriverOps* flash, + ParamIndex_t int_num, + ParamIndex_t str_num, int32_t first_page_idx, size_t pages_num); /** diff --git a/libparams.cmake b/libparams.cmake index d7f88ca..acc382e 100644 --- a/libparams.cmake +++ b/libparams.cmake @@ -18,10 +18,24 @@ FILE(GLOB libparamsPlatformSpecificSrc ${CMAKE_CURRENT_LIST_DIR}/platform_specific/${LIBPARAMS_PLATFORM}/*.c* ) +if(LIBPARAMS_PLATFORM STREQUAL "stm32h753xx") + FILE(GLOB libparamsStm32h753xxSpiFramSrc + ${CMAKE_CURRENT_LIST_DIR}/platform_specific/stm32h753xx/stm32h753xx_spifram/*.c* + ) + list(APPEND libparamsPlatformSpecificSrc ${libparamsStm32h753xxSpiFramSrc}) +endif() + FILE(GLOB libparamsPlatformSpecificHeaders ${CMAKE_CURRENT_LIST_DIR}/platform_specific/${LIBPARAMS_PLATFORM}/ ) +set(libparamsExtraPlatformHeaders) +if(LIBPARAMS_PLATFORM STREQUAL "stm32h753xx") + list(APPEND libparamsExtraPlatformHeaders + ${CMAKE_CURRENT_LIST_DIR}/platform_specific/stm32h753xx/stm32h753xx_spifram/ + ) +endif() + set(libparamsSrc ${CMAKE_CURRENT_LIST_DIR}/src/rom.c ${CMAKE_CURRENT_LIST_DIR}/src/storage.c @@ -32,4 +46,5 @@ set(libparamsHeaders ${CMAKE_CURRENT_LIST_DIR}/include/libparams/ ${CMAKE_CURRENT_LIST_DIR}/platform_specific/${LIBPARAMS_PLATFORM}/ ${libparamsPlatformSpecificHeaders} + ${libparamsExtraPlatformHeaders} ) diff --git a/platform_specific/stm32f103/flash_driver.c b/platform_specific/stm32f103/flash_driver.c index c859d53..8887c5a 100644 --- a/platform_specific/stm32f103/flash_driver.c +++ b/platform_specific/stm32f103/flash_driver.c @@ -8,6 +8,7 @@ #include "flash_driver.h" #include +#include "platform_flash_driver.h" #include "libparams_error_codes.h" #include "flash_registers.h" @@ -21,21 +22,29 @@ uint32_t HAL_GetTick(); +static void flashInit(void); +static int8_t flashUnlock(void); +static int8_t flashLock(void); +static int8_t flashErase(uint32_t start_page_idx, uint32_t num_of_pages); +static int32_t flashWrite(const uint8_t* data, size_t offset, size_t size); +static size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read); +static uint16_t flashGetNumberOfPages(void); +static uint32_t flashGetPageSize(void); static uint8_t* flashGetPointer(); static int8_t flashWaitForLastOperation(uint32_t timeout); static void flashPageErase(uint32_t page_address); static void flashProgramHalfWord(uint32_t address, uint16_t data); -void flashInit() { +static void flashInit(void) { } -int8_t flashUnlock() { +static int8_t flashUnlock(void) { WRITE_REG(FLASH->KEYR, FLASH_KEYR_KEY1); WRITE_REG(FLASH->KEYR, FLASH_KEYR_KEY2); return 0; } -int8_t flashLock() { +static int8_t flashLock(void) { SET_BIT(FLASH->CR, FLASH_CR_LOCK); return 0; } @@ -46,7 +55,7 @@ int8_t flashLock() { * max 40 ms * @note from https://www.st.com/resource/en/datasheet/stm32f103c8.pdf */ -int8_t flashErase(uint32_t start_page_idx, uint32_t num_of_pages) { +static int8_t flashErase(uint32_t start_page_idx, uint32_t num_of_pages) { if (flashWaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE) != 0) { return -1; } @@ -70,7 +79,7 @@ static uint8_t* flashGetPointer() { return (uint8_t*) FLASH_START_ADDR; } -int32_t flashWrite(const uint8_t* data, size_t offset, size_t size) { +static int32_t flashWrite(const uint8_t* data, size_t offset, size_t size) { int32_t status = flashWaitForLastOperation(FLASH_TIMEOUT_VALUE); if (status < 0) { @@ -92,7 +101,7 @@ int32_t flashWrite(const uint8_t* data, size_t offset, size_t size) { return status; } -size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read) { +static size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read) { if (data == NULL) { return 0; } @@ -102,14 +111,29 @@ size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read) { return bytes_to_read; } -uint16_t flashGetNumberOfPages() { +static uint16_t flashGetNumberOfPages(void) { return 128; } -uint32_t flashGetPageSize() { +static uint32_t flashGetPageSize(void) { return FLASH_PAGE_SIZE; } +const FlashDriverOps* stm32f103InternalFlashGetOps(void) { + static const FlashDriverOps ops = { + flashInit, + flashUnlock, + flashLock, + flashErase, + flashWrite, + flashRead, + flashGetNumberOfPages, + flashGetPageSize, + FLASH_START_ADDR, + }; + return &ops; +} + static int8_t flashWaitForLastOperation(uint32_t timeout) { uint32_t tickstart = HAL_GetTick(); diff --git a/platform_specific/stm32f103/platform_flash_driver.h b/platform_specific/stm32f103/platform_flash_driver.h new file mode 100644 index 0000000..dc80d2a --- /dev/null +++ b/platform_specific/stm32f103/platform_flash_driver.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2026 Ilia Kliantsevich + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef LIBPARAMS_STM32F103_PLATFORM_FLASH_DRIVER_H_ +#define LIBPARAMS_STM32F103_PLATFORM_FLASH_DRIVER_H_ + +#include "flash_driver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const FlashDriverOps* stm32f103InternalFlashGetOps(void); + +#ifdef __cplusplus +} +#endif + +#endif // LIBPARAMS_STM32F103_PLATFORM_FLASH_DRIVER_H_ diff --git a/platform_specific/stm32g0b1/flash_driver.c b/platform_specific/stm32g0b1/flash_driver.c index a361c67..c4df894 100644 --- a/platform_specific/stm32g0b1/flash_driver.c +++ b/platform_specific/stm32g0b1/flash_driver.c @@ -8,10 +8,19 @@ #include "flash_driver.h" #include +#include "platform_flash_driver.h" #include "main.h" #include "libparams_error_codes.h" +static void flashInit(void); +static int8_t flashUnlock(void); +static int8_t flashLock(void); +static int8_t flashErase(uint32_t first_page_idx, uint32_t num_of_pages); +static int32_t flashWrite(const uint8_t* data, size_t offset, size_t size); +static size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read); +static uint16_t flashGetNumberOfPages(void); +static uint32_t flashGetPageSize(void); static uint8_t* flashGetPointer(); static int8_t flashErasePagessInSingleBank(uint32_t first_page_idx, uint32_t num_of_pages); static int8_t flashWriteU64(uint32_t address, uint64_t data); @@ -20,13 +29,13 @@ static int8_t flashWriteU64(uint32_t address, uint64_t data); static const size_t FLASH_WORD_SIZE = 8; -void flashInit() { +static void flashInit(void) { } -int8_t flashUnlock() { +static int8_t flashUnlock(void) { return -HAL_FLASH_Unlock(); } -int8_t flashLock() { +static int8_t flashLock(void) { return -HAL_FLASH_Lock(); } @@ -36,7 +45,7 @@ int8_t flashLock() { * max 40 ms * @note from https://www.st.com/resource/en/datasheet/stm32g030c6.pdf */ -int8_t flashErase(uint32_t first_page_idx, uint32_t num_of_pages) { +static int8_t flashErase(uint32_t first_page_idx, uint32_t num_of_pages) { uint32_t last_page_idx = first_page_idx + num_of_pages; if (last_page_idx > flashGetNumberOfPages() || num_of_pages == 0) { return LIBPARAMS_WRONG_ARGS; @@ -57,7 +66,7 @@ int8_t flashErase(uint32_t first_page_idx, uint32_t num_of_pages) { } -int32_t flashWrite(const uint8_t* data, size_t offset, size_t size) { +static int32_t flashWrite(const uint8_t* data, size_t offset, size_t size) { int32_t status = 0; if ((data == NULL) || (size == 0U)) { return LIBPARAMS_WRONG_ARGS; @@ -85,7 +94,7 @@ int32_t flashWrite(const uint8_t* data, size_t offset, size_t size) { return (int32_t)size; } -size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read) { +static size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read) { if (data == NULL) { return 0; } @@ -95,14 +104,29 @@ size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read) { return bytes_to_read; } -uint16_t flashGetNumberOfPages() { +static uint16_t flashGetNumberOfPages(void) { return 256; } -uint32_t flashGetPageSize() { +static uint32_t flashGetPageSize(void) { return 2048; } +const FlashDriverOps* stm32g0b1InternalFlashGetOps(void) { + static const FlashDriverOps ops = { + flashInit, + flashUnlock, + flashLock, + flashErase, + flashWrite, + flashRead, + flashGetNumberOfPages, + flashGetPageSize, + FLASH_START_ADDR, + }; + return &ops; +} + static uint8_t* flashGetPointer() { return (uint8_t*) FLASH_START_ADDR; } diff --git a/platform_specific/stm32g0b1/platform_flash_driver.h b/platform_specific/stm32g0b1/platform_flash_driver.h new file mode 100644 index 0000000..cbd5a2d --- /dev/null +++ b/platform_specific/stm32g0b1/platform_flash_driver.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2026 Ilia Kliantsevich + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef LIBPARAMS_STM32G0B1_PLATFORM_FLASH_DRIVER_H_ +#define LIBPARAMS_STM32G0B1_PLATFORM_FLASH_DRIVER_H_ + +#include "flash_driver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const FlashDriverOps* stm32g0b1InternalFlashGetOps(void); + +#ifdef __cplusplus +} +#endif + +#endif // LIBPARAMS_STM32G0B1_PLATFORM_FLASH_DRIVER_H_ diff --git a/platform_specific/stm32h753xx/flash_driver.c b/platform_specific/stm32h753xx/flash_driver.c index caa1f91..f4df0fe 100644 --- a/platform_specific/stm32h753xx/flash_driver.c +++ b/platform_specific/stm32h753xx/flash_driver.c @@ -9,9 +9,18 @@ #include "flash_driver.h" #include #include +#include "platform_flash_driver.h" #include "libparams_error_codes.h" #include "stm32h7xx_hal.h" +static void flashInit(void); +static int8_t flashUnlock(void); +static int8_t flashLock(void); +static int8_t flashErase(uint32_t first_page_idx, uint32_t num_of_pages); +static int32_t flashWrite(const uint8_t* data, size_t offset, size_t size); +static size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read); +static uint16_t flashGetNumberOfPages(void); +static uint32_t flashGetPageSize(void); static uint8_t* flashGetPointer(); static int8_t flashEraseSectorsInSingleBank(uint32_t first_sector_idx, uint32_t num_of_sectors, @@ -20,14 +29,14 @@ static int8_t flashWriteFlashword(uint32_t address, const uint8_t data[]); static const size_t FLASH_WORD_SIZE = (FLASH_NB_32BITWORD_IN_FLASHWORD * 4U); -void flashInit() { +static void flashInit(void) { } -int8_t flashUnlock() { +static int8_t flashUnlock(void) { return -HAL_FLASH_Unlock(); } -int8_t flashLock() { +static int8_t flashLock(void) { return -HAL_FLASH_Lock(); } @@ -37,7 +46,7 @@ int8_t flashLock() { * max 2.6 s * @note from STM32H753 datasheet */ -int8_t flashErase(uint32_t first_page_idx, uint32_t num_of_pages) { +static int8_t flashErase(uint32_t first_page_idx, uint32_t num_of_pages) { uint32_t last_page_idx = first_page_idx + num_of_pages; if (last_page_idx > flashGetNumberOfPages() || num_of_pages == 0) { return LIBPARAMS_WRONG_ARGS; @@ -68,7 +77,7 @@ int8_t flashErase(uint32_t first_page_idx, uint32_t num_of_pages) { return res; } -int32_t flashWrite(const uint8_t* data, size_t offset, size_t size) { +static int32_t flashWrite(const uint8_t* data, size_t offset, size_t size) { int32_t status = 0; if (data == NULL || size == 0U) { return LIBPARAMS_WRONG_ARGS; @@ -97,7 +106,7 @@ int32_t flashWrite(const uint8_t* data, size_t offset, size_t size) { return (status < 0) ? status : (int32_t)size; } -size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read) { +static size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read) { if (data == NULL) { return 0; } @@ -107,7 +116,7 @@ size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read) { return bytes_to_read; } -uint16_t flashGetNumberOfPages() { +static uint16_t flashGetNumberOfPages(void) { #if defined(DUAL_BANK) return (uint16_t)(FLASH_SECTOR_TOTAL * 2U); #else @@ -115,10 +124,25 @@ uint16_t flashGetNumberOfPages() { #endif } -uint32_t flashGetPageSize() { +static uint32_t flashGetPageSize(void) { return FLASH_SECTOR_SIZE; } +const FlashDriverOps* stm32h753xxInternalFlashGetOps(void) { + static const FlashDriverOps ops = { + flashInit, + flashUnlock, + flashLock, + flashErase, + flashWrite, + flashRead, + flashGetNumberOfPages, + flashGetPageSize, + FLASH_START_ADDR, + }; + return &ops; +} + static uint8_t* flashGetPointer() { return (uint8_t*)FLASH_START_ADDR; } diff --git a/platform_specific/stm32h753xx/platform_flash_driver.h b/platform_specific/stm32h753xx/platform_flash_driver.h new file mode 100644 index 0000000..b2ae2c2 --- /dev/null +++ b/platform_specific/stm32h753xx/platform_flash_driver.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2026 Ilia Kliantsevich + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef LIBPARAMS_STM32H753XX_PLATFORM_FLASH_DRIVER_H_ +#define LIBPARAMS_STM32H753XX_PLATFORM_FLASH_DRIVER_H_ + +#include "flash_driver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const FlashDriverOps* stm32h753xxInternalFlashGetOps(void); +const FlashDriverOps* stm32h753xxSpiFramGetOps(void); + +#ifdef __cplusplus +} +#endif + +#endif // LIBPARAMS_STM32H753XX_PLATFORM_FLASH_DRIVER_H_ diff --git a/platform_specific/stm32h753xx/stm32h753xx_spifram/flash_driver.c b/platform_specific/stm32h753xx/stm32h753xx_spifram/flash_driver.c new file mode 100644 index 0000000..a895f97 --- /dev/null +++ b/platform_specific/stm32h753xx/stm32h753xx_spifram/flash_driver.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2026 Ilia Kliantsevich + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +#include "flash_driver.h" +#include "platform_flash_driver.h" +#include +#include "libparams_error_codes.h" +#include "main.h" +#include "spi.h" + +#define FM25V02_SIZE_BYTES (32U * 1024U) +#define SPIFRAM_TRANSFER_TIMEOUT 100U +#define SPIFRAM_ERASE_CHUNK_SIZE 64U + +#ifndef LIBPARAMS_SPIFRAM_SPI + #define LIBPARAMS_SPIFRAM_SPI hspi5 +#endif + +#ifndef LIBPARAMS_SPIFRAM_CS_PORT + #define LIBPARAMS_SPIFRAM_CS_PORT SPI5_NCS1_FRAM_GPIO_Port +#endif + +#ifndef LIBPARAMS_SPIFRAM_CS_PIN + #define LIBPARAMS_SPIFRAM_CS_PIN SPI5_NCS1_FRAM_Pin +#endif + +static void flashInit(void); +static int8_t flashErase(uint32_t start_page_idx, uint32_t num_of_pages); +static int32_t flashWrite(const uint8_t* data, size_t offset, size_t bytes_to_write); +static int8_t flashUnlock(void); +static int8_t flashLock(void); +static size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read); +static uint16_t flashGetNumberOfPages(void); +static uint32_t flashGetPageSize(void); + +typedef enum { + SPIFRAM_CMD_WREN = 0x06U, // Set Write Enable Latch + SPIFRAM_CMD_WRDI = 0x04U, // Write Disable + SPIFRAM_CMD_RDSR = 0x05U, // Read Status Register + SPIFRAM_CMD_WRSR = 0x01U, // Write Status Register + SPIFRAM_CMD_READ = 0x03U, // Read Memory Data + SPIFRAM_CMD_FSTRD = 0x0BU, // Fast Read Memory Data + SPIFRAM_CMD_WRITE = 0x02U, // Write Memory Data + SPIFRAM_CMD_SLEEP = 0xB9U, // Enter Sleep Mode + SPIFRAM_CMD_RDID = 0x9FU, // Read Device ID + SPIFRAM_CMD_SNR = 0xC3U, // Read Serial Number +} SpiframCommand; + + +static int8_t spiframNormalizeOffset(size_t offset, uint16_t* fram_offset); +static int8_t spiframWriteEnable(void); +static int8_t spiframWrite(uint16_t address, const uint8_t* data, uint16_t size); +static int8_t spiframRead(uint16_t address, uint8_t* data, uint16_t size); +static int8_t spiframTransmit(const uint8_t* data, uint16_t size); +static int8_t spiframReceive(uint8_t* data, uint16_t size); +static void spiframSelect(void) { + HAL_GPIO_WritePin(LIBPARAMS_SPIFRAM_CS_PORT, LIBPARAMS_SPIFRAM_CS_PIN, GPIO_PIN_RESET); +} + +static void spiframDeselect(void) { + HAL_GPIO_WritePin(LIBPARAMS_SPIFRAM_CS_PORT, LIBPARAMS_SPIFRAM_CS_PIN, GPIO_PIN_SET); +} + +static int8_t spiframTransmit(const uint8_t* data, uint16_t size) { + if (data == NULL || size == 0U) { + return LIBPARAMS_WRONG_ARGS; + } + HAL_StatusTypeDef status = HAL_SPI_Transmit(&LIBPARAMS_SPIFRAM_SPI, + (uint8_t*)data, + size, + SPIFRAM_TRANSFER_TIMEOUT); + return (status == HAL_OK) ? LIBPARAMS_OK : LIBPARAMS_UNKNOWN_HAL_ERROR; +} + +static int8_t spiframReceive(uint8_t* data, uint16_t size) { + if (data == NULL || size == 0U) { + return LIBPARAMS_WRONG_ARGS; + } + HAL_StatusTypeDef status = HAL_SPI_Receive(&LIBPARAMS_SPIFRAM_SPI, + data, + size, + SPIFRAM_TRANSFER_TIMEOUT); + return (status == HAL_OK) ? LIBPARAMS_OK : LIBPARAMS_UNKNOWN_HAL_ERROR; +} + +static int8_t spiframNormalizeOffset(size_t offset, uint16_t* fram_offset) { + if (fram_offset == NULL) { + return LIBPARAMS_WRONG_ARGS; + } + + if (offset >= FLASH_START_ADDR) { + offset -= FLASH_START_ADDR; + } + + if (offset >= FM25V02_SIZE_BYTES) { + return LIBPARAMS_WRONG_ARGS; + } + + *fram_offset = (uint16_t)offset; + return LIBPARAMS_OK; +} + +static int8_t spiframWriteEnable(void) { + const uint8_t cmd = SPIFRAM_CMD_WREN; + + spiframSelect(); + int8_t res = spiframTransmit(&cmd, sizeof(cmd)); + spiframDeselect(); + + return res; +} + +static int8_t spiframWrite(uint16_t address, const uint8_t* data, uint16_t size) { + if (data == NULL || size == 0U || (uint32_t)address + size > FM25V02_SIZE_BYTES) { + return LIBPARAMS_WRONG_ARGS; + } + + int8_t res = spiframWriteEnable(); + if (res != LIBPARAMS_OK) { + return res; + } + + const uint8_t cmd_write[3] = { + SPIFRAM_CMD_WRITE, + (uint8_t)(address >> 8U), + (uint8_t)(address & 0xFFU), + }; + + spiframSelect(); + res = spiframTransmit(cmd_write, sizeof(cmd_write)); + if (res == LIBPARAMS_OK) { + res = spiframTransmit(data, size); + } + spiframDeselect(); + + return res; +} + +static int8_t spiframRead(uint16_t address, uint8_t* data, uint16_t size) { + if (data == NULL || size == 0U || (uint32_t)address + size > FM25V02_SIZE_BYTES) { + return LIBPARAMS_WRONG_ARGS; + } + + const uint8_t cmd_read[3] = { + SPIFRAM_CMD_READ, + (uint8_t)(address >> 8U), + (uint8_t)(address & 0xFFU), + }; + + spiframSelect(); + int8_t res = spiframTransmit(cmd_read, sizeof(cmd_read)); + if (res == LIBPARAMS_OK) { + res = spiframReceive(data, size); + } + spiframDeselect(); + + return res; +} + +static void flashInit(void) { + spiframDeselect(); +} + + +static int8_t flashErase(uint32_t start_page_idx, uint32_t num_of_pages) { + if (num_of_pages == 0U || start_page_idx + num_of_pages > flashGetNumberOfPages()) { + return LIBPARAMS_WRONG_ARGS; + } + + uint8_t erased_chunk[SPIFRAM_ERASE_CHUNK_SIZE]; + memset(erased_chunk, 0xFF, sizeof(erased_chunk)); + + size_t offset = start_page_idx * flashGetPageSize(); + size_t bytes_left = num_of_pages * flashGetPageSize(); + + while (bytes_left > 0U) { + const size_t chunk_size = (bytes_left < sizeof(erased_chunk)) ? + bytes_left : sizeof(erased_chunk); + int32_t written = flashWrite(erased_chunk, offset, chunk_size); + if (written != (int32_t)chunk_size) { + return (written < 0) ? (int8_t)written : LIBPARAMS_UNKNOWN_HAL_ERROR; + } + + offset += chunk_size; + bytes_left -= chunk_size; + } + + return LIBPARAMS_OK; +} + + + +static int32_t flashWrite(const uint8_t* data, size_t offset, size_t bytes_to_write) { + if (data == NULL || bytes_to_write == 0U) { + return LIBPARAMS_WRONG_ARGS; + } + const size_t requested_size = bytes_to_write; + + uint16_t address = 0; + if (spiframNormalizeOffset(offset, &address) != LIBPARAMS_OK) { + return LIBPARAMS_WRONG_ARGS; + } + if ((size_t)address + bytes_to_write > FM25V02_SIZE_BYTES) { + return LIBPARAMS_WRONG_ARGS; + } + + while (bytes_to_write > 0U) { + const size_t chunk_size = (bytes_to_write > UINT16_MAX) ? UINT16_MAX : bytes_to_write; + int8_t res = spiframWrite(address, data, (uint16_t)chunk_size); + if (res != LIBPARAMS_OK) { + return res; + } + + address = (uint16_t)(address + chunk_size); + data += chunk_size; + bytes_to_write -= chunk_size; + } + + return (int32_t)requested_size; +} + +static int8_t flashUnlock(void) { + return LIBPARAMS_OK; +} + +static int8_t flashLock(void) { + return LIBPARAMS_OK; +} + + +static size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read) { + if (data == NULL || bytes_to_read == 0U) { + return 0; + } + + uint16_t address = 0; + if (spiframNormalizeOffset(offset, &address) != LIBPARAMS_OK) { + return 0; + } + if ((size_t)address + bytes_to_read > FM25V02_SIZE_BYTES) { + return 0; + } + + size_t bytes_left = bytes_to_read; + while (bytes_left > 0U) { + const size_t chunk_size = (bytes_left > UINT16_MAX) ? UINT16_MAX : bytes_left; + int8_t res = spiframRead(address, data, (uint16_t)chunk_size); + if (res != LIBPARAMS_OK) { + return 0; + } + + address = (uint16_t)(address + chunk_size); + data += chunk_size; + bytes_left -= chunk_size; + } + + return bytes_to_read; +} + +static uint16_t flashGetNumberOfPages(void) { + // Only one page since whole memory can be accessed sequentially + return 1; +} +static uint32_t flashGetPageSize(void) { + return FM25V02_SIZE_BYTES; +} + +const FlashDriverOps* stm32h753xxSpiFramGetOps(void) { + static const FlashDriverOps ops = { + flashInit, + flashUnlock, + flashLock, + flashErase, + flashWrite, + flashRead, + flashGetNumberOfPages, + flashGetPageSize, + FLASH_START_ADDR, + }; + return &ops; +} diff --git a/platform_specific/ubuntu/flash_driver.cpp b/platform_specific/ubuntu/flash_driver.cpp index b7abab1..702157c 100644 --- a/platform_specific/ubuntu/flash_driver.cpp +++ b/platform_specific/ubuntu/flash_driver.cpp @@ -9,6 +9,7 @@ #include #include "storage.h" #include "flash_driver.h" +#include "platform_flash_driver.h" #include "libparams_error_codes.h" #include "params.hpp" #include "YamlParameters.hpp" @@ -40,11 +41,19 @@ static ParametersLayout_t params_layout = { static YamlParameters yaml_params = YamlParameters(mem_layout, params_layout); +static void flashInit(); +static int8_t flashUnlock(); +static int8_t flashLock(); +static int8_t flashErase(uint32_t start_page_idx, uint32_t num_of_pages); +static size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read); +static int32_t flashWrite(const uint8_t* data, size_t offset, size_t bytes_to_write); +static uint16_t flashGetNumberOfPages(); +static uint32_t flashGetPageSize(); static uint8_t* flashGetPointer(); static int32_t __save_to_files(); static int8_t __read_from_files(); -void flashInit() { +static void flashInit() { // Deprecated since v0.15.0, kept for backward compatibility. // Can be removed once the supported version is above v0.15.x. #ifdef LIBPARAMS_INIT_PARAMS_FILE_NAME @@ -69,17 +78,17 @@ void flashInit() { __read_from_files(); } -int8_t flashUnlock() { +static int8_t flashUnlock() { is_locked = false; return 0; } -int8_t flashLock() { +static int8_t flashLock() { is_locked = true; return 0; } -int8_t flashErase(uint32_t start_page_idx, uint32_t num_of_pages) { +static int8_t flashErase(uint32_t start_page_idx, uint32_t num_of_pages) { if (is_locked || start_page_idx + num_of_pages > 2 * n_flash_pages || num_of_pages == 0) { return LIBPARAMS_WRONG_ARGS; } @@ -92,14 +101,14 @@ static uint8_t* flashGetPointer() { return (uint8_t*)flash_memory; } -size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read) { +static size_t flashRead(uint8_t* data, size_t offset, size_t bytes_to_read) { const uint8_t* rom = &(flashGetPointer()[offset]); memcpy(data, rom, bytes_to_read); return bytes_to_read; } -int32_t flashWrite(const uint8_t* data, size_t offset, size_t bytes_to_write) { +static int32_t flashWrite(const uint8_t* data, size_t offset, size_t bytes_to_write) { if (is_locked || offset < FLASH_START_ADDR || offset >= FLASH_START_ADDR + sizeof(flash_memory)) { return LIBPARAMS_WRONG_ARGS; @@ -114,14 +123,29 @@ int32_t flashWrite(const uint8_t* data, size_t offset, size_t bytes_to_write) { return __save_to_files(); } -uint16_t flashGetNumberOfPages() { +static uint16_t flashGetNumberOfPages() { return 2 * n_flash_pages; } -uint32_t flashGetPageSize() { +static uint32_t flashGetPageSize() { return PAGE_SIZE_BYTES; } +const FlashDriverOps* ubuntuFlashGetOps() { + static const FlashDriverOps ops = { + flashInit, + flashUnlock, + flashLock, + flashErase, + flashWrite, + flashRead, + flashGetNumberOfPages, + flashGetPageSize, + FLASH_START_ADDR, + }; + return &ops; +} + int32_t __save_to_files() { const char* dir = paramsGetDir(); if (dir == nullptr || dir[0] == '\0') { diff --git a/platform_specific/ubuntu/platform_flash_driver.h b/platform_specific/ubuntu/platform_flash_driver.h new file mode 100644 index 0000000..509f4a2 --- /dev/null +++ b/platform_specific/ubuntu/platform_flash_driver.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2026 Ilia Kliantsevich + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef LIBPARAMS_UBUNTU_PLATFORM_FLASH_DRIVER_H_ +#define LIBPARAMS_UBUNTU_PLATFORM_FLASH_DRIVER_H_ + +#include "flash_driver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const FlashDriverOps* ubuntuFlashGetOps(void); + +#ifdef __cplusplus +} +#endif + +#endif // LIBPARAMS_UBUNTU_PLATFORM_FLASH_DRIVER_H_ diff --git a/src/rom.c b/src/rom.c index 81ac376..f1827f4 100644 --- a/src/rom.c +++ b/src/rom.c @@ -9,29 +9,45 @@ #include "rom.h" #include #include -#include "flash_driver.h" #include "libparams_error_codes.h" int32_t libparams_rom_error_code = 0; -RomDriverInstance romInit(int32_t first_page_idx, size_t pages_amount) { - if (first_page_idx < 0) { - first_page_idx += flashGetNumberOfPages(); - } +static bool isFlashOpsValid(const FlashDriverOps* flash) { + return flash != NULL && + flash->init != NULL && + flash->unlock != NULL && + flash->lock != NULL && + flash->erase != NULL && + flash->write != NULL && + flash->read != NULL && + flash->get_number_of_pages != NULL && + flash->get_page_size != NULL; +} +RomDriverInstance romInit(const FlashDriverOps* flash, int32_t first_page_idx, + size_t pages_amount) { RomDriverInstance rom = {0}; + if (!isFlashOpsValid(flash)) { + return rom; + } + + if (first_page_idx < 0) { + first_page_idx += flash->get_number_of_pages(); + } if (first_page_idx < 0 || - first_page_idx + pages_amount > flashGetNumberOfPages() || + first_page_idx + pages_amount > flash->get_number_of_pages() || pages_amount == 0) { return rom; } - flashInit(); + flash->init(); - rom.addr = FLASH_START_ADDR + first_page_idx * flashGetPageSize(); + rom.flash = flash; + rom.addr = flash->start_addr + first_page_idx * flash->get_page_size(); rom.first_page_idx = first_page_idx; - rom.total_size = pages_amount * flashGetPageSize(); + rom.total_size = pages_amount * flash->get_page_size(); rom.pages_amount = pages_amount; rom.inited = true; rom.write_protected = true; @@ -39,7 +55,8 @@ RomDriverInstance romInit(int32_t first_page_idx, size_t pages_amount) { } size_t romRead(const RomDriverInstance* rom, size_t offset, uint8_t* data, size_t requested_size) { - if (rom == NULL || data == NULL || offset >= rom->total_size || requested_size == 0) { + if (rom == NULL || rom->flash == NULL || data == NULL || + offset >= rom->total_size || requested_size == 0) { return 0; } @@ -51,19 +68,21 @@ size_t romRead(const RomDriverInstance* rom, size_t offset, uint8_t* data, size_ bytes_to_read = requested_size; } - return flashRead(data, rom->first_page_idx * flashGetPageSize() + offset, bytes_to_read); + return rom->flash->read(data, + rom->first_page_idx * rom->flash->get_page_size() + offset, + bytes_to_read); } void romBeginWrite(RomDriverInstance* rom) { - if (rom == NULL) { + if (rom == NULL || rom->flash == NULL) { return; } - if (flashUnlock() < 0) { + if (rom->flash->unlock() < 0) { return; } - if (flashErase((uint32_t)rom->first_page_idx, (uint32_t)rom->pages_amount) < 0) { + if (rom->flash->erase((uint32_t)rom->first_page_idx, (uint32_t)rom->pages_amount) < 0) { return; } @@ -71,7 +90,7 @@ void romBeginWrite(RomDriverInstance* rom) { } int32_t romWrite(const RomDriverInstance* rom, size_t offset, const uint8_t* data, size_t size) { - if (rom == NULL || data == NULL || + if (rom == NULL || rom->flash == NULL || data == NULL || offset >= rom->total_size || size == 0 || offset + size > rom->total_size) { libparams_rom_error_code = LIBPARAMS_ROM_WRITE_BAD_ARGS_ERROR; return LIBPARAMS_ROM_WRITE_BAD_ARGS_ERROR; @@ -83,7 +102,7 @@ int32_t romWrite(const RomDriverInstance* rom, size_t offset, const uint8_t* dat } int32_t status = 0; - status = flashWrite(data, (uint32_t)offset + rom->addr, size); + status = rom->flash->write(data, (uint32_t)offset + rom->addr, size); if (status < 0) { libparams_rom_error_code = -1000 + status; @@ -102,12 +121,12 @@ uint32_t romGetAvailableMemory(const RomDriverInstance* rom) { } void romEndWrite(RomDriverInstance* rom) { - if (rom == NULL) { + if (rom == NULL || rom->flash == NULL) { return; } if (!rom->write_protected) { - flashLock(); + rom->flash->lock(); rom->write_protected = true; } } diff --git a/src/storage.c b/src/storage.c index ce55de6..b46d9b9 100644 --- a/src/storage.c +++ b/src/storage.c @@ -74,16 +74,17 @@ const char* paramsGetDir() { #endif } -int8_t paramsInit(ParamIndex_t int_num, +int8_t paramsInit(const FlashDriverOps* flash, + ParamIndex_t int_num, ParamIndex_t str_num, int32_t first_page_idx, size_t pages_num) { - if (int_num > 512 || str_num > 512) { + if (flash == NULL || int_num > 512 || str_num > 512) { return LIBPARAMS_WRONG_ARGS; } uint32_t need_memory_bytes = sizeof(IntegerParamValue_t) * int_num +\ MAX_STRING_LENGTH * str_num; - primary_rom = romInit(first_page_idx, pages_num); + primary_rom = romInit(flash, first_page_idx, pages_num); if (!primary_rom.inited) { return LIBPARAMS_UNKNOWN_ERROR; @@ -121,7 +122,7 @@ bool paramsIsCrcValid() { int8_t paramsInitRedundantPage() { size_t pages_amount = primary_rom.pages_amount; int32_t redundant_rom_first_page_idx = (int32_t)(primary_rom.first_page_idx - pages_amount); - redundant_rom = romInit(redundant_rom_first_page_idx, pages_amount); + redundant_rom = romInit(primary_rom.flash, redundant_rom_first_page_idx, pages_amount); if (!redundant_rom.inited) { return LIBPARAMS_UNKNOWN_ERROR; } diff --git a/tests/params_generator/test.cpp b/tests/params_generator/test.cpp index 3d44677..8370330 100644 --- a/tests/params_generator/test.cpp +++ b/tests/params_generator/test.cpp @@ -10,6 +10,7 @@ #include #include #include "storage.h" +#include "platform_flash_driver.h" #include "params.hpp" bool strCompareSafe(const char* first, const char* second, size_t len) { @@ -23,7 +24,7 @@ bool strCompareSafe(const char* first, const char* second, size_t len) { } void init() { - paramsInit(IntParamsIndexes::INTEGER_PARAMS_AMOUNT, NUM_OF_STR_PARAMS, -1, 1); + paramsInit(ubuntuFlashGetOps(), IntParamsIndexes::INTEGER_PARAMS_AMOUNT, NUM_OF_STR_PARAMS, -1, 1); paramsLoad(); } diff --git a/tests/platform_specific/cmake/stm32_platform_test.cmake b/tests/platform_specific/cmake/stm32_platform_test.cmake index c3f13ee..cf7180e 100644 --- a/tests/platform_specific/cmake/stm32_platform_test.cmake +++ b/tests/platform_specific/cmake/stm32_platform_test.cmake @@ -3,6 +3,11 @@ function(add_libparams_stm32_platform_test target platform device_define) cmake_path(GET PLATFORM_SPECIFIC_TESTS_DIR PARENT_PATH TESTS_DIR) cmake_path(GET TESTS_DIR PARENT_PATH ROOT_DIR) + set(cpu cortex-m3) + if(ARGC GREATER 3) + set(cpu ${ARGV3}) + endif() + set(LIBPARAMS_PLATFORM ${platform}) include(${ROOT_DIR}/libparams.cmake) @@ -26,7 +31,7 @@ function(add_libparams_stm32_platform_test target platform device_define) ) target_compile_options(${target} PRIVATE - -mcpu=cortex-m3 + -mcpu=${cpu} -mthumb -Og -Wall @@ -40,7 +45,7 @@ function(add_libparams_stm32_platform_test target platform device_define) ) target_link_options(${target} PRIVATE - -mcpu=cortex-m3 + -mcpu=${cpu} -mthumb -specs=nano.specs -specs=nosys.specs diff --git a/tests/platform_specific/stm32f103/application.c b/tests/platform_specific/stm32f103/application.c index 9123631..97c8e08 100644 --- a/tests/platform_specific/stm32f103/application.c +++ b/tests/platform_specific/stm32f103/application.c @@ -8,15 +8,17 @@ #include "rom.h" #include "flash_driver.h" +#include "platform_flash_driver.h" void test_flash_wr() { - RomDriverInstance rom = romInit(127, 1); + const FlashDriverOps* flash = stm32f103InternalFlashGetOps(); + RomDriverInstance rom = romInit(flash, 127, 1); const uint8_t first_buf[2048]; - romWrite(&rom, 0, first_buf, flashGetPageSize()); + romWrite(&rom, 0, first_buf, flash->get_page_size()); uint8_t second_buf[2048]; - romRead(&rom, 0, second_buf, flashGetPageSize()); + romRead(&rom, 0, second_buf, flash->get_page_size()); } int main() { diff --git a/tests/platform_specific/stm32g0b1/README.md b/tests/platform_specific/stm32g0b1/README.md index e61f2d1..f7496fa 100644 --- a/tests/platform_specific/stm32g0b1/README.md +++ b/tests/platform_specific/stm32g0b1/README.md @@ -4,7 +4,7 @@ This is the simplest stm32g0b1 CMake example. ## Purpose -The application is inbtended simply to check that the library can be builded with corresponded compiler for given plathorm without Warnings and Errors. +The application is intended simply to check that the library can be builded with corresponded compiler for given plathorm without Warnings and Errors. ## Usage diff --git a/tests/platform_specific/stm32g0b1/application.c b/tests/platform_specific/stm32g0b1/application.c index b86da39..1983f12 100644 --- a/tests/platform_specific/stm32g0b1/application.c +++ b/tests/platform_specific/stm32g0b1/application.c @@ -8,15 +8,17 @@ #include "rom.h" #include "flash_driver.h" +#include "platform_flash_driver.h" void test_flash_wr() { - RomDriverInstance rom = romInit(255, 1); + const FlashDriverOps* flash = stm32g0b1InternalFlashGetOps(); + RomDriverInstance rom = romInit(flash, 255, 1); const uint8_t first_buf[2048]; - romWrite(&rom, 0, first_buf, flashGetPageSize()); + romWrite(&rom, 0, first_buf, flash->get_page_size()); uint8_t second_buf[2048]; - romRead(&rom, 0, second_buf, flashGetPageSize()); + romRead(&rom, 0, second_buf, flash->get_page_size()); } int main() { diff --git a/tests/platform_specific/stm32h753xx/CMakeLists.txt b/tests/platform_specific/stm32h753xx/CMakeLists.txt new file mode 100644 index 0000000..72194ab --- /dev/null +++ b/tests/platform_specific/stm32h753xx/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.22) +project(libparams_stm32h753xx C) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_EXECUTABLE_SUFFIX ".elf") + +include(${CMAKE_CURRENT_LIST_DIR}/../cmake/stm32_platform_test.cmake) +add_libparams_stm32_platform_test(libparams_stm32h753xx + stm32h753xx + STM32H753xx + cortex-m7 +) +add_libparams_stm32_platform_test(libparams_stm32h753xx_spifram + stm32h753xx + STM32H753xx + cortex-m7 +) diff --git a/tests/platform_specific/stm32h753xx/README.md b/tests/platform_specific/stm32h753xx/README.md new file mode 100644 index 0000000..2939740 --- /dev/null +++ b/tests/platform_specific/stm32h753xx/README.md @@ -0,0 +1,26 @@ +# stm32h753xx flash driver examples + +This example checks that both STM32H753xx flash backends build with the ARM embedded compiler. + +## Purpose + +The application is intended to verify that libparams and the STM32H753xx platform flash drivers compile without warnings or errors: + +- `stm32h753xx` internal flash +- `stm32h753xx/stm32h753xx_spifram` external SPI FRAM + +## Usage + + +```bash +cd libparams +make stm32h753xx +``` + +It will generate `.elf`, `.hex`, and `.bin` files in the `libparams/build` folder. + +## Notes + +- The test uses local HAL and SPI mocks from this directory. +- The binaries are compile/link smoke tests, not hardware-in-the-loop tests. +- Related workflow: [![CI](https://github.com/PonomarevDA/libparams/actions/workflows/ci.yml/badge.svg)](https://github.com/PonomarevDA/libparams/actions/workflows/ci.yml) diff --git a/tests/platform_specific/stm32h753xx/application.c b/tests/platform_specific/stm32h753xx/application.c new file mode 100644 index 0000000..3a85f20 --- /dev/null +++ b/tests/platform_specific/stm32h753xx/application.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022-2023 Dmitry Ponomarev + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "rom.h" +#include "flash_driver.h" +#include "platform_flash_driver.h" + +void test_flash_wr(void) { + const FlashDriverOps* flash = stm32h753xxInternalFlashGetOps(); + RomDriverInstance rom = romInit(flash, 0, 1); + + const FlashDriverOps* spifram = stm32h753xxSpiFramGetOps(); + RomDriverInstance spifram_rom = romInit(spifram, 0, 1); + + const uint8_t first_buf[32] = {0}; + romWrite(&rom, 0, first_buf, sizeof(first_buf)); + romWrite(&spifram_rom, 0, first_buf, sizeof(first_buf)); + + uint8_t second_buf[32]; + romRead(&rom, 0, second_buf, sizeof(second_buf)); + romRead(&spifram_rom, 0, second_buf, sizeof(second_buf)); +} + +int main(void) { + test_flash_wr(); + + return 0; +} diff --git a/tests/platform_specific/stm32h753xx/main.c b/tests/platform_specific/stm32h753xx/main.c new file mode 100644 index 0000000..0ae2d99 --- /dev/null +++ b/tests/platform_specific/stm32h753xx/main.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2022-2023 Dmitry Ponomarev + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "main.h" +#include +#include "spi.h" + +#define TEST_FLASH_SIZE FLASH_SECTOR_SIZE +#define TEST_SPIFRAM_SIZE (32U * 1024U) + +static uint8_t flash_memory[TEST_FLASH_SIZE]; +static uint8_t spifram_memory[TEST_SPIFRAM_SIZE]; +static uint16_t spifram_address; + +SPI_HandleTypeDef hspi5; + +uint32_t HAL_GetTick(void) { + return 0; +} + +HAL_StatusTypeDef HAL_FLASH_Unlock(void) { + return HAL_OK; +} + +HAL_StatusTypeDef HAL_FLASH_Lock(void) { + return HAL_OK; +} + +HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef* pEraseInit, uint32_t* SectorError) { + if (pEraseInit == 0 || SectorError == 0 || + pEraseInit->TypeErase != FLASH_TYPEERASE_SECTORS || + pEraseInit->NbSectors == 0U || + pEraseInit->Sector + pEraseInit->NbSectors > FLASH_SECTOR_TOTAL || + pEraseInit->VoltageRange != FLASH_VOLTAGE_RANGE_3) { + return HAL_ERROR; + } + + *SectorError = 0xFFFFFFFFU; + memset(flash_memory, 0xFF, sizeof(flash_memory)); + return HAL_OK; +} + +HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint32_t DataAddress) { + if (TypeProgram != FLASH_TYPEPROGRAM_FLASHWORD || + Address < FLASH_START_ADDR || + Address + FLASH_NB_32BITWORD_IN_FLASHWORD * 4U > FLASH_START_ADDR + TEST_FLASH_SIZE || + Address % (FLASH_NB_32BITWORD_IN_FLASHWORD * 4U) != 0U) { + return HAL_ERROR; + } + + memcpy(&flash_memory[Address - FLASH_START_ADDR], + (const void*)(uintptr_t)DataAddress, + FLASH_NB_32BITWORD_IN_FLASHWORD * 4U); + return HAL_OK; +} + +void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState) { + (void)GPIOx; + (void)GPIO_Pin; + (void)PinState; +} + +HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef* hspi, + uint8_t* pData, + uint16_t Size, + uint32_t Timeout) { + (void)Timeout; + + if (hspi != &hspi5 || pData == 0 || Size == 0U) { + return HAL_ERROR; + } + + if (Size == 1U && pData[0] == 0x06U) { + return HAL_OK; + } + + if (Size == 3U && (pData[0] == 0x02U || pData[0] == 0x03U)) { + spifram_address = ((uint16_t)pData[1] << 8U) | pData[2]; + return HAL_OK; + } + + if ((uint32_t)spifram_address + Size > sizeof(spifram_memory)) { + return HAL_ERROR; + } + + memcpy(&spifram_memory[spifram_address], pData, Size); + spifram_address = (uint16_t)(spifram_address + Size); + return HAL_OK; +} + +HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef* hspi, + uint8_t* pData, + uint16_t Size, + uint32_t Timeout) { + (void)Timeout; + + if (hspi != &hspi5 || pData == 0 || + Size == 0U || + (uint32_t)spifram_address + Size > sizeof(spifram_memory)) { + return HAL_ERROR; + } + + memcpy(pData, &spifram_memory[spifram_address], Size); + spifram_address = (uint16_t)(spifram_address + Size); + return HAL_OK; +} diff --git a/tests/platform_specific/stm32h753xx/main.h b/tests/platform_specific/stm32h753xx/main.h new file mode 100644 index 0000000..c4d21ab --- /dev/null +++ b/tests/platform_specific/stm32h753xx/main.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022-2023 Dmitry Ponomarev + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef STM32H753XX_TEST_MAIN_H_ +#define STM32H753XX_TEST_MAIN_H_ + +#include "stm32h7xx_hal.h" + +#define SPI5_NCS1_FRAM_GPIO_Port ((GPIO_TypeDef*)0x50000000U) +#define SPI5_NCS1_FRAM_Pin 7U + +#endif // STM32H753XX_TEST_MAIN_H_ diff --git a/tests/platform_specific/stm32h753xx/spi.h b/tests/platform_specific/stm32h753xx/spi.h new file mode 100644 index 0000000..0ef1e4b --- /dev/null +++ b/tests/platform_specific/stm32h753xx/spi.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2026 Ilia Kliantsevich + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef STM32H753XX_TEST_SPI_H_ +#define STM32H753XX_TEST_SPI_H_ + +#include "stm32h7xx_hal.h" + +extern SPI_HandleTypeDef hspi5; + +#endif // STM32H753XX_TEST_SPI_H_ diff --git a/tests/platform_specific/stm32h753xx/stm32h7xx_hal.h b/tests/platform_specific/stm32h753xx/stm32h7xx_hal.h new file mode 100644 index 0000000..1e713d2 --- /dev/null +++ b/tests/platform_specific/stm32h753xx/stm32h7xx_hal.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2026 Ilia Kliantsevich + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef STM32H7XX_HAL_MOCK_H_ +#define STM32H7XX_HAL_MOCK_H_ + +#include + +#define FLASH_TYPEERASE_SECTORS 0x00U +#define FLASH_TYPEPROGRAM_FLASHWORD 0x01U +#define FLASH_BANK_1 1U +#define FLASH_BANK_2 2U +#define FLASH_VOLTAGE_RANGE_3 3U +#define FLASH_NB_32BITWORD_IN_FLASHWORD 8U +#define FLASH_SECTOR_SIZE (128U * 1024U) +#define FLASH_SECTOR_TOTAL 8U +#ifndef FLASH_START_ADDR +#define FLASH_START_ADDR 0x08000000U +#endif +#define GPIO_PIN_RESET 0U +#define GPIO_PIN_SET 1U + +typedef enum +{ + HAL_OK = 0x00U, + HAL_ERROR = 0x01U, + HAL_BUSY = 0x02U, + HAL_TIMEOUT = 0x03U +} HAL_StatusTypeDef; + +typedef uint32_t GPIO_PinState; + +typedef struct +{ + uint32_t TypeErase; + uint32_t Banks; + uint32_t Sector; + uint32_t NbSectors; + uint32_t VoltageRange; +} FLASH_EraseInitTypeDef; + +typedef struct +{ + uint32_t dummy; +} GPIO_TypeDef; + +typedef struct +{ + uint32_t dummy; +} SPI_HandleTypeDef; + +uint32_t HAL_GetTick(void); +HAL_StatusTypeDef HAL_FLASH_Unlock(void); +HAL_StatusTypeDef HAL_FLASH_Lock(void); +HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef* pEraseInit, uint32_t* SectorError); +HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint32_t DataAddress); +void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState); +HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef* hspi, + uint8_t* pData, + uint16_t Size, + uint32_t Timeout); +HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef* hspi, + uint8_t* pData, + uint16_t Size, + uint32_t Timeout); + +#endif // STM32H7XX_HAL_MOCK_H_ diff --git a/tests/platform_specific/ubuntu/main.cpp b/tests/platform_specific/ubuntu/main.cpp index 46e3933..f8b9b40 100644 --- a/tests/platform_specific/ubuntu/main.cpp +++ b/tests/platform_specific/ubuntu/main.cpp @@ -8,6 +8,7 @@ #include #include "flash_driver.h" +#include "platform_flash_driver.h" #include "libparams_error_codes.h" #include "params.hpp" @@ -16,7 +17,7 @@ extern uint8_t flash_memory[2048]; int main (int argc, char *argv[]) { - paramsInit(IntParamsIndexes::INTEGER_PARAMS_AMOUNT, NUM_OF_STR_PARAMS, -1, 1); + paramsInit(ubuntuFlashGetOps(), IntParamsIndexes::INTEGER_PARAMS_AMOUNT, NUM_OF_STR_PARAMS, -1, 1); paramsLoad(); std::cout << "Integer parameters:" << std::endl; diff --git a/tests/unit_tests/test_flash_driver.cpp b/tests/unit_tests/test_flash_driver.cpp index 83c70ae..3e61437 100644 --- a/tests/unit_tests/test_flash_driver.cpp +++ b/tests/unit_tests/test_flash_driver.cpp @@ -9,49 +9,55 @@ #include #include #include "flash_driver.h" +#include "platform_flash_driver.h" #include "libparams_error_codes.h" #include "common/algorithms.hpp" // Test Case 1. Initialize flash driver TEST(TestFlashDriver, initializeFlashDriver) { - flashUnlock(); - auto res = flashErase(0, 1); - flashLock(); + const FlashDriverOps* flash = ubuntuFlashGetOps(); + flash->unlock(); + auto res = flash->erase(0, 1); + flash->lock(); ASSERT_EQ(res, LIBPARAMS_OK); } // Test case 2. Erase TEST(TestFlashDriver, test_erase_ok) { - flashUnlock(); - auto res = flashErase(0, 1); - flashLock(); + const FlashDriverOps* flash = ubuntuFlashGetOps(); + flash->unlock(); + auto res = flash->erase(0, 1); + flash->lock(); ASSERT_EQ(res, LIBPARAMS_OK); } TEST(TestFlashDriver, test_erase_error_locked) { - flashLock(); - auto res = flashErase(0, 1); - flashLock(); + const FlashDriverOps* flash = ubuntuFlashGetOps(); + flash->lock(); + auto res = flash->erase(0, 1); + flash->lock(); ASSERT_TRUE(res < 0); } TEST(TestFlashDriver, test_erase_error_bad_second_arg) { - flashUnlock(); - auto res = flashErase(0, 0); - flashLock(); + const FlashDriverOps* flash = ubuntuFlashGetOps(); + flash->unlock(); + auto res = flash->erase(0, 0); + flash->lock(); ASSERT_TRUE(res < 0); } // Test case 3. flashRead TEST(TestFlashDriver, test_read_flash_ok) { - flashUnlock(); - auto res = flashErase(0, 1); - flashLock(); + const FlashDriverOps* flash = ubuntuFlashGetOps(); + flash->unlock(); + auto res = flash->erase(0, 1); + flash->lock(); ASSERT_EQ(res, LIBPARAMS_OK); uint8_t val; - res = flashRead(&val, 0, 1); + res = flash->read(&val, 0, 1); ASSERT_EQ(res, 1); ASSERT_EQ(0, val); } @@ -59,43 +65,47 @@ TEST(TestFlashDriver, test_read_flash_ok) { // Test case 4. flashWrite TEST(TestFlashDriver, test_write_flash_wrong_addr) { - flashUnlock(); - auto res = flashWrite((uint8_t*)42, 0, 1); - flashLock(); + const FlashDriverOps* flash = ubuntuFlashGetOps(); + flash->unlock(); + auto res = flash->write((uint8_t*)42, 0, 1); + flash->lock(); ASSERT_EQ(res, LIBPARAMS_WRONG_ARGS); } TEST(TestFlashDriver, test_write_flash_ok) { - flashUnlock(); + const FlashDriverOps* flash = ubuntuFlashGetOps(); + flash->unlock(); uint8_t val = 42; - auto res = flashWrite(&val, FLASH_START_ADDR, 1); - flashLock(); + auto res = flash->write(&val, FLASH_START_ADDR, 1); + flash->lock(); ASSERT_EQ(res, LIBPARAMS_OK); } // Test case 5. Check values` TEST(TestFlashDriver, test_flash_check_numeric_ok) { - flashUnlock(); + const FlashDriverOps* flash = ubuntuFlashGetOps(); + flash->unlock(); uint8_t val = 42; - auto res = flashWrite(&val, FLASH_START_ADDR, 1); - flashLock(); + auto res = flash->write(&val, FLASH_START_ADDR, 1); + flash->lock(); ASSERT_EQ(res, LIBPARAMS_OK); uint8_t read_val = 0; - res = flashRead(&read_val, 0, 1); + res = flash->read(&read_val, 0, 1); ASSERT_EQ(res, 1); ASSERT_EQ(val, read_val); } TEST(TestFlashDriver, test_flash_check_string_ok) { + const FlashDriverOps* flash = ubuntuFlashGetOps(); char val[56]; generateRandomCString(val, 56); - flashUnlock(); - auto res = flashWrite((uint8_t*)val, FLASH_START_ADDR, 56); - flashLock(); + flash->unlock(); + auto res = flash->write((uint8_t*)val, FLASH_START_ADDR, 56); + flash->lock(); ASSERT_EQ(res, LIBPARAMS_OK); uint8_t read_val[56]; - res = flashRead(read_val, 0, 56); + res = flash->read(read_val, 0, 56); ASSERT_EQ(res, 56); ASSERT_STREQ(val, (char*)read_val); } diff --git a/tests/unit_tests/test_rom.cpp b/tests/unit_tests/test_rom.cpp index 1b7fbe5..9a41ff6 100644 --- a/tests/unit_tests/test_rom.cpp +++ b/tests/unit_tests/test_rom.cpp @@ -7,29 +7,119 @@ */ #include +#include #include #include "rom.h" #include "libparams_error_codes.h" #include "flash_driver.h" +#include "platform_flash_driver.h" + +namespace { + +constexpr size_t CUSTOM_FLASH_START_ADDR = 0x1000U; +constexpr size_t CUSTOM_FLASH_PAGE_SIZE = 32U; +constexpr size_t CUSTOM_FLASH_NUM_PAGES = 2U; + +uint8_t custom_flash[CUSTOM_FLASH_PAGE_SIZE * CUSTOM_FLASH_NUM_PAGES]; +bool custom_unlocked = false; +bool custom_erase_called = false; +bool custom_write_called = false; +bool custom_read_called = false; + +void customFlashInit() { + memset(custom_flash, 0, sizeof(custom_flash)); + custom_unlocked = false; + custom_erase_called = false; + custom_write_called = false; + custom_read_called = false; +} + +int8_t customFlashUnlock() { + custom_unlocked = true; + return LIBPARAMS_OK; +} + +int8_t customFlashLock() { + custom_unlocked = false; + return LIBPARAMS_OK; +} + +int8_t customFlashErase(uint32_t start_page_idx, uint32_t num_of_pages) { + if (!custom_unlocked || + num_of_pages == 0U || + start_page_idx + num_of_pages > CUSTOM_FLASH_NUM_PAGES) { + return LIBPARAMS_WRONG_ARGS; + } + custom_erase_called = true; + memset(&custom_flash[start_page_idx * CUSTOM_FLASH_PAGE_SIZE], + 0xFF, + num_of_pages * CUSTOM_FLASH_PAGE_SIZE); + return LIBPARAMS_OK; +} + +int32_t customFlashWrite(const uint8_t* data, size_t offset, size_t bytes_to_write) { + if (!custom_unlocked || + data == nullptr || + offset < CUSTOM_FLASH_START_ADDR || + offset + bytes_to_write > CUSTOM_FLASH_START_ADDR + sizeof(custom_flash)) { + return LIBPARAMS_WRONG_ARGS; + } + custom_write_called = true; + memcpy(&custom_flash[offset - CUSTOM_FLASH_START_ADDR], data, bytes_to_write); + return static_cast(bytes_to_write); +} + +size_t customFlashRead(uint8_t* data, size_t offset, size_t bytes_to_read) { + if (data == nullptr || offset + bytes_to_read > sizeof(custom_flash)) { + return 0U; + } + custom_read_called = true; + memcpy(data, &custom_flash[offset], bytes_to_read); + return bytes_to_read; +} + +uint16_t customFlashGetNumberOfPages() { + return CUSTOM_FLASH_NUM_PAGES; +} + +uint32_t customFlashGetPageSize() { + return CUSTOM_FLASH_PAGE_SIZE; +} + +const FlashDriverOps custom_flash_ops = { + customFlashInit, + customFlashUnlock, + customFlashLock, + customFlashErase, + customFlashWrite, + customFlashRead, + customFlashGetNumberOfPages, + customFlashGetPageSize, + CUSTOM_FLASH_START_ADDR, +}; + +} // namespace class RomDriverMultiplePagesTest : public ::testing::Test { protected: RomDriverInstance rom; void SetUp() override { - rom = romInit(0, flashGetNumberOfPages()); + const FlashDriverOps* flash = ubuntuFlashGetOps(); + rom = romInit(flash, 0, flash->get_number_of_pages()); } }; // Test Case 1. Initialize ROM Driver Instance // Test 1.1: Initialize with Single Latest Page, Negative Number TEST(TestRom, initializeWithSingleLatestPageNegativeNumber) { - auto rom = romInit(-1, 1); + auto rom = romInit(ubuntuFlashGetOps(), -1, 1); ASSERT_TRUE(rom.inited)<< "Failed to init with single latest page using negative number"; } // Test 1.2: Initialize with Single Latest Page, Positive Number TEST(TestRom, initializeWithSingleLatestPagePositiveNumber) { - auto rom = romInit(flashGetNumberOfPages() - 1, 1); + const FlashDriverOps* flash = ubuntuFlashGetOps(); + auto rom = romInit(flash, flash->get_number_of_pages() - 1, 1); ASSERT_TRUE(rom.inited) << "Failed to init with single latest page using positive number"; } // Test 1.3: Initialize with Multiple Pages @@ -38,14 +128,20 @@ TEST_F(RomDriverMultiplePagesTest, initializeWithMultiplePages) { } // Test 1.4: Initialize with Invalid Page Index TEST(TestRom, initializeWithInvalidPageIndex) { - auto rom = romInit(flashGetNumberOfPages(), 1); + const FlashDriverOps* flash = ubuntuFlashGetOps(); + auto rom = romInit(flash, flash->get_number_of_pages(), 1); ASSERT_FALSE(rom.inited) << "Initialized with invalid page index"; } // Test 1.5: Initialize with Zero Pages TEST(TestRom, initializeWithZeroPages) { - auto rom = romInit(-1, 0); + auto rom = romInit(ubuntuFlashGetOps(), -1, 0); ASSERT_FALSE(rom.inited) << "Initialized with zero pages"; } +// Test 1.6: Initialize with null flash ops +TEST(TestRom, initializeWithNullFlashOps) { + auto rom = romInit(nullptr, -1, 1); + ASSERT_FALSE(rom.inited) << "Initialized with null flash ops"; +} // Test Case 2: Read from ROM @@ -89,6 +185,26 @@ TEST_F(RomDriverMultiplePagesTest, writeDataWithingBounds) { ASSERT_EQ(romRead(&rom, 0, read_data, sizeof(SAMPLE_DATA)), sizeof(SAMPLE_DATA)); ASSERT_EQ(memcmp(SAMPLE_DATA, read_data, sizeof(SAMPLE_DATA)), 0); } + +TEST(TestRom, usesInstanceFlashOps) { + RomDriverInstance rom = romInit(&custom_flash_ops, 1, 1); + ASSERT_TRUE(rom.inited); + ASSERT_EQ(rom.flash, &custom_flash_ops); + ASSERT_EQ(rom.addr, CUSTOM_FLASH_START_ADDR + CUSTOM_FLASH_PAGE_SIZE); + + const uint8_t data[] = {9U, 8U, 7U, 6U}; + uint8_t read_data[sizeof(data)] = {}; + + romBeginWrite(&rom); + ASSERT_EQ(romWrite(&rom, 0, data, sizeof(data)), sizeof(data)); + romEndWrite(&rom); + ASSERT_TRUE(custom_erase_called); + ASSERT_TRUE(custom_write_called); + + ASSERT_EQ(romRead(&rom, 0, read_data, sizeof(read_data)), sizeof(read_data)); + ASSERT_TRUE(custom_read_called); + ASSERT_EQ(memcmp(data, read_data, sizeof(data)), 0); +} // Test 3.2: Write Data Exceeding Bounds TEST_F(RomDriverMultiplePagesTest, writeDataExceedingBounds) { const uint8_t SAMPLE_DATA[] = {1, 2, 3, 4, 5, 6, 7, 8}; @@ -128,7 +244,8 @@ TEST_F(RomDriverMultiplePagesTest, writeDataExceedingBounds) { // Test Case 4: Get Available Memory // Test 4.1: Verify Available Memory Calculation with correct_input TEST_F(RomDriverMultiplePagesTest, verifyAvaliableMemoryCalculationWithCorrectInput) { - ASSERT_EQ(romGetAvailableMemory(&rom), flashGetNumberOfPages() * flashGetPageSize()); + const FlashDriverOps* flash = ubuntuFlashGetOps(); + ASSERT_EQ(romGetAvailableMemory(&rom), flash->get_number_of_pages() * flash->get_page_size()); } // Test 4.2: Verify Available Memory Calculation with nullptr TEST_F(RomDriverMultiplePagesTest, test_4_2_verifyAvaliableMemoryCalculationWithNullptr) { diff --git a/tests/unit_tests/test_storage.cpp b/tests/unit_tests/test_storage.cpp index f10108e..c956cee 100644 --- a/tests/unit_tests/test_storage.cpp +++ b/tests/unit_tests/test_storage.cpp @@ -9,6 +9,7 @@ #include #include #include "storage.h" +#include "platform_flash_driver.h" #include "libparams_error_codes.h" #include "common/algorithms.hpp" @@ -33,11 +34,15 @@ class RedundantRomStorageDriverTest : public ::testing::Test { protected: size_t primary_rom_addr; size_t redundant_rom_addr; + const FlashDriverOps* params_flash; void SetUp() override { - paramsInit(INTEGER_PARAMS_AMOUNT, STRING_PARAMS_AMOUNT, -1, 1); + params_flash = ubuntuFlashGetOps(); + paramsInit(params_flash, INTEGER_PARAMS_AMOUNT, STRING_PARAMS_AMOUNT, -1, 1); EXPECT_NE(active_rom, nullptr); + EXPECT_EQ(active_rom->flash, params_flash); paramsInitRedundantPage(); EXPECT_NE(standby_rom, nullptr); + EXPECT_EQ(standby_rom->flash, params_flash); primary_rom_addr = active_rom->addr; redundant_rom_addr = standby_rom->addr; paramsLoad(); @@ -54,8 +59,8 @@ class SinglePageStorageDriverTest : public ::testing::Test { RomDriverInstance rom; void SetUp() override { - rom = romInit(-1, 1); - paramsInit(INTEGER_PARAMS_AMOUNT, STRING_PARAMS_AMOUNT, -1, 1); + rom = romInit(ubuntuFlashGetOps(), -1, 1); + paramsInit(ubuntuFlashGetOps(), INTEGER_PARAMS_AMOUNT, STRING_PARAMS_AMOUNT, -1, 1); paramsLoad(); } }; @@ -63,7 +68,7 @@ class SinglePageStorageDriverTest : public ::testing::Test { class EmptyStorageDriverTest : public ::testing::Test { protected: void SetUp() override { - paramsInit(0, 0, -1, 1); // reset storage + paramsInit(ubuntuFlashGetOps(), 0, 0, -1, 1); // reset storage } }; @@ -72,23 +77,27 @@ class EmptyStorageDriverTest : public ::testing::Test { // Test Case 1: Initialization of Parameters // Test 1.1: Initialize with Valid Inputs TEST_F(EmptyStorageDriverTest, initializeWithValidInput) { - ASSERT_EQ(LIBPARAMS_OK, paramsInit(INTEGER_PARAMS_AMOUNT, STRING_PARAMS_AMOUNT, -1, 1)); + ASSERT_EQ(LIBPARAMS_OK, paramsInit(ubuntuFlashGetOps(), INTEGER_PARAMS_AMOUNT, STRING_PARAMS_AMOUNT, -1, 1)); } // Test 1.2: Initialize with zero params TEST_F(EmptyStorageDriverTest, initializeWithZeroParams) { - ASSERT_EQ(LIBPARAMS_OK, paramsInit(0, 0, -1, 1)); + ASSERT_EQ(LIBPARAMS_OK, paramsInit(ubuntuFlashGetOps(), 0, 0, -1, 1)); } // Test 1.3: Initialize with too much params TEST_F(EmptyStorageDriverTest, initializeWithTooMuchParams) { - ASSERT_EQ(LIBPARAMS_WRONG_ARGS, paramsInit(1000, 1000, -1, 1)); + ASSERT_EQ(LIBPARAMS_WRONG_ARGS, paramsInit(ubuntuFlashGetOps(), 1000, 1000, -1, 1)); } // Test 1.4: Initialize with Zero Pages TEST_F(EmptyStorageDriverTest, initializeZeroPages) { - ASSERT_EQ(LIBPARAMS_UNKNOWN_ERROR, paramsInit(INTEGER_PARAMS_AMOUNT, STRING_PARAMS_AMOUNT, 0, 0)); + ASSERT_EQ(LIBPARAMS_UNKNOWN_ERROR, paramsInit(ubuntuFlashGetOps(), INTEGER_PARAMS_AMOUNT, STRING_PARAMS_AMOUNT, 0, 0)); } // Test 1.5: Initialize with Invalid Page Index TEST_F(EmptyStorageDriverTest, initializeWithInvalidaPageIndex) { - ASSERT_EQ(LIBPARAMS_UNKNOWN_ERROR, paramsInit(INTEGER_PARAMS_AMOUNT, STRING_PARAMS_AMOUNT, -1, 2)); + ASSERT_EQ(LIBPARAMS_UNKNOWN_ERROR, paramsInit(ubuntuFlashGetOps(), INTEGER_PARAMS_AMOUNT, STRING_PARAMS_AMOUNT, -1, 2)); +} +// Test 1.6: Initialize with null flash ops +TEST_F(EmptyStorageDriverTest, initializeWithNullFlashOps) { + ASSERT_EQ(LIBPARAMS_WRONG_ARGS, paramsInit(nullptr, INTEGER_PARAMS_AMOUNT, STRING_PARAMS_AMOUNT, -1, 1)); } // Test Case 2: Load Parameters @@ -131,19 +140,19 @@ TEST_F(EmptyStorageDriverTest, loadParametersSuccessfully) { // Test 3.1: Save Parameters Successfully TEST_F(EmptyStorageDriverTest, saveParametersSuccessfully) { // Normal - ASSERT_EQ(LIBPARAMS_OK, paramsInit(INTEGER_PARAMS_AMOUNT, STRING_PARAMS_AMOUNT, -1, 1)); + ASSERT_EQ(LIBPARAMS_OK, paramsInit(ubuntuFlashGetOps(), INTEGER_PARAMS_AMOUNT, STRING_PARAMS_AMOUNT, -1, 1)); ASSERT_EQ(LIBPARAMS_OK, paramsSave()); // Zero integers is ok - ASSERT_EQ(LIBPARAMS_OK, paramsInit(0, STRING_PARAMS_AMOUNT, -1, 1)); + ASSERT_EQ(LIBPARAMS_OK, paramsInit(ubuntuFlashGetOps(), 0, STRING_PARAMS_AMOUNT, -1, 1)); ASSERT_EQ(LIBPARAMS_OK, paramsSave()); // Zero strings is ok - ASSERT_EQ(LIBPARAMS_OK, paramsInit(INTEGER_PARAMS_AMOUNT, 0, -1, 1)); + ASSERT_EQ(LIBPARAMS_OK, paramsInit(ubuntuFlashGetOps(), INTEGER_PARAMS_AMOUNT, 0, -1, 1)); ASSERT_EQ(LIBPARAMS_OK, paramsSave()); // Full storage is ok - ASSERT_EQ(LIBPARAMS_OK, paramsInit((ParamIndex_t)512, 0, -1, 1)); + ASSERT_EQ(LIBPARAMS_OK, paramsInit(ubuntuFlashGetOps(), (ParamIndex_t)512, 0, -1, 1)); ASSERT_EQ(LIBPARAMS_OK, paramsSave()); } @@ -323,10 +332,14 @@ TEST_F(SinglePageStorageDriverTest, test_paramsSetStringValue) { TEST_F(RedundantRomStorageDriverTest, pageSwitchAfterSave) { ASSERT_EQ(active_rom->addr, primary_rom_addr); ASSERT_EQ(standby_rom->addr, redundant_rom_addr); + ASSERT_EQ(active_rom->flash, params_flash); + ASSERT_EQ(standby_rom->flash, params_flash); paramsSave(); ASSERT_EQ(active_rom->addr, redundant_rom_addr); ASSERT_EQ(standby_rom->addr, primary_rom_addr); + ASSERT_EQ(active_rom->flash, params_flash); + ASSERT_EQ(standby_rom->flash, params_flash); ASSERT_TRUE(standby_rom->erased); } @@ -335,10 +348,14 @@ TEST_F(RedundantRomStorageDriverTest, pageSwitchAfterSave) { TEST_F(RedundantRomStorageDriverTest, pageEraseAfterSave) { ASSERT_EQ(active_rom->addr, primary_rom_addr); ASSERT_EQ(standby_rom->addr, redundant_rom_addr); + ASSERT_EQ(active_rom->flash, params_flash); + ASSERT_EQ(standby_rom->flash, params_flash); paramsSave(); ASSERT_EQ(active_rom->addr, redundant_rom_addr); ASSERT_EQ(standby_rom->addr, primary_rom_addr); + ASSERT_EQ(active_rom->flash, params_flash); + ASSERT_EQ(standby_rom->flash, params_flash); // standby rom has to be erased ASSERT_TRUE(standby_rom->erased); romRead(standby_rom, 0, (uint8_t*)integer_values_pool, 4);