SDK สำหรับ TESAIoT Dev Kit
คู่มืออ้างอิง API และ Tutorial (MTB & µPython)
Loading...
Searching...
No Matches
E4 — การอ่านข้อมูลวินิจฉัยของ Edge AI
variant ที่ใช้ได้
mtb-mpy และ mtb-only

แถวข้อมูลวินิจฉัย (diagnostics) บนหน้าจอมีเหมือนกันทั้งสอง variant ส่วน edge_ai.diag() และ ui._diag() เป็นการเรียกบน REPL ของ MicroPython จึงมีเฉพาะบน mtb-mpy เท่านั้น สิ่งที่เทียบเท่ากันบน mtb-only คือแถวบนหน้าจอ บวกกับการเรียก ipc_ui_platform_diag() จากฝั่ง C

Note
เครดิต: โมเดล Edge AI เป็นของ Infineon ไม่ใช่ของ TESAIoT โมเดล motion, audio และ radar ที่เฟิร์มแวร์นี้ส่งมอบ (proj_cm55/modules/ai_models/model_*.c) เป็นผลลัพธ์ที่ export จาก DEEPCRAFT™ Studio และมีลิขสิทธิ์ของ Imagimob AB ซึ่งเป็นบริษัทในเครือ Infineon Technologies ส่วนโมเดล Siren, Cough และ Factory Alarm เป็น DEEPCRAFT™ Ready Model ของผู้สร้างรายเดียวกัน เผยแพร่โดย Infineon อยู่ภายใต้ Imagimob AI Model Evaluation License Agreement และไม่ได้แจกจ่ายต่อในแพ็กเกจนี้ TESAIoT ไม่ได้ฝึกและไม่ได้เป็นเจ้าของโมเดลใดเลย สิ่งที่เป็นของ TESAIoT คือ engine ที่ครอบอยู่ ซอร์สของโมเดลที่ส่งมอบมาระบุเพียง All Rights Reserved โดยไม่มีการให้สิทธิ์ใด ๆ เขียนไว้ในไฟล์ ที่นี่จึงเป็นการให้เครดิต ไม่ใช่การส่งต่อสิทธิ์ การใช้งานที่นี่เป็นไปเพื่อการวิจัยและการอบรม ไม่ใช่การใช้เชิงพาณิชย์ ผู้ที่ต้องการสิทธิ์การใช้งานต้องขอจาก Infineon และ Imagimob โดยตรง ผู้ที่ต้องการฝึกโมเดลของตนเองเริ่มได้ที่ https://www.infineon.com/design-resources/embedded-software/deepcraft-edge-ai-solutions/deepcraft-studio รายละเอียดฉบับเต็มและการอ้างอิงข้อสัญญาอยู่ที่ THIRD_PARTY_NOTICES.md §2.2, §2.4 และ §4.3

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

อ่านพื้นผิวข้อมูลวินิจฉัยทั้งสามแหล่ง — เวิร์ดสัญญาณชีพ (heartbeat) ที่อัดรวมค่าไว้ แถวสถิติบนหน้าจอ และดิกชันนารีจาก edge_ai.diag() — แล้วใช้เงื่อนไขผ่านข้อเดียวที่สำคัญจริง: npu_cycles ต้องเดินหน้าไปเรื่อย ๆ ขณะที่ stale_drops ต้องนิ่งอยู่กับที่ และจะทราบด้วยว่าเหตุใด printf ในโค้ด CM55 ที่เขียนเองจึงไม่พิมพ์อะไรออกมา

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

ระนาบเหตุการณ์ — สัญญาณชีพที่อัดรวมค่า ภายใน set กิ่งของเหตุการณ์เจตนาจะถูกข้ามไปทั้งหมด (deepcraft_task.c:831-836, :853-866: สมาชิกทุกตัวเขียนลง slot เดียวกัน และไบต์เจตนาบอกไม่ได้ว่าโมเดลตัวใดเป็นผู้ทำให้เกิดขึ้น) สัญญาณชีพจึงพาตัวนับที่อัดรวมค่าไว้แทน:

ที่มา
ยกมาจาก deepcraft_task.c:880-917 (คอมไพล์รวมอยู่ใน archive สำเร็จรูป ไม่ได้ส่งมอบมาเป็นซอร์ส)

