USART and RS485 transceiver

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello guys.
I have problem like here.
https://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=70150&start=0.
Here is my unsuccessful attempt to resolve it

void Transmit_0_ON(void)
{
while (UCSR0A & _BV(RXC0));//While unread data in receive buffer (reading in ISR)
UCSR0B &= ~_BV(RXEN0); //Desable receiver
UCSR0B |= _BV(TXEN0); //Enable transmitter
UCSR0A |= _BV(TXC0); //Transmit complete
RE0_DE0_port |= _BV(RE0_DE0_pin); //RS485 TX ON
}

void USART0_transmit(unsigned char data)
{
while(!(UCSR0A & (1<<UDRE0))); //While buffer not empty
UCSR0A |= _BV(TXC0); //Must be cleared befor each transmission
UDR0=data;
}

void Receive_0_ON(void)
{
while(!(UCSR0A & _BV(TXC0))); //Wait for the transmission to complete 
while(!(UCSR0A & _BV(UDRE0))); //While buffer not empty
UCSR0B &= ~_BV(TXEN0); //Desable transmitter
UCSR0B |= _BV(RXEN0); //Enable receiver
RE0_DE0_port &= ~_BV(RE0_DE0_pin); //RS485 RX ON
}

unsigned char USART0_receive(void)
{
while (!(UCSR0A & (1<<RXC0))); //While buffer is empty
return UDR0;
}

This code on both sides.
It gives an frame errors on simple echo

Transmit_0_ON();
USART0_transmit('+');
USART0_transmit('E');
Receive_0_ON();
while (RX0_fifo_count < 0x02)
....

Receving in ISR(USART0_RX_vect).
Transmission - manual (I have to clear TXC0).
A bit of criticism shoud work, because I confused.

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

The thread you linked to says "16MHz crystal". Is that what you are using too? What have you done to verify the speed.

Also for switching of RS485 you want to check TXC not UDRE. (the former says when the very last bit has gone off down the line while the latter just says that the Tx buffer has a gap but nothing about the state of the current transmission).

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

I've not looked at your code in detail, just a couple of generic cautions...

1) You need to be careful to not disable the transceiver's transmit enable until the last character has totally finished (that is, its stop bit is fully out). That is, you should wait for TXC0 or UDR0 to go true. TXC0 may be the easier one to handle.

2) Frame error means that something was detected as a start bit, but no stop bit was ever detected. In a loopback test, this is likely due to mismanagement of either the TX enable of the transceiver or RX enable. I tend to leave the RX always enabled and use that to compare the received transmit against what you think was transmitted. If the two differ, it is usually because of a "collision" in which some other device was trying to transmit at the same time.

3) In trying to diagnose the framing error, I would also look at the "character" that was received. That should show you what is really happening.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

There is no need to disable/enable the AVR's TX and RX of the USART.

Generally, these functions are written interrupt-driven. The TXC routine determines if there are more characters to send, and if not then it flips the RS485 TE. (We tie TE to /RE in all of our designs. Others here "listen" to what they send and drive them separately.)

Example code:

// *****************************************************
// *****************************************************
char getchar1(void)
{
char data;

while (rx_ctr1==0);	// >>blocking getchar(); hangs here!!!

data=rx_buffer1[rx_rd_index1];
if (++rx_rd_index1 >= RX_BUFFER_SIZE1) rx_rd_index1=0;
//_CLI();
#asm("CLI");
--rx_ctr1;
//_SEI();
#asm("SEI");
return data;
}
// *****************************************************
// *****************************************************
// Write a character to the UART1 Transmitter buffer
void putchar1(char c)
{

while (tx_ctr1 >= TX_BUFFER_SIZE1)	// blocking putchar()
	{
	RS485_TE1();	// ensure that the MAX485 is transmit-enabled
	}

#asm("CLI");
if (tx_ctr1 || ((UCSR1A & DATA_REGISTER_EMPTY1)==0))
   {
   tx_buffer1[tx_wr_index1]=c;
   if (++tx_wr_index1 == TX_BUFFER_SIZE1) tx_wr_index1=0;
   ++tx_ctr1;
   }
else
	{
	RS485_TE1();	// flip the MAX485 to transmit-enabled
	UDR1=c;
	}
#asm("SEI");
}

// *****************************************************
// *****************************************************
// Write a flash string to the UART1 Transmitter buffer
void	putsf1			(char flash *s)
{
	while (*s)
  		{
		putchar1(*s++);
		}
}

// *****************************************************
// *****************************************************
// Write a string to the UART1 Transmitter buffer
void puts1(char *s)
{
	while (*s)
  		{
		putchar1(*s++);
		}
}


// *****************************************************
// *****************************************************
// UART1 Transmitter interrupt service routine
interrupt [USART1_TXC] void 	uart1_tx_isr			(void)
{

if (tx_ctr1)
   {
   RS485_TE1();	// ensure that the MAX485 is transmit-enabled
   --tx_ctr1;

   UDR1=tx_buffer1[tx_rd_index1];
   if (++tx_rd_index1 >= TX_BUFFER_SIZE1) tx_rd_index1=0;
   }
else
	{
	RS485_RE1();	// switch the MAX485 to receive mode
	}

}

