Raspberry Piボヌドの結論に基づいお任意のシヌケンスを生成したす





投皿者Nikolai Khabarov、Embedded Expert DataArt、スマヌトホヌムテクノロゞヌ゚バンゞェリスト



この蚘事では、最新のLinux ARM ARMプロセッサ甚の通垞のPythonナヌザヌ空間アプリケヌションを䜜成しお、ボヌドの結論に基づいお耇雑なパルスシヌケンスを生成する方法を説明したす。 アむデアの本質は、プロセッサのDMAモゞュヌルを䜿甚しお、GPIOのメモリ内の事前に準備されたバッファから時間内に高い粟床でコピヌするこずです。



ステッピングモヌタヌなどの耇雑なパルスシヌケンスを生成する必芁がある堎合、通垞、特別なリアルタむムオペレヌティングシステムがむンストヌルされおいるか、オペレヌティングシステムがたったくない、叀き良きシンプルなマむクロコントロヌラヌを䜿甚したす。 この堎合の実装は、せいぜいC ++で曞かれおいたす。 珟圚、プロセッサははるかに進歩しおおり、パフォヌマンス、すべおのむンフラストラクチャおよび゜フトりェアでLinuxオペレヌティングシステムを䜿甚できるこず、Pythonなどの高レベルプログラミング蚀語など、倚くの利点がありたす。 それでも、最新のマむクロコントロヌラヌは、原則ずしお、耇雑なマむクロコントロヌラヌを䜿甚しおGPIOピンを生成したせん。



Pythonで完党に蚘述され、Raspberry Piボヌド䞊の最新のARMプロセッサで実行されるCNCマシン、工䜜機械、3DプリンタヌのコントロヌラヌのプロゞェクトであるPyCNCプロゞェクトのステッピングモヌタヌを制埡するためのパルス生成を実装したした。



この蚘事は、他のプロセッサのDMAモゞュヌルを䜿甚しお、他の高レベルプログラミング蚀語の1぀たたは耇数のGPIOの出力に蚭定レベルの耇雑なシヌケンスの生成を実装する堎合に圹立ちたす。



GPIO



汎甚入力出力GPIOは、物理出力の論理レベルを蚭定するプロセッサモゞュヌルです。 ご存知のように、デゞタルの䞖界では、出力は「0」、぀たり、脚が「グランド」に匕っ匵られるか、「1」、぀たり脚が電源に匕っ匵られる可胜性がありたす。



きっずあなたの倚くがLEDを点灯しお、マむクロコントロヌラヌの脚の1぀を制埡したす。 たずえば、AVRマむクロコントロヌラヌの堎合、これは倉数の察応するビット、たたはよく呌ばれるようにPORTxレゞスタを蚭定するこずで行われたした。 この倉数は䜕ですか ヘッダヌファむルを芋るず、次のようなものがありたす。



#define PORT (*(volatile uint8_t *)(0x12345678))
      
      





぀たり、出力状態レコヌドは、既知のアドレスでのこの倀のレコヌドです。 これはRAMのアドレスではなく、プロセスの仮想メモリのアドレスではなく、プロセッサ自䜓のアドレス空間のアドレスであるこずに泚意しおください。 物理的で、チップ内のどこかに、実際のGPIOモゞュヌルがこのアドレスに接続され、プロセッサコアを介しおこのアドレスでアクセスし、情報のバむトを枡しお出力ステヌタスを蚭定したす。 そしお、ほずんどすべおのプロセッサにこのようなモゞュヌルがありたす。 Raspberry Pi ARMプロセッサも䟋倖ではありたせん。 各モゞュヌルがアドレス空間のどこにあるかを正確に知るには、関心のあるプロセッサのドキュメントを調べる必芁がありたす。



Raspberry Piの堎合、このドキュメントはこちらです。



その䞭で、GPIOレゞスタはバスアドレス0x7E200000にありたす。぀たり、察応するアドレスにデヌタを曞き蟌むこずで、ピンの状態を制埡できたす。 すぐに、Raspberry Pi 1、2、および3プロセッサの呚蟺党䜓が同じであり、アドレス0x7E000000から始たる呚蟺バスアドレスがマッピングされる物理アドレスのみが異なるこずに泚意しおください。 Raspberry Piのバヌゞョン1の堎合、これは0x20000000になり、バヌゞョン2および3の堎合は0x3F000000になりたす。 ぀たり、RPi3プロセッサの堎合、バスアドレス0x7E200000にアクセスするには、物理​​アドレス0x3F200000に曞き蟌む必芁がありたす。 䞊蚘のリンクのドキュメントでは、すべおのアドレスはバスアドレスです。



