SPIバスの抂芁ず組み蟌みLinux甚のスレヌブSPIデバむスのドラむバヌの開発パヌト1、抂芁

この蚘事では、SPIバスさたざたなデバむスを接続するために䜿甚される組み蟌み技術で広く䜿甚されおいるむンタヌフェむスの簡単な抂芁を瀺し、Linux甹SPIデバむスのプロトコルレベルのドラむバヌを䜜成するプロセスを説明したす。 このドキュメントは完党なガむドではなく、正しい方向を瀺すこずを目的ずしおいたす。 この蚘事は1぀のトピックのサむズに含たれおいなかったため、2぀の郚分に分割する必芁がありたした。



0.導入する代わりに



この蚘事は䜕ですか

この蚘事は、さたざたな゜ヌスからの情報をたずめたものであり、ドキュメントの䞀郚を無料で翻蚳したものです。たた、私自身のコメント、远加、発生した問題の説明も掲茉しおいたす。



この蚘事の察象者

たず第䞀に、私は初心者向けです。 組み蟌みLinuxフォヌラムでは、「このボヌドでSPIを操䜜する方法は」ずいう質問を芋぀けるこずができたす。 私が答えようずするのは圌にずっおです。 䟋ずしお、テストSPIデバむスで動䜜するように蚘述されたコヌドを提䟛したす。



蚘事の構造

倚くの情報があったため、この蚘事はいく぀かのセクションに分かれおいたす。

  1. SPIずは䜕ですか
  2. Linux SPIサブシステムの抂芁
  3. spidevを䜿甚したナヌザヌ空間プロトコルSPIドラむバヌの開発
  4. カヌネルレベルのプロトコルSPIドラむバヌの開発
  5. ドキュメント


最初の2぀の段萜は蚘事の最初の郚分に含たれ、残りは2番目の郚分に含たれたす。



最初のサブセクションではSPIバスの動䜜に぀いお説明したす。蚘事のこの郚分は特にLinuxに結び付けられおいないため、Linuxに興味がない人でも読むこずができたすが、このむンタヌフェヌスに関する情報を取埗するだけでかたいたせん。



2番目のサブセクションでは、LinuxでSPIを䜿甚する基瀎ずなる構造ずメカニズムに぀いお説明したす; 3番目ず4番目のパヌトで説明する内容を理解するために読む必芁がありたす。



翻蚳や远加に興味がない堎合は、すぐに5番目のセクションに進んでください。ここでは、この問題に関する必芁な情報をすべお入手できる堎所に関する情報を芋぀けるこずができたす。



構造たたは関数の名前にリンクが衚瀺されおいる堎合、新しいタブで開くこずができるため、Linuxカヌネルの公匏ドキュメントでこの構造/関数の説明に盎接アクセスできたす。



間違い

私は魔術垫ではありたせん、ただ勉匷しおいたす。 ゚ラヌや䞍正確な点を芋぀けた堎合は、お知らせください。



1. SPIずは䜕ですか



SPIずいう略語は、「シリアルペリフェラルむンタヌフェヌス」たたはロシア語版では「シリアルペリフェラルむンタヌフェヌス」を意味したす。 名前はそれ自䜓を物語っおいたす。このむンタヌフェむスは、さたざたな呚蟺機噚を操䜜するために䜿甚されたす。 たずえば、さたざたなDAC / ADC、ポテンショメヌタ、センサヌ、入出力ポヌト゚クスパンダGPIO、さたざたなメモリ、さらにはオヌディオコヌデックやむヌサネットコントロヌラなどのより耇雑な呚蟺機噚を䜿甚できたす。



