กลับไปหน้ารวมไฟล์
yetanother-usb-oscilloscope-255bf0.md

title: "YetAnotherUSB Oscilloscope: ปลดล็อกพลัง 350kSps ของ Arduino Zero/MKR ด้วย USB Isochronous"

โปรเจกต์ Oscilloscope ส่วนใหญ่ที่ใช้บอร์ดตระกูล Arduino Zero หรือ MKR มักจะติดข้อจำกัดสำคัญอยู่สองประการ:

  1. การใช้ Sound Card ของคอมพิวเตอร์: ซึ่งจำกัด Bandwidth และความแม่นยำของแรงดันไฟฟ้า
  2. การใช้พอร์ต USB ผ่าน Protocol Bulk Transfer: แม้จะเป็น USB 2.0 แต่ Protocol นี้ถูกจำกัดความเร็วไว้ที่ 64 bytes ต่อมิลลิวินาที (ตามมาตรฐาน USB 2.0 Full Speed CDC) ซึ่งไม่เพียงพอสำหรับการส่งข้อมูลความละเอียดสูงแบบ Real-time

บทความนี้จะพาคุณไปพบกับแนวทางการวิศวกรรมเพื่อทำลายขีดจำกัดดังกล่าว และดึงประสิทธิภาพสูงสุดของชิป SAMD21 ออกมาใช้งานจริง

ความท้าทายในเชิงตัวเลข (The Engineering Challenge)

หัวใจหลักของ Arduino Zero/MKR คือชิป SAMD21G18 (ARM Cortex-M0+) ซึ่งมีโมดูล ADC (Analog-to-Digital Converter) ขนาด 12-bit ที่สามารถทำ Sampling Rate ได้สูงถึง 350kSps (350,000 ตัวอย่างต่อวินาที) นี่คือสเปกที่น่าทึ่งมากสำหรับไมโครคอนโทรลเลอร์ระดับนี้ แต่คำถามคือเราจะส่งข้อมูลมหาศาลนี้เข้าคอมพิวเตอร์เพื่อแสดงผลที่ 60Hz (ทุกๆ 16ms) ได้อย่างไร?

ลองคำนวณดู:

  • ที่ 60Hz หรือ 16ms ต่อเฟรม หากเราต้องการ Sampling ที่ 350kSps
  • เราจะมีข้อมูลทั้งหมด: 5,600 Samples ต่อ 16ms
  • ข้อมูล 1 Sample ประกอบด้วย: Overhead + ข้อมูล ADC (12-bit) + Timestamp (12-bit) รวมแล้วประมาณ 3 ถึง 6 bytes
  • ดังนั้น ข้อมูลที่ต้องส่งคือ: 5,600 x (3 ถึง 6) = 16,800 ถึง 33,600 bytes ต่อ 16ms

เปรียบเทียบกับขีดจำกัดของ USB 2.0 Full Speed:

  • USB Bulk Transfer: ส่งได้ 64 bytes/ms ≈ 1,024 bytes/16ms (ไม่พออย่างมาก!)
  • USB Isochronous Transfer: ส่งได้ 1,023 bytes/ms ≈ 16,368 bytes/16ms (เข้าใกล้เป้าหมายมากขึ้น)

ภาพด้านล่างแสดงคุณสมบัติหลักและการจัดการข้อมูลของแอปพลิเคชันนี้:

การออกแบบระบบ (System Architecture)

เพื่อให้ได้ประสิทธิภาพสูงสุด เราจำเป็นต้องใช้เทคนิค Multi-threading ทั้งในฝั่ง Hardware และ Software เพื่อให้การรับข้อมูล (Data Capture) และการแสดงผล (Rendering) ทำงานขนานกันไปได้

แอปพลิเคชันนี้แบ่งการทำงานออกเป็น 3 Thread หลัก:

  1. C# Graphical User Interface (UI): รับผิดชอบส่วนติดต่อผู้ใช้ แยกออกมาจากงานหลักเพื่อให้ความหน่วงของ UI ไม่ไปรบกวนกระบวนการรับส่งข้อมูล
  2. C++ DLL (OpenGL): ใช้ Native C DLL ในการหุ้ม (Wrap) หน้าต่าง OpenGL เพื่อให้การวาดกราฟเส้นสัญญาณเป็นหน้าที่ของ GPU โดยตรง ซึ่ง OpenGL เป็น Library ที่มีประสิทธิภาพสูงและรองรับหลาย Platform
  3. C++ DLL (WinUSB): ส่วนนี้สำคัญที่สุด คือการใช้ Driver winusb.sys เพื่อจัดการการรับส่งข้อมูลแบบ Isochronous.
    • ทำไมต้อง Isochronous? เพราะเป็น Mode ที่เน้น "Streaming" ข้อมูลเป็นหลัก โดยยอมเสียสละเรื่อง Data Integrity Check (การตรวจสอบความถูกต้องของข้อมูลซ้ำ) เพื่อแลกกับความเร็วและความต่อเนื่องของ Bandwidth ทำให้เราส่งข้อมูลได้ถึง 1023 bytes ทุกๆ 1ms
Wireshark capture แสดงการส่งข้อมูลผ่าน Isochronous Transfer

วิเคราะห์ประสิทธิภาพจากการทดสอบจริง

