0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

使用MM32F3270基于Azure RTOS動態(tài)內存管理的應用

靈動MM32MCU ? 來源:靈動MM32MCU ? 2022-12-23 11:01 ? 次閱讀

簡 介

Azure RTOS ThreadX 是 Microsoft 提供的高級工業(yè)級實時操作系統 (RTOS)。它是專門為深度嵌入式實時 IoT 應用程序設計的。Azure RTOS ThreadX 提供高級計劃、通信、同步、計時器、內存管理和中斷管理功能。此外,Azure RTOS ThreadX 具有許多高級功能,包括 picokernel 體系結構、preemption-threshold 計劃、event-chaining、執(zhí)行分析、性能指標和系統事件跟蹤。Azure RTOS ThreadX 非常易于使用,適用于要求極其苛刻的嵌入式應用程序。Azure RTOS ThreadX 在各種產品(包括消費者設備、醫(yī)療電子設備和工業(yè)控制設備)上的部署次數已達數十億次。

在前文描述移植基本內核的基礎上,該應用手冊描述了MM32F3270系列MCU結合Azure RTOS ThreadX內存池的使用,引導用戶理解Azure RTOS ThreadX動態(tài)內存管理功能。

表 1 適用系列型號

系列 芯片型號 開發(fā)板
MM32F3270 MM32F3273G9P EVB-F3270

1移植應用的準備

1.1 硬件開發(fā)板的準備

該移植過程中應用的開發(fā)板為MM32的EVB-F3270,板載MM32F3273G9P。

f6ae7fdc-81fb-11ed-8abf-dac502259ad0.png

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 庫函數和例程。

f6d63676-81fb-11ed-8abf-dac502259ad0.png? ??

Azure RTOS ThreadX(源碼)

ThreadX 的源代碼已經開放,我們可以從 ThreadX 公共源代碼存儲庫獲取 Azure RTOS ThreadX,網址為:

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

Azure RTOS 何時需要許可證?

Microsoft 將 Azure RTOS 源代碼發(fā)布到 GitHub。安裝和使用該軟件進行內部開發(fā)、測試和評估無需許可證。分發(fā)或銷售組件和設備需要許可證,除非使用 Azure RTOS 許可的硬件。

ThreadX 安裝

可以通過將 GitHub 存儲庫克隆到本地計算機來安裝 ThreadX。下面是用于在 PC 上創(chuàng)建 ThreadX 存儲庫的克隆的典型語法。

shell復制

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

或者,也可以使用 GitHub 主頁上的“下載”按鈕來下載存儲庫的副本。

下載后的倉庫代碼目錄列表如下:

f6e7f082-81fb-11ed-8abf-dac502259ad0.png ? ?

Azure RTOS ThreadX(源碼)支持的開發(fā)環(huán)境

ThreadX 內核提供好了各種主流硬件平臺和軟件平臺的移植文件,以Cortex_M3為例,可以支持以下六種開發(fā)環(huán)境:

f6f5f16e-81fb-11ed-8abf-dac502259ad0.png

本次移植過程使用Azure RTOS原有的sample_threadx.c文件為例,稍作修改,演示動態(tài)內存管理功能。

2ThreadX 動態(tài)內存管理的應用

該章節(jié)介紹動態(tài)內存管理相關知識,演示程序可在MM32F3273G9P的EVB-F3270上運行。此示例在文件 main_malloc_demo.c 中實現,旨在說明如何在嵌入式多線程環(huán)境中使用動態(tài)內存管理功能。

2.1 動態(tài)內存管理

2.1.1 內存塊池

在實時應用程序中,采用快速且確定的方式分配內存始終是一項挑戰(zhàn)。考慮到這一點,ThreadX 提供了創(chuàng)建和管理多個固定大小的內存塊池的功能。

由于內存塊池由固定大小的塊組成,因此永遠不會出現任何碎片問題。當然,碎片會導致出現本質上不確定的行為。此外,分配和釋放固定大小內存塊所需的時間與簡單的鏈接列表操作所需的時間相當。另外,還可以在可用列表的開頭完成內存塊分配和取消分配。這可以提供最快的鏈接列表處理速度,并且有助于將實際的內存塊保存在緩存中。