ほずんどの堎合、LinuxはARMプロセッサにむンストヌルされたす。 物理メモリにアクセスする方法に぀いおの質問がすぐに発生したす。 それぞのアクセスはOSの䞭栞です。 仮想アドレス空間で実行する通垞のアプリケヌションを䜜成したす。 幞いなこずに、Linuxカヌネルは仮想デバむス「/ dev / mem」を介しお物理メモリぞのアクセスを提䟛したす。これを開くずスヌパヌナヌザヌ暩限が必芁です、物理メモリに曞き蟌むこずができたす。 公平に蚀うず、公匏のRaspberry Pi OSでは、Raspbianにはドラむバヌ 'bcm2835_gpiomem'によっお提䟛されるデバむス '/ dev / gpiomem'もあり、スヌパヌナヌザヌ暩限がなくおもアクセスできたす-最初のGPIOレゞスタぞのアクセスはすぐにれロでむンデントされたす。



少し緎習しおみたしょう。䞊蚘のすべおを理解する方が簡単だず思いたす。 Raspberry Pi 2および3で実行されおいるGPIO21ピンに接続されたLEDを点灯する単玔なPythonアプリケヌションを䜜成しおみたしょうRPi1の堎合、リストのアドレスを修正したす。 Pythonの代わりに、libc.soからシステム関数を呌び出すこずができる他のプログラミング蚀語を䜿甚できたす。 コヌドは次のずおりです。



#!/usr/bin/env python
import os
import mmap
import time
import ctypes
fd = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
mem = mmap.mmap(fd, mmap.PAGESIZE, flags=mmap.MAP_SHARED, offset=0x3F200000)
os.close(fd)
v = ctypes.c_uint32.from_buffer(mem, 0x8).value
v &= ~(0b111 << 3)
v |= 0b001 << 3
ctypes.c_uint32.from_buffer(mem, 0x8).value |= v
try:
while True:
ctypes.c_uint32.from_buffer(mem, 0x1C).value = 1 << 21
time.sleep(0.5)
ctypes.c_uint32.from_buffer(mem, 0x28).value = 1 << 21
time.sleep(0.5)
except KeyboardInterrupt:
pass
ctypes.c_uint32.from_buffer(mem, 0x8).value &= ~(0b111 << 3)
mem.close()
view raw 1 hosted with ❀ by GitHub


コヌドにマゞックナンバヌを意図的に残したした-説明しやすいでしょう。 コヌドを行ごずに解析したしょう。



䞊䜍5行は、必芁な暙準Pythonモゞュヌルのむンポヌトです。



7行目では、ファむル '/ dev / mem'を盎接開いおメモリにアクセスしたす。



8行目で、 memmapシステム関数を呌び出したす。この関数は、仮想ではありたすが、プロセスの仮想アドレス空間にファむルを投圱したす。 ぀たり、プロセスの仮想メモリに曞き蟌むず、実際に物理メモリに曞き蟌みたす。 たた、コヌドは、メモリを投圱するアドレスから始たるむンデントず長さmmap.PAGESIZEも瀺したす。 最初のGPIOレゞスタのアドレスずメモリの1ペヌゞの長さを瀺したす。 䞀芋、「/ dev / mem」を開いお目的のアドレスに戻り、ファむルの曞き蟌みを開始するように芋えるかもしれたせんが、残念ながら、それはうたくいきたせん。



9行目では、ハンドルを開いたたたにする必芁がないため、ファむルを閉じたす。マッピングはどこにも消えたせん。



11〜14行目では、0x08むンデントされたレゞスタを読み曞きしたす。 ドキュメントを芋るず、これはレゞスタGPFSEL2 GPIO機胜遞択2です。これらのレゞスタを䜿甚しお、チップレッグが実行する機胜を遞択したす。 この堎合、出力が出力ずしお機胜するように、001で3番目から始たる3ビットを蚭定最初にクリアし、次にOR挔算を䜿甚しお蚭定したす。 実際には、異なるモヌドを蚭定する結論は非垞に倚く、1぀のレゞスタヌでは十分ではないため、レゞスタヌはそれぞれ10の結論のグルヌプに分割されたす。



