Algoritmo di controllo dell’oscillatore DCO per microcontrollore MSP430

Un algoritmo di controllo e regolazione dell’oscillatore interno DCO del microcontrollore Texas Instruments MSP430: le sue prestazioni lo rendono particolarmente adatto ad applicazioni quali strumentazione di misura, sensoristica intelligente  ed elettronica di consumo. Le periferiche sono state progettate  per richiedere il minor supporto software possibile. L’algoritmo è stato scritto interamente in linguaggio C ed è suddiviso in due funzioni: il ciclo di taratura del DCO e il controllo della stabilità dell’oscillatore nel tempo.

Introduzione

Il microcontrollore  MSP430 di Texas Instruments, è un RISC a 16 bit con architettura von Neumann (figura 1).

Figura 1. Architettura del MSP430

Figura 1. Architettura del MSP430

Di seguito le principali caratteristiche del micro:

  • 1KB-120KB di Flash ISP;
  • Fino a 10KB RAM;
  • ADC a 10/12/16 bit;
  • DAC a 12 bit;
  • Comparatore interno;
  • Supporto per pilotaggio LCD;
  • SVS (Supply Voltage Supervisor);
  • Timers a 8 e 16 bit;
  • Watchdog timer;
  • UART/LIN;
  • I2C;
  • SPI;
  • IrDA;
  • Moltiplicatore hardware;
  • Controller DMA;
  • Sensore di temperatura;

Il convertitore A/D ha un sistema di scansione automatica dei vari ingressi e l’avvio della conversione (che avviene via hardware) avvia un trasferimento dati in DMA. Il sistema di clock di questo microcontrollore è studiato appositamente per applicazioni low-power.  Un clock ausiliario a bassa frequenza (ACLK) viene direttamente pilotato  da un cristallo a 32KHz o da un oscillatore interno  e può essere  usato come real-time clock in background. Il sistema DCO (Digitally  Controlled Oscillator) fornisce invece i segnali di MCLK (master clock) e SMCLK (Sub-Master Clock) che vengono utilizzati rispettivamente dalla CPU e dalle periferiche. La struttura del sistema di clock è riportata in figura 2.

Figura 2. Il sistema clock interno al microcontrollore

Figura 2. Il sistema clock interno al microcontrollore

IL DCO

Questo articolo mostrerà un efficiente algoritmo per il  controllo  della  precisione del DCO interno al microcontrollore dal punto di vista della stabilità dell’oscillazione nel tempo e del ciclo di taratura. Questa periferica del microcontrollore  MSP430 è un oscillatore con le caratteristiche di un circuito RC. Come un oscillatore RC la sua frequenza varia in funzione della temperatura e della tensione e, a parità di condizioni,  è diversa da componente a componente. Per poter utilizzare questo oscillatore come clock di sistema è necessario quindi tarare la sua frequenza e controllare costantemente il suo valore per correggere le inevitabili variazioni indotte  dalle variazioni di temperatura e tensione di alimentazione. Il valore di resistenza che alimenta il DCO che definisce la sua frequenza di oscillazione. È possibile  selezionare  8 resistenze interne alla periferica oppure utilizzare una resistenza esterna. Questa ultima scelta permette di stabilizzare le variazioni in  temperatura  e di  raggiungere frequenze più elevate ma non sarà considerata in questo articolo. Il DCO è un oscillatore ad anello a otto stadi quindi, scelta la resistenza che determina la frequenza base di oscillazione, è possibile ottenere fino a otto frequenze diverse. Le due frequenze adiacenti nell’intervallo di otto frequenze selezionato possono essere modulate per ottenere una frequenza intermedia. La modulazione avviene con la formula seguente:

318

dove fDCO  e f(DCO+1) sono le due frequenza adiacenti nell’intervallo selezionato.

MOD indica quante volte viene utilizzata fDCO  dal modulatore nel periodo di 32 cicli di clock del DCO.In  conclusione si possono selezionare otto diversi intervalli di frequenza per l’oscillatore, che sono parzialmente sovrapposti. All’interno  di ogni intervallo sono definite 8 frequenze base che possono essere modulate per ottenere diverse frequenze intermedie I registri interni che controllano il DCO sono:

Il registro BCSCTL1: in questo registro è possibile selezionare la resistenza interna Rsel che alimenta il DCO e quindi definire il gruppo di otto frequenze base. Il registro DCOCTL che controlla il modulatore e consente di ottenere tutte le frequenze intermedie.

