API collection of Ukifune. Initial publish. Documents are not ready.

ukifuneはUI基板『浮舟』のAPIモジュールです。 浮舟はNucleo F746ZGに接続して使うUI基板で、以下のような特徴を持っています。

  • ピアノ鍵盤を模した13個のタクトスイッチ
  • 3個のモード切り替えスイッチ
  • 12個のLED
  • 2ポートのI2Cを通して使える計8個のボリューム。

以下にukifuneモジュール及び浮舟について解説します。

ハードウェア

浮舟基板は、Nucleo F746ZGのCN12ヘッダーに接続して使うUI基板です。 /media/uploads/shorie/imgp2217.jpg この写真では中央下の緑の基板が浮舟です。上の白い基板はNucleo F746ZGで、その上には、変換基板桐壺を介してアクアシグナルのUMB-ADAU1361-Aが接続されています。また、浮舟の両側にはやはりアクアシグナルのTPOL-POT4-Aが接続されています。

Nucleo F746ZGのCN12は非常に多くのピンが用意されていますが、そのうち最初の50ピンのみを使っています。使用している機能はGPIO機能のほか、I2C3およびI2C4ポートです。I2C2ポートは、CN11で使えるように手付かずであけてあります。

プッシュボタンはアンチ・チャタリング回路を入れていますが、簡易型であるためあまり効きがよくありません。現時点ではキャパシタの無駄です。追試してみたい方は時定数を大きくするか、いっそアンチ・チャタリング回路をやめてもいいでしょう。

LEDもプッシュボタンも、アクティブHです。すなわち、LEDは論理状態1で点灯し、プッシュボタンを押すと論理状態が1になります。

I2Cポートは基板でプルアップした後、外部に開放しています。これらはアクアシグナルのTOL-POT4-Aに直結できるピン配置になっています。 浮舟基板にはテストポイントが3本出ています。うち1本はGNDで、残りの2本は割り込み処理時間と信号処理時間を測定するためのステータスピンです。

ソフトウェア

ukifuneモジュールは浮舟基板制御用のAPI群です。これらは名前空間ukifuneでラップされており、ukifune.hを読むことで利用できます。 APIの一覧については、このページのAPI Documentationタブを参照してください。APIドキュメントには、LEDおよびプッシュ・ボタン・スイッチをプログラムから参照するための識別子も列挙してあります。

ukifuneモジュールのAPIを使用するためには、事前にukifune::init() APIを一度だけ呼ぶ必要があります。このAPIは内部変数を初期化するほか、雲仙オーディオフレームワークへのポインタを受け取り、フレームワークに対してテストピンを駆動するためのコールバック群を登録します。

ボリュームを使う場合には、周期的に ukifune::tick() を呼んでください。このAPIは呼ばれるたびにI2C経由でADCにアクセスしてアナログ値を読み取り、ukifuneモジュールの内部変数を更新します。呼び出し周期はおおむね50mS以内であれば十分でしょう。周期の精度については適当でかまいません。

プッシュボタンの状態を知りたい場合には、ukifune::get_button_state() を呼び出します。このAPIは3つのビットマスクを返します。

pushing 引数は、前回のAPI呼び出し時からどのボタンが押し込まれたかを返します。言い換えると、前回押されていなかったにもかかわらず、今回のAPI呼び出しで押されていることが検出されたボタンがこの変数から返されます。pushing引数はビットマップであり、ビット位置は enum ukifune::SWITCHの要素の値に対応します。対応するビットが1であるようなスイッチが、押し込まれたスイッチです。

releasing 引数は、前回のAPI呼び出し時からどのボタンが戻されたかを返します。言い換えると、前回押されていたにもかかわらず、今回のAPI呼び出しで押されていないことが検出されたプッシュボタンがこの変数から返されます。releasing引数はビットマップであり、ビット位置は enum ukifune::SWITCHの要素の値に対応します。対応するビットが1であるようなスイッチが、戻されたスイッチです。