ระนาบดึงข้อมูล — MODEL_LINK_Q_DIAG ตอบมาจาก callback ของ IPC (deepcraft_task.c:356-395) จึงยังมาถึงแม้ ai_task จะค้างอยู่ และถูกนำออกมาเป็น edge_ai.diag() (modedgeai.c:438-489) getter ที่มันอ่านมีดังนี้:

ที่มา
ยกมาจาก deepcraft_task.c:371-382 (คอมไพล์รวมอยู่ใน archive สำเร็จรูป ไม่ได้ส่งมอบมาเป็นซอร์ส)

ระนาบหน้าจอ — แถวสถิติ page_edge_ai.c:1455-1479 เรนเดอร์ push/s feed/s flush/s … init N/M rc R stale S:

ที่มา
ยกมาจาก page_edge_ai.c:1454-1477 (คอมไพล์รวมอยู่ใน archive สำเร็จรูป ไม่ได้ส่งมอบมาเป็นซอร์ส)

อัตราการป้อนข้อมูลเป็นผลต่างที่วัดในช่วงอย่างน้อยหนึ่งวินาที:

ที่มา
ยกมาจาก page_edge_ai.c:1319-1328 (คอมไพล์รวมอยู่ใน archive สำเร็จรูป ไม่ได้ส่งมอบมาเป็นซอร์ส)

คู่มือฟิลด์

ฟิลด์ Getter อ่านอย่างไร
npu_cycles ai_engine_npu_cycles() เป็น u64 ที่แยกส่งเป็นครึ่งบน/ครึ่งล่างบนสาย การที่ค่าเดินหน้า = NPU กำลังถูกใช้งาน แต่ ไม่ใช่ หลักฐานว่าการอนุมานทำจนจบ
stale_drops ai_engine_stale_drops() ต้องนิ่งอยู่กับที่ขณะที่ npu_cycles เดินหน้า นี่คือเงื่อนไขผ่าน ส่วน ml_state เพียงตัวเดียวเชื่อถือไม่ได้ (modedgeai.c:432-437)
feeds ai_engine_feeds() มีเพียงฟิลด์ "feed" ในข้อมูลวินิจฉัยเท่านั้นที่รายงานปริมาณข้อมูลที่โมเดลรับเข้าไป ให้อนุมานเป็น Hz จากช่วง ≥1 s
dq_ok / dq_calls ai_engine_dq_ok() / ai_engine_dq_calls() dq_ok ค้างอยู่ขณะที่ dq_calls ไต่ขึ้น = NPU ค้าง ส่วน dq_calls ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ — มีการจับคู่ในตัวอย่างที่เขียนขึ้นเองด้านล่าง
init_calls / init_returns ai_engine_init_calls() / ai_engine_init_returns() ให้อ่านคู่กัน ค่า "2/1" = เข้าสู่ init แล้วไม่เคยออกมา
last_init_rc ai_engine_last_init_rc() 0x7FFFFFFF = ไม่เคยถูกเรียก; 0 = ปกติ
inits ai_engine_inits() เป็น nibble ที่อัดรวมอยู่ในเวิร์ดของสัญญาณชีพ
stack_words / stack_free_words ai_engine_stack_words() / ai_engine_stack_free_words() 0 เวิร์ด = เครื่องยนต์ไม่เคยเริ่มทำงาน ส่วน stack_free_words เป็นการสแกนแบบ O(stack) ให้เรียกราว 1 Hz และห้ามเรียกทุกเฟรม

การจับคู่ dq_calls ในตัวอย่างที่เขียนขึ้นเอง:

static void bento_ex_ai_engine_dq_calls(void)
{
static uint32_t last_calls, last_ok;
if (ai_engine_stack_words() == 0u) {
return; /* engine never started — no data */
}
/* Call this block at >= 1 s intervals (e.g. the same 1 Hz slot as
* the watchdog); the deltas are the signal, not the totals. */
uint32_t calls = ai_engine_dq_calls();
uint32_t ok = ai_engine_dq_ok();
uint32_t d_calls = calls - last_calls;
uint32_t d_ok = ok - last_ok;
last_calls = calls;
last_ok = ok;
if (d_calls > 0u && d_ok == 0u) {
/* NPU stall signature: dequeues attempted, none succeeded over
* the whole interval. Surface it — do not silently keep polling.
* (ml_state alone is untrustworthy for this; the counters are
* the evidence.) */
}
}

ทีละขั้น

