● 実験テーマ33

「PIC32MX_タッチパネル(T.P)の実験〜T.Pを使用したオシロの実験」

■ 2013.5.27
  ・とりあえず、タッチパネルのTESTプログラムは、後閑氏が、
   dsPIC33Fオシロの時に、デバッグ用で、タッチ座標位置表示ルーチンを
   組込んでいるので、その部分のみチョイスする形で進めてみる。

   但し、後閑氏のそれは、タッチパネルコントローラICを使用しないで
   PIC内蔵のADに、タッチ信号を直接入力している方式なので
   今回、私がやろうとしている、タッチコントローラIC:XPT2046への
   アクセス・プログラムは独自に検討しなければならない。

 

 

 

 

 

 

 

 

 

 


■ 2013.5.30
  ・今迄、仕事でタッチパネルを扱ったことはあるが、その時のハードは、キーシートの延長線上
   のもので、パネル内部にメカスイッチがマトリックス状に配置された単純なものであった。
   抵抗膜式のタッチパネルは初体験である。
   そこで、まずは、抵抗膜式のタッチパネルの原理を学習してみることにした。
   これについての参考文献は、トラ技の過去の記事にもあったし、後閑氏のHPにも解説が
   載っているので、それを参考にしました。
   以下は、私なりに理解した内容を、ごく簡単にまとめたものです。


■ 2013.5.31
  ・大方、タッチポイント座標表示のデバッグルーチンと、タッチ構造・原理はできたので、今日は、
   いよいよ今回の核となる、タッチパネル・コントローラICの、SPI制御について、ライブラリ化を
   前提に考えてみる。
   遅れましたが、
今回の液晶に搭載のタッチパネル・コントローラICは、TI社の「ADS7843」と互換性
   のある
中国製(SHENZHEN XPTEK TECHNOLOGY CO., LTD)の、「XPT2046」という、
   4線式抵抗膜タッチパネルを、SPIで制御するものです。

  ・aitendoのHPに、当該製品の参考コードが載っていたので、ダウンロード(rar圧縮されたファイル)
   したが、WIN_ZIPで解凍したら、何故かプログラム・コメントが文字化けを起こしており、
   解析するには、障害となってしまうが、これを基に検討することにした。


■ 2013.6.1〜 2013.6.3
  ・ここまで、aitendo_HPの参考コードの解析を行ってきた。
   かなり多くのタッチ関連の関数が用意されていたが、この内どこまで必要か?
   どれをチョイスして、どう後閑氏のテストプロとリンクさせるかを、今日は検討してみたい。
  → とりあえず、参考コードの中で、SPI制御で、「XPT2046」内蔵のADの、変換値を読み出すのに
     必要な最小限の関数は、以下の2つがあれば事足りると思われる。
     (関数名の付け方として、頭の文字をコントローラICの型番、頭3文字としているので、
      参考コードの、TI社のADSを、XPTに変更することにした。また参考コードの対象としているMPU
            は、stMicro社の、「STM32」なので、このソースをPIC32MXに移植すべき変数型などの記述
     を適時変更しています。)

   <SPI制御に必要な最低限の関数2つ>
    @ void XPT_Write_Byte(unsigned char num)
    → コマンド・ライト関数(8クロック・サイクル)
       引数:num→ SPIコマンド・コードを指定
       以下の2つ目の関数の下請け関数になる。

    A unsigned short XPT_Read_AD(unsigned char CMD)
    → 12bitAD変換値読込み関数(16クロック・サイクル)
       引数:CMD→ CMD_RDX(0xD0)又は、CMD_RDY(0x90)を指定
       戻り値:Num→ AD変換の読み値を返す。

  ・以下に、最初に、参考コードを解析した時の、メモ書き程度のドキュメント(画像)をアップしておきます。
   この時点で考えたままのことを書いてますので、あくまでも最終形でなく途中経過のものとして参照
   してください。

  ・割込みは、PENIRQ/(ペン割込み)出力信号のよる外部エッジ割込み(INT割込み)にしようと
   思う。(最初はこう考えたのだが、これが中々難航するハメに・・・・・・)
  → たぶんスクリーン上の何処かをタッチした時に負パルスが出力されると思われるので
     立下りトリガに設定すればよいはず。
  → この割込み関数の中で、後閑氏の、T1(50mS周期)割込みで行っているタッチ処理(PIC内
     ADを使っている方式)を今回の、XPT2046コントローラを使った方法に適合した書き方に変えれば
     よいはずだが・・・・
  → PENIRQ/信号について、XPTの英文データシートで調べてみた。
     ざっと回路ブロックをみた感じでは、どうも、X+信号をレベルシフトした信号が出ているようである。
     また途中にバッファICらしきものが入っているのでチャッターは少ないと思われる。


