Forum: Mikrocontroller und Digitale Elektronik SPI-Kommunikation Atmega644 - ADS1118


von Eros (Gast)


Angehängte Dateien:

Lesenswert?

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
int main(void)
2
{
3
   uint16_t u16_measval;
4
5
   AdcExt_Init();
6
   u16_measval = AdcExt_Read();
7
}

Ausschnitt DrvAdc.c:
1
void AdcExt_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
  SPITransmit(CONFIG_MSB);
14
  SPITransmit(CONFIG_LSB);
15
  
16
  // SPI Interface resetten
17
  SET_EADC_SEL;
18
  
19
  // SPI disable
20
  SPIInit(DISABLE_SPI);
21
}
22
uint16_t AdcExt_Read(void)
23
{
24
  uint16_t u16_measVal;
25
  uint8_t u8_adcDataRegMSB, u8_adcDataRegLSB, u8_adcConfigRegMSB, u8_adcConfigRegLSB;
26
  
27
  // SPI enable
28
  SPIInit(ENABLE_SPI);
29
  
30
  // CS auf Low ziehen um ADC zu enablen
31
  DEF_EADC_SEL;
32
  CLR_EADC_SEL;
33
  _delay_us(3);
34
35
  
36
  u8_adcDataRegMSB = SPIReceive(CONFIG_MSB);
37
  u8_adcDataRegLSB = SPIReceive(CONFIG_LSB);
38
39
  
40
  // SPI Interface resetten
41
  SET_EADC_SEL;
42
  
43
  // SPI disable
44
  SPIInit(DISABLE_SPI);
45
  
46
  // 16-Bit Wert aus zwei 8-Bit Werten zusammenstellen
47
  u16_measVal = ((uint16_t)u8_adcDataRegMSB << 8) | u8_adcDataRegLSB;
48
  
49
  return u16_measVal;
50
}

Ausschnitt aus DrvAdc.h:
1
// Konfigurationsregister des externen ADC
2
#define CONFIG_MSB 0xC3    // Bits 15-8 des Config Registers des ADS1118, AIN0 enabled, Singleshot Mode, Mode Bit 1, FSR +/- 4.096 V
3
#define CONFIG_LSB 0x8A    // Bits 7-0 des Config Registers des ADS1118, 128SPS, ADC Mode enabled, Pullup Resistor enabled

