【经验】灵动微电子MM32F3270系列MCU基于Azure RTOS动态内存管理的应用设计指南

2023-07-15 灵动MM32MCU公众号
MCU,开发板,微控制器,MM32F3270 MCU,开发板,微控制器,MM32F3270 MCU,开发板,微控制器,MM32F3270 MCU,开发板,微控制器,MM32F3270

Azure RTOS ThreadX 是 Microsoft 提供的高级工业级实时操作系统 (RTOS)。它是专门为深度嵌入式实时 IoT 应用程序设计的。Azure RTOS ThreadX 提供高级计划、通信、同步、计时器、内存管理和中断管理功能。此外,Azure RTOS ThreadX 具有许多高级功能,包括 picokernel™ 体系结构、preemption-threshold™ 计划、event-chaining™、执行分析、性能指标和系统事件跟踪。Azure RTOS ThreadX 非常易于使用,适用于要求极其苛刻的嵌入式应用程序。Azure RTOS ThreadX 在各种产品(包括消费者设备、医疗电子设备和工业控制设备)上的部署次数已达数十亿次。

具体的介绍和用户指南可以参考:https://docs.microsoft.com/zh-cn/azure/rtos/threadx/ 


在前文描述移植基本内核的基础上,本文介绍MM32F3270系列MCU结合Azure RTOS ThreadX内存池的使用,引导用户理解Azure RTOS ThreadX动态内存管理功能。

表 1 适用系列型号

1、移植应用的准备

1.1   硬件开发板的准备

该移植过程中应用的开发板为MM32的EVB-F3270,板载MM32F3273G9P

EVB-F3270 (MM32F3273G9P) 的简要参数:

  • Arm Cortex-M3 内核

  • 板载 MM32F3273G9P(LQFP144)

  • USB Host / Device、SPI、I2C

  • 4 x Key、4 x LED

  • I2S Speaker

  • TF-Card

  • Ethernet PHY


1.2  软件的准备

  • 库函数和例程(Lib Samples)

该移植过程中应用的 Firmware 分别为 MM32F3270 库函数和例程,下载地址:

https://www.mindmotion.com.cn/products/mm32mcu/mm32f/mm32f_mainstream/mm32f3270/ 

  • Azure RTOS ThreadX(源码)

ThreadX 的源代码已经开放,我们可以从 ThreadX 公共源代码存储库获取 Azure RTOS ThreadX,网址为:

https://github.com/azure-rtos/threadx/ 


具体的商用使用条件参考Azure的许可证说明:

https://www.microsoft.com/en-us/legal/intellectualproperty/tech-licensing/programs?msclkid=f7ab4ff3afa011ec90a79366a52034fa&activetab=pivot1:primaryr11 


Microsoft publishes the Azure RTOS source code to GitHub. No license is required to install and use the software for internal development, testing, and evaluation purposes. A license is required to distribute or sell components and devices unless using Azure RTOS licensed hardware.


  • Azure RTOS 何时需要许可证?

Microsoft 将 Azure RTOS 源代码发布到 GitHub。安装和使用该软件进行内部开发、测试和评估无需许可证。分发或销售组件和设备需要许可证,除非使用 Azure RTOS 许可的硬件。

  • ThreadX 安装

可以通过将 GitHub 存储库克隆到本地计算机来安装 ThreadX。下面是用于在 PC 上创建 ThreadX 存储库的克隆的典型语法。

  • shell复制

git clone https://github.com/azure-rtos/threadx

或者,也可以使用 GitHub 主页上的“下载”按钮来下载存储库的副本。

下载后的仓库代码目录列表如下:

  • Azure RTOS ThreadX(源码)支持的开发环境

ThreadX 内核提供好了各种主流硬件平台和软件平台的移植文件,以Cortex_M3为例,可以支持以下六种开发环境:

本次移植过程使用Azure RTOS原有的sample_threadx.c文件为例,稍作修改,演示动态内存管理功能。


2、ThreadX 动态内存管理的应用

该章节介绍动态内存管理相关知识,演示程序可在MM32F3273G9P的EVB-F3270上运行。此示例在文件 main_malloc_demo.c 中实现,旨在说明如何在嵌入式多线程环境中使用动态内存管理功能。


2.1  动态内存管理

2.1.1  内存块池

在实时应用程序中,采用快速且确定的方式分配内存始终是一项挑战。考虑到这一点,ThreadX 提供了创建和管理多个固定大小的内存块池的功能。


由于内存块池由固定大小的块组成,因此永远不会出现任何碎片问题。当然,碎片会导致出现本质上不确定的行为。此外,分配和释放固定大小内存块所需的时间与简单的链接列表操作所需的时间相当。另外,还可以在可用列表的开头完成内存块分配和取消分配。这可以提供最快的链接列表处理速度,并且有助于将实际的内存块保存在缓存中。


缺乏灵活性是固定大小内存池的主要缺点。池的块大小必须足够大,才能处理其用户最坏情况下的内存需求。当然,如果对同一个池发出了许多大小不同的内存请求,则可能会浪费内存。一种可能的解决方案是创建多个不同的内存块池,这些池包含不同大小的内存块。


每个内存块池都是一个公用资源。ThreadX 对如何使用池没有任何限制。


2.1.2  创建内存块池

内存块池由应用程序线程在初始化期间或运行时创建。应用程序中内存块池的数量没有限制。


2.1.3  内存块大小

如前所述,内存块池包含许多固定大小的块。块大小(以字节为单位)在创建池时指定。