■ 2013.6.4
  ・大方、ソフト案のテキスト(TOUCH_TEST_PRO(Plan).txt)は出来たので、次の手順で作業を進める
   ことにした。
    @ ここで、タッチ関係の制御信号を水魚堂回路図に追加し、ポートを確定する。
      (とりあえず全ての制御信号を配線するが、BUSY線は未使用としてみる。)
    A ソースとしてまとめる。
      a. イニシャルにSPIレベル初期化を追加
      b. タッチ関連は、ライブラリーとしてまとめる。

  ・ハードの見直し
   PENIRQ/信号を受ける外部割込みピンは、INT0が空いているので、これを使うことにする。
   (他の、INT1〜4はSWに接続されているため)


■ 2013.6.5
  ・一応、ソフトまとめ終了
   コンパイルの準備が出来た。
  → 凡ミス多発(スペルミスなど)だったが、割とすんなりコンパイルOKになる。

  <動作確認: 1回目>
   ・トリガボタンの、△▽キャラクターは表示する。
   ・△をタッチすると座標が表示されるが、X= 095, Y= 095となる。
    また、どこをタッチしても、この値に変化なし。

  <調査>
   ・まず、スクリーン上のどこかをタッチすると、PENIRQ/によるINT0外部割込みが掛るか、LEDにて
    確認
   → どこかをタッチすると、INT0割込み関数の頭に入れた、LED_ON行が実行され点灯して止まる
      ので、INT0に正常にジャンプしている。
   → また、Checkbtn(x,y)ルーチンの最初の、タッチ座標表示のところまでは、RUNしているが、
      どこかをタッチしてそこでブレイクして座標を確認するが、どこをタッチしても
      X= 095 Y= 095となる?

  ・ここで大きな誤り発見
   それは、DOUTのデファインを、LAT・・・と記述してしまったことである。
   この信号名は、XPT側にとっての出力信号なので、PIC32MX側では当然入力になる。
   つまり、PORT・・・・と定義しないとダメ。
  → この修正を行ったら、AD変換値が変わるようになったが、変換値が、メチャクチャにバラツク。
  → そこでハードをまず疑う。
     ポート割付(ソフト)+回路図の再確認はOK
     また実配線もOK


■ 2013.6.6
  ・タッチ入力アンプ形態を、ノイズの点から有利な差動入力にしているのだが、シンプルなシングルエンド
   に設定をかえてみたが関係なし。
  ・参考コードのままだと、TCLKの周期は、特に遅延を入れてないので、相当速いはずで、もしかしたら
   これでは規格オーバーになって動かないと思って最初から、1uSの遅延を入れ大凡、500kHzの
   転送スピードにしたつもりであるが、
   
XPTのクロック周期の規格を調べると、400nS(min)= 2.5MHz(max)であった。
   AD変換読み値の安定化の為に、複数回サンプル+変換を繰返し、さらにソート+平均化したデータ
   を最終的に座標として割込み中で扱っているので、1回の変換は早いほど望ましいと考える。
   そのためには、規格の上限付近に設定してみた方が、ソフトの流れがよくなると考え、
   
TCLKの周波数を、2MHzに設定してみることにした。
   それも割と正確にと思い、FORループによる方法や、NOPを単純に並べる方法などで、
   それだけ実行させてカウンタで実測し確認しながら記述を確定しようと考えた。
   ・・・明日に続く。


