• 正文
    • 1、FreeRTOS-generic
    • 2、FreeRTOS-外設
  • 相關推薦
申請入駐 產業(yè)圖譜

飛凌嵌入式 基于i.MX9352開發(fā)板M核的FreeRTOS設計例程

06/13 16:19
176
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

嵌入式系統(tǒng)領域,嵌入式實時操作系統(tǒng)(RTOS) 的應用正日益廣泛,采用RTOS能夠更合理、更高效地利用CPU資源,F(xiàn)reeRTOS作為一款輕量級且成熟的實時操作系統(tǒng)內核,其核心功能完備,包括任務管理、時間管理(如延時、定時器)、同步機制(信號量、互斥鎖)、進程間通信(消息隊列)等等。這些特性使其能夠很好地滿足資源相對有限的中小型嵌入式系統(tǒng)的需求。

i.MX 9352作為NXP 推出的新一代輕量級邊緣AI處理器,集成2個Cortex-A55核和1個Cortex-M33實時核,其架構設計充分體現(xiàn)了對實時性與復雜任務處理能力的兼顧。為了幫助開發(fā)者充分利用i.MX 9352 M33核的實時能力,其配套的M核SDK包提供的FreeRTOS例程分為兩類,一類介紹FreeRTOS系統(tǒng)組件特性,如信號量、互斥量、隊列等,另一類是介紹外設接口如何在FreeRTOS使用,我們分別挑選這兩類下的例程進行演示。

1、FreeRTOS-generic

飛凌嵌入式OK-MX9352-C開發(fā)板支持FreeRTOS功能特性示例代碼如下:

-freertos_event:任務事件演示例程

-freertos_queue:隊列消息實現(xiàn)任務間通信的演示例程

-freertos_mutex:互斥鎖使用例程

-freertos_sem:信號量使用例程

-freertos_swtimer:軟件計數器及其回調的用法。

-freertos_tickless:使用 LPTMR 延時喚醒或者硬件中斷喚醒例程

-freertos_generic:task、queue、swtimer、tick hook 、semaphore 組合利用演示例程。

因FreeRTOS_generic例程使用的FreeRTOS特性較多,我們重點分析此例程。

(1)軟件實現(xiàn)

示例程序內容包括:任務創(chuàng)建、隊列、軟定時器、系統(tǒng)節(jié)拍時鐘、信號量、異常處理。具體如下:

任務創(chuàng)建:

主函數創(chuàng)建了隊列發(fā)送、接收,信號量三個任務。

//  創(chuàng)建隊列接收任務
if(xTaskCreate(prvQueueReceiveTask,"Rx",configMINIMAL_STACK_SIZE+166,NULL,mainQUEUE_RECEIVE_TASK_PRIORITY,NULL)!=pdPASS)
// 創(chuàng)建隊列發(fā)送任務
if(xTaskCreate(prvQueueSendTask,"TX",configMINIMAL_STACK_SIZE+166, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL) !=pdPASS)
// 創(chuàng)建信號量任務
if(xTaskCreate(prvEventSemaphoreTask,"Sem",configMINIMAL_STACK_SIZE+166,NULL,mainEVENT_SEMAPHORE_TASK_PRIORITY, NULL) != pdPASS)

隊列:

隊列發(fā)送任務,阻塞200ms后向隊列發(fā)送數據;隊列接收任務,任務阻塞讀取隊列,數據讀取正確,則打印此時的隊列接收數量。

// 隊列發(fā)送任務,阻塞200ms后 向隊列發(fā)送數據 
static void prvQueueSendTask(void *pvParameters)  
{  
    TickType_t xNextWakeTime;  
    const uint32_t ulValueToSend = 100UL;  
    xNextWakeTime = xTaskGetTickCount();  
    for (;;)  
    {  
        // 任務阻塞,直至200ms延時結束  
        vTaskDelayUntil(&xNextWakeTime, mainQUEUE_SEND_PERIOD_MS);  
        // 向隊列發(fā)送數據,阻塞時間為0表示當隊列滿的時候就立即返回  
        xQueueSend(xQueue, &ulValueToSend, 0);  
    }  
} 
// 隊列接收任務,任務阻塞讀取隊列,數據讀取正確,則打印此時的隊列接收數量。
static void prvQueueReceiveTask(void *pvParameters)  
{  
    uint32_t ulReceivedValue;  
    for (;;)  
    {  
        // 任務一直阻塞,知道隊列內讀取到數據  
        xQueueReceive(xQueue, &ulReceivedValue, portMAX_DELAY);  
        //  隊列數據和發(fā)送一致,隊列接收數量+1 輸出此時的隊列接收數量  
        if (ulReceivedValue == 100UL)  
        {  
            ulCountOfItemsReceivedOnQueue++;  
            PRINTF("Receive message counter: %d.rn", ulCountOfItemsReceivedOnQueue);  
        }  
    }  
}  

