9 Schieberegister Seriell oder Parallel beschreiben, was ist schneller?

Hi

Hab wieder zeit gefunden, um an der Ansteuerung meines LED-Cubes weiterzuarbeiten.

Ich benutze 9 Schieberegister.
1 um die 8 Ebenen zu schalten, und 8 für die 64 LEDs der geschalteten Ebene.
Es läuft so so ab, wenn ich das nicht falsch verstanden habe:

  1. Schieberegister schaltet auf Ebene 1, die 8 Schieberegister werden mit dem "bild" der 1. Ebene beschrieben.
  2. Schieberegister schaltet auf Ebene 2, die 8 Schieberegister werden mit dem "bild" der 2. Ebene beschrieben.
    .
    .
    .

Oder?

Da ein Mikrokontroller ja die daten nach und nach bearbeitet, und nichts gleichzeitig kann, hätte ich dazu eine Frage.

Wollte erst jedem Schieberegister eine Datenleitung geben, also dass die Register parallel beschrieben werden. Die andere möglichkeit wäre ja seriell, also die Daten durch die 9 schieberegister schieben.
Nur was ist schneller? Kommts nich aufs selbe hinaus?
Und würde der Ardu das von der verarbeitungsgeschwindigkeit schaffen?

MFG, Robdeflop®

Die schnellst Variante um die Schieberegister zu beschreiben ist Mit der SPI Schnistelle. Die Register Datenleitung an MOSI den Takt an CLK und den Latch an einen Beligigen Port

Hi

Danke erstmal :slight_smile:

Wie genau funktioniert das dann?
Also mit welchen Funktionen?
Sind ja nur einsen und nullen, die ich in Arrays gespeichert hab^^

MFG, Robdeflop®

Du kannst es ja erstmal mit dem "normalen" Shiftout probieren in meinem 7K Porgramm habe ich eine laufzeit zwischen 600-700µs deswegen reicht das mit du brauchst deine Daten in der Datenform Byte also Pakete für jeweils 8Ports weiter hier.
http://arduino.cc/en/Reference/ShiftOut
mit dem schnelleren SPI:
siehe hier
SPI - Arduino Reference baruchst dann aber auch die Daten in Bytes.

Ich verwende für meine Uhr 4 Register in "Seriell" und kann damit alle 60SekundenLeds leuchten lassen ohne Probleme mit dem langsamen Shiftout

Hi

ShiftOut kenn und kann ich^^
das mit dem SPI muss ich mir mal anschauen.

Bei mir gehts ja darum, 512 LEDs so anzusteuern, dass es flüssig aussieht.
Ob da ShiftOut reichen wird?

MFG, Robdeflop®

Hi

Ich hab grad mal das shiftOut sketch für 2 Schieberegister modifiziert, um zu schauen ob das mit 9 Schieberegistern, seriell beschrieben, von der Verarbeitungszeit her funktioniert.
Habe 2 Schieberegister angeschlossen, die restlichen weggelassen, der ardu "beschreibt" die nicht vorhandenen trotzdem^^

Hier der Code, ich hoffe er is nich falsch (nur zum testen):

const int latchPin = 8;
const int clockPin = 12;
const int dataPin = 11;

char inputString[2];

void setup() 
{
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
}

void loop() 
{
  for (int thisLed = 0; thisLed < 72; thisLed++) 
  {
    registerWrite(thisLed, HIGH);
  }
}

// This method sends bits to the shift registers:

void registerWrite(int whichPin, int whichState) {
  // the bits you want to send. Use an unsigned int,
  // so you can use all 16 bits:
  unsigned int bitsToSend = 0;    

  // turn off the output so the pins don't light up
  // while you're shifting bits:
  digitalWrite(latchPin, LOW);

  // turn on the next highest bit in bitsToSend:
  bitWrite(bitsToSend, whichPin, whichState);

  // break the bits into two bytes, one for 
  // the first register and one for the second:
  byte registerOne = highByte(bitsToSend);
  byte registerTwo = highByte(bitsToSend);
  byte registerTre = highByte(bitsToSend);
  byte registerFor = highByte(bitsToSend);
  byte registerFiv = highByte(bitsToSend);
  byte registerSix = highByte(bitsToSend);
  byte registerSev = highByte(bitsToSend);
  byte registerAig = highByte(bitsToSend);
  byte registerNin = highByte(bitsToSend);

  // shift the bytes out:
  shiftOut(dataPin, clockPin, MSBFIRST, registerNin);
  shiftOut(dataPin, clockPin, MSBFIRST, registerAig);
  shiftOut(dataPin, clockPin, MSBFIRST, registerSev);
  shiftOut(dataPin, clockPin, MSBFIRST, registerSix);
  shiftOut(dataPin, clockPin, MSBFIRST, registerFiv);
  shiftOut(dataPin, clockPin, MSBFIRST, registerFor);
  shiftOut(dataPin, clockPin, MSBFIRST, registerTre);
  shiftOut(dataPin, clockPin, MSBFIRST, registerTwo);
  shiftOut(dataPin, clockPin, MSBFIRST, registerOne);

  // turn on the output so the LEDs can light up:
  digitalWrite(latchPin, HIGH);
}

Das Ergebnis: Viel zu langsam! Eine LED, die ich angeschlossen habe, und nach jedem Beschreiben aufleuchtet, blinkt geschätzt 10 mal die Sekunde.
Und das is ja noch nicht viel was da im sketch ist. Es sollen ja noch Animationen usw kommen, evtl auch ein 2x16 char Display und ein SD-Kartenslot.

Wie ich mit dem SPI einzelne Bytes, oder halt Bits in ein Schieberegister scheiben kann, weiß ich leider immernoch nicht. Stehe wieder auf dem Schlauch. Und wird das dann ausreichend schnell genug sein?

Hier gehts ja auch. Nur der hat da noch nen ganzen batzen weitere Elektronik, so wie das aussieht.
Ich wollts ja einfach mit 9 Schieberegistern, 8 Transistoren und 8 8-bit LED-Treiber-Arrays (und natürlich widerständen) machen.

Schonmal danke im Vorraus.

MFG, Robdeflop®

Das SPI interface kann daten mit bis zu F_CPU/2 'verschieben'. Alles weitere steht im datenblatt (sogar mit C code beispielen). Fuer register-phobiker gibt es auch eine spi library im arduino fundus.

Wenn du auch noch animationen von einer SD card streamen willst, dann besorge dir am besten eine cpu, die 2 SPI schnittstellen hat. Eine davon geht fuer die speicherkarte wohl drauf. Im prinzip ist SPI zwar multi-slave, aber fuer den wuerfel koennte es evtl. zu zeitkritisch sein zwischendurch zu lesen (= wuerfel ist 'tot') und einen buffer zu fuellen.

Hi

Hmm, dann hätte ich aber wieder den Huddel mit dem Beschreiben des neuen CPU/uC, whatever. Bin es gewohnt direkt über USB den uC zu proggen. Einen ISP progger habe ich nicht, und wie man sowas beschreibt weiß ich (noch) nicht^^

Wie wäre es, notfalls 2 Arduinos zu verwenden?

(erstmal reichts wenn die Ansteuerung alleine funktioniert, mit paar Animationen die schon auf dem Ardu sind, das andere Gedöns mit dem Display, Speicherkarte usw kann ja später noch kommen).
Bin den Cube auch eig fast nur zum lernen ab bauen.

MFG, Robdeflop®

Naja. Wenigstens die schieberegister sind ja praktisch fast kostenlos. Am besten einfach ausprobieren :wink:

Hi

Hab den ganzen kram ja schon da^^
Nur bevor ich das zusammen schuster, wollte ich halt fragen, wie ich es zusammenschuster/löte....

