Sigrok用のデコーダーの作成

画像



デジタル技術で作業する場合、遅かれ早かれロジックアナライザーが必要になります。利用可能なハムの1つは、DreamSourceLabのDSLogicロジックアナライザーです。彼は少なくとも1つ2つ3 つのサイトで何度も言及されました



その機能はオープンソースであり、オープンソースのsigrokライブラリが信号のデコードを担当しているという事実もありますこのライブラリは、既存の信号デコーダの印象的なリストとともに、独自のAPIを作成するためのAPIを提供します。これが私たちがすることです。



デモスタンド



, . TTP229-BSF. 8- 16- . Arduino, DSLogic.



画像





, , . , . , , .



sigrokの各デコーダーは、Python 3で記述された個別のパッケージであり、decodersフォルダーの下に独自のディレクトリがあります。他のPythonパッケージと同様に、デコーダーには__init__.pyが含まれています。また、sigrokの命名規則に従って、pd.pyは実際の実装を含むファイルです。



画像



__init__.pyのコードは標準であり、プロトコルを説明するdocstringとデコーダーのインポート(d28dee9)が含まれています



'''
Protocol description.
'''

from .pd import Decoder


pd.pyファイルには、デコーダーの実装(d28dee9が含まれています



class Decoder(srd.Decoder):
    api_version = 3
    id = 'empty'
    name = 'empty'
    longname = 'empty decoder'
    desc = 'Empty decoder that can be loaded by sigrok.'
    license = 'mit'
    inputs = ['logic']
    outputs = ['empty']
    tags = ['Embedded/industrial']
    channels = (
        {'id': 'scl', 'name': 'SCL', 'desc': 'Clock'},
        {'id': 'sdo', 'name': 'SDO', 'desc': 'Data'},
    )

    def start(self):
        pass

    def reset(self):
        pass

    def decode(self):
        pass


これは、ライブラリによってロードできる最小限の実装ですが、何もデコードしません。必要なプロパティを分析しましょう:



  • api_version – Protocol decoder API, . libsigrokdecode 3- Protocol decoder API. .
  • id – , . , .
  • name, longname, desc – , , . .
  • inputs, outputs – . 'logic' . . , , SPI. SPI . , SPI . 'spi'.
  • license, tag – . DSView 1.1.1 + libsigrokdecode tags - .
  • チャネル -デコーダーによって使用される信号線のリスト。このプロパティは、入力データ形式がロジックであるデコーダーに必要です。


および必要なメソッド:



  • start() -デコードの開始前に呼び出されるメソッド。この方法では、現在のデコードセッションの設定を行う必要があります。
  • reset() -デコードが停止したときに呼び出されるメソッド。デコーダを初期状態に戻す必要があります。
  • decode()は、信号をデコードするために呼び出されるメソッドです。


デコーダーの最小限の実装を処理したら、実際の信号のデコードを開始できます。



フル機能のデコーダー



まず、データ信号のタイミング図を見てみましょう。TTP229-BSFにはいくつかの動作モードがあり、以下で使用するモードのタイミング図のみを示しています。マイクロ回路のすべての動作モードに関する詳細情報は、そのドキュメントに記載されています。



画像



何よりもまず、デコーダーが動作する必須ラインのセットを説明する必要があります。この場合、クロックライン(SCL)とデータライン(SDO)の2つがあります。



class Decoder(srd.Decoder):
    ...
    inputs = ['logic']
    channels = (
        {'id': 'scl', 'name': 'SCL', 'desc': 'Clock'},
        {'id': 'sdo', 'name': 'SDO', 'desc': 'Data'},
    )


マイクロ回路がボタンの押下を検出すると、SDOラインにデータ有効(DV)信号を設定します。これにより、レシーバーがデータの読み取りを開始する必要があります。この信号を見つけてデコードしてみましょう。



sigrok , . . , , . Protocol decoder API . . wait(). . , self.samplenum .



, , – , :



  • 'l'-低レベル、論理0;
  • 'h'-高レベル、論理1。
  • 'r'-信号の立ち上がり、ロー状態からハイ状態への遷移。
  • 'f'-信号の低下、高から低への移行。
  • 'e'-信号の任意の変化、上昇または下降。
  • 「s」は安定状態、0または1です。


したがって、DV信号の始まりを見つけるために、SCLラインがHighであることを表す条件があり、データライン(SDO)で信号のロールオフが発生します。準備した条件でwait()関数を呼び出して、サンプル番号を保存しましょう。



        self.wait({0: 'h', 1: 'f'})
        self.dv_block_ss = self.samplenum


DV信号の終わりを見つけるには、SCLラインがHighのままで、データラインがHighになる条件を設定する必要があります。

        self.wait({0: 'h', 1: 'r'})


wait()関数の最後の呼び出しが完了すると、DV信号の開始と終了のサンプル番号がわかります。それのために注釈を作成する時が来ました。これを行うには、デコーダーに注釈を追加し、それらをグループ化します(annotation_rows):



class Decoder(srd.Decoder):
    ...
    annotations = (
        ('dv', 'Data valid'),
    )
    annotation_rows = (
        ('fields', 'Fields', (0,)),
    )


0は、このグループに属するself.annotationsタプル内のアノテーションのインデックスです。また、アノテーションの出力を登録する必要があります。



    def start(self):
        self.out_ann = self.register(srd.OUTPUT_ANN)


これで、DV信号に注釈を配置する準備がすべて整いました。これは、put()関数(f613b83)を呼び出すことによって行われます



        self.put(self.dv_block_ss, self.samplenum,
                 self.out_ann, [0, ['Data valid', 'DV']])


関数パラメーター:アノテーション開始サンプル番号(self.dv_block_ss)、アノテーション終了サンプル番号(self.samplenum)、アノテーション出力識別子(self.out_ann)、およびアノテーションのデータ。データは、注釈インデックス(0)のリストと、説明に表示するための最長から最短までの文字列のネストされたリストとして表示されます。複数の行が指定されている場合、インターフェースは、たとえば使用されているスケールに応じて、表示された行を個別に選択できます。







同様に、DV信号の終了とマイクロコントローラーによるデータ読み取りの開始の間のTw遅延の注釈を追加します。次に、ボタンプレスデータのデコードを開始できます。



TTP229-BSFは、選択したモードに応じて、8個または16個のタッチボタンで動作します。この場合、送信されたデータには、マイクロ回路の動作モードに関する情報が含まれていません。したがって、デコーダーの場合、マイクロ回路が動作するモードを設定するオプションを追加する価値があります。



class Decoder(srd.Decoder):
    ...
    options = (
        {'id': 'key_num', 'desc': 'Key number', 'default': 8,
         'values': (8, 16)},
    )
    def start(self):
        ...
        self.key_num = self.options['key_num']


このオプションは、デコーダーを選択するときにユーザーインターフェイスで値を設定するために使用できます。



タイミング図からわかるように、SDOラインのデータは、SCLがアクティブ(ロー)レベルになると設定され、信号がパッシブレベルに戻ると保存されます。この時点で、マイクロコントローラーとデコーダーの両方がSDLラインにデータセットを記録できます。SCLがアクティブレイヤーに戻る遷移は、次のデータ送信の開始と見なすことができます。この場合、デコード関数は(ca9a370)のようになります



    def decode(self):
        self.wait({0: 'h', 1: 'f'})
        self.dv_block_ss = self.samplenum

        self.wait({0: 'h', 1: 'r'})
        self.put(self.dv_block_ss, self.samplenum,
                 self.out_ann, [0, ['Data valid', 'DV']])
        self.tw_block_ss = self.samplenum

        self.wait([{0: 'f', 1: 'h'}, {0: 'f', 1: 'f'}])
        self.put(self.tw_block_ss, self.samplenum,
                 self.out_ann, [1, ['Tw', 'Tw']])
        self.bt_block_ss = self.samplenum

        for i in range(self.key_num):
            (scl, sdo) = self.wait({0: 'r'})
            sdo = 0 if sdo else 1

            self.wait({0: 'f'})
            self.put(self.bt_block_ss, self.samplenum,
                     self.out_ann, [2, ['Bit: %d' % sdo, '%d' % sdo]])
            self.bt_block_ss = self.samplenum


しかし、アノテーションを配置するこのアプローチには欠点があります。最後のビットのアノテーションは、マイクロコントローラーが次のデータを読み取るまで続きます。







. . , SCL . , SCL 2 ., . 'skip', , , . , . metadata(). Hz.



    def metadata(self, key, value):
        if key == srd.SRD_CONF_SAMPLERATE:
            self.timeout_samples_num = int(2 * (value / 1000.0))


次に、デコード関数の条件が次の形式でスキップを使用して書き込まれますさらに、押されたボタンに関するデータを読み取るときにチップが初期状態戻っていないことの追加チェック(6a0422d)。



    def decode(self):
        ...
        for i in range(self.key_num):
            ...
            self.wait([{0: 'f'}, {'skip': self.timeout_samples_num}])
            self.put(self.bt_block_ss, self.samplenum,
                     self.out_ann, [2, ['Bit: %d' % sdo, '%d' % sdo]])
            if (self.matched & 0b10) and i != (self.key_num - 1):
                break


これで、デコーダーは完全なデータ送信を処理できます。そして、個々のビットに関する情報に加えて、どのボタンが押されたかについての注釈が追加されると便利です。これを行うには、別の注釈の説明を追加します。ボタンを押すための注釈は、データ送信全体を参照し、以前に追加された注釈と交差するため、別のグループに配置する必要があります。彼女のために、注釈「キーメッセージ」の新しいグループを作成しましょう。91c64e6)。