技術的な芳点から芋るず、SPIは同期4線匏バスです。 これは、2぀の同期シフトレゞスタの接続であり、SPIデバむスの䞭心的な芁玠です。 接続はマスタヌ/スレヌブ構成を䜿甚したす。 マスタヌのみが同期パルスを生成できたす。 回路には垞に1぀のマスタヌしかありたせん耇数のマスタヌを䜿甚できるオプションがある同じI2Cバスずは異なり、スレヌブの数は異なる堎合がありたす。 䞀般的な堎合、マスタヌの出力はスレヌブの入力に接続され、逆の堎合、スレヌブの出力はマスタヌの入力に接続されたす。 SCK出力に同期パルスを適甚するず、デヌタはマスタヌによっおMOSI出力からプッシュされ、MISO入力でスレヌブによっおキャプチャされたす。 したがっお、シフトレゞスタの幅に察応する数の同期パルスを送信するず、レゞスタ内のデヌタが堎所を亀換したす。 SPIは垞に党二重モヌドで動䜜したす。 ただし、パラメヌタを曞き蟌むずきにデバむスから受信したデヌタが必芁かどうかは別の問題です。 デバむスにデヌタを曞き蟌むずきにデバむスから受信したデヌタがガベヌゞであるこずがよくありたす。その堎合、それらは単に無芖されたすが、垌望に関係なく受信したす。



SPIコントロヌラヌは通垞、MCUたたはeMPUの呚蟺装眮によっお実装されたす。 ほずんどのチップでは、マスタヌモヌドずスレヌブモヌドの䞡方で動䜜したす。 しかし珟時点では、Linuxはマスタヌモヌドのみをサポヌトしおいたす。



SPIデバむスを有効にする方法はいく぀かありたす。

画像








あなたが䞊の写真で芋るそれらの最も単玔なもの無料のGFDLラむセンスの䞋の写真に぀いおはWikipediaに感謝したす。 この堎合、スレヌブ遞択信号〜CSを陀き、すべおのスレヌブがマスタヌに䞊列に接続されたす。 各スレヌブには個別のスレヌブ遞択信号が必芁です図ではSSxずしお指定されおいたす。 スレヌブ遞択信号の堎合、この目的のために特別に蚭蚈されたSPIコントロヌラヌ出力ず、マむクロコントロヌラヌの汎甚入出力GPIOポヌトの䞡方を䜿甚できたす。



デヌタ䌝送には2぀の導䜓が䜿甚されたす。1぀はクロックパルスを䟛絊し、もう1぀は各スレヌブのスレヌブを遞択するための信号です。

䜿甚される信号の説明





独立した接続の特殊なケヌスは、単䞀のスレヌブを持぀オプションです。 この堎合、デバむスが垞にアクティブ状態になるように〜CS信号をグランドにプルするこずができたす。 ただし、スレヌブは初期化たたはその他のサヌビス目的でCS信号を䜿甚できるため、これを行うこずは非垞に掚奚されたせん。



スレヌブの独立した接続の䞻な䞍䟿は、スレヌブごずに個別の信号〜CSが必芁なこずです。 倖囜文孊で「デむゞヌチェヌン」「ガヌランド」ず翻蚳できるず呌ばれるカスケヌド接続スキヌムには、このような欠点がありたせん。

画像








䞊の図からわかるように、ここではすべおのスレヌブに共通のスレヌブ遞択信号が䜿甚されおいたす。 各スレヌブの出力は、次のスレヌブの入力に接続されたす。 最埌のスレヌブの出力はマスタヌの入力に接続されおいるため、閉回路を圢成したす。 この接続では、盎列接続されたデバむスが1぀の倧きなシフトレゞスタを圢成するず仮定できたす。 したがっお、必芁なパッケヌゞを収集した埌、接続の物理的な順序に察応する順序で各デバむスのデヌタを組み合わせお、すべおのデバむスにデヌタを「䞀床に」曞き蟌むこずができたす。 ただし、埮劙な点が1぀ありたす。 たず、すべおの超小型回路がこのタむプの接続をサポヌトする必芁がありたす。 第二に、Linuxカヌネルはこのタむプの接続をサポヌトしおいないため、匕き続き䜿甚する堎合は、既存のドラむバヌを倉曎するか、独自のドラむバヌを䜜成する必芁がありたす。



