How to setup and use RS-232 interface on SP7021 BPi-F2P board of Banana Pi
The goal of the document is to illustrate how to setup and use RS-232 interface of BPi-F2P board of Banana Pi. BPi-F2P board of Banana Pi is based on Sunplus SP7021 SoC and is designed for industrial control. Refer to picture below, SP7021 is covered under black heat-sink.
BPi-F2P board has one channel of RS-232 interface which is connected to a DB-9 connector (on the most left side).
1. Schematics
Refer to schematic of RS-232 of BPi-F2P board below, signal SOC-UART-RX-3 is connected to GPIO_P5_2 (G_MX[42]) of SP7021. Signal SOC-UART-TX-3 is connected to GPIO_P5_5 (G_MX[45]) of SP7021. Signal SOC-UART-CTS-3 is connected to GPIO_P6_5 (G_MX[53]) of SP7021. Signal SOC-UART-RTS-3 is connected to GPIO_P4_0 (G_MX[32]) of SP7021. U13 and U15 are dual-channel digital isolator from Novosense Microelectronics. One channel for input and the other for output. They are added for electric isolation between internal digital circuits and output drivers. U14 is a multi-channel line-drivers and receivers of RS-232 from Texas Instruments. It converts 0V/5V-level signals to RS-232 line-signal (+10V/-10V). RS-232 line signals are then connected to a DB-9 connector. U17 is an isolated DC-DC converter from MORNSUN Guangzhou Science & Technology. It is used to supply +5V power (VDD5V-ISO) of output drivers.
2. Modify device-tree source
From schematics, we list connections of all RS-232 signals in the following table:
Signals of RS-232 | Mux-Pins of SP7021 |
|---|---|
SOC-UART-TX-3 | 45 (GPIO_P5_5/G_MX[45]) |
SOC-UART-RX-3 | 42 (GPIO_P5_2/G_MX[42]) |
SOC-UART-RTS-3 | 32 (GPIO_P4_0/G_MX[32]) |
SOC-UART-CTS-3 | 53 (GPIO_P6_5/G_MX[53]) |
Modify device-tree node uart3 in device-tree source file linux/kernel/arch/arm/boot/dts/sp7021-bpi-f2p.dts to setup channel 3 of UART for RS-232 interface as shown below:
&uart3 {
pinctrl-names = "default";
pinctrl-0 = <&pins_uart3>;
status = "okay";
};Note that uart3 is a label to node serial@9c000880.
Also, modify dts node pinmux_uart3-pins to setup pins for channel 3 of UART as shown below:
pins_uart3: pinmux_uart3-pins {
sunplus,pins = <
SPPCTL_IOPAD(45, SPPCTL_PCTL_G_PMUX, MUXF_UA3_TX, 0)
SPPCTL_IOPAD(42, SPPCTL_PCTL_G_PMUX, MUXF_UA3_RX, 0)
SPPCTL_IOPAD(32, SPPCTL_PCTL_G_PMUX, MUXF_UA3_RTS, 0)
SPPCTL_IOPAD(53, SPPCTL_PCTL_G_PMUX, MUXF_UA3_CTS, 0)
>;
};Note that node pinmux_uart3-pins is sub-node of node pctl.
Please note that to comply with Linux rules, after version 5.10.59, 4 property-names of pin node of SP7021 are changed as shown in table below:
5.4.35 | 5.10.59 |
|---|---|
sppctl,function | function |
sppctl,groups | groups |
sppctl,pins | sunplus,pins |
sppctl,zero_func | sunplus,zerofunc |
3. Enable Linux UART drivers
By default, UART module is enabled. Refer to screenshot of “Linux kernel Configuration Menu”:
“Sunplus UART serial port support” is enabled.
4. Build Linux image
Go to top folder. Run make config to select to build image for “BPi-F2P Board”. After make config completes, run make all to build Linux image.
5. Boot Linux
Boot Linux with the built image.
6. Serial port setup, write and read
Use stty command to setup serial port. For example,
~ # stty -F /dev/ttyS3 115200 cs8 cstopb -parenbIt sets channel 3 of serial port (UART) to 115,200 Baud (bps), 8-bit data, 2-bit stop-bit, no parity.
Use echo command to transmit a character string to serial port. For example,
~ # echo 'A' > /dev/ttyS3Character ‘A', CR and LF will be transmitted. ASCII code of character 'A’ is 0x41. ASCII code of CR is 0x0D. ASCII code of LF is 0x0A. Refer to snapshot of oscilloscope which was captured when the command is run:
where C1 (yellow) is signal SOC-UART-TX-3, C2 (red) is signal SOC-UART-RTS-3, C3 (blue) is signal UART-232-TX-3, and C4 (green) is signal UART-232-RTS-3. Z1, Z2, Z3 and Z4 are zoom-in of C1, C2, C3 and C4, respectively.
Note that less significant bit (LSB) is sent first.
You can use command-line option -n to suppress CR and LF.
~ # echo -n 'ABC' > /dev/ttyS3Character ‘A', ‘B' and 'C’ will be transmitted. There is no CR and LF. Refer to snapshot of oscilloscope which was captured when the command is run:
where C1 (yellow) is signal SOC-UART-TX-3, C2 (red) is signal SOC-UART-RTS-3, C3 (blue) is signal UART-232-TX-3, and C4 (green) is signal UART-232-RTS-3. Z1, Z2, Z3 and Z4 are zoom-in of C1, C2, C3 and C4, respectively.
ASCII code 0x41, 0x42 and 0x43 are transmitted successively. LSB is sent first.
Use cat command to receive characters from serial port. For example,
~ # cat /dev/ttyS3
HELLO!
^C
~ #A character string ‘HELLO!’ is received. It is sent by (another BPi-F2P board):
~ # stty -F /dev/ttyS3 115200 cs8 cstopb -parenb
~ # echo ‘HELLO!’ > /dev/ttyS3Refer to snapshot of oscilloscope which was captured when the command is run:
where C1 (yellow) is signal UART-232-RX-3, C2 (red) is signal UART-232-CTS-3, C3 (blue) is signal SOC-UART-RX-3, and C4 (green) is signal SOC-UART-CTS-3. Z1, Z2, Z3 and Z4 are zoom-in of C1, C2, C3 and C4, respectively.
ASCII code 0x48, 0x45, 0x4C, 0x4C, 0x4F, 0x21, 0x0D and 0x0A are received successively.
Refer to snapshot of oscilloscope which was captured while 'A', CR and LF are received:
where C1 (yellow) is signal UART-232-RX-3, C2 (red) is signal UART-232-CTS-3, C3 (blue) is signal SOC-UART-RX-3, and C4 (green) is signal SOC-UART-CTS-3. Z1, Z2, Z3 and Z4 are zoom-in of C1, C2, C3 and C4, respectively.
ASCII code 0x41, 0x0D and 0x0A are received successively.
7. An example application of serial port programming in C
A. Read a string from serial port
/*====================================================================================================*/
/* An Example of Serial Port Programming in C */
/* Non Cannonical mode */
/*----------------------------------------------------------------------------------------------------*/
/* Program reads a string from the serial port. */
/* Baudrate - 115,200 bps */
/* Stop bits - 2 bits */
/* Parity - none */
/*====================================================================================================*/
/*====================================================================================================*/
/* Sellecting the serial port number on Linux */
/* ---------------------------------------------------------------------------------------------------*/
/* /dev/ttySx - for hardware based serial ports (uart), where x can be 0, 1, 2, ... */
/* /dev/ttyUSBx - for USB to serial converter, where x can be 0, 1, 2, ... */
/*====================================================================================================*/
#include <stdio.h>
#include <fcntl.h> /* File Control Definitions */
#include <termios.h> /* POSIX Terminal Control Definitions */
#include <unistd.h> /* UNIX Standard Definitions */
#include <errno.h> /* ERROR Number Definitions */
void main(void)
{
int fd; /* File Descriptor*/
struct termios SerialPortSettings; /* Structure termios for setting serial ports */
char read_buffer[32]; /* Buffer to store the data received */
int bytes_read; /* Number of bytes to read */
int i; /* Index */
/*------------------------------- Open the serial port ----------------------------------*/
fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY); /* ttyS1 is channel 1 of serial (uart) */
if (fd == -1) /* Error Checking */
printf("\n Error happened while opening '/dev/ttyS1'!\n");
else
printf("\n '/dev/ttyS1' is opened successfully!\n");
/*---------- Setting the attributes of the serial port using termios structure --------- */
tcgetattr(fd, &SerialPortSettings); /* Get the current attributes of the serial port */
/* Setting the Baud rate */
cfsetispeed(&SerialPortSettings, B115200); /* Set read speed as 115,200 bps. */
cfsetospeed(&SerialPortSettings, B115200); /* Set write speed as 115,200 bps. */
/* 8N2 Mode */
SerialPortSettings.c_cflag &= ~PARENB; /* Disables the parity enable bit (PARENB). */
SerialPortSettings.c_cflag |= CSTOPB; /* CSTOPB = 2 Stop bits */
SerialPortSettings.c_cflag &= ~CSIZE; /* Clears the mask for setting the data size. */
SerialPortSettings.c_cflag |= CS8; /* Set the data bits to 8 bits. */
SerialPortSettings.c_cflag &= ~CRTSCTS; /* No hardware flow Control! */
SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Enable receiver, ignore modem control lines. */
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY); /* Disable XON/XOFF flow control both i/p and o/p */
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* Non Cannonical mode */
SerialPortSettings.c_oflag &= ~OPOST; /* No output processing! */
/* Setting Time outs */
SerialPortSettings.c_cc[VMIN] = 15; /* Read at least 15 characters. */
SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinetly. */
if ((tcsetattr(fd, TCSANOW, &SerialPortSettings)) != 0) /* Set the attributes to the termios structure. */
printf(" Error happened while setting attributes!\n");
else
printf(" BaudRate = 115,200 bps\n StopBits = 2\n Parity = none\n");
/*------------------------------- Read data from serial port -----------------------------*/
tcflush(fd, TCIFLUSH); /* Discards old data in the rx buffer. */
bytes_read = read(fd, &read_buffer, 32); /* Read the data. */
printf("\n Received bytes = %d\n", bytes_read);/* Print the number of bytes read. */
printf("\n");
for (i = 0; i < 15; i++) /* Print the received data. */
printf("%c", read_buffer[i]);
close(fd); /* Close the serial port. */
}
B. Write a string to serial port
Use write function to send data to serial port. For example,
int bytes_written; /* Number of bytes written */
char write_buffer[] = "Hello!\n"; /* A string to write */
bytes_written = write(fd, &write_buffer, sizeof(write_buffer));