[TUT] [SOFT] Using the USART - Interrupt driven serial comms

Go To Last Post
339 posts / 0 new

Pages

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm trying to understand on this code:

int main(void)
{
	usartinit(9600);
	sei();
    while(1)
    {
		if (rxFlag==1){
        // usartwritechar_nostream(rx[rxn-1]);
		rxFlag=0;
		}		
    }
}

ISR(USART_RX_vect)
{
	    while ( !(UCSR0A & (1<<RXC0)) );
		if (rxn==BUFFER_SIZE) // if BUFFER_SIZE is reached, reset to start of buffer.
		rxn=0;
		rx[rxn++] = UDR0; // increment rxn and return new value.
		usartwritechar_nostream(rx[rxn-1]);
		rxFlag=1; // notify main of receipt of data.
}

why the flag is no set at all. The interrupt in this case works and echo back what I write (I could use UDR0 directly, I know that, is simply done using the function). Putting the write function inside IF() will be never used. I feel a bit stupid. What am I missing?

EDIT: the flag is set, after receiving a char bacame 1 (I printed it out on uart). But if I write this:

if (rxFlag==1){
        printf("R");
		rxFlag=0;
		}		

The R char will be never printed. (do not enter in if condition at all). Try with my code. :)

EDIT EDIT: "SOLVED". It works ONLY if I put a delay or something else after the if (out of it and before the last bracket of the main). It doesn't make sense!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sounds like rxFlag may not be volatile.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Sounds like rxFlag may not be volatile.

Ok thank you, with volatile it works. The optimizer skips the if() condition. :)http://publications.gbdirect.co.uk/c_book/chapter8/const_and_volatile.html

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also see this tutorial I wrote which is focused on avr-gcc

http://www.avrfreaks.net/index.p...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Dean,

It is a great tutorial and I am using it for building my first UART program. I am using Proteus to simulate the hyperterminal. I am using Atmega8 with internal RC osc. settings of 1Mhz.

When I use F_CPU 1000000UL and use internal RC at 1Mhz then the program gives garbage value as return character.

When I set F_CPU 8000000UL and change intern RC at 8Mhz it works. Is this normal behavioir.

Is the code indenpendent of CPU speed ?

Or am I doing something wrong here.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You cannot do 9600 baud on 1MHz. The error (as the datasheet tells you in the Examples tables) is -7.0% while UART only works with errors between -2% and +2%.

Either change the code to use U2X mode. Or change the code to use a baud rate with an abs(error) less than 2%. Or change the CPU frequency to something other than 1MHz.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the quick reply clawson.
I will keep this in mind.

BTW- Your avatar GIF is just great. Liked it pretty much.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also note that you where lucky with 8 MHz from the internal RC. It can be off by so much as 10% - again violating the 2% limit.

If you really want to trust the internal RC with UART comms, then search this site for earlier discussions on calibrating the internal RC (once and for all if running conditions will be stable, or repeatedly if they will vary).

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, I will keep that in mind for UART comms.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi guys

I'm trying to learn how to program against the UART on an atmega16a.

I'm using the code from the the pdf at the beginning of the thread. Here is the code with a couple minor mods.

#include 
#include 

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

int main ( void )
{
	DDRC = _BV(PC0);
	DDRC |= _BV(PC1);
	
	UCSRB = (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
	UCSRC = (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8- bit character sizes
	
	UBRRH = ( BAUD_PRESCALE >> 8); // Load upper 8- bits of the baud rate value into the high byte
									// of the UBRR register
									
	UBRRL = BAUD_PRESCALE ; // Load lower 8- bits of the baud rate value into the low byte of the
							// UBRR register
							
	UCSRB |= (1 << RXCIE ); // Enable the USART Recieve Complete interrupt ( USART_RXC )
	
	sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed
	
	for (;;) // Loop forever
	{
		// Do nothing - echoing is handled by the ISR instead of in the main loop
		UART_TxChar('A');
		PORTC = _BV(PC0);
		
	}
}

void UART_TxChar(unsigned char data)
{
	while(!(UCSRA & (1<<UDRE)));
	UDR = data;
}
	
ISR(USART_RXC_vect)
{
	PORTC = _BV(PC1);
	//char ReceivedByte ;
	//ReceivedByte = UDR; // Fetch the received byte value into the variable " ByteReceived "
	//UDR = ReceivedByte; // Echo back the received byte back to the computer
}

I am using realterm to monitor the traffic coming from the chip. In the for loop you will see the transmit command that sends and 'A' to the terminal software. This is working fine, but as soon as I try and send a character back to the chip, it locks up.

By lockup I mean that the data in realterm stops scrolling and never restarts. I put a line in the beginning of the interrupt that should light an indicator LED, but the LED is not lighting, so it looks like I am not getting to that code.

Can anybody see what I'm doing wrong? Am I using the wrong registries for this chip?

Thanks
Anthony

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That sounds like the vector is incorrect. Are you sure the name of the vector is correct? My guess is that it should be USART_RXC1_vect.

Edit: In looking at the .h file, the name is USARTRXC_vect.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, that fixed it. Seeing what you wrote, I search the file and found the h. and now I see the naming convention so I should be able to find this again if I ever run into the same problem.

Can I take the question one step further? How did the .h file get included? Was the compiler doing it as a built in function, or is there a conditional include somewhere that I am missing?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

or is there a conditional include somewhere that I am missing?

Take a look at avr/io.h, it's basically one big conditional statement. The choice is based on a define made inside the compiler as a result of the -mmcu= value passed when you compile.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Quote:

or is there a conditional include somewhere that I am missing?

Take a look at avr/io.h, it's basically one big conditional statement. The choice is based on a define made inside the compiler as a result of the -mmcu= value passed when you compile.

Thanks, i knew it had to be using the mmcu value, but I was not thinking about the io.h file. I was mentally stuck looking through the interrupt.h file.

Thanks for the info. The help is appreciated.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi guys,

Is there a way to carry the value of "receiveData " outside the ISR? I need to use the "receiveData " value in another function.

ISR(USART_RXC_vect) 
{	
	receiveData = UDR;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Declare/Define recieveData as a global variable, and because it is going to be used in the ISR and another function it should also be declared as volatile.

volatile char receiveData;

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." - Marcus Aurelius               

Last Edited: Sun. Jan 12, 2014 - 08:38 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you sir.
It worked.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Great work on the tutorial.
I am using the same code as mentioned in the tutorial for ATmega16. However the program does not go past the build stage. It shows the same error in winavr and avr studio also.

# include 
# include 
# define USART_BAUDRATE 9600
# define BAUD_PRESCALE ((( F_CPU / ( USART_BAUDRATE * 16 UL))) - 1)
int main ( void )
{
UCSRB = (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
UCSRC = (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8- bit character sizes
UBRRH = ( BAUD_PRESCALE >> 8); // Load upper 8- bits of the baud rate value into the high byte
of the UBRR register
UBRRL = BAUD_PRESCALE ; // Load lower 8- bits of the baud rate value into the low byte of the
UBRR register
UCSRB |= (1 << RXCIE ); // Enable the USART Recieve Complete interrupt ( USART_RXC )
sei (); // Enable the Global Interrupt Enable flag so that interrupts can be processed
for (;;) // Loop forever
{
// Do nothing - echoing is handled by the ISR instead of in the main loop
}
}
ISR ( USART_RXC_vect )
{
char ReceivedByte ;
ReceivedByte = UDR ;
UDR = ReceivedByte ;
}

the error shown in programmers notepad and avrstudio is the same which is error: expected ')' before 'UL'
i have attached a screenshot in case of further reference

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

UL is a suffix. It looks to me as though you have a space between the 16 and it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you.Yes that did seem to be the problem. Funny that the original code, copied as it is giving errors though.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello, guys i already rad lots of tutorials here, but i have a problem that i cannot solve so i come here to ask for help. i'm trying to do something i think it should be ease . I'm trying to read a string from serial console when i press enter and see if the string is "ab" and if it is should return the string "good". So far i cannot do any, i tried to solve the first problem with really basic situation, like press key and return a number by transmition interrupt, but causes a infinite loop. Thanks in advance


#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 16000000

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

volatile char rx [4];
volatile int rxn=0;
volatile int i=0;
volatile char str[10];

ISR(USART_RXC_vect)
{

char ReceivedByte;

ReceivedByte = UDR; // Fetch the received byte value into the variable "ByteReceived"

if (ReceivedByte==0x0D) {
rx[rxn++] = '\0';
putS();
}
else{
rx[rxn++] = ReceivedByte;
} // increment rxn and return new value.

}

ISR(USART_TXC_vect)
{
i++;
}

int main (void)
{
//UART CONFIG:
UCSRB = (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes and 1 stop bit

UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register

UCSRB |= (1 << RXCIE ) | (1 << TXCIE );

sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed

for(;;);

}

void code_Generator () {
if (rx == "ab")
*str="Good";

}
void putS () {

while(str[i]='\0')
putC(str[i]);

}

void putC (char c) {
UDR = c;
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You clearly need to read this and the other UART tutorials first. Your code is very confused.

(BTW this isn't really the place to ask anyway - the thread is only really for feedback about this tutorial).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You increment rxn, but you:
A) never check to see if the increment results in a valid index for rx[]
B) never set rxn back to 0
A very bad combination.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

Fails for 115200,  returns 7 instead of 8

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jstampfl wrote:

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

Fails for 115200,  returns 7 instead of 8

Based on the numbers you've provided, I'm betting your running with an external 16.000MHz crystal.

 

Any frequency that dose not produce results (when using the above formula) that are whole numbers will truncate the fractional part of the result.  Crystals that are so called "Magic  Frequencies", such as 1.47345MHz, 1.8432MHz 14.7456MHz, 18.432MHz crystals WILL produce whole number results, when using n = ( F_CPU / ( USART_BAUDRATE * 16 UL )) - 1.

 

Then there will be the complaint that "Magic Frequencies" do not work well for exact 2^n results when working out timer calculations, such as 100uS, 1mS, 10mS, etc. result in timing inaccuracies.

 

If say, the crystal frequency is 18.432MHz, that resolves down to about 5.4nS per timer tick.  That translates to about a 0.5% error over a 1uS span, as apposed to a best case error of 3.5%, when attempting to communicate at 115.2K BAUD and using a 16.000MHz crystal.

 

To me, its better to be off a few nanoseconds in your timing (especially over longer timing intervals) and have the most error free & reliable communications, rather then have perfect timing and error prone & unreliable communications. 

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think many are using Arduino boards which are 16MHz.  Someone had commented that the tutorial code failed for 115200.  I was pointing out that the code doesn't work for  115200 at 16MHz (as was pointed out by Microcarl) because of the "# define BAUD_PRESCALE ((( F_CPU / ( USART_BAUDRATE * 16 UL ))) - 1)".  If you read the datasheet you can set the value to 8 directly.  Reading the datasheet, you might notice that 76800 has a much lower error.

 

The point about the "Magic Frequencies" is good to keep in mind.  But may not be the deciding factor in a given application.

 

I think that the variety and quantity of Arduino hardware is compelling.

 

And cost,  Chinese - pro-mini/Nano style board $2 - $3, UNO style $5, Mega2560 Style $12.  Hard to beat for hobbyists and low income (developing world residents).

 

Avrdude downloads at 115200 and I have yet to see a problem.

 

Last Edited: Sun. Dec 28, 2014 - 04:02 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jstampfl wrote:

Avrdude downloads at 115200 and I have yet to see a problem.

 

Create the following small echo-back program.

I am using the ImageCraft ICCAVR V7.xx compiler and so, you will have to add the appropriate iomxxx.h headder, getchar.c and putchar.c, if needed.

#define UART0_Tx_ON() UCSR0B |= (1<<TXEN0)
#define UART0_Tx_OFF() UCSR0B &= ~(1<<TXEN0)
#define UART0_Rx_ON() UCSR0B |= (1<<RXEN0)
#define UART0_Rx_OFF() UCSR0B &= ~(1<<RXEN0)
#define ESC 0x1B
#define BEL 0x07
#define CR 0x0D
#define LF 0x0A

#define SCREEN_CLEAR() (printf("%c[2J", ESC))
#define DO_CR_LF() (printf("%c%c", CR, LF))
#define DO_BELL() (printf("%c", BEL))
#define CURSOR_PUT(x, y) (printf("%c[%d;%dH", ESC, y, x)) // First X, then Y
#define CURSOR_HIDE() (printf("%c[?25l", ESC))
#define CURSOR_SHOW() (printf("%c[?25h", ESC))
#define TEXT_SET_ATTRIBUTES(r, i, b, c) (printf("%c[%d;%d;%d;%dm", ESC, r, i, b, c))

// Fcpu = 16.000MHz
#ifdef Nano
  #define BAUD_2400 416
  #define BAUD_4800 207
  #define BAUD_9600 103
  #define BAUD_14_4K 68
  #define BAUD_19_2K 51
  #define BAUD_28_8K 34
  #define BAUD_38_4K 25
  #define BAUD_57_6K 16
  #define BAUD_76_8K 12
  #define BAUD_115_2K 8
  #define BAUD_230_4K 3
#endif

void USART0_Init(unsigned int ubrr) {
  UCSR0B = NULL; // Disable while setting baud rate
  UCSR0A = NULL;
  UCSR0C = (1<<UCSZ01) | (1<<UCSZ00); // 8 bit data
  UBRR0H = (unsigned char)(ubrr>>8);
  UBRR0L = (unsigned char)ubrr;
}

void main(void) {
char Temp;
unsigned long int MY_UBRR = ((Fosc / 16) / BAUD) - 1;
 
USART0_Init(BAUD_115_2K);
UART0_Tx_ON(); // Enable USART0 transmitter
UART0_Rx_ON(); // Enable USART0 receiver 
SCREEN_CLEAR();
CURSOR_SHOW();
DO_BELL()
printf("BAUD = %lu > ", MY_UBRR);
  
  while (1) {
     Temp = getchar();      
     if (Temp == CR) {
        DO_CR_LF();
        printf("BAUD = %u > ", MY_UBRR);     
        Temp = NULL;
     }     
     else if (Temp != NULL) {
       putchar(Temp);
     }
  }
}

Use HyperTerm or TerraTerm for your terminal program, running at 115.2K and your favorite AVR - an Arduino board running a 16.000MHz program will do just fine.

 

Once you've got it working, simply typing your name or some short text.  You'll find that everything  works great at keyboard typing speeds.  But if you hold down the "RETURN" key for a few seconds, you'll notice that there are a substantial number of characters returned that are wrong.

 

Several years ago, I designed a small control system that continually fed status data to HyerTerm that used the advanced cursor positioning and other features of the ANSII VT100 terminal.  It was most frustrating because, data wasn't always put in the correct place on the display.

 

So, while everyone seem quite happy with simple keyboard text being reliably sent to and from an AVR at the error rate imposed with 16.000MHz and 115.2K BAUD, when near real time data is being passed back & forth between two systems, the errors become very pronounced.

 

If you like, change it up with a 14.7456MHz or 18.432MHz crystal and use the appreciate BAUD constant and you'll find that you don't get any data errors when holding down the "RETURN" key.  Ive providet the BAUD list for 18.432MHz.

// Fcpu = 18.432MHz
#ifdef Duemilanove
  #define BAUD_2400 479
  #define BAUD_4800 239
  #define BAUD_9600 119
  #define BAUD_14_4K 79
  #define BAUD_19_2K 59
  #define BAUD_28_8K 39
  #define BAUD_38_4K 29
  #define BAUD_57_6K 19
  #define BAUD_76_8K 14
  #define BAUD_115_2K 9
  #define BAUD_230_4K 4
#endif

Also note that, using MY_UBRR = ((Fosc / 16) / BAUD) - 1, returns the value '7' and not '8', when Fosc is 16.000MHz.

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

Last Edited: Mon. Dec 29, 2014 - 06:29 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't agree that holding the key down is 'near realtime' it's not even close.

there should be a key repeat of like 500ms between each key.

There's something else happening there.

 

It's important to buffer in and out of your micro, not enough people do that.

I'm talking about a circular buffer that the tx isr transmits out of and another that the rx ISR reads into.

Blocking serial IO will bring the house down. Serial is slowy McSlow.

Keith Vasilakes

Firmware engineer

Minnesota

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The following program works on a Chinese VISduino UNO R3 style board and on a Chinese Nano style b oard.  Does not work on a Arduino Mega2560 board.

 

 
.cseg

.org 0x0000 ;Places the following code from address 0x0000
        jmp RESET ; Reset Handler
        jmp EXT_INT0 ; IRQ0 Handler
        jmp EXT_INT1 ; IRQ1 Handler
        jmp PCINT0L ; PCINT0 Handler
        jmp PCINT1L ; PCINT1 Handler
        jmp PCINT2L ; PCINT2 Handler
        jmp WDT ; Watchdog Timer Handler
        jmp TIM2_COMPA ; Timer2 Compare A Handler
        jmp TIM2_COMPB ; Timer2 Compare B Handler
        jmp TIM2_OVF ; Timer2 Overflow Handler
        jmp TIM1_CAPT ; Timer1 Capture Handler
        jmp TIM1_COMPA ; Timer1 Compare A Handler
        jmp TIM1_COMPB ; Timer1 Compare B Handler
        jmp TIM1_OVF ; Timer1 Overflow Handler
        jmp TIM0_COMPA ; Timer0 Compare A Handler
        jmp TIM0_COMPB ; Timer0 Compare B Handler
        jmp TIM0_OVF ; Timer0 Overflow Handler
        jmp SPI_STC ; SPI Transfer Complete Handler
        jmp USART_RXC ; USART, RX Complete Handler
        jmp USART_UDRE ; USART, UDR Empty Handler
        jmp USART_TXC ; USART, TX Complete Handler
        jmp ADCR ; ADC Conversion Complete Handler
        jmp EE_RDY ; EEPROM Ready Handler
        jmp ANA_COMP ; Analog Comparator Handler
        jmp TWI ; 2-wire Serial Interface Handler
        jmp SPM_RDY ; Store Program Memory Ready Handler
;
RESET:    ldi r16, high(RAMEND); Main program start
        out SPH,r16 ; Set Stack Pointer to top of RAM
        ldi r16, low(RAMEND)
        out SPL,r16
        cli ; disable interupts
        ; Set baud rate
        ldi r16,8   ; 8 = 115200, 16 = 57600, 103 = 9600, 207 = 4800
        sts UBRR0L, r16
        clr r16
        sts UBRR0H, r16
        sts UCSR0A, r16 ; set to zero to be sure

; Enable receiver and transmitter
        ldi r16, 0b0001_1000 ; (1<<RXEN0) | (1<< TXEN0 )  ;
        sts UCSR0B,r16
; Set frame format: 8data, 1stop bit
        ldi r16, 0b0000_0110 ;
        sts UCSR0C,r16

again:
        lds r18, UCSR0A
        andi r18,0b1000_0000
        breq again
        lds r19,UDR0
        sts UDR0,r19
        jmp again

 

;  ISR

EXT_INT0:
EXT_INT1:
PCINT0L:
PCINT1L:
PCINT2L:
WDT:
TIM2_COMPA:
TIM2_COMPB:
TIM2_OVF:
TIM1_CAPT:
TIM1_COMPA:
TIM1_COMPB:
TIM1_OVF:
TIM0_COMPA:
TIM0_COMPB:
TIM0_OVF:
SPI_STC:
USART_RXC:
USART_UDRE:
USART_TXC:
ADCR:
EE_RDY:
ANA_COMP:
TWI:
SPM_RDY:
    reti

;

 

The version ported to the Mega2560 works at 76800.  I think the problem may be related to the Mega16U2 code.   Both Chinese boards use the CH340.

 

Avrdude seems to write to the Mega2560 at 115200.

 

If all you want to do is interface to a terminal program using a lower baud rate: 38400, 76800, both have a lower error rate (see the datasheet).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

keith v wrote:

I don't agree that holding the key down is 'near realtime' it's not even close.

 

there should be a key repeat of like 500ms between each key.

 

There's something else happening there.

Well, if the controller is sitting around 99% of the time (as with the code I posted) waiting for a key stroke, sees a key stroke, transfers it to the UDR Xmit register, and is back waiting for the next key stroke before the current UDR character is finished being sent, from the keyboard's perspective, that's as "Real Time" as it gets!  Your comparing a few dozen clock cycle at about 15nS each, as aposed to a 500mS repeate rate - nearly an eternity to the uC !

 

A second reason your statements are flawed is because, while the errors are best case 3.5% at Fosc = 16.000MHz & 115.2K BAUD are quite frequent.  But, if what you claim were true, increasing Fosc to 18.432MHz (even with a theoretical error of 0.0%)you would tend to think that the increase in Fosc would tend to make the issue worse, you think?

 

But, in fact, the errors that were generated when using Fosc = 16.000MHz totally disappear, when using Fosc = 18.432MHz.

 

keith v wrote:

It's important to buffer in and out of your micro, not enough people do that.

I'm talking about a circular buffer that the tx isr transmits out of and another that the rx ISR reads into.

Blocking serial IO will bring the house down. Serial is slowy McSlow.

I'm not going to argue with the concept of using a buffer, though, honestly, I've never used a buffer of more than 16 bytes in any of my control applications because pretty much all of the communications that would require any buffering were when sending repetitive data to a PC - keyboard data entry is simply not fast enough to cause UDR over run at even 2400 BAUD.  And, the fact is, EVERY PC communications package that I know of, uses some sort of buffer.

 

So then, you'll have to come up with a better reason as to why, when a uC repetitively sends a string of data to the PC at 115.2K BAUD when Fosc = 16.000MHz, there are frequent and random errors.  And yet, when Fosc is changed to 18.432MHz, the errors totally clear up.  The facts and simple logic says - EXCESSIVE BAUD RTE ERROR !!!  Nothing else...

 

By the way, I've done a fair amount of work using serial communications between a uC & PC with HyperTerminal & TerraTerm.  The results are always the same - 16.000MHz always generates spurious errors when Fosc is 16.000MHz, BAUD - 115.2K and there is high repetitive data being sent to a PC..  And where it really becomes pronounced is when you are doing direct VT100 cursor placement of the data to specific places on the terminal screen.

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

Last Edited: Thu. Jan 1, 2015 - 07:16 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is my code ported to the Arduino Mega2560.

 

Note it is running at 1,000,000 BAUD. 

 

ie. UBRR0 = 0.

 

/*
 * u2560.asm
 *
 *  Created: 12/31/2014 11:09:19 PM
 *   Author: john
 */ 

;
.cseg

.org 0x0000 ;Places the following code from address 0x0000
		jmp RESET		; Reset Handler
		jmp EXT_INT0	; IRQ0 Handler
		jmp EXT_INT1	; IRQ1 Handler
		jmp EXT_INT2	; IRQ2 Handler
		jmp EXT_INT3	; IRQ3 Handler
		jmp EXT_INT4	; IRQ4 Handler
		jmp EXT_INT5	; IRQ5 Handler
		jmp EXT_INT6	; IRQ6 Handler
		jmp EXT_INT7	; IRQ7 Handler
		jmp PCINT0L		; PCINT0 Handler
		jmp PCINT1L		; PCINT1 Handler
		jmp PCINT2L		; PCINT2 Handler
		jmp WDT			; Watchdog Timer Handler
		jmp TIM2_COMPA	; Timer2 Compare A Handler
		jmp TIM2_COMPB	; Timer2 Compare B Handler
		jmp TIM2_OVF	; Timer2 Overflow Handler
		jmp TIM1_CAPT	; Timer1 Capture Handler
		jmp TIM1_COMPA	; Timer1 Compare A Handler
		jmp TIM1_COMPB	; Timer1 Compare B Handler
		jmp TIM1_COMPC	; Timer1 Compare c Handler
		jmp TIM1_OVF	; Timer1 Overflow Handler
		jmp TIM0_COMPA	; Timer0 Compare A Handler
		jmp TIM0_COMPB	; Timer0 Compare B Handler
		jmp TIM0_OVF	; Timer0 Overflow Handler
		jmp SPI_STC		; SPI Transfer Complete Handler
		jmp USART0_RXC	; USART0, RX Complete Handler
		jmp USART0_UDRE ; USART0, UDR Empty Handler
		jmp USART0_TXC	; USART0, TX Complete Handler
		jmp ANA_COMP	; Analog Comparator Handler
		jmp ADCR		; ADC Conversion Complete Handler
		jmp EE_RDY		; EEPROM Ready Handler
		jmp TIM3_CAPT	; Timer3 Capture Handler
		jmp TIM3_COMPA	; Timer3 Compare A Handler
		jmp TIM3_COMPB	; Timer3 Compare B Handler
		jmp TIM3_COMPC	; Timer3 Compare c Handler
		jmp TIM3_OVF	; Timer3 Overflow Handler
		jmp USART1_RXC	; USART1, RX Complete Handler
		jmp USART1_UDRE ; USART1, UDR Empty Handler
		jmp USART1_TXC	; USART1, TX Complete Handler
		jmp TWI			; 2-wire Serial Interface Handler
		jmp SPM_RDY		; Store Program Memory Ready Handler
		jmp TIM4_CAPT	; Timer4 Capture Handler
		jmp TIM4_COMPA	; Timer4 Compare A Handler
		jmp TIM4_COMPB	; Timer4 Compare B Handler
		jmp TIM4_COMPC	; Timer4 Compare c Handler
		jmp TIM4_OVF	; Timer4 Overflow Handler
		jmp TIM5_CAPT	; Timer5 Capture Handler
		jmp TIM5_COMPA	; Timer5 Compare A Handler
		jmp TIM5_COMPB	; Timer5 Compare B Handler
		jmp TIM5_COMPC	; Timer5 Compare c Handler
		jmp TIM5_OVF	; Timer5 Overflow Handler
		jmp USART2_RXC	; USART2, RX Complete Handler
		jmp USART2_UDRE ; USART2, UDR Empty Handler
		jmp USART2_TXC	; USART2, TX Complete Handler
		jmp USART3_RXC	; USART3, RX Complete Handler
		jmp USART3_UDRE ; USART3, UDR Empty Handler
		jmp USART3_TXC	; USART3, TX Complete Handler
;
		nop

RESET:	ldi r16, high(RAMEND); Main program start
		out SPH,r16 ; Set Stack Pointer to top of RAM
		ldi r16, low(RAMEND)
		out SPL,r16
		cli ; disable interupts
								; Set baud rates
		ldi r16, 0     		; 1,000,000
		sts UBRR0L, r16			;connection to PC

		clr r16
		sts UBRR0H, r16			;high baud rate

		sts UCSR0A, r16			; set to zero to be sure


; Enable receiver and transmitter
		ldi r16,0b0001_1000   ; rx&tx to gps and enable interrupt rx
		sts UCSR0B,r16
; Set frame format: 8data, 1stop bit
		ldi r16, 0b0000_0110 ;
		sts UCSR0C,r16

; finished setup of USART
		;sei						;turn on global interrupts

again:
        lds r18, UCSR0A
		andi r18,0b1000_0000
		breq again
		lds r19,UDR0
		sts UDR0,r19
		rjmp again

;ISR

EXT_INT0:
EXT_INT1:
EXT_INT2:
EXT_INT3:
EXT_INT4:
EXT_INT5:
EXT_INT6:
EXT_INT7:
PCINT0L:
PCINT1L:
PCINT2L:
WDT:
TIM2_COMPA:
TIM2_COMPB:
TIM2_OVF:
TIM1_CAPT:
TIM1_COMPA:
TIM1_COMPB:
TIM1_COMPC:
TIM1_OVF:
TIM0_COMPA:
TIM0_COMPB:
TIM0_OVF:
SPI_STC:
USART0_RXC:

USART0_UDRE:

USART0_TXC:
ANA_COMP:
ADCR:
EE_RDY:
TIM3_CAPT:
TIM3_COMPA:
TIM3_COMPB:
TIM3_COMPC:
TIM3_OVF:
USART1_RXC:
USART1_UDRE:
USART1_TXC:
TWI:
SPM_RDY:
TIM4_CAPT:
TIM4_COMPA:
TIM4_COMPB:
TIM4_COMPC:
TIM4_OVF:
TIM5_CAPT:
TIM5_COMPA:
TIM5_COMPB:
TIM5_COMPC:
TIM5_OVF:
USART2_RXC:
USART2_UDRE:
USART2_TXC:
USART3_RXC:
USART3_UDRE:
USART3_TXC:
;
		

compiled for a ATMega2560 in Atmel Studio 6.2

 

Last Edited: Fri. Jan 2, 2015 - 04:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is an Arduino sketch that echos at 2,000,000 BAUD.

 

/*
 Serial test 
   Modified from the Mega multple serial test in the Arduino
   examples/communication

 Receives from the main serial port and echos.
 Receives from serial port 0, sends to the main serial (Serial 0).

 
 * Serial monitor open on Serial port 0:

 created 30 Dec. 2008
 modified 20 May 2012
 by Tom Igoe & Jed Roach
 modified 4 Jam 2014
 by John Stampfl
 This example code is in the public domain.

 */


void setup() {
  // initialize both serial ports:
  Serial.begin(2000000);
}

void loop() {
  // read from port 1, send to port 0:
  if (Serial.available()) {
    int inByte = Serial.read();
    Serial.write(inByte);
  }
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Other than you possibly got your code to actually work, your example really don't qualify for anything because, for an Fosc of 16.000MHz 1.0M BAUD IS 0.0% error according to the datasheet, as are the 0.5M BAUD and 150.0K BAUD rates.  So what, exactly, is your point?

 

Try that same set up, but at 115.2K BAUD.  Or better yet, try it at 230.0K BAUD.  Good luck with that...

 

The point here is that, n = [Fosc / (16 * BAUD) ] -1 doesn't always work because the equation produces answers with a fractional component that gets truncated because... integers do not have fractional parts.  Integers, by definition, are whole numbers.  The effect of truncation of mixed numbers (whole + fractional part) is that, the results of converting the float to integer ALWAYS rounds down of the answer, when, in fact, rounding up may be the better action because it may well produce an outcome, producing less error than rounding down.

 

So then, as I stated above, the examples you've provided speaks absolutely nothing to the issues associated with n = [Fosc / (16 * BAUD) ] -1 and the BAUD rate errors caused by the truncation of floating point fractional parts when converted to integers.

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Actually, I tested 76800, 115200,230400,250000, 500000,1000000,2000000.

 

Results using the Arduino sketch above.  All worked fine, that is the Arduino boards and the Chinese boards.

 

Results using the assembly code above:  the Chinese boards worked for all values.  The Arduino Mega2560 and UNO failed for 115200.

 

I took a look at the wiring code, it has a work around to the problem in the code of the ATMega16U2 & 8U2 used the the Arduino boards.

 

Thinking about the ASYNC in this case.  The only ASYNC is between two ATMEL processors, both running off 16MHz crystals.  It is USB to the PC.

 

 

Last Edited: Sun. Jan 4, 2015 - 12:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I connected an Adafruit FTDI Friend usb2serial to serial port 1 on my Arduino Mega2560.

 

Works for 115200 and 1,000,000.  In double speed mode works for 230.400 and 2,000,000.

 

Since 115,200 & 230,400 fail for Serial Port 0 using the ATMega16U2 ( and also on an Arduino Uno R3) but works for Serial Port1 using the FTDI Friend (and a VISduino UNO R3 and a Nano style board both with a CH340G usb2serial chip.  I suspect a problem in the software for the ATMega16U2.

 

A work around for 115,200, is to run at double speed.

 

/*
 * s12560.asm
 *
 *  Created: 1/6/2015 10:22:49 PM
 *   Author: john
 */ 


 /*
 * u2560.asm
 *
 *  Created: 12/31/2014 11:09:19 PM
 *   Author: john
 */ 

;
.cseg

.org 0x0000 ;Places the following code from address 0x0000
		jmp RESET		; Reset Handler
		jmp EXT_INT0	; IRQ0 Handler
		jmp EXT_INT1	; IRQ1 Handler
		jmp EXT_INT2	; IRQ2 Handler
		jmp EXT_INT3	; IRQ3 Handler
		jmp EXT_INT4	; IRQ4 Handler
		jmp EXT_INT5	; IRQ5 Handler
		jmp EXT_INT6	; IRQ6 Handler
		jmp EXT_INT7	; IRQ7 Handler
		jmp PCINT0L		; PCINT0 Handler
		jmp PCINT1L		; PCINT1 Handler
		jmp PCINT2L		; PCINT2 Handler
		jmp WDT			; Watchdog Timer Handler
		jmp TIM2_COMPA	; Timer2 Compare A Handler
		jmp TIM2_COMPB	; Timer2 Compare B Handler
		jmp TIM2_OVF	; Timer2 Overflow Handler
		jmp TIM1_CAPT	; Timer1 Capture Handler
		jmp TIM1_COMPA	; Timer1 Compare A Handler
		jmp TIM1_COMPB	; Timer1 Compare B Handler
		jmp TIM1_COMPC	; Timer1 Compare c Handler
		jmp TIM1_OVF	; Timer1 Overflow Handler
		jmp TIM0_COMPA	; Timer0 Compare A Handler
		jmp TIM0_COMPB	; Timer0 Compare B Handler
		jmp TIM0_OVF	; Timer0 Overflow Handler
		jmp SPI_STC		; SPI Transfer Complete Handler
		jmp USART0_RXC	; USART0, RX Complete Handler
		jmp USART0_UDRE ; USART0, UDR Empty Handler
		jmp USART0_TXC	; USART0, TX Complete Handler
		jmp ANA_COMP	; Analog Comparator Handler
		jmp ADCR		; ADC Conversion Complete Handler
		jmp EE_RDY		; EEPROM Ready Handler
		jmp TIM3_CAPT	; Timer3 Capture Handler
		jmp TIM3_COMPA	; Timer3 Compare A Handler
		jmp TIM3_COMPB	; Timer3 Compare B Handler
		jmp TIM3_COMPC	; Timer3 Compare c Handler
		jmp TIM3_OVF	; Timer3 Overflow Handler
		jmp USART1_RXC	; USART1, RX Complete Handler
		jmp USART1_UDRE ; USART1, UDR Empty Handler
		jmp USART1_TXC	; USART1, TX Complete Handler
		jmp TWI			; 2-wire Serial Interface Handler
		jmp SPM_RDY		; Store Program Memory Ready Handler
		jmp TIM4_CAPT	; Timer4 Capture Handler
		jmp TIM4_COMPA	; Timer4 Compare A Handler
		jmp TIM4_COMPB	; Timer4 Compare B Handler
		jmp TIM4_COMPC	; Timer4 Compare c Handler
		jmp TIM4_OVF	; Timer4 Overflow Handler
		jmp TIM5_CAPT	; Timer5 Capture Handler
		jmp TIM5_COMPA	; Timer5 Compare A Handler
		jmp TIM5_COMPB	; Timer5 Compare B Handler
		jmp TIM5_COMPC	; Timer5 Compare c Handler
		jmp TIM5_OVF	; Timer5 Overflow Handler
		jmp USART2_RXC	; USART2, RX Complete Handler
		jmp USART2_UDRE ; USART2, UDR Empty Handler
		jmp USART2_TXC	; USART2, TX Complete Handler
		jmp USART3_RXC	; USART3, RX Complete Handler
		jmp USART3_UDRE ; USART3, UDR Empty Handler
		jmp USART3_TXC	; USART3, TX Complete Handler
;
		nop

RESET:	ldi r16, high(RAMEND); Main program start
		out SPH,r16 ; Set Stack Pointer to top of RAM
		ldi r16, low(RAMEND)
		out SPL,r16
		cli ; disable interupts
								; Set baud rates
		ldi r16, 8   		    ; 8 = 115,200
		
		sts UBRR1L, r16			;connection to PC

		clr r16
		sts UBRR1H, r16			;high baud rate
		sts UCSR1A, r16			; 


; Enable receiver and transmitter
		ldi r16,0b0001_1000   ; rx&tx to gps and enable interrupt rx
		sts UCSR1B,r16
; Set frame format: 8data, 1stop bit
		ldi r16, 0b0000_0110 ;
		sts UCSR1C,r16

; finished setup of USART
		;sei						;turn on global interrupts

again:
        lds r18, UCSR1A
		andi r18,0b1000_0000
		breq again
		lds r19,UDR1
		sts UDR1,r19
		rjmp again

;ISR

EXT_INT0:
EXT_INT1:
EXT_INT2:
EXT_INT3:
EXT_INT4:
EXT_INT5:
EXT_INT6:
EXT_INT7:
PCINT0L:
PCINT1L:
PCINT2L:
WDT:
TIM2_COMPA:
TIM2_COMPB:
TIM2_OVF:
TIM1_CAPT:
TIM1_COMPA:
TIM1_COMPB:
TIM1_COMPC:
TIM1_OVF:
TIM0_COMPA:
TIM0_COMPB:
TIM0_OVF:
SPI_STC:
USART0_RXC:

USART0_UDRE:

USART0_TXC:
ANA_COMP:
ADCR:
EE_RDY:
TIM3_CAPT:
TIM3_COMPA:
TIM3_COMPB:
TIM3_COMPC:
TIM3_OVF:
USART1_RXC:
USART1_UDRE:
USART1_TXC:
TWI:
SPM_RDY:
TIM4_CAPT:
TIM4_COMPA:
TIM4_COMPB:
TIM4_COMPC:
TIM4_OVF:
TIM5_CAPT:
TIM5_COMPA:
TIM5_COMPB:
TIM5_COMPC:
TIM5_OVF:
USART2_RXC:
USART2_UDRE:
USART2_TXC:
USART3_RXC:
USART3_UDRE:
USART3_TXC:
;
		

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I posted:

 

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

Fails for 115200,  returns 7 instead of 8

This fixed the tutorial code for my VISduino UNO R3 which uses a CH340G usb2serial chip for 115200 or 230400 in double speed mode.

 

Turns out that the tutorial fails on boards using the ATMega16U2 as the usb2serial chip.

 

In the previous post I connected an Adafruit FTDI Friend usb2serial to USART1 on an Arduino Mega2560 which works  at 115200

 

Now I report that I connect the FTDI Friend to USART0 on an Arduino UNO R3 which works at 115200.  Note that I loaded the code to the Arduino via the ATMega16U2 and when testing the code, it fails at 115200 when using the ATMega16U2.

 

Between the tests on the Arduino UNO R3 at 115200, I did not reload the code.  Just changed the connections.

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As we know,usart1 just has putchar1() function .i need to send enter order by usart so i need send ascii code of enter(that is 13) 

i want to know how should i send ascii code by putchar function?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ghazal.a wrote:
usart1 just has putchar1() function

A USART is just part of the hardware - it doesn't have any software inherent to it.

 

i need send ascii code of enter(that is 13) 

i want to know how should i send ascii code by putchar function?

Err ... 

putchar( 13 );

or

putchar( 0x0D );

or

putchar( '\r' );

etc, ... 

 

This is standard 'C' - not specific to AVR

 

http://www.avrfreaks.net/comment...

Pages