SPIデバむスには4぀の動䜜モヌドがありたす。 原則ずしお、初心者の間で最も混乱を匕き起こすのは圌らです。 これらの4぀のモヌドは、2ビットの組み合わせです。



これらの2ビットはモヌド番号を圢成したす。 CPOLは最䞊䜍ビットであり、CPHAは最䞋䜍ビットです。 デバむスのドキュメントにモヌド番号が明瀺的に瀺されおいない堎合もありたすが、タむミング図からい぀でも簡単に刀断できたす。 デヌタのサンプリングずむンストヌルは垞にクロック信号の反察偎の゚ッゞで行われるこずを理解するこずも重芁です。 たずえば、デバむスをモヌド0最も䞀般的なオプションで動䜜させたす。この堎合、スレヌブデバむスはクロック信号の立ち䞊がり゚ッゞに沿っおMOSI入力からデヌタビットを読み取り、マスタヌは立ち䞊がり゚ッゞに沿っおMISO入力でスレヌブからデヌタを読み取りたす。 より明確にするために、4぀の動䜜モヌドすべおのオシログラムを瀺したす。

画像

この図は、MOSI青線およびSCK黄線信号を瀺しおいたす。 すべおの堎合においお、番号0x64が送信されたす。 明るい瞊線は、デヌタサンプリングの瞬間を瀺しおいたす。 モヌド2に぀いお考えおみたす。思い出しおくださいが、CPOL = 1およびCPHA = 0です。 したがっお、同期信号は最初は高レベルであり、サンプリングは立ち䞊がり゚ッゞこの堎合は立ち䞋がりで行われたす。 私のオシロスコヌプには2぀のチャンネルしかないため、〜CSおよびMISO信号は衚瀺されたせん。 しかし、この堎合、それらはあたりおもしろくありたせん。たずえば、〜CS信号は、デヌタ転送党䜓を通しお単玔に「障害」です。



2. LinuxのSPIサブシステムの抂芁



Linux SPIドラむバヌは2぀の郚分に分かれおいたす。 1぀はSPIコントロヌラヌのドラむバヌで、特定のコントロヌラヌのハヌドりェアず盎接連携したす。 このようなドラむバヌは、コントロヌラヌの構成方法、サスペンドモヌドぞの切り替えサスペンドおよび終了再開、メッセヌゞの送信キュヌspi_message、すぐ䞋のキュヌに぀いおからの次の送信spi_transferの遞択、および盎接送信時に行うアクションを決定したすポヌトに察しお、CSを介しお特定のデバむスをアクティブ化/非アクティブ化する方法も決定されたすcs_activate / cs_deactivate関数。 この蚘事では、このタむプのドラむバヌに぀いおは説明したせん。 原則ずしお、それらはLinuxポヌトが存圚するMCU / eMPUに既に実装されおおり、倖郚から目的のスレヌブデバむスをアクティブにできるように、チップセレクトデコヌドなどの特定の機胜が必芁な堎合にのみそれらに登る必芁がありたすロゞック。 これは、たずえばGPIOがない堎合に圹立぀こずがありたす。



2番目の郚分は、SPIバスに接続されおいるさたざたなスレヌブで動䜜するために䜿甚されるプロトコルドラむバヌです。 これらのドラむバヌは、「プロトコル」ず呌ばれたす。これは、機噚ず盎接連携せずに、スレヌブずの間でのみさたざたなデヌタを送受信するためです。 関心のあるスレヌブのサポヌトをシステムに远加できるため、このタむプのドラむバヌが最も関心がありたす。これに぀いお怜蚎したす。



ほずんどのプロトコルドラむバヌはカヌネルモゞュヌルです。 たずえば、デバむスがSPIを介しお接続されたオヌディオコヌデックである堎合、ドラむバヌはALSAが提䟛する機胜も䜿甚し、プログラムたずえば、madplayは、ハヌドりェアの構成方法に぀いお少しも考えずに、シンボルデバむス/ dev /オヌディオを介しおそれを操䜜できたすどのバスが接続されおいるか。



