SDK สำหรับ TESAIoT Dev Kit
คู่มืออ้างอิง API และ Tutorial (ModusToolbox)
Loading...
Searching...
No Matches
A1 — จากไฟล์ zip ถึงโปรแกรมแรก

เป้าหมายของหัวข้อนี้

เมื่อจบบทนี้ บอร์ดจะรันโค้ดที่เขียนขึ้นเอง ไม่ใช่ "ภายในไม่กี่นาที" เพราะการดึง dependency มีขนาดราว 1.9 GB มี patch series ที่ต้องนำไปใช้กับของที่ดึงมา และการ build ครอบคลุม 3 คอร์ ขั้นสุดท้ายคือหัวใจของบทนี้ ได้แก่ โปรแกรมแรกที่อ่านเซนเซอร์จริงและขับ LED จริง ตามรูปแบบของแพ็กเกจที่ถืออยู่

ลำดับการทำงานจริงของเฟิร์มแวร์

คำสั่งทั้งหมดคือ bootstrap ที่ส่งมอบจริง ยกมาจาก README ที่แตกไฟล์ zip ออกมาได้ (README.md:35-44) และตรวจทานกับ README ฉบับหน้า dist ที่ยาวกว่า (release/dist/<variant>/README.md ซึ่งไม่ได้อยู่ในไฟล์ zip)

แพ็กเกจ 2 แบบ ต่างกันเท่าที่ตารางนี้บอก
mtb-mpy mtb-only
คืออะไร ModusToolbox พร้อม MicroPython VM: REPL บน UART, /boot.py และ /main.py, extension module และลิงก์ TACP ที่ BENTO IDE ใช้แฟลช ภาษา C ล้วนบน FreeRTOS ไม่มี VM ไม่มี REPL ไม่มี /main.py ไม่มี TACP
สิ่งที่ต้องมีเพิ่ม micropython-psoc-edge-psoc-edge-main/ วางข้างเทมเพลต (154 MB เป็น repository แยก) ไม่มี
บรรทัดบอกความมีชีวิต [MPY] GC heap u KB @ p in s หนึ่งครั้งตอนบูต (mpy_main.c:552-554) [HB] t=lus tasks=u ทุก 10 วินาที (proj_cm33_ns/main.c:110-112)
ป้ายบนหน้าจอ Home v<BENTOCLAW_VERSION>-mtb_mpy v<BENTOCLAW_VERSION>-mtb_only
วิธีแฟลช make program ผ่าน KitProg หรือแฟลชจาก BENTO IDE make program ผ่าน KitProg เท่านั้น — IDE สื่อสารด้วย TACP ผ่าน UART ของ REPL และ variant นี้ไม่มีทั้ง 2 อย่าง (variants/mtb-only.mk:19-20, :29-31)
โปรแกรมแรก โค้ดไม่กี่บรรทัดที่ REPL task หนึ่งตัวใน proj_cm33_ns/main.c

ไม่ต้องเลือกเอง เพราะ zip แต่ละตัวตั้งค่าเริ่มต้นเป็น variant ของตัวเองไว้แล้ว (common.mk:85 ตั้ง BENTO_VARIANT?=mtb-mpy, :87-89 ปฏิเสธค่าอื่นทุกค่า ส่วนฉบับในไฟล์ zip ของ mtb-only ระบุ mtb-only) ห้ามส่ง BENTO_VARIANT= ทางบรรทัดคำสั่งสำหรับแพ็กเกจที่ดาวน์โหลดมา การส่งค่านี้โดยมีช่องว่างต่อท้ายเป็นกับดักที่ Makefile ป้องกันไว้แล้ว (common.mk:83-85) flag เพียงตัวเดียว ที่ไปถึงโค้ด C คือ BENTO_HAS_MPY (variants/mtb-only.mk:28, :33) ทุก #if BENTO_HAS_MPY ที่จะพบในบทหลัง ๆ คือสวิตช์ตัวนี้ตัวเดียว

