การพัฒนาเฟิร์มแวร์สำหรับ RP2040 ด้วยภาษา C/C++ (ตอน 3 การดีบั๊ก)

Supachai Vorapojpisut
4 min readMay 7, 2022

--

เนื้อหาตอนนี้จะเน้นไปที่ความสามารถในการแอบดูและควบคุม (breakpoint, step, watch, …) หน่วยประมวลผล ซึ่งเป็นฟีเจอร์จำเป็นสำหรับขั้นตอนการทดสอบบอร์ดแบบ white-box และการดีบั๊กซอฟต์แวร์ ใครที่เพิ่งอ่านบทความนี้ แนะนำให้ย้อนไปดู 2 ตอนแรกที่จะแนะนำเครื่องมือพัฒนาในส่วนของการ build ก่อน จะได้ไม่สับสนเครื่องมือพัฒนา

  1. การพัฒนาเฟิร์มแวร์ด้วย MicroPython, Arduino และ Mbed OS
  2. การพัฒนาเฟิร์มแวร์แบบ dual core ด้วย C/C++ SDK

ทีมพัฒนาของ Raspberry Pi Foundation และ community ได้เตรียมช่องทางดีบั๊ก RP2040 ไว้หลายรูปแบบทั้งการใช้ debug probe ผ่านขา SWD (serial wire debug) ที่เป็นรูปแบบพื้นฐานของ ARM Cortex หรือใช้ซอฟต์แวร์ไปทำงานบนคอร์ proc1 เพื่อดีบั๊กคอร์ proc0 (bus fabric ทำให้ proc0/proc1 เข้าถึงองค์ประกอบต่างๆบนชิพแบบเท่าเทียม) ผมเลือกใช้บอร์ด Maker Pi Pico ของ Cytron เพราะมีหัวต่อ SWD เตรียมไว้อยู่แล้ว จึงสะดวกที่ไม่ต้องบัดกรีขาตรงส่วนปลายของบอร์ด

บอร์ด Maker Pi Pico

การดีบั๊กผ่าน SWD

ARM Cortex เป็นสถาปัตยกรรมหน่วยประมวลผลที่ถูกออกแบบให้มีฟีเจอร์ on-chip debugger ไว้ตั้งแต่ต้น จึงรองรับการเชื่อมต่อจากคอมพิวเตอร์เข้าไปจัดการสถานะและลำดับการประมวลผลภายในหน่วยประมวลผลได้ หน่วยประมวลผล RP2040 ใช้สถาปัตยกรรม ARM Cortex-M0 จึงรองรับเฉพาะฟังก์ชัน DAP (debug access port) สำหรับแต่ละคอร์ proc0/proc1 ได้แก่

  • ตั้ง hardware breakpoint ได้สูงสุด 4 ตำแหน่งของส่วนโค้ด และใช้ software breakpoint (รหัสคำสั่ง BKPT ได้ไม่จำกัด)
  • ตั้ง data watchpoint ได้สูงสุด 2 ตำแหน่งของข้อมูล
  • ทำ single-step ได้
  • ทำ vector catch เพื่อดักสถานะ exception จากตำแหน่ง vector ได้

แต่ไม่ได้รวมถึง Micro Trace Buffer จึงไม่สามารถดักส่วนโค้ดที่ทำงานก่อนหน้ารวมทั้งแสดง logging ผ่าน SWD

บอร์ดสำหรับการเรียนรู้ไมโครคอนโทรลเลอร์ ARM อื่นๆ มักจะรวมส่วนเชื่อมต่อที่ทำหน้าที่เป็นทั้ง programmer และ debugger ไว้ด้วย ตัวอย่างเช่น บอร์ด STM32 Nucleo จะมีชิพทำหน้าที่เป็น ST-Link เพื่อเชื่อมต่อกับคอมพิวเตอร์ผ่านพอร์ต USB ทำให้เครื่องมือพัฒนาบนฝั่งคอมพิวเตอร์สามารถตรวจสอบและควบคุมหน่วยประมวลผลหลักของบอร์ดได้

บอร์ด STM32 Nucleo มีตัวแปลง ST-Link ที่ส่วนหัวของบอร์ด