■ 2013.6.7
  <TCLK周波数= 2MHz設定の試行錯誤>
   ・まず、delay無しに、ただポート='0'、ポート='1'を交互に繰り返すだけにした場合の、カウンタでの
    実測は、6.6Mzであった。つまりこれがMAXで、このままでは規格オーバーになる。
   ・結局、Nop();をサブルーチンの中に、5個並べ、この関数を利用して実行すると、
    カウンタ実測で、1.997MHzになることが判った。
    つまり、次のような関数を用意した。

        #define TCLK_PW delay_250n()

   void delay_250n(void) {
             Nop();
             Nop();
             Nop();
             Nop();
             Nop();
        }

    これを、
   while(1) {
             TCLK= 0;
             TCLK_PW;
             TCLK= 1;
             TCLK_PW;
        }

        とすれば、周期は、250nS*2= 500nS つまり周波数は、2MHzになるというこである。
            


■ 2013.6.9
  ・AD変換値を、ソフトで安定化したものを座標として、液晶画面に表示してデバッグを続けているが
   どうも相変わらずバラツキが多い。
  ・ここで、TCLK=2MHz化の他、SPIタイミングを今一度見直すことにした。
  → まずこれまで気になっている点を修正してみることにした。
     1つは、今は参考コードに習って、BUSY状態を監視するステートメントは入れず、タイマー待ちで代用
     しているのだが、それを
BUSY状態を監視する方式に変更してみる。
     もう一つは、
24クロック・サイクルが終了した後、TCSをノンアクティブにするタイミングであり、
     参考コードは直ぐにノンアクティブにしているが、通常ここは、
1クロック空けるべきと考えて、
     そのように修正してみた。
  
→ これをやってみたが、動作的には、そのバラツキは殆ど変らず。


■ 2013.6.10
  ・ここで、修正したタイミングのソースが意図通り動いているか確認するため、ソフト・オシロ2にて
   タイミングを確認してみた。
   以下に、その図を示す。→ 意図通り動いているようである。


■ 2013.6.12
  ・どうもここまで、うまく行ってない原因は、何となくだが、
PENIRQ/で外部割込み処理をしているのに無理が
   あるのかもしれないと思い、いっそのこと今迄、PENIRQ/での外部割込みでやってたのを、PENIRQ/信号
   をポートで受け、これが、Lowの時:タッチON/Hiの時:タッチOFFと判断に使えるので、
   後閑式の、50mS周期のT1タイマー割込み(タッチと非同期)に変更してみようと考えた。

  ・一応ソースを変更(この時点では、タッチ・ボタンは右端上下に2個(TRG_UP/TRG_DWN)のみ用意)
   コンパイルは難なくOK

  <動作確認>
   @ T1割込み(50mS)周期確認用に、デバッグLEDをトグルさせてみたが、見た目、チカチカ、ブリンク
      しているので、周期はほぼよさそうだ。
      割込み起動できている。
   A ペンで、長押しぎみにタッチすると、その間、座標値が、パラパラ動き、ペンを離すと座標表示が
      消えるので、PENIRQ/入力の判断は、うまく行っているようである。
   B タッチ位置を移動すると、それなりに違う値で数カウント以内に留まって近い値になっているので
      前とはだいぶ動作が安定したようである。
   C ただ、後閑氏が、私とは異なる液晶パネル(TP付)と検出ハードにしているためか、後閑氏が
      公表している座標位置の数値とは合わない。
      例えば、右端上部タッチで、私のは、X=320位、Y=220位/ 後閑氏のは、X=730 Y=120
      尚、この時の測定条件は、差動入力/Vref=3.3V/AD変換値:生データ

      <以下は、上記の他、様々な条件にした場合の、右端上部タッチ時の座標表示結果です。>
       条件@: 差動入力/Vref=3.3V/AD変換値:生データ15個を取得後、昇順ソートし前後5データを捨てた後平均
             X=260、Y=220
       条件A: 差動入力/Vref=3.3V/AD変換値:生データ15個の単純平均
             X=250、Y=230
       条件B: 差動入力/Vref=3.3V/AD変換値:生データ30個の単純平均
             X=250、Y=230(多少のバラツキはあるが、条件Aと殆ど同じ)
       条件C: シングルエンド入力/Vref=2.5V/AD変換値:生データ15個の単純平均
             X=250、Y=230(多少のバラツキはあるが、条件Aと殆ど同じ)