16行目ず22行目には、キヌボヌドのCtrl + Cがプログラムを終了するのを埅぀ハンドラヌをむンストヌルしたす。



17行目で、無限ルヌプを開始したす。



18行目では、ビットマスクをGPSET0レゞスタに曞き蟌むこずにより、出力をHighに蚭定したす。



19行目ず21行目では、0.5秒の遅延を実珟しおいたす。



20行目では、GPCLR0ビットマスクを曞き蟌むこずで出力を䞋げおいたす。



25行目ず26行目で、ピンを初期化解陀し、デフォルト状態入力に倉換しお、メモリマッピングを閉じたす。



短いメモBCM2835には、AVRのようなPORTAに䌌たレゞスタがありたせん。぀たり、すべおのピンの状態ハむたたはロヌをすぐに蚘録するこずはできたせん。 ナニットがビットマスクで瀺されおいるすべおのピンに論理ナニットを蚭定できるSETレゞスタず、ナニットがビットマスクで指定されおいるすべおのピンに論理れロを蚭定できるCLEARレゞスタのみがありたす。



たずえば、コマンド 'sudo python gpio.py'を䜿甚しおRaspberry Pi 2たたは3でスヌパヌナヌザヌ暩限でこのコヌドを実行し、LEDをピン21に接続するず、点滅するこずがわかりたす。



GPIOピンを管理する既補の実装が必芁な堎合は、このファむルからGPIOクラスを䜿甚できたす 。



ステッピングモヌタヌ



ステッピングモヌタヌの制埡は、䞀芋するず単玔なように単玔ではありたせん。 問題の本質を簡単に説明し、そのようなシヌケンスを生成する必芁がある理由を芋おみたしょう。 ステッピングモヌタヌデバむスの理論の詳现に぀いおは説明したせん。ご垌望の方はここで読むこずができたす 。



代わりに、すぐに珟実に戻り、ステッピングモヌタヌには4぀の巻線から4぀たたは5぀の出力がありたす。 ゚ンゞンを回転させるのに必芁な電流は非垞に高く、単䞀のマむクロコントロヌラヌたたはプロセッサヌがこれを提䟛するこずはできたせん。 たた、このような電流を生成するには、原則ずしお、プロセッサロゞックの電圧を超える電圧が必芁です。 そのため、ステッピングモヌタヌでは、ドラむバヌ、堎合によっおはモヌタヌハりゞングに組み蟌たれた特殊なマむクロ回路が䜿甚されたす。 最も単玔なドラむバULN2003などは、暙準のマむクロコントロヌラロゞック電圧ず互換性のある䜎電流巻線制埡入力を提䟛するだけです。 このようなドラむバでは、巻線ごずにパルスシヌケンスを生成する必芁がありたす。 最も人気のあるA4988やDRV8825を含むほずんどのドラむバヌは、モヌタヌ巻線を扱う際の頭痛の皮になりたす。 これらは、2぀の䜎電流出力STEPおよびDIRのシンプルなむンタヌフェむスを提䟛したす。 名前から掚枬できるように、STEPにパルスを印加するず、ドラむバヌぱンゞンを1ステップ移動したすドラむバヌはいわゆるマむクロステップ、぀たり1 / 2、1 / 4などのステップの移動甚に構成するこずもできたす-これは達成されたす巻線技術。 DIRピンは、䜎レベルず高レベルのどちらが適甚されるかに応じお、゚ンゞンの回転方向を遞択するために䜿甚されたす。



兞型的なA4988接続図は次のようになりたすむンタヌネットで写真を借りたした。









最も単玔なケヌスでは、STEP端子にパルスを印加するこずにより、特定の呚波数で゚ンゞンを回転させるこずができたす。 圌ず遊ぶだけで十分です。 しかし、物理法則は実際のデバむスに䜜甚するため、機構を壊したくない堎合は、固定呚波数のパルスを印加するだけでは、゚ンゞンを必芁な速床にすぐに加速するこずはできたせん。 䞀定の加速床で゚ンゞンを回転させお垌望の速床にし、その埌完党に停止するたで゚ンゞンを枛速させる必芁がありたす。 したがっお、パルス繰り返し率は加速および加速䞭に倉化するはずであり、必芁な信号はもはや呚期的ではなくなりたす。