カヌネルは、キャラクタヌデバむスの圢匏のむンタヌフェむスを備えた、spidevず呌ばれる汎甚プロトコルドラむバヌも提䟛したす。 これにより、暙準のreadおよびwriteシステムコヌルを䜿甚しおスレヌブSPIデバむスに半二重呌び出しを行い、動䜜モヌドを蚭定し、ioctl呌び出しを介しお党二重デヌタ亀換を実行できたす。



したがっお、SPIデバむスのプロトコルドラむバヌは2぀のタむプに分類できたす。



LinuxはSPIデバむスぞのすべおの呌び出しを呌び出したす。 SPIプロトコルドラむバヌは、耇数セグメントSPIトランザクションであるspi_message構造䜓によっお衚されるメッセヌゞを明瀺的たたは暗黙的に凊理したす。

struct spi_message { struct list_head transfers; struct spi_device *spi; unsigned is_dma_mapped:1; void (*complete)(void *context); void *context; unsigned actual_length; int status; struct list_head queue; void *state; };
      
      





転送-トランザクション転送で送信されたセグメントのリンクリスト。

spi-このメッセヌゞが眮かれおいるキュヌ内のspiデバむスぞのポむンタヌ。

is_dma_maped-このフラグがtrueの堎合、各送信バッファヌにdmaおよびcpu仮想アドレスの䞡方が提䟛されたす。

complete-トランザクションの終了を通知するために呌び出されるコヌルバック。

context-コヌルバックする匕数complete;

actual_length-すべおの成功した転送で送信されたバむトの総数。

status-成功した堎合は0、゚ラヌの堎合はerrnoの負の倀。



spi_message構造は 、デヌタ転送のアトミックシヌケンスを実行するために䜿甚されたす。各デヌタ転送は、 spi_transfer構造で衚されたす。 前のメッセヌゞが完党に送信されるたで、 SPIバスを䜿甚しお別のspi_messageメッセヌゞを送信できないずいう意味で、送信シヌケンスは「アトミック」です。 䞀郚のシステムでは、このようなシヌケンスの倚くは、単䞀のプログラムされたDMA送信ずしお実行できたす。 すべおのシステムで、これらのメッセヌゞはキュヌに入れられ、他のデバむスずのトランザクションの埌に完了するこずができたす。 単䞀のスレヌブぞのすべおの呌び出しは、垞にFIFOの順序で実行されたす。



struct spi_transfer構造䜓は、リンクされたメッセヌゞリスト内の単䞀の送信を蚘述し、読み取り/曞き蟌みバッファのペアを定矩したす。

 struct spi_transfer { const void *tx_buf; void *rx_buf; unsigned len; dma_addr_t tx_dma; dma_addr_t rx_dma; unsigned cs_change:1; u8 bits_per_word; u16 delay_usecs; u32 speed_hz; struct list_head transfer_list; };
      
      





tx_buf-送信するカヌネルメモリ空間のデヌタバッファぞのポむンタ、たたはNULL。

rx_buf-デヌタを読み蟌むカヌネルメモリ空間のデヌタバッファぞのポむンタ、たたはNULL。

lenは、rxおよびtxバッファヌのサむズバむト単䜍です。

tx_dma-spi_message.is_dma_mappedが蚭定されおいる堎合に䜿甚されるDMAアドレスtx_buf。

rx_dma-DMAアドレスrx_buf。spi_message.is_dma_mappedが蚭定されおいる堎合に䜿甚されたす。

speed_hz-デバむスのデフォルト倀以倖の䌝送速床を蚭定したす。 この倀が0の堎合、spi_device構造䜓のmax_speed_hzフィヌルドで指定されたデフォルトの速床が䜿甚されたす。

bits_per_word-デフォルトずは異なるワヌドあたりのビット数を蚭定したす。 この倀が0の堎合、spi_device構造䜓のbits_per_wordフィヌルドで指定されたデフォルト倀が䜿甚されたす。

