MSP430F5529 UART: UCTXIFG no se configura nuevamente después de iniciar la transmisión

2

Estoy intentando programar un tipo de puente entre UCA0 y UCA1 en el modo UART en el MSP430F5529 usando el Placa de desarrollo MSP-EXP430F5529LP . Estoy usando una interrupción para recibir datos, pero para la transmisión, solo estoy cargando el UCAxTXBUF directamente (no hay interrupciones de TX habilitadas). Digo UCA x TXBUF porque el puente debe ser bidireccional, por lo que puede ser UCA0TXBUF o UCA1TXBUF.

Mi rutina de servicio de interrupción se basa en los ejemplos UART de TI disponibles en los paquetes MSP430Ware. Los ejemplos usan una espera ocupada dentro del ISR para esperar a que el búfer de TX esté disponible (UCTXIFG sube) antes de cargar UCAxTXBUF con los datos. Odio la idea de poner una espera ocupada dentro de una interrupción, pero por el bien de la discusión estoy siguiendo los ejemplos. De todos modos, el problema es que, si bien UCTXIFG es alto cuando me estoy preparando para transmitir el primer byte, tan pronto como cargue el UCAxTXBUF con los datos, el bit UCTXIFG se borra (como se esperaba), pero nunca se vuelve a configurar. Esto sugiere que, por razones desconocidas, los datos no se transmiten, por lo que UCBUSY permanece configurado y UCTXIFG no sube de nivel, lo que indica que el búfer está listo para más datos. ¿Cuál podría ser el problema? Los ISR para UCA0 y UCA1 se muestran a continuación:

UCA0 ISR:

#pragma vector = USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void) {
    __no_operation();
    switch(__even_in_range(UCA0IV,4)) {
        case 0:                                         // No interrupt
            break;
        case 2:                                         // RX interrupt
            __disable_interrupt();                      // Disable interrupts
            UCA0_rxByte = UCA0RXBUF;

            while (!(UCA1IFG & UCTXIFG));               // Wait for UCA1 TX buffer to be ready
                                                        //  Bad practice - should not have busy
                                                        //  wait in ISR
            UCA1TXBUF = UCA0_rxByte;                    // Pass through to 485
            UCA0_rxString[UCA0_idx] = UCA0_rxByte;      // Save current byte in buffer
            UCA0_idx++;
            TA0_clearTimer();                           // Restart timer
            __enable_interrupt();                       // Re-enable interrupts
            break;
        case 4:                                         // TX interrupt
            break;
    }
}

UCA1 ISR:

#pragma vector=USCI_A1_VECTOR                           // UCA0 RX/TX interrupt vector
__interrupt void USCI_A1_ISR(void) {
    switch(__even_in_range(UCA1IV,4)) {
        case 0:                                         // No interrupt
            break;
        case 2:                                         // RX interrupt
            __disable_interrupt();                      // Disable interrupts
            UCA1_rxByte = UCA1RXBUF;                    // Get current byte

            UCA1_rxString[UCA1_idx] = UCA1_rxByte;      // Save current byte in buffer

            while (!(UCA0IFG & UCTXIFG));               // Wait for UCA0 TX buffer to be ready
                                                        //  Bad practice - should not have busy
                                                        //  wait in ISR
            UCA0TXBUF = UCA1_rxByte;                    // Pass through to TTL
            UCA1_idx++;
            TA0_clearTimer();                           // Restart timer
            __enable_interrupt();                       // Re-enable interrupts
            break;
        case 4:                                         // TX interrupt
            break;
    }
}

Las líneas __disable_interrupt() y __enable_interrupt() se agregaron en después de que apareció por primera vez este problema, por lo que estoy bastante seguro de que no son el problema.

Cuando intento transmitir el primer carácter desde UCA0, el% de prueba while(!(UCA1IFG & UCTXIFG)) cae directamente, como espero que el UCA1TXBUF esté vacío y listo para los datos. Sin embargo, cuando intento transmitir el segundo carácter de UCA0, el programa se bloquea en esa misma prueba. Al verificar los registros en CCS veo que UCBUSY está configurado y UCTXIFG aún está claro.

¿Qué podría causar este tipo de comportamiento? He encontrado varias preguntas formuladas aquí y en otros sitios que describen un problema similar, pero todas parecen ser para I2C o SPI, y las soluciones no parecen aplicarse a mi problema actual con el UART.

El ISR real del ejemplo UCA0 de TI se muestra a continuación. Los bits agregados anteriormente son modificaciones a las variables que uso para mis propios fines.