この接続により、マむクロコントロヌラ自䜓にほずんどすべおの機胜を実装できるため、STEPおよびDIR出力でモヌタヌを制埡するこのアプロヌチは最も䞀般的です。 たずえば、読者が質問する堎合がありたす-I2CたたはUARTむンタヌフェむスを備えたドラむバヌはありたすか 理論的には、このようなドラむバヌを䜜成できたすが、同じ3Dプリンタヌを制埡するには、いく぀かのステッピングモヌタヌを同期制埡する必芁がありたす。 さらに、それぞれに異なる加速パラメヌタヌ、1ミリメヌトルあたりのステップ数、および最倧速床を蚭定できたす。 その結果、そのような耇雑さのドラむバヌは、CNCコントロヌラヌのアナログになりたす。



ご想像のずおり、䞊蚘のGPIO制埡方法では、ピン䞊のパルスを正しく圢成できたせん。 Pythonコヌドの実行の遅延が予枬できないずいうだけではありたせん。 CですべおをLinux Linuxのカヌネルモゞュヌルの圢匏で実装しおも、Linuxはリアルタむムオペレヌティングシステムではないため、良い結果は埗られたせん。 い぀でも、プロセッサコアは他のタスクの実行に切り替えるこずができ、時間内に衝動を䞎えたせん。 しかし、そのような些现なこずで私たちは蚈画ぞの道を阻たれたすか



DMA



ダむレクトメモリアクセスは、コアプロセッサ自䜓のサヌビスに頌らずに、ある堎所から別の堎所にメモリをコピヌできる専甚のプロセッサハヌドりェアモゞュヌルです。 このようなモゞュヌルは単玔なマむクロコントロヌラヌでも存圚したすが、実装はプロセッサヌモデルごずに倧きく異なりたす。 Raspberry Piの実装はかなり平凡です。必芁なものはすべお揃っおいたすが、食り気はありたせん。 たた、たずえば、Rockchip RK3399 DMAモゞュヌルは、小さいながらも䞀連の呜什を備えたミニコアプロセッサに䌌おいたす。



私はオリゞナルのドキュメントの完党な翻蚳を曞く仕事を自分自身に蚭定しおいたせん。 そしお、GPIOモゞュヌルにデヌタをコピヌするモヌドでDMAモゞュヌルを実行できるようにするメむンレゞスタに぀いお説明したす。



ご想像のずおり、メモリ内にバッファを生成し、GPIOモゞュヌルのロケヌションアドレスにコピヌしたす。 しかし、DMAモゞュヌルが機胜するためには、このバッファが物理メモリのどこかにあるこずが必芁です。 圓然、スワップに該圓しなかった仮想メモリも物理メ​​モリに栌玍されたす。 「/ proc / self / pagemap」を䜿甚するず、独自のプロセスのメモリのマッピングテヌブルを物理メモリに取埗できたす。぀たり、バッファを割り圓おお、その物理アドレスを芋぀けたす。



しかし、これはDMAで行う䟡倀はありたせん。これは、メモリがスワップに入る可胜性ず、オペレヌティングシステムのメモリマネヌゞャが割り圓おられたメモリを別の堎所に転送できるためです。 ブヌト時にLinuxカヌネルkmallocからメ゜ッドを呌び出す単玔なカヌネルモゞュヌルを䜜成できたす。このメ゜ッドは、可胜な転送からメモリを割り圓お、ブロックしたす。 次に、たずえば仮想デバむスを介しお、割り圓おられたメモリのアドレスをアプリケヌションに枡したす。 このアドレスを䜿甚するず、アプリケヌションはGPIOセクションで説明した方法ずたったく同じ方法でメモリにアクセスできたす。 割り圓おたアドレスたたはバッファは、DMAモゞュヌルで䜿甚できたす。



ただし、非垞に単玔ではありたすが、匷力なモゞュヌルを䜜成する必芁はないでしょう。



さお、既補の゜リュヌション-仮想デバむス '/ dev / vcio'がありたす。 Raspberry Piグラフィックカヌドドラむバヌによっお䜜成されたす。 通信のために、VideoCoreずCPUはいわゆるメヌルボックスを䜿甚したす。これは、本質的に、ビデオカヌドに割り圓おられたメモリに割り圓おられた郚分です。 デフォルトでは、ビデオカヌドには64 MBが割り圓おられおおり、必芁に応じおこの倀を倉曎できたす。 必芁に応じおビデオメモリからいく぀かのリ゜ヌスを割り圓おるずいう事実は、ビデオカヌドの動䜜に圱響を䞎えるこずはありたせん。䞻なこずは、あたり倚くをずらないこずです。 実際には、Raspbian OSデスクトップが正垞に機胜するには30〜35 MBのメモリで十分です玄半分。 ぀たり、OpenGLを䜿甚しおアプリケヌションを起動する予定がない堎合、埌半は完党にアクセス可胜です。 さらに、GPU自䜓に転送するためのメモリの䞀郚の割り圓おは、通垞の手順です。 たた、メモリを割り圓おおも、ビデオプロセッサに割り圓おない堎合、問題は発生したせん。 このようなメモリ割り圓おを䜿甚する公匏の䟋を次に瀺したす。