จากการวิเคราะห์ผ่าน Wireshark และการ Monitor ระบบ พบข้อมูลที่น่าสนใจดังนี้:

  • เราสามารถทำ Sampling ได้ที่ประมาณ 270kSps ในขณะที่ระบบกำลังรัน (สาเหตุที่ลดลงจาก 350kSps เพราะ CPU ต้องแบ่งทรัพยากรไปจัดการ USB Stack ของ Arduino ด้วย)
  • การรวบรวมและส่งข้อมูลขนาด 1023 bytes ผ่านพอร์ต USB ใช้เวลาประมาณ 6.7ms ซึ่งคิดเป็น 264 samples ต่อชุดข้อมูล
  • กระบวนการเตรียมข้อมูล (Transform), สร้างกราฟ (Build) และวาดลงจอ (Draw) ใช้เวลารวมเพียง 2.1ms (0.15 + 0.35 + 1.6ms ตามลำดับ)
  • Total Frame Rate ที่วัดได้ใน OpenGL อยู่ที่ประมาณ 9.2ms ซึ่งเร็วกว่าเป้าหมายที่ 16ms มาก ทำให้เราสามารถเพิ่มจำนวน Sample ต่อเฟรมเป็น 2048 ได้โดยที่ภาพยังลื่นไหล

ขั้นตอนการติดตั้งและเตรียมอุปกรณ์

แอปพลิเคชันนี้มีความเป็น "Experimental" สูง ดังนั้นการติดตั้งจึงต้องอาศัยทักษะทางเทคนิคระดับหนึ่ง:

  1. ฝั่ง Arduino: บอร์ดต้องมีระบบ Isochronous USB ติดตั้งไว้ ซึ่งปกติ ArduinoCore ทั่วไปจะไม่รองรับ ในโปรเจกต์นี้มี Code สำหรับขยายความสามารถ (Extension) ของ ArduinoCore มาให้ เพื่อให้บอร์ดรองรับพอร์ต Isochronous โดยที่ยังสามารถใช้ Serial.print ได้ตามปกติ
  2. ฝั่ง Windows (Driver): คุณต้องติดตั้งไฟล์ WinUSB.inf โดยต้องรัน Windows ใน Test Mode เนื่องจากตัว Driver ยังไม่มี Digital Certificate ที่เป็นทางการ
  3. ฝั่ง Software: Source Code บน GitHub ยังไม่ได้ทำการ Compile (Uncompiled) เพื่อสนับสนุนให้นักพัฒนาท่านอื่นนำไปปรับแต่ง (Adjust) และ Build ขึ้นมาเองตามความเหมาะสมของระบบ

ข้อจำกัดและการพัฒนาในอนาคต

โปรเจกต์ "YetAnotherUSB Oscilloscope" พัฒนาขึ้นบน Visual Studio 2019 ด้วย .NET Framework ล่าสุด และทดสอบบนระบบ 64-bit เท่านั้น:

  • ความเสถียร: ระบบ Multi-threading ยังไม่ Robust เต็มที่ อาจเกิด Infinite Loop ได้ในกรณีที่ดึงสาย USB ออกกะทันหันระหว่างอ่านค่า
  • ฟีเจอร์ที่ขาดหาย: ปัจจุบันยังไม่มีระบบ FFT (Fast Fourier Transform), Triggers ที่ซับซ้อน และความสามารถในการบันทึกข้อมูล (Memorizing)

หวังว่าโปรเจกต์นี้จะเป็นแรงบันดาลใจและเป็นฐานข้อมูลที่ดีสำหรับวิศวกรหรือ Maker ที่ต้องการดึงพลังแฝงของ Arduino ออกมาใช้งานในระดับสูงครับ!

Keep Making!

ข้อมูล Frontmatter ดั้งเดิม

title: "YetAnother USB Oscilloscope"
description: "A USB based oscilloscope that squeezes everything out of the Arduino MKR / Zero ADC. It features Isochronous WinUSB transfer and OpenGL."
author: "alexisvanbaelen"
category: "Lab Stuff"
tags:
  - "arduino mkr"
  - "isochronous"
  - "winusb"
  - "opengl"
  - "usb"
views: 9224
likes: 5
price: 1499
difficulty: "Intermediate"
components:
  - "1x Arduino Zero"
tools: []
apps:
  - "1x Visual Studio 2019"
  - "1x Arduino IDE"
downloadableFiles:
  - "https://github.com/abaelen/YetAnother-USB-Oscilloscope/tree/master/YetAnotherUSBOscilloscope"
  - "https://github.com/abaelen/YetAnother-USB-Oscilloscope/tree/master/Arduino_ADC_with_Isochronous_USB"
  - "https://github.com/abaelen/YetAnother-USB-Oscilloscope/tree/master/Arduino_ADC_with_Isochronous_USB"
documentationLinks: []
passwordHash: "51aa071129c6ab0f16d2036f80ced4b7882fe7a35554a42f0b4824f028926d8f"
encryptedPayload: "U2FsdGVkX1/c1UVtRfugi5A9YVH6bWJo4X9DpuYAaVUYSepBVoR2l0UDwHB+49Kk+31GXU3ThYJC7gf8pmKcuZ1KpguGJoBwlvMNQ/rdjDuAg6ncU1BuAOBhXdhUBFxq"
seoDescription: "A high-performance USB Oscilloscope for Arduino MKR / Zero ADC featuring Isochronous WinUSB transfer and OpenGL visualization."
videoLinks: []
heroImage: "https://cdn.jsdelivr.net/gh/bigboxthailand/arduino-assets@main/images/projects/yetanother-usb-oscilloscope-255bf0_cover.jpg"
lang: "en"