Problema interfacciamento SPI tra Arduino DUE e DAC esterno

Buongiorno a tutti!

Ho un problema riguardo la comunicazione SPI tra Arduino DUE e un DAC esterno ad elevata risoluzione (componente AD5570 http://www.analog.com/media/en/technical-documentation/data-sheets/AD5570.pdf Quello che mi piacerebbe fare sarebbe acquisire tramite il monitor seriale la tensione desiderata in uscita al DAC (ex. 100mV o 1V) e trasferirla al DAC tramite SPI dopo averla convertita in codifica binaria. Oltre a questo mi piacerebbe ottenere in uscita al DAC una rampa in tensione lenta.

Sto lavorando al codice ma ho problemi nella parte di selezione della tensione, conversione e conseguente comunicazione al DAC. Purtroppo non ho ancora disponibile il componente per poterlo testare, ma volevo portarmi avanti con il codice per capire al meglio come affrontare il problema. Ho trovato alcuni esempi sul web ma non ho capito del tutto come siano stati realizzati.

Per quanto riguarda i collegamenti, considerando il pinout del componente, pensavo di collegare:

5------PWM 10 arduino DUE; 6------SPI_SCK; 7------MOSI SPI; 8------MISO SPI; 9------DGND

Gli altri pin sarebbero collegati a I/O digitali della board.

Vi ringrazio in anticipo e mi scuso per il disturbo.

Giacomo

... ma prima di comprare una board ... li leggete i reference per capire le caratteristiche di cosa state comprando ?

Sulla DUE il bus SPI NON si trova sui pin come su Arduino UNO, ma SOLO sul connettore SPI a sei poli !

Ti rammento inoltre che la scheda funziona esclusivamente a 3.3V e molti dei suoi pin sono in grado di dare un decimo della corrente (max 3 mA) dei pin degli altri Arduino (max 40 mA). I rimanenti comunque non danno più di 15 mA.

Guglielmo

Buongiorno,

Forse mi sono spiegato male, ma i collegamenti li ho realizzati sul connettore SPI a sei poli eccetto il pin di sincronismo che è collegato al pin PWM 10 della board.

Giacomo

... perdona, ma ... non era assolutamente chiaro ::)

Quando chiedi spiegazioni/aiuto dai sempre il massimo delle informazioni (link ai prodotti, nome dei connettori usati, ecc.) perché noi ... non possiamo sapere cosa l'utente fa ;)

Guglielmo

Mi dispiace ed effettivamente è vero!

I numeri sulla sinistra si riferiscono ai pin del DAC mentre sulla destra ho riportato i corrispondenti pin della board. Cercherò di fornire le informazioni il più precisamente possibile, come penso di aver fatto per il mio problema.

Grazie e scusate ancora

Giacomo

... però resta poco chiaro cosa vuoi fare :)

... Quello che mi piacerebbe fare sarebbe acquisire tramite il monitor seriale la tensione desiderata in uscita al DAC (ex. 100mV o 1V) e trasferirla al DAC tramite SPI dopo averla convertita in codifica binaria. Oltre a questo mi piacerebbe ottenere in uscita al DAC una rampa in tensione lenta.

:o ... puoi spiegarlo meglio ?

Guglielmo

Forse sono stato poco chiaro anche in questo!
Il DAC mi serve per generare segnali da inviare ad un dispositivo. Ciò che vorrei ottenere sarebbe:

1-tensione continua in uscita al DAC (ex. 100mV, 1V) che possa essere scelta dall’utente, quindi l’utente sceglierà la tensione tramite il monitor seriale e questo valore deve essere trasferito al DAC come cofica binaria per generare il segnale desiderato;

2-rampa di tensione in uscita al DAC con pendenza regolabile dall’utente per realizzare una misura diversa dalla precedente. Quindi anche in questo caso il DAC genererà una rampa di tensione con “pendenza” specificata dall’utente o fissa.