このプロセスは非垞に簡単ですが、コヌドのマゞックナンバヌの埌ろに隠れおいたす。 / dev / vcioを開き、ioctlメ゜ッドを䜿甚しお、リク゚ストで構造䜓を枡し、答えを取埗したす。 メモリマネヌゞャが割り圓おた郚分をどこにも䜿甚しないように、メモリを割り圓おおロックする必芁がありたす。 䞊蚘のリンクから実装を確認できたす。mem_alloc、mem_lockメ゜ッド、そしおもちろん、mem_unlock、mem_freeをクリヌンアップできるメ゜ッドに興味がありたす。 Cの実装に混乱しおいる堎合は、これらのメ゜ッドを他の蚀語で曞き換えるこずができたす。



たあ。 バッファを割り圓おる堎所。 ここで、どうにかしおDMAをプログラムし、必芁なこずを行う必芁がありたす。 DMAモゞュヌルは物理メモリ内のほんの数個のレゞスタであるこずに泚意しおください。 構造を目的のアドレスに曞き蟌むこずにより、同じ方法で管理されたす。 合蚈で、Raspberry Piには16個のDMAチャネルがありたす。 最初の8぀は完党に機胜し、残りの8぀は機胜がわずかに制限されおいたす。 各チャネルには、独自のレゞスタセットがありたす。 DMAモゞュヌルバスのベヌスアドレスは0x7E007000です。぀たり、Raspberry Pi 2たたは3の堎合、0x3F007000で曞き蟌む必芁がありたす。 最初のDMAチャネルの最初のレゞスタは次のずおりです。 埌続の各オフセットは0x100です15を陀き、0x7EE05000にありたす。



䜿甚するチャネルは チャネルをカヌネルで䜿甚できるため、遞択は非垞に耇雑です。 コマンド「cat / sys / class / dma / dma0chan * / in_use」を䜿甚しお、sysfsを介しおカヌネル自䜓で䜿甚されおいるチャネルを正確に芋぀けるこずができたす。 原則ずしお、0、1、2、3、6、7チャンネルはmicroSDカヌドリヌダヌずビデオカヌドドラむバヌを䜿甚するため、䜿甚しないでください。



DMAモゞュヌルを制埡するためのメむンレゞスタは、CSおよびCONBLK_ADです。 DMAを起動するのはそれらを埋めるこずです。 最初のレゞスタはCSであり、その䞭のフィヌルドに興味がありたす。

ビット

数
フィヌルド 説明 アクセス
31 リセット ナニットを曞き蟌むず、DMAモゞュヌルがリセットされたす。 W
1 終了 ナニットが曞き蟌たれるず、送信終了フラグがリセットされたす。 W
0 ACTIVE ナニットを曞き蟌むずき、DMAは動䜜を開始したす。 このフィヌルドを䜿甚する

DMAを䞀時停止できたす。 転送が完了するず、フィヌルド

自動的に倀0を取りたす。
Rw




レゞスタにはさらに倚くのフィヌルドがありたす。奜奇心itive盛な読者は、 䞊蚘で出䌚ったリンク 47ペヌゞ を䜿甚しお、公匏文曞で各フィヌルドの説明を芋぀けるこずができたす。



いわゆるコントロヌルナニットがDMAモゞュヌルの凊理内容を蚘述するアドレスは、CONBLK_ADレゞスタに曞き蟌たれたす。 同時に、制埡ブロックはリンクリストです。぀たり、耇数の制埡ブロックを䜿甚しお、さたざたなタスクのチェヌンを構築できたす。 タスクを完了するず、DMAモゞュヌルは自動的にすべおの制埡ブロックを通過したす。 CONBLK_ADのアドレスから、CSレゞスタにACTIVEビットが蚭定されるず、DMAモゞュヌルがコピヌを開始したす。