■ 2013.6.13
  ・今日は、もう1つ気になっている、タッチ入力のノイズ除去の必要性を検討してみる。
   後閑氏のハードは、ここに、0.01uのコンデンサをAGND間に挿入している。
   ただこの実験をするには、液晶タッチモジュールの裏側に、コントローラICが実装されているため、
   治具基板に、波形モニタをするための穴を空けなければいけないことと、0.01u追加加工が、狭間ピッチIC
   のため、ピン直接に追加することが難しい点がネックになる。
   0.01uの追加位置については、コントローラICのピン直接でなく、そこから出ているパターンのレジストを
   剥がし、そこにハンダ付することにした。 
   以下にその改造写真を示す。


■ 2013.6.14
  ・コンデンサ追加後のデータ取りをやってみたが、ここで追加したことによる不具合発生
   この時、左右端と中央の、上下中央、計9点のタッチを試したのだが、何故かこの改造をやると、
   中央の上と、左端の上下中央のタッチ検出が上手くいかなくなるようで、このポイントの座標を
   表示しなくなる。
   これは、タッチ入力である、X+入力と直関係のあるPENIRQ/信号を使っているため、
   ここにCを入れたため、PENIRQ/信号が鈍り、それが影響していると推測する。    

  ・このような結果になってしまったので、せっかく追加したコンデンサを外すことにした。
   ただ、タッチ入力にどのような印加電圧が掛っているかモニターしたいので、そっくりそのまま
   部品を取るのではなく、ニッパで、Cのリードだけ切り、余ったリードをテストポイントとして利用する
   ことにした。

  ・タッチ入力にどのような印加電圧が掛っているか、ソフトオシロ2でモニターするために
   再び、TCLKを2kHzまでダウンさせるが、15データの平均でやると、T1割込み処理時間が伸びるため
   ハングアップしてしまうので、この実験のために、生データのみの取得に戻した。
   また、ソフトオシロ2のプローブを使うので、差動入力から、シングルエンド入力に変更してある。

  ・また、最初タッチパネルの、X、Yの向きが、長手方向が、X、短い方が、Yと思っていたが、実際
   タッチ実験してみると、短い方がX、長手方向がYに見える。
   この辺を確かめようと、再度T.Pマニュアルを調べてみた。
   マニュアルというほどのマニュアルは、見つけられなかったので、あきらめかけていたが、
   aitendo_HPの当該製品ページに、外形寸法図が載っていて、よくそれを見ると、XとYの方向が
   書かれていた。
   それによると、思っていた通り、短い方がX、長手方向がYということが確認できた。
   以下にその図を示す。


■ 2013.6.15
  ・昨日準備した、タッチ入力波形実測実験を行ってみた。
   以下に、タッチ入力波形実測実験メモと、結果を画像で示しました。

  ・以上の結果で、ほぼ思惑通り動いているようなので、(一部さらなる追求が必要な部分もあるが・・・)

  ・いよいよ、タッチポイントの座標から、TRG_UP/TRG_DWNボタンのどちらが押されたかを判断して
   それぞれの処理を実行するルーチンを、追加実験することにする。
   ここで、タッチ仕様を整理してみたい。
   <タッチ仕様整理>
    @ 
タッチボタンは、4個用意する。
      (後閑氏が使っているタッチパネルは、表示部以外の右端領域に5個のキーが印刷されているが
       私が購入したT.Pには、この部分のタッチ機能は無いので、液晶表示面にボタン描画して
       それを使うしかない。)
    A 今は、