class Decoder(srd.Decoder):
    ...
    annotations = (
        ('dv', 'Data valid'),
        ('tw', 'Tw'),
        ('bit', 'Bit'),
        ('key', 'Key press status'),
    )
    annotation_rows = (
        ('fields', 'Fields', (0, 1, 2)),
        ('keymsg', 'Key message', (3,)),
    )
    def decode(self):
        ...
        keys_pressed = list()

        for i in range(self.key_num):
            ...
        else:
            key_msg = \
                'Key: %s' % (','.join(keys_pressed)) if keys_pressed else 'Key unpressed'
            key_msg_short = \
                'K: %s' % (','.join(keys_pressed)) if keys_pressed else 'KU'

            self.put(self.dv_block_ss, self.samplenum,
                     self.out_ann, [3, [key_msg, key_msg_short]])






この時点まで、すべてのコードは最初の前提でのみ機能しました。デコーダー名の横に19%があることに気付きましたか?これは、decode()関数を終了する前に処理されたサンプルの割合です。すべてのサンプルを処理するには、別のデータ送信(48f95fbをデコードするためにコードの周りに無限ループを追加する必要があります



    def decode(self):
        ...
        while True:
            self.wait({Pin.SCL: self.passive_signal, Pin.SDO: self.front_edge})
            self.dv_block_ss = self.samplenum
            ...


次のサンプルを検索するときにwait()関数がそれらすべてを繰り返すと、デコードは自動的に終了します。この変更の結果、すべてのサンプルとすべてのデータ送信KDPVに示されているように処理されます。



最後の仕上げとして、アクティブな信号レベルを選択する機能が追加され、TTP229-BSF用の本格的なデコーダーの準備が整います。最終的なソースコードはGitHubでも入手できます




All Articles