แต่การใช้อุปกรณ์ programmer/debugger ของบอร์ด ARM ตระกูลอื่น เช่น ST-Link และ J-Link ยังมีข้อจำกัดบางอย่าง ทำให้ยังใช้กับ RP2040 ไม่ได้ เช่น

  • ไม่รองรับ multi-drop SWD ที่จำเป็นสำหรับการเข้าถึงหน่วยประมวลผลแบบ dual core
  • ซอฟต์แวร์ไดรเวอร์ที่นิยมใช้ เช่น OpenOCD หรือ PyOCD ยังไม่รองรับ

สถานะล่าสุดของการดีบั๊กบอร์ดของ RP2040 จึงมีทางเลือกหลักอยู่ 2 แนวทางคือ การใช้เฟิร์มแวร์ picoprobe และ pico-debug ทำงานบน RP2040 เพื่อเชื่อมต่อกับพอร์ต SWD ใน RP2040 เอง

การดีบั๊กโค้ด C/C++ SDK ด้วย picoprobe

บอร์ด Raspberry Pi Pico ไม่ได้ติดตั้งตัวแปลง USB-SWD มาด้วย จึงต้องเตรียมฮาร์ดแวร์เพิ่ม เพื่อเปิดให้คอมพิวเตอร์สามารถเข้าควบคุมหน่วยประมวลผลได้ ทั้งนี้ทางทีมพัฒนา RP2040 ได้พัฒนาเฟิร์มแวร์ picoprobe สำหรับใช้บอร์ด RPi Pico เป็นตัวแปลง USB-SWD โดยดูรายละเอียดได้จากภาคผนวก A ของเอกสาร Getting started with Raspberry Pi Pico ข้อดีของวิธีนี้ คือ ตัวบอร์ด RPi Pico ที่ถูกโปรแกรมเฟิร์มแวร์ picoprobe จะทำหน้าที่เป็นทั้ง USB-SWD และ USB-UART ทำให้สะดวกในการตรวจสอบส่วนโค้ดบนบอร์ดที่ถูกตรวจสอบทั้งสถานะ runtime และ halt

การใช้บอร์ด RPi Pico เป็น programmer/debugger ผ่าน SWD

การเตรียมการบนฝั่งคอมพิวเตอร์จะใช้ซอฟต์แวร์โอเพนซอร์ส OpenOCD และ GDB เป็นตัวเชื่อมกับเครื่องมือพัฒนา เช่น VS Code โดยมีขั้นตอนดังนี้

  1. เชื่อมต่อขา 3V3, GND, GP2 -> SWCLK, GP3 ->SWDIO
  2. ดาวน์โหลดและติดตั้งไฟล์ picoprobe.uf2 ลงบอร์ด Raspberry Pi Pico โดยกดปุ่ม boot และรีเซ็ต แล้วคลิกลากไฟล์ลงในไดร์ฟ RPI-RP2
  3. ดาวน์โหลดและเรียกใช้โปรแกรม Zdiag เพื่อติดตั้งไดรเวอร์ WinUSB ให้กับบอร์ดที่ติดตั้งเฟิร์มแวร์ picoprobe
  4. เช็ค Device Manager ว่ามี Picoprobe และพอร์ตอนุกรม แสดงแล้ว
  5. เรียกใช้ Developer Command Prompt for Pico จากนั้นพิมพ์คำสั่งเพื่อทดลอง OpenOCD: openocd -f interface/picoprobe.cfg -f target/rp2040.cfg
การใช้งานไดรเวอร์และใช้งาน OpenOCD ร่วมกับ picoprobe