pushed 引数は、どのボタンが押されているかを返します。pushed引数はビットマップであり、ビット位置は enum ukifune::SWITCHの要素の値に対応します。対応するビットが1であるようなスイッチが、押されているスイッチです。

ukifune::get_volume()は、ボリュームの状態を返します。引数は0から7の整数で、ボリュームに対応します。返り値の範囲は0から1.0です。

基板設計情報およびパーツリスト

ukifuneの 基板設計情報をアップロードしておきます( 2017/01/28, ver 2 )。

この基板はKiCad 4.0.2 で設計し、出力したgerberデータをスイッチサイエンスの基板製造サービスで製造し、動作を確認しています(写真)。万に一つのことがありますので、基板を外注に出す方は、くれぐれも事前の注意を払ってください。また、この基板は実験用に作成したものであり、民生、産業、医療などの用途に耐えるような設計ではありません。どのような理由であれ、この基板によって発生した問題については責任を取りません。

部品表は以下の通りです。C1の脚の幅にご注意ください。LEDやプッシュボタン・スイッチの色は任意です。なお、U1だけは表面実装部品です。ご注意ください。 以下の部品の他に、Nucleo側のピンヘッダおよび、基板接続用のフラットケーブル(圧接コネクタ付き)が必要です。

ReferenceValueFootprint注釈
C10.1uCapacitors_ThroughHole:C_Disc_D3_P2.50.1uF ピン幅2.54mm
C210uCapacitors_ThroughHole:C_Radial_D5_L6_P2.510uF ピン幅2.54mm
C30.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C40.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C50.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C60.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C70.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C80.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C90.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C100.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C110.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C120.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C130.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C140.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C150.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C160.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C170.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
C180.1uCapacitors_ThroughHole:C_Disc_D6_P50.1uF ピン幅5.08mm
D1_1LEDLEDs:LED-3MMLED ピン幅2.54mm
D1_2LEDLEDs:LED-3MMLED ピン幅2.54mm
D1_3LEDLEDs:LED-3MMLED ピン幅2.54mm
D1_4LEDLEDs:LED-3MMLED ピン幅2.54mm
D2_1LEDLEDs:LED-3MMLED ピン幅2.54mm
D2_2LEDLEDs:LED-3MMLED ピン幅2.54mm
D2_3LEDLEDs:LED-3MMLED ピン幅2.54mm
D2_4LEDLEDs:LED-3MMLED ピン幅2.54mm
D3_1LEDLEDs:LED-3MMLED ピン幅2.54mm
D3_2LEDLEDs:LED-3MMLED ピン幅2.54mm
D3_3LEDLEDs:LED-3MMLED ピン幅2.54mm
D3_4LEDLEDs:LED-3MMLED ピン幅2.54mm
P1CONN_02X25Pin_Headers:Pin_Header_Straight_2x25ピンヘッダ 2x25 2.54mm
P2CONN_02X05Pin_Headers:Pin_Header_Straight_2x05ピンヘッダ 2x5 2.54mm
P3CONN_02X05Pin_Headers:Pin_Header_Straight_2x05ピンヘッダ 2x5 2.54mm
R1660Resistors_ThroughHole:Resistor_Horizontal_RM7mm660Ω 炭素皮膜
R2660Resistors_ThroughHole:Resistor_Horizontal_RM7mm660Ω 炭素皮膜
R3660Resistors_ThroughHole:Resistor_Horizontal_RM7mm660Ω 炭素皮膜
R4660Resistors_ThroughHole:Resistor_Horizontal_RM7mm660Ω 炭素皮膜
R5660Resistors_ThroughHole:Resistor_Horizontal_RM7mm660Ω 炭素皮膜
R6660Resistors_ThroughHole:Resistor_Horizontal_RM7mm660Ω 炭素皮膜
R7660Resistors_ThroughHole:Resistor_Horizontal_RM7mm660Ω 炭素皮膜
R8660Resistors_ThroughHole:Resistor_Horizontal_RM7mm660Ω 炭素皮膜
R9660Resistors_ThroughHole:Resistor_Horizontal_RM7mm660Ω 炭素皮膜
R10660Resistors_ThroughHole:Resistor_Horizontal_RM7mm660Ω 炭素皮膜
R11660Resistors_ThroughHole:Resistor_Horizontal_RM7mm660Ω 炭素皮膜
R12660Resistors_ThroughHole:Resistor_Horizontal_RM7mm660Ω 炭素皮膜
R13330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R14330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R15330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R16330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R17330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R18330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R19330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R20330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R21330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R22330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R23330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R24330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R25330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R26330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R27330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R28330kResistors_ThroughHole:Resistor_Horizontal_RM7mm330kΩ 炭素皮膜
R292.2kResistors_ThroughHole:Resistor_Horizontal_RM7mm2.2kΩ 炭素皮膜
R302.2kResistors_ThroughHole:Resistor_Horizontal_RM7mm2.2kΩ 炭素皮膜
R312.2kResistors_ThroughHole:Resistor_Horizontal_RM7mm2.2kΩ 炭素皮膜
R322.2kResistors_ThroughHole:Resistor_Horizontal_RM7mm2.2kΩ 炭素皮膜
SWM1SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWM2SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWM3SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWK1SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWK2SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWK3SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWK4SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWK5SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWK6SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWK7SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWK8SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWK9SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWK10SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWK11SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWK12SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
SWK13SPSTButtons_Switches_ThroughHole:SW_PUSH_6mmタクトスイッチ
TP1TEST_1PPin_Headers:Pin_Header_Straight_1x01
TP2TEST_1PPin_Headers:Pin_Header_Straight_1x01
TP3TEST_1PPin_Headers:Pin_Header_Straight_1x01
U1TA48M033FTO_SOT_Packages_SMD:TO-252-2LeadSMD 3.3V レギュレータ

