UART Transmission TX inside ISR

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

UART Transmission TX inside ISR

MSP430 - Discuss mailing list
I'm curious if someone can explain to me the (negative?) effects of trying to send UART bytes directly from my Interrupt Service Routine.  Is this bad design practice because now my ISR will take longer to execute?  Should I be using DMA to TX data here?  Thanks in advance.
 

 static void ParseRxData(const uint8_t rx_byte)
 {
     // Only Allow ASCII Characters to be loaded into buffer
     // This will drop CR/LF etc, won't go in gRxBuffer
     if (rx_byte >= 0x20)
         gRxBuffer[gWrIndex++] = tolower(rx_byte); // stuff lowercase only into buffer
 

     UartSendChar(rx_byte);
 

     if (rx_byte == 0x0A) // End of Command
     {
         gRxBuffer[gWrIndex] = 0;  // Add null pointer to end
         gFlagCmdReady = true;  // Set Global Flag Ready Command
         gWrIndex = 0;
     }
 }
 

 

 //******************************************************************************
 //
 //This is the USCI_A1 interrupt vector service routine.
 //
 //******************************************************************************
 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
 #pragma vector=USCI_A1_VECTOR
 __interrupt
 #elif defined(__GNUC__)
 __attribute__((interrupt(USCI_A1_VECTOR)))
 #endif
 void EUSCI_A1_ISR(void)
 {
     uint8_t RXData;
     switch(__even_in_range(UCA1IV,USCI_UART_UCTXCPTIFG))
     {
     case USCI_NONE: break;
     case USCI_UART_UCRXIFG:
         RXData = EUSCI_A_UART_receiveData(EUSCI_A1_BASE);
         ParseRxData(RXData);
         break;
     case USCI_UART_UCTXIFG: break;
     case USCI_UART_UCSTTIFG: break;
     case USCI_UART_UCTXCPTIFG: break;
     }
 }
 

Reply | Threaded
Open this post in threaded view
|

Re: UART Transmission TX inside ISR

MSP430 - Discuss mailing list
Without seeing how that compiles it is hard to say. What I can say is
that transmitting inside the interrupt, provided your interrupt is
small, is generally the fastest and most efficient way to do it. The DMA
on the MSP430 is not a true DMA in that it steals clocks from the CPU so
isn't as efficient as a traditional DMA. If you have DMA and your
messages are reasonably long then it's worthwhile usign DMA most of the
time. You have to weigh the DMA set up overhead, and the loss of CPU
cycles against the savings made, and make allowances for all scenarios

This is a typical UART handler that handles both Tx and RX although RX
isn't used in this case.

Handling the RX may seem pedantic, but register RAM corruption does
occur (I probably made a tidy living for many years off of that common
omission) and unless you have other more complex safeguards in place
this is a simple way of avoiding erroneous transmission. It should have
another instruction prior to exit that clears the RXIFG so that the
false int doesn't keep re-occurring, but it wasn't in my original code
so I left it so I could point out my own error.

;****** THIS UART A0 IS USED FOR RF COMMS


USCABTX_ISR:                         ;UART1 TX VECTOR, TRAP IF UNUSED.
     BIT    #UCA0TXIFG,&IFG2           ;Test Tx int flag
     JNZ    TXHB0                      ;jump if set
     BIC    #LPM3,0(SP)                ;set low poer mode on exit
     RETI                              ;else exit
TXHB0:
     MOV    &TX_PTR,R12                ;set up to use indexed fetch
     INC    &TX_PTR
     MOV.B    TX_BUFFER(R12),&UCA0TXBUF    ;write next byte to Tx OUTPUT reg
     DEC    DIGITS                     ;DIGITS is a reserved register
for tracking the Tx size
     JNZ    ENDTX                      ;if not last byte continue
     BIC.B    #UCA0TXIE,&IE2           ;else disable ISR
     BIS.B    #GREEN,&P2OUT            ;turn Green Tx LED off
     BIC    #LPM3,0(SP)                ;and exit in LPM3
ENDTX:
     RETI

Al


On 30/09/2016 12:57 AM, [hidden email] [msp430] wrote:

>
>
> I'm curious if someone can explain to me the (negative?) effects of
> trying to send UART bytes directly from my Interrupt Service Routine.
>  Is this bad design practice because now my ISR will take longer to
> execute?  Should I be using DMA to TX data here?  Thanks in advance.
>
>
> static void ParseRxData(const uint8_t rx_byte)
>
> {
>
>     // Only Allow ASCII Characters to be loaded into buffer
>
>     // This will drop CR/LF etc, won't go in gRxBuffer
>
>     if (rx_byte >= 0x20)
>
>         gRxBuffer[gWrIndex++] = tolower(rx_byte); // stuff lowercase
> only into buffer
>
>
>     UartSendChar(rx_byte);
>
>
>     if (rx_byte == 0x0A) // End of Command
>
>     {
>
>         gRxBuffer[gWrIndex] = 0;  // Add null pointer to end
>
>         gFlagCmdReady = true;  // Set Global Flag Ready Command
>
>         gWrIndex = 0;
>
>     }
>
> }
>
>
>
> //******************************************************************************
>
> //
>
> //This is the USCI_A1 interrupt vector service routine.
>
> //
>
> //******************************************************************************
>
> #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
>
> #pragma vector=USCI_A1_VECTOR
>
> __interrupt
>
> #elif defined(__GNUC__)
>
> __attribute__((interrupt(USCI_A1_VECTOR)))
>
> #endif
>
> void EUSCI_A1_ISR(void)
>
> {
>
>     uint8_t RXData;
>
>     switch(__even_in_range(UCA1IV,USCI_UART_UCTXCPTIFG))
>
>     {
>
>     case USCI_NONE: break;
>
>     case USCI_UART_UCRXIFG:
>
>         RXData = EUSCI_A_UART_receiveData(EUSCI_A1_BASE);
>
>         ParseRxData(RXData);
>
>         break;
>
>     case USCI_UART_UCTXIFG: break;
>
>     case USCI_UART_UCSTTIFG: break;
>
>     case USCI_UART_UCTXCPTIFG: break;
>
>     }
>
> }
>
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: UART Transmission TX inside ISR

MSP430 - Discuss mailing list
In reply to this post by MSP430 - Discuss mailing list
Hi xilverbolt,

you are receiving a byte and just send it.
UartSendChar() is typically waiting for the sending UART to be free again -
and will block your interrupts and CPU for this time - maybe not a good
idea. You should at least enable the interrupts before calling ParseRXData
(EINT()). However, in case the sending and transmitting UART are both
working at the same speed, this will never happen.

Another point: I would not call subroutines from the interrupt, this need
much more cycles e.g. for saving all registers to stack. In a short int-
routine, as in your example, only a few registern are needed to be pushed
to the stack and popped. However maybe the compiler is good one and is
inlining your subroutine automatically. Another advantage is, you will see
what happen in only a few lines - e.g. that UartSendChar() is blocking your
code.
Encapsulation of code in subroutines is often a good idea, but sometimes
not.

In case you just want to copy a byte from uarta to uartb - this can be done
with the DMA only - just code for the setup is required, no active code
during execution of the task required and no blocking of the CPU, for my
opinion the best solution - however you need some time to find out the
right setup bits ;-). It is possible to have a additional rx interrupt that
is handling the buffering of the bytes only.

Matthias

"[hidden email] [msp430]" <[hidden email]>:

> I'm curious if someone can explain to me the (negative?) effects of
> trying to send UART bytes directly from my Interrupt Service Routine.
> Is this bad design practice because now my ISR will take longer to
> execute?  Should I be using DMA to TX data here?  Thanks in advance.
>  
>
>  static void ParseRxData(const uint8_t rx_byte)
>  {
>      // Only Allow ASCII Characters to be loaded into buffer
>      // This will drop CR/LF etc, won't go in gRxBuffer
>      if (rx_byte >= 0x20)
>          gRxBuffer[gWrIndex++] = tolower(rx_byte); // stuff lowercase
>          only into buffer
>  
>
>      UartSendChar(rx_byte);
>  
>
>      if (rx_byte == 0x0A) // End of Command
>      {
>          gRxBuffer[gWrIndex] = 0;  // Add null pointer to end
>          gFlagCmdReady = true;  // Set Global Flag Ready Command
>          gWrIndex = 0;
>      }
>  }
>  
>
>  
>
>  //**********************************************************************
>  ******** //
>  //This is the USCI_A1 interrupt vector service routine.
>  //
>  //**********************************************************************
>  ******** #if defined(__TI_COMPILER_VERSION__) ||
>  defined(__IAR_SYSTEMS_ICC__) #pragma vector=USCI_A1_VECTOR
>  __interrupt
>  #elif defined(__GNUC__)
>  __attribute__((interrupt(USCI_A1_VECTOR)))
>  #endif
>  void EUSCI_A1_ISR(void)
>  {
>      uint8_t RXData;
>      switch(__even_in_range(UCA1IV,USCI_UART_UCTXCPTIFG))
>      {
>      case USCI_NONE: break;
>      case USCI_UART_UCRXIFG:
>          RXData = EUSCI_A_UART_receiveData(EUSCI_A1_BASE);
>          ParseRxData(RXData);
>          break;
>      case USCI_UART_UCTXIFG: break;
>      case USCI_UART_UCSTTIFG: break;
>      case USCI_UART_UCTXCPTIFG: break;
>      }
>  }
>