מתנד בשליטה נומרית (NCO) – הסבר, ביקורת והדגמה

במיקרו-בקרים מודרניים של Microchip, מצטרף אל הטיימרים הקלאסיים – בין מודולי החומרה הוותיקים ביותר במיקרו-בקרים בכלל – מודול תזמון בשם "מתנד בשליטה נומרית" (NCO – Numerically Controlled Oscillator). מה עושה ה-NCO, איך משתמשים בו ומה היתרונות והחסרונות שלו לעומת טיימר רגיל?

לוח פיתוח Curiosity Nano למיקרו-בקר PIC18F57Q43
לוח פיתוח Curiosity Nano למיקרו-בקר PIC18F57Q43

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

ההסבר

טיימרים "רגילים" מודרניים יכולים להיות משוכללים מאוד, אך ברמה העקרונית הם מבוססים על מנגנון די פשוט: רגיסטר פנימי סופר פעימות של משהו (למשל של שעון המערכת), ואנחנו קובעים לו סף עליון (1 עד 255 לטיימר 8-ביט) שכאשר הוא מגיע אליו הוא מתאפס וגם עושה איזו פעולה (למשל להפוך את המתח בפין פלט דיגיטלי). אם המחזור הזה מהיר מדי לטעמנו, אפשר להיעזר ב-prescaler – רגיסטר מתווך שסופר את הפעימות המקוריות, ומקדם את הרגיסטר של הטיימר עצמו באחד רק כשהמספר המצטבר מגיע לחזקה כלשהי של 2 (מתוך מבחר מוגבל של חזקות).

גם ב-NCO יש רגיסטר מונה שעושה פעולה כשהוא מגיע לסף, אך בניגוד לטיימר, אנחנו קובעים בכמה הוא יגדל עם כל פעימה. אי אפשר לשנות את ערך המונה "מבחוץ" בזמן שהמודול פעיל, והסף העליון קבוע, אבל – וזה אבל גדול – אם במקרה הערך של המונה עבר את הסף הזה (למשל, אם אנחנו מוסיפים 21 בכל פעימה והסף העליון הוא 100), המונה לא מתאפס לגמרי אלא שומר על השארית (5) וממשיך את הספירה ממנה.

הביקורת

לכאורה, זה יופי של דבר: אנחנו משתחררים מהתלות במספרים שלמים-בלבד ובחזקות של 2, ונפתח לנו מרחב חדש של תדירות פעולות. אבל רק לכאורה. זאת כי ההצטברות של השארית לאורך זמן גורמת לכך שה"תקתוקים" של ה-NCO אינם במרווחי זמן אחידים! אחת לכמה מחזורים (המספר המדויק תלוי כמובן בערך שאנחנו מוסיפים כל פעם) יהיו לנו שני תקתוקים סמוכים יותר מהרגיל. סטיות כאלה מהקצב, שנקראות Jitter, יכולות להפריע ואפילו להיות קטלניות לרוב יישומי התזמון שאני יכול לחשוב עליהם. סתם לדוגמה, דמיינו מישהו שמנסה לנגן לפי קצב של מטרונום עם Jitter…

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

ה-Jitter לא יפריע לנו אם אנחנו צריכים תדירות פולסים מדויקת רק בממוצע לאורך זמן, אבל זה מצב די נדיר. מסתבר שהוא יכול להתקיים, למשל, במייצב מתח ממתג (switching), ואולי גם בהפעלת מנועי DC, בתנאי שהתדירות גבוהה מספיק. יש גם מספר מוגבל מאוד של תדירויות, שבהן לא תצטבר שארית והדיוק יהיה מושלם. האם בשביל מקרים יוצאי דופן כאלה שווה לכלול בחומרה סוג מודול חדש? ב-Microchip החליטו שכן, אז בואו נראה איך זה עובד שם.

ההדגמה