コントロヌルナニットは、32バむトのアラむメントでメモリに栌玍する必芁がありたすアドレスの最䞋䜍5ビットはれロでなければなりたせん。 次に、制埡ブロックの構造を芋おみたしょう。

むンデントバむト フィヌルド 説明
0 Ti デヌタコピヌ蚭定を指定するさたざたなフラグのセット。
4 SOURCE_AD コピヌを開始する゜ヌスアドレス。
8 DEST_AD コピヌ先の宛先アドレス。
12 TXFR_LEN コピヌするバむト数。

特別な2Dモヌドでは、最高16ビットが蚭定されたす

コピヌサむクル数、䞋䜍16ビット-

サむクルごずにコピヌされるバむト数。
16 ストラむド 2Dモヌドでのみ䜿甚されたす。 䞋䜍16バむト

シフト量を指定する笊号付き数倀を保存したす

次のサむクルの開始前の送信元アドレス。

䞊䜍16バむトには、必芁な笊号付き番号が栌玍されたす

次のサむクルを開始する前に宛先アドレスをシフトしたす。
20 NEXTCONBK 次の制埡ブロックぞのポむンタヌ。


チャネル0〜7は、2Dモヌド制埡ブロックのTIフィヌルドのTDMODEフラグビット1で蚭定をサポヌトしたす。これにより、YバむトのXコピヌを敎理できたす。 この堎合、各コピヌの前の宛先および/たたは送信元アドレスは、制埡ブロックのSTRIDEフィヌルドに埓っお、特定の量だけ増枛できたす。



各DMAチャネルには、TI、SOURCE_AD、DEST_AD、TXFR_LEN、STRIDE、NEXTCONBKのレゞスタセットもあり、これらは読み取り専甚です。 それらは珟圚の制埡ブロックからロヌドされたす。



さお、PythonのDMAおよびGPIOモゞュヌルを䜿っお簡単なこずを詊しおみたしょう。 プログラムのリストがそれほど長くなく、䜙分なマゞックナンバヌが含たれないように、このファむルからいく぀かの既補のコヌドを取りたしょう。



それから、定数ずクラス「PhysicalMemory」GPIOの䟋で行ったように物理メモリぞのアクセスず「CMAPhysicalMemory」これは䞊で曞いたビデオドラむバ/ dev / vcioを䜿甚しお物理メモリを割り圓おる実装ですを䜿甚したす。



#!/usr/bin/env python
import time
from rpgpio_private import *
DMA_CHANNEL = 14
PIN = 21
gpio = PhysicalMemory(PERI_BASE + GPIO_REGISTER_BASE)
gpio_fsel_offset = 4 * int(PIN / 10) + GPIO_FSEL_OFFSET
v = gpio.read_int(gpio_fsel_offset)
v &= ~(7 << ((PIN % 10) * 3))
v |= (1 << ((PIN % 10) * 3))
gpio.write_int(gpio_fsel_offset, v)
gpio.write_int(GPIO_SET_OFFSET, 1 << PIN)
time.sleep(1)
physmem = CMAPhysicalMemory(64)
cb1 = (
DMA_TI_NO_WIDE_BURSTS | DMA_TI_WAIT_RESP, # info
physmem.get_bus_address() + 24, # source
PHYSICAL_GPIO_BUS + GPIO_SET_OFFSET, # destination
4, # length
0, # stride
physmem.get_bus_address() + 32, # next control block
1 << PIN, # padding, use as source
0 # padding
)
cb2 = (
DMA_TI_NO_WIDE_BURSTS | DMA_TI_WAIT_RESP, # info
physmem.get_bus_address() + 32 + 24, # source
PHYSICAL_GPIO_BUS + GPIO_CLEAR_OFFSET, # destination
4, # length
0, # stride
physmem.get_bus_address(), # next control block
1 << PIN, # padding, use as source
0 # padding
)
physmem.write(0, "8I", cb1)
physmem.write(32, "8I", cb2)
dma = PhysicalMemory(PERI_BASE + DMA_BASE + DMA_CHANNEL * 0x100)
dma.write_int(DMA_CS, DMA_CS_RESET)
dma.write_int(DMA_CS, DMA_CS_END)
dma.write_int(DMA_CONBLK_AD, physmem.get_bus_address())
dma.write_int(DMA_CS, DMA_CS_ACTIVE)
raw_input("Press Enter to stop")
dma.write_int(DMA_CS, DMA_CS_RESET)
v = gpio.read_int(gpio_fsel_offset)
v &= ~(7 << ((PIN % 10) * 3))
gpio.write_int(gpio_fsel_offset, v)
view raw 2 hosted with ❀ by GitHub


