RS485 communication not supported using FTDI cable - c

I'm trying to port a program, which communicates over RS485 half-duplex UART, to Raspberry Pi. Since Pi's built-in UARTs don't support the RS485 standard, I'm using the USB-RS485-WE-1800-BT FTDI cable.
When connected, I can confirm that the cable's FTDI chip shows up in dmesg, the ftdi_sio driver is loaded, and properly exposes the /dev/ttyUSB0 serial terminal to the rest of the system. However, when I attempt to enable RS485 mode from a simple C program:
struct serial_rs485 config = {
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND,
.delay_rts_before_send = 0,
.delay_rts_after_send = 0
};
if (ioctl(fd, TIOCSRS485, &config) < 0) {
fprintf(stderr, "ioctl failed (%d): %s\n", errno, strerror(errno));
exit(0);
}
... I get the following error:
ioctl failed (25): Inappropriate ioctl for device
Looking into a schematic, I realized that the FTDI cable internally uses 2 components:
the FT232R chip, which is controlled by the ftdi_sio driver over USB and produces conventional serial output, and
the ZT485EEN chip, which transforms conventional serial comms to RS485.
So, given that FT232R doesn't technically emit RS485, I understand why its driver complains when asked to enable RS485 mode. What it doesn't know, though, is that the second chip takes care of format conversion transparently.
Having researched this topic for a bit and read answers to a similar question, I'm now curious how to proceed. Should I change the request ID in my ioctl() call to something else than TIOCSRS485? Should I remove the ioctl() call entirely? And if I do that, how can RS485 flags and RTS delays be set? Finally, if this means that enabling RS485 mode is not required in this configuration, can the FTDI cable be bypassed entirely by using Raspberry Pi's built-in UARTs combined with a chip like ZT485EEN?

Should I change the request ID in my ioctl() call to something else than TIOCSRS485? Should I remove the ioctl() call entirely?
Removing the ioctl() would be the appropriate thing to do in this case, as the serial converter is handling it entirely for you. As far as you are concerned, it is just a serial port that you read and write to.
And if I do that, how can RS485 flags and RTS delays be set?
You can't set any flags or delay using the FTDI cable. However, since the data that comes out of the cable is already RS485, there's no need to set anything. As long as whatever it is you're talking to is half-duplex(it does not talk at the same time as you do), this isn't an issue, and you can use it just like an RS232 cable. This depends on your specific use-case though. I have never encountered the need to have an RTS delay.
Finally, if this means that enabling RS485 mode is not required in this configuration, can the FTDI cable be bypassed entirely by using Raspberry Pi's built-in UARTs combined with a chip like ZT485EEN?
Sure, you can do that. There are also many different models of RS485 transcievers that you could use; Electronics.SE would the the place to ask for more information on that. You may need to enable RS485 at that point with TIOCSRS485, but that's going to be driver-dependent. I don't know about the Pi, but at least on some Atmel chips that I have used before setting the RS485 mode sets a certain bit in the peripheral on the chip that automatically toggles the RTS pin to enable/disable the RS485 transciever; otherwise, Linux needs to toggle a GPIO in order to set the transciever into the correct state.
Specifically on the FTDI, there are GPIOs that can be set that will turn on/off at appropriate times. One of these is the TXDEN signal, which controls the transciever for you automatically. Others are used for the Tx/Rx LEDs.

There’s no “rs485” mode. Just forget about it and everything will be OK. RS485 is just an electrical standard, and the ZT485 does the electrical translation from logic levels to differential signaling and back. You could use that chip (or any equivalent) directly with the UART pins on the Raspberry PI: those are not RS232 nor RS485, just bare asynchronous logic level UART pins. Your assertion that Raspberry PI “doesn’t support” RS485 is meaningless: it doesn’t support RS232 either, and it’s not supposed to. Those electrical standards require level translation/interface chips, and the “other side” is always the same: logic level asynchronous serial streams and control lines. The only “pitfall” is choosing the proper logic levels (3.3V be 5V - I don’t offhand remember what does RPI support).

Related

Raspberry Pi - UART - disable TX and enable RX in program C

I need connect my raspberry pi 4 model b with a servo via UART, but it is possible only via 1 wire. That means I must connect pin TX and RX together. In order to do so, I must have a way how to manually disable only TX or RX in my C program.
I am able to easily disable RX thanks to termios.h library, but I didn't find any way how to disable TX.
I was trying to disable it through this
tcflow(fd_myUART, TCOOFF); // it should suspend output
But that didn't work, so I thought that maybe if I change the pin of TX to INPUT, it will change the pin from UART to GPIO, but that didn't work either.
Do you have a way, how to do that, please?
First of all, just "randomly" connecting both wires is a bad idea.
Below image shows how to do it better for a prototype.
Slave devices are able to pull the IO line low during a read bit or a reset while the TX signal is high.
When used in this configuration, you should not disable RX nor TX. You can use "normal" UART operation.
More information can be found here (maxim integrated tutorial 214 "USING A UART TO IMPLEMENT A 1-WIRE BUS MASTER")
Since you will have a lot of connected slave, you should consider using a dedicated chip:
I use a DS2482S-100 over I2C.