軟定時器:

設置軟定時器周期1s,時間到后,調用回調函數,記錄次數并串口打印。

// 創(chuàng)建軟件定時器任務 時間為1s,周期循環(huán)  
xExampleSoftwareTimer = xTimerCreate(  
                                     "LEDTimer",  
                                     mainSOFTWARE_TIMER_PERIOD_MS,  
                                     pdTRUE,  
                                     (void *)0,  
                                     vExampleTimerCallback);  
// 啟動軟件定時器  
xTimerStart(xExampleSoftwareTimer, 0); 
   // 回調函數
static void vExampleTimerCallback(TimerHandle_t xTimer)  
{  
    // 每1s進入一次回調函數,計數增加  
    ulCountOfTimerCallbackExecutions++;  
    PRINTF("Soft timer: %d s.rn", ulCountOfTimerCallbackExecutions);  
}

系統(tǒng)節(jié)拍時鐘:

通過設置文件 FreeRTOSConfig.h 中 configTICK_RATE_HZ 設置任務節(jié)拍中斷頻率, 在啟動任務調度器時,系統(tǒng)會根據另一個變量CPU的頻率configCPU_CLOCK_HZ計算對應寫入節(jié)拍計數器的值,啟動定時器中斷。

// 設置系統(tǒng)時鐘節(jié)拍為 1000/200=5ms  
#define configTICK_RATE_HZ                      ((TickType_t)200)

信號量:

每個系統(tǒng)節(jié)拍時鐘中斷中,調用函數vApplicationTickHook,累積500次即500*5ms=2.5s后,發(fā)送信號量。信號量任務獲取信號后,計數并打印累積次數。

// 系統(tǒng)節(jié)拍為5ms,每個500*5ms=2.5s 釋放事件信號量  
void vApplicationTickHook(void)  
{  
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;  
    static uint32_t ulCount             = 0;  
    ulCount++;  
    if (ulCount >= 500UL)  
    {  
        // 在中斷中釋放事件信號量  
        xSemaphoreGiveFromISR(xEventSemaphore, &xHigherPriorityTaskWoken);  
        ulCount = 0UL;  
    }  
} 
// 任務阻塞等待信號量,收到后,接收次數增加,并通過串口打印  
static void prvEventSemaphoreTask(void *pvParameters)  
{  
    for (;;)  
    {  
        // 任務阻塞,直到能獲取信號量  
        if (xSemaphoreTake(xEventSemaphore, portMAX_DELAY) != pdTRUE)  
        {  
            PRINTF("Failed to take semaphore.rn");  
        }  
        // 接收到信號量的次數累加  
        ulCountOfReceivedSemaphores++;  
        PRINTF("Event task is running. Get semaphore :%d rn",ulCountOfReceivedSemaphores);  
    }  
}  

異常處理:

當內存分配失敗、堆棧發(fā)生錯誤或任務空閑時,進入相應的函數,用戶可添加相應的處理函數。

// 內存分配失敗函數,當內存分配失敗時,進入此函數  
void vApplicationMallocFailedHook(void)  
{  
    for (;;)  
        ;  
}
// 堆棧錯誤檢查函數,當堆棧發(fā)生溢出時,進入此函數  
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)  
{  
    (void)pcTaskName;  
    (void)xTask;  
    for (;;)  
        ;  
}  
// 空閑任務,優(yōu)先級最低,沒有實際意義,只是讓CPU有事情做,用戶可以自己添加自己的函數  
void vApplicationIdleHook(void)  
{  
    volatile size_t xFreeStackSpace;  
    xFreeStackSpace = xPortGetFreeHeapSize();  
    if (xFreeStackSpace > 100)  
    {  
    }  
}  