ThreadX 为池中的每个内存块增加了少量开销(C 指针的大小)。此外,ThreadX 可能需要填充块大小,从而确保每个内存块的开头能够正确对齐。


2.1.4  池容量

池中的内存块数是在创建过程中提供的内存区域的块大小和总字节数的函数。池容量的计算方法是将块大小(包括填充和指针开销字节)除以提供的内存区域的总字节数。


2.1.5  池的内存区域

如前所述,块池的内存区域在创建时指定。与 ThreadX 中的其他内存区域一样,该区域可以位于目标地址空间的任何位置。

这是一项重要的功能,因为它提供了相当大的灵活性。例如,假设某个通信产品有一个用于 I/O 的高速内存区域。将此内存区域设置为 ThreadX 内存块池,即可轻松对其进行管理。


2.1.6  线程挂起

在等待空池中的内存块时,应用程序线程可能会挂起。当块返回到池时,将为挂起的线程提供此块,并恢复线程。

如果同一内存块池中挂起多个线程,这些线程将按挂起的顺序 (FIFO) 恢复。

不过,如果应用程序在取消线程挂起的块释放调用之前调用 tx_block_pool_prioritize,还可以恢复优先级。块池设置优先级服务将优先级最高的线程置于挂起列表的前面,让所有其他挂起的线程采用相同的 FIFO 顺序。


2.1.7  运行时块池性能信息

ThreadX 提供可选的运行时块池性能信息。如果 ThreadX 库和应用程序是在定义 TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO 的情况下生成的,ThreadX 会累积以下信息。

整个系统的总数:

  • 已分配的块数

  • 已释放的块数

  • 分配挂起数

  • 分配超时数

每个块池的总数:

  • 已分配的块数

  • 已释放的块数

  • 分配挂起数

  • 分配超时数

此信息在运行时通过 tx_block_pool_performance_info_get和 tx_block_pool_performance_system_info_get服务提供。块池性能信息在确定应用程序是否正常运行时非常有用。此信息对于优化应用程序也很有用。例如,“分配挂起数”相对较高可能表明块池太小。


2.1.8  内存块池控制块 TX_BLOCK_POOL

每个内存块池的特征都可在其控制块中找到。该控制块包含诸如可用的内存块数和内存池块大小等信息。此结构在 tx_api.h文件中定义。

池控制块也可以位于内存中的任意位置,但最常见的是通过在任何函数的作用域外部定义该控件块来使其成为全局结构。


2.1.9  覆盖内存块

务必确保已分配内存块的用户不会在其边界之外写入。如果发生这种情况,则会损坏其相邻的内存区域(通常是后续区域)。结果不可预测,且对于应用程序来说通常很严重。


2.1.10  内存字节池

内存字节池由应用程序线程在初始化期间或运行时创建。应用程序中内存字节池的数量没有限制。


2.1.11  池容量

内存字节池中可分配的字节数略小于创建期间指定的字节数。这是因为可用内存区域的管理带来了一些开销。池中的每个可用内存块都需要相当于两个 C 指针的开销。此外,创建的池包含两个块:一个较大的可用块和在内存区域末端永久分配的一个较小的块。这个分配块用于提高分配算法的性能。这样就无需在合并期间持续检查池区域末端。

在运行时,池中的开销通常会增加。如果分配奇数字节数,系统会加以填充,以确保正确对齐下一个内存块。此外,随着池变得更加零碎,开销也会增加。


2.1.12  池的内存区域

内存字节池的内存区域在创建过程中指定。与 ThreadX 中的其他内存区域一样,该区域可以位于目标地址空间的任何位置。这是一项重要的功能,因为它提供了相当大的灵活性。例如,如果目标硬件有高速内存区域和低速内存区域,用户可以通过在每个区域中创建池来管理这两个区域的内存分配。


2.1.13  线程挂起

在等待池中的内存字节时,应用程序线程可能会挂起。当有足够的连续内存可用时,将为已挂起的线程提供其请求的内存,并且恢复线程。

如果同一内存字节池中挂起多个线程,则按这些线程挂起的顺序 (FIFO) 为其提供内存(恢复)。

不过,如果应用程序在信号灯发出取消线程挂起的字节释放调用之前调用 tx_byte_pool_prioritize,还可以恢复优先级。字节池设置优先级服务将最高优先级的线程置于挂起列表的前面,让所有其他挂起的线程采用相同的 FIFO 顺序。


2.1.14  运行时字节池性能信息

ThreadX 提供可选的运行时字节池性能信息。如果 ThreadX 库和应用程序是在定义 TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO 的情况下生成的,ThreadX 会累积以下信息。

整个系统的总数:

  • 分配数

  • 版本

  • 搜索的片段数

  • 合并的片段数

  • 创建的片段数

  • 分配挂起数

  • 分配超时数

每个字节池的总数:

  • 分配数

  • 版本

  • 搜索的片段数

  • 合并的片段数

  • 创建的片段数

  • 分配挂起数

  • 分配超时数

此信息在运行时通过 tx_byte_pool_performance_info_get和 tx_byte_pool_performance_system_info_get 服务提供。字节池性能信息在确定应用程序是否正常运行时非常有用。此信息对于优化应用程序也很有用。例如,“分配挂起数”相对较高可能表明字节池太小。


2.1.15  内存字节池控制块 TX_BYTE_POOL

每个内存字节池的特征都可在其控制块中找到。该控制块包含诸如池中可用的字节数等有用的信息。此结构在 tx_api.h 文件中定义。

