3. FreeRTOS システムのソースコード移植

目次

1. FreeRTOS ソースコードを入手する

2. FreeRTOS システムのソースコードの内容

3. FreeRTOS システムのソースコード移植

1. FreeRTOS ソースコードを入手する

FreeRTOS 公式 Web サイトにアクセスしてください: https://www.freertos.org/

ここで主に提供するのは、FreeRTOS の V10.4.6 バージョンです。

1. 公式 Web サイトにアクセスし、「FreeRTOS をダウンロード」をクリックします。

2. 「ダウンロード」をクリックします。

2. FreeRTOS システムのソースコードの内容

 私たちと密接に関係しているのは FreeRTOS カーネルです。freeRTOS システム カーネル フォルダーを開きます。

 各フォルダの中身は、

名前 説明する
デモ FreeRTOS デモ ルーチン
ライセンス FreeRTOS に関連するライセンス
ソース FreeRTOS ソースコード
テスト 共通および移植層のテストコード

デモフォルダー

        Demo フォルダーには、F1、F4、F7 などのさまざまなチップ アーキテクチャをサポートする FreeRTOS のデモンストレーション ルーチンがあり、デモンストレーションが動作します。

ソースフォルダー 

        Source フォルダーはソース コードのインスタンスです。

 次に、各ファイルの意味を見てみましょう。

名前 説明する
含む FreeRTOS のヘッダー ファイルが含まれています
ポータブル FreeRTOS 用の移植ファイルが含まれています
クロイチン.c コルーチン関連ファイル
イベントグループ.c イベント関連書類
list.c 関連ファイルをリストする
tail.c キュー関連ファイル
ストリームバッファ.c ストリームバッファ関連ファイル
タスク.c ソフトウェア関連ドキュメント
タイマー.c ソフトウェアタイマー関連資料

太字の赤色のものは追加する必要があり、その他は必要に応じて使用するかどうかを選択できます。

ポータブルフォルダー

        結局のところ、FreeRTOS オペレーティング システムはソフトウェア レベルのものですが、FreeRTOS はハードウェアとどのように連携するのでしょうか?

        ポータブルフォルダーの中のものは橋です

開発には MDK を使用するため、ここではいくつかの移行ファイルの紹介に焦点を当てます。

名前 説明する
ケイル RBDSフォルダーをポイントします
RVDS 異なるコアチップ用の移行ファイル
メンマン メモリ管理ファイル

3. FreeRTOS システムのソースコード移植

移植の準備:

1.FreeRTOS ソースコード

2.基礎工学

移行手順:

1. 基本プロジェクト、ヘッダーファイルのパスなどにFreeRTOSのソースコードを追加(add FreeRTOS)のソースコードを追加します。

2. FreeRTOSConfig、FreeRTOSconfig.h 構成ファイルを追加します。

3. SYSTEM ファイルを変更し、SYSTEM ファイル内の sys.c、delay.c、usart.c を変更します。

4. 割り込み関連ファイルを変更し、Systick 割り込み、SVC 割り込み、PendSV 割り込みを変更します。

5. アプリケーションプログラムを追加し、移植が成功したかどうかを確認します。

移植を開始します。

1. FreeRTOS ソースコードを追加する

        次の図に示すように、基本プロジェクトの Middlewares フォルダーに新しい FreeRTOS サブフォルダーを作成します。

         次に、新しく作成した FreeRTOS サブファイルに FreeRTOS のソース コードを追加する必要があります。次の図に示すように、FreeRTOS カーネル ソース コードの Source フォルダーにあるすべてのファイルをプロジェクトの FreeRTOS フォルダーに追加します。

          このうち、先ほど紹介したポータブルなファイルは実際に使用されるファイルは 3 つだけで、その他の未使用ファイルは削除できます。

         MemMang では、これはメモリ管理アルゴリズムです。実際には、アルゴリズム 4 のみ、つまり heap_4.c のみを使用します。RVDS はソフトウェアとハ​​ードウェアの間のブリッジです。カーネルが異なれば、ファイルも異なります。

2. ファイルをプロジェクトに追加します

        プロジェクトを開き、次の図に示すように、Middlewares/FreeRTOS_CORE と Middlewares/FreeRTOS_PORT という 2 つの新しいファイル グループを作成します。

        カーネルの C ソース コードを Middlewares/FreeRTOS_CORE に追加し、FreeRTOS カーネルの移行ファイルを保存するために Middlewares/FreeRTOS_PORT グループを使用します。2 つのファイル (heap_x.c と port.c) をこのグループに追加する必要があります。 。開発ボードが異なれば、移植する port.c フォルダーも異なります。