(2)實驗現(xiàn)象

① 編譯程序:在uboot手動加載M核程序。

② 隊列:每隔200ms,隊列發(fā)送任務發(fā)送數據,隊列接收任務獲取數據,從阻塞態(tài)到運行態(tài),打印計數。

③ 軟定時器:每隔1s,時間到達,調用回調函數,打印計數。

④ 信號量:每隔5ms,系統(tǒng)時鐘節(jié)拍中斷調用函數,超過500次后,釋放信號量。信號量任務獲的信號量,從阻塞態(tài)到運行態(tài),打印計數。

2、FreeRTOS-外設

飛凌嵌入式OK-MX9352-C開發(fā)板支持外設使用FreeRTOS完成相應功能,示例代碼如下:

-freertos_uart:freertos串口演示例程

-freertos_lpi2c_b2b:freertos I2C演示例程

-freertos_lpspi_b2b:freertos SPI演示例程

因freertos_uart例程使用的FreeRTOS特性比較典型,我們重點分析此例程。

(1)軟件實現(xiàn)

示例程序內容包括:串口初始化任務、串口發(fā)送任務、串口接收任務。具體如下:

串口初始化任務:

主要包含串口外設初始化,發(fā)送、接收互斥量,發(fā)送和接收事件組。串口外設初始化在裸跑串口例程中已展現(xiàn),此處不再詳述。

//  創(chuàng)建串口發(fā)送互斥量
handle->txSemaphore = xSemaphoreCreateMutex();
//  創(chuàng)建串口接收互斥量
handle->rxSemaphore = xSemaphoreCreateMutex(); 
// 創(chuàng)建發(fā)送事件標志組
handle->txEvent     = xEventGroupCreate();
// 創(chuàng)建接收事件標志組
handle->rxEvent     = xEventGroupCreate();

串口發(fā)送:

發(fā)送前獲取信號量,啟動發(fā)送流程,在中斷中置位發(fā)送完成事件標志。發(fā)送任務獲取到事件后,釋放發(fā)送信號量。

// 1 獲取發(fā)送信號量  
if (pdFALSE == xSemaphoreTake(handle->txSemaphore, 0))   
{  
    return kStatus_Fail;  
}  
handle->txTransfer.data     = (uint8_t *)buffer;  
handle->txTransfer.dataSize = (uint32_t)length;  
// 2 阻塞式發(fā)送  
status = UART_TransferSendNonBlocking(handle->base, handle->t_state, &handle->txTransfer);  
if (status != kStatus_Success)  
{  
    (void)xSemaphoreGive(handle->txSemaphore);   
    return kStatus_Fail;  
}  
// 3 等待發(fā)送完成的事件  
ev = xEventGroupWaitBits(handle->txEvent, RTOS_UART_COMPLETE, pdTRUE, pdFALSE, portMAX_DELAY);// 等待并判斷多個事件位  
if ((ev & RTOS_UART_COMPLETE) == 0U)  
{  
    retval = kStatus_Fail;  
}  
// 4 發(fā)送完成,釋放發(fā)送信號量  
if (pdFALSE == xSemaphoreGive(handle->txSemaphore)) // 釋放信號量  
{  
    retval = kStatus_Fail;  
}

串口接收:

接收前獲取信號量,調用串口接收函數,在中斷中置位獲取事件標志。接收任務獲取到事件后,釋放接收信號量。

