Forum: Mikrocontroller und Digitale Elektronik AVR als Schieberegister


von Peter (Gast)


Lesenswert?

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ß

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

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. ;-)

von Peter (Gast)


Lesenswert?

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.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

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. :-)

von Leo B. (luigi)


Lesenswert?

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.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

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. :-)

von Leo B. (luigi)


Lesenswert?

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.

: Bearbeitet durch User
von Klaus (Gast)


Lesenswert?

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

von asdfasd (Gast)


Lesenswert?

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.

von Thomas W. (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Leo B. (luigi)


Lesenswert?

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...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Christian K. (the_kirsch)


Lesenswert?

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.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

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.

von Christian K. (the_kirsch)


Lesenswert?

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.

von Bernd K. (prof7bit)


Lesenswert?

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.

von Bernd K. (prof7bit)


Lesenswert?

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).

: Bearbeitet durch User
von Christian K. (the_kirsch)


Lesenswert?

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.

: 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.