switch(__even_in_range(UCA0IV,4)) {
    case 0:break;                             // Vector 0 - no interrupt
    case 2:                                   // Vector 2 - RXIFG
        while (!(UCA0IFG&UCTXIFG));             // USCI_A0 TX buffer ready?
        UCA0TXBUF = UCA0RXBUF;                  // TX -> RXed character
        break;
    case 4:break;                             // Vector 4 - TXIFG
    default: break;
}

ACTUALIZACIÓN: Para completar, aquí está el código de inicialización para UCA1 (efectivamente idéntico a la inicialización para UCA0):

void UCA1_init(uint32_t smclk, uint32_t baudrate) {
    P4SEL |= BIT4 + BIT5;                                       // Select alternate function for P4.4, 4.5 (UCA1 TXD, RXD)
    UCA1CTL1 |= UCSWRST;                                        // Reset USCI state machine
    UCA0CTL1 |= UCSSEL_2;                                       // Set clock to SMCLK
    UCA1BR0 = 52;                                               // Low byte of clock prescaler (9600 bps)
    UCA1BR1 = 0;                                                // High byte of clock prescaler
    UCA1MCTL = UCBRS_0 + UCBRF_1 + UCOS16;                      // Modulation stages; oversampling mode
    UCA1CTL1 &= ~UCSWRST;                                       // Restart USCI state machine
    UCA1IE |= UCRXIE;                                           // Enable RX interrupt
}

Y la inicialización del puerto para UCA1 (tenga en cuenta que UCA1 está asignado en el puerto):

// PORT4
P4SEL = (BIT4 + BIT5);                                  // Set P4.4 as UCA1TXD, P4.5 as UCA1RXD, rest as I/O
PMAPKEYID = 0x2D52;                                     // Unlock port mapping register configuration
PMAPCTL |= PMAPRECFG;                                   //      Allow reconfiguration of mapping
P4MAP4 = 12;                                            //      Map P4.4 to PM_UCA1
P4DIR |= BIT4;                                          //      Set P4.4 as input (UCA1TXD)
P4MAP5 = 11;                                            //      Map P4.5 to PM_UCA1
P4MAP5 &= ~(BIT5);                                      //      Set P4.5 as input (UCA1RXD)
P4DIR |= (BIT7 + BIT6 + BIT3 + BIT2 + BIT1 + BIT0);     // Set rest of PORT4 as outputs
P4OUT &= ~(GPIO_ALL);                                   // Clear PORT4 outputs

Estoy empezando a preguntarme si puede haber un problema con mi asignación de los puertos. Debería haber incluido esto desde el principio. Tal vez alguien pueda identificar un error?

    
pregunta DerStrom8

1 respuesta

1
void UCA1_init(...) {
    ...
    UCA1CTL1 |= UCSWRST;                         // Reset USCI state machine
    UCA0CTL1 |= UCSSEL_2;                        // Set clock to SMCLK
       ^

Esto deja la fuente del reloj USCI_A 1 en su configuración predeterminada (externa), y supongo que P4.0 no está configurado para eso.

Hay un método para evitar el bucle dentro del controlador de interrupciones (requiere ambas interrupciones TX / RX):

bool UCA0_received;
bool UCA1_txReady;

USCI_A0_ISR() {
    switch (UCA0IV) {
    case USCI_UCRXIFG:
        UCA0_rxByte = UCA0RXBUF;
        UCA0_received = true;
        maybeEchoTo1();
        break;
    }
}

USCI_A1_ISR() {
    switch (UCA1IV) {
    case USCI_UCTXIFG:
        UCA1_txReady = true;
        maybeEchoTo1();
        break;
    }
}

maybeEchoTo1() {
    if (UCA0_received && UCA1_txReady) {
        UCA1TXBUF = UCA0_rxByte;
        UCA0_received = false;
        UCA1_txReady = false;
    }
}

Y, por favor, no use números mágicos, sino los símbolos adecuados para los valores del vector de interrupción.
No están documentados en ninguna parte (incluso los escritores de los ejemplos de TI no los conocen), por lo que debe eliminarlos del archivo de encabezado:

/* USCI Interrupt Vector Definitions */
#define USCI_NONE              (0x0000)       /* No Interrupt pending */
#define USCI_UCRXIFG           (0x0002)       /* Interrupt Vector: UCRXIFG */
#define USCI_UCTXIFG           (0x0004)       /* Interrupt Vector: UCTXIFG */
    
respondido por el CL.

Lea otras preguntas en las etiquetas