Forum: Mikrocontroller und Digitale Elektronik Atmega 32 und AD7788 (SPI)


von Ralf (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich versuche schon die ganzen 2,5 Tage SPI ans laufen zu bekommen. Aber 
ich schaffe es nicht.
Es kommen immer Werte wie 255, 127, 0 und ab und an auch 95 raus.

Anbei mein Programm, darin steht auch wo ich was angeschlossen habe.

Ueber die Suche habe ich leider nichts zum AD7788 (16 Bit) oder AD7789 
(24 Bit) gefunden.

Hier noch meine spi.h:
unsigned char empf(void)
{
        //PORTB &= ~(1<<1);
        SPDR = 0xff;
        loop_until_bit_is_set(SPSR, SPIF);
        //PORTB |= (1<<1);
        return SPDR;
}

void send(unsigned char wert)
{
        //PORTB &= ~(1<<1);
        SPDR = wert;
        loop_until_bit_is_set(SPSR, SPIF);
        wert = SPDR;
        //PORTB |= (1<<1);
}

Waere echt super, wenn mir jemand sagen koennte, was ich falsch mache.
Das Datenblatt habe ich bestimmt viermal inzwischen durchgelesen, ich 
finde einfach keinen Fehler mehr :(

Wenn ich jedesmal statt 0xff 0x3c schicke, erhalte ich sehr seltsame 
Daten.
Meist in der Reihenfolge: 255 0 0
oder: 255 28 28

An der seriellen Schnittstelle kann es eigentlich nicht liegen. Ich kann 
Texte, integer und float ausgeben.

Mir sind auch noch zwei Sachen nicht ganz klar:
1. Wie lese ich 16 Bit? (Im Moment lese ich ja nur 8 Bit)
Oder ist es so, dass ich beim ersten Mal lesen die ersten 8 und danach 
die zweiten 8 Bit lese?
2. Sendet der Atmega32 immer einen Takt auf SCK oder nur wenn gerade 
Daten gesendet oder empfangen werden sollen?

Die Geschwindigkeit vom Takt habe ich auch schon reduziert, ohne Erfolg, 
ja sogar ganz ohne Aenderung.

Wenn ich MISO abklemme, erhalte ich immer 255, nichts anderes.
Demzufolge scheint er ja irgendwas zu empfangen...

Danke! (Auch fuer weitere Literaturhinweise, falls ihr anhand von dem 
Script/Geschriebenen denkt, dass mein Wissen fuer so ein Projekt nicht 
ausreicht)

von Joan P. (joan)


Lesenswert?

Ralf wrote:
> ich versuche schon die ganzen 2,5 Tage SPI ans laufen zu bekommen. Aber
> ich schaffe es nicht.

> Waere echt super, wenn mir jemand sagen koennte, was ich falsch mache.
> Das Datenblatt habe ich bestimmt viermal inzwischen durchgelesen, ich
> finde einfach keinen Fehler mehr :(

Normal besteht die Kommunikation zu einem Slave via SPI aus mehreren 
bytes, direkt hintereinander.. im ersten byte immer was und wo man etwas 
machen möchte und die folgenden dann meistens die zu schreibenden oder 
zu lesenden Daten.

Das Datenblatt deines AD7788 (S.11)
"... All communications to the part must start with a write operation to 
the communications register. The data written to the communications 
register determines whether the next operation is a read or write 
operation, and to which register this operation takes place.
For read or write operations, once the subsequent read or write 
operation to the selected register is complete, the interface returns to 
where it expects a write operation to the communications register. This 
is the default state of the interface and, on power-up or after a reset, 
the ADC is in this default state waiting for a write operation to the 
communications register. ..."

Schau dir dazu auch mal Figure 11 auf S.15 genauer an.. da sind 
mehrere bytes hintereinander abegebildet.. nicht nur einzlene Bits..

Für nen anderen Chip, den ich mit 4Mhz SPI-CLK bedudele, brauch ich zB 2 
byte um dem zu sagen, dass ich ihm im 2ten byte die 8-Bit informationen 
übergebe und im ersten erzähl ich dem, wo er damit hin soll:
1
static void spi_write (uint8_t addr, uint8_t byte_write)
2
{
3
  PORTB &= ~(1<<PB0); // SEL low
4
  SPDR = 0xC0 + addr; // SPI write auf Register mit Adresse 'addr'
5
    // do 17 clock-cycles nothing
6
    __asm__ __volatile__ (" nop \n nop \n nop \n nop \n nop \n nop \n nop \n"
7
    "nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n":: );
8
  SPDR = byte_write; // SPI write mit Inhalt 'byte_write'
9
    // do 17 clock-cycles nothing
10
    __asm__ __volatile__ (" nop \n nop \n nop \n nop \n nop \n nop \n nop \n"
11
    "nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n":: );
12
  PORTB |= (1<<PB0); // SEL high
13
}

> Wenn ich jedesmal statt 0xff 0x3c schicke, erhalte ich sehr seltsame
> Daten.
> Meist in der Reihenfolge: 255 0 0
> oder: 255 28 28

Oszi zum gucken der MOSI, SCK und MISO Leitungen hast du nicht, oder? 
:-(
Das hilft bei so was ungemein..

> An der seriellen Schnittstelle kann es eigentlich nicht liegen. Ich kann
> Texte, integer und float ausgeben.
>
> Mir sind auch noch zwei Sachen nicht ganz klar:
> 1. Wie lese ich 16 Bit? (Im Moment lese ich ja nur 8 Bit)
> Oder ist es so, dass ich beim ersten Mal lesen die ersten 8 und danach
> die zweiten 8 Bit lese?

Sollte dafür einen Befehl geben, wie viel er dir dann sendet..
Müsstest dann theo. 1 byte Befehl+Adresse, 2. byte und 3. byte dann in 
deinem SPDR nachsehen, was er dir geschickt hat..
1
static uint8_t spi_read (uint8_t addr)
2
{
3
  PORTB &= ~(1<<PB0); // SEL low
4
  SPDR = 0x80 + addr; // SPI read auf Register mit Adresse 'addr'
5
    // do 17 clock-cycles nothing
6
    __asm__ __volatile__ (" nop \n nop \n nop \n nop \n nop \n nop \n nop \n"
7
    "nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n":: );
8
  SPDR = 0x00; // SPI clk erzeugen
9
    // do 17 clock-cycles nothing
10
    __asm__ __volatile__ (" nop \n nop \n nop \n nop \n nop \n nop \n nop \n"
11
    "nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n":: );
12
  PORTB |= (1<<PB0); // SEL high
13
  return (SPDR); // read byte and give back
14
}

Für mehrere Bytes an Daten musste dann halt mehrfach lesen und statt 
8Bit halt 16Bit oder mehr übergeben am Ende..
1
static uint16_t spi_read_2bytes (void)
2
{
3
  PORTB &= ~(1<<PB0); // SEL low
4
  uint16_t two_bytes_read=0;
5
  SPDR = 0x20; // SPI read Frame
6
    // do 17 clock-cycles nothing
7
    __asm__ __volatile__ (" nop \n nop \n nop \n nop \n nop \n nop \n nop \n"
8
    "nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n":: );
9
  SPDR = 0x00; // SPI create SCK
10
    // do 17 clock-cycles nothing
11
    __asm__ __volatile__ (" nop \n nop \n nop \n nop \n nop \n nop \n nop \n"
12
    "nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n":: );
13
  two_bytes_read |= (SPDR << 8); // lies & schieb 'first_byte' um 8 Stellen nach links
14
  SPDR = 0x00; // SPI create SCK
15
    // do 17 clock-cycles nothing
16
    __asm__ __volatile__ (" nop \n nop \n nop \n nop \n nop \n nop \n nop \n"
17
    "nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n":: );
18
  two_bytes_read |= SPDR; // lies 'second_byte'
19
  PORTB |= (1<<PB0); // SEL high
20
  return (two_bytes_read); // give back 2 bytes
21
}

> 2. Sendet der Atmega32 immer einen Takt auf SCK oder nur wenn gerade
> Daten gesendet oder empfangen werden sollen?

Er sendet 8 Clocks, sobald du was in SPDR schreibst.. bei 8MHz fCPUI/O 
braucht das rausschieben dann ca 4µs pro byte, wenn die SPI mit halbem 
CPU-Takt läuft (also max-speed in dem Fall -> 4MHz)..

Kann dein AD7788 4MHz per SPI lesen?

> Die Geschwindigkeit vom Takt habe ich auch schon reduziert, ohne Erfolg,
> ja sogar ganz ohne Aenderung.
>
> Wenn ich MISO abklemme, erhalte ich immer 255, nichts anderes.
> Demzufolge scheint er ja irgendwas zu empfangen...

Ja, der Master zieht masterINslaveOUT ja auch High und wenn der Slave 
die nicht runterziehen kann, liest der Master auch bei jedem Takt nur 
High :-)

Nebenbei.. die Datenrichtungen deiner SPI-Pins und deren Pull-Ups hast 
du auch richtig konfiguriert, ja?!
Sonst hier die Einstellungen:

PullUp:
für (SS), (RST) ON
für (SCK), (MOSI) OFF

DDR:
als Ausgang (SS), (SCK), (MOSI), (RST)
als Eingang (MISO)

> Danke! (Auch fuer weitere Literaturhinweise, falls ihr anhand von dem
> Script/Geschriebenen denkt, dass mein Wissen fuer so ein Projekt nicht
> ausreicht)

Schau dir mal das Datenblatt vom Atmel AT86RF230 an.. da hats auch 
schöne Timing-Bildchen für SPI drin, die dir weiterhelfen sollten, wegen 
dem Verständniss..

Grüsse

von Ralf (Gast)


Lesenswert?

Erstmal vielen Dank fuer die Muehe.

Ich schreibe im Programm ja zweimal, also an zwei Stellen. Auch 
ansonsten sehe ich bei den Einstellungen keinen Fehler.
Den Takt habe ich ja schon von 4 MHz auf 0,5 MHz reduziert, keine 
Aenderung.
Wenn ich das Datenblatt richtig verstehe, werden 4 MHz akzeptiert.

Was meinst du eigentlich mit RST?

Wie auch immer, ich werde morgen nochmal die komplette Verkabelung 
entfernen und neu machen, vielleicht liegt ja auch dort der Fehler.

Viele Gruesse
Ralf

von Joan P. (joan)


Lesenswert?

Ralf wrote:
> Erstmal vielen Dank fuer die Muehe.

büdde :)

> Ich schreibe im Programm ja zweimal, also an zwei Stellen.

In deiner angehängten main.c war nur 1x /send()/ drin.. und ne Menge 
/wait()'s/.

Nach dem was ich so in dem Datenblatt lese, musst du zuerst immer in das 
Communication-Register schreiben und dort sagen, was du machen möchtest.
Danach kannst du bei dem Teil entweder den Status abfragen, es 
Einstellen oder aber Daten lesen..

Ich persönlich würde es ja mit single conversion probieren.
Also folgende Bytes senden (write to mode_reg, single_conv and 
start_it): (0x90), (0x82) dann warten bis Dout/RDY low wird.
Dann (read from dataregister, data, data): (0xB8), (0x00), (0x00).
Insgesamt musst du also 3 bytes hinschicken und 2 lesen, wenn ich 
richtig liege..

Kann auch sein, ich hab die bisschen falsch verstanden, denn die Fig. 11 
zeigt kein (0xB8) vor den zu lesenden Daten, dann könnte man die ja weg 
lassen und nach dem RDY low gleich loslegen (wirst ja dann sehen, was 
der chip antwortet :-) .. aber laut Datenblatt, muss man immer mit dem 
Com_Reg anfangen: "All communications to the part must start with a 
write operation to the communications register."

Also nochmal (Single Conversion):
send (0x90)
send (0x82)
wait for RDY == low
send (0xB8) // kann man vieleicht weglassen..
read_byte1 (per SPI 0x00 senden und danach SPDR auslesen)
read_byte2 (per SPI 0x00 senden und danach SPDR auslesen)

> Auch ansonsten sehe ich bei den Einstellungen keinen Fehler.
> Den Takt habe ich ja schon von 4 MHz auf 0,5 MHz reduziert, keine
> Aenderung.
> Wenn ich das Datenblatt richtig verstehe, werden 4 MHz akzeptiert.
>
> Was meinst du eigentlich mit RST?

Sry, ist mir reingerutscht von meinem Chip.. der Reset für den Slave, 
falls der mal geerdet werden muss vom Master.

> Wie auch immer, ich werde morgen nochmal die komplette Verkabelung
> entfernen und neu machen, vielleicht liegt ja auch dort der Fehler.

Viel Erfolg!

Ich hab heut selber 4h ein Phantom gejagt..

von Ralf (Gast)


Lesenswert?

Ich habe gerade etwas festgestellt:

Wenn ich "make program" ausfuehre, wird mein Atmega32 programmiert, das 
Programm faengt an zu laufen, bricht ab, das Programm wird dann wohl 
noch verifziert und laeuft dann erneut an.

Somit stimmt ja alles nicht mehr, was ich hinsende, wenn ich denke ich 
bin am Anfang, ist der AD7788 schon teilweise programmiert und gerade 
mittendrin, in einem Byte.

Jedenfalls erhalte ich nur reproduzierbare Ergebnisse, wenn ich nach dem 
"make program" die Stromzufuhr trenne und neu einschalte.

Und jetzt schaue ich ob die Ergebnisse auch richtig sind :)

von Ralf (Gast)


Lesenswert?

Nochmal ich:

Funktionieren tut es ja jetzt, aber nur die ersten 10 Bit sind stabil.

Wenn ich mit dem Mikrokontroller selbst messe, bekomme ich genauere 
Messergebnisse, wobei der ja ich glaube nur 12 Bit kann.

Hat da jemand noch einen Tip fuer mich?

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.