delay_usecs-䌝送の最埌のビットが送信されおからチップセレクトの状態を倉曎するたで、たたはキュヌ内の次の䌝送の䌝送を開始するたでのマむクロ秒単䜍のタむムアりト。 このパラメヌタヌには现心の泚意を払っおください。遅延が実装されおいるコントロヌラヌドラむバヌの郚分を確認する必芁がありたす。 たずえば、at91シリヌズチップの堎合、割り蟌みハンドラに実装されるため、その䜿甚には結果が䌎いたす。



spi_transfer構造を初期化するずき、非垞に重芁なポむントがありたす。それらは、kmalloc、kzallocなどを介しおDMAで䜿甚可胜なメモリ領域に割り圓おる必芁がありたす。 マスタヌドラむバヌがdmaを䜿甚しおいる堎合、静的に宣蚀された配列を䜿甚するず、転送しようずしたずきにドラむバヌがクラッシュしたす。



SPIを介しおデヌタを送信する堎合、蚘録されたビット数は垞に読み取られたビット数ず等しくなりたす。 プロトコルドラむバヌは、垞にtx_bufバッファヌたたはrx_bufバッファヌぞのポむンタヌを提䟛する必芁がありたす。 堎合によっおは、送信デヌタのDMAアドレスを提䟛する堎合がありたす。



各転送のデヌタ転送レヌトずワヌドあたりのビット数を個別に無効にする機胜は、特定のドラむバヌの実装ずコントロヌラヌのハヌドりェア機胜に䟝存したす。 たずえば、at91シリヌズチップのSPIコントロヌラヌの堎合、フィヌルドspeed_hzおよびbits_per_wordを再定矩する可胜性は提䟛されないため、垞に0に蚭定する必芁がありたす。そうしないず、デヌタを転送しようずしたずきに゚ラヌが発生したす。



tx_bufぞのポむンタヌがNULLに蚭定されおいる堎合、SPIコントロヌラヌはrx_bufバッファヌがいっぱいになるずれロをポップアりトしたす。 rx_bufがNULLに蚭定されおいる堎合、読み取られたデヌタは無芖されたす。 プッシュおよびキャプチャされるバむト数は垞にlenです。 単語の䞀郚のみをプ​​ッシュしようずするず、゚ラヌが発生したす。 たずえば、3バむトず16ビットたたは20ビットのワヌド長をプッシュしようずする堎合、最初のケヌスではワヌドごずに2バむトが䜿甚され、2番目では4バむトが䜿甚されたす。



送信するデヌタは、垞に特定のハヌドりェアプラットフォヌムに固有の順序で保存されたす。 デヌタの送信/読み取り時に、バむト順序はSPI固有SPI_LSB_FIRSTパラメヌタヌが蚭定されおいない限り、通垞ビッグ゚ンディアンからこのCPUのハヌドりェア固有の順序に自動的に倉換されたす。 たずえば、bits_per_wordパラメヌタヌが16の堎合、バッファヌは2Nバむトを占有し、このCPUに固有のバむト順で栌玍された、それぞれ16ビットの長さのNワヌドを含みたす。



ワヌドサむズが2のべき乗でない堎合、メモリ内のワヌドの衚珟には远加のビットが含たれたす。 プロトコルドラむバヌ甚にメモリに保存されおいる単語は垞に右揃えであるため、䜙分なビットは垞に高䜍ビットになりたす。

わかりやすくするために、もう䞀床オシログラムを瀺したす。

画像

この堎合、txバッファヌには倀0xf98eが含たれ、蚭定倀bits_per_wordはワヌドあたり12ビットに察応したす。 デバむスはSPI_MODE_0で実行されおいたす。 図では、青い線がMOSIコントロヌラヌの出力に察応し、黄色の線がSCKに察応しおいたす。 ここでは、送信䞭に0x098eのみが送信され、䞊䜍4ビットは远加ず芋なされるため、砎棄されたこずが明確にわかりたす。 非垞に単玔な堎合、1぀の12ビットワヌドがメモリの2バむトを占有し、メモリのワヌドサむズず実際のサむズの差は2 * 8-12 = 4ビットであり、送信䞭に砎棄されたす。



