← C Programming on Bare-metal STM32 Microcontrollers — מחזור 1

#1 (2025-03-10)

טוען נגן…

תמלול

בטעות לחצתי, אפשר להשאיר את ה-note taker?

כן, יישלח אחרי זה סיכום לכולם בקבוצה. ניתן איזה חצי משפט. אני התחלתי את ההקלטה ב-19:00, תודה רבה שעלייתם בזמן. מי שלא עלה בזמן, יראה את ההקלטה הזאת ופעם הבאה יעלה בזמן. שיחשבו לבד כמה זמן הם בזבזו אם נתחיל בכמה דקות איחור.

מי שלא יצא לו לדבר איתי... מישהו פה במקרה לא יצא לו לדבר איתי? נרשם באיזה... בסדר, נרשם באיזה אורח פלא בלי לעבור דרכי? נראה לי דיברתי עם כולכם.

יכול להיות שלא דיברנו.

נעים להכיר. אז אני שחף, אני קורא לזה מנהל האקדמיה והקהילה של Embedded Academy. מסע מאוד יפה שהתחלנו לפני שנתיים ותפס תאוצה. התחלנו בפיתוחים פשוטים והתחלנו לגלוש, נראה לי בחצי שנה האחרונה, על הליבה של הליבה של הליבה של הברזלים של ה-Embedded.

ואור הוא המרצה הבכיר אצלנו. הוא גם מעביר לנו הרצאות במועדון המפתחים וגם Embedded Linux, שזה קורס שמי שאוהב לסבול מוזמן להצטרף למחזור השני שלו, כי הראשון כבר בעיצומו. Embedded Linux זה קורס כבד, שאני חושב שתצאו מהקורס הזה עם מספיק ידע כדי לדעת שאתם אוהבים Embedded ורוצים לסבול עוד בחיים.

זהו, תודה רבה שנרשמתם. אתם יודעים את הטלפון שלי, מאור אם צריך, אני בקבוצת ה-WhatsApp של ה-Bare-metal שיש לכם, זמין שם, ותראה גם את הטלפון שלי שם. יש לי מספר אמריקאי ב-WhatsApp, עם החברה, בגדול היא בקליפורניה.

וכל מה שקשור לאדמיניסטרציה, כל מה שקשור לדברים שלא מוצא חן בעיניכם, עדיין עיניכם, כל מה שקשור להקלטות, כל מה שקשור ל... לא יודע, דברים שהם מעבר ל... נקרא לזה חומר הלימודי הדידקטי, כעסים על המורה, אז תשלחו לי.

וכל מה שקשור לדברים חכמים שצריך ידע רב ומקיף ב-Embedded, ככה אני עושה לך הרמה לפני שאני מעביר לך את הבמה, אז יש לנו פה את אור, שהוא מהנדס Embedded שהתחיל כבר בצבא להתעסק בפיתוח מערכות. וצבר קילומטראז' מרשים, ואני מאוד שמחתי שהוא הצטרף אלינו לאקדמיה.

אתם צריכים לשאוף ממנו מידע וללמוד להיות מפתחי Embedded. הוא צמח בתעשייה ויש לו המון ידע של איך עושים את זה בעולם האמיתי, Real-time ב-Real world. וזה המטרה שלנו. המטרה שלנו זה לא לחוד חידות, אלא להצליח ללמוד, ומה שלא ברור - אנחנו צריכים שתשאלו. ותבטיחו לי שאתם הולכים לחרוש ולהיות תלמידים טובים, ולעשות תרגולים ולהשקיע בפרויקט.

כי אחרי זה, פיתוח, אתם לא יכולים ללמוד רק מלראות את הפרצוף היפה שלי או של אור, אחד של השני. אתם תצטרכו ללכלך את האצבעות ולשים שומנים על המקלדת ולהתעצבן על ה-ST, ובשאיפה לבלות איזה כמה שעות של תסכול שלא הולך כלום, כי אנחנו הולכים לדגדג בברזלים, וזה לא High-level, אנשים, זה C, כן? זה שפה שהיא נמוכה, זה שפה שהרבה אנשים בורחים ממנה והולכים ל-ChatGPT לדבר איתם בעברית. אנחנו הולכים לכתוב C ולראות Disassembly של דברים.

וזה מעיד עליכם הרבה. זה מעיד... אני מאוד אוהב שכשאני מגייס מפתחים לחברה שיש לי של R&D, אנשי Embedded זה אנשים שצורת החשיבה שלהם היא מדהימה. ואני יודע שמי שמפתח Embedded טוב, מי שיודע לכתוב Low-level ב-C טוב, אם אני אתן לו אפליקציה של Full-stack או אפליקציה של Data analysis או שאני אעשה לו איזה סקריפט Python, זה יהיה ה-costay שלו. כי שום דבר לא קשה מ-Embedded.

אני באמת לא ראיתי מפתחים עם חשיבה כל כך חכמה כמו שמפתחי Embedded, מישהו שבאמת יורד ל-Real-time, ל-microsecond, וחשוב לו כל register שישב במקום. על הבום.

וזהו, אור, קח את זה מכאן. יש לך...

תודה על ההקדמה. אני אתן את ההקדמה עליי, אז אולי כבר אני אשתף את המסך. תגידו לי אם רואים תמונה ויזואלית. רגע. כמובן כי חייב להיות בומר ולא לשתף את המסך הנכון. מעולה.

סבבה, אז ברוכים הבאים לקורס Bare-metal Programming STM32 Microcontrollers.

## מבוא והצגת המשתתפים

אני אספר לכם קצת על עצמי. קוראים לי אור סולימני, יש לי 10 שנים של ניסיון טכני בתעשייה ועוד 7 שנים כ-Software developer. ב-5 שנים האחרונות אני מפתח Embedded בעיקר על Linux, וגם הייתה לי איטרציה על מיקרו-קונטרולרים של Silicon Labs ו-ST.

בצבא הייתי באלקטרוניקה בחיל האוויר. עבדתי על כמה network stacks שקיימים, מדובר על 4G, על TCP/IP, וגם של לוויינים. תחום ההתמחות שלי בגדול זה multi-threaded, multi-process, Real-time C/C++ Embedded Linux.

בעבר עבדתי גם על LTE protocols, שזה 4G, בכל השכבות, אז אם אתם מכירים, אז גם ציינתי אותם פה. וגם כן פרויקט של תקשורת לוויינית בחברת גילת, שנמשך כמה שנים, שבו עשיתי shared process communication, Yocto, ו-Linux kernel driver development.

הניסיון שרלוונטי לקורס שלנו, אז יש פיתוח firmware למיקרו-קונטרולרים של Cortex-M3, M4 של ARM, על IoT devices ו-low-level drivers מהתקשורות שתראו כאן, אז I2C, UART, SPI, ו-RS-ים. הרבה ניסיון ב-hardware bring-up, board-level communication, ואוטומציה ל-firmware hardware ו-QA.

ואאם אני כבר מסיים על הניסיון, אז כל מיני פלטפורמות שאני מאוד חזק בהן, אז Linux, GDB, FreeRTOS, U-Boot, CMake, MQTT, ו-packet processing.

לפני שאני אצלול על הכל, אז הייתי רוצה שכל אחד מכם באמת, כמו שרשמתי לכם, יגיד לי איזה שתיים-שלוש משפטים על עצמו. לא צריך כמו שאני עשיתי כאן, זה באמת אני חתכתי את זה מהקורות חיים שלי כדי שזה יהיה הרבה יותר מרוכז, אבל כזה: מי אני, מה שמי, ומה אני מצפה.

טוב, אני אתחיל. קוראים לי גיל, אני מהנדס אלקטרוניקה ומכונות. אני מתכנת בעיקר Arduino כרגע, ואני חושב שלהוסיף את היכולת הזאת זה מכפיל כוח רציני לדעת לתכנת Low-level, ופותח עוד אפיקים.

על מיקרו-קונטרולרים זה נכון מאוד. לפיכך.

אוקיי, אז אני אציג את עצמי גם. אני מאור. למדתי פיזיקה, ויצא לי לעבוד בכמה חברות אופטיקה כאלה ואחרות. ולא מעט פעמים יצא לי להתעסק באמת עם Arduino. לפעמים באופן יזום, כי מאוד רציתי בכוח להכניס את ה-Arduino לתהליך. ואני אשמח ללמוד על מיקרו-קונטרולרים הרבה יותר, כדי שפעם הבאה זה יצא יותר טוב.

נקסט, חברים, כולם ידברו, פשוט תתחילו.

כן, אני עידו כץ. אני סטודנט שנה רביעית להנדסת תוכנה. במקביל אני עובד באיזה שהוש סטארט-אפ שמתעסק במכונות CNC. אז כן יוצא לי כאילו להתעסק עם הרבה מאוד סוגים שונים של בקרים, ואני פה בעיקר כדי לצלול עוד לעומק ולהבין בתחום הזה. זהו.

אני תומר, אני סטודנט למדעי המחשב, שנה אחרונה. ואני רוצה להיכנס לתחום הזה. יצא לי כבר לתכנת Low-level, וזה משהו שכן קרץ לי ומאוד עניין אותי, לשלב חומרה גם בתכנות. וזה תחום חדש שאני רוצה להתמקצע בו.

אוקיי, אז אני נועם, בוגר מדעי המחשב. עשיתי איזה חצי בדיקה כזאת של Embedded, אז למדתי C, C++ ומה שקשור ל-processes, threading וכאלה. לא ממש נגעתי בברזלים או בקרים או דברים כאלו, ואני רוצה לראות יותר את זה ולבין מה זה ולהיכנס לתחום.

שמי איתי. יש לי ניסיון של 10 שנים בעולם התעופה, סביבה של Embedded, אבל ברמה של High-level. הציפייה שלי להשלים את מה שחסר ב-Low-level.

טוב, אז אני נועם. בגדול אין לי כל כך ניסיון סניוריאלי או משהו, כאילו אני כזה חצי שנה באיזה משרת סייבר R&D כזאת חמודה. ובגדול הציפייה שלי מהקורס שבסופו של דבר, דווקא יותר בפן המחקרי, זאת אומרת לבוא, להצליח לקחת איזשהו firmware ששמו על STM, ולדעת לנתח אותו ומשמה להתקדם. אבל בגדול לדעת לנתח אותו.

אני דור, סטודנט להנדסת תוכנה. ובא לי להיכנס לעולם ה-hardware.

מבורך. כולכם נשמע שיש לכם באמת reasoning מאוד טוב. אני אגיד שאנחנו הולכים לצלול להרבה ארכיטקטורה כאן, ואנחנו הולכים לצלול בהרבה פיתוח שהוא על הברזל, ככה שלהבין איך הדברים נעשים ולהבין איך אנחנו עובדים איתם אנחנו נעשה.

## פילוסופיית הקורס ומטרותיו

הקורס מסתיים באיזה שהיא מימוש שאנחנו עושים ביחד ל-Scheduler, שזה בעצם Scheduler של כמה tasks, ובאיזה ששת השיעורים האחרונים גם יהיה לנו פרויקט. אז הפרויקט זה יהיה או פרויקטים שאני אתן לכם דוגמאות ואתם תמשיכו עם לכתוב design והכל, או דברים שאתם רוצים... שנייה רגע, או דברים שאתם תרצו לממש בסקופ של הקורס, ותוכלו לממש אותם, כמובן.

עוד דבר, יש לנו גם קורס המשך מתוכנן. אני חושב ששחף יציין אותו בהמשך ואת הכל, אבל קורס של פיתוח דרייברים. בקורס הזה גם כן יהיה פרויקט, ככה שאם אתם מתכננים פרויקט וממשיכים, זה גם יכול לעבוד.

אז בואו נדבר... רגע, הייתה שאלה, גיל?

לא, הרמתי את היד קודם.

הבנתי. בואו נמשיך על פילוסופיית הקורס ועל המטרות שלנו.

מבחינתי בפילוסופיה, אין דבר כזה "אני כבר למדתי את זה" או "אני יודע". גם אם אתם למדתם משהו, כמו לדוגמה עכשיו אנחנו נעשה חזרה על C, יכול להיות שלמדתם C ספציפית ל-application ב-Linux, או C ספציפית ל-database או whatever, או איזושהי סטייה ל-Windows, אבל אנחנו פה הולכים לדבר על C למיקרו-קונטרולרים, וזה שונה, במיוחד שה-alignment של ה-MCU שלנו הוא 32 bit, ואנחנו נדבר על כל בהמשך הקורס.

