Forum: Mikrocontroller und Digitale Elektronik SPI Master mit Attiny1616


von David P. (devryd)


Lesenswert?

Hallo zusammen,
ich habe derzeit ein Projekt, bei dem ein Attin1616 über SPI mit einem 
SX1276 LoRa Modul reden soll. Leider bekomme ich die SPI Kommunikation 
nicht wirklich hin. Ich habe mir 3 Methoden geschrieben:
1
void init_spi() {
2
  PORTA_DIRSET = 0x02 | 0x04 | 0x10; //set clock, MOSI and NSS as output
3
  PORTC_DIRSET = 0x02; //set rst as output
4
  PORTC_OUTSET = 0x02; //set reset high
5
  SPI0_CTRLA = 0x23; 
6
  SPI0_CTRLB = 0x04;
7
}
1
void readReg(uint8_t reg, uint8_t *result, size_t length = 1) {
2
  uint8_t message[length + 1];
3
  PORTA_OUTCLR = 0x10;
4
  _delay_ms(2);
5
  for (int i = 0; i < length; i++) {
6
    message[i + 1] = 0;
7
  }
8
  message[0] = reg;
9
  for (int i = 0; i < length + 1; i++) {
10
    SPI0_DATA = message[i];
11
    //while (!SPI0_INTFLAGS & 0x80) ; // wait for transmission to be over
12
    _delay_ms(5);
13
    message[i] = SPI0_DATA;
14
    send_char(message[i]);
15
  }
16
  memcpy(result, &message[1], length);
17
  PORTA_OUTSET = 0x10;
18
}
1
void writeReg(uint8_t reg, uint8_t *data, size_t length = 1) {
2
  //pull cs low
3
  PORTA_OUTCLR = 0x10;
4
  _delay_ms(2);
5
  uint8_t message[length + 1];
6
  message[0] = reg | 0x80;
7
  memcpy(&message[1], data, length);
8
  for (int i = 0; i < length + 1; i++) {
9
    SPI0_DATA = message[i];
10
   //; while (!SPI0_INTFLAGS & 0x80) ; // wait for transmission to be over
11
    _delay_ms(5);
12
    send_char(SPI0_DATA);    
13
  }
14
  PORTA_OUTSET = 0x10;
15
}

Die Methode send_char() macht über UART eine Ausgabe zum debuggen. 
Leider bekomme ich immer nur 0x00 zurück. Sieht jemand auf Anhieb etwas 
das Falsch läuft? Falls nein, hat jemand evtl ein paar Code Fetzen, die 
ich mir anschauen kann? Microchip hat zwar ein Guide zu SPI an Attiny 0 
und 1 serie, allerdings habe ich da nicht wirklich etwas finden können, 
was erklärt, warum das ganze hier nicht funktioniert. Ich habe leider 
kein Oszilloskop um mir die Leitungen anzuschauen. Die Pinbelegung ist 
MOSI PA1, MISO PA2, SPI_CLK PA3, CS PA4, also die Standartbelegung des 
Attiny1616, wenn ich das richtig aus dem Datenblatt gelesen habe.

Danke schon mal für Eure Hilfe und noch einen schönen Abend.

von Wastl (hartundweichware)


Lesenswert?

David P. schrieb:
> PORTA_DIRSET = 0x02 | 0x04 | 0x10; //set clock, MOSI and NSS as output

Auf die Schnelle: ich vermisse den Clock in deinen Magic Numbers

David P. schrieb:
> Die Pinbelegung ist
> MOSI PA1, MISO PA2, SPI_CLK PA3, CS PA4

   0x02      0x04      0x08         0x10

Das wären meine Magic Numbers ..... wenn man den Clock auch als
Output definieren müsste. MISO natürlich nicht ...

von Wastl (hartundweichware)


Lesenswert?

David P. schrieb:
> SPI0_CTRLA = 0x23;
> SPI0_CTRLB = 0x04;

Bei solchen Magic Numbers weiss natürlich gleich jeder ob
du alles richtig gemacht hast. Nicht wahr? Wozu gibt
es Header-Files vom Hersteller wo alles vordefiniert ist?

von David P. (devryd)


Lesenswert?

Wastl schrieb:
> Das wären meine Magic Numbers ..... wenn man den Clock auch als
> Output definieren müsste. MISO natürlich nicht ...

