Bench worksheets · transcribed from the lab notebook實驗桌工作單 · 由實驗筆記本謄寫ベンチ用ワークシート · 研究ノートからの書き起こしLembar kerja meja praktik · disalin dari buku catatan lab
Digital System Training數位系統訓練デジタルシステム訓練Pelatihan Sistem Digital
Radio Frequency & Microwave Lab, NSYSU國立中山大學 射頻與微波實驗室国立中山大学 高周波・マイクロ波研究室Laboratorium Frekuensi Radio & Gelombang Mikro, NSYSU
Verilog on the fabric, a host program on the desk, and the link between them. Each section is
a run of builds that stack, so nothing gets thrown away when the next one starts.
FPGA 上跑 Verilog,桌上跑主機端程式,中間是把兩者接起來的那條線。每個章節都是一串會互相堆疊的實作,所以做下一題時,上一題不會被丟掉。FPGA 側は Verilog、机の上はホストプログラム、そしてその二つをつなぐ線。各セクションは積み上がっていく課題の連なりで、次に進んでも前の成果を捨てることはない。Verilog di atas fabric, program host di meja, dan sambungan di antara keduanya. Setiap bagian adalah rangkaian pekerjaan yang saling menumpuk, sehingga tidak ada yang dibuang ketika bagian berikutnya dimulai.
FPGA Starter HomeworkFPGA 入門作業FPGA 入門課題Tugas Awal FPGA
Warm-up builds that walk from a counter blinking on the board's LEDs up to
a motor turning under duty-cycle control, then hand the host side to Python.
Each one adds a single new idea to the thing you built before it.
從板子上 LED 閃爍的計數器一路做到用工作週期控制轉動的馬達,最後把主機端交給 Python。每一題都只在前一題的基礎上加入一個新觀念。ボードの LED を光らせるカウンタからデューティ比で回るモータまで進み、最後にホスト側を Python へ渡す。各課題は前の課題に新しい考え方を一つだけ足していく。Latihan pemanasan yang berjalan dari pencacah yang mengedipkan LED di papan sampai motor yang berputar di bawah kendali duty cycle, lalu menyerahkan sisi host kepada Python. Masing-masing hanya menambahkan satu gagasan baru pada apa yang sudah kamu bangun sebelumnya.
FabricFPGA 端FPGA 側Sisi FPGA
Verilog · Quartus or Vivado
Host主機端ホスト側Sisi host
LabVIEW or Python
System clock系統時脈システムクロックClock sistem
50 MHz
Serial link串列連線シリアル接続Sambungan serial
115200 8N1
Hardware — what you are given硬體 —— 你會拿到的東西ハードウェア — 貸し出すものPerangkat keras — apa yang kamu terima
There should be three Digilent Artix-7 dev boards — the white ones — in the
lab. If they are not on the bench, ask Tony, or anyone who can reach Yiya; between them they
know where the boards ended up.
實驗室裡應該有三片 Digilent Artix-7 開發板——白色那款。如果桌上找不到,去問 Tony,或任何聯絡得到 Yiya 的人;板子最後跑到哪去,他們之間會知道。研究室にはDigilent Artix-7 開発ボードが 3 枚——白いボード——あるはず。机の上に無ければ Tony に、あるいは Yiya に連絡が取れる人に聞くこと。どこへ行ったかは彼らが知っている。Seharusnya ada tiga papan pengembangan Digilent Artix-7 — yang berwarna putih — di lab. Kalau tidak ada di meja, tanyakan kepada Tony, atau siapa saja yang bisa menghubungi Yiya; di antara mereka pasti ada yang tahu papan itu berakhir di mana.
I will hand each of you a USB-to-TTL adapter — that is how the FPGA talks to your PC or laptop, and every task from 3 onward assumes one is plugged in. Three rules before it touches the board: cross TX and RX, tie the grounds together, and leave the adapter's VCC pin unconnected — the board powers itself, and 5 V from an adapter into a 3.3 V I/O bank is the standard way to lose a bank. If the adapter has a 3.3 V / 5 V jumper, set it to 3.3 V first. It appears as a COM port on Windows (CH340 or CP2102 driver) and as /dev/ttyUSB0 on Linux.我會發給每個人一條 USB 轉 TTL 轉接器——FPGA 就是靠它跟你的桌機或筆電溝通,第 3 題之後每一題都預設你手上有一條插著。接到板子之前先記三件事:TX 與 RX 要交叉、地要共接、轉接器的 VCC 腳不要接——板子自己有電源,把 5 V 從轉接器灌進 3.3 V 的 I/O bank,就是燒掉一整個 bank 的標準做法。如果轉接器上有 3.3 V/5 V 跳線,先切到 3.3 V。它在 Windows 上會出現成一個 COM 埠(CH340 或 CP2102 驅動),在 Linux 上是 /dev/ttyUSB0。USB-TTL 変換アダプタは全員に一本ずつ渡す——FPGA が PC やノートと話すのはこれ経由で、課題 3 以降はすべて手元にある前提だ。ボードにつなぐ前に三つ:TX と RX をクロスする、グラウンドを共通にする、アダプタの VCC ピンはつながない——ボードは自前で給電しており、アダプタの 5 V を 3.3 V の I/O バンクに入れるのはバンクを一つ壊す典型的な方法だ。3.3 V/5 V のジャンパがあるなら、先に 3.3 V にしておくこと。Windows では COM ポート(CH340 か CP2102 のドライバ)、Linux では /dev/ttyUSB0 として見える。Saya akan membagikan satu adapter USB-ke-TTL kepada setiap orang — lewat itulah FPGA berbicara dengan PC atau laptopmu, dan setiap tugas mulai dari nomor 3 mengandaikan ada satu yang tercolok. Tiga aturan sebelum benda itu menyentuh papan: silangkan TX dan RX, satukan ground, dan biarkan pin VCC adapter tidak tersambung — papan itu punya catu daya sendiri, dan 5 V dari adapter yang masuk ke bank I/O 3.3 V adalah cara baku untuk kehilangan satu bank. Kalau adapter punya jumper 3.3 V / 5 V, setel dulu ke 3.3 V. Ia muncul sebagai port COM di Windows (driver CH340 atau CP2102) dan sebagai /dev/ttyUSB0 di Linux.
Check the oscillator before you build anything. Every divisor on this sheet
assumes a 50 MHz clock. The common Digilent Artix-7 boards ship a 100 MHz oscillator — read
your board's reference manual, and if it says 100 MHz, double all of these:
動手做之前先確認振盪器頻率。本工作單上所有除數都假設 50 MHz 時脈。常見的 Digilent Artix-7 板子出廠是 100 MHz——請查你手上板子的 reference manual,如果是 100 MHz,下列數字全部乘二:作り始める前に発振器を確認すること。このシートの分周値はすべて 50 MHz クロック前提。一般的な Digilent Artix-7 ボードは 100 MHz 発振器を積んでいる——ボードのリファレンスマニュアルを読み、100 MHz なら以下をすべて 2 倍にする:Periksa osilatornya sebelum membangun apa pun. Semua pembagi pada lembar ini mengandaikan clock 50 MHz. Papan Digilent Artix-7 yang umum dikirim dengan osilator 100 MHz — baca reference manual papanmu, dan kalau tertulis 100 MHz, gandakan semua angka berikut:
20 ms servo frame20 ms 伺服框架20 ms サーボフレームframe servo 20 ms
1e6 → 2e6 counts
1.5 ms servo centre1.5 ms 伺服中位1.5 ms サーボ中立titik tengah servo 1.5 ms
75,000 → 150,000
Before you program the board — install the USB-JTAG cable driver燒錄之前 —— 先裝好 USB-JTAG 下載線驅動ボードに書き込む前に — USB-JTAG ケーブルドライバを入れるSebelum memprogram papan — pasang driver kabel USB-JTAG
There is no separate "Artix-7 FPGA driver", so stop looking for one. The FPGA
die is configured over JTAG and Windows never sees it. What Windows has to recognise is the
USB-to-JTAG bridge chip on the Arty A7 — an FTDI part — and until that chip is
bound to a driver, neither Vivado's Hardware Manager nor Digilent's djtgcfg can
reach the board. "Installing the FPGA driver" means installing this cable driver, nothing else.
沒有一個叫「Artix-7 FPGA 驅動」的東西,不用再找了。FPGA 晶片本身是透過 JTAG 燒錄,Windows 從頭到尾看不到它。Windows 真正要認得的是 Arty A7 板上的 USB 轉 JTAG 橋接晶片——一顆 FTDI 的 IC——在這顆晶片綁好驅動之前,Vivado 的 Hardware Manager 和 Digilent 的 djtgcfg 都碰不到板子。所謂「裝 FPGA 驅動」,就是裝這條下載線的驅動,沒有別的。「Artix-7 FPGA ドライバ」という別物は存在しないので探すのはやめること。FPGA のダイは JTAG で書き込まれ、Windows からは一切見えない。Windows が認識しなければならないのは Arty A7 に載っている USB-JTAG ブリッジチップ——FTDI 製——で、これにドライバが結び付くまでは Vivado の Hardware Manager も Digilent の djtgcfg もボードに届かない。「FPGA ドライバを入れる」とはこのケーブルドライバを入れることであり、それ以外ではない。Tidak ada "driver FPGA Artix-7" yang terpisah, jadi berhenti mencarinya. Die FPGA dikonfigurasi lewat JTAG dan Windows tidak pernah melihatnya. Yang harus dikenali Windows adalah chip jembatan USB-ke-JTAG di Arty A7 — sebuah komponen FTDI — dan sampai chip itu terikat ke driver, baik Hardware Manager Vivado maupun djtgcfg dari Digilent tidak bisa menjangkau papan. "Memasang driver FPGA" berarti memasang driver kabel ini, tidak lebih.
Two ways to get there. Pick by what you need, not by which is shorter:有兩條路。依你需要什麼來選,不是選比較短的那條:方法は二つ。短い方ではなく、必要なものに合わせて選ぶこと:Ada dua jalan. Pilih berdasarkan apa yang kamu butuhkan, bukan mana yang lebih pendek:
driver + djtgcfg only, no Vivado只有驅動 + djtgcfg,沒有 Vivadoドライバ + djtgcfg のみ、Vivado 無しhanya driver + djtgcfg, tanpa Vivado
Path B is not a substitute for Path A. It gives you the transport and a command-line
programmer, and nothing that can turn Verilog into a bitstream. If you are going to build the
tasks on this sheet you need Vivado, so you need Path A.
路線 B 不能取代路線 A。它只給你傳輸層和一個命令列燒錄工具,沒有任何東西能把 Verilog 變成 bitstream。既然你要做這份工作單上的題目,就需要 Vivado,也就需要路線 A。B は A の代わりにはならない。B が与えるのは通信路とコマンドラインの書き込みツールだけで、Verilog をビットストリームにするものは何も無い。このシートの課題を作るなら Vivado が要るので、A が要る。Jalur B bukan pengganti Jalur A. Ia memberimu transport dan pemrogram baris perintah, tetapi tidak ada apa pun yang bisa mengubah Verilog menjadi bitstream. Kalau kamu akan membangun tugas-tugas di lembar ini kamu butuh Vivado, jadi kamu butuh Jalur A.
Path A — Vivado cable drivers (Windows)路線 A —— Vivado 下載線驅動(Windows)A — Vivado ケーブルドライバ(Windows)Jalur A — driver kabel Vivado (Windows)
Get the installer. Download the Vivado installer or install image for the release you plan to use from AMD's downloads page. Any current release works for the Artix-7; the free edition covers it.拿到安裝程式。從 AMD 的下載頁抓你打算用的那個版本的 Vivado 安裝程式或安裝映像。Artix-7 任何現行版本都能用,免費版就涵蓋了。インストーラを入手する。AMD のダウンロードページから、使う予定のリリースの Vivado インストーラまたはインストールイメージを取る。Artix-7 なら現行のどのリリースでも動き、無償版で足りる。Ambil installer-nya. Unduh installer atau image instalasi Vivado untuk rilis yang akan kamu pakai dari halaman unduhan AMD. Rilis terkini mana pun bekerja untuk Artix-7; edisi gratisnya sudah mencakupnya.
The installer's checkbox is a shortcut, not a guarantee. During installation Vivado offers an "install cable drivers" option. Take it, but do not trust it: for years it has silently failed for some people — the box shows unchecked again, or the driver never binds. Step 3 is the reliable method and works whether or not you ticked the box.安裝程式裡的勾選框是捷徑,不是保證。安裝過程中 Vivado 會提供「install cable drivers」的選項。勾起來,但不要信它:多年來它對某些人會默默失敗——勾選框又變回沒勾,或驅動根本沒綁上。第 3 步才是可靠的方法,不管你有沒有勾那個框都適用。インストーラのチェックボックスは近道であって保証ではない。インストール中に Vivado は「install cable drivers」の選択肢を出す。チェックはするが信用しないこと:何年も前から一部の環境で黙って失敗する——チェックが外れて表示される、あるいはドライバが結び付かない。手順 3 が確実な方法で、チェックの有無に関係なく使える。Kotak centang di installer adalah jalan pintas, bukan jaminan. Selama instalasi Vivado menawarkan opsi "install cable drivers". Centang, tetapi jangan percaya begitu saja: selama bertahun-tahun ia gagal diam-diam pada sebagian orang — kotaknya tampil tidak tercentang lagi, atau driver-nya tidak pernah terikat. Langkah 3 adalah cara yang andal dan bekerja terlepas dari apakah kamu mencentang kotak itu.
Run the driver script yourself, as Administrator. Open Command Prompt or PowerShell with Run as administrator, then:自己以系統管理員身分跑驅動安裝腳本。用以系統管理員身分執行開啟命令提示字元或 PowerShell,然後:ドライバスクリプトを自分で、管理者として実行する。コマンドプロンプトか PowerShell を管理者として実行で開き、次を実行:Jalankan skrip driver sendiri, sebagai Administrator. Buka Command Prompt atau PowerShell dengan Run as administrator, lalu:
:: replace the two paths with your own install directory
cd C:\Xilinx\Vivado\2025.2\data\xicom\cable_drivers\nt64
install_drivers_wrapper.bat C:\Xilinx\Vivado\2025.2\install_log
The single argument is the folder for the install log; leave it out and the script writes install_drivers_wrapper.log into the Vivado install directory instead. Old forum posts show a three-argument form from legacy releases — ignore them, current releases take only the log directory. The script installs both the Digilent components and the generic Xilinx Platform Cable (pcusb) driver.唯一的參數是安裝紀錄要寫到哪個資料夾;不給的話,腳本會把 install_drivers_wrapper.log 寫進 Vivado 的安裝目錄。舊的論壇文章會出現三個參數的寫法,那是舊版的——不用理,現行版本只吃紀錄資料夾這一個參數。這支腳本會同時裝 Digilent 元件和通用的 Xilinx Platform Cable(pcusb)驅動。唯一の引数はインストールログを書き出すフォルダで、省略するとスクリプトは install_drivers_wrapper.log を Vivado のインストールディレクトリに書く。古いフォーラム投稿には旧リリース由来の三引数形式が出てくるが無視すること。現行リリースはログディレクトリだけを取る。このスクリプトは Digilent のコンポーネントと汎用の Xilinx Platform Cable(pcusb)ドライバの両方を入れる。Satu-satunya argumen adalah folder untuk log instalasi; kalau dihilangkan, skrip menulis install_drivers_wrapper.log ke direktori instalasi Vivado. Postingan forum lama menunjukkan bentuk tiga argumen dari rilis lawas — abaikan, rilis terkini hanya menerima direktori log. Skrip ini memasang komponen Digilent sekaligus driver generik Xilinx Platform Cable (pcusb).
Replug and look in Device Manager. Unplug the Arty A7's USB cable, plug it back in, and open Device Manager. The board should now appear as a JTAG/USB device — no "Unknown device", no yellow warning icon.重插一次,看裝置管理員。把 Arty A7 的 USB 線拔掉再插回去,打開裝置管理員。板子現在應該以 JTAG/USB 裝置出現——沒有「未知的裝置」,沒有黃色驚嘆號。抜き差ししてデバイスマネージャーを見る。Arty A7 の USB ケーブルを抜いて挿し直し、デバイスマネージャーを開く。ボードが JTAG/USB デバイスとして見えているはず——「不明なデバイス」も黄色い警告アイコンも無いこと。Colok ulang dan lihat Device Manager. Cabut kabel USB Arty A7, colok kembali, dan buka Device Manager. Papan kini seharusnya muncul sebagai perangkat JTAG/USB — tidak ada "Unknown device", tidak ada ikon peringatan kuning.
Confirm the tool sees it. In Vivado: Open Hardware Manager → Open Target → Auto Connect, and the Arty A7 should be listed under the local server. Or from a prompt run djtgcfg enum — the Vivado driver install normally brings the Adept components with it; if the command is missing, Path B installs it.確認工具看得到它。在 Vivado 裡:Open Hardware Manager → Open Target → Auto Connect,Arty A7 應該會列在本機伺服器底下。或者在命令列跑 djtgcfg enum——Vivado 的驅動安裝通常會連 Adept 元件一起帶進來;如果找不到這個指令,走路線 B 就會裝到。ツールから見えることを確認する。Vivado で Open Hardware Manager → Open Target → Auto Connect を実行すると、ローカルサーバの下に Arty A7 が並ぶはず。あるいはプロンプトから djtgcfg enum を実行する——Vivado のドライバインストールは通常 Adept のコンポーネントも一緒に入れる。コマンドが見つからなければ B の手順で入る。Pastikan alatnya melihat papan. Di Vivado: Open Hardware Manager → Open Target → Auto Connect, dan Arty A7 seharusnya tercantum di bawah server lokal. Atau dari prompt jalankan djtgcfg enum — instalasi driver Vivado biasanya membawa komponen Adept bersamanya; kalau perintahnya tidak ada, Jalur B memasangnya.
Path B — Digilent Adept 2 Runtime only (no Vivado)路線 B —— 只裝 Digilent Adept 2 Runtime(不裝 Vivado)B — Digilent Adept 2 Runtime のみ(Vivado 無し)Jalur B — hanya Digilent Adept 2 Runtime (tanpa Vivado)
For a laptop that only has to detect the board or load a .bit file someone else built — bring-up checks, a demo machine — you can skip Vivado entirely.如果某台筆電只需要認得板子,或載入別人做好的 .bit 檔——例如做開機檢查、當展示機——可以完全不裝 Vivado。ボードの検出か、他人が作った .bit の書き込みだけが目的のノート——立ち上げ確認やデモ機——なら、Vivado は丸ごと省ける。Untuk laptop yang hanya perlu mendeteksi papan atau memuat berkas .bit buatan orang lain — pemeriksaan bring-up, mesin demo — kamu bisa melewatkan Vivado sepenuhnya.
Download the Adept 2 Runtime from Digilent, not from AMD — the link is below.下載 Adept 2 Runtime,從 Digilent 拿,不是 AMD——連結在下面。Adept 2 Runtime を AMD ではなく Digilent からダウンロードする——リンクは下にある。Unduh Adept 2 Runtime dari Digilent, bukan dari AMD — tautannya di bawah.
Install the Windows package. It brings the USB/JTAG driver for Digilent boards, the Adept runtime libraries and the command-line utilities, djtgcfg among them.安裝 Windows 版套件。它會裝上 Digilent 板子用的 USB/JTAG 驅動、Adept 執行期函式庫,以及包含 djtgcfg 在內的命令列工具。Windows 用パッケージをインストールする。Digilent ボード用の USB/JTAG ドライバ、Adept ランタイムライブラリ、そして djtgcfg を含むコマンドラインツールが入る。Pasang paket Windows-nya. Ia membawa driver USB/JTAG untuk papan Digilent, pustaka runtime Adept, dan utilitas baris perintah, termasuk djtgcfg.
Verify from a command prompt. A working install answers like this:在命令提示字元裡驗證。裝好的話會這樣回你:コマンドプロンプトから確認する。正しく入っていればこう返ってくる:Verifikasi dari command prompt. Instalasi yang bekerja menjawab seperti ini:
> djtgcfg enum
Found 1 device(s)
Device: ArtyA7
Product Name: Digilent Arty A7 - 35T
User Name: ArtyA7
Serial Number: <serial>
What this path cannot do: synthesise, implement or generate a bitstream — you still need Vivado, or a pre-built .bit, for that — and there is no Hardware Manager GUI. Programming is the command line only:這條路做不到的事:合成、實作、產生 bitstream——這些還是要 Vivado,或是一個做好的 .bit——而且沒有 Hardware Manager 的圖形介面。燒錄只能靠命令列:この方法でできないこと:合成・配置配線・ビットストリーム生成——これには依然 Vivado か、出来合いの .bit が要る——そして Hardware Manager の GUI も無い。書き込みはコマンドラインだけ:Yang tidak bisa dilakukan jalur ini: sintesis, implementasi, atau membangkitkan bitstream — untuk itu kamu tetap butuh Vivado, atau .bit yang sudah jadi — dan tidak ada GUI Hardware Manager. Pemrograman hanya lewat baris perintah:
When it does not work不成功的時候うまくいかないときSaat tidak berhasil
"Unknown device" in Device Manager after plugging in. The cable driver is not bound. Re-run step 3 of Path A as Administrator, then unplug and replug.插上去之後裝置管理員顯示「未知的裝置」。下載線驅動沒綁上。以系統管理員身分重跑路線 A 的第 3 步,然後拔掉重插。接続後にデバイスマネージャーで「不明なデバイス」。ケーブルドライバが結び付いていない。A の手順 3 を管理者として再実行し、抜き差しする。"Unknown device" di Device Manager setelah dicolok. Driver kabel belum terikat. Jalankan ulang langkah 3 Jalur A sebagai Administrator, lalu cabut dan colok kembali.
Vivado shows "localhost Connected" but no hardware target. Almost always a driver-binding problem, not a bad cable or a dead board. Re-running the driver installer as Administrator clears most cases.Vivado 顯示「localhost Connected」,但底下沒有硬體目標。幾乎都是驅動沒綁好,不是線壞了或板子掛了。以系統管理員身分重跑一次驅動安裝程式,大多數情況就解決了。Vivado に「localhost Connected」と出るがハードウェアターゲットが無い。ほぼ確実にドライバの結び付きの問題で、ケーブルやボードの故障ではない。ドライバインストーラを管理者として再実行すればたいてい直る。Vivado menampilkan "localhost Connected" tetapi tidak ada target perangkat keras. Hampir selalu masalah pengikatan driver, bukan kabel rusak atau papan mati. Menjalankan ulang installer driver sebagai Administrator menyelesaikan sebagian besar kasus.
djtgcfg enum finds nothing. Make sure the USB cable carries data — many phone cables are charge-only — and try another port. USB 3.0 hubs have occasionally broken enumeration with older Adept versions; a port on the machine itself is the safer test.djtgcfg enum 什麼都找不到。確認 USB 線能傳資料——很多手機線只能充電——並換一個埠試試。USB 3.0 集線器偶爾會讓舊版 Adept 列舉失敗;直接插機器本體的埠比較保險。djtgcfg enum が何も見つけない。USB ケーブルがデータ対応か確認する——スマホ用ケーブルには充電専用が多い——別のポートも試すこと。USB 3.0 ハブは古い Adept で列挙に失敗することがあるので、本体のポートで試すのが確実。djtgcfg enum tidak menemukan apa pun. Pastikan kabel USB-nya membawa data — banyak kabel ponsel hanya untuk pengisian — dan coba port lain. Hub USB 3.0 kadang merusak enumerasi pada versi Adept yang lebih lama; port di mesin itu sendiri adalah uji yang lebih aman.
The log says windrvr6 is "not installed". Normal on Windows 10 and 11. Current Vivado packages install a pcusb-based driver; windrvr6 belongs to Windows 7-era installs and is expected to be absent.紀錄檔寫 windrvr6「not installed」。在 Windows 10、11 上這是正常的。現行 Vivado 套件裝的是以 pcusb 為基礎的驅動;windrvr6 是 Windows 7 時代的東西,本來就該不存在。ログに windrvr6 が「not installed」と出る。Windows 10/11 では正常。現行の Vivado パッケージは pcusb ベースのドライバを入れる。windrvr6 は Windows 7 時代のもので、無いのが当然。Log mengatakan windrvr6 "not installed". Normal di Windows 10 dan 11. Paket Vivado terkini memasang driver berbasis pcusb; windrvr6 milik instalasi era Windows 7 dan memang diharapkan tidak ada.
Check the board is seen確認板子被偵測到ボード検出の確認Periksa papan terdeteksi
djtgcfg enum
Program a bitstream from the CLI用命令列燒 bitstreamCLI からビットストリーム書き込みProgram bitstream dari CLI
djtgcfg prog -d ArtyA7 -i 0 -f x.bit
How to buy the materials you need要用的材料怎麼買必要な材料の買い方Cara membeli bahan yang kamu butuhkan
The boards and the adapter are lent to you, not given. Everything else on this sheet
you buy yourself, and it is worth doing: one breadboard, a handful of jumper wires and a spare
adapter is the difference between debugging only at the bench and debugging at home at 1 a.m.
In Kaohsiung the place to buy them is 中將電子.
板子和轉接器是借你的,不是給你的。這份工作單上其他東西都要自己買,而且值得買:一塊麵包板、一把杜邦線、一條備用轉接器,決定了你只能在實驗桌上除錯,還是凌晨一點在家也能除錯。在高雄,要買這些就去中將電子。ボードとアダプタは貸与で、譲渡ではない。このシートに出てくるそれ以外のものは自分で買う——買う価値がある。ブレッドボード一枚、ジャンパ線ひと束、予備のアダプタ一本があるかどうかで、研究室の机でしかデバッグできないか、深夜一時に自宅でもできるかが変わる。高雄でそれを買う場所は中將電子だ。Papan dan adapternya dipinjamkan kepadamu, bukan diberikan. Semua yang lain di lembar ini kamu beli sendiri, dan itu sepadan: satu breadboard, segenggam kabel jumper, dan satu adapter cadangan adalah pembeda antara hanya bisa men-debug di meja lab dan bisa men-debug di rumah pada pukul satu pagi. Di Kaohsiung, tempat membelinya adalah 中將電子.
中將電子實業有限公司 has been on 長明街 since August 1977, and in 1993 it pulled out the service
counters and reopened as an open warehouse floor — the largest electronic-parts store in southern
Taiwan. You walk the aisles, take the parts off the shelf yourself, and pay at the front. It is a
short walk from 高雄車站, so from the lab it is 西子灣 → 美麗島 → red line → 高雄車站.
中將電子實業有限公司從 1977 年 8 月就在長明街,1993 年拆掉櫃台,改成開放式大賣場——南台灣最大的電子零件專賣場。你自己走走道、自己從架上拿零件、到前面結帳。它離高雄車站走路就到,所以從實驗室出發是:西子灣 → 美麗島 → 轉紅線 → 高雄車站。中將電子實業有限公司は 1977 年 8 月から長明街にあり、1993 年にカウンターを撤去して開放型の大型売場として開き直した——南台湾で最大の電子部品売場である。自分で通路を歩き、自分で棚から部品を取り、前のレジで払う。高雄車站から歩いてすぐなので、研究室からは 西子灣 → 美麗島 → 紅線 → 高雄車站。中將電子實業有限公司 sudah berada di 長明街 sejak Agustus 1977, dan pada 1993 mereka membongkar meja layanannya lalu dibuka kembali sebagai lantai gudang terbuka — toko komponen elektronik terbesar di Taiwan selatan. Kamu berjalan sendiri di antara rak, mengambil komponennya sendiri, lalu membayar di depan. Jaraknya dekat dengan jalan kaki dari 高雄車站, jadi dari lab: 西子灣 → 美麗島 → jalur merah → 高雄車站.
Read this before you plan a trip around their website. 中將電子 has a web presence
but no web store: no catalogue, no stock levels, no cart. What exists is a Facebook page and a LINE
official account, plus a web66 詢價 page at 1207833627324.web66.tw — that is a contact
form, not a shop. Its trade listing reads 電子器材、電子設備批發 and gives the company address on
建國二路, one street over from the shop floor, so the address you find online is not always the door
you want. The working method is: message the LINE account with a photo of the part or its part
number, ask 有現貨嗎?多少錢?, and go in once they answer. Never conclude from the website
that they do or do not carry something.
在你照著他們的網站安排行程之前,先看這一段。中將電子有網路門面,但沒有網路商店:沒有型錄、沒有庫存數量、沒有購物車。實際存在的是一個 Facebook 粉絲頁、一個 LINE 官方帳號,加上一頁 web66 詢價官網 1207833627324.web66.tw——那是聯絡表單,不是商店。上面的營業項目寫「電子器材、電子設備批發」,登記地址在建國二路,跟賣場只隔一條街,所以你在網路上查到的地址不一定是你要走進去的那個門。正確做法是:用 LINE 傳零件照片或料號過去,問有現貨嗎?多少錢?,等回覆再跑一趟。絕對不要從網站去推論他們有沒有賣某樣東西。サイトを見て予定を立てる前に、ここを読むこと。中將電子はウェブ上の窓口はあるが、ウェブストアは無い:カタログも在庫数も買い物カゴも無い。あるのは Facebook ページと LINE 公式アカウント、それに web66 の見積依頼ページ 1207833627324.web66.tw ——これは問い合わせフォームであって店ではない。営業項目は「電子器材、電子設備批發」、登記住所は売場から一本隣の建國二路になっているので、ネットで出てくる住所が入りたい入口とは限らない。正しい手順はこうだ:LINE に部品の写真か型番を送り、有現貨嗎?多少錢?(在庫はありますか、いくらですか)と聞き、返事が来てから行く。サイトを根拠に取扱いの有無を判断してはいけない。Baca ini sebelum kamu menyusun rencana berdasarkan situs mereka. 中將電子 punya kehadiran di web, tetapi tidak punya toko online: tidak ada katalog, tidak ada jumlah stok, tidak ada keranjang. Yang ada adalah halaman Facebook dan akun resmi LINE, ditambah satu halaman permintaan harga (詢價) di web66, 1207833627324.web66.tw — itu formulir kontak, bukan toko. Kategori usahanya tertulis 電子器材、電子設備批發 dan alamat terdaftarnya di 建國二路, satu jalan dari lantai tokonya, jadi alamat yang kamu temukan online belum tentu pintu yang kamu tuju. Cara kerjanya: kirim foto komponen atau nomor partnya ke akun LINE, tanyakan 有現貨嗎?多少錢? ("ada stok? berapa harganya?"), dan datang setelah mereka menjawab. Jangan pernah menyimpulkan dari situsnya bahwa mereka menjual atau tidak menjual sesuatu.
Ask at the counter in Mandarin or Taiwanese — asking in English will slow you down. The names that get you the
parts on this sheet: 麵包板 (breadboard), 杜邦線 母對母/公對母 (jumper wires, F–F / M–F),
排針 2.54mm (headers), 電阻 220Ω/1kΩ (resistors), LED, 直流減速馬達 (geared DC motor),
馬達驅動模組 L298N/TB6612 (motor driver), SG90 伺服馬達 (servo).
在櫃台用國語或台語問——用英文只會拖慢你。能換到這份工作單上零件的名字:麵包板、杜邦線 母對母/公對母、排針 2.54mm、電阻 220Ω/1kΩ、LED、直流減速馬達、馬達驅動模組 L298N/TB6612、SG90 伺服馬達。レジでは中国語(華語)か台湾語で聞くこと——英語で聞くと話が遅くなる。このシートの部品にたどり着く名前:麵包板(ブレッドボード)、杜邦線 母對母/公對母(ジャンパ線 メス–メス/オス–メス)、排針 2.54mm(ピンヘッダ)、電阻 220Ω/1kΩ(抵抗)、LED、直流減速馬達(ギヤード DC モータ)、馬達驅動模組 L298N/TB6612(モータドライバ)、SG90 伺服馬達(サーボ)。Tanyakan di kasir dalam bahasa Mandarin atau Hokkien Taiwan — bertanya dalam bahasa Inggris hanya memperlambatmu. Nama-nama yang akan membawamu ke komponen di lembar ini: 麵包板 (breadboard), 杜邦線 母對母/公對母 (kabel jumper F–F / M–F), 排針 2.54mm (pin header), 電阻 220Ω/1kΩ (resistor), LED, 直流減速馬達 (motor DC bergigi), 馬達驅動模組 L298N/TB6612 (driver motor), SG90 伺服馬達 (servo).
What the invoice is actually for. You are not meant to end up carrying the cost of
lab materials yourself — it is paid back to you out of the lab's research budget at the university,
and the invoice is the one document that lets that happen. The accounting office reimburses against a
三聯式 uniform invoice made out to the university itself — 國立中山大學,
統一編號 76211194 — because only that can be entered in the books as a university
purchase. A 二聯式 invoice or a plain 收據 is issued to you, so there is nothing for the
school to reimburse and the cost stays yours. So at the counter, before they ring it up, say
要開三聯式發票 and give that 統編; a swap afterwards is a favour, not a right. Hand the
invoice to me together with the part — a lost invoice is an unreimbursed purchase — and clear the
purchase with me before you spend, not after, because the budget has to have room for it first.
發票到底是拿來做什麼的。實驗室材料費不該由你自己吸收——這筆錢會從學校的實驗室研究經費核銷回來給你,而發票就是唯一能讓這件事成立的憑證。會計室是憑三聯式統一發票報帳,而且發票要開給學校本身——國立中山大學,統一編號 76211194——因為只有這樣,帳上才記得成一筆學校的採購。二聯式發票或收據是開給你的,學校沒有東西可以核銷,這筆錢就變成你自己出。所以在櫃台結帳之前就要說「要開三聯式發票」,並把統編給他;事後想換是人情,不是你的權利。發票請跟零件一起交給我——發票掉了,這筆就報不了——而且要在花錢之前跟我說,不是花完才說,因為經費要先有空間。發票は何のためにあるのか。研究室の材料費を最後まで自分で負担する筋合いはない——この費用は大学にある研究室の研究費から精算されて戻ってくるし、發票はそれを成立させる唯一の証憑だ。会計課が精算に使うのは三聯式の統一發票で、宛先は大学そのもの——國立中山大學、統一編號 76211194——でなければならない。そう書かれて初めて、帳簿上「大学の購入」として記録できるからだ。二聯式の發票や收據はあなた宛なので、大学には精算する対象が無く、費用はあなたの負担のままになる。だからレジを通す前に「要開三聯式發票」と言い、その統一編號を伝えること。後から差し替えてもらうのは好意であって権利ではない。發票は部品と一緒に私に渡すこと——發票を失くせば、その分は精算できない——そして使った後ではなく、使う前に私に確認すること。先に予算の枠が必要だからだ。Untuk apa sebenarnya fakturnya. Kamu tidak seharusnya akhirnya menanggung sendiri biaya bahan lab — biaya itu dibayarkan kembali kepadamu dari anggaran riset lab di universitas, dan faktur adalah satu-satunya dokumen yang memungkinkan hal itu. Bagian keuangan mengganti biaya berdasarkan faktur resmi 三聯式 yang dibuat atas nama universitas itu sendiri — 國立中山大學, 統一編號 76211194 — karena hanya itu yang bisa dicatat dalam pembukuan sebagai pembelian universitas. Faktur 二聯式 atau 收據 biasa diterbitkan atas nama kamu, jadi tidak ada yang bisa diganti oleh kampus dan biayanya tetap menjadi bebanmu. Maka di kasir, sebelum mereka menghitung, katakan 要開三聯式發票 dan berikan 統一編號 itu; menukarnya belakangan adalah kebaikan hati mereka, bukan hakmu. Serahkan fakturnya kepada saya bersama komponennya — faktur yang hilang berarti pembelian yang tidak diganti — dan bicarakan dulu dengan saya sebelum belanja, bukan sesudahnya, karena anggarannya harus punya ruang lebih dahulu.
Shop floor賣場売場Lantai toko
高雄市三民區長明街 247 號
Phone電話電話Telepon
07-235-4786
Hours營業時間営業時間Jam buka
09:00 – 21:30
From the lab從實驗室出發研究室からDari lab
西子灣 → 美麗島 → 高雄車站
Online cart線上購物車オンラインカートKeranjang online
none — LINE, or walk in沒有 —— 用 LINE,或直接走進去無し — LINE か店頭tidak ada — LINE, atau datang langsung
Invoice to發票開給發票の宛先Faktur atas nama
三聯式 · 國立中山大學 · 統編 76211194
Seller, registered as賣方登記名稱売主の登記名Penjual, terdaftar sebagai
中將電子實業有限公司 · 統編 86900206
How to hand it in — all three parts, every task怎麼交 —— 每一題都要三樣提出方法 — 各課題につき 3 点すべてCara mengumpulkannya — ketiga bagian, untuk setiap tugas
A testbench. Simulate the module and show the waveform that proves the
behaviour — the exact signals and the exact moment named in that task's
Done when list, not a screenshot of the whole run.
一個 testbench。模擬你的模組,並秀出能證明行為的波形——要正好是該題完成條件裡點名的訊號與時間點,不是整段模擬的截圖。testbench。モジュールをシミュレーションし、動作を証明する波形を示すこと——その課題の完了条件で名指しされた信号とその瞬間であって、実行全体のスクリーンショットではない。Sebuah testbench. Simulasikan modulnya dan tunjukkan bentuk gelombang yang membuktikan perilakunya — sinyal yang tepat dan saat yang tepat seperti disebut pada daftar Selesai bila tugas itu, bukan tangkapan layar seluruh simulasi.
A video on YouTube. Record the hardware doing it, upload it (unlisted is
fine) and hand in the link. A simulation that passes while the board does nothing is not
a finished task.
一支 YouTube 影片。拍下硬體實際運作,上傳(設不公開即可),把連結交上來。模擬過了但板子沒動,不算做完。YouTube の動画。ハードウェアが実際に動いている様子を撮影してアップロードし(限定公開で可)、リンクを提出する。シミュレーションが通ってもボードが動かなければ課題は完了ではない。Sebuah video di YouTube. Rekam perangkat kerasnya saat bekerja, unggah (unlisted tidak masalah) dan kumpulkan tautannya. Simulasi yang lolos sementara papannya diam bukanlah tugas yang selesai.
A live demo. If I am in the lab, run it on your own host and walk me
through it there. If I am not, make an appointment and demo it over Google Meet with your
screen shared — same thing, same questions.
一次現場展示。我人在實驗室的話,就用你自己的電腦跑給我看,當場講解。我不在的話,跟我約時間,用 Google Meet 分享螢幕展示——一樣的流程,一樣會問問題。ライブデモ。私が研究室にいるときは、自分のホストで動かして目の前で説明すること。いないときはアポイントを取り、Google Meet で画面共有してデモする——内容も質問も同じ。Demo langsung. Kalau saya ada di lab, jalankan di host-mu sendiri dan jelaskan langsung di sana. Kalau saya tidak ada, buat janji dan demokan lewat Google Meet dengan layar dibagikan — sama saja, pertanyaannya juga sama.
8 pts分点poin1FIRST LIGHT
Count on the LEDs, and watch it wrap用 LED 數數,並看著它繞回 0LED でカウントし、ラップするのを見るMencacah di LED, dan mengamati saat ia berputar kembali
Verilog
Counter
Clock enable
Pin constraints
“use the led on dev. board to show the output of counter and wrap”
↳ added as the warm-up
The first thing that has to work: a bitstream on the board, pins assigned correctly, and
something moving. Run a free counter, put it on the LEDs, and make the wrap from 255 back
to 0 visible as its own event rather than something you infer.
第一件必須成功的事:bitstream 燒進板子、腳位指定正確、而且看得到東西在動。跑一個自由計數器,把它接到 LED 上,並讓 255 繞回 0 這件事本身變成看得見的事件,而不是用推的。最初に動かなければならないもの:ボードに書き込まれたビットストリーム、正しく割り当てられたピン、そして何かが動いていること。フリーランのカウンタを走らせて LED に出し、255 から 0 へのラップを推測ではなく目に見えるイベントにする。Hal pertama yang harus jalan: bitstream di papan, pin yang ditetapkan dengan benar, dan sesuatu yang bergerak. Jalankan pencacah bebas, tampilkan di LED, dan buat perputaran dari 255 kembali ke 0 terlihat sebagai kejadian tersendiri, bukan sesuatu yang hanya kamu simpulkan.
50 MHz is far too fast to watch, so the counter does not run on every clock — it runs on a
tick. One clock, one enable: that habit is the reason this task comes before
everything else.
50 MHz 快到根本看不見,所以計數器不是每個時脈都走——它是靠 tick 走。單一時脈、單一 enable:這個習慣就是這題排在最前面的理由。50 MHz は速すぎて見えないので、カウンタは毎クロックではなく tick で進む。クロックは一つ、イネーブルは一つ——この習慣こそ、この課題が最初に来る理由だ。50 MHz jauh terlalu cepat untuk diamati, jadi pencacahnya tidak berjalan pada setiap clock — ia berjalan pada sebuah tick. Satu clock, satu enable: kebiasaan itulah alasan tugas ini datang sebelum yang lain.
// one clock, one enable — never a counter bit as a clock
wire tick = (pre == DIV-1); // 0.5 Hz
if (tick) cnt <= cnt + 1'b1; // 8-bit, wraps by itself
Target numbers目標數字目標値Angka target
Tick ratetick 頻率tick レートLaju tick
0.5 Hz → 1 count / 2 s
Prescale divisor前置除數プリスケール分周値Pembagi prescale
50e6 / 0.5 = 100,000,000
Prescaler width前置計數器位寬プリスケーラ幅Lebar prescaler
27 bits (2^27 > 1e8)
Counter
8 bits → 256 states
Wrap period繞回週期ラップ周期Periode perputaran
512 s = 8 min 32 s
Wrap flash繞回閃燈ラップ点灯Kedip saat berputar
1 tick = 2 s
Traps陷阱落とし穴Jebakan
Never write always @(posedge cnt[24]). A counter bit used as a clock is a ripple clock: it works on the bench, and it makes every timing report after it meaningless. Use a clock enable.絕對不要寫 always @(posedge cnt[24])。把計數器的某個位元拿來當時脈就是 ripple clock:在桌上會動,但之後每一份 timing report 都失去意義。請改用 clock enable。always @(posedge cnt[24]) と書いてはいけない。カウンタのビットをクロックに使うのはリップルクロックで、机の上では動くがそれ以降のタイミングレポートをすべて無意味にする。クロックイネーブルを使うこと。Jangan pernah menulis always @(posedge cnt[24]). Bit pencacah yang dipakai sebagai clock adalah ripple clock: ia jalan di meja praktik, dan membuat setiap laporan timing setelahnya tidak bermakna. Pakai clock enable.
Most boards wire LEDs active low. All eight stuck on usually means a missing ~, not a dead board.多數板子的 LED 是低電位點亮。八顆全亮通常是少了一個 ~,不是板子壞了。多くのボードで LED はアクティブロー配線。8 個とも点きっぱなしなら、たいていはボードの故障ではなく ~ の書き忘れ。Kebanyakan papan memasang LED secara active low. Kedelapan LED yang menyala terus biasanya berarti ada ~ yang hilang, bukan papan yang mati.
The carry-out is one clock wide — 20 ns. Stretch it to a full tick or you will never see the wrap.進位輸出只有一個時脈寬——20 ns。把它拉長成一整個 tick,否則你永遠看不到繞回。キャリーアウトは 1 クロック幅、つまり 20 ns。1 tick 分に伸ばさなければラップは絶対に見えない。Carry-out hanya selebar satu clock — 20 ns. Regangkan menjadi satu tick penuh atau kamu tidak akan pernah melihat perputarannya.
No pin assignment, no light. Quartus wants a .qsf location and I/O standard per pin; Vivado wants the same pair in an .xdc.沒有指定腳位就沒有燈。Quartus 需要在 .qsf 裡給每支腳位置與 I/O standard;Vivado 則是在 .xdc 裡寫同樣兩項。ピン割り当てが無ければ光らない。Quartus は .qsf にピンごとの位置と I/O 規格を要求し、Vivado は同じ二つを .xdc に要求する。Tanpa penetapan pin, tidak ada cahaya. Quartus meminta lokasi .qsf dan standar I/O per pin; Vivado meminta pasangan yang sama di dalam .xdc.
Give it a reset and use it. An uninitialised counter starts wherever the fabric powers up, which makes "it starts at a weird number" your first wasted afternoon.給它一個 reset,而且真的要用。沒初始化的計數器會從上電當下的任意值開始,「怎麼從奇怪的數字開始」會是你第一個浪費掉的下午。リセットを用意し、実際に使うこと。初期化されていないカウンタは電源投入時の値から始まり、「変な数字から始まる」で最初の午後を丸ごと潰すことになる。Beri ia reset dan gunakan. Pencacah yang tidak diinisialisasi mulai dari nilai apa pun yang muncul saat fabric menyala, dan itulah yang membuat "kok mulainya dari angka aneh" menjadi sore pertama yang kamu buang percuma.
Done when完成條件完了条件Selesai bila
Reference answer — not released yet參考解答 —— 尚未開放参考解答 — まだ公開されていませんJawaban acuan — belum dirilis
Reference answer參考解答参考解答Jawaban acuan
module led_counter #(parameter DIV = 100_000_000) // 0.5 Hz at 50 MHz
(input clk, input rst_n, output [7:0] led, output wrap_led);
reg [26:0] pre;
reg [7:0] cnt;
reg wrap_q;
wire tick = (pre == DIV-1);
always @(posedge clk or negedge rst_n)
if (!rst_n) begin
pre <= 27'd0; cnt <= 8'd0; wrap_q <= 1'b0;
end else begin
pre <= tick ? 27'd0 : pre + 1'b1;
if (tick) begin
cnt <= cnt + 1'b1; // 255 + 1 wraps to 0
wrap_q <= (cnt == 8'hFF); // hold the carry for one whole tick
end
end
assign led = ~cnt; // active-low board LEDs
assign wrap_led = ~wrap_q;
endmodule
wrap_q is the whole trick: the carry-out itself lasts 20 ns, but latching
it at the tick holds it for the next two seconds, which is long enough to film.
wrap_q 就是整個訣竅:進位本身只有 20 ns,但在 tick 上把它鎖住,就能維持接下來的兩秒——足夠拍進影片。wrap_q が肝心な仕掛け:キャリー自体は 20 ns しかないが、tick でラッチすれば次の 2 秒間保持され、撮影できる長さになる。wrap_q adalah inti triknya: carry-out itu sendiri hanya bertahan 20 ns, tetapi menguncinya pada tick menahannya selama dua detik berikutnya, cukup lama untuk direkam.
Pins are board-specific — read your board's schematic and substitute:腳位因板子而異——請看你板子的電路圖再代入:ピンはボードごとに異なる——手元のボードの回路図を見て置き換えること:Pin bergantung pada papan — baca skematik papanmu lalu sesuaikan:
# Quartus, in the .qsf
set_location_assignment PIN_A8 -to led[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to led[0]
# Vivado, in the .xdc
set_property -dict {PACKAGE_PIN U16 IOSTANDARD LVCMOS33} [get_ports {led[0]}]
At 0.5 Hz a full 256-count wrap takes 8 minutes 32 seconds, which is nobody's idea of a
video. Drop DIV to 5,000,000 for the hand-in clip — 10 Hz, whole cycle in
25.6 s — and put it back afterwards. That one parameter is the only thing separating
"too fast to see" from "too slow to sit through", and changing it touches no logic.
在 0.5 Hz 下,數完 256 次要 8 分 32 秒,沒有人想看這種影片。交件影片就把 DIV 降到 5,000,000——10 Hz,整圈 25.6 秒——拍完再改回來。「快到看不見」和「慢到坐不住」之間就差這一個參數,而改它完全不動到邏輯。0.5 Hz では 256 カウント一周に 8 分 32 秒かかり、動画としては誰も見たくない。提出用のクリップでは DIV を 5,000,000 に下げ——10 Hz、一周 25.6 秒——撮り終えたら戻す。「速すぎて見えない」と「遅すぎて見ていられない」を分けるのはこのパラメータ一つだけで、変更してもロジックには一切触れない。Pada 0.5 Hz, satu perputaran penuh 256 hitungan memakan 8 menit 32 detik, dan itu bukan video yang mau ditonton siapa pun. Turunkan DIV menjadi 5,000,000 untuk klip yang dikumpulkan — 10 Hz, satu siklus penuh dalam 25.6 s — lalu kembalikan sesudahnya. Satu parameter itulah satu-satunya yang memisahkan "terlalu cepat untuk dilihat" dari "terlalu lambat untuk ditunggu", dan mengubahnya tidak menyentuh logika sama sekali.
12 pts分点poin2CONCURRENCY
Two FSMs, one clock, no stalls兩個 FSM、同一時脈、不停頓二つの FSM、一つのクロック、停滞なしDua FSM, satu clock, tanpa macet
Verilog
FSM
Handshake
Testbench
“multi-fsm running at same time (e.g. uart serialize & uart buffer allocater)”
Write the transmitter as two independent state machines that run every clock edge
and talk only through a handshake — never through a shared variable. The serializer owns
the bit timing; the allocator owns which byte comes next. Both live in their own
always block; neither one waits for the other to finish a whole byte.
把發送端寫成兩個各自獨立、每個時脈邊緣都在跑的狀態機,彼此只透過 handshake 溝通——絕不共用變數。serializer 負責位元時序,allocator 負責決定下一個 byte。兩者各自待在自己的 always 區塊裡;誰都不必等對方把一整個 byte 做完。送信側は二つの独立したステートマシンとして書く。どちらも毎クロックエッジで動き、やり取りはハンドシェイクのみ——共有変数は使わない。シリアライザはビットタイミングを、アロケータは次のバイトを担当する。それぞれ自分の always ブロックに置き、相手が 1 バイトを終えるのを待たない。Tulis pemancarnya sebagai dua mesin keadaan mandiri yang berjalan pada setiap tepi clock dan hanya berbicara lewat handshake — jangan pernah lewat variabel bersama. Serializer memegang pewaktuan bit; alokator memegang byte mana yang menyusul. Keduanya hidup di blok always masing-masing; tidak satu pun menunggu yang lain menyelesaikan satu byte penuh.
// allocator → serializer, one byte per handshake
tx_valid // allocator: this byte is real
tx_ready // serializer: I latched it, give me the next
tx_data[7:0]
// transfer happens on the edge where both are high
Bits per frame每個 frame 的位元數1 フレームのビット数Bit per frame
10 (1+8+1)
Ring buffer環形緩衝區リングバッファRing buffer
16 B, wrapping wr/rd ptr
Traps陷阱落とし穴Jebakan
One always @(posedge clk) block per FSM. Two blocks driving the same reg is a compile error waiting for you.每個 FSM 一個 always @(posedge clk) 區塊。兩個區塊去驅動同一個 reg,等著吃編譯錯誤。FSM ごとに always @(posedge clk) ブロックを一つ。二つのブロックで同じ reg を駆動すればコンパイルエラーが待っている。Satu blok always @(posedge clk) untuk tiap FSM. Dua blok yang menggerakkan reg yang sama adalah galat kompilasi yang sedang menunggumu.
The allocator must handle full and empty as distinct states — an equal read and write pointer means both unless you keep a count.allocator 必須把滿和空當成兩種不同狀態——讀寫指標相等時兩者都成立,除非你另外記一個計數。アロケータはフルとエンプティを別の状態として扱う必要がある——読み書きポインタが等しいだけでは両方を意味するので、カウントを別に持つこと。Alokator harus memperlakukan penuh dan kosong sebagai keadaan yang berbeda — pointer baca dan tulis yang sama nilainya berarti keduanya, kecuali kamu menyimpan pencacah.
Register the outputs. Combinational tx straight off the state decoder will glitch.輸出要打一級暫存器。直接從狀態解碼拉出來的組合邏輯 tx 會有毛刺。出力はレジスタで受けること。ステートデコーダから直接出した組み合わせ論理の tx はグリッチする。Registerkan keluarannya. tx kombinasional langsung dari dekoder keadaan akan menghasilkan glitch.
Done when完成條件完了条件Selesai bila
Reference answer — not released yet參考解答 —— 尚未開放参考解答 — まだ公開されていませんJawaban acuan — belum dirilis
Reference answer參考解答参考解答Jawaban acuan
Serializer — the shift register carries its own framing, so the FSM only counts bits:serializer——移位暫存器自己帶著框架,所以 FSM 只需要數位元:シリアライザ——シフトレジスタ自身がフレーミングを持つので、FSM はビットを数えるだけ:Serializer — shift register membawa framing-nya sendiri, jadi FSM cukup mencacah bit:
localparam DIV = 434;
reg [9:0] sh; reg [8:0] baud; reg [3:0] bit_i; reg st;
always @(posedge clk or negedge rst_n)
if (!rst_n) begin st <= 0; tx <= 1'b1; end
else if (!st) begin
if (tx_valid) begin
sh <= {1'b1, tx_data, 1'b0}; // stop | data | start
bit_i <= 0; baud <= 0; st <= 1;
end
end else begin
tx <= sh[0]; // drive the current bit
if (baud == DIV-1) begin
baud <= 0;
sh <= {1'b1, sh[9:1]}; // shift in idle-high
bit_i <= bit_i + 1'b1;
if (bit_i == 4'd9) st <= 0; // 10th bit sent
end else baud <= baud + 1'b1;
end
assign tx_ready = ~st;
Allocator — one extra pointer bit is what separates full from empty:allocator——多一個指標位元,就能分辨滿和空:アロケータ——ポインタを 1 ビット増やすだけでフルとエンプティが区別できる:Alokator — satu bit pointer tambahan itulah yang memisahkan penuh dari kosong:
reg [7:0] mem [0:15];
reg [4:0] wr, rd; // 5 bits for 16 slots
wire full = (wr[3:0] == rd[3:0]) && (wr[4] != rd[4]);
wire empty = (wr == rd);
always @(posedge clk) begin
if (push && !full) begin mem[wr[3:0]] <= din; wr <= wr + 1'b1; end
if (tx_valid && tx_ready) rd <= rd + 1'b1;
end
assign tx_valid = ~empty;
assign tx_data = mem[rd[3:0]];
assign can_push = ~full; // refuse, never drop
The serializer never reads wr/rd and the allocator never reads
baud. That is the whole point of the exercise: the only wires between them
are valid, ready and data.
serializer 從不去讀 wr/rd,allocator 也從不去讀 baud。這就是這題的重點:兩者之間只有 valid、ready、data 這三條線。シリアライザは wr/rd を読まず、アロケータは baud を読まない。それがこの課題の要点で、両者をつなぐ線は valid、ready、data だけ。Serializer tidak pernah membaca wr/rd dan alokator tidak pernah membaca baud. Itulah inti latihan ini: satu-satunya kabel di antara keduanya adalah valid, ready dan data.
15 pts分点poin3LOOPBACK
LabVIEW writes, the FPGA echoes it backLabVIEW 送出,FPGA 原封回傳LabVIEW が送り、FPGA がそのまま返すLabVIEW menulis, FPGA menggemakannya kembali
UART RX
Synchronizer
VISA
“Use labview to send data to rx of uart on FPGA and FPGA echo the data back to labview”
Now build the receiver and wire it straight into the transmitter from task 2. The whole
design is a wire with a clock in the middle: whatever the host writes, it should read back
byte-identical. This is the test rig you will reuse for everything after it.
現在做接收端,並直接接到第 2 題的發送端。整個設計就是一條中間夾了時脈的線:主機寫什麼,就該原樣讀回什麼。這是你後面每一題都會重複用到的測試平台。次に受信側を作り、課題 2 の送信側へ直結する。設計全体は真ん中にクロックが入った一本の線で、ホストが書いた内容がそのまま読み戻せるはず。これ以降ずっと使い回すテスト治具になる。Sekarang bangun penerimanya dan sambungkan langsung ke pemancar dari tugas 2. Seluruh rancangannya adalah sehelai kabel dengan clock di tengahnya: apa pun yang ditulis host, harus terbaca kembali identik byte demi byte. Inilah perangkat uji yang akan kamu pakai lagi untuk semua yang berikutnya.
On the LabVIEW side: VISA Configure Serial Port → VISA Write →
VISA Read → VISA Close, with the read byte count wired from
Bytes at Port rather than a guess.
LabVIEW 這邊:VISA Configure Serial Port → VISA Write → VISA Read → VISA Close,讀取的 byte 數要從 Bytes at Port 接過來,不要用猜的。LabVIEW 側は VISA Configure Serial Port → VISA Write → VISA Read → VISA Close。読み取りバイト数は当て推量ではなく Bytes at Port から配線する。Di sisi LabVIEW: VISA Configure Serial Port → VISA Write → VISA Read → VISA Close, dengan jumlah byte yang dibaca disambungkan dari Bytes at Port, bukan dari tebakan.
Target numbers目標數字目標値Angka target
Oversampling過取樣オーバーサンプリングOversampling
16× per bit
Tick divisortick 除數tick 分周値Pembagi tick
50e6/(115200·16) ≈ 27
Sample point取樣點サンプリング点Titik pencuplikan
tick 8 of 16 (mid-bit)
Input sync輸入同步入力同期Sinkronisasi masukan
2 flip-flops on rx
Soak test長時間測試ソークテストUji rendam
1000 random bytes, 0 mismatches
Traps陷阱落とし穴Jebakan
The rx pin is asynchronous. Two flip-flops before it touches any FSM, or you will chase a bug that only appears once an hour.rx 腳是非同步訊號。在它碰到任何 FSM 之前先過兩級正反器,否則你會去追一個一小時才出現一次的 bug。rx ピンは非同期。FSM に触れる前にフリップフロップ 2 段を通すこと。さもないと 1 時間に 1 度しか出ないバグを追うことになる。Pin rx bersifat asinkron. Dua flip-flop sebelum ia menyentuh FSM mana pun, atau kamu akan mengejar bug yang hanya muncul sekali sejam.
Re-check the start bit at mid-bit and abort if it went high — that is your noise rejection.在位元中央再確認一次 start bit,如果變成高電位就中止——這就是你的雜訊排除。ビット中央でスタートビットを再確認し、ハイになっていれば中止する——これがノイズ除去になる。Periksa ulang start bit di tengah bit dan batalkan kalau ternyata sudah naik — itulah penolakan derau milikmu.
Flow control off, and confirm both ends agree on 8N1. Half the "corrupted echo" reports are a parity mismatch.關掉流量控制,並確認兩端都設 8N1。所謂「回傳資料壞掉」有一半是 parity 設定不一致。フロー制御はオフ、両端が 8N1 で一致していることを確認する。「エコーが壊れる」という報告の半分はパリティの不一致。Flow control mati, dan pastikan kedua ujung sepakat pada 8N1. Separuh laporan "gema rusak" sebenarnya adalah ketidakcocokan paritas.
Echoing at the same baud you receive means zero headroom. Keep the FIFO from task 2 in the path.用跟接收相同的 baud 回傳等於毫無餘裕。把第 2 題的 FIFO 留在路徑上。受信と同じ baud で返すと余裕がゼロになる。課題 2 の FIFO を経路に残しておくこと。Menggemakan pada baud yang sama dengan yang kamu terima berarti nol ruang lega. Pertahankan FIFO dari tugas 2 tetap di jalurnya.
Done when完成條件完了条件Selesai bila
Reference answer — not released yet參考解答 —— 尚未開放参考解答 — まだ公開されていませんJawaban acuan — belum dirilis
Reference answer參考解答参考解答Jawaban acuan
Receiver, 16× oversampled. tick is 4 bits so it wraps once per bit for free:接收端,16 倍過取樣。tick 是 4 位元,所以它剛好每個位元自動繞回一次:受信側、16 倍オーバーサンプリング。tick は 4 ビットなので、1 ビットごとに自然にラップする:Penerima, dengan oversampling 16×. tick selebar 4 bit sehingga ia berputar sekali per bit dengan sendirinya:
reg [1:0] sync;
always @(posedge clk) sync <= {sync[0], rx_pin}; // 2-FF synchronizer
wire rx_s = sync[1];
localparam OS = 27; // 50e6 / (115200*16)
reg [4:0] os; reg [3:0] tick, bit_i; reg [7:0] sh; reg busy;
always @(posedge clk) begin
rx_valid <= 1'b0; // one-cycle strobe
if (!busy) begin
if (!rx_s) begin busy <= 1'b1; os <= 0; tick <= 0; bit_i <= 0; end
end else if (os == OS-1) begin
os <= 0;
tick <= tick + 1'b1;
if (tick == 4'd7) begin // mid-bit
if (bit_i == 4'd0) begin if (rx_s) busy <= 1'b0; end // false start
else if (bit_i <= 4'd8) sh <= {rx_s, sh[7:1]}; // LSB first
else begin rx_data <= sh; rx_valid <= 1'b1; busy <= 1'b0; end
end
if (tick == 4'd15) bit_i <= bit_i + 1'b1;
end else os <= os + 1'b1;
end
The echo is then one line — the receiver strobe becomes the FIFO push from task 2:回傳就只是一行——接收端的 strobe 直接當成第 2 題 FIFO 的 push:エコーは 1 行で済む——受信ストローブがそのまま課題 2 の FIFO への push になる:Gemanya lalu hanya satu baris — strobe penerima menjadi dorongan masuk FIFO dari tugas 2:
assign push = rx_valid;
assign din = rx_data;
Nothing else connects the two halves. Because the FIFO absorbs the burst, a 64-byte
write from the host drains at line rate without a single dropped byte.
兩半之間沒有別的連線。因為 FIFO 吸收了突發,主機寫入的 64 byte 會以線路速率排出,一個 byte 都不會掉。二つの半分をつなぐものは他に無い。FIFO がバーストを吸収するので、ホストからの 64 バイト書き込みは回線速度で掃け、1 バイトも落ちない。Tidak ada lagi yang menghubungkan kedua bagian itu. Karena FIFO menyerap burst-nya, penulisan 64 byte dari host mengalir keluar pada laju saluran tanpa satu byte pun hilang.
18 pts分点poin4FIXED POINT
A single-pole low-pass filter in Q format用 Q format 做單極點低通濾波器Q フォーマットによる 1 次ローパスフィルタTapis lolos-rendah kutub tunggal dalam format Q
IIR
Q format
Saturation
Host主機端ホスト側Sisi host
“fast low pass filter (for fixed point operation practice) with labview”
Integers only — no float, no double, anywhere in the loop. Every value is a Q-format
number: a plain integer whose binary point you track in your head, not in the machine.
The point is not the filter, it is knowing where that point sits after every multiply and
what happens at the edges of the word.
整數,只有整數——迴圈裡不准有 float、不准有 double。每個值都是 Q format 數字:本質上就是整數,小數點位置由你自己記在腦子裡,而不是交給機器。重點不是濾波器,而是每次乘法之後那個小數點跑到哪裡,以及字組邊界會發生什麼事。整数のみ——ループ内に float も double も置かない。すべての値は Q フォーマットの数、つまり小数点の位置を機械ではなく自分の頭で管理する普通の整数だ。要点はフィルタではなく、掛け算のたびに小数点がどこへ動くか、そしてワードの端で何が起きるかを知ることにある。Bilangan bulat saja — tanpa float, tanpa double, di mana pun dalam loop. Setiap nilai adalah bilangan format Q: bilangan bulat biasa yang titik binernya kamu lacak di kepalamu, bukan di mesin. Intinya bukan tapisnya, melainkan mengetahui di mana titik itu berada setelah setiap perkalian dan apa yang terjadi di tepi word.
// y[n] = y[n-1] + a·(x[n] - y[n-1]), 15 fraction bits
err = x - y // I16, may overflow → saturate
acc = a * err // I32, 30 fraction bits
y = y + (acc >> 15) // shift back to 15
The coefficient is picked once, away from the bench, and enters the code as the integer
3869 — that is a 20 Hz corner at 1 kHz, scaled by 215. Nothing in the running
loop ever sees a fraction.
係數只在離開實驗桌時算一次,進到程式裡就是整數 3869——那是 1 kHz 取樣下 20 Hz 轉角頻率乘以 215 的結果。執行中的迴圈從頭到尾看不到任何分數。係数は机の外で一度だけ決め、コードには整数 3869 として入る——1 kHz サンプリングでの 20 Hz カットオフを 215 倍した値だ。実行中のループが小数を見ることは一度もない。Koefisiennya dipilih sekali, jauh dari meja praktik, dan masuk ke kode sebagai bilangan bulat 3869 — itu adalah sudut 20 Hz pada 1 kHz, diskalakan dengan 215. Tidak ada satu pun bagian loop berjalan yang pernah melihat pecahan.
Target numbers目標數字目標値Angka target
Sample rate取樣率サンプリングレートLaju cuplik
1 kHz
Cutoff截止頻率カットオフFrekuensi potong
20 Hz
Format格式フォーマットFormat
16-bit Q, 15 frac bits
α as an integerα 的整數值整数としての αα sebagai bilangan bulat
>> 15 on a negative number truncates toward −∞. Add the rounding term (1<<14) before shifting, or your output drifts down.對負數做 >> 15 會往 −∞ truncate。移位前先加上四捨五入項 (1<<14),否則輸出會一路往下漂。負数に対する >> 15 は −∞ 方向に切り捨てられる。シフト前に丸め項 (1<<14) を足さないと出力が下へドリフトする。>> 15 pada bilangan negatif memotong ke arah −∞. Tambahkan suku pembulatan (1<<14) sebelum menggeser, atau keluaranmu akan melorot turun.
Saturate x − y; do not let it wrap. A wrap turns a smooth step into a spike.把 x − y 做飽和處理,不要讓它 wrap。一旦 wrap,平滑的步階就會變成尖刺。x − y は飽和させ、ラップさせないこと。ラップすると滑らかなステップがスパイクに化ける。Jenuhkan x − y; jangan biarkan ia berputar. Perputaran mengubah step yang mulus menjadi lonjakan.
With a small α the increment can round to zero — the output parks a few LSB short of the input and stays there. That limit cycle is expected; measure it, do not patch it away with a float.α 很小時,增量會被四捨五入成零——輸出會停在離輸入差幾個 LSB 的地方不動。這個極限環是預期中的現象;把它量出來,不要用浮點數把它蓋掉。α が小さいと増分がゼロに丸められ、出力は入力より数 LSB 手前で止まったままになる。このリミットサイクルは想定内であり、測定すべきもので、float で誤魔化すものではない。Dengan α yang kecil, penambahnya bisa membulat menjadi nol — keluarannya berhenti beberapa LSB di bawah masukan dan diam di situ. Siklus batas itu memang diharapkan; ukurlah, jangan ditambal dengan float.
Force the wire/array types (I16, I32) explicitly. Leave it to coercion and you get doubles without noticing.明確指定接線/陣列型別(I16、I32)。放著讓它自動轉型,你會在不知不覺中拿到 double。配線や配列の型(I16、I32)は明示的に指定する。暗黙変換に任せると、気づかないうちに double になる。Paksakan tipe wire/array (I16, I32) secara eksplisit. Serahkan pada koersi dan kamu akan mendapat double tanpa menyadarinya.
Done when完成條件完了条件Selesai bila
Reference answer — not released yet參考解答 —— 尚未開放参考解答 — まだ公開されていませんJawaban acuan — belum dirilis
Reference answer參考解答参考解答Jawaban acuan
The whole filter, integers only. Python's >> floors toward −∞ exactly like an arithmetic shift in hardware, so this is bit-identical to the Verilog you would write:整個濾波器,全整數。Python 的 >> 跟硬體的算術移位一樣是往 −∞ 取整,所以這段跟你會寫的 Verilog 逐位元相同:フィルタ全体、整数のみ。Python の >> はハードウェアの算術シフトと同じく −∞ 方向に丸めるので、書くことになる Verilog とビット単位で一致する:Seluruh tapisnya, bilangan bulat saja. Operator >> pada Python membulatkan ke bawah menuju −∞ persis seperti pergeseran aritmetika di perangkat keras, jadi ini identik bit demi bit dengan Verilog yang akan kamu tulis:
A = 3869 # alpha, 15 fraction bits
def sat16(v):
return -32768 if v < -32768 else (32767 if v > 32767 else v)
def step(x, y): # one sample, both Q-format counts
err = sat16(x - y) # never let this wrap
return sat16(y + ((A * err + (1 << 14)) >> 15))
Verify it against integers you worked out yourself, never against a float model. A
+16384 step gives, term by term:
拿你自己算出來的整數去驗證,絕不要拿浮點模型。+16384 的步階,一項一項是:検証は自分で計算した整数に対して行い、float モデルとは比べない。+16384 のステップは順に:Verifikasikan terhadap bilangan bulat yang kamu hitung sendiri, jangan pernah terhadap model float. Step +16384 menghasilkan, suku demi suku:
That 4-count shortfall is the limit cycle, and it is arithmetic, not a bug: the
increment is (3869·err + 16384) >> 15, which reaches 1 only once
err ≥ 5. At err = 4 it rounds to zero and the output stops
there forever. Raise α, widen the state to 32 bits with 31 fraction bits, or accept the
offset — those are the three real options, and picking one knowingly is the exercise.
少掉的那 4 個計數就是極限環,它是算術結果而不是 bug:增量是 (3869·err + 16384) >> 15,只有在 err ≥ 5 時才會等於 1。當 err = 4 時它四捨五入成零,輸出就永遠停在那裡。把 α 調大、把狀態加寬成 32 位元(31 位小數)、或接受這個偏移——這是實際上僅有的三個選項,而在知情的狀況下選一個,就是這題要練的事。この 4 カウントの不足がリミットサイクルであり、バグではなく算術の結果だ。増分は (3869·err + 16384) >> 15 で、err ≥ 5 になって初めて 1 に達する。err = 4 ではゼロに丸められ、出力はそこで永遠に止まる。α を上げる、状態を 32 ビット(小数部 31 ビット)に広げる、あるいはオフセットを受け入れる——現実的な選択肢はこの三つで、理解したうえで一つを選ぶことがこの課題だ。Selisih 4 hitungan itu adalah siklus batas, dan itu aritmetika, bukan bug: penambahnya adalah (3869·err + 16384) >> 15, yang baru mencapai 1 setelah err ≥ 5. Pada err = 4 ia membulat menjadi nol dan keluarannya berhenti di situ selamanya. Naikkan α, lebarkan state menjadi 32 bit dengan 31 bit pecahan, atau terima simpangannya — itulah ketiga pilihan yang nyata, dan memilih salah satunya dengan sadar adalah inti latihannya.
23 pts分点poin5ACTUATOR
PWM a positional servo to a commanded angle用 PWM 把位置型伺服機轉到指定角度PWM で位置制御サーボを指定角度へ回すMem-PWM servo posisional ke sudut yang diperintahkan
PWM
Pulse width
Angle mapping
Closed loop
Bench supply
“pwm control the easy servo motor” ↳ positional, angle-commanded
A servo's PWM is not a throttle. The 50 Hz frame you send carries exactly one number — the width of the high pulse — and that width is an angle setpoint: 1.0 ms is one end of the travel, 2.0 ms the other, 1.5 ms the middle. Nothing in that signal tells the motor how fast to turn. Inside the case a potentiometer reads the actual shaft angle, a PI controller works on the error between it and your setpoint, and that loop decides the motor's speed and direction through the servo's own H-bridge. You command where; the servo decides how fast. Your job is the counter and the compare that turn an angle into that pulse width, with the angle read straight off the FPGA's GPIO pins.伺服機的 PWM 不是油門。你送出去的 50 Hz 框架只帶一個數字——高電位脈波的寬度——而那個寬度是角度設定值:1.0 ms 是行程的一端,2.0 ms 是另一端,1.5 ms 是中間。這個訊號裡沒有任何一處在告訴馬達要轉多快。殼子裡面有一顆電位器在讀實際的軸角度,一個 PI 控制器處理它與你的設定值之間的誤差,而決定馬達轉速與方向的是那個迴路,透過伺服機自己的 H 橋去驅動。你命令的是「到哪裡」,「轉多快」由伺服機自己決定。你要做的是把角度換成那個脈波寬度的計數器與比較器,而角度直接從 FPGA 的 GPIO 腳位讀進來。サーボの PWM はスロットルではない。送り出す 50 Hz のフレームが運ぶ数値はただ一つ——ハイパルスの幅——で、その幅は角度の設定値だ:1.0 ms が可動範囲の一端、2.0 ms がもう一端、1.5 ms が中央。この信号のどこにも、モータをどれだけ速く回すかという情報はない。ケースの中ではポテンショメータが実際の軸角度を読み、PI 制御器が設定値との誤差を処理し、モータの速度と方向を決めるのはそのループで、サーボ自身の H ブリッジを通して駆動する。指令するのは「どこへ」であり、「どれだけ速く」はサーボが決める。あなたの仕事は、角度をそのパルス幅に変換するカウンタと比較器で、角度は FPGA の GPIO ピンから直接読む。PWM sebuah servo bukanlah pengatur tenaga. Frame 50 Hz yang kamu kirim membawa tepat satu angka — lebar pulsa tingginya — dan lebar itu adalah setpoint sudut: 1.0 ms adalah salah satu ujung lintasan, 2.0 ms ujung yang lain, 1.5 ms bagian tengahnya. Tidak ada apa pun dalam sinyal itu yang memberi tahu motor seberapa cepat harus berputar. Di dalam casing-nya, sebuah potensiometer membaca sudut poros yang sebenarnya, sebuah kendali PI bekerja atas selisih antara nilai itu dan setpoint-mu, dan loop itulah yang menentukan kecepatan serta arah motor melalui H-bridge milik servo sendiri. Kamu memerintahkan ke mana; servo yang memutuskan secepat apa. Tugasmu adalah pencacah dan pembanding yang mengubah sudut menjadi lebar pulsa itu, dengan sudutnya dibaca langsung dari pin GPIO FPGA.
Those GPIO pins are asynchronous to your clock, so double-flop them before use and latch the whole word at the frame edge — sampling a multi-bit angle mid-transition hands you a value that was never on the pins at all, and the servo will faithfully drive to it.那些 GPIO 腳位跟你的時鐘不同步,所以要先過兩級正反器同步,再在框架邊界上把整個字一次鎖住——在多位元角度值跳變的中途取樣,拿到的會是一個從來沒出現在腳位上的值,而伺服機會忠實地轉到那個角度去。その GPIO ピンはクロックに非同期なので、使う前に二段フリップフロップで同期し、ワード全体をフレームのエッジでラッチすること——多ビットの角度値を遷移の途中でサンプルすると、ピン上に一度も存在しなかった値を拾い、サーボは忠実にその角度へ動いてしまう。Pin GPIO itu asinkron terhadap clock-mu, jadi lewatkan lebih dulu melalui dua flip-flop dan kunci seluruh word pada tepi frame — mencuplik sudut multi-bit di tengah transisi memberimu nilai yang sebenarnya tidak pernah ada di pin, dan servo akan dengan patuh bergerak ke sana.
This task needs no driver stage at all. The servo's signal wire is a logic input on its internal control board — a few hundred microamps, happy with 3.3 V — so it goes straight to an FPGA pin with nothing in between. No MOSFET, no H-bridge, no flyback diode: the bridge is already in there, one centimetre from the PI loop driving it, and a bridge of your own in front of a logic input would only destroy the signal. What the servo does need is power it can actually draw: its own 4.8–6 V rail, never the board's 5 V pin, with the two grounds tied at a single point so your pulse has a reference.這題完全不需要任何驅動級。伺服機的訊號線是它內部控制板上的一個邏輯輸入——幾百微安培,3.3 V 就吃得下——所以直接接到 FPGA 腳位,中間什麼都不用加。不用 MOSFET、不用 H 橋、不用續流二極體:橋本來就在裡面,離驅動它的 PI 迴路一公分遠,你自己在邏輯輸入前面再加一座橋,只會把訊號毀掉。伺服機真正需要的是它拉得動的電源:自己一條 4.8–6 V 的電源軌,絕對不要用板子的 5 V 腳,並且兩邊的地要在單一點接在一起,你的脈波才有參考點。この課題にドライバ段は一切不要だ。サーボの信号線は内部制御基板のロジック入力——数百マイクロアンペアで、3.3 V でも問題ない——なので、間に何も挟まず FPGA のピンへ直結する。MOSFET も H ブリッジもフライバックダイオードも要らない:ブリッジはすでに中にあり、それを駆動する PI ループから 1 cm の距離にある。ロジック入力の手前に自前のブリッジを置いても信号を壊すだけだ。サーボが本当に必要とするのは実際に引ける電力だ:専用の 4.8–6 V レールを用意し、ボードの 5 V ピンは使わない。そして両方の GND を一点で接続し、パルスに基準を与えること。Tugas ini sama sekali tidak memerlukan tingkat penggerak. Kabel sinyal servo adalah masukan logika pada papan kendali internalnya — beberapa ratus mikroampere, senang dengan 3.3 V — jadi ia langsung ke pin FPGA tanpa apa pun di antaranya. Tanpa MOSFET, tanpa H-bridge, tanpa dioda flyback: jembatannya sudah ada di dalam sana, satu sentimeter dari loop PI yang menggerakkannya, dan jembatan buatanmu sendiri di depan masukan logika hanya akan merusak sinyalnya. Yang justru dibutuhkan servo adalah daya yang benar-benar bisa ia tarik: rel 4.8–6 V miliknya sendiri, jangan pernah pin 5 V papan, dengan kedua ground disatukan di satu titik agar pulsamu punya acuan.
Read what that package actually is before wiring it: an MG90S is a brushed motor, a gearbox, a feedback potentiometer and the PI loop with its own H-bridge, all sealed in one case. That is why three wires are enough — power, ground, and one signal line carrying nothing but your angle.接線之前先搞清楚那顆東西是什麼:MG90S 是有刷馬達、齒輪箱、回饋電位器,加上那個帶自己 H 橋的 PI 迴路,全部封在同一個殼裡。這就是為什麼三條線就夠了——電源、地,以及一條只送角度的訊號線。配線する前にそれが何なのかを把握すること:MG90S はブラシモータ、ギアボックス、フィードバック用ポテンショメータ、そして自前の H ブリッジを備えた PI ループが、すべて一つのケースに封じられている。だから線は三本で足りる——電源、GND、そして角度だけを運ぶ信号線 1 本だ。Pahami dulu apa isi paket itu sebelum menyambungnya: sebuah MG90S adalah motor brushed, gearbox, potensiometer umpan balik dan loop PI dengan H-bridge-nya sendiri, semuanya tersegel dalam satu casing. Itulah sebabnya tiga kabel sudah cukup — daya, ground, dan satu jalur sinyal yang tidak membawa apa pun selain sudutmu.
Buy the 180° version. That is the positional servo this task is about: pulse width commands an angle and the internal loop holds it there against a load. The 360° version looks identical and is a different device — its potentiometer is decoupled from the output shaft, so there is no angle to hold, and the same pulse width becomes a speed and direction command with 1.5 ms meaning stop. With that part the angle checkpoints below are not reachable; it is an open-loop motor with a driver attached.請買 180° 的版本。那顆才是這題要的位置型伺服:脈波寬度命令角度,內部迴路會頂著負載把它維持在那裡。360° 那顆外觀一樣,但是另一種裝置——它的電位器已經和輸出軸脫開,所以沒有角度可以維持,同一個脈波寬度變成命令速度與方向,1.5 ms 代表停止。用那顆的話,下面的角度檢查點做不到;它只是一顆接了驅動器的開迴路馬達。180° 版を買うこと。それがこの課題で使う位置制御サーボだ:パルス幅が角度を指令し、内部ループが負荷に抗してそこを保持する。360° 版は見た目が同じでも別の装置で——ポテンショメータが出力軸から切り離されているため保持すべき角度が存在せず、同じパルス幅が速度と方向の指令になり、1.5 ms が停止を意味する。その部品では下の角度チェックポイントに到達できない。ドライバの付いた開ループのモータにすぎない。Belilah versi 180°. Itulah servo posisional yang menjadi pokok tugas ini: lebar pulsa memerintahkan sudut dan loop internal menahannya di sana melawan beban. Versi 360° terlihat identik tetapi merupakan perangkat yang berbeda — potensiometernya dilepas dari poros keluaran, sehingga tidak ada sudut untuk ditahan, dan lebar pulsa yang sama berubah menjadi perintah kecepatan dan arah dengan 1.5 ms berarti berhenti. Dengan komponen itu, checkpoint sudut di bawah tidak bisa dicapai; ia adalah motor loop-terbuka dengan penggerak yang menempel.
Do not write a new angle to the compare register the instant the GPIO pins change. A servo commanded from 0° to 180° in a single frame goes there as fast as its internal loop can manage — full current, full torque, and a supply sag that resets the FPGA if the two share a rail. Move the setpoint one degree per frame instead: full travel then takes 180 × 20 ms = 3.6 s, comfortably outside the 500 ms floor, and the mechanism never sees a step. This is the same ramp the brushed-motor extension needs, applied to a position instead of a duty.不要在 GPIO 腳位一變就把新角度寫進比較暫存器。一個在單一框架內從 0° 被命令到 180° 的伺服機,會用它內部迴路能給的最快速度衝過去——滿電流、滿扭矩,如果它和 FPGA 共用一條電源軌,電壓會塌到讓 FPGA 重置。改成每個框架只移動一度:跑完全行程要 180 × 20 ms = 3.6 s,穩穩地落在 500 ms 的下限之外,而機構永遠不會看到階躍。這和有刷馬達那一節需要的斜升是同一件事,只是作用在位置而不是 duty 上。GPIO ピンが変わった瞬間に新しい角度を比較レジスタへ書いてはいけない。1 フレームで 0° から 180° へ指令されたサーボは、内部ループが出せる限りの速さでそこへ飛ぶ——全電流、全トルク、そして FPGA と電源レールを共有していれば電圧が落ちて FPGA がリセットする。代わりに設定値をフレームごとに 1 度ずつ動かすこと:全行程は 180 × 20 ms = 3.6 s となり、500 ms の下限には余裕で収まり、機構がステップを見ることはない。これはブラシモータの発展課題で必要になるランプと同じ話を、デューティではなく位置に適用したものだ。Jangan menulis sudut baru ke register pembanding begitu pin GPIO berubah. Servo yang diperintahkan dari 0° ke 180° dalam satu frame akan ke sana secepat yang bisa dilakukan loop internalnya — arus penuh, torsi penuh, dan tegangan yang anjlok sehingga FPGA ter-reset kalau keduanya berbagi rel. Geser setpoint-nya satu derajat per frame saja: lintasan penuh lalu memakan 180 × 20 ms = 3.6 s, jauh di atas batas bawah 500 ms, dan mekanismenya tidak pernah menerima step. Ini adalah ramp yang sama dengan yang dibutuhkan perluasan motor brushed, hanya diterapkan pada posisi alih-alih duty.
Extension — a bare brushed motor延伸:換成裸的有刷馬達発展——剥き出しのブラシモータPerluasan — motor brushed telanjang
Everything above stops at the servo's signal pin, because the loop that turns your angle into motor current is already inside the case. Build that inner half yourself — a bare brushed motor, no feedback — and this is what you have to add: a carrier fast enough to be inaudible, a compare value that now means speed, a bridge if you want reversal, and a buffer stage between the FPGA pin and the winding. Note that only reversal needs a bridge; one low-side transistor is enough for one direction.上面所有東西都停在伺服機的訊號腳,因為把你的角度變成馬達電流的那個迴路,已經在殼子裡了。自己把裡面那一半做出來——一顆裸的有刷馬達,沒有回饋——要加的就是這些:一個快到聽不見的載波、一個現在代表轉速的比較值、想換向的話再加一座橋,以及 FPGA 腳位與線圈之間的緩衝級。注意只有換向才需要橋;單一方向用一顆低邊電晶體就夠了。ここまでの内容はサーボの信号ピンで終わる。角度をモータ電流に変えるループは、すでにケースの中にあるからだ。その内側の半分を自分で作るなら——剥き出しのブラシモータ、フィードバックなし——追加が必要なのは次のものだ:可聴域を超えたキャリア、いまや速度を意味する比較値、反転させたいならブリッジ、そして FPGA のピンと巻線の間のバッファ段。ブリッジが必要なのは反転のときだけで、片方向なら低電位側のトランジスタ 1 個で足りる。Semua di atas berhenti pada pin sinyal servo, karena loop yang mengubah sudutmu menjadi arus motor sudah ada di dalam casing. Bangun sendiri separuh bagian dalam itu — motor brushed telanjang, tanpa umpan balik — dan inilah yang harus kamu tambahkan: pembawa yang cukup cepat sehingga tak terdengar, nilai pembanding yang sekarang berarti kecepatan, sebuah jembatan kalau kamu ingin pembalikan arah, dan tingkat penyangga antara pin FPGA dan lilitannya. Perhatikan bahwa hanya pembalikan arah yang butuh jembatan; satu transistor sisi-bawah sudah cukup untuk satu arah.
The FPGA pin is a control signal, not a power source. An I/O pin drives a few milliamps — 24 mA at the very most, and only if the bank is configured for it — while a small brushed motor pulls several hundred milliamps running and close to an amp stalled. Between the PWM output and the motor you have to design a buffer stage of your own. Wiring a motor straight to an I/O pin kills the pin, and often takes the whole bank with it.FPGA 的腳位是控制訊號,不是電源。一支 I/O 腳只能推幾毫安培——最多 24 mA,而且還要 bank 有這樣設定——但一顆小型有刷馬達運轉時要幾百毫安培,堵轉時接近一安培。PWM 輸出和馬達之間,你必須自己設計一級緩衝電路。把馬達直接接到 I/O 腳,那支腳會死,而且常常整個 bank 一起陪葬。FPGA のピンは制御信号であって電源ではない。I/O ピンが流せるのは数ミリアンペア——バンクの設定次第で最大 24 mA——に対し、小型のブラシモータは回転中で数百ミリアンペア、ストール時には 1 A 近くを引く。PWM 出力とモータの間には、自分で設計したバッファ段が必要だ。モータを I/O ピンに直結すればそのピンは壊れ、多くの場合バンクごと道連れになる。Pin FPGA adalah sinyal kendali, bukan sumber daya. Sebuah pin I/O menggerakkan beberapa miliampere — paling banter 24 mA, dan hanya kalau bank-nya dikonfigurasi untuk itu — sementara motor brushed kecil menarik beberapa ratus miliampere saat berjalan dan mendekati satu ampere saat macet. Di antara keluaran PWM dan motor, kamu harus merancang sendiri tingkat penyangga. Menyambungkan motor langsung ke pin I/O akan membunuh pin itu, dan sering kali membawa serta seluruh bank-nya.
That buffer can be a single transistor. One logic-level N-MOSFET as a low-side switch — source to ground, drain to the motor's negative terminal, motor positive to its own supply — gives you full PWM speed control in one direction, and an NPN BJT with a base resistor does the same job at lower current. Three details decide whether it works: the MOSFET must be logic-level, because a plain IRF540 never fully turns on at 3.3 V; a flyback diode across the motor catches the inductive kick; and a 10 kΩ pull-down on the gate keeps the motor still while the FPGA is still configuring and the pin is high-Z. For a BJT, size the base resistor from the current you need — at β ≈ 100 and 500 mA that is 5 mA of base current, so (3.3 − 0.7) / 5 mA ≈ 470 Ω. Only the reversal checkpoint needs more than one transistor; that is what the H-bridge is for.這個緩衝電路可以只有一顆電晶體。一顆邏輯準位 N-MOSFET 當低邊開關——source 接地、drain 接馬達負端、馬達正端接它自己的電源——就能在單一方向上做完整的 PWM 調速;電流不大時,一顆 NPN BJT 加上基極電阻也能做同樣的事。成敗取決於三個細節:MOSFET 必須是邏輯準位的,因為一般的 IRF540 在 3.3 V 下根本不會完全導通;馬達要並一顆續流二極體吸收電感回衝;閘極要接一顆 10 kΩ 下拉電阻,讓 FPGA 還在組態、腳位還是高阻抗時馬達不會亂動。用 BJT 的話,基極電阻要照需要的電流算——β ≈ 100、負載 500 mA 時基極要 5 mA,所以 (3.3 − 0.7) / 5 mA ≈ 470 Ω。只有「換向」那個檢查點需要一顆以上的電晶體,那正是 H 橋存在的理由。このバッファはトランジスタ 1 個でも構わない。ロジックレベルの N-MOSFET をローサイドスイッチとして使えば——ソースを GND、ドレインをモータのマイナス端子、モータのプラス端子は専用電源へ——片方向で完全な PWM 速度制御ができる。電流が小さければ、ベース抵抗付きの NPN BJT でも同じ役目を果たす。成否を決めるのは三点:MOSFET はロジックレベル品であること(普通の IRF540 は 3.3 V では完全にオンしない)、モータと並列のフライバックダイオードで誘導性のキックを逃がすこと、そしてゲートの 10 kΩ プルダウンで、FPGA がまだコンフィグ中でピンがハイインピーダンスの間にモータが動かないようにすること。BJT ならベース抵抗は必要な電流から決める——β ≈ 100 で 500 mA ならベース電流 5 mA、つまり (3.3 − 0.7) / 5 mA ≈ 470 Ω。トランジスタが 1 個で足りないのは反転のチェックポイントだけで、そのために H ブリッジがある。Penyangga itu bisa berupa satu transistor. Satu N-MOSFET logic-level sebagai sakelar sisi-bawah — source ke ground, drain ke terminal negatif motor, positif motor ke catu dayanya sendiri — sudah memberimu kendali kecepatan PWM penuh dalam satu arah, dan BJT NPN dengan resistor basis melakukan pekerjaan yang sama pada arus yang lebih rendah. Tiga hal menentukan apakah ini berhasil: MOSFET-nya harus logic-level, karena IRF540 biasa tidak pernah benar-benar menyala penuh pada 3.3 V; dioda flyback melintang pada motor menangkap tendangan induktifnya; dan pull-down 10 kΩ pada gate menjaga motor tetap diam selagi FPGA masih dikonfigurasi dan pin-nya masih high-Z. Untuk BJT, hitung resistor basis dari arus yang kamu butuhkan — pada β ≈ 100 dan 500 mA itu berarti arus basis 5 mA, jadi (3.3 − 0.7) / 5 mA ≈ 470 Ω. Hanya checkpoint pembalikan arah yang butuh lebih dari satu transistor; untuk itulah H-bridge ada.
If you want the motor's noise to stay out of the FPGA altogether, put a photocoupler between the two: the PWM pin drives the coupler's LED through a series resistor, the phototransistor on the far side drives the gate, and the only thing crossing between the two grounds is light. Watch the speed — a common PC817 takes a few microseconds to switch, which is a visible slice of a 50 µs PWM period and distorts the duty; at 20 kHz reach for a fast logic coupler (6N137) or a gate-driver coupler (TLP250) instead. Size the LED resistor from the coupler's forward voltage — (3.3 − 1.2) / 5 mA ≈ 470 Ω — and remember the transistor side needs its own supply and pull-up, or the isolation buys you nothing.如果你希望馬達的雜訊完全進不了 FPGA,就在兩者之間放一顆光耦合器:PWM 腳透過一顆串聯電阻去推光耦裡的 LED,另一端的光電晶體再去驅動閘極,兩邊的地之間就只剩下光在傳遞。要注意速度——常見的 PC817 切換要好幾微秒,在 50 µs 的 PWM 週期裡是看得出來的一塊,會讓 duty 失真;20 kHz 請改用高速邏輯型光耦(6N137)或閘極驅動型光耦(TLP250)。LED 的限流電阻依它的順向電壓計算——(3.3 − 1.2) / 5 mA ≈ 470 Ω——另外別忘了電晶體那一側要有自己的電源與上拉電阻,否則這層隔離等於白做。モータのノイズを FPGA に一切入れたくないなら、両者の間にフォトカプラを置く:PWM ピンが直列抵抗を介してカプラの LED を駆動し、反対側のフォトトランジスタがゲートを駆動する。二つのグラウンドの間を渡るのは光だけになる。速度には注意——よくある PC817 はスイッチングに数マイクロ秒かかり、50 µs の PWM 周期では無視できない割合を占めてデューティを歪ませる。20 kHz なら高速ロジック用(6N137)かゲートドライバ用(TLP250)のフォトカプラを使うこと。LED の抵抗は順方向電圧から決める——(3.3 − 1.2) / 5 mA ≈ 470 Ω——そしてトランジスタ側には独自の電源とプルアップが要る。でなければ絶縁した意味がない。Kalau kamu ingin derau motor sama sekali tidak masuk ke FPGA, pasang photocoupler di antara keduanya: pin PWM menggerakkan LED coupler lewat resistor seri, fototransistor di seberangnya menggerakkan gate, dan satu-satunya yang menyeberang di antara kedua ground adalah cahaya. Perhatikan kecepatannya — PC817 yang umum butuh beberapa mikrodetik untuk beralih, dan itu potongan yang kelihatan dari periode PWM 50 µs sehingga merusak duty-nya; pada 20 kHz, pilihlah coupler logika cepat (6N137) atau coupler gate-driver (TLP250). Hitung resistor LED dari tegangan maju coupler-nya — (3.3 − 1.2) / 5 mA ≈ 470 Ω — dan ingat sisi transistornya butuh catu daya dan pull-up sendiri, kalau tidak isolasinya tidak memberimu apa-apa.
Putting a MOSFET or an H-bridge in front of the servo's signal wire. It is a logic input, not a winding — drive it directly.在伺服機訊號線前面加 MOSFET 或 H 橋。那是邏輯輸入,不是線圈——直接推它就好。サーボの信号線の手前に MOSFET や H ブリッジを置くこと。あれは巻線ではなくロジック入力だ——直結して駆動する。Memasang MOSFET atau H-bridge di depan kabel sinyal servo. Itu masukan logika, bukan lilitan — gerakkan langsung.
A frame that is only approximately 20 ms, or a pulse that jitters by a microsecond, makes the horn buzz and hunt — that is your counter, not the servo.框架只是「大約」20 ms,或脈波抖動個一微秒,舵臂就會嗡嗡叫並來回找位——那是你的計數器的問題,不是伺服機的。フレームが「およそ」20 ms しかない、あるいはパルスが 1 マイクロ秒ジッタするだけで、ホーンは唸って位置を探し続ける——それはサーボではなく自分のカウンタの問題だ。Frame yang hanya kira-kira 20 ms, atau pulsa yang bergetar sebesar satu mikrodetik, membuat horn berdengung dan mencari-cari — itu pencacahmu, bukan servonya.
Commanding past the mechanical end stop. Below 1.0 ms or above 2.0 ms the loop keeps pushing against the stop, draws stall current and cooks the gearbox — clamp the angle in hardware, not in the host that feeds the pins.命令超過機械極限。低於 1.0 ms 或高於 2.0 ms 時,迴路會一直頂著限位推,吃堵轉電流並把齒輪箱燒掉——角度要在硬體裡夾住,不要靠餵腳位的那一端自律。機械的なエンドストップを越えて指令すること。1.0 ms 未満または 2.0 ms 超では、ループはストッパを押し続けてストール電流を引き、ギアボックスを焼く——角度はハードウェアでクランプする。ピンに値を送る側の良心に任せてはいけない。Memerintahkan melewati batas mekanis. Di bawah 1.0 ms atau di atas 2.0 ms, loop-nya terus mendorong melawan batas itu, menarik arus macet dan memanggang gearbox — kunci sudutnya di perangkat keras, bukan di host yang memberi umpan ke pin.
An MG90S takes 3.3 V logic on the signal pin happily, but never power it from the board's 5 V pin — a stalled servo pulls close to an amp and the FPGA resets with it.MG90S 的訊號腳吃 3.3 V 邏輯沒問題,但絕對不要用板子的 5 V 腳供電——伺服機堵轉時電流接近一安培,FPGA 會跟著重置。MG90S の信号ピンは 3.3 V ロジックで問題なく動くが、ボードの 5 V ピンから電源を取ってはいけない——ストール時に 1 A 近く流れ、FPGA も一緒にリセットする。MG90S menerima logika 3.3 V pada pin sinyal dengan senang hati, tetapi jangan pernah memberinya daya dari pin 5 V papan — servo yang macet menarik mendekati satu ampere dan FPGA ikut ter-reset.
Separate motor supply, grounds tied at one point. Powering the motor off the board rail browns out the FPGA the moment it stalls.馬達要獨立供電,接地只在一點共接。用板子的電源軌去推馬達,堵轉那一瞬間 FPGA 就會掉電。モータ電源は別系統にし、グラウンドは一点で接続する。ボードの電源レールからモータを回すと、ストールした瞬間に FPGA が電圧降下で落ちる。Catu daya motor terpisah, ground disatukan di satu titik. Memberi daya motor dari rel papan akan membuat FPGA brownout begitu motornya macet.
Step the duty from 0 to full and the inrush trips the supply. Ramp the compare register.把 duty 從 0 一步跳到滿,突入電流會讓電源跳掉。比較暫存器要用斜升的。デューティを 0 から一気に全開にすると突入電流で電源が落ちる。比較レジスタはランプさせること。Naikkan duty dari 0 ke penuh sekaligus dan arus inrush-nya akan menjatuhkan catu daya. Ramp-kan register pembandingnya.
Never drive both sides of a bridge leg on at once. Insert the dead time in the FSM, not in your head.絕不要讓橋臂的上下兩側同時導通。死區時間要寫進 FSM 裡,不是放在你腦子裡。ブリッジの上下アームを同時にオンにしてはいけない。デッドタイムは頭の中ではなく FSM に入れること。Jangan pernah menyalakan kedua sisi satu kaki jembatan sekaligus. Sisipkan dead time-nya di dalam FSM, bukan di kepalamu.
Below a few percent duty the motor buzzes and does not turn — that is the deadband, not a bug.duty 低於百分之幾時馬達只會嗡嗡叫而不轉——那是死區,不是 bug。デューティが数パーセントを下回るとモータは唸るだけで回らない——それはデッドバンドであってバグではない。Di bawah beberapa persen duty, motor berdengung dan tidak berputar — itu deadband, bukan bug.
Done when完成條件完了条件Selesai bila
Reference answer — not released yet參考解答 —— 尚未開放参考解答 — まだ公開されていませんJawaban acuan — belum dirilis
Reference answer參考解答参考解答Jawaban acuan
The frame and the compare. One counter, one comparison — the whole peripheral:框架與比較。一個計數器、一次比較——整個外設就這樣:フレームと比較。カウンタ 1 個、比較 1 回——ペリフェラル全体がこれだけだ:Frame dan pembandingnya. Satu pencacah, satu perbandingan — itulah seluruh periferalnya:
Angle to pulse width, in the same Q-format arithmetic as task 4. There are 2500/9 ≈ 277.78 counts per degree, so scale by 71111/256 and shift — no divider, and the error across full travel is one count:角度換算成脈波寬度,用的是跟第 4 題同一套 Q 格式算術。每度是 2500/9 ≈ 277.78 個計數,所以乘以 71111 再右移 8 位——不需要除法器,而跑完全行程的誤差是一個計數:角度からパルス幅へ、課題 4 と同じ Q フォーマットの算術で変換する。1 度あたり 2500/9 ≈ 277.78 カウントなので、71111 を掛けて 8 ビット右シフトする——除算器は不要で、全行程での誤差は 1 カウントだ:Sudut menjadi lebar pulsa, dengan aritmetika format Q yang sama seperti tugas 4. Ada 2500/9 ≈ 277.78 hitungan per derajat, jadi skalakan dengan 71111/256 lalu geser — tanpa pembagi, dan galat sepanjang lintasan penuh hanya satu hitungan:
The GPIO word crosses into your clock domain, and the setpoint is slew-limited a degree at a time so the mechanism never sees a step. Clamping happens here too, once, where the value enters:GPIO 的字要跨進你的時鐘域,而設定值以一度為單位做迴轉率限制,機構才不會看到階躍。夾限也在這裡做,只做一次,就在值進來的地方:GPIO のワードは自分のクロックドメインへ渡り、設定値は 1 度ずつスルーレート制限されるので、機構がステップを見ることはない。クランプもここで、値が入る一箇所だけで行う:Word GPIO menyeberang ke domain clock-mu, dan setpoint-nya dibatasi lajunya satu derajat demi satu derajat sehingga mekanismenya tidak pernah menerima step. Pengekangan nilai juga terjadi di sini, satu kali, di tempat nilainya masuk:
reg [7:0] g1, g2, ang_q;
wire [7:0] tgt = (g2 > 180) ? 8'd180 : g2; // clamp once, here
always @(posedge clk) begin
g1 <= gpio_angle; g2 <= g1; // two flops, async in
if (scnt == SPER-1) // once per 20 ms frame
if (ang_q < tgt) ang_q <= ang_q + 1'b1;
else if (ang_q > tgt) ang_q <= ang_q - 1'b1;
end
A PWM peripheral is a counter and a compare, and that never changes. What changes is what the compare value means. Here it is a position, and the loop that turns it into current belongs to the servo. In the extension it is a duty, it means speed, and that loop is yours to build.PWM 外設就是一個計數器加一次比較,這一點永遠不變。變的是比較值代表什麼。在這裡它是位置,而把它變成電流的那個迴路屬於伺服機。在延伸題裡它是 duty、代表轉速,而那個迴路要你自己做。PWM ペリフェラルはカウンタと比較であり、それは決して変わらない。変わるのは比較値が何を意味するかだ。ここでは位置であり、それを電流に変えるループはサーボのものだ。発展課題ではデューティであり、速度を意味し、そのループは自分で作ることになる。Sebuah periferal PWM adalah pencacah dan pembanding, dan itu tidak pernah berubah. Yang berubah adalah arti nilai pembandingnya. Di sini ia adalah posisi, dan loop yang mengubahnya menjadi arus adalah milik servo. Pada perluasannya ia adalah duty, ia berarti kecepatan, dan loop itu harus kamu bangun sendiri.
Extension — the brushed-motor half. Same counter, a carrier instead of a frame, and the compare value latched at the period edge so a mid-period write cannot emit a runt pulse:延伸——有刷馬達那一半。同一個計數器,把框架換成載波,並在週期邊界上鎖住比較值,週期中途寫入才不會產生殘缺脈波:発展——ブラシモータ側。同じカウンタで、フレームの代わりにキャリアを使い、比較値を周期のエッジでラッチして、周期途中の書き込みがランとパルスを出さないようにする:Perluasan — separuh motor brushed. Pencacah yang sama, pembawa alih-alih frame, dan nilai pembanding dikunci pada tepi periode agar penulisan di tengah periode tidak bisa memancarkan pulsa kerdil:
localparam PER = 2500;
reg [11:0] cnt, duty;
always @(posedge clk) begin
cnt <= (cnt == PER-1) ? 12'd0 : cnt + 1'b1;
if (cnt == PER-1) duty <= duty_next; // atomic update
end
assign pwm = (cnt < duty);
Sign-magnitude drive: PWM one leg, hold the other, and force a coast window across every direction change:符號—大小驅動:一邊橋臂做 PWM,另一邊固定,並在每次換向時強制插入一段滑行視窗:符号・絶対値駆動:片方のアームを PWM し、もう片方は固定、方向転換のたびに惰走区間を強制的に挟む:Penggerak sign-magnitude: PWM satu kaki, tahan yang lain, dan paksakan jendela coast pada setiap pergantian arah:
localparam DEAD = 50; // 1 us at 50 MHz
reg [5:0] dead; reg dir_q;
always @(posedge clk) begin
if (dir != dir_q) begin dead <= DEAD; dir_q <= dir; end
else if (|dead) dead <= dead - 1'b1;
end
wire coast = |dead;
assign in_a = coast ? 1'b0 : ( dir & pwm);
assign in_b = coast ? 1'b0 : (~dir & pwm);
And the ramp, so the supply never sees a step: move duty_next by one count
per 100 µs and full scale takes 250 ms, comfortably inside the 200 ms floor.
再來是斜升,讓電源永遠不會看到階躍:每 100 µs 讓 duty_next 動一個計數,滿刻度就要 250 ms,安穩地落在 200 ms 的下限之外。そしてランプ——電源にステップを見せないため、duty_next を 100 µs ごとに 1 カウント動かすと、フルスケールまで 250 ms かかり、200 ms の下限を余裕で満たす。Dan ramp-nya, agar catu daya tidak pernah menerima step: geser duty_next satu hitungan tiap 100 µs sehingga skala penuh memakan 250 ms, nyaman di dalam batas bawah 200 ms.
24 pts分点poin6HOST SIDE
Retire LabVIEW: the same panel in Python讓 LabVIEW 退休:用 Python 做同一個控制面板LabVIEW を引退させる:同じパネルを Python でPensiunkan LabVIEW: panel yang sama dalam Python
pyserial
Tkinter
Threads
Python 3
“better use python to code gui program to replace labview”
↳ added after the notebook page
Rebuild tasks 3–5 as one Python window: a port selector, an echo self-test, a live plot of
the filtered stream, and a duty slider. Same FPGA bitstream, same 115200 8N1 link — only
the desk side changes. pyserial plus stdlib tkinter is the whole
dependency list, which is the argument for doing it this way.
把第 3 到第 5 題重做成一個 Python 視窗:串列埠選單、回傳自我測試、濾波資料的即時繪圖,以及一根 duty 滑桿。FPGA 的 bitstream 一樣、115200 8N1 的連線一樣——只有桌上這端換掉。相依套件就只有 pyserial 加上標準函式庫的 tkinter,這就是這樣做的理由。課題 3〜5 を一つの Python ウィンドウとして作り直す:ポート選択、エコーの自己テスト、フィルタ済みデータのライブプロット、そしてデューティのスライダ。FPGA のビットストリームも 115200 8N1 のリンクも同じで、変わるのは机の上だけだ。依存は pyserial と標準ライブラリの tkinter だけ——それがこのやり方を選ぶ理由になる。Bangun ulang tugas 3–5 sebagai satu jendela Python: pemilih port, uji-mandiri gema, plot langsung aliran hasil tapis, dan penggeser duty. Bitstream FPGA yang sama, sambungan 115200 8N1 yang sama — hanya sisi mejanya yang berubah. pyserial ditambah tkinter dari stdlib adalah seluruh daftar dependensinya, dan itulah alasan melakukannya dengan cara ini.
One byte stream now carries three different things, so give it a frame:
A5 | cmd | len | payload… | xor. Sync on A5, drop the frame if
the checksum disagrees, and never assume one read() returns one frame.
同一條位元組串流現在要載三種東西,所以給它一個框架:A5 | cmd | len | payload… | xor。用 A5 同步,checksum 不合就丟掉整個 frame,而且永遠不要假設一次 read() 剛好回來一個 frame。一本のバイトストリームが三種類のものを運ぶことになるので、フレームを与える:A5 | cmd | len | payload… | xor。A5 で同期し、チェックサムが合わなければそのフレームを捨てる。1 回の read() が 1 フレームを返すとは決して仮定しないこと。Satu aliran byte sekarang membawa tiga hal berbeda, jadi berilah ia frame: A5 | cmd | len | payload… | xor. Sinkronkan pada A5, buang frame-nya kalau checksum tidak cocok, dan jangan pernah mengandaikan satu read() mengembalikan satu frame.
Target numbers目標數字目標値Angka target
Port串列埠ポートPort
serial.Serial(port, 115200)
Defaults預設值デフォルトNilai bawaan
8N1, no flow control
Reader讀取執行緒リーダPembaca
1 daemon thread → queue
UI drainUI 取用UI の取り出しPengurasan UI
root.after(30 ms)
Frame框架フレームFrame
A5 · cmd · len · data · xor
Windows port ≥ 10Windows 埠號 ≥ 10Windows のポート番号 ≥ 10Port Windows ≥ 10
\\.\COM10
Traps陷阱落とし穴Jebakan
Never touch a Tk widget from the reader thread. Push bytes into a queue.Queue and drain it from after() on the main thread — this is the single most common way these panels hang.絕對不要從讀取執行緒去碰 Tk 元件。把位元組丟進 queue.Queue,再由主執行緒的 after() 取出——這類面板當掉,最常見的原因就是這個。リーダスレッドから Tk のウィジェットに触れてはいけない。バイト列は queue.Queue に入れ、メインスレッドの after() で取り出す——この種のパネルがフリーズする原因の第一位がこれだ。Jangan pernah menyentuh widget Tk dari thread pembaca. Dorong byte-nya ke dalam queue.Queue dan kuras dari after() di thread utama — inilah cara paling umum panel semacam ini menggantung.
ser.read(n) returns up to n bytes when the timeout expires. Accumulate into a buffer and parse frames out of it; do not treat one read as one message.ser.read(n) 在逾時的時候回傳的是最多 n 個位元組。請累積到緩衝區裡再從中解析 frame;不要把一次讀取當成一則訊息。ser.read(n) はタイムアウト時に最大 n バイトを返す。バッファに貯めてからフレームを切り出すこと。1 回の read を 1 メッセージとして扱ってはいけない。ser.read(n) mengembalikan paling banyak n byte ketika timeout-nya habis. Kumpulkan ke dalam buffer dan parse frame-nya dari sana; jangan perlakukan satu read sebagai satu pesan.
A Tk Scale fires its callback on every pixel of drag. Throttle it, or send only on release, or you queue hundreds of duty writes into a 115200 pipe.Tk 的 Scale 每拖動一個像素就觸發一次回呼。要節流,或只在放開時送出,否則你會把幾百筆 duty 寫入塞進 115200 的管線裡。Tk の Scale はドラッグ 1 ピクセルごとにコールバックを呼ぶ。スロットリングするか、離した時だけ送ること。さもないと 115200 の細い管に数百回の書き込みを詰め込むことになる。Scale pada Tk memicu callback-nya pada setiap piksel gerakan. Batasi lajunya, atau kirim hanya saat dilepas, kalau tidak kamu menumpuk ratusan penulisan duty ke dalam pipa 115200.
Close the port on WM_DELETE_WINDOW. On Windows the handle stays locked and the next run fails with "Access is denied" until you replug.在 WM_DELETE_WINDOW 時關閉串列埠。在 Windows 上那個 handle 會一直被鎖住,下次執行會出現「Access is denied」,直到你把線拔掉重插。WM_DELETE_WINDOW でポートを閉じること。Windows ではハンドルがロックされたままになり、挿し直すまで次回の実行が「Access is denied」で失敗する。Tutup port-nya pada WM_DELETE_WINDOW. Di Windows, handle-nya tetap terkunci dan jalan berikutnya gagal dengan "Access is denied" sampai kamu mencabut dan memasangnya lagi.
Plot decimated data. Redrawing 1000 points at 1 kHz starves the event loop; keep a ring of the last ~500 samples and redraw at 30 Hz.繪圖前先抽取。以 1 kHz 重畫 1000 個點會把事件迴圈餓死;保留最近約 500 筆的環形緩衝,用 30 Hz 重畫就好。プロットは間引くこと。1 kHz で 1000 点を再描画するとイベントループが飽和する。直近 500 サンプル程度のリングを持ち、30 Hz で描き直す。Plot data yang sudah didesimasi. Menggambar ulang 1000 titik pada 1 kHz membuat event loop kelaparan; simpan ring berisi ~500 cuplikan terakhir dan gambar ulang pada 30 Hz.
Done when完成條件完了条件Selesai bila
Reference answer — not released yet參考解答 —— 尚未開放参考解答 — まだ公開されていませんJawaban acuan — belum dirilis
Reference answer參考解答参考解答Jawaban acuan
The skeleton that solves the threading half. Everything else hangs off it:解決執行緒那一半問題的骨架。其他東西都掛在它上面:スレッド側の問題を解く骨組み。残りはすべてここにぶら下がる:Kerangka yang menyelesaikan separuh persoalan threading. Semua yang lain menggantung padanya:
import queue, threading, tkinter as tk
import serial
ser = serial.Serial("COM7", 115200, timeout=0.05) # 8N1 is default
rx = queue.Queue()
alive = threading.Event(); alive.set()
def reader(): # thread: bytes in, frames out
buf = bytearray()
while alive.is_set():
try:
buf += ser.read(256)
except serial.SerialException as e:
rx.put(("error", str(e))); break
while len(buf) >= 3 and (n := buf[2]) + 4 <= len(buf):
if buf[0] != 0xA5:
del buf[0]; continue
frame = bytes(buf[:n+4])
del buf[:n+4]
rx.put(("frame", frame))
threading.Thread(target=reader, daemon=True).start()
The main thread never blocks on the port — it only drains the queue:主執行緒永遠不會卡在串列埠上——它只負責把佇列清空:メインスレッドはポートでブロックせず、キューを取り出すだけ:Thread utama tidak pernah terblokir pada port — ia hanya menguras queue:
def drain():
while not rx.empty():
kind, payload = rx.get()
if kind == "error": status.set(payload)
else: plot_push(payload)
root.after(30, drain)
def on_close():
alive.clear(); ser.close(); root.destroy() # release the port
root.protocol("WM_DELETE_WINDOW", on_close)
root.after(30, drain)
root.mainloop()
And the duty slider, throttled so a drag cannot flood the link:還有 duty 滑桿,加了節流,讓拖動不會灌爆連線:そしてデューティのスライダ。スロットリングして、ドラッグがリンクを溢れさせないようにする:Dan penggeser duty-nya, dibatasi lajunya agar satu gerakan tidak bisa membanjiri sambungan:
pending = None
def on_duty(v): # Scale(from_=0, to=255, resolution=1)
global pending
pending = int(v) # slider counts ARE the duty byte
def flush_duty(): # at most 20 writes/second
global pending
if pending is not None:
ser.write(bytes([0xA5, 0x02, 1, pending, 0x02 ^ 1 ^ pending]))
pending = None
root.after(50, flush_duty)
Swap tkinter for PySide6 and the structure is identical — a reader thread,
a queue, and a timer on the UI thread. The dependency list is what changes, not the
design.
把 tkinter 換成 PySide6,結構完全一樣——一條讀取執行緒、一個佇列,加上 UI 執行緒上的計時器。變的是相依套件,不是設計。tkinter を PySide6 に置き換えても構造は同じ——リーダスレッド、キュー、そして UI スレッド上のタイマー。変わるのは依存関係であって設計ではない。Tukar tkinter dengan PySide6 dan strukturnya tetap identik — satu thread pembaca, satu queue, dan satu timer di thread UI. Yang berubah adalah daftar dependensinya, bukan rancangannya.
Section 02 · C language · 21 terms to recognise第 02 章 · C 語言 · 21 個要認得的名詞セクション 02 · C 言語 · 覚えておきたい 21 語Bagian 02 · bahasa C · 21 istilah yang harus dikenali
Some Tips for Advanced Learning給進階學習的一些建議さらに先へ進むためのヒントBeberapa Kiat untuk Pembelajaran Lanjutan
The list below is what gets asked in interviews at top-tier and foreign firms, and what
actually matters once you start writing C to make LabVIEW go faster. You are not expected to
master any of it now.
下面這份清單,是進頂尖公司或外商面試一定會被問到的東西,也是你開始用 C 加速 LabVIEW 之後真正會用到的東西。現在不需要精通任何一項。以下のリストは、トップ企業や外資の面接で必ず訊かれる事柄であり、C を書いて LabVIEW を高速化し始めたときに実際に効いてくる事柄でもある。今すべてを習得する必要はない。Daftar di bawah adalah apa yang ditanyakan pada wawancara di perusahaan papan atas dan perusahaan asing, dan apa yang benar-benar penting begitu kamu mulai menulis C agar LabVIEW berjalan lebih cepat. Kamu tidak dituntut menguasai semuanya sekarang.
「你不用特地去學,看過清單、對名詞有個印象,有遇到問題當作參考資料,或是過來問我。」
— from a note written for a graduating member of the RF & MW lab.
Concurrency並行處理並行処理Konkurensi
Why this list exists at all: threads are where the speed-up lives, and where the bugs live.這份清單存在的理由:加速來自執行緒,bug 也來自執行緒。このリストが存在する理由:速度はスレッドから来て、バグもスレッドから来る。Mengapa daftar ini ada sama sekali: thread adalah tempat percepatannya berada, dan juga tempat bug-nya berada.
Coherency vs parallelismcoherency 與 parallelism 的差異コヒーレンシと並列性の違いKoherensi vs paralelismeTwo different problems. Know which one you actually have.這是兩個不同的問題。要知道你手上遇到的是哪一個。別々の問題である。自分が直面しているのがどちらかを見分けること。Dua persoalan yang berbeda. Ketahui mana yang sebenarnya kamu hadapi.
One DLL, many LabVIEW threads一個 DLL、多個 LabVIEW 執行緒一つの DLL、複数の LabVIEW スレッドSatu DLL, banyak thread LabVIEWSeveral threads calling the same function need synchronisation. LabVIEW's multithreading is the whole reason to drop into C — and the reason it breaks.多個執行緒呼叫同一個函式時必須同步。LabVIEW 的多執行緒正是你要跳進 C 的理由——也正是它會壞掉的理由。複数のスレッドが同じ関数を呼ぶなら同期が要る。LabVIEW のマルチスレッドこそ C に降りる理由であり、同時に壊れる理由でもある。Beberapa thread yang memanggil fungsi yang sama membutuhkan sinkronisasi. Multithreading LabVIEW adalah seluruh alasan untuk turun ke C — sekaligus alasan mengapa ia rusak.
Reentrant vs thread-safereentrant 與 thread-safe 的差異リエントラントとスレッドセーフの違いReentrant vs thread-safeNot the same property. A function can be one without being the other.這不是同一件事。一個函式可以是其中之一而不是另一個。同じ性質ではない。片方だけを満たす関数もあり得る。Bukan sifat yang sama. Sebuah fungsi bisa memiliki yang satu tanpa memiliki yang lain.
Race condition and deadlockrace condition 與 deadlockレースコンディションとデッドロックRace condition dan deadlockHow each arises, and why they show up once a day instead of once a run.各自是怎麼發生的,以及為什麼它們是一天出現一次,而不是每次執行都出現。それぞれがどう起きるか、そしてなぜ毎回ではなく一日に一度だけ現れるのか。Bagaimana masing-masing muncul, dan mengapa keduanya menampakkan diri sekali sehari alih-alih sekali per jalan.
Critical sectioncritical sectionクリティカルセクションCritical sectionWhat it is, how it relates to the two above, and why it is the answer to both.它是什麼、和上面兩件事的關係,以及為什麼它是兩者的解答。それが何か、上の二つとどう関係するか、そしてなぜ両方の答えになるのか。Apa itu, bagaimana kaitannya dengan kedua hal di atas, dan mengapa ia adalah jawaban untuk keduanya.
Atomic operationsatomic 操作アトミック操作Operasi atomikWhat the CPU guarantees on its own, without a lock.在不上鎖的情況下,CPU 自己保證了什麼。ロック無しで CPU 自身が保証してくれるものは何か。Apa yang dijamin CPU dengan sendirinya, tanpa lock.
Language mechanics people skip大家跳過的語言機制みんなが飛ばす言語の仕組みMekanika bahasa yang sering dilewati
The parts of C that separate code you can maintain from code you can only rewrite.C 語言裡把「可維護的程式」和「只能重寫的程式」分開的那些部分。保守できるコードと書き直すしかないコードを分ける、C の部分。Bagian-bagian C yang memisahkan kode yang bisa kamu rawat dari kode yang hanya bisa kamu tulis ulang.
staticstaticstaticstaticFile scope and persistent locals — one keyword, two meanings, both worth knowing.檔案範圍與持續存在的區域變數——同一個關鍵字、兩種意義,兩種都值得懂。ファイルスコープと寿命の続くローカル変数——一つのキーワードに二つの意味、どちらも知る価値がある。Cakupan berkas dan variabel lokal yang persisten — satu kata kunci, dua makna, keduanya perlu diketahui.
Function call vs macro函式呼叫與 macro 的差異関数呼び出しとマクロの違いPemanggilan fungsi vs makroA call is not free. Know when that cost matters and what a macro gives up in exchange.呼叫不是免費的。要知道那個成本什麼時候會有影響,以及 macro 用什麼換來速度。呼び出しはただではない。そのコストがいつ効いてくるか、マクロが引き換えに何を捨てているかを知ること。Sebuah pemanggilan tidak gratis. Ketahui kapan biaya itu berarti dan apa yang dilepaskan sebuah makro sebagai gantinya.
Function pointers inside structsstruct 裡的函式指標構造体の中の関数ポインタPointer fungsi di dalam structThis is how you get C++-shaped code out of C, and how the Qualcomm- and MediaTek-class SDKs are written. Miss this pattern and their source stays unreadable.這就是用 C 寫出 C++ 形狀程式的方法,也是 Qualcomm、MediaTek 這個等級的 SDK 的寫法。不懂這個 pattern,他們的原始碼你就一直讀不懂。C で C++ のような形のコードを書く方法であり、Qualcomm や MediaTek クラスの SDK の書き方でもある。このパターンを知らなければ、彼らのソースは読めないままだ。Inilah cara mendapatkan kode berbentuk C++ dari C, dan cara SDK sekelas Qualcomm dan MediaTek ditulis. Lewatkan pola ini dan kode sumber mereka akan tetap tak terbaca.
union vs structunion 與 struct 的差異union と struct の違いunion vs structOverlapping storage against adjacent storage.重疊的儲存空間,對上相鄰的儲存空間。重なった記憶域か、隣り合った記憶域か。Penyimpanan yang bertumpang tindih melawan penyimpanan yang berdampingan.
Arrays through pointers用指標操作陣列ポインタによる配列操作Larik lewat pointerWhat an array name really is, and exactly where the equivalence with a pointer stops.陣列名字到底是什麼,以及它和指標的等價關係到哪裡為止。配列名が実際には何であり、ポインタとの等価性がどこで途切れるのか。Apa sebenarnya nama sebuah larik itu, dan di titik mana tepatnya kesetaraannya dengan pointer berhenti.
Call by value vs by addresscall by value 與 call by address値渡しとアドレス渡しPemanggilan lewat nilai vs lewat alamatRead C99: both are call by value. One of them just happens to pass an address.去看 C99:兩個都是 call by value。只是其中一個傳的剛好是位址。C99 を読むこと:どちらも値渡しであり、片方はたまたまアドレスを渡しているだけだ。Baca C99: keduanya adalah pemanggilan lewat nilai. Salah satunya kebetulan saja melewatkan sebuah alamat.
Data structures資料結構データ構造Struktur data
Concepts, not implementations — except the one you should write by hand.重點是觀念,不是實作——除了那個你應該親手寫一次的。実装ではなく概念で足りる——一つだけ、手で書くべきものを除いて。Konsep, bukan implementasi — kecuali satu yang sebaiknya kamu tulis dengan tangan.
Queue and stackqueue 與 stackキューとスタックQueue dan stackMost day-to-day work turns out to be one of these two.日常工作裡碰到的,多半就是這兩個之一。日々の作業で出てくるのは、たいていこの二つのどちらかだ。Sebagian besar pekerjaan sehari-hari ternyata adalah salah satu dari kedua ini.
Linked listlinked list連結リストLinked listImplement one yourself once. The pointer practice is the actual exercise.自己實作一次。真正在練的是指標。一度は自分で実装すること。本当の練習はポインタの方だ。Implementasikan satu sendiri, sekali saja. Latihan pointer-nya itulah inti latihan yang sebenarnya.
Trees and graphs樹與圖木とグラフTree dan grafHave the concept even if you never write one.就算一輩子不會寫,也要有觀念。書く機会が無くても、概念は持っておくこと。Pahami konsepnya walaupun kamu tidak pernah menulisnya.
Reading over writing讀懂比寫出來更重要書くより読めることMembaca lebih penting daripada menulisGenerating small examples with AI is fine. Being able to read them is the requirement.用 AI 產生小範例沒問題。要求是你要看得懂。小さな例を AI に作らせるのは構わない。要求されるのは、それを読めることだ。Membuat contoh kecil dengan AI tidak masalah. Yang dituntut adalah kemampuan membacanya.
The machine underneath底下那台機器その下にある機械Mesin di bawahnya
Where performance comes from once the algorithm is already right.當演算法已經正確之後,效能是從哪裡來的。アルゴリズムが正しくなった後、性能がどこから来るのか。Dari mana kinerja itu datang, setelah algoritmanya sendiri sudah benar.
Why cache hits matter為什麼 cache hit 很重要なぜキャッシュヒットが効くのかMengapa cache hit itu pentingA layout that fits the cache beats a cleverer algorithm that does not — and how to write for it.塞得進 cache 的資料排列,會贏過塞不進去的聰明演算法——以及要怎麼寫才塞得進去。キャッシュに収まるレイアウトは、収まらない賢いアルゴリズムに勝つ——そのためにどう書くか。Tata letak yang muat di dalam cache mengalahkan algoritma yang lebih pintar tetapi tidak muat — dan bagaimana menulis kode untuk itu.
Inline assembly內嵌組合語言インラインアセンブリAssembly inlineHave the concept, and know the narrow set of cases that call for it.要有觀念,並知道那少數幾種真的需要它的情況。概念を持ち、それが本当に必要になる狭い場面を知っておくこと。Pahami konsepnya, dan kenali kumpulan kasus sempit yang benar-benar memerlukannya.
Out-of-order execution亂序執行アウトオブオーダー実行Eksekusi tak berurutanEvery modern CPU reorders for instruction throughput. Know when a barrier is required to keep that from being wrong.現代 CPU 都會為了指令吞吐量重排順序。要知道什麼時候必須下 barrier,才不會因此出錯。現代の CPU は命令スループットのために順序を入れ替える。それが誤りにならないよう、いつバリアが必要かを知ること。Setiap CPU modern menyusun ulang instruksi untuk throughput. Ketahui kapan sebuah barrier diperlukan agar penyusunan ulang itu tidak menjadi salah.
Trading space for time以空間換時間空間を時間に換えるMenukar ruang dengan waktuDynamic programming and its relatives.動態規劃以及它的親戚們。動的計画法とその仲間たち。Pemrograman dinamis dan kerabat-kerabatnya.
Iteration vs recursion迭代與遞迴反復と再帰Iterasi vs rekursiThe difference, and which problems take either form.兩者的差別,以及哪些問題兩種寫法都成立。両者の違いと、どちらの形でも書ける問題はどれか。Perbedaannya, dan persoalan mana yang bisa mengambil salah satu bentuknya.
One thing worth watching一份值得看的影片見る価値のあるものSatu hal yang layak ditonton
Section 03 · version control · one deck · one server第 03 章 · 版本控制 · 一份投影片 · 一台伺服器セクション 03 · バージョン管理 · スライド一式 · サーバー一台Bagian 03 · kontrol versi · satu dek slide · satu server
GitGit 版本控制Git によるバージョン管理Git
Everything you make here ends up in a repository sooner or later — the worksheet, the
testbench, the Verilog. The deck below is the starting point: what a commit is, what a
branch is, and the handful of commands that cover almost everything you do day to day.
你在這裡做的東西,遲早都會進到 repository:工作單、testbench、Verilog。下面這份投影片是起點:commit 是什麼、branch 是什麼,以及日常幾乎用得完的那幾個指令。ここで作るものは、遅かれ早かれリポジトリに入る——ワークシート、testbench、Verilog。下のスライドが出発点だ:commit とは何か、branch とは何か、そして日々の作業のほとんどを賄う数個のコマンド。Semua yang kamu buat di sini cepat atau lambat berakhir di sebuah repositori — lembar kerja, testbench, Verilog. Dek slide di bawah adalah titik awalnya: apa itu commit, apa itu branch, dan segelintir perintah yang mencakup hampir semua yang kamu lakukan sehari-hari.
The Gitea server runs on a VM inside the lab's private network. It is not reachable from the
open internet, so before you can clone or push anything you need a VPN account and a working
VPN connection. The deck below shows the setup; the steps under it get you the account.
Gitea 伺服器跑在實驗室私有網路裡的一台 VM 上,外網連不到。所以在 clone 或 push 任何東西之前,你需要一個 VPN 帳號和一條能通的 VPN 連線。下面的投影片教你怎麼設定;再下面的步驟教你怎麼拿到帳號。Gitea サーバーは研究室のプライベートネットワーク内の VM で動いている。外のインターネットからは届かないので、clone や push をする前に VPN アカウントと繋がる VPN 接続が要る。下のスライドが設定方法、その下の手順がアカウントの取り方だ。Server Gitea berjalan di sebuah VM di dalam jaringan privat lab. Ia tidak bisa dijangkau dari internet terbuka, jadi sebelum bisa clone atau push apa pun kamu perlu akun VPN dan koneksi VPN yang berfungsi. Dek slide di bawah menunjukkan cara penyiapannya; langkah-langkah di bawahnya mengurus akunnya.
Getting a VPN account申請 VPN 帳號VPN アカウントの申請Mendapatkan akun VPN
Pick an id and a password. Choose the username and password you want for the VPN and send them to me. Use a password you do not use anywhere else.想好帳號和密碼。決定你想要的 VPN 帳號名稱和密碼,然後寄給我。密碼請用一組沒在別處用過的。ID とパスワードを決める。VPN で使いたいユーザー名とパスワードを決めて私に送る。他で使っていないパスワードにすること。Pilih id dan kata sandi. Tentukan nama pengguna dan kata sandi yang kamu inginkan untuk VPN, lalu kirimkan ke saya. Pakai kata sandi yang tidak kamu gunakan di tempat lain.
Wait for my email. I create the account on the VPN server. Once it is done, I email you to say so.等我的 email。我會在 VPN 伺服器上建好帳號。建好之後,我會寄信通知你。私からのメールを待つ。VPN サーバー上にアカウントを作成する。出来たらメールで知らせる。Tunggu email dari saya. Saya membuat akunnya di server VPN. Setelah selesai, saya mengirim email untuk memberitahumu.
Follow the deck. Set up the VPN client with the slides above, connect, and then open gitea.rflab.lan to register your git account.照投影片做。用上面的投影片把 VPN client 設好、連上,然後打開 gitea.rflab.lan 註冊你的 git 帳號。スライドに従う。上のスライドで VPN クライアントを設定して接続し、gitea.rflab.lan を開いて git アカウントを登録する。Ikuti dek slide. Siapkan klien VPN dengan slide di atas, sambungkan, lalu buka gitea.rflab.lan untuk mendaftarkan akun git-mu.
The video part of every hand-in goes through here: one YouTube link per task, saved with a
timestamp so neither of us has to argue about when it arrived. The testbench and the live
demo are still handed in the way the worksheet says.
每一題繳交裡的影片都從這裡交:每題一個 YouTube 連結,存檔時附上時間戳記,我們就不用爭論它是什麼時候交的。testbench 和現場展示還是照工作單上寫的方式交。各課題の提出物のうち動画はここから:課題ごとに YouTube リンク一つ、タイムスタンプ付きで保存されるので、いつ届いたかで揉めることがない。testbench とライブデモはワークシートの指示どおりに提出する。Bagian video dari setiap pengumpulan lewat sini: satu tautan YouTube per tugas, disimpan dengan stempel waktu sehingga kita tidak perlu berdebat kapan ia tiba. Testbench dan demo langsung tetap dikumpulkan seperti yang tertulis di lembar kerja.
How it works流程流れCara kerjanya
Register once. The first time you open the page, enter your email and choose a password. There is no separate sign-up step: that pair becomes your account.只註冊一次。第一次打開頁面時,輸入你的 email,並設一個密碼。沒有另外的註冊流程:這一組就是你的帳號。登録は一度だけ。初めてページを開いたとき、メールアドレスを入力し、パスワードを決める。別の登録手続きは無い。その組がそのままアカウントになる。Daftar sekali. Saat pertama membuka halaman, masukkan email-mu dan pilih kata sandi. Tidak ada langkah pendaftaran terpisah: pasangan itu menjadi akunmu.
The clock starts at registration. You have 30 days from that moment. The days left are shown in the top-left corner every time you sign in, down to zero; links saved after that are still accepted but marked late.倒數從註冊那一刻開始。從那時起你有 30 天。每次登入,左上角都會顯示剩餘天數,一直數到零;之後存的連結仍會收,但會標記為逾期。カウントダウンは登録時に始まる。その時点から 30 日。サインインするたびに左上に残り日数がゼロまで表示される。それ以降に保存したリンクも受け付けるが、遅延と記録される。Hitung mundur dimulai saat pendaftaran. Kamu punya 30 hari dari saat itu. Sisa hari ditampilkan di pojok kiri atas setiap kali masuk, sampai nol; tautan yang disimpan setelahnya tetap diterima tetapi ditandai terlambat.
Paste one link per task and save. Unlisted videos are fine. Paste a new link over an old one to replace it — every save is kept with its timestamp, and the history table shows exactly what I will see.每題貼一個連結,然後儲存。影片設不公開即可。在舊連結上貼新的就能取代——每一次儲存都會連時間戳記保留,歷史表格顯示的就是我會看到的內容。課題ごとにリンクを一つ貼って保存する。限定公開の動画で構わない。古いリンクの上に新しいものを貼れば置き換わる——保存はすべてタイムスタンプ付きで残り、履歴の表に出るものがそのまま私の見るものだ。Tempel satu tautan per tugas dan simpan. Video unlisted tidak masalah. Tempel tautan baru di atas yang lama untuk menggantinya — setiap penyimpanan disimpan dengan stempel waktunya, dan tabel riwayat menunjukkan persis apa yang akan saya lihat.
Answers stay hidden on the worksheet until they are released from the manager console. The
same console lists every student’s latest link per task beside their 30-day countdown,
and the complete timestamped log of what was handed in.
解答在工作單上一直是隱藏的,直到從管理主控台開放為止。同一個主控台會列出每位學生每題最新的連結、旁邊是他們的 30 天倒數,還有完整帶時間戳記的繳交紀錄。解答は管理コンソールから公開するまでワークシート上では隠れている。同じコンソールに、各学生の課題ごとの最新リンクが 30 日カウントダウンと並んで表示され、提出物の完全なタイムスタンプ付きログも見られる。Jawaban tetap tersembunyi di lembar kerja sampai dilepas dari konsol manajer. Konsol yang sama mencantumkan tautan terbaru setiap mahasiswa per tugas di samping hitung mundur 30 hari mereka, dan log lengkap berstempel waktu dari apa yang dikumpulkan.
Manager console管理主控台管理コンソールKonsol manajer
Sign in with the same user and password as the visitor statistics page. The credentials live on the server, not in this page, and are changed from the statistics page.用與訪客統計頁相同的帳號密碼登入。憑證存在伺服器上,不在這個頁面裡;要改密碼請到統計頁。訪問統計ページと同じユーザー名とパスワードでサインインする。認証情報はこのページではなくサーバ側にあり、変更は統計ページから行う。Masuk dengan pengguna dan kata sandi yang sama dengan halaman statistik pengunjung. Kredensialnya ada di server, bukan di halaman ini, dan diubah dari halaman statistik.
Answer release — one switch per task, saved on the server so every student’s worksheet follows it.解答開放——每題一個開關,存在伺服器上,所有學生的工作單都會跟著變。解答の公開——課題ごとにスイッチ一つ。サーバに保存され、全学生のワークシートに反映される。Pelepasan jawaban — satu sakelar per tugas, disimpan di server sehingga lembar kerja setiap mahasiswa mengikutinya.
Class overview — every registered email, days left, and the latest link per task, late ones in red.全班總覽——每個已註冊的 email、剩餘天數、每題最新連結,逾期的標紅。クラス概観——登録済みの全メール、残り日数、課題ごとの最新リンク。遅延は赤。Ikhtisar kelas — setiap email terdaftar, sisa hari, dan tautan terbaru per tugas, yang terlambat berwarna merah.
Submission log — every save with its timestamp, filterable by email, downloadable as CSV.繳交紀錄——每一次儲存與時間戳記,可依 email 篩選,可下載 CSV。提出ログ——タイムスタンプ付きの全保存記録。メールで絞り込め、CSV でダウンロードできる。Log pengumpulan — setiap penyimpanan dengan stempel waktunya, dapat disaring per email, dapat diunduh sebagai CSV.
The release gate is a convenience, not a lock: the answers ship inside this page, so anyone who
opens the source can read them regardless of the switches.
開放關卡只是方便,不是鎖:解答就在這個頁面裡,任何人打開原始碼都讀得到,跟開關無關。公開ゲートは便宜であってロックではない:解答はこのページ内にあるので、ソースを開けばスイッチに関係なく読める。Gerbang pelepasan adalah kemudahan, bukan kunci: jawabannya ada di dalam halaman ini, jadi siapa pun yang membuka sumbernya bisa membacanya terlepas dari sakelar.