מבחינתי, כל פעם שחוזרים על נושא, כל פעם אפילו שאני חוזר על נושא לקראת הדברים, לומדים עוד דברים חדשים, אז בסדר, קצת סבלנות. לכולנו יש הפרעות קשב וריכוז בשנים האחרונות, אז זה עוזר לנו לתפוס את הדברים.

הצורה שבה אנחנו נלמד, יהיה לנו שיעורים שהם יהיו ברמת קושי עולה. השיעורים יהיו מאוד מבניים כמו שרשמתי, זאת אומרת שדבר ראשון אני מתחיל בצורה תיאורטית, מסביר את כל התיאוריה של השיעור, אחר כך אנחנו פותחים את ה-IDE, כותבים קוד או שיש דוגמאות מוכנות. אני מעדיף שיהיו דוגמאות מוכנות ככה שהכל באמת מסודר, ואנחנו מתחילים לעבוד ולהסביר, אוקיי? אז אם השיעור נראה לכם מתחיל, תחכו קצת, זה מהר מאוד מתקדם, גם אין לנו הרבה שיעורים אז אנחנו מהר מאוד מתקדמים.

אתם תצאו מפה עם הבנה מאוד רצינית של ה-MCU-ים שאנחנו נעבוד עליהם. ואני מאמין גם שתשאלו שאלות, אתם יכולים לשאול אותי, אתם יכולים לשאול בקבוצה, יש פה קבוצה גדולה, מיני קהילה. אם מישהו נתקע במשהו, אז יכול להיות שתצליחו לפתור את זה לפני שאני אגיע לזה. אז יש קבוצת WhatsApp מעולה, תכתבו שאלות והכל, רעיונות לפרויקטים, פשוט תתחילו לשפוך שם מידע.

המטרות שלנו בעצם בקורס, של כולנו, שלי ושלכם, זה בעצם ללמוד לפתח מערכות קטנות. בגדול ה-MCU-ים שאנחנו עובדים עליהם הם מאוד קטנים ואין להם הרבה זיכרון, ככה שכל...

ברגע שאני בוחר כמה פעמים, אם אני לוקח משתנים מסוג uint8_t או מסוג uint16_t, מי שלא מכיר נגיע לזה, רק כדי להבין כמה מעט זיכרון יש. וזו בעצם העבודה אל מול הברזלים: צריך לעשות קוד קומפקטי ויעיל.

נבין קצת קונספטים של bare metal, בעצם איך אנחנו כותבים לרגיסטרים, איך אנחנו משתמשים בהם, איך אנחנו בעצם לומדים את הארכיטקטורה של ה-MCU שאנחנו עובדים עליו, startup code, בעצם איך אנחנו מתחילים, ו-memory-mapped registers. איך אנחנו ממפים בעצם את הבאסים, על הבאס גם כן נדבר, את הבאס לתוך הקוד ומתחילים לעבוד עליו.

נדבר קצת על bare metal ברמה של מה קורה בתוך ה-STM, איך אנחנו עושים קונפיגורציות, איך אנחנו עובדים עם אינטרפטים, שזה דבר שלא עובדים איתו בשאר המקומות. עבודה עם אינטרפטים לרוב לא משתמשים בזה במקומות שהם לא embedded. יכול להיות שעובדים בצורה קצת אסינכרונית, אבל אינטרפטים או interrupt handling לא משתמשים.

## Agenda

נמשיך. אז האג'נדה שלנו להיום.

Introduction שלי כבר עשיתי, דיברנו על ה-philosophy ועל הקורס. נסביר שנייה על ה-course structure ועל ה-repository של הקורס. אנחנו עובדים עם repository של Git. נדבר על course assignments, מה אנחנו עושים, ואז נתחיל לצלול קצת לתוך ה-STM microcontrollers, נדבר על ST ועל המשפחה של ה-STM32.

Real-world applications, למה משתמשים בעצם ב-microcontrollers היפים האלה.

התקנה. ונקנפג STM32CubeIDE, בסדר? שזה IDE, זה Integrated Development Environment, סביבת פיתוח.

נעשה התקנה של GCC. יכול להיות שיש לכם כבר GCC מותקן, אנחנו הולכים להתקין GCC 14.2. אז לא לרוץ ולמחוק, פשוט יהיה לכם עוד התקנה של GCC. ונסביר גם איך אנחנו עושים toolchain setup. ראיתי שיש כמה עם Linux, אני חושב שלכם החיים פשוט הרבה יותר קלים, בסדר?

ונעשה איזשהו alignment ב-C. אני חושב שלרובכם יש ניסיון אז אנחנו נרוץ על זה, ואם אני אראה שאתם ברמה כבר גבוהה, אז בשיעור הבא יש המשך של ה-alignment, אז אני אנסה להריץ אותו עוד יותר, או שנגיע למצב שאנחנו צוללים לכל מיני מקרי קצה של אופטימיזציות וכל מיני storage specifiers, בסדר?

## How the Course is Built

אז איך הקורס בנוי?

כל שיעור בנוי משעתיים: חלק תיאורטי, חלק מעשי, ואנחנו עושים hands-on examples. אתם מוזמנים לעשות follow along בעצם תוך כדי השיעור, לקחת את הדוגמאות ולכתוב. הדוגמאות יהיו לכם ב-Git. מי שכבר עשה clone ראה כבר את הדוגמאות של השיעור היום. היום אנחנו גם נראה לכם איך אני יוצר branch ואיך אתם לוקחים אותו, ככה שתוכלו כבר לקחת את הדוגמאות של הכל.

הכנה לפני השיעור, אוקיי? לכל שיעור, פשוט אני שולח לכם את ה-branch שאנחנו עובדים עליו. אתם עושים לו checkout, ואז יש לכם את כל הקוד ואת כל ה-resources שיהיו. בהמשך יצטרפו לנו גם המסמכים, המסמכים יופיעו ב-Git. כי אין טעם שאני אתן לכם אתר להורדה, פשוט אני שם את המסמכים ב-Git, אז בגדול יהיו לנו שני מסמכים.

יהיה לנו Technical Reference Manual, מה שנקרא בעברית TRM, שזה בעצם כל המידע על ה-MCU שאני עובד ושאתם תעבדו עם שלכם, נמצא שם. ויהיה לנו את מסמך הארכיטקטורה.

אם אני כבר נכנסתי לנושא, אז אני אגיד: אני עובד עם ה-Discovery board הזה. ה-MCU שלי הוא מסוג STM32F411, שזה אומר: ה-F זה הגרסה של ביצועים, 4 זה M4, ו-11 זה איזשהו חרטה שלהם, סליחה, 11 זה משהו שאומר בטח משהו. אבל בגדול זה אומר שיש לנו MCU של M4. מי שמזמין ומחכה ל-MCU שלו, הכל בסדר. יכול להיות שזה אמור להגיע, לי הגיע תוך פחות משבוע מהאתר של ST. אז בגדול סבבה. אני חושב שזה מוזמן דרך Mouser, אבל דרך האתר של ST מקבלים הנחה על המשלוח. עדיף לנסות דרך ST.

בואו נחזור. אז רגע, אז אני הולך לעבוד על כל הארכיטקטורה של M4 של Cortex-M, זאת אומרת שהדוגמאות יהיו של M4. אתם יכולים, נראה לי שאמרתי כבר את זה לכולם כמעט, אתם יכולים פשוט במקום M4 להוריד את המקביל של M7, M3, M0, M33, או יש עוד איזה M1, ולעשות במקביל. החומר של השיעור יהיה דומה בשני המקרים. אני חושב שמספר האינטרפטים אולי שונה ועוד כל מיני דברים, ו-floating point אם אנחנו מתכננים, אבל אין עבודה עם floating point לפחות לא ברמה הזאתי. ובכללי אנחנו לא עובדים עם floating point ב-embedded.

בסדר? זה הכל מהבחינה הזאתי.

Assignments: בעצם יהיו assignments בכל סוף שיעור. אתם לא חייבים להגיש אותם, זה לא קורס באוניברסיטה. אבל אם אתם רוצים, אתם יכולים לשלוח לי, אני אעשה לכם code review, אני אסתכל על מה שעשיתם. אני יכול להגיד שזה השיעור השני, המחזור השני שאני כבר רץ ככה, ולא קיבלתי assignment אחד לבדיקה. אבל בא לכם, תביאו. תקבלו הערות, רק דברים בונים, אני לא באמת... אין ציון.

## Course Repository

סבבה. אז ה-repository של הקורס.

ה-repository של הקורס גם שלחתי לכם אותו וגם כאן אתם יכולים לראות אותו כאן. בגדול זה ה-repository. זה מה שיש בו. עוד שנייה אנחנו נעשה פה clone והכל, נראה איך משתמשים. וגם נתקין קודם כל Git ל-Windows. מי שיש לו Linux, אני מעריך שתסתדרו. אם לא, אז תגידו.

Assignments דיברנו על זה עוד שנייה. באמת אני מעודד אתכם לעשות אותם, אני אתן לכם assignments, אבל אתם יודעים, אף אחד לא מחייב אתכם, כנראה גם שלא תעשו, וזה בסדר גמור.

## STM32 Microcontrollers

בואו נדבר על STM microcontrollers, הסיבה שבעצם אנחנו כאן.

אז STMicroelectronics, סליחה, STMicroelectronics זו החברה שפיתחה את הצ'יפים האלה. הם התחילו בשם אחר, אני חושב שקראו להם SGS-THOMSON. התחילו ב-1987. התמחות באמת: industrial, automotive ו-personal electronics. בשנים האחרונות גם IoT solutions, כי IoT נכנס.

מאוד אוהבים אותם בצבא. אני חושב שזה ה-MCU שמשתמשים בו לכל דבר שלא יוצא מהאטמוספרה, אחרת משתמשים ב-TI בגלל איזשהו תקן של... לא זוכר.

הם בעצם משתמשים בהרבה... בעצם מייצרים הרבה סוגים של מיקרו-קונטרולרים, גם חיישנים, גם power management devices.

הסדרה הכי נמכרת שלהם זה ה-STM32. בעצם משתמשים ב-ARM Cortex MCUs. בעצם כשאני אומר ARM Cortex, זו הארכיטקטורה. ARM זו חברה שמוכרת ארכיטקטורות. מוכרת ארכיטקטורות, זאת אומרת שכל ה-instruction set וגם איך שעובדים בתוך ה-MCU, אז ARM נותנת לך את הרישיון לזה, בעצם את ה-IP, ואתה צריך לממש את זה בתוך ה-MCU שלך מבחינת הסיליקון. סליחה, אתה, החברה.

ל-ST יש בעצם כמה סדרות של MCUs. סיפרתי לכם על ה-F-series שלי, יש גם את ה-ultra-low-power L-series, ויש גם עוד WB שזה ל-wireless, שזה מאוד דומה ל-ESP32 שעכשיו נהיה פירצה. אם אתם רוצים, אתם יכולים לרשום לי שנייה את ה-MCU שאתם רוצים לעבוד איתו. ככה רק את הזה, או מהר להגיד.

ברמה העקרונית אבל זה לא משנה במה אנחנו משתמשים, נכון? כאילו כרגע. מבחינת ה-skills שנתרגל.

זה ממש לא משנה. יש לך איזשהו בורד, תרשום שנדע מה זה. אם כולכם עם M7 אז מבחינתי אני יכול להחליף ל-M7 כי יש לי. אבל לא פחות מ-M4.

יש הבדל מהותי בין ה-755 ל-411?

לא. מבחינתנו לא. מבחינתם אפשר להסתכל על השוואה. אני לא באמת יודע מה המספרים האחרים עושים, האחרים אומרים. אני חושב שיש פה חבר'ה עם ה-Nucleo F411RE, שזה גם אותו דבר, נכון? מי ששלח לי את ה-MCU הזה. בסדר, אם בא לכם תרשמו בצ'אט, אחרי זה נעבור על זה. אם לא, אז לא.

## Microcontrollers vs. CPUs

