本帖最后由 kai迪皮 于 2023-2-13 14:16 编辑
#申请原创# @21小跑堂
前言
最近在玩APM32F407IG的板子,发现官方提供了两个RTOS的demo,FreeRTOS和RT-thread。想着APM32F4这么丰富的资源,是不是也可以跑一下Azure RTOS看看。APM32F4移植Azure RTOS的过程可以看着这篇帖子https://bbs.21ic.com/icview-3271244-1-1.html。我最近学习Azure RTOS的动态内存管理,在查阅网上资料学习后成功移植了,本篇文章就记录一下整个过程,供各位做个参考,权当抛砖引玉了。
1 Azure RTOS简介
Azure RTOS ThreadX(这里是它的官方网站:https://learn.microsoft.com/zh-cn/azure/rtos/threadx/overview-threadx)。它是专门为深度嵌入式实时 IoT 应用程序设计的。 Azure RTOS ThreadX 提供高级计划、通信、同步、计时器、内存管理和中断管理功能。 此外,Azure RTOS ThreadX 具有许多高级功能,包括 picokernel™ 体系结构、preemption-threshold™ 计划、event-chaining™、执行分析、性能指标和系统事件跟踪。 Azure RTOS ThreadX 非常易于使用,适用于要求极其苛刻的嵌入式应用程序。 Azure RTOS ThreadX 在各种产品(包括消费者设备、医疗电子设备和工业控制设备)上的部署次数已达数十亿次。(节选自其官网)
为什么说它厉害呢?以上内容也仅是它的应用介绍,这个RTOS的真正厉害之处在于其通过了各项安全认证。以下便是其通过的安全认证:
1. 医疗 - FDA510(k),IEC-62304 Class C,IEC-60601,ISO-14971
2. 工业 - UL-1998,IEC-61508 SIL 4
3. 运输/铁路 - EN50128 SIL 4,BS50128, 49CFR236,IEC-61508
4. 航空航天设备 - DO-178B,ED-12B,DO-278
5. 汽车 - IEC-61508 ASIL D
6. 核应用 - IEC-61508
7. 家电 - UL/IEC 60730/60335
其实它之前是收费闭源的,自被微软收购后就开源出来,而且我们出于学习评估的目的,是不会被限制的。这个RTOS的更厉害之处,大家可以查阅他们的官网,这里就不赘述了。
2 源码获取
移植前我们需要准备一些源码
1. APM32F407的工程模板,这个可以在他们官网获取:
2. ThreadX源码,这个可以在他们的开源仓库获取:https://github.com/azure-rtos/threadx
需要注意的是,由于我们本次环境使用的是MDK环境,我们需要使用5.30以上的MDK。具体移植的过程我们这里省略,大家也可以直接拿到后文的标准模板后自行跟着下面的步骤一步步进行验证。
3 动态内存
在我们正式的使用动态内存前,我这里先简单介绍一下什么是内存。
内存,我们顾名思义,在MCU中便是用于我们代码程序运行时所使用到(注意:是“用于程序运行”有别于“用于存储程序”的)的存储空间。一般该空间便是我们经常所说的RAM,那我们一直都说“动态内存”,那同样的便也有“静态内存”。
大家可能对“静态内存”一头雾水,但不着急我相信大家都是经常使用到的这个东西。比如说下面这行代码:
这个代码我们便是经常定义的一个16字节的buffer。这个buffer是占了空间的,这个空间由我们程序编译时的编译器去进行分配。其在程序的运行过程中buffer的大小及位置是不能进行更改的,这便是“静态”。
根据上面的描述,与之对应的“动态内存”相关的特性我们就可以触类旁通,程序运行过程中的buffer的大小及位置能进行更改的,这便是“动态”。
在C语言中,我们一般会使用 malloc()和 free()动态的分配内存和释放内存。但是我们的MCU是没有MMU(Memory Management Unit)即内存管理单元的,无法实现对内存进行动态映射(这里的知识点较多,大家可以自行百度一下)。一般有以下两个问题:
1. 由于分配算法的复杂度和堆空间的使用情况,分配的时间无法确定;
2. 在大量的申请、释放的过程中,容易因为内存对齐问题而产生碎片化内存;
换句简单的话来说,在MCU上“使用malloc()和 free()来实现动态的分配内存和释放内存”这个做法是存在一定风险的,并不建议日常使用。因为这个缺陷,MCU在使用动态内存分配时的一般解决方法便是自己实现内存管理。
但是,我们使用到的Azure RTOS便有相应的动态内存管理(有现成的内存管理,会用就好),我们便不必自己实现内存管理咯。
4 Azure RTOS的动态内存管理
Azure RTOS的内存管理的相关函数有如下几个://分配固定大小的内存块
UINT tx_block_allocate(
TX_BLOCK_POOL *pool_ptr,
VOID **block_ptr,
ULONG wait_option);
//创建固定大小内存块的池
UINT tx_block_pool_create(
TX_BLOCK_POOL pool_ptr,
CHAR name_ptr,
ULONG block_size,
VOID pool_start,
ULONG pool_size);
//删除内存块池
UINT tx_block_pool_delete(TX_BLOCK_POOL *pool_ptr);
//检索有关块池的信息
UINT tx_block_pool_info_get(
TX_BLOCK_POOL *pool_ptr,
CHAR **name,
ULONG *available,
ULONG *total_blocks,
TX_THREAD **first_suspended,
ULONG *suspended_count,
TX_BLOCK_POOL **next_pool);
//获取块池性能信息
UINT tx_block_pool_performance_info_get(
TX_BLOCK_POOL *pool_ptr,
ULONG *allocates,
ULONG *releases,
ULONG *suspensions,
ULONG *timeouts));
//获取块池系统性能信息
UINT tx_block_pool_performance_system_info_get(
ULONG *allocates,
ULONG *releases,
ULONG *suspensions,
ULONG *timeouts);
//设置块池挂起列表的优先级
UINT tx_block_pool_prioritize(TX_BLOCK_POOL *pool_ptr);
//释放固定大小的内存块
UINT tx_block_release(VOID *block_ptr);
涉及了动态内存必备的申请、释放,以及相关内存的信息获取,这部分的信息我们均可从Azure RTOS的手册中看到:[第 4 章 - Azure RTOS ThreadX 服务的说明 | Microsoft Learn](https://learn.microsoft.com/zh-cn/azure/rtos/threadx/chapter4)
5 APM32F4的Azure RTOS 动态内存示例
我们将上次所制作的Examples/ThreadX_Template复制一份出来并改名为ThreadX_Memory_Management,将工程名字也改好。我们将在上次已经做好的示例代码中完成动态内存操作的示例了。
我们将在两个线程内分别完成内存块(Block)的申请与释放操作;内存池(Pool)的申请、释放与信息获取操作。
1. 首先我们需要对内存块及内存池区域进行创建,使用tx_block_pool_create函数:
第一步我们先定义一下内存块及内存池的基本信息: TX_BLOCK_POOL tx1_block;
TX_BYTE_POOL tx2_pool;
uint32_t tx1_block_buffer[1024];
uint32_t tx2_pool_buffer[1024];
然后线程1完成内存块区域创建: /* Create a memory block for a fixed size memory unit request */
tx_block_pool_create(&tx1_block,
"tx1_block",
4, /* Memory unit size */
(VOID *)tx1_block_buffer, /* The address of a memory block that needs to be 4-byte aligned */
sizeof(tx1_block_buffer)); /* The size of the memory block is in bytes */
接着在线程2完成内存池区域创建: /* Creating a memory pool */
tx_byte_pool_create(&tx2_pool,
"tx2_pool",
(VOID *)tx2_pool_buffer, /* Memory pool address, which needs to be 4-byte aligned */
sizeof(tx2_pool_buffer)); /* The size of the memory pool is in bytes */
2. 第二步,线程1内完成内存块的申请与释放,并打印信息。 /* Apply for memory blocks of 4 bytes each time */
status = tx_block_allocate(&tx1_block,
(VOID **)&tx1_block_ptr,
TX_NO_WAIT);
if (status == TX_SUCCESS)
{
printf("The tx1_block memory block request was successful \r\n");
}
status = tx_block_release(tx1_block_ptr);
if (status == TX_SUCCESS)
{
printf("The tx1_block memory block was released successfully \r\n");
}
3. 最后在线程2内完成内存池的申请、释放及信息查看,并打印相关信息。 status = tx_byte_allocate(&tx2_pool,
(VOID **)&tx2_pool_ptr,
77,
TX_NO_WAIT);
if (status == TX_SUCCESS)
{
printf("The tx2_pool memory pool application was successful \r\n");
tx_byte_pool_info_get(&tx2_pool,
TX_NULL,
&available,
TX_NULL,
TX_NULL,
TX_NULL,
TX_NULL);
printf(" Residual memory pool size : %d bytes \r\n", (int)available);
}
status = tx_byte_release(tx2_pool_ptr);
if (status == TX_SUCCESS)
{
printf("The txx2_pool memory pool was released successfully \r\n");
tx_byte_pool_info_get(&tx2_pool,
TX_NULL,
&available,
TX_NULL,
TX_NULL,
TX_NULL,
TX_NULL);
printf(" Residual memory pool size : %d bytes \r\n", (int)available);
}
6 编译与下载
最后我们编译工程,编译结果如下。
然后我们下载程序进板子后,LED2和LED3闪烁,若连接串口可以查看到如下信息:
本次APM32F4基于Azure RTOS动态内存管理的应用过程便到此结束,具体代码请参考:
APM32F4xx_SDK_ThreadX_v0.2.zip
(3.59 MB)
。
|
实用的动态内存管理方案,提高内存的灵活性,整体的操作流程较为完善,实现的效果较好。