TRG_UP/TRG_DWNの右端上下の、2ボタンのみだが、左端にも、次に予定の
       時間軸レンジアップ/ダウン用の2ボタンも想定しておく。

       今回はこの部分は書かないで、座標テーブルのみ用意しておく。

  ・この仕様で、ソースを修正した。
   尚、タッチ入力形態は、シングルエンドでも、差動入力でも、変換値のバラツキに大差はなかったので、
   シンプルな、シングルエンド入力に、FIXすることにした。
   シングル・エンドの利点を言えば、差動にした場合使えない、XPT内蔵の高精度Vrefの、2.5Vが使える点と
   タッチ入力の波形観測が容易にできる点が挙げられる。   

  ・早速実験を行い、タッチの仕方によってどの位のバラツキ範囲があるかデータを取ってみることにした。
   下表が、その結果で、サンプル数は15データとして、それぞれその平均、+偏差、-偏差を求め、
   平均値を、参照座標テーブルに登録、偏差をボタン判断ルーチン(IF分岐)の、判断範囲の参考値とした。


■ 2013.6.16
  ・修正したソースで、タッチによる、トリガレベル・アップ/ダウン動作は、大方OKなので、
   続いて、時間軸レンジ切替も、タッチでやってみる。
  ・下図を踏まえ、ソース修正を行った。

  <ソース修正箇所概要>
   @ 
