О подробностях подключения FTDI для прошивки и используемой модели см. предыдущий пост.
Пример отсюда: https://www.avrfreaks.net/forum/what-happens-if-you-read-udr0-multiple-times
Мой вариант, поменял F_CPU на 1000000UL и BAUD на 2400:
/*
* GccApplication1.c
*
* To answer the question, "What happens when you read the UART's
* Data Register (UDR) multiple times?"
* posed on AVRFreaks:
* https://www.avrfreaks.net/comment/3006581#comment-3006581
*
* Created: 05/10/2020 19:09:14
* Author : awn
*/
#define F_CPU 1000000UL // Clock Speed
#include <avr/io.h>
#include <util/delay.h>
#define BAUD 2400
#define MYUBRR F_CPU/16/BAUD-1
void usart_init( uint16_t ubrr_val )
{
// Set baud rate
UBRR0 = ubrr_val;
// Enable receiver and transmitter
UCSR0B = (1<<RXEN0) | (1<<TXEN0);
// Set frame format: 8 data, 2 stop bit
UCSR0C = (1<<USBS0) | (3<<UCSZ00);
}
void usart_txByte( uint8_t data )
{
while ( !( UCSR0A & (1<<UDRE0) ) )
{
// Wait for empty transmit buffer
}
// Put data into buffer, sends the data
UDR0 = data;
}
void usart_txString( char * string )
{
while ( *string )
{
usart_txByte( (uint8_t)*string );
++string;
}
}
int main(void)
{
usart_init( MYUBRR );
usart_txString( "Hello, ATmega328P XPlained Mini world\r\n" );
while (1)
{
while ( !(UCSR0A & (1<<RXC0)) )
{
// Wait for RXC
}
// At this point, RXC0 must be set - so there must be at least one byte to read from UDR0;
// Read & display the UDR0 plus RXC0 and DOR0 (overrun) bits multiple times...
usart_txString( "\r\nRXC0: " ); usart_txByte( (UCSR0A & (1<<RXC0)) ? '1' : '0' ); usart_txString( "; DOR0: " ); usart_txByte( (UCSR0A & (1<<DOR0)) ? '1' : '0' ); usart_txString( "; UDR0: " ); usart_txByte( UDR0);
usart_txString( "\r\nRXC0: " ); usart_txByte( (UCSR0A & (1<<RXC0)) ? '1' : '0' ); usart_txString( "; DOR0: " ); usart_txByte( (UCSR0A & (1<<DOR0)) ? '1' : '0' ); usart_txString( "; UDR0: " ); usart_txByte( UDR0);
usart_txString( "\r\nRXC0: " ); usart_txByte( (UCSR0A & (1<<RXC0)) ? '1' : '0' ); usart_txString( "; DOR0: " ); usart_txByte( (UCSR0A & (1<<DOR0)) ? '1' : '0' ); usart_txString( "; UDR0: " ); usart_txByte( UDR0);
usart_txString( "\r\nRXC0: " ); usart_txByte( (UCSR0A & (1<<RXC0)) ? '1' : '0' ); usart_txString( "; DOR0: " ); usart_txByte( (UCSR0A & (1<<DOR0)) ? '1' : '0' ); usart_txString( "; UDR0: " ); usart_txByte( UDR0);
usart_txString( "\r\nRXC0: " ); usart_txByte( (UCSR0A & (1<<RXC0)) ? '1' : '0' ); usart_txString( "; DOR0: " ); usart_txByte( (UCSR0A & (1<<DOR0)) ? '1' : '0' ); usart_txString( "; UDR0: " ); usart_txByte( UDR0);
usart_txString( "\r\nRXC0: " ); usart_txByte( (UCSR0A & (1<<RXC0)) ? '1' : '0' ); usart_txString( "; DOR0: " ); usart_txByte( (UCSR0A & (1<<DOR0)) ? '1' : '0' ); usart_txString( "; UDR0: " ); usart_txByte( UDR0);
usart_txString( "\r\n" );
// Pause - allow the user to type some characters
_delay_ms(3000);
}
}
Файл makefile:
FILENAME = udr_multi_read
PORT = ft0
DEVICE = atmega328p
PROGRAMMER = ftdi
BAUD = 2400
COMPILE = avr-gcc -Wall -Os -mmcu=${DEVICE}
default: compile upload clean
compile:
${COMPILE} -c ${FILENAME}.c -o ${FILENAME}.o
${COMPILE} -o ${FILENAME}.elf ${FILENAME}.o
avr-objcopy -j .text -j .data -O ihex ${FILENAME}.elf ${FILENAME}.hex
avr-size --format=avr --mcu=${DEVICE} ${FILENAME}.elf
upload:
avrdude -v -p ${DEVICE} -c ${PROGRAMMER} -P ${PORT} -b ${BAUD} -U flash:w:${FILENAME}.hex:i
clean:
rm ${FILENAME}.o
rm ${FILENAME}.elf
rm ${FILENAME}.hex
В консоли запустил:
screen /dev/tty.usbserial-A50285BI 2400
Подключил FTDI: (MCU RXD -> TX, MCU TXD -> RX, MCU GND -> GND, MCU VCC -> VCC) и увидел в screen такой результат:
Первая строчка появилась как только подключил FTDI к atmega328p, стопка последующих записей - сразу после нажатия клавиши "y" на клавиатуре (в английской раскладке). Так и должна работать программа, если посмотреть в код: пишет приветствие, потом ждет получения информации на линии RX, и возвращает полученную информацию в линию TX --- судя по том, что выдает screen, передача информации работает: символ "y" дошел до чипа и успешно вернулся обратно.