Baud detection con dsPIC30F

La selezione del baud rate dell’UART di un microcontrollore è generalmente eseguita nella fase di inizializzazione, ma nel caso in cui il baud rate dei dati in arrivo non sia noto a priori, oppure la sorgente del clock del micro non sia sufficientemente precisa (ad esempio se generata tramite un oscillatore RC), sarà necessario utilizzare un metodo di Automatic Baud detection, brevemente detto Auto Baud.

I  microcontrollori delle famiglie dsPIC30F e 33F sono dotati di UART con supporto per l’Auto Baud: quando in un dsPIC si abilita la procedura di Auto Baud, il segnale presente  sul pin RX dell’UART viene connesso internamente ad uno dei moduli di Input Capture, così da permettere la misura dei tempi intercorrenti tra i fronti del segnale stesso. Tuttavia necessitiamo di un software appositamente sviluppato per calcolare il baud rate corretto. Nel seguito dell’articolo saranno illustrati due metodi per il calcolo, tratti dalla AN962 di Microchip. Tali metodi, sebbene implementati su un dsPIC30F, sono utilizzabili con le dovute modifiche anche su altri microcontrollori.

Metodi  di Automatic Baud Detection

Per poter eseguire la procedura di Auto Baud, è necessario che il mittente usi un protocollo di comunicazione che preveda l’invio di un dato noto a priori prima di effettuare la trasmissione dei dati utili. Generalmente è utilizzata a questo scopo la lettera ‘U’ (01010101 in binario) poiché presenta il massimo numero di fronti di salita e discesa, permettendo così di ottenere la maggiore precisione nel calcolo del baud rate. In figura 1 è rappresentato  il segnale ricevuto dall’UART del dsPIC: il fronte di discesa all’istante t0  segnala  il bit di Start, seguono quindi gli 8 bit di dati (lsb first, per cui avremo la successione 10101010), ed infine il bit di Stop all’istante t9.

Figura 1: segnale per la procedura di Auto Baud ricevuto dall’UART.

Figura 1: segnale per la procedura di Auto Baud ricevuto dall’UART.

La procedura di Auto Baud si occuperà di misurare  i tempi in cui avvengono  i fronti di salita e discesa in modo da determinare, come vedremo, il valore da immettere nel registro del Baud Rate generator, UxBRG. Il  baud rate dell’UART di un dsPIC viene calcolato tramite la formula seguente:

dove Fcy è la frequenza di ciclo, pari a ¼ della Frequenza di clock del micro, Fosc. Quindi, il valore da immettere nel registro UxBRG, una volta determinato il baud rate, sarà pari a

Eq 1

Vedremo ora due algoritmi utilizzabili per calcolare il  baud rate del segnale ricevuto.

Algoritmo  di approssimazione semplice

Questo algoritmo deriva il valore da immettere nel registro UxBRG come segue: viene innanzitutto calcolato il bit time misurando il tempo che intercorre tra la ricezione del bit di start e quella del bit b7

In realtà il micro misura  il tempo contando (tramite un timer) il numero di impulsi nx, alla frequenza di ciclo Fcy, che intercorrono tra i fronti, per cui possiamo riscrivere l’equazione precedente come:

 

dato che il bit time non è altro che l’inverso del baud rate, possiamo sostituire questa equazione nella eq.1, ottenendo

Eq. 2

La scelta di t8  come tempo finale semplifica i calcoli, poiché la divisione per 128 viene effettuata con un semplice shift. Osserviamo come dalla formula sia scomparso il termine Fcy, ragione per cui l’algoritmo di Auto baud, come già detto, può essere usato anche quando la frequenza di clock non sia nota con esattezza, o sia comunque soggetta a drift, come nel caso dell’oscillatore interno RC del dsPIC. Questo algoritmo richiede poche risorse computazionali per essere eseguito e fornisce generalmente dei buoni risultati. Un metodo molto simile viene usato in alcuni PIC, come il PIC18F2550,  dotati di capacità Auto Baud, implementate, data la semplicità, in hardware. In aggiunta è possibile implementare un semplice controllo di errore basato sul time-out: questo si verifica se il tempo tra due fronti successivi è eccessivo, indice di un errore di comunicazione.

Algoritmo  di regressione lineare

Un secondo metodo per il calcolo del baud rate, più preciso del precedente, utilizza la tecnica della regressione lineare. Si tratta di una tecnica di smoothing, meglio nota come retta dei minimi quadrati, usata per determinare la linea che approssima maggiormente un insieme di punti. Si consulti eventualmente un qualsiasi testo di Calcolo Numerico per chiarimenti. Nel nostro caso abbiamo a disposizione 10 misurazioni (x0, y0), (x1, y1),...(x9, y9). La pendenza m della retta dei minimi quadrati passante per i punti suddetti, sarà allora (usiamo una notazione semplificata per non appesantire troppo l’esposizione):

