Seemingly simple code, but hidden secrets...

Click on "Uncle Wheat" above and select "Top/Star Public Account"

Welfare dry goods, delivered as soon as possible

Being able to see embedded problems from PC machine programming is the first step;

Learning to use embedded programming ideas is the second step;

Combining PC thinking with embedded thinking and applying it to actual projects is the third step.

Many friends have switched from PC programming to embedded programming.

In China, few friends of embedded programming are serious graduates from computer majors, and they all graduate from automatic control and electronics-related majors.

These children's shoes have rich practical experience, but lack of theoretical knowledge; a large part of children's shoes who graduate from computer majors go to higher-level applications such as online games and web pages, which are independent of the operating system.

I'm not very willing to engage in the embedded industry, after all, this road is not easy to go. They have strong theoretical knowledge, but lack related knowledge such as circuits. Learning in embedded requires learning some specific knowledge, which is more difficult to walk.

Although no industry research has been done, from what I've seen and recruited, engineers working in the embedded industry either lack theoretical knowledge or practical experience.

Rarely does both. The reason for this is the problem of university education in China. This issue is not discussed here to avoid war of words. I would like to list a few examples from my practice. Arouse everyone's attention to some problems when doing projects in embedded.

First example:

8fabd11e6fc8765152c116f9fa603d7c.png

A colleague developed a serial port driver under uC/OS-II, and problems were found in both the driver and the interface during the test. A communication program is developed in the application, and the serial port driver provides a function to query the characters of the driver buffer: GetRxBuffCharNum() .

The upper layer needs to accept a certain number of characters before parsing the packet. Code written by a colleague, expressed in pseudocode as follows:

bExit = FALSE;

do {

if (GetRxBuffCharNum() >= 30)

       bExit = ReadRxBuff(buff, GetRxBuffCharNum());

} while (!bExit);

This code judges that there are more than 30 characters in the current buffer, and reads all the characters in the buffer into the buffer until the reading is successful.

The logic is clear and the thinking is clear. But this code is not working properly. If it is on a PC, there must be no problem, and the work is abnormally normal. But in embedded it is really unknown. Colleagues are very depressed, do not know why.

Come and ask me to solve the problem. When I saw the code, I asked him, how is GetRxBuffCharNum() implemented? Open it up and take a look:

unsigned GetRxBuffCharNum(void)
{
    cpu_register reg;
    unsigned num;
    
    reg = interrupt_disable();
    num = gRxBuffCharNum;
    interrupt_enable(reg);
    
    return (num);
}

Obviously, since there is a global critical region between interrupt_disable() and interrupt_enable() in the loop, the integrity of gRxBufCharNum is guaranteed.

However, because in the outer do { } while() loop, the CPU frequently closes interrupts and opens interrupts, this time is very short.

In fact, the CPU may not respond to the UART interrupt normally. Of course, this has something to do with the baud rate of the uart, the size of the hardware buffer, and the speed of the CPU. We are using a very high baud rate, around 3Mbps.

The uart start signal and stop signal occupy one bit. One byte takes 10 cycles. A baud rate of 3Mbps takes about 3.3us to transmit a byte.

How many CPU instructions can 3.3us execute?

A 100MHz ARM can execute about 150 instructions. How long does it take to turn off interrupts as a result? Generally, ARM needs more than 4 instructions to close the interrupt, and more than 4 instructions to open it.

The code to receive the uart interrupt is actually more than 20 instructions. Therefore, in this way, there may be a bug of losing communication data, which is reflected in the system level, that is, the communication is unstable.

Modifying this code is actually very simple, the easiest way is to modify it from a high level. which is:

bExit = FALSE;

    do {
        DelayUs(20); //延时 20us,一般采用空循环指令实现
        num = GetRxBuffCharNum();
        if (num >= 30)
        bExit = ReadRxBuff(buff, num);

     } while (!bExit);

In this way, the CPU has time to execute the interrupted code, thereby avoiding the untimely execution of the interrupted code and the loss of information caused by frequently closing the interrupt.

In embedded systems, most RTOS applications do not have serial port drivers. When designing your own code, you do not fully consider the combination of code and kernel. Causes deep problems in the code.

RTOS is called RTOS because of its fast response to events; fast response to events depends on how fast the CPU responds to interrupts.

In systems like Linux, drivers are highly integrated with the kernel and run together in kernel mode. Although RTOS cannot copy the structure of linux, it has certain reference significance.

As can be seen from the above example, embedded requires developers to understand all aspects of the code clearly.

Second example:

cab4b53fc24eaec173a0cf69c393030d.png

A colleague drives a 14094 serial-to-parallel chip. Serial signals are simulated using IO because there is no dedicated hardware. A colleague wrote a driver at random, but after 3 or 4 days of debugging, there is still a problem.

I really couldn't stand it anymore, so I went to have a look. The parallel signal of the control is sometimes normal and sometimes not normal. I looked at the code and in pseudocode it is probably:

for (i = 0; i < 8; i++)
{

    SetData((data >> i) & 0x1);
    SetClockHigh();
    
    for (j = 0; j < 5; j++);
    SetClockLow();
}

The 8 bits of data are sent out sequentially from bit0 to bit7 at each high level. Should be normal. Can't see where the problem is?

I thought about it carefully, and after reading the datasheet of 14094, I understood.

It turned out that the 14094 requires that the high level of the clock lasts for 10 ns, and the low level also lasts for 10 ns. This code does a high-level time delay, but not a low-level delay. This code is ok if the interrupt is inserted between lows to work.

But if the CPU does not have an interrupt inserted at a low level, it will not work properly. So there are good times and bad.

The modification is also relatively simple:

for (i = 0; i < 8; i++)

{

    SetData((data >> i) & 0x1);
    SetClockHigh();

    for (j = 0; j < 5; j++);
    
    SetClockLow();

    for (j = 0; j < 5; j++);

}

This is completely normal. But this is still a code that cannot be ported very well, because once the compiler optimizes, it may cause the loss of these two delay loops.

If it is lost, the requirement that the high level and the low level last for 10ns cannot be guaranteed, and it will not work normally.

Therefore, the real portable code should make this loop a nanosecond DelayNs(10);

Like Linux, when powering on, first measure how long it takes to execute a nop instruction, and how many nop instructions execute 10ns.

Execute a certain nop instruction on it. Use the compiler's anti-optimization pragma or special keywords to prevent the delay loop from being optimized away by the compiler. as in GCC

__volatile__ __asm__("nop;\n");

It can be clearly seen from this example that writing a good piece of code requires a lot of knowledge to support. what do you say?

Article source: https://blog.csdn.net/coolbacon/article/details/6842921

The copyright belongs to the original author or the platform and is only for learning reference. If there is any infringement, please contact to delete it~

—— The End ——

Recommended in the past

How to prevent cracking? MCU encryption technology revealed

I advise you to stop being a traffic slave...

The university in the header file asks that the C language needs to pay attention to these principles...

7 C programs summarized in actual combat, good things are not hidden

To become an embedded master, these more than 100 software and hardware open source projects are indispensable

Click on the card above to follow me

90bfd75c794b01479f5871f5d65ea100.png

Everything you ordered looks good , I take it seriously as I like it

Guess you like

Origin blog.csdn.net/u010632165/article/details/123144177