STM32 I2C set SDA to low

Is there any way to set the SDA and SCL pin of the I2C1 connection of the STM32 to low or high signal?
I use a security chip and I have to send a wake condition, with the following condition:
if SDA is held low for a period of greater than 60us, the device will exit low power mode and
after a delay of 1500us, it will be ready to receive I2C commands.
I've already tried to toggle the actual pin with HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_9);, but this isn't working.
I've configured my project with STM32CubeMX.
Thanks for your help.
In I2C, the START condition requires a High to Low transition, if you then send a dummy address 0, a NACK will be generated (or rather the lack of any response will be interpreted as a NACK). In a normal transaction, the software would respond to the NACK by generating a repeated START or a STOP condition, however this must be done in software, so all you have to do is nothing for 1.5ms. Thereafter you can generate the START with the device's actual address, and if the device is running it will generate an ACK.
I am not familiar with the HAL library driver, and frankly the documentation is abysmal, but it is possible that it does not give you the necessary control, and you will have to access the I2C peripheral at the register level for at least this procedure. You might try a zero-length I2C_MasterRequestWrite() call to address zero followed by a delay. An oscilloscope would be useful here to ensure the expected signal timing is being generated.
When you initialize I2C, GPIO pins mode is set to ALTERNATE MODE,so writing HAL commands won't work on it.
Using normal HAL libraries won't help you in this. You have to configure I2C protocol on your own using stm32 registers.
I recommend that the ownaddress of the slave address using the device of the using I2C channel sets like the below code.
I2C_InitStructure.I2C_OwnAddress1 = 0x30; // the unique slave address of the deviecs
because the master could be send the broadcast operation not the unique operation.

Changing hardware flow control pins on STM32

I have been reading up on handshaking and hardware flow control for serial communication and I have a question that I can't seem to find an answer to.
If you set up hardware flow control for a serial port on cubeMX it will set the pins up that are required. I know you can use alternative pins as well and this can be done through cubeMX.
My question is, could you set up hardware flow control manually by using different pins or do you strictly have to use the implemented pins?
I am using a STM32F207ZETx and I am using USB as well as serial - however when using the USB peripheral it blocks the hardware flow control pins for USART1 which I need, and I need hardware flow control for my project! The alternate pins for hardware flow control are also already used so I'm in a bit of a pickle.
My question is, could you set up hardware flow control manually by using different pins or do you strictly have to use the implemented pins?
You can do hardware flow control yourself in software, and in fact it is quite simple to do.
The USART1_RTS is an output pin. It is set/high when the USART1 is ready to receive data. The USART1_CTS is an input pin. The other end sets it high when it is ready to receive data, and low when it is not.
Let's say that you send and receive one character at a time, and use two GPIO pins for USART1_RTS and USART1_CTS instead of the hardware support.
Normally, you keep USART1_RTS high. When receiving data, if you are running out of receive buffer, you set USART1_RTS low. When you make more room in the receive buffer, you set USART1_RTS high. (If you have a buffering scheme that cannot run out of receive buffer, you can tie the RTS line high.)
Before sending each character, you check if USART1_CTS is high. If it is low, you don't send the data, but wait for USART1_CTS to become high before you do.
That's it.

RS232 Serial Pin Read in C in Linux

Ist there any possibility to read values from the pins of the COM Port? Any solution in C under Linux is appreciated!
Yes, see for instance this guide.
You use the ioctl() function, to read the various control pins. Data is, of course, best read through the normal read() handling, you don't want to be polling asynchronuous serial data.
I don't think your assumption (expressed in a comment) that the driver must check the pin-states to handle data is correct, normally a serial port is "backed" by an UART and that typically handles the RX/TX pins in hardware.
Am pretty sure , you can't read/write pins of UART.
Even at the hardware level , you have to read/write an entire byte.There is no bit access or read/write pin access.
The Byte is read/written in the Receive/Transmit UART buffer .
In either ways you can't just access the buffer directly , on your behalf the linux driver will do the job. You just have to make use of the driver in your application , to work with the UART , the linux driver for UART provides , standard API's like open(),read(),write(),ioctl() through which you interact the UART device.
If you want to work with drivers , and new to this field , the best place to start will be
this book.
The exact answer to this question depends on the precise hardware in question. I know of a piece of code where I worked, based on receiving the letter 'a' as the indication of bitrate, and it would poll the RX pin to detect the transitions between 0 and 1 to detect the "width" of the bits, and it would then calculate the correct clock-rate for the serial port and configure the serial port to match the bitrate of the other end.
A "PC" type hardware solution will not be able to read the RX/TX pins. In other hardware, it may be possible to do so. Many embedded systems allow various pins to be configured as inputs, outputs or "have a function" (in our case, RX, TX, CTS, RTS, etc) - so for example, you could configure the RX pin to be a input, and thus read the state of it. Of course, the normal serial port drivers will probably set these pins to "have a function" [or expect the boot code running before the kernel is started to have configure it this way]. So you would have to reconfigure the pins in some kernel code of your own, most likely. Beware that this may cause unexpected side-effects with the driver for the actual serial port - it may "get upset" when it tries to do things to the serial port and it's "not working as expected" because it's been "misconfigured".
You can almost certainly read (and/or write) the state of the control pins, such as CTS, RTS via IOCTL calls.