หลังจากยืนยันว่า OpenOCD สามารถเชื่อมต่อกับเฟิร์มแวร์ picoprobe บนบอร์ดที่เตรียมไว้ ให้ปิดหน้าต่างของ Developer Command Prompt แล้วเปิด VS Code แล้วเตรียม project สำหรับ C/C++ SDK จากนั้นให้ทำตามขั้นตอนดังนี้

  1. สร้างโฟลเดอร์ .vscode สำหรับไฟล์ setting เฉพาะ project นี้
  2. เตรียมไฟล์ launch.json และ settings.json เพื่อใช้งาน OpenOCD ในการ program/debug ผ่าน picoprobe ตามเนื้อหาที่แนะนำในเว็บ digikey (หากใช้ pico-setup-windows ในการติดตั้ง C/C++ SDK โฟลเดอร์ของ openocd จะอยู่ใน C:/Users/<ชื่อผู้ใช้>/Documents/Pico/tools/openocd-picoprobe/)
  3. เลือกเมนู Run > Start Debugging หรือกดปุ่ม F5 เพื่อทำการ build > deploy > debug โค้ด
  4. VS Code จะแสดง toolbar ด้านบนสำหรับฟังก์ชันต่างๆที่ใช้ควบคุมหน่วยประมวลผล ได้แก่ Reset device / Continue / Step over / Step in / Step out / Restart / Stop และแสดงลูกศรชี้ตำแหน่งโค้ดปัจจุบัน
หน้าจอ VS Code ในโหมด Debug

เนื้อหาของไฟล์ launch.json

{
"version": "0.2.0",
"configurations": [
{
"name": "Pico Debug",
"cwd": "${workspaceRoot}",
"executable": "${command:cmake.launchTargetPath}",
"request": "launch",
"type": "cortex-debug",
"servertype": "openocd",
"gdbPath" : "arm-none-eabi-gdb",
"device": "RP2040",
"configFiles": [
"interface/picoprobe.cfg",
"target/rp2040.cfg"
],
"svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd",
"runToMain": true,
"postRestartCommands": [
"break main",
"continue"
],
"searchDir": ["C:/Users/<ชื่อผู้ใช้>/Documents/Pico/tools/openocd-picoprobe/scripts"],
}
]
}

เนื้อหาของไฟล์ settings.json

{
"cmake.statusbar.advanced": {
"debug": { "visibility": "hidden" },
"launch": { "visibility": "hidden" },
"build": { "visibility": "default" },
"buildTarget": { "visibility": "hidden" }
},
"cmake.buildBeforeRun": true,
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
"cortex-debug.openocdPath": "C:/Users/<ชื่อผู้ใช้>/Documents/Pico/tools/openocd-picoprobe/openocd.exe"
}

การดีบั๊กโค้ด C/C++ SDK ด้วย pico-debug

CMSIS-DAP คือ โพรโทคอลสำหรับเฟิร์มแวร์ของอุปกรณ์ debugger ที่ใช้เชื่อมต่อกับส่วนคอร์ของหน่วยประมวล ARM Cortex ซึ่งเป็นมาตรฐานที่ ARM กำหนดขึ้นเพื่อให้การเชื่อมต่อหน่วยประมวลผลผ่านพอร์ต USB เป็นแนวทางเดียวกัน การที่ RP2040 เป็น dual-core ARM จึงได้มีนักพัฒนาสร้างเฟิร์มแวร์ pico-debug ที่ทำงานในคอร์ proc0 ตามข้อกำหนด CMSIS-DAP เพื่อใช้ในการดีบั๊กโดยไม่ต้องมีฮาร์ดแวร์เพิ่มเติม เฟิร์มแวร์ pico-debug ถูกพัฒนาให้ทำงานจาก RAM หลังจากลากไฟล์ pico-debug-gimmecache.uf2 ลงในไดร์ฟจำลอง RPI-RP2 (กดปุ่ม boot + รีเซ็ต) จะยึดส่วนเชื่อมต่อ USB มาทำงานเป็น debugger แบบ CMSIS-DAP ทันที

การเชื่อมต่อกับ pico-debug

อย่างไรก็ตาม OpenOCD ที่ติดตั้งด้วย pico-setup-windows ยังเป็นรุ่นเก่าจึงยังไม่รองรับโพรโทคอล CMSIS-DAP จึงต้องติดตั้ง OpenOCD รุ่นใหม่ตามขั้นตอนดังนี้

  1. ดาวน์โหลดและขยายไฟล์ OpenOCD ที่ prebuilt สำหรับ Windows
  2. นำไฟล์ openocd.exe libusb-1.0.dll และ libhidapi-0.dll ไปแทนไฟล์เดิมที่ติดตั้งใน C:/Users/<ชื่อ user>/Documents/Pico/tools/openocd-picoprobe/
  3. ย้ายโฟลเดอร์ scripts ไปแทนโฟลเดอร์เดิม
  4. เรียกใช้ Developer Command Prompt for Pico จากนั้นพิมพ์คำสั่งเพื่อทดลอง OpenOCD: openocd -f board/pico-debug.cfg
  5. แก้ไขข้อกำหนดในไฟล์ platformio.ini เพื่อเลือกใช้ CMSIS-DAP
  6. แก้ไขไฟล์ launch.json โดยเปลี่ยนข้อกำหนดของ OpenOCD
