espera de bloqueo para cambio de pin en un microcontrolador LPC1114

0

Necesito sincronizar el flanco ascendente de un PWM con el flanco descendente de otro pulso de señal en un LPC1114FN28 (tratando de manejar un TCD1304DG ), pero no estoy logrando esto hasta ahora. He intentado lo siguiente:

while (LPC_GPIO0->MASKED_ACCESS[ClockMask]);    //wait for the clock to go low
while (!(LPC_GPIO0->MASKED_ACCESS[ClockMask]));   //wait for the start of PWM cycle
LPC_GPIO0->MASKED_ACCESS[ICGMask] = 0x0;   //make the ICG pin go low

donde ClockMask es una máscara del pin PWM correspondiente, que se ejecuta a una frecuencia de 1MHz, 50% de ciclo de trabajo y ICGMask una máscara del pin que estoy intentando sincronizar con el PWM.

El extraño problema que encontré es que uno de los dos while s parece que se bloquea para siempre por alguna razón y cualquier código después de ellos no se ejecuta. Cuando los quito, funciona bien. Esto podría deberse probablemente a que las instrucciones para while duran lo mismo que en el período de PWM y, por lo tanto, la condición siempre vería el pin en el mismo estado, pero me parece bastante improbable ...

Estoy ejecutando el chip a 48MHz desde el IRC y el PWM medido con mi osciloscopio es prácticamente impecable.

Entonces, ¿qué podría estar haciendo mal? ¿Hay alguna manera mejor de hacer esto? ¿Escribir esta parte del código en ensamblador ayudaría con los tiempos (deben ser bastante precisos)? Si es así, ¿hay algún tutorial para esto?

¡Gracias de antemano por cualquier respuesta!

Editar:
Incluso utilizando interrupciones no pude obtener resultados suficientemente invariables: el tiempo de la interrupción después de que cambia el pulso. Intentaré más métodos ...

Otros métodos no funcionaron en absoluto. Probablemente esto no sea fácil de conseguir, pero no sé, ¿qué otra cosa podría estar haciendo mal si no es el momento (ya que el CCD de Toshiba aún no responde)?

    
pregunta Matouš Vrba

2 respuestas

0

Lo que resolvió esto al final fue usar las funciones de Registro de coincidencia externa para borrar y configurar los pines deseados con los mismos tiempos exactos que el PWM. Esto se logra utilizando el mismo temporizador y el Registro de coincidencias para el PWM y para la señal sincronizada.
Aquí está el código que utilicé:

#include <LPC11xx.h>            /* LPC11xx Peripheral Registers */
#include "system_LPC11xx.h"

#define NOOP ((void)0)
#define LED       (1<<9)      /* LED D1 connect to PIO1_9 */

void ClockInit(void);
void SetICG_synced(void);   //Sets the ICG pin synchronously with PWM
void ClrICG_synced(void);   //Sets the ICG pin synchronously with PWM

#define ClockMask 256//0x01 << 8;   //pin 0_8
#define SHMask 512//0x01 << 9;  //pin 0_9
#define ICGMask 1024//0x01 << 10;   //pin 0_10

int timer_IRQ_done = 0;

int main(void)
{
     int i;

   ClockInit();
   LPC_IOCON->PIO0_9       &= ~0x07;        // Set pin dp2 as output
   LPC_IOCON->SWCLK_PIO0_10       &= ~0x043F;       // Set pin dp3 as CT16B0_MAT2
   LPC_IOCON->SWCLK_PIO0_10       |= 0x03;       // Set pin dp3 as CT16B0_MAT2

   LPC_GPIO0->DIR |= ICGMask | SHMask | ClockMask;

   LPC_GPIO0->MASKED_ACCESS[SHMask] = 0x0;
   LPC_GPIO0->MASKED_ACCESS[ICGMask] = 0x0FFF;


 while (1)
 {

  ClrICG_synced();
  NOOP;  //~200ns pause
  NOOP;
  NOOP;
  NOOP;
  NOOP;
  NOOP;
  LPC_GPIO0->MASKED_ACCESS[SHMask] = 0x0FFF;
  for (i = 0; i < 25; i++);
  LPC_GPIO0->MASKED_ACCESS[SHMask] = 0x0;
  for (i = 0; i < 25; i++);

  SetICG_synced();

  for (i = 0; i < 47135; i++);  //wait
 }
 // unreachable
 return 0;
}

void ClockInit(void)    //sets the PWM on pin dp1
{
 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7);    // enable clock for Timer0_16
 LPC_TMR16B0->PR  = 23;   // set divider to 23 (48/(2*(23+1)) = 1us)

 LPC_IOCON->PIO0_8       &= ~0x07;  //clear pin settings
 LPC_IOCON->PIO0_8       |= 0x02;        // set as Timer0_16 MAT0

 LPC_TMR16B0->PWMC       = (1<<3)        // set the Match3
                        | (1<<0)        // set PWM0
                        | (1<<1)        // set PWM1
                        ;

 LPC_TMR16B0->MR2 = 1;  // set the period to 1us
 LPC_TMR16B0->MR0 = 1;    // 50% duty cycle
 LPC_TMR16B0->MR1 = 1;    // 50% duty cycle

 LPC_TMR16B0->MCR = (3<<6);              // Reset tht TC when it matches the MR2 and generate interrupt

 LPC_TMR16B0->TCR = (1<<0);              // start Timer0_16

}

void SetICG_synced(void)
{
 #define MASK 512
 LPC_TMR16B0->EMR = (MASK);
 #undef MASK
}
void ClrICG_synced(void)
{
 #define MASK 260
 LPC_TMR16B0->EMR = (MASK);
 #undef MASK
}

Nota: este código está diseñado para un propósito muy específico y para ser usado en una aplicación más general, tendría que ser editado (especialmente las funciones SetICG_synced y ClrICG_synced , que sobrescribirían cualquier otra configuración en el EMR).

Gracias por todos los comentarios, el osciloscopio dice que todo está bien ahora, así que creo que puedo cerrar esta pregunta.

    
respondido por el Matouš Vrba
1

Supongo que ha cambiado el IOCON del pin de salida PWM para cambiar su función del pin GPIO al pin de salida del contador / temporizador. Sus declaraciones while intentan usar el mismo pin que una entrada de GPIO, y supongo que no puede hacer eso.

No nos ha dicho el ciclo de trabajo de su señal PWM pero a 1 MHz solo tiene 48 ciclos de reloj para todo el período. Si el ciclo de trabajo desciende por debajo del 10% o por encima del 90%, será muy difícil capturar tanto el tiempo bajo como el tiempo alto. Este podría ser un buen lugar para el código de ensamblaje optimizado a mano.

En cualquier caso, será difícil detectar un borde en una señal de 1MHz y alternar otro bit de salida muy rápidamente. No estoy seguro de que pueda decir que la salida estaba "sincronizada" con el borde de PWM.

    
respondido por el Joe Hass

Lea otras preguntas en las etiquetas