Forum: Mikrocontroller und Digitale Elektronik Tiny861 USI Slave Mode


von Jasson J. (jasson)


Lesenswert?

Hallo zusammen,

ich hänge gerade am SPI mode vom USI in einem Tiny fest.

Grundsätzlich geht es schon mal und die Daten fahren Kreisverkehr.

>AAAHaber
wo kann ich mich im SlaveMode mit eigenen Daten einhängen? Geht das 
überhaupt - ich dachte so läuft SPI
Also wenn bei jeden empfangenem byte via USI ein anderer Wert in USIDR 
geschrieben wird.
So dachte ich mir das jedenfalls.
Im Moment komme ich von dem Loopback nicht weg.

viele Grüße!

von S. Landolt (Gast)


Lesenswert?

Im Datenblatt das Bild 'Universal Serial Interface, Block Diagram' sowie 
das Programmteil 'SPI Slave Operation Example' sollten weiterhelfen. 
Wenn nicht, was wurde nicht verstanden, bzw. wie sieht das nicht 
funktionierende Programm aus?

von Jasson J. (jasson)


Lesenswert?

Ja, die Teile im DB hab ich gelesen und auch noch mal genau, ob ich was 
finde, das von meinem intuitiven Verständnis abweicht. Hab ich ne 
AppNode gesichtet und einen anderen Beitrag hier.

Ach ja, es sind keine Interrupts aktiviert.

Der Code:
1
slaveSelStatusNew = (PINB & 0b01000000);// read slave select Pin
2
if(slaveSelStatusNew != slaveSelStatusOld)//SS edge detect
3
{
4
  if(slaveSelStatusOld == 0)//jetzt SS IDLE - vorher also activ
5
  {
6
    dummyChar = USIBR; //read buffer 
7
    USIDR = 'a' + charCntr; //create fake data to return
8
    charCntr++;
9
    if(charCntr >= 5) charCntr = 0;
10
  }
11
  else
12
  {
13
    USIDR = 'a' + charCntr;//Griff nach dem Strohhalm
14
  }
15
}
16
slaveSelStatusOld = slaveSelStatusNew; // part of edge detection

von S. Landolt (Gast)


Lesenswert?

Es tut mir leid, mit diesem Programmschnipsel kommt niemand weiter, es 
zeigt u.a. die USISR.USIOIF-Abfrage nicht.

von Jasson J. (jasson)


Lesenswert?

Das USIOIF benutze ich nicht. Ich habe die Schnittstelle für mich so 
definiert, dass bei einer Rising Edge auf dem Software-SlaveSelect Pin 
von einer eingegangenen Übertragung ausgegangen wird.

Ansonsten halte ich den Code für verständlich. Die Variablen haben 
selbstredende Namen, es gibt Kommentare und mit der Abfrage von PINB ist 
klar, dass der Abschnitt zyklisch aufgerufen werden muss und da auch 
nichts dazwischen funken kann, da wie beschrieben keine Interrupte 
aktiviert sind.

von S. Landolt (Gast)


Lesenswert?

Das heißt, dass der Master pro SPI-Zyklus nur ein einziges Byte sendet? 
Und der gezeigte Programmteil ist in eine Schleife eingebettet? Wenn das 
alles ist, hätten Sie aber auch das komplette Slave-Programm zeigen 
können.

Der Master sendet also 'irgendwas', und erhält im nächsten SPI-Zyklus 
eben dieses 'irgendwas' statt des erwarteten 'a' ('b' 'c' ...) - okay, 
dann muss ich passen, vielleicht sieht ein Anderer mehr.

von Jasson J. (jasson)


Lesenswert?

>Das heißt, dass der Master pro SPI-Zyklus nur ein einziges Byte sendet?
>Und der gezeigte Programmteil ist in eine Schleife eingebettet?
>>genau
>>genau

Und das komische ist, die erste Ziffer der Fakedaten kommt zuverlässig.

von S. Landolt (Gast)


Lesenswert?

Der "Strohhalm"-Zweig überschreibt Ihnen jedesmal das zuvor gesetzte UDR 
- stilllegen.

von S. Landolt (Gast)


Lesenswert?

PS:
Er schreibt in die laufende Übertragung hinein das UDR, das Resultat ist 
also davon abhängig, wie lange der Master benötigt vom Setzen des 
Slave-Select bis zum eigentlichen Übertragungsstart.

von Peter D. (peda)


Lesenswert?

Jasson J. schrieb:
> Also wenn bei jeden empfangenem byte via USI ein anderer Wert in USIDR
> geschrieben wird.

So macht man es auch. Dazu muß man aber USICNT entsprechend vorladen und 
dann auf USIOIF warten. Anders kann man das Ende eines Bytes nicht 
erkennen.

von S. Landolt (Gast)


Lesenswert?

> Ansonsten halte ich den Code für verständlich.
Schon richtig, aber er ist nicht vollständig. Und das nötige 
Vervollständigen hält mich Assemblerprogrammierer davon ab, das Ganze 
mal eben schnell auszuprobieren. Der Fragesteller sollte es potenziellen 
Helfern möglichst einfach machen - dazu gehört auch eine kurze 
Beschreibung der Rahmenbedingungen, wie z.B. dass nur immer ein einziges 
Byte übertragen wird.

von Jasson J. (jasson)


Lesenswert?

>So macht man es auch. Dazu muß man aber USICNT entsprechend vorladen

ja, Versuche mit Vorladen von USICNT hab ich gemacht, aber keine 
gezielten. Hab im Datenblatt nicht die Stelle gefunden, die z.B. sagt 
"Laden von USIDR geht nur, wenn USICNT = 'n' ist."
In den ASM Beispielen im DB machen die das auch nicht.
> Ansonsten: auf was lädt man USICNT vor?

Vielleicht funktioniert meine Strategie einfach nicht:
Wie gesagt, benutze ich das USIOIF nicht. Habe im Datenblatt nicht 
gefunden, dass man das unbedingt muss. Ich übertrage während jeder 
Activ-Zeit von SlaveSelect nur ein Byte und der Empfänger (USI Slave) 
geht davon aus, das bei der Flanke auf SlaveSelect->IDLE ein Byte 
eingegangen ist, liest USIBR aus und schreibt in USIDR rein.

Grundsätzlich habe ich mich schon gefragt, dass man irgendwo den USICNT 
manuell rücksetzten sollte, weil es ja auch sein kann, dass die 
Statemachines (die es letztlich in Form der Shiftregister sind) mal aus 
dem Sync kommen können.
Deswegen hatte ich mal versucht bei genannter Flanke von SlaveSelect auf 
IDLE USICNT=0 zu setzten. Ohne Erfolg.

von S. Landolt (Gast)


Lesenswert?

1
Das Zählregister zählt: Null, eins,
2
zwei, drei, vier, fünf, sechs, sieb'n und: keins;
3
  das macht, es zählt oktal.
4
5
Es ist beschränkt wie mancher Mann
6
der nur bis sieben zählen kann
7
  und merkt es nicht einmal.

KLEN, in memoriam

Nachfolgendes Programm schickt an den Master: 0x00, 'a', 'b', 'c' ..., 
wie ursprünglich verlangt ganz ohne USIOIF oder USICNT.
1
#define  F_CPU 8000000
2
#include <avr/io.h>
3
uint8_t slaveSelStatusNew,slaveSelStatusOld,dummyChar,charCntr;
4
int main(void)
5
{  
6
slaveSelStatusOld=1;charCntr=0;
7
DDRA=0b00000010;
8
USIPP=(1<<USIPOS); // optional
9
USICR=(1<<USIWM0)|(1<<USICS1);
10
while (1)
11
{  
12
slaveSelStatusNew = (PINB & 0b01000000);// read slave select Pin
13
if(slaveSelStatusNew != slaveSelStatusOld)//SS edge detect
14
{
15
  if(slaveSelStatusOld == 0)//jetzt SS IDLE - vorher also activ
16
  {
17
    dummyChar = USIBR; //read buffer 
18
    USIDR = 'a' + charCntr; //create fake data to return
19
    charCntr++;
20
    if(charCntr >= 5) charCntr = 0;
21
  }
22
  else
23
  {
24
//    USIDR = 'x'; //'a' + charCntr;//Griff nach dem Strohhalm
25
  }
26
}
27
slaveSelStatusOld = slaveSelStatusNew; // part of edge detection
28
}
29
}

von c-hater (Gast)


Lesenswert?

S. Landolt schrieb:

> Nachfolgendes Programm schickt an den Master: 0x00, 'a', 'b', 'c' ...,
[...]

Ja, klar den Fehler erkannt. Die Sache läuft ja immer über zwei Toggles. 
Bei der steigenden Flanke werden die richtigen Daten bereitgestellt 
(aber nicht genutzt, da steigende Flanke ja den inaktiven Zustand 
einleitet), um dann bei fallender Flanke, wenn die Daten endlich ihrer 
Verwendung zugeführt werden würden, überschrieben zu werden, bevor es 
wirklich losgeht...

von Peter D. (peda)


Lesenswert?

Jasson J. schrieb:
> Ich übertrage während jeder
> Activ-Zeit von SlaveSelect nur ein Byte

Wozu soll das gut sein?
Du verlierst damit die Synchronisation, d.h. der Empfänger weiß nicht 
mehr, welches Byte welche Bedeutung hat, weil er den Frameanfang nicht 
erkennen kann. Jedes Byte ist für den Empfänger quasi ein neuer Frame.

von Jasson J. (jasson)


Lesenswert?

@c-hater

ok, vll. liegt da der Fehler - welche Stellen meinst du genau?
>Bei der steigenden Flanke werden die richtigen Daten bereitgestellt
>>Zeile 18 mit USIDR = 'a' + charCntr; meinst du da?

>aber nicht genutzt
>> in wie fern nicht genutzt? Bei Zyklus n liegen (so dachte ich´s mir) noch die 
bei Zyklus n-1 rein geschriebenen Daten drin und gehen eben während Zyklus n auf 
die Reise

>überschrieben zu werden
>> An welcher Stelle / bzw. zu welchem Moment werden die überschrieben?

von c-hater (Gast)


Lesenswert?

Jasson J. schrieb:

> ok, vll. liegt da der Fehler

Ganz sicher sogar.

> - welche Stellen meinst du genau?

Das hat doch der Herr Landolt schon getan, indem er den schädlichen Code 
auskommentiert hat.

Man kann natürlich sinnvollerweise auch den kompletten else-Zweig dahin 
verschieben, wo er hingehört...

von S. Landolt (Gast)


Lesenswert?

> Zyklus n-1 ...Zyklus n

Nein: UDR ist ein Schieberegister, das mit 'UDR= ' parallel geladen 
wird, und zwar zum Zeitpunkt des Befehls, ohne jede Synchronisation.

Landolt schrieb:
> ... schreibt in die laufende Übertragung hinein ...
je nach Zeitverhältnissen zwischen Master und Slave.

von S. Landolt (Gast)


Lesenswert?

Konkret:
Master mit Systemtakt von 20 MHz, SPI-Takt 1.25 MHz, Slave (ATtiny461) 8 
MHz; ich reaktiviere die besagte Zeile mit
1
USIDR = 'J';
dann dürfte der Master (schließen wir mal nichts aus) nur 0x61..0x65 
(a..e) sowie 0x4A (J) sehen - es kommt aber z.B. 0x69 0x52 0x72 ...

von S. Landolt (Gast)


Lesenswert?

Na, wie ich sehe, gewinne ich keinen Blumentopf. Dann sei wenigstens, 
zur allgemeinen Unterhaltung, KLENs Vorlage nachgetragen, Morgensterns 
Perlhuhn:
1
Das Perlhuhn
2
3
Das Perlhuhn zählt: Eins, zwei, drei, vier...
4
Was zählt es wohl, das gute Tier,
5
      dort unter den dunklen Erlen?
6
7
Es zählt, von Wissensdrang gejückt,
8
(die es sowohl wie uns entzückt:)
9
      die Anzahl seiner Perlen.

Guten Abend, allerseits

von Jasson J. (jasson)


Lesenswert?

Ick hoab et...

Die Chip Select Flanken waren zu nah um die Datentransmission.
Hab beim SPI Master ein Delay 'nach' EnableChipSelect und 'vor' 
DisableChipSelect gesetzt.

Vielen Dank an alle, die mit geschrieben haben!

von c-hater (Gast)


Lesenswert?

Jasson J. schrieb:

> Ick hoab et...
>
> Die Chip Select Flanken waren zu nah um die Datentransmission.
> Hab beim SPI Master ein Delay 'nach' EnableChipSelect und 'vor'
> DisableChipSelect gesetzt.

Du hast es nicht wirklich. Die Lösung ist, was S. Landolt geposted hat.

Delays könnten höchsten ZUSÄTZLICH nötig sein/werden. Allerdings: 
genau WENN sie das werden, zeigt das nur zu deutlich die prinzipielle 
Untauglichkeit des Konzepts...

von Jasson J. (jasson)


Lesenswert?

Wie währ´s ob du es einfach mich selbst beurteilen lässt, ob etwas für 
meine Anwendung in Ordnung ist?
Ich glaube, du verstehst den Kontext nicht.
Ich HABE das was Landolt gepostet hat und er hatte Dinge zu meinem Code 
hinzugefügt.
Das Problem war aber nicht im SPI Slave, sondern im Master, der zwischen 
den Select Flanken nicht genug Zeit zum Byte-Transmission gelassen hat.

Mit einem Check auf´s USIOIF hätte es erstmal sicher funktioniert. Nur 
was ist, wenn auf der Taktleitung mal was schief geht? Es muss einen 
Mechanismus geben, der einen Sync herstellen kann. Das heißt für diesen 
Fall wird man ein Select Signal brauchen das man (wenn man USIOIF 
benutzt) zum manuellen Rücksetzten des Counters nehmen kann. Und dann 
hätte ich mich mit dem Timing wie es war auf die Nase gelegt. Und zwar 
nicht immer wie jetzt, wo es sofort auffällt, sondern nur super selten - 
eben wenn auf der CLK Leitung mal was schief geht. Dieses "super selten" 
ist ein Debug-Alptraum.

von c-hater (Gast)


Lesenswert?

Jasson J. schrieb:

> Wie währ´s ob du es einfach mich selbst beurteilen lässt, ob etwas für
> meine Anwendung in Ordnung ist?

Wenn dir dadurch besser wird...

> Ich HABE das was Landolt gepostet hat und er hatte Dinge zu meinem Code
> hinzugefügt.

Er hat vor allem aber das, was definitiv VOLLKOMMEN FALSCH war und 
deshalb niemals funktionieren konnte, ausgemerzt. Das mag dir peinlich 
sein (sollte es vielleicht sogar), ist aber die objektive Wahrheit.

Ob es dir passt oder nicht, ist angesichts der Allgewalt der objektiven 
Realität völlig irrelevant.

von S. Landolt (Gast)


Lesenswert?

> er hatte Dinge zu meinem Code hinzugefügt.

Glauben Sie ihm kein Wort, c-hater: ich habe lediglich den fehlenden 
Rahmen zu seinem Programmschnipsel ergänzt, ich musste das Ganze ja 
durch den Compiler bringen. Wenn seine (nicht gezeigte) Initialisierung 
anders aussieht, so ist das sein Problem, nicht meines.

Und jetzt endgültig - Gute Nacht

von Peter D. (peda)


Lesenswert?

Jasson J. schrieb:
> Die Chip Select Flanken waren zu nah um die Datentransmission.
> Hab beim SPI Master ein Delay 'nach' EnableChipSelect und 'vor'
> DisableChipSelect gesetzt.

Damit hast Du den Hauptmangel der AVR-Slaves entdeckt, sie haben keinen 
Sendepuffer. Daher muß der Master an den entsprechenden Stellen 
Gedenkpausen einlegen, bis der Slave reagiert hat.
Soll der Slave aber nicht nur Däumchen drehen, sondern auch andere Tasks 
ausführen, dann müssen die Gedenkpausen noch größer werden.

Einige neuere AVRs haben da nachgelegt und einen Sendpuffer spendiert 
bekommen. Zusätzlich haben sie eine konfigurierbare Interruptpriorität, 
d.h. der SPI-Interrupt kann sich vordrängeln, ohne andere Interrupts 
abwarten zu müssen.

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.