After hours of reading I understand I need to set pin to low/high when receiving or transmiting. So I need to set pins (basically one pin for both on RS485 component DE & !RE) to high/low. Those pin is in my case connected to RTSA pin of UART which should do this job automatically based on datasheet, do I need to enable somehow auto RTS? In datasheet it says:
This pin only affects the transmit and receive operations when Auto-RTS function is enabled via the Enhanced Features Register (EFR[6]) for hardware flow control operation.
Would be better in my case if I use some of free GPIO pins from UART and manually changing pin to low/high?
Correct.
I only skimmed the datasheet, but I'm not sure that the auto RTS feature is going to work. My basic understanding of RTS is that if there is data to be transmitted, then RTS is set, and cleared when the data has been sent. The datasheet talks about an interaction with the Rx buffer. I'm not sure why, unless it is referring to the remote device Rx buffer, but this isn't clear to me from the datasheet.
The chip has a manual RTS mode where you can control the RTS pin directly with a bit 1 of the Modem Control Register. This might be be better but you would then have to check the internal Tx FIFO buffer to see if it wad empty.
However, before trying the manual RTS approach, it would be worth checking via web searches to see if there is a clearer explanation of auto RTS for this device.
If you have any test gear, a logic analyser for example, then you could investigate yourself.
EDIT: A quick search suggests that auto RTS is the correct way to auto control the RS485 module. Maybe it's too early in the day, or it's a poor explanation in the datasheet...
How would I set manual RTS pin? There is option to upload sketch on receiver which would have LOW and on transmision which would have HIGH?
Now i'm on a bigger screen, I can see something else that may help you. According to the SC16IS752 datasheet I have, there's a section 9 called RS-485 features. And more specifically section 9.1 Auto RS-485 RTS control. It says:
Normally the RTS pin is controlled by MCR bit 1, or if hardware flow control is enabled, the
logic state of the RTS pin is controlled by the hardware flow control circuitry. EFCR
register bit 4 will take the precedence over the other two modes; once this bit is set, the
transmitter will control the state of the RTS pin. The transmitter automatically asserts the
RTS pin (logic 0) once the host writes data to the transmit FIFO, and de-asserts RTS pin
(logic 1) once the last bit of the data has been transmitted.
I've highlighted in bold the useful bit. So, it seems that all you need to do is set bit 4 in the Extra Features Control Register and the UART should take care of controlling the RE & DE pins using its RTS signal.
I think you would also need to set bit 5 in the EFCR as well as that inverts the RTS pin - you need RTS to be a 1 when transmitting so that the SN65HVD762 line driver/receiver goes into transmit mode.
I'm already using this driver: SC16IS752/SC16IS752.cpp at master · nopnop2002/SC16IS752 · GitHub
For example there is code:
void SC16IS752::FIFOSetTriggerLevel(uint8_t channel, uint8_t rx_fifo, uint8_t length)
{
uint8_t temp_reg;
temp_reg = ReadRegister(channel, SC16IS750_REG_MCR);
temp_reg |= 0x04;
WriteRegister(channel, SC16IS750_REG_MCR,temp_reg); //SET MCR[2] to '1' to use TLR register or trigger level control in FCR register
temp_reg = ReadRegister(channel, SC16IS750_REG_EFR);
WriteRegister(channel, SC16IS750_REG_EFR, temp_reg|0x10); //set ERF[4] to '1' to use the enhanced features
if (rx_fifo == 0) {
WriteRegister(channel, SC16IS750_REG_TLR, length<<4); //Tx FIFO trigger level setting
} else {
WriteRegister(channel, SC16IS750_REG_TLR, length); //Rx FIFO Trigger level setting
}
WriteRegister(channel, SC16IS750_REG_EFR, temp_reg); //restore EFR register
return;
}
A lot of functions aren't used here or never called, don't know why, havent found any other driver which would have implemented those functions. From my understanding I just have to somewhere in driver use something like that but with right registers:
temp_reg = ReadRegister(channel, SC16IS750_REG_MCR);
temp_reg |= 0x04;
WriteRegister(channel, SC16IS750_REG_MCR,temp_reg); //SET MCR[2] to '1' to use TLR register or trigger level control in FCR register
Also another question, when from device A for example data is sent to device B, what would be voltage on RTS pin on UART? If I understand it right device A as transmiter should have on RTS 3,3V and device B as receiver should have RTS voltage 0, also on device A on RS485 should be on TX pin voltage 3,3V on RX 0 and on device B should be voltage on TX pin 0 and RX pin 3,3V. Is this correct? If this is right than will be easier for me to debuging it because currently is really hard as I have two same devices with same drivers and I don't know if it works right. I could use RS485 on PC and send data to one of my devices and try to write right driver firstly for receiver and than combine with transmiter.
It looks like that library doesn't expose any RS485 specific functions, and the only place in the code that I could see a reference to the EFCR was 3 occurrences in the function FIFOSetTriggerLevel() that you showed above.
I think that you might need to change:
WriteRegister(channel, SC16IS750_REG_EFR, temp_reg|0x10);
to
WriteRegister(channel, SC16IS750_REG_EFR, temp_reg|0x30);
As that will invert the RTS signal so that it is a '1' during transmission which should put the line driver into Tx mode.
If there is no active transmission, then both RTS signals should be 0v. RTS should only go to 3v3 when actually transmitting bytes.
I would have thought that the 'idle' voltage of the Tx pin would be 3v3 (i.e. a '1') as a normal UART serial Tx line goes from '1' to a '0' to indicate the start bit. With no activity, both your Tx pins should be at 3v3.
And, I would have thought that the Rx pins would also be at 3v3 when there is no activity as they would be driven by the RO signal from the SN65HVD72.
If you have an RS485 adapter for your PC, then that makes things a whole lot easier as you would have a known working setup. I would use a terminal program on your PC to listen to the RS485 bus and create a simple sketch that tried to send a single character once a second or so. Transmission is easier than reception as in theory you just write to the Tx FIFO on the chip and let it get on with the transmission.