לוח פיתוח ייעודי כבר יש. איך כותבים קוד שרץ על ה-ATmega4809 החדש (מבלי לחכות לתמיכה של ארדואינו)?
מה צריך
כדי לגשת לכתיבת קוד ל-4809, נזדקק ראשית כל לשלושה מסמכים. הראשון הוא ה-Manual של משפחת megaAVR 0-Series. זהו מדריך מפורט שמסביר את הארכיטקטורה עצמה: מודולים, רגיסטרים, שעונים, הגדרות וכו'. המסמך השני, לצערנו, הוא ה-Errata של אותה משפחה: רצוי מאוד לחפש בו כל מודול ואלמנט שאנחנו מתכוונים להשתמש בו, כדי להימנע מהפתעות לא נעימות בהמשך. המסמך השלישי הוא ה-Datasheet של הג'וק עצמו, שמכיל את המידע הרלוונטי לחומרה הפיזית הספציפית של הדגם: מיפוי הפינים, פרמטרים חשמליים, מידות וכדומה. [עריכה: עם הזמן, המסמכים אוחדו – כעת צריך רק Datasheet ו-Errata, הקישורים למעלה תוקנו בהתאם]
נזדקק כמובן גם לסביבת פיתוח. נכון ש-Atmel Studio היא עדיין הגרסה הבשלה והרשמית לרכיבי AVR, אבל ממש לאחרונה יצאה גרסה 5 של MPLAB X עם תמיכת בטא בצורב Atmel-ICE ובלא מעט ג'וקים של Atmel, אז בשביל הקטע נשתמש בה וניצור פרויקט חדש ל-ATmega4809. לא ניכנס לפרטים הטכניים של זה כאן.
הרגיסטרים
השלב הראשון – אצלי, לפחות – בכתיבת קוד למיקרו-בקר הוא הגדרה של שעון המערכת לתדר הרצוי. במקרה הספציפי הזה, כיוון שאנחנו רוצים בסך הכול לד מהבהב, אפשר להסתפק בהגדרות ברירת המחדל שאיתן המיקרו-בקר יצא מהמפעל. לפעמים צריך להוסיף קוד כדי לעצור את ה-Watchdog או "לשחרר" את פיני ה-GPIO (למשל בכמה מיקרו-בקרים של TI), כאן, לשמחתנו, לא. אז בעצם אפשר לגשת ישירות למודול ששולט בפיני ה-IO ולראות איך מגדירים פין כפין פלט ואיך משנים את הפלט שלו. תזכורת מהפוסט הקודם: הלד בלוח שלי מחובר לפין PC6 – הפין השביעי מתוך שמונה (הספירה מתחילה ב-0) של פורט C.
ב-ATmega וב-ATtiny החדשים, כל המודולים מסודרים מאוד מבחינת התיעוד, ואחרי שמבינים את הפרנציפ קל למצוא את התכונות והאפשרויות השונות. סעיף 15 ב-Manual עוסק בקונפיגורציה של פיני הקלט/פלט ("PORT"), ושם אנחנו יכולים לקרוא ולהבין שהרגיסטר PORTC.DIRSET הוא הדרך הכי בטוחה ונוחה להשיג את המטרה: פשוט מציבים בו ערך מספרי, שהביטים שהם "1" בו מייצגים את הפינים שאנחנו רוצים להפוך לפלט. במקרה שלנו זהו הביט השישי, כלומר בייצוג בינארי המספר צריך להיות 01000000, או בייצוג הקסדצימלי 0x40. השורה הראשונה בפונקציה main תהיה לפיכך:
PORTC_DIRSET = 0x40;
אפרופו, ב-Manual הרגיסטר מוצג כ-PORTC.DIRSET, עם נקודה באמצע, אבל סביבות הפיתוח מכירות את הגרסה לעיל עם הקו התחתון, שמוגדרת בקובץ avr/io.h. נו מילא, לא נהיה קטנוניים.
הלולאה הראשית שלנו תכלול איזושהי השהייה, אותה אפשר לממש בשלב ראשון באמצעות לולאת ספירה פשוטה. את מספר החזרות הדרוש ללולאה הזו כדי להבהב, נניח, פעם בשנייה, אפשר לגלות בניסוי וטעייה. בשביל הכיבוי וההדלקה של הלד נחזור ל-Manual ונגלה את הרגיסטר השימושי PORTC.OUTTGL, שפועל בדיוק באותה שיטה כמו DIRSET, רק שבמקום להגדיר פין כפין פלט, הוא מחליף (Toggle) את מצב הפלט. מכאן שהפקודה לעבור בין המצבים LOW ו-HIGH ב-PC6 שהגדרנו כפין פלט דיגיטלי היא:
PORTC_OUTTGL = 0x40;
והתוכנה המלאה שמהבהבת בלד בלוח שלי נראית כך:
#include <avr/io.h> int main(void) { PORTC_DIRSET = 0x40; while (1) { for (uint32_t x = 40000; x; --x) { } PORTC_OUTTGL = 0x40; } }
שעונים ונעילות
בלי קשר לתוכנת הבלינק דווקא, כברירת מחדל, שעון המערכת מופעל על בסיס מתנד הפנימי בתדר 20MHz, עם חלוקה ב-6 (כלומר 3.333MHz). אפשר לשנות את התדר של המתנד הזה ל-16MHz או להסתמך על מקורות תדר אחרים, ואפשר לשנות את החלוקה למספר ערכים שונים בין 0 ל-48 – אם כי צריך לזכור שתדרים גבוהים לא נתמכים במתחי הפעלה נמוכים.
כדי לשנות את מקור התדר או את החלוקה, שנחשבים פרמטרים רגישים שמסוכן להתעסק איתם, צריך "לבטל נעילה". הדבר מתבצע באמצעות כתיבת הערך 0xD8 לרגיסטר CPU_CCP. מאותו רגע, למשך ארבעה מחזורי שעון בלבד, אפשר לשנות למשל את הרגיסטר CLKCTRL_MCLKCTRLB שמגדיר את החלוקה. ב-Manual, בתיאור המפורט של כל רגיסטר, מצוין אם הוא מוגן בנעילה כזו.
שימו לב שאם אתם מנסים לשנות רגיסטר מוגן אבל שורת הקוד שעושה את זה כוללת איזשהו חישוב, יש סיכוי טוב מאוד שהחישוב עצמו ייקח יותר מארבעה מחזורי שעון, הנעילה תחזור והשינוי לא יתבצע. חייבים לחשב את הערך הסופי הרצוי לתוך משתנה נפרד לפני ביטול הנעילה, לבטל אותה, ורק אז להעתיק את הערך לרגיסטר.
ממשק צריבה ו-RESET
בניגוד למיקרו-בקרים הישנים והמוכרים ממשפחת AVR, בחדשים הצריבה מתבצעת דרך ממשק שנקרא UPDI (ראשי תיבות של Unified Program and Debug Interface), ושזקוק – מעבר לאדמה המשותפת, כמובן – לפין אחד ויחיד בלבד.
לממשק הזה יש כמה יתרונות בולטים. בין השאר הוא לא מפריע (לפחות ב-4809) לפיני קלט/פלט רגילים, והוא לא תלוי בשעון המערכת – עובדה שיכולה לחסוך המון כאבי ראש. למעשה הוא כל כך עצמאי שהוא אפילו לא תלוי בפין RESET, אשר מוגדר כברירת מחדל כפין קלט/פלט רגיל לכל דבר. במילים אחרות, אם לא תשנו את ה-Fuse המתאים דרך סביבת הפיתוח, "משיכה" של פין RESET לאדמה לא תאתחל את המיקרו-בקר, ובמצבים מסוימים עלולה אפילו להזיק לו.
מחשבות על ה-4809
המיקרו-בקר החדש מרשים ומסקרן מכמה בחינות. יש לו ארבעה מודולי UART בחומרה, שישה טיימרים (משלושה סוגים שונים) ועוד המון תוספות מודרניות ושימושיות, אם כי חלקן חולקות פינים ואי אפשר להפעיל את כולן בבת אחת. יש לו 6KB זיכרון SRAM – כמות יוצאת-דופן בקטגוריה, פי שלושה מה-ATmega328P שבארדואינו Uno – וגם יותר Flash, אם כי דווקא פחות EEPROM. לרוע המזל, אין לו ממיר דיגיטלי-לאנלוגי (DAC) שכמעט הפך לסטנדרט במיקרו-בקרים מודרניים, וקיים אפילו ב-ATtiny 1-Series החדשים.
המשמעות היא שבגדול, מנעד היישומים הפוטנציאליים של ה-4809 רחב יותר מזה של ה-328P, וגם משל ה-328PB הפחות-מוכר. במובן מסוים הוא ממלא פער שהיה קיים עד היום בין ה-328P לבין הדגמים היקרים וה"מגושמים", כגון ה-ATmega2560, ומוסיף עוד כמה טריקים נחמדים על הדרך. השאלה המעניינת ביותר, לטעמי, היא האם מישהו עובד כעת מאחורי הקלעים על סדרת ATmega 1-Series. אם לסמוך על דוגמת ה-ATtiny, בסדרה כזו יהיה יותר זיכרון, יהיה DAC, ואולי יהיו עוד כמה תוספות מעניינות, שיקפיצו את AVR סופית אל תוך העשור השלישי של המאה.
Hello, sorry to bother you. but I am using the atmega 4809 in a project and I am struggling a bit with trying to get the ADC to work. you don´t by any chance happen to have any code for the ADC that you would be willing to share
I'm afraid I didn't have the chance yet to try the ADC… but this may be a good opportunity to do so. If you don't want to wait for a post, write to me at info@idogendel.com, maybe we can work out the problem.