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!
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.
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.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.