Oscilloscopio - progetto common per le vacanze

Ciao ragazzi,
Ho cominciato a lavorare sulla brutta copia di un oscilloscopio basato du arduino due (una scheda due perché ha molti vantaggi per questo progetto).

Cerco qualcuno interessato a svilupparlo in creative common per poi alla fine pubblicare un post su instructables.

Qualche d'uno è interessato a lavorarci?

Sto scrivendo da cellulare, poi vi posto il codice e lo schema.

Ciao a tutti.
Nicola aka Muplex

la libreria UTFT per far funzionale lo schermo è qui:

UTFT Library

il resto è allegato sotto.

Le modalità che per ora ho sviluppato sono:
Single : singola acquisizione alla pressione del tasto OK
Triggered: Triggherato in base al livello dell'encoder rotativo. alla pressione del tastino dell'encoder, si cambia la pendenza del triggher
live: acquisizioni in tempo reale.

la velocità di acquisizione che sono riuscito a raggiungere adesso è di circa 650 KHz con singolo canale, la quale diventa 350 KHz a doppio canale.

Facendo varie sperimentazioni, si riesce ad avere un ottima risoluzione di lettura reale, fino a 150 KHz del segnale entrante (non è malaccio per un inizio)

Le acquisizioni, sono nativamente a 12 bit, uno dei motivi per preferire la scheda DUE per questo progetto.

NOTA BENE: vista la scheda in uso, la massima tensione di entrata è 3.3 V. Non misurare tensioni maggiori!
Avrei un'idea di collegare diversi partitori a un interruttore rotativo per avere diverse possiblità di tensioni in ingresso, ma è uno sviluppo futuro (visto anche che per ora non possiedo un rotary switch :slight_smile: )

Attendo qualche commento, ci ho messo tanto impegno anche nel creare un codice più possibile pulito e leggibile =)

Il margine per migliorare è parecchio. Chi ha qualche idea può scriverla qua sotto. Se ci sono delle "adesioni" organizzo meglio un post riassuntivo.

Grazie a tutti per l'attenzione.

Oscilloscopy_ArduinoDUE.ino (17 KB)

Innanzitutto, complimenti per l'impegno.

Non mi offro come volontario e fido compagno di avventura, perchè non potrei garantire impegno e costanza, però seguirò volentieri e dove potrò e avrà senso, magari mi farò sentire.

Ho fatto una cosa molto rudimentale, tempo fa, per monitorare il debounce di un pulsante e per verificare il comportamento di un pin in input lasciato flottante, per vedere se si poteva veramente utilizzare per generare numeri casuali.
Ci dovrebbe essere ancora la discussione da qualche parte :wink:

Io sono riuscito a fare letture alla massima velocità possibile, pur usando la analogRead(), adottando il tuo stesso approccio, cioè scrivere dritto su un array e poi pensare al resto, per non frapporre nessuna elaborazione nel mezzo.
Tu hai bypassato la analogRead() e quindi dovresti aver raggiunto velocità maggiori rispetto alle mie.
Mi limito quindi ad un piccolo consiglio per cercare di limare ancora qualcosina.

void measureValues()
{
  timeValue = micros();
  for (int i = 0; i < nMeasuredValues; i++) {
    for (int j = 0; j < ChannelsMaxN; j++) {
      if (channelActive[j]) {
        while ((ADC->ADC_ISR & 0x80) == 0); // wait for conversion
        measuredValues[j][i] = ADC->ADC_CDR[7 - j]; //get values
      }
      else if (!channelActive[j]) {
        break;
      }
    }
    delayMicroseconds(TimeDiv);
  }
}

la

