แพลตฟอร์ม mbed 101
คุยกับคุณชัยวัฒน์ INEX มาสักพักเกี่ยวกับการถ่ายทอดประสบการณ์ด้าน embedded software เลยถือโอกาสที่เพิ่งซื้อชุดทดลอง NUCLEO-64 Activity Kit ของ INEX มาลองใช้ เพื่อเล่าไอเดียกับประสบการณ์ของการพัฒนาซอฟต์แวร์ด้วยแพลตฟอร์ม mbed เนื้อหาตอนแรกเลยอยากปูพื้นให้เข้าใจก่อนว่าแพลตฟอร์ม mbed มีจุดไหนที่น่าสนใจบ้าง โดยเฉพาะเมื่อเปรียบเทียบกับ Arduino ที่มีฐานใหญ่มากในไทย
จากจุดเริ่มต้น
ก่อนอื่นต้องเข้าใจก่อนว่าแพลตฟอร์ม mbed มีจุดเริ่มต้นที่แตกต่างจาก Arduino แม้จะใช้ลิขสิทธิ์ซอฟต์แวร์ open-source เช่นเดียวกัน ประวัติของ Arduino เริ่มจากการสร้างเครื่องมือซอฟต์แวร์มารองรับฮาร์ดแวร์รุ่นแรกของ Arduino ที่พัฒนาสำหรับการเรียนรู้ จากนั้นจึงเติบโตขึ้นเรื่อยๆจากการขยายธุรกิจในส่วนฮาร์ดแวร์แล้วมีแรงสนับสนุนจากทั้งธุรกิจอื่นๆและนักพัฒนาจนเติบโตไปในทุกทิศทาง ในช่วงเวลาใกล้กัน แพลตฟอร์ม mbed เริ่มต้นจากวิศวกร ARM ที่เห็นถึงปัญหาของการพัฒนาต้นแบบด้วยเทคโนโลยีหน่วยประมวลผล ผนวกกับการร้องขอจากคู่ค้าที่ไลเซนส์สถาปัตยกรรมหน่วยประมวลผลระดับไมโครคอนโทรลเลอร์ไปใช้ จึงกลายมาเป็นแพลตฟอร์ม mbed ที่เน้นสนับสนุนเฉพาะหน่วยประมวลผล ARM เท่านั้น การเติบโตของทั้งสองแพลตฟอร์มจึงมีทิศทางที่ค่อนข้างแตกต่างอย่างชัดเจน
หากจะสรุปจุดเด่นระหว่าง Arduino และ mbed ด้วยประโยคเดียวในมุมมองของผมคงต้องบอกว่า
Arduino is for makers, while mbed is for developers
ดังนั้นแนวโน้มที่ผ่านมาของ Arduino แม้จะมีส่วน core API ที่ไม่เปลี่ยนมากนัก แต่ความหลากหลายของหน่วยประมวลผลและไลบรารีกลับเหมือนระเบิดไปในทุกทิศทาง จนกระทั่งตัว IDE ยุคหลังถึงต้องมีส่วนบริหารจัดการบอร์ดและไลบรารีในแบบ distributed platform เพื่อพยายามคุมให้สามารถพัฒนาซอฟต์แวร์ได้ง่ายขึ้น ในขณะที่ mbed กลับเน้นที่การขยายส่วน component และ API ของ OS stack ให้มีความสามารถเพิ่มขึ้นเรื่อยๆ จากเดิมที่มีแค่ RTOS และไดรเวอร์จัดการฮาร์ดแวร์ แนวโน้มนี้คาดว่าเป็นกลยุทธ์หนึ่งของ ARM ในการดึงให้นักพัฒนาหันมาเลือกใช้สถาปัตยกรรม ARM ที่มีทรัพยากรมากกว่าหน่วยประมวลผลที่มีอยู่เดิมในตลาด เช่น PIC, AVR, MSP430 ฯลฯ
ในอีกมุมมองหนึ่ง เครื่องมือพัฒนาหลักของ Arduino คือ Arduino IDE ที่หุ้มการทำงานของซอฟต์แวร์ gcc และมีขีดความสามารถหลักคือการ build และ deploy โค้ดไปยังบอร์ด ส่วนแพลตฟอร์ม mbed เริ่มจาก mbed online compiler ที่เป็นเว็บไซต์ทำหน้าที่เป็น IDE แบบออนไลน์ ซึ่งจะ build แล้วดาวน์โหลดไฟล์อิมเมจมาโปรแกรมลงบอร์ดเอง แต่ช่วงหลังทาง ARM ได้ผลักดันด้านเครื่องมือพัฒนาที่พยายามตอบโจทย์การพัฒนามากขึ้น ได้แก่ mbed CLI ที่ใช้รูปแบบ command line ที่รวมฟีเจอร์ version control ไว้ด้วย ทำให้ผนวกเข้ากับกลไก continuous integration (CI) ได้ง่ายขึ้น และ Mbed Studio ซึ่งเป็นซอฟต์แวร์ IDE แบบออฟไลน์ที่รวม Arm Compiler แบบเต็มความสามารถ (ราคาจริงประมาณ $4,000) มาให้ใช้ฟรีด้วย
ในฐานะของอาจารย์ mbed ตอบโจทย์การศึกษาของผมได้ดีกว่า Arduino ทั้งในแง่ของสถาปัตยกรรมฮาร์ดแวร์ (หน่วยประมวลผล 32 บิต หน่วยความจำขนาดใหญ่ มีส่วนประมวลผลร่วม) และซอฟต์แวร ์(เครื่องมือพัฒนาหลากหลาย มี RTOS และ middleware ครบชุด) อีก 1 เรื่องที่ชอบคือ โค้ดตัวอย่างที่เป็น mbed จะหาได้ยากจากเว็บคนไทย รวมทั้งมีคนที่รับจ้างไม่เยอะนัก ซึ่งเป็นมุมมืดของวงการศึกษาไทยที่ทำให้หลายคนในวงการมืออาชีพอารมณ์เสียเอาการ ส่วนเรื่องที่ไม่ชอบมีอยู่ 2 เรื่องคือ ขนาดของไฟล์อิมเมจจะใหญ่มากเพราะแบก OS และ middleware ไปครบชุดแม้จะทำงานแค่ไฟกระพริบ ส่วนอีกเรื่องที่หนักหน่อยคือ API ไม่ค่อยนิ่ง มีการเปลี่ยนแปลงไปแล้วหลายยุค รุ่นล่าสุดคือ mbed 5.15 ที่จะเป็นรุ่นสุดท้ายของ 5.x ในปีนี้แล้วปรับเป็น mbed 6.x ซึ่งมีการเปลี่ยนแปลงหลายอย่างเกิดขึ้น เช่น โปรไฟล์ baremetal สำหรับหน่วยประมวลผลที่มีทรัพยากรจำกัด ซึ่งจะเหมาะกับบอร์ด NUCLEO-L053R8 ที่มากับชุดทดลอง แต่สถานะของ baremetal API ยังมีบั๊กอยู่หลายจุดจึงไม่แนะนำให้ใช้
ไฟกระพริบของ mbed
เมื่อกล่าวถึงโค้ดตัวอย่างแรกของ Arduino ย่อมต้องเป็น blink หรือการทำไฟกระพริบด้วย LED ที่แสดงถึงจุดเด่นของโครงสร้างส่วนโค้ดใน 2 ประเด็นคือ ฟังก์ชัน setup() และ loop() ที่เป็นหน้าที่หลักของโค้ด และ API ที่ซ่อนรายละเอียดของหน่วยประมวลผล เช่น ฟังก์ชัน pinMode() digitalWrite() และ delay() เนื้อหาต่อไปนี้จะสาธิตโค้ดตัวอย่าง blink ในรูปแบบ mbed โดยใช้บอร์ด NUCLEO-F401RE และบอร์ดทดลองในชุด NUCLEO-64 Activity Kit ร่วมกับ Mbed Studio ที่ดาวน์โหลดฟรีได้จากเว็บ https://os.mbed.com/studio/ สำหรับคนที่อยากลองโค้ดตัวอย่างตอนนี้เลย โดยไม่อยากเสียเวลาดาวน์โหลดโปรแกรมมาติดตั้งอาจจะใช้ online compiler โดยไปลงทะเบียนด้วย email กับเว็บ https://os.mbed.com/ แต่ผมไม่แนะนำวิธีนี้กับการสอนในห้องเรียน เพราะเคยเจอปัญหา online IDE ค้างตอนที่มีนักเรียนพยายามสั่งคอมไพล์พร้อมๆกัน
บอร์ด NUCLEO-F401RE เป็นฮาร์ดแวร์สำหรับเรียนรู้ไมโครคอนโทรลเลอร์ตระกูล F4 ของบริษัท ST Microelectronics ที่ขายออกมาด้วยราคาที่ถูกมากเมื่อคิดถึงประสิทธิภาพเทียบกับบอร์ด Arduino รวมทั้งมี ST-Link/V2 สำหรับเชื่อมต่อ PC ที่รองรับ 3 โปรไฟล์ (mass storage สำหรับโปรแกรมแบบง่าย / CDC สำหรับสื่อสารข้อมูล / ST-Link สำหรับโปรแกรมและดีบั๊กตัวชิพ) ตัวบอร์ดจัดอยู่ในกลุ่ม NUCLEO-64 ที่ใช้ไอซีหน่วยประมวลผลแบบ 64 ขาและมีการวางขาต่างๆที่รองรับทั้งหัวต่อ Arduino shield และหัวต่อ Morpho แบบ 2 แถวที่เป็นของ ST Microelectronics เอง ชุดทดลอง NUCLEO-64 Activity Kit จะต่อเข้ากับหัวต่อ Morpho ทำให้หัวต่อ Arduino shield จะว่างอยู่ ซึ่งหากขาสัญญาณไม่ถูกใช้งานอาจจะนำไปใช้ต่อกับบอร์ดเสริมอื่นๆได้ เช่น บอร์ดเสริมในกลุ่ม X-Nucleo ที่ใช้สาธิตไอซีรุ่นต่างๆของ ST Micro เอง
การใช้งาน Mbed Studio แนะนำให้เริ่มจากเมนู File > Open Workspace เพื่อเลือกโฟลเดอร์สำหรับจัดเก็บโปรแกรมต่างๆ จากนั้นตรวจสอบรุ่นของบอร์ด/หน่วยประมวลผลจากช่อง Target แล้วจึงเลือกเมนู File > New Program ผมแนะนำให้เลือกตัวอย่าง mbed-os-example-blinky ที่เป็นโค้ดตัวอย่างไฟกระพริบ เมื่อโปรแกรมใหม่ถูกสร้างแล้ว โปรแกรม Mbed Studio จะเริ่มดาวน์โหลดไลบรารี mbed-os จาก https://github.com/ARMmbed/mbed-os ซึ่งจะมีขนาดไฟล์เกือบ 1 GB จึงแนะนำให้เริ่มทำในบริเวณที่มีอินเตอร์เน็ตความเร็วสูง อีก 1 ขั้นที่ช้ามากคือตอน build ครั้งแรก เพราะ Arm Compiler จะต้องคอมไพล์ไฟล์จากโฟลเดอร์ mbed-os โดยอาจนานถึง 20 นาที
หน้าจอของโปรแกรม Mbed Studio แบ่งออกเป็น 4 ส่วนหลักคือ
- ส่วนกำหนดการ build มีรายละเอียดคือ โปรแกรมที่จะ build, หน่วยประมวผลและการเชื่อมต่อ และเงื่อนไข (Debug, Develop, Release) โดยเราจะเริ่มจาก Debug เพื่อให้สามารถตรวจสอบการทำงานได้
- รายการไฟล์ แสดงถึงไฟล์ต่างๆในแต่ละโปรแกรม โดยไฟล์ส่วนโค้ดคือ main.cpp และไฟล์ mbed_app.json ใช้สำหรับกำหนดเงื่อนไขของไลบรารีต่างๆ
- ส่วน editor ใช้สำหรับแก้ไขโค้ดและไฟล์อื่น
- กลุ่มหน้าต่างผลลัพธ์ที่แสดงข้อมูลต่างๆ เช่น error ที่เกิดขึ้น สถานะของการ build รวมไปถึงหน้าต่างแสดงข้อความที่ได้รับจากช่องสื่อสาร USB
ส่วนโค้ดของตัวอย่าง mbed-os-example-blinky คือ ไฟล์ main.cpp ซึ่งเขียนในรูปแบบภาษา C++ โดยมีการประกาศ object ชื่อ led1 จากคลาส DigitalOut และมีการเรียกใช้ฟังก์ชัน thread_sleep_for() เพื่อหน่วงเวลาเป็นเวลา 500 มิลลิวินาที (0.5 วินาที) คนที่คุ้นเคยกับการเขียนโค้ด Arduino น่าจะรู้สึกว่าโค้ด blinky ของ mbed ดูเข้าใจยากกว่า แต่อาจจะเป็นสิ่งที่ถูกใจนักพัฒนาที่คุ้นเคยสไตล์ OOP เช่น การสลับสถานะติด/ดับของ LED ด้วยการใช้ตัวกระทำ NOT (led1 = !led1)
#include “mbed.h”
#define WAIT_TIME 500 //msecDigitalOut led1(LED1);int main() {
while (true) {
led1 = !led1;
thread_sleep_for(WAIT_TIME);
}
}
การทดลองโค้ดตัวอย่างให้กดปุ่ม Run program (build + deploy) เพื่อเริ่มการคอมไพล์โค้ดทั้งหมดแล้วติดตั้งไปที่บอร์ด จะเห็น LED สีเขียวกระพริบที่บอร์ดด้วยความถี่ 1 Hz (ติด 0.5 วินาที ดับ 0.5 วินาที) หน้าต่าง Output จะแสดงรายละเอียดของไฟล์อิมเมจที่สร้างขึ้น โดยโปรแกรม blinky จะใช้หน่วยความจำแฟลช 36 kB และ RAM อีก 9 kB
mbed online compiler
ผู้ที่อยากลอง mbed แบบเร็วๆ ไม่อยากวุ่นวายกับการติดตั้งโปรแกรม ขอแนะนำให้ไปลองใช้ mbed online compiler ที่สะดวก (ใช้แค่เบราเซอร์) แต่มีข้อจำกัดบ้างตรงที่ไม่สามารถดีบั๊กได้ การใช้งาน online compiler ทำได้ทันทีหลังจากลงทะเบียนที่เว็บไซต์ https://os.mbed.com/ โดยคลิกที่ปุ่ม Compiler ตรงมุมบนขวาของหน้าเพจ ตัวเว็บไซต์ online IDE จะเปิดขึ้นมา ซึ่งจะเริ่มจากไม่มีทั้งฮาร์ดแวร์และโปรแกรมเลย การเริ่มใช้งานให้ทำตามขั้นตอนดังนี้
- กดที่ปุ่ม Add Platform บริเวณมุมขวาบนเพื่อเปิดหน้าต่างสำหรับกำหนดฮาร์ดแวร์ที่จะใช้
- กดที่ปุ่ม Add Board จะเปิดเว็บไซต์ที่รวมแพลตฟอร์มฮาร์ดแวร์ที่ใช้ได้กับ mbed ให้เลือกบอร์ดที่เราจะใช้ โดยอาจจะสืบค้นชื่อ เช่น “nucleo F401RE” หรือคัดกรองด้วยเงื่อนไข เช่น ผู้ผลิตเป็น ST Microelectronics และเป็น ARM Cortex-M4
- คลิกเลือกที่บอร์ด NUCLEO-F401RE จะมีการแสดงข้อมูลของบอร์ด ให้กดที่ปุ่ม Add to Compiler บริเวณส่วนขวาของหน้าเพจ
หลังจากเราเพิ่มบอร์ด NUCLEO-F401RE ให้กับ mbed online compiler แล้ว สามารถเริ่มทดลองโค้ดตัวอย่างได้เลย โดยอาจจะคลิกที่ปุ่ม New > New Program หรือเลือก Import เพื่อไปดึงโค้ดตัวอย่างจากออนไลน์ผ่านกลไก git ได้ สำหรับโค้ดตัวอย่าง mbed-os-example-blinky เราจะใช้การ Import โดยคลิกปุ่ม Import แล้วเลือกแบบ Import URL ซึ่งจะมีการแสดงหน้าต่างมารับข้อมูล โค้ดตัวอย่างจะอยู่บน github ที่ URL คือ https://github.com/ARMmbed/mbed-os-example-blinky จากนั้นให้คลิกยืนยันเพื่อให้ตัว online IDE ไป clone repo มาเป็นโปรแกรมใหม่ ทั้งนี้เราสามารถคลิกปุ่ม Compile เพื่อให้เซิร์ฟเวอร์ mbed ทำการ build แล้วดาวน์โหลดไฟล์อิมเมจ ซึ่งมีชื่อขึ้นต้นด้วยโปรแกรมและตามด้วยฮาร์ดแวร์และนามสกุล .bin เช่น “mbed-os-example-blinky-baremetal.NUCLEO_F401RE.bin” ไฟล์ที่ดาวน์โหลดมาให้คลิกลากไปใส่แฟลชไดร์ฟจำลองของบอร์ดที่มีชื่อว่า “NODE_F401RE” จะเป็นการโปรแกรมลงบอร์ด
mbed แบบ baremetal
บอร์ด NUCLEO-L053R8 ที่มากับชุดทดลอง NUCLEO-64 Activity Kit ไม่สามารถใช้ไลบรารี mbed-os แบบปกติได้ เนื่องจากมี RAM เพียง 8 kB ไม่เพียงพอสำหรับการสร้าง thread ที่ต้องจองหน่วยความจำ stack แยกจากกัน ดังนั้นจึงต้องปรับไปใช้โปรไฟล์แบบ baremetal ที่มี API จำกัดเฉพาะไดรเวอร์ระดับฮาร์ดแวร์ ไม่มี RTOS และ middleware อื่นๆ อย่างไรก็ตาม ส่วนโค้ดและเครื่องมือสำหรับโปรไฟล์ baremetal ยังไม่นิ่ง จึงมีปัญหาค่อนข้างเยอะ และต้องปรับแก้ไฟล์ในไลบรารี mbed-os เพื่อให้สามารถคอมไพล์ผ่าน จึงไม่แนะนำสำหรับผู้เริ่มต้นที่อยากเรียนรู้ mbed ทั้งนี้บริษัท ST Microelectronics จะออกบอร์ดในกลุ่ม NUCLEO-64 ออกมาหลายรุ่น ซึ่งมีหัวต่อ Morpho และตำแหน่งขาเหมือนกัน ผมแนะนำว่าควรเลือกซื้อบอร์ดที่มีหน่วยประมวลผลตระกูล F4 หรือ L4 มากกว่า ซึ่งราคาไม่ได้แตกต่างจากรุ่น L053 เลย
ไลบรารี mbed-os ล่าสุดคือ รุ่น 5.15 ณ วันที่ผมเขียนบทความนี้ ยังมีส่วนโค้ดบางส่วนของ “NUCLEO_L053R8” target ยังไม่ได้ปรับแก้ให้ใช้กับ baremetal ได้ รายการไฟล์ที่ต้องแก้ไขมีทั้งหมด 3 ไฟล์คือ
- ไฟล์ mbed-os\targets\targets.json โดยให้ค้นหาบรรทัด “NUCLEO_L053R8” จากนั้นเปลี่ยนเงื่อนไข key:value ของไลบรารีมาตรฐาน C จาก
"default_lib": "small",
เป็น
"c_lib": "small",
"supported_c_libs": {
"arm": ["std", "small"],
"gcc_arm": ["std", "small"],
"iar": ["std"]
},
2. เปลี่ยนชื่อโฟลเดอร์ TOOLCHAIN_ARM_STD ที่อยู่ใน mbed-os\targets\TARGET_STM\TARGET_STM32L0\TARGET_STM32L053x8\device\ เพื่อเป็นการ backup จากนั้นสำเนาโฟลเดอร์ TOOLCHAIN_ARM_MICRO มาแทน ซึ่งจะทำให้มีนิยามของหน่วยความจำ heap และ stack
3. ไฟล์ mbed_app.json ในตัวโค้ดตัวอย่าง โดยเพิ่มเงื่อนไขที่ทำให้ใช้หน่วยความจำน้อยลง คำเตือนคือ การใช้คำสั่ง printf() จะมีข้อจำกัด เช่น ไม่สามารถแสดงเลขทศนิยมได้
{
"requires": ["bare-metal"],
"target_overrides": {
"*": {
"target.printf_lib": "minimal-printf",
"platform.minimal-printf-enable-floating-point": "false",
"platform.stdio-minimal-console-only": true
}
}
}
ทิ้งท้าย
นอกจากแพลตฟอร์ม mbed ผมเองยังใช้ ESP32 ที่พัฒนาด้วย Arduino IDE เป็นอีกหนึ่งตัวเลือก ข้อดีของ ESP32 ในมุมมองของผมคือ การมี API ของ FreeRTOS และ protocol stack ทั้ง Bluetooth และ WiFi รวมมาด้วย เปิดช่องให้เรียนรู้การพัฒนาแอพพลิเคชันสำหรับ Internet of Things ได้ เมื่อเปรียบเทียบฮาร์ดแวร์ ราคา การเขียนโค้ด และการหาซื้อ ผมคงต้องบอกว่า ESP32 จะเหนือกว่าแพลตฟอร์ม mbed ในภาพรวมไปพอสมควร
หาก ESP32 ดีกว่า mbed ในแง่เทคนิค แต่ประสบการณ์กับ github ของ mbed-os ค่อนข้างจะดีกว่ามาก เช่น เมื่อผมรายงานปัญหาที่คาดว่าจะเป็น bug ของไลบรารี จะมีคนมาตอบภายในเวลาไม่ถึง 1 วัน แต่ฝั่ง github ของ Arduino (ส่วนใหญ่จะเจอแต่ post ประเภทขอฟีเจอร์เพิ่ม) จะอยู่ในช่วง 2–3 วัน ความแตกต่างนี้ไม่ใช่เพราะชุมชนของ mbed จะ active กว่า แต่เป็นเพราะ ARM จ้างนักพัฒนามาคอยดู github ซึ่งเป็นเป็นส่วนหนึ่งของงานของนักพัฒนาพวกนี้ ดังนั้นผมคงขอจบด้วยข้อความนี้อีกครั้ง
Arduino is for makers, while mbed is for developers
อ้างอิง
- “Founders interview” ออนไลน์ที่ https://os.mbed.com/handbook/Founders-interview
- “An introduction to Arm Mbed OS 5” ดูออนไลน์ https://os.mbed.com/docs/mbed-os/v5.15/introduction/index.html
- “Using small C libraries in Mbed OS bare metal” ดูออนไลน์ https://github.com/ARMmbed/mbed-os-example-blinky-baremetal
- “NUCLEO-F401RE” ดูออนไลน์ https://os.mbed.com/platforms/ST-Nucleo-F401RE/