すべおのSPI転送は、察応するチップセレクトのアクティブ化から始たりたす。 通垞、スレヌブはメッセヌゞの最埌の送信たでアクティブのたたです。 ドラむバヌは、 spi_transfer構造䜓のcs_changeフラグを䜿甚しおcsの状態を倉曎できたす。



spi_message およびそのspi_transferのを䞋䜍レベルに枡すコヌドは、これらの構造のメモリを管理したす。 明瀺的に定矩されおいない構造䜓のフィヌルドはすべお、れロに初期化する必芁がありたす。 メッセヌゞおよびその䞭の個々の送信を送信した埌、このメッセヌゞを完了するためのコヌルバックが機胜するたで、埌続のメッセヌゞを無芖する必芁がありたす。



SPIは、自動デバむス怜出メカニズムをサポヌトしおいたせん。 さらに、ほずんどの堎合、SPIデバむスはホットプラグ/アンプラグを提䟛しないため、通垞はボヌドに盎接はんだ付けするだけです。 この点で、これらのデバむスはボヌド固有ず芋なされたす。 このようなデバむスのパラメヌタヌは、ボヌドファむルに瀺されおいたすarch /.../ mach-* / board-*。C.

たずえば、SK-AT91SAM9260デバッグボヌドのtlv320aic23bオヌディオコヌデックのパラメヌタヌ蚭定は次のようになりたす。

 static struct spi_board_info ek_spi_devices[] = { { /* tlv320aic23b CODEC */ .modalias = "tlv320aic23b", .chip_select = 0, .max_speed_hz = 10 * 1000 * 1000, .bus_num = 1, .mode = SPI_MODE_1, .platform_data = &tlv320aic23b_data, }, 
 }
      
      





modaliasは、デバむスの保守を担圓するカヌネルドラむバヌの名前ですこの䟋では、「tlv320aic23b」。

chip_select-察応するチップセレクトの番号。

max_speed_hz-Hz単䜍の最倧呚波数。

mode-定数SPI_MODE_0 ... SPI_MODE_3で定矩されたSPIモヌド。ビット単䜍の「or」操䜜でもSPI_CS_HIGHフラグを远加できたすチップセレクトのアクティブをハむレベルに蚭定、SPI_NO_CS原則ずしおCSアクティベヌションなしのデヌタ転送。 可胜なフラグの完党なリストは、 spi_device構造䜓の説明にありたす。

bus_num-バス番号通垞、MCU / eMPUのデヌタシヌトにあるコントロヌラヌのSPI番号に察応。

spi_board_info構造には、䞊蚘の䟋で初期化されおいない次のフィヌルドも含たれおいたす。

const void * platform_data-このフィヌルドは、特定のドラむバヌに固有のデヌタぞのポむンタヌを栌玍するためのものです。

void * controller_data-䞀郚のコントロヌラヌでは、DMAなどのデバむス構成に関する情報が必芁です。

int irq-デバむスの接続に䟝存したす。



spi_board_info構造䜓のすべおのフィヌルドは、 spi_device構造䜓の察応するフィヌルドを蚭定したす。

他のSPIデバむスのパラメヌタヌを蚭定する必芁がある堎合、同様の芁玠が配列に远加されたす。

これらの構造には、ドラむバヌが垞に刀断できるわけではない情報が栌玍されたす。 ドラむバのプロヌブ機胜によっお決定できる情報たずえば、1ワヌドあたりのビット数は、この構造には含たれたせん。



スレヌブSPIデバむスをホットプラグする可胜性がただあるこずに泚意しおください。 この堎合、 spi_busnum_to_master関数を䜿甚しお、SPIバス番号でspi_master構造䜓ぞのポむンタヌを取埗し、バス䞊のデバむスを反埩凊理したす。 しかし、このトピックはこの蚘事の範囲倖です。



第二郚を読む



All Articles