การปักรุ่น toolchain: ต้องเป็น ModusToolbox 3.6 เท่านั้น พร้อม ARM GCC ที่มากับรุ่นนั้น (ฉบับในไฟล์ zip README.md:189; ฉบับ dist mtb-mpy:28, mtb-only:29) README ในไฟล์ zip อธิบายว่าเหตุใดรุ่นใหม่กว่าจึงไม่ได้ดีกว่า: Configurator รุ่นหลังจะสร้าง BSP ขึ้นใหม่จาก design.modus แล้วปล่อยข้อความแจ้งเตือนที่ -Werror=cpp เปลี่ยนให้กลายเป็น error ในไฟล์ที่ไม่เคยแก้ไขเลย

ผังของ workspace — ให้แตกไฟล์ zip ไว้ ต่ำกว่า workspace หนึ่งชั้น

<your workspace>/
  mtb_shared/                         created by make getlibs
  bento-firmware-template-mtb-only/   unzip this here

ทีละขั้น

ขั้นที่ 1 — แตกไฟล์และตรวจสอบสิ่งที่ได้รับมา

cd bento-firmware-template-mtb-only
(cd lib && ./verify.sh) # signature + digest of every shipped file

lib/verify.sh ตรวจลายเซ็นดิจิทัลและค่า digest ของ archive (ไฟล์ไลบรารีแบบสแตติก .a) ที่คอมไพล์มาแล้วทุกตัวที่ส่งมอบ (README ฉบับ dist mtb-mpy:34, mtb-only:36) README ทั่วไปในไฟล์ zip เริ่มที่ขั้นถัดไป ส่วนบรรทัด verify อยู่บนหน้า dist

สิ่งที่ควรสังเกต
verify.sh จบด้วยรหัส 0 และรายงานว่า archive ทุกตัวใต้ lib/ ผ่านการตรวจสอบ หากจบด้วยค่าที่ไม่ใช่ 0 แปลว่าแพ็กเกจนี้ไม่ใช่ตัวที่ลงลายเซ็นไว้ — ให้หยุด

ให้สังเกตสิ่งที่ ไม่มี ด้วย: lib/mpy_secure ไม่อยู่ในไฟล์ zip นี้โดยเจตนา ชื่อ lfs_wifi_creds_* ทั้งหกที่ควรได้จากที่นั่น มาจาก bento_libs/claw/common/storage_c/lfs_wifi_creds_c.c ในรูปซอร์สแทน (บท G1)

ขั้นที่ 2 — Doctor

./bento.sh doctor # toolchain + tree check (variant-aware)

README ในไฟล์ zip README.md:35 ("is everything present?"); ฉบับ dist mtb-mpy:35, mtb-only:37 คำสั่ง doctor ตรวจ toolchain และตรวจต้นไม้ไฟล์ที่เทมเพลตนี้จงใจไม่พามาด้วย คำแนะนำของ README ในไฟล์ zip (:54-56): "Fix whatever it reports before building; the errors you get otherwise are long and unhelpful."

สิ่งที่ควรสังเกต
doctor ระบุชื่อ ModusToolbox 3.6 กับ GCC ของรุ่นนั้น บน workspace ที่เพิ่งตั้งใหม่จะรายงานว่าไม่มี mtb_shared/ ซึ่งคือขั้นที่ 3 ไม่ใช่ความล้มเหลว คอมเมนต์ในฉบับ dist ระบุว่า variant-aware กล่าวคือ บน variant นี้ doctor ไม่ถามหา MicroPython port

ขั้นที่ 3 — ดึง dependency ทีละโปรเจกต์

for p in proj_cm33_s proj_cm33_ns proj_cm55; do (cd $p && make getlibs); done

README ในไฟล์ zip README.md:37-41; ฉบับ dist mtb-mpy:37-38, mtb-only:39-40 ("dependencies are fetched PER PROJECT — there is no top-level getlibs") README ในไฟล์ zip บันทึกผลของการรันในโปรเจกต์เดียวไว้ว่า "running it only in proj_cm33_ns fetches 33 of the 41 assets and the build then stops inside ninja on a missing optiga-trust-m file." ขั้นนี้คือขั้นขนาด 1.9 GB จะใช้เวลานานเท่าที่การเชื่อมต่อของเครื่องนั้นทำได้

สิ่งที่ควรสังเกต
../mtb_shared/ ปรากฏขึ้นข้างเทมเพลตและมีไฟล์อยู่ภายใน การรัน make getlibs ทั้ง 3 ครั้งจบโดยไม่มี error สังเกตชื่อคำสั่งด้วย ขั้นนี้ใช้ make รันภายในแต่ละโปรเจกต์ ไม่ใช่ bento.sh