STM32シリーズ開発ボードタイプ port.c が置かれているフォルダー
STM32F1 ARM_CM3
STM32F4 ARM_CM4F
STM32F7 ARM_CM7/r0p1
STM32H7 ARM_CM7/r0p1

        追加後は、次の図のようになります。

3. ヘッダーファイルのパスを追加します

        合計 2 つのヘッダー ファイルを追加する必要があります。1 つは FreeRTOS システムのインクルード ヘッダー ファイル、もう 1 つはハードウェア接続のヘッダー ファイルです。追加後のパスは次の図に示されます。

 4. FreeRTOSConfig.h ファイルを追加します。

       FreeRTOSConfig.h は FreeRTOS オペレーティング システムの構成ファイルです。FreeRTOS オペレーティング システムはトリミング可能です。ユーザーは必要に応じて FreeRTOS をトリミングしたり、FreeRTOS を必要としない機能をトリミングしたりして、MCU のメモリ リソースを節約できます。 。

5.SYSTEMファイルを変更する

        sys.h、delay.h、usart.hをそれぞれ修正します。

5.1、sys.h

        #define SYS_SUPPORT_OS 1 の 1 を 0 に変更します。

/**
 * SYS_SUPPORT_OS用于定义系统文件夹是否支持OS
 * 0,不支持OS
 * 1,支持OS
 */
#define SYS_SUPPORT_OS         1

5.2、usart.c

        usart.c ファイルの変更も非常に簡単です。変更する必要がある箇所は 2 か所あります。1 つはシリアル ポートの割り込みサービス関数です。μC/OS を使用する場合は、OSIntEnter() と OSIntExit() を変更する必要があります。これは、µC/OS の割り込み関連の処理メカニズムですが、FreeRTOS にはそのようなメカニズムがないため、この 2 行のコードが削除され、修正された割り込みサービス関数が追加されます。シリアルポートは次のとおりです。

/**
 * @brief       串口1中断服务函数
 * @param       无
 * @retval      无
 */
void USART_UX_IRQHandler(void)
{ 
    uint32_t timeout = 0;
    uint32_t maxDelay = 0x1FFFF;
  
    HAL_UART_IRQHandler(&g_uart1_handle);       /* 调用HAL库中断处理公用函数 */

    timeout = 0;
    while (HAL_UART_GetState(&g_uart1_handle) != HAL_UART_STATE_READY) /* 等待就绪 */
    {
        timeout++;                              /* 超时处理 */
        if(timeout > maxDelay)
        {
            break;
        }
    }
     
    timeout=0;
    
    /* 一次处理完成之后,重新开启中断并设置RxXferCount为1 */
    while (HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE) != HAL_OK)
    {
        timeout++;                              /* 超时处理 */
        if (timeout > maxDelay)
        {
            break;
        }
    }

}

#endif

        次に、usart.c を変更する 2 番目の場所は、インポートされたヘッダー ファイルです。これは、シリアル ポートの割り込みサービス関数で µC/OS の関連コードが削除されており、FreeRTOS の関連コードが使用されていないためです。 usart.cに含まれるOSに関するヘッダファイルを削除しますが、削除するコードは以下のとおりです。

/* 如果使用os,则包括下面的头文件即可 */
#if SYS_SUPPORT_OS
#include "os.h"                               /* os 使用 */
#endif

5.3、遅延.c

        次に、SYSTEM フォルダ内の最後のファイル、delay.c を変更します。delay.c ファイルは大幅に変更する必要があり、大きく 3 つのステップに分けることができます: µC/OS に適用できるが適用できない関連コードを削除します。 FreeRTOS に、FreeRTOS の関連コードを追加し、一部の内容を変更します。

(1) µC/OS では動作するが FreeRTOS では動作しない関連コードを削除します。

        グローバル変数 1 個、マクロ定義 6 個、関数 3 個の合計を削除する必要があります。これらの削除コードは µC/OS を使用する場合に使用しますが、FreeRTOS を使用する場合は使用する必要はありません。以下の通り:

static uint32_t g_fac_us = 0;       /* us延时倍乘数 */