sostituiamo xi   con 0, 1,...9 ed yi   con i tempi misurati t0, t1,...t9. Osserviamo che se disponessimo di due sole misurazioni t0   e t8, riotterremmo la stessa formula dell’approssimazione semplice. Notiamo inoltre che t0=0, ed otteniamo la formula seguente

la pendenza m della retta non è altro che il bit time, e ricordando che il micro misura il tempo contando il numero di impulsi nx, alla frequenza di ciclo Fcy, che intercorrono tra i fronti, possiamo riscrivere l’eq. precedente come:

Dato che il bit time è l’inverso del baud rate, possiamo sostituire questa equazione nella eq.1, ottenendo:

Eq.3

È possibile implementare un controllo di errore più sofisticato, oltre al semplice controllo del time-out, in grado di determinare se il  pattern ricevuto è diverso da quello atteso. Un metodo statistico, computazionalmente non troppo esigente, è quello della media del valore assoluto dell’errore, determinato dalla formula seguente:

dove n è il numero totale di campioni, ti  è il tempo misurato per il fronte i, mentre t’i è il tempo atteso. Il  calcolo del tempo atteso richiede di conoscere la pendenza della retta m ed i tempi misurati, resi già disponibili dall’algoritmo di regressione lineare. Per i particolari si veda il listato 2.

Implementazione dell’Auto  Baud per i dsPIC

Il codice allegato all’AN962 è stato sviluppato con il compilatore C30 di Microchip. Si ipotizza una Fcy di 29491200 Hz, corrispondente ad una velocità di clock di 117964800 Hz. Nella funzione principale main() viene richiamata la funzione SetupAutoBaud() la quale si occupa di effettuare le necessarie inizializzazioni delle periferiche usate dalla procedura di Auto Baud. Un valore diverso da zero del registro U1BRG segnala l’avvenuto setup dell’UART. Viene quindi trasmesso tramite l’UART stessa, al solo scopo di test, il baud rate calcolato. Il tutto in un loop infinito. La funzione SetupAutoBaud() inizializza le periferiche UART1, il  modulo di Input Capture 1 ed il  Timer 3. È necessario abilitare l’opzione di auto baud dell’UART1 settando il bit U1MODE<ABAUD>. Il modulo Input Capture 1 (IC1) utilizza il Timer 3 per il conteggio degli impulsi tra un fronte del segnale ed il successivo.  Il Timer 3 è settato per incrementarsi ad ogni Tcy in modo da ottenere la massima risoluzione possibile. Infine viene abilitato l’interrupt di IC1.

Routine  di interrupt

Sono usate due routine di interrupt: una per l’input Capture 1 e l’altra per il Timer 3. La routine di interrupt per IC1, associata al vettore di interrupt _IC1Interrupt, viene invocata ad ogni fronte del segnale ricevuto dall’UART. La routine inizia salvando il tempo del fronte precedente e leggendo  il tempo del fronte attuale dal registro IC1BUF,  il cui valore è incrementato dal Timer3. Alla prima invocazione dell’interrupt vengono inizializzate le variabili per il calcolo del baud rate e viene attivato anche l’interrupt del Timer 3. La routine di interrupt del Timer 3 viene usata per controllare un eventuale time out tra un fronte ed il successivo: se la distanza temporale fra essi è tale da causare due volte il rollover del timer, la procedura di Auto Baud viene iniziata nuovamente. Poiché il rollover avviene ogni 1/457s a 30 Mips, tale metodo è valido fino ad un baud rate minimo di 600 baud. Ad ogni interrupt di IC1 il tempo del fronte attuale viene sottratto a quello precedente per determinare  il bit time. Il resto della procedura è differente nel caso dell’approssimazione semplice o della regressione lineare. Nel caso dell’approssimazione semplice (si veda il flow chart in figura 2), il bit time è aggiunto a un totale parziale finché non si arriva al fronte t8.

Figura 2: flow chart della ISR di IC1 - Approssimazione semplice.

Figura 2: flow chart della ISR di IC1 - Approssimazione semplice.

All’arrivo del decimo fronte t9, viene effettuato il calcolo del valore da immettere nel registro U1BRG secondo l’eq.2. Prima di effettuare la divisione per 128 si effettua un arrotondamento per eccesso aggiungendo 64 (vale a dire ½ cifra) al totale. La divisione per 128 viene eseguita tramite uno shift a destra di 7 posizioni. Nel caso della regressione  lineare (si veda il flow chart in figura 3), invece, ogni bit time viene aggiunto al precedente e memorizzato come elemento successivo in un array in modo da essere utilizzato per i calcoli seguenti.

Figura 3: flow chart ISR di IC1 - Regressione lineare.

Figura 3: flow chart ISR di IC1 - Regressione lineare.