池控制块也可以位于内存中的任意位置,但最常见的是通过在任何函数的作用域外部定义该控件块来使其成为全局结构。


2.1.16  非确定性行为

尽管内存字节池提供了最灵活的内存分配,但这些池也受一些非确定性行为的影响。例如,内存字节池可能有 2,000 字节的可用内存,但可能无法满足 1,000 字节的分配请求。这是因为无法保证有多少可用字节是连续的。即使存在 1,000 字节可用块,也不能保证找到此块需要多长时间。完全有可能需要搜索整个内存池来查找这个 1,000 字节块。

由于内存字节池的不确定性行为,通常应避免在需要确定性实时行为的区域中使用内存字节服务。许多应用程序在初始化或运行时配置期间预先分配其所需的内存。


2.1.17  覆盖内存块

务必确保已分配内存的用户不会在其边界之外写入。如果发生这种情况,则会损坏其相邻的内存区域(通常是后续区域)。结果不可预测,且对于程序执行来说通常是灾难性的。


2.2  Azure ThreadX 动态内存管理的相关函数

tx_block_allocate分配固定大小的内存块UINT tx_block_allocate(
TX_BLOCK_POOL *pool_ptr, 
VOID **block_ptr, 
ULONG wait_option);


说明

此服务从指定的内存池中分配固定大小的内存块。内存块的实际大小是在创建内存池的过程中确定的参数。

  • pool_ptr:指向之前创建的内存块池的指针。

  • block_ptr:指向目标块指针的指针。成功分配时,已分配内存块的地址就位于此参数所指向的位置。

  • wait_option:定义此服务在没有可用的内存块时的行为方式。等待选项的定义如下:

TX_NO_WAIT (0x00000000):如果选择 TX_NO_WAIT,则无论此服务是否成功,都会导致立即从此服务返回 。如果从非线程(例如初始化、计时器或 ISR)调用服务,则这是唯一有效的选项。


TX_WAIT_FOREVER (0xFFFFFFF):选择 TX_WAIT_FOREVER 会导致发出调用的线程无限期挂起,直到内存块可用为止 。超时值(0x00000001 至 0xFFFFFFFE):如果选择一个数值(1 到 0xFFFFFFFE),则会指定在等待内存块时发出调用的线程保持挂起的最大计时器时钟周期数。


返回值

TX_SUCCESS (0x00) 成功分配内存块。

TX_DELETED (0x01) 线程挂起时删除了内存块池。

TX_NO_MEMORY (0x10) 服务无法在指定的等待时间内分配内存块。

TX_WAIT_ABORTED (0x1A) 挂起状态由其他线程、计时器或 ISR 中止。

TX_POOL_ERROR:(0x02) 内存块池指针无效。

TX_WAIT_ERROR:(0x04) 从非线程调用时指定了除 TX_NO_WAIT 以外的等待选项。

TX_PTR_ERROR:(0x03) 指向目标指针的指针无效。


示例

TX_BLOCK_POOL my_pool;
unsigned char *memory_ptr;

UINT status;

/* Allocate a memory block from my_pool. Assume that the pool has
already been created with a call to tx_block_pool_create. */

status = tx_block_allocate(&my_pool, (VOID **) &memory_ptr,
  TX_NO_WAIT);

/* If status equals TX_SUCCESS, memory_ptr contains the address of
the allocated block of memory. */


另请参阅

  • tx_block_pool_create

  • tx_block_pool_delete

  • tx_block_pool_info_get

  • tx_block_pool_performance_info_get

  • tx_block_pool_performance_system_info_get

  • tx_block_pool_prioritize

  • tx_block_release


  • tx_byte_allocate

  • tx_byte_pool_create

  • tx_byte_pool_delete

  • tx_byte_pool_info_get

  • tx_byte_pool_performance_info_get

  • tx_byte_pool_performance_system_info_get

  • tx_byte_pool_prioritize

  • tx_byte_release

具体函数的中文说明可以参考:

https://docs.microsoft.com/zh-cn/azure/rtos/threadx/chapter4 

具体函数的英文说明可以参考:

https://docs.microsoft.com/en-us/azure/rtos/threadx/threadx-smp/chapter4 


2.3  动态内存管理的应用演示

2.3.1  工程目录的建立

打开目标工程文件夹“MM32F3270Project”:

移除原有样例.c 文件sample_threadx.c:

参考sample_threadx.c建立main_malloc_demo.c文件,并添加hardware目录中的led.c、key.c到工程项目中。

注意:

需要在delay.c中配置USE_SYSTICK_DELAY 为 0。

#define USE_SYSTICK_DELAY 0


3、ThreadX 的内存管理应用

创建如下几个任务:

1)LED1闪烁指示当前系统运行。

2)按键(K1、K2、K3、K4)按下,对应的事件标志置位:

3)获取事件标志,执行处理程序:

  • K1按下,从指定的内存块池中申请固定大小的内存块

  • K2按下,将以前分配的内存块释放回其关联的内存池

  • K3按下,从指定的内存字节池中分配指定的字节数

  • K4按下,将以前分配的内存字节数释放回其关联的内存池

  • 打印内存池信息

3.1  代码实现

下载调试默认会运行到main()函数,如下为全部实现的代码。

Demo演示代码

/* This is a small demo of the high-performance ThreadX kernel.  It includes examples of six
   threads of different priorities, using a message queue, semaphore, and an event flags group.  */

#include "tx_api.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "uart.h"

#define DEMO_STACK_SIZE         1024