Ausschnitt aus SPI.c:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
uint8_t SPITransmitting;
5
uint8_t gudt_ReceivedData;
6
7
void SPIInit(uint8_t u8_SPE)
8
{
9
  // MOSI, SCK, und SS pins als Ausgänge definieren
10
  DDRB |= (1 << PB5) | (1 << PB7) | (1 << PB4); 
11
  
12
  // MISO als Eingang definieren
13
  DDRB &= ~(1 << PB6);
14
  
15
  // SPI Register initialisieren
16
  SPCR =  (0 << SPIE)    |  // SPI Interrupt enable
17
      (u8_SPE << SPE)  |  // SPIE Enable
18
      (0 << DORD)    |  // Data order      --> 1 = LSB first, 0 = MSB first
19
      (1 << MSTR)    |  // Master/Slave select  --> 1 = Master Mode, 0 = Slave
20
      (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
void SPITransmit(uint8_t data)
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_t SPIReceive(uint8_t data)  // 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
  return SPDR;
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.

von Mitlesa (Gast)


Lesenswert?

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.

von Mitlesa (Gast)


Lesenswert?

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.

von Mitlesa (Gast)


Lesenswert?

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.

von Sascha W. (sascha-w)


Lesenswert?

@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

von Eros (Gast)


Angehängte Dateien:

Lesenswert?

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:
ADS1118  ATMEGA644
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..

von S. Landolt (Gast)


Lesenswert?

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?

von Sascha W. (sascha-w)


Lesenswert?

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

von Mitlesa (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

Ich hätte es als "gesetztes Ready-Flag" bezeichnet, aber wir meinen 
dasselbe, SPIF.

von Mitlesa (Gast)


Lesenswert?

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_t SPITransfer (uint8_t data)
2
{
3
  SPDR = data;       // Bidirektionalen Transfer starten
4
  while ( ! (SPSR & (1 << SPIF)));  // Warten bis Transfer abgeschlossen
5
  return SPDR;
6
}

von S. Landolt (Gast)


Lesenswert?

Genau!
  Alles andere mag für Spezialisten sein, die ein paar Systemtakte 
einsparen wollen/müssen.

von S. Landolt (Gast)


Lesenswert?

Es bleiben allerdings Fragezeichen:

> Das Schicken der Daten funktioniert einwandfrei
> Habe auch bereits mit dem Logic Analyzer nachgemessen
> Das Senden funktioniert einwandfrei

von Eros (Gast)


Lesenswert?

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
void SPITransmit(uint8_t data)
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_t SPIReceive(uint8_t data)  // 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
  return SPDR;
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.

von Eros (Gast)


Lesenswert?

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..

von Mitlesa (Gast)


Lesenswert?

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

von S. Landolt (Gast)


Lesenswert?

> 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.

von S. Landolt (Gast)


Lesenswert?

Hier Mitlesas Vorschlag in der Nomenklatur von Microchip (aus TB3215):
1
{
2
uint8_t SPI0_exchangeData(uint8_t data)
3
{
4
SPI0.DATA = data;
5
while (!(SPI0.INTFLAGS & SPI_IF_bm)) /* waits until data is exchanged*/
6
{
7
;
8
}
9
return SPI0.DATA;
10
}
11
}

von Eros (Gast)


Angehängte Dateien:

Lesenswert?

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_t SPITransfer (uint8_t data)
2
{
3
  SPDR = data;       // Bidirektionalen Transfer starten
4
  while ( ! (SPSR & (1 << SPIF)));  // Warten bis Transfer abgeschlossen
5
  return SPDR;
6
}

Dann rufe ich zunächst AdcExt_Init auf, um das Konfigurationsregister zu 
setzen:
1
void AdcExt_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:
1
uint16_t AdcExt_Read(void)
2
{
3
  uint16_t u16_measVal;
4
  uint8_t u8_adcDataRegMSB, u8_adcDataRegLSB, u8_adcConfigRegMSB, u8_adcConfigRegLSB;
5
  
6
  // SPI enable
7
  SPIInit(ENABLE_SPI);
8
  
9
  // CS auf Low ziehen um ADC zu enablen
10
  DEF_EADC_SEL;
11
  CLR_EADC_SEL;
12
  _delay_us(3);
13
14
  
15
  u8_adcDataRegMSB = SPITransfer(CONFIG_MSB);
16
  u8_adcDataRegLSB = SPITransfer(CONFIG_LSB);
17
18
  
19
  // SPI Interface resetten
20
  SET_EADC_SEL;
21
  
22
  // SPI disable
23
  SPIInit(DISABLE_SPI);
24
  
25
  // 16-Bit Wert aus zwei 8-Bit Werten zusammenstellen
26
  u16_measVal = ((uint16_t)u8_adcDataRegMSB << 8) | u8_adcDataRegLSB;
27
  
28
  return u16_measVal;
29
}

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.

von Mitlesa (Gast)


Lesenswert?

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.

von Mitlesa (Gast)


Lesenswert?

Also so etwa, mehr braucht es nicht. Die SPI Hardware muss
natürlich einmal vorher initialisiert werden.
1
void AdcExt_Init (void)
2
{
3
  uint8_t  temp1, 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
12
  SET_EADC_SEL;    // CS high
13
14
  // hier was mit temp1, temp2 machen
15
  // ......
16
}

von Patrick C. (pcrom)


Lesenswert?

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

von S. Landolt (Gast)


Lesenswert?

> 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
void AdcExt_Init (void)
2
{
3
  uint8_t  temp1, 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.

von Mitlesa (Gast)


Lesenswert?

S. Landolt schrieb:
> Danach sieht man weiter.

Danke sehr, S.!

von Mitlesa (Gast)


Lesenswert?

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.

von Mitlesa (Gast)


Lesenswert?

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!

von Sascha W. (sascha-w)


Lesenswert?

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

von S. Landolt (Gast)


Lesenswert?

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.

Beitrag #6323241 wurde von einem Moderator gelöscht.
Beitrag #6323312 wurde von einem Moderator gelöscht.
von Eros (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

> ... 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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Eros schrieb:
> Schaltbild ist eigentlich ganz simpel:
> ADS1118  ATMEGA644
> 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.

: Bearbeitet durch Moderator
von Mitlesa (Gast)


Lesenswert?

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.

von Pete K. (pete77)


Lesenswert?

Schaltplan und Layout wären auch nicht schlecht (siehe auch den 3. 
Beitrag).

: Bearbeitet durch User
von Eros (Gast)


Lesenswert?

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_t AdcExt_Xfer(uint8_t data)
2
{
3
  SPDR = data;
4
  while( ! (SPSR & (1 << SPIF)));
5
  return SPDR;
6
}

In der Funktion AdcExt_Read übertrage ich die 4 Bytes:
1
uint16_t AdcExt_Read(void)
2
{
3
  uint16_t u16_measVal;
4
  uint8_t u8_adcDataRegMSB, u8_adcDataRegLSB, u8_adcConfigRegMSB, u8_adcConfigRegLSB;
5
6
  // ADC SPI ENABLEN
7
  ADC_ENABLE;
8
  
9
  // ADC CS auf Low ziehen um ADC zu aktivieren
10
  CLR_EADC_SEL;
11
  _delay_ms(1);
12
  
13
  u8_adcDataRegMSB = AdcExt_Xfer(CONFIG_MSB);
14
  u8_adcDataRegLSB = AdcExt_Xfer(CONFIG_LSB);
15
  u8_adcConfigRegMSB = AdcExt_Xfer(CONFIG_MSB);
16
  u8_adcConfigRegLSB = AdcExt_Xfer(CONFIG_LSB);
17
18
  // CS auf High ziehen um ADC zu deaktivieren
19
  SET_EADC_SEL;
20
  //ADC SPI disablen
21
  ADC_DISABLE;
22
  
23
  // 16-Bit Wert aus zwei 8-Bit Werten zusammenstellen
24
  u16_measVal = ((uint16_t)u8_adcDataRegMSB << 8) | u8_adcDataRegLSB;
25
  
26
  return u16_measVal;
27
}

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 ;)

von Falk B. (falk)


Lesenswert?

Eros schrieb:
> Mit 1ms Delay funktioniert es aber sehr zuverlässig.

So ein Käse. Da ist was faul!

von Falk B. (falk)


Lesenswert?

>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.

von Eros (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von Eros (Gast)


Lesenswert?

Falk B. schrieb:
> Bestenfalls im Control Register, denn dort wird alles eingestellt. Mit
> Ausnahme von SPI2x. Wie sieht das MACRO aus?
1
#define BM_ADC_SCK    0x80  //PB7
2
#define BM_ADC_SI    0x20  //PB5
3
#define BM_ADC_SO    0x40  //PB6
4
#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
5
#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)

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...

von Falk B. (falk)


Lesenswert?

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!

von Mitlesa (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

> 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.

von Mitlesa (Gast)


Lesenswert?

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.

von Eros (Gast)


Lesenswert?

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.

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.