ขั้นที่ 4 — นำ patch series ของ third-party ไปใช้ และพิสูจน์ว่าลงจริง

(cd ../mtb_shared \
&& for p in $(cat ../bento-firmware-template-mtb-only/third_party_patches/series); do
patch -p1 -F0 --forward < "../bento-firmware-template-mtb-only/third_party_patches/$p" || exit 1
done \
&& shasum -a 256 -c ../bento-firmware-template-mtb-only/third_party_patches/PATCHED.sha256)

README ฉบับ dist mtb-mpy:40-45, mtb-only:42-48 ส่วน README ในไฟล์ zip อธิบายข้อกำหนดเดียวกันในรูปความเรียง (:51-53) ว่าเป็นการแก้ไขเฉพาะเครื่องต่อ asset ใต้ mtb_shared ที่ getlibs ไม่ได้ให้มา — "one stops the build, the rest fail silently, including the one that binds the OPTIGA key into the TLS session" ลำดับการนำ patch ไปใช้เป็นไปตามที่ระบุใน third_party_patches/series และใช้ -F0 เพื่อให้ patch ที่ลงไม่สนิทหยุดลูปทันที แทนที่จะเดาตำแหน่งแล้วลงต่อ ส่วน shasum -c เทียบกับ PATCHED.sha256 คือหลักฐาน เพราะตัว build เองจะไม่ยอมเริ่มหาก asset ที่ patch แล้วหายไปหรือผิด และจะบอกด้วยว่าไฟล์ใด

สิ่งที่ควรสังเกต
patch ทุกครั้งรายงานว่า hunk ลงครบ และ shasum -a 256 -c พิมพ์ OK ให้ทุกไฟล์ในรายการ บรรทัด FAILED ที่นี่จะกลายเป็นการที่ build ปฏิเสธไม่ยอมเริ่มในขั้นที่ 5 โดยเรียกชื่อไฟล์เดียวกัน หากแพ็กเกจที่ได้รับมาไม่มี third_party_patches/ มาด้วย README ในไฟล์ zip บอกให้ขอมา (:53)

ขั้นที่ 5 — สร้างทั้ง 3 คอร์

make build -j

README ฉบับ dist mtb-mpy:47, mtb-only:50 README ในไฟล์ zip เสนอวิธีเดียวกันผ่าน wrapper (./bento.sh build, README.md:43, "~10 minutes for a clean build of all three cores") ใช้ได้ทั้งสองแบบ เพราะ wrapper เรียก make ตัวเดียวกัน

สิ่งที่ควรสังเกต
Build complete ปรากฏครบทั้ง 3 คอร์ — CM33_S, CM33_NS, CM55 — และมีบรรทัด undefined reference เป็นศูนย์ error จาก linker ที่ชี้ไปยัง symbol ซึ่งมีอยู่ในซอร์สจริง คืออาการของ object ที่ค้างเก่า ไม่ใช่ฟังก์ชันที่หายไป ให้ลบ proj_cm55/build แล้ว build ใหม่ หากการเชื่อม (link) ฟ้องถึง symbol ของ MicroPython บน variant นี้ แสดงว่ามีบางอย่างนำ BENTO_HAS_MPY=1 กลับเข้ามา ให้ตรวจว่า common.mk:85 ในต้นไม้ไฟล์ที่แตกออกมายังไม่ถูกแก้ไข

ขั้นที่ 6 — แฟลช เปิดคอนโซล แล้วตัดไฟจ่ายไฟใหม่

make program

README ฉบับ dist mtb-mpy:48, mtb-only:51; ฉบับในไฟล์ zip ใช้ ./bento.sh flash (README.md:44)

บอร์ดมีช่องทางข้อความเพียงช่องเดียว คือ UART ของ KitProg ที่ CM33_NS เป็นเจ้าของ (proj_cm55/main.c:9-10: "CM55 must NOT use printf/retarget-io. CM33_NS owns the UART for MicroPython REPL.") ให้เปิดค้างไว้ที่ 115200 8N1 ก่อนตัดไฟจ่ายไฟใหม่ อัตรานี้ระบุไว้ใน README ฉบับ dist ของ mtb-only (:57: "Expect on the UART at 115200") พอร์ตจะปรากฏเป็น /dev/tty.usbmodem* บน macOS, /dev/ttyACM* บน Linux และเป็นพอร์ต COM บน Windows