else if (!channelActive[j]) {

potrebbe essere sostituita direttamente da una

else

perchè è l'esatta negazione della condizione testata nell'IF, quindi non serve.

Poi, si potrebbe eliminare completamente l'IF all'interno del ciclo, perchè se tieni conto del numero di canali attivi in ChannelsMaxN o altra variabile, il secondo for si limiterebbe a ciclare unicamente sui canali attivi.
Quindi, potrebbe diventare:

void measureValues()
{
  timeValue = micros();
  for (int i = 0; i < nMeasuredValues; i++) {
    for (int j = 0; j < MAX_CANALI_ATTIVI; j++) {
      while ((ADC->ADC_ISR & 0x80) == 0); // wait for conversion
      measuredValues[j][i] = ADC->ADC_CDR[7 - j]; //get values
    }
    delayMicroseconds(TimeDiv);
  }
}

limando ancora qualcosina.

MAX_CANALI_ATTIVI sarà la variabile che indica quanti canali acquisire, non so se sia già quello che fa la ChannelsMaxN.

Ultima cosa, il problema di questo tipo di aggeggio, è la SRAM per la memorizzazione delle letture.
Più SRAM hai e più può essere larga la finestra temporale di acquisizione.
Più canali acquisisci e più questa finestra si restringe.
In definitiva, io non la gestirei in modo fisso, ma variabile, per poter sfruttare la finestra massima possibile.
Quindi, identificato l'ammontare di SRAM che posso sfruttare per memorizzare le letture, andrei a calcolarmi nMeasuredValues dividendo il totale per il numero di canali.

Anche io avevo adottato la lettura a trigger, appunto per il tempo limitato della finestra di acquisizione, però con un trucco.
Facevo letture sull'array, gestito in modo circolare, allo scattare del trigger, continuavo a leggere per un numero inferiore rispetto alla capienza massima dell'array, ad es. se potevo fare 100 letture, allo scattare del trigger ne facevo solo 80, in modo da avere nell'array anche le 20 letture precedenti al trigger.
In questo modo, potevo vedere ad es, il fronte di salita che mi portava a far scattare un trigger al superamento di una certa soglia.
Quindi attivata la modalità trigger, leggevo a raffica in modo continuo sovrascrivendo le letture ad ogni giro fino allo scattare del trigger.
Qui serve aggiungere una funzione di uscita dal trigger, magari una interrupt che setta un flag che testo ad ogni lettura.
Se lo testo ad ogni lettura, tutte le letture sono distanziate allo stesso modo, anche se si rallentano un pelino, se lo testo ogni tot letture, inserisco un delay (per il test della condizione di uscita) ogni tot letture.
E' da decidere se questo piccolo rallentamento una tantum può creare più danni che vantaggi.
Dipende dalla precisione dell'onda che si vuole monitorare.
A naso, direi che potrebbe essere ininfluente, perchè significa che sto cercando di beccare variazioni di tempi paragonabili alla frequenza di campionamento, quindi l'onda risulterà sempre e comunque distorta per raggiunti limiti di campionamento dello strumento di misura.

Per ora è tutto.
Mi siedo, prendo fiato, e mi godo il proseguimento del progetto :wink:
Maurizio

Ciao Muplex
Interessante il tuo progetto
Hai pensato ti creare un repository Github dove inserire il codice e poter collaborare?

Anche noi del gruppo Arduino di Pinerolo (To) ci stiamo interessando sulla possibilità di realizzare dei DSO in ambiente Arduino

Ti elenco alcuni progetti di Oscilloscopi che stiamo analizzando da cui prendere spunto

Girino
Questo progetto acquisisce i dati con un Arduino Uno e poi usa un PC per la rappresentazione grafica.
E' interessante la parte di articolo dove spiega come gestire il segnale in ingresso

Ho trovato alcuni esempi che utilizzano gli ARM di STM (invece di Atmel/Microchip) e la board STM32F103duino

Come Hardware valuterei anche i SAMD21 tipo Arduino- MKR Zero

Gio

Io ho realizzato il progettino su STM32 ma lo sketch l'ho preso dal forum STM32duino dove sono partiti dall'STM32-O-Scope e sono andati un po' avanti.
Fa uso del DMA per l'acquisizione, se non ricordo male.

Ciao e grazie per le vostre risposte.

Sto proprio pensando di creare una repo di GitHub (prima volta) e mi rendo conto che l'argomento trattato è uno dei più vasti e interessanti di Arduino perchè prende dentro un po' tutto.

Comunque volevo condividere la prima versione dell'oscilloscopio.
L'ho migliorato e adesso campiona a 1 Msaps con una buona risoluzione delle onde fino a 250 Ksaps reali (relazione di nyquist).

Sto lavorando a una nuova veste grafica e a complicare parecchio i menù.

Posto ogni update e vi faccio sapere se metto su la Repo.

Grazie a tutti,
saluti,
Nicola.

Oscilloscopy_Due_FAST_REV1.ino (17.4 KB)