Submitted by admin on Wed, 02/02/2011 - 22:20
เอกสารอ้างอิง
การใช้งาน GPIO บน Embedded Linux
ในโลกของ Embedded System ทั่วไป การควบคุม GPIO ทำได้ง่ายดายเพียงแค่อ่านหรือเขียนลง Control Register แต่สำหรับผู้ที่เริ่มใช้ Embedded Linux แล้วมักจะมีคำถามเสมอว่าการใช้งาน GPIO ทำได้อย่างไร บทความนี้จะสาธิตการใช้งาน GPIO กับ Embedded Linux บนบอร์ด MINI2440 ซึ่งสามารถนำไปประยุกต์ใช้งานได้กับบอร์ด Embedded Linux อื่นๆ
Sysfs
ในระบบ Embedded System การติดต่อฮาร์แวร์จะไม่กระทำโดยตรง แต่จะทำผ่านส่วนที่เรียกว่า Device Driver โดยผู้ใช้จะมองฮาร์ดแวร์ทุกอย่างเป็นเสมือนไฟล์ เพียงแต่ไฟล์นี้จะเป็นไฟล์ชนิดพิเศษที่เมื่อ Read/Write ข้อมูลลงไปในไฟล์นี้แล้ว จะเหมือนการ read/write ข้อมูลไปยังฮาร์แวร์
ใน Linux kernel version 2.4 ไฟล์พิเศษนี้จะอยู่ภายใต้ไดเร็คทอรี่ /dev และจะต้องถูกสร้างขึ้นมาในระบบโดยผู้ใช้ก่อนการใช้งาน ซึ่งถ้าหากฮาร์แวร์ถูกถอดออกไปจากระบบ ไฟล์นี้ก็ยังดำรงอยู่ยกเว้นผู้ใช้จะไปทำการลบออกจากระบบเอง สำหรับ Linux kernel version 2.6 ได้มีการคิดค้นระบบไฟล์สำหรับฮาร์แวร์ใหม่โดยไฟล์ที่ว่านี้เรียกว่า Sysfs ซึ่งเป็น virtual file system และจะถูกสร้างขึ้นมาในลักษณะเดียวกับ ram drive ระบบจะสร้างไฟล์ตามฮาร์แวร์ที่มีอยู่จริงโดยอัตโนมัติ ทำให้ผู้ใช้ไม่ต้องสร้างหรือลบไฟล์ด้วยตัวเอง สำหรับ Sysfs นี้จะปรากฏอยู่ในระบบภายใต้ไดเร็คทอรี่ /sys
รายละเอียดเพิ่มเติมของ sysfs สามารถหาอ่านได้จาก http://www.kernel.org/pub/linux/kernel/people/mochel/doc/papers/ols-2005/mochel.pdf
GPIO ภายใต้ sysfs

เมื่อบูทระบบแล้ว Sysfs จะสร้างลิงค์ /sys/class/gpio/gpiochipN เพื่อใช้ติดต่อกับ IO PORT ของระบบดังนี้

โดย gpiochip หนึ่งตัวก็จะแทน port หนึ่งตัว ลองดูตัวอย่างโครงสร้างของไดเร็คทอรี่ภายใต้ gpiochip32 จะเป็นดังนี้

โดยไฟล์ label, base และ ngpio จะให้รายละเอียดของ GPIO ที่มันควบคุมดังนี้

ซึ่งจากข้อมูลเบื้องต้น
- label แสดงว่า gpiochip32 จะควบคุม Port B ของชิพ s3c2440
- base แสดงว่าหมายเลขที่ใช้ในการติดต่อกับ bit 0 ของ Port B นี้คือ 32
- ngpio แสดงว่าจำนวนบิททั้งหมดที่สามารถสั่งงานได้ใน port นี้มี 16 ตัว
ดังนั้น สมมติเราต้องการจะควบคุม bit 6 ของ Port B หรือ GPB6 หมายเลขประจำบิทนี้ก็คือ 32 + 6 = 38 นั่นเอง
การควบคุม GPIO

เราลองมาเปิดปิด LED2 บนบอร์ด mini2440 กันดูนะครับ จากวงจร จะเห็นว่า LED2 ต่ออยู่กับ GPB6 ซึ่งจากการคำนวณข้างต้นมีหมายเลขประจำตัวคือ 38
เริ่มต้นการใช้งานด้วยการส่งตัวเลขประจำบิทที่เราจะควบคุมไปยังไฟล์พิเศษที่ชื่อ export ด้วยคำสั่ง echo
โปรดสังเกตุว่าจะมี link ใหม่ถูกสร้างขึ้นที่ชื่อว่า gpio38
ลองตรวจสอบดูจะเห็นโครงสร้างไฟล์ภายใต้ link ดังนี้