Ah da ist mir wohl ein Fehler unterlaufen. Geht aber leider immer noch 
nicht.

Die Einstellungen zu SPI sollten denke ich passen, Das sollte SPI Master 
Mode sein mit clockdiv 16 und SPI enable. Das zweite ist Nur Slave 
Select Disable, da ich kein multi Master mache.

von Veit D. (devil-elec)


Lesenswert?


: Bearbeitet durch User
von David P. (devryd)


Lesenswert?

Veit D. schrieb:
> schau dir Kapitel 25.3.1  nochmal genauer an.

Hast du was gesehen, was ich falsch gemacht habe oder ist das mehr ein 
"hier sollte alles drin stehen"? Ich habe eigentlich beides gelesen, 
aber scheinbar dann wohl nicht richtig.

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


Lesenswert?

David P. schrieb:
> Sieht jemand auf Anhieb etwas das Falsch läuft?
Meine übliche Vorgehensweise wäre jetzt, ein/en Oszi/Logicanalyzer zu 
nehmen, und zu kontrollieren, ob sich auf dem SPI das tut, was ich 
erwarte. Und wenn nicht das passiert, was ich erwarte, dann sehe ich, wo 
ich noch korrigieren muss.

David P. schrieb:
> Die Einstellungen zu SPI sollten denke ich passen
Da muss man dann gar nichts Denken, sondern einfach nur kontrollieren. 
Alles andere ist wie "Blindflug im Nebel" oder "Autofahren nach Gehör". 
Es ist mir ein völliges Rätsel, wie man serielle Busse ohne Speicheroszi 
bzw. LA in Betrieb nehmen kann.

von David P. (devryd)


Lesenswert?

Lothar M. schrieb:
> wie man serielle Busse ohne Speicheroszi
> bzw. LA in Betrieb nehmen kann.

Geht ja scheinbar auch nicht.

Werde das Board wohl morgen auf der Arbeit ans Oszilloskop hängen.

von S. L. (sldt)


Lesenswert?

Nur ein ATtiny (1616) vorhanden?
  Ansonsten: den zweiten als SPI-Slave nehmen und (per 
Einfachstprogrammen) Buchstaben hin&her schicken. Solche Programme 
lassen sich hier dann auch vollständig vorstellen (und der Sonntag 
wäre gerettet).

von Veit D. (devil-elec)


Lesenswert?

David P. schrieb:
> Veit D. schrieb:
>> schau dir Kapitel 25.3.1  nochmal genauer an.
>
> Hast du was gesehen, was ich falsch gemacht habe oder ist das mehr ein
> "hier sollte alles drin stehen"? Ich habe eigentlich beides gelesen,
> aber scheinbar dann wohl nicht richtig.

Eher da steht in Beiden alles drin. Dein Code Ausschnitt ist leider 
schwer bis kaum lesbar. Niemand übersetzt Hexcode in Binär und zurück 
nur zum vergleichen.
Bekommst du eine Led zum blinken?
Ansonsten, halte dich an die App Note und es wird funktionieren.
Tue dir selbst auch einen Gefallen. Verwende Bitnummern oder noch besser 
Bitnamen bzw. Bitmasken (die mit _bm am Ende).

Deine:
1
PORTA_DIRSET = 0x02 | 0x04 | 0x10; //set clock, MOSI and NSS as output
übersetzt:
1
PORTA_DIRSET = _BV(1) | _BV(2) | _BV(4); //set clock, MOSI and NSS as output
Stellst du schon etwas fest?
Wenn nicht, an welchen Portpins verwendest du SPI?
Wie heißen die Portpins?
Was sind deren Bitnummern?
Gehe alles nochmal durch.

von David P. (devryd)


Lesenswert?

Wenn ich einen zweiten Attiny1616 als Slave setze und etwas nicht geht, 
habe ich ja nichts gewonnen. Ich weiß dann ja nicht, ob es an der 
Master- oder Slave Seite liegt. Eine zweite Platine müsste ich erst 
bestücken; dafür, dass das Resultat nicht. Aber kann ich Testweise 
einfach MISO und MOSI verbinden?
Dann sollte doch zumindest immer das ankommen, was ich sende, um zu 
schauen, ob das SPI an sich überhaupt funktioniert.

von Wastl (hartundweichware)


