Forum: Mikrocontroller und Digitale Elektronik komisches SPI Verhalten Arduino Uno /ATMega328p)


von Dennis (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Leute,

so langsam bin ich echt am Verzweifeln. Ich versuche nun seit Stunden 
die SPI-Schnittstelle beim Arduino Uno zum laufen zu bekommen, um einen 
12-Bit DA-Wandler des Typs MCP4821 anzusprechen. Ich bin mir bei der 
Initialisierung der spi eigentlich sehr sicher alles richtig gemacht zu 
haben. Nichts desto Trotz möchte ich euch bitten mal kurz drüber zu 
schauen:
1
void spi_Init(){
2
  
3
  
4
  /** Set the CS-Pins as Output | Set Shutdown Pin output */
5
  DDRD |= (1<<DDD6)|(1<<DDD5)|(1<<DDD4);
6
  /** Set CS-Pins High --> no communication|shutdown mode off */
7
  PORTD|= (1<<CS1)|(1<<CS2)|(1<<PD4);
8
  /** Set MOSI, SCK, SS Output */
9
  DDRB |= (1<<DDB3)|(1<<DDB5)|(1<<DDB2);
10
  /** Enable SPI | Master Mode | prescaler 4 */
11
  SPCR |= (1<<SPE)|(1<<MSTR);
12
}

so sieht erst mal die Initialisierung der Schnittstelle aus.
in der main wird nun zum Test einmalig folgendes gemacht:
1
uint16_t val = 3000;
2
3
int main(void)
4
{
5
        /** start communication */
6
        PORTD &= !(1<<PD5);
7
8
        /** send command-bits and high-byte */
9
        SPDR = (0x10|highByte(val));
10
        while(!(SPSR&(1 << SPIF)));
11
12
        /** send low-byte */
13
        spi_send(lowByte(val));
14
        while(!(SPSR&(1 << SPIF)));
15
16
        /** end communication */
17
        PORTD |= (1<<PD5);
18
}

die beiden Makros mit highByte und lowByte sind aus der 
Arduino-Bibliothek abgeschrieben, ansonsten habe ich aber versucht alles 
ohne die Wiring-Funktionen zu lösen. die 0x10h die im ersten Sendelauf 
mit dem Spannungswert verodert werden sind commandbits für den DA, dann 
folgen 12 bit an Daten.
Was mich nun so verwirrt seht ihr im mitgeliefertern oszi-screenshot:

CH1 - Chip-Select (PD5)
CH2 - MOSI
CH3 - Vout des DA
CH4 - SCK

Die Frequenz der Clock stimmt nicht mit der eingestellten überein und 
nach drei Takten kommt kein ClK-Signal mehr raus? Außerdem wird kein 
einziges Bit gesendet während der "Übertragung". Hat einer eine Idee was 
da schief läuft?

Danke und schon mal Sorry im Voraus falls ich meine Hausaufgaben nicht 
gemacht hab.

mfg,
Dennis

von Rainer U. (r-u)


Lesenswert?

Sende doch erstmal einfach ein Byte, z.B. (hex) 55 oder AA, da brauchst 
Du Dich um das SPIF nicht zu kümmern und solltest ein MOSI-Signal mit 
der halben Frequenz der Clock sehen.

Und lies mal im Datenblatt - vielleicht ist bei SPCR noch mehr 
einzustellen.

von Falk B. (falk)


Lesenswert?

@Dennis (Gast)

>so langsam bin ich echt am Verzweifeln. Ich versuche nun seit Stunden
>die SPI-Schnittstelle beim Arduino Uno zum laufen zu bekommen,

Warum nutzt du nicht die Arduino-Funktionen?

>void spi_Init(){

  /** Set CS-Pins High --> no communication|shutdown mode off */
  PORTD|= (1<<CS1)|(1<<CS2)|(1<<PD4);
  /** Set MOSI, SCK, SS Output */
  DDRB |= (1<<DDB3)|(1<<DDB5)|(1<<DDB2);

Beim AVR MUSS das SS-Pin als Ausgang geschaltet werden, sond geht das 
nicht! Steht auch in der Arduino-Doku. Ausserdem sit SCLK PB1, nicht 
PB5!

https://www.arduino.cc/en/Reference/SPIBegin

: Bearbeitet durch User
von Sajuuk (Gast)


Lesenswert?

Falk B. schrieb:
> Beim AVR MUSS das SS-Pin als Ausgang geschaltet werden, sond geht das
> nicht!

Das stimmt so nicht ganz. Im Datenblatt des ATmega328P steht dazu: 
"Sollte der die SPI im Master Mode konfiguriert sein kann der SS-Pin 
frei konfiguriert werden (also als Input oder Output). Ist der SS-Pin 
als Input konfiguriert, muss man allerdings dafür sorgen das er High 
Pegel hat. Sollte die SPI als Master und der SS-Pin als Input 
konfiguriert sein und man bekommt am SS-Pin ein Low Signal so wird die 
SPI automatisch in den Slave-Mode zurückgesetzt."

> Steht auch in der Arduino-Doku. Ausserdem sit SCLK PB1, nicht
> PB5!

Laut Datenblatt ist PB5 SCK

Hast du irgendwas an der ICSP-Schnittstelle angeschlossen?

von Falk B. (falk)


Lesenswert?

@Sajuuk (Gast)

>> Steht auch in der Arduino-Doku. Ausserdem sit SCLK PB1, nicht
>> PB5!

>Laut Datenblatt ist PB5 SCK

Ja?

https://www.arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf

von Falk B. (falk)


Lesenswert?

Ahhh, Ich Depp. Ich hab auf den ATmega16U2 geschaut, der ist aber nur 
der Programmieradapter!

Ok, dann stimmt die Initialisierung des OP.

von Rudolph (Gast)


Lesenswert?

Sajuuk schrieb:
> Ist der SS-Pin als Input konfiguriert,
> muss man allerdings dafür sorgen das er High Pegel hat.

Was macht man mit einem Input-Pin der nur High-Pegel haben darf? :-)

von Falk B. (falk)


Lesenswert?

@ Rudolph (Gast)

>> Ist der SS-Pin als Input konfiguriert,
>> muss man allerdings dafür sorgen das er High Pegel hat.

>Was macht man mit einem Input-Pin der nur High-Pegel haben darf? :-)

