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?