Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use all free RAM for FreeRTOS heap #2172

Merged
merged 17 commits into from
Dec 9, 2024
Merged
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,10 @@ add_definitions(-DFREERTOS)
add_definitions(-D__STACK_SIZE=1024)
add_definitions(-D__HEAP_SIZE=0)
add_definitions(-DMYNEWT_VAL_BLE_LL_RFMGMT_ENABLE_TIME=1500)
add_definitions(-DLFS_CONFIG=libs/lfs_config.h)

# _sbrk is purposefully not implemented so that builds fail when it is used
add_link_options(-Wl,-wrap=malloc -Wl,-wrap=free -Wl,-wrap=calloc -Wl,-wrap=realloc -Wl,-wrap=_malloc_r -Wl,-wrap=_sbrk)

# Note: Only use this for debugging
# Derive the low frequency clock from the main clock (SYNT)
Expand Down
28 changes: 16 additions & 12 deletions src/FreeRTOS/heap_4_infinitime.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,6 @@ task.h is included from an application file. */
/* Assumes 8bit bytes! */
#define heapBITS_PER_BYTE ( ( size_t ) 8 )

/* Allocate the memory for the heap. */
#if( configAPPLICATION_ALLOCATED_HEAP == 1 )
/* The application writer has already defined the array used for the RTOS
heap - probably so it can be placed in a special segment or address. */
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */

/* Define the linked list structure. This is used to link free blocks in order
of their memory address. */
typedef struct A_BLOCK_LINK
Expand Down Expand Up @@ -113,6 +104,8 @@ application. When the bit is free the block is still part of the free heap
space. */
static size_t xBlockAllocatedBit = 0;

static size_t xHeapSize = 0;

/*-----------------------------------------------------------*/

void *pvPortMalloc( size_t xWantedSize )
Expand Down Expand Up @@ -332,27 +325,38 @@ size_t xPortGetMinimumEverFreeHeapSize( void )
}
/*-----------------------------------------------------------*/

size_t xPortGetHeapSize( void )
{
return xHeapSize;
}
/*-----------------------------------------------------------*/

void vPortInitialiseBlocks( void )
{
/* This just exists to keep the linker quiet. */
}
/*-----------------------------------------------------------*/

extern uint8_t *__HeapLimit; // Defined by nrf_common.ld