/* 如果SYS_SUPPORT_OS定义了,说明要支持OS了(不限于UCOS) */
#if SYS_SUPPORT_OS

/* 添加公共头文件 ( ucos需要用到) */
#include "os.h"

/* 定义g_fac_ms变量, 表示ms延时的倍乘数, 代表每个节拍的ms数, (仅在使能os的时候,需要用到) */
static uint16_t g_fac_ms = 0;

/*
 *  当delay_us/delay_ms需要支持OS的时候需要三个与OS相关的宏定义和函数来支持
 *  首先是3个宏定义:
 *      delay_osrunning    :用于表示OS当前是否正在运行,以决定是否可以使用相关函数
 *      delay_ostickspersec:用于表示OS设定的时钟节拍,delay_init将根据这个参数来初始化systick
 *      delay_osintnesting :用于表示OS中断嵌套级别,因为中断里面不可以调度,delay_ms使用该参数来决定如何运行
 *  然后是3个函数:
 *      delay_osschedlock  :用于锁定OS任务调度,禁止调度
 *      delay_osschedunlock:用于解锁OS任务调度,重新开启调度
 *      delay_ostimedly    :用于OS延时,可以引起任务调度.
 *
 *  本例程仅作UCOSII的支持,其他OS,请自行参考着移植
 */

/* 支持UCOSII */
#define delay_osrunning     OSRunning           /* OS是否运行标记,0,不运行;1,在运行 */
#define delay_ostickspersec OS_TICKS_PER_SEC    /* OS时钟节拍,即每秒调度次数 */
#define delay_osintnesting  OSIntNesting        /* 中断嵌套级别,即中断嵌套次数 */


/**
 * @brief     us级延时时,关闭任务调度(防止打断us级延迟)
 * @param     无
 * @retval    无
 */
void delay_osschedlock(void)
{
    OSSchedLock();                      /* UCOSII的方式,禁止调度,防止打断us延时 */
}

/**
 * @brief     us级延时时,恢复任务调度
 * @param     无
 * @retval    无
 */
void delay_osschedunlock(void)
{
    OSSchedUnlock();                    /* UCOSII的方式,恢复调度 */
}

/**
 * @brief     us级延时时,恢复任务调度
 * @param     ticks: 延时的节拍数
 * @retval    无
 */
void delay_ostimedly(uint32_t ticks)
{
    OSTimeDly(ticks);                               /* UCOSII延时 */
}

/**
 * @brief     systick中断服务函数,使用OS时用到
 * @param     ticks : 延时的节拍数  
 * @retval    无
 */  
void SysTick_Handler(void)
{
    /* OS 开始跑了,才执行正常的调度处理 */
    if (delay_osrunning == OS_TRUE)
    {
        /* 调用 uC/OS-II 的 SysTick 中断服务函数 */
        OS_CPU_SysTickHandler();
    }
    HAL_IncTick();
}
#endif

(2) FreeRTOSの関連コードを追加

        extern キーワードを使用して、FreeRTOS 関数 —— xPortSysTickHandler() を遅延.c ファイルにインポートします。この関数は、FreeRTOS システム クロック ビートの処理に使用されます。このチュートリアルでは、FreeRTOS オペレーティング システムのハートビートとして SysTick を使用するため、この関数は SysTick 割り込みサービス関数内で呼び出すため、SysTick 割り込みサービス関数の前にコードを追加し、コードを次のように変更します。

void SysTick_Handler(void)
{
   代码省略
}
#endif

(3) 内容の一部を修正する場合

        最後に変更するものには、ヘッダー ファイルと 4 つの関数の 2 つが含まれます。まず、変更する必要がある 4 つの関数、つまり SysTick_Handler()、lay_init()、lay_us()、および late_ms() を確認します。

(a) SysTick_Handler()

        この関数は SysTick の割り込みサービス関数です。この関数では、前の手順でインポートした関数 xPortSysTickHandler() を繰り返し呼び出す必要があります。変更されたコードは次のとおりです。

/**
 * @brief     systick中断服务函数,使用OS时用到
 * @param     ticks: 延时的节拍数
 * @retval    无
 */  