Ho letto alcuni esempi online ma non credo di averli capiti…se dovesse esserci qualcos’altro di poco chiaro cercherò di chiarire al meglio il tutto. Spero anche di non aver sbagliato sezione.

Vi ringrazio ancora

Giacomo

ok ... molto più chiaro. Ancora una domanda, perché fai riferimento a PWM ? Per cosa ti occorre un segnale PWM ?

Chiarita quest'ultima cosa ... quali dubbi hai in generale ? Cosa c'è che non va nel tuo programma ?

Guglielmo

Il pin 10 in realtà è legato a comodità nella realizzazione del layout.
Per quanto riguarda il codice, non capisco come poter realizzare questo passaggio dalla selezione della tensione all’effettiva generazione da parte del DAC. Relativamente al primo punto del post precedente la bozza del codice implementato per ora è:

int DACR;
float DACR_MILLI;
long Din;                          //segnale in ingresso al DAC
String Din_Bin;                    //codifica binaria in ingresso al DAC
const int V_ref = 5;               //tensione di riferimento del DAC
const int tot_level = 65536;       //2^16 livelli in cui può essere suddivisa l'uscita
float millivolt = 0.001;           //conversione in millivolt


 if (Serial.available()!=0){
    DACR = Serial.parseInt() ;
    DACR_MILLI = DACR*millivolt;
    Serial.print("Voltage selected [mV]: ");
    Serial.println(DACR,DEC);
    Din = (DACR_MILLI/(4*V_ref) + 0.5)*tot_level;
    Din_Bin = Din_Bin + String(Din,BIN);          
    Serial.println(Din_Bin);                        
    delay(1000);
    
    
    digitalWrite(pinSYNC_DAC,LOW);                                   //comunicazione SPI tra Arduino e DAC
    SPI.transfer(pinSYNC_DAC, highByte(Din_Byte), SPI_CONTINUE);
    SPI.transfer(pinSYNC_DAC, lowByte(Din_Byte), SPI_LAST);
   digitalWrite(pinSYNC_DAC,HIGH);
  }
}

non so se questa sia la strada più semplice…la parte di codice che segue l’if pensavo di includerla in una funzione apposita che mi permetta di impostare il DAC prima della misura.
Relativamente al secondo punto non ho idea di come procedere per avere la rampa, ma forse è meglio concentrarsi su un problema alla volta.

Grazie per l’attenzione

Giacomo

... scusa, vedo che dichiari int, float, long, String ... a che servono tutti questi tipi dati ? ? ?

Quell'affare in ingresso vuole semplicemente 2 bytes ovvero un "unsigned int" che rappresenta il valore da generare dato appunto dalla formula che trovi nel datasheet a pag. 17 ovvero :

Vout = -2 * Vrefin + 4 * Vrefin * (unsigned_int / 65536)

Quindi ... leggi il valore dalla seriale, ti calcoli l'opportuno "unsigned int" e lo trasferisci al DAC. Perché mettere in mezzo la classe String ?

Guglielmo

Infatti pensavo ci fosse qualcosa che non andava, tenendo conto anche del fatto che highByte() e lowByte() non funzionano con un argomento di tipo String.
Il float è legato al fatto che io inserisco un numero da seriale, ma se questo valore lo volessi in millivolt e non in volt, dovrei moltiplicare il tutto per 0.001.

il concetto quindi è convertire il dato immesso da seriale in un unsigned int?

Giacomo

... da seriale accetta pure il valore in millivolt (... o in volt, come preferisci), poi, sapendo Vrefin (lo fissi tu) e Vout (valore letto dalla seriale) ti calcoli ... l'incognita (:D ... ovvero il valore intero non segnato) da trasmettere al DAC ;)

Guglielmo

Perfetto, quindi se ho capito bene il codice diventa più o meno così:

int DACR;
unsigned int Din;                  //codifica binaria in ingresso al DAC
const int V_ref = 5;               //tensione di riferimento del DAC
const int tot_level = 65536;       //2^16 livelli in cui può essere suddivisa l'uscita

