title: UART transmission via interrupt on a 8051 microcontroller
body: <p>My platform is a c8051F120 microcontroller. I would like to send (=tx) bytes via UART0 using interrupts. My design so far is the following:</p>
  
  <pre><code>#define UART0_TX_SIZE 16    
  char UART0_tx[UART0_TX_SIZE];
  short UART0_tx_uart = 0;
  short UART0_tx_main = 0;
  short UART0_tx_available = 0;
  
  void UART0_putChar(char value) {
    char SAVE_SFRPAGE;
    bit EA_SAVE = EA;
    // potentially blocking code
    while (UART0_tx_available == UART0_TX_SIZE)
      ;
    // disable interrupts
    EA = 0;
    EA = 0;
    if (UART0_tx_available) {
      UART0_tx[UART0_tx_main] = value;
      ++UART0_tx_main;
      if (UART0_tx_main == UART0_TX_SIZE)
        UART0_tx_main = 0;
      ++UART0_tx_available;
    } else {
      SAVE_SFRPAGE = SFRPAGE;
      SFRPAGE = UART0_PAGE;
      SBUF0 = value;
      SFRPAGE = SAVE_SFRPAGE;
    }
    // reenable if necessary
    EA = EA_SAVE;
  }
  
  // (return void works for other interrupts)
  void UART0_Interrupt() interrupt (4) {
    if (RI0 == 1) {
      RI0 = 0;
    }
    if (TI0 == 1) { // cause of interrupt: previous tx is finished
      TI0 = 0; // Q: Should this clear tx interrupt flag be further down?
      if (SSTA0 &amp; 0x20) { // Errors tx collision
        SSTA0 &amp;= 0xDF;
      }
      if (UART0_tx_available) { // If buffer not empty
        --UART0_tx_available; // Decrease array size
        SBUF0 = UART0_tx[UART0_tx_uart]; //Transmit
        ++UART0_tx_uart; //Update counter
        if (UART0_tx_uart == UART0_TX_SIZE)
          UART0_tx_uart = 0;
      }    
    }
  }
  </code></pre>
  
  <p>I am pretty sure that the initialization regarding UART0 registers and timing via Timer2 (not part of the above code) is correct, because I am able to use the blocking function:</p>
  
  <pre><code>char putchar_Blocking(char value) {
    char SFRPAGE_SAVE = SFRPAGE;
    SFRPAGE = UART0_PAGE;
    while (!TI0) // while TI0 == 1 wait for transmit complete
      ;
    TI0 = 0;
    SBUF0 = value;
    SFRPAGE = SFRPAGE_SAVE;
    return value;
  }
  </code></pre>
  
  <p>When I want to switch to the interrupt design, of course, I also set </p>
  
  <pre><code>ES0 = 1;
  </code></pre>
  
  <p>Does anybody find a flaw in my design that attempts to use the interupt? Or, does anybody have sample code for this? Thank you! And a big shout-out to jszakmeister, who answered my question regarding reading the TCNT register.</p>