void SysTick_Handler(void)
{
    HAL_IncTick();
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) /* OS开始跑了,才执行正常的调度处理 */
    {
        xPortSysTickHandler();
    }
}

 (b) 遅延初期化()

         関数 late_init() は主に SysTick を初期化するために使用されます。ここで説明しなければならないのは、関数 vTaskStartScheduler() がその後呼び出されるとき (この関数は、以下の FreeRTOS タスク スケジューラを説明するときに詳細に分析されます)、FreeRTOS は FreeRTOSConfig.h ファイルの構成に従って SysTick を初期化するため、delay_init ( ) 初期化された関数 SysTick は主に FreeRTOS がタスク スケジューリングを開始する前に使用されます。関数遅延_init()の修正箇所は主にSysTickのリロード値と未使用コードの削除です。

void delay_init(uint16_t sysclk)
{
#if SYS_SUPPORT_OS                                      /* 如果需要支持OS */
    uint32_t reload;
#endif
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);/* SYSTICK使用内核时钟源,同CPU同频率 */
    g_fac_us = sysclk;                                  /* 不论是否使用OS,g_fac_us都需要使用 */
#if SYS_SUPPORT_OS                                      /* 如果需要支持OS. */
    reload = sysclk;                                    /* 每秒钟的计数次数 单位为M */
    reload *= 1000000 / configTICK_RATE_HZ;             /* 根据delay_ostickspersec设定溢出时间,reload为24位
                                                           寄存器,最大值:16777216,在168M下,约合0.099s左右 */
    SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;          /* 开启SYSTICK中断 */
    SysTick->LOAD = reload;                             /* 每1/delay_ostickspersec秒中断一次 */
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;           /* 开启SYSTICK */
#endif 
}

(c) 遅延_us()

        関数 late_us() は、マイクロ秒レベルの CPU ビジー遅延に使用されます。オリジナルの関数 late_us() には、μC/OS タスク スケジューラをロックおよびロック解除するための遅延の前後にカスタム関数 late_osschedlock() および late_osschedunlock() が追加されています。遅延がより正確になります。FreeRTOS では、これら 2 つの関数を追加する必要はありませんが、これにより関数 late_us() のマイクロ秒レベルの遅延の精度が低下することに注意する必要があります。

void delay_us(uint32_t nus)
{
    uint32_t ticks;
    uint32_t told, tnow, tcnt = 0;
    uint32_t reload = SysTick->LOAD;        /* LOAD的值 */
    
    ticks = nus * g_fac_us;                 /* 需要的节拍数 */
    told = SysTick->VAL;                    /* 刚进入时的计数器值 */
    while (1)
    {
        tnow = SysTick->VAL;
        if (tnow != told)
        {
            if (tnow < told)
            {
                tcnt += told - tnow;        /* 这里注意一下SYSTICK是一个递减的计数器就可以了 */
            }
            else
            {
                tcnt += reload - tnow + told;
            }
            told = tnow;
            if (tcnt >= ticks) 
            {
                break;                      /* 时间超过/等于要延迟的时间,则退出 */
            }
        }
    }
} 

 (d) 遅延_ms()

        ミリ秒レベルの CPU ビジー遅延を実現する関数は、関数 late_ms() を使用します。独自の関数 late_ms() は、μC/OS が動作しているかどうかを判断します。μC/OS が動作している場合は、μC/OS OS 遅延を使用して、ミリ秒レベルの遅延を実行します。そうでない場合は、関数lay_us()を呼び出して、ミリ秒レベルのCPUビジー遅延を実行します。FreeRTOS では、関数 delay_ms() は CPU ビジー遅延としてのみ定義できますが、OS 遅延が必要な場合は、FreeRTOS が提供する OS 遅延関数 vTaskDelay() を呼び出します (FreeRTOS の時間管理の説明で後述します)。 ) システム ティック レベルの遅延を実行するために、関数 late_ms() の変更されたコードは次のとおりです。

void delay_ms(uint16_t nms)
{
    uint32_t i;

    for (i=0; i<nms; i++)
    {
        delay_us(1000);
    }
}

(e) ヘッダーを含める

        上記手順の修正により、Delay.cファイル内でFreeRTOSの関連機能が使用されるため、FreeRTOSの関連ヘッダファイルをDelay.cファイルにインクルードし、既存のμC/OS関連を削除する必要があります。ヘッダファイル。まず、変更前の遅延.c ファイルに含まれる µC/OS 関連のヘッダー ファイルを確認します。

/* 添加公共头文件 (FreeRTOS 需要用到) */
#include "FreeRTOS.h"
#include "task.h"