La procedura di configurazione dell’oscillatore DCO è la seguente:

  1. Selezionare il range di frequenze scegliendo la resistenza Rsel (registro BCSCTL1 bit0..2);
  2. Segliere una  frequenza base scelta tra  le otto possibili dell’intervallo  selezionato (registro DCOCTL bit 5..7);
  3. Definire la modulazione tra le due frequenze adiacenti fDCO, fDCO+1(registro DCOCTL bit 0..4).

ALGORITMO DI CONTROLLO

Per controllare la frequenza di oscillazione del DCO l’algoritmo  utilizza un timer interno al microcontrollore. È possibile scegliere uno qualsiasi dei due timer A o B presenti nell’ MSP430 (nel codice descritto nel listato 1 la definizione DCOuseTMRA o DCOuseTMRB permette di effettuare facilmente questa scelta). L’uscita del DCO, tramite il clock SMCLK, viene utilizzata come clock per il timer selezionato. Uno dei registri del timer è quindi configurato come funzione di capture controllato  da un segnale esterno di trigger. Questo segnale cattura periodicamente, nel registro prescelto il valore del timer (figura 3).

Figura 3. Schema delle connessioni dei timer interni al microcontrollore

Figura 3. Schema delle connessioni dei timer interni al microcontrollore

La differenza tra due letture successive fornisce il rapporto tra la frequenza di clock del timer e la frequenza del segnale di  capture applicato  esternamente. Nota la frequenza del segnale di capture è possibile ricavare il valore attuale della frequenza del DCO con la formula:

320

Il segnale periodico per la funzione di capture viene fornito  dal clock interno ACLK, che si ottiene collegando un quarzo, in questo caso da 32KHz, all’oscillatore in bassa frequenza LFXT1CLK. Per avere una migliore  approssimazione della frequenza misurata la frequenza del clock ACLK viene ridotta internamente al microcontrollore prima di applicarla al segnale di capture del registro del timer. L’architettura  dell’MSP430 prevede la possibilità di collegare il segnale di ACLK direttamente al segnale di capture di un registro del timer.  Per conoscere questa configurazione si deve esaminare il datasheet del componente prescelto. In questa applicazione il segnale ACLK è stato diviso per 8 per ottenere la massima risoluzione possibile per il contatore per il calcolo della frequenza del DCO. La formula per ottenere la frequenza di oscillazione del DCO risulta pertanto:

321

Dove TimerN+1  e TimerN  rappresentano due letture successive del registro di capture del timer.

Nota  la frequenza del DCO si deve elaborare una procedura di taratura che consenta di raggiungere rapidamente il valore di frequenza desiderato fSET. L’algoritmo descritto in [1] utilizza una funzione denominata p-control che consiste nel modificare la frequenza dell’oscillatore con un valore proporzionale all’errore rilevato (fSET - fDCO). Questa procedura richiede l’esecuzione di una moltiplicazione (fattore di proporzionalità per errore misurato). Molte versioni dell’MSP430 integrano un moltiplicatore hardware che permette di eseguire rapidamente l’operazione. L’algoritmo proposto invece non utilizza moltiplicazioni ma semplicemente confronti ed è quindi utilizzabile anche per le versioni sprovviste del moltiplicatore hardware. Questa procedura, inoltre, esegue la scansione completa delle frequenze generate dall’oscillatore scegliendo poi quella che più si avvicina alla frequenza desiderata. La funzione di taratura si applica solo all’accensione per tarare il DCO. Come descritto in precedenza, le variazioni di temperatura e tensione di alimentazione variano la frequenza del DCO rispetto al punto di taratura raggiunto  inizialmente. Queste variazioni avvengono lentamente e possono essere compensate modificando la configurazione del modulatore per far rientrare  l’errore  fra la frequenza desiderata e quella misurata non rientra nel limite previsto. Perciò durante il normale funzionamento dell’applicazione, si devono effettuare misure periodiche della frequenza del DCO ed eventualmente modificare il registro DCOCTL per variare la configurazione del modulatore. Questo algoritmo di controllo è molto semplice e considera solamente il segno dell’errore fra frequenza attuale e frequenza desiderata del DCO.

DESCRIZIONE DELLE FUNZIONI

Funzione di taratura

La procedura di taratura seleziona la frequenza di oscillazione del DCO che minimizza l’errore assoluto |fSET - fDCO| tra la frequenza desiderata e la frequenza del DCO. Questa procedura, descritta nel diagramma di flusso in figura 4, viene eseguita all’accensione ed esegue la scansione di tutte le possibili frequenze generate dal DCO.