if (Serial.available()!=0){
    DACR = Serial.parseInt() ;
    Serial.print("Voltage selected [mV]: ");
    Serial.println(DACR,DEC);
    Din = (DACR/(4*V_ref) + 0.5)*tot_level;         
    Serial.println(Din);                        
    delay(1000);
    
    
    digitalWrite(pinSYNC_DAC,LOW);                                   //comunicazione SPI tra Arduino e DAC
    SPI.transfer(pinSYNC_DAC, highByte(Din), SPI_CONTINUE);
    SPI.transfer(pinSYNC_DAC, lowByte(Din), SPI_LAST);
    digitalWrite(pinSYNC_DAC,HIGH);
  }

in questo modo il DAC mi dovrebbe fornire in uscità ciò che ho selezionato tramite la seriale?

… hai verificato se il valore che stampa la Serial.println() corrisponde al valore che ti aspetti ? Se SI … c’è da mettere solo a punto/verificare la comunicazione SPI … :wink:

Guglielmo

Con il codice che del messaggio precedente (al quale aggiungere il Serial.begin() nel Setup()) non ottengo buoni risultati. Infatti inserendo il valore "100" per esempio, mi aspetterei 1100100, che comunque è insufficiente da inviare al DAC. Invece il monito seriale stampa questo:

Voltage selected [mV]: 100 360448 Voltage selected [mV]: 200 688128

Cosa sto sbagliando?

Giacomo

Scusa, a me viene (chiamando X il valore da dare al DAC ed esprimendo tutti i valori in Volt) :

Vout = -2 * Vrefin + 4 * Vrefin * (X / 65536)

Vout + 2 * Vrefin = 4 * Vrefin * X / 65536

(Vout + 2 * Vrefin) * 65536 = 4 * Vrefin * X

((Vout + 2 * Vrefin) * 65536) / (4 * Vrefin) = X

... sbaglio io o tu hai scritto un'altra formula ? ::)

Guglielmo

const int tot_level = 65536;       //2^16 livelli in cui può essere suddivisa l'uscita

Non puoi assegnare a un int il valore 65536, ma nemmeno ad un insigned int visto che il valore massimo è 65535.

    Din = (DACR/(4*V_ref) + 0.5)*tot_level;

Anche questo calcolo è senza senso e porta a risultati bizzarri.

Buongiorno a tutti,
rieccomi qui con lo stesso problema di qualche giorno fa.

Ho ottenuto alcuni buoni risultati consultando il forum e la rete ma non completamente purtroppo.
Il codice è il seguente:

#include <SPI.h>

int DACR;
long Din;                          //Input signal 
const int V_ref = 5;              //reference voltage
long tot_level = 65536;           //2^16 of the output (16 bit DAC)

void setup() {
Serial.begin(115200);

}

void loop() {
  if (Serial.available()!=0){
    DACR = Serial.parseInt() ;
    Serial.print("Voltage selected: ");
    Serial.println(DACR,DEC);
    Din = ((DACR + 2* V_ref)*tot_level)/(4*V_ref);         
    Serial.println(Din);
    delay(1000);
    if(Din>=tot_level){
        Din=tot_level;}
    byte msg2=(byte)Din;
    byte msg1=(byte)(Din>>8);
    msg1=msg1 | 0b01010000;
    Serial.println(msg1,BIN);
    Serial.println(msg2,BIN);
   
    }
}

Tuttavia quello che ottengo sul monitor seriale è:

Voltage selected: 1
36044
10001100
11001100
Voltage selected: 2
39321
10011001
10011001
Voltage selected: 3
42598
10100110
1100110
Voltage selected: -1
29491
1110011
110011
Voltage selected: -2
26214
1100110
1100110

Ho sicuramente problemi con i numeri negativi ma non capisco come mai il valore “3” mi dia quel risultato.

Grazie per l’attenzione

Buongiorno,

Probabilmente ho sbagliato sezione nel forum. Sapreste indicarmi qual è la sezione corretta alla quale rivolgermi?

Grazie per l'attenzione