PIO Signaling and Measurement
การสร้างสัญญาณเอาต์พุตโดยใช้ PIO ของ RP2040 และการวัดสัญญาณเอาต์พุตจริงโดยใช้ออสซิลโลสโคปแบบดิจิทัล -- เริ่มต้นเขียนเมื่อวันที่ 15 กุมภาพันธ์ พ.ศ. 2564
โค้ดตัวอย่างที่ 1
มาเริ่มต้นด้วยการอ่านค่าความถี่ของ RP2040 ที่ใช้สำหรับไมโครไพธอน ดังนี้
และจะได้ข้อความเอาต์พุตดังนี้ (ซึ่งจะได้ความถี่เท่ากับ 125 MHz)
CPU frequency: 125 MHz
ถ้าลองเขียนโค้ดไมโครไพธอน เพื่อเปิดใช้งานขา GPIO เช่น ขา GP14 ให้เป็นเอาต์พุต และใช้คำสั่งเพื่อเปลี่ยนสถานะลอจิก High และ Low ตามลำดับ และทำซ้ำไปเรื่อย ๆ แบบ while
จากนั้นลองวัดสัญญาณเอาต์พุตที่ได้
จากรูปคลื่นสัญญาณที่ได้จะเห็นว่า สัญญาณมีการเปลี่ยนแปลงสถานะลอจิก แต่มีคาบเวลาที่ไม่คงที่ ค่อนข้างเลื่อนไปมา หรือมี Jitter เกิดขึ้นอย่างเห็นได้ชัด
โค้ดตัวอย่างที่ 2
ตัวอย่างนี้ลองสร้างสัญญาณเอาต์พุตที่ขา GP14 เป็นเอาต์พุต และเขียนโปรแกรมสำหรับ PIO โดยเลือกใช้ StateMachine หมายเลข 0 (SM0) และใช้คำสั่ง set()
เพื่อทำให้ขา GP14 เปลี่ยนหรือสลับสถานะลอจิก 1 กับ 0 ตามลำดับ ให้ทำซ้ำไปเรื่อย ๆ เริ่มต้นมีสถานะลอจิกเป็น Low และในการทำงานของ SM0 ได้เลือกใช้ความถี่ เช่น 2 MHz
การทำคำสั่ง set()
จะใช้เพียงหนึ่งไซเคิลเท่านั้น ดังนั้นถ้าทำสองคำสั่งที่อยู่ระหว่าง wrap_target()
กับ wrap()
ก็จะใช้ 2 ไซเคิล ความถี่เอาต์พุตที่ควรจะได้คือ 2 MHz /2 = 1 MHz
ข้อสังเกต: การใช้พารามิเตอร์ set_base
เป็นการกำหนดหมายเลขของขาเริ่มต้น (ใช้ได้สูงสุดถึง 5 ขา ที่เรียงติดกัน) และจะนำไปใช้กับ SM ในตัวอย่างนี้ได้ระบุอาร์กิวเนนต์เป็น Pin(14)
มีเพียงขาเดียวเท่านั้น และในส่วนของ Python decorator @asm_pio(
) มีการใช้พารามิเตอร์ set_init
เพื่อกำหนดทิศทางเป็นเอาต์พุตและกำหนดค่าเริ่มต้น โดยระบุอาร์กิวเมนต์เป็น (PIO.OUT_LOW)
หรือจะเปลี่ยนไปใช้วิธี Side Setting แทนก็ได้
ถ้าเปลี่ยนความถี่ในการทำงานของ SM0 จาก 2 MHz ให้เป็น 50 MHz ความถี่ของสัญญาณเอาต์พุตที่ได้ควรจะเป็น 50 MHz /2 = 25 MHz ตามรูปคลื่นสัญญาณที่วัดได้จะเห็นว่า มีลักษณะไม่เป็นคลื่นสี่เหลี่ยม แต่มีอัตราการเปลี่ยนระดับแรงดันไฟฟ้าสองระดับ เท่ากับ 25 MHz
โค้ดตัวอย่างที่ 3
ตัวอย่างนี้คล้ายกับตัวอย่างที่แล้ว แต่มีการเปลี่ยนจากการใช้คำสั่ง wrap_target()
และ wrap()
เพื่อกำหนดขอบเขตการทำลำดับของคำสั่งแบบวนซ้ำโดยอัตโนมัติ มาเป็นการใช้คำสั่ง label()
และ jmp()
แทน
คำสั่ง set()
มีการใช้งานอยู่ 2 คำสั่ง ตามลำดับ ใช้สำหรับกำหนดสถานะลอจิกของขาเอาต์พุต (ใช้ขา GP14
เพียงขาเดียวในตัวอย่างนี้) ให้เป็น High และ Low สลับกันไป (เริ่มต้นมีสถานะลอจิกเป็น Low)
เมื่อทำคำสั่ง set()
ทั้งสองคำสั่งแล้ว จึงทำคำสั่ง jmp()
เพื่อให้ย้อนกลับไปเริ่มทำคำสั่งที่อยู่ถัดไปจากบรรทัดที่มีการประกาศ label()
โดยรวมทั้งหมด มี 3 คำสั่ง แต่ละคำสั่งใช้เวลาหนึ่งไซเคิล ดังนั้นจึงใช้ 3 ไซเคิล ต่อหนึ่งรอบ
ในตัวอย่างนี้ได้เลือกใช้ความถี่สำหรับ SM0 ของ PIO ให้เท่ากับ 5 MHz ดังนั้น จะได้ความถี่ของสัญญาณเอาต์พุตเท่ากับ 5 MHz /3 = 1.667 MHz มีช่วงเวลาที่เป็น High : Low เท่ากับ 1 : 2 หรือมีค่า Duty Cycle = 33.33%
โค้ดตัวอย่างที่ 4
จากโค้ดตัวอย่างที่ 3 ลองมาเพิ่มการหน่วงเวลา (delay) หลังจากทำคำสั่ง set()
แต่ละคำสั่งดูบ้าง โดยเขียนจำนวนไซเคิล (เป็นค่าคงที่เลขจำนวนเต็มบวกขนาดไม่เกิน 5 บิต หรือ 1..31) ในวงเล็บสี่เหลี่ยมต่อท้ายคำสั่ง เช่น [1]
หมายถึง หน่วงเวลาไว้หนึ่งไซเคิลหลังจากทำคำสั่งนั้นเสร็จแล้ว
จากนั้นมาลองวัดสัญญาณเอาต์พุตดูว่า มีการเปลี่ยนแปลงไปอย่างไร
จากรูปสัญญาณเอาต์พุตที่ได้ จะเห็นว่า มีความถี่ 1 MHz และความกว้างช่วงที่เป็น High และ Low มีอัตราส่วน 2:3 หรือ Duty Cycle = 40%
โค้ดตัวอย่างที่ 5
ตัวอย่างนี้สาธิตการใช้งานขา GPIO จำนวน 2 ขา คือ GP14 และ GP15 โดยใช้เป็นเอาต์พุตเหมือนกันและจะถูกกำหนดสถานะลอจิกโดย StateMachine (SM) ของ PIO แต่ใช้งานต่างรูปแบบกัน เช่น ได้เลือกใช้ GP14 ใช้กับคำสั่ง set()
แต่ GP15 ใช้สำหรับ .side()
ในรูปแบบที่เรียกว่า Side Setting เกิดขึ้นพร้อมกับการคำสั่งในบรรทัดเดียวกัน
ความถี่ในการทำงานของ SM ในตัวอย่างนี้คือ 2 MHz ดังนั้น ความถี่ของสัญญาณเอาต์พุตที่ได้จากขา GP14 และ GP15 คือ 2 MHz /2 = 1 MHz แต่สถานะลอจิกของขาทั้งสองจะต่างกัน
โค้ดตัวอย่างที่ 6
ตัวอย่างนี้สาธิตการใช้ StateMachine พร้อมกัน 4 ชุด (เลือกใช้ SM 0,1,2,3 ของ PIO 0) ให้สร้างสัญญาณเอาต์พุตที่ขา GP13, GP12, GP11, GP10 ตามลำดับ และให้รอสัญญาณอินพุตที่ขา GP14 เปลี่ยนจาก High เป็น Low ก่อน ซึ่งได้จากการต่อวงจรปุ่มกดจากภายนอก จากนั้นจึงเริ่มทำงาน
วงจร SM0 - SM3 จะเริ่มต้นสร้างสัญญาณพัลส์ไม่พร้อมกัน เนื่องจากมีการใช้คำสั่ง nop() [...]
และหน่วงเวลาไว้แตกต่างกัน ก่อนเริ่มทำลำดับคำสั่งที่วนซ้ำระหว่าง wrap_target()
และ wrap()
การทำงานของ SM0 - SM3 ใช้ความถี่ 2 MHz และในการทำงานแต่ละรอบของกลำดับคำสั่งจะใช้เวลาเท่ากับ 4 ไซเคิล ดังนั้นจะได้ความถี่ 2 MHz /4 = 500 kHz
โค้ดตัวอย่างที่ 7
ตัวอย่างนี้สาธิตการเขียนโค้ดเพื่อให้ PIO คอยตรวจสอบอินพุตแล้วให้เอาต์พุตเปลี่ยนสถานะของเอาต์พุตตามสถานะของอินพุตที่อ่านเข้ามา และใช้วงจรปุ่มกดสร้างสัญญาณอินพุต ไม่กดได้ลอจิก High และแต่ถ้ากดปุ่มค้างไว้จะได้ลอจิก Low
ขา GP14 ถูกเลือกใช้เป็นขาอินพุต และขา GP15 ถูกเลือกใช้เป็นขาเอาต์พุต และกำหนดความถี่ในการทำงานเท่ากับ 5 MHz (1 Cycle = 200 ns)
โค้ดตัวอย่างที่ 8
ตัวอย่างนี้คล้ายตัวอย่างที่ 7 แต่ใช้วิธีตรวจสอบสถานะของอินพุตที่ขา GP14 โดยใช้การเลื่อนบิตเข้ามาหนึ่งตำแหน่ง ซึ่งจะเก็บไว้ใน ISR (Input Shift Register) จากนั้นก็สำเนาค่าจาก ISR ไปยัง OSR (Output Shift Register) แล้วเลื่อนบิตออกไปหนึ่งตำแหน่งไปยังขาเอาต์พุตที่ขา GP15
กล่าวสรุป
เนื้อหาในส่วนนี้ได้นำเสนอตัวอย่างโค้ดไมโครไพธอน เพื่อนำไปทดลองใช้งานกับบอร์ด Raspberry Pi Pico (RP2040) สาธิตการทำงานของวงจร Programmable I/O (PIO) ที่อยู่ภายใน และใช้เครื่องมือวัดออสซิลโลสโคปในการวัดสัญญาณ I/O เพื่อให้เห็นพฤติกรรมการทำงานของ PIO เช่น การเปลี่ยนแปลงของสัญญาณและการตอบสนองในเชิงเวลาที่เกิดจากการทำงานคำสั่งพื้นฐานของ PIO
Last updated