Electronic – Does this interrupt improve performance even with while loop in ISR

avrcinterruptsmicrocontrolleruart

Note: I am a beginner 🙂 MCU: Atmega328p

Which program below burdens the CPU the least? Would it be a significant difference?

Objective: to make a more "efficient" serial monitor by reducing the CPU burden.

Both programs send the int num = 65534 to my PC where I can see value coming in repeatedly through a serial monitor. Program 1 uses a empty data register interrupt and program 2 does not use any interrupts.

Considering I am still using while (( UCSR0A & (1<<UDRE0)) == 0){} in uarttrasnmitinteger function within the ISR in program 1, does program 1 reduce the "workload" of the CPU compared to not using this interrupt such as in program 2 (see below)?

Program 1:

char snum[20];
int num = 65534;
        
int main (void) {
  uarttransmitenable();
  sei(); 
  while (1) {
    //no code here
  }
}

ISR(USART_UDRE_vect) {
  uarttrasnmitinteger(num, snum);
}
        
void uarttransmitenable(void) {
  UBRR0H = (BRC >> 8);
  UBRR0L = BRC;
            
  UCSR0B = (1<<TXEN0)| (1<<RXEN0) | (1<<UDRIE0);
  UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
}
            
void uarttrasnmitinteger(unsigned int num, char* snum) {
  utoa(num, snum, 10);
  unsigned int i;
  for (i=0; i<strlen(snum); i++) {
    while ((UCSR0A & (1 << UDRE0)) == 0) {}
    UDR0 = (char)snum[i];
  }
}

Program 2:

char snum[20];
int num = 65534;
        
int main (void) {
  uarttransmitenable();
  while (1) {
    uarttrasnmitinteger(num, snum); // same function used in program 1
  }
}

void uarttransmitenable(void) {
  UBRR0H = (BRC >> 8);
  UBRR0L = BRC;
            
  UCSR0B = (1 << TXEN0)| (1 << RXEN0);
  UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
}

Best Answer

Branching to the interrupt, saving registers, restoring registers, and then returning from the interrupt all take clock cycles. If the only thing you are doing is transmitting this serial data, then not having the interrupt is going to use less clock cycles overall.

Some other comments about the code.

  • Blocking while you send multiple characters within an interrupt will cause you to stay within the interrupt for hundreds of us to several ms depending on your baud rate. Generally speaking its good practice to enter and leave an interrupt quickly (like within a few us or 10s of us). Therefore blocking while you send multiple characters within an interrupt is generally not good practice.

  • Typically one would add characters to a FIFO and then enable the transmit data register empty interrupt. The interrupt would send only one character and then return. Once the character was sent, the interrupt would occur again and send the next character. Once the FIFO was empty the interrupt would be turned off. This would allow the characters to be sent essentially in the background while other code executes.

  • Use of a loop inside of an interrupt is usually not good practice (especially if the loop bounds are not well known). It can create the same timing problems mentioned above.