4.2.chuong4 - FreeRTOS - QUAN LY BO NHO - 2
4.2.chuong4 - FreeRTOS - QUAN LY BO NHO - 2
4.2.chuong4 - FreeRTOS - QUAN LY BO NHO - 2
2:
Quản lý tài nguyên và bộ nhớ
với FreeRTOS
2
Resource & Memory Management
Memory blocks are essential parts of modern embedded systems, especially microcontroller-based
ones.
Memory blocks are semiconductor devices that store and retrieve information or data; a
microcontroller central processing unit (CPU) uses and processes data stored in memory blocks to perform
specific tasks.
As shown in the image below, memory blocks in microcontrollers are usually described as arrays.
Memory arrays are divided into cells that can store data and be accessed using a unique identifier
representing its address or position relative to the memory array. Information in memory cells is stored
using binary digits (bits), usually organized in bytes (8-bits); it can also be retrieved later by the MCU or
other components of a microcontroller-based system.
Memory in computing systems can be volatile or non-volatile.
Volatile memory is a temporary memory, this means that data is stored while the system is running, but it
is lost forever when the system is turned off.
Non-volatile memory is permanent memory; data is not lost even if the system is turned off.
6
Memory Architecture
Arduino® boards are mainly based on two families of microcontrollers: AVR® and ARM®.
AVR® family microcontrollers are based on the Harvard architecture model
ARM® family microcontrollers can be based on either von Neuman or Harvard architectures models.
The following table summarizes Arduino boards microcontrollers architectures:
11
Arduino® Boards Architectures
Arduino® boards are mainly based on two families of microcontrollers: AVR® and ARM®.
AVR® family microcontrollers are based on the Harvard architecture model
ARM® family microcontrollers can be based on either von Neuman or Harvard architectures models.
The following table summarizes Arduino boards microcontrollers architectures:
12
Arduino® Boards Architectures
Arduino® boards are mainly based on two families of microcontrollers: AVR® and ARM®.
AVR® family microcontrollers are based on the Harvard architecture model
ARM® family microcontrollers can be based on either von Neuman or Harvard architectures models.
The following table summarizes Arduino boards microcontrollers architectures:
13
Memory Types
All the different memory units inside a microcontroller can be divided into two main
types: RAM and ROM.
RAM (from Random-Access Memory) in microcontroller-based systems is a volatile memory used to
store temporary data such as the system's firmware variables.
ROM (from Read-Only Memory) in microcontroller-based systems is non-volatile memory used to
store permanent data such as the system's firmware.
RAM and ROM in microcontroller-based systems are organized into three main categories:
Flash
RAM
EEPROM
14
Memory Types
Flash
Flash memory in microcontroller-based systems is part of its ROM. The flash memory is where the
system's firmware is stored to be executed. For example, think of the famous Blink.ino sketch: when
we compile this sketch, we create a binary file that is later stored in the flash memory of an Arduino
board. The sketch is then executed when the board is powered on.
RAM in microcontroller-based systems is where the system's temporary data or run-time
data is stored;
for example, the variables created by functions of a program. RAM in microcontrollers usually
is SRAM; this is a type of RAM that uses a flip-flop to store one bit of data. There is also another type
of RAM that can be found in microcontrollers: DRAM.
EEPROM: In microcontroller-based systems, Erasable Programmable Read-Only Memory, or
EEPROM, is also part of its ROM; actually, Flash memory is a type of EEPROM.
The main difference between Flash memory and EEPROM is how they are managed; EEPROM can
be managed at the byte level (write or erased) while Flash can be managed at the block level.
15
Arduino® Boards Memory Allocation
RAM:
TCB
SCB
QCB
RAM space is used for Global data, arrays, static variables, …
22
Memory Allocation in FreeRTOS
2 options:
If you use dynamic creation method then they will be created in the heap memory of the RAM
If you create them statically then they will be created in other part of the RAM except heap and stack space
23
Memory Allocation in FreeRTOS
By default,
25
Memory Allocation in FreeRTOS
Resource Management:
Using Mutex
Using Couting Semaphore
The count value indicates number of available resources
To get a resource, a task must obtain (take) a semaphore
When a task finishes with the resource, it 'gives' the semaphore back
Tham khảo thêm:
https://www.youtube.com/watch?v=AsZcF3pVlvY&list=PLaN_SFaG
u-90sD41MHD_6YOw_4CYQm5yx&index=7
33
Resource & Memory Management
The RTOS kernel needs RAM each time a task, queue, mutex, software timer, semaphore or
event group is created.
The RAM can be automatically dynamically allocated from the RTOS heap within the RTOS
API object creation functions, or it can be provided by the application writer.
If RTOS objects are created dynamically then the standard C library malloc() and free()
functions can sometimes be used for the purpose, but:
they are not always available on embedded systems,
they take up valuable code space,
they are not thread safe, and
they are not deterministic (the amount of time taken to execute the function will differ from call to
call)…
So more often than not an alternative memory allocation implementation is required.
36
Heap Memory Management in FreeRTOS
One embedded/real time system can have very different RAM and timing requirements to
another => A single RAM allocation algorithm will only ever be appropriate for a subset of
applications.
To get around this problem, FreeRTOS keeps the memory allocation API in its portable layer.
The portable layer is outside of the source files that implement the core RTOS functionality, allowing
an application specific implementation appropriate for the real time system being developed to be
provided.
When the RTOS kernel requires RAM, instead of calling malloc(), it instead calls pvPortMalloc().
When RAM is being freed, instead of calling free(), the RTOS kernel calls vPortFree().
37
Heap Memory Management in FreeRTOS
FreeRTOS offers several heap management schemes that range in complexity and features.
It is also possible to provide your own heap implementation, and even to use two heap
implementations simultaneously.
Using two heap implementations simultaneously permits task stacks and other RTOS objects
to be placed in fast internal RAM, and application data to be placed in slower external RAM.
The FreeRTOS download includes five sample memory allocation implementations (Figure.)
Other implementations can be added as needed. Exactly one of these source files should be
included in a project at a time [the heap defined by these portable layer functions will be used
by the RTOS kernel even if the application that is using the RTOS opts to use its own heap
implementation].
38
Heap Memory Management in FreeRTOS
In FreeRTOS download:
40
Heap Memory Management in FreeRTOS
Heap1.c
41
Heap Memory Management in FreeRTOS
Heap1.c
Does not permit memory to be freed once it has been allocated. Despite this, heap_1.c is appropriate
for a large number of embedded applications.
This is because many small and deeply embedded applications create all the tasks, queues, semaphores, etc.
required when the system boots, and then use all of these objects for the lifetime of program (until the
application is switched off again, or is rebooted). Nothing ever gets deleted.
The xPortGetFreeHeapSize() API function returns the total amount of heap space that remains
unallocated, allowing the configTOTAL_HEAP_SIZE setting to be optimised.
The heap_1 implementation:
Can be used if your application never deletes a task, queue, semaphore, mutex, etc. (which actually covers the
majority of applications in which FreeRTOS gets used).
Is always deterministic (always takes the same amount of time to execute) and cannot result in memory
fragmentation.
Is very simple and allocated memory from a statically allocated array, meaning it is often suitable for use in
applications that do not permit true dynamic memory allocation.
42
Heap Memory Management in FreeRTOS
Heap2.c
43
Heap Memory Management in FreeRTOS
Heap2.c
heap_2 uses a best fit algorithm and, unlike scheme 1, allows previously allocated blocks to
be freed. It does not combine adjacent free blocks into a single large block.
See heap_4.c for an implementation that does coalescence free blocks.
The xPortGetFreeHeapSize() API function returns the total amount of heap space that
remains unallocated, (allowing the configTOTAL_HEAP_SIZE setting to be optimised), but
does not provided information on how the unallocated memory is fragmented into smaller
blocks.
The pvPortCalloc() function has the same signature as the standard library calloc function.
It allocates memory for an array of objects and initializes all bytes in the allocated storage to zero.
If allocation succeeds, it returns a pointer to the lowest byte in the allocated memory block. On
failure, it returns a null pointer.
44
Heap Memory Management in FreeRTOS
Heap2.c
This implementation:
Can be used even when the application repeatedly deletes tasks, queues, semaphores, mutexes, etc., with the caveat
below regarding memory fragmentation.
Should not be used if the memory being allocated and freed is of a random size. For example:
If an application dynamically creates and deletes tasks, and the size of the stack allocated to the tasks being created is
always the same, then heap2.c can be used in most cases. However, if the size of the stack allocated to the tasks being
created was not always the same, then the available free memory might become fragmented into many small blocks,
eventually resulting in allocation failures. (heap_4.c would be a better choise in this case)
If an application dynamically creates and deletes queues, and the queue storage area is the same in each case (the
queue storage area is the queue item size multiplied by the length of the queue), then heap_2.c can be used in most
cases. However, if the queue storage area were not the same in each case, then the available free memory might become
fragmented into many small blocks, eventually resulting in allocation failures. (heap_4.c would be a better choise in this
case).
The application called pvPortMalloc() and vPortFree() directly, rather than just indirectly through other FreeRTOS
API functions.
Could possible result in memory fragmentation problems if your application queues, tasks, semaphores, mutexes, etc.
in an unpredictable order. This would be unlikely for nearly all applications but should be kept in mind.
Is not deterministic - but is much more efficient that most standard C library malloc implementations.
45
Heap Memory Management in FreeRTOS
Heap3.c
This implements a simple wrapper for the standard C library malloc() and free() functions that
will, in most cases, be supplied with your chosen compiler.
The wrapper simply makes the malloc() and free() functions thread safe.
This implementation:
Requires the linker to setup a heap, and the compiler library to provide malloc() and free()
implementations.
Is not deterministic.
Will probably considerably increase the RTOS kernel code size.
Note that the configTOTAL_HEAP_SIZE setting in FreeRTOSConfig.h has no effect when
heap_3 is used.
46
Heap Memory Management in FreeRTOS
Heap4.c
47
Heap Memory Management in FreeRTOS
Heap4.c
This scheme uses a first fit algorithm and, unlike scheme 2, it does combine adjacent free
memory blocks into a single large block (it does include a coalescence algorithm).
The total amount of available heap space is set by configTOTAL_HEAP_SIZE - which is defined
in FreeRTOSConfig.h. The configAPPLICATION_ALLOCATED_HEAP FreeRTOSConfig.h
configuration constant is provided to allow the heap to be placed at a specific address in
memory.
The xPortGetFreeHeapSize() API function returns the total amount of heap space that remains
unallocated when the function is called, and the xPortGetMinimumEverFreeHeapSize() API
function returns lowest amount of free heap space that has existed system the FreeRTOS
application booted. Neither function provides information on how the unallocated memory is
fragmented into smaller blocks.
The vPortGetHeapStats() API function provides additional information
48
Heap Memory Management in FreeRTOS
Heap4.c
The pvPortCalloc() function has the same signature as the standard library calloc function.
This implementation:
Can be used even when the application repeatedly deletes tasks, queues, semaphores, mutexes, etc..
Is much less likely than the heap_2 implementation to result in a heap space that is badly fragmented
into multiple small blocks - even when the memory being allocated and freed is of random size.
Is not deterministic - but is much more efficient that most standard C library malloc implementations.
heap_4.c is particularly useful for applications that want to use the portable layer memory
allocation schemes directly in the application code (rather than just indirectly by calling API
functions that themselves call pvPortMalloc() and vPortFree())
49
Heap Memory Management in FreeRTOS
Heap5.c
This scheme uses the same first fit and memory coalescence algorithms as heap_4, and
allows the heap to span multiple non adjacent (non-contiguous) memory regions.
Heap_5 is initialised by calling vPortDefineHeapRegions(), and cannot be used until after
vPortDefineHeapRegions() has executed.
Creating an RTOS object (task, queue, semaphore, etc.) will implicitly call pvPortMalloc() so it
is essential that, when using heap_5, vPortDefineHeapRegions() is called before the creation
of any such object.
vPortDefineHeapRegions() takes a single parameter. The parameter is an array of HeapRegion_t
structures
50
Heap Memory Management in FreeRTOS
Heap5.c
The xPortGetFreeHeapSize() API function returns the total amount of heap space that
remains unallocated when the function is called,
The xPortGetMinimumEverFreeHeapSize() API function returns lowest amount of free heap
space that has existed system the FreeRTOS application booted.
Neither function provides information on how the unallocated memory is fragmented into
smaller blocks.
The pvPortCalloc() function has the same signature as the standard library calloc function.
The vPortGetHeapStats() API function provides additional information on the heap status.
51
Q&A
52
Câu hỏi ôn tập Chương 4