Ticks / nanosecond delay

0

En un STM32F103C8T6 (72MHz), quiero usar un retardo en el rango de 100 nanosegundos (para crear un controlador de tira de LED, WS2813B).

Dado que HAL solo proporciona un retraso de ms, encontré en varios lugares el código para usar el contador de marcas / depuración como temporizador.

Tengo el siguiente código:

Inicialización:

volatile unsigned int *DWT_CYCCNT = (volatile unsigned int *)0xE0001004; //address of the register
volatile unsigned int *DWT_CONTROL = (volatile unsigned int *)0xE0001000; //address of the register
volatile unsigned int *SCB_DEMCR = (volatile unsigned int *)0xE000EDFC; //address of the register

unsigned int count = 0;

Dentro de main() :

  *SCB_DEMCR = *SCB_DEMCR | 0x01000000;
  *DWT_CYCCNT = 0; // reset the counter
  *DWT_CONTROL = *DWT_CONTROL | 1 ; // enable the counter

  int ticks = 1;

  while (1)
  {
      unsigned int start, current;
      start = *DWT_CYCCNT;
      do
      {
          current = *DWT_CYCCNT;
      } while((current - start) < ticks);

  if (count++ % 1000 == 0)
  {
         HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_6);
  }
}

Cuando conecto un analizador lógico, veo una señal PWM de 0.53 ms por conmutador. Como se alterna cada 1,000 recuentos, esto significa 0.53 us (530 ns). Sin embargo, con 1 tick, esperaría algo así como 1 / 72,000,000 = 14 ns (más alguna sobrecarga para el loop while / counter). (nota: el contador de 1,000 que usé porque mi analizador lógico solo puede manejar 200 kHz).

No estoy seguro de si las direcciones en la inicialización son correctas (se encontraron solo para STM32F103VET6).

Entonces, mi pregunta: ¿Cuál es el error en el programa anterior?

(pregunta adicional: ¿es este método bueno de todos modos para un controlador LED, o debo enviar los datos por interrupción o DMA?).

Actualizar

La razón por la que necesito este tipo de retrasos es el T0H , T1H , T0L y T1L veces que se pueden encontrar en Hoja de datos de WS2813B , página 5.

  

Tiempo de transferencia de datos (TH + TL = 1.25µs ± 300ns)

     

T0H código 0, tiempo de alto nivel 300ns ~ 450ns

     

T1H 1-código, tiempo de alto nivel 750ns ~ 1000ns

     

T0L 0-code, Low-level time 300ns ~ 100us

     

T1L 1-code, Low-level time 300ns ~ 100us

     

Unidad de marco RES, tiempo de nivel bajo 300µs o más

    
pregunta Michel Keijzers

2 respuestas

4

Ejecutando a 72 MHz un ciclo de instrucción es ~ 14 ns. El tiempo de instrucción es aproximadamente 1 instrucción por ciclo, pero el acceso a la memoria, el bus periférico, la penalización de bifurcación y el tiempo de flash se interponen. Para obtener una forma de onda externa que sea lo suficientemente precisa para un solo WS2813B es factible en el ensamblador, pero para una cadena de estos LED es un trabajo muy difícil (o imposible).

Su mejor oportunidad es (mal) usar el periférico SPI y alimentar los bytes que se calculan previamente para producir la forma de onda deseada.

O cambie al WS2801, que tiene líneas separadas de reloj y datos.

actualización:

La ventaja de SPI es que hay cierto búfer: IIRC puede cargar un byte mientras el otro se está desplazando, y el hardware se encargará de poner los bytes inmediatamente uno detrás del otro. Esto elimina la mayor parte del dolor del momento.

Uno de mis alumnos realmente hizo esto para su proyecto de fin de primer año, pero fue en un Arduino Due (también Cortex M3, pero a 92 MHz, y con un periférico SPI diferente). Primero trató de acertar en el momento en el que la compra modificó C ++, pero era demasiado frágil y no podía manejar una cadena más larga.

    
respondido por el Wouter van Ooijen
2

Puede conducir los leds WS utilizando DMA y la señal PWM generada por temporizador. Lea sobre el registro DMAR y cómo usarlo en el RM. No sé si es posible usar la biblioteca HAL ya que no la uso.

El registro simple es fácil y directo.

    
respondido por el P__J__

Lea otras preguntas en las etiquetas