UART optimization GCC. - Page 1
Forum section: electronics / general

author: luiHS
author_rank: Frequent Contributor
timestamp: December 11, 2020, 11:02:33 am
content: HiI continue with my problems due to GCC optimizations, but now with somewhat weirder results. I have a circuit with a Kinetis MK66 microcontroller that communicates via serial port with a Raspberry. I work with MCUXpresso in C with the GCC compiler, if the source is not optimized everything works, the funny thing is optimizing depending on how it is connected, it works or stays stopped and also does not allow Raspberry to start.These three possible situations are generated:1.- With the Jlink programmer connected and powered, even if a Debug session is not started, everything always works with and without optimization.2.- With the Jlink programmer connected but without power, nothing starts up, as if the Kinetis were in a continuous Reset (the Kinetis does have a supply voltage, of course).3.- The Jlink programmer not connected, then only the circuit works without source optimization. As soon as it is optimized, something very strange happens, the Kinetis starts up but when it tries to communicate via serial port with the Raspberry, it stops and the Raspberry doesn't start.For now the only thing I can think of is to put pullup resistors on the Reset, TX and RX line of the Kinetis. I have already defined the variables of the UART buffers as volatile, without any result. What surprises me the most is that the Raspberry does not start, I suppose it is because of the state of the TX and RX lines that the Kinetis handles.

author: Siwastaja
author_rank: Super Contributor
timestamp: December 11, 2020, 12:21:30 pm
content: Remove all libraries, access the UART registers directly (typically around 5 lines of code!), see if you can reproduce the problem, then post the code of the minimum example reproducing the problem, and just the problem, here.

author: newbrain
author_rank: Super Contributor
timestamp: December 11, 2020, 02:48:45 pm
content: 1.2. is quite normal - the J-link is probably holding the reset line asserted (close to 0 V). A pull-up might or might not work, though.3. Can you analyse what is going through the serial with a scope or a LA? At least some insight could be gained on where the protocol hangs. Setting breakpoints in the Kinetis and using printf on the Raspberry could help pinpointing what is going on.Still, correct code that does not depend on strict timing and has no critical races should behave the same.As noted in he other thread, a protocol (and code) able to auto-resync in case of errors (both sides) would be an improvement.And, of course, heed Siwastaja's advice to reduce the SW to the bare minimum still showing the problem.

author: ehughes
author_rank: Frequent Contributor
timestamp: December 11, 2020, 06:19:42 pm
content: Turn on -pedantic -Wall -WextraThis can sometimes can expose issues that might be triggering the optimizer to remove code.Responsible C development should always have all warnings turned on. Don't be surprised if the NXP/FSL libraries generate 10000 warnings.

author: brucehoult
author_rank: Super Contributor
timestamp: December 11, 2020, 08:22:09 pm
content: Quote from: luiHS on December 11, 2020, 11:02:33 amNo, you really don't.

