USART transmission errors with CP210x

avrtransmissionuart

I am sending ADC results from an ATmega16 controller to a PC through CP2102. Baudrate: 0.5Mb/s, 8 data-bits, 1 stop bit, no parity. I've written a software to visualize received data. Here is an example of ADC results from sampling a sine wave signal:

chart

At some point my PC was under heavy load and this is the result that I had:

chart_spikes

In my previous question I assumed that these spikes were caused by the ADC itself. However it is clearly seen now that these spikes are caused by transmission errors.

As far as I understand this problem occurs due to the overflow of CP210 TX buffer. Is my assumption correct? And if so, what can be done to prevent this?

Besides these spikes I've also found another problem. I am sending two bytes consecutively (ADCL and ADCH). What I've noticed is that sometimes the received bytes are swapped (i.e. ADCH is received before ADCL).

I've dumped some data where the spikes occur (first byte is ADCH, second is ADCL and the number is the resulting integer value)

Example 1:

821 : 00000011, 00110101
803 : 00000011, 00100011
783 : 00000011, 00001111
1018 : 00000011, 11111010
740 : 00000010, 11100100
718 : 00000010, 11001110
694 : 00000010, 10110110

Example 2:

229 : 00000000, 11100101
237 : 00000000, 11101101
246 : 00000000, 11110110
255 : 00000000, 11111111
10 : 00000000, 00001010
276 : 00000001, 00010100
289 : 00000001, 00100001

Update: added usart initialization routine

#define F_CPU 16000000UL
#define USART_BAUDRATE 500000
#define BAUD_PRESCALE ((F_CPU / (USART_BAUDRATE * 16UL)) - 1)

void USARTInit() {
    UBRRH &= ~(1 << URSEL);
    UBRRH = (unsigned char) (BAUD_PRESCALE >> 8);
    UBRRL = (unsigned char) BAUD_PRESCALE;
    UCSRB = (1 << TXEN) | (1 << RXEN) | (1 << RXCIE);
    UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0); // 1 stop bit, 8-bit data length
}

Update: added a simple test for usart

I've disabled ADC and replaced my main routine with a simple loop:

for (uint16_t i = 0; i < 1023; i++) {
    USARTSendByte(uint8_t(i));
    USARTSendByte(uint8_t(i >> 8));
}  

When I start the terminal on my computer and put the system under heavy load (lots of background processes) I sometimes receive results like this:

...
252 : 00000000, 11111100
253 : 00000000, 11111101
254 : 00000000, 11111110
255 : 00000000, 11111111
0 : 00000000, 00000000
257 : 00000001, 00000001
513 : 00000001, 00000010
769 : 00000001, 00000011
260 : 00000001, 00000100
261 : 00000001, 00000101
...

Best Answer

As far as I understand this problem occurs due to the overflow of CP210 TX buffer. Is my assumption correct?

We don't have enough details to answer this - but it sounds highly likely.

And if so, what can be done to prevent this?

The CP210x provides the RS232 handshake signals, e.g. RTS/CTS - but that would require a buffer for the UART data on the ATmega.

Try using a big buffer on the PC side: USB transfers work without much CPU interventions in most cases. Note that you cannot elimitnate the data loss when the PC load is too high, you can only try to migitate it with some sort of protocol.