I'm trying to make UART connection to Atmega328p from HW-199 UART module. Here's my code:
static void UartPutChar(char ch)
{
while (!(UCSR0A & (1 << UDRE0)));
UDR0 = ch;
}
static void UartPutString(const char* str, uint32_t size)
{
for (uint32_t i = 0; i < size; i++) {
UartPutChar(str[i]);
}
}
static char UartReceiveChar(bool echo)
{
while (!(UCSR0A & (1 << RXC0)));
char ch = UDR0;
if (echo) {
UartPutChar(ch);
}
return ch;
}
static uint8_t UartReceiveString(char* str, uint8_t maxLen, bool echo)
{
uint8_t i = 0;
char c = 0;
while (i < maxLen && c != '\n' && c != '\r')
{
c = UartReceiveChar(echo);
str[i] = c;
i++;
}
return i;
}
int main(void)
{
srand(time(0));
_NOP();
CFG_OUTPUT_PDn(PD5);
SET_LOW_PDn(PD5);
uint16_t ubrr = (F_CPU / 16 / BAUD) - 1;
UBRR0H = (uint8_t)(ubrr >> 8);
UBRR0L = (uint8_t)(ubrr & 0xFF);
UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
const char* statusText = "\r\nSTATUS\r\n"
"Accelerometer data:\r\n"
"\tX: %d\r\n"
"\tY: %d\r\n"
"\tZ: %d\r\n"
"Gyroscope data:\r\n"
"\tX: %d\r\n"
"\tY: %d\r\n"
"\tZ: %d\r\n"
"Magnetometer data:\r\n"
"\tX: %d\r\n"
"\tY: %d\r\n"
"\tZ: %d\r\n"
"Temperature: %d\r\n"
"Pressure: %d\r\n"
"Altitude: %d\r\n"
;
char buf[1024] = {0};
while (1)
{
UartReceiveChar(true);
UartPutString("\r\n", 2);
memset(buf, 0, sizeof(buf));
uint32_t len = sprintf(buf, statusText, rand() % 32, rand() % 32, rand() % 32, rand() % 32, rand() % 32, rand() % 32, rand() % 32, rand() % 32, rand() % 32, rand() % 32, rand() % 32, rand() % 32);
UartPutString(buf, len);
UartPutString("\r\n", 2);
}
}
This code outputs a large piece of random data for testing purposes. When I press any key in terminal, it prints system data to the terminal, then the loop goes on and wait for the next key. Everything works good until some moment which causes either UART to drop connection to COM port (error writing to serial device) or it just hangs at some point and I need to reset the MCU, reconnect USB, and terminal and start the program over (losing all RAM data). I don't see any obvious issues with my code, it looks ok. BAUD is set to 4800 in code, putty, and in Windows device manager for UART device. 1 stop bit, 8 data bits, no parity also set by default in putty, Windows device, and Atmega328p initializes needed registers on launch to match this configuration.
What do I do wrong and how to make UART messaging not causing everything to stuck?
Here is a moment when it gets stuck. Terminal doesn't respond to my keystrokes, Tx/Rx LEDs of the UART are not lit
This is how I made the hardware:
UPD
Tested on higher baud rate of 9600, it either gets stuck on even the very first print or starts spamming testing text (however the code waits for user to press any key). When it spams, texts are delimited with unknown character and the UART doesn't get stuck
UPD2 The problem is definitely not in terminal software (I'm using putty). Tested via WSL and GNU screen utility, the behavior is the same
while
statement is a candidate for lockups ... replace it withif
... add a counter to exit after a number of retries \$\endgroup\$