author: Nominal Animal
author_rank: Super Contributor
timestamp: December 11, 2020, 10:33:41 pm
content: Quote from: luiHS on December 11, 2020, 11:02:33 amThen, the code is buggy.I happen to know that there are no extra-special weirdness on the Kinetis K66, because Teensy 3.6 also uses that MCU, and does not suffer from anything like you described. While its development is supported in the Arduino environment using the Teensyduino add-on, that also uses the ARM GCC (arm-none-eabi-gcc version 5.4.1 on Teensyduino 1.53 on Linux on x86-64).Now, I know this sounds like an assholy post. But, fact is, the faster you focus on the correct part, the faster you find and fix the problem.Indeed, it sounds exactly the kind of issue discussed in your other thread about GCC and optimization: the compiler assumes things wrong based on the code, unless you stupidify it so fully it makes no assumptions about anything anymore.Basically, you will now go on a Hunt for the Missing Volatiles. And that, I think, is worthy of its own topic: how to debug ARM MCU code that does not use volatile enough.(Why a separate topic, when we have a perfectly good thread right here? Because a proper title and question page will mean that others will find the topic later on too. I personally am completely uninterested in solving this problem separately again and again for each person that asks; I'd rather just work it out once with others, and then have something to point to. But, with a title like "UART optimization GCC", how many will associate that with finding where "volatile" was omitted but should have been used?)

author: luiHS
author_rank: Frequent Contributor
timestamp: December 12, 2020, 01:52:54 am
content: Quote from: newbrain on December 11, 2020, 02:48:45 pmI assumed that too.Quote from: newbrain on December 11, 2020, 02:48:45 pmI will first use the oscilloscope to see what state the Reset, TX and RX pins are in.The problem is that everything fails, only when the programmer is not connected. So doing a Debug session doesn't work for me because in that situation it always works. That is why I suspect that it could be a problem related to the reset pin of the microcontroller, I want to see how it varies and in what state it is depending on whether or not the Jlink programmer is connected.

author: luiHS
author_rank: Frequent Contributor
timestamp: December 12, 2020, 01:53:36 am
content: Quote from: Siwastaja on December 11, 2020, 12:21:30 pmI will try thanks, I have no experience handling the UART, I will look for information to avoid using the NXP library.

author: luiHS
author_rank: Frequent Contributor
timestamp: December 12, 2020, 02:36:37 am
content: Well, I solved the problem, I have enabled in MCUXpresso, the pullup resistors for the TX and RX lines of the Kinetis UART, and now it works perfectly with the optimized source.I don't know why this happened and what intrigues me are these two things:1.- Why the Raspberry did not start according to the state of the TX and RX lines.2.- Why with the optimized source the TX and RX pins remain in a different initial state than when it is not optimized.Without optimizing everything worked, when optimizing and starting without the programmer connected, the TX and RX lines were in a state that prevented the Raspberry from starting, if the Raspberry did not start then the Kinetis was waiting for a serial communication that could never take place.The problem was not a malfunction of the UART, but of the initial state of the TX and RX ports of the UART when the source is optimized.

author: DiTBho
author_rank: Super Contributor
timestamp: December 12, 2020, 04:03:39 am
content: Two years ago I had a similar problem with a router connected to a MPU though the router's serial console.The biggest mistake ever! Never attach anything to the serial console!Why? Well ... by investigating about that showed that when the MPU crashed it then sent out a stream of garbage 0x20 bytes plus all the "modem" lines turned on on the serial console of the router and *this* prevented the router from bootstrapping because it was somehow interacting with the boot-monitor.Then I modified the booting firmware to ignore all the "modem lines" and I also introduced a "magic sequence" of chars to stop the booting process.So to stop the booting process of the router, *what is attacked to its serial console* would need to send exactly the stream 'm','a','g','i','c' in this precise order rather than allowing a simply space-char to stop the boot-process (on u-boot, this can do it)It worked and temporary solved the problem until I moved the MPU to a dedicated usb-to-serial line, as I still consider my first temporary solution as nothing but a "weak workaround".

author: newbrain
author_rank: Super Contributor
timestamp: December 12, 2020, 11:07:20 am
content: Quote from: luiHS on December 12, 2020, 02:36:37 amLet's be honest: you have hidden the symptoms - but still missing are:A real root cause: the initial Tx and Rx pins state should not be affected by the optimizations or debugger connection.A real solution for fragile SW (at least on the RPi side).

author: Siwastaja
author_rank: Super Contributor
timestamp: December 12, 2020, 12:08:55 pm
content: I really fail to see why a microcontroller manufacturer develops and encourages usage of a graphical tool that generates code for turning pullup/pulldown on/off "at init" (whatever that means; the whole idea of "configuring peripherals" once at the start of main() is a stupid, unhelpful "simplification" which doesn't simplify anything. Do things whenever needed!).Changing the pullup/pulldown settings is the normal operation to be done anywhere in the code, takes 1 line of code unabstracted, or 1 line of code (not 10) properly abstracted (I use IO_PULLUP_ON(GPIOE, 15);). Why on Earth would you want to do that in a graphical click&play interface then wonder if it happens at all, when it happens, and where it happens? I'd understand if there was a issue of inability to write any code at all (then consider Labview et al), but code needs to be written anyway.Just turn the pullup on when you want and need to do it, just like you turn the IO high or low, or read an input pin in code. This is the basic essence of programming microcontrollers.Remember that sometimes you need pullups/pulldowns that are enabled as soon as power rails rise. In such cases, you can't wait for the startup delay of the CPU (at least microseconds, often milliseconds) to enable the IO port resistors, and need to add external resistors on the PCB. If the timing of enabling the pullups is important, then the optimization setting might seemingly make a difference; obviously at -O3, they will be enabled sooner than at -O0.Simplification is the only way to reach understanding in manageable time, and understanding is the only way to go forward IMHO.