// Timer : PWM sur une sortie // EPFL 2020, Pierre-Yves Rochat, pyr@pyr.ch #include #include // Définition des LED et des poussoirs pour la carte "blanche" #define Led1On P1OUT|=(1<<0) #define Led1Off P1OUT&=~(1<<0) #define Led1Toggle P1OUT^=(1<<0) #define InitLed1 P1DIR|=(1<<0);Led1Off #define Led2On P8OUT|=(1<<1) #define Led2Off P8OUT&=~(1<<1) #define Led2Toggle P8OUT^=(1<<1) #define InitLed2 P8DIR|=(1<<1);Led2Off #define Led3On P8OUT|=(1<<2) #define Led3Off P8OUT&=~(1<<2) #define Led3Toggle P8OUT^=(1<<2) #define InitLed3 P8DIR|=(1<<2);Led3Off #define Led4On P1OUT|=(1<<1) #define Led4Off P1OUT&=~(1<<1) #define Led4Toggle P1OUT^=(1<<1) #define InitLed4 P1DIR|=(1<<1);Led4Off #define Led5On P1OUT|=(1<<2) #define Led5Off P1OUT&=~(1<<2) #define Led5Toggle P1OUT^=(1<<2) #define InitLed5 P1DIR|=(1<<2);Led5Off #define Led6On P1OUT|=(1<<3) #define Led6Off P1OUT&=~(1<<3) #define Led6Toggle P1OUT^=(1<<3) #define InitLed6 P1DIR|=(1<<3);Led6Off #define Led7On P1OUT|=(1<<4) #define Led7Off P1OUT&=~(1<<4) #define Led7Toggle P1OUT^=(1<<4) #define InitLed7 P1DIR|=(1<<4);Led7Off #define Led8On P1OUT|=(1<<5) #define Led8Off P1OUT&=~(1<<5) #define Led8Toggle P1OUT^=(1<<5) #define InitLed8 P1DIR|=(1<<5);Led8Off #define Pous1On (!(P1IN&(1<<7))) #define InitPous1 P1DIR&=~(1<<7);P1REN|=(1<<7);P1OUT|=(1<<7) #define Pous2On (!(P2IN&(1<<2))) #define InitPous2 P2DIR&=~(1<<2);P2REN|=(1<<2);P2OUT|=(1<<2) void InitCarteBlanche() { InitLed1; InitLed2; InitLed3; InitLed4; InitLed5; InitLed6; InitLed7; InitLed8; InitPous1; InitPous2; } void AfficheLedBleues(uint16_t val) { if (val & (1<<0)) { Led8On; } else { Led8Off; } if (val & (1<<1)) { Led7On; } else { Led7Off; } if (val & (1<<2)) { Led6On; } else { Led6Off; } if (val & (1<<3)) { Led5On; } else { Led5Off; } if (val & (1<<4)) { Led4On; } else { Led4Off; } } // Procédures pour passer la fréquence de 1 à 25 MHz // (fournies par Texas Instrument !) void SetVCoreUp (unsigned int level) { PMMCTL0_H = 0xA5; // Open PMM registers for write access // Set SVS/SVM high side new level : SVSMHCTL = SVSHE + SVSHRVL0 * level + SVMHE + SVSMHRRL0 * level; // Set SVM low side to new level : SVSMLCTL = SVSLE + SVMLE + SVSMLRRL0 * level; while ((PMMIFG & SVSMLDLYIFG) == 0) {} // Wait till SVM is settled PMMIFG &= ~(SVMLVLRIFG + SVMLIFG); // Clear already set flags PMMCTL0_L = PMMCOREV0 * level; // Set VCore to new level if ((PMMIFG & SVMLIFG)) { // Wait till new level reached while ((PMMIFG & SVMLVLRIFG) == 0); } // Set SVS/SVM low side to new level : SVSMLCTL = SVSLE + SVSLRVL0 * level + SVMLE + SVSMLRRL0 * level; PMMCTL0_H = 0x00; // Lock PMM registers for write access } void setupDCO(void) { SetVCoreUp(1u); // Power settings SetVCoreUp(2u); SetVCoreUp(3u); UCSCTL3 = SELREF__REFOCLK; // select REFO as FLL source UCSCTL6 = XT1OFF | XT2OFF; // turn off XT1 and XT2 // Initialize DCO to 25.00MHz : __bis_SR_register(SCG0); // Disable the FLL control loop UCSCTL0 = 0x0000u; // Set lowest possible DCOx, MODx UCSCTL1 = DCORSEL_6; // Set RSELx for DCO = 50 MHz UCSCTL2 = 762u; // Set DCO Multiplier for 25MHz // (N + 1) * FLLRef = Fdco, (762 + 1) * 32768 = 25.00MHz UCSCTL4 = SELA__REFOCLK | SELS__DCOCLK | SELM__DCOCLK; __bic_SR_register(SCG0); // Enable the FLL control loop // Worst-case settling time for the DCO when the DCO range bits have been // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx // UG for optimization. // 32*32*25MHz/32768Hz = 781250 = MCLK cycles for DCO to settle __delay_cycles(781250u); do { // Loop until XT1,XT2 & DCO fault flag is cleared UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); // Clear XT2,XT1,DCO fault flags SFRIFG1 &= ~OFIFG; // Clear fault flags } while (SFRIFG1&OFIFG); // Test oscillator fault flag } uint16_t cptCycle; void main(void) { WDTCTL = WDTPW | WDTHOLD; setupDCO(); // Fréquence à 25 MHz InitCarteBlanche(); Led7On; // intensité de référence; le PWM est sur la LED8 cptCycle = 0; // compteur de cycle // Initialisation du Timer : // choix de l'horloge et mode continu TA0CTL = TASSEL_2 | ID_0 | MC_2 | TAIE; TA0CCR1 = 16384; // PWM à 25% // Interruption pour registre de comparaison 0 : TA0CCTL1 = CCIE; __enable_interrupt(); // Active l'ensemble des interruption while (1) { // boucle infinie vide } } // Timer_A1 Interrupt Vector (TAIV) handler #pragma vector=TIMER0_A1_VECTOR __interrupt void Timer_A1(void) { switch(TA0IV) { case 2: // CCR1 : fin de l'impulsion Led8Off; break; case 4: // CCR2 : not used break; case 6: // CCR3 : not used break; case 8: // CCR4 : not used break; case 14: // Overflow (cette valeur était de 10 pour le MSP430G) Led8On; // début du cycle cptCycle++; if (cptCycle == 2000) { cptCycle = 0; Led1Toggle; } break; } } // Estimation de la fréquence du PWM : //------------------------------------ // // 25 MHz correspond à une période de 1/25'000'000 secondes, soit 0.04 us (microseconde). // Avec le prédiviseur à 1, c'est un signal avec cette période qui fait compter le Timer. // Le timer a 16 bits, il compte donc jusqu'à 2^16, soit 65'536 cycles. // La période du PWM est donc de 65'536 * 0.04us = 2'621 us, soit environ 2.6 ms, ce qui correspond 381 Hz // En agissant sur la LED 1 tous les 2'000 cycles, on devrait mesurer : // 2.6 ms * 2'000 = 5'200 ms, donc 5.2 secondes