このプログラムを実行するずスヌパヌナヌザヌ暩限で実行するこずを忘れないでください、ピン21に接続されたLEDが最倧茝床で0.5秒間点灯し違いが顕著になるように、Enterキヌを抌すたで半茝床で点灯したす。 行ごずに解析したしょう。



2-3行-モゞュヌルのむンポヌト。



5番目ず6番目は、䜿甚するDMAチャネルずGPIO出力を瀺す倉数です。



8-15th-瀺されたGPIO出力を出力ずしお初期化し、0.5秒間点灯したすそのため、DMAがオンになったずきに違いがはっきりず芋えるようになりたす。 実際、これは最初のプログラムで行ったものず同じですが、少し高いレベルで曞かれおいたす。



17行目-ビデオドラむバヌに64バむトのメモリを割り圓おるように䟝頌したす。 CMAPhysicalMemoryクラスでは、メモリはペヌゞサむズ、぀たり4096バむトに等しいアラむメントで割り圓おられるため、このメモリを䜿甚する堎合、割り圓おられたメモリの先頭は垞にDMAモゞュヌルが必芁ずする32バむトにアラむメントされたす。



18行目-制埡ブロックの最初の構造を埋めたす。 これに぀いおさらに詳しく説明したす。



19行目-最初の4バむト-TI転送情報フラグ。 DMA_TI_NO_WIDE_BURSTS — burst- — — , , .

DMA_TI_WAIT_RESP — DMA- .



DMA_TI_SRC_INC DMA_TI_DST_INC — , DMA- 4 . , DMA-, / . .



20- — , . , , () ( get_bus_address()). , , , . .



21- — GPIO- SET, . . , .



22- — — 4 .



23- — stride, , 0.



24- — next control block, 32 .



25- — , , 21- 4 , , — , GPIO.



26 — .



28–37- — , . CLEAR GPIO, . , .



38–39- — .



41- — DMA- .



42-43- — DMA-.



44- — .



45- — DMA-.



47- — Enter.



49–52- — . DMA- ().



, :









Raspberry Pi 2. , 1.5 — ( ~2 ) , , .



DMA



, , — DMA- GPIO-. DMA — , , 
 , .



DMA 1 . , STEP, , , 2 . , 2 , . . 500 000 . 4 , . : 1 ( 200 200 / — ), 114 . — 228 . , ? , , . 114 .



DMA- — . DMA- — . , , , , , , 16 4 . , . . - , . , , .



GPIO DMA , - . , 3D-. . ?



.



:









, GPIO, DMA ( ). « 1» , « 2» — . . 200 200 /. « 2», . , , . . , . CNC- .



(200 400 — 80 000 ) 128 ( 32 ), DMA ~9.8 . . , , . 3D- , . . 39.2 , , ( - ), .



, ? , , , . . GPIO . DMA- — . PWM (, , , ). PWM , , DMA FIFO- PMW. PWM- . , PWM , FIFO.



DMA- PWM-, PERMAP TI , , 5, PWM- .



, , DMAGPIO. rpgpio, , ( 1, 2, 3, 4 5 ). :









, , , .



 import rpgpio PIN=21 PINMASK = 1 << PIN PULSE_LENGTH_US = 1000 PULSE_DELAY_US = 1000 DELAY_US = 2000 g = rpgpio.GPIO() g.init(PIN, rpgpio.GPIO.MODE_OUTPUT) dma = rpgpio.DMAGPIO() for i in range(1, 6): for i in range(0, i): dma.add_pulse(PINMASK, PULSE_LENGTH_US) dma.add_delay(PULSE_DELAY_US) dma.add_delay(DELAY_US) dma.run(True) raw_input("Press Enter to stop") dma.stop() g.init(PIN, rpgpio.GPIO.MODE_INPUT_NOPULL)
      
      





DMA-



DMA-, , FM- Raspberry Pi — .



DMA-, 250 . , DMA- . . PWM ( PWM , PWM- ), . , , . , DMA-, PWM-, , .



PRU



BeagleBone PRU (programmable real-time unit), 200 32- , AM3358. . . — .



おわりに



DMA- , , .



, , . , . Raspberry Pi Zero, , .



— , , :






All Articles