Forum: Mikrocontroller und Digitale Elektronik SPI-Verbindung Attiny <->SAMD21


von Stromverdichter (Gast)


Lesenswert?

Hallo Controller-Freunde,

im Moment beschäftige ich mich mit der SPI-Ansteuerung eines Attiny828, 
den ich als Wandler für zusätzliche 24 AD-Kanäle an meinen SAMD21 
Hauptcontroller anbinden möchte. Ich verwende die 
Hardware-SPI-Schnittstelle des Attiny als Slave und eine Sercom des 
SAMD21 als Master. Grundsätzlich funktioniert die Verbindung bis auf ein 
kleines systematisches Problem.
Ich verwende mit beiden Controllern den Interrupt um auf 
empfangene/gesendete Bytes zu reagieren. In den Interrupts der beiden 
Controller toggle ich einen PIN um den zeitlichen Verlauf im Interrupt 
erfassen zu können. Im Moment betreibe ich die Schnittstelle bei 1,5MHz, 
ab 2MHz macht der Attiny wie im Handbuch erwähnt nicht mehr mit.
Um im Attiny als Tranceiver Bytes als Antwort zurückzuschicken, warte 
ich auf den „Byte-Empfangen“-Interrupt, werte das empfangene Byte aus 
und kopiere dann ein entsprechendes Byte zurück in den Puffer. Dieser 
ganze Vorgang dauert im Interrupt jedoch recht lange, da ja zunächst 
alle Register gesichert werden müssen. Die gemessene Zeit im Interrupt 
liegt bei ca. 5µS.
Zusätzlich habe ich noch einen Timer im Hintergrund laufen, der 
verschiedene Vorgänge steuert. Sobald das Slave-Signal kommt, kann ich 
die weniger wichtigen Prozesse im Timer abschalten, dennoch bleiben auch 
hier 7 µS als Interrupt-Zeit stehen. Kommt jetzt ein Timer-Interrupt 
ungünstig daher, verzögert er, auch wegen seiner höheren Priorität den 
SPI-Interrupt. Ich muss also im Master nach jedem übertragenen Byte eine 
Mindestwartezeit einfügen, bis das nächste Byte übertragen werden darf. 
Damit komme ich jedoch nur auf etwa 50% der möglichen Übertragungsrate.

Eine Möglichkeit sehe ich darin, den Interrupt im Attiny einfach nicht 
zu verlassen, solange ein Slave-Select-Signal anliegt. Ich fühle mich 
aber nie wohl, wenn ich den Prozessablauf so blokiere.
Gibt es einen richtigen Weg, den ich nur nicht sehe, oder wird das 
üblicherweise so gehandhabt?
1
CLOCK    _¯_¯_¯_¯_¯_¯_¯___________________¯_¯_¯_¯_¯_¯_¯_¯__________
2
3
MOSI     __¯¯¯__¯¯__¯¯¯_____________________¯¯¯__¯¯__¯¯¯___________
4
5
INT TIM  _____________¯¯¯¯¯¯¯¯¯________________________________________
6
INT SPI   _______________________¯¯¯¯¯¯¯¯¯______________________________
7
8
               Daten   Timer_INT  SPI_INT
9
                                      | >hier werden erst die Daten vom Slave geschrieben
10
                      > notwendige Wartezeit
11
                              für den Master<

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Prüfe, ob Du den Timer im Polling betreiben kannst, anstelle des 
Timer-Interrupts. Wenn ein Jitter erlaubt ist, dann kann das 
funktionieren und der SPI-Interrupt wird nicht verzögert. Wie schnell 
läuft Dein Tiny jetzt? Und wieso soll bei 2Mhz-SPI-Frequenz Schluss 
sein? Der Tiny schafft bei 20Mhz immerhin 10Mhz SPI-Takt im Double 
Speed.

von Stromverdichter (Gast)


Lesenswert?

Hallo Knut,
der Tiny ist ein 828 ohne Quarz, der geht nur bis 8MHz. SPI geht 
zuverlässig nur bis 1/4 des Prozessortaktes. Den Timer abschalten würde 
ich ungern, da ich dadurch insgesamt Takte verlieren würde. Da nehme ich 
dann doch lieber die langsame Übertragungsrate in Kauf. Zeitlich könnte 
ich auch im SPI-Interupt zunächst die komplette Übertragung blockierend 
erledigen, d.h. ich würde einfach im Interrupt bleiben, bis Slave-Select 
wieder freigegeben wird. Das kommt mir aber sehr unschön vor, ich möchte 
eigentlich nicht blockierend programmieren. Eine komplette Übertragung 
dauert bei 50-100 Bytes ca. 1-2 ms. Wenn ich die Wartezeiten zwischen 
den Bytes reduzieren könnte, auch unter 1 ms. Im speziellen Fall könnte 
man eventuell auch das Timing synchronisieren. Ich wüsste jedoch gerne, 
wie das allgemein gehandhabt wird, wenn im System mehrere Interrupts 
auftreten können. Zudem wüsste ich gerne, wie man schnell vom Slave zum 
Master die Daten bekommt, wenn man erst im Interrupt die Antwort 
schreiben kann. Dadurch ergibt sich ja alleine schon ein großes Delay.

von Stromverdichter (Gast)


Lesenswert?

Knut B. schrieb:
> Der Tiny schafft bei 20Mhz immerhin 10Mhz SPI-Takt im Double
> Speed.

Double-Speed geht nur im Master-Mode, nicht als Slave. Der 828 geht nur 
bis 8Mhz.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Stromverdichter schrieb:
> der Tiny ist ein 828 ohne Quarz, der geht nur bis 8MHz.

Nein, geht er nicht. Über OSCCAL kommst Du auf rund 14Mhz, je nach Chip.

Stromverdichter schrieb:
> SPI geht
> zuverlässig nur bis 1/4 des Prozessortaktes.

Nein. Als Master und im DoubleSpeed bis fCPU/2.

Stromverdichter schrieb:
> Den Timer abschalten würde
> ich ungern, da ich dadurch insgesamt Takte verlieren würde.

Sollst ja nicht abschalten, sondern nur umorganisieren -> Progamm 
ändern.

von Stromverdichter (Gast)


Lesenswert?

Hallo Knut,

über OSCAL den Takt zu erhöhen, kommt mir doch sehr experimentell vor. 
Da kann ich ja nie wissen, ob mit der nächsten Charge Chips von Atmel 
das noch so funktioniert. Die Verdoppelung des SPI-Taktes geht nur als 
Master, der Tiny ist hier jedoch nur der Slave.

Umorganisieren des Timers ist eine tolle Idee, nur wie?
Der Timer hat unglücklicherweise eine höhere Priorität wie der SPI. Das 
lässt sich beim Tiny imho auch nicht ändern. Den Timer benötige ich für 
verschiedene weitere Funktionen von Takt für Sensoren über langsame PWM 
bis zu einfachen Zeitmessungen. Daher kann ich den eigentlich nicht 
abschalten ohne die Messwerte zu verfälschen.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Stromverdichter schrieb:
> über OSCAL den Takt zu erhöhen, kommt mir doch sehr experimentell vor.

Der Tiny ist bei 5V bis 20MHz spezifiziert.

Stromverdichter schrieb:
> der Tiny ist hier jedoch nur der Slave.

Aha. Eine wichtige Information!

Stromverdichter schrieb:
> Der Timer hat unglücklicherweise eine höhere Priorität wie der SPI.

Beim Tiny gibt es keine wirklichen Prioritäten. Mehrfach auflaufende 
Interrupte werden in der Priorität ihres Vektors abgearbeitet. Hier bei 
Deinem Ansatz kann aber jeder Interrupt jeden verzögern, sowohl das SPI 
den Timer, als auch umgekehrt. Wenn SPI "Ultrawichtig" ist, dann darf es 
auf dem Controller auch nur einen Interrupt geben. Alles andere muss 
gepollt werden.

von Stromverdichter (Gast)


Lesenswert?

Ich betreibe den Tiny mit 3,3V, da er wie bereits im ersten Post 
geschrieben als Slave am SAMD21 hängt. Da steht also die wichtige Info 
schon. Da er am SAMD21 hängt, kann man sich die 3,3V ja gut erschließen.
Den Tiny kannst du zuverlässig bis 8,8MHz betreiben, alles darüber ist 
nicht mehr sicher, speziell wenn du das EEPROM oder FLASH schreibend 
nutzen möchtest.
Den Timer zu pollen ist auch nicht so prickelnd. Ich hatte nur gehofft, 
ich hätte etwas übersehen oder nicht richtig verstanden. Z.B. 
Möglichkeiten wie preloading des SPI-Puffer oder solche Dinge.

Das mit den Interrupts habe ich aus dem Datenlatt genauso wie du 
verstanden. Effektiv macht die Priorität bei 2 Interrupts dann wohl 
keinen Unterschied, solange beide zu Lebzeiten aus ihrem Thread wieder 
herauskommen. Man könnte eventuell den Timer-Interrupt unterbrechbar 
machen, sozusagen die Interrupt-Verwaltung direkt im Timer wieder 
aktivieren. Ob das Sinn macht kann ich jetzt aber garnicht einschätzen, 
das kommt mir gefährlich vor.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Was wäre denn, wenn der Tiny der SPI-Master ist, dann könnte er am SPI 
doppelt so schnell arbeiten. Der Cortex wird damit doch wohl zurecht 
kommen?

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Stromverdichter schrieb:
> preloading des SPI-Puffer oder solche Dinge.

Du kannst im Datenregister die Daten schon eintragen, bevor der Master 
diese abholt. Eigentlich unmittelbar im SPI-Complete Interrupt als erste 
Aktion. Danach kannst Du das Datenregister lesen und gucken, was der 
Master wollte. Wenn sich das mit Deinem Restprogramm vereinbaren lässt.

von Stromverdichter (Gast)


Lesenswert?

Knut B. schrieb:
> Was wäre denn, wenn der Tiny der SPI-Master ist, dann könnte er am SPI
> doppelt so schnell arbeiten.
daran hatte ich auch schon gedacht. Nur wird so einiges vom D21 aus 
gesteuert, was man ungern nur pollen möchte. Klar könnte ich auch on the 
fly über den SS von Master wieder auf Slave umschalten. Das sind aber 
alles nur Umwege um das grundsätzliche Problem zu lösen. Der Tiny wird 
auch über die Cortexe programmiert, er dient auch als EEPROM Speicher 
und soll eigentlich immer erreichbar bleiben.
Wen der Tiny im Interrupt antwortet, dann natürlich erst für das nächste 
Byte, dass der Master sendet. Es ist ja ein Ringpuffer, der im gleichen 
Takt die Bytes vom Master zum Slave und gleichzeitig umgekehrt schiebt. 
Das eigentliche Problem ist, dass der Tiny schon einige Zeit benötigt, 
um die Register im Interrupt auf den Stack zu sichern. Sicher könnte man 
das mit den entsprechenden Assembler-Kenntnissen optimieren, das ist mir 
aber noch nicht gegeben. Zusätzlich muss ich ja berücksichtigen, dass 
eventuell im gleichen Zyklus auch der Timer gefeuert haben kann, womit 2 
Interrupts die Daten verzögern. Der Master kann das aber nicht erkennen. 
Ich muss also den worst-case berechnen und die Pausen zwischen einzelnen 
Bytes entsprechend dimensionieren, dass auch 2 ungünstige Interrups noch 
dazwischenpassen. Geschrieben wird im Slave immer direkt nach dem Lesen, 
also direkt im SPI-Interrupt.

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.