ＴＯＰＰＥＲＳ基礎実装セミナー（STM32F401/446 Nulceo版：基本）

基礎２編：２日目
TOPPERSプロジェクト

教育ワーキング・グループ

2021/08/01

TOPPERSプロジェクト認定1

本教材の利用条件
NEXCESS基礎コース01
組込みソフトウェア開発技術の基礎
Copyright (C) 2006-2007 by 名古屋大学 組込みソフトウェア技術者人材養成プログラム
Copyright (C) 2006-2007 by本田晋也, 高田広章
上記著作権者は，以下の(1)～(4)の条件を満たす場合に限り，本コンテンツ（本コンテンツを改変・翻訳したものを含む．
以下同じ）を使用・複製・改変・翻訳・再配布（以下，利用と呼ぶ）することを無償で許諾する．
(1) この枠内の著作権表記等が，そのままの形でコンテンツ中に含まれていること．
(2) 本コンテンツを再配布する場合には，再配布の形態等を，以下のウェブサイトから報告すること．
http://www.nces.is.nagoya-u.ac.jp/NEXCESS/REPORT/(3) 本コンテンツを改変・翻訳する場合には，コンテンツを改変・翻訳した旨の記述を，コンテンツ中に含めること．また，改変・翻訳者の著作権表記等は，この枠内の著作権表記等とは別に行うこと．
(4) 本コンテンツの利用により直接的または間接的に生じるいかなる損害からも，上記著作権者を免責すること．
※ 本コンテンツの一部は，文部科学省 科学技術振興調整費により，名古屋大学 組込みソフトウェア技術者人材養成プログラム（NEXCESS）の一環として作成しました．
※ 本コンテンツ中に記載されている商品名やサービス名などは，各社の商標または登録商標です．

2021/08/01

TOPPERSプロジェクト認定2