Konstantenspeicher!

von Marco G. (grmg2010)


Lesenswert?

Neben dem SS-Pin, der wie bereits geschrieben wurde als Ausgang 
geschaltet sein muss, ist die Polarität des Signals(Signalbeginn bei 
steigender oder fallender Flanke)

von Sajuuk (Gast)


Lesenswert?

Rudolph schrieb:
> Was macht man mit einem Input-Pin der nur High-Pegel haben darf? :-)

MM...Gute Frage. Vielleicht ist die Platine ja nur ein Teil eines 
Modularen Aufbaus und ich möchte das jedes Modul für sich autark läuft. 
Kombiniert man mehrere Module möchte ich ja nur einen Master haben. Ist 
der SS-Pin nun als Input geschaltet hat man so natürlich ne einfache 
Möglichkeit, dass in der Hirarchie niedrigere Modul in den Slave-Mode zu 
zwingen.
Aber wir schweifen glaub ich grad ab... ;-)

Es ist natürlich besser für die Anwendung des OP den SS-Pin im 
SPI-Master-Mode als Output zu konfigurieren. Das hat der OP ja auch 
getan.

von Sajuuk (Gast)


Lesenswert?

Marco G. schrieb:
> Neben dem SS-Pin, der wie bereits geschrieben wurde als Ausgang
> geschaltet sein muss, ist die Polarität des Signals(Signalbeginn bei
> steigender oder fallender Flanke)

Wenn du dir die Initialisierung anschaust wirst du festellen das die SPI 
im Mode 0 ist. Also Bitübertragung bei steigender Flanke. Das passt für 
den  MCP4821.

von Dennis (Gast)


Lesenswert?

Hallo nochmal,

danke schonmal für eure Ideen. Vorweg noch eine kleine Ergänzung zum 
code aus meinem ersten Beitrag:

die Pins CS1 und CS2 sind natürlich PD5 und PD6, das hab ich nur wegen 
der Handhabung so definiert. Und die Funktion spi_send(value) macht 
nichts anderes wie die beiden Zeilen darüber, hab nur vergessen das 
abzuändern. Nur falls Verwirrung aufkommen sollte. Nun zu euren 
Vorschlägen:

Rainer U. schrieb:
> Sende doch erstmal einfach ein Byte, z.B. (hex) 55 oder AA, da
> brauchst
> Du Dich um das SPIF nicht zu kümmern und solltest ein MOSI-Signal mit
> der halben Frequenz der Clock sehen.

das hab ich ausprobiert, leider kommt das selbe Ergebnis im scope.

Falk B. schrieb:

> Warum nutzt du nicht die Arduino-Funktionen?