screen /dev/tty.usbmodem1103 115200
# or: picocom -b 115200 /dev/tty.usbmodem1103
# or: python3 -m serial.tools.miniterm /dev/tty.usbmodem1103 115200
Warning
จากนั้นให้ตัดไฟแล้วจ่ายไฟใหม่ การรีเซ็ตจากดีบักเกอร์ทำให้จอดับ ซึ่งดูเหมือนการแฟลชที่ล้มเหลวทุกประการ (README ฉบับในไฟล์ zip :47-49: "the display backlight needs a cold 0→1 edge and stays dark otherwise, which looks exactly like a failed flash"; ฉบับ dist mtb-mpy:51-52, mtb-only:54) จอที่ดับทันทีหลัง make program เป็นสภาพที่คาดไว้ ยังสรุปไม่ได้ว่าอิมเมจเสีย ให้ถอดสาย USB ออกแล้วเสียบกลับ นี่คือภาคผนวก X #21
ข้อเพิ่มเฉพาะ mtb-only — ไฟส่องหลังจอ (backlight) ตอนบูตเย็นอาจต้องถอดสายแล้วเสียบกลับอีกครั้งหนึ่ง ฉบับ dist mtb-only:55 คัดมาตามตัวอักษร: "the cold-boot backlight can want a second unplug-replug." หากคอนโซลแสดง [HB] เต้นอยู่แต่พาเนลยังดับหลังตัดไฟจ่ายไฟใหม่ครั้งแรก ให้ถอดสายแล้วเสียบกลับอีกครั้งหนึ่งก่อนจะสรุปสิ่งใดเกี่ยวกับอิมเมจ นี่คือภาคผนวก X #22
สิ่งที่ควรสังเกต
การแฟลชจบด้วยบรรทัด verified … bytes จาก programmer จากนั้น หลังถอดสายแล้วเสียบกลับ บนคอนโซลอนุกรมจะได้
[HB] t=%lus tasks=%u

มาจาก proj_cm33_ns/main.c:110-112lu คือจำนวนวินาทีนับจากบูต u คือจำนวน task ของ FreeRTOS นี่คือสัญญาณบูตเชิงบวกเพียงอย่างเดียวบน variant นี้ ขั้นอื่นที่สำเร็จล้วนเงียบทั้งหมด ความเงียบในบรรทัด storage: หมายความว่าการเมานต์สำเร็จ ส่วนความล้มเหลวจะดัง: storage: SMIF setup failed 0x%08lx (bento_storage.c:108) หรือ storage: mount failed (d); volume left untouched (:131) ตามด้วย ERROR: storage unavailable — config and WiFi credentials will use defaults (main.c:306-308)

จากนั้นคือหน้าจอ: ตารางการ์ดของหน้า Home พร้อมป้ายเวอร์ชันตามที่ตารางข้างต้นระบุ (proj_cm55/modules/page-components/_core/page_home.c:485-489) คอมเมนต์เหนือป้ายนั้น (:481-484) อธิบายว่าเหตุใดจึงต้องมี: เคยมีบอร์ด mtb-only ที่ "introduced itself on screen as mtb_mpy, and the only way to tell the truth was a serial console."

ขั้นที่ 7 — โปรแกรมแรก

variant นี้ไม่มี REPL โปรแกรมแรกจึงเป็น task หนึ่งตัวใน proj_cm33_ns/main.c ตัวไฟล์ include ทุกอย่างที่ต้องใช้ไว้แล้ว — cybsp.h (:21), FreeRTOS.h กับ task.h (:26-27) และ sensor_auto_task.h (:29)

