This page shows how to add the MtFmt
library to your project.
A simple way to download source files is that click here. It will download the zip file from the main branch of the GitHub repository. The other way is to install git and run the following command in your terminal, which is suitable for the professional developer.
git clone --depth=1 git@github.com:MtFmT-Lib/mtfmt.git
# or: https://github.com/MtFmT-Lib/mtfmt.git if you have not ssh key
You can add it to the git submodule also.
git submodule add git@github.com:MtFmT-Lib/mtfmt.git
The two folders should be included in the archive file. The src
folder including C source files is all implementations. And, the inc
folder includes C header files and C++ wrapper header files. A reasonable approach is to create a new folder to contain the inc
and the src
directories and copy that into your project directory.
Using the middleware package is an easy way to add to the Keil IDE. You can find them here. Alternatively, you can manually add the sources and configure the including path.
The middleware package was auto-generated by GitHub action. Found that and make sure the branch is master
. In your IDE, open the package installer.
Then import the download files manually. The package file has the .pack
extension name.
After that, we can find the mtfmt
package in the package list.
Now open your project and click the "Manage Run-time Environment" button.
And found the mtfmt
package in the Utility
item. Click the check box and you add the library succeeded. Go to the next section to see how to customize the library.
Firstly, download the library sources and select the "Add existing file to Source Group" option like in Figure 2.6.
Then, add all files in the folder src
into your project.
Now you add all source files succeeded. The next step is that add the including directory. The preprocessor must know where the file locates in that the preprocessor of the C compiler will copy the header into the source file simply. To add that to the project, click the "Options for Target" button in the toolbar.
Then find the "C/C++" tab and click the "..." button on the right side of the edit box.
And select the inc
folder in the dialog.
Finally, we must set the C99 standard.
Now you completed this section! Click the "Build" button or press the F7
key to build your project and check the output has not any errors. Then, you can go to the next section!
The archive includes the CMake file. Using the git submodule is a good choice if you use that version control system. Section 1 shows how to add the library by git submodule. Otherwise, copy the file to a suitable directory first.
Then, append the following to your CMakeLists.txt
. That adds the library directory to the build. See more details in the CMake document
# assume that you copy all files into "./mtfmt"
add_subdirectory(mtfmt)
Finally, add the including path manually because the add_subdirectory
command only appends a subdirectory to the build.
target_include_directories(your_target PRIVATE "./mtfmt/inc")
Now you completed this section. Go to the next section!
TODO
The microcontroller has a different instruction set such as ARM v6m or ARM v7m. The instruction set includes different data processing instructions and architecture memory models. And for the microprocessor unit, or MPU that runs an operating system usually. The MtFmt
library provides a series of macros for conditional compilation, that makes it possible to control the final generated instructions, control memory allocators, and so on.
The following table 3.1 shows all available macros.
Macros | Default | Description |
---|---|---|
_MSTR_USE_HARDWARE_DIV |
0 | Enable to use hardware divider operator. |
_MSTR_USE_MALLOC |
0 | Enable to use malloc instead build-in heap manager. |
_MSTR_RUNTIME_HEAP_ALIGN |
4 | Specify the alignment of build-in heap manager. |
_MSTR_USE_STD_IO |
0 | Enable to use stdout support. |
_MSTR_USE_UTF_8 |
1 | Enable the UTF-8 support. |
Define the macro equal to 1
to enable it. Otherwise, the value is not equal to 1
or the macro is undefined means disabling it.
Notes: UTF-8 Encoding
In the C and the C++ programming language, the UTF-8 literal string includes the prefix
u8
such asu8"UTF-8"
. The minimum support version is C11 and C++11. The literal string such as"中文"
or"😊"
is not a UTF-8 encoding string. Normally, the string encoding will follow your system. For example, the Chinese string will be compiled into GB-2312 encoding and it will cause anMStr_Err_UnicodeEncodingError
when you enable UTF-8 support.
TODO
Data synchronization is very important in the multi-threading or multi-task system. The built-in memory manager has no data synchronization. That means you cannot use that in those situations. Instead using the OS API to replace the built-in memory manager. It is recommended to follow the following guidelines.
The C standard library provides the heap manager function. Enable the macro _MSTR_USE_MALLOC
to use the malloc
and the free
function instead built-in heap manager. Go to the next section!
Many RTOS like FreeRTOS or µC/OS provides a thread-safe or task-safe memory manager. To replace the build-in heap manager with that, enable the macro _MSTR_USE_MALLOC
first and find ./inc/mm_cfg.h
. The _MSTR_MEM_ALLOC_FUNCTION
macro specifies the allocating memory function and holds the same type $\text{size_t}\rightarrow\text{void}$ of malloc
in the C standard library. Likewise, the _MSTR_MEM_FREE_FUNCTION
macro specifies the releasing memory function and holds the same type $\text{void}\rightarrow\text{void}$ of free
. By default, those macros will be defined as follows.
#define _MSTR_MEM_ALLOC_FUNCTION(s) malloc(s)
#define _MSTR_MEM_FREE_FUNCTION(s) free(s)
Adding those macros to the file ./inc/mm_cfg.h
will replace the default implementation.
#if !defined(_INCLUDE_MM_CFG_H_)
#define _INCLUDE_MM_CFG_H_
#include <stdint.h>
// add the macro definitions to here or #include "your_configure.h"
...
#endif // _INCLUDE_MM_CFG_H_
The FreeRTOS provides five different memory manager tactics which can be found here. The pvPortMalloc
function is the instead version of malloc
and the vPortFree
function is the instead version of free
. They have the same signature as the standard library function. So we can replace the function symbol directly as follows.
// #include "freertos.h"
#define _MSTR_MEM_ALLOC_FUNCTION(s) pvPortMalloc(s)
#define _MSTR_MEM_FREE_FUNCTION(s) vPortFree(s)
You can go to section 5 to view the demo.
The μC/OS provides API which can be found here is not the same as the standard library function and is a block allocator. That means we must write two helper functions in a standard C source file and then add them into mm_cfg.h
.
The function requires a parameter pmem
to specify the list of free memory control blocks. A simple way is that export your free memory control block variable to the global namespace. And then create that with a block size of 64 bytes at least. Finally, create a C source file, the source code may seem like the following.
// #include "ucos.h"
// #include "mm_cfg.h"
// your global memory block
extern OS_MEM* mtfmt_mem;
// create that:
// OS_MEM *mtfmt_mem;
// INT8U mtfmt_mem_block[8][64];
// INT8U err;
// mtfmt_mem = OSMemCreate(mtfmt_mem_block, 8, 64, &err);
void* wrap_ucos_mget(size_t sz) {
(void)sz;
uint8_t err = OS_NO_ERR;
void* pblock = OSMemGet(mtfmt_mem, &err);
if (err != OS_NO_ERR) {
return NULL;
} else {
return pblock;
}
}
void wrap_ucos_mfree(void* pblock) {
(void)OSMemPut(mtfmt_mem, pblock);
}
Normally, the memory usage is very small for the value formatting. The except situation is string formatting, for the $L$ bytes string formatting the library will use $2L$ bytes memory. Finally, append those macros and two function prototypes into mm_cfg.h
.
extern void* wrap_ucos_mget(size_t sz);
extern void wrap_ucos_mfree(void* pblock);
#define _MSTR_MEM_ALLOC_FUNCTION(s) wrap_ucos_mget(s)
#define _MSTR_MEM_FREE_FUNCTION(s) wrap_ucos_mfree(s)
You can go to section 5 now.
The RT-Thread provides API is the same signature as the standard library which can be found here. So we can replace the function symbol directly as follows.
// #include "rtthread.h"
#define _MSTR_MEM_ALLOC_FUNCTION(s) rt_malloc(s)
#define _MSTR_MEM_FREE_FUNCTION(s) rt_free(s)
You can go to section 5 to view the demo.
For the other operating system, make sure functions have the same signature as the malloc
and free functions. If the signature is different, you should implement a wrapper function like section 4.2.2. Finally, append those macros as follows.
#define _MSTR_MEM_ALLOC_FUNCTION(s) your_mem_alloc(s)
#define _MSTR_MEM_FREE_FUNCTION(s) your_mem_free(s)
TODO