Ich bin neu bei Mikrocontrollern - ich versuche, externe ADC-Werte von einem AD7798-ADC mithilfe von SPI-Kommunikation zu lesen.
Zunächst muss ich einige ADC-Register einrichten - einige Register sind nicht konfiguriert. Um die Register zu konfigurieren, muss ich das Kommunikationsregister verwenden, um auszuwählen, welches Register ich konfigurieren möchte.
Zum Beispiel möchte ich das AD7798-Konfigurationsregister (16 Bit) einstellen. Ich habe Code wie diesen: #include #define ADC_CS PORTB.3 #define WG_CS PORTB.4 #define MOSI PORTB.5 #define MISO_PU PORTB.6 #define MISO_PIN PINB.6 #define SCK PORTB.7
//global functions.
unsigned int adcConfig;
unsigned int adcMode;
unsigned int adcId;
void init_io(void)
{
DDRB = 0xBF; // make SCK, MOSI, CS1, CS2 outputs
ADC_CS = 1; //disable ADC
WG_CS = 1; //disable WaveGenerator
MISO_PU = 1; //enable pull-up on MISO so we can test !RDY
}
unsigned char spi(unsigned char data)
{
//Start transmision
SPDR = data;
//Wait for transmision complete
while (!(SPSR & (1<<SPIF)));
return SPDR;
}
//Sets the waveform generator output to given phase
void SetWGPhase(unsigned int phase)
{
SPCR = 0x5A; // mode #2 F_CPU/64
WG_CS = 0; // enable
spi(0x20);
spi(0x00);
spi((phase >> 8) | 0xC0); //Load into phase register 0
spi(phase & 0x00FF);
WG_CS = 1;
}
void setupAd(){
SPCR = 0x5D;
ADC_CS = 0;
// while(spi(0x10) != 0x10);
spi(0x10); //set up communication register for configuration reg.
spi(0x07);
spi(0x10);
spi(0x08); //set up communication register for mode reg.
spi(0x00);
spi(0x0A);
ADC_CS = 1;
}
unsigned int ReadAd(void)
{
unsigned int data;
SPCR = 0x5D; // mode #3 F_CPU/16
CheckStatus();
ADC_CS = 0; // enable
while (MISO_PIN != 0) ; // wait for DOUT/!RDY line to go low
//Read data
spi(0x58); //Place readinstruction in communication register
data = spi(0xFF); // read hi-byte
data = (data << 8) | spi(0xFF); // and lo-byte.
ADC_CS = 1; // disable
return data;
}
unsigned char CheckStatus(void)
{
char adcStatus;
SPCR = 0x5D;
ADC_CS = 0; // enable
while(ADC_CS_PIN);
adcStatus = 0xFF;
while(!(adcStatus & 0x80)){
spi(0x40);
adcStatus = spi(0xFF);
}
ADC_CS = 1;
return adcStatus;
}
unsigned int ReadAdConfReg(void)
{
unsigned int retvalconfig;
SPCR = 0x5D;
ADC_CS = 0;
while (MISO_PIN != 0) ;
spi(0x50);
adcConfig = spi(0xFF);
adcConfig = (adcConfig << 8) | spi(0xFF);
retvalconfig= adcConfig;
ADC_CS = 1;
return retvalconfig;
}
unsigned int ReadAdModeReg(void)
{
unsigned retvalmode;
SPCR = 0x5D;
ADC_CS = 0;
while (MISO_PIN != 0) ;
spi(0x48);
adcMode = spi(0xFF);
adcMode = (adcMode << 8) | spi(0xFF);
retvalmode =adcMode;
ADC_CS = 1;
return retvalmode;
}
unsigned int ReadAdIdReg(void)
{
SPCR = 0x5D;
ADC_CS = 0;
while (MISO_PIN != 0) ;
spi(0x60);
adcId = spi(0xFF);
ADC_CS = 1;
return adcId;
}
Wenn ich das Konfigurationsregister drucke, gibt es den Wert "16383" an. aber wenn ich das Ziel aus-/einschalte, erhalte ich "1808 (was 0x0710 entspricht)", danach gibt es den gleichen Wert wie "16383". Ich habe auch mit verschiedenen Konfigurationen getestet, aber es ändert sich nicht, es wird immer "16383" gedruckt, außer beim Ausschalten / Einschalten. Ich denke, der Standardwert.
Selbst mit dem Modusregister wird immer "10 (was 0x000A entspricht)" gedruckt, aber das ist der Wert, den ich immer bekomme, auch wenn ich die Konfiguration auf "0x0022" ändere.
Sogar ich habe versucht, das ID-Register zu lesen, aber es gibt "0x48". aber im Datenblatt wurde "0xX8" für AD7798 erwähnt. Vielen Dank im Voraus.
Jemand hilft mir bitte, ich bekomme keine Ahnung, welchen Fehler ich hier mache.
Während dieses Datenblatt meine Augen mit der Komplexität einer einfachen Konvertierung/Lesung bluten lässt, müssen Sie einige einfache Änderungen vornehmen.
Ich bin mir nicht sicher, warum die Leute es sich schwerer machen, als es wirklich ist. Sie ziehen die Chipauswahlleitung nach unten, und der Ziel-IC sollte einfach lesen, was Sie ihm geben, bis Sie ihn wieder nach oben ziehen. Nur weil Ihre Methode einen 8-Bit-Wert annimmt, heißt das nicht, dass Sie sie nicht zweimal aufrufen können, um einen 16-Bit-Wert an Ihren IC zu übergeben. Es ist nicht nötig, irgendetwas zu bit-bangen. Das ist Unsinn.
Rufen Sie Ihre SPI-Methode auf, um dem ADC mitzuteilen, dass Sie in das Konfigurationsregister schreiben möchten:
spi(0x10);
Wie ich aus dem Datenblatt verstehe, können Sie Ihren 16-Bit-Wert danach sofort in das Konfigurationsregister schreiben, also würden Sie Folgendes tun:
spi(0x07);
spi(0x10);
Ich habe vergessen, auf welche Weise das auf der Ziel-IC-Seite zusammengebaut wird, sodass Sie sie einfach umkehren können, wenn die Dinge nicht richtig funktionieren. Es besteht überhaupt keine Notwendigkeit, irgendwelche Werte zu verschieben. Im schlimmsten Fall müssen Sie die CS-Leitung wieder auf High ziehen, bevor Sie sie wieder auf Low ziehen, um die Daten tatsächlich zum Schreiben in das Konfigurationsregister zu senden.
Ansonsten ist das super einfach. Denken Sie daran, wenn das Ziel-SPI-Gerät mehr als ein Byte erwartet, dh einen 16-Bit-Wert, stehen die Chancen gut, dass die Bytes in der Reihenfolge gesendet werden, in der sie sonst normal erscheinen würden (wenn Sie also 0x1234 senden möchten, hätten Sie 0x12 und 0x34) funktionieren gut und Sie müssen nichts verschieben.
spi()
Aber OP muss dann seine Funktion
ändern . Zwischen den Cals deaktiviert er SS nie, so dass dies automatisch in der Funktion ist. Vielleicht könnte er ein optionales Argument hinzufügen hold_ss
.ChipSelectAd()
Funktion, aber falsch, sie zwischen einem Befehl und den zugehörigen Daten zu deaktivieren.Die Chipauswahlleitung auf dem AD7798 ist aktiv niedrig. Es sieht so aus, als hätten Sie die Polarität in Ihrem Code rückwärts.
Sie müssen CS zu Beginn der Übertragung auf niedrig (0) und nach der Übertragung auf hoch setzen. Also versuchen Sie Folgendes:
void setupADC()
{
ChipSelectAd(0); // was 1
spi(0x10);
spi(0x07);
spi(0x10);
ChipSelectAd(1); // was 0
}
Überprüfen Sie auch, ob Sie den richtigen SPI-Modus verwenden (auf vielen Mikrocontrollern CPOL und CPHA genannt, für "Taktpolarität" und "Taktphase"). Dies bestimmt, welche Taktflanke Datenübergänge auslöst und welchen Pegel der Takt zwischen Transaktionen (im Leerlauf) hat.
Der AD7798 erfordert CPOL=1 und CPHA=1 (SPI-Modus 3).
ChipSelectAd
die Inversion durchgeführt wird (deshalb hilft es, mehr Code anzuzeigen). Welchen Prozessor verwendest du? (füge dies der Frage hinzu)Wie RocketMagnet sagt
spi(0x07)<<8;
macht keinen Sinn. Obwohl die Funktion spi()
definiert ist char
, verschieben Sie sie nach links und verwerfen sie dann.
spi(0x07 << 8);
verschiebt das Argument um 8 Bits nach links, also wird es sein 0x0700
. Aber das macht nicht das, was du willst. Sie deaktivieren SS (Slave Select) zwischen Aufrufen der spi()
Funktion nicht, sodass dies automatisch erfolgt. Ich würde es so ändern, dass es ein optionales Argument hold_ss
hat, sodass Sie das erste Byte und dann das zweite verschieben und erst dann SS deaktivieren können.
Auf diese Weise können Sie 16 Datenbits zum ADC verschieben, ohne Daten vor dem spi()
Anruf verschieben zu müssen. Alternativ können Sie eine Funktion schreiben spi16()
:
unsigned int spi16(unsigned int data16)
{
assert_SS(IOpin);
spi8(data >> 8); /* assuming LSB is shifted first */
spi8(data);
deassert_SS(IOpin);
}
(Ich ignoriere die eingehenden Daten im Moment.)
Das Datenblatt zeigt an, dass das Konfigurationsregister tatsächlich 16 Bit benötigt, aber obwohl es keine Details enthält, würde ich erwarten, dass es sie als einzelne Übertragung benötigt. Überprüfen Sie die spi()
Funktion des Compilers Ihres Mikrocontrollers und das Datenblatt des Mikrocontrollers, um festzustellen, ob 16-Bit-Übertragungen überhaupt möglich sind. Wenn der Controller 16-Bit-Übertragungen ausführen kann, sollten Sie dies tun können:
spi(0x0710);
Wenn nur 8-Bit-Übertragungen möglich sind, müssen Sie meiner Meinung nach auf ein Bit-Banged-SPI zurückgreifen (was nicht so schwierig ist).
bearbeiten
Rocketmagnet weist mich auf die Definition der spi()
Funktion hin:
char spi(char data)
Das sagt alles: Das Argument ist vom Typ char
, also nur 8-Bit.
( Danke für den Hinweis (kein Wortspiel beabsichtigt), Rocketmagnet )
Welches Mikro verwendest du? Sie haben keine Angaben dazu gemacht, was spi()
dort vor sich geht. Es könnte 8 Bit senden. In diesem Fall führt Ihre 8-Bit-Verschiebung zu Unsinn. Jetzt haben Sie angegeben, dass Sie "0x0710" senden möchten. Denken Sie eine Sekunde lang darüber nach, was in Ihrem Code passieren könnte.
Sie scheinen verwirrt darüber zu sein, wie diese SPI-Übertragung stattfindet.
Zuerst senden Sie 0x10. Angenommen , Ihre spi()
Funktion sendet 16 Bits, senden Sie 0x0700. Sie haben gerade 0x100700 übertragen.
Ich bin mir ziemlich sicher, dass Ihre spi()
Funktion Ihre 16 Bits nicht sendet. Sie senden also im Grunde zwei Bytes: 0x10 und 0x00. Gut gemacht.
Sie müssen die Byte-Reihenfolge umkehren, wenn Sie mehrere Bytes über SPI senden. Senden Sie zuerst 0x07 und erst dann 0x10.
stevenvh
Raketenmagnet
Raketenmagnet
verendra
Trygve Laugstøl