Speedup SD card & enlarge your RAM. (#1649)
* 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: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									ab4bb55d0f
								
							
						
					
					
						commit
						99a7d06f71
					
				| @ -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) { | ||||
|  | ||||
| @ -3,7 +3,7 @@ App( | ||||
|     name="Basic services", | ||||
|     apptype=FlipperAppType.METAPACKAGE, | ||||
|     provides=[ | ||||
|         "rpc", | ||||
|         "rpc_start", | ||||
|         "bt", | ||||
|         "desktop", | ||||
|         "loader", | ||||
|  | ||||
| @ -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, | ||||
| ) | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
							
								
								
									
										59
									
								
								firmware/targets/f7/fatfs/sector_cache.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								firmware/targets/f7/fatfs/sector_cache.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| #include "sector_cache.h" | ||||
| 
 | ||||
| #include <stddef.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <furi.h> | ||||
| #include <furi_hal_memory.h> | ||||
| 
 | ||||
| #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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										36
									
								
								firmware/targets/f7/fatfs/sector_cache.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								firmware/targets/f7/fatfs/sector_cache.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #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 | ||||
| @ -92,6 +92,7 @@ | ||||
| #include "string.h" | ||||
| #include "stdio.h" | ||||
| #include <furi_hal.h> | ||||
| #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); | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #include <furi_hal.h> | ||||
| #include <furi_hal_mpu.h> | ||||
| #include <furi_hal_memory.h> | ||||
| 
 | ||||
| #include <stm32wbxx_ll_cortex.h> | ||||
| 
 | ||||
| @ -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
 | ||||
|  | ||||
							
								
								
									
										119
									
								
								firmware/targets/f7/furi_hal/furi_hal_memory.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								firmware/targets/f7/furi_hal/furi_hal_memory.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,119 @@ | ||||
| #include <furi_hal.h> | ||||
| #include <furi_hal_memory.h> | ||||
| #include <furi_hal_rtc.h> | ||||
| 
 | ||||
| #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; | ||||
| } | ||||
| @ -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; | ||||
|         } | ||||
|  | ||||
| @ -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 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										44
									
								
								firmware/targets/furi_hal_include/furi_hal_memory.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								firmware/targets/furi_hal_include/furi_hal_memory.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| /**
 | ||||
|  * @file furi_hal_memory.h | ||||
|  * Memory HAL API | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #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 | ||||
| @ -1,6 +1,7 @@ | ||||
| #include "memmgr.h" | ||||
| #include "common_defines.h" | ||||
| #include <string.h> | ||||
| #include <furi_hal_memory.h> | ||||
| 
 | ||||
| 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(); | ||||
| } | ||||
| @ -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 | ||||
|  | ||||
| @ -7,7 +7,9 @@ | ||||
| #include "mutex.h" | ||||
| 
 | ||||
| #include <task.h> | ||||
| #include "log.h" | ||||
| #include <m-string.h> | ||||
| #include <furi_hal_rtc.h> | ||||
| #include <furi_hal_console.h> | ||||
| 
 | ||||
| #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); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| #include <applications.h> | ||||
| #include <furi.h> | ||||
| #include <furi_hal_version.h> | ||||
| #include <furi_hal_memory.h> | ||||
| 
 | ||||
| #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; | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 SG
						SG