// *****************************************************
// *****************************************************
// UART1 Receiver interrupt service routine
interrupt [USART1_RXC] void 	uart1_rx_isr			(void)
{
char status,data;
status=UCSR1A;
data=UDR1;

if ((status & (FRAMING_ERROR1 | DATA_OVERRUN1))==0)
   {
   rx_buffer1[rx_wr_index1]=data;
   if (data==RX_TERM1) rx_msg1++;
   if (++rx_wr_index1 >= RX_BUFFER_SIZE1) rx_wr_index1=0;
   if (++rx_ctr1 >= RX_BUFFER_SIZE1)
      {
      rx_ctr1=RX_BUFFER_SIZE1;
      rx_ovf1=1;
      }
   }
}


You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Clock Frequency - 8 MHz, 9600 bps.
Everything work proper in conjunction USART-USART with simple

void USART0_transmit(unsigned char data)
{
   while(!(UCSR0A & (1<<UDRE0)));
   UDR0=data;
}
unsigned char USART0_receive(void)
{
   while (!(UCSR0A & (1<<RXC0)));
   return UDR0;
}

ISR(USART0_RX_vect)
{
   serial_addtorxfifo0();
}

My transmitter are not the interrupt driven, I have a lot of time. Thanks for the code above.

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

I still can not understand.
I went through all the possible options for checking the input and output buffers (TXC0, UDRE0, RXC0).
The thing is right after I switching RS485 tranceiver to the receive mode, my ISR(USART0_RX_vect) gone crazy and gives me a bunch of garbage even when there is no active transmitters on other side. I removed all unnecessary code and even tried to use the pullup resistor to V+ for RX - the same.
Atmega324pa + ADM4850.
Proteus with MAX487 repeats the same mistake?

Last Edited: Tue. Feb 14, 2012 - 10:23 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You need a resistor to Vcc on one side of the terminating resistor and a resistor to ground on the other side. You have a terminator (vicinity of 120 ohms)?

You only need one pull up and one pull down resistor, somewhere in the system. It is usually at the terminating resistor, but it does not have to be.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

I'm using true fail-safe receivers with 120 Ohm term.
I mean that when switching on the transmission, output RO of the RS485 transceiver is in a high impedance state, so you may want to use a pullup on RX controller pin. But steel, it dose note explane all time frame errors when RX active after first switching - when tere is no one to transmit.
Somehow RXC0 is allways set, I think.

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

Take out the termination and see what happens. Or add the bias resistors. I usually have leds on the rxd and txd for diagnostics. If there is a problem you can usually see it on the leds.

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

When there is no enabled transmitter on the line, the only thing that sets the voltage is leakage current and noise from the local environment. The receiver can indicate anything at any time.

In addition to the terminating resistor, you need TWO resistors, one to make one side of the line low and one to make the other side of the line high.

Here is how you figure out which resistor to connect to which line:

1) What is the "idle" state of a UART Tx output? If you check the UART section of any AVR spec sheet, you will find a part that discusses "frame format". Take a look at the drawing and you will see that the output is logic high when idle.

2) Which output of the transceiver does what? If you look at the spec sheet for your transceiver, you will find that it has two pins labeled "A" and "B". If you look at the logic table for the transmitter, you will find that, when the transmitter is enabled, A has the same logic state as the input and B has the complementary state.

3) When the transmitter is disabled, you want the line to be in the same logic state as when the transmitter is enabled and the UART is idle. Thus, you want to pull up the A line and pull down the B line. Connecting a resistor to only one line does not define the state for the other line.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

Quote:
In addition to the terminating resistor, you need TWO resistors, one to make one side of the line low and one to make the other side of the line high.


I beg to differ with this statement just a little.
I just finished a project using RS-485 and the two resistors mentioned are not used. Just the 120 ohm terminator resistors. YES the spec says they need to be there, but in practical use, I have only seen them used a small handfull of times. I myself don't use them just the termination resistors, and have not had any problems.

Should they be there? YES. MUST they be there is a choice by the designer

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

In RS-422 systems where a transmitter always controls the state of the line, said resistors are clearly not needed.

In RS-485 systems, it has been such a problem that IC manufacturers are now making RS-485 specific receivers with built-in offset so that 0V differential is always recognized as line-idle. With these receivers, no extra resistors are needed. With "classic" transceivers in true RS-485 systems, you are playing with fire if you assume that it will always work correctly without the resistors. This is due, in part, to the uncertainly in the receiver input offset voltage. For example, the widely used MAX485, if I read the specs correctly, can have an input offset anywhere between +200mV and -200mV. If it happens to be close to 0V, line noise gets converted into pseudo-data; input hysteresis is only 70mV. Most RS422/485 devices seem to have 70mV hysteresis, and this is probably what is saving things in average situations.

In the current thread, the OP states that there is garbage data as soon as the transmitter is disabled. The simple solution, in this case, is to add the two resistors. Do they "have to be there?" Not generally, but in this case, it appears that they do.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

Jim,

This statement in my last post:

Quote:
Should they be there? YES. MUST they be there is a choice by the designer

clearly states that I agree with you. I suppose I should have noted that if someone reading this thread sees the resistors missing not to get too excited, that's all.

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

Great.... We have agreed to agree.

I was concerned because it sounded like the OP added one resistor, and still had problems. To achieve this function, you need 2, not 1, in addition to the terminator.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

Hello all again. Thank you for your time.
The problem is solved! I researched whole board with oscilloscope and found defects that left after bad process of etching and a large number of leakages. Had to work with a scalpel :) There's more to say that there are couple crystals and analog circuits with amplifiers for strain sensors. A lot of noise. (The sum of all capacitors on board limited to 10uF). Also gone instability of the OPamp filters and finally MCP4012 work proper.
Apparently, a local manufacturer of boards treat to small orders disrespectful.