Ucos II 記憶體管理
在mcu21的項目裡,暫時還沒用到記憶體管理。不過還是有必要學習一下的。
為了消除記憶體片段,ucos II 把連續的大塊記憶體按分區來管理。每個分區中包含有整數個大小相同的記憶體塊。
類似每個任務對應一個任務控制塊,每個事件對應一個事件控制塊,ucos II裡每個記憶體塊也是對應一個記憶體控制塊。記憶體控制塊是一個資料結構,定義如下:
typedef struct { void *OSMemAddr; void *OSMemFreeList; INT32U OSMemBlkSize; INT32U OSMemNBlks; INT32U OSMemNFree;} OS_MEM; typedef struct { void *OSMemAddr; void *OSMemFreeList; INT32U OSMemBlkSize; INT32U OSMemNBlks; INT32U OSMemNFree;} OS_MEM;
.OSMemAddr是指向記憶體分區起始地址的指標。它在建立記憶體分區OSMemCreate()時被初始化,在此之後就不能更改了。
.OSMemFreeList是指向下一個空閑記憶體控制塊或者下一個閒置記憶體塊的指標,具體含義要根據該記憶體分區是否已經建立來決定。
.OSMemBlkSize是記憶體分區中記憶體塊的大小,是使用者建立該記憶體分區時指定的。
.OSMemNBlks是記憶體分區中總的記憶體塊數量,也是使用者建立該記憶體分區時指定的。
.OSMemNFree是記憶體分區中當前可以得空閑記憶體塊數量。
完整地使用記憶體,需要經過以下步驟:
1. 建立一個記憶體分區(OSMemCreate())
2. 調用OSMemGet()函數從已經建立的記憶體分區中申請記憶體塊
3. 當使用者應用程式不再使用一個記憶體塊時,調用OSMemPut()釋放記憶體。
4. 在這過程中可以調用OSMemQuery()查詢一個記憶體分區的狀態
建立一個記憶體分區需要使用ucos II 系統函數OSMemCreate()。實現過程如下:
OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err){ OS_MEM *pmem; INT8U *pblk; void **plink; INT32U i; if (nblks < 2) { (1) *err = OS_MEM_INVALID_BLKS; return ((OS_MEM *)0); } if (blksize < sizeof(void *)) { (2) *err = OS_MEM_INVALID_SIZE; return ((OS_MEM *)0); } OS_ENTER_CRITICAL(); pmem = OSMemFreeList; (3) if (OSMemFreeList != (OS_MEM *)0) { OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList; } OS_EXIT_CRITICAL(); if (pmem == (OS_MEM *)0) { (4) *err = OS_MEM_INVALID_PART; return ((OS_MEM *)0); } plink = (void **)addr; (5) pblk = (INT8U *)addr + blksize; for (i = 0; i < (nblks - 1); i++) { *plink = (void *)pblk; plink = (void **)pblk; pblk = pblk + blksize; } *plink = (void *)0; OS_ENTER_CRITICAL(); pmem->OSMemAddr = addr; (6) pmem->OSMemFreeList = addr; pmem->OSMemNFree = nblks; pmem->OSMemNBlks = nblks; pmem->OSMemBlkSize = blksize; OS_EXIT_CRITICAL(); *err = OS_NO_ERR; return (pmem); (7)
該函數共有4個參數:記憶體分區的起始地址、分區內的記憶體塊總塊數、每個記憶體塊的位元組數和一個指向錯誤資訊代碼的指標。如果OSMemCreate()操作失敗,它將返回一個NULL指標。否則,它將返回一個指向記憶體控制塊的指標。對記憶體管理的其它操作,象OSMemGet(),OSMemPut(),OSMemQuery()函數等,都要通過該指標進行。
在mcu21的理解中,以上程式,簡單來說,主要執行以下兩大步驟,一是從空閑記憶體控制塊中擷取一個記憶體控制塊,二是初始化這塊記憶體控制塊。