I'm using an Arduino as an AVR programmer for an ATMega328p chip. I want to send Serial data from the ATMega328p back to the Arduino, which the latter shall print to the Serial monitor. (Incidentally, I'd welcome advice on a preferable method of debugging.)
I'm just working with the ATMega328p's USART. It seems to kind of work, but I'm trying to send 4-byte packages, and about one in six bytes gets dropped (way more than the 0.2% error rating which the datasheet indicated for a 96K baudrate). What should I be doing differently?
ATMega328p code:
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define baudrate 9600
#define UBRRVAL ((F_CPU/(baudrate*16UL)) - 1)
void init()
{
// set baudrate
UBRR0H = UBRRVAL >> 8; // set high byte for baudrate
UBRR0L = (uint8_t) UBRRVAL; // set low byte for baudrate
// enable transmitter only
UCSR0B = (1<<TXEN0);
// set frame format: asynch, no parity, 1 stop bit, 8-bit
UCSR0C = (0<<UMSEL00) | (0<<UPM00) | (0<<USBS0) | (3<<UCSZ00);
}
void sendByte(uint8_t dataByte) // datasheet p 206
{
// wait for empty transmit buffer
while ( UCSR0A & (1<<UDRE0) == 0 );
// put data into buffer (this effectively sends the data)
UDR0 = dataByte;
}
int main()
{
init();
while (1)
{
sendByte('h');
sendByte('q');
sendByte('!');
sendByte('\n');
}
return 1;
}
(Yes, I'm looking at the datasheet1 (it's technically for 168p, but I can't find anything more than a summary for the 328p).)
(The reason I'm working directly with the chip's USART is I tried to #include Arduino library files in the code for my ATMega328p, but my attempts to transmit to the Arduino failed.)
Apologies for the lateness of my reply. I took ill yesterday.
Does this... ...make any difference?
It does. It looks as though the last two bytes of each packet are dropped consistently. (I don't understand it.)
hqhqhqhqhqhqhqhq
Char? i isn't a char.
It's true that I'm counting, but unsigned byte, uint8_t, and char are fundamentally the same type. I used char because it's part of ANSI C.
No need to actually make sure that there is room in the array?
A worthy question. I believe, however, that the code executes quickly enough that the array will never nearly fill at 9600 bps. (To check, I added some monitor output at the end of the output 'for' loop, and it appears that I don't get more than a byte of serial input before the Arduino is ready to access it (speaking for this code at this baudrate).)
@jraskell's suggestion proves the problem is not with the Mega. My earlier suggestion proves the problem is not with the receiver (PC or Serial Monitor). What's left?
(It's good to see a transmission working, but as a solution,
That is not a solution. It's a test to determine where the problem lies.
The ATmega328 USART has, what is essentially, a two byte output queue. If two bytes are sent but not the third then your program is not correctly managing the two byte queue. In other words, the bug is in sendByte.
Like you, I thought equals-comparison has lower precedence than bitwise-and but that is not the case (search for "Operator precedence")...
So, the solution is to add parenthesis...
void sendByte(uint8_t dataByte) // datasheet p 206
{
// wait for empty transmit buffer
while ( ( UCSR0A & (1<<UDRE0) ) == 0 );
// put data into buffer (this effectively sends the data)
UDR0 = dataByte;
}