כדי להדגים את פעולת ה-NCO, אשתמש בלוח פיתוח/הדגמה Curiosity Nano של Microchip למיקרו-בקר החדש והמשוכלל PIC18F57Q43. המפלץ הקטן הזה כולל 3 מודולי NCO נפרדים, ומי שממש רוצה יכול אפילו לשרשר אותם בתדר מינימלי לכל אחד, לחבר את הראשון לשעון הפנימי הכי איטי ולקבל בפלט הסופי סיגנל פעם בכמה מיליוני שנים בערך. כאן נתמקד במודול יחיד (NCO1) ובתדרים גבוהים קצת יותר.

הפרמטרים המדויקים של ה-NCO תלויים בדגם המיקרו-בקר. במקרה שלנו, הרגיסטר המונה (למעשה, שילוב של ביטים מ-3 רגיסטרים) הוא בגודל 20 ביט (ערכים 0-1048575), וגם הערך שאנחנו יכולים להוסיף כל פעם הוא עד 20 ביט.

בתור התחלה, יצרתי תוכנה שלא עושה כלום, רק עם configuration bits שמחברים את המערכת למתנד פנימי בתדר 64MHz (התדר של שעון הפעולות ב-PIC הוא תמיד רבע משעון המערכת), ומוציאים את אות שעון הפעולות כפלט בפין RA6. האות יצא קצת חלוש, אבל בהחלט בתדר הצפוי – כ-16MHz.

פלט שעון הפעולות של ה-PIC
פלט שעון הפעולות של ה-PIC (לחצו להגדלה)

ניגש להגדרת NCO1. אנחנו יכולים לבחור בין שני אופני פלט. הראשון הוא גל ריבועי (הפלט מתחלף עם כל "פולס" של ה-NCO, כמו PWM עם Duty cycle של 50%), והשני הוא פולסים קצרים, שנמשכים 1-128 "תקתוקי שעון", לבחירתנו. זהירות כאן: מדובר על אותו שעון שמזין את ה-NCO, כך שאם אנחנו מבקשים פולס ארוך וגם מגדילים את המונה במספר גדול מאוד כל פעם, הפולס למעשה יהיה ארוך יותר מקצב הפלט ולא נראה שום שינוי. למען הפשטות נבחר באפשרות הראשונה של גל ריבועי, שהיא גם ברירת המחדל. זה מוגדר בביט הנמוך של הרגיסטר NCO1CON, שנקרא PFM. באותו רגיסטר, הביט הגבוה (EN) הוא זה שמפעיל או מכבה את המודול, אבל בו נוגעים רק אחרי שכל ההגדרות הושלמו.

בחמשת הביטים הנמוכים של הרגיסטר NCO1CLK נבחר את מקור השעון הרצוי לנו. במקרה זה, שעון המערכת (Fosc) שהקוד עבורו 00000. גם כן ברירת המחדל, כמה נוח. אבל זה קצת חשוד, כי Fosc הוא הרי בתדר של 64MHz, האם ה-NCO באמת יכול לבצע את החישובים הדרושים במהירות כזו? נחכה ונראה… מעבר לזה, נשאר לנו רק להגדיר את ההגדלה של המונה, ברגיסטר משולש- הבייטים NCO1INC.

הנוסחה לחישוב תדר הפלט (שיתחלק לנו לשניים אם מייצרים ממנו גל ריבועי) מופיעה ב-datasheet כך:

נוסחת תדירות הפלט של ה-NCO, מתוך ה-datasheet של PIC18F57Q43
נוסחת תדירות הפלט של ה-NCO, מתוך ה-datasheet של PIC18F57Q43

ואם נשחק איתה, נגלה שערך הגדלה 1 לשעון של 64MHz אמור לתת גל ריבועי בתדר 30.51758Hz. אבל רגע, איפה אנחנו אמורים לראות את הפלט הזה? שום פין לא מוקצה כברירת מחדל, ואנחנו צריכים לבחור אותו בעצמנו בעזרת מודול ה-PPS המגניב (מככב בפוסט הזה). רציתי לבחור את פין RF3, גם כי הוא בקצה הלוח וזה נוח לחיבור הפרוב של הסקופ, וגם כי לפין הזה מחובר לד מובנה, שאוכל לראות את התוצאה בעין. לצערי, בטבלת האופציות של ה-PPS הסתבר שעבור NCO1, מותר לי לבחור מפורט A או D בלבד, ואילו F מחוץ לתחום. טוב, אז שיהיה בפין RD2.