למה אנחנו צריכים מיקרו-קונטרולרים ומה זה בעצם מיקרו-קונטרולר? מיקרו-קונטרולר זה בעצם איזשהו מעבד קטן עם בעצם איזשהו קור של עיבוד. לדוגמה אם אנחנו מדברים על ARM Cortex אז זה הקור עצמו שבעצם רץ.

יש מרחב כתובות וזיכרון שהוא בעצם תלוי ב-alignment של ה-MCU, שבמקרה שלנו זה 32. אז אם היה לי מרחב כתובות של 8, אם היה לי MCU שהוא 8-bit, אז הייתי יכול ניגש ל-256 כתובות. למה זה המצב? כי בעצם עד 256 בייטים, שזה 256 ביטים שונים, בלי 0, ואז הייתי יכול להשתמש בזה. יש גם אפשרות שבה אנחנו בעצם מחברים כמה בתים לתוך כתובת, אבל זה פחות קורה וזה הרבה פחות יעיל.

היום עם המהפכה הטכנולוגית, מהפכת הסיליקון, המחיר של MCU של 32-bit ושל 8 ו-16-bit נהיה אותו דבר, אז גם אם היית צריך MCU שהוא 8-bit, אתה כבר קונה 32-bit ואתה יכול להשתמש עד $2^{32}$ כתובות בזיכרון. עד $2^{32}$ כתובות של זיכרון שאליהם אתה יכול לשים. אז יש לך בעצם מרחב כתובות הרבה יותר גדול, הרבה יותר מקום להריץ את התוכנית והרבה יותר דאטה. אנחנו נסתכל איך זה נראה בהמשך.

אז מה ההבדל בין מיקרו-קונטרולר ל-CPU?

מיקרו-קונטרולר יש לו בתוך אותו הצ'יפ גם CPU core אחד, או בגדול אחד לרוב, יש לנו memory, יש לנו או flash או RAM שהוא כבר baked in לתוך הצ'יפ. אנחנו לא נראה... במקרה יש לי פה מהקורס השני את ה-BeagleBone Black שעליו אנחנו רצים, אז יש לנו פה את ה-MPU שזה ה-Microprocessor Unit, והזיכרון שלו הוא חיצוני. אז בגדול, ב-MCU שלנו הכל נמצא על אותו הצ'יפ: גם ה-memory, גם הפריפריאלים. בעצם אני לא ניגש לחומרה חיצונית כדי לתקשר איתה, הכל נמצא על צ'יפ אחד, גם ה-Analog to Digital Converter ו-whatnot, כל מה שמשתמשים.

אז בעצם יש לזה אופטימיזציה ל-embedded, ל-real-time, ל-control, והרבה פעמים אנחנו יכולים לקנות צ'יפ שהוא ספציפי ל-environment ספציפית. נגיד בסביבה נפיצה אז יש מיקרו-קונטרולרים ספציפיים. אם אנחנו מדברים ואנחנו חייבים מיקרו-קונטרולר שהוא מאוד מאוד low-power, אז ה-microcontrollers של Silicon Labs הם מאוד קטנים ומאוד low-power.

לעומת זאת, יש לנו CPU, בעצם Central Processing Unit. בדרך כלל משמשים ל-personal computer או ל-שרתים, יש להם זיכרון חיצוני, מה שנקרא הסלוטים של ה-RAM שאנחנו דוחפים, ו-I/O-יים חיצוניים, כל מה שבעצם מפוזר על הלוח. הפוקוס שלו זה הרבה מאוד חישוב והרבה throughput של דאטה שעובר, ו-

ומה שמוגדר לרוב, operating system יותר complex.

כשאומרים Bare Metal, אז אנחנו בעצם מדברים על ריצה בלי operating system לחלוטין. הכוונה של Bare Metal זה כאילו על המתכת, על הברזלים. הרבה פעמים עושים לזה abuse, כי גם עבודה עם FreeRTOS, שזה הקורס השלישי בסדרה, נקראת Bare Metal. אבל Bare Metal לחלוטין זו עבודה ישירה ואי-מימוש של מערכת הפעלה, שזה מה שאנחנו עושים כאן.

## Real World Applications of STM32

קצת על אפליקציות של העולם האמיתי עם STM32.

יש לנו consumer electronics, משעונים... הנוכחות של הצ'יפים האלה, ה-MCU-ים של ST, קצת מפתיעה אותי, איך בעצם עובדים איתם בשעונים ועם כל מיני wearables, אבל זה עדיין קורה. יש כל מיני home appliances, אפשר לחבר את זה לאינטרנט עם מודם ולעשות עם זה מה שרוצים, multimedia.

בעולם ה-industrial יש עבודה מול CAN bus, כל מיני סנסורים וכל מיני מנועים. אלו בעצם האפליקציות של ה-MCU-ים האלה בעולם האמיתי.

IoT ו-connectivity: עבודה עם wireless modules, מימוש של Bluetooth stack או של Wi-Fi, אינטגרציה של סנסורים, או real-time data processing.

Medical and healthcare: הרבה פעמים המיקרוקונטרולר שלנו יושב בתוך מודול רפואי. לדוגמה ב-Medtronic, אני חושב שיש להם שם איזשהו מיקרוקונטרולר שמשתמשים בו כדי לעשות monitoring ל-CO2, לעבד את כל ה-data ולהעביר. הוא שולח את המידע, אם אני לא טועה, ב-UART.

אני רואה שאלה מהקהל: האם יש דרך נוחה לחבר?

כן, בגדול אפשר לקנות כל מודם של Wi-Fi, אתה יכול להתחבר איתו ב-UART. זו בדרך כלל התקשורת. אתה פשוט מתקשר עם ה-Wi-Fi דרך ה-MCU, ננעל על רשת, שולח data, פותח socket, whatever.

## התקנת Git ופקודות בסיסיות

בואו נעשה התקנה. למי מכם יש Git for Windows? אפשר להרים יד.

אני רואה שלושה. אתם מרימים ידיים בכל מיני תצורות שונות, אז מי שאין לו, בואו נעשה מהר התקנה. זה האתר של Git Bash. עושים download ל-Windows. תגידו לי כשתסיימו. נעשה את זה ביחד איתכם. אנחנו מורידים את הגרסה הזאת כאן.

– זה client, ה-Git Bash הזה?

– לא, ב-Git Bash אתה רץ עם Bash בטרמינל.

– החשבון הוא ב-GitHub עצמו?

– זה נותן לך את האפשרות להריץ פקודות.

– שלחת את הלינקים?

– שלחתי אותם בקבוצה פה. אם לוחצים בצ'אט, אפשר להגיע ל-Git עצמו.

– זה לא מופיע לי בצ'אט.

– יכול להיות שעשית את זה private?

– אה, אולי שלחתי את זה לנועם. מצטער.

– העברתי לוואטסאפ. מי שיראה בהקלטה, זה מופיע פה.

– מעולה.

בקיצור נכנסים, מורידים את הלינק עצמו, לוחצים על הלינק. נותנים הרשאות להתקין דברים על המחשב. Next. אם רוצים GUI, יש פה GUI. אני לא יודע להשתמש בו, אבל אם מישהו יודע ואוהב, לסמן גם כן את ה-GUI. לעשות אסוציאציה של קובצי Git, זה יותר בשביל metadata. Profile לא צריך. ל-Windows Terminal, האמת שזה לא רעיון רע, כי אז אפשר לפתוח עם Windows Terminal.

נמשיך הלאה. אני פה בחרתי את Visual Studio Code להיות ה-default Git editor. אתם יכולים לבחור גם ב-Notepad++, או ב-Vim אם אתם יודעים לצאת מ-Vim... אני לא יודע לצאת מ-Vim, זו בדיחה, אני מתנצל. אז תבחרו פה מה שבא לכם.

– אפשר לציין שבמשובים של קורס אחר הבדיחות של אור קיבלו ציון מאוד מאוד גבוה.

– אני מבקש לצחוק.

נמשיך הלאה. גם פה, אתם עוקבים, נכון? תבחרו ב-Let Git decide. בגדול, תנועת ה-woke הגיעה גם לקוד, אז הם לא רוצים שנגיד יותר master ו-slave, הם רוצים להגיד main ו-secondary. תחליטו מה שבא לכם, אבל Let Git decide.

בשלב הבא: Use Git from Git Bash only, זה מה שאנחנו בוחרים.

את OpenSSH אנחנו צריכים גם כן כדי ליצור מפתח SSH, אנחנו נראה איך עושים את זה.

Use native Windows Secure Channel library – עדיף לבחור כאן.

פה יש לנו איזשהו קונפליקט. מה קורה? ב-Windows – אין צורך להעמיק בזה, אתן לכם את זה כאקסטרה – כל ירידת שורה עושים carriage return ו-line feed (CRLF), וב-Linux לא עושים את זה. אם עוברים בין שתי הפלטפורמות יכולות להיות בעיות. לכן הרבה פעמים עושים dos2unix ב-Windows או ב-Linux כדי שיהיה אפשר לעבוד עם הקבצים ולא יהיו תקלות. אז אני פשוט בוחר checkout as-is, commit as-is, ופשוט כל אחד משתמש בזה איך שהוא רוצה ואין לנו שום בעיה.

פה זה הטרמינל שאנחנו נרוץ איתו.

Fast-forward or merge זו הצורה שבה נעשה את ה-merge.

Git Credential Manager.

Enable file system caching ו-Enable symbolic links. רוב הסיכויים שלא נשתמש ב-symbolic links, אבל תעשו לזה Enable.

אם מישהו לא עוקב שיגיד.

ובסופו של דבר Install. אני כבר עשיתי את זה.

– אתה יכול לחזור שנייה עוד פעם על הכל? זריז על האופציות, לראות שלא פספסתי.

– אוקיי, בוא נגיע להתחלה. זו ההתחלה. אמרתי פה, אם מישהו רוצה להוסיף ל-Terminal, זה לא רעיון רע לסמן את זה. אני לא סימנתי ואני לא רוצה לעשות התקנה עכשיו.

אחר כך בחרתי את Visual Studio Code להיות ה-default ל-Git. אם אתם עושים קומיטים, commit amend, יש לכם קונפליקטים, הרבה יותר קל לפתור את זה דרך Visual Studio.

פה לתת Let Git decide.

Use Git from Git Bash only.

Use bundled OpenSSH.

Use native Windows Secure Channel library.

Checkout as-is, commit as-is.

MinTTY.

Fast-forward or merge.

Git Credential Manager.

Enable file system caching.

Enable symbolic links, אם נרצה להשתמש ב-symbolic links, ו-Install.

## יצירת מפתח SSH ל-GitHub

ברגע שנסיים להתקין, יכול להיות שתצטרכו לעשות reboot, תעשו את זה בהפסקה. ההפסקה תהיה חמש דקות לקראת השעה העגולה או אחרי השעה העגולה, תלוי מתי נסתכל על השעון.

אחרי שהתקנו את זה, אנחנו נלך לתוך התיקייה שנרצה להשתמש בה. אני יצרתי תיקייה שנקראת src בתוך המחשב שלי. ומכאן ב-Windows 10, Windows 11 או Linux, תפתחו Git Bash שמופיע לכם. תראו שה-path שמוגדר לכם זה `C:\src` או מה שבחרתם.

אחרי שעשיתם את זה, אתם יכולים לעשות clone לקורס. הלינק נמצא בוואטסאפ.

איך אנחנו עושים clone? מזינים `git clone` ואת ה-repository. יש לנו שתי דרכים לעשות: או HTTPS או SSH. מעניין אתכם לדעת איך ליצור מפתח SSH ל-GitHub? בואו נעשה את זה.

איך אני יוצר מפתח SSH? אני צריך ליצור אותו מכל file system. בגדול, מה שיש לנו פה בתוך ה-MinGW זה file system שונה לגמרי. אם אני אעשה `ls /`, תוכלו לראות שיש לנו כאן bin, MinGW, usr – זה file system משלו. בשביל זה אנחנו צריכים ליצור מפתח SSH.

יש לנו כבר `ssh-keygen` מובנה. ברגע שאתם מריצים `ssh-keygen`, הוא שואל אתכם אם ליצור מפתח חדש ואומר לכם איפה הוא שם אותו. לי אין צורך ליצור מפתח חדש, אבל בגדול אתם עושים enter, enter (ללא passphrase), ואחר כך יהיה לכם מפתח בנתיב הזה.

