บทความนี้แนะนำการใช้งานซอฟต์แวร์ ARM Keil uVision 5 IDE และ MDK (Microcontroller Development Kit) Version 5 ในเบื้องต้น โดยจะนำมาใช้กับบอร์ดไมโครโทรลเลอร์ที่ใช้ชิป ATSAMD21 ของบริษัท Atmel (สำหรับผู้อ่านที่สนใจ จะเลือกใช้บอร์ดหรือมีตัวเลือกในการพิจารณาอย่างไรบ้าง สามารถอ่านเพิ่มเติมได้จากบทความ “ตัวเลือกสำหรับการเขียนโปรแกรมไมโครคอนโทรลเลอร์ Atmel SAMD21”)
แต่เนื่องจากซอฟต์แวร์นี้เป็นประเภท Commercial ถ้าจะใช้ฟรี ต้องใช้งานในเวอร์ชันหรือโหมด MDK-Lite Edition และถูกจำกัดการใช้งานด้วยขนาดของโปรแกรมและข้อมูลที่ได้จากการคอมไพล์ จะต้องไม่เกิน 32KB อย่างไรก็ตาม ก็ยังสามารถใช้ได้ในกรณีที่ต้องการฝึกเขียนโค้ดที่ไม่ซับซ้อนมากนัก (แต่ถ้าจะใช้แบบมืออาชีพในเวอร์ชัน Professional หรือ Plus จะต้องเสียค่า Software License)
จุดเด่นของซอฟต์แวร์ ARM Keil uVision & MDK คือ เราสามารถเขียนโค้ดสำหรับไมโครคอนโทรลเลอร์ที่ใช้ตระกูล ARM Cortex-M ได้หลายบริษัทให้เลือกใช้ได้ สามารถคอมไพล์โค้ดภาษา C/C++ ให้เป็นไฟล์เอาต์พุต .hex และจำลองการทำงานของโปรแกรมโดยใช้ Simulator และยังไม่จำเป็นต้องใช้ฮาร์ดแวร์จริง
ขั้นตอนการดำเนินการมีดังนี้
- ดาวน์โหลดและติดตั้งใช้งาน MDK-ARM สำหรับระบบปฏิบัติการ Windows (ในกรณีที่ยังไม่มีโปรแกรมในเครื่องคอมพิวเตอร์) เวอร์ชันที่ได้นำมาใช้คือ MDK-ARM version 5.29
- เมื่อติดตั้งและใช้งานครั้งแรก จะมีการให้เลือกดาวน์โหลดและติดตั้ง Software Packs ในส่วนที่เรียกว่า MDK Pack Installer ซึ่งจะใช้สำหรับตรวจสอบอัปเดทและติดตั้งซอฟต์แวร์ต่าง ๆ ของ MDK
- นอกเหนือจาก MDK Core เช่น ARM::CMSIS และ Keil::ARM Compiler จะต้องติดตั้ง Software Pack สำหรับชิปไมโครคอนโทรลเลอร์ที่จะใช้งาน ในกรณีนี้คือ ATSAMD21 ของบริษัท Microchip/Atmel
- เปิดโปรแกรม Keil uVision5 IDE เพื่อใช้งาน แล้วสร้างโปรเจกต์ใหม่ (สร้างไดเรกทอรีสำหรับโปรเจกต์ ตั้งชื่อโปรเจกต์ และเลือกชิปเป้าหมายเป็น ATSAMD21G18A)
- สร้างไฟล์ main.c และเพิ่มเข้าเป็นส่วนหนึ่งของโปรเจกต์ ในส่วน Source Group และแกัไขเพิ่มเติมโค้ด (เช่น การทำให้เกิด I/O Toggle สำหรับ LED)
- ตั้งค่าในส่วน Option for Target เช่น การเลือกใช้ Simulator สำหรับการจำลองทำงานงานของโปรแกรม
- ตั้งค่าสำหรับ Debug ในกรณีที่ต้องการอัปโหลดโปรแกรมไปยังบอร์ดไมโครคอนโทรลเลอร์ และทำการดีบักโค้ดที่รันโดยไมโครคอนโทรลเลอร์บนบอร์ดทดลอง เช่น การใช้อุปกรณ์ ARM Keil ULINK2 เป็นต้น
เมื่อได้สร้างโปรเจกต์ใหม่ (Create New Project) แล้วจะเห็นว่า มีการใส่ไฟล์ เช่น system_SAMD21.s ซึ่งเป็น Startup File ให้โดยอัตโนมัติ ภายในมีโค้ดที่เขียนด้วยภาษา Assembly ทำหน้าที่ทำคำสั่งต่าง ๆ เพื่อทำฮาร์ดแวร์ให้พร้อมสำหรับการทำงาน เช่น การกำหนดค่าเริ่มต้นเพื่อใช้งาน Stack และ Heap ในหน่วยความจำ SRAM การกำหนดค่าเริ่มต้นให้ Interrupt Vector Table และ Default Handlers ก่อนที่จะเรียกฟังก์ชัน SystemInit() และ ฟังก์ชัน main() เป็นลำดับถัดไป
ไฟล์ system_samd21.c เป็นไฟล์โค้ดภาษา C ภายในมีการสร้างฟังก์ชัน SystemInit() โดยทั่วไปแล้ว จะทำหน้าที่กำหนดหรือตั้งค่าการใช้งานให้สัญญาณ Clock ต่าง ๆ ภายในไมโครคอนโทรลเลอร์ และ SAMD21 มีวงจร Internal Oscillator ภายใน ความถี่ 8 MHz (เรียกว่า OSC8M) และตั้งค่าตัวหารความถี่ไว้เท่ากับ DIV8 ดังนั้นการทำงานของซีพียูจะใช้ความถี่ 1 MHz
ในโค้ดตัวอย่าง main.c ถ้าอยากทราบว่า ชื่อของตัวแปรหรือฟังก์ชัน เช่น PORT_IOBUS มีการประกาศไว้อย่างไรและอยู่ในไฟล์ใด ก็สามารถค้นหาได้ (ทำคำสั่ง Go To Definition of … หรือ Go To Declarations of …)
ตัวอย่างการตั้งค่าก่อนเริ่มต้นดีบัก (Debug) เพื่อจำลองการทำงาน
ในส่วนของ Option for Target > Debug ให้ระบุชื่อไฟล์สำหรับ Initialization File ตามตัวอย่าง เมื่อกดปุ่ม Edit จะมีการเปิดไฟล์ .ini ใน Editor (ถ้ายังไม่มีไฟล์ดังกล่าว ก็จะสร้างขึ้นใหม่) จากนั้นให้ใส่ช่วงของแอดเดรส (Address Ranges) ตามตัวอย่างต่อไปนี้ เพื่ออนุญาตให้มีการเขียนและอ่านในหน่วยความจำสำหรับ Peripherals ใน Memory Map ของ ATSAMD21 ได้ เมื่อจำลองการทำงานด้วย Simulator
เมื่อทำขั้นตอน Build ได้สำเร็จแล้ว ก็สามารถตรวจสอบการทำงานของโค้ด โดยใช้ Simulator ให้ทำคำสั่งจากเมนู Debug > Start/Stop Debug Session จากนั้นจะเห็น Popup Window แสดงคำเตือนว่า เป็นการทำงานในโหมด “Evaluation Mode” จำกัดขนาดของโค้ดไว้ที่ไม่เกิน 32 KB
ในโหมด Debug จะมีการแสดงข้อมูลในหน้าต่างย่อยต่าง ๆ (เลือกเปิดดูเพิ่มได้ในเมนู View > … Windows) ยกตัวอย่างเช่น แถบทางด้านซ้ายมือเป็น Register Windows แสดงรีจิสเตอร์ภายใน Register File ของซีพียู และถ้าดูในกลุ่ม Internal จะเห็นว่า ในโหมด Simulator มี States (Cycle Value) เป็นตัวระบุจำนวนไซเคิลที่ได้ทำไปแล้วโดยซีพียู ซึ่งเป็นค่าโดยประมาณ (Approximated Cycle Value) และมี Sec (Cycle Timer) เป็นตัวระบุเวลาที่ผ่านไป (Elapsed Time) หน่วยเป็นวินาที ซึ่งขึ้นอยู่กับค่า Clock ที่ได้ตั้งไว้ (ในกรณีนี้คือ ใช้ความถี่ 1 MHz หรือ 1 usec per cycle)
เมื่อกดปุ่ม F5 (Run) แต่ละครั้ง จะมีการทำคำสั่งต่อไป จนถึง Breakpoint (ในบรรทัดที่มีจุดกลมสีแดงที่ปรากฏ) แล้วหยุดชั่วคราว (ในโค้ดตัวอย่าง ก็หมายถึง การทำคำสั่งใน while loop หนึ่งรอบ) ค่าของ States และ Sec จะเพิ่มขึ้น ในกรณีตัวอย่างนี้ States จะเพิ่มขึ้นครั้งละ 3 ไซเคิล เนื่องจากทำคำสั่ง Instructions ได้แก่ STR (Word, immediate offset) และ B (Unconditional Branch) และที่ตัวนับ Sec จะเพิ่มขึ้นครั้งละ 3 usec
หน้าต่างด้านบน Assembly Windows แสดงโค้ดในภาษา Assembly ที่ได้จากการคอมไพล์โค้ดภาษา C ในไฟล์ main.c และมีการแสดงความเชื่อมโยงระหว่างคำสั่งในระดับ Assembly กับประโยคคำสั่งในภาษา C
ข้อสังเกต:
- การใช้งานขา I/O ของ ATSAMD21 ซึ่งมีพอร์ต PA (Port Group 0) และ PB (Port Group 1) เพื่อใช้งานเป็น GPIO (Digital I/O) จะต้องมีการเขียนค่าลงในรีจิสเตอร์ที่เกี่ยวข้อง เช่น การกำหนดทิศทางของให้เป็นเอาต์พุต (Direction: 0=Input, 1=Output) และเขียนค่าบิตเป็น 0 (Clear Bit) หรือ 1 (Set Bit) ในตำแหน่งบิตที่เกี่ยวข้อง หรือสลับค่าบิตในขณะนั้น (Toggle Bit)
- ในตัวอย่างนี้เป็นการสาธิตการเข้าถึงรีจิสเตอร์ของ I/O Peripherals ผ่าน IOBUS (single-cycle I/O Bus Access) ซึ่งจะเร็วกว่าการเข้าถึงรีจิสเตอร์ผ่าน APB Bus (ใช้เวลามากกว่าหนึ่งไซเคิล)
การทำขั้นตอนดีบักโดยใช้งานร่วมกับบอร์ดไมโครคอนโทรลเลอร์
หลังจากได้ทดลองใช้งาน ARM Keil Simulator ไปบ้างแล้ว ถัดไปจะนำโปรแกรมที่ได้ไปทดลองรันโดยใช้บอร์ดไมโครคอนโทรลเลอร์ (เลือกใช้บอร์ด RobotDyn SAMD21 M0-Mini เนื่องจากมีราคาไม่แพง) และจะใช้ร่วมกับอุปกรณ์ ARM Keil ULINK2 Programmer/Debugger ซึ่งทำงานได้ในโหมด CMSIS-DAP JTAG / SWD
อุปสรรคในการใช้งาน
- เนื่องจากบอร์ด RobotDyn SAMD21 M0-Mini ใช้คอนเนกเตอร์แบบ 50-mil 2x5 pin headers แต่สายเชื่อมต่อของอุปกรณ์ ULINK2 เป็นแบบ 100-mil 2x10 Flat Cable ดังนั้นจึงต้องใช้ Adapter Module + Flat Cable
- บอร์ด ATSAMD21 ไม่ได้ใช้ JTAG แต่ใช้ SWD Interface (Serial Wire Debug) ซึ่งใช้สัญญาณ 2 เส้น คือ SWCLK และ SWDIO
คำเตือน/ข้อควรระวัง:
การอัปโหลดโปรแกรมไปยังบอร์ดไมโครคอนโทรลเลอร์ RobotDyn SAMD21 M0-Mini เริ่มต้นที่แอดเดรส 0x0 ถึง 0x40000 (หรือ 256 KB) ดังนั้น จะเขียนทับส่วนที่เป็น Arduino Bootloader (ถ้ามี จะอยู่ในช่วง 0x0 ถึง 0x02000 หรือ 8 KB แรก) หน่วยความจำ Flash และถ้าจะกลับไปใช้ Arduino IDE เขียนโค้ดและอัปโหลดผ่าน USB จะต้องทำการโปรแกรม Arduino Bootloader ลงในชิปใหม่ [ถ้าต้องการติดตั้ง Arduino-SAMD Bootloader ใหม่อีกครั้ง โดยใช้อุปกรณ์ ULINK2 หรือ J-LINK Programmer สามารถศึกษาวิธีได้จากบทความนี้]
เมื่อตั้งค่าใน Option for Target > Debug : Use CMSIS-DAP Debugger แล้ว ให้ทำขั้นตอน Flash > Download จากนั้นก็สามารถทำขั้นตอน Debug > Start/Stop Debug Session ได้เหมือนกรณีที่ใช้ Simulator
ถ้าจบการทำงานใน Debug Session แล้วกดปุ่ม Reset บนบอร์ด และลองวัดสัญญาณที่ขา PA17 ของ ATSAMD21 ด้วยเครื่อง Digital Oscilloscope จะเห็นว่า คลื่นสัญญาณเอาต์พุตมีคาบเท่ากับ 6 usec (หรือครึ่งคาบเท่ากับ 3 usec)
ความถี่ของสัญญาณเอาต์พุตที่ขา PA17 คำนวณได้ดังนี้ 1 MHz / 6 usec = 166.7 kHz ซึ่งถือว่า ใกล้เคียงกับที่วัดได้จริง
ถ้าลองแก้ไขโค้ดใหม่ในไฟล์ main.c แทนที่จะเข้าถึงรีจิสเตอร์ของพอร์ต PA (Port Group 0) ผ่าน IOBUS แต่ใช้ผ่าน APB BUS และนำไปทดสอบการทำงานกับฮาร์ดแวร์จริง จะได้ความถี่ของเอาต์พุตที่ต่ำลง หนึ่งคาบจะใช้เวลา 12 usec หรือจะได้ความถี่ประมาณ 83.3 kHz ดังนั้นจะเห็นได้ว่า การเข้าถึงรีจิสเตอร์ของ I/O Port Peripheral ผ่าน APB BUS จะทำได้ช้ากว่า IOBUS
การเลือกใช้เครื่องมือ ทั้งซอฟต์แวร์ (IDE, Compiler, Debugger, Simulator) และฮาร์ดแวร ์ (Device Programmer/Debugger, Instruments) ให้เหมาะสมกับการพัฒนาโปรแกรมหรือเฟิร์มแวร์ เพื่อนำไปใช้กับไมโครคอนโทรลเลอร์และระบบสมองกลฝังตัว ถือว่าเป็นสิ่งสำคัญที่จะช่วยให้นักพัฒนาทำงานได้ง่ายขึ้น และเข้าใจพฤติกรรมการทำงานของโปรแกรมได้ดียิ่งขึ้น
Creative Commons, Attribution-Non Commercial-Share Alike 4.0 International (CC BY-NC-SA 4.0)