Verwenden eines Zählers zum Reduzieren der Pin-Anzahl für die SPI-Slave-Auswahl

Ich habe fünf SPI-SRAM-Chips, die ich von einem einzelnen Arduino aus steuern möchte. Ich habe solche Setups gesehen, die SCLK, MOSIund MISO, mit separaten SSPins teilen:

Mehrere Slave-SPI
(Bild mit freundlicher Genehmigung von Wikipedia)

Ich möchte jedoch vermeiden, fünf Pins für separate SSFreigaben zu verwenden. Ich denke darüber nach, einen Zähler zu verwenden, um die verschiedenen Slaves auszuwählen, damit ich den Countdown auf 2 Pins reduzieren kann.

Die Idee ist, zwei Stifte für die Richtung und die Uhr des Zählers zu verwenden. Der Code würde in etwa so aussehen:

int currentSlave = 1; // on setup I'll set the counter to 1

void SelectSlave(int id)
{
  // error checking
  if (id < 1 || id > 5) Serial.writeln("Invalid slave ID passed to SelectSlave.");

  // calculate the ID difference
  int diff = abs(id - currentSlave);
  if (diff == 0) return; // no need to do anything

  if (id > currentSlave) set(CTR_DIRECTION); // increment
  if (id < currentSlave) clear(CTR_DIRECTION); // decrement

  // calculate the number of clock pulses to send to the counter
  int pulses = 0;
  if (id > currentSlave) pulses = (1 << (id - 1)) - (1 << (currentSlave - 1));
  if (id < currentSlave) pulses = (1 << (currentSlave - 1)) - (1 << (id - 1));

  // send the clock pulses
  for(int i = 0; i < pulses; i++)
  {
    set(CTR_CLOCK);
    delay(1);
    clear(CTR_CLOCK);
    delay(1);
  }
}

Ich habe ein paar Fragen:

  • Gibt es Probleme im Zusammenhang mit dem SSEin- und Ausschalten mehrerer Pins während des Zwischenzählzeitraums?
  • Kann ich mich darauf verlassen, dass (die meisten) Zähler beim ersten Einschalten auf Null gesetzt werden?
  • Gibt es andere/bessere Möglichkeiten, die Anzahl der Pins in dieser Art von Setup zu reduzieren?
Anstatt eine Richtungslinie und eine Uhr zu verwenden, könnten Sie in Betracht ziehen, nur eine Reset-Linie und eine Uhr zu verwenden. Auf diese Weise können Sie immer sicher sein, dass der Zähler auf dem richtigen Wert steht, ohne sich merken zu müssen, wo er war. Nicht ganz so schnell, wenn Sie nur zu einem benachbarten Sklaven wechseln müssen, aber viel einfacher. Sie möchten wahrscheinlich sowieso eine Reset-Leitung, also spart dies einen Pin.
@tcrosley Ja, das habe ich auch in Betracht gezogen. Ich werde wahrscheinlich einen 4024-Zähler verwenden, da er klein und einfach ist.
Da Sie sowieso Inverter am Ausgang des 4024 haben müssen (da Chip-Selects fast immer negativ sind), sollten Sie stattdessen NAND-Gatter und einen retriggerbaren One-Shot verwenden, der alle Chip-Selects hoch hält, bis Sie aufhören, Takt zu senden Impulse.
Nicht unbedingt. Ich könnte einfach bis ~nstatt zählen n. Anstelle von 1, 2, 4, 8, 16würden die Impulszahlen also sein 30, 29, 27, 23, 15.
Nett, solange es kein Problem ist, mehrere CS's zu haben (wie an anderer Stelle besprochen). Nach einem Reset sind alle eingeschaltet.
Ja, nach einem Reset sende ich 30 Impulse, um das erste Gerät auszuwählen.

Antworten (3)

Sie könnten einen Serial-In-Parallel-Out-Shifter wie 74HC164 in Betracht ziehen. Du brauchst 2 Stifte. Mit 2 Pins können Sie beliebig viele Freigaben generieren. Ein 74HC138-Decoder würde mehr Pins benötigen, wenn die Anzahl der Ausgänge zunimmt. Ein Zähler würde in einigen Fällen viele viele Taktimpulse benötigen, um jeweils nur einen Ausgang zu aktivieren. Der 74HC164-Shifter benötigt höchstens n Taktimpulse, um n Freigaben zu erzeugen.

Ah, im Wesentlichen könnte ich das Register "leeren", indem ich 8 Taktimpulse mit dem Datenpin hoch sende und dann einen Taktimpuls mit dem Datenpin niedrig sende, um ein einzelnes "Aktivierungs" -Bit hinzuzufügen. Dann kann ich mehr Taktimpulse mit dem Datenpin hoch senden, um das Aktivierungsbit auf das Gerät zu drücken, das ich brauche. Das ist schlau, ich schaue mir das an. Update: Ah, ich habe tatsächlich ein paar 74HC164N-Ersatz-ICs herumhängen, großartig :)
Normalerweise würden Sie die ersten 3 Ausgänge für Ihre Freigaben verwenden. Dann brauchst du nicht zu spülen. Takten Sie einfach 3 Datenbits ein.
Nun, die ersten 5 in meinem Fall :)

