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("Total heap size: %d\r\n", memmgr_get_total_heap()); | ||||||
|     printf("Minimum heap size: %d\r\n", memmgr_get_minimum_free_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("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) { | void cli_command_free_blocks(Cli* cli, string_t args, void* context) { | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ App( | |||||||
|     name="Basic services", |     name="Basic services", | ||||||
|     apptype=FlipperAppType.METAPACKAGE, |     apptype=FlipperAppType.METAPACKAGE, | ||||||
|     provides=[ |     provides=[ | ||||||
|         "rpc", |         "rpc_start", | ||||||
|         "bt", |         "bt", | ||||||
|         "desktop", |         "desktop", | ||||||
|         "loader", |         "loader", | ||||||
|  | |||||||
| @ -1,12 +1,8 @@ | |||||||
| App( | App( | ||||||
|     appid="rpc", |     appid="rpc_start", | ||||||
|     name="RpcSrv", |     apptype=FlipperAppType.STARTUP, | ||||||
|     apptype=FlipperAppType.SERVICE, |     entry_point="rpc_on_system_start", | ||||||
|     entry_point="rpc_srv", |  | ||||||
|     cdefines=["SRV_RPC"], |     cdefines=["SRV_RPC"], | ||||||
|     requires=[ |     requires=["cli"], | ||||||
|         "cli", |  | ||||||
|     ], |  | ||||||
|     stack_size=4 * 1024, |  | ||||||
|     order=10, |     order=10, | ||||||
| ) | ) | ||||||
|  | |||||||
| @ -395,7 +395,7 @@ void rpc_session_close(RpcSession* session) { | |||||||
|     furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtDisconnect); |     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); |     UNUSED(p); | ||||||
|     Rpc* rpc = malloc(sizeof(Rpc)); |     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); |         cli, "start_rpc_session", CliCommandFlagParallelSafe, rpc_cli_command_start_session, rpc); | ||||||
| 
 | 
 | ||||||
|     furi_record_create(RECORD_RPC, rpc); |     furi_record_create(RECORD_RPC, rpc); | ||||||
| 
 |  | ||||||
|     return 0; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void rpc_add_handler(RpcSession* session, pb_size_t message_tag, RpcHandler* handler) { | 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 configENABLE_MPU 0 | ||||||
| 
 | 
 | ||||||
| #define configUSE_PREEMPTION 1 | #define configUSE_PREEMPTION 1 | ||||||
| #define configSUPPORT_STATIC_ALLOCATION 0 | #define configSUPPORT_STATIC_ALLOCATION 1 | ||||||
| #define configSUPPORT_DYNAMIC_ALLOCATION 1 | #define configSUPPORT_DYNAMIC_ALLOCATION 1 | ||||||
| #define configUSE_IDLE_HOOK 0 | #define configUSE_IDLE_HOOK 0 | ||||||
| #define configUSE_TICK_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 "string.h" | ||||||
| #include "stdio.h" | #include "stdio.h" | ||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
|  | #include "sector_cache.h" | ||||||
| 
 | 
 | ||||||
| /** @addtogroup BSP
 | /** @addtogroup BSP
 | ||||||
|   * @{ |   * @{ | ||||||
| @ -377,6 +378,8 @@ uint8_t BSP_SD_Init(bool reset_card) { | |||||||
|     furi_hal_sd_spi_handle = NULL; |     furi_hal_sd_spi_handle = NULL; | ||||||
|     furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_slow); |     furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_slow); | ||||||
| 
 | 
 | ||||||
|  |     sector_cache_init(); | ||||||
|  | 
 | ||||||
|     /* SD initialized and set to SPI mode properly */ |     /* SD initialized and set to SPI mode properly */ | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| @ -427,9 +430,15 @@ uint8_t | |||||||
|     uint32_t offset = 0; |     uint32_t offset = 0; | ||||||
|     uint32_t addr; |     uint32_t addr; | ||||||
|     uint8_t retr = BSP_SD_ERROR; |     uint8_t retr = BSP_SD_ERROR; | ||||||
|     uint8_t* ptr = NULL; |  | ||||||
|     SD_CmdAnswer_typedef response; |     SD_CmdAnswer_typedef response; | ||||||
|     uint16_t BlockSize = 512; |     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 
 |     /* 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) */ |      Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */ | ||||||
| @ -440,12 +449,6 @@ uint8_t | |||||||
|         goto error; |         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 */ |     /* Initialize the address */ | ||||||
|     addr = (ReadAddr * ((flag_SDHC == 1) ? 1 : BlockSize)); |     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 */ |         /* 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) { |         if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) { | ||||||
|             /* Read the SD block data : read NumByteToRead data */ |             /* 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*/ |             /* Set next read address*/ | ||||||
|             offset += BlockSize; |             offset += BlockSize; | ||||||
| @ -479,13 +482,16 @@ uint8_t | |||||||
|         SD_IO_WriteByte(SD_DUMMY_BYTE); |         SD_IO_WriteByte(SD_DUMMY_BYTE); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if(single_sector_read) { | ||||||
|  |         sector_cache_put(ReadAddr, (uint8_t*)pData); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     retr = BSP_SD_OK; |     retr = BSP_SD_OK; | ||||||
| 
 | 
 | ||||||
| error: | error: | ||||||
|     /* Send dummy byte: 8 Clock pulses of delay */ |     /* Send dummy byte: 8 Clock pulses of delay */ | ||||||
|     SD_IO_CSState(1); |     SD_IO_CSState(1); | ||||||
|     SD_IO_WriteByte(SD_DUMMY_BYTE); |     SD_IO_WriteByte(SD_DUMMY_BYTE); | ||||||
|     if(ptr != NULL) free(ptr); |  | ||||||
| 
 | 
 | ||||||
|     /* Return the reponse */ |     /* Return the reponse */ | ||||||
|     return retr; |     return retr; | ||||||
| @ -509,9 +515,9 @@ uint8_t BSP_SD_WriteBlocks( | |||||||
|     uint32_t offset = 0; |     uint32_t offset = 0; | ||||||
|     uint32_t addr; |     uint32_t addr; | ||||||
|     uint8_t retr = BSP_SD_ERROR; |     uint8_t retr = BSP_SD_ERROR; | ||||||
|     uint8_t* ptr = NULL; |  | ||||||
|     SD_CmdAnswer_typedef response; |     SD_CmdAnswer_typedef response; | ||||||
|     uint16_t BlockSize = 512; |     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 
 |     /* 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) */ |      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; |         goto error; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ptr = malloc(sizeof(uint8_t) * BlockSize); |  | ||||||
|     if(ptr == NULL) { |  | ||||||
|         goto error; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* Initialize the address */ |     /* Initialize the address */ | ||||||
|     addr = (WriteAddr * ((flag_SDHC == 1) ? 1 : BlockSize)); |     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); |         SD_IO_WriteByte(SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE); | ||||||
| 
 | 
 | ||||||
|         /* Write the block data to SD */ |         /* 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 */ |         /* Set next write address */ | ||||||
|         offset += BlockSize; |         offset += BlockSize; | ||||||
| @ -569,7 +570,7 @@ uint8_t BSP_SD_WriteBlocks( | |||||||
|     retr = BSP_SD_OK; |     retr = BSP_SD_OK; | ||||||
| 
 | 
 | ||||||
| error: | error: | ||||||
|     if(ptr != NULL) free(ptr); | 
 | ||||||
|     /* Send dummy byte: 8 Clock pulses of delay */ |     /* Send dummy byte: 8 Clock pulses of delay */ | ||||||
|     SD_IO_CSState(1); |     SD_IO_CSState(1); | ||||||
|     SD_IO_WriteByte(SD_DUMMY_BYTE); |     SD_IO_WriteByte(SD_DUMMY_BYTE); | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| #include <furi_hal_mpu.h> | #include <furi_hal_mpu.h> | ||||||
|  | #include <furi_hal_memory.h> | ||||||
| 
 | 
 | ||||||
| #include <stm32wbxx_ll_cortex.h> | #include <stm32wbxx_ll_cortex.h> | ||||||
| 
 | 
 | ||||||
| @ -78,6 +79,7 @@ void furi_hal_init() { | |||||||
|     furi_hal_rfid_init(); |     furi_hal_rfid_init(); | ||||||
| #endif | #endif | ||||||
|     furi_hal_bt_init(); |     furi_hal_bt_init(); | ||||||
|  |     furi_hal_memory_init(); | ||||||
|     furi_hal_compress_icon_init(); |     furi_hal_compress_icon_init(); | ||||||
| 
 | 
 | ||||||
|     // FatFS driver initialization
 |     // 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) { |     uint32_t timeout) { | ||||||
|     furi_assert(handle); |     furi_assert(handle); | ||||||
|     furi_assert(handle->bus->current_handle == handle); |     furi_assert(handle->bus->current_handle == handle); | ||||||
|     furi_assert(tx_buffer); |  | ||||||
|     furi_assert(rx_buffer); |  | ||||||
|     furi_assert(size > 0); |     furi_assert(size > 0); | ||||||
| 
 | 
 | ||||||
|     bool ret = true; |     bool ret = true; | ||||||
| @ -149,15 +147,23 @@ bool furi_hal_spi_bus_trx( | |||||||
| 
 | 
 | ||||||
|     while(size > 0) { |     while(size > 0) { | ||||||
|         if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE(handle->bus->spi) && tx_allowed) { |         if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE(handle->bus->spi) && tx_allowed) { | ||||||
|             LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer); |             if(tx_buffer) { | ||||||
|             tx_buffer++; |                 LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer); | ||||||
|  |                 tx_buffer++; | ||||||
|  |             } else { | ||||||
|  |                 LL_SPI_TransmitData8(handle->bus->spi, 0xFF); | ||||||
|  |             } | ||||||
|             tx_size--; |             tx_size--; | ||||||
|             tx_allowed = false; |             tx_allowed = false; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(LL_SPI_IsActiveFlag_RXNE(handle->bus->spi)) { |         if(LL_SPI_IsActiveFlag_RXNE(handle->bus->spi)) { | ||||||
|             *rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi); |             if(rx_buffer) { | ||||||
|             rx_buffer++; |                 *rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi); | ||||||
|  |                 rx_buffer++; | ||||||
|  |             } else { | ||||||
|  |                 LL_SPI_ReceiveData8(handle->bus->spi); | ||||||
|  |             } | ||||||
|             size--; |             size--; | ||||||
|             tx_allowed = true; |             tx_allowed = true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -57,7 +57,8 @@ MEMORY | |||||||
| { | { | ||||||
| FLASH (rx)                 : ORIGIN = 0x08000000, LENGTH = 1024K | FLASH (rx)                 : ORIGIN = 0x08000000, LENGTH = 1024K | ||||||
| RAM1 (xrw)                 : ORIGIN = 0x20000008, LENGTH = 0x2FFF8 | 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 */ | /* Define output sections */ | ||||||
| @ -186,9 +187,12 @@ SECTIONS | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .ARM.attributes 0       : { *(.ARM.attributes) } |   .ARM.attributes 0       : { *(.ARM.attributes) } | ||||||
|    MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED |   ._sram2a_start : { . = ALIGN(4); __sram2a_start__ = .; } >RAM2A | ||||||
|    MB_MEM1 (NOLOAD)       : { *(MB_MEM1) } >RAM_SHARED |    MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM2A | ||||||
|    MB_MEM2 (NOLOAD)       : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED |    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 | FLASH (rx)                 : ORIGIN = 0x08000000, LENGTH = 1024K | ||||||
| RAM1 (xrw)                 : ORIGIN = 0x20000000, LENGTH = 0x30000 | 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 */ | /* Define output sections */ | ||||||
| @ -184,9 +185,12 @@ SECTIONS | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .ARM.attributes 0       : { *(.ARM.attributes) } |   .ARM.attributes 0       : { *(.ARM.attributes) } | ||||||
|    MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED |   ._sram2a_start : { . = ALIGN(4); __sram2a_start__ = .; } >RAM2A | ||||||
|    MB_MEM1 (NOLOAD)       : { *(MB_MEM1) } >RAM_SHARED |    MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM2A | ||||||
|    MB_MEM2 (NOLOAD)       : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED |    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 "memmgr.h" | ||||||
| #include "common_defines.h" | #include "common_defines.h" | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  | #include <furi_hal_memory.h> | ||||||
| 
 | 
 | ||||||
| extern void* pvPortMalloc(size_t xSize); | extern void* pvPortMalloc(size_t xSize); | ||||||
| extern void vPortFree(void* pv); | extern void vPortFree(void* pv); | ||||||
| @ -77,3 +78,18 @@ void* __wrap__realloc_r(struct _reent* r, void* ptr, size_t size) { | |||||||
|     UNUSED(r); |     UNUSED(r); | ||||||
|     return realloc(ptr, size); |     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); | 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 | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -7,7 +7,9 @@ | |||||||
| #include "mutex.h" | #include "mutex.h" | ||||||
| 
 | 
 | ||||||
| #include <task.h> | #include <task.h> | ||||||
|  | #include "log.h" | ||||||
| #include <m-string.h> | #include <m-string.h> | ||||||
|  | #include <furi_hal_rtc.h> | ||||||
| #include <furi_hal_console.h> | #include <furi_hal_console.h> | ||||||
| 
 | 
 | ||||||
| #define THREAD_NOTIFY_INDEX 1 // Index 0 is used for stream buffers
 | #define THREAD_NOTIFY_INDEX 1 // Index 0 is used for stream buffers
 | ||||||
| @ -20,6 +22,7 @@ struct FuriThreadStdout { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct FuriThread { | struct FuriThread { | ||||||
|  |     bool is_service; | ||||||
|     FuriThreadState state; |     FuriThreadState state; | ||||||
|     int32_t ret; |     int32_t ret; | ||||||
| 
 | 
 | ||||||
| @ -84,6 +87,11 @@ static void furi_thread_body(void* context) { | |||||||
|     furi_assert(thread->state == FuriThreadStateRunning); |     furi_assert(thread->state == FuriThreadStateRunning); | ||||||
|     furi_thread_set_state(thread, FuriThreadStateStopped); |     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
 |     // clear thread local storage
 | ||||||
|     __furi_thread_stdout_flush(thread); |     __furi_thread_stdout_flush(thread); | ||||||
|     furi_assert(pvTaskGetThreadLocalStoragePointer(NULL, 0) != NULL); |     furi_assert(pvTaskGetThreadLocalStoragePointer(NULL, 0) != NULL); | ||||||
| @ -96,7 +104,7 @@ static void furi_thread_body(void* context) { | |||||||
| FuriThread* furi_thread_alloc() { | FuriThread* furi_thread_alloc() { | ||||||
|     FuriThread* thread = malloc(sizeof(FuriThread)); |     FuriThread* thread = malloc(sizeof(FuriThread)); | ||||||
|     string_init(thread->output.buffer); |     string_init(thread->output.buffer); | ||||||
| 
 |     thread->is_service = false; | ||||||
|     return thread; |     return thread; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -117,6 +125,10 @@ void furi_thread_set_name(FuriThread* thread, const char* name) { | |||||||
|     thread->name = name ? strdup(name) : NULL; |     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) { | void furi_thread_set_stack_size(FuriThread* thread, size_t stack_size) { | ||||||
|     furi_assert(thread); |     furi_assert(thread); | ||||||
|     furi_assert(thread->state == FuriThreadStateStopped); |     furi_assert(thread->state == FuriThreadStateStopped); | ||||||
| @ -168,15 +180,23 @@ void furi_thread_start(FuriThread* thread) { | |||||||
| 
 | 
 | ||||||
|     furi_thread_set_state(thread, FuriThreadStateStarting); |     furi_thread_set_state(thread, FuriThreadStateStarting); | ||||||
| 
 | 
 | ||||||
|     BaseType_t ret = xTaskCreate( |     uint32_t stack = thread->stack_size / 4; | ||||||
|         furi_thread_body, |     UBaseType_t priority = thread->priority ? thread->priority : FuriThreadPriorityNormal; | ||||||
|         thread->name, |     if(thread->is_service) { | ||||||
|         thread->stack_size / 4, |         thread->task_handle = xTaskCreateStatic( | ||||||
|         thread, |             furi_thread_body, | ||||||
|         thread->priority ? thread->priority : FuriThreadPriorityNormal, |             thread->name, | ||||||
|         &thread->task_handle); |             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); |     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); | 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
 | /** Set FuriThread stack size
 | ||||||
|  * |  * | ||||||
|  * @param      thread      FuriThread instance |  * @param      thread      FuriThread instance | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| #include <applications.h> | #include <applications.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi_hal_version.h> | #include <furi_hal_version.h> | ||||||
|  | #include <furi_hal_memory.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "Flipper" | #define TAG "Flipper" | ||||||
| 
 | 
 | ||||||
| @ -38,9 +39,28 @@ void flipper_init() { | |||||||
|         furi_thread_set_name(thread, FLIPPER_SERVICES[i].name); |         furi_thread_set_name(thread, FLIPPER_SERVICES[i].name); | ||||||
|         furi_thread_set_stack_size(thread, FLIPPER_SERVICES[i].stack_size); |         furi_thread_set_stack_size(thread, FLIPPER_SERVICES[i].stack_size); | ||||||
|         furi_thread_set_callback(thread, FLIPPER_SERVICES[i].app); |         furi_thread_set_callback(thread, FLIPPER_SERVICES[i].app); | ||||||
|  |         furi_thread_mark_as_service(thread); | ||||||
| 
 | 
 | ||||||
|         furi_thread_start(thread); |         furi_thread_start(thread); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I(TAG, "services startup complete"); |     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