PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] Atmega32 SPI will nicht



-schumi-
05.03.2012, 20:38
Hallo zusammen,

ich versuche gerade einen DAC per SPI anzusteuern (erster Kontakt mit SPI :)). Aber natürlich gehts nich so wie ich das will...

Der DAC ist ein MCP4812 von Microchip (2x10Bit). Das Datenblatt gibts hier (http://www.reichelt.de/index.html?;ACTION=7;LA=3;OPEN=0;INDEX=0;FILENAME= A200%2FMCP4802-4812-4822.pdf;SID=10TuS1ln8AAAIAAGZ@dZg66204c4c071ca167 ef22763f6669f148). Eigentlich klingt die Ansteuerung sehr simpel:

The write command is initiated by driving the CS pin low, followed by clocking the four Configuration bits and
the 12 data bits into the SDI pin on the rising edge of SCK. The CS pin is then raised, causing the data to be latched into the selected DAC’s input registers.

Sprich man muss CS auf Low legen, dann 4ConfigBits senden und anschließend 12Datenbits die die Ausgangsspg angeben. (Bei mir werden die 2 niederwertigsten Bits vom DAC einfach nicht ausgewertet, weil der ja nur 10Bit hat). Dann wird CS wieder auf High gelegt und der DAC legt den gesendeten Wert als analoge Spannung an den Ausgang (vorausgesetzt LDAC ist auf Low=GND, was bei mir der Fall ist). Alle Bits werden dabei bei der steigenden Flanke von SCK gesendet.

Angeschlossen ist mein DAC folgendermaßen:


DAC Pin:

AVR Pin nr.

AVR Pin Bezeichnung



CS
5
PB4 (SS)


SCK
8
PB7 (SCK)


SDI (=MOSI)
6
PB5 (MOSI)



Mein Programm (Alles SPI ist rot markiert):


#include <avr/io.h>
#include <util/delay.h>
#include "LCD.h"

void SPI_INIT (void)
{
DDRB = DDRB | (1<<DDB5) | (1<<DDB7); // SCK und MOSI als Ausgang
SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR0); // SPE = SPI_Enable; MSTR = Master; SPR0 = f_sck/16 = 1MHz SCK Frequenz (16MHz Quarz), DAC schafft 20MHz
}

void SPI_DATA (char data)
{
SPDR = data; // Daten schicken
while(!(SPSR & (1<<SPIF))); // und warten bis alles gesendet ist
}


int main(void)
{
DDRB = 0b00001111;
PORTB = 0b00000001;
_delay_ms(100);
PORTB = 0b00000010; // Lauflicht, wartet bis die Spannungen an allen Bauteilen stabil stehen
_delay_ms(100);
PORTB = 0b00000100;
_delay_ms(100);
PORTB = 0b00001000;
LCD_INIT();
LCD_STRING(" Labor-Netzteil "); // LC-Display gedudel (Hängt an PortD)

SPI_INIT();
DDRB = DDRB | 0b00010000; // SS als Ausgang (Für CS des DAC)
PORTB = PORTB & 0b11101111; // SS auf Low, weil CS des DAC Lowaktiv
SPI_DATA (0b00111111); // Höherwertiges Nibble senden
SPI_DATA (0b11111100); // Niederwertigeres Nibble senden
PORTB = PORTB | 0b00010000; // SS wieder auf High, damit DAC den Wert analog ausgibt

while(1)
{
}
return 0;
}


Ich sende dem DAC also folgendes:
0011 1111 1111 1100
Das bedeutet Farbgemäß (Datenblatt S. 22):
Config Bits:
0 = Write to DAC_A (Ja, da dran messe ich auch)
0 = Zitat Datenblatt: Don't Care
1 = Output Gain selection Bit, 1 = 1x (VOUT = VREF * D/4096), also auswal der Refferenz
1 = Output Shutdown Control Bit: 1 = Active mode operation, Vout is aviable

Wert der Ausgangsspannung, alles high sollte 5V sein

Nicht Relevant, da mein DAC nur 10Bit hat


Soweit ich das sehe, hab ich doch alles korrekt gemacht, oder? Aber der DAC tut absolut garnichts! (Mit dem DMM mess ich immer ca. 2V, egal was ich sende)

Kann mir bitte jemand helfen? O:)

Vielen herzlichen Dank schonmal
-schumi-

-schumi-
05.03.2012, 22:53
So, hab den Fehler doch glatt selbst noch gefunden.

Und zwar hab ich bei der fallenden Flanke von SCK gesendet, der DAC will aber bei der steigenden.. Somit gibts eine Änderung im Code:


void SPI_INIT (void)
{
DDRB = DDRB | (1<<DDB5) | (1<<DDB7) | (1<<DDB4);
SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR0) | (1<<CPHA);
}


Zwar gibt der DAC anstatt der erwarteten 0-5V nur 2.05-4.05 aus, aber dem komm ich schon noch auf die Schliche.. hoffe ich^^
Aber da direkt danach sowiso ein OP kommt sollte das kein Problem sein..

Viele Grüße
-schumi-

sternst
05.03.2012, 23:51
Somit gibts eine Änderung im Code:Der Code enthält allerdings auch noch eine weitere Änderung, die auf jeden Fall essentiell wichtig ist: SS wird auf Ausgang geschaltet bevor das SPI-Interface konfiguriert wird.

-schumi-
06.03.2012, 00:08
Ah stimmt, glatt übersehen^^

Aber irgendwas stimmt da trotzdem noch nicht...
Das SPI funzt zwar, aber eigentlich sollte der DAC je nach konfiguration entweder von 0V-2.048V oder 0V-4.096V (Dann halt mit halb so großer Genauigkeit) ausgeben können.

Bei mir macht der ganz was anderes.
0V-4.096V wird zu 2.048V-4.096
und bei
0V-2.048V gibt er immer 2.048V aus, egal welchen Wert ich reinschreib..

Naja, mal drüber schlafen, vielleicht krieg ichs morgen noch hin. Oder ich nerv mal demnächst meinen Ausbilder damit^^

Viele Grüße
-schumi-

Kampi
09.03.2012, 15:55
Hast du das Problem gelöst?

ePyx
09.03.2012, 17:03
Da ich fast die gleichen DACs habe, bin ich natürlich auch daran interessiert ob du sie ans laufen bekommst. Hast du mal versucht die Reihenfolge der Bits zu ändern ? Irgendwie scheint es mir so, dass erst die Config Bits eintreffen sollten und dann die Datenbits.

Kampi
09.03.2012, 17:19
Also ich habs gerade mal mit Bascom und C probiert und bei mir laufen sie ;)

-schumi-
09.03.2012, 22:09
Bei mir funktionierts so:


SPI_WORD( 0b10100000 | ((setspg>>6) & 0b00011111) , setspg<<2 );
In setspg steht der gewünschte Wert der Ausgangsspg drin.

Gibt dann 0V-4.095 aus. (Vermute ich, aufs Bit genau geht mein DMM nicht)

Allerdings ist das hier noch ein wenig verschoben (beim zuerst gesendeten Byte hab ich meine Angaben um ein Bit nach links verschoben (Glück gehabt, dass das MSB 0 sein muss wenn man DAC_A braucht^^).

Ich hab den verdacht, dass SCK schon irgendwo zu früh eine steigende Flanke macht und der DAC schon am lesen ist. Aber ich hab leider momentan in der Arbeit wenig Zeit übrig (Prüfungsvorbereitung) und deswegen bin ich noch nicht dazu gekommen mir den BUS mit dem Digitaloskar anzusehen.

PS: meine SPI Routinen:


void SPI_INIT (void)
{
DDRB = DDRB | (1<<DDB5) | (1<<DDB7) | (1<<DDB4);
SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR0) | (1<<CPHA);
}

void SPI_WORD (char data1, char data2)
{
PORTB = PORTB & 0b11101111;
SPDR = data1;
while(!(SPSR & (1<<SPIF)));
SPDR = data2;
while(!(SPSR & (1<<SPIF)));
PORTB = PORTB | 0b00010000;
}


Viele Grüße
-schumi-