RT-Thread學習筆記1-啟動順序與執行緒建立
阿新 • • 發佈:2021-02-17
[toc]
***
## 1. 啟動順序
1. SystemInit()
2. $Sub$$main()
3. rtthread_startup()
4. rt_application_init()
5. main_thread_entry
6. $Super$$main使用者主函式
## 2. 堆範圍
自由分配的記憶體(堆)起始地址為RAM的起始地址加上RW+ZI段後的地址區域。
編譯出的program size分為:
1. Code: 程式碼段,存放程式的程式碼部分
2. RO-data: 只讀資料段,存放程式中定義的常量
3. RW-data: 讀寫資料段,存放初始化為非0值的全域性變數
4. ZI-data: 0資料段,存放未初始化得全域性變數及初始化為0的變數
實際佔用空間情況為:
1. RO Size包含了Code及RO-data,表示程式佔用flash空間的大小
2. RW Size包含了RW-data及ZI-data,表示執行時佔用RAM的大小
3. ROM Size包含了Code, RO Data和RW data,表示燒寫程式佔用flash空間的大小
板子上電後預設從flash啟動,啟動之後會將RW段中的RW-data(初始化的全域性變數)搬運到RAM中,但不會搬運RO段,即CPU的執行程式碼從flash中讀取,另外根據編譯器給出的ZI地址和大小,分配出ZI段,並將這塊RAM區域清零。動態記憶體堆為未使用的RAM空間,應用程式申請和釋放的記憶體都來自該空間
[![BsntdH.png](https://s1.ax1x.com/2020/11/03/BsntdH.png)](https://imgchr.com/i/BsntdH)
```
char *ptr;
ptr = rt_malloc(10);
if (ptr != RT_NULL)
{
rt_memset(ptr, 0, 10);
rt_kprintf("malloc success\n");
rt_free(ptr);
ptr = RT_NULL;
}
```
## 3. 執行緒建立
RT-Thread中,執行緒由三部分組成:執行緒程式碼(入口函式)、執行緒控制塊、執行緒堆疊
### 3.1 執行緒程式碼(入口函式)
```
無限迴圈結構
void thread_entry(void *parameter)
{
while(1)
{
/* 等待事件發生 */
/* 處理事件 */
}
}
順序執行結構
void thread_entry(void *parameter)
{
/* 事務1處理 */
/* 事務2處理 */
/* 事務3處理 */
}
```
### 3.2 執行緒控制塊
作業系統管理執行緒的一個數據結構。存放執行緒的一些資訊,比如優先順序、執行緒名稱、執行緒狀態等等,也包括執行緒與執行緒之間連線用的連結串列結構,執行緒等待時間集合等
```
struct rt_thread;
struct rt_thread *rt_thread_t;
```
### 3.3 執行緒棧
每個執行緒都有獨立的棧空間,執行緒切換時,系統會將當前執行緒的上下文儲存線上程棧中,當執行緒要恢復執行時,再從執行緒棧中讀取上下文資訊,恢復執行緒的執行。執行緒上下文是指執行緒執行時的環境,各個變數和資料包括所有的暫存器變數,堆疊資訊,記憶體資訊等。執行緒棧在形式上是一段連續的記憶體空間,可以通過定義一個數組或者申請一段動態記憶體來作為執行緒的棧
建立執行緒:
```
建立靜態執行緒
rt_err_t rt_thread_init(struct rt_thread *thread,
const char *name,
void (*entry)(void *parameter),
void *parameter,
void *stack_start,
rt_uint32_t stack_size,
rt_uint8_t priority,
rt_uint32_t tick)
建立動態執行緒
rt_thread_t rt_thread_create(const char *name,
void (*entry(void *parameter),
void *parameter,
rt_uint32_t stack_size,
rt_uint8_t priority,
rt_uint32_t tick))
啟動執行緒
rt_err_t rt_thread_startup(rt_thread_t thread)
呼叫此函式後建立的執行緒會被加入到執行緒的就緒佇列,執行排程
rt_err_t thread_static_init()
{
rt_err_t result;
result = rt_thread_init(&thread,
"test",
thread_entry, RT_NULL,
&thread_stack[0], sizeof(thread_stack),
THREAD_PRIORITY, 10);
if (result == RT_EOK)
rt_thread_startup(&thread);
else
tc_stat(TC_STAT_END | TC_STAT_FAILED);
return result;
}
int thread_dynamic_init()
{
rt_thread_t tid;
tid = rt_thread_create("test",
thread_entry, RT_NULL,
THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
if (tid != RT_NULL)
rt_thread_startup(tid);
else
tc_stat(TC_STAT_END | TC_STAT_FAILED);
return 0;
}
rt_thread_delay(15); // 根據時鐘頻率決定。時鐘頻率100HZ,那麼一次delay 10ms.此處就未150ms
rt_thread_sleep(15);
rt_thread_mdelay(15); // delay 15ms
```
區別:
1. 資源分配形式不同:靜態執行緒的執行緒控制塊和執行緒棧是靜態分配的,而動態執行緒的這兩部分是執行時動態分配的
2. 執行效率:如果堆空間是片外RAM,那麼動態執行緒的執行效率低於靜態執行緒。反之,如果都是片內RAM,則沒有差別
## 4. 系統滴答時鐘
心跳時鐘由硬體定時器的定時中斷產生。稱之為系統滴答或者時鐘節拍。其頻率需要根據CPU的處理能力來決定。始終街拍使得核心可以將執行緒延時若干個時鐘節拍,以及執行緒等待時間發生時,超時的依據。頻率越快,核心函式介入系統執行的概率越大,核心佔用的處理器時間就越長,系統的負荷就越大。頻率越小,時間處理精度又不夠。在stm32平臺上一般設定系統滴答頻率為100HZ,即每個滴答的時間是10ms。在rtconfig.h中的RT_TICK_PER_SECOND巨集,就是代表的HZ數
## 5. GPIO驅動架構操作IO
```
#