タッチボタン座標データ・テーブルを、次のように変更
     // タッチボタン座標データ
      short Button[4][2] = {{300,245},    // [0]:TIME_UPボタン
                                                                  {1814,250},  // [1]:TIME_DWNボタン
                                                                  {337,1847},  // [2]:TRIG_UPボタン
                                                                  {1840,1817} // [3]:TRIG_DWNボタン
                   };

   A 時間軸レンジ切替を、ロータリーDIP_SWから、タッチに変更したので、500mec/divを追加
   B 時間軸レンジの追加及び、タッチボタン追加に伴い、座標描画関数(
AxisDraw)を、次のように修正

        /******************************************
        * Drawing Coordinate Axis
        *******************************************/
        void AxisDraw(void){
            short i;

            Glcd_Clear(BLACK);

            /// X、Y座標軸,補助線表示
            for(i=0; i<319; i+=50) Glcd_Line(i, 0, i, 231, BROWN); // Y axis
            for(i=0; i<239; i+=58) Glcd_Line(0, i, 319, i, BROWN); // X axis


            /* Disp. Unit Time Axis (msec/div) */
            switch(SW){
                case 0: Glcd_Str(13, 0, str_0_1ms, CYAN, BLACK);
                            break;
                case 1: Glcd_Str(13, 0, str_0_2ms, CYAN, BLACK);
                            break;
                case 2: Glcd_Str(13, 0, str_0_5ms, CYAN, BLACK);
                            break;
                case 3: Glcd_Str(13, 0, str_1_0ms, CYAN, BLACK);
                            break;
                case 4: Glcd_Str(13 ,0, str_2_0ms, CYAN, BLACK); 
                            break;
                case 5: Glcd_Str(13, 0, str_5_0ms, CYAN, BLACK);
                            break;
                case 6: Glcd_Str(13, 0, str_10ms, CYAN, BLACK);
                            break;
                case 7: Glcd_Str(13, 0, str_50ms, CYAN, BLACK);
                            break;
                case 8: Glcd_Str(13, 0, str_500ms, CYAN, BLACK);
                            break;


                default:Glcd_Str(13, 0, str_0_5ms, CYAN, BLACK); 
                            break;
            }

            Glcd_Str(25, 0, MsgUp, BLACK, WHITE); // トリガ・アップ・ボタン表示(キャラクタ)
            Glcd_Str(25, 16, MsgDown, BLACK, WHITE); // トリガ・ダウン・ボタン表示(キャラクタ) 

            Glcd_Str(0, 0, MsgUp, BLACK, WHITE); // 時間軸レンジ・アップ・ボタン表示(キャラクタ)
            Glcd_Str(0, 16, MsgDown, BLACK, WHITE); // 時間軸レンジ・ダウン・ボタン表示(キャラクタ) 


            Glcd_Line(310, Y_pos, 319, Y_pos, YELLOW); // トリガレベルライン描画

            itostring(3, POT, str_Trig + 5); // POTデータを文字列に変換
            Glcd_Str(2, 0, str_Trig, WHITE, BLACK); // トリガレベル値表示

        }

   C 時間軸レンジ切替追加に伴い、Process関数の、case0、case1に、その処理内容を]記述

        void Process(short sw)
        {
            switch(sw){
                case 0: /// 時間軸レンジアップ(サンプル周期小へ移行)
                            SW--;
                            if (SW < 0) SW= 8;
                            Chatta = 1; // 130616追加 
                            break;

                case 1: /// 時間軸レンジアップダウン(サンプル周期大へ移行)
                            SW++;
                            if (SW > 8) SW= 0;
                            Chatta = 1; // 130616追加
                            break;
                                            ・
                                            ・
                                            ・

   D 時間軸レンジを切替えた時(Chattaフラグがセットされた時)は、T1割込みの中で時間軸レンジ表示
      の更新を行うよう修正(後閑氏のソースを参考にしました。)

        /****************************************************
        * タイマ1割り込み処理:タッチ用5OmS周期   130612
        ****************************************************/
        void __ISR(4, ipl2) T1Handler(void){
            static short Xset, Yset, Xold, Yold;

            mT1ClearIntFlag(); //割り込みフラグクリア

            Xset = XPT_Read_XY(CMD_RDX); // X座標値取得(15回変換の平均化処理後のデータ)
            Yset = XPT_Read_XY(CMD_RDY); // Y座標値取得(15回変換の平均化処理後のデータ)

            //// <確実なタッチの検出>
            //// X座標、Y座標とも「15カウント以内」
            //// に入る状態が「3回」以上続いたら位置座標として確定する。
            if(!PENIRQ) {     // タッチONの場合、確実なタッチの検出処理を実行
                                // タッチOFFの場合、 SETデータを、OLDデータに置換えて抜けるだけ
                if((abs(Xset - Xold) < 15) && abs(Yset - Yold) < 15){
                    Count++;
                    if((Count >= 3)&&(Chatta==0)){
                        Count = 0;
                        Process(CheckBtn(Xset, Yset));
                        if(Chatta) AxisDraw(); // 時間軸レンジを変えた時は、ここで時間軸レンジ表示更新:130616追加
                    }
                }
                else Count = 0;
            }

            Xold = Xset;
            Yold = Yset;

        }


■ 2013.6.17
  ・昨日いろいろやって、時間軸レンジのタッチ化も大方うまく行った。

   >>後書きになるが、昨日やっていて気が付いたことを整理してみる。
    トリガレベルボタンと、時間軸レンジ切替ボタンの表示位置を、2ボタンの時と逆にしたため、時間軸レンジの方は、
    割と正確にタッチ位置を検出するが、トリガレベル(左端上下ボタン)の方は、
    複数タッチした場合のバラツキデータを取らないまま、やや適当な座標テーブルになっているため、
    タッチ動作が不安定であった。

          そこで、左端に移した、トリガレベルボタンの座標取得を、数回(15回)データ取りし、その平均をテーブル値、
     偏差を判断基準の範囲(幅)設定の参考値にしようと思った。
    その結果を下表に示す。
    尚、右端上下の時間軸レンジボタンについては、先に行った(2ボタンの時の)データを元に、テーブル値等
    決めているので問題ありません。

  ・これで、タッチ関係の動作はよさそうなので、最後にオシロ動作を確認した時の、波形サンプルを以下にアップします。


<最終回路図>
 ・こちらから、どうぞ→ 「PIC32MX_QVGA+タッチ_オシロ実験回路図」

<最終ソース及び、ヘッダーファイル>
 ・こちらから、どうぞ→ Scope_QVGA_PIC32MX_Touch_TRG.c
                  Touch_XPT2046_Lib.c
                  Touch_XPT2046_Lib.h

  ※ 尚、この他に、QVGAグラフィックライブラリ(colorlcd_libdsPICVH.c, colorlcd_libdsPICVH.h, ASCII12dot.h)
     が必要ですが、それらは、実験テーマ31に公開済なので、そちらを参照してください。


← 実験テーマ1に戻る   TOP PAGEに戻る   実験テーマ34へ →