אם אנחנו רוצים לראות את המפתח: פקודת `cat` נותנת לנו לראות את התוכן של הקובץ. מריצים:

`cat /c/Users/admin/.ssh/id_ed25519.pub`

ומקבלים פה את המפתח המלא שאיתו משתמשים.

אני מעתיק את המפתח הזה, הולך לתוך ה-profile שלי ב-GitHub -> Settings -> SSH and GPG keys -> New SSH key. מדביק אותו כאן, נותן לו שם, ועושה Add SSH key. לי כבר יש אחד כזה שנוצר, אז אין צורך.

ברגע שאני עושה את זה, נוצר איזשהו handshake בין ה-terminal לבין ה-Git client ב-GitHub, ואני יכול פשוט לעשות clone בצורה הזאת.

אם לא עשינו את זה, אנחנו משתמשים ב-HTTPS, והוא יבקש מאיתנו סיסמה. יש גם אפשרות להוריד את זה כ-ZIP – אל תעשו את זה, פשוט תשתמשו ב-Git, כי אני הולך לעדכן כל שבוע את ה-codebase. לעשות כל שבוע מחדש download ו-merge יוצר בלבול. תשתמשו ב-Git, עדיף SSH. ב-HTTPS פשוט תצטרכו להכניס את הסיסמה.

בואו תראו איפה אנחנו: מריצים `pwd`, רואים שאנחנו בתוך `C:\src`. הפקודה שאנחנו עושים היא `git clone`, בעצם להעתיק את ה-remote repository של הקורס אל המכונה שלכם.

מריצים `git clone` ואת הלינק. לי זה כבר קיים, אז אוסיף שם תיקייה חדשה, למשל `class_clone` (אתם לא חייבים להוסיף שם). עכשיו הוא עושה clone לתוך התיקייה הזאת.

`ls`

`ls`

אז יש לי פה שתי תיקיות, אחת מהן זה ה-default של השם של הקורס, ומה שעשיתי עכשיו. אם אני אכנס לתוך class_clone, נעשה ככה, אז אני אוכל לראות שיש לי פה את Lesson_0, את LICENSE, אוי סליחה, ואת ה-README עצמו.

בואו נפתח את ה-README, אז `cat README`. ויש לנו את השינוי הזה. אז אם אנחנו עושים איזשהו שינוי, אז אנחנו רוצים לדחוף אותו בחזרה. בואו נעשה ככה שינוי רק בשביל התרגול, כי אמרתי שאני אעבור על כמה פקודות.

אז אני אלך שוב ל-src בתוך C, class_clone, ואני רוצה לשנות משהו ב-README. בואו נפתח את זה עם Notepad++, ובאמת ככה לכרוב בצורה יפה את כל ה-end line של Windows, ואז אני אעשה:

`class changes to learn Git`

Ctrl+S שומר את זה, אוקיי. ופה אני אעשה `git status`. רואה את השינויים, אז אתם רואים הוא אומר לי יש לך שינויים פה בתוך README.md.

אוקיי. אז ברגע שעשיתי את זה, אז אני יכול להוסיף אותם. אז אני אשתמש ב-`git add`. `git add` עושה לי בעצם איזשהו checkout, מעביר אותי למקום שהוא זמני. `git add README`, רק פעם אחת, ואז הוא מעלה אותם.

יש אפשרות לעשות `git add .` - אל תעשו את זה, זה מקור להרבה בלגן, זה מוסיף את כל השינויים שקרו. אמנם שזה קצת מייגע לפעמים להוסיף קובץ קובץ וזה, אז עדיף ככה.

אם אני אעשה `git status` עכשיו, אני אראה שבעצם יש לי כמה קבצים שמחכים להיות committed, שאני אתחייב עליהם, ואני אעשה להם commit. אז:

`git commit -m "added something to README.md for class study purpose"`

בסדר? ואם אני ארצה עכשיו לדחוף את זה ל-remote, אז `git push`. בסדר, יכול להיות שאתם תצטרכו להכניס את השם ואת הסיסמה שלכם, ועכשיו זה נמצא בתוך ה-main.

כדי שתכלו אתם לקבל את השינויים שאני עשיתי, אז בואו עכשיו נעשה דוגמה כאילו אני עכשיו אעבור אל ה-repository השני שהוא לא מעודכן, כי הוא לא יודע, הוא לא קיבל את המידע הזה. אז נעבור ל-bare metal, הוא גם ב-main. אם אני אעשה `git status`, הוא כבר יגיד לי ש... טוב, יש פה כל מיני דברים שנמחקו... הוא יגיד לי שה-main התקדם יותר ממני.

בואו נעשה ככה: `git fetch` כדי למשוך את השינויים מה-main, ונעשה `git status`. אוקיי, עכשיו הוא אומר לי your branch is behind main על ידי commit אחד. מה אנחנו רוצים לעשות? אז בואו נעשה את זה. לפני הכול, אני צריך להוסיף את השינויים ל-Lesson_1.

אז `git add Lesson_1`. `git pull`, בעצם אני מושך את השינויים מה-branch עצמו, אז אתם רואים, קיבלתי שני שינויים מ-README. וזה בעצם מה שאתם צריכים לעשות. בגדול, אתם לא הולכים לדחוף שום קוד, אבל אתם צריכים לעשות `git fetch`, בעצם לקבל את כל השינויים שנעשו ב-repository, ולעשות `git pull`, לקחת אותם אליכם.

רק אני דוחף קוד. אתם אחר כך כשתרצו, תצרו לכם repository שלכם, תכניסו את זה לתוך ה-GitHub שלכם, זה יהיה חלק מתיק העבודות שלכם. מאוד עוזר למצוא עבודה בימים האלה, ימים שיהיו קשים במציאת עבודה. זה הכול, אוקיי?

אז סבבה. לכל שיעור יהיה branch משלו, אז `git branch` נותן לי את השמות של השיעורים. כרגע יש רק אחד. בואו ניצור branch חדש, אז `git checkout -b` כדי ליצור את ה-branch. בלי זה, זה רק לעבור. `git checkout`, נקרא לזה Lesson_0, אנחנו מתחילים מ-0.

ועכשיו אנחנו שם. אם אני רוצה לדחוף את זה, אז `git push`. הוא אומר לי: אני לא מכיר את זה. `git push --set-upstream`, הוא פשוט נותן לי ממש את הפקודה, אני דוחף את ה-branch ל-remote.

וכאן כבר יופיע ה-branch עצמו. אוקיי, יש לנו עכשיו שני branch-ים, וה-branch שאנחנו עליו הוא Lesson_0. אז אתם צריכים לעשות `git fetch` ולעבור ל-branch לפני כל שיעור. בסדר? זה ברור?

## התקנת GCC והקמת ה-Toolchain

מעולה. אני חושב שעברתי פה על הכול. נמשיך הלאה. GCC.

GCC - למרות שלא שלחתי לכם, כי עוד לא שברנו דיסטנס כל כך, זה GNU C Compiler. זה בעצם קבוצה של מפתחים שמפתחים open source, הם לקחו את ה-compiler של C וקידמו אותו. הם הוציאו לאחרונה את גרסה 14, שזו הגרסה שאנחנו הולכים להשתמש בה.

ואנחנו הולכים להשתמש בה עם toolchain שנקרא MinGW. ה-toolchain בעצם מאגד גם את ה-compiler, גם את ה-linker, וגם את ה-GDB. יש עוד הרבה דברים שכלולים בתוך ה-toolchain. פחות רלוונטי לנו כרגע מה שאנחנו עושים עם ה-toolchain, אנחנו כרגע צריכים רק את ה-compiler, ובחלק מזה גם אפילו לא את ה-linker, בעצם גם את ה-linker נצטרך בדוגמאות של השיעור.

בעצם יש את התהליכים של הקומפילציה. יש את ה-pre-compilation, שזה הדבקה של כל מיני מאקרואים, אנחנו ניגע גם בזה מתישהו בשיעור הבא. יש אחר כך את התהליך של הקומפילציה עצמה, ויש את התהליך של ה-linking, שזה בעצם החיבור של כל הקבצים לתוך executable אחד.

בכל הדברים האלה אנחנו משתמשים ב-toolchain כדי שיתן לנו את השירותים האלה. וה-toolchain שאנחנו הולכים להתקין זה MinGW ל-Windows, כי אנחנו עובדים עם Windows.

מי שעובד עם Linux, החיים שלכם הרבה יותר קלים, אז פשוט, רשמתי פה: `sudo apt-get install build-essential` אם אתם ב-Debian-based distribution. `sudo apt-get install build-essential`.

מישהו אמר לי שהוא הולך לעבוד עם Mac, נכון?

[תלמיד: הסתדרתי בסוף.]

יופי, תודה. אבל בגדול, אתה יכול להתקין גם GCC ל-Mac, אני לא חושב שזה סיפור כזה גדול. סבבה.

אוקיי, אז בואו, אני אשלח לכם את הלינק הזה גם כן. איפה ה-instruction notes? טוב, אין לי את זה כאן, אז אני אשלח לכם את הלינק הזה כאן. רוצים גם ב-WhatsApp? אז זו הקבוצה, סבבה. אשלח גם פה.

בואו נעשה את ההתקנה ככה ביחד. אז אנחנו מגיעים לכאן, בעצם יש לנו את ה-GCC החדש ביותר, 14.2. נגיד שגם אצלנו בעבודה עברנו ל-14.2.

אז בעצם Binutils זה ה-linker ועוד כל מיני דברים שאנחנו מקבלים, אז הוא גם עודכן ל-2.43, שזה גם מאוד חדש. זה לא מעניין. CC בעצם משמש כ-alias ל-GCC, בעצם זה soft link, ו-OpenSSL, ויש גם פאטצ'ים ל-MinGW. כי זה לא רץ natively כמו ב-Linux.

אז אנחנו רוצים בעצם להשתמש, להוריד את מה שאנחנו הולכים להשתמש בו. אז אם אני, רשמתי את זה במצגת, כי זה הרבה יותר קל, אנחנו הולכים לחפש את ה-package שנגמר ב-x86_64 של POSIX, שזה עוד קבוצה של open source maintainers שעושים סטנדרטים בעיקר. וזה עצמו נקרא ככה, אני אשלח לכם את זה כדי שתוכלו לוודא שאתם מורידים את הנכון. בסדר?

אז ככה, הכי קל בעצם לעשות כזה דבר: Ctrl+F, Ctrl+V, ולחפש את זה כאן. זה האחד, אנחנו לוחצים על זה, מורידים אותו.

ברגע שהוא יורד, אנחנו מגיעים ספציפית לזה כאן, בסדר?

[תלמיד: איפה שלחת את זה? ב-WhatsApp?]

את הלינק בשניהם, את השם של זה שלחתי פה בצ'אט. שלחתי ב-WhatsApp, תודה מאור.

סבבה. אנחנו פותחים את זה, כל אחד עושה לזה extract בצורה שלו. אני מקווה שאתם לא צריכים שום דבר כדי לעשות לזה extract. תעשו extract all, כי זה בצורה של 7-Zip.