ตัวอย่าง (เขียนขึ้นเอง — ไม่มี call site ในของที่ส่งมอบจริง)
/* proj_cm33_ns/main.c — beside the other static task functions */
static void first_program_task(void *arg)
{
(void)arg;
for (;;) {
sensor_auto_bmi270_cache_t imu;
sensor_auto_get_bmi270(&imu);
if (imu.valid) {
/* centi-m/s^2: integers only, like the heartbeat at main.c:110 */
printf("[APP] ax=%d ay=%d az=%d\r\n",
(int)(imu.ax * 100.0f),
(int)(imu.ay * 100.0f),
(int)(imu.az * 100.0f));
if (imu.ax > 3.0f || imu.ax < -3.0f) {
Cy_GPIO_Set(CYBSP_USER_LED1_PORT, CYBSP_USER_LED1_PIN);
} else {
Cy_GPIO_Clr(CYBSP_USER_LED1_PORT, CYBSP_USER_LED1_PIN);
}
}
vTaskDelay(pdMS_TO_TICKS(500));
}
}
/* ...in main(), immediately after the call that is already on line 318 ... */
sensor_auto_task_create();
xTaskCreate(first_program_task, "first", 512, NULL, 1, NULL);

sensor_auto_task_create() มีอยู่ใน main() อยู่แล้วที่ main.c:318 — task เบื้องหลังตัวนั้นอ่านเซนเซอร์ทุกรอบและเก็บค่า BMI270 ล่าสุดไว้ในแคช โปรแกรมนี้จึงเพียงอ่านแคชนั้น sensor_auto_get_bmi270() ประกาศไว้ที่ sensor_auto_task.h:35 (โครงสร้าง sensor_auto_bmi270_cache_t ที่ :26-32, การพัฒนาอยู่ที่ sensor_auto_task.c:1498) และหัวไฟล์ระบุไว้ว่า "lock-free, updated every ~100ms" (:34) ซึ่งเป็นเหตุผลที่ task นี้ ไม่ต้อง take sensor_i2c_lock() เอง — บัสมีเจ้าของอยู่แล้ว (J1 — บัสของเซนเซอร์และ lock ของมัน)

Cy_GPIO_Set คือสิ่งเดียวกับที่ led.on() ทำบน mtb-mpy (modgpio.c:288-291) LED จึงเป็น active-high ส่วน CYBSP_USER_LED1_PORT และ CYBSP_USER_LED1_PIN คือชื่อแทนของ BSP ที่ led_table[] ใน modgpio.c:38-50 สร้างขึ้นมาจาก การพิมพ์เป็นจำนวนเต็มเป็นความตั้งใจ: [HB] ที่ main.c:110-112 ก็พิมพ์จำนวนเต็มเช่นกัน และการเรียก printf("f") ไม่ใช่สิ่งที่บทนี้จะรับรองให้

สิ่งที่ควรสังเกต
บรรทัด [APP] ax=… ay=… az=… ทุกครึ่งวินาที แทรกอยู่ระหว่าง [HB] ที่มาทุก 10 วินาที ขณะวางนิ่ง แกนหนึ่งอ่านได้ราว 980 และอีกสองแกนใกล้ 0 เมื่อเอียงบอร์ดจนแกน X รับแรงโน้มถ่วง ค่า ax จะเคลื่อนออกจากศูนย์และ LED1 ติด หากทุกแกนอ่านได้ 0 ตลอด แปลว่า imu.valid เป็นเท็จอยู่ — ให้ดูบรรทัดความล้มเหลวของบัสตอนบูต ไม่ใช่ที่โค้ดนี้
Warning
การต่อดีบักเกอร์เข้ากับบอร์ด mtb-only ที่กำลังทำงานอยู่ ทำให้ CM33 ค้างอยู่ในลูปของ boot ROM คอมเมนต์เหนือการสร้าง task สัญญาณชีพบันทึกไว้ (proj_cm33_ns/main.c:292-302): "attaching the debugger to a running board parks CM33 in a boot-ROM loop (measured 2026-08-28; the mpy variant tolerates the same attach, cause not established)." variant นี้ไม่มี REPL การไล่จุดบกพร่องของโปรแกรมข้างต้นจึงทำผ่าน printf และ LED เท่านั้น เรื่องเต็มอยู่ที่บท G2 นี่คือภาคผนวก X #16

