Comportamiento de interrupción inexplicable en el contador de temporizador de AVR ATMEGA324P ISR

2

Tengo un ATMEGA324P que controla un circuito de controlador de motor dual. Estoy usando el contador 1 del temporizador de 16 bits en el modo correcto de fase y frecuencia para crear (2) salidas PWM utilizando el ICR1 como valor TOP y OCR1A y OCR1B para generar las señales PWM en los pines de salida. El problema persiste igual en OCR1A y OCR1B, así que he deshabilitado OCR1A para simplificar la resolución de problemas.

El problema que estoy experimentando es cuando alguna otra interrupción en el sistema se dispara, como UART o PCINT, el ciclo de trabajo PWM se invertirá. Por ejemplo, si el ciclo de trabajo se establece en 75%, se invertirá a 25% y se desplazará hacia adelante y hacia atrás cuando otras interrupciones disparen, lo que hace que la salida sea extremadamente errática. Las tomas de alcance debajo muestran la salida deseada en la parte superior y la invertida en la parte inferior. He podido activar esta inversión por UART RX ISR, ISR de interrupción de cambio de pin, y el contador de temporizador 0 y 2 Compare A & B ISR's. Por ejemplo, enviar un carácter al UART hará que se invierta.

Todoparecefuncionarenmicódigo(acontinuación),exceptoporesteproblema.Heprobadounanuevaplacadecircuitoymostróelmismocomportamientoquesugierequenoesunproblemadehardware.LoquecreoquepodríaestarsucediendoesquelainterrupciónOCR1Bseactivadealgunamaneracuandolaotrainterrupciónsedispara,loqueprovocauncambioadicionaldeOCR1Benelpindesalida.Unavezqueestosucede,siguefuncionandocomodebería,alternandoelpinperoenunestadoinvertido.Estoseilustraenelsiguientediagramadetiempo.

EsposiblequetengaalgúnerrorconmipilayqueladirecciónISRestédañada.LasdireccionesqueheprobadosemuestranacontinuaciónconlaXyladireccióndedestinoconlaflecha.Apreciocualquierayuda.

#define SS_Hi()         PORTB |= _BV(4)
#define SS_Lo()         PORTB &= ~ _BV(4)
#define SS_IN()     (PINB&_BV(PINB4))


void init_TCNT1(void) {

    // setup timer counter 1

    // PWM, Phase Frequency Correct 8-bit. TOP = ICR1

    TCCR1A |= _BV(WGM11);
    TCCR1B |= _BV(WGM13);
    TCCR1B |= _BV(CS11); 

    ICR1 = 40;  

    TIMSK1 |= _BV(OCIE1A); 
//  TIMSK1 |= _BV(OCIE1B);

    OCR1A = 10; 
    OCR1B = 10;
    TCNT1 = 0; 

}

ISR(TIMER1_COMPA_vect) {

    if ((EnA_1() != 0) && (EnB_1() != 0)) { // only if both enable pins are high

    // if (PWM_PIN_1() == 0) PWMIN_1_Hi(); else PWMIN_1_Lo();

    }
    else PWMIN_1_Lo();
} // End Timer 1 Compare A ISR

ISR(TIMER1_COMPB_vect) {
// ISR For Motor 2
    if (SS_IN() == 0) SS_Hi(); else SS_Lo();
} // End Timer 1 Compare B ISR
    
pregunta Neelix

2 respuestas

1

Con la ayuda de los comentarios y la publicación a continuación, pude determinar la causa del problema.

enlace

La causa del problema no es una interrupción adicional, ya que originalmente pensé que se estaba perdiendo una porque las interrupciones globales estaban deshabilitadas para manejar otro ISR. Pude verificar esto agregando un sei (); La instrucción al comienzo de todos los demás controladores de ISR y el problema de la inversión desaparecieron. Rehabilitar las interrupciones globales en todos los demás ISR no es una solución ideal y causa más problemas, especialmente con el UART. La mejor solución sería utilizar los pines OCR1A / B en PD4 y PD5; sin embargo, estos pines se usan para otra cosa, por lo que no es realmente una opción. La solución que se me ocurrió es usar la interrupción por desbordamiento del temporizador 1 para borrar el pin de salida que se dispara en BOTTOM en el modo PWM de fase y frecuencia. Entonces, independientemente de que se pierda un interruptor cuando el contador esté en la parte inferior, el pin se borrará y el error solo existirá durante unos pocos ciclos como máximo.

#define SS_Hi() PORTB |= _BV(4)
# define SS_Lo() PORTB &= ~_BV(4)
# define SS_IN()(PINB & _BV(PINB4))

void init_TCNT1(void) {
  // setup timer counter 1
  // PWM, Phase and Frequency Correct 8-bit. TOP = ICR1

  TCCR1A |= _BV(WGM11);
  TCCR1B |= _BV(WGM13);
  TCCR1B |= _BV(CS11);

  ICR1 = 40;

  TIMSK1 |= _BV(OCIE1A);
  TIMSK1 |= _BV(OCIE1B);
  TIMSK1 |= _BV(TOIE1);

  OCR1A = 10; //Set the top value
  OCR1B = 10; // Set the compare value 
  TCNT1 = 0; // intitilize the start value 

}

ISR(TIMER1_COMPA_vect) {

    if ((EnA_1() != 0) && (EnB_1() != 0))

  } // End Timer 1 Compare A ISR

ISR(TIMER1_COMPB_vect) {
    // ISR For Motor 2

    if (SS_IN() == 0) SS_Hi();
    else SS_Lo();

  } // End Timer 1 Compare B ISR

ISR(TIMER1_OVF_vect) {

  SS_Lo();
}
    
respondido por el Neelix
0

Ya que estás alternando manualmente los pines en el isr, estás expuesto a rmw. Así que lo que has experimentado es posible.

Configure los bits COMx en su lugar.

    
respondido por el dannyf

Lea otras preguntas en las etiquetas