Hallo,
hat einer bereits einen AVR als SPI Schieberegister programmiert?
Ich habe nach einem Schieberegister gesucht, was wenn einmal Daten über
SPI erhalten hat, eine eigenständige PWM durchläuft für insgesamt 3
Kanäle. Ich brauche hierbei eine PWM Freq von ~15kHz.
Nun habe ich es noch nicht sinnvoll hinbekommen, dass der Master die
Daten an die Slaves schickt. Das erste Register soll 3*256 Bits abrufen.
Solange SS den Zustand nicht gewechselt halt, soll er die nächsten Bits
an die nächsten Slaves weiterleiten. Erst wenn sich der Status von SS
ändert, sollen die Werte an die PWMs weitergeleitet werden.
So wie halt ein HC595 oder ähnliches. Dabei soll das ganze System ohne
feste Adresse ablaufen. In einen AVR rein und hinten wieder raus.
Doch den part bekomme ich nicht hin und bei den Suchbegriffen findet man
immer nur das falsche -> AVR Schieberegister.
Ich hatte zwischenzeitig schon an ein WS2801 IC gedacht mit getakteter
Konstantspannung am Ausgang (s. DB). Jedoch ist die Schaltfrequenz der 3
Ausgänge nur bei etwa 2,5kHz.
Gruß
Hallo Peter,
Peter schrieb:> Ich habe nach einem Schieberegister gesucht, was wenn einmal Daten über> SPI erhalten hat, eine eigenständige PWM durchläuft für insgesamt 3> Kanäle. Ich brauche hierbei eine PWM Freq von ~15kHz.
Gibt es ein Schaltbild für dein Vorhaben?
Was bedeutet es, "eine eigenständige PWM" zu "durchlaufen"? Soll das der
AVR tun?
> Nun habe ich es noch nicht sinnvoll hinbekommen, dass der Master die> Daten an die Slaves schickt. Das erste Register soll 3*256 Bits abrufen.> Solange SS den Zustand nicht gewechselt halt, soll er die nächsten Bits> an die nächsten Slaves weiterleiten. Erst wenn sich der Status von SS> ändert, sollen die Werte an die PWMs weitergeleitet werden.
Wer ändert den Status von SS? Ist das ein Eingang des AVR oder ein
Ausgang?
> Doch den part bekomme ich nicht hin
Würde ich auch nicht... ich hab ihn nicht verstanden. ;-)
Hallo Markus,
einen Schaltplan habe ich noch nicht erstellen können. Die KSQ habe ich
noch nicht aufgebaut. Derzeit teste ich das ganze mit einfachen RGB Leds
(+3Widerstände) an einem Attiny841.
Eigenständige PWM soll heißen, ich möchte einmalig Daten an den SPI
Slave schicken. zB:
127, 0, 0,
Nun wird abgewartet bis der SS wieder HIGH ist. Dann werden die Daten
übernommen werden. Nun macht der Slave dauerhaft auf dem roten Kanal
eine PWM mit 50%.
Wenn ich nun aber 255,127,0,0,55,125 schicke, sollen die ersten 3 Bytes
direkt an den nächsten Slave weitergeleitet werden.
Habe hier im Forum schon einige Vorschläge gelesen, dass man für das
Vorhaben auch direkt einen AVR nehmen kann, da diese meist sogar
günstiger als bestimmte Schieberegister sind (von den hc595 rede ich
nicht) und man halt diese frei programmieren kann. Einen Code Snippets
zum Einstieg habe ich nicht gefunden. Die AppNotes haben nicht
weitergeholfen.
Peter schrieb:> 127, 0, 0,> Nun wird abgewartet bis der SS wieder HIGH ist. Dann werden die Daten> übernommen werden. Nun macht der Slave dauerhaft auf dem roten Kanal> eine PWM mit 50%.
Wer wartet? Das AVR-basierte Schieberegister, das du verwenden willst?
SS = Slave Select, oder?
> Wenn ich nun aber 255,127,0,0,55,125 schicke, sollen die ersten 3 Bytes> direkt an den nächsten Slave weitergeleitet werden.
Wenn ich es richtig verstehe, soll ein 768 bit langer Bitstrom
aufgesplittet werden in Portionen von 24 bit. Jede dieser Portion soll
an einen anderen Ausgang gehen...?
Oder wird der Strom sowieso an alle 841 gleichzeitig gesendet, und du
willst nur die SS-Eingänge der 841 alle 24 bit umschalten
Kann aber gut sein, dass meine grauen Zellen schon etwas langsam
rotieren um diese Uhrzeit. :-)
Wie stellst du dir die CLK-Leitung vor?
Wenn du die auf alle Chips verteils, woher soll ein µC dann wissen an
welcher Position es sitzt? Soll da dann jeweils noch eine SS-Leitung von
Chip zu Chip, die jeweils vom Vorgänger aktiviert wird, sobald der seine
3 Bytes hat?
Dann hast du ein kleines Problem mit dem SPI-Moduls. Selbiges erlaubt
dir ja immer erst nach dem vollständigen Empfangen eins Bytes Zugriff
auf das Byte, welches du ja gerade schon weiter schicken willst. Du
müsstest also schon vorher wissen was du empfangen wirst um das auch im
richtigen Moment weiter schicken zu können. Folglich kannst das 1.Byte
für den 2. Slave erst mit dem 4. vom Master gesendeten Byte aus dem
SPI-Modul des 1.Slave getaktet werden. Das führt dazu, dass dir am Ende
Takte fehlen (Jeder Slaver verzögert die Daten ja um 1 Byte). Der Master
müsste also für jeden gesendeten 3-Byte-Block ganz am ende ein weiteres
Dummy-Byte senden damit die Daten für das letzt Slave auch bei diesem
ankommen können.
Alternativ musst jeder Slave nach dem 3.Byte das SPI deaktivieren und
per Software die Datenleitung "überbrücken". Das führt natürlich zu
einer Latenz und kann nach ein paar µCs schon zu Fehlern führen.
Leo B. schrieb:> Selbiges erlaubt> dir ja immer erst nach dem vollständigen Empfangen eins Bytes Zugriff> auf das Byte, welches du ja gerade schon weiter schicken willst.
Hallo Leo, berechtigter Einwand.
Das Problem tritt aber nicht auf, wenn SPI per Software abgewickelt
wird. Dann kann man quasi sofort Bit für Bit reagieren.
Bringt mich aber wieder zu Frage 1: ein (zumindest grob skizzierter)
Schaltplan wär nicht verkehrt. :-)
Markus Weber schrieb:> Hallo Leo, berechtigter Einwand.> Das Problem tritt aber nicht auf, wenn SPI per Software abgewickelt> wird. Dann kann man quasi sofort Bit für Bit reagieren.
Dann schreib 2 software-SPI-Module, sonst wird die Datenleitung über die
Chips zu arg verzögert gegenüber dem CLK-Signal.
Aber mir kam ein anderer Gedanke:
Slave n empfängt 3 Byte, legt dann das 1.Byte zum Senden ins
SPI-Datenregister und aktiviert SS von Slave n+1. Möglicherweise kommen
jetzt wieder 3 Byte vom Master/Slave n-1. Diese überschreiben dann die
vorherigen, wobei die vorherigen jeweils an Slave n+1 übertragen werden.
Das wiederholt sich immer und immer wieder bis SS vom Master/Slave n-1
deaktiviert wird. Dann wird auch SS für Slave n+1 deaktiviert und die
jetzt im Speicher befindlichen Daten werden verwendet.
Das würde zwar die ersten 3-Byte zum letzen Chip durch schieben und
nicht wie bei den WSxxx-Chips im 1.Chip behalten aber die Reihenfolge
kann der Master ja auch umdrehen. Tut ja nicht weh.
Leo B. schrieb:> Aber mir kam ein anderer Gedanke:> Slave n empfängt 3 Byte, legt dann das 1.Byte zum Senden ins> SPI-Datenregister und aktiviert SS von Slave n+1. Möglicherweise kommen> jetzt wieder 3 Byte vom Master/Slave n-1. Diese überschreiben dann die> vorherigen, wobei die vorherigen jeweils an Slave n+1 übertragen werden.> Das wiederholt sich immer und immer wieder bis SS vom Master/Slave n-1> deaktiviert wird. Dann wird auch SS für Slave n+1 deaktiviert und die> jetzt im Speicher befindlichen Daten werden verwendet.>> Das würde zwar die ersten 3-Byte zum letzen Chip durch schieben und> nicht wie bei den WSxxx-Chips im 1.Chip behalten aber die Reihenfolge> kann der Master ja auch umdrehen. Tut ja nicht weh.
Eigentlich müßte man es umgekehrt machen:
Wenn SS aktiviert wird, liest der Slave die ersten 3 Byte und verwendet
sie. Kommen weitere, solange SS immer noch aktiv ist, aktiviert er
selbst sein SS-out zum nächsten und schickt die Bytes die er jetzt
bekommt weiter, solange sein SS-input immer noch aktiv ist. Wird sein
SS-input deaktiviert, macht er das Byte, daß er gerade in Arbeit hat
fertig, und deaktiviert sein SS-out. Die Message wird so bei jedem Slave
jedesmal um 3 Byte kürzer. Kein Slave braucht zu wissen, wo er in der
Kette plaziert ist und wie lang die Message ist oder sein wird. Die
ersten 3 Byte sind auf jedenfall für ihn.
Die Clock vom Master-SPI der die Daten weiterreicht sollte man frisch
erzeugen, dann hat man weniger Probleme mit Delays bei den Daten.
MfG Klaus
Wo ist das Problem? Das SS bei AVR ne reine Softwaresache ist, kann man
da machen was man will. Und nen beliebig langes Schieberegister ist
doch nicht das Problem:
CLK und SS an alle Module parallel, DI vom ersten zum Master, DO zum DI
des zweiten usw. Jedes Modul hat einen Buffer von n Bytes und einen
Index i, der auf das aktuelle Byte zeigt.
Vorgehensweise auf allen Modulen:
- Der Counter-Overflow-Irq macht folgendes: Input-Register lesen und
Daten in buf[i] abspeichern, i incrementieren (modulo n), buf[i] ins
Output-Register schreiben.
- Der Pin-Change-Irq von SS macht folgendes: Daten aus dem Buffer zur
PWM-Routine übergeben, CLK-Counter und Index resetten.
Man muss halt nur "rückwärts" senden - die Bytes die als letztes
gesendet werden, landen im ersten Modul. Also z.B. bei n=3 und der
Bytefolge 00 11 22 33 44 55 landet 33 44 55 im ersten Module und 00 11
22 im zweiten - genau wie bei hintereinandergeschalteten
Schieberegistern.
Dass am Anfang Müll weitergeschoben wird (im Buffer und Output-Register
noch nichts Sinnvolles), ist egal - der Müll fällt am letzten Modul eh
hinten raus.
Zur Initialisierung sollte der Master eine lange 0-Folge senden
(mindestens ein Byte länger als das gesamte Schieberegister aller Module
zusammen) und dann einen Puls auf SS zu geben. Dadurch werden alle Bit-
und Byte-Counter synchronisiert und alle PWMs auf 0 gesetzt.
Markus Weber schrieb:> Bringt mich aber wieder zu Frage 1: ein (zumindest grob skizzierter)> Schaltplan wär nicht verkehrt. :-)
Und wo wir schon bei Dokumentation sind: Ein Impulsdiagramm würde die
Sache sicher verständlicher machen und ewaige Probleme aufdecken,
insbesondere wenn man das gleich mit dem der SPI-Schnittstelle gegenüber
stellt.
Peter schrieb:> So wie halt ein HC595 oder ähnliches.
Ganz genau so macht es das AVR-SPI.
Das SPI ist ein 8Bit-SRG, einfach MISO des einen mit MOSI des nächsten
verbinden.
Du sendest 3 Byte, dann hat der erste das letzte, der 2. das mittlere
und der letzte das erste Byte empfangen.
Peter schrieb:> Wenn ich nun aber 255,127,0,0,55,125 schicke, sollen die ersten 3 Bytes> direkt an den nächsten Slave weitergeleitet werden.
Das geht natürlich nicht. Das SRG ist immer 8Bit lang.
Du könntest 3 Pakete a 2 Byte draus machen, also 2 Byte, Pause, 2 Byte,
Pause usw. Ein Timerinterrupt erkennt dann die Pause und übernimmt das
Byte.
Eine Weitere Möglichkeit wäre wohl, Daten und Takt vom Master parallel
an alle Slaves zu schicken und nur das SS durch zu schleifen. Jedes
Slave empfängt 3 Byte und aktiviert dann den SS des nächsten Slave.
Damit das zuverlässig funktioniert sollte der Master vielleicht eine
kleine Pause nach jedem 3er-Block einlegen, damit ein Slave zeit hat
seinen Nachfolger zu aktivieren, und der dann auch die Daten so empfängt
wie gewünscht und nicht evtl. um ein paar Bit verschoben.
Möglichkeiten über Möglichkeiten... Der TO sollte sich vielleicht auch
mal ein paar Gedanken machen und einfach ausprobieren. Learning by
doing...
Hier noch eine Möglichkeit:
Beitrag "Equinox-Uhr mit 60 ATtinys"
Immerhin schafft jeder ATtiny damit 3 x 12 Bit PWMs und ist damit jeder
WS2812-LED haushoch überlegen.
Wo ist das Problem?
Man kann doch problemlos die SPI-Slavas kaskadieren, auch mit der
Hardware-SPI der AVRs.
In der ISR muss nur das letzte empfangende Byte sofort wieder ins
Senderegister schreiben und die letzten 3 Bytes speichern.
volatile uint8_t spi1;
volatile uint8_t spi2;
volatile uint8_t spi3;
ISR( SPI_STC_vect ) {
spi3 = spi2;
spi2 = spi1
spi1 = SPDR;
SPDR = SPDR;
}
Der Master sollte dann aber nach jedem Byte die CLK Leitung kurz ruhen
lassen, damit die Slaves ihre ISR ausführen können.
Eventuell geht das sogar automatisch da der Master ja selbst in einer
ISR steckt, um das nächste Byte zu laden.
EDIT:
Zusätzlich zur SS Leitung am besten noch eine weitere Leitung benutzen,
die dann besagt das die Übertragung abgeschlossen ist.
Ähnlich wie der RCK-Pin eines 74xx595. Auch wenn die SS-Leitung die
ganze Zeit Low ist und am Ende wieder auf HI geht, kannst du das schwer
in der Software auswerten.
Theoretisch geht es auch mit einer Leitung wenn du sie zusätzlich auf
einen weiteren Pin legst der Interrupt fähig ist.
Manche AVRs haben auch PIN-Change-Interrupt für jede Ports, darüber kann
man dann auch den SS-Pin nochmal abfragen.
Christian K. schrieb:> Man kann doch problemlos die SPI-Slavas kaskadieren, auch mit der> Hardware-SPI der AVRs.
Korrekt, das geht sowohl mit der Hardware-SPI als auch mit dem USI.
> In der ISR muss nur das letzte empfangende Byte sofort wieder ins> Senderegister schreiben
Wenn mich meine Erinnerung nicht ganz täuscht, muß man zumindest beim
USI nicht mal dies tun, es genügt hier, das USIOIF zurückzusetzen. Das
Shift-Register behält doch seinen Inhalt, man muß da nicht extra noch
einmal exakt dasselbe erneut reinschreiben. Und bei neueren Tinys
braucht man nichtmal mehr zwingend sofort jedes empfangene Byte
auslesen, sondern hat knapp acht SPI-Bitzeiten lang Zeit, zu ermitteln,
ob es einen überhaupt interessiert, um es dann ggf. noch aus dem
Bufferregister des USI auszulesen.
Beim Hardware-SPI bin ich mir nicht ganz sicher, ob der Schreibvorgang
nach SPDR eventuell nötig ist, um die SPI-Logik wieder "freizugeben".
Müßte man glatt mal ausprobieren, ob es auch ohne geht. Ich würde fast
vermuten, daß es prinizipiell genauso wie beim USI garnicht nötig ist.
c-hater schrieb:> Beim Hardware-SPI bin ich mir nicht ganz sicher, ob der Schreibvorgang> nach SPDR eventuell nötig ist, um die SPI-Logik wieder "freizugeben".> Müßte man glatt mal ausprobieren, ob es auch ohne geht. Ich würde fast> vermuten, daß es prinizipiell genauso wie beim USI garnicht nötig ist.
Du könntest recht haben, das die Zeile
SPDR = SPDR;
unnötig ist. Eine Daisy Chain hab ich mit AVR-SPI-Slaves noch nicht
gemacht. Einfach mal ausprobieren.
asdfasd schrieb:> Vorgehensweise auf allen Modulen:>> - Der Counter-Overflow-Irq macht folgendes: Input-Register lesen und> Daten in buf[i] abspeichern, i incrementieren (modulo n), buf[i] ins> Output-Register schreiben.>> - Der Pin-Change-Irq von SS macht folgendes: Daten aus dem Buffer zur> PWM-Routine übergeben, CLK-Counter und Index resetten.
Das ist die richtige Antwort.
Die SS-Leitung würde ich aber umtaufen zu RCK um mit der einschlägigen
Literatur und üblichen Bezeichnungen dieser Leitung konform zu gehen.
Christian K. schrieb:> In der ISR muss nur das letzte empfangende Byte sofort wieder ins> Senderegister schreiben und die letzten 3 Bytes speichern.
Nein, er muss sie verzögern, er braucht einen 2 Byte grossen FIFO-Puffer
in jedem Device denn wenn der RCK kommt "gehören" jedem Device genau die
3 Byte die es zuletzt bekommen hat (das was noch im Register steht und
die anderen zwei aus dem FIFO), und die gehören dem jeweiligen Device
alleine, es soll ja keine Überlappungen geben.
> Zusätzlich zur SS Leitung am besten noch
Er braucht gar keine SS denn es gibt ja nichts zum selecten, es gibt ja
nur einen einzigen (sehr langen) Slave, der ist immer aktiv. Er braucht
nur
MOSI->MOSI, MISO->MOSI,... ,
SCK (parallel an alle) und
RCK (parallel an alle).
Doch SS wird benötigt, da die Slaves sonst nicht wissen wann das erste
Bit los geht, würde SS Hard auf LOW verdrahtet sein, könnten sie aus den
Tritt geraten.
Aber man kann das gleiche Signal für SS und RCK nehmen.
Er hat geschrieben das er ATTiny841 benutzt.
Da würde ich den PCINT0 verwenden und diesen nur auf PORTA7 Triggern,
das ist der SS-Pin.
In der PCINT0-ISR abfragen ob PA7 HI ist, und dann die Variablen SPI1,2
und 3 auswerten.