Nucleo F746ZGの改造

Nucleo F746ZGは非常に多機能なSoCマイコンを使っています。多くの機能がピンに多重化されているものの、一部は基板外の複数の信号がピンを奪い合う形になっています。これを解決するために、Nucleo F746ZGには多くのショート・ブリッジがあります。

浮舟基板を使うためにはNucleo F746ZGの以下のショート・ブリッジを取り去ってください。

  • SB125
  • SB132
  • SB133
  • SB178
  • SB181

また、以下のジャンパー・ピンはオープンにしてください。

  • JP6
  • JP7

以上の改造によって、Nucelo F746ZGのEthernetポートおよび、USB OTGポートが使用できなくなります(ホストと接続しているmbed用USBポートには影響はありません)。

既知の問題

  • アンチ・チャタリング回路は見直した方がいいです。現状でチャタリングが残っています。
  • C1は他のキャパシタと異なり、2.54mmピッチです。

参考リンク

Revision:
1:6253da3ab855
Parent:
0:bb828a2c4208
Child:
7:e2a690a654ff
--- a/ukifune.cpp	Sat Jan 21 07:16:57 2017 +0000
+++ b/ukifune.cpp	Sun Jan 22 13:51:48 2017 +0000
@@ -1,17 +1,19 @@
 #include "mbed.h"
 #include "ukifune.h"
 #include "unzen.h"
+#include "amakusa.h"
 
 #define AD7999 (0x29<<1)
 #define ADCBUFSIZE 8
-
+#define ADCNUM 8
 
 namespace ukifune
 {
         // 
     DigitalOut *leds[12];
     DigitalIn *switches[16];
-    float adc[8];
+    float adc[ADCNUM];
+    amakusa::Hysteresis * hysteresis[ADCNUM];
     
         
         // Test points
@@ -36,7 +38,7 @@
     
         // Mode Button
     DigitalIn SWM1(PD_14);
-    DigitalIn SWM2(PB_3);
+    DigitalIn SWM2(PB_4);
     DigitalIn SWM3(PA_12);
     
         // Key Button
@@ -50,7 +52,7 @@
     DigitalIn SWK8(PB_12);
     DigitalIn SWK9(PA_7);
     DigitalIn SWK10(PA_6);
-    DigitalIn SWK11(PD_8);
+    DigitalIn SWK11(PC_7);
     DigitalIn SWK12(PC_5);
     DigitalIn SWK13(PC_8);
 
@@ -81,6 +83,7 @@
     
     void init( unzen::Framework *audio)
     {
+            
             // Setup interrupt/process activity flag.
         audio->set_pre_interrupt_callback( assert_interrupt_flag );
         audio->set_post_interrupt_callback( deassert_interrupt_flag );
@@ -120,11 +123,15 @@
         switches[ swk11 ] = & SWK11;
         switches[ swk12 ] = & SWK12;
         switches[ swk13 ] = & SWK13;
+        
+        for ( int i= 0; i<ADCNUM; i++ )
+            hysteresis[ i ] = new amakusa::Hysteresis((int32_t)0,(int32_t) 255);
+            
     }
     
     void get_button_state(
-            uint32_t & rising, 
-            uint32_t & falling, 
+            uint32_t & pusshing, 
+            uint32_t & releasing, 
             uint32_t & pushed )
     {
         static int last_button  = 0;
@@ -144,10 +151,10 @@
         pushed = current_button; 
         
             // buttons which are pushed from last state.
-        rising =  ( last_button ^ current_button ) & current_button;
+        pusshing =  ( last_button ^ current_button ) & current_button;
         
             // buttons which are released from last state
-        falling = ( last_button ^ current_button ) & last_button;
+        releasing = ( last_button ^ current_button ) & last_button;
         
         last_button = current_button;
     }
@@ -172,13 +179,52 @@
         return *( leds[ led ] );
     }
 
+    float get_volume( int number )
+    {
+        if ( number < 0)
+            return 0.0;
+        if ( number >= ADCNUM )
+            return 0.0;
+            
+        return adc[ number ];
+            
+    }
+
+    void parse_adc( char * buf, int &ch, int &data )
+    {
+        ch = ( buf[0] & 0x30 ) >> 4;
+        data = 
+            ( buf[0] & 0x0F ) << 4 |
+            ( buf[1] & 0xF0 ) >> 4;
+        
+    } 
+
+
+
     void tick(void)
     {
-        unsigned char adcbuf[ADCBUFSIZE];
+        char adcbuf[ADCBUFSIZE];
+        int ch, data;
         
-        i2c3..read( AD7999, adcbuf, 8);
-        i2c4..read( AD7999, adcbuf, 8);
-
+        i2c3.read( AD7999, adcbuf, 8);
+        parse_adc(& adcbuf[0], ch, data);
+        adc[ch] = hysteresis[ch]->run( data ) / 255.0;
+        parse_adc(& adcbuf[2], ch, data);
+        adc[ch] = hysteresis[ch]->run( data ) / 255.0;
+        parse_adc(& adcbuf[4], ch, data);
+        adc[ch] = hysteresis[ch]->run( data ) / 255.0;
+        parse_adc(& adcbuf[6], ch, data);
+        adc[ch] = hysteresis[ch]->run( data ) / 255.0;
+        
+        i2c4.read( AD7999, adcbuf, 8);
+        parse_adc(& adcbuf[0], ch, data);
+        adc[ch+4] = hysteresis[ch+4]->run( data ) / 255.0;
+        parse_adc(& adcbuf[2], ch, data);
+        adc[ch+4] = hysteresis[ch+4]->run( data ) / 255.0;
+        parse_adc(& adcbuf[4], ch, data);
+        adc[ch+4] = hysteresis[ch+4]->run( data ) / 255.0;
+        parse_adc(& adcbuf[6], ch, data);
+        adc[ch+4] = hysteresis[ch+4]->run( data ) / 255.0;
     }