ברגע שעושים extract, אנחנו מקבלים תיקייה כזאת שנקראת `mingw64`. זה ה-toolchain שבו אנחנו משתמשים. ברגע שזה מסיים, עושים Ctrl+C, ותוקעים את זה במקום שברור לכולם. אני ממליץ להשתמש ב-`C:\`.

אז אתם רואים שיש לי פה `mingw64`. את ההעתקה והכול, אם אנחנו ניכנס לתוך `bin`, אז יש לנו את כל הבינארים שנותן לנו ה-toolchain. אז בואו נדבר עליהם שנייה. CC ראינו שזה בעצם איזשהו לינק ל-GCC, שזה ה-GNU compiler. לקחת את זה, לגרור את זה לתוך ה-`C:\`.

GDB זה GNU Debugger, זה ה-debugger שמשתמשים בו. LD זה ה-linker, מה שמחבר לנו את ה-objects. ויש לנו פה עוד כל מיני... אז ככה, אם אני עכשיו אעשה מפה `cmd`, אוקיי?

אז הוא יפתח לי את ה-command prompt. בואו נעשה שנייה `ls` נראה מה... לא `ls`, אנחנו עובדים ב-Windows, `dir`. אני נמצא בתוך `C:\mingw64\bin`. איך אני רואה current working directory? בסדר, אנחנו רואים את זה, בקיצור. אתה רואה את זה.

כן. אז `C:\mingw64\bin`, אם אני ארצה להריץ עכשיו `gcc.exe --version` כדי לראות את הגרסה, אז אני אראה שהגרסה היא 14. בסדר? אבל אם אני יוצא מהתיקייה הזאתי, GCC לא עובד. למה? כי הוא לא קיים לנו ב-PATH.

אז אנחנו הולכים להוסיף אותו ל-PATH, בסדר? בואו נחזור רק למצגת לראות איפה אנחנו.

[תלמיד: מה זה פה?]

זה בעצם הסביבה שכל מקום יכיר אותה. אתה לא צריך ספציפית להיכנס לתוך התיקייה או לכוון לתיקייה הזאת כדי לקבל את ה-GCC, בעצם יהיה לך איזשהו לינק, symbolic link, שנותנת לך מערכת ההפעלה של Windows, שברגע שתקליד GCC, הוא יכוון אותך ישירות לכאן, אוקיי? ל-PATH הזה.

[תלמיד: מדובר בעצם על המשתנה הגלובלי?]

אני מדבר על כן, בדיוק, על environment variable. תראו עוד רגע על מה אני מדבר ותבינו. בסדר?

[תלמיד: אגב, תוכל להרחיב קצת יותר על ה-linker וכל שאר הדברים שדיברת עליהם? או אם יש צורך וזה יגיע?]

אין בעיה, לשיעור הבא זה מתוכנן. כאילו, הרחבה של כל ה-build process תיכנס בשיעור הבא. סבבה?

[תלמיד: תודה.]

בכיף. באמת העולם של ה-linking זה משהו שכמפתחי C מאוד חשוב לדעת וחשוב להכיר. אני אספר לכם על משהו שאני עושה כרגע, אפילו סיימתי:

ב-Linux יש לנו גם את ה-GCC וגם את ה-glibc, שזה בעצם הסביבה של C וכל פקודות C שאתם מקבלים, ויש אפשרות בעצם לעשות linkage ל-glibc בצורה סטטית. אז אני עושה לכם preview מה זה בצורה סטטית, בעצם שכל executable יכיל בתוכו את כל מה שהוא צריך. ואז אתם מגיעים לאיזשהו executable ששוקל כמה מאות מגה ואתם לא מבינים למה, כי הבאתם את הכול בצורה סטטית. יש אפשרות לעשות linking של פונקציות בצורה דינמית, בעצם ברגע שאני קורא ל... לא יודע, דוגמה הכי פשוטה `printf`...

אז אני לא צריך לבנות את printf לתוך ה-executable שלי. אני בעצם מרים איזשהו printf ש... לך למערכת ההפעלה, אומר לה תביאי לי printf והיא מביאה את ה-printf שנמצא ב-libc שלי. אוקיי, סתם דוגמה, אני ארחיב על הכל בהמשך, אני קצת עושה לכם teasing. בואו נמשיך הלאה. אז איך אנחנו מוסיפים ל-PATH, אוקיי?

## עדכון PATH ב-Windows

אז, רשום כבר כאן. אז או שאני הולך ל-System Properties או שאני רושם כאן environment, ואני עושה Edit the system environment variables, זה אפשרות אחת. אוקיי, והוא פותח לי את הכל בצד השני. או דרך System Properties, Advanced, Environment Variables. אז הנה אנחנו בתוך ה-System Properties, יש לנו את ה-Environment Variables, ויש לנו פה PATH, אוקיי? ואתם רואים, עושים ככה, מוסיפים New ואת ה-PATH לתוך ה-bin, כל ה-bins שהוספנו. אוקיי, אז רושמים פה C, סלאש, ככה, MinGW64, או איך שקראתם לתיקייה, אבל תרשמו ככה שיהיה לנו הכי אחיד, ו-bin, עושים Enter, ו-OK, ו-OK, ו-OK.

אוקיי, ואז אנחנו רוצים לבדוק שזה באמת עובד. אז מה אמרנו, איך אנחנו בודקים שזה עובד? אנחנו יוצאים מהתיקייה הזאתי, נלך לתיקייה של source, כאן, dir, יש לנו פה את מה ששמנו בקלון, ואנחנו עושים gcc --version, ואנחנו רואים שזה פועל עדיין. סבבה? זה כל מה שאנחנו צריכים לעשות.

## התקנה ב-Linux

מי שעובד עם Linux, אז sudo apt-get install build-essential. אם אתם רוצים gcc 14, אתם יכולים לבנות אותו מה-source, כאילו... אתם לא חייבים. אני לא חושב שאנחנו משתמשים בפיצ'רים של gcc 14, אבל בשביל הנוחות תתקינו את האחרון שלא יהיו לנו בעיות ושטויות וכל מיני באגים של קומפיילר, שזה דבר שכנראה קיים. במיוחד עם אופטימיזציות, שבזה אנחנו הולכים לגעת, כן.

שאלות על מה שעשינו כאן? למישהו שלא עבד לו, בעיות?

- לי לא עבד.

- מי זה לי?

- גיל.

- מה לא עבד לך?

- עשיתי את ה-New, הוספתי, ואז ירדתי ל-C, ואז אני עושה gcc --version וזה not recognized.

- נתת את ה-PATH עצמו של MinGW?

- כן.

- שזה C:\MinGW64\bin?

- לא, עשיתי חדש.

- אה, בתוך PATH אתה מוסיף פה חדש, בסדר?

- הבנתי.

- סבבה, תעדכן אם עובד.

טוב, בואו נעשה שני דברים.

- מה אתם עושים עכשיו?

- אנחנו מעדכנים את ה-environment PATH של כולנו. אתם רואים את זה כאן, נכון? אז זה צריך להיות כאן. ואני אשאל שוב, אתם נתתם את זה C:\MinGW64\bin, ככה, בצורה הזאתי?

- כן.

- את התיקייה מהתחלה אני שמתי שמה, כאילו בדקתי שזה באמת ה-PATH.

- אני צריך להעלות אותו למעלה אולי? לעשות לו Move Up כזה, או שזה לא משנה?

- מה הכוונה ב-Move Up?

- יש אפשרות לעשות Move Up, יענו להעלות אותו למעלה, שהוא יראה אותו ראשון.

- בגדול MinGW נמצאת אצלך כאן, אתה רואה? נמצאת לי כאן, כן, ב-C. ב-C, ובתוך bin יש לך את כל אלו?

- בוא אני איכנס רגע ל-bin אסתכל.

- אם אתה עושה פה ככה cmd...

טוב, עכשיו אנחנו נצא להפסקה, אנחנו נחזור עוד 5 דקות, ב-8:11, 8:12.

- אצלך גיל, אתה לא מצליח מה-PATH עצמו?

- לא, בתיקייה של ה-MinGW זה עובד, אבל אם אני יוצא החוצה זה לא עובד. אם אני הולך ל-Variables ועושה PATH ועושה Edit, ואז הוספתי את ה-MinGW, הוא מופיע שם וזה עדיין לא עובד.

- אתה רוצה לעשות לי צילום מסך?

- כן.

שלחתי בוואטסאפ.

- דרך ה-CMD זה כן עובד לי, דרך ה-Git Bash לא עבד. מעניין.

- אוקיי. אה, אתה לא צריך להעלות את זה למעלה, הבנתי מה זה ה-Move Up שאתה מדבר עליו. גם כן לא צריך. בואו תנסו להכניס את זה ל-System Variables, אוקיי? ולהכניס את זה כאן, ו-New, ממש אותו דבר.

- עוד פעם, תחזור רגע? פספסתי את ה...

- יש לנו גם את ה-System Variables עצמו. אוקיי. ו-New, אותו דבר. אין לכם במקרה מחשב בעברית? לא, אני רואה שאצל גיל אין.

- לי גם לא.

- יופי.

אוקיי, נראה. וכיוון שזה Windows...

- אתה אומר ריבוט יעזור?

- זה Windows, אי אפשר לדעת. תנסו לעשות ריבוט ונראה, אוקיי?

- תודה.

- אם עדיין לא, אנחנו נתייעץ עם הבחור שודע את זה, עם ה-IT של העולם, עם הצ'אט. נשאל אותו what the fuck.

- ה-IT של העולם... אהבתי.

עומר וגיל, נכון? רק גיל עדיין לא חזר. ראית מה עשיתי על המסך? עכשיו עובד לי גם ב-Git Bash. נייס, מעולה. כן, תודה.

## התקנה והגדרה של STM32CubeIDE

מעולה. אז לרובנו יש את זה מותקן, מי שלא, נמשיך הלאה. בואו נעשה התקנה של STM32. אוקיי, אז כמו מקודם עם הלינקים, נשלח את זה גם פה, גם בקבוצה.

בואו ניכנס לאתר. זה האתר של ST, ככה צבוע בצבעי ST יפים כאלה. אנחנו רוצים להוריד, אז בעצם אם אנחנו רוצים להוריד אנחנו צריכים... רק שנייה, יתרענן פה... אנחנו צריכים...

להגיע למטה ולהירשם.

מי שיש לו Mac, הוא מתכנן לעבוד עם Mac, מי שמתכנן לעבוד עם Linux, עם איזושהי איזשהו טעם של Debian... שבהצלחה, כאילו פה.

Windows, באמת הגישה, הצורה הכי קלה. אז Get Latest, בסדר? כאן, אני מסכים.

עכשיו, אם אתם רוצים account או שלא, או שאתם פשוט מורידים את זה, אז אפשר פשוט להוריד. לא, הם מאוד לא רוצים את המידע שלכם. אז אין ברירה, פשוט צריך להתקין.

אנחנו ממשיכים. אז login. לי יש כבר login. אם לא, תצרו, תצרו account. וברגע שעושים את ה-login, אני חושב שצריך לחזור לאותה נקודה ולהוריד. בסדר?

אז זה כבר יורד אוטומטית. סבבה. ברגע שזה יורד, אנחנו שוב מגיעים לאיזשהו zip. בואו נחסוך bandwidth. יש לי את זה כבר כאן. אז בואו נפתח. מ-Downloads...

STM, עשינו לו extract, אז יש לנו איזשהו פה קובץ של הרצה. אוקיי. איזשהו אפליקציה. שזה הקובץ של ה-installer. אוקיי.

- מה ההבדל בין standalone ל-portable?

- שאלה טובה. אני חושב שיכול להיות שפשוט בנו את זה עם cross compile או עם איזה משהו כזה, אין לי באמת מושג. ויכול להיות שאחד זה פשוט ה-executable בעצמו, ואחד זה בעצם קובץ התקנה.

- מה אנחנו מורידים? לא שמתי לב.

- את ה-installer.

- אוקיי.

- לא ראיתי פה אפשרות של standalone מול זה... פה את ה-installer כאן, 1.18. ואז זה בעצם מוריד לנו איזשהו Eclipse based IDE. ואני אחזור למצגת, כי יש לי פה את ההסבר על Eclipse.

- מה עושים לאחר ההורדה?

- לאחר ההורדה עושים extract, אוקיי? ומתקינים. לוחצים על... יש התקנה. בואו נעשה התקנה מחדש, אני אבוא איתכם על השלבים. זה בגדול די straight forward. Next, אני מסכים. אני בוחר בהגדרות... בוא נתן לי אפשרויות להרחבה. ותסברו שאפילו עושים התקנה מחדש, בגלל שצריך לעשות restart.

טוב, אז אחרי זה הוא יתחייב, אז אני לא אעצור, אבל בואו נמשיך.

בעצם, אחרי שהתקנו את זה, אנחנו פותחים את ה-STM32. אני אסגור אותו, ואנחנו נפתח את ה-workspace. ואם הצלחתם, ואם אתם הבנתם כבר, אז ה-workspace זה יהיה ה-git שעשינו.

בואו נראה מה אני עושה כאן, כי בעצם התחלתי את ההתקנה. נתן לזה שנייה. ככה, בינתיים.

גיל, האם הצליח לך?

- כן, ה-restart עשה את העבודה.

- מעולה. Windows will always be Windows, מה שנקרא.

- Windows או מה?

- Windows תמיד יהיה Windows.

- כן.

טוב, בינתיים אנחנו מתקינים את זה. אני חושב שגם אתם מחכים. אני אנסה לראות אם אני מצליח לעשות איזשהו שעטנז כזה. אז כן. אז פה, STM. רושם STM, מגיע לי ה-IDE עצמו. IDE זה סביבת פיתוח, נראה לי אמרנו. ואתם מפספסים את הגרפיקה היפה שלה, כי במסך השני משום מה.

בינתיים הוא מעלה, ואז הוא יצטרך לבחור workspace. ה-workspace שאני אבחר יהיה ה-git repository.

אוקיי, אז הגעתי לכאן, יש לי STM IDE, CubeIDE Launcher, ואז הוא מבקש ממני לבחור איזשהו path או איזשהו זה. אז אני בעצם בוחר את זה כאן. זה האחד שאני בוחר. משום מה הגיט קצת התחרפן, נתן לי Lesson 1 כפול. אני אעיף אותו. ואני בוחר את התיקייה של Lesson 0, בסדר? ברגע שבחרתי אותה, אני עושה Launch.

הוא בינתיים לוקח כל מיני... הוא מעתיק כל מיני תיקיות, כל מיני XMLים וכל מיני דברים, מקווה שזה לא יפריע. שוב, יש לי את הגרפיקה של העלייה, וניפתח לי ה-STM Cube עצמו. אוקיי?

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

אז מה אני עושה כדי להשתמש בהם? אני עושה Open, Open Projects from File System... אני בוחר את ה-Directory. בעצם ה-Directory שלי תהיה ה-Directory הזה, אז Select Folder. והוא ימצא את כל אלה, אני אומר לו תמשיך. ולכאן יהיה את כל הדוגמאות.

אוקיי, בגלל שלא כל הדוגמאות, אז בוא נעשה שוב. בוא נעשה Switch Workspace מהתחלה. נתן לו בלי Lesson 0. בוא ננסה ככה. נתן לו את Lesson 0, סורי. ככה, ונבחר. זה כנראה לוקח קצת זמן, כי זה לא ה-IDE הכי חזק.

וזהו. ה-IDE הזה הוא מותאם מאוד ל-STM32. הוא לא הכי נוח מבחינת כתיבת קוד. הרבה פעמים אני יודע שאנשים עובדים עם VS Code לכתוב קוד או עם מה שנוח להם, ואת הקומפילציה וההרצה עושים מכאן. מה שנוח בסביבת פיתוח שמבוססת Eclipse, זה שהן בונות את ה-Makefile ובונות את הקומפילציה בעצמן. זה נוח, אבל מצד שני זה קצת קשה כי אתה לא בעצם יכול לשלוט בזה. יכול להיות שיהיה לך איזשהו circular dependency או ומה לא שעושה לך בעיות.

אני ממש מחכה שהדבר הזה יפסיק כדי שנוכל להתחיל לעבוד. אם אתם צריכים לעקוב, אז עכשיו הוא בעצם מתקין את הספריות של libc בעצם. והוא מעתיק ממש את ה-libc עצמו, כי אנחנו לא התקנו את libc לתוך... בעצם את כל המילים השמורות של השפה, של C ו-C++. אנחנו לא התקנו אותם, אז הוא עכשיו עושה את זה במיוחד. ונחנו יכולים לעשות את הדבר הבא בינתיים.

## C Level Alignment Part 1

בואו נבדוק שיש לנו בעצם... בוא נבדוק שיש לנו קומפילר מקונפג. אז איך בודקים שיש קומפילר מקונפג? אז עושים לבנות, ואאם אנחנו בונים, אנחנו נראה את הפקודות שהוא עושה. אני אגדיל את זה כאן, כדי שתוכלו לראות.

הפקודה שהוא עושה היא gcc -O0, שזה האופטימיזציה, -g3... אנחנו נדבר על אופטימיזציה ועל g בשיעור הבא. -g3 שזה ההעתקה של הסימבולים בשביל ה-debugger. זה בעצם flag ל-debugging. -Wall, בעצם תראה את כל ה-warnings שיש לך, ובעצם זה -fmessage, זה בעצם איזושהי הודעה.

ופה אני קובע... -o קטן קובע לי את ה-output של הקומפילציה. אז ה-output הולך לתוך תיקיית source, basic_types.c במקרה הזה, אנחנו נעשה עוד שנייה Hello World, ומשהו משתמש זה basic_types.c.

ובסופו של דבר הוא עושה עוד פקודה של gcc, שזה הפקודה שעשינו, אז הוא עושה -o לתוך basic_types executable והוא לוקח את ה-object שהוא עשה כאן. סבבה?

בואו ניצור פרויקט חדש.

- שנייה, שנייה שנייה. אם זה לא מופיע לכם...

- איך עשית את הפקודה הזאת?

- אני עשיתי פשוט Build, לחצתי על הפטיש.

- אה, אוקיי. אבל אין לי את ה... עשיתי את ה-project, את ה-workspace ואין את ה... אלה בצד. הוא אומר לי: There are no projects in your workspace.

- עשית Open Projects from File System?

- Open Projects from File System... לא. עכשיו.

- Import project, ואז אתה בוחר Directory, את ה-Directory הזה שנקרא Lesson 0.

- אה-הא.

- כן? Select. Finish.

טוב, זה כבר גם הסתיים. וגם פה.

אוקיי. עכשיו איך אנחנו יוצרים פרויקט חדש לפני שזה? אז New. יש לנו שני סוגים של פרויקטים. היום אנחנו לא עושים פרויקטים שהולכים לתקשר עם החומרה, כי החומרה לא מחוברת. בשיעור הבא אנחנו נעשה, נתחיל ב-Hello World יפה כזה גם מחובר, אבל היום אנחנו נעשה Hello World משלנו.

C/C++ Project, בעצם ייתן לנו את זה. אנחנו נבחר ב-C Managed Build, ככה שהוא יבנה לנו את הכל. ניקרא לזה בשם, ניקרא לו Hello World. Hello World, ופה אנחנו צריכים לבחור, וזה קריטי, ב-MinGW GCC. שזה ה-GCC שהתקנו.

יש מישהו שלא מופיע לו ה-GCC? אם הוא לא מזהה את ה-GCC, אז אנחנו צריכים לעשות כזה דבר: צריכים ללכת ל-Window, Preferences, C/C++, ופה Build... פה הרבה מאוד הגדרות. אני יכול להגיד שאני עדיין לא יודע את כולן, ורוב האנשים גם לא, כי זה פשוט בלתי נגמר. שנייה, אני אנסה להגיע להגדרה הספציפית הזאת שאנחנו מחפשים.

טוב, בסדר. בגדול, אם אתם לא מוצאים, אני אשלח לכם. אני חושב שזה אמור להיות זה, אבל לא מופיע פה. נמשיך הלאה.

בסדר, בואו ניצור פרויקט. New, C/C++ Project, נלך לרוץ על ה-host machine, שזה ה-Windows שלנו. אנחנו ממשיכים עם C Managed Build, ניצור פרויקט של Hello World, ניקרא לו בשם המקורי hello_world_stm32_course. נעשה כבר שיג'נרט לנו את זה. נמשיך. נעשה Finish, והוא ייצור לנו פה, אתם רואים, הוא ייצור לנו למטה את הסביבה.

אני אעשה כזה דבר ואקטין. אז בעצם יש לנו שימוש בשתי ספריות: stdio.h, זה Standard Input Output, זה בעצם איזשהו header file שנותן לנו את כל הכתיבה והקריאה הסטנדרטית, נותן לנו את printf, וגם את puts.

אוקיי? ובעצם, ברגע שאנחנו משתמשים ב-printf, אז הוא בעצם מביא לנו את המידע מה-file descriptor הראשון, אוקיי? stdout. stdout, סורי, stdout. descriptor 1.

יש לנו את stdlib.h. משתמשים בו בעיקר בשביל ה-EXIT_SUCCESS, אבל בואו נמחק את זה שנייה, ונעשה את זה בצורה שלנו.

אז נעשה ככה, ואז int, כי הפונקציה הראשית של ה-main מחזירה int. int main, כאן נעשה printf, סוגריים, זה... Hello STM32 Bare Metal Programming Course. וחייבים לעשות n\. למה חייבים לעשות n\? כי אם לא עושים n\ לא נעשה flushing למידע, ובעצם זה נשאר לפי ה-stream policy. דיברנו על זה בשיעור של ה-Embedded Linux, סורי, רלוונטי פה.

Exit, אנחנו... או אנחנו לא משתמשים ב-Exit, אנחנו עושים return 0. שזה אומר שיצאנו, שהצלחנו בלי זה. Ctrl+S ל-save. Build. בעצם Build יבנה לנו רק את זה, ואנחנו מריצים. וכמובן שצריך להגדיר את זה. יש קצת בעייתיות...

והעבודה עם ה-IDE הזה... אבל בגדול אנחנו מוגבלים ואנחנו לא יכולים להשתמש בו. אז עוד שנייה אנחנו נטפל בהכול.

אז ככה, אנחנו רוצים לסדר את הקומפיילר, את ה-executable שירוץ. אז יש לנו executable שנוצר, ואם אנחנו ממש נלך לתוך source – בואו אני אראה לכם אותו – אם אנחנו נלך לתוך source, Bare Metal, Lesson 0, וניכנס לתוך STM32 Course... אני חושב שפה נכנסים לזה... לא, בתוך Debug, אז יש לנו פה את ה-executable.

אם נרצה להריץ אותו ולבדוק, אנחנו יכולים לעשות CMD. CMD, ואנחנו מריצים את `hello_world`, אז יש לנו פה `Hello STM32 Bare Metal Programming Course`. זה אנחנו.

אם אנחנו רוצים להריץ את זה מתוך ה-IDE עצמו, אז אנחנו צריכים לעשות כזה דבר: מקש ימני על הפרויקט עצמו, Properties, C/C++ Build, Tool Chain Editor, ואנחנו צריכים להגדיר לו שוב את ה-toolchain שאנחנו עובדים. מסתבר שזה קורה, היום נתקלתי בזה כמה פעמים. MinGW GCC, נעשה Apply, ונעשה Clean Project, Build Project, Run As Local C/C++ Application, והנה הצלחנו. אז יש לנו גם פה: `Hello STM32 Bare Metal Programming Course`. בסדר גמור.

## Basic Data Types

אוקיי, אז זה היה החלק הראשון של הקורס. עכשיו אנחנו נעשה קצת alignment של הרמה של C. יש לנו שני חלקים: חלק אחד נעשה היום, חלק שני נעשה בשיעור הבא. אני אנסה לרוץ על זה ונעשה את זה מהר.

אז Basic Data Types. אנחנו משתמשים בכמה סוגים של data types ב-C. אלה הסוגים הסטנדרטיים שבעצם אנחנו משתמשים בהם ומרחיבים אותם כשאנחנו עובדים על סביבה. הסוגים האלה והגדלים שלהם משתנים לפי ה-alignment של ה-CPU.

אם ה-CPU שלי הוא 64-bit כמו המכונות Windows שאנחנו עובדים, ה-x86, אז `int` יהיה 8 בתים, גם `long` יהיה 8 בתים, וגם `long long`. אם אנחנו עובדים על 32-bit, אז ה-native, הצורה הבסיסית שאנחנו עובדים, תהיה שונה – היא תהיה 32-bit. אז `int` הוא 32-bit, בסדר?

אז בואו נתחיל:

`char` – `char` הוא תמיד בית אחד. זה בעצם איזשהו character שהוא מ-128- עד 127 אם אנחנו עובדים איתו עם סימן (`signed`), ואם אנחנו עובדים איתו בלי סימן (`unsigned`), אז מ-0 עד 255. לכן כשאמרתי שאם אנחנו עם native MCU שה-alignment שלו הוא 8-bit, אז אנחנו יכולים לגשת ל-256 כתובות, כי זה הגודל של בית אחד שאנחנו משתמשים.

אחר כך יש לנו `short`. `short` בעצם מגדיל לנו את ה-range, אנחנו יכולים לעבוד על שני בתים, $2^{16}$. אז מ-0 עד $2^{16}$ אם אנחנו `unsigned`, ואם אנחנו `signed`, עם סימן, אז מ-32,768- עד אותו מספר פחות 1 בפלוס.

אחר כך אנחנו עובדים עם `int` ו-`long`, שזה בעצם בצורה שלנו ארבעה בתים. למה? כי אנחנו לא מחברים בתים ל-יותר ממה שעושה ה-MCU שלנו, זה ה-instruction set שאנחנו משתמשים בו.

אחר כך יש לנו `float`. `float` משתמש בתצורה של floating point, אני לא זוכר את התקן. זה לא באמת רלוונטי כי לרוב לא משתמשים ב-floating point לדברים אלה כי זה תופס המון מקום. אז בעצם הרבה פעמים משתמשים ב-`int` או `unsigned int` (ללא סימן) ועושים לו חלוקה או מקצים לו כמה ספרות לנקודה העשרונית.

אותו דבר גם `double`, זה פי שניים יותר בתים. פחות משתמשים בו, וזה גם תלוי ב-MCU שלכם. אם יש לו Floating Point Processing Unit, מה שנקרא FPU, אז יכול להיות שתוכלו להשתמש ב-`double`. אם אין לו FPU, אז יכול להיות שלא תשתמשו ב-`double`, אבל בכל מקרה באמת שפחות משתמשים.

למה זה משנה? Memory footprint. בעצם אין לי הרבה זיכרון לעבוד איתו, אין לי הרבה non-volatile memory, אין לי הרבה RAM שאני יכול לעבוד, אז בעצם כל אופרטור או כל משתנה אני בוחר בקפדנות. כל באפר שאני מעתיק אליו, כל מערך, אני באמת בוחר בקפדנות, והרבה פעמים אני בעצם מגיע למצב של קומפילציות של משתנים רק כדי שאני אוכל לתמוך בכמה באפרים ובכמה מוצרים שונים. אני לא נמצא בעולם ה-CPUs שאני מפזר זיכרון לכל מקום, אני בעצם מאוד קטן בזיכרון והרבה פעמים אני מקצה את כל הזיכרון שלי מראש. אנחנו נדבר על זה בשיטות לניהול זיכרון.

למה זה עוד משנה? Range ו-precision. אם אני בעצם משתמש במספר שהוא קטן מדי, אז אני לא יכול לייצג איתו את ה-data. זה בעצם איזשהו משחק כזה שמשחקים, ואם אני משתמש ב-counter של 255, אז בעצם יהיה לי overflow ואני אהיה בבעיה.

בואו נראה איזושהי דוגמה לפני שאנחנו עוברים לדבר הבא. אז זו הדוגמה שלנו. נגיע פה ל-source, `01_basic_data_types`.

אז אלה ה-types הבסיסיים שאנחנו משתמשים. יש לנו counter של 100, אם אנחנו נעשה לו פה `counter++` ונעתיק את זה לכאן, אנחנו נראה שהוא גדל.

אחר כך יש לנו floating point. floating point מגדירים עם `f` בסוף, אחרת זה עושה casting ממספר גדול יותר שהוא `double`. יש לנו `double` שהוא double precision, ויש לנו `char`.

אם אני מדפיס כל אחד מהם, אני צריך להשתמש ב-format specifier שלו. אז `%d` זה ל-`int` שהוא `signed`, `%u` זה ל-`unsigned`. בואו נעשה שנייה פה, ניצור פה איזשהו `unsigned char` שמונה בתים, `unsigned`, וניתן לו את המספר 255, ונקרא לו `u8`.

אם אנחנו נרצה להדפיס אותו, אז בואו נעשה פה הדפסה של `u8`, ונראה מה זה נותן לנו ב-overflow. נעשה פה `++`. ובואו נעשה להדפיס גם את ה-`u8` הזה עם `%d`, נראה את ההבדל ב-format specifier. אז יש לנו פה עוד `u8`.

נבנה... הוא כבר מתריע לי שיכול להיות שאני אעבור את הגודל של `u8` ובעצם אני אעשה overflow. זה רק warning, אז אני חושב שאני יכול להמשיך. בואו נריץ.

בסדר. אז אם אנחנו מריצים את זה עם `%u`, אנחנו מדפיסים 0. ב-`%d` זה 255, משהו פה קצת לא נכון. ופה יש לנו כבר overflow, אז בואו נבחר מספר יותר יפה, 164. נעשה build, נעשה את הריצה.

אוקיי, אז יכול להיות שהוא באמת הופך לי את זה פה, ו-`%u` הוא קטן, `%u` בעצם מגדיר לי `unsigned int`, הוא לא מגדיר לי `unsigned char`. בשביל `unsigned char` אני לא זוכר את הפורמט, אבל בגדול יש פורמט ל-`unsigned char`, אנחנו נסתכל עליו עוד רגע כשנדבר על fixed-width integer limits.

## Fixed Width Integers & Limits

`stdint.h` נותן לי פונקציונליות מאוד חשובה כשאנחנו עובדים עם מיקרו-קונטרולרים או שאני עובד ברמת ה-low level. הוא נותן לי בעצם איזושהי עטיפה של כל ה-`int`, `unsigned int` וכל החבר'ה שיש כאן בעצם לאיזשהו גודל קבוע. זאת אומרת, אם אני בוחר ב-`int8_t`, זה תמיד יהיה signed 8-bit בכל מערכת. זה לא משנה אם האופרטור שלי הוא מגודל 8, 16, ווטאבר.

בואו נסתכל בעצם איך זה נראה, ואני אראה לכם גם איך אנחנו יכולים לראות את הגדלים שלהם ככה מהר. אז זה ה-source שאני הולך להשתמש בו (`02_fixed_width_integers_limits`).

יש לי `int8_t`, הוא מקבל אותו מ-`stdint.h`. ואם תסתכלו, הוא משתמש ב-`typedef`. `typedef` נותן שם חדש למשתנה. אז אם אני משתמש ב-`signed char`, זה 8-bit. אם אני משתמש ב-`unsigned char`, אז אני בעצם קורא לו `uint8_t` ואני יכול להשתמש ב-`uint8_t`. זה מה שעושה `stdint.h`, אתם רואים עכשיו אנחנו בתוך הספריה של `stdint.h`.

ויש עוד ספריה שנקראת `limits.h`, שזה בעצם ה-header file הזה, שהוא בעצם מגדיר לי ונותן לי את כל הגדלים שאני יכול להשתמש בהם. אז אם אני עושה את המקסימום של `int8_t`, אז זה 127. הרבה פעמים משתמשים בו כדי ליצור sentinels, בעצם ערכים מאוד גדולים או ערכים מאוד קטנים, שברגע שאני מתחיל לעבוד אז אני דורס אותם.

אלה התצורות שאנחנו עובדים: `int8_t`, `uint8_t`, `int16_t`, `uint16_t`. להם אנחנו מצרפים את ה-limits ואת ה-macros שמקבלים מתוך הספריה הזאתי שנותנת לי את כל הגדלים. היופי של זה הוא שבעצם בכל CPU שאני משתמש, אז יהיה לי את כל אחד מאלה. אז זה יהיה 4 בתים בכל CPU, `int32_t` או `uint32_t` יהיה 4 בתים, 16 גם כן יהיה 2 בתים, ו-8 יהיה בית אחד בכל CPU, וככה תמיד יש לי התנהגות שהיא צפויה ואני יכול להשתמש בה. לא משנה אם אני עובר בין ארכיטקטורות ובין כל מיני דברים.

בואו רק נריץ את הקוד לשם הסדר הטוב. נריץ אותו כ-Local Application. אם זה לא מקומפל אז בונים אותו, ואז בעצם אנחנו רואים ש-`int8_t` המקסימום שלו הוא 127, שזה בעצם המאקרו שהגדרנו כאן. 16 – אז זה 65,535, שזה $2^{16}$. המינימום של `int32_t` – אז זה המספר. אם אנחנו נכנסים לתוך ה-header עצמו (אני לוחץ על Ctrl ונכנס להגדרה שלו) זו ההגדרה שלו, אותו דבר עם 64-bit שזה 8 בתים. בשביל להדפיס את זה אני צריך להוסיף `%llu` שזה long long unsigned.

## Operators & Expressions

אופרטורים. אנחנו משתמשים באופרטורים האלה ב-C. יש לנו אופרטורים אריתמטיים: פלוס, מינוס, כפל, חילוק ומודולו.

שימו לב שאם אנחנו מגדירים משתנה מסוג int ואנחנו עושים חלוקה, אז התוצאה שלנו תהיה int ובעצם יהיה לנו טרנקציה של התוצאה. בעצם אנחנו מעיפים את... אנחנו מעיפים את הנקודה העשרונית וזה מה שיוצא לנו. אוקיי.

אחר כך יש לנו bitwise operators, אז יש לנו AND, OR, XOR, סליחה, AND, OR, XOR זה הצורה שלהם. NOT, left shift ו-right shift שזה בעצם חזקה של שתיים ושורש. תמיד שכחתי את הסדר, אז אנחנו נעשה פה בדיקה עוד רגע ונסתכל.

ואחר כך יש לנו אופרטורים לוגיים, ש-AND, OR ו-NOT שאנחנו משתמשים בהם, ויש לנו precedence, זה בעצם הצורה שבה ה... C עושה את ה-evaluation. אז ה-precedence הוא ככה: קודם כל כפל יותר חזק מחיבור, אחר כך יש לנו bitwise operators שזה בעצם בגדול חזקה, ויש לנו parentheses. לגבי פלוס פלוס ומינוס מינוס אז אני חושב שהם אחרונים ויש גם השמה. תמיד אפשר להשתמש בסוגריים כדי להיות ברורים וכדי זה. זה לא באמת חייב, אבל הרבה פעמים זה עוזר לקריאות.

אז בואו נעבור על הקוד שיש לנו כאן, אני גם אגדיל אותו. יש אפשרות להגדיל אותו? כן. סבבה. אז יש לנו פה משתנה מסוג uint8_t ואני יכול להגדיר אותו בצורה הבינארית שלו עם 0b. אם אני משתמש רק ב-0 זה בצורה האוקטלית שלו, אוקיי? אוקטלית זה בבסיס 8. ואם אני משתמש ב-0x זה בצורה ההקסדצימלית, בבסיס 16.

אז אם אני משתמש בזה, אז בעצם זה 170 בצורה דצימלית, וה-b הוא 204 בצורה דצימלית. אם אני מחבר ביניהם בתוך int, למה אני חייב לחבר ביניהם בתוך int? כי יהיה לי overflow אם אני אחבר אותם בתוך uint8_t. אם אני מחבר בתוך int אז יהיה לי 170 ועוד 204, 374. ואם אני מחסר ביניהם אז יהיה לי את ההפרש.

עכשיו, אם אני אעשה ביניהם את ה-AND, אז בעצם בכל מקום שיש 1 בשניהם, אז יהיה 1 בסוף. אז יש לנו כאן במקום האחרון, ב-MSB, ב-Most Significant Bit, ויש לנו ב... ב-4. אוקיי, סליחה, 1, 2, 4 ו-8, ו-8. אז ביחד יצא לנו 8 ו-128, אז אנחנו חייבים לעשות את החיבור, או שעשינו 136.

אותו דבר עם OR. אז OR, אז כל מקום שיש או 0 או 1 או שניהם, אז יהיה לי 1 בסוף. אז זה מה שיוצא כאן.

XOR, XOR זה exclusive OR. זה אומר שרק במקום שיש או זה או זה, אם יש את שניהם אז לא. אז אם אנחנו רואים, אז ה-bit הראשון יהיה 0, ה-bit השני יהיה 1, ה-bit השלישי יהיה 1, ה-bit הרביעי יהיה 0 כי זה exclusive OR, וכן הלאה.

אחר כך יש לנו את NOT, שכל מקום שיש 0 אז הוא הופך ל-1 וכל מקום שיש 1 ל-0.

left shift בעצם עושה לי חזקה של שתיים, אז בעצם את כולם הוא מזיז אחד שמאלה. במקרה הזה הוא עושה לנו בעצם overflow, אז ה-1 הראשון הוא פשוט נתעלם ממנו וכל השאר זזים אחד שמאלה. אז מתוסף לנו פה 0 בהתחלה, ואז יש לנו את ה-0 המקורי וכל השאר זזים שמאלה, וכאן, למרות שזה לא מחושב, אז יש את ה-1. והמספר יצא 84.

shift right עושה לנו שורש, בעצם מעביר את כולם ימינה. אז המספר הזה אנחנו מתעלמים ממנו, בעצם מעבירים 0 לכאן וכולם זזים ימינה.

אז בואו עכשיו נריץ ונסתכל על החיבור, ואחרי זה נדבר על logical operations. טוב, build, ואז יש לנו run. אנחנו מדברים על ה-operator expressions, אז יש לנו run. רוצים שיריץ את זה כ-STM application. אוקיי, הוא פלט פה למטה.

אז אוקיי, אז החיבור היה 374, החיסור הוא זה. זה יותר מה שמעניין אותנו, והוא מדפיס לנו את זה בהקסה, אוקיי? אז הקסה זה כל ארבעת הביטים זה ספרה אחת, אוקיי? בהקסה. אז אם אנחנו ניקח את ה-4 הראשונים של ה-OR, אז זה 0 0 0 1, אז יש לנו 1, 2, 4, 8, אז יש לנו 8. אותו דבר גם השני, יש לנו עוד 8, אז זה 88, בסדר? 0x88. אחר כך יש לנו EE, אז זה 1 1 1 0, אז יש לנו 8 ועוד 4 ועוד 2, זה 14, ו-14 זה E בהקסה. אם אתם מסתבכים יש לנו מחשבון בתוך ה-Windows.

- אם היית מדפיס את כולם כ-int, היית מקבל את הדצימלי?

- כן, עם %d היית מקבל את הדצימלי, ופה %x.

- הבנתי.

אין לנו אפשרות להדפיס בבסיס בינארי בתוך printf. לא הכניסו את זה בספריה, הם חשבו שאנשים מספיק חכמים ומעדיפים להשתמש בהקסה. זה מה שזה. אוקיי, אותו דבר, אנחנו מדברים על השיפטים וכל אלה. תריצו את הדוגמאות בבית, תעשו אותם ותבינו.

## Logical Operators and Precedence

אוקיי, עכשיו אנחנו רוצים לעשות את ה-logical operators, אז יש לנו AND. אז אם a לא שווה ל-0 וגם b גדול מ-200, אז שני התנאים האלה נבדקים ביחד, ואנחנו בעצם מדפיסים condition met, וזה בעצם מה שאנחנו עושים.

נעבור ל-operator precedence, בעצם על הקדימויות. אוקיי, יש לזה דוגמה נוספת. קדימויות של מה קורה קודם. אני חושב שאני כבר אזיז את זה ואנחנו נגדיל את המסך כאן.

אז יש לנו כאן שלושה משתנים, אוקיי? והתוצאה שלנו תהיה לפי הסדר פעולות חשבון שאנחנו מכירים, אז קודם כל y * z, אז יצא לנו 12, ועוד 2, בעצם יצא לנו 14. ואם אנחנו משתמשים בסוגריים, אותו דבר.

מה קורה כאשר אנחנו משתמשים בחזקה? אז קודם כל אנחנו נעשה את החזקה, אז y בחזקה פעמיים, אז פעמיים חזקה של 2, אוקיי? אנחנו מזיזים את כל הביטים של y שמאלה פעמיים, בעצם אנחנו מעלים אותה בחזקה של 4. אז קודם כל את החזקה נעשה, אחר כך אנחנו חוזרים ואנחנו עושים את x ועוד ה-evaluation שיש לנו כאן, פחות z, זה לפי הסדר. וזהו, אם אנחנו רוצים לעשות את זה יותר explicit, אנחנו עושים ככה.

בואו נעשה דוגמה. אז זה בעצם מה שאמרנו, 14, פה יש לנו 20 כי זה קורה קודם. אחר כך יש לנו את זה, שזה ה-evaluation הזאתי שקורית כאן, unary left קודם ואז... אוקיי, זה פשוט ה-minus sign, זה לא... הבנתי.

## Storage Class Specifiers

אוקיי, בואו נעבור ל-storage classes, שזה יותר מעניין, זה כבר עבודה עם כמה קבצים במקביל.

יש לנו כמה סוגים של storage classes. אז ככה, בואו נפתח את הדוגמה ב-C. יש לנו פה שני קבצים, בואו נסגור את כל השאר, נראה אותם. יש לנו פה שני קבצים, אוקיי? רואים אותם? כן, מעולה. אני אגדיל את זה ככה שיהיה לנו.

אז יש לנו שני קבצים, יש לנו קובץ הראשי שממנו יש את ה-main, ויש לנו פה איזשהו קובץ שהוא לא מוגדר כ-header file, הוא בעצם מוגדר עם הספריות והכול. מה אנחנו רוצים להשתמש? אז יש לנו את ה-storage class שנקרא static, שבעצם הוא אומר שהמשתנה שיוגדר כ-static הוא יכול לחיות רק בתוך הקובץ הזה. אני לא יכול לגשת אליו מ-file_2, כי הוא נמצא בתוך זה. בסדר? אז זה static.

יש לנו את ה-storage class שנקרא extern, שהוא נותן לגשת לפונקציות בלי ה-header file שלהם, אלא לגשת לפונקציות שנמצאות בקובץ אחר. אז incrementCounter בעצם מוגדרת כאן, ואני יכול לגשת אליה באמצעות extern. בלי זה זה שגיאת קומפילציה, אוקיי?

אותו דבר יש לי את callDebug, בעצם אני יכול לקרוא ל-callDebug, אבל callDebug יכול לקרוא ל-debugMessage, ו-debugMessage מוגדרת כפונקציה סטטית. אם היא פונקציה סטטית, אז אפשר לקרוא לה רק מתוך הקובץ הזה. אז בעצם אנחנו צריכים לעשות איזשהו wrapper, איזושהי פונקציית מעטפת שתוכל לקרוא.

ובתוך הפונקציה הסטטית הזאתי אני מגדיר איזשהו משתנה שהוא סטטי. מה זה המשתנה הזה שהוא סטטי? בעצם זה אומר שהוא לא מתאפס כל פעם שקוראים לפונקציה, הוא בפעם הראשונה מוגדר כאיזשהו ערך התחלתי ששמים לו, אני שמתי לו 0, ואחר כך כל פעם שמשנים אותו, הערך שלו נשמר גם ביציאה של הפונקציה. בגדול הוא מתנהג כמו גלובלי, אבל עם גישה רק מתוך הפונקציה עצמה. בעצם הוא נשמר במקום בזיכרון שנשמרים כל המשתנים הגלובליים, וה-GCC, הקומפיילר נותן גישה אליו רק מתוך הפונקציה עצמה.

אז מה יש לנו כאן? בעצם יש לנו פה שתי קריאות ל-incrementCounter, כדי שנוכל לראות את האינקרמנטציה, ויש לנו גם את ה-staticCounter. בעצם staticCounter הוא מתקדם רק כאשר קוראים ל-incrementCounter. אוקיי? incrementCounter ישר קורא ומגדיל לנו את ה-staticCounter.

וכאשר אני קורא ל-callDebug, שמוגדר לי כאן, אז callDebug קורא ל-debugMessage שהיא פונקציה סטטית, והיא גם מגדילה לנו משתנה סטטי שסופר, ומדפיסה לנו את הערכים שיש לנו בתוך הקובץ הזה.

אוקיי, בואו נעשה לזה build. כשאנחנו עושים build, שימו לב שהוא בעצם יוצר לי את האובייקטים. אז זה קובץ שהוא לא קובץ הרצה, אין לו main, אז בעצם הוא צריך להכיר את זה כשהוא מקמפל, אז הוא בעצם יוצר לי את זה עם פלאג של `-c`, זה אומר שזה לא קובץ שיש לו main. והוא גם יוצר את השני באותה צורה, גם את file_2 למרות שיש לו main, ובסופו של דבר הוא מחבר אותם ביחד, ואז הוא יודע לראות שזה מה שקורה.

בואו נריץ ונסתכל מה קורה. אז run as, local...

אז אוקיי, אז יש לנו את ה-staticCounter. staticCounter בתוך file_1 הוא 1, פעם השנייה שקראנו לו הוא 2, כי עשינו לו אינקרמנטציה, בעצם הגדלנו אותו. אחר כך יש לנו קריאה משולשת ל-debugMessage. אז debugMessage, אתם רואים שהוא לא מגדיל את ה-staticCounter, אבל הוא רק ניגש אליו, אז הוא מדפיס זה ה-staticCounter. מעולה.

אחר כך, כל פעם שאנחנו קוראים, לזה יש לו איזשהו קאונטר שהוא סטטי, שזה היה מבלבל לקרוא לראשון staticCounter, אבל זה ה-functionCounter. אז ה-functionCounter עצמו, כל פעם שקוראים אז הוא גדל, ואתם רואים שלמרות שאיפסתי אותו בפעם הראשונה, הערך שלו גדל: היה 0, אחר כך הפכתי אותו ל-1, 2 ו-3. אוקיי?

## Decision Making in C

אנחנו מאוד קרובים לסיום, אז בואו נרוץ ככה מהר על decision making. יש לנו if, מי שמכיר.

אז יש לנו decision making, אז יש לנו פה if. אנחנו בעצם מגדירים command, ואז אנחנו יכולים לעשות בצורה של if ו-else. אז אם אחד מהתנאים הוא מתבצע, אז אנחנו נכנסים לבפנים. אם לא, אנחנו לא נכנסים לבפנים, אנחנו מגיעים אל ה-else. אז אם אנחנו נגדיר את זה להיות 0, אנחנו ניכנס לכאן, 1 לכאן, ו-2 לכאן, וכל מה שהוא לא אלו, אז נגיע ל-else, אוקיי?

אותו דבר, יש לנו גם את ה-switch. לא בדיוק אותו דבר. ה-switch עובד עם כמה סוגים. אז אותו דבר, 0, 1 ו-2, ויש לנו את ה-default, שזה ה-else שלנו. היתרון ב-switch לעומת if, ל-switch יש לו כבר פקודות jump שהן שמורות בזיכרון התוכנית, עוד מעט נדבר עליו, וכאשר אני קופץ לשם...

...אני קופץ ב-offset של אפס ואני לא צריך לחפש. אז ה-switch הוא הרבה יותר מהיר מבעצם לעשות nested ifs.

אוקיי? אז תמיד אם יש אפשרות, להשתמש ב-switches. לא הכי נוח ולא הכי קל, פחות... זה גם לא הכי קריא, אבל נוח.

## Scopes and Prototypes

דוגמה אחרונה זה function scope ו-prototypes, אני ארוץ גם על זה.

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

אחר כך יש לנו function prototype, שזה בעצם ההגדרה. ואם אני מגדיר את הפונקציה, אני יכול לגשת אליה מכל מקום. אחרת, הפונקציות יכולות לגשת רק לפונקציות שמוגדרות מעליהן.

אז אם הייתי פה עושה מעל ל-multiply את multiply_by_two, אז הייתי יכול לגשת אליו. אם אין לי prototype, הייתי יכול לגשת אליו רק אם הוא מוגדר מעליי. בסדר?

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

אז יש לנו פה את ה-localVal, אז הוא חי רק בתוך ה-main. הוא לא חי בחוץ. אבל לעומת זאת הגלובלי מוגדר בחוץ, ואני כן יכול לשנות אותו גם מבפנים.

אז globalVal, יכולים לשנות אותו מכל מקום. ואם אני מגדיר איזשהו משתנה מכאן, אז הוא גם חי כאן.

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

טוב, זה היה השיעור שלנו. סיימנו יחסית בזמן. בהמשך תעשו git pull ל-branch ותקבלו אותם.

- אפשר לשלוח את המצגת?

- בגדול אני לא שולח מצגות. שלחתי בהתחלה ואז ראיתי שזה מתגלגל בכל מיני ידיים. אבל יש לך את ההקלטות, אוקיי?

אני חושב שאפשר לעצור את ההקלטה ואפשר גם קצת לדבר.