本ドキュメントに関して
１． 著作権に関しての表記-----------------------------------------------------------------------------------------------------------<TOPPERS基礎実装セミナー(STM32F401/446 nucleo-64版：基本２）２日目>
Copyright (C) 2006-2008 by 名古屋大学 組込みソフトウェア技術者人材養成プログラム
Copyright (C) 2006-2008 by 本田晋也、高田広章 名古屋大学
Copyright (C) 2008-2021 by 竹内良輔 （株）リコー
上記著作権者は、以下の (1)～(3) の条件を満たす場合に限り、本ドキュメント（本ドキュメントを改変したものを含む。
以下同じ）を使用・複製・改変・再配布（以下、利用と呼ぶ）することを無償で許諾する。
(1) 本ドキュメントを利用する場合には、上記の著作権表示、この利用条件および以下の無保証規定が、そのままの形でドキュメント中に含まれていること。
(2) 本ドキュメントを改変する場合には、ドキュメントを改変した旨の記述を、改変後のドキュメント中に含めること。
ただし、改変後のドキュメントがTOPPERSプロジェクト指定の開発成果物である場合には、この限りではない。
(3) 本ドキュメントの利用により直接的または間接的に生じるいかなる損害からも、上記著作権者およびTOPPERSプロ
ジェクトを免責すること。また、本ドキュメントのユーザまたはエンドユーザからのいかなる理由に基づく請求からも、上記著作者およびTOPPERSプロジェクトを免責すること。
本ドキュメントは、無保証で提供されているものである。上記著作権者およびTOPPERSプロジェクトは、本ドキュメントに関して、特定の使用目的に対する適合性も含めて、いかなる保障もしない。また、本ドキュメントの利用により直接的
または間接的に生じたいかなる損害に関しても、その責任を負わない。
------------------------------------------------------------------------------------------------------------

２．

本ドキュメントに関するご意見・ご提言・ご感想・ご質問等がありましたら、TOPPERSプロジェクト事務
局までE-Mailにてご連絡ください。

３．

本ドキュメントの内容は、内容の改善や適正化の目的で予告無く改定することがあります。
本ドキュメントでは、Microsoft社のClip Art Galleryコンテンツを使用しています。
TRONは”The Real-time Operating system Nucleus”の略称です。ITRONは”Industrial TRON”の略称です。
μITRONは”Micro Industrial TRON”の略称です。TOPPERS/JSPはToyohashi Open Platform for Embedded
Real-Time System/Just Standard Profile Kernelの略称です。」
本ドキュメント中の商品名及び商標名は、各社の商標または登録商標です。

2021/08/01

TOPPERSプロジェクト認定3

スケジュール◼

２日目

１．実習開発環境の構築

0.5時間

２． RTOSの基礎プログラミング実習１

1.5時間

３． RTOSの基礎プログラミング実習２

2.0時間

４．同期通信機能プログラミング実習

1.5時間

５．まとめ

0.5時間

2021/08/01

TOPPERSプロジェクト認定4概要
マイコンボード上でのRTOSを用いたプログラミングを学ぶ• 実行・開発環境の説明– ASPでのインクルードファイルと型設定– 実行・開発環境の使用方法• RTOS基本プログラミング実習– RTOS基本プログラミングの概要– タスク生成方法– デバッグ方法– マルチタスクプログラミング– 周期ハンドラ– 割込みハンドラ
2021/08/01

TOPPERSプロジェクト認定

5

概要• RTOS同期･通信機能プログラミング実習– セマフォによる排他制御– イベントフラグ, データキューによる事象通知• カップラーメンタイマーの実装（宿題）– タスク設計– 実装

2021/08/01

TOPPERSプロジェクト認定

6

実習開発環境の構築

2021/08/01

TOPPERSプロジェクト認定7２日目の開発環境の構築作業• ２日目の実習環境はＲＯＭモニタを使用します– 作成したプログラムはTeraTermを用いてダウンロード
し、そのまま、実行確認ができます• ２日目の実習環境を構築するために以下の作業を行う– 作業用のmy_programディレクトリを作成– カーネルライブラリを作成• 毎回、カーネルプログラムのコンパイル必要がなくなる– サンプル用のled1_taskプログラムをビルド、実行する• このプログラムを元にいろいろな改造を行う

2021/08/01

TOPPERSプロジェクト認定8

開発・実行環境の使用方法• 開発環境と2種類の実行環境使用方法について解説• ROM使用版– ROMモニタを使用してプログラムをダウンロードして実行– ダウンロード後、ROMモニタのGOコマンドでプログラムが起動する• ASPがUARTを乗っ取る形で実行– 電源OFF、リセットでプログラムが消滅する• 直接実行版– プログラムをフラッシュメモリに書き込み実行– 電源オンで毎回実行できる• タスクモニタを用いたデバッグは可能

2021/08/01

TOPPERSプロジェクト認定

9カーネルライブラリのビルド• これから作業を行うワークディレクトリ
（OBJ/STM32F401NUCLEO_GCC）の下にカーネルライブ
ラリ用ディレクトリ：libkernelにカーネルライブラリ（libkernel.a）を作成する• configureコマンド実行
後は、３つのファイル
Makefile,sample1.cfg,sa
mple1.c,sample1.hが生
成される

ここに
libkernel.aを作成、これを使うとビルド時間が短縮できる$ cd asp/OBJ/STM32F401NUCLEO_GCC$ mkdir libkernel$ cd libkernel$ ../../../configure –T stm32f401nucleo_gcc -f
2021/08/01

TOPPERSプロジェクト認定10開発・実行環境の使用方法：タスク時間の測定• asp/OBJ/STM32F401NUCLEO_GCC/libkernelを修正• タスクの実行時間の測定が行えるようMakefileのコンパ
イルスイッチに、LOG_DSP_ENTERとLOG_DSP_LEAVEを追加する
Makefile

143 ifndef OMIT_OPTIMIZATION
144 COPTS := $(COPTS) –O2
145 endif
146 CDEFS := $(CDEFS) –DLOG_DSP_ENTER –DLOG_DSP_LEAVE
147 INCLUDES := -I. –I$(SRCDIR)/include –I$(SRCDIR)/arch ….
$ make libkernel.a2021/08/01

TOPPERSプロジェクト認定11

開発・実行環境の使用方法：ビルド• led_1taskがカーネルプログラムをコンパイルせずビルドできる• led_1task/Makefileの82行目にカーネルライブラリの指定
変数（KERNEL_LIB）の定義があり、この設定があるとカーネルライブラリをビルドしない• configureでsample1を生成した場合は、KERNEL_LIBの設定は空になっている
81 #82 # カーネルライブラリ(libkernel.a)のディレクトリ名
83 # (カーネルライブラリもmake対象にする時は、空に定義する)
84 #85 KERNEL_LIB = $(SRCDIR)/OBJ/$(TARGET2)/libkernel
2021/08/01

TOPPERSプロジェクト認定12

開発・実行環境の使用方法：カーネルライブラリ• 学習用のワークスペースはaspに並列して開発環境のbase2をコピーする• base2ディレクトリの中にmy_programを作成して開発を行う• カーネルライブラリは
asp/OBJ/STM32F401NUCLEO_GCC/libkernelに作成

2021/08/01

TOPPERSプロジェクト認定13

開発・実行環境の使用方法：ビルド• kernelライブラリが正しく参照しているかの確認を行う• 確認用にprogram2/led_1taskをビルドする• led_1taskフォルダのコピー– ファイルを変更できるよう， led_1taskのフォルダをコピーする– program2下の２つのファイルを
my_program/ にコピーする– Makefile.config– command.c$ cd ../../../../base2/my_program/led1_task$ make2021/08/01

TOPPERSプロジェクト認定14

開発・実行環境の使用方法：ダウンロード• ROMモニタ使用版– ROMモニタ起動後、LDコマンドにてダウンロードに移行– asp.srecをTeraTermにドロップしてダウンロード• 直接実行版– ROM実行モードでビルドを行う（デフォルトがROMモニタ版）• make DBGENV=ROM– 基礎１セミナーの”フラッシュメモリからの起動”を参考に
asp.srecをSTM32 ST-LINK Utilityを用いてフラッシュメ
モリに書き込む

2021/08/01

TOPPERSプロジェクト認定15

開発・実行環境の使用方法 : TeraTermの実行• TeraTermは，UARTから送られてくるデータを表示する• UARTによる通信は双方でスピード（BPS）やデータ
フォーマットを合わせる必要がある• TeraTermのメニューのSetup→Serial port で設定– Port は接続しているCOMポートの番号に設定– Baud rate : 115200bps, Data : 8bit
– Parity : none, Stop :1bit, Flow control : なし
• 設定後メニューのSetup→Save setupで設定を保存

2021/08/01

TOPPERSプロジェクト認定16

開発・実行環境の使用方法 : 実行
• ROMモニタ使用 : GOコマンドにより実行する• 直接実行版: ST-LINKで書き込む• 実行されると，起動メッセージが TeraTerm に表示される
ROMモニタを再び書き込む場合、STM32 ST-LINK Utilityを使用してフラッシュROMに書き込む

2021/08/01

TOPPERSプロジェクト認定

17

RTOSの基礎プログラミング実習
1. 概要
2. タスク生成方法
3. デバッグ方法
4. マルチタスクプログラミング
5. 周期ハンドラ
6. 割込みプログラム
2021/08/01

TOPPERSプロジェクト認定18

概要• TOPPERS/ASPカーネルを用いてRTOSの基本プログラミングを学ぶ• タスク生成方法– 1タスクによるLED点滅プログラムの解説• デバッグ方法– デバッグ方法を解説し、1タスクによるLED点滅プログラムに適用• マルチタスクプログラミング– 1タスクによるLED点滅プログラムをマルチタスクプログラムに拡張• 周期ハンドラ– 周期ハンドラを用いてLED点滅プログラムを作成• 割込みプログラム– スイッチ割込みによる割込みサービスルーチン、ハンドラを作成

2021/08/01

TOPPERSプロジェクト認定

19

RTOS基本プログラミング実習 : プログラムファイル• プログラムファイルの置き場所– 教材ディレクトリ/program2
タスク生成

led_1task: 1タスクによるLED点滅プログラム
led_1task_syslog : 1タスクによるLED点滅プログラム（printf（）デバッグ）
マルチタスクプログラミング
base: 2タスクによるLED点滅プログラム（forループ版）
led_2tasks: 2タスクによるLED点滅プログラム（dly_tsk版）
led_2tasks_init: 2タスクによるLED点滅プログラム（初期化ルーチン）
led_2tasks_share : 2タスクによるLED点滅プログラム（コード共有）
周期ハンドラ
led_cyc: 周期ハンドラによるLED点滅プログラム
割込みプログラム
sw_int: 割込みサービスルーチンによるLED点滅プログラム
sw_int2: 複数の割込みによるLED点滅プログラム
sw_int_api/2: 割込みハンドラからのAPI呼び出し（タスク起動/起床）
cpu_lock: CPUロック状態
2021/08/01

TOPPERSプロジェクト認定

20

RTOSの基礎プログラミング実習
1. 概要
2. タスク生成方法
3. デバッグ方法
4. マルチタスクプログラミング
5. 周期ハンドラ
6. 割込みプログラム
2021/08/01

TOPPERSプロジェクト認定21

1タスクによるLED点滅プログラム : led_1task 概要• タスクによりLED1を一定周期で点滅させる• 学習内容– プログラムの全体像の理解– デバイスドライバ– タスクの記述方法– コンフィギュレーションファイル• タスクの生成方法• 構成ファイル
– led_1task.h– led_1task.c– led_1task.cfg– Makefile
2021/08/01: ヘッダーファイル: Cソースファイル: コンフィギュレーションファイル: メイクファイル

TOPPERSプロジェクト認定22

led_1task 解説 : デバイス操作関数群 LED• 拡張I/OボードのLEDとスイッチ用のドライバ関数– pdic/stm32f4xxディレクトリ以下のドライバを使用します– device.c device.h device.cfg• LED関連#define LED01(1<<LEDN3)– マクロ#define LED02(1<<LEDN4)#define LED03
0#define LED04
0#define LED_MASK (LED01|LED02|LED03|LED04)– 関数• void led_init(intptr_t exinf)– 初期化（引数は0とする）• void led_out(unsigned short led_data)– 引数にマクロで点灯パターンを指定
2021/08/01

TOPPERSプロジェクト認定23

led_1task 解説 : ITRON用のデバイスドライバ• SILを用いてドライバを記載する#define TADR_LED_BASE TADR_GPIOD_BASE#define OFF_LEDON TOFF_GPIO_BSRRL#define OFF_LEDOFF TOFF_GPIO_BSRRH
void led_out(unsigned short led_data){
unsigned short reg1, reg2;
reg1 = ~led_data & LED_MASK;
reg2 = led_data & LED_MASK;
sil_wrh_mem((uint32_t*)(TADR_LED_BASE+OFF_LEDOFF), reg1);
sil_wrh_mem((uint32_t*)(TADR_LED_BASE+OFF_LEDON), reg2);}• 割込み関連（後述）– 割込みハンドラの登録や呼び出しはTOPPERS/ASPで実現（ITRONではユーザー側での記載が必要）– 静的APIを用いて割込み設定を行います
2021/08/01

TOPPERSプロジェクト認定24

led_1task 解説 : ディップスイッチ操作関数群• シールド上の２ピンのDIPSWを使用する。
• マクロ#define DSW1
#define DSW2

0x01
0x02

• 関数
– uint_t switch_dip_sense(void)• ディップスイッチの状態取得• 戻り値にON状態スイッチのビットを’1’とした値を返す

2021/08/01

TOPPERSプロジェクト認定25

led_1task 解説 : プッシュスイッチ操作関数群• マクロ#define PSW1

0x001

• 関数
– void switch_push_init(intptr_t exinf)• 初期化（引数は使用しない）– void switch_push_clear(void)• PUSHスイッチ割込みのクリアを行う• 割込み設定– 割込み設定は静的APIで行う– （他のRTOSとの大きな違い）

2021/08/01

TOPPERSプロジェクト認定26

led_1task 解説 :ヘッダーファイル（led_1task.h）• タスクやハンドラの外部宣言を記述• コンフィギュレーションファイルで参照する各種マクロとタ
スクやハンドラのプロトタイプ宣言を記述する• TOPPERS_MACRO_ONLYはアセンブラ言語から参照された場合、解釈できないマクロ以外の記載を示すためのコンパイルスイッチで、ここでは必ずしも設定する必要はありません#define STACK_SIZE
386 /* タスクのスタックサイズ */#define DEFAULT_PRIORITY 8 /* タスクの優先度 */アセンブラ言語で解釈できない記載を定義#ifndef TOPPERS_MACRO_ONLY
extern void led1_task(intptr_t exinf);#endif /* TOPPERS_MACRO_ONLY */2021/08/01

TOPPERSプロジェクト認定

対応が分かり易いように
27

led_1task 解説 : Cソースファイル（led_1task.c）• タスク等を記述• TOPPERS/ASPの標準インクルードファイルと自動ID割付
け結果ヘッダファイルの二つのファイルをインクルードする• タスクは実行されると無限ループ内で，busy_wait()関数により一定時間毎にLED1を点滅させる#include <kernel.h>#include <t_syslog.h>#include <t_stdlib.h>#include "kernel_cfg.h“#include “device.h”

2021/08/01

void
led1_task(intptr_t exinf){
led_init(0);for (;;) {led_out(LED01);
busy_wait();
led_out(0x00);
busy_wait();}}

TOPPERSプロジェクト認定

28

点灯

消灯

led_1task 解説 :コンフィギュレーションファイル• 静的APIを記述（led_1task.cfg）•••

led1_task 関数から開始されるタスクを生成
ヘッダーファイルをインクルード
サポートモジュールのコンフィギュレーションファイルをインクルード

INCLUDE(“target_timer.cfg);
INCLUDE(“syssvc/syslog.cfg);
INCLUDE(“syssvc/banner.cfg”);
INCLUDE(“syssvc/serial.cfg”);
INCLUDE(“syssvc/logtask.cfg”);
INCLUDE(“monitor/montor.cfg”);

サポートモジュールのコン
フィギュレーションファイル

起動時に実
行可能状態

タスクの
起動番地

#include “led_1task.h”
CRE_TSK(MAIN_TASK, { TA_ACT, 0, led_1task,
DEFAULT_PRIORITY, STACK_SIZE, NULL });2021/08/01

TOPPERSプロジェクト認定29

led_1task 解説 : コンフィギュレータ• コンフィギュレーションファイルを処理するプログラム• コンフィギュレータを実行（ProjectEditorでcfg.oを選択して部
分ビルド）• コンフィギュレーションファイルはコンフィギュレータにより処理され、以下の二つのファイルが生成される– kernel_cfg.h: ID自動割付結果ファイル– kernel_cfg.c: カーネル構成･初期化ファイル• コンフィギュレータはプロジェクトのビルド時に自動的に実行• コンフィギュレータは２つのパスで実行される
cfg1_out.srec

led_1task.cfg

pass1

2021/08/01

cfg1_out.map

TOPPERSプロジェクト認定

kernel_cfg.hpass2

kernel_cfg.c30

led_1task 解説 : ID自動割付結果ファイル kernel_cfg.h
•
•
•
•
•
•

カーネルオブジェクトのIDマクロを定義
タスクや他のカーネルオブジェクトにはIDが割り付けられる
IDはコンフィギュレータが自動的に割り付ける
静的APIにはオブジェクトIDをマクロ定義する名前を指定する
kernel_cfg.hには名前をID番号に定義するマクロ定義が出力されるプログラムではこのマクロを用いてIDを指定する.hに定義がない
コンフィギュレーションファイル•

CRE_TSK(MAIN_TASK, { TA_ACT, 0, led1_task,
DEFAULT_PRIORITY, STACK_SIZE, NULL });•kernel_cfg.h#define LOGTASK#define MONTASK#define MAIN_TASK#define SERIAL_RCV_SEM1…….
2021/08/01

1
2
3
1

•

タスクのID指定

act_tsk(MAIN_TASK);•TOPPERSプロジェクト認定

あと2つタスクが存在する….
31

led_1task 解説 : カーネル構成･初期化ファイル kernel_cfg.c• カーネルオブジェクトの生成情報から生成されたカーネルの
内部データ• タスク管理ブロック（TCB）やスタック領域を確保#include "led_1task.h“...
static STK_T _kernel_stack_MAIN_TASK[COUNT_STK_T(STACK_SIZE)];...
const TINIB _kernel_tinib_table[TNUM_TSKID] = {{ TA_ACT, (intptr_t)(0), (led1_task),
INT_PRIORITY(DEFAULT_PRIORITY), ROUND_STK_T(ST....

• コンフィギュレーションファイルでのincludeまたは
INCLUDE指定（静的API）
include "led_1task.h"2021/08/01

TOPPERSプロジェクト認定32

RTOSの基礎プログラミング実習
1. 概要
2. タスク生成方法
3. デバッグ方法
4. マルチタスクプログラミング
5. 周期ハンドラ
6. 割込みプログラム
2021/08/01

TOPPERSプロジェクト認定33

タスクモニタ : タスクモニタとは?
• led1_taskタスク以外に2つのタスクが存在する• タスクモニタ（タスク）– led_1task.cfg からインクルードするmonitor.cfg 内で生成
– UARTを経由してコマンドを受付け，他のタスクの管理や監視を行うタスク• ログタスク•– led_1task.cfg からインクルードするlogtask.cfg 内で生成– カーネルログの出力を行うタスク
asp/monitor/monitor.cfg#include "monitor.h"
CRE_TSK(MONTASK, { TA_HLNG|TA_ACT,MONITOR_PORTID,
monitor,MONITOR_PRIORITY,MONITOR_STACK_SIZE, NULL });2021/08/01

TOPPERSプロジェクト認定34

演習 : タスクモニタの使用方法• コンソールにコマンドを入力して使用する• このプログラムを実行すると，タスクモニタが起動されてコンソールにモニタの起動ログを表示し，コマンド待ちを示す
mon> が表示される• helpと入力するとコマンド一覧が表示される

2021/08/01

TOPPERSプロジェクト認定35

演習 : タスクモニタによるタスク操作• タスクモニタではタスクに対して次の操作が可能– タスクの起動（act_tsk）: タスクを実行可能状態に– タスクの終了（ter_tsk）: タスクを休止状態に– タスクのサスペンド（sus_tsk）: タスクを強制待ち状態に– タスクのレジューム（rsm_tsk）: タスクを強制待ち状態から復帰– 優先度の変更（chg_pri）: タスクの優先度を変更する• タスクの操作する前に操作対象のタスクを指定する必要がある– タスクIDは kernel_cfg.h で定義されている値– 一度設定すると，それ以後のタスク操作は指定したタスクに対して行
われる
mon> set task [タスクID]
2021/08/01

TOPPERSプロジェクト認定36

演習 : led1_taskの停止
led1_task（ID番号３）を休止状態にする• set task 3 ： ID番号3のタスク指定• task terminate： タスクの終了• LED1の点滅が停止する（実行可能状態から休止状態に）• display task でタスクの状態を表示可能• コマンドは最初の一文字で短縮可能
2021/08/01

TOPPERSプロジェクト認定37

演習 : タスクモニタによるled1_taskの起動
先ほど休止状態にしたled1_taskを起動させる• 起動は task activate コマンドで行います• 起動すると，LED1の点滅が再開される– タスクとした関数の先頭から実行される（休止状態から実行可能状態）

起動

2021/08/01

TOPPERSプロジェクト認定38

演習 : タスクモニタ使用時の優先度設定に関する注意
優先度の設定によってはタスクモニタを使用できなくなる場合がある• タスクモニタの優先度は4で通常はコンソールからの入力待ちで待ち状態になっており，コンソールに入力があると起床して指定されたコマンドを実行する• タスクモニタでタスクの優先度を設定できるが，タスクモニタ
より高い優先度を設定すると、タスクモニタが動作しなくなるため，注意が必要– led1_task(タスク4)はループで時間を作っているため
led1_taskの優先度を６にコマンドを受付
led1_taskの優先度を２にこれ以上コマンドを受付られない2021/08/01

TOPPERSプロジェクト認定39

printf（）デバッグ• オーソドックスなデバッグ手法– UNIX等のプログラム開発と同じ• プログラム中で変数の値を表示させたり、パスの確認のために使用• 出力先や出力方法が必要– PC上のプログラムの場合は、画面に文字を表示する– 組込みの場合，UART経由で文字を出力可能– UARTがない場合もしくは、コード中で出力系の関数が使えない箇所（割込みハンドラ等）は、LEDに値を表示してprintf()デバッグの代わりとする

2021/08/01

TOPPERSプロジェクト認定40

printf（）デバッグ : syslog()関数
TOPPERS/ASPでは，printf（）の代わりにsyslog()関数を使用する• 標準関数を実装するとリソース使用量が多くなるため、代替方法を用意している• printf（）と異なり第一引数はログ出力レベルを指定• 引数の数に応じてx(0～6)の値を変更する
syslog_x(LOG_NOTICE, ……..)
syslog_0(LOG_NOTICE, "test");syslog_1(LOG_NOTICE, "test = %d", i);syslog_2(LOG_NOTICE, "test = %d , 0x%x", i, e);...
syslog_6(LOG_NOTICE, …..
2021/08/01

TOPPERSプロジェクト認定41

演習 : led_1taskへのprintf()デバッグ適用（led_1task_syslog）• led_1taskをLED出力部分でLEDの出力値をsyslog()でコンソールに出力するように改造• タスク関数名(led1_task)を表示するようコメントを作成
void
led1_task(intptr_t exinf){
led_init(0);for (;;) {syslog_1(LOG_NOTICE,"led1_task : out_put 0x%x", LED01);
led_out(LED01);
busy_wait();syslog_1(LOG_NOTICE,"led1_task : out_put 0x%x", 0x00);
led_out(0x00);
busy_wait();}}2021/08/01

TOPPERSプロジェクト認定

42

RTOSの基礎プログラミング実習
1. 概要
2. タスク生成方法
3. デバッグ方法
4. マルチタスクプログラミング
5. 周期ハンドラ
6. 割込みプログラム
2021/08/01

TOPPERSプロジェクト認定43

2タスクによるLED点滅プログラム : led_2tasks_for
led_1task にLED2を点滅させるタスク（led2_task）
を追加する• 学習内容– 新規プロジェクトの作成方法– 待ち状態– 初期化ルーチン– タスクのコード共有

2021/08/01

TOPPERSプロジェクト認定44

演習 : 新規プロジェクトの作成方法• 雛形のプロジェクトファイ
ルをベースに作成• プロジェクトのためのフォルダ（led_2tasks_for）を
my_program/に作成• program2/base にあるファイルを作成したフォルダにコピーする2021/08/01

TOPPERSプロジェクト認定

led_2tasks_forに変更

45

新規プロジェクトの作成方法 : ヘッダーファイル• ヘッダーファイル（led_2tasks.h） をフォルダ led_2tasks_for に作成• ヘッダーファイルに記述する内容– タスクのプロトタイプ宣言– タスクのスタックサイズ– タスク優先度の設定
また、マクロ以外のC言語の表記は#ifndef
TOPPERS_MACRO_ONLY ～#endifで囲む必要がある• led_1taskのヘッダーファイル（led_1task.h）の内容をコピーする#define STACK_SIZE
386 /* タスクのスタックサイズ */#define DEFAULT_PRIORITY 8 /* タスクの優先度 */#ifndef TOPPERS_MACRO_ONLY
extern void led1_task(VP_INT exinf);#endif /* TOPPERS_MACRO_ONLY */2021/08/01

TOPPERSプロジェクト認定46

プロジェクトの作成方法 : Cソースファイル• Cソースファイル（ led_2tasks.c ）を作成したフォルダに作成• Cソースファイルの先頭にはTOPPERS/ASPの標準インク
ルードファイルと自動ID割付け結果ヘッダファイルの二つのファイルをインクルードする#include <kernel.h>#include <t_syslog.h>#include <t_stdlib.h>#include "kernel_cfg.h"• led_1taskのCソースファイル（led_1task.c）の内容をコピーする

2021/08/01

TOPPERSプロジェクト認定47

プロジェクトの作成方法 : コンフィギュレーションファイル• led_2tasks.cfgがカーネルコンフィギュレーションファイル• xxx.hの部分を作成するプロジェクトのヘッダーファイル（この例ではled_2tasks.h）に置き換える• プロジェクトに必要な静的APIを追加する
INCLUDE(“target_timer.cfg")
INCLUDE(“syssvc/syslog.cfg")
INCLUDE(“syssvc/banner.cfg")
INCLUDE(“syssvc/serial.cfg")
INCLUDE(“syssvc/logtask.cfg")
INCLUDE(“monitor/monitor.cfg")#include “device.h”#include "xxx.h"/* 静的API追加 */• led_1taskのカーネルコンフィギュレーションファイルの静的API（タスクled1_taskの生成）をコピーする
2021/08/01

TOPPERSプロジェクト認定48

演習 : 2タスクによるLED点滅プログラムの作成（ led_2tasks_for ）• led_1taskにLED2を点滅するタスク（led2_task）を追加する• 手順– LEDの状態は共有変数により保持する– led2_task の内容は led1_task をベースにしてforループ
で時間を作成する– led2_task の優先度やスタックサイズは led1_task と同一にする– タスクが追加されていることは，タスクモニタで，display
task を実行することにより確認できる– 正しくタスクを追加しても，LEDは片方しか点滅しないので，理由を考察する

2021/08/01

TOPPERSプロジェクト認定49

led_2tasks_for 解説 : Cソースファイル（led_2tasks.c）• LED1点滅タスク
unsigned short led_data= 0;
void
led1_task(intptr_t exinf){
led_init(0);for (;;) {led_data &= ~LED01;
led_out(led_data);
busy_wait();
led_data |= LED01;
led_out(led_data);
busy_wait();}}2021/08/01

LEDのデータの共有メモリ化を行う• LED2点滅タスク
void
led2_task(intptr_t exinf){for (;;) {led_data &= ~LED02;
led_out(led_data);
busy_wait();
led_data |= LED02;
led_out(led_data);
busy_wait();}}

TOPPERSプロジェクト認定50

led_2tasks_for 解説 : その他のファイル• ヘッダーファイル（led_2tasks.h）#ifndef TOPPERS_MACRO_ONLY
extern void led1_task(intptr_t exinf);
extern void led2_task(intptr_t exinf);#endif /* TOPPERS_MACRO_ONLY */• コンフィギュレーションファイル（led_2tasks.cfg）
CRE_TSK(MAIN_TASK, { TA_ACT, 0, led1_task,
DEFAULT_PRIORITY, STACK_SIZE, NULL });CRE_TSK(LED2_TASK, { TA_ACT, 0, led2_task,
DEFAULT_PRIORITY, STACK_SIZE, NULL });2021/08/01

TOPPERSプロジェクト認定51

led_2tasks_for : 実行
• 意図した通りに動作したか?
– 片方のLEDしか点滅しない• led1_task, led2_taskは同一優先度でかつ、待ち状態に入らないため、どちらかのタスクのみ（レディキューの先頭にある方）実行状態になっている• 同一優先度のタスク間ではFCFS（First Come First Served）のルールで実行される
log task 1000コマンドでタスクの実行状態を確認
task 4(led2_task)の実行
時間がゼロ

2021/08/01

TOPPERSプロジェクト認定52

led_2tasks_for : タスクレベルの変更• タスクモニタで led1_task と led2_task の優先度を変更してスケジューリング方法を確認する– set task 4 ：タスク４(led2_task)に変更– task priority 6 ：タスク優先度を６に変更• これによりLED2のみ点滅する

優先順位

2021/08/01

優先度4

タスクモニタ

優先度8

led1_task
TOPPERSプロジェクト認定

led2_task53

演習 : 2タスクによるLED点滅プログラム改(led_2tasks)• LED1を1秒間隔，LED2を0.25秒間隔で点滅するようにプログラムを書き換える• 方式
1. 定期的に2個のタスクを切り替える方式
2. 時間生成を待ち状態で実現する方式– 本プログラムは時間を作るのが本質なので2を採用– led_2tasks_forをコピーしてled_2tasksに変更• ITRON仕様には、任意の時間自タスクを待ち状態にする
API dly_tsk（） がある– ミリ秒単位で待ち時間を指定可能

2021/08/01

TOPPERSプロジェクト認定54

led_2task : Cソースファイル（led_2tasks.c）• 共有メモリの排他制御は必要ない– タスクが切り替わるポイントを考える••

LED1点滅タスク#define LED1_INTERVAL 1000void
led1_task(intptr_t exinf){
led_init(0);for (;;) {led_data &= ~LED01;
led_out(led_data);
dly_tsk(LED1_INTERVAL);
led_data |= LED01;
led_out(led_data);
dly_tsk(LED1_INTERVAL);}}
2021/08/01

LED2点滅タスク#define LED2_INTERVAL 250
void
led_dataの
led2_task(intptr_t exinf){

排他制御は
必要ない

for (;;) {led_data &= ~LED02;
led_out(led_data);
dly_tsk(LED2_INTERVAL);
led_data |= LED02;
led_out(led_data);
dly_tsk(LED2_INTERVAL);}}TOPPERSプロジェクト認定55

初期化ルーチン• LED接続ポートの初期化関数（led_init（0））は led1_task
が実行している– led1_task が実行されるまでは初期化されず，先にled2_task が実行された場合、出力関数（led_out（））が正しく動作しない• 対処方法1. 初期化ずみかどうかチェック変数を用意
2. 両方のタスクで初期化
3. 初期化関数としてカーネル起動時に実行– 3の方法が最もスマート• ITRON仕様には初期化ルーチンを登録する静的API（ATT_INI）がある
拡張情報
属性(Cかアセンブラか)(初期化ルーチンへの引数)

初期化ルーチンの
起動番地

ATT_INI({ATR intatr, intptr_t exinf, FP intrtn});
2021/08/01

TOPPERSプロジェクト認定56

演習 : 2タスクによるLED点滅プログラム改（led_2tasks_init）• led_2tasks をベースにLEDの初期化関数をカーネルの初期化ルーチンとして実行するようプログラムを変更する• led_2tasksからは初期化ルーチンを外す• コンフィギュレーションファイル• デバイスドライバのヘッダーファイルのインクルード• 初期化ルーチンの登録#include “device.h“
ATT_INI({TA_NULL, 0, led_init});• device.cfgの取り込み
INCLUDE(“pdic/stm32f4xx/device.cfg”);
2021/08/01

TOPPERSプロジェクト認定57

演習 : タスクのコード共有（led_2tasks_share）• 2タスクによるLED点滅プログラムの
led1_task と led2_task のコードを共有化する• 個別に持つ情報– LEDの設定ビット– 点滅周期– 構造体の配列に入れ，そのインデックスを exinf で渡す• 正しく設定するLED情報と点滅周期を得ているかタスク
起動時にコンソールに出力すること
typedef struct{uint16_t led_bit;
int
interval;}LED_TASK_INFO;
LED_TASK_INFO task_info[] ={{LED01, LED1_INTERVAL},{LED02, LED2_INTERVAL}};
2021/08/01

TOPPERSプロジェクト認定58

led_2tasks_share : Cソースファイル（led_2tasks.c）• 実行されたらローカル変数にLEDの設定ビットと点滅周期をコピーする
void
led_task(intptr_t exinf){
uint16_t led_bit = task_info[(int)exinf].led_bit;
int
interval = task_info[(int)exinf].interval;
syslog_3(LOG_NOTICE, "led_task : exinf = %d, led_bit = 0x%x,
interval = %d msec", exinf, led_bit, interval);for (;;) {led_data &= ~led_bit;
led_out(led_data);
dly_tsk(interval);
led_data |= led_bit;
led_out(led_data);
dly_tsk(interval);}}
2021/08/01

TOPPERSプロジェクト認定59

led_2tasks_share : その他のファイル• ヘッダーファイル（led_2tasks.h）#ifndef TOPPERS_MACRO_ONLY
extern void led_task(intptr_t exinf);#endif /* TOPPERS_MACRO_ONLY */• コンフィギュレーションファイル（led_2tasks.cfg）
同一関数 led_task を指定
CRE_TSK(MAIN_TASK, { TA_ACT, 0, led_task,
DEFAULT_PRIORITY, STACK_SIZE, NULL });CRE_TSK(LED2_TASK, { TA_ACT, 1, led_task,
DEFAULT_PRIORITY, STACK_SIZE, NULL });2021/08/01

TOPPERSプロジェクト認定60

led_2tasks_share : コンフィギュレーションファイル• コンソール出力

2021/08/01

TOPPERSプロジェクト認定

61

RTOSの基礎プログラミング実習
1. 概要
2. タスク生成方法
3. デバッグ方法
4. マルチタスクプログラミング
5. 周期ハンドラ
6. 割込みプログラム
2021/08/01

TOPPERSプロジェクト認定62

演習 : 周期ハンドラによるLED点滅プログラム（led_cyc）• LED1をタスクにより1秒周期で，LED2を周期ハンドラにより0.5秒周期で点滅させるプログラムを作成• 手順– led_1taskをベースにする– LED2点滅タスク（led2_task）は生成しない– Cファイルに周期ハンドラを追加– コンフィギュレーションファイルに生成情報を追加

2021/08/01

TOPPERSプロジェクト認定63led_cyc : Cソースファイル• 周期ハンドラはタスクと同様に関数として記述する
LEDのデータの• LED2点滅周期ハンドラ
共有メモリ化を行う

unsigned short led_data= 0;
void
led2_cyc_handler(intptr_t exinf){
if((led_data & LED02) == LED02){
led_data &= ~LED02;}else{
led_data |= LED02;}
led_out(led_data);}

2021/08/01

TOPPERSプロジェクト認定64

led_cyc : Cソースファイル• LED1点滅タスクを共有型に変更
void
led1_task(intptr_t exinf){
led_init(0);for (;;) {led_data &= ~LED01;
led_out(led_data);
busy_wait();
led_data |= LED01;
led_out(led_data);
busy_wait();}}2021/08/01

TOPPERSプロジェクト認定65led_cyc : その他のファイル• ヘッダーファイル（led_1task.h）#define LED2_INTERVAL 500#ifndef TOPPERS_MACRO_ONLY…….
extern void led2_cyc_handler(intptr_t exinf);#endif /* TOPPERS_MACRO_ONLY */• コンフィギュレーションファイル（led_1task.cfg）
CRE_CYC(LED2_CYC_HANDLER,{TA_STA,
0, led2_cyc_handler, LED2_INTERVAL,0});2021/08/01

TOPPERSプロジェクト認定

66

RTOSの基礎プログラミング実習
1. 概要
2. タスク生成方法
3. デバッグ方法
4. マルチタスクプログラミング
5. 周期ハンドラ
6. 割込みプログラム

2021/08/01

TOPPERSプロジェクト認定67

割込みプログラミング : 割込みルーチン登録• TOPPERS/ASPの割込みルーチンの使い方を学ぶ– ASPでは割込みハンドラと割込み要求ライン属性の設定にて割込みを登録する
割込みハンドラのハンドラ番号属性（実装定義）

起動番地

DEF_INH(INHNO inhno, {ATR inhatr, FP inthdr});• STM32F4xx Nucleoでは，ハンドラ番号として”ソフトウェ
ア割込み番号”を指定する• DEF_INHは割込みハンドラの登録及び，ハンドラの前後処理は行いますが，割込み関連の属性の設定は
CFG_INTで行う• タスク実行時は，プロセッサの状態は割込み許可状態で割込みマスクはしない状態です2021/08/01

TOPPERSプロジェクト認定68

割込みプログラミング : 割込み要求ライン属性設定• 割込み属性の設定を行う– 割込み属性を登録する静的API
ハンドラ番号属性（実装定義）

割込み優先度CFG_INT(INTNO inhno, {ATR intatr, PRI intpri});• intatrは割込み属性（［TA_ENAINT］｜［TA_EDGE］等）• intpriは割込み優先度を指定する• 優先度は-1～-15で設定する

2021/08/01

TOPPERSプロジェクト認定69

割込みプログラム：割込みハンドラ• TOPPERS/ASPの割込みハンドラを用いて割込み処理を行う– ITRON準拠の割込みハンドラの登録を行う
割込み番号

割込みハンドラDEF_INH(INTNO inthno{ATR inhatr, FP inthdr});
割込みハンドラ属性• inhnoで指定された割込みハンドラ番号に対してinthdrで指定する割込みハンドラを設定する• inhatrで指定する割込み属性は通常は実装依存で
TA_NULLを指定する
2021/08/01

TOPPERSプロジェクト認定70

割込みによるLED点滅プログラム（sw_int）• 割込みによるLED点滅プログラムsw_intをbase/program2/sw_intをmy_programにコピーする• プログラムの説明– SW1の割込みは割込みハンドラを使用して作成している– SW1の初期化ルーチン• switch_push_init(void)– プッシュスイッチ初期化と割込み設定– SW1の割込みハンドラ• 静的APIで登録• SW1(EXTI4)の割込み番号は10(IRQ_VECTOR_EXTI4)– device.hで定義（INTNO_SW1/INHNO_SW1）– SW1の割込み属性を静的APIで登録• エッジ割込み、優先度は-4– device.hで定義（INTATR_SW1,INTPRI_SW1）

2021/08/01

TOPPERSプロジェクト認定71

sw_int : Cソースファイル（sw_int.c）•

SW1の割込みサービスルーチン– 割込みサービスルーチンはタスクと同様に関数として記述する
void
sw_int(void){
unsigned int led = (unsigned int)LED02;
switch_push_clear(); /* 割込みクリア */if ( (led_data & led) == led ) {led_data &= ~led;} else {led_data |= led;}
led_out(led_data);
syslog_1(LOG_NOTICE,"sw_int : led_data 0x%x",led_data);}
2021/08/01

TOPPERSプロジェクト認定72

sw_int : その他のファイル• ヘッダーファイル（sw_int.h）#ifndef TOPPERS_MACRO_ONLY
extern void led1_task(intptr_t exinf);
extern void sw_int(void);#endif /* TOPPERS_MACRO_ONLY */• コンフィギュレーションファイル（sw_int.cfg）• SW1の割込み番号は device.h で定義済み
ATT_INI({ TA_NULL, 0, switch_push_init });DEF_INH(INHNO_SW1, { TA_NULL, sw_int});
CFG_INT(INTNO_SW1, {TA_ENAINT|INTATR_SW1,INTPRI_SW1});

2021/08/01

TOPPERSプロジェクト認定73

演習：sw_intをビルド実行する• sw_intをビルド、ダウンロードしてSW1押下で割込みが発生し、LED2の発光が変わることを確認しよう

2021/08/01

TOPPERSプロジェクト認定74

割込みプログラミング : 割込みサービスルーチン登録• TOPPERS/ASPの割込みルーチンの使い方を学ぶ– ASPでは割込みサービスルーチンを登録する静的APIを用意している
割込みサービス
ルーチン属性

割込み番号

割込みサービス
ルーチン優先度ATT_ISR({ATR isratr, intptr_t exinf, INTNO inhno, ISR isr, PRI isrpri});
サービスルーチン
拡張情報

割込みサービスルー
チンの起動番地• 割込みサービスルーチン優先度は１、拡張情報にて割込み
サービスルーチンに引数を渡せます。その他はDEF_INH、
CFG_INTの設定と同じです
2021/08/01

TOPPERSプロジェクト認定75

演習 : 割込みによるLED点滅プログラム（sw_int2）• sw_int を割込みサービスルーチンを用いて記述する
割込みサービスルーチンは同一属性の割込みを共通化できる• 手順– sw_intをベースにする– sw_intをmy_program上でコピーして、名前をsw_int2にして演習を行ってください

2021/08/01

TOPPERSプロジェクト認定76

sw_int2 : Cソースファイル（sw_int.c）• SW1の割込みサービスルーチン– 割込みハンドラをATT_ISRを用いて割込みサービス
ルーチンに書き換える– 割込みサービスルーチンではLED2を引数として渡す• インクルードファイル（sw_int.h）
extern void led1_task(intptr_t exinf);
extern void sw_int(intptr_t exinf);• コンフィギュレーションファイル（sw_int.cfg）
ATT_ISR({TA_NULL, LED02, INTNO_SW1, sw_int, 1 });CFG_INT(INTNO_SW1, {TA_ENAINT|INTATR_SW1, INTPRI_SW1});

2021/08/01

TOPPERSプロジェクト認定77

sw_int2：Cソースファイル（int_sw.c）• 割込みサービスルーチンを用いれば、PUSHスイッチが複数ある場合、引数にてLEDの設定を行うことができる
void
sw_int(intptr_t exinf){
unsigned int led = (unsigned int)exinf;
switch_push_clear(); /* 割込みクリア */if ( (led_data & led) == led ) {led_data &= ~led;} else {led_data |= led;}
led_out(led_data);
syslog_1(LOG_NOTICE,"sw_int : led_data 0x%x",led_data);}
2021/08/01

TOPPERSプロジェクト認定78

演習 : 割込みハンドラからのAPI呼び出し（ sw_int_api）• 割込みハンドラからのAPI呼び出しを行うプログラムを作成• sw_intをベースに作り変えます• sw_intをmy_program上でコピーして、名前をsw_int_apiに変更• プログラム仕様– 割込みハンドラを用いて作成– タスクは休止状態で生成（CRE_TSKの引数の属性に
TA_ACTを付加しない）– タスクは起動時と終了時にコンソールにその旨を出力– SW1割込みハンドラからのタスクを起動– タスクはLED1を0.5秒間隔で点滅を2回繰り返したのち
ext_tsk() で終了

2021/08/01

TOPPERSプロジェクト認定79

sw_int_api : Cソースファイル（sw_int_api.c）• タスクの終了– ext_tskは明示的に呼び出さない場合でも，タスクの終了時に自動的に呼び出される
void
led1_task(intptr_t exinf){
int i;
syslog(LOG_NOTICE,"led1_task : start!");for (i = 0; i < 4; i++) {if((led_data & LED01) == LED01){
led_data &= ~LED01;} else {led_data |= LED01;}
led_out(led_data);
dly_tsk(LED1_INTERVAL);}
syslog(LOG_NOTICE,"led1_task : done!");ext_tsk(); ←ITRON仕様書 : P82(PDF P100)}
2021/08/01

TOPPERSプロジェクト認定80

sw_int_api : 割込みコールバック関数• SW1割込みコールバック関数
void
sw_int(void){switch_push_clear();syslog(LOG_NOTICE,"sw1_int: start!");
SVC_PERROR(act_tsk(MAIN_TASK));}• 割込みハンドラや周期ハンドラ等の非タスクコンテキスト
ではiが先頭に付くAPIのみが使用できる• 通常のAPI（act_tsk）を使うとAPIは実行されず、コンテキ
ストエラー（E_CTX）が返される• APIの使用ミスを防ぐためには，戻り値のチェック（正常終了のE_OKかどうか）が必要• SVC_PERROR()マクロにより実現
2021/08/01

TOPPERSプロジェクト認定81

sw_int_api : サービスコールチェックマクロ• t_perror関数を用いたマクロでエラーのログを表示/** サービスコールのエラーのログ出力*/
void
svc_perror(const char *file, int_t line, const char *expr, ER ercd){
if (ercd < 0) {t_perror(LOG_ERROR, file, line, expr, ercd);}}#define SVC_PERROR(expr) svc_perror(__FILE__, __LINE__, #expr, (expr))• t_perror関数はercdからエラー内容を変換して表示する関数です• SVC_PERRORマクロを作成しサービスコールのエラー
チェックができます
2021/08/01

TOPPERSプロジェクト認定82

sw_int_api : その他の修正• インターバル設定を1000から500へ#define LED1_INTEVAL 500• コンフィギュレーションファイル（sw_int.cfg）• SW1の割込みコールバック関数は device.h で定義済み
CRE_TSK(MAIN_TASK, { TA_NULL, 0, led1_task,
DEFAULT_PRIORITY,
STACK_SIZE, NULL });DEF_INH(INHNO_SW1, { TA_NULL, sw_int });CFG_INT(INTNO_SW1, { TA_ENAINT | INTATR_SW1, INTPRI_SW1});
2021/08/01

TOPPERSプロジェクト認定83

sw_int_api : SVC_PERRORによる引数チェック• エラーが発生するサービスコールに書き換えて、戻り値がE_OK以外で正しくエラーログが表示されるかの確認を行
います void
sw1_int(void){switch_push_clear();syslog(LOG_NOTICE,"sw1_int : start!");
SVC_PERROR(act_tsk(MAIN_TASK));
}

SW1プッ
シュ

2021/08/01

TOPPERSプロジェクト認定84

sw_int_api : 起動要求のキューイング
• 起動要求はキューイングされます••

SW1割込みハンドラのiact_tsk()をSVC_PERROR付きに書き換える
LED1点滅タスクが起動している間にもう一度SW1割込みを入れてLED1点
滅タスクに起動要求を出す

起動要求1回目
LED1点滅タスク再起動
起動要求2回目
LED1点滅タスク起動••

実行可能状態のタスクに，起動要求を出すとその要求はキューイン
グされる
起動要求がキューイングされていると，タスクが終了した後，再びタ
スク先頭から実行される

2021/08/01

TOPPERSプロジェクト認定85

sw_int_api ： キューイング回数• SW1を連続して3回押して起動要求を3回発行する••

SW1割込みハンドラを3回以上起動して起動要求を発行すると起動要
求は無視され、キューイングオーバーフローエラー（E_QOVR）が返される
キューイング回数には上限がある– TOPPERS/ASPカーネルではタスク起動のキューイング回数は1回
起動要求1回目

起動要求2回目
LED1点滅タスク起動
起動要求3回目

エラー
2021/08/01

TOPPERSプロジェクト認定86

演習:割込みハンドラからのAPIの呼び出し（sw_int_api2）• タスクの起動要求と同様に，タスクの起床要求もキューイ
ングされる• タスクの起動要求のキューイングを確認するため，プロ
グラムを変更して、SW1割込みハンドラからタスクを起床させることで、LED1を点滅させるように変更• タスクは実行可能状態で生成する必要がある• sw_int_apiをmy_program上でコピーして名前を
sw_int_api2に変更して作成する
CRE_TSK(MAIN_TASK, { TA_ACT, 0, led1_task,
DEFAULT_MAIN_PRIORITY,
STACK_SIZE, NULL });2021/08/01

TOPPERSプロジェクト認定87

sw_int_api2 : Cソースファイル（sw_int_api.c）• 起動されると slp_tsk により起床待ち状態となる• 起床すると，LED1を2回点灯させる
void
led1_task(intptr_t exinf){
int i;for (;;) {syslog(LOG_NOTICE,"led1_task : sleep!");slp_tsk();syslog(LOG_NOTICE,"led1_task : wakeup!");for (i = 0; i < 4; i++) {if ((led_data & LED01) == LED01) {led_data &= ~LED01;} else {led_data |= LED01;}
led_out(led_data);
dly_tsk(LED1_INTERVAL);}}}
2021/08/01

TOPPERSプロジェクト認定88

sw_int_api2 : 割込みハンドラ• iwup_tsk() により led1_task を起床させる
void
sw_int(void){switch_push_clear();syslog(LOG_NOTICE,"sw_int : start!");
SVC_PERROR(iwup_tsk(MAIN_TASK));}• 起床要求のキューイング回数は起動要求と同じく1回

2021/08/01

TOPPERSプロジェクト認定89CPUロック状態（割込みの禁止・許可）• 全ての割り込みとディスパッチを禁止する状態• タスク間，タスク-割込みハンドラ間，割込みハンドラ間の排他制御を実現する– タスク間は，セマフォで排他制御した方がよい• カーネル起動時は，CPUロック解除状態• 時間制約のある処理のため一定時間プロセッサを占有するためにも用いられる– 例）デバイスの設定• CPUロック状態では，一部の例外（CPUロック解除，状態参照）を除いてシステムコールを呼び出せない• システムコール• CPUロック状態への移行• CPUロック状態の解除

loc_cpu()

unl_cpu()

2021/08/01

TOPPERSプロジェクト認定90

演習 : CPUロック状態（cpu_lock）• CPUロック状態の機能を確認するプログラムを作成する• プログラム仕様– タスク（dip_task）は実行可能状態で生成し，5秒単位に割込み禁止状態と割込み許可状態を繰り返す• 割込み禁止状態では「INT DISABLE !」を表示:LED1オン• 割込み許可状態では「INT ENABLE !」を表示：LED1オフ• 一定時間はビジーループにより生成する– タスクは常に実行状態とする– SW1割り込みにより割込みハンドラ（sw1_int）を実行する• 割込みハンドラは起動したことが分かるようにログを出力• 確認事項– CPUロック状態では割込みハンドラが実行されないことを確認– CPUロック中に発生した割込みはCPUロック解除後にどうなるか

2021/08/01

TOPPERSプロジェクト認定91

cpu_lock : タスク（dip_task）• ５秒毎に割込み禁止と許可を繰り返すプログラムを作成

INT DISABLE ! を表示

void dip_task(intptr_t exinf){
５秒間割込み禁止
dly_tsk(500);
for(;;){
syslog(LOG_EMERG, “INT_DISABLE !”);
led_out(LED01);
loc_cpu();
INT ENABLE !を表示
int_delay(D5SEC);
５秒間割込み許可
led_out(0):unl_cpu();
syslog(LOG_EMERG, “INT ENABLE !”);
int_delay(D5SEC);}}

2021/08/01

TOPPERSプロジェクト認定92

cpu_lock : 割込みハンドラ• 起動するとログを出力
void
sw_int(void){switch_push_clear(); /* 割込みクリア */syslog_0(LOG_NOTICE,"sw_int : start!");}2021/08/01

TOPPERSプロジェクト認定93

cpu_lock : コンフィギュレーションファイル• タスク生成と割込みハンドラの登録
CRE_TSK(MAIN_TASK, { TA_ACT, (VP_INT) 0, dip_task,
DEFAULT_MAIN_PRIORITY,
STACK_SIZE, NULL });DEF_INH(INHNO_SW1, { TA_HLNG, sw_int });CFG_INT(INTNO_SW1, {TA_ENAINT|INTATR_SW1, INTPRI_SW1});• 初期化ルーチン– ディップスイッチとプッシュスイッチの初期化はdevice.cfgにて登録済です

2021/08/01

TOPPERSプロジェクト認定94

RTOS基本プログラム実習 : まとめ
•
•

タスク生成
デバッグ方法–••プロジェクトの作成方法
マルチタスクプログラミング–••

forループ, dly_tsk（）, コード共有 ,初期化ルーチン

周期ハンドラ
割込みハンドラ––•タスクモニタ, printf（）デバッグ

割込みの禁止戻り値のチェック（SVC_PERROR()）, 起動・起床要求のキューイ
ング

組込みプログラム開発では、闇雲なprintf()デバッグより，コードを注意深くチェックした方が効率的

2021/08/01

TOPPERSプロジェクト認定95

同期通信機能プログラミング実習

1. 実習内容の説明
2. セマフォによる排他制御
3. イベントフラグによる事象通知
4. データキューによる事象通知
2021/08/01

TOPPERSプロジェクト認定

96

RTOS同期･通信機能プログラミング実習• TOPPERS/ASPカーネルを用いてRTOSの同期・通信機
能を用いたプログラミングを学ぶ• セマフォ
– タスク間の排他制御をしないプログラムの解説– 上記プログラムへのセマフォによる排他制御追加• イベントフラグ– イベントフラグによる事象通知を行うプログラムの作成• データキュー– イベントフラグを用いたプログラムをデータキューにより書き換え

2021/08/01

TOPPERSプロジェクト認定97プログラムファイル• プログラムファイルの置き場所– /program2
ex_none

排他制御なし2タスク出力プログラム

ex_semセマフォによる排他制御あり2タスクプログラム

sw_flg_cyc

イベントフラグによる通知プログラム（周期ハンドラから）

sw_flg_tsk
sw_dtq_cyc

イベントフラグによる通知プログラム（タスクから）
データキューによる通知プログラム（周期ハンドラから）

sw_dtq_tsk

データキューによる通知プログラム（タスクから）

2021/08/01

TOPPERSプロジェクト認定98同期通信機能プログラミング実習

1. 実習内容の説明
2. セマフォによる排他制御
3. イベントフラグによる事象通知
4. データキューによる事象通知
2021/08/01

TOPPERSプロジェクト認定99

演習 : 排他制御なし2タスク出力プログラム（ex_none）• 排他制御を行っていないプログラムを実行する
•

•
•
•

同じコードを共有する2つのタスク（タスク1とタスク２）がforループで時間を作りながらグローバル変数countを関数busy_wait_inc()の引数として渡し，その戻り値をcountに入れる
同時にローカル変数local_countをインクリメントする
2つのタスクは，一定時間で実行を切り替える（方法は後述）
2つのタスクでインクリメントするcount は local_count の倍となる
int count = 0;
voidtask(intptr_t exinf){
int local_count = 0;
for (;;) {count = busy_wait_inc(count);
local_count = busy_wait_inc(local_count);syslog_3(LOG_NOTICE, "Task %d : count = %d, local_count = %d",exinf, count, local_count);}}

2021/08/01

TOPPERSプロジェクト認定100

ex_none : busy_wait_inc• busy_wait_incは引数をインクリメントして，一定時間経過
してから返す（作為的な）関数#define DELAY_LOOP (250*1000) /* 250ms */busy_wait_inc(int e){long i;e++;for(i = 0; i < DELAY_LOOP; i++);sil_dly_nse(1000);
return e;}• タスクは関数 task のタスクを2個作成
CRE_TSK(MAIN_TASK, { TA_ACT, 1, task,
DEFAULT_PRIORITY, STACK_SIZE, NULL });CRE_TSK(TASK2, { TA_ACT, 2, task,
DEFAULT_PRIORITY, STACK_SIZE, NULL });2021/08/01

TOPPERSプロジェクト認定101

ex_none : irot_rdq()• このままでは，片方のタスクしか動作しないため，10m周期で起動する周期ハンドラでタスクの優先順位の回転を行う
irot_rdq() を実行することで，10m毎にタスクを切り替える
優先度8
void
rot_cyc_handler(void){
SVC_PERROR(irot_rdq(DEFAULT_PRIORITY));}

周期ハンドラ優先順位

irot_rdq(8)優先度4

タスクモニタ

優先度8

task1

2021/08/01

優先順位

task2

TOPPERSプロジェクト認定

優先度4

タスクモニタ

優先度8

task2

102

task1

ex_none : 実行
• 二つのタスクでインクリメントする count が local_count と同
じ増加量となってる– busy_wait_inc()実行中に周期ハンドラが動作してirot_rdq()によりタ
スク切り替えが発生した場合、片方のタスクがcountを更新する前にcountを読み込むため• countの増加を正しくするためには，countへのアクセス（読み込みと更新の間）を排他制御する必要がある
countが正しく
インクリメント
されない

2021/08/01

TOPPERSプロジェクト認定103

演習 : セマフォによる排他制御プログラム（ex_sem）• ex_noneを改造してセマフォによる排他制御を行うプログ
ラムを作成する• 作成方法– ex_noneをmy_programにコピーして名前をex_semに変更– ex_sem内の以下のプログラムをリネーム• ex_none.c →ex_sem.c• ex_none.cfg →ex_sem.cfg• ex_none.h →ex_sem.h– Makefileの156行目ex_noneをex_semに書き換え– ex_sem.cfgの10行目ex_noneをex_semに書き換え– ex_sem.cの9行目ex_none.hをex_sem.hに書き換え• ex_semディレクトリ上でmakeを行って確認
2021/08/01

TOPPERSプロジェクト認定104

演習 : セマフォによる排他制御プログラム（ex_sem）• 共有変数 count の更新をセマフォで排他制御する• セマフォ生成API– 属性はTA_NULL(FIFO順)を指定します– 初期値，最大値は排他制御対象の資源の性質によって適切に
設定する
属性

初期値

最大数

CRE_SEM(ID semid, {ATR sematr, unit_t isemcnt, uint_t maxsem});• セマフォ操作API
wai_sem(ID semid)
sig_sem(ID semid)

2021/08/01: セマフォ資源の獲得: セマフォ資源の返却

TOPPERSプロジェクト認定105

ex_sem ： Cソースファイルとコンフィギュレーションファイル• Cソースファイル（ex_sem.c）voidtask(VP_INT exinf){
int local_count = 0;
for (;;) {wai_sem(SEM_COUNT);
count = busy_wait_inc(count);
sig_sem(SEM_COUNT);
local_count = busy_wait_inc(local_count);
....
}
}

• コンフィギュレーションファイル（ex_sem.cfg）• 初期状態では資源は使用可能なので初期値は1• 資源は最大で1個なので最大値は1
CRE_SEM(SEM_COUNT, {TA_NULL, 1, 1});2021/08/01

TOPPERSプロジェクト認定106

ex_sem : 実行結果
• 排他制御によりcountがlocal_countの倍の頻度で更新されることが確認できる• count更新中にタスクが切り替わっても，他のタスクはセマフォを取得できないない• 他の方法– ディスパッチ禁止状態やCPUロック状態でも排他制御が可能– ディスパッチ禁止 ： dis_dsp()/ena_dsp()– CPUロック: loc_cpu()/unl_cpu
セマフォを使う場合との相違点は?
2021/08/01

TOPPERSプロジェクト認定107

ex_sem : 排他制御の実現方法• 各排他制御方法の違いを理解して使用する必要がある• 割込みハンドラとの排他制御– タスク・割込みハンドラ間，割込みハンドラ間の排他制御はCPU
ロック状態でなければ実現できない• 影響範囲– CPUロック状態やディスパッチ禁止状態は，資源に関係ないタス
クや割込みハンドラへ影響を及ぼす– セマフォは資源に関連するタスク間でのみの排他制御を実現する• 割込み応答時間– CPUロック状態を長時間使用すると割込み応答性が悪くなる• プロセッサの占有– デバイス等の初期化で，プログラムの実行を中断なく実行したい
場合には，CPUロック状態を用いる必要がある
2021/08/01

TOPPERSプロジェクト認定108

同期通信機能プログラミング実習

1. 実習内容の説明
2. セマフォによる排他制御
3. イベントフラグによる事象通知
4. データキューによる事象通知

2021/08/01

TOPPERSプロジェクト認定109

演習 : イベントフラグによる通知プログラム（sw_flg_cyc）• イベントフラグと周期ハンドラを使ってディップスイッチの状態をLEDに反映させるプログラムを作成する• プログラムの仕様– 周期ハンドラ• DIPSW1,2の状態を周期的に監視し，状態が変化したらタス
クにイベントフラグで通知する• イベントフラグをセットするタイミングはスイッチの状態が変化した場合のみが望ましいですが，常に周期ハンドラでス
イッチの状態を設定しても問題ない– タスク• イベントフラグ待ちとなりイベントフラグによる通知があれば，その通知に従ってLEDの状態を変更する– 初期状態• 初期化ルーチンで設定する
2021/08/01

TOPPERSプロジェクト認定110

演習 : イベントフラグによる通知プログラム• program上のsw_flg_cycをmy_programにコピーする• sw_flg_cycをビルドして、ROMモニタのldコマンドでダウ
ンロード• goコマンドで実行する
DIP SWを操作するとイベントフラグのロ
グを表示する2021/08/01

TOPPERSプロジェクト認定111

sw_flg_cyc : イベントフラグ関連のAPI• イベントフラグ生成API– 属性はTA_CLRを指定する
属性

初期値

CRE_FLG(ID flgid, {ATR flgatr, FLGPTN iflgptn});• イベントフラグ操作API
•

フラグ待ち

待ちパターン

TWF_ORW

ビット
パターン

wai_flg(ID flgid, FLGPTN waiptn, MODE wfmode, FLGPTN *p_flgptn)•

フラグのセット

設定ビットパターン（論理和となる）

set_flg(ID flgid, FLGPTN setptn )2021/08/01

TOPPERSプロジェクト認定112

sw_flg_cyc : イベントへの割り付け• フラグの各ビットにイベントを割り付ける#define LED1_ON
0x0001#define LED1_OFF 0x0002#define LED2_ON
0x0004#define LED2_OFF 0x0008#define LED_EV_MASK 0x000f• スイッチの状態変化でイベントフラグをセットするためは
前回スキャンしたスイッチ状態を記憶しておく必要がある

2021/08/01

TOPPERSプロジェクト認定113

sw_flg_cyc : 初期化ルーチン• 起動時のスイッチの状態をLEDに設定• 初期化ルーチンをATT_INIでコンフィギュレーションファ
イルに登録する
unsigned short led_data;
unsigned int sw_state;void
state_init(intptr_t exinf){
led_data = 0;
sw_state = switch_dip_sense();if ((sw_state & DSW1) == DSW1) {led_data |= LED01;}
if ((sw_state & DSW2) == DSW2) {led_data |= LED02;}
led_out(led_data);}
2021/08/01

TOPPERSプロジェクト認定114

sw_flg_cyc : 周期ハンドラ• ディップスイッチの状態をチェックし，変更があればイベン
トフラグにより通知する
void sw_cyc_handler(intptr_t exinf){
unsigned int tmp;
FLGPTN flgptn = 0;
tmp = switch_dip_sense();if ((sw_state & DSW1) != (tmp & DSW1)) {if ((tmp & DSW1) == DSW1) {flgptn |= LED1_ON;} else {flgptn |= LED1_OFF;}}... 省略 ...
if (flgptn != 0) {SVC_PERROR(iset_flg(SW_FLG, flgptn));
sw_state = tmp;}}
2021/08/01

TOPPERSプロジェクト認定• 状態に変更があればフラグで通知

115

sw_flg_cyc : タスク• イベントフラグによりスイッチの変更を受け取り，LEDを
設定する
void
いずれかの
全イベントOR
led_task(intptr_t exinf){
イベントがセットFLGPTN flgptn;
されたら起床for(;;) {wai_flg(SW_FLG, SW_EV_MASK, TWF_ORW, &flgptn);
syslog_1(LOG_NOTICE, "led_task : eventflag pattern = 0x%x", flgptn);
if ((flgptn & LED1_ON) == LED1_ON) {led_data |= LED01;}
if ((flgptn & LED1_OFF) == LED1_OFF) {led_data &= ~LED01;}... 省略 ...
led_out(led_data);}}
2021/08/01

TOPPERSプロジェクト認定116

sw_flg_cyc : コンフィギュレーションファイル• フラグの生成– 初期状態は何もセットされていないとする
CRE_FLG(SW_FLG, {TA_CLR, 0});• プログラム実行– DIPSWの状態が変更されると– イベントフラグで通知される

2021/08/01

TOPPERSプロジェクト認定117

演習 :イベントフラグによる通知プログラム• sw_flg_cycを改造してタスクからイベントフラグを通知するプログラムを作成する• 作成方法
– sw_flg_cycをmy_programにコピーして名前をsw_flg_tskに変更– sw_flg_tsk内の以下のプログラムをリネーム• sw_flg_cyc.c →sw_flg_tsk.c• sw_flg_cyc.cfg →sw_flg_tsk.cfg• sw_flg_cyc.h →sw_flg_tsk.h– Makefileの156行目sw_flg_cycをsw_flg_tskに書き換え– sw_flg_tsk.cfgの16行目sw_flg_cycをsw_flg_tskに書き換え– sw_flg_tsk.cの10行目sw_flg_cyc.hをsw_flg_tsk.hに書き換え• sw_flg_tskディレクトリ上でmakeを行って確認

2021/08/01

TOPPERSプロジェクト認定118

演習 : イベントフラグによる通知プログラム（sw_flg_tsk）• イベントフラグとタスクを使ってディップスイッチの状態をLEDに反映させるプログラムをsw_flg_cycをもとに作成する• プログラムの仕様– 監視タスク• DIPSW1,2の状態を周期的に監視し，状態が変化したらタス
クにイベントフラグで通知する• イベントフラグをセットするタイミングはスイッチの状態が変
化した場合
– タスク
• イベントフラグ待ちとなりイベントフラグによる通知があれば，その通知に従ってLEDの状態を変更する– 初期状態• 初期化ルーチンで設定する
2021/08/01

TOPPERSプロジェクト認定119sw_flg_tsk : 監視タスク• タスク実行でディップスイッチの状態をチェックし，変更があればイベントフラグにより通知する
void sw_task(intptr_t exinf){
unsigned int tmp;
FLGPTN flgptn;
for(;;){
tmp = switch_dip_sense();flgptn = 0;
if ((sw_state & DSW1) != (tmp & DSW1)) {if ((tmp & DSW1) == DSW1) {flgptn |= LED1_ON;... 省略 ...
if (flgptn != 0) {SVC_PERROR(set_flg(SW_FLG, flgptn));
sw_state = tmp;}
dly_tsk(SW_SCAN_INTERVAL);}

2021/08/01

TOPPERSプロジェクト認定• 状態に変更があればフラグで通知

120

sw_flg_tsk ： その他の修正• インクルードファイル（sw_flg_tsk.h）#ifndef TOPPERS_MACRO_ONLY
extern void led_task(intptr_t exinf);
extern void sw_task (intptr_t exinf);
extern void state_init(intptr_t exinf);#endif /* TOPPERS_MACRO_ONLY */• コンフィギュレーションファイル（sw_flg_tsk.cfg）• sw_taskをCRE_TASKで定義#include “device.h”#include “sw_flg_tsk.h”
CRE_TSK(MAIN_TASK, {TA_ACT, 1, led_task,
DEFAULT_PRIORITY, STACK_SIZE, NULL});
CRE_TSK(SW_TASK, {TA_ACT, 0, sw_task,
DEFAULT_PRIORITY, STACK_SIZE, NULL});
ATT_INI(TA_NULL, 0, state_init});2021/08/01

TOPPERSプロジェクト認定121

同期通信機能プログラミング実習

1. 実習内容の説明
2. セマフォによる排他制御
3. イベントフラグによる事象通知
4. データキューによる事象通知

2021/08/01

TOPPERSプロジェクト認定122

演習 :データキューによる通知プログラム（sw_dtq_cyc）• sw_flg_cycを改造してタスクからイベントフラグを通知するプログラムを作成する• 作成方法
– sw_flg_cycをmy_programにコピーして名前をsw_dtq_cycに変更– sw_dtq_cyc内の以下のプログラムをリネーム• sw_flg_cyc.c →sw_dtq_cyc.c• sw_flg_cyc.cfg →sw_dtq_cyc.cfg• sw_flg_cyc.h →sw_dtq_cyc.h– Makefileの156行目sw_flg_cycをsw_dtq_cycに書き換え– sw_dtq_cyc.cfgの16行目sw_flg_cycをsw_dtq_cycに書き換え– sw_dtq_cyc.cの10行目sw_flg_cyc.hをsw_dtq_cyc.hに書き換え• sw_dtq_cycディレクトリ上でmakeを行って確認

2021/08/01

TOPPERSプロジェクト認定123

演習 : データキューによる通知プログラム（sw_dtq_cyc）• イベントフラグによる通知プログラムをデータキューにより通知するように書き換える• データキュー生成静的API– 属性はTA_NULL– バッファ場所はNULL

バッファ数

バッファ場所

CRE_DTQ(ID dtqid, {ATR dtqatr, uint_t dtqcnt, void *dtq});• データキュー操作API•

送信
snd_dtq(ID dtqid, intptr_t data)

•

属性

受信
rcv_dtq(ID dtqid, intptr_t *p_data )2021/08/01

TOPPERSプロジェクト認定

送信データ
受信データ入れる変数のポインタ124

sw_dtq_cyc : 周期ハンドラ• スイッチの状態が変化したらデータキューにデータを送る
void sw_cyc_handler(intptr_t exinf){
unsigned int tmp = switch_dip_sense();if ((sw_state & DSW1) != (tmp & DSW1)) {if ((tmp & DSW1) == DSW1) {SVC_PERROR(ipsnd_dtq(SW_DTQ, LED1_ON));} else {SVC_PERROR(ipsnd_dtq(SW_DTQ, LED1_OFF));}}
if ((sw_state & SW2) != (tmp & SW2)) {if ((tmp & DSW2) == DSW2) {SVC_PERROR(ipsnd_dtq(SW_DTQ, LED2_ON));} else {SVC_PERROR(ipsnd_dtq(SW_DTQ, LED2_OFF));}}sw_state = tmp;}
2021/08/01

TOPPERSプロジェクト認定125

sw_dtq_cyc : タスク• データキューからデータを受け取り，LEDをセットする
void led_task(intptr_t exinf){
int sw_data;for (;;) {rcv_dtq(SW_DTQ, &sw_data);
syslog_1(LOG_NOTICE, "led_task : switch changed = 0x%x", sw_data);
if (sw_data == LED1_ON) {led_data |= LED01;}else if (sw_data == LED1_OFF) {led_data &= ~LED01;}else if (sw_data == LED2_ON) {led_data |= LED02;}else if (sw_data == LED2_OFF) {led_data &= ~LED02;}
led_out(led_data);}}
2021/08/01

TOPPERSプロジェクト認定126

sw_dtq_cyc : コンフィギュレーションファイル• sw_dtq_cyc.cfg
CRE_DTQ(SW_DTQ,{TA_NULL, 2, NULL});

宿題：
イベントフラグによる通知プログラムと同様にスイッチのスキャンを周期ハンドラではなくタスク（sw_task）で行
うようにプログラムを変更する（sw_dtq_tsk）

2021/08/01

TOPPERSプロジェクト認定

127

RTOS同期･通信機能プログラミング実習 : まとめ• ITRONの同期・通信機能を用いたプログラミング– セマフォによる排他制御• タスクの優先順位の回転 irot_rdq()– イベントフラグによる事象通知• 周期ハンドラ、タスク間• タスク間– データキューによる事象通知• 周期ハンドラ、タスク間• タスク間2021/08/01

TOPPERSプロジェクト認定

128

まとめ

2021/08/01

TOPPERSプロジェクト認定

129

TOPPERS/ASP導入実習のまとめ• コンパイルやリンク等の開発環境とターゲットボードがあれ
ば、比較的簡単にTOPPERS/ASPの動作確認が行える• ソースが供給されているので、ＲＴＯＳのしくみを理解しやすい、問題発生時もソースを用いた問題解析が可能である• ＲＴＯＳを使用する中規模組込み開発では、多人数の開発者が分業して多くのプログラム開発やミドルウェアの導入を行うことが多い、タスクモニタをシステム用に機能拡張し、問題発生時に、問題の要因を簡単に判別できる開発環境を用意していくことが、開発効率や品質の向上につながる

2021/08/01

TOPPERSプロジェクト認定130

基礎２実習通信講座終了の方へ• my_programには、以下のディレクトリができ正しくプログラ
ムが実行されているはずです• my_programをzip圧縮して、TOPPERS事務局に送り、講座終了判定を行ってください
実習済プログラムcpu_lockex_semled_1task
led_2tasks
led_2tasks_for
led_cycsw_dtq_cyc
sw_flg_tsk
sw_int_api
sw_int_api2
sw_int2
2021/08/01(sw_dtq_tskは無くても良い): CPUロック確認プログラム（コピー）: LEDカウント排他制御あり: １タスクLED点滅プログラムデバッグ確認: ２タスクLED点滅プログラム完成版: ２タスクLED点滅改造初版: １タスクと周期ハンドラによるLED点滅: SW制御を周期ハンドラからデータキュー通信: SW制御をタスクからイベントフラグ通信: プッシュスイッチ割込みタスク起動: プッシュスイッチ割込みタスク起床:プッシュスイッチ割込み
TOPPERSプロジェクト認定131

著者リスト• 実装開発環境• 竹内 良輔（（株）リコー）• RTOSの基礎プログラミング実習１• RTOSの基礎プログラミング実習２• 同期通信機能プログラミング実習• 本田 晋也（名古屋大学）• 竹内 良輔（（株）リコー）• STM32F401 nucleoボード対応• 竹内 良輔（（株）リコー）

2021/08/01

TOPPERSプロジェクト認定

132

謝辞
本教材の開発において、NPO法人組込みソフトウェア管理者・技術者育成研究会およびNPO法人TOPPERSプロ
ジェクトの作成した以下の教材を参考としました．
– OpenSESSAME Seminar組込みソフトウェア技術者･管理者向けセミナー初級者向けテキスト第5版– TOPPERS初級実装セミナー教材
両団体および上記教材の作者の皆様へ感謝します．
本教材の開発において、 NEXCESS初級コースおよび指導者養成コースの受講者の皆様のコメントを参考としました．
両コースの受講者の皆様へ感謝します．

2021/08/01

TOPPERSプロジェクト認定133