• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

C言語でBBC micro:bit V2およびDFRobot micro:Maqueenを操作する


Commit MetaInfo

Revisión97f55ec28b363b9db68581c7609fda1ea77b9bff (tree)
Tiempo2023-09-14 06:51:08
Autorxm6_original <tanaka_yasushi2008@yaho...>
Commiterxm6_original

Log Message

ミュージックドライバまで

Cambiar Resumen

Diferencia incremental

--- a/nRFHello/.cproject
+++ b/nRFHello/.cproject
@@ -87,7 +87,7 @@
8787 <option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.warning.missingprototypes.39027230" name="Warn if a global function has no prototype (-Wmissing-prototypes)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.warning.missingprototypes" useByScannerDiscovery="true" value="true" valueType="boolean"/>
8888 <option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.warning.badfunctioncast.802810021" name="Warn if wrong cast (-Wbad-function-cast)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.warning.badfunctioncast" useByScannerDiscovery="true" value="true" valueType="boolean"/>
8989 <option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.warning.strictprototypes.55888613" name="Warn if a function has no arg type (-Wstrict-prototypes)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.warning.strictprototypes" useByScannerDiscovery="true" value="true" valueType="boolean"/>
90- <option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.otheroptimizations.379956610" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.otheroptimizations" value="-fsingle-precision-constant" valueType="string"/>
90+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.otheroptimizations.379956610" name="その他の最適化フラグ" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.otheroptimizations" useByScannerDiscovery="true" value="-fsingle-precision-constant" valueType="string"/>
9191 <inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input.59146624" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input"/>
9292 </tool>
9393 <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.894778314" name="GNU Arm Cross C++ Compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler">
@@ -100,7 +100,10 @@
100100 <option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.defs.1680054453" name="定義済みシンボル (-D)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.defs" useByScannerDiscovery="true" valueType="definedSymbols">
101101 <listOptionValue builtIn="false" value="DEBUG"/>
102102 <listOptionValue builtIn="false" value="TRACE"/>
103+ <listOptionValue builtIn="false" value="OS_USE_TRACE_SEMIHOSTING_STDOUT"/>
104+ <listOptionValue builtIn="false" value="NRF52833_XXAA"/>
103105 </option>
106+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.warnabi.1516595037" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.warnabi" value="false" valueType="boolean"/>
104107 <inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input.161133683" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input"/>
105108 </tool>
106109 <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker.1340459132" name="GNU Arm Cross C Linker" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker">
@@ -219,6 +222,16 @@
219222 <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.size.698871301" name="Size command" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.size" value="size" valueType="string"/>
220223 <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.make.543432284" name="ビルド・コマンド" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.make" value="make" valueType="string"/>
221224 <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.rm.1313472073" name="Remove command" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.rm" value="rm" valueType="string"/>
225+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi.276165612" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi.hard" valueType="enumerated"/>
226+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit.43487436" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit.fpv4spd16" valueType="enumerated"/>
227+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.uninitialized.1838683092" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.uninitialized" value="true" valueType="boolean"/>
228+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.missingdeclaration.1471617354" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.missingdeclaration" value="true" valueType="boolean"/>
229+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.conversion.1000939115" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.conversion" value="true" valueType="boolean"/>
230+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.pointerarith.1755960847" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.pointerarith" value="true" valueType="boolean"/>
231+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.shadow.1404970943" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.shadow" value="true" valueType="boolean"/>
232+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.logicalop.1416267589" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.logicalop" value="true" valueType="boolean"/>
233+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.floatequal.2015684798" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.floatequal" value="true" valueType="boolean"/>
234+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.padded.1699569031" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.warnings.padded" value="false" valueType="boolean"/>
222235 <targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform.773906421" isAbstract="false" osList="all" superClass="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform"/>
223236 <builder buildPath="${workspace_loc:/nRFHello}/Release" id="ilg.gnuarmeclipse.managedbuild.cross.builder.36652053" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make ビルダー" superClass="ilg.gnuarmeclipse.managedbuild.cross.builder"/>
224237 <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler.342206795" name="GNU Arm Cross Assembler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler">
@@ -243,7 +256,12 @@
243256 </option>
244257 <option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.defs.644095446" name="定義済みシンボル (-D)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.defs" useByScannerDiscovery="true" valueType="definedSymbols">
245258 <listOptionValue builtIn="false" value="NDEBUG"/>
259+ <listOptionValue builtIn="false" value="NRF52833_XXAA"/>
246260 </option>
261+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.otheroptimizations.1155659942" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.otheroptimizations" value="-fsingle-precision-constant" valueType="string"/>
262+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.warning.missingprototypes.603782387" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.warning.missingprototypes" value="true" valueType="boolean"/>
263+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.warning.strictprototypes.1934558844" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.warning.strictprototypes" value="true" valueType="boolean"/>
264+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.warning.badfunctioncast.1880518477" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.warning.badfunctioncast" value="true" valueType="boolean"/>
247265 <inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input.1426178694" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input"/>
248266 </tool>
249267 <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.3867943" name="GNU Arm Cross C++ Compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler">
@@ -255,7 +273,9 @@
255273 </option>
256274 <option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.defs.1367930683" name="定義済みシンボル (-D)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.defs" useByScannerDiscovery="true" valueType="definedSymbols">
257275 <listOptionValue builtIn="false" value="NDEBUG"/>
276+ <listOptionValue builtIn="false" value="NRF52833_XXAA"/>
258277 </option>
278+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.std.1900154255" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.std" value="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.std.gnucpp14" valueType="enumerated"/>
259279 <inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input.706143826" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input"/>
260280 </tool>
261281 <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker.609428063" name="GNU Arm Cross C Linker" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker">
@@ -282,11 +302,13 @@
282302 </option>
283303 <option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.scriptfile.366703270" name="スクリプト・ファイル (-T)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.scriptfile" valueType="stringList">
284304 <listOptionValue builtIn="false" value="mem.ld"/>
285- <listOptionValue builtIn="false" value="libs.ld"/>
286305 <listOptionValue builtIn="false" value="sections.ld"/>
287306 </option>
288307 <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nostart.955404113" name="標準開始ファイルを使用しない (-nostartfiles)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nostart" value="true" valueType="boolean"/>
289308 <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usenewlibnano.628835414" name="Use newlib-nano (--specs=nano.specs)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usenewlibnano" value="true" valueType="boolean"/>
309+ <option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.flags.240737852" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.flags" valueType="stringList">
310+ <listOptionValue builtIn="false" value="--no-warn-rwx-segments"/>
311+ </option>
290312 <inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.input.1847511563" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.input">
291313 <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
292314 <additionalInput kind="additionalinput" paths="$(LIBS)"/>
--- a/nRFHello/.gitignore
+++ b/nRFHello/.gitignore
@@ -1,3 +1,4 @@
11 /Debug/
22 /src/html/
33 /.settings/
4+/Release/
--- a/nRFHello/include/pf_gpio.h
+++ b/nRFHello/include/pf_gpio.h
@@ -48,6 +48,8 @@ typedef enum PF_GPIO_ID_Tag
4848 PF_GPIO_ID_INTERNAL_SDA, //!< 内部I2Cバス SDA
4949 PF_GPIO_ID_EXTERNAL_SCL, //!< 外部I2Cバス SCL
5050 PF_GPIO_ID_EXTERNAL_SDA, //!< 外部I2Cバス SDA
51+ PF_GPIO_ID_INTERNAL_SPEAKER, //!< 内部スピーカー
52+ PF_GPIO_ID_MAQUEEN_SPEAKER, //!< MAQUEEN スピーカー
5153 PF_GPIO_ID_MAQUEEN_LED_L, //!< MAQUEEN LED L
5254 PF_GPIO_ID_MAQUEEN_LED_R, //!< MAQUEEN LED R
5355 PF_GPIO_ID_MAQUEEN_PATROL_L, //!< MAQUEEN PATROL L
--- a/nRFHello/include/pf_interrupt.h
+++ b/nRFHello/include/pf_interrupt.h
@@ -35,6 +35,7 @@ typedef enum PF_INTERRUPT_PRI_Tag
3535 PF_INTERRUPT_PRI_DISPLAY_TIMER, //!< Display Timer
3636 PF_INTERRUPT_PRI_I2C_INT, //!< I2C(内部)
3737 PF_INTERRUPT_PRI_I2C_EXT, //!< I2C(外部)
38+ PF_INTERRUPT_PRI_MUSIC, //!< 音楽演奏
3839 } PF_INTERRUPT_PRI;
3940
4041 //! @brief グローバル割り込み禁止
--- a/nRFHello/include/pf_motor.h
+++ b/nRFHello/include/pf_motor.h
@@ -33,7 +33,7 @@ typedef enum PF_MOTOR_DIR_Tag
3333 PF_MOTOR_DIR_FORWARD, //!< 前進
3434 PF_MOTOR_DIR_LEFT, //!< 左回転
3535 PF_MOTOR_DIR_RIGHT, //!< 右回転
36- PF_MOTOR_DIR_BACKWORD, //!< 後進
36+ PF_MOTOR_DIR_BACKWARD, //!< 後進
3737 PF_MOTOR_DIR_STOP, //!< 停止
3838 PF_MOTOR_DIR_MAX, //!< (方向の個数を表す)
3939 } PF_MOTOR_DIR;
@@ -48,7 +48,19 @@ void pf_motor_task(void);
4848
4949 //! @brief モータ駆動
5050 //! @details モータ定期タスクで実際のモータ出力が行われる
51+//! @details pf_motor_freeとは排他的に動作する
5152 //! @param [in] dir モータ駆動方向
5253 void pf_motor_drive(PF_MOTOR_DIR dir);
5354
55+//! @brief モータ制御
56+//! @details モータ定期タスクで実際のモータ出力が行われる
57+//! @details pf_motor_driveとは排他的に動作する
58+//! @param [in] left 左モータ駆動速度(0=停止)
59+//! @param [in] right 右モータ駆動速度(0=停止)
60+void pf_motor_ctrl(u1 left, u1 right);
61+
62+//! @brief モータ速度設定
63+//! @param [in] speed モータ駆動速度(デフォルト=100)
64+void pf_motor_speed(u1 speed);
65+
5466 #endif // PF_MOTOR_H
--- /dev/null
+++ b/nRFHello/include/pf_music.h
@@ -0,0 +1,49 @@
1+//! @file pf_music.h
2+//! @brief プラットフォーム(音楽演奏)ヘッダファイル
3+
4+// The MIT License (MIT)
5+// Copyright (c) 2023 @xm6_original
6+//
7+// Permission is hereby granted, free of charge, to any person obtaining a
8+// copy of this software and associated documentation files (the "Software"),
9+// to deal in the Software without restriction, including without limitation
10+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
11+// and/or sell copies of the Software, and to permit persons to whom the
12+// Software is furnished to do so, subject to the following conditions:
13+//
14+// The above copyright notice and this permission notice shall be included in
15+// all copies or substantial portions of the Software.
16+//
17+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23+// DEALINGS IN THE SOFTWARE.
24+
25+#ifndef PF_MUSIC_H
26+#define PF_MUSIC_H
27+
28+#include "pf_types.h"
29+
30+//! @brief 音楽演奏デバイス
31+typedef enum PF_MUSIC_DEVICE_Tag
32+{
33+ PF_MUSIC_DEVICE_INTERNAL, //!< 内蔵スピーカー
34+ PF_MUSIC_DEVICE_MAQUEEN, //!< MAQUEENスピーカー(スイッチでON/OFF可)
35+ PF_MUSIC_DEVICE_MAX, //!< (デバイスの個数を表す)
36+} PF_MUSIC_DEVICE;
37+
38+//! @brief 音楽演奏初期化
39+//! @remarks プラットフォーム初期化処理から呼び出すこと
40+//! @attention GPIO初期化およびTimer初期化の後に呼び出すこと
41+void pf_music_init(void);
42+
43+//! @brief 音楽演奏開始
44+void pf_music_play(void);
45+
46+//! @brief 音楽演奏停止
47+void pf_music_stop(void);
48+
49+#endif // PF_MUSIC_H
--- a/nRFHello/include/pf_patrol.h
+++ b/nRFHello/include/pf_patrol.h
@@ -54,6 +54,6 @@ void pf_patrol_task(void);
5454 //! @brief ラインセンサの白黒状態を取得
5555 //! @param [in] id ラインセンサのID
5656 //! @return 色状態(PF_PATROL_COLOR_WHITE=白色/PF_PATROL_COLOR_BLACK=黒色)
57-PF_PATROL_COLOR pf_patrol_get(PF_PATROL_ID id);
57+PF_PATROL_COLOR pf_patrol_line(PF_PATROL_ID id);
5858
5959 #endif // PF_PATROL_H
--- a/nRFHello/include/pf_systick.h
+++ b/nRFHello/include/pf_systick.h
@@ -28,7 +28,7 @@
2828 #include "pf_types.h"
2929
3030 //! @brief 制御周期[ms]
31-#define PF_SYSTICK_SYNC_MS ((u4)10U)
31+#define PF_SYSTICK_SYNC_MS ((u4)5U)
3232
3333 //! @brief SysTick時刻情報構造体
3434 typedef struct PF_SYSTICK_TIME_Tag
--- a/nRFHello/include/pf_timer.h
+++ b/nRFHello/include/pf_timer.h
@@ -38,6 +38,7 @@ typedef void (*PF_TIMER_CALLBACK)(u4 eventbit);
3838 typedef enum PF_TIMER_ID_Tag
3939 {
4040 PF_TIMER_ID_DISPLAY = 0, //!< ディスプレイタイマ
41+ PF_TIMER_ID_MUSIC, //!< 音楽
4142 PF_TIMER_ID_MAX //!< (IDの個数を表す)
4243 } PF_TIMER_ID;
4344
--- a/nRFHello/src/main.c
+++ b/nRFHello/src/main.c
@@ -35,6 +35,7 @@
3535 #include "pf_led.h"
3636 #include "pf_patrol.h"
3737 #include "pf_motor.h"
38+#include "pf_music.h"
3839
3940 //! @brief プラットフォーム初期化
4041 //! @attention 初期化順序に注意する
@@ -59,6 +60,7 @@ static void pf_init(void)
5960 pf_led_init();
6061 pf_patrol_init();
6162 pf_motor_init();
63+ pf_music_init();
6264 }
6365
6466 //! @brief 定期タスク(入力系)
@@ -77,92 +79,466 @@ static void pf_output_task(void)
7779 pf_motor_task();
7880 }
7981
80-static BOOL button_prev[2];
81-static PF_DISPLAY_ID display_id;
82-static char display_ch = 0x20;
83-static PF_MOTOR_DIR motor_dir = 0;
82+//! @brief ボタン過去状態
83+static BOOL app_button_prev[2];
8484
85-//! @brief アプリケーションタスク
86-static void app_task(void)
85+//! @brief ボタンOFF→ONフラグ
86+static BOOL app_button_trigger[2];
87+
88+//! @brief ボタンOFF→ON判定
89+static void app_button_task(void)
8790 {
88- BOOL button_now[2];
91+ BOOL button[2];
8992
90- button_now[0] = pf_button_get(PF_BUTTON_ID_BUTTON_A);
91- button_now[1] = pf_button_get(PF_BUTTON_ID_BUTTON_B);
93+ // トリガ初期化
94+ app_button_trigger[0] = FALSE;
95+ app_button_trigger[1] = FALSE;
9296
93- if (button_now[0] != button_prev[0])
97+ // ボタン取得
98+ button[0] = pf_button_get(PF_BUTTON_ID_BUTTON_A);
99+ button[1] = pf_button_get(PF_BUTTON_ID_BUTTON_B);
100+
101+ // FALSE→TRUEへの変化でトリガON[0]
102+ if ((FALSE == app_button_prev[0]) && (TRUE == button[0]))
94103 {
95- if (button_now[0])
96- {
97- pf_uart_log("Button A: OFF -> ON");
104+ app_button_trigger[0] = TRUE;
105+ }
98106
99- // アイコン系
100- pf_display_id(display_id);
101- display_id++;
102- if (display_id >= PF_DISPLAY_ID_MAX)
103- {
104- display_id = 0;
105- }
106- }
107- else
107+ // FALSE→TRUEへの変化でトリガON[1]
108+ if ((FALSE == app_button_prev[1]) && (TRUE == button[1]))
109+ {
110+ app_button_trigger[1] = TRUE;
111+ }
112+
113+ // 現在のボタン状態を記憶
114+ app_button_prev[0] = button[0];
115+ app_button_prev[1] = button[1];
116+}
117+
118+//! @brief モード状態定義
119+typedef enum APP_MODE_ID_Tag
120+{
121+ APP_MODE_ID_IDLE, //!< アイドル状態
122+ APP_MODE_ID_SQUARE, //!< 矩形走行状態
123+ APP_MODE_ID_LINE, //!< ライントレース状態
124+ APP_MODE_ID_MUSIC, //!< 音楽演奏切り替え状態
125+ APP_MODE_ID_MAX, //!< (IDの個数を表す)
126+} APP_MODE_ID;
127+
128+//! @brief モード状態遷移
129+static APP_MODE_ID app_mode;
130+
131+//! @brief 走行状態遷移
132+static BOOL app_run;
133+
134+//! @brief 音楽演奏状態遷移
135+static BOOL app_play;
136+
137+//! @brief 走行状態ステップ
138+static u4 app_step;
139+
140+//! @brief 走行方向
141+static PF_MOTOR_DIR app_dir;
142+
143+//! @brief アイドル時のディスプレイ個数
144+#define APP_DISPLAY_MAX ((u4)10U)
145+
146+//! @brief アイドル時のディスプレイテーブル
147+static const PF_DISPLAY_ID app_display_idle[10] =
148+{
149+ PF_DISPLAY_ID_HEART, //!< ハート
150+ PF_DISPLAY_ID_HAPPY, //!< HAPPY(嬉しい)
151+ PF_DISPLAY_ID_SMILE, //!< SMILE(笑い)
152+ PF_DISPLAY_ID_SAD, //!< SAD(悲しい)
153+ PF_DISPLAY_ID_CONFUSED, //!< CONFUSED(混乱)
154+ PF_DISPLAY_ID_ANGRY, //!< ANGRY(怒り)
155+ PF_DISPLAY_ID_YES, //!< YES(チェックマーク)
156+ PF_DISPLAY_ID_NO, //!< NO(×マーク)
157+ PF_DISPALY_ID_TRIANGLE, //!< 三角形
158+ PF_DISPLAY_ID_CHESSBOARD, //!< チェスボード(縞模様)
159+};
160+
161+//! @brief 走行時のディスプレイテーブル
162+static const PF_DISPLAY_ID app_display_run[5] =
163+{
164+ PF_DISPLAY_ID_ARROW_N, //!< 前進
165+ PF_DISPLAY_ID_ARROW_W, //!< 左回転
166+ PF_DISPLAY_ID_ARROW_E, //!< 右回転
167+ PF_DISPLAY_ID_ARROW_S, //!< 後進
168+ PF_DISPLAY_ID_YES, //!< 停止
169+};
170+
171+//! @brief 音楽停止時のイメージ
172+static const u1 app_display_musicoff[PF_DISPLAY_ROW_MAX * PF_DISPLAY_COL_MAX] =
173+{
174+ 0, 0, 1, 0, 0,
175+ 0, 0, 1, 0, 0,
176+ 0, 0, 1, 0, 0,
177+ 1, 1, 1, 0, 0,
178+ 1, 1, 1, 0, 0,
179+};
180+
181+//! @brief 矩形走行単位構造体
182+typedef struct APP_SQUARE_UNIT_Tag
183+{
184+ PF_MOTOR_DIR dir; //!< 駆動方向
185+ u4 cycle; //!< 動作周期
186+} APP_SQUARE_UNIT;
187+
188+//! @brief 矩形走行テーブル
189+static const APP_SQUARE_UNIT app_square_table[9] =
190+{
191+ // 前進
192+ {
193+ PF_MOTOR_DIR_FORWARD,
194+ 240,
195+ },
196+
197+ // 右回転
198+ {
199+ PF_MOTOR_DIR_RIGHT,
200+ 76,
201+ },
202+
203+ // 前進
204+ {
205+ PF_MOTOR_DIR_FORWARD,
206+ 240,
207+ },
208+
209+ // 左回転
210+ {
211+ PF_MOTOR_DIR_LEFT,
212+ 74,
213+ },
214+
215+ // 後進
216+ {
217+ PF_MOTOR_DIR_BACKWARD,
218+ 240,
219+ },
220+
221+ // 左回転
222+ {
223+ PF_MOTOR_DIR_LEFT,
224+ 72,
225+ },
226+
227+ // 前進
228+ {
229+ PF_MOTOR_DIR_FORWARD,
230+ 240,
231+ },
232+
233+ // 右回転
234+ {
235+ PF_MOTOR_DIR_RIGHT,
236+ 76,
237+ },
238+
239+ // 終端
240+ {
241+ PF_MOTOR_DIR_STOP,
242+ 0,
243+ },
244+};
245+
246+//! @brief モード状態遷移(Aボタンで遷移)
247+static void app_mode_task(void)
248+{
249+ // Aボタンで遷移
250+ if (TRUE == app_button_trigger[0])
251+ {
252+ app_mode++;
253+ if (app_mode >= APP_MODE_ID_MAX)
108254 {
109- pf_uart_log("Button A: ON -> OFF\n");
255+ app_mode = 0;
110256 }
257+
258+ // 常に停止状態、ステップ戻す
259+ app_run = FALSE;
260+ app_step = 0;
111261 }
112262
113- if (button_now[1] != button_prev[1])
263+ // Bボタンでトグル切り替え
264+ if (TRUE == app_button_trigger[1])
114265 {
115- if (button_now[1])
266+ switch (app_mode)
116267 {
117- pf_uart_log("Button B: OFF -> ON");
268+ // Bボタンでディスプレイ表示IDが変化する
269+ case APP_MODE_ID_IDLE:
270+ // ステップを上げる。APP_DISPLAY_MAXで1回転
271+ app_step++;
272+ if (app_step >= APP_DISPLAY_MAX)
273+ {
274+ app_step = 0;
275+ }
276+ break;
118277
119- // キャラクタ系
120- pf_display_ch(display_ch);
121- if (display_ch == 0x7F)
278+ // Bボタンで音楽演奏⇔音楽停止のトグル切り替え
279+ case APP_MODE_ID_MUSIC:
280+ if (FALSE == app_play)
122281 {
123- display_ch = 0x20;
282+ app_play = TRUE;
124283 }
125284 else
126285 {
127- display_ch++;
286+ app_play = FALSE;
128287 }
288+ break;
129289
130- // モータ駆動
131- pf_motor_drive(motor_dir);
132- motor_dir++;
133- if (motor_dir >= PF_MOTOR_DIR_MAX)
290+ // Bボタンで走行モード⇔停止モードのトグル切り替え
291+ default:
292+ if (FALSE == app_run)
134293 {
135- motor_dir = 0;
294+ app_run = TRUE;
136295 }
296+ else
297+ {
298+ app_run = FALSE;
299+ }
300+
301+ // ステップを戻す
302+ app_step = 0;
303+ break;
304+ }
305+ }
306+}
307+
308+//! @brief ディスプレイ表示
309+static void app_display_task(void)
310+{
311+ // モードに応じたディスプレイ表示
312+ switch (app_mode)
313+ {
314+ // アイドル状態
315+ case APP_MODE_ID_IDLE:
316+ pf_display_id(app_display_idle[app_step]);
317+ break;
318+
319+ // 音楽演奏切り替え状態
320+ case APP_MODE_ID_MUSIC:
321+ if (FALSE == app_play)
322+ {
323+ pf_display_image(app_display_musicoff);
137324 }
138325 else
139326 {
140- pf_uart_log("Button B: ON -> OFF\n");
327+ pf_display_id(PF_DISPLAY_ID_MUSIC);
141328 }
329+ break;
330+
331+ // 走行状態
332+ case APP_MODE_ID_SQUARE:
333+ if (FALSE == app_run)
334+ {
335+ pf_display_id(PF_DISPLAY_ID_SQUARE);
336+ }
337+ else
338+ {
339+ pf_display_id(app_display_run[app_dir]);
340+ }
341+ break;
342+
343+ case APP_MODE_ID_LINE:
344+ if (FALSE == app_run)
345+ {
346+ pf_display_id(PF_DISPLAY_ID_DIAMOND);
347+ }
348+ else
349+ {
350+ pf_display_id(app_display_run[app_dir]);
351+ }
352+ break;
353+
354+ default:
355+ break;
142356 }
357+}
358+
359+//! @brief LED表示
360+static void app_led_task(void)
361+{
362+ PF_PATROL_COLOR left;
363+ PF_PATROL_COLOR right;
143364
144- // ラインセンサとLEDの連携制御(黒色で点灯、白色で消灯)
145- if (PF_PATROL_COLOR_BLACK == pf_patrol_get(PF_PATROL_ID_L))
365+ // 取得
366+ left = pf_patrol_line(PF_PATROL_ID_L);
367+ right = pf_patrol_line(PF_PATROL_ID_R);
368+
369+ // stepが32の倍数(160ms)で点滅
370+ if (app_step & 0x0020)
146371 {
147- pf_led_ctrl(PF_LED_ID_L, TRUE);
372+ // 常に消灯
373+ pf_led_ctrl(PF_LED_ID_L, FALSE);
374+ pf_led_ctrl(PF_LED_ID_R, FALSE);
148375 }
149376 else
150377 {
151- pf_led_ctrl(PF_LED_ID_L, FALSE);
378+ // 白色で点灯(左)
379+ if (PF_PATROL_COLOR_WHITE == left)
380+ {
381+ pf_led_ctrl(PF_LED_ID_L, TRUE);
382+ }
383+ else
384+ {
385+ pf_led_ctrl(PF_LED_ID_L, FALSE);
386+ }
387+
388+ // 白色で点灯(右)
389+ if (PF_PATROL_COLOR_WHITE == right)
390+ {
391+ pf_led_ctrl(PF_LED_ID_R, TRUE);
392+ }
393+ else
394+ {
395+ pf_led_ctrl(PF_LED_ID_R, FALSE);
396+ }
397+ }
398+}
399+
400+//! @brief 走行(矩形)
401+static void app_run_square(void)
402+{
403+ const APP_SQUARE_UNIT *unit;
404+ u4 step;
405+ BOOL next;
406+
407+ // オート変数初期化
408+ unit = &app_square_table[0];
409+ step = app_step;
410+ next = TRUE;
411+
412+ // 現在のapp_stepより、適切なunitを割り出す
413+ while (step >= unit->cycle)
414+ {
415+ // unitを進める
416+ step -= unit->cycle;
417+ unit++;
418+
419+ // unitが終端に来たら、巻き戻す
420+ if (0 == unit->cycle)
421+ {
422+ unit = &app_square_table[0];
423+ next = FALSE;
424+ }
152425 }
153426
154- if (PF_PATROL_COLOR_BLACK == pf_patrol_get(PF_PATROL_ID_R))
427+ // nextフラグでapp_stepを更新
428+ if (TRUE == next)
155429 {
156- pf_led_ctrl(PF_LED_ID_R, TRUE);
430+ app_step++;
157431 }
158432 else
159433 {
160- pf_led_ctrl(PF_LED_ID_R, FALSE);
434+ app_step = 0;
161435 }
162436
163- // ボタン情報を更新
164- button_prev[0] = button_now[0];
165- button_prev[1] = button_now[1];
437+ // 方向決定
438+ app_dir = unit->dir;
439+ pf_motor_drive(app_dir);
440+}
441+
442+//! @brief 走行(ライントレース)
443+static void app_run_line(void)
444+{
445+ PF_PATROL_COLOR left;
446+ PF_PATROL_COLOR right;
447+ PF_MOTOR_DIR dir;
448+
449+ // オート変数初期化
450+ left = PF_PATROL_COLOR_WHITE;
451+ right = PF_PATROL_COLOR_WHITE;
452+ dir = PF_MOTOR_DIR_BACKWARD;
453+
454+ // 取得
455+ left = pf_patrol_line(PF_PATROL_ID_L);
456+ right = pf_patrol_line(PF_PATROL_ID_R);
457+
458+ // 共に白色で前進
459+ if ((PF_PATROL_COLOR_WHITE == left) && (PF_PATROL_COLOR_WHITE == right))
460+ {
461+ dir = PF_MOTOR_DIR_FORWARD;
462+ }
463+
464+ // 左が黒色なら左回転
465+ if ((PF_PATROL_COLOR_BLACK == left) && (PF_PATROL_COLOR_WHITE == right))
466+ {
467+ dir = PF_MOTOR_DIR_LEFT;
468+ }
469+
470+ // 右が黒色なら左回転
471+ if ((PF_PATROL_COLOR_WHITE == left) && (PF_PATROL_COLOR_BLACK == right))
472+ {
473+ dir = PF_MOTOR_DIR_RIGHT;
474+ }
475+
476+ // モータ速度(後進のみ遅い)
477+ if (PF_MOTOR_DIR_BACKWARD == dir)
478+ {
479+ pf_motor_speed(50);
480+ }
481+ else
482+ {
483+ pf_motor_speed(100);
484+ }
485+
486+ // モータ設定
487+ app_dir = dir;
488+ pf_motor_drive(app_dir);
489+
490+ // ステップ更新処理
491+ app_step++;
492+}
493+
494+//! @brief アプリケーションタスク
495+static void app_task(void)
496+{
497+ BOOL run;
498+
499+ // オート変数初期化
500+ run = FALSE;
501+
502+ // ボタン
503+ app_button_task();
504+
505+ // モード切替
506+ app_mode_task();
507+
508+ // ディスプレイ表示
509+ app_display_task();
510+
511+ // LED表示
512+ app_led_task();
513+
514+ // 走行(矩形)
515+ if ((APP_MODE_ID_SQUARE == app_mode) && (TRUE == app_run))
516+ {
517+ app_run_square();
518+ run = TRUE;
519+ }
520+
521+ // 走行(ライントレース)
522+ if ((APP_MODE_ID_LINE == app_mode) && (TRUE == app_run))
523+ {
524+ app_run_line();
525+ run = TRUE;
526+ }
527+
528+ // 走行状態以外なら停止
529+ if (FALSE == run)
530+ {
531+ pf_motor_drive(PF_MOTOR_DIR_STOP);
532+ pf_music_stop();
533+ }
534+ else
535+ {
536+ // 音楽演奏フラグに従い演奏
537+ if (TRUE == app_play)
538+ {
539+ pf_music_play();
540+ }
541+ }
166542 }
167543
168544 //! @brief メインプログラム
--- a/nRFHello/src/pf/pf_button.c
+++ b/nRFHello/src/pf/pf_button.c
@@ -27,7 +27,7 @@
2727 #include "pf_button.h"
2828
2929 //! @brief チャタリング防止のためのフィルタ段数(最低2段以上にすること)
30-#define PF_BUTTON_FILTER_MAX ((u4)3U)
30+#define PF_BUTTON_FILTER_MAX ((u4)5U)
3131
3232 //! @brief ボタン→GPIO IDテーブル
3333 static const PF_GPIO_ID pf_button_to_gpio[PF_BUTTON_ID_MAX] =
--- a/nRFHello/src/pf/pf_gpio.c
+++ b/nRFHello/src/pf/pf_gpio.c
@@ -74,7 +74,6 @@ typedef struct PF_GPIO_INIT_Tag
7474 } PF_GPIO_INIT;
7575
7676 //! @brief GPIOピン初期化情報テーブル
77-//! @todo 未使用ピンがすべてプルアップ有効の入力にするよう設定すること
7877 const PF_GPIO_INIT pf_gpio_init_table[PF_GPIO_ID_MAX] =
7978 {
8079 // PF_GPIO_ID_UART_TXD
@@ -276,6 +275,28 @@ const PF_GPIO_INIT pf_gpio_init_table[PF_GPIO_ID_MAX] =
276275 PF_GPIO_DRIVE_S0D1, // 駆動特性
277276 },
278277
278+ // PF_GPIO_ID_INTERNAL_SPEAKER
279+ {
280+ 0, // ポート
281+ 0, // ピン
282+ FALSE, // 初期出力レベル
283+ PF_GPIO_DIR_OUTPUT, // 入出力方向
284+ PF_GPIO_INBUF_DISCONNECT, // 入力バッファ
285+ PF_GPIO_PULL_NONE, // プルアップ・プルダウン
286+ PF_GPIO_DRIVE_S0S1, // 駆動特性
287+ },
288+
289+ // PF_GPIO_ID_MAQUEEN_SPEAKER
290+ {
291+ 0, // ポート
292+ 2, // ピン
293+ FALSE, // 初期出力レベル
294+ PF_GPIO_DIR_OUTPUT, // 入出力方向
295+ PF_GPIO_INBUF_DISCONNECT, // 入力バッファ
296+ PF_GPIO_PULL_NONE, // プルアップ・プルダウン
297+ PF_GPIO_DRIVE_S0S1, // 駆動特性
298+ },
299+
279300 // PF_GPIO_ID_MAQUEEN_LED_L
280301 {
281302 0, // ポート
--- a/nRFHello/src/pf/pf_i2c.c
+++ b/nRFHello/src/pf/pf_i2c.c
@@ -62,7 +62,7 @@ static const PF_I2C_ADDR pf_i2c_addr_table[PF_I2C_ID_MAX] =
6262 };
6363
6464 //! @brief I2C動作情報構造体
65-typedef struct PF_I2C_STATUS_Tag
65+typedef struct PF_I2C_INFO_Tag
6666 {
6767 PF_I2C_CALLBACK callback; //!< コールバック関数
6868 BOOL busy; //!< BUSYフラグ
@@ -71,10 +71,10 @@ typedef struct PF_I2C_STATUS_Tag
7171 u4 anack; //!< アドレスNACK発生回数
7272 u4 dnack; //!< データNACK発生回数
7373 u1 reg; //!< 受信レジスタ
74-} PF_I2C_STATUS;
74+} PF_I2C_INFO;
7575
7676 //! @brief I2C動作情報テーブル
77-static PF_I2C_STATUS pf_i2c_status[PF_I2C_ID_MAX];
77+static PF_I2C_INFO pf_i2c_info[PF_I2C_ID_MAX];
7878
7979 //! @brief I2Cチャネル→デバイステーブル
8080 static NRF_TWIM_Type* const pf_i2c_channel_to_dev[PF_I2C_CHANNEL_MAX] =
@@ -149,7 +149,7 @@ static BOOL pf_i2c_get_busy(u4 channel)
149149 if (channel == pf_i2c_addr_table[id].channel)
150150 {
151151 // BUSYであれば
152- if (TRUE == pf_i2c_status[id].busy)
152+ if (TRUE == pf_i2c_info[id].busy)
153153 {
154154 // そのチャネルはBUSY
155155 busy = TRUE;
@@ -179,7 +179,7 @@ static PF_I2C_ID pf_i2c_get_id(u4 channel)
179179 if (channel == pf_i2c_addr_table[id].channel)
180180 {
181181 // BUSYであれば
182- if (TRUE == pf_i2c_status[id].busy)
182+ if (TRUE == pf_i2c_info[id].busy)
183183 {
184184 // このIDが該当する
185185 break;
@@ -195,18 +195,18 @@ static PF_I2C_ID pf_i2c_get_id(u4 channel)
195195 static void pf_i2c_init_id(PF_I2C_ID id)
196196 {
197197 // コールバック関数なし
198- pf_i2c_status[id].callback = NULL;
198+ pf_i2c_info[id].callback = NULL;
199199
200200 // デバイスREADY
201- pf_i2c_status[id].busy = FALSE;
201+ pf_i2c_info[id].busy = FALSE;
202202
203203 // エラーなし
204- pf_i2c_status[id].overrun = 0;
205- pf_i2c_status[id].anack = 0;
206- pf_i2c_status[id].dnack = 0;
204+ pf_i2c_info[id].overrun = 0;
205+ pf_i2c_info[id].anack = 0;
206+ pf_i2c_info[id].dnack = 0;
207207
208208 // 受信レジスタ0
209- pf_i2c_status[id].reg = 0;
209+ pf_i2c_info[id].reg = 0;
210210 }
211211
212212 //! @brief I2C初期化(デバイス)
@@ -371,13 +371,13 @@ BOOL pf_i2c_send(PF_I2C_ID id, const u1 *buf, u4 bytes)
371371 if (FALSE == busy)
372372 {
373373 // 通信成功に初期化
374- pf_i2c_status[id].status = TRUE;
374+ pf_i2c_info[id].status = TRUE;
375375
376376 // 送信開始
377377 pf_i2c_send_dev(channel, pf_i2c_addr_table[id].addr, buf, bytes);
378378
379379 // BUSYへ変更
380- pf_i2c_status[id].busy = TRUE;
380+ pf_i2c_info[id].busy = TRUE;
381381
382382 // 送信開始に成功した
383383 result = TRUE;
@@ -463,17 +463,16 @@ BOOL pf_i2c_recv(PF_I2C_ID id, u1 reg, u1 *buf, u4 bytes)
463463 if (FALSE == busy)
464464 {
465465 // 受信レジスタを記憶
466- pf_i2c_status[id].reg = reg;
466+ pf_i2c_info[id].reg = reg;
467467
468468 // 通信成功に初期化
469- pf_i2c_status[id].status = TRUE;
469+ pf_i2c_info[id].status = TRUE;
470470
471471 // 送受信開始
472- pf_i2c_recv_dev(channel, pf_i2c_addr_table[id].addr, &pf_i2c_status[id].reg, buf,
473- bytes);
472+ pf_i2c_recv_dev(channel, pf_i2c_addr_table[id].addr, &pf_i2c_info[id].reg, buf, bytes);
474473
475474 // BUSYへ変更
476- pf_i2c_status[id].busy = TRUE;
475+ pf_i2c_info[id].busy = TRUE;
477476
478477 // 送受信開始に成功した
479478 result = TRUE;
@@ -510,14 +509,14 @@ void pf_i2c_error(PF_I2C_ID id, PF_I2C_ERROR *error)
510509 enable = pf_i2c_interrupt_disable(channel);
511510
512511 // エラー情報を転送
513- error->overrun = pf_i2c_status[id].overrun;
514- error->anack = pf_i2c_status[id].anack;
515- error->dnack = pf_i2c_status[id].dnack;
512+ error->overrun = pf_i2c_info[id].overrun;
513+ error->anack = pf_i2c_info[id].anack;
514+ error->dnack = pf_i2c_info[id].dnack;
516515
517516 // プラットフォーム内部のエラー情報をクリア
518- pf_i2c_status[id].overrun = 0;
519- pf_i2c_status[id].anack = 0;
520- pf_i2c_status[id].dnack = 0;
517+ pf_i2c_info[id].overrun = 0;
518+ pf_i2c_info[id].anack = 0;
519+ pf_i2c_info[id].dnack = 0;
521520
522521 // I2C割り込み復元
523522 pf_i2c_interrupt_restore(channel, enable);
@@ -547,7 +546,7 @@ void pf_i2c_callback(PF_I2C_ID id, PF_I2C_CALLBACK func)
547546 enable = pf_i2c_interrupt_disable(channel);
548547
549548 // コールバック関数設定
550- pf_i2c_status[id].callback = func;
549+ pf_i2c_info[id].callback = func;
551550
552551 // I2C割り込み復元
553552 pf_i2c_interrupt_restore(channel, enable);
@@ -568,12 +567,12 @@ static void pf_i2c_isr_stopped(u4 channel)
568567 id = pf_i2c_get_id(channel);
569568
570569 // 通信終了
571- pf_i2c_status[id].busy = FALSE;
570+ pf_i2c_info[id].busy = FALSE;
572571
573572 // I2Cコールバック関数が登録されていれば、呼び出す
574- if (NULL != pf_i2c_status[id].callback)
573+ if (NULL != pf_i2c_info[id].callback)
575574 {
576- pf_i2c_status[id].callback(pf_i2c_status[id].status);
575+ pf_i2c_info[id].callback(pf_i2c_info[id].status);
577576 }
578577 }
579578
@@ -599,13 +598,13 @@ static void pf_i2c_isr_error(u4 channel)
599598 id = pf_i2c_get_id(channel);
600599
601600 // 通信エラーあり
602- pf_i2c_status[id].status = FALSE;
601+ pf_i2c_info[id].status = FALSE;
603602
604603 // エラー種別判定(ANACK)
605604 if (anack == (dev->ERRORSRC & anack))
606605 {
607606 // ANACK発生。'1'を書き込むことでクリアする
608- pf_i2c_status[id].anack++;
607+ pf_i2c_info[id].anack++;
609608 dev->ERRORSRC = anack;
610609 }
611610
@@ -613,7 +612,7 @@ static void pf_i2c_isr_error(u4 channel)
613612 if (dnack == (dev->ERRORSRC & dnack))
614613 {
615614 // DNACK発生。'1'を書き込むことでクリアする
616- pf_i2c_status[id].dnack++;
615+ pf_i2c_info[id].dnack++;
617616 dev->ERRORSRC = dnack;
618617 }
619618
@@ -621,7 +620,7 @@ static void pf_i2c_isr_error(u4 channel)
621620 if (overrun == (dev->ERRORSRC & overrun))
622621 {
623622 // オーバーラン発生。'0'を書き込むことでクリアする
624- pf_i2c_status[id].overrun++;
623+ pf_i2c_info[id].overrun++;
625624 dev->ERRORSRC = TWIM_ERRORSRC_OVERRUN_NotReceived << TWIM_ERRORSRC_OVERRUN_Pos;
626625 }
627626
--- a/nRFHello/src/pf/pf_interrupt.c
+++ b/nRFHello/src/pf/pf_interrupt.c
@@ -41,6 +41,10 @@ u4 pf_interrupt_global_disable(void)
4141 // 割り込み禁止
4242 __disable_irq();
4343
44+ // メモリバリア・命令バリア(念のため)
45+ __DSB();
46+ __ISB();
47+
4448 return primask;
4549 }
4650
@@ -89,6 +93,11 @@ static IRQn_Type pf_interrupt_get_irq(PF_INTERRUPT_PRI pri)
8993 irq = SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQn;
9094 break;
9195
96+ // 音楽演奏
97+ case PF_INTERRUPT_PRI_MUSIC:
98+ irq = TIMER1_IRQn;
99+ break;
100+
92101 default:
93102 break;
94103 }
--- a/nRFHello/src/pf/pf_motor.c
+++ b/nRFHello/src/pf/pf_motor.c
@@ -27,6 +27,9 @@
2727 #include "pf_i2c.h"
2828 #include "pf_motor.h"
2929
30+//! @brief I2C常時送信動作(TRUE=常時送信/FALSE=キャッシュ動作)
31+#define PF_MOTOR_I2C_ANY (TRUE)
32+
3033 //! @brief モータ速度(デフォルト)
3134 #define PF_MOTOR_DEFAULT_SPEED ((u1)100U)
3235
@@ -45,6 +48,9 @@
4548 //! @brief 回転方向(後回転)
4649 #define PF_MOTOR_MOVE_BACKWARD ((u1)0x01U)
4750
51+//! @brief 回転方向(不定値)
52+#define PF_MOTOR_MOVE_UNFORMATTED ((u1)0xFFU)
53+
4854 //! @brief 動作速度(駆動)
4955 #define PF_MOTOR_SPEED_DRIVE ((u1)0x01U)
5056
@@ -60,16 +66,16 @@ typedef enum PF_MOTOR_I2C_Tag
6066 PF_MOTOR_I2C_MAX, //!< (バッファのサイズを表す)
6167 } PF_MOTOR_I2C;
6268
63-//! @brief モータ駆動情報構造体
64-typedef struct PF_MOTOR_DIR_INFO_Tag
69+//! @brief I2C通信パケット構造体
70+typedef struct PF_MOTOR_I2C_PACKET_Tag
6571 {
6672 u1 channel; //!< チャネル
6773 u1 direction; //!< 駆動方向
6874 u1 speed; //!< 動作速度
69-} PF_MOTOR_DIR_INFO;
75+} PF_MOTOR_I2C_PACKET;
7076
71-//! @brief モータ駆動方向→モータ駆動情報テーブル
72-static const PF_MOTOR_DIR_INFO pf_motor_dir_to_info[PF_MOTOR_DIR_MAX][PF_MOTOR_CHANNEL_MAX] =
77+//! @brief 駆動方向→I2C通信パケットテーブル
78+static const PF_MOTOR_I2C_PACKET pf_motor_dir_to_packet[PF_MOTOR_DIR_MAX][PF_MOTOR_CHANNEL_MAX] =
7379 {
7480 // PF_MOTOR_DIR_FORWARD
7581 {
@@ -157,42 +163,59 @@ static const PF_MOTOR_DIR_INFO pf_motor_dir_to_info[PF_MOTOR_DIR_MAX][PF_MOTOR_C
157163 },
158164 };
159165
160-//! @brief I2C通信バッファ
161-static u1 pf_motor_buf[PF_MOTOR_CHANNEL_MAX][PF_MOTOR_I2C_MAX];
162-
163-//! @brief 現在のモータ駆動方向
164-static PF_MOTOR_DIR pf_motor_current_dir;
165-
166-//! @brief 次回のモータ駆動方向
167-static PF_MOTOR_DIR pf_motor_next_dir;
168-
169-//! @brief 現在のモータ速度
170-static u1 pf_motor_current_speed;
171-
172-//! @brief 現在の送信中チャネル
173-static u4 pf_motor_current_channel;
166+//! @brief モータ動作情報構造体
167+typedef struct PF_MOTOR_INFO_Tag
168+{
169+ PF_MOTOR_DIR dir; //!< 現在の駆動方向
170+ u4 channel; //!< 送信中チャネル
171+ BOOL free; //!< フリー動作フラグ
172+ u1 speed; //!< 駆動速度(フリー動作以外)
173+ u1 left; //!< 駆動速度(フリー動作L)
174+ u1 right; //!< 駆動速度(フリー動作R)
175+ u1 buf[PF_MOTOR_CHANNEL_MAX][PF_MOTOR_I2C_MAX]; //!< I2C通信バッファ(送信中)
176+ u1 i2c[PF_MOTOR_CHANNEL_MAX][PF_MOTOR_I2C_MAX]; //!< I2C通信バッファ(送信完了)
177+} PF_MOTOR_INFO;
178+
179+// モータ動作情報
180+static PF_MOTOR_INFO pf_motor_info;
174181
175182 //! @brief I2Cからのコールバック関数
176183 //! @param [in] status 通信ステータス(TRUE=成功/FALSE=失敗)
177184 static void pf_motor_callback(BOOL status)
178185 {
186+ u4 loop;
187+
188+ // オート変数初期化
189+ loop = 0;
190+
179191 // 成功の場合
180192 if (TRUE == status)
181193 {
182194 // 送信中チャネルをインクリメント
183- pf_motor_current_channel++;
195+ pf_motor_info.channel++;
184196
185197 // 送信中チャネルが最大値に達しているか
186- if (pf_motor_current_channel < PF_MOTOR_CHANNEL_MAX)
198+ if (pf_motor_info.channel < PF_MOTOR_CHANNEL_MAX)
187199 {
188- // 次の送信をスタート
189- (void)pf_i2c_send(PF_I2C_ID_MAQUEEN_MOTOR, &pf_motor_buf[pf_motor_current_channel][0],
200+ // 次のI2C送信をスタート
201+ (void)pf_i2c_send(PF_I2C_ID_MAQUEEN_MOTOR, &pf_motor_info.buf[pf_motor_info.channel][0],
190202 PF_MOTOR_I2C_MAX);
191203 }
192204 else
193205 {
194- // すべてのチャネルを送信完了したので、更新
195- pf_motor_current_dir = pf_motor_next_dir;
206+ // すべてのチャネルが正常送信できた
207+ if (FALSE == pf_motor_info.free)
208+ {
209+ // チャネル数ループ
210+ for (loop = 0; loop < PF_MOTOR_CHANNEL_MAX; loop++)
211+ {
212+ // pf_motor_info.bufをpf_motor_info.i2cへコピー(回転方向と速度のみ)
213+ pf_motor_info.i2c[loop][PF_MOTOR_I2C_MOVE] =
214+ pf_motor_info.buf[loop][PF_MOTOR_I2C_MOVE];
215+ pf_motor_info.i2c[loop][PF_MOTOR_I2C_SPEED] =
216+ pf_motor_info.buf[loop][PF_MOTOR_I2C_SPEED];
217+ }
218+ }
196219 }
197220 }
198221 }
@@ -201,20 +224,97 @@ static void pf_motor_callback(BOOL status)
201224 //! @remarks プラットフォーム初期化処理から呼び出すこと
202225 void pf_motor_init(void)
203226 {
204- // モータ駆動方向: 停止
205- pf_motor_current_dir = PF_MOTOR_DIR_STOP;
206- pf_motor_next_dir = PF_MOTOR_DIR_STOP;
227+ u4 loop;
228+
229+ // オート変数初期化
230+ loop = 0;
231+
232+ // モータ駆動方向
233+ pf_motor_info.dir = PF_MOTOR_DIR_STOP;
234+
235+ // 送信中チャネル
236+ pf_motor_info.channel = 0;
237+
238+ // フリー動作フラグ
239+ pf_motor_info.free = FALSE;
240+
241+ // 駆動速度(フリー動作以外)
242+ pf_motor_info.speed = PF_MOTOR_DEFAULT_SPEED;
243+
244+ // 駆動速度(フリー動作)
245+ pf_motor_info.left = PF_MOTOR_DEFAULT_SPEED;
246+ pf_motor_info.right = PF_MOTOR_DEFAULT_SPEED;
207247
208- // モータ速度: デフォルト
209- pf_motor_current_speed = PF_MOTOR_DEFAULT_SPEED;
248+ // I2C通信バッファ(送信完了)
249+ for (loop = 0; loop < PF_MOTOR_CHANNEL_MAX; loop++)
250+ {
251+ // 回転方向を不定値とすることで、初回送信が確実に行われるようにする
252+ pf_motor_info.i2c[loop][PF_MOTOR_I2C_MOVE] = PF_MOTOR_MOVE_UNFORMATTED;
253+ }
210254
211255 // I2Cコールバック関数を設定
212256 pf_i2c_callback(PF_I2C_ID_MAQUEEN_MOTOR, pf_motor_callback);
213257 }
214258
215-//! @brief モータ駆動情報送信
259+//! @brief I2C送信
216260 static void pf_motor_send(void)
217261 {
262+#if PF_MOTOR_I2C_ANY == TRUE
263+ // 送信中チャネルをクリア
264+ pf_motor_info.channel = 0;
265+
266+ // 常に送信開始
267+ (void)pf_i2c_send(PF_I2C_ID_MAQUEEN_MOTOR, &pf_motor_info.buf[pf_motor_info.channel][0],
268+ PF_MOTOR_I2C_MAX);
269+#else
270+ u4 enable;
271+ u4 loop;
272+ BOOL request;
273+
274+ // オート変数初期化
275+ enable = 0;
276+ loop = 0;
277+ request = FALSE;
278+
279+ // I2C割り込み(外部)を禁止
280+ enable = pf_interrupt_local_disable(PF_INTERRUPT_PRI_I2C_EXT);
281+
282+ // 左右のモータを調べ、双方とも既に目的の動作になっていればI2C送信をスキップする
283+ for (loop = 0; loop < PF_MOTOR_CHANNEL_MAX; loop++)
284+ {
285+ // 回転方向が異なっていたら送信を要求
286+ if (pf_motor_info.buf[loop][PF_MOTOR_I2C_MOVE]
287+ != pf_motor_info.i2c[loop][PF_MOTOR_I2C_MOVE])
288+ {
289+ request = TRUE;
290+ }
291+
292+ // 速度が異なっていたら送信を要求
293+ if (pf_motor_info.buf[loop][PF_MOTOR_I2C_SPEED]
294+ != pf_motor_info.i2c[loop][PF_MOTOR_I2C_SPEED])
295+ {
296+ request = TRUE;
297+ }
298+ }
299+
300+ // 送信中チャネルをクリア
301+ pf_motor_info.channel = 0;
302+
303+ // I2C割り込み(外部)を復元
304+ pf_interrupt_local_restore(PF_INTERRUPT_PRI_I2C_EXT, enable);
305+
306+ // 要求があれば、送信開始
307+ if (TRUE == request)
308+ {
309+ (void)pf_i2c_send(PF_I2C_ID_MAQUEEN_MOTOR, &pf_motor_info.buf[pf_motor_info.channel][0],
310+ PF_MOTOR_I2C_MAX);
311+ }
312+#endif // PF_MOTOR_I2C_ANY
313+}
314+
315+//! @brief I2Cバッファ構成(駆動方向)
316+static void pf_motor_build_dir(void)
317+{
218318 u4 loop;
219319
220320 // オート変数初期化
@@ -224,65 +324,112 @@ static void pf_motor_send(void)
224324 for (loop = 0; loop < PF_MOTOR_CHANNEL_MAX; loop++)
225325 {
226326 // チャネル
227- pf_motor_buf[loop][PF_MOTOR_I2C_CHANNEL] =
228- pf_motor_dir_to_info[pf_motor_next_dir][loop].channel;
327+ pf_motor_info.buf[loop][PF_MOTOR_I2C_CHANNEL] =
328+ pf_motor_dir_to_packet[pf_motor_info.dir][loop].channel;
229329
230- // 駆動方向
231- pf_motor_buf[loop][PF_MOTOR_I2C_MOVE] =
232- pf_motor_dir_to_info[pf_motor_next_dir][loop].direction;
330+ // 回転方向
331+ pf_motor_info.buf[loop][PF_MOTOR_I2C_MOVE] =
332+ pf_motor_dir_to_packet[pf_motor_info.dir][loop].direction;
233333
234- // 動作速度(駆動の場合は現在の速度を設定する)
235- if (PF_MOTOR_SPEED_STOP == pf_motor_dir_to_info[pf_motor_next_dir][loop].speed)
334+ // 速度(駆動の場合は現在の速度を設定する)
335+ if (PF_MOTOR_SPEED_STOP == pf_motor_dir_to_packet[pf_motor_info.dir][loop].speed)
236336 {
237337 // 停止
238- pf_motor_buf[loop][PF_MOTOR_I2C_SPEED] = PF_MOTOR_SPEED_STOP;
338+ pf_motor_info.buf[loop][PF_MOTOR_I2C_SPEED] = PF_MOTOR_SPEED_STOP;
239339 }
240340 else
241341 {
242342 // 現在の速度で駆動
243- pf_motor_buf[loop][PF_MOTOR_I2C_SPEED] = pf_motor_current_speed;
343+ pf_motor_info.buf[loop][PF_MOTOR_I2C_SPEED] = pf_motor_info.speed;
244344 }
245345 }
346+}
246347
247- // 送信中チャネルを初期化
248- pf_motor_current_channel = 0;
348+//! @brief I2Cバッファ構成(フリー)
349+static void pf_motor_build_free(void)
350+{
351+ u4 loop;
249352
250- // 最初のチャネルの送信をスタート
251- (void)pf_i2c_send(PF_I2C_ID_MAQUEEN_MOTOR, &pf_motor_buf[0][0], PF_MOTOR_I2C_MAX);
353+ // オート変数初期化
354+ loop = 0;
355+
356+ // チャネル数ループ
357+ for (loop = 0; loop < PF_MOTOR_CHANNEL_MAX; loop++)
358+ {
359+ // チャネル
360+ pf_motor_info.buf[loop][PF_MOTOR_I2C_CHANNEL] =
361+ pf_motor_dir_to_packet[pf_motor_info.dir][loop].channel;
362+
363+ // 回転方向(前回転固定)
364+ pf_motor_info.buf[loop][PF_MOTOR_I2C_MOVE] = PF_MOTOR_MOVE_FORWARD;
365+
366+ // 速度
367+ if (0 == loop)
368+ {
369+ pf_motor_info.buf[loop][PF_MOTOR_I2C_SPEED] = pf_motor_info.left;
370+ }
371+ else
372+ {
373+ pf_motor_info.buf[loop][PF_MOTOR_I2C_SPEED] = pf_motor_info.right;
374+ }
375+ }
252376 }
253377
254378 //! @brief モータ定期タスク
255379 //! @remarks プラットフォーム定期タスク(出力系)処理から呼び出すこと
256380 void pf_motor_task(void)
257381 {
258- u4 enable;
259- PF_MOTOR_DIR current;
260-
261- // オート変数初期化
262- enable = 0;
263- current = PF_MOTOR_DIR_STOP;
264-
265- // 現在の駆動方向を取得(グローバル割り込みを禁止して行う)
266- enable = pf_interrupt_global_disable();
267- current = pf_motor_current_dir;
268- pf_interrupt_global_restore(enable);
269-
270- // 駆動方向を比較
271- if (current != pf_motor_next_dir)
382+ // フリー種別で分ける
383+ if (FALSE == pf_motor_info.free)
384+ {
385+ // I2Cバッファ構成(駆動方向)
386+ pf_motor_build_dir();
387+ }
388+ else
272389 {
273- // 一致するまで送信
274- pf_motor_send();
390+ // I2Cバッファ構成(フリー)
391+ pf_motor_build_free();
275392 }
393+
394+ // I2C送信(必要に応じて行う)
395+ pf_motor_send();
276396 }
277397
278398 //! @brief モータ駆動
279399 //! @details モータ定期タスクで実際のモータ出力が行われる
400+//! @details pf_motor_freeとは排他的に動作する
280401 //! @param [in] dir モータ駆動方向
281402 void pf_motor_drive(PF_MOTOR_DIR dir)
282403 {
283404 // パラメータチェック
284405 if (dir < PF_MOTOR_DIR_MAX)
285406 {
286- pf_motor_next_dir = dir;
407+ // 方向を設定
408+ pf_motor_info.dir = dir;
409+
410+ // フリー動作なし
411+ pf_motor_info.free = FALSE;
287412 }
288413 }
414+
415+//! @brief モータ制御
416+//! @details モータ定期タスクで実際のモータ出力が行われる
417+//! @details pf_motor_driveとは排他的に動作する
418+//! @param [in] left 左モータ駆動速度(0=停止)
419+//! @param [in] right 右モータ駆動速度(0=停止)
420+void pf_motor_ctrl(u1 left, u1 right)
421+{
422+ // 速度を設定
423+ pf_motor_info.left = left;
424+ pf_motor_info.right = right;
425+
426+ // フリー動作あり
427+ pf_motor_info.free = TRUE;
428+}
429+
430+//! @brief モータ速度設定
431+//! @param [in] speed モータ駆動速度(デフォルト=100)
432+void pf_motor_speed(u1 speed)
433+{
434+ pf_motor_info.speed = speed;
435+}
--- /dev/null
+++ b/nRFHello/src/pf/pf_music.c
@@ -0,0 +1,945 @@
1+//! @file pf_music.c
2+//! @brief プラットフォーム(音楽)実装ファイル
3+
4+// The MIT License (MIT)
5+// Copyright (c) 2023 @xm6_original
6+//
7+// Permission is hereby granted, free of charge, to any person obtaining a
8+// copy of this software and associated documentation files (the "Software"),
9+// to deal in the Software without restriction, including without limitation
10+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
11+// and/or sell copies of the Software, and to permit persons to whom the
12+// Software is furnished to do so, subject to the following conditions:
13+//
14+// The above copyright notice and this permission notice shall be included in
15+// all copies or substantial portions of the Software.
16+//
17+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23+// DEALINGS IN THE SOFTWARE.
24+
25+#include "pf_types.h"
26+#include "nrf52833.h"
27+#include "nrf52833_bitfields.h"
28+#include "pf_gpio.h"
29+#include "pf_timer.h"
30+#include "pf_music.h"
31+
32+//! @brief コマンド定義
33+typedef enum PF_MUSIC_CMD_Tag
34+{
35+ PF_MUSIC_CMD_LEN1 = 0, //!< 全音符(全休符)
36+ PF_MUSIC_CMD_LEN2P, //!< 符点二分音符(符点二分休符)
37+ PF_MUSIC_CMD_LEN2, //!< 二分音符(二分休符)
38+ PF_MUSIC_CMD_LEN4P, //!< 符点四分音符(符点四分休符)
39+ PF_MUSIC_CMD_LEN4, //!< 四分音符(四分休符)
40+ PF_MUSIC_CMD_LEN8P, //!< 符点八分音符(符点八分休符)
41+ PF_MUSIC_CMD_LEN8, //!< 八分音符(八分休符)
42+ PF_MUSIC_CMD_LEN16P, //!< 符点十六分音符(符点十六分休符)
43+ PF_MUSIC_CMD_LEN3, //!< 三連符(三連休符)
44+ PF_MUSIC_CMD_LEN16, //!< 十六分音符(十六分休符)
45+ PF_MUSIC_CMD_C, //!< C
46+ PF_MUSIC_CMD_CSHARP, //!< C♯/D♭
47+ PF_MUSIC_CMD_D, //!< D
48+ PF_MUSIC_CMD_DSHARP, //!< D♯/E♭
49+ PF_MUSIC_CMD_E, //!< E
50+ PF_MUSIC_CMD_F, //!< F
51+ PF_MUSIC_CMD_FSHARP, //!< F♯/G♭
52+ PF_MUSIC_CMD_G, //!< G
53+ PF_MUSIC_CMD_GSHARP, //!< G♯/A♭
54+ PF_MUSIC_CMD_A, //!< A
55+ PF_MUSIC_CMD_ASHARP, //!< A♯/B♭
56+ PF_MUSIC_CMD_B, //!< B
57+ PF_MUSIC_CMD_REST, //!< 休符
58+ PF_MUSIC_CMD_TIE, //!< タイ
59+ PF_MUSIC_CMD_TEMPO, //!< テンポ
60+ PF_MUSIC_CMD_QUANTIZE, //!< クォンタイズ
61+ PF_MUSIC_CMD_OCTAVE_UP, //!< 1オクターブ上げる
62+ PF_MUSIC_CMD_OCTAVE_DOWN, //!< 1オクターブ下げる
63+ PF_MUSIC_CMD_LOOP_SET, //!< ループ位置設定
64+ PF_MUSIC_CMD_LOOP_GO, //!< ループ位置ジャンプ
65+} PF_MUSIC_CMD;
66+
67+//! @brief サンプル曲「春が来た」メロディー
68+const PF_MUSIC_CMD pf_music_melody[] =
69+{
70+ // 初回動作
71+ PF_MUSIC_CMD_TEMPO,
72+ (PF_MUSIC_CMD)108,
73+ PF_MUSIC_CMD_OCTAVE_UP,
74+ PF_MUSIC_CMD_OCTAVE_UP,
75+ PF_MUSIC_CMD_QUANTIZE,
76+ (PF_MUSIC_CMD)7,
77+ PF_MUSIC_CMD_LOOP_SET,
78+
79+ // 第1小節
80+ PF_MUSIC_CMD_LEN4,
81+ PF_MUSIC_CMD_G,
82+ PF_MUSIC_CMD_LEN8,
83+ PF_MUSIC_CMD_E,
84+ PF_MUSIC_CMD_F,
85+ PF_MUSIC_CMD_LEN4,
86+ PF_MUSIC_CMD_G,
87+ PF_MUSIC_CMD_A,
88+
89+ // 第2小節
90+ PF_MUSIC_CMD_LEN4,
91+ PF_MUSIC_CMD_G,
92+ PF_MUSIC_CMD_LEN8,
93+ PF_MUSIC_CMD_E,
94+ PF_MUSIC_CMD_F,
95+ PF_MUSIC_CMD_LEN4,
96+ PF_MUSIC_CMD_G,
97+ PF_MUSIC_CMD_OCTAVE_UP,
98+ PF_MUSIC_CMD_C,
99+ PF_MUSIC_CMD_OCTAVE_DOWN,
100+
101+ // 第3小節
102+ PF_MUSIC_CMD_LEN4,
103+ PF_MUSIC_CMD_A,
104+ PF_MUSIC_CMD_G,
105+ PF_MUSIC_CMD_LEN4P,
106+ PF_MUSIC_CMD_E,
107+ PF_MUSIC_CMD_LEN8,
108+ PF_MUSIC_CMD_C,
109+
110+ // 第4小節
111+ PF_MUSIC_CMD_LEN2P,
112+ PF_MUSIC_CMD_D,
113+ PF_MUSIC_CMD_LEN4,
114+ PF_MUSIC_CMD_REST,
115+
116+ // 第5小節
117+ PF_MUSIC_CMD_LEN4,
118+ PF_MUSIC_CMD_G,
119+ PF_MUSIC_CMD_LEN8,
120+ PF_MUSIC_CMD_A,
121+ PF_MUSIC_CMD_G,
122+ PF_MUSIC_CMD_LEN4,
123+ PF_MUSIC_CMD_E,
124+ PF_MUSIC_CMD_G,
125+
126+ // 第6小節
127+ PF_MUSIC_CMD_LEN4,
128+ PF_MUSIC_CMD_OCTAVE_UP,
129+ PF_MUSIC_CMD_C,
130+ PF_MUSIC_CMD_LEN8,
131+ PF_MUSIC_CMD_D,
132+ PF_MUSIC_CMD_C,
133+ PF_MUSIC_CMD_OCTAVE_DOWN,
134+ PF_MUSIC_CMD_LEN4,
135+ PF_MUSIC_CMD_A,
136+ PF_MUSIC_CMD_OCTAVE_UP,
137+ PF_MUSIC_CMD_C,
138+ PF_MUSIC_CMD_OCTAVE_DOWN,
139+
140+ // 第7小節
141+ PF_MUSIC_CMD_LEN4,
142+ PF_MUSIC_CMD_G,
143+ PF_MUSIC_CMD_OCTAVE_UP,
144+ PF_MUSIC_CMD_E,
145+ PF_MUSIC_CMD_LEN4P,
146+ PF_MUSIC_CMD_D,
147+ PF_MUSIC_CMD_OCTAVE_DOWN,
148+ PF_MUSIC_CMD_LEN8,
149+ PF_MUSIC_CMD_G,
150+
151+ // 第8小節
152+ PF_MUSIC_CMD_LEN2P,
153+ PF_MUSIC_CMD_OCTAVE_UP,
154+ PF_MUSIC_CMD_C,
155+ PF_MUSIC_CMD_OCTAVE_DOWN,
156+ PF_MUSIC_CMD_LEN4,
157+ PF_MUSIC_CMD_REST,
158+
159+ // ループ
160+ PF_MUSIC_CMD_LOOP_GO,
161+};
162+
163+//! @brief サンプル曲「春が来た」ベース
164+const PF_MUSIC_CMD pf_music_base[] =
165+{
166+ // 初回動作
167+ PF_MUSIC_CMD_OCTAVE_UP,
168+ PF_MUSIC_CMD_QUANTIZE,
169+ (PF_MUSIC_CMD)6,
170+ PF_MUSIC_CMD_LOOP_SET,
171+
172+ // 第1小節
173+ PF_MUSIC_CMD_LEN8,
174+ PF_MUSIC_CMD_C,
175+ PF_MUSIC_CMD_G,
176+ PF_MUSIC_CMD_E,
177+ PF_MUSIC_CMD_G,
178+ PF_MUSIC_CMD_C,
179+ PF_MUSIC_CMD_G,
180+ PF_MUSIC_CMD_E,
181+ PF_MUSIC_CMD_G,
182+
183+ // 第2小節
184+ PF_MUSIC_CMD_LEN8,
185+ PF_MUSIC_CMD_C,
186+ PF_MUSIC_CMD_G,
187+ PF_MUSIC_CMD_E,
188+ PF_MUSIC_CMD_G,
189+ PF_MUSIC_CMD_C,
190+ PF_MUSIC_CMD_G,
191+ PF_MUSIC_CMD_E,
192+ PF_MUSIC_CMD_G,
193+
194+ // 第3小節
195+ PF_MUSIC_CMD_LEN8,
196+ PF_MUSIC_CMD_C,
197+ PF_MUSIC_CMD_G,
198+ PF_MUSIC_CMD_E,
199+ PF_MUSIC_CMD_G,
200+ PF_MUSIC_CMD_C,
201+ PF_MUSIC_CMD_G,
202+ PF_MUSIC_CMD_E,
203+ PF_MUSIC_CMD_G,
204+
205+ // 第4小節
206+ PF_MUSIC_CMD_LEN8,
207+ PF_MUSIC_CMD_OCTAVE_DOWN,
208+ PF_MUSIC_CMD_G,
209+ PF_MUSIC_CMD_OCTAVE_UP,
210+ PF_MUSIC_CMD_G,
211+ PF_MUSIC_CMD_F,
212+ PF_MUSIC_CMD_G,
213+ PF_MUSIC_CMD_E,
214+ PF_MUSIC_CMD_G,
215+ PF_MUSIC_CMD_D,
216+ PF_MUSIC_CMD_G,
217+
218+ // 第5小節
219+ PF_MUSIC_CMD_LEN8,
220+ PF_MUSIC_CMD_C,
221+ PF_MUSIC_CMD_G,
222+ PF_MUSIC_CMD_E,
223+ PF_MUSIC_CMD_G,
224+ PF_MUSIC_CMD_C,
225+ PF_MUSIC_CMD_G,
226+ PF_MUSIC_CMD_E,
227+ PF_MUSIC_CMD_G,
228+
229+ // 第6小節
230+ PF_MUSIC_CMD_LEN8,
231+ PF_MUSIC_CMD_C,
232+ PF_MUSIC_CMD_A,
233+ PF_MUSIC_CMD_F,
234+ PF_MUSIC_CMD_A,
235+ PF_MUSIC_CMD_C,
236+ PF_MUSIC_CMD_A,
237+ PF_MUSIC_CMD_F,
238+ PF_MUSIC_CMD_A,
239+
240+ // 第7小節
241+ PF_MUSIC_CMD_LEN8,
242+ PF_MUSIC_CMD_C,
243+ PF_MUSIC_CMD_G,
244+ PF_MUSIC_CMD_E,
245+ PF_MUSIC_CMD_G,
246+ PF_MUSIC_CMD_OCTAVE_DOWN,
247+ PF_MUSIC_CMD_G,
248+ PF_MUSIC_CMD_OCTAVE_UP,
249+ PF_MUSIC_CMD_G,
250+ PF_MUSIC_CMD_OCTAVE_DOWN,
251+ PF_MUSIC_CMD_B,
252+ PF_MUSIC_CMD_OCTAVE_UP,
253+ PF_MUSIC_CMD_G,
254+
255+ // 第8小節
256+ PF_MUSIC_CMD_LEN8,
257+ PF_MUSIC_CMD_C,
258+ PF_MUSIC_CMD_G,
259+ PF_MUSIC_CMD_E,
260+ PF_MUSIC_CMD_G,
261+ PF_MUSIC_CMD_LEN4,
262+ PF_MUSIC_CMD_C,
263+ PF_MUSIC_CMD_REST,
264+
265+ // ループ
266+ PF_MUSIC_CMD_LOOP_GO,
267+};
268+
269+//! @brief 音階定義
270+typedef enum PF_MUSIC_NOTE_Tag
271+{
272+ PF_MUSIC_NOTE_C = 0, //!< C
273+ PF_MUSIC_NOTE_CSHARP, //!< C♯/D♭
274+ PF_MUSIC_NOTE_D, //!< D
275+ PF_MUSIC_NOTE_DSHARP, //!< D♯/E♭
276+ PF_MUSIC_NOTE_E, //!< E
277+ PF_MUSIC_NOTE_F, //!< F
278+ PF_MUSIC_NOTE_FSHARP, //!< F♯/G♭
279+ PF_MUSIC_NOTE_G, //!< G
280+ PF_MUSIC_NOTE_GSHARP, //!< G♯/A♭
281+ PF_MUSIC_NOTE_A, //!< A
282+ PF_MUSIC_NOTE_ASHARP, //!< A♯/B♭
283+ PF_MUSIC_NOTE_B, //!< B
284+ PF_MUSIC_NOTE_MAX, //!< (音階の個数を表す)
285+} PF_MUSIC_NOTE;
286+
287+//! @brief 音階→PWM周期テーブル(PWMクロック=4MHz)
288+const u4 pf_music_note_table[PF_MUSIC_NOTE_MAX] =
289+{
290+ 30578, //!< C
291+ 28862, //!< C♯/D♭
292+ 27242, //!< D
293+ 25713, //!< D♯/E♭
294+ 24270, //!< E
295+ 22908, //!< F
296+ 21622, //!< F♯/G♭
297+ 20408, //!< G
298+ 19263, //!< G♯/A♭
299+ 18182, //!< A
300+ 17161, //!< A♯/B♭
301+ 16198, //!< B
302+};
303+
304+//! @brief コマンド→クロックテーブル
305+const u4 pf_music_cmd_to_clock[10] =
306+{
307+ // PF_MUSIC_CMD_LEN1
308+ 192,
309+
310+ // PF_MUSIC_CMD_LEN2P
311+ 144,
312+
313+ // PF_MUSIC_CMD_LEN2
314+ 96,
315+
316+ // PF_MUSIC_CMD_LEN4P
317+ 72,
318+
319+ // PF_MUSIC_CMD_LEN4
320+ 48,
321+
322+ // PF_MUSIC_CMD_LEN8P
323+ 36,
324+
325+ // PF_MUSIC_CMD_LEN8
326+ 24,
327+
328+ // PF_MUSIC_CMD_LEN16P
329+ 18,
330+
331+ // PF_MUSIC_CMD_LEN3
332+ 16,
333+
334+ // PF_MUSIC_CMD_LEN16
335+ 12
336+};
337+
338+//! @brief 音楽デバイス→PWMテーブル
339+static NRF_PWM_Type* const pf_music_device_to_pwm[PF_MUSIC_DEVICE_MAX] =
340+{
341+ NRF_PWM0, //!< 内蔵スピーカー
342+ NRF_PWM1, //!< MAQUEENスピーカー
343+};
344+
345+//! @brief 音楽デバイス→GPIOテーブル
346+static const PF_GPIO_ID pf_music_device_to_gpio[PF_MUSIC_DEVICE_MAX] =
347+{
348+ PF_GPIO_ID_INTERNAL_SPEAKER, //!< 内蔵スピーカー
349+ PF_GPIO_ID_MAQUEEN_SPEAKER, //!< MAQUEENスピーカー
350+};
351+
352+//! @brief 演奏情報構造体
353+typedef struct PF_MUSIC_INFO_Tag
354+{
355+ BOOL playing; //!< 演奏中フラグ
356+ const PF_MUSIC_CMD *ptr; //!< データポインタ
357+ const PF_MUSIC_CMD *loop; //!< ループポインタ
358+ u4 clock; //!< クロック数
359+ u4 length; //!< 音長
360+ BOOL on; //!< キーオンフラグ
361+ u4 off; //!< キーオフカウンタ
362+ u4 octave; //!< オクターブ(0=除算なし)
363+ u4 quantize; //!< クォンタイズ
364+ PF_MUSIC_NOTE note; //!< 音階
365+ BOOL tie; //!< タイフラグ
366+ s4 countertop; //!< PWM周波数
367+ BOOL lfo_enable; //!< LFO有効フラグ
368+ u4 lfo_delay; //!< LFOディレイ
369+ u4 lfo_keyon; //!< LFOディレイ(カレント)
370+ u4 lfo_cycle; //!< LFOサイクル(三角波の片方向クロック)
371+ u4 lfo_current; //!< LFOサイクル(カレント)
372+ s4 lfo_diff; //!< LFO差分
373+ s4 lfo_signed; //!< LFO差分(カレント)
374+ u2 duty; //!< デューティー比
375+} PF_MUSIC_INFO;
376+
377+//! @brief 演奏情報
378+static PF_MUSIC_INFO pf_music_info[PF_MUSIC_DEVICE_MAX];
379+
380+//! @brief PWM初期化
381+static void pf_music_init_pwm(void)
382+{
383+ NRF_PWM_Type *pwm;
384+ u4 loop;
385+ PF_GPIO_ID gpio;
386+ u4 port;
387+ u4 pin;
388+
389+ // オート変数初期化
390+ pwm = NRF_PWM0;
391+ loop = 0;
392+ gpio = PF_GPIO_ID_INTERNAL_SPEAKER;
393+ port = 0;
394+ pin = 0;
395+
396+ // 音楽デバイスだけループ
397+ for (loop = 0; loop < PF_MUSIC_DEVICE_MAX; loop++)
398+ {
399+ // PWMデバイス取得
400+ pwm = pf_music_device_to_pwm[loop];
401+
402+ // PWM停止
403+ pwm->ENABLE = PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos;
404+
405+ // イベントのショートカット
406+ pwm->SHORTS = 0;
407+
408+ // 割り込み有効
409+ pwm->INTEN = 0;
410+
411+ // 波形モード
412+ pwm->MODE = PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos;
413+
414+ // デコーダーモード
415+ pwm->DECODER = (PWM_DECODER_LOAD_Common << PWM_DECODER_LOAD_Pos)
416+ | (PWM_DECODER_MODE_NextStep << PWM_DECODER_MODE_Pos);
417+
418+ // プリスケーラー(4MHz)
419+ pwm->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_4 << PWM_PRESCALER_PRESCALER_Pos;
420+
421+ // PWM周期
422+ pwm->COUNTERTOP = pf_music_note_table[0];
423+
424+ // ループ回数(RAMテーブルをループしない)
425+ pwm->LOOP = PWM_LOOP_CNT_Disabled << PWM_LOOP_CNT_Pos;
426+
427+ // GPIO IDを取得
428+ gpio = pf_music_device_to_gpio[loop];
429+
430+ // GPIOポートとGPIOピンを取得
431+ port = pf_gpio_get_port(gpio);
432+ pin = pf_gpio_get_pin(gpio);
433+
434+ // PSEL.OUT[0]のみ使用する
435+ pwm->PSEL.OUT[0] = (pin << PWM_PSEL_OUT_PIN_Pos) | (port << PWM_PSEL_OUT_PORT_Pos)
436+ | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos);
437+
438+ // PWM有効
439+ pwm->ENABLE = PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos;
440+ }
441+}
442+
443+//! @brief キーオン
444+//! @param [in] device 音楽デバイス
445+static void pf_music_on(u4 device)
446+{
447+ NRF_PWM_Type *pwm;
448+ u4 cycle;
449+ u4 octave;
450+
451+ // オート変数初期化
452+ pwm = pf_music_device_to_pwm[device];
453+ cycle = (u4)pf_music_info[device].countertop;
454+ octave = pf_music_info[device].octave;
455+
456+ // オクターブ演算
457+ cycle >>= octave;
458+
459+ // PWM周期設定
460+ pwm->COUNTERTOP = (u2)cycle;
461+
462+ // デューティー比(31.25%)設定値は逆の68.75%とする
463+ cycle *= (16 - 5);
464+ cycle >>= 4;
465+ pf_music_info[device].duty = (u2)cycle;
466+
467+ // ポインタ
468+ pwm->SEQ[0].PTR = (u4)&pf_music_info[device].duty;
469+
470+ // 個数
471+ pwm->SEQ[0].CNT = 1;
472+
473+ // リフレッシュ
474+ pwm->SEQ[0].REFRESH = 0;
475+
476+ // 遅延
477+ pwm->SEQ[0].ENDDELAY = 0;
478+
479+ // シーケンススタート
480+ pwm->TASKS_SEQSTART[0] = PWM_TASKS_SEQSTART_TASKS_SEQSTART_Trigger
481+ << PWM_TASKS_SEQSTART_TASKS_SEQSTART_Pos;
482+}
483+
484+//! @brief キーオフ
485+//! @param [in] device 音楽デバイス
486+static void pf_music_off(u4 device)
487+{
488+ NRF_PWM_Type *pwm;
489+
490+ // オート変数初期化
491+ pwm = pf_music_device_to_pwm[device];
492+
493+ // PWM停止(DAC出力はLowレベル)
494+ pwm->TASKS_STOP = PWM_TASKS_STOP_TASKS_STOP_Trigger << PWM_TASKS_STOP_TASKS_STOP_Pos;
495+}
496+
497+//! @brief 音符
498+//! @param [in] device 音楽デバイス
499+//! @param [in] note 音階
500+static void pf_music_note(u4 device, PF_MUSIC_NOTE note)
501+{
502+ u4 off;
503+
504+ // オート変数初期化
505+ off = 0;
506+
507+ // 音階セット
508+ pf_music_info[device].note = note;
509+
510+ // タイの有無で分ける
511+ if (FALSE == pf_music_info[device].tie)
512+ {
513+ // クォンタイズを考慮してキーオフクロックを算出
514+ off = pf_music_info[device].length;
515+ off *= pf_music_info[device].quantize;
516+ off >>= 3;
517+ pf_music_info[device].off = off;
518+ }
519+ else
520+ {
521+ // タイの効力は1音きり(TIE+音符1+音符2のように構成する)
522+ pf_music_info[device].tie = FALSE;
523+ pf_music_info[device].off = 0;
524+ }
525+
526+ // クロック
527+ pf_music_info[device].clock = pf_music_info[device].length;
528+
529+ // PWM周波数設定
530+ pf_music_info[device].countertop = (s4)pf_music_note_table[note];
531+
532+ // LFO初期化
533+ pf_music_info[device].lfo_keyon = pf_music_info[device].lfo_delay;
534+ pf_music_info[device].lfo_current = pf_music_info[device].lfo_cycle;
535+ pf_music_info[device].lfo_signed = pf_music_info[device].lfo_diff;
536+
537+ // キーオン
538+ pf_music_on(device);
539+
540+ // キーオン状態
541+ pf_music_info[device].on = TRUE;
542+}
543+
544+//! @brief 休符
545+//! @param [in] device 音楽デバイス
546+static void pf_music_rest(u4 device)
547+{
548+ // キーオン中なら、キーオフ
549+ if (TRUE == pf_music_info[device].on)
550+ {
551+ pf_music_off(device);
552+
553+ // キーオフ状態
554+ pf_music_info[device].on = FALSE;
555+ }
556+
557+ // キーオフカウンタとクロック
558+ pf_music_info[device].off = 0;
559+ pf_music_info[device].clock = pf_music_info[device].length;
560+}
561+
562+//! @brief タイ
563+//! @param [in] device 音楽デバイス
564+static void pf_music_tie(u4 device)
565+{
566+ // フラグセットのみ(TIE+音符1+音符2のように構成する)
567+ pf_music_info[device].tie = TRUE;
568+}
569+
570+//! @brief テンポ
571+//! @param [in] device 音楽デバイス
572+static void pf_music_tempo(u4 device)
573+{
574+ u4 cc;
575+ u4 bpm;
576+ PF_MUSIC_CMD cmd;
577+
578+ // オート変数初期化
579+ cc = 1250000U;
580+ bpm = 0;
581+ cmd = PF_MUSIC_CMD_TEMPO;
582+
583+ // データフェッチ
584+ cmd = *(pf_music_info[device].ptr);
585+ pf_music_info[device].ptr++;
586+ bpm = (u4)cmd;
587+
588+ // 1拍=48クロックで算出する
589+ // 最適化前の式:60*1000*1000/(48*bpm)
590+ cc /= bpm;
591+
592+ pf_timer_cc(PF_TIMER_ID_MUSIC, &cc);
593+}
594+
595+//! @brief クォンタイズ
596+//! @param [in] device 音楽デバイス
597+static void pf_music_quantize(u4 device)
598+{
599+ u4 quantize;
600+ PF_MUSIC_CMD cmd;
601+
602+ // オート変数初期化
603+ quantize = 0;
604+ cmd = PF_MUSIC_CMD_QUANTIZE;
605+
606+ // データフェッチ
607+ cmd = *(pf_music_info[device].ptr);
608+ pf_music_info[device].ptr++;
609+ quantize = (u4)cmd;
610+
611+ // セット
612+ pf_music_info[device].quantize = quantize;
613+}
614+
615+//! @brief オクターブアップ
616+//! @param [in] device 音楽デバイス
617+static void pf_music_octave_up(u4 device)
618+{
619+ pf_music_info[device].octave++;
620+}
621+
622+//! @brief オクターブダウン
623+//! @param [in] device 音楽デバイス
624+static void pf_music_octave_down(u4 device)
625+{
626+ pf_music_info[device].octave--;
627+}
628+
629+//! @brief ループ位置設定
630+//! @param [in] device 音楽デバイス
631+static void pf_music_loop_set(u4 device)
632+{
633+ pf_music_info[device].loop = pf_music_info[device].ptr;
634+}
635+
636+//! @brief ループ位置ジャンプ
637+//! @param [in] device 音楽デバイス
638+static void pf_music_loop_go(u4 device)
639+{
640+ pf_music_info[device].ptr = pf_music_info[device].loop;
641+}
642+
643+//! @brief コマンド解釈
644+//! @param [in] device 音楽デバイス
645+static void pf_music_interpret(u4 device)
646+{
647+ PF_MUSIC_CMD cmd;
648+
649+ // オート変数初期化
650+ cmd = PF_MUSIC_CMD_LOOP_GO;
651+
652+ // コマンド取得
653+ cmd = *(pf_music_info[device].ptr);
654+ pf_music_info[device].ptr++;
655+
656+ // コマンド別
657+ if (cmd < PF_MUSIC_CMD_C)
658+ {
659+ // 音長設定
660+ pf_music_info[device].length = pf_music_cmd_to_clock[cmd];
661+ }
662+ else
663+ {
664+ if (cmd < PF_MUSIC_CMD_REST)
665+ {
666+ // 音符
667+ pf_music_note(device, (PF_MUSIC_NOTE)(cmd - PF_MUSIC_CMD_C));
668+ }
669+ else
670+ {
671+ // コマンド別
672+ switch (cmd)
673+ {
674+ // 休符
675+ case PF_MUSIC_CMD_REST:
676+ pf_music_rest(device);
677+ break;
678+
679+ // タイ
680+ case PF_MUSIC_CMD_TIE:
681+ pf_music_tie(device);
682+ break;
683+
684+ // テンポ
685+ case PF_MUSIC_CMD_TEMPO:
686+ pf_music_tempo(device);
687+ break;
688+
689+ // クォンタイズ
690+ case PF_MUSIC_CMD_QUANTIZE:
691+ pf_music_quantize(device);
692+ break;
693+
694+ // オクターブアップ
695+ case PF_MUSIC_CMD_OCTAVE_UP:
696+ pf_music_octave_up(device);
697+ break;
698+
699+ // オクターブダウン
700+ case PF_MUSIC_CMD_OCTAVE_DOWN:
701+ pf_music_octave_down(device);
702+ break;
703+
704+ // ループ位置設定
705+ case PF_MUSIC_CMD_LOOP_SET:
706+ pf_music_loop_set(device);
707+ break;
708+
709+ // ループ位置ジャンプ
710+ case PF_MUSIC_CMD_LOOP_GO:
711+ pf_music_loop_go(device);
712+ break;
713+
714+ // その他(この1バイトは無視)
715+ default:
716+ break;
717+ }
718+ }
719+ }
720+}
721+
722+//! @brief LFO処理
723+//! @param [in] device 音楽デバイス
724+static void pf_music_lfo(u4 device)
725+{
726+ // キーオン時かつLFO有効時に限る
727+ if ((TRUE == pf_music_info[device].on) && (TRUE == pf_music_info[device].lfo_enable))
728+ {
729+ // LFOディレイが有効であれば、デクリメント
730+ if (pf_music_info[device].lfo_keyon > 0)
731+ {
732+ pf_music_info[device].lfo_keyon--;
733+ }
734+ else
735+ {
736+ // 差分を加算
737+ pf_music_info[device].countertop += pf_music_info[device].lfo_signed;
738+
739+ // 三角波カウンタをデクリメント
740+ pf_music_info[device].lfo_current--;
741+
742+ // 0になったら、周期2倍と反転処理
743+ if (0 == pf_music_info[device].lfo_current)
744+ {
745+ pf_music_info[device].lfo_current = pf_music_info[device].lfo_cycle * 2;
746+ pf_music_info[device].lfo_signed = 0 - pf_music_info[device].lfo_signed;
747+ }
748+
749+ // キーオン
750+ pf_music_on(device);
751+ }
752+ }
753+}
754+
755+//! @brief クロック処理
756+//! @param [in] device 音楽デバイス
757+static void pf_music_clock(u4 device)
758+{
759+ // LFOは常に行う
760+ pf_music_lfo(device);
761+
762+ // キーオフチェック
763+ if (pf_music_info[device].off > 0)
764+ {
765+ pf_music_info[device].off--;
766+ if (0 == pf_music_info[device].off)
767+ {
768+ // キーオン状態であれば、キーオフ
769+ if (TRUE == pf_music_info[device].on)
770+ {
771+ pf_music_off(device);
772+ pf_music_info[device].on = FALSE;
773+ }
774+ }
775+ }
776+
777+ // クロックチェック
778+ if (pf_music_info[device].clock > 0)
779+ {
780+ pf_music_info[device].clock--;
781+ if (0 == pf_music_info[device].clock)
782+ {
783+ // コマンド解釈
784+ while (0 == pf_music_info[device].clock)
785+ {
786+ pf_music_interpret(device);
787+ }
788+ }
789+ }
790+}
791+
792+//! @brief Timerコールバック
793+//! @param [in] eventbit イベントビットパターン(bit0:クロックタイミング)
794+//! @attention Timer割り込みコンテキストで実行される
795+static void pf_music_callback(u4 /*eventbit*/)
796+{
797+ u4 loop;
798+
799+ // オート変数初期化
800+ loop = 0;
801+
802+ // 音楽デバイスだけループ
803+ for (loop = 0; loop < PF_MUSIC_DEVICE_MAX; loop++)
804+ {
805+ // 演奏中の場合に限る
806+ if (TRUE == pf_music_info[loop].playing)
807+ {
808+ pf_music_clock(loop);
809+ }
810+ }
811+}
812+
813+//! @brief 音楽演奏初期化
814+//! @remarks プラットフォーム初期化処理から呼び出すこと
815+//! @attention GPIO初期化およびTimer初期化の後に呼び出すこと
816+void pf_music_init(void)
817+{
818+ // PWM初期化
819+ pf_music_init_pwm();
820+
821+ // Timerコールバック関数設定
822+ pf_timer_callback(PF_TIMER_ID_MUSIC, pf_music_callback);
823+}
824+
825+//! @brief 演奏開始のためのセットアップ
826+//! @param [in] device 音楽デバイス
827+//! @param [in] sequence シーケンスデータ
828+static void pf_music_setup(u4 device, const PF_MUSIC_CMD *sequence)
829+{
830+ // 演奏中フラグ
831+ pf_music_info[device].playing = TRUE;
832+
833+ // カレントポインタとループポインタ
834+ pf_music_info[device].ptr = sequence;
835+ pf_music_info[device].loop = sequence;
836+
837+ // 初回クロック
838+ pf_music_info[device].clock = 1;
839+
840+ // 音長(デフォルトで四分音符)
841+ pf_music_info[device].length = 48;
842+
843+ // キーオン状態
844+ pf_music_info[device].on = FALSE;
845+
846+ // キーオフするまでのカウンタ
847+ pf_music_info[device].off = 0;
848+
849+ // オクターブ
850+ pf_music_info[device].octave = 0;
851+
852+ // クォンタイズ(1~8)
853+ pf_music_info[device].quantize = 8;
854+
855+ // タイフラグ
856+ pf_music_info[device].tie = FALSE;
857+
858+ // LFO有効フラグ
859+ pf_music_info[device].lfo_enable = FALSE;
860+
861+ // LFOディレイ
862+ pf_music_info[device].lfo_delay = 0;
863+ pf_music_info[device].lfo_keyon = 0;
864+
865+ // LFOサイクル
866+ pf_music_info[device].lfo_cycle = 0;
867+ pf_music_info[device].lfo_current = 0;
868+
869+ // LFO差分
870+ pf_music_info[device].lfo_diff = 0;
871+ pf_music_info[device].lfo_signed = 0;
872+}
873+
874+//! @brief 音楽演奏開始
875+void pf_music_play(void)
876+{
877+ u4 loop;
878+ BOOL playing;
879+
880+ // オート変数初期化
881+ loop = 0;
882+ playing = FALSE;
883+
884+ // 音楽デバイスだけループ
885+ for (loop = 0; loop < PF_MUSIC_DEVICE_MAX; loop++)
886+ {
887+ // どちらかが演奏中なら、演奏中フラグを立てる
888+ if (TRUE == pf_music_info[loop].playing)
889+ {
890+ playing = TRUE;
891+ }
892+ }
893+
894+ // ともに演奏停止中の場合
895+ if (FALSE == playing)
896+ {
897+ // 音楽デバイスのセットアップ
898+ pf_music_setup(0, pf_music_base);
899+ pf_music_setup(1, pf_music_melody);
900+
901+ // メロディー側のみLFOを有効にする
902+ pf_music_info[1].lfo_enable = TRUE;
903+ pf_music_info[1].lfo_delay = 30;
904+ pf_music_info[1].lfo_cycle = 12;
905+ pf_music_info[1].lfo_diff = 14;
906+
907+ // タイマ開始
908+ pf_timer_start(PF_TIMER_ID_MUSIC);
909+ }
910+}
911+
912+//! @brief 音楽演奏開始
913+void pf_music_stop(void)
914+{
915+ u4 loop;
916+ BOOL playing;
917+
918+ // オート変数初期化
919+ loop = 0;
920+ playing = FALSE;
921+
922+ // 音楽デバイスだけループ
923+ for (loop = 0; loop < PF_MUSIC_DEVICE_MAX; loop++)
924+ {
925+ // どちらかが演奏中なら、演奏中フラグを立てる
926+ if (TRUE == pf_music_info[loop].playing)
927+ {
928+ playing = TRUE;
929+ }
930+ }
931+
932+ // どちらかが演奏中の場合
933+ if (TRUE == playing)
934+ {
935+ // タイマ停止
936+ pf_timer_stop(PF_TIMER_ID_MUSIC);
937+
938+ // 演奏停止
939+ for (loop = 0; loop < PF_MUSIC_DEVICE_MAX; loop++)
940+ {
941+ pf_music_info[loop].playing = FALSE;
942+ pf_music_off(loop);
943+ }
944+ }
945+}
--- a/nRFHello/src/pf/pf_patrol.c
+++ b/nRFHello/src/pf/pf_patrol.c
@@ -70,16 +70,16 @@ static void pf_patrol_task_id(PF_PATROL_ID id)
7070 // オート変数初期化
7171 gpio = pf_patrol_to_gpio[id];
7272
73- // 現在のフォトリフレクタ情報を取得(GPIOからの入力が'L'で白色)
73+ // 現在のフォトリフレクタ情報を取得(GPIOからの入力が'L'で黒色)
7474 if (FALSE == pf_gpio_input(gpio))
7575 {
76- // 白色
77- pf_patrol_info[id] = PF_PATROL_COLOR_WHITE;
76+ // 黒色
77+ pf_patrol_info[id] = PF_PATROL_COLOR_BLACK;
7878 }
7979 else
8080 {
81- // 黒色
82- pf_patrol_info[id] = PF_PATROL_COLOR_BLACK;
81+ // 白色
82+ pf_patrol_info[id] = PF_PATROL_COLOR_WHITE;
8383 }
8484 }
8585
@@ -103,7 +103,7 @@ void pf_patrol_task(void)
103103 //! @brief ラインセンサの白黒状態を取得
104104 //! @param [in] id ラインセンサのID
105105 //! @return 色状態(PF_PATROL_COLOR_WHITE=白色/PF_PATROL_COLOR_BLACK=黒色)
106-PF_PATROL_COLOR pf_patrol_get(PF_PATROL_ID id)
106+PF_PATROL_COLOR pf_patrol_line(PF_PATROL_ID id)
107107 {
108108 PF_PATROL_COLOR result;
109109
--- a/nRFHello/src/pf/pf_power.c
+++ b/nRFHello/src/pf/pf_power.c
@@ -105,6 +105,9 @@ static void pf_power_greetings(void)
105105
106106 // 表示OFF
107107 pf_display_off();
108+
109+ // 明るさ再設定
110+ pf_display_brightness(80);
108111 }
109112
110113 //! @brief Power初期化
--- a/nRFHello/src/pf/pf_timer.c
+++ b/nRFHello/src/pf/pf_timer.c
@@ -65,11 +65,24 @@ const PF_TIMER_INIT pf_timer_table[PF_TIMER_ID_MAX] =
6565 PF_INTERRUPT_PRI_DISPLAY_TIMER, // 割り込み優先度
6666 PF_TIMER_ACTION_INTERVAL, // Timer動作
6767 2, // コンペア数
68- MICROSEC_TO_TIMERCC(900), // コンペア値(0)
68+ MICROSEC_TO_TIMERCC(800), // コンペア値(0)
6969 MICROSEC_TO_TIMERCC(1000), // コンペア値(1)
7070 0, // コンペア値(2)
7171 0, // コンペア値(3)
7272 },
73+
74+ // PF_TIMER_ID_MUSIC
75+ {
76+ 1, // チャネル
77+ NRF_TIMER1, // デバイス
78+ PF_INTERRUPT_PRI_MUSIC, // 割り込み優先度
79+ PF_TIMER_ACTION_INTERVAL, // Timer動作
80+ 1, // コンペア数
81+ MICROSEC_TO_TIMERCC(12500), // コンペア値(0)
82+ 0, // コンペア値(1)
83+ 0, // コンペア値(2)
84+ 0, // コンペア値(3)
85+ },
7386 };
7487
7588 //! @brief compares→CLEARビットテーブル
@@ -103,15 +116,15 @@ static const IRQn_Type pf_timer_to_irq[PF_TIMER_CHANNEL_MAX] =
103116 };
104117
105118 //! @brief Timer動作情報構造体
106-typedef struct PF_TIMER_STATUS_Tag
119+typedef struct PF_TIMER_INFO_Tag
107120 {
108121 PF_TIMER_CALLBACK callback; //!< コールバック関数
109122 u4 cc[4]; //!< コンペア値
110123 BOOL running; //!< 動作中フラグ
111-} PF_TIMER_STATUS;
124+} PF_TIMER_INFO;
112125
113126 //! @brief Timer動作情報テーブル
114-static PF_TIMER_STATUS pf_timer_status[PF_TIMER_ID_MAX];
127+static PF_TIMER_INFO pf_timer_info[PF_TIMER_ID_MAX];
115128
116129 //! @brief INTENSETレジスタへの設定値を得る
117130 //! @param [in] id TimerのID
@@ -212,12 +225,12 @@ static void pf_timer_init_id(PF_TIMER_ID id)
212225 }
213226
214227 // 動作情報テーブルを初期化
215- pf_timer_status[id].callback = NULL;
216- pf_timer_status[id].cc[0] = pf_timer_table[id].cc0;
217- pf_timer_status[id].cc[1] = pf_timer_table[id].cc1;
218- pf_timer_status[id].cc[2] = pf_timer_table[id].cc2;
219- pf_timer_status[id].cc[3] = pf_timer_table[id].cc3;
220- pf_timer_status[id].running = FALSE;
228+ pf_timer_info[id].callback = NULL;
229+ pf_timer_info[id].cc[0] = pf_timer_table[id].cc0;
230+ pf_timer_info[id].cc[1] = pf_timer_table[id].cc1;
231+ pf_timer_info[id].cc[2] = pf_timer_table[id].cc2;
232+ pf_timer_info[id].cc[3] = pf_timer_table[id].cc3;
233+ pf_timer_info[id].running = FALSE;
221234
222235 // 割り込み設定
223236 irq = pf_timer_to_irq[id];
@@ -259,7 +272,7 @@ void pf_timer_start(PF_TIMER_ID id)
259272 TIMER_TASKS_START_TASKS_START_Trigger << TIMER_TASKS_START_TASKS_START_Pos;
260273
261274 // 動作中フラグセット(割り込み干渉を考慮する必要はない)
262- pf_timer_status[id].running = TRUE;
275+ pf_timer_info[id].running = TRUE;
263276 }
264277 }
265278
@@ -275,7 +288,7 @@ void pf_timer_stop(PF_TIMER_ID id)
275288 << TIMER_TASKS_STOP_TASKS_STOP_Pos;
276289
277290 // 動作中フラグクリア(割り込み干渉を考慮する必要はない)
278- pf_timer_status[id].running = FALSE;
291+ pf_timer_info[id].running = FALSE;
279292 }
280293 }
281294
@@ -303,7 +316,7 @@ void pf_timer_callback(PF_TIMER_ID id, PF_TIMER_CALLBACK func)
303316 NVIC_DisableIRQ(irq);
304317
305318 // コールバック関数設定
306- pf_timer_status[id].callback = func;
319+ pf_timer_info[id].callback = func;
307320
308321 // 割り込み復元
309322 if (0 != enable)
@@ -339,10 +352,10 @@ void pf_timer_cc(PF_TIMER_ID id, u4 *cc)
339352 for (loop = 0; loop < pf_timer_table[id].compares; loop++)
340353 {
341354 // 異なっている要素だけ設定する
342- if (pf_timer_status[id].cc[loop] != cc[loop])
355+ if (pf_timer_info[id].cc[loop] != cc[loop])
343356 {
344- pf_timer_status[id].cc[loop] = cc[loop];
345- pf_timer_table[id].dev->CC[loop] = pf_timer_status[id].cc[loop];
357+ pf_timer_info[id].cc[loop] = cc[loop];
358+ pf_timer_table[id].dev->CC[loop] = pf_timer_info[id].cc[loop];
346359 }
347360 }
348361
@@ -418,9 +431,9 @@ static void pf_timer_isr(u4 channel)
418431 }
419432
420433 // Timerコールバック関数が登録されていれば、呼び出す
421- if (NULL != pf_timer_status[id].callback)
434+ if (NULL != pf_timer_info[id].callback)
422435 {
423- pf_timer_status[id].callback(compare);
436+ pf_timer_info[id].callback(compare);
424437 }
425438 }
426439 }