最終更新: llysfactoryll 2020年09月13日(日) 21:46:32履歴
TOPPERS/ASPカーネルも、STM32F4 Discovery用の実装があるようだ。
STM32CubeIDEでの構築例もあるようだが、ほとんどがLinuxコマンドラインベースでの作業になり、freeRTOSほど簡単ではなさそうである。
なのでひとまずおいておいて、freeRTOSの実装を探ってみる。
自前のμITRONの、多重割り込み化のヒントにもなるかも知れない。
PendSVはOS構築のために用意されたと言う。
PendSVの優先度を最低に割り当てておいて、割り込みハンドラの中からでも構わずPendSVを要求するというやり方が想定され、ITRONのディレイドディスパッチの概念と良くマッチし、魅力的だと思うが、どうもその具体的な実装方法がよく分からない。
自前のμITRONの、Cortex-Mへの私の移植では、タスクの切り換え(=dpt_tsk())を優先度を一番高くしたSVCallで行っている。
自前のμITRONは、タスクの切り換え(=dpt_tsk())を割り込み禁止で呼び出している。
PendSVでタスク切り換えを行なうためには、割り込み禁止では行なえない。
dpt_tsk()を割り込み禁止を解除して呼び出せるか検証してみたが、難しいようである。
freeRTOSを解析してみた結果、タスクからのディスパッチも、割り込みハンドラからのディスパッチも予想通りと言うか、見事に優先度を最低にしたPendSVで実現されていた。
freeRTOSではクリティカルセッションのロックをBASEPRIを用いる方法で行われている。私の方法とほぼ同じである。
ロックのかかった状態でPendSVが要求されるがそこでは実行されない。その後ロックが一瞬外され、そこでPendSVが実行され、ディスパッチが起こると思われる。
その後すぐにロックされ後処理が行われるが、その間に割り込みが入ってコンテキストが変わってしまって問題にならないのか心配になる。
後処理で行われることはおもに戻り値の処理である。freeRTOSの仕様ならばこのラフな作りでも問題にならないのかも知れない。
例えばSignalは、タスクに付属しているし、osSingalClearは実装されていない。
シグナルは受け取ったときにしかクリアしないし、割り込みハンドラからクリアできない。
TOPPERSの技術資料の中に、PendSV、またはSVCallの優先度を最高にする必要がある旨の記述を見つけた。
ITRON系のOSの仕様を満たすためには、優先度を最低にしたPendSVの手法は使えないような気もしてきた。
STM32の割り込み優先度は4ビットで表される。
割り込み優先度はその4ビットを、グループ優先度とサブ優先度に分けて管理されている。
グループ優先度とサブ優先度をその4ビットのどこで分かれるかは、PRIGROUPレジスタの値によって決まる。
main()の入り口でブレークをかけ、PRIGROUPレジスタの値を調べてみると3である。
これはグループ優先度に4ビット全てが割り当てられている。
割り込み優先度はすべてがグループ優先度で、0(高い)〜15(低い)の16段階であることが分かる。
PRIGROUP=割り込み優先度グループ:3ビット。
0〜3: グループ優先度4ビット。サブ優先度なし。
4: グループ優先度3ビット。サブ優先度1ビット。
5: グループ優先度2ビット。サブ優先度2ビット。
6: グループ優先度1ビット。サブ優先度3ビット。
7: グループ優先度なし。サブ優先度4ビット。
タスクの実行途中でブレークをかけて、その状態を調べてみよう。
BASEPRI、PRIMASK、FAULMASKは全てゼロで、例外は何も禁止されていないことが分かる。
CONTROLの下位2ビットが1で、非特権レベル、プロセススタックで動作していることが分かる。
IPSRはゼロで、スレッドモードで実行(例外処理中ではない)ことが分かる。
BASEPRI=ベース優先度マスク:STM32はビット7〜4が有効。
ゼロ以外が設定されると、設定された優先度以下の例外を禁止する。
PRIMASK=優先度マスク:下位1ビット。
1: フォールト、NMI以外禁止する。
FAULTMASK=フォールトマスク:下位1ビット。
1: フォールトも含めNMI以外禁止する。
IPSR=割込みプログラム・ステータス・レジスタ():8ビット。
現在実行中の割込番号。
PDF版にはスクリーンショットも載っています。
1-start.pdf
osSignalWait つぎの経路でportYIELD が呼び出され、portYIELD の中からPendSVが発行されている。
osSignalWait --> xTaskNotifyWait --> portYIELD_WITHIN_API (=portYIELD)
PendSVの割り込み優先度は15に設定されているが、portYIELDは、taskENTER_CRITICALとtaskEXIT_CRITICALに挟まれている。
taskENTER_CRITICALでは、BASEPRIの上位4ビットが8に設定され、優先度8〜15の例外は禁止されている。
従ってportYIELD呼び出しの時点ではPendSVが実行されない。
portYIELDの直後にtaskEXIT_CRITICALが呼び出されているので、PendSVはその直後に実行されると思われる。
PDF版にはソースコードも載っています。
2-wignal-wait.pdf
TIM1の割り込みハンドラがどんな状態で飛んでくるか、ブレークをかけて調べてみる。
BASEPRI、PRIMASK、FAULMASKは全てゼロで、例外は何も禁止されていないことが分かる。
CONTROLの下位2ビットが0で、特権レベル、メインスタックで動作していることが分かる。
IPSRは41で、例外番号41の例外処理中であることが分かる。
PDF版にはスクリーンショットも載っています。
3-interrupt.pdf
STM32CubeIDEでの構築例もあるようだが、ほとんどがLinuxコマンドラインベースでの作業になり、freeRTOSほど簡単ではなさそうである。
なのでひとまずおいておいて、freeRTOSの実装を探ってみる。
自前のμITRONの、多重割り込み化のヒントにもなるかも知れない。
PendSVはOS構築のために用意されたと言う。
PendSVの優先度を最低に割り当てておいて、割り込みハンドラの中からでも構わずPendSVを要求するというやり方が想定され、ITRONのディレイドディスパッチの概念と良くマッチし、魅力的だと思うが、どうもその具体的な実装方法がよく分からない。
自前のμITRONの、Cortex-Mへの私の移植では、タスクの切り換え(=dpt_tsk())を優先度を一番高くしたSVCallで行っている。
自前のμITRONは、タスクの切り換え(=dpt_tsk())を割り込み禁止で呼び出している。
PendSVでタスク切り換えを行なうためには、割り込み禁止では行なえない。
dpt_tsk()を割り込み禁止を解除して呼び出せるか検証してみたが、難しいようである。
freeRTOSを解析してみた結果、タスクからのディスパッチも、割り込みハンドラからのディスパッチも予想通りと言うか、見事に優先度を最低にしたPendSVで実現されていた。
freeRTOSではクリティカルセッションのロックをBASEPRIを用いる方法で行われている。私の方法とほぼ同じである。
ロックのかかった状態でPendSVが要求されるがそこでは実行されない。その後ロックが一瞬外され、そこでPendSVが実行され、ディスパッチが起こると思われる。
その後すぐにロックされ後処理が行われるが、その間に割り込みが入ってコンテキストが変わってしまって問題にならないのか心配になる。
後処理で行われることはおもに戻り値の処理である。freeRTOSの仕様ならばこのラフな作りでも問題にならないのかも知れない。
例えばSignalは、タスクに付属しているし、osSingalClearは実装されていない。
シグナルは受け取ったときにしかクリアしないし、割り込みハンドラからクリアできない。
TOPPERSの技術資料の中に、PendSV、またはSVCallの優先度を最高にする必要がある旨の記述を見つけた。
ITRON系のOSの仕様を満たすためには、優先度を最低にしたPendSVの手法は使えないような気もしてきた。
開発環境 STM32CubeIDE 1.4.2
基板 STM32FDISCOVERY
CPU STM32F407VGT6
ARM Cortex-M4
STM32の割り込み優先度は4ビットで表される。
割り込み優先度はその4ビットを、グループ優先度とサブ優先度に分けて管理されている。
グループ優先度とサブ優先度をその4ビットのどこで分かれるかは、PRIGROUPレジスタの値によって決まる。
main()の入り口でブレークをかけ、PRIGROUPレジスタの値を調べてみると3である。
これはグループ優先度に4ビット全てが割り当てられている。
割り込み優先度はすべてがグループ優先度で、0(高い)〜15(低い)の16段階であることが分かる。
PRIGROUP=割り込み優先度グループ:3ビット。
0〜3: グループ優先度4ビット。サブ優先度なし。
4: グループ優先度3ビット。サブ優先度1ビット。
5: グループ優先度2ビット。サブ優先度2ビット。
6: グループ優先度1ビット。サブ優先度3ビット。
7: グループ優先度なし。サブ優先度4ビット。
タスクの実行途中でブレークをかけて、その状態を調べてみよう。
BASEPRI、PRIMASK、FAULMASKは全てゼロで、例外は何も禁止されていないことが分かる。
CONTROLの下位2ビットが1で、非特権レベル、プロセススタックで動作していることが分かる。
IPSRはゼロで、スレッドモードで実行(例外処理中ではない)ことが分かる。
BASEPRI=ベース優先度マスク:STM32はビット7〜4が有効。
ゼロ以外が設定されると、設定された優先度以下の例外を禁止する。
PRIMASK=優先度マスク:下位1ビット。
1: フォールト、NMI以外禁止する。
FAULTMASK=フォールトマスク:下位1ビット。
1: フォールトも含めNMI以外禁止する。
IPSR=割込みプログラム・ステータス・レジスタ():8ビット。
現在実行中の割込番号。
PDF版にはスクリーンショットも載っています。
1-start.pdf
osSignalWait つぎの経路でportYIELD が呼び出され、portYIELD の中からPendSVが発行されている。
osSignalWait --> xTaskNotifyWait --> portYIELD_WITHIN_API (=portYIELD)
PendSVの割り込み優先度は15に設定されているが、portYIELDは、taskENTER_CRITICALとtaskEXIT_CRITICALに挟まれている。
taskENTER_CRITICALでは、BASEPRIの上位4ビットが8に設定され、優先度8〜15の例外は禁止されている。
従ってportYIELD呼び出しの時点ではPendSVが実行されない。
portYIELDの直後にtaskEXIT_CRITICALが呼び出されているので、PendSVはその直後に実行されると思われる。
PDF版にはソースコードも載っています。
2-wignal-wait.pdf
TIM1の割り込みハンドラがどんな状態で飛んでくるか、ブレークをかけて調べてみる。
BASEPRI、PRIMASK、FAULMASKは全てゼロで、例外は何も禁止されていないことが分かる。
CONTROLの下位2ビットが0で、特権レベル、メインスタックで動作していることが分かる。
IPSRは41で、例外番号41の例外処理中であることが分かる。
PDF版にはスクリーンショットも載っています。
3-interrupt.pdf
コメントをかく