This article is published by RT-Thread account 123: https://club.rt-thread.org/as…

RTT Serial Port V1 Usage Analysis and Troubleshooting Guide (2)

Troubleshooting of serial port problems

Undertake the use analysis of RTT serial port V1 and troubleshooting guide (1) article.

Based on the feedback about serial port usage, this section analyzes problems related to the serial port of the FinSH component and problems related to the use of serial port devices at the application layer. This section discusses serial port issues on FinSH components.

Because the serial port peripherals involve a wide range of aspects, the analysis cannot cover all application scenarios (the above two aspects should cover 70% or 80% of the application scenarios in the use of serial ports). However, combined with the analysis method in this chapter, I believe that other problems will be solved easily.

The serial port on the FinSH component is faulty

Speaking of the FinSH component, it must be inseparable from the serial port. By default, the underlying data flow of the FinSH component is provided by the serial port peripheral (of course, you can also choose the network, USB, Bluetooth, etc., this section only discusses the issues related to the serial port).

The FinSH component of RT-Thread provides a set of operation interfaces for users to invoke on the command line to debug or view system information, similar to Terminal in Linux. Its execution sequence is shown in the following figure (sequence diagram of copied document center)

Combined with the figure above, FinSH is roughly similar to creating a serial Thread in the RT-Thread system. It receives (listens to) user data, parses the data, executes the results, and sends the desired results to the user through the serial port. In short, is the serial port peripheral transceiver tasks.

So it boils down to three things: 1. How does the FinSH thread start and work? 2. How does FinSH receive data? 3. How does FinSH display the execution result to the user?

FinSH workflow analysis

The key statements in the figure are (1), (2), and (3).

The (1) statement is a shell device that sets the FinSH thread. In this case, the shell device is a serial port device.

/* void finsh_set_device(const char *device_name) {dev = rt_device_find(device_name); . . /* open this device and set the new device in finsh shell */ if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | \ RT_DEVICE_FLAG_STREAM) == RT_EOK) { rt_device_set_rx_indicate(dev, finsh_rx_ind); }... . }

As you can see, the device’s open mode is RT_DEVICE_FLAG_INT_RX, and the send does not indicate whether the interrupt is RT_DEVICE_FLAG_INT_TX or RT_DEVICE_FLAG_DMA_TX, which means that the device sends in polling mode. That is, FinSH receive is in receive interrupt mode, and FinSH send is in polling mode. This is very important to remember.

Finsh_getchar (); / / finsh_getchar(); / / finsh_getchar(); / / finsh_getchar(); When finsh_getchar() is executed, rt_device_read() is used to read a byte of data. As long as the return value is not 1 (a return value of 1 would indicate that data has been read), the thread is suspended permanently through the semaphore until FinSH data is received. If any data is received, a semaphore is released through FinSH’s data receive callback finSH_rx_ind (), and the FinSH thread starts executing, reading a byte of data.

Static rt_err_t finsh_rx_ind(rt_device_t dev, rt_size_t size) {RT_ASSERT(shell! = RT_NULL); /* release semaphore to let finsh thread rx data */ rt_sem_release(&shell->rx_sem); return RT_EOK; }

(3) A statement is a send statement. After executing statement (2), the Finsh thread gets a byte of data. After data parsing, the Finsh thread will display this byte of data back to the terminal, that is, send the data to the terminal through rt_kprintf. The bottom layer of rT_kprintf is how to send the serial port data, here due to space limited, will not go into detail, directly say the conclusion is that rT_kprintf bottom layer is connected to the serial port polling sending mode.

FinSH summary