Habe leider nicht so ein großes BreadBoard um die komplette Schaltung aufzubauen, deswegen hab ich einfach 1 Schieberegister genommen, eine LED, und simuliere die 9 Schieberegister. Ich schiebe also dauerhaft immer 72 Bits durch die "9 Register". (schiebe nur einsen durch). Die LED blinkt ca 10 mal in der Sekunde, also dauert das ganze zu lang.
Habe das ganze jez einfach mit dem ShiftOut gemacht, siehe weiter oben, da is der Code.

MFG, Robdeflop®

Dann probier das mal aus (ATmega168/328):

void setup_hardware_spi(void)
{
	byte clr;
	// spi prescaler:
	//
	// SPCR: SPR1 SPR0
	// SPSR: SPI2X
	//
	// SPI2X SPR1 SPR0
	//   0     0     0    fosc/4
	//   0     0     1    fosc/16
	//   0     1     0    fosc/64
	//   0     1     1    fosc/128
	//   1     0     0    fosc/2
	//   1     0     1    fosc/8
	//   1     1     0    fosc/32
	//   1     1     1    fosc/64

	/* enable SPI as master */
	SPCR |= (_BV(SPE) | _BV(MSTR));
	/* clear registers */
	clr = SPSR;
	clr = SPDR;
	/* set prescaler to fosc/2 */
	SPCR &= ~(_BV(SPR1) | _BV(SPR0));
	SPSR |= _BV(SPI2X);
}

byte spi_transfer(byte data)
{
	SPDR = data;		// Start the transmission
	while (!(SPSR & _BV(SPIF))) {}; // Wait for the end of the transmission
	return SPDR;	
}

data out: pin #11
data in: pin #12
clock: pin #13
latch: pin #10

Hi

Vielen dank schonmal!!!
Scheint ja nich viel zu sein^^

Data In pin wird ja denke ich mal nicht benötigt, also kann ich den einfach getrennt lassen?

Und zum senden eines Bytes muss ich nur die Funktion spi_transfer(byte) aufrufen? (bin noch nicht so fit mit dem Gram den du gepostet hast)

MFG, Robdeflop®

Genau.

Ein minimalbeispiel:

#define CLOCK 13
#define LATCH 10
#define DATA_IN 12
#define DATA_OUT 11

void setup(void) {
  pinMode(LATCH,OUTPUT); // CS/LATCH _muss_ als output definiert sein, bevor das spi modul als master aktiviert wird.
  pinMode(DATA_OUT,OUTPUT);
  pinMode(CLOCK,OUTPUT);
  pinMode(DATA_IN,INPUT);
  setup_hardware_spi();
}

void loop(void) {
  digitalWrite(LATCH,LOW);
  spi_transfer(255);
  // usw.
  digitalWrite(LATCH,HIGH);
}

void setup_hardware_spi(void)
{
	byte clr;
	/* enable SPI as master */
	SPCR |= (_BV(SPE) | _BV(MSTR));
	/* clear registers */
	clr = SPSR;
	clr = SPDR;
	/* set prescaler to fosc/2 */
	SPCR &= ~(_BV(SPR1) | _BV(SPR0));
	SPSR |= _BV(SPI2X);
        /* LSB first */
        SPCR |= _BV(DORD); // comment for MSB first
}

byte spi_transfer(byte data)
{
	SPDR = data;		// Start the transmission
	while (!(SPSR & _BV(SPIF))) {}; // Wait for the end of the transmission
	return SPDR;	
}

Hi

Danke :slight_smile:

ABER, da tut sich nun irgendwie garnix.
wenn ich 255 übertrage, ist ja jedes bit auf 1, aber trotzdem leuchtet keine LED. Auch der Clock bin sollte ja dauerhaft pulsieren, also leuchten, aber auch dieser bleibt dunkel.

MFG, Robdeflop®

Welches board hast du denn ueberhaupt?

Die pin nummern sind fuer den 10000er, 2009er und den uno gueltig. Und bei den schieberegistern (595?) alles beschaltet (reset, enable...)?