#define THREAD0_PRIORITY 1
#define THREAD0_PREEMPTION_THRESHOLD 1
#define THREAD1_PRIORITY 2
#define THREAD1_PREEMPTION_THRESHOLD 2

#define THREAD5_PRIORITY 4
#define THREAD5_PREEMPTION_THRESHOLD 4
//#define THREAD5_PREEMPTION_THRESHOLD_NEW 0


#define BIT_0  ((ULONG)0x0000001) 
#define BIT_1  ((ULONG)0x0000002) 
#define BIT_2  ((ULONG)0x0000004) 
#define BIT_3  ((ULONG)0x0000008) 
#define BIT_ALL (BIT_0|BIT_1|BIT_2|BIT_3)

/* Define the ThreadX object control blocks...  */
TX_THREAD               thread_0;
TX_THREAD               thread_1;

TX_THREAD               thread_5;

TX_EVENT_FLAGS_GROUP  EventGroup;

TX_BLOCK_POOL MyBlock; 
TX_BYTE_POOL MyByte;   

/* Define the counters used in the demo application...  */
ULONG                   thread_0_counter;
ULONG                   thread_1_counter;

ULONG                   thread_5_counter;

/* Define the thread stacks.  */
UCHAR                   thread_0_stack[DEMO_STACK_SIZE];
UCHAR                   thread_1_stack[DEMO_STACK_SIZE];

UCHAR                   thread_5_stack[DEMO_STACK_SIZE];

/* Define thread prototypes.  */

void    thread_0_entry(ULONG thread_input);
void    thread_1_entry(ULONG thread_input);

void    thread_5_entry(ULONG thread_input);


volatile unsigned int bootloop;


uint32_t MyBlockBuf[1024];
uint32_t MyByteBuf[1024];



void System_Init(void);
void AppThreadCreate(void);
void AppModuleCreate(void);


/* Define main entry point.  */

int main()
{
    System_Init();

    /* Enter the ThreadX kernel.  */
    tx_kernel_enter();
}


/* Define what the initial system looks like.  */

void tx_application_define(void* first_unused_memory)
{
    AppThreadCreate();
    AppModuleCreate();

}

void System_Init(void)
{
    DELAY_Init();//can not use systick
    LED_Init();
    KEY_Init();
    CONSOLE_Init(115200);
    printf("!!! Start !!!\r\n");  

}

void AppThreadCreate(void)
{
    /* Create thread 0.  */
    tx_thread_create(
            &thread_0, 
            "thread 0", 
            thread_0_entry, 
            0,
            thread_0_stack, 
            DEMO_STACK_SIZE,
            THREAD0_PRIORITY, 
            THREAD0_PREEMPTION_THRESHOLD, 
            TX_NO_TIME_SLICE, 
            TX_AUTO_START);

    /* Create thread 1.  */
    tx_thread_create(
            &thread_1, 
            "thread 1", 
            thread_1_entry, 
            0,
            thread_1_stack, 
            DEMO_STACK_SIZE,
            THREAD1_PRIORITY, 
            THREAD1_PREEMPTION_THRESHOLD, 
            TX_NO_TIME_SLICE, 
            TX_AUTO_START);


    /* Create thread 5. */
    tx_thread_create(
            &thread_5, 
            "thread 5", 
            thread_5_entry, 
            5,
            thread_5_stack, 
            DEMO_STACK_SIZE,
            THREAD5_PRIORITY, 
            THREAD5_PREEMPTION_THRESHOLD, 
            TX_NO_TIME_SLICE, 
            TX_AUTO_START);

}

void AppModuleCreate(void)
{        
        /* Creates a memory block for applying for a fixed-size memory unit */
        tx_block_pool_create(&MyBlock,
                             "MyBlock",
                             4,                  /* The size of the memory unit */
                             (VOID *)MyBlockBuf,  /* Memory block address, ensure 4-byte alignment */
                                sizeof(MyBlockBuf));/* Memory block size, in bytes */    
        /* Create a memory pool */  
        tx_byte_pool_create(&MyByte, 
                            "MyByte",
                            (VOID *)MyByteBuf,    /* Memory pool address, ensure 4-byte alignment */
                             sizeof(MyByteBuf));    /* Memory pool size */
        /* Create an event flag group */
        tx_event_flags_create(&EventGroup, "EventGroupName");
}


/* Define the test threads.  */
void thread_0_entry(ULONG thread_input)
{
    /* This thread simply controls LED flashing to indicate that the system is running  */
    while(1)
    {
        /* Increment the thread counter.  */
        thread_0_counter++;

        LED1_TOGGLE();

        /* Sleep for 300 ticks.  */
        tx_thread_sleep(300);

    }
}