Figura 4. Diagramma di principio dell’algoritmo

Figura 4. Diagramma di principio dell’algoritmo

Un ciclo for esterno esegue la scansione di tutte le resistenze interne Rsel collegabili al DCO. Ogni ciclo definisce il range di oscillazione e le otto  frequenze base del DCO. All’interno  del ciclo, cioè per ogni valore di Rsel, si esegue una procedura suddivisa in tre passi modificando la configurazione del modulatore:

Il DCO viene configurato per oscillare alla frequenza limite inferiore dell’intervallo (DCOCTL=0). Questa frequenza viene confrontata con la frequenza desiderata e se la frequenza del DCO risulta superiore alla frequenza desiderata, quest’ultima non è compresa nell’intervallo selezionato ma risulta inferiore a tutte le frequenze dell’intervallo selezionato. Si deve quindi necessariamente modificare Rsel per selezionare un nuovo intervallo in cui effettuare la ricerca. Se la frequenza limite inferiore dell’intervallo selezionato risulta inferiore a quella cercata è necessario eseguire un nuovo confronto  con la frequenza limite  superiore dell’intervallo  (DCOCTL =0xE0) la frequenza limite superiore dell’intervallo non ammette modulazione.

In questo secondo confronto se la frequenza di oscillazione del DCO è inferiore alla frequenza desiderata allora la frequenza desiderata è superiore a tutte  le frequenze dell’intervallo e quindi si deve necessariamente  modificare  Rsel per  selezionare un  nuovo intervallo di ricerca. Se invece la frequenza desiderata è inferiore alla frequenza limite superiore allora la frequenza cercata è compresa nell’intervallo selezionato e si deve eseguire la ricerca all’interno dell’intervallo selezionato. Il terzo passo consiste nel cercare all’interno dell’intervallo prescelto la frequenza che meglio approssima la frequenza desiderata. La scansione si effettua con un algoritmo  di ricerca binaria modificando il valore  del  registro  DCOCTL partendo  dai  limiti 0x00..0xE0. Si confronta la frequenza centrale dell’intervallo con fSET  e si sposta il limite inferiore/superiore dell’intervallo  se la frequenza centrale risulta superiore/inferiore a fSET. L’algoritmo convergerà verso la frequenza che meglio approssima quella cercata. La ricerca binaria permette di limitare i confronti a log2   224 = 7,2 (224 sono i possibili valori per il registro DCOCTL).

Al termine di questa ricerca si confronta l’errore |fSET - fDCO| con il valore calcolato nella precedente approssimazione. Se l’errore risulta inferiore al valore precedente si memorizzano i valori di Rsel e del registro DCOCTL. Dopo aver ripetuto la ricerca per tutti gli 8 intervalli di frequenza la coppia Rsel DCOCTL  memorizzata è quella che meglio approssima la frequenza cercata fSET. Si osservi che per ogni intervallo di frequenza, o meglio per ogni possibile resistenza  Rsel che alimenta il DCO, si ottiene la migliore approssimazione possibile della frequenza cercata anche se quest’ultima  è esterna all’intervallo  selezionato. In questo caso l’algoritmo  convergerà necessariamente verso il valore massimo o minimo  dell’intervallo fornendo un’approssimazione probabilmente grossolana della frequenza desiderata.

PROCEDURA DI CONTROLLO

Questa procedura agisce principalmente sul modulatore del DCO per compensare le variazioni di frequenza dovute a variazioni di temperatura/tensione. La funzione di controllo dev’essere inserita nel ciclo di normale funzionamento dell’applicazione. La funzione utilizza l’interrupt  associato al segnale di capture del timer. Ad ogni interrupt viene valutata la differenza tra due successive letture del registro di capture. Periodicamente la funzione di controllo legge questa differenza e valuta l’errore rispetto alla frequenza desiderata. Se l’errore è troppo  elevato si interviene sul modulatore per compensare la variazione di frequenza. Il segno dell’errore determina la direzione dello spostamento, la correzione  si esegue finchè l’errore non rientra nei limiti previsti.

Realizzazione delle funzioni descritte

Nella descrizione precedente, per semplicità, sono stati omessi alcuni dettagli che invece sono necessari nella realizzazione delle funzioni.

