Question

Something interesting to note, which I am not fully understanding. My UART is initialized with 9600 baud. I've looked at the TX on the line via logic analyzer, and the bytes I send have minimal delay. It is 36µs per byte, which is expected.

Now, if I initialize that UART with a different baud rate, say 115,200, the delay between each byte sent increases significantly. It jumps to 125µs per byte.

This is causing a problem, since I've got to increase my baud rate at some point, but have a time constraint on my response.

Shouldn't the delay decrease between bytes, since it should be sending more bits at the same frequency?

This blocking method is for writing to the UART.

static inline void uart2_putchar(uint8_t data)
{
    // Disable interrupts to get exclusive access to ring_buffer_out.
    cli();
    if (ring_buffer_is_empty(&ring_buffer_out2)) {
        // First data in buffer, enable data ready interrupt
        UCSR2B |=  (1 << UDRIE2);
    }
    // Put data in buffer
    ring_buffer_put(&ring_buffer_out2, data);

    // Re-enable interrupts
    sei();
}

Which is triggered based on an interrupt.

ISR(USART2_UDRE_vect)
{
    // if there is data in the ring buffer, fetch it and send it
    if (!ring_buffer_is_empty(&ring_buffer_out2)) {
        UDR2 = ring_buffer_get(&ring_buffer_out2);
    }
    else {
        // no more data to send, turn off data ready interrupt
        UCSR2B &= ~(1 << UDRIE2);
    }
}

Timing Diagrams below:

~9600 Baud Rate -- enter image description here enter image description here

~115,200 Baud Rate -- enter image description here

Was it helpful?

Solution

Three points to check:

  • Do you feed the buffer fast enough? If not, the increased gap is due to your data providing code, not due to an internal behaviour of the processor. (use a toggle pin to find out)

  • Is it possible that because of the increased speed, your code just switches off the data register empty interrupt every single time it transmits data? Instead of using a put_char to fill up your ringbuffer, you could use a put_string(array, length) to fill it up with multiple chars at once (using memcopy for example, think about splitting it up into two mwmcopy operations when data has to wrap at the end of the buffer). (again, use a toggle pin to find out).

  • Reduce the code wraped into cli() and sei() to a minimum. Switch filling up the buffer with the flag check and and exclude this part from the cli-sei part

good luck!

OTHER TIPS

As long as you call uart2_putchar() often enough, your circular buffer is never empty and the the gap you measure is determined by the interrupt response time.

However, when you increase the baudrate you'll empty that buffer a lot quicker. Up to a critical point where the interrupt handler will find the buffer empty and cannot transmit a byte. The gap you measure is now determined by the rate at which you call uart2_putchar().

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top