void thread_1_entry(ULONG thread_input)
{
    UCHAR *BlockPtr;
    UCHAR *BytePtr;
    ULONG available;

    ULONG actual_events;
    UINT status;

    while(1)
    {
    /* Increment the thread counter.  */
        thread_1_counter++;    
        status = tx_event_flags_get(&EventGroup,
                                    BIT_ALL, 
                                    TX_OR_CLEAR,
                                    &actual_events, 
                                    TX_WAIT_FOREVER);
        if(status == TX_SUCCESS)
        {
            switch(actual_events)
            {
                case BIT_0:
                    /* Apply for memory blocks of 4 bytes each time */
                    status = tx_block_allocate(&MyBlock, 
                                               (VOID **)&BlockPtr, 
                                               TX_NO_WAIT);
                    if(status == TX_SUCCESS)
                    {
                        printf("Succeeded in applying for a memory block. \r\n");
                        tx_block_pool_info_get(&MyBlock, 
                                               TX_NULL,
                                               &available, 
                                               TX_NULL,
                                               TX_NULL,
                                               TX_NULL,
                                               TX_NULL);
                        printf("Number of blocks available in MyBlock = %d\r\n", (int)available);
                    }                                    
                    break;
                case BIT_1:
                    status = tx_block_release(BlockPtr);
                    if(status == TX_SUCCESS)
                    {
                        printf("The memory block was released successfully.\r\n");
                        tx_block_pool_info_get(&MyBlock, 
                                               TX_NULL,
                                               &available, 
                                               TX_NULL,
                                               TX_NULL,
                                               TX_NULL,
                                               TX_NULL);
                        printf("Number of blocks available in MyBlock = %d\r\n", (int)available);
                    }                                            
                    break;
                case BIT_2:
                    /* Apply for a memory byte pool, specifying 100 bytes */
                    status = tx_byte_allocate(&MyByte,
                                              (VOID **)&BytePtr,
                                              100, 
                                              TX_NO_WAIT);
                    if(status == TX_SUCCESS)
                    {
                        printf("Succeeded in applying for the memory byte pool.\r\n");
                        tx_byte_pool_info_get(&MyByte, 
                                              TX_NULL,
                                              &available, 
                                              TX_NULL,
                                              TX_NULL, 
                                              TX_NULL,
                                              TX_NULL);                    
                        printf("The available MyByte size = %d bytes. \r\n", (int)available);
                    }                                                            
                    break;                                    
                case BIT_3:
                    status = tx_byte_release(BytePtr);
                    if(status == TX_SUCCESS)
                    {
                        printf("The memory byte pool was released successfully. \r\n");                                                
                        tx_byte_pool_info_get(&MyByte, 
                                              TX_NULL,
                                              &available, 
                                              TX_NULL,
                                              TX_NULL, 
                                              TX_NULL,
                                              TX_NULL);
                        printf("The available MyByte size = %d bytes. \r\n", (int)available);
                    }                                        
                    break;
                default:
                    break;
            }                            

        }    
    }
}


void thread_5_entry(ULONG thread_input)
{  
    UCHAR t = 0;
    /* This thread simply scan button is pressed to send the semaphore.  */
    while(1)
    {    
        /* Increment the thread counter.  */
        thread_5_counter++;         
        t = KEY_Scan(0);
        if(KEY1_PRES == t) 
        {
            //LED1_TOGGLE();
            tx_event_flags_set(&EventGroup, BIT_0, TX_OR);
        }
        else if(KEY2_PRES == t) 
        {
            //LED2_TOGGLE();
            tx_event_flags_set(&EventGroup, BIT_1, TX_OR);  
        }            
        else if(KEY3_PRES == t) 
        {
            //LED3_TOGGLE();
            tx_event_flags_set(&EventGroup, BIT_2, TX_OR);
        }
        else if(KEY4_PRES == t) 
                {
            //LED4_TOGGLE();
            tx_event_flags_set(&EventGroup, BIT_3, TX_OR);
        }
        else 
        {
            tx_thread_sleep(10);
        }
    }
}


3.2  下载与调试

运行程序,板载LED1闪烁。观察串口调试助手,依次按下K1、K2、K3、K4键,串口打印信息:

创建事件标志组初始化为零,用于任务同步。任务5执行按键扫描,当按键按下时通过tx_event_flags_set设置事件标志。任务1通过tx_event_flags_get用于检索事件标志,执行对应的处理程序,其中K1进行内存块申请,K2进行内存块释放,K3用于内存字节申请,K4用于内存字节释放,观测串口打印信息,Demo演示成功。


按下K3从MyByte内存池中申请分配了100个字节,还有3980字节可用,而按下K4释放后变成了4088字节可用,前后差值为108个字节,为什么多了8个字节?感兴趣的同学可以思考一下,找找答案!


4、小结

Azure RTOS ThreadX提供内存池能够以快速且确定的方式分配内存,结合MM32F3270的强大性能,可以实现Azure RTOS广泛的应用场景。

授权代理商:世强先进(深圳)科技股份有限公司
技术资料,数据手册,3D模型库,原理图,PCB封装文件,选型指南来源平台:世强硬创平台www.sekorm.com
现货商城,价格查询,交期查询,订货,现货采购,在线购买,样品申请渠道:世强硬创平台电子商城www.sekorm.com/supply/
概念,方案,设计,选型,BOM优化,FAE技术支持,样品,加工定制,测试,量产供应服务提供:世强硬创平台www.sekorm.com
集成电路,电子元件,电子材料,电气自动化,电机,仪器全品类供应:世强硬创平台www.sekorm.com
  • +1 赞 0
  • 收藏
  • 评论 0

本文由ll转载自灵动MM32MCU公众号,原文标题为:灵动微课堂 (第241讲)|使用MM32F3270基于Azure RTOS动态内存管理的应用,本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

评论

   |   

提交评论

