MSP430 ตอนที่ 1 Clock System

Sirichat Sangjuiwong
MCUREGIS
Published in
3 min readMay 16, 2019

วันนี้จะมาแชร์ประสบการณ์เขียนไมโครคอนโทรลเลอร์จากค่าย Texas Instruments โดยเลือก MSP430FR5729 มาใช้ ซึ่งประเด็นหลักๆเลยของบทความนี้คืออยากมาแชร์การเซ็ทรีจิสเตอร์สำหรับ ตั้งค่า Clock ที่จ่ายให้ CPU และ Peripheral ต่างๆ

สิ่งที่จะพูดถึงในบทความนี้

  1. Function Block Diagram ของ MSP430FR5729
  2. Clock System
  3. ตัวอย่างการเซ็ท External Clock เพื่อจ่ายให้กับ MSP430FR5729
  1. Function Block Diagram ของ MSP430FR5729

จาก datasheet ของ MSP430FR5729 ในส่วนของ Function Block Diagram พบว่า Output ของ Clock System ที่จ่ายให้ CPU ก็คือ MCLK ส่วน ACLK , SMCLK จะใช้จ่ายให้ Peripheral ต่างๆ

2. Clock System

จาก user guides ของ MSP430FR5729 จะพบว่า ACLK , MCLK และ SMCLK จะมี Multiplexer ในการเลือก Clock Source หลังจากนั้นก็จะนำ Clock ที่ได้ไปหารเพื่อให้ความถี่เหมาะสมกับอุปกรณ์ต่าง

ซึ่งใน user guides มีคำอธิบายโดยละเอียดอยู่ว่าพารามิเตอร์ตัวไหนมีหน้าที่ทำอะไรโดยพารามิเตอร์พวกนี้จะถูกแมปเข้ามาเป็น Register ให้เราได้ตั้งค่ากันซึ่งจะรวบรวมอยู่ด้านล่างสุดของบทนั้นๆดังภาพ

3. ตัวอย่างการเซ็ท External Clock เพื่อจ่ายให้กับ MSP430FR5729

ในตัวอย่างนี้เราใช้ External Crystal ความถี่ 16 MHz โดยในหัวข้อ 3.1 ถึง 3.9 จะอยู่ภายในฟังก์ชัน main ส่วน 3.10 จะอยู่ที่อื่นเพราะเป็น Interrupt Service Routine

ปล.ในโค๊ดผมจะใช้การ shift รีจิสเตอร์ โดยจะไม่ใช้ค่าที Texas ทำการ Define ไว้เพราะอยากให้คนอ่านเชื่อมโยงกับ user guides

3.1 ส่วนนี้เป็นการเซ็ท Pin ให้เปลี่ยนจาก GPIO ให้เป็น external crystal
ดูได้จากหัวข้อ Input/Output Diagrams ใน datasheet
PJSEL1 &= ~(0x01<<4);
PJSEL0 |= 0x01<<4;
3.2 ทำการใส่รหัสเพื่อเข้าถึง Clock System RegisterCSCTL0_H = 0xA5; 3.3 ทำการเซ็ต Digitally Controlled Oscillator (DCO) หรือ Clock ภายในของ MSP430FR5729 เพราะว่าในกรณีที่ External Clock เกิด Fault ระบบจะสวิทช์กลับมาใช้ DCO เป็น Default ในที่นี้เซ็ทให้เป็น 8 MHz ไว้ก่อนCSCTL1 &= ~(0x01<<7);
CSCTL1 |= 0x03<<1;

3.4 เซ็ต Multiplexer เพื่อเลือกใช้ external clock ทั้ง 3 module
CSCTL2 &= ~(0x07); //Select XT1CLK for MCLK
CSCTL2 &= ~(0x07<<4); //Select XT1CLK for SMCLK
CSCTL2 &= ~(0x07<<8); //Select XT1CLK for ACLK
3.5 เนื่องจากในที่นี่ใช้ External Crystal 16 MHz ก็เลยเอามาหาร 2 มันทุกโมดูลไปเลย
ในส่วนนี้แล้วแต่นะว่าอยากจะให้แต่ละอันใช้ความถี่เท่าไหร่ แต่ MCLK ต้องไม่เกิน 8 MHz
CSCTL3 &= ~(0x07); //MCLK = F/2
CSCTL3 |= 0x01;
CSCTL3 &= ~(0x07<<4); //SMCLK = F/2
CSCTL3 |= 0x01<<4;
CSCTL3 &= ~(0x07<<8); //ACLK = F/2
CSCTL3 |= 0x01<<8;
3.6 เนื่องจาก External Crystal ที่ใช้เป็น 16 MHz ทำให้ต้องเซ็ทให้เป็น HF Mode
ดูรายละเอียดจากหัวข้อ Specification ใน datasheet
CSCTL4 |= 0x01<<5; // XTS = 1 : High Frequency Mode
CSCTL4 &= ~(0x01<<4); // XT1BYPASS = 0 : Source From External Clock
CSCTL4 &= ~(0x03<<6); // XT1DRIVE = 10b : HF Mode 10-16 MHz
CSCTL4 |= 0x02<<6;
3.7 Turn On XT1 โดยต้องเช็คด้วยว่า Fault รึเปล่า ถ้ามี Flag ของ Oscillator Fault ให้เคลียร์ Flag ไปเรื่อยๆจนกว่าจะไม่มี Fault FlagCSCTL4 &= ~0x01; //TURN ON XT1CLK
do
{
CSCTL5 &= ~0x01; // Clear XT1 Fault Flag
SFRIFG1 &= ~0x02; // Clear Oscillator Fault Interrupt Flag
}
while(SFRIFG1&0x02);
3.8 เซ็ทเสร็จแล้วก็ล็อค Register ด้วยการใส่รหัสผิดเข้าไป
CSCTL0_H = 0x00; // Lock CSCTL Register
3.9 ทำการ Enable Oscillator Fault Interrupt เผื่อใช้ๆไปแล้วเกิด Fault ขึ้นมาอีกก็ให้กระโดดเข้าไปที่ Interrupt Service RoutineSFRIFG1 &= ~0x02; // Enable Oscillator Fault Interrupt
SFRIFG1 |= 0x02;
3.10 เมื่อโดดเข้ามาใน Oscillator Fault Interrupt Service Routine นั่นหมายความว่ามี Fault เกิดขึ้น ก็ทำแบบเดียวกับข้อ 3.7#pragma vector = UNMI_VECTOR
__interrupt void UNMI_ISR(void)
{
CSCTL0_H |= 0xA5;
do
{
CSCTL5 &= ~0x01;
SFRIFG1 &= ~0x02;
}
while(SFRIFG1&0x02);
CSCTL0_H |= 0x00;
}

--

--