UART TX Interrupt Flag raised by default? (MSP430) - Page 1
Forum section: electronics / general

author: Jon86
author_rank: Frequent Contributor
timestamp: March 12, 2019, 02:33:44 pm
content: This may have a completely obvious answer, so apologies if that's the case, but this has been giving me some real trouble.I've been playing with some UART code on an MSP430 launchpad board, trying to move away from the arduino environment I'm so familiar with.The code I wrote hasn't been doing what I wanted, so I've now narrowed it down to this.Code:#include "msp430g2553.h"#include <stdio.h>unsigned int InterruptFlags;void main(void){WDTCTL = WDTPW + WDTHOLD; // Stop the Watch dog//------------------- Configure the Clocks -------------------//DCOCTL = 0; // Select lowest DCOx and MODx settingsBCSCTL1 = CALBC1_1MHZ; // Set rangeDCOCTL = CALDCO_1MHZ; // Set DCO step + modulation//---------------- Configuring the LED's ----------------------//P1DIR |= BIT0 + BIT6; // P1.0 and P1.6 outputP1OUT &= ~BIT0 + BIT6; // P1.0 and P1.6 = 0//--------- Setting the UART function for P1.1 & P1.2 --------//P1SEL |= BIT1 + BIT2; // P1.1 UCA0RXD inputP1SEL2 |= BIT1 + BIT2; // P1.2 UCA0TXD output//------------ Configuring the UART(USCI_A0) ----------------//UCA0CTL1 |= UCSSEL_2 + UCSWRST; // USCI Clock = SMCLK,USCI_A0 disabledUCA0BR0 = 104; // 104 From datasheet table-UCA0BR1 = 0; // -selects baudrate =9600,clk = SMCLKUCA0MCTL = UCBRS_1; // Modulation value = 1 from datasheetUCA0CTL1 &= ~UCSWRST; // Clear UCSWRST to enable USCI_A0IE2 |= UCA0TXIE;IE2 |= UCA0RXIE;InterruptFlags = IFG2;_BIS_SR(LPM0_bits + GIE); // Going to LPM0}#pragma vector = USCIAB0TX_VECTOR__interrupt void TransmitInterrupt(void){IFG2 &= ~UCA0TXIFG;InterruptFlags = IFG2;}#pragma vector = USCIAB0RX_VECTOR__interrupt void ReceiveInterrupt(void){IFG2 &= ~UCA0RXIFG;}And I've finally figured out by looking at the "InterruptFlag" variable in the debugger (CCS), that the transmit interrupt flag "UCA0TXIFG" appears to be raised when I enable the interrupts...This means that as soon as my code runs, without any input, the TX interrupt is being called, which doesn't seem right.Now I can just reset this bit straight after I enable the interrupt, but why does it give me the chance to do this first, instead of calling the interrupt straight away?I'm sure I'm missing something obvious, but I think I need some help figuring it out.

author: Jon86
author_rank: Frequent Contributor
timestamp: March 12, 2019, 02:52:53 pm
content: Solved!Apparently when USCI comes out of reset, the flag is set, so I should only set it when I've got data to send.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: March 12, 2019, 03:19:12 pm
content: On most MCUs, by default TX int means "give me more data" ( in some cases this can be changed to assert at the end of transmission, for RS485 control) , so reasonable for it to be active as soon as enabled.

author: Jon86
author_rank: Frequent Contributor
timestamp: March 12, 2019, 04:23:59 pm
content: That makes a lot of sense now, cheers Mike!

author: rhodges
author_rank: Frequent Contributor
timestamp: March 12, 2019, 09:36:57 pm
content: It is common for an interrupt service routine to check the TX interrupt ENABLE before looking at the TX buffer empty flag. The TX enable is only set when there is more data to send.

author: ebclr
author_rank: Super Contributor
timestamp: March 13, 2019, 03:04:33 am
content: This will help you void polishing bits, If you have installed ccs on driver C will workhttp://localhost:55432/content/c:/ti/msp430ware_3_80_06_03/driverlib/doc/MSP430FR2xx_4xx/html/index.html#intro

author: bson
author_rank: Unknown
timestamp: March 13, 2019, 10:37:00 pm
content: You shouldn't clear TXIFG in the interrupt handler. It's cleared automatically when you write to TXBUF.The logic goes something like this:B is a tx buffer (or ring, deque, etc)send bytes in message M:check or busy wait for B to have enough space to hold Madd M to Bif TXIFG is set:TXBUF = next byte in Btx interrupt handler:if B isn't empty:TXBUF = next byte in BSo while you get an interrupt initially when you enable interrupts (because TXBUF is empty), the interrupt handler shouldn't do anything since the buffer should have been initialized to empty. Alternatively you can, if it bothers you, clear TXIFG in during initialization.

