Monitoraggio del battito cardiaco fetale: il firmware

prototipo-fetal-monitor

Qualche tempo fa abbiamo iniziato a parlare dell'importanza del controllo periodico e del monitoraggio del battito cardiaco del feto. Da questo è scaturita l'idea di un progetto che abbiamo portato avanti grazie alla partnership con Infineon. L'hardware del nostro progetto Open Source è stato completamente documentato ma ciò che manca è la parte firmware, che oggi analizzeremo nel dettaglio descrivendo i moduli software al lavoro. Buona lettura.

Il nostro sistema di monitoraggio del battito fetale è semplice, a basso costo e molto efficace. Come vedrete, anche la documentazione lo dimostrerà dal momento che riusciremo senza alcuna difficoltà, a descrivere tutto in maniera immediata e completa.

Le potenzialità di questo sistema sono altissime e dal momento che abbiamo a che fare con un processore ARM0, esso può davvero dare del filo da torcere a tanti altri sistemi e tante altre schede basate su microcontrollore.

Forti di questo, abbiamo utilizzato l'ambiente di sviluppo DAVE per realizzare il progetto; DAVE ha permesso l'ottimizzazione del codice, aiutando molto nella preparazione del sistema.

Per completare il progetto è stato, infatti, fatto largo uso delle applicazioni di base che ci hanno permesso, in maniera anche abbastanza intuitiva, di progettare l'intero sistema in tempi rapidi.

Va segnalata, però, una limitazione che riguarda la memoria del processore: quando si utilizzano, infatti, le applicazioni di base per gestire le periferiche del processore, lo si fa tramite librerie generiche che, purtroppo, richiedono un massiccio utilizzo di memoria. Valutate quindi sempre il modo migliore per gestire le periferiche, relativamente alla vostra applicazione.

Per poter completare il tutto è stato necessario suddividere il sistema in moduli in maniera tale da poter modificare le caratteristiche adattandole all'hardware a disposizione.

A questo punto del progetto è stato necessario cominciare l'assegnazione dei pin dell'XMC2Go per poter realizzare le connessioni dei vari componenti al circuito. Ecco un immagine esplicativa:

(fai click sull'immagine per ingrandirla)
Come chiaramente si evince, ogni pin del processore può essere riallocato a seconda delle proprie esigenze, il che ci aiuta molto a rendere il nostro software indipendente dall'hardware. Questo potrebbe essere un vantaggio per un futuro ipotetico riposizionamento dei pin, dal momento che aumenta il grado di astrazione del sistema.

Stabilite le regole delle connessioni, si passa a lavorare sulla gestione dei moduli, un procedimento che può essere riassunto tramite l'utilizzo di un semplice diagramma:

Ciò che abbiamo visto nel diagramma deve, ovviamente, essere trasformato in codice; ed eccolo qui:

int main(void)
{
unsigned int a;

    DAVE_Init();            // Initialization of DAVE Apps

    /* Generate Load Event*/
    ADC004_GenerateLoadEvent(&ADC004_Handle0);
    UART001_WriteDataBytes(&UART001_Handle0,"HEARTBEAT ",9);

      /* set dello stato dei led */

    IO004_SetPin(IO004_Handle0);
    IO004_SetPin(IO004_Handle2);


    IO004_SetOutputValue(IO004_Handle0,0);
    IO004_SetOutputValue(IO004_Handle2,0);

    /* preparzione variabili di lavoro */
    Data_count=0;

      /* imposta il volume dell’auricolare */
    Hearphone_Volume(0,DW);

    while(1)
    {

        Key_Read();     // attesa funzione

       // Funzione arrivata :

         if (SELECT==1) Data_Loader();  // acquisisce i dati dall'A/D converter

        if (SELECT==2) Display_data(); // invia i dati sul BT

    }
    return 0;
}

Sostanzialmente si svolge tutto all'interno di un solo Main.

Come tutti sappiamo, ogni progetto in C si struttura all'interno di un modulo base nel quale il processore effettua le prime operazioni. Qui succedono diverse cose: viene definita la nostra macchina, inizializzate le variabili, assegnati eventuali valori costanti, identificate le periferiche e così via dicendo.

Finita questa parte, il programma inizia il suo vero e proprio ciclo di vita seguendo le istruzioni, condizionale o meno, fino a terminare.

In particolare, in questo caso, si è generato un ciclo infinito grazie alla condizione “While(1)”; il programma, dunque, rimarrà in loop fino a quando un evento specifico non “deciderà” altrimenti.

La variabile SELECT verrà utilizzata per chiamare ciascun modulo in base al suo valore, che varierà grazie a Key_Read().

unsigned int Key_Read()
{
unsigned int Press_time=0;

   if(IO004_ReadPin(IO004_Handle1)==0)
   {
       Delay(1000);

    while(IO004_ReadPin(IO004_Handle1)==0)
    {
        Blinker(1);
         Press_time++;
    }
   }

if(Press_time==1)
    {
     UART001_WriteDataBytes(&UART001_Handle0,"DATA_LOAD \n",11);
     IO004_SetOutputValue(IO004_Handle0,1); // led rosso ON

     SELECT=1;
    return(0);
    }

if(Press_time==2)
    {
     UART001_WriteDataBytes(&UART001_Handle0,"DISPLAY DATA \n",14);
     IO004_SetOutputValue(IO004_Handle0,1); // led rosso ON

      SELECT=2;
    return(0);
    }

if(Press_time==3)
    {
     
     //FUTURE MODULE TO CALL etc. etc.

     SELECT=3;
    return(0);
    }

return(0);
}

Poter gestire il sistema con un menù selezionabile tramite un solo pulsante (One Button Menu) è, in sintesi, quello che questa funzione permette di fare. Basandosi sulla valutazione del numero di pressioni del pulsante in un dato lasso di tempo sarà, infatti, possibile abilitare funzioni differenti.

Ma il sistema, il vero e proprio “cuore” di tutto, si basa sulla funzione di acquisizione, relativamente semplice. Essa rileva ed invia i dati al BLE113.

Quando Key_read() ha “finito”, il controllo viene rilasciato alle funzioni interessate, ovvero quelle che riportiamo qui di seguito:

/* Global Result Register ISR*/
void GlobalResultEvent(void)
{

    /* Read the Result Register*/

    ADC004_GetResult(&ADC004_Handle0, &Result);

    if(SELECT==1)

     {
        Media+=Result.Result;
         Samples+=1;

      if(Samples>=MEDIA_SAMPLES)
      {
       Media=Media/MEDIA_SAMPLES;

       AUDIO[Data_count]=(char)Media;
          Data_count=Data_count+1;        // contatori campioni da memorizzare

        Samples=0;                        // contatore campioni per media
     Media=0;                    // azzero variabile Media

                    if(Data_count>MAX_SAMPLE)
                                  {
                                  Data_count=0; // azzero conteggio bytes
                                  DATA_ACK=1;   // informo che e' terminata la lettura
                                  SELECT=0;
                                  Samples=0;
                                  }
      }
    }
}

La funzione, come il commento suggerisce, è abbastanza semplice perché si tratta di creare un registro di risultati. Il modulo è inserito in un timing di interrupt, sincronizzato con il  segnale di End Of Conversion del modulo A/D converter.

Per ciascun campione viene generato un interrupt ed il controllo passa a questa procedura che, caricato il valore del registro analogico, prima di memorizzarlo nel Buffer AUDIO[], lo sottopone ad un'operazione di media.

Questo ciclo si ripete fino a che non sono stati caricati tutti i valori determinati dalla MAX_SAMPLE, che indica il numero massimo di elementi che possono essere inseriti nel buffer.

La logica seguita per l'implementazione di questa routine è abbastanza semplice: la frequenza di campionamento del modulo A/D è stata calcolata per consentire la lettura di un segnale a bassissima frequenza (compreso cioè tra 0 e 10 Hz). Per questo, abbiamo impostato la frequenza del clock dell’A/D per ottenere un accesso alla funzione “GlobalResultEvent” all'incirca ogni 100 Hz.

È stato, quindi, applicato il Teorema del campionamento, che, come noto, dice: “La frequenza di campionamento di un segnale deve essere almeno il doppio della massima frequenza analogica da campionare”. In questo modo, il convertitore A/D può leggere “comodamente” i valori ammessi nell’intervallo di tempo stabilito.

Nel caso specifico è stata impostata una frequenza di campionamento pari a 50 kHz, così da non modificare troppo i parametri del configuratore del DAVE; vengono comunque effettuate delle medie di tali campionamenti (come specificato dalla costante MEDIA_SAMPLES) così da poter eventualmente ridurre “a piacimento” la quantità di letture da salvare nel nostro buffer AUDIO.

Focalizzando l'attenzione si nota che MEDIA_SAMPLES (impostato a 500 ma modificabile) memorizza un nuovo valore, ottenuto dal rapporto della somma dei valori letti e della quantità da leggere (la classica media aritmetica), nel buffer AUDIO.

Questo certamente porta a perdite di enormi quantità di campioni ma dato che il segnale si trova in quel range di frequenze, stiamo già abbondantemente sovra-campionando.

Infatti, questa operazione risulta sufficiente per la creazione di uno stream di dati contenenti valori mediati e più facili da interpretare.

Invio dei dati

Una volta che i dati sono stati ottenuti e raccolti, è il momento di inviarli al modulo BLE113.

Questa operazione viene implementata grazie ad una semplice routine, SEND_DATA(). L’invio avviene in modo asincrono, ovvero senza controlli di flusso; questo è sicuramente riduttivo, in termini di velocità, ma ha un aspetto positivo: semplifica le connessioni hardware per basse velocità di trasferimento.

Il modulo con cui stiamo lavorando, a dirla tutta, è molto semplice da implementare all'interno del sistema perché è Bluetooth 4 ed è dotato di funzionalità molto differenti dei normali moduli Bluetooth, uno tra tutti l’RN42.

Per poter rendere il progetto il più versatile possibile, abbiamo inserito anche una funzione di programmazione all'interno del nostro modulo; ciò è stato fatto per rendere il sistema già compatibile con eventuali impieghi futuri che lo richiedano. In questo caso, quindi, sarà possibile eventualmente sostituire il BLE113 ed utilizzare i dati BT standard.

Perché abbiamo scelto BLE113? Perché trattasi di un componente davvero notevole soprattutto dal punto di vista del risparmio energetico ma non solo: è dotato di caratteristiche ottime in termini di portata ed ha una libreria di applicativi estremamente ampia, oltre alla possibilità di programmare gli I/O come riteniamo più opportuno.

Il modulo viene venduto con un loader precaricato grazie al quale è possibile effettuare una connessione con un programmatore/debugger, “CC DEBUGGER” della Texas instruments (il core del modulo BLE) il che ci consente di caricare la libreria più adeguata al funzionamento come BRIDGE SERIALE (Cable replacement).

Sebbene semplice concettualmente, quest'operazione non è del tutto immediata in quanto il Bluetooth 4 utilizza un vero e proprio stack programmabile ove ogni campo del protocollo ha un significato ed un valore ben definiti.

In pratica, è necessario modificare gli script XML della libreria in maniera tale da renderla compatibile con la nostra applicazione, così da farlo riconoscere alle altre periferiche come device identificato secondo una tabella condivisa (le caratteristiche del BT4 che ci possono aiutare a capire come implementare le librerie sono state trattate in una rubrica dedicata).

Consigli sulla preparazione

Prima di rendere operativo il modulo BLE113, è necessario modificare le librerie relative al firmware dell’esempio del CABLE-REPLACEMENT ovvero è necessario modificare due files .XML che servono proprio a configurare le porte del modulo e le caratteristiche della classe del pacchetto nonché il nome della periferica.

Infatti nel file gatt.xml, presente nella cartella “cable_replacement”, va modificato il campo value con il nome del nostro progetto (possiamo chiamarlo HEART_MON o in qualunque altro modo)

 <characteristic uuid="2a00">
        <properties read="true" const="true" />
        <value>HEART_MON</value>
      </characteristic>

Dopo aver salvato il file sempre nella stessa cartella, è necessario aprire il secondo file di configurazione, Hardware.xml e modificare i parametri della seriale:

<?xml version="1.0" encoding="UTF-8" ?>
  
<hardware>
    <sleeposc enable="true" ppm="30" />
    <usb enable="false" />
    <sleep enable="false" />
    <txpower power="15" bias="5" />
    <script enable="true" />
    <usart channel="1" alternate="1"  baud="115200" endpoint="none" flow = "false"/>
    <port index="0" tristatemask="0" pull="down" />
    <port index="1" tristatemask="0" pull="down" />
    <port index="2" tristatemask="0" pull="down" />
</hardware>

L’aggiunta del parametro FLOW=”FALSE” permette al modulo di funzionare senza Handshake,

essendo la seriale dell’XMC2Go senza controlli di flusso.

Impostando i parametri “USART=1” e “ALTERNATE=1” si può selezionare la porta UART ed i relativi pin, come potete vedere direttamente dal manuale del modulo, TABELLA 3-PERIPHERIAL I/O PIN MAPPING).