ไฟล์ที่น่าสนใจคือ direction และ value โดย
- direction เมื่ออ่านค่าจากไฟล์นี้ จะได้ค่า in หรือ out เพื่อบอกทิศทางว่าเป็น input หรือ output และเมื่อเขียนสามารถกำหนดทิศทางของบิทได้ โดยค่าที่เขียนสามารถเป็น in หรือ out โดยปกติแล้วเมื่อเขียนค่าด้วย out บิทจะถูก initialize ให้เป็น low ไปพร้อมๆกัน แต่ถ้าต้องการเปลี่ยนทิศทางให้เป็น out ในขณะเดียวกัน initialize เป็น high ก็สามารถส่งคำสั่ง high ไปแทนได้
- value อ่านค่าได้ 1 หรือ 0 สำหรับ input และ ส่งค่า 1 หรือ 0 สำหรับควบคุม output
ลองคำสั่งดังต่อไปนี้

cat gpio38/direction แสดงให้เห็นว่าเริ่มต้น IO port GPB6 จะถูกกำหนดไว้เป็น input
echo out > gpio38/direction จะทำการเซ็ท IO port GPB6 ให้เป็น ouput ในขณะเดียวกันจะ Initialize ค่าให้เป็น low โปรดสังเกตุว่า LED2 บนบอร์ดจะติด
ทดลองส่งค่า 1 ไปยัง gpio38/value จะทำให้ LED2 บนบอร์ดดับ จากนั้นยกเลิกการใช้งานบิท GPB6 ด้วยคำสั่ง echo 38 > unexport ตรวจสอบดูจะเห็นว่า link gpio38 ที่ใช้ควบคุมบิท GPB6 จะหายไป
ลองมาทดสอบ input ดูบ้างนะครับ

เราจะมาทดสอบการใช้งาน ปุ่มกด K6 ซึ่งจากวงจรจะเท่ากับ GPG11

จากการตรวจสอบจะเห็นว่าบิท 0 ของ GPIOG เท่ากับ 192 ดังนั้น GPG11 ก็จะมีหมายเลขประจำบิทเท่ากับ 192 + 11 = 203
เริ่มต้นการใช้งานบิท 203 ด้วยการ export จะเห็นว่า link gpio203 จะถูกสร้างขึ้น

ตรวจสอบสถานะของบิทดูจะเห็นว่าเป็น input และ มีค่าเท่ากับ 1 ซึ่งสอดคล้องกับวงจรที่มีการ pull high ผ่าน R22

ทำการกดปุ่ม K6 ค้างไว้แล้วตรวจสอบค่าจะเห็นว่าเปลี่ยนไปเป็น 0

เมื่อเสร็จสิ้นการใช้งานแล้วเราสามารถที่จะยกเลิกการใช้งานบิท GPG11 ด้วยคำสั่ง echo 203 > unexport จะสังเกตุได้ว่า link gpio203 จะหายไป

การควบคุม GPIO จากโปรแกรม
ติดตั้ง cross tool chain ตามลิงค์ http://project4fun.com/node/10
ทำการคอมไพล์โปรแกรมด้วยคำสั่ง
arm-angstrom-linux-gnueabi-gcc gpio.c -o gpio
จะได้เอาท์พุทไฟล์ที่ชื่อว่า gpio หลังจาก copy ไปยัง mini2440 แล้วให้ execute ด้วยคำสั่ง ./gpio
จะสังเกตุเห็น LED2 กระพริบด้วยความถี่ 1Hz และถ้ากดปุ่ม K6 ค้างไว้เป็นเวลาสามวินาทีก็จะออกจากโปรแกรม
|
/******************************** #include <string.h> FILE *fp; int write(char *fname,char *mode,char *value) int read(char *fname,char *mode,char *value) printf("\n**********************************\n" //Using sysfs we need to write "203" to /sys/class/gpio/export
if( strcmp( read_value, "0" ) == 0 ) //Pause for one second |
หวังว่าตัวอย่างนี้คงเป็นแนวทางในการใช้งาน GPIO ได้เป็นอย่างดีนะครับ เนื่องจากการควบคุมแบบนี้อิงมาตราฐานของLinux ดังนั้นจึงสามารถนำไปประยุกต์ใช้กับบอร์ดอื่นๆที่รองรับ Kernel 2.6 ได้ด้วยครับ
เอกสารอ้างอิง
1. http://www.mjmwired.net/kernel/Documentation/gpio.txt
2. http://www.avrfreaks.net/wiki/index.php/Documentation:Linux/GPIO
3. http://www.kernel.org/pub/linux/kernel/people/mochel/doc/papers/ols-2005/mochel.pdf
»