لنتعلم برمجة الأنظمة المدمجة

Embedded Systems Programming Bootcamp

كورس تعليمي يهدف الى اكسابك المعرفة اللازمة والمهارات التقنية المتعلقة ببرمجة وتطوير الأنظمة المدمجة وفهم خصائصها ومكوناتها

الصفحة الرئيسية
قائمة الدروس
خدمة RSS

للتواصل

10. Phased Lock Loop - PLL

2018-06-20






مصادر الساعة

توفر ساعة المتحكم النبضات اللازمة للحفاظ على تشغيل التطبيقات بطريقة متزامنة. وبالعودة الى دليل البيانات data sheet ص 222:

بإمكاننا أن نرى عدة مصادر للساعة ويوجد لدينا أشكال تشبه متوازي الأضلاع عبارة عن محددات أو مقسمات تحدد بعض الخصائص عن طريق التحكم في بعض البتات bits في سجلات registers معينه.

بإمكان نظام الساعة أن يستخدم أحد المصادر التالية:

1. Percision Internal Oscillator - PIOSC

2. Main Oscillator - MOSC

3. Low Frequency Internal Oscillator - LFIOSC

4. Hibernation Module Clock Source

مع ملاحظة أنه يجب عدم تعطيل PIOSC إلا إذا لزم الأمر، وذلك لأنه إذا تم استخدام MOSC وفشل لسبب ما، فإن PIOSC ستتولى دور توفير إشارة للساعة.


Phased Lock Loop - PLL

تردد الكرستالة المستخدمة في البورد هي 16 ميجاهيرتز، ولكن بإمكان المتحكم أن يصل الى تردد 80 ميجاهيرتز كيف يكون ذلك؟

ما يحدد سرعة تنفيذ المتحكم هو الكرستالة الخارجية المستخدمة والتي تبلغ في هذه البورد 16 ميجاهيرتز. لكن يوجد لدينا ما يسمى بالـ Phased Lock Loop - PLL والتي تسمح للبرنامج بضبط سرعة الساعة وجعلها تعمل بترددات أعلى أو أقل من تردد الكرستالة. عادةً ما يتضمن اختيار التردد المفاضلة بين سرعة تنفيذ البرامج والطاقة الكهربائية المستخدمة. أي أن إبطاء الساعة يجعل من المتحكم يستهلك طاقة أقل. وتسريع الساعة يسمح بتنفيذ المزيد من العلميات في الثانية، ولكن ذلك يتطلب المزيد من الطاقة.

يبلغ تردد المذبذب الداخلي internal oscillator سرعة 16 ميجاهيرتز ودقة 1٪. وهو أقل دقة بكثير من الكرستالة، ولكنه يتطلب طاقة أقل ولا يحتاج إلى كرستالة خارجية. ولكن إذا كنا نرغب في التحكم الدقيق بالوقت، سنقوم بتنشيط الكرستالة الخارجية (تسمى المذبذب الرئيسي main oscillator) واستخدام PLL لتحديد السرعة المطلوبة.

من دون تفعيل الـ PLL، فإن المتحكم سيعمل بتردد 16 ميجاهيرتز، مما يعني أن عداد SysTick سينقص كل 62.5 نانوثانية وإذا قمنا بتنشيط الـ PLL لتشغيل المتحكم بسرعة 80 ميجا هرتز، فإن عداد SysTick سينقص كل 12.5 نانوثانية.

وتتراوح ترددات الـ PLL الداخلي internal PLL (على خلاف الـ USB PLL) من 3.125 ميجاهرتز إلى 80 ميجاهرتز. ويأتي المتحكم المستخدم مع PLL داخلي بتردد 400 ميجاهرتز ويقبل أي كرستالة من 5 إلى 25 ميجاهرتز. ويمكن للمذبذبات التالية أن تكون مصدراً للـ PLL:


السجلات

1. Run-Mode Clock Configuration - RCC

توفر عناصر التحكم بساعة النظام.

تفصيل هذا السجل في دليل البيانات data sheet ص 254:

#define SYSCTL_RCC_R	(*((volatile unsigned long *)0x400FE060))

وما يهمنا في هذا السجل هو الحقل التالي:

نحدد في هذا الحقل قيمة تردد الكرستالة المرفقة بالمذبذب الرئيسي للبورد حسب الجدول أدناه:

2. Run-Mode Clock Configuration 2 - RCC2

توفر عناصر التحكم بساعة النظام. يستخدم سجل RCC2 لتوفير خصائص تحكم إضافية عن تلك الموجودة في سجل RCC.

تفصيل هذا السجل في دليل البيانات data sheet ص 260:

#define SYSCTL_RCC2_R	(*((volatile unsigned long *)0x400FE070))

وما يهمنا في هذا السجل هو الحقول التالية:

إذا كانت SISDIV2 تساوي 4 فإن السرعة ستكون 400 مقسومة على 4 + 1 وبذلك يكون الناتج 80 ميجاهيرتز. وإذا أردنا تشغيل المتحكم بسرعة أبطأ فكل ما علينا فعله هو زيادة قيمة SISDIV2.