HI

Habe das Uno.

Jop, sollte richtig sein.
Reset? Enable? Meinst Latch oder was? oO

Die verkabelung ist wie im shiftOut Tutorial, nur halt an die Pins in den Defines angepasst.

Nen 1 uF Cap hab ich net, hab den einfach weggelassen, ging sonst auch immer so.

Trotzdem sollte man die LED an Pin 13 doch blinken sehen?

Achja, Schieberegister sind die 595^^

MFG, Robdeflop®

Der kondensator ist unnoetig. Diesbezueglich ist das tutorial schlichtweg falsch. Leider aendert das einfach niemand.

Das mein beispiel code nicht funktioniert ist mein fehler. Ich habe ihn berichtigt. Ich hatte es noch im hinterkopf, bin dann aber selbst darauf hereingefallen. Damit die SPI hardware als master (clock generator) funktioniert, MUSS der latch (CS, chip select) pin als OUTPUT definiert sein, bevor man das SPI modul activiert. Ich habe also die pinMode befehle einfach vorgezogen. Diesesmal habe ich es auf meinem 10000er geprueft und die 13er led leuchtet ganz schwach. So wie es sein sollte.

Hi

Viiiieeelen dank :slight_smile:
Werds gleich mal versuchen und berichten^^
Aber nochmals herzlichen Dank :wink:

Hab übrigens ma nen 2x2x2 Cube zusammengelötet und bissl rumgespielt um das Funktionsprinzip das ich im Kopf habe zu testen, klappt^^ Direkt auch erstmal meine erstan Animationen erstellt :smiley:
Wenn das mit dem SPI schnell genug ist, werd ich die komplette Elektronik mal zusammenlöten, sobald die neuen NPN-Transistoren da sind, die alten waren zu schwach.

MFG, Robdeflop®

Hi

Hmm, eben getestet.

void loop(void) 
{
  digitalWrite(LATCH,LOW);
  spi_transfer(255);
  spi_transfer(255);
  spi_transfer(255);
  spi_transfer(255);
  spi_transfer(255);
  spi_transfer(255);
  spi_transfer(255);
  spi_transfer(255);
  digitalWrite(LATCH,HIGH);
}

Da is ja jede LED an. Klappt auch.

void loop(void) 
{
  digitalWrite(LATCH,LOW);
  spi_transfer(255);
  spi_transfer(255);
  spi_transfer(255);
  spi_transfer(255);
  spi_transfer(255);
  spi_transfer(255);
  spi_transfer(255);
  spi_transfer(0);
  digitalWrite(LATCH,HIGH);
}

(hab 2 schieberegister angeschlossen, an jedem jeweils eine LED)
So sollte die LED des ersten Schieberegisters aus sein, die des zweiten an. Richtig? Es leuchten aber trotzdem beide.

Außerdem: Hab ja GND und VCC der Register auf 5V und GND. Die LEDs leuchten aber auch, wenn ich NUR GND oder 5V angeschlossen habe. Habe ich beides angeschlossen, leuchten die LEDs heller, andernfalls dunkler. Normal oder? Wenn ich GND oder 5V ab habe, versorgt ja der uC die Register mit strom, andernfalls der spannungsregler vom ardu = Heller?

MFG, Robdeflop®

Ohne Vcc am SR wird das ueber die clamping dioden versorgt. Das kann, muss aber nicht zuverlaessig funktionieren.

Warum da dennoch beide SR voll an zu sein scheinen kann ich auf den ersten blick nicht sagen. Ich wuerde da mal ein dickes delay (1-2 sekunden) in die schleife packen und ein alternierendes muster senden, damit es blinkt. Oder du nimmst ein osci.

Edit:

Ich habe deine loop() gerade mal mit 4 SR getestet. 3 sind an, 1 ist aus. Funktioniert.

Gehen sie aus, wenn du nur 0 sendest?