ATTENZIONE: i files modificati devono essere salvati nella stessa cartella di origine.

Una volta pronti, si può passare alla fase di programmazione. Come fare a rendere tutto questo ancora più semplice? Utilizzando il programmer della Texas “CC Debugger”, dal momento che il flashing del firmware può avvenire nel modulo solo con questo tipo di dispositivo.

Utilizziamo il programma della Blue Giga BLE SW Update Tool.

Al momento, tramite uno sniffer per moduli BLE, si è riusciti a trasmettere ed a ricevere dati da e verso il BT, selezionata che fosse la funzione SEND_DATA.

Un consiglio utile a tutti quelli che si cimenteranno nella costruzione del modulo: è fortemente consigliato, per non dire necessario, acquistare anche il sistema di sviluppo della Texas Instruments (che è proprietaria delle librerie e del chip del BT).

E vista la natura Open Source di questo progetto, dal momento che si tratta di un “primo approccio” al monitoraggio fetale, abbiamo cercato di lasciare aperti i parametri del software in maniera tale che ogni miglioria o aggiunta o modifica possa essere inserita senza dover riscrivere interamente il codice.

Nella versione aggiornata del firmware, che trovate tra gli allegati, sono stati risolti tutti i problemi rilevati.

Sono state anche fatte diverse prove e ad oggi, mentre scriviamo, lo stream dei dati, sotto forma di caratteri ASCII, viene letto senza problemi da un iPhone (BLE utility per IPHONE).

Naturalmente restano aperte le porte per lo sviluppo dell'applicazione, per la quale bisogna lavorare sul modulo BLE per personalizzare le caratteristiche del protocollo e gli identificativi del prodotto e così via dicendo. Questi parametri servono per effettuare il riconoscimento ed inserire il dispositivo nelle tabelle server GATT del BLE.

Ed ora la parola a voi: cosa ne pensate?

Vi vengono in mente delle modifiche/migliorie da proporre per questo sistema?

ALLEGATI (per fare il download devi essere un utente registrato)

FetalHeart-Software

FetalHeart-Hardware

Scarica subito una copia gratis

4 Commenti

  1. Avatar photo gfranco78 10 Novembre 2014
    • Avatar photo Emanuele 10 Novembre 2014
  2. Avatar photo Gius_Res 10 Novembre 2014
    • Avatar photo Emanuele 10 Novembre 2014

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend