This release contains a widespread set of updates and optimisations to the micro:bit runtime, with a view to reducing the SRAM footprint of the whole system. This is to provide as much usable HEAP storage for application programs as possible. Specific updates and optimisations include: - Additional compilation flags to allow the core micro:bit runtime to be configured. These are defined in MicroBitConfig.h - A custom heap allocator. This is now included for two reasons: 1) To provide a simple mechanism to to utilise both the mbed heap space and other memory regions (such as unused memory in the SoftDevice region) as a single virtual heap. 2) To address some issues that have been noted that are attributable to heap fragmentation. The micro:bit heap allocator has a simple algorithm, but one that is chosen to respond well to the relativelt high 'heap churn' found in the micro:bit environment. All micro:bit components and user programs now use this heap allocator trasparently. - Updates to BLE services to remove persistent references to their GATT services. This consumes vast amounts SRAM, rather unecessarily. Instead only handles to the relevant GATT characteristics are now stored. This specifically includes: + MicroBitDFUService + MicroBitEventService + DeviceInformationService - Updates to the Fiber scheduler to save SRAM. More specifically: + Removed the need to hold an empty processor context to intialise fibers. + The IDLE fiber now runs without a stack + fiber stacks are now only created when a fiber is descheduled for the first time, thereby reducing heap churn. + the 'main' fiber is now recycled into the fiber_pool if it leaves app_main() + fibers created through invoke() now only maintains the necessary part of teh parent stack that is needed, thereby reducing the stack size of spawned fibers. - Updates to the Message Bus to reduce the overall memory footprint of processing events. More specifically: + Event handlers are now always called using invoke(), such that non-blocking event handlers no longer need a dedicated fiber to execute - thereby saving SRAM and processor time. + Processing of events from the event queue is now rate paced. Events only continue to be processed as long as there are no fibers on the run queue. i.e. event processing is no longer greedy, thereby reducing the number of fibers created on the runqueue. - Updates to BLUEZOENE code to bring up core BLE services even if they are not enabled by default. This allows programs that do not require BLE to operate to benefit from the full range of SRAM, whilst still allowing the device to be programmed over BLE. - Updates to the Soft Device initialisation configuration, reducing the size of the GATT table held in the top 1.8K of its 8K memory region to around 800 bytes. This is sufficient to run the default set of BLE services on the micro:bit so the additional memory is configured as HEAP storage by MicroBitHeapAllocator. - Minor changes to a range of components to integrate with the above changes. + rename of free() to release() in DynamicPWM to avoid namespace collision with MicroBitHeap free() + rename of fork_on_block to invoke() to enhance readbility. - Many code cleanups and updates to out of date comments.master
parent
42f43b2255
commit
857a626ed0
@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Compile time configuration options for the micro:bit runtime.
|
||||
*/
|
||||
|
||||
#ifndef MICROBIT_CONFIG_H
|
||||
#define MICROBIT_CONFIG_H
|
||||
|
||||
#include "mbed.h"
|
||||
|
||||
//
|
||||
// Memory configuration
|
||||
//
|
||||
|
||||
// Physical address of the top of SRAM.
|
||||
#define MICROBIT_SRAM_END 0x20004000
|
||||
|
||||
// Physical address of the top of the system stack (on mbed-classic this is the top of SRAM)
|
||||
#define CORTEX_M0_STACK_BASE MICROBIT_SRAM_END
|
||||
|
||||
// Amount of memory reserved for the stack at the end of memory (bytes).
|
||||
#define MICROBIT_STACK_SIZE 2000
|
||||
|
||||
// Physical address of the end of heap space.
|
||||
#define MICROBIT_HEAP_END (CORTEX_M0_STACK_BASE - MICROBIT_STACK_SIZE)
|
||||
|
||||
// Block size used by the allocator in bytes.
|
||||
// n.b. Currently only 32 bits (4 bytes) is supported.
|
||||
#define MICROBIT_HEAP_BLOCK_SIZE 4
|
||||
|
||||
// The proportion of SRAM available on the mbed heap to reserve for the micro:bit heap.
|
||||
#define MICROBIT_HEAP_SIZE 0.95
|
||||
|
||||
// if defined, reuse the 8K of SRAM reserved for SoftDevice (Nordic's memory resident BLE stack) as heap memory.
|
||||
// The amount of memory reused depends upon whether or not BLE is enabled using MICROBIT_BLE_ENABLED.
|
||||
#define MICROBIT_HEAP_REUSE_SD
|
||||
|
||||
// The lowest address of memory that is safe to use as heap storage when BLE is DISABLED
|
||||
// Used to define the base of the heap when MICROBIT_HEAP_REUSE_SD is defined.
|
||||
#define MICROBIT_HEAP_BASE_BLE_DISABLED 0x20000008
|
||||
|
||||
// The lowest address of memory that is safe to use as heap storage when BLE is ENABLED
|
||||
// This is permissable if SD is configured to release some of its internal storage that
|
||||
// is normally reserved for its BLE GATT table.
|
||||
#define MICROBIT_HEAP_BASE_BLE_ENABLED 0x20001C00
|
||||
|
||||
// The highest address of memory normally reserved for Soft Device that is safe to use as heap storage
|
||||
#define MICROBIT_HEAP_SD_LIMIT 0x20002000
|
||||
|
||||
//
|
||||
// Fiber scheduler configuration
|
||||
//
|
||||
|
||||
// Scheduling quantum (milliseconds)
|
||||
// Also used to drive the micro:bit runtime system ticker.
|
||||
#define FIBER_TICK_PERIOD_MS 6
|
||||
|
||||
|
||||
//
|
||||
// Core micro:bit services
|
||||
//
|
||||
|
||||
// To reduce memory cost and complexity, the micro:bit allows components to register for
|
||||
// periodic callback events during interrupt context, which occur every scheduling quantum (FIBER_TICK_PERIOD_MS)
|
||||
// This defines the maximum size of interrupt callback list.
|
||||
#define MICROBIT_SYSTEM_COMPONENTS 10
|
||||
|
||||
// To reduce memory cost and complexity, the micro:bit allows components to register for
|
||||
// periodic callback events when the processor is idle.
|
||||
// This defines the maximum size of the idle callback list.
|
||||
#define MICROBIT_IDLE_COMPONENTS 6
|
||||
|
||||
//
|
||||
// BLE options
|
||||
//
|
||||
// The BLE stack is very memory hungry. Each service can therefore be compiled in or out
|
||||
// by enabling/disabling the options below.
|
||||
//
|
||||
// n.b. The minimum set of services to enable over the air programming of the device will
|
||||
// still be brought up in 'BLUEZONE' mode regardless of the settings below.
|
||||
//
|
||||
|
||||
// Enable/Disable BLE during normal operation.
|
||||
#define MICROBIT_BLE_ENABLED
|
||||
|
||||
// Enable/Disable BLUEZONE mode at power up.
|
||||
#define MICROBIT_BLE_BLUEZONE
|
||||
|
||||
// Enable/Disable BLE Service: MicroBitDFU
|
||||
// This allows over the air programming during normal operation.
|
||||
#define MICROBIT_BLE_DFU_SERVICE
|
||||
|
||||
// Enable/Disable BLE Service: MicroBitEventService
|
||||
// This allows routing of events from the micro:bit message bus over BLE.
|
||||
#define MICROBIT_BLE_EVENT_SERVICE
|
||||
|
||||
// Enable/Disable BLE Service: MicroBitDeviceInformationService
|
||||
// This enables the standard BLE device information service.
|
||||
#define MICROBIT_BLE_DEVICE_INFORMATION_SERVICE
|
||||
|
||||
//
|
||||
// Panic options
|
||||
//
|
||||
|
||||
// Enable this to invoke a panic on out of memory conditions.
|
||||
#define MICROBIT_PANIC_HEAP_FULL
|
||||
|
||||
//
|
||||
// Debug options
|
||||
//
|
||||
|
||||
// Enable this to route debug messages through the USB serial interface.
|
||||
// n.b. This also disables the user serial port 'uBit.serial'.
|
||||
//#define MICROBIT_DBG
|
||||
|
||||
// Enable this to receive diagnostic messages from the heap allocator via the USB serial interface.
|
||||
// n.b. This requires MICROBIT_DBG to be defined.
|
||||
//#define MICROBIT_HEAP_DBG
|
||||
|
||||
#endif
|
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* A simple 32 bit block based memory allocator. This allows one or more memory segments to
|
||||
* be designated as heap storage, and is designed to run in a static memory area or inside the standard C
|
||||
* heap for use by the micro:bit runtime. This is required for several reasons:
|
||||
*
|
||||
* 1) It reduces memory fragmentation due to the high churn sometime placed on the heap
|
||||
* by ManagedTypes, fibers and user code. Underlying heap implentations are often have very simplistic
|
||||
* allocation pilicies and suffer from fragmentation in prolonged use - which can cause programs to
|
||||
* stop working after a period of time. The algorithm implemented here is simple, but highly tolerant to
|
||||
* large amounts of churn.
|
||||
*
|
||||
* 2) It allows us to reuse the 8K of SRAM set aside for SoftDevice as additional heap storage
|
||||
* when BLE is not in use.
|
||||
*
|
||||
* 3) It gives a simple example of how memory allocation works! :-)
|
||||
*
|
||||
* N.B. The need for this should be reviewed in the future, should a different memory allocator be
|
||||
* made availiable in the mbed platform.
|
||||
*
|
||||
* P.S. This is a very simple allocator, therefore not without its weaknesses. Why don't you consider
|
||||
* what these are, and consider the tradeoffs against simplicity...
|
||||
*
|
||||
* TODO: Consider caching recently freed blocks to improve allocation time.
|
||||
*/
|
||||
|
||||
#ifndef MICROBIT_HEAP_ALLOCTOR_H
|
||||
#define MICROBIT_HEAP_ALLOCTOR_H
|
||||
|
||||
#include "Microbit.h"
|
||||
#include <new>
|
||||
|
||||
// The number of heap segments created.
|
||||
#define MICROBIT_HEAP_COUNT 2
|
||||
|
||||
// Flag to indicate that a given block is FREE/USED
|
||||
#define MICROBIT_HEAP_BLOCK_FREE 0x80000000
|
||||
|
||||
int microbit_heap_init();
|
||||
void *microbit_malloc(size_t size);
|
||||
void microbit_free(void *mem);
|
||||
|
||||
/*
|
||||
* Wrapper function to ensure we have an explicit handle on the heap allocator provided
|
||||
* by our underlying platform.
|
||||
*
|
||||
* @param size The amount of memory to allocate.
|
||||
* @return A pointer to the memory allocated. NULL if no memory is available.
|
||||
*/
|
||||
inline void *native_malloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper function to ensure we have an explicit handle on the heap allocator provided
|
||||
* by our underlying platform.
|
||||
*
|
||||
* @param p Pointer to the memory to be freed.
|
||||
*/
|
||||
inline void native_free(void *p)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the 'new' operator globally, and redirects calls to the micro:bit theap allocator.
|
||||
*/
|
||||
inline void* operator new(size_t size) throw(std::bad_alloc)
|
||||
{
|
||||
return microbit_malloc(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the 'delete' operator globally, and redirects calls to the micro:bit theap allocator.
|
||||
*/
|
||||
inline void operator delete(void *ptr) throw()
|
||||
{
|
||||
microbit_free(ptr);
|
||||
}
|
||||
|
||||
// Macros to override overrides the 'malloc' and 'delete' functions globally, and redirects calls
|
||||
// to the micro:bit theap allocator.
|
||||
#define malloc(X) microbit_malloc( X )
|
||||
#define free(X) microbit_free( X )
|
||||
|
||||
#endif
|
@ -1,39 +0,0 @@
|
||||
#ifndef MICROBIT_MALLOC_H
|
||||
#define MICROBIT_MALLOC_H
|
||||
|
||||
#include "MicroBit.h"
|
||||
#include <new>
|
||||
|
||||
/**
|
||||
\brief Overrides malloc globally, and fires the panic function if we run out of memory!
|
||||
*/
|
||||
inline void* ubit_malloc(size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = malloc(size);
|
||||
|
||||
if(ptr == NULL)
|
||||
panic(MICROBIT_OOM);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Overrides malloc globally, and fires the panic function if we run out of memory!
|
||||
*/
|
||||
inline void* operator new(size_t size) throw(std::bad_alloc)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = malloc(size);
|
||||
|
||||
if(ptr == NULL)
|
||||
panic(MICROBIT_OOM);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#define malloc(X) ubit_malloc( X ) //macro! Override malloc! Hehehe
|
||||
|
||||
#endif
|
@ -0,0 +1,17 @@
|
||||
#ifndef MICROBIT_PANIC_H
|
||||
#define MICROBIT_PANIC_H
|
||||
|
||||
/**
|
||||
* Displays "=(" and an accompanying status code.
|
||||
* @param statusCode the appropriate status code - 0 means no code will be displayed. Status codes must be in the range 0-255.
|
||||
*/
|
||||
void panic(int statusCode);
|
||||
|
||||
/**
|
||||
* Resets the micro:bit.
|
||||
* @param statusCode the appropriate status code. Status codes must be in the range 0-255.
|
||||
*/
|
||||
void reset(int statusCode);
|
||||
|
||||
#endif
|
||||
|