static void prvHeapInit( void )
{
BlockLink_t *pxFirstFreeBlock;
uint8_t *pucAlignedHeap;
size_t uxAddress;
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
size_t xTotalHeapSize = ( size_t ) &__StackLimit - ( size_t ) &__HeapLimit;
uint8_t *pucHeap = ( uint8_t * ) &__HeapLimit;

xHeapSize = xTotalHeapSize;

/* Ensure the heap starts on a correctly aligned boundary. */
uxAddress = ( size_t ) ucHeap;
uxAddress = ( size_t ) pucHeap;

if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{
uxAddress += ( portBYTE_ALIGNMENT - 1 );
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
xTotalHeapSize -= uxAddress - ( size_t ) ucHeap;
xTotalHeapSize -= uxAddress - ( size_t ) pucHeap;
}

pucAlignedHeap = ( uint8_t * ) uxAddress;
Expand Down
1 change: 1 addition & 0 deletions src/FreeRTOS/portmacro_cmsis.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ __STATIC_INLINE uint32_t ulPortRaiseBASEPRI( void )

/*-----------------------------------------------------------*/

size_t xPortGetHeapSize(void);

#ifdef __cplusplus
}
Expand Down
1 change: 0 additions & 1 deletion src/FreeRTOSConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
#define configTICK_RATE_HZ 1024
#define configMAX_PRIORITIES (3)
#define configMINIMAL_STACK_SIZE (120)
#define configTOTAL_HEAP_SIZE (1024 * 40)
#define configMAX_TASK_NAME_LEN (4)
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
Expand Down
3 changes: 2 additions & 1 deletion src/displayapp/screens/SystemInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen3() {
"#808080 SPI Flash# %02x-%02x-%02x\n"
"\n"
"#808080 Memory heap#\n"
" #808080 Free# %d\n"
" #808080 Free# %d/%d\n"
" #808080 Min free# %d\n"
" #808080 Alloc err# %d\n"
" #808080 Ovrfl err# %d\n",
Expand All @@ -209,6 +209,7 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen3() {
spiFlashId.type,
spiFlashId.density,
xPortGetFreeHeapSize(),
xPortGetHeapSize(),
xPortGetMinimumEverFreeHeapSize(),
mallocFailedCount,
stackOverflowCount);
Expand Down
234 changes: 234 additions & 0 deletions src/libs/lfs_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
#pragma once

#include <libraries/log/nrf_log.h>

#define LFS_TRACE(fmt, ...) NRF_LOG_DEBUG("[LFS] %s:%d:trace: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define LFS_DEBUG(fmt, ...) NRF_LOG_DEBUG("[LFS] %s:%d:debug: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define LFS_WARN(fmt, ...) NRF_LOG_WARNING("[LFS] %s:%d:warn: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define LFS_ERROR(fmt, ...) NRF_LOG_ERROR("[LFS] %s:%d:error: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
FintasticMan marked this conversation as resolved.
Show resolved Hide resolved

// This is required in order for the CRC implementation in littlefs/lfs_util.c to be compiled
#undef LFS_CONFIG

// ====== Everything below this line is copied from lfs_util.h ======
FintasticMan marked this conversation as resolved.
Show resolved Hide resolved

// System includes
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <inttypes.h>

#ifndef LFS_NO_MALLOC
#include <stdlib.h>
#endif
#ifndef LFS_NO_ASSERT
#include <assert.h>
#endif
#if !defined(LFS_NO_DEBUG) || \
!defined(LFS_NO_WARN) || \
!defined(LFS_NO_ERROR) || \
defined(LFS_YES_TRACE)
#include <stdio.h>
#endif

#ifdef __cplusplus
extern "C"
{
#endif


// Macros, may be replaced by system specific wrappers. Arguments to these
// macros must not have side-effects as the macros can be removed for a smaller
// code footprint

// Logging functions
#ifndef LFS_TRACE
#ifdef LFS_YES_TRACE
#define LFS_TRACE_(fmt, ...) \
printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
#else
#define LFS_TRACE(...)
#endif
#endif

#ifndef LFS_DEBUG
#ifndef LFS_NO_DEBUG
#define LFS_DEBUG_(fmt, ...) \
printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "")
#else
#define LFS_DEBUG(...)
#endif
#endif

#ifndef LFS_WARN
#ifndef LFS_NO_WARN
#define LFS_WARN_(fmt, ...) \
printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "")
#else
#define LFS_WARN(...)
#endif
#endif

#ifndef LFS_ERROR
#ifndef LFS_NO_ERROR
#define LFS_ERROR_(fmt, ...) \
printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "")
#else
#define LFS_ERROR(...)
#endif
#endif

// Runtime assertions
#ifndef LFS_ASSERT
#ifndef LFS_NO_ASSERT
#define LFS_ASSERT(test) assert(test)
#else
#define LFS_ASSERT(test)
#endif
#endif


// Builtin functions, these may be replaced by more efficient
// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
// expensive basic C implementation for debugging purposes

// Min/max functions for unsigned 32-bit numbers
static inline uint32_t lfs_max(uint32_t a, uint32_t b) {
return (a > b) ? a : b;
}

static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
return (a < b) ? a : b;
}

// Align to nearest multiple of a size
static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) {
return a - (a % alignment);
}

static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) {
return lfs_aligndown(a + alignment-1, alignment);
}

