Forum: Mikrocontroller und Digitale Elektronik MAX1168 mit Atmega8535 ohne SPI ansteuern


von Nicolas G. (nicolas_g)


Lesenswert?

Hallo,

ich habe ein Problem mit der Ansteuerung eines MAX1168 mit dem 
Atmega8535. Da ich die SPI-Schnittstelle nicht nutzen möchte, habe ich 
mir selbst Funktionen geschrieben um mit dem Chip zu kommunizieren. Den 
D/A-Wandler MAX541 habe ich so wunderbar zum Laufen bekommen und er gibt 
mir auch immer die richtigen Werte aus.
Der MAX1168 erwartet zunächst eine 8 Bit Konfiguration, die ihm sagt 
welchen Analog-Kanal ich benutzen möchte, welche Referenzspannung, 
internen oder externen Clock und ob es SPI oder etwas anderes sein soll.
Leider gibt mir der MAX1168 als Antwort immer nur Nullen zurück, was 
nicht stimmen kann, weil ich zum Test die volle Referenzspannung 
angeschlossen habe. Jetzt steht ihm Datenblatt etwas von maximal ~4 MHz, 
aber der Atmega8535 läuft mit 8 MHz. Vielleicht ist das schon das 
Problem. Leider habe ich keinen 4 MHz-Quartz da. Vielleicht kann sich ja 
mal jemand den Quellcode anschauen und mir dann sagen, welche 
Informationen er noch braucht.

Die Testschaltung ist einwandfrei verdrahtet und wurde mittels 
Multimeter auf Leitfähigkeit getestet. DIN ist an MOSI, DOUT an MISO, 
CLK an SCLK und CS stimmt auch. Ich nutze dafür die Bits von Port A, 
weil der noch frei ist. Bit 0 und Bit 1 sind für den CS der beiden 
MAX541 zuständig, Bit 2 ist CS von MAX1168, Bit 5 ist MOSI, Bit 6 ist 
MISO, Bit 7 ist SCLK.

Der Quellcode ist unter folgendem Link zu finden:
http://freakscorner.de/avr/AVRTest.zip

Vielen Dank schonmal für eure Mühe!

von Nicolas G. (nicolas_g)


Lesenswert?

Hat niemand eine Idee dazu?

von Martin G. (mager)


Lesenswert?

Ohne Deinen Code betrachtet zu haben (keine Lust, ein ZIP runterzuladen, 
zu entpacken und anzuschauen: das geht einfacher!): wenn das Teil nur 4 
MHz verträgt und Du mit 8 MHz die Bits per selbstgebautem SPI 
reinpustest wird es nicht funktionieren. Bau doch mal ein paar delays 
ein.

von Nicolas G. (nicolas_g)


Lesenswert?

Ja, das ist eine Idee, auf die ich selbst schon gekommen bin. Ich habe 
das nur im Nachhinein nicht mehr geschrieben. Vielleicht hätte ich das 
tun sollen.
Mit dem Delay hat es leider nicht funktioniert.

Und wegen dem ZIP. Es sind mehrere Dateien und die sind nicht gerade 
kurz. Aber ich kann dir hier mal die wichtigsten Stellen schreiben.

spi.h
1
/*
2
 * spi.h
3
 *
4
 *  Created on: 11.04.2010
5
 *      Author: nicolas
6
 */
7
8
#ifndef SPI_H_
9
#define SPI_H_
10
11
void SPI_init();
12
void SPI_setDAC(int i);
13
void SPI_setADC(int i);
14
15
#define CONV_MOSI 5
16
#define CONV_MISO 6
17
#define CONV_SCLK 7
18
#define CONV_DDR DDRA
19
#define CONV_PORT PORTA
20
void SPI_send8(int chip, char c);
21
void SPI_send16(int chip, char high, char low);
22
void SPI_receive16(int chip, char* high, char* low);
23
24
int SPI_isADC(int chip);
25
26
struct SPI_value {
27
  char high;
28
  char low;
29
};
30
31
#endif /* SPI_H_ */

