เป้าหมายของหัวข้อนี้
เหตุผลที่ mtb-only มีบรรทัด UART หนึ่งบรรทัดทุก 10 วินาที สิ่งที่มันไม่ใช่ (ไม่ใช่ LED ไม่ใช่การ publish ทาง MQTT ไม่ใช่ตัวนับบน CM55) และกับดักการต่อดีบักเกอร์ที่มันเกิดขึ้นมาเพื่อเปิดเผย เมื่อจบบทนี้จะถือว่า [HB] คือเครื่องมือวัดความมีชีวิตของ variant นี้ และจะไม่ต่อดีบักเกอร์เข้ากับบอร์ดที่กำลังทำงานอยู่
ลำดับการทำงานจริงของเฟิร์มแวร์
คุณสมบัตินี้ทั้งหมดคือ task 11 บรรทัดกับ xTaskCreate หนึ่งครั้ง อยู่ใน proj_cm33_ns/main.c เฉพาะสาขา mtb-only
ตัว task (main.c:105-115):
static void bento_heartbeat_task(void *arg)
{
(void)arg;
for (;;) {
vTaskDelay(pdMS_TO_TICKS(10000));
printf("[HB] t=%lus tasks=%u\r\n",
(unsigned long)(xTaskGetTickCount() / configTICK_RATE_HZ),
(unsigned)uxTaskGetNumberOfTasks());
}
}
การสร้าง task นี้เป็นสิ่งแรกในบล็อก #else (mtb-only) — ก่อนที่เก็บข้อมูล ก่อน config ก่อน IPC pipe — พร้อมคอมเมนต์อธิบายเหตุผลที่การออกแบบกำหนดให้คงไว้คัดมาตามตัวอักษร (main.c:292-303):
xTaskCreate(bento_heartbeat_task, "HB", 256, NULL, 1, NULL);
คอมเมนต์ฉบับเต็ม ยกมาทั้งหมดเพื่อให้คงอยู่แม้ snippet จะมีการแก้ไขในอนาคต:
/* Liveness heartbeat over UART, every 10 s.
*
* This variant has no REPL, so with the boot prints muted the only sign of
* life used to be the debugger — and 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). One line
* every ten seconds is what let that be discovered at all: a heartbeat
* that kept beating for six minutes detached, after an hour of postmortems
* that all blamed the firmware. Keep it until the variant has an
* instrument that is not also the murder weapon. */
xTaskCreate(bento_heartbeat_task, "HB", 256, NULL, 1, NULL);
พารามิเตอร์: stack 256 เวิร์ด ลำดับความสำคัญ 1 (ต่ำสุดเหนือ idle) และไม่เก็บ handle ไว้ task นี้ทำให้สิ่งใดอดตายไม่ได้ และไม่มีสิ่งใดค้างรอมันได้
สิ่งที่มันไม่ใช่
- ไม่ใช่ app_task_beat บน CM55 proj_cm55/main.c เพิ่มค่า volatile uint32_t app_task_beat ทุก 500 ms ใน app_task นั่นเป็นตัวนับที่แสดงบนหน้าข้อมูลวินิจฉัยของ Joystick ไม่มี UART ไม่มี LED ซอร์สระบุว่าการกะพริบ LED นั้นนำออกไปแล้ว "so users can control LED1 from Python without conflict."
- ไม่ใช่สัญญาณชีพของ MQTT tesaiot_mqtt.c มีฟิลด์ config ชื่อ keepalive (tesaiot_config_store.c:127) และค่าเริ่มต้นของ topic ฝั่ง telemetry (device/s/telemetry, tesaiot_mqtt.c:24) แต่ ไม่มี task ที่ publish สัญญาณชีพเป็นระยะอยู่ ในซอร์สชุดนี้ keepalive ของ MQTT คือ PINGREQ ของเซสชันกับ broker ซึ่งจัดการอยู่ภายในไลบรารี MQTT และไม่ได้บอกอะไรเกี่ยวกับเฟิร์มแวร์ส่วนที่เหลือ
- ไม่มีอยู่บน mtb-mpy task นี้อยู่ภายใน #if BENTO_HAS_MPY … #else สัญญาณความมีชีวิตของ mtb-mpy คือ REPL และบรรทัด [MPY] GC heap u KB @ p in s เพียงบรรทัดเดียวตอนบูต (mpy_main.c:552-554)
ทีละขั้น
ขั้นที่ 1 — จับจังหวะให้ได้
ตัดไฟแล้วจ่ายไฟใหม่ให้บอร์ด mtb-only โดยเปิดคอนโซลไว้ที่ 115200
- สิ่งที่ควรสังเกต
- สิบวินาทีหลัง scheduler เริ่มทำงาน จะได้ [HB] t=lus tasks=u (main.c:110-112) — ตัวอย่างใน README ของ dist ฝั่ง mtb-only คือ [HB] t=10s tasks=… (:57) จากนั้นทุก 10 s โดย t เพิ่มขึ้นครั้งละ 10 และ tasks นิ่งเมื่อการบูตเข้าที่แล้ว (ค่านี้จะไต่ขึ้นในไม่กี่วินาทีแรกขณะที่ task ของ WiFi, MQTT และ HSM ถูกสร้างขึ้น) นี่เป็นสัญญาณยืนยันการบูตเพียง หนึ่งเดียว ของ variant นี้ ขั้นอื่นที่สำเร็จล้วนเงียบทั้งหมด (บท A2)
ขั้นที่ 2 — ใช้เป็นเครื่องมือวัดระหว่างการชันสูตรเหตุขัดข้อง
บางอย่างบนบอร์ดดูเหมือนหยุดไป — จอค้าง หรือ page ไม่ตอบสนอง ก่อนจะหยิบดีบักเกอร์ ให้ดูคอนโซลก่อน
- สิ่งที่ควรสังเกต
- หาก [HB] ยังมาทุก 10 s แสดงว่า CM33_NS ยังจัดตารางงานอยู่ ปัญหาจึงอยู่ใน task ใด page ใด หรืออยู่บน CM55 ไม่ใช่คอร์ที่ตาย ประวัติในคอมเมนต์เองคือข้อสรุปนั้น: "a heartbeat that kept beating for six minutes detached, after an hour of postmortems that all blamed the firmware." หาก [HB] หยุดไป แสดงว่า CM33_NS หยุดนิ่งหรือวนอยู่โดย scheduler ค้าง สิ่งที่อ่านต่อคือเครื่องหมาย fault ใน SRAM และรหัส LED (บท A3) และให้ตัดไฟแล้วจ่ายไฟใหม่ หากต้องการคอร์กลับมา
ขั้นที่ 3 — กับดักที่บอกไว้ แต่ไม่ให้ลงมือทำ
- Warning
- ห้ามต่อดีบักเกอร์เข้ากับบอร์ด mtb-only ที่กำลังทำงานอยู่ การทำเช่นนั้นทำให้ CM33 ค้างอยู่ในลูปของ boot-ROM (main.c:292-302 วัดเมื่อ 2026-08-28) variant mpy ทนต่อการต่อแบบเดียวกันได้ ส่วนสาเหตุของความต่างนี้ยังสรุปไม่ได้ นี่คือภาคผนวก X #16 และยกขึ้นไปไว้ในบท A2 ด้วย เพื่อให้อ่านตั้งแต่การแฟลชครั้งแรก
- สิ่งที่ควรสังเกต
- ไม่มีอะไร — ขั้นนี้เป็นคำสั่งไม่ให้ทำ หากต่อไปแล้ว: [HB] หยุดทันทีและไม่กลับมาแม้ถอดดีบักเกอร์ออก หน้าจอค้างอยู่อย่างเดิม (CM55 ยังแสดงเฟรมสุดท้ายของมันต่อไป) มีเพียงการตัดไฟแล้วจ่ายไฟใหม่เท่านั้นที่กู้คอร์กลับมาได้ และสัญญาณชีพจะเริ่มนับใหม่จาก t=10s หากจำเป็นต้องใช้ดีบักเกอร์บน variant นี้ ให้แฟลชแล้ว halt-on-reset จากเซสชันโปรแกรมใหม่ แทนการต่อเข้ากับบอร์ดที่กำลังทำงาน
กับดัก
- ภาคผนวก X #16 — การต่อดีบักเกอร์ทำให้ CM33 ของ mtb-only ที่กำลังทำงานค้างอยู่ในลูปของ boot-ROM (main.c:292-302)
- การเข้าใจผิดว่าความเงียบคือความตาย เมื่อข้อความบูตทุกบรรทัดปิดเสียงหรือคอมไพล์ออกไปแล้ว บอร์ด mtb-only ที่สมบูรณ์ดีจะไม่พิมพ์อะไรเลยนอกจาก [HB] คอนโซลที่ว่างเปล่านานเก้าวินาทีเป็นเรื่องปกติ
- การตีความ [HB] เกินกว่าที่มันเป็น มันพิสูจน์ว่า scheduler ทำงานและ UART ใช้ได้ แต่ไม่ได้พิสูจน์ WiFi, MQTT, ที่เก็บข้อมูล หรือ CM55 — แต่ละอย่างมีสัญญาณของตัวเอง (บท G1, C3, B2)
- การไปหามันบน mtb-mpy มันไม่มีอยู่ที่นั่น ดู สิ่งที่มันไม่ใช่
- การนับ tasks เป็นตัวชี้วัดสุขภาพ ค่านั้นคือ uxTaskGetNumberOfTasks() มีประโยชน์สำหรับจับ task ที่ไม่เคยถูกสร้างหรือ task ที่รั่ว ไม่ใช่ตัวเลขบอกภาระงาน
ขอบเขตการใช้กับ variant
- Variant
- mtb-only task สัญญาณชีพคอมไพล์เฉพาะภายใต้ BENTO_HAS_MPY=0