Forum: Mikrocontroller und Digitale Elektronik DAC LTC1257 / Probleme mit der Ansteuerung


von Mike G. (Firma: ixwyc) (balu1980)


Angehängte Dateien:

Lesenswert?

Moin,

ich verwende den DAC LTC1257 der über drei Ports angesteuert wird.
Mit dem Threads:

Beitrag "LTC1257 - Problem mit Ansteuerung (SPI)"
Beitrag "LTC1257 Low Level Routinen"

habe ich mich bereits auseinandergesetzt.

Irgendwie funktioniert das bei mir nicht wirklich.

Laut den Threads soll es darum gehen einen Sägezahn zu erzeugen.
Das funktioniert nicht wirklich bei mir.

Ich verwende den AT90CAN128 der extern über ein 16MHz Quarz getaktet
wird. Im Anhang befindet sich eine Ossidarstellung von der derzeitigen 
Funktion.

Hier noch der Auszug vom Quelltext:


//---------------------------------------------------------------------- 
-----------
// Digital Analog Wandler Initialisieren

#define DACOUT    PORTC
#define DACIN    PORTC

#define DACLOAD(LEVEL)  DACOUT = (LEVEL) ? (DACIN & ~_BV(PC0)):(DACIN | 
_BV(PC0))
#define DACCLK(LEVEL)  DACOUT = (LEVEL) ? (DACIN & ~_BV(PC1)):(DACIN | 
_BV(PC1))
#define DACDATA(LEVEL)  DACOUT = (LEVEL) ? (DACIN & ~_BV(PC2)):(DACIN | 
_BV(PC2))

#define LATCHTIMING  0xFF        /* spend some time to the latch  */

#define LEV_LOW    0
#define LEV_HIGH  1

inline void DAC_init(void);
inline void DAC_send(unsigned int data);

/*
 * Low level initialisation routine for LTC1257.
 */

inline void DAC_init(void)
{
  /* Initial port/pin state */
  DACCLK(LEV_LOW);        /* clock pin low -> idle  */
  DACLOAD(LEV_HIGH);        /* load pin high -> idle  */
}


//---------------------------------------------------------------------- 
-----------
// Wert an Digital Analog Wandler uebertragen

inline void DAC_send(unsigned int data)
{
  volatile unsigned char bitctr = 0;

  for(bitctr = 0; bitctr < 0x0C; bitctr++)
  {
    DACCLK(LEV_LOW);

    if (data & 0x800)      /* output MSB (bits [11..0]!)    */
       DACDATA(LEV_HIGH);
    else
       DACDATA(LEV_LOW);

    data <<= 1;        /* shift next bit to MSB    */

    DACCLK(LEV_HIGH);      /* -> await rising edge      */

    _delay_us(4);
  }

  DACCLK(LEV_LOW);        /* clock pin low -> idle    */
  DACLOAD(LEV_LOW);        /* load pulled low -> output    */

  for (bitctr = 0; bitctr < LATCHTIMING; bitctr++)
    ;

  DACLOAD(LEV_HIGH);        /* load pulled high -> idle    */
}


Gruß Mike

von Jörg X. (Gast)


Lesenswert?

- Hast du die Pins alle als Ausgang gschaltet?
- Arbeiten die DACLOAD, DAC_CLK etc. -Macros nicht invertiert (d.h. 
"DACDATA(LEV_LOW)" setzt den Pin)?
- Das LATCHTIMING solltest du, laut LTC-Datenblatt, ersetzen können 
durch
1
NOP();
2
NOP();
3
NOP();
4
// NOP() ist dabei sowas:
5
#define NOP() asm volatile ("nop\n\t")
- Evtl. muss du vor "DACCLOCK(LEV_HIGH)" noch mal warten 
(_delay_us(0.5), oder so)

- Der gepostete Code erzeugt GANZ sicher keinen Sägezahn ;)
- Poste noch mal:
 - was nicht geht
 - was du erwartest
 - welche Fehlermeldungen du bekommst

hth. Jörg

von Michael U. (amiga)


Lesenswert?

Hallo,

nur als Hinweis: Du kannst den LTC1257 auch an den Hardware-SPI hängen.
CPOL=1 war glaube ich passend. Allerdings müssen die Daten dann links 
bündig liegen, die ersten 4 Bit fallen dann "hinten" raus und mit /LOAD 
werden am Ende der 2 SPI Ausgaben die richtigen 12Bit übernimmen.

Gruß aus Berlin
Michael

von Mike (Gast)


Lesenswert?

Moin,

schonmal vielen dank für die Info.


- was nicht geht

        wenn ich mir den erzeugten Sägezahn auf dem Ossciloskop anschaue
        ist dieser wohl erkennbar, wird aber durch zahlreiche
        nebenschwingungen überlagert.

 - was du erwartest

         als Übung möchte ich erstmal das Projekt mit dem
         Sägezahn vollenden, um den Umgang mit diesem DAC zu lernen,
         anschließend möchte ich ein über den ADC Wandler eingelesenes
         Signal über den DAC ausgeben, ebenfalls zur Übung.


 - welche Fehlermeldungen du bekommst

         Ich verwende das AVR Studio 4 und zum programmieren einen
         AVR ISP MKII. Der Compiler gibt keine Fehlermeldung und keine
         Warnung aus.