חלק מטבלת הפורטים הזמינים לפי מקורות ה-PPS
חלק מטבלת הפורטים הזמינים לפי מקורות ה-PPS. ה-NCO שלנו בשורה השלישית (לחצו להגדלה)

נכתוב את כל הקוד הדרוש:

קוד מינימלי להפעלת NCO והפניית הפלט שלו לפין GPIO (ב-MPLAB X)
קוד מינימלי להפעלת NCO והפניית הפלט שלו לפין GPIO (ב-MPLAB X)

והנה הפלט מפין RD2:

פלט NCO עם INC של 1
פלט NCO עם INC של 1 (לחצו להגדלה)

איזה יופי! ואם נכפיל את NCO1INC, נקבל-

פלט NCO עם INC של 2
פלט NCO עם INC של 2 (לחצו להגדלה)

למרבה האכזבה, מסתבר שה-NCO יכול אמנם לספור סיגנלים משעון ב-64MHz, אבל לא לבצע את שאר הפעולות באותו קצב. כשניסיתי להפיק ממנו תדר גבוה יותר מ-8MHz (שוב, במצב גל ריבועי זה אומר שתדר הפלט של ה-NCO עצמו הוא למעשה יותר מ-16MHz), הוא כשל והפיק רק רעש.

ומה בדבר ה-Jitter? בסקופ קצת קשה לבודד ולראות אותו, אך הנה תמונה של פלט מ-INC של 32768 (חזקה של 2, אז אין שארית):

פלט NCO עם INC של 32768
פלט NCO עם INC של 32768 (לחצו להגדלה)

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

פלט NCO עם INC של 24576
פלט NCO עם INC של 24576 (לחצו להגדלה)

תגידו מה שתגידו על השימושיות של ה-NCO, דבר אחד בטוח – ממש קל להפעיל אותו, ובמקרה של ה-PIC הזה, עם הטווח המכובד של 20 ביט, אפשר גם להפיק ממנו הרבה מאוד תדירויות פלט בלי להתעסק עם prescaler וסיבוכים אחרים. רק בזהירות.

להרשמה
הודע לי על
3 תגובות
מהכי חדשה
מהכי ישנה לפי הצבעות
Inline Feedbacks
הראה את כל התגובות

תוך שימוש בסינון או שילוב עם PLL חיצוני המודול יכול לשמש לייצור אותות בתדר מאוד מדוייק ונקי – זה יכול להיות שימוש מרגש מאוד אם תרצה להרים מקלט\משדר רדיו משלך עם בקרים ממשפחה זו. בשילוב עם טבלת ערכים שחושבו מראש (ו-DAC) ניתן לייצר ככה סיגנל שרירותי בכל תדר שתבחר, מה שנקרא DDS – וזה שימוש אפילו יותר מרגש. עם זאת ממה שהבנתי זה לא נתמך בחומרה, ואני חושד שמימוש תכנתי יהיה במקרה הטוב מוגבל. אני מודה שלא הבנתי מה-app notes של מיקרוצ'יפ מה השוס הגדול שהמודול הזה מציע אצלהם. ולא, דימר לנורות לד ברזולוציה גבוהה (כמו שהם הציעו בappnote כלשהו)… לקרוא עוד »

חלק מהקסם שבסינון זה שהג'יטר הזה יכול להעלם ברובו המכריע – הסינון יותיר סינוס יחסית נקי, אם יעשה בצורה מוצלחת (אני חושב ש-PLL הוא פתרון טוב לסינון כזה אך בכנות אין לי הבנה כל כך טובה בזה).