ข้อกำหนดสำหรับไฟล์ platformio.ini
upload_protocol = cmsis-dap
debug_tool = cmsis-dap
เงื่อนไขสำหรับไฟล์ launch.json
"configFiles": [
"board/pico-debug.cfg"
],

การดีบั๊กโค้ด Arduino

การทดสอบ Arduino framework ที่มากับ Platform.io ณ วันที่เขียนบทความนี้ในเดือน พค. 65 พบว่ายังมีปัญหาในการเชื่อมต่อผ่าน OpenOCD ทั้งกรณีการเชื่อมต่อผ่าน picoprobe และ pico-debug โดยพบปัญหา DAP Init failed แม้ว่าจะเรียกให้ OpenOCD ทำงานได้แล้ว แถมด้วยปัญหาจุกจิกคือ ไฟล์ launch.json จะถูกอัพเดทตอนเริ่มทำงาน ทำให้ต้องมาคอยเพิ่มข้อกำหนดในการดีบั๊กผ่าน OpenOCD

สถานะล่าสุดคือ มี branch ของการพัฒนาที่แยกออกจาก Arduino core ที่รองรับการใช้ picoprobe และ pico-debug จึงคงต้องรออีกสักพักกว่าฟีเจอร์ debug จะลงตัวและ merge เข้ากับ main branch ของ platform.io

終わりに (ในตอนท้าย)

การดีบั๊กหน่วยประมวลผล RP2040 ผ่านทางส่วนเชื่อมต่อ SWD ทำได้ไม่ยากนักด้วย 2 ตัวเลือกราคาถูกคือ ใช้บอร์ด Raspberry Pi Pico ที่ติดตั้ง picoprobe หรือใช้เฟิร์มแวร์ pico-debug ข้อแตกต่างอยู่ที่ฟังก์ชันของส่วนโค้ด โดย picoprobe จะ ok ในภาพใหญ่แม้จะเปลืองบอร์ดเพิ่ม ส่วน pico-debug จะสะดวกกว่าแต่จะใช้ไม่ได้หากต้องใช้ USB หรือ dual core อีก 1 ตัวเลือกที่ยังไม่ได้ทดลองคือ raspberrypi-swd ซึ่งเป็นการใช้เทคนิค bit-bang ในการควบคุมขา GPIO เพื่อเชื่อมต่อแบบ SWD

คำเตือน โปรแกรม Zdiag อาจทำให้เกิดปัญหากับไดรเวอร์ของ CMSIS-DAP จนทำให้โปรแกรม openocd ไม่สามารถหาอุปกรณ์ได้ (ข้อความ Error: unable to find a matching CMSIS-DAP device) วิธีแก้ไขไม่สามารถใช้การ uninstall ไดรเวอร์แบบปกติได้ ให้ทำตามขั้นตอนดังนี้

  1. พิมพ์คำสั่ง pnputil.exe -e > pnplist.txt เพื่อตรวจสอบรายการของอุปกรณ์ plug-and-play
  2. ค้นหา Signer ของอุปกรณ์ USB รหัส VID_1209&PID_2488 เพื่อหา Published name: oem???.inf
  3. พิมพ์คำสั่ง pnputil.exe -d oem???.inf เพื่อลบไดรเวอร์

อ่านเพิ่มเติม

  1. Debugging the Raspberry Pi Pico on Windows 10
  2. Raspberry Pi Pico and RP2040 — C/C++ Part 2: Debugging with VS Code
  3. Arduino core for Raspberry Pi Pico

--

--

Supachai Vorapojpisut
Supachai Vorapojpisut

Written by Supachai Vorapojpisut

Assistant Professor at Thammasat University

No responses yet