全部评论(0

暂无评论

相关推荐

灵动微电子MM32F0160系列MCU FlexCAN-FD通信应用指南

MM32F0160系列MCU具有一个 FlexCAN 模块,该模块遵循 ISO 11898-1 标准、 CAN FD 和 CAN 2.0B 协议规范,不仅兼容传统CAN,还支持CAN FD模式。本章节初步学习使用MM32F0160 FlexCAN-FD接口实现CAN FD通信,相关例程参考灵动官网的LibSamples或在此基础上修改。

设计经验    发布时间 : 2024-01-07

使用灵动MM32F5270 MCU UART配置实现LIN通信

本文主要简述MM32F5270 UART是如何实现LIN通信的。从LIN驱动程序、 主机程序、从机程序和验证等方面来讲代码实现。

设计经验    发布时间 : 2024-02-23

基于MM32F5270 MCU的Ethernet实现LwIP协议栈移植

LwIP是轻量化的TCP/IP协议,由瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。本文基于搭载了MM32F5277E9P MCU的开发板 PLUS-F5270 V2.0进行实现LwIP协议栈移植。

设计经验    发布时间 : 2024-08-30

【IC】灵动微电子高性能通用32位MCU产品MM32H5480荣获“2024年度硬核MCU芯片奖”

近日,第六届硬核芯生态大会在深圳举办,同期2024年度硬核中国芯获奖榜单正式发布。作为国内领先的本土通用32位MCU产品及解决方案供应商,MindMotion灵动微电子凭借高性能产品MM32H5480斩获“2024年度硬核MCU芯片奖”。

原厂动态    发布时间 : 2024-10-18

MindMotion(灵动微) MCU选型表

32位高性能,高性价比MCU,Core核心有M0、M0+、2XM0、M3、STAR-MC1,Flash存储容量范围 16KB~2048KB,RAM存储容量范围 2KB~128KB,工作电压:1.8~48V,CPU频率(MHz):48~180MHz,GPIO 端口数(个):6~86,LQFP/TSSOP/QFN等多种封装形式。

产品型号
品类
内核
管脚数(个)
工作温度(℃)
CPU频率(MHz)
工作电压(V)
GPIO 端口数(个)
Flash(KB)
SRAM (KB)
封装/外壳/尺寸
MM32F0163D7PV
32位MCU
M0
64
-40℃~105℃
96MHz
2.0~5.5V
57
128KB
16KB
LQFP64

选型表  -  MindMotion 立即选型

灵动微电子扎根张江造“芯”,打造本土32位MCU知名品牌

灵动微电子成立于2011年,2016年进军MCU市场,2019年积极向工业、大家电、汽车等领域发力,目前已涵盖消费电子、电机与电源、家电、汽车、计算机与通信、工业控制等应用领域,客户群体包括飞利浦、小米、汇川、海尔、海信、美的等,是中国本土领先的通用32位MCU 产品及解决方案供应商。

原厂动态    发布时间 : 2024-09-19

MindMotion(灵动微)MM32系列32位MCU选型指南

描述- 灵动微电子成立于2011年,是中国本土领先的通用32位MCU产品及解决方案供应商。灵动微电子的 MCU 产品以 MM32 为标识,基于 Arm Cortex-M 系列内核,自主研发软硬件和生态系统。

型号- MM32G0163D4PV,MM32L0XX,MM32F0144C6PM,MM32F5230,MM32SPIN580C,MM32G0020,MM32G0140,MM32L073PF,MM32F0133C4Q,MM32SPIN080GN,MM32SPIN560CM,MM32SPIN023C,MM32F0133C4P,MM32F5287L8PV,MM32SPIN533AM,MM32F0162D7P,MM32F0121C6P,MM32F0163D4Q,MM32SPIN0230,MM32SPIN080C,MM32F0141C1T,MM32L062NT,MM32F0020B1N,MM32F0144C1TV,MM32F5330,MM32G0001,MM32G0120,MM32F0144C1TM,MM32F0163D7P,MM32SPIN030CN,MM32G0121C1TV,MM32F0010A1TV,MM32SPIN07PF,MM32SPIN05PFOP,MM32SPIN0230B1TV,MM32SPIN37PSD,MM32G0001A6T,MM32F3270,MM32F0121C4P,MM32F0121C4Q,MM32F5277E9PV,MM32F5287L9PV,MM32F0163D6P,MM32F5333D6PV,MM32SPIN0280DAPV,MM32F0121C4N,MM32SPIN080G,MM32SPIN560,MM32F0144C4PM,MM32F0144C4PV,MM32F5280,MM32SPIN06NT,MM32F0140,MM32SPIN560C,MM32F0020,MM32G5333D6QV,MM32F0162D4Q,MM32F0050C1TV,MM32F0273D6P,MM32SPIN0230B3NV,MM32SPIN06PF,MM32G0144C4QV,MM32SPIN0280,MM32L052NT,MM32F5270,MM32F0144C4P,MM32F5277E8PV,MM32F031C6T6,MM32F0130,MM32F0010,MM32F0020B1TV,MM32F5333D7PV,MM32G0144C4PV,MM32SPIN080CN,MM32F0144C4Q,MM32SPIN060G,MM32L0136C7P,MM32F0133C7P,MM32SPIN05NW,MM32F5331D3NV,MM32F0040B1T,MM32SPIN05NT,MM32G0001A6T1V,MM32SPIN06PT,MM32F0120,MM32F0162D6P,MM32F5331D3NM,MM32F003NW,MM32G0160,MM32SPIN27NF,MM32F0163D4QM,MM32SPIN05PF,MM32F031,MM32F3273G6P,MM32F0163D4QV,MM32L0136B6P,MM32G0001A1TV,MM32F0133C6P,MM32SPIN0280D7PV,MM32F5277E7PV,MM32F0144C6P,MM32SPIN222C,MM32F0144C6PV,MM32F0010A6T,MM32G0001A1T,MM32F3273G7P,MM32L0130,MM32G0001A1N,MM32SPIN05PT,MM32G0121C4PV,MM32F0010A1T,MM32F5233D7PV,MM32SPIN27PF,MM32F0010A1N,MM32G5330,MM32SPINEBK,MM32SPIN07,MM32F3273G8P,MM32SPIN160C,MM32SPIN06,MM32F0040B1N,MM32SPIN0230B1NV,MM32L0136C6P,MM32SPIN05,MM32L0020,MM32F0050,MM32SPIN0280D6PV,MM32SPIN533,MM32F031K6U6,MM32F3273G9P,MM32F0163D6PM,MM32SPIN040C,MM32G0020B1T,MM32F0163D6PV,MM32F003,MM32SPIN37,MM32G0020B1N,MM32F0273D8P,MM32F0160,MM32L0136C3T,MM32F0040,MM32G0001A1NV,MM32SPIN0280D6QV,MM32F0144C1T,MM32F103CBT6,MM32F5233D6PV,MM32F0144C4QM,MM32F3273E6P,MM32SPIN27PQ,MM32SPIN27PS,MM32SPIN27PT,MM32L0136C4N,MM32SPIN27,MM32F0020B1NV,MM32F0270,MM32G0121C4QV,MM32F031F6U6,MM32F0273D7P,MM32F003TW,MM32G0144C1TV,MM32F3273E7P,MM32F0141B1T,MM32G0163D6PV,MM32F0163D7PM,MM32SPIN030C,MM32F0163D7PV,MM32F0131C7P,MM32F103,MM32SPIN05TW,MM32F031Y6Y6,MM32F0141C4P,MM32F0141C4Q,MM32F0141C4N,MM32F031K6T6,MM32F0010A1NV,MM32F0131C6P,MM32SPIN422C,MM32F0020B1T,MM32SPIN0280D4PV,MM32L0020B1T,MM32F103RBT6,MM32L0020B1N,MM32F031F6P6,MM32F0121C1N,MM32F0050C1NV,MM32F5333D4QM,MM32G0001A6TV,MM32SPIN360C,MM32,MM32F5333D4QV,MM32F0141C6P,MM32F0141B4P,MM32F0131C4P,MM32F0131C4Q,MM32SPIN0230B3TV,MM32SPIN533A,MM32SPIN033A,MM32F5287L7PV,MM32F5233D4QV

选型指南  -  MINDMOTION  - 2024/5/30 PDF 中文 下载

【IC】灵动发布全新入门级32位MCU MM32G0001系列,内置时钟全温度范围内偏差不超过±2%

灵动股份推出全新超值型MM32G0001系列MCU。2023年初,灵动首次发布了其主打高性价比的MM32G系列,目前已陆续推出了G0140,G0160和G5330系列产品。为进一步丰富MM32G系列产品组合,灵动和上下游合作伙伴通力合作,打造出全新入门级超值型MM32G0001系列MCU。

新产品    发布时间 : 2023-07-01

New Milestone! Following the Success of MM32G0001, MindMotion Launches the Next-Level, High-Value MCU – MM32F0120

MindMotion Microelectronics is excited to announce the official launch of its next-level MCU, the MM32F0120. In 2023, MindMotion‘s entry-level MCU, MM32G0001, made a huge impact with its cost-performance ratio, comparable to or even surpassing 8/16-bit MCUs, earning high praise in the market.

产品    发布时间 : 2024-09-14

灵动MM32SPIN⸺专注电机控制的MCU和SOC

型号- SPIN080G,MM32SPIN030C,SPIN360C,MM32SPIN06NT,SPIN033A,SPIN590G,MM32SPIN560C,MM32SPIN05PT,MM32SPIN580C,MM32SPIN05TW,SPIN0260,MM32SPIN27PF,MM32SPINEBK,MM32SPIN0230B3NV,MM32SPIN080GN,MM32SPIN06PF,SPIN02XX,MM32SPIN07,MM32SPIN0280,MM32SPIN160C,SPIN533A,MM32SPIN,MM32SPIN560CM,SPIN27,MM32SPIN023C,MM32SPIN06,MM32SPIN05,MM32SPIN0230B1NV,MM32SPIN422C,MM32SPIN0280D4PV,MM32SPIN0280D6PV,SPIN060G,SPIN0250,SPIN080C,SPIN222C,SPIN0290,SPIN040C,MM32SPIN080CN,MM32SPIN0230,MM32SPIN060G,MM32SPIN080C,SPIN0230,MM32SPIN040C,SPIN56XX,MM32SPIN37,MM32SPIN05NW,SPIN580C,SPIN160C,SPIN023C,MM32SPIN05NT,MM32SPIN06PT,MM32SPIN0280D6QV,MM32SPIN360C,SPIN0280,SPIN495C,MM32SPIN030CN,MM32SPIN27NF,SPIN560C,SPIN05XX,MM32SPIN07PF,SPIN07,SPIN06,MM32SPIN05PF,MM32SPIN27PQ,MM32SPIN0230B3TV,SPIN5630,MM32SPIN05PFOP,MM32SPIN27PS,MM32SPIN27PT,MM32SPIN0230B1TV,MM32SPIN37PSD,SPIN05,MM32SPIN533A,MM32SPIN033A,MM32SPIN27,MM32SPIN0280D7PV,MM32SPIN222C,SPIN080X,SPIN422C,MM32SPIN0280DAPV,SPIN030C,MM32SPIN080G

商品及供应商介绍  -  MINDMOTION  - 2024/4/30 PDF 中文 下载

基于灵动MM32F0130微控制器的智能插排方案,实现远程开关控制、定时开关、随时了解家电设备的使用状况

智能插座又可以称为WIFI插座,在普通插座的功能基础上延伸了许多功能,如防雷击,防短路,防过载,防漏电,配合智能手机的APP应用,可以实现远程开关控制、定时开关、随时了解家电设备的使用状况。基于灵动MM32F0130微控制器的插排,具有以下特点:-内置Timer进行解码红外输入-通过串口与云端连接,进行远程控制,以及电量监控等-通过I2C与计量芯片通讯,进行异常检测,过流,过/欠压等保护

应用方案    发布时间 : 2024-03-13

【经验】灵动微电子MM32F0160微控制器开源项目:如何实现一套低成本带RGB灯效的机械键盘

灵动的软件与系统工程SE团队,基于带有 USB 外设模块的 MM32F0160 微控制器,实现了一套低成本带RGB灯效的机械键盘。这里将设计机械键盘的全过程开源出来,感兴趣的开发者,可以向灵动申请 MM32F0160 微控制器的样片,复刻一把自己专属的机械键盘,也可以继续进行二次开发,实现更加有趣的作品。

设计经验    发布时间 : 2023-07-01

【经验】基于灵动微MM32L0130系列MCU的低功耗电子时钟设计指南

MM32L0130作为灵动微电子推出的一款低功耗芯片,内置多种省电工作模式保证低功耗应用的要求。本文通过讲述灵动微电子MM32L0130系列MCU PWR电源控制模式,以及SLCD 和RTC外设配置,实现低功耗应用场景。

设计经验    发布时间 : 2023-07-08

基于MM32F5270 MCU初步学习移植FreeRTOS

FreeRTOS是一个RTOS类的嵌入式实时操作系统,具有源码公开、可移植、可裁减、调度策略灵活的特点,可以方便地移植到各种单片机上运行。本系列微课堂基于MM32F5270 MCU初步学习使用FreeRTOS开发。

设计经验    发布时间 : 2024-08-30

展开更多

电子商城

查看更多

品牌:MindMotion

品类:高性能MCU

价格:¥19.8000

现货: 0

品牌:MindMotion

品类:高性能MCU

价格:

现货: 0

品牌:MindMotion

品类:电机专用SOC

价格:¥8.2805

现货: 295

品牌:MindMotion

品类:32位MCU

价格:¥7.7125

现货: 250

品牌:MindMotion

品类:电机专用MCU

价格:¥4.2617

现货: 250

品牌:MindMotion

品类:电机专用MCU

价格:¥3.7500

现货: 250

品牌:MindMotion

品类:电机专用MCU

价格:¥4.9500

现货: 250

品牌:MindMotion

品类:电机专用MCU

价格:¥10.6250

现货: 160

品牌:MindMotion

品类:高性能MCU

价格:¥14.6125

现货: 90

品牌:MindMotion

品类:32位MCU

价格:¥1.6125

现货: 72

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

现货市场

查看更多

品牌:MindMotion

品类:32位MCU

价格:¥5.9400

现货:19,996

品牌:MindMotion

品类:32位MCU

价格:¥2.3800

现货:6,427

品牌:RENESAS

品类:16-BIT MCU

价格:¥5.5190

现货:910,635

品牌:RENESAS

品类:MCU

价格:¥5.1500

现货:200,000

品牌:RENESAS

品类:microcontroller

价格:¥2.8532

现货:188,410

品牌:恒烁

品类:MCU

价格:¥1.0800

现货:154,600

品牌:Advanced Digital Chips

品类:MCU

价格:¥6.6000

现货:100,000

品牌:RENESAS

品类:MCU

价格:¥5.8041

现货:86,925

品牌:RENESAS

品类:32-BIT GENERAL MCU

价格:¥7.3800

现货:76,715

品牌:RENESAS

品类:32-BIT GENERAL MCU

价格:¥15.3000

现货:75,000

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

品牌:

品类:

价格:

现货:

服务

查看更多

压力传感器定制

可定制板装式压力传感器支持产品量程从5inch水柱到100 psi气压;数字输出压力传感器压力范围0.5~60inH2O,温度补偿范围-20~85ºС;模拟和数字低压传感器可以直接与微控制器通信,具备多种小型SIP和DIP封装可选择。

提交需求>

液冷板/液冷机箱定制

定制水冷板尺寸30*30mm~1000*1000 mm,厚度1mm~50mm,散热能力最高50KW,承压可达3MPA;液冷机箱散热能力达500W~100KW。项目单次采购额需满足1万元以上,或年需求5万元以上。

提交需求>

查看更多

授权代理品牌:接插件及结构件

查看更多

授权代理品牌:部件、组件及配件

查看更多

授权代理品牌:电源及模块

查看更多

授权代理品牌:电子材料

查看更多

授权代理品牌:仪器仪表及测试配组件

查看更多

授权代理品牌:电工工具及材料

查看更多

授权代理品牌:机械电子元件

查看更多

授权代理品牌:加工与定制

世强和原厂的技术专家将在一个工作日内解答,帮助您快速完成研发及采购。
我要提问

954668/400-830-1766(工作日 9:00-18:00)

service@sekorm.com

研发客服
商务客服
服务热线

联系我们

954668/400-830-1766(工作日 9:00-18:00)

service@sekorm.com

投诉与建议

E-mail:claim@sekorm.com

商务合作

E-mail:contact@sekorm.com

收藏
收藏当前页面