ขั้นที่ 1 — อ่านแถวบนหน้าจอ (ทั้งสอง variant)

เลือกโมเดลใดก็ได้บนหน้า Edge AI แล้วรอจนขึ้น CHIP_RUNNING

สิ่งที่ควรสังเกต แถวสถิติอัปเดตประมาณวินาทีละครั้ง ค่า feed/s ไม่เป็นศูนย์ คู่ init N/M มี N == M ค่า rc 0 และ stale คงค่าเดิมไว้ขณะที่โมเดลกำลังทำงาน

ขั้นที่ 2 — ใช้เงื่อนไขผ่าน (mtb-mpy)

>>> a = edge_ai.diag(); import time; time.sleep(2); b = edge_ai.diag()
>>> b['npu_cycles'] > a['npu_cycles'], b['stale_drops'] == a['stale_drops']
(True, True)

สิ่งที่ควรสังเกต ได้ (True, True) ส่วนผลลัพธ์แบบอื่นใดคือการค้าง หรือการป้อนข้อมูลที่ขาดแคลน ให้ดูคู่มือฟิลด์ประกอบ

ขั้นที่ 3 — อ่านตัวเลขของ GFX task (แยกตาม variant)

mtb-mpy:

>>> ui._diag()

สิ่งที่ควรสังเกต เวิร์ด 10 ตัวที่ ipc_ui_platform_diag() คืนมา (tesaiot_display.c:593-609): สถานะ IRQ ของ DC, ตัวนับการ flush (flush_start_count ที่เพิ่มขึ้น = เฟรมกำลังไหลอยู่), stack HWM ของ GFX และร้อยละของเวลาว่าง ส่วน ui._diag() อยู่ที่ modui.c:1470

mtb-only: ไม่มี REPL ให้เรียก ipc_ui_platform_diag(out, max_words) จากโค้ด CM55 ที่เขียนเอง โดยต้องมี max_words >= 10 และฟังก์ชันคืนค่ามา 10 เวิร์ด ตัวเข้าถึงตัวนั้น — ไม่ใช่ struct g_tesaiot_display_diag — คือเส้นทางที่รองรับ

ขั้นที่ 4 — ยืนยันว่าไม่มีอะไรบน UART ที่เป็นของ Edge AI

สิ่งที่ควรสังเกต บน mtb-mpy คอนโซลแสดง [MPY] ตอนบูต และไม่มีอะไรต่อการอนุมานแต่ละครั้ง ส่วนบน mtb-only แสดง [HB] t=lus tasks=u ทุก 10 s และไม่มีอย่างอื่น ห้ามรอบรรทัดของ Edge AI เพราะไม่มีอยู่จริง CM55 ไม่ได้เป็นเจ้าของ UART (proj_cm55/main.c:9-10)

กับดัก

Warning
printf บน CM55 กลายเป็น no-op เงียบ ๆ ทันทีที่ลิงก์ libbento_edge_ai.a archive ตัวนี้นิยาม printf และ puts เป็น no-op stub โดยเจตนา (ai_engine.c:276-288; nm -S แสดง symbol ชนิด T ขนาด 8 และ 4 ไบต์) เหตุผลอยู่ที่ ai_engine.c:270-275: UART เป็นของ CM33_NS และ newlib stdio บน CM55 จะไปจับ lock ที่ไม่ใช่ของตนแล้ว panic ดังนั้น printf ใด ๆ ในโค้ด CM55 ที่เขียนเองจะไม่พิมพ์อะไรออกมา และลิงก์ newlib stdio เข้ากับคอร์นี้ไม่ได้ symbol ทั้ง 2 ตัวนี้เป็น ABI hazard ไม่ใช่ API
ml_state ไม่ใช่สัญญาณบอกสุขภาพ ให้ใช้คู่ cycles/stale แทน
ห้ามเรียก stack_free_words() ทุกเฟรม

กล่อง Variant

mtb-mpy mtb-only
ข้อมูลวินิจฉัยของเครื่องยนต์ edge_ai.diag() บวกแถวบนหน้าจอ แถวบนหน้าจอ และ getter ฝั่ง C จากโค้ด CM55 ที่เขียนเอง
ข้อมูลวินิจฉัยของ GFX ui._diag() เรียก ipc_ui_platform_diag() จากฝั่ง C
คอนโซล มีเพียง [MPY] มีเพียง [HB]