3. Raw Interrupt Status - RIS

تفصيل هذا السجل في دليل البيانات data sheet ص 244:

#define SYSCTL_RIS_R	(*((volatile unsigned long *)0x400FE050))

وما يهمنا في هذا السجل هو الحقل التالي:


تفعيل الـ PLL

فيما يلي الخطوات المطلوبة لتفعيل البورد مع مذبذب رئيسي بتردد 16 ميجاهيرتز لتشغيل المتحكم بسرعة 80 ميجاهيرتز.

1. استخدم RCC2 لأنه يوفر المزيد من الخيارات على RCC ويكون ذلك عن طريق إسناد 1 الى حقل USERCC2 (بت 31) في RCC2

SYSCTL_RCC2_R |=  0x80000000; // 1000 0000 0000 0000 0000 0000 0000 0000  

2. تجاوز مقسم ساعة PLL وساعة النظام عن طريق إسناد 1 الى حقل BYPASS2 (بت 11) في RCC2. عند هذه النقطة يتم تجاوز PLL ولا يوجد مقسم ساعة نظام.

SYSCTL_RCC2_R |=  0x00000800; // 0000 0000 0000 0000 0000 1000 0000 0000

3. تحديد تردد الكرستالة في حقل XTAL في RCC باستخدام القيّم في جدول XTAL السابق.

بما أن الكرستالة التي على البورد تستخدم مذبذب بتردد 16 ميجاهيرتز فإننا، وحسب الجدول السابق، نقوم بضبط حقل XTAL ليحمل القيمة 0x15 أي 10101. ولو كانت الكرستالة بتردد مختلف، 24 ميجاهيرتز مثلاً، فسنضع القيمة 0x19 أي 11001 في حقل XTAL.

بما أن هذا الحقل يقع من البت 6 الى 10، فإن الرقم الست عشري hex الذي يفعّل جميع بتات هذا الحقل هو:

0x000007C0 = 0000 0000 0000 0000 0000 0111 1100 0000

ولمسح القيمة الموجودة داخل هذا الحقل فإننا نعكس هذا الرقم:

~(0x000007C0) = 1111 1111 1111 1111 1111 1000 0011 1111

وتصبح العملية بلغة الـ C كما يلي:

SYSCTL_RCC_R &= ~0x000007C0;

ولإسناد القيمة 0x15 أي 10101 والتي تمثل قيمة تردد الكرستالة 16 ميجاهيرتز فإنه يجب علينا أن نضع هذه القيمة في حقل XTAL والذي يقع بين البتات 6-10 من السجل RCC. ولذلك نستخدم العدد الست عشري التالي:

0x00000540 = 0000 0000 0000 0000 0000 0000 0000 0101 0100 0000

وبإسناده الى SYSCTL_RCC_R يصبح لدينا:

SYSCTL_RCC_R |= 0x00000540;

4. يتم إسناد 0 الى حقل OSCSRC2 (بت 4-6) في RCC2 لتحديد المذبذب الرئيسي main oscillator كمصدر مذبذب للساعة.

SYSCTL_RCC2_R &= ~0x00000070; // 1111 1111 1111 1111 1111 1111 1000 1111

5. مسح PWRDN2 (بت 13) في RCC2 لتنشيط الـ PLL وتفعيله.

SYSCTL_RCC2_R &= ~0x00002000; // 1111 1111 1111 1111 1101 1111 1111 1111

6. إختيار الـ 400MHz PLL بدلاً من الـ 200MHz PLL عن طريق إسناد 1 الى حقل DIV400 (بت 30) في RCC2.

SYSCTL_RCC2_R |= 0x40000000; // 0100 0000 0000 0000 0000 0000 0000 0000

7. تمكين مقسم الساعة باستخدام حقلي SYSDIV2 و SYSDIV2LSB (بت 22 الى 28) في RCC2.

كما ذكرنا سابقاً، فإنه يتم الإستفادة من حقل SYSDIV2LSB كـ least significant bit لأننا أسندنا 1 الى DIV400.

نقوم أولاً بحذف القيمة الموجودة سابقاً في SYSDIV2 و SYSDIV2LSB (بت 22 الى 28) في RCC2:

SYSCTL_RCC2_R &= ~0x1FC00000; // 1110 0000 0011 1111 1111 1111 1111 1111

ثانياً، للحصول على تردد 80 ميجاهيرتز نحتاج إلى القسمة على 5. لذا، نقوم بوضع 4 في حقل SYSDIV2 و SYSDIV2LSB:

SYSCTL_RCC2_R |= (4<<22); // 0000 0001 0000 0000 0000 0000 0000 0000

8. بعد ذلك، ننتظر حتى يستقر وينتظم الـ PLL ﺑﻮاﺳﻄﺔ مراقبة PLLRIS (ﺒﺖ 6) ﻓﻲ RIS الى أن ﺗﺼﺒﺢ قيمتها 1.