Cambiando la configurazione del DCO si modifica la frequenza di conteggio del timer di controllo. Poiché la modifica della configurazione del DCO avviene in modo  asincrono rispetto  al segnale di  capture,  si deve attendere almeno tre interrupt  del segnale di capture prima di valutare la nuova frequenza. Nell’implementazione la variabile che determina questo ritardo è delayCCRx. Nella procedura di taratura, i limiti  ammessi per il registro DCOCTL sono inferiori ai limiti massimi pre- visti (0x00 e 0xE0). Questa scelta semplifica la succes- siva procedura di controllo periodico che modifica il registro DCOCTL. La procedura di controllo,  infatti, potrebbe far raggiungere al registro DCOCTL il valore massimo o minimo, ammessi. In  questo caso si dovrebbe selezionare un  nuovo valore per Rsel ed eseguire una nuova ricerca binaria sul  nuovo  intervallo  di  frequenze per  cercare la migliore approssimazione per fSET. Durante la procedura di taratura la variazione del registro DCOCTL potrà  avvenire solo tra (0x00+DCOSAFE) e (0xE0- DCOSAFE). L’algoritmo di controllo invece potrà raggiungere i limiti  estremi per il registro DCOCTL ed eventualmente procedere con una nuova ricerca binaria solo se questi limiti vengono superati.

TEMPI DI ESECUZIONE DELL’ALGORITMO

La procedura di taratura per ogni  intervallo di frequenze richiede i seguenti confronti:

  • Confronto con il limite minimo dell’intervallo selezionato;
  • Confronto con il limite massimo dell’intervallo selezionato;
  • Al massimo otto confronti per cercare la frequenza all’interno dell’intervallo selezionato.

In totale dieci confronti per otto intervalli di frequenza possibili cioè al massimo 80 confronti. Poiché è necessario attendere almeno tre interrupt di capture dopo ogni modifica del DCO per valutare la nuova frequenza sono necessari 80 * 3 = 240 interrupt di capture per effettuare la scansione completa delle frequenze del DCO. Se si utilizza un segnale ACLK a 32KHz quindi con un segnale di capture di 4KHz cioè un interrupt ogni 250ms  il tempo  massimo necessario per la taratura del DCO è di 60ms. In realtà il tempo è notevolmente inferiore poiché se la frequenza è esterna all’intervallo selezionato si effettuano solo i controlli  limite inferiore e superiore. Inoltre, per ottimizzare l’algoritmo, si può limitare la scansione degli intervalli di frequenza a quelli che includono sicuramente la frequenza cercata.

CONCLUSIONI

L’algoritmo  è stato applicato con successo a due microcontrollori  MSP430F149 e MSP430F1611. Le applicazioni realizzate non prevedono particolari stati di funzionamento in idle o power down mode. Il controllo della frequenza pertanto viene effettuato continuamente.

 

Bibliografia:

[1] A. Muehlhofer, “Controlling the DCO frequency of the MSP430x11x”, Texas Instruments applica- tion report slaa074.

[2] “MSP430x1xx      family     user    guide”,     Texas

Instruments user guide slau049e.

[3] “MSP430x161x  datasheet”,  Texas Instruments datasheet slas368d.

Listato codice:

// DCO adjust
#include "lxhw.h"

#define DCO_SET         2000         // DCO target frequency in KHz
#define RSELSET         4            // DOC internal R nominal frequency set 0.13 0.28 0.47
0.75 1.3 2.0 3.2 MHz
#define F_REF           32768/8      // ACLK/8
#define TCLK_DIV        1            // Timer A DCO frequency divisor

#define FSET            488          // (DCO_SET * 1000)/(F_REF * TCLK_DIV) //
(DCO_SET*1000)/TCLK_DIV --> TMRA clock
#define DFSET           10           // 2% FSET

#define DELAYCCRxSET     3          // 4KHz / 5 = 800Hz --> 1.2ms

#define DCOMAX           0xE0       // DCO set frequency max = 7
#define DCOMIN           0x00       // DCO set frequency min = 0
#define DCOSAFE          0x0A       // DCO set limit safe area

#define MAXRsel          0x07       // Rsel max
#define MINRsel          0x00       // Rsel min

// timer selection
#define DCOuseTMRA       0
#define DCOuseTMRB       1

#if DCOuseTMRA
#define TxCTL            TACTL
#define TxCCTL           TACCTL2
#define CCRx             TACCR2


#define CFGTxCTL         0x0204
#define CFGTxCCTL        0x5100
#endif

#if DCOuseTMRB
#define TxCTL            TBCTL
#define TxCCTL           TBCCTL6
#define CCRx             TBCCR6