spi.c
1
#include <avr/io.h>
2
#include "spi.h"
3
#include <util/delay.h>
4
5
// Da fehlt noch Code
6
7
void SPI_receive16(int chip, char* high, char* low) {
8
  if (!SPI_isADC(chip)) {
9
    *high = SPI_values[chip].high;
10
    *low = SPI_values[chip].low;
11
    LED_red(1);
12
    return;
13
  }
14
  CONV_PORT = (1 << chip);
15
  //_delay_us(1);
16
  CONV_PORT &= ~(1 << chip);
17
18
  // first sending configuration
19
  char config;
20
21
  config = 0b00000000;
22
23
  int bit;
24
  unsigned int shift = 128;
25
  for (bit = 0; bit < 8; bit++) {
26
    if (shift & config) {
27
      CONV_PORT |= (1 << CONV_MOSI);
28
    } else {
29
      CONV_PORT &= ~(1 << CONV_MOSI);
30
    }
31
    shift = shift >> 1;
32
    CONV_PORT |= (1 << CONV_SCLK);
33
    CONV_PORT &= ~(1 << CONV_SCLK);
34
  }
35
36
  //reading 16 Bits
37
38
  *high = 0;
39
  for (bit = 0; bit < 8; bit++) {
40
    if (CONV_PORT & CONV_MISO) {
41
      *high |= 1;
42
      LED_green(1);
43
      _delay_ms(100);
44
    }
45
    *high = *high << 1;
46
    CONV_PORT |= (1 << CONV_SCLK);
47
    CONV_PORT &= ~(1 << CONV_SCLK);
48
  }
49
50
  *low = 0;
51
  for (bit = 0; bit < 8; bit++) {
52
    if (CONV_PORT & CONV_MISO) {
53
      *low |= 1;
54
      LED_green(1);
55
    }
56
    *low = *low << 1;
57
    CONV_PORT |= (1 << CONV_SCLK);
58
    CONV_PORT &= ~(1 << CONV_SCLK);
59
  }
60
61
//  _delay_us(1);
62
  CONV_PORT &= ~(1 << chip);
63
}
64
65
//Da fehlt noch Code

Der Befehl LED_green() war zum Debuggen gedacht, damit ich sehe, ob 
überhaupt mal ein Bit kommt, das nicht 0 ist.

von Felix T. (felix)


Lesenswert?

Hallo Nicolas

Bist du mittlerweile weitergekommen?
Ich hab mich in letzter Zeit ein bisschen mit dem MAX1168 auseinander 
gesetzt. Ich habe den MAX1168 mit Hilfe der SPI-Schnittstelle im 
Controller (bei mir ATmega2561) angesteuert. Das hat zwar nicht auf 
Anhieb funktioniert aber mitterweile läuft es problemlos. Wenn du willst 
kann ich den Code hier posten.
Auf jeden Fall ist es wichtig am MAX1168 den Pin DSEL auf GND und DSPR 
auf High zu legen. Ansonsten rührt sich der MAX1168 nicht.

Insgesamt steig ich durch deinen Code nicht so recht durch da du so gut 
wie keine Kommentare nutzt. Was z.B. bedeutet bei SPI_send16(int chip, 
char high, char low) chip, high und low?
Ich empfehle dir deine Routine SPI_send8 zu nutzen die ist im Ansatz 
schon richtig allerdings dürfte der Aufruf von
1
  CONV_PORT = (1 << chip);
2
  CONV_PORT &= ~(1 << chip);
am Anfang und Ende von SPI_send8 zu Problemen führen. Ich denke diese 
beiden Zeilen sollen so eine Art Chip-Select sein oder? Wenn du dir das 
Datenblatt ansiehst so findest du auf Seite 17 und Folgende dass während 
der Kommunikation das CS-Signal dauerhaft auf low sein muss. Der 
kurzeitige High-Impuls wirkt wahrscheinlich wie ein Reset für den 
MAX1168. Außerdem verhindert er dass der MAX1168 das samplen und 
konvertieren der AD-Kanäle beginnt.