//    0x00000040 = 0000 0000 0000 0000 0000 0000 0100 0000
while((SYSCTL_RIS_R & 0x00000040)==0){};

9. الخطوة الأخيرة هي تمكين الـ PLL عن طريق مسح بت BYPASS2 (بت 11) في RCC2.

SYSCTL_RCC2_R &= ~0x00000800; // 1111 1111 1111 1111 1111 0111 1111 1111

الكود

#define SYSCTL_RIS_R      (*((volatile unsigned long *)0x400FE050))
#define SYSCTL_RCC_R      (*((volatile unsigned long *)0x400FE060))
#define SYSCTL_RCC2_R     (*((volatile unsigned long *)0x400FE070))
  
int main (void) {
  // 1) Use RCC2 for advanced features
  //    Set USERCC2 (bit 31) in RCC2
  //    0x80000000 = 1000 0000 0000 0000 0000 0000 0000 0000
  SYSCTL_RCC2_R |=  0x80000000;
  
  // 2) Bypass PLL while initializing
  //    Set BYPASS2 (bit 11) in RCC2
  //    0x00000800 = 0000 0000 0000 0000 0000 1000 0000 0000
  SYSCTL_RCC2_R |=  0x00000800;
  
  // 3) Select the crystal value and oscillator source
  // 3.a) Clear XTAL (bits 10-6) in RCC
  //       0x000007C0 = 0000 0000 0000 0000 0000 0111 1100 0000
  //      ~0x000007C0 = 1111 1111 1111 1111 1111 1000 0011 1111
  SYSCTL_RCC_R &= ~0x000007C0;
  // 3.b) Set XTAL (bits 10-6) in RCC to 0x15 (10101) for 16 MHz crystal
  //      0x00000540 = 0000 0000 0000 0000 0000 0101 0100 0000
  SYSCTL_RCC_R |= 0x00000540;
  
  // 4) Configure for main oscillator source
  //    Set OSCSRC2 (bits 6-4) in RCC2 to 0 to select main oscillator
  //     0x00000070 = 0000 0000 0000 0000 0000 0000 0111 0000
  //    ~0x00000070 = 1111 1111 1111 1111 1111 1111 1000 1111
  SYSCTL_RCC2_R &= ~0x00000070;
  
  // 5) Activate PLL by clearing PWRDN2 (bit 13) in RCC2
  //     0x00002000 = 0000 0000 0000 0000 0010 0000 0000 0000
  //    ~0x00002000 = 1111 1111 1111 1111 1101 1111 1111 1111
  SYSCTL_RCC2_R &= ~0x00002000;
  
  // 6) Use 400 MHz PLL instead of 200 MHz PLL
  //    Set DIV400 (bit 30) in RCC2 to 1
  //    0x40000000 = 0100 0000 0000 0000 0000 0000 0000 0000
  SYSCTL_RCC2_R |= 0x40000000;   
  
  // 7) Set the desired system divider and the system divider least significant bit
  // 7.a) Clear system clock divider and the system divider least significant bit
  //      Set SYSDIV2 (bits 28-23) in RCC2 to 0
  //      Set SYSDIV2LSB (bit 22) in RCC2 to 0
  //       0x1FC00000 = 0001 1111 1100 0000 0000 0000 0000 0000
  //      ~0x1FC00000 = 1110 0000 0011 1111 1111 1111 1111 1111
  SYSCTL_RCC2_R &= ~0x1FC00000;
  // 7.b) Configure for 80 MHz clock
  //      Set SYSDIV2 + SYSDIV2LSB (bits 28-22) in RCC2 to 4
  //      4<<22 = 0000 0001 0000 0000 0000 0000 0000 0000
  SYSCTL_RCC2_R |= (4<<22);
                                    
  // 8) Wait for the PLL to lock by polling PLLLRIS (bit 6) in RIS
  //    0x00000040 = 0000 0000 0000 0000 0000 0000 0100 0000
  while((SYSCTL_RIS_R & 0x00000040)==0){};
    
  // 9) Enable use of PLL by clearing BYPASS2 (bit 11) in RCC2
  //    ~0x00000800 = 1111 1111 1111 1111 1111 0111 1111 1111
  SYSCTL_RCC2_R &= ~0x00000800;
  
  return 0;
}


المراجع

  1. http://embedded-lab.com/blog/tiva-c-clock-system
  2. http://shukra.cedt.iisc.ernet.in/edwiki/EmSys:TM4C123_Using_PLL
  3. https://courses.edx.org/courses/course-v1:UTAustinX+UT.6.10x+2T2018

ملاحظة: هذه المقالة تحت التحديث المستمر،، وملاحظاتكم وإقتراحاتكم ستساعد بإذن الله في إخراجها بالصورة التي كتبت من أجلها وهي تمهيد الطريق أمامكم لتعلم برمجة الأنظمة المدمجة