Der typische Weg, dies zu tun, ist mit einem Demux oder Decoder 3 bis 8 Decoder .

In Ihrem Fall würden Sie jedoch 3 Signale benötigen, um die 5 Chipauswahlleitungen mit diesem Ansatz zu erzeugen (Sie erhalten tatsächlich 8 Ausgänge für 3 Eingänge).

Ihr Ansatz hat auch Vorteile, solange Sie keine Daten senden, während Sie Ihre Chipauswahloptionen durchlaufen. Die meisten Zähler haben eine voreingestellte Zeile oder eine Methode, sie beim Start zu löschen.

Solange ich also keine SPI-Operationen initiiere (dh solange ich aufhöre, Taktimpulse über den CLKPin zu senden), sollte es bei diesem Ansatz kein Problem geben?
Ich kann mir keine vorstellen, solange der Ausgang des Zählers in der Lage ist, den Eingang Ihres Spi-Geräts anzusteuern.
Gibt es einen Grund, warum ein Zähler es nicht steuern könnte? Ich suchte nach einem 8-Bit-Up/Down-Zähler, konnte aber keinen guten finden. Im Moment schaue ich mir die Verwendung des SN74HC590 an, der nur hochzählt, für den ich einfach auf 0 zurücksetzen kann, wenn die neue Slave-ID niedriger als die aktuelle ist.
@Polynomial Denken Sie nur daran, dass es sich um einen Decoder mit aktiven Low-Ausgängen handeln muss (wie der 74VHC138, den Matt Ihnen vorgeschlagen hat). Und vergessen Sie Zähler (die normalerweise mehrere Ausgänge gleichzeitig aktivieren). Sie benötigen einen Decoder (der jeweils nur einen Ausgang aktiviert) oder einen Demultiplexer (komplexer).
@Telaclavo Siehe Kommentare zur Frage selbst für meine Lösung des Active-Low-Problems. Gibt es eigentlich einen Grund, warum ich nicht mehrere SPI-Slaves kurzzeitig aktivieren sollte? Die Geräte verwenden keine Interrupts, und ich verschiebe während des Umschaltens keine Daten zum oder vom Gerät. Ich deaktiviere sogar die Uhr während des Umschaltens. Ich habe das SPI-Protokoll schnell gelesen, und es sieht so aus, als würde nichts passieren, es sei denn, ich veranlasse es ausdrücklich. Ein 3-zu-8-Decoder benötigt einen zusätzlichen Pin, daher möchte ich ihn wirklich vermeiden.
Dieser Zähler sollte ihn antreiben, ich wollte eher, dass Sie sicherstellen, dass Ihre Logikpegel gleich sind und dass aktive Tiefs/Hochs richtig funktionieren. Möglicherweise müssen Sie den Ausgängen des Zählers einen Inverter hinzufügen oder auf eine Zahl zählen, die weniger intuitiv ist, um Ihnen alle Einsen und eine Null zu geben.

Ich hatte in der Vergangenheit ein ähnliches Problem, aber mit nur zwei SPI-Geräten. Meine Lösung bestand darin, einen PIC12F1822 als SS-Umschalter zu verwenden. Es lief mit 8 MIPS unter Verwendung seines internen Oszillators und hatte Code, der diese Funktion ausführte:

if SS input goes low then
    if MOSI is low, then
        set SS_OUT_1 low
     else
        set SS_OUT_2 low
    end if
end if

if SS input goes high then
    set SS_OUT_1 high
    set SS_OUT_2 high
end if

Es hat sich einfach ewig darauf geschleift. Der Code wurde in etwa 20 Assembleranweisungen geschrieben und hatte eine ziemlich gute Latenz von etwa einer Mikrosekunde IIRC.

Sie könnten einen sehr ähnlichen Code schreiben, mit dem Sie eine beliebige Anzahl von Slaves auswählen können, indem Sie MOSI als Up / Down-Signal verwenden, EG

bits = 0b11111110

begin loop
    if SS input goes low then
        if MOSI is low, then
            bits <<= 1
        else
            bits >>= 1
        end if

        SS_PORT = bits
    end if

    if SS input goes high then
        SS_PORT = 0b11111111
    end if

end loop

Obwohl Sie einen PIC mit mehr Pins verwenden müssten, z. B. PIC12LF1840T48A .

Scheint für eine solche Anwendung übertrieben zu sein - ich müsste einen PIC-Programmierer kaufen / bauen.
@Polynomial - Ersetzen Sie dann den PIC12 durch ein ATtiny, dafür haben Sie einen Programmierer. Ein ATtiny13A-SU hat 6 IO Pins, das sollte reichen.
Trotzdem könnte ich es mit einem Zähler billiger (und etwas einfacher) herstellen.
@Polynomial - Oder ein Schieberegister?