Ich hab mir mal die Anleitung in der reference durchgelesen, habs aber 
ehrlich gesagt nicht so ganz durchblickt wie die das machen. Und im 
Atmel Datenblatt is es ja auch eigentlich wirklich gut erklärt und das 
code-beispiel zur Initialisierung kann man ja auch fast abschreiben.

Sajuuk schrieb:

> Wenn du dir die Initialisierung anschaust wirst du festellen das die SPI
> im Mode 0 ist. Also Bitübertragung bei steigender Flanke. Das passt für
> den  MCP4821.

Habe unabhängig davon die SPI-Pins auch direkt am Arduino abgegriffen. 
Selbes Ergebnis...

von Falk B. (falk)


Lesenswert?

@Dennis (Gast)

>> Warum nutzt du nicht die Arduino-Funktionen?

>Ich hab mir mal die Anleitung in der reference durchgelesen, habs aber
>ehrlich gesagt nicht so ganz durchblickt wie die das machen.

Bitte? Was kann einfacher sein als ein spi.begin() und spi.transfer()?
Und vor allem, das funktioniert!

In deinem Osziscreenshot sind Kanal 1 und 2 identisch, da stimmt was 
nicht.
Kurzschlüsse?

von holger (Gast)


Lesenswert?

>        /** start communication */
>        PORTD &= !(1<<PD5);

        PORTD &= ~(1<<PD5);

von Dennis (Gast)


Lesenswert?

Falk B. schrieb:

>
> Bitte? Was kann einfacher sein als ein spi.begin() und spi.transfer()?
> Und vor allem, das funktioniert!

Habs probiert mit den Arduino Funktionen --> gleiches Bild wieder

> In deinem Osziscreenshot sind Kanal 1 und 2 identisch, da stimmt was
> nicht.
> Kurzschlüsse?

Wenn ein Kurzschluss vorliegen sollte, dann eigentlich nur auf dem 
Arduino selbst, da ich ja den D/A schon weggehängt hab und immernoch 
dieselben Symptome vorliegen. Aber auch da scheint keiner vorzuliegen...

holger schrieb:

>>        /** start communication */
>>        PORTD &= !(1<<PD5);
>
>         PORTD &= ~(1<<PD5);

Oh das hab ich gar nich gesehen ^^. Aber war wohl auch nicht die Ursache 
des Übels.

von Sajuuk (Gast)


Lesenswert?

Falk B. schrieb:
> In deinem Osziscreenshot sind Kanal 1 und 2 identisch, da stimmt was
> nicht.
> Kurzschlüsse?

Jetzt wo du es sagst. Was würde denn passieren wenn da ein Kurzschluss 
ist?
Das erste Byte ist ja ne 00110000 also 0x30h. Wenn Chipseleckt und Mosi 
kurzgeschlossen wären könnte es ja beim dritten Bit nen mehr oder 
weniger kurzen High Piek auf der Chipselect Leitung geben. Das wäre 
zumindest die bisher beste Erklärung für das Verhalten. Oder?

Du solltest auch mal das SHDN-Signal in deinem Oszi mit überwachen. 
Nicht das da was merkwürdiges passiert. Es wäre auch hilfreich wenn du 
mal nen Schaltplan von deiner Hardware reinstellst. Eventuell liegt das 
Problem dort.

Mir ist auch noch was am Code aufgefallen.

>uint16_t val = 3000;
Das ergiebt doch: 3000 = 0x0BB8 = 00001011/10111000 oder liege ich da 
falsch?

>SPDR = (0x10|highByte(val));
Das müsste dann Bitweise Oder von 0x10 und 0x0B = 0x1B sein.
Nun geht meine überlegung weiter.
In deiner initialisierung kann ich nicht sehen das du das du das Bit5 
(DORD: Data Order Bit) im SPCR (SPI Control Register) auf High gesetzt 
hast. Nun sendest du ja als erstes 0x1B (highByte) Da du das DORD Bit 
nicht gesetzt hast wird zuerst das LSB von diesem Byte gesendet. Also 
anstatt 00011011 (0x1B) sendest du 11011000. Im Datenblatt des MCP4821 
steht aber das,dass erste Bit welches gesendet wird eine 0 sein muss bei 
einer 1 wird das Kommando ignoriert.