Die Ports von dem µC (AT90CAN128) habe ich als Ausgang definiert mit

         DDRC = (1 << PC0) | (1 << PC1) | (1 << PC2);

Ich werde das morgen mit NOP() versuchen, habe heute Abend keine Zeit 
mehr.

Ob die Macros invertiert laufen weiß ich nicht, ich werde dieses mal mit
einer LED testen.

Den LTC1257 kann ich Hardwaretechnisch nicht an den SPI Port hängen,
da es sich bereits um eine fertige Platine handelt, die ich derzeitig
nicht mehr ändern kann.

MFG Mike

von Mike G. (Firma: ixwyc) (balu1980)


Angehängte Dateien:

Lesenswert?

Moin,

so, habe es hinbekommen, ich kann eine saubere Sägezahnspannung 
erzeugen.
Nur wie muß ich die vom ADC übergebenen Werte an den LTC1257 übergeben,
damit das Analog eingelesene Signal wieder dargestellt wird.

Bis jetzt habe ich aus dem ADC Wert eine Spannung berechnet mit 
folgender Formel:

Vin= ADC_Wert*Referenzspannung/1023

Gruß Mike

von Jörg X. (Gast)


Lesenswert?

Benutzt du den internen ADC?
Dann musst du die Werte 0-1023 auf 0-4095 abbilden (geht wohl am besten 
mit "ADC * 4" (oder ADC<<2 falls der Compiler das nicht rafft))...

von Mike G. (Firma: ixwyc) (balu1980)


Lesenswert?

Moin,

ja, ich verwende den internen ADC. Die Funktion ist auch gegeben, habe 
mit
einer fixen Spannung getestet. Bei 2,56V ergibt sich ein ADC Wert von 
1023,
und bei 0 V von 0.

Nun habe ich diesen Wert mit 4 multipliziert, aber das Signal am DAC ist
nicht annähernd das vom ADC.

Vielleicht hilft es weiter. ich möchte ein Audiosignal mit ~10khz 
Bandbreite
übertragen. vor dem ADC habe ich einen dementsprechenden Tiefpassfilter, 
den selbigen am Ausgang vom DAC. Das Eingangssignal am ADC verschiebe 
ich noch mit einer angelegten Spannung von 1V in den positiven 
Wertebereich.

Gruß Mike

von Jörg X. (Gast)


Lesenswert?

> Vielleicht hilft es weiter. ich möchte ein Audiosignal mit ~10khz
> Bandbreite übertragen.
Ich bin nicht so fit in der Theorie, aber das wird schwierig, der 
interne ADC macht nur max. 15kSpS (200kHz/13.5) bei voller Auflösung.

Das Übertragen ist ja nicht so kompliziert: einfach alle 1/10kHz 
Sekunden (Timer!) einen neuen Wert an den DAC schicken.

hth. Jörg

von Falk B. (falk)


Lesenswert?

@ Jörg X. (Gast)

>Das Übertragen ist ja nicht so kompliziert: einfach alle 1/10kHz
>Sekunden (Timer!) einen neuen Wert an den DAC schicken.

Oder noch besser per ADC-Complete Interrupt im Free Running mode.

MFG
Falk

von Mike G. (Firma: ixwyc) (balu1980)


Lesenswert?

Moin,

vielen dank für die prompten Antworten,

Der Free Running Modus wird doch mit dem Bit

ADCSRB |= (1 << ADTS0);

aktiviert, so habe ich es aus dem Datenblatt des AT90CAN128
verstanden. Nur wie greife ich dann auf das Bit zu, bzw. wie
erhalte ich die Daten vom Interrupt. Habe soetwas noch nie gemacht.

Den ADC spreche ich folgendermaßen an:

void ADC_init(void)
{
  // Kanal AD0 gewählt
  ADMUX = 0;

  // Interne Referenzspannung verwenden
  ADMUX |= (1 << REFS0) | (1 << REFS1) | (1 << ADLAR);

  // ADC aktivieren, Teilungsfaktor auf 128
  ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);

  // Free Running Modus aktiviert
-->  // ADCSRB |= (1 << ADTS0);         <-- (richtig ???)

  ADCSRA |= (1 << ADSC);

  // Eine ADC Wandlung zum Warmlaufen ohne den Wert zu übergeben
  while (ADCSRA & (1 << ADSC))
  {
    ;
  }
}

unsigned char ADC_read()
{
  ADCSRA |= (1<<ADSC);
  // eine Wandlung

    while ( ADCSRA & (1<<ADSC) )
  {
      ; // auf Abschluss der Konvertierung warten
    }

    return ADCW;
  // Wandlungsergebnisse zurückgeben
}

Gruß Mike

Gruß Mike

von Jack (Gast)


Lesenswert?

Hallo,

wenn man in einer Funktion auf einem Mikrocontroller was gerechnet hat, 
und dabei einen wert Analog ausgeben will, denn weist man den Wert dem 
PORT zu.
zb.
1
DDRC=0xff;
2
PORTC=Wert;
so, und wenn die Bits an den PINS fakeln denn kann man sie anhand einen 
DAC wieder herstellen
Frage:
1-ist das Richtig
2-Soll man beim Testen die Test Schaltung von dem DAC "die im Datenblatt 
als Test Circuit bezeichnet" aufbauen, reicht das "Erfahrung nach !!"

Danke im Voraus

mfg

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.