Uso de un contador para reducir el conteo de pines para la selección de esclavos SPI

Tengo cinco chips SPI SRAM, que quiero controlar con un solo Arduino. He visto configuraciones como esta, que comparten SCLK, MOSIy MISO, con SSpines separados:

SPI esclavo múltiple
(imagen cortesía de Wikipedia)

Sin embargo, me gustaría evitar el uso de cinco pines para SShabilitaciones separadas. Estoy considerando usar un contador para seleccionar los diferentes esclavos, así puedo reducir el conteo a 2 pines.

La idea es usar dos pines para la dirección del contador y el reloj. El código sería algo como esto:

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

Tengo algunas preguntas:

  • ¿ Hay algún problema relacionado con la activación SSy desactivación de varios pines durante el período de conteo intermedio?
  • ¿Puedo confiar en que (la mayoría) de los contadores se establezcan en cero cuando se enciende por primera vez?
  • ¿Hay otras/mejores formas de reducir el número de pines en este tipo de configuración?
En lugar de usar una línea de dirección y un reloj, puede considerar simplemente usar una línea y un reloj de reinicio. De esa manera, siempre puede estar seguro de que el contador está en el valor correcto, sin tener que recordar dónde estaba. No tan rápido si solo tienes que moverte a un esclavo adyacente, pero mucho más simple. Probablemente querrá una línea de reinicio de todos modos, por lo que esto ahorra un pin.
@tcrosley Sí, también lo consideré. Probablemente terminaré usando un contador 4024, ya que es pequeño y simple.
Dado que de todos modos tendrá que tener inversores en la salida del 4024 (ya que las selecciones de chip son casi siempre negativas), podría considerar usar puertas NAND en su lugar y un disparo único reactivable que mantendría todas las selecciones de chip altas hasta que deje de enviar el reloj pulsos.
No necesariamente. Podría contar hasta ~nen lugar de n. Entonces, en lugar de 1, 2, 4, 8, 16, el conteo de pulsos sería 30, 29, 27, 23, 15.
Lindo, siempre que tener múltiples CS encendidos no sea un problema (como se discutió en otra parte). Después de un reinicio, todos estarán encendidos.
Sí, después de un reinicio, enviaré 30 pulsos para seleccionar el primer dispositivo.

Respuestas (3)

Podría considerar una palanca de cambios de entrada en serie y salida en paralelo como 74HC164. Necesitas 2 pines. Puede generar tantas habilitaciones como desee con 2 pines. Un decodificador 74HC138 necesitaría más pines a medida que aumentara el número de salidas. Un contador necesitaría muchos pulsos de reloj para habilitar solo una salida a la vez en algunos casos. La palanca de cambios 74HC164 necesita como máximo n pulsos de reloj para producir n habilitaciones.

Ah, esencialmente podría "vaciar" el registro enviando 8 pulsos de reloj con el pin de datos alto, luego enviar un pulso de reloj con el pin de datos bajo para agregar un solo bit de "habilitación". Luego puedo enviar más pulsos de reloj con el pin de datos alto para empujar el bit de habilitación hacia el dispositivo que necesito. Eso es inteligente, lo investigaré. Actualización: Ah, en realidad tengo algunos circuitos integrados 74HC164N de repuesto dando vueltas, increíble :)
Por lo general, usaría las primeras 3 salidas para sus habilitaciones. Entonces no es necesario tirar de la cadena. Solo registre 3 bits de datos.
Bueno, los primeros 5 en mi caso :)

La forma típica de hacer esto es con un demultiplexor o decodificador de 3 a 8 decodificadores .

Sin embargo, en su caso, necesitaría 3 señales para producir las 5 líneas de selección de chips utilizando este enfoque (en realidad obtiene 8 salidas para 3 entradas).

Su enfoque también tiene mérito, siempre que no envíe datos mientras recorre las opciones de selección de su chip. La mayoría de los contadores tienen una línea preestablecida o algún método para borrarlos al inicio.

Entonces, mientras no inicie ninguna operación SPI (es decir, mientras deje de enviar pulsos de reloj por el CLKpin), ¿no debería haber ningún problema con este enfoque?
No puedo pensar en ninguno, siempre que la salida del contador sea capaz de controlar la entrada de su dispositivo spi.
¿Hay alguna razón por la que un contador no pueda conducirlo? Estaba buscando un contador arriba/abajo de 8 bits, pero no pude encontrar uno bueno. En este momento, estoy considerando usar el SN74HC590, que solo cuenta hacia arriba, por lo que puedo restablecerlo a 0 si la nueva ID de esclavo es menor que la actual.
@Polynomial Solo recuerde que tiene que ser un decodificador con salidas bajas activas (como el 74VHC138 que Matt le ha propuesto). Y olvídate de los contadores (que suelen activar varias salidas a la vez). Necesita un decodificador (que activa solo una salida a la vez) o un demultiplexor (más complejo).
@Telaclavo Vea los comentarios sobre la pregunta en sí para mi solución al problema de actividad baja. ¿Hay alguna razón por la que no deba habilitar múltiples esclavos SPI por un corto tiempo? Los dispositivos no usan interrupciones, y no muevo ningún dato hacia o desde el dispositivo durante el cambio. Incluso estoy deshabilitando el reloj durante el cambio. Leí rápidamente el protocolo SPI y parece que no pasa nada a menos que lo provoque explícitamente. Un decodificador de 3 a 8 requiere un pin adicional, por lo que realmente me gustaría evitarlo.
Ese contador debería impulsarlo, quería más que se asegurara de que sus niveles lógicos fueran los mismos y que los mínimos/máximos activos funcionen correctamente. Es posible que deba agregar un inversor a las salidas del contador o contar hasta un número que sea menos intuitivo para obtener todos unos y un cero.

Me he enfrentado a un problema similar en el pasado, pero con solo dos dispositivos SPI. Mi solución fue usar un PIC12F1822 como conmutador SS. Corría a 8 MIPS usando su oscilador interno y tenía un código que hacía esta función:

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

Simplemente se repitió para siempre en eso. El código se escribió en unas 20 instrucciones de ensamblador y tenía una latencia bastante buena de aproximadamente un microsegundo IIRC.

Podría escribir un código muy similar que le permita seleccionar cualquier número de esclavos, usando MOSI como una señal arriba/abajo, 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

Aunque tendrías que usar un PIC con más pines, EG PIC12LF1840T48A .

Parece excesivo para una aplicación de este tipo: tendría que comprar/construir un programador PIC.
@Polynomial: luego sustituya un ATtiny por el PIC12, tiene un programador para eso. Un ATtiny13A-SU tiene 6 pines IO, eso debería funcionar.
Aún así, podría producirlo más barato (y algo más fácil) con un contador.
@Polynomial - ¿O un registro de desplazamiento?