Der linkt zu dem MCP4821 den du gepostet hast führt übrigens zu einem 
veralteten Datenblatt du solltest dir mal ne aktuelle Version anschauen.
https://docs.google.com/viewer?url=https%3A%2F%2Fwww.google.de%2Furl%3Fsa%3Dt%26rct%3Dj%26q%3D%26esrc%3Ds%26source%3Dweb%26cd%3D2%26cad%3Drja%26uact%3D8%26ved%3D0ahUKEwjE7pe3kKvJAhVM7xQKHX-wDX4QFggpMAE%26url%3Dhttp%253A%252F%252Fww1.microchip.com%252Fdownloads%252Fen%252FDeviceDoc%252F22244B.pdf%26usg%3DAFQjCNGD9bco9NeBUc49GCOWDOIg8UYnvQ

von Sajuuk (Gast)


Lesenswert?

Dennis schrieb:
> Wenn ein Kurzschluss vorliegen sollte, dann eigentlich nur auf dem
> Arduino selbst, da ich ja den D/A schon weggehängt hab und immernoch
> dieselben Symptome vorliegen. Aber auch da scheint keiner vorzuliegen...

Also ist aktuell gar nix angeschlossen? Oder hast du noch Irgendwas an 
der Programmierschnittstelle dran? Die hängt ja auch an der SPI.

von Felix P. (fixxl)


Lesenswert?

Sajuuk schrieb:
> Nun sendest du ja als erstes 0x1B (highByte) Da du das DORD Bit
> nicht gesetzt hast wird zuerst das LSB von diesem Byte gesendet.
Das ist so nicht richtig. Lt. Datenblatt:
DORD == 0 --> MSB-first
DORD == 1 --> LSB-first

von Rainer U. (r-u)


Lesenswert?

Dennis schrieb:
> das hab ich ausprobiert, leider kommt das selbe Ergebnis im scope.

auch wenn Du das aller-einfachste Arduino-Sample zum senden eines Bytes 
per SPI benutzt? Das Senden passiert ja eigentlich mit der SPI-Hardware, 
also wenn da ein Byte rausgeht, sollte die Clock 8x "klingeln". Wenn 
nicht, würde ich an der Hardware zweifeln.

Oder benutzt Du Software-SPI?

von Sajuuk (Gast)


Lesenswert?

Felix P. schrieb:
> Das ist so nicht richtig. Lt. Datenblatt:
> DORD == 0 --> MSB-first
> DORD == 1 --> LSB-first

Stimmt hab mich vertan

von Dennis (Gast)


Lesenswert?

Sajuuk schrieb:

> Der linkt zu dem MCP4821 den du gepostet hast führt übrigens zu einem
> veralteten Datenblatt du solltest dir mal ne aktuelle Version anschauen.
> https://docs.google.com/viewer?url=https%3A%2F%2Fw...

ehrlich gesagt hab ich da selber gar nichts verlinkt das wurde 
automatisch gemacht ^^. Habe die aktuelle Version verwendet.

> Also ist aktuell gar nix angeschlossen? Oder hast du noch Irgendwas an
> der Programmierschnittstelle dran? Die hängt ja auch an der SPI.

nein ich gehe momentan direkt mit den tastköpfen auf die Pins vom 
Arduino. Dachte mir halt wenn eh nichts gescheites aus der MOSI-Leitung 
rauskommt, brauch ich auch nichts anzuschließen. An der ISP hängt nichts 
dran.

Habe auch die gesamte SPI Peripherie nochmal auf Kurzschluss geprüft, da 
ist definitiv alles IO.


Rainer U. schrieb:

> Dennis schrieb:
>> das hab ich ausprobiert, leider kommt das selbe Ergebnis im scope.
>
> auch wenn Du das aller-einfachste Arduino-Sample zum senden eines Bytes
> per SPI benutzt? Das Senden passiert ja eigentlich mit der SPI-Hardware,
> also wenn da ein Byte rausgeht, sollte die Clock 8x "klingeln". Wenn
> nicht, würde ich an der Hardware zweifeln.
>
> Oder benutzt Du Software-SPI?

ja eben das verwundert mich ja, dass die clock erstens mal viel später 
einsetzt als die fallende flanke vom CS, und dann noch dass nach 3 
cycles einfach schluss ist. Ich verwende die normale SPI-Peripherie des 
µC.

von Sajuuk (Gast)


Lesenswert?

Dann würde ich mal vorschlagen du nimmst nen zweites Uno und testest es 
mal.

von Dennis (Gast)


Lesenswert?

Sajuuk schrieb:
> Dann würde ich mal vorschlagen du nimmst nen zweites Uno und
> testest es
> mal.

ist in Arbeit. Frag grad rum wer eins hat, hab jez nich grad ne Sammlung 
oder so.

Hab auch mal versucht n altes Projekt per ISP mit dem Uno als Programmer 
zu flashen. Das geht komischerweise...

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.