Im Prinzip ist die Kommunikation mit dem MAX1168 nicht sonderlich 
kompliziert (als Beispiel die Kommunikations-Sequenz in Figure 14 auf 
Seite 19 im Datenblatt, so habe ich es verwendet):
1. /CS von high nach low schalten
2. Konfigurations-Register mit MSB zuerst an den MAX1168 senden, bei mir 
ist es folgendermaßen konfiguriert:
1
CCC_MAX1168 = (1<<CH_SEL2)|(1<<CH_SEL1)|(1<<CH_SEL0)|(0<<SCAN1)|(1<<SCAN0)|(0<<REF_PDSEL1)|(0<<REF_PDSEL0)|(1<<INT_EXT_CLK);
3. warten bis der MAX1168 das /EOC auf low setzt --> Konvertierung zu 
Ende
4. Nacheinander die n mal 16 bit reintakten. Das n ergibt sich aus der 
konfiguration von (1<<CH_SEL2)|(1<<CH_SEL1)|(1<<CH_SEL0) und 
(0<<SCAN1)|(1<<SCAN0). Näheres dazu findest du im Datenblatt. Bei mir 
ist es so konfiguriert, dass er alle 8 Kanäle sampled und diese 
überträgt, es müssen also 8 x 16 bit übertragen werden.
5. /CS wieder auf high setzen

Wichtig ist wie schon erwähnt, dass Pin DSEL auf GND und DSPR auf High 
liegen.
Damit deine SPI-Routine nicht zu schnell taktet kannst du ja ein paar 
NOPs einbauen:
1
void SPI_send8(int chip, char c) {
2
  CONV_PORT = (1 << chip);
3
  CONV_PORT &= ~(1 << chip);
4
5
  int bit;
6
  unsigned int shift = 128;
7
  for (bit = 0; bit < 8; bit++) {
8
    if (shift & c) {
9
      CONV_PORT |= (1 << CONV_MOSI);
10
    } else {
11
      CONV_PORT &= ~(1 << CONV_MOSI);
12
    }
13
    shift = shift >> 1;
14
    asm ("nop");
15
    asm ("nop");
16
    asm ("nop");
17
    CONV_PORT |= (1 << CONV_SCLK);
18
    asm ("nop");
19
    asm ("nop");
20
    asm ("nop");
21
    CONV_PORT &= ~(1 << CONV_SCLK);
22
  }
23
  SPI_values[chip].low = c;
24
25
  CONV_PORT = (1 << chip);
26
  CONV_PORT &= ~(1 << chip);
27
}
Das sollte reichen bei 8MHz Taktfrequenz.

Also dann viel Erfolg.

Viele Grüße,
Felix

von Nicolas G. (nicolas_g)


Lesenswert?

Danke dir,

werde das mal die Tage testen. Komme nicht so oft dazu.
Asnsonsten hätte ich auf jeden Fall Interesse an deinem kompletten Code.
Ich brauche nur einen Eingangs-Kanal und und deswegen brauche ich nicht 
die 8x16 Bits lesen, sondern nur 16 Bits.
Ich habe das im Datenblatt so verstanden, dass die einzelnen Bits, die 
ich lese zum selben Zeitpunkt gesampled werden wie ich sie lese. Aber 
scheinbar liege ich da falsch.

Ich würde mich also freuen mal deinen Code zu sehen. Und wegen den 
Kommentaren: Tut mir Leid. ;)
Ich bin eigentlich ein großer Kommentar-Freund, aber während der 
Entwicklung und bei so einem kurzen Code warte ich immer bis alles 
funktioniert, weil sich ja immer nochmal viel ändern kann.

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.