กับดัก

  • ภาคผนวก X #21 — ตัดไฟแล้วจ่ายไฟใหม่หลังการแฟลชทุกครั้ง (ขั้นที่ 6) หากข้ามขั้นนี้ จะเสียเวลา "ไล่จุดบกพร่อง" ให้กับเฟิร์มแวร์ที่ไม่ได้มีปัญหาอะไรเลย
  • จอดับหลังการแฟลช = การรีเซ็ตจากดีบักเกอร์ ไม่ใช่การแฟลชที่ล้มเหลว เป็นข้อเดียวกัน ที่ย้ำอีกครั้งเพราะเป็นกับดักที่มีโอกาสกินเวลาไปหนึ่งชั่วโมงมากที่สุด
  • การรัน make getlibs เพียงโปรเจกต์เดียว ได้ asset มา 33 จาก 41 ตัว แล้ว ninja หยุดเพราะไฟล์ของ optiga-trust-m หายไป (README ในไฟล์ zip README.md:38-40)
  • การข้าม patch series build จะไม่ยอมเริ่มและบอกชื่อ asset ที่ยังไม่ได้ patch — แต่เกิดขึ้นเฉพาะเมื่อ PATCHED.sha256 ไม่ตรงเท่านั้น ส่วน cy_tls.c ที่ไม่ได้ patch และบังเอิญไม่ตรงกับรายการใดเลย คือความล้มเหลว เงียบ ๆ ที่ README เตือนไว้ กุญแจ OPTIGA จะไม่เคยผูกเข้ากับ TLS และ mTLS จะล้มเหลวในภายหลังมาก ที่บท C4
  • การส่ง BENTO_VARIANT= ให้ zip ที่ดาวน์โหลดมา ไม่จำเป็น เพราะ common.mk:85 ในไฟล์ zip ตั้งค่าเริ่มต้นไว้ถูกต้องแล้ว ช่องว่างต่อท้ายค่าเป็นกับดักที่บันทึกไว้เป็นเอกสารแล้ว (common.mk:83-85)
  • การรอบรรทัด "boot OK" ความสำเร็จบน CM33_NS เงียบ ยกเว้นบรรทัดบอกความมีชีวิตในตารางข้างต้นเท่านั้น การลงทะเบียน PSA/OPTIGA ที่ proj_cm33_ns/main.c:237-244 พิมพ์ข้อความเฉพาะตอนล้มเหลว ผู้อ่านต้องตีความจากสิ่งที่ไม่ปรากฏ — บัญชีเต็มของสิ่งที่พิมพ์ออกมาได้จริงอยู่ที่ ภาคผนวก W — แผนที่สัญญาณ
  • การใช้บรรทัดที่ปิดเสียงไว้เป็นหลักฐาน [WiFi-Boot], [WiFiIPC], [TESAIOT_CFG], [TESAIOT_IPC] และแบนเนอร์ BOOT_VERBOSE ทุกอัน มีอยู่ในซอร์สแต่ไม่เคยพิมพ์ออกมา หากเอกสารใดบอกให้รอบรรทัดเหล่านี้ เอกสารนั้นเก่าเกินจริง
  • ภาคผนวก X #22 — ไฟส่องหลังจอตอนบูตเย็น (mtb-only) ถอดสายแล้วเสียบกลับอีกครั้งหนึ่ง (ขั้นที่ 6)
  • ภาคผนวก X #16 — การต่อดีบักเกอร์เข้ากับบอร์ด mtb-only ที่กำลังทำงานอยู่ (main.c:292-302; ขั้นที่ 7)
  • การคาดหวังให้ BENTO IDE แฟลชบอร์ดนี้ ทำไม่ได้ (variants/mtb-only.mk:19-20)
  • การอ่าน variants/README.md เพื่อดูสถานะการ build ข้อความ "does not build yet, on purpose" และหัวข้อ "Contributing to mtb-only" ในไฟล์นั้นเก่าแล้ว เพราะ blocker ทั้ง 3 ข้อที่ระบุไว้ลงครบแล้ว (variants/mtb-only.mk:1-26) ส่วนจำนวน object/TU ที่อ้างว่า "measured" ตรวจสอบย้อนไม่ได้ อย่านำไปกล่าวซ้ำ

ขอบเขตการใช้กับแต่ละ variant

variant ที่ใช้ได้
mtb-mpy และ mtb-only ลำดับคำสั่งเหมือนกันทั้งสอง variant ความต่างทั้งหมดอยู่ในตารางที่หัวบท: MicroPython port (เฉพาะ mtb-mpy), บรรทัดบอกความมีชีวิต, ป้ายบนหน้าจอ, ช่องทางการแฟลช และรูปแบบของโปรแกรมแรก