Angehängte Dateien:

Lesenswert?

Ich verstehe nicht warum man immer mit Magic Numbers herumeiern
muss wenn doch alle Register und Bits mit Namen in einer Datei
bereitgestellt werden und für jeden verfügbar sind.

Nein, ich verstehe es nicht. Es lassen sich so viele Fehler
vermeiden und die Community versteht weitaus besser was im
Programm los ist.

von David P. (devryd)


Lesenswert?

Veit D. schrieb:
> Deine:PORTA_DIRSET = 0x02 | 0x04 | 0x10; //set clock, MOSI and NSS as
> output
> übersetzt:PORTA_DIRSET = _BV(1) | _BV(2) | _BV(4); //set clock, MOSI and
> NSS as output

Den Fehler hatte schon dein Vorredner gesehen. Das ganze habe ich 
korrigiert auf
1
PORTA_DIRSET = 0x02 | 0x08 | 0x10;

daraus habe ich jetzt das hier gemacht
1
PORTA_DIRSET = PIN1_bm | PIN3_bm | PIN4_bm;
aber das ändert ja nichts an der Funktionalität.

von Wastl (hartundweichware)


Lesenswert?

David P. schrieb:
> daraus habe ich jetzt das hier gemacht

Siehe meinen Beitrag vorher.

von S. L. (sldt)


Lesenswert?

> Aber kann ich Testweise einfach MISO und MOSI verbinden?

Ja.

Aber auch dabei führt ein schlichtes Hauptprogramm (nix aufwändige 
'Methoden') schneller zum Verständnis.

von Wastl (hartundweichware)


Angehängte Dateien:

Lesenswert?

Hier mal ein Beispiel wie "man" das ohne Magic Numbers macht.

von S. L. (sldt)


Lesenswert?

Wie praktisch, dass zufällig RXCIE und IF auf derselben Bitposition 
liegen.

von David P. (devryd)


Lesenswert?

Ich habe den Fehler gefunden. Es war tatsächlich was ganz anderes und 
unglaublich dämliches. Anstatt in der main() spi_init(); aufzurufen, 
hatte ich stattdessen void spi_init(); da stehen, also eine lokale 
Redefinition(?) der Methode? Ohne das setzen aller PINS und Register 
geht natürlich gar nichts...

von Wastl (hartundweichware)


Lesenswert?

David P. schrieb:
> also eine lokale Redefinition(?) der Methode?

Das von was du redest sind im üblichen Sprachgebrauch keine
Methoden sondern Funktionen. Erst in einer (C++) Klasse redet
man von Methoden.

von Veit D. (devil-elec)


Lesenswert?

David P. schrieb:
> Ich habe den Fehler gefunden. Es war tatsächlich was ganz anderes und
> unglaublich dämliches

Also 2 Fehler. Ohne Korrektur der Bits hätte es immer noch nicht 
funktioniert. Beim nächsten Mal kompletten reduzierten Code zeigen, der 
das noch Problem zeigt. Dann gibt es kein Rätselraten.

von David P. (devryd)


Lesenswert?

Wastl schrieb:
> Das von was du redest sind im üblichen Sprachgebrauch keine
> Methoden sondern Funktionen. Erst in einer (C++) Klasse redet
> man von Methoden.

Ah ok, ich kannte als Unterscheidung: Methode - kein Rückgabewert, 
Funktion - Rückgabewert.

von Harald K. (kirnbichler)


Lesenswert?

Wastl schrieb:
> Erst in einer (C++) Klasse redet
> man von Methoden.

Eigentlich auch da nicht. Das sind Memberfunktionen. "Methoden" ist so 
ein Javading.

David P. schrieb:
> Methode - kein Rückgabewert, Funktion - Rückgabewert.

Das war Pascal mit "Prozedur" und "Funktion". Friede seiner Asche.

von Veit D. (devil-elec)


Lesenswert?

Harald K. schrieb:
> Wastl schrieb:
>> Erst in einer (C++) Klasse redet
>> man von Methoden.
>
> Eigentlich auch da nicht. Das sind Memberfunktionen. "Methoden" ist so
> ein Javading.

Also ganz präzise heißt das in C++ Elementfunktion. Aber Methoden und 
Memberfunktion versteht auch jeder.  ;-)

: Bearbeitet durch User
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.