Transmitir binario PWM a 400kbps (o 800kbps)

2

Necesito enviar una cadena de bits a un conjunto encadenado de LED RGB, cada uno de los cuales tiene su propio controlador IC. La hoja de datos para ese IC, el WS2811, está aquí .

El protocolo es bastante simple: cada bit, tanto el 1 como el 0, se envían como alto y bajo, con diferentes proporciones de espacio de marca, y luego se enlazan entre sí.

A 400 kbps, el espacio de marca es el siguiente:

  • Binario 1: 1.2us alto seguido de 1.3us bajo (cada +/- 150ns)
  • Binario 0: 0.5us alto seguido de 2.0us bajo (cada +/- 150ns)

Los datos pueden enviarse a 400kbps o 800kbps. No me molesta cuál uso, pero espero que 400kbps sea más fácil de implementar. (A 800 kbps, los tiempos anteriores se reducen a la mitad).

Mi pregunta: ¿Cómo se podría implementar esto? Probablemente esté usando una MCU PIC de 8 bits a 20MHz (5MIPs) para determinar qué datos se enviarán, y estoy buscando por el equivalente de un USART IC en el que la MCU podría confiar para transmitir datos con la codificación anterior.

Posibles soluciones

Hay tres formas en las que me imagino enviar ese tipo de datos a esa velocidad:

  1. Encontrar un IC / ASIC que esté dedicado a este propósito.
  2. Usar una segunda MCU dedicada a recibir datos de la MCU primaria y convertirla directamente a la codificación PWM anterior.
  3. Creación de un transmisor dedicado a partir de circuitos integrados de lógica TTL / CMOS o similar.

Para el punto 1, no puedo encontrar ningún IC que lo haga. ¿Existen?

Para el punto 2, tengo ideas sobre cómo podría funcionar, pero hasta ahora no tengo soluciones. Una solución: golpear los bits sería muy difícil, ya que debe escribirse en un ensamblador dado los requisitos de tiempo. Otra solución, aunque no es capaz de alcanzar la resolución de 100 ns para que la temporización de la señal PWM coincida con las especificaciones de la hoja de datos, podría configurar el USART en una MCU PIC para transmitir de forma sincrónica, excepto que cada 4 bits transmitidos sería una forma de enviar. un bit PWM. Entonces, para enviar datos PWM de 400 kbps, el USART tendría que ser capaz de 400 x 4 = 1.6Mbps. Luego, para enviar un binario 1 de PWM, el USART enviaría HHLL, y para enviar un binario 0 de PWM, el USART enviaría HLLL. Esto apenas satisfaría los requisitos de tiempo de +/- 150ns, un margen de 25ns. Y no he encontrado un PIC que pueda transmitir tan rápido en serie de todos modos.

Entonces, en este momento, la opción 3 es mi única opción: construir hardware dedicado a partir de circuitos integrados lógicos. Por ejemplo:

  • Construya un registro de desplazamiento de 25 bits para generar el PWM, requerido para un solo bit. Luego, los circuitos que llenan el registro en función de si debe transmitirse un 1 o un 0 binarios. Y como esto aún sería muy intensivo en la MCU, agregaría quizás un pestillo de 8 bits en el que la MCU podría escribir, y permitiría que los circuitos adicionales procesaran los 8 bits uno a la vez, para cada uno codificar el bit en el Registro de desplazamiento de 25 bits como ciclo PWM.
  • Como en el caso anterior, pero reemplace el registro de desplazamiento de 25 bits con un monoestable que genera un impulso largo o corto, y otro que carga un nuevo bit cada 2.5us.
  • Al usar un IC de memoria que actúa como una tabla de búsqueda, tal vez (con circuitos adicionales) se le pueda dar un byte para que transmita desde la MCU y devuelva datos que un circuito podría convertir en datos en serie como salida PWM.

En resumen, ¡no puedo encontrar una buena solución! Parece un montón de trabajo para un problema tan simple. ¿Cómo lo harías?

    
pregunta CL22

3 respuestas

4

Estos son chips populares, y los muy populares LEDs RGB WS2812 (también conocidos como Neopixels ) utilizan el mismo tiempo de señal de 800 KHz y Protocolo, por lo que no estás solo!

Los chips no son tan complicados como parecen y pueden manejarse fácilmente desde un microcontrolador de 8 bits ...

enlace

Las personas normalmente las golpean directamente desde un pin GPIO normal, lo que requiere un poco de conteo de ciclos para obtener la sincronización correcta, pero no requiere ningún hardware adicional, excepto quizás un cambio de nivel si está ejecutando la MCU a baja tensión. El artículo anterior incluye el siguiente código muy simple para AVR que debería ser trivial para convertirlo a PIC ...

// These are the timing constraints taken mostly from the WS2812 datasheets
// These are chosen to be conservative and avoid problems rather than for maximum throughput 

#define T1H  900    // Width of a 1 bit in ns
#define T1L  600    // Width of a 1 bit in ns

#define T0H  400    // Width of a 0 bit in ns
#define T0L  900    // Width of a 0 bit in ns

#define RES 7000    // Width of the low gap between bits to cause a frame to latch

// Here are some convenience defines for using nanoseconds specs to generate actual CPU delays

#define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives

#define CYCLES_PER_SEC (F_CPU)

#define NS_PER_CYCLE ( NS_PER_SEC / CYCLES_PER_SEC )

#define NS_TO_CYCLES(n) ( (n) / NS_PER_CYCLE )

#define DELAY_CYCLES(n) ( ((n)>0) ? __builtin_avr_delay_cycles( n ) : __builtin_avr_delay_cycles( 0 ) ) // Make sure we never have a delay less than zero

// Actually send a bit to the string. We turn off optimizations to make sure the compile does
// not reorder things and make it so the delay happens in the wrong place.

void sendBit(bool) __attribute__ ((optimize(0)));

void sendBit( bool bitVal ) {

    if ( bitVal ) {      // 1-bit

      bitSet( PIXEL_PORT , PIXEL_BIT );

      DELAY_CYCLES( NS_TO_CYCLES( T1H ) - 2 ); // 1-bit width less overhead for the actual bit setting
                                                     // Note that this delay could be longer and everything would still work
      bitClear( PIXEL_PORT , PIXEL_BIT );

      DELAY_CYCLES( NS_TO_CYCLES( T1L ) - 10 ); // 1-bit gap less the overhead of the loop

    } else {             // 0-bit

      cli();                                       // We need to protect this bit from being made wider by an interrupt 

      bitSet( PIXEL_PORT , PIXEL_BIT );

      DELAY_CYCLES( NS_TO_CYCLES( T0H ) - 2 ); // 0-bit width less overhead
                                                    // **************************************************************************
                                                    // This line is really the only tight goldilocks timing in the whole program!
                                                    // **************************************************************************
      bitClear( PIXEL_PORT , PIXEL_BIT );

      sei();

      DELAY_CYCLES( NS_TO_CYCLES( T0L ) - 10 ); // 0-bit gap less overhead of the loop

    }

    // Note that the inter-bit gap can be as long as you want as long as it doesn't exceed the 5us reset timeout (which is A long time)
    // Here I have been generous and not tried to squeeze the gap tight but instead erred on the side of lots of extra time.
    // This has thenice side effect of avoid glitches on very long strings becuase

}

void sendByte( unsigned char byte ) {

    for( unsigned char bit = 0 ; bit < 8 ; bit++ ) {

      sendBit( bitRead( byte , 7 ) ); // Neopixel wants bit in highest-to-lowest order
                                                     // so send highest bit (bit #7 in an 8-bit byte since they start at 0)
      byte <<= 1; // and then shift left so bit 6 moves into 7, 5 moves into 6, etc

    }
}

Otras técnicas también son posibles. He tenido éxito al obtener un UART para conducirlos ...

enlace

... que puede relajar los requisitos de tiempo, especialmente en chips que tienen grandes buffers de transmisión.

PJRC también ha conseguido un PWM conducido por DMA para generar la señal correcta ...

enlace

(desplácese hacia abajo hasta "Detalles técnicos")

... que es muy complicado, pero muy bueno ya que casi no hay carga de CPU.

Todas estas son soluciones fáciles y hay muchos ejemplos de código para todas ellas. La elección correcta realmente depende de la aplicación y de los factores que sean importantes para usted.

    
respondido por el bigjosh
1

El tiempo WS2811 es este: -

Y,parecequealgunaspersonasestánusandoSPIdeestamanera:-

Entonces, tal vez considere usar SPI si su chip lo admite.

    
respondido por el Andy aka
1

Los conduciré con demoras suspendidas de datos SPI o USART y pines de reloj

ejecutarlo a 400Khz reloj acortar el pulso de reloj a 250ns cuando a los datos son cero y extiéndalos a 1500 ns cuando los datos son 1

haga que el bit bit conduzca un generador de rampa y use la señal de datos para establecer el umbral para un comparador que esté observando la rampa, de esta manera puede obtener un bit de datos por cada bit que ingresa en el comando usart

    
respondido por el Jasen

Lea otras preguntas en las etiquetas