5.5. 割り込みタイマー機能の変更

        FreeRTOS の移植中には、FreeRTOS システム タイムベース タイマー割り込み (SysTick 割り込み)、SVC 割り込み、PendSV 割り込みという、いくつかから 3 つの重要な割り込みが発生します (SVC 割り込みと PendSV 割り込みについては、以下で説明します。FreeRTOS 割り込みと FreeRTOS タスク)。これら 3 つの割り込みの割り込みサービス関数は、HAL ライブラリによって提供されるファイルで定義されています。異なるタイムアトムを持つ STM32 開発ボードの場合、異なるファイルは異なるファイルに対応します。具体的な対応関係は次のとおりです。次の表のとおりです。

STM32シリーズ開発ボードのPunctual Atomタイプ 割り込みサービス関数が配置されているファイル
STM32F1 stm32f1xx_it.c
STM32F4 stm32f4xx_it.c
STM32F7 stm32f7xx_it.c
STM32H7 stm32h7xx_it.c

        このうち、SysTick の割り込みサービス関数は、delay.c ファイルで定義されており、FreeRTOS も SVC と PendSV の割り込みサービス関数を提供しているため、HAL ライブラリが提供する 3 つの割り込みサービス関数をコメントアウトする必要があります。このように、HAL ライブラリの 3 つの割り込みサービス関数はコンパイルに含まれていませんが、使用するマクロは sys.h で定義されているため、sys.h ヘッダ ファイルもインポートする必要があります。上の表を参照して、対応するファイルを見つけて変更します。変更後のコードは次のようになります。

/*导入sys.h头文件*/
#include "./SYSTEM/SYS/sys.h"

#if(!SYS_SUPPORT_OS)
void SVC_Handler(void)
{
}
#endif


#if(!SYS_SUPPORT_OS)
void PendSV_Handler(void)
{
}
#endif

#if(!SYS_SUPPORT_OS)
void SysTick_Handler(void)
{
  HAL_IncTick();
}
#endif

        最後に、FreeRTOS を移植するために変更する最後の場所でもあります。FreeRTOSConfig.h ファイルには次の定義があります: #define configPRIO_BITS __NVIC_PRIO_BITS

        私たちはする必要があります

#define __NVIC_PRIO_BITS 4U

        に変更されました

#define __NVIC_PRIO_BITS 4

5.6. オプションの手順

        このステップはオプションですが、このステップは後続の実験で使用され、プロジェクトが標準化されるため、著者は読者にこのステップを完了することを強く推奨します。このセクションは 3 つの小さな部分に分かれており、それぞれプロジェクト ターゲット名の変更、USMART デバッグ コンポーネントの削除、タイマー ドライバーの追加です。

1. プロジェクトのターゲット名を変更する

        以前の基本プロジェクト名を FreeRTOS に変更します

 2. USMART デバッグ コンポーネントを削除します。

 

 3.タイマードライバーの追加

        STM32 の基本的なタイマー ペリフェラルはその後の実験で使用する必要があるため、プロジェクトにタイマー関連のドライバー ファイルを追加する必要があります。

5.7. アプリケーションの追加

        もちろん、FreeRTOS を移植した後は、移植が成功したかどうかをテストする必要があります。このステップでは、合計 1 つのファイルを変更し、2 つのファイルを追加する必要があります。変更された 1 つのファイルは main.c で、追加された 2 つのファイルは freertos_demo.c と freertos_demo.h です。main.c の場合、主に main() 関数で一部のハードウェア初期化を完了し、最後に freertos_demo.c ファイル内の freertos_demo() 関数を呼び出します。また、freertos_demo.c は、FreeRTOS 関連のアプリケーション コードを記述するために使用されます。

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/SRAM/sram.h"
#include "./MALLOC/malloc.h"
#include "freertos_demo.h"
int main(void)
{
 HAL_Init(); /* 初始化 HAL 库 */
 sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
 delay_init(72); /* 延时初始化 */
 usart_init(115200); /* 串口初始化为 115200 */
 led_init(); /* 初始化 LED */
 lcd_init(); /* 初始化 LCD */
 key_init(); /* 初始化按键 */
 sram_init(); /* SRAM 初始化 */
 my_mem_init(SRAMIN); /* 初始化内部 SRAM 内存池 */
 my_mem_init(SRAMEX); /* 初始化外部 SRAM 内存池 */
 
 freertos_demo(); /* 运行 FreeRTOS 例程 */
}

おすすめ

転載: blog.csdn.net/zywcxz/article/details/131499260