Some conclusions can be drawn from the above:

  1. When the serial port peripheral is used as the data flow, the FinSH sends in polling mode and receives in interrupt mode.
  2. The reception relies on the semaphore to do the data communication, and each time the reception interrupt, can only receive single-byte data.
  3. When the receiver does not receive data, FinSH suspends itself through the semaphore, so it is in non-blocking receive mode.
  4. The sender (including rt_kprintf) is a polling sender and therefore a blocking sender. By extension, can rt_kprintf be used in interrupt Settings? The answer is yes, because the function does not affect the state of the interrupt environment, wait for semaphores, or suspend threads. However, try to print data in interrupt environments as little as possible, because interrupt execution time should be as short as possible, adding printing will cause the interrupt execution time to be longer than expected, resulting in an unsafe unexpected risk)

Discussion of other issues

Combined with some features of FinSH and problems encountered in daily life, the following frequent points are summarized for your reference:

  1. Failed to receive data after FinSH is opened:

    Since FinSH is in interrupt receiving mode, since no data can be received, the following points can be directly located:

    1. Is the 'finsh_thread_entry' thread successfully initialized and waiting at 'finsh_getCHAR ()'? 2. Can 'finsh_getchar()' return data immediately when entering any character? 3. Is' finsh_rx_ind() 'receiving interrupt callback executed when any character is entered? 4. Input any characters, the corresponding serial port can enter the serial port interrupt, and check the serial port corresponding to the receive data register (RDR) whether there is a value (the value is the ASCII code value of the character you input)? 5. If there is no data even in the receive data register, check the serial port configuration (including clock, pin, interrupt, etc.) or the hardware problem
  2. After hardware reset, the system cannot output:

    This problem is not related to FinSH, but many people think this is a console output problem, so IT should be FinSH related, so I’ll just leave it there.

    This problem is similar to problem 1, but there are essential differences, that is, the reproduced scene occurs after the reset, so basically can be located to be related to the reset. Experience tells us that some development boards have integrated a one-key download circuit on the serial port of the development board because of the one-key download function. As a result, the BOOT mode is directly changed when the system is reset, thus entering the serial port ISP download mode. The hardware reset program is not working properly

  3. FinSH output garbled characters:

    This problem is either due to the console software of the computer terminal, or the wrong configuration such as the baud rate, or the hardware is not grounded.

  4. The default FinSH output is normal, but it will not work after switching to another serial port:

    This problem according to problem 1 to check the line, the large probability is the fifth point, the configuration problem, the serial port output redirection error and so on.

  5. If FinSH is enabled, the system will have hardfault:

    There is no special method for this problem, just follow the normal hardfault. Also see this link for the cortex-M kernel hardware failure analysis method

Summary of personal Debugging

When debugging FINSH, I usually use a more direct means, first pay attention to whether the FINSH thread is started, if it is normal, directly pull out the send data register TDR and receive data register RDR of the serial port (according to the version and model of MCU, some of these two registers are called DR data register. But the function is the same). Personally, I think this way is the most efficient. Take STM32F4 as an example and MDK debugging environment as an example.

How do I determine that the serial port FinSH reception is normal?

As mentioned above, FinSH receive is interrupt receive, so it is very simple to hit a breakpoint in the serial port to receive interrupt position, and then keyboard input a character to see whether the interrupt triggered, and determine whether the receive data register is the corresponding ASCII value of the input character. As shown in the figure:

The left box breakpoint position is where the serial port received the interrupt trigger, the right DR register is where the serial port received the characters stored, let the program run at full speed. The code at this breakpoint will not be executed without typing a character. Now hit the number “1” on the keyboard. If normal, you will get something like this:

After entering the number “1”, you can see that the program has reached the breakpoint. At this time, the DR data register also obtains the ASCII code value corresponding to the number “1”, which means that FinSH is receiving data normally.

How do I determine that the serial port FinSH sending is normal? According to the analogy of the received test method, the polling sending mode is used when sending data, so directly set a breakpoint at the stM32_getc () function, as shown in the figure below:

You can use rt_kprintf, or the FinSH echo function, which will eventually execute this section of code, and then check to see if the DR register data is correct.

The serial port at the application layer is faulty

To be continued, see the next chapter…