缺乏靈活性是固定大小內存池的主要缺點。池的塊大小必須足夠大,才能處理其用戶最壞情況下的內存需求。當然,如果對同一個池發(fā)出了許多大小不同的內存請求,則可能會浪費內存。一種可能的解決方案是創(chuàng)建多個不同的內存塊池,這些池包含不同大小的內存塊。

每個內存塊池都是一個公用資源。ThreadX 對如何使用池沒有任何限制。

2.1.1 創(chuàng)建內存塊池

內存塊池由應用程序線程在初始化期間或運行時創(chuàng)建。應用程序中內存塊池的數量沒有限制。

2.1.3 內存塊大小

如前所述,內存塊池包含許多固定大小的塊。塊大?。ㄒ宰止?jié)為單位)在創(chuàng)建池時指定。

ThreadX 為池中的每個內存塊增加了少量開銷(C 指針的大?。?。此外,ThreadX 可能需要填充塊大小,從而確保每個內存塊的開頭能夠正確對齊。

2.1.4 池容量

池中的內存塊數是在創(chuàng)建過程中提供的內存區(qū)域的塊大小和總字節(jié)數的函數。池容量的計算方法是將塊大?。òㄌ畛浜椭羔橀_銷字節(jié))除以提供的內存區(qū)域的總字節(jié)數。

2.1.5 池的內存區(qū)域

如前所述,塊池的內存區(qū)域在創(chuàng)建時指定。與 ThreadX 中的其他內存區(qū)域一樣,該區(qū)域可以位于目標地址空間的任何位置。

這是一項重要的功能,因為它提供了相當大的靈活性。例如,假設某個通信產品有一個用于 I/O 的高速內存區(qū)域。將此內存區(qū)域設置為 ThreadX 內存塊池,即可輕松對其進行管理。

2.1.6 線程掛起

在等待空池中的內存塊時,應用程序線程可能會掛起。當塊返回到池時,將為掛起的線程提供此塊,并恢復線程。

如果同一內存塊池中掛起多個線程,這些線程將按掛起的順序 (FIFO) 恢復。

不過,如果應用程序在取消線程掛起的塊釋放調用之前調用 tx_block_pool_prioritize,還可以恢復優(yōu)先級。塊池設置優(yōu)先級服務將優(yōu)先級最高的線程置于掛起列表的前面,讓所有其他掛起的線程采用相同的 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服務提供。塊池性能信息在確定應用程序是否正常運行時非常有用。此信息對于優(yōu)化應用程序也很有用。例如,“分配掛起數”相對較高可能表明塊池太小。

2.1.8 內存塊池控制塊 TX_BLOCK_POOL

每個內存塊池的特征都可在其控制塊中找到。該控制塊包含諸如可用的內存塊數和內存池塊大小等信息。此結構在 tx_api.h文件中定義。

池控制塊也可以位于內存中的任意位置,但最常見的是通過在任何函數的作用域外部定義該控件塊來使其成為全局結構。

2.1.9 覆蓋內存塊

務必確保已分配內存塊的用戶不會在其邊界之外寫入。如果發(fā)生這種情況,則會損壞其相鄰的內存區(qū)域(通常是后續(xù)區(qū)域)。結果不可預測,且對于應用程序來說通常很嚴重。

2.1.10 內存字節(jié)池

內存字節(jié)池由應用程序線程在初始化期間或運行時創(chuàng)建。應用程序中內存字節(jié)池的數量沒有限制。

2.1.12 池容量

內存字節(jié)池中可分配的字節(jié)數略小于創(chuàng)建期間指定的字節(jié)數。這是因為可用內存區(qū)域的管理帶來了一些開銷。池中的每個可用內存塊都需要相當于兩個 C 指針的開銷。此外,創(chuàng)建的池包含兩個塊:一個較大的可用塊和在內存區(qū)域末端永久分配的一個較小的塊。這個分配塊用于提高分配算法的性能。這樣就無需在合并期間持續(xù)檢查池區(qū)域末端。

在運行時,池中的開銷通常會增加。如果分配奇數字節(jié)數,系統會加以填充,以確保正確對齊下一個內存塊。此外,隨著池變得更加零碎,開銷也會增加。

2.1.13 池的內存區(qū)域

內存字節(jié)池的內存區(qū)域在創(chuàng)建過程中指定。與 ThreadX 中的其他內存區(qū)域一樣,該區(qū)域可以位于目標地址空間的任何位置。這是一項重要的功能,因為它提供了相當大的靈活性。例如,如果目標硬件有高速內存區(qū)域和低速內存區(qū)域,用戶可以通過在每個區(qū)域中創(chuàng)建池來管理這兩個區(qū)域的內存分配。

2.1.14 線程掛起

在等待池中的內存字節(jié)時,應用程序線程可能會掛起。當有足夠的連續(xù)內存可用時,將為已掛起的線程提供其請求的內存,并且恢復線程。

如果同一內存字節(jié)池中掛起多個線程,則按這些線程掛起的順序 (FIFO) 為其提供內存(恢復)。

不過,如果應用程序在信號燈發(fā)出取消線程掛起的字節(jié)釋放調用之前調用 tx_byte_pool_prioritize,還可以恢復優(yōu)先級。字節(jié)池設置優(yōu)先級服務將最高優(yōu)先級的線程置于掛起列表的前面,讓所有其他掛起的線程采用相同的 FIFO 順序。

2.1.15 運行時字節(jié)池性能信息

ThreadX 提供可選的運行時字節(jié)池性能信息。如果 ThreadX 庫和應用程序是在定義 TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO 的情況下生成的,ThreadX 會累積以下信息。

整個系統的總數:

分配數

版本

搜索的片段數

合并的片段數

創(chuàng)建的片段數

分配掛起數

分配超時數

每個字節(jié)池的總數:

分配數

版本

搜索的片段數

合并的片段數

創(chuàng)建的片段數

分配掛起數

分配超時數

此信息在運行時通過 tx_byte_pool_performance_info_get和 tx_byte_pool_performance_system_info_get 服務提供。字節(jié)池性能信息在確定應用程序是否正常運行時非常有用。此信息對于優(yōu)化應用程序也很有用。例如,“分配掛起數”相對較高可能表明字節(jié)池太小。

2.1.16 內存字節(jié)池控制塊 TX_BYTE_POOL

每個內存字節(jié)池的特征都可在其控制塊中找到。該控制塊包含諸如池中可用的字節(jié)數等有用的信息。此結構在 tx_api.h 文件中定義。

池控制塊也可以位于內存中的任意位置,但最常見的是通過在任何函數的作用域外部定義該控件塊來使其成為全局結構。

2.1.17 非確定性行為

盡管內存字節(jié)池提供了最靈活的內存分配,但這些池也受一些非確定性行為的影響。例如,內存字節(jié)池可能有 2,000 字節(jié)的可用內存,但可能無法滿足 1,000 字節(jié)的分配請求。這是因為無法保證有多少可用字節(jié)是連續(xù)的。即使存在 1,000 字節(jié)可用塊,也不能保證找到此塊需要多長時間。完全有可能需要搜索整個內存池來查找這個 1,000 字節(jié)塊。

由于內存字節(jié)池的不確定性行為,通常應避免在需要確定性實時行為的區(qū)域中使用內存字節(jié)服務。許多應用程序在初始化或運行時配置期間預先分配其所需的內存。

2.1.18 覆蓋內存塊

務必確保已分配內存的用戶不會在其邊界之外寫入。如果發(fā)生這種情況,則會損壞其相鄰的內存區(qū)域(通常是后續(xù)區(qū)域)。結果不可預測,且對于程序執(zhí)行來說通常是災難性的。

2.2 Azure ThreadX 動態(tài)內存管理的相關函數

tx_block_allocate分配固定大小的內存塊

UINTtx_block_allocate(
TX_BLOCK_POOL*pool_ptr,
VOID**block_ptr,
ULONGwait_option);

說明

此服務從指定的內存池中分配固定大小的內存塊。內存塊的實際大小是在創(chuàng)建內存池的過程中確定的參數。

pool_ptr:指向之前創(chuàng)建的內存塊池的指針。

block_ptr:指向目標塊指針的指針。成功分配時,已分配內存塊的地址就位于此參數所指向的位置。

wait_option:定義此服務在沒有可用的內存塊時的行為方式。等待選項的定義如下:

TX_NO_WAIT (0x00000000)

如果選擇 TX_NO_WAIT,則無論此服務是否成功,都會導致立即從此服務返回 。如果從非線程(例如初始化、計時器或 ISR)調用服務,則這是唯一有效的選項。

TX_WAIT_FOREVER (0xFFFFFFF)

選擇 TX_WAIT_FOREVER 會導致發(fā)出調用的線程無限期掛起,直到內存塊可用為止 。

超時值(0x00000001 至 0xFFFFFFFE)

如果選擇一個數值(1 到 0xFFFFFFFE),則會指定在等待內存塊時發(fā)出調用的線程保持掛起的最大計時器時鐘周期數。

返回值

TX_SUCCESS (0x00) 成功分配內存塊。

TX_DELETED (0x01) 線程掛起時刪除了內存塊池。

TX_NO_MEMORY (0x10) 服務無法在指定的等待時間內分配內存塊。

TX_WAIT_ABORTED (0x1A) 掛起狀態(tài)由其他線程、計時器或 ISR 中止。

TX_POOL_ERROR:(0x02) 內存塊池指針無效。

TX_WAIT_ERROR:(0x04) 從非線程調用時指定了除 TX_NO_WAIT 以外的等待選項。

TX_PTR_ERROR:(0x03) 指向目標指針的指針無效。

示例

TX_BLOCK_POOLmy_pool;
unsignedchar*memory_ptr;

UINTstatus;

/*Allocateamemoryblockfrommy_pool.Assumethatthepoolhas
alreadybeencreatedwithacalltotx_block_pool_create.*/

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

/*IfstatusequalsTX_SUCCESS,memory_ptrcontainstheaddressof
theallocatedblockofmemory.*/

另請參閱

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

2.3 動態(tài)內存管理的應用演示

2.3.1 工程目錄的建立

打開目標工程文件夾“MM32F3270Project”:

f7045812-81fb-11ed-8abf-dac502259ad0.png

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

f7187b4e-81fb-11ed-8abf-dac502259ad0.png

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

f72d8b9c-81fb-11ed-8abf-dac502259ad0.png

注意:

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

#define USE_SYSTICK_DELAY 0

3ThreadX 的內存管理應用

創(chuàng)建如下幾個任務:

LED1閃爍指示當前系統運行。

按鍵(K1、K2、K3、K4)按下,對應的事件標志置位:

獲取事件標志,執(zhí)行處理程序:

K1按下,從指定的內存塊池中申請固定大小的內存塊

K2按下,將以前分配的內存塊釋放回其關聯的內存池

K3按下,從指定的內存字節(jié)池中分配指定的字節(jié)數

K4按下,將以前分配的內存字節(jié)數釋放回其關聯的內存池

打印內存池信息

3.1 代碼實現

下載調試默認會運行到main()函數,如下為全部實現的代碼。

Demo演示代碼

/*Thisisasmalldemoofthehigh-performanceThreadXkernel.Itincludesexamplesofsix
threadsofdifferentpriorities,usingamessagequeue,semaphore,andaneventflagsgroup.*/

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

#defineDEMO_STACK_SIZE1024

#defineTHREAD0_PRIORITY1
#defineTHREAD0_PREEMPTION_THRESHOLD1
#defineTHREAD1_PRIORITY2
#defineTHREAD1_PREEMPTION_THRESHOLD2

#defineTHREAD5_PRIORITY4
#defineTHREAD5_PREEMPTION_THRESHOLD4
//#defineTHREAD5_PREEMPTION_THRESHOLD_NEW0


#defineBIT_0((ULONG)0x0000001)
#defineBIT_1((ULONG)0x0000002)
#defineBIT_2((ULONG)0x0000004)
#defineBIT_3((ULONG)0x0000008)
#defineBIT_ALL(BIT_0|BIT_1|BIT_2|BIT_3)

/*DefinetheThreadXobjectcontrolblocks...*/
TX_THREADthread_0;
TX_THREADthread_1;

TX_THREADthread_5;

TX_EVENT_FLAGS_GROUPEventGroup;

TX_BLOCK_POOLMyBlock;
TX_BYTE_POOLMyByte;

/*Definethecountersusedinthedemoapplication...*/
ULONGthread_0_counter;
ULONGthread_1_counter;

ULONGthread_5_counter;

/*Definethethreadstacks.*/
UCHARthread_0_stack[DEMO_STACK_SIZE];
UCHARthread_1_stack[DEMO_STACK_SIZE];

UCHARthread_5_stack[DEMO_STACK_SIZE];

/*Definethreadprototypes.*/

voidthread_0_entry(ULONGthread_input);
voidthread_1_entry(ULONGthread_input);

voidthread_5_entry(ULONGthread_input);


volatileunsignedintbootloop;


uint32_tMyBlockBuf[1024];
uint32_tMyByteBuf[1024];



voidSystem_Init(void);
voidAppThreadCreate(void);
voidAppModuleCreate(void);


/*Definemainentrypoint.*/

intmain()
{
System_Init();

/*EntertheThreadXkernel.*/
tx_kernel_enter();
}


/*Definewhattheinitialsystemlookslike.*/

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

}

voidSystem_Init(void)
{
DELAY_Init();//cannotusesystick
LED_Init();
KEY_Init();
CONSOLE_Init(115200);
printf("!!!Start!!!
");

}

voidAppThreadCreate(void)
{
/*Createthread0.*/
tx_thread_create(
&thread_0,
"thread0",
thread_0_entry,
0,
thread_0_stack,
DEMO_STACK_SIZE,
THREAD0_PRIORITY,
THREAD0_PREEMPTION_THRESHOLD,
TX_NO_TIME_SLICE,
TX_AUTO_START);

/*Createthread1.*/
tx_thread_create(
&thread_1,
"thread1",
thread_1_entry,
0,
thread_1_stack,
DEMO_STACK_SIZE,
THREAD1_PRIORITY,
THREAD1_PREEMPTION_THRESHOLD,
TX_NO_TIME_SLICE,
TX_AUTO_START);


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

}

voidAppModuleCreate(void)
{
/*Createsamemoryblockforapplyingforafixed-sizememoryunit*/
tx_block_pool_create(&MyBlock,
"MyBlock",
4,/*Thesizeofthememoryunit*/
(VOID*)MyBlockBuf,/*Memoryblockaddress,ensure4-bytealignment*/
sizeof(MyBlockBuf));/*Memoryblocksize,inbytes*/
/*Createamemorypool*/
tx_byte_pool_create(&MyByte,
"MyByte",
(VOID*)MyByteBuf,/*Memorypooladdress,ensure4-bytealignment*/
sizeof(MyByteBuf));/*Memorypoolsize*/
/*Createaneventflaggroup*/
tx_event_flags_create(&EventGroup,"EventGroupName");
}


/*Definethetestthreads.*/
voidthread_0_entry(ULONGthread_input)
{
/*ThisthreadsimplycontrolsLEDflashingtoindicatethatthesystemisrunning*/
while(1)
{
/*Incrementthethreadcounter.*/
thread_0_counter++;

LED1_TOGGLE();

/*Sleepfor300ticks.*/
tx_thread_sleep(300);

}
}

voidthread_1_entry(ULONGthread_input)
{
UCHAR*BlockPtr;
UCHAR*BytePtr;
ULONGavailable;

ULONGactual_events;
UINTstatus;

while(1)
{
/*Incrementthethreadcounter.*/
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)
{
caseBIT_0:
/*Applyformemoryblocksof4byteseachtime*/
status=tx_block_allocate(&MyBlock,
(VOID**)&BlockPtr,
TX_NO_WAIT);
if(status==TX_SUCCESS)
{
printf("Succeededinapplyingforamemoryblock.
");
tx_block_pool_info_get(&MyBlock,
TX_NULL,
&available,
TX_NULL,
TX_NULL,
TX_NULL,
TX_NULL);
printf("NumberofblocksavailableinMyBlock=%d
",(int)available);
}
break;
caseBIT_1:
status=tx_block_release(BlockPtr);
if(status==TX_SUCCESS)
{
printf("Thememoryblockwasreleasedsuccessfully.
");
tx_block_pool_info_get(&MyBlock,
TX_NULL,
&available,
TX_NULL,
TX_NULL,
TX_NULL,
TX_NULL);
printf("NumberofblocksavailableinMyBlock=%d
",(int)available);
}
break;
caseBIT_2:
/*Applyforamemorybytepool,specifying100bytes*/
status=tx_byte_allocate(&MyByte,
(VOID**)&BytePtr,
100,
TX_NO_WAIT);
if(status==TX_SUCCESS)
{
printf("Succeededinapplyingforthememorybytepool.
");
tx_byte_pool_info_get(&MyByte,
TX_NULL,
&available,
TX_NULL,
TX_NULL,
TX_NULL,
TX_NULL);
printf("TheavailableMyBytesize=%dbytes.
",(int)available);
}
break;
caseBIT_3:
status=tx_byte_release(BytePtr);
if(status==TX_SUCCESS)
{
printf("Thememorybytepoolwasreleasedsuccessfully.
");
tx_byte_pool_info_get(&MyByte,
TX_NULL,
&available,
TX_NULL,
TX_NULL,
TX_NULL,
TX_NULL);
printf("TheavailableMyBytesize=%dbytes.
",(int)available);
}
break;
default:
break;
}

}
}
}


voidthread_5_entry(ULONGthread_input)
{
UCHARt=0;
/*Thisthreadsimplyscanbuttonispressedtosendthesemaphore.*/
while(1)
{
/*Incrementthethreadcounter.*/
thread_5_counter++;
t=KEY_Scan(0);
if(KEY1_PRES==t)
{
//LED1_TOGGLE();
tx_event_flags_set(&EventGroup,BIT_0,TX_OR);
}
elseif(KEY2_PRES==t)
{
//LED2_TOGGLE();
tx_event_flags_set(&EventGroup,BIT_1,TX_OR);
}
elseif(KEY3_PRES==t)
{
//LED3_TOGGLE();
tx_event_flags_set(&EventGroup,BIT_2,TX_OR);
}
elseif(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鍵,串口打印信息:

f74afcc2-81fb-11ed-8abf-dac502259ad0.png

創(chuàng)建事件標志組初始化為零,用于任務同步。任務5執(zhí)行按鍵掃描,當按鍵按下時通過tx_event_flags_set設置事件標志。任務1通過tx_event_flags_get用于檢索事件標志,執(zhí)行對應的處理程序,其中K1進行內存塊申請,K2進行內存塊釋放,K3用于內存字節(jié)申請,K4用于內存字節(jié)釋放,觀測串口打印信息,Demo演示成功。

按下K3從MyByte內存池中申請分配了100個字節(jié),還有3980字節(jié)可用,而按下K4釋放后變成了4088字節(jié)可用,前后差值為108個字節(jié),為什么多了8個字節(jié)?感興趣的同學可以思考一下,找找答案!

4小結

Azure RTOS ThreadX提供內存池能夠以快速且確定的方式分配內存,結合MM32F3270的強大性能,可以實現Azure RTOS廣泛的應用場景。

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯系本站處理。 舉報投訴
  • threadx
    +關注

    關注

    0

    文章

    15

    瀏覽量

    13801
  • RTOS
    +關注

    關注

    21

    文章

    807

    瀏覽量

    119287
  • 動態(tài)內存管理

    關注

    0

    文章

    5

    瀏覽量

    6604
  • Azure
    +關注

    關注

    1

    文章

    119

    瀏覽量

    12745

原文標題:靈動微課堂 (第241講)|使用MM32F3270基于Azure RTOS動態(tài)內存管理的應用

文章出處:【微信號:MindMotion-MMCU,微信公眾號:靈動MM32MCU】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    使用MM32F3270基于Azure RTOS定時器組的應用

    高級計劃、通信、同步、計時器、內存管理和中斷管理功能。此外,Azure RTOS ThreadX 具有許多高級功能,包括 picokerne
    的頭像 發(fā)表于 12-29 17:26 ?1569次閱讀

    MM32F3270系列32位MCU的特點有哪些

    、家電、電源管理、打印機和掃描儀、通信轉換模塊等應用領域范圍。MM32F3270系列支持工業(yè)級(-40℃至85℃)和擴展工業(yè)級(-40℃~105℃)工作溫度。內置多種省電工作模式保證低功耗應用的要求
    發(fā)表于 11-03 07:20

    使用MM32F3270基于Azure RTOS定時器組的應用

    各種產品(包括消費者設備、醫(yī)療電子設備和工業(yè)控制設備)上的部署次數已達數十億次。在前文描述移植基本內核的基礎上,該應用手冊描述了MM32F3270系列MCU結合Azure RTOS ThreadX
    發(fā)表于 02-07 14:18

    靈動微電子MM32F3270系列MCU的特點介紹

    、家電、電源管理、打印機和掃描儀、通信轉換模塊等應用領域范圍。MM32F3270系列支持工業(yè)級(-40℃~85℃)和擴展工業(yè)級(-40℃~105℃)工作溫度。內置多種省電工作模式保證低功耗應用的要求。
    發(fā)表于 03-22 16:57 ?2109次閱讀

    【國產MCU移植】MM32F3270 EVBoard

    【國產MCU移植】MM32F3270 EVBoard
    發(fā)表于 12-03 17:21 ?5次下載
    【國產MCU移植】<b class='flag-5'>MM32F3270</b> EVBoard

    基于MM32F3270 以太網 Client使用

    接下來給大家介紹基于TCP包的通訊。內容分為基于MM32F3270以太網Client的使用與基于MM32F3270以太網Server的使用。
    發(fā)表于 02-08 15:10 ?0次下載
    基于<b class='flag-5'>MM32F3270</b> 以太網 Client使用

    使用MM32F3270基于Azure RTOS信號量的應用

    高級計劃、通信、同步、計時器、內存管理和中斷管理功能。此外,Azure RTOS ThreadX 具有許多高級功能,包括 picokerne
    的頭像 發(fā)表于 12-16 09:23 ?943次閱讀

    使用MM32F3270基于Azure RTOS事件標志組的應用

    使用MM32F3270基于Azure RTOS事件標志組的應用
    的頭像 發(fā)表于 10-27 11:31 ?460次閱讀
    使用<b class='flag-5'>MM32F3270</b>基于<b class='flag-5'>Azure</b> <b class='flag-5'>RTOS</b>事件標志組的應用

    使用MM32F3270基于Azure RTOS (ThreadX) 的移植

    使用MM32F3270基于Azure RTOS (ThreadX) 的移植
    的頭像 發(fā)表于 10-27 10:15 ?684次閱讀
    使用<b class='flag-5'>MM32F3270</b>基于<b class='flag-5'>Azure</b> <b class='flag-5'>RTOS</b> (ThreadX) 的移植

    MM32F3270 ADC注入通道

    MM32F3270 ADC注入通道
    的頭像 發(fā)表于 09-27 15:59 ?909次閱讀
    <b class='flag-5'>MM32F3270</b> ADC注入通道

    使用MM32F3270 FSMC驅動OLED

    使用MM32F3270 FSMC驅動OLED
    的頭像 發(fā)表于 09-27 15:30 ?841次閱讀
    使用<b class='flag-5'>MM32F3270</b> FSMC驅動OLED

    使用MM32F3270 FSMC驅動TFT-LCD

    使用MM32F3270 FSMC驅動TFT-LCD
    的頭像 發(fā)表于 09-27 15:34 ?857次閱讀
    使用<b class='flag-5'>MM32F3270</b> FSMC驅動TFT-LCD

    基于MM32F3270以太網Client使用

    基于MM32F3270以太網Client使用
    的頭像 發(fā)表于 09-27 15:44 ?635次閱讀
    基于<b class='flag-5'>MM32F3270</b>以太網Client使用

    基于MM32F3270以太網UDP使用

    基于MM32F3270以太網 UDP使用
    的頭像 發(fā)表于 09-27 15:42 ?433次閱讀
    基于<b class='flag-5'>MM32F3270</b>以太網UDP使用

    基于MM32F3270以太網Client_Socket使用

    基于MM32F3270以太網Client_Socket使用
    的頭像 發(fā)表于 09-27 15:37 ?495次閱讀
    基于<b class='flag-5'>MM32F3270</b>以太網Client_Socket使用