120 likes | 226 Vues
การสื่อสารกับบอร์ด MCU ผ่านพอร์ต USB. ปฏิบัติการเกี่ยวกับวิศวกรรมคอมพิวเตอร์ (01204223). ผศ.ดร.ชัยพร ใจแก้ว ภาควิชาวิศวกรรมคอมพิวเตอร์ คณะวิศวกรรมศาสตร์ มหาวิทยาลัยเกษตรศาสตร์. สถาปัตยกรรม USB. อุปกรณ์ด้านหนึ่งทำหน้าที่เป็นโฮสท์ (Host) อีกด้านหนึ่งทำหน้าที่เป็นดีไวซ์ (Device)
E N D
การสื่อสารกับบอร์ด MCUผ่านพอร์ต USB ปฏิบัติการเกี่ยวกับวิศวกรรมคอมพิวเตอร์(01204223) ผศ.ดร.ชัยพร ใจแก้ว ภาควิชาวิศวกรรมคอมพิวเตอร์คณะวิศวกรรมศาสตร์ มหาวิทยาลัยเกษตรศาสตร์
สถาปัตยกรรม USB • อุปกรณ์ด้านหนึ่งทำหน้าที่เป็นโฮสท์ (Host) อีกด้านหนึ่งทำหน้าที่เป็นดีไวซ์ (Device) • ไม่ว่าจะเขียนข้อมูลไปยังดีไวซ์ หรืออ่านข้อมูลจากดีไวซ์ ฝั่งโฮสท์ต้องมีการส่งคำร้องขอ (request) ไปก่อนเสมอ Request PC - Notebook - USB Host USBDevice - Flash drive - Mouse - Game controller - etc. DeviceDriver App USB Cable Response
โครงสร้างของคำร้องขอ • ประกอบด้วยข้อมูล 5 ส่วน • RequestType (1 ไบท์) – ทิศทางการส่งข้อมูล • Request (1 ไบท์) – หมายเลขคำร้องขอ • Value (2 ไบท์) – พารามิเตอร์ประกอบคำร้องเพิ่มเติม • Index (2 ไบท์) – พารามิเตอร์ประกอบคำร้องเพิ่มเติม • Length (2 ไบท์) – จำนวนไบท์ของข้อมูลที่ต้องการส่งให้หรือรับจากดีไวซ์
โค้ดตัวอย่าง • ดาวน์โหลดได้จาก http://www.cpe.ku.ac.th/~cpj/204223/usb-example.tgz • แตกไฟล์ไว้ในเครื่องของตนโดยเรียกคำสั่งเชลล์ • ในไฟล์ตัวอย่างประกอบด้วย • ไลบรารี V-USB • main.c –ตัวอย่างเฟิร์มแวร์ฝั่งดีไวซ์ • practicum.py – ไพธอนมอดูลสำหรับฝั่งโฮสท์ • peri.py – ไฟล์เริ่มต้นสำหรับทำแบบฝึกหัด • test-usb.py – โค้ดสำหรับทดสอบแบบฝึกหัด • Makefile $ tar zxf usb-example.tgz
เฟิร์มแวร์ฝั่งดีไวซ์ (บอร์ด MCU) • อาศัยไลบรารี V-USB จำลองกลไก USB ด้วยซอฟต์แวร์ • แก้ไขการตั้งค่าในไฟล์ usbconfig.h • เปลี่ยน USB_CFG_DEVICE_NAME ให้เป็น Practicum Group XX โดย XX เป็นหมายเลขกลุ่ม(อย่าลืมระบุความยาวสตริงให้ถูกต้อง) • โค้ดในเมนลูปมีการเรียกฟังก์ชัน usbPoll() เพื่อตรวจสอบคำร้องขอจากฝั่งโฮสท์ • เมื่อได้รับคำร้องขอ ไลบรารี V-USB จะเรียกฟังก์ชัน usbFunctionSetup() โดยอัตโนมัติ • ต้องเขียนฟังก์ชันนี้ขึ้นมาเอง
ตัวอย่างฟังก์ชัน usbFunctionSetup usbMsgLen_t usbFunctionSetup(uint8_t data[8]) { usbRequest_t *rq = (void *)data; static uint16_t returnedData; if (rq->bRequest == 0) { /* Do something */ return 0; } else if (rq->bRequest == 1) { /* Do something */ usbMsgPtr = (uchar*) &returnedData; return sizeof(returnedData); } return 0; } ตรวจสอบหมายเลขคำร้อง ตอบสนองคำร้องขอที่ไม่ขอข้อมูลคืน- ให้ฟังก์ชันคืนค่า 0 ตอบสนองคำร้องขอที่ต้องการข้อมูลคืน- ให้ตัวแปร usbMsgPtr ชี้ที่ตำแหน่งของข้อมูลที่ต้องการส่งให้โฮสท์- ให้ฟังก์ชันคืนค่าจำนวนไบท์ที่ต้องการส่งให้โฮสท์
โครงสร้างคำร้องขอ • มีขนาด 8 ไบท์ นิยามไว้แล้วในสตรัค usbRequest_t (ในไฟล์ usbdrv/usbdrv.h) ดังนี้ • ucharถูกนิยามให้เป็นชนิดข้อมูล unsigned char (ซึ่งเทียบเท่ากับ uint8_t) ส่วน usbWord_tนิยามเป็นชนิด union ดังนี้ typedefstruct usbRequest{ uchar bmRequestType; /* 1ไบท์*/ uchar bRequest; /* 1ไบท์*/ usbWord_t wValue; /* 2ไบท์*/ usbWord_t wIndex; /* 2ไบท์*/ usbWord_t wLength; /* 2ไบท์*/ }usbRequest_t; typedefunion usbWord{ unsigned word; uchar bytes[2]; }usbWord_t;
โปรแกรมฝั่งโฮสท์ (ไพธอน) • อาศัยไลบรารี PyUSB • ทดสอบโดยเรียกคำสั่ง import usbในไพธอน • (Linux) หากไม่พบให้ติดตั้งโดยใช้คำสั่ง • (MacOS) หากไม่พบให้ดาวน์โหลด libusb1.0 จาก SourceForge • มอดูล practicum.py เตรียมคลาส McuBoard ไว้ให้ใช้งานได้สะดวกขึ้น $ sudo apt-get install python-usb >>> from practicum import McuBoard >>> b = McuBoard() >>> help(b)
ตัวอย่างการส่งคำร้อง >>> from practicum import McuBoard >>> b = McuBoard() # สั่งให้ LED สีเขียว (หมายเลข 2) บน Peripheral board ติด >>> b.usb_write(0, index=2, value=1) # อ่านสถานะสวิตช์บน Peripheral board >>> b.usb_read(1, length=1)
แบบฝึกหัด • แก้ไขเฟิร์มแวร์ (main.c) เพื่อเพิ่มคำร้องขอหมายเลข 2 • ส่งค่าแสง 10 บิตกลับมายังโฮสท์ (2 ไบท์) • ค่าใน tuple ที่ส่งคืนคือ (ไบท์ต่ำ, ไบท์สูง) • แก้คลาส PeriBoard ในมอดูล peri.py ที่สืบเชื้อสายมาจากคลาส McuBoard ใน practicum.py โดยให้มีเมท็อดดังนี้ • setLed(self, led_no, led_value) – เซ็ตสถานะ LED ตามหมายเลข led_no ที่ระบุให้เป็นไปตาม led_value (0 = ดับ, 1 = ติด) • setLedValue(self, value) – นำ 3 บิตล่างของ value แสดงผลบน LED โดยให้สีแดงเป็นบิตขวาสุด เขียวเป็นบิตซ้ายสุด • getSwitch(self) – คืนค่า True เมื่อสวิตช์ถูกกด False เมื่อปล่อย • getLight(self) – คืนค่าแสงในช่วง 0-1023
โปรแกรมสำหรับทดสอบ (test-usb.py) from peri import PeriBoard from time import sleep b = PeriBoard() count = 0 whileTrue: b.setLedValue(count) sw = b.getSwitch() light = b.getLight() if sw isTrue: state = "PRESSED" else: state = "RELEASED" print "LEDs set to %d | Switch state: %-8s | Light value: %d" % ( count, state, light) sleep(0.25) count = (count + 1) % 8
โครงงานปลายภาค • แต่ละกลุ่มพัฒนาโครงงานขนาดเล็ก • เพิ่มฮาร์ดแวร์จาก peripheral board ที่มีอยู่หรือทำบอร์ดใหม่หากต้องการ • พัฒนาเฟิร์มแวร์สำหรับ MCU • เชื่อมต่อกับซอฟต์แวร์บนฝั่งพีซีผ่านพอร์ต USB • กำหนดส่งและนำเสนอ: แจ้งให้ทราบภายหลัง • ดูตัวอย่างโครงงานของรุ่นพี่ได้จากเว็บ • http://cloud3.cpe.ku.ac.th/practicum