בפוסט קודם דיברנו על מודול החומרה NCO במיקרו-בקרים. כעת נעבור למודול אחר, נפוץ קצת יותר אך עדיין לא מוכר למשתמש הארדואינו הטיפוסי: DAC (ראשי תיבות של Digital to Analog Converter), שהוא בעצם ההיפך של ADC המוכר: לוקח ערך מספרי וממיר אותו לפלט מתח אנלוגי.
חשוב להבהיר שבניגוד לפקודת analogWrite בארדואינו, שבה הפלט הוא למעשה דיגיטלי לגמרי (HIGH או LOW) ורק מתחלף במהירות, הפלט של מודולי DAC הוא מתח אנלוגי אמתי וקבוע, שיכול להיות כל ערך בין ה-GND לבין מתח האספקה של המודול עצמו – במגבלות הרזולוציה. את הרזולוציה הזו מבטאים כמספר ביטים, שקובעים את מספר הרמות השונות האפשריות. כמו שב-ADC של ארדואינו (בעל 10 ביט) יש 2-בחזקת-10 ערכים מספריים שונים שאפשר לקבל, כך ב-DAC של 5 ביט אפשר לקבל 2-בחזקת-5, או 32, מתחים שונים. למיקרו-בקר מדגם PIC18F57Q43, שבו אשתמש כאן, יש מודול DAC יחיד ברזולוציה נוחה של 8 ביט – 256 ערכים.
יש כל מיני דרכים לממש DAC בחומרה. במיקרו-בקר שלנו כאן, הוא מבוסס על שרשרת ארוכה של נגדים, ומולטיפלקסר שבוחר – לפי הערך שאנחנו מבקשים – נקודה כלשהי לאורך השרשרת. ערכי הנגדים המצטברים לפני ואחרי אותה נקודה יוצרים "מחלק מתח" קלאסי ואת המתח שמתקבל בפועל ביציאה. בגלל צורת העבודה הזו, הזרם שאפשר להוציא מהמודול הוא אפסי: אם חשבתם לחקות בעזרתו סוללת אלקליין 1.5V לפנס או משהו כזה, צפויה לכם אכזבה מרה. ה-DAC הזה הוא למתחי רפרנס בלבד.
עם זאת, גם מתח רפרנס יכול להספיק כדי להפעיל מתמר פיאזו, מה שאומר שאנחנו יכולים בעיקרון להפיק סאונד אנלוגי סביר בפשטות, וזה מה שבחרתי לעשות לצורך ההדגמה. למיקרו-בקר שלנו יש 128KB של זיכרון FLASH – די והותר בשביל דגימת אודיו קצרה או שתיים!
ההדגמה
הקלטתי את עצמי אומר "נא ללחוץ" ו"נא לעזוב", שמרתי את ההקלטות בפורמט PCM גולמי, 8-ביט ללא סימן (קצב דגימה 44.1KHz, למה לא), ובעזרת תוכנת פייתון קצרה המרתי את הערכים שבקבצים האלה למספרים כתובים כטקסט ומופרדים בפסיקים, כדי שאוכל להעתיק-ולהדביק אותם כמערכי בייטים ענקיים בקוד התוכנה של המיקרו-בקר. המערך הראשון תפס 32,640 בייטים, והשני 31,616.
כדי להשמיע את הדגימות צריך משהו שיתזמן את שליחת הבייטים מהמערך לפיאזו, בקצב זהה (או קרוב ככל האפשר) לקצב הדגימה. טיימר הוא המועמד הטבעי, אך ה-NCO הפשוט מהפוסט שהזכרתי למעלה יספיק גם כן: עם שעון מערכת של 64MHz, אפשר להגיע איתו לתדר של 44.128KHz. כאן, במקום לחבר את הפלט של ה-NCO לפין פיזי, נגרום לו להפעיל פסיקה, ובתוך פונקציית הפסיקה נכתוב את הקוד ששולח בייט חדש כל פעם ל-DAC. כמובן, אני גם אגדיר פין אחר בתור פין קלט ללחצן, כדי שתהיה משמעות מעשית לדגימות הקול שהקלטתי.
כדי להפעיל את ה-DAC עצמו ב-PIC18F57Q43 צריך להכיר רק שני רגיסטרים: DAC1DATL, שהוא פשוט הערך שאנחנו רוצים לשלוח למודול (בין 0 ל-255), ו-DAC1CON ששולט באופציות השונות: ביט EN בו מפעיל/משבית את המודול כולו, צמד הביטים OE קובע לאן יילך הפלט (פין RA2, פין RB7 או ללא פלט חיצוני), צמד הביטים PSS קובע מה יהיה מקור המתח העליון עבור שרשרת הנגדים (מתח המערכת, מתח מפין חיצוני, או רפרנס פנימי קבוע) והביט NSS קובע את מקור המתח התחתון (שוב, GND של המערכת או מתח מפין חיצוני).
כהערת שוליים, המיקרו-בקר גרם לי להתקף לב קטן כשגיליתי שהסיגנל מהפוסט על ה-NCO המשיך להופיע בפין הפלט שהגדרתי שם, אף על פי שהקוד החדש שהעליתי לא כלל שום הפניית פלט כזו. בסופו של דבר, האותיות הקטנות ב-datasheet גילו שכל עוד אין POR (אתחול כתוצאה מניתוק מהחשמל וחיבור-מחדש, Power-On Reset), מודול ה-PPS ממשיך עם הפניות הפלט האחרונות שהוגדרו לו – גם אם צורבים קוד חדש לגמרי שדורס לכאורה את כל הזיכרון!
אחרי שכתבתי עוד קצת קוד בלולאה הראשית ובפונקציית הפסיקה, שהחליט איזו דגימת קול להשמיע בהתאם לקלט מהלחצן ושלח את הבייטים הרלוונטיים ל-DAC, הפרויקט הושלם. הבעיה היחידה הייתה שהצליל יצא חלש מאוד, ברמה שצריך לקרב את האוזן לפיאזו כדי לשמוע.
שני פתרונות קופצים מיד לראש: להיעזר ברכיב מגבר שרת עם מקור מתח גבוה יותר כדי להגביר את המתח לפיאזו, או (מה שבחרתי בסוף) להיעזר במגבר שרת כ-buffer פשוט, שייתן את אותו המתח אך יהיה מסוגל גם לתת קצת יותר זרם, ואת זה לחבר לרמקול "קלאסי" קטן. התוצאה היא עדיין לא משהו שיגרום לשכנים להתלונן למוקד של העירייה, אך מספיק בשביל לשמוע ממרחק סביר בחדר שקט:
מגניב