Le somme parziali dell’algoritmo di regressione lineare sono calcolate nella routine di interrupt ad ogni fronte ricevuto, mentre il calcolo finale della pendenza della retta e quindi del valore di U1BRG vengono eseguiti alla ricezione del decimo fronte (dalla funzione CalculateBaud()). La funzione CalculateBaud() si occupa anche del calcolo dell’errore secondo il metodo della media del valore assoluto. In particolare, se l’errore risulta superiore al 5% del tempo totale (equivale a ½ bit time), la procedura di Auto Baud viene iniziata daccapo. Lo svantaggio nell’uso della procedura di calcolo dell’errore, consiste nel fatto che i calcoli più complessi vanno eseguiti dopo la ricezione dell’ultimo fronte, diminuendo così il tempo disponibile per gli stessi, dato che devono terminare prima della ricezione dei dati utili da parte dell’UART. In entrambi i casi, infine, si disabilitano gli interrupt di IC1 e del Timer 3 e si abilita l’UART con il baud rate corretto. Nel listato 1 è riportato il codice della ISR di IC1 nel caso dell’approssimazione semplice, mentre nel listato 2 sono riportati il codice della ISR di IC1 e della funzione CalculateBaud() usati per la regressione lineare.

void _ISR _IC1Interrupt(void)
{
     IFS0bits.IC1IF = 0;
     PreviousCapture = CurrentCapture;
     CurrentCapture = IC1BUF;
     T3Count = 0;
     if(ICCount == 0) // se e’ la prima volta
     {
        IFS0bits.T3IF = 0;
        IEC0bits.T3IE = 1;
        SumOfBitTimes = 0;
     }
     else
    {
        if(ICCount != 9)
        {
             CaptureDifference = CurrentCapture - PreviousCapture;
             SumOfBitTimes += CaptureDifference;
         }
         else // ultimo fronte
         {
             IEC0bits.IC1IE = 0;
             IEC0bits.T3IE = 0;
             // calcola U1BRG e setta l’UART
             U1BRG = ((SumOfBitTimes + 64) >> 7) - 1;
             U1MODE = 0x8000;
             U1STA = 0x0400;
        }
    }
    ICCount++;
}
Listato 1: ISR di IC1 - Approssimazione semplice
void _ISR _IC1Interrupt(void)
{
  IFS0bits.IC1IF = 0;
  PreviousCapture = CurrentCapture;
  CurrentCapture = IC1BUF;
  T3Count = 0;
  if(ICCount == 0) // se e’ la prima volta
  {
   IFS0bits.T3IF = 0;
   IEC0bits.T3IE = 1;
   RegressionData[0] = 0;
   SumY = 0;
   SumXY = 0;
  }
  else
  {
   CaptureDifference = CurrentCapture - PreviousCapture;
   RegressionData[ICCount] = RegressionData[ICCount-1] + CaptureDifference;
   SumY += RegressionData[ICCount];
   SumXY += RegressionData[ICCount] * ICCount;
  }
  ICCount++;
  if(ICCount == 10) // ultimo fronte
  {
   IEC0bits.IC1IE = 0;
   IEC0bits.T3IE = 0;
   // calcolo baud rate e controllo errore
   CalculateBaud();
  }
}
void CalculateBaud(void)
{
  int i;
  long Slope;
  long Yintercept;
  long PlotLine;
  long SumOfErrors = 0;
  // calcola la pendenza della retta
  Slope = (2 * SumXY - 9 * SumY) / 165;
  // stima t’0 per il calcolo dell’errore
  Yintercept = (SumY - Slope * 45) / 10;
  // calcola l’errore
  PlotLine = Yintercept;
  for(i=0; i<10; i++)
  {
  SumOfErrors += abs(RegressionData[i] - PlotLine);
  PlotLine += Slope;
  }
  if((SumOfErrors * 2) < Slope) //se errore <5%
  {
  //Calcola U1BRG con arrotondamento
  U1BRG = ((Slope + 8) >> 4) - 1;
  U1MODE = 0x8000;
  U1STA = 0x0400;
  }
  else //se errore >5%
  {
  SetupAutoBaud();
 }
}
Listato 2: ISR di IC1 e funzione CalculateBaud() - Regressione lineare

In figura 4 è riportato un esempio di simulazione della procedura di Auto Baud (regressione lineare) in MPLAB.

Figura 4: simulazione della procedura di Auto Baud in MPLAB.

Figura 4: simulazione della procedura
di Auto Baud in MPLAB.

Conclusioni

I due metodi illustrati permettono di calcolare il baud rate con una precisione sufficiente nella maggior parte dei casi. Il metodo di approssimazione semplice è poco oneroso in termini di risorse di calcolo e sufficiente nel caso in cui la velocità di trasmissione dei dati della sorgente sia stabile. Il  metodo della regressione lineare è molto più preciso e tollerante agli errori: richiede però una capacità di calcolo notevole non sempre disponibile in tutte le applicazioni. È pertanto consigliabile in quei casi in cui la sorgente di clock della sorgente e/o del dsPIC non sia particolarmente precisa e stabile.

 

Scrivi un commento

EOS-Academy
EOS-Academy