// Find the smallest power of 2 greater than or equal to a
static inline uint32_t lfs_npw2(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
return 32 - __builtin_clz(a-1);
#else
uint32_t r = 0;
uint32_t s;
a -= 1;
s = (a > 0xffff) << 4; a >>= s; r |= s;
s = (a > 0xff ) << 3; a >>= s; r |= s;
s = (a > 0xf ) << 2; a >>= s; r |= s;
s = (a > 0x3 ) << 1; a >>= s; r |= s;
return (r | (a >> 1)) + 1;
#endif
}

// Count the number of trailing binary zeros in a
// lfs_ctz(0) may be undefined
static inline uint32_t lfs_ctz(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__)
return __builtin_ctz(a);
#else
return lfs_npw2((a & -a) + 1) - 1;
#endif
}

// Count the number of binary ones in a
static inline uint32_t lfs_popc(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
return __builtin_popcount(a);
#else
a = a - ((a >> 1) & 0x55555555);
a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
#endif
}

// Find the sequence comparison of a and b, this is the distance
// between a and b ignoring overflow
static inline int lfs_scmp(uint32_t a, uint32_t b) {
return (int)(unsigned)(a - b);
}

// Convert between 32-bit little-endian and native order
static inline uint32_t lfs_fromle32(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
return a;
#elif !defined(LFS_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \
(defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
return __builtin_bswap32(a);
#else
return (((uint8_t*)&a)[0] << 0) |
(((uint8_t*)&a)[1] << 8) |
(((uint8_t*)&a)[2] << 16) |
(((uint8_t*)&a)[3] << 24);
#endif
}

static inline uint32_t lfs_tole32(uint32_t a) {
return lfs_fromle32(a);
}

// Convert between 32-bit big-endian and native order
static inline uint32_t lfs_frombe32(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
return __builtin_bswap32(a);
#elif !defined(LFS_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \
(defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
return a;
#else
return (((uint8_t*)&a)[0] << 24) |
(((uint8_t*)&a)[1] << 16) |
(((uint8_t*)&a)[2] << 8) |
(((uint8_t*)&a)[3] << 0);
#endif
}

static inline uint32_t lfs_tobe32(uint32_t a) {
return lfs_frombe32(a);
}

// Calculate CRC-32 with polynomial = 0x04c11db7
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size);

// Allocate memory, only used if buffers are not provided to littlefs
// Note, memory must be 64-bit aligned
static inline void *lfs_malloc(size_t size) {
#ifndef LFS_NO_MALLOC
return malloc(size);
#else
(void)size;
return NULL;
#endif
}

// Deallocate memory, only used if buffers are not provided to littlefs
static inline void lfs_free(void *p) {
#ifndef LFS_NO_MALLOC
free(p);
#else
(void)p;
#endif
}


#ifdef __cplusplus
} /* extern "C" */
#endif
36 changes: 30 additions & 6 deletions src/stdlib.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <stdlib.h>
#include <string.h>
#include <FreeRTOS.h>

// Override malloc() and free() to use the memory manager from FreeRTOS.
Expand All @@ -10,18 +11,41 @@ void* malloc(size_t size) {
return pvPortMalloc(size);
}

void* __wrap_malloc(size_t size) {
return malloc(size);
}

void* __wrap__malloc_r(struct _reent* reent, size_t size) {
(void) reent;
return malloc(size);
}

void free(void* ptr) {
vPortFree(ptr);
}

void __wrap_free(void* ptr) {
free(ptr);
}

void* calloc(size_t num, size_t size) {
(void)(num);
(void)(size);
// Not supported
return NULL;
void *ptr = malloc(num * size);
if (ptr) {
memset(ptr, 0, num * size);
}
return ptr;
}

void *pvPortRealloc(void *ptr, size_t xWantedSize);
void* realloc( void *ptr, size_t newSize) {
void* __wrap_calloc(size_t num, size_t size) {
return calloc(num, size);
}

void* pvPortRealloc(void* ptr, size_t xWantedSize);

void* realloc(void* ptr, size_t newSize) {
return pvPortRealloc(ptr, newSize);
}

void* __wrap_realloc(void* ptr, size_t newSize) {
return realloc(ptr, newSize);
}
Loading