From 99a7d06f71f40b3dea27622f27b71010624291c4 Mon Sep 17 00:00:00 2001 From: SG Date: Sat, 27 Aug 2022 14:25:47 +1000 Subject: [PATCH] Speedup SD card & enlarge your RAM. (#1649) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FuriHal: sram2 memory manager * FuriHal: sram2 memory allocator * FuriHal: allow NULL buffers for txrx in spi hal * SD card: sector cache * FuriHal: fix init in memory hal * RPC: STARTUP instead SERVICE * Memory: pool "free" command * Thread: service can be statically allocated in a memory pool Co-authored-by: あく --- applications/cli/cli_commands.c | 3 + applications/meta/application.fam | 2 +- applications/rpc/application.fam | 12 +- applications/rpc/rpc.c | 4 +- firmware/targets/f7/Inc/FreeRTOSConfig.h | 2 +- firmware/targets/f7/fatfs/sector_cache.c | 59 +++++++++ firmware/targets/f7/fatfs/sector_cache.h | 36 ++++++ firmware/targets/f7/fatfs/stm32_adafruit_sd.c | 35 +++--- firmware/targets/f7/furi_hal/furi_hal.c | 2 + .../targets/f7/furi_hal/furi_hal_memory.c | 119 ++++++++++++++++++ firmware/targets/f7/furi_hal/furi_hal_spi.c | 18 ++- firmware/targets/f7/stm32wb55xx_flash.ld | 12 +- firmware/targets/f7/stm32wb55xx_ram_fw.ld | 12 +- .../furi_hal_include/furi_hal_memory.h | 44 +++++++ furi/core/memmgr.c | 16 +++ furi/core/memmgr.h | 22 ++++ furi/core/thread.c | 38 ++++-- furi/core/thread.h | 7 ++ furi/flipper.c | 20 +++ 19 files changed, 410 insertions(+), 53 deletions(-) create mode 100644 firmware/targets/f7/fatfs/sector_cache.c create mode 100644 firmware/targets/f7/fatfs/sector_cache.h create mode 100644 firmware/targets/f7/furi_hal/furi_hal_memory.c create mode 100644 firmware/targets/furi_hal_include/furi_hal_memory.h diff --git a/applications/cli/cli_commands.c b/applications/cli/cli_commands.c index 177a274a..a6dd672f 100644 --- a/applications/cli/cli_commands.c +++ b/applications/cli/cli_commands.c @@ -281,6 +281,9 @@ void cli_command_free(Cli* cli, string_t args, void* context) { printf("Total heap size: %d\r\n", memmgr_get_total_heap()); printf("Minimum heap size: %d\r\n", memmgr_get_minimum_free_heap()); printf("Maximum heap block: %d\r\n", memmgr_heap_get_max_free_block()); + + printf("Pool free: %d\r\n", memmgr_pool_get_free()); + printf("Maximum pool block: %d\r\n", memmgr_pool_get_max_block()); } void cli_command_free_blocks(Cli* cli, string_t args, void* context) { diff --git a/applications/meta/application.fam b/applications/meta/application.fam index a447b94a..8b873b5f 100644 --- a/applications/meta/application.fam +++ b/applications/meta/application.fam @@ -3,7 +3,7 @@ App( name="Basic services", apptype=FlipperAppType.METAPACKAGE, provides=[ - "rpc", + "rpc_start", "bt", "desktop", "loader", diff --git a/applications/rpc/application.fam b/applications/rpc/application.fam index 683396e3..3a139cb3 100644 --- a/applications/rpc/application.fam +++ b/applications/rpc/application.fam @@ -1,12 +1,8 @@ App( - appid="rpc", - name="RpcSrv", - apptype=FlipperAppType.SERVICE, - entry_point="rpc_srv", + appid="rpc_start", + apptype=FlipperAppType.STARTUP, + entry_point="rpc_on_system_start", cdefines=["SRV_RPC"], - requires=[ - "cli", - ], - stack_size=4 * 1024, + requires=["cli"], order=10, ) diff --git a/applications/rpc/rpc.c b/applications/rpc/rpc.c index d767a928..abba6ea4 100644 --- a/applications/rpc/rpc.c +++ b/applications/rpc/rpc.c @@ -395,7 +395,7 @@ void rpc_session_close(RpcSession* session) { furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtDisconnect); } -int32_t rpc_srv(void* p) { +void rpc_on_system_start(void* p) { UNUSED(p); Rpc* rpc = malloc(sizeof(Rpc)); @@ -406,8 +406,6 @@ int32_t rpc_srv(void* p) { cli, "start_rpc_session", CliCommandFlagParallelSafe, rpc_cli_command_start_session, rpc); furi_record_create(RECORD_RPC, rpc); - - return 0; } void rpc_add_handler(RpcSession* session, pb_size_t message_tag, RpcHandler* handler) { diff --git a/firmware/targets/f7/Inc/FreeRTOSConfig.h b/firmware/targets/f7/Inc/FreeRTOSConfig.h index f54d774c..ab2dc14e 100644 --- a/firmware/targets/f7/Inc/FreeRTOSConfig.h +++ b/firmware/targets/f7/Inc/FreeRTOSConfig.h @@ -14,7 +14,7 @@ extern uint32_t SystemCoreClock; #define configENABLE_MPU 0 #define configUSE_PREEMPTION 1 -#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_STATIC_ALLOCATION 1 #define configSUPPORT_DYNAMIC_ALLOCATION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 diff --git a/firmware/targets/f7/fatfs/sector_cache.c b/firmware/targets/f7/fatfs/sector_cache.c new file mode 100644 index 00000000..5a4f1b97 --- /dev/null +++ b/firmware/targets/f7/fatfs/sector_cache.c @@ -0,0 +1,59 @@ +#include "sector_cache.h" + +#include +#include +#include +#include +#include + +#define SECTOR_SIZE 512 +#define N_SECTORS 8 + +typedef struct { + uint32_t itr; + uint32_t sectors[N_SECTORS]; + uint8_t sector_data[N_SECTORS][SECTOR_SIZE]; +} SectorCache; + +static SectorCache* cache = NULL; + +void sector_cache_init() { + if(cache == NULL) { + cache = furi_hal_memory_alloc(sizeof(SectorCache)); + } + + if(cache != NULL) { + FURI_LOG_I("SectorCache", "Initializing sector cache"); + memset(cache, 0, sizeof(SectorCache)); + } else { + FURI_LOG_E("SectorCache", "Cannot enable sector cache"); + } +} + +uint8_t* sector_cache_get(uint32_t n_sector) { + if(cache != NULL && n_sector != 0) { + for(int sector_i = 0; sector_i < N_SECTORS; ++sector_i) { + if(cache->sectors[sector_i] == n_sector) { + return cache->sector_data[sector_i]; + } + } + } + return NULL; +} + +void sector_cache_put(uint32_t n_sector, uint8_t* data) { + if(cache == NULL) return; + cache->sectors[cache->itr % N_SECTORS] = n_sector; + memcpy(cache->sector_data[cache->itr % N_SECTORS], data, SECTOR_SIZE); + cache->itr++; +} + +void sector_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector) { + if(cache == NULL) return; + for(int sector_i = 0; sector_i < N_SECTORS; ++sector_i) { + if((cache->sectors[sector_i] >= start_sector) && + (cache->sectors[sector_i] <= end_sector)) { + cache->sectors[sector_i] = 0; + } + } +} \ No newline at end of file diff --git a/firmware/targets/f7/fatfs/sector_cache.h b/firmware/targets/f7/fatfs/sector_cache.h new file mode 100644 index 00000000..5fe4a2ed --- /dev/null +++ b/firmware/targets/f7/fatfs/sector_cache.h @@ -0,0 +1,36 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Init sector cache system + */ +void sector_cache_init(); + +/** + * @brief Get sector data from cache + * @param n_sector Sector number + * @return Pointer to sector data or NULL if not found + */ +uint8_t* sector_cache_get(uint32_t n_sector); + +/** + * @brief Put sector data to cache + * @param n_sector Sector number + * @param data Pointer to sector data + */ +void sector_cache_put(uint32_t n_sector, uint8_t* data); + +/** + * @brief Invalidate sector cache for given range + * @param start_sector Start sector number + * @param end_sector End sector number + */ +void sector_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/fatfs/stm32_adafruit_sd.c b/firmware/targets/f7/fatfs/stm32_adafruit_sd.c index 6db430a5..07cae31f 100644 --- a/firmware/targets/f7/fatfs/stm32_adafruit_sd.c +++ b/firmware/targets/f7/fatfs/stm32_adafruit_sd.c @@ -92,6 +92,7 @@ #include "string.h" #include "stdio.h" #include +#include "sector_cache.h" /** @addtogroup BSP * @{ @@ -377,6 +378,8 @@ uint8_t BSP_SD_Init(bool reset_card) { furi_hal_sd_spi_handle = NULL; furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_slow); + sector_cache_init(); + /* SD initialized and set to SPI mode properly */ return res; } @@ -427,9 +430,15 @@ uint8_t uint32_t offset = 0; uint32_t addr; uint8_t retr = BSP_SD_ERROR; - uint8_t* ptr = NULL; SD_CmdAnswer_typedef response; uint16_t BlockSize = 512; + uint8_t* cached_data; + + bool single_sector_read = (NumOfBlocks == 1); + if(single_sector_read && (cached_data = sector_cache_get(ReadAddr))) { + memcpy(pData, cached_data, BlockSize); + return BSP_SD_OK; + } /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */ @@ -440,12 +449,6 @@ uint8_t goto error; } - ptr = malloc(sizeof(uint8_t) * BlockSize); - if(ptr == NULL) { - goto error; - } - memset(ptr, SD_DUMMY_BYTE, sizeof(uint8_t) * BlockSize); - /* Initialize the address */ addr = (ReadAddr * ((flag_SDHC == 1) ? 1 : BlockSize)); @@ -461,7 +464,7 @@ uint8_t /* Now look for the data token to signify the start of the data */ if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) { /* Read the SD block data : read NumByteToRead data */ - SD_IO_WriteReadData(ptr, (uint8_t*)pData + offset, BlockSize); + SD_IO_WriteReadData(NULL, (uint8_t*)pData + offset, BlockSize); /* Set next read address*/ offset += BlockSize; @@ -479,13 +482,16 @@ uint8_t SD_IO_WriteByte(SD_DUMMY_BYTE); } + if(single_sector_read) { + sector_cache_put(ReadAddr, (uint8_t*)pData); + } + retr = BSP_SD_OK; error: /* Send dummy byte: 8 Clock pulses of delay */ SD_IO_CSState(1); SD_IO_WriteByte(SD_DUMMY_BYTE); - if(ptr != NULL) free(ptr); /* Return the reponse */ return retr; @@ -509,9 +515,9 @@ uint8_t BSP_SD_WriteBlocks( uint32_t offset = 0; uint32_t addr; uint8_t retr = BSP_SD_ERROR; - uint8_t* ptr = NULL; SD_CmdAnswer_typedef response; uint16_t BlockSize = 512; + sector_cache_invalidate_range(WriteAddr, WriteAddr + NumOfBlocks); /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */ @@ -522,11 +528,6 @@ uint8_t BSP_SD_WriteBlocks( goto error; } - ptr = malloc(sizeof(uint8_t) * BlockSize); - if(ptr == NULL) { - goto error; - } - /* Initialize the address */ addr = (WriteAddr * ((flag_SDHC == 1) ? 1 : BlockSize)); @@ -547,7 +548,7 @@ uint8_t BSP_SD_WriteBlocks( SD_IO_WriteByte(SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE); /* Write the block data to SD */ - SD_IO_WriteReadData((uint8_t*)pData + offset, ptr, BlockSize); + SD_IO_WriteReadData((uint8_t*)pData + offset, NULL, BlockSize); /* Set next write address */ offset += BlockSize; @@ -569,7 +570,7 @@ uint8_t BSP_SD_WriteBlocks( retr = BSP_SD_OK; error: - if(ptr != NULL) free(ptr); + /* Send dummy byte: 8 Clock pulses of delay */ SD_IO_CSState(1); SD_IO_WriteByte(SD_DUMMY_BYTE); diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index d0856127..141efdb6 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -1,5 +1,6 @@ #include #include +#include #include @@ -78,6 +79,7 @@ void furi_hal_init() { furi_hal_rfid_init(); #endif furi_hal_bt_init(); + furi_hal_memory_init(); furi_hal_compress_icon_init(); // FatFS driver initialization diff --git a/firmware/targets/f7/furi_hal/furi_hal_memory.c b/firmware/targets/f7/furi_hal/furi_hal_memory.c new file mode 100644 index 00000000..43dc56f1 --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_memory.c @@ -0,0 +1,119 @@ +#include +#include +#include + +#define TAG "FuriHalMemory" + +typedef enum { + SRAM_A, + SRAM_B, + SRAM_MAX, +} SRAM; + +typedef struct { + void* start; + uint32_t size; +} FuriHalMemoryRegion; + +typedef struct { + FuriHalMemoryRegion region[SRAM_MAX]; +} FuriHalMemory; + +static FuriHalMemory* furi_hal_memory = NULL; + +extern const void __sram2a_start__; +extern const void __sram2a_free__; +extern const void __sram2b_start__; + +void furi_hal_memory_init() { + if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { + return; + } + + if(!ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT)) { + FURI_LOG_E(TAG, "C2 start timeout"); + return; + } + + FuriHalMemory* memory = malloc(sizeof(FuriHalMemory)); + + const BleGlueC2Info* c2_ver = ble_glue_get_c2_info(); + + if(c2_ver->mode == BleGlueC2ModeStack) { + uint32_t sram2a_busy_size = (uint32_t)&__sram2a_free__ - (uint32_t)&__sram2a_start__; + uint32_t sram2a_unprotected_size = (32 - c2_ver->MemorySizeSram2A) * 1024; + uint32_t sram2b_unprotected_size = (32 - c2_ver->MemorySizeSram2B) * 1024; + + memory->region[SRAM_A].start = (uint8_t*)&__sram2a_free__; + memory->region[SRAM_B].start = (uint8_t*)&__sram2b_start__; + + if(sram2a_unprotected_size > sram2a_busy_size) { + memory->region[SRAM_A].size = sram2a_unprotected_size - sram2a_busy_size; + } else { + memory->region[SRAM_A].size = 0; + } + memory->region[SRAM_B].size = sram2b_unprotected_size; + + FURI_LOG_I( + TAG, "SRAM2A: 0x%p, %d", memory->region[SRAM_A].start, memory->region[SRAM_A].size); + FURI_LOG_I( + TAG, "SRAM2B: 0x%p, %d", memory->region[SRAM_B].start, memory->region[SRAM_B].size); + + if((memory->region[SRAM_A].size > 0) || (memory->region[SRAM_B].size > 0)) { + if((memory->region[SRAM_A].size > 0)) { + FURI_LOG_I(TAG, "SRAM2A clear"); + memset(memory->region[SRAM_A].start, 0, memory->region[SRAM_A].size); + } + if((memory->region[SRAM_B].size > 0)) { + FURI_LOG_I(TAG, "SRAM2B clear"); + memset(memory->region[SRAM_B].start, 0, memory->region[SRAM_B].size); + } + furi_hal_memory = memory; + FURI_LOG_I(TAG, "Enabled"); + } else { + free(memory); + FURI_LOG_E(TAG, "No SRAM2 available"); + } + } else { + free(memory); + FURI_LOG_E(TAG, "No Core2 available"); + } +} + +void* furi_hal_memory_alloc(size_t size) { + if(furi_hal_memory == NULL) { + return NULL; + } + + for(int i = 0; i < SRAM_MAX; i++) { + if(furi_hal_memory->region[i].size >= size) { + void* ptr = furi_hal_memory->region[i].start; + furi_hal_memory->region[i].start += size; + furi_hal_memory->region[i].size -= size; + return ptr; + } + } + return NULL; +} + +size_t furi_hal_memory_get_free() { + if(furi_hal_memory == NULL) return 0; + + size_t free = 0; + for(int i = 0; i < SRAM_MAX; i++) { + free += furi_hal_memory->region[i].size; + } + return free; +} + +size_t furi_hal_memory_max_pool_block() { + if(furi_hal_memory == NULL) return 0; + + size_t max = 0; + for(int i = 0; i < SRAM_MAX; i++) { + if(furi_hal_memory->region[i].size > max) { + max = furi_hal_memory->region[i].size; + } + } + return max; +} \ No newline at end of file diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi.c b/firmware/targets/f7/furi_hal/furi_hal_spi.c index f8c5a2c7..2d54278d 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi.c +++ b/firmware/targets/f7/furi_hal/furi_hal_spi.c @@ -139,8 +139,6 @@ bool furi_hal_spi_bus_trx( uint32_t timeout) { furi_assert(handle); furi_assert(handle->bus->current_handle == handle); - furi_assert(tx_buffer); - furi_assert(rx_buffer); furi_assert(size > 0); bool ret = true; @@ -149,15 +147,23 @@ bool furi_hal_spi_bus_trx( while(size > 0) { if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE(handle->bus->spi) && tx_allowed) { - LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer); - tx_buffer++; + if(tx_buffer) { + LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer); + tx_buffer++; + } else { + LL_SPI_TransmitData8(handle->bus->spi, 0xFF); + } tx_size--; tx_allowed = false; } if(LL_SPI_IsActiveFlag_RXNE(handle->bus->spi)) { - *rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi); - rx_buffer++; + if(rx_buffer) { + *rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi); + rx_buffer++; + } else { + LL_SPI_ReceiveData8(handle->bus->spi); + } size--; tx_allowed = true; } diff --git a/firmware/targets/f7/stm32wb55xx_flash.ld b/firmware/targets/f7/stm32wb55xx_flash.ld index 20314ba3..4124c096 100644 --- a/firmware/targets/f7/stm32wb55xx_flash.ld +++ b/firmware/targets/f7/stm32wb55xx_flash.ld @@ -57,7 +57,8 @@ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K RAM1 (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8 -RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +RAM2A (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +RAM2B (xrw) : ORIGIN = 0x20038000, LENGTH = 10K } /* Define output sections */ @@ -186,9 +187,12 @@ SECTIONS } .ARM.attributes 0 : { *(.ARM.attributes) } - MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED - MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED - MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED + ._sram2a_start : { . = ALIGN(4); __sram2a_start__ = .; } >RAM2A + MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM2A + MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM2A + MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM2A + ._sram2a_free : { . = ALIGN(4); __sram2a_free__ = .; } >RAM2A + ._sram2b_start : { . = ALIGN(4); __sram2b_start__ = .; } >RAM2B } diff --git a/firmware/targets/f7/stm32wb55xx_ram_fw.ld b/firmware/targets/f7/stm32wb55xx_ram_fw.ld index 8c4d41c5..1b7fe360 100644 --- a/firmware/targets/f7/stm32wb55xx_ram_fw.ld +++ b/firmware/targets/f7/stm32wb55xx_ram_fw.ld @@ -57,7 +57,8 @@ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K RAM1 (xrw) : ORIGIN = 0x20000000, LENGTH = 0x30000 -RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +RAM2A (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +RAM2B (xrw) : ORIGIN = 0x20038000, LENGTH = 10K } /* Define output sections */ @@ -184,9 +185,12 @@ SECTIONS } .ARM.attributes 0 : { *(.ARM.attributes) } - MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED - MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED - MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED + ._sram2a_start : { . = ALIGN(4); __sram2a_start__ = .; } >RAM2A + MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM2A + MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM2A + MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM2A + ._sram2a_free : { . = ALIGN(4); __sram2a_free__ = .; } >RAM2A + ._sram2b_start : { . = ALIGN(4); __sram2b_start__ = .; } >RAM2B } diff --git a/firmware/targets/furi_hal_include/furi_hal_memory.h b/firmware/targets/furi_hal_include/furi_hal_memory.h new file mode 100644 index 00000000..e9efa08c --- /dev/null +++ b/firmware/targets/furi_hal_include/furi_hal_memory.h @@ -0,0 +1,44 @@ +/** + * @file furi_hal_memory.h + * Memory HAL API + */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Init memory pool manager + */ +void furi_hal_memory_init(); + +/** + * @brief Allocate memory from separate memory pool. That memory can't be freed. + * + * @param size + * @return void* + */ +void* furi_hal_memory_alloc(size_t size); + +/** + * @brief Get free memory pool size + * + * @return size_t + */ +size_t furi_hal_memory_get_free(); + +/** + * @brief Get max free block size from memory pool + * + * @return size_t + */ +size_t furi_hal_memory_max_pool_block(); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/furi/core/memmgr.c b/furi/core/memmgr.c index 80f87b93..dba1a707 100644 --- a/furi/core/memmgr.c +++ b/furi/core/memmgr.c @@ -1,6 +1,7 @@ #include "memmgr.h" #include "common_defines.h" #include +#include extern void* pvPortMalloc(size_t xSize); extern void vPortFree(void* pv); @@ -77,3 +78,18 @@ void* __wrap__realloc_r(struct _reent* r, void* ptr, size_t size) { UNUSED(r); return realloc(ptr, size); } + +void* memmgr_alloc_from_pool(size_t size) { + void* p = furi_hal_memory_alloc(size); + if(p == NULL) p = malloc(size); + + return p; +} + +size_t memmgr_pool_get_free(void) { + return furi_hal_memory_get_free(); +} + +size_t memmgr_pool_get_max_block(void) { + return furi_hal_memory_max_pool_block(); +} \ No newline at end of file diff --git a/furi/core/memmgr.h b/furi/core/memmgr.h index d7285fb2..fdecfd72 100644 --- a/furi/core/memmgr.h +++ b/furi/core/memmgr.h @@ -35,6 +35,28 @@ size_t memmgr_get_total_heap(void); */ size_t memmgr_get_minimum_free_heap(void); +/** + * @brief Allocate memory from separate memory pool. That memory can't be freed. + * + * @param size + * @return void* + */ +void* memmgr_alloc_from_pool(size_t size); + +/** + * @brief Get free memory pool size + * + * @return size_t + */ +size_t memmgr_pool_get_free(void); + +/** + * @brief Get max free block size from memory pool + * + * @return size_t + */ +size_t memmgr_pool_get_max_block(void); + #ifdef __cplusplus } #endif diff --git a/furi/core/thread.c b/furi/core/thread.c index 044f8371..a68472b5 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -7,7 +7,9 @@ #include "mutex.h" #include +#include "log.h" #include +#include #include #define THREAD_NOTIFY_INDEX 1 // Index 0 is used for stream buffers @@ -20,6 +22,7 @@ struct FuriThreadStdout { }; struct FuriThread { + bool is_service; FuriThreadState state; int32_t ret; @@ -84,6 +87,11 @@ static void furi_thread_body(void* context) { furi_assert(thread->state == FuriThreadStateRunning); furi_thread_set_state(thread, FuriThreadStateStopped); + if(thread->is_service) { + FURI_LOG_E( + "Service", "%s thread exited. Thread memory cannot be reclaimed.", thread->name); + } + // clear thread local storage __furi_thread_stdout_flush(thread); furi_assert(pvTaskGetThreadLocalStoragePointer(NULL, 0) != NULL); @@ -96,7 +104,7 @@ static void furi_thread_body(void* context) { FuriThread* furi_thread_alloc() { FuriThread* thread = malloc(sizeof(FuriThread)); string_init(thread->output.buffer); - + thread->is_service = false; return thread; } @@ -117,6 +125,10 @@ void furi_thread_set_name(FuriThread* thread, const char* name) { thread->name = name ? strdup(name) : NULL; } +void furi_thread_mark_as_service(FuriThread* thread) { + thread->is_service = true; +} + void furi_thread_set_stack_size(FuriThread* thread, size_t stack_size) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); @@ -168,15 +180,23 @@ void furi_thread_start(FuriThread* thread) { furi_thread_set_state(thread, FuriThreadStateStarting); - BaseType_t ret = xTaskCreate( - furi_thread_body, - thread->name, - thread->stack_size / 4, - thread, - thread->priority ? thread->priority : FuriThreadPriorityNormal, - &thread->task_handle); + uint32_t stack = thread->stack_size / 4; + UBaseType_t priority = thread->priority ? thread->priority : FuriThreadPriorityNormal; + if(thread->is_service) { + thread->task_handle = xTaskCreateStatic( + furi_thread_body, + thread->name, + stack, + thread, + priority, + memmgr_alloc_from_pool(sizeof(StackType_t) * stack), + memmgr_alloc_from_pool(sizeof(StaticTask_t))); + } else { + BaseType_t ret = xTaskCreate( + furi_thread_body, thread->name, stack, thread, priority, &thread->task_handle); + furi_check(ret == pdPASS); + } - furi_check(ret == pdPASS); furi_check(thread->task_handle); } diff --git a/furi/core/thread.h b/furi/core/thread.h index 7f746f03..f15b9ff6 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -73,6 +73,13 @@ void furi_thread_free(FuriThread* thread); */ void furi_thread_set_name(FuriThread* thread, const char* name); +/** Mark thread as service + * The service cannot be stopped or removed, and cannot exit from the thread body + * + * @param thread + */ +void furi_thread_mark_as_service(FuriThread* thread); + /** Set FuriThread stack size * * @param thread FuriThread instance diff --git a/furi/flipper.c b/furi/flipper.c index c7d7c5a6..2acfea01 100755 --- a/furi/flipper.c +++ b/furi/flipper.c @@ -2,6 +2,7 @@ #include #include #include +#include #define TAG "Flipper" @@ -38,9 +39,28 @@ void flipper_init() { furi_thread_set_name(thread, FLIPPER_SERVICES[i].name); furi_thread_set_stack_size(thread, FLIPPER_SERVICES[i].stack_size); furi_thread_set_callback(thread, FLIPPER_SERVICES[i].app); + furi_thread_mark_as_service(thread); furi_thread_start(thread); } FURI_LOG_I(TAG, "services startup complete"); } + +void vApplicationGetIdleTaskMemory( + StaticTask_t** tcb_ptr, + StackType_t** stack_ptr, + uint32_t* stack_size) { + *tcb_ptr = memmgr_alloc_from_pool(sizeof(StaticTask_t)); + *stack_ptr = memmgr_alloc_from_pool(sizeof(StackType_t) * configMINIMAL_STACK_SIZE); + *stack_size = configMINIMAL_STACK_SIZE; +} + +void vApplicationGetTimerTaskMemory( + StaticTask_t** tcb_ptr, + StackType_t** stack_ptr, + uint32_t* stack_size) { + *tcb_ptr = memmgr_alloc_from_pool(sizeof(StaticTask_t)); + *stack_ptr = memmgr_alloc_from_pool(sizeof(StackType_t) * configTIMER_TASK_STACK_DEPTH); + *stack_size = configTIMER_TASK_STACK_DEPTH; +} \ No newline at end of file