RT-Thread RTOS
An open source embedded real-time operating system
|
UART (Universal Asynchronous Receiver/Transmitter), as a kind of asynchronous serial communication protocol, the working principle is to transmit each character of the transmitted data one by one. It is the most frequently used data bus during application development.
The UART serial port is characterized by sequentially transmitting data one bit at a time. As long as two transmission lines can realize two-way communication, one line transmits data while the other receives data . There are several important functions for UART serial communication, namely baud rate, start bit, data bit, stop bit and parity bit. For two ports that use UART serial port communication, these functions must be matched, otherwise the communication can't be carried out normally. The data format of the UART serial port transmission is as shown below:
The application accesses the serial port hardware through the I/O device management interface provided by RT-Thread. The related interfaces are as follows:
Funtion | Description |
---|---|
rt_device_find() | find device |
rt_device_open() | open device |
rt_device_read() | read device |
rt_device_write() | write device |
rt_device_control() | control device |
rt_device_set_rx_indicate() | set receive callback function |
rt_device_set_tx_complete() | set send complete callback function |
rt_device_close() | close device |
The application obtains the device handle according to the uart device name, and then can operate the uart device.The device find function is shown below
Parameter | Description |
---|---|
name | device's name |
back | —— |
device handle | finding the corresponding device will return to the corresponding device handle |
RT_NULL | corresponding device object was not found |
Generally, the name of the uart device registered to the system is uart0, uart1, etc. samples are as follows:
Through the device handle, the application can open and close the device. When the device is opened, it will detect whether the device has been initialized. If it is not initialized, it will call the initialization interface to initialize the device by default. Open the device through the following functions:
Parameter | Description |
---|---|
dev | device handle |
oflags | device mode flags |
back | —— |
RT_EOK | device opened successfully |
-RT_EBUSY | If the standalone parameter RT_DEVICE_FLAG_STANDALONE is included in the functions specified when the device is registered, the device will not be allowed to be opened repeatedly |
Other error codes | device failed to open |
oflags parameters support the following values (Use OR logic to support multiple values):
There are three modes of uart data receiving and sending: interrupt mode, polling mode and DMA mode. When used, only one of the three modes can be selected. If the open parameter oflag of the serial port does not specify the use of interrupt mode or DMA mode, the polling mode is used by default.
The DMA (Direct Memory Access) transfer mode does not require the CPU to directly control the transfer, and does not have the process of reserving the scene and restoring the scene as they have in the interrupt processing mode. The DMA controller opens a path for directly transferring data to the RAM and the I/O device, which saves CPU resources to do other things. Using DMA transfer can continuously acquire or send a piece of information without taking up interrupts or delays, which is useful when communication is frequent or when large pieces of information are to be transmitted.
>RT_DEVICE_FLAG_STREAM: Stream mode is used to output a string to the serial terminal: when the output character is "\n"
(corresponding to the hexadecimal value 0x0A), a `\r"
is automatically output in front (corresponding to hexadecimal value is 0x0D).
The stream mode RT_DEVICE_FLAG_STREAM
can be used with the receive and send mode parameter with the "|" logic.
An example of using a uart device in interrupt receive mode and polling mode as follows:
If the uart is to use the DMA receive mode, the oflags takes the value RT_DEVICE_FLAG_DMA_RX. An example of using a uart device in the DMA receive and polling send mode is as follows:
Through command control word, the application can configure the uart device by the following function:
Parameter | Description |
---|---|
dev | device handle |
cmd | command control word can be valued as:RT_DEVICE_CTRL_CONFIG |
arg | controlled parameter: struct serial_configure |
Back | —— |
RT_EOK | function executed successfully |
-RT_ENOSYS | execution failed, dev is empty |
Other error codes | execution failed |
The configuration parameters provided by RT-Thread can be defined as the following macro definitions::
Receive Buffer
When the uart device is opened using interrupt receive mode, the uart driver framework will open a buffer according to the size of RT_SERIAL_RB_BUFSZ to save the received data. When the underlying driver receives a data, it will put the data into the buffer in the interrupt service program.
>The default size of the receive data buffer is 64 bytes. If the number of received data in one-time is too large and the data is not read in time, the data of the buffer will be overwritten by the newly received data, resulting in data loss. It is recommended to increase the buffer.
A sample for configuring uart hardware parameters such as data bits, check bits, stop bits, and so on are shown below:
To write data to the serial port, the following functions can be used:
Parameter | Description |
---|---|
dev | device handle |
pos | Write data offset, this parameter is not used in uart device |
buffer | Memory buffer pointer, place the data to be written |
size | The size of the written data |
back | —— |
The actual size of the written data | If it is a character device, the return size is in bytes; |
0 | It needs to read the current thread's errno to determine the error status |
Calling this function will write the data in the buffer
to the dev
device, the size of the write data is: size.
The sample program for writing data to the serial port is as follows:
When the application calls rt_device_write()
to write data, if the underlying hardware can support automatic transmission, the upper application can set a callback function. This callback function is called after the underlying hardware data has been sent (for example, when the DMA transfer is complete or the FIFO has been written to complete the completion interrupt). You can set the device to send completion instructions by the following function:
Parameter | Description |
---|---|
dev | device handle |
tx_done | callback function pointer |
back | —— |
RT_EOK | set up successfully |
When this function is called, the callback function is provided by the user. When the hardware device sends the data, the device driver calls back this function and passes the sent data block address buffer as a parameter to the upper application. When the application (thread) receives the indication, it will release the buffer memory block or use it as the buffer for the next write data according to the condition of sending the buffer.
The data receiving instruction can be set by the following function. When the serial port receives the data, it will inform the upper application thread that the data has arrived:
Parameter | Description |
---|---|
dev | device handle |
rx_ind | callback function pointer |
dev | device handle (callback function parameter) |
size | buffer data size (callback function parameter) |
back | —— |
RT_EOK | set up successfully |
The callback function for this function is provided by the user. If the uart device is opened in interrupt receive mode, the callback function will be called when the serial port receives a data, and the data size of the buffer will be placed in the size
parameter, and the uart device handle will be placed in the dev
parameter.
If the uart is opened in DMA receive mode, the callback function is called when the DMA completes receiving a batch of data.
Normally the receiving callback function can send a semaphore or event to notify the serial port data processing thread that data has arrived. The example is as follows:
You can call the following function to read the data received by the uart:
Parameter | Description |
---|---|
dev | device handle |
pos | Read data offset, uart device dose not use this parameter |
buffer | Buffer pointer, the data read will be saved in the buffer |
size | Read the size of the data |
back | —— |
Read the actual size of the data | If it is a character device, the return size is in bytes. |
0 | It needs to read the current thread's errno to determine the error status |
Read data offset: pos is not valid for character devices. This parameter is mainly used for block devices.
An example of using the interrupt receive mode with the receive callback function is as follows:
After the application completes the serial port operation, the uart device can be closed by the following functions:
Parameter | Description |
---|---|
dev | device handle |
back | —— |
RT_EOK | device closed successfully |
-RT_ERROR | The device has been completely shut down and cannot be shut down repeatedly |
other error codes | fail to close the device |
Use the rt_device_close()
interface and rt_device_open()
interface in pair. When you open the device, you need to close the device once, so that the device will be completely shut down, otherwise the device will remain open.
The main steps of the sample code are as follows:
The running sequence diagram is shown as follows:
When the serial port receives a batch of data, it will call the receive callback function. The receive callback function will send the data size of the buffer at this time to the waiting data processing thread through the message queue. After the thread gets the message, it is activated and reads the data. In general, the DMA receive mode completes data reception in conjunction with the DMA receive completion interrupt and the serial port idle interrupt.
The running sequence diagram is shown below: