簡 介
Azure RTOS ThreadX 是 Microsoft 提供的高級(jí)工業(yè)級(jí)實(shí)時(shí)操作系統(tǒng) (RTOS)。它是專門為深度嵌入式實(shí)時(shí) IoT 應(yīng)用程序設(shè)計(jì)的。Azure RTOS ThreadX 提供高級(jí)計(jì)劃、通信、同步、計(jì)時(shí)器、內(nèi)存管理和中斷管理功能。此外,Azure RTOS ThreadX 具有許多高級(jí)功能,包括 picokernel 體系結(jié)構(gòu)、preemption-threshold 計(jì)劃、event-chaining、執(zhí)行分析、性能指標(biāo)和系統(tǒng)事件跟蹤。Azure RTOS ThreadX 非常易于使用,適用于要求極其苛刻的嵌入式應(yīng)用程序。Azure RTOS ThreadX 在各種產(chǎn)品(包括消費(fèi)者設(shè)備、醫(yī)療電子設(shè)備和工業(yè)控制設(shè)備)上的部署次數(shù)已達(dá)數(shù)十億次。
在前文描述移植基本內(nèi)核的基礎(chǔ)上,該應(yīng)用手冊(cè)描述了MM32F3270系列MCU結(jié)合Azure RTOS ThreadX內(nèi)存池的使用,引導(dǎo)用戶理解Azure RTOS ThreadX動(dòng)態(tài)內(nèi)存管理功能。
表 1 適用系列型號(hào)
系列 | 芯片型號(hào) | 開發(fā)板 |
MM32F3270 | MM32F3273G9P | EVB-F3270 |
1移植應(yīng)用的準(zhǔn)備
1.1 硬件開發(fā)板的準(zhǔn)備
該移植過程中應(yīng)用的開發(fā)板為MM32的EVB-F3270,板載MM32F3273G9P。
EVB-F3270 (MM32F3273G9P) 的簡要參數(shù):
Arm Cortex-M3 內(nèi)核
板載 MM32F3273G9P(LQFP144)
4 x Key、4 x LED
I2S Speaker
TF-Card
Ethernet PHY
1.2 軟件的準(zhǔn)備
庫函數(shù)和例程(Lib Samples)
該移植過程中應(yīng)用的 Firmware 分別為 MM32F3270 庫函數(shù)和例程。
? ??
Azure RTOS ThreadX(源碼)
ThreadX 的源代碼已經(jīng)開放,我們可以從 ThreadX 公共源代碼存儲(chǔ)庫獲取 Azure RTOS ThreadX,網(wǎng)址為:
https://github.com/azure-rtos/threadx/
Azure RTOS 何時(shí)需要許可證?
Microsoft 將 Azure RTOS 源代碼發(fā)布到 GitHub。安裝和使用該軟件進(jìn)行內(nèi)部開發(fā)、測試和評(píng)估無需許可證。分發(fā)或銷售組件和設(shè)備需要許可證,除非使用 Azure RTOS 許可的硬件。
ThreadX 安裝
可以通過將 GitHub 存儲(chǔ)庫克隆到本地計(jì)算機(jī)來安裝 ThreadX。下面是用于在 PC 上創(chuàng)建 ThreadX 存儲(chǔ)庫的克隆的典型語法。
shell復(fù)制
git clone https://github.com/azure-rtos/threadx
或者,也可以使用 GitHub 主頁上的“下載”按鈕來下載存儲(chǔ)庫的副本。
下載后的倉庫代碼目錄列表如下:
? ?
Azure RTOS ThreadX(源碼)支持的開發(fā)環(huán)境
ThreadX 內(nèi)核提供好了各種主流硬件平臺(tái)和軟件平臺(tái)的移植文件,以Cortex_M3為例,可以支持以下六種開發(fā)環(huán)境:
本次移植過程使用Azure RTOS原有的sample_threadx.c文件為例,稍作修改,演示動(dòng)態(tài)內(nèi)存管理功能。
2ThreadX 動(dòng)態(tài)內(nèi)存管理的應(yīng)用
該章節(jié)介紹動(dòng)態(tài)內(nèi)存管理相關(guān)知識(shí),演示程序可在MM32F3273G9P的EVB-F3270上運(yùn)行。此示例在文件 main_malloc_demo.c 中實(shí)現(xiàn),旨在說明如何在嵌入式多線程環(huán)境中使用動(dòng)態(tài)內(nèi)存管理功能。
2.1 動(dòng)態(tài)內(nèi)存管理
2.1.1 內(nèi)存塊池
在實(shí)時(shí)應(yīng)用程序中,采用快速且確定的方式分配內(nèi)存始終是一項(xiàng)挑戰(zhàn)??紤]到這一點(diǎn),ThreadX 提供了創(chuàng)建和管理多個(gè)固定大小的內(nèi)存塊池的功能。
由于內(nèi)存塊池由固定大小的塊組成,因此永遠(yuǎn)不會(huì)出現(xiàn)任何碎片問題。當(dāng)然,碎片會(huì)導(dǎo)致出現(xiàn)本質(zhì)上不確定的行為。此外,分配和釋放固定大小內(nèi)存塊所需的時(shí)間與簡單的鏈接列表操作所需的時(shí)間相當(dāng)。另外,還可以在可用列表的開頭完成內(nèi)存塊分配和取消分配。這可以提供最快的鏈接列表處理速度,并且有助于將實(shí)際的內(nèi)存塊保存在緩存中。
缺乏靈活性是固定大小內(nèi)存池的主要缺點(diǎn)。池的塊大小必須足夠大,才能處理其用戶最壞情況下的內(nèi)存需求。當(dāng)然,如果對(duì)同一個(gè)池發(fā)出了許多大小不同的內(nèi)存請(qǐng)求,則可能會(huì)浪費(fèi)內(nèi)存。一種可能的解決方案是創(chuàng)建多個(gè)不同的內(nèi)存塊池,這些池包含不同大小的內(nèi)存塊。
每個(gè)內(nèi)存塊池都是一個(gè)公用資源。ThreadX 對(duì)如何使用池沒有任何限制。
2.1.1 創(chuàng)建內(nèi)存塊池
內(nèi)存塊池由應(yīng)用程序線程在初始化期間或運(yùn)行時(shí)創(chuàng)建。應(yīng)用程序中內(nèi)存塊池的數(shù)量沒有限制。
2.1.3 內(nèi)存塊大小
如前所述,內(nèi)存塊池包含許多固定大小的塊。塊大?。ㄒ宰止?jié)為單位)在創(chuàng)建池時(shí)指定。
ThreadX 為池中的每個(gè)內(nèi)存塊增加了少量開銷(C 指針的大?。4送?,ThreadX 可能需要填充塊大小,從而確保每個(gè)內(nèi)存塊的開頭能夠正確對(duì)齊。
2.1.4 池容量
池中的內(nèi)存塊數(shù)是在創(chuàng)建過程中提供的內(nèi)存區(qū)域的塊大小和總字節(jié)數(shù)的函數(shù)。池容量的計(jì)算方法是將塊大?。òㄌ畛浜椭羔橀_銷字節(jié))除以提供的內(nèi)存區(qū)域的總字節(jié)數(shù)。
2.1.5 池的內(nèi)存區(qū)域
如前所述,塊池的內(nèi)存區(qū)域在創(chuàng)建時(shí)指定。與 ThreadX 中的其他內(nèi)存區(qū)域一樣,該區(qū)域可以位于目標(biāo)地址空間的任何位置。
這是一項(xiàng)重要的功能,因?yàn)樗峁┝讼喈?dāng)大的靈活性。例如,假設(shè)某個(gè)通信產(chǎn)品有一個(gè)用于 I/O 的高速內(nèi)存區(qū)域。將此內(nèi)存區(qū)域設(shè)置為 ThreadX 內(nèi)存塊池,即可輕松對(duì)其進(jìn)行管理。
2.1.6 線程掛起
在等待空池中的內(nèi)存塊時(shí),應(yīng)用程序線程可能會(huì)掛起。當(dāng)塊返回到池時(shí),將為掛起的線程提供此塊,并恢復(fù)線程。
如果同一內(nèi)存塊池中掛起多個(gè)線程,這些線程將按掛起的順序 (FIFO) 恢復(fù)。
不過,如果應(yīng)用程序在取消線程掛起的塊釋放調(diào)用之前調(diào)用 tx_block_pool_prioritize,還可以恢復(fù)優(yōu)先級(jí)。塊池設(shè)置優(yōu)先級(jí)服務(wù)將優(yōu)先級(jí)最高的線程置于掛起列表的前面,讓所有其他掛起的線程采用相同的 FIFO 順序。
2.1.7 運(yùn)行時(shí)塊池性能信息
ThreadX 提供可選的運(yùn)行時(shí)塊池性能信息。如果 ThreadX 庫和應(yīng)用程序是在定義 TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO 的情況下生成的,ThreadX 會(huì)累積以下信息。
整個(gè)系統(tǒng)的總數(shù):
已分配的塊數(shù)
已釋放的塊數(shù)
分配掛起數(shù)
分配超時(shí)數(shù)
每個(gè)塊池的總數(shù):
已分配的塊數(shù)
已釋放的塊數(shù)
分配掛起數(shù)
分配超時(shí)數(shù)
此信息在運(yùn)行時(shí)通過 tx_block_pool_performance_info_get和 tx_block_pool_performance_system_info_get服務(wù)提供。塊池性能信息在確定應(yīng)用程序是否正常運(yùn)行時(shí)非常有用。此信息對(duì)于優(yōu)化應(yīng)用程序也很有用。例如,“分配掛起數(shù)”相對(duì)較高可能表明塊池太小。
2.1.8 內(nèi)存塊池控制塊 TX_BLOCK_POOL
每個(gè)內(nèi)存塊池的特征都可在其控制塊中找到。該控制塊包含諸如可用的內(nèi)存塊數(shù)和內(nèi)存池塊大小等信息。此結(jié)構(gòu)在 tx_api.h文件中定義。
池控制塊也可以位于內(nèi)存中的任意位置,但最常見的是通過在任何函數(shù)的作用域外部定義該控件塊來使其成為全局結(jié)構(gòu)。
2.1.9 覆蓋內(nèi)存塊
務(wù)必確保已分配內(nèi)存塊的用戶不會(huì)在其邊界之外寫入。如果發(fā)生這種情況,則會(huì)損壞其相鄰的內(nèi)存區(qū)域(通常是后續(xù)區(qū)域)。結(jié)果不可預(yù)測,且對(duì)于應(yīng)用程序來說通常很嚴(yán)重。
2.1.10 內(nèi)存字節(jié)池
內(nèi)存字節(jié)池由應(yīng)用程序線程在初始化期間或運(yùn)行時(shí)創(chuàng)建。應(yīng)用程序中內(nèi)存字節(jié)池的數(shù)量沒有限制。
2.1.12 池容量
內(nèi)存字節(jié)池中可分配的字節(jié)數(shù)略小于創(chuàng)建期間指定的字節(jié)數(shù)。這是因?yàn)榭捎脙?nèi)存區(qū)域的管理帶來了一些開銷。池中的每個(gè)可用內(nèi)存塊都需要相當(dāng)于兩個(gè) C 指針的開銷。此外,創(chuàng)建的池包含兩個(gè)塊:一個(gè)較大的可用塊和在內(nèi)存區(qū)域末端永久分配的一個(gè)較小的塊。這個(gè)分配塊用于提高分配算法的性能。這樣就無需在合并期間持續(xù)檢查池區(qū)域末端。
在運(yùn)行時(shí),池中的開銷通常會(huì)增加。如果分配奇數(shù)字節(jié)數(shù),系統(tǒng)會(huì)加以填充,以確保正確對(duì)齊下一個(gè)內(nèi)存塊。此外,隨著池變得更加零碎,開銷也會(huì)增加。
2.1.13 池的內(nèi)存區(qū)域
內(nèi)存字節(jié)池的內(nèi)存區(qū)域在創(chuàng)建過程中指定。與 ThreadX 中的其他內(nèi)存區(qū)域一樣,該區(qū)域可以位于目標(biāo)地址空間的任何位置。這是一項(xiàng)重要的功能,因?yàn)樗峁┝讼喈?dāng)大的靈活性。例如,如果目標(biāo)硬件有高速內(nèi)存區(qū)域和低速內(nèi)存區(qū)域,用戶可以通過在每個(gè)區(qū)域中創(chuàng)建池來管理這兩個(gè)區(qū)域的內(nèi)存分配。
2.1.14 線程掛起
在等待池中的內(nèi)存字節(jié)時(shí),應(yīng)用程序線程可能會(huì)掛起。當(dāng)有足夠的連續(xù)內(nèi)存可用時(shí),將為已掛起的線程提供其請(qǐng)求的內(nèi)存,并且恢復(fù)線程。
如果同一內(nèi)存字節(jié)池中掛起多個(gè)線程,則按這些線程掛起的順序 (FIFO) 為其提供內(nèi)存(恢復(fù))。
不過,如果應(yīng)用程序在信號(hào)燈發(fā)出取消線程掛起的字節(jié)釋放調(diào)用之前調(diào)用 tx_byte_pool_prioritize,還可以恢復(fù)優(yōu)先級(jí)。字節(jié)池設(shè)置優(yōu)先級(jí)服務(wù)將最高優(yōu)先級(jí)的線程置于掛起列表的前面,讓所有其他掛起的線程采用相同的 FIFO 順序。
2.1.15 運(yùn)行時(shí)字節(jié)池性能信息
ThreadX 提供可選的運(yùn)行時(shí)字節(jié)池性能信息。如果 ThreadX 庫和應(yīng)用程序是在定義 TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO 的情況下生成的,ThreadX 會(huì)累積以下信息。
整個(gè)系統(tǒng)的總數(shù):
分配數(shù)
版本
搜索的片段數(shù)
合并的片段數(shù)
創(chuàng)建的片段數(shù)
分配掛起數(shù)
分配超時(shí)數(shù)
每個(gè)字節(jié)池的總數(shù):
分配數(shù)
版本
搜索的片段數(shù)
合并的片段數(shù)
創(chuàng)建的片段數(shù)
分配掛起數(shù)
分配超時(shí)數(shù)
此信息在運(yùn)行時(shí)通過 tx_byte_pool_performance_info_get和 tx_byte_pool_performance_system_info_get 服務(wù)提供。字節(jié)池性能信息在確定應(yīng)用程序是否正常運(yùn)行時(shí)非常有用。此信息對(duì)于優(yōu)化應(yīng)用程序也很有用。例如,“分配掛起數(shù)”相對(duì)較高可能表明字節(jié)池太小。
2.1.16 內(nèi)存字節(jié)池控制塊 TX_BYTE_POOL
每個(gè)內(nèi)存字節(jié)池的特征都可在其控制塊中找到。該控制塊包含諸如池中可用的字節(jié)數(shù)等有用的信息。此結(jié)構(gòu)在 tx_api.h 文件中定義。
池控制塊也可以位于內(nèi)存中的任意位置,但最常見的是通過在任何函數(shù)的作用域外部定義該控件塊來使其成為全局結(jié)構(gòu)。
2.1.17 非確定性行為
盡管內(nèi)存字節(jié)池提供了最靈活的內(nèi)存分配,但這些池也受一些非確定性行為的影響。例如,內(nèi)存字節(jié)池可能有 2,000 字節(jié)的可用內(nèi)存,但可能無法滿足 1,000 字節(jié)的分配請(qǐng)求。這是因?yàn)闊o法保證有多少可用字節(jié)是連續(xù)的。即使存在 1,000 字節(jié)可用塊,也不能保證找到此塊需要多長時(shí)間。完全有可能需要搜索整個(gè)內(nèi)存池來查找這個(gè) 1,000 字節(jié)塊。
由于內(nèi)存字節(jié)池的不確定性行為,通常應(yīng)避免在需要確定性實(shí)時(shí)行為的區(qū)域中使用內(nèi)存字節(jié)服務(wù)。許多應(yīng)用程序在初始化或運(yùn)行時(shí)配置期間預(yù)先分配其所需的內(nèi)存。
2.1.18 覆蓋內(nèi)存塊
務(wù)必確保已分配內(nèi)存的用戶不會(huì)在其邊界之外寫入。如果發(fā)生這種情況,則會(huì)損壞其相鄰的內(nèi)存區(qū)域(通常是后續(xù)區(qū)域)。結(jié)果不可預(yù)測,且對(duì)于程序執(zhí)行來說通常是災(zāi)難性的。
2.2 Azure ThreadX 動(dòng)態(tài)內(nèi)存管理的相關(guān)函數(shù)
tx_block_allocate分配固定大小的內(nèi)存塊
UINTtx_block_allocate( TX_BLOCK_POOL*pool_ptr, VOID**block_ptr, ULONGwait_option);
說明
此服務(wù)從指定的內(nèi)存池中分配固定大小的內(nèi)存塊。內(nèi)存塊的實(shí)際大小是在創(chuàng)建內(nèi)存池的過程中確定的參數(shù)。
pool_ptr:指向之前創(chuàng)建的內(nèi)存塊池的指針。
block_ptr:指向目標(biāo)塊指針的指針。成功分配時(shí),已分配內(nèi)存塊的地址就位于此參數(shù)所指向的位置。
wait_option:定義此服務(wù)在沒有可用的內(nèi)存塊時(shí)的行為方式。等待選項(xiàng)的定義如下:
TX_NO_WAIT (0x00000000)
如果選擇 TX_NO_WAIT,則無論此服務(wù)是否成功,都會(huì)導(dǎo)致立即從此服務(wù)返回 。如果從非線程(例如初始化、計(jì)時(shí)器或 ISR)調(diào)用服務(wù),則這是唯一有效的選項(xiàng)。
TX_WAIT_FOREVER (0xFFFFFFF)
選擇 TX_WAIT_FOREVER 會(huì)導(dǎo)致發(fā)出調(diào)用的線程無限期掛起,直到內(nèi)存塊可用為止 。
超時(shí)值(0x00000001 至 0xFFFFFFFE)
如果選擇一個(gè)數(shù)值(1 到 0xFFFFFFFE),則會(huì)指定在等待內(nèi)存塊時(shí)發(fā)出調(diào)用的線程保持掛起的最大計(jì)時(shí)器時(shí)鐘周期數(shù)。
返回值
TX_SUCCESS (0x00) 成功分配內(nèi)存塊。
TX_DELETED (0x01) 線程掛起時(shí)刪除了內(nèi)存塊池。
TX_NO_MEMORY (0x10) 服務(wù)無法在指定的等待時(shí)間內(nèi)分配內(nèi)存塊。
TX_WAIT_ABORTED (0x1A) 掛起狀態(tài)由其他線程、計(jì)時(shí)器或 ISR 中止。
TX_POOL_ERROR:(0x02) 內(nèi)存塊池指針無效。
TX_WAIT_ERROR:(0x04) 從非線程調(diào)用時(shí)指定了除 TX_NO_WAIT 以外的等待選項(xiàng)。
TX_PTR_ERROR:(0x03) 指向目標(biāo)指針的指針無效。
示例
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.*/
另請(qǐng)參閱
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 動(dòng)態(tài)內(nèi)存管理的應(yīng)用演示
2.3.1 工程目錄的建立
打開目標(biāo)工程文件夾“MM32F3270Project”:
移除原有樣例.c 文件sample_threadx.c:
參考sample_threadx.c建立main_malloc_demo.c文件,并添加hardware目錄中的led.c、key.c到工程項(xiàng)目中。
注意:
需要在delay.c中配置USE_SYSTICK_DELAY 為 0。
#define USE_SYSTICK_DELAY 0
3ThreadX 的內(nèi)存管理應(yīng)用
創(chuàng)建如下幾個(gè)任務(wù):
LED1閃爍指示當(dāng)前系統(tǒng)運(yùn)行。
按鍵(K1、K2、K3、K4)按下,對(duì)應(yīng)的事件標(biāo)志置位:
獲取事件標(biāo)志,執(zhí)行處理程序:
K1按下,從指定的內(nèi)存塊池中申請(qǐng)固定大小的內(nèi)存塊
K2按下,將以前分配的內(nèi)存塊釋放回其關(guān)聯(lián)的內(nèi)存池
K3按下,從指定的內(nèi)存字節(jié)池中分配指定的字節(jié)數(shù)
K4按下,將以前分配的內(nèi)存字節(jié)數(shù)釋放回其關(guān)聯(lián)的內(nèi)存池
打印內(nèi)存池信息
3.1 代碼實(shí)現(xiàn)
下載調(diào)試默認(rèn)會(huì)運(yùn)行到main()函數(shù),如下為全部實(shí)現(xiàn)的代碼。
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 下載與調(diào)試
運(yùn)行程序,板載LED1閃爍。觀察串口調(diào)試助手,依次按下K1、K2、K3、K4鍵,串口打印信息:
創(chuàng)建事件標(biāo)志組初始化為零,用于任務(wù)同步。任務(wù)5執(zhí)行按鍵掃描,當(dāng)按鍵按下時(shí)通過tx_event_flags_set設(shè)置事件標(biāo)志。任務(wù)1通過tx_event_flags_get用于檢索事件標(biāo)志,執(zhí)行對(duì)應(yīng)的處理程序,其中K1進(jìn)行內(nèi)存塊申請(qǐng),K2進(jìn)行內(nèi)存塊釋放,K3用于內(nèi)存字節(jié)申請(qǐng),K4用于內(nèi)存字節(jié)釋放,觀測串口打印信息,Demo演示成功。
按下K3從MyByte內(nèi)存池中申請(qǐng)分配了100個(gè)字節(jié),還有3980字節(jié)可用,而按下K4釋放后變成了4088字節(jié)可用,前后差值為108個(gè)字節(jié),為什么多了8個(gè)字節(jié)?感興趣的同學(xué)可以思考一下,找找答案!
4小結(jié)
Azure RTOS ThreadX提供內(nèi)存池能夠以快速且確定的方式分配內(nèi)存,結(jié)合MM32F3270的強(qiáng)大性能,可以實(shí)現(xiàn)Azure RTOS廣泛的應(yīng)用場景。
審核編輯:湯梓紅
-
threadx
+關(guān)注
關(guān)注
0文章
17瀏覽量
14063 -
RTOS
+關(guān)注
關(guān)注
24文章
851瀏覽量
121154 -
動(dòng)態(tài)內(nèi)存管理
+關(guān)注
關(guān)注
0文章
5瀏覽量
6678 -
Azure
+關(guān)注
關(guān)注
1文章
127瀏覽量
13312
原文標(biāo)題:靈動(dòng)微課堂 (第241講)|使用MM32F3270基于Azure RTOS動(dòng)態(tài)內(nèi)存管理的應(yīng)用
文章出處:【微信號(hào):MindMotion-MMCU,微信公眾號(hào):靈動(dòng)MM32MCU】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
使用MM32F3270基于Azure RTOS定時(shí)器組的應(yīng)用
MM32F3270系列32位MCU的特點(diǎn)有哪些
使用MM32F3270基于Azure RTOS定時(shí)器組的應(yīng)用
靈動(dòng)微電子MM32F3270系列MCU的特點(diǎn)介紹
基于MM32F3270 以太網(wǎng) Client使用

評(píng)論