Cómo usar ATmega328 SPI con un registro de desplazamiento de 31 bits

5

Estoy usando un controlador Allegro 6280 PWM LED para un proyecto. Este es un pequeño IC fresco, excepto por el hecho de que es un registro de entrada de 31 bits. Esto no es un problema si simplemente recorro mis 31 bits y configuro los estados de los pines en consecuencia, pero quiero usar el SPI incorporado de la atmega para acelerar las cosas un poco (el 6280 requiere una fuente de reloj externa para su bit de 10 bits ciclo PWM largo).

El registro de 31 bits se ve así en mi aplicación donde R, G & B indica los valores PWM de 10 bits para los LED adjuntos.

0BBBBBBBBBBGGGGGGGGGGRRRRRRRRRR

Estos registros de turnos son desechables, por lo que he creado una lista enlazada para representarlos:

struct Pixel {
  uint16_t red;
  uint16_t green;
  uint16_t blue;
  Pixel *next;
};

Por lo tanto, la idea es establecer el pin de cierre bajo, iterar a través de todos los píxeles y luego, después de enviar el último, establecer el bloqueo alto para bloquear los datos en cada registro. Esto parece fácil, excepto que debido a la longitud desigual del registro, tengo que construir un código de aspecto desagradable para poder volver al principio de manera que nunca envíe ningún bit vacío. Además, es posible que el pestillo deba ocurrir después de que se transmita un número arbitrario de bits, no solo el último.

¿Alguien tiene alguna idea sobre cómo hacer esto, o simplemente estoy ladrando el árbol equivocado y reteniéndome manualmente con los estados del pin?

Gracias.

    
pregunta jamesotron

2 respuestas

5

He estado monitoreando esta pregunta y, como nadie ha respondido todavía, voy a intentarlo. Pido disculpas por adelantado si mi razonamiento termina siendo defectuoso, pero haré mi mejor esfuerzo.

Creo que la posibilidad de hacer que su proyecto funcione depende de cuántos LEDs RGB planea usar. He estado revisando la hoja de datos de Allegro, y parece que necesita emparejar un IC con uno de cada LED rojo, verde y azul (es decir, un píxel RGB). Todos los datos se transmiten a lo largo de la cadena de 6280.

Si solo quieres tener un píxel RGB, o más específicamente, N píxeles que muestren la misma información temporal, entonces creo que podrías salirte con el uso de SPI. Creo que la idea de la lista enlazada es el camino correcto, pero obviamente la clave es bloquear el LI en el momento adecuado (cada 31 bits), y no estará en los límites de 8 bits. Las únicas bibliotecas SPI que he usado en micros toman un byte, registran los datos y leen el byte de respuesta. En su caso, deberá averiguar cómo realizar una función SPI que pueda activar LI durante una transferencia de bytes.

Dado que SPI requiere transferir un byte a la vez, se verá obligado a enviar 32 bits cuando solo desee 31. Por lo tanto, el 32do bit será el primer bit de su segundo conjunto de datos RGB. Establecerás LI antes de cerrar el bit 32. Para la siguiente ronda de datos, activará LI antes de cerrar el bit 31st. Es posible que pueda hacer esto sin escribir su propia biblioteca SPI, pero no estoy seguro.

Si desea admitir datos de desplazamiento, entonces las cosas parecen un poco más complicadas. Me está costando mucho formular la explicación, pero la sincronización con LI será interesante. LI determina la rapidez con la que se desplazará la pantalla, ya que determina cuándo un 6280 envía los datos al siguiente.

Para el primer conjunto de datos RGB, activará LI tan pronto como haya marcado 31 bits. También ha marcado 1 bit para el siguiente conjunto de datos. Luego, registrará otros 3 bytes de datos, más 6 más antes de activar LI. Pero si el tiempo de desplazamiento es lento, no puede enviar el byte que contiene los últimos 6 bits hasta que esté listo para activar LI , ¡porque no desea desbordar el búfer del registro de desplazamiento! Pero una vez que esté listo para activar LI, enviará este byte. Ahora 2 bits para el siguiente conjunto de datos ya están en el búfer en serie. Envíe otros 3 bytes (26 bits en total) y espere hasta que necesite activar LI. Cuando sea el momento, envíe el siguiente byte (que tiene los 5 bits restantes). Repite esto una y otra vez.

Espero que esto tenga sentido. Como dije, no tengo experiencia con este chip, pero lo que he escrito aquí es al menos el primer paso que tomaría para tratar de resolver este problema utilizando SPI.

¡Buena suerte, y mantennos informados!

    
respondido por el Dave
3

Resulta que la forma de hacerlo es simplemente desbordar el registro de desplazamiento con más bits de los que necesita y asegurarse de que los 31 más importantes sean los ÚLTIMOS. Creo un búfer lo suficientemente largo como para contener 32 bits:

static uint8_t[BUFFER_SIZE] spiBuffer;

Lo relleno cada vez que hay un cambio y utilizo el SPI de interrupción para transmitirlo:

void transmitSpiBuffer() {
  static uint8_t c = 0;
  SPDR=spiBuffer[c++];
  if (c == (BUFFER_SIZE)) {
    c = 0;
    digitalWrite(LATCH_PIN, HIGH);
    // should I sleep? nah.
    digitalWrite(LATCH_PIN, LOW);
  }
}

void setup() {
   // Enable MOSI and SCK as output, all others input.
   PORTB = (1<<PINB3)|(1<<PINB5);

   ISR(SPI_STC_vect) {
     transmitSpiBuffer();
   }

   // Enable SPI
   SPCR = (1<<SPIE)|(1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0);
}

Esto funciona muy bien para mí. Problema resuelto.

    
respondido por el jamesotron

Lea otras preguntas en las etiquetas