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) {
|
||||||
|
if(tx_buffer) {
|
||||||
LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer);
|
LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer);
|
||||||
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)) {
|
||||||
|
if(rx_buffer) {
|
||||||
*rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi);
|
*rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi);
|
||||||
rx_buffer++;
|
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;
|
||||||
|
UBaseType_t priority = thread->priority ? thread->priority : FuriThreadPriorityNormal;
|
||||||
|
if(thread->is_service) {
|
||||||
|
thread->task_handle = xTaskCreateStatic(
|
||||||
furi_thread_body,
|
furi_thread_body,
|
||||||
thread->name,
|
thread->name,
|
||||||
thread->stack_size / 4,
|
stack,
|
||||||
thread,
|
thread,
|
||||||
thread->priority ? thread->priority : FuriThreadPriorityNormal,
|
priority,
|
||||||
&thread->task_handle);
|
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…
Reference in New Issue
Block a user