// 1獲取接收信號量  
if (pdFALSE == xSemaphoreTake(handle->rxSemaphore, portMAX_DELAY))    
{  
    return kStatus_Fail;  
}  
handle->rxTransfer.data     = buffer;  
handle->rxTransfer.dataSize = (uint32_t)length;  
// 2 串口接收函數  
status = UART_TransferReceiveNonBlocking(handle->base, handle->t_state, &handle->rxTransfer, &n);  
if (status != kStatus_Success)  
{  
    (void)xSemaphoreGive(handle->rxSemaphore);   
    return kStatus_Fail;  
}  
// 3 獲取接收事件  
ev = xEventGroupWaitBits(handle->rxEvent,RTOS_UART_COMPLETE | RTOS_UART_RING_BUFFER_OVERRUN | RTOS_UART_HARDWARE_BUFFER_OVERRUN, pdTRUE, pdFALSE, portMAX_DELAY);   // 等待并判斷接收完成事件位  
// 3.1 硬件接收錯誤  
if ((ev & RTOS_UART_HARDWARE_BUFFER_OVERRUN) != 0U)   
{  
    UART_TransferAbortReceive(handle->base, handle->t_state);  
    (void)xEventGroupClearBits(handle->rxEvent, RTOS_UART_COMPLETE);    // 將接收完成的事件位清零,  
    retval         = kStatus_UART_RxHardwareOverrun;  
    local_received = 0;  
}  
// 3.2 接收緩沖區(qū)過載錯誤  
else if ((ev & RTOS_UART_RING_BUFFER_OVERRUN) != 0U)   
{  
    UART_TransferAbortReceive(handle->base, handle->t_state);  
    (void)xEventGroupClearBits(handle->rxEvent, RTOS_UART_COMPLETE);    // 將接收完成的事件位清零,  
    retval         = kStatus_UART_RxRingBufferOverrun;  
    local_received = 0;  
}  
// 3.3 接收完成  
else if ((ev & RTOS_UART_COMPLETE) != 0U)     
{  
    retval         = kStatus_Success;  
    local_received = length;  
}  
else  
{  
    retval         = kStatus_UART_Error;  
    local_received = 0;  
}  
// 4 釋放接收信號量  
if (pdFALSE == xSemaphoreGive(handle->rxSemaphore))   
{  
    retval = kStatus_Fail;  
} 

(2)實驗現(xiàn)象

① 編譯程序,在uboot手動加載M核程序。

② 裝置上電后,串口打印程序信息,此時通過鍵盤輸入4個字符,M核調試串口將回顯,重復輸入和回顯字符,證明程序運行成功。

以上就是在飛凌嵌入式i.MX 9352開發(fā)板M核上軟件設計FreeRTOS的例程演示,希望能夠對各位工程師朋友有所幫助。

飛凌嵌入式

飛凌嵌入式

保定飛凌嵌入式技術有限公司,創(chuàng)建于2006年,是一家專注嵌入式核心控制系統(tǒng)研發(fā)、設計和生產的高新技術企業(yè),是國內較早專業(yè)從事嵌入式技術的企業(yè)之一。 經過十幾年的發(fā)展與積累,公司擁有業(yè)內優(yōu)秀的軟硬件研發(fā)團隊,在北京及保定建立兩大研發(fā)基地,在蘇州、深圳設有華東、華南技術服務中心,并在北美、歐洲以及亞太等其他國家和地區(qū)擁有國際業(yè)務網絡。公司研發(fā)的智能設備核心平臺廣泛應用于物聯(lián)網、工控、軌道交通、醫(yī)療、電力、商業(yè)電子、智能家居、安防、機器人、環(huán)境監(jiān)測等諸多領域。

保定飛凌嵌入式技術有限公司,創(chuàng)建于2006年,是一家專注嵌入式核心控制系統(tǒng)研發(fā)、設計和生產的高新技術企業(yè),是國內較早專業(yè)從事嵌入式技術的企業(yè)之一。 經過十幾年的發(fā)展與積累,公司擁有業(yè)內優(yōu)秀的軟硬件研發(fā)團隊,在北京及保定建立兩大研發(fā)基地,在蘇州、深圳設有華東、華南技術服務中心,并在北美、歐洲以及亞太等其他國家和地區(qū)擁有國際業(yè)務網絡。公司研發(fā)的智能設備核心平臺廣泛應用于物聯(lián)網、工控、軌道交通、醫(yī)療、電力、商業(yè)電子、智能家居、安防、機器人、環(huán)境監(jiān)測等諸多領域。收起

查看更多

相關推薦

登錄即可解鎖
  • 海量技術文章
  • 設計資源下載
  • 產業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄

秉承專業(yè)態(tài)度,專注智能設備核心平臺研發(fā)與制造,以技術研發(fā)創(chuàng)新為主導,以客戶實用化,產品化為目標,把握嵌入式行業(yè)的前沿發(fā)展需求,利用核心技術為客戶提供穩(wěn)定、可靠、功能優(yōu)異的高品質產品。合作聯(lián)系:17713286011