Forum: Mikrocontroller und Digitale Elektronik Digitales Potentiometer (Poti) AD8400 erwartet 10bit von ATMEGA128 über SPI


von Fabian (Gast)


Angehängte Dateien:

Lesenswert?

Liebe Forenleser und uC-Anwender

Habe eine Frage betreffend Digitalem Potentiometer von Analog Device 
(AD8400) und ATMEGA 128.
Der ATMEGA128 läuft mit einem clock von 16Mhz und ist auf einem Display 
3000 2.1" montiert.
(Link Display 3000: http://www.display3000.com/)

Das Problem sieht wie folgt aus:

Der Digitale Potentiometer von Analog Device (AD8400) erwartet eine 
10bit-Nachricht um den Poti einzustellen.
(Link zu AD8400: 
http://www.analog.com/en/digital-to-analog-converters/digital-potentiometers/ad8400/products/product.html)
Die ersten 2bits definieren die Adresse des RDAC-Speicher und da es nur 
einen einzigen gibt also folgendermassen A1=A0=0.
Alle nächsten 8bits (von der 10bit Nachricht) sind die Einstellungswerte 
von 0-255.
Programmiert wird der AD8400 über SPI, zu finden auf dem ATMEL 128 bei 
den Pins CLK (PB1), SS (PB0) und MOSI (PB2).
Da aber der SPI nur eine 8bit-Nachricht (SPSR) ausgeben kann, habe ich 
die Nachricht in 2x8bit aufgeteilt.
In der ersten 8bit-Nachricht sind lauter NULLEN und in der 
2ten-8bit-Nachricht der einzustellende Wert.
Leider übernimmt mir der Digitale Potentiometer die Einstellungen nicht 
und ich weiss nicht wieso.
Hat jemand von euch eine Idee oder einen anderen Lösungsvorschlag?

------------------code---------------------
#include <avr/io.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdlib.h>

/**************************/
// Variablen
/**************************/

unsigned char poti_init = 0; //
unsigned char poti_adress = 0b00;//0 in 8Bit
//unsigned char poti_data = 0b11001100;//127 in 8Bit
//unsigned char poti_adress = 0;//0 in 8Bit
unsigned char poti_data = 25; //127 in 8Bit


void SPI_MasterInit(void)
{
  /*Set SS(PB0), SCK(PB1) and MOSI(PB2) output, all others input */
  DDRB = (1<<DDB0) | (1<<DDB1) | (1<<DDB2);

  /*Enable SPI, Data Order, Master Select, set clock rate fck/16 */
  SPCR = (1<<SPE) | (1<<DORD) | (1<<MSTR);


}

void SPI_MasterTransmitDelete(unsigned char poti_init)
{
  //PORTB |= (1<<PB0); // CS (oder SS hier bei ATMEG128) auf High setzen
  PORTB &= ~ (1<<PB0); // CS (oder SS hier bei ATMEG128) auf Low setzen
  /*---------------------*/
  /*Start 1. transmission*/
  SPDR = poti_init;
  /*Wait for 1. transmission complete*/
  while (!(SPSR & (1<<SPIF)))
    {
    ;
  }
  /*1. transmission finished*/

  //PORTB |= (1<<PB0); // CS (oder SS hier bei ATMEG128) auf High setzen
  //PORTB &= ~ (1<<PB0); // CS (oder SS hier bei ATMEG128) auf Low 
setzen
  /*---------------------*/
  /*Start 2. transmission*/
  SPDR = poti_init;
  /*Wait for 2. transmission complete*/
  while (!(SPSR & (1<<SPIF)))
    {
    ;
  }
  /*2. transmission finished*/
  /*---------------------*/
  /*Start 3. transmission*/
  SPDR = poti_init;
  /*Wait for 3. transmission complete*/
  while (!(SPSR & (1<<SPIF)))
    {
    ;
  }
  /*3. transmission finished*/
  /*---------------------*/
  PORTB |= (1<<PB0); // CS (oder SS hier bei ATMEG128) auf High setzen
  //PORTB &= ~ (1<<PB0); // CS (oder SS hier bei ATMEG128) auf Low 
setzen
}

void SPI_MasterTransmit(unsigned char poti_adress, unsigned char 
poti_data)
{
  //PORTB |= (1<<PB0); // CS (oder SS hier bei ATMEG128) auf High setzen
  PORTB &= ~ (1<<PB0); // CS (oder SS hier bei ATMEG128) auf Low setzen

  /*Start transmission*/
  //SPDR = poti_adress;

  /*Wait for transmission complete*/
  /*while (!(SPSR & (1<<SPIF)))
    {
    ;
  }*/
  //PORTB |= (1<<PB0); // CS (oder SS hier bei ATMEG128) auf High setzen

  //PORTB &= ~ (1<<PB0); // CS (oder SS hier bei ATMEG128) auf Low 
setzen

  SPDR = poti_data;
  while (!(SPSR & (1<<SPIF)))
    {
    ;
  }

  PORTB |= (1<<PB0); // CS (oder SS hier bei ATMEG128) auf High setzen
  //PORTB &= ~ (1<<PB0); // CS (oder SS hier bei ATMEG128) auf Low 
setzen
}

int main(void)
{
  SPI_MasterInit();
  //SPI_MasterTransmitDelete(poti_init);
  //_delay_ms(1);
  //sei();
  SPI_MasterTransmitDelete(poti_init);
  _delay_ms(2000);
  SPI_MasterTransmit(poti_adress, poti_data);

  /*while(1){

  _delay_ms(10);
  }*/
  return 0;
}
------------------code---------------------

von Christian R. (supachris)


Lesenswert?

Das wird so nicht klappen, weil du ja innerhalb der 1. Schreiboperation 
das CS bedienen müsstest. Du müsstest entweder eine Software-SPI 
realisieren, oder 8 Bit schicken, dann die ports auf normale I/O 
umschalten und noch 2 Bits manuell hinterher klappern.

von Fabian (Gast)


Lesenswert?

Hallo Christian

Danke für die Infos.

Verstehe jedoch deine erste Bemerkung nicht ganz oder interpretiere sie 
falsch: "Das wird so nicht klappen, weil du ja innerhalb der 1. 
Schreiboperation das CS bedienen müsstest."

Über die 2. Idee hatte ich bereits nachgedacht, würde dies jedoch anders 
realisieren.
Ich würde die ersten 2bit (A1=A0=0) über GPIO senden.
Danach das SPI "Enablen" und die 8bit Daten über SPI senden.
Dies bedeutet jedoch die ganzen Signale (clock, CS, Data) 
Softwaretechnisch zu realisieren, was nach meinem Wissensstand (Bin 
nicht der Profiprogrammierer!) zeitaufwändig wäre.

Die andere Variante (1. Variante) mit der Software-SPI hört sich 
verlockend an.
Wie müsste ich dies realisieren oder könntest du mir einen Anhaltspunkt 
(Buch, Website, Link) angeben?

von Matthias L. (Gast)


Lesenswert?

So wie ich Datenblatt verstanden habe, ist das ein echtes SPI.

Das heißt:
Du kannst soviel Bits da durch schieben, wie du willst. Sobald das CS 
auch HIGH geht, sind die letzten 10Bits gültig. Das ist SPI.

Also muss es gehen, wenn du:

- CS auf LOW legst,
- zwei Addressbits als unteren zwei von acht Bit ausgibst (MSB first),
- acht Datenbits ausgibst (MSB fisrt),
- CS auf HIGH ziehst.

Dann muss das laut SPI gehen.

von Christian R. (supachris)


Lesenswert?

Steht leider nicht so eindeutig im Datenblatt. So wie ich sein erstes 
Posting verstehe, macht er das ja schon so, aber der Chip reagiert 
nicht.

von Matthias L. (Gast)


Lesenswert?

Naja, aus den Ausführungen unter "digital Interface" (Seite21) würde ich 
das aber so herauslesen.

von Ralph (Gast)


Lesenswert?

Les mal im Datenblatt deines Atmel.

Viele µC, ich weiß nicht ob es dein Atmel auch kann, können auch auf 
exotische Bitzahlen auf der SPI eingestellt werden. Es lässt sich dort 
also einstellen das zb 10 Bit gesendet werden.

von Dieter W. (dds5)


Lesenswert?

Ralph wrote:
> Viele µC, ich weiß nicht ob es dein Atmel auch kann, können auch auf
> exotische Bitzahlen auf der SPI eingestellt werden.

Hast Du dafür vielleicht zufällig ein Beispiel?
Ich kenne keinen Controller bei dem das mit der Hardware-SPI möglich 
ist.

von Ralph (Gast)


Lesenswert?

zb XC866 von Infineon, ist ein 8052 compatibler 8 Bitter.
Datenbreite auf SPI kann von 2 - 8 Bit eingestellt werden.
Für diesen Fall müsste erst mit 2 Bit Einstellung das Kommando/Adresse 
und danach mit 8 Bit das Datenbyte gesendet werden.

Bei 32 Bit µC wäre es der TMS 470 von TI ist ein ARM7TDMI derivat.
Hier lassen sich 3 bis 16 Bit einstellen.

von Markus H. (markus5)


Lesenswert?

Hallo Fabian

Das sollte doch kein Problem sein. schick einfach 2 Byte. Zuerst Die 
Adresse und als nächstes die Daten. Die ersten 6 Bits der Daten sollten 
eigentlich aus dem Register des AD8400 rausgeschoben werden.


MOSI   X   X   X   X   X   X  A1  A0  D7  D6  D5  D4  D3  D2  D1  D0

CS  1  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   1

falls nicht: software SPI!

von Ralph (Gast)


Lesenswert?

Ist ja wieder mal ein typisches Beispiel dafür das die ATMEL AVR nur zum 
Spielen geeignet sind.
Für sinnvolle Anwendungen muss mann dann doch andere µC verwenden.

DUCKUNDWEG

von Falk B. (falk)


Lesenswert?

@ Ralph (Gast)

>Ist ja wieder mal ein typisches Beispiel dafür das die ATMEL AVR nur zum
>Spielen geeignet sind.

Das mal wieder ein typische Beispiel dafür, dass einige Entwickler von 
ICs nicht gerafft haben, dass SPI byteorientiert arbeitet. Die TLC59xx 
LED Treiber fallen mir da spontan ein. Sechzehn einfache FlopFlops a 6 
Transistoren hätten dort das Problem der 7 Bit/Digit gelöst. Wieviel 
Quadratmikrometer hätten diese 96 Transistoren gekostet? Um wieviel wäre 
IC dadurch teurer geworden?

MFG
Falk

P.S. Ich hab den virtuellen Smily schon gesehen ;-)

von Fabian (Gast)


Lesenswert?

An Alle

Es funktioniert jetzt.
Habe den Poti durch einen neuen AD8400 ersetzt sowie den Code nochmals 
von Anfang an neu geschrieben.
Jetzt funktioniert alles wie es soll.
Es werden wie von Markus betont die ersten 6bits herausgeschoben.

Besten Dank und nochmals herzlichen Dank für Eure beispiellose Hilfe.

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.