#define CFGTxCTL         0x0204
#define CFGTxCCTL        0x5100
#endif


unsigned      lastCCRx ;               // Last captured value
unsigned      DCCRx ;                  // Difference between last two read

unsigned char delayCCRx ;              // Delay wait read timer

unsigned char DCOhi = DCOMAX-DCOSAFE ;  // only for calibrate DCO start value
unsigned char DCOlo = DCOMIN+DCOSAFE ;

unsigned char DCOflags ;
#define FDCOTask 0x01                 // 1 DCO task request

unsigned char DCOmode ;
#define MDCOidle             0x00    // Monitor DCO frequency monitor
#define MDCOlo               0x01    // Test DCO Rsel min
#define MDCOhi               0x02    // Test DCO Rsel max
#define MDCOset              0x03    // Find DCO freqeuncy in Rsel range
#define MDCOadj              0x04    // Adjust DCO frequency near set value
#define MDCOstart            0x05    // Init DCO calibration procedure

// interrupt routine

#if DCOuseTMRA
#pragma vector=TIMERA1_VECTOR
__interrupt void DCOfrequencyisr()
{

  if (TxCCTL & CCIFG)
  {
    TxCCTL &= ~CCIFG ;

    // Update DCCRx = SMCLK count between two ACLK/8 rising edges
    // Memo last captured value
    DCCRx = CCRx - lastCCRx ;
    lastCCRx = CCRx ;

    // Wait until delay CCRx expire
    // Count more than one time the SMCLK
    if (--delayCCRx == 0)
    {
      delayCCRx = DELAYCCRxSET ;
      DCOflags |= FDCOTask ;
    }
  }
}
#endif


#if DCOuseTMRB
#pragma vector=TIMERB1_VECTOR
__interrupt void DCOfrequencyisr()
{
  switch(TBIV)
  {
    case 0x0C:
//         TxCCTL &= ~CCIFG ;

        // Update DCCRx = SMCLK count between two ACLK/8 rising edges
        // Memo last captured value
        DCCRx = CCRx - lastCCRx ;
        lastCCRx = CCRx ;


       // Wait until delay CCRx expire
       // Count more than one time the SMCLK
       if (--delayCCRx == 0)
       {
         delayCCRx = DELAYCCRxSET ;
         DCOflags |= FDCOTask ;
        }
        break ;

     default: break ;
  }
}
#endif

void WriteRsel(unsigned char Rsel)
{

  unsigned tmpBCSCTL1 = BCSCTL1 ;

  tmpBCSCTL1 &= 0xF8 ; // Reset RSel bit
  tmpBCSCTL1 |= Rsel ;

  BCSCTL1 = tmpBCSCTL1 ;
}

void DCOfrequencyTask()
{
   unsigned char Rsel ;

   unsigned Error ;

   switch (DCOmode)
   {
     case MDCOstart:

           // Configure timers
           // ACLK/8 internaly connect CCI2B (Caputre timer signal)
           // TMRx free runnning count UP

           TxCCTL = CFGTxCCTL ;
           TxCTL = CFGTxCTL | 0x20 ; // start count


           // Configure DCO
           // Start with oscillator R = 4
           // DCO to min value (Lower frequency for this Rsel range)

           DCOCTL = DCOMIN+DCOSAFE ; delayCCRx = DELAYCCRxSET ;


           // Init DCO claibrate state machine

           DCOmode = MDCOlo ;
           break ;

     // Check the lower frequency range for select Rsel (DCO = min value)
     case MDCOlo:

           // IF SMCLK target >= SMCLK count can be the right range
           // check the upper limit
           if (FSET >= DCCRx)
           {
             DCOCTL = DCOMAX-DCOSAFE ; delayCCRx = DELAYCCRxSET ;

             DCOmode = MDCOhi ;
           }

          // IF SMCLK target < SMCLK count target frequency is out of range (lower side)
          // Must decrease Rsel
          else
          {
             DCOmode = MDCOidle ;
           }
           break ;

    // Check the upper frequency range for select Rsel (DCO = max value)
    case MDCOhi:

         // IF SMCLK target >= SMCLK count frequency is out of range (upper side)
         // Must increase Rsel
         if (FSET >= DCCRx)
         {
           DCOmode = MDCOidle ;
         }

        // IF SMCLK target < SMCLK count target frequency is in range
        // Select the middle point of freqeuncy rnage and check it
        else
        {
           DCOCTL = (DCOhi+DCOlo) >> 1 ; delayCCRx = DELAYCCRxSET ;
           DCOmode = MDCOset ;
        }
        break ;

       // Find near freqeuncy in the select range (Rsel fixed)
   case MDCOset:

         // IF SMCLK target == SMCLK Found exactly !!
         if (FSET == DCCRx)

         {
            DCOmode = MDCOidle ;
         }

         // Look at the upper half range
         else if (FSET > DCCRx)
         {
            DCOlo = DCOCTL+1 ;
         }

        // Look at the lower half range
        else
        {
           DCOhi = DCOCTL-1 ;
        }


        // if range >= 1 repeat search
        // Set DCO with the middle frequency point
        if (DCOhi > DCOlo)
        {
           DCOCTL = (DCOhi+DCOlo) >> 1 ; delayCCRx = DELAYCCRxSET ;
        }

       // if range = 0 assign nearest frequency
       else
       {
          DCOmode = MDCOidle ;
       }

       break ;

   // DCO frequency monitor
   case MDCOidle:

       // frequency set error
       Error = (FSET > DCCRx) ? (FSET - DCCRx) : (DCCRx - FSET) ;

      //if error over max set error adjust frequency
      if (Error > DFSET) DCOmode = MDCOadj ;
      break ;

  // If freqeuncy error > max error adjust frequency
  case MDCOadj:
       DCOmode = MDCOidle ;

       // FSET > DCCRx --> SMCLK < SMCLKset (frequency is low)
       if (FSET > DCCRx)
       {

          // change frequency without change Rsel
          if (DCOCTL < DCOMAX)
            DCOCTL++ ;
          else

            // check upper Rsel limit
            // ok can select another range
            // over end and restore idle mode
            Rsel = BCSCTL1 & 0x07 ;
            if (Rsel < MAXRsel)
            {
              WriteRsel(++Rsel) ;
              DCOmode = MDCOlo ;
           }
       }


      // FSET < DCCRx --> SMCLK > SMCLKset (frequency is high)
      if (FSET < DCCRx)
      {
        if (DCOCTL > DCOMIN)
          DCOCTL-- ;
        else

          // check lower Rsel limit

          // ok --> can select another range
          // under --> end and restore idle mode
          Rsel = BCSCTL1 & 0x07 ;
          if (Rsel > MINRsel)
          {
            WriteRsel(--Rsel) ;
            DCOmode = MDCOlo ;
         }
     }

     break ;

  default:
       DCOmode = MDCOidle ;
       break ;
  }

  DCOflags &= ~FDCOTask ;
}

void DCOfrequencyset()
{
   unsigned bestError = 0xFFFF ;
   unsigned Error ;

   unsigned char bestDCO ;
   unsigned char bestRsel ;

   unsigned char Rsel ;

   for (Rsel=MINRsel ; Rsel<=MAXRsel ; Rsel++)
   {
     WriteRsel (Rsel) ; DCOmode = MDCOstart ; DCOflags |= FDCOTask ;

     do
     {

        // Check capture interupt every 4.096KHz (ACLK/8)
        if (TxCCTL & CCIFG)
        {
          TxCCTL &= ~CCIFG ; // reset interrupt flag
          DCCRx = CCRx - lastCCRx ; // SMCLK periods in ACLK/8 period
          lastCCRx = CCRx ; // remember last capture value


          // Wait until delay CCRx expire
          // Count more than one time the SMCLK
          if (--delayCCRx == 0) DCOflags |= FDCOTask ;
        }

        if (DCOflags & FDCOTask) DCOfrequencyTask() ;
      }
      while (DCOmode != MDCOidle) ; // repeat until frequency found of out of range


     // calcualte frequency error
     Error = (FSET > DCCRx) ? (FSET - DCCRx) : (DCCRx - FSET) ; // abs value

     // remember best frequency cfg
     if (Error < bestError)
     {
        bestRsel = Rsel ;
        bestDCO = DCOCTL ;
        bestError = Error ;
      }
   } // loop for all Rsel

  // configure DCO with best frequency
  WriteRsel (bestRsel) ; DCOCTL = bestDCO ;
}

void DCOfrequencyadj()
{
   if (DCOflags & FDCOTask) DCOfrequencyTask() ;
}
// eof


4 Commenti

  1. cbuona 13 gennaio 2017
  2. Maurizio Di Paolo Emilio Maurizio Di Paolo Emilio 13 gennaio 2017

Scrivi un commento

ESPertino è la nuova scheda per IoT compatibile ARDUINO.
Scopri come averla GRATIS!