author: westfw
author_rank: Super Contributor
timestamp: March 14, 2019, 01:41:51 am
content: QuoteNote that this implies that the TX ISR needs to disable the transmitter (or perhaps just the TX interrupt) when thereisn'tmore data to send, which is substantially different from how you'd treat a UART inAnd it means that the user-level code needs to handle re-enabling the transmitter or tx interrupt whenever it gets new data to send, and it's not already enabled.TherewereUARTs that only interrupted on "tx regsiter BECAME available" (or perhaps it was just edge-triggered interrupt controllers?) I don't think I've seen one in a long time. In that case, you needed to make sure that the user-level code output the first character directly...

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: March 14, 2019, 09:35:15 am
content: Quote from: westfw on March 14, 2019, 01:41:51 amOne way to do this is to have only the interrupt code able initiate transmisison, and the user code force an interrupt when adding data to an empty tx buffer

author: bson
author_rank: Unknown
timestamp: March 15, 2019, 06:28:30 am
content: Quote from: mikeselectricstuff on March 14, 2019, 09:35:15 amHmmm... now we get into the annoying thing about the whole TI IFG business.How do you determine if the TX register is empty? The IFG is set! So you want to interrupt... how? Set the already set flag?(It might be possible to clear it, and then either the UART sets it immediately again, or you get to manually set it.)Either way, another very good habit is to make interrupt handlers ignore spurious interrupts by explicitly checking status bits and ignore the interrupt if nothing needs to be done.

author: mikerj
author_rank: Super Contributor
timestamp: March 15, 2019, 01:02:23 pm
content: Quote from: rhodges on March 12, 2019, 09:36:57 pmThis is required on micros like the PIC that have a common ISR for multiple peripherals, but not for 'normal' micros. You you are executing in the interrupt handler then the interrupt enable flag must have been set to get you there.Quote from: westfw on March 14, 2019, 01:41:51 amThat's exactly how a typical interrupt driven UART would work, it's much the same as interrupt driven SPI. To send data you add it to your FIFO buffer and enable the TX interrupt (if not already set). In the TX interrupt handler you put the next byte of data into the UART TX buffer if it's available, otherwise you disable the TX interrupt.

author: Rickta59
author_rank: Newbie
timestamp: March 17, 2019, 05:01:30 pm
content: Quote from: mikerj on March 15, 2019, 01:02:23 pmI'm not sure if you are saying that the msp430g2553 is a 'normal'. I'm pretty sure the msp430g2553 USCI peripheral does use a single interrupt vector for the UART and I2C features (actually 2 vectors one for TX one for RX). If you are using both I2C and UART you need to check which one is triggering. As far as the USCI peripheral and vectors used, it really depends on the actually msp430 part if it shares or doesn't share the interrupts.Quote from: mikerj on March 15, 2019, 01:02:23 pmOften with the msp430g2553 you are using the extremely limited memory for something else. It only has 512 bytes of ram. You need to share that with the stack and all other memory usage. I usually forego any output serial buffering and spinlock on write waiting for the peripheral TXBUF to be empty. I much prefer to use the msp430g2553's limited buffer memory for the receive queue where you can't control when you are going to receive data.

author: ebclr
author_rank: Super Contributor
timestamp: March 17, 2019, 06:53:52 pm
content: // ISR#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)#pragma vector=USCI_A0_VECTOR__interrupt void USCI_A0_ISR(void)#elif defined(__GNUC__)void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)#else#error Compiler not supported!#endif{switch(__even_in_range(UCA0IV,USCI_UART_UCTXCPTIFG)){case USCI_NONE: break;case USCI_UART_UCRXIFG:P1OUT |= BIT0; // Switch on red LED when byte received; TX vector will switch it off, it should be a short flickerwhile(UCA0STATW&UCBUSY); // Busy-waits inside ISR is bad code, but this is a stupid simple exampleUCA0TXBUF = UCA0RXBUF+1;__no_operation();break;case USCI_UART_UCTXIFG:P1OUT &= ~BIT0;break;case USCI_UART_UCSTTIFG: break;case USCI_UART_UCTXCPTIFG: break;default: break;}}