STM32N6 מבוסס על Cortex‑M55 שמגיע עד 800MHz, כולל 4.2MB של SRAM פנימי, ממשקי זיכרון חיצוני, TrustZone ויכולות מולטימדיה, ובדגמי N6x7 גם מאיץ Neural‑ART ל־AI. אבל הפרט שבאמת משנה את צורת העבודה הוא שאין בו Flash פנימי רגיל שמחזיק את אפליקציית המוצר. על מנת לבחון את הבקר ולהרגיש את הכאב על בשרי, החלטתי לרכוש את ערכות הפיתוח ולהרביץ עבודה. בפרויקט מעשי על NUCLEO‑N657X0‑Q נדרשו ארבעה הקשרים נפרדים: FSBL, אפליקציה Secure, אפליקציה Non‑Secure ו־ExtMemLoader שמאפשר לכלי הצריבה להגיע אל ה־NOR החיצוני. שרשרת האתחול הייתה BootROM, אחריו FSBL, אחריו הקוד המאובטח ורק אז האפליקציה הרגילה. זו כבר אינה תוכנית אחת שמגיעה אל main; זו סדרת מסירות אחריות, וכל מסירה כזאת צריכה להכין במדויק את הקרקע לבאה אחריה.
אחרי שהצלחתי להעלות את השרשרת הבסיסית, הוספתי חיישן VL53L9CX דרך I3C ו־DMA, מערכת ThreadX, USBX CDC, זיהוי חיבור USB Type‑C, מסוף טקסט ועדכון A/B חתום עם מצב ניסיון וחזרה לאחור. האתחול מה־Flash החיצוני, החיישן וה־USB כבר נבדקו ועבדו על חומרה אמיתית, בעוד שמנגנון העדכון עדיין דורש בדיקת חומרה מלאה של העברה, Trial Boot ו־Rollback לפני שאפשר לקרוא לו מוכן לייצור. תוך כדי העבודה הבנתי שלא כמות הקוד לבדה יוצרת את הקושי, אלא מספר שכבות האחריות שמתחברות זו לזו. כתובת אחת לא נכונה, פסיקה שנשארה בבעלות Secure, Buffer שנעלם לפני סיום DMA או Generate Code שהחזיר ערך ישן — וכל המערכת יכולה להיעצר במקום רחוק מאוד מהטעות המקורית. במקום לשאול רק איזו פריפריה אני רוצה להפעיל, התחלתי לשאול חמש שאלות רחבות יותר: מי מאתחל את המערכת, איפה הקוד והנתונים חיים, מי בעל כל משאב, מי מחזיק את הנתונים בזמן פעולה אסינכרונית, ומה CubeMX עלול לשנות בפעם הבאה שאייצר קוד. חמש השאלות האלה הפכו בהדרגה את הפרויקט מערפל של מושגים למערכת שאפשר לפרק ולהבין.
השאלה הראשונה הייתה מי רץ לפני מי. בתוך STM32N6 יש BootROM קבוע ש־ST צרבה במפעל, והוא הקוד הראשון שפועל אחרי Reset. הוא אינו האפליקציה שלי; תפקידו למצוא תמונה ראשונית, להעלות אותה אל SRAM ולהעביר אליה שליטה. התמונה הזאת היא FSBL, טוען קטן שמגדיר את הדרך לזיכרון החיצוני ומעלה את שלבי התוכנה הבאים, ולכן בפרויקט שלי הוא טען מה־NOR תמונת Secure ותמונת Non‑Secure נפרדות. הקוד המאובטח הגדיר את חלוקת TrustZone ורק אחר כך העביר שליטה ל־Reset_Handler של האפליקציה הרגילה. ברגע שהבנתי את הסדר הזה, התברר לי גם למה Debug מוצלח אינו הוכחה לאתחול תקין: ה־Debugger יכול להניח קוד ישירות ב־SRAM ולעקוף חלק מהדרך שהמוצר יצטרך לעבור לבדו. לכן הרצתי Blink דרך Debug, ניתקתי מתח וראיתי אותו נעלם, ואז צרבתי שרשרת מלאה ובדקתי שהוא חוזר גם בלי מחשב; בכל מעבר עצרתי ובדקתי את ה־PC, את ה־MSP ואת טבלת הווקטורים, ורק אז עברתי לשאלה הבאה — מאיפה הקוד באמת רץ.
כאן נכנסת שכבת הזיכרון. ב־F4 התרגלתי שהמקום שבו הקוד נשמר הוא בדרך כלל גם המקום שממנו המעבד קורא אותו, אבל ב־N6 אלה שתי החלטות נפרדות. תמונה יכולה להישמר ב־NOR החיצוני, להיות מועתקת ל־SRAM הפנימי ולרוץ משם, או להישאר ב־NOR ולרוץ ב־XIP דרך חלון זיכרון שה־FSBL מיפה. גם 4.2MB של SRAM אינם בריכה אחת חסרת גבולות: יש Linker Scripts, Stacks, Heaps, אזורי TCM ו־Buffers גדולים שצריכים לחלוק את אותו תקציב. ראיתי את הקשר הזה כאשר ניתוח ראשוני של דוחות Stack הוביל אותי להגדיל את Stack עיבוד העומק ל־320KB; במקום לקבל יציבות, ההקצאה הסטטית הגדולה חנקה את ה־Heap שנדרש לספריית העיבוד. רק אחרי שבדקתי את מסלול הקריאות שבאמת פעיל יכולתי להוריד את ה־Stack ל־96KB ולהחזיר כמעט 192KB למערכת. מאותו רגע הפסקתי להתייחס ל־Stack ול־Heap כשני מספרים נפרדים והתחלתי לנהל מפת זיכרון אחת שמציגה כתובת אחסון, כתובת ריצה, גודל מרבי, Buffers קבועים ומרווח אמיתי למצבי שיא.
הזיכרון הוביל ישירות לבעיה הבאה: מי רשאי לגשת לכל אזור ולכל פריפריה. TrustZone אינו Checkbox שמוסיף את המילה Secure לפרויקט, אלא חלוקה פעילה של כתובות, זיכרונות, GPIO, DMA ופסיקות בין שני עולמות. ב־STM32N6 משתתפים בחלוקה הזאת מנגנונים כמו SAU, RIF ו־RISAF, ובקצה נמצאים גם EXTI ו־NVIC שקובעים לאן פסיקה תגיע. באחד משלבי החיבור יכולתי להגדיר את בקר I3C ואת פין החיישן כ־Non‑Secure ועדיין לא לקבל אירוע, מפני שחלק אחר במסלול הפסיקה נשאר בבעלות Secure. מבחוץ זה נראה כמו חיישן שלא עונה או כמו דרייבר שנתקע, אבל בפועל הנתונים הגיעו עד גבול אבטחה שלא הוגדר נכון. אחרי החוויה הזאת בניתי טבלת בעלות: לכל Peripheral, GPIO, DMA, IRQ ואזור זיכרון רשמתי מי מגדיר אותו, מי משתמש בו ובאיזה שלב הוא משתחרר לעולם הלא־מאובטח. הטבלה הזאת הייתה שימושית יותר מעוד ניסיון להוסיף Delay, משום שהיא חיברה את הסימפטום אל מסלול הבעלות המלא.
לאחר שהמשאבים קיבלו בעלים, היה צריך לעשות אותו דבר לנתונים. בפעולה חוסמת הפונקציה חוזרת רק כשהחומרה סיימה, ולכן Buffer מקומי יכול להספיק; בפעולת DMA אסינכרונית הפונקציה חוזרת מיד, בזמן שהחומרה ממשיכה להשתמש בכתובות שקיבלה. בגרסת X‑CUBE‑53L9A1 V1.0.0 שבדקתי מצאתי מסלול שהעביר ל־DMA מצביעים למבנים מקומיים על ה־Stack ואז חזר מהפונקציה. לפעמים עברו כמה פריימים לפני שהתקלה הופיעה, מפני שהזיכרון הישן עדיין נראה תקין, ורק המעבר למבני Context קבועים פתר את בעיית אורך החיים. מעל זה ישב ThreadX עם משימות רכישה ועיבוד, ומעליו USBX ו־USB‑PD עם משימות ו־Callbacks משלהם, כך שגם תזמון הפך לחלק מבעלות הנתונים. בניתי שלושה Slots קבועים לפריימים של החיישן, הפרדתי את משימת ה־USB ממשימת הרכישה והגבלתי את התורים, כדי שמחשב שאינו קורא את המסוף לא יעצור את המדידה הפיזית. העדפתי להפיל תצוגת טקסט ישנה כאשר ה־USB עמוס, במקום לצבור פריימים עד שהזיכרון נגמר או לעצור את החיישן שממשיך לייצר מידע בזמן אמת.
בשלב הזה כבר היה ברור שגם דוגמה רשמית אינה בהכרח מוצר מוכן. בדוגמת USB CDC High‑Speed שנבדקה, Endpoint שמפרסם Packet של 512 בתים קיבל FIFO שידור של 0x10 מילים, כלומר 64 בתים בלבד; המכשיר הופיע במחשב, אבל העברת ה־Bulk הראשונה לא יכלה להתחיל במסלול ללא DMA. הגדלת ה־FIFO פתרה את החסם ולימדה אותי ש־Enumeration מוצלח מוכיח רק את ערוץ הבקרה, לא את נתיב הנתונים. במקביל גיליתי שגם CubeMX צריך לקבל תפקיד מוגדר: הוא מצוין ליצירת שלד של שעונים, פינים, HAL, אבטחה ו־Middleware, אבל הוא אינו מכיר את כל החלטות המוצר שנוספו אחר כך. פעולת Generate Code אחת החזירה את Stack משימת USB‑PD CAD ל־1KB, שינתה קישורים לדרייברי HAL והשמיטה הגדרות שה־FSBL היה זקוק להן; על החומרה נרשמה גלישת Stack בדיוק בשרשרת TCPP0203 ו־RCC. הגדלתי את ה־Stack ל־8KB והוספתי בדיקה שמסרבת לחתום על התמונות כאשר הערך נסוג, וכך הפכתי ידע שהיה תלוי בזיכרון שלי לכלל שהפרויקט יכול לאכוף. חשוב גם לא להאשים את היצרן בכל התאמה: Port ממשפחה אחרת או Stack שמרני הם החלטות שלי, בעוד שמבנה מקומי שנמסר ל־DMA, FIFO קטן מה־Packet או break חסר הם ממצאים נקודתיים שצריך לתעד עם גרסה ושחזור מדויק.
מתוך כל התקלות האלה נבנה אצלי מסלול עבודה הרבה יותר רגוע. אני כבר לא מנסה להפעיל Boot, TrustZone, חיישן, DMA, RTOS ו־USB באותו יום, אלא מסיים כל שכבה בהוכחה שאפשר לראות. תחילה אני בונה FSBL קטן, תמונת Secure קטנה ותמונת Non‑Secure שרק מדליקה LED או כותבת ל־UART, ואז בודק Cold Boot שוב ושוב בלי Debug. לאחר מכן אני מצייר מפת זיכרון שמראה לכל תמונה את הכתובת ב־NOR, כתובת הטעינה, כתובת הריצה והגודל המרבי, ומשווה אותה לקובצי ה־map שה־Linker יצר בפועל. רק כאשר השרשרת הזאת יציבה אני מוסיף פריפריה אחת במצב חוסם, למשל קריאת מזהה מחיישן, כדי להוכיח מתח, פינים, Clock ופרוטוקול בלי לערב עדיין DMA ותזמון. המעבר לפעולה אסינכרונית מגיע אחר כך, יחד עם ציור פשוט שמראה מי מקצה כל Buffer, מי ממלא אותו, מי מקבל Callback ומי מחזיר אותו. בדרך הזאת, כאשר משהו נשבר, נשארת רק שכבה חדשה אחת שיכולה להסביר את השינוי.
אחרי שהפעולה האסינכרונית יציבה אני מכניס RTOS ו־Middleware לפי נתיבי העומס, לא לפי סדר התפריטים ב־CubeMX. עבודה שמאבדת מידע בזמן אמת מקבלת עדיפות על פלט איטי, כל תור מקבל גבול, ו־Stack נקבע לפי דוחות הקומפיילר, מסלול הקריאות ומדידה בזמן ריצה. במקביל אני משאיר UART דרך ST‑LINK כערוץ דיבוג עצמאי, מפני שכאשר אני מפתח USB הוא אינו יכול להיות גם הדרך היחידה להסביר לי למה USB לא עלה. רק אחרי שהאתחול, הזיכרון והתקשורת יציבים אני מוסיף עדכון מאובטח עם Slot פעיל, Slot מועמד, אימות חתימה, Trial Boot ו־Rollback. גם כאן הבעיות הגיעו מהחיבורים: מחיקה מלאה של Slot בגודל 1MB לפני תשובת XMODEM גרמה לשולח לחשוב שהמקלט נתקע, ולכן עברתי למחיקת Sector עצלה; SysTick מאובטח שהושעה הפך Timeout של HAL להמתנה אינסופית; ומנוע PKA התחיל לעבוד רק לאחר שהבעלות, ה־Clock, ה־Reset וה־RNG הוגדרו בעולם Secure. המסקנה שלי היא שהביטוי Secure Boot אינו תכונה שמסמנים אלא מסלול שצריך לבדוק תחת ניתוק מתח, תמונה פגומה, גרסה ישנה ואפליקציה שאינה מאשרת שהיא בריאה.
בפרויקט כזה AI משנה מאוד את מאזן הכוחות. הוא מאפשר לי לחפש במקביל במדריך, בקוד HAL, בדוגמאות הרשמיות, ב־Linker Scripts ובקובצי map, להשוות גרסאות ולחבר בין כתובת Fault לבין פונקציה מדויקת בתוך ה־ELF. בלי העזרה הזאת, מהנדס יחיד עלול לבלות ימים בכל מעבר בין אבטחה, USB, זיכרון חיצוני ו־RTOS, או להזדקק לצוות גדול שבו כל אדם מכיר רק חלק מהתמונה. אבל AI אינו האוסצילוסקופ ואינו בעל האחריות: הוא יכול להציע הסבר משכנע שמתאים למשפחה אחרת או לגרסת תוכנה אחרת. האמת הסופית עדיין מגיעה מהסכמה, מהלוח שעל השולחן, מהבינארי שבאמת נבנה, מרגיסטרי התקלה ומניסוי שאפשר לחזור עליו. מבחינתי AI הוא מכפיל כוח יוצא דופן לחקירה, אבל לא רשות האישור של המוצר.
למנהלים חשוב להבין שהשינוי הזה אינו הופך מהנדסי F4 ותיקים לפחות רלוונטיים. להפך: מי שכבר מבין Timing, פסיקות, Race Conditions, חומרה לא מושלמת והבדל בין Demo למוצר מחזיק בדיוק את היסודות הנדרשים, אבל צריך לתת לו זמן וכלים להרחיב את המפה שלו מפריפריה אחת אל מערכת שלמה. בחירת STM32N6 אינה שדרוג תדר על אותו תהליך, ולכן צריך לתקצב שלב ארכיטקטורה לאתחול ולזיכרון, הכשרה ב־TrustZone, זמן מעבדה, בדיקה אחרי Generate Code, ניתוח Stack ו־Heap ותהליך מסודר של חתימה ועדכון. אם כל אלה נדחפים לסוף הספרינט, החוב אינו נעלם; הוא חוזר בתור Boot אקראי, USB שנתקע או עדכון שאי אפשר לסמוך עליו. ההשקעה החשובה ביותר היא מסלול למידה סביב חומרה אמיתית שבו המהנדס עולה שכבה, מודד אותה, מסביר אותה לחבר צוות ומתעד את ההחלטה. כך הידע אינו נשאר אצל אדם אחד או בתוך שיחה עם AI, אלא הופך לנכס שאפשר לבנות עליו את המוצר הבא.
כאן יש ל־Future Electronics ולאנשי ה־FAE המקומיים מקום שימושי מאוד. Future משקיעה בתכנים ובהדגמות סביב STM32N6, הציגה ב־Embedded World 2026 יישומי ראייה על הבקר, ובישראל נערכה יחד עם ST סדנת Hands‑On של יום שלם; לפי החברה, מהנדסי השטח שלה פועלים בשוק המקומי ומחוברים למומחי היצרן. FAE שמכיר את המשפחה יכול לעזור לבחור גרסה ולוח התחלה, לאתר את הדוגמה הרשמית הקרובה ביותר, לעבור על תכנון Boot וזיכרון, לזהות מגבלה מוכרת ולנסח הסלמה שאיש המפעל יוכל לשחזר. כדי לקבל עזרה כזאת צריך להגיע עם חומר רציני: מספר רכיב ולוח, גרסאות CubeMX ו־STM32CubeN6, קובץ IOC, רצף Boot מלא, map או ELF, כתובות צריבה, רגיסטרי Fault, מדידות ופרויקט מינימלי. Future היא כמובן מפיצה ומרוויחה כאשר רכיב שהיא מייצגת נכנס למוצר, ולכן יש לה אינטרס מסחרי ברור להשקיע ב־Workshop וב־FAE; לא מצאתי עדות לבלעדיות שלה על STM32N6, וגם מפיצים אחרים מציעים את המשפחה. מבחינתי השקיפות הזאת אינה מבטלת את הערך, אלא מגדירה נכון את היחסים: אני משתמש בידע המקומי ובקשר ליצרן, אבל משאיר אצלי את האחריות על הארכיטקטורה, הבדיקות ומפתחות הייצור. ה־FAE מביא ניסיון שטח ונתיב הסלמה, ה־AI מביא רוחב ומהירות, והדוגמאות הרשמיות מביאות נקודת ייחוס; החיבור ביניהם מאפשר גם לצוות קטן להתמודד עם מערכת שבעבר הייתה דורשת מחלקה שלמה.
המעבר מ־STM32F4 ל־STM32N6 עדיין תלול, אבל הוא לא מוחק עשרים שנות ניסיון; הוא דורש להשתמש באותו ניסיון ברמה גבוהה יותר. מי שכבר למד למדוד פסיקה, לא להאמין ל־Delay מקרי ולפחד מ־Buffer ללא בעלים מחזיק בדיוק את היסודות הנכונים, ואחרי שמוסיפים להם Boot, זיכרון חיצוני, גבולות אבטחה ותהליך עבודה מסודר, גם STM32N6 חוזר להיות מערכת שאפשר לפרק, למדוד ולהבין.
הזווית ההנדסית
למה זה מעניין
STM32N6 מראה כיצד Embedded עובר מתוכנית אחת על מיקרו־בקר למערכת שדורשת הבנה משותפת של Boot, זיכרון, אבטחה, RTOS וכלי היצרן. הכתבה מספרת בגוף ראשון כיצד מפתח STM32F4 ותיק התמודד עם המעבר, והופכת ממצאים אמיתיים מפרויקט מורכב למסלול כניסה מדורג למהנדסים ולרשימת השקעות ברורה למנהלים — תוך שימוש שקוף ב־AI וב־FAE של Future Electronics כמכפילי כוח, לא כתחליף לאחריות ההנדסית.

השיחה ממשיכה
תגובות
שאלות, תיקונים ורעיונות שאפשר לבנות מהם משהו.