Guten Tag
Ich versuche die SPI Kommunikation zwischen einem 16-Bit ADC von TI -
genauer der ADS1118 - und meinem ATMEGA644 zum Laufen zu bringen. Das
Schicken der Daten funktioniert einwandfrei, allerdings scheint der ADC
einfach keine Daten ausspucken zu wollen. Habe auch bereits mit dem
Logic Analyzer nachgemessen, Clock vorhanden, Daten gehen raus, MISO
bleibt tot. Die Hardwareverbindungen habe ich schon mehrmals
nachgemessen und überprüft, sogar mal den ADC ersetzt... Ohne Erfolg, da
tut sich nichts.
Aussschnitt main.c:
1
intmain(void)
2
{
3
uint16_tu16_measval;
4
5
AdcExt_Init();
6
u16_measval=AdcExt_Read();
7
}
Ausschnitt DrvAdc.c:
1
voidAdcExt_Init(void)
2
{
3
// SPI enable
4
SPIInit(ENABLE_SPI);
5
6
// CS auf Low ziehen um ADC zu enablen
7
DEF_EADC_SEL;
8
CLR_EADC_SEL;
9
_delay_ms(1000);
10
_delay_us(3);
11
12
// Die zwei Bytes für das Konfigurationsregister des ADCs schicken.
(0<<CPOL)|// Clock Polarity --> 1 = SCK high when idle, 0 = SCK low when idle
21
(0<<CPHA)|// Clock Phase --> 1 = Sample on Trailing Edge, 0 = Sample on Leading Edge
22
(0<<SPR1)|// SPI Clock Rate Select
23
(1<<SPR0);// f_osc/8
24
SPSR=1;// Sets SPI2X Double Speed bit. SCK Frequency will be doubled when the SPI is in Master mode
25
26
// Die aktuellen Einstellungen löschen das SPI Interrupt Flag im Register SPSR,
27
// also wird das globale Flag genutzt um zu signalisieren, dass noch keine Übertragung stattfindet
28
SPITransmitting=0;
29
}
30
31
voidSPITransmit(uint8_tdata)
32
{
33
// Globales Flag abfragen, ob gerade eine Übertragung stattfindet
34
if(SPITransmitting)
35
{
36
while(!(SPSR&(1<<SPIF)));// Warten bis aktuelle Übertragung abgeschlossen
37
}
38
SPDR=data;// Übertragung starten
39
SPITransmitting=1;// Mit dem Flag kennzeichnen, dass eine Übertragung in Arbeit ist
40
}
41
42
uint8_tSPIReceive(uint8_tdata)// data ist in der Regel ein dummy byte --> 0
43
{
44
if(SPITransmitting)
45
{
46
while(!(SPSR&(1<<SPIF)));// Warten bis aktuelle Übertragung abgeschlossen
47
}
48
_delay_us(3);
49
50
51
SPDR=data;// Bidirektionalen Transfer starten
52
while(!(SPSR&(1<<SPIF)));// Warten bis Übertragung abgeschlossen
53
54
// Die aktuellen Einstellungen löschen das SPI Interrupt Flag im Register SPSR,
55
// also wird das globale Flag genutzt um zu signalisieren, dass noch keine Übertragung stattfindet
56
SPITransmitting=0;
57
returnSPDR;
58
}
Ausschnitt aus DrvGPIO.h:
1
/*********** PA4 ALS AUSGANG DEFINIEREN FÜR ADC CS ***************/
2
#define EADC_SEL (1<<PA4)
3
#define DEF_EADC_SEL DDRA |= EADC_SEL
4
#define SET_EADC_SEL PORTA |= EADC_SEL
5
#define CLR_EADC_SEL PORTA &=~EADC_SEL
Der Chip Select funktioniert, das habe ich bereits nachgemessen. Gemäss
Datenblatt S.25 des ADCs müsste ein 16Bit-Transmission Cycle genau so
funktionieren. Ich schicke das MSB des Konfigurationsregisters und
müsste das MSB des Dataregisters auslesen können. Danach schicke ich das
LSB des Konfigurationsregisters, um direkt im Anschluss das LSB des
Dataregisters auslesen zu können. Das Senden funktioniert einwandfrei,
allerdings bleibt DOUT vom ADC stets low. Gemäss Datasheet bedeutet das,
dass DANN Daten zum abholen anliegen müssten. Allerdings kann ich mit
dem Logic Analyzer keine Datenübertragung feststellen. Gar nichts. Das
macht in meinen Augen keinerlei Sinn und ich werkel nun schon seit einer
Woche daran. Nichts tut sich. Vielleicht hat einer von euch eine Idee
oder kann mir sagen, was genau ich falsch mache.
Eros schrieb:> Vielleicht hat einer von euch eine Idee> oder kann mir sagen, was genau ich falsch mache.
Nach dem Datenblatt auf Seite 26 und folgende musst du den ADC
erst mal konfigurieren.
Im Einschaltzustand befindet sich der Chip im Single-Shot-Mode
den du auch per Kommando erst auslösen musst. Einfach mal das
Datenblatt lesen. Manchen Leute sagen auch RTFM.
Sorry ich war ein wenig zu voreilig. Du willst ja erst mal
das Config-Register nur zurückbekommen ....
Zeig doch mal deinen Aufbau und das Schaltbild dazu.
Eros schrieb:> SPIInit(ENABLE_SPI);
Das ist gefährlich, da undurchsichtig. Du verwendest ENABLE_SPI
direkt als Variable in der Initialisierung der Bits. Du hast
auch nicht die Definition davon angegeben. Allgemein ist es un-
günstig nur Codefragemente zu zeigen. Zeige deinen volständigen
Code und poste ihn als Anhang.
@Eros,
ohne jetzt das DB gelesen zu haben. Bei SPI findet eine Transaktion
immer zwischen CS=L und CS=H statt. Das heißt wenn du ein Register lesen
willst sendest du hier eben die Adresse mit 2 Byte und anschließend 2
Dummybytes um die 16Bit des Registers zu lesen. Der Bus überträgt immer
Daten in beide Richtungen zur gleichen Zeit.
Sascha
Erstmal danke an alle für die raschen Antworten.
>Nach dem Datenblatt auf Seite 26 und folgende musst du den ADC>erst mal konfigurieren.
Das ist eigentlich genau DAS, was ich in meiner Funktion AdcExt_Init
mache:
1
// Die zwei Bytes für das Konfigurationsregister des ADCs schicken.
2
SPITransmit(CONFIG_MSB);
3
SPITransmit(CONFIG_LSB);
Das sich der ADC im Einschaltmodus in einem Defaultzustand befindet ist
mir durchaus bewusst.
>Sorry ich war ein wenig zu voreilig. Du willst ja erst mal>das Config-Register nur zurückbekommen ....
Nicht ganz. Ich versuche eine an AIN0 angelegte Spannung auszulesen. Das
Config Register muss ich dafür nicht auslesen. Daher nur die
16-Bit-Transmission. Allerdings wäre ich mal froh überhaupt IRGENDWAS
zurückzulesen.
Schaltbild ist eigentlich ganz simpel:
ADS1118ATMEGA644
DOUT MISO
DIN MOSI
SCK SCK
CS PA4
Mehr ist da nicht.
>Das ist gefährlich, da undurchsichtig. Du verwendest ENABLE_SPI>direkt als Variable in der Initialisierung der Bits. Du hast>auch nicht die Definition davon angegeben. Allgemein ist es un->günstig nur Codefragemente zu zeigen. Zeige deinen volständigen>Code und poste ihn als Anhang.
Okay undurchsichtig, das macht sicherlich Sinn. ENABLE_SPI ist 1 und
DISABLE_SPI ist 0. Die sind im Header des SPI Treibers definiert, das
habe ich vergessen reinzukopieren. Grundsätzlich kann ich schon den
ganzen Code hochladen, bin mir aber ziemlich sicher, dass es Aufwändiger
ist, sich durch den Quellcode zu arbeiten. Aber wenn das hilft nur allzu
gerne.
>Das heißt wenn du ein Register lesen willst sendest du hier eben die >Adresse mit
2 Byte und anschließend 2 Dummybytes um die 16Bit des Registers >zu lesen.
Das heisst ich sollte es mal so versuchen:
1
// Konfigurationsregister
2
SPITransmit(CONFIG_MSB);
3
SPITransmit(CONFIG_LSB);
4
// Dummy Bytes
5
u8_adcDataRegMSB=SPIReceive(0x0);
6
u8_adcDataRegLSB=SPIReceive(0x0);
Macht das Sinn? Das wäre dann aber eine 32-Bit-Transmission, die gemäss
Datasheet SO funktioniert wie im angehängten JPG. Ergo wären dann in
meinen Variablen u8_adcDataRegMSB/LSB ja dann einfach nur das
zurückgelesene ConfigRegister. Ich will ja aber das DataRegister. In
meinen Augen macht das, was TI da in das Datenblatt schreibt
grundsätzlich wenig Sinn für mich. Es mag sein, dass das Register vom
ADC beim Aufstarten Defaultwerte annimmt. Die interessieren ja aber
erstmal nicht. Gemäss Bild müsste ich ja dann bei der SPI Übertragung
einerseits das MSB vom Konfigurationsregister übertragen und
gleichzeitig bereits schon das MSB des Datenregisters erhalten. Woher
will denn der ADC wissen, was er da nun zu übertragen hat, wenn er noch
nichtmal das LSB vom Konfigurationsregister erhalten hat? Das erscheint
mir ein wenig unlogisch..
Vorab: diese kunstvoll-künstliche Aufspaltung von SPI in -Transmit und
-Receive ist mir zu undurchsichtig und ich halte sie für schlecht; es
gibt nur doch, sozusagen, nur ein 'SPItransceive'.
Es mag also sein, dass ich das falsch verstehe, aber:
1
SPITransmit(CONFIG_LSB);
2
3
// SPI Interface resetten
4
SET_EADC_SEL;
Hier wird mitten in der Übertragung das /CS high gesetzt, oder?
ok, ich dachte du willst das Configregister zurücklesen. Da das Teil
aber nur das eine Configregister hat passt das mit dem 16Bit Transfer
mit dem das Configr. geschrieben und gleichzeitig das Datenregister
gelesen wird.
was mich allerdings sutzig macht ist Punkt 9.5.5, dort wird auf
DOUT/DRDY (ganz SPI unüblich) das vorliegen neuer Daten signalisiert.
Was passiert wenn man vor DRDY Daten lesen will konnte ich auf die
Schnelle nicht finden.
Sascha
S. Landolt schrieb:> Hier wird mitten in der Übertragung das /CS high gesetzt, oder?
Ja richtig, denn er wartet nach dem Schreiben nicht auf das
gelöschte Busy-Flag im Statusregister.
S. Landolt schrieb:> Ich hätte es als "gesetztes Ready-Flag" bezeichnet, aber wir meinen> dasselbe, SPIF.
Ja hab mich fehlerhaft ausgedrückt.
Eigentlich müsste so eine Funktion ausreichen, Lesen und Schreiben.
1
uint8_tSPITransfer(uint8_tdata)
2
{
3
SPDR=data;// Bidirektionalen Transfer starten
4
while(!(SPSR&(1<<SPIF)));// Warten bis Transfer abgeschlossen
Es bleiben allerdings Fragezeichen:
> Das Schicken der Daten funktioniert einwandfrei> Habe auch bereits mit dem Logic Analyzer nachgemessen> Das Senden funktioniert einwandfrei
Mitlesa schrieb:> Eigentlich müsste so eine Funktion ausreichen, Lesen und Schreiben.> uint8_t SPITransfer (uint8_t data)> {> SPDR = data; // Bidirektionalen Transfer starten> while ( ! (SPSR & (1 << SPIF))); // Warten bis Transfer abgeschlossen> return SPDR;> }
Das ist genau das, was ich in meiner Funktion "SPITransmit" mache:
1
voidSPITransmit(uint8_tdata)
2
{
3
// Globales Flag abfragen, ob gerade eine Übertragung stattfindet
4
if(SPITransmitting)
5
{
6
while(!(SPSR&(1<<SPIF)));// Warten bis aktuelle Übertragung abgeschlossen
7
}
8
SPDR=data;// Übertragung starten
9
SPITransmitting=1;// Mit dem Flag kennzeichnen, dass eine Übertragung in Arbeit ist
10
}
In der Funktion "SPIReceive" genau so:
1
uint8_tSPIReceive(uint8_tdata)// data ist in der Regel ein dummy byte --> 0
2
{
3
if(SPITransmitting)
4
{
5
while(!(SPSR&(1<<SPIF)));// Warten bis aktuelle Übertragung abgeschlossen
6
}
7
_delay_us(3);
8
9
10
SPDR=data;// Bidirektionalen Transfer starten
11
while(!(SPSR&(1<<SPIF)));// Warten bis Übertragung abgeschlossen
12
13
// Die aktuellen Einstellungen löschen das SPI Interrupt Flag im Register SPSR,
14
// also wird das globale Flag genutzt um zu signalisieren, dass noch keine Übertragung stattfindet
15
SPITransmitting=0;
16
returnSPDR;
17
}
Somit wird durchaus gewartet, bis das Flag im Status Register gesetzt
ist, bevor ich den CS wieder auf high setze. Das Senden der Daten
funktioniert einwandfrei und kann auch genau so nachgemessen werden.
Zurück kommt trotzdem nichts. MISO bleibt low.
Grundsätzlich sehe ich das aber genau so, die Aufspaltung der Funktionen
Receive und Transmit macht wenig Sinn, da beim Senden ja gleichzeitig
immer auch etwas empfangen wird. Eine Funktion SPITransceive würde
sicherlich mehr Sinn machen.
Dennoch löst es das Problem leider nicht. Der ADC scheint seine Daten
nicht ausspucken zu wollen.
Sascha W. schrieb:> was mich allerdings sutzig macht ist Punkt 9.5.5, dort wird auf> DOUT/DRDY (ganz SPI unüblich) das vorliegen neuer Daten signalisiert.> Was passiert wenn man vor DRDY Daten lesen will konnte ich auf die> Schnelle nicht finden.
Unter Punkt 9.5.7.2 steht:
If Config Register data are not required to be readback, the ADS1118
conversion data can also be clocked out in
a short 16-bit data transmission cycle, as shown in Figure 42.
Therefore, CS must be taken high after the 16th
SCLK cycle. Taking CS high resets the SPI interface. The next time CS is
taken low, data transmission starts
with the currently buffered conversion result on the first SCLK rising
edge. If DOUT/DRDY is low when data
retrieval starts, the conversion buffer is already updated with a new
result. Otherwise, if DOUT/DRDY is high, the
same result from the previous data transmission cycle is read.
Das bedeutet wenn ich Daten lesen will, bevor DRDY low geht, werde ich
wieder dasselbe Resultat wie im vorherigen Conversion Cycle zurücklesen,
die Daten sind dann also nicht aktuell. Figure 42 ist übrigens das JPG,
dass ich oben gepostet habe mit dem 16 Bit Übertragungszyklus.
Grundsätzlich ist es genau das, was ich mache:
-AdcExt_Init aufrufen, daher wird CS low gesetzt, die 16-Bit für das
Config
Register geschickt, CS wieder high gesetzt
-AdcExt_Read aufrufen, CS wird wieder low gesetzt, dann schicke ich
erneut
dieselben Daten für das Config Register (damit der ADC für die nächste
Conversion bereits richtig initialisiert ist) und versuche dabei das
Dataregister auszulesen, von dort kommt allerdings nichts. Nach der
Übertragung setze ich CS wieder high..
Eros schrieb:> Das ist genau das, was ich in meiner Funktion "SPITransmit" mache
Nein! Und nochmals nein.
In SPITransmit(...) wartest du erst auf das Statusregister, dann
schreibst du ins Datenregister. Aber dir ist nicht bewusst dass
die Hardware erst den 8-Bit Transfer startet wenn das Register
beschrieben ist. Noch während die Hardware die 8 Bit überträgt
reisst du nach Rückkehr aus dieser Funktion am Chip Select (machst
ihn inaktiv, also high) und deaktivierst damit den ADS1118 der
noch mit Empfangen des Datenstroms beschäftigt ist.
Insofern ist Landolts Bermerkung haarscharf richtig:
S. Landolt schrieb:> Hier wird mitten in der Übertragung das /CS high gesetzt, oder?
Deswegen gilt auch der Ablauf meiner vorgeschlagenen SPI-Transfer
Funktion als korrekt:
- SPI Datenregister schreiben
- SPI Statusregister abwarten
- (Rückkehr aus Funktion)
- Chip Select deaktivieren
> Das ist genau das, was ich in meiner Funktion "SPITransmit" mache
Das sollten Sie sich nochmals genauer anschauen; und auch den
Logikanalysator zu Rate ziehen.
Mitlesa schrieb:> In SPITransmit(...) wartest du erst auf das Statusregister, dann> schreibst du ins Datenregister. Aber dir ist nicht bewusst dass> die Hardware erst den 8-Bit Transfer startet wenn das Register> beschrieben ist. Noch während die Hardware die 8 Bit überträgt> reisst du nach Rückkehr aus dieser Funktion am Chip Select (machst> ihn inaktiv, also high) und deaktivierst damit den ADS1118 der> noch mit Empfangen des Datenstroms beschäftigt ist.
Ihr habt absolut Recht. Die Funktion SPITransmit wird verlassen, noch
bevor gewartet wird dass SPIF gesetzt wird.
Ich habe nun das hier übernommen
1
uint8_tSPITransfer(uint8_tdata)
2
{
3
SPDR=data;// Bidirektionalen Transfer starten
4
while(!(SPSR&(1<<SPIF)));// Warten bis Transfer abgeschlossen
5
returnSPDR;
6
}
Dann rufe ich zunächst AdcExt_Init auf, um das Konfigurationsregister zu
setzen:
1
voidAdcExt_Init(void)
2
{
3
// SPI enable
4
SPIInit(ENABLE_SPI);
5
6
// CS auf Low ziehen um ADC zu enablen
7
DEF_EADC_SEL;
8
CLR_EADC_SEL;
9
_delay_ms(1000);
10
_delay_us(3);
11
12
// Die zwei Bytes für das Konfigurationsregister des ADCs schicken.
13
SPITransfer(CONFIG_MSB);
14
SPITransfer(CONFIG_LSB);
15
16
// SPI Interface resetten
17
SET_EADC_SEL;
18
19
// SPI disable
20
SPIInit(DISABLE_SPI);
21
}
Im Anschluss dann AdcExt_Read, um die Daten zurückzulesen:
Das Resultat bleibt allerdings dasselbe. Es findet kein Datenaustausch
statt. Nun müsste der Transfer ja abgeschlossen sein, wenn ich CS wieder
high ziehe oder?
Ich kann mit dem Logikanalyzer erkennen, dass Daten rausgehen.. Aber
zurück kommt nichts.
Ich habe mal das Bild hochgeladen
D0 ist SCLK
D1 ist MISO
D2 ist MOSI hier sieht man auch, dass offenbar Daten rausgehen
D3 ist aktuell nicht belegt.
Sorry aber mit diiser Unsitte dauernd SPIInit() aufzurufen
bringst du die Konsistenz deiner Hardware völlig ausser Tritt.
SPIInit() ruft man einmal beim Programmstart auf und dann nie
mehr!
Ebenso ist das Makro DEF_EADC_SEL unsinning es jedesmal auszu-
führen.
Ich würde mir beim Init bereits durch Debugger oder Testprints
ansehen ob ich etwas vom Slave zurückbekomme was nicht null ist.
Ich kann mich irren, aber muszz MISO kein pullup haben ?
Dann geht MISO sowieso immer hoch wenn CS nicht aktiv ist
Anfangen mit einfachste comm, also nur status register auslesen
> nur status register auslesen
Dem schließe ich mich an, also '9.5.7.1 32-Bit Data Transmission Cycle',
in Ergänzung von Mitlesa:
1
voidAdcExt_Init(void)
2
{
3
uint8_ttemp1,temp2;
4
5
CLR_EADC_SEL;// CS low
6
_delay_us(3);
7
8
// Konfigurationsregister beschreiben
9
temp1=SPITransfer(CONFIG_MSB);
10
temp2=SPITransfer(CONFIG_LSB);
11
temp1=SPITransfer(CONFIG_MSB);
12
temp2=SPITransfer(CONFIG_LSB);
13
14
SET_EADC_SEL;// CS high
15
}
Nun muss in temp1 0xC3 sowie in temp2 0x8A stehen.
(The Config register setting written in the first two bytes of a 32-bit
transmission cycle is read back in the last two bytes of the same cycle)
Danach sieht man weiter.
Das Makro
DEF_EADC_SEL;
führt man auch genau einmal aus, am besten bei der
SPI-Initialisierung.
Aber es ist natürlich im Zusammenhang mit diesen Änderungen
wichtig dass es an irgendeiner Stelle gemacht wird, was vorher
vielleicht untergegangen ist.
Die plötzliche Stille die jetzt gerade auftritt ist
symptomatisch für (eines wird schon zutreffen):
a) der TO hat sich aus Verzweiflung aus dem 20. Stockwerk
eines Hochhauses gestürzt und kann gesundheitsbedingt nicht
mehr antworten.
oder
b) der TO hat sein Problem gelöst und ist dermassen begeistert
über seine Leistung (die natürlich in keinster Weise mit der
Abhandlung hier im Forum koreliert!) dass er alles um sich herum
vergessen hat und nur noch mit Stolz geschwellter Brust herumläuft.
oder
c) der TO hat mal wieder keine Ahnung von
https://www.mikrocontroller.net/articles/Netiquette
im Speziellen darin dass zu einem Thread auch ein Happy End in
Form einer Erfolgs- oder Fehlmeldung gehört.
Dass man - wenn einem geholfen wurde - sich auch für die heissen
Tipps bedanken kann ist natürlich völlig abwegig darüber nach-
zudenken. Das wäre echt zu viel verlangt!
Eros schrieb:> Ich kann mit dem Logikanalyzer erkennen, dass Daten rausgehen.. Aber> zurück kommt nichts.>> Ich habe mal das Bild hochgeladen> D0 ist SCLK> D1 ist MISO> D2 ist MOSI hier sieht man auch, dass offenbar Daten rausgehen> D3 ist aktuell nicht belegt.
na immerhin zieht der AD MISO auf LOW, macht 0x0000 als Ergebnis.
Wenn du schon noch einen Kanal hast, dann klemm den doch mal an CS.
Sascha
Spielt zum jetzigen Zeitpunkt der Fehlersuche vielleicht keine Rolle,
aber:
Wenn ich mir 'Figure 1. Serial Interface Timing' im Datenblatt anschaue,
so scheint es sich um 'sample on trailing (falling) edge' zu handeln,
was aber Eros' SPI-Initialisierung mit
> (0 << CPHA) | // Clock Phase --> 1 = Sample on Trailing Edge, 0 = Sample on
Leading Edge
widerspräche.
Mitlesa schrieb:> Die plötzliche Stille die jetzt gerade auftritt ist> symptomatisch für (eines wird schon zutreffen):>> a) der TO hat sich aus Verzweiflung aus dem 20. Stockwerk> eines Hochhauses gestürzt und kann gesundheitsbedingt nicht> mehr antworten.>> oder>> b) der TO hat sein Problem gelöst und ist dermassen begeistert> über seine Leistung (die natürlich in keinster Weise mit der> Abhandlung hier im Forum koreliert!) dass er alles um sich herum> vergessen hat und nur noch mit Stolz geschwellter Brust herumläuft.>> oder>> c) der TO hat mal wieder keine Ahnung von>> https://www.mikrocontroller.net/articles/Netiquette>> im Speziellen darin dass zu einem Thread auch ein Happy End in> Form einer Erfolgs- oder Fehlmeldung gehört.
Einen guten Morgen wünsche ich allen. Schade, dass man andere hier
offenbar mit Aussagen wie "hat mal wieder keine Ahnung" als blöd
hinstellen muss, nur weil die Kenntnisse im Bereich
Microcontrollerprogrammierung noch nicht so fundiert sind und man sich
halt dann doch irgendwann mal an Leute mit mehr Erfahrung wendet. Andere
als Stolz und Eitel (und im selben Atemzug dann als blöd) zu bezeichnen
und dann auch noch auf Etikette hinzuweisen ist schon next Level.
An die anderen, die ein wenig mehr Geduld haben: Ich bin gestern leider
nicht mehr dazu gekommen, die vorgeschlagenen Tipps auszutesten, werde
das allerdings heute noch machen und dann ein entsprechendes Feedback
geben.
S. Landolt schrieb:> Wenn ich mir 'Figure 1. Serial Interface Timing' im Datenblatt anschaue,> so scheint es sich um 'sample on trailing (falling) edge' zu handeln,> was aber Eros' SPI-Initialisierung mit>> (0 << CPHA) | // Clock Phase --> 1 = Sample on Trailing Edge, 0 = Sample on> Leading Edge> widerspräche.
Das ist sicherlich noch ein guter Hinweis, danke dafür.
> ... heute noch machen ...
Na, dann besteht ja Hoffnung, das Problem in vernünftiger Zeit vom Tisch
zu bekommen.
Wenn ich die Vorschläge zusammenfassen darf: ein 32-bit-Transfer, und
davon ein Bild mit dem Logikanalysator mit allen SPI-Leitungen sollte
uns ein gutes Stück weiterbringen.
Eros schrieb:> Schaltbild ist eigentlich ganz simpel:> ADS1118ATMEGA644> DOUT MISO> DIN MOSI> SCK SCK> CS PA4> Mehr ist da nicht.
Dann ist es ja einfach: Masse fehlt. Und die Versorgungsspannung...
Eros schrieb:> Der Chip Select funktioniert, das habe ich bereits nachgemessen.
Hast du ein Oszilloskop? Oder einen Logikanalyzer?
Dann könntest du einfach mal das Timing der 4 beteiligten Signale messen
und kontrollieren, ob es dem im Datenblatt entspricht. Solange es das
nicht tut, kann alles passieren.
Eros schrieb:> mit Aussagen wie "hat mal wieder keine Ahnung" als blöd> hinstellen muss, nur weil die Kenntnisse im Bereich> Microcontrollerprogrammierung noch nicht so fundiert sind
Wer lesen kann ist klar im Vorteil. Ich fasse meine Aussage
nochmal in Kurzform (man beachte den Link im hervorgehobenen
Wort):
---------------------------------------------------------------
c) der TO hat mal wieder keine Ahnung von Netiquette,
im Speziellen darin dass zu einem Thread auch ein Happy End in
Form einer Erfolgs- oder Fehlmeldung gehört.
---------------------------------------------------------------
Von einer Ahnunglosigkeit wie du sie hineininterpretierst
habe ich niemals gesprochen! Wer lesen kann ist klar im Vorteil.
So meine lieben Freunde der gepflegten Digitaltechnik.
Ich habe die Vorschläge vom Herrn Landolt wie auch von Mitlesa
umgesetzt.
Die Übertragung ist dabei sehr einfach gehalten:
1
uint16_tAdcExt_Xfer(uint8_tdata)
2
{
3
SPDR=data;
4
while(!(SPSR&(1<<SPIF)));
5
returnSPDR;
6
}
In der Funktion AdcExt_Read übertrage ich die 4 Bytes:
Der ADC wird zu Beginn des Programms initialisiert und CS High gesetzt,
damit er mir nicht ständig dazwischenschwafelt (was nämlich auch so eine
Sache war), Dank an der Stelle an Mitlesa.
Mit dem Makro ADC Enable werden die SPI-Leitungen als Aus- bzw Eingang
definiert (SCL/MOSI als Ausgänge, MISO als Eingang) und das Status
Register für die SPI Kommunikation korrekt gesetzt (SPI Enable, CPHA 1,
CPOL 0, wie im Datenblatt gefordert, danke für den Hinweis an Herrn
Landolt). Mit dem Makro ADC_DISABLE wird SPI auch wieder disabled. Des
weiteren war die Zeit mit 3us Delay sehr kurz, so dass es teilweise
funktioniert hat, teilweise aber der Output zu wenig schnell geschaltet
hat, CS noch HIGH war und das Programm bereits die Übertragung gestartet
hat. Im Datenblatt wird angegeben, dass zwischen CS Low und Übertragung
mindestens 100ns vergehen sollten, dachte ich wäre mit 3us mehr als
übers Ziel hinaus. Allerdings braucht der uC ja auch seine Zeit, bis der
Eingang schaltet. Mit 1ms Delay funktioniert es aber sehr zuverlässig.
Fazit der ganzen Geschichte: Datenaustausch im Datenblatt grundsätzlich
richtig verstanden, allerdings eine Menge Fehler bei der Übertragung
gemacht, was CS angeht. Teilweise bereits wieder auf High gesetzt,
während die Übertragung lief und teilweise noch nicht auf Low während
die Übertragung bereits lief.
Nun aber läuft es und ich denke ich konnte eine Menge über die SPI
Kommunikation lernen. Vielen Dank an alle und ich hoffe ihr nehmt es mir
nicht übel, wenn ich trotzdem mit Stolz geschwellter Brust herumlaufe ;)
>Mit dem Makro ADC Enable werden die SPI-Leitungen als Aus- bzw Eingang>definiert (SCL/MOSI als Ausgänge, MISO als Eingang) und das Status>Register für die SPI Kommunikation korrekt gesetzt (SPI Enable, CPHA 1,>CPOL 0, wie im Datenblatt gefordert,
Noch so ein Käse. Das macht man EINMALIG zum Programmstart und dann NIE
wieder. Bei der Sache kann man sich, je nach Konstellation auch ins Knie
schiessen, vor allem mit dem SS Ausgang. Der MUSS als Ausgang definiert
sein, bevor das SPI als MAster aktiviert wird. Siehe Datenblatt SS Pin
functionality.
>uint16_t AdcExt_Xfer(uint8_t data)>{
Warum 16 Bit? SPI ist vor allem beim AVR nur 8 Bit.
Falk B. schrieb:> Noch so ein Käse. Das macht man EINMALIG zum Programmstart und dann NIE> wieder. Bei der Sache kann man sich, je nach Konstellation auch ins Knie> schiessen, vor allem mit dem SS Ausgang. Der MUSS als Ausgang definiert> sein, bevor das SPI als MAster aktiviert wird. Siehe Datenblatt SS Pin> functionality.
Da hängen noch 3 andere Bauteile am SPI, die jeweils unterschiedliche
Konfigurationen im Status Register bekommen. Zumal ich den ADC-Treiber,
so wie auch die Treiber der anderen Bausteine gerne so geschrieben
hätte, dass ich sie problemlos auch in andere Projekte einbinden kann.
Für dich mag das Käse sein, für mich macht es Sinn so.
Falk B. schrieb:>>Mit dem Makro ADC Enable werden die SPI-Leitungen als Aus- bzw> Eingang>>definiert (SCL/MOSI als Ausgänge, MISO als Eingang) und das Status>>Register für die SPI Kommunikation korrekt gesetzt (SPI Enable, CPHA 1,>>CPOL 0, wie im Datenblatt gefordert,>> Noch so ein Käse. Das macht man EINMALIG zum Programmstart und dann NIE> wieder. Bei der Sache kann man sich, je nach Konstellation auch ins Knie> schiessen, vor allem mit dem SS Ausgang. Der MUSS als Ausgang definiert> sein, bevor das SPI als MAster aktiviert wird. Siehe Datenblatt SS Pin> functionality.>>>uint16_t AdcExt_Xfer(uint8_t data)>>{>> Warum 16 Bit? SPI ist vor allem beim AVR nur 8 Bit.
Der SPI mag 8 Bit sein, der ADC ist es nicht. Scheint aber ein
Überbleibsel meiner Aufräumaktion zu sein, da ich MSB und LSB vorher in
dieser Funktion zusammengerechnet und zurückgegeben habe. Danke für den
Hinweis.
Eros schrieb:> Falk B. schrieb:>> Noch so ein Käse. Das macht man EINMALIG zum Programmstart und dann NIE>> wieder. Bei der Sache kann man sich, je nach Konstellation auch ins Knie>> schiessen, vor allem mit dem SS Ausgang. Der MUSS als Ausgang definiert>> sein, bevor das SPI als MAster aktiviert wird. Siehe Datenblatt SS Pin>> functionality.>> Da hängen noch 3 andere Bauteile am SPI, die jeweils unterschiedliche> Konfigurationen im Status Register bekommen.
Bestenfalls im Control Register, denn dort wird alles eingestellt. Mit
Ausnahme von SPI2x. Wie sieht das MACRO aus?
> Zumal ich den ADC-Treiber,> so wie auch die Treiber der anderen Bausteine gerne so geschrieben> hätte, dass ich sie problemlos auch in andere Projekte einbinden kann.> Für dich mag das Käse sein, für mich macht es Sinn so.
Jaja. Dumm nur, das DIESE Funktion NIE 16 Bit werte liefern wird.
Bestenfalls eine übergeordnete Funktion, welche 16 Bit ADC-Werte
ausliest.
Ich wage zu behaupten, daß mit deinem CS-Signal was nicht stimmt.
Möglicherweise ist das Pin als EINGANG konfiguriert und du schaltest nur
unbewußt den internen Pull-Up Widerstand ein und aus. Dann sind die
Schaltflanke SCHNARCHLANGSAM, vor allem die steigende Flanke. Wenn da
nicht irgend ein Leckstrom auf LOW zieht, geht das Signal nie auf LOW.
Schau dir die Signale mit einem Oszi an, ein Logicanalyser ist hier
blind.
Falk B. schrieb:> Ich wage zu behaupten, daß mit deinem CS-Signal was nicht stimmt.> Möglicherweise ist das Pin als EINGANG konfiguriert und du schaltest nur> unbewußt den internen Pull-Up Widerstand ein und aus.
1
#define EADC_SEL (1<<PA4)
2
#define DEF_EADC_SEL DDRA |= EADC_SEL
3
#define SET_EADC_SEL PORTA |= EADC_SEL
4
#define CLR_EADC_SEL PORTA &=~EADC_SEL
CS funktioniert meiner Meinung nach einwandfrei...
Eros schrieb:> Falk B. schrieb:>> Bestenfalls im Control Register, denn dort wird alles eingestellt. Mit>> Ausnahme von SPI2x. Wie sieht das MACRO aus?> #define BM_ADC_SCK 0x80 //PB7> #define BM_ADC_SI 0x20 //PB5> #define BM_ADC_SO 0x40 //PB6> #define ADC_ENABLE DDRB|=(BM_ADC_SCK|BM_ADC_SI|BM_ADC_SO);SPSR => (1<<SPI2X);SPCR => (1<<SPE)|(1<<MSTR)|(0<<SPR0)|(0<<SPR1)|(0<<CPOL)|(1<<CPHA)|(0<<DORD);gu8
_Tmp=SPSR;gu8_Tmp=SPDR
> #define ADC_DISABLE SPCR = 0; PORTB> &=~(BM_ADC_SCK|BM_ADC_SI|BM_ADC_SO);DDRB &=> ~(BM_ADC_SCK|BM_ADC_SI|BM_ADC_SO)
Ohjemine! Glaubst du allen Ernstes, mit diesem Makro-Unsinn irgend etwas
sinnvolles zu bewirken? Zu allererst sollte ein Programm sauber
strukturiert, lesbar und vor allem funktional KORREKT sein! Dann kann
man irgendwann über Optimierungen nachdenken!
https://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Prinzipien_der_Optimierung
Und warum in aller Welt glaubst du, permanent die IOs umkonfigurieren zu
müssen? Das muss man nicht! Bestenfalls die Einstellung für den SPI-Mode
und den SPI-Taktteiler umstellen!
> Falk B. schrieb:>> Ich wage zu behaupten, daß mit deinem CS-Signal was nicht stimmt.>> Möglicherweise ist das Pin als EINGANG konfiguriert und du schaltest nur>> unbewußt den internen Pull-Up Widerstand ein und aus.> #define EADC_SEL (1<<PA4)> #define DEF_EADC_SEL DDRA |= EADC_SEL> #define SET_EADC_SEL PORTA |= EADC_SEL> #define CLR_EADC_SEL PORTA &=~EADC_SEL
Völliger Käse! Das IO-Pin für CS muss nicht dauern von Ausgang auf
Eingang umgestellt werden!
> CS funktioniert meiner Meinung nach einwandfrei...
Jaja, meinen und glauben kann man viel. WISSEN kann man nur durch
kritischens MESSEN! Tu das!
Falk B. schrieb:> Noch so ein Käse. Das macht man EINMALIG zum Programmstart und dann NIE> wieder. Bei der Sache kann man sich, je nach Konstellation auch ins Knie> schiessen
Bei solchen Dingen die beharrlich zäh im Sourcecode verbleiben
drängt sich dann doch allmählich der Verdacht auf Starrsinn
bzw. Beratungsresistenz auf. Insbesondere weil bereits schon
früh darauf hingewiesen wurde.
Mitlesa schrieb:> Sorry aber mit diiser Unsitte dauernd SPIInit() aufzurufen> bringst du die Konsistenz deiner Hardware völlig ausser Tritt.>> SPIInit() ruft man einmal beim Programmstart auf und dann nie> mehr!>> Ebenso ist das Makro DEF_EADC_SEL unsinning es jedesmal auszu-> führen.
Ich weiß nicht - also ich sehe nur ein paar Definitionen, aber nicht,
wie oft sie in Eros' aktuellem Programm verwendet werden.
Und dass letzteres vermutlich alles andere als optimal ist - je nun,
Hauptsache ist doch, dass es erstmal läuft, worüber er sich freuen kann
(und ich mich mit ihm). Wenn er Unterstützung bei der Optimierung
wünscht/benötigt, wird er sich schon melden.
Dieser aufkommende leicht aggressive Unterton aber ärgert mich.
S. Landolt schrieb:> Hauptsache ist doch, dass es erstmal läuft, worüber er sich freuen kann
Wenn er 1 MILLISEKUNDE nach dem Aktivieren des Chip select warten muss,
damit die Übertragung "funktioniert", läuft da gehörig was schief.
> Dieser aufkommende leicht aggressive Unterton aber ärgert mich.
Diese permanente Ignoranz gegenüber sachlicher Kritik und Hinweisen erst
recht.
> permanente Ignoranz
Schließen Sie das aus diesem einen Satz von ihm
> CS funktioniert meiner Meinung nach einwandfrei...
? Da irrt er vermutlich, aber "permanente Ignoranz"? Sehe ich nicht so.
Meine Erkenntnis des heutigen Tages:
Probleme die auf Beratungsresistente, Starrsinnige, Ignoranten,
Unbelehrbaren beruhen bzw. zurückzuführen sind, sind weitaus
schwieriger zu lösen als massive Hardware- oder Software-Probleme
die eindeutig und klar dokumentiert sind.
Unabhängig davon, was hier genau das Thema ist, ist es immer so, dass
der Ton die Musik macht. Wenn man von sachlicher Kritik spricht, im
selben Atemzug die Arbeit eines anderen aber als Käse und Unsinn
bezeichnet (auch unabhängig davon, ob es nun so ist oder nicht), dann
braucht man sich nicht wundern, wenn solches mit Starrsinn, Ignoranz
oder Sturheit quittiert wird. Und das zieht sich so durchs ganze Leben.
So spricht man meiner Meinung nach weder mit Angestellten, noch mit
Vorgesetzten und schon gar nicht mit dem Lebenspartner. Aber jeder hat
da wohl seine eigene Vorgehensweise.
Dennoch bedanke ich mich und wünsche allen einen angenehmen Start in die
Woche. Ich denke dieser Thread hier kann geschlossen werden.