Steps to make a LED on or off from a C program using Serial Port?

I knew there is a similar post:
Steps to make a LED blink from a C/C++ program?
But now I am working on a arm-based development board, and it seems to have two serial ports that I could use it to make a LED on or off.
Basically I think the flow is , make one pin in serial "1" or on and the LED will be turned on and "0" to make it off.
Is there some reference code in C-language I could refers?
Generally speaking, the board should come with some Board Support Package (BSP) which lets you control the built in I/O. Look for a serial library if you really want to use the Hardware flow control signals.
I'd recommend looking for some GPIO (General Purpose I/O, or digial I/O) on the board, which typically lets you configure it as an input or an output. You should be able to connect the LED via a current limiting resister between a digital I/O line and a ground pin. Make sure you have the LED oriented correctly if you connect it backwards it will block the current instead lighting. And as always make sure you check it out with a digital voltage meter before connecting it.
Even if you don't have a BSP for digital I/O the configuration is usually pretty simple.
Set a bit in a register to enable it, set bit in another register to select input or output they will normally be arranged in 8-bit "ports." Some systems allow you configure individual I/O pins, other will only allow you to configure the whole port for input or output. Then you just write a 1 or 0 to the bit you want to control in an write/output register.
ARM chips typically have a considerable amount of built in peripherals today, so most boards will just be bringing the I/O out to physical connectors on the board and you may need to read the chip vender's documentation to find the register memory map. Better board venders will supply documentation, a library (BSP) and examples. Luminary Micro even supplies chips with built in ethernet MACs and PHYs, just add a connector and Magnetics and you have a 1 chip Webserver.
This will, I'm afraid, be heavily dependent on the specifications of the particular arm-based development board you are using.
You need to find documentation specific to that board.
I used to do this kind of programming before.
You need to study the serial port connection
http://www.lammertbies.nl/comm/cable/RS-232.html
http://www.beyondlogic.org/serial/serial.htm
It has +5v, -5v on the output, I can't remember clearly now. Not every pin is needed.
I never use ARM before, but I use a 8-bit PIC controller to program it. I guess you can find a lot of example online.
The preferred alternative for controlling a GPIO is via a BSP. Because this BSP (board support package) does all the work for you in setting all peripherals to good defaults and and allowing you to call a function. Possibly your BSP of choice will have a function to write a byte to an 8-bit GPIO port; your LED will only have one bit. In this case your C code could look like: (at least: it will work like this on Luminary Micro kits). (Example code; requires a bit of extra work to make it compile especially on your kit).
/* each LED is addressed by an address (byte) and a bit-within-this-byte */
struct {
address, // address of IO register for LED port
bit // bit of LED
} LEDConfigPair;
struct LEDConfigPair LEDConfig[NUMBER_OF_LEDS] = {
{GPIO_PORTB_BASE,0}, // LED_0 is at port B0
{GPIO_PORTB_BASE,1} // LED_1 is at port B1
} ;
/* function LED_init configures the GPIOs where LEDs are connected as output */
led_init(void)
{
U32 i;
for(i=0;i<NUMBER_OF_LEDS;i++)
{
GPIODirModeSet( LEDConfig[i][0], LEDConfig[i][1], GPIO_DIR_MODE_OUT );
}
}
/* my LED function
set_led_state makes use of the BSP of Luminary Micro to access a GPIO function
Implementation: this BSP requires setting 8 port wide IO, so the function will calculate a mask (
*/
set_led_state(U8 led,bool state)
{
U8 andmask;
U8 setmask;
andmask = ~(1 << LEDConfig[led].bit);// a bitmask with all 1's except bit of LED
if (true == state)
{
setmask = (1 << LEDConfig[led].bit); // set bit for LED
} else
{
setmask = 0;
}
GPIOPinWrite(LEDConfig[led].address, andmask, setmask);
}
Of course this is all spelled out; it can be done in a single lines like this:
#DEFINE SETLEDSTATE(led,state) GPIOPinWrite(LEDConfig[led].address, ~(1<<LEDConfig[led].bit),(state<<LEDConfig[led].bit))
this will do the same, but only makes sense when you can dream bit masks, and you only want to toggle some LEDs to debug the real program...
The alternative: bare metal.
In this case you need to set up everything for yourself. For an embedded system, you need to be aware of pin multiplexing and power management (assuming memory controller and cpu clocks are already set up!)
initialization: set pin multiplexing in such a way that the function you want to control is actually mapped on the package.
initialization of pheripheral (in this case either a UART, or a GPIO function on the same pin)
You can't do it using Rx or Tx pins of Serial port. For that you just need to control the RTS or CTS pins of serial port.
Just google for "access COM port in VC++ code" and then control the RTS and CTS status pins to turn ON and OFF any external device.

Resources