UART problema de interrupción en LPC1788

0

Escribí un código

int main(void) {
    uart2();
    NVIC_EnableIRQ(UART2_IRQn);
    while(1);   
} 

void receive(void) {
    SMR_485RECEIVE;
    receive_byte = LPC_UART2->RBR;
    }

void send(void) {
    SMR_485TRANSMIT;
    LPC_UART2->THR = receive_byte;
    }

void UART2_IRQHandler(void) {   

    BYTE maska = LPC_UART2->LSR & 0x01;
    if(maska == 0x01){
        delay_1_ms();
        receive();
        delay_1_ms();
        send();
        }
    }

Funciona la primera vez que envío un carácter a través de un terminal a la CPU, me envía de vuelta lo mismo, pero luego comienza a enviarme de vuelta \ 0 , ¿alguien tiene idea de qué causa el bucle infinito, Pienso mientras (1), pero no estoy seguro de cómo y por qué, y cómo resolver esto.

Así es como se ve en la terminal

    
pregunta Lazar

2 respuestas

1

¿Está seguro de que no hay una interrupción global que deba eliminarse? Yo diría que la mayoría de los sistemas tienen una bandera clearable en alguna parte.

Además, ¿su rutina de manejador de interrupciones solo es activada por el UART o es donde aterrizarán todas las interrupciones?

En las arquitecturas PIC micro y Atmel (por lo que supongo que también ARM, de lo contrario mi respuesta no contiene agua), solo hay una función a la que se llama cuando se produce una interrupción. Depende del programador determinar qué interrupción específica ha ocurrido desde el código. Si tiene, digamos, diez posibles fuentes de interrupción, entonces necesita sondear esas diez banderas individualmente para encontrar la fuente de la IRQ. Desde allí se llama a una rutina individual para esa interrupción.

En su caso, el envío constante del carácter NULO se debe a que el programa ejecuta continuamente la rutina del controlador, pero se debe a que la interrupción de UART se está detectando o porque se establece una interrupción global . Tu código no te permite averiguarlo en este momento. La solución fácil es agregar una sola declaración "if" como la primera línea de la rutina de interrupción que regresa de la rutina inmediatamente si el indicador UART no está establecido. Haga esto, luego ejecute el código.

¿Qué pasa?

Si nada cambia, sabe que DEBE poder borrar el indicador de interrupción de UART. Si realmente es solo de lectura, intente deshabilitar y luego volver a habilitar la interrupción de UART. ¡Tiene que haber una manera de limpiar la bandera! Ejecuta el código de nuevo.

Si el NULL continuo ha desaparecido, no necesariamente ha terminado. Recuerde que el indicador de interrupción global aún puede estar configurado, por lo que, para fines de depuración, agregue más código a la rutina del controlador de interrupciones a haga algo (tal vez envíe un carácter particular) si se llama a la rutina pero el indicador UART NO está establecido. Esa es la única forma en que sabrás que estás lidiando con las interrupciones correctamente.

EDITAR:

Después de rastrear a través del ARM178x User Manual, he encontrado la línea clave (página 510, "18.6.5 - Registro de Identificación de Interrupción UARTn") como sigue:

Se debe leer el UnIIR para eliminar la interrupción antes de salir de la rutina de servicio de interrupción.

Su código simplemente asume que se ha llamado a la interrupción debido a una sola solicitud y, aunque es posible que solo haya habilitado una única fuente de interrupción, el ARM espera lo contrario. En un programa completo, habrá más de una razón para que se produzca el IRQ de UARTn, lo que significa que tendría que leer LPC_UART2- > IIR para averiguar qué ha causado la interrupción. En su caso, debería ser suficiente solo leer la dirección y descartar la información, pero podría ser una buena práctica al menos verificar el IIR para asegurarse de que está manejando la interrupción correcta.

En mi opinión, una rutina de interrupción "correcta" no debería contener mucho código. Solo debe verificar el registro de interrupción que necesite y luego llamar a las subrutinas para llevar a cabo el código necesario. Por ejemplo:

void InterruptServiceRoutine(void) {

    BYTE InterruptRegisterState = Requesting_Interrupt_Register;
        // This 'read' instruction should clear your read-only flags

    if (InterruptRegisterState && InterruptFlag_A)
        Interrupt_A_Handler(void);

    if (InterruptRegisterState && InterruptFlag_B)
        Interrupt_B_Handler(void);

    if (InterruptRegisterState && InterruptFlag_C)
        Interrupt_C_Handler(void);

    // ... add one for each interrupt source
}

void Interrupt_A_Handler(void) {
    // Put actual your code here...
}
    . . . etc.

Como puede ver, esto hace que su ISR inicial sea mucho más claro, ya que no contiene nada. Entonces, es libre de escribir tanto código en su subrutina "Interrupt_X_Handler ()" como desee.

    
respondido por el CharlieHanson
0

Finalmente funciona, aquí está el código, gracias a todos por ayudarme.

int main(void) {

    uart2();
    NVIC_EnableIRQ(UART2_IRQn);
    while(1);
} 

void receive(void) {

    SMR_485RECEIVE;
    receive_byte = LPC_UART2->RBR;
    }

void send(void) {

    if(receive_byte != '
int main(void) {

    uart2();
    NVIC_EnableIRQ(UART2_IRQn);
    while(1);
} 

void receive(void) {

    SMR_485RECEIVE;
    receive_byte = LPC_UART2->RBR;
    }

void send(void) {

    if(receive_byte != '%pre%'){ //ADDED THIS IF
        SMR_485TRANSMIT;
        LPC_UART2->THR = receive_byte;
        }
}

void UART2_IRQHandler(void) {   

    BYTE maska = LPC_UART2->IIR & 0x06;

    if(maska == 0x04) {
        receive();
        delay_1_ms();
        send();
        delay_1_ms();
        }   
}
'){ //ADDED THIS IF SMR_485TRANSMIT; LPC_UART2->THR = receive_byte; } } void UART2_IRQHandler(void) { BYTE maska = LPC_UART2->IIR & 0x06; if(maska == 0x04) { receive(); delay_1_ms(); send